blob: 6dd339f4c0fc52a933e3eb101f18bc88b94160f7 [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>
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010063#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include <asm/uaccess.h>
65#include <linux/usb.h>
66#include <linux/usb_cdc.h>
67#include <asm/byteorder.h>
68#include <asm/unaligned.h>
David Kubicek61a87ad2005-11-01 18:51:34 +010069#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71#include "cdc-acm.h"
72
73/*
74 * Version Information
75 */
David Kubicek61a87ad2005-11-01 18:51:34 +010076#define DRIVER_VERSION "v0.25"
77#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
Linus Torvalds1da177e2005-04-16 15:20:36 -070078#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
79
80static struct usb_driver acm_driver;
81static struct tty_driver *acm_tty_driver;
82static struct acm *acm_table[ACM_TTY_MINORS];
83
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010084static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86#define ACM_READY(acm) (acm && acm->dev && acm->used)
87
88/*
89 * Functions for ACM control messages.
90 */
91
92static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
93{
94 int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
95 request, USB_RT_ACM, value,
96 acm->control->altsetting[0].desc.bInterfaceNumber,
97 buf, len, 5000);
98 dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
99 return retval < 0 ? retval : 0;
100}
101
102/* devices aren't required to support these requests.
103 * the cdc acm descriptor tells whether they do...
104 */
105#define acm_set_control(acm, control) \
106 acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
107#define acm_set_line(acm, line) \
108 acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
109#define acm_send_break(acm, ms) \
110 acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
111
112/*
Oliver Neukum884b6002005-04-21 21:28:02 +0200113 * Write buffer management.
114 * All of these assume proper locks taken by the caller.
115 */
116
117static int acm_wb_alloc(struct acm *acm)
118{
119 int i, wbn;
120 struct acm_wb *wb;
121
122 wbn = acm->write_current;
123 i = 0;
124 for (;;) {
125 wb = &acm->wb[wbn];
126 if (!wb->use) {
127 wb->use = 1;
128 return wbn;
129 }
130 wbn = (wbn + 1) % ACM_NWB;
131 if (++i >= ACM_NWB)
132 return -1;
133 }
134}
135
136static void acm_wb_free(struct acm *acm, int wbn)
137{
138 acm->wb[wbn].use = 0;
139}
140
141static int acm_wb_is_avail(struct acm *acm)
142{
143 int i, n;
144
145 n = 0;
146 for (i = 0; i < ACM_NWB; i++) {
147 if (!acm->wb[i].use)
148 n++;
149 }
150 return n;
151}
152
153static inline int acm_wb_is_used(struct acm *acm, int wbn)
154{
155 return acm->wb[wbn].use;
156}
157
158/*
159 * Finish write.
160 */
161static void acm_write_done(struct acm *acm)
162{
163 unsigned long flags;
164 int wbn;
165
166 spin_lock_irqsave(&acm->write_lock, flags);
167 acm->write_ready = 1;
168 wbn = acm->write_current;
169 acm_wb_free(acm, wbn);
170 acm->write_current = (wbn + 1) % ACM_NWB;
171 spin_unlock_irqrestore(&acm->write_lock, flags);
172}
173
174/*
175 * Poke write.
176 */
177static int acm_write_start(struct acm *acm)
178{
179 unsigned long flags;
180 int wbn;
181 struct acm_wb *wb;
182 int rc;
183
184 spin_lock_irqsave(&acm->write_lock, flags);
185 if (!acm->dev) {
186 spin_unlock_irqrestore(&acm->write_lock, flags);
187 return -ENODEV;
188 }
189
190 if (!acm->write_ready) {
191 spin_unlock_irqrestore(&acm->write_lock, flags);
192 return 0; /* A white lie */
193 }
194
195 wbn = acm->write_current;
196 if (!acm_wb_is_used(acm, wbn)) {
197 spin_unlock_irqrestore(&acm->write_lock, flags);
198 return 0;
199 }
200 wb = &acm->wb[wbn];
201
202 acm->write_ready = 0;
203 spin_unlock_irqrestore(&acm->write_lock, flags);
204
205 acm->writeurb->transfer_buffer = wb->buf;
206 acm->writeurb->transfer_dma = wb->dmah;
207 acm->writeurb->transfer_buffer_length = wb->len;
208 acm->writeurb->dev = acm->dev;
209
210 if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) {
211 dbg("usb_submit_urb(write bulk) failed: %d", rc);
212 acm_write_done(acm);
213 }
214 return rc;
215}
216
217/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 * Interrupt handlers for various ACM device responses
219 */
220
221/* control interface reports status changes with "interrupt" transfers */
222static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs)
223{
224 struct acm *acm = urb->context;
225 struct usb_cdc_notification *dr = urb->transfer_buffer;
226 unsigned char *data;
227 int newctrl;
228 int status;
229
230 switch (urb->status) {
231 case 0:
232 /* success */
233 break;
234 case -ECONNRESET:
235 case -ENOENT:
236 case -ESHUTDOWN:
237 /* this urb is terminated, clean up */
238 dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
239 return;
240 default:
241 dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
242 goto exit;
243 }
244
245 if (!ACM_READY(acm))
246 goto exit;
247
248 data = (unsigned char *)(dr + 1);
249 switch (dr->bNotificationType) {
250
251 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
252
253 dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
254 break;
255
256 case USB_CDC_NOTIFY_SERIAL_STATE:
257
258 newctrl = le16_to_cpu(get_unaligned((__le16 *) data));
259
260 if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
261 dbg("calling hangup");
262 tty_hangup(acm->tty);
263 }
264
265 acm->ctrlin = newctrl;
266
267 dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
268 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
269 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
270 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
271 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
272
273 break;
274
275 default:
276 dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
277 dr->bNotificationType, dr->wIndex,
278 dr->wLength, data[0], data[1]);
279 break;
280 }
281exit:
282 status = usb_submit_urb (urb, GFP_ATOMIC);
283 if (status)
284 err ("%s - usb_submit_urb failed with result %d",
285 __FUNCTION__, status);
286}
287
288/* data interface returns incoming bytes, or we got unthrottled */
289static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
290{
David Kubicek61a87ad2005-11-01 18:51:34 +0100291 struct acm_rb *buf;
292 struct acm_ru *rcv = urb->context;
293 struct acm *acm = rcv->instance;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 dbg("Entering acm_read_bulk with status %d\n", urb->status);
295
296 if (!ACM_READY(acm))
297 return;
298
299 if (urb->status)
300 dev_dbg(&acm->data->dev, "bulk rx status %d\n", urb->status);
301
David Kubicek61a87ad2005-11-01 18:51:34 +0100302 buf = rcv->buffer;
303 buf->size = urb->actual_length;
304
305 spin_lock(&acm->read_lock);
306 list_add_tail(&rcv->list, &acm->spare_read_urbs);
307 list_add_tail(&buf->list, &acm->filled_read_bufs);
308 spin_unlock(&acm->read_lock);
309
310 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311}
312
313static void acm_rx_tasklet(unsigned long _acm)
314{
315 struct acm *acm = (void *)_acm;
David Kubicek61a87ad2005-11-01 18:51:34 +0100316 struct acm_rb *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 struct tty_struct *tty = acm->tty;
David Kubicek61a87ad2005-11-01 18:51:34 +0100318 struct acm_ru *rcv;
319 //unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 int i = 0;
321 dbg("Entering acm_rx_tasklet");
322
David Kubicek61a87ad2005-11-01 18:51:34 +0100323 if (!ACM_READY(acm) || acm->throttle)
324 return;
325
326next_buffer:
327 spin_lock(&acm->read_lock);
328 if (list_empty(&acm->filled_read_bufs)) {
329 spin_unlock(&acm->read_lock);
330 goto urbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100332 buf = list_entry(acm->filled_read_bufs.next,
333 struct acm_rb, list);
334 list_del(&buf->list);
335 spin_unlock(&acm->read_lock);
336
337 dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d\n", buf, buf->size);
338
Alan Cox33f0f882006-01-09 20:54:13 -0800339 tty_buffer_request_room(tty, buf->size);
340 if (!acm->throttle)
341 tty_insert_flip_string(tty, buf->base, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100342 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344 spin_lock(&acm->throttle_lock);
345 if (acm->throttle) {
346 dbg("Throtteling noticed");
David Kubicek61a87ad2005-11-01 18:51:34 +0100347 memmove(buf->base, buf->base + i, buf->size - i);
348 buf->size -= i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 spin_unlock(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100350 spin_lock(&acm->read_lock);
351 list_add(&buf->list, &acm->filled_read_bufs);
352 spin_unlock(&acm->read_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 return;
354 }
355 spin_unlock(&acm->throttle_lock);
356
David Kubicek61a87ad2005-11-01 18:51:34 +0100357 spin_lock(&acm->read_lock);
358 list_add(&buf->list, &acm->spare_read_bufs);
359 spin_unlock(&acm->read_lock);
360 goto next_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
David Kubicek61a87ad2005-11-01 18:51:34 +0100362urbs:
363 while (!list_empty(&acm->spare_read_bufs)) {
364 spin_lock(&acm->read_lock);
365 if (list_empty(&acm->spare_read_urbs)) {
366 spin_unlock(&acm->read_lock);
367 return;
368 }
369 rcv = list_entry(acm->spare_read_urbs.next,
370 struct acm_ru, list);
371 list_del(&rcv->list);
372 spin_unlock(&acm->read_lock);
373
374 buf = list_entry(acm->spare_read_bufs.next,
375 struct acm_rb, list);
376 list_del(&buf->list);
377
378 rcv->buffer = buf;
379
380 usb_fill_bulk_urb(rcv->urb, acm->dev,
381 acm->rx_endpoint,
382 buf->base,
383 acm->readsize,
384 acm_read_bulk, rcv);
385 rcv->urb->transfer_dma = buf->dma;
386 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
387
388 dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p\n", rcv->urb, rcv, buf);
389
390 /* This shouldn't kill the driver as unsuccessful URBs are returned to the
391 free-urbs-pool and resubmited ASAP */
392 if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
393 list_add(&buf->list, &acm->spare_read_bufs);
394 spin_lock(&acm->read_lock);
395 list_add(&rcv->list, &acm->spare_read_urbs);
396 spin_unlock(&acm->read_lock);
397 return;
398 }
399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400}
401
402/* data interface wrote those outgoing bytes */
403static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
404{
405 struct acm *acm = (struct acm *)urb->context;
Oliver Neukum884b6002005-04-21 21:28:02 +0200406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 dbg("Entering acm_write_bulk with status %d\n", urb->status);
408
Oliver Neukum884b6002005-04-21 21:28:02 +0200409 acm_write_done(acm);
410 acm_write_start(acm);
411 if (ACM_READY(acm))
412 schedule_work(&acm->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413}
414
415static void acm_softint(void *private)
416{
417 struct acm *acm = private;
418 dbg("Entering acm_softint.\n");
419
420 if (!ACM_READY(acm))
421 return;
422 tty_wakeup(acm->tty);
423}
424
425/*
426 * TTY handlers
427 */
428
429static int acm_tty_open(struct tty_struct *tty, struct file *filp)
430{
431 struct acm *acm;
432 int rv = -EINVAL;
David Kubicek61a87ad2005-11-01 18:51:34 +0100433 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 dbg("Entering acm_tty_open.\n");
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100435
436 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
438 acm = acm_table[tty->index];
439 if (!acm || !acm->dev)
440 goto err_out;
441 else
442 rv = 0;
443
444 tty->driver_data = acm;
445 acm->tty = tty;
446
David Kubicek61a87ad2005-11-01 18:51:34 +0100447 /* force low_latency on so that our tty_push actually forces the data through,
448 otherwise it is scheduled, and with high data rates data can get lost. */
449 tty->low_latency = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 if (acm->used++) {
452 goto done;
453 }
454
455 acm->ctrlurb->dev = acm->dev;
456 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
457 dbg("usb_submit_urb(ctrl irq) failed");
458 goto bail_out;
459 }
460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS))
462 goto full_bailout;
463
David Kubicek61a87ad2005-11-01 18:51:34 +0100464 INIT_LIST_HEAD(&acm->spare_read_urbs);
465 INIT_LIST_HEAD(&acm->spare_read_bufs);
466 INIT_LIST_HEAD(&acm->filled_read_bufs);
467 for (i = 0; i < ACM_NRU; i++) {
468 list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
469 }
470 for (i = 0; i < ACM_NRB; i++) {
471 list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
472 }
473
474 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
476done:
477err_out:
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100478 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 return rv;
480
481full_bailout:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 usb_kill_urb(acm->ctrlurb);
483bail_out:
484 acm->used--;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100485 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 return -EIO;
487}
488
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700489static void acm_tty_unregister(struct acm *acm)
490{
David Kubicek61a87ad2005-11-01 18:51:34 +0100491 int i;
492
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700493 tty_unregister_device(acm_tty_driver, acm->minor);
494 usb_put_intf(acm->control);
495 acm_table[acm->minor] = NULL;
496 usb_free_urb(acm->ctrlurb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700497 usb_free_urb(acm->writeurb);
David Kubicek61a87ad2005-11-01 18:51:34 +0100498 for (i = 0; i < ACM_NRU; i++)
499 usb_free_urb(acm->ru[i].urb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700500 kfree(acm);
501}
502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503static void acm_tty_close(struct tty_struct *tty, struct file *filp)
504{
505 struct acm *acm = tty->driver_data;
David Kubicek61a87ad2005-11-01 18:51:34 +0100506 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 if (!acm || !acm->used)
509 return;
510
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100511 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 if (!--acm->used) {
513 if (acm->dev) {
514 acm_set_control(acm, acm->ctrlout = 0);
515 usb_kill_urb(acm->ctrlurb);
516 usb_kill_urb(acm->writeurb);
David Kubicek61a87ad2005-11-01 18:51:34 +0100517 for (i = 0; i < ACM_NRU; i++)
518 usb_kill_urb(acm->ru[i].urb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700519 } else
520 acm_tty_unregister(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 }
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100522 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523}
524
525static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
526{
527 struct acm *acm = tty->driver_data;
528 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200529 unsigned long flags;
530 int wbn;
531 struct acm_wb *wb;
532
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 dbg("Entering acm_tty_write to write %d bytes,\n", count);
534
535 if (!ACM_READY(acm))
536 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 if (!count)
538 return 0;
539
Oliver Neukum884b6002005-04-21 21:28:02 +0200540 spin_lock_irqsave(&acm->write_lock, flags);
541 if ((wbn = acm_wb_alloc(acm)) < 0) {
542 spin_unlock_irqrestore(&acm->write_lock, flags);
543 acm_write_start(acm);
544 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200546 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Oliver Neukum884b6002005-04-21 21:28:02 +0200548 count = (count > acm->writesize) ? acm->writesize : count;
549 dbg("Get %d bytes...", count);
550 memcpy(wb->buf, buf, count);
551 wb->len = count;
552 spin_unlock_irqrestore(&acm->write_lock, flags);
553
554 if ((stat = acm_write_start(acm)) < 0)
555 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 return count;
557}
558
559static int acm_tty_write_room(struct tty_struct *tty)
560{
561 struct acm *acm = tty->driver_data;
562 if (!ACM_READY(acm))
563 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200564 /*
565 * Do not let the line discipline to know that we have a reserve,
566 * or it might get too enthusiastic.
567 */
568 return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569}
570
571static int acm_tty_chars_in_buffer(struct tty_struct *tty)
572{
573 struct acm *acm = tty->driver_data;
574 if (!ACM_READY(acm))
575 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200576 /*
577 * This is inaccurate (overcounts), but it works.
578 */
579 return (ACM_NWB - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580}
581
582static void acm_tty_throttle(struct tty_struct *tty)
583{
584 struct acm *acm = tty->driver_data;
585 if (!ACM_READY(acm))
586 return;
587 spin_lock_bh(&acm->throttle_lock);
588 acm->throttle = 1;
589 spin_unlock_bh(&acm->throttle_lock);
590}
591
592static void acm_tty_unthrottle(struct tty_struct *tty)
593{
594 struct acm *acm = tty->driver_data;
595 if (!ACM_READY(acm))
596 return;
597 spin_lock_bh(&acm->throttle_lock);
598 acm->throttle = 0;
599 spin_unlock_bh(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100600 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601}
602
603static void acm_tty_break_ctl(struct tty_struct *tty, int state)
604{
605 struct acm *acm = tty->driver_data;
606 if (!ACM_READY(acm))
607 return;
608 if (acm_send_break(acm, state ? 0xffff : 0))
609 dbg("send break failed");
610}
611
612static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file)
613{
614 struct acm *acm = tty->driver_data;
615
616 if (!ACM_READY(acm))
617 return -EINVAL;
618
619 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
620 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
621 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
622 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
623 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
624 TIOCM_CTS;
625}
626
627static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
628 unsigned int set, unsigned int clear)
629{
630 struct acm *acm = tty->driver_data;
631 unsigned int newctrl;
632
633 if (!ACM_READY(acm))
634 return -EINVAL;
635
636 newctrl = acm->ctrlout;
637 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
638 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
639
640 newctrl = (newctrl & ~clear) | set;
641
642 if (acm->ctrlout == newctrl)
643 return 0;
644 return acm_set_control(acm, acm->ctrlout = newctrl);
645}
646
647static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
648{
649 struct acm *acm = tty->driver_data;
650
651 if (!ACM_READY(acm))
652 return -EINVAL;
653
654 return -ENOIOCTLCMD;
655}
656
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100657static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 0, 50, 75, 110, 134, 150, 200, 300, 600,
659 1200, 1800, 2400, 4800, 9600, 19200, 38400,
660 57600, 115200, 230400, 460800, 500000, 576000,
661 921600, 1000000, 1152000, 1500000, 2000000,
662 2500000, 3000000, 3500000, 4000000
663};
664
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100665static const __u8 acm_tty_size[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 5, 6, 7, 8
667};
668
669static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
670{
671 struct acm *acm = tty->driver_data;
672 struct termios *termios = tty->termios;
673 struct usb_cdc_line_coding newline;
674 int newctrl = acm->ctrlout;
675
676 if (!ACM_READY(acm))
677 return;
678
679 newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
680 (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
681 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
682 newline.bParityType = termios->c_cflag & PARENB ?
683 (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
684 newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
685
686 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
687
688 if (!newline.dwDTERate) {
689 newline.dwDTERate = acm->line.dwDTERate;
690 newctrl &= ~ACM_CTRL_DTR;
691 } else newctrl |= ACM_CTRL_DTR;
692
693 if (newctrl != acm->ctrlout)
694 acm_set_control(acm, acm->ctrlout = newctrl);
695
696 if (memcmp(&acm->line, &newline, sizeof newline)) {
697 memcpy(&acm->line, &newline, sizeof newline);
698 dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
699 newline.bCharFormat, newline.bParityType,
700 newline.bDataBits);
701 acm_set_line(acm, &acm->line);
702 }
703}
704
705/*
706 * USB probe and disconnect routines.
707 */
708
Oliver Neukum884b6002005-04-21 21:28:02 +0200709/* Little helper: write buffers free */
710static void acm_write_buffers_free(struct acm *acm)
711{
712 int i;
713 struct acm_wb *wb;
714
715 for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
716 usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
717 }
718}
719
720/* Little helper: write buffers allocate */
721static int acm_write_buffers_alloc(struct acm *acm)
722{
723 int i;
724 struct acm_wb *wb;
725
726 for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
727 wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
728 &wb->dmah);
729 if (!wb->buf) {
730 while (i != 0) {
731 --i;
732 --wb;
733 usb_buffer_free(acm->dev, acm->writesize,
734 wb->buf, wb->dmah);
735 }
736 return -ENOMEM;
737 }
738 }
739 return 0;
740}
741
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742static int acm_probe (struct usb_interface *intf,
743 const struct usb_device_id *id)
744{
745 struct usb_cdc_union_desc *union_header = NULL;
746 char *buffer = intf->altsetting->extra;
747 int buflen = intf->altsetting->extralen;
748 struct usb_interface *control_interface;
749 struct usb_interface *data_interface;
750 struct usb_endpoint_descriptor *epctrl;
751 struct usb_endpoint_descriptor *epread;
752 struct usb_endpoint_descriptor *epwrite;
753 struct usb_device *usb_dev = interface_to_usbdev(intf);
754 struct acm *acm;
755 int minor;
756 int ctrlsize,readsize;
757 u8 *buf;
758 u8 ac_management_function = 0;
759 u8 call_management_function = 0;
760 int call_interface_num = -1;
761 int data_interface_num;
762 unsigned long quirks;
David Kubicek61a87ad2005-11-01 18:51:34 +0100763 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
765 /* handle quirks deadly to normal probing*/
766 quirks = (unsigned long)id->driver_info;
767 if (quirks == NO_UNION_NORMAL) {
768 data_interface = usb_ifnum_to_if(usb_dev, 1);
769 control_interface = usb_ifnum_to_if(usb_dev, 0);
770 goto skip_normal_probe;
771 }
772
773 /* normal probing*/
774 if (!buffer) {
775 err("Wierd descriptor references\n");
776 return -EINVAL;
777 }
778
779 if (!buflen) {
780 if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
781 dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n");
782 buflen = intf->cur_altsetting->endpoint->extralen;
783 buffer = intf->cur_altsetting->endpoint->extra;
784 } else {
785 err("Zero length descriptor references\n");
786 return -EINVAL;
787 }
788 }
789
790 while (buflen > 0) {
791 if (buffer [1] != USB_DT_CS_INTERFACE) {
792 err("skipping garbage\n");
793 goto next_desc;
794 }
795
796 switch (buffer [2]) {
797 case USB_CDC_UNION_TYPE: /* we've found it */
798 if (union_header) {
799 err("More than one union descriptor, skipping ...");
800 goto next_desc;
801 }
802 union_header = (struct usb_cdc_union_desc *)
803 buffer;
804 break;
805 case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */
806 break; /* for now we ignore it */
807 case USB_CDC_HEADER_TYPE: /* maybe check version */
808 break; /* for now we ignore it */
809 case USB_CDC_ACM_TYPE:
810 ac_management_function = buffer[3];
811 break;
812 case USB_CDC_CALL_MANAGEMENT_TYPE:
813 call_management_function = buffer[3];
814 call_interface_num = buffer[4];
815 if ((call_management_function & 3) != 3)
816 err("This device cannot do calls on its own. It is no modem.");
817 break;
818
819 default:
820 err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]);
821 break;
822 }
823next_desc:
824 buflen -= buffer[0];
825 buffer += buffer[0];
826 }
827
828 if (!union_header) {
829 if (call_interface_num > 0) {
830 dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n");
831 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
832 control_interface = intf;
833 } else {
834 dev_dbg(&intf->dev,"No union descriptor, giving up\n");
835 return -ENODEV;
836 }
837 } else {
838 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
839 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
840 if (!control_interface || !data_interface) {
841 dev_dbg(&intf->dev,"no interfaces\n");
842 return -ENODEV;
843 }
844 }
845
846 if (data_interface_num != call_interface_num)
847 dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n");
848
849skip_normal_probe:
850
851 /*workaround for switched interfaces */
852 if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
853 if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
854 struct usb_interface *t;
855 dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
856
857 t = control_interface;
858 control_interface = data_interface;
859 data_interface = t;
860 } else {
861 return -EINVAL;
862 }
863 }
864
865 if (usb_interface_claimed(data_interface)) { /* valid in this context */
866 dev_dbg(&intf->dev,"The data interface isn't available\n");
867 return -EBUSY;
868 }
869
870
871 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
872 return -EINVAL;
873
874 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
875 epread = &data_interface->cur_altsetting->endpoint[0].desc;
876 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
877
878
879 /* workaround for switched endpoints */
880 if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) {
881 /* descriptors are swapped */
882 struct usb_endpoint_descriptor *t;
883 dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
884
885 t = epread;
886 epread = epwrite;
887 epwrite = t;
888 }
889 dbg("interfaces are valid");
890 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
891
892 if (minor == ACM_TTY_MINORS) {
893 err("no more free acm devices");
894 return -ENODEV;
895 }
896
Oliver Neukum46f116e2005-10-24 22:42:35 +0200897 if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
898 dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 goto alloc_fail;
900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
902 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
David Kubicek61a87ad2005-11-01 18:51:34 +0100903 readsize = le16_to_cpu(epread->wMaxPacketSize)*2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize);
905 acm->control = control_interface;
906 acm->data = data_interface;
907 acm->minor = minor;
908 acm->dev = usb_dev;
909 acm->ctrl_caps = ac_management_function;
910 acm->ctrlsize = ctrlsize;
911 acm->readsize = readsize;
David Kubicek61a87ad2005-11-01 18:51:34 +0100912 acm->urb_task.func = acm_rx_tasklet;
913 acm->urb_task.data = (unsigned long) acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 INIT_WORK(&acm->work, acm_softint, acm);
915 spin_lock_init(&acm->throttle_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +0200916 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100917 spin_lock_init(&acm->read_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +0200918 acm->write_ready = 1;
David Kubicek61a87ad2005-11-01 18:51:34 +0100919 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
921 buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
922 if (!buf) {
923 dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
924 goto alloc_fail2;
925 }
926 acm->ctrl_buffer = buf;
927
Oliver Neukum884b6002005-04-21 21:28:02 +0200928 if (acm_write_buffers_alloc(acm) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
930 goto alloc_fail4;
931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
933 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
934 if (!acm->ctrlurb) {
935 dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
936 goto alloc_fail5;
937 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100938 for (i = 0; i < ACM_NRU; i++) {
939 struct acm_ru *rcv = &(acm->ru[i]);
940
941 if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
942 dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n");
943 goto alloc_fail7;
944 }
945
946 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
947 rcv->instance = acm;
948 }
949 for (i = 0; i < ACM_NRB; i++) {
950 struct acm_rb *buf = &(acm->rb[i]);
951
952 // Using usb_buffer_alloc instead of kmalloc as Oliver suggested
953 if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
954 dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
955 goto alloc_fail7;
956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 }
958 acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
959 if (!acm->writeurb) {
960 dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n");
961 goto alloc_fail7;
962 }
963
964 usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
965 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
966 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
967 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
968
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
Oliver Neukum884b6002005-04-21 21:28:02 +0200970 NULL, acm->writesize, acm_write_bulk, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
973 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
974
975 acm_set_control(acm, acm->ctrlout);
976
977 acm->line.dwDTERate = cpu_to_le32(9600);
978 acm->line.bDataBits = 8;
979 acm_set_line(acm, &acm->line);
980
981 usb_driver_claim_interface(&acm_driver, data_interface, acm);
982
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700983 usb_get_intf(control_interface);
984 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
986 acm_table[minor] = acm;
987 usb_set_intfdata (intf, acm);
988 return 0;
989
990alloc_fail7:
David Kubicek61a87ad2005-11-01 18:51:34 +0100991 for (i = 0; i < ACM_NRB; i++)
992 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
993 for (i = 0; i < ACM_NRU; i++)
994 usb_free_urb(acm->ru[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 usb_free_urb(acm->ctrlurb);
996alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +0200997 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998alloc_fail4:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
1000alloc_fail2:
1001 kfree(acm);
1002alloc_fail:
1003 return -ENOMEM;
1004}
1005
1006static void acm_disconnect(struct usb_interface *intf)
1007{
1008 struct acm *acm = usb_get_intfdata (intf);
1009 struct usb_device *usb_dev = interface_to_usbdev(intf);
David Kubicek61a87ad2005-11-01 18:51:34 +01001010 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
1012 if (!acm || !acm->dev) {
1013 dbg("disconnect on nonexisting interface");
1014 return;
1015 }
1016
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001017 mutex_lock(&open_mutex);
Oliver Neukum86067eea2006-01-08 12:39:13 +01001018 if (!usb_get_intfdata(intf)) {
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001019 mutex_unlock(&open_mutex);
Oliver Neukum86067eea2006-01-08 12:39:13 +01001020 return;
1021 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 acm->dev = NULL;
Oliver Neukum86067eea2006-01-08 12:39:13 +01001023 usb_set_intfdata(acm->control, NULL);
1024 usb_set_intfdata(acm->data, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
David Kubicek61a87ad2005-11-01 18:51:34 +01001026 tasklet_disable(&acm->urb_task);
1027
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 usb_kill_urb(acm->ctrlurb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 usb_kill_urb(acm->writeurb);
David Kubicek61a87ad2005-11-01 18:51:34 +01001030 for (i = 0; i < ACM_NRU; i++)
1031 usb_kill_urb(acm->ru[i].urb);
1032
1033 INIT_LIST_HEAD(&acm->filled_read_bufs);
1034 INIT_LIST_HEAD(&acm->spare_read_bufs);
1035
1036 tasklet_enable(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
1038 flush_scheduled_work(); /* wait for acm_softint */
1039
Oliver Neukum884b6002005-04-21 21:28:02 +02001040 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
David Kubicek61a87ad2005-11-01 18:51:34 +01001042 for (i = 0; i < ACM_NRB; i++)
1043 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Oliver Neukum86067eea2006-01-08 12:39:13 +01001045 usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
1047 if (!acm->used) {
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001048 acm_tty_unregister(acm);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001049 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 return;
1051 }
1052
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001053 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054
1055 if (acm->tty)
1056 tty_hangup(acm->tty);
1057}
1058
1059/*
1060 * USB driver structure.
1061 */
1062
1063static struct usb_device_id acm_ids[] = {
1064 /* quirky and broken devices */
1065 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1066 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1067 },
Masahito Omote8753e652005-07-29 12:17:25 -07001068 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1069 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1070 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 /* control interfaces with various AT-command sets */
1072 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1073 USB_CDC_ACM_PROTO_AT_V25TER) },
1074 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1075 USB_CDC_ACM_PROTO_AT_PCCA101) },
1076 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1077 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1078 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1079 USB_CDC_ACM_PROTO_AT_GSM) },
1080 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1081 USB_CDC_ACM_PROTO_AT_3G ) },
1082 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1083 USB_CDC_ACM_PROTO_AT_CDMA) },
1084
1085 /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */
1086 { }
1087};
1088
1089MODULE_DEVICE_TABLE (usb, acm_ids);
1090
1091static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 .name = "cdc_acm",
1093 .probe = acm_probe,
1094 .disconnect = acm_disconnect,
1095 .id_table = acm_ids,
1096};
1097
1098/*
1099 * TTY driver structures.
1100 */
1101
1102static struct tty_operations acm_ops = {
1103 .open = acm_tty_open,
1104 .close = acm_tty_close,
1105 .write = acm_tty_write,
1106 .write_room = acm_tty_write_room,
1107 .ioctl = acm_tty_ioctl,
1108 .throttle = acm_tty_throttle,
1109 .unthrottle = acm_tty_unthrottle,
1110 .chars_in_buffer = acm_tty_chars_in_buffer,
1111 .break_ctl = acm_tty_break_ctl,
1112 .set_termios = acm_tty_set_termios,
1113 .tiocmget = acm_tty_tiocmget,
1114 .tiocmset = acm_tty_tiocmset,
1115};
1116
1117/*
1118 * Init / exit.
1119 */
1120
1121static int __init acm_init(void)
1122{
1123 int retval;
1124 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1125 if (!acm_tty_driver)
1126 return -ENOMEM;
1127 acm_tty_driver->owner = THIS_MODULE,
1128 acm_tty_driver->driver_name = "acm",
1129 acm_tty_driver->name = "ttyACM",
1130 acm_tty_driver->devfs_name = "usb/acm/",
1131 acm_tty_driver->major = ACM_TTY_MAJOR,
1132 acm_tty_driver->minor_start = 0,
1133 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1134 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
1135 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
1136 acm_tty_driver->init_termios = tty_std_termios;
1137 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1138 tty_set_operations(acm_tty_driver, &acm_ops);
1139
1140 retval = tty_register_driver(acm_tty_driver);
1141 if (retval) {
1142 put_tty_driver(acm_tty_driver);
1143 return retval;
1144 }
1145
1146 retval = usb_register(&acm_driver);
1147 if (retval) {
1148 tty_unregister_driver(acm_tty_driver);
1149 put_tty_driver(acm_tty_driver);
1150 return retval;
1151 }
1152
1153 info(DRIVER_VERSION ":" DRIVER_DESC);
1154
1155 return 0;
1156}
1157
1158static void __exit acm_exit(void)
1159{
1160 usb_deregister(&acm_driver);
1161 tty_unregister_driver(acm_tty_driver);
1162 put_tty_driver(acm_tty_driver);
1163}
1164
1165module_init(acm_init);
1166module_exit(acm_exit);
1167
1168MODULE_AUTHOR( DRIVER_AUTHOR );
1169MODULE_DESCRIPTION( DRIVER_DESC );
1170MODULE_LICENSE("GPL");
1171