blob: 93de121f52a8693682a4b947dc205c331b4ee668 [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
338 for (i = 0; i < buf->size && !acm->throttle; i++) {
339 /* if we insert more than TTY_FLIPBUF_SIZE characters,
340 we drop them. */
341 if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
342 tty_flip_buffer_push(tty);
343 }
344 tty_insert_flip_char(tty, buf->base[i], 0);
345 }
346 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
348 spin_lock(&acm->throttle_lock);
349 if (acm->throttle) {
350 dbg("Throtteling noticed");
David Kubicek61a87ad2005-11-01 18:51:34 +0100351 memmove(buf->base, buf->base + i, buf->size - i);
352 buf->size -= i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 spin_unlock(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100354 spin_lock(&acm->read_lock);
355 list_add(&buf->list, &acm->filled_read_bufs);
356 spin_unlock(&acm->read_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 return;
358 }
359 spin_unlock(&acm->throttle_lock);
360
David Kubicek61a87ad2005-11-01 18:51:34 +0100361 spin_lock(&acm->read_lock);
362 list_add(&buf->list, &acm->spare_read_bufs);
363 spin_unlock(&acm->read_lock);
364 goto next_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
David Kubicek61a87ad2005-11-01 18:51:34 +0100366urbs:
367 while (!list_empty(&acm->spare_read_bufs)) {
368 spin_lock(&acm->read_lock);
369 if (list_empty(&acm->spare_read_urbs)) {
370 spin_unlock(&acm->read_lock);
371 return;
372 }
373 rcv = list_entry(acm->spare_read_urbs.next,
374 struct acm_ru, list);
375 list_del(&rcv->list);
376 spin_unlock(&acm->read_lock);
377
378 buf = list_entry(acm->spare_read_bufs.next,
379 struct acm_rb, list);
380 list_del(&buf->list);
381
382 rcv->buffer = buf;
383
384 usb_fill_bulk_urb(rcv->urb, acm->dev,
385 acm->rx_endpoint,
386 buf->base,
387 acm->readsize,
388 acm_read_bulk, rcv);
389 rcv->urb->transfer_dma = buf->dma;
390 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
391
392 dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p\n", rcv->urb, rcv, buf);
393
394 /* This shouldn't kill the driver as unsuccessful URBs are returned to the
395 free-urbs-pool and resubmited ASAP */
396 if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
397 list_add(&buf->list, &acm->spare_read_bufs);
398 spin_lock(&acm->read_lock);
399 list_add(&rcv->list, &acm->spare_read_urbs);
400 spin_unlock(&acm->read_lock);
401 return;
402 }
403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404}
405
406/* data interface wrote those outgoing bytes */
407static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
408{
409 struct acm *acm = (struct acm *)urb->context;
Oliver Neukum884b6002005-04-21 21:28:02 +0200410
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 dbg("Entering acm_write_bulk with status %d\n", urb->status);
412
Oliver Neukum884b6002005-04-21 21:28:02 +0200413 acm_write_done(acm);
414 acm_write_start(acm);
415 if (ACM_READY(acm))
416 schedule_work(&acm->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417}
418
419static void acm_softint(void *private)
420{
421 struct acm *acm = private;
422 dbg("Entering acm_softint.\n");
423
424 if (!ACM_READY(acm))
425 return;
426 tty_wakeup(acm->tty);
427}
428
429/*
430 * TTY handlers
431 */
432
433static int acm_tty_open(struct tty_struct *tty, struct file *filp)
434{
435 struct acm *acm;
436 int rv = -EINVAL;
David Kubicek61a87ad2005-11-01 18:51:34 +0100437 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 dbg("Entering acm_tty_open.\n");
439
440 down(&open_sem);
441
442 acm = acm_table[tty->index];
443 if (!acm || !acm->dev)
444 goto err_out;
445 else
446 rv = 0;
447
448 tty->driver_data = acm;
449 acm->tty = tty;
450
David Kubicek61a87ad2005-11-01 18:51:34 +0100451 /* force low_latency on so that our tty_push actually forces the data through,
452 otherwise it is scheduled, and with high data rates data can get lost. */
453 tty->low_latency = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455 if (acm->used++) {
456 goto done;
457 }
458
459 acm->ctrlurb->dev = acm->dev;
460 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
461 dbg("usb_submit_urb(ctrl irq) failed");
462 goto bail_out;
463 }
464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS))
466 goto full_bailout;
467
David Kubicek61a87ad2005-11-01 18:51:34 +0100468 INIT_LIST_HEAD(&acm->spare_read_urbs);
469 INIT_LIST_HEAD(&acm->spare_read_bufs);
470 INIT_LIST_HEAD(&acm->filled_read_bufs);
471 for (i = 0; i < ACM_NRU; i++) {
472 list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
473 }
474 for (i = 0; i < ACM_NRB; i++) {
475 list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
476 }
477
478 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
480done:
481err_out:
482 up(&open_sem);
483 return rv;
484
485full_bailout:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 usb_kill_urb(acm->ctrlurb);
487bail_out:
488 acm->used--;
489 up(&open_sem);
490 return -EIO;
491}
492
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700493static void acm_tty_unregister(struct acm *acm)
494{
David Kubicek61a87ad2005-11-01 18:51:34 +0100495 int i;
496
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700497 tty_unregister_device(acm_tty_driver, acm->minor);
498 usb_put_intf(acm->control);
499 acm_table[acm->minor] = NULL;
500 usb_free_urb(acm->ctrlurb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700501 usb_free_urb(acm->writeurb);
David Kubicek61a87ad2005-11-01 18:51:34 +0100502 for (i = 0; i < ACM_NRU; i++)
503 usb_free_urb(acm->ru[i].urb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700504 kfree(acm);
505}
506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507static void acm_tty_close(struct tty_struct *tty, struct file *filp)
508{
509 struct acm *acm = tty->driver_data;
David Kubicek61a87ad2005-11-01 18:51:34 +0100510 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
512 if (!acm || !acm->used)
513 return;
514
515 down(&open_sem);
516 if (!--acm->used) {
517 if (acm->dev) {
518 acm_set_control(acm, acm->ctrlout = 0);
519 usb_kill_urb(acm->ctrlurb);
520 usb_kill_urb(acm->writeurb);
David Kubicek61a87ad2005-11-01 18:51:34 +0100521 for (i = 0; i < ACM_NRU; i++)
522 usb_kill_urb(acm->ru[i].urb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700523 } else
524 acm_tty_unregister(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 }
526 up(&open_sem);
527}
528
529static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
530{
531 struct acm *acm = tty->driver_data;
532 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200533 unsigned long flags;
534 int wbn;
535 struct acm_wb *wb;
536
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 dbg("Entering acm_tty_write to write %d bytes,\n", count);
538
539 if (!ACM_READY(acm))
540 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 if (!count)
542 return 0;
543
Oliver Neukum884b6002005-04-21 21:28:02 +0200544 spin_lock_irqsave(&acm->write_lock, flags);
545 if ((wbn = acm_wb_alloc(acm)) < 0) {
546 spin_unlock_irqrestore(&acm->write_lock, flags);
547 acm_write_start(acm);
548 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200550 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
Oliver Neukum884b6002005-04-21 21:28:02 +0200552 count = (count > acm->writesize) ? acm->writesize : count;
553 dbg("Get %d bytes...", count);
554 memcpy(wb->buf, buf, count);
555 wb->len = count;
556 spin_unlock_irqrestore(&acm->write_lock, flags);
557
558 if ((stat = acm_write_start(acm)) < 0)
559 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 return count;
561}
562
563static int acm_tty_write_room(struct tty_struct *tty)
564{
565 struct acm *acm = tty->driver_data;
566 if (!ACM_READY(acm))
567 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200568 /*
569 * Do not let the line discipline to know that we have a reserve,
570 * or it might get too enthusiastic.
571 */
572 return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573}
574
575static int acm_tty_chars_in_buffer(struct tty_struct *tty)
576{
577 struct acm *acm = tty->driver_data;
578 if (!ACM_READY(acm))
579 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200580 /*
581 * This is inaccurate (overcounts), but it works.
582 */
583 return (ACM_NWB - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584}
585
586static void acm_tty_throttle(struct tty_struct *tty)
587{
588 struct acm *acm = tty->driver_data;
589 if (!ACM_READY(acm))
590 return;
591 spin_lock_bh(&acm->throttle_lock);
592 acm->throttle = 1;
593 spin_unlock_bh(&acm->throttle_lock);
594}
595
596static void acm_tty_unthrottle(struct tty_struct *tty)
597{
598 struct acm *acm = tty->driver_data;
599 if (!ACM_READY(acm))
600 return;
601 spin_lock_bh(&acm->throttle_lock);
602 acm->throttle = 0;
603 spin_unlock_bh(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100604 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605}
606
607static void acm_tty_break_ctl(struct tty_struct *tty, int state)
608{
609 struct acm *acm = tty->driver_data;
610 if (!ACM_READY(acm))
611 return;
612 if (acm_send_break(acm, state ? 0xffff : 0))
613 dbg("send break failed");
614}
615
616static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file)
617{
618 struct acm *acm = tty->driver_data;
619
620 if (!ACM_READY(acm))
621 return -EINVAL;
622
623 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
624 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
625 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
626 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
627 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
628 TIOCM_CTS;
629}
630
631static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
632 unsigned int set, unsigned int clear)
633{
634 struct acm *acm = tty->driver_data;
635 unsigned int newctrl;
636
637 if (!ACM_READY(acm))
638 return -EINVAL;
639
640 newctrl = acm->ctrlout;
641 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
642 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
643
644 newctrl = (newctrl & ~clear) | set;
645
646 if (acm->ctrlout == newctrl)
647 return 0;
648 return acm_set_control(acm, acm->ctrlout = newctrl);
649}
650
651static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
652{
653 struct acm *acm = tty->driver_data;
654
655 if (!ACM_READY(acm))
656 return -EINVAL;
657
658 return -ENOIOCTLCMD;
659}
660
661static __u32 acm_tty_speed[] = {
662 0, 50, 75, 110, 134, 150, 200, 300, 600,
663 1200, 1800, 2400, 4800, 9600, 19200, 38400,
664 57600, 115200, 230400, 460800, 500000, 576000,
665 921600, 1000000, 1152000, 1500000, 2000000,
666 2500000, 3000000, 3500000, 4000000
667};
668
669static __u8 acm_tty_size[] = {
670 5, 6, 7, 8
671};
672
673static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
674{
675 struct acm *acm = tty->driver_data;
676 struct termios *termios = tty->termios;
677 struct usb_cdc_line_coding newline;
678 int newctrl = acm->ctrlout;
679
680 if (!ACM_READY(acm))
681 return;
682
683 newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
684 (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
685 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
686 newline.bParityType = termios->c_cflag & PARENB ?
687 (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
688 newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
689
690 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
691
692 if (!newline.dwDTERate) {
693 newline.dwDTERate = acm->line.dwDTERate;
694 newctrl &= ~ACM_CTRL_DTR;
695 } else newctrl |= ACM_CTRL_DTR;
696
697 if (newctrl != acm->ctrlout)
698 acm_set_control(acm, acm->ctrlout = newctrl);
699
700 if (memcmp(&acm->line, &newline, sizeof newline)) {
701 memcpy(&acm->line, &newline, sizeof newline);
702 dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
703 newline.bCharFormat, newline.bParityType,
704 newline.bDataBits);
705 acm_set_line(acm, &acm->line);
706 }
707}
708
709/*
710 * USB probe and disconnect routines.
711 */
712
Oliver Neukum884b6002005-04-21 21:28:02 +0200713/* Little helper: write buffers free */
714static void acm_write_buffers_free(struct acm *acm)
715{
716 int i;
717 struct acm_wb *wb;
718
719 for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
720 usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
721 }
722}
723
724/* Little helper: write buffers allocate */
725static int acm_write_buffers_alloc(struct acm *acm)
726{
727 int i;
728 struct acm_wb *wb;
729
730 for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
731 wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
732 &wb->dmah);
733 if (!wb->buf) {
734 while (i != 0) {
735 --i;
736 --wb;
737 usb_buffer_free(acm->dev, acm->writesize,
738 wb->buf, wb->dmah);
739 }
740 return -ENOMEM;
741 }
742 }
743 return 0;
744}
745
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746static int acm_probe (struct usb_interface *intf,
747 const struct usb_device_id *id)
748{
749 struct usb_cdc_union_desc *union_header = NULL;
750 char *buffer = intf->altsetting->extra;
751 int buflen = intf->altsetting->extralen;
752 struct usb_interface *control_interface;
753 struct usb_interface *data_interface;
754 struct usb_endpoint_descriptor *epctrl;
755 struct usb_endpoint_descriptor *epread;
756 struct usb_endpoint_descriptor *epwrite;
757 struct usb_device *usb_dev = interface_to_usbdev(intf);
758 struct acm *acm;
759 int minor;
760 int ctrlsize,readsize;
761 u8 *buf;
762 u8 ac_management_function = 0;
763 u8 call_management_function = 0;
764 int call_interface_num = -1;
765 int data_interface_num;
766 unsigned long quirks;
David Kubicek61a87ad2005-11-01 18:51:34 +0100767 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
769 /* handle quirks deadly to normal probing*/
770 quirks = (unsigned long)id->driver_info;
771 if (quirks == NO_UNION_NORMAL) {
772 data_interface = usb_ifnum_to_if(usb_dev, 1);
773 control_interface = usb_ifnum_to_if(usb_dev, 0);
774 goto skip_normal_probe;
775 }
776
777 /* normal probing*/
778 if (!buffer) {
779 err("Wierd descriptor references\n");
780 return -EINVAL;
781 }
782
783 if (!buflen) {
784 if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
785 dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n");
786 buflen = intf->cur_altsetting->endpoint->extralen;
787 buffer = intf->cur_altsetting->endpoint->extra;
788 } else {
789 err("Zero length descriptor references\n");
790 return -EINVAL;
791 }
792 }
793
794 while (buflen > 0) {
795 if (buffer [1] != USB_DT_CS_INTERFACE) {
796 err("skipping garbage\n");
797 goto next_desc;
798 }
799
800 switch (buffer [2]) {
801 case USB_CDC_UNION_TYPE: /* we've found it */
802 if (union_header) {
803 err("More than one union descriptor, skipping ...");
804 goto next_desc;
805 }
806 union_header = (struct usb_cdc_union_desc *)
807 buffer;
808 break;
809 case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */
810 break; /* for now we ignore it */
811 case USB_CDC_HEADER_TYPE: /* maybe check version */
812 break; /* for now we ignore it */
813 case USB_CDC_ACM_TYPE:
814 ac_management_function = buffer[3];
815 break;
816 case USB_CDC_CALL_MANAGEMENT_TYPE:
817 call_management_function = buffer[3];
818 call_interface_num = buffer[4];
819 if ((call_management_function & 3) != 3)
820 err("This device cannot do calls on its own. It is no modem.");
821 break;
822
823 default:
824 err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]);
825 break;
826 }
827next_desc:
828 buflen -= buffer[0];
829 buffer += buffer[0];
830 }
831
832 if (!union_header) {
833 if (call_interface_num > 0) {
834 dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n");
835 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
836 control_interface = intf;
837 } else {
838 dev_dbg(&intf->dev,"No union descriptor, giving up\n");
839 return -ENODEV;
840 }
841 } else {
842 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
843 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
844 if (!control_interface || !data_interface) {
845 dev_dbg(&intf->dev,"no interfaces\n");
846 return -ENODEV;
847 }
848 }
849
850 if (data_interface_num != call_interface_num)
851 dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n");
852
853skip_normal_probe:
854
855 /*workaround for switched interfaces */
856 if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
857 if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
858 struct usb_interface *t;
859 dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
860
861 t = control_interface;
862 control_interface = data_interface;
863 data_interface = t;
864 } else {
865 return -EINVAL;
866 }
867 }
868
869 if (usb_interface_claimed(data_interface)) { /* valid in this context */
870 dev_dbg(&intf->dev,"The data interface isn't available\n");
871 return -EBUSY;
872 }
873
874
875 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
876 return -EINVAL;
877
878 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
879 epread = &data_interface->cur_altsetting->endpoint[0].desc;
880 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
881
882
883 /* workaround for switched endpoints */
884 if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) {
885 /* descriptors are swapped */
886 struct usb_endpoint_descriptor *t;
887 dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
888
889 t = epread;
890 epread = epwrite;
891 epwrite = t;
892 }
893 dbg("interfaces are valid");
894 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
895
896 if (minor == ACM_TTY_MINORS) {
897 err("no more free acm devices");
898 return -ENODEV;
899 }
900
Oliver Neukum46f116e2005-10-24 22:42:35 +0200901 if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
902 dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 goto alloc_fail;
904 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
906 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
David Kubicek61a87ad2005-11-01 18:51:34 +0100907 readsize = le16_to_cpu(epread->wMaxPacketSize)*2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize);
909 acm->control = control_interface;
910 acm->data = data_interface;
911 acm->minor = minor;
912 acm->dev = usb_dev;
913 acm->ctrl_caps = ac_management_function;
914 acm->ctrlsize = ctrlsize;
915 acm->readsize = readsize;
David Kubicek61a87ad2005-11-01 18:51:34 +0100916 acm->urb_task.func = acm_rx_tasklet;
917 acm->urb_task.data = (unsigned long) acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 INIT_WORK(&acm->work, acm_softint, acm);
919 spin_lock_init(&acm->throttle_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +0200920 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100921 spin_lock_init(&acm->read_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +0200922 acm->write_ready = 1;
David Kubicek61a87ad2005-11-01 18:51:34 +0100923 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
925 buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
926 if (!buf) {
927 dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
928 goto alloc_fail2;
929 }
930 acm->ctrl_buffer = buf;
931
Oliver Neukum884b6002005-04-21 21:28:02 +0200932 if (acm_write_buffers_alloc(acm) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
934 goto alloc_fail4;
935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
937 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
938 if (!acm->ctrlurb) {
939 dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
940 goto alloc_fail5;
941 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100942 for (i = 0; i < ACM_NRU; i++) {
943 struct acm_ru *rcv = &(acm->ru[i]);
944
945 if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
946 dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n");
947 goto alloc_fail7;
948 }
949
950 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
951 rcv->instance = acm;
952 }
953 for (i = 0; i < ACM_NRB; i++) {
954 struct acm_rb *buf = &(acm->rb[i]);
955
956 // Using usb_buffer_alloc instead of kmalloc as Oliver suggested
957 if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
958 dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
959 goto alloc_fail7;
960 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 }
962 acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
963 if (!acm->writeurb) {
964 dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n");
965 goto alloc_fail7;
966 }
967
968 usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
969 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
970 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
971 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
972
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
Oliver Neukum884b6002005-04-21 21:28:02 +0200974 NULL, acm->writesize, acm_write_bulk, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
977 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
978
979 acm_set_control(acm, acm->ctrlout);
980
981 acm->line.dwDTERate = cpu_to_le32(9600);
982 acm->line.bDataBits = 8;
983 acm_set_line(acm, &acm->line);
984
985 usb_driver_claim_interface(&acm_driver, data_interface, acm);
986
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700987 usb_get_intf(control_interface);
988 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
990 acm_table[minor] = acm;
991 usb_set_intfdata (intf, acm);
992 return 0;
993
994alloc_fail7:
David Kubicek61a87ad2005-11-01 18:51:34 +0100995 for (i = 0; i < ACM_NRB; i++)
996 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
997 for (i = 0; i < ACM_NRU; i++)
998 usb_free_urb(acm->ru[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 usb_free_urb(acm->ctrlurb);
1000alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001001 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002alloc_fail4:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
1004alloc_fail2:
1005 kfree(acm);
1006alloc_fail:
1007 return -ENOMEM;
1008}
1009
1010static void acm_disconnect(struct usb_interface *intf)
1011{
1012 struct acm *acm = usb_get_intfdata (intf);
1013 struct usb_device *usb_dev = interface_to_usbdev(intf);
David Kubicek61a87ad2005-11-01 18:51:34 +01001014 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 if (!acm || !acm->dev) {
1017 dbg("disconnect on nonexisting interface");
1018 return;
1019 }
1020
1021 down(&open_sem);
1022 acm->dev = NULL;
1023 usb_set_intfdata (intf, NULL);
1024
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
1044 usb_driver_release_interface(&acm_driver, acm->data);
1045
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