OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [irda/] [ircomm/] [ircomm_tty_attach.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.