blob: fe940e0536e03488016d1171da3866ce8bb6dd00 [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>
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010062#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#include <asm/uaccess.h>
64#include <linux/usb.h>
David Brownella8c28f22006-06-13 09:57:47 -070065#include <linux/usb/cdc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#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
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010083static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
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 }
Oliver Neukum86478942006-05-13 22:50:47 +0200129 wbn = (wbn + 1) % ACM_NW;
130 if (++i >= ACM_NW)
Oliver Neukum884b6002005-04-21 21:28:02 +0200131 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
Oliver Neukum86478942006-05-13 22:50:47 +0200144 n = ACM_NW;
145 for (i = 0; i < ACM_NW; i++) {
146 n -= acm->wb[i].use;
Oliver Neukum884b6002005-04-21 21:28:02 +0200147 }
148 return n;
149}
150
151static inline int acm_wb_is_used(struct acm *acm, int wbn)
152{
153 return acm->wb[wbn].use;
154}
155
156/*
157 * Finish write.
158 */
159static void acm_write_done(struct acm *acm)
160{
161 unsigned long flags;
162 int wbn;
163
164 spin_lock_irqsave(&acm->write_lock, flags);
165 acm->write_ready = 1;
166 wbn = acm->write_current;
167 acm_wb_free(acm, wbn);
Oliver Neukum86478942006-05-13 22:50:47 +0200168 acm->write_current = (wbn + 1) % ACM_NW;
Oliver Neukum884b6002005-04-21 21:28:02 +0200169 spin_unlock_irqrestore(&acm->write_lock, flags);
170}
171
172/*
173 * Poke write.
174 */
175static int acm_write_start(struct acm *acm)
176{
177 unsigned long flags;
178 int wbn;
179 struct acm_wb *wb;
180 int rc;
181
182 spin_lock_irqsave(&acm->write_lock, flags);
183 if (!acm->dev) {
184 spin_unlock_irqrestore(&acm->write_lock, flags);
185 return -ENODEV;
186 }
187
188 if (!acm->write_ready) {
189 spin_unlock_irqrestore(&acm->write_lock, flags);
190 return 0; /* A white lie */
191 }
192
193 wbn = acm->write_current;
194 if (!acm_wb_is_used(acm, wbn)) {
195 spin_unlock_irqrestore(&acm->write_lock, flags);
196 return 0;
197 }
198 wb = &acm->wb[wbn];
199
200 acm->write_ready = 0;
201 spin_unlock_irqrestore(&acm->write_lock, flags);
202
203 acm->writeurb->transfer_buffer = wb->buf;
204 acm->writeurb->transfer_dma = wb->dmah;
205 acm->writeurb->transfer_buffer_length = wb->len;
206 acm->writeurb->dev = acm->dev;
207
208 if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) {
209 dbg("usb_submit_urb(write bulk) failed: %d", rc);
210 acm_write_done(acm);
211 }
212 return rc;
213}
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100214/*
215 * attributes exported through sysfs
216 */
217static ssize_t show_caps
218(struct device *dev, struct device_attribute *attr, char *buf)
219{
220 struct usb_interface *intf = to_usb_interface(dev);
221 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum884b6002005-04-21 21:28:02 +0200222
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100223 return sprintf(buf, "%d", acm->ctrl_caps);
224}
225static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
226
227static ssize_t show_country_codes
228(struct device *dev, struct device_attribute *attr, char *buf)
229{
230 struct usb_interface *intf = to_usb_interface(dev);
231 struct acm *acm = usb_get_intfdata(intf);
232
233 memcpy(buf, acm->country_codes, acm->country_code_size);
234 return acm->country_code_size;
235}
236
237static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
238
239static ssize_t show_country_rel_date
240(struct device *dev, struct device_attribute *attr, char *buf)
241{
242 struct usb_interface *intf = to_usb_interface(dev);
243 struct acm *acm = usb_get_intfdata(intf);
244
245 return sprintf(buf, "%d", acm->country_rel_date);
246}
247
248static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
Oliver Neukum884b6002005-04-21 21:28:02 +0200249/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 * Interrupt handlers for various ACM device responses
251 */
252
253/* control interface reports status changes with "interrupt" transfers */
David Howells7d12e782006-10-05 14:55:46 +0100254static void acm_ctrl_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
256 struct acm *acm = urb->context;
257 struct usb_cdc_notification *dr = urb->transfer_buffer;
258 unsigned char *data;
259 int newctrl;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700260 int retval;
261 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700263 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 case 0:
265 /* success */
266 break;
267 case -ECONNRESET:
268 case -ENOENT:
269 case -ESHUTDOWN:
270 /* this urb is terminated, clean up */
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700271 dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 return;
273 default:
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700274 dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 goto exit;
276 }
277
278 if (!ACM_READY(acm))
279 goto exit;
280
281 data = (unsigned char *)(dr + 1);
282 switch (dr->bNotificationType) {
283
284 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
285
286 dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
287 break;
288
289 case USB_CDC_NOTIFY_SERIAL_STATE:
290
291 newctrl = le16_to_cpu(get_unaligned((__le16 *) data));
292
293 if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
294 dbg("calling hangup");
295 tty_hangup(acm->tty);
296 }
297
298 acm->ctrlin = newctrl;
299
300 dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
301 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
302 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
303 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
304 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
305
306 break;
307
308 default:
309 dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
310 dr->bNotificationType, dr->wIndex,
311 dr->wLength, data[0], data[1]);
312 break;
313 }
314exit:
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700315 retval = usb_submit_urb (urb, GFP_ATOMIC);
316 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 err ("%s - usb_submit_urb failed with result %d",
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700318 __FUNCTION__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319}
320
321/* data interface returns incoming bytes, or we got unthrottled */
David Howells7d12e782006-10-05 14:55:46 +0100322static void acm_read_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323{
David Kubicek61a87ad2005-11-01 18:51:34 +0100324 struct acm_rb *buf;
325 struct acm_ru *rcv = urb->context;
326 struct acm *acm = rcv->instance;
Oliver Neukum86478942006-05-13 22:50:47 +0200327 int status = urb->status;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700328
329 dbg("Entering acm_read_bulk with status %d", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 if (!ACM_READY(acm))
332 return;
333
Oliver Neukum86478942006-05-13 22:50:47 +0200334 if (status)
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200335 dev_dbg(&acm->data->dev, "bulk rx status %d", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
David Kubicek61a87ad2005-11-01 18:51:34 +0100337 buf = rcv->buffer;
338 buf->size = urb->actual_length;
339
Oliver Neukum86478942006-05-13 22:50:47 +0200340 if (likely(status == 0)) {
341 spin_lock(&acm->read_lock);
342 list_add_tail(&rcv->list, &acm->spare_read_urbs);
343 list_add_tail(&buf->list, &acm->filled_read_bufs);
344 spin_unlock(&acm->read_lock);
345 } else {
346 /* we drop the buffer due to an error */
347 spin_lock(&acm->read_lock);
348 list_add_tail(&rcv->list, &acm->spare_read_urbs);
349 list_add(&buf->list, &acm->spare_read_bufs);
350 spin_unlock(&acm->read_lock);
351 /* nevertheless the tasklet must be kicked unconditionally
352 so the queue cannot dry up */
353 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100354 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355}
356
357static void acm_rx_tasklet(unsigned long _acm)
358{
359 struct acm *acm = (void *)_acm;
David Kubicek61a87ad2005-11-01 18:51:34 +0100360 struct acm_rb *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 struct tty_struct *tty = acm->tty;
David Kubicek61a87ad2005-11-01 18:51:34 +0100362 struct acm_ru *rcv;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200363 unsigned long flags;
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100364 unsigned char throttled;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 dbg("Entering acm_rx_tasklet");
366
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100367 if (!ACM_READY(acm))
368 return;
369
Oliver Neukum834dbca2007-03-06 10:47:04 +0100370 spin_lock_irqsave(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100371 throttled = acm->throttle;
Oliver Neukum834dbca2007-03-06 10:47:04 +0100372 spin_unlock_irqrestore(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100373 if (throttled)
David Kubicek61a87ad2005-11-01 18:51:34 +0100374 return;
375
376next_buffer:
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->filled_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200379 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100380 goto urbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100382 buf = list_entry(acm->filled_read_bufs.next,
383 struct acm_rb, list);
384 list_del(&buf->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200385 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100386
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200387 dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100388
Alan Cox33f0f882006-01-09 20:54:13 -0800389 tty_buffer_request_room(tty, buf->size);
Oliver Neukum834dbca2007-03-06 10:47:04 +0100390 spin_lock_irqsave(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100391 throttled = acm->throttle;
Oliver Neukum834dbca2007-03-06 10:47:04 +0100392 spin_unlock_irqrestore(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100393 if (!throttled)
Alan Cox33f0f882006-01-09 20:54:13 -0800394 tty_insert_flip_string(tty, buf->base, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100395 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100397 if (throttled) {
398 dbg("Throttling noticed");
Jarek Poplawski762f0072006-10-06 07:23:11 +0200399 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100400 list_add(&buf->list, &acm->filled_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200401 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 return;
403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
Jarek Poplawski762f0072006-10-06 07:23:11 +0200405 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100406 list_add(&buf->list, &acm->spare_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200407 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100408 goto next_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
David Kubicek61a87ad2005-11-01 18:51:34 +0100410urbs:
411 while (!list_empty(&acm->spare_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200412 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100413 if (list_empty(&acm->spare_read_urbs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200414 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100415 return;
416 }
417 rcv = list_entry(acm->spare_read_urbs.next,
418 struct acm_ru, list);
419 list_del(&rcv->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200420 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100421
422 buf = list_entry(acm->spare_read_bufs.next,
423 struct acm_rb, list);
424 list_del(&buf->list);
425
426 rcv->buffer = buf;
427
428 usb_fill_bulk_urb(rcv->urb, acm->dev,
429 acm->rx_endpoint,
430 buf->base,
431 acm->readsize,
432 acm_read_bulk, rcv);
433 rcv->urb->transfer_dma = buf->dma;
434 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
435
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200436 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 +0100437
438 /* This shouldn't kill the driver as unsuccessful URBs are returned to the
439 free-urbs-pool and resubmited ASAP */
440 if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
441 list_add(&buf->list, &acm->spare_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200442 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100443 list_add(&rcv->list, &acm->spare_read_urbs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200444 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100445 return;
446 }
447 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448}
449
450/* data interface wrote those outgoing bytes */
David Howells7d12e782006-10-05 14:55:46 +0100451static void acm_write_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
453 struct acm *acm = (struct acm *)urb->context;
Oliver Neukum884b6002005-04-21 21:28:02 +0200454
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200455 dbg("Entering acm_write_bulk with status %d", urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
Oliver Neukum884b6002005-04-21 21:28:02 +0200457 acm_write_done(acm);
458 acm_write_start(acm);
459 if (ACM_READY(acm))
460 schedule_work(&acm->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461}
462
David Howellsc4028952006-11-22 14:57:56 +0000463static void acm_softint(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464{
David Howellsc4028952006-11-22 14:57:56 +0000465 struct acm *acm = container_of(work, struct acm, work);
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200466 dbg("Entering acm_softint.");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
468 if (!ACM_READY(acm))
469 return;
470 tty_wakeup(acm->tty);
471}
472
473/*
474 * TTY handlers
475 */
476
477static int acm_tty_open(struct tty_struct *tty, struct file *filp)
478{
479 struct acm *acm;
480 int rv = -EINVAL;
David Kubicek61a87ad2005-11-01 18:51:34 +0100481 int i;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200482 dbg("Entering acm_tty_open.");
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100483
484 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486 acm = acm_table[tty->index];
487 if (!acm || !acm->dev)
488 goto err_out;
489 else
490 rv = 0;
491
492 tty->driver_data = acm;
493 acm->tty = tty;
494
David Kubicek61a87ad2005-11-01 18:51:34 +0100495 /* force low_latency on so that our tty_push actually forces the data through,
496 otherwise it is scheduled, and with high data rates data can get lost. */
497 tty->low_latency = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 if (acm->used++) {
500 goto done;
501 }
502
503 acm->ctrlurb->dev = acm->dev;
504 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
505 dbg("usb_submit_urb(ctrl irq) failed");
506 goto bail_out;
507 }
508
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100509 if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
510 (acm->ctrl_caps & USB_CDC_CAP_LINE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 goto full_bailout;
512
David Kubicek61a87ad2005-11-01 18:51:34 +0100513 INIT_LIST_HEAD(&acm->spare_read_urbs);
514 INIT_LIST_HEAD(&acm->spare_read_bufs);
515 INIT_LIST_HEAD(&acm->filled_read_bufs);
Oliver Neukum86478942006-05-13 22:50:47 +0200516 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100517 list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
518 }
Oliver Neukum86478942006-05-13 22:50:47 +0200519 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100520 list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
521 }
522
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100523 acm->throttle = 0;
524
David Kubicek61a87ad2005-11-01 18:51:34 +0100525 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527done:
528err_out:
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100529 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 return rv;
531
532full_bailout:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 usb_kill_urb(acm->ctrlurb);
534bail_out:
535 acm->used--;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100536 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 return -EIO;
538}
539
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700540static void acm_tty_unregister(struct acm *acm)
541{
Oliver Neukum86478942006-05-13 22:50:47 +0200542 int i,nr;
David Kubicek61a87ad2005-11-01 18:51:34 +0100543
Oliver Neukum86478942006-05-13 22:50:47 +0200544 nr = acm->rx_buflimit;
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700545 tty_unregister_device(acm_tty_driver, acm->minor);
546 usb_put_intf(acm->control);
547 acm_table[acm->minor] = NULL;
548 usb_free_urb(acm->ctrlurb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700549 usb_free_urb(acm->writeurb);
Oliver Neukum86478942006-05-13 22:50:47 +0200550 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100551 usb_free_urb(acm->ru[i].urb);
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100552 kfree(acm->country_codes);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700553 kfree(acm);
554}
555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556static void acm_tty_close(struct tty_struct *tty, struct file *filp)
557{
558 struct acm *acm = tty->driver_data;
Oliver Neukum86478942006-05-13 22:50:47 +0200559 int i,nr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
561 if (!acm || !acm->used)
562 return;
563
Oliver Neukum86478942006-05-13 22:50:47 +0200564 nr = acm->rx_buflimit;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100565 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 if (!--acm->used) {
567 if (acm->dev) {
568 acm_set_control(acm, acm->ctrlout = 0);
569 usb_kill_urb(acm->ctrlurb);
570 usb_kill_urb(acm->writeurb);
Oliver Neukum86478942006-05-13 22:50:47 +0200571 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100572 usb_kill_urb(acm->ru[i].urb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700573 } else
574 acm_tty_unregister(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 }
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100576 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577}
578
579static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
580{
581 struct acm *acm = tty->driver_data;
582 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200583 unsigned long flags;
584 int wbn;
585 struct acm_wb *wb;
586
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200587 dbg("Entering acm_tty_write to write %d bytes,", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589 if (!ACM_READY(acm))
590 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 if (!count)
592 return 0;
593
Oliver Neukum884b6002005-04-21 21:28:02 +0200594 spin_lock_irqsave(&acm->write_lock, flags);
595 if ((wbn = acm_wb_alloc(acm)) < 0) {
596 spin_unlock_irqrestore(&acm->write_lock, flags);
597 acm_write_start(acm);
598 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200600 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Oliver Neukum884b6002005-04-21 21:28:02 +0200602 count = (count > acm->writesize) ? acm->writesize : count;
603 dbg("Get %d bytes...", count);
604 memcpy(wb->buf, buf, count);
605 wb->len = count;
606 spin_unlock_irqrestore(&acm->write_lock, flags);
607
608 if ((stat = acm_write_start(acm)) < 0)
609 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 return count;
611}
612
613static int acm_tty_write_room(struct tty_struct *tty)
614{
615 struct acm *acm = tty->driver_data;
616 if (!ACM_READY(acm))
617 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200618 /*
619 * Do not let the line discipline to know that we have a reserve,
620 * or it might get too enthusiastic.
621 */
622 return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623}
624
625static int acm_tty_chars_in_buffer(struct tty_struct *tty)
626{
627 struct acm *acm = tty->driver_data;
628 if (!ACM_READY(acm))
629 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200630 /*
631 * This is inaccurate (overcounts), but it works.
632 */
Oliver Neukum86478942006-05-13 22:50:47 +0200633 return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634}
635
636static void acm_tty_throttle(struct tty_struct *tty)
637{
638 struct acm *acm = tty->driver_data;
639 if (!ACM_READY(acm))
640 return;
641 spin_lock_bh(&acm->throttle_lock);
642 acm->throttle = 1;
643 spin_unlock_bh(&acm->throttle_lock);
644}
645
646static void acm_tty_unthrottle(struct tty_struct *tty)
647{
648 struct acm *acm = tty->driver_data;
649 if (!ACM_READY(acm))
650 return;
651 spin_lock_bh(&acm->throttle_lock);
652 acm->throttle = 0;
653 spin_unlock_bh(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100654 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655}
656
657static void acm_tty_break_ctl(struct tty_struct *tty, int state)
658{
659 struct acm *acm = tty->driver_data;
660 if (!ACM_READY(acm))
661 return;
662 if (acm_send_break(acm, state ? 0xffff : 0))
663 dbg("send break failed");
664}
665
666static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file)
667{
668 struct acm *acm = tty->driver_data;
669
670 if (!ACM_READY(acm))
671 return -EINVAL;
672
673 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
674 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
675 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
676 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
677 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
678 TIOCM_CTS;
679}
680
681static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
682 unsigned int set, unsigned int clear)
683{
684 struct acm *acm = tty->driver_data;
685 unsigned int newctrl;
686
687 if (!ACM_READY(acm))
688 return -EINVAL;
689
690 newctrl = acm->ctrlout;
691 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
692 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
693
694 newctrl = (newctrl & ~clear) | set;
695
696 if (acm->ctrlout == newctrl)
697 return 0;
698 return acm_set_control(acm, acm->ctrlout = newctrl);
699}
700
701static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
702{
703 struct acm *acm = tty->driver_data;
704
705 if (!ACM_READY(acm))
706 return -EINVAL;
707
708 return -ENOIOCTLCMD;
709}
710
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100711static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 0, 50, 75, 110, 134, 150, 200, 300, 600,
713 1200, 1800, 2400, 4800, 9600, 19200, 38400,
714 57600, 115200, 230400, 460800, 500000, 576000,
715 921600, 1000000, 1152000, 1500000, 2000000,
716 2500000, 3000000, 3500000, 4000000
717};
718
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100719static const __u8 acm_tty_size[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 5, 6, 7, 8
721};
722
Alan Cox606d0992006-12-08 02:38:45 -0800723static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724{
725 struct acm *acm = tty->driver_data;
Alan Cox606d0992006-12-08 02:38:45 -0800726 struct ktermios *termios = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 struct usb_cdc_line_coding newline;
728 int newctrl = acm->ctrlout;
729
730 if (!ACM_READY(acm))
731 return;
732
733 newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
734 (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
735 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
736 newline.bParityType = termios->c_cflag & PARENB ?
737 (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
738 newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
739
740 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
741
742 if (!newline.dwDTERate) {
743 newline.dwDTERate = acm->line.dwDTERate;
744 newctrl &= ~ACM_CTRL_DTR;
745 } else newctrl |= ACM_CTRL_DTR;
746
747 if (newctrl != acm->ctrlout)
748 acm_set_control(acm, acm->ctrlout = newctrl);
749
750 if (memcmp(&acm->line, &newline, sizeof newline)) {
751 memcpy(&acm->line, &newline, sizeof newline);
752 dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
753 newline.bCharFormat, newline.bParityType,
754 newline.bDataBits);
755 acm_set_line(acm, &acm->line);
756 }
757}
758
759/*
760 * USB probe and disconnect routines.
761 */
762
Oliver Neukum884b6002005-04-21 21:28:02 +0200763/* Little helper: write buffers free */
764static void acm_write_buffers_free(struct acm *acm)
765{
766 int i;
767 struct acm_wb *wb;
768
Oliver Neukum86478942006-05-13 22:50:47 +0200769 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200770 usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
771 }
772}
773
774/* Little helper: write buffers allocate */
775static int acm_write_buffers_alloc(struct acm *acm)
776{
777 int i;
778 struct acm_wb *wb;
779
Oliver Neukum86478942006-05-13 22:50:47 +0200780 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200781 wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
782 &wb->dmah);
783 if (!wb->buf) {
784 while (i != 0) {
785 --i;
786 --wb;
787 usb_buffer_free(acm->dev, acm->writesize,
788 wb->buf, wb->dmah);
789 }
790 return -ENOMEM;
791 }
792 }
793 return 0;
794}
795
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796static int acm_probe (struct usb_interface *intf,
797 const struct usb_device_id *id)
798{
799 struct usb_cdc_union_desc *union_header = NULL;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100800 struct usb_cdc_country_functional_desc *cfd = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 char *buffer = intf->altsetting->extra;
802 int buflen = intf->altsetting->extralen;
803 struct usb_interface *control_interface;
804 struct usb_interface *data_interface;
805 struct usb_endpoint_descriptor *epctrl;
806 struct usb_endpoint_descriptor *epread;
807 struct usb_endpoint_descriptor *epwrite;
808 struct usb_device *usb_dev = interface_to_usbdev(intf);
809 struct acm *acm;
810 int minor;
811 int ctrlsize,readsize;
812 u8 *buf;
813 u8 ac_management_function = 0;
814 u8 call_management_function = 0;
815 int call_interface_num = -1;
816 int data_interface_num;
817 unsigned long quirks;
Oliver Neukum86478942006-05-13 22:50:47 +0200818 int num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +0100819 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Oliver Neukum86478942006-05-13 22:50:47 +0200821 /* normal quirks */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 quirks = (unsigned long)id->driver_info;
Oliver Neukum86478942006-05-13 22:50:47 +0200823 num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
824
825 /* handle quirks deadly to normal probing*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (quirks == NO_UNION_NORMAL) {
827 data_interface = usb_ifnum_to_if(usb_dev, 1);
828 control_interface = usb_ifnum_to_if(usb_dev, 0);
829 goto skip_normal_probe;
830 }
831
832 /* normal probing*/
833 if (!buffer) {
834 err("Wierd descriptor references\n");
835 return -EINVAL;
836 }
837
838 if (!buflen) {
839 if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200840 dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 buflen = intf->cur_altsetting->endpoint->extralen;
842 buffer = intf->cur_altsetting->endpoint->extra;
843 } else {
844 err("Zero length descriptor references\n");
845 return -EINVAL;
846 }
847 }
848
849 while (buflen > 0) {
850 if (buffer [1] != USB_DT_CS_INTERFACE) {
851 err("skipping garbage\n");
852 goto next_desc;
853 }
854
855 switch (buffer [2]) {
856 case USB_CDC_UNION_TYPE: /* we've found it */
857 if (union_header) {
858 err("More than one union descriptor, skipping ...");
859 goto next_desc;
860 }
861 union_header = (struct usb_cdc_union_desc *)
862 buffer;
863 break;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100864 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
865 cfd = (struct usb_cdc_country_functional_desc *)buffer;
866 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 case USB_CDC_HEADER_TYPE: /* maybe check version */
868 break; /* for now we ignore it */
869 case USB_CDC_ACM_TYPE:
870 ac_management_function = buffer[3];
871 break;
872 case USB_CDC_CALL_MANAGEMENT_TYPE:
873 call_management_function = buffer[3];
874 call_interface_num = buffer[4];
875 if ((call_management_function & 3) != 3)
876 err("This device cannot do calls on its own. It is no modem.");
877 break;
878
879 default:
880 err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]);
881 break;
882 }
883next_desc:
884 buflen -= buffer[0];
885 buffer += buffer[0];
886 }
887
888 if (!union_header) {
889 if (call_interface_num > 0) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200890 dev_dbg(&intf->dev,"No union descriptor, using call management descriptor");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
892 control_interface = intf;
893 } else {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200894 dev_dbg(&intf->dev,"No union descriptor, giving up");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 return -ENODEV;
896 }
897 } else {
898 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
899 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
900 if (!control_interface || !data_interface) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200901 dev_dbg(&intf->dev,"no interfaces");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 return -ENODEV;
903 }
904 }
905
906 if (data_interface_num != call_interface_num)
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200907 dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
909skip_normal_probe:
910
911 /*workaround for switched interfaces */
912 if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
913 if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
914 struct usb_interface *t;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200915 dev_dbg(&intf->dev,"Your device has switched interfaces.");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
917 t = control_interface;
918 control_interface = data_interface;
919 data_interface = t;
920 } else {
921 return -EINVAL;
922 }
923 }
924
925 if (usb_interface_claimed(data_interface)) { /* valid in this context */
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200926 dev_dbg(&intf->dev,"The data interface isn't available");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 return -EBUSY;
928 }
929
930
931 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
932 return -EINVAL;
933
934 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
935 epread = &data_interface->cur_altsetting->endpoint[0].desc;
936 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
937
938
939 /* workaround for switched endpoints */
Luiz Fernando N. Capitulino45aea702006-10-26 13:02:48 -0300940 if (!usb_endpoint_dir_in(epread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 /* descriptors are swapped */
942 struct usb_endpoint_descriptor *t;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200943 dev_dbg(&intf->dev,"The data interface has switched endpoints");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
945 t = epread;
946 epread = epwrite;
947 epwrite = t;
948 }
949 dbg("interfaces are valid");
950 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
951
952 if (minor == ACM_TTY_MINORS) {
953 err("no more free acm devices");
954 return -ENODEV;
955 }
956
Oliver Neukum46f116e2005-10-24 22:42:35 +0200957 if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200958 dev_dbg(&intf->dev, "out of memory (acm kzalloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 goto alloc_fail;
960 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
962 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
Oliver Neukum86478942006-05-13 22:50:47 +0200963 readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize);
965 acm->control = control_interface;
966 acm->data = data_interface;
967 acm->minor = minor;
968 acm->dev = usb_dev;
969 acm->ctrl_caps = ac_management_function;
970 acm->ctrlsize = ctrlsize;
971 acm->readsize = readsize;
Oliver Neukum86478942006-05-13 22:50:47 +0200972 acm->rx_buflimit = num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +0100973 acm->urb_task.func = acm_rx_tasklet;
974 acm->urb_task.data = (unsigned long) acm;
David Howellsc4028952006-11-22 14:57:56 +0000975 INIT_WORK(&acm->work, acm_softint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 spin_lock_init(&acm->throttle_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +0200977 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100978 spin_lock_init(&acm->read_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +0200979 acm->write_ready = 1;
David Kubicek61a87ad2005-11-01 18:51:34 +0100980 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982 buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
983 if (!buf) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200984 dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 goto alloc_fail2;
986 }
987 acm->ctrl_buffer = buf;
988
Oliver Neukum884b6002005-04-21 21:28:02 +0200989 if (acm_write_buffers_alloc(acm) < 0) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200990 dev_dbg(&intf->dev, "out of memory (write buffer alloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 goto alloc_fail4;
992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
994 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
995 if (!acm->ctrlurb) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200996 dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 goto alloc_fail5;
998 }
Oliver Neukum86478942006-05-13 22:50:47 +0200999 for (i = 0; i < num_rx_buf; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +01001000 struct acm_ru *rcv = &(acm->ru[i]);
1001
1002 if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001003 dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)");
David Kubicek61a87ad2005-11-01 18:51:34 +01001004 goto alloc_fail7;
1005 }
1006
1007 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1008 rcv->instance = acm;
1009 }
Oliver Neukum86478942006-05-13 22:50:47 +02001010 for (i = 0; i < num_rx_buf; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +01001011 struct acm_rb *buf = &(acm->rb[i]);
1012
David Kubicek61a87ad2005-11-01 18:51:34 +01001013 if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001014 dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)");
David Kubicek61a87ad2005-11-01 18:51:34 +01001015 goto alloc_fail7;
1016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 }
1018 acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
1019 if (!acm->writeurb) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001020 dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 goto alloc_fail7;
1022 }
1023
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001024 usb_set_intfdata (intf, acm);
1025
1026 i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
1027 if (i < 0)
1028 goto alloc_fail8;
1029
1030 if (cfd) { /* export the country data */
1031 acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
1032 if (!acm->country_codes)
1033 goto skip_countries;
1034 acm->country_code_size = cfd->bLength - 4;
1035 memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4);
1036 acm->country_rel_date = cfd->iCountryCodeRelDate;
1037
1038 i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
1039 if (i < 0) {
1040 kfree(acm->country_codes);
1041 goto skip_countries;
1042 }
1043
1044 i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
1045 if (i < 0) {
1046 kfree(acm->country_codes);
1047 goto skip_countries;
1048 }
1049 }
1050
1051skip_countries:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
1053 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
1054 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1055 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
1056
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
Oliver Neukum884b6002005-04-21 21:28:02 +02001058 NULL, acm->writesize, acm_write_bulk, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
1061 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
1062
1063 acm_set_control(acm, acm->ctrlout);
1064
1065 acm->line.dwDTERate = cpu_to_le32(9600);
1066 acm->line.bDataBits = 8;
1067 acm_set_line(acm, &acm->line);
1068
1069 usb_driver_claim_interface(&acm_driver, data_interface, acm);
1070
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001071 usb_get_intf(control_interface);
1072 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
1074 acm_table[minor] = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001076 return 0;
1077alloc_fail8:
1078 usb_free_urb(acm->writeurb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079alloc_fail7:
Oliver Neukum86478942006-05-13 22:50:47 +02001080 for (i = 0; i < num_rx_buf; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001081 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
Oliver Neukum86478942006-05-13 22:50:47 +02001082 for (i = 0; i < num_rx_buf; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001083 usb_free_urb(acm->ru[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 usb_free_urb(acm->ctrlurb);
1085alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001086 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087alloc_fail4:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
1089alloc_fail2:
1090 kfree(acm);
1091alloc_fail:
1092 return -ENOMEM;
1093}
1094
1095static void acm_disconnect(struct usb_interface *intf)
1096{
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001097 struct acm *acm = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 struct usb_device *usb_dev = interface_to_usbdev(intf);
David Kubicek61a87ad2005-11-01 18:51:34 +01001099 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101 if (!acm || !acm->dev) {
1102 dbg("disconnect on nonexisting interface");
1103 return;
1104 }
1105
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001106 mutex_lock(&open_mutex);
Oliver Neukum86067eea2006-01-08 12:39:13 +01001107 if (!usb_get_intfdata(intf)) {
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001108 mutex_unlock(&open_mutex);
Oliver Neukum86067eea2006-01-08 12:39:13 +01001109 return;
1110 }
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001111 if (acm->country_codes){
1112 device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
1113 device_remove_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
1114 }
1115 device_remove_file(&intf->dev, &dev_attr_bmCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 acm->dev = NULL;
Oliver Neukum86067eea2006-01-08 12:39:13 +01001117 usb_set_intfdata(acm->control, NULL);
1118 usb_set_intfdata(acm->data, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
David Kubicek61a87ad2005-11-01 18:51:34 +01001120 tasklet_disable(&acm->urb_task);
1121
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 usb_kill_urb(acm->ctrlurb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 usb_kill_urb(acm->writeurb);
Oliver Neukum86478942006-05-13 22:50:47 +02001124 for (i = 0; i < acm->rx_buflimit; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001125 usb_kill_urb(acm->ru[i].urb);
1126
1127 INIT_LIST_HEAD(&acm->filled_read_bufs);
1128 INIT_LIST_HEAD(&acm->spare_read_bufs);
1129
1130 tasklet_enable(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
1132 flush_scheduled_work(); /* wait for acm_softint */
1133
Oliver Neukum884b6002005-04-21 21:28:02 +02001134 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Oliver Neukum86478942006-05-13 22:50:47 +02001136 for (i = 0; i < acm->rx_buflimit; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001137 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138
Oliver Neukum86067eea2006-01-08 12:39:13 +01001139 usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
1141 if (!acm->used) {
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001142 acm_tty_unregister(acm);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001143 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 return;
1145 }
1146
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001147 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
1149 if (acm->tty)
1150 tty_hangup(acm->tty);
1151}
1152
1153/*
1154 * USB driver structure.
1155 */
1156
1157static struct usb_device_id acm_ids[] = {
1158 /* quirky and broken devices */
1159 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1160 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1161 },
Andrey Arapovb0e2a702007-07-04 17:11:42 +02001162 { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
1163 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1164 },
Masahito Omote8753e652005-07-29 12:17:25 -07001165 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1166 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1167 },
Chris Malley91a9c922006-10-03 10:08:28 +01001168 { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
1169 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1170 },
Oliver Neukum86478942006-05-13 22:50:47 +02001171 { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
1172 .driver_info = SINGLE_RX_URB, /* firmware bug */
1173 },
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001174 { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
1175 .driver_info = SINGLE_RX_URB, /* firmware bug */
1176 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001177 { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
1178 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1179 },
1180
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 /* control interfaces with various AT-command sets */
1182 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1183 USB_CDC_ACM_PROTO_AT_V25TER) },
1184 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1185 USB_CDC_ACM_PROTO_AT_PCCA101) },
1186 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1187 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1188 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1189 USB_CDC_ACM_PROTO_AT_GSM) },
1190 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1191 USB_CDC_ACM_PROTO_AT_3G ) },
1192 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1193 USB_CDC_ACM_PROTO_AT_CDMA) },
1194
1195 /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */
1196 { }
1197};
1198
1199MODULE_DEVICE_TABLE (usb, acm_ids);
1200
1201static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 .name = "cdc_acm",
1203 .probe = acm_probe,
1204 .disconnect = acm_disconnect,
1205 .id_table = acm_ids,
1206};
1207
1208/*
1209 * TTY driver structures.
1210 */
1211
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001212static const struct tty_operations acm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 .open = acm_tty_open,
1214 .close = acm_tty_close,
1215 .write = acm_tty_write,
1216 .write_room = acm_tty_write_room,
1217 .ioctl = acm_tty_ioctl,
1218 .throttle = acm_tty_throttle,
1219 .unthrottle = acm_tty_unthrottle,
1220 .chars_in_buffer = acm_tty_chars_in_buffer,
1221 .break_ctl = acm_tty_break_ctl,
1222 .set_termios = acm_tty_set_termios,
1223 .tiocmget = acm_tty_tiocmget,
1224 .tiocmset = acm_tty_tiocmset,
1225};
1226
1227/*
1228 * Init / exit.
1229 */
1230
1231static int __init acm_init(void)
1232{
1233 int retval;
1234 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1235 if (!acm_tty_driver)
1236 return -ENOMEM;
1237 acm_tty_driver->owner = THIS_MODULE,
1238 acm_tty_driver->driver_name = "acm",
1239 acm_tty_driver->name = "ttyACM",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 acm_tty_driver->major = ACM_TTY_MAJOR,
1241 acm_tty_driver->minor_start = 0,
1242 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1243 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001244 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 acm_tty_driver->init_termios = tty_std_termios;
1246 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1247 tty_set_operations(acm_tty_driver, &acm_ops);
1248
1249 retval = tty_register_driver(acm_tty_driver);
1250 if (retval) {
1251 put_tty_driver(acm_tty_driver);
1252 return retval;
1253 }
1254
1255 retval = usb_register(&acm_driver);
1256 if (retval) {
1257 tty_unregister_driver(acm_tty_driver);
1258 put_tty_driver(acm_tty_driver);
1259 return retval;
1260 }
1261
1262 info(DRIVER_VERSION ":" DRIVER_DESC);
1263
1264 return 0;
1265}
1266
1267static void __exit acm_exit(void)
1268{
1269 usb_deregister(&acm_driver);
1270 tty_unregister_driver(acm_tty_driver);
1271 put_tty_driver(acm_tty_driver);
1272}
1273
1274module_init(acm_init);
1275module_exit(acm_exit);
1276
1277MODULE_AUTHOR( DRIVER_AUTHOR );
1278MODULE_DESCRIPTION( DRIVER_DESC );
1279MODULE_LICENSE("GPL");
1280