Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / drivers / usb / acm.c
blob88112996668c83c0cc6de39c0ee593300d6a88f1
1 /*
2 * acm.c Version 0.18
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>
9 * USB Abstract Control Model driver for USB modems and ISDN adapters
11 * Sponsored by SuSE
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
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.
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.
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
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>
58 * CMSPAR, some architectures can't have space and mark parity.
61 #ifndef CMSPAR
62 #define CMSPAR 0
63 #endif
66 * Major and minor numbers.
69 #define ACM_TTY_MAJOR 166
70 #define ACM_TTY_MINORS 32
73 * Requests.
76 #define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
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
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
90 * IRQs.
93 #define ACM_IRQ_NETWORK 0x00
94 #define ACM_IRQ_LINE_STATE 0x20
97 * Output control lines.
100 #define ACM_CTRL_DTR 0x01
101 #define ACM_CTRL_RTS 0x02
104 * Input control lines and line errors.
107 #define ACM_CTRL_DCD 0x01
108 #define ACM_CTRL_DSR 0x02
109 #define ACM_CTRL_BRK 0x04
110 #define ACM_CTRL_RI 0x08
112 #define ACM_CTRL_FRAMING 0x10
113 #define ACM_CTRL_PARITY 0x20
114 #define ACM_CTRL_OVERRUN 0x40
117 * Line speed and caracter encoding.
120 struct acm_line {
121 __u32 speed;
122 __u8 stopbits;
123 __u8 parity;
124 __u8 databits;
125 } __attribute__ ((packed));
128 * Internal driver structures.
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 */
147 static struct usb_driver acm_driver;
148 static struct tty_driver acm_tty_driver;
149 static struct acm *acm_table[ACM_TTY_MINORS];
151 #define ACM_READY(acm) (acm && acm->dev && acm->used)
154 * Functions for ACM control messages.
157 static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
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;
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)
170 * Interrupt handler for various ACM control events
173 static void acm_ctrl_irq(struct urb *urb)
175 struct acm *acm = urb->context;
176 devrequest *dr = urb->transfer_buffer;
177 unsigned char *data = (unsigned char *)(dr + 1);
178 int newctrl;
180 if (!ACM_READY(acm)) return;
182 if (urb->status < 0) {
183 dbg("nonzero ctrl irq status received: %d", urb->status);
184 return;
187 switch (dr->request) {
189 case ACM_IRQ_NETWORK:
191 dbg("%s network", data[0] ? "connected to" : "disconnected from");
192 return;
194 case ACM_IRQ_LINE_STATE:
196 newctrl = le16_to_cpup((__u16 *) data);
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);
204 #endif
206 acm->ctrlin = newctrl;
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 ? '+' : '-');
214 return;
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;
223 static void acm_read_bulk(struct urb *urb)
225 struct acm *acm = urb->context;
226 struct tty_struct *tty = acm->tty;
227 unsigned char *data = urb->transfer_buffer;
228 int i = 0;
230 if (!ACM_READY(acm)) return;
232 if (urb->status)
233 dbg("nonzero read bulk status received: %d", urb->status);
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);
241 if (acm->throttle) {
242 memmove(data, data + i, urb->actual_length - i);
243 urb->actual_length -= i;
244 return;
247 urb->actual_length = 0;
248 urb->dev = acm->dev;
250 if (usb_submit_urb(urb))
251 dbg("failed resubmitting read urb");
254 static void acm_write_bulk(struct urb *urb)
256 struct acm *acm = (struct acm *)urb->context;
258 if (!ACM_READY(acm)) return;
260 if (urb->status)
261 dbg("nonzero write bulk status received: %d", urb->status);
263 queue_task(&acm->tqueue, &tq_immediate);
264 mark_bh(IMMEDIATE_BH);
267 static void acm_softint(void *private)
269 struct acm *acm = private;
270 struct tty_struct *tty = acm->tty;
272 if (!ACM_READY(acm)) return;
274 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
275 (tty->ldisc.write_wakeup)(tty);
277 wake_up_interruptible(&tty->write_wait);
281 * TTY handlers
284 static int acm_tty_open(struct tty_struct *tty, struct file *filp)
286 struct acm *acm = acm_table[MINOR(tty->device)];
288 if (!acm || !acm->dev) return -EINVAL;
290 tty->driver_data = acm;
291 acm->tty = tty;
293 MOD_INC_USE_COUNT;
295 if (acm->used++) return 0;
297 acm->ctrlurb.dev = acm->dev;
298 if (usb_submit_urb(&acm->ctrlurb))
299 dbg("usb_submit_urb(ctrl irq) failed");
301 acm->readurb.dev = acm->dev;
302 if (usb_submit_urb(&acm->readurb))
303 dbg("usb_submit_urb(read bulk) failed");
305 acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
307 return 0;
310 static void acm_tty_close(struct tty_struct *tty, struct file *filp)
312 struct acm *acm = tty->driver_data;
314 if (!acm || !acm->used) return;
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);
328 MOD_DEC_USE_COUNT;
331 static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
333 struct acm *acm = tty->driver_data;
335 if (!ACM_READY(acm)) return -EINVAL;
336 if (acm->writeurb.status == -EINPROGRESS) return 0;
337 if (!count) return 0;
339 count = (count > acm->writesize) ? acm->writesize : count;
341 if (from_user)
342 copy_from_user(acm->writeurb.transfer_buffer, buf, count);
343 else
344 memcpy(acm->writeurb.transfer_buffer, buf, count);
346 acm->writeurb.transfer_buffer_length = count;
347 acm->writeurb.dev = acm->dev;
349 if (usb_submit_urb(&acm->writeurb))
350 dbg("usb_submit_urb(write bulk) failed");
352 return count;
355 static int acm_tty_write_room(struct tty_struct *tty)
357 struct acm *acm = tty->driver_data;
358 if (!ACM_READY(acm)) return -EINVAL;
359 return acm->writeurb.status == -EINPROGRESS ? 0 : acm->writesize;
362 static int acm_tty_chars_in_buffer(struct tty_struct *tty)
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;
369 static void acm_tty_throttle(struct tty_struct *tty)
371 struct acm *acm = tty->driver_data;
372 if (!ACM_READY(acm)) return;
373 acm->throttle = 1;
376 static void acm_tty_unthrottle(struct tty_struct *tty)
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);
385 static void acm_tty_break_ctl(struct tty_struct *tty, int state)
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");
393 static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
395 struct acm *acm = tty->driver_data;
396 unsigned int retval, mask, newctrl;
398 if (!ACM_READY(acm)) return -EINVAL;
400 switch (cmd) {
402 case TIOCMGET:
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);
411 case TIOCMSET:
412 case TIOCMBIS:
413 case TIOCMBIC:
415 if ((retval = get_user(mask, (unsigned long *) arg))) return retval;
417 newctrl = acm->ctrlout;
418 mask = (mask & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (mask & TIOCM_RTS ? ACM_CTRL_RTS : 0);
420 switch (cmd) {
421 case TIOCMSET: newctrl = mask; break;
422 case TIOCMBIS: newctrl |= mask; break;
423 case TIOCMBIC: newctrl &= ~mask; break;
426 if (acm->ctrlout == newctrl) return 0;
427 return acm_set_control(acm, acm->ctrlout = newctrl);
430 return -ENOIOCTLCMD;
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
441 static __u8 acm_tty_size[] = {
442 5, 6, 7, 8
445 static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
447 struct acm *acm = tty->driver_data;
448 struct termios *termios = tty->termios;
449 struct acm_line newline;
450 int newctrl = acm->ctrlout;
452 if (!ACM_READY(acm)) return;
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];
461 acm->clocal = termios->c_cflag & CLOCAL;
463 if (!newline.speed) {
464 newline.speed = acm->line.speed;
465 newctrl &= ~ACM_CTRL_DTR;
466 } else newctrl |= ACM_CTRL_DTR;
468 if (newctrl != acm->ctrlout)
469 acm_set_control(acm, acm->ctrlout = newctrl);
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);
479 * USB probe and disconnect routines.
482 static void *acm_probe(struct usb_device *dev, unsigned int ifnum,
483 const struct usb_device_id *id)
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;
493 * Since 0 is treated as a wildcard by the USB pattern matching,
494 * we explicitly check bDeviceSubClass and bDeviceProtocol here.
497 if (dev->descriptor.bDeviceSubClass != 0 ||
498 dev->descriptor.bDeviceProtocol != 0)
499 return NULL;
501 for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
503 cfacm = dev->config + i;
505 dbg("probing config %d", cfacm->bConfigurationValue);
507 if (cfacm->bNumInterfaces != 2 ||
508 usb_interface_claimed(cfacm->interface + 0) ||
509 usb_interface_claimed(cfacm->interface + 1))
510 continue;
512 ifcom = cfacm->interface[0].altsetting + 0;
513 ifdata = cfacm->interface[1].altsetting + 0;
515 if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2) {
516 ifcom = cfacm->interface[1].altsetting + 0;
517 ifdata = cfacm->interface[0].altsetting + 0;
518 if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2)
519 continue;
522 if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
523 ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints < 1)
524 continue;
526 epctrl = ifcom->endpoint + 0;
527 epread = ifdata->endpoint + 0;
528 epwrite = ifdata->endpoint + 1;
530 if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
531 (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
532 ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
533 continue;
535 if ((epread->bEndpointAddress & 0x80) != 0x80) {
536 epread = ifdata->endpoint + 1;
537 epwrite = ifdata->endpoint + 0;
540 usb_set_configuration(dev, cfacm->bConfigurationValue);
542 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
543 if (acm_table[minor]) {
544 err("no more free acm devices");
545 return NULL;
548 if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
549 err("out of memory");
550 return NULL;
552 memset(acm, 0, sizeof(struct acm));
554 ctrlsize = epctrl->wMaxPacketSize;
555 readsize = epread->wMaxPacketSize;
556 acm->writesize = epwrite->wMaxPacketSize;
557 acm->iface = cfacm->interface;
558 acm->minor = minor;
559 acm->dev = dev;
561 acm->tqueue.routine = acm_softint;
562 acm->tqueue.data = acm;
564 if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
565 err("out of memory");
566 kfree(acm);
567 return NULL;
570 FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
571 buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
573 FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
574 buf += ctrlsize, readsize, acm_read_bulk, acm);
575 acm->readurb.transfer_flags |= USB_NO_FSBR;
577 FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
578 buf += readsize, acm->writesize, acm_write_bulk, acm);
579 acm->writeurb.transfer_flags |= USB_NO_FSBR;
581 printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
583 acm_set_control(acm, acm->ctrlout);
585 acm->line.speed = cpu_to_le32(9600);
586 acm->line.databits = 8;
587 acm_set_line(acm, &acm->line);
589 usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
590 usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
592 tty_register_devfs(&acm_tty_driver, 0, minor);
593 return acm_table[minor] = acm;
596 return NULL;
599 static void acm_disconnect(struct usb_device *dev, void *ptr)
601 struct acm *acm = ptr;
603 if (!acm || !acm->dev) {
604 dbg("disconnect on nonexisting interface");
605 return;
608 acm->dev = NULL;
610 usb_unlink_urb(&acm->ctrlurb);
611 usb_unlink_urb(&acm->readurb);
612 usb_unlink_urb(&acm->writeurb);
614 kfree(acm->ctrlurb.transfer_buffer);
616 usb_driver_release_interface(&acm_driver, acm->iface + 0);
617 usb_driver_release_interface(&acm_driver, acm->iface + 1);
619 if (!acm->used) {
620 tty_unregister_devfs(&acm_tty_driver, acm->minor);
621 acm_table[acm->minor] = NULL;
622 kfree(acm);
623 return;
626 if (acm->tty)
627 tty_hangup(acm->tty);
631 * USB driver structure.
634 static struct usb_device_id acm_ids[] = {
635 { bDeviceClass: 2, bDeviceSubClass: 0, bDeviceProtocol: 0},
639 MODULE_DEVICE_TABLE (usb, acm_ids);
641 static struct usb_driver acm_driver = {
642 name: "acm",
643 probe: acm_probe,
644 disconnect: acm_disconnect,
645 id_table: acm_ids,
649 * TTY driver structures.
652 static int acm_tty_refcount;
654 static struct tty_struct *acm_tty_table[ACM_TTY_MINORS];
655 static struct termios *acm_tty_termios[ACM_TTY_MINORS];
656 static struct termios *acm_tty_termios_locked[ACM_TTY_MINORS];
658 static struct tty_driver acm_tty_driver = {
659 magic: TTY_DRIVER_MAGIC,
660 driver_name: "acm",
661 name: "usb/acm/%d",
662 major: ACM_TTY_MAJOR,
663 minor_start: 0,
664 num: ACM_TTY_MINORS,
665 type: TTY_DRIVER_TYPE_SERIAL,
666 subtype: SERIAL_TYPE_NORMAL,
667 flags: TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
669 refcount: &acm_tty_refcount,
671 table: acm_tty_table,
672 termios: acm_tty_termios,
673 termios_locked: acm_tty_termios_locked,
675 open: acm_tty_open,
676 close: acm_tty_close,
677 write: acm_tty_write,
678 write_room: acm_tty_write_room,
679 ioctl: acm_tty_ioctl,
680 throttle: acm_tty_throttle,
681 unthrottle: acm_tty_unthrottle,
682 chars_in_buffer: acm_tty_chars_in_buffer,
683 break_ctl: acm_tty_break_ctl,
684 set_termios: acm_tty_set_termios
688 * Init / exit.
691 static int __init acm_init(void)
693 acm_tty_driver.init_termios = tty_std_termios;
694 acm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
696 if (tty_register_driver(&acm_tty_driver))
697 return -1;
699 if (usb_register(&acm_driver) < 0) {
700 tty_unregister_driver(&acm_tty_driver);
701 return -1;
704 return 0;
707 static void __exit acm_exit(void)
709 usb_deregister(&acm_driver);
710 tty_unregister_driver(&acm_tty_driver);
713 module_init(acm_init);
714 module_exit(acm_exit);
716 MODULE_AUTHOR("Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik");
717 MODULE_DESCRIPTION("USB Abstract Control Model driver for USB modems and ISDN adapters");