blob: ddeb6919253734ebcb3b7a92b6294b30bb305d52 [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
Alan Cox6e47e062009-06-11 12:37:06 +010019 * v0.12 - added TIOCM ioctls, added break handling, made struct acm
20 * kmalloced
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 * v0.13 - added termios, added hangup
22 * v0.14 - sized down struct acm
23 * v0.15 - fixed flow control again - characters could be lost
24 * v0.16 - added code for modems with swapped data and control interfaces
25 * v0.17 - added new style probing
26 * v0.18 - fixed new style probing for devices with more configurations
27 * v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan)
28 * v0.20 - switched to probing on interface (rather than device) class
29 * v0.21 - revert to probing on device for devices with multiple configs
30 * v0.22 - probe only the control interface. if usbcore doesn't choose the
31 * config we want, sysadmin changes bConfigurationValue in sysfs.
32 * v0.23 - use softirq for rx processing, as needed by tty layer
33 * v0.24 - change probe method to evaluate CDC union descriptor
David Kubicek61a87ad2005-11-01 18:51:34 +010034 * v0.25 - downstream tasks paralelized to maximize throughput
David Engrafe4cf3aa2008-03-20 10:01:34 +010035 * v0.26 - multiple write urbs, writesize increased
Linus Torvalds1da177e2005-04-16 15:20:36 -070036 */
37
38/*
39 * This program is free software; you can redistribute it and/or modify
40 * it under the terms of the GNU General Public License as published by
41 * the Free Software Foundation; either version 2 of the License, or
42 * (at your option) any later version.
43 *
44 * This program is distributed in the hope that it will be useful,
45 * but WITHOUT ANY WARRANTY; without even the implied warranty of
46 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47 * GNU General Public License for more details.
48 *
49 * You should have received a copy of the GNU General Public License
50 * along with this program; if not, write to the Free Software
51 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
52 */
53
54#undef DEBUG
David Brownelle5fbab52008-08-06 18:46:10 -070055#undef VERBOSE_DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57#include <linux/kernel.h>
58#include <linux/errno.h>
59#include <linux/init.h>
60#include <linux/slab.h>
61#include <linux/tty.h>
62#include <linux/tty_driver.h>
63#include <linux/tty_flip.h>
64#include <linux/module.h>
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010065#include <linux/mutex.h>
Alan Cox10077d42009-06-11 12:36:09 +010066#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#include <linux/usb.h>
David Brownella8c28f22006-06-13 09:57:47 -070068#include <linux/usb/cdc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#include <asm/byteorder.h>
70#include <asm/unaligned.h>
David Kubicek61a87ad2005-11-01 18:51:34 +010071#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
73#include "cdc-acm.h"
74
David Brownelle5fbab52008-08-06 18:46:10 -070075
76#define ACM_CLOSE_TIMEOUT 15 /* seconds to let writes drain */
77
Linus Torvalds1da177e2005-04-16 15:20:36 -070078/*
79 * Version Information
80 */
David Engrafe4cf3aa2008-03-20 10:01:34 +010081#define DRIVER_VERSION "v0.26"
David Kubicek61a87ad2005-11-01 18:51:34 +010082#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
Linus Torvalds1da177e2005-04-16 15:20:36 -070083#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
84
85static struct usb_driver acm_driver;
86static struct tty_driver *acm_tty_driver;
87static struct acm *acm_table[ACM_TTY_MINORS];
88
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010089static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
Alan Cox10077d42009-06-11 12:36:09 +010091#define ACM_READY(acm) (acm && acm->dev && acm->port.count)
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Alan Cox739e0282009-06-11 12:27:50 +010093static const struct tty_port_operations acm_port_ops = {
94};
95
David Brownelle5fbab52008-08-06 18:46:10 -070096#ifdef VERBOSE_DEBUG
97#define verbose 1
98#else
99#define verbose 0
100#endif
101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102/*
103 * Functions for ACM control messages.
104 */
105
Alan Cox6e47e062009-06-11 12:37:06 +0100106static int acm_ctrl_msg(struct acm *acm, int request, int value,
107 void *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108{
109 int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
110 request, USB_RT_ACM, value,
111 acm->control->altsetting[0].desc.bInterfaceNumber,
112 buf, len, 5000);
Alan Cox6e47e062009-06-11 12:37:06 +0100113 dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d",
114 request, value, len, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 return retval < 0 ? retval : 0;
116}
117
118/* devices aren't required to support these requests.
119 * the cdc acm descriptor tells whether they do...
120 */
121#define acm_set_control(acm, control) \
122 acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
123#define acm_set_line(acm, line) \
124 acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
125#define acm_send_break(acm, ms) \
126 acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
127
128/*
Oliver Neukum884b6002005-04-21 21:28:02 +0200129 * Write buffer management.
130 * All of these assume proper locks taken by the caller.
131 */
132
133static int acm_wb_alloc(struct acm *acm)
134{
135 int i, wbn;
136 struct acm_wb *wb;
137
David Engrafe4cf3aa2008-03-20 10:01:34 +0100138 wbn = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200139 i = 0;
140 for (;;) {
141 wb = &acm->wb[wbn];
142 if (!wb->use) {
143 wb->use = 1;
144 return wbn;
145 }
Oliver Neukum86478942006-05-13 22:50:47 +0200146 wbn = (wbn + 1) % ACM_NW;
147 if (++i >= ACM_NW)
Oliver Neukum884b6002005-04-21 21:28:02 +0200148 return -1;
149 }
150}
151
Oliver Neukum884b6002005-04-21 21:28:02 +0200152static int acm_wb_is_avail(struct acm *acm)
153{
154 int i, n;
David Brownelle5fbab52008-08-06 18:46:10 -0700155 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200156
Oliver Neukum86478942006-05-13 22:50:47 +0200157 n = ACM_NW;
David Brownelle5fbab52008-08-06 18:46:10 -0700158 spin_lock_irqsave(&acm->write_lock, flags);
Alan Cox6e47e062009-06-11 12:37:06 +0100159 for (i = 0; i < ACM_NW; i++)
Oliver Neukum86478942006-05-13 22:50:47 +0200160 n -= acm->wb[i].use;
David Brownelle5fbab52008-08-06 18:46:10 -0700161 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200162 return n;
163}
164
Oliver Neukum884b6002005-04-21 21:28:02 +0200165/*
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800166 * Finish write. Caller must hold acm->write_lock
Oliver Neukum884b6002005-04-21 21:28:02 +0200167 */
David Engrafe4cf3aa2008-03-20 10:01:34 +0100168static void acm_write_done(struct acm *acm, struct acm_wb *wb)
Oliver Neukum884b6002005-04-21 21:28:02 +0200169{
David Engrafe4cf3aa2008-03-20 10:01:34 +0100170 wb->use = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200171 acm->transmitting--;
Oliver Neukum884b6002005-04-21 21:28:02 +0200172}
173
174/*
175 * Poke write.
Oliver Neukum11ea8592008-06-20 11:25:57 +0200176 *
177 * the caller is responsible for locking
Oliver Neukum884b6002005-04-21 21:28:02 +0200178 */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200179
180static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
181{
182 int rc;
183
184 acm->transmitting++;
185
186 wb->urb->transfer_buffer = wb->buf;
187 wb->urb->transfer_dma = wb->dmah;
188 wb->urb->transfer_buffer_length = wb->len;
189 wb->urb->dev = acm->dev;
190
Alan Cox6e47e062009-06-11 12:37:06 +0100191 rc = usb_submit_urb(wb->urb, GFP_ATOMIC);
192 if (rc < 0) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200193 dbg("usb_submit_urb(write bulk) failed: %d", rc);
194 acm_write_done(acm, wb);
195 }
196 return rc;
197}
198
David Engrafe4cf3aa2008-03-20 10:01:34 +0100199static int acm_write_start(struct acm *acm, int wbn)
Oliver Neukum884b6002005-04-21 21:28:02 +0200200{
201 unsigned long flags;
David Brownell934da462008-08-06 18:44:12 -0700202 struct acm_wb *wb = &acm->wb[wbn];
Oliver Neukum884b6002005-04-21 21:28:02 +0200203 int rc;
204
205 spin_lock_irqsave(&acm->write_lock, flags);
206 if (!acm->dev) {
David Brownell934da462008-08-06 18:44:12 -0700207 wb->use = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200208 spin_unlock_irqrestore(&acm->write_lock, flags);
209 return -ENODEV;
210 }
211
Oliver Neukum11ea8592008-06-20 11:25:57 +0200212 dbg("%s susp_count: %d", __func__, acm->susp_count);
213 if (acm->susp_count) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200214 acm->delayed_wb = wb;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200215 schedule_work(&acm->waker);
216 spin_unlock_irqrestore(&acm->write_lock, flags);
217 return 0; /* A white lie */
218 }
219 usb_mark_last_busy(acm->dev);
220
Oliver Neukum11ea8592008-06-20 11:25:57 +0200221 rc = acm_start_wb(acm, wb);
Oliver Neukum884b6002005-04-21 21:28:02 +0200222 spin_unlock_irqrestore(&acm->write_lock, flags);
223
Oliver Neukum884b6002005-04-21 21:28:02 +0200224 return rc;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200225
Oliver Neukum884b6002005-04-21 21:28:02 +0200226}
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100227/*
228 * attributes exported through sysfs
229 */
230static ssize_t show_caps
231(struct device *dev, struct device_attribute *attr, char *buf)
232{
233 struct usb_interface *intf = to_usb_interface(dev);
234 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum884b6002005-04-21 21:28:02 +0200235
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100236 return sprintf(buf, "%d", acm->ctrl_caps);
237}
238static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
239
240static ssize_t show_country_codes
241(struct device *dev, struct device_attribute *attr, char *buf)
242{
243 struct usb_interface *intf = to_usb_interface(dev);
244 struct acm *acm = usb_get_intfdata(intf);
245
246 memcpy(buf, acm->country_codes, acm->country_code_size);
247 return acm->country_code_size;
248}
249
250static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
251
252static ssize_t show_country_rel_date
253(struct device *dev, struct device_attribute *attr, char *buf)
254{
255 struct usb_interface *intf = to_usb_interface(dev);
256 struct acm *acm = usb_get_intfdata(intf);
257
258 return sprintf(buf, "%d", acm->country_rel_date);
259}
260
261static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
Oliver Neukum884b6002005-04-21 21:28:02 +0200262/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 * Interrupt handlers for various ACM device responses
264 */
265
266/* control interface reports status changes with "interrupt" transfers */
David Howells7d12e782006-10-05 14:55:46 +0100267static void acm_ctrl_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{
269 struct acm *acm = urb->context;
270 struct usb_cdc_notification *dr = urb->transfer_buffer;
Alan Cox10077d42009-06-11 12:36:09 +0100271 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 unsigned char *data;
273 int newctrl;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700274 int retval;
275 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700277 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 case 0:
279 /* success */
280 break;
281 case -ECONNRESET:
282 case -ENOENT:
283 case -ESHUTDOWN:
284 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800285 dbg("%s - urb shutting down with status: %d", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 return;
287 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800288 dbg("%s - nonzero urb status received: %d", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 goto exit;
290 }
291
292 if (!ACM_READY(acm))
293 goto exit;
294
295 data = (unsigned char *)(dr + 1);
296 switch (dr->bNotificationType) {
Alan Cox6e47e062009-06-11 12:37:06 +0100297 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
298 dbg("%s network", dr->wValue ?
299 "connected to" : "disconnected from");
300 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Alan Cox6e47e062009-06-11 12:37:06 +0100302 case USB_CDC_NOTIFY_SERIAL_STATE:
303 tty = tty_port_tty_get(&acm->port);
304 newctrl = get_unaligned_le16(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Alan Cox6e47e062009-06-11 12:37:06 +0100306 if (tty) {
307 if (!acm->clocal &&
308 (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
309 dbg("calling hangup");
310 tty_hangup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 }
Alan Cox6e47e062009-06-11 12:37:06 +0100312 tty_kref_put(tty);
313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Alan Cox6e47e062009-06-11 12:37:06 +0100315 acm->ctrlin = newctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Alan Cox6e47e062009-06-11 12:37:06 +0100317 dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
318 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',
319 acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
320 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-',
321 acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
322 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',
323 acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
324 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 break;
326
Alan Cox6e47e062009-06-11 12:37:06 +0100327 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 }
333exit:
Oliver Neukum11ea8592008-06-20 11:25:57 +0200334 usb_mark_last_busy(acm->dev);
Alan Cox6e47e062009-06-11 12:37:06 +0100335 retval = usb_submit_urb(urb, GFP_ATOMIC);
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700336 if (retval)
Greg Kroah-Hartman9908a32e92008-08-14 09:37:34 -0700337 dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with "
338 "result %d", __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;
Alan Cox10077d42009-06-11 12:36:09 +0100386 struct tty_struct *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
Alan Cox10077d42009-06-11 12:36:09 +0100393 if (!ACM_READY(acm)) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200394 dbg("acm_rx_tasklet: ACM not ready");
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100395 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200396 }
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100397
Oliver Neukum834dbca2007-03-06 10:47:04 +0100398 spin_lock_irqsave(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100399 throttled = acm->throttle;
Oliver Neukum834dbca2007-03-06 10:47:04 +0100400 spin_unlock_irqrestore(&acm->throttle_lock, flags);
Alan Cox10077d42009-06-11 12:36:09 +0100401 if (throttled) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200402 dbg("acm_rx_tasklet: throttled");
David Kubicek61a87ad2005-11-01 18:51:34 +0100403 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200404 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100405
Alan Cox10077d42009-06-11 12:36:09 +0100406 tty = tty_port_tty_get(&acm->port);
407
David Kubicek61a87ad2005-11-01 18:51:34 +0100408next_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 Cox10077d42009-06-11 12:36:09 +0100421 if (tty) {
422 spin_lock_irqsave(&acm->throttle_lock, flags);
423 throttled = acm->throttle;
424 spin_unlock_irqrestore(&acm->throttle_lock, flags);
425 if (!throttled) {
426 tty_buffer_request_room(tty, buf->size);
427 tty_insert_flip_string(tty, buf->base, buf->size);
428 tty_flip_buffer_push(tty);
429 } else {
430 tty_kref_put(tty);
431 dbg("Throttling noticed");
432 spin_lock_irqsave(&acm->read_lock, flags);
433 list_add(&buf->list, &acm->filled_read_bufs);
434 spin_unlock_irqrestore(&acm->read_lock, flags);
435 return;
436 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
Jarek Poplawski762f0072006-10-06 07:23:11 +0200439 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100440 list_add(&buf->list, &acm->spare_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200441 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100442 goto next_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
David Kubicek61a87ad2005-11-01 18:51:34 +0100444urbs:
Alan Cox10077d42009-06-11 12:36:09 +0100445 tty_kref_put(tty);
446
David Kubicek61a87ad2005-11-01 18:51:34 +0100447 while (!list_empty(&acm->spare_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200448 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100449 if (list_empty(&acm->spare_read_urbs)) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200450 acm->processing = 0;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200451 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100452 return;
453 }
454 rcv = list_entry(acm->spare_read_urbs.next,
455 struct acm_ru, list);
456 list_del(&rcv->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200457 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100458
459 buf = list_entry(acm->spare_read_bufs.next,
460 struct acm_rb, list);
461 list_del(&buf->list);
462
463 rcv->buffer = buf;
464
465 usb_fill_bulk_urb(rcv->urb, acm->dev,
466 acm->rx_endpoint,
467 buf->base,
468 acm->readsize,
469 acm_read_bulk, rcv);
470 rcv->urb->transfer_dma = buf->dma;
471 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
472
Alan Cox6e47e062009-06-11 12:37:06 +0100473 /* This shouldn't kill the driver as unsuccessful URBs are
474 returned to the free-urbs-pool and resubmited ASAP */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200475 spin_lock_irqsave(&acm->read_lock, flags);
Alan Cox6e47e062009-06-11 12:37:06 +0100476 if (acm->susp_count ||
477 usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100478 list_add(&buf->list, &acm->spare_read_bufs);
David Kubicek61a87ad2005-11-01 18:51:34 +0100479 list_add(&rcv->list, &acm->spare_read_urbs);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200480 acm->processing = 0;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200481 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100482 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200483 } else {
484 spin_unlock_irqrestore(&acm->read_lock, flags);
485 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 +0100486 }
487 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200488 spin_lock_irqsave(&acm->read_lock, flags);
489 acm->processing = 0;
490 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491}
492
493/* data interface wrote those outgoing bytes */
David Howells7d12e782006-10-05 14:55:46 +0100494static void acm_write_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
Ming Leicdc97792008-02-24 18:41:47 +0800496 struct acm_wb *wb = urb->context;
David Brownelle5fbab52008-08-06 18:46:10 -0700497 struct acm *acm = wb->instance;
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800498 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200499
David Brownelle5fbab52008-08-06 18:46:10 -0700500 if (verbose || urb->status
501 || (urb->actual_length != urb->transfer_buffer_length))
502 dev_dbg(&acm->data->dev, "tx %d/%d bytes -- > %d\n",
503 urb->actual_length,
504 urb->transfer_buffer_length,
505 urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800507 spin_lock_irqsave(&acm->write_lock, flags);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100508 acm_write_done(acm, wb);
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800509 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200510 if (ACM_READY(acm))
511 schedule_work(&acm->work);
David Brownelle5fbab52008-08-06 18:46:10 -0700512 else
513 wake_up_interruptible(&acm->drain_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514}
515
David Howellsc4028952006-11-22 14:57:56 +0000516static void acm_softint(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
David Howellsc4028952006-11-22 14:57:56 +0000518 struct acm *acm = container_of(work, struct acm, work);
Alan Cox10077d42009-06-11 12:36:09 +0100519 struct tty_struct *tty;
David Brownelle5fbab52008-08-06 18:46:10 -0700520
521 dev_vdbg(&acm->data->dev, "tx work\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 if (!ACM_READY(acm))
523 return;
Alan Cox10077d42009-06-11 12:36:09 +0100524 tty = tty_port_tty_get(&acm->port);
525 tty_wakeup(tty);
526 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527}
528
Oliver Neukum11ea8592008-06-20 11:25:57 +0200529static void acm_waker(struct work_struct *waker)
530{
531 struct acm *acm = container_of(waker, struct acm, waker);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200532 int rv;
533
534 rv = usb_autopm_get_interface(acm->control);
535 if (rv < 0) {
Greg Kroah-Hartman9908a32e92008-08-14 09:37:34 -0700536 dev_err(&acm->dev->dev, "Autopm failure in %s\n", __func__);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200537 return;
538 }
539 if (acm->delayed_wb) {
540 acm_start_wb(acm, acm->delayed_wb);
541 acm->delayed_wb = NULL;
542 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200543 usb_autopm_put_interface(acm->control);
544}
545
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546/*
547 * TTY handlers
548 */
549
550static int acm_tty_open(struct tty_struct *tty, struct file *filp)
551{
552 struct acm *acm;
553 int rv = -EINVAL;
David Kubicek61a87ad2005-11-01 18:51:34 +0100554 int i;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200555 dbg("Entering acm_tty_open.");
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100556
557 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
559 acm = acm_table[tty->index];
560 if (!acm || !acm->dev)
561 goto err_out;
562 else
563 rv = 0;
564
David Engraf28d1dfa2008-03-20 10:53:52 +0100565 set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
Alan Cox10077d42009-06-11 12:36:09 +0100566
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 tty->driver_data = acm;
Alan Cox10077d42009-06-11 12:36:09 +0100568 tty_port_tty_set(&acm->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
Oliver Neukum94409cc2008-02-11 15:22:29 +0100570 if (usb_autopm_get_interface(acm->control) < 0)
571 goto early_bail;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200572 else
573 acm->control->needs_remote_wakeup = 1;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200574
575 mutex_lock(&acm->mutex);
Alan Cox10077d42009-06-11 12:36:09 +0100576 if (acm->port.count++) {
Oliver Neukum1365baf2007-10-12 17:24:28 +0200577 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 goto done;
Alan Cox10077d42009-06-11 12:36:09 +0100579 }
Oliver Neukum1365baf2007-10-12 17:24:28 +0200580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 acm->ctrlurb->dev = acm->dev;
582 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
583 dbg("usb_submit_urb(ctrl irq) failed");
584 goto bail_out;
585 }
586
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100587 if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
588 (acm->ctrl_caps & USB_CDC_CAP_LINE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 goto full_bailout;
Alan Cox10077d42009-06-11 12:36:09 +0100590
Oliver Neukum11ea8592008-06-20 11:25:57 +0200591 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
David Kubicek61a87ad2005-11-01 18:51:34 +0100593 INIT_LIST_HEAD(&acm->spare_read_urbs);
594 INIT_LIST_HEAD(&acm->spare_read_bufs);
595 INIT_LIST_HEAD(&acm->filled_read_bufs);
Alan Cox6e47e062009-06-11 12:37:06 +0100596
597 for (i = 0; i < acm->rx_buflimit; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100598 list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
Alan Cox6e47e062009-06-11 12:37:06 +0100599 for (i = 0; i < acm->rx_buflimit; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100600 list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
David Kubicek61a87ad2005-11-01 18:51:34 +0100601
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100602 acm->throttle = 0;
603
David Kubicek61a87ad2005-11-01 18:51:34 +0100604 tasklet_schedule(&acm->urb_task);
Alan Cox10077d42009-06-11 12:36:09 +0100605 rv = tty_port_block_til_ready(&acm->port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606done:
Oliver Neukum1365baf2007-10-12 17:24:28 +0200607 mutex_unlock(&acm->mutex);
Alexey Dobriyan74573ee2008-08-20 16:56:04 -0700608err_out:
Oliver Neukum94409cc2008-02-11 15:22:29 +0100609 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 return rv;
611
612full_bailout:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 usb_kill_urb(acm->ctrlurb);
614bail_out:
Oliver Neukum1365baf2007-10-12 17:24:28 +0200615 usb_autopm_put_interface(acm->control);
Alan Cox10077d42009-06-11 12:36:09 +0100616 acm->port.count--;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200617 mutex_unlock(&acm->mutex);
Oliver Neukum94409cc2008-02-11 15:22:29 +0100618early_bail:
619 mutex_unlock(&open_mutex);
Alan Cox10077d42009-06-11 12:36:09 +0100620 tty_port_tty_set(&acm->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return -EIO;
622}
623
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700624static void acm_tty_unregister(struct acm *acm)
625{
Alan Cox10077d42009-06-11 12:36:09 +0100626 int i, nr;
David Kubicek61a87ad2005-11-01 18:51:34 +0100627
Oliver Neukum86478942006-05-13 22:50:47 +0200628 nr = acm->rx_buflimit;
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700629 tty_unregister_device(acm_tty_driver, acm->minor);
630 usb_put_intf(acm->control);
631 acm_table[acm->minor] = NULL;
632 usb_free_urb(acm->ctrlurb);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100633 for (i = 0; i < ACM_NW; i++)
634 usb_free_urb(acm->wb[i].urb);
Oliver Neukum86478942006-05-13 22:50:47 +0200635 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100636 usb_free_urb(acm->ru[i].urb);
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100637 kfree(acm->country_codes);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700638 kfree(acm);
639}
640
David Brownelle5fbab52008-08-06 18:46:10 -0700641static int acm_tty_chars_in_buffer(struct tty_struct *tty);
642
Alan Cox10077d42009-06-11 12:36:09 +0100643static void acm_port_down(struct acm *acm, int drain)
644{
645 int i, nr = acm->rx_buflimit;
646 mutex_lock(&open_mutex);
647 if (acm->dev) {
648 usb_autopm_get_interface(acm->control);
649 acm_set_control(acm, acm->ctrlout = 0);
650 /* try letting the last writes drain naturally */
651 if (drain) {
652 wait_event_interruptible_timeout(acm->drain_wait,
653 (ACM_NW == acm_wb_is_avail(acm)) || !acm->dev,
654 ACM_CLOSE_TIMEOUT * HZ);
655 }
656 usb_kill_urb(acm->ctrlurb);
657 for (i = 0; i < ACM_NW; i++)
658 usb_kill_urb(acm->wb[i].urb);
659 for (i = 0; i < nr; i++)
660 usb_kill_urb(acm->ru[i].urb);
661 acm->control->needs_remote_wakeup = 0;
662 usb_autopm_put_interface(acm->control);
663 }
664 mutex_unlock(&open_mutex);
665}
666
667static void acm_tty_hangup(struct tty_struct *tty)
668{
669 struct acm *acm = tty->driver_data;
670 tty_port_hangup(&acm->port);
671 acm_port_down(acm, 0);
672}
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674static void acm_tty_close(struct tty_struct *tty, struct file *filp)
675{
676 struct acm *acm = tty->driver_data;
677
Alan Cox10077d42009-06-11 12:36:09 +0100678 /* Perform the closing process and see if we need to do the hardware
679 shutdown */
680 if (tty_port_close_start(&acm->port, tty, filp) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 return;
Alan Cox10077d42009-06-11 12:36:09 +0100682 acm_port_down(acm, 0);
683 tty_port_close_end(&acm->port, tty);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100684 mutex_lock(&open_mutex);
Alan Cox10077d42009-06-11 12:36:09 +0100685 tty_port_tty_set(&acm->port, NULL);
686 if (!acm->dev)
687 acm_tty_unregister(acm);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100688 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689}
690
Alan Cox6e47e062009-06-11 12:37:06 +0100691static int acm_tty_write(struct tty_struct *tty,
692 const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693{
694 struct acm *acm = tty->driver_data;
695 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200696 unsigned long flags;
697 int wbn;
698 struct acm_wb *wb;
699
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200700 dbg("Entering acm_tty_write to write %d bytes,", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 if (!ACM_READY(acm))
703 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 if (!count)
705 return 0;
706
Oliver Neukum884b6002005-04-21 21:28:02 +0200707 spin_lock_irqsave(&acm->write_lock, flags);
Alan Cox6e47e062009-06-11 12:37:06 +0100708 wbn = acm_wb_alloc(acm);
709 if (wbn < 0) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200710 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200711 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200713 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
Oliver Neukum884b6002005-04-21 21:28:02 +0200715 count = (count > acm->writesize) ? acm->writesize : count;
716 dbg("Get %d bytes...", count);
717 memcpy(wb->buf, buf, count);
718 wb->len = count;
719 spin_unlock_irqrestore(&acm->write_lock, flags);
720
Alan Cox6e47e062009-06-11 12:37:06 +0100721 stat = acm_write_start(acm, wbn);
722 if (stat < 0)
Oliver Neukum884b6002005-04-21 21:28:02 +0200723 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 return count;
725}
726
727static int acm_tty_write_room(struct tty_struct *tty)
728{
729 struct acm *acm = tty->driver_data;
730 if (!ACM_READY(acm))
731 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200732 /*
733 * Do not let the line discipline to know that we have a reserve,
734 * or it might get too enthusiastic.
735 */
David Brownell934da462008-08-06 18:44:12 -0700736 return acm_wb_is_avail(acm) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737}
738
739static int acm_tty_chars_in_buffer(struct tty_struct *tty)
740{
741 struct acm *acm = tty->driver_data;
742 if (!ACM_READY(acm))
743 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200744 /*
745 * This is inaccurate (overcounts), but it works.
746 */
Oliver Neukum86478942006-05-13 22:50:47 +0200747 return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748}
749
750static void acm_tty_throttle(struct tty_struct *tty)
751{
752 struct acm *acm = tty->driver_data;
753 if (!ACM_READY(acm))
754 return;
755 spin_lock_bh(&acm->throttle_lock);
756 acm->throttle = 1;
757 spin_unlock_bh(&acm->throttle_lock);
758}
759
760static void acm_tty_unthrottle(struct tty_struct *tty)
761{
762 struct acm *acm = tty->driver_data;
763 if (!ACM_READY(acm))
764 return;
765 spin_lock_bh(&acm->throttle_lock);
766 acm->throttle = 0;
767 spin_unlock_bh(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100768 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769}
770
Alan Cox9e989662008-07-22 11:18:03 +0100771static int acm_tty_break_ctl(struct tty_struct *tty, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772{
773 struct acm *acm = tty->driver_data;
Alan Cox9e989662008-07-22 11:18:03 +0100774 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 if (!ACM_READY(acm))
Alan Cox9e989662008-07-22 11:18:03 +0100776 return -EINVAL;
777 retval = acm_send_break(acm, state ? 0xffff : 0);
778 if (retval < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 dbg("send break failed");
Alan Cox9e989662008-07-22 11:18:03 +0100780 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781}
782
783static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file)
784{
785 struct acm *acm = tty->driver_data;
786
787 if (!ACM_READY(acm))
788 return -EINVAL;
789
790 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
791 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
792 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
793 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
794 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
795 TIOCM_CTS;
796}
797
798static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
799 unsigned int set, unsigned int clear)
800{
801 struct acm *acm = tty->driver_data;
802 unsigned int newctrl;
803
804 if (!ACM_READY(acm))
805 return -EINVAL;
806
807 newctrl = acm->ctrlout;
Alan Cox6e47e062009-06-11 12:37:06 +0100808 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
809 (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
810 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
811 (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 newctrl = (newctrl & ~clear) | set;
814
815 if (acm->ctrlout == newctrl)
816 return 0;
817 return acm_set_control(acm, acm->ctrlout = newctrl);
818}
819
Alan Cox6e47e062009-06-11 12:37:06 +0100820static int acm_tty_ioctl(struct tty_struct *tty, struct file *file,
821 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822{
823 struct acm *acm = tty->driver_data;
824
825 if (!ACM_READY(acm))
826 return -EINVAL;
827
828 return -ENOIOCTLCMD;
829}
830
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100831static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 0, 50, 75, 110, 134, 150, 200, 300, 600,
833 1200, 1800, 2400, 4800, 9600, 19200, 38400,
834 57600, 115200, 230400, 460800, 500000, 576000,
835 921600, 1000000, 1152000, 1500000, 2000000,
836 2500000, 3000000, 3500000, 4000000
837};
838
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100839static const __u8 acm_tty_size[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 5, 6, 7, 8
841};
842
Alan Cox6e47e062009-06-11 12:37:06 +0100843static void acm_tty_set_termios(struct tty_struct *tty,
844 struct ktermios *termios_old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845{
846 struct acm *acm = tty->driver_data;
Alan Cox606d0992006-12-08 02:38:45 -0800847 struct ktermios *termios = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 struct usb_cdc_line_coding newline;
849 int newctrl = acm->ctrlout;
850
851 if (!ACM_READY(acm))
852 return;
853
Alan Cox6e47e062009-06-11 12:37:06 +0100854 /* FIXME: Needs to support the tty_baud interface */
855 /* FIXME: Broken on sparc */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
857 (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
858 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
859 newline.bParityType = termios->c_cflag & PARENB ?
Alan Cox6e47e062009-06-11 12:37:06 +0100860 (termios->c_cflag & PARODD ? 1 : 2) +
861 (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
Alan Cox6e47e062009-06-11 12:37:06 +0100863 /* FIXME: Needs to clear unsupported bits in the termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
865
866 if (!newline.dwDTERate) {
867 newline.dwDTERate = acm->line.dwDTERate;
868 newctrl &= ~ACM_CTRL_DTR;
Alan Cox6e47e062009-06-11 12:37:06 +0100869 } else
870 newctrl |= ACM_CTRL_DTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
872 if (newctrl != acm->ctrlout)
873 acm_set_control(acm, acm->ctrlout = newctrl);
874
875 if (memcmp(&acm->line, &newline, sizeof newline)) {
876 memcpy(&acm->line, &newline, sizeof newline);
877 dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
878 newline.bCharFormat, newline.bParityType,
879 newline.bDataBits);
880 acm_set_line(acm, &acm->line);
881 }
882}
883
884/*
885 * USB probe and disconnect routines.
886 */
887
Oliver Neukum830f4022008-06-25 14:17:16 +0200888/* Little helpers: write/read buffers free */
Oliver Neukum884b6002005-04-21 21:28:02 +0200889static void acm_write_buffers_free(struct acm *acm)
890{
891 int i;
892 struct acm_wb *wb;
Oliver Neukuma496c642008-10-21 10:39:04 +0200893 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
Oliver Neukum884b6002005-04-21 21:28:02 +0200894
Alan Cox6e47e062009-06-11 12:37:06 +0100895 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++)
Oliver Neukuma496c642008-10-21 10:39:04 +0200896 usb_buffer_free(usb_dev, acm->writesize, wb->buf, wb->dmah);
Oliver Neukum884b6002005-04-21 21:28:02 +0200897}
898
Oliver Neukum830f4022008-06-25 14:17:16 +0200899static void acm_read_buffers_free(struct acm *acm)
900{
901 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
902 int i, n = acm->rx_buflimit;
903
904 for (i = 0; i < n; i++)
Alan Cox6e47e062009-06-11 12:37:06 +0100905 usb_buffer_free(usb_dev, acm->readsize,
906 acm->rb[i].base, acm->rb[i].dma);
Oliver Neukum830f4022008-06-25 14:17:16 +0200907}
908
Oliver Neukum884b6002005-04-21 21:28:02 +0200909/* Little helper: write buffers allocate */
910static int acm_write_buffers_alloc(struct acm *acm)
911{
912 int i;
913 struct acm_wb *wb;
914
Oliver Neukum86478942006-05-13 22:50:47 +0200915 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200916 wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
917 &wb->dmah);
918 if (!wb->buf) {
919 while (i != 0) {
920 --i;
921 --wb;
922 usb_buffer_free(acm->dev, acm->writesize,
923 wb->buf, wb->dmah);
924 }
925 return -ENOMEM;
926 }
927 }
928 return 0;
929}
930
Alan Cox10077d42009-06-11 12:36:09 +0100931static int acm_probe(struct usb_interface *intf,
932 const struct usb_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933{
934 struct usb_cdc_union_desc *union_header = NULL;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100935 struct usb_cdc_country_functional_desc *cfd = NULL;
David Brownellc6dbf552008-04-13 14:00:44 -0700936 unsigned char *buffer = intf->altsetting->extra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 int buflen = intf->altsetting->extralen;
938 struct usb_interface *control_interface;
939 struct usb_interface *data_interface;
940 struct usb_endpoint_descriptor *epctrl;
941 struct usb_endpoint_descriptor *epread;
942 struct usb_endpoint_descriptor *epwrite;
943 struct usb_device *usb_dev = interface_to_usbdev(intf);
944 struct acm *acm;
945 int minor;
Alan Cox6e47e062009-06-11 12:37:06 +0100946 int ctrlsize, readsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 u8 *buf;
948 u8 ac_management_function = 0;
949 u8 call_management_function = 0;
950 int call_interface_num = -1;
951 int data_interface_num;
952 unsigned long quirks;
Oliver Neukum86478942006-05-13 22:50:47 +0200953 int num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +0100954 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
Oliver Neukum86478942006-05-13 22:50:47 +0200956 /* normal quirks */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 quirks = (unsigned long)id->driver_info;
Oliver Neukum86478942006-05-13 22:50:47 +0200958 num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
959
960 /* handle quirks deadly to normal probing*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 if (quirks == NO_UNION_NORMAL) {
962 data_interface = usb_ifnum_to_if(usb_dev, 1);
963 control_interface = usb_ifnum_to_if(usb_dev, 0);
964 goto skip_normal_probe;
965 }
Alan Cox6e47e062009-06-11 12:37:06 +0100966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 /* normal probing*/
968 if (!buffer) {
Greg Kroah-Hartman9908a32e92008-08-14 09:37:34 -0700969 dev_err(&intf->dev, "Weird descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 return -EINVAL;
971 }
972
973 if (!buflen) {
Alan Cox6e47e062009-06-11 12:37:06 +0100974 if (intf->cur_altsetting->endpoint->extralen &&
975 intf->cur_altsetting->endpoint->extra) {
976 dev_dbg(&intf->dev,
977 "Seeking extra descriptors on endpoint\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 buflen = intf->cur_altsetting->endpoint->extralen;
979 buffer = intf->cur_altsetting->endpoint->extra;
980 } else {
Greg Kroah-Hartman9908a32e92008-08-14 09:37:34 -0700981 dev_err(&intf->dev,
982 "Zero length descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 return -EINVAL;
984 }
985 }
986
987 while (buflen > 0) {
Alan Cox6e47e062009-06-11 12:37:06 +0100988 if (buffer[1] != USB_DT_CS_INTERFACE) {
Greg Kroah-Hartman9908a32e92008-08-14 09:37:34 -0700989 dev_err(&intf->dev, "skipping garbage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 goto next_desc;
991 }
992
Alan Cox6e47e062009-06-11 12:37:06 +0100993 switch (buffer[2]) {
994 case USB_CDC_UNION_TYPE: /* we've found it */
995 if (union_header) {
996 dev_err(&intf->dev, "More than one "
997 "union descriptor, skipping ...\n");
998 goto next_desc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 }
Alan Cox6e47e062009-06-11 12:37:06 +01001000 union_header = (struct usb_cdc_union_desc *)buffer;
1001 break;
1002 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
1003 cfd = (struct usb_cdc_country_functional_desc *)buffer;
1004 break;
1005 case USB_CDC_HEADER_TYPE: /* maybe check version */
1006 break; /* for now we ignore it */
1007 case USB_CDC_ACM_TYPE:
1008 ac_management_function = buffer[3];
1009 break;
1010 case USB_CDC_CALL_MANAGEMENT_TYPE:
1011 call_management_function = buffer[3];
1012 call_interface_num = buffer[4];
1013 if ((call_management_function & 3) != 3)
1014 dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
1015 break;
1016 default:
1017 /* there are LOTS more CDC descriptors that
1018 * could legitimately be found here.
1019 */
1020 dev_dbg(&intf->dev, "Ignoring descriptor: "
1021 "type %02x, length %d\n",
1022 buffer[2], buffer[0]);
1023 break;
1024 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025next_desc:
1026 buflen -= buffer[0];
1027 buffer += buffer[0];
1028 }
1029
1030 if (!union_header) {
1031 if (call_interface_num > 0) {
Alan Cox6e47e062009-06-11 12:37:06 +01001032 dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
1034 control_interface = intf;
1035 } else {
Alan Cox6e47e062009-06-11 12:37:06 +01001036 dev_dbg(&intf->dev,
1037 "No union descriptor, giving up\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return -ENODEV;
1039 }
1040 } else {
1041 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
1042 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
1043 if (!control_interface || !data_interface) {
Alan Cox6e47e062009-06-11 12:37:06 +01001044 dev_dbg(&intf->dev, "no interfaces\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 return -ENODEV;
1046 }
1047 }
Alan Cox6e47e062009-06-11 12:37:06 +01001048
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 if (data_interface_num != call_interface_num)
Alan Cox6e47e062009-06-11 12:37:06 +01001050 dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
1052skip_normal_probe:
1053
1054 /*workaround for switched interfaces */
Alan Cox6e47e062009-06-11 12:37:06 +01001055 if (data_interface->cur_altsetting->desc.bInterfaceClass
1056 != CDC_DATA_INTERFACE_TYPE) {
1057 if (control_interface->cur_altsetting->desc.bInterfaceClass
1058 == CDC_DATA_INTERFACE_TYPE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 struct usb_interface *t;
Alan Cox6e47e062009-06-11 12:37:06 +01001060 dev_dbg(&intf->dev,
1061 "Your device has switched interfaces.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 t = control_interface;
1063 control_interface = data_interface;
1064 data_interface = t;
1065 } else {
1066 return -EINVAL;
1067 }
1068 }
Alan Stern74da5d62007-08-02 13:29:10 -04001069
1070 /* Accept probe requests only for the control interface */
1071 if (intf != control_interface)
1072 return -ENODEV;
Alan Cox6e47e062009-06-11 12:37:06 +01001073
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 if (usb_interface_claimed(data_interface)) { /* valid in this context */
Alan Cox6e47e062009-06-11 12:37:06 +01001075 dev_dbg(&intf->dev, "The data interface isn't available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 return -EBUSY;
1077 }
1078
1079
1080 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
1081 return -EINVAL;
1082
1083 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
1084 epread = &data_interface->cur_altsetting->endpoint[0].desc;
1085 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
1086
1087
1088 /* workaround for switched endpoints */
Luiz Fernando N. Capitulino45aea702006-10-26 13:02:48 -03001089 if (!usb_endpoint_dir_in(epread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 /* descriptors are swapped */
1091 struct usb_endpoint_descriptor *t;
Alan Cox6e47e062009-06-11 12:37:06 +01001092 dev_dbg(&intf->dev,
1093 "The data interface has switched endpoints\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 t = epread;
1095 epread = epwrite;
1096 epwrite = t;
1097 }
1098 dbg("interfaces are valid");
1099 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
1100
1101 if (minor == ACM_TTY_MINORS) {
Greg Kroah-Hartman9908a32e92008-08-14 09:37:34 -07001102 dev_err(&intf->dev, "no more free acm devices\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 return -ENODEV;
1104 }
1105
Alan Cox6e47e062009-06-11 12:37:06 +01001106 acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
1107 if (acm == NULL) {
Joe Perches898eb712007-10-18 03:06:30 -07001108 dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 goto alloc_fail;
1110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
1112 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
Alan Cox6e47e062009-06-11 12:37:06 +01001113 readsize = le16_to_cpu(epread->wMaxPacketSize) *
1114 (quirks == SINGLE_RX_URB ? 1 : 2);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001115 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 acm->control = control_interface;
1117 acm->data = data_interface;
1118 acm->minor = minor;
1119 acm->dev = usb_dev;
1120 acm->ctrl_caps = ac_management_function;
1121 acm->ctrlsize = ctrlsize;
1122 acm->readsize = readsize;
Oliver Neukum86478942006-05-13 22:50:47 +02001123 acm->rx_buflimit = num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +01001124 acm->urb_task.func = acm_rx_tasklet;
1125 acm->urb_task.data = (unsigned long) acm;
David Howellsc4028952006-11-22 14:57:56 +00001126 INIT_WORK(&acm->work, acm_softint);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001127 INIT_WORK(&acm->waker, acm_waker);
David Brownelle5fbab52008-08-06 18:46:10 -07001128 init_waitqueue_head(&acm->drain_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 spin_lock_init(&acm->throttle_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +02001130 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +01001131 spin_lock_init(&acm->read_lock);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001132 mutex_init(&acm->mutex);
David Kubicek61a87ad2005-11-01 18:51:34 +01001133 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Alan Cox739e0282009-06-11 12:27:50 +01001134 tty_port_init(&acm->port);
1135 acm->port.ops = &acm_port_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
1137 buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
1138 if (!buf) {
Joe Perches898eb712007-10-18 03:06:30 -07001139 dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 goto alloc_fail2;
1141 }
1142 acm->ctrl_buffer = buf;
1143
Oliver Neukum884b6002005-04-21 21:28:02 +02001144 if (acm_write_buffers_alloc(acm) < 0) {
Joe Perches898eb712007-10-18 03:06:30 -07001145 dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 goto alloc_fail4;
1147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
1149 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
1150 if (!acm->ctrlurb) {
Joe Perches898eb712007-10-18 03:06:30 -07001151 dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 goto alloc_fail5;
1153 }
Oliver Neukum86478942006-05-13 22:50:47 +02001154 for (i = 0; i < num_rx_buf; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +01001155 struct acm_ru *rcv = &(acm->ru[i]);
1156
Alan Cox6e47e062009-06-11 12:37:06 +01001157 rcv->urb = usb_alloc_urb(0, GFP_KERNEL);
1158 if (rcv->urb == NULL) {
1159 dev_dbg(&intf->dev,
1160 "out of memory (read urbs usb_alloc_urb)\n");
David Kubicek61a87ad2005-11-01 18:51:34 +01001161 goto alloc_fail7;
1162 }
1163
1164 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1165 rcv->instance = acm;
1166 }
Oliver Neukum86478942006-05-13 22:50:47 +02001167 for (i = 0; i < num_rx_buf; i++) {
David Brownell672c4e12008-08-06 18:41:12 -07001168 struct acm_rb *rb = &(acm->rb[i]);
David Kubicek61a87ad2005-11-01 18:51:34 +01001169
David Brownell672c4e12008-08-06 18:41:12 -07001170 rb->base = usb_buffer_alloc(acm->dev, readsize,
1171 GFP_KERNEL, &rb->dma);
1172 if (!rb->base) {
Alan Cox6e47e062009-06-11 12:37:06 +01001173 dev_dbg(&intf->dev,
1174 "out of memory (read bufs usb_buffer_alloc)\n");
David Kubicek61a87ad2005-11-01 18:51:34 +01001175 goto alloc_fail7;
1176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 }
Alan Cox6e47e062009-06-11 12:37:06 +01001178 for (i = 0; i < ACM_NW; i++) {
David Engrafe4cf3aa2008-03-20 10:01:34 +01001179 struct acm_wb *snd = &(acm->wb[i]);
1180
Alan Cox6e47e062009-06-11 12:37:06 +01001181 snd->urb = usb_alloc_urb(0, GFP_KERNEL);
1182 if (snd->urb == NULL) {
1183 dev_dbg(&intf->dev,
1184 "out of memory (write urbs usb_alloc_urb)");
David Engrafe4cf3aa2008-03-20 10:01:34 +01001185 goto alloc_fail7;
1186 }
1187
Alan Cox6e47e062009-06-11 12:37:06 +01001188 usb_fill_bulk_urb(snd->urb, usb_dev,
1189 usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
1190 NULL, acm->writesize, acm_write_bulk, snd);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001191 snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1192 snd->instance = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 }
1194
Alan Cox6e47e062009-06-11 12:37:06 +01001195 usb_set_intfdata(intf, acm);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001196
1197 i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
1198 if (i < 0)
1199 goto alloc_fail8;
1200
1201 if (cfd) { /* export the country data */
1202 acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
1203 if (!acm->country_codes)
1204 goto skip_countries;
1205 acm->country_code_size = cfd->bLength - 4;
Alan Cox6e47e062009-06-11 12:37:06 +01001206 memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0,
1207 cfd->bLength - 4);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001208 acm->country_rel_date = cfd->iCountryCodeRelDate;
1209
1210 i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
1211 if (i < 0) {
1212 kfree(acm->country_codes);
1213 goto skip_countries;
1214 }
1215
Alan Cox6e47e062009-06-11 12:37:06 +01001216 i = device_create_file(&intf->dev,
1217 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001218 if (i < 0) {
1219 kfree(acm->country_codes);
1220 goto skip_countries;
1221 }
1222 }
1223
1224skip_countries:
Alan Cox6e47e062009-06-11 12:37:06 +01001225 usb_fill_int_urb(acm->ctrlurb, usb_dev,
1226 usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
1227 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
1228 epctrl->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1230 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
1231
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
1233
1234 acm_set_control(acm, acm->ctrlout);
1235
1236 acm->line.dwDTERate = cpu_to_le32(9600);
1237 acm->line.bDataBits = 8;
1238 acm_set_line(acm, &acm->line);
1239
1240 usb_driver_claim_interface(&acm_driver, data_interface, acm);
David Brownell672c4e12008-08-06 18:41:12 -07001241 usb_set_intfdata(data_interface, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001243 usb_get_intf(control_interface);
1244 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
1246 acm_table[minor] = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001248 return 0;
1249alloc_fail8:
David Engrafe4cf3aa2008-03-20 10:01:34 +01001250 for (i = 0; i < ACM_NW; i++)
1251 usb_free_urb(acm->wb[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252alloc_fail7:
Oliver Neukum830f4022008-06-25 14:17:16 +02001253 acm_read_buffers_free(acm);
Oliver Neukum86478942006-05-13 22:50:47 +02001254 for (i = 0; i < num_rx_buf; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001255 usb_free_urb(acm->ru[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 usb_free_urb(acm->ctrlurb);
1257alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001258 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259alloc_fail4:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
1261alloc_fail2:
1262 kfree(acm);
1263alloc_fail:
1264 return -ENOMEM;
1265}
1266
Oliver Neukum1365baf2007-10-12 17:24:28 +02001267static void stop_data_traffic(struct acm *acm)
1268{
1269 int i;
Oliver Neukum11ea8592008-06-20 11:25:57 +02001270 dbg("Entering stop_data_traffic");
Oliver Neukum1365baf2007-10-12 17:24:28 +02001271
1272 tasklet_disable(&acm->urb_task);
1273
1274 usb_kill_urb(acm->ctrlurb);
Alan Cox6e47e062009-06-11 12:37:06 +01001275 for (i = 0; i < ACM_NW; i++)
David Engrafe4cf3aa2008-03-20 10:01:34 +01001276 usb_kill_urb(acm->wb[i].urb);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001277 for (i = 0; i < acm->rx_buflimit; i++)
1278 usb_kill_urb(acm->ru[i].urb);
1279
Oliver Neukum1365baf2007-10-12 17:24:28 +02001280 tasklet_enable(&acm->urb_task);
1281
1282 cancel_work_sync(&acm->work);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001283 cancel_work_sync(&acm->waker);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001284}
1285
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286static void acm_disconnect(struct usb_interface *intf)
1287{
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001288 struct acm *acm = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 struct usb_device *usb_dev = interface_to_usbdev(intf);
Alan Cox10077d42009-06-11 12:36:09 +01001290 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291
David Brownell672c4e12008-08-06 18:41:12 -07001292 /* sibling interface is already cleaning up */
1293 if (!acm)
Oliver Neukum86067eea2006-01-08 12:39:13 +01001294 return;
David Brownell672c4e12008-08-06 18:41:12 -07001295
1296 mutex_lock(&open_mutex);
Alan Cox6e47e062009-06-11 12:37:06 +01001297 if (acm->country_codes) {
Alan Stern74da5d62007-08-02 13:29:10 -04001298 device_remove_file(&acm->control->dev,
1299 &dev_attr_wCountryCodes);
1300 device_remove_file(&acm->control->dev,
1301 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001302 }
Alan Stern74da5d62007-08-02 13:29:10 -04001303 device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 acm->dev = NULL;
Oliver Neukum86067eea2006-01-08 12:39:13 +01001305 usb_set_intfdata(acm->control, NULL);
1306 usb_set_intfdata(acm->data, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
Oliver Neukum1365baf2007-10-12 17:24:28 +02001308 stop_data_traffic(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309
Oliver Neukum884b6002005-04-21 21:28:02 +02001310 acm_write_buffers_free(acm);
Alan Cox6e47e062009-06-11 12:37:06 +01001311 usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer,
1312 acm->ctrl_dma);
Oliver Neukum830f4022008-06-25 14:17:16 +02001313 acm_read_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314
Oliver Neukum830f4022008-06-25 14:17:16 +02001315 usb_driver_release_interface(&acm_driver, intf == acm->control ?
1316 acm->data : acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
Alan Cox10077d42009-06-11 12:36:09 +01001318 if (acm->port.count == 0) {
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001319 acm_tty_unregister(acm);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001320 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 return;
1322 }
1323
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001324 mutex_unlock(&open_mutex);
Alan Cox10077d42009-06-11 12:36:09 +01001325 tty = tty_port_tty_get(&acm->port);
1326 if (tty) {
1327 tty_hangup(tty);
1328 tty_kref_put(tty);
1329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330}
1331
Oliver Neukum35758582008-07-01 19:10:08 +02001332#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001333static int acm_suspend(struct usb_interface *intf, pm_message_t message)
1334{
1335 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001336 int cnt;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001337
Alan Stern65bfd292008-11-25 16:39:18 -05001338 if (message.event & PM_EVENT_AUTO) {
Oliver Neukum11ea8592008-06-20 11:25:57 +02001339 int b;
1340
1341 spin_lock_irq(&acm->read_lock);
1342 spin_lock(&acm->write_lock);
1343 b = acm->processing + acm->transmitting;
1344 spin_unlock(&acm->write_lock);
1345 spin_unlock_irq(&acm->read_lock);
1346 if (b)
1347 return -EBUSY;
1348 }
1349
1350 spin_lock_irq(&acm->read_lock);
1351 spin_lock(&acm->write_lock);
1352 cnt = acm->susp_count++;
1353 spin_unlock(&acm->write_lock);
1354 spin_unlock_irq(&acm->read_lock);
1355
1356 if (cnt)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001357 return 0;
1358 /*
1359 we treat opened interfaces differently,
1360 we must guard against open
1361 */
1362 mutex_lock(&acm->mutex);
1363
Alan Cox10077d42009-06-11 12:36:09 +01001364 if (acm->port.count)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001365 stop_data_traffic(acm);
1366
1367 mutex_unlock(&acm->mutex);
1368 return 0;
1369}
1370
1371static int acm_resume(struct usb_interface *intf)
1372{
1373 struct acm *acm = usb_get_intfdata(intf);
1374 int rv = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +02001375 int cnt;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001376
Oliver Neukum11ea8592008-06-20 11:25:57 +02001377 spin_lock_irq(&acm->read_lock);
1378 acm->susp_count -= 1;
1379 cnt = acm->susp_count;
1380 spin_unlock_irq(&acm->read_lock);
1381
1382 if (cnt)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001383 return 0;
1384
1385 mutex_lock(&acm->mutex);
Alan Cox10077d42009-06-11 12:36:09 +01001386 if (acm->port.count) {
Oliver Neukum1365baf2007-10-12 17:24:28 +02001387 rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
1388 if (rv < 0)
Oliver Neukum11ea8592008-06-20 11:25:57 +02001389 goto err_out;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001390
1391 tasklet_schedule(&acm->urb_task);
1392 }
1393
1394err_out:
1395 mutex_unlock(&acm->mutex);
1396 return rv;
1397}
Oliver Neukum35758582008-07-01 19:10:08 +02001398
1399#endif /* CONFIG_PM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400/*
1401 * USB driver structure.
1402 */
1403
1404static struct usb_device_id acm_ids[] = {
1405 /* quirky and broken devices */
1406 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1407 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1408 },
Andrey Arapovb0e2a702007-07-04 17:11:42 +02001409 { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
1410 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1411 },
Andrew Lunn0f9c7b42008-12-23 17:31:23 +01001412 { USB_DEVICE(0x0e8d, 0x3329), /* MediaTek Inc GPS */
1413 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1414 },
Masahito Omote8753e652005-07-29 12:17:25 -07001415 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1416 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1417 },
Chris Malley91a9c922006-10-03 10:08:28 +01001418 { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
1419 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1420 },
Alan Cox7abcf202009-04-06 17:35:01 +01001421 { USB_DEVICE(0x0ace, 0x1602), /* ZyDAS 56K USB MODEM */
1422 .driver_info = SINGLE_RX_URB,
1423 },
Oliver Neukum86478942006-05-13 22:50:47 +02001424 { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
1425 .driver_info = SINGLE_RX_URB, /* firmware bug */
1426 },
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001427 { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
1428 .driver_info = SINGLE_RX_URB, /* firmware bug */
1429 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001430 { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
1431 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1432 },
Iain McFarlane6149ed52008-05-04 00:13:49 +01001433 { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */
1434 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1435 },
Eric Sandeenc8fd2c32008-08-14 08:25:40 -05001436 { USB_DEVICE(0x0572, 0x1321), /* Conexant USB MODEM CX93010 */
1437 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1438 },
Alan Coxc89c60e2009-01-11 19:53:10 +00001439 { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */
1440 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1441 },
Xiao Kaijiancab98a02009-05-08 00:48:23 +08001442 { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */
1443 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1444 },
Dmitriy Taychenachev155df652009-02-25 12:36:51 +08001445 { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
1446 },
Adam Richterc332b4e2009-02-18 16:17:15 -08001447 { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */
1448 .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on
1449 data interface instead of
1450 communications interface.
1451 Maybe we should define a new
1452 quirk for this. */
1453 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001454
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 /* control interfaces with various AT-command sets */
1456 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1457 USB_CDC_ACM_PROTO_AT_V25TER) },
1458 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1459 USB_CDC_ACM_PROTO_AT_PCCA101) },
1460 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1461 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1462 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1463 USB_CDC_ACM_PROTO_AT_GSM) },
1464 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
Alan Cox6e47e062009-06-11 12:37:06 +01001465 USB_CDC_ACM_PROTO_AT_3G) },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1467 USB_CDC_ACM_PROTO_AT_CDMA) },
1468
1469 /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */
1470 { }
1471};
1472
Alan Cox6e47e062009-06-11 12:37:06 +01001473MODULE_DEVICE_TABLE(usb, acm_ids);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
1475static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 .name = "cdc_acm",
1477 .probe = acm_probe,
1478 .disconnect = acm_disconnect,
Oliver Neukum35758582008-07-01 19:10:08 +02001479#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001480 .suspend = acm_suspend,
1481 .resume = acm_resume,
Oliver Neukum35758582008-07-01 19:10:08 +02001482#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 .id_table = acm_ids,
Oliver Neukum35758582008-07-01 19:10:08 +02001484#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001485 .supports_autosuspend = 1,
Oliver Neukum35758582008-07-01 19:10:08 +02001486#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487};
1488
1489/*
1490 * TTY driver structures.
1491 */
1492
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001493static const struct tty_operations acm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 .open = acm_tty_open,
1495 .close = acm_tty_close,
Alan Cox10077d42009-06-11 12:36:09 +01001496 .hangup = acm_tty_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 .write = acm_tty_write,
1498 .write_room = acm_tty_write_room,
1499 .ioctl = acm_tty_ioctl,
1500 .throttle = acm_tty_throttle,
1501 .unthrottle = acm_tty_unthrottle,
1502 .chars_in_buffer = acm_tty_chars_in_buffer,
1503 .break_ctl = acm_tty_break_ctl,
1504 .set_termios = acm_tty_set_termios,
1505 .tiocmget = acm_tty_tiocmget,
1506 .tiocmset = acm_tty_tiocmset,
1507};
1508
1509/*
1510 * Init / exit.
1511 */
1512
1513static int __init acm_init(void)
1514{
1515 int retval;
1516 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1517 if (!acm_tty_driver)
1518 return -ENOMEM;
1519 acm_tty_driver->owner = THIS_MODULE,
1520 acm_tty_driver->driver_name = "acm",
1521 acm_tty_driver->name = "ttyACM",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 acm_tty_driver->major = ACM_TTY_MAJOR,
1523 acm_tty_driver->minor_start = 0,
1524 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1525 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001526 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 acm_tty_driver->init_termios = tty_std_termios;
Alan Cox6e47e062009-06-11 12:37:06 +01001528 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD |
1529 HUPCL | CLOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 tty_set_operations(acm_tty_driver, &acm_ops);
1531
1532 retval = tty_register_driver(acm_tty_driver);
1533 if (retval) {
1534 put_tty_driver(acm_tty_driver);
1535 return retval;
1536 }
1537
1538 retval = usb_register(&acm_driver);
1539 if (retval) {
1540 tty_unregister_driver(acm_tty_driver);
1541 put_tty_driver(acm_tty_driver);
1542 return retval;
1543 }
1544
Greg Kroah-Hartman5909f6e2008-08-18 13:21:04 -07001545 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
1546 DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
1548 return 0;
1549}
1550
1551static void __exit acm_exit(void)
1552{
1553 usb_deregister(&acm_driver);
1554 tty_unregister_driver(acm_tty_driver);
1555 put_tty_driver(acm_tty_driver);
1556}
1557
1558module_init(acm_init);
1559module_exit(acm_exit);
1560
Alan Cox6e47e062009-06-11 12:37:06 +01001561MODULE_AUTHOR(DRIVER_AUTHOR);
1562MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563MODULE_LICENSE("GPL");
Scott James Remnante766aeb2009-04-06 17:33:18 +01001564MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR);