blob: fee7d8b94fe23dc99bb1b96386d9e85527febf3a [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>
Pavel Macheka2531292010-07-18 14:27:13 +02005 * Copyright (c) 1999 Pavel Machek <pavel@ucw.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * 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>
Oliver Neukum7af25b42009-09-08 23:51:28 +020062#include <linux/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#include <linux/tty_driver.h>
64#include <linux/tty_flip.h>
65#include <linux/module.h>
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010066#include <linux/mutex.h>
Alan Cox10077d42009-06-11 12:36:09 +010067#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#include <linux/usb.h>
David Brownella8c28f22006-06-13 09:57:47 -070069#include <linux/usb/cdc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#include <asm/byteorder.h>
71#include <asm/unaligned.h>
David Kubicek61a87ad2005-11-01 18:51:34 +010072#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
74#include "cdc-acm.h"
75
David Brownelle5fbab52008-08-06 18:46:10 -070076
77#define ACM_CLOSE_TIMEOUT 15 /* seconds to let writes drain */
78
Linus Torvalds1da177e2005-04-16 15:20:36 -070079/*
80 * Version Information
81 */
David Engrafe4cf3aa2008-03-20 10:01:34 +010082#define DRIVER_VERSION "v0.26"
David Kubicek61a87ad2005-11-01 18:51:34 +010083#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
Linus Torvalds1da177e2005-04-16 15:20:36 -070084#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
85
86static struct usb_driver acm_driver;
87static struct tty_driver *acm_tty_driver;
88static struct acm *acm_table[ACM_TTY_MINORS];
89
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010090static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Alan Cox10077d42009-06-11 12:36:09 +010092#define ACM_READY(acm) (acm && acm->dev && acm->port.count)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
Alan Cox739e0282009-06-11 12:27:50 +010094static const struct tty_port_operations acm_port_ops = {
95};
96
David Brownelle5fbab52008-08-06 18:46:10 -070097#ifdef VERBOSE_DEBUG
98#define verbose 1
99#else
100#define verbose 0
101#endif
102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103/*
104 * Functions for ACM control messages.
105 */
106
Alan Cox6e47e062009-06-11 12:37:06 +0100107static int acm_ctrl_msg(struct acm *acm, int request, int value,
108 void *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
110 int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
111 request, USB_RT_ACM, value,
112 acm->control->altsetting[0].desc.bInterfaceNumber,
113 buf, len, 5000);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100114 dev_dbg(&acm->control->dev,
115 "%s - rq 0x%02x, val %#x, len %#x, result %d\n",
116 __func__, request, value, len, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 return retval < 0 ? retval : 0;
118}
119
120/* devices aren't required to support these requests.
121 * the cdc acm descriptor tells whether they do...
122 */
123#define acm_set_control(acm, control) \
124 acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
125#define acm_set_line(acm, line) \
126 acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
127#define acm_send_break(acm, ms) \
128 acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
129
130/*
Oliver Neukum884b6002005-04-21 21:28:02 +0200131 * Write buffer management.
132 * All of these assume proper locks taken by the caller.
133 */
134
135static int acm_wb_alloc(struct acm *acm)
136{
137 int i, wbn;
138 struct acm_wb *wb;
139
David Engrafe4cf3aa2008-03-20 10:01:34 +0100140 wbn = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200141 i = 0;
142 for (;;) {
143 wb = &acm->wb[wbn];
144 if (!wb->use) {
145 wb->use = 1;
146 return wbn;
147 }
Oliver Neukum86478942006-05-13 22:50:47 +0200148 wbn = (wbn + 1) % ACM_NW;
149 if (++i >= ACM_NW)
Oliver Neukum884b6002005-04-21 21:28:02 +0200150 return -1;
151 }
152}
153
Oliver Neukum884b6002005-04-21 21:28:02 +0200154static int acm_wb_is_avail(struct acm *acm)
155{
156 int i, n;
David Brownelle5fbab52008-08-06 18:46:10 -0700157 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200158
Oliver Neukum86478942006-05-13 22:50:47 +0200159 n = ACM_NW;
David Brownelle5fbab52008-08-06 18:46:10 -0700160 spin_lock_irqsave(&acm->write_lock, flags);
Alan Cox6e47e062009-06-11 12:37:06 +0100161 for (i = 0; i < ACM_NW; i++)
Oliver Neukum86478942006-05-13 22:50:47 +0200162 n -= acm->wb[i].use;
David Brownelle5fbab52008-08-06 18:46:10 -0700163 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200164 return n;
165}
166
Oliver Neukum884b6002005-04-21 21:28:02 +0200167/*
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800168 * Finish write. Caller must hold acm->write_lock
Oliver Neukum884b6002005-04-21 21:28:02 +0200169 */
David Engrafe4cf3aa2008-03-20 10:01:34 +0100170static void acm_write_done(struct acm *acm, struct acm_wb *wb)
Oliver Neukum884b6002005-04-21 21:28:02 +0200171{
David Engrafe4cf3aa2008-03-20 10:01:34 +0100172 wb->use = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200173 acm->transmitting--;
Oliver Neukum97d35f92009-12-16 17:05:57 +0100174 usb_autopm_put_interface_async(acm->control);
Oliver Neukum884b6002005-04-21 21:28:02 +0200175}
176
177/*
178 * Poke write.
Oliver Neukum11ea8592008-06-20 11:25:57 +0200179 *
180 * the caller is responsible for locking
Oliver Neukum884b6002005-04-21 21:28:02 +0200181 */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200182
183static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
184{
185 int rc;
186
187 acm->transmitting++;
188
189 wb->urb->transfer_buffer = wb->buf;
190 wb->urb->transfer_dma = wb->dmah;
191 wb->urb->transfer_buffer_length = wb->len;
192 wb->urb->dev = acm->dev;
193
Alan Cox6e47e062009-06-11 12:37:06 +0100194 rc = usb_submit_urb(wb->urb, GFP_ATOMIC);
195 if (rc < 0) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100196 dev_err(&acm->data->dev,
197 "%s - usb_submit_urb(write bulk) failed: %d\n",
198 __func__, rc);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200199 acm_write_done(acm, wb);
200 }
201 return rc;
202}
203
David Engrafe4cf3aa2008-03-20 10:01:34 +0100204static int acm_write_start(struct acm *acm, int wbn)
Oliver Neukum884b6002005-04-21 21:28:02 +0200205{
206 unsigned long flags;
David Brownell934da462008-08-06 18:44:12 -0700207 struct acm_wb *wb = &acm->wb[wbn];
Oliver Neukum884b6002005-04-21 21:28:02 +0200208 int rc;
209
210 spin_lock_irqsave(&acm->write_lock, flags);
211 if (!acm->dev) {
David Brownell934da462008-08-06 18:44:12 -0700212 wb->use = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200213 spin_unlock_irqrestore(&acm->write_lock, flags);
214 return -ENODEV;
215 }
216
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100217 dev_dbg(&acm->data->dev, "%s - susp_count %d\n", __func__,
218 acm->susp_count);
Oliver Neukum97d35f92009-12-16 17:05:57 +0100219 usb_autopm_get_interface_async(acm->control);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200220 if (acm->susp_count) {
Oliver Neukum97d35f92009-12-16 17:05:57 +0100221 if (!acm->delayed_wb)
222 acm->delayed_wb = wb;
223 else
224 usb_autopm_put_interface_async(acm->control);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200225 spin_unlock_irqrestore(&acm->write_lock, flags);
226 return 0; /* A white lie */
227 }
228 usb_mark_last_busy(acm->dev);
229
Oliver Neukum11ea8592008-06-20 11:25:57 +0200230 rc = acm_start_wb(acm, wb);
Oliver Neukum884b6002005-04-21 21:28:02 +0200231 spin_unlock_irqrestore(&acm->write_lock, flags);
232
Oliver Neukum884b6002005-04-21 21:28:02 +0200233 return rc;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200234
Oliver Neukum884b6002005-04-21 21:28:02 +0200235}
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100236/*
237 * attributes exported through sysfs
238 */
239static ssize_t show_caps
240(struct device *dev, struct device_attribute *attr, char *buf)
241{
242 struct usb_interface *intf = to_usb_interface(dev);
243 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum884b6002005-04-21 21:28:02 +0200244
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100245 return sprintf(buf, "%d", acm->ctrl_caps);
246}
247static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
248
249static ssize_t show_country_codes
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 memcpy(buf, acm->country_codes, acm->country_code_size);
256 return acm->country_code_size;
257}
258
259static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
260
261static ssize_t show_country_rel_date
262(struct device *dev, struct device_attribute *attr, char *buf)
263{
264 struct usb_interface *intf = to_usb_interface(dev);
265 struct acm *acm = usb_get_intfdata(intf);
266
267 return sprintf(buf, "%d", acm->country_rel_date);
268}
269
270static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
Oliver Neukum884b6002005-04-21 21:28:02 +0200271/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 * Interrupt handlers for various ACM device responses
273 */
274
275/* control interface reports status changes with "interrupt" transfers */
David Howells7d12e782006-10-05 14:55:46 +0100276static void acm_ctrl_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
278 struct acm *acm = urb->context;
279 struct usb_cdc_notification *dr = urb->transfer_buffer;
Alan Cox10077d42009-06-11 12:36:09 +0100280 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 unsigned char *data;
282 int newctrl;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700283 int retval;
284 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700286 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 case 0:
288 /* success */
289 break;
290 case -ECONNRESET:
291 case -ENOENT:
292 case -ESHUTDOWN:
293 /* this urb is terminated, clean up */
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100294 dev_dbg(&acm->control->dev,
295 "%s - urb shutting down with status: %d\n",
296 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 return;
298 default:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100299 dev_dbg(&acm->control->dev,
300 "%s - nonzero urb status received: %d\n",
301 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 goto exit;
303 }
304
305 if (!ACM_READY(acm))
306 goto exit;
307
Johan Hovold7e7797e2011-03-22 11:12:11 +0100308 usb_mark_last_busy(acm->dev);
309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 data = (unsigned char *)(dr + 1);
311 switch (dr->bNotificationType) {
Alan Cox6e47e062009-06-11 12:37:06 +0100312 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100313 dev_dbg(&acm->control->dev, "%s - network connection: %d\n",
314 __func__, dr->wValue);
Alan Cox6e47e062009-06-11 12:37:06 +0100315 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Alan Cox6e47e062009-06-11 12:37:06 +0100317 case USB_CDC_NOTIFY_SERIAL_STATE:
318 tty = tty_port_tty_get(&acm->port);
319 newctrl = get_unaligned_le16(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Alan Cox6e47e062009-06-11 12:37:06 +0100321 if (tty) {
322 if (!acm->clocal &&
323 (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100324 dev_dbg(&acm->control->dev,
325 "%s - calling hangup\n", __func__);
Alan Cox6e47e062009-06-11 12:37:06 +0100326 tty_hangup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 }
Alan Cox6e47e062009-06-11 12:37:06 +0100328 tty_kref_put(tty);
329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
Alan Cox6e47e062009-06-11 12:37:06 +0100331 acm->ctrlin = newctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100333 dev_dbg(&acm->control->dev,
334 "%s - input control lines: dcd%c dsr%c break%c "
335 "ring%c framing%c parity%c overrun%c\n",
336 __func__,
Alan Cox6e47e062009-06-11 12:37:06 +0100337 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',
338 acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
339 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-',
340 acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
341 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',
342 acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
343 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 break;
345
Alan Cox6e47e062009-06-11 12:37:06 +0100346 default:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100347 dev_dbg(&acm->control->dev,
348 "%s - unknown notification %d received: index %d "
349 "len %d data0 %d data1 %d\n",
350 __func__,
Alan Cox6e47e062009-06-11 12:37:06 +0100351 dr->bNotificationType, dr->wIndex,
352 dr->wLength, data[0], data[1]);
353 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 }
355exit:
Alan Cox6e47e062009-06-11 12:37:06 +0100356 retval = usb_submit_urb(urb, GFP_ATOMIC);
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700357 if (retval)
Johan Hovold1d9846e2011-03-22 11:12:14 +0100358 dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n",
359 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
362/* data interface returns incoming bytes, or we got unthrottled */
David Howells7d12e782006-10-05 14:55:46 +0100363static void acm_read_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
David Kubicek61a87ad2005-11-01 18:51:34 +0100365 struct acm_rb *buf;
366 struct acm_ru *rcv = urb->context;
367 struct acm *acm = rcv->instance;
Oliver Neukum86478942006-05-13 22:50:47 +0200368 int status = urb->status;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700369
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100370 dev_dbg(&acm->data->dev, "%s - status %d\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Oliver Neukum11ea8592008-06-20 11:25:57 +0200372 if (!ACM_READY(acm)) {
Johan Hovold1d9846e2011-03-22 11:12:14 +0100373 dev_dbg(&acm->data->dev, "%s - acm not ready\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200375 }
376 usb_mark_last_busy(acm->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Oliver Neukum86478942006-05-13 22:50:47 +0200378 if (status)
Johan Hovold1d9846e2011-03-22 11:12:14 +0100379 dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n",
380 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
David Kubicek61a87ad2005-11-01 18:51:34 +0100382 buf = rcv->buffer;
383 buf->size = urb->actual_length;
384
Oliver Neukum86478942006-05-13 22:50:47 +0200385 if (likely(status == 0)) {
386 spin_lock(&acm->read_lock);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200387 acm->processing++;
Oliver Neukum86478942006-05-13 22:50:47 +0200388 list_add_tail(&rcv->list, &acm->spare_read_urbs);
389 list_add_tail(&buf->list, &acm->filled_read_bufs);
390 spin_unlock(&acm->read_lock);
391 } else {
392 /* we drop the buffer due to an error */
393 spin_lock(&acm->read_lock);
394 list_add_tail(&rcv->list, &acm->spare_read_urbs);
395 list_add(&buf->list, &acm->spare_read_bufs);
396 spin_unlock(&acm->read_lock);
397 /* nevertheless the tasklet must be kicked unconditionally
398 so the queue cannot dry up */
399 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200400 if (likely(!acm->susp_count))
401 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402}
403
404static void acm_rx_tasklet(unsigned long _acm)
405{
406 struct acm *acm = (void *)_acm;
David Kubicek61a87ad2005-11-01 18:51:34 +0100407 struct acm_rb *buf;
Alan Cox10077d42009-06-11 12:36:09 +0100408 struct tty_struct *tty;
David Kubicek61a87ad2005-11-01 18:51:34 +0100409 struct acm_ru *rcv;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200410 unsigned long flags;
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100411 unsigned char throttled;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200412
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100413 dev_dbg(&acm->data->dev, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Alan Cox10077d42009-06-11 12:36:09 +0100415 if (!ACM_READY(acm)) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100416 dev_dbg(&acm->data->dev, "%s - acm not ready\n", __func__);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100417 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200418 }
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100419
Oliver Neukum834dbca2007-03-06 10:47:04 +0100420 spin_lock_irqsave(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100421 throttled = acm->throttle;
Oliver Neukum834dbca2007-03-06 10:47:04 +0100422 spin_unlock_irqrestore(&acm->throttle_lock, flags);
Alan Cox10077d42009-06-11 12:36:09 +0100423 if (throttled) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100424 dev_dbg(&acm->data->dev, "%s - throttled\n", __func__);
David Kubicek61a87ad2005-11-01 18:51:34 +0100425 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200426 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100427
Alan Cox10077d42009-06-11 12:36:09 +0100428 tty = tty_port_tty_get(&acm->port);
429
David Kubicek61a87ad2005-11-01 18:51:34 +0100430next_buffer:
Jarek Poplawski762f0072006-10-06 07:23:11 +0200431 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100432 if (list_empty(&acm->filled_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200433 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100434 goto urbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100436 buf = list_entry(acm->filled_read_bufs.next,
437 struct acm_rb, list);
438 list_del(&buf->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200439 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100440
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100441 dev_dbg(&acm->data->dev, "%s - processing buf 0x%p, size = %d\n",
442 __func__, buf, buf->size);
Alan Cox10077d42009-06-11 12:36:09 +0100443 if (tty) {
444 spin_lock_irqsave(&acm->throttle_lock, flags);
445 throttled = acm->throttle;
446 spin_unlock_irqrestore(&acm->throttle_lock, flags);
447 if (!throttled) {
Alan Cox10077d42009-06-11 12:36:09 +0100448 tty_insert_flip_string(tty, buf->base, buf->size);
449 tty_flip_buffer_push(tty);
450 } else {
451 tty_kref_put(tty);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100452 dev_dbg(&acm->data->dev, "%s - throttling noticed\n",
453 __func__);
Alan Cox10077d42009-06-11 12:36:09 +0100454 spin_lock_irqsave(&acm->read_lock, flags);
455 list_add(&buf->list, &acm->filled_read_bufs);
456 spin_unlock_irqrestore(&acm->read_lock, flags);
457 return;
458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Jarek Poplawski762f0072006-10-06 07:23:11 +0200461 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100462 list_add(&buf->list, &acm->spare_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200463 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100464 goto next_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
David Kubicek61a87ad2005-11-01 18:51:34 +0100466urbs:
Alan Cox10077d42009-06-11 12:36:09 +0100467 tty_kref_put(tty);
468
David Kubicek61a87ad2005-11-01 18:51:34 +0100469 while (!list_empty(&acm->spare_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200470 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100471 if (list_empty(&acm->spare_read_urbs)) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200472 acm->processing = 0;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200473 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100474 return;
475 }
476 rcv = list_entry(acm->spare_read_urbs.next,
477 struct acm_ru, list);
478 list_del(&rcv->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200479 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100480
481 buf = list_entry(acm->spare_read_bufs.next,
482 struct acm_rb, list);
483 list_del(&buf->list);
484
485 rcv->buffer = buf;
486
Oliver Neukumcf7fdd52009-08-04 23:52:09 +0200487 if (acm->is_int_ep)
Arseniy Lartsev5186ffe2009-07-01 16:27:26 +0400488 usb_fill_int_urb(rcv->urb, acm->dev,
489 acm->rx_endpoint,
490 buf->base,
491 acm->readsize,
Oliver Neukumcf7fdd52009-08-04 23:52:09 +0200492 acm_read_bulk, rcv, acm->bInterval);
Arseniy Lartsev5186ffe2009-07-01 16:27:26 +0400493 else
494 usb_fill_bulk_urb(rcv->urb, acm->dev,
495 acm->rx_endpoint,
496 buf->base,
497 acm->readsize,
498 acm_read_bulk, rcv);
David Kubicek61a87ad2005-11-01 18:51:34 +0100499 rcv->urb->transfer_dma = buf->dma;
500 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
501
Alan Cox6e47e062009-06-11 12:37:06 +0100502 /* This shouldn't kill the driver as unsuccessful URBs are
503 returned to the free-urbs-pool and resubmited ASAP */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200504 spin_lock_irqsave(&acm->read_lock, flags);
Alan Cox6e47e062009-06-11 12:37:06 +0100505 if (acm->susp_count ||
506 usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100507 list_add(&buf->list, &acm->spare_read_bufs);
David Kubicek61a87ad2005-11-01 18:51:34 +0100508 list_add(&rcv->list, &acm->spare_read_urbs);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200509 acm->processing = 0;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200510 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100511 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200512 } else {
513 spin_unlock_irqrestore(&acm->read_lock, flags);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100514 dev_dbg(&acm->data->dev,
515 "%s - sending urb 0x%p, rcv 0x%p, buf 0x%p\n",
516 __func__, rcv->urb, rcv, buf);
David Kubicek61a87ad2005-11-01 18:51:34 +0100517 }
518 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200519 spin_lock_irqsave(&acm->read_lock, flags);
520 acm->processing = 0;
521 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522}
523
524/* data interface wrote those outgoing bytes */
David Howells7d12e782006-10-05 14:55:46 +0100525static void acm_write_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526{
Ming Leicdc97792008-02-24 18:41:47 +0800527 struct acm_wb *wb = urb->context;
David Brownelle5fbab52008-08-06 18:46:10 -0700528 struct acm *acm = wb->instance;
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800529 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200530
David Brownelle5fbab52008-08-06 18:46:10 -0700531 if (verbose || urb->status
532 || (urb->actual_length != urb->transfer_buffer_length))
Johan Hovold1d9846e2011-03-22 11:12:14 +0100533 dev_dbg(&acm->data->dev, "%s - len %d/%d, status %d\n",
534 __func__,
David Brownelle5fbab52008-08-06 18:46:10 -0700535 urb->actual_length,
536 urb->transfer_buffer_length,
537 urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800539 spin_lock_irqsave(&acm->write_lock, flags);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100540 acm_write_done(acm, wb);
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800541 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200542 if (ACM_READY(acm))
543 schedule_work(&acm->work);
David Brownelle5fbab52008-08-06 18:46:10 -0700544 else
545 wake_up_interruptible(&acm->drain_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546}
547
David Howellsc4028952006-11-22 14:57:56 +0000548static void acm_softint(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
David Howellsc4028952006-11-22 14:57:56 +0000550 struct acm *acm = container_of(work, struct acm, work);
Alan Cox10077d42009-06-11 12:36:09 +0100551 struct tty_struct *tty;
David Brownelle5fbab52008-08-06 18:46:10 -0700552
Johan Hovold1d9846e2011-03-22 11:12:14 +0100553 dev_vdbg(&acm->data->dev, "%s\n", __func__);
554
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 if (!ACM_READY(acm))
556 return;
Alan Cox10077d42009-06-11 12:36:09 +0100557 tty = tty_port_tty_get(&acm->port);
Johan Hovold15e5bee2011-03-22 11:12:10 +0100558 if (!tty)
559 return;
Alan Cox10077d42009-06-11 12:36:09 +0100560 tty_wakeup(tty);
561 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562}
563
564/*
565 * TTY handlers
566 */
567
568static int acm_tty_open(struct tty_struct *tty, struct file *filp)
569{
570 struct acm *acm;
Thadeu Lima de Souza Cascardo42dd2aa2009-06-25 14:41:24 +0100571 int rv = -ENODEV;
David Kubicek61a87ad2005-11-01 18:51:34 +0100572 int i;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100573
574 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
576 acm = acm_table[tty->index];
577 if (!acm || !acm->dev)
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100578 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 else
580 rv = 0;
581
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100582 dev_dbg(&acm->control->dev, "%s\n", __func__);
583
David Engraf28d1dfa2008-03-20 10:53:52 +0100584 set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
Alan Cox10077d42009-06-11 12:36:09 +0100585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 tty->driver_data = acm;
Alan Cox10077d42009-06-11 12:36:09 +0100587 tty_port_tty_set(&acm->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Oliver Neukum94409cc2008-02-11 15:22:29 +0100589 if (usb_autopm_get_interface(acm->control) < 0)
590 goto early_bail;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200591 else
592 acm->control->needs_remote_wakeup = 1;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200593
594 mutex_lock(&acm->mutex);
Alan Cox10077d42009-06-11 12:36:09 +0100595 if (acm->port.count++) {
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100596 mutex_unlock(&acm->mutex);
Oliver Neukum1365baf2007-10-12 17:24:28 +0200597 usb_autopm_put_interface(acm->control);
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100598 goto out;
Alan Cox10077d42009-06-11 12:36:09 +0100599 }
Oliver Neukum1365baf2007-10-12 17:24:28 +0200600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 acm->ctrlurb->dev = acm->dev;
602 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100603 dev_err(&acm->control->dev,
604 "%s - usb_submit_urb(ctrl irq) failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 goto bail_out;
606 }
607
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100608 if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
609 (acm->ctrl_caps & USB_CDC_CAP_LINE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 goto full_bailout;
Alan Cox10077d42009-06-11 12:36:09 +0100611
Oliver Neukum11ea8592008-06-20 11:25:57 +0200612 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
David Kubicek61a87ad2005-11-01 18:51:34 +0100614 INIT_LIST_HEAD(&acm->spare_read_urbs);
615 INIT_LIST_HEAD(&acm->spare_read_bufs);
616 INIT_LIST_HEAD(&acm->filled_read_bufs);
Alan Cox6e47e062009-06-11 12:37:06 +0100617
618 for (i = 0; i < acm->rx_buflimit; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100619 list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
Alan Cox6e47e062009-06-11 12:37:06 +0100620 for (i = 0; i < acm->rx_buflimit; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100621 list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
David Kubicek61a87ad2005-11-01 18:51:34 +0100622
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100623 acm->throttle = 0;
624
Oliver Neukum7af25b42009-09-08 23:51:28 +0200625 set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
Alan Cox10077d42009-06-11 12:36:09 +0100626 rv = tty_port_block_til_ready(&acm->port, tty, filp);
Henry Gebhardt18a77b52009-11-04 11:19:28 +0100627 tasklet_schedule(&acm->urb_task);
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100628
Oliver Neukum1365baf2007-10-12 17:24:28 +0200629 mutex_unlock(&acm->mutex);
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100630out:
Oliver Neukum94409cc2008-02-11 15:22:29 +0100631 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 return rv;
633
634full_bailout:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 usb_kill_urb(acm->ctrlurb);
636bail_out:
Alan Cox10077d42009-06-11 12:36:09 +0100637 acm->port.count--;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200638 mutex_unlock(&acm->mutex);
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100639 usb_autopm_put_interface(acm->control);
Oliver Neukum94409cc2008-02-11 15:22:29 +0100640early_bail:
641 mutex_unlock(&open_mutex);
Alan Cox10077d42009-06-11 12:36:09 +0100642 tty_port_tty_set(&acm->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 return -EIO;
644}
645
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700646static void acm_tty_unregister(struct acm *acm)
647{
Alan Cox10077d42009-06-11 12:36:09 +0100648 int i, nr;
David Kubicek61a87ad2005-11-01 18:51:34 +0100649
Oliver Neukum86478942006-05-13 22:50:47 +0200650 nr = acm->rx_buflimit;
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700651 tty_unregister_device(acm_tty_driver, acm->minor);
652 usb_put_intf(acm->control);
653 acm_table[acm->minor] = NULL;
654 usb_free_urb(acm->ctrlurb);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100655 for (i = 0; i < ACM_NW; i++)
656 usb_free_urb(acm->wb[i].urb);
Oliver Neukum86478942006-05-13 22:50:47 +0200657 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100658 usb_free_urb(acm->ru[i].urb);
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100659 kfree(acm->country_codes);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700660 kfree(acm);
661}
662
David Brownelle5fbab52008-08-06 18:46:10 -0700663static int acm_tty_chars_in_buffer(struct tty_struct *tty);
664
Arnd Bergmann4e608672010-06-01 22:53:04 +0200665static void acm_port_down(struct acm *acm)
Alan Cox10077d42009-06-11 12:36:09 +0100666{
667 int i, nr = acm->rx_buflimit;
668 mutex_lock(&open_mutex);
669 if (acm->dev) {
670 usb_autopm_get_interface(acm->control);
671 acm_set_control(acm, acm->ctrlout = 0);
Alan Cox10077d42009-06-11 12:36:09 +0100672 usb_kill_urb(acm->ctrlurb);
673 for (i = 0; i < ACM_NW; i++)
674 usb_kill_urb(acm->wb[i].urb);
Johan Hovold23b80552011-03-22 11:12:09 +0100675 tasklet_disable(&acm->urb_task);
Alan Cox10077d42009-06-11 12:36:09 +0100676 for (i = 0; i < nr; i++)
677 usb_kill_urb(acm->ru[i].urb);
Johan Hovold23b80552011-03-22 11:12:09 +0100678 tasklet_enable(&acm->urb_task);
Alan Cox10077d42009-06-11 12:36:09 +0100679 acm->control->needs_remote_wakeup = 0;
680 usb_autopm_put_interface(acm->control);
681 }
682 mutex_unlock(&open_mutex);
683}
684
685static void acm_tty_hangup(struct tty_struct *tty)
686{
687 struct acm *acm = tty->driver_data;
688 tty_port_hangup(&acm->port);
Arnd Bergmann4e608672010-06-01 22:53:04 +0200689 acm_port_down(acm);
Alan Cox10077d42009-06-11 12:36:09 +0100690}
691
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692static void acm_tty_close(struct tty_struct *tty, struct file *filp)
693{
694 struct acm *acm = tty->driver_data;
695
Alan Cox10077d42009-06-11 12:36:09 +0100696 /* Perform the closing process and see if we need to do the hardware
697 shutdown */
Francesco Lavra051522b2009-11-03 10:53:07 +0000698 if (!acm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 return;
Francesco Lavra051522b2009-11-03 10:53:07 +0000700 if (tty_port_close_start(&acm->port, tty, filp) == 0) {
701 mutex_lock(&open_mutex);
702 if (!acm->dev) {
703 tty_port_tty_set(&acm->port, NULL);
704 acm_tty_unregister(acm);
705 tty->driver_data = NULL;
706 }
707 mutex_unlock(&open_mutex);
708 return;
709 }
Arnd Bergmann4e608672010-06-01 22:53:04 +0200710 acm_port_down(acm);
Alan Cox10077d42009-06-11 12:36:09 +0100711 tty_port_close_end(&acm->port, tty);
Alan Cox10077d42009-06-11 12:36:09 +0100712 tty_port_tty_set(&acm->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713}
714
Alan Cox6e47e062009-06-11 12:37:06 +0100715static int acm_tty_write(struct tty_struct *tty,
716 const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717{
718 struct acm *acm = tty->driver_data;
719 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200720 unsigned long flags;
721 int wbn;
722 struct acm_wb *wb;
723
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 if (!ACM_READY(acm))
725 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 if (!count)
727 return 0;
728
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100729 dev_dbg(&acm->data->dev, "%s - count %d\n", __func__, count);
730
Oliver Neukum884b6002005-04-21 21:28:02 +0200731 spin_lock_irqsave(&acm->write_lock, flags);
Alan Cox6e47e062009-06-11 12:37:06 +0100732 wbn = acm_wb_alloc(acm);
733 if (wbn < 0) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200734 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200735 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200737 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
Oliver Neukum884b6002005-04-21 21:28:02 +0200739 count = (count > acm->writesize) ? acm->writesize : count;
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100740 dev_dbg(&acm->data->dev, "%s - write %d\n", __func__, count);
Oliver Neukum884b6002005-04-21 21:28:02 +0200741 memcpy(wb->buf, buf, count);
742 wb->len = count;
743 spin_unlock_irqrestore(&acm->write_lock, flags);
744
Alan Cox6e47e062009-06-11 12:37:06 +0100745 stat = acm_write_start(acm, wbn);
746 if (stat < 0)
Oliver Neukum884b6002005-04-21 21:28:02 +0200747 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 return count;
749}
750
751static int acm_tty_write_room(struct tty_struct *tty)
752{
753 struct acm *acm = tty->driver_data;
754 if (!ACM_READY(acm))
755 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200756 /*
757 * Do not let the line discipline to know that we have a reserve,
758 * or it might get too enthusiastic.
759 */
David Brownell934da462008-08-06 18:44:12 -0700760 return acm_wb_is_avail(acm) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761}
762
763static int acm_tty_chars_in_buffer(struct tty_struct *tty)
764{
765 struct acm *acm = tty->driver_data;
766 if (!ACM_READY(acm))
Alan Cox23198fd2009-07-20 16:05:27 +0100767 return 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200768 /*
769 * This is inaccurate (overcounts), but it works.
770 */
Oliver Neukum86478942006-05-13 22:50:47 +0200771 return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772}
773
774static void acm_tty_throttle(struct tty_struct *tty)
775{
776 struct acm *acm = tty->driver_data;
777 if (!ACM_READY(acm))
778 return;
779 spin_lock_bh(&acm->throttle_lock);
780 acm->throttle = 1;
781 spin_unlock_bh(&acm->throttle_lock);
782}
783
784static void acm_tty_unthrottle(struct tty_struct *tty)
785{
786 struct acm *acm = tty->driver_data;
787 if (!ACM_READY(acm))
788 return;
789 spin_lock_bh(&acm->throttle_lock);
790 acm->throttle = 0;
791 spin_unlock_bh(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100792 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793}
794
Alan Cox9e989662008-07-22 11:18:03 +0100795static int acm_tty_break_ctl(struct tty_struct *tty, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
797 struct acm *acm = tty->driver_data;
Alan Cox9e989662008-07-22 11:18:03 +0100798 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 if (!ACM_READY(acm))
Alan Cox9e989662008-07-22 11:18:03 +0100800 return -EINVAL;
801 retval = acm_send_break(acm, state ? 0xffff : 0);
802 if (retval < 0)
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100803 dev_dbg(&acm->control->dev, "%s - send break failed\n",
804 __func__);
Alan Cox9e989662008-07-22 11:18:03 +0100805 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806}
807
Alan Cox60b33c12011-02-14 16:26:14 +0000808static int acm_tty_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809{
810 struct acm *acm = tty->driver_data;
811
812 if (!ACM_READY(acm))
813 return -EINVAL;
814
815 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
816 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
817 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
818 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
819 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
820 TIOCM_CTS;
821}
822
Alan Cox20b9d172011-02-14 16:26:50 +0000823static int acm_tty_tiocmset(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 unsigned int set, unsigned int clear)
825{
826 struct acm *acm = tty->driver_data;
827 unsigned int newctrl;
828
829 if (!ACM_READY(acm))
830 return -EINVAL;
831
832 newctrl = acm->ctrlout;
Alan Cox6e47e062009-06-11 12:37:06 +0100833 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
834 (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
835 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
836 (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
838 newctrl = (newctrl & ~clear) | set;
839
840 if (acm->ctrlout == newctrl)
841 return 0;
842 return acm_set_control(acm, acm->ctrlout = newctrl);
843}
844
Alan Cox6caa76b2011-02-14 16:27:22 +0000845static int acm_tty_ioctl(struct tty_struct *tty,
Alan Cox6e47e062009-06-11 12:37:06 +0100846 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847{
848 struct acm *acm = tty->driver_data;
849
850 if (!ACM_READY(acm))
851 return -EINVAL;
852
853 return -ENOIOCTLCMD;
854}
855
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100856static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 0, 50, 75, 110, 134, 150, 200, 300, 600,
858 1200, 1800, 2400, 4800, 9600, 19200, 38400,
859 57600, 115200, 230400, 460800, 500000, 576000,
860 921600, 1000000, 1152000, 1500000, 2000000,
861 2500000, 3000000, 3500000, 4000000
862};
863
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100864static const __u8 acm_tty_size[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 5, 6, 7, 8
866};
867
Alan Cox6e47e062009-06-11 12:37:06 +0100868static void acm_tty_set_termios(struct tty_struct *tty,
869 struct ktermios *termios_old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
871 struct acm *acm = tty->driver_data;
Alan Cox606d0992006-12-08 02:38:45 -0800872 struct ktermios *termios = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 struct usb_cdc_line_coding newline;
874 int newctrl = acm->ctrlout;
875
876 if (!ACM_READY(acm))
877 return;
878
Alan Cox9b80fee2009-09-19 13:13:23 -0700879 newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
881 newline.bParityType = termios->c_cflag & PARENB ?
Alan Cox6e47e062009-06-11 12:37:06 +0100882 (termios->c_cflag & PARODD ? 1 : 2) +
883 (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
Alan Cox6e47e062009-06-11 12:37:06 +0100885 /* FIXME: Needs to clear unsupported bits in the termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
887
888 if (!newline.dwDTERate) {
889 newline.dwDTERate = acm->line.dwDTERate;
890 newctrl &= ~ACM_CTRL_DTR;
Alan Cox6e47e062009-06-11 12:37:06 +0100891 } else
892 newctrl |= ACM_CTRL_DTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
894 if (newctrl != acm->ctrlout)
895 acm_set_control(acm, acm->ctrlout = newctrl);
896
897 if (memcmp(&acm->line, &newline, sizeof newline)) {
898 memcpy(&acm->line, &newline, sizeof newline);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100899 dev_dbg(&acm->control->dev, "%s - set line: %d %d %d %d\n",
900 __func__,
901 le32_to_cpu(newline.dwDTERate),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 newline.bCharFormat, newline.bParityType,
903 newline.bDataBits);
904 acm_set_line(acm, &acm->line);
905 }
906}
907
908/*
909 * USB probe and disconnect routines.
910 */
911
Oliver Neukum830f4022008-06-25 14:17:16 +0200912/* Little helpers: write/read buffers free */
Oliver Neukum884b6002005-04-21 21:28:02 +0200913static void acm_write_buffers_free(struct acm *acm)
914{
915 int i;
916 struct acm_wb *wb;
Oliver Neukuma496c642008-10-21 10:39:04 +0200917 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
Oliver Neukum884b6002005-04-21 21:28:02 +0200918
Alan Cox6e47e062009-06-11 12:37:06 +0100919 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++)
Daniel Mack997ea582010-04-12 13:17:25 +0200920 usb_free_coherent(usb_dev, acm->writesize, wb->buf, wb->dmah);
Oliver Neukum884b6002005-04-21 21:28:02 +0200921}
922
Oliver Neukum830f4022008-06-25 14:17:16 +0200923static void acm_read_buffers_free(struct acm *acm)
924{
925 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
926 int i, n = acm->rx_buflimit;
927
928 for (i = 0; i < n; i++)
Daniel Mack997ea582010-04-12 13:17:25 +0200929 usb_free_coherent(usb_dev, acm->readsize,
930 acm->rb[i].base, acm->rb[i].dma);
Oliver Neukum830f4022008-06-25 14:17:16 +0200931}
932
Oliver Neukum884b6002005-04-21 21:28:02 +0200933/* Little helper: write buffers allocate */
934static int acm_write_buffers_alloc(struct acm *acm)
935{
936 int i;
937 struct acm_wb *wb;
938
Oliver Neukum86478942006-05-13 22:50:47 +0200939 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Daniel Mack997ea582010-04-12 13:17:25 +0200940 wb->buf = usb_alloc_coherent(acm->dev, acm->writesize, GFP_KERNEL,
Oliver Neukum884b6002005-04-21 21:28:02 +0200941 &wb->dmah);
942 if (!wb->buf) {
943 while (i != 0) {
944 --i;
945 --wb;
Daniel Mack997ea582010-04-12 13:17:25 +0200946 usb_free_coherent(acm->dev, acm->writesize,
Oliver Neukum884b6002005-04-21 21:28:02 +0200947 wb->buf, wb->dmah);
948 }
949 return -ENOMEM;
950 }
951 }
952 return 0;
953}
954
Alan Cox10077d42009-06-11 12:36:09 +0100955static int acm_probe(struct usb_interface *intf,
956 const struct usb_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957{
958 struct usb_cdc_union_desc *union_header = NULL;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100959 struct usb_cdc_country_functional_desc *cfd = NULL;
David Brownellc6dbf552008-04-13 14:00:44 -0700960 unsigned char *buffer = intf->altsetting->extra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 int buflen = intf->altsetting->extralen;
962 struct usb_interface *control_interface;
963 struct usb_interface *data_interface;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +0200964 struct usb_endpoint_descriptor *epctrl = NULL;
965 struct usb_endpoint_descriptor *epread = NULL;
966 struct usb_endpoint_descriptor *epwrite = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 struct usb_device *usb_dev = interface_to_usbdev(intf);
968 struct acm *acm;
969 int minor;
Alan Cox6e47e062009-06-11 12:37:06 +0100970 int ctrlsize, readsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 u8 *buf;
972 u8 ac_management_function = 0;
973 u8 call_management_function = 0;
974 int call_interface_num = -1;
975 int data_interface_num;
976 unsigned long quirks;
Oliver Neukum86478942006-05-13 22:50:47 +0200977 int num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +0100978 int i;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +0200979 int combined_interfaces = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Oliver Neukum86478942006-05-13 22:50:47 +0200981 /* normal quirks */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 quirks = (unsigned long)id->driver_info;
Oliver Neukum86478942006-05-13 22:50:47 +0200983 num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
984
985 /* handle quirks deadly to normal probing*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 if (quirks == NO_UNION_NORMAL) {
987 data_interface = usb_ifnum_to_if(usb_dev, 1);
988 control_interface = usb_ifnum_to_if(usb_dev, 0);
989 goto skip_normal_probe;
990 }
Alan Cox6e47e062009-06-11 12:37:06 +0100991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 /* normal probing*/
993 if (!buffer) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700994 dev_err(&intf->dev, "Weird descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 return -EINVAL;
996 }
997
998 if (!buflen) {
Toby Gray577045c2010-09-02 10:46:20 +0100999 if (intf->cur_altsetting->endpoint &&
1000 intf->cur_altsetting->endpoint->extralen &&
Alan Cox6e47e062009-06-11 12:37:06 +01001001 intf->cur_altsetting->endpoint->extra) {
1002 dev_dbg(&intf->dev,
1003 "Seeking extra descriptors on endpoint\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 buflen = intf->cur_altsetting->endpoint->extralen;
1005 buffer = intf->cur_altsetting->endpoint->extra;
1006 } else {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001007 dev_err(&intf->dev,
1008 "Zero length descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 return -EINVAL;
1010 }
1011 }
1012
1013 while (buflen > 0) {
Alan Cox6e47e062009-06-11 12:37:06 +01001014 if (buffer[1] != USB_DT_CS_INTERFACE) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001015 dev_err(&intf->dev, "skipping garbage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 goto next_desc;
1017 }
1018
Alan Cox6e47e062009-06-11 12:37:06 +01001019 switch (buffer[2]) {
1020 case USB_CDC_UNION_TYPE: /* we've found it */
1021 if (union_header) {
1022 dev_err(&intf->dev, "More than one "
1023 "union descriptor, skipping ...\n");
1024 goto next_desc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 }
Alan Cox6e47e062009-06-11 12:37:06 +01001026 union_header = (struct usb_cdc_union_desc *)buffer;
1027 break;
1028 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
1029 cfd = (struct usb_cdc_country_functional_desc *)buffer;
1030 break;
1031 case USB_CDC_HEADER_TYPE: /* maybe check version */
1032 break; /* for now we ignore it */
1033 case USB_CDC_ACM_TYPE:
1034 ac_management_function = buffer[3];
1035 break;
1036 case USB_CDC_CALL_MANAGEMENT_TYPE:
1037 call_management_function = buffer[3];
1038 call_interface_num = buffer[4];
Julian Calabyce126642010-01-05 23:58:20 +11001039 if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
Alan Cox6e47e062009-06-11 12:37:06 +01001040 dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
1041 break;
1042 default:
1043 /* there are LOTS more CDC descriptors that
1044 * could legitimately be found here.
1045 */
1046 dev_dbg(&intf->dev, "Ignoring descriptor: "
1047 "type %02x, length %d\n",
1048 buffer[2], buffer[0]);
1049 break;
1050 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051next_desc:
1052 buflen -= buffer[0];
1053 buffer += buffer[0];
1054 }
1055
1056 if (!union_header) {
1057 if (call_interface_num > 0) {
Alan Cox6e47e062009-06-11 12:37:06 +01001058 dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
1060 control_interface = intf;
1061 } else {
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001062 if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
1063 dev_dbg(&intf->dev,"No union descriptor, giving up\n");
1064 return -ENODEV;
1065 } else {
1066 dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n");
1067 combined_interfaces = 1;
1068 control_interface = data_interface = intf;
1069 goto look_for_collapsed_interface;
1070 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 }
1072 } else {
1073 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
1074 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
1075 if (!control_interface || !data_interface) {
Alan Cox6e47e062009-06-11 12:37:06 +01001076 dev_dbg(&intf->dev, "no interfaces\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 return -ENODEV;
1078 }
1079 }
Alan Cox6e47e062009-06-11 12:37:06 +01001080
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 if (data_interface_num != call_interface_num)
Alan Cox6e47e062009-06-11 12:37:06 +01001082 dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001084 if (control_interface == data_interface) {
1085 /* some broken devices designed for windows work this way */
1086 dev_warn(&intf->dev,"Control and data interfaces are not separated!\n");
1087 combined_interfaces = 1;
1088 /* a popular other OS doesn't use it */
1089 quirks |= NO_CAP_LINE;
1090 if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) {
1091 dev_err(&intf->dev, "This needs exactly 3 endpoints\n");
1092 return -EINVAL;
1093 }
1094look_for_collapsed_interface:
1095 for (i = 0; i < 3; i++) {
1096 struct usb_endpoint_descriptor *ep;
1097 ep = &data_interface->cur_altsetting->endpoint[i].desc;
1098
1099 if (usb_endpoint_is_int_in(ep))
1100 epctrl = ep;
1101 else if (usb_endpoint_is_bulk_out(ep))
1102 epwrite = ep;
1103 else if (usb_endpoint_is_bulk_in(ep))
1104 epread = ep;
1105 else
1106 return -EINVAL;
1107 }
1108 if (!epctrl || !epread || !epwrite)
1109 return -ENODEV;
1110 else
1111 goto made_compressed_probe;
1112 }
1113
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114skip_normal_probe:
1115
1116 /*workaround for switched interfaces */
Alan Cox6e47e062009-06-11 12:37:06 +01001117 if (data_interface->cur_altsetting->desc.bInterfaceClass
1118 != CDC_DATA_INTERFACE_TYPE) {
1119 if (control_interface->cur_altsetting->desc.bInterfaceClass
1120 == CDC_DATA_INTERFACE_TYPE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 struct usb_interface *t;
Alan Cox6e47e062009-06-11 12:37:06 +01001122 dev_dbg(&intf->dev,
1123 "Your device has switched interfaces.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 t = control_interface;
1125 control_interface = data_interface;
1126 data_interface = t;
1127 } else {
1128 return -EINVAL;
1129 }
1130 }
Alan Stern74da5d62007-08-02 13:29:10 -04001131
1132 /* Accept probe requests only for the control interface */
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001133 if (!combined_interfaces && intf != control_interface)
Alan Stern74da5d62007-08-02 13:29:10 -04001134 return -ENODEV;
Alan Cox6e47e062009-06-11 12:37:06 +01001135
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001136 if (!combined_interfaces && usb_interface_claimed(data_interface)) {
1137 /* valid in this context */
Alan Cox6e47e062009-06-11 12:37:06 +01001138 dev_dbg(&intf->dev, "The data interface isn't available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 return -EBUSY;
1140 }
1141
1142
1143 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
1144 return -EINVAL;
1145
1146 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
1147 epread = &data_interface->cur_altsetting->endpoint[0].desc;
1148 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
1149
1150
1151 /* workaround for switched endpoints */
Luiz Fernando N. Capitulino45aea702006-10-26 13:02:48 -03001152 if (!usb_endpoint_dir_in(epread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 /* descriptors are swapped */
1154 struct usb_endpoint_descriptor *t;
Alan Cox6e47e062009-06-11 12:37:06 +01001155 dev_dbg(&intf->dev,
1156 "The data interface has switched endpoints\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 t = epread;
1158 epread = epwrite;
1159 epwrite = t;
1160 }
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001161made_compressed_probe:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +01001162 dev_dbg(&intf->dev, "interfaces are valid\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
1164
1165 if (minor == ACM_TTY_MINORS) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001166 dev_err(&intf->dev, "no more free acm devices\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 return -ENODEV;
1168 }
1169
Alan Cox6e47e062009-06-11 12:37:06 +01001170 acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
1171 if (acm == NULL) {
Johan Hovold255ab562011-03-22 11:12:13 +01001172 dev_err(&intf->dev, "out of memory (acm kzalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 goto alloc_fail;
1174 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
1176 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
Alan Cox6e47e062009-06-11 12:37:06 +01001177 readsize = le16_to_cpu(epread->wMaxPacketSize) *
1178 (quirks == SINGLE_RX_URB ? 1 : 2);
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001179 acm->combined_interfaces = combined_interfaces;
David Engrafe4cf3aa2008-03-20 10:01:34 +01001180 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 acm->control = control_interface;
1182 acm->data = data_interface;
1183 acm->minor = minor;
1184 acm->dev = usb_dev;
1185 acm->ctrl_caps = ac_management_function;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001186 if (quirks & NO_CAP_LINE)
1187 acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 acm->ctrlsize = ctrlsize;
1189 acm->readsize = readsize;
Oliver Neukum86478942006-05-13 22:50:47 +02001190 acm->rx_buflimit = num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +01001191 acm->urb_task.func = acm_rx_tasklet;
1192 acm->urb_task.data = (unsigned long) acm;
David Howellsc4028952006-11-22 14:57:56 +00001193 INIT_WORK(&acm->work, acm_softint);
David Brownelle5fbab52008-08-06 18:46:10 -07001194 init_waitqueue_head(&acm->drain_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 spin_lock_init(&acm->throttle_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +02001196 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +01001197 spin_lock_init(&acm->read_lock);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001198 mutex_init(&acm->mutex);
David Kubicek61a87ad2005-11-01 18:51:34 +01001199 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Oliver Neukumcf7fdd52009-08-04 23:52:09 +02001200 acm->is_int_ep = usb_endpoint_xfer_int(epread);
1201 if (acm->is_int_ep)
1202 acm->bInterval = epread->bInterval;
Alan Cox739e0282009-06-11 12:27:50 +01001203 tty_port_init(&acm->port);
1204 acm->port.ops = &acm_port_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205
Daniel Mack997ea582010-04-12 13:17:25 +02001206 buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 if (!buf) {
Johan Hovold255ab562011-03-22 11:12:13 +01001208 dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 goto alloc_fail2;
1210 }
1211 acm->ctrl_buffer = buf;
1212
Oliver Neukum884b6002005-04-21 21:28:02 +02001213 if (acm_write_buffers_alloc(acm) < 0) {
Johan Hovold255ab562011-03-22 11:12:13 +01001214 dev_err(&intf->dev, "out of memory (write buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 goto alloc_fail4;
1216 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
1218 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
1219 if (!acm->ctrlurb) {
Johan Hovold255ab562011-03-22 11:12:13 +01001220 dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 goto alloc_fail5;
1222 }
Oliver Neukum86478942006-05-13 22:50:47 +02001223 for (i = 0; i < num_rx_buf; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +01001224 struct acm_ru *rcv = &(acm->ru[i]);
1225
Alan Cox6e47e062009-06-11 12:37:06 +01001226 rcv->urb = usb_alloc_urb(0, GFP_KERNEL);
1227 if (rcv->urb == NULL) {
Johan Hovold255ab562011-03-22 11:12:13 +01001228 dev_err(&intf->dev,
Alan Cox6e47e062009-06-11 12:37:06 +01001229 "out of memory (read urbs usb_alloc_urb)\n");
Axel Linc2572b72010-05-31 08:04:47 +08001230 goto alloc_fail6;
David Kubicek61a87ad2005-11-01 18:51:34 +01001231 }
1232
1233 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1234 rcv->instance = acm;
1235 }
Oliver Neukum86478942006-05-13 22:50:47 +02001236 for (i = 0; i < num_rx_buf; i++) {
David Brownell672c4e12008-08-06 18:41:12 -07001237 struct acm_rb *rb = &(acm->rb[i]);
David Kubicek61a87ad2005-11-01 18:51:34 +01001238
Daniel Mack997ea582010-04-12 13:17:25 +02001239 rb->base = usb_alloc_coherent(acm->dev, readsize,
David Brownell672c4e12008-08-06 18:41:12 -07001240 GFP_KERNEL, &rb->dma);
1241 if (!rb->base) {
Johan Hovold255ab562011-03-22 11:12:13 +01001242 dev_err(&intf->dev,
Daniel Mack997ea582010-04-12 13:17:25 +02001243 "out of memory (read bufs usb_alloc_coherent)\n");
David Kubicek61a87ad2005-11-01 18:51:34 +01001244 goto alloc_fail7;
1245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 }
Alan Cox6e47e062009-06-11 12:37:06 +01001247 for (i = 0; i < ACM_NW; i++) {
David Engrafe4cf3aa2008-03-20 10:01:34 +01001248 struct acm_wb *snd = &(acm->wb[i]);
1249
Alan Cox6e47e062009-06-11 12:37:06 +01001250 snd->urb = usb_alloc_urb(0, GFP_KERNEL);
1251 if (snd->urb == NULL) {
Johan Hovold255ab562011-03-22 11:12:13 +01001252 dev_err(&intf->dev,
Johan Hovold59d7fec2011-03-22 11:12:12 +01001253 "out of memory (write urbs usb_alloc_urb)\n");
Axel Linc2572b72010-05-31 08:04:47 +08001254 goto alloc_fail8;
David Engrafe4cf3aa2008-03-20 10:01:34 +01001255 }
1256
Arseniy Lartsev5186ffe2009-07-01 16:27:26 +04001257 if (usb_endpoint_xfer_int(epwrite))
1258 usb_fill_int_urb(snd->urb, usb_dev,
1259 usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
1260 NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval);
1261 else
1262 usb_fill_bulk_urb(snd->urb, usb_dev,
1263 usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
1264 NULL, acm->writesize, acm_write_bulk, snd);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001265 snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1266 snd->instance = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 }
1268
Alan Cox6e47e062009-06-11 12:37:06 +01001269 usb_set_intfdata(intf, acm);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001270
1271 i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
1272 if (i < 0)
1273 goto alloc_fail8;
1274
1275 if (cfd) { /* export the country data */
1276 acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
1277 if (!acm->country_codes)
1278 goto skip_countries;
1279 acm->country_code_size = cfd->bLength - 4;
Alan Cox6e47e062009-06-11 12:37:06 +01001280 memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0,
1281 cfd->bLength - 4);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001282 acm->country_rel_date = cfd->iCountryCodeRelDate;
1283
1284 i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
1285 if (i < 0) {
1286 kfree(acm->country_codes);
1287 goto skip_countries;
1288 }
1289
Alan Cox6e47e062009-06-11 12:37:06 +01001290 i = device_create_file(&intf->dev,
1291 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001292 if (i < 0) {
Axel Linc2572b72010-05-31 08:04:47 +08001293 device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001294 kfree(acm->country_codes);
1295 goto skip_countries;
1296 }
1297 }
1298
1299skip_countries:
Alan Cox6e47e062009-06-11 12:37:06 +01001300 usb_fill_int_urb(acm->ctrlurb, usb_dev,
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001301 usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
1302 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
1303 /* works around buggy devices */
1304 epctrl->bInterval ? epctrl->bInterval : 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1306 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
1307
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
1309
1310 acm_set_control(acm, acm->ctrlout);
1311
1312 acm->line.dwDTERate = cpu_to_le32(9600);
1313 acm->line.bDataBits = 8;
1314 acm_set_line(acm, &acm->line);
1315
1316 usb_driver_claim_interface(&acm_driver, data_interface, acm);
David Brownell672c4e12008-08-06 18:41:12 -07001317 usb_set_intfdata(data_interface, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001319 usb_get_intf(control_interface);
1320 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
1322 acm_table[minor] = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001324 return 0;
1325alloc_fail8:
David Engrafe4cf3aa2008-03-20 10:01:34 +01001326 for (i = 0; i < ACM_NW; i++)
1327 usb_free_urb(acm->wb[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328alloc_fail7:
Oliver Neukum830f4022008-06-25 14:17:16 +02001329 acm_read_buffers_free(acm);
Axel Linc2572b72010-05-31 08:04:47 +08001330alloc_fail6:
Oliver Neukum86478942006-05-13 22:50:47 +02001331 for (i = 0; i < num_rx_buf; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001332 usb_free_urb(acm->ru[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 usb_free_urb(acm->ctrlurb);
1334alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001335 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336alloc_fail4:
Daniel Mack997ea582010-04-12 13:17:25 +02001337 usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338alloc_fail2:
1339 kfree(acm);
1340alloc_fail:
1341 return -ENOMEM;
1342}
1343
Oliver Neukum1365baf2007-10-12 17:24:28 +02001344static void stop_data_traffic(struct acm *acm)
1345{
1346 int i;
Johan Hovolda5cc7ef2011-03-22 11:12:15 +01001347
1348 dev_dbg(&acm->control->dev, "%s\n", __func__);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001349
1350 tasklet_disable(&acm->urb_task);
1351
1352 usb_kill_urb(acm->ctrlurb);
Alan Cox6e47e062009-06-11 12:37:06 +01001353 for (i = 0; i < ACM_NW; i++)
David Engrafe4cf3aa2008-03-20 10:01:34 +01001354 usb_kill_urb(acm->wb[i].urb);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001355 for (i = 0; i < acm->rx_buflimit; i++)
1356 usb_kill_urb(acm->ru[i].urb);
1357
Oliver Neukum1365baf2007-10-12 17:24:28 +02001358 tasklet_enable(&acm->urb_task);
1359
1360 cancel_work_sync(&acm->work);
1361}
1362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363static void acm_disconnect(struct usb_interface *intf)
1364{
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001365 struct acm *acm = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 struct usb_device *usb_dev = interface_to_usbdev(intf);
Alan Cox10077d42009-06-11 12:36:09 +01001367 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
David Brownell672c4e12008-08-06 18:41:12 -07001369 /* sibling interface is already cleaning up */
1370 if (!acm)
Oliver Neukum86067eea2006-01-08 12:39:13 +01001371 return;
David Brownell672c4e12008-08-06 18:41:12 -07001372
1373 mutex_lock(&open_mutex);
Alan Cox6e47e062009-06-11 12:37:06 +01001374 if (acm->country_codes) {
Alan Stern74da5d62007-08-02 13:29:10 -04001375 device_remove_file(&acm->control->dev,
1376 &dev_attr_wCountryCodes);
1377 device_remove_file(&acm->control->dev,
1378 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001379 }
Alan Stern74da5d62007-08-02 13:29:10 -04001380 device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 acm->dev = NULL;
Oliver Neukum86067eea2006-01-08 12:39:13 +01001382 usb_set_intfdata(acm->control, NULL);
1383 usb_set_intfdata(acm->data, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
Oliver Neukum1365baf2007-10-12 17:24:28 +02001385 stop_data_traffic(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386
Oliver Neukum884b6002005-04-21 21:28:02 +02001387 acm_write_buffers_free(acm);
Daniel Mack997ea582010-04-12 13:17:25 +02001388 usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer,
1389 acm->ctrl_dma);
Oliver Neukum830f4022008-06-25 14:17:16 +02001390 acm_read_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001392 if (!acm->combined_interfaces)
1393 usb_driver_release_interface(&acm_driver, intf == acm->control ?
Oliver Neukum830f4022008-06-25 14:17:16 +02001394 acm->data : acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
Alan Cox10077d42009-06-11 12:36:09 +01001396 if (acm->port.count == 0) {
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001397 acm_tty_unregister(acm);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001398 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 return;
1400 }
1401
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001402 mutex_unlock(&open_mutex);
Alan Cox10077d42009-06-11 12:36:09 +01001403 tty = tty_port_tty_get(&acm->port);
1404 if (tty) {
1405 tty_hangup(tty);
1406 tty_kref_put(tty);
1407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408}
1409
Oliver Neukum35758582008-07-01 19:10:08 +02001410#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001411static int acm_suspend(struct usb_interface *intf, pm_message_t message)
1412{
1413 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001414 int cnt;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001415
Alan Stern65bfd292008-11-25 16:39:18 -05001416 if (message.event & PM_EVENT_AUTO) {
Oliver Neukum11ea8592008-06-20 11:25:57 +02001417 int b;
1418
1419 spin_lock_irq(&acm->read_lock);
1420 spin_lock(&acm->write_lock);
1421 b = acm->processing + acm->transmitting;
1422 spin_unlock(&acm->write_lock);
1423 spin_unlock_irq(&acm->read_lock);
1424 if (b)
1425 return -EBUSY;
1426 }
1427
1428 spin_lock_irq(&acm->read_lock);
1429 spin_lock(&acm->write_lock);
1430 cnt = acm->susp_count++;
1431 spin_unlock(&acm->write_lock);
1432 spin_unlock_irq(&acm->read_lock);
1433
1434 if (cnt)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001435 return 0;
1436 /*
1437 we treat opened interfaces differently,
1438 we must guard against open
1439 */
1440 mutex_lock(&acm->mutex);
1441
Alan Cox10077d42009-06-11 12:36:09 +01001442 if (acm->port.count)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001443 stop_data_traffic(acm);
1444
1445 mutex_unlock(&acm->mutex);
1446 return 0;
1447}
1448
1449static int acm_resume(struct usb_interface *intf)
1450{
1451 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum97d35f92009-12-16 17:05:57 +01001452 struct acm_wb *wb;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001453 int rv = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +02001454 int cnt;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001455
Oliver Neukum11ea8592008-06-20 11:25:57 +02001456 spin_lock_irq(&acm->read_lock);
1457 acm->susp_count -= 1;
1458 cnt = acm->susp_count;
1459 spin_unlock_irq(&acm->read_lock);
1460
1461 if (cnt)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001462 return 0;
1463
1464 mutex_lock(&acm->mutex);
Alan Cox10077d42009-06-11 12:36:09 +01001465 if (acm->port.count) {
Oliver Neukum1365baf2007-10-12 17:24:28 +02001466 rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
Oliver Neukum97d35f92009-12-16 17:05:57 +01001467
1468 spin_lock_irq(&acm->write_lock);
1469 if (acm->delayed_wb) {
1470 wb = acm->delayed_wb;
1471 acm->delayed_wb = NULL;
1472 spin_unlock_irq(&acm->write_lock);
Oliver Neukumf0730922010-03-03 00:37:56 +01001473 acm_start_wb(acm, wb);
Oliver Neukum97d35f92009-12-16 17:05:57 +01001474 } else {
1475 spin_unlock_irq(&acm->write_lock);
1476 }
1477
1478 /*
1479 * delayed error checking because we must
1480 * do the write path at all cost
1481 */
Oliver Neukum1365baf2007-10-12 17:24:28 +02001482 if (rv < 0)
Oliver Neukum11ea8592008-06-20 11:25:57 +02001483 goto err_out;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001484
1485 tasklet_schedule(&acm->urb_task);
1486 }
1487
1488err_out:
1489 mutex_unlock(&acm->mutex);
1490 return rv;
1491}
Oliver Neukum35758582008-07-01 19:10:08 +02001492
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001493static int acm_reset_resume(struct usb_interface *intf)
1494{
1495 struct acm *acm = usb_get_intfdata(intf);
1496 struct tty_struct *tty;
1497
1498 mutex_lock(&acm->mutex);
1499 if (acm->port.count) {
1500 tty = tty_port_tty_get(&acm->port);
1501 if (tty) {
1502 tty_hangup(tty);
1503 tty_kref_put(tty);
1504 }
1505 }
1506 mutex_unlock(&acm->mutex);
1507 return acm_resume(intf);
1508}
1509
Oliver Neukum35758582008-07-01 19:10:08 +02001510#endif /* CONFIG_PM */
Adrian Taylorc1479a92009-11-19 10:35:33 +00001511
1512#define NOKIA_PCSUITE_ACM_INFO(x) \
1513 USB_DEVICE_AND_INTERFACE_INFO(0x0421, x, \
1514 USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \
1515 USB_CDC_ACM_PROTO_VENDOR)
1516
Toby Gray4035e452010-09-01 16:01:19 +01001517#define SAMSUNG_PCSUITE_ACM_INFO(x) \
1518 USB_DEVICE_AND_INTERFACE_INFO(0x04e7, x, \
1519 USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \
1520 USB_CDC_ACM_PROTO_VENDOR)
1521
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522/*
1523 * USB driver structure.
1524 */
1525
Németh Márton6ef48522010-01-10 15:33:45 +01001526static const struct usb_device_id acm_ids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 /* quirky and broken devices */
1528 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1529 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1530 },
Andrey Arapovb0e2a702007-07-04 17:11:42 +02001531 { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
1532 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1533 },
Andrew Lunn0f9c7b4a2008-12-23 17:31:23 +01001534 { USB_DEVICE(0x0e8d, 0x3329), /* MediaTek Inc GPS */
1535 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1536 },
Masahito Omote8753e652005-07-29 12:17:25 -07001537 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1538 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1539 },
Chris Malley91a9c922006-10-03 10:08:28 +01001540 { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
1541 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1542 },
Alan Cox7abcf202009-04-06 17:35:01 +01001543 { USB_DEVICE(0x0ace, 0x1602), /* ZyDAS 56K USB MODEM */
1544 .driver_info = SINGLE_RX_URB,
1545 },
Oliver Neukum86478942006-05-13 22:50:47 +02001546 { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
1547 .driver_info = SINGLE_RX_URB, /* firmware bug */
1548 },
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001549 { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
1550 .driver_info = SINGLE_RX_URB, /* firmware bug */
1551 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001552 { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
1553 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1554 },
Iain McFarlane6149ed52008-05-04 00:13:49 +01001555 { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */
1556 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1557 },
Eric Sandeenc8fd2c32008-08-14 08:25:40 -05001558 { USB_DEVICE(0x0572, 0x1321), /* Conexant USB MODEM CX93010 */
1559 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1560 },
Alan Coxc89c60e2009-01-11 19:53:10 +00001561 { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */
1562 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1563 },
Xiao Kaijiancab98a02009-05-08 00:48:23 +08001564 { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */
1565 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1566 },
Dmitriy Taychenachev155df652009-02-25 12:36:51 +08001567 { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
1568 },
Adam Richterc332b4e2009-02-18 16:17:15 -08001569 { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */
1570 .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on
1571 data interface instead of
1572 communications interface.
1573 Maybe we should define a new
1574 quirk for this. */
1575 },
Kir Kolyshkin1f17c502009-05-28 20:33:58 +04001576 { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */
1577 .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
1578 },
Russ Nelsonc3baa192010-04-21 23:07:03 -04001579 { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */
1580 .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
1581 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001582
Adrian Taylorc1479a92009-11-19 10:35:33 +00001583 /* Nokia S60 phones expose two ACM channels. The first is
1584 * a modem and is picked up by the standard AT-command
1585 * information below. The second is 'vendor-specific' but
1586 * is treated as a serial device at the S60 end, so we want
1587 * to expose it on Linux too. */
1588 { NOKIA_PCSUITE_ACM_INFO(0x042D), }, /* Nokia 3250 */
1589 { NOKIA_PCSUITE_ACM_INFO(0x04D8), }, /* Nokia 5500 Sport */
1590 { NOKIA_PCSUITE_ACM_INFO(0x04C9), }, /* Nokia E50 */
1591 { NOKIA_PCSUITE_ACM_INFO(0x0419), }, /* Nokia E60 */
1592 { NOKIA_PCSUITE_ACM_INFO(0x044D), }, /* Nokia E61 */
1593 { NOKIA_PCSUITE_ACM_INFO(0x0001), }, /* Nokia E61i */
1594 { NOKIA_PCSUITE_ACM_INFO(0x0475), }, /* Nokia E62 */
1595 { NOKIA_PCSUITE_ACM_INFO(0x0508), }, /* Nokia E65 */
1596 { NOKIA_PCSUITE_ACM_INFO(0x0418), }, /* Nokia E70 */
1597 { NOKIA_PCSUITE_ACM_INFO(0x0425), }, /* Nokia N71 */
1598 { NOKIA_PCSUITE_ACM_INFO(0x0486), }, /* Nokia N73 */
1599 { NOKIA_PCSUITE_ACM_INFO(0x04DF), }, /* Nokia N75 */
1600 { NOKIA_PCSUITE_ACM_INFO(0x000e), }, /* Nokia N77 */
1601 { NOKIA_PCSUITE_ACM_INFO(0x0445), }, /* Nokia N80 */
1602 { NOKIA_PCSUITE_ACM_INFO(0x042F), }, /* Nokia N91 & N91 8GB */
1603 { NOKIA_PCSUITE_ACM_INFO(0x048E), }, /* Nokia N92 */
1604 { NOKIA_PCSUITE_ACM_INFO(0x0420), }, /* Nokia N93 */
1605 { NOKIA_PCSUITE_ACM_INFO(0x04E6), }, /* Nokia N93i */
1606 { NOKIA_PCSUITE_ACM_INFO(0x04B2), }, /* Nokia 5700 XpressMusic */
1607 { NOKIA_PCSUITE_ACM_INFO(0x0134), }, /* Nokia 6110 Navigator (China) */
1608 { NOKIA_PCSUITE_ACM_INFO(0x046E), }, /* Nokia 6110 Navigator */
1609 { NOKIA_PCSUITE_ACM_INFO(0x002f), }, /* Nokia 6120 classic & */
1610 { NOKIA_PCSUITE_ACM_INFO(0x0088), }, /* Nokia 6121 classic */
1611 { NOKIA_PCSUITE_ACM_INFO(0x00fc), }, /* Nokia 6124 classic */
1612 { NOKIA_PCSUITE_ACM_INFO(0x0042), }, /* Nokia E51 */
1613 { NOKIA_PCSUITE_ACM_INFO(0x00b0), }, /* Nokia E66 */
1614 { NOKIA_PCSUITE_ACM_INFO(0x00ab), }, /* Nokia E71 */
1615 { NOKIA_PCSUITE_ACM_INFO(0x0481), }, /* Nokia N76 */
1616 { NOKIA_PCSUITE_ACM_INFO(0x0007), }, /* Nokia N81 & N81 8GB */
1617 { NOKIA_PCSUITE_ACM_INFO(0x0071), }, /* Nokia N82 */
1618 { NOKIA_PCSUITE_ACM_INFO(0x04F0), }, /* Nokia N95 & N95-3 NAM */
1619 { NOKIA_PCSUITE_ACM_INFO(0x0070), }, /* Nokia N95 8GB */
1620 { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */
1621 { NOKIA_PCSUITE_ACM_INFO(0x0099), }, /* Nokia 6210 Navigator, RM-367 */
1622 { NOKIA_PCSUITE_ACM_INFO(0x0128), }, /* Nokia 6210 Navigator, RM-419 */
1623 { NOKIA_PCSUITE_ACM_INFO(0x008f), }, /* Nokia 6220 Classic */
1624 { NOKIA_PCSUITE_ACM_INFO(0x00a0), }, /* Nokia 6650 */
1625 { NOKIA_PCSUITE_ACM_INFO(0x007b), }, /* Nokia N78 */
1626 { NOKIA_PCSUITE_ACM_INFO(0x0094), }, /* Nokia N85 */
1627 { NOKIA_PCSUITE_ACM_INFO(0x003a), }, /* Nokia N96 & N96-3 */
1628 { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */
1629 { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */
1630 { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */
Przemo Firszt83a4eae2010-06-28 21:29:34 +01001631 { NOKIA_PCSUITE_ACM_INFO(0x02e3), }, /* Nokia 5230, RM-588 */
Toby Gray4035e452010-09-01 16:01:19 +01001632 { NOKIA_PCSUITE_ACM_INFO(0x0178), }, /* Nokia E63 */
1633 { NOKIA_PCSUITE_ACM_INFO(0x010e), }, /* Nokia E75 */
1634 { NOKIA_PCSUITE_ACM_INFO(0x02d9), }, /* Nokia 6760 Slide */
1635 { NOKIA_PCSUITE_ACM_INFO(0x01d0), }, /* Nokia E52 */
1636 { NOKIA_PCSUITE_ACM_INFO(0x0223), }, /* Nokia E72 */
1637 { NOKIA_PCSUITE_ACM_INFO(0x0275), }, /* Nokia X6 */
1638 { NOKIA_PCSUITE_ACM_INFO(0x026c), }, /* Nokia N97 Mini */
1639 { NOKIA_PCSUITE_ACM_INFO(0x0154), }, /* Nokia 5800 XpressMusic */
1640 { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */
1641 { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */
Arvid Ephraim Picciani721d92f2011-01-25 15:58:40 +01001642 { NOKIA_PCSUITE_ACM_INFO(0x0302), }, /* Nokia N8 */
Toby Gray4035e452010-09-01 16:01:19 +01001643 { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */
Adrian Taylorc1479a92009-11-19 10:35:33 +00001644
1645 /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
1646
Julian Calaby7c5d8c32010-01-05 23:57:46 +11001647 /* Support Lego NXT using pbLua firmware */
Julian Calabyce126642010-01-05 23:58:20 +11001648 { USB_DEVICE(0x0694, 0xff00),
1649 .driver_info = NOT_A_MODEM,
Otavio Salvador7893afc2010-09-26 23:35:05 -03001650 },
Julian Calaby7c5d8c32010-01-05 23:57:46 +11001651
Philippe Corbes5b239f02010-08-31 19:31:32 +02001652 /* control interfaces without any protocol set */
1653 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1654 USB_CDC_PROTO_NONE) },
1655
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 /* control interfaces with various AT-command sets */
1657 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1658 USB_CDC_ACM_PROTO_AT_V25TER) },
1659 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1660 USB_CDC_ACM_PROTO_AT_PCCA101) },
1661 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1662 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1663 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1664 USB_CDC_ACM_PROTO_AT_GSM) },
1665 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
Alan Cox6e47e062009-06-11 12:37:06 +01001666 USB_CDC_ACM_PROTO_AT_3G) },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1668 USB_CDC_ACM_PROTO_AT_CDMA) },
1669
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 { }
1671};
1672
Alan Cox6e47e062009-06-11 12:37:06 +01001673MODULE_DEVICE_TABLE(usb, acm_ids);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
1675static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 .name = "cdc_acm",
1677 .probe = acm_probe,
1678 .disconnect = acm_disconnect,
Oliver Neukum35758582008-07-01 19:10:08 +02001679#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001680 .suspend = acm_suspend,
1681 .resume = acm_resume,
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001682 .reset_resume = acm_reset_resume,
Oliver Neukum35758582008-07-01 19:10:08 +02001683#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 .id_table = acm_ids,
Oliver Neukum35758582008-07-01 19:10:08 +02001685#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001686 .supports_autosuspend = 1,
Oliver Neukum35758582008-07-01 19:10:08 +02001687#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688};
1689
1690/*
1691 * TTY driver structures.
1692 */
1693
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001694static const struct tty_operations acm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 .open = acm_tty_open,
1696 .close = acm_tty_close,
Alan Cox10077d42009-06-11 12:36:09 +01001697 .hangup = acm_tty_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 .write = acm_tty_write,
1699 .write_room = acm_tty_write_room,
1700 .ioctl = acm_tty_ioctl,
1701 .throttle = acm_tty_throttle,
1702 .unthrottle = acm_tty_unthrottle,
1703 .chars_in_buffer = acm_tty_chars_in_buffer,
1704 .break_ctl = acm_tty_break_ctl,
1705 .set_termios = acm_tty_set_termios,
1706 .tiocmget = acm_tty_tiocmget,
1707 .tiocmset = acm_tty_tiocmset,
1708};
1709
1710/*
1711 * Init / exit.
1712 */
1713
1714static int __init acm_init(void)
1715{
1716 int retval;
1717 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1718 if (!acm_tty_driver)
1719 return -ENOMEM;
1720 acm_tty_driver->owner = THIS_MODULE,
1721 acm_tty_driver->driver_name = "acm",
1722 acm_tty_driver->name = "ttyACM",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 acm_tty_driver->major = ACM_TTY_MAJOR,
1724 acm_tty_driver->minor_start = 0,
1725 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1726 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001727 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 acm_tty_driver->init_termios = tty_std_termios;
Alan Cox6e47e062009-06-11 12:37:06 +01001729 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD |
1730 HUPCL | CLOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 tty_set_operations(acm_tty_driver, &acm_ops);
1732
1733 retval = tty_register_driver(acm_tty_driver);
1734 if (retval) {
1735 put_tty_driver(acm_tty_driver);
1736 return retval;
1737 }
1738
1739 retval = usb_register(&acm_driver);
1740 if (retval) {
1741 tty_unregister_driver(acm_tty_driver);
1742 put_tty_driver(acm_tty_driver);
1743 return retval;
1744 }
1745
Greg Kroah-Hartman5909f6e2008-08-18 13:21:04 -07001746 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
1747 DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748
1749 return 0;
1750}
1751
1752static void __exit acm_exit(void)
1753{
1754 usb_deregister(&acm_driver);
1755 tty_unregister_driver(acm_tty_driver);
1756 put_tty_driver(acm_tty_driver);
1757}
1758
1759module_init(acm_init);
1760module_exit(acm_exit);
1761
Alan Cox6e47e062009-06-11 12:37:06 +01001762MODULE_AUTHOR(DRIVER_AUTHOR);
1763MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764MODULE_LICENSE("GPL");
Scott James Remnante766aeb2009-04-06 17:33:18 +01001765MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR);