blob: 910247d191e87df12ad69cef7b2560248d035e03 [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
147static inline int acm_wb_is_used(struct acm *acm, int wbn)
148{
149 return acm->wb[wbn].use;
150}
151
152/*
153 * Finish write.
154 */
David Engrafe4cf3aa2008-03-20 10:01:34 +0100155static void acm_write_done(struct acm *acm, struct acm_wb *wb)
Oliver Neukum884b6002005-04-21 21:28:02 +0200156{
157 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200158
159 spin_lock_irqsave(&acm->write_lock, flags);
160 acm->write_ready = 1;
David Engrafe4cf3aa2008-03-20 10:01:34 +0100161 wb->use = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200162 acm->transmitting--;
Oliver Neukum884b6002005-04-21 21:28:02 +0200163 spin_unlock_irqrestore(&acm->write_lock, flags);
164}
165
166/*
167 * Poke write.
Oliver Neukum11ea8592008-06-20 11:25:57 +0200168 *
169 * the caller is responsible for locking
Oliver Neukum884b6002005-04-21 21:28:02 +0200170 */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200171
172static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
173{
174 int rc;
175
176 acm->transmitting++;
177
178 wb->urb->transfer_buffer = wb->buf;
179 wb->urb->transfer_dma = wb->dmah;
180 wb->urb->transfer_buffer_length = wb->len;
181 wb->urb->dev = acm->dev;
182
183 if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) {
184 dbg("usb_submit_urb(write bulk) failed: %d", rc);
185 acm_write_done(acm, wb);
186 }
187 return rc;
188}
189
David Engrafe4cf3aa2008-03-20 10:01:34 +0100190static int acm_write_start(struct acm *acm, int wbn)
Oliver Neukum884b6002005-04-21 21:28:02 +0200191{
192 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200193 struct acm_wb *wb;
194 int rc;
195
196 spin_lock_irqsave(&acm->write_lock, flags);
197 if (!acm->dev) {
198 spin_unlock_irqrestore(&acm->write_lock, flags);
199 return -ENODEV;
200 }
201
202 if (!acm->write_ready) {
203 spin_unlock_irqrestore(&acm->write_lock, flags);
204 return 0; /* A white lie */
205 }
206
Oliver Neukum11ea8592008-06-20 11:25:57 +0200207 wb = &acm->wb[wbn];
208 if(acm_wb_is_avail(acm) <= 1)
209 acm->write_ready = 0;
210
211 dbg("%s susp_count: %d", __func__, acm->susp_count);
212 if (acm->susp_count) {
213 acm->old_ready = acm->write_ready;
214 acm->delayed_wb = wb;
215 acm->write_ready = 0;
216 schedule_work(&acm->waker);
217 spin_unlock_irqrestore(&acm->write_lock, flags);
218 return 0; /* A white lie */
219 }
220 usb_mark_last_busy(acm->dev);
221
Oliver Neukum884b6002005-04-21 21:28:02 +0200222 if (!acm_wb_is_used(acm, wbn)) {
223 spin_unlock_irqrestore(&acm->write_lock, flags);
224 return 0;
225 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200226
Oliver Neukum11ea8592008-06-20 11:25:57 +0200227 rc = acm_start_wb(acm, wb);
Oliver Neukum884b6002005-04-21 21:28:02 +0200228 spin_unlock_irqrestore(&acm->write_lock, flags);
229
Oliver Neukum884b6002005-04-21 21:28:02 +0200230 return rc;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200231
Oliver Neukum884b6002005-04-21 21:28:02 +0200232}
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100233/*
234 * attributes exported through sysfs
235 */
236static ssize_t show_caps
237(struct device *dev, struct device_attribute *attr, char *buf)
238{
239 struct usb_interface *intf = to_usb_interface(dev);
240 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum884b6002005-04-21 21:28:02 +0200241
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100242 return sprintf(buf, "%d", acm->ctrl_caps);
243}
244static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
245
246static ssize_t show_country_codes
247(struct device *dev, struct device_attribute *attr, char *buf)
248{
249 struct usb_interface *intf = to_usb_interface(dev);
250 struct acm *acm = usb_get_intfdata(intf);
251
252 memcpy(buf, acm->country_codes, acm->country_code_size);
253 return acm->country_code_size;
254}
255
256static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
257
258static ssize_t show_country_rel_date
259(struct device *dev, struct device_attribute *attr, char *buf)
260{
261 struct usb_interface *intf = to_usb_interface(dev);
262 struct acm *acm = usb_get_intfdata(intf);
263
264 return sprintf(buf, "%d", acm->country_rel_date);
265}
266
267static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
Oliver Neukum884b6002005-04-21 21:28:02 +0200268/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 * Interrupt handlers for various ACM device responses
270 */
271
272/* control interface reports status changes with "interrupt" transfers */
David Howells7d12e782006-10-05 14:55:46 +0100273static void acm_ctrl_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
275 struct acm *acm = urb->context;
276 struct usb_cdc_notification *dr = urb->transfer_buffer;
277 unsigned char *data;
278 int newctrl;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700279 int retval;
280 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700282 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 case 0:
284 /* success */
285 break;
286 case -ECONNRESET:
287 case -ENOENT:
288 case -ESHUTDOWN:
289 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800290 dbg("%s - urb shutting down with status: %d", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 return;
292 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800293 dbg("%s - nonzero urb status received: %d", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 goto exit;
295 }
296
297 if (!ACM_READY(acm))
298 goto exit;
299
300 data = (unsigned char *)(dr + 1);
301 switch (dr->bNotificationType) {
302
303 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
304
305 dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
306 break;
307
308 case USB_CDC_NOTIFY_SERIAL_STATE:
309
Harvey Harrisona5abdea2008-04-29 01:03:40 -0700310 newctrl = get_unaligned_le16(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
313 dbg("calling hangup");
314 tty_hangup(acm->tty);
315 }
316
317 acm->ctrlin = newctrl;
318
319 dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
320 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
321 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
322 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
323 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
324
325 break;
326
327 default:
328 dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
329 dr->bNotificationType, dr->wIndex,
330 dr->wLength, data[0], data[1]);
331 break;
332 }
333exit:
Oliver Neukum11ea8592008-06-20 11:25:57 +0200334 usb_mark_last_busy(acm->dev);
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700335 retval = usb_submit_urb (urb, GFP_ATOMIC);
336 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 err ("%s - usb_submit_urb failed with result %d",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800338 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339}
340
341/* data interface returns incoming bytes, or we got unthrottled */
David Howells7d12e782006-10-05 14:55:46 +0100342static void acm_read_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
David Kubicek61a87ad2005-11-01 18:51:34 +0100344 struct acm_rb *buf;
345 struct acm_ru *rcv = urb->context;
346 struct acm *acm = rcv->instance;
Oliver Neukum86478942006-05-13 22:50:47 +0200347 int status = urb->status;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700348
349 dbg("Entering acm_read_bulk with status %d", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Oliver Neukum11ea8592008-06-20 11:25:57 +0200351 if (!ACM_READY(acm)) {
352 dev_dbg(&acm->data->dev, "Aborting, acm not ready");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200354 }
355 usb_mark_last_busy(acm->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Oliver Neukum86478942006-05-13 22:50:47 +0200357 if (status)
Joe Perches898eb712007-10-18 03:06:30 -0700358 dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
David Kubicek61a87ad2005-11-01 18:51:34 +0100360 buf = rcv->buffer;
361 buf->size = urb->actual_length;
362
Oliver Neukum86478942006-05-13 22:50:47 +0200363 if (likely(status == 0)) {
364 spin_lock(&acm->read_lock);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200365 acm->processing++;
Oliver Neukum86478942006-05-13 22:50:47 +0200366 list_add_tail(&rcv->list, &acm->spare_read_urbs);
367 list_add_tail(&buf->list, &acm->filled_read_bufs);
368 spin_unlock(&acm->read_lock);
369 } else {
370 /* we drop the buffer due to an error */
371 spin_lock(&acm->read_lock);
372 list_add_tail(&rcv->list, &acm->spare_read_urbs);
373 list_add(&buf->list, &acm->spare_read_bufs);
374 spin_unlock(&acm->read_lock);
375 /* nevertheless the tasklet must be kicked unconditionally
376 so the queue cannot dry up */
377 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200378 if (likely(!acm->susp_count))
379 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380}
381
382static void acm_rx_tasklet(unsigned long _acm)
383{
384 struct acm *acm = (void *)_acm;
David Kubicek61a87ad2005-11-01 18:51:34 +0100385 struct acm_rb *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 struct tty_struct *tty = acm->tty;
David Kubicek61a87ad2005-11-01 18:51:34 +0100387 struct acm_ru *rcv;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200388 unsigned long flags;
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100389 unsigned char throttled;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 dbg("Entering acm_rx_tasklet");
392
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100393 if (!ACM_READY(acm))
Oliver Neukum11ea8592008-06-20 11:25:57 +0200394 {
395 dbg("acm_rx_tasklet: ACM not ready");
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100396 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200397 }
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100398
Oliver Neukum834dbca2007-03-06 10:47:04 +0100399 spin_lock_irqsave(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100400 throttled = acm->throttle;
Oliver Neukum834dbca2007-03-06 10:47:04 +0100401 spin_unlock_irqrestore(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100402 if (throttled)
Oliver Neukum11ea8592008-06-20 11:25:57 +0200403 {
404 dbg("acm_rx_tasklet: throttled");
David Kubicek61a87ad2005-11-01 18:51:34 +0100405 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200406 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100407
408next_buffer:
Jarek Poplawski762f0072006-10-06 07:23:11 +0200409 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100410 if (list_empty(&acm->filled_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200411 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100412 goto urbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100414 buf = list_entry(acm->filled_read_bufs.next,
415 struct acm_rb, list);
416 list_del(&buf->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200417 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100418
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200419 dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100420
Alan Cox33f0f882006-01-09 20:54:13 -0800421 tty_buffer_request_room(tty, buf->size);
Oliver Neukum834dbca2007-03-06 10:47:04 +0100422 spin_lock_irqsave(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100423 throttled = acm->throttle;
Oliver Neukum834dbca2007-03-06 10:47:04 +0100424 spin_unlock_irqrestore(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100425 if (!throttled)
Alan Cox33f0f882006-01-09 20:54:13 -0800426 tty_insert_flip_string(tty, buf->base, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100427 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100429 if (throttled) {
430 dbg("Throttling noticed");
Jarek Poplawski762f0072006-10-06 07:23:11 +0200431 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100432 list_add(&buf->list, &acm->filled_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200433 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 return;
435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
Jarek Poplawski762f0072006-10-06 07:23:11 +0200437 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100438 list_add(&buf->list, &acm->spare_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200439 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100440 goto next_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
David Kubicek61a87ad2005-11-01 18:51:34 +0100442urbs:
443 while (!list_empty(&acm->spare_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200444 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100445 if (list_empty(&acm->spare_read_urbs)) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200446 acm->processing = 0;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200447 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100448 return;
449 }
450 rcv = list_entry(acm->spare_read_urbs.next,
451 struct acm_ru, list);
452 list_del(&rcv->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200453 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100454
455 buf = list_entry(acm->spare_read_bufs.next,
456 struct acm_rb, list);
457 list_del(&buf->list);
458
459 rcv->buffer = buf;
460
461 usb_fill_bulk_urb(rcv->urb, acm->dev,
462 acm->rx_endpoint,
463 buf->base,
464 acm->readsize,
465 acm_read_bulk, rcv);
466 rcv->urb->transfer_dma = buf->dma;
467 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
468
David Kubicek61a87ad2005-11-01 18:51:34 +0100469 /* This shouldn't kill the driver as unsuccessful URBs are returned to the
470 free-urbs-pool and resubmited ASAP */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200471 spin_lock_irqsave(&acm->read_lock, flags);
472 if (acm->susp_count || usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100473 list_add(&buf->list, &acm->spare_read_bufs);
David Kubicek61a87ad2005-11-01 18:51:34 +0100474 list_add(&rcv->list, &acm->spare_read_urbs);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200475 acm->processing = 0;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200476 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100477 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200478 } else {
479 spin_unlock_irqrestore(&acm->read_lock, flags);
480 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 +0100481 }
482 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200483 spin_lock_irqsave(&acm->read_lock, flags);
484 acm->processing = 0;
485 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486}
487
488/* data interface wrote those outgoing bytes */
David Howells7d12e782006-10-05 14:55:46 +0100489static void acm_write_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490{
David Engrafe4cf3aa2008-03-20 10:01:34 +0100491 struct acm *acm;
Ming Leicdc97792008-02-24 18:41:47 +0800492 struct acm_wb *wb = urb->context;
Oliver Neukum884b6002005-04-21 21:28:02 +0200493
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200494 dbg("Entering acm_write_bulk with status %d", urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
David Engrafe4cf3aa2008-03-20 10:01:34 +0100496 acm = wb->instance;
497 acm_write_done(acm, wb);
Oliver Neukum884b6002005-04-21 21:28:02 +0200498 if (ACM_READY(acm))
499 schedule_work(&acm->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500}
501
David Howellsc4028952006-11-22 14:57:56 +0000502static void acm_softint(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
David Howellsc4028952006-11-22 14:57:56 +0000504 struct acm *acm = container_of(work, struct acm, work);
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200505 dbg("Entering acm_softint.");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507 if (!ACM_READY(acm))
508 return;
509 tty_wakeup(acm->tty);
510}
511
Oliver Neukum11ea8592008-06-20 11:25:57 +0200512static void acm_waker(struct work_struct *waker)
513{
514 struct acm *acm = container_of(waker, struct acm, waker);
Takashi Iwai81eb8ad2008-07-31 19:06:13 +0200515 unsigned long flags;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200516 int rv;
517
518 rv = usb_autopm_get_interface(acm->control);
519 if (rv < 0) {
520 err("Autopm failure in %s", __func__);
521 return;
522 }
523 if (acm->delayed_wb) {
524 acm_start_wb(acm, acm->delayed_wb);
525 acm->delayed_wb = NULL;
526 }
527 spin_lock_irqsave(&acm->write_lock, flags);
528 acm->write_ready = acm->old_ready;
529 spin_unlock_irqrestore(&acm->write_lock, flags);
530 usb_autopm_put_interface(acm->control);
531}
532
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533/*
534 * TTY handlers
535 */
536
537static int acm_tty_open(struct tty_struct *tty, struct file *filp)
538{
539 struct acm *acm;
540 int rv = -EINVAL;
David Kubicek61a87ad2005-11-01 18:51:34 +0100541 int i;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200542 dbg("Entering acm_tty_open.");
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100543
544 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
546 acm = acm_table[tty->index];
547 if (!acm || !acm->dev)
548 goto err_out;
549 else
550 rv = 0;
551
David Engraf28d1dfa2008-03-20 10:53:52 +0100552 set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 tty->driver_data = acm;
554 acm->tty = tty;
555
David Kubicek61a87ad2005-11-01 18:51:34 +0100556 /* force low_latency on so that our tty_push actually forces the data through,
557 otherwise it is scheduled, and with high data rates data can get lost. */
558 tty->low_latency = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
Oliver Neukum94409cc2008-02-11 15:22:29 +0100560 if (usb_autopm_get_interface(acm->control) < 0)
561 goto early_bail;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200562 else
563 acm->control->needs_remote_wakeup = 1;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200564
565 mutex_lock(&acm->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 if (acm->used++) {
Oliver Neukum1365baf2007-10-12 17:24:28 +0200567 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 goto done;
569 }
570
Oliver Neukum1365baf2007-10-12 17:24:28 +0200571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 acm->ctrlurb->dev = acm->dev;
573 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
574 dbg("usb_submit_urb(ctrl irq) failed");
575 goto bail_out;
576 }
577
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100578 if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
579 (acm->ctrl_caps & USB_CDC_CAP_LINE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 goto full_bailout;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200581 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
David Kubicek61a87ad2005-11-01 18:51:34 +0100583 INIT_LIST_HEAD(&acm->spare_read_urbs);
584 INIT_LIST_HEAD(&acm->spare_read_bufs);
585 INIT_LIST_HEAD(&acm->filled_read_bufs);
Oliver Neukum86478942006-05-13 22:50:47 +0200586 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100587 list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
588 }
Oliver Neukum86478942006-05-13 22:50:47 +0200589 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100590 list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
591 }
592
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100593 acm->throttle = 0;
594
David Kubicek61a87ad2005-11-01 18:51:34 +0100595 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
597done:
598err_out:
Oliver Neukum1365baf2007-10-12 17:24:28 +0200599 mutex_unlock(&acm->mutex);
Oliver Neukum94409cc2008-02-11 15:22:29 +0100600 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 return rv;
602
603full_bailout:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 usb_kill_urb(acm->ctrlurb);
605bail_out:
Oliver Neukum1365baf2007-10-12 17:24:28 +0200606 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 acm->used--;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200608 mutex_unlock(&acm->mutex);
Oliver Neukum94409cc2008-02-11 15:22:29 +0100609early_bail:
610 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 return -EIO;
612}
613
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700614static void acm_tty_unregister(struct acm *acm)
615{
Oliver Neukum86478942006-05-13 22:50:47 +0200616 int i,nr;
David Kubicek61a87ad2005-11-01 18:51:34 +0100617
Oliver Neukum86478942006-05-13 22:50:47 +0200618 nr = acm->rx_buflimit;
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700619 tty_unregister_device(acm_tty_driver, acm->minor);
620 usb_put_intf(acm->control);
621 acm_table[acm->minor] = NULL;
622 usb_free_urb(acm->ctrlurb);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100623 for (i = 0; i < ACM_NW; i++)
624 usb_free_urb(acm->wb[i].urb);
Oliver Neukum86478942006-05-13 22:50:47 +0200625 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100626 usb_free_urb(acm->ru[i].urb);
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100627 kfree(acm->country_codes);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700628 kfree(acm);
629}
630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631static void acm_tty_close(struct tty_struct *tty, struct file *filp)
632{
633 struct acm *acm = tty->driver_data;
Oliver Neukum86478942006-05-13 22:50:47 +0200634 int i,nr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
636 if (!acm || !acm->used)
637 return;
638
Oliver Neukum86478942006-05-13 22:50:47 +0200639 nr = acm->rx_buflimit;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100640 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 if (!--acm->used) {
642 if (acm->dev) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200643 usb_autopm_get_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 acm_set_control(acm, acm->ctrlout = 0);
645 usb_kill_urb(acm->ctrlurb);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100646 for (i = 0; i < ACM_NW; i++)
647 usb_kill_urb(acm->wb[i].urb);
Oliver Neukum86478942006-05-13 22:50:47 +0200648 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100649 usb_kill_urb(acm->ru[i].urb);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200650 acm->control->needs_remote_wakeup = 0;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200651 usb_autopm_put_interface(acm->control);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700652 } else
653 acm_tty_unregister(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100655 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656}
657
658static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
659{
660 struct acm *acm = tty->driver_data;
661 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200662 unsigned long flags;
663 int wbn;
664 struct acm_wb *wb;
665
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200666 dbg("Entering acm_tty_write to write %d bytes,", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
668 if (!ACM_READY(acm))
669 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 if (!count)
671 return 0;
672
Oliver Neukum884b6002005-04-21 21:28:02 +0200673 spin_lock_irqsave(&acm->write_lock, flags);
674 if ((wbn = acm_wb_alloc(acm)) < 0) {
675 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200676 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200678 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Oliver Neukum884b6002005-04-21 21:28:02 +0200680 count = (count > acm->writesize) ? acm->writesize : count;
681 dbg("Get %d bytes...", count);
682 memcpy(wb->buf, buf, count);
683 wb->len = count;
684 spin_unlock_irqrestore(&acm->write_lock, flags);
685
David Engrafe4cf3aa2008-03-20 10:01:34 +0100686 if ((stat = acm_write_start(acm, wbn)) < 0)
Oliver Neukum884b6002005-04-21 21:28:02 +0200687 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 return count;
689}
690
691static int acm_tty_write_room(struct tty_struct *tty)
692{
693 struct acm *acm = tty->driver_data;
694 if (!ACM_READY(acm))
695 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200696 /*
697 * Do not let the line discipline to know that we have a reserve,
698 * or it might get too enthusiastic.
699 */
700 return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701}
702
703static int acm_tty_chars_in_buffer(struct tty_struct *tty)
704{
705 struct acm *acm = tty->driver_data;
706 if (!ACM_READY(acm))
707 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200708 /*
709 * This is inaccurate (overcounts), but it works.
710 */
Oliver Neukum86478942006-05-13 22:50:47 +0200711 return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712}
713
714static void acm_tty_throttle(struct tty_struct *tty)
715{
716 struct acm *acm = tty->driver_data;
717 if (!ACM_READY(acm))
718 return;
719 spin_lock_bh(&acm->throttle_lock);
720 acm->throttle = 1;
721 spin_unlock_bh(&acm->throttle_lock);
722}
723
724static void acm_tty_unthrottle(struct tty_struct *tty)
725{
726 struct acm *acm = tty->driver_data;
727 if (!ACM_READY(acm))
728 return;
729 spin_lock_bh(&acm->throttle_lock);
730 acm->throttle = 0;
731 spin_unlock_bh(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100732 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733}
734
Alan Cox9e989662008-07-22 11:18:03 +0100735static int acm_tty_break_ctl(struct tty_struct *tty, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736{
737 struct acm *acm = tty->driver_data;
Alan Cox9e989662008-07-22 11:18:03 +0100738 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 if (!ACM_READY(acm))
Alan Cox9e989662008-07-22 11:18:03 +0100740 return -EINVAL;
741 retval = acm_send_break(acm, state ? 0xffff : 0);
742 if (retval < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 dbg("send break failed");
Alan Cox9e989662008-07-22 11:18:03 +0100744 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745}
746
747static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file)
748{
749 struct acm *acm = tty->driver_data;
750
751 if (!ACM_READY(acm))
752 return -EINVAL;
753
754 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
755 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
756 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
757 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
758 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
759 TIOCM_CTS;
760}
761
762static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
763 unsigned int set, unsigned int clear)
764{
765 struct acm *acm = tty->driver_data;
766 unsigned int newctrl;
767
768 if (!ACM_READY(acm))
769 return -EINVAL;
770
771 newctrl = acm->ctrlout;
772 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
773 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
774
775 newctrl = (newctrl & ~clear) | set;
776
777 if (acm->ctrlout == newctrl)
778 return 0;
779 return acm_set_control(acm, acm->ctrlout = newctrl);
780}
781
782static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
783{
784 struct acm *acm = tty->driver_data;
785
786 if (!ACM_READY(acm))
787 return -EINVAL;
788
789 return -ENOIOCTLCMD;
790}
791
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100792static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 0, 50, 75, 110, 134, 150, 200, 300, 600,
794 1200, 1800, 2400, 4800, 9600, 19200, 38400,
795 57600, 115200, 230400, 460800, 500000, 576000,
796 921600, 1000000, 1152000, 1500000, 2000000,
797 2500000, 3000000, 3500000, 4000000
798};
799
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100800static const __u8 acm_tty_size[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 5, 6, 7, 8
802};
803
Alan Cox606d0992006-12-08 02:38:45 -0800804static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
806 struct acm *acm = tty->driver_data;
Alan Cox606d0992006-12-08 02:38:45 -0800807 struct ktermios *termios = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 struct usb_cdc_line_coding newline;
809 int newctrl = acm->ctrlout;
810
811 if (!ACM_READY(acm))
812 return;
813
814 newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
815 (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
816 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
817 newline.bParityType = termios->c_cflag & PARENB ?
818 (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
819 newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
820
821 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
822
823 if (!newline.dwDTERate) {
824 newline.dwDTERate = acm->line.dwDTERate;
825 newctrl &= ~ACM_CTRL_DTR;
826 } else newctrl |= ACM_CTRL_DTR;
827
828 if (newctrl != acm->ctrlout)
829 acm_set_control(acm, acm->ctrlout = newctrl);
830
831 if (memcmp(&acm->line, &newline, sizeof newline)) {
832 memcpy(&acm->line, &newline, sizeof newline);
833 dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
834 newline.bCharFormat, newline.bParityType,
835 newline.bDataBits);
836 acm_set_line(acm, &acm->line);
837 }
838}
839
840/*
841 * USB probe and disconnect routines.
842 */
843
Oliver Neukum830f4022008-06-25 14:17:16 +0200844/* Little helpers: write/read buffers free */
Oliver Neukum884b6002005-04-21 21:28:02 +0200845static void acm_write_buffers_free(struct acm *acm)
846{
847 int i;
848 struct acm_wb *wb;
849
Oliver Neukum86478942006-05-13 22:50:47 +0200850 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200851 usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
852 }
853}
854
Oliver Neukum830f4022008-06-25 14:17:16 +0200855static void acm_read_buffers_free(struct acm *acm)
856{
857 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
858 int i, n = acm->rx_buflimit;
859
860 for (i = 0; i < n; i++)
861 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
862}
863
Oliver Neukum884b6002005-04-21 21:28:02 +0200864/* Little helper: write buffers allocate */
865static int acm_write_buffers_alloc(struct acm *acm)
866{
867 int i;
868 struct acm_wb *wb;
869
Oliver Neukum86478942006-05-13 22:50:47 +0200870 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200871 wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
872 &wb->dmah);
873 if (!wb->buf) {
874 while (i != 0) {
875 --i;
876 --wb;
877 usb_buffer_free(acm->dev, acm->writesize,
878 wb->buf, wb->dmah);
879 }
880 return -ENOMEM;
881 }
882 }
883 return 0;
884}
885
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886static int acm_probe (struct usb_interface *intf,
887 const struct usb_device_id *id)
888{
889 struct usb_cdc_union_desc *union_header = NULL;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100890 struct usb_cdc_country_functional_desc *cfd = NULL;
David Brownellc6dbf552008-04-13 14:00:44 -0700891 unsigned char *buffer = intf->altsetting->extra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 int buflen = intf->altsetting->extralen;
893 struct usb_interface *control_interface;
894 struct usb_interface *data_interface;
895 struct usb_endpoint_descriptor *epctrl;
896 struct usb_endpoint_descriptor *epread;
897 struct usb_endpoint_descriptor *epwrite;
898 struct usb_device *usb_dev = interface_to_usbdev(intf);
899 struct acm *acm;
900 int minor;
901 int ctrlsize,readsize;
902 u8 *buf;
903 u8 ac_management_function = 0;
904 u8 call_management_function = 0;
905 int call_interface_num = -1;
906 int data_interface_num;
907 unsigned long quirks;
Oliver Neukum86478942006-05-13 22:50:47 +0200908 int num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +0100909 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
Oliver Neukum86478942006-05-13 22:50:47 +0200911 /* normal quirks */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 quirks = (unsigned long)id->driver_info;
Oliver Neukum86478942006-05-13 22:50:47 +0200913 num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
914
915 /* handle quirks deadly to normal probing*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 if (quirks == NO_UNION_NORMAL) {
917 data_interface = usb_ifnum_to_if(usb_dev, 1);
918 control_interface = usb_ifnum_to_if(usb_dev, 0);
919 goto skip_normal_probe;
920 }
921
922 /* normal probing*/
923 if (!buffer) {
Joe Perches898eb712007-10-18 03:06:30 -0700924 err("Weird descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 return -EINVAL;
926 }
927
928 if (!buflen) {
929 if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
Joe Perches898eb712007-10-18 03:06:30 -0700930 dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 buflen = intf->cur_altsetting->endpoint->extralen;
932 buffer = intf->cur_altsetting->endpoint->extra;
933 } else {
934 err("Zero length descriptor references\n");
935 return -EINVAL;
936 }
937 }
938
939 while (buflen > 0) {
940 if (buffer [1] != USB_DT_CS_INTERFACE) {
941 err("skipping garbage\n");
942 goto next_desc;
943 }
944
945 switch (buffer [2]) {
946 case USB_CDC_UNION_TYPE: /* we've found it */
947 if (union_header) {
948 err("More than one union descriptor, skipping ...");
949 goto next_desc;
950 }
951 union_header = (struct usb_cdc_union_desc *)
952 buffer;
953 break;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100954 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
955 cfd = (struct usb_cdc_country_functional_desc *)buffer;
956 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 case USB_CDC_HEADER_TYPE: /* maybe check version */
958 break; /* for now we ignore it */
959 case USB_CDC_ACM_TYPE:
960 ac_management_function = buffer[3];
961 break;
962 case USB_CDC_CALL_MANAGEMENT_TYPE:
963 call_management_function = buffer[3];
964 call_interface_num = buffer[4];
965 if ((call_management_function & 3) != 3)
966 err("This device cannot do calls on its own. It is no modem.");
967 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 default:
David Brownellc6dbf552008-04-13 14:00:44 -0700969 /* there are LOTS more CDC descriptors that
970 * could legitimately be found here.
971 */
972 dev_dbg(&intf->dev, "Ignoring descriptor: "
973 "type %02x, length %d\n",
974 buffer[2], buffer[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 break;
976 }
977next_desc:
978 buflen -= buffer[0];
979 buffer += buffer[0];
980 }
981
982 if (!union_header) {
983 if (call_interface_num > 0) {
Joe Perches898eb712007-10-18 03:06:30 -0700984 dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
986 control_interface = intf;
987 } else {
Joe Perches898eb712007-10-18 03:06:30 -0700988 dev_dbg(&intf->dev,"No union descriptor, giving up\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 return -ENODEV;
990 }
991 } else {
992 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
993 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
994 if (!control_interface || !data_interface) {
Joe Perches898eb712007-10-18 03:06:30 -0700995 dev_dbg(&intf->dev,"no interfaces\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 return -ENODEV;
997 }
998 }
999
1000 if (data_interface_num != call_interface_num)
Joe Perchesdc0d5c12007-12-17 11:40:18 -08001001 dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003skip_normal_probe:
1004
1005 /*workaround for switched interfaces */
1006 if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
1007 if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
1008 struct usb_interface *t;
Joe Perches898eb712007-10-18 03:06:30 -07001009 dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
1011 t = control_interface;
1012 control_interface = data_interface;
1013 data_interface = t;
1014 } else {
1015 return -EINVAL;
1016 }
1017 }
Alan Stern74da5d62007-08-02 13:29:10 -04001018
1019 /* Accept probe requests only for the control interface */
1020 if (intf != control_interface)
1021 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023 if (usb_interface_claimed(data_interface)) { /* valid in this context */
Joe Perches898eb712007-10-18 03:06:30 -07001024 dev_dbg(&intf->dev,"The data interface isn't available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 return -EBUSY;
1026 }
1027
1028
1029 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
1030 return -EINVAL;
1031
1032 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
1033 epread = &data_interface->cur_altsetting->endpoint[0].desc;
1034 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
1035
1036
1037 /* workaround for switched endpoints */
Luiz Fernando N. Capitulino45aea702006-10-26 13:02:48 -03001038 if (!usb_endpoint_dir_in(epread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 /* descriptors are swapped */
1040 struct usb_endpoint_descriptor *t;
Joe Perches898eb712007-10-18 03:06:30 -07001041 dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
1043 t = epread;
1044 epread = epwrite;
1045 epwrite = t;
1046 }
1047 dbg("interfaces are valid");
1048 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
1049
1050 if (minor == ACM_TTY_MINORS) {
1051 err("no more free acm devices");
1052 return -ENODEV;
1053 }
1054
Oliver Neukum46f116e2005-10-24 22:42:35 +02001055 if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
Joe Perches898eb712007-10-18 03:06:30 -07001056 dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 goto alloc_fail;
1058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
Oliver Neukum86478942006-05-13 22:50:47 +02001061 readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001062 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 acm->control = control_interface;
1064 acm->data = data_interface;
1065 acm->minor = minor;
1066 acm->dev = usb_dev;
1067 acm->ctrl_caps = ac_management_function;
1068 acm->ctrlsize = ctrlsize;
1069 acm->readsize = readsize;
Oliver Neukum86478942006-05-13 22:50:47 +02001070 acm->rx_buflimit = num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +01001071 acm->urb_task.func = acm_rx_tasklet;
1072 acm->urb_task.data = (unsigned long) acm;
David Howellsc4028952006-11-22 14:57:56 +00001073 INIT_WORK(&acm->work, acm_softint);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001074 INIT_WORK(&acm->waker, acm_waker);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 spin_lock_init(&acm->throttle_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +02001076 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +01001077 spin_lock_init(&acm->read_lock);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001078 mutex_init(&acm->mutex);
Oliver Neukum884b6002005-04-21 21:28:02 +02001079 acm->write_ready = 1;
David Kubicek61a87ad2005-11-01 18:51:34 +01001080 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
1082 buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
1083 if (!buf) {
Joe Perches898eb712007-10-18 03:06:30 -07001084 dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 goto alloc_fail2;
1086 }
1087 acm->ctrl_buffer = buf;
1088
Oliver Neukum884b6002005-04-21 21:28:02 +02001089 if (acm_write_buffers_alloc(acm) < 0) {
Joe Perches898eb712007-10-18 03:06:30 -07001090 dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 goto alloc_fail4;
1092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
1094 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
1095 if (!acm->ctrlurb) {
Joe Perches898eb712007-10-18 03:06:30 -07001096 dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 goto alloc_fail5;
1098 }
Oliver Neukum86478942006-05-13 22:50:47 +02001099 for (i = 0; i < num_rx_buf; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +01001100 struct acm_ru *rcv = &(acm->ru[i]);
1101
1102 if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
Joe Perches898eb712007-10-18 03:06:30 -07001103 dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n");
David Kubicek61a87ad2005-11-01 18:51:34 +01001104 goto alloc_fail7;
1105 }
1106
1107 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1108 rcv->instance = acm;
1109 }
Oliver Neukum86478942006-05-13 22:50:47 +02001110 for (i = 0; i < num_rx_buf; i++) {
David Brownell672c4e12008-08-06 18:41:12 -07001111 struct acm_rb *rb = &(acm->rb[i]);
David Kubicek61a87ad2005-11-01 18:51:34 +01001112
David Brownell672c4e12008-08-06 18:41:12 -07001113 rb->base = usb_buffer_alloc(acm->dev, readsize,
1114 GFP_KERNEL, &rb->dma);
1115 if (!rb->base) {
Joe Perches898eb712007-10-18 03:06:30 -07001116 dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
David Kubicek61a87ad2005-11-01 18:51:34 +01001117 goto alloc_fail7;
1118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 }
David Engrafe4cf3aa2008-03-20 10:01:34 +01001120 for(i = 0; i < ACM_NW; i++)
1121 {
1122 struct acm_wb *snd = &(acm->wb[i]);
1123
1124 if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) {
1125 dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)");
1126 goto alloc_fail7;
1127 }
1128
1129 usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
1130 NULL, acm->writesize, acm_write_bulk, snd);
1131 snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1132 snd->instance = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 }
1134
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001135 usb_set_intfdata (intf, acm);
1136
1137 i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
1138 if (i < 0)
1139 goto alloc_fail8;
1140
1141 if (cfd) { /* export the country data */
1142 acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
1143 if (!acm->country_codes)
1144 goto skip_countries;
1145 acm->country_code_size = cfd->bLength - 4;
1146 memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4);
1147 acm->country_rel_date = cfd->iCountryCodeRelDate;
1148
1149 i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
1150 if (i < 0) {
1151 kfree(acm->country_codes);
1152 goto skip_countries;
1153 }
1154
1155 i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
1156 if (i < 0) {
1157 kfree(acm->country_codes);
1158 goto skip_countries;
1159 }
1160 }
1161
1162skip_countries:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
1164 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
1165 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1166 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
1167
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
1169
1170 acm_set_control(acm, acm->ctrlout);
1171
1172 acm->line.dwDTERate = cpu_to_le32(9600);
1173 acm->line.bDataBits = 8;
1174 acm_set_line(acm, &acm->line);
1175
1176 usb_driver_claim_interface(&acm_driver, data_interface, acm);
David Brownell672c4e12008-08-06 18:41:12 -07001177 usb_set_intfdata(data_interface, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001179 usb_get_intf(control_interface);
1180 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
1182 acm_table[minor] = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001184 return 0;
1185alloc_fail8:
David Engrafe4cf3aa2008-03-20 10:01:34 +01001186 for (i = 0; i < ACM_NW; i++)
1187 usb_free_urb(acm->wb[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188alloc_fail7:
Oliver Neukum830f4022008-06-25 14:17:16 +02001189 acm_read_buffers_free(acm);
Oliver Neukum86478942006-05-13 22:50:47 +02001190 for (i = 0; i < num_rx_buf; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001191 usb_free_urb(acm->ru[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 usb_free_urb(acm->ctrlurb);
1193alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001194 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195alloc_fail4:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
1197alloc_fail2:
1198 kfree(acm);
1199alloc_fail:
1200 return -ENOMEM;
1201}
1202
Oliver Neukum1365baf2007-10-12 17:24:28 +02001203static void stop_data_traffic(struct acm *acm)
1204{
1205 int i;
Oliver Neukum11ea8592008-06-20 11:25:57 +02001206 dbg("Entering stop_data_traffic");
Oliver Neukum1365baf2007-10-12 17:24:28 +02001207
1208 tasklet_disable(&acm->urb_task);
1209
1210 usb_kill_urb(acm->ctrlurb);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001211 for(i = 0; i < ACM_NW; i++)
1212 usb_kill_urb(acm->wb[i].urb);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001213 for (i = 0; i < acm->rx_buflimit; i++)
1214 usb_kill_urb(acm->ru[i].urb);
1215
Oliver Neukum1365baf2007-10-12 17:24:28 +02001216 tasklet_enable(&acm->urb_task);
1217
1218 cancel_work_sync(&acm->work);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001219 cancel_work_sync(&acm->waker);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001220}
1221
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222static void acm_disconnect(struct usb_interface *intf)
1223{
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001224 struct acm *acm = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 struct usb_device *usb_dev = interface_to_usbdev(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
David Brownell672c4e12008-08-06 18:41:12 -07001227 /* sibling interface is already cleaning up */
1228 if (!acm)
Oliver Neukum86067eea2006-01-08 12:39:13 +01001229 return;
David Brownell672c4e12008-08-06 18:41:12 -07001230
1231 mutex_lock(&open_mutex);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001232 if (acm->country_codes){
Alan Stern74da5d62007-08-02 13:29:10 -04001233 device_remove_file(&acm->control->dev,
1234 &dev_attr_wCountryCodes);
1235 device_remove_file(&acm->control->dev,
1236 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001237 }
Alan Stern74da5d62007-08-02 13:29:10 -04001238 device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 acm->dev = NULL;
Oliver Neukum86067eea2006-01-08 12:39:13 +01001240 usb_set_intfdata(acm->control, NULL);
1241 usb_set_intfdata(acm->data, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
Oliver Neukum1365baf2007-10-12 17:24:28 +02001243 stop_data_traffic(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
Oliver Neukum884b6002005-04-21 21:28:02 +02001245 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Oliver Neukum830f4022008-06-25 14:17:16 +02001247 acm_read_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
Oliver Neukum830f4022008-06-25 14:17:16 +02001249 usb_driver_release_interface(&acm_driver, intf == acm->control ?
1250 acm->data : acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
1252 if (!acm->used) {
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001253 acm_tty_unregister(acm);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001254 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 return;
1256 }
1257
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001258 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
1260 if (acm->tty)
1261 tty_hangup(acm->tty);
1262}
1263
Oliver Neukum35758582008-07-01 19:10:08 +02001264#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001265static int acm_suspend(struct usb_interface *intf, pm_message_t message)
1266{
1267 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001268 int cnt;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001269
Oliver Neukum11ea8592008-06-20 11:25:57 +02001270 if (acm->dev->auto_pm) {
1271 int b;
1272
1273 spin_lock_irq(&acm->read_lock);
1274 spin_lock(&acm->write_lock);
1275 b = acm->processing + acm->transmitting;
1276 spin_unlock(&acm->write_lock);
1277 spin_unlock_irq(&acm->read_lock);
1278 if (b)
1279 return -EBUSY;
1280 }
1281
1282 spin_lock_irq(&acm->read_lock);
1283 spin_lock(&acm->write_lock);
1284 cnt = acm->susp_count++;
1285 spin_unlock(&acm->write_lock);
1286 spin_unlock_irq(&acm->read_lock);
1287
1288 if (cnt)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001289 return 0;
1290 /*
1291 we treat opened interfaces differently,
1292 we must guard against open
1293 */
1294 mutex_lock(&acm->mutex);
1295
1296 if (acm->used)
1297 stop_data_traffic(acm);
1298
1299 mutex_unlock(&acm->mutex);
1300 return 0;
1301}
1302
1303static int acm_resume(struct usb_interface *intf)
1304{
1305 struct acm *acm = usb_get_intfdata(intf);
1306 int rv = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +02001307 int cnt;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001308
Oliver Neukum11ea8592008-06-20 11:25:57 +02001309 spin_lock_irq(&acm->read_lock);
1310 acm->susp_count -= 1;
1311 cnt = acm->susp_count;
1312 spin_unlock_irq(&acm->read_lock);
1313
1314 if (cnt)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001315 return 0;
1316
1317 mutex_lock(&acm->mutex);
1318 if (acm->used) {
1319 rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
1320 if (rv < 0)
Oliver Neukum11ea8592008-06-20 11:25:57 +02001321 goto err_out;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001322
1323 tasklet_schedule(&acm->urb_task);
1324 }
1325
1326err_out:
1327 mutex_unlock(&acm->mutex);
1328 return rv;
1329}
Oliver Neukum35758582008-07-01 19:10:08 +02001330
1331#endif /* CONFIG_PM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332/*
1333 * USB driver structure.
1334 */
1335
1336static struct usb_device_id acm_ids[] = {
1337 /* quirky and broken devices */
1338 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1339 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1340 },
Andrey Arapovb0e2a702007-07-04 17:11:42 +02001341 { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
1342 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1343 },
Masahito Omote8753e652005-07-29 12:17:25 -07001344 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1345 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1346 },
Chris Malley91a9c922006-10-03 10:08:28 +01001347 { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
1348 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1349 },
Oliver Neukum86478942006-05-13 22:50:47 +02001350 { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
1351 .driver_info = SINGLE_RX_URB, /* firmware bug */
1352 },
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001353 { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
1354 .driver_info = SINGLE_RX_URB, /* firmware bug */
1355 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001356 { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
1357 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1358 },
Iain McFarlane6149ed52008-05-04 00:13:49 +01001359 { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */
1360 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1361 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 /* control interfaces with various AT-command sets */
1364 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1365 USB_CDC_ACM_PROTO_AT_V25TER) },
1366 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1367 USB_CDC_ACM_PROTO_AT_PCCA101) },
1368 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1369 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1370 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1371 USB_CDC_ACM_PROTO_AT_GSM) },
1372 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1373 USB_CDC_ACM_PROTO_AT_3G ) },
1374 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1375 USB_CDC_ACM_PROTO_AT_CDMA) },
1376
1377 /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */
1378 { }
1379};
1380
1381MODULE_DEVICE_TABLE (usb, acm_ids);
1382
1383static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 .name = "cdc_acm",
1385 .probe = acm_probe,
1386 .disconnect = acm_disconnect,
Oliver Neukum35758582008-07-01 19:10:08 +02001387#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001388 .suspend = acm_suspend,
1389 .resume = acm_resume,
Oliver Neukum35758582008-07-01 19:10:08 +02001390#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 .id_table = acm_ids,
Oliver Neukum35758582008-07-01 19:10:08 +02001392#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001393 .supports_autosuspend = 1,
Oliver Neukum35758582008-07-01 19:10:08 +02001394#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395};
1396
1397/*
1398 * TTY driver structures.
1399 */
1400
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001401static const struct tty_operations acm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 .open = acm_tty_open,
1403 .close = acm_tty_close,
1404 .write = acm_tty_write,
1405 .write_room = acm_tty_write_room,
1406 .ioctl = acm_tty_ioctl,
1407 .throttle = acm_tty_throttle,
1408 .unthrottle = acm_tty_unthrottle,
1409 .chars_in_buffer = acm_tty_chars_in_buffer,
1410 .break_ctl = acm_tty_break_ctl,
1411 .set_termios = acm_tty_set_termios,
1412 .tiocmget = acm_tty_tiocmget,
1413 .tiocmset = acm_tty_tiocmset,
1414};
1415
1416/*
1417 * Init / exit.
1418 */
1419
1420static int __init acm_init(void)
1421{
1422 int retval;
1423 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1424 if (!acm_tty_driver)
1425 return -ENOMEM;
1426 acm_tty_driver->owner = THIS_MODULE,
1427 acm_tty_driver->driver_name = "acm",
1428 acm_tty_driver->name = "ttyACM",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 acm_tty_driver->major = ACM_TTY_MAJOR,
1430 acm_tty_driver->minor_start = 0,
1431 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1432 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001433 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 acm_tty_driver->init_termios = tty_std_termios;
1435 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1436 tty_set_operations(acm_tty_driver, &acm_ops);
1437
1438 retval = tty_register_driver(acm_tty_driver);
1439 if (retval) {
1440 put_tty_driver(acm_tty_driver);
1441 return retval;
1442 }
1443
1444 retval = usb_register(&acm_driver);
1445 if (retval) {
1446 tty_unregister_driver(acm_tty_driver);
1447 put_tty_driver(acm_tty_driver);
1448 return retval;
1449 }
1450
1451 info(DRIVER_VERSION ":" DRIVER_DESC);
1452
1453 return 0;
1454}
1455
1456static void __exit acm_exit(void)
1457{
1458 usb_deregister(&acm_driver);
1459 tty_unregister_driver(acm_tty_driver);
1460 put_tty_driver(acm_tty_driver);
1461}
1462
1463module_init(acm_init);
1464module_exit(acm_exit);
1465
1466MODULE_AUTHOR( DRIVER_AUTHOR );
1467MODULE_DESCRIPTION( DRIVER_DESC );
1468MODULE_LICENSE("GPL");
1469