blob: a9dd28f446d8f1fad580eda15ff2c75dc49afc75 [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
David Engrafe4cf3aa2008-03-20 10:01:34 +010034 * v0.26 - multiple write urbs, writesize increased
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 */
36
37/*
38 * This program is free software; you can redistribute it and/or modify
39 * it under the terms of the GNU General Public License as published by
40 * the Free Software Foundation; either version 2 of the License, or
41 * (at your option) any later version.
42 *
43 * This program is distributed in the hope that it will be useful,
44 * but WITHOUT ANY WARRANTY; without even the implied warranty of
45 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46 * GNU General Public License for more details.
47 *
48 * You should have received a copy of the GNU General Public License
49 * along with this program; if not, write to the Free Software
50 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
51 */
52
53#undef DEBUG
54
55#include <linux/kernel.h>
56#include <linux/errno.h>
57#include <linux/init.h>
58#include <linux/slab.h>
59#include <linux/tty.h>
60#include <linux/tty_driver.h>
61#include <linux/tty_flip.h>
62#include <linux/module.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 Engrafe4cf3aa2008-03-20 10:01:34 +010076#define DRIVER_VERSION "v0.26"
David Kubicek61a87ad2005-11-01 18:51:34 +010077#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
David Engrafe4cf3aa2008-03-20 10:01:34 +0100122 wbn = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200123 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
Oliver Neukum884b6002005-04-21 21:28:02 +0200136static int acm_wb_is_avail(struct acm *acm)
137{
138 int i, n;
139
Oliver Neukum86478942006-05-13 22:50:47 +0200140 n = ACM_NW;
141 for (i = 0; i < ACM_NW; i++) {
142 n -= acm->wb[i].use;
Oliver Neukum884b6002005-04-21 21:28:02 +0200143 }
144 return n;
145}
146
Oliver Neukum884b6002005-04-21 21:28:02 +0200147/*
148 * Finish write.
149 */
David Engrafe4cf3aa2008-03-20 10:01:34 +0100150static void acm_write_done(struct acm *acm, struct acm_wb *wb)
Oliver Neukum884b6002005-04-21 21:28:02 +0200151{
152 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200153
154 spin_lock_irqsave(&acm->write_lock, flags);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100155 wb->use = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200156 acm->transmitting--;
Oliver Neukum884b6002005-04-21 21:28:02 +0200157 spin_unlock_irqrestore(&acm->write_lock, flags);
158}
159
160/*
161 * Poke write.
Oliver Neukum11ea8592008-06-20 11:25:57 +0200162 *
163 * the caller is responsible for locking
Oliver Neukum884b6002005-04-21 21:28:02 +0200164 */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200165
166static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
167{
168 int rc;
169
170 acm->transmitting++;
171
172 wb->urb->transfer_buffer = wb->buf;
173 wb->urb->transfer_dma = wb->dmah;
174 wb->urb->transfer_buffer_length = wb->len;
175 wb->urb->dev = acm->dev;
176
177 if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) {
178 dbg("usb_submit_urb(write bulk) failed: %d", rc);
179 acm_write_done(acm, wb);
180 }
181 return rc;
182}
183
David Engrafe4cf3aa2008-03-20 10:01:34 +0100184static int acm_write_start(struct acm *acm, int wbn)
Oliver Neukum884b6002005-04-21 21:28:02 +0200185{
186 unsigned long flags;
David Brownell934da462008-08-06 18:44:12 -0700187 struct acm_wb *wb = &acm->wb[wbn];
Oliver Neukum884b6002005-04-21 21:28:02 +0200188 int rc;
189
190 spin_lock_irqsave(&acm->write_lock, flags);
191 if (!acm->dev) {
David Brownell934da462008-08-06 18:44:12 -0700192 wb->use = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200193 spin_unlock_irqrestore(&acm->write_lock, flags);
194 return -ENODEV;
195 }
196
Oliver Neukum11ea8592008-06-20 11:25:57 +0200197 dbg("%s susp_count: %d", __func__, acm->susp_count);
198 if (acm->susp_count) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200199 acm->delayed_wb = wb;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200200 schedule_work(&acm->waker);
201 spin_unlock_irqrestore(&acm->write_lock, flags);
202 return 0; /* A white lie */
203 }
204 usb_mark_last_busy(acm->dev);
205
Oliver Neukum11ea8592008-06-20 11:25:57 +0200206 rc = acm_start_wb(acm, wb);
Oliver Neukum884b6002005-04-21 21:28:02 +0200207 spin_unlock_irqrestore(&acm->write_lock, flags);
208
Oliver Neukum884b6002005-04-21 21:28:02 +0200209 return rc;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200210
Oliver Neukum884b6002005-04-21 21:28:02 +0200211}
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100212/*
213 * attributes exported through sysfs
214 */
215static ssize_t show_caps
216(struct device *dev, struct device_attribute *attr, char *buf)
217{
218 struct usb_interface *intf = to_usb_interface(dev);
219 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum884b6002005-04-21 21:28:02 +0200220
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100221 return sprintf(buf, "%d", acm->ctrl_caps);
222}
223static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
224
225static ssize_t show_country_codes
226(struct device *dev, struct device_attribute *attr, char *buf)
227{
228 struct usb_interface *intf = to_usb_interface(dev);
229 struct acm *acm = usb_get_intfdata(intf);
230
231 memcpy(buf, acm->country_codes, acm->country_code_size);
232 return acm->country_code_size;
233}
234
235static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
236
237static ssize_t show_country_rel_date
238(struct device *dev, struct device_attribute *attr, char *buf)
239{
240 struct usb_interface *intf = to_usb_interface(dev);
241 struct acm *acm = usb_get_intfdata(intf);
242
243 return sprintf(buf, "%d", acm->country_rel_date);
244}
245
246static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
Oliver Neukum884b6002005-04-21 21:28:02 +0200247/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 * Interrupt handlers for various ACM device responses
249 */
250
251/* control interface reports status changes with "interrupt" transfers */
David Howells7d12e782006-10-05 14:55:46 +0100252static void acm_ctrl_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253{
254 struct acm *acm = urb->context;
255 struct usb_cdc_notification *dr = urb->transfer_buffer;
256 unsigned char *data;
257 int newctrl;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700258 int retval;
259 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700261 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 case 0:
263 /* success */
264 break;
265 case -ECONNRESET:
266 case -ENOENT:
267 case -ESHUTDOWN:
268 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800269 dbg("%s - urb shutting down with status: %d", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 return;
271 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800272 dbg("%s - nonzero urb status received: %d", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 goto exit;
274 }
275
276 if (!ACM_READY(acm))
277 goto exit;
278
279 data = (unsigned char *)(dr + 1);
280 switch (dr->bNotificationType) {
281
282 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
283
284 dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
285 break;
286
287 case USB_CDC_NOTIFY_SERIAL_STATE:
288
Harvey Harrisona5abdea2008-04-29 01:03:40 -0700289 newctrl = get_unaligned_le16(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291 if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
292 dbg("calling hangup");
293 tty_hangup(acm->tty);
294 }
295
296 acm->ctrlin = newctrl;
297
298 dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
299 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
300 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
301 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
302 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
303
304 break;
305
306 default:
307 dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
308 dr->bNotificationType, dr->wIndex,
309 dr->wLength, data[0], data[1]);
310 break;
311 }
312exit:
Oliver Neukum11ea8592008-06-20 11:25:57 +0200313 usb_mark_last_busy(acm->dev);
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700314 retval = usb_submit_urb (urb, GFP_ATOMIC);
315 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 err ("%s - usb_submit_urb failed with result %d",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800317 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318}
319
320/* data interface returns incoming bytes, or we got unthrottled */
David Howells7d12e782006-10-05 14:55:46 +0100321static void acm_read_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
David Kubicek61a87ad2005-11-01 18:51:34 +0100323 struct acm_rb *buf;
324 struct acm_ru *rcv = urb->context;
325 struct acm *acm = rcv->instance;
Oliver Neukum86478942006-05-13 22:50:47 +0200326 int status = urb->status;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700327
328 dbg("Entering acm_read_bulk with status %d", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Oliver Neukum11ea8592008-06-20 11:25:57 +0200330 if (!ACM_READY(acm)) {
331 dev_dbg(&acm->data->dev, "Aborting, acm not ready");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200333 }
334 usb_mark_last_busy(acm->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Oliver Neukum86478942006-05-13 22:50:47 +0200336 if (status)
Joe Perches898eb712007-10-18 03:06:30 -0700337 dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
David Kubicek61a87ad2005-11-01 18:51:34 +0100339 buf = rcv->buffer;
340 buf->size = urb->actual_length;
341
Oliver Neukum86478942006-05-13 22:50:47 +0200342 if (likely(status == 0)) {
343 spin_lock(&acm->read_lock);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200344 acm->processing++;
Oliver Neukum86478942006-05-13 22:50:47 +0200345 list_add_tail(&rcv->list, &acm->spare_read_urbs);
346 list_add_tail(&buf->list, &acm->filled_read_bufs);
347 spin_unlock(&acm->read_lock);
348 } else {
349 /* we drop the buffer due to an error */
350 spin_lock(&acm->read_lock);
351 list_add_tail(&rcv->list, &acm->spare_read_urbs);
352 list_add(&buf->list, &acm->spare_read_bufs);
353 spin_unlock(&acm->read_lock);
354 /* nevertheless the tasklet must be kicked unconditionally
355 so the queue cannot dry up */
356 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200357 if (likely(!acm->susp_count))
358 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359}
360
361static void acm_rx_tasklet(unsigned long _acm)
362{
363 struct acm *acm = (void *)_acm;
David Kubicek61a87ad2005-11-01 18:51:34 +0100364 struct acm_rb *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 struct tty_struct *tty = acm->tty;
David Kubicek61a87ad2005-11-01 18:51:34 +0100366 struct acm_ru *rcv;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200367 unsigned long flags;
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100368 unsigned char throttled;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 dbg("Entering acm_rx_tasklet");
371
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100372 if (!ACM_READY(acm))
Oliver Neukum11ea8592008-06-20 11:25:57 +0200373 {
374 dbg("acm_rx_tasklet: ACM not ready");
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100375 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200376 }
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100377
Oliver Neukum834dbca2007-03-06 10:47:04 +0100378 spin_lock_irqsave(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100379 throttled = acm->throttle;
Oliver Neukum834dbca2007-03-06 10:47:04 +0100380 spin_unlock_irqrestore(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100381 if (throttled)
Oliver Neukum11ea8592008-06-20 11:25:57 +0200382 {
383 dbg("acm_rx_tasklet: throttled");
David Kubicek61a87ad2005-11-01 18:51:34 +0100384 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200385 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100386
387next_buffer:
Jarek Poplawski762f0072006-10-06 07:23:11 +0200388 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100389 if (list_empty(&acm->filled_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200390 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100391 goto urbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100393 buf = list_entry(acm->filled_read_bufs.next,
394 struct acm_rb, list);
395 list_del(&buf->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200396 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100397
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200398 dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100399
Alan Cox33f0f882006-01-09 20:54:13 -0800400 tty_buffer_request_room(tty, buf->size);
Oliver Neukum834dbca2007-03-06 10:47:04 +0100401 spin_lock_irqsave(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100402 throttled = acm->throttle;
Oliver Neukum834dbca2007-03-06 10:47:04 +0100403 spin_unlock_irqrestore(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100404 if (!throttled)
Alan Cox33f0f882006-01-09 20:54:13 -0800405 tty_insert_flip_string(tty, buf->base, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100406 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100408 if (throttled) {
409 dbg("Throttling noticed");
Jarek Poplawski762f0072006-10-06 07:23:11 +0200410 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100411 list_add(&buf->list, &acm->filled_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200412 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 return;
414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
Jarek Poplawski762f0072006-10-06 07:23:11 +0200416 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100417 list_add(&buf->list, &acm->spare_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200418 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100419 goto next_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
David Kubicek61a87ad2005-11-01 18:51:34 +0100421urbs:
422 while (!list_empty(&acm->spare_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200423 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100424 if (list_empty(&acm->spare_read_urbs)) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200425 acm->processing = 0;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200426 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100427 return;
428 }
429 rcv = list_entry(acm->spare_read_urbs.next,
430 struct acm_ru, list);
431 list_del(&rcv->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200432 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100433
434 buf = list_entry(acm->spare_read_bufs.next,
435 struct acm_rb, list);
436 list_del(&buf->list);
437
438 rcv->buffer = buf;
439
440 usb_fill_bulk_urb(rcv->urb, acm->dev,
441 acm->rx_endpoint,
442 buf->base,
443 acm->readsize,
444 acm_read_bulk, rcv);
445 rcv->urb->transfer_dma = buf->dma;
446 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
447
David Kubicek61a87ad2005-11-01 18:51:34 +0100448 /* This shouldn't kill the driver as unsuccessful URBs are returned to the
449 free-urbs-pool and resubmited ASAP */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200450 spin_lock_irqsave(&acm->read_lock, flags);
451 if (acm->susp_count || usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100452 list_add(&buf->list, &acm->spare_read_bufs);
David Kubicek61a87ad2005-11-01 18:51:34 +0100453 list_add(&rcv->list, &acm->spare_read_urbs);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200454 acm->processing = 0;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200455 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100456 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200457 } else {
458 spin_unlock_irqrestore(&acm->read_lock, flags);
459 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 +0100460 }
461 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200462 spin_lock_irqsave(&acm->read_lock, flags);
463 acm->processing = 0;
464 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465}
466
467/* data interface wrote those outgoing bytes */
David Howells7d12e782006-10-05 14:55:46 +0100468static void acm_write_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469{
David Engrafe4cf3aa2008-03-20 10:01:34 +0100470 struct acm *acm;
Ming Leicdc97792008-02-24 18:41:47 +0800471 struct acm_wb *wb = urb->context;
Oliver Neukum884b6002005-04-21 21:28:02 +0200472
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200473 dbg("Entering acm_write_bulk with status %d", urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
David Engrafe4cf3aa2008-03-20 10:01:34 +0100475 acm = wb->instance;
476 acm_write_done(acm, wb);
Oliver Neukum884b6002005-04-21 21:28:02 +0200477 if (ACM_READY(acm))
478 schedule_work(&acm->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479}
480
David Howellsc4028952006-11-22 14:57:56 +0000481static void acm_softint(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
David Howellsc4028952006-11-22 14:57:56 +0000483 struct acm *acm = container_of(work, struct acm, work);
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200484 dbg("Entering acm_softint.");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486 if (!ACM_READY(acm))
487 return;
488 tty_wakeup(acm->tty);
489}
490
Oliver Neukum11ea8592008-06-20 11:25:57 +0200491static void acm_waker(struct work_struct *waker)
492{
493 struct acm *acm = container_of(waker, struct acm, waker);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200494 int rv;
495
496 rv = usb_autopm_get_interface(acm->control);
497 if (rv < 0) {
498 err("Autopm failure in %s", __func__);
499 return;
500 }
501 if (acm->delayed_wb) {
502 acm_start_wb(acm, acm->delayed_wb);
503 acm->delayed_wb = NULL;
504 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200505 usb_autopm_put_interface(acm->control);
506}
507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508/*
509 * TTY handlers
510 */
511
512static int acm_tty_open(struct tty_struct *tty, struct file *filp)
513{
514 struct acm *acm;
515 int rv = -EINVAL;
David Kubicek61a87ad2005-11-01 18:51:34 +0100516 int i;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200517 dbg("Entering acm_tty_open.");
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100518
519 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
521 acm = acm_table[tty->index];
522 if (!acm || !acm->dev)
523 goto err_out;
524 else
525 rv = 0;
526
David Engraf28d1dfa2008-03-20 10:53:52 +0100527 set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 tty->driver_data = acm;
529 acm->tty = tty;
530
David Kubicek61a87ad2005-11-01 18:51:34 +0100531 /* force low_latency on so that our tty_push actually forces the data through,
532 otherwise it is scheduled, and with high data rates data can get lost. */
533 tty->low_latency = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Oliver Neukum94409cc2008-02-11 15:22:29 +0100535 if (usb_autopm_get_interface(acm->control) < 0)
536 goto early_bail;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200537 else
538 acm->control->needs_remote_wakeup = 1;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200539
540 mutex_lock(&acm->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 if (acm->used++) {
Oliver Neukum1365baf2007-10-12 17:24:28 +0200542 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 goto done;
544 }
545
Oliver Neukum1365baf2007-10-12 17:24:28 +0200546
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 acm->ctrlurb->dev = acm->dev;
548 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
549 dbg("usb_submit_urb(ctrl irq) failed");
550 goto bail_out;
551 }
552
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100553 if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
554 (acm->ctrl_caps & USB_CDC_CAP_LINE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 goto full_bailout;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200556 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
David Kubicek61a87ad2005-11-01 18:51:34 +0100558 INIT_LIST_HEAD(&acm->spare_read_urbs);
559 INIT_LIST_HEAD(&acm->spare_read_bufs);
560 INIT_LIST_HEAD(&acm->filled_read_bufs);
Oliver Neukum86478942006-05-13 22:50:47 +0200561 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100562 list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
563 }
Oliver Neukum86478942006-05-13 22:50:47 +0200564 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100565 list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
566 }
567
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100568 acm->throttle = 0;
569
David Kubicek61a87ad2005-11-01 18:51:34 +0100570 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
572done:
573err_out:
Oliver Neukum1365baf2007-10-12 17:24:28 +0200574 mutex_unlock(&acm->mutex);
Oliver Neukum94409cc2008-02-11 15:22:29 +0100575 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 return rv;
577
578full_bailout:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 usb_kill_urb(acm->ctrlurb);
580bail_out:
Oliver Neukum1365baf2007-10-12 17:24:28 +0200581 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 acm->used--;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200583 mutex_unlock(&acm->mutex);
Oliver Neukum94409cc2008-02-11 15:22:29 +0100584early_bail:
585 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 return -EIO;
587}
588
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700589static void acm_tty_unregister(struct acm *acm)
590{
Oliver Neukum86478942006-05-13 22:50:47 +0200591 int i,nr;
David Kubicek61a87ad2005-11-01 18:51:34 +0100592
Oliver Neukum86478942006-05-13 22:50:47 +0200593 nr = acm->rx_buflimit;
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700594 tty_unregister_device(acm_tty_driver, acm->minor);
595 usb_put_intf(acm->control);
596 acm_table[acm->minor] = NULL;
597 usb_free_urb(acm->ctrlurb);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100598 for (i = 0; i < ACM_NW; i++)
599 usb_free_urb(acm->wb[i].urb);
Oliver Neukum86478942006-05-13 22:50:47 +0200600 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100601 usb_free_urb(acm->ru[i].urb);
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100602 kfree(acm->country_codes);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700603 kfree(acm);
604}
605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606static void acm_tty_close(struct tty_struct *tty, struct file *filp)
607{
608 struct acm *acm = tty->driver_data;
Oliver Neukum86478942006-05-13 22:50:47 +0200609 int i,nr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
611 if (!acm || !acm->used)
612 return;
613
Oliver Neukum86478942006-05-13 22:50:47 +0200614 nr = acm->rx_buflimit;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100615 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 if (!--acm->used) {
617 if (acm->dev) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200618 usb_autopm_get_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 acm_set_control(acm, acm->ctrlout = 0);
620 usb_kill_urb(acm->ctrlurb);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100621 for (i = 0; i < ACM_NW; i++)
622 usb_kill_urb(acm->wb[i].urb);
Oliver Neukum86478942006-05-13 22:50:47 +0200623 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100624 usb_kill_urb(acm->ru[i].urb);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200625 acm->control->needs_remote_wakeup = 0;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200626 usb_autopm_put_interface(acm->control);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700627 } else
628 acm_tty_unregister(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100630 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632
633static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
634{
635 struct acm *acm = tty->driver_data;
636 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200637 unsigned long flags;
638 int wbn;
639 struct acm_wb *wb;
640
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200641 dbg("Entering acm_tty_write to write %d bytes,", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
643 if (!ACM_READY(acm))
644 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 if (!count)
646 return 0;
647
Oliver Neukum884b6002005-04-21 21:28:02 +0200648 spin_lock_irqsave(&acm->write_lock, flags);
649 if ((wbn = acm_wb_alloc(acm)) < 0) {
650 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200651 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200653 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Oliver Neukum884b6002005-04-21 21:28:02 +0200655 count = (count > acm->writesize) ? acm->writesize : count;
656 dbg("Get %d bytes...", count);
657 memcpy(wb->buf, buf, count);
658 wb->len = count;
659 spin_unlock_irqrestore(&acm->write_lock, flags);
660
David Engrafe4cf3aa2008-03-20 10:01:34 +0100661 if ((stat = acm_write_start(acm, wbn)) < 0)
Oliver Neukum884b6002005-04-21 21:28:02 +0200662 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 return count;
664}
665
666static int acm_tty_write_room(struct tty_struct *tty)
667{
668 struct acm *acm = tty->driver_data;
669 if (!ACM_READY(acm))
670 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200671 /*
672 * Do not let the line discipline to know that we have a reserve,
673 * or it might get too enthusiastic.
674 */
David Brownell934da462008-08-06 18:44:12 -0700675 return acm_wb_is_avail(acm) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676}
677
678static int acm_tty_chars_in_buffer(struct tty_struct *tty)
679{
680 struct acm *acm = tty->driver_data;
681 if (!ACM_READY(acm))
682 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200683 /*
684 * This is inaccurate (overcounts), but it works.
685 */
Oliver Neukum86478942006-05-13 22:50:47 +0200686 return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687}
688
689static void acm_tty_throttle(struct tty_struct *tty)
690{
691 struct acm *acm = tty->driver_data;
692 if (!ACM_READY(acm))
693 return;
694 spin_lock_bh(&acm->throttle_lock);
695 acm->throttle = 1;
696 spin_unlock_bh(&acm->throttle_lock);
697}
698
699static void acm_tty_unthrottle(struct tty_struct *tty)
700{
701 struct acm *acm = tty->driver_data;
702 if (!ACM_READY(acm))
703 return;
704 spin_lock_bh(&acm->throttle_lock);
705 acm->throttle = 0;
706 spin_unlock_bh(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100707 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708}
709
Alan Cox9e989662008-07-22 11:18:03 +0100710static int acm_tty_break_ctl(struct tty_struct *tty, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{
712 struct acm *acm = tty->driver_data;
Alan Cox9e989662008-07-22 11:18:03 +0100713 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 if (!ACM_READY(acm))
Alan Cox9e989662008-07-22 11:18:03 +0100715 return -EINVAL;
716 retval = acm_send_break(acm, state ? 0xffff : 0);
717 if (retval < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 dbg("send break failed");
Alan Cox9e989662008-07-22 11:18:03 +0100719 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720}
721
722static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file)
723{
724 struct acm *acm = tty->driver_data;
725
726 if (!ACM_READY(acm))
727 return -EINVAL;
728
729 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
730 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
731 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
732 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
733 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
734 TIOCM_CTS;
735}
736
737static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
738 unsigned int set, unsigned int clear)
739{
740 struct acm *acm = tty->driver_data;
741 unsigned int newctrl;
742
743 if (!ACM_READY(acm))
744 return -EINVAL;
745
746 newctrl = acm->ctrlout;
747 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
748 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
749
750 newctrl = (newctrl & ~clear) | set;
751
752 if (acm->ctrlout == newctrl)
753 return 0;
754 return acm_set_control(acm, acm->ctrlout = newctrl);
755}
756
757static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
758{
759 struct acm *acm = tty->driver_data;
760
761 if (!ACM_READY(acm))
762 return -EINVAL;
763
764 return -ENOIOCTLCMD;
765}
766
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100767static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 0, 50, 75, 110, 134, 150, 200, 300, 600,
769 1200, 1800, 2400, 4800, 9600, 19200, 38400,
770 57600, 115200, 230400, 460800, 500000, 576000,
771 921600, 1000000, 1152000, 1500000, 2000000,
772 2500000, 3000000, 3500000, 4000000
773};
774
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100775static const __u8 acm_tty_size[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 5, 6, 7, 8
777};
778
Alan Cox606d0992006-12-08 02:38:45 -0800779static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
781 struct acm *acm = tty->driver_data;
Alan Cox606d0992006-12-08 02:38:45 -0800782 struct ktermios *termios = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 struct usb_cdc_line_coding newline;
784 int newctrl = acm->ctrlout;
785
786 if (!ACM_READY(acm))
787 return;
788
789 newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
790 (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
791 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
792 newline.bParityType = termios->c_cflag & PARENB ?
793 (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
794 newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
795
796 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
797
798 if (!newline.dwDTERate) {
799 newline.dwDTERate = acm->line.dwDTERate;
800 newctrl &= ~ACM_CTRL_DTR;
801 } else newctrl |= ACM_CTRL_DTR;
802
803 if (newctrl != acm->ctrlout)
804 acm_set_control(acm, acm->ctrlout = newctrl);
805
806 if (memcmp(&acm->line, &newline, sizeof newline)) {
807 memcpy(&acm->line, &newline, sizeof newline);
808 dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
809 newline.bCharFormat, newline.bParityType,
810 newline.bDataBits);
811 acm_set_line(acm, &acm->line);
812 }
813}
814
815/*
816 * USB probe and disconnect routines.
817 */
818
Oliver Neukum830f4022008-06-25 14:17:16 +0200819/* Little helpers: write/read buffers free */
Oliver Neukum884b6002005-04-21 21:28:02 +0200820static void acm_write_buffers_free(struct acm *acm)
821{
822 int i;
823 struct acm_wb *wb;
824
Oliver Neukum86478942006-05-13 22:50:47 +0200825 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200826 usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
827 }
828}
829
Oliver Neukum830f4022008-06-25 14:17:16 +0200830static void acm_read_buffers_free(struct acm *acm)
831{
832 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
833 int i, n = acm->rx_buflimit;
834
835 for (i = 0; i < n; i++)
836 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
837}
838
Oliver Neukum884b6002005-04-21 21:28:02 +0200839/* Little helper: write buffers allocate */
840static int acm_write_buffers_alloc(struct acm *acm)
841{
842 int i;
843 struct acm_wb *wb;
844
Oliver Neukum86478942006-05-13 22:50:47 +0200845 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200846 wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
847 &wb->dmah);
848 if (!wb->buf) {
849 while (i != 0) {
850 --i;
851 --wb;
852 usb_buffer_free(acm->dev, acm->writesize,
853 wb->buf, wb->dmah);
854 }
855 return -ENOMEM;
856 }
857 }
858 return 0;
859}
860
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861static int acm_probe (struct usb_interface *intf,
862 const struct usb_device_id *id)
863{
864 struct usb_cdc_union_desc *union_header = NULL;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100865 struct usb_cdc_country_functional_desc *cfd = NULL;
David Brownellc6dbf552008-04-13 14:00:44 -0700866 unsigned char *buffer = intf->altsetting->extra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 int buflen = intf->altsetting->extralen;
868 struct usb_interface *control_interface;
869 struct usb_interface *data_interface;
870 struct usb_endpoint_descriptor *epctrl;
871 struct usb_endpoint_descriptor *epread;
872 struct usb_endpoint_descriptor *epwrite;
873 struct usb_device *usb_dev = interface_to_usbdev(intf);
874 struct acm *acm;
875 int minor;
876 int ctrlsize,readsize;
877 u8 *buf;
878 u8 ac_management_function = 0;
879 u8 call_management_function = 0;
880 int call_interface_num = -1;
881 int data_interface_num;
882 unsigned long quirks;
Oliver Neukum86478942006-05-13 22:50:47 +0200883 int num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +0100884 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
Oliver Neukum86478942006-05-13 22:50:47 +0200886 /* normal quirks */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 quirks = (unsigned long)id->driver_info;
Oliver Neukum86478942006-05-13 22:50:47 +0200888 num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
889
890 /* handle quirks deadly to normal probing*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 if (quirks == NO_UNION_NORMAL) {
892 data_interface = usb_ifnum_to_if(usb_dev, 1);
893 control_interface = usb_ifnum_to_if(usb_dev, 0);
894 goto skip_normal_probe;
895 }
896
897 /* normal probing*/
898 if (!buffer) {
Joe Perches898eb712007-10-18 03:06:30 -0700899 err("Weird descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 return -EINVAL;
901 }
902
903 if (!buflen) {
904 if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
Joe Perches898eb712007-10-18 03:06:30 -0700905 dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 buflen = intf->cur_altsetting->endpoint->extralen;
907 buffer = intf->cur_altsetting->endpoint->extra;
908 } else {
909 err("Zero length descriptor references\n");
910 return -EINVAL;
911 }
912 }
913
914 while (buflen > 0) {
915 if (buffer [1] != USB_DT_CS_INTERFACE) {
916 err("skipping garbage\n");
917 goto next_desc;
918 }
919
920 switch (buffer [2]) {
921 case USB_CDC_UNION_TYPE: /* we've found it */
922 if (union_header) {
923 err("More than one union descriptor, skipping ...");
924 goto next_desc;
925 }
926 union_header = (struct usb_cdc_union_desc *)
927 buffer;
928 break;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100929 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
930 cfd = (struct usb_cdc_country_functional_desc *)buffer;
931 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 case USB_CDC_HEADER_TYPE: /* maybe check version */
933 break; /* for now we ignore it */
934 case USB_CDC_ACM_TYPE:
935 ac_management_function = buffer[3];
936 break;
937 case USB_CDC_CALL_MANAGEMENT_TYPE:
938 call_management_function = buffer[3];
939 call_interface_num = buffer[4];
940 if ((call_management_function & 3) != 3)
941 err("This device cannot do calls on its own. It is no modem.");
942 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 default:
David Brownellc6dbf552008-04-13 14:00:44 -0700944 /* there are LOTS more CDC descriptors that
945 * could legitimately be found here.
946 */
947 dev_dbg(&intf->dev, "Ignoring descriptor: "
948 "type %02x, length %d\n",
949 buffer[2], buffer[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 break;
951 }
952next_desc:
953 buflen -= buffer[0];
954 buffer += buffer[0];
955 }
956
957 if (!union_header) {
958 if (call_interface_num > 0) {
Joe Perches898eb712007-10-18 03:06:30 -0700959 dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
961 control_interface = intf;
962 } else {
Joe Perches898eb712007-10-18 03:06:30 -0700963 dev_dbg(&intf->dev,"No union descriptor, giving up\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return -ENODEV;
965 }
966 } else {
967 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
968 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
969 if (!control_interface || !data_interface) {
Joe Perches898eb712007-10-18 03:06:30 -0700970 dev_dbg(&intf->dev,"no interfaces\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 return -ENODEV;
972 }
973 }
974
975 if (data_interface_num != call_interface_num)
Joe Perchesdc0d5c12007-12-17 11:40:18 -0800976 dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
978skip_normal_probe:
979
980 /*workaround for switched interfaces */
981 if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
982 if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
983 struct usb_interface *t;
Joe Perches898eb712007-10-18 03:06:30 -0700984 dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
986 t = control_interface;
987 control_interface = data_interface;
988 data_interface = t;
989 } else {
990 return -EINVAL;
991 }
992 }
Alan Stern74da5d62007-08-02 13:29:10 -0400993
994 /* Accept probe requests only for the control interface */
995 if (intf != control_interface)
996 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
998 if (usb_interface_claimed(data_interface)) { /* valid in this context */
Joe Perches898eb712007-10-18 03:06:30 -0700999 dev_dbg(&intf->dev,"The data interface isn't available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 return -EBUSY;
1001 }
1002
1003
1004 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
1005 return -EINVAL;
1006
1007 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
1008 epread = &data_interface->cur_altsetting->endpoint[0].desc;
1009 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
1010
1011
1012 /* workaround for switched endpoints */
Luiz Fernando N. Capitulino45aea702006-10-26 13:02:48 -03001013 if (!usb_endpoint_dir_in(epread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 /* descriptors are swapped */
1015 struct usb_endpoint_descriptor *t;
Joe Perches898eb712007-10-18 03:06:30 -07001016 dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
1018 t = epread;
1019 epread = epwrite;
1020 epwrite = t;
1021 }
1022 dbg("interfaces are valid");
1023 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
1024
1025 if (minor == ACM_TTY_MINORS) {
1026 err("no more free acm devices");
1027 return -ENODEV;
1028 }
1029
Oliver Neukum46f116e2005-10-24 22:42:35 +02001030 if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
Joe Perches898eb712007-10-18 03:06:30 -07001031 dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 goto alloc_fail;
1033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
1035 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
Oliver Neukum86478942006-05-13 22:50:47 +02001036 readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001037 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 acm->control = control_interface;
1039 acm->data = data_interface;
1040 acm->minor = minor;
1041 acm->dev = usb_dev;
1042 acm->ctrl_caps = ac_management_function;
1043 acm->ctrlsize = ctrlsize;
1044 acm->readsize = readsize;
Oliver Neukum86478942006-05-13 22:50:47 +02001045 acm->rx_buflimit = num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +01001046 acm->urb_task.func = acm_rx_tasklet;
1047 acm->urb_task.data = (unsigned long) acm;
David Howellsc4028952006-11-22 14:57:56 +00001048 INIT_WORK(&acm->work, acm_softint);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001049 INIT_WORK(&acm->waker, acm_waker);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 spin_lock_init(&acm->throttle_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +02001051 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +01001052 spin_lock_init(&acm->read_lock);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001053 mutex_init(&acm->mutex);
David Kubicek61a87ad2005-11-01 18:51:34 +01001054 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
1056 buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
1057 if (!buf) {
Joe Perches898eb712007-10-18 03:06:30 -07001058 dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 goto alloc_fail2;
1060 }
1061 acm->ctrl_buffer = buf;
1062
Oliver Neukum884b6002005-04-21 21:28:02 +02001063 if (acm_write_buffers_alloc(acm) < 0) {
Joe Perches898eb712007-10-18 03:06:30 -07001064 dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 goto alloc_fail4;
1066 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
1068 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
1069 if (!acm->ctrlurb) {
Joe Perches898eb712007-10-18 03:06:30 -07001070 dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 goto alloc_fail5;
1072 }
Oliver Neukum86478942006-05-13 22:50:47 +02001073 for (i = 0; i < num_rx_buf; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +01001074 struct acm_ru *rcv = &(acm->ru[i]);
1075
1076 if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
Joe Perches898eb712007-10-18 03:06:30 -07001077 dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n");
David Kubicek61a87ad2005-11-01 18:51:34 +01001078 goto alloc_fail7;
1079 }
1080
1081 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1082 rcv->instance = acm;
1083 }
Oliver Neukum86478942006-05-13 22:50:47 +02001084 for (i = 0; i < num_rx_buf; i++) {
David Brownell672c4e12008-08-06 18:41:12 -07001085 struct acm_rb *rb = &(acm->rb[i]);
David Kubicek61a87ad2005-11-01 18:51:34 +01001086
David Brownell672c4e12008-08-06 18:41:12 -07001087 rb->base = usb_buffer_alloc(acm->dev, readsize,
1088 GFP_KERNEL, &rb->dma);
1089 if (!rb->base) {
Joe Perches898eb712007-10-18 03:06:30 -07001090 dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
David Kubicek61a87ad2005-11-01 18:51:34 +01001091 goto alloc_fail7;
1092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 }
David Engrafe4cf3aa2008-03-20 10:01:34 +01001094 for(i = 0; i < ACM_NW; i++)
1095 {
1096 struct acm_wb *snd = &(acm->wb[i]);
1097
1098 if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) {
1099 dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)");
1100 goto alloc_fail7;
1101 }
1102
1103 usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
1104 NULL, acm->writesize, acm_write_bulk, snd);
1105 snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1106 snd->instance = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 }
1108
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001109 usb_set_intfdata (intf, acm);
1110
1111 i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
1112 if (i < 0)
1113 goto alloc_fail8;
1114
1115 if (cfd) { /* export the country data */
1116 acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
1117 if (!acm->country_codes)
1118 goto skip_countries;
1119 acm->country_code_size = cfd->bLength - 4;
1120 memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4);
1121 acm->country_rel_date = cfd->iCountryCodeRelDate;
1122
1123 i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
1124 if (i < 0) {
1125 kfree(acm->country_codes);
1126 goto skip_countries;
1127 }
1128
1129 i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
1130 if (i < 0) {
1131 kfree(acm->country_codes);
1132 goto skip_countries;
1133 }
1134 }
1135
1136skip_countries:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
1138 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
1139 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1140 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
1141
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
1143
1144 acm_set_control(acm, acm->ctrlout);
1145
1146 acm->line.dwDTERate = cpu_to_le32(9600);
1147 acm->line.bDataBits = 8;
1148 acm_set_line(acm, &acm->line);
1149
1150 usb_driver_claim_interface(&acm_driver, data_interface, acm);
David Brownell672c4e12008-08-06 18:41:12 -07001151 usb_set_intfdata(data_interface, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001153 usb_get_intf(control_interface);
1154 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
1156 acm_table[minor] = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001158 return 0;
1159alloc_fail8:
David Engrafe4cf3aa2008-03-20 10:01:34 +01001160 for (i = 0; i < ACM_NW; i++)
1161 usb_free_urb(acm->wb[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162alloc_fail7:
Oliver Neukum830f4022008-06-25 14:17:16 +02001163 acm_read_buffers_free(acm);
Oliver Neukum86478942006-05-13 22:50:47 +02001164 for (i = 0; i < num_rx_buf; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001165 usb_free_urb(acm->ru[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 usb_free_urb(acm->ctrlurb);
1167alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001168 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169alloc_fail4:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
1171alloc_fail2:
1172 kfree(acm);
1173alloc_fail:
1174 return -ENOMEM;
1175}
1176
Oliver Neukum1365baf2007-10-12 17:24:28 +02001177static void stop_data_traffic(struct acm *acm)
1178{
1179 int i;
Oliver Neukum11ea8592008-06-20 11:25:57 +02001180 dbg("Entering stop_data_traffic");
Oliver Neukum1365baf2007-10-12 17:24:28 +02001181
1182 tasklet_disable(&acm->urb_task);
1183
1184 usb_kill_urb(acm->ctrlurb);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001185 for(i = 0; i < ACM_NW; i++)
1186 usb_kill_urb(acm->wb[i].urb);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001187 for (i = 0; i < acm->rx_buflimit; i++)
1188 usb_kill_urb(acm->ru[i].urb);
1189
Oliver Neukum1365baf2007-10-12 17:24:28 +02001190 tasklet_enable(&acm->urb_task);
1191
1192 cancel_work_sync(&acm->work);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001193 cancel_work_sync(&acm->waker);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001194}
1195
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196static void acm_disconnect(struct usb_interface *intf)
1197{
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001198 struct acm *acm = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 struct usb_device *usb_dev = interface_to_usbdev(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
David Brownell672c4e12008-08-06 18:41:12 -07001201 /* sibling interface is already cleaning up */
1202 if (!acm)
Oliver Neukum86067eea2006-01-08 12:39:13 +01001203 return;
David Brownell672c4e12008-08-06 18:41:12 -07001204
1205 mutex_lock(&open_mutex);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001206 if (acm->country_codes){
Alan Stern74da5d62007-08-02 13:29:10 -04001207 device_remove_file(&acm->control->dev,
1208 &dev_attr_wCountryCodes);
1209 device_remove_file(&acm->control->dev,
1210 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001211 }
Alan Stern74da5d62007-08-02 13:29:10 -04001212 device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 acm->dev = NULL;
Oliver Neukum86067eea2006-01-08 12:39:13 +01001214 usb_set_intfdata(acm->control, NULL);
1215 usb_set_intfdata(acm->data, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
Oliver Neukum1365baf2007-10-12 17:24:28 +02001217 stop_data_traffic(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Oliver Neukum884b6002005-04-21 21:28:02 +02001219 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Oliver Neukum830f4022008-06-25 14:17:16 +02001221 acm_read_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
Oliver Neukum830f4022008-06-25 14:17:16 +02001223 usb_driver_release_interface(&acm_driver, intf == acm->control ?
1224 acm->data : acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
1226 if (!acm->used) {
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001227 acm_tty_unregister(acm);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001228 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 return;
1230 }
1231
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001232 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
1234 if (acm->tty)
1235 tty_hangup(acm->tty);
1236}
1237
Oliver Neukum35758582008-07-01 19:10:08 +02001238#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001239static int acm_suspend(struct usb_interface *intf, pm_message_t message)
1240{
1241 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001242 int cnt;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001243
Oliver Neukum11ea8592008-06-20 11:25:57 +02001244 if (acm->dev->auto_pm) {
1245 int b;
1246
1247 spin_lock_irq(&acm->read_lock);
1248 spin_lock(&acm->write_lock);
1249 b = acm->processing + acm->transmitting;
1250 spin_unlock(&acm->write_lock);
1251 spin_unlock_irq(&acm->read_lock);
1252 if (b)
1253 return -EBUSY;
1254 }
1255
1256 spin_lock_irq(&acm->read_lock);
1257 spin_lock(&acm->write_lock);
1258 cnt = acm->susp_count++;
1259 spin_unlock(&acm->write_lock);
1260 spin_unlock_irq(&acm->read_lock);
1261
1262 if (cnt)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001263 return 0;
1264 /*
1265 we treat opened interfaces differently,
1266 we must guard against open
1267 */
1268 mutex_lock(&acm->mutex);
1269
1270 if (acm->used)
1271 stop_data_traffic(acm);
1272
1273 mutex_unlock(&acm->mutex);
1274 return 0;
1275}
1276
1277static int acm_resume(struct usb_interface *intf)
1278{
1279 struct acm *acm = usb_get_intfdata(intf);
1280 int rv = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +02001281 int cnt;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001282
Oliver Neukum11ea8592008-06-20 11:25:57 +02001283 spin_lock_irq(&acm->read_lock);
1284 acm->susp_count -= 1;
1285 cnt = acm->susp_count;
1286 spin_unlock_irq(&acm->read_lock);
1287
1288 if (cnt)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001289 return 0;
1290
1291 mutex_lock(&acm->mutex);
1292 if (acm->used) {
1293 rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
1294 if (rv < 0)
Oliver Neukum11ea8592008-06-20 11:25:57 +02001295 goto err_out;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001296
1297 tasklet_schedule(&acm->urb_task);
1298 }
1299
1300err_out:
1301 mutex_unlock(&acm->mutex);
1302 return rv;
1303}
Oliver Neukum35758582008-07-01 19:10:08 +02001304
1305#endif /* CONFIG_PM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306/*
1307 * USB driver structure.
1308 */
1309
1310static struct usb_device_id acm_ids[] = {
1311 /* quirky and broken devices */
1312 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1313 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1314 },
Andrey Arapovb0e2a702007-07-04 17:11:42 +02001315 { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
1316 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1317 },
Masahito Omote8753e652005-07-29 12:17:25 -07001318 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1319 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1320 },
Chris Malley91a9c922006-10-03 10:08:28 +01001321 { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
1322 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1323 },
Oliver Neukum86478942006-05-13 22:50:47 +02001324 { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
1325 .driver_info = SINGLE_RX_URB, /* firmware bug */
1326 },
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001327 { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
1328 .driver_info = SINGLE_RX_URB, /* firmware bug */
1329 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001330 { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
1331 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1332 },
Iain McFarlane6149ed52008-05-04 00:13:49 +01001333 { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */
1334 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1335 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001336
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 /* control interfaces with various AT-command sets */
1338 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1339 USB_CDC_ACM_PROTO_AT_V25TER) },
1340 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1341 USB_CDC_ACM_PROTO_AT_PCCA101) },
1342 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1343 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1344 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1345 USB_CDC_ACM_PROTO_AT_GSM) },
1346 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1347 USB_CDC_ACM_PROTO_AT_3G ) },
1348 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1349 USB_CDC_ACM_PROTO_AT_CDMA) },
1350
1351 /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */
1352 { }
1353};
1354
1355MODULE_DEVICE_TABLE (usb, acm_ids);
1356
1357static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 .name = "cdc_acm",
1359 .probe = acm_probe,
1360 .disconnect = acm_disconnect,
Oliver Neukum35758582008-07-01 19:10:08 +02001361#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001362 .suspend = acm_suspend,
1363 .resume = acm_resume,
Oliver Neukum35758582008-07-01 19:10:08 +02001364#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 .id_table = acm_ids,
Oliver Neukum35758582008-07-01 19:10:08 +02001366#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001367 .supports_autosuspend = 1,
Oliver Neukum35758582008-07-01 19:10:08 +02001368#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369};
1370
1371/*
1372 * TTY driver structures.
1373 */
1374
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001375static const struct tty_operations acm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 .open = acm_tty_open,
1377 .close = acm_tty_close,
1378 .write = acm_tty_write,
1379 .write_room = acm_tty_write_room,
1380 .ioctl = acm_tty_ioctl,
1381 .throttle = acm_tty_throttle,
1382 .unthrottle = acm_tty_unthrottle,
1383 .chars_in_buffer = acm_tty_chars_in_buffer,
1384 .break_ctl = acm_tty_break_ctl,
1385 .set_termios = acm_tty_set_termios,
1386 .tiocmget = acm_tty_tiocmget,
1387 .tiocmset = acm_tty_tiocmset,
1388};
1389
1390/*
1391 * Init / exit.
1392 */
1393
1394static int __init acm_init(void)
1395{
1396 int retval;
1397 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1398 if (!acm_tty_driver)
1399 return -ENOMEM;
1400 acm_tty_driver->owner = THIS_MODULE,
1401 acm_tty_driver->driver_name = "acm",
1402 acm_tty_driver->name = "ttyACM",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 acm_tty_driver->major = ACM_TTY_MAJOR,
1404 acm_tty_driver->minor_start = 0,
1405 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1406 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001407 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 acm_tty_driver->init_termios = tty_std_termios;
1409 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1410 tty_set_operations(acm_tty_driver, &acm_ops);
1411
1412 retval = tty_register_driver(acm_tty_driver);
1413 if (retval) {
1414 put_tty_driver(acm_tty_driver);
1415 return retval;
1416 }
1417
1418 retval = usb_register(&acm_driver);
1419 if (retval) {
1420 tty_unregister_driver(acm_tty_driver);
1421 put_tty_driver(acm_tty_driver);
1422 return retval;
1423 }
1424
1425 info(DRIVER_VERSION ":" DRIVER_DESC);
1426
1427 return 0;
1428}
1429
1430static void __exit acm_exit(void)
1431{
1432 usb_deregister(&acm_driver);
1433 tty_unregister_driver(acm_tty_driver);
1434 put_tty_driver(acm_tty_driver);
1435}
1436
1437module_init(acm_init);
1438module_exit(acm_exit);
1439
1440MODULE_AUTHOR( DRIVER_AUTHOR );
1441MODULE_DESCRIPTION( DRIVER_DESC );
1442MODULE_LICENSE("GPL");
1443