~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/usb/acm.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.