RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / net / irda / ircomm / ircomm_tty_attach.c
blob4f18e7466fa09ae1990484a55c900a8a53423b34
1 /*********************************************************************
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>
12 * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
13 * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
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.
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.
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
30 ********************************************************************/
32 #include <linux/init.h>
33 #include <linux/sched.h>
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>
42 #include <net/irda/ircomm_core.h>
43 #include <net/irda/ircomm_param.h>
44 #include <net/irda/ircomm_event.h>
46 #include <net/irda/ircomm_tty.h>
47 #include <net/irda/ircomm_tty_attach.h>
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);
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);
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 *** ",
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 ****",
111 #endif /* CONFIG_IRDA_DEBUG */
113 static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
114 struct sk_buff *skb, struct ircomm_tty_info *info) =
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,
125 * Function ircomm_tty_attach_cable (driver)
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.
131 int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
133 IRDA_DEBUG(0, "%s()\n", __func__ );
135 IRDA_ASSERT(self != NULL, return -1;);
136 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
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;
144 /* Make sure nobody tries to write before the link is up */
145 self->tty->hw_stopped = 1;
147 ircomm_tty_ias_register(self);
149 ircomm_tty_do_event(self, IRCOMM_TTY_ATTACH_CABLE, NULL, NULL);
151 return 0;
155 * Function ircomm_detach_cable (driver)
157 * Detach cable, or cable has been detached by peer
160 void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
162 IRDA_DEBUG(0, "%s()\n", __func__ );
164 IRDA_ASSERT(self != NULL, return;);
165 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
167 del_timer(&self->watchdog_timer);
169 /* Remove discovery handler */
170 if (self->ckey) {
171 irlmp_unregister_client(self->ckey);
172 self->ckey = NULL;
174 /* Remove IrCOMM hint bits */
175 if (self->skey) {
176 irlmp_unregister_service(self->skey);
177 self->skey = NULL;
180 if (self->iriap) {
181 iriap_close(self->iriap);
182 self->iriap = NULL;
185 /* Remove LM-IAS object */
186 if (self->obj) {
187 irias_delete_object(self->obj);
188 self->obj = NULL;
191 ircomm_tty_do_event(self, IRCOMM_TTY_DETACH_CABLE, NULL, NULL);
193 /* Reset some values */
194 self->daddr = self->saddr = 0;
195 self->dlsap_sel = self->slsap_sel = 0;
197 memset(&self->settings, 0, sizeof(struct ircomm_params));
201 * Function ircomm_tty_ias_register (self)
203 * Register with LM-IAS depending on which service type we are
206 static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
208 __u8 oct_seq[6];
209 __u16 hints;
211 IRDA_DEBUG(0, "%s()\n", __func__ );
213 IRDA_ASSERT(self != NULL, return;);
214 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
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);
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);
230 /* If already done, no need to do it again */
231 if (self->obj)
232 return;
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);
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);
250 /* Register parameters with LM-IAS */
251 irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6,
252 IAS_KERNEL_ATTR);
254 irias_insert_object(self->obj);
258 * Function ircomm_tty_ias_unregister (self)
260 * Remove our IAS object and client hook while connected.
263 static void ircomm_tty_ias_unregister(struct ircomm_tty_cb *self)
265 if (self->obj) {
266 irias_delete_object(self->obj);
267 self->obj = NULL;
273 * Function ircomm_send_initial_parameters (self)
275 * Send initial parameters to the remote IrCOMM device. These parameters
276 * must be sent before any data.
278 int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)
280 IRDA_ASSERT(self != NULL, return -1;);
281 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
283 if (self->service_type & IRCOMM_3_WIRE_RAW)
284 return 0;
287 * Set default values, but only if the application for some reason
288 * haven't set them already
290 IRDA_DEBUG(2, "%s(), data-rate = %d\n", __func__ ,
291 self->settings.data_rate);
292 if (!self->settings.data_rate)
293 self->settings.data_rate = 9600;
294 IRDA_DEBUG(2, "%s(), data-format = %d\n", __func__ ,
295 self->settings.data_format);
296 if (!self->settings.data_format)
297 self->settings.data_format = IRCOMM_WSIZE_8; /* 8N1 */
299 IRDA_DEBUG(2, "%s(), flow-control = %d\n", __func__ ,
300 self->settings.flow_control);
301 /*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/
303 /* Do not set delta values for the initial parameters */
304 self->settings.dte = IRCOMM_DTR | IRCOMM_RTS;
306 /* Only send service type parameter when we are the client */
307 if (self->client)
308 ircomm_param_request(self, IRCOMM_SERVICE_TYPE, FALSE);
309 ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);
310 ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
312 /* For a 3 wire service, we just flush the last parameter and return */
313 if (self->settings.service_type == IRCOMM_3_WIRE) {
314 ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE);
315 return 0;
318 /* Only 9-wire service types continue here */
319 ircomm_param_request(self, IRCOMM_FLOW_CONTROL, FALSE);
320 /* Notify peer that we are ready to receive data */
321 ircomm_param_request(self, IRCOMM_DTE, TRUE);
323 return 0;
327 * Function ircomm_tty_discovery_indication (discovery)
329 * Remote device is discovered, try query the remote IAS to see which
330 * device it is, and which services it has.
333 static void ircomm_tty_discovery_indication(discinfo_t *discovery,
334 DISCOVERY_MODE mode,
335 void *priv)
337 struct ircomm_tty_cb *self;
338 struct ircomm_tty_info info;
340 IRDA_DEBUG(2, "%s()\n", __func__ );
342 if(mode == DISCOVERY_PASSIVE)
343 return;
345 info.daddr = discovery->daddr;
346 info.saddr = discovery->saddr;
348 self = (struct ircomm_tty_cb *) priv;
349 ircomm_tty_do_event(self, IRCOMM_TTY_DISCOVERY_INDICATION,
350 NULL, &info);
354 * Function ircomm_tty_disconnect_indication (instance, sap, reason, skb)
356 * Link disconnected
359 void ircomm_tty_disconnect_indication(void *instance, void *sap,
360 LM_REASON reason,
361 struct sk_buff *skb)
363 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
365 IRDA_DEBUG(2, "%s()\n", __func__ );
367 IRDA_ASSERT(self != NULL, return;);
368 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
370 if (!self->tty)
371 return;
373 /* This will stop control data transfers */
374 self->flow = FLOW_STOP;
376 /* Stop data transfers */
377 self->tty->hw_stopped = 1;
379 ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL,
380 NULL);
384 * Function ircomm_tty_getvalue_confirm (result, obj_id, value, priv)
386 * Got result from the IAS query we make
389 static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,
390 struct ias_value *value,
391 void *priv)
393 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv;
395 IRDA_DEBUG(2, "%s()\n", __func__ );
397 IRDA_ASSERT(self != NULL, return;);
398 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
400 /* We probably don't need to make any more queries */
401 iriap_close(self->iriap);
402 self->iriap = NULL;
404 /* Check if request succeeded */
405 if (result != IAS_SUCCESS) {
406 IRDA_DEBUG(4, "%s(), got NULL value!\n", __func__ );
407 return;
410 switch (value->type) {
411 case IAS_OCT_SEQ:
412 IRDA_DEBUG(2, "%s(), got octet sequence\n", __func__ );
414 irda_param_extract_all(self, value->t.oct_seq, value->len,
415 &ircomm_param_info);
417 ircomm_tty_do_event(self, IRCOMM_TTY_GOT_PARAMETERS, NULL,
418 NULL);
419 break;
420 case IAS_INTEGER:
421 /* Got LSAP selector */
422 IRDA_DEBUG(2, "%s(), got lsapsel = %d\n", __func__ ,
423 value->t.integer);
425 if (value->t.integer == -1) {
426 IRDA_DEBUG(0, "%s(), invalid value!\n", __func__ );
427 } else
428 self->dlsap_sel = value->t.integer;
430 ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL);
431 break;
432 case IAS_MISSING:
433 IRDA_DEBUG(0, "%s(), got IAS_MISSING\n", __func__ );
434 break;
435 default:
436 IRDA_DEBUG(0, "%s(), got unknown type!\n", __func__ );
437 break;
439 irias_delete_value(value);
443 * Function ircomm_tty_connect_confirm (instance, sap, qos, max_sdu_size, skb)
445 * Connection confirmed
448 void ircomm_tty_connect_confirm(void *instance, void *sap,
449 struct qos_info *qos,
450 __u32 max_data_size,
451 __u8 max_header_size,
452 struct sk_buff *skb)
454 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
456 IRDA_DEBUG(2, "%s()\n", __func__ );
458 IRDA_ASSERT(self != NULL, return;);
459 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
461 self->client = TRUE;
462 self->max_data_size = max_data_size;
463 self->max_header_size = max_header_size;
464 self->flow = FLOW_START;
466 ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL);
468 /* No need to kfree_skb - see ircomm_ttp_connect_confirm() */
472 * Function ircomm_tty_connect_indication (instance, sap, qos, max_sdu_size,
473 * skb)
475 * we are discovered and being requested to connect by remote device !
478 void ircomm_tty_connect_indication(void *instance, void *sap,
479 struct qos_info *qos,
480 __u32 max_data_size,
481 __u8 max_header_size,
482 struct sk_buff *skb)
484 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
485 int clen;
487 IRDA_DEBUG(2, "%s()\n", __func__ );
489 IRDA_ASSERT(self != NULL, return;);
490 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
492 self->client = FALSE;
493 self->max_data_size = max_data_size;
494 self->max_header_size = max_header_size;
495 self->flow = FLOW_START;
497 clen = skb->data[0];
498 if (clen)
499 irda_param_extract_all(self, skb->data+1,
500 IRDA_MIN(skb->len, clen),
501 &ircomm_param_info);
503 ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL);
505 /* No need to kfree_skb - see ircomm_ttp_connect_indication() */
509 * Function ircomm_tty_link_established (self)
511 * Called when the IrCOMM link is established
514 void ircomm_tty_link_established(struct ircomm_tty_cb *self)
516 IRDA_DEBUG(2, "%s()\n", __func__ );
518 IRDA_ASSERT(self != NULL, return;);
519 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
521 if (!self->tty)
522 return;
524 del_timer(&self->watchdog_timer);
527 * IrCOMM link is now up, and if we are not using hardware
528 * flow-control, then declare the hardware as running. Otherwise we
529 * will have to wait for the peer device (DCE) to raise the CTS
530 * line.
532 if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {
533 IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ );
534 return;
535 } else {
536 IRDA_DEBUG(1, "%s(), starting hardware!\n", __func__ );
538 self->tty->hw_stopped = 0;
540 /* Wake up processes blocked on open */
541 wake_up_interruptible(&self->open_wait);
544 schedule_work(&self->tqueue);
548 * Function ircomm_tty_start_watchdog_timer (self, timeout)
550 * Start the watchdog timer. This timer is used to make sure that any
551 * connection attempt is successful, and if not, we will retry after
552 * the timeout
554 static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self,
555 int timeout)
557 IRDA_ASSERT(self != NULL, return;);
558 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
560 irda_start_timer(&self->watchdog_timer, timeout, (void *) self,
561 ircomm_tty_watchdog_timer_expired);
565 * Function ircomm_tty_watchdog_timer_expired (data)
567 * Called when the connect procedure have taken to much time.
570 static void ircomm_tty_watchdog_timer_expired(void *data)
572 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data;
574 IRDA_DEBUG(2, "%s()\n", __func__ );
576 IRDA_ASSERT(self != NULL, return;);
577 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
579 ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL);
584 * Function ircomm_tty_do_event (self, event, skb)
586 * Process event
589 int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
590 struct sk_buff *skb, struct ircomm_tty_info *info)
592 IRDA_ASSERT(self != NULL, return -1;);
593 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
595 IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
596 ircomm_tty_state[self->state], ircomm_tty_event[event]);
598 return (*state[self->state])(self, event, skb, info);
602 * Function ircomm_tty_next_state (self, state)
604 * Switch state
607 static inline void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
610 IRDA_ASSERT(self != NULL, return;);
611 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
613 IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __func__ ,
614 ircomm_tty_state[self->state], self->service_type);
616 self->state = state;
620 * Function ircomm_tty_state_idle (self, event, skb, info)
622 * Just hanging around
625 static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,
626 IRCOMM_TTY_EVENT event,
627 struct sk_buff *skb,
628 struct ircomm_tty_info *info)
630 int ret = 0;
632 IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
633 ircomm_tty_state[self->state], ircomm_tty_event[event]);
634 switch (event) {
635 case IRCOMM_TTY_ATTACH_CABLE:
636 /* Try to discover any remote devices */
637 ircomm_tty_start_watchdog_timer(self, 3*HZ);
638 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
640 irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
641 break;
642 case IRCOMM_TTY_DISCOVERY_INDICATION:
643 self->daddr = info->daddr;
644 self->saddr = info->saddr;
646 if (self->iriap) {
647 IRDA_WARNING("%s(), busy with a previous query\n",
648 __func__);
649 return -EBUSY;
652 self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
653 ircomm_tty_getvalue_confirm);
655 iriap_getvaluebyclass_request(self->iriap,
656 self->saddr, self->daddr,
657 "IrDA:IrCOMM", "Parameters");
659 ircomm_tty_start_watchdog_timer(self, 3*HZ);
660 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
661 break;
662 case IRCOMM_TTY_CONNECT_INDICATION:
663 del_timer(&self->watchdog_timer);
665 /* Accept connection */
666 ircomm_connect_response(self->ircomm, NULL);
667 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
668 break;
669 case IRCOMM_TTY_WD_TIMER_EXPIRED:
670 /* Just stay idle */
671 break;
672 case IRCOMM_TTY_DETACH_CABLE:
673 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
674 break;
675 default:
676 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
677 ircomm_tty_event[event]);
678 ret = -EINVAL;
680 return ret;
684 * Function ircomm_tty_state_search (self, event, skb, info)
686 * Trying to discover an IrCOMM device
689 static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
690 IRCOMM_TTY_EVENT event,
691 struct sk_buff *skb,
692 struct ircomm_tty_info *info)
694 int ret = 0;
696 IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
697 ircomm_tty_state[self->state], ircomm_tty_event[event]);
699 switch (event) {
700 case IRCOMM_TTY_DISCOVERY_INDICATION:
701 self->daddr = info->daddr;
702 self->saddr = info->saddr;
704 if (self->iriap) {
705 IRDA_WARNING("%s(), busy with a previous query\n",
706 __func__);
707 return -EBUSY;
710 self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
711 ircomm_tty_getvalue_confirm);
713 if (self->service_type == IRCOMM_3_WIRE_RAW) {
714 iriap_getvaluebyclass_request(self->iriap, self->saddr,
715 self->daddr, "IrLPT",
716 "IrDA:IrLMP:LsapSel");
717 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
718 } else {
719 iriap_getvaluebyclass_request(self->iriap, self->saddr,
720 self->daddr,
721 "IrDA:IrCOMM",
722 "Parameters");
724 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
726 ircomm_tty_start_watchdog_timer(self, 3*HZ);
727 break;
728 case IRCOMM_TTY_CONNECT_INDICATION:
729 del_timer(&self->watchdog_timer);
730 ircomm_tty_ias_unregister(self);
732 /* Accept connection */
733 ircomm_connect_response(self->ircomm, NULL);
734 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
735 break;
736 case IRCOMM_TTY_WD_TIMER_EXPIRED:
737 /* Give up */
738 break;
739 case IRCOMM_TTY_DETACH_CABLE:
740 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
741 break;
742 default:
743 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
744 ircomm_tty_event[event]);
745 ret = -EINVAL;
747 return ret;
751 * Function ircomm_tty_state_query (self, event, skb, info)
753 * Querying the remote LM-IAS for IrCOMM parameters
756 static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,
757 IRCOMM_TTY_EVENT event,
758 struct sk_buff *skb,
759 struct ircomm_tty_info *info)
761 int ret = 0;
763 IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
764 ircomm_tty_state[self->state], ircomm_tty_event[event]);
766 switch (event) {
767 case IRCOMM_TTY_GOT_PARAMETERS:
768 if (self->iriap) {
769 IRDA_WARNING("%s(), busy with a previous query\n",
770 __func__);
771 return -EBUSY;
774 self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
775 ircomm_tty_getvalue_confirm);
777 iriap_getvaluebyclass_request(self->iriap, self->saddr,
778 self->daddr, "IrDA:IrCOMM",
779 "IrDA:TinyTP:LsapSel");
781 ircomm_tty_start_watchdog_timer(self, 3*HZ);
782 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
783 break;
784 case IRCOMM_TTY_WD_TIMER_EXPIRED:
785 /* Go back to search mode */
786 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
787 ircomm_tty_start_watchdog_timer(self, 3*HZ);
788 break;
789 case IRCOMM_TTY_CONNECT_INDICATION:
790 del_timer(&self->watchdog_timer);
791 ircomm_tty_ias_unregister(self);
793 /* Accept connection */
794 ircomm_connect_response(self->ircomm, NULL);
795 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
796 break;
797 case IRCOMM_TTY_DETACH_CABLE:
798 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
799 break;
800 default:
801 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
802 ircomm_tty_event[event]);
803 ret = -EINVAL;
805 return ret;
809 * Function ircomm_tty_state_query_lsap_sel (self, event, skb, info)
811 * Query remote LM-IAS for the LSAP selector which we can connect to
814 static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,
815 IRCOMM_TTY_EVENT event,
816 struct sk_buff *skb,
817 struct ircomm_tty_info *info)
819 int ret = 0;
821 IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
822 ircomm_tty_state[self->state], ircomm_tty_event[event]);
824 switch (event) {
825 case IRCOMM_TTY_GOT_LSAPSEL:
826 /* Connect to remote device */
827 ret = ircomm_connect_request(self->ircomm, self->dlsap_sel,
828 self->saddr, self->daddr,
829 NULL, self->service_type);
830 ircomm_tty_start_watchdog_timer(self, 3*HZ);
831 ircomm_tty_next_state(self, IRCOMM_TTY_SETUP);
832 break;
833 case IRCOMM_TTY_WD_TIMER_EXPIRED:
834 /* Go back to search mode */
835 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
836 ircomm_tty_start_watchdog_timer(self, 3*HZ);
837 break;
838 case IRCOMM_TTY_CONNECT_INDICATION:
839 del_timer(&self->watchdog_timer);
840 ircomm_tty_ias_unregister(self);
842 /* Accept connection */
843 ircomm_connect_response(self->ircomm, NULL);
844 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
845 break;
846 case IRCOMM_TTY_DETACH_CABLE:
847 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
848 break;
849 default:
850 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
851 ircomm_tty_event[event]);
852 ret = -EINVAL;
854 return ret;
858 * Function ircomm_tty_state_setup (self, event, skb, info)
860 * Trying to connect
863 static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
864 IRCOMM_TTY_EVENT event,
865 struct sk_buff *skb,
866 struct ircomm_tty_info *info)
868 int ret = 0;
870 IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
871 ircomm_tty_state[self->state], ircomm_tty_event[event]);
873 switch (event) {
874 case IRCOMM_TTY_CONNECT_CONFIRM:
875 del_timer(&self->watchdog_timer);
876 ircomm_tty_ias_unregister(self);
879 * Send initial parameters. This will also send out queued
880 * parameters waiting for the connection to come up
882 ircomm_tty_send_initial_parameters(self);
883 ircomm_tty_link_established(self);
884 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
885 break;
886 case IRCOMM_TTY_CONNECT_INDICATION:
887 del_timer(&self->watchdog_timer);
888 ircomm_tty_ias_unregister(self);
890 /* Accept connection */
891 ircomm_connect_response(self->ircomm, NULL);
892 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
893 break;
894 case IRCOMM_TTY_WD_TIMER_EXPIRED:
895 /* Go back to search mode */
896 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
897 ircomm_tty_start_watchdog_timer(self, 3*HZ);
898 break;
899 case IRCOMM_TTY_DETACH_CABLE:
900 /* ircomm_disconnect_request(self->ircomm, NULL); */
901 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
902 break;
903 default:
904 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
905 ircomm_tty_event[event]);
906 ret = -EINVAL;
908 return ret;
912 * Function ircomm_tty_state_ready (self, event, skb, info)
914 * IrCOMM is now connected
917 static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
918 IRCOMM_TTY_EVENT event,
919 struct sk_buff *skb,
920 struct ircomm_tty_info *info)
922 int ret = 0;
924 switch (event) {
925 case IRCOMM_TTY_DATA_REQUEST:
926 ret = ircomm_data_request(self->ircomm, skb);
927 break;
928 case IRCOMM_TTY_DETACH_CABLE:
929 ircomm_disconnect_request(self->ircomm, NULL);
930 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
931 break;
932 case IRCOMM_TTY_DISCONNECT_INDICATION:
933 ircomm_tty_ias_register(self);
934 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
935 ircomm_tty_start_watchdog_timer(self, 3*HZ);
937 if (self->flags & ASYNC_CHECK_CD) {
938 /* Drop carrier */
939 self->settings.dce = IRCOMM_DELTA_CD;
940 ircomm_tty_check_modem_status(self);
941 } else {
942 IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ );
943 if (self->tty)
944 tty_hangup(self->tty);
946 break;
947 default:
948 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
949 ircomm_tty_event[event]);
950 ret = -EINVAL;
952 return ret;