headers: remove sched.h from interrupt.h
[safe/jmp/linux-2.6] / net / irda / ircomm / ircomm_tty_attach.c
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 = (struct ircomm_tty_cb *) 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