~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/irda/ircomm/ircomm_tty_attach.c

Version: ~ [ linux-5.4-rc3 ] ~ [ linux-5.3.6 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.79 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.149 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.196 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.196 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.75 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*********************************************************************
  2  *                
  3  * Filename:      ircomm_tty_attach.c
  4  * Version:       
  5  * Description:   Code for attaching the serial driver to IrCOMM
  6  * Status:        Experimental.
  7  * Author:        Dag Brattli <dagb@cs.uit.no>
  8  * Created at:    Sat Jun  5 17:42:00 1999
  9  * Modified at:   Tue Jan  4 14:20:49 2000
 10  * Modified by:   Dag Brattli <dagb@cs.uit.no>
 11  * 
 12  *     Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
 13  *     
 14  *     This program is free software; you can redistribute it and/or 
 15  *     modify it under the terms of the GNU General Public License as 
 16  *     published by the Free Software Foundation; either version 2 of 
 17  *     the License, or (at your option) any later version.
 18  * 
 19  *     This program is distributed in the hope that it will be useful,
 20  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 21  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 22  *     GNU General Public License for more details.
 23  * 
 24  *     You should have received a copy of the GNU General Public License 
 25  *     along with this program; if not, write to the Free Software 
 26  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
 27  *     MA 02111-1307 USA
 28  *     
 29  ********************************************************************/
 30 
 31 #include <linux/sched.h>
 32 #include <linux/init.h>
 33 
 34 #include <net/irda/irda.h>
 35 #include <net/irda/irlmp.h>
 36 #include <net/irda/iriap.h>
 37 #include <net/irda/irttp.h>
 38 #include <net/irda/irias_object.h>
 39 #include <net/irda/parameters.h>
 40 
 41 #include <net/irda/ircomm_core.h>
 42 #include <net/irda/ircomm_param.h>
 43 #include <net/irda/ircomm_event.h>
 44 
 45 #include <net/irda/ircomm_tty.h>
 46 #include <net/irda/ircomm_tty_attach.h>
 47 
 48 static void ircomm_tty_ias_register(struct ircomm_tty_cb *self);
 49 static void ircomm_tty_discovery_indication(discovery_t *discovery,
 50                                             DISCOVERY_MODE mode,
 51                                             void *priv);
 52 static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, 
 53                                         struct ias_value *value, void *priv);
 54 void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout);
 55 void ircomm_tty_watchdog_timer_expired(void *data);
 56 
 57 static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, 
 58                                  IRCOMM_TTY_EVENT event, 
 59                                  struct sk_buff *skb, 
 60                                  struct ircomm_tty_info *info);
 61 static int ircomm_tty_state_search(struct ircomm_tty_cb *self, 
 62                                    IRCOMM_TTY_EVENT event, 
 63                                    struct sk_buff *skb, 
 64                                    struct ircomm_tty_info *info);
 65 static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, 
 66                                              IRCOMM_TTY_EVENT event, 
 67                                              struct sk_buff *skb, 
 68                                              struct ircomm_tty_info *info);
 69 static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, 
 70                                            IRCOMM_TTY_EVENT event, 
 71                                            struct sk_buff *skb, 
 72                                            struct ircomm_tty_info *info);
 73 static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, 
 74                                   IRCOMM_TTY_EVENT event, 
 75                                   struct sk_buff *skb, 
 76                                   struct ircomm_tty_info *info);
 77 static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, 
 78                                   IRCOMM_TTY_EVENT event, 
 79                                   struct sk_buff *skb, 
 80                                   struct ircomm_tty_info *info);
 81 
 82 char *ircomm_tty_state[] = {
 83         "IRCOMM_TTY_IDLE",
 84         "IRCOMM_TTY_SEARCH",
 85         "IRCOMM_TTY_QUERY_PARAMETERS",
 86         "IRCOMM_TTY_QUERY_LSAP_SEL",
 87         "IRCOMM_TTY_SETUP",
 88         "IRCOMM_TTY_READY",
 89         "*** ERROR *** ",
 90 };
 91 
 92 char *ircomm_tty_event[] = {
 93         "IRCOMM_TTY_ATTACH_CABLE",
 94         "IRCOMM_TTY_DETACH_CABLE",
 95         "IRCOMM_TTY_DATA_REQUEST",
 96         "IRCOMM_TTY_DATA_INDICATION",
 97         "IRCOMM_TTY_DISCOVERY_REQUEST",
 98         "IRCOMM_TTY_DISCOVERY_INDICATION",
 99         "IRCOMM_TTY_CONNECT_CONFIRM",
100         "IRCOMM_TTY_CONNECT_INDICATION",
101         "IRCOMM_TTY_DISCONNECT_REQUEST",
102         "IRCOMM_TTY_DISCONNECT_INDICATION",
103         "IRCOMM_TTY_WD_TIMER_EXPIRED",
104         "IRCOMM_TTY_GOT_PARAMETERS",
105         "IRCOMM_TTY_GOT_LSAPSEL",
106         "*** ERROR ****",
107 };
108 
109 static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
110                       struct sk_buff *skb, struct ircomm_tty_info *info) = 
111 {
112         ircomm_tty_state_idle,
113         ircomm_tty_state_search,
114         ircomm_tty_state_query_parameters,
115         ircomm_tty_state_query_lsap_sel,
116         ircomm_tty_state_setup,
117         ircomm_tty_state_ready,
118 };
119 
120 /*
121  * Function ircomm_tty_attach_cable (driver)
122  *
123  *    Try to attach cable (IrCOMM link). This function will only return
124  *    when the link has been connected, or if an error condition occurs. 
125  *    If success, the return value is the resulting service type.
126  */
127 int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
128 {
129         IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
130 
131         ASSERT(self != NULL, return -1;);
132         ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
133 
134         /* Check if somebody has already connected to us */
135         if (ircomm_is_connected(self->ircomm)) {
136                 IRDA_DEBUG(0, "%s(), already connected!\n", __FUNCTION__);
137                 return 0;
138         }
139 
140         /* Make sure nobody tries to write before the link is up */
141         self->tty->hw_stopped = 1;
142 
143         ircomm_tty_ias_register(self);
144 
145         /* Check if somebody has already connected to us */
146         if (ircomm_is_connected(self->ircomm)) {
147                 IRDA_DEBUG(0, "%s(), already connected!\n", __FUNCTION__);
148                 return 0;
149         }
150 
151         ircomm_tty_do_event(self, IRCOMM_TTY_ATTACH_CABLE, NULL, NULL);
152 
153         return 0;
154 }
155 
156 /*
157  * Function ircomm_detach_cable (driver)
158  *
159  *    Detach cable, or cable has been detached by peer
160  *
161  */
162 void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
163 {
164         IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
165 
166         ASSERT(self != NULL, return;);
167         ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
168 
169         del_timer(&self->watchdog_timer);
170 
171         /* Remove IrCOMM hint bits */
172         irlmp_unregister_client(self->ckey);
173         irlmp_unregister_service(self->skey);
174 
175         if (self->iriap) { 
176                 iriap_close(self->iriap);
177                 self->iriap = NULL;
178         }
179 
180         /* Remove LM-IAS object */
181         if (self->obj) {
182                 irias_delete_object(self->obj);
183                 self->obj = NULL;
184         }
185 
186         ircomm_tty_do_event(self, IRCOMM_TTY_DETACH_CABLE, NULL, NULL);
187 
188         /* Reset some values */
189         self->daddr = self->saddr = 0;
190         self->dlsap_sel = self->slsap_sel = 0;
191 
192         memset(&self->settings, 0, sizeof(struct ircomm_params));
193 }
194 
195 /*
196  * Function ircomm_tty_ias_register (self)
197  *
198  *    Register with LM-IAS depending on which service type we are
199  *
200  */
201 static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
202 {
203         __u8 oct_seq[6];
204         __u16 hints;
205 
206         IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
207 
208         ASSERT(self != NULL, return;);
209         ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
210         
211         if (self->service_type & IRCOMM_3_WIRE_RAW) {
212                 hints = irlmp_service_to_hint(S_PRINTER);
213                 hints |= irlmp_service_to_hint(S_COMM);
214                 
215                 /* Register IrLPT with LM-IAS */
216                 self->obj = irias_new_object("IrLPT", IAS_IRLPT_ID);
217                 irias_add_integer_attrib(self->obj, "IrDA:IrLMP:LsapSel", 
218                                          self->slsap_sel, IAS_KERNEL_ATTR);
219                 irias_insert_object(self->obj);
220         } else {
221                 hints = irlmp_service_to_hint(S_COMM);
222 
223                 /* Register IrCOMM with LM-IAS */
224                 self->obj = irias_new_object("IrDA:IrCOMM", IAS_IRCOMM_ID);
225                 irias_add_integer_attrib(self->obj, "IrDA:TinyTP:LsapSel", 
226                                          self->slsap_sel, IAS_KERNEL_ATTR);
227                 
228                 /* Code the parameters into the buffer */
229                 irda_param_pack(oct_seq, "bbbbbb", 
230                                 IRCOMM_SERVICE_TYPE, 1, self->service_type,
231                                 IRCOMM_PORT_TYPE,    1, IRCOMM_SERIAL);
232                 
233                 /* Register parameters with LM-IAS */
234                 irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6,
235                                         IAS_KERNEL_ATTR);
236                 irias_insert_object(self->obj);
237         }
238         self->skey = irlmp_register_service(hints);
239         self->ckey = irlmp_register_client(
240                 hints, ircomm_tty_discovery_indication, NULL, (void *) self);
241 }
242 
243 /*
244  * Function ircomm_send_initial_parameters (self)
245  *
246  *    Send initial parameters to the remote IrCOMM device. These parameters
247  *    must be sent before any data.
248  */
249 int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)
250 {
251         ASSERT(self != NULL, return -1;);
252         ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
253 
254         if (self->service_type & IRCOMM_3_WIRE_RAW) 
255                 return 0;
256 
257         /* 
258          * Set default values, but only if the application for some reason 
259          * haven't set them already
260          */
261         IRDA_DEBUG(2, "%s(), data-rate = %d\n", __FUNCTION__,
262                    self->settings.data_rate);
263         if (!self->settings.data_rate)
264                 self->settings.data_rate = 9600;
265         IRDA_DEBUG(2, "%s(), data-format = %d\n", __FUNCTION__,
266                    self->settings.data_format);
267         if (!self->settings.data_format)
268                 self->settings.data_format = IRCOMM_WSIZE_8;  /* 8N1 */
269 
270         IRDA_DEBUG(2, "%s(), flow-control = %d\n", __FUNCTION__,
271                    self->settings.flow_control);
272         /*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/
273 
274         /* Do not set delta values for the initial parameters */
275         self->settings.dte = IRCOMM_DTR | IRCOMM_RTS;
276 
277         /* Only send service type parameter when we are the client */
278         if (self->client)
279                 ircomm_param_request(self, IRCOMM_SERVICE_TYPE, FALSE);
280         ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);
281         ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
282         
283         /* For a 3 wire service, we just flush the last parameter and return */
284         if (self->settings.service_type == IRCOMM_3_WIRE) {
285                 ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE);
286                 return 0;
287         }
288 
289         /* Only 9-wire service types continue here */
290         ircomm_param_request(self, IRCOMM_FLOW_CONTROL, FALSE);
291 #if 0
292         ircomm_param_request(self, IRCOMM_XON_XOFF, FALSE);
293         ircomm_param_request(self, IRCOMM_ENQ_ACK, FALSE);
294 #endif  
295         /* Notify peer that we are ready to receive data */
296         ircomm_param_request(self, IRCOMM_DTE, TRUE);
297         
298         return 0;
299 }
300 
301 /*
302  * Function ircomm_tty_discovery_indication (discovery)
303  *
304  *    Remote device is discovered, try query the remote IAS to see which
305  *    device it is, and which services it has.
306  *
307  */
308 static void ircomm_tty_discovery_indication(discovery_t *discovery,
309                                             DISCOVERY_MODE mode,
310                                             void *priv)
311 {
312         struct ircomm_tty_cb *self;
313         struct ircomm_tty_info info;
314 
315         IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
316 
317         /* Important note :
318          * We need to drop all passive discoveries.
319          * The LSAP management of IrComm is deficient and doesn't deal
320          * with the case of two instance connecting to each other
321          * simultaneously (it will deadlock in LMP).
322          * The proper fix would be to use the same technique as in IrNET,
323          * to have one server socket and separate instances for the
324          * connecting/connected socket.
325          * The workaround is to drop passive discovery, which drastically
326          * reduce the probability of this happening.
327          * Jean II */
328         if(mode == DISCOVERY_PASSIVE)
329                 return;
330 
331         info.daddr = discovery->daddr;
332         info.saddr = discovery->saddr;
333 
334         self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
335         while (self != NULL) {
336                 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
337                 
338                 ircomm_tty_do_event(self, IRCOMM_TTY_DISCOVERY_INDICATION, 
339                                     NULL, &info);
340 
341                 self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty);
342         }
343 }
344 
345 /*
346  * Function ircomm_tty_disconnect_indication (instance, sap, reason, skb)
347  *
348  *    Link disconnected
349  *
350  */
351 void ircomm_tty_disconnect_indication(void *instance, void *sap, 
352                                       LM_REASON reason,
353                                       struct sk_buff *skb)
354 {
355         struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
356 
357         IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
358 
359         ASSERT(self != NULL, return;);
360         ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
361 
362         if (!self->tty)
363                 return;
364 
365         /* This will stop control data transfers */
366         self->flow = FLOW_STOP;
367 
368         /* Stop data transfers */
369         self->tty->hw_stopped = 1;
370 
371         ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL, 
372                             NULL);
373 }
374 
375 /*
376  * Function ircomm_tty_getvalue_confirm (result, obj_id, value, priv)
377  *
378  *    Got result from the IAS query we make
379  *
380  */
381 static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, 
382                                         struct ias_value *value, 
383                                         void *priv)
384 {
385         struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv;
386 
387         IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
388 
389         ASSERT(self != NULL, return;);
390         ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
391 
392         /* We probably don't need to make any more queries */
393         iriap_close(self->iriap);
394         self->iriap = NULL;
395 
396         /* Check if request succeeded */
397         if (result != IAS_SUCCESS) {
398                 IRDA_DEBUG(4, "%s(), got NULL value!\n", __FUNCTION__);
399                 return;
400         }
401 
402         switch (value->type) {
403         case IAS_OCT_SEQ:
404                 IRDA_DEBUG(2, "%s(), got octet sequence\n", __FUNCTION__);
405 
406                 irda_param_extract_all(self, value->t.oct_seq, value->len,
407                                        &ircomm_param_info);
408 
409                 ircomm_tty_do_event(self, IRCOMM_TTY_GOT_PARAMETERS, NULL, 
410                                     NULL);
411                 break;
412         case IAS_INTEGER:
413                 /* Got LSAP selector */ 
414                 IRDA_DEBUG(2, "%s(), got lsapsel = %d\n", __FUNCTION__,
415                            value->t.integer);
416 
417                 if (value->t.integer == -1) {
418                         IRDA_DEBUG(0, "%s(), invalid value!\n", __FUNCTION__);
419                 } else
420                         self->dlsap_sel = value->t.integer;
421 
422                 ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL);
423                 break;
424         case IAS_MISSING:
425                 IRDA_DEBUG(0, "%s(), got IAS_MISSING\n", __FUNCTION__);
426                 break;
427         default:
428                 IRDA_DEBUG(0, "%s(), got unknown type!\n", __FUNCTION__);
429                 break;
430         }
431         irias_delete_value(value);
432 }
433 
434 /*
435  * Function ircomm_tty_connect_confirm (instance, sap, qos, max_sdu_size, skb)
436  *
437  *    Connection confirmed
438  *
439  */
440 void ircomm_tty_connect_confirm(void *instance, void *sap, 
441                                 struct qos_info *qos, 
442                                 __u32 max_data_size, 
443                                 __u8 max_header_size, 
444                                 struct sk_buff *skb)
445 {
446         struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
447 
448         IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
449 
450         ASSERT(self != NULL, return;);
451         ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
452 
453         self->client = TRUE;
454         self->max_data_size = max_data_size;
455         self->max_header_size = max_header_size;
456         self->flow = FLOW_START;
457 
458         ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL);
459 
460         dev_kfree_skb(skb);
461 }
462 
463 /*
464  * Function ircomm_tty_connect_indication (instance, sap, qos, max_sdu_size, 
465  *                                         skb)
466  *
467  *    we are discovered and being requested to connect by remote device !
468  *
469  */
470 void ircomm_tty_connect_indication(void *instance, void *sap, 
471                                    struct qos_info *qos, 
472                                    __u32 max_data_size,
473                                    __u8 max_header_size, 
474                                    struct sk_buff *skb)
475 {
476         struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
477         int clen;
478 
479         IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
480 
481         ASSERT(self != NULL, return;);
482         ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
483 
484         self->client = FALSE;
485         self->max_data_size = max_data_size;
486         self->max_header_size = max_header_size;
487         self->flow = FLOW_START;
488 
489         clen = skb->data[0];
490         if (clen)
491                 irda_param_extract_all(self, skb->data+1, 
492                                        IRDA_MIN(skb->len, clen), 
493                                        &ircomm_param_info);
494 
495         ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL);
496 
497         dev_kfree_skb(skb);
498 }
499 
500 /*
501  * Function ircomm_tty_link_established (self)
502  *
503  *    Called when the IrCOMM link is established
504  *
505  */
506 void ircomm_tty_link_established(struct ircomm_tty_cb *self)
507 {
508         IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
509 
510         ASSERT(self != NULL, return;);
511         ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
512 
513         if (!self->tty)
514                 return;
515         
516         del_timer(&self->watchdog_timer);
517 
518         /* Remove LM-IAS object now so it is not reused.
519          * IrCOMM deals very poorly with multiple incomming connections.
520          * It should looks a lot more like IrNET, and "dup" a server TSAP
521          * to the application TSAP (based on various rules).
522          * This is a cheap workaround allowing multiple clients to
523          * connect to us. It will not always work.
524          * Each IrCOMM socket has an IAS entry. Incomming connection will
525          * pick the first one found. So, when we are fully connected,
526          * we remove our IAS entries so that the next IAS entry is used.
527          * We do that for *both* client and server, because a server
528          * can also create client instances.
529          * Jean II */
530         if (self->obj) {
531                 irias_delete_object(self->obj);
532                 self->obj = NULL;
533         }
534 
535         /* 
536          * IrCOMM link is now up, and if we are not using hardware
537          * flow-control, then declare the hardware as running. Otherwise we
538          * will have to wait for the peer device (DCE) to raise the CTS
539          * line.  
540          */
541         if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {
542                 IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __FUNCTION__);
543                 return;
544         } else {
545                 IRDA_DEBUG(1, "%s(), starting hardware!\n", __FUNCTION__);
546 
547                 self->tty->hw_stopped = 0;
548         
549                 /* Wake up processes blocked on open */
550                 wake_up_interruptible(&self->open_wait);
551         }
552 
553         queue_task(&self->tqueue, &tq_immediate);
554         mark_bh(IMMEDIATE_BH);
555 }
556 
557 /*
558  * Function irlan_start_watchdog_timer (self, timeout)
559  *
560  *    Start the watchdog timer. This timer is used to make sure that any 
561  *    connection attempt is successful, and if not, we will retry after 
562  *    the timeout
563  */
564 void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout)
565 {
566         ASSERT(self != NULL, return;);
567         ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
568 
569         irda_start_timer(&self->watchdog_timer, timeout, (void *) self,
570                          ircomm_tty_watchdog_timer_expired);
571 }
572 
573 /*
574  * Function ircomm_tty_watchdog_timer_expired (data)
575  *
576  *    Called when the connect procedure have taken to much time.
577  *
578  */
579 void ircomm_tty_watchdog_timer_expired(void *data)
580 {
581         struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data;
582         
583         IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
584 
585         ASSERT(self != NULL, return;);
586         ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
587 
588         ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL);
589 }
590 
591 /*
592  * Function ircomm_tty_state_idle (self, event, skb, info)
593  *
594  *    Just hanging around
595  *
596  */
597 static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, 
598                                  IRCOMM_TTY_EVENT event, 
599                                  struct sk_buff *skb, 
600                                  struct ircomm_tty_info *info)
601 {
602         int ret = 0;
603 
604         IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__,
605                    ircomm_tty_state[self->state], ircomm_tty_event[event]);
606         switch (event) {
607         case IRCOMM_TTY_ATTACH_CABLE:
608                 /* Try to discover any remote devices */                
609                 ircomm_tty_start_watchdog_timer(self, 3*HZ);
610                 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
611                 
612                 irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
613                 break;
614         case IRCOMM_TTY_DISCOVERY_INDICATION:
615                 self->daddr = info->daddr;
616                 self->saddr = info->saddr;
617 
618                 if (self->iriap) {
619                         WARNING("%s(), busy with a previous query\n", __FUNCTION__);
620                         return -EBUSY;
621                 }
622 
623                 self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
624                                          ircomm_tty_getvalue_confirm);
625 
626                 iriap_getvaluebyclass_request(self->iriap,
627                                               self->saddr, self->daddr,
628                                               "IrDA:IrCOMM", "Parameters");
629                 
630                 ircomm_tty_start_watchdog_timer(self, 3*HZ);
631                 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
632                 break;
633         case IRCOMM_TTY_CONNECT_INDICATION:
634                 del_timer(&self->watchdog_timer);
635 
636                 /* Accept connection */
637                 ircomm_connect_response(self->ircomm, NULL);
638                 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
639                 break;
640         case IRCOMM_TTY_WD_TIMER_EXPIRED:
641                 /* Just stay idle */
642                 break;
643         case IRCOMM_TTY_DETACH_CABLE:
644                 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
645                 break;
646         default:
647                 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__,
648                            ircomm_tty_event[event]);
649                 return -EINVAL;
650         }
651         return ret;
652 }
653 
654 /*
655  * Function ircomm_tty_state_search (self, event, skb, info)
656  *
657  *    Trying to discover an IrCOMM device
658  *
659  */
660 static int ircomm_tty_state_search(struct ircomm_tty_cb *self, 
661                                    IRCOMM_TTY_EVENT event, 
662                                    struct sk_buff *skb, 
663                                    struct ircomm_tty_info *info)
664 {
665         int ret = 0;
666 
667         IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__,
668                    ircomm_tty_state[self->state], ircomm_tty_event[event]);
669 
670         switch (event) {
671         case IRCOMM_TTY_DISCOVERY_INDICATION:
672                 self->daddr = info->daddr;
673                 self->saddr = info->saddr;
674 
675                 if (self->iriap) {
676                         WARNING("%s(), busy with a previous query\n", __FUNCTION__);
677                         return -EBUSY;
678                 }
679                 
680                 self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
681                                          ircomm_tty_getvalue_confirm);
682                 
683                 if (self->service_type == IRCOMM_3_WIRE_RAW) {
684                         iriap_getvaluebyclass_request(self->iriap, self->saddr,
685                                                       self->daddr, "IrLPT", 
686                                                       "IrDA:IrLMP:LsapSel");
687                         ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
688                 } else {
689                         iriap_getvaluebyclass_request(self->iriap, self->saddr,
690                                                       self->daddr, 
691                                                       "IrDA:IrCOMM", 
692                                                       "Parameters");
693 
694                         ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
695                 }
696                 ircomm_tty_start_watchdog_timer(self, 3*HZ);
697                 break;
698         case IRCOMM_TTY_CONNECT_INDICATION:
699                 del_timer(&self->watchdog_timer);
700 
701                 /* Accept connection */
702                 ircomm_connect_response(self->ircomm, NULL);
703                 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
704                 break;
705         case IRCOMM_TTY_WD_TIMER_EXPIRED:
706 #if 1
707                 /* Give up */
708 #else
709                 /* Try to discover any remote devices */                
710                 ircomm_tty_start_watchdog_timer(self, 3*HZ);
711                 irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
712 #endif
713                 break;
714         case IRCOMM_TTY_DETACH_CABLE:
715                 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
716                 break;
717         default:
718                 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__,
719                            ircomm_tty_event[event]);
720                 return -EINVAL;
721         }
722         return ret;
723 }
724 
725 /*
726  * Function ircomm_tty_state_query (self, event, skb, info)
727  *
728  *    Querying the remote LM-IAS for IrCOMM parameters
729  *
730  */
731 static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, 
732                                              IRCOMM_TTY_EVENT event, 
733                                              struct sk_buff *skb, 
734                                              struct ircomm_tty_info *info)
735 {
736         int ret = 0;
737 
738         IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__,
739                    ircomm_tty_state[self->state], ircomm_tty_event[event]);
740 
741         switch (event) {
742         case IRCOMM_TTY_GOT_PARAMETERS:
743                 if (self->iriap) {
744                         WARNING("%s(), busy with a previous query\n", __FUNCTION__);
745                         return -EBUSY;
746                 }
747                 
748                 self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
749                                          ircomm_tty_getvalue_confirm);
750 
751                 iriap_getvaluebyclass_request(self->iriap, self->saddr, 
752                                               self->daddr, "IrDA:IrCOMM", 
753                                               "IrDA:TinyTP:LsapSel");
754 
755                 ircomm_tty_start_watchdog_timer(self, 3*HZ);
756                 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
757                 break;
758         case IRCOMM_TTY_WD_TIMER_EXPIRED:
759                 /* Go back to search mode */
760                 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
761                 ircomm_tty_start_watchdog_timer(self, 3*HZ); 
762                 break;
763         case IRCOMM_TTY_CONNECT_INDICATION:
764                 del_timer(&self->watchdog_timer);
765 
766                 /* Accept connection */
767                 ircomm_connect_response(self->ircomm, NULL);
768                 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
769                 break;
770         case IRCOMM_TTY_DETACH_CABLE:
771                 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
772                 break;
773         default:
774                 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__,
775                            ircomm_tty_event[event]);
776                 return -EINVAL;
777         }
778         return ret;
779 }
780 
781 /*
782  * Function ircomm_tty_state_query_lsap_sel (self, event, skb, info)
783  *
784  *    Query remote LM-IAS for the LSAP selector which we can connect to
785  *
786  */
787 static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, 
788                                            IRCOMM_TTY_EVENT event, 
789                                            struct sk_buff *skb, 
790                                            struct ircomm_tty_info *info)
791 {
792         int ret = 0;
793 
794         IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__,
795                    ircomm_tty_state[self->state], ircomm_tty_event[event]);
796 
797         switch (event) {
798         case IRCOMM_TTY_GOT_LSAPSEL:
799                 /* Connect to remote device */
800                 ret = ircomm_connect_request(self->ircomm, self->dlsap_sel,
801                                              self->saddr, self->daddr, 
802                                              NULL, self->service_type);
803                 ircomm_tty_start_watchdog_timer(self, 3*HZ);
804                 ircomm_tty_next_state(self, IRCOMM_TTY_SETUP);
805                 break;
806         case IRCOMM_TTY_WD_TIMER_EXPIRED:
807                 /* Go back to search mode */
808                 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
809                 ircomm_tty_start_watchdog_timer(self, 3*HZ);
810                 break;
811         case IRCOMM_TTY_CONNECT_INDICATION:
812                 del_timer(&self->watchdog_timer);
813 
814                 /* Accept connection */
815                 ircomm_connect_response(self->ircomm, NULL);
816                 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
817                 break;
818         case IRCOMM_TTY_DETACH_CABLE:
819                 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
820                 break;
821         default:
822                 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__,
823                            ircomm_tty_event[event]);
824                 return -EINVAL;
825         }
826         return ret;
827 }
828 
829 /*
830  * Function ircomm_tty_state_setup (self, event, skb, info)
831  *
832  *    Trying to connect
833  *
834  */
835 static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, 
836                                   IRCOMM_TTY_EVENT event, 
837                                   struct sk_buff *skb, 
838                                   struct ircomm_tty_info *info)
839 {
840         int ret = 0;
841 
842         IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__,
843                    ircomm_tty_state[self->state], ircomm_tty_event[event]);
844 
845         switch (event) {
846         case IRCOMM_TTY_CONNECT_CONFIRM:
847                 del_timer(&self->watchdog_timer);
848                 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
849                 
850                 /* 
851                  * Send initial parameters. This will also send out queued
852                  * parameters waiting for the connection to come up 
853                  */
854                 ircomm_tty_send_initial_parameters(self);
855                 ircomm_tty_link_established(self);
856                 break;
857         case IRCOMM_TTY_CONNECT_INDICATION:
858                 del_timer(&self->watchdog_timer);
859                 
860                 /* Accept connection */
861                 ircomm_connect_response(self->ircomm, NULL);
862                 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
863                 break;
864         case IRCOMM_TTY_WD_TIMER_EXPIRED:
865                 /* Go back to search mode */
866                 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
867                 ircomm_tty_start_watchdog_timer(self, 3*HZ);
868                 break;
869         case IRCOMM_TTY_DETACH_CABLE:
870                 /* ircomm_disconnect_request(self->ircomm, NULL); */
871                 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
872                 break;
873         default:
874                 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__,
875                            ircomm_tty_event[event]);
876                 return -EINVAL;
877         }
878         return ret;
879 }
880 
881 /*
882  * Function ircomm_tty_state_ready (self, event, skb, info)
883  *
884  *    IrCOMM is now connected
885  *
886  */
887 static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, 
888                                   IRCOMM_TTY_EVENT event, 
889                                   struct sk_buff *skb, 
890                                   struct ircomm_tty_info *info)
891 {
892         int ret = 0;
893 
894         switch (event) {
895         case IRCOMM_TTY_DATA_REQUEST:
896                 ret = ircomm_data_request(self->ircomm, skb);
897                 break;          
898         case IRCOMM_TTY_DETACH_CABLE:
899                 ircomm_disconnect_request(self->ircomm, NULL);
900                 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
901                 break;
902         case IRCOMM_TTY_DISCONNECT_INDICATION:
903                 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
904                 ircomm_tty_start_watchdog_timer(self, 3*HZ);
905 
906                 if (self->flags & ASYNC_CHECK_CD) {
907                         /* Drop carrier */
908                         self->settings.dce = IRCOMM_DELTA_CD;
909                         ircomm_tty_check_modem_status(self);
910                 } else {
911                         IRDA_DEBUG(0, "%s(), hanging up!\n", __FUNCTION__);
912                         if (self->tty)
913                                 tty_hangup(self->tty);
914                 }
915                 break;
916         default:
917                 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__,
918                            ircomm_tty_event[event]);
919                 return -EINVAL;
920         }
921         return ret;
922 }
923 
924 /*
925  * Function ircomm_tty_do_event (self, event, skb)
926  *
927  *    Process event
928  *
929  */
930 int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
931                         struct sk_buff *skb, struct ircomm_tty_info *info) 
932 {
933         ASSERT(self != NULL, return -1;);
934         ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
935 
936         IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__,
937                    ircomm_tty_state[self->state], ircomm_tty_event[event]);
938         
939         return (*state[self->state])(self, event, skb, info);
940 }
941 
942 /*
943  * Function ircomm_tty_next_state (self, state)
944  *
945  *    Switch state
946  *
947  */
948 void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
949 {
950         ASSERT(self != NULL, return;);
951         ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
952 
953         self->state = state;
954         
955         IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __FUNCTION__,
956                    ircomm_tty_state[self->state], self->service_type);
957 }
958 
959 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp