Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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