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