aboutsummaryrefslogtreecommitdiffstats
path: root/net/irda/ircomm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/irda/ircomm
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'net/irda/ircomm')
-rw-r--r--net/irda/ircomm/Kconfig12
-rw-r--r--net/irda/ircomm/Makefile8
-rw-r--r--net/irda/ircomm/ircomm_core.c587
-rw-r--r--net/irda/ircomm/ircomm_event.c251
-rw-r--r--net/irda/ircomm/ircomm_lmp.c372
-rw-r--r--net/irda/ircomm/ircomm_param.c511
-rw-r--r--net/irda/ircomm/ircomm_ttp.c369
-rw-r--r--net/irda/ircomm/ircomm_tty.c1405
-rw-r--r--net/irda/ircomm/ircomm_tty_attach.c1006
-rw-r--r--net/irda/ircomm/ircomm_tty_ioctl.c428
10 files changed, 4949 insertions, 0 deletions
diff --git a/net/irda/ircomm/Kconfig b/net/irda/ircomm/Kconfig
new file mode 100644
index 00000000000..2d4c6b4a78d
--- /dev/null
+++ b/net/irda/ircomm/Kconfig
@@ -0,0 +1,12 @@
1config IRCOMM
2 tristate "IrCOMM protocol"
3 depends on IRDA
4 help
5 Say Y here if you want to build support for the IrCOMM protocol.
6 To compile it as modules, choose M here: the modules will be
7 called ircomm and ircomm_tty.
8 IrCOMM implements serial port emulation, and makes it possible to
9 use all existing applications that understands TTY's with an
10 infrared link. Thus you should be able to use application like PPP,
11 minicom and others.
12
diff --git a/net/irda/ircomm/Makefile b/net/irda/ircomm/Makefile
new file mode 100644
index 00000000000..48689458c08
--- /dev/null
+++ b/net/irda/ircomm/Makefile
@@ -0,0 +1,8 @@
1#
2# Makefile for the Linux IrDA IrCOMM protocol layer.
3#
4
5obj-$(CONFIG_IRCOMM) += ircomm.o ircomm-tty.o
6
7ircomm-objs := ircomm_core.o ircomm_event.o ircomm_lmp.o ircomm_ttp.o
8ircomm-tty-objs := ircomm_tty.o ircomm_tty_attach.o ircomm_tty_ioctl.o ircomm_param.o
diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c
new file mode 100644
index 00000000000..28688197885
--- /dev/null
+++ b/net/irda/ircomm/ircomm_core.c
@@ -0,0 +1,587 @@
1/*********************************************************************
2 *
3 * Filename: ircomm_core.c
4 * Version: 1.0
5 * Description: IrCOMM service interface
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Sun Jun 6 20:37:34 1999
9 * Modified at: Tue Dec 21 13:26:41 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 *
12 * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
13 * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of
18 * the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28 * MA 02111-1307 USA
29 *
30 ********************************************************************/
31
32#include <linux/config.h>
33#include <linux/module.h>
34#include <linux/sched.h>
35#include <linux/proc_fs.h>
36#include <linux/seq_file.h>
37#include <linux/init.h>
38
39#include <net/irda/irda.h>
40#include <net/irda/irmod.h>
41#include <net/irda/irlmp.h>
42#include <net/irda/iriap.h>
43#include <net/irda/irttp.h>
44#include <net/irda/irias_object.h>
45
46#include <net/irda/ircomm_event.h>
47#include <net/irda/ircomm_lmp.h>
48#include <net/irda/ircomm_ttp.h>
49#include <net/irda/ircomm_param.h>
50#include <net/irda/ircomm_core.h>
51
52static int __ircomm_close(struct ircomm_cb *self);
53static void ircomm_control_indication(struct ircomm_cb *self,
54 struct sk_buff *skb, int clen);
55
56#ifdef CONFIG_PROC_FS
57extern struct proc_dir_entry *proc_irda;
58static int ircomm_seq_open(struct inode *, struct file *);
59
60static struct file_operations ircomm_proc_fops = {
61 .owner = THIS_MODULE,
62 .open = ircomm_seq_open,
63 .read = seq_read,
64 .llseek = seq_lseek,
65 .release = seq_release,
66};
67#endif /* CONFIG_PROC_FS */
68
69hashbin_t *ircomm = NULL;
70
71static int __init ircomm_init(void)
72{
73 ircomm = hashbin_new(HB_LOCK);
74 if (ircomm == NULL) {
75 IRDA_ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__);
76 return -ENOMEM;
77 }
78
79#ifdef CONFIG_PROC_FS
80 { struct proc_dir_entry *ent;
81 ent = create_proc_entry("ircomm", 0, proc_irda);
82 if (ent)
83 ent->proc_fops = &ircomm_proc_fops;
84 }
85#endif /* CONFIG_PROC_FS */
86
87 IRDA_MESSAGE("IrCOMM protocol (Dag Brattli)\n");
88
89 return 0;
90}
91
92static void __exit ircomm_cleanup(void)
93{
94 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
95
96 hashbin_delete(ircomm, (FREE_FUNC) __ircomm_close);
97
98#ifdef CONFIG_PROC_FS
99 remove_proc_entry("ircomm", proc_irda);
100#endif /* CONFIG_PROC_FS */
101}
102
103/*
104 * Function ircomm_open (client_notify)
105 *
106 * Start a new IrCOMM instance
107 *
108 */
109struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line)
110{
111 struct ircomm_cb *self = NULL;
112 int ret;
113
114 IRDA_DEBUG(2, "%s(), service_type=0x%02x\n", __FUNCTION__ ,
115 service_type);
116
117 IRDA_ASSERT(ircomm != NULL, return NULL;);
118
119 self = kmalloc(sizeof(struct ircomm_cb), GFP_ATOMIC);
120 if (self == NULL)
121 return NULL;
122
123 memset(self, 0, sizeof(struct ircomm_cb));
124
125 self->notify = *notify;
126 self->magic = IRCOMM_MAGIC;
127
128 /* Check if we should use IrLMP or IrTTP */
129 if (service_type & IRCOMM_3_WIRE_RAW) {
130 self->flow_status = FLOW_START;
131 ret = ircomm_open_lsap(self);
132 } else
133 ret = ircomm_open_tsap(self);
134
135 if (ret < 0) {
136 kfree(self);
137 return NULL;
138 }
139
140 self->service_type = service_type;
141 self->line = line;
142
143 hashbin_insert(ircomm, (irda_queue_t *) self, line, NULL);
144
145 ircomm_next_state(self, IRCOMM_IDLE);
146
147 return self;
148}
149
150EXPORT_SYMBOL(ircomm_open);
151
152/*
153 * Function ircomm_close_instance (self)
154 *
155 * Remove IrCOMM instance
156 *
157 */
158static int __ircomm_close(struct ircomm_cb *self)
159{
160 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
161
162 /* Disconnect link if any */
163 ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL);
164
165 /* Remove TSAP */
166 if (self->tsap) {
167 irttp_close_tsap(self->tsap);
168 self->tsap = NULL;
169 }
170
171 /* Remove LSAP */
172 if (self->lsap) {
173 irlmp_close_lsap(self->lsap);
174 self->lsap = NULL;
175 }
176 self->magic = 0;
177
178 kfree(self);
179
180 return 0;
181}
182
183/*
184 * Function ircomm_close (self)
185 *
186 * Closes and removes the specified IrCOMM instance
187 *
188 */
189int ircomm_close(struct ircomm_cb *self)
190{
191 struct ircomm_cb *entry;
192
193 IRDA_ASSERT(self != NULL, return -EIO;);
194 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;);
195
196 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
197
198 entry = hashbin_remove(ircomm, self->line, NULL);
199
200 IRDA_ASSERT(entry == self, return -1;);
201
202 return __ircomm_close(self);
203}
204
205EXPORT_SYMBOL(ircomm_close);
206
207/*
208 * Function ircomm_connect_request (self, service_type)
209 *
210 * Impl. of this function is differ from one of the reference. This
211 * function does discovery as well as sending connect request
212 *
213 */
214int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel,
215 __u32 saddr, __u32 daddr, struct sk_buff *skb,
216 __u8 service_type)
217{
218 struct ircomm_info info;
219 int ret;
220
221 IRDA_DEBUG(2 , "%s()\n", __FUNCTION__ );
222
223 IRDA_ASSERT(self != NULL, return -1;);
224 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
225
226 self->service_type= service_type;
227
228 info.dlsap_sel = dlsap_sel;
229 info.saddr = saddr;
230 info.daddr = daddr;
231
232 ret = ircomm_do_event(self, IRCOMM_CONNECT_REQUEST, skb, &info);
233
234 return ret;
235}
236
237EXPORT_SYMBOL(ircomm_connect_request);
238
239/*
240 * Function ircomm_connect_indication (self, qos, skb)
241 *
242 * Notify user layer about the incoming connection
243 *
244 */
245void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
246 struct ircomm_info *info)
247{
248 int clen = 0;
249
250 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
251
252 /* Check if the packet contains data on the control channel */
253 if (skb->len > 0)
254 clen = skb->data[0];
255
256 /*
257 * If there are any data hiding in the control channel, we must
258 * deliver it first. The side effect is that the control channel
259 * will be removed from the skb
260 */
261 if (self->notify.connect_indication)
262 self->notify.connect_indication(self->notify.instance, self,
263 info->qos, info->max_data_size,
264 info->max_header_size, skb);
265 else {
266 IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
267 }
268}
269
270/*
271 * Function ircomm_connect_response (self, userdata, max_sdu_size)
272 *
273 * User accepts connection
274 *
275 */
276int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata)
277{
278 int ret;
279
280 IRDA_ASSERT(self != NULL, return -1;);
281 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
282
283 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
284
285 ret = ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata, NULL);
286
287 return ret;
288}
289
290EXPORT_SYMBOL(ircomm_connect_response);
291
292/*
293 * Function connect_confirm (self, skb)
294 *
295 * Notify user layer that the link is now connected
296 *
297 */
298void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
299 struct ircomm_info *info)
300{
301 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
302
303 if (self->notify.connect_confirm )
304 self->notify.connect_confirm(self->notify.instance,
305 self, info->qos,
306 info->max_data_size,
307 info->max_header_size, skb);
308 else {
309 IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
310 }
311}
312
313/*
314 * Function ircomm_data_request (self, userdata)
315 *
316 * Send IrCOMM data to peer device
317 *
318 */
319int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb)
320{
321 int ret;
322
323 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
324
325 IRDA_ASSERT(self != NULL, return -EFAULT;);
326 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
327 IRDA_ASSERT(skb != NULL, return -EFAULT;);
328
329 ret = ircomm_do_event(self, IRCOMM_DATA_REQUEST, skb, NULL);
330
331 return ret;
332}
333
334EXPORT_SYMBOL(ircomm_data_request);
335
336/*
337 * Function ircomm_data_indication (self, skb)
338 *
339 * Data arrived, so deliver it to user
340 *
341 */
342void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
343{
344 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
345
346 IRDA_ASSERT(skb->len > 0, return;);
347
348 if (self->notify.data_indication)
349 self->notify.data_indication(self->notify.instance, self, skb);
350 else {
351 IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
352 }
353}
354
355/*
356 * Function ircomm_process_data (self, skb)
357 *
358 * Data arrived which may contain control channel data
359 *
360 */
361void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb)
362{
363 int clen;
364
365 IRDA_ASSERT(skb->len > 0, return;);
366
367 clen = skb->data[0];
368
369 /*
370 * If there are any data hiding in the control channel, we must
371 * deliver it first. The side effect is that the control channel
372 * will be removed from the skb
373 */
374 if (clen > 0)
375 ircomm_control_indication(self, skb, clen);
376
377 /* Remove control channel from data channel */
378 skb_pull(skb, clen+1);
379
380 if (skb->len)
381 ircomm_data_indication(self, skb);
382 else {
383 IRDA_DEBUG(4, "%s(), data was control info only!\n",
384 __FUNCTION__ );
385 }
386}
387
388/*
389 * Function ircomm_control_request (self, params)
390 *
391 * Send control data to peer device
392 *
393 */
394int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb)
395{
396 int ret;
397
398 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
399
400 IRDA_ASSERT(self != NULL, return -EFAULT;);
401 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
402 IRDA_ASSERT(skb != NULL, return -EFAULT;);
403
404 ret = ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb, NULL);
405
406 return ret;
407}
408
409EXPORT_SYMBOL(ircomm_control_request);
410
411/*
412 * Function ircomm_control_indication (self, skb)
413 *
414 * Data has arrived on the control channel
415 *
416 */
417static void ircomm_control_indication(struct ircomm_cb *self,
418 struct sk_buff *skb, int clen)
419{
420 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
421
422 /* Use udata for delivering data on the control channel */
423 if (self->notify.udata_indication) {
424 struct sk_buff *ctrl_skb;
425
426 /* We don't own the skb, so clone it */
427 ctrl_skb = skb_clone(skb, GFP_ATOMIC);
428 if (!ctrl_skb)
429 return;
430
431 /* Remove data channel from control channel */
432 skb_trim(ctrl_skb, clen+1);
433
434 self->notify.udata_indication(self->notify.instance, self,
435 ctrl_skb);
436
437 /* Drop reference count -
438 * see ircomm_tty_control_indication(). */
439 dev_kfree_skb(ctrl_skb);
440 } else {
441 IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
442 }
443}
444
445/*
446 * Function ircomm_disconnect_request (self, userdata, priority)
447 *
448 * User layer wants to disconnect the IrCOMM connection
449 *
450 */
451int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata)
452{
453 struct ircomm_info info;
454 int ret;
455
456 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
457
458 IRDA_ASSERT(self != NULL, return -1;);
459 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
460
461 ret = ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, userdata,
462 &info);
463 return ret;
464}
465
466EXPORT_SYMBOL(ircomm_disconnect_request);
467
468/*
469 * Function disconnect_indication (self, skb)
470 *
471 * Tell user that the link has been disconnected
472 *
473 */
474void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
475 struct ircomm_info *info)
476{
477 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
478
479 IRDA_ASSERT(info != NULL, return;);
480
481 if (self->notify.disconnect_indication) {
482 self->notify.disconnect_indication(self->notify.instance, self,
483 info->reason, skb);
484 } else {
485 IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
486 }
487}
488
489/*
490 * Function ircomm_flow_request (self, flow)
491 *
492 *
493 *
494 */
495void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow)
496{
497 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
498
499 IRDA_ASSERT(self != NULL, return;);
500 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
501
502 if (self->service_type == IRCOMM_3_WIRE_RAW)
503 return;
504
505 irttp_flow_request(self->tsap, flow);
506}
507
508EXPORT_SYMBOL(ircomm_flow_request);
509
510#ifdef CONFIG_PROC_FS
511static void *ircomm_seq_start(struct seq_file *seq, loff_t *pos)
512{
513 struct ircomm_cb *self;
514 loff_t off = 0;
515
516 spin_lock_irq(&ircomm->hb_spinlock);
517
518 for (self = (struct ircomm_cb *) hashbin_get_first(ircomm);
519 self != NULL;
520 self = (struct ircomm_cb *) hashbin_get_next(ircomm)) {
521 if (off++ == *pos)
522 break;
523
524 }
525 return self;
526}
527
528static void *ircomm_seq_next(struct seq_file *seq, void *v, loff_t *pos)
529{
530 ++*pos;
531
532 return (void *) hashbin_get_next(ircomm);
533}
534
535static void ircomm_seq_stop(struct seq_file *seq, void *v)
536{
537 spin_unlock_irq(&ircomm->hb_spinlock);
538}
539
540static int ircomm_seq_show(struct seq_file *seq, void *v)
541{
542 const struct ircomm_cb *self = v;
543
544 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EINVAL; );
545
546 if(self->line < 0x10)
547 seq_printf(seq, "ircomm%d", self->line);
548 else
549 seq_printf(seq, "irlpt%d", self->line - 0x10);
550
551 seq_printf(seq,
552 " state: %s, slsap_sel: %#02x, dlsap_sel: %#02x, mode:",
553 ircomm_state[ self->state],
554 self->slsap_sel, self->dlsap_sel);
555
556 if(self->service_type & IRCOMM_3_WIRE_RAW)
557 seq_printf(seq, " 3-wire-raw");
558 if(self->service_type & IRCOMM_3_WIRE)
559 seq_printf(seq, " 3-wire");
560 if(self->service_type & IRCOMM_9_WIRE)
561 seq_printf(seq, " 9-wire");
562 if(self->service_type & IRCOMM_CENTRONICS)
563 seq_printf(seq, " Centronics");
564 seq_putc(seq, '\n');
565
566 return 0;
567}
568
569static struct seq_operations ircomm_seq_ops = {
570 .start = ircomm_seq_start,
571 .next = ircomm_seq_next,
572 .stop = ircomm_seq_stop,
573 .show = ircomm_seq_show,
574};
575
576static int ircomm_seq_open(struct inode *inode, struct file *file)
577{
578 return seq_open(file, &ircomm_seq_ops);
579}
580#endif /* CONFIG_PROC_FS */
581
582MODULE_AUTHOR("Dag Brattli <dag@brattli.net>");
583MODULE_DESCRIPTION("IrCOMM protocol");
584MODULE_LICENSE("GPL");
585
586module_init(ircomm_init);
587module_exit(ircomm_cleanup);
diff --git a/net/irda/ircomm/ircomm_event.c b/net/irda/ircomm/ircomm_event.c
new file mode 100644
index 00000000000..01f4e801a1b
--- /dev/null
+++ b/net/irda/ircomm/ircomm_event.c
@@ -0,0 +1,251 @@
1/*********************************************************************
2 *
3 * Filename: ircomm_event.c
4 * Version: 1.0
5 * Description: IrCOMM layer state machine
6 * Status: Stable
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Sun Jun 6 20:33:11 1999
9 * Modified at: Sun Dec 12 13:44:32 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 *
12 * Copyright (c) 1999 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/proc_fs.h>
33#include <linux/init.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
41#include <net/irda/ircomm_core.h>
42#include <net/irda/ircomm_event.h>
43
44static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event,
45 struct sk_buff *skb, struct ircomm_info *info);
46static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
47 struct sk_buff *skb, struct ircomm_info *info);
48static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
49 struct sk_buff *skb, struct ircomm_info *info);
50static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
51 struct sk_buff *skb, struct ircomm_info *info);
52
53char *ircomm_state[] = {
54 "IRCOMM_IDLE",
55 "IRCOMM_WAITI",
56 "IRCOMM_WAITR",
57 "IRCOMM_CONN",
58};
59
60#ifdef CONFIG_IRDA_DEBUG
61static char *ircomm_event[] = {
62 "IRCOMM_CONNECT_REQUEST",
63 "IRCOMM_CONNECT_RESPONSE",
64 "IRCOMM_TTP_CONNECT_INDICATION",
65 "IRCOMM_LMP_CONNECT_INDICATION",
66 "IRCOMM_TTP_CONNECT_CONFIRM",
67 "IRCOMM_LMP_CONNECT_CONFIRM",
68
69 "IRCOMM_LMP_DISCONNECT_INDICATION",
70 "IRCOMM_TTP_DISCONNECT_INDICATION",
71 "IRCOMM_DISCONNECT_REQUEST",
72
73 "IRCOMM_TTP_DATA_INDICATION",
74 "IRCOMM_LMP_DATA_INDICATION",
75 "IRCOMM_DATA_REQUEST",
76 "IRCOMM_CONTROL_REQUEST",
77 "IRCOMM_CONTROL_INDICATION",
78};
79#endif /* CONFIG_IRDA_DEBUG */
80
81static int (*state[])(struct ircomm_cb *self, IRCOMM_EVENT event,
82 struct sk_buff *skb, struct ircomm_info *info) =
83{
84 ircomm_state_idle,
85 ircomm_state_waiti,
86 ircomm_state_waitr,
87 ircomm_state_conn,
88};
89
90/*
91 * Function ircomm_state_idle (self, event, skb)
92 *
93 * IrCOMM is currently idle
94 *
95 */
96static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event,
97 struct sk_buff *skb, struct ircomm_info *info)
98{
99 int ret = 0;
100
101 switch (event) {
102 case IRCOMM_CONNECT_REQUEST:
103 ircomm_next_state(self, IRCOMM_WAITI);
104 ret = self->issue.connect_request(self, skb, info);
105 break;
106 case IRCOMM_TTP_CONNECT_INDICATION:
107 case IRCOMM_LMP_CONNECT_INDICATION:
108 ircomm_next_state(self, IRCOMM_WAITR);
109 ircomm_connect_indication(self, skb, info);
110 break;
111 default:
112 IRDA_DEBUG(4, "%s(), unknown event: %s\n", __FUNCTION__ ,
113 ircomm_event[event]);
114 ret = -EINVAL;
115 }
116 return ret;
117}
118
119/*
120 * Function ircomm_state_waiti (self, event, skb)
121 *
122 * The IrCOMM user has requested an IrCOMM connection to the remote
123 * device and is awaiting confirmation
124 */
125static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
126 struct sk_buff *skb, struct ircomm_info *info)
127{
128 int ret = 0;
129
130 switch (event) {
131 case IRCOMM_TTP_CONNECT_CONFIRM:
132 case IRCOMM_LMP_CONNECT_CONFIRM:
133 ircomm_next_state(self, IRCOMM_CONN);
134 ircomm_connect_confirm(self, skb, info);
135 break;
136 case IRCOMM_TTP_DISCONNECT_INDICATION:
137 case IRCOMM_LMP_DISCONNECT_INDICATION:
138 ircomm_next_state(self, IRCOMM_IDLE);
139 ircomm_disconnect_indication(self, skb, info);
140 break;
141 default:
142 IRDA_DEBUG(0, "%s(), unknown event: %s\n", __FUNCTION__ ,
143 ircomm_event[event]);
144 ret = -EINVAL;
145 }
146 return ret;
147}
148
149/*
150 * Function ircomm_state_waitr (self, event, skb)
151 *
152 * IrCOMM has received an incoming connection request and is awaiting
153 * response from the user
154 */
155static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
156 struct sk_buff *skb, struct ircomm_info *info)
157{
158 int ret = 0;
159
160 switch (event) {
161 case IRCOMM_CONNECT_RESPONSE:
162 ircomm_next_state(self, IRCOMM_CONN);
163 ret = self->issue.connect_response(self, skb);
164 break;
165 case IRCOMM_DISCONNECT_REQUEST:
166 ircomm_next_state(self, IRCOMM_IDLE);
167 ret = self->issue.disconnect_request(self, skb, info);
168 break;
169 case IRCOMM_TTP_DISCONNECT_INDICATION:
170 case IRCOMM_LMP_DISCONNECT_INDICATION:
171 ircomm_next_state(self, IRCOMM_IDLE);
172 ircomm_disconnect_indication(self, skb, info);
173 break;
174 default:
175 IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ ,
176 ircomm_event[event]);
177 ret = -EINVAL;
178 }
179 return ret;
180}
181
182/*
183 * Function ircomm_state_conn (self, event, skb)
184 *
185 * IrCOMM is connected to the peer IrCOMM device
186 *
187 */
188static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
189 struct sk_buff *skb, struct ircomm_info *info)
190{
191 int ret = 0;
192
193 switch (event) {
194 case IRCOMM_DATA_REQUEST:
195 ret = self->issue.data_request(self, skb, 0);
196 break;
197 case IRCOMM_TTP_DATA_INDICATION:
198 ircomm_process_data(self, skb);
199 break;
200 case IRCOMM_LMP_DATA_INDICATION:
201 ircomm_data_indication(self, skb);
202 break;
203 case IRCOMM_CONTROL_REQUEST:
204 /* Just send a separate frame for now */
205 ret = self->issue.data_request(self, skb, skb->len);
206 break;
207 case IRCOMM_TTP_DISCONNECT_INDICATION:
208 case IRCOMM_LMP_DISCONNECT_INDICATION:
209 ircomm_next_state(self, IRCOMM_IDLE);
210 ircomm_disconnect_indication(self, skb, info);
211 break;
212 case IRCOMM_DISCONNECT_REQUEST:
213 ircomm_next_state(self, IRCOMM_IDLE);
214 ret = self->issue.disconnect_request(self, skb, info);
215 break;
216 default:
217 IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ ,
218 ircomm_event[event]);
219 ret = -EINVAL;
220 }
221 return ret;
222}
223
224/*
225 * Function ircomm_do_event (self, event, skb)
226 *
227 * Process event
228 *
229 */
230int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event,
231 struct sk_buff *skb, struct ircomm_info *info)
232{
233 IRDA_DEBUG(4, "%s: state=%s, event=%s\n", __FUNCTION__ ,
234 ircomm_state[self->state], ircomm_event[event]);
235
236 return (*state[self->state])(self, event, skb, info);
237}
238
239/*
240 * Function ircomm_next_state (self, state)
241 *
242 * Switch state
243 *
244 */
245void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state)
246{
247 self->state = state;
248
249 IRDA_DEBUG(4, "%s: next state=%s, service type=%d\n", __FUNCTION__ ,
250 ircomm_state[self->state], self->service_type);
251}
diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c
new file mode 100644
index 00000000000..d9097207aed
--- /dev/null
+++ b/net/irda/ircomm/ircomm_lmp.c
@@ -0,0 +1,372 @@
1/*********************************************************************
2 *
3 * Filename: ircomm_lmp.c
4 * Version: 1.0
5 * Description: Interface between IrCOMM and IrLMP
6 * Status: Stable
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Sun Jun 6 20:48:27 1999
9 * Modified at: Sun Dec 12 13:44:17 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 * Sources: Previous IrLPT work by Thomas Davis
12 *
13 * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
14 * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License as
18 * published by the Free Software Foundation; either version 2 of
19 * the License, or (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29 * MA 02111-1307 USA
30 *
31 ********************************************************************/
32
33#include <linux/sched.h>
34#include <linux/init.h>
35
36#include <net/irda/irda.h>
37#include <net/irda/irlmp.h>
38#include <net/irda/iriap.h>
39#include <net/irda/irda_device.h> /* struct irda_skb_cb */
40
41#include <net/irda/ircomm_event.h>
42#include <net/irda/ircomm_lmp.h>
43
44
45/*
46 * Function ircomm_lmp_connect_request (self, userdata)
47 *
48 *
49 *
50 */
51static int ircomm_lmp_connect_request(struct ircomm_cb *self,
52 struct sk_buff *userdata,
53 struct ircomm_info *info)
54{
55 int ret = 0;
56
57 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
58
59 /* Don't forget to refcount it - should be NULL anyway */
60 if(userdata)
61 skb_get(userdata);
62
63 ret = irlmp_connect_request(self->lsap, info->dlsap_sel,
64 info->saddr, info->daddr, NULL, userdata);
65 return ret;
66}
67
68/*
69 * Function ircomm_lmp_connect_response (self, skb)
70 *
71 *
72 *
73 */
74static int ircomm_lmp_connect_response(struct ircomm_cb *self,
75 struct sk_buff *userdata)
76{
77 struct sk_buff *tx_skb;
78 int ret;
79
80 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
81
82 /* Any userdata supplied? */
83 if (userdata == NULL) {
84 tx_skb = dev_alloc_skb(64);
85 if (!tx_skb)
86 return -ENOMEM;
87
88 /* Reserve space for MUX and LAP header */
89 skb_reserve(tx_skb, LMP_MAX_HEADER);
90 } else {
91 /*
92 * Check that the client has reserved enough space for
93 * headers
94 */
95 IRDA_ASSERT(skb_headroom(userdata) >= LMP_MAX_HEADER,
96 return -1;);
97
98 /* Don't forget to refcount it - should be NULL anyway */
99 skb_get(userdata);
100 tx_skb = userdata;
101 }
102
103 ret = irlmp_connect_response(self->lsap, tx_skb);
104
105 return 0;
106}
107
108static int ircomm_lmp_disconnect_request(struct ircomm_cb *self,
109 struct sk_buff *userdata,
110 struct ircomm_info *info)
111{
112 struct sk_buff *tx_skb;
113 int ret;
114
115 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
116
117 if (!userdata) {
118 tx_skb = dev_alloc_skb(64);
119 if (!tx_skb)
120 return -ENOMEM;
121
122 /* Reserve space for MUX and LAP header */
123 skb_reserve(tx_skb, LMP_MAX_HEADER);
124 userdata = tx_skb;
125 } else {
126 /* Don't forget to refcount it - should be NULL anyway */
127 skb_get(userdata);
128 }
129
130 ret = irlmp_disconnect_request(self->lsap, userdata);
131
132 return ret;
133}
134
135/*
136 * Function ircomm_lmp_flow_control (skb)
137 *
138 * This function is called when a data frame we have sent to IrLAP has
139 * been deallocated. We do this to make sure we don't flood IrLAP with
140 * frames, since we are not using the IrTTP flow control mechanism
141 */
142static void ircomm_lmp_flow_control(struct sk_buff *skb)
143{
144 struct irda_skb_cb *cb;
145 struct ircomm_cb *self;
146 int line;
147
148 IRDA_ASSERT(skb != NULL, return;);
149
150 cb = (struct irda_skb_cb *) skb->cb;
151
152 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
153
154 line = cb->line;
155
156 self = (struct ircomm_cb *) hashbin_lock_find(ircomm, line, NULL);
157 if (!self) {
158 IRDA_DEBUG(2, "%s(), didn't find myself\n", __FUNCTION__ );
159 return;
160 }
161
162 IRDA_ASSERT(self != NULL, return;);
163 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
164
165 self->pkt_count--;
166
167 if ((self->pkt_count < 2) && (self->flow_status == FLOW_STOP)) {
168 IRDA_DEBUG(2, "%s(), asking TTY to start again!\n", __FUNCTION__ );
169 self->flow_status = FLOW_START;
170 if (self->notify.flow_indication)
171 self->notify.flow_indication(self->notify.instance,
172 self, FLOW_START);
173 }
174}
175
176/*
177 * Function ircomm_lmp_data_request (self, userdata)
178 *
179 * Send data frame to peer device
180 *
181 */
182static int ircomm_lmp_data_request(struct ircomm_cb *self,
183 struct sk_buff *skb,
184 int not_used)
185{
186 struct irda_skb_cb *cb;
187 int ret;
188
189 IRDA_ASSERT(skb != NULL, return -1;);
190
191 cb = (struct irda_skb_cb *) skb->cb;
192
193 cb->line = self->line;
194
195 IRDA_DEBUG(4, "%s(), sending frame\n", __FUNCTION__ );
196
197 /* Don't forget to refcount it - see ircomm_tty_do_softint() */
198 skb_get(skb);
199
200 skb->destructor = ircomm_lmp_flow_control;
201
202 if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) {
203 IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __FUNCTION__ );
204 self->flow_status = FLOW_STOP;
205 if (self->notify.flow_indication)
206 self->notify.flow_indication(self->notify.instance,
207 self, FLOW_STOP);
208 }
209 ret = irlmp_data_request(self->lsap, skb);
210 if (ret) {
211 IRDA_ERROR("%s(), failed\n", __FUNCTION__);
212 /* irlmp_data_request already free the packet */
213 }
214
215 return ret;
216}
217
218/*
219 * Function ircomm_lmp_data_indication (instance, sap, skb)
220 *
221 * Incoming data which we must deliver to the state machine, to check
222 * we are still connected.
223 */
224static int ircomm_lmp_data_indication(void *instance, void *sap,
225 struct sk_buff *skb)
226{
227 struct ircomm_cb *self = (struct ircomm_cb *) instance;
228
229 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
230
231 IRDA_ASSERT(self != NULL, return -1;);
232 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
233 IRDA_ASSERT(skb != NULL, return -1;);
234
235 ircomm_do_event(self, IRCOMM_LMP_DATA_INDICATION, skb, NULL);
236
237 /* Drop reference count - see ircomm_tty_data_indication(). */
238 dev_kfree_skb(skb);
239
240 return 0;
241}
242
243/*
244 * Function ircomm_lmp_connect_confirm (instance, sap, qos, max_sdu_size,
245 * max_header_size, skb)
246 *
247 * Connection has been confirmed by peer device
248 *
249 */
250static void ircomm_lmp_connect_confirm(void *instance, void *sap,
251 struct qos_info *qos,
252 __u32 max_seg_size,
253 __u8 max_header_size,
254 struct sk_buff *skb)
255{
256 struct ircomm_cb *self = (struct ircomm_cb *) instance;
257 struct ircomm_info info;
258
259 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
260
261 IRDA_ASSERT(self != NULL, return;);
262 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
263 IRDA_ASSERT(skb != NULL, return;);
264 IRDA_ASSERT(qos != NULL, return;);
265
266 info.max_data_size = max_seg_size;
267 info.max_header_size = max_header_size;
268 info.qos = qos;
269
270 ircomm_do_event(self, IRCOMM_LMP_CONNECT_CONFIRM, skb, &info);
271
272 /* Drop reference count - see ircomm_tty_connect_confirm(). */
273 dev_kfree_skb(skb);
274}
275
276/*
277 * Function ircomm_lmp_connect_indication (instance, sap, qos, max_sdu_size,
278 * max_header_size, skb)
279 *
280 * Peer device wants to make a connection with us
281 *
282 */
283static void ircomm_lmp_connect_indication(void *instance, void *sap,
284 struct qos_info *qos,
285 __u32 max_seg_size,
286 __u8 max_header_size,
287 struct sk_buff *skb)
288{
289 struct ircomm_cb *self = (struct ircomm_cb *)instance;
290 struct ircomm_info info;
291
292 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
293
294 IRDA_ASSERT(self != NULL, return;);
295 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
296 IRDA_ASSERT(skb != NULL, return;);
297 IRDA_ASSERT(qos != NULL, return;);
298
299 info.max_data_size = max_seg_size;
300 info.max_header_size = max_header_size;
301 info.qos = qos;
302
303 ircomm_do_event(self, IRCOMM_LMP_CONNECT_INDICATION, skb, &info);
304
305 /* Drop reference count - see ircomm_tty_connect_indication(). */
306 dev_kfree_skb(skb);
307}
308
309/*
310 * Function ircomm_lmp_disconnect_indication (instance, sap, reason, skb)
311 *
312 * Peer device has closed the connection, or the link went down for some
313 * other reason
314 */
315static void ircomm_lmp_disconnect_indication(void *instance, void *sap,
316 LM_REASON reason,
317 struct sk_buff *skb)
318{
319 struct ircomm_cb *self = (struct ircomm_cb *) instance;
320 struct ircomm_info info;
321
322 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
323
324 IRDA_ASSERT(self != NULL, return;);
325 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
326
327 info.reason = reason;
328
329 ircomm_do_event(self, IRCOMM_LMP_DISCONNECT_INDICATION, skb, &info);
330
331 /* Drop reference count - see ircomm_tty_disconnect_indication(). */
332 if(skb)
333 dev_kfree_skb(skb);
334}
335/*
336 * Function ircomm_open_lsap (self)
337 *
338 * Open LSAP. This function will only be used when using "raw" services
339 *
340 */
341int ircomm_open_lsap(struct ircomm_cb *self)
342{
343 notify_t notify;
344
345 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
346
347 /* Register callbacks */
348 irda_notify_init(&notify);
349 notify.data_indication = ircomm_lmp_data_indication;
350 notify.connect_confirm = ircomm_lmp_connect_confirm;
351 notify.connect_indication = ircomm_lmp_connect_indication;
352 notify.disconnect_indication = ircomm_lmp_disconnect_indication;
353 notify.instance = self;
354 strlcpy(notify.name, "IrCOMM", sizeof(notify.name));
355
356 self->lsap = irlmp_open_lsap(LSAP_ANY, &notify, 0);
357 if (!self->lsap) {
358 IRDA_DEBUG(0,"%sfailed to allocate tsap\n", __FUNCTION__ );
359 return -1;
360 }
361 self->slsap_sel = self->lsap->slsap_sel;
362
363 /*
364 * Initialize the call-table for issuing commands
365 */
366 self->issue.data_request = ircomm_lmp_data_request;
367 self->issue.connect_request = ircomm_lmp_connect_request;
368 self->issue.connect_response = ircomm_lmp_connect_response;
369 self->issue.disconnect_request = ircomm_lmp_disconnect_request;
370
371 return 0;
372}
diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c
new file mode 100644
index 00000000000..6009bab0509
--- /dev/null
+++ b/net/irda/ircomm/ircomm_param.c
@@ -0,0 +1,511 @@
1/*********************************************************************
2 *
3 * Filename: ircomm_param.c
4 * Version: 1.0
5 * Description: Parameter handling for the IrCOMM protocol
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Mon Jun 7 10:25:11 1999
9 * Modified at: Sun Jan 30 14:32:03 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/workqueue.h>
33#include <linux/interrupt.h>
34
35#include <net/irda/irda.h>
36#include <net/irda/parameters.h>
37
38#include <net/irda/ircomm_core.h>
39#include <net/irda/ircomm_tty_attach.h>
40#include <net/irda/ircomm_tty.h>
41
42#include <net/irda/ircomm_param.h>
43
44static int ircomm_param_service_type(void *instance, irda_param_t *param,
45 int get);
46static int ircomm_param_port_type(void *instance, irda_param_t *param,
47 int get);
48static int ircomm_param_port_name(void *instance, irda_param_t *param,
49 int get);
50static int ircomm_param_service_type(void *instance, irda_param_t *param,
51 int get);
52static int ircomm_param_data_rate(void *instance, irda_param_t *param,
53 int get);
54static int ircomm_param_data_format(void *instance, irda_param_t *param,
55 int get);
56static int ircomm_param_flow_control(void *instance, irda_param_t *param,
57 int get);
58static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get);
59static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get);
60static int ircomm_param_line_status(void *instance, irda_param_t *param,
61 int get);
62static int ircomm_param_dte(void *instance, irda_param_t *param, int get);
63static int ircomm_param_dce(void *instance, irda_param_t *param, int get);
64static int ircomm_param_poll(void *instance, irda_param_t *param, int get);
65
66static pi_minor_info_t pi_minor_call_table_common[] = {
67 { ircomm_param_service_type, PV_INT_8_BITS },
68 { ircomm_param_port_type, PV_INT_8_BITS },
69 { ircomm_param_port_name, PV_STRING }
70};
71static pi_minor_info_t pi_minor_call_table_non_raw[] = {
72 { ircomm_param_data_rate, PV_INT_32_BITS | PV_BIG_ENDIAN },
73 { ircomm_param_data_format, PV_INT_8_BITS },
74 { ircomm_param_flow_control, PV_INT_8_BITS },
75 { ircomm_param_xon_xoff, PV_INT_16_BITS },
76 { ircomm_param_enq_ack, PV_INT_16_BITS },
77 { ircomm_param_line_status, PV_INT_8_BITS }
78};
79static pi_minor_info_t pi_minor_call_table_9_wire[] = {
80 { ircomm_param_dte, PV_INT_8_BITS },
81 { ircomm_param_dce, PV_INT_8_BITS },
82 { ircomm_param_poll, PV_NO_VALUE },
83};
84
85static pi_major_info_t pi_major_call_table[] = {
86 { pi_minor_call_table_common, 3 },
87 { pi_minor_call_table_non_raw, 6 },
88 { pi_minor_call_table_9_wire, 3 }
89/* { pi_minor_call_table_centronics } */
90};
91
92pi_param_info_t ircomm_param_info = { pi_major_call_table, 3, 0x0f, 4 };
93
94/*
95 * Function ircomm_param_request (self, pi, flush)
96 *
97 * Queue a parameter for the control channel
98 *
99 */
100int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
101{
102 struct tty_struct *tty;
103 unsigned long flags;
104 struct sk_buff *skb;
105 int count;
106
107 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
108
109 IRDA_ASSERT(self != NULL, return -1;);
110 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
111
112 tty = self->tty;
113 if (!tty)
114 return 0;
115
116 /* Make sure we don't send parameters for raw mode */
117 if (self->service_type == IRCOMM_3_WIRE_RAW)
118 return 0;
119
120 spin_lock_irqsave(&self->spinlock, flags);
121
122 skb = self->ctrl_skb;
123 if (!skb) {
124 skb = dev_alloc_skb(256);
125 if (!skb) {
126 spin_unlock_irqrestore(&self->spinlock, flags);
127 return -ENOMEM;
128 }
129
130 skb_reserve(skb, self->max_header_size);
131 self->ctrl_skb = skb;
132 }
133 /*
134 * Inserting is a little bit tricky since we don't know how much
135 * room we will need. But this should hopefully work OK
136 */
137 count = irda_param_insert(self, pi, skb->tail, skb_tailroom(skb),
138 &ircomm_param_info);
139 if (count < 0) {
140 IRDA_WARNING("%s(), no room for parameter!\n", __FUNCTION__);
141 spin_unlock_irqrestore(&self->spinlock, flags);
142 return -1;
143 }
144 skb_put(skb, count);
145
146 spin_unlock_irqrestore(&self->spinlock, flags);
147
148 IRDA_DEBUG(2, "%s(), skb->len=%d\n", __FUNCTION__ , skb->len);
149
150 if (flush) {
151 /* ircomm_tty_do_softint will take care of the rest */
152 schedule_work(&self->tqueue);
153 }
154
155 return count;
156}
157
158/*
159 * Function ircomm_param_service_type (self, buf, len)
160 *
161 * Handle service type, this function will both be called after the LM-IAS
162 * query and then the remote device sends its initial parameters
163 *
164 */
165static int ircomm_param_service_type(void *instance, irda_param_t *param,
166 int get)
167{
168 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
169 __u8 service_type = (__u8) param->pv.i;
170
171 IRDA_ASSERT(self != NULL, return -1;);
172 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
173
174 if (get) {
175 param->pv.i = self->settings.service_type;
176 return 0;
177 }
178
179 /* Find all common service types */
180 service_type &= self->service_type;
181 if (!service_type) {
182 IRDA_DEBUG(2,
183 "%s(), No common service type to use!\n", __FUNCTION__ );
184 return -1;
185 }
186 IRDA_DEBUG(0, "%s(), services in common=%02x\n", __FUNCTION__ ,
187 service_type);
188
189 /*
190 * Now choose a preferred service type of those available
191 */
192 if (service_type & IRCOMM_CENTRONICS)
193 self->settings.service_type = IRCOMM_CENTRONICS;
194 else if (service_type & IRCOMM_9_WIRE)
195 self->settings.service_type = IRCOMM_9_WIRE;
196 else if (service_type & IRCOMM_3_WIRE)
197 self->settings.service_type = IRCOMM_3_WIRE;
198 else if (service_type & IRCOMM_3_WIRE_RAW)
199 self->settings.service_type = IRCOMM_3_WIRE_RAW;
200
201 IRDA_DEBUG(0, "%s(), resulting service type=0x%02x\n", __FUNCTION__ ,
202 self->settings.service_type);
203
204 /*
205 * Now the line is ready for some communication. Check if we are a
206 * server, and send over some initial parameters.
207 * Client do it in ircomm_tty_state_setup().
208 * Note : we may get called from ircomm_tty_getvalue_confirm(),
209 * therefore before we even have open any socket. And self->client
210 * is initialised to TRUE only later. So, we check if the link is
211 * really initialised. - Jean II
212 */
213 if ((self->max_header_size != IRCOMM_TTY_HDR_UNINITIALISED) &&
214 (!self->client) &&
215 (self->settings.service_type != IRCOMM_3_WIRE_RAW))
216 {
217 /* Init connection */
218 ircomm_tty_send_initial_parameters(self);
219 ircomm_tty_link_established(self);
220 }
221
222 return 0;
223}
224
225/*
226 * Function ircomm_param_port_type (self, param)
227 *
228 * The port type parameter tells if the devices are serial or parallel.
229 * Since we only advertise serial service, this parameter should only
230 * be equal to IRCOMM_SERIAL.
231 */
232static int ircomm_param_port_type(void *instance, irda_param_t *param, int get)
233{
234 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
235
236 IRDA_ASSERT(self != NULL, return -1;);
237 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
238
239 if (get)
240 param->pv.i = IRCOMM_SERIAL;
241 else {
242 self->settings.port_type = (__u8) param->pv.i;
243
244 IRDA_DEBUG(0, "%s(), port type=%d\n", __FUNCTION__ ,
245 self->settings.port_type);
246 }
247 return 0;
248}
249
250/*
251 * Function ircomm_param_port_name (self, param)
252 *
253 * Exchange port name
254 *
255 */
256static int ircomm_param_port_name(void *instance, irda_param_t *param, int get)
257{
258 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
259
260 IRDA_ASSERT(self != NULL, return -1;);
261 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
262
263 if (get) {
264 IRDA_DEBUG(0, "%s(), not imp!\n", __FUNCTION__ );
265 } else {
266 IRDA_DEBUG(0, "%s(), port-name=%s\n", __FUNCTION__ , param->pv.c);
267 strncpy(self->settings.port_name, param->pv.c, 32);
268 }
269
270 return 0;
271}
272
273/*
274 * Function ircomm_param_data_rate (self, param)
275 *
276 * Exchange data rate to be used in this settings
277 *
278 */
279static int ircomm_param_data_rate(void *instance, irda_param_t *param, int get)
280{
281 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
282
283 IRDA_ASSERT(self != NULL, return -1;);
284 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
285
286 if (get)
287 param->pv.i = self->settings.data_rate;
288 else
289 self->settings.data_rate = param->pv.i;
290
291 IRDA_DEBUG(2, "%s(), data rate = %d\n", __FUNCTION__ , param->pv.i);
292
293 return 0;
294}
295
296/*
297 * Function ircomm_param_data_format (self, param)
298 *
299 * Exchange data format to be used in this settings
300 *
301 */
302static int ircomm_param_data_format(void *instance, irda_param_t *param,
303 int get)
304{
305 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
306
307 IRDA_ASSERT(self != NULL, return -1;);
308 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
309
310 if (get)
311 param->pv.i = self->settings.data_format;
312 else
313 self->settings.data_format = (__u8) param->pv.i;
314
315 return 0;
316}
317
318/*
319 * Function ircomm_param_flow_control (self, param)
320 *
321 * Exchange flow control settings to be used in this settings
322 *
323 */
324static int ircomm_param_flow_control(void *instance, irda_param_t *param,
325 int get)
326{
327 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
328
329 IRDA_ASSERT(self != NULL, return -1;);
330 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
331
332 if (get)
333 param->pv.i = self->settings.flow_control;
334 else
335 self->settings.flow_control = (__u8) param->pv.i;
336
337 IRDA_DEBUG(1, "%s(), flow control = 0x%02x\n", __FUNCTION__ , (__u8) param->pv.i);
338
339 return 0;
340}
341
342/*
343 * Function ircomm_param_xon_xoff (self, param)
344 *
345 * Exchange XON/XOFF characters
346 *
347 */
348static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get)
349{
350 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
351
352 IRDA_ASSERT(self != NULL, return -1;);
353 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
354
355 if (get) {
356 param->pv.i = self->settings.xonxoff[0];
357 param->pv.i |= self->settings.xonxoff[1] << 8;
358 } else {
359 self->settings.xonxoff[0] = (__u16) param->pv.i & 0xff;
360 self->settings.xonxoff[1] = (__u16) param->pv.i >> 8;
361 }
362
363 IRDA_DEBUG(0, "%s(), XON/XOFF = 0x%02x,0x%02x\n", __FUNCTION__ ,
364 param->pv.i & 0xff, param->pv.i >> 8);
365
366 return 0;
367}
368
369/*
370 * Function ircomm_param_enq_ack (self, param)
371 *
372 * Exchange ENQ/ACK characters
373 *
374 */
375static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get)
376{
377 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
378
379 IRDA_ASSERT(self != NULL, return -1;);
380 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
381
382 if (get) {
383 param->pv.i = self->settings.enqack[0];
384 param->pv.i |= self->settings.enqack[1] << 8;
385 } else {
386 self->settings.enqack[0] = (__u16) param->pv.i & 0xff;
387 self->settings.enqack[1] = (__u16) param->pv.i >> 8;
388 }
389
390 IRDA_DEBUG(0, "%s(), ENQ/ACK = 0x%02x,0x%02x\n", __FUNCTION__ ,
391 param->pv.i & 0xff, param->pv.i >> 8);
392
393 return 0;
394}
395
396/*
397 * Function ircomm_param_line_status (self, param)
398 *
399 *
400 *
401 */
402static int ircomm_param_line_status(void *instance, irda_param_t *param,
403 int get)
404{
405 IRDA_DEBUG(2, "%s(), not impl.\n", __FUNCTION__ );
406
407 return 0;
408}
409
410/*
411 * Function ircomm_param_dte (instance, param)
412 *
413 * If we get here, there must be some sort of null-modem connection, and
414 * we are probably working in server mode as well.
415 */
416static int ircomm_param_dte(void *instance, irda_param_t *param, int get)
417{
418 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
419 __u8 dte;
420
421 IRDA_ASSERT(self != NULL, return -1;);
422 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
423
424 if (get)
425 param->pv.i = self->settings.dte;
426 else {
427 dte = (__u8) param->pv.i;
428
429 self->settings.dce = 0;
430
431 if (dte & IRCOMM_DELTA_DTR)
432 self->settings.dce |= (IRCOMM_DELTA_DSR|
433 IRCOMM_DELTA_RI |
434 IRCOMM_DELTA_CD);
435 if (dte & IRCOMM_DTR)
436 self->settings.dce |= (IRCOMM_DSR|
437 IRCOMM_RI |
438 IRCOMM_CD);
439
440 if (dte & IRCOMM_DELTA_RTS)
441 self->settings.dce |= IRCOMM_DELTA_CTS;
442 if (dte & IRCOMM_RTS)
443 self->settings.dce |= IRCOMM_CTS;
444
445 /* Take appropriate actions */
446 ircomm_tty_check_modem_status(self);
447
448 /* Null modem cable emulator */
449 self->settings.null_modem = TRUE;
450 }
451
452 return 0;
453}
454
455/*
456 * Function ircomm_param_dce (instance, param)
457 *
458 *
459 *
460 */
461static int ircomm_param_dce(void *instance, irda_param_t *param, int get)
462{
463 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
464 __u8 dce;
465
466 IRDA_DEBUG(1, "%s(), dce = 0x%02x\n", __FUNCTION__ , (__u8) param->pv.i);
467
468 dce = (__u8) param->pv.i;
469
470 IRDA_ASSERT(self != NULL, return -1;);
471 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
472
473 self->settings.dce = dce;
474
475 /* Check if any of the settings have changed */
476 if (dce & 0x0f) {
477 if (dce & IRCOMM_DELTA_CTS) {
478 IRDA_DEBUG(2, "%s(), CTS \n", __FUNCTION__ );
479 }
480 }
481
482 ircomm_tty_check_modem_status(self);
483
484 return 0;
485}
486
487/*
488 * Function ircomm_param_poll (instance, param)
489 *
490 * Called when the peer device is polling for the line settings
491 *
492 */
493static int ircomm_param_poll(void *instance, irda_param_t *param, int get)
494{
495 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
496
497 IRDA_ASSERT(self != NULL, return -1;);
498 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
499
500 /* Poll parameters are always of lenght 0 (just a signal) */
501 if (!get) {
502 /* Respond with DTE line settings */
503 ircomm_param_request(self, IRCOMM_DTE, TRUE);
504 }
505 return 0;
506}
507
508
509
510
511
diff --git a/net/irda/ircomm/ircomm_ttp.c b/net/irda/ircomm/ircomm_ttp.c
new file mode 100644
index 00000000000..d98bf3570d2
--- /dev/null
+++ b/net/irda/ircomm/ircomm_ttp.c
@@ -0,0 +1,369 @@
1/*********************************************************************
2 *
3 * Filename: ircomm_ttp.c
4 * Version: 1.0
5 * Description: Interface between IrCOMM and IrTTP
6 * Status: Stable
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Sun Jun 6 20:48:27 1999
9 * Modified at: Mon Dec 13 11:35:13 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 *
12 * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
13 * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of
18 * the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28 * MA 02111-1307 USA
29 *
30 ********************************************************************/
31
32#include <linux/sched.h>
33#include <linux/init.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
40#include <net/irda/ircomm_event.h>
41#include <net/irda/ircomm_ttp.h>
42
43static int ircomm_ttp_data_indication(void *instance, void *sap,
44 struct sk_buff *skb);
45static void ircomm_ttp_connect_confirm(void *instance, void *sap,
46 struct qos_info *qos,
47 __u32 max_sdu_size,
48 __u8 max_header_size,
49 struct sk_buff *skb);
50static void ircomm_ttp_connect_indication(void *instance, void *sap,
51 struct qos_info *qos,
52 __u32 max_sdu_size,
53 __u8 max_header_size,
54 struct sk_buff *skb);
55static void ircomm_ttp_flow_indication(void *instance, void *sap,
56 LOCAL_FLOW cmd);
57static void ircomm_ttp_disconnect_indication(void *instance, void *sap,
58 LM_REASON reason,
59 struct sk_buff *skb);
60static int ircomm_ttp_data_request(struct ircomm_cb *self,
61 struct sk_buff *skb,
62 int clen);
63static int ircomm_ttp_connect_request(struct ircomm_cb *self,
64 struct sk_buff *userdata,
65 struct ircomm_info *info);
66static int ircomm_ttp_connect_response(struct ircomm_cb *self,
67 struct sk_buff *userdata);
68static int ircomm_ttp_disconnect_request(struct ircomm_cb *self,
69 struct sk_buff *userdata,
70 struct ircomm_info *info);
71
72/*
73 * Function ircomm_open_tsap (self)
74 *
75 *
76 *
77 */
78int ircomm_open_tsap(struct ircomm_cb *self)
79{
80 notify_t notify;
81
82 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
83
84 /* Register callbacks */
85 irda_notify_init(&notify);
86 notify.data_indication = ircomm_ttp_data_indication;
87 notify.connect_confirm = ircomm_ttp_connect_confirm;
88 notify.connect_indication = ircomm_ttp_connect_indication;
89 notify.flow_indication = ircomm_ttp_flow_indication;
90 notify.disconnect_indication = ircomm_ttp_disconnect_indication;
91 notify.instance = self;
92 strlcpy(notify.name, "IrCOMM", sizeof(notify.name));
93
94 self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
95 &notify);
96 if (!self->tsap) {
97 IRDA_DEBUG(0, "%sfailed to allocate tsap\n", __FUNCTION__ );
98 return -1;
99 }
100 self->slsap_sel = self->tsap->stsap_sel;
101
102 /*
103 * Initialize the call-table for issuing commands
104 */
105 self->issue.data_request = ircomm_ttp_data_request;
106 self->issue.connect_request = ircomm_ttp_connect_request;
107 self->issue.connect_response = ircomm_ttp_connect_response;
108 self->issue.disconnect_request = ircomm_ttp_disconnect_request;
109
110 return 0;
111}
112
113/*
114 * Function ircomm_ttp_connect_request (self, userdata)
115 *
116 *
117 *
118 */
119static int ircomm_ttp_connect_request(struct ircomm_cb *self,
120 struct sk_buff *userdata,
121 struct ircomm_info *info)
122{
123 int ret = 0;
124
125 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
126
127 /* Don't forget to refcount it - should be NULL anyway */
128 if(userdata)
129 skb_get(userdata);
130
131 ret = irttp_connect_request(self->tsap, info->dlsap_sel,
132 info->saddr, info->daddr, NULL,
133 TTP_SAR_DISABLE, userdata);
134
135 return ret;
136}
137
138/*
139 * Function ircomm_ttp_connect_response (self, skb)
140 *
141 *
142 *
143 */
144static int ircomm_ttp_connect_response(struct ircomm_cb *self,
145 struct sk_buff *userdata)
146{
147 int ret;
148
149 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
150
151 /* Don't forget to refcount it - should be NULL anyway */
152 if(userdata)
153 skb_get(userdata);
154
155 ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, userdata);
156
157 return ret;
158}
159
160/*
161 * Function ircomm_ttp_data_request (self, userdata)
162 *
163 * Send IrCOMM data to IrTTP layer. Currently we do not try to combine
164 * control data with pure data, so they will be sent as separate frames.
165 * Should not be a big problem though, since control frames are rare. But
166 * some of them are sent after connection establishment, so this can
167 * increase the latency a bit.
168 */
169static int ircomm_ttp_data_request(struct ircomm_cb *self,
170 struct sk_buff *skb,
171 int clen)
172{
173 int ret;
174
175 IRDA_ASSERT(skb != NULL, return -1;);
176
177 IRDA_DEBUG(2, "%s(), clen=%d\n", __FUNCTION__ , clen);
178
179 /*
180 * Insert clen field, currently we either send data only, or control
181 * only frames, to make things easier and avoid queueing
182 */
183 IRDA_ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;);
184
185 /* Don't forget to refcount it - see ircomm_tty_do_softint() */
186 skb_get(skb);
187
188 skb_push(skb, IRCOMM_HEADER_SIZE);
189
190 skb->data[0] = clen;
191
192 ret = irttp_data_request(self->tsap, skb);
193 if (ret) {
194 IRDA_ERROR("%s(), failed\n", __FUNCTION__);
195 /* irttp_data_request already free the packet */
196 }
197
198 return ret;
199}
200
201/*
202 * Function ircomm_ttp_data_indication (instance, sap, skb)
203 *
204 * Incoming data
205 *
206 */
207static int ircomm_ttp_data_indication(void *instance, void *sap,
208 struct sk_buff *skb)
209{
210 struct ircomm_cb *self = (struct ircomm_cb *) instance;
211
212 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
213
214 IRDA_ASSERT(self != NULL, return -1;);
215 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
216 IRDA_ASSERT(skb != NULL, return -1;);
217
218 ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL);
219
220 /* Drop reference count - see ircomm_tty_data_indication(). */
221 dev_kfree_skb(skb);
222
223 return 0;
224}
225
226static void ircomm_ttp_connect_confirm(void *instance, void *sap,
227 struct qos_info *qos,
228 __u32 max_sdu_size,
229 __u8 max_header_size,
230 struct sk_buff *skb)
231{
232 struct ircomm_cb *self = (struct ircomm_cb *) instance;
233 struct ircomm_info info;
234
235 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
236
237 IRDA_ASSERT(self != NULL, return;);
238 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
239 IRDA_ASSERT(skb != NULL, return;);
240 IRDA_ASSERT(qos != NULL, goto out;);
241
242 if (max_sdu_size != TTP_SAR_DISABLE) {
243 IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
244 __FUNCTION__);
245 goto out;
246 }
247
248 info.max_data_size = irttp_get_max_seg_size(self->tsap)
249 - IRCOMM_HEADER_SIZE;
250 info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
251 info.qos = qos;
252
253 ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info);
254
255out:
256 /* Drop reference count - see ircomm_tty_connect_confirm(). */
257 dev_kfree_skb(skb);
258}
259
260/*
261 * Function ircomm_ttp_connect_indication (instance, sap, qos, max_sdu_size,
262 * max_header_size, skb)
263 *
264 *
265 *
266 */
267static void ircomm_ttp_connect_indication(void *instance, void *sap,
268 struct qos_info *qos,
269 __u32 max_sdu_size,
270 __u8 max_header_size,
271 struct sk_buff *skb)
272{
273 struct ircomm_cb *self = (struct ircomm_cb *)instance;
274 struct ircomm_info info;
275
276 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
277
278 IRDA_ASSERT(self != NULL, return;);
279 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
280 IRDA_ASSERT(skb != NULL, return;);
281 IRDA_ASSERT(qos != NULL, goto out;);
282
283 if (max_sdu_size != TTP_SAR_DISABLE) {
284 IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
285 __FUNCTION__);
286 goto out;
287 }
288
289 info.max_data_size = irttp_get_max_seg_size(self->tsap)
290 - IRCOMM_HEADER_SIZE;
291 info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
292 info.qos = qos;
293
294 ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info);
295
296out:
297 /* Drop reference count - see ircomm_tty_connect_indication(). */
298 dev_kfree_skb(skb);
299}
300
301/*
302 * Function ircomm_ttp_disconnect_request (self, userdata, info)
303 *
304 *
305 *
306 */
307static int ircomm_ttp_disconnect_request(struct ircomm_cb *self,
308 struct sk_buff *userdata,
309 struct ircomm_info *info)
310{
311 int ret;
312
313 /* Don't forget to refcount it - should be NULL anyway */
314 if(userdata)
315 skb_get(userdata);
316
317 ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL);
318
319 return ret;
320}
321
322/*
323 * Function ircomm_ttp_disconnect_indication (instance, sap, reason, skb)
324 *
325 *
326 *
327 */
328static void ircomm_ttp_disconnect_indication(void *instance, void *sap,
329 LM_REASON reason,
330 struct sk_buff *skb)
331{
332 struct ircomm_cb *self = (struct ircomm_cb *) instance;
333 struct ircomm_info info;
334
335 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
336
337 IRDA_ASSERT(self != NULL, return;);
338 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
339
340 info.reason = reason;
341
342 ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info);
343
344 /* Drop reference count - see ircomm_tty_disconnect_indication(). */
345 if(skb)
346 dev_kfree_skb(skb);
347}
348
349/*
350 * Function ircomm_ttp_flow_indication (instance, sap, cmd)
351 *
352 * Layer below is telling us to start or stop the flow of data
353 *
354 */
355static void ircomm_ttp_flow_indication(void *instance, void *sap,
356 LOCAL_FLOW cmd)
357{
358 struct ircomm_cb *self = (struct ircomm_cb *) instance;
359
360 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
361
362 IRDA_ASSERT(self != NULL, return;);
363 IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
364
365 if (self->notify.flow_indication)
366 self->notify.flow_indication(self->notify.instance, self, cmd);
367}
368
369
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
new file mode 100644
index 00000000000..5d1e61168eb
--- /dev/null
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -0,0 +1,1405 @@
1/*********************************************************************
2 *
3 * Filename: ircomm_tty.c
4 * Version: 1.0
5 * Description: IrCOMM serial TTY driver
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Sun Jun 6 21:00:56 1999
9 * Modified at: Wed Feb 23 00:09:02 2000
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 * Sources: serial.c and previous IrCOMM work by Takahide Higuchi
12 *
13 * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
14 * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License as
18 * published by the Free Software Foundation; either version 2 of
19 * the License, or (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29 * MA 02111-1307 USA
30 *
31 ********************************************************************/
32
33#include <linux/config.h>
34#include <linux/init.h>
35#include <linux/module.h>
36#include <linux/fs.h>
37#include <linux/sched.h>
38#include <linux/termios.h>
39#include <linux/tty.h>
40#include <linux/interrupt.h>
41#include <linux/device.h> /* for MODULE_ALIAS_CHARDEV_MAJOR */
42
43#include <asm/uaccess.h>
44
45#include <net/irda/irda.h>
46#include <net/irda/irmod.h>
47
48#include <net/irda/ircomm_core.h>
49#include <net/irda/ircomm_param.h>
50#include <net/irda/ircomm_tty_attach.h>
51#include <net/irda/ircomm_tty.h>
52
53static int ircomm_tty_open(struct tty_struct *tty, struct file *filp);
54static void ircomm_tty_close(struct tty_struct * tty, struct file *filp);
55static int ircomm_tty_write(struct tty_struct * tty,
56 const unsigned char *buf, int count);
57static int ircomm_tty_write_room(struct tty_struct *tty);
58static void ircomm_tty_throttle(struct tty_struct *tty);
59static void ircomm_tty_unthrottle(struct tty_struct *tty);
60static int ircomm_tty_chars_in_buffer(struct tty_struct *tty);
61static void ircomm_tty_flush_buffer(struct tty_struct *tty);
62static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch);
63static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout);
64static void ircomm_tty_hangup(struct tty_struct *tty);
65static void ircomm_tty_do_softint(void *private_);
66static void ircomm_tty_shutdown(struct ircomm_tty_cb *self);
67static void ircomm_tty_stop(struct tty_struct *tty);
68
69static int ircomm_tty_data_indication(void *instance, void *sap,
70 struct sk_buff *skb);
71static int ircomm_tty_control_indication(void *instance, void *sap,
72 struct sk_buff *skb);
73static void ircomm_tty_flow_indication(void *instance, void *sap,
74 LOCAL_FLOW cmd);
75#ifdef CONFIG_PROC_FS
76static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len,
77 int *eof, void *unused);
78#endif /* CONFIG_PROC_FS */
79static struct tty_driver *driver;
80
81hashbin_t *ircomm_tty = NULL;
82
83static struct tty_operations ops = {
84 .open = ircomm_tty_open,
85 .close = ircomm_tty_close,
86 .write = ircomm_tty_write,
87 .write_room = ircomm_tty_write_room,
88 .chars_in_buffer = ircomm_tty_chars_in_buffer,
89 .flush_buffer = ircomm_tty_flush_buffer,
90 .ioctl = ircomm_tty_ioctl, /* ircomm_tty_ioctl.c */
91 .tiocmget = ircomm_tty_tiocmget, /* ircomm_tty_ioctl.c */
92 .tiocmset = ircomm_tty_tiocmset, /* ircomm_tty_ioctl.c */
93 .throttle = ircomm_tty_throttle,
94 .unthrottle = ircomm_tty_unthrottle,
95 .send_xchar = ircomm_tty_send_xchar,
96 .set_termios = ircomm_tty_set_termios,
97 .stop = ircomm_tty_stop,
98 .start = ircomm_tty_start,
99 .hangup = ircomm_tty_hangup,
100 .wait_until_sent = ircomm_tty_wait_until_sent,
101#ifdef CONFIG_PROC_FS
102 .read_proc = ircomm_tty_read_proc,
103#endif /* CONFIG_PROC_FS */
104};
105
106/*
107 * Function ircomm_tty_init()
108 *
109 * Init IrCOMM TTY layer/driver
110 *
111 */
112static int __init ircomm_tty_init(void)
113{
114 driver = alloc_tty_driver(IRCOMM_TTY_PORTS);
115 if (!driver)
116 return -ENOMEM;
117 ircomm_tty = hashbin_new(HB_LOCK);
118 if (ircomm_tty == NULL) {
119 IRDA_ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__);
120 put_tty_driver(driver);
121 return -ENOMEM;
122 }
123
124 driver->owner = THIS_MODULE;
125 driver->driver_name = "ircomm";
126 driver->name = "ircomm";
127 driver->devfs_name = "ircomm";
128 driver->major = IRCOMM_TTY_MAJOR;
129 driver->minor_start = IRCOMM_TTY_MINOR;
130 driver->type = TTY_DRIVER_TYPE_SERIAL;
131 driver->subtype = SERIAL_TYPE_NORMAL;
132 driver->init_termios = tty_std_termios;
133 driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
134 driver->flags = TTY_DRIVER_REAL_RAW;
135 tty_set_operations(driver, &ops);
136 if (tty_register_driver(driver)) {
137 IRDA_ERROR("%s(): Couldn't register serial driver\n",
138 __FUNCTION__);
139 put_tty_driver(driver);
140 return -1;
141 }
142 return 0;
143}
144
145static void __exit __ircomm_tty_cleanup(struct ircomm_tty_cb *self)
146{
147 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
148
149 IRDA_ASSERT(self != NULL, return;);
150 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
151
152 ircomm_tty_shutdown(self);
153
154 self->magic = 0;
155 kfree(self);
156}
157
158/*
159 * Function ircomm_tty_cleanup ()
160 *
161 * Remove IrCOMM TTY layer/driver
162 *
163 */
164static void __exit ircomm_tty_cleanup(void)
165{
166 int ret;
167
168 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
169
170 ret = tty_unregister_driver(driver);
171 if (ret) {
172 IRDA_ERROR("%s(), failed to unregister driver\n",
173 __FUNCTION__);
174 return;
175 }
176
177 hashbin_delete(ircomm_tty, (FREE_FUNC) __ircomm_tty_cleanup);
178 put_tty_driver(driver);
179}
180
181/*
182 * Function ircomm_startup (self)
183 *
184 *
185 *
186 */
187static int ircomm_tty_startup(struct ircomm_tty_cb *self)
188{
189 notify_t notify;
190 int ret = -ENODEV;
191
192 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
193
194 IRDA_ASSERT(self != NULL, return -1;);
195 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
196
197 /* Check if already open */
198 if (test_and_set_bit(ASYNC_B_INITIALIZED, &self->flags)) {
199 IRDA_DEBUG(2, "%s(), already open so break out!\n", __FUNCTION__ );
200 return 0;
201 }
202
203 /* Register with IrCOMM */
204 irda_notify_init(&notify);
205 /* These callbacks we must handle ourselves */
206 notify.data_indication = ircomm_tty_data_indication;
207 notify.udata_indication = ircomm_tty_control_indication;
208 notify.flow_indication = ircomm_tty_flow_indication;
209
210 /* Use the ircomm_tty interface for these ones */
211 notify.disconnect_indication = ircomm_tty_disconnect_indication;
212 notify.connect_confirm = ircomm_tty_connect_confirm;
213 notify.connect_indication = ircomm_tty_connect_indication;
214 strlcpy(notify.name, "ircomm_tty", sizeof(notify.name));
215 notify.instance = self;
216
217 if (!self->ircomm) {
218 self->ircomm = ircomm_open(&notify, self->service_type,
219 self->line);
220 }
221 if (!self->ircomm)
222 goto err;
223
224 self->slsap_sel = self->ircomm->slsap_sel;
225
226 /* Connect IrCOMM link with remote device */
227 ret = ircomm_tty_attach_cable(self);
228 if (ret < 0) {
229 IRDA_ERROR("%s(), error attaching cable!\n", __FUNCTION__);
230 goto err;
231 }
232
233 return 0;
234err:
235 clear_bit(ASYNC_B_INITIALIZED, &self->flags);
236 return ret;
237}
238
239/*
240 * Function ircomm_block_til_ready (self, filp)
241 *
242 *
243 *
244 */
245static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
246 struct file *filp)
247{
248 DECLARE_WAITQUEUE(wait, current);
249 int retval;
250 int do_clocal = 0, extra_count = 0;
251 unsigned long flags;
252 struct tty_struct *tty;
253
254 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
255
256 tty = self->tty;
257
258 /*
259 * If non-blocking mode is set, or the port is not enabled,
260 * then make the check up front and then exit.
261 */
262 if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
263 /* nonblock mode is set or port is not enabled */
264 self->flags |= ASYNC_NORMAL_ACTIVE;
265 IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __FUNCTION__ );
266 return 0;
267 }
268
269 if (tty->termios->c_cflag & CLOCAL) {
270 IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__ );
271 do_clocal = 1;
272 }
273
274 /* Wait for carrier detect and the line to become
275 * free (i.e., not in use by the callout). While we are in
276 * this loop, self->open_count is dropped by one, so that
277 * mgsl_close() knows when to free things. We restore it upon
278 * exit, either normal or abnormal.
279 */
280
281 retval = 0;
282 add_wait_queue(&self->open_wait, &wait);
283
284 IRDA_DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n",
285 __FILE__,__LINE__, tty->driver->name, self->open_count );
286
287 /* As far as I can see, we protect open_count - Jean II */
288 spin_lock_irqsave(&self->spinlock, flags);
289 if (!tty_hung_up_p(filp)) {
290 extra_count = 1;
291 self->open_count--;
292 }
293 spin_unlock_irqrestore(&self->spinlock, flags);
294 self->blocked_open++;
295
296 while (1) {
297 if (tty->termios->c_cflag & CBAUD) {
298 /* Here, we use to lock those two guys, but
299 * as ircomm_param_request() does it itself,
300 * I don't see the point (and I see the deadlock).
301 * Jean II */
302 self->settings.dte |= IRCOMM_RTS + IRCOMM_DTR;
303
304 ircomm_param_request(self, IRCOMM_DTE, TRUE);
305 }
306
307 current->state = TASK_INTERRUPTIBLE;
308
309 if (tty_hung_up_p(filp) ||
310 !test_bit(ASYNC_B_INITIALIZED, &self->flags)) {
311 retval = (self->flags & ASYNC_HUP_NOTIFY) ?
312 -EAGAIN : -ERESTARTSYS;
313 break;
314 }
315
316 /*
317 * Check if link is ready now. Even if CLOCAL is
318 * specified, we cannot return before the IrCOMM link is
319 * ready
320 */
321 if (!test_bit(ASYNC_B_CLOSING, &self->flags) &&
322 (do_clocal || (self->settings.dce & IRCOMM_CD)) &&
323 self->state == IRCOMM_TTY_READY)
324 {
325 break;
326 }
327
328 if (signal_pending(current)) {
329 retval = -ERESTARTSYS;
330 break;
331 }
332
333 IRDA_DEBUG(1, "%s(%d):block_til_ready blocking on %s open_count=%d\n",
334 __FILE__,__LINE__, tty->driver->name, self->open_count );
335
336 schedule();
337 }
338
339 __set_current_state(TASK_RUNNING);
340 remove_wait_queue(&self->open_wait, &wait);
341
342 if (extra_count) {
343 /* ++ is not atomic, so this should be protected - Jean II */
344 spin_lock_irqsave(&self->spinlock, flags);
345 self->open_count++;
346 spin_unlock_irqrestore(&self->spinlock, flags);
347 }
348 self->blocked_open--;
349
350 IRDA_DEBUG(1, "%s(%d):block_til_ready after blocking on %s open_count=%d\n",
351 __FILE__,__LINE__, tty->driver->name, self->open_count);
352
353 if (!retval)
354 self->flags |= ASYNC_NORMAL_ACTIVE;
355
356 return retval;
357}
358
359/*
360 * Function ircomm_tty_open (tty, filp)
361 *
362 * This routine is called when a particular tty device is opened. This
363 * routine is mandatory; if this routine is not filled in, the attempted
364 * open will fail with ENODEV.
365 */
366static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
367{
368 struct ircomm_tty_cb *self;
369 unsigned int line;
370 unsigned long flags;
371 int ret;
372
373 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
374
375 line = tty->index;
376 if ((line < 0) || (line >= IRCOMM_TTY_PORTS)) {
377 return -ENODEV;
378 }
379
380 /* Check if instance already exists */
381 self = hashbin_lock_find(ircomm_tty, line, NULL);
382 if (!self) {
383 /* No, so make new instance */
384 self = kmalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL);
385 if (self == NULL) {
386 IRDA_ERROR("%s(), kmalloc failed!\n", __FUNCTION__);
387 return -ENOMEM;
388 }
389 memset(self, 0, sizeof(struct ircomm_tty_cb));
390
391 self->magic = IRCOMM_TTY_MAGIC;
392 self->flow = FLOW_STOP;
393
394 self->line = line;
395 INIT_WORK(&self->tqueue, ircomm_tty_do_softint, self);
396 self->max_header_size = IRCOMM_TTY_HDR_UNINITIALISED;
397 self->max_data_size = IRCOMM_TTY_DATA_UNINITIALISED;
398 self->close_delay = 5*HZ/10;
399 self->closing_wait = 30*HZ;
400
401 /* Init some important stuff */
402 init_timer(&self->watchdog_timer);
403 init_waitqueue_head(&self->open_wait);
404 init_waitqueue_head(&self->close_wait);
405 spin_lock_init(&self->spinlock);
406
407 /*
408 * Force TTY into raw mode by default which is usually what
409 * we want for IrCOMM and IrLPT. This way applications will
410 * not have to twiddle with printcap etc.
411 */
412 tty->termios->c_iflag = 0;
413 tty->termios->c_oflag = 0;
414
415 /* Insert into hash */
416 hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL);
417 }
418 /* ++ is not atomic, so this should be protected - Jean II */
419 spin_lock_irqsave(&self->spinlock, flags);
420 self->open_count++;
421
422 tty->driver_data = self;
423 self->tty = tty;
424 spin_unlock_irqrestore(&self->spinlock, flags);
425
426 IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __FUNCTION__ , tty->driver->name,
427 self->line, self->open_count);
428
429 /* Not really used by us, but lets do it anyway */
430 self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
431
432 /*
433 * If the port is the middle of closing, bail out now
434 */
435 if (tty_hung_up_p(filp) ||
436 test_bit(ASYNC_B_CLOSING, &self->flags)) {
437
438 /* Hm, why are we blocking on ASYNC_CLOSING if we
439 * do return -EAGAIN/-ERESTARTSYS below anyway?
440 * IMHO it's either not needed in the first place
441 * or for some reason we need to make sure the async
442 * closing has been finished - if so, wouldn't we
443 * probably better sleep uninterruptible?
444 */
445
446 if (wait_event_interruptible(self->close_wait, !test_bit(ASYNC_B_CLOSING, &self->flags))) {
447 IRDA_WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n",
448 __FUNCTION__);
449 return -ERESTARTSYS;
450 }
451
452#ifdef SERIAL_DO_RESTART
453 return ((self->flags & ASYNC_HUP_NOTIFY) ?
454 -EAGAIN : -ERESTARTSYS);
455#else
456 return -EAGAIN;
457#endif
458 }
459
460 /* Check if this is a "normal" ircomm device, or an irlpt device */
461 if (line < 0x10) {
462 self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
463 self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */
464 /* Jan Kiszka -> add DSR/RI -> Conform to IrCOMM spec */
465 self->settings.dce = IRCOMM_CTS | IRCOMM_CD | IRCOMM_DSR | IRCOMM_RI; /* Default line settings */
466 IRDA_DEBUG(2, "%s(), IrCOMM device\n", __FUNCTION__ );
467 } else {
468 IRDA_DEBUG(2, "%s(), IrLPT device\n", __FUNCTION__ );
469 self->service_type = IRCOMM_3_WIRE_RAW;
470 self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */
471 }
472
473 ret = ircomm_tty_startup(self);
474 if (ret)
475 return ret;
476
477 ret = ircomm_tty_block_til_ready(self, filp);
478 if (ret) {
479 IRDA_DEBUG(2,
480 "%s(), returning after block_til_ready with %d\n", __FUNCTION__ ,
481 ret);
482
483 return ret;
484 }
485 return 0;
486}
487
488/*
489 * Function ircomm_tty_close (tty, filp)
490 *
491 * This routine is called when a particular tty device is closed.
492 *
493 */
494static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
495{
496 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
497 unsigned long flags;
498
499 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
500
501 if (!tty)
502 return;
503
504 IRDA_ASSERT(self != NULL, return;);
505 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
506
507 spin_lock_irqsave(&self->spinlock, flags);
508
509 if (tty_hung_up_p(filp)) {
510 spin_unlock_irqrestore(&self->spinlock, flags);
511
512 IRDA_DEBUG(0, "%s(), returning 1\n", __FUNCTION__ );
513 return;
514 }
515
516 if ((tty->count == 1) && (self->open_count != 1)) {
517 /*
518 * Uh, oh. tty->count is 1, which means that the tty
519 * structure will be freed. state->count should always
520 * be one in these conditions. If it's greater than
521 * one, we've got real problems, since it means the
522 * serial port won't be shutdown.
523 */
524 IRDA_DEBUG(0, "%s(), bad serial port count; "
525 "tty->count is 1, state->count is %d\n", __FUNCTION__ ,
526 self->open_count);
527 self->open_count = 1;
528 }
529
530 if (--self->open_count < 0) {
531 IRDA_ERROR("%s(), bad serial port count for ttys%d: %d\n",
532 __FUNCTION__, self->line, self->open_count);
533 self->open_count = 0;
534 }
535 if (self->open_count) {
536 spin_unlock_irqrestore(&self->spinlock, flags);
537
538 IRDA_DEBUG(0, "%s(), open count > 0\n", __FUNCTION__ );
539 return;
540 }
541
542 /* Hum... Should be test_and_set_bit ??? - Jean II */
543 set_bit(ASYNC_B_CLOSING, &self->flags);
544
545 /* We need to unlock here (we were unlocking at the end of this
546 * function), because tty_wait_until_sent() may schedule.
547 * I don't know if the rest should be protected somehow,
548 * so someone should check. - Jean II */
549 spin_unlock_irqrestore(&self->spinlock, flags);
550
551 /*
552 * Now we wait for the transmit buffer to clear; and we notify
553 * the line discipline to only process XON/XOFF characters.
554 */
555 tty->closing = 1;
556 if (self->closing_wait != ASYNC_CLOSING_WAIT_NONE)
557 tty_wait_until_sent(tty, self->closing_wait);
558
559 ircomm_tty_shutdown(self);
560
561 if (tty->driver->flush_buffer)
562 tty->driver->flush_buffer(tty);
563 if (tty->ldisc.flush_buffer)
564 tty->ldisc.flush_buffer(tty);
565
566 tty->closing = 0;
567 self->tty = NULL;
568
569 if (self->blocked_open) {
570 if (self->close_delay) {
571 current->state = TASK_INTERRUPTIBLE;
572 schedule_timeout(self->close_delay);
573 }
574 wake_up_interruptible(&self->open_wait);
575 }
576
577 self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
578 wake_up_interruptible(&self->close_wait);
579}
580
581/*
582 * Function ircomm_tty_flush_buffer (tty)
583 *
584 *
585 *
586 */
587static void ircomm_tty_flush_buffer(struct tty_struct *tty)
588{
589 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
590
591 IRDA_ASSERT(self != NULL, return;);
592 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
593
594 /*
595 * Let do_softint() do this to avoid race condition with
596 * do_softint() ;-)
597 */
598 schedule_work(&self->tqueue);
599}
600
601/*
602 * Function ircomm_tty_do_softint (private_)
603 *
604 * We use this routine to give the write wakeup to the user at at a
605 * safe time (as fast as possible after write have completed). This
606 * can be compared to the Tx interrupt.
607 */
608static void ircomm_tty_do_softint(void *private_)
609{
610 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) private_;
611 struct tty_struct *tty;
612 unsigned long flags;
613 struct sk_buff *skb, *ctrl_skb;
614
615 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
616
617 if (!self || self->magic != IRCOMM_TTY_MAGIC)
618 return;
619
620 tty = self->tty;
621 if (!tty)
622 return;
623
624 /* Unlink control buffer */
625 spin_lock_irqsave(&self->spinlock, flags);
626
627 ctrl_skb = self->ctrl_skb;
628 self->ctrl_skb = NULL;
629
630 spin_unlock_irqrestore(&self->spinlock, flags);
631
632 /* Flush control buffer if any */
633 if(ctrl_skb) {
634 if(self->flow == FLOW_START)
635 ircomm_control_request(self->ircomm, ctrl_skb);
636 /* Drop reference count - see ircomm_ttp_data_request(). */
637 dev_kfree_skb(ctrl_skb);
638 }
639
640 if (tty->hw_stopped)
641 return;
642
643 /* Unlink transmit buffer */
644 spin_lock_irqsave(&self->spinlock, flags);
645
646 skb = self->tx_skb;
647 self->tx_skb = NULL;
648
649 spin_unlock_irqrestore(&self->spinlock, flags);
650
651 /* Flush transmit buffer if any */
652 if (skb) {
653 ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL);
654 /* Drop reference count - see ircomm_ttp_data_request(). */
655 dev_kfree_skb(skb);
656 }
657
658 /* Check if user (still) wants to be waken up */
659 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
660 tty->ldisc.write_wakeup)
661 {
662 (tty->ldisc.write_wakeup)(tty);
663 }
664 wake_up_interruptible(&tty->write_wait);
665}
666
667/*
668 * Function ircomm_tty_write (tty, buf, count)
669 *
670 * This routine is called by the kernel to write a series of characters
671 * to the tty device. The characters may come from user space or kernel
672 * space. This routine will return the number of characters actually
673 * accepted for writing. This routine is mandatory.
674 */
675static int ircomm_tty_write(struct tty_struct *tty,
676 const unsigned char *buf, int count)
677{
678 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
679 unsigned long flags;
680 struct sk_buff *skb;
681 int tailroom = 0;
682 int len = 0;
683 int size;
684
685 IRDA_DEBUG(2, "%s(), count=%d, hw_stopped=%d\n", __FUNCTION__ , count,
686 tty->hw_stopped);
687
688 IRDA_ASSERT(self != NULL, return -1;);
689 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
690
691 /* We may receive packets from the TTY even before we have finished
692 * our setup. Not cool.
693 * The problem is that we don't know the final header and data size
694 * to create the proper skb, so any skb we would create would have
695 * bogus header and data size, so need care.
696 * We use a bogus header size to safely detect this condition.
697 * Another problem is that hw_stopped was set to 0 way before it
698 * should be, so we would drop this skb. It should now be fixed.
699 * One option is to not accept data until we are properly setup.
700 * But, I suspect that when it happens, the ppp line discipline
701 * just "drops" the data, which might screw up connect scripts.
702 * The second option is to create a "safe skb", with large header
703 * and small size (see ircomm_tty_open() for values).
704 * We just need to make sure that when the real values get filled,
705 * we don't mess up the original "safe skb" (see tx_data_size).
706 * Jean II */
707 if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED) {
708 IRDA_DEBUG(1, "%s() : not initialised\n", __FUNCTION__);
709#ifdef IRCOMM_NO_TX_BEFORE_INIT
710 /* We didn't consume anything, TTY will retry */
711 return 0;
712#endif
713 }
714
715 if (count < 1)
716 return 0;
717
718 /* Protect our manipulation of self->tx_skb and related */
719 spin_lock_irqsave(&self->spinlock, flags);
720
721 /* Fetch current transmit buffer */
722 skb = self->tx_skb;
723
724 /*
725 * Send out all the data we get, possibly as multiple fragmented
726 * frames, but this will only happen if the data is larger than the
727 * max data size. The normal case however is just the opposite, and
728 * this function may be called multiple times, and will then actually
729 * defragment the data and send it out as one packet as soon as
730 * possible, but at a safer point in time
731 */
732 while (count) {
733 size = count;
734
735 /* Adjust data size to the max data size */
736 if (size > self->max_data_size)
737 size = self->max_data_size;
738
739 /*
740 * Do we already have a buffer ready for transmit, or do
741 * we need to allocate a new frame
742 */
743 if (skb) {
744 /*
745 * Any room for more data at the end of the current
746 * transmit buffer? Cannot use skb_tailroom, since
747 * dev_alloc_skb gives us a larger skb than we
748 * requested
749 * Note : use tx_data_size, because max_data_size
750 * may have changed and we don't want to overwrite
751 * the skb. - Jean II
752 */
753 if ((tailroom = (self->tx_data_size - skb->len)) > 0) {
754 /* Adjust data to tailroom */
755 if (size > tailroom)
756 size = tailroom;
757 } else {
758 /*
759 * Current transmit frame is full, so break
760 * out, so we can send it as soon as possible
761 */
762 break;
763 }
764 } else {
765 /* Prepare a full sized frame */
766 skb = dev_alloc_skb(self->max_data_size+
767 self->max_header_size);
768 if (!skb) {
769 spin_unlock_irqrestore(&self->spinlock, flags);
770 return -ENOBUFS;
771 }
772 skb_reserve(skb, self->max_header_size);
773 self->tx_skb = skb;
774 /* Remember skb size because max_data_size may
775 * change later on - Jean II */
776 self->tx_data_size = self->max_data_size;
777 }
778
779 /* Copy data */
780 memcpy(skb_put(skb,size), buf + len, size);
781
782 count -= size;
783 len += size;
784 }
785
786 spin_unlock_irqrestore(&self->spinlock, flags);
787
788 /*
789 * Schedule a new thread which will transmit the frame as soon
790 * as possible, but at a safe point in time. We do this so the
791 * "user" can give us data multiple times, as PPP does (because of
792 * its 256 byte tx buffer). We will then defragment and send out
793 * all this data as one single packet.
794 */
795 schedule_work(&self->tqueue);
796
797 return len;
798}
799
800/*
801 * Function ircomm_tty_write_room (tty)
802 *
803 * This routine returns the numbers of characters the tty driver will
804 * accept for queuing to be written. This number is subject to change as
805 * output buffers get emptied, or if the output flow control is acted.
806 */
807static int ircomm_tty_write_room(struct tty_struct *tty)
808{
809 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
810 unsigned long flags;
811 int ret;
812
813 IRDA_ASSERT(self != NULL, return -1;);
814 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
815
816#ifdef IRCOMM_NO_TX_BEFORE_INIT
817 /* max_header_size tells us if the channel is initialised or not. */
818 if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED)
819 /* Don't bother us yet */
820 return 0;
821#endif
822
823 /* Check if we are allowed to transmit any data.
824 * hw_stopped is the regular flow control.
825 * Jean II */
826 if (tty->hw_stopped)
827 ret = 0;
828 else {
829 spin_lock_irqsave(&self->spinlock, flags);
830 if (self->tx_skb)
831 ret = self->tx_data_size - self->tx_skb->len;
832 else
833 ret = self->max_data_size;
834 spin_unlock_irqrestore(&self->spinlock, flags);
835 }
836 IRDA_DEBUG(2, "%s(), ret=%d\n", __FUNCTION__ , ret);
837
838 return ret;
839}
840
841/*
842 * Function ircomm_tty_wait_until_sent (tty, timeout)
843 *
844 * This routine waits until the device has written out all of the
845 * characters in its transmitter FIFO.
846 */
847static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
848{
849 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
850 unsigned long orig_jiffies, poll_time;
851 unsigned long flags;
852
853 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
854
855 IRDA_ASSERT(self != NULL, return;);
856 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
857
858 orig_jiffies = jiffies;
859
860 /* Set poll time to 200 ms */
861 poll_time = IRDA_MIN(timeout, msecs_to_jiffies(200));
862
863 spin_lock_irqsave(&self->spinlock, flags);
864 while (self->tx_skb && self->tx_skb->len) {
865 spin_unlock_irqrestore(&self->spinlock, flags);
866 current->state = TASK_INTERRUPTIBLE;
867 schedule_timeout(poll_time);
868 spin_lock_irqsave(&self->spinlock, flags);
869 if (signal_pending(current))
870 break;
871 if (timeout && time_after(jiffies, orig_jiffies + timeout))
872 break;
873 }
874 spin_unlock_irqrestore(&self->spinlock, flags);
875 current->state = TASK_RUNNING;
876}
877
878/*
879 * Function ircomm_tty_throttle (tty)
880 *
881 * This routine notifies the tty driver that input buffers for the line
882 * discipline are close to full, and it should somehow signal that no
883 * more characters should be sent to the tty.
884 */
885static void ircomm_tty_throttle(struct tty_struct *tty)
886{
887 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
888
889 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
890
891 IRDA_ASSERT(self != NULL, return;);
892 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
893
894 /* Software flow control? */
895 if (I_IXOFF(tty))
896 ircomm_tty_send_xchar(tty, STOP_CHAR(tty));
897
898 /* Hardware flow control? */
899 if (tty->termios->c_cflag & CRTSCTS) {
900 self->settings.dte &= ~IRCOMM_RTS;
901 self->settings.dte |= IRCOMM_DELTA_RTS;
902
903 ircomm_param_request(self, IRCOMM_DTE, TRUE);
904 }
905
906 ircomm_flow_request(self->ircomm, FLOW_STOP);
907}
908
909/*
910 * Function ircomm_tty_unthrottle (tty)
911 *
912 * This routine notifies the tty drivers that it should signals that
913 * characters can now be sent to the tty without fear of overrunning the
914 * input buffers of the line disciplines.
915 */
916static void ircomm_tty_unthrottle(struct tty_struct *tty)
917{
918 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
919
920 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
921
922 IRDA_ASSERT(self != NULL, return;);
923 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
924
925 /* Using software flow control? */
926 if (I_IXOFF(tty)) {
927 ircomm_tty_send_xchar(tty, START_CHAR(tty));
928 }
929
930 /* Using hardware flow control? */
931 if (tty->termios->c_cflag & CRTSCTS) {
932 self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
933
934 ircomm_param_request(self, IRCOMM_DTE, TRUE);
935 IRDA_DEBUG(1, "%s(), FLOW_START\n", __FUNCTION__ );
936 }
937 ircomm_flow_request(self->ircomm, FLOW_START);
938}
939
940/*
941 * Function ircomm_tty_chars_in_buffer (tty)
942 *
943 * Indicates if there are any data in the buffer
944 *
945 */
946static int ircomm_tty_chars_in_buffer(struct tty_struct *tty)
947{
948 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
949 unsigned long flags;
950 int len = 0;
951
952 IRDA_ASSERT(self != NULL, return -1;);
953 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
954
955 spin_lock_irqsave(&self->spinlock, flags);
956
957 if (self->tx_skb)
958 len = self->tx_skb->len;
959
960 spin_unlock_irqrestore(&self->spinlock, flags);
961
962 return len;
963}
964
965static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
966{
967 unsigned long flags;
968
969 IRDA_ASSERT(self != NULL, return;);
970 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
971
972 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
973
974 if (!test_and_clear_bit(ASYNC_B_INITIALIZED, &self->flags))
975 return;
976
977 ircomm_tty_detach_cable(self);
978
979 spin_lock_irqsave(&self->spinlock, flags);
980
981 del_timer(&self->watchdog_timer);
982
983 /* Free parameter buffer */
984 if (self->ctrl_skb) {
985 dev_kfree_skb(self->ctrl_skb);
986 self->ctrl_skb = NULL;
987 }
988
989 /* Free transmit buffer */
990 if (self->tx_skb) {
991 dev_kfree_skb(self->tx_skb);
992 self->tx_skb = NULL;
993 }
994
995 if (self->ircomm) {
996 ircomm_close(self->ircomm);
997 self->ircomm = NULL;
998 }
999
1000 spin_unlock_irqrestore(&self->spinlock, flags);
1001}
1002
1003/*
1004 * Function ircomm_tty_hangup (tty)
1005 *
1006 * This routine notifies the tty driver that it should hangup the tty
1007 * device.
1008 *
1009 */
1010static void ircomm_tty_hangup(struct tty_struct *tty)
1011{
1012 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
1013 unsigned long flags;
1014
1015 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
1016
1017 IRDA_ASSERT(self != NULL, return;);
1018 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
1019
1020 if (!tty)
1021 return;
1022
1023 /* ircomm_tty_flush_buffer(tty); */
1024 ircomm_tty_shutdown(self);
1025
1026 /* I guess we need to lock here - Jean II */
1027 spin_lock_irqsave(&self->spinlock, flags);
1028 self->flags &= ~ASYNC_NORMAL_ACTIVE;
1029 self->tty = NULL;
1030 self->open_count = 0;
1031 spin_unlock_irqrestore(&self->spinlock, flags);
1032
1033 wake_up_interruptible(&self->open_wait);
1034}
1035
1036/*
1037 * Function ircomm_tty_send_xchar (tty, ch)
1038 *
1039 * This routine is used to send a high-priority XON/XOFF character to
1040 * the device.
1041 */
1042static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch)
1043{
1044 IRDA_DEBUG(0, "%s(), not impl\n", __FUNCTION__ );
1045}
1046
1047/*
1048 * Function ircomm_tty_start (tty)
1049 *
1050 * This routine notifies the tty driver that it resume sending
1051 * characters to the tty device.
1052 */
1053void ircomm_tty_start(struct tty_struct *tty)
1054{
1055 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
1056
1057 ircomm_flow_request(self->ircomm, FLOW_START);
1058}
1059
1060/*
1061 * Function ircomm_tty_stop (tty)
1062 *
1063 * This routine notifies the tty driver that it should stop outputting
1064 * characters to the tty device.
1065 */
1066static void ircomm_tty_stop(struct tty_struct *tty)
1067{
1068 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
1069
1070 IRDA_ASSERT(self != NULL, return;);
1071 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
1072
1073 ircomm_flow_request(self->ircomm, FLOW_STOP);
1074}
1075
1076/*
1077 * Function ircomm_check_modem_status (self)
1078 *
1079 * Check for any changes in the DCE's line settings. This function should
1080 * be called whenever the dce parameter settings changes, to update the
1081 * flow control settings and other things
1082 */
1083void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
1084{
1085 struct tty_struct *tty;
1086 int status;
1087
1088 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
1089
1090 IRDA_ASSERT(self != NULL, return;);
1091 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
1092
1093 tty = self->tty;
1094
1095 status = self->settings.dce;
1096
1097 if (status & IRCOMM_DCE_DELTA_ANY) {
1098 /*wake_up_interruptible(&self->delta_msr_wait);*/
1099 }
1100 if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
1101 IRDA_DEBUG(2,
1102 "%s(), ircomm%d CD now %s...\n", __FUNCTION__ , self->line,
1103 (status & IRCOMM_CD) ? "on" : "off");
1104
1105 if (status & IRCOMM_CD) {
1106 wake_up_interruptible(&self->open_wait);
1107 } else {
1108 IRDA_DEBUG(2,
1109 "%s(), Doing serial hangup..\n", __FUNCTION__ );
1110 if (tty)
1111 tty_hangup(tty);
1112
1113 /* Hangup will remote the tty, so better break out */
1114 return;
1115 }
1116 }
1117 if (self->flags & ASYNC_CTS_FLOW) {
1118 if (tty->hw_stopped) {
1119 if (status & IRCOMM_CTS) {
1120 IRDA_DEBUG(2,
1121 "%s(), CTS tx start...\n", __FUNCTION__ );
1122 tty->hw_stopped = 0;
1123
1124 /* Wake up processes blocked on open */
1125 wake_up_interruptible(&self->open_wait);
1126
1127 schedule_work(&self->tqueue);
1128 return;
1129 }
1130 } else {
1131 if (!(status & IRCOMM_CTS)) {
1132 IRDA_DEBUG(2,
1133 "%s(), CTS tx stop...\n", __FUNCTION__ );
1134 tty->hw_stopped = 1;
1135 }
1136 }
1137 }
1138}
1139
1140/*
1141 * Function ircomm_tty_data_indication (instance, sap, skb)
1142 *
1143 * Handle incoming data, and deliver it to the line discipline
1144 *
1145 */
1146static int ircomm_tty_data_indication(void *instance, void *sap,
1147 struct sk_buff *skb)
1148{
1149 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
1150
1151 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
1152
1153 IRDA_ASSERT(self != NULL, return -1;);
1154 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
1155 IRDA_ASSERT(skb != NULL, return -1;);
1156
1157 if (!self->tty) {
1158 IRDA_DEBUG(0, "%s(), no tty!\n", __FUNCTION__ );
1159 return 0;
1160 }
1161
1162 /*
1163 * If we receive data when hardware is stopped then something is wrong.
1164 * We try to poll the peers line settings to check if we are up todate.
1165 * Devices like WinCE can do this, and since they don't send any
1166 * params, we can just as well declare the hardware for running.
1167 */
1168 if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
1169 IRDA_DEBUG(0, "%s(), polling for line settings!\n", __FUNCTION__ );
1170 ircomm_param_request(self, IRCOMM_POLL, TRUE);
1171
1172 /* We can just as well declare the hardware for running */
1173 ircomm_tty_send_initial_parameters(self);
1174 ircomm_tty_link_established(self);
1175 }
1176
1177 /*
1178 * Just give it over to the line discipline. There is no need to
1179 * involve the flip buffers, since we are not running in an interrupt
1180 * handler
1181 */
1182 self->tty->ldisc.receive_buf(self->tty, skb->data, NULL, skb->len);
1183
1184 /* No need to kfree_skb - see ircomm_ttp_data_indication() */
1185
1186 return 0;
1187}
1188
1189/*
1190 * Function ircomm_tty_control_indication (instance, sap, skb)
1191 *
1192 * Parse all incoming parameters (easy!)
1193 *
1194 */
1195static int ircomm_tty_control_indication(void *instance, void *sap,
1196 struct sk_buff *skb)
1197{
1198 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
1199 int clen;
1200
1201 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
1202
1203 IRDA_ASSERT(self != NULL, return -1;);
1204 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
1205 IRDA_ASSERT(skb != NULL, return -1;);
1206
1207 clen = skb->data[0];
1208
1209 irda_param_extract_all(self, skb->data+1, IRDA_MIN(skb->len-1, clen),
1210 &ircomm_param_info);
1211
1212 /* No need to kfree_skb - see ircomm_control_indication() */
1213
1214 return 0;
1215}
1216
1217/*
1218 * Function ircomm_tty_flow_indication (instance, sap, cmd)
1219 *
1220 * This function is called by IrTTP when it wants us to slow down the
1221 * transmission of data. We just mark the hardware as stopped, and wait
1222 * for IrTTP to notify us that things are OK again.
1223 */
1224static void ircomm_tty_flow_indication(void *instance, void *sap,
1225 LOCAL_FLOW cmd)
1226{
1227 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
1228 struct tty_struct *tty;
1229
1230 IRDA_ASSERT(self != NULL, return;);
1231 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
1232
1233 tty = self->tty;
1234
1235 switch (cmd) {
1236 case FLOW_START:
1237 IRDA_DEBUG(2, "%s(), hw start!\n", __FUNCTION__ );
1238 tty->hw_stopped = 0;
1239
1240 /* ircomm_tty_do_softint will take care of the rest */
1241 schedule_work(&self->tqueue);
1242 break;
1243 default: /* If we get here, something is very wrong, better stop */
1244 case FLOW_STOP:
1245 IRDA_DEBUG(2, "%s(), hw stopped!\n", __FUNCTION__ );
1246 tty->hw_stopped = 1;
1247 break;
1248 }
1249 self->flow = cmd;
1250}
1251
1252static int ircomm_tty_line_info(struct ircomm_tty_cb *self, char *buf)
1253{
1254 int ret=0;
1255
1256 ret += sprintf(buf+ret, "State: %s\n", ircomm_tty_state[self->state]);
1257
1258 ret += sprintf(buf+ret, "Service type: ");
1259 if (self->service_type & IRCOMM_9_WIRE)
1260 ret += sprintf(buf+ret, "9_WIRE");
1261 else if (self->service_type & IRCOMM_3_WIRE)
1262 ret += sprintf(buf+ret, "3_WIRE");
1263 else if (self->service_type & IRCOMM_3_WIRE_RAW)
1264 ret += sprintf(buf+ret, "3_WIRE_RAW");
1265 else
1266 ret += sprintf(buf+ret, "No common service type!\n");
1267 ret += sprintf(buf+ret, "\n");
1268
1269 ret += sprintf(buf+ret, "Port name: %s\n", self->settings.port_name);
1270
1271 ret += sprintf(buf+ret, "DTE status: ");
1272 if (self->settings.dte & IRCOMM_RTS)
1273 ret += sprintf(buf+ret, "RTS|");
1274 if (self->settings.dte & IRCOMM_DTR)
1275 ret += sprintf(buf+ret, "DTR|");
1276 if (self->settings.dte)
1277 ret--; /* remove the last | */
1278 ret += sprintf(buf+ret, "\n");
1279
1280 ret += sprintf(buf+ret, "DCE status: ");
1281 if (self->settings.dce & IRCOMM_CTS)
1282 ret += sprintf(buf+ret, "CTS|");
1283 if (self->settings.dce & IRCOMM_DSR)
1284 ret += sprintf(buf+ret, "DSR|");
1285 if (self->settings.dce & IRCOMM_CD)
1286 ret += sprintf(buf+ret, "CD|");
1287 if (self->settings.dce & IRCOMM_RI)
1288 ret += sprintf(buf+ret, "RI|");
1289 if (self->settings.dce)
1290 ret--; /* remove the last | */
1291 ret += sprintf(buf+ret, "\n");
1292
1293 ret += sprintf(buf+ret, "Configuration: ");
1294 if (!self->settings.null_modem)
1295 ret += sprintf(buf+ret, "DTE <-> DCE\n");
1296 else
1297 ret += sprintf(buf+ret,
1298 "DTE <-> DTE (null modem emulation)\n");
1299
1300 ret += sprintf(buf+ret, "Data rate: %d\n", self->settings.data_rate);
1301
1302 ret += sprintf(buf+ret, "Flow control: ");
1303 if (self->settings.flow_control & IRCOMM_XON_XOFF_IN)
1304 ret += sprintf(buf+ret, "XON_XOFF_IN|");
1305 if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT)
1306 ret += sprintf(buf+ret, "XON_XOFF_OUT|");
1307 if (self->settings.flow_control & IRCOMM_RTS_CTS_IN)
1308 ret += sprintf(buf+ret, "RTS_CTS_IN|");
1309 if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT)
1310 ret += sprintf(buf+ret, "RTS_CTS_OUT|");
1311 if (self->settings.flow_control & IRCOMM_DSR_DTR_IN)
1312 ret += sprintf(buf+ret, "DSR_DTR_IN|");
1313 if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT)
1314 ret += sprintf(buf+ret, "DSR_DTR_OUT|");
1315 if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN)
1316 ret += sprintf(buf+ret, "ENQ_ACK_IN|");
1317 if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT)
1318 ret += sprintf(buf+ret, "ENQ_ACK_OUT|");
1319 if (self->settings.flow_control)
1320 ret--; /* remove the last | */
1321 ret += sprintf(buf+ret, "\n");
1322
1323 ret += sprintf(buf+ret, "Flags: ");
1324 if (self->flags & ASYNC_CTS_FLOW)
1325 ret += sprintf(buf+ret, "ASYNC_CTS_FLOW|");
1326 if (self->flags & ASYNC_CHECK_CD)
1327 ret += sprintf(buf+ret, "ASYNC_CHECK_CD|");
1328 if (self->flags & ASYNC_INITIALIZED)
1329 ret += sprintf(buf+ret, "ASYNC_INITIALIZED|");
1330 if (self->flags & ASYNC_LOW_LATENCY)
1331 ret += sprintf(buf+ret, "ASYNC_LOW_LATENCY|");
1332 if (self->flags & ASYNC_CLOSING)
1333 ret += sprintf(buf+ret, "ASYNC_CLOSING|");
1334 if (self->flags & ASYNC_NORMAL_ACTIVE)
1335 ret += sprintf(buf+ret, "ASYNC_NORMAL_ACTIVE|");
1336 if (self->flags)
1337 ret--; /* remove the last | */
1338 ret += sprintf(buf+ret, "\n");
1339
1340 ret += sprintf(buf+ret, "Role: %s\n", self->client ?
1341 "client" : "server");
1342 ret += sprintf(buf+ret, "Open count: %d\n", self->open_count);
1343 ret += sprintf(buf+ret, "Max data size: %d\n", self->max_data_size);
1344 ret += sprintf(buf+ret, "Max header size: %d\n", self->max_header_size);
1345
1346 if (self->tty)
1347 ret += sprintf(buf+ret, "Hardware: %s\n",
1348 self->tty->hw_stopped ? "Stopped" : "Running");
1349
1350 ret += sprintf(buf+ret, "\n");
1351 return ret;
1352}
1353
1354
1355/*
1356 * Function ircomm_tty_read_proc (buf, start, offset, len, eof, unused)
1357 *
1358 *
1359 *
1360 */
1361#ifdef CONFIG_PROC_FS
1362static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len,
1363 int *eof, void *unused)
1364{
1365 struct ircomm_tty_cb *self;
1366 int count = 0, l;
1367 off_t begin = 0;
1368 unsigned long flags;
1369
1370 spin_lock_irqsave(&ircomm_tty->hb_spinlock, flags);
1371
1372 self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
1373 while ((self != NULL) && (count < 4000)) {
1374 if (self->magic != IRCOMM_TTY_MAGIC)
1375 break;
1376
1377 l = ircomm_tty_line_info(self, buf + count);
1378 count += l;
1379 if (count+begin > offset+len)
1380 goto done;
1381 if (count+begin < offset) {
1382 begin += count;
1383 count = 0;
1384 }
1385
1386 self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty);
1387 }
1388 *eof = 1;
1389done:
1390 spin_unlock_irqrestore(&ircomm_tty->hb_spinlock, flags);
1391
1392 if (offset >= count+begin)
1393 return 0;
1394 *start = buf + (offset-begin);
1395 return ((len < begin+count-offset) ? len : begin+count-offset);
1396}
1397#endif /* CONFIG_PROC_FS */
1398
1399MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
1400MODULE_DESCRIPTION("IrCOMM serial TTY driver");
1401MODULE_LICENSE("GPL");
1402MODULE_ALIAS_CHARDEV_MAJOR(IRCOMM_TTY_MAJOR);
1403
1404module_init(ircomm_tty_init);
1405module_exit(ircomm_tty_cleanup);
diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c
new file mode 100644
index 00000000000..99f5eddbb4b
--- /dev/null
+++ b/net/irda/ircomm/ircomm_tty_attach.c
@@ -0,0 +1,1006 @@
1/*********************************************************************
2 *
3 * Filename: ircomm_tty_attach.c
4 * Version:
5 * Description: Code for attaching the serial driver to IrCOMM
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Sat Jun 5 17:42:00 1999
9 * Modified at: Tue Jan 4 14:20:49 2000
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 *
12 * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
13 * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of
18 * the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28 * MA 02111-1307 USA
29 *
30 ********************************************************************/
31
32#include <linux/sched.h>
33#include <linux/init.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
49static void ircomm_tty_ias_register(struct ircomm_tty_cb *self);
50static void ircomm_tty_discovery_indication(discinfo_t *discovery,
51 DISCOVERY_MODE mode,
52 void *priv);
53static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,
54 struct ias_value *value, void *priv);
55static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self,
56 int timeout);
57static void ircomm_tty_watchdog_timer_expired(void *data);
58
59static 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);
63static 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);
67static 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);
71static 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);
75static 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);
79static 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
84char *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
95static char *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
113static 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 */
131int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
132{
133 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
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", __FUNCTION__ );
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 */
160void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
161{
162 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
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 */
206static 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", __FUNCTION__ );
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 */
263static 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 */
300int 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", __FUNCTION__ ,
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", __FUNCTION__ ,
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", __FUNCTION__ ,
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 */
359static 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", __FUNCTION__ );
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 /* FIXME. We have a locking problem on the hashbin here.
386 * We probably need to use hashbin_find_next(), but we first
387 * need to ensure that "line" is unique. - Jean II */
388 self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
389 while (self != NULL) {
390 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
391
392 ircomm_tty_do_event(self, IRCOMM_TTY_DISCOVERY_INDICATION,
393 NULL, &info);
394
395 self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty);
396 }
397}
398
399/*
400 * Function ircomm_tty_disconnect_indication (instance, sap, reason, skb)
401 *
402 * Link disconnected
403 *
404 */
405void ircomm_tty_disconnect_indication(void *instance, void *sap,
406 LM_REASON reason,
407 struct sk_buff *skb)
408{
409 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
410
411 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
412
413 IRDA_ASSERT(self != NULL, return;);
414 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
415
416 if (!self->tty)
417 return;
418
419 /* This will stop control data transfers */
420 self->flow = FLOW_STOP;
421
422 /* Stop data transfers */
423 self->tty->hw_stopped = 1;
424
425 ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL,
426 NULL);
427}
428
429/*
430 * Function ircomm_tty_getvalue_confirm (result, obj_id, value, priv)
431 *
432 * Got result from the IAS query we make
433 *
434 */
435static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,
436 struct ias_value *value,
437 void *priv)
438{
439 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv;
440
441 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
442
443 IRDA_ASSERT(self != NULL, return;);
444 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
445
446 /* We probably don't need to make any more queries */
447 iriap_close(self->iriap);
448 self->iriap = NULL;
449
450 /* Check if request succeeded */
451 if (result != IAS_SUCCESS) {
452 IRDA_DEBUG(4, "%s(), got NULL value!\n", __FUNCTION__ );
453 return;
454 }
455
456 switch (value->type) {
457 case IAS_OCT_SEQ:
458 IRDA_DEBUG(2, "%s(), got octet sequence\n", __FUNCTION__ );
459
460 irda_param_extract_all(self, value->t.oct_seq, value->len,
461 &ircomm_param_info);
462
463 ircomm_tty_do_event(self, IRCOMM_TTY_GOT_PARAMETERS, NULL,
464 NULL);
465 break;
466 case IAS_INTEGER:
467 /* Got LSAP selector */
468 IRDA_DEBUG(2, "%s(), got lsapsel = %d\n", __FUNCTION__ ,
469 value->t.integer);
470
471 if (value->t.integer == -1) {
472 IRDA_DEBUG(0, "%s(), invalid value!\n", __FUNCTION__ );
473 } else
474 self->dlsap_sel = value->t.integer;
475
476 ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL);
477 break;
478 case IAS_MISSING:
479 IRDA_DEBUG(0, "%s(), got IAS_MISSING\n", __FUNCTION__ );
480 break;
481 default:
482 IRDA_DEBUG(0, "%s(), got unknown type!\n", __FUNCTION__ );
483 break;
484 }
485 irias_delete_value(value);
486}
487
488/*
489 * Function ircomm_tty_connect_confirm (instance, sap, qos, max_sdu_size, skb)
490 *
491 * Connection confirmed
492 *
493 */
494void ircomm_tty_connect_confirm(void *instance, void *sap,
495 struct qos_info *qos,
496 __u32 max_data_size,
497 __u8 max_header_size,
498 struct sk_buff *skb)
499{
500 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
501
502 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
503
504 IRDA_ASSERT(self != NULL, return;);
505 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
506
507 self->client = TRUE;
508 self->max_data_size = max_data_size;
509 self->max_header_size = max_header_size;
510 self->flow = FLOW_START;
511
512 ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL);
513
514 /* No need to kfree_skb - see ircomm_ttp_connect_confirm() */
515}
516
517/*
518 * Function ircomm_tty_connect_indication (instance, sap, qos, max_sdu_size,
519 * skb)
520 *
521 * we are discovered and being requested to connect by remote device !
522 *
523 */
524void ircomm_tty_connect_indication(void *instance, void *sap,
525 struct qos_info *qos,
526 __u32 max_data_size,
527 __u8 max_header_size,
528 struct sk_buff *skb)
529{
530 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
531 int clen;
532
533 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
534
535 IRDA_ASSERT(self != NULL, return;);
536 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
537
538 self->client = FALSE;
539 self->max_data_size = max_data_size;
540 self->max_header_size = max_header_size;
541 self->flow = FLOW_START;
542
543 clen = skb->data[0];
544 if (clen)
545 irda_param_extract_all(self, skb->data+1,
546 IRDA_MIN(skb->len, clen),
547 &ircomm_param_info);
548
549 ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL);
550
551 /* No need to kfree_skb - see ircomm_ttp_connect_indication() */
552}
553
554/*
555 * Function ircomm_tty_link_established (self)
556 *
557 * Called when the IrCOMM link is established
558 *
559 */
560void ircomm_tty_link_established(struct ircomm_tty_cb *self)
561{
562 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
563
564 IRDA_ASSERT(self != NULL, return;);
565 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
566
567 if (!self->tty)
568 return;
569
570 del_timer(&self->watchdog_timer);
571
572 /*
573 * IrCOMM link is now up, and if we are not using hardware
574 * flow-control, then declare the hardware as running. Otherwise we
575 * will have to wait for the peer device (DCE) to raise the CTS
576 * line.
577 */
578 if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {
579 IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __FUNCTION__ );
580 return;
581 } else {
582 IRDA_DEBUG(1, "%s(), starting hardware!\n", __FUNCTION__ );
583
584 self->tty->hw_stopped = 0;
585
586 /* Wake up processes blocked on open */
587 wake_up_interruptible(&self->open_wait);
588 }
589
590 schedule_work(&self->tqueue);
591}
592
593/*
594 * Function ircomm_tty_start_watchdog_timer (self, timeout)
595 *
596 * Start the watchdog timer. This timer is used to make sure that any
597 * connection attempt is successful, and if not, we will retry after
598 * the timeout
599 */
600static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self,
601 int timeout)
602{
603 IRDA_ASSERT(self != NULL, return;);
604 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
605
606 irda_start_timer(&self->watchdog_timer, timeout, (void *) self,
607 ircomm_tty_watchdog_timer_expired);
608}
609
610/*
611 * Function ircomm_tty_watchdog_timer_expired (data)
612 *
613 * Called when the connect procedure have taken to much time.
614 *
615 */
616static void ircomm_tty_watchdog_timer_expired(void *data)
617{
618 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data;
619
620 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
621
622 IRDA_ASSERT(self != NULL, return;);
623 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
624
625 ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL);
626}
627
628
629/*
630 * Function ircomm_tty_do_event (self, event, skb)
631 *
632 * Process event
633 *
634 */
635int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
636 struct sk_buff *skb, struct ircomm_tty_info *info)
637{
638 IRDA_ASSERT(self != NULL, return -1;);
639 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
640
641 IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
642 ircomm_tty_state[self->state], ircomm_tty_event[event]);
643
644 return (*state[self->state])(self, event, skb, info);
645}
646
647/*
648 * Function ircomm_tty_next_state (self, state)
649 *
650 * Switch state
651 *
652 */
653static inline void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
654{
655 /*
656 IRDA_ASSERT(self != NULL, return;);
657 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
658
659 IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __FUNCTION__ ,
660 ircomm_tty_state[self->state], self->service_type);
661 */
662 self->state = state;
663}
664
665/*
666 * Function ircomm_tty_state_idle (self, event, skb, info)
667 *
668 * Just hanging around
669 *
670 */
671static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,
672 IRCOMM_TTY_EVENT event,
673 struct sk_buff *skb,
674 struct ircomm_tty_info *info)
675{
676 int ret = 0;
677
678 IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
679 ircomm_tty_state[self->state], ircomm_tty_event[event]);
680 switch (event) {
681 case IRCOMM_TTY_ATTACH_CABLE:
682 /* Try to discover any remote devices */
683 ircomm_tty_start_watchdog_timer(self, 3*HZ);
684 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
685
686 irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
687 break;
688 case IRCOMM_TTY_DISCOVERY_INDICATION:
689 self->daddr = info->daddr;
690 self->saddr = info->saddr;
691
692 if (self->iriap) {
693 IRDA_WARNING("%s(), busy with a previous query\n",
694 __FUNCTION__);
695 return -EBUSY;
696 }
697
698 self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
699 ircomm_tty_getvalue_confirm);
700
701 iriap_getvaluebyclass_request(self->iriap,
702 self->saddr, self->daddr,
703 "IrDA:IrCOMM", "Parameters");
704
705 ircomm_tty_start_watchdog_timer(self, 3*HZ);
706 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
707 break;
708 case IRCOMM_TTY_CONNECT_INDICATION:
709 del_timer(&self->watchdog_timer);
710
711 /* Accept connection */
712 ircomm_connect_response(self->ircomm, NULL);
713 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
714 break;
715 case IRCOMM_TTY_WD_TIMER_EXPIRED:
716 /* Just stay idle */
717 break;
718 case IRCOMM_TTY_DETACH_CABLE:
719 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
720 break;
721 default:
722 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
723 ircomm_tty_event[event]);
724 ret = -EINVAL;
725 }
726 return ret;
727}
728
729/*
730 * Function ircomm_tty_state_search (self, event, skb, info)
731 *
732 * Trying to discover an IrCOMM device
733 *
734 */
735static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
736 IRCOMM_TTY_EVENT event,
737 struct sk_buff *skb,
738 struct ircomm_tty_info *info)
739{
740 int ret = 0;
741
742 IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
743 ircomm_tty_state[self->state], ircomm_tty_event[event]);
744
745 switch (event) {
746 case IRCOMM_TTY_DISCOVERY_INDICATION:
747 self->daddr = info->daddr;
748 self->saddr = info->saddr;
749
750 if (self->iriap) {
751 IRDA_WARNING("%s(), busy with a previous query\n",
752 __FUNCTION__);
753 return -EBUSY;
754 }
755
756 self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
757 ircomm_tty_getvalue_confirm);
758
759 if (self->service_type == IRCOMM_3_WIRE_RAW) {
760 iriap_getvaluebyclass_request(self->iriap, self->saddr,
761 self->daddr, "IrLPT",
762 "IrDA:IrLMP:LsapSel");
763 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
764 } else {
765 iriap_getvaluebyclass_request(self->iriap, self->saddr,
766 self->daddr,
767 "IrDA:IrCOMM",
768 "Parameters");
769
770 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
771 }
772 ircomm_tty_start_watchdog_timer(self, 3*HZ);
773 break;
774 case IRCOMM_TTY_CONNECT_INDICATION:
775 del_timer(&self->watchdog_timer);
776 ircomm_tty_ias_unregister(self);
777
778 /* Accept connection */
779 ircomm_connect_response(self->ircomm, NULL);
780 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
781 break;
782 case IRCOMM_TTY_WD_TIMER_EXPIRED:
783#if 1
784 /* Give up */
785#else
786 /* Try to discover any remote devices */
787 ircomm_tty_start_watchdog_timer(self, 3*HZ);
788 irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
789#endif
790 break;
791 case IRCOMM_TTY_DETACH_CABLE:
792 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
793 break;
794 default:
795 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
796 ircomm_tty_event[event]);
797 ret = -EINVAL;
798 }
799 return ret;
800}
801
802/*
803 * Function ircomm_tty_state_query (self, event, skb, info)
804 *
805 * Querying the remote LM-IAS for IrCOMM parameters
806 *
807 */
808static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,
809 IRCOMM_TTY_EVENT event,
810 struct sk_buff *skb,
811 struct ircomm_tty_info *info)
812{
813 int ret = 0;
814
815 IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
816 ircomm_tty_state[self->state], ircomm_tty_event[event]);
817
818 switch (event) {
819 case IRCOMM_TTY_GOT_PARAMETERS:
820 if (self->iriap) {
821 IRDA_WARNING("%s(), busy with a previous query\n",
822 __FUNCTION__);
823 return -EBUSY;
824 }
825
826 self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
827 ircomm_tty_getvalue_confirm);
828
829 iriap_getvaluebyclass_request(self->iriap, self->saddr,
830 self->daddr, "IrDA:IrCOMM",
831 "IrDA:TinyTP:LsapSel");
832
833 ircomm_tty_start_watchdog_timer(self, 3*HZ);
834 ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
835 break;
836 case IRCOMM_TTY_WD_TIMER_EXPIRED:
837 /* Go back to search mode */
838 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
839 ircomm_tty_start_watchdog_timer(self, 3*HZ);
840 break;
841 case IRCOMM_TTY_CONNECT_INDICATION:
842 del_timer(&self->watchdog_timer);
843 ircomm_tty_ias_unregister(self);
844
845 /* Accept connection */
846 ircomm_connect_response(self->ircomm, NULL);
847 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
848 break;
849 case IRCOMM_TTY_DETACH_CABLE:
850 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
851 break;
852 default:
853 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
854 ircomm_tty_event[event]);
855 ret = -EINVAL;
856 }
857 return ret;
858}
859
860/*
861 * Function ircomm_tty_state_query_lsap_sel (self, event, skb, info)
862 *
863 * Query remote LM-IAS for the LSAP selector which we can connect to
864 *
865 */
866static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,
867 IRCOMM_TTY_EVENT event,
868 struct sk_buff *skb,
869 struct ircomm_tty_info *info)
870{
871 int ret = 0;
872
873 IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
874 ircomm_tty_state[self->state], ircomm_tty_event[event]);
875
876 switch (event) {
877 case IRCOMM_TTY_GOT_LSAPSEL:
878 /* Connect to remote device */
879 ret = ircomm_connect_request(self->ircomm, self->dlsap_sel,
880 self->saddr, self->daddr,
881 NULL, self->service_type);
882 ircomm_tty_start_watchdog_timer(self, 3*HZ);
883 ircomm_tty_next_state(self, IRCOMM_TTY_SETUP);
884 break;
885 case IRCOMM_TTY_WD_TIMER_EXPIRED:
886 /* Go back to search mode */
887 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
888 ircomm_tty_start_watchdog_timer(self, 3*HZ);
889 break;
890 case IRCOMM_TTY_CONNECT_INDICATION:
891 del_timer(&self->watchdog_timer);
892 ircomm_tty_ias_unregister(self);
893
894 /* Accept connection */
895 ircomm_connect_response(self->ircomm, NULL);
896 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
897 break;
898 case IRCOMM_TTY_DETACH_CABLE:
899 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
900 break;
901 default:
902 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
903 ircomm_tty_event[event]);
904 ret = -EINVAL;
905 }
906 return ret;
907}
908
909/*
910 * Function ircomm_tty_state_setup (self, event, skb, info)
911 *
912 * Trying to connect
913 *
914 */
915static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
916 IRCOMM_TTY_EVENT event,
917 struct sk_buff *skb,
918 struct ircomm_tty_info *info)
919{
920 int ret = 0;
921
922 IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
923 ircomm_tty_state[self->state], ircomm_tty_event[event]);
924
925 switch (event) {
926 case IRCOMM_TTY_CONNECT_CONFIRM:
927 del_timer(&self->watchdog_timer);
928 ircomm_tty_ias_unregister(self);
929
930 /*
931 * Send initial parameters. This will also send out queued
932 * parameters waiting for the connection to come up
933 */
934 ircomm_tty_send_initial_parameters(self);
935 ircomm_tty_link_established(self);
936 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
937 break;
938 case IRCOMM_TTY_CONNECT_INDICATION:
939 del_timer(&self->watchdog_timer);
940 ircomm_tty_ias_unregister(self);
941
942 /* Accept connection */
943 ircomm_connect_response(self->ircomm, NULL);
944 ircomm_tty_next_state(self, IRCOMM_TTY_READY);
945 break;
946 case IRCOMM_TTY_WD_TIMER_EXPIRED:
947 /* Go back to search mode */
948 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
949 ircomm_tty_start_watchdog_timer(self, 3*HZ);
950 break;
951 case IRCOMM_TTY_DETACH_CABLE:
952 /* ircomm_disconnect_request(self->ircomm, NULL); */
953 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
954 break;
955 default:
956 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
957 ircomm_tty_event[event]);
958 ret = -EINVAL;
959 }
960 return ret;
961}
962
963/*
964 * Function ircomm_tty_state_ready (self, event, skb, info)
965 *
966 * IrCOMM is now connected
967 *
968 */
969static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
970 IRCOMM_TTY_EVENT event,
971 struct sk_buff *skb,
972 struct ircomm_tty_info *info)
973{
974 int ret = 0;
975
976 switch (event) {
977 case IRCOMM_TTY_DATA_REQUEST:
978 ret = ircomm_data_request(self->ircomm, skb);
979 break;
980 case IRCOMM_TTY_DETACH_CABLE:
981 ircomm_disconnect_request(self->ircomm, NULL);
982 ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
983 break;
984 case IRCOMM_TTY_DISCONNECT_INDICATION:
985 ircomm_tty_ias_register(self);
986 ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
987 ircomm_tty_start_watchdog_timer(self, 3*HZ);
988
989 if (self->flags & ASYNC_CHECK_CD) {
990 /* Drop carrier */
991 self->settings.dce = IRCOMM_DELTA_CD;
992 ircomm_tty_check_modem_status(self);
993 } else {
994 IRDA_DEBUG(0, "%s(), hanging up!\n", __FUNCTION__ );
995 if (self->tty)
996 tty_hangup(self->tty);
997 }
998 break;
999 default:
1000 IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
1001 ircomm_tty_event[event]);
1002 ret = -EINVAL;
1003 }
1004 return ret;
1005}
1006
diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c
new file mode 100644
index 00000000000..197e3e7ed7e
--- /dev/null
+++ b/net/irda/ircomm/ircomm_tty_ioctl.c
@@ -0,0 +1,428 @@
1/*********************************************************************
2 *
3 * Filename: ircomm_tty_ioctl.c
4 * Version:
5 * Description:
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Thu Jun 10 14:39:09 1999
9 * Modified at: Wed Jan 5 14:45:43 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/init.h>
32#include <linux/fs.h>
33#include <linux/sched.h>
34#include <linux/termios.h>
35#include <linux/tty.h>
36#include <linux/serial.h>
37
38#include <asm/uaccess.h>
39
40#include <net/irda/irda.h>
41#include <net/irda/irmod.h>
42
43#include <net/irda/ircomm_core.h>
44#include <net/irda/ircomm_param.h>
45#include <net/irda/ircomm_tty_attach.h>
46#include <net/irda/ircomm_tty.h>
47
48#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
49
50/*
51 * Function ircomm_tty_change_speed (driver)
52 *
53 * Change speed of the driver. If the remote device is a DCE, then this
54 * should make it change the speed of its serial port
55 */
56static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
57{
58 unsigned cflag, cval;
59 int baud;
60
61 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
62
63 if (!self->tty || !self->tty->termios || !self->ircomm)
64 return;
65
66 cflag = self->tty->termios->c_cflag;
67
68 /* byte size and parity */
69 switch (cflag & CSIZE) {
70 case CS5: cval = IRCOMM_WSIZE_5; break;
71 case CS6: cval = IRCOMM_WSIZE_6; break;
72 case CS7: cval = IRCOMM_WSIZE_7; break;
73 case CS8: cval = IRCOMM_WSIZE_8; break;
74 default: cval = IRCOMM_WSIZE_5; break;
75 }
76 if (cflag & CSTOPB)
77 cval |= IRCOMM_2_STOP_BIT;
78
79 if (cflag & PARENB)
80 cval |= IRCOMM_PARITY_ENABLE;
81 if (!(cflag & PARODD))
82 cval |= IRCOMM_PARITY_EVEN;
83
84 /* Determine divisor based on baud rate */
85 baud = tty_get_baud_rate(self->tty);
86 if (!baud)
87 baud = 9600; /* B0 transition handled in rs_set_termios */
88
89 self->settings.data_rate = baud;
90 ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);
91
92 /* CTS flow control flag and modem status interrupts */
93 if (cflag & CRTSCTS) {
94 self->flags |= ASYNC_CTS_FLOW;
95 self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
96 /* This got me. Bummer. Jean II */
97 if (self->service_type == IRCOMM_3_WIRE_RAW)
98 IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __FUNCTION__);
99 } else {
100 self->flags &= ~ASYNC_CTS_FLOW;
101 self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
102 }
103 if (cflag & CLOCAL)
104 self->flags &= ~ASYNC_CHECK_CD;
105 else
106 self->flags |= ASYNC_CHECK_CD;
107#if 0
108 /*
109 * Set up parity check flag
110 */
111
112 if (I_INPCK(self->tty))
113 driver->read_status_mask |= LSR_FE | LSR_PE;
114 if (I_BRKINT(driver->tty) || I_PARMRK(driver->tty))
115 driver->read_status_mask |= LSR_BI;
116
117 /*
118 * Characters to ignore
119 */
120 driver->ignore_status_mask = 0;
121 if (I_IGNPAR(driver->tty))
122 driver->ignore_status_mask |= LSR_PE | LSR_FE;
123
124 if (I_IGNBRK(self->tty)) {
125 self->ignore_status_mask |= LSR_BI;
126 /*
127 * If we're ignore parity and break indicators, ignore
128 * overruns too. (For real raw support).
129 */
130 if (I_IGNPAR(self->tty))
131 self->ignore_status_mask |= LSR_OE;
132 }
133#endif
134 self->settings.data_format = cval;
135
136 ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
137 ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE);
138}
139
140/*
141 * Function ircomm_tty_set_termios (tty, old_termios)
142 *
143 * This routine allows the tty driver to be notified when device's
144 * termios settings have changed. Note that a well-designed tty driver
145 * should be prepared to accept the case where old == NULL, and try to
146 * do something rational.
147 */
148void ircomm_tty_set_termios(struct tty_struct *tty,
149 struct termios *old_termios)
150{
151 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
152 unsigned int cflag = tty->termios->c_cflag;
153
154 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
155
156 if ((cflag == old_termios->c_cflag) &&
157 (RELEVANT_IFLAG(tty->termios->c_iflag) ==
158 RELEVANT_IFLAG(old_termios->c_iflag)))
159 {
160 return;
161 }
162
163 ircomm_tty_change_speed(self);
164
165 /* Handle transition to B0 status */
166 if ((old_termios->c_cflag & CBAUD) &&
167 !(cflag & CBAUD)) {
168 self->settings.dte &= ~(IRCOMM_DTR|IRCOMM_RTS);
169 ircomm_param_request(self, IRCOMM_DTE, TRUE);
170 }
171
172 /* Handle transition away from B0 status */
173 if (!(old_termios->c_cflag & CBAUD) &&
174 (cflag & CBAUD)) {
175 self->settings.dte |= IRCOMM_DTR;
176 if (!(tty->termios->c_cflag & CRTSCTS) ||
177 !test_bit(TTY_THROTTLED, &tty->flags)) {
178 self->settings.dte |= IRCOMM_RTS;
179 }
180 ircomm_param_request(self, IRCOMM_DTE, TRUE);
181 }
182
183 /* Handle turning off CRTSCTS */
184 if ((old_termios->c_cflag & CRTSCTS) &&
185 !(tty->termios->c_cflag & CRTSCTS))
186 {
187 tty->hw_stopped = 0;
188 ircomm_tty_start(tty);
189 }
190}
191
192/*
193 * Function ircomm_tty_tiocmget (tty, file)
194 *
195 *
196 *
197 */
198int ircomm_tty_tiocmget(struct tty_struct *tty, struct file *file)
199{
200 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
201 unsigned int result;
202
203 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
204
205 if (tty->flags & (1 << TTY_IO_ERROR))
206 return -EIO;
207
208 result = ((self->settings.dte & IRCOMM_RTS) ? TIOCM_RTS : 0)
209 | ((self->settings.dte & IRCOMM_DTR) ? TIOCM_DTR : 0)
210 | ((self->settings.dce & IRCOMM_CD) ? TIOCM_CAR : 0)
211 | ((self->settings.dce & IRCOMM_RI) ? TIOCM_RNG : 0)
212 | ((self->settings.dce & IRCOMM_DSR) ? TIOCM_DSR : 0)
213 | ((self->settings.dce & IRCOMM_CTS) ? TIOCM_CTS : 0);
214 return result;
215}
216
217/*
218 * Function ircomm_tty_tiocmset (tty, file, set, clear)
219 *
220 *
221 *
222 */
223int ircomm_tty_tiocmset(struct tty_struct *tty, struct file *file,
224 unsigned int set, unsigned int clear)
225{
226 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
227
228 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
229
230 if (tty->flags & (1 << TTY_IO_ERROR))
231 return -EIO;
232
233 IRDA_ASSERT(self != NULL, return -1;);
234 IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
235
236 if (set & TIOCM_RTS)
237 self->settings.dte |= IRCOMM_RTS;
238 if (set & TIOCM_DTR)
239 self->settings.dte |= IRCOMM_DTR;
240
241 if (clear & TIOCM_RTS)
242 self->settings.dte &= ~IRCOMM_RTS;
243 if (clear & TIOCM_DTR)
244 self->settings.dte &= ~IRCOMM_DTR;
245
246 if ((set|clear) & TIOCM_RTS)
247 self->settings.dte |= IRCOMM_DELTA_RTS;
248 if ((set|clear) & TIOCM_DTR)
249 self->settings.dte |= IRCOMM_DELTA_DTR;
250
251 ircomm_param_request(self, IRCOMM_DTE, TRUE);
252
253 return 0;
254}
255
256/*
257 * Function get_serial_info (driver, retinfo)
258 *
259 *
260 *
261 */
262static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
263 struct serial_struct __user *retinfo)
264{
265 struct serial_struct info;
266
267 if (!retinfo)
268 return -EFAULT;
269
270 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
271
272 memset(&info, 0, sizeof(info));
273 info.line = self->line;
274 info.flags = self->flags;
275 info.baud_base = self->settings.data_rate;
276 info.close_delay = self->close_delay;
277 info.closing_wait = self->closing_wait;
278
279 /* For compatibility */
280 info.type = PORT_16550A;
281 info.port = 0;
282 info.irq = 0;
283 info.xmit_fifo_size = 0;
284 info.hub6 = 0;
285 info.custom_divisor = 0;
286
287 if (copy_to_user(retinfo, &info, sizeof(*retinfo)))
288 return -EFAULT;
289
290 return 0;
291}
292
293/*
294 * Function set_serial_info (driver, new_info)
295 *
296 *
297 *
298 */
299static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self,
300 struct serial_struct __user *new_info)
301{
302#if 0
303 struct serial_struct new_serial;
304 struct ircomm_tty_cb old_state, *state;
305
306 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
307
308 if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
309 return -EFAULT;
310
311
312 state = self
313 old_state = *self;
314
315 if (!capable(CAP_SYS_ADMIN)) {
316 if ((new_serial.baud_base != state->settings.data_rate) ||
317 (new_serial.close_delay != state->close_delay) ||
318 ((new_serial.flags & ~ASYNC_USR_MASK) !=
319 (self->flags & ~ASYNC_USR_MASK)))
320 return -EPERM;
321 state->flags = ((state->flags & ~ASYNC_USR_MASK) |
322 (new_serial.flags & ASYNC_USR_MASK));
323 self->flags = ((self->flags & ~ASYNC_USR_MASK) |
324 (new_serial.flags & ASYNC_USR_MASK));
325 /* self->custom_divisor = new_serial.custom_divisor; */
326 goto check_and_exit;
327 }
328
329 /*
330 * OK, past this point, all the error checking has been done.
331 * At this point, we start making changes.....
332 */
333
334 if (self->settings.data_rate != new_serial.baud_base) {
335 self->settings.data_rate = new_serial.baud_base;
336 ircomm_param_request(self, IRCOMM_DATA_RATE, TRUE);
337 }
338
339 self->close_delay = new_serial.close_delay * HZ/100;
340 self->closing_wait = new_serial.closing_wait * HZ/100;
341 /* self->custom_divisor = new_serial.custom_divisor; */
342
343 self->flags = ((self->flags & ~ASYNC_FLAGS) |
344 (new_serial.flags & ASYNC_FLAGS));
345 self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
346
347 check_and_exit:
348
349 if (self->flags & ASYNC_INITIALIZED) {
350 if (((old_state.flags & ASYNC_SPD_MASK) !=
351 (self->flags & ASYNC_SPD_MASK)) ||
352 (old_driver.custom_divisor != driver->custom_divisor)) {
353 if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
354 driver->tty->alt_speed = 57600;
355 if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
356 driver->tty->alt_speed = 115200;
357 if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
358 driver->tty->alt_speed = 230400;
359 if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
360 driver->tty->alt_speed = 460800;
361 ircomm_tty_change_speed(driver);
362 }
363 }
364#endif
365 return 0;
366}
367
368/*
369 * Function ircomm_tty_ioctl (tty, file, cmd, arg)
370 *
371 *
372 *
373 */
374int ircomm_tty_ioctl(struct tty_struct *tty, struct file *file,
375 unsigned int cmd, unsigned long arg)
376{
377 struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
378 int ret = 0;
379
380 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
381
382 if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
383 (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
384 (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
385 if (tty->flags & (1 << TTY_IO_ERROR))
386 return -EIO;
387 }
388
389 switch (cmd) {
390 case TIOCGSERIAL:
391 ret = ircomm_tty_get_serial_info(self, (struct serial_struct __user *) arg);
392 break;
393 case TIOCSSERIAL:
394 ret = ircomm_tty_set_serial_info(self, (struct serial_struct __user *) arg);
395 break;
396 case TIOCMIWAIT:
397 IRDA_DEBUG(0, "(), TIOCMIWAIT, not impl!\n");
398 break;
399
400 case TIOCGICOUNT:
401 IRDA_DEBUG(0, "%s(), TIOCGICOUNT not impl!\n", __FUNCTION__ );
402#if 0
403 save_flags(flags); cli();
404 cnow = driver->icount;
405 restore_flags(flags);
406 p_cuser = (struct serial_icounter_struct __user *) arg;
407 if (put_user(cnow.cts, &p_cuser->cts) ||
408 put_user(cnow.dsr, &p_cuser->dsr) ||
409 put_user(cnow.rng, &p_cuser->rng) ||
410 put_user(cnow.dcd, &p_cuser->dcd) ||
411 put_user(cnow.rx, &p_cuser->rx) ||
412 put_user(cnow.tx, &p_cuser->tx) ||
413 put_user(cnow.frame, &p_cuser->frame) ||
414 put_user(cnow.overrun, &p_cuser->overrun) ||
415 put_user(cnow.parity, &p_cuser->parity) ||
416 put_user(cnow.brk, &p_cuser->brk) ||
417 put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
418 return -EFAULT;
419#endif
420 return 0;
421 default:
422 ret = -ENOIOCTLCMD; /* ioctls which we must ignore */
423 }
424 return ret;
425}
426
427
428