blob: 41d4ca527f82303aedc162e5331ec4d900a29aa9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * cdc-acm.c
3 *
4 * Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de>
5 * Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
6 * Copyright (c) 1999 Johannes Erdfelt <johannes@erdfelt.com>
7 * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
8 * Copyright (c) 2004 Oliver Neukum <oliver@neukum.name>
David Kubicek61a87ad2005-11-01 18:51:34 +01009 * Copyright (c) 2005 David Kubicek <dave@awk.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * USB Abstract Control Model driver for USB modems and ISDN adapters
12 *
13 * Sponsored by SuSE
14 *
15 * ChangeLog:
16 * v0.9 - thorough cleaning, URBification, almost a rewrite
17 * v0.10 - some more cleanups
18 * v0.11 - fixed flow control, read error doesn't stop reads
19 * v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced
20 * v0.13 - added termios, added hangup
21 * v0.14 - sized down struct acm
22 * v0.15 - fixed flow control again - characters could be lost
23 * v0.16 - added code for modems with swapped data and control interfaces
24 * v0.17 - added new style probing
25 * v0.18 - fixed new style probing for devices with more configurations
26 * v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan)
27 * v0.20 - switched to probing on interface (rather than device) class
28 * v0.21 - revert to probing on device for devices with multiple configs
29 * v0.22 - probe only the control interface. if usbcore doesn't choose the
30 * config we want, sysadmin changes bConfigurationValue in sysfs.
31 * v0.23 - use softirq for rx processing, as needed by tty layer
32 * v0.24 - change probe method to evaluate CDC union descriptor
David Kubicek61a87ad2005-11-01 18:51:34 +010033 * v0.25 - downstream tasks paralelized to maximize throughput
David Engrafe4cf3aa2008-03-20 10:01:34 +010034 * v0.26 - multiple write urbs, writesize increased
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 */
36
37/*
38 * This program is free software; you can redistribute it and/or modify
39 * it under the terms of the GNU General Public License as published by
40 * the Free Software Foundation; either version 2 of the License, or
41 * (at your option) any later version.
42 *
43 * This program is distributed in the hope that it will be useful,
44 * but WITHOUT ANY WARRANTY; without even the implied warranty of
45 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46 * GNU General Public License for more details.
47 *
48 * You should have received a copy of the GNU General Public License
49 * along with this program; if not, write to the Free Software
50 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
51 */
52
53#undef DEBUG
David Brownelle5fbab52008-08-06 18:46:10 -070054#undef VERBOSE_DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56#include <linux/kernel.h>
57#include <linux/errno.h>
58#include <linux/init.h>
59#include <linux/slab.h>
60#include <linux/tty.h>
61#include <linux/tty_driver.h>
62#include <linux/tty_flip.h>
63#include <linux/module.h>
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010064#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#include <asm/uaccess.h>
66#include <linux/usb.h>
David Brownella8c28f22006-06-13 09:57:47 -070067#include <linux/usb/cdc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#include <asm/byteorder.h>
69#include <asm/unaligned.h>
David Kubicek61a87ad2005-11-01 18:51:34 +010070#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
72#include "cdc-acm.h"
73
David Brownelle5fbab52008-08-06 18:46:10 -070074
75#define ACM_CLOSE_TIMEOUT 15 /* seconds to let writes drain */
76
Linus Torvalds1da177e2005-04-16 15:20:36 -070077/*
78 * Version Information
79 */
David Engrafe4cf3aa2008-03-20 10:01:34 +010080#define DRIVER_VERSION "v0.26"
David Kubicek61a87ad2005-11-01 18:51:34 +010081#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
Linus Torvalds1da177e2005-04-16 15:20:36 -070082#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
83
84static struct usb_driver acm_driver;
85static struct tty_driver *acm_tty_driver;
86static struct acm *acm_table[ACM_TTY_MINORS];
87
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010088static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90#define ACM_READY(acm) (acm && acm->dev && acm->used)
91
Alan Cox739e0282009-06-11 12:27:50 +010092static const struct tty_port_operations acm_port_ops = {
93};
94
David Brownelle5fbab52008-08-06 18:46:10 -070095#ifdef VERBOSE_DEBUG
96#define verbose 1
97#else
98#define verbose 0
99#endif
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101/*
102 * Functions for ACM control messages.
103 */
104
105static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
106{
107 int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
108 request, USB_RT_ACM, value,
109 acm->control->altsetting[0].desc.bInterfaceNumber,
110 buf, len, 5000);
111 dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
112 return retval < 0 ? retval : 0;
113}
114
115/* devices aren't required to support these requests.
116 * the cdc acm descriptor tells whether they do...
117 */
118#define acm_set_control(acm, control) \
119 acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
120#define acm_set_line(acm, line) \
121 acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
122#define acm_send_break(acm, ms) \
123 acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
124
125/*
Oliver Neukum884b6002005-04-21 21:28:02 +0200126 * Write buffer management.
127 * All of these assume proper locks taken by the caller.
128 */
129
130static int acm_wb_alloc(struct acm *acm)
131{
132 int i, wbn;
133 struct acm_wb *wb;
134
David Engrafe4cf3aa2008-03-20 10:01:34 +0100135 wbn = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200136 i = 0;
137 for (;;) {
138 wb = &acm->wb[wbn];
139 if (!wb->use) {
140 wb->use = 1;
141 return wbn;
142 }
Oliver Neukum86478942006-05-13 22:50:47 +0200143 wbn = (wbn + 1) % ACM_NW;
144 if (++i >= ACM_NW)
Oliver Neukum884b6002005-04-21 21:28:02 +0200145 return -1;
146 }
147}
148
Oliver Neukum884b6002005-04-21 21:28:02 +0200149static int acm_wb_is_avail(struct acm *acm)
150{
151 int i, n;
David Brownelle5fbab52008-08-06 18:46:10 -0700152 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200153
Oliver Neukum86478942006-05-13 22:50:47 +0200154 n = ACM_NW;
David Brownelle5fbab52008-08-06 18:46:10 -0700155 spin_lock_irqsave(&acm->write_lock, flags);
Oliver Neukum86478942006-05-13 22:50:47 +0200156 for (i = 0; i < ACM_NW; i++) {
157 n -= acm->wb[i].use;
Oliver Neukum884b6002005-04-21 21:28:02 +0200158 }
David Brownelle5fbab52008-08-06 18:46:10 -0700159 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200160 return n;
161}
162
Oliver Neukum884b6002005-04-21 21:28:02 +0200163/*
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800164 * Finish write. Caller must hold acm->write_lock
Oliver Neukum884b6002005-04-21 21:28:02 +0200165 */
David Engrafe4cf3aa2008-03-20 10:01:34 +0100166static void acm_write_done(struct acm *acm, struct acm_wb *wb)
Oliver Neukum884b6002005-04-21 21:28:02 +0200167{
David Engrafe4cf3aa2008-03-20 10:01:34 +0100168 wb->use = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200169 acm->transmitting--;
Oliver Neukum884b6002005-04-21 21:28:02 +0200170}
171
172/*
173 * Poke write.
Oliver Neukum11ea8592008-06-20 11:25:57 +0200174 *
175 * the caller is responsible for locking
Oliver Neukum884b6002005-04-21 21:28:02 +0200176 */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200177
178static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
179{
180 int rc;
181
182 acm->transmitting++;
183
184 wb->urb->transfer_buffer = wb->buf;
185 wb->urb->transfer_dma = wb->dmah;
186 wb->urb->transfer_buffer_length = wb->len;
187 wb->urb->dev = acm->dev;
188
189 if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) {
190 dbg("usb_submit_urb(write bulk) failed: %d", rc);
191 acm_write_done(acm, wb);
192 }
193 return rc;
194}
195
David Engrafe4cf3aa2008-03-20 10:01:34 +0100196static int acm_write_start(struct acm *acm, int wbn)
Oliver Neukum884b6002005-04-21 21:28:02 +0200197{
198 unsigned long flags;
David Brownell934da462008-08-06 18:44:12 -0700199 struct acm_wb *wb = &acm->wb[wbn];
Oliver Neukum884b6002005-04-21 21:28:02 +0200200 int rc;
201
202 spin_lock_irqsave(&acm->write_lock, flags);
203 if (!acm->dev) {
David Brownell934da462008-08-06 18:44:12 -0700204 wb->use = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200205 spin_unlock_irqrestore(&acm->write_lock, flags);
206 return -ENODEV;
207 }
208
Oliver Neukum11ea8592008-06-20 11:25:57 +0200209 dbg("%s susp_count: %d", __func__, acm->susp_count);
210 if (acm->susp_count) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200211 acm->delayed_wb = wb;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200212 schedule_work(&acm->waker);
213 spin_unlock_irqrestore(&acm->write_lock, flags);
214 return 0; /* A white lie */
215 }
216 usb_mark_last_busy(acm->dev);
217
Oliver Neukum11ea8592008-06-20 11:25:57 +0200218 rc = acm_start_wb(acm, wb);
Oliver Neukum884b6002005-04-21 21:28:02 +0200219 spin_unlock_irqrestore(&acm->write_lock, flags);
220
Oliver Neukum884b6002005-04-21 21:28:02 +0200221 return rc;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200222
Oliver Neukum884b6002005-04-21 21:28:02 +0200223}
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100224/*
225 * attributes exported through sysfs
226 */
227static ssize_t show_caps
228(struct device *dev, struct device_attribute *attr, char *buf)
229{
230 struct usb_interface *intf = to_usb_interface(dev);
231 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum884b6002005-04-21 21:28:02 +0200232
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100233 return sprintf(buf, "%d", acm->ctrl_caps);
234}
235static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
236
237static ssize_t show_country_codes
238(struct device *dev, struct device_attribute *attr, char *buf)
239{
240 struct usb_interface *intf = to_usb_interface(dev);
241 struct acm *acm = usb_get_intfdata(intf);
242
243 memcpy(buf, acm->country_codes, acm->country_code_size);
244 return acm->country_code_size;
245}
246
247static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
248
249static ssize_t show_country_rel_date
250(struct device *dev, struct device_attribute *attr, char *buf)
251{
252 struct usb_interface *intf = to_usb_interface(dev);
253 struct acm *acm = usb_get_intfdata(intf);
254
255 return sprintf(buf, "%d", acm->country_rel_date);
256}
257
258static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
Oliver Neukum884b6002005-04-21 21:28:02 +0200259/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 * Interrupt handlers for various ACM device responses
261 */
262
263/* control interface reports status changes with "interrupt" transfers */
David Howells7d12e782006-10-05 14:55:46 +0100264static void acm_ctrl_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
266 struct acm *acm = urb->context;
267 struct usb_cdc_notification *dr = urb->transfer_buffer;
268 unsigned char *data;
269 int newctrl;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700270 int retval;
271 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700273 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 case 0:
275 /* success */
276 break;
277 case -ECONNRESET:
278 case -ENOENT:
279 case -ESHUTDOWN:
280 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800281 dbg("%s - urb shutting down with status: %d", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 return;
283 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800284 dbg("%s - nonzero urb status received: %d", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 goto exit;
286 }
287
288 if (!ACM_READY(acm))
289 goto exit;
290
291 data = (unsigned char *)(dr + 1);
292 switch (dr->bNotificationType) {
293
294 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
295
296 dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
297 break;
298
299 case USB_CDC_NOTIFY_SERIAL_STATE:
300
Harvey Harrisona5abdea2008-04-29 01:03:40 -0700301 newctrl = get_unaligned_le16(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303 if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
304 dbg("calling hangup");
305 tty_hangup(acm->tty);
306 }
307
308 acm->ctrlin = newctrl;
309
310 dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
311 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
312 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
313 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
314 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
315
316 break;
317
318 default:
319 dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
320 dr->bNotificationType, dr->wIndex,
321 dr->wLength, data[0], data[1]);
322 break;
323 }
324exit:
Oliver Neukum11ea8592008-06-20 11:25:57 +0200325 usb_mark_last_busy(acm->dev);
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700326 retval = usb_submit_urb (urb, GFP_ATOMIC);
327 if (retval)
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700328 dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with "
329 "result %d", __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330}
331
332/* data interface returns incoming bytes, or we got unthrottled */
David Howells7d12e782006-10-05 14:55:46 +0100333static void acm_read_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
David Kubicek61a87ad2005-11-01 18:51:34 +0100335 struct acm_rb *buf;
336 struct acm_ru *rcv = urb->context;
337 struct acm *acm = rcv->instance;
Oliver Neukum86478942006-05-13 22:50:47 +0200338 int status = urb->status;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700339
340 dbg("Entering acm_read_bulk with status %d", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Oliver Neukum11ea8592008-06-20 11:25:57 +0200342 if (!ACM_READY(acm)) {
343 dev_dbg(&acm->data->dev, "Aborting, acm not ready");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200345 }
346 usb_mark_last_busy(acm->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
Oliver Neukum86478942006-05-13 22:50:47 +0200348 if (status)
Joe Perches898eb712007-10-18 03:06:30 -0700349 dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
David Kubicek61a87ad2005-11-01 18:51:34 +0100351 buf = rcv->buffer;
352 buf->size = urb->actual_length;
353
Oliver Neukum86478942006-05-13 22:50:47 +0200354 if (likely(status == 0)) {
355 spin_lock(&acm->read_lock);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200356 acm->processing++;
Oliver Neukum86478942006-05-13 22:50:47 +0200357 list_add_tail(&rcv->list, &acm->spare_read_urbs);
358 list_add_tail(&buf->list, &acm->filled_read_bufs);
359 spin_unlock(&acm->read_lock);
360 } else {
361 /* we drop the buffer due to an error */
362 spin_lock(&acm->read_lock);
363 list_add_tail(&rcv->list, &acm->spare_read_urbs);
364 list_add(&buf->list, &acm->spare_read_bufs);
365 spin_unlock(&acm->read_lock);
366 /* nevertheless the tasklet must be kicked unconditionally
367 so the queue cannot dry up */
368 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200369 if (likely(!acm->susp_count))
370 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371}
372
373static void acm_rx_tasklet(unsigned long _acm)
374{
375 struct acm *acm = (void *)_acm;
David Kubicek61a87ad2005-11-01 18:51:34 +0100376 struct acm_rb *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 struct tty_struct *tty = acm->tty;
David Kubicek61a87ad2005-11-01 18:51:34 +0100378 struct acm_ru *rcv;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200379 unsigned long flags;
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100380 unsigned char throttled;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200381
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 dbg("Entering acm_rx_tasklet");
383
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100384 if (!ACM_READY(acm))
Oliver Neukum11ea8592008-06-20 11:25:57 +0200385 {
386 dbg("acm_rx_tasklet: ACM not ready");
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100387 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200388 }
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100389
Oliver Neukum834dbca2007-03-06 10:47:04 +0100390 spin_lock_irqsave(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100391 throttled = acm->throttle;
Oliver Neukum834dbca2007-03-06 10:47:04 +0100392 spin_unlock_irqrestore(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100393 if (throttled)
Oliver Neukum11ea8592008-06-20 11:25:57 +0200394 {
395 dbg("acm_rx_tasklet: throttled");
David Kubicek61a87ad2005-11-01 18:51:34 +0100396 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200397 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100398
399next_buffer:
Jarek Poplawski762f0072006-10-06 07:23:11 +0200400 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100401 if (list_empty(&acm->filled_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200402 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100403 goto urbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100405 buf = list_entry(acm->filled_read_bufs.next,
406 struct acm_rb, list);
407 list_del(&buf->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200408 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100409
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200410 dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100411
Alan Cox33f0f882006-01-09 20:54:13 -0800412 tty_buffer_request_room(tty, buf->size);
Oliver Neukum834dbca2007-03-06 10:47:04 +0100413 spin_lock_irqsave(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100414 throttled = acm->throttle;
Oliver Neukum834dbca2007-03-06 10:47:04 +0100415 spin_unlock_irqrestore(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100416 if (!throttled)
Alan Cox33f0f882006-01-09 20:54:13 -0800417 tty_insert_flip_string(tty, buf->base, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100418 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100420 if (throttled) {
421 dbg("Throttling noticed");
Jarek Poplawski762f0072006-10-06 07:23:11 +0200422 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100423 list_add(&buf->list, &acm->filled_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200424 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 return;
426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
Jarek Poplawski762f0072006-10-06 07:23:11 +0200428 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100429 list_add(&buf->list, &acm->spare_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200430 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100431 goto next_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
David Kubicek61a87ad2005-11-01 18:51:34 +0100433urbs:
434 while (!list_empty(&acm->spare_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200435 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100436 if (list_empty(&acm->spare_read_urbs)) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200437 acm->processing = 0;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200438 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100439 return;
440 }
441 rcv = list_entry(acm->spare_read_urbs.next,
442 struct acm_ru, list);
443 list_del(&rcv->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200444 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100445
446 buf = list_entry(acm->spare_read_bufs.next,
447 struct acm_rb, list);
448 list_del(&buf->list);
449
450 rcv->buffer = buf;
451
452 usb_fill_bulk_urb(rcv->urb, acm->dev,
453 acm->rx_endpoint,
454 buf->base,
455 acm->readsize,
456 acm_read_bulk, rcv);
457 rcv->urb->transfer_dma = buf->dma;
458 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
459
David Kubicek61a87ad2005-11-01 18:51:34 +0100460 /* This shouldn't kill the driver as unsuccessful URBs are returned to the
461 free-urbs-pool and resubmited ASAP */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200462 spin_lock_irqsave(&acm->read_lock, flags);
463 if (acm->susp_count || usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100464 list_add(&buf->list, &acm->spare_read_bufs);
David Kubicek61a87ad2005-11-01 18:51:34 +0100465 list_add(&rcv->list, &acm->spare_read_urbs);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200466 acm->processing = 0;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200467 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100468 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200469 } else {
470 spin_unlock_irqrestore(&acm->read_lock, flags);
471 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 +0100472 }
473 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200474 spin_lock_irqsave(&acm->read_lock, flags);
475 acm->processing = 0;
476 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477}
478
479/* data interface wrote those outgoing bytes */
David Howells7d12e782006-10-05 14:55:46 +0100480static void acm_write_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
Ming Leicdc97792008-02-24 18:41:47 +0800482 struct acm_wb *wb = urb->context;
David Brownelle5fbab52008-08-06 18:46:10 -0700483 struct acm *acm = wb->instance;
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800484 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200485
David Brownelle5fbab52008-08-06 18:46:10 -0700486 if (verbose || urb->status
487 || (urb->actual_length != urb->transfer_buffer_length))
488 dev_dbg(&acm->data->dev, "tx %d/%d bytes -- > %d\n",
489 urb->actual_length,
490 urb->transfer_buffer_length,
491 urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800493 spin_lock_irqsave(&acm->write_lock, flags);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100494 acm_write_done(acm, wb);
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800495 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200496 if (ACM_READY(acm))
497 schedule_work(&acm->work);
David Brownelle5fbab52008-08-06 18:46:10 -0700498 else
499 wake_up_interruptible(&acm->drain_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500}
501
David Howellsc4028952006-11-22 14:57:56 +0000502static void acm_softint(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
David Howellsc4028952006-11-22 14:57:56 +0000504 struct acm *acm = container_of(work, struct acm, work);
David Brownelle5fbab52008-08-06 18:46:10 -0700505
506 dev_vdbg(&acm->data->dev, "tx work\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 if (!ACM_READY(acm))
508 return;
509 tty_wakeup(acm->tty);
510}
511
Oliver Neukum11ea8592008-06-20 11:25:57 +0200512static void acm_waker(struct work_struct *waker)
513{
514 struct acm *acm = container_of(waker, struct acm, waker);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200515 int rv;
516
517 rv = usb_autopm_get_interface(acm->control);
518 if (rv < 0) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700519 dev_err(&acm->dev->dev, "Autopm failure in %s\n", __func__);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200520 return;
521 }
522 if (acm->delayed_wb) {
523 acm_start_wb(acm, acm->delayed_wb);
524 acm->delayed_wb = NULL;
525 }
Oliver Neukum11ea8592008-06-20 11:25:57 +0200526 usb_autopm_put_interface(acm->control);
527}
528
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529/*
530 * TTY handlers
531 */
532
533static int acm_tty_open(struct tty_struct *tty, struct file *filp)
534{
535 struct acm *acm;
536 int rv = -EINVAL;
David Kubicek61a87ad2005-11-01 18:51:34 +0100537 int i;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200538 dbg("Entering acm_tty_open.");
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100539
540 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
542 acm = acm_table[tty->index];
543 if (!acm || !acm->dev)
544 goto err_out;
545 else
546 rv = 0;
547
David Engraf28d1dfa2008-03-20 10:53:52 +0100548 set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 tty->driver_data = acm;
550 acm->tty = tty;
551
Oliver Neukum94409cc2008-02-11 15:22:29 +0100552 if (usb_autopm_get_interface(acm->control) < 0)
553 goto early_bail;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200554 else
555 acm->control->needs_remote_wakeup = 1;
Oliver Neukum1365baf72007-10-12 17:24:28 +0200556
557 mutex_lock(&acm->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 if (acm->used++) {
Oliver Neukum1365baf72007-10-12 17:24:28 +0200559 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 goto done;
561 }
562
Oliver Neukum1365baf72007-10-12 17:24:28 +0200563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 acm->ctrlurb->dev = acm->dev;
565 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
566 dbg("usb_submit_urb(ctrl irq) failed");
567 goto bail_out;
568 }
569
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100570 if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
571 (acm->ctrl_caps & USB_CDC_CAP_LINE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 goto full_bailout;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200573 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
David Kubicek61a87ad2005-11-01 18:51:34 +0100575 INIT_LIST_HEAD(&acm->spare_read_urbs);
576 INIT_LIST_HEAD(&acm->spare_read_bufs);
577 INIT_LIST_HEAD(&acm->filled_read_bufs);
Oliver Neukum86478942006-05-13 22:50:47 +0200578 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100579 list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
580 }
Oliver Neukum86478942006-05-13 22:50:47 +0200581 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100582 list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
583 }
584
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100585 acm->throttle = 0;
586
David Kubicek61a87ad2005-11-01 18:51:34 +0100587 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589done:
Oliver Neukum1365baf72007-10-12 17:24:28 +0200590 mutex_unlock(&acm->mutex);
Alexey Dobriyan74573ee2008-08-20 16:56:04 -0700591err_out:
Oliver Neukum94409cc2008-02-11 15:22:29 +0100592 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 return rv;
594
595full_bailout:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 usb_kill_urb(acm->ctrlurb);
597bail_out:
Oliver Neukum1365baf72007-10-12 17:24:28 +0200598 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 acm->used--;
Oliver Neukum1365baf72007-10-12 17:24:28 +0200600 mutex_unlock(&acm->mutex);
Oliver Neukum94409cc2008-02-11 15:22:29 +0100601early_bail:
602 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 return -EIO;
604}
605
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700606static void acm_tty_unregister(struct acm *acm)
607{
Oliver Neukum86478942006-05-13 22:50:47 +0200608 int i,nr;
David Kubicek61a87ad2005-11-01 18:51:34 +0100609
Oliver Neukum86478942006-05-13 22:50:47 +0200610 nr = acm->rx_buflimit;
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700611 tty_unregister_device(acm_tty_driver, acm->minor);
612 usb_put_intf(acm->control);
613 acm_table[acm->minor] = NULL;
614 usb_free_urb(acm->ctrlurb);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100615 for (i = 0; i < ACM_NW; i++)
616 usb_free_urb(acm->wb[i].urb);
Oliver Neukum86478942006-05-13 22:50:47 +0200617 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100618 usb_free_urb(acm->ru[i].urb);
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100619 kfree(acm->country_codes);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700620 kfree(acm);
621}
622
David Brownelle5fbab52008-08-06 18:46:10 -0700623static int acm_tty_chars_in_buffer(struct tty_struct *tty);
624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625static void acm_tty_close(struct tty_struct *tty, struct file *filp)
626{
627 struct acm *acm = tty->driver_data;
Oliver Neukum86478942006-05-13 22:50:47 +0200628 int i,nr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 if (!acm || !acm->used)
631 return;
632
Oliver Neukum86478942006-05-13 22:50:47 +0200633 nr = acm->rx_buflimit;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100634 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 if (!--acm->used) {
636 if (acm->dev) {
Oliver Neukum11ea8592008-06-20 11:25:57 +0200637 usb_autopm_get_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 acm_set_control(acm, acm->ctrlout = 0);
David Brownelle5fbab52008-08-06 18:46:10 -0700639
640 /* try letting the last writes drain naturally */
641 wait_event_interruptible_timeout(acm->drain_wait,
642 (ACM_NW == acm_wb_is_avail(acm))
643 || !acm->dev,
644 ACM_CLOSE_TIMEOUT * HZ);
645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 usb_kill_urb(acm->ctrlurb);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100647 for (i = 0; i < ACM_NW; i++)
648 usb_kill_urb(acm->wb[i].urb);
Oliver Neukum86478942006-05-13 22:50:47 +0200649 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100650 usb_kill_urb(acm->ru[i].urb);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200651 acm->control->needs_remote_wakeup = 0;
Oliver Neukum1365baf72007-10-12 17:24:28 +0200652 usb_autopm_put_interface(acm->control);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700653 } else
654 acm_tty_unregister(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100656 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657}
658
659static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
660{
661 struct acm *acm = tty->driver_data;
662 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200663 unsigned long flags;
664 int wbn;
665 struct acm_wb *wb;
666
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200667 dbg("Entering acm_tty_write to write %d bytes,", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
669 if (!ACM_READY(acm))
670 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 if (!count)
672 return 0;
673
Oliver Neukum884b6002005-04-21 21:28:02 +0200674 spin_lock_irqsave(&acm->write_lock, flags);
675 if ((wbn = acm_wb_alloc(acm)) < 0) {
676 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200677 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200679 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Oliver Neukum884b6002005-04-21 21:28:02 +0200681 count = (count > acm->writesize) ? acm->writesize : count;
682 dbg("Get %d bytes...", count);
683 memcpy(wb->buf, buf, count);
684 wb->len = count;
685 spin_unlock_irqrestore(&acm->write_lock, flags);
686
David Engrafe4cf3aa2008-03-20 10:01:34 +0100687 if ((stat = acm_write_start(acm, wbn)) < 0)
Oliver Neukum884b6002005-04-21 21:28:02 +0200688 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 return count;
690}
691
692static int acm_tty_write_room(struct tty_struct *tty)
693{
694 struct acm *acm = tty->driver_data;
695 if (!ACM_READY(acm))
696 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200697 /*
698 * Do not let the line discipline to know that we have a reserve,
699 * or it might get too enthusiastic.
700 */
David Brownell934da462008-08-06 18:44:12 -0700701 return acm_wb_is_avail(acm) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702}
703
704static int acm_tty_chars_in_buffer(struct tty_struct *tty)
705{
706 struct acm *acm = tty->driver_data;
707 if (!ACM_READY(acm))
708 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200709 /*
710 * This is inaccurate (overcounts), but it works.
711 */
Oliver Neukum86478942006-05-13 22:50:47 +0200712 return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713}
714
715static void acm_tty_throttle(struct tty_struct *tty)
716{
717 struct acm *acm = tty->driver_data;
718 if (!ACM_READY(acm))
719 return;
720 spin_lock_bh(&acm->throttle_lock);
721 acm->throttle = 1;
722 spin_unlock_bh(&acm->throttle_lock);
723}
724
725static void acm_tty_unthrottle(struct tty_struct *tty)
726{
727 struct acm *acm = tty->driver_data;
728 if (!ACM_READY(acm))
729 return;
730 spin_lock_bh(&acm->throttle_lock);
731 acm->throttle = 0;
732 spin_unlock_bh(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100733 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734}
735
Alan Cox9e989662008-07-22 11:18:03 +0100736static int acm_tty_break_ctl(struct tty_struct *tty, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
738 struct acm *acm = tty->driver_data;
Alan Cox9e989662008-07-22 11:18:03 +0100739 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 if (!ACM_READY(acm))
Alan Cox9e989662008-07-22 11:18:03 +0100741 return -EINVAL;
742 retval = acm_send_break(acm, state ? 0xffff : 0);
743 if (retval < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 dbg("send break failed");
Alan Cox9e989662008-07-22 11:18:03 +0100745 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746}
747
748static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file)
749{
750 struct acm *acm = tty->driver_data;
751
752 if (!ACM_READY(acm))
753 return -EINVAL;
754
755 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
756 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
757 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
758 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
759 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
760 TIOCM_CTS;
761}
762
763static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
764 unsigned int set, unsigned int clear)
765{
766 struct acm *acm = tty->driver_data;
767 unsigned int newctrl;
768
769 if (!ACM_READY(acm))
770 return -EINVAL;
771
772 newctrl = acm->ctrlout;
773 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
774 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
775
776 newctrl = (newctrl & ~clear) | set;
777
778 if (acm->ctrlout == newctrl)
779 return 0;
780 return acm_set_control(acm, acm->ctrlout = newctrl);
781}
782
783static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
784{
785 struct acm *acm = tty->driver_data;
786
787 if (!ACM_READY(acm))
788 return -EINVAL;
789
790 return -ENOIOCTLCMD;
791}
792
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100793static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 0, 50, 75, 110, 134, 150, 200, 300, 600,
795 1200, 1800, 2400, 4800, 9600, 19200, 38400,
796 57600, 115200, 230400, 460800, 500000, 576000,
797 921600, 1000000, 1152000, 1500000, 2000000,
798 2500000, 3000000, 3500000, 4000000
799};
800
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100801static const __u8 acm_tty_size[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 5, 6, 7, 8
803};
804
Alan Cox606d0992006-12-08 02:38:45 -0800805static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806{
807 struct acm *acm = tty->driver_data;
Alan Cox606d0992006-12-08 02:38:45 -0800808 struct ktermios *termios = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 struct usb_cdc_line_coding newline;
810 int newctrl = acm->ctrlout;
811
812 if (!ACM_READY(acm))
813 return;
814
815 newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
816 (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
817 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
818 newline.bParityType = termios->c_cflag & PARENB ?
819 (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
820 newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
821
822 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
823
824 if (!newline.dwDTERate) {
825 newline.dwDTERate = acm->line.dwDTERate;
826 newctrl &= ~ACM_CTRL_DTR;
827 } else newctrl |= ACM_CTRL_DTR;
828
829 if (newctrl != acm->ctrlout)
830 acm_set_control(acm, acm->ctrlout = newctrl);
831
832 if (memcmp(&acm->line, &newline, sizeof newline)) {
833 memcpy(&acm->line, &newline, sizeof newline);
834 dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
835 newline.bCharFormat, newline.bParityType,
836 newline.bDataBits);
837 acm_set_line(acm, &acm->line);
838 }
839}
840
841/*
842 * USB probe and disconnect routines.
843 */
844
Oliver Neukum830f4022008-06-25 14:17:16 +0200845/* Little helpers: write/read buffers free */
Oliver Neukum884b6002005-04-21 21:28:02 +0200846static void acm_write_buffers_free(struct acm *acm)
847{
848 int i;
849 struct acm_wb *wb;
Oliver Neukuma496c642008-10-21 10:39:04 +0200850 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
Oliver Neukum884b6002005-04-21 21:28:02 +0200851
Oliver Neukum86478942006-05-13 22:50:47 +0200852 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukuma496c642008-10-21 10:39:04 +0200853 usb_buffer_free(usb_dev, acm->writesize, wb->buf, wb->dmah);
Oliver Neukum884b6002005-04-21 21:28:02 +0200854 }
855}
856
Oliver Neukum830f4022008-06-25 14:17:16 +0200857static void acm_read_buffers_free(struct acm *acm)
858{
859 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
860 int i, n = acm->rx_buflimit;
861
862 for (i = 0; i < n; i++)
863 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
864}
865
Oliver Neukum884b6002005-04-21 21:28:02 +0200866/* Little helper: write buffers allocate */
867static int acm_write_buffers_alloc(struct acm *acm)
868{
869 int i;
870 struct acm_wb *wb;
871
Oliver Neukum86478942006-05-13 22:50:47 +0200872 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200873 wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
874 &wb->dmah);
875 if (!wb->buf) {
876 while (i != 0) {
877 --i;
878 --wb;
879 usb_buffer_free(acm->dev, acm->writesize,
880 wb->buf, wb->dmah);
881 }
882 return -ENOMEM;
883 }
884 }
885 return 0;
886}
887
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888static int acm_probe (struct usb_interface *intf,
889 const struct usb_device_id *id)
890{
891 struct usb_cdc_union_desc *union_header = NULL;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100892 struct usb_cdc_country_functional_desc *cfd = NULL;
David Brownellc6dbf552008-04-13 14:00:44 -0700893 unsigned char *buffer = intf->altsetting->extra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 int buflen = intf->altsetting->extralen;
895 struct usb_interface *control_interface;
896 struct usb_interface *data_interface;
897 struct usb_endpoint_descriptor *epctrl;
898 struct usb_endpoint_descriptor *epread;
899 struct usb_endpoint_descriptor *epwrite;
900 struct usb_device *usb_dev = interface_to_usbdev(intf);
901 struct acm *acm;
902 int minor;
903 int ctrlsize,readsize;
904 u8 *buf;
905 u8 ac_management_function = 0;
906 u8 call_management_function = 0;
907 int call_interface_num = -1;
908 int data_interface_num;
909 unsigned long quirks;
Oliver Neukum86478942006-05-13 22:50:47 +0200910 int num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +0100911 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
Oliver Neukum86478942006-05-13 22:50:47 +0200913 /* normal quirks */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 quirks = (unsigned long)id->driver_info;
Oliver Neukum86478942006-05-13 22:50:47 +0200915 num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
916
917 /* handle quirks deadly to normal probing*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 if (quirks == NO_UNION_NORMAL) {
919 data_interface = usb_ifnum_to_if(usb_dev, 1);
920 control_interface = usb_ifnum_to_if(usb_dev, 0);
921 goto skip_normal_probe;
922 }
923
924 /* normal probing*/
925 if (!buffer) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700926 dev_err(&intf->dev, "Weird descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 return -EINVAL;
928 }
929
930 if (!buflen) {
931 if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
Joe Perches898eb712007-10-18 03:06:30 -0700932 dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 buflen = intf->cur_altsetting->endpoint->extralen;
934 buffer = intf->cur_altsetting->endpoint->extra;
935 } else {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700936 dev_err(&intf->dev,
937 "Zero length descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 return -EINVAL;
939 }
940 }
941
942 while (buflen > 0) {
943 if (buffer [1] != USB_DT_CS_INTERFACE) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700944 dev_err(&intf->dev, "skipping garbage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 goto next_desc;
946 }
947
948 switch (buffer [2]) {
949 case USB_CDC_UNION_TYPE: /* we've found it */
950 if (union_header) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700951 dev_err(&intf->dev, "More than one "
952 "union descriptor, "
953 "skipping ...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 goto next_desc;
955 }
956 union_header = (struct usb_cdc_union_desc *)
957 buffer;
958 break;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100959 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
960 cfd = (struct usb_cdc_country_functional_desc *)buffer;
961 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 case USB_CDC_HEADER_TYPE: /* maybe check version */
963 break; /* for now we ignore it */
964 case USB_CDC_ACM_TYPE:
965 ac_management_function = buffer[3];
966 break;
967 case USB_CDC_CALL_MANAGEMENT_TYPE:
968 call_management_function = buffer[3];
969 call_interface_num = buffer[4];
970 if ((call_management_function & 3) != 3)
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -0700971 dev_err(&intf->dev, "This device "
972 "cannot do calls on its own. "
973 "It is no modem.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 default:
David Brownellc6dbf552008-04-13 14:00:44 -0700976 /* there are LOTS more CDC descriptors that
977 * could legitimately be found here.
978 */
979 dev_dbg(&intf->dev, "Ignoring descriptor: "
980 "type %02x, length %d\n",
981 buffer[2], buffer[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 break;
983 }
984next_desc:
985 buflen -= buffer[0];
986 buffer += buffer[0];
987 }
988
989 if (!union_header) {
990 if (call_interface_num > 0) {
Joe Perches898eb712007-10-18 03:06:30 -0700991 dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
993 control_interface = intf;
994 } else {
Joe Perches898eb712007-10-18 03:06:30 -0700995 dev_dbg(&intf->dev,"No union descriptor, giving up\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 return -ENODEV;
997 }
998 } else {
999 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
1000 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
1001 if (!control_interface || !data_interface) {
Joe Perches898eb712007-10-18 03:06:30 -07001002 dev_dbg(&intf->dev,"no interfaces\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 return -ENODEV;
1004 }
1005 }
1006
1007 if (data_interface_num != call_interface_num)
Joe Perchesdc0d5c12007-12-17 11:40:18 -08001008 dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
1010skip_normal_probe:
1011
1012 /*workaround for switched interfaces */
1013 if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
1014 if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
1015 struct usb_interface *t;
Joe Perches898eb712007-10-18 03:06:30 -07001016 dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
1018 t = control_interface;
1019 control_interface = data_interface;
1020 data_interface = t;
1021 } else {
1022 return -EINVAL;
1023 }
1024 }
Alan Stern74da5d62007-08-02 13:29:10 -04001025
1026 /* Accept probe requests only for the control interface */
1027 if (intf != control_interface)
1028 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
1030 if (usb_interface_claimed(data_interface)) { /* valid in this context */
Joe Perches898eb712007-10-18 03:06:30 -07001031 dev_dbg(&intf->dev,"The data interface isn't available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 return -EBUSY;
1033 }
1034
1035
1036 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
1037 return -EINVAL;
1038
1039 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
1040 epread = &data_interface->cur_altsetting->endpoint[0].desc;
1041 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
1042
1043
1044 /* workaround for switched endpoints */
Luiz Fernando N. Capitulino45aea702006-10-26 13:02:48 -03001045 if (!usb_endpoint_dir_in(epread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 /* descriptors are swapped */
1047 struct usb_endpoint_descriptor *t;
Joe Perches898eb712007-10-18 03:06:30 -07001048 dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
1050 t = epread;
1051 epread = epwrite;
1052 epwrite = t;
1053 }
1054 dbg("interfaces are valid");
1055 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
1056
1057 if (minor == ACM_TTY_MINORS) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001058 dev_err(&intf->dev, "no more free acm devices\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 return -ENODEV;
1060 }
1061
Oliver Neukum46f116e2005-10-24 22:42:35 +02001062 if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
Joe Perches898eb712007-10-18 03:06:30 -07001063 dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 goto alloc_fail;
1065 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
Oliver Neukum86478942006-05-13 22:50:47 +02001068 readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001069 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 acm->control = control_interface;
1071 acm->data = data_interface;
1072 acm->minor = minor;
1073 acm->dev = usb_dev;
1074 acm->ctrl_caps = ac_management_function;
1075 acm->ctrlsize = ctrlsize;
1076 acm->readsize = readsize;
Oliver Neukum86478942006-05-13 22:50:47 +02001077 acm->rx_buflimit = num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +01001078 acm->urb_task.func = acm_rx_tasklet;
1079 acm->urb_task.data = (unsigned long) acm;
David Howellsc4028952006-11-22 14:57:56 +00001080 INIT_WORK(&acm->work, acm_softint);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001081 INIT_WORK(&acm->waker, acm_waker);
David Brownelle5fbab52008-08-06 18:46:10 -07001082 init_waitqueue_head(&acm->drain_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 spin_lock_init(&acm->throttle_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +02001084 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +01001085 spin_lock_init(&acm->read_lock);
Oliver Neukum1365baf72007-10-12 17:24:28 +02001086 mutex_init(&acm->mutex);
David Kubicek61a87ad2005-11-01 18:51:34 +01001087 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Alan Cox739e0282009-06-11 12:27:50 +01001088 tty_port_init(&acm->port);
1089 acm->port.ops = &acm_port_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
1091 buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
1092 if (!buf) {
Joe Perches898eb712007-10-18 03:06:30 -07001093 dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 goto alloc_fail2;
1095 }
1096 acm->ctrl_buffer = buf;
1097
Oliver Neukum884b6002005-04-21 21:28:02 +02001098 if (acm_write_buffers_alloc(acm) < 0) {
Joe Perches898eb712007-10-18 03:06:30 -07001099 dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 goto alloc_fail4;
1101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
1103 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
1104 if (!acm->ctrlurb) {
Joe Perches898eb712007-10-18 03:06:30 -07001105 dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 goto alloc_fail5;
1107 }
Oliver Neukum86478942006-05-13 22:50:47 +02001108 for (i = 0; i < num_rx_buf; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +01001109 struct acm_ru *rcv = &(acm->ru[i]);
1110
1111 if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
Joe Perches898eb712007-10-18 03:06:30 -07001112 dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n");
David Kubicek61a87ad2005-11-01 18:51:34 +01001113 goto alloc_fail7;
1114 }
1115
1116 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1117 rcv->instance = acm;
1118 }
Oliver Neukum86478942006-05-13 22:50:47 +02001119 for (i = 0; i < num_rx_buf; i++) {
David Brownell672c4e12008-08-06 18:41:12 -07001120 struct acm_rb *rb = &(acm->rb[i]);
David Kubicek61a87ad2005-11-01 18:51:34 +01001121
David Brownell672c4e12008-08-06 18:41:12 -07001122 rb->base = usb_buffer_alloc(acm->dev, readsize,
1123 GFP_KERNEL, &rb->dma);
1124 if (!rb->base) {
Joe Perches898eb712007-10-18 03:06:30 -07001125 dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
David Kubicek61a87ad2005-11-01 18:51:34 +01001126 goto alloc_fail7;
1127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 }
David Engrafe4cf3aa2008-03-20 10:01:34 +01001129 for(i = 0; i < ACM_NW; i++)
1130 {
1131 struct acm_wb *snd = &(acm->wb[i]);
1132
1133 if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) {
1134 dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)");
1135 goto alloc_fail7;
1136 }
1137
1138 usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
1139 NULL, acm->writesize, acm_write_bulk, snd);
1140 snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1141 snd->instance = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 }
1143
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001144 usb_set_intfdata (intf, acm);
1145
1146 i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
1147 if (i < 0)
1148 goto alloc_fail8;
1149
1150 if (cfd) { /* export the country data */
1151 acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
1152 if (!acm->country_codes)
1153 goto skip_countries;
1154 acm->country_code_size = cfd->bLength - 4;
1155 memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4);
1156 acm->country_rel_date = cfd->iCountryCodeRelDate;
1157
1158 i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
1159 if (i < 0) {
1160 kfree(acm->country_codes);
1161 goto skip_countries;
1162 }
1163
1164 i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
1165 if (i < 0) {
1166 kfree(acm->country_codes);
1167 goto skip_countries;
1168 }
1169 }
1170
1171skip_countries:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
1173 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
1174 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1175 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
1176
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
1178
1179 acm_set_control(acm, acm->ctrlout);
1180
1181 acm->line.dwDTERate = cpu_to_le32(9600);
1182 acm->line.bDataBits = 8;
1183 acm_set_line(acm, &acm->line);
1184
1185 usb_driver_claim_interface(&acm_driver, data_interface, acm);
David Brownell672c4e12008-08-06 18:41:12 -07001186 usb_set_intfdata(data_interface, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001188 usb_get_intf(control_interface);
1189 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190
1191 acm_table[minor] = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001193 return 0;
1194alloc_fail8:
David Engrafe4cf3aa2008-03-20 10:01:34 +01001195 for (i = 0; i < ACM_NW; i++)
1196 usb_free_urb(acm->wb[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197alloc_fail7:
Oliver Neukum830f4022008-06-25 14:17:16 +02001198 acm_read_buffers_free(acm);
Oliver Neukum86478942006-05-13 22:50:47 +02001199 for (i = 0; i < num_rx_buf; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001200 usb_free_urb(acm->ru[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 usb_free_urb(acm->ctrlurb);
1202alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001203 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204alloc_fail4:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
1206alloc_fail2:
1207 kfree(acm);
1208alloc_fail:
1209 return -ENOMEM;
1210}
1211
Oliver Neukum1365baf72007-10-12 17:24:28 +02001212static void stop_data_traffic(struct acm *acm)
1213{
1214 int i;
Oliver Neukum11ea8592008-06-20 11:25:57 +02001215 dbg("Entering stop_data_traffic");
Oliver Neukum1365baf72007-10-12 17:24:28 +02001216
1217 tasklet_disable(&acm->urb_task);
1218
1219 usb_kill_urb(acm->ctrlurb);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001220 for(i = 0; i < ACM_NW; i++)
1221 usb_kill_urb(acm->wb[i].urb);
Oliver Neukum1365baf72007-10-12 17:24:28 +02001222 for (i = 0; i < acm->rx_buflimit; i++)
1223 usb_kill_urb(acm->ru[i].urb);
1224
Oliver Neukum1365baf72007-10-12 17:24:28 +02001225 tasklet_enable(&acm->urb_task);
1226
1227 cancel_work_sync(&acm->work);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001228 cancel_work_sync(&acm->waker);
Oliver Neukum1365baf72007-10-12 17:24:28 +02001229}
1230
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231static void acm_disconnect(struct usb_interface *intf)
1232{
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001233 struct acm *acm = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 struct usb_device *usb_dev = interface_to_usbdev(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
David Brownell672c4e12008-08-06 18:41:12 -07001236 /* sibling interface is already cleaning up */
1237 if (!acm)
Oliver Neukum86067eea2006-01-08 12:39:13 +01001238 return;
David Brownell672c4e12008-08-06 18:41:12 -07001239
1240 mutex_lock(&open_mutex);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001241 if (acm->country_codes){
Alan Stern74da5d62007-08-02 13:29:10 -04001242 device_remove_file(&acm->control->dev,
1243 &dev_attr_wCountryCodes);
1244 device_remove_file(&acm->control->dev,
1245 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001246 }
Alan Stern74da5d62007-08-02 13:29:10 -04001247 device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 acm->dev = NULL;
Oliver Neukum86067eea2006-01-08 12:39:13 +01001249 usb_set_intfdata(acm->control, NULL);
1250 usb_set_intfdata(acm->data, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
Oliver Neukum1365baf72007-10-12 17:24:28 +02001252 stop_data_traffic(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
Oliver Neukum884b6002005-04-21 21:28:02 +02001254 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Oliver Neukum830f4022008-06-25 14:17:16 +02001256 acm_read_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
Oliver Neukum830f4022008-06-25 14:17:16 +02001258 usb_driver_release_interface(&acm_driver, intf == acm->control ?
1259 acm->data : acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
1261 if (!acm->used) {
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001262 acm_tty_unregister(acm);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001263 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 return;
1265 }
1266
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001267 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
1269 if (acm->tty)
1270 tty_hangup(acm->tty);
1271}
1272
Oliver Neukum35758582008-07-01 19:10:08 +02001273#ifdef CONFIG_PM
Oliver Neukum1365baf72007-10-12 17:24:28 +02001274static int acm_suspend(struct usb_interface *intf, pm_message_t message)
1275{
1276 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001277 int cnt;
Oliver Neukum1365baf72007-10-12 17:24:28 +02001278
Alan Stern65bfd292008-11-25 16:39:18 -05001279 if (message.event & PM_EVENT_AUTO) {
Oliver Neukum11ea8592008-06-20 11:25:57 +02001280 int b;
1281
1282 spin_lock_irq(&acm->read_lock);
1283 spin_lock(&acm->write_lock);
1284 b = acm->processing + acm->transmitting;
1285 spin_unlock(&acm->write_lock);
1286 spin_unlock_irq(&acm->read_lock);
1287 if (b)
1288 return -EBUSY;
1289 }
1290
1291 spin_lock_irq(&acm->read_lock);
1292 spin_lock(&acm->write_lock);
1293 cnt = acm->susp_count++;
1294 spin_unlock(&acm->write_lock);
1295 spin_unlock_irq(&acm->read_lock);
1296
1297 if (cnt)
Oliver Neukum1365baf72007-10-12 17:24:28 +02001298 return 0;
1299 /*
1300 we treat opened interfaces differently,
1301 we must guard against open
1302 */
1303 mutex_lock(&acm->mutex);
1304
1305 if (acm->used)
1306 stop_data_traffic(acm);
1307
1308 mutex_unlock(&acm->mutex);
1309 return 0;
1310}
1311
1312static int acm_resume(struct usb_interface *intf)
1313{
1314 struct acm *acm = usb_get_intfdata(intf);
1315 int rv = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +02001316 int cnt;
Oliver Neukum1365baf72007-10-12 17:24:28 +02001317
Oliver Neukum11ea8592008-06-20 11:25:57 +02001318 spin_lock_irq(&acm->read_lock);
1319 acm->susp_count -= 1;
1320 cnt = acm->susp_count;
1321 spin_unlock_irq(&acm->read_lock);
1322
1323 if (cnt)
Oliver Neukum1365baf72007-10-12 17:24:28 +02001324 return 0;
1325
1326 mutex_lock(&acm->mutex);
1327 if (acm->used) {
1328 rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
1329 if (rv < 0)
Oliver Neukum11ea8592008-06-20 11:25:57 +02001330 goto err_out;
Oliver Neukum1365baf72007-10-12 17:24:28 +02001331
1332 tasklet_schedule(&acm->urb_task);
1333 }
1334
1335err_out:
1336 mutex_unlock(&acm->mutex);
1337 return rv;
1338}
Oliver Neukum35758582008-07-01 19:10:08 +02001339
1340#endif /* CONFIG_PM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341/*
1342 * USB driver structure.
1343 */
1344
1345static struct usb_device_id acm_ids[] = {
1346 /* quirky and broken devices */
1347 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1348 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1349 },
Andrey Arapovb0e2a702007-07-04 17:11:42 +02001350 { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
1351 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1352 },
Andrew Lunn0f9c7b42008-12-23 17:31:23 +01001353 { USB_DEVICE(0x0e8d, 0x3329), /* MediaTek Inc GPS */
1354 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1355 },
Masahito Omote8753e652005-07-29 12:17:25 -07001356 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1357 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1358 },
Chris Malley91a9c922006-10-03 10:08:28 +01001359 { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
1360 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1361 },
Alan Cox7abcf202009-04-06 17:35:01 +01001362 { USB_DEVICE(0x0ace, 0x1602), /* ZyDAS 56K USB MODEM */
1363 .driver_info = SINGLE_RX_URB,
1364 },
Oliver Neukum86478942006-05-13 22:50:47 +02001365 { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
1366 .driver_info = SINGLE_RX_URB, /* firmware bug */
1367 },
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001368 { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
1369 .driver_info = SINGLE_RX_URB, /* firmware bug */
1370 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001371 { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
1372 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1373 },
Iain McFarlane6149ed52008-05-04 00:13:49 +01001374 { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */
1375 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1376 },
Eric Sandeenc8fd2c32008-08-14 08:25:40 -05001377 { USB_DEVICE(0x0572, 0x1321), /* Conexant USB MODEM CX93010 */
1378 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1379 },
Alan Coxc89c60e2009-01-11 19:53:10 +00001380 { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */
1381 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1382 },
Xiao Kaijiancab98a02009-05-08 00:48:23 +08001383 { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */
1384 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1385 },
Dmitriy Taychenachev155df652009-02-25 12:36:51 +08001386 { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
1387 },
Adam Richterc332b4e2009-02-18 16:17:15 -08001388 { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */
1389 .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on
1390 data interface instead of
1391 communications interface.
1392 Maybe we should define a new
1393 quirk for this. */
1394 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 /* control interfaces with various AT-command sets */
1397 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1398 USB_CDC_ACM_PROTO_AT_V25TER) },
1399 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1400 USB_CDC_ACM_PROTO_AT_PCCA101) },
1401 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1402 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1403 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1404 USB_CDC_ACM_PROTO_AT_GSM) },
1405 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1406 USB_CDC_ACM_PROTO_AT_3G ) },
1407 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1408 USB_CDC_ACM_PROTO_AT_CDMA) },
1409
1410 /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */
1411 { }
1412};
1413
1414MODULE_DEVICE_TABLE (usb, acm_ids);
1415
1416static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 .name = "cdc_acm",
1418 .probe = acm_probe,
1419 .disconnect = acm_disconnect,
Oliver Neukum35758582008-07-01 19:10:08 +02001420#ifdef CONFIG_PM
Oliver Neukum1365baf72007-10-12 17:24:28 +02001421 .suspend = acm_suspend,
1422 .resume = acm_resume,
Oliver Neukum35758582008-07-01 19:10:08 +02001423#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 .id_table = acm_ids,
Oliver Neukum35758582008-07-01 19:10:08 +02001425#ifdef CONFIG_PM
Oliver Neukum1365baf72007-10-12 17:24:28 +02001426 .supports_autosuspend = 1,
Oliver Neukum35758582008-07-01 19:10:08 +02001427#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428};
1429
1430/*
1431 * TTY driver structures.
1432 */
1433
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001434static const struct tty_operations acm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 .open = acm_tty_open,
1436 .close = acm_tty_close,
1437 .write = acm_tty_write,
1438 .write_room = acm_tty_write_room,
1439 .ioctl = acm_tty_ioctl,
1440 .throttle = acm_tty_throttle,
1441 .unthrottle = acm_tty_unthrottle,
1442 .chars_in_buffer = acm_tty_chars_in_buffer,
1443 .break_ctl = acm_tty_break_ctl,
1444 .set_termios = acm_tty_set_termios,
1445 .tiocmget = acm_tty_tiocmget,
1446 .tiocmset = acm_tty_tiocmset,
1447};
1448
1449/*
1450 * Init / exit.
1451 */
1452
1453static int __init acm_init(void)
1454{
1455 int retval;
1456 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1457 if (!acm_tty_driver)
1458 return -ENOMEM;
1459 acm_tty_driver->owner = THIS_MODULE,
1460 acm_tty_driver->driver_name = "acm",
1461 acm_tty_driver->name = "ttyACM",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 acm_tty_driver->major = ACM_TTY_MAJOR,
1463 acm_tty_driver->minor_start = 0,
1464 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1465 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001466 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 acm_tty_driver->init_termios = tty_std_termios;
1468 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1469 tty_set_operations(acm_tty_driver, &acm_ops);
1470
1471 retval = tty_register_driver(acm_tty_driver);
1472 if (retval) {
1473 put_tty_driver(acm_tty_driver);
1474 return retval;
1475 }
1476
1477 retval = usb_register(&acm_driver);
1478 if (retval) {
1479 tty_unregister_driver(acm_tty_driver);
1480 put_tty_driver(acm_tty_driver);
1481 return retval;
1482 }
1483
Greg Kroah-Hartman5909f6e2008-08-18 13:21:04 -07001484 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
1485 DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
1487 return 0;
1488}
1489
1490static void __exit acm_exit(void)
1491{
1492 usb_deregister(&acm_driver);
1493 tty_unregister_driver(acm_tty_driver);
1494 put_tty_driver(acm_tty_driver);
1495}
1496
1497module_init(acm_init);
1498module_exit(acm_exit);
1499
1500MODULE_AUTHOR( DRIVER_AUTHOR );
1501MODULE_DESCRIPTION( DRIVER_DESC );
1502MODULE_LICENSE("GPL");
Scott James Remnante766aeb2009-04-06 17:33:18 +01001503MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR);