blob: 023cf5d45a9dd4a99607fc9f5b497df0b471faba [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>
David Brownella8c28f22006-06-13 09:57:47 -070066#include <linux/usb/cdc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#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 }
Oliver Neukum86478942006-05-13 22:50:47 +0200130 wbn = (wbn + 1) % ACM_NW;
131 if (++i >= ACM_NW)
Oliver Neukum884b6002005-04-21 21:28:02 +0200132 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
Oliver Neukum86478942006-05-13 22:50:47 +0200145 n = ACM_NW;
146 for (i = 0; i < ACM_NW; i++) {
147 n -= acm->wb[i].use;
Oliver Neukum884b6002005-04-21 21:28:02 +0200148 }
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);
Oliver Neukum86478942006-05-13 22:50:47 +0200169 acm->write_current = (wbn + 1) % ACM_NW;
Oliver Neukum884b6002005-04-21 21:28:02 +0200170 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 */
David Howells7d12e782006-10-05 14:55:46 +0100221static void acm_ctrl_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222{
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 */
David Howells7d12e782006-10-05 14:55:46 +0100288static void acm_read_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
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;
Oliver Neukum86478942006-05-13 22:50:47 +0200293 int status = urb->status;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200294 dbg("Entering acm_read_bulk with status %d", urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296 if (!ACM_READY(acm))
297 return;
298
Oliver Neukum86478942006-05-13 22:50:47 +0200299 if (status)
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200300 dev_dbg(&acm->data->dev, "bulk rx status %d", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
David Kubicek61a87ad2005-11-01 18:51:34 +0100302 buf = rcv->buffer;
303 buf->size = urb->actual_length;
304
Oliver Neukum86478942006-05-13 22:50:47 +0200305 if (likely(status == 0)) {
306 spin_lock(&acm->read_lock);
307 list_add_tail(&rcv->list, &acm->spare_read_urbs);
308 list_add_tail(&buf->list, &acm->filled_read_bufs);
309 spin_unlock(&acm->read_lock);
310 } else {
311 /* we drop the buffer due to an error */
312 spin_lock(&acm->read_lock);
313 list_add_tail(&rcv->list, &acm->spare_read_urbs);
314 list_add(&buf->list, &acm->spare_read_bufs);
315 spin_unlock(&acm->read_lock);
316 /* nevertheless the tasklet must be kicked unconditionally
317 so the queue cannot dry up */
318 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100319 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320}
321
322static void acm_rx_tasklet(unsigned long _acm)
323{
324 struct acm *acm = (void *)_acm;
David Kubicek61a87ad2005-11-01 18:51:34 +0100325 struct acm_rb *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 struct tty_struct *tty = acm->tty;
David Kubicek61a87ad2005-11-01 18:51:34 +0100327 struct acm_ru *rcv;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200328 unsigned long flags;
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100329 unsigned char throttled;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 dbg("Entering acm_rx_tasklet");
331
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100332 if (!ACM_READY(acm))
333 return;
334
335 spin_lock(&acm->throttle_lock);
336 throttled = acm->throttle;
337 spin_unlock(&acm->throttle_lock);
338 if (throttled)
David Kubicek61a87ad2005-11-01 18:51:34 +0100339 return;
340
341next_buffer:
Jarek Poplawski762f0072006-10-06 07:23:11 +0200342 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100343 if (list_empty(&acm->filled_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200344 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100345 goto urbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100347 buf = list_entry(acm->filled_read_bufs.next,
348 struct acm_rb, list);
349 list_del(&buf->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200350 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100351
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200352 dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100353
Alan Cox33f0f882006-01-09 20:54:13 -0800354 tty_buffer_request_room(tty, buf->size);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100355 spin_lock(&acm->throttle_lock);
356 throttled = acm->throttle;
357 spin_unlock(&acm->throttle_lock);
358 if (!throttled)
Alan Cox33f0f882006-01-09 20:54:13 -0800359 tty_insert_flip_string(tty, buf->base, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100360 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100362 if (throttled) {
363 dbg("Throttling noticed");
Jarek Poplawski762f0072006-10-06 07:23:11 +0200364 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100365 list_add(&buf->list, &acm->filled_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200366 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 return;
368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Jarek Poplawski762f0072006-10-06 07:23:11 +0200370 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100371 list_add(&buf->list, &acm->spare_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200372 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100373 goto next_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
David Kubicek61a87ad2005-11-01 18:51:34 +0100375urbs:
376 while (!list_empty(&acm->spare_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200377 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100378 if (list_empty(&acm->spare_read_urbs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200379 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100380 return;
381 }
382 rcv = list_entry(acm->spare_read_urbs.next,
383 struct acm_ru, list);
384 list_del(&rcv->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200385 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100386
387 buf = list_entry(acm->spare_read_bufs.next,
388 struct acm_rb, list);
389 list_del(&buf->list);
390
391 rcv->buffer = buf;
392
393 usb_fill_bulk_urb(rcv->urb, acm->dev,
394 acm->rx_endpoint,
395 buf->base,
396 acm->readsize,
397 acm_read_bulk, rcv);
398 rcv->urb->transfer_dma = buf->dma;
399 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
400
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200401 dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf);
David Kubicek61a87ad2005-11-01 18:51:34 +0100402
403 /* This shouldn't kill the driver as unsuccessful URBs are returned to the
404 free-urbs-pool and resubmited ASAP */
405 if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
406 list_add(&buf->list, &acm->spare_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200407 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100408 list_add(&rcv->list, &acm->spare_read_urbs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200409 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100410 return;
411 }
412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413}
414
415/* data interface wrote those outgoing bytes */
David Howells7d12e782006-10-05 14:55:46 +0100416static void acm_write_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417{
418 struct acm *acm = (struct acm *)urb->context;
Oliver Neukum884b6002005-04-21 21:28:02 +0200419
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200420 dbg("Entering acm_write_bulk with status %d", urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Oliver Neukum884b6002005-04-21 21:28:02 +0200422 acm_write_done(acm);
423 acm_write_start(acm);
424 if (ACM_READY(acm))
425 schedule_work(&acm->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426}
427
David Howellsc4028952006-11-22 14:57:56 +0000428static void acm_softint(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429{
David Howellsc4028952006-11-22 14:57:56 +0000430 struct acm *acm = container_of(work, struct acm, work);
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200431 dbg("Entering acm_softint.");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433 if (!ACM_READY(acm))
434 return;
435 tty_wakeup(acm->tty);
436}
437
438/*
439 * TTY handlers
440 */
441
442static int acm_tty_open(struct tty_struct *tty, struct file *filp)
443{
444 struct acm *acm;
445 int rv = -EINVAL;
David Kubicek61a87ad2005-11-01 18:51:34 +0100446 int i;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200447 dbg("Entering acm_tty_open.");
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100448
449 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 acm = acm_table[tty->index];
452 if (!acm || !acm->dev)
453 goto err_out;
454 else
455 rv = 0;
456
457 tty->driver_data = acm;
458 acm->tty = tty;
459
David Kubicek61a87ad2005-11-01 18:51:34 +0100460 /* force low_latency on so that our tty_push actually forces the data through,
461 otherwise it is scheduled, and with high data rates data can get lost. */
462 tty->low_latency = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 if (acm->used++) {
465 goto done;
466 }
467
468 acm->ctrlurb->dev = acm->dev;
469 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
470 dbg("usb_submit_urb(ctrl irq) failed");
471 goto bail_out;
472 }
473
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100474 if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
475 (acm->ctrl_caps & USB_CDC_CAP_LINE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 goto full_bailout;
477
David Kubicek61a87ad2005-11-01 18:51:34 +0100478 INIT_LIST_HEAD(&acm->spare_read_urbs);
479 INIT_LIST_HEAD(&acm->spare_read_bufs);
480 INIT_LIST_HEAD(&acm->filled_read_bufs);
Oliver Neukum86478942006-05-13 22:50:47 +0200481 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100482 list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
483 }
Oliver Neukum86478942006-05-13 22:50:47 +0200484 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100485 list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
486 }
487
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100488 acm->throttle = 0;
489
David Kubicek61a87ad2005-11-01 18:51:34 +0100490 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
492done:
493err_out:
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100494 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 return rv;
496
497full_bailout:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 usb_kill_urb(acm->ctrlurb);
499bail_out:
500 acm->used--;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100501 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 return -EIO;
503}
504
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700505static void acm_tty_unregister(struct acm *acm)
506{
Oliver Neukum86478942006-05-13 22:50:47 +0200507 int i,nr;
David Kubicek61a87ad2005-11-01 18:51:34 +0100508
Oliver Neukum86478942006-05-13 22:50:47 +0200509 nr = acm->rx_buflimit;
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700510 tty_unregister_device(acm_tty_driver, acm->minor);
511 usb_put_intf(acm->control);
512 acm_table[acm->minor] = NULL;
513 usb_free_urb(acm->ctrlurb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700514 usb_free_urb(acm->writeurb);
Oliver Neukum86478942006-05-13 22:50:47 +0200515 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100516 usb_free_urb(acm->ru[i].urb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700517 kfree(acm);
518}
519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520static void acm_tty_close(struct tty_struct *tty, struct file *filp)
521{
522 struct acm *acm = tty->driver_data;
Oliver Neukum86478942006-05-13 22:50:47 +0200523 int i,nr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
525 if (!acm || !acm->used)
526 return;
527
Oliver Neukum86478942006-05-13 22:50:47 +0200528 nr = acm->rx_buflimit;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100529 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 if (!--acm->used) {
531 if (acm->dev) {
532 acm_set_control(acm, acm->ctrlout = 0);
533 usb_kill_urb(acm->ctrlurb);
534 usb_kill_urb(acm->writeurb);
Oliver Neukum86478942006-05-13 22:50:47 +0200535 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100536 usb_kill_urb(acm->ru[i].urb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700537 } else
538 acm_tty_unregister(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 }
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100540 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541}
542
543static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
544{
545 struct acm *acm = tty->driver_data;
546 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200547 unsigned long flags;
548 int wbn;
549 struct acm_wb *wb;
550
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200551 dbg("Entering acm_tty_write to write %d bytes,", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553 if (!ACM_READY(acm))
554 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 if (!count)
556 return 0;
557
Oliver Neukum884b6002005-04-21 21:28:02 +0200558 spin_lock_irqsave(&acm->write_lock, flags);
559 if ((wbn = acm_wb_alloc(acm)) < 0) {
560 spin_unlock_irqrestore(&acm->write_lock, flags);
561 acm_write_start(acm);
562 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200564 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Oliver Neukum884b6002005-04-21 21:28:02 +0200566 count = (count > acm->writesize) ? acm->writesize : count;
567 dbg("Get %d bytes...", count);
568 memcpy(wb->buf, buf, count);
569 wb->len = count;
570 spin_unlock_irqrestore(&acm->write_lock, flags);
571
572 if ((stat = acm_write_start(acm)) < 0)
573 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 return count;
575}
576
577static int acm_tty_write_room(struct tty_struct *tty)
578{
579 struct acm *acm = tty->driver_data;
580 if (!ACM_READY(acm))
581 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200582 /*
583 * Do not let the line discipline to know that we have a reserve,
584 * or it might get too enthusiastic.
585 */
586 return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587}
588
589static int acm_tty_chars_in_buffer(struct tty_struct *tty)
590{
591 struct acm *acm = tty->driver_data;
592 if (!ACM_READY(acm))
593 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200594 /*
595 * This is inaccurate (overcounts), but it works.
596 */
Oliver Neukum86478942006-05-13 22:50:47 +0200597 return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598}
599
600static void acm_tty_throttle(struct tty_struct *tty)
601{
602 struct acm *acm = tty->driver_data;
603 if (!ACM_READY(acm))
604 return;
605 spin_lock_bh(&acm->throttle_lock);
606 acm->throttle = 1;
607 spin_unlock_bh(&acm->throttle_lock);
608}
609
610static void acm_tty_unthrottle(struct tty_struct *tty)
611{
612 struct acm *acm = tty->driver_data;
613 if (!ACM_READY(acm))
614 return;
615 spin_lock_bh(&acm->throttle_lock);
616 acm->throttle = 0;
617 spin_unlock_bh(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100618 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619}
620
621static void acm_tty_break_ctl(struct tty_struct *tty, int state)
622{
623 struct acm *acm = tty->driver_data;
624 if (!ACM_READY(acm))
625 return;
626 if (acm_send_break(acm, state ? 0xffff : 0))
627 dbg("send break failed");
628}
629
630static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file)
631{
632 struct acm *acm = tty->driver_data;
633
634 if (!ACM_READY(acm))
635 return -EINVAL;
636
637 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
638 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
639 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
640 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
641 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
642 TIOCM_CTS;
643}
644
645static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
646 unsigned int set, unsigned int clear)
647{
648 struct acm *acm = tty->driver_data;
649 unsigned int newctrl;
650
651 if (!ACM_READY(acm))
652 return -EINVAL;
653
654 newctrl = acm->ctrlout;
655 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
656 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
657
658 newctrl = (newctrl & ~clear) | set;
659
660 if (acm->ctrlout == newctrl)
661 return 0;
662 return acm_set_control(acm, acm->ctrlout = newctrl);
663}
664
665static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
666{
667 struct acm *acm = tty->driver_data;
668
669 if (!ACM_READY(acm))
670 return -EINVAL;
671
672 return -ENOIOCTLCMD;
673}
674
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100675static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 0, 50, 75, 110, 134, 150, 200, 300, 600,
677 1200, 1800, 2400, 4800, 9600, 19200, 38400,
678 57600, 115200, 230400, 460800, 500000, 576000,
679 921600, 1000000, 1152000, 1500000, 2000000,
680 2500000, 3000000, 3500000, 4000000
681};
682
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100683static const __u8 acm_tty_size[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 5, 6, 7, 8
685};
686
Alan Cox606d0992006-12-08 02:38:45 -0800687static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
689 struct acm *acm = tty->driver_data;
Alan Cox606d0992006-12-08 02:38:45 -0800690 struct ktermios *termios = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 struct usb_cdc_line_coding newline;
692 int newctrl = acm->ctrlout;
693
694 if (!ACM_READY(acm))
695 return;
696
697 newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
698 (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
699 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
700 newline.bParityType = termios->c_cflag & PARENB ?
701 (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
702 newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
703
704 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
705
706 if (!newline.dwDTERate) {
707 newline.dwDTERate = acm->line.dwDTERate;
708 newctrl &= ~ACM_CTRL_DTR;
709 } else newctrl |= ACM_CTRL_DTR;
710
711 if (newctrl != acm->ctrlout)
712 acm_set_control(acm, acm->ctrlout = newctrl);
713
714 if (memcmp(&acm->line, &newline, sizeof newline)) {
715 memcpy(&acm->line, &newline, sizeof newline);
716 dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
717 newline.bCharFormat, newline.bParityType,
718 newline.bDataBits);
719 acm_set_line(acm, &acm->line);
720 }
721}
722
723/*
724 * USB probe and disconnect routines.
725 */
726
Oliver Neukum884b6002005-04-21 21:28:02 +0200727/* Little helper: write buffers free */
728static void acm_write_buffers_free(struct acm *acm)
729{
730 int i;
731 struct acm_wb *wb;
732
Oliver Neukum86478942006-05-13 22:50:47 +0200733 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200734 usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
735 }
736}
737
738/* Little helper: write buffers allocate */
739static int acm_write_buffers_alloc(struct acm *acm)
740{
741 int i;
742 struct acm_wb *wb;
743
Oliver Neukum86478942006-05-13 22:50:47 +0200744 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200745 wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
746 &wb->dmah);
747 if (!wb->buf) {
748 while (i != 0) {
749 --i;
750 --wb;
751 usb_buffer_free(acm->dev, acm->writesize,
752 wb->buf, wb->dmah);
753 }
754 return -ENOMEM;
755 }
756 }
757 return 0;
758}
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760static int acm_probe (struct usb_interface *intf,
761 const struct usb_device_id *id)
762{
763 struct usb_cdc_union_desc *union_header = NULL;
764 char *buffer = intf->altsetting->extra;
765 int buflen = intf->altsetting->extralen;
766 struct usb_interface *control_interface;
767 struct usb_interface *data_interface;
768 struct usb_endpoint_descriptor *epctrl;
769 struct usb_endpoint_descriptor *epread;
770 struct usb_endpoint_descriptor *epwrite;
771 struct usb_device *usb_dev = interface_to_usbdev(intf);
772 struct acm *acm;
773 int minor;
774 int ctrlsize,readsize;
775 u8 *buf;
776 u8 ac_management_function = 0;
777 u8 call_management_function = 0;
778 int call_interface_num = -1;
779 int data_interface_num;
780 unsigned long quirks;
Oliver Neukum86478942006-05-13 22:50:47 +0200781 int num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +0100782 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
Oliver Neukum86478942006-05-13 22:50:47 +0200784 /* normal quirks */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 quirks = (unsigned long)id->driver_info;
Oliver Neukum86478942006-05-13 22:50:47 +0200786 num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
787
788 /* handle quirks deadly to normal probing*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 if (quirks == NO_UNION_NORMAL) {
790 data_interface = usb_ifnum_to_if(usb_dev, 1);
791 control_interface = usb_ifnum_to_if(usb_dev, 0);
792 goto skip_normal_probe;
793 }
794
795 /* normal probing*/
796 if (!buffer) {
797 err("Wierd descriptor references\n");
798 return -EINVAL;
799 }
800
801 if (!buflen) {
802 if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200803 dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 buflen = intf->cur_altsetting->endpoint->extralen;
805 buffer = intf->cur_altsetting->endpoint->extra;
806 } else {
807 err("Zero length descriptor references\n");
808 return -EINVAL;
809 }
810 }
811
812 while (buflen > 0) {
813 if (buffer [1] != USB_DT_CS_INTERFACE) {
814 err("skipping garbage\n");
815 goto next_desc;
816 }
817
818 switch (buffer [2]) {
819 case USB_CDC_UNION_TYPE: /* we've found it */
820 if (union_header) {
821 err("More than one union descriptor, skipping ...");
822 goto next_desc;
823 }
824 union_header = (struct usb_cdc_union_desc *)
825 buffer;
826 break;
827 case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */
828 break; /* for now we ignore it */
829 case USB_CDC_HEADER_TYPE: /* maybe check version */
830 break; /* for now we ignore it */
831 case USB_CDC_ACM_TYPE:
832 ac_management_function = buffer[3];
833 break;
834 case USB_CDC_CALL_MANAGEMENT_TYPE:
835 call_management_function = buffer[3];
836 call_interface_num = buffer[4];
837 if ((call_management_function & 3) != 3)
838 err("This device cannot do calls on its own. It is no modem.");
839 break;
840
841 default:
842 err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]);
843 break;
844 }
845next_desc:
846 buflen -= buffer[0];
847 buffer += buffer[0];
848 }
849
850 if (!union_header) {
851 if (call_interface_num > 0) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200852 dev_dbg(&intf->dev,"No union descriptor, using call management descriptor");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
854 control_interface = intf;
855 } else {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200856 dev_dbg(&intf->dev,"No union descriptor, giving up");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 return -ENODEV;
858 }
859 } else {
860 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
861 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
862 if (!control_interface || !data_interface) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200863 dev_dbg(&intf->dev,"no interfaces");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 return -ENODEV;
865 }
866 }
867
868 if (data_interface_num != call_interface_num)
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200869 dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
871skip_normal_probe:
872
873 /*workaround for switched interfaces */
874 if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
875 if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
876 struct usb_interface *t;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200877 dev_dbg(&intf->dev,"Your device has switched interfaces.");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
879 t = control_interface;
880 control_interface = data_interface;
881 data_interface = t;
882 } else {
883 return -EINVAL;
884 }
885 }
886
887 if (usb_interface_claimed(data_interface)) { /* valid in this context */
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200888 dev_dbg(&intf->dev,"The data interface isn't available");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 return -EBUSY;
890 }
891
892
893 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
894 return -EINVAL;
895
896 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
897 epread = &data_interface->cur_altsetting->endpoint[0].desc;
898 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
899
900
901 /* workaround for switched endpoints */
Luiz Fernando N. Capitulino45aea702006-10-26 13:02:48 -0300902 if (!usb_endpoint_dir_in(epread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 /* descriptors are swapped */
904 struct usb_endpoint_descriptor *t;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200905 dev_dbg(&intf->dev,"The data interface has switched endpoints");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
907 t = epread;
908 epread = epwrite;
909 epwrite = t;
910 }
911 dbg("interfaces are valid");
912 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
913
914 if (minor == ACM_TTY_MINORS) {
915 err("no more free acm devices");
916 return -ENODEV;
917 }
918
Oliver Neukum46f116e2005-10-24 22:42:35 +0200919 if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200920 dev_dbg(&intf->dev, "out of memory (acm kzalloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 goto alloc_fail;
922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
924 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
Oliver Neukum86478942006-05-13 22:50:47 +0200925 readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize);
927 acm->control = control_interface;
928 acm->data = data_interface;
929 acm->minor = minor;
930 acm->dev = usb_dev;
931 acm->ctrl_caps = ac_management_function;
932 acm->ctrlsize = ctrlsize;
933 acm->readsize = readsize;
Oliver Neukum86478942006-05-13 22:50:47 +0200934 acm->rx_buflimit = num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +0100935 acm->urb_task.func = acm_rx_tasklet;
936 acm->urb_task.data = (unsigned long) acm;
David Howellsc4028952006-11-22 14:57:56 +0000937 INIT_WORK(&acm->work, acm_softint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 spin_lock_init(&acm->throttle_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +0200939 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100940 spin_lock_init(&acm->read_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +0200941 acm->write_ready = 1;
David Kubicek61a87ad2005-11-01 18:51:34 +0100942 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
944 buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
945 if (!buf) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200946 dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 goto alloc_fail2;
948 }
949 acm->ctrl_buffer = buf;
950
Oliver Neukum884b6002005-04-21 21:28:02 +0200951 if (acm_write_buffers_alloc(acm) < 0) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200952 dev_dbg(&intf->dev, "out of memory (write buffer alloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 goto alloc_fail4;
954 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
956 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
957 if (!acm->ctrlurb) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200958 dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 goto alloc_fail5;
960 }
Oliver Neukum86478942006-05-13 22:50:47 +0200961 for (i = 0; i < num_rx_buf; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100962 struct acm_ru *rcv = &(acm->ru[i]);
963
964 if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200965 dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)");
David Kubicek61a87ad2005-11-01 18:51:34 +0100966 goto alloc_fail7;
967 }
968
969 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
970 rcv->instance = acm;
971 }
Oliver Neukum86478942006-05-13 22:50:47 +0200972 for (i = 0; i < num_rx_buf; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100973 struct acm_rb *buf = &(acm->rb[i]);
974
David Kubicek61a87ad2005-11-01 18:51:34 +0100975 if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200976 dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)");
David Kubicek61a87ad2005-11-01 18:51:34 +0100977 goto alloc_fail7;
978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 }
980 acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
981 if (!acm->writeurb) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200982 dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 goto alloc_fail7;
984 }
985
986 usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
987 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
988 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
989 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
990
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
Oliver Neukum884b6002005-04-21 21:28:02 +0200992 NULL, acm->writesize, acm_write_bulk, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
995 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
996
997 acm_set_control(acm, acm->ctrlout);
998
999 acm->line.dwDTERate = cpu_to_le32(9600);
1000 acm->line.bDataBits = 8;
1001 acm_set_line(acm, &acm->line);
1002
1003 usb_driver_claim_interface(&acm_driver, data_interface, acm);
1004
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001005 usb_get_intf(control_interface);
1006 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008 acm_table[minor] = acm;
1009 usb_set_intfdata (intf, acm);
1010 return 0;
1011
1012alloc_fail7:
Oliver Neukum86478942006-05-13 22:50:47 +02001013 for (i = 0; i < num_rx_buf; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001014 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
Oliver Neukum86478942006-05-13 22:50:47 +02001015 for (i = 0; i < num_rx_buf; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001016 usb_free_urb(acm->ru[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 usb_free_urb(acm->ctrlurb);
1018alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001019 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020alloc_fail4:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
1022alloc_fail2:
1023 kfree(acm);
1024alloc_fail:
1025 return -ENOMEM;
1026}
1027
1028static void acm_disconnect(struct usb_interface *intf)
1029{
1030 struct acm *acm = usb_get_intfdata (intf);
1031 struct usb_device *usb_dev = interface_to_usbdev(intf);
David Kubicek61a87ad2005-11-01 18:51:34 +01001032 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034 if (!acm || !acm->dev) {
1035 dbg("disconnect on nonexisting interface");
1036 return;
1037 }
1038
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001039 mutex_lock(&open_mutex);
Oliver Neukum86067eea2006-01-08 12:39:13 +01001040 if (!usb_get_intfdata(intf)) {
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001041 mutex_unlock(&open_mutex);
Oliver Neukum86067eea2006-01-08 12:39:13 +01001042 return;
1043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 acm->dev = NULL;
Oliver Neukum86067eea2006-01-08 12:39:13 +01001045 usb_set_intfdata(acm->control, NULL);
1046 usb_set_intfdata(acm->data, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
David Kubicek61a87ad2005-11-01 18:51:34 +01001048 tasklet_disable(&acm->urb_task);
1049
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 usb_kill_urb(acm->ctrlurb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 usb_kill_urb(acm->writeurb);
Oliver Neukum86478942006-05-13 22:50:47 +02001052 for (i = 0; i < acm->rx_buflimit; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001053 usb_kill_urb(acm->ru[i].urb);
1054
1055 INIT_LIST_HEAD(&acm->filled_read_bufs);
1056 INIT_LIST_HEAD(&acm->spare_read_bufs);
1057
1058 tasklet_enable(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060 flush_scheduled_work(); /* wait for acm_softint */
1061
Oliver Neukum884b6002005-04-21 21:28:02 +02001062 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Oliver Neukum86478942006-05-13 22:50:47 +02001064 for (i = 0; i < acm->rx_buflimit; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001065 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
Oliver Neukum86067eea2006-01-08 12:39:13 +01001067 usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
1069 if (!acm->used) {
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001070 acm_tty_unregister(acm);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001071 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 return;
1073 }
1074
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001075 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
1077 if (acm->tty)
1078 tty_hangup(acm->tty);
1079}
1080
1081/*
1082 * USB driver structure.
1083 */
1084
1085static struct usb_device_id acm_ids[] = {
1086 /* quirky and broken devices */
1087 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1088 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1089 },
Masahito Omote8753e652005-07-29 12:17:25 -07001090 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1091 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1092 },
Chris Malley91a9c922006-10-03 10:08:28 +01001093 { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
1094 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1095 },
Oliver Neukum86478942006-05-13 22:50:47 +02001096 { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
1097 .driver_info = SINGLE_RX_URB, /* firmware bug */
1098 },
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001099 { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
1100 .driver_info = SINGLE_RX_URB, /* firmware bug */
1101 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 /* control interfaces with various AT-command sets */
1103 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1104 USB_CDC_ACM_PROTO_AT_V25TER) },
1105 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1106 USB_CDC_ACM_PROTO_AT_PCCA101) },
1107 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1108 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1109 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1110 USB_CDC_ACM_PROTO_AT_GSM) },
1111 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1112 USB_CDC_ACM_PROTO_AT_3G ) },
1113 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1114 USB_CDC_ACM_PROTO_AT_CDMA) },
1115
1116 /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */
1117 { }
1118};
1119
1120MODULE_DEVICE_TABLE (usb, acm_ids);
1121
1122static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 .name = "cdc_acm",
1124 .probe = acm_probe,
1125 .disconnect = acm_disconnect,
1126 .id_table = acm_ids,
1127};
1128
1129/*
1130 * TTY driver structures.
1131 */
1132
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001133static const struct tty_operations acm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 .open = acm_tty_open,
1135 .close = acm_tty_close,
1136 .write = acm_tty_write,
1137 .write_room = acm_tty_write_room,
1138 .ioctl = acm_tty_ioctl,
1139 .throttle = acm_tty_throttle,
1140 .unthrottle = acm_tty_unthrottle,
1141 .chars_in_buffer = acm_tty_chars_in_buffer,
1142 .break_ctl = acm_tty_break_ctl,
1143 .set_termios = acm_tty_set_termios,
1144 .tiocmget = acm_tty_tiocmget,
1145 .tiocmset = acm_tty_tiocmset,
1146};
1147
1148/*
1149 * Init / exit.
1150 */
1151
1152static int __init acm_init(void)
1153{
1154 int retval;
1155 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1156 if (!acm_tty_driver)
1157 return -ENOMEM;
1158 acm_tty_driver->owner = THIS_MODULE,
1159 acm_tty_driver->driver_name = "acm",
1160 acm_tty_driver->name = "ttyACM",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 acm_tty_driver->major = ACM_TTY_MAJOR,
1162 acm_tty_driver->minor_start = 0,
1163 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1164 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001165 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 acm_tty_driver->init_termios = tty_std_termios;
1167 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1168 tty_set_operations(acm_tty_driver, &acm_ops);
1169
1170 retval = tty_register_driver(acm_tty_driver);
1171 if (retval) {
1172 put_tty_driver(acm_tty_driver);
1173 return retval;
1174 }
1175
1176 retval = usb_register(&acm_driver);
1177 if (retval) {
1178 tty_unregister_driver(acm_tty_driver);
1179 put_tty_driver(acm_tty_driver);
1180 return retval;
1181 }
1182
1183 info(DRIVER_VERSION ":" DRIVER_DESC);
1184
1185 return 0;
1186}
1187
1188static void __exit acm_exit(void)
1189{
1190 usb_deregister(&acm_driver);
1191 tty_unregister_driver(acm_tty_driver);
1192 put_tty_driver(acm_tty_driver);
1193}
1194
1195module_init(acm_init);
1196module_exit(acm_exit);
1197
1198MODULE_AUTHOR( DRIVER_AUTHOR );
1199MODULE_DESCRIPTION( DRIVER_DESC );
1200MODULE_LICENSE("GPL");
1201