blob: 97bdeb1c2181650428841826f1c185f53ee81be0 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * cdc-acm.c
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 * Copyright (c) 2004 Oliver Neukum <oliver@neukum.name>
David Kubicek61a87ad2005-11-01 18:51:34 +01009 * Copyright (c) 2005 David Kubicek <dave@awk.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * USB Abstract Control Model driver for USB modems and ISDN adapters
12 *
13 * Sponsored by SuSE
14 *
15 * ChangeLog:
16 * v0.9 - thorough cleaning, URBification, almost a rewrite
17 * v0.10 - some more cleanups
18 * v0.11 - fixed flow control, read error doesn't stop reads
19 * v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced
20 * v0.13 - added termios, added hangup
21 * v0.14 - sized down struct acm
22 * v0.15 - fixed flow control again - characters could be lost
23 * v0.16 - added code for modems with swapped data and control interfaces
24 * v0.17 - added new style probing
25 * v0.18 - fixed new style probing for devices with more configurations
26 * v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan)
27 * v0.20 - switched to probing on interface (rather than device) class
28 * v0.21 - revert to probing on device for devices with multiple configs
29 * v0.22 - probe only the control interface. if usbcore doesn't choose the
30 * config we want, sysadmin changes bConfigurationValue in sysfs.
31 * v0.23 - use softirq for rx processing, as needed by tty layer
32 * v0.24 - change probe method to evaluate CDC union descriptor
David Kubicek61a87ad2005-11-01 18:51:34 +010033 * v0.25 - downstream tasks paralelized to maximize throughput
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 */
35
36/*
37 * This program is free software; you can redistribute it and/or modify
38 * it under the terms of the GNU General Public License as published by
39 * the Free Software Foundation; either version 2 of the License, or
40 * (at your option) any later version.
41 *
42 * This program is distributed in the hope that it will be useful,
43 * but WITHOUT ANY WARRANTY; without even the implied warranty of
44 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45 * GNU General Public License for more details.
46 *
47 * You should have received a copy of the GNU General Public License
48 * along with this program; if not, write to the Free Software
49 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
50 */
51
52#undef DEBUG
53
54#include <linux/kernel.h>
55#include <linux/errno.h>
56#include <linux/init.h>
57#include <linux/slab.h>
58#include <linux/tty.h>
59#include <linux/tty_driver.h>
60#include <linux/tty_flip.h>
61#include <linux/module.h>
62#include <linux/smp_lock.h>
63#include <asm/uaccess.h>
64#include <linux/usb.h>
65#include <linux/usb_cdc.h>
66#include <asm/byteorder.h>
67#include <asm/unaligned.h>
David Kubicek61a87ad2005-11-01 18:51:34 +010068#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70#include "cdc-acm.h"
71
72/*
73 * Version Information
74 */
David Kubicek61a87ad2005-11-01 18:51:34 +010075#define DRIVER_VERSION "v0.25"
76#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
Linus Torvalds1da177e2005-04-16 15:20:36 -070077#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
78
79static struct usb_driver acm_driver;
80static struct tty_driver *acm_tty_driver;
81static struct acm *acm_table[ACM_TTY_MINORS];
82
83static DECLARE_MUTEX(open_sem);
84
85#define ACM_READY(acm) (acm && acm->dev && acm->used)
86
87/*
88 * Functions for ACM control messages.
89 */
90
91static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
92{
93 int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
94 request, USB_RT_ACM, value,
95 acm->control->altsetting[0].desc.bInterfaceNumber,
96 buf, len, 5000);
97 dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
98 return retval < 0 ? retval : 0;
99}
100
101/* devices aren't required to support these requests.
102 * the cdc acm descriptor tells whether they do...
103 */
104#define acm_set_control(acm, control) \
105 acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
106#define acm_set_line(acm, line) \
107 acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
108#define acm_send_break(acm, ms) \
109 acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
110
111/*
Oliver Neukum884b6002005-04-21 21:28:02 +0200112 * Write buffer management.
113 * All of these assume proper locks taken by the caller.
114 */
115
116static int acm_wb_alloc(struct acm *acm)
117{
118 int i, wbn;
119 struct acm_wb *wb;
120
121 wbn = acm->write_current;
122 i = 0;
123 for (;;) {
124 wb = &acm->wb[wbn];
125 if (!wb->use) {
126 wb->use = 1;
127 return wbn;
128 }
129 wbn = (wbn + 1) % ACM_NWB;
130 if (++i >= ACM_NWB)
131 return -1;
132 }
133}
134
135static void acm_wb_free(struct acm *acm, int wbn)
136{
137 acm->wb[wbn].use = 0;
138}
139
140static int acm_wb_is_avail(struct acm *acm)
141{
142 int i, n;
143
144 n = 0;
145 for (i = 0; i < ACM_NWB; i++) {
146 if (!acm->wb[i].use)
147 n++;
148 }
149 return n;
150}
151
152static inline int acm_wb_is_used(struct acm *acm, int wbn)
153{
154 return acm->wb[wbn].use;
155}
156
157/*
158 * Finish write.
159 */
160static void acm_write_done(struct acm *acm)
161{
162 unsigned long flags;
163 int wbn;
164
165 spin_lock_irqsave(&acm->write_lock, flags);
166 acm->write_ready = 1;
167 wbn = acm->write_current;
168 acm_wb_free(acm, wbn);
169 acm->write_current = (wbn + 1) % ACM_NWB;
170 spin_unlock_irqrestore(&acm->write_lock, flags);
171}
172
173/*
174 * Poke write.
175 */
176static int acm_write_start(struct acm *acm)
177{
178 unsigned long flags;
179 int wbn;
180 struct acm_wb *wb;
181 int rc;
182
183 spin_lock_irqsave(&acm->write_lock, flags);
184 if (!acm->dev) {
185 spin_unlock_irqrestore(&acm->write_lock, flags);
186 return -ENODEV;
187 }
188
189 if (!acm->write_ready) {
190 spin_unlock_irqrestore(&acm->write_lock, flags);
191 return 0; /* A white lie */
192 }
193
194 wbn = acm->write_current;
195 if (!acm_wb_is_used(acm, wbn)) {
196 spin_unlock_irqrestore(&acm->write_lock, flags);
197 return 0;
198 }
199 wb = &acm->wb[wbn];
200
201 acm->write_ready = 0;
202 spin_unlock_irqrestore(&acm->write_lock, flags);
203
204 acm->writeurb->transfer_buffer = wb->buf;
205 acm->writeurb->transfer_dma = wb->dmah;
206 acm->writeurb->transfer_buffer_length = wb->len;
207 acm->writeurb->dev = acm->dev;
208
209 if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) {
210 dbg("usb_submit_urb(write bulk) failed: %d", rc);
211 acm_write_done(acm);
212 }
213 return rc;
214}
215
216/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 * Interrupt handlers for various ACM device responses
218 */
219
220/* control interface reports status changes with "interrupt" transfers */
221static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs)
222{
223 struct acm *acm = urb->context;
224 struct usb_cdc_notification *dr = urb->transfer_buffer;
225 unsigned char *data;
226 int newctrl;
227 int status;
228
229 switch (urb->status) {
230 case 0:
231 /* success */
232 break;
233 case -ECONNRESET:
234 case -ENOENT:
235 case -ESHUTDOWN:
236 /* this urb is terminated, clean up */
237 dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
238 return;
239 default:
240 dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
241 goto exit;
242 }
243
244 if (!ACM_READY(acm))
245 goto exit;
246
247 data = (unsigned char *)(dr + 1);
248 switch (dr->bNotificationType) {
249
250 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
251
252 dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
253 break;
254
255 case USB_CDC_NOTIFY_SERIAL_STATE:
256
257 newctrl = le16_to_cpu(get_unaligned((__le16 *) data));
258
259 if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
260 dbg("calling hangup");
261 tty_hangup(acm->tty);
262 }
263
264 acm->ctrlin = newctrl;
265
266 dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
267 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
268 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
269 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
270 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
271
272 break;
273
274 default:
275 dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
276 dr->bNotificationType, dr->wIndex,
277 dr->wLength, data[0], data[1]);
278 break;
279 }
280exit:
281 status = usb_submit_urb (urb, GFP_ATOMIC);
282 if (status)
283 err ("%s - usb_submit_urb failed with result %d",
284 __FUNCTION__, status);
285}
286
287/* data interface returns incoming bytes, or we got unthrottled */
288static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
289{
David Kubicek61a87ad2005-11-01 18:51:34 +0100290 struct acm_rb *buf;
291 struct acm_ru *rcv = urb->context;
292 struct acm *acm = rcv->instance;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 dbg("Entering acm_read_bulk with status %d\n", urb->status);
294
295 if (!ACM_READY(acm))
296 return;
297
298 if (urb->status)
299 dev_dbg(&acm->data->dev, "bulk rx status %d\n", urb->status);
300
David Kubicek61a87ad2005-11-01 18:51:34 +0100301 buf = rcv->buffer;
302 buf->size = urb->actual_length;
303
304 spin_lock(&acm->read_lock);
305 list_add_tail(&rcv->list, &acm->spare_read_urbs);
306 list_add_tail(&buf->list, &acm->filled_read_bufs);
307 spin_unlock(&acm->read_lock);
308
309 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310}
311
312static void acm_rx_tasklet(unsigned long _acm)
313{
314 struct acm *acm = (void *)_acm;
David Kubicek61a87ad2005-11-01 18:51:34 +0100315 struct acm_rb *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 struct tty_struct *tty = acm->tty;
David Kubicek61a87ad2005-11-01 18:51:34 +0100317 struct acm_ru *rcv;
318 //unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 int i = 0;
320 dbg("Entering acm_rx_tasklet");
321
David Kubicek61a87ad2005-11-01 18:51:34 +0100322 if (!ACM_READY(acm) || acm->throttle)
323 return;
324
325next_buffer:
326 spin_lock(&acm->read_lock);
327 if (list_empty(&acm->filled_read_bufs)) {
328 spin_unlock(&acm->read_lock);
329 goto urbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100331 buf = list_entry(acm->filled_read_bufs.next,
332 struct acm_rb, list);
333 list_del(&buf->list);
334 spin_unlock(&acm->read_lock);
335
336 dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d\n", buf, buf->size);
337
Alan Cox33f0f882006-01-09 20:54:13 -0800338 tty_buffer_request_room(tty, buf->size);
339 if (!acm->throttle)
340 tty_insert_flip_string(tty, buf->base, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100341 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 spin_lock(&acm->throttle_lock);
344 if (acm->throttle) {
345 dbg("Throtteling noticed");
David Kubicek61a87ad2005-11-01 18:51:34 +0100346 memmove(buf->base, buf->base + i, buf->size - i);
347 buf->size -= i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 spin_unlock(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100349 spin_lock(&acm->read_lock);
350 list_add(&buf->list, &acm->filled_read_bufs);
351 spin_unlock(&acm->read_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 return;
353 }
354 spin_unlock(&acm->throttle_lock);
355
David Kubicek61a87ad2005-11-01 18:51:34 +0100356 spin_lock(&acm->read_lock);
357 list_add(&buf->list, &acm->spare_read_bufs);
358 spin_unlock(&acm->read_lock);
359 goto next_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
David Kubicek61a87ad2005-11-01 18:51:34 +0100361urbs:
362 while (!list_empty(&acm->spare_read_bufs)) {
363 spin_lock(&acm->read_lock);
364 if (list_empty(&acm->spare_read_urbs)) {
365 spin_unlock(&acm->read_lock);
366 return;
367 }
368 rcv = list_entry(acm->spare_read_urbs.next,
369 struct acm_ru, list);
370 list_del(&rcv->list);
371 spin_unlock(&acm->read_lock);
372
373 buf = list_entry(acm->spare_read_bufs.next,
374 struct acm_rb, list);
375 list_del(&buf->list);
376
377 rcv->buffer = buf;
378
379 usb_fill_bulk_urb(rcv->urb, acm->dev,
380 acm->rx_endpoint,
381 buf->base,
382 acm->readsize,
383 acm_read_bulk, rcv);
384 rcv->urb->transfer_dma = buf->dma;
385 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
386
387 dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p\n", rcv->urb, rcv, buf);
388
389 /* This shouldn't kill the driver as unsuccessful URBs are returned to the
390 free-urbs-pool and resubmited ASAP */
391 if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
392 list_add(&buf->list, &acm->spare_read_bufs);
393 spin_lock(&acm->read_lock);
394 list_add(&rcv->list, &acm->spare_read_urbs);
395 spin_unlock(&acm->read_lock);
396 return;
397 }
398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399}
400
401/* data interface wrote those outgoing bytes */
402static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
403{
404 struct acm *acm = (struct acm *)urb->context;
Oliver Neukum884b6002005-04-21 21:28:02 +0200405
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 dbg("Entering acm_write_bulk with status %d\n", urb->status);
407
Oliver Neukum884b6002005-04-21 21:28:02 +0200408 acm_write_done(acm);
409 acm_write_start(acm);
410 if (ACM_READY(acm))
411 schedule_work(&acm->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412}
413
414static void acm_softint(void *private)
415{
416 struct acm *acm = private;
417 dbg("Entering acm_softint.\n");
418
419 if (!ACM_READY(acm))
420 return;
421 tty_wakeup(acm->tty);
422}
423
424/*
425 * TTY handlers
426 */
427
428static int acm_tty_open(struct tty_struct *tty, struct file *filp)
429{
430 struct acm *acm;
431 int rv = -EINVAL;
David Kubicek61a87ad2005-11-01 18:51:34 +0100432 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 dbg("Entering acm_tty_open.\n");
434
435 down(&open_sem);
436
437 acm = acm_table[tty->index];
438 if (!acm || !acm->dev)
439 goto err_out;
440 else
441 rv = 0;
442
443 tty->driver_data = acm;
444 acm->tty = tty;
445
David Kubicek61a87ad2005-11-01 18:51:34 +0100446 /* force low_latency on so that our tty_push actually forces the data through,
447 otherwise it is scheduled, and with high data rates data can get lost. */
448 tty->low_latency = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
450 if (acm->used++) {
451 goto done;
452 }
453
454 acm->ctrlurb->dev = acm->dev;
455 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
456 dbg("usb_submit_urb(ctrl irq) failed");
457 goto bail_out;
458 }
459
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS))
461 goto full_bailout;
462
David Kubicek61a87ad2005-11-01 18:51:34 +0100463 INIT_LIST_HEAD(&acm->spare_read_urbs);
464 INIT_LIST_HEAD(&acm->spare_read_bufs);
465 INIT_LIST_HEAD(&acm->filled_read_bufs);
466 for (i = 0; i < ACM_NRU; i++) {
467 list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
468 }
469 for (i = 0; i < ACM_NRB; i++) {
470 list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
471 }
472
473 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
475done:
476err_out:
477 up(&open_sem);
478 return rv;
479
480full_bailout:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 usb_kill_urb(acm->ctrlurb);
482bail_out:
483 acm->used--;
484 up(&open_sem);
485 return -EIO;
486}
487
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700488static void acm_tty_unregister(struct acm *acm)
489{
David Kubicek61a87ad2005-11-01 18:51:34 +0100490 int i;
491
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700492 tty_unregister_device(acm_tty_driver, acm->minor);
493 usb_put_intf(acm->control);
494 acm_table[acm->minor] = NULL;
495 usb_free_urb(acm->ctrlurb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700496 usb_free_urb(acm->writeurb);
David Kubicek61a87ad2005-11-01 18:51:34 +0100497 for (i = 0; i < ACM_NRU; i++)
498 usb_free_urb(acm->ru[i].urb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700499 kfree(acm);
500}
501
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502static void acm_tty_close(struct tty_struct *tty, struct file *filp)
503{
504 struct acm *acm = tty->driver_data;
David Kubicek61a87ad2005-11-01 18:51:34 +0100505 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507 if (!acm || !acm->used)
508 return;
509
510 down(&open_sem);
511 if (!--acm->used) {
512 if (acm->dev) {
513 acm_set_control(acm, acm->ctrlout = 0);
514 usb_kill_urb(acm->ctrlurb);
515 usb_kill_urb(acm->writeurb);
David Kubicek61a87ad2005-11-01 18:51:34 +0100516 for (i = 0; i < ACM_NRU; i++)
517 usb_kill_urb(acm->ru[i].urb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700518 } else
519 acm_tty_unregister(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 }
521 up(&open_sem);
522}
523
524static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
525{
526 struct acm *acm = tty->driver_data;
527 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200528 unsigned long flags;
529 int wbn;
530 struct acm_wb *wb;
531
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 dbg("Entering acm_tty_write to write %d bytes,\n", count);
533
534 if (!ACM_READY(acm))
535 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 if (!count)
537 return 0;
538
Oliver Neukum884b6002005-04-21 21:28:02 +0200539 spin_lock_irqsave(&acm->write_lock, flags);
540 if ((wbn = acm_wb_alloc(acm)) < 0) {
541 spin_unlock_irqrestore(&acm->write_lock, flags);
542 acm_write_start(acm);
543 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200545 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Oliver Neukum884b6002005-04-21 21:28:02 +0200547 count = (count > acm->writesize) ? acm->writesize : count;
548 dbg("Get %d bytes...", count);
549 memcpy(wb->buf, buf, count);
550 wb->len = count;
551 spin_unlock_irqrestore(&acm->write_lock, flags);
552
553 if ((stat = acm_write_start(acm)) < 0)
554 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 return count;
556}
557
558static int acm_tty_write_room(struct tty_struct *tty)
559{
560 struct acm *acm = tty->driver_data;
561 if (!ACM_READY(acm))
562 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200563 /*
564 * Do not let the line discipline to know that we have a reserve,
565 * or it might get too enthusiastic.
566 */
567 return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568}
569
570static int acm_tty_chars_in_buffer(struct tty_struct *tty)
571{
572 struct acm *acm = tty->driver_data;
573 if (!ACM_READY(acm))
574 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200575 /*
576 * This is inaccurate (overcounts), but it works.
577 */
578 return (ACM_NWB - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579}
580
581static void acm_tty_throttle(struct tty_struct *tty)
582{
583 struct acm *acm = tty->driver_data;
584 if (!ACM_READY(acm))
585 return;
586 spin_lock_bh(&acm->throttle_lock);
587 acm->throttle = 1;
588 spin_unlock_bh(&acm->throttle_lock);
589}
590
591static void acm_tty_unthrottle(struct tty_struct *tty)
592{
593 struct acm *acm = tty->driver_data;
594 if (!ACM_READY(acm))
595 return;
596 spin_lock_bh(&acm->throttle_lock);
597 acm->throttle = 0;
598 spin_unlock_bh(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100599 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600}
601
602static void acm_tty_break_ctl(struct tty_struct *tty, int state)
603{
604 struct acm *acm = tty->driver_data;
605 if (!ACM_READY(acm))
606 return;
607 if (acm_send_break(acm, state ? 0xffff : 0))
608 dbg("send break failed");
609}
610
611static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file)
612{
613 struct acm *acm = tty->driver_data;
614
615 if (!ACM_READY(acm))
616 return -EINVAL;
617
618 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
619 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
620 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
621 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
622 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
623 TIOCM_CTS;
624}
625
626static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
627 unsigned int set, unsigned int clear)
628{
629 struct acm *acm = tty->driver_data;
630 unsigned int newctrl;
631
632 if (!ACM_READY(acm))
633 return -EINVAL;
634
635 newctrl = acm->ctrlout;
636 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
637 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
638
639 newctrl = (newctrl & ~clear) | set;
640
641 if (acm->ctrlout == newctrl)
642 return 0;
643 return acm_set_control(acm, acm->ctrlout = newctrl);
644}
645
646static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
647{
648 struct acm *acm = tty->driver_data;
649
650 if (!ACM_READY(acm))
651 return -EINVAL;
652
653 return -ENOIOCTLCMD;
654}
655
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100656static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 0, 50, 75, 110, 134, 150, 200, 300, 600,
658 1200, 1800, 2400, 4800, 9600, 19200, 38400,
659 57600, 115200, 230400, 460800, 500000, 576000,
660 921600, 1000000, 1152000, 1500000, 2000000,
661 2500000, 3000000, 3500000, 4000000
662};
663
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100664static const __u8 acm_tty_size[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 5, 6, 7, 8
666};
667
668static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
669{
670 struct acm *acm = tty->driver_data;
671 struct termios *termios = tty->termios;
672 struct usb_cdc_line_coding newline;
673 int newctrl = acm->ctrlout;
674
675 if (!ACM_READY(acm))
676 return;
677
678 newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
679 (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
680 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
681 newline.bParityType = termios->c_cflag & PARENB ?
682 (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
683 newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
684
685 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
686
687 if (!newline.dwDTERate) {
688 newline.dwDTERate = acm->line.dwDTERate;
689 newctrl &= ~ACM_CTRL_DTR;
690 } else newctrl |= ACM_CTRL_DTR;
691
692 if (newctrl != acm->ctrlout)
693 acm_set_control(acm, acm->ctrlout = newctrl);
694
695 if (memcmp(&acm->line, &newline, sizeof newline)) {
696 memcpy(&acm->line, &newline, sizeof newline);
697 dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
698 newline.bCharFormat, newline.bParityType,
699 newline.bDataBits);
700 acm_set_line(acm, &acm->line);
701 }
702}
703
704/*
705 * USB probe and disconnect routines.
706 */
707
Oliver Neukum884b6002005-04-21 21:28:02 +0200708/* Little helper: write buffers free */
709static void acm_write_buffers_free(struct acm *acm)
710{
711 int i;
712 struct acm_wb *wb;
713
714 for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
715 usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
716 }
717}
718
719/* Little helper: write buffers allocate */
720static int acm_write_buffers_alloc(struct acm *acm)
721{
722 int i;
723 struct acm_wb *wb;
724
725 for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
726 wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
727 &wb->dmah);
728 if (!wb->buf) {
729 while (i != 0) {
730 --i;
731 --wb;
732 usb_buffer_free(acm->dev, acm->writesize,
733 wb->buf, wb->dmah);
734 }
735 return -ENOMEM;
736 }
737 }
738 return 0;
739}
740
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741static int acm_probe (struct usb_interface *intf,
742 const struct usb_device_id *id)
743{
744 struct usb_cdc_union_desc *union_header = NULL;
745 char *buffer = intf->altsetting->extra;
746 int buflen = intf->altsetting->extralen;
747 struct usb_interface *control_interface;
748 struct usb_interface *data_interface;
749 struct usb_endpoint_descriptor *epctrl;
750 struct usb_endpoint_descriptor *epread;
751 struct usb_endpoint_descriptor *epwrite;
752 struct usb_device *usb_dev = interface_to_usbdev(intf);
753 struct acm *acm;
754 int minor;
755 int ctrlsize,readsize;
756 u8 *buf;
757 u8 ac_management_function = 0;
758 u8 call_management_function = 0;
759 int call_interface_num = -1;
760 int data_interface_num;
761 unsigned long quirks;
David Kubicek61a87ad2005-11-01 18:51:34 +0100762 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
764 /* handle quirks deadly to normal probing*/
765 quirks = (unsigned long)id->driver_info;
766 if (quirks == NO_UNION_NORMAL) {
767 data_interface = usb_ifnum_to_if(usb_dev, 1);
768 control_interface = usb_ifnum_to_if(usb_dev, 0);
769 goto skip_normal_probe;
770 }
771
772 /* normal probing*/
773 if (!buffer) {
774 err("Wierd descriptor references\n");
775 return -EINVAL;
776 }
777
778 if (!buflen) {
779 if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
780 dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n");
781 buflen = intf->cur_altsetting->endpoint->extralen;
782 buffer = intf->cur_altsetting->endpoint->extra;
783 } else {
784 err("Zero length descriptor references\n");
785 return -EINVAL;
786 }
787 }
788
789 while (buflen > 0) {
790 if (buffer [1] != USB_DT_CS_INTERFACE) {
791 err("skipping garbage\n");
792 goto next_desc;
793 }
794
795 switch (buffer [2]) {
796 case USB_CDC_UNION_TYPE: /* we've found it */
797 if (union_header) {
798 err("More than one union descriptor, skipping ...");
799 goto next_desc;
800 }
801 union_header = (struct usb_cdc_union_desc *)
802 buffer;
803 break;
804 case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */
805 break; /* for now we ignore it */
806 case USB_CDC_HEADER_TYPE: /* maybe check version */
807 break; /* for now we ignore it */
808 case USB_CDC_ACM_TYPE:
809 ac_management_function = buffer[3];
810 break;
811 case USB_CDC_CALL_MANAGEMENT_TYPE:
812 call_management_function = buffer[3];
813 call_interface_num = buffer[4];
814 if ((call_management_function & 3) != 3)
815 err("This device cannot do calls on its own. It is no modem.");
816 break;
817
818 default:
819 err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]);
820 break;
821 }
822next_desc:
823 buflen -= buffer[0];
824 buffer += buffer[0];
825 }
826
827 if (!union_header) {
828 if (call_interface_num > 0) {
829 dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n");
830 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
831 control_interface = intf;
832 } else {
833 dev_dbg(&intf->dev,"No union descriptor, giving up\n");
834 return -ENODEV;
835 }
836 } else {
837 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
838 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
839 if (!control_interface || !data_interface) {
840 dev_dbg(&intf->dev,"no interfaces\n");
841 return -ENODEV;
842 }
843 }
844
845 if (data_interface_num != call_interface_num)
846 dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n");
847
848skip_normal_probe:
849
850 /*workaround for switched interfaces */
851 if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
852 if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
853 struct usb_interface *t;
854 dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
855
856 t = control_interface;
857 control_interface = data_interface;
858 data_interface = t;
859 } else {
860 return -EINVAL;
861 }
862 }
863
864 if (usb_interface_claimed(data_interface)) { /* valid in this context */
865 dev_dbg(&intf->dev,"The data interface isn't available\n");
866 return -EBUSY;
867 }
868
869
870 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
871 return -EINVAL;
872
873 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
874 epread = &data_interface->cur_altsetting->endpoint[0].desc;
875 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
876
877
878 /* workaround for switched endpoints */
879 if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) {
880 /* descriptors are swapped */
881 struct usb_endpoint_descriptor *t;
882 dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
883
884 t = epread;
885 epread = epwrite;
886 epwrite = t;
887 }
888 dbg("interfaces are valid");
889 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
890
891 if (minor == ACM_TTY_MINORS) {
892 err("no more free acm devices");
893 return -ENODEV;
894 }
895
Oliver Neukum46f116e2005-10-24 22:42:35 +0200896 if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
897 dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 goto alloc_fail;
899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
901 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
David Kubicek61a87ad2005-11-01 18:51:34 +0100902 readsize = le16_to_cpu(epread->wMaxPacketSize)*2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize);
904 acm->control = control_interface;
905 acm->data = data_interface;
906 acm->minor = minor;
907 acm->dev = usb_dev;
908 acm->ctrl_caps = ac_management_function;
909 acm->ctrlsize = ctrlsize;
910 acm->readsize = readsize;
David Kubicek61a87ad2005-11-01 18:51:34 +0100911 acm->urb_task.func = acm_rx_tasklet;
912 acm->urb_task.data = (unsigned long) acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 INIT_WORK(&acm->work, acm_softint, acm);
914 spin_lock_init(&acm->throttle_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +0200915 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100916 spin_lock_init(&acm->read_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +0200917 acm->write_ready = 1;
David Kubicek61a87ad2005-11-01 18:51:34 +0100918 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
920 buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
921 if (!buf) {
922 dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
923 goto alloc_fail2;
924 }
925 acm->ctrl_buffer = buf;
926
Oliver Neukum884b6002005-04-21 21:28:02 +0200927 if (acm_write_buffers_alloc(acm) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
929 goto alloc_fail4;
930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
932 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
933 if (!acm->ctrlurb) {
934 dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
935 goto alloc_fail5;
936 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100937 for (i = 0; i < ACM_NRU; i++) {
938 struct acm_ru *rcv = &(acm->ru[i]);
939
940 if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
941 dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n");
942 goto alloc_fail7;
943 }
944
945 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
946 rcv->instance = acm;
947 }
948 for (i = 0; i < ACM_NRB; i++) {
949 struct acm_rb *buf = &(acm->rb[i]);
950
951 // Using usb_buffer_alloc instead of kmalloc as Oliver suggested
952 if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
953 dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
954 goto alloc_fail7;
955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 }
957 acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
958 if (!acm->writeurb) {
959 dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n");
960 goto alloc_fail7;
961 }
962
963 usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
964 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
965 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
966 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
967
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
Oliver Neukum884b6002005-04-21 21:28:02 +0200969 NULL, acm->writesize, acm_write_bulk, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
972 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
973
974 acm_set_control(acm, acm->ctrlout);
975
976 acm->line.dwDTERate = cpu_to_le32(9600);
977 acm->line.bDataBits = 8;
978 acm_set_line(acm, &acm->line);
979
980 usb_driver_claim_interface(&acm_driver, data_interface, acm);
981
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700982 usb_get_intf(control_interface);
983 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985 acm_table[minor] = acm;
986 usb_set_intfdata (intf, acm);
987 return 0;
988
989alloc_fail7:
David Kubicek61a87ad2005-11-01 18:51:34 +0100990 for (i = 0; i < ACM_NRB; i++)
991 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
992 for (i = 0; i < ACM_NRU; i++)
993 usb_free_urb(acm->ru[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 usb_free_urb(acm->ctrlurb);
995alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +0200996 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997alloc_fail4:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
999alloc_fail2:
1000 kfree(acm);
1001alloc_fail:
1002 return -ENOMEM;
1003}
1004
1005static void acm_disconnect(struct usb_interface *intf)
1006{
1007 struct acm *acm = usb_get_intfdata (intf);
1008 struct usb_device *usb_dev = interface_to_usbdev(intf);
David Kubicek61a87ad2005-11-01 18:51:34 +01001009 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
1011 if (!acm || !acm->dev) {
1012 dbg("disconnect on nonexisting interface");
1013 return;
1014 }
1015
1016 down(&open_sem);
Oliver Neukum86067eea2006-01-08 12:39:13 +01001017 if (!usb_get_intfdata(intf)) {
1018 up(&open_sem);
1019 return;
1020 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 acm->dev = NULL;
Oliver Neukum86067eea2006-01-08 12:39:13 +01001022 usb_set_intfdata(acm->control, NULL);
1023 usb_set_intfdata(acm->data, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
David Kubicek61a87ad2005-11-01 18:51:34 +01001025 tasklet_disable(&acm->urb_task);
1026
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 usb_kill_urb(acm->ctrlurb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 usb_kill_urb(acm->writeurb);
David Kubicek61a87ad2005-11-01 18:51:34 +01001029 for (i = 0; i < ACM_NRU; i++)
1030 usb_kill_urb(acm->ru[i].urb);
1031
1032 INIT_LIST_HEAD(&acm->filled_read_bufs);
1033 INIT_LIST_HEAD(&acm->spare_read_bufs);
1034
1035 tasklet_enable(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
1037 flush_scheduled_work(); /* wait for acm_softint */
1038
Oliver Neukum884b6002005-04-21 21:28:02 +02001039 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
David Kubicek61a87ad2005-11-01 18:51:34 +01001041 for (i = 0; i < ACM_NRB; i++)
1042 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Oliver Neukum86067eea2006-01-08 12:39:13 +01001044 usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
1046 if (!acm->used) {
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001047 acm_tty_unregister(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 up(&open_sem);
1049 return;
1050 }
1051
1052 up(&open_sem);
1053
1054 if (acm->tty)
1055 tty_hangup(acm->tty);
1056}
1057
1058/*
1059 * USB driver structure.
1060 */
1061
1062static struct usb_device_id acm_ids[] = {
1063 /* quirky and broken devices */
1064 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1065 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1066 },
Masahito Omote8753e652005-07-29 12:17:25 -07001067 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1068 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1069 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 /* control interfaces with various AT-command sets */
1071 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1072 USB_CDC_ACM_PROTO_AT_V25TER) },
1073 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1074 USB_CDC_ACM_PROTO_AT_PCCA101) },
1075 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1076 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1077 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1078 USB_CDC_ACM_PROTO_AT_GSM) },
1079 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1080 USB_CDC_ACM_PROTO_AT_3G ) },
1081 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1082 USB_CDC_ACM_PROTO_AT_CDMA) },
1083
1084 /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */
1085 { }
1086};
1087
1088MODULE_DEVICE_TABLE (usb, acm_ids);
1089
1090static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 .name = "cdc_acm",
1092 .probe = acm_probe,
1093 .disconnect = acm_disconnect,
1094 .id_table = acm_ids,
1095};
1096
1097/*
1098 * TTY driver structures.
1099 */
1100
1101static struct tty_operations acm_ops = {
1102 .open = acm_tty_open,
1103 .close = acm_tty_close,
1104 .write = acm_tty_write,
1105 .write_room = acm_tty_write_room,
1106 .ioctl = acm_tty_ioctl,
1107 .throttle = acm_tty_throttle,
1108 .unthrottle = acm_tty_unthrottle,
1109 .chars_in_buffer = acm_tty_chars_in_buffer,
1110 .break_ctl = acm_tty_break_ctl,
1111 .set_termios = acm_tty_set_termios,
1112 .tiocmget = acm_tty_tiocmget,
1113 .tiocmset = acm_tty_tiocmset,
1114};
1115
1116/*
1117 * Init / exit.
1118 */
1119
1120static int __init acm_init(void)
1121{
1122 int retval;
1123 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1124 if (!acm_tty_driver)
1125 return -ENOMEM;
1126 acm_tty_driver->owner = THIS_MODULE,
1127 acm_tty_driver->driver_name = "acm",
1128 acm_tty_driver->name = "ttyACM",
1129 acm_tty_driver->devfs_name = "usb/acm/",
1130 acm_tty_driver->major = ACM_TTY_MAJOR,
1131 acm_tty_driver->minor_start = 0,
1132 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1133 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
1134 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
1135 acm_tty_driver->init_termios = tty_std_termios;
1136 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1137 tty_set_operations(acm_tty_driver, &acm_ops);
1138
1139 retval = tty_register_driver(acm_tty_driver);
1140 if (retval) {
1141 put_tty_driver(acm_tty_driver);
1142 return retval;
1143 }
1144
1145 retval = usb_register(&acm_driver);
1146 if (retval) {
1147 tty_unregister_driver(acm_tty_driver);
1148 put_tty_driver(acm_tty_driver);
1149 return retval;
1150 }
1151
1152 info(DRIVER_VERSION ":" DRIVER_DESC);
1153
1154 return 0;
1155}
1156
1157static void __exit acm_exit(void)
1158{
1159 usb_deregister(&acm_driver);
1160 tty_unregister_driver(acm_tty_driver);
1161 put_tty_driver(acm_tty_driver);
1162}
1163
1164module_init(acm_init);
1165module_exit(acm_exit);
1166
1167MODULE_AUTHOR( DRIVER_AUTHOR );
1168MODULE_DESCRIPTION( DRIVER_DESC );
1169MODULE_LICENSE("GPL");
1170