blob: c7ee5a908295ed0a811d37446eaaa5d749f6c6b4 [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{
Johan Hovold9f81ca82014-05-26 19:23:39 +0200126 int retval;
127
128 retval = usb_autopm_get_interface(acm->control);
129 if (retval)
130 return retval;
131
132 retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 request, USB_RT_ACM, value,
134 acm->control->altsetting[0].desc.bInterfaceNumber,
135 buf, len, 5000);
Johan Hovold9f81ca82014-05-26 19:23:39 +0200136
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100137 dev_dbg(&acm->control->dev,
138 "%s - rq 0x%02x, val %#x, len %#x, result %d\n",
139 __func__, request, value, len, retval);
Johan Hovold9f81ca82014-05-26 19:23:39 +0200140
141 usb_autopm_put_interface(acm->control);
142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 return retval < 0 ? retval : 0;
144}
145
146/* devices aren't required to support these requests.
147 * the cdc acm descriptor tells whether they do...
148 */
149#define acm_set_control(acm, control) \
150 acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
151#define acm_set_line(acm, line) \
152 acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
153#define acm_send_break(acm, ms) \
154 acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
155
156/*
Oliver Neukum884b6002005-04-21 21:28:02 +0200157 * Write buffer management.
158 * All of these assume proper locks taken by the caller.
159 */
160
161static int acm_wb_alloc(struct acm *acm)
162{
163 int i, wbn;
164 struct acm_wb *wb;
165
David Engrafe4cf3aa2008-03-20 10:01:34 +0100166 wbn = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200167 i = 0;
168 for (;;) {
169 wb = &acm->wb[wbn];
170 if (!wb->use) {
171 wb->use = 1;
172 return wbn;
173 }
Oliver Neukum86478942006-05-13 22:50:47 +0200174 wbn = (wbn + 1) % ACM_NW;
175 if (++i >= ACM_NW)
Oliver Neukum884b6002005-04-21 21:28:02 +0200176 return -1;
177 }
178}
179
Oliver Neukum884b6002005-04-21 21:28:02 +0200180static int acm_wb_is_avail(struct acm *acm)
181{
182 int i, n;
David Brownelle5fbab52008-08-06 18:46:10 -0700183 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200184
Oliver Neukum86478942006-05-13 22:50:47 +0200185 n = ACM_NW;
David Brownelle5fbab52008-08-06 18:46:10 -0700186 spin_lock_irqsave(&acm->write_lock, flags);
Alan Cox6e47e062009-06-11 12:37:06 +0100187 for (i = 0; i < ACM_NW; i++)
Oliver Neukum86478942006-05-13 22:50:47 +0200188 n -= acm->wb[i].use;
David Brownelle5fbab52008-08-06 18:46:10 -0700189 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200190 return n;
191}
192
Oliver Neukum884b6002005-04-21 21:28:02 +0200193/*
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800194 * Finish write. Caller must hold acm->write_lock
Oliver Neukum884b6002005-04-21 21:28:02 +0200195 */
David Engrafe4cf3aa2008-03-20 10:01:34 +0100196static void acm_write_done(struct acm *acm, struct acm_wb *wb)
Oliver Neukum884b6002005-04-21 21:28:02 +0200197{
David Engrafe4cf3aa2008-03-20 10:01:34 +0100198 wb->use = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200199 acm->transmitting--;
Oliver Neukum97d35f92009-12-16 17:05:57 +0100200 usb_autopm_put_interface_async(acm->control);
Oliver Neukum884b6002005-04-21 21:28:02 +0200201}
202
203/*
204 * Poke write.
Oliver Neukum11ea8592008-06-20 11:25:57 +0200205 *
206 * the caller is responsible for locking
Oliver Neukum884b6002005-04-21 21:28:02 +0200207 */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200208
209static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
210{
211 int rc;
212
213 acm->transmitting++;
214
215 wb->urb->transfer_buffer = wb->buf;
216 wb->urb->transfer_dma = wb->dmah;
217 wb->urb->transfer_buffer_length = wb->len;
218 wb->urb->dev = acm->dev;
219
Alan Cox6e47e062009-06-11 12:37:06 +0100220 rc = usb_submit_urb(wb->urb, GFP_ATOMIC);
221 if (rc < 0) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100222 dev_err(&acm->data->dev,
223 "%s - usb_submit_urb(write bulk) failed: %d\n",
224 __func__, rc);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200225 acm_write_done(acm, wb);
226 }
227 return rc;
228}
229
David Engrafe4cf3aa2008-03-20 10:01:34 +0100230static int acm_write_start(struct acm *acm, int wbn)
Oliver Neukum884b6002005-04-21 21:28:02 +0200231{
232 unsigned long flags;
David Brownell934da462008-08-06 18:44:12 -0700233 struct acm_wb *wb = &acm->wb[wbn];
Oliver Neukum884b6002005-04-21 21:28:02 +0200234 int rc;
235
236 spin_lock_irqsave(&acm->write_lock, flags);
237 if (!acm->dev) {
David Brownell934da462008-08-06 18:44:12 -0700238 wb->use = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200239 spin_unlock_irqrestore(&acm->write_lock, flags);
240 return -ENODEV;
241 }
242
Johan Hovold5e9e75f2011-03-22 11:12:17 +0100243 dev_vdbg(&acm->data->dev, "%s - susp_count %d\n", __func__,
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100244 acm->susp_count);
Oliver Neukum97d35f92009-12-16 17:05:57 +0100245 usb_autopm_get_interface_async(acm->control);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200246 if (acm->susp_count) {
Johan Hovold21ffba32014-05-26 19:23:38 +0200247 usb_anchor_urb(wb->urb, &acm->delayed);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200248 spin_unlock_irqrestore(&acm->write_lock, flags);
Johan Hovold21ffba32014-05-26 19:23:38 +0200249 return 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200250 }
251 usb_mark_last_busy(acm->dev);
252
Oliver Neukum11ea8592008-06-20 11:25:57 +0200253 rc = acm_start_wb(acm, wb);
Oliver Neukum884b6002005-04-21 21:28:02 +0200254 spin_unlock_irqrestore(&acm->write_lock, flags);
255
Oliver Neukum884b6002005-04-21 21:28:02 +0200256 return rc;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200257
Oliver Neukum884b6002005-04-21 21:28:02 +0200258}
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100259/*
260 * attributes exported through sysfs
261 */
262static ssize_t show_caps
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);
Oliver Neukum884b6002005-04-21 21:28:02 +0200267
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100268 return sprintf(buf, "%d", acm->ctrl_caps);
269}
270static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
271
272static ssize_t show_country_codes
273(struct device *dev, struct device_attribute *attr, char *buf)
274{
275 struct usb_interface *intf = to_usb_interface(dev);
276 struct acm *acm = usb_get_intfdata(intf);
277
278 memcpy(buf, acm->country_codes, acm->country_code_size);
279 return acm->country_code_size;
280}
281
282static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
283
284static ssize_t show_country_rel_date
285(struct device *dev, struct device_attribute *attr, char *buf)
286{
287 struct usb_interface *intf = to_usb_interface(dev);
288 struct acm *acm = usb_get_intfdata(intf);
289
290 return sprintf(buf, "%d", acm->country_rel_date);
291}
292
293static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
Oliver Neukum884b6002005-04-21 21:28:02 +0200294/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 * Interrupt handlers for various ACM device responses
296 */
297
298/* control interface reports status changes with "interrupt" transfers */
David Howells7d12e782006-10-05 14:55:46 +0100299static void acm_ctrl_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
301 struct acm *acm = urb->context;
302 struct usb_cdc_notification *dr = urb->transfer_buffer;
Alan Cox10077d42009-06-11 12:36:09 +0100303 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 unsigned char *data;
305 int newctrl;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700306 int retval;
307 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700309 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 case 0:
311 /* success */
312 break;
313 case -ECONNRESET:
314 case -ENOENT:
315 case -ESHUTDOWN:
316 /* this urb is terminated, clean up */
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100317 dev_dbg(&acm->control->dev,
318 "%s - urb shutting down with status: %d\n",
319 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 return;
321 default:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100322 dev_dbg(&acm->control->dev,
323 "%s - nonzero urb status received: %d\n",
324 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 goto exit;
326 }
327
Johan Hovold7e7797e2011-03-22 11:12:11 +0100328 usb_mark_last_busy(acm->dev);
329
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 data = (unsigned char *)(dr + 1);
331 switch (dr->bNotificationType) {
Alan Cox6e47e062009-06-11 12:37:06 +0100332 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100333 dev_dbg(&acm->control->dev, "%s - network connection: %d\n",
334 __func__, dr->wValue);
Alan Cox6e47e062009-06-11 12:37:06 +0100335 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
Alan Cox6e47e062009-06-11 12:37:06 +0100337 case USB_CDC_NOTIFY_SERIAL_STATE:
338 tty = tty_port_tty_get(&acm->port);
339 newctrl = get_unaligned_le16(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Alan Cox6e47e062009-06-11 12:37:06 +0100341 if (tty) {
342 if (!acm->clocal &&
343 (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100344 dev_dbg(&acm->control->dev,
345 "%s - calling hangup\n", __func__);
Alan Cox6e47e062009-06-11 12:37:06 +0100346 tty_hangup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 }
Alan Cox6e47e062009-06-11 12:37:06 +0100348 tty_kref_put(tty);
349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Alan Cox6e47e062009-06-11 12:37:06 +0100351 acm->ctrlin = newctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100353 dev_dbg(&acm->control->dev,
354 "%s - input control lines: dcd%c dsr%c break%c "
355 "ring%c framing%c parity%c overrun%c\n",
356 __func__,
Alan Cox6e47e062009-06-11 12:37:06 +0100357 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',
358 acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
359 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-',
360 acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
361 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',
362 acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
363 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 break;
365
Alan Cox6e47e062009-06-11 12:37:06 +0100366 default:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100367 dev_dbg(&acm->control->dev,
368 "%s - unknown notification %d received: index %d "
369 "len %d data0 %d data1 %d\n",
370 __func__,
Alan Cox6e47e062009-06-11 12:37:06 +0100371 dr->bNotificationType, dr->wIndex,
372 dr->wLength, data[0], data[1]);
373 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 }
375exit:
Alan Cox6e47e062009-06-11 12:37:06 +0100376 retval = usb_submit_urb(urb, GFP_ATOMIC);
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700377 if (retval)
Johan Hovold1d9846e2011-03-22 11:12:14 +0100378 dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n",
379 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380}
381
Johan Hovold088c64f2011-03-25 11:06:02 +0100382static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383{
Johan Hovold088c64f2011-03-25 11:06:02 +0100384 int res;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700385
Johan Hovold088c64f2011-03-25 11:06:02 +0100386 if (!test_and_clear_bit(index, &acm->read_urbs_free))
387 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Johan Hovold088c64f2011-03-25 11:06:02 +0100389 dev_vdbg(&acm->data->dev, "%s - urb %d\n", __func__, index);
390
391 res = usb_submit_urb(acm->read_urbs[index], mem_flags);
392 if (res) {
393 if (res != -EPERM) {
394 dev_err(&acm->data->dev,
395 "%s - usb_submit_urb failed: %d\n",
396 __func__, res);
397 }
398 set_bit(index, &acm->read_urbs_free);
399 return res;
400 }
401
402 return 0;
403}
404
405static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags)
406{
407 int res;
408 int i;
409
410 for (i = 0; i < acm->rx_buflimit; ++i) {
411 res = acm_submit_read_urb(acm, i, mem_flags);
412 if (res)
413 return res;
414 }
415
416 return 0;
417}
418
419static void acm_process_read_urb(struct acm *acm, struct urb *urb)
420{
421 struct tty_struct *tty;
422
423 if (!urb->actual_length)
424 return;
425
426 tty = tty_port_tty_get(&acm->port);
427 if (!tty)
428 return;
429
430 tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length);
431 tty_flip_buffer_push(tty);
432
433 tty_kref_put(tty);
434}
435
436static void acm_read_bulk_callback(struct urb *urb)
437{
438 struct acm_rb *rb = urb->context;
439 struct acm *acm = rb->instance;
440 unsigned long flags;
441
442 dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__,
443 rb->index, urb->actual_length);
444 set_bit(rb->index, &acm->read_urbs_free);
445
446 if (!acm->dev) {
447 dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200449 }
450 usb_mark_last_busy(acm->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
Johan Hovold088c64f2011-03-25 11:06:02 +0100452 if (urb->status) {
Johan Hovold1d9846e2011-03-22 11:12:14 +0100453 dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n",
Johan Hovold088c64f2011-03-25 11:06:02 +0100454 __func__, urb->status);
455 return;
456 }
457 acm_process_read_urb(acm, urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Johan Hovold088c64f2011-03-25 11:06:02 +0100459 /* throttle device if requested by tty */
460 spin_lock_irqsave(&acm->read_lock, flags);
461 acm->throttled = acm->throttle_req;
462 if (!acm->throttled && !acm->susp_count) {
463 spin_unlock_irqrestore(&acm->read_lock, flags);
464 acm_submit_read_urb(acm, rb->index, GFP_ATOMIC);
Oliver Neukum86478942006-05-13 22:50:47 +0200465 } else {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200466 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468}
469
470/* data interface wrote those outgoing bytes */
David Howells7d12e782006-10-05 14:55:46 +0100471static void acm_write_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
Ming Leicdc97792008-02-24 18:41:47 +0800473 struct acm_wb *wb = urb->context;
David Brownelle5fbab52008-08-06 18:46:10 -0700474 struct acm *acm = wb->instance;
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800475 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200476
Johan Hovold4fa46262011-03-22 11:12:16 +0100477 if (urb->status || (urb->actual_length != urb->transfer_buffer_length))
478 dev_vdbg(&acm->data->dev, "%s - len %d/%d, status %d\n",
Johan Hovold1d9846e2011-03-22 11:12:14 +0100479 __func__,
David Brownelle5fbab52008-08-06 18:46:10 -0700480 urb->actual_length,
481 urb->transfer_buffer_length,
482 urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800484 spin_lock_irqsave(&acm->write_lock, flags);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100485 acm_write_done(acm, wb);
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800486 spin_unlock_irqrestore(&acm->write_lock, flags);
Havard Skinnemoen99823f42011-12-09 16:51:54 -0800487 schedule_work(&acm->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488}
489
David Howellsc4028952006-11-22 14:57:56 +0000490static void acm_softint(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
David Howellsc4028952006-11-22 14:57:56 +0000492 struct acm *acm = container_of(work, struct acm, work);
Alan Cox10077d42009-06-11 12:36:09 +0100493 struct tty_struct *tty;
David Brownelle5fbab52008-08-06 18:46:10 -0700494
Johan Hovold1d9846e2011-03-22 11:12:14 +0100495 dev_vdbg(&acm->data->dev, "%s\n", __func__);
496
Alan Cox10077d42009-06-11 12:36:09 +0100497 tty = tty_port_tty_get(&acm->port);
Johan Hovold15e5bee2011-03-22 11:12:10 +0100498 if (!tty)
499 return;
Alan Cox10077d42009-06-11 12:36:09 +0100500 tty_wakeup(tty);
501 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502}
503
504/*
505 * TTY handlers
506 */
507
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800508static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509{
510 struct acm *acm;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800511 int retval;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100512
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800513 dev_dbg(tty->dev, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800515 acm = acm_get_by_index(tty->index);
516 if (!acm)
517 return -ENODEV;
518
Jiri Slabyf8a8c102012-03-05 14:51:48 +0100519 retval = tty_standard_install(driver, tty);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800520 if (retval)
521 goto error_init_termios;
522
523 tty->driver_data = acm;
524
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800525 return 0;
526
527error_init_termios:
528 tty_port_put(&acm->port);
529 return retval;
530}
531
532static int acm_tty_open(struct tty_struct *tty, struct file *filp)
533{
534 struct acm *acm = tty->driver_data;
535
536 dev_dbg(tty->dev, "%s\n", __func__);
537
538 return tty_port_open(&acm->port, tty, filp);
539}
540
541static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)
542{
543 struct acm *acm = container_of(port, struct acm, port);
544 int retval = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100546 dev_dbg(&acm->control->dev, "%s\n", __func__);
547
Oliver Neukum1365baf2007-10-12 17:24:28 +0200548 mutex_lock(&acm->mutex);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800549 if (acm->disconnected)
550 goto disconnected;
551
552 retval = usb_autopm_get_interface(acm->control);
553 if (retval)
554 goto error_get_interface;
555
556 /*
557 * FIXME: Why do we need this? Allocating 64K of physically contiguous
558 * memory is really nasty...
559 */
560 set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
561 acm->control->needs_remote_wakeup = 1;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 acm->ctrlurb->dev = acm->dev;
564 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100565 dev_err(&acm->control->dev,
566 "%s - usb_submit_urb(ctrl irq) failed\n", __func__);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800567 goto error_submit_urb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 }
569
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800570 acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS;
571 if (acm_set_control(acm, acm->ctrlout) < 0 &&
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100572 (acm->ctrl_caps & USB_CDC_CAP_LINE))
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800573 goto error_set_control;
Alan Cox10077d42009-06-11 12:36:09 +0100574
Oliver Neukum11ea8592008-06-20 11:25:57 +0200575 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Otto Meta9cc2d462012-06-06 18:46:21 +0200577 /*
578 * Unthrottle device in case the TTY was closed while throttled.
579 */
580 spin_lock_irq(&acm->read_lock);
581 acm->throttled = 0;
582 acm->throttle_req = 0;
583 spin_unlock_irq(&acm->read_lock);
584
Johan Hovold088c64f2011-03-25 11:06:02 +0100585 if (acm_submit_read_urbs(acm, GFP_KERNEL))
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800586 goto error_submit_read_urbs;
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100587
Oliver Neukum1365baf2007-10-12 17:24:28 +0200588 mutex_unlock(&acm->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800590 return 0;
591
592error_submit_read_urbs:
593 acm->ctrlout = 0;
594 acm_set_control(acm, acm->ctrlout);
595error_set_control:
596 usb_kill_urb(acm->ctrlurb);
597error_submit_urb:
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100598 usb_autopm_put_interface(acm->control);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800599error_get_interface:
600disconnected:
601 mutex_unlock(&acm->mutex);
602 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603}
604
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800605static void acm_port_destruct(struct tty_port *port)
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700606{
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800607 struct acm *acm = container_of(port, struct acm, port);
608
609 dev_dbg(&acm->control->dev, "%s\n", __func__);
David Kubicek61a87ad2005-11-01 18:51:34 +0100610
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800611 acm_release_minor(acm);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700612 usb_put_intf(acm->control);
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100613 kfree(acm->country_codes);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700614 kfree(acm);
615}
616
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800617static void acm_port_shutdown(struct tty_port *port)
Alan Cox10077d42009-06-11 12:36:09 +0100618{
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800619 struct acm *acm = container_of(port, struct acm, port);
Johan Hovold21ffba32014-05-26 19:23:38 +0200620 struct urb *urb;
621 struct acm_wb *wb;
Johan Hovolddab54c92011-03-22 11:12:21 +0100622 int i;
623
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800624 dev_dbg(&acm->control->dev, "%s\n", __func__);
625
626 mutex_lock(&acm->mutex);
627 if (!acm->disconnected) {
Alan Cox10077d42009-06-11 12:36:09 +0100628 usb_autopm_get_interface(acm->control);
629 acm_set_control(acm, acm->ctrlout = 0);
Johan Hovold21ffba32014-05-26 19:23:38 +0200630
631 for (;;) {
632 urb = usb_get_from_anchor(&acm->delayed);
633 if (!urb)
634 break;
635 wb = urb->context;
636 wb->use = 0;
637 usb_autopm_put_interface_async(acm->control);
638 }
639
Alan Cox10077d42009-06-11 12:36:09 +0100640 usb_kill_urb(acm->ctrlurb);
641 for (i = 0; i < ACM_NW; i++)
642 usb_kill_urb(acm->wb[i].urb);
Johan Hovolddab54c92011-03-22 11:12:21 +0100643 for (i = 0; i < acm->rx_buflimit; i++)
Johan Hovold088c64f2011-03-25 11:06:02 +0100644 usb_kill_urb(acm->read_urbs[i]);
Alan Cox10077d42009-06-11 12:36:09 +0100645 acm->control->needs_remote_wakeup = 0;
646 usb_autopm_put_interface(acm->control);
647 }
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800648 mutex_unlock(&acm->mutex);
649}
650
651static void acm_tty_cleanup(struct tty_struct *tty)
652{
653 struct acm *acm = tty->driver_data;
654 dev_dbg(&acm->control->dev, "%s\n", __func__);
655 tty_port_put(&acm->port);
Alan Cox10077d42009-06-11 12:36:09 +0100656}
657
658static void acm_tty_hangup(struct tty_struct *tty)
659{
660 struct acm *acm = tty->driver_data;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800661 dev_dbg(&acm->control->dev, "%s\n", __func__);
Alan Cox10077d42009-06-11 12:36:09 +0100662 tty_port_hangup(&acm->port);
Alan Cox10077d42009-06-11 12:36:09 +0100663}
664
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665static void acm_tty_close(struct tty_struct *tty, struct file *filp)
666{
667 struct acm *acm = tty->driver_data;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800668 dev_dbg(&acm->control->dev, "%s\n", __func__);
669 tty_port_close(&acm->port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670}
671
Alan Cox6e47e062009-06-11 12:37:06 +0100672static int acm_tty_write(struct tty_struct *tty,
673 const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674{
675 struct acm *acm = tty->driver_data;
676 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200677 unsigned long flags;
678 int wbn;
679 struct acm_wb *wb;
680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 if (!count)
682 return 0;
683
Johan Hovold5e9e75f2011-03-22 11:12:17 +0100684 dev_vdbg(&acm->data->dev, "%s - count %d\n", __func__, count);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100685
Oliver Neukum884b6002005-04-21 21:28:02 +0200686 spin_lock_irqsave(&acm->write_lock, flags);
Alan Cox6e47e062009-06-11 12:37:06 +0100687 wbn = acm_wb_alloc(acm);
688 if (wbn < 0) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200689 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200690 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200692 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Oliver Neukum884b6002005-04-21 21:28:02 +0200694 count = (count > acm->writesize) ? acm->writesize : count;
Johan Hovold5e9e75f2011-03-22 11:12:17 +0100695 dev_vdbg(&acm->data->dev, "%s - write %d\n", __func__, count);
Oliver Neukum884b6002005-04-21 21:28:02 +0200696 memcpy(wb->buf, buf, count);
697 wb->len = count;
698 spin_unlock_irqrestore(&acm->write_lock, flags);
699
Alan Cox6e47e062009-06-11 12:37:06 +0100700 stat = acm_write_start(acm, wbn);
701 if (stat < 0)
Oliver Neukum884b6002005-04-21 21:28:02 +0200702 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 return count;
704}
705
706static int acm_tty_write_room(struct tty_struct *tty)
707{
708 struct acm *acm = tty->driver_data;
Oliver Neukum884b6002005-04-21 21:28:02 +0200709 /*
710 * Do not let the line discipline to know that we have a reserve,
711 * or it might get too enthusiastic.
712 */
David Brownell934da462008-08-06 18:44:12 -0700713 return acm_wb_is_avail(acm) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714}
715
716static int acm_tty_chars_in_buffer(struct tty_struct *tty)
717{
718 struct acm *acm = tty->driver_data;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800719 /*
720 * if the device was unplugged then any remaining characters fell out
721 * of the connector ;)
722 */
723 if (acm->disconnected)
Alan Cox23198fd2009-07-20 16:05:27 +0100724 return 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200725 /*
726 * This is inaccurate (overcounts), but it works.
727 */
Oliver Neukum86478942006-05-13 22:50:47 +0200728 return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729}
730
731static void acm_tty_throttle(struct tty_struct *tty)
732{
733 struct acm *acm = tty->driver_data;
Johan Hovold088c64f2011-03-25 11:06:02 +0100734
Johan Hovold088c64f2011-03-25 11:06:02 +0100735 spin_lock_irq(&acm->read_lock);
736 acm->throttle_req = 1;
737 spin_unlock_irq(&acm->read_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738}
739
740static void acm_tty_unthrottle(struct tty_struct *tty)
741{
742 struct acm *acm = tty->driver_data;
Johan Hovold088c64f2011-03-25 11:06:02 +0100743 unsigned int was_throttled;
744
Johan Hovold088c64f2011-03-25 11:06:02 +0100745 spin_lock_irq(&acm->read_lock);
746 was_throttled = acm->throttled;
747 acm->throttled = 0;
748 acm->throttle_req = 0;
749 spin_unlock_irq(&acm->read_lock);
750
751 if (was_throttled)
752 acm_submit_read_urbs(acm, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753}
754
Alan Cox9e989662008-07-22 11:18:03 +0100755static int acm_tty_break_ctl(struct tty_struct *tty, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756{
757 struct acm *acm = tty->driver_data;
Alan Cox9e989662008-07-22 11:18:03 +0100758 int retval;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800759
Alan Cox9e989662008-07-22 11:18:03 +0100760 retval = acm_send_break(acm, state ? 0xffff : 0);
761 if (retval < 0)
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100762 dev_dbg(&acm->control->dev, "%s - send break failed\n",
763 __func__);
Alan Cox9e989662008-07-22 11:18:03 +0100764 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765}
766
Alan Cox60b33c12011-02-14 16:26:14 +0000767static int acm_tty_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768{
769 struct acm *acm = tty->driver_data;
770
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
772 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
773 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
774 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
775 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
776 TIOCM_CTS;
777}
778
Alan Cox20b9d172011-02-14 16:26:50 +0000779static int acm_tty_tiocmset(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 unsigned int set, unsigned int clear)
781{
782 struct acm *acm = tty->driver_data;
783 unsigned int newctrl;
784
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 newctrl = acm->ctrlout;
Alan Cox6e47e062009-06-11 12:37:06 +0100786 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
787 (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
788 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
789 (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791 newctrl = (newctrl & ~clear) | set;
792
793 if (acm->ctrlout == newctrl)
794 return 0;
795 return acm_set_control(acm, acm->ctrlout = newctrl);
796}
797
Oliver Neukum18c75722012-02-17 17:21:24 -0500798static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
799{
800 struct serial_struct tmp;
801
802 if (!info)
803 return -EINVAL;
804
805 memset(&tmp, 0, sizeof(tmp));
806 tmp.flags = ASYNC_LOW_LATENCY;
807 tmp.xmit_fifo_size = acm->writesize;
808 tmp.baud_base = le32_to_cpu(acm->line.dwDTERate);
Dan Williams1229a832012-11-08 12:47:41 -0600809 tmp.close_delay = acm->port.close_delay / 10;
810 tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
811 ASYNC_CLOSING_WAIT_NONE :
812 acm->port.closing_wait / 10;
Oliver Neukum18c75722012-02-17 17:21:24 -0500813
814 if (copy_to_user(info, &tmp, sizeof(tmp)))
815 return -EFAULT;
816 else
817 return 0;
818}
819
Dan Williams1229a832012-11-08 12:47:41 -0600820static int set_serial_info(struct acm *acm,
821 struct serial_struct __user *newinfo)
822{
823 struct serial_struct new_serial;
824 unsigned int closing_wait, close_delay;
825 int retval = 0;
826
827 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
828 return -EFAULT;
829
830 close_delay = new_serial.close_delay * 10;
831 closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
832 ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
833
834 mutex_lock(&acm->port.mutex);
835
836 if (!capable(CAP_SYS_ADMIN)) {
837 if ((close_delay != acm->port.close_delay) ||
838 (closing_wait != acm->port.closing_wait))
839 retval = -EPERM;
840 else
841 retval = -EOPNOTSUPP;
842 } else {
843 acm->port.close_delay = close_delay;
844 acm->port.closing_wait = closing_wait;
845 }
846
847 mutex_unlock(&acm->port.mutex);
848 return retval;
849}
850
Alan Cox6caa76b2011-02-14 16:27:22 +0000851static int acm_tty_ioctl(struct tty_struct *tty,
Alan Cox6e47e062009-06-11 12:37:06 +0100852 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853{
Oliver Neukum18c75722012-02-17 17:21:24 -0500854 struct acm *acm = tty->driver_data;
855 int rv = -ENOIOCTLCMD;
856
857 switch (cmd) {
858 case TIOCGSERIAL: /* gets serial port data */
859 rv = get_serial_info(acm, (struct serial_struct __user *) arg);
860 break;
Dan Williams1229a832012-11-08 12:47:41 -0600861 case TIOCSSERIAL:
862 rv = set_serial_info(acm, (struct serial_struct __user *) arg);
863 break;
Oliver Neukum18c75722012-02-17 17:21:24 -0500864 }
865
866 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867}
868
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100869static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 0, 50, 75, 110, 134, 150, 200, 300, 600,
871 1200, 1800, 2400, 4800, 9600, 19200, 38400,
872 57600, 115200, 230400, 460800, 500000, 576000,
873 921600, 1000000, 1152000, 1500000, 2000000,
874 2500000, 3000000, 3500000, 4000000
875};
876
Alan Cox6e47e062009-06-11 12:37:06 +0100877static void acm_tty_set_termios(struct tty_struct *tty,
878 struct ktermios *termios_old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879{
880 struct acm *acm = tty->driver_data;
Alan Cox606d0992006-12-08 02:38:45 -0800881 struct ktermios *termios = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 struct usb_cdc_line_coding newline;
883 int newctrl = acm->ctrlout;
884
Alan Cox9b80fee2009-09-19 13:13:23 -0700885 newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
887 newline.bParityType = termios->c_cflag & PARENB ?
Alan Cox6e47e062009-06-11 12:37:06 +0100888 (termios->c_cflag & PARODD ? 1 : 2) +
889 (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
Nicolas Boullisa5204462012-10-16 00:06:23 +0200890 switch (termios->c_cflag & CSIZE) {
891 case CS5:
892 newline.bDataBits = 5;
893 break;
894 case CS6:
895 newline.bDataBits = 6;
896 break;
897 case CS7:
898 newline.bDataBits = 7;
899 break;
900 case CS8:
901 default:
902 newline.bDataBits = 8;
903 break;
904 }
Alan Cox6e47e062009-06-11 12:37:06 +0100905 /* FIXME: Needs to clear unsupported bits in the termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
907
908 if (!newline.dwDTERate) {
909 newline.dwDTERate = acm->line.dwDTERate;
910 newctrl &= ~ACM_CTRL_DTR;
Alan Cox6e47e062009-06-11 12:37:06 +0100911 } else
912 newctrl |= ACM_CTRL_DTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914 if (newctrl != acm->ctrlout)
915 acm_set_control(acm, acm->ctrlout = newctrl);
916
917 if (memcmp(&acm->line, &newline, sizeof newline)) {
918 memcpy(&acm->line, &newline, sizeof newline);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100919 dev_dbg(&acm->control->dev, "%s - set line: %d %d %d %d\n",
920 __func__,
921 le32_to_cpu(newline.dwDTERate),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 newline.bCharFormat, newline.bParityType,
923 newline.bDataBits);
924 acm_set_line(acm, &acm->line);
925 }
926}
927
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800928static const struct tty_port_operations acm_port_ops = {
929 .shutdown = acm_port_shutdown,
930 .activate = acm_port_activate,
931 .destruct = acm_port_destruct,
932};
933
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934/*
935 * USB probe and disconnect routines.
936 */
937
Oliver Neukum830f4022008-06-25 14:17:16 +0200938/* Little helpers: write/read buffers free */
Oliver Neukum884b6002005-04-21 21:28:02 +0200939static void acm_write_buffers_free(struct acm *acm)
940{
941 int i;
942 struct acm_wb *wb;
Oliver Neukuma496c642008-10-21 10:39:04 +0200943 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
Oliver Neukum884b6002005-04-21 21:28:02 +0200944
Alan Cox6e47e062009-06-11 12:37:06 +0100945 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++)
Daniel Mack997ea582010-04-12 13:17:25 +0200946 usb_free_coherent(usb_dev, acm->writesize, wb->buf, wb->dmah);
Oliver Neukum884b6002005-04-21 21:28:02 +0200947}
948
Oliver Neukum830f4022008-06-25 14:17:16 +0200949static void acm_read_buffers_free(struct acm *acm)
950{
951 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
Johan Hovolddab54c92011-03-22 11:12:21 +0100952 int i;
Oliver Neukum830f4022008-06-25 14:17:16 +0200953
Johan Hovolddab54c92011-03-22 11:12:21 +0100954 for (i = 0; i < acm->rx_buflimit; i++)
Daniel Mack997ea582010-04-12 13:17:25 +0200955 usb_free_coherent(usb_dev, acm->readsize,
Johan Hovold088c64f2011-03-25 11:06:02 +0100956 acm->read_buffers[i].base, acm->read_buffers[i].dma);
Oliver Neukum830f4022008-06-25 14:17:16 +0200957}
958
Oliver Neukum884b6002005-04-21 21:28:02 +0200959/* Little helper: write buffers allocate */
960static int acm_write_buffers_alloc(struct acm *acm)
961{
962 int i;
963 struct acm_wb *wb;
964
Oliver Neukum86478942006-05-13 22:50:47 +0200965 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Daniel Mack997ea582010-04-12 13:17:25 +0200966 wb->buf = usb_alloc_coherent(acm->dev, acm->writesize, GFP_KERNEL,
Oliver Neukum884b6002005-04-21 21:28:02 +0200967 &wb->dmah);
968 if (!wb->buf) {
969 while (i != 0) {
970 --i;
971 --wb;
Daniel Mack997ea582010-04-12 13:17:25 +0200972 usb_free_coherent(acm->dev, acm->writesize,
Oliver Neukum884b6002005-04-21 21:28:02 +0200973 wb->buf, wb->dmah);
974 }
975 return -ENOMEM;
976 }
977 }
978 return 0;
979}
980
Alan Cox10077d42009-06-11 12:36:09 +0100981static int acm_probe(struct usb_interface *intf,
982 const struct usb_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983{
984 struct usb_cdc_union_desc *union_header = NULL;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100985 struct usb_cdc_country_functional_desc *cfd = NULL;
David Brownellc6dbf552008-04-13 14:00:44 -0700986 unsigned char *buffer = intf->altsetting->extra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 int buflen = intf->altsetting->extralen;
988 struct usb_interface *control_interface;
989 struct usb_interface *data_interface;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +0200990 struct usb_endpoint_descriptor *epctrl = NULL;
991 struct usb_endpoint_descriptor *epread = NULL;
992 struct usb_endpoint_descriptor *epwrite = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 struct usb_device *usb_dev = interface_to_usbdev(intf);
994 struct acm *acm;
995 int minor;
Alan Cox6e47e062009-06-11 12:37:06 +0100996 int ctrlsize, readsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 u8 *buf;
998 u8 ac_management_function = 0;
999 u8 call_management_function = 0;
1000 int call_interface_num = -1;
Erik Slagterfd5054c2011-05-11 12:06:55 +02001001 int data_interface_num = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 unsigned long quirks;
Oliver Neukum86478942006-05-13 22:50:47 +02001003 int num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +01001004 int i;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001005 int combined_interfaces = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
Oliver Neukum86478942006-05-13 22:50:47 +02001007 /* normal quirks */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 quirks = (unsigned long)id->driver_info;
Oliver Neukum86478942006-05-13 22:50:47 +02001009 num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
1010
1011 /* handle quirks deadly to normal probing*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 if (quirks == NO_UNION_NORMAL) {
1013 data_interface = usb_ifnum_to_if(usb_dev, 1);
1014 control_interface = usb_ifnum_to_if(usb_dev, 0);
1015 goto skip_normal_probe;
1016 }
Alan Cox6e47e062009-06-11 12:37:06 +01001017
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 /* normal probing*/
1019 if (!buffer) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001020 dev_err(&intf->dev, "Weird descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 return -EINVAL;
1022 }
1023
1024 if (!buflen) {
Toby Gray577045c2010-09-02 10:46:20 +01001025 if (intf->cur_altsetting->endpoint &&
1026 intf->cur_altsetting->endpoint->extralen &&
Alan Cox6e47e062009-06-11 12:37:06 +01001027 intf->cur_altsetting->endpoint->extra) {
1028 dev_dbg(&intf->dev,
1029 "Seeking extra descriptors on endpoint\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 buflen = intf->cur_altsetting->endpoint->extralen;
1031 buffer = intf->cur_altsetting->endpoint->extra;
1032 } else {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001033 dev_err(&intf->dev,
1034 "Zero length descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 return -EINVAL;
1036 }
1037 }
1038
1039 while (buflen > 0) {
Alan Cox6e47e062009-06-11 12:37:06 +01001040 if (buffer[1] != USB_DT_CS_INTERFACE) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001041 dev_err(&intf->dev, "skipping garbage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 goto next_desc;
1043 }
1044
Alan Cox6e47e062009-06-11 12:37:06 +01001045 switch (buffer[2]) {
1046 case USB_CDC_UNION_TYPE: /* we've found it */
1047 if (union_header) {
1048 dev_err(&intf->dev, "More than one "
1049 "union descriptor, skipping ...\n");
1050 goto next_desc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 }
Alan Cox6e47e062009-06-11 12:37:06 +01001052 union_header = (struct usb_cdc_union_desc *)buffer;
1053 break;
1054 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
1055 cfd = (struct usb_cdc_country_functional_desc *)buffer;
1056 break;
1057 case USB_CDC_HEADER_TYPE: /* maybe check version */
1058 break; /* for now we ignore it */
1059 case USB_CDC_ACM_TYPE:
1060 ac_management_function = buffer[3];
1061 break;
1062 case USB_CDC_CALL_MANAGEMENT_TYPE:
1063 call_management_function = buffer[3];
1064 call_interface_num = buffer[4];
Julian Calabyce126642010-01-05 23:58:20 +11001065 if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
Alan Cox6e47e062009-06-11 12:37:06 +01001066 dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
1067 break;
1068 default:
1069 /* there are LOTS more CDC descriptors that
1070 * could legitimately be found here.
1071 */
1072 dev_dbg(&intf->dev, "Ignoring descriptor: "
1073 "type %02x, length %d\n",
1074 buffer[2], buffer[0]);
1075 break;
1076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077next_desc:
1078 buflen -= buffer[0];
1079 buffer += buffer[0];
1080 }
1081
1082 if (!union_header) {
1083 if (call_interface_num > 0) {
Alan Cox6e47e062009-06-11 12:37:06 +01001084 dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
Erik Slagterfd5054c2011-05-11 12:06:55 +02001085 /* quirks for Droids MuIn LCD */
1086 if (quirks & NO_DATA_INTERFACE)
1087 data_interface = usb_ifnum_to_if(usb_dev, 0);
1088 else
1089 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 control_interface = intf;
1091 } else {
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001092 if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
1093 dev_dbg(&intf->dev,"No union descriptor, giving up\n");
1094 return -ENODEV;
1095 } else {
1096 dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n");
1097 combined_interfaces = 1;
1098 control_interface = data_interface = intf;
1099 goto look_for_collapsed_interface;
1100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 }
1102 } else {
1103 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
1104 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
1105 if (!control_interface || !data_interface) {
Alan Cox6e47e062009-06-11 12:37:06 +01001106 dev_dbg(&intf->dev, "no interfaces\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 return -ENODEV;
1108 }
1109 }
Alan Cox6e47e062009-06-11 12:37:06 +01001110
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 if (data_interface_num != call_interface_num)
Alan Cox6e47e062009-06-11 12:37:06 +01001112 dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001114 if (control_interface == data_interface) {
1115 /* some broken devices designed for windows work this way */
1116 dev_warn(&intf->dev,"Control and data interfaces are not separated!\n");
1117 combined_interfaces = 1;
1118 /* a popular other OS doesn't use it */
1119 quirks |= NO_CAP_LINE;
1120 if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) {
1121 dev_err(&intf->dev, "This needs exactly 3 endpoints\n");
1122 return -EINVAL;
1123 }
1124look_for_collapsed_interface:
1125 for (i = 0; i < 3; i++) {
1126 struct usb_endpoint_descriptor *ep;
1127 ep = &data_interface->cur_altsetting->endpoint[i].desc;
1128
1129 if (usb_endpoint_is_int_in(ep))
1130 epctrl = ep;
1131 else if (usb_endpoint_is_bulk_out(ep))
1132 epwrite = ep;
1133 else if (usb_endpoint_is_bulk_in(ep))
1134 epread = ep;
1135 else
1136 return -EINVAL;
1137 }
1138 if (!epctrl || !epread || !epwrite)
1139 return -ENODEV;
1140 else
1141 goto made_compressed_probe;
1142 }
1143
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144skip_normal_probe:
1145
1146 /*workaround for switched interfaces */
Alan Cox6e47e062009-06-11 12:37:06 +01001147 if (data_interface->cur_altsetting->desc.bInterfaceClass
1148 != CDC_DATA_INTERFACE_TYPE) {
1149 if (control_interface->cur_altsetting->desc.bInterfaceClass
1150 == CDC_DATA_INTERFACE_TYPE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 struct usb_interface *t;
Alan Cox6e47e062009-06-11 12:37:06 +01001152 dev_dbg(&intf->dev,
1153 "Your device has switched interfaces.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 t = control_interface;
1155 control_interface = data_interface;
1156 data_interface = t;
1157 } else {
1158 return -EINVAL;
1159 }
1160 }
Alan Stern74da5d62007-08-02 13:29:10 -04001161
1162 /* Accept probe requests only for the control interface */
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001163 if (!combined_interfaces && intf != control_interface)
Alan Stern74da5d62007-08-02 13:29:10 -04001164 return -ENODEV;
Alan Cox6e47e062009-06-11 12:37:06 +01001165
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001166 if (!combined_interfaces && usb_interface_claimed(data_interface)) {
1167 /* valid in this context */
Alan Cox6e47e062009-06-11 12:37:06 +01001168 dev_dbg(&intf->dev, "The data interface isn't available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 return -EBUSY;
1170 }
1171
1172
Sven Schnellea9959bb2012-08-17 21:43:43 +02001173 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2 ||
1174 control_interface->cur_altsetting->desc.bNumEndpoints == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 return -EINVAL;
1176
1177 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
1178 epread = &data_interface->cur_altsetting->endpoint[0].desc;
1179 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
1180
1181
1182 /* workaround for switched endpoints */
Luiz Fernando N. Capitulino45aea702006-10-26 13:02:48 -03001183 if (!usb_endpoint_dir_in(epread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 /* descriptors are swapped */
1185 struct usb_endpoint_descriptor *t;
Alan Cox6e47e062009-06-11 12:37:06 +01001186 dev_dbg(&intf->dev,
1187 "The data interface has switched endpoints\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 t = epread;
1189 epread = epwrite;
1190 epwrite = t;
1191 }
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001192made_compressed_probe:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +01001193 dev_dbg(&intf->dev, "interfaces are valid\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
Alan Cox6e47e062009-06-11 12:37:06 +01001195 acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
1196 if (acm == NULL) {
Johan Hovold255ab562011-03-22 11:12:13 +01001197 dev_err(&intf->dev, "out of memory (acm kzalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 goto alloc_fail;
1199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001201 minor = acm_alloc_minor(acm);
1202 if (minor == ACM_TTY_MINORS) {
1203 dev_err(&intf->dev, "no more free acm devices\n");
1204 kfree(acm);
1205 return -ENODEV;
1206 }
1207
Kuninori Morimoto29cc8892011-08-23 03:12:03 -07001208 ctrlsize = usb_endpoint_maxp(epctrl);
1209 readsize = usb_endpoint_maxp(epread) *
Alan Cox6e47e062009-06-11 12:37:06 +01001210 (quirks == SINGLE_RX_URB ? 1 : 2);
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001211 acm->combined_interfaces = combined_interfaces;
Kuninori Morimoto29cc8892011-08-23 03:12:03 -07001212 acm->writesize = usb_endpoint_maxp(epwrite) * 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 acm->control = control_interface;
1214 acm->data = data_interface;
1215 acm->minor = minor;
1216 acm->dev = usb_dev;
1217 acm->ctrl_caps = ac_management_function;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001218 if (quirks & NO_CAP_LINE)
1219 acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 acm->ctrlsize = ctrlsize;
1221 acm->readsize = readsize;
Oliver Neukum86478942006-05-13 22:50:47 +02001222 acm->rx_buflimit = num_rx_buf;
David Howellsc4028952006-11-22 14:57:56 +00001223 INIT_WORK(&acm->work, acm_softint);
Oliver Neukum884b6002005-04-21 21:28:02 +02001224 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +01001225 spin_lock_init(&acm->read_lock);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001226 mutex_init(&acm->mutex);
David Kubicek61a87ad2005-11-01 18:51:34 +01001227 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Oliver Neukumcf7fdd52009-08-04 23:52:09 +02001228 acm->is_int_ep = usb_endpoint_xfer_int(epread);
1229 if (acm->is_int_ep)
1230 acm->bInterval = epread->bInterval;
Alan Cox739e0282009-06-11 12:27:50 +01001231 tty_port_init(&acm->port);
1232 acm->port.ops = &acm_port_ops;
Johan Hovold21ffba32014-05-26 19:23:38 +02001233 init_usb_anchor(&acm->delayed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Daniel Mack997ea582010-04-12 13:17:25 +02001235 buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 if (!buf) {
Johan Hovold255ab562011-03-22 11:12:13 +01001237 dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 goto alloc_fail2;
1239 }
1240 acm->ctrl_buffer = buf;
1241
Oliver Neukum884b6002005-04-21 21:28:02 +02001242 if (acm_write_buffers_alloc(acm) < 0) {
Johan Hovold255ab562011-03-22 11:12:13 +01001243 dev_err(&intf->dev, "out of memory (write buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 goto alloc_fail4;
1245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
1247 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
1248 if (!acm->ctrlurb) {
Johan Hovold255ab562011-03-22 11:12:13 +01001249 dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 goto alloc_fail5;
1251 }
Oliver Neukum86478942006-05-13 22:50:47 +02001252 for (i = 0; i < num_rx_buf; i++) {
Johan Hovold088c64f2011-03-25 11:06:02 +01001253 struct acm_rb *rb = &(acm->read_buffers[i]);
1254 struct urb *urb;
David Kubicek61a87ad2005-11-01 18:51:34 +01001255
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001256 rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
1257 &rb->dma);
1258 if (!rb->base) {
1259 dev_err(&intf->dev, "out of memory "
1260 "(read bufs usb_alloc_coherent)\n");
1261 goto alloc_fail6;
1262 }
Johan Hovold088c64f2011-03-25 11:06:02 +01001263 rb->index = i;
1264 rb->instance = acm;
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001265
Johan Hovold088c64f2011-03-25 11:06:02 +01001266 urb = usb_alloc_urb(0, GFP_KERNEL);
1267 if (!urb) {
Johan Hovold255ab562011-03-22 11:12:13 +01001268 dev_err(&intf->dev,
Alan Cox6e47e062009-06-11 12:37:06 +01001269 "out of memory (read urbs usb_alloc_urb)\n");
Axel Linc2572b72010-05-31 08:04:47 +08001270 goto alloc_fail6;
David Kubicek61a87ad2005-11-01 18:51:34 +01001271 }
Johan Hovold088c64f2011-03-25 11:06:02 +01001272 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1273 urb->transfer_dma = rb->dma;
1274 if (acm->is_int_ep) {
1275 usb_fill_int_urb(urb, acm->dev,
1276 acm->rx_endpoint,
1277 rb->base,
1278 acm->readsize,
1279 acm_read_bulk_callback, rb,
1280 acm->bInterval);
1281 } else {
1282 usb_fill_bulk_urb(urb, acm->dev,
1283 acm->rx_endpoint,
1284 rb->base,
1285 acm->readsize,
1286 acm_read_bulk_callback, rb);
1287 }
David Kubicek61a87ad2005-11-01 18:51:34 +01001288
Johan Hovold088c64f2011-03-25 11:06:02 +01001289 acm->read_urbs[i] = urb;
1290 __set_bit(i, &acm->read_urbs_free);
David Kubicek61a87ad2005-11-01 18:51:34 +01001291 }
Alan Cox6e47e062009-06-11 12:37:06 +01001292 for (i = 0; i < ACM_NW; i++) {
David Engrafe4cf3aa2008-03-20 10:01:34 +01001293 struct acm_wb *snd = &(acm->wb[i]);
1294
Alan Cox6e47e062009-06-11 12:37:06 +01001295 snd->urb = usb_alloc_urb(0, GFP_KERNEL);
1296 if (snd->urb == NULL) {
Johan Hovold255ab562011-03-22 11:12:13 +01001297 dev_err(&intf->dev,
Johan Hovold59d7fec2011-03-22 11:12:12 +01001298 "out of memory (write urbs usb_alloc_urb)\n");
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001299 goto alloc_fail7;
David Engrafe4cf3aa2008-03-20 10:01:34 +01001300 }
1301
Arseniy Lartsev5186ffe2009-07-01 16:27:26 +04001302 if (usb_endpoint_xfer_int(epwrite))
1303 usb_fill_int_urb(snd->urb, usb_dev,
Ming Leie83863d2012-10-16 21:21:21 +08001304 usb_sndintpipe(usb_dev, epwrite->bEndpointAddress),
Arseniy Lartsev5186ffe2009-07-01 16:27:26 +04001305 NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval);
1306 else
1307 usb_fill_bulk_urb(snd->urb, usb_dev,
1308 usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
1309 NULL, acm->writesize, acm_write_bulk, snd);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001310 snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1311 snd->instance = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 }
1313
Alan Cox6e47e062009-06-11 12:37:06 +01001314 usb_set_intfdata(intf, acm);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001315
1316 i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
1317 if (i < 0)
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001318 goto alloc_fail7;
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001319
1320 if (cfd) { /* export the country data */
1321 acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
1322 if (!acm->country_codes)
1323 goto skip_countries;
1324 acm->country_code_size = cfd->bLength - 4;
Alan Cox6e47e062009-06-11 12:37:06 +01001325 memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0,
1326 cfd->bLength - 4);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001327 acm->country_rel_date = cfd->iCountryCodeRelDate;
1328
1329 i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
1330 if (i < 0) {
1331 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
Alan Cox6e47e062009-06-11 12:37:06 +01001337 i = device_create_file(&intf->dev,
1338 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001339 if (i < 0) {
Axel Linc2572b72010-05-31 08:04:47 +08001340 device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001341 kfree(acm->country_codes);
Julia Lawalle7c8e862011-12-23 14:02:55 +01001342 acm->country_codes = NULL;
1343 acm->country_code_size = 0;
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001344 goto skip_countries;
1345 }
1346 }
1347
1348skip_countries:
Alan Cox6e47e062009-06-11 12:37:06 +01001349 usb_fill_int_urb(acm->ctrlurb, usb_dev,
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001350 usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
1351 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
1352 /* works around buggy devices */
1353 epctrl->bInterval ? epctrl->bInterval : 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1355 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
1356
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
1358
1359 acm_set_control(acm, acm->ctrlout);
1360
1361 acm->line.dwDTERate = cpu_to_le32(9600);
1362 acm->line.bDataBits = 8;
1363 acm_set_line(acm, &acm->line);
1364
1365 usb_driver_claim_interface(&acm_driver, data_interface, acm);
David Brownell672c4e12008-08-06 18:41:12 -07001366 usb_set_intfdata(data_interface, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001368 usb_get_intf(control_interface);
1369 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001371 return 0;
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001372alloc_fail7:
David Engrafe4cf3aa2008-03-20 10:01:34 +01001373 for (i = 0; i < ACM_NW; i++)
1374 usb_free_urb(acm->wb[i].urb);
Axel Linc2572b72010-05-31 08:04:47 +08001375alloc_fail6:
Oliver Neukum86478942006-05-13 22:50:47 +02001376 for (i = 0; i < num_rx_buf; i++)
Johan Hovold088c64f2011-03-25 11:06:02 +01001377 usb_free_urb(acm->read_urbs[i]);
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001378 acm_read_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 usb_free_urb(acm->ctrlurb);
1380alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001381 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382alloc_fail4:
Daniel Mack997ea582010-04-12 13:17:25 +02001383 usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384alloc_fail2:
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001385 acm_release_minor(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 kfree(acm);
1387alloc_fail:
1388 return -ENOMEM;
1389}
1390
Oliver Neukum1365baf2007-10-12 17:24:28 +02001391static void stop_data_traffic(struct acm *acm)
1392{
1393 int i;
Johan Hovolda5cc7ef2011-03-22 11:12:15 +01001394
1395 dev_dbg(&acm->control->dev, "%s\n", __func__);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001396
Oliver Neukum1365baf2007-10-12 17:24:28 +02001397 usb_kill_urb(acm->ctrlurb);
Alan Cox6e47e062009-06-11 12:37:06 +01001398 for (i = 0; i < ACM_NW; i++)
David Engrafe4cf3aa2008-03-20 10:01:34 +01001399 usb_kill_urb(acm->wb[i].urb);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001400 for (i = 0; i < acm->rx_buflimit; i++)
Johan Hovold088c64f2011-03-25 11:06:02 +01001401 usb_kill_urb(acm->read_urbs[i]);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001402
1403 cancel_work_sync(&acm->work);
1404}
1405
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406static void acm_disconnect(struct usb_interface *intf)
1407{
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001408 struct acm *acm = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 struct usb_device *usb_dev = interface_to_usbdev(intf);
Alan Cox10077d42009-06-11 12:36:09 +01001410 struct tty_struct *tty;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001411 int i;
1412
1413 dev_dbg(&intf->dev, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
David Brownell672c4e12008-08-06 18:41:12 -07001415 /* sibling interface is already cleaning up */
1416 if (!acm)
Oliver Neukum86067eea2006-01-08 12:39:13 +01001417 return;
David Brownell672c4e12008-08-06 18:41:12 -07001418
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001419 mutex_lock(&acm->mutex);
1420 acm->disconnected = true;
Alan Cox6e47e062009-06-11 12:37:06 +01001421 if (acm->country_codes) {
Alan Stern74da5d62007-08-02 13:29:10 -04001422 device_remove_file(&acm->control->dev,
1423 &dev_attr_wCountryCodes);
1424 device_remove_file(&acm->control->dev,
1425 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001426 }
Alan Stern74da5d62007-08-02 13:29:10 -04001427 device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
Oliver Neukum86067eea2006-01-08 12:39:13 +01001428 usb_set_intfdata(acm->control, NULL);
1429 usb_set_intfdata(acm->data, NULL);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001430 mutex_unlock(&acm->mutex);
1431
1432 tty = tty_port_tty_get(&acm->port);
1433 if (tty) {
1434 tty_vhangup(tty);
1435 tty_kref_put(tty);
1436 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437
Oliver Neukum1365baf2007-10-12 17:24:28 +02001438 stop_data_traffic(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439
Johan Hovold10a00e32013-03-19 09:21:06 +01001440 tty_unregister_device(acm_tty_driver, acm->minor);
1441
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001442 usb_free_urb(acm->ctrlurb);
1443 for (i = 0; i < ACM_NW; i++)
1444 usb_free_urb(acm->wb[i].urb);
1445 for (i = 0; i < acm->rx_buflimit; i++)
1446 usb_free_urb(acm->read_urbs[i]);
Oliver Neukum884b6002005-04-21 21:28:02 +02001447 acm_write_buffers_free(acm);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001448 usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Oliver Neukum830f4022008-06-25 14:17:16 +02001449 acm_read_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001451 if (!acm->combined_interfaces)
1452 usb_driver_release_interface(&acm_driver, intf == acm->control ?
Oliver Neukum830f4022008-06-25 14:17:16 +02001453 acm->data : acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001455 tty_port_put(&acm->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456}
1457
Oliver Neukum35758582008-07-01 19:10:08 +02001458#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001459static int acm_suspend(struct usb_interface *intf, pm_message_t message)
1460{
1461 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001462 int cnt;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001463
Oliver Neukum11ea8592008-06-20 11:25:57 +02001464 spin_lock_irq(&acm->read_lock);
1465 spin_lock(&acm->write_lock);
Johan Hovoldbe7978b2014-05-26 19:23:36 +02001466 if (PMSG_IS_AUTO(message)) {
1467 if (acm->transmitting) {
1468 spin_unlock(&acm->write_lock);
1469 spin_unlock_irq(&acm->read_lock);
1470 return -EBUSY;
1471 }
1472 }
Oliver Neukum11ea8592008-06-20 11:25:57 +02001473 cnt = acm->susp_count++;
1474 spin_unlock(&acm->write_lock);
1475 spin_unlock_irq(&acm->read_lock);
1476
1477 if (cnt)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001478 return 0;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001479
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001480 if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
Oliver Neukum1365baf2007-10-12 17:24:28 +02001481 stop_data_traffic(acm);
1482
Oliver Neukum1365baf2007-10-12 17:24:28 +02001483 return 0;
1484}
1485
1486static int acm_resume(struct usb_interface *intf)
1487{
1488 struct acm *acm = usb_get_intfdata(intf);
Johan Hovold21ffba32014-05-26 19:23:38 +02001489 struct urb *urb;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001490 int rv = 0;
1491
Oliver Neukum11ea8592008-06-20 11:25:57 +02001492 spin_lock_irq(&acm->read_lock);
Johan Hovold97e72c42014-05-26 19:23:37 +02001493 spin_lock(&acm->write_lock);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001494
Johan Hovold97e72c42014-05-26 19:23:37 +02001495 if (--acm->susp_count)
1496 goto out;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001497
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001498 if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
Johan Hovold97e72c42014-05-26 19:23:37 +02001499 rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);
Oliver Neukum97d35f92009-12-16 17:05:57 +01001500
Johan Hovold21ffba32014-05-26 19:23:38 +02001501 for (;;) {
1502 urb = usb_get_from_anchor(&acm->delayed);
1503 if (!urb)
1504 break;
1505
1506 acm_start_wb(acm, urb->context);
Oliver Neukum97d35f92009-12-16 17:05:57 +01001507 }
1508
1509 /*
1510 * delayed error checking because we must
1511 * do the write path at all cost
1512 */
Oliver Neukum1365baf2007-10-12 17:24:28 +02001513 if (rv < 0)
Johan Hovold97e72c42014-05-26 19:23:37 +02001514 goto out;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001515
Johan Hovold97e72c42014-05-26 19:23:37 +02001516 rv = acm_submit_read_urbs(acm, GFP_ATOMIC);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001517 }
Johan Hovold97e72c42014-05-26 19:23:37 +02001518out:
1519 spin_unlock(&acm->write_lock);
1520 spin_unlock_irq(&acm->read_lock);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001521
Oliver Neukum1365baf2007-10-12 17:24:28 +02001522 return rv;
1523}
Oliver Neukum35758582008-07-01 19:10:08 +02001524
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001525static int acm_reset_resume(struct usb_interface *intf)
1526{
1527 struct acm *acm = usb_get_intfdata(intf);
1528 struct tty_struct *tty;
1529
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001530 if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001531 tty = tty_port_tty_get(&acm->port);
1532 if (tty) {
1533 tty_hangup(tty);
1534 tty_kref_put(tty);
1535 }
1536 }
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001537
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001538 return acm_resume(intf);
1539}
1540
Oliver Neukum35758582008-07-01 19:10:08 +02001541#endif /* CONFIG_PM */
Adrian Taylorc1479a92009-11-19 10:35:33 +00001542
1543#define NOKIA_PCSUITE_ACM_INFO(x) \
1544 USB_DEVICE_AND_INTERFACE_INFO(0x0421, x, \
1545 USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \
1546 USB_CDC_ACM_PROTO_VENDOR)
1547
Toby Gray4035e452010-09-01 16:01:19 +01001548#define SAMSUNG_PCSUITE_ACM_INFO(x) \
1549 USB_DEVICE_AND_INTERFACE_INFO(0x04e7, x, \
1550 USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \
1551 USB_CDC_ACM_PROTO_VENDOR)
1552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553/*
1554 * USB driver structure.
1555 */
1556
Németh Márton6ef48522010-01-10 15:33:45 +01001557static const struct usb_device_id acm_ids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 /* quirky and broken devices */
David Cluytensbd73e382013-12-03 14:18:57 +01001559 { USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */
1560 .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1562 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1563 },
Andrey Arapovb0e2a702007-07-04 17:11:42 +02001564 { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
1565 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1566 },
Andrew Lunn0f9c7b42008-12-23 17:31:23 +01001567 { USB_DEVICE(0x0e8d, 0x3329), /* MediaTek Inc GPS */
1568 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1569 },
Masahito Omote8753e652005-07-29 12:17:25 -07001570 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1571 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1572 },
Chris Malley91a9c922006-10-03 10:08:28 +01001573 { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
1574 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1575 },
Alan Cox7abcf202009-04-06 17:35:01 +01001576 { USB_DEVICE(0x0ace, 0x1602), /* ZyDAS 56K USB MODEM */
1577 .driver_info = SINGLE_RX_URB,
1578 },
Oliver Neukum86478942006-05-13 22:50:47 +02001579 { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
1580 .driver_info = SINGLE_RX_URB, /* firmware bug */
1581 },
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001582 { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
1583 .driver_info = SINGLE_RX_URB, /* firmware bug */
1584 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001585 { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
1586 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1587 },
Iain McFarlane6149ed52008-05-04 00:13:49 +01001588 { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */
1589 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1590 },
Eric Sandeenc8fd2c32008-08-14 08:25:40 -05001591 { USB_DEVICE(0x0572, 0x1321), /* Conexant USB MODEM CX93010 */
1592 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1593 },
Alan Coxc89c60e2009-01-11 19:53:10 +00001594 { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */
1595 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1596 },
Xiao Kaijiancab98a02009-05-08 00:48:23 +08001597 { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */
1598 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1599 },
Dmitriy Taychenachev155df652009-02-25 12:36:51 +08001600 { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
1601 },
Krzysztof Hałasa6abff5d2011-12-12 14:51:00 +01001602 /* Motorola H24 HSPA module: */
1603 { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */
Michael Ulbrichtb08f08b2014-03-25 10:34:18 +01001604 { USB_DEVICE(0x22b8, 0x2d92), /* modem + diagnostics */
1605 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1606 },
1607 { USB_DEVICE(0x22b8, 0x2d93), /* modem + AT port */
1608 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1609 },
1610 { USB_DEVICE(0x22b8, 0x2d95), /* modem + AT port + diagnostics */
1611 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1612 },
1613 { USB_DEVICE(0x22b8, 0x2d96), /* modem + NMEA */
1614 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1615 },
1616 { USB_DEVICE(0x22b8, 0x2d97), /* modem + diagnostics + NMEA */
1617 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1618 },
1619 { USB_DEVICE(0x22b8, 0x2d99), /* modem + AT port + NMEA */
1620 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1621 },
1622 { USB_DEVICE(0x22b8, 0x2d9a), /* modem + AT port + diagnostics + NMEA */
1623 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1624 },
Krzysztof Hałasa6abff5d2011-12-12 14:51:00 +01001625
Adam Richterc332b4e2009-02-18 16:17:15 -08001626 { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */
1627 .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on
1628 data interface instead of
1629 communications interface.
1630 Maybe we should define a new
1631 quirk for this. */
1632 },
Jean-Christian de Rivaz52538352012-10-10 12:49:02 +00001633 { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */
1634 .driver_info = NO_UNION_NORMAL,
1635 },
Denis N Ladinb756d752012-12-26 18:29:44 +05001636 { USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */
1637 .driver_info = NO_UNION_NORMAL,
1638 },
Kir Kolyshkin1f17c502009-05-28 20:33:58 +04001639 { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */
1640 .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
1641 },
Russ Nelsonc3baa192010-04-21 23:07:03 -04001642 { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */
1643 .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
1644 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001645
Adrian Taylorc1479a92009-11-19 10:35:33 +00001646 /* Nokia S60 phones expose two ACM channels. The first is
1647 * a modem and is picked up by the standard AT-command
1648 * information below. The second is 'vendor-specific' but
1649 * is treated as a serial device at the S60 end, so we want
1650 * to expose it on Linux too. */
1651 { NOKIA_PCSUITE_ACM_INFO(0x042D), }, /* Nokia 3250 */
1652 { NOKIA_PCSUITE_ACM_INFO(0x04D8), }, /* Nokia 5500 Sport */
1653 { NOKIA_PCSUITE_ACM_INFO(0x04C9), }, /* Nokia E50 */
1654 { NOKIA_PCSUITE_ACM_INFO(0x0419), }, /* Nokia E60 */
1655 { NOKIA_PCSUITE_ACM_INFO(0x044D), }, /* Nokia E61 */
1656 { NOKIA_PCSUITE_ACM_INFO(0x0001), }, /* Nokia E61i */
1657 { NOKIA_PCSUITE_ACM_INFO(0x0475), }, /* Nokia E62 */
1658 { NOKIA_PCSUITE_ACM_INFO(0x0508), }, /* Nokia E65 */
1659 { NOKIA_PCSUITE_ACM_INFO(0x0418), }, /* Nokia E70 */
1660 { NOKIA_PCSUITE_ACM_INFO(0x0425), }, /* Nokia N71 */
1661 { NOKIA_PCSUITE_ACM_INFO(0x0486), }, /* Nokia N73 */
1662 { NOKIA_PCSUITE_ACM_INFO(0x04DF), }, /* Nokia N75 */
1663 { NOKIA_PCSUITE_ACM_INFO(0x000e), }, /* Nokia N77 */
1664 { NOKIA_PCSUITE_ACM_INFO(0x0445), }, /* Nokia N80 */
1665 { NOKIA_PCSUITE_ACM_INFO(0x042F), }, /* Nokia N91 & N91 8GB */
1666 { NOKIA_PCSUITE_ACM_INFO(0x048E), }, /* Nokia N92 */
1667 { NOKIA_PCSUITE_ACM_INFO(0x0420), }, /* Nokia N93 */
1668 { NOKIA_PCSUITE_ACM_INFO(0x04E6), }, /* Nokia N93i */
1669 { NOKIA_PCSUITE_ACM_INFO(0x04B2), }, /* Nokia 5700 XpressMusic */
1670 { NOKIA_PCSUITE_ACM_INFO(0x0134), }, /* Nokia 6110 Navigator (China) */
1671 { NOKIA_PCSUITE_ACM_INFO(0x046E), }, /* Nokia 6110 Navigator */
1672 { NOKIA_PCSUITE_ACM_INFO(0x002f), }, /* Nokia 6120 classic & */
1673 { NOKIA_PCSUITE_ACM_INFO(0x0088), }, /* Nokia 6121 classic */
1674 { NOKIA_PCSUITE_ACM_INFO(0x00fc), }, /* Nokia 6124 classic */
1675 { NOKIA_PCSUITE_ACM_INFO(0x0042), }, /* Nokia E51 */
1676 { NOKIA_PCSUITE_ACM_INFO(0x00b0), }, /* Nokia E66 */
1677 { NOKIA_PCSUITE_ACM_INFO(0x00ab), }, /* Nokia E71 */
1678 { NOKIA_PCSUITE_ACM_INFO(0x0481), }, /* Nokia N76 */
1679 { NOKIA_PCSUITE_ACM_INFO(0x0007), }, /* Nokia N81 & N81 8GB */
1680 { NOKIA_PCSUITE_ACM_INFO(0x0071), }, /* Nokia N82 */
1681 { NOKIA_PCSUITE_ACM_INFO(0x04F0), }, /* Nokia N95 & N95-3 NAM */
1682 { NOKIA_PCSUITE_ACM_INFO(0x0070), }, /* Nokia N95 8GB */
1683 { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */
1684 { NOKIA_PCSUITE_ACM_INFO(0x0099), }, /* Nokia 6210 Navigator, RM-367 */
1685 { NOKIA_PCSUITE_ACM_INFO(0x0128), }, /* Nokia 6210 Navigator, RM-419 */
1686 { NOKIA_PCSUITE_ACM_INFO(0x008f), }, /* Nokia 6220 Classic */
1687 { NOKIA_PCSUITE_ACM_INFO(0x00a0), }, /* Nokia 6650 */
1688 { NOKIA_PCSUITE_ACM_INFO(0x007b), }, /* Nokia N78 */
1689 { NOKIA_PCSUITE_ACM_INFO(0x0094), }, /* Nokia N85 */
1690 { NOKIA_PCSUITE_ACM_INFO(0x003a), }, /* Nokia N96 & N96-3 */
1691 { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */
1692 { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */
1693 { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */
Przemo Firszt83a4eae2010-06-28 21:29:34 +01001694 { NOKIA_PCSUITE_ACM_INFO(0x02e3), }, /* Nokia 5230, RM-588 */
Toby Gray4035e452010-09-01 16:01:19 +01001695 { NOKIA_PCSUITE_ACM_INFO(0x0178), }, /* Nokia E63 */
1696 { NOKIA_PCSUITE_ACM_INFO(0x010e), }, /* Nokia E75 */
1697 { NOKIA_PCSUITE_ACM_INFO(0x02d9), }, /* Nokia 6760 Slide */
1698 { NOKIA_PCSUITE_ACM_INFO(0x01d0), }, /* Nokia E52 */
1699 { NOKIA_PCSUITE_ACM_INFO(0x0223), }, /* Nokia E72 */
1700 { NOKIA_PCSUITE_ACM_INFO(0x0275), }, /* Nokia X6 */
1701 { NOKIA_PCSUITE_ACM_INFO(0x026c), }, /* Nokia N97 Mini */
1702 { NOKIA_PCSUITE_ACM_INFO(0x0154), }, /* Nokia 5800 XpressMusic */
1703 { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */
1704 { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */
Arvid Ephraim Picciani721d92f2011-01-25 15:58:40 +01001705 { NOKIA_PCSUITE_ACM_INFO(0x0302), }, /* Nokia N8 */
Toby Gray4061fde2011-06-06 14:52:48 +01001706 { NOKIA_PCSUITE_ACM_INFO(0x0335), }, /* Nokia E7 */
1707 { NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */
Toby Gray4035e452010-09-01 16:01:19 +01001708 { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */
Adrian Taylorc1479a92009-11-19 10:35:33 +00001709
Denis Pershin65e52f42011-09-04 17:37:21 +07001710 /* Support for Owen devices */
1711 { USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */
1712
Adrian Taylorc1479a92009-11-19 10:35:33 +00001713 /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
1714
Julian Calaby7c5d8c32010-01-05 23:57:46 +11001715 /* Support Lego NXT using pbLua firmware */
Julian Calabyce126642010-01-05 23:58:20 +11001716 { USB_DEVICE(0x0694, 0xff00),
1717 .driver_info = NOT_A_MODEM,
Otavio Salvador7893afc2010-09-26 23:35:05 -03001718 },
Julian Calaby7c5d8c32010-01-05 23:57:46 +11001719
Erik Slagterfd5054c2011-05-11 12:06:55 +02001720 /* Support for Droids MuIn LCD */
1721 { USB_DEVICE(0x04d8, 0x000b),
1722 .driver_info = NO_DATA_INTERFACE,
1723 },
1724
Philippe Corbes5b239f02010-08-31 19:31:32 +02001725 /* control interfaces without any protocol set */
1726 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1727 USB_CDC_PROTO_NONE) },
1728
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 /* control interfaces with various AT-command sets */
1730 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1731 USB_CDC_ACM_PROTO_AT_V25TER) },
1732 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1733 USB_CDC_ACM_PROTO_AT_PCCA101) },
1734 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1735 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1736 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1737 USB_CDC_ACM_PROTO_AT_GSM) },
1738 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
Alan Cox6e47e062009-06-11 12:37:06 +01001739 USB_CDC_ACM_PROTO_AT_3G) },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1741 USB_CDC_ACM_PROTO_AT_CDMA) },
1742
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 { }
1744};
1745
Alan Cox6e47e062009-06-11 12:37:06 +01001746MODULE_DEVICE_TABLE(usb, acm_ids);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747
1748static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 .name = "cdc_acm",
1750 .probe = acm_probe,
1751 .disconnect = acm_disconnect,
Oliver Neukum35758582008-07-01 19:10:08 +02001752#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001753 .suspend = acm_suspend,
1754 .resume = acm_resume,
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001755 .reset_resume = acm_reset_resume,
Oliver Neukum35758582008-07-01 19:10:08 +02001756#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 .id_table = acm_ids,
Oliver Neukum35758582008-07-01 19:10:08 +02001758#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001759 .supports_autosuspend = 1,
Oliver Neukum35758582008-07-01 19:10:08 +02001760#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761};
1762
1763/*
1764 * TTY driver structures.
1765 */
1766
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001767static const struct tty_operations acm_ops = {
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001768 .install = acm_tty_install,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 .open = acm_tty_open,
1770 .close = acm_tty_close,
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001771 .cleanup = acm_tty_cleanup,
Alan Cox10077d42009-06-11 12:36:09 +01001772 .hangup = acm_tty_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 .write = acm_tty_write,
1774 .write_room = acm_tty_write_room,
1775 .ioctl = acm_tty_ioctl,
1776 .throttle = acm_tty_throttle,
1777 .unthrottle = acm_tty_unthrottle,
1778 .chars_in_buffer = acm_tty_chars_in_buffer,
1779 .break_ctl = acm_tty_break_ctl,
1780 .set_termios = acm_tty_set_termios,
1781 .tiocmget = acm_tty_tiocmget,
1782 .tiocmset = acm_tty_tiocmset,
1783};
1784
1785/*
1786 * Init / exit.
1787 */
1788
1789static int __init acm_init(void)
1790{
1791 int retval;
1792 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1793 if (!acm_tty_driver)
1794 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 acm_tty_driver->driver_name = "acm",
1796 acm_tty_driver->name = "ttyACM",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 acm_tty_driver->major = ACM_TTY_MAJOR,
1798 acm_tty_driver->minor_start = 0,
1799 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1800 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001801 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 acm_tty_driver->init_termios = tty_std_termios;
Alan Cox6e47e062009-06-11 12:37:06 +01001803 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD |
1804 HUPCL | CLOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 tty_set_operations(acm_tty_driver, &acm_ops);
1806
1807 retval = tty_register_driver(acm_tty_driver);
1808 if (retval) {
1809 put_tty_driver(acm_tty_driver);
1810 return retval;
1811 }
1812
1813 retval = usb_register(&acm_driver);
1814 if (retval) {
1815 tty_unregister_driver(acm_tty_driver);
1816 put_tty_driver(acm_tty_driver);
1817 return retval;
1818 }
1819
Johan Hovolda2c7b932011-03-22 11:12:18 +01001820 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821
1822 return 0;
1823}
1824
1825static void __exit acm_exit(void)
1826{
1827 usb_deregister(&acm_driver);
1828 tty_unregister_driver(acm_tty_driver);
1829 put_tty_driver(acm_tty_driver);
1830}
1831
1832module_init(acm_init);
1833module_exit(acm_exit);
1834
Alan Cox6e47e062009-06-11 12:37:06 +01001835MODULE_AUTHOR(DRIVER_AUTHOR);
1836MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837MODULE_LICENSE("GPL");
Scott James Remnante766aeb2009-04-06 17:33:18 +01001838MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR);