blob: 7ffd5f55738d95cc1f61200c5f6d53674ab351c2 [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;
Johan Hovold8fd20d52014-05-26 19:23:44 +0200545 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100547 dev_dbg(&acm->control->dev, "%s\n", __func__);
548
Oliver Neukum1365baf2007-10-12 17:24:28 +0200549 mutex_lock(&acm->mutex);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800550 if (acm->disconnected)
551 goto disconnected;
552
553 retval = usb_autopm_get_interface(acm->control);
554 if (retval)
555 goto error_get_interface;
556
557 /*
558 * FIXME: Why do we need this? Allocating 64K of physically contiguous
559 * memory is really nasty...
560 */
561 set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
562 acm->control->needs_remote_wakeup = 1;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 acm->ctrlurb->dev = acm->dev;
565 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100566 dev_err(&acm->control->dev,
567 "%s - usb_submit_urb(ctrl irq) failed\n", __func__);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800568 goto error_submit_urb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 }
570
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800571 acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS;
572 if (acm_set_control(acm, acm->ctrlout) < 0 &&
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100573 (acm->ctrl_caps & USB_CDC_CAP_LINE))
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800574 goto error_set_control;
Alan Cox10077d42009-06-11 12:36:09 +0100575
Oliver Neukum11ea8592008-06-20 11:25:57 +0200576 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
Otto Meta9cc2d462012-06-06 18:46:21 +0200578 /*
579 * Unthrottle device in case the TTY was closed while throttled.
580 */
581 spin_lock_irq(&acm->read_lock);
582 acm->throttled = 0;
583 acm->throttle_req = 0;
584 spin_unlock_irq(&acm->read_lock);
585
Johan Hovold088c64f2011-03-25 11:06:02 +0100586 if (acm_submit_read_urbs(acm, GFP_KERNEL))
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800587 goto error_submit_read_urbs;
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100588
Oliver Neukum1365baf2007-10-12 17:24:28 +0200589 mutex_unlock(&acm->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800591 return 0;
592
593error_submit_read_urbs:
Johan Hovold8fd20d52014-05-26 19:23:44 +0200594 for (i = 0; i < acm->rx_buflimit; i++)
595 usb_kill_urb(acm->read_urbs[i]);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800596 acm->ctrlout = 0;
597 acm_set_control(acm, acm->ctrlout);
598error_set_control:
599 usb_kill_urb(acm->ctrlurb);
600error_submit_urb:
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100601 usb_autopm_put_interface(acm->control);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800602error_get_interface:
603disconnected:
604 mutex_unlock(&acm->mutex);
605 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606}
607
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800608static void acm_port_destruct(struct tty_port *port)
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700609{
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800610 struct acm *acm = container_of(port, struct acm, port);
611
612 dev_dbg(&acm->control->dev, "%s\n", __func__);
David Kubicek61a87ad2005-11-01 18:51:34 +0100613
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800614 acm_release_minor(acm);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700615 usb_put_intf(acm->control);
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100616 kfree(acm->country_codes);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700617 kfree(acm);
618}
619
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800620static void acm_port_shutdown(struct tty_port *port)
Alan Cox10077d42009-06-11 12:36:09 +0100621{
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800622 struct acm *acm = container_of(port, struct acm, port);
Johan Hovold21ffba32014-05-26 19:23:38 +0200623 struct urb *urb;
624 struct acm_wb *wb;
Johan Hovolddab54c92011-03-22 11:12:21 +0100625 int i;
626
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800627 dev_dbg(&acm->control->dev, "%s\n", __func__);
628
629 mutex_lock(&acm->mutex);
630 if (!acm->disconnected) {
Alan Cox10077d42009-06-11 12:36:09 +0100631 usb_autopm_get_interface(acm->control);
632 acm_set_control(acm, acm->ctrlout = 0);
Johan Hovold21ffba32014-05-26 19:23:38 +0200633
634 for (;;) {
635 urb = usb_get_from_anchor(&acm->delayed);
636 if (!urb)
637 break;
638 wb = urb->context;
639 wb->use = 0;
640 usb_autopm_put_interface_async(acm->control);
641 }
642
Alan Cox10077d42009-06-11 12:36:09 +0100643 usb_kill_urb(acm->ctrlurb);
644 for (i = 0; i < ACM_NW; i++)
645 usb_kill_urb(acm->wb[i].urb);
Johan Hovolddab54c92011-03-22 11:12:21 +0100646 for (i = 0; i < acm->rx_buflimit; i++)
Johan Hovold088c64f2011-03-25 11:06:02 +0100647 usb_kill_urb(acm->read_urbs[i]);
Alan Cox10077d42009-06-11 12:36:09 +0100648 acm->control->needs_remote_wakeup = 0;
649 usb_autopm_put_interface(acm->control);
650 }
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800651 mutex_unlock(&acm->mutex);
652}
653
654static void acm_tty_cleanup(struct tty_struct *tty)
655{
656 struct acm *acm = tty->driver_data;
657 dev_dbg(&acm->control->dev, "%s\n", __func__);
658 tty_port_put(&acm->port);
Alan Cox10077d42009-06-11 12:36:09 +0100659}
660
661static void acm_tty_hangup(struct tty_struct *tty)
662{
663 struct acm *acm = tty->driver_data;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800664 dev_dbg(&acm->control->dev, "%s\n", __func__);
Alan Cox10077d42009-06-11 12:36:09 +0100665 tty_port_hangup(&acm->port);
Alan Cox10077d42009-06-11 12:36:09 +0100666}
667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668static void acm_tty_close(struct tty_struct *tty, struct file *filp)
669{
670 struct acm *acm = tty->driver_data;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800671 dev_dbg(&acm->control->dev, "%s\n", __func__);
672 tty_port_close(&acm->port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673}
674
Alan Cox6e47e062009-06-11 12:37:06 +0100675static int acm_tty_write(struct tty_struct *tty,
676 const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677{
678 struct acm *acm = tty->driver_data;
679 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200680 unsigned long flags;
681 int wbn;
682 struct acm_wb *wb;
683
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 if (!count)
685 return 0;
686
Johan Hovold5e9e75f2011-03-22 11:12:17 +0100687 dev_vdbg(&acm->data->dev, "%s - count %d\n", __func__, count);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100688
Oliver Neukum884b6002005-04-21 21:28:02 +0200689 spin_lock_irqsave(&acm->write_lock, flags);
Alan Cox6e47e062009-06-11 12:37:06 +0100690 wbn = acm_wb_alloc(acm);
691 if (wbn < 0) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200692 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200693 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200695 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
Oliver Neukum884b6002005-04-21 21:28:02 +0200697 count = (count > acm->writesize) ? acm->writesize : count;
Johan Hovold5e9e75f2011-03-22 11:12:17 +0100698 dev_vdbg(&acm->data->dev, "%s - write %d\n", __func__, count);
Oliver Neukum884b6002005-04-21 21:28:02 +0200699 memcpy(wb->buf, buf, count);
700 wb->len = count;
701 spin_unlock_irqrestore(&acm->write_lock, flags);
702
Alan Cox6e47e062009-06-11 12:37:06 +0100703 stat = acm_write_start(acm, wbn);
704 if (stat < 0)
Oliver Neukum884b6002005-04-21 21:28:02 +0200705 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 return count;
707}
708
709static int acm_tty_write_room(struct tty_struct *tty)
710{
711 struct acm *acm = tty->driver_data;
Oliver Neukum884b6002005-04-21 21:28:02 +0200712 /*
713 * Do not let the line discipline to know that we have a reserve,
714 * or it might get too enthusiastic.
715 */
David Brownell934da462008-08-06 18:44:12 -0700716 return acm_wb_is_avail(acm) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717}
718
719static int acm_tty_chars_in_buffer(struct tty_struct *tty)
720{
721 struct acm *acm = tty->driver_data;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800722 /*
723 * if the device was unplugged then any remaining characters fell out
724 * of the connector ;)
725 */
726 if (acm->disconnected)
Alan Cox23198fd2009-07-20 16:05:27 +0100727 return 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200728 /*
729 * This is inaccurate (overcounts), but it works.
730 */
Oliver Neukum86478942006-05-13 22:50:47 +0200731 return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732}
733
734static void acm_tty_throttle(struct tty_struct *tty)
735{
736 struct acm *acm = tty->driver_data;
Johan Hovold088c64f2011-03-25 11:06:02 +0100737
Johan Hovold088c64f2011-03-25 11:06:02 +0100738 spin_lock_irq(&acm->read_lock);
739 acm->throttle_req = 1;
740 spin_unlock_irq(&acm->read_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741}
742
743static void acm_tty_unthrottle(struct tty_struct *tty)
744{
745 struct acm *acm = tty->driver_data;
Johan Hovold088c64f2011-03-25 11:06:02 +0100746 unsigned int was_throttled;
747
Johan Hovold088c64f2011-03-25 11:06:02 +0100748 spin_lock_irq(&acm->read_lock);
749 was_throttled = acm->throttled;
750 acm->throttled = 0;
751 acm->throttle_req = 0;
752 spin_unlock_irq(&acm->read_lock);
753
754 if (was_throttled)
755 acm_submit_read_urbs(acm, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756}
757
Alan Cox9e989662008-07-22 11:18:03 +0100758static int acm_tty_break_ctl(struct tty_struct *tty, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
760 struct acm *acm = tty->driver_data;
Alan Cox9e989662008-07-22 11:18:03 +0100761 int retval;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800762
Alan Cox9e989662008-07-22 11:18:03 +0100763 retval = acm_send_break(acm, state ? 0xffff : 0);
764 if (retval < 0)
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100765 dev_dbg(&acm->control->dev, "%s - send break failed\n",
766 __func__);
Alan Cox9e989662008-07-22 11:18:03 +0100767 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768}
769
Alan Cox60b33c12011-02-14 16:26:14 +0000770static int acm_tty_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771{
772 struct acm *acm = tty->driver_data;
773
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
775 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
776 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
777 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
778 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
779 TIOCM_CTS;
780}
781
Alan Cox20b9d172011-02-14 16:26:50 +0000782static int acm_tty_tiocmset(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 unsigned int set, unsigned int clear)
784{
785 struct acm *acm = tty->driver_data;
786 unsigned int newctrl;
787
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 newctrl = acm->ctrlout;
Alan Cox6e47e062009-06-11 12:37:06 +0100789 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
790 (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
791 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
792 (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794 newctrl = (newctrl & ~clear) | set;
795
796 if (acm->ctrlout == newctrl)
797 return 0;
798 return acm_set_control(acm, acm->ctrlout = newctrl);
799}
800
Oliver Neukum18c75722012-02-17 17:21:24 -0500801static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
802{
803 struct serial_struct tmp;
804
805 if (!info)
806 return -EINVAL;
807
808 memset(&tmp, 0, sizeof(tmp));
809 tmp.flags = ASYNC_LOW_LATENCY;
810 tmp.xmit_fifo_size = acm->writesize;
811 tmp.baud_base = le32_to_cpu(acm->line.dwDTERate);
Dan Williams1229a832012-11-08 12:47:41 -0600812 tmp.close_delay = acm->port.close_delay / 10;
813 tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
814 ASYNC_CLOSING_WAIT_NONE :
815 acm->port.closing_wait / 10;
Oliver Neukum18c75722012-02-17 17:21:24 -0500816
817 if (copy_to_user(info, &tmp, sizeof(tmp)))
818 return -EFAULT;
819 else
820 return 0;
821}
822
Dan Williams1229a832012-11-08 12:47:41 -0600823static int set_serial_info(struct acm *acm,
824 struct serial_struct __user *newinfo)
825{
826 struct serial_struct new_serial;
827 unsigned int closing_wait, close_delay;
828 int retval = 0;
829
830 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
831 return -EFAULT;
832
833 close_delay = new_serial.close_delay * 10;
834 closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
835 ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
836
837 mutex_lock(&acm->port.mutex);
838
839 if (!capable(CAP_SYS_ADMIN)) {
840 if ((close_delay != acm->port.close_delay) ||
841 (closing_wait != acm->port.closing_wait))
842 retval = -EPERM;
843 else
844 retval = -EOPNOTSUPP;
845 } else {
846 acm->port.close_delay = close_delay;
847 acm->port.closing_wait = closing_wait;
848 }
849
850 mutex_unlock(&acm->port.mutex);
851 return retval;
852}
853
Alan Cox6caa76b2011-02-14 16:27:22 +0000854static int acm_tty_ioctl(struct tty_struct *tty,
Alan Cox6e47e062009-06-11 12:37:06 +0100855 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856{
Oliver Neukum18c75722012-02-17 17:21:24 -0500857 struct acm *acm = tty->driver_data;
858 int rv = -ENOIOCTLCMD;
859
860 switch (cmd) {
861 case TIOCGSERIAL: /* gets serial port data */
862 rv = get_serial_info(acm, (struct serial_struct __user *) arg);
863 break;
Dan Williams1229a832012-11-08 12:47:41 -0600864 case TIOCSSERIAL:
865 rv = set_serial_info(acm, (struct serial_struct __user *) arg);
866 break;
Oliver Neukum18c75722012-02-17 17:21:24 -0500867 }
868
869 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870}
871
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100872static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 0, 50, 75, 110, 134, 150, 200, 300, 600,
874 1200, 1800, 2400, 4800, 9600, 19200, 38400,
875 57600, 115200, 230400, 460800, 500000, 576000,
876 921600, 1000000, 1152000, 1500000, 2000000,
877 2500000, 3000000, 3500000, 4000000
878};
879
Alan Cox6e47e062009-06-11 12:37:06 +0100880static void acm_tty_set_termios(struct tty_struct *tty,
881 struct ktermios *termios_old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882{
883 struct acm *acm = tty->driver_data;
Alan Cox606d0992006-12-08 02:38:45 -0800884 struct ktermios *termios = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 struct usb_cdc_line_coding newline;
886 int newctrl = acm->ctrlout;
887
Alan Cox9b80fee2009-09-19 13:13:23 -0700888 newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
890 newline.bParityType = termios->c_cflag & PARENB ?
Alan Cox6e47e062009-06-11 12:37:06 +0100891 (termios->c_cflag & PARODD ? 1 : 2) +
892 (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
Nicolas Boullisa5204462012-10-16 00:06:23 +0200893 switch (termios->c_cflag & CSIZE) {
894 case CS5:
895 newline.bDataBits = 5;
896 break;
897 case CS6:
898 newline.bDataBits = 6;
899 break;
900 case CS7:
901 newline.bDataBits = 7;
902 break;
903 case CS8:
904 default:
905 newline.bDataBits = 8;
906 break;
907 }
Alan Cox6e47e062009-06-11 12:37:06 +0100908 /* FIXME: Needs to clear unsupported bits in the termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
910
911 if (!newline.dwDTERate) {
912 newline.dwDTERate = acm->line.dwDTERate;
913 newctrl &= ~ACM_CTRL_DTR;
Alan Cox6e47e062009-06-11 12:37:06 +0100914 } else
915 newctrl |= ACM_CTRL_DTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
917 if (newctrl != acm->ctrlout)
918 acm_set_control(acm, acm->ctrlout = newctrl);
919
920 if (memcmp(&acm->line, &newline, sizeof newline)) {
921 memcpy(&acm->line, &newline, sizeof newline);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100922 dev_dbg(&acm->control->dev, "%s - set line: %d %d %d %d\n",
923 __func__,
924 le32_to_cpu(newline.dwDTERate),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 newline.bCharFormat, newline.bParityType,
926 newline.bDataBits);
927 acm_set_line(acm, &acm->line);
928 }
929}
930
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800931static const struct tty_port_operations acm_port_ops = {
932 .shutdown = acm_port_shutdown,
933 .activate = acm_port_activate,
934 .destruct = acm_port_destruct,
935};
936
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937/*
938 * USB probe and disconnect routines.
939 */
940
Oliver Neukum830f4022008-06-25 14:17:16 +0200941/* Little helpers: write/read buffers free */
Oliver Neukum884b6002005-04-21 21:28:02 +0200942static void acm_write_buffers_free(struct acm *acm)
943{
944 int i;
945 struct acm_wb *wb;
Oliver Neukuma496c642008-10-21 10:39:04 +0200946 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
Oliver Neukum884b6002005-04-21 21:28:02 +0200947
Alan Cox6e47e062009-06-11 12:37:06 +0100948 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++)
Daniel Mack997ea582010-04-12 13:17:25 +0200949 usb_free_coherent(usb_dev, acm->writesize, wb->buf, wb->dmah);
Oliver Neukum884b6002005-04-21 21:28:02 +0200950}
951
Oliver Neukum830f4022008-06-25 14:17:16 +0200952static void acm_read_buffers_free(struct acm *acm)
953{
954 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
Johan Hovolddab54c92011-03-22 11:12:21 +0100955 int i;
Oliver Neukum830f4022008-06-25 14:17:16 +0200956
Johan Hovolddab54c92011-03-22 11:12:21 +0100957 for (i = 0; i < acm->rx_buflimit; i++)
Daniel Mack997ea582010-04-12 13:17:25 +0200958 usb_free_coherent(usb_dev, acm->readsize,
Johan Hovold088c64f2011-03-25 11:06:02 +0100959 acm->read_buffers[i].base, acm->read_buffers[i].dma);
Oliver Neukum830f4022008-06-25 14:17:16 +0200960}
961
Oliver Neukum884b6002005-04-21 21:28:02 +0200962/* Little helper: write buffers allocate */
963static int acm_write_buffers_alloc(struct acm *acm)
964{
965 int i;
966 struct acm_wb *wb;
967
Oliver Neukum86478942006-05-13 22:50:47 +0200968 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Daniel Mack997ea582010-04-12 13:17:25 +0200969 wb->buf = usb_alloc_coherent(acm->dev, acm->writesize, GFP_KERNEL,
Oliver Neukum884b6002005-04-21 21:28:02 +0200970 &wb->dmah);
971 if (!wb->buf) {
972 while (i != 0) {
973 --i;
974 --wb;
Daniel Mack997ea582010-04-12 13:17:25 +0200975 usb_free_coherent(acm->dev, acm->writesize,
Oliver Neukum884b6002005-04-21 21:28:02 +0200976 wb->buf, wb->dmah);
977 }
978 return -ENOMEM;
979 }
980 }
981 return 0;
982}
983
Alan Cox10077d42009-06-11 12:36:09 +0100984static int acm_probe(struct usb_interface *intf,
985 const struct usb_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986{
987 struct usb_cdc_union_desc *union_header = NULL;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100988 struct usb_cdc_country_functional_desc *cfd = NULL;
David Brownellc6dbf552008-04-13 14:00:44 -0700989 unsigned char *buffer = intf->altsetting->extra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 int buflen = intf->altsetting->extralen;
991 struct usb_interface *control_interface;
992 struct usb_interface *data_interface;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +0200993 struct usb_endpoint_descriptor *epctrl = NULL;
994 struct usb_endpoint_descriptor *epread = NULL;
995 struct usb_endpoint_descriptor *epwrite = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 struct usb_device *usb_dev = interface_to_usbdev(intf);
997 struct acm *acm;
998 int minor;
Alan Cox6e47e062009-06-11 12:37:06 +0100999 int ctrlsize, readsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 u8 *buf;
1001 u8 ac_management_function = 0;
1002 u8 call_management_function = 0;
1003 int call_interface_num = -1;
Erik Slagterfd5054c2011-05-11 12:06:55 +02001004 int data_interface_num = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 unsigned long quirks;
Oliver Neukum86478942006-05-13 22:50:47 +02001006 int num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +01001007 int i;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001008 int combined_interfaces = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
Oliver Neukum86478942006-05-13 22:50:47 +02001010 /* normal quirks */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 quirks = (unsigned long)id->driver_info;
Oliver Neukum86478942006-05-13 22:50:47 +02001012 num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
1013
1014 /* handle quirks deadly to normal probing*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 if (quirks == NO_UNION_NORMAL) {
1016 data_interface = usb_ifnum_to_if(usb_dev, 1);
1017 control_interface = usb_ifnum_to_if(usb_dev, 0);
1018 goto skip_normal_probe;
1019 }
Alan Cox6e47e062009-06-11 12:37:06 +01001020
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 /* normal probing*/
1022 if (!buffer) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001023 dev_err(&intf->dev, "Weird descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 return -EINVAL;
1025 }
1026
1027 if (!buflen) {
Toby Gray577045c2010-09-02 10:46:20 +01001028 if (intf->cur_altsetting->endpoint &&
1029 intf->cur_altsetting->endpoint->extralen &&
Alan Cox6e47e062009-06-11 12:37:06 +01001030 intf->cur_altsetting->endpoint->extra) {
1031 dev_dbg(&intf->dev,
1032 "Seeking extra descriptors on endpoint\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 buflen = intf->cur_altsetting->endpoint->extralen;
1034 buffer = intf->cur_altsetting->endpoint->extra;
1035 } else {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001036 dev_err(&intf->dev,
1037 "Zero length descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return -EINVAL;
1039 }
1040 }
1041
1042 while (buflen > 0) {
Alan Cox6e47e062009-06-11 12:37:06 +01001043 if (buffer[1] != USB_DT_CS_INTERFACE) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001044 dev_err(&intf->dev, "skipping garbage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 goto next_desc;
1046 }
1047
Alan Cox6e47e062009-06-11 12:37:06 +01001048 switch (buffer[2]) {
1049 case USB_CDC_UNION_TYPE: /* we've found it */
1050 if (union_header) {
1051 dev_err(&intf->dev, "More than one "
1052 "union descriptor, skipping ...\n");
1053 goto next_desc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 }
Alan Cox6e47e062009-06-11 12:37:06 +01001055 union_header = (struct usb_cdc_union_desc *)buffer;
1056 break;
1057 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
1058 cfd = (struct usb_cdc_country_functional_desc *)buffer;
1059 break;
1060 case USB_CDC_HEADER_TYPE: /* maybe check version */
1061 break; /* for now we ignore it */
1062 case USB_CDC_ACM_TYPE:
1063 ac_management_function = buffer[3];
1064 break;
1065 case USB_CDC_CALL_MANAGEMENT_TYPE:
1066 call_management_function = buffer[3];
1067 call_interface_num = buffer[4];
Julian Calabyce126642010-01-05 23:58:20 +11001068 if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
Alan Cox6e47e062009-06-11 12:37:06 +01001069 dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
1070 break;
1071 default:
1072 /* there are LOTS more CDC descriptors that
1073 * could legitimately be found here.
1074 */
1075 dev_dbg(&intf->dev, "Ignoring descriptor: "
1076 "type %02x, length %d\n",
1077 buffer[2], buffer[0]);
1078 break;
1079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080next_desc:
1081 buflen -= buffer[0];
1082 buffer += buffer[0];
1083 }
1084
1085 if (!union_header) {
1086 if (call_interface_num > 0) {
Alan Cox6e47e062009-06-11 12:37:06 +01001087 dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
Erik Slagterfd5054c2011-05-11 12:06:55 +02001088 /* quirks for Droids MuIn LCD */
1089 if (quirks & NO_DATA_INTERFACE)
1090 data_interface = usb_ifnum_to_if(usb_dev, 0);
1091 else
1092 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 control_interface = intf;
1094 } else {
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001095 if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
1096 dev_dbg(&intf->dev,"No union descriptor, giving up\n");
1097 return -ENODEV;
1098 } else {
1099 dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n");
1100 combined_interfaces = 1;
1101 control_interface = data_interface = intf;
1102 goto look_for_collapsed_interface;
1103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 }
1105 } else {
1106 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
1107 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
1108 if (!control_interface || !data_interface) {
Alan Cox6e47e062009-06-11 12:37:06 +01001109 dev_dbg(&intf->dev, "no interfaces\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 return -ENODEV;
1111 }
1112 }
Alan Cox6e47e062009-06-11 12:37:06 +01001113
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 if (data_interface_num != call_interface_num)
Alan Cox6e47e062009-06-11 12:37:06 +01001115 dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001117 if (control_interface == data_interface) {
1118 /* some broken devices designed for windows work this way */
1119 dev_warn(&intf->dev,"Control and data interfaces are not separated!\n");
1120 combined_interfaces = 1;
1121 /* a popular other OS doesn't use it */
1122 quirks |= NO_CAP_LINE;
1123 if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) {
1124 dev_err(&intf->dev, "This needs exactly 3 endpoints\n");
1125 return -EINVAL;
1126 }
1127look_for_collapsed_interface:
1128 for (i = 0; i < 3; i++) {
1129 struct usb_endpoint_descriptor *ep;
1130 ep = &data_interface->cur_altsetting->endpoint[i].desc;
1131
1132 if (usb_endpoint_is_int_in(ep))
1133 epctrl = ep;
1134 else if (usb_endpoint_is_bulk_out(ep))
1135 epwrite = ep;
1136 else if (usb_endpoint_is_bulk_in(ep))
1137 epread = ep;
1138 else
1139 return -EINVAL;
1140 }
1141 if (!epctrl || !epread || !epwrite)
1142 return -ENODEV;
1143 else
1144 goto made_compressed_probe;
1145 }
1146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147skip_normal_probe:
1148
1149 /*workaround for switched interfaces */
Alan Cox6e47e062009-06-11 12:37:06 +01001150 if (data_interface->cur_altsetting->desc.bInterfaceClass
1151 != CDC_DATA_INTERFACE_TYPE) {
1152 if (control_interface->cur_altsetting->desc.bInterfaceClass
1153 == CDC_DATA_INTERFACE_TYPE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 struct usb_interface *t;
Alan Cox6e47e062009-06-11 12:37:06 +01001155 dev_dbg(&intf->dev,
1156 "Your device has switched interfaces.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 t = control_interface;
1158 control_interface = data_interface;
1159 data_interface = t;
1160 } else {
1161 return -EINVAL;
1162 }
1163 }
Alan Stern74da5d62007-08-02 13:29:10 -04001164
1165 /* Accept probe requests only for the control interface */
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001166 if (!combined_interfaces && intf != control_interface)
Alan Stern74da5d62007-08-02 13:29:10 -04001167 return -ENODEV;
Alan Cox6e47e062009-06-11 12:37:06 +01001168
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001169 if (!combined_interfaces && usb_interface_claimed(data_interface)) {
1170 /* valid in this context */
Alan Cox6e47e062009-06-11 12:37:06 +01001171 dev_dbg(&intf->dev, "The data interface isn't available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 return -EBUSY;
1173 }
1174
1175
Sven Schnellea9959bb2012-08-17 21:43:43 +02001176 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2 ||
1177 control_interface->cur_altsetting->desc.bNumEndpoints == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 return -EINVAL;
1179
1180 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
1181 epread = &data_interface->cur_altsetting->endpoint[0].desc;
1182 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
1183
1184
1185 /* workaround for switched endpoints */
Luiz Fernando N. Capitulino45aea702006-10-26 13:02:48 -03001186 if (!usb_endpoint_dir_in(epread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 /* descriptors are swapped */
1188 struct usb_endpoint_descriptor *t;
Alan Cox6e47e062009-06-11 12:37:06 +01001189 dev_dbg(&intf->dev,
1190 "The data interface has switched endpoints\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 t = epread;
1192 epread = epwrite;
1193 epwrite = t;
1194 }
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001195made_compressed_probe:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +01001196 dev_dbg(&intf->dev, "interfaces are valid\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197
Alan Cox6e47e062009-06-11 12:37:06 +01001198 acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
1199 if (acm == NULL) {
Johan Hovold255ab562011-03-22 11:12:13 +01001200 dev_err(&intf->dev, "out of memory (acm kzalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 goto alloc_fail;
1202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001204 minor = acm_alloc_minor(acm);
1205 if (minor == ACM_TTY_MINORS) {
1206 dev_err(&intf->dev, "no more free acm devices\n");
1207 kfree(acm);
1208 return -ENODEV;
1209 }
1210
Kuninori Morimoto29cc8892011-08-23 03:12:03 -07001211 ctrlsize = usb_endpoint_maxp(epctrl);
1212 readsize = usb_endpoint_maxp(epread) *
Alan Cox6e47e062009-06-11 12:37:06 +01001213 (quirks == SINGLE_RX_URB ? 1 : 2);
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001214 acm->combined_interfaces = combined_interfaces;
Kuninori Morimoto29cc8892011-08-23 03:12:03 -07001215 acm->writesize = usb_endpoint_maxp(epwrite) * 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 acm->control = control_interface;
1217 acm->data = data_interface;
1218 acm->minor = minor;
1219 acm->dev = usb_dev;
1220 acm->ctrl_caps = ac_management_function;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001221 if (quirks & NO_CAP_LINE)
1222 acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 acm->ctrlsize = ctrlsize;
1224 acm->readsize = readsize;
Oliver Neukum86478942006-05-13 22:50:47 +02001225 acm->rx_buflimit = num_rx_buf;
David Howellsc4028952006-11-22 14:57:56 +00001226 INIT_WORK(&acm->work, acm_softint);
Oliver Neukum884b6002005-04-21 21:28:02 +02001227 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +01001228 spin_lock_init(&acm->read_lock);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001229 mutex_init(&acm->mutex);
David Kubicek61a87ad2005-11-01 18:51:34 +01001230 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Oliver Neukumcf7fdd52009-08-04 23:52:09 +02001231 acm->is_int_ep = usb_endpoint_xfer_int(epread);
1232 if (acm->is_int_ep)
1233 acm->bInterval = epread->bInterval;
Alan Cox739e0282009-06-11 12:27:50 +01001234 tty_port_init(&acm->port);
1235 acm->port.ops = &acm_port_ops;
Johan Hovold21ffba32014-05-26 19:23:38 +02001236 init_usb_anchor(&acm->delayed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
Daniel Mack997ea582010-04-12 13:17:25 +02001238 buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 if (!buf) {
Johan Hovold255ab562011-03-22 11:12:13 +01001240 dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 goto alloc_fail2;
1242 }
1243 acm->ctrl_buffer = buf;
1244
Oliver Neukum884b6002005-04-21 21:28:02 +02001245 if (acm_write_buffers_alloc(acm) < 0) {
Johan Hovold255ab562011-03-22 11:12:13 +01001246 dev_err(&intf->dev, "out of memory (write buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 goto alloc_fail4;
1248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
1251 if (!acm->ctrlurb) {
Johan Hovold255ab562011-03-22 11:12:13 +01001252 dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 goto alloc_fail5;
1254 }
Oliver Neukum86478942006-05-13 22:50:47 +02001255 for (i = 0; i < num_rx_buf; i++) {
Johan Hovold088c64f2011-03-25 11:06:02 +01001256 struct acm_rb *rb = &(acm->read_buffers[i]);
1257 struct urb *urb;
David Kubicek61a87ad2005-11-01 18:51:34 +01001258
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001259 rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
1260 &rb->dma);
1261 if (!rb->base) {
1262 dev_err(&intf->dev, "out of memory "
1263 "(read bufs usb_alloc_coherent)\n");
1264 goto alloc_fail6;
1265 }
Johan Hovold088c64f2011-03-25 11:06:02 +01001266 rb->index = i;
1267 rb->instance = acm;
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001268
Johan Hovold088c64f2011-03-25 11:06:02 +01001269 urb = usb_alloc_urb(0, GFP_KERNEL);
1270 if (!urb) {
Johan Hovold255ab562011-03-22 11:12:13 +01001271 dev_err(&intf->dev,
Alan Cox6e47e062009-06-11 12:37:06 +01001272 "out of memory (read urbs usb_alloc_urb)\n");
Axel Linc2572b72010-05-31 08:04:47 +08001273 goto alloc_fail6;
David Kubicek61a87ad2005-11-01 18:51:34 +01001274 }
Johan Hovold088c64f2011-03-25 11:06:02 +01001275 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1276 urb->transfer_dma = rb->dma;
1277 if (acm->is_int_ep) {
1278 usb_fill_int_urb(urb, acm->dev,
1279 acm->rx_endpoint,
1280 rb->base,
1281 acm->readsize,
1282 acm_read_bulk_callback, rb,
1283 acm->bInterval);
1284 } else {
1285 usb_fill_bulk_urb(urb, acm->dev,
1286 acm->rx_endpoint,
1287 rb->base,
1288 acm->readsize,
1289 acm_read_bulk_callback, rb);
1290 }
David Kubicek61a87ad2005-11-01 18:51:34 +01001291
Johan Hovold088c64f2011-03-25 11:06:02 +01001292 acm->read_urbs[i] = urb;
1293 __set_bit(i, &acm->read_urbs_free);
David Kubicek61a87ad2005-11-01 18:51:34 +01001294 }
Alan Cox6e47e062009-06-11 12:37:06 +01001295 for (i = 0; i < ACM_NW; i++) {
David Engrafe4cf3aa2008-03-20 10:01:34 +01001296 struct acm_wb *snd = &(acm->wb[i]);
1297
Alan Cox6e47e062009-06-11 12:37:06 +01001298 snd->urb = usb_alloc_urb(0, GFP_KERNEL);
1299 if (snd->urb == NULL) {
Johan Hovold255ab562011-03-22 11:12:13 +01001300 dev_err(&intf->dev,
Johan Hovold59d7fec2011-03-22 11:12:12 +01001301 "out of memory (write urbs usb_alloc_urb)\n");
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001302 goto alloc_fail7;
David Engrafe4cf3aa2008-03-20 10:01:34 +01001303 }
1304
Arseniy Lartsev5186ffe2009-07-01 16:27:26 +04001305 if (usb_endpoint_xfer_int(epwrite))
1306 usb_fill_int_urb(snd->urb, usb_dev,
Ming Leie83863d2012-10-16 21:21:21 +08001307 usb_sndintpipe(usb_dev, epwrite->bEndpointAddress),
Arseniy Lartsev5186ffe2009-07-01 16:27:26 +04001308 NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval);
1309 else
1310 usb_fill_bulk_urb(snd->urb, usb_dev,
1311 usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
1312 NULL, acm->writesize, acm_write_bulk, snd);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001313 snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1314 snd->instance = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 }
1316
Alan Cox6e47e062009-06-11 12:37:06 +01001317 usb_set_intfdata(intf, acm);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001318
1319 i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
1320 if (i < 0)
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001321 goto alloc_fail7;
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001322
1323 if (cfd) { /* export the country data */
1324 acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
1325 if (!acm->country_codes)
1326 goto skip_countries;
1327 acm->country_code_size = cfd->bLength - 4;
Alan Cox6e47e062009-06-11 12:37:06 +01001328 memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0,
1329 cfd->bLength - 4);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001330 acm->country_rel_date = cfd->iCountryCodeRelDate;
1331
1332 i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
1333 if (i < 0) {
1334 kfree(acm->country_codes);
Julia Lawalle7c8e862011-12-23 14:02:55 +01001335 acm->country_codes = NULL;
1336 acm->country_code_size = 0;
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001337 goto skip_countries;
1338 }
1339
Alan Cox6e47e062009-06-11 12:37:06 +01001340 i = device_create_file(&intf->dev,
1341 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001342 if (i < 0) {
Axel Linc2572b72010-05-31 08:04:47 +08001343 device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001344 kfree(acm->country_codes);
Julia Lawalle7c8e862011-12-23 14:02:55 +01001345 acm->country_codes = NULL;
1346 acm->country_code_size = 0;
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001347 goto skip_countries;
1348 }
1349 }
1350
1351skip_countries:
Alan Cox6e47e062009-06-11 12:37:06 +01001352 usb_fill_int_urb(acm->ctrlurb, usb_dev,
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001353 usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
1354 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
1355 /* works around buggy devices */
1356 epctrl->bInterval ? epctrl->bInterval : 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1358 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
1359
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
1361
1362 acm_set_control(acm, acm->ctrlout);
1363
1364 acm->line.dwDTERate = cpu_to_le32(9600);
1365 acm->line.bDataBits = 8;
1366 acm_set_line(acm, &acm->line);
1367
1368 usb_driver_claim_interface(&acm_driver, data_interface, acm);
David Brownell672c4e12008-08-06 18:41:12 -07001369 usb_set_intfdata(data_interface, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001371 usb_get_intf(control_interface);
1372 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001374 return 0;
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001375alloc_fail7:
David Engrafe4cf3aa2008-03-20 10:01:34 +01001376 for (i = 0; i < ACM_NW; i++)
1377 usb_free_urb(acm->wb[i].urb);
Axel Linc2572b72010-05-31 08:04:47 +08001378alloc_fail6:
Oliver Neukum86478942006-05-13 22:50:47 +02001379 for (i = 0; i < num_rx_buf; i++)
Johan Hovold088c64f2011-03-25 11:06:02 +01001380 usb_free_urb(acm->read_urbs[i]);
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001381 acm_read_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 usb_free_urb(acm->ctrlurb);
1383alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001384 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385alloc_fail4:
Daniel Mack997ea582010-04-12 13:17:25 +02001386 usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387alloc_fail2:
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001388 acm_release_minor(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 kfree(acm);
1390alloc_fail:
1391 return -ENOMEM;
1392}
1393
Oliver Neukum1365baf2007-10-12 17:24:28 +02001394static void stop_data_traffic(struct acm *acm)
1395{
1396 int i;
Johan Hovolda5cc7ef2011-03-22 11:12:15 +01001397
1398 dev_dbg(&acm->control->dev, "%s\n", __func__);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001399
Oliver Neukum1365baf2007-10-12 17:24:28 +02001400 usb_kill_urb(acm->ctrlurb);
Alan Cox6e47e062009-06-11 12:37:06 +01001401 for (i = 0; i < ACM_NW; i++)
David Engrafe4cf3aa2008-03-20 10:01:34 +01001402 usb_kill_urb(acm->wb[i].urb);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001403 for (i = 0; i < acm->rx_buflimit; i++)
Johan Hovold088c64f2011-03-25 11:06:02 +01001404 usb_kill_urb(acm->read_urbs[i]);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001405
1406 cancel_work_sync(&acm->work);
1407}
1408
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409static void acm_disconnect(struct usb_interface *intf)
1410{
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001411 struct acm *acm = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 struct usb_device *usb_dev = interface_to_usbdev(intf);
Alan Cox10077d42009-06-11 12:36:09 +01001413 struct tty_struct *tty;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001414 int i;
1415
1416 dev_dbg(&intf->dev, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
David Brownell672c4e12008-08-06 18:41:12 -07001418 /* sibling interface is already cleaning up */
1419 if (!acm)
Oliver Neukum86067eea2006-01-08 12:39:13 +01001420 return;
David Brownell672c4e12008-08-06 18:41:12 -07001421
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001422 mutex_lock(&acm->mutex);
1423 acm->disconnected = true;
Alan Cox6e47e062009-06-11 12:37:06 +01001424 if (acm->country_codes) {
Alan Stern74da5d62007-08-02 13:29:10 -04001425 device_remove_file(&acm->control->dev,
1426 &dev_attr_wCountryCodes);
1427 device_remove_file(&acm->control->dev,
1428 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001429 }
Alan Stern74da5d62007-08-02 13:29:10 -04001430 device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
Oliver Neukum86067eea2006-01-08 12:39:13 +01001431 usb_set_intfdata(acm->control, NULL);
1432 usb_set_intfdata(acm->data, NULL);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001433 mutex_unlock(&acm->mutex);
1434
1435 tty = tty_port_tty_get(&acm->port);
1436 if (tty) {
1437 tty_vhangup(tty);
1438 tty_kref_put(tty);
1439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440
Oliver Neukum1365baf2007-10-12 17:24:28 +02001441 stop_data_traffic(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442
Johan Hovold10a00e32013-03-19 09:21:06 +01001443 tty_unregister_device(acm_tty_driver, acm->minor);
1444
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001445 usb_free_urb(acm->ctrlurb);
1446 for (i = 0; i < ACM_NW; i++)
1447 usb_free_urb(acm->wb[i].urb);
1448 for (i = 0; i < acm->rx_buflimit; i++)
1449 usb_free_urb(acm->read_urbs[i]);
Oliver Neukum884b6002005-04-21 21:28:02 +02001450 acm_write_buffers_free(acm);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001451 usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Oliver Neukum830f4022008-06-25 14:17:16 +02001452 acm_read_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001454 if (!acm->combined_interfaces)
1455 usb_driver_release_interface(&acm_driver, intf == acm->control ?
Oliver Neukum830f4022008-06-25 14:17:16 +02001456 acm->data : acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001458 tty_port_put(&acm->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459}
1460
Oliver Neukum35758582008-07-01 19:10:08 +02001461#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001462static int acm_suspend(struct usb_interface *intf, pm_message_t message)
1463{
1464 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001465 int cnt;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001466
Oliver Neukum11ea8592008-06-20 11:25:57 +02001467 spin_lock_irq(&acm->read_lock);
1468 spin_lock(&acm->write_lock);
Johan Hovoldbe7978b2014-05-26 19:23:36 +02001469 if (PMSG_IS_AUTO(message)) {
1470 if (acm->transmitting) {
1471 spin_unlock(&acm->write_lock);
1472 spin_unlock_irq(&acm->read_lock);
1473 return -EBUSY;
1474 }
1475 }
Oliver Neukum11ea8592008-06-20 11:25:57 +02001476 cnt = acm->susp_count++;
1477 spin_unlock(&acm->write_lock);
1478 spin_unlock_irq(&acm->read_lock);
1479
1480 if (cnt)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001481 return 0;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001482
Johan Hovold181614f2014-05-26 19:23:40 +02001483 stop_data_traffic(acm);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001484
Oliver Neukum1365baf2007-10-12 17:24:28 +02001485 return 0;
1486}
1487
1488static int acm_resume(struct usb_interface *intf)
1489{
1490 struct acm *acm = usb_get_intfdata(intf);
Johan Hovold21ffba32014-05-26 19:23:38 +02001491 struct urb *urb;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001492 int rv = 0;
1493
Oliver Neukum11ea8592008-06-20 11:25:57 +02001494 spin_lock_irq(&acm->read_lock);
Johan Hovold97e72c42014-05-26 19:23:37 +02001495 spin_lock(&acm->write_lock);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001496
Johan Hovold97e72c42014-05-26 19:23:37 +02001497 if (--acm->susp_count)
1498 goto out;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001499
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001500 if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
Johan Hovold97e72c42014-05-26 19:23:37 +02001501 rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);
Oliver Neukum97d35f92009-12-16 17:05:57 +01001502
Johan Hovold21ffba32014-05-26 19:23:38 +02001503 for (;;) {
1504 urb = usb_get_from_anchor(&acm->delayed);
1505 if (!urb)
1506 break;
1507
1508 acm_start_wb(acm, urb->context);
Oliver Neukum97d35f92009-12-16 17:05:57 +01001509 }
1510
1511 /*
1512 * delayed error checking because we must
1513 * do the write path at all cost
1514 */
Oliver Neukum1365baf2007-10-12 17:24:28 +02001515 if (rv < 0)
Johan Hovold97e72c42014-05-26 19:23:37 +02001516 goto out;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001517
Johan Hovold97e72c42014-05-26 19:23:37 +02001518 rv = acm_submit_read_urbs(acm, GFP_ATOMIC);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001519 }
Johan Hovold97e72c42014-05-26 19:23:37 +02001520out:
1521 spin_unlock(&acm->write_lock);
1522 spin_unlock_irq(&acm->read_lock);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001523
Oliver Neukum1365baf2007-10-12 17:24:28 +02001524 return rv;
1525}
Oliver Neukum35758582008-07-01 19:10:08 +02001526
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001527static int acm_reset_resume(struct usb_interface *intf)
1528{
1529 struct acm *acm = usb_get_intfdata(intf);
1530 struct tty_struct *tty;
1531
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001532 if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001533 tty = tty_port_tty_get(&acm->port);
1534 if (tty) {
1535 tty_hangup(tty);
1536 tty_kref_put(tty);
1537 }
1538 }
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001539
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001540 return acm_resume(intf);
1541}
1542
Oliver Neukum35758582008-07-01 19:10:08 +02001543#endif /* CONFIG_PM */
Adrian Taylorc1479a92009-11-19 10:35:33 +00001544
1545#define NOKIA_PCSUITE_ACM_INFO(x) \
1546 USB_DEVICE_AND_INTERFACE_INFO(0x0421, x, \
1547 USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \
1548 USB_CDC_ACM_PROTO_VENDOR)
1549
Toby Gray4035e452010-09-01 16:01:19 +01001550#define SAMSUNG_PCSUITE_ACM_INFO(x) \
1551 USB_DEVICE_AND_INTERFACE_INFO(0x04e7, x, \
1552 USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \
1553 USB_CDC_ACM_PROTO_VENDOR)
1554
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555/*
1556 * USB driver structure.
1557 */
1558
Németh Márton6ef48522010-01-10 15:33:45 +01001559static const struct usb_device_id acm_ids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 /* quirky and broken devices */
David Cluytensbd73e382013-12-03 14:18:57 +01001561 { USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */
1562 .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1564 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1565 },
Andrey Arapovb0e2a702007-07-04 17:11:42 +02001566 { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
1567 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1568 },
Andrew Lunn0f9c7b42008-12-23 17:31:23 +01001569 { USB_DEVICE(0x0e8d, 0x3329), /* MediaTek Inc GPS */
1570 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1571 },
Masahito Omote8753e652005-07-29 12:17:25 -07001572 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1573 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1574 },
Chris Malley91a9c922006-10-03 10:08:28 +01001575 { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
1576 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1577 },
Alan Cox7abcf202009-04-06 17:35:01 +01001578 { USB_DEVICE(0x0ace, 0x1602), /* ZyDAS 56K USB MODEM */
1579 .driver_info = SINGLE_RX_URB,
1580 },
Oliver Neukum86478942006-05-13 22:50:47 +02001581 { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
1582 .driver_info = SINGLE_RX_URB, /* firmware bug */
1583 },
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001584 { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
1585 .driver_info = SINGLE_RX_URB, /* firmware bug */
1586 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001587 { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
1588 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1589 },
Iain McFarlane6149ed52008-05-04 00:13:49 +01001590 { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */
1591 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1592 },
Eric Sandeenc8fd2c32008-08-14 08:25:40 -05001593 { USB_DEVICE(0x0572, 0x1321), /* Conexant USB MODEM CX93010 */
1594 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1595 },
Alan Coxc89c60e2009-01-11 19:53:10 +00001596 { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */
1597 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1598 },
Xiao Kaijiancab98a02009-05-08 00:48:23 +08001599 { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */
1600 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1601 },
Dmitriy Taychenachev155df652009-02-25 12:36:51 +08001602 { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
1603 },
Krzysztof Hałasa6abff5d2011-12-12 14:51:00 +01001604 /* Motorola H24 HSPA module: */
1605 { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */
Michael Ulbrichtb08f08b2014-03-25 10:34:18 +01001606 { USB_DEVICE(0x22b8, 0x2d92), /* modem + diagnostics */
1607 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1608 },
1609 { USB_DEVICE(0x22b8, 0x2d93), /* modem + AT port */
1610 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1611 },
1612 { USB_DEVICE(0x22b8, 0x2d95), /* modem + AT port + diagnostics */
1613 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1614 },
1615 { USB_DEVICE(0x22b8, 0x2d96), /* modem + NMEA */
1616 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1617 },
1618 { USB_DEVICE(0x22b8, 0x2d97), /* modem + diagnostics + NMEA */
1619 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1620 },
1621 { USB_DEVICE(0x22b8, 0x2d99), /* modem + AT port + NMEA */
1622 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1623 },
1624 { USB_DEVICE(0x22b8, 0x2d9a), /* modem + AT port + diagnostics + NMEA */
1625 .driver_info = NO_UNION_NORMAL, /* handle only modem interface */
1626 },
Krzysztof Hałasa6abff5d2011-12-12 14:51:00 +01001627
Adam Richterc332b4e2009-02-18 16:17:15 -08001628 { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */
1629 .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on
1630 data interface instead of
1631 communications interface.
1632 Maybe we should define a new
1633 quirk for this. */
1634 },
Jean-Christian de Rivaz52538352012-10-10 12:49:02 +00001635 { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */
1636 .driver_info = NO_UNION_NORMAL,
1637 },
Denis N Ladinb756d752012-12-26 18:29:44 +05001638 { USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */
1639 .driver_info = NO_UNION_NORMAL,
1640 },
Kir Kolyshkin1f17c502009-05-28 20:33:58 +04001641 { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */
1642 .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
1643 },
Russ Nelsonc3baa192010-04-21 23:07:03 -04001644 { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */
1645 .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
1646 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001647
Adrian Taylorc1479a92009-11-19 10:35:33 +00001648 /* Nokia S60 phones expose two ACM channels. The first is
1649 * a modem and is picked up by the standard AT-command
1650 * information below. The second is 'vendor-specific' but
1651 * is treated as a serial device at the S60 end, so we want
1652 * to expose it on Linux too. */
1653 { NOKIA_PCSUITE_ACM_INFO(0x042D), }, /* Nokia 3250 */
1654 { NOKIA_PCSUITE_ACM_INFO(0x04D8), }, /* Nokia 5500 Sport */
1655 { NOKIA_PCSUITE_ACM_INFO(0x04C9), }, /* Nokia E50 */
1656 { NOKIA_PCSUITE_ACM_INFO(0x0419), }, /* Nokia E60 */
1657 { NOKIA_PCSUITE_ACM_INFO(0x044D), }, /* Nokia E61 */
1658 { NOKIA_PCSUITE_ACM_INFO(0x0001), }, /* Nokia E61i */
1659 { NOKIA_PCSUITE_ACM_INFO(0x0475), }, /* Nokia E62 */
1660 { NOKIA_PCSUITE_ACM_INFO(0x0508), }, /* Nokia E65 */
1661 { NOKIA_PCSUITE_ACM_INFO(0x0418), }, /* Nokia E70 */
1662 { NOKIA_PCSUITE_ACM_INFO(0x0425), }, /* Nokia N71 */
1663 { NOKIA_PCSUITE_ACM_INFO(0x0486), }, /* Nokia N73 */
1664 { NOKIA_PCSUITE_ACM_INFO(0x04DF), }, /* Nokia N75 */
1665 { NOKIA_PCSUITE_ACM_INFO(0x000e), }, /* Nokia N77 */
1666 { NOKIA_PCSUITE_ACM_INFO(0x0445), }, /* Nokia N80 */
1667 { NOKIA_PCSUITE_ACM_INFO(0x042F), }, /* Nokia N91 & N91 8GB */
1668 { NOKIA_PCSUITE_ACM_INFO(0x048E), }, /* Nokia N92 */
1669 { NOKIA_PCSUITE_ACM_INFO(0x0420), }, /* Nokia N93 */
1670 { NOKIA_PCSUITE_ACM_INFO(0x04E6), }, /* Nokia N93i */
1671 { NOKIA_PCSUITE_ACM_INFO(0x04B2), }, /* Nokia 5700 XpressMusic */
1672 { NOKIA_PCSUITE_ACM_INFO(0x0134), }, /* Nokia 6110 Navigator (China) */
1673 { NOKIA_PCSUITE_ACM_INFO(0x046E), }, /* Nokia 6110 Navigator */
1674 { NOKIA_PCSUITE_ACM_INFO(0x002f), }, /* Nokia 6120 classic & */
1675 { NOKIA_PCSUITE_ACM_INFO(0x0088), }, /* Nokia 6121 classic */
1676 { NOKIA_PCSUITE_ACM_INFO(0x00fc), }, /* Nokia 6124 classic */
1677 { NOKIA_PCSUITE_ACM_INFO(0x0042), }, /* Nokia E51 */
1678 { NOKIA_PCSUITE_ACM_INFO(0x00b0), }, /* Nokia E66 */
1679 { NOKIA_PCSUITE_ACM_INFO(0x00ab), }, /* Nokia E71 */
1680 { NOKIA_PCSUITE_ACM_INFO(0x0481), }, /* Nokia N76 */
1681 { NOKIA_PCSUITE_ACM_INFO(0x0007), }, /* Nokia N81 & N81 8GB */
1682 { NOKIA_PCSUITE_ACM_INFO(0x0071), }, /* Nokia N82 */
1683 { NOKIA_PCSUITE_ACM_INFO(0x04F0), }, /* Nokia N95 & N95-3 NAM */
1684 { NOKIA_PCSUITE_ACM_INFO(0x0070), }, /* Nokia N95 8GB */
1685 { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */
1686 { NOKIA_PCSUITE_ACM_INFO(0x0099), }, /* Nokia 6210 Navigator, RM-367 */
1687 { NOKIA_PCSUITE_ACM_INFO(0x0128), }, /* Nokia 6210 Navigator, RM-419 */
1688 { NOKIA_PCSUITE_ACM_INFO(0x008f), }, /* Nokia 6220 Classic */
1689 { NOKIA_PCSUITE_ACM_INFO(0x00a0), }, /* Nokia 6650 */
1690 { NOKIA_PCSUITE_ACM_INFO(0x007b), }, /* Nokia N78 */
1691 { NOKIA_PCSUITE_ACM_INFO(0x0094), }, /* Nokia N85 */
1692 { NOKIA_PCSUITE_ACM_INFO(0x003a), }, /* Nokia N96 & N96-3 */
1693 { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */
1694 { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */
1695 { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */
Przemo Firszt83a4eae2010-06-28 21:29:34 +01001696 { NOKIA_PCSUITE_ACM_INFO(0x02e3), }, /* Nokia 5230, RM-588 */
Toby Gray4035e452010-09-01 16:01:19 +01001697 { NOKIA_PCSUITE_ACM_INFO(0x0178), }, /* Nokia E63 */
1698 { NOKIA_PCSUITE_ACM_INFO(0x010e), }, /* Nokia E75 */
1699 { NOKIA_PCSUITE_ACM_INFO(0x02d9), }, /* Nokia 6760 Slide */
1700 { NOKIA_PCSUITE_ACM_INFO(0x01d0), }, /* Nokia E52 */
1701 { NOKIA_PCSUITE_ACM_INFO(0x0223), }, /* Nokia E72 */
1702 { NOKIA_PCSUITE_ACM_INFO(0x0275), }, /* Nokia X6 */
1703 { NOKIA_PCSUITE_ACM_INFO(0x026c), }, /* Nokia N97 Mini */
1704 { NOKIA_PCSUITE_ACM_INFO(0x0154), }, /* Nokia 5800 XpressMusic */
1705 { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */
1706 { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */
Arvid Ephraim Picciani721d92f2011-01-25 15:58:40 +01001707 { NOKIA_PCSUITE_ACM_INFO(0x0302), }, /* Nokia N8 */
Toby Gray4061fde2011-06-06 14:52:48 +01001708 { NOKIA_PCSUITE_ACM_INFO(0x0335), }, /* Nokia E7 */
1709 { NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */
Toby Gray4035e452010-09-01 16:01:19 +01001710 { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */
Adrian Taylorc1479a92009-11-19 10:35:33 +00001711
Denis Pershin65e52f42011-09-04 17:37:21 +07001712 /* Support for Owen devices */
1713 { USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */
1714
Adrian Taylorc1479a92009-11-19 10:35:33 +00001715 /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
1716
Julian Calaby7c5d8c32010-01-05 23:57:46 +11001717 /* Support Lego NXT using pbLua firmware */
Julian Calabyce126642010-01-05 23:58:20 +11001718 { USB_DEVICE(0x0694, 0xff00),
1719 .driver_info = NOT_A_MODEM,
Otavio Salvador7893afc2010-09-26 23:35:05 -03001720 },
Julian Calaby7c5d8c32010-01-05 23:57:46 +11001721
Erik Slagterfd5054c2011-05-11 12:06:55 +02001722 /* Support for Droids MuIn LCD */
1723 { USB_DEVICE(0x04d8, 0x000b),
1724 .driver_info = NO_DATA_INTERFACE,
1725 },
1726
Philippe Corbes5b239f02010-08-31 19:31:32 +02001727 /* control interfaces without any protocol set */
1728 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1729 USB_CDC_PROTO_NONE) },
1730
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 /* control interfaces with various AT-command sets */
1732 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1733 USB_CDC_ACM_PROTO_AT_V25TER) },
1734 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1735 USB_CDC_ACM_PROTO_AT_PCCA101) },
1736 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1737 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1738 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1739 USB_CDC_ACM_PROTO_AT_GSM) },
1740 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
Alan Cox6e47e062009-06-11 12:37:06 +01001741 USB_CDC_ACM_PROTO_AT_3G) },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1743 USB_CDC_ACM_PROTO_AT_CDMA) },
1744
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 { }
1746};
1747
Alan Cox6e47e062009-06-11 12:37:06 +01001748MODULE_DEVICE_TABLE(usb, acm_ids);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
1750static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 .name = "cdc_acm",
1752 .probe = acm_probe,
1753 .disconnect = acm_disconnect,
Oliver Neukum35758582008-07-01 19:10:08 +02001754#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001755 .suspend = acm_suspend,
1756 .resume = acm_resume,
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001757 .reset_resume = acm_reset_resume,
Oliver Neukum35758582008-07-01 19:10:08 +02001758#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 .id_table = acm_ids,
Oliver Neukum35758582008-07-01 19:10:08 +02001760#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001761 .supports_autosuspend = 1,
Oliver Neukum35758582008-07-01 19:10:08 +02001762#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763};
1764
1765/*
1766 * TTY driver structures.
1767 */
1768
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001769static const struct tty_operations acm_ops = {
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001770 .install = acm_tty_install,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 .open = acm_tty_open,
1772 .close = acm_tty_close,
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001773 .cleanup = acm_tty_cleanup,
Alan Cox10077d42009-06-11 12:36:09 +01001774 .hangup = acm_tty_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 .write = acm_tty_write,
1776 .write_room = acm_tty_write_room,
1777 .ioctl = acm_tty_ioctl,
1778 .throttle = acm_tty_throttle,
1779 .unthrottle = acm_tty_unthrottle,
1780 .chars_in_buffer = acm_tty_chars_in_buffer,
1781 .break_ctl = acm_tty_break_ctl,
1782 .set_termios = acm_tty_set_termios,
1783 .tiocmget = acm_tty_tiocmget,
1784 .tiocmset = acm_tty_tiocmset,
1785};
1786
1787/*
1788 * Init / exit.
1789 */
1790
1791static int __init acm_init(void)
1792{
1793 int retval;
1794 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1795 if (!acm_tty_driver)
1796 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 acm_tty_driver->driver_name = "acm",
1798 acm_tty_driver->name = "ttyACM",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 acm_tty_driver->major = ACM_TTY_MAJOR,
1800 acm_tty_driver->minor_start = 0,
1801 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1802 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001803 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 acm_tty_driver->init_termios = tty_std_termios;
Alan Cox6e47e062009-06-11 12:37:06 +01001805 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD |
1806 HUPCL | CLOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 tty_set_operations(acm_tty_driver, &acm_ops);
1808
1809 retval = tty_register_driver(acm_tty_driver);
1810 if (retval) {
1811 put_tty_driver(acm_tty_driver);
1812 return retval;
1813 }
1814
1815 retval = usb_register(&acm_driver);
1816 if (retval) {
1817 tty_unregister_driver(acm_tty_driver);
1818 put_tty_driver(acm_tty_driver);
1819 return retval;
1820 }
1821
Johan Hovolda2c7b932011-03-22 11:12:18 +01001822 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823
1824 return 0;
1825}
1826
1827static void __exit acm_exit(void)
1828{
1829 usb_deregister(&acm_driver);
1830 tty_unregister_driver(acm_tty_driver);
1831 put_tty_driver(acm_tty_driver);
1832}
1833
1834module_init(acm_init);
1835module_exit(acm_exit);
1836
Alan Cox6e47e062009-06-11 12:37:06 +01001837MODULE_AUTHOR(DRIVER_AUTHOR);
1838MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839MODULE_LICENSE("GPL");
Scott James Remnante766aeb2009-04-06 17:33:18 +01001840MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR);