Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/irda/ircomm/ircomm_tty_attach.c
15111 views
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 <[email protected]>
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 <[email protected]>
11
*
12
* Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
13
* Copyright (c) 2000-2003 Jean Tourrilhes <[email protected]>
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
998
999