Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / net / irda / ircomm / ircomm_tty_attach.c
blobad5ee4b0f28b0d694adeaef217531cccc0bd1f03
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>
12 * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2 of
17 * the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
27 * MA 02111-1307 USA
29 ********************************************************************/
31 #include <linux/sched.h>
32 #include <linux/init.h>
34 #include <net/irda/irda.h>
35 #include <net/irda/irlmp.h>
36 #include <net/irda/iriap.h>
37 #include <net/irda/irttp.h>
38 #include <net/irda/irias_object.h>
39 #include <net/irda/parameters.h>
41 #include <net/irda/ircomm_core.h>
42 #include <net/irda/ircomm_param.h>
43 #include <net/irda/ircomm_event.h>
45 #include <net/irda/ircomm_tty.h>
46 #include <net/irda/ircomm_tty_attach.h>
48 static void ircomm_tty_ias_register(struct ircomm_tty_cb *self);
49 static void ircomm_tty_discovery_indication(discovery_t *discovery,
50 void *priv);
51 static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,
52 struct ias_value *value, void *priv);
53 void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout);
54 void ircomm_tty_watchdog_timer_expired(void *data);
56 static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,
57 IRCOMM_TTY_EVENT event,
58 struct sk_buff *skb,
59 struct ircomm_tty_info *info);
60 static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
61 IRCOMM_TTY_EVENT event,
62 struct sk_buff *skb,
63 struct ircomm_tty_info *info);
64 static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,
65 IRCOMM_TTY_EVENT event,
66 struct sk_buff *skb,
67 struct ircomm_tty_info *info);
68 static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,
69 IRCOMM_TTY_EVENT event,
70 struct sk_buff *skb,
71 struct ircomm_tty_info *info);
72 static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
73 IRCOMM_TTY_EVENT event,
74 struct sk_buff *skb,
75 struct ircomm_tty_info *info);
76 static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
77 IRCOMM_TTY_EVENT event,
78 struct sk_buff *skb,
79 struct ircomm_tty_info *info);
81 char *ircomm_tty_state[] = {
82 "IRCOMM_TTY_IDLE",
83 "IRCOMM_TTY_SEARCH",
84 "IRCOMM_TTY_QUERY_PARAMETERS",
85 "IRCOMM_TTY_QUERY_LSAP_SEL",
86 "IRCOMM_TTY_SETUP",
87 "IRCOMM_TTY_READY",
88 "*** ERROR *** ",
91 char *ircomm_tty_event[] = {
92 "IRCOMM_TTY_ATTACH_CABLE",
93 "IRCOMM_TTY_DETACH_CABLE",
94 "IRCOMM_TTY_DATA_REQUEST",
95 "IRCOMM_TTY_DATA_INDICATION",
96 "IRCOMM_TTY_DISCOVERY_REQUEST",
97 "IRCOMM_TTY_DISCOVERY_INDICATION",
98 "IRCOMM_TTY_CONNECT_CONFIRM",
99 "IRCOMM_TTY_CONNECT_INDICATION",
100 "IRCOMM_TTY_DISCONNECT_REQUEST",
101 "IRCOMM_TTY_DISCONNECT_INDICATION",
102 "IRCOMM_TTY_WD_TIMER_EXPIRED",
103 "IRCOMM_TTY_GOT_PARAMETERS",
104 "IRCOMM_TTY_GOT_LSAPSEL",
105 "*** ERROR ****",
108 static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
109 struct sk_buff *skb, struct ircomm_tty_info *info) =
111 ircomm_tty_state_idle,
112 ircomm_tty_state_search,
113 ircomm_tty_state_query_parameters,
114 ircomm_tty_state_query_lsap_sel,
115 ircomm_tty_state_setup,
116 ircomm_tty_state_ready,
120 * Function ircomm_tty_attach_cable (driver)
122 * Try to attach cable (IrCOMM link). This function will only return
123 * when the link has been connected, or if an error condition occurs.
124 * If success, the return value is the resulting service type.
126 int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
128 IRDA_DEBUG(0, __FUNCTION__ "()\n");
130 ASSERT(self != NULL, return -1;);
131 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
133 /* Check if somebody has already connected to us */
134 if (ircomm_is_connected(self->ircomm)) {
135 IRDA_DEBUG(0, __FUNCTION__ "(), already connected!\n");
136 return 0;
139 /* Make sure nobody tries to write before the link is up */
140 self->tty->hw_stopped = 1;
142 ircomm_tty_ias_register(self);
144 /* Check if somebody has already connected to us */
145 if (ircomm_is_connected(self->ircomm)) {
146 IRDA_DEBUG(0, __FUNCTION__ "(), already connected!\n");
147 return 0;
150 ircomm_tty_do_event(self, IRCOMM_TTY_ATTACH_CABLE, NULL, NULL);
152 return 0;
156 * Function ircomm_detach_cable (driver)
158 * Detach cable, or cable has been detached by peer
161 void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
163 IRDA_DEBUG(0, __FUNCTION__ "()\n");
165 ASSERT(self != NULL, return;);
166 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
168 del_timer(&self->watchdog_timer);
170 /* Remove IrCOMM hint bits */
171 irlmp_unregister_client(self->ckey);
172 irlmp_unregister_service(self->skey);
174 if (self->iriap) {
175 iriap_close(self->iriap);
176 self->iriap = NULL;
179 /* Remove LM-IAS object */
180 if (self->obj) {
181 irias_delete_object(self->obj);
182 self->obj = NULL;
185 ircomm_tty_do_event(self, IRCOMM_TTY_DETACH_CABLE, NULL, NULL);
187 /* Reset some values */
188 self->daddr = self->saddr = 0;
189 self->dlsap_sel = self->slsap_sel = 0;
191 memset(&self->settings, 0, sizeof(struct ircomm_params));
195 * Function ircomm_tty_ias_register (self)
197 * Register with LM-IAS depending on which service type we are
200 static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
202 __u8 oct_seq[6];
203 __u16 hints;
205 IRDA_DEBUG(0, __FUNCTION__ "()\n");
207 ASSERT(self != NULL, return;);
208 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
210 if (self->service_type & IRCOMM_3_WIRE_RAW) {
211 hints = irlmp_service_to_hint(S_PRINTER);
212 hints |= irlmp_service_to_hint(S_COMM);
214 /* Register IrLPT with LM-IAS */
215 self->obj = irias_new_object("IrLPT", IAS_IRLPT_ID);
216 irias_add_integer_attrib(self->obj, "IrDA:IrLMP:LsapSel",
217 self->slsap_sel, IAS_KERNEL_ATTR);
218 irias_insert_object(self->obj);
219 } else {
220 hints = irlmp_service_to_hint(S_COMM);
222 /* Register IrCOMM with LM-IAS */
223 self->obj = irias_new_object("IrDA:IrCOMM", IAS_IRCOMM_ID);
224 irias_add_integer_attrib(self->obj, "IrDA:TinyTP:LsapSel",
225 self->slsap_sel, IAS_KERNEL_ATTR);
227 /* Code the parameters into the buffer */
228 irda_param_pack(oct_seq, "bbbbbb",
229 IRCOMM_SERVICE_TYPE, 1, self->service_type,
230 IRCOMM_PORT_TYPE, 1, IRCOMM_SERIAL);
232 /* Register parameters with LM-IAS */
233 irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6,
234 IAS_KERNEL_ATTR);
235 irias_insert_object(self->obj);
237 self->skey = irlmp_register_service(hints);
238 self->ckey = irlmp_register_client(
239 hints, ircomm_tty_discovery_indication, NULL, (void *) self);
243 * Function ircomm_send_initial_parameters (self)
245 * Send initial parameters to the remote IrCOMM device. These parameters
246 * must be sent before any data.
248 int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)
250 ASSERT(self != NULL, return -1;);
251 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
253 if (self->service_type & IRCOMM_3_WIRE_RAW)
254 return 0;
257 * Set default values, but only if the application for some reason
258 * haven't set them already
260 IRDA_DEBUG(2, __FUNCTION__ "(), data-rate = %d\n",
261 self->settings.data_rate);
262 if (!self->settings.data_rate)
263 self->settings.data_rate = 9600;
264 IRDA_DEBUG(2, __FUNCTION__ "(), data-format = %d\n",
265 self->settings.data_format);
266 if (!self->settings.data_format)
267 self->settings.data_format = IRCOMM_WSIZE_8; /* 8N1 */
269 IRDA_DEBUG(2, __FUNCTION__ "(), flow-control = %d\n",
270 self->settings.flow_control);
271 /*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/
273 /* Do not set delta values for the initial parameters */
274 self->settings.dte = IRCOMM_DTR | IRCOMM_RTS;
276 /* Only send service type parameter when we are the client */
277 if (self->client)
278 ircomm_param_request(self, IRCOMM_SERVICE_TYPE, FALSE);
279 ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);
280 ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
282 /* For a 3 wire service, we just flush the last parameter and return */
283 if (self->settings.service_type == IRCOMM_3_WIRE) {
284 ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE);
285 return 0;
288 /* Only 9-wire service types continue here */
289 ircomm_param_request(self, IRCOMM_FLOW_CONTROL, FALSE);
290 #if 0
291 ircomm_param_request(self, IRCOMM_XON_XOFF, FALSE);
292 ircomm_param_request(self, IRCOMM_ENQ_ACK, FALSE);
293 #endif
294 /* Notify peer that we are ready to receive data */
295 ircomm_param_request(self, IRCOMM_DTE, TRUE);
297 return 0;
301 * Function ircomm_tty_discovery_indication (discovery)
303 * Remote device is discovered, try query the remote IAS to see which
304 * device it is, and which services it has.
307 static void ircomm_tty_discovery_indication(discovery_t *discovery,
308 void *priv)
310 struct ircomm_tty_cb *self;
311 struct ircomm_tty_info info;
313 IRDA_DEBUG(2, __FUNCTION__"()\n");
315 info.daddr = discovery->daddr;
316 info.saddr = discovery->saddr;
318 self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
319 while (self != NULL) {
320 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
322 ircomm_tty_do_event(self, IRCOMM_TTY_DISCOVERY_INDICATION,
323 NULL, &info);
325 self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty);
330 * Function ircomm_tty_disconnect_indication (instance, sap, reason, skb)
332 * Link disconnected
335 void ircomm_tty_disconnect_indication(void *instance, void *sap,
336 LM_REASON reason,
337 struct sk_buff *skb)
339 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
341 IRDA_DEBUG(2, __FUNCTION__ "()\n");
343 ASSERT(self != NULL, return;);
344 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
346 if (!self->tty)
347 return;
349 /* This will stop control data transfers */
350 self->flow = FLOW_STOP;
352 /* Stop data transfers */
353 self->tty->hw_stopped = 1;
355 ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL,
356 NULL);
360 * Function ircomm_tty_getvalue_confirm (result, obj_id, value, priv)
362 * Got result from the IAS query we make
365 static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,
366 struct ias_value *value,
367 void *priv)
369 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv;
371 IRDA_DEBUG(2, __FUNCTION__"()\n");
373 ASSERT(self != NULL, return;);
374 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
376 /* We probably don't need to make any more queries */
377 iriap_close(self->iriap);
378 self->iriap = NULL;
380 /* Check if request succeeded */
381 if (result != IAS_SUCCESS) {
382 IRDA_DEBUG(4, __FUNCTION__ "(), got NULL value!\n");
383 return;
386 switch (value->type) {
387 case IAS_OCT_SEQ:
388 IRDA_DEBUG(2, __FUNCTION__"(), got octet sequence\n");
390 irda_param_extract_all(self, value->t.oct_seq, value->len,
391 &ircomm_param_info);
393 ircomm_tty_do_event(self, IRCOMM_TTY_GOT_PARAMETERS, NULL,
394 NULL);
395 break;
396 case IAS_INTEGER:
397 /* Got LSAP selector */
398 IRDA_DEBUG(2, __FUNCTION__"(), got lsapsel = %d\n",
399 value->t.integer);
401 if (value->t.integer == -1) {
402 IRDA_DEBUG(0, __FUNCTION__"(), invalid value!\n");
403 } else
404 self->dlsap_sel = value->t.integer;
406 ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL);
407 break;
408 case IAS_MISSING:
409 IRDA_DEBUG(0, __FUNCTION__"(), got IAS_MISSING\n");
410 break;
411 default:
412 IRDA_DEBUG(0, __FUNCTION__"(), got unknown type!\n");
413 break;
415 irias_delete_value(value);
419 * Function ircomm_tty_connect_confirm (instance, sap, qos, max_sdu_size, skb)
421 * Connection confirmed
424 void ircomm_tty_connect_confirm(void *instance, void *sap,
425 struct qos_info *qos,
426 __u32 max_data_size,
427 __u8 max_header_size,
428 struct sk_buff *skb)
430 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
432 IRDA_DEBUG(2, __FUNCTION__ "()\n");
434 ASSERT(self != NULL, return;);
435 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
437 self->client = TRUE;
438 self->max_data_size = max_data_size;
439 self->max_header_size = max_header_size;
440 self->flow = FLOW_START;
442 ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL);
444 dev_kfree_skb(skb);
448 * Function ircomm_tty_connect_indication (instance, sap, qos, max_sdu_size,
449 * skb)
451 * we are discovered and being requested to connect by remote device !
454 void ircomm_tty_connect_indication(void *instance, void *sap,
455 struct qos_info *qos,
456 __u32 max_data_size,
457 __u8 max_header_size,
458 struct sk_buff *skb)
460 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
461 int clen;
463 IRDA_DEBUG(2, __FUNCTION__ "()\n");
465 ASSERT(self != NULL, return;);
466 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
468 self->client = FALSE;
469 self->max_data_size = max_data_size;
470 self->max_header_size = max_header_size;
471 self->flow = FLOW_START;
473 clen = skb->data[0];
474 if (clen)
475 irda_param_extract_all(self, skb->data+1,
476 IRDA_MIN(skb->len, clen),
477 &ircomm_param_info);
479 ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL);
481 dev_kfree_skb(skb);
485 * Function ircomm_tty_link_established (self)
487 * Called when the IrCOMM link is established
490 void ircomm_tty_link_established(struct ircomm_tty_cb *self)
492 IRDA_DEBUG(2, __FUNCTION__ "()\n");
494 ASSERT(self != NULL, return;);
495 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
497 if (!self->tty)
498 return;
500 del_timer(&self->watchdog_timer);
503 * IrCOMM link is now up, and if we are not using hardware
504 * flow-control, then declare the hardware as running. Otherwise we
505 * will have to wait for the peer device (DCE) to raise the CTS
506 * line.
508 if (self->flags & ASYNC_CTS_FLOW) {
509 IRDA_DEBUG(0, __FUNCTION__ "(), waiting for CTS ...\n");
510 return;
511 } else {
512 IRDA_DEBUG(2, __FUNCTION__ "(), starting hardware!\n");
514 self->tty->hw_stopped = 0;
516 /* Wake up processes blocked on open */
517 wake_up_interruptible(&self->open_wait);
520 queue_task(&self->tqueue, &tq_immediate);
521 mark_bh(IMMEDIATE_BH);
525 * Function irlan_start_watchdog_timer (self, timeout)
527 * Start the watchdog timer. This timer is used to make sure that any
528 * connection attempt is successful, and if not, we will retry after
529 * the timeout
531 void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout)
533 ASSERT(self != NULL, return;);
534 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
536 irda_start_timer(&self->watchdog_timer, timeout, (void *) self,
537 ircomm_tty_watchdog_timer_expired);
541 * Function ircomm_tty_watchdog_timer_expired (data)
543 * Called when the connect procedure have taken to much time.
546 void ircomm_tty_watchdog_timer_expired(void *data)
548 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data;
550 IRDA_DEBUG(2, __FUNCTION__ "()\n");
552 ASSERT(self != NULL, return;);
553 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
555 ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL);
559 * Function ircomm_tty_state_idle (self, event, skb, info)
561 * Just hanging around
564 static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,
565 IRCOMM_TTY_EVENT event,
566 struct sk_buff *skb,
567 struct ircomm_tty_info *info)
569 int ret = 0;
571 IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
572 ircomm_tty_state[self->state], ircomm_tty_event[event]);
573 switch (event) {
574 case IRCOMM_TTY_ATTACH_CABLE:
575 /* Try to discover any remote devices */
576 ircomm_tty_start_watchdog_timer(self, 3*HZ);
577 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
579 irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
580 break;
581 case IRCOMM_TTY_DISCOVERY_INDICATION:
582 self->daddr = info->daddr;
583 self->saddr = info->saddr;
585 if (self->iriap) {
586 WARNING(__FUNCTION__
587 "(), busy with a previous query\n");
588 return -EBUSY;
591 self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
592 ircomm_tty_getvalue_confirm);
594 iriap_getvaluebyclass_request(self->iriap,
595 self->saddr, self->daddr,
596 "IrDA:IrCOMM", "Parameters");
598 ircomm_tty_start_watchdog_timer(self, 3*HZ);
599 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
600 break;
601 case IRCOMM_TTY_CONNECT_INDICATION:
602 del_timer(&self->watchdog_timer);
604 /* Accept connection */
605 ircomm_connect_response(self->ircomm, NULL);
606 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
607 break;
608 case IRCOMM_TTY_WD_TIMER_EXPIRED:
609 /* Just stay idle */
610 break;
611 case IRCOMM_TTY_DETACH_CABLE:
612 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
613 break;
614 default:
615 IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %s\n",
616 ircomm_tty_event[event]);
617 return -EINVAL;
619 return ret;
623 * Function ircomm_tty_state_search (self, event, skb, info)
625 * Trying to discover an IrCOMM device
628 static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
629 IRCOMM_TTY_EVENT event,
630 struct sk_buff *skb,
631 struct ircomm_tty_info *info)
633 int ret = 0;
635 IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
636 ircomm_tty_state[self->state], ircomm_tty_event[event]);
638 switch (event) {
639 case IRCOMM_TTY_DISCOVERY_INDICATION:
640 self->daddr = info->daddr;
641 self->saddr = info->saddr;
643 if (self->iriap) {
644 WARNING(__FUNCTION__
645 "(), busy with a previous query\n");
646 return -EBUSY;
649 self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
650 ircomm_tty_getvalue_confirm);
652 if (self->service_type == IRCOMM_3_WIRE_RAW) {
653 iriap_getvaluebyclass_request(self->iriap, self->saddr,
654 self->daddr, "IrLPT",
655 "IrDA:IrLMP:LsapSel");
656 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
657 } else {
658 iriap_getvaluebyclass_request(self->iriap, self->saddr,
659 self->daddr,
660 "IrDA:IrCOMM",
661 "Parameters");
663 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
665 ircomm_tty_start_watchdog_timer(self, 3*HZ);
666 break;
667 case IRCOMM_TTY_CONNECT_INDICATION:
668 del_timer(&self->watchdog_timer);
670 /* Accept connection */
671 ircomm_connect_response(self->ircomm, NULL);
672 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
673 break;
674 case IRCOMM_TTY_WD_TIMER_EXPIRED:
675 #if 1
676 /* Give up */
677 #else
678 /* Try to discover any remote devices */
679 ircomm_tty_start_watchdog_timer(self, 3*HZ);
680 irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
681 #endif
682 break;
683 case IRCOMM_TTY_DETACH_CABLE:
684 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
685 break;
686 default:
687 IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %s\n",
688 ircomm_tty_event[event]);
689 return -EINVAL;
691 return ret;
695 * Function ircomm_tty_state_query (self, event, skb, info)
697 * Querying the remote LM-IAS for IrCOMM parameters
700 static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,
701 IRCOMM_TTY_EVENT event,
702 struct sk_buff *skb,
703 struct ircomm_tty_info *info)
705 int ret = 0;
707 IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
708 ircomm_tty_state[self->state], ircomm_tty_event[event]);
710 switch (event) {
711 case IRCOMM_TTY_GOT_PARAMETERS:
712 if (self->iriap) {
713 WARNING(__FUNCTION__
714 "(), busy with a previous query\n");
715 return -EBUSY;
718 self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
719 ircomm_tty_getvalue_confirm);
721 iriap_getvaluebyclass_request(self->iriap, self->saddr,
722 self->daddr, "IrDA:IrCOMM",
723 "IrDA:TinyTP:LsapSel");
725 ircomm_tty_start_watchdog_timer(self, 3*HZ);
726 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
727 break;
728 case IRCOMM_TTY_WD_TIMER_EXPIRED:
729 /* Go back to search mode */
730 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
731 ircomm_tty_start_watchdog_timer(self, 3*HZ);
732 break;
733 case IRCOMM_TTY_CONNECT_INDICATION:
734 del_timer(&self->watchdog_timer);
736 /* Accept connection */
737 ircomm_connect_response(self->ircomm, NULL);
738 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
739 break;
740 case IRCOMM_TTY_DETACH_CABLE:
741 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
742 break;
743 default:
744 IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %s\n",
745 ircomm_tty_event[event]);
746 return -EINVAL;
748 return ret;
752 * Function ircomm_tty_state_query_lsap_sel (self, event, skb, info)
754 * Query remote LM-IAS for the LSAP selector which we can connect to
757 static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,
758 IRCOMM_TTY_EVENT event,
759 struct sk_buff *skb,
760 struct ircomm_tty_info *info)
762 int ret = 0;
764 IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
765 ircomm_tty_state[self->state], ircomm_tty_event[event]);
767 switch (event) {
768 case IRCOMM_TTY_GOT_LSAPSEL:
769 /* Connect to remote device */
770 ret = ircomm_connect_request(self->ircomm, self->dlsap_sel,
771 self->saddr, self->daddr,
772 NULL, self->service_type);
773 ircomm_tty_start_watchdog_timer(self, 3*HZ);
774 ircomm_tty_next_state(self, IRCOMM_TTY_SETUP);
775 break;
776 case IRCOMM_TTY_WD_TIMER_EXPIRED:
777 /* Go back to search mode */
778 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
779 ircomm_tty_start_watchdog_timer(self, 3*HZ);
780 break;
781 case IRCOMM_TTY_CONNECT_INDICATION:
782 del_timer(&self->watchdog_timer);
784 /* Accept connection */
785 ircomm_connect_response(self->ircomm, NULL);
786 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
787 break;
788 case IRCOMM_TTY_DETACH_CABLE:
789 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
790 break;
791 default:
792 IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %s\n",
793 ircomm_tty_event[event]);
794 return -EINVAL;
796 return ret;
800 * Function ircomm_tty_state_setup (self, event, skb, info)
802 * Trying to connect
805 static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
806 IRCOMM_TTY_EVENT event,
807 struct sk_buff *skb,
808 struct ircomm_tty_info *info)
810 int ret = 0;
812 IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
813 ircomm_tty_state[self->state], ircomm_tty_event[event]);
815 switch (event) {
816 case IRCOMM_TTY_CONNECT_CONFIRM:
817 del_timer(&self->watchdog_timer);
818 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
821 * Send initial parameters. This will also send out queued
822 * parameters waiting for the connection to come up
824 ircomm_tty_send_initial_parameters(self);
825 ircomm_tty_link_established(self);
826 break;
827 case IRCOMM_TTY_CONNECT_INDICATION:
828 del_timer(&self->watchdog_timer);
830 /* Accept connection */
831 ircomm_connect_response(self->ircomm, NULL);
832 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
833 break;
834 case IRCOMM_TTY_WD_TIMER_EXPIRED:
835 /* Go back to search mode */
836 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
837 ircomm_tty_start_watchdog_timer(self, 3*HZ);
838 break;
839 case IRCOMM_TTY_DETACH_CABLE:
840 /* ircomm_disconnect_request(self->ircomm, NULL); */
841 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
842 break;
843 default:
844 IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %s\n",
845 ircomm_tty_event[event]);
846 return -EINVAL;
848 return ret;
852 * Function ircomm_tty_state_ready (self, event, skb, info)
854 * IrCOMM is now connected
857 static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
858 IRCOMM_TTY_EVENT event,
859 struct sk_buff *skb,
860 struct ircomm_tty_info *info)
862 int ret = 0;
864 switch (event) {
865 case IRCOMM_TTY_DATA_REQUEST:
866 ret = ircomm_data_request(self->ircomm, skb);
867 break;
868 case IRCOMM_TTY_DETACH_CABLE:
869 ircomm_disconnect_request(self->ircomm, NULL);
870 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
871 break;
872 case IRCOMM_TTY_DISCONNECT_INDICATION:
873 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
874 ircomm_tty_start_watchdog_timer(self, 3*HZ);
876 if (self->flags & ASYNC_CHECK_CD) {
877 /* Drop carrier */
878 self->settings.dce = IRCOMM_DELTA_CD;
879 ircomm_tty_check_modem_status(self);
880 } else {
881 IRDA_DEBUG(0, __FUNCTION__ "(), hanging up!\n");
882 if (self->tty)
883 tty_hangup(self->tty);
885 break;
886 default:
887 IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %s\n",
888 ircomm_tty_event[event]);
889 return -EINVAL;
891 return ret;
895 * Function ircomm_tty_do_event (self, event, skb)
897 * Process event
900 int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
901 struct sk_buff *skb, struct ircomm_tty_info *info)
903 ASSERT(self != NULL, return -1;);
904 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
906 IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
907 ircomm_tty_state[self->state], ircomm_tty_event[event]);
909 return (*state[self->state])(self, event, skb, info);
913 * Function ircomm_tty_next_state (self, state)
915 * Switch state
918 void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
920 ASSERT(self != NULL, return;);
921 ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
923 self->state = state;
925 IRDA_DEBUG(2, __FUNCTION__": next state=%s, service type=%d\n",
926 ircomm_tty_state[self->state], self->service_type);