blob: b4e73aa759d6a7a2b1dad4b31835896dfab2eb66 [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
David Brownelle5fbab52008-08-06 18:46:10 -070054#undef VERBOSE_DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56#include <linux/kernel.h>
57#include <linux/errno.h>
58#include <linux/init.h>
59#include <linux/slab.h>
60#include <linux/tty.h>
61#include <linux/tty_driver.h>
62#include <linux/tty_flip.h>
63#include <linux/module.h>
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010064#include <linux/mutex.h>
Alan Cox10077d42009-06-11 12:36:09 +010065#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#include <linux/usb.h>
David Brownella8c28f22006-06-13 09:57:47 -070067#include <linux/usb/cdc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#include <asm/byteorder.h>
69#include <asm/unaligned.h>
David Kubicek61a87ad2005-11-01 18:51:34 +010070#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
72#include "cdc-acm.h"
73
David Brownelle5fbab52008-08-06 18:46:10 -070074
75#define ACM_CLOSE_TIMEOUT 15 /* seconds to let writes drain */
76
Linus Torvalds1da177e2005-04-16 15:20:36 -070077/*
78 * Version Information
79 */
David Engrafe4cf3aa2008-03-20 10:01:34 +010080#define DRIVER_VERSION "v0.26"
David Kubicek61a87ad2005-11-01 18:51:34 +010081#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
Linus Torvalds1da177e2005-04-16 15:20:36 -070082#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
83
84static struct usb_driver acm_driver;
85static struct tty_driver *acm_tty_driver;
86static struct acm *acm_table[ACM_TTY_MINORS];
87
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010088static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Alan Cox10077d42009-06-11 12:36:09 +010090#define ACM_READY(acm) (acm && acm->dev && acm->port.count)
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Alan Cox739e0282009-06-11 12:27:50 +010092static const struct tty_port_operations acm_port_ops = {
93};
94
David Brownelle5fbab52008-08-06 18:46:10 -070095#ifdef VERBOSE_DEBUG
96#define verbose 1
97#else
98#define verbose 0
99#endif
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101/*
102 * Functions for ACM control messages.
103 */
104
105static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
106{
107 int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
108 request, USB_RT_ACM, value,
109 acm->control->altsetting[0].desc.bInterfaceNumber,
110 buf, len, 5000);
111 dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
112 return retval < 0 ? retval : 0;
113}
114
115/* devices aren't required to support these requests.
116 * the cdc acm descriptor tells whether they do...
117 */
118#define acm_set_control(acm, control) \
119 acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
120#define acm_set_line(acm, line) \
121 acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
122#define acm_send_break(acm, ms) \
123 acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
124
125/*
Oliver Neukum884b6002005-04-21 21:28:02 +0200126 * Write buffer management.
127 * All of these assume proper locks taken by the caller.
128 */
129
130static int acm_wb_alloc(struct acm *acm)
131{
132 int i, wbn;
133 struct acm_wb *wb;
134
David Engrafe4cf3aa2008-03-20 10:01:34 +0100135 wbn = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200136 i = 0;
137 for (;;) {
138 wb = &acm->wb[wbn];
139 if (!wb->use) {
140 wb->use = 1;
141 return wbn;
142 }
Oliver Neukum86478942006-05-13 22:50:47 +0200143 wbn = (wbn + 1) % ACM_NW;
144 if (++i >= ACM_NW)
Oliver Neukum884b6002005-04-21 21:28:02 +0200145 return -1;
146 }
147}
148
Oliver Neukum884b6002005-04-21 21:28:02 +0200149static int acm_wb_is_avail(struct acm *acm)
150{
151 int i, n;
David Brownelle5fbab52008-08-06 18:46:10 -0700152 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200153
Oliver Neukum86478942006-05-13 22:50:47 +0200154 n = ACM_NW;
David Brownelle5fbab52008-08-06 18:46:10 -0700155 spin_lock_irqsave(&acm->write_lock, flags);
Oliver Neukum86478942006-05-13 22:50:47 +0200156 for (i = 0; i < ACM_NW; i++) {
157 n -= acm->wb[i].use;
Oliver Neukum884b6002005-04-21 21:28:02 +0200158 }
David Brownelle5fbab52008-08-06 18:46:10 -0700159 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200160 return n;
161}
162
Oliver Neukum884b6002005-04-21 21:28:02 +0200163/*
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800164 * Finish write. Caller must hold acm->write_lock
Oliver Neukum884b6002005-04-21 21:28:02 +0200165 */
David Engrafe4cf3aa2008-03-20 10:01:34 +0100166static void acm_write_done(struct acm *acm, struct acm_wb *wb)
Oliver Neukum884b6002005-04-21 21:28:02 +0200167{
David Engrafe4cf3aa2008-03-20 10:01:34 +0100168 wb->use = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200169 acm->transmitting--;
Oliver Neukum884b6002005-04-21 21:28:02 +0200170}
171
172/*
173 * Poke write.
Oliver Neukum11ea8592008-06-20 11:25:57 +0200174 *
175 * the caller is responsible for locking
Oliver Neukum884b6002005-04-21 21:28:02 +0200176 */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200177
178static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
179{
180 int rc;
181
182 acm->transmitting++;
183
184 wb->urb->transfer_buffer = wb->buf;
185 wb->urb->transfer_dma = wb->dmah;
186 wb->urb->transfer_buffer_length = wb->len;
187 wb->urb->dev = acm->dev;
188
189 if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) {
190 dbg("usb_submit_urb(write bulk) failed: %d", rc);
191 acm_write_done(acm, wb);
192 }
193 return rc;
194}
195
David Engrafe4cf3aa2008-03-20 10:01:34 +0100196static int acm_write_start(struct acm *acm, int wbn)
Oliver Neukum884b6002005-04-21 21:28:02 +0200197{
198 unsigned long flags;
David Brownell934da462008-08-06 18:44:12 -0700199 struct acm_wb *wb = &acm->wb[wbn];
Oliver Neukum884b6002005-04-21 21:28:02 +0200200 int rc;
201
202 spin_lock_irqsave(&acm->write_lock, flags);
203 if (!acm->dev) {
David Brownell934da462008-08-06 18:44:12 -0700204 wb->use = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200205 spin_unlock_irqrestore(&acm->write_lock, flags);
206 return -ENODEV;
207 }
208
Oliver Neukum11ea8592008-06-20 11:25:57 +0200209 dbg("%s susp_count: %d", __func__, acm->susp_count);
210 if (acm->susp_count) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200211 acm->delayed_wb = wb;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200212 schedule_work(&acm->waker);
213 spin_unlock_irqrestore(&acm->write_lock, flags);
214 return 0; /* A white lie */
215 }
216 usb_mark_last_busy(acm->dev);
217
Oliver Neukum11ea8592008-06-20 11:25:57 +0200218 rc = acm_start_wb(acm, wb);
Oliver Neukum884b6002005-04-21 21:28:02 +0200219 spin_unlock_irqrestore(&acm->write_lock, flags);
220
Oliver Neukum884b6002005-04-21 21:28:02 +0200221 return rc;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200222
Oliver Neukum884b6002005-04-21 21:28:02 +0200223}
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100224/*
225 * attributes exported through sysfs
226 */
227static ssize_t show_caps
228(struct device *dev, struct device_attribute *attr, char *buf)
229{
230 struct usb_interface *intf = to_usb_interface(dev);
231 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum884b6002005-04-21 21:28:02 +0200232
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100233 return sprintf(buf, "%d", acm->ctrl_caps);
234}
235static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
236
237static ssize_t show_country_codes
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 memcpy(buf, acm->country_codes, acm->country_code_size);
244 return acm->country_code_size;
245}
246
247static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
248
249static ssize_t show_country_rel_date
250(struct device *dev, struct device_attribute *attr, char *buf)
251{
252 struct usb_interface *intf = to_usb_interface(dev);
253 struct acm *acm = usb_get_intfdata(intf);
254
255 return sprintf(buf, "%d", acm->country_rel_date);
256}
257
258static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
Oliver Neukum884b6002005-04-21 21:28:02 +0200259/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 * Interrupt handlers for various ACM device responses
261 */
262
263/* control interface reports status changes with "interrupt" transfers */
David Howells7d12e782006-10-05 14:55:46 +0100264static void acm_ctrl_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
266 struct acm *acm = urb->context;
267 struct usb_cdc_notification *dr = urb->transfer_buffer;
Alan Cox10077d42009-06-11 12:36:09 +0100268 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 unsigned char *data;
270 int newctrl;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700271 int retval;
272 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700274 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 case 0:
276 /* success */
277 break;
278 case -ECONNRESET:
279 case -ENOENT:
280 case -ESHUTDOWN:
281 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800282 dbg("%s - urb shutting down with status: %d", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 return;
284 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800285 dbg("%s - nonzero urb status received: %d", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 goto exit;
287 }
288
289 if (!ACM_READY(acm))
290 goto exit;
291
292 data = (unsigned char *)(dr + 1);
293 switch (dr->bNotificationType) {
294
295 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
296
297 dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
298 break;
299
300 case USB_CDC_NOTIFY_SERIAL_STATE:
Alan Cox10077d42009-06-11 12:36:09 +0100301 tty = tty_port_tty_get(&acm->port);
Harvey Harrisona5abdea2008-04-29 01:03:40 -0700302 newctrl = get_unaligned_le16(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Alan Cox10077d42009-06-11 12:36:09 +0100304 if (tty) {
305 if (!acm->clocal &&
306 (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
307 dbg("calling hangup");
308 tty_hangup(tty);
309 }
310 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 }
312
313 acm->ctrlin = newctrl;
314
315 dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
316 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
317 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
318 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
319 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
320
321 break;
322
323 default:
324 dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
325 dr->bNotificationType, dr->wIndex,
326 dr->wLength, data[0], data[1]);
327 break;
328 }
329exit:
Oliver Neukum11ea8592008-06-20 11:25:57 +0200330 usb_mark_last_busy(acm->dev);
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700331 retval = usb_submit_urb (urb, GFP_ATOMIC);
332 if (retval)
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700333 dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with "
334 "result %d", __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335}
336
337/* data interface returns incoming bytes, or we got unthrottled */
David Howells7d12e782006-10-05 14:55:46 +0100338static void acm_read_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
David Kubicek61a87ad2005-11-01 18:51:34 +0100340 struct acm_rb *buf;
341 struct acm_ru *rcv = urb->context;
342 struct acm *acm = rcv->instance;
Oliver Neukum86478942006-05-13 22:50:47 +0200343 int status = urb->status;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700344
345 dbg("Entering acm_read_bulk with status %d", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Oliver Neukum11ea8592008-06-20 11:25:57 +0200347 if (!ACM_READY(acm)) {
348 dev_dbg(&acm->data->dev, "Aborting, acm not ready");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200350 }
351 usb_mark_last_busy(acm->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Oliver Neukum86478942006-05-13 22:50:47 +0200353 if (status)
Joe Perches898eb712007-10-18 03:06:30 -0700354 dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
David Kubicek61a87ad2005-11-01 18:51:34 +0100356 buf = rcv->buffer;
357 buf->size = urb->actual_length;
358
Oliver Neukum86478942006-05-13 22:50:47 +0200359 if (likely(status == 0)) {
360 spin_lock(&acm->read_lock);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200361 acm->processing++;
Oliver Neukum86478942006-05-13 22:50:47 +0200362 list_add_tail(&rcv->list, &acm->spare_read_urbs);
363 list_add_tail(&buf->list, &acm->filled_read_bufs);
364 spin_unlock(&acm->read_lock);
365 } else {
366 /* we drop the buffer due to an error */
367 spin_lock(&acm->read_lock);
368 list_add_tail(&rcv->list, &acm->spare_read_urbs);
369 list_add(&buf->list, &acm->spare_read_bufs);
370 spin_unlock(&acm->read_lock);
371 /* nevertheless the tasklet must be kicked unconditionally
372 so the queue cannot dry up */
373 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200374 if (likely(!acm->susp_count))
375 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376}
377
378static void acm_rx_tasklet(unsigned long _acm)
379{
380 struct acm *acm = (void *)_acm;
David Kubicek61a87ad2005-11-01 18:51:34 +0100381 struct acm_rb *buf;
Alan Cox10077d42009-06-11 12:36:09 +0100382 struct tty_struct *tty;
David Kubicek61a87ad2005-11-01 18:51:34 +0100383 struct acm_ru *rcv;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200384 unsigned long flags;
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100385 unsigned char throttled;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 dbg("Entering acm_rx_tasklet");
388
Alan Cox10077d42009-06-11 12:36:09 +0100389 if (!ACM_READY(acm)) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200390 dbg("acm_rx_tasklet: ACM not ready");
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100391 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200392 }
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100393
Oliver Neukum834dbca2007-03-06 10:47:04 +0100394 spin_lock_irqsave(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100395 throttled = acm->throttle;
Oliver Neukum834dbca2007-03-06 10:47:04 +0100396 spin_unlock_irqrestore(&acm->throttle_lock, flags);
Alan Cox10077d42009-06-11 12:36:09 +0100397 if (throttled) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200398 dbg("acm_rx_tasklet: throttled");
David Kubicek61a87ad2005-11-01 18:51:34 +0100399 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200400 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100401
Alan Cox10077d42009-06-11 12:36:09 +0100402 tty = tty_port_tty_get(&acm->port);
403
David Kubicek61a87ad2005-11-01 18:51:34 +0100404next_buffer:
Jarek Poplawski762f0072006-10-06 07:23:11 +0200405 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100406 if (list_empty(&acm->filled_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200407 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100408 goto urbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100410 buf = list_entry(acm->filled_read_bufs.next,
411 struct acm_rb, list);
412 list_del(&buf->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200413 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100414
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200415 dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100416
Alan Cox10077d42009-06-11 12:36:09 +0100417 if (tty) {
418 spin_lock_irqsave(&acm->throttle_lock, flags);
419 throttled = acm->throttle;
420 spin_unlock_irqrestore(&acm->throttle_lock, flags);
421 if (!throttled) {
422 tty_buffer_request_room(tty, buf->size);
423 tty_insert_flip_string(tty, buf->base, buf->size);
424 tty_flip_buffer_push(tty);
425 } else {
426 tty_kref_put(tty);
427 dbg("Throttling noticed");
428 spin_lock_irqsave(&acm->read_lock, flags);
429 list_add(&buf->list, &acm->filled_read_bufs);
430 spin_unlock_irqrestore(&acm->read_lock, flags);
431 return;
432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Jarek Poplawski762f0072006-10-06 07:23:11 +0200435 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100436 list_add(&buf->list, &acm->spare_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200437 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100438 goto next_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
David Kubicek61a87ad2005-11-01 18:51:34 +0100440urbs:
Alan Cox10077d42009-06-11 12:36:09 +0100441 tty_kref_put(tty);
442
David Kubicek61a87ad2005-11-01 18:51:34 +0100443 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{
Ming Leicdc97792008-02-24 18:41:47 +0800491 struct acm_wb *wb = urb->context;
David Brownelle5fbab52008-08-06 18:46:10 -0700492 struct acm *acm = wb->instance;
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800493 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200494
David Brownelle5fbab52008-08-06 18:46:10 -0700495 if (verbose || urb->status
496 || (urb->actual_length != urb->transfer_buffer_length))
497 dev_dbg(&acm->data->dev, "tx %d/%d bytes -- > %d\n",
498 urb->actual_length,
499 urb->transfer_buffer_length,
500 urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800502 spin_lock_irqsave(&acm->write_lock, flags);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100503 acm_write_done(acm, wb);
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800504 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200505 if (ACM_READY(acm))
506 schedule_work(&acm->work);
David Brownelle5fbab52008-08-06 18:46:10 -0700507 else
508 wake_up_interruptible(&acm->drain_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509}
510
David Howellsc4028952006-11-22 14:57:56 +0000511static void acm_softint(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
David Howellsc4028952006-11-22 14:57:56 +0000513 struct acm *acm = container_of(work, struct acm, work);
Alan Cox10077d42009-06-11 12:36:09 +0100514 struct tty_struct *tty;
David Brownelle5fbab52008-08-06 18:46:10 -0700515
516 dev_vdbg(&acm->data->dev, "tx work\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 if (!ACM_READY(acm))
518 return;
Alan Cox10077d42009-06-11 12:36:09 +0100519 tty = tty_port_tty_get(&acm->port);
520 tty_wakeup(tty);
521 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522}
523
Oliver Neukum11ea8592008-06-20 11:25:57 +0200524static void acm_waker(struct work_struct *waker)
525{
526 struct acm *acm = container_of(waker, struct acm, waker);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200527 int rv;
528
529 rv = usb_autopm_get_interface(acm->control);
530 if (rv < 0) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700531 dev_err(&acm->dev->dev, "Autopm failure in %s\n", __func__);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200532 return;
533 }
534 if (acm->delayed_wb) {
535 acm_start_wb(acm, acm->delayed_wb);
536 acm->delayed_wb = NULL;
537 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200538 usb_autopm_put_interface(acm->control);
539}
540
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541/*
542 * TTY handlers
543 */
544
545static int acm_tty_open(struct tty_struct *tty, struct file *filp)
546{
547 struct acm *acm;
548 int rv = -EINVAL;
David Kubicek61a87ad2005-11-01 18:51:34 +0100549 int i;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200550 dbg("Entering acm_tty_open.");
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100551
552 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
554 acm = acm_table[tty->index];
555 if (!acm || !acm->dev)
556 goto err_out;
557 else
558 rv = 0;
559
David Engraf28d1dfa2008-03-20 10:53:52 +0100560 set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
Alan Cox10077d42009-06-11 12:36:09 +0100561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 tty->driver_data = acm;
Alan Cox10077d42009-06-11 12:36:09 +0100563 tty_port_tty_set(&acm->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
Oliver Neukum94409cc2008-02-11 15:22:29 +0100565 if (usb_autopm_get_interface(acm->control) < 0)
566 goto early_bail;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200567 else
568 acm->control->needs_remote_wakeup = 1;
Oliver Neukum1365baf72007-10-12 17:24:28 +0200569
570 mutex_lock(&acm->mutex);
Alan Cox10077d42009-06-11 12:36:09 +0100571 if (acm->port.count++) {
Oliver Neukum1365baf72007-10-12 17:24:28 +0200572 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 goto done;
Alan Cox10077d42009-06-11 12:36:09 +0100574 }
Oliver Neukum1365baf72007-10-12 17:24:28 +0200575
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 acm->ctrlurb->dev = acm->dev;
577 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
578 dbg("usb_submit_urb(ctrl irq) failed");
579 goto bail_out;
580 }
581
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100582 if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
583 (acm->ctrl_caps & USB_CDC_CAP_LINE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 goto full_bailout;
Alan Cox10077d42009-06-11 12:36:09 +0100585
Oliver Neukum11ea8592008-06-20 11:25:57 +0200586 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
David Kubicek61a87ad2005-11-01 18:51:34 +0100588 INIT_LIST_HEAD(&acm->spare_read_urbs);
589 INIT_LIST_HEAD(&acm->spare_read_bufs);
590 INIT_LIST_HEAD(&acm->filled_read_bufs);
Oliver Neukum86478942006-05-13 22:50:47 +0200591 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100592 list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
593 }
Oliver Neukum86478942006-05-13 22:50:47 +0200594 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100595 list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
596 }
597
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100598 acm->throttle = 0;
599
David Kubicek61a87ad2005-11-01 18:51:34 +0100600 tasklet_schedule(&acm->urb_task);
Alan Cox10077d42009-06-11 12:36:09 +0100601 rv = tty_port_block_til_ready(&acm->port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602done:
Oliver Neukum1365baf72007-10-12 17:24:28 +0200603 mutex_unlock(&acm->mutex);
Alexey Dobriyan74573ee2008-08-20 16:56:04 -0700604err_out:
Oliver Neukum94409cc2008-02-11 15:22:29 +0100605 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 return rv;
607
608full_bailout:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 usb_kill_urb(acm->ctrlurb);
610bail_out:
Oliver Neukum1365baf72007-10-12 17:24:28 +0200611 usb_autopm_put_interface(acm->control);
Alan Cox10077d42009-06-11 12:36:09 +0100612 acm->port.count--;
Oliver Neukum1365baf72007-10-12 17:24:28 +0200613 mutex_unlock(&acm->mutex);
Oliver Neukum94409cc2008-02-11 15:22:29 +0100614early_bail:
615 mutex_unlock(&open_mutex);
Alan Cox10077d42009-06-11 12:36:09 +0100616 tty_port_tty_set(&acm->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 return -EIO;
618}
619
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700620static void acm_tty_unregister(struct acm *acm)
621{
Alan Cox10077d42009-06-11 12:36:09 +0100622 int i, nr;
David Kubicek61a87ad2005-11-01 18:51:34 +0100623
Oliver Neukum86478942006-05-13 22:50:47 +0200624 nr = acm->rx_buflimit;
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700625 tty_unregister_device(acm_tty_driver, acm->minor);
626 usb_put_intf(acm->control);
627 acm_table[acm->minor] = NULL;
628 usb_free_urb(acm->ctrlurb);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100629 for (i = 0; i < ACM_NW; i++)
630 usb_free_urb(acm->wb[i].urb);
Oliver Neukum86478942006-05-13 22:50:47 +0200631 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100632 usb_free_urb(acm->ru[i].urb);
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100633 kfree(acm->country_codes);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700634 kfree(acm);
635}
636
David Brownelle5fbab52008-08-06 18:46:10 -0700637static int acm_tty_chars_in_buffer(struct tty_struct *tty);
638
Alan Cox10077d42009-06-11 12:36:09 +0100639static void acm_port_down(struct acm *acm, int drain)
640{
641 int i, nr = acm->rx_buflimit;
642 mutex_lock(&open_mutex);
643 if (acm->dev) {
644 usb_autopm_get_interface(acm->control);
645 acm_set_control(acm, acm->ctrlout = 0);
646 /* try letting the last writes drain naturally */
647 if (drain) {
648 wait_event_interruptible_timeout(acm->drain_wait,
649 (ACM_NW == acm_wb_is_avail(acm)) || !acm->dev,
650 ACM_CLOSE_TIMEOUT * HZ);
651 }
652 usb_kill_urb(acm->ctrlurb);
653 for (i = 0; i < ACM_NW; i++)
654 usb_kill_urb(acm->wb[i].urb);
655 for (i = 0; i < nr; i++)
656 usb_kill_urb(acm->ru[i].urb);
657 acm->control->needs_remote_wakeup = 0;
658 usb_autopm_put_interface(acm->control);
659 }
660 mutex_unlock(&open_mutex);
661}
662
663static void acm_tty_hangup(struct tty_struct *tty)
664{
665 struct acm *acm = tty->driver_data;
666 tty_port_hangup(&acm->port);
667 acm_port_down(acm, 0);
668}
669
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670static void acm_tty_close(struct tty_struct *tty, struct file *filp)
671{
672 struct acm *acm = tty->driver_data;
673
Alan Cox10077d42009-06-11 12:36:09 +0100674 /* Perform the closing process and see if we need to do the hardware
675 shutdown */
676 if (tty_port_close_start(&acm->port, tty, filp) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 return;
Alan Cox10077d42009-06-11 12:36:09 +0100678 acm_port_down(acm, 0);
679 tty_port_close_end(&acm->port, tty);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100680 mutex_lock(&open_mutex);
Alan Cox10077d42009-06-11 12:36:09 +0100681 tty_port_tty_set(&acm->port, NULL);
682 if (!acm->dev)
683 acm_tty_unregister(acm);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100684 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685}
686
687static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
688{
689 struct acm *acm = tty->driver_data;
690 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200691 unsigned long flags;
692 int wbn;
693 struct acm_wb *wb;
694
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200695 dbg("Entering acm_tty_write to write %d bytes,", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
697 if (!ACM_READY(acm))
698 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 if (!count)
700 return 0;
701
Oliver Neukum884b6002005-04-21 21:28:02 +0200702 spin_lock_irqsave(&acm->write_lock, flags);
703 if ((wbn = acm_wb_alloc(acm)) < 0) {
704 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200705 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200707 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Oliver Neukum884b6002005-04-21 21:28:02 +0200709 count = (count > acm->writesize) ? acm->writesize : count;
710 dbg("Get %d bytes...", count);
711 memcpy(wb->buf, buf, count);
712 wb->len = count;
713 spin_unlock_irqrestore(&acm->write_lock, flags);
714
David Engrafe4cf3aa2008-03-20 10:01:34 +0100715 if ((stat = acm_write_start(acm, wbn)) < 0)
Oliver Neukum884b6002005-04-21 21:28:02 +0200716 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 return count;
718}
719
720static int acm_tty_write_room(struct tty_struct *tty)
721{
722 struct acm *acm = tty->driver_data;
723 if (!ACM_READY(acm))
724 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200725 /*
726 * Do not let the line discipline to know that we have a reserve,
727 * or it might get too enthusiastic.
728 */
David Brownell934da462008-08-06 18:44:12 -0700729 return acm_wb_is_avail(acm) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730}
731
732static int acm_tty_chars_in_buffer(struct tty_struct *tty)
733{
734 struct acm *acm = tty->driver_data;
735 if (!ACM_READY(acm))
736 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200737 /*
738 * This is inaccurate (overcounts), but it works.
739 */
Oliver Neukum86478942006-05-13 22:50:47 +0200740 return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741}
742
743static void acm_tty_throttle(struct tty_struct *tty)
744{
745 struct acm *acm = tty->driver_data;
746 if (!ACM_READY(acm))
747 return;
748 spin_lock_bh(&acm->throttle_lock);
749 acm->throttle = 1;
750 spin_unlock_bh(&acm->throttle_lock);
751}
752
753static void acm_tty_unthrottle(struct tty_struct *tty)
754{
755 struct acm *acm = tty->driver_data;
756 if (!ACM_READY(acm))
757 return;
758 spin_lock_bh(&acm->throttle_lock);
759 acm->throttle = 0;
760 spin_unlock_bh(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100761 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762}
763
Alan Cox9e989662008-07-22 11:18:03 +0100764static int acm_tty_break_ctl(struct tty_struct *tty, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
766 struct acm *acm = tty->driver_data;
Alan Cox9e989662008-07-22 11:18:03 +0100767 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 if (!ACM_READY(acm))
Alan Cox9e989662008-07-22 11:18:03 +0100769 return -EINVAL;
770 retval = acm_send_break(acm, state ? 0xffff : 0);
771 if (retval < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 dbg("send break failed");
Alan Cox9e989662008-07-22 11:18:03 +0100773 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774}
775
776static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file)
777{
778 struct acm *acm = tty->driver_data;
779
780 if (!ACM_READY(acm))
781 return -EINVAL;
782
783 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
784 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
785 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
786 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
787 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
788 TIOCM_CTS;
789}
790
791static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
792 unsigned int set, unsigned int clear)
793{
794 struct acm *acm = tty->driver_data;
795 unsigned int newctrl;
796
797 if (!ACM_READY(acm))
798 return -EINVAL;
799
800 newctrl = acm->ctrlout;
801 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
802 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
803
804 newctrl = (newctrl & ~clear) | set;
805
806 if (acm->ctrlout == newctrl)
807 return 0;
808 return acm_set_control(acm, acm->ctrlout = newctrl);
809}
810
811static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
812{
813 struct acm *acm = tty->driver_data;
814
815 if (!ACM_READY(acm))
816 return -EINVAL;
817
818 return -ENOIOCTLCMD;
819}
820
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100821static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 0, 50, 75, 110, 134, 150, 200, 300, 600,
823 1200, 1800, 2400, 4800, 9600, 19200, 38400,
824 57600, 115200, 230400, 460800, 500000, 576000,
825 921600, 1000000, 1152000, 1500000, 2000000,
826 2500000, 3000000, 3500000, 4000000
827};
828
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100829static const __u8 acm_tty_size[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 5, 6, 7, 8
831};
832
Alan Cox606d0992006-12-08 02:38:45 -0800833static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
835 struct acm *acm = tty->driver_data;
Alan Cox606d0992006-12-08 02:38:45 -0800836 struct ktermios *termios = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 struct usb_cdc_line_coding newline;
838 int newctrl = acm->ctrlout;
839
840 if (!ACM_READY(acm))
841 return;
842
843 newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
844 (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
845 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
846 newline.bParityType = termios->c_cflag & PARENB ?
847 (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
848 newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
849
850 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
851
852 if (!newline.dwDTERate) {
853 newline.dwDTERate = acm->line.dwDTERate;
854 newctrl &= ~ACM_CTRL_DTR;
855 } else newctrl |= ACM_CTRL_DTR;
856
857 if (newctrl != acm->ctrlout)
858 acm_set_control(acm, acm->ctrlout = newctrl);
859
860 if (memcmp(&acm->line, &newline, sizeof newline)) {
861 memcpy(&acm->line, &newline, sizeof newline);
862 dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
863 newline.bCharFormat, newline.bParityType,
864 newline.bDataBits);
865 acm_set_line(acm, &acm->line);
866 }
867}
868
869/*
870 * USB probe and disconnect routines.
871 */
872
Oliver Neukum830f4022008-06-25 14:17:16 +0200873/* Little helpers: write/read buffers free */
Oliver Neukum884b6002005-04-21 21:28:02 +0200874static void acm_write_buffers_free(struct acm *acm)
875{
876 int i;
877 struct acm_wb *wb;
Oliver Neukuma496c642008-10-21 10:39:04 +0200878 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
Oliver Neukum884b6002005-04-21 21:28:02 +0200879
Oliver Neukum86478942006-05-13 22:50:47 +0200880 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukuma496c642008-10-21 10:39:04 +0200881 usb_buffer_free(usb_dev, acm->writesize, wb->buf, wb->dmah);
Oliver Neukum884b6002005-04-21 21:28:02 +0200882 }
883}
884
Oliver Neukum830f4022008-06-25 14:17:16 +0200885static void acm_read_buffers_free(struct acm *acm)
886{
887 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
888 int i, n = acm->rx_buflimit;
889
890 for (i = 0; i < n; i++)
891 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
892}
893
Oliver Neukum884b6002005-04-21 21:28:02 +0200894/* Little helper: write buffers allocate */
895static int acm_write_buffers_alloc(struct acm *acm)
896{
897 int i;
898 struct acm_wb *wb;
899
Oliver Neukum86478942006-05-13 22:50:47 +0200900 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200901 wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
902 &wb->dmah);
903 if (!wb->buf) {
904 while (i != 0) {
905 --i;
906 --wb;
907 usb_buffer_free(acm->dev, acm->writesize,
908 wb->buf, wb->dmah);
909 }
910 return -ENOMEM;
911 }
912 }
913 return 0;
914}
915
Alan Cox10077d42009-06-11 12:36:09 +0100916static int acm_probe(struct usb_interface *intf,
917 const struct usb_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918{
919 struct usb_cdc_union_desc *union_header = NULL;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100920 struct usb_cdc_country_functional_desc *cfd = NULL;
David Brownellc6dbf552008-04-13 14:00:44 -0700921 unsigned char *buffer = intf->altsetting->extra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 int buflen = intf->altsetting->extralen;
923 struct usb_interface *control_interface;
924 struct usb_interface *data_interface;
925 struct usb_endpoint_descriptor *epctrl;
926 struct usb_endpoint_descriptor *epread;
927 struct usb_endpoint_descriptor *epwrite;
928 struct usb_device *usb_dev = interface_to_usbdev(intf);
929 struct acm *acm;
930 int minor;
931 int ctrlsize,readsize;
932 u8 *buf;
933 u8 ac_management_function = 0;
934 u8 call_management_function = 0;
935 int call_interface_num = -1;
936 int data_interface_num;
937 unsigned long quirks;
Oliver Neukum86478942006-05-13 22:50:47 +0200938 int num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +0100939 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Oliver Neukum86478942006-05-13 22:50:47 +0200941 /* normal quirks */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 quirks = (unsigned long)id->driver_info;
Oliver Neukum86478942006-05-13 22:50:47 +0200943 num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
944
945 /* handle quirks deadly to normal probing*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 if (quirks == NO_UNION_NORMAL) {
947 data_interface = usb_ifnum_to_if(usb_dev, 1);
948 control_interface = usb_ifnum_to_if(usb_dev, 0);
949 goto skip_normal_probe;
950 }
951
952 /* normal probing*/
953 if (!buffer) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700954 dev_err(&intf->dev, "Weird descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 return -EINVAL;
956 }
957
958 if (!buflen) {
959 if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
Joe Perches898eb712007-10-18 03:06:30 -0700960 dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 buflen = intf->cur_altsetting->endpoint->extralen;
962 buffer = intf->cur_altsetting->endpoint->extra;
963 } else {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700964 dev_err(&intf->dev,
965 "Zero length descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 return -EINVAL;
967 }
968 }
969
970 while (buflen > 0) {
971 if (buffer [1] != USB_DT_CS_INTERFACE) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700972 dev_err(&intf->dev, "skipping garbage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 goto next_desc;
974 }
975
976 switch (buffer [2]) {
977 case USB_CDC_UNION_TYPE: /* we've found it */
978 if (union_header) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700979 dev_err(&intf->dev, "More than one "
980 "union descriptor, "
981 "skipping ...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 goto next_desc;
983 }
984 union_header = (struct usb_cdc_union_desc *)
985 buffer;
986 break;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100987 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
988 cfd = (struct usb_cdc_country_functional_desc *)buffer;
989 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 case USB_CDC_HEADER_TYPE: /* maybe check version */
991 break; /* for now we ignore it */
992 case USB_CDC_ACM_TYPE:
993 ac_management_function = buffer[3];
994 break;
995 case USB_CDC_CALL_MANAGEMENT_TYPE:
996 call_management_function = buffer[3];
997 call_interface_num = buffer[4];
998 if ((call_management_function & 3) != 3)
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700999 dev_err(&intf->dev, "This device "
1000 "cannot do calls on its own. "
1001 "It is no modem.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 default:
David Brownellc6dbf552008-04-13 14:00:44 -07001004 /* there are LOTS more CDC descriptors that
1005 * could legitimately be found here.
1006 */
1007 dev_dbg(&intf->dev, "Ignoring descriptor: "
1008 "type %02x, length %d\n",
1009 buffer[2], buffer[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 break;
1011 }
1012next_desc:
1013 buflen -= buffer[0];
1014 buffer += buffer[0];
1015 }
1016
1017 if (!union_header) {
1018 if (call_interface_num > 0) {
Joe Perches898eb712007-10-18 03:06:30 -07001019 dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
1021 control_interface = intf;
1022 } else {
Joe Perches898eb712007-10-18 03:06:30 -07001023 dev_dbg(&intf->dev,"No union descriptor, giving up\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 return -ENODEV;
1025 }
1026 } else {
1027 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
1028 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
1029 if (!control_interface || !data_interface) {
Joe Perches898eb712007-10-18 03:06:30 -07001030 dev_dbg(&intf->dev,"no interfaces\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 return -ENODEV;
1032 }
1033 }
1034
1035 if (data_interface_num != call_interface_num)
Joe Perchesdc0d5c12007-12-17 11:40:18 -08001036 dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
1038skip_normal_probe:
1039
1040 /*workaround for switched interfaces */
1041 if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
1042 if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
1043 struct usb_interface *t;
Joe Perches898eb712007-10-18 03:06:30 -07001044 dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
1046 t = control_interface;
1047 control_interface = data_interface;
1048 data_interface = t;
1049 } else {
1050 return -EINVAL;
1051 }
1052 }
Alan Stern74da5d62007-08-02 13:29:10 -04001053
1054 /* Accept probe requests only for the control interface */
1055 if (intf != control_interface)
1056 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
1058 if (usb_interface_claimed(data_interface)) { /* valid in this context */
Joe Perches898eb712007-10-18 03:06:30 -07001059 dev_dbg(&intf->dev,"The data interface isn't available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return -EBUSY;
1061 }
1062
1063
1064 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
1065 return -EINVAL;
1066
1067 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
1068 epread = &data_interface->cur_altsetting->endpoint[0].desc;
1069 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
1070
1071
1072 /* workaround for switched endpoints */
Luiz Fernando N. Capitulino45aea702006-10-26 13:02:48 -03001073 if (!usb_endpoint_dir_in(epread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 /* descriptors are swapped */
1075 struct usb_endpoint_descriptor *t;
Joe Perches898eb712007-10-18 03:06:30 -07001076 dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
1078 t = epread;
1079 epread = epwrite;
1080 epwrite = t;
1081 }
1082 dbg("interfaces are valid");
1083 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
1084
1085 if (minor == ACM_TTY_MINORS) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001086 dev_err(&intf->dev, "no more free acm devices\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 return -ENODEV;
1088 }
1089
Oliver Neukum46f116e2005-10-24 22:42:35 +02001090 if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
Joe Perches898eb712007-10-18 03:06:30 -07001091 dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 goto alloc_fail;
1093 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
1095 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
Oliver Neukum86478942006-05-13 22:50:47 +02001096 readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001097 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 acm->control = control_interface;
1099 acm->data = data_interface;
1100 acm->minor = minor;
1101 acm->dev = usb_dev;
1102 acm->ctrl_caps = ac_management_function;
1103 acm->ctrlsize = ctrlsize;
1104 acm->readsize = readsize;
Oliver Neukum86478942006-05-13 22:50:47 +02001105 acm->rx_buflimit = num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +01001106 acm->urb_task.func = acm_rx_tasklet;
1107 acm->urb_task.data = (unsigned long) acm;
David Howellsc4028952006-11-22 14:57:56 +00001108 INIT_WORK(&acm->work, acm_softint);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001109 INIT_WORK(&acm->waker, acm_waker);
David Brownelle5fbab52008-08-06 18:46:10 -07001110 init_waitqueue_head(&acm->drain_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 spin_lock_init(&acm->throttle_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +02001112 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +01001113 spin_lock_init(&acm->read_lock);
Oliver Neukum1365baf72007-10-12 17:24:28 +02001114 mutex_init(&acm->mutex);
David Kubicek61a87ad2005-11-01 18:51:34 +01001115 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Alan Cox739e0282009-06-11 12:27:50 +01001116 tty_port_init(&acm->port);
1117 acm->port.ops = &acm_port_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
1119 buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
1120 if (!buf) {
Joe Perches898eb712007-10-18 03:06:30 -07001121 dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 goto alloc_fail2;
1123 }
1124 acm->ctrl_buffer = buf;
1125
Oliver Neukum884b6002005-04-21 21:28:02 +02001126 if (acm_write_buffers_alloc(acm) < 0) {
Joe Perches898eb712007-10-18 03:06:30 -07001127 dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 goto alloc_fail4;
1129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
1131 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
1132 if (!acm->ctrlurb) {
Joe Perches898eb712007-10-18 03:06:30 -07001133 dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 goto alloc_fail5;
1135 }
Oliver Neukum86478942006-05-13 22:50:47 +02001136 for (i = 0; i < num_rx_buf; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +01001137 struct acm_ru *rcv = &(acm->ru[i]);
1138
1139 if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
Joe Perches898eb712007-10-18 03:06:30 -07001140 dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n");
David Kubicek61a87ad2005-11-01 18:51:34 +01001141 goto alloc_fail7;
1142 }
1143
1144 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1145 rcv->instance = acm;
1146 }
Oliver Neukum86478942006-05-13 22:50:47 +02001147 for (i = 0; i < num_rx_buf; i++) {
David Brownell672c4e12008-08-06 18:41:12 -07001148 struct acm_rb *rb = &(acm->rb[i]);
David Kubicek61a87ad2005-11-01 18:51:34 +01001149
David Brownell672c4e12008-08-06 18:41:12 -07001150 rb->base = usb_buffer_alloc(acm->dev, readsize,
1151 GFP_KERNEL, &rb->dma);
1152 if (!rb->base) {
Joe Perches898eb712007-10-18 03:06:30 -07001153 dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
David Kubicek61a87ad2005-11-01 18:51:34 +01001154 goto alloc_fail7;
1155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 }
David Engrafe4cf3aa2008-03-20 10:01:34 +01001157 for(i = 0; i < ACM_NW; i++)
1158 {
1159 struct acm_wb *snd = &(acm->wb[i]);
1160
1161 if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) {
1162 dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)");
1163 goto alloc_fail7;
1164 }
1165
1166 usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
1167 NULL, acm->writesize, acm_write_bulk, snd);
1168 snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1169 snd->instance = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 }
1171
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001172 usb_set_intfdata (intf, acm);
1173
1174 i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
1175 if (i < 0)
1176 goto alloc_fail8;
1177
1178 if (cfd) { /* export the country data */
1179 acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
1180 if (!acm->country_codes)
1181 goto skip_countries;
1182 acm->country_code_size = cfd->bLength - 4;
1183 memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4);
1184 acm->country_rel_date = cfd->iCountryCodeRelDate;
1185
1186 i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
1187 if (i < 0) {
1188 kfree(acm->country_codes);
1189 goto skip_countries;
1190 }
1191
1192 i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
1193 if (i < 0) {
1194 kfree(acm->country_codes);
1195 goto skip_countries;
1196 }
1197 }
1198
1199skip_countries:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
1201 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
1202 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1203 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
1204
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
1206
1207 acm_set_control(acm, acm->ctrlout);
1208
1209 acm->line.dwDTERate = cpu_to_le32(9600);
1210 acm->line.bDataBits = 8;
1211 acm_set_line(acm, &acm->line);
1212
1213 usb_driver_claim_interface(&acm_driver, data_interface, acm);
David Brownell672c4e12008-08-06 18:41:12 -07001214 usb_set_intfdata(data_interface, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001216 usb_get_intf(control_interface);
1217 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
1219 acm_table[minor] = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001221 return 0;
1222alloc_fail8:
David Engrafe4cf3aa2008-03-20 10:01:34 +01001223 for (i = 0; i < ACM_NW; i++)
1224 usb_free_urb(acm->wb[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225alloc_fail7:
Oliver Neukum830f4022008-06-25 14:17:16 +02001226 acm_read_buffers_free(acm);
Oliver Neukum86478942006-05-13 22:50:47 +02001227 for (i = 0; i < num_rx_buf; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001228 usb_free_urb(acm->ru[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 usb_free_urb(acm->ctrlurb);
1230alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001231 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232alloc_fail4:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
1234alloc_fail2:
1235 kfree(acm);
1236alloc_fail:
1237 return -ENOMEM;
1238}
1239
Oliver Neukum1365baf72007-10-12 17:24:28 +02001240static void stop_data_traffic(struct acm *acm)
1241{
1242 int i;
Oliver Neukum11ea8592008-06-20 11:25:57 +02001243 dbg("Entering stop_data_traffic");
Oliver Neukum1365baf72007-10-12 17:24:28 +02001244
1245 tasklet_disable(&acm->urb_task);
1246
1247 usb_kill_urb(acm->ctrlurb);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001248 for(i = 0; i < ACM_NW; i++)
1249 usb_kill_urb(acm->wb[i].urb);
Oliver Neukum1365baf72007-10-12 17:24:28 +02001250 for (i = 0; i < acm->rx_buflimit; i++)
1251 usb_kill_urb(acm->ru[i].urb);
1252
Oliver Neukum1365baf72007-10-12 17:24:28 +02001253 tasklet_enable(&acm->urb_task);
1254
1255 cancel_work_sync(&acm->work);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001256 cancel_work_sync(&acm->waker);
Oliver Neukum1365baf72007-10-12 17:24:28 +02001257}
1258
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259static void acm_disconnect(struct usb_interface *intf)
1260{
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001261 struct acm *acm = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 struct usb_device *usb_dev = interface_to_usbdev(intf);
Alan Cox10077d42009-06-11 12:36:09 +01001263 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
David Brownell672c4e12008-08-06 18:41:12 -07001265 /* sibling interface is already cleaning up */
1266 if (!acm)
Oliver Neukum86067eea2006-01-08 12:39:13 +01001267 return;
David Brownell672c4e12008-08-06 18:41:12 -07001268
1269 mutex_lock(&open_mutex);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001270 if (acm->country_codes){
Alan Stern74da5d62007-08-02 13:29:10 -04001271 device_remove_file(&acm->control->dev,
1272 &dev_attr_wCountryCodes);
1273 device_remove_file(&acm->control->dev,
1274 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001275 }
Alan Stern74da5d62007-08-02 13:29:10 -04001276 device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 acm->dev = NULL;
Oliver Neukum86067eea2006-01-08 12:39:13 +01001278 usb_set_intfdata(acm->control, NULL);
1279 usb_set_intfdata(acm->data, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
Oliver Neukum1365baf72007-10-12 17:24:28 +02001281 stop_data_traffic(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
Oliver Neukum884b6002005-04-21 21:28:02 +02001283 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Oliver Neukum830f4022008-06-25 14:17:16 +02001285 acm_read_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286
Oliver Neukum830f4022008-06-25 14:17:16 +02001287 usb_driver_release_interface(&acm_driver, intf == acm->control ?
1288 acm->data : acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
Alan Cox10077d42009-06-11 12:36:09 +01001290 if (acm->port.count == 0) {
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001291 acm_tty_unregister(acm);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001292 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 return;
1294 }
1295
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001296 mutex_unlock(&open_mutex);
Alan Cox10077d42009-06-11 12:36:09 +01001297 tty = tty_port_tty_get(&acm->port);
1298 if (tty) {
1299 tty_hangup(tty);
1300 tty_kref_put(tty);
1301 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302}
1303
Oliver Neukum35758582008-07-01 19:10:08 +02001304#ifdef CONFIG_PM
Oliver Neukum1365baf72007-10-12 17:24:28 +02001305static int acm_suspend(struct usb_interface *intf, pm_message_t message)
1306{
1307 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001308 int cnt;
Oliver Neukum1365baf72007-10-12 17:24:28 +02001309
Alan Stern65bfd292008-11-25 16:39:18 -05001310 if (message.event & PM_EVENT_AUTO) {
Oliver Neukum11ea8592008-06-20 11:25:57 +02001311 int b;
1312
1313 spin_lock_irq(&acm->read_lock);
1314 spin_lock(&acm->write_lock);
1315 b = acm->processing + acm->transmitting;
1316 spin_unlock(&acm->write_lock);
1317 spin_unlock_irq(&acm->read_lock);
1318 if (b)
1319 return -EBUSY;
1320 }
1321
1322 spin_lock_irq(&acm->read_lock);
1323 spin_lock(&acm->write_lock);
1324 cnt = acm->susp_count++;
1325 spin_unlock(&acm->write_lock);
1326 spin_unlock_irq(&acm->read_lock);
1327
1328 if (cnt)
Oliver Neukum1365baf72007-10-12 17:24:28 +02001329 return 0;
1330 /*
1331 we treat opened interfaces differently,
1332 we must guard against open
1333 */
1334 mutex_lock(&acm->mutex);
1335
Alan Cox10077d42009-06-11 12:36:09 +01001336 if (acm->port.count)
Oliver Neukum1365baf72007-10-12 17:24:28 +02001337 stop_data_traffic(acm);
1338
1339 mutex_unlock(&acm->mutex);
1340 return 0;
1341}
1342
1343static int acm_resume(struct usb_interface *intf)
1344{
1345 struct acm *acm = usb_get_intfdata(intf);
1346 int rv = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +02001347 int cnt;
Oliver Neukum1365baf72007-10-12 17:24:28 +02001348
Oliver Neukum11ea8592008-06-20 11:25:57 +02001349 spin_lock_irq(&acm->read_lock);
1350 acm->susp_count -= 1;
1351 cnt = acm->susp_count;
1352 spin_unlock_irq(&acm->read_lock);
1353
1354 if (cnt)
Oliver Neukum1365baf72007-10-12 17:24:28 +02001355 return 0;
1356
1357 mutex_lock(&acm->mutex);
Alan Cox10077d42009-06-11 12:36:09 +01001358 if (acm->port.count) {
Oliver Neukum1365baf72007-10-12 17:24:28 +02001359 rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
1360 if (rv < 0)
Oliver Neukum11ea8592008-06-20 11:25:57 +02001361 goto err_out;
Oliver Neukum1365baf72007-10-12 17:24:28 +02001362
1363 tasklet_schedule(&acm->urb_task);
1364 }
1365
1366err_out:
1367 mutex_unlock(&acm->mutex);
1368 return rv;
1369}
Oliver Neukum35758582008-07-01 19:10:08 +02001370
1371#endif /* CONFIG_PM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372/*
1373 * USB driver structure.
1374 */
1375
1376static struct usb_device_id acm_ids[] = {
1377 /* quirky and broken devices */
1378 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1379 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1380 },
Andrey Arapovb0e2a702007-07-04 17:11:42 +02001381 { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
1382 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1383 },
Andrew Lunn0f9c7b42008-12-23 17:31:23 +01001384 { USB_DEVICE(0x0e8d, 0x3329), /* MediaTek Inc GPS */
1385 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1386 },
Masahito Omote8753e652005-07-29 12:17:25 -07001387 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1388 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1389 },
Chris Malley91a9c922006-10-03 10:08:28 +01001390 { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
1391 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1392 },
Alan Cox7abcf202009-04-06 17:35:01 +01001393 { USB_DEVICE(0x0ace, 0x1602), /* ZyDAS 56K USB MODEM */
1394 .driver_info = SINGLE_RX_URB,
1395 },
Oliver Neukum86478942006-05-13 22:50:47 +02001396 { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
1397 .driver_info = SINGLE_RX_URB, /* firmware bug */
1398 },
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001399 { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
1400 .driver_info = SINGLE_RX_URB, /* firmware bug */
1401 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001402 { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
1403 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1404 },
Iain McFarlane6149ed52008-05-04 00:13:49 +01001405 { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */
1406 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1407 },
Eric Sandeenc8fd2c32008-08-14 08:25:40 -05001408 { USB_DEVICE(0x0572, 0x1321), /* Conexant USB MODEM CX93010 */
1409 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1410 },
Alan Coxc89c60e2009-01-11 19:53:10 +00001411 { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */
1412 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1413 },
Xiao Kaijiancab98a02009-05-08 00:48:23 +08001414 { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */
1415 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1416 },
Dmitriy Taychenachev155df652009-02-25 12:36:51 +08001417 { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
1418 },
Adam Richterc332b4e2009-02-18 16:17:15 -08001419 { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */
1420 .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on
1421 data interface instead of
1422 communications interface.
1423 Maybe we should define a new
1424 quirk for this. */
1425 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001426
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 /* control interfaces with various AT-command sets */
1428 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1429 USB_CDC_ACM_PROTO_AT_V25TER) },
1430 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1431 USB_CDC_ACM_PROTO_AT_PCCA101) },
1432 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1433 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1434 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1435 USB_CDC_ACM_PROTO_AT_GSM) },
1436 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1437 USB_CDC_ACM_PROTO_AT_3G ) },
1438 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1439 USB_CDC_ACM_PROTO_AT_CDMA) },
1440
1441 /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */
1442 { }
1443};
1444
1445MODULE_DEVICE_TABLE (usb, acm_ids);
1446
1447static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 .name = "cdc_acm",
1449 .probe = acm_probe,
1450 .disconnect = acm_disconnect,
Oliver Neukum35758582008-07-01 19:10:08 +02001451#ifdef CONFIG_PM
Oliver Neukum1365baf72007-10-12 17:24:28 +02001452 .suspend = acm_suspend,
1453 .resume = acm_resume,
Oliver Neukum35758582008-07-01 19:10:08 +02001454#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 .id_table = acm_ids,
Oliver Neukum35758582008-07-01 19:10:08 +02001456#ifdef CONFIG_PM
Oliver Neukum1365baf72007-10-12 17:24:28 +02001457 .supports_autosuspend = 1,
Oliver Neukum35758582008-07-01 19:10:08 +02001458#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459};
1460
1461/*
1462 * TTY driver structures.
1463 */
1464
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001465static const struct tty_operations acm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 .open = acm_tty_open,
1467 .close = acm_tty_close,
Alan Cox10077d42009-06-11 12:36:09 +01001468 .hangup = acm_tty_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 .write = acm_tty_write,
1470 .write_room = acm_tty_write_room,
1471 .ioctl = acm_tty_ioctl,
1472 .throttle = acm_tty_throttle,
1473 .unthrottle = acm_tty_unthrottle,
1474 .chars_in_buffer = acm_tty_chars_in_buffer,
1475 .break_ctl = acm_tty_break_ctl,
1476 .set_termios = acm_tty_set_termios,
1477 .tiocmget = acm_tty_tiocmget,
1478 .tiocmset = acm_tty_tiocmset,
1479};
1480
1481/*
1482 * Init / exit.
1483 */
1484
1485static int __init acm_init(void)
1486{
1487 int retval;
1488 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1489 if (!acm_tty_driver)
1490 return -ENOMEM;
1491 acm_tty_driver->owner = THIS_MODULE,
1492 acm_tty_driver->driver_name = "acm",
1493 acm_tty_driver->name = "ttyACM",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 acm_tty_driver->major = ACM_TTY_MAJOR,
1495 acm_tty_driver->minor_start = 0,
1496 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1497 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001498 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 acm_tty_driver->init_termios = tty_std_termios;
1500 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1501 tty_set_operations(acm_tty_driver, &acm_ops);
1502
1503 retval = tty_register_driver(acm_tty_driver);
1504 if (retval) {
1505 put_tty_driver(acm_tty_driver);
1506 return retval;
1507 }
1508
1509 retval = usb_register(&acm_driver);
1510 if (retval) {
1511 tty_unregister_driver(acm_tty_driver);
1512 put_tty_driver(acm_tty_driver);
1513 return retval;
1514 }
1515
Greg Kroah-Hartman5909f6e2008-08-18 13:21:04 -07001516 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
1517 DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518
1519 return 0;
1520}
1521
1522static void __exit acm_exit(void)
1523{
1524 usb_deregister(&acm_driver);
1525 tty_unregister_driver(acm_tty_driver);
1526 put_tty_driver(acm_tty_driver);
1527}
1528
1529module_init(acm_init);
1530module_exit(acm_exit);
1531
1532MODULE_AUTHOR( DRIVER_AUTHOR );
1533MODULE_DESCRIPTION( DRIVER_DESC );
1534MODULE_LICENSE("GPL");
Scott James Remnante766aeb2009-04-06 17:33:18 +01001535MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR);