blob: e7570ecac598c51f6e4993231308b9ba009343d7 [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>
Johan Hovold088c64f2011-03-25 11:06:02 +010010 * Copyright (c) 2011 Johan Hovold <jhovold@gmail.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 *
12 * USB Abstract Control Model driver for USB modems and ISDN adapters
13 *
14 * Sponsored by SuSE
15 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 */
30
31#undef DEBUG
David Brownelle5fbab52008-08-06 18:46:10 -070032#undef VERBOSE_DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
34#include <linux/kernel.h>
35#include <linux/errno.h>
36#include <linux/init.h>
37#include <linux/slab.h>
38#include <linux/tty.h>
Oliver Neukum7af25b42009-09-08 23:51:28 +020039#include <linux/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/tty_driver.h>
41#include <linux/tty_flip.h>
Oliver Neukum18c75722012-02-17 17:21:24 -050042#include <linux/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/module.h>
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010044#include <linux/mutex.h>
Alan Cox10077d42009-06-11 12:36:09 +010045#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <linux/usb.h>
David Brownella8c28f22006-06-13 09:57:47 -070047#include <linux/usb/cdc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <asm/byteorder.h>
49#include <asm/unaligned.h>
David Kubicek61a87ad2005-11-01 18:51:34 +010050#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#include "cdc-acm.h"
53
David Brownelle5fbab52008-08-06 18:46:10 -070054
Johan Hovold088c64f2011-03-25 11:06:02 +010055#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek, Johan Hovold"
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
57
58static struct usb_driver acm_driver;
59static struct tty_driver *acm_tty_driver;
60static struct acm *acm_table[ACM_TTY_MINORS];
61
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -080062static DEFINE_MUTEX(acm_table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -080064/*
65 * acm_table accessors
66 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -080068/*
69 * Look up an ACM structure by index. If found and not disconnected, increment
70 * its refcount and return it with its mutex held.
71 */
72static struct acm *acm_get_by_index(unsigned index)
73{
74 struct acm *acm;
75
76 mutex_lock(&acm_table_lock);
77 acm = acm_table[index];
78 if (acm) {
79 mutex_lock(&acm->mutex);
80 if (acm->disconnected) {
81 mutex_unlock(&acm->mutex);
82 acm = NULL;
83 } else {
84 tty_port_get(&acm->port);
85 mutex_unlock(&acm->mutex);
86 }
87 }
88 mutex_unlock(&acm_table_lock);
89 return acm;
90}
91
92/*
93 * Try to find an available minor number and if found, associate it with 'acm'.
94 */
95static int acm_alloc_minor(struct acm *acm)
96{
97 int minor;
98
99 mutex_lock(&acm_table_lock);
100 for (minor = 0; minor < ACM_TTY_MINORS; minor++) {
101 if (!acm_table[minor]) {
102 acm_table[minor] = acm;
103 break;
104 }
105 }
106 mutex_unlock(&acm_table_lock);
107
108 return minor;
109}
110
111/* Release the minor number associated with 'acm'. */
112static void acm_release_minor(struct acm *acm)
113{
114 mutex_lock(&acm_table_lock);
115 acm_table[acm->minor] = NULL;
116 mutex_unlock(&acm_table_lock);
117}
Alan Cox739e0282009-06-11 12:27:50 +0100118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119/*
120 * Functions for ACM control messages.
121 */
122
Alan Cox6e47e062009-06-11 12:37:06 +0100123static int acm_ctrl_msg(struct acm *acm, int request, int value,
124 void *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125{
126 int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
127 request, USB_RT_ACM, value,
128 acm->control->altsetting[0].desc.bInterfaceNumber,
129 buf, len, 5000);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100130 dev_dbg(&acm->control->dev,
131 "%s - rq 0x%02x, val %#x, len %#x, result %d\n",
132 __func__, request, value, len, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 return retval < 0 ? retval : 0;
134}
135
136/* devices aren't required to support these requests.
137 * the cdc acm descriptor tells whether they do...
138 */
139#define acm_set_control(acm, control) \
140 acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
141#define acm_set_line(acm, line) \
142 acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
143#define acm_send_break(acm, ms) \
144 acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
145
146/*
Oliver Neukum884b6002005-04-21 21:28:02 +0200147 * Write buffer management.
148 * All of these assume proper locks taken by the caller.
149 */
150
151static int acm_wb_alloc(struct acm *acm)
152{
153 int i, wbn;
154 struct acm_wb *wb;
155
David Engrafe4cf3aa2008-03-20 10:01:34 +0100156 wbn = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200157 i = 0;
158 for (;;) {
159 wb = &acm->wb[wbn];
160 if (!wb->use) {
161 wb->use = 1;
162 return wbn;
163 }
Oliver Neukum86478942006-05-13 22:50:47 +0200164 wbn = (wbn + 1) % ACM_NW;
165 if (++i >= ACM_NW)
Oliver Neukum884b6002005-04-21 21:28:02 +0200166 return -1;
167 }
168}
169
Oliver Neukum884b6002005-04-21 21:28:02 +0200170static int acm_wb_is_avail(struct acm *acm)
171{
172 int i, n;
David Brownelle5fbab52008-08-06 18:46:10 -0700173 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200174
Oliver Neukum86478942006-05-13 22:50:47 +0200175 n = ACM_NW;
David Brownelle5fbab52008-08-06 18:46:10 -0700176 spin_lock_irqsave(&acm->write_lock, flags);
Alan Cox6e47e062009-06-11 12:37:06 +0100177 for (i = 0; i < ACM_NW; i++)
Oliver Neukum86478942006-05-13 22:50:47 +0200178 n -= acm->wb[i].use;
David Brownelle5fbab52008-08-06 18:46:10 -0700179 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200180 return n;
181}
182
Oliver Neukum884b6002005-04-21 21:28:02 +0200183/*
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800184 * Finish write. Caller must hold acm->write_lock
Oliver Neukum884b6002005-04-21 21:28:02 +0200185 */
David Engrafe4cf3aa2008-03-20 10:01:34 +0100186static void acm_write_done(struct acm *acm, struct acm_wb *wb)
Oliver Neukum884b6002005-04-21 21:28:02 +0200187{
David Engrafe4cf3aa2008-03-20 10:01:34 +0100188 wb->use = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200189 acm->transmitting--;
Oliver Neukum97d35f92009-12-16 17:05:57 +0100190 usb_autopm_put_interface_async(acm->control);
Oliver Neukum884b6002005-04-21 21:28:02 +0200191}
192
193/*
194 * Poke write.
Oliver Neukum11ea8592008-06-20 11:25:57 +0200195 *
196 * the caller is responsible for locking
Oliver Neukum884b6002005-04-21 21:28:02 +0200197 */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200198
199static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
200{
201 int rc;
202
203 acm->transmitting++;
204
205 wb->urb->transfer_buffer = wb->buf;
206 wb->urb->transfer_dma = wb->dmah;
207 wb->urb->transfer_buffer_length = wb->len;
208 wb->urb->dev = acm->dev;
209
Alan Cox6e47e062009-06-11 12:37:06 +0100210 rc = usb_submit_urb(wb->urb, GFP_ATOMIC);
211 if (rc < 0) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100212 dev_err(&acm->data->dev,
213 "%s - usb_submit_urb(write bulk) failed: %d\n",
214 __func__, rc);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200215 acm_write_done(acm, wb);
216 }
217 return rc;
218}
219
David Engrafe4cf3aa2008-03-20 10:01:34 +0100220static int acm_write_start(struct acm *acm, int wbn)
Oliver Neukum884b6002005-04-21 21:28:02 +0200221{
222 unsigned long flags;
David Brownell934da462008-08-06 18:44:12 -0700223 struct acm_wb *wb = &acm->wb[wbn];
Oliver Neukum884b6002005-04-21 21:28:02 +0200224 int rc;
225
226 spin_lock_irqsave(&acm->write_lock, flags);
227 if (!acm->dev) {
David Brownell934da462008-08-06 18:44:12 -0700228 wb->use = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200229 spin_unlock_irqrestore(&acm->write_lock, flags);
230 return -ENODEV;
231 }
232
Johan Hovold5e9e75f2011-03-22 11:12:17 +0100233 dev_vdbg(&acm->data->dev, "%s - susp_count %d\n", __func__,
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100234 acm->susp_count);
Oliver Neukum97d35f92009-12-16 17:05:57 +0100235 usb_autopm_get_interface_async(acm->control);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200236 if (acm->susp_count) {
Johan Hovold21ffba32014-05-26 19:23:38 +0200237 usb_anchor_urb(wb->urb, &acm->delayed);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200238 spin_unlock_irqrestore(&acm->write_lock, flags);
Johan Hovold21ffba32014-05-26 19:23:38 +0200239 return 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200240 }
241 usb_mark_last_busy(acm->dev);
242
Oliver Neukum11ea8592008-06-20 11:25:57 +0200243 rc = acm_start_wb(acm, wb);
Oliver Neukum884b6002005-04-21 21:28:02 +0200244 spin_unlock_irqrestore(&acm->write_lock, flags);
245
Oliver Neukum884b6002005-04-21 21:28:02 +0200246 return rc;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200247
Oliver Neukum884b6002005-04-21 21:28:02 +0200248}
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100249/*
250 * attributes exported through sysfs
251 */
252static ssize_t show_caps
253(struct device *dev, struct device_attribute *attr, char *buf)
254{
255 struct usb_interface *intf = to_usb_interface(dev);
256 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum884b6002005-04-21 21:28:02 +0200257
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100258 return sprintf(buf, "%d", acm->ctrl_caps);
259}
260static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
261
262static ssize_t show_country_codes
263(struct device *dev, struct device_attribute *attr, char *buf)
264{
265 struct usb_interface *intf = to_usb_interface(dev);
266 struct acm *acm = usb_get_intfdata(intf);
267
268 memcpy(buf, acm->country_codes, acm->country_code_size);
269 return acm->country_code_size;
270}
271
272static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
273
274static ssize_t show_country_rel_date
275(struct device *dev, struct device_attribute *attr, char *buf)
276{
277 struct usb_interface *intf = to_usb_interface(dev);
278 struct acm *acm = usb_get_intfdata(intf);
279
280 return sprintf(buf, "%d", acm->country_rel_date);
281}
282
283static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
Oliver Neukum884b6002005-04-21 21:28:02 +0200284/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 * Interrupt handlers for various ACM device responses
286 */
287
288/* control interface reports status changes with "interrupt" transfers */
David Howells7d12e782006-10-05 14:55:46 +0100289static void acm_ctrl_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
291 struct acm *acm = urb->context;
292 struct usb_cdc_notification *dr = urb->transfer_buffer;
Alan Cox10077d42009-06-11 12:36:09 +0100293 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 unsigned char *data;
295 int newctrl;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700296 int retval;
297 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700299 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 case 0:
301 /* success */
302 break;
303 case -ECONNRESET:
304 case -ENOENT:
305 case -ESHUTDOWN:
306 /* this urb is terminated, clean up */
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100307 dev_dbg(&acm->control->dev,
308 "%s - urb shutting down with status: %d\n",
309 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 return;
311 default:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100312 dev_dbg(&acm->control->dev,
313 "%s - nonzero urb status received: %d\n",
314 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 goto exit;
316 }
317
Johan Hovold7e7797e2011-03-22 11:12:11 +0100318 usb_mark_last_busy(acm->dev);
319
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 data = (unsigned char *)(dr + 1);
321 switch (dr->bNotificationType) {
Alan Cox6e47e062009-06-11 12:37:06 +0100322 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100323 dev_dbg(&acm->control->dev, "%s - network connection: %d\n",
324 __func__, dr->wValue);
Alan Cox6e47e062009-06-11 12:37:06 +0100325 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Alan Cox6e47e062009-06-11 12:37:06 +0100327 case USB_CDC_NOTIFY_SERIAL_STATE:
328 tty = tty_port_tty_get(&acm->port);
329 newctrl = get_unaligned_le16(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
Alan Cox6e47e062009-06-11 12:37:06 +0100331 if (tty) {
332 if (!acm->clocal &&
333 (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100334 dev_dbg(&acm->control->dev,
335 "%s - calling hangup\n", __func__);
Alan Cox6e47e062009-06-11 12:37:06 +0100336 tty_hangup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 }
Alan Cox6e47e062009-06-11 12:37:06 +0100338 tty_kref_put(tty);
339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Alan Cox6e47e062009-06-11 12:37:06 +0100341 acm->ctrlin = newctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100343 dev_dbg(&acm->control->dev,
344 "%s - input control lines: dcd%c dsr%c break%c "
345 "ring%c framing%c parity%c overrun%c\n",
346 __func__,
Alan Cox6e47e062009-06-11 12:37:06 +0100347 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',
348 acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
349 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-',
350 acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
351 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',
352 acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
353 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 break;
355
Alan Cox6e47e062009-06-11 12:37:06 +0100356 default:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100357 dev_dbg(&acm->control->dev,
358 "%s - unknown notification %d received: index %d "
359 "len %d data0 %d data1 %d\n",
360 __func__,
Alan Cox6e47e062009-06-11 12:37:06 +0100361 dr->bNotificationType, dr->wIndex,
362 dr->wLength, data[0], data[1]);
363 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 }
365exit:
Alan Cox6e47e062009-06-11 12:37:06 +0100366 retval = usb_submit_urb(urb, GFP_ATOMIC);
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700367 if (retval)
Johan Hovold1d9846e2011-03-22 11:12:14 +0100368 dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n",
369 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370}
371
Johan Hovold088c64f2011-03-25 11:06:02 +0100372static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
Johan Hovold088c64f2011-03-25 11:06:02 +0100374 int res;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700375
Johan Hovold088c64f2011-03-25 11:06:02 +0100376 if (!test_and_clear_bit(index, &acm->read_urbs_free))
377 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Johan Hovold088c64f2011-03-25 11:06:02 +0100379 dev_vdbg(&acm->data->dev, "%s - urb %d\n", __func__, index);
380
381 res = usb_submit_urb(acm->read_urbs[index], mem_flags);
382 if (res) {
383 if (res != -EPERM) {
384 dev_err(&acm->data->dev,
385 "%s - usb_submit_urb failed: %d\n",
386 __func__, res);
387 }
388 set_bit(index, &acm->read_urbs_free);
389 return res;
390 }
391
392 return 0;
393}
394
395static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags)
396{
397 int res;
398 int i;
399
400 for (i = 0; i < acm->rx_buflimit; ++i) {
401 res = acm_submit_read_urb(acm, i, mem_flags);
402 if (res)
403 return res;
404 }
405
406 return 0;
407}
408
409static void acm_process_read_urb(struct acm *acm, struct urb *urb)
410{
411 struct tty_struct *tty;
412
413 if (!urb->actual_length)
414 return;
415
416 tty = tty_port_tty_get(&acm->port);
417 if (!tty)
418 return;
419
420 tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length);
421 tty_flip_buffer_push(tty);
422
423 tty_kref_put(tty);
424}
425
426static void acm_read_bulk_callback(struct urb *urb)
427{
428 struct acm_rb *rb = urb->context;
429 struct acm *acm = rb->instance;
430 unsigned long flags;
431
432 dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__,
433 rb->index, urb->actual_length);
434 set_bit(rb->index, &acm->read_urbs_free);
435
436 if (!acm->dev) {
437 dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200439 }
440 usb_mark_last_busy(acm->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
Johan Hovold088c64f2011-03-25 11:06:02 +0100442 if (urb->status) {
Johan Hovold1d9846e2011-03-22 11:12:14 +0100443 dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n",
Johan Hovold088c64f2011-03-25 11:06:02 +0100444 __func__, urb->status);
445 return;
446 }
447 acm_process_read_urb(acm, urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Johan Hovold088c64f2011-03-25 11:06:02 +0100449 /* throttle device if requested by tty */
450 spin_lock_irqsave(&acm->read_lock, flags);
451 acm->throttled = acm->throttle_req;
452 if (!acm->throttled && !acm->susp_count) {
453 spin_unlock_irqrestore(&acm->read_lock, flags);
454 acm_submit_read_urb(acm, rb->index, GFP_ATOMIC);
Oliver Neukum86478942006-05-13 22:50:47 +0200455 } else {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200456 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458}
459
460/* data interface wrote those outgoing bytes */
David Howells7d12e782006-10-05 14:55:46 +0100461static void acm_write_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
Ming Leicdc97792008-02-24 18:41:47 +0800463 struct acm_wb *wb = urb->context;
David Brownelle5fbab52008-08-06 18:46:10 -0700464 struct acm *acm = wb->instance;
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800465 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200466
Johan Hovold4fa46262011-03-22 11:12:16 +0100467 if (urb->status || (urb->actual_length != urb->transfer_buffer_length))
468 dev_vdbg(&acm->data->dev, "%s - len %d/%d, status %d\n",
Johan Hovold1d9846e2011-03-22 11:12:14 +0100469 __func__,
David Brownelle5fbab52008-08-06 18:46:10 -0700470 urb->actual_length,
471 urb->transfer_buffer_length,
472 urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800474 spin_lock_irqsave(&acm->write_lock, flags);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100475 acm_write_done(acm, wb);
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800476 spin_unlock_irqrestore(&acm->write_lock, flags);
Havard Skinnemoen99823f42011-12-09 16:51:54 -0800477 schedule_work(&acm->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478}
479
David Howellsc4028952006-11-22 14:57:56 +0000480static void acm_softint(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
David Howellsc4028952006-11-22 14:57:56 +0000482 struct acm *acm = container_of(work, struct acm, work);
Alan Cox10077d42009-06-11 12:36:09 +0100483 struct tty_struct *tty;
David Brownelle5fbab52008-08-06 18:46:10 -0700484
Johan Hovold1d9846e2011-03-22 11:12:14 +0100485 dev_vdbg(&acm->data->dev, "%s\n", __func__);
486
Alan Cox10077d42009-06-11 12:36:09 +0100487 tty = tty_port_tty_get(&acm->port);
Johan Hovold15e5bee2011-03-22 11:12:10 +0100488 if (!tty)
489 return;
Alan Cox10077d42009-06-11 12:36:09 +0100490 tty_wakeup(tty);
491 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492}
493
494/*
495 * TTY handlers
496 */
497
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800498static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
500 struct acm *acm;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800501 int retval;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100502
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800503 dev_dbg(tty->dev, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800505 acm = acm_get_by_index(tty->index);
506 if (!acm)
507 return -ENODEV;
508
Jiri Slabyf8a8c102012-03-05 14:51:48 +0100509 retval = tty_standard_install(driver, tty);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800510 if (retval)
511 goto error_init_termios;
512
513 tty->driver_data = acm;
514
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800515 return 0;
516
517error_init_termios:
518 tty_port_put(&acm->port);
519 return retval;
520}
521
522static int acm_tty_open(struct tty_struct *tty, struct file *filp)
523{
524 struct acm *acm = tty->driver_data;
525
526 dev_dbg(tty->dev, "%s\n", __func__);
527
528 return tty_port_open(&acm->port, tty, filp);
529}
530
531static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)
532{
533 struct acm *acm = container_of(port, struct acm, port);
534 int retval = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100536 dev_dbg(&acm->control->dev, "%s\n", __func__);
537
Oliver Neukum1365baf2007-10-12 17:24:28 +0200538 mutex_lock(&acm->mutex);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800539 if (acm->disconnected)
540 goto disconnected;
541
542 retval = usb_autopm_get_interface(acm->control);
543 if (retval)
544 goto error_get_interface;
545
546 /*
547 * FIXME: Why do we need this? Allocating 64K of physically contiguous
548 * memory is really nasty...
549 */
550 set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
551 acm->control->needs_remote_wakeup = 1;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200552
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 acm->ctrlurb->dev = acm->dev;
554 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100555 dev_err(&acm->control->dev,
556 "%s - usb_submit_urb(ctrl irq) failed\n", __func__);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800557 goto error_submit_urb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 }
559
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800560 acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS;
561 if (acm_set_control(acm, acm->ctrlout) < 0 &&
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100562 (acm->ctrl_caps & USB_CDC_CAP_LINE))
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800563 goto error_set_control;
Alan Cox10077d42009-06-11 12:36:09 +0100564
Oliver Neukum11ea8592008-06-20 11:25:57 +0200565 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Otto Meta9cc2d462012-06-06 18:46:21 +0200567 /*
568 * Unthrottle device in case the TTY was closed while throttled.
569 */
570 spin_lock_irq(&acm->read_lock);
571 acm->throttled = 0;
572 acm->throttle_req = 0;
573 spin_unlock_irq(&acm->read_lock);
574
Johan Hovold088c64f2011-03-25 11:06:02 +0100575 if (acm_submit_read_urbs(acm, GFP_KERNEL))
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800576 goto error_submit_read_urbs;
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100577
Oliver Neukum1365baf2007-10-12 17:24:28 +0200578 mutex_unlock(&acm->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800580 return 0;
581
582error_submit_read_urbs:
583 acm->ctrlout = 0;
584 acm_set_control(acm, acm->ctrlout);
585error_set_control:
586 usb_kill_urb(acm->ctrlurb);
587error_submit_urb:
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100588 usb_autopm_put_interface(acm->control);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800589error_get_interface:
590disconnected:
591 mutex_unlock(&acm->mutex);
592 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593}
594
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800595static void acm_port_destruct(struct tty_port *port)
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700596{
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800597 struct acm *acm = container_of(port, struct acm, port);
598
599 dev_dbg(&acm->control->dev, "%s\n", __func__);
David Kubicek61a87ad2005-11-01 18:51:34 +0100600
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800601 acm_release_minor(acm);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700602 usb_put_intf(acm->control);
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100603 kfree(acm->country_codes);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700604 kfree(acm);
605}
606
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800607static void acm_port_shutdown(struct tty_port *port)
Alan Cox10077d42009-06-11 12:36:09 +0100608{
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800609 struct acm *acm = container_of(port, struct acm, port);
Johan Hovold21ffba32014-05-26 19:23:38 +0200610 struct urb *urb;
611 struct acm_wb *wb;
Johan Hovolddab54c92011-03-22 11:12:21 +0100612 int i;
613
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800614 dev_dbg(&acm->control->dev, "%s\n", __func__);
615
616 mutex_lock(&acm->mutex);
617 if (!acm->disconnected) {
Alan Cox10077d42009-06-11 12:36:09 +0100618 usb_autopm_get_interface(acm->control);
619 acm_set_control(acm, acm->ctrlout = 0);
Johan Hovold21ffba32014-05-26 19:23:38 +0200620
621 for (;;) {
622 urb = usb_get_from_anchor(&acm->delayed);
623 if (!urb)
624 break;
625 wb = urb->context;
626 wb->use = 0;
627 usb_autopm_put_interface_async(acm->control);
628 }
629
Alan Cox10077d42009-06-11 12:36:09 +0100630 usb_kill_urb(acm->ctrlurb);
631 for (i = 0; i < ACM_NW; i++)
632 usb_kill_urb(acm->wb[i].urb);
Johan Hovolddab54c92011-03-22 11:12:21 +0100633 for (i = 0; i < acm->rx_buflimit; i++)
Johan Hovold088c64f2011-03-25 11:06:02 +0100634 usb_kill_urb(acm->read_urbs[i]);
Alan Cox10077d42009-06-11 12:36:09 +0100635 acm->control->needs_remote_wakeup = 0;
636 usb_autopm_put_interface(acm->control);
637 }
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800638 mutex_unlock(&acm->mutex);
639}
640
641static void acm_tty_cleanup(struct tty_struct *tty)
642{
643 struct acm *acm = tty->driver_data;
644 dev_dbg(&acm->control->dev, "%s\n", __func__);
645 tty_port_put(&acm->port);
Alan Cox10077d42009-06-11 12:36:09 +0100646}
647
648static void acm_tty_hangup(struct tty_struct *tty)
649{
650 struct acm *acm = tty->driver_data;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800651 dev_dbg(&acm->control->dev, "%s\n", __func__);
Alan Cox10077d42009-06-11 12:36:09 +0100652 tty_port_hangup(&acm->port);
Alan Cox10077d42009-06-11 12:36:09 +0100653}
654
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655static void acm_tty_close(struct tty_struct *tty, struct file *filp)
656{
657 struct acm *acm = tty->driver_data;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800658 dev_dbg(&acm->control->dev, "%s\n", __func__);
659 tty_port_close(&acm->port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660}
661
Alan Cox6e47e062009-06-11 12:37:06 +0100662static int acm_tty_write(struct tty_struct *tty,
663 const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
665 struct acm *acm = tty->driver_data;
666 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200667 unsigned long flags;
668 int wbn;
669 struct acm_wb *wb;
670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 if (!count)
672 return 0;
673
Johan Hovold5e9e75f2011-03-22 11:12:17 +0100674 dev_vdbg(&acm->data->dev, "%s - count %d\n", __func__, count);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100675
Oliver Neukum884b6002005-04-21 21:28:02 +0200676 spin_lock_irqsave(&acm->write_lock, flags);
Alan Cox6e47e062009-06-11 12:37:06 +0100677 wbn = acm_wb_alloc(acm);
678 if (wbn < 0) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200679 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200680 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200682 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Oliver Neukum884b6002005-04-21 21:28:02 +0200684 count = (count > acm->writesize) ? acm->writesize : count;
Johan Hovold5e9e75f2011-03-22 11:12:17 +0100685 dev_vdbg(&acm->data->dev, "%s - write %d\n", __func__, count);
Oliver Neukum884b6002005-04-21 21:28:02 +0200686 memcpy(wb->buf, buf, count);
687 wb->len = count;
688 spin_unlock_irqrestore(&acm->write_lock, flags);
689
Alan Cox6e47e062009-06-11 12:37:06 +0100690 stat = acm_write_start(acm, wbn);
691 if (stat < 0)
Oliver Neukum884b6002005-04-21 21:28:02 +0200692 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return count;
694}
695
696static int acm_tty_write_room(struct tty_struct *tty)
697{
698 struct acm *acm = tty->driver_data;
Oliver Neukum884b6002005-04-21 21:28:02 +0200699 /*
700 * Do not let the line discipline to know that we have a reserve,
701 * or it might get too enthusiastic.
702 */
David Brownell934da462008-08-06 18:44:12 -0700703 return acm_wb_is_avail(acm) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704}
705
706static int acm_tty_chars_in_buffer(struct tty_struct *tty)
707{
708 struct acm *acm = tty->driver_data;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800709 /*
710 * if the device was unplugged then any remaining characters fell out
711 * of the connector ;)
712 */
713 if (acm->disconnected)
Alan Cox23198fd2009-07-20 16:05:27 +0100714 return 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200715 /*
716 * This is inaccurate (overcounts), but it works.
717 */
Oliver Neukum86478942006-05-13 22:50:47 +0200718 return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719}
720
721static void acm_tty_throttle(struct tty_struct *tty)
722{
723 struct acm *acm = tty->driver_data;
Johan Hovold088c64f2011-03-25 11:06:02 +0100724
Johan Hovold088c64f2011-03-25 11:06:02 +0100725 spin_lock_irq(&acm->read_lock);
726 acm->throttle_req = 1;
727 spin_unlock_irq(&acm->read_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728}
729
730static void acm_tty_unthrottle(struct tty_struct *tty)
731{
732 struct acm *acm = tty->driver_data;
Johan Hovold088c64f2011-03-25 11:06:02 +0100733 unsigned int was_throttled;
734
Johan Hovold088c64f2011-03-25 11:06:02 +0100735 spin_lock_irq(&acm->read_lock);
736 was_throttled = acm->throttled;
737 acm->throttled = 0;
738 acm->throttle_req = 0;
739 spin_unlock_irq(&acm->read_lock);
740
741 if (was_throttled)
742 acm_submit_read_urbs(acm, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743}
744
Alan Cox9e989662008-07-22 11:18:03 +0100745static int acm_tty_break_ctl(struct tty_struct *tty, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
747 struct acm *acm = tty->driver_data;
Alan Cox9e989662008-07-22 11:18:03 +0100748 int retval;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800749
Alan Cox9e989662008-07-22 11:18:03 +0100750 retval = acm_send_break(acm, state ? 0xffff : 0);
751 if (retval < 0)
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100752 dev_dbg(&acm->control->dev, "%s - send break failed\n",
753 __func__);
Alan Cox9e989662008-07-22 11:18:03 +0100754 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755}
756
Alan Cox60b33c12011-02-14 16:26:14 +0000757static int acm_tty_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758{
759 struct acm *acm = tty->driver_data;
760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
762 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
763 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
764 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
765 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
766 TIOCM_CTS;
767}
768
Alan Cox20b9d172011-02-14 16:26:50 +0000769static int acm_tty_tiocmset(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 unsigned int set, unsigned int clear)
771{
772 struct acm *acm = tty->driver_data;
773 unsigned int newctrl;
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 newctrl = acm->ctrlout;
Alan Cox6e47e062009-06-11 12:37:06 +0100776 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
777 (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
778 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
779 (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 newctrl = (newctrl & ~clear) | set;
782
783 if (acm->ctrlout == newctrl)
784 return 0;
785 return acm_set_control(acm, acm->ctrlout = newctrl);
786}
787
Oliver Neukum18c75722012-02-17 17:21:24 -0500788static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
789{
790 struct serial_struct tmp;
791
792 if (!info)
793 return -EINVAL;
794
795 memset(&tmp, 0, sizeof(tmp));
796 tmp.flags = ASYNC_LOW_LATENCY;
797 tmp.xmit_fifo_size = acm->writesize;
798 tmp.baud_base = le32_to_cpu(acm->line.dwDTERate);
Dan Williams1229a832012-11-08 12:47:41 -0600799 tmp.close_delay = acm->port.close_delay / 10;
800 tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
801 ASYNC_CLOSING_WAIT_NONE :
802 acm->port.closing_wait / 10;
Oliver Neukum18c75722012-02-17 17:21:24 -0500803
804 if (copy_to_user(info, &tmp, sizeof(tmp)))
805 return -EFAULT;
806 else
807 return 0;
808}
809
Dan Williams1229a832012-11-08 12:47:41 -0600810static int set_serial_info(struct acm *acm,
811 struct serial_struct __user *newinfo)
812{
813 struct serial_struct new_serial;
814 unsigned int closing_wait, close_delay;
815 int retval = 0;
816
817 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
818 return -EFAULT;
819
820 close_delay = new_serial.close_delay * 10;
821 closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
822 ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
823
824 mutex_lock(&acm->port.mutex);
825
826 if (!capable(CAP_SYS_ADMIN)) {
827 if ((close_delay != acm->port.close_delay) ||
828 (closing_wait != acm->port.closing_wait))
829 retval = -EPERM;
830 else
831 retval = -EOPNOTSUPP;
832 } else {
833 acm->port.close_delay = close_delay;
834 acm->port.closing_wait = closing_wait;
835 }
836
837 mutex_unlock(&acm->port.mutex);
838 return retval;
839}
840
Alan Cox6caa76b2011-02-14 16:27:22 +0000841static int acm_tty_ioctl(struct tty_struct *tty,
Alan Cox6e47e062009-06-11 12:37:06 +0100842 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843{
Oliver Neukum18c75722012-02-17 17:21:24 -0500844 struct acm *acm = tty->driver_data;
845 int rv = -ENOIOCTLCMD;
846
847 switch (cmd) {
848 case TIOCGSERIAL: /* gets serial port data */
849 rv = get_serial_info(acm, (struct serial_struct __user *) arg);
850 break;
Dan Williams1229a832012-11-08 12:47:41 -0600851 case TIOCSSERIAL:
852 rv = set_serial_info(acm, (struct serial_struct __user *) arg);
853 break;
Oliver Neukum18c75722012-02-17 17:21:24 -0500854 }
855
856 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857}
858
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100859static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 0, 50, 75, 110, 134, 150, 200, 300, 600,
861 1200, 1800, 2400, 4800, 9600, 19200, 38400,
862 57600, 115200, 230400, 460800, 500000, 576000,
863 921600, 1000000, 1152000, 1500000, 2000000,
864 2500000, 3000000, 3500000, 4000000
865};
866
Alan Cox6e47e062009-06-11 12:37:06 +0100867static void acm_tty_set_termios(struct tty_struct *tty,
868 struct ktermios *termios_old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869{
870 struct acm *acm = tty->driver_data;
Alan Cox606d0992006-12-08 02:38:45 -0800871 struct ktermios *termios = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 struct usb_cdc_line_coding newline;
873 int newctrl = acm->ctrlout;
874
Alan Cox9b80fee2009-09-19 13:13:23 -0700875 newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
877 newline.bParityType = termios->c_cflag & PARENB ?
Alan Cox6e47e062009-06-11 12:37:06 +0100878 (termios->c_cflag & PARODD ? 1 : 2) +
879 (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
Nicolas Boullisa5204462012-10-16 00:06:23 +0200880 switch (termios->c_cflag & CSIZE) {
881 case CS5:
882 newline.bDataBits = 5;
883 break;
884 case CS6:
885 newline.bDataBits = 6;
886 break;
887 case CS7:
888 newline.bDataBits = 7;
889 break;
890 case CS8:
891 default:
892 newline.bDataBits = 8;
893 break;
894 }
Alan Cox6e47e062009-06-11 12:37:06 +0100895 /* FIXME: Needs to clear unsupported bits in the termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
897
898 if (!newline.dwDTERate) {
899 newline.dwDTERate = acm->line.dwDTERate;
900 newctrl &= ~ACM_CTRL_DTR;
Alan Cox6e47e062009-06-11 12:37:06 +0100901 } else
902 newctrl |= ACM_CTRL_DTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903
904 if (newctrl != acm->ctrlout)
905 acm_set_control(acm, acm->ctrlout = newctrl);
906
907 if (memcmp(&acm->line, &newline, sizeof newline)) {
908 memcpy(&acm->line, &newline, sizeof newline);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100909 dev_dbg(&acm->control->dev, "%s - set line: %d %d %d %d\n",
910 __func__,
911 le32_to_cpu(newline.dwDTERate),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 newline.bCharFormat, newline.bParityType,
913 newline.bDataBits);
914 acm_set_line(acm, &acm->line);
915 }
916}
917
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800918static const struct tty_port_operations acm_port_ops = {
919 .shutdown = acm_port_shutdown,
920 .activate = acm_port_activate,
921 .destruct = acm_port_destruct,
922};
923
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924/*
925 * USB probe and disconnect routines.
926 */
927
Oliver Neukum830f4022008-06-25 14:17:16 +0200928/* Little helpers: write/read buffers free */
Oliver Neukum884b6002005-04-21 21:28:02 +0200929static void acm_write_buffers_free(struct acm *acm)
930{
931 int i;
932 struct acm_wb *wb;
Oliver Neukuma496c642008-10-21 10:39:04 +0200933 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
Oliver Neukum884b6002005-04-21 21:28:02 +0200934
Alan Cox6e47e062009-06-11 12:37:06 +0100935 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++)
Daniel Mack997ea582010-04-12 13:17:25 +0200936 usb_free_coherent(usb_dev, acm->writesize, wb->buf, wb->dmah);
Oliver Neukum884b6002005-04-21 21:28:02 +0200937}
938
Oliver Neukum830f4022008-06-25 14:17:16 +0200939static void acm_read_buffers_free(struct acm *acm)
940{
941 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
Johan Hovolddab54c92011-03-22 11:12:21 +0100942 int i;
Oliver Neukum830f4022008-06-25 14:17:16 +0200943
Johan Hovolddab54c92011-03-22 11:12:21 +0100944 for (i = 0; i < acm->rx_buflimit; i++)
Daniel Mack997ea582010-04-12 13:17:25 +0200945 usb_free_coherent(usb_dev, acm->readsize,
Johan Hovold088c64f2011-03-25 11:06:02 +0100946 acm->read_buffers[i].base, acm->read_buffers[i].dma);
Oliver Neukum830f4022008-06-25 14:17:16 +0200947}
948
Oliver Neukum884b6002005-04-21 21:28:02 +0200949/* Little helper: write buffers allocate */
950static int acm_write_buffers_alloc(struct acm *acm)
951{
952 int i;
953 struct acm_wb *wb;
954
Oliver Neukum86478942006-05-13 22:50:47 +0200955 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Daniel Mack997ea582010-04-12 13:17:25 +0200956 wb->buf = usb_alloc_coherent(acm->dev, acm->writesize, GFP_KERNEL,
Oliver Neukum884b6002005-04-21 21:28:02 +0200957 &wb->dmah);
958 if (!wb->buf) {
959 while (i != 0) {
960 --i;
961 --wb;
Daniel Mack997ea582010-04-12 13:17:25 +0200962 usb_free_coherent(acm->dev, acm->writesize,
Oliver Neukum884b6002005-04-21 21:28:02 +0200963 wb->buf, wb->dmah);
964 }
965 return -ENOMEM;
966 }
967 }
968 return 0;
969}
970
Alan Cox10077d42009-06-11 12:36:09 +0100971static int acm_probe(struct usb_interface *intf,
972 const struct usb_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973{
974 struct usb_cdc_union_desc *union_header = NULL;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100975 struct usb_cdc_country_functional_desc *cfd = NULL;
David Brownellc6dbf552008-04-13 14:00:44 -0700976 unsigned char *buffer = intf->altsetting->extra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 int buflen = intf->altsetting->extralen;
978 struct usb_interface *control_interface;
979 struct usb_interface *data_interface;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +0200980 struct usb_endpoint_descriptor *epctrl = NULL;
981 struct usb_endpoint_descriptor *epread = NULL;
982 struct usb_endpoint_descriptor *epwrite = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 struct usb_device *usb_dev = interface_to_usbdev(intf);
984 struct acm *acm;
985 int minor;
Alan Cox6e47e062009-06-11 12:37:06 +0100986 int ctrlsize, readsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 u8 *buf;
988 u8 ac_management_function = 0;
989 u8 call_management_function = 0;
990 int call_interface_num = -1;
Erik Slagterfd5054c2011-05-11 12:06:55 +0200991 int data_interface_num = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 unsigned long quirks;
Oliver Neukum86478942006-05-13 22:50:47 +0200993 int num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +0100994 int i;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +0200995 int combined_interfaces = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996
Oliver Neukum86478942006-05-13 22:50:47 +0200997 /* normal quirks */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 quirks = (unsigned long)id->driver_info;
Oliver Neukum86478942006-05-13 22:50:47 +0200999 num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
1000
1001 /* handle quirks deadly to normal probing*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 if (quirks == NO_UNION_NORMAL) {
1003 data_interface = usb_ifnum_to_if(usb_dev, 1);
1004 control_interface = usb_ifnum_to_if(usb_dev, 0);
1005 goto skip_normal_probe;
1006 }
Alan Cox6e47e062009-06-11 12:37:06 +01001007
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 /* normal probing*/
1009 if (!buffer) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001010 dev_err(&intf->dev, "Weird descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 return -EINVAL;
1012 }
1013
1014 if (!buflen) {
Toby Gray577045c2010-09-02 10:46:20 +01001015 if (intf->cur_altsetting->endpoint &&
1016 intf->cur_altsetting->endpoint->extralen &&
Alan Cox6e47e062009-06-11 12:37:06 +01001017 intf->cur_altsetting->endpoint->extra) {
1018 dev_dbg(&intf->dev,
1019 "Seeking extra descriptors on endpoint\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 buflen = intf->cur_altsetting->endpoint->extralen;
1021 buffer = intf->cur_altsetting->endpoint->extra;
1022 } else {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001023 dev_err(&intf->dev,
1024 "Zero length descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 return -EINVAL;
1026 }
1027 }
1028
1029 while (buflen > 0) {
Alan Cox6e47e062009-06-11 12:37:06 +01001030 if (buffer[1] != USB_DT_CS_INTERFACE) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001031 dev_err(&intf->dev, "skipping garbage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 goto next_desc;
1033 }
1034
Alan Cox6e47e062009-06-11 12:37:06 +01001035 switch (buffer[2]) {
1036 case USB_CDC_UNION_TYPE: /* we've found it */
1037 if (union_header) {
1038 dev_err(&intf->dev, "More than one "
1039 "union descriptor, skipping ...\n");
1040 goto next_desc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 }
Alan Cox6e47e062009-06-11 12:37:06 +01001042 union_header = (struct usb_cdc_union_desc *)buffer;
1043 break;
1044 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
1045 cfd = (struct usb_cdc_country_functional_desc *)buffer;
1046 break;
1047 case USB_CDC_HEADER_TYPE: /* maybe check version */
1048 break; /* for now we ignore it */
1049 case USB_CDC_ACM_TYPE:
1050 ac_management_function = buffer[3];
1051 break;
1052 case USB_CDC_CALL_MANAGEMENT_TYPE:
1053 call_management_function = buffer[3];
1054 call_interface_num = buffer[4];
Julian Calabyce126642010-01-05 23:58:20 +11001055 if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
Alan Cox6e47e062009-06-11 12:37:06 +01001056 dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
1057 break;
1058 default:
1059 /* there are LOTS more CDC descriptors that
1060 * could legitimately be found here.
1061 */
1062 dev_dbg(&intf->dev, "Ignoring descriptor: "
1063 "type %02x, length %d\n",
1064 buffer[2], buffer[0]);
1065 break;
1066 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067next_desc:
1068 buflen -= buffer[0];
1069 buffer += buffer[0];
1070 }
1071
1072 if (!union_header) {
1073 if (call_interface_num > 0) {
Alan Cox6e47e062009-06-11 12:37:06 +01001074 dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
Erik Slagterfd5054c2011-05-11 12:06:55 +02001075 /* quirks for Droids MuIn LCD */
1076 if (quirks & NO_DATA_INTERFACE)
1077 data_interface = usb_ifnum_to_if(usb_dev, 0);
1078 else
1079 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 control_interface = intf;
1081 } else {
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001082 if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
1083 dev_dbg(&intf->dev,"No union descriptor, giving up\n");
1084 return -ENODEV;
1085 } else {
1086 dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n");
1087 combined_interfaces = 1;
1088 control_interface = data_interface = intf;
1089 goto look_for_collapsed_interface;
1090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 }
1092 } else {
1093 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
1094 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
1095 if (!control_interface || !data_interface) {
Alan Cox6e47e062009-06-11 12:37:06 +01001096 dev_dbg(&intf->dev, "no interfaces\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 return -ENODEV;
1098 }
1099 }
Alan Cox6e47e062009-06-11 12:37:06 +01001100
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 if (data_interface_num != call_interface_num)
Alan Cox6e47e062009-06-11 12:37:06 +01001102 dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001104 if (control_interface == data_interface) {
1105 /* some broken devices designed for windows work this way */
1106 dev_warn(&intf->dev,"Control and data interfaces are not separated!\n");
1107 combined_interfaces = 1;
1108 /* a popular other OS doesn't use it */
1109 quirks |= NO_CAP_LINE;
1110 if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) {
1111 dev_err(&intf->dev, "This needs exactly 3 endpoints\n");
1112 return -EINVAL;
1113 }
1114look_for_collapsed_interface:
1115 for (i = 0; i < 3; i++) {
1116 struct usb_endpoint_descriptor *ep;
1117 ep = &data_interface->cur_altsetting->endpoint[i].desc;
1118
1119 if (usb_endpoint_is_int_in(ep))
1120 epctrl = ep;
1121 else if (usb_endpoint_is_bulk_out(ep))
1122 epwrite = ep;
1123 else if (usb_endpoint_is_bulk_in(ep))
1124 epread = ep;
1125 else
1126 return -EINVAL;
1127 }
1128 if (!epctrl || !epread || !epwrite)
1129 return -ENODEV;
1130 else
1131 goto made_compressed_probe;
1132 }
1133
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134skip_normal_probe:
1135
1136 /*workaround for switched interfaces */
Alan Cox6e47e062009-06-11 12:37:06 +01001137 if (data_interface->cur_altsetting->desc.bInterfaceClass
1138 != CDC_DATA_INTERFACE_TYPE) {
1139 if (control_interface->cur_altsetting->desc.bInterfaceClass
1140 == CDC_DATA_INTERFACE_TYPE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 struct usb_interface *t;
Alan Cox6e47e062009-06-11 12:37:06 +01001142 dev_dbg(&intf->dev,
1143 "Your device has switched interfaces.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 t = control_interface;
1145 control_interface = data_interface;
1146 data_interface = t;
1147 } else {
1148 return -EINVAL;
1149 }
1150 }
Alan Stern74da5d62007-08-02 13:29:10 -04001151
1152 /* Accept probe requests only for the control interface */
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001153 if (!combined_interfaces && intf != control_interface)
Alan Stern74da5d62007-08-02 13:29:10 -04001154 return -ENODEV;
Alan Cox6e47e062009-06-11 12:37:06 +01001155
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001156 if (!combined_interfaces && usb_interface_claimed(data_interface)) {
1157 /* valid in this context */
Alan Cox6e47e062009-06-11 12:37:06 +01001158 dev_dbg(&intf->dev, "The data interface isn't available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 return -EBUSY;
1160 }
1161
1162
Sven Schnellea9959bb2012-08-17 21:43:43 +02001163 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2 ||
1164 control_interface->cur_altsetting->desc.bNumEndpoints == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 return -EINVAL;
1166
1167 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
1168 epread = &data_interface->cur_altsetting->endpoint[0].desc;
1169 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
1170
1171
1172 /* workaround for switched endpoints */
Luiz Fernando N. Capitulino45aea702006-10-26 13:02:48 -03001173 if (!usb_endpoint_dir_in(epread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 /* descriptors are swapped */
1175 struct usb_endpoint_descriptor *t;
Alan Cox6e47e062009-06-11 12:37:06 +01001176 dev_dbg(&intf->dev,
1177 "The data interface has switched endpoints\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 t = epread;
1179 epread = epwrite;
1180 epwrite = t;
1181 }
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001182made_compressed_probe:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +01001183 dev_dbg(&intf->dev, "interfaces are valid\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184
Alan Cox6e47e062009-06-11 12:37:06 +01001185 acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
1186 if (acm == NULL) {
Johan Hovold255ab562011-03-22 11:12:13 +01001187 dev_err(&intf->dev, "out of memory (acm kzalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 goto alloc_fail;
1189 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001191 minor = acm_alloc_minor(acm);
1192 if (minor == ACM_TTY_MINORS) {
1193 dev_err(&intf->dev, "no more free acm devices\n");
1194 kfree(acm);
1195 return -ENODEV;
1196 }
1197
Kuninori Morimoto29cc8892011-08-23 03:12:03 -07001198 ctrlsize = usb_endpoint_maxp(epctrl);
1199 readsize = usb_endpoint_maxp(epread) *
Alan Cox6e47e062009-06-11 12:37:06 +01001200 (quirks == SINGLE_RX_URB ? 1 : 2);
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001201 acm->combined_interfaces = combined_interfaces;
Kuninori Morimoto29cc8892011-08-23 03:12:03 -07001202 acm->writesize = usb_endpoint_maxp(epwrite) * 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 acm->control = control_interface;
1204 acm->data = data_interface;
1205 acm->minor = minor;
1206 acm->dev = usb_dev;
1207 acm->ctrl_caps = ac_management_function;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001208 if (quirks & NO_CAP_LINE)
1209 acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 acm->ctrlsize = ctrlsize;
1211 acm->readsize = readsize;
Oliver Neukum86478942006-05-13 22:50:47 +02001212 acm->rx_buflimit = num_rx_buf;
David Howellsc4028952006-11-22 14:57:56 +00001213 INIT_WORK(&acm->work, acm_softint);
Oliver Neukum884b6002005-04-21 21:28:02 +02001214 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +01001215 spin_lock_init(&acm->read_lock);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001216 mutex_init(&acm->mutex);
David Kubicek61a87ad2005-11-01 18:51:34 +01001217 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Oliver Neukumcf7fdd52009-08-04 23:52:09 +02001218 acm->is_int_ep = usb_endpoint_xfer_int(epread);
1219 if (acm->is_int_ep)
1220 acm->bInterval = epread->bInterval;
Alan Cox739e0282009-06-11 12:27:50 +01001221 tty_port_init(&acm->port);
1222 acm->port.ops = &acm_port_ops;
Johan Hovold21ffba32014-05-26 19:23:38 +02001223 init_usb_anchor(&acm->delayed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
Daniel Mack997ea582010-04-12 13:17:25 +02001225 buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 if (!buf) {
Johan Hovold255ab562011-03-22 11:12:13 +01001227 dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 goto alloc_fail2;
1229 }
1230 acm->ctrl_buffer = buf;
1231
Oliver Neukum884b6002005-04-21 21:28:02 +02001232 if (acm_write_buffers_alloc(acm) < 0) {
Johan Hovold255ab562011-03-22 11:12:13 +01001233 dev_err(&intf->dev, "out of memory (write buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 goto alloc_fail4;
1235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
1237 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
1238 if (!acm->ctrlurb) {
Johan Hovold255ab562011-03-22 11:12:13 +01001239 dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 goto alloc_fail5;
1241 }
Oliver Neukum86478942006-05-13 22:50:47 +02001242 for (i = 0; i < num_rx_buf; i++) {
Johan Hovold088c64f2011-03-25 11:06:02 +01001243 struct acm_rb *rb = &(acm->read_buffers[i]);
1244 struct urb *urb;
David Kubicek61a87ad2005-11-01 18:51:34 +01001245
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001246 rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
1247 &rb->dma);
1248 if (!rb->base) {
1249 dev_err(&intf->dev, "out of memory "
1250 "(read bufs usb_alloc_coherent)\n");
1251 goto alloc_fail6;
1252 }
Johan Hovold088c64f2011-03-25 11:06:02 +01001253 rb->index = i;
1254 rb->instance = acm;
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001255
Johan Hovold088c64f2011-03-25 11:06:02 +01001256 urb = usb_alloc_urb(0, GFP_KERNEL);
1257 if (!urb) {
Johan Hovold255ab562011-03-22 11:12:13 +01001258 dev_err(&intf->dev,
Alan Cox6e47e062009-06-11 12:37:06 +01001259 "out of memory (read urbs usb_alloc_urb)\n");
Axel Linc2572b72010-05-31 08:04:47 +08001260 goto alloc_fail6;
David Kubicek61a87ad2005-11-01 18:51:34 +01001261 }
Johan Hovold088c64f2011-03-25 11:06:02 +01001262 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1263 urb->transfer_dma = rb->dma;
1264 if (acm->is_int_ep) {
1265 usb_fill_int_urb(urb, acm->dev,
1266 acm->rx_endpoint,
1267 rb->base,
1268 acm->readsize,
1269 acm_read_bulk_callback, rb,
1270 acm->bInterval);
1271 } else {
1272 usb_fill_bulk_urb(urb, acm->dev,
1273 acm->rx_endpoint,
1274 rb->base,
1275 acm->readsize,
1276 acm_read_bulk_callback, rb);
1277 }
David Kubicek61a87ad2005-11-01 18:51:34 +01001278
Johan Hovold088c64f2011-03-25 11:06:02 +01001279 acm->read_urbs[i] = urb;
1280 __set_bit(i, &acm->read_urbs_free);
David Kubicek61a87ad2005-11-01 18:51:34 +01001281 }
Alan Cox6e47e062009-06-11 12:37:06 +01001282 for (i = 0; i < ACM_NW; i++) {
David Engrafe4cf3aa2008-03-20 10:01:34 +01001283 struct acm_wb *snd = &(acm->wb[i]);
1284
Alan Cox6e47e062009-06-11 12:37:06 +01001285 snd->urb = usb_alloc_urb(0, GFP_KERNEL);
1286 if (snd->urb == NULL) {
Johan Hovold255ab562011-03-22 11:12:13 +01001287 dev_err(&intf->dev,
Johan Hovold59d7fec2011-03-22 11:12:12 +01001288 "out of memory (write urbs usb_alloc_urb)\n");
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001289 goto alloc_fail7;
David Engrafe4cf3aa2008-03-20 10:01:34 +01001290 }
1291
Arseniy Lartsev5186ffe2009-07-01 16:27:26 +04001292 if (usb_endpoint_xfer_int(epwrite))
1293 usb_fill_int_urb(snd->urb, usb_dev,
Ming Leie83863d2012-10-16 21:21:21 +08001294 usb_sndintpipe(usb_dev, epwrite->bEndpointAddress),
Arseniy Lartsev5186ffe2009-07-01 16:27:26 +04001295 NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval);
1296 else
1297 usb_fill_bulk_urb(snd->urb, usb_dev,
1298 usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
1299 NULL, acm->writesize, acm_write_bulk, snd);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001300 snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1301 snd->instance = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 }
1303
Alan Cox6e47e062009-06-11 12:37:06 +01001304 usb_set_intfdata(intf, acm);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001305
1306 i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
1307 if (i < 0)
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001308 goto alloc_fail7;
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001309
1310 if (cfd) { /* export the country data */
1311 acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
1312 if (!acm->country_codes)
1313 goto skip_countries;
1314 acm->country_code_size = cfd->bLength - 4;
Alan Cox6e47e062009-06-11 12:37:06 +01001315 memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0,
1316 cfd->bLength - 4);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001317 acm->country_rel_date = cfd->iCountryCodeRelDate;
1318
1319 i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
1320 if (i < 0) {
1321 kfree(acm->country_codes);
Julia Lawalle7c8e862011-12-23 14:02:55 +01001322 acm->country_codes = NULL;
1323 acm->country_code_size = 0;
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001324 goto skip_countries;
1325 }
1326
Alan Cox6e47e062009-06-11 12:37:06 +01001327 i = device_create_file(&intf->dev,
1328 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001329 if (i < 0) {
Axel Linc2572b72010-05-31 08:04:47 +08001330 device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001331 kfree(acm->country_codes);
Julia Lawalle7c8e862011-12-23 14:02:55 +01001332 acm->country_codes = NULL;
1333 acm->country_code_size = 0;
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001334 goto skip_countries;
1335 }
1336 }
1337
1338skip_countries:
Alan Cox6e47e062009-06-11 12:37:06 +01001339 usb_fill_int_urb(acm->ctrlurb, usb_dev,
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001340 usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
1341 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
1342 /* works around buggy devices */
1343 epctrl->bInterval ? epctrl->bInterval : 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1345 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
1346
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
1348
1349 acm_set_control(acm, acm->ctrlout);
1350
1351 acm->line.dwDTERate = cpu_to_le32(9600);
1352 acm->line.bDataBits = 8;
1353 acm_set_line(acm, &acm->line);
1354
1355 usb_driver_claim_interface(&acm_driver, data_interface, acm);
David Brownell672c4e12008-08-06 18:41:12 -07001356 usb_set_intfdata(data_interface, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001358 usb_get_intf(control_interface);
1359 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001361 return 0;
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001362alloc_fail7:
David Engrafe4cf3aa2008-03-20 10:01:34 +01001363 for (i = 0; i < ACM_NW; i++)
1364 usb_free_urb(acm->wb[i].urb);
Axel Linc2572b72010-05-31 08:04:47 +08001365alloc_fail6:
Oliver Neukum86478942006-05-13 22:50:47 +02001366 for (i = 0; i < num_rx_buf; i++)
Johan Hovold088c64f2011-03-25 11:06:02 +01001367 usb_free_urb(acm->read_urbs[i]);
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001368 acm_read_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 usb_free_urb(acm->ctrlurb);
1370alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001371 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372alloc_fail4:
Daniel Mack997ea582010-04-12 13:17:25 +02001373 usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374alloc_fail2:
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001375 acm_release_minor(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 kfree(acm);
1377alloc_fail:
1378 return -ENOMEM;
1379}
1380
Oliver Neukum1365baf2007-10-12 17:24:28 +02001381static void stop_data_traffic(struct acm *acm)
1382{
1383 int i;
Johan Hovolda5cc7ef2011-03-22 11:12:15 +01001384
1385 dev_dbg(&acm->control->dev, "%s\n", __func__);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001386
Oliver Neukum1365baf2007-10-12 17:24:28 +02001387 usb_kill_urb(acm->ctrlurb);
Alan Cox6e47e062009-06-11 12:37:06 +01001388 for (i = 0; i < ACM_NW; i++)
David Engrafe4cf3aa2008-03-20 10:01:34 +01001389 usb_kill_urb(acm->wb[i].urb);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001390 for (i = 0; i < acm->rx_buflimit; i++)
Johan Hovold088c64f2011-03-25 11:06:02 +01001391 usb_kill_urb(acm->read_urbs[i]);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001392
1393 cancel_work_sync(&acm->work);
1394}
1395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396static void acm_disconnect(struct usb_interface *intf)
1397{
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001398 struct acm *acm = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 struct usb_device *usb_dev = interface_to_usbdev(intf);
Alan Cox10077d42009-06-11 12:36:09 +01001400 struct tty_struct *tty;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001401 int i;
1402
1403 dev_dbg(&intf->dev, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
David Brownell672c4e12008-08-06 18:41:12 -07001405 /* sibling interface is already cleaning up */
1406 if (!acm)
Oliver Neukum86067eea2006-01-08 12:39:13 +01001407 return;
David Brownell672c4e12008-08-06 18:41:12 -07001408
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001409 mutex_lock(&acm->mutex);
1410 acm->disconnected = true;
Alan Cox6e47e062009-06-11 12:37:06 +01001411 if (acm->country_codes) {
Alan Stern74da5d62007-08-02 13:29:10 -04001412 device_remove_file(&acm->control->dev,
1413 &dev_attr_wCountryCodes);
1414 device_remove_file(&acm->control->dev,
1415 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001416 }
Alan Stern74da5d62007-08-02 13:29:10 -04001417 device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
Oliver Neukum86067eea2006-01-08 12:39:13 +01001418 usb_set_intfdata(acm->control, NULL);
1419 usb_set_intfdata(acm->data, NULL);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001420 mutex_unlock(&acm->mutex);
1421
1422 tty = tty_port_tty_get(&acm->port);
1423 if (tty) {
1424 tty_vhangup(tty);
1425 tty_kref_put(tty);
1426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
Oliver Neukum1365baf2007-10-12 17:24:28 +02001428 stop_data_traffic(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
Johan Hovold10a00e32013-03-19 09:21:06 +01001430 tty_unregister_device(acm_tty_driver, acm->minor);
1431
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001432 usb_free_urb(acm->ctrlurb);
1433 for (i = 0; i < ACM_NW; i++)
1434 usb_free_urb(acm->wb[i].urb);
1435 for (i = 0; i < acm->rx_buflimit; i++)
1436 usb_free_urb(acm->read_urbs[i]);
Oliver Neukum884b6002005-04-21 21:28:02 +02001437 acm_write_buffers_free(acm);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001438 usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Oliver Neukum830f4022008-06-25 14:17:16 +02001439 acm_read_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001441 if (!acm->combined_interfaces)
1442 usb_driver_release_interface(&acm_driver, intf == acm->control ?
Oliver Neukum830f4022008-06-25 14:17:16 +02001443 acm->data : acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001445 tty_port_put(&acm->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446}
1447
Oliver Neukum35758582008-07-01 19:10:08 +02001448#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001449static int acm_suspend(struct usb_interface *intf, pm_message_t message)
1450{
1451 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001452 int cnt;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001453
Oliver Neukum11ea8592008-06-20 11:25:57 +02001454 spin_lock_irq(&acm->read_lock);
1455 spin_lock(&acm->write_lock);
Johan Hovoldbe7978b2014-05-26 19:23:36 +02001456 if (PMSG_IS_AUTO(message)) {
1457 if (acm->transmitting) {
1458 spin_unlock(&acm->write_lock);
1459 spin_unlock_irq(&acm->read_lock);
1460 return -EBUSY;
1461 }
1462 }
Oliver Neukum11ea8592008-06-20 11:25:57 +02001463 cnt = acm->susp_count++;
1464 spin_unlock(&acm->write_lock);
1465 spin_unlock_irq(&acm->read_lock);
1466
1467 if (cnt)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001468 return 0;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001469
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001470 if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
Oliver Neukum1365baf2007-10-12 17:24:28 +02001471 stop_data_traffic(acm);
1472
Oliver Neukum1365baf2007-10-12 17:24:28 +02001473 return 0;
1474}
1475
1476static int acm_resume(struct usb_interface *intf)
1477{
1478 struct acm *acm = usb_get_intfdata(intf);
Johan Hovold21ffba32014-05-26 19:23:38 +02001479 struct urb *urb;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001480 int rv = 0;
1481
Oliver Neukum11ea8592008-06-20 11:25:57 +02001482 spin_lock_irq(&acm->read_lock);
Johan Hovold97e72c42014-05-26 19:23:37 +02001483 spin_lock(&acm->write_lock);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001484
Johan Hovold97e72c42014-05-26 19:23:37 +02001485 if (--acm->susp_count)
1486 goto out;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001487
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001488 if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
Johan Hovold97e72c42014-05-26 19:23:37 +02001489 rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);
Oliver Neukum97d35f92009-12-16 17:05:57 +01001490
Johan Hovold21ffba32014-05-26 19:23:38 +02001491 for (;;) {
1492 urb = usb_get_from_anchor(&acm->delayed);
1493 if (!urb)
1494 break;
1495
1496 acm_start_wb(acm, urb->context);
Oliver Neukum97d35f92009-12-16 17:05:57 +01001497 }
1498
1499 /*
1500 * delayed error checking because we must
1501 * do the write path at all cost
1502 */
Oliver Neukum1365baf2007-10-12 17:24:28 +02001503 if (rv < 0)
Johan Hovold97e72c42014-05-26 19:23:37 +02001504 goto out;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001505
Johan Hovold97e72c42014-05-26 19:23:37 +02001506 rv = acm_submit_read_urbs(acm, GFP_ATOMIC);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001507 }
Johan Hovold97e72c42014-05-26 19:23:37 +02001508out:
1509 spin_unlock(&acm->write_lock);
1510 spin_unlock_irq(&acm->read_lock);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001511
Oliver Neukum1365baf2007-10-12 17:24:28 +02001512 return rv;
1513}
Oliver Neukum35758582008-07-01 19:10:08 +02001514
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001515static int acm_reset_resume(struct usb_interface *intf)
1516{
1517 struct acm *acm = usb_get_intfdata(intf);
1518 struct tty_struct *tty;
1519
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001520 if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001521 tty = tty_port_tty_get(&acm->port);
1522 if (tty) {
1523 tty_hangup(tty);
1524 tty_kref_put(tty);
1525 }
1526 }
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001527
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001528 return acm_resume(intf);
1529}
1530
Oliver Neukum35758582008-07-01 19:10:08 +02001531#endif /* CONFIG_PM */
Adrian Taylorc1479a92009-11-19 10:35:33 +00001532
1533#define NOKIA_PCSUITE_ACM_INFO(x) \
1534 USB_DEVICE_AND_INTERFACE_INFO(0x0421, x, \
1535 USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \
1536 USB_CDC_ACM_PROTO_VENDOR)
1537
Toby Gray4035e452010-09-01 16:01:19 +01001538#define SAMSUNG_PCSUITE_ACM_INFO(x) \
1539 USB_DEVICE_AND_INTERFACE_INFO(0x04e7, x, \
1540 USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \
1541 USB_CDC_ACM_PROTO_VENDOR)
1542
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543/*
1544 * USB driver structure.
1545 */
1546
Németh Márton6ef48522010-01-10 15:33:45 +01001547static const struct usb_device_id acm_ids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 /* quirky and broken devices */
David Cluytensbd73e382013-12-03 14:18:57 +01001549 { USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */
1550 .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1552 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1553 },
Andrey Arapovb0e2a702007-07-04 17:11:42 +02001554 { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
1555 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1556 },
Andrew Lunn0f9c7b42008-12-23 17:31:23 +01001557 { USB_DEVICE(0x0e8d, 0x3329), /* MediaTek Inc GPS */
1558 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1559 },
Masahito Omote8753e652005-07-29 12:17:25 -07001560 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1561 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1562 },
Chris Malley91a9c922006-10-03 10:08:28 +01001563 { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
1564 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1565 },
Alan Cox7abcf202009-04-06 17:35:01 +01001566 { USB_DEVICE(0x0ace, 0x1602), /* ZyDAS 56K USB MODEM */
1567 .driver_info = SINGLE_RX_URB,
1568 },
Oliver Neukum86478942006-05-13 22:50:47 +02001569 { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
1570 .driver_info = SINGLE_RX_URB, /* firmware bug */
1571 },
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001572 { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
1573 .driver_info = SINGLE_RX_URB, /* firmware bug */
1574 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001575 { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
1576 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1577 },
Iain McFarlane6149ed52008-05-04 00:13:49 +01001578 { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */
1579 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1580 },
Eric Sandeenc8fd2c32008-08-14 08:25:40 -05001581 { USB_DEVICE(0x0572, 0x1321), /* Conexant USB MODEM CX93010 */
1582 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1583 },
Alan Coxc89c60e2009-01-11 19:53:10 +00001584 { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */
1585 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1586 },
Xiao Kaijiancab98a02009-05-08 00:48:23 +08001587 { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */
1588 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1589 },
Dmitriy Taychenachev155df652009-02-25 12:36:51 +08001590 { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
1591 },
Krzysztof Hałasa6abff5d2011-12-12 14:51:00 +01001592 /* Motorola H24 HSPA module: */
1593 { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */
Michael Ulbrichtb08f08b2014-03-25 10:34:18 +01001594 { USB_DEVICE(0x22b8, 0x2d92), /* modem + diagnostics */
1595 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1596 },
1597 { USB_DEVICE(0x22b8, 0x2d93), /* modem + AT port */
1598 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1599 },
1600 { USB_DEVICE(0x22b8, 0x2d95), /* modem + AT port + diagnostics */
1601 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1602 },
1603 { USB_DEVICE(0x22b8, 0x2d96), /* modem + NMEA */
1604 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1605 },
1606 { USB_DEVICE(0x22b8, 0x2d97), /* modem + diagnostics + NMEA */
1607 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1608 },
1609 { USB_DEVICE(0x22b8, 0x2d99), /* modem + AT port + NMEA */
1610 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1611 },
1612 { USB_DEVICE(0x22b8, 0x2d9a), /* modem + AT port + diagnostics + NMEA */
1613 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1614 },
Krzysztof Hałasa6abff5d2011-12-12 14:51:00 +01001615
Adam Richterc332b4e2009-02-18 16:17:15 -08001616 { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */
1617 .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on
1618 data interface instead of
1619 communications interface.
1620 Maybe we should define a new
1621 quirk for this. */
1622 },
Jean-Christian de Rivaz52538352012-10-10 12:49:02 +00001623 { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */
1624 .driver_info = NO_UNION_NORMAL,
1625 },
Denis N Ladinb756d752012-12-26 18:29:44 +05001626 { USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */
1627 .driver_info = NO_UNION_NORMAL,
1628 },
Kir Kolyshkin1f17c502009-05-28 20:33:58 +04001629 { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */
1630 .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
1631 },
Russ Nelsonc3baa192010-04-21 23:07:03 -04001632 { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */
1633 .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
1634 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001635
Adrian Taylorc1479a92009-11-19 10:35:33 +00001636 /* Nokia S60 phones expose two ACM channels. The first is
1637 * a modem and is picked up by the standard AT-command
1638 * information below. The second is 'vendor-specific' but
1639 * is treated as a serial device at the S60 end, so we want
1640 * to expose it on Linux too. */
1641 { NOKIA_PCSUITE_ACM_INFO(0x042D), }, /* Nokia 3250 */
1642 { NOKIA_PCSUITE_ACM_INFO(0x04D8), }, /* Nokia 5500 Sport */
1643 { NOKIA_PCSUITE_ACM_INFO(0x04C9), }, /* Nokia E50 */
1644 { NOKIA_PCSUITE_ACM_INFO(0x0419), }, /* Nokia E60 */
1645 { NOKIA_PCSUITE_ACM_INFO(0x044D), }, /* Nokia E61 */
1646 { NOKIA_PCSUITE_ACM_INFO(0x0001), }, /* Nokia E61i */
1647 { NOKIA_PCSUITE_ACM_INFO(0x0475), }, /* Nokia E62 */
1648 { NOKIA_PCSUITE_ACM_INFO(0x0508), }, /* Nokia E65 */
1649 { NOKIA_PCSUITE_ACM_INFO(0x0418), }, /* Nokia E70 */
1650 { NOKIA_PCSUITE_ACM_INFO(0x0425), }, /* Nokia N71 */
1651 { NOKIA_PCSUITE_ACM_INFO(0x0486), }, /* Nokia N73 */
1652 { NOKIA_PCSUITE_ACM_INFO(0x04DF), }, /* Nokia N75 */
1653 { NOKIA_PCSUITE_ACM_INFO(0x000e), }, /* Nokia N77 */
1654 { NOKIA_PCSUITE_ACM_INFO(0x0445), }, /* Nokia N80 */
1655 { NOKIA_PCSUITE_ACM_INFO(0x042F), }, /* Nokia N91 & N91 8GB */
1656 { NOKIA_PCSUITE_ACM_INFO(0x048E), }, /* Nokia N92 */
1657 { NOKIA_PCSUITE_ACM_INFO(0x0420), }, /* Nokia N93 */
1658 { NOKIA_PCSUITE_ACM_INFO(0x04E6), }, /* Nokia N93i */
1659 { NOKIA_PCSUITE_ACM_INFO(0x04B2), }, /* Nokia 5700 XpressMusic */
1660 { NOKIA_PCSUITE_ACM_INFO(0x0134), }, /* Nokia 6110 Navigator (China) */
1661 { NOKIA_PCSUITE_ACM_INFO(0x046E), }, /* Nokia 6110 Navigator */
1662 { NOKIA_PCSUITE_ACM_INFO(0x002f), }, /* Nokia 6120 classic & */
1663 { NOKIA_PCSUITE_ACM_INFO(0x0088), }, /* Nokia 6121 classic */
1664 { NOKIA_PCSUITE_ACM_INFO(0x00fc), }, /* Nokia 6124 classic */
1665 { NOKIA_PCSUITE_ACM_INFO(0x0042), }, /* Nokia E51 */
1666 { NOKIA_PCSUITE_ACM_INFO(0x00b0), }, /* Nokia E66 */
1667 { NOKIA_PCSUITE_ACM_INFO(0x00ab), }, /* Nokia E71 */
1668 { NOKIA_PCSUITE_ACM_INFO(0x0481), }, /* Nokia N76 */
1669 { NOKIA_PCSUITE_ACM_INFO(0x0007), }, /* Nokia N81 & N81 8GB */
1670 { NOKIA_PCSUITE_ACM_INFO(0x0071), }, /* Nokia N82 */
1671 { NOKIA_PCSUITE_ACM_INFO(0x04F0), }, /* Nokia N95 & N95-3 NAM */
1672 { NOKIA_PCSUITE_ACM_INFO(0x0070), }, /* Nokia N95 8GB */
1673 { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */
1674 { NOKIA_PCSUITE_ACM_INFO(0x0099), }, /* Nokia 6210 Navigator, RM-367 */
1675 { NOKIA_PCSUITE_ACM_INFO(0x0128), }, /* Nokia 6210 Navigator, RM-419 */
1676 { NOKIA_PCSUITE_ACM_INFO(0x008f), }, /* Nokia 6220 Classic */
1677 { NOKIA_PCSUITE_ACM_INFO(0x00a0), }, /* Nokia 6650 */
1678 { NOKIA_PCSUITE_ACM_INFO(0x007b), }, /* Nokia N78 */
1679 { NOKIA_PCSUITE_ACM_INFO(0x0094), }, /* Nokia N85 */
1680 { NOKIA_PCSUITE_ACM_INFO(0x003a), }, /* Nokia N96 & N96-3 */
1681 { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */
1682 { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */
1683 { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */
Przemo Firszt83a4eae2010-06-28 21:29:34 +01001684 { NOKIA_PCSUITE_ACM_INFO(0x02e3), }, /* Nokia 5230, RM-588 */
Toby Gray4035e452010-09-01 16:01:19 +01001685 { NOKIA_PCSUITE_ACM_INFO(0x0178), }, /* Nokia E63 */
1686 { NOKIA_PCSUITE_ACM_INFO(0x010e), }, /* Nokia E75 */
1687 { NOKIA_PCSUITE_ACM_INFO(0x02d9), }, /* Nokia 6760 Slide */
1688 { NOKIA_PCSUITE_ACM_INFO(0x01d0), }, /* Nokia E52 */
1689 { NOKIA_PCSUITE_ACM_INFO(0x0223), }, /* Nokia E72 */
1690 { NOKIA_PCSUITE_ACM_INFO(0x0275), }, /* Nokia X6 */
1691 { NOKIA_PCSUITE_ACM_INFO(0x026c), }, /* Nokia N97 Mini */
1692 { NOKIA_PCSUITE_ACM_INFO(0x0154), }, /* Nokia 5800 XpressMusic */
1693 { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */
1694 { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */
Arvid Ephraim Picciani721d92f2011-01-25 15:58:40 +01001695 { NOKIA_PCSUITE_ACM_INFO(0x0302), }, /* Nokia N8 */
Toby Gray4061fde2011-06-06 14:52:48 +01001696 { NOKIA_PCSUITE_ACM_INFO(0x0335), }, /* Nokia E7 */
1697 { NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */
Toby Gray4035e452010-09-01 16:01:19 +01001698 { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */
Adrian Taylorc1479a92009-11-19 10:35:33 +00001699
Denis Pershin65e52f42011-09-04 17:37:21 +07001700 /* Support for Owen devices */
1701 { USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */
1702
Adrian Taylorc1479a92009-11-19 10:35:33 +00001703 /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
1704
Julian Calaby7c5d8c32010-01-05 23:57:46 +11001705 /* Support Lego NXT using pbLua firmware */
Julian Calabyce126642010-01-05 23:58:20 +11001706 { USB_DEVICE(0x0694, 0xff00),
1707 .driver_info = NOT_A_MODEM,
Otavio Salvador7893afc2010-09-26 23:35:05 -03001708 },
Julian Calaby7c5d8c32010-01-05 23:57:46 +11001709
Erik Slagterfd5054c2011-05-11 12:06:55 +02001710 /* Support for Droids MuIn LCD */
1711 { USB_DEVICE(0x04d8, 0x000b),
1712 .driver_info = NO_DATA_INTERFACE,
1713 },
1714
Philippe Corbes5b239f02010-08-31 19:31:32 +02001715 /* control interfaces without any protocol set */
1716 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1717 USB_CDC_PROTO_NONE) },
1718
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 /* control interfaces with various AT-command sets */
1720 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1721 USB_CDC_ACM_PROTO_AT_V25TER) },
1722 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1723 USB_CDC_ACM_PROTO_AT_PCCA101) },
1724 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1725 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1726 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1727 USB_CDC_ACM_PROTO_AT_GSM) },
1728 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
Alan Cox6e47e062009-06-11 12:37:06 +01001729 USB_CDC_ACM_PROTO_AT_3G) },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1731 USB_CDC_ACM_PROTO_AT_CDMA) },
1732
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 { }
1734};
1735
Alan Cox6e47e062009-06-11 12:37:06 +01001736MODULE_DEVICE_TABLE(usb, acm_ids);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
1738static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 .name = "cdc_acm",
1740 .probe = acm_probe,
1741 .disconnect = acm_disconnect,
Oliver Neukum35758582008-07-01 19:10:08 +02001742#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001743 .suspend = acm_suspend,
1744 .resume = acm_resume,
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001745 .reset_resume = acm_reset_resume,
Oliver Neukum35758582008-07-01 19:10:08 +02001746#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 .id_table = acm_ids,
Oliver Neukum35758582008-07-01 19:10:08 +02001748#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001749 .supports_autosuspend = 1,
Oliver Neukum35758582008-07-01 19:10:08 +02001750#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751};
1752
1753/*
1754 * TTY driver structures.
1755 */
1756
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001757static const struct tty_operations acm_ops = {
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001758 .install = acm_tty_install,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 .open = acm_tty_open,
1760 .close = acm_tty_close,
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001761 .cleanup = acm_tty_cleanup,
Alan Cox10077d42009-06-11 12:36:09 +01001762 .hangup = acm_tty_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 .write = acm_tty_write,
1764 .write_room = acm_tty_write_room,
1765 .ioctl = acm_tty_ioctl,
1766 .throttle = acm_tty_throttle,
1767 .unthrottle = acm_tty_unthrottle,
1768 .chars_in_buffer = acm_tty_chars_in_buffer,
1769 .break_ctl = acm_tty_break_ctl,
1770 .set_termios = acm_tty_set_termios,
1771 .tiocmget = acm_tty_tiocmget,
1772 .tiocmset = acm_tty_tiocmset,
1773};
1774
1775/*
1776 * Init / exit.
1777 */
1778
1779static int __init acm_init(void)
1780{
1781 int retval;
1782 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1783 if (!acm_tty_driver)
1784 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 acm_tty_driver->driver_name = "acm",
1786 acm_tty_driver->name = "ttyACM",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 acm_tty_driver->major = ACM_TTY_MAJOR,
1788 acm_tty_driver->minor_start = 0,
1789 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1790 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001791 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 acm_tty_driver->init_termios = tty_std_termios;
Alan Cox6e47e062009-06-11 12:37:06 +01001793 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD |
1794 HUPCL | CLOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 tty_set_operations(acm_tty_driver, &acm_ops);
1796
1797 retval = tty_register_driver(acm_tty_driver);
1798 if (retval) {
1799 put_tty_driver(acm_tty_driver);
1800 return retval;
1801 }
1802
1803 retval = usb_register(&acm_driver);
1804 if (retval) {
1805 tty_unregister_driver(acm_tty_driver);
1806 put_tty_driver(acm_tty_driver);
1807 return retval;
1808 }
1809
Johan Hovolda2c7b932011-03-22 11:12:18 +01001810 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811
1812 return 0;
1813}
1814
1815static void __exit acm_exit(void)
1816{
1817 usb_deregister(&acm_driver);
1818 tty_unregister_driver(acm_tty_driver);
1819 put_tty_driver(acm_tty_driver);
1820}
1821
1822module_init(acm_init);
1823module_exit(acm_exit);
1824
Alan Cox6e47e062009-06-11 12:37:06 +01001825MODULE_AUTHOR(DRIVER_AUTHOR);
1826MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827MODULE_LICENSE("GPL");
Scott James Remnante766aeb2009-04-06 17:33:18 +01001828MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR);