1 /*
2 * acm.c Version 0.18
3 *
4 * Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de>
5 * Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
6 * Copyright (c) 1999 Johannes Erdfelt <jerdfelt@valinux.com>
7 * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
8 *
9 * USB Abstract Control Model driver for USB modems and ISDN adapters
10 *
11 * Sponsored by SuSE
12 *
13 * ChangeLog:
14 * v0.9 - thorough cleaning, URBification, almost a rewrite
15 * v0.10 - some more cleanups
16 * v0.11 - fixed flow control, read error doesn't stop reads
17 * v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced
18 * v0.13 - added termios, added hangup
19 * v0.14 - sized down struct acm
20 * v0.15 - fixed flow control again - characters could be lost
21 * v0.16 - added code for modems with swapped data and control interfaces
22 * v0.17 - added new style probing
23 * v0.18 - fixed new style probing for devices with more configurations
24 */
25
26 /*
27 * This program is free software; you can redistribute it and/or modify
28 * it under the terms of the GNU General Public License as published by
29 * the Free Software Foundation; either version 2 of the License, or
30 * (at your option) any later version.
31 *
32 * This program is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
36 *
37 * You should have received a copy of the GNU General Public License
38 * along with this program; if not, write to the Free Software
39 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
40 */
41
42 #include <linux/kernel.h>
43 #include <linux/sched.h>
44 #include <linux/signal.h>
45 #include <linux/errno.h>
46 #include <linux/poll.h>
47 #include <linux/init.h>
48 #include <linux/malloc.h>
49 #include <linux/fcntl.h>
50 #include <linux/tty_driver.h>
51 #include <linux/tty_flip.h>
52 #include <linux/tty.h>
53 #include <linux/module.h>
54 #undef DEBUG
55 #include <linux/usb.h>
56
57 /*
58 * CMSPAR, some architectures can't have space and mark parity.
59 */
60
61 #ifndef CMSPAR
62 #define CMSPAR 0
63 #endif
64
65 /*
66 * Major and minor numbers.
67 */
68
69 #define ACM_TTY_MAJOR 166
70 #define ACM_TTY_MINORS 32
71
72 /*
73 * Requests.
74 */
75
76 #define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
77
78 #define ACM_REQ_COMMAND 0x00
79 #define ACM_REQ_RESPONSE 0x01
80 #define ACM_REQ_SET_FEATURE 0x02
81 #define ACM_REQ_GET_FEATURE 0x03
82 #define ACM_REQ_CLEAR_FEATURE 0x04
83
84 #define ACM_REQ_SET_LINE 0x20
85 #define ACM_REQ_GET_LINE 0x21
86 #define ACM_REQ_SET_CONTROL 0x22
87 #define ACM_REQ_SEND_BREAK 0x23
88
89 /*
90 * IRQs.
91 */
92
93 #define ACM_IRQ_NETWORK 0x00
94 #define ACM_IRQ_LINE_STATE 0x20
95
96 /*
97 * Output control lines.
98 */
99
100 #define ACM_CTRL_DTR 0x01
101 #define ACM_CTRL_RTS 0x02
102
103 /*
104 * Input control lines and line errors.
105 */
106
107 #define ACM_CTRL_DCD 0x01
108 #define ACM_CTRL_DSR 0x02
109 #define ACM_CTRL_BRK 0x04
110 #define ACM_CTRL_RI 0x08
111
112 #define ACM_CTRL_FRAMING 0x10
113 #define ACM_CTRL_PARITY 0x20
114 #define ACM_CTRL_OVERRUN 0x40
115
116 /*
117 * Line speed and caracter encoding.
118 */
119
120 struct acm_line {
121 __u32 speed;
122 __u8 stopbits;
123 __u8 parity;
124 __u8 databits;
125 } __attribute__ ((packed));
126
127 /*
128 * Internal driver structures.
129 */
130
131 struct acm {
132 struct usb_device *dev; /* the coresponding usb device */
133 struct usb_interface *iface; /* the interfaces - +0 control +1 data */
134 struct tty_struct *tty; /* the coresponding tty */
135 struct urb ctrlurb, readurb, writeurb; /* urbs */
136 struct acm_line line; /* line coding (bits, stop, parity) */
137 struct tq_struct tqueue; /* task queue for line discipline waking up */
138 unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
139 unsigned int ctrlout; /* output control lines (DTR, RTS) */
140 unsigned int writesize; /* max packet size for the output bulk endpoint */
141 unsigned int used; /* someone has this acm's device open */
142 unsigned int minor; /* acm minor number */
143 unsigned char throttle; /* throttled by tty layer */
144 unsigned char clocal; /* termios CLOCAL */
145 };
146
147 static struct usb_driver acm_driver;
148 static struct tty_driver acm_tty_driver;
149 static struct acm *acm_table[ACM_TTY_MINORS];
150
151 #define ACM_READY(acm) (acm && acm->dev && acm->used)
152
153 /*
154 * Functions for ACM control messages.
155 */
156
157 static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
158 {
159 int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
160 request, USB_RT_ACM, value, acm->iface[0].altsetting[0].bInterfaceNumber, buf, len, HZ * 5);
161 dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
162 return retval < 0 ? retval : 0;
163 }
164
165 #define acm_set_control(acm, control) acm_ctrl_msg(acm, ACM_REQ_SET_CONTROL, control, NULL, 0)
166 #define acm_set_line(acm, line) acm_ctrl_msg(acm, ACM_REQ_SET_LINE, 0, line, sizeof(struct acm_line))
167 #define acm_send_break(acm, ms) acm_ctrl_msg(acm, ACM_REQ_SEND_BREAK, ms, NULL, 0)
168
169 /*
170 * Interrupt handler for various ACM control events
171 */
172
173 static void acm_ctrl_irq(struct urb *urb)
174 {
175 struct acm *acm = urb->context;
176 devrequest *dr = urb->transfer_buffer;
177 unsigned char *data = (unsigned char *)(dr + 1);
178 int newctrl;
179
180 if (!ACM_READY(acm)) return;
181
182 if (urb->status < 0) {
183 dbg("nonzero ctrl irq status received: %d", urb->status);
184 return;
185 }
186
187 switch (dr->request) {
188
189 case ACM_IRQ_NETWORK:
190
191 dbg("%s network", data[0] ? "connected to" : "disconnected from");
192 return;
193
194 case ACM_IRQ_LINE_STATE:
195
196 newctrl = le16_to_cpup((__u16 *) data);
197
198 #if 0
199 /* Please someone tell me how to do this properly to kill pppd and not kill minicom */
200 if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
201 dbg("calling hangup");
202 tty_hangup(acm->tty);
203 }
204 #endif
205
206 acm->ctrlin = newctrl;
207
208 dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
209 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
210 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
211 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
212 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
213
214 return;
215
216 default:
217 dbg("unknown control event received: request %d index %d len %d data0 %d data1 %d",
218 dr->request, dr->index, dr->length, data[0], data[1]);
219 return;
220 }
221 }
222
223 static void acm_read_bulk(struct urb *urb)
224 {
225 struct acm *acm = urb->context;
226 struct tty_struct *tty = acm->tty;
227 unsigned char *data = urb->transfer_buffer;
228 int i = 0;
229
230 if (!ACM_READY(acm)) return;
231
232 if (urb->status)
233 dbg("nonzero read bulk status received: %d", urb->status);
234
235 if (!urb->status & !acm->throttle) {
236 for (i = 0; i < urb->actual_length && !acm->throttle; i++)
237 tty_insert_flip_char(tty, data[i], 0);
238 tty_flip_buffer_push(tty);
239 }
240
241 if (acm->throttle) {
242 memmove(data, data + i, urb->actual_length - i);
243 urb->actual_length -= i;
244 return;
245 }
246
247 urb->actual_length = 0;
248 urb->dev = acm->dev;
249
250 if (usb_submit_urb(urb))
251 dbg("failed resubmitting read urb");
252 }
253
254 static void acm_write_bulk(struct urb *urb)
255 {
256 struct acm *acm = (struct acm *)urb->context;
257
258 if (!ACM_READY(acm)) return;
259
260 if (urb->status)
261 dbg("nonzero write bulk status received: %d", urb->status);
262
263 queue_task(&acm->tqueue, &tq_immediate);
264 mark_bh(IMMEDIATE_BH);
265 }
266
267 static void acm_softint(void *private)
268 {
269 struct acm *acm = private;
270 struct tty_struct *tty = acm->tty;
271
272 if (!ACM_READY(acm)) return;
273
274 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
275 (tty->ldisc.write_wakeup)(tty);
276
277 wake_up_interruptible(&tty->write_wait);
278 }
279
280 /*
281 * TTY handlers
282 */
283
284 static int acm_tty_open(struct tty_struct *tty, struct file *filp)
285 {
286 struct acm *acm = acm_table[MINOR(tty->device)];
287
288 if (!acm || !acm->dev) return -EINVAL;
289
290 tty->driver_data = acm;
291 acm->tty = tty;
292
293 MOD_INC_USE_COUNT;
294
295 if (acm->used++) return 0;
296
297 acm->ctrlurb.dev = acm->dev;
298 if (usb_submit_urb(&acm->ctrlurb))
299 dbg("usb_submit_urb(ctrl irq) failed");
300
301 acm->readurb.dev = acm->dev;
302 if (usb_submit_urb(&acm->readurb))
303 dbg("usb_submit_urb(read bulk) failed");
304
305 acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
306
307 return 0;
308 }
309
310 static void acm_tty_close(struct tty_struct *tty, struct file *filp)
311 {
312 struct acm *acm = tty->driver_data;
313
314 if (!acm || !acm->used) return;
315
316 if (!--acm->used) {
317 if (acm->dev) {
318 acm_set_control(acm, acm->ctrlout = 0);
319 usb_unlink_urb(&acm->ctrlurb);
320 usb_unlink_urb(&acm->writeurb);
321 usb_unlink_urb(&acm->readurb);
322 } else {
323 tty_unregister_devfs(&acm_tty_driver, acm->minor);
324 acm_table[acm->minor] = NULL;
325 kfree(acm);
326 }
327 }
328 MOD_DEC_USE_COUNT;
329 }
330
331 static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
332 {
333 struct acm *acm = tty->driver_data;
334
335 if (!ACM_READY(acm)) return -EINVAL;
336 if (acm->writeurb.status == -EINPROGRESS) return 0;
337 if (!count) return 0;
338
339 count = (count > acm->writesize) ? acm->writesize : count;
340
341 if (from_user)
342 copy_from_user(acm->writeurb.transfer_buffer, buf, count);
343 else
344 memcpy(acm->writeurb.transfer_buffer, buf, count);
345
346 acm->writeurb.transfer_buffer_length = count;
347 acm->writeurb.dev = acm->dev;
348
349 if (usb_submit_urb(&acm->writeurb))
350 dbg("usb_submit_urb(write bulk) failed");
351
352 return count;
353 }
354
355 static int acm_tty_write_room(struct tty_struct *tty)
356 {
357 struct acm *acm = tty->driver_data;
358 if (!ACM_READY(acm)) return -EINVAL;
359 return acm->writeurb.status == -EINPROGRESS ? 0 : acm->writesize;
360 }
361
362 static int acm_tty_chars_in_buffer(struct tty_struct *tty)
363 {
364 struct acm *acm = tty->driver_data;
365 if (!ACM_READY(acm)) return -EINVAL;
366 return acm->writeurb.status == -EINPROGRESS ? acm->writeurb.transfer_buffer_length : 0;
367 }
368
369 static void acm_tty_throttle(struct tty_struct *tty)
370 {
371 struct acm *acm = tty->driver_data;
372 if (!ACM_READY(acm)) return;
373 acm->throttle = 1;
374 }
375
376 static void acm_tty_unthrottle(struct tty_struct *tty)
377 {
378 struct acm *acm = tty->driver_data;
379 if (!ACM_READY(acm)) return;
380 acm->throttle = 0;
381 if (acm->readurb.status != -EINPROGRESS)
382 acm_read_bulk(&acm->readurb);
383 }
384
385 static void acm_tty_break_ctl(struct tty_struct *tty, int state)
386 {
387 struct acm *acm = tty->driver_data;
388 if (!ACM_READY(acm)) return;
389 if (acm_send_break(acm, state ? 0xffff : 0))
390 dbg("send break failed");
391 }
392
393 static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
394 {
395 struct acm *acm = tty->driver_data;
396 unsigned int retval, mask, newctrl;
397
398 if (!ACM_READY(acm)) return -EINVAL;
399
400 switch (cmd) {
401
402 case TIOCMGET:
403
404 return put_user((acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
405 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
406 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
407 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
408 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
409 TIOCM_CTS, (unsigned long *) arg);
410
411 case TIOCMSET:
412 case TIOCMBIS:
413 case TIOCMBIC:
414
415 if ((retval = get_user(mask, (unsigned long *) arg))) return retval;
416
417 newctrl = acm->ctrlout;
418 mask = (mask & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (mask & TIOCM_RTS ? ACM_CTRL_RTS : 0);
419
420 switch (cmd) {
421 case TIOCMSET: newctrl = mask; break;
422 case TIOCMBIS: newctrl |= mask; break;
423 case TIOCMBIC: newctrl &= ~mask; break;
424 }
425
426 if (acm->ctrlout == newctrl) return 0;
427 return acm_set_control(acm, acm->ctrlout = newctrl);
428 }
429
430 return -ENOIOCTLCMD;
431 }
432
433 static __u32 acm_tty_speed[] = {
434 0, 50, 75, 110, 134, 150, 200, 300, 600,
435 1200, 1800, 2400, 4800, 9600, 19200, 38400,
436 57600, 115200, 230400, 460800, 500000, 576000,
437 921600, 1000000, 1152000, 1500000, 2000000,
438 2500000, 3000000, 3500000, 4000000
439 };
440
441 static __u8 acm_tty_size[] = {
442 5, 6, 7, 8
443 };
444
445 static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
446 {
447 struct acm *acm = tty->driver_data;
448 struct termios *termios = tty->termios;
449 struct acm_line newline;
450 int newctrl = acm->ctrlout;
451
452 if (!ACM_READY(acm)) return;
453
454 newline.speed = cpu_to_le32p(acm_tty_speed +
455 (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
456 newline.stopbits = termios->c_cflag & CSTOPB ? 2 : 0;
457 newline.parity = termios->c_cflag & PARENB ?
458 (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
459 newline.databits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
460
461 acm->clocal = termios->c_cflag & CLOCAL;
462
463 if (!newline.speed) {
464 newline.speed = acm->line.speed;
465 newctrl &= ~ACM_CTRL_DTR;
466 } else newctrl |= ACM_CTRL_DTR;
467
468 if (newctrl != acm->ctrlout)
469 acm_set_control(acm, acm->ctrlout = newctrl);
470
471 if (memcmp(&acm->line, &newline, sizeof(struct acm_line))) {
472 memcpy(&acm->line, &newline, sizeof(struct acm_line));
473 dbg("set line: %d %d %d %d", newline.speed, newline.stopbits, newline.parity, newline.databits);
474 acm_set_line(acm, &acm->line);
475 }
476 }
477
478 /*
479 * USB probe and disconnect routines.
480 */
481
482 static void *acm_probe(struct usb_device *dev, unsigned int ifnum,
483 const struct usb_device_id *id)
484 {
485 struct acm *acm;
486 struct usb_config_descriptor *cfacm;
487 struct usb_interface_descriptor *ifcom, *ifdata;
488 struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
489 int readsize, ctrlsize, minor, i;
490 unsigned char *buf;
491
492 for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
493
494 cfacm = dev->config + i;
495
496 dbg("probing config %d", cfacm->bConfigurationValue);
497
498 if (cfacm->bNumInterfaces != 2 ||
499 usb_interface_claimed(cfacm->interface + 0) ||
500 usb_interface_claimed(cfacm->interface + 1))
501 continue;
502
503 ifcom = cfacm->interface[0].altsetting + 0;
504 ifdata = cfacm->interface[1].altsetting + 0;
505
506 if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2) {
507 ifcom = cfacm->interface[1].altsetting + 0;
508 ifdata = cfacm->interface[0].altsetting + 0;
509 if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2)
510 continue;
511 }
512
513 if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
514 ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints < 1)
515 continue;
516
517 epctrl = ifcom->endpoint + 0;
518 epread = ifdata->endpoint + 0;
519 epwrite = ifdata->endpoint + 1;
520
521 if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
522 (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
523 ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
524 continue;
525
526 if ((epread->bEndpointAddress & 0x80) != 0x80) {
527 epread = ifdata->endpoint + 1;
528 epwrite = ifdata->endpoint + 0;
529 }
530
531 usb_set_configuration(dev, cfacm->bConfigurationValue);
532
533 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
534 if (acm_table[minor]) {
535 err("no more free acm devices");
536 return NULL;
537 }
538
539 if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
540 err("out of memory");
541 return NULL;
542 }
543 memset(acm, 0, sizeof(struct acm));
544
545 ctrlsize = epctrl->wMaxPacketSize;
546 readsize = epread->wMaxPacketSize;
547 acm->writesize = epwrite->wMaxPacketSize;
548 acm->iface = cfacm->interface;
549 acm->minor = minor;
550 acm->dev = dev;
551
552 acm->tqueue.routine = acm_softint;
553 acm->tqueue.data = acm;
554
555 if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
556 err("out of memory");
557 kfree(acm);
558 return NULL;
559 }
560
561 FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
562 buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
563
564 FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
565 buf += ctrlsize, readsize, acm_read_bulk, acm);
566 acm->readurb.transfer_flags |= USB_NO_FSBR;
567
568 FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
569 buf += readsize, acm->writesize, acm_write_bulk, acm);
570 acm->writeurb.transfer_flags |= USB_NO_FSBR;
571
572 printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
573
574 acm_set_control(acm, acm->ctrlout);
575
576 acm->line.speed = cpu_to_le32(9600);
577 acm->line.databits = 8;
578 acm_set_line(acm, &acm->line);
579
580 usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
581 usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
582
583 tty_register_devfs(&acm_tty_driver, 0, minor);
584 return acm_table[minor] = acm;
585 }
586
587 return NULL;
588 }
589
590 static void acm_disconnect(struct usb_device *dev, void *ptr)
591 {
592 struct acm *acm = ptr;
593
594 if (!acm || !acm->dev) {
595 dbg("disconnect on nonexisting interface");
596 return;
597 }
598
599 acm->dev = NULL;
600
601 usb_unlink_urb(&acm->ctrlurb);
602 usb_unlink_urb(&acm->readurb);
603 usb_unlink_urb(&acm->writeurb);
604
605 kfree(acm->ctrlurb.transfer_buffer);
606
607 usb_driver_release_interface(&acm_driver, acm->iface + 0);
608 usb_driver_release_interface(&acm_driver, acm->iface + 1);
609
610 if (!acm->used) {
611 tty_unregister_devfs(&acm_tty_driver, acm->minor);
612 acm_table[acm->minor] = NULL;
613 kfree(acm);
614 return;
615 }
616
617 if (acm->tty)
618 tty_hangup(acm->tty);
619 }
620
621 /*
622 * USB driver structure.
623 */
624
625 static struct usb_device_id acm_ids[] = {
626 { USB_DEVICE_INFO(2, 0, 0) },
627 { }
628 };
629
630 MODULE_DEVICE_TABLE (usb, acm_ids);
631
632 static struct usb_driver acm_driver = {
633 name: "acm",
634 probe: acm_probe,
635 disconnect: acm_disconnect,
636 id_table: acm_ids,
637 };
638
639 /*
640 * TTY driver structures.
641 */
642
643 static int acm_tty_refcount;
644
645 static struct tty_struct *acm_tty_table[ACM_TTY_MINORS];
646 static struct termios *acm_tty_termios[ACM_TTY_MINORS];
647 static struct termios *acm_tty_termios_locked[ACM_TTY_MINORS];
648
649 static struct tty_driver acm_tty_driver = {
650 magic: TTY_DRIVER_MAGIC,
651 driver_name: "acm",
652 name: "usb/acm/%d",
653 major: ACM_TTY_MAJOR,
654 minor_start: 0,
655 num: ACM_TTY_MINORS,
656 type: TTY_DRIVER_TYPE_SERIAL,
657 subtype: SERIAL_TYPE_NORMAL,
658 flags: TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
659
660 refcount: &acm_tty_refcount,
661
662 table: acm_tty_table,
663 termios: acm_tty_termios,
664 termios_locked: acm_tty_termios_locked,
665
666 open: acm_tty_open,
667 close: acm_tty_close,
668 write: acm_tty_write,
669 write_room: acm_tty_write_room,
670 ioctl: acm_tty_ioctl,
671 throttle: acm_tty_throttle,
672 unthrottle: acm_tty_unthrottle,
673 chars_in_buffer: acm_tty_chars_in_buffer,
674 break_ctl: acm_tty_break_ctl,
675 set_termios: acm_tty_set_termios
676 };
677
678 /*
679 * Init / exit.
680 */
681
682 static int __init acm_init(void)
683 {
684 acm_tty_driver.init_termios = tty_std_termios;
685 acm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
686
687 if (tty_register_driver(&acm_tty_driver))
688 return -1;
689
690 if (usb_register(&acm_driver) < 0) {
691 tty_unregister_driver(&acm_tty_driver);
692 return -1;
693 }
694
695 return 0;
696 }
697
698 static void __exit acm_exit(void)
699 {
700 usb_deregister(&acm_driver);
701 tty_unregister_driver(&acm_tty_driver);
702 }
703
704 module_init(acm_init);
705 module_exit(acm_exit);
706
707 MODULE_AUTHOR("Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik");
708 MODULE_DESCRIPTION("USB Abstract Control Model driver for USB modems and ISDN adapters");
709
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.