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

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

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

~ [ 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