blob: e2ed09d26e63c55158a4d9bb8d6b149696511d35 [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
flintmanc6dc72f2014-08-11 21:52:25 -040055/*
56 * Version Information
57 */
58#define DRIVER_VERSION "v0.26-mbm_2"
59#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
61
62static struct usb_driver acm_driver;
63static struct tty_driver *acm_tty_driver;
64static struct acm *acm_table[ACM_TTY_MINORS];
65
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -080066static DEFINE_MUTEX(acm_table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -080068/*
69 * acm_table accessors
70 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -080072/*
73 * Look up an ACM structure by index. If found and not disconnected, increment
74 * its refcount and return it with its mutex held.
75 */
76static struct acm *acm_get_by_index(unsigned index)
77{
78 struct acm *acm;
79
80 mutex_lock(&acm_table_lock);
81 acm = acm_table[index];
82 if (acm) {
83 mutex_lock(&acm->mutex);
84 if (acm->disconnected) {
85 mutex_unlock(&acm->mutex);
86 acm = NULL;
87 } else {
88 tty_port_get(&acm->port);
89 mutex_unlock(&acm->mutex);
90 }
91 }
92 mutex_unlock(&acm_table_lock);
93 return acm;
94}
95
96/*
97 * Try to find an available minor number and if found, associate it with 'acm'.
98 */
99static int acm_alloc_minor(struct acm *acm)
100{
101 int minor;
102
103 mutex_lock(&acm_table_lock);
104 for (minor = 0; minor < ACM_TTY_MINORS; minor++) {
105 if (!acm_table[minor]) {
106 acm_table[minor] = acm;
107 break;
108 }
109 }
110 mutex_unlock(&acm_table_lock);
111
112 return minor;
113}
114
115/* Release the minor number associated with 'acm'. */
116static void acm_release_minor(struct acm *acm)
117{
118 mutex_lock(&acm_table_lock);
119 acm_table[acm->minor] = NULL;
120 mutex_unlock(&acm_table_lock);
121}
Alan Cox739e0282009-06-11 12:27:50 +0100122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123/*
124 * Functions for ACM control messages.
125 */
126
Alan Cox6e47e062009-06-11 12:37:06 +0100127static int acm_ctrl_msg(struct acm *acm, int request, int value,
128 void *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129{
130 int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
131 request, USB_RT_ACM, value,
132 acm->control->altsetting[0].desc.bInterfaceNumber,
133 buf, len, 5000);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100134 dev_dbg(&acm->control->dev,
135 "%s - rq 0x%02x, val %#x, len %#x, result %d\n",
136 __func__, request, value, len, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 return retval < 0 ? retval : 0;
138}
139
flintmanc6dc72f2014-08-11 21:52:25 -0400140/* MBM */
141#define USB_CDC_SET_COMM_FEATURE 0x02
142#define USB_CDC_GET_COMM_FEATURE 0x03
143#define USB_CDC_CLEAR_COMM_FEATURE 0x04
144
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145/* devices aren't required to support these requests.
146 * the cdc acm descriptor tells whether they do...
147 */
148#define acm_set_control(acm, control) \
149 acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
150#define acm_set_line(acm, line) \
151 acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
152#define acm_send_break(acm, ms) \
153 acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
flintmanc6dc72f2014-08-11 21:52:25 -0400154/* MBM */
155#define acm_set_comm_feature(acm, feature, state) \
156 acm_ctrl_msg(acm, USB_CDC_SET_COMM_FEATURE, feature, state, 2)
157#define acm_clear_comm_feature(acm, feature) \
158 acm_ctrl_msg(acm, USB_CDC_CLEAR_COMM_FEATURE, feature, NULL, 0)
159#define acm_send_encap_resp(acm, msg) \
160 acm_ctrl_msg(acm, USB_CDC_SEND_ENCAPSULATED_COMMAND, 0, msg, sizeof *(msg))
161
162
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164/*
Oliver Neukum884b6002005-04-21 21:28:02 +0200165 * Write buffer management.
166 * All of these assume proper locks taken by the caller.
167 */
168
169static int acm_wb_alloc(struct acm *acm)
170{
171 int i, wbn;
172 struct acm_wb *wb;
173
David Engrafe4cf3aa2008-03-20 10:01:34 +0100174 wbn = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200175 i = 0;
176 for (;;) {
177 wb = &acm->wb[wbn];
178 if (!wb->use) {
179 wb->use = 1;
180 return wbn;
181 }
Oliver Neukum86478942006-05-13 22:50:47 +0200182 wbn = (wbn + 1) % ACM_NW;
183 if (++i >= ACM_NW)
Oliver Neukum884b6002005-04-21 21:28:02 +0200184 return -1;
185 }
186}
187
Oliver Neukum884b6002005-04-21 21:28:02 +0200188static int acm_wb_is_avail(struct acm *acm)
189{
190 int i, n;
David Brownelle5fbab52008-08-06 18:46:10 -0700191 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200192
Oliver Neukum86478942006-05-13 22:50:47 +0200193 n = ACM_NW;
David Brownelle5fbab52008-08-06 18:46:10 -0700194 spin_lock_irqsave(&acm->write_lock, flags);
Alan Cox6e47e062009-06-11 12:37:06 +0100195 for (i = 0; i < ACM_NW; i++)
Oliver Neukum86478942006-05-13 22:50:47 +0200196 n -= acm->wb[i].use;
David Brownelle5fbab52008-08-06 18:46:10 -0700197 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200198 return n;
199}
200
Oliver Neukum884b6002005-04-21 21:28:02 +0200201/*
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800202 * Finish write. Caller must hold acm->write_lock
Oliver Neukum884b6002005-04-21 21:28:02 +0200203 */
David Engrafe4cf3aa2008-03-20 10:01:34 +0100204static void acm_write_done(struct acm *acm, struct acm_wb *wb)
Oliver Neukum884b6002005-04-21 21:28:02 +0200205{
David Engrafe4cf3aa2008-03-20 10:01:34 +0100206 wb->use = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200207 acm->transmitting--;
Oliver Neukum97d35f92009-12-16 17:05:57 +0100208 usb_autopm_put_interface_async(acm->control);
Oliver Neukum884b6002005-04-21 21:28:02 +0200209}
210
211/*
212 * Poke write.
Oliver Neukum11ea8592008-06-20 11:25:57 +0200213 *
214 * the caller is responsible for locking
Oliver Neukum884b6002005-04-21 21:28:02 +0200215 */
Oliver Neukum11ea8592008-06-20 11:25:57 +0200216
217static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
218{
219 int rc;
220
221 acm->transmitting++;
222
223 wb->urb->transfer_buffer = wb->buf;
224 wb->urb->transfer_dma = wb->dmah;
225 wb->urb->transfer_buffer_length = wb->len;
226 wb->urb->dev = acm->dev;
227
Alan Cox6e47e062009-06-11 12:37:06 +0100228 rc = usb_submit_urb(wb->urb, GFP_ATOMIC);
229 if (rc < 0) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100230 dev_err(&acm->data->dev,
231 "%s - usb_submit_urb(write bulk) failed: %d\n",
232 __func__, rc);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200233 acm_write_done(acm, wb);
234 }
235 return rc;
236}
237
David Engrafe4cf3aa2008-03-20 10:01:34 +0100238static int acm_write_start(struct acm *acm, int wbn)
Oliver Neukum884b6002005-04-21 21:28:02 +0200239{
240 unsigned long flags;
David Brownell934da462008-08-06 18:44:12 -0700241 struct acm_wb *wb = &acm->wb[wbn];
Oliver Neukum884b6002005-04-21 21:28:02 +0200242 int rc;
243
244 spin_lock_irqsave(&acm->write_lock, flags);
245 if (!acm->dev) {
David Brownell934da462008-08-06 18:44:12 -0700246 wb->use = 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200247 spin_unlock_irqrestore(&acm->write_lock, flags);
248 return -ENODEV;
249 }
250
Johan Hovold5e9e75f2011-03-22 11:12:17 +0100251 dev_vdbg(&acm->data->dev, "%s - susp_count %d\n", __func__,
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100252 acm->susp_count);
Oliver Neukum97d35f92009-12-16 17:05:57 +0100253 usb_autopm_get_interface_async(acm->control);
Oliver Neukum11ea8592008-06-20 11:25:57 +0200254 if (acm->susp_count) {
Oliver Neukum97d35f92009-12-16 17:05:57 +0100255 if (!acm->delayed_wb)
256 acm->delayed_wb = wb;
flintmanc6dc72f2014-08-11 21:52:25 -0400257 else {
258 if (acm->delayed_wb->len + wb->len <= acm->writesize ) {
259 memcpy(acm->delayed_wb->buf + acm->delayed_wb->len, wb->buf, wb->len);
260 acm->delayed_wb->len += wb->len;
261 }
262 wb->use = 0;
Oliver Neukum97d35f92009-12-16 17:05:57 +0100263 usb_autopm_put_interface_async(acm->control);
flintmanc6dc72f2014-08-11 21:52:25 -0400264 }
265
Oliver Neukum11ea8592008-06-20 11:25:57 +0200266 spin_unlock_irqrestore(&acm->write_lock, flags);
267 return 0; /* A white lie */
268 }
269 usb_mark_last_busy(acm->dev);
270
Oliver Neukum11ea8592008-06-20 11:25:57 +0200271 rc = acm_start_wb(acm, wb);
Oliver Neukum884b6002005-04-21 21:28:02 +0200272 spin_unlock_irqrestore(&acm->write_lock, flags);
273
Oliver Neukum884b6002005-04-21 21:28:02 +0200274 return rc;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200275
Oliver Neukum884b6002005-04-21 21:28:02 +0200276}
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100277/*
278 * attributes exported through sysfs
279 */
280static ssize_t show_caps
281(struct device *dev, struct device_attribute *attr, char *buf)
282{
283 struct usb_interface *intf = to_usb_interface(dev);
284 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum884b6002005-04-21 21:28:02 +0200285
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100286 return sprintf(buf, "%d", acm->ctrl_caps);
287}
288static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
289
290static ssize_t show_country_codes
291(struct device *dev, struct device_attribute *attr, char *buf)
292{
293 struct usb_interface *intf = to_usb_interface(dev);
294 struct acm *acm = usb_get_intfdata(intf);
295
296 memcpy(buf, acm->country_codes, acm->country_code_size);
297 return acm->country_code_size;
298}
299
300static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
301
302static ssize_t show_country_rel_date
303(struct device *dev, struct device_attribute *attr, char *buf)
304{
305 struct usb_interface *intf = to_usb_interface(dev);
306 struct acm *acm = usb_get_intfdata(intf);
307
308 return sprintf(buf, "%d", acm->country_rel_date);
309}
310
311static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
Oliver Neukum884b6002005-04-21 21:28:02 +0200312/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 * Interrupt handlers for various ACM device responses
314 */
315
flintmanc6dc72f2014-08-11 21:52:25 -0400316/* MBM */
317static void acm_in_callback(struct urb *urb)
318{
319 struct acm *acm = urb->context;
320 int status = urb->status;
321
322 if (status) {
323 switch (status) {
324 case -ENOENT:
325 dev_dbg(&urb->dev->dev,
326 "nonzero urb status received: -ENOENT");
327 goto skip_error;
328 case -ECONNRESET:
329 dev_dbg(&urb->dev->dev,
330 "nonzero urb status received: -ECONNRESET");
331 goto skip_error;
332 case -ESHUTDOWN:
333 dev_dbg(&urb->dev->dev,
334 "nonzero urb status received: -ESHUTDOWN");
335 goto skip_error;
336 case -EPIPE:
337 dev_err(&urb->dev->dev,
338 "nonzero urb status received: -EPIPE\n");
339 break;
340 default:
341 dev_err(&urb->dev->dev,
342 "Unexpected error %d\n", status);
343 break;
344 }
345 }
346
347 dbg("unsupported encap: %s", (char *)acm->inbuf);
348skip_error:
349 dbg("");
350}
351
352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353/* control interface reports status changes with "interrupt" transfers */
David Howells7d12e782006-10-05 14:55:46 +0100354static void acm_ctrl_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
356 struct acm *acm = urb->context;
357 struct usb_cdc_notification *dr = urb->transfer_buffer;
flintmanc6dc72f2014-08-11 21:52:25 -0400358 /* MBM */
359 struct usb_ctrlrequest *req = acm->irq;
Alan Cox10077d42009-06-11 12:36:09 +0100360 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 unsigned char *data;
362 int newctrl;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700363 int retval;
364 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700366 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 case 0:
368 /* success */
369 break;
370 case -ECONNRESET:
371 case -ENOENT:
372 case -ESHUTDOWN:
373 /* this urb is terminated, clean up */
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100374 dev_dbg(&acm->control->dev,
375 "%s - urb shutting down with status: %d\n",
376 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 return;
378 default:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100379 dev_dbg(&acm->control->dev,
380 "%s - nonzero urb status received: %d\n",
381 __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 goto exit;
383 }
384
Johan Hovold7e7797e2011-03-22 11:12:11 +0100385 usb_mark_last_busy(acm->dev);
386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 data = (unsigned char *)(dr + 1);
388 switch (dr->bNotificationType) {
Alan Cox6e47e062009-06-11 12:37:06 +0100389 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
flintmanc6dc72f2014-08-11 21:52:25 -0400390 /* MBM */
391 dev_info(&urb->dev->dev, "%s network", dr->wValue ?
392 "connected to" : "disconnected from");
Alan Cox6e47e062009-06-11 12:37:06 +0100393 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
Alan Cox6e47e062009-06-11 12:37:06 +0100395 case USB_CDC_NOTIFY_SERIAL_STATE:
396 tty = tty_port_tty_get(&acm->port);
397 newctrl = get_unaligned_le16(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Alan Cox6e47e062009-06-11 12:37:06 +0100399 if (tty) {
400 if (!acm->clocal &&
401 (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100402 dev_dbg(&acm->control->dev,
403 "%s - calling hangup\n", __func__);
Alan Cox6e47e062009-06-11 12:37:06 +0100404 tty_hangup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 }
Alan Cox6e47e062009-06-11 12:37:06 +0100406 tty_kref_put(tty);
407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Alan Cox6e47e062009-06-11 12:37:06 +0100409 acm->ctrlin = newctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100411 dev_dbg(&acm->control->dev,
412 "%s - input control lines: dcd%c dsr%c break%c "
413 "ring%c framing%c parity%c overrun%c\n",
414 __func__,
Alan Cox6e47e062009-06-11 12:37:06 +0100415 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',
416 acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
417 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-',
418 acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
419 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',
420 acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
421 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 break;
423
flintmanc6dc72f2014-08-11 21:52:25 -0400424 /* MBM */
425 case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
426 dev_err(&urb->dev->dev, "NOTIFY_RESPONSE_AVAILABLE received: index %d len %d",
427 dr->wIndex, dr->wLength);
428 req->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
429 req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
430 req->wValue = 0;
431 req->wIndex = cpu_to_le16(dr->wIndex);
432 req->wLength = cpu_to_le16(acm->bMaxPacketSize0);
433
434 usb_fill_control_urb(
435 acm->response,
436 acm->dev,
437 usb_sndctrlpipe(acm->dev, 0),
438 (unsigned char *)req,
439 acm->inbuf,
440 acm->bMaxPacketSize0,
441 acm_in_callback,
442 acm);
443
444 break;
445
Alan Cox6e47e062009-06-11 12:37:06 +0100446 default:
flintmanc6dc72f2014-08-11 21:52:25 -0400447 /* MBM */
448 dev_info(&urb->dev->dev,"unknown notification %d received: index %d len %d data0 %d data1 %d",
Alan Cox6e47e062009-06-11 12:37:06 +0100449 dr->bNotificationType, dr->wIndex,
450 dr->wLength, data[0], data[1]);
451 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 }
453exit:
Alan Cox6e47e062009-06-11 12:37:06 +0100454 retval = usb_submit_urb(urb, GFP_ATOMIC);
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700455 if (retval)
Johan Hovold1d9846e2011-03-22 11:12:14 +0100456 dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n",
457 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458}
459
Johan Hovold088c64f2011-03-25 11:06:02 +0100460static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461{
Johan Hovold088c64f2011-03-25 11:06:02 +0100462 int res;
Greg Kroah-Hartman185d4052007-07-18 10:58:02 -0700463
Johan Hovold088c64f2011-03-25 11:06:02 +0100464 if (!test_and_clear_bit(index, &acm->read_urbs_free))
465 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Johan Hovold088c64f2011-03-25 11:06:02 +0100467 dev_vdbg(&acm->data->dev, "%s - urb %d\n", __func__, index);
468
469 res = usb_submit_urb(acm->read_urbs[index], mem_flags);
470 if (res) {
471 if (res != -EPERM) {
472 dev_err(&acm->data->dev,
473 "%s - usb_submit_urb failed: %d\n",
474 __func__, res);
475 }
476 set_bit(index, &acm->read_urbs_free);
477 return res;
478 }
479
480 return 0;
481}
482
483static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags)
484{
485 int res;
486 int i;
487
488 for (i = 0; i < acm->rx_buflimit; ++i) {
489 res = acm_submit_read_urb(acm, i, mem_flags);
490 if (res)
491 return res;
492 }
493
494 return 0;
495}
496
497static void acm_process_read_urb(struct acm *acm, struct urb *urb)
498{
499 struct tty_struct *tty;
500
501 if (!urb->actual_length)
502 return;
503
504 tty = tty_port_tty_get(&acm->port);
505 if (!tty)
506 return;
507
508 tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length);
509 tty_flip_buffer_push(tty);
510
511 tty_kref_put(tty);
512}
513
514static void acm_read_bulk_callback(struct urb *urb)
515{
516 struct acm_rb *rb = urb->context;
517 struct acm *acm = rb->instance;
518 unsigned long flags;
519
520 dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__,
521 rb->index, urb->actual_length);
522 set_bit(rb->index, &acm->read_urbs_free);
523
524 if (!acm->dev) {
525 dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 return;
Oliver Neukum11ea8592008-06-20 11:25:57 +0200527 }
528 usb_mark_last_busy(acm->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
Johan Hovold088c64f2011-03-25 11:06:02 +0100530 if (urb->status) {
Johan Hovold1d9846e2011-03-22 11:12:14 +0100531 dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n",
Johan Hovold088c64f2011-03-25 11:06:02 +0100532 __func__, urb->status);
533 return;
534 }
535 acm_process_read_urb(acm, urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
Johan Hovold088c64f2011-03-25 11:06:02 +0100537 /* throttle device if requested by tty */
538 spin_lock_irqsave(&acm->read_lock, flags);
539 acm->throttled = acm->throttle_req;
540 if (!acm->throttled && !acm->susp_count) {
541 spin_unlock_irqrestore(&acm->read_lock, flags);
542 acm_submit_read_urb(acm, rb->index, GFP_ATOMIC);
Oliver Neukum86478942006-05-13 22:50:47 +0200543 } else {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200544 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546}
547
548/* data interface wrote those outgoing bytes */
David Howells7d12e782006-10-05 14:55:46 +0100549static void acm_write_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550{
Ming Leicdc97792008-02-24 18:41:47 +0800551 struct acm_wb *wb = urb->context;
David Brownelle5fbab52008-08-06 18:46:10 -0700552 struct acm *acm = wb->instance;
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800553 unsigned long flags;
Oliver Neukum884b6002005-04-21 21:28:02 +0200554
Johan Hovold4fa46262011-03-22 11:12:16 +0100555 if (urb->status || (urb->actual_length != urb->transfer_buffer_length))
556 dev_vdbg(&acm->data->dev, "%s - len %d/%d, status %d\n",
Johan Hovold1d9846e2011-03-22 11:12:14 +0100557 __func__,
David Brownelle5fbab52008-08-06 18:46:10 -0700558 urb->actual_length,
559 urb->transfer_buffer_length,
560 urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800562 spin_lock_irqsave(&acm->write_lock, flags);
David Engrafe4cf3aa2008-03-20 10:01:34 +0100563 acm_write_done(acm, wb);
Brandon Philipsad0b65e2008-11-06 11:19:11 -0800564 spin_unlock_irqrestore(&acm->write_lock, flags);
Havard Skinnemoen99823f42011-12-09 16:51:54 -0800565 schedule_work(&acm->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566}
567
David Howellsc4028952006-11-22 14:57:56 +0000568static void acm_softint(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
David Howellsc4028952006-11-22 14:57:56 +0000570 struct acm *acm = container_of(work, struct acm, work);
Alan Cox10077d42009-06-11 12:36:09 +0100571 struct tty_struct *tty;
David Brownelle5fbab52008-08-06 18:46:10 -0700572
Johan Hovold1d9846e2011-03-22 11:12:14 +0100573 dev_vdbg(&acm->data->dev, "%s\n", __func__);
574
Alan Cox10077d42009-06-11 12:36:09 +0100575 tty = tty_port_tty_get(&acm->port);
Johan Hovold15e5bee2011-03-22 11:12:10 +0100576 if (!tty)
577 return;
Alan Cox10077d42009-06-11 12:36:09 +0100578 tty_wakeup(tty);
579 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580}
581
582/*
583 * TTY handlers
584 */
585
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800586static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587{
588 struct acm *acm;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800589 int retval;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100590
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800591 dev_dbg(tty->dev, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800593 acm = acm_get_by_index(tty->index);
594 if (!acm)
595 return -ENODEV;
596
Jiri Slabyf8a8c102012-03-05 14:51:48 +0100597 retval = tty_standard_install(driver, tty);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800598 if (retval)
599 goto error_init_termios;
600
601 tty->driver_data = acm;
602
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800603 return 0;
604
605error_init_termios:
606 tty_port_put(&acm->port);
607 return retval;
608}
609
610static int acm_tty_open(struct tty_struct *tty, struct file *filp)
611{
612 struct acm *acm = tty->driver_data;
613
614 dev_dbg(tty->dev, "%s\n", __func__);
615
616 return tty_port_open(&acm->port, tty, filp);
617}
618
619static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)
620{
621 struct acm *acm = container_of(port, struct acm, port);
622 int retval = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100624 dev_dbg(&acm->control->dev, "%s\n", __func__);
625
Oliver Neukum1365baf2007-10-12 17:24:28 +0200626 mutex_lock(&acm->mutex);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800627 if (acm->disconnected)
628 goto disconnected;
629
630 retval = usb_autopm_get_interface(acm->control);
631 if (retval)
632 goto error_get_interface;
633
634 /*
635 * FIXME: Why do we need this? Allocating 64K of physically contiguous
636 * memory is really nasty...
637 */
638 set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
639 acm->control->needs_remote_wakeup = 1;
Oliver Neukum1365baf2007-10-12 17:24:28 +0200640
flintmanc6dc72f2014-08-11 21:52:25 -0400641#ifndef CONFIG_MACH_TENDERLOIN
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 acm->ctrlurb->dev = acm->dev;
643 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100644 dev_err(&acm->control->dev,
645 "%s - usb_submit_urb(ctrl irq) failed\n", __func__);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800646 goto error_submit_urb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 }
flintmanc6dc72f2014-08-11 21:52:25 -0400648#endif
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800649 acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS;
650 if (acm_set_control(acm, acm->ctrlout) < 0 &&
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100651 (acm->ctrl_caps & USB_CDC_CAP_LINE))
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800652 goto error_set_control;
Alan Cox10077d42009-06-11 12:36:09 +0100653
flintmanc6dc72f2014-08-11 21:52:25 -0400654 /* MBM */
655 acm->state &= ~ACM_ABS_IDLE;
656 if (0 > acm_set_comm_feature(acm, ACM_ABSTRACT_STATE, &acm->state) &&
657 (acm->ctrl_caps & USB_CDC_COMM_FEATURE))
658 goto error_set_control;
659
Oliver Neukum11ea8592008-06-20 11:25:57 +0200660 usb_autopm_put_interface(acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
Otto Meta9cc2d462012-06-06 18:46:21 +0200662 /*
663 * Unthrottle device in case the TTY was closed while throttled.
664 */
665 spin_lock_irq(&acm->read_lock);
666 acm->throttled = 0;
667 acm->throttle_req = 0;
668 spin_unlock_irq(&acm->read_lock);
669
Johan Hovold088c64f2011-03-25 11:06:02 +0100670 if (acm_submit_read_urbs(acm, GFP_KERNEL))
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800671 goto error_submit_read_urbs;
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100672
Oliver Neukum1365baf2007-10-12 17:24:28 +0200673 mutex_unlock(&acm->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800675 return 0;
676
677error_submit_read_urbs:
678 acm->ctrlout = 0;
679 acm_set_control(acm, acm->ctrlout);
680error_set_control:
681 usb_kill_urb(acm->ctrlurb);
flintmanc6dc72f2014-08-11 21:52:25 -0400682#ifndef CONFIG_MACH_TENDERLOIN
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800683error_submit_urb:
Oliver Neukum2b626dc2010-02-03 17:10:22 +0100684 usb_autopm_put_interface(acm->control);
flintmanc6dc72f2014-08-11 21:52:25 -0400685#endif
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800686error_get_interface:
687disconnected:
688 mutex_unlock(&acm->mutex);
689 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690}
691
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800692static void acm_port_destruct(struct tty_port *port)
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700693{
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800694 struct acm *acm = container_of(port, struct acm, port);
695
696 dev_dbg(&acm->control->dev, "%s\n", __func__);
David Kubicek61a87ad2005-11-01 18:51:34 +0100697
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800698 acm_release_minor(acm);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700699 usb_put_intf(acm->control);
flintmanc6dc72f2014-08-11 21:52:25 -0400700 /* MBM */
701 usb_free_urb(acm->response);
702 kfree(acm->irq);
703
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100704 kfree(acm->country_codes);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700705 kfree(acm);
706}
707
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800708static void acm_port_shutdown(struct tty_port *port)
Alan Cox10077d42009-06-11 12:36:09 +0100709{
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800710 struct acm *acm = container_of(port, struct acm, port);
Johan Hovolddab54c92011-03-22 11:12:21 +0100711 int i;
712
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800713 dev_dbg(&acm->control->dev, "%s\n", __func__);
714
715 mutex_lock(&acm->mutex);
716 if (!acm->disconnected) {
Alan Cox10077d42009-06-11 12:36:09 +0100717 usb_autopm_get_interface(acm->control);
718 acm_set_control(acm, acm->ctrlout = 0);
flintmanc6dc72f2014-08-11 21:52:25 -0400719 /* MBM */
720 acm->state |= ACM_ABS_IDLE;
721 acm_set_comm_feature(acm, ACM_ABSTRACT_STATE, &acm->state);
722 /* MBM, Device can still transmitt INT messages dont kill */
723 /* usb_kill_urb(acm->ctrlurb); */
Alan Cox10077d42009-06-11 12:36:09 +0100724 for (i = 0; i < ACM_NW; i++)
725 usb_kill_urb(acm->wb[i].urb);
Johan Hovolddab54c92011-03-22 11:12:21 +0100726 for (i = 0; i < acm->rx_buflimit; i++)
Johan Hovold088c64f2011-03-25 11:06:02 +0100727 usb_kill_urb(acm->read_urbs[i]);
Alan Cox10077d42009-06-11 12:36:09 +0100728 acm->control->needs_remote_wakeup = 0;
729 usb_autopm_put_interface(acm->control);
730 }
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800731 mutex_unlock(&acm->mutex);
732}
733
734static void acm_tty_cleanup(struct tty_struct *tty)
735{
736 struct acm *acm = tty->driver_data;
737 dev_dbg(&acm->control->dev, "%s\n", __func__);
738 tty_port_put(&acm->port);
Alan Cox10077d42009-06-11 12:36:09 +0100739}
740
741static void acm_tty_hangup(struct tty_struct *tty)
742{
743 struct acm *acm = tty->driver_data;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800744 dev_dbg(&acm->control->dev, "%s\n", __func__);
Alan Cox10077d42009-06-11 12:36:09 +0100745 tty_port_hangup(&acm->port);
Alan Cox10077d42009-06-11 12:36:09 +0100746}
747
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748static void acm_tty_close(struct tty_struct *tty, struct file *filp)
749{
750 struct acm *acm = tty->driver_data;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800751 dev_dbg(&acm->control->dev, "%s\n", __func__);
752 tty_port_close(&acm->port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753}
754
Alan Cox6e47e062009-06-11 12:37:06 +0100755static int acm_tty_write(struct tty_struct *tty,
756 const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
758 struct acm *acm = tty->driver_data;
759 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200760 unsigned long flags;
761 int wbn;
762 struct acm_wb *wb;
763
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 if (!count)
765 return 0;
766
Johan Hovold5e9e75f2011-03-22 11:12:17 +0100767 dev_vdbg(&acm->data->dev, "%s - count %d\n", __func__, count);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100768
Oliver Neukum884b6002005-04-21 21:28:02 +0200769 spin_lock_irqsave(&acm->write_lock, flags);
Alan Cox6e47e062009-06-11 12:37:06 +0100770 wbn = acm_wb_alloc(acm);
771 if (wbn < 0) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200772 spin_unlock_irqrestore(&acm->write_lock, flags);
Oliver Neukum884b6002005-04-21 21:28:02 +0200773 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200775 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Oliver Neukum884b6002005-04-21 21:28:02 +0200777 count = (count > acm->writesize) ? acm->writesize : count;
Johan Hovold5e9e75f2011-03-22 11:12:17 +0100778 dev_vdbg(&acm->data->dev, "%s - write %d\n", __func__, count);
Oliver Neukum884b6002005-04-21 21:28:02 +0200779 memcpy(wb->buf, buf, count);
780 wb->len = count;
781 spin_unlock_irqrestore(&acm->write_lock, flags);
782
Alan Cox6e47e062009-06-11 12:37:06 +0100783 stat = acm_write_start(acm, wbn);
784 if (stat < 0)
Oliver Neukum884b6002005-04-21 21:28:02 +0200785 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 return count;
787}
788
789static int acm_tty_write_room(struct tty_struct *tty)
790{
791 struct acm *acm = tty->driver_data;
Oliver Neukum884b6002005-04-21 21:28:02 +0200792 /*
793 * Do not let the line discipline to know that we have a reserve,
794 * or it might get too enthusiastic.
795 */
David Brownell934da462008-08-06 18:44:12 -0700796 return acm_wb_is_avail(acm) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797}
798
799static int acm_tty_chars_in_buffer(struct tty_struct *tty)
800{
801 struct acm *acm = tty->driver_data;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800802 /*
803 * if the device was unplugged then any remaining characters fell out
804 * of the connector ;)
805 */
806 if (acm->disconnected)
Alan Cox23198fd2009-07-20 16:05:27 +0100807 return 0;
Oliver Neukum884b6002005-04-21 21:28:02 +0200808 /*
809 * This is inaccurate (overcounts), but it works.
810 */
Oliver Neukum86478942006-05-13 22:50:47 +0200811 return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812}
813
814static void acm_tty_throttle(struct tty_struct *tty)
815{
816 struct acm *acm = tty->driver_data;
Johan Hovold088c64f2011-03-25 11:06:02 +0100817
Johan Hovold088c64f2011-03-25 11:06:02 +0100818 spin_lock_irq(&acm->read_lock);
819 acm->throttle_req = 1;
820 spin_unlock_irq(&acm->read_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821}
822
823static void acm_tty_unthrottle(struct tty_struct *tty)
824{
825 struct acm *acm = tty->driver_data;
Johan Hovold088c64f2011-03-25 11:06:02 +0100826 unsigned int was_throttled;
827
Johan Hovold088c64f2011-03-25 11:06:02 +0100828 spin_lock_irq(&acm->read_lock);
829 was_throttled = acm->throttled;
830 acm->throttled = 0;
831 acm->throttle_req = 0;
832 spin_unlock_irq(&acm->read_lock);
833
834 if (was_throttled)
835 acm_submit_read_urbs(acm, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836}
837
Alan Cox9e989662008-07-22 11:18:03 +0100838static int acm_tty_break_ctl(struct tty_struct *tty, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839{
840 struct acm *acm = tty->driver_data;
Alan Cox9e989662008-07-22 11:18:03 +0100841 int retval;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -0800842
Alan Cox9e989662008-07-22 11:18:03 +0100843 retval = acm_send_break(acm, state ? 0xffff : 0);
844 if (retval < 0)
Johan Hovolda5cc7ef2011-03-22 11:12:15 +0100845 dev_dbg(&acm->control->dev, "%s - send break failed\n",
846 __func__);
Alan Cox9e989662008-07-22 11:18:03 +0100847 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848}
849
Alan Cox60b33c12011-02-14 16:26:14 +0000850static int acm_tty_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851{
852 struct acm *acm = tty->driver_data;
853
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
855 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
856 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
857 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
858 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
859 TIOCM_CTS;
860}
861
Alan Cox20b9d172011-02-14 16:26:50 +0000862static int acm_tty_tiocmset(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 unsigned int set, unsigned int clear)
864{
865 struct acm *acm = tty->driver_data;
866 unsigned int newctrl;
867
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 newctrl = acm->ctrlout;
Alan Cox6e47e062009-06-11 12:37:06 +0100869 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
870 (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
871 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
872 (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
874 newctrl = (newctrl & ~clear) | set;
875
876 if (acm->ctrlout == newctrl)
877 return 0;
878 return acm_set_control(acm, acm->ctrlout = newctrl);
879}
880
Oliver Neukum18c75722012-02-17 17:21:24 -0500881static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
882{
883 struct serial_struct tmp;
884
885 if (!info)
886 return -EINVAL;
887
888 memset(&tmp, 0, sizeof(tmp));
889 tmp.flags = ASYNC_LOW_LATENCY;
890 tmp.xmit_fifo_size = acm->writesize;
891 tmp.baud_base = le32_to_cpu(acm->line.dwDTERate);
Dan Williams1229a832012-11-08 12:47:41 -0600892 tmp.close_delay = acm->port.close_delay / 10;
893 tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
894 ASYNC_CLOSING_WAIT_NONE :
895 acm->port.closing_wait / 10;
Oliver Neukum18c75722012-02-17 17:21:24 -0500896
897 if (copy_to_user(info, &tmp, sizeof(tmp)))
898 return -EFAULT;
899 else
900 return 0;
901}
902
Dan Williams1229a832012-11-08 12:47:41 -0600903static int set_serial_info(struct acm *acm,
904 struct serial_struct __user *newinfo)
905{
906 struct serial_struct new_serial;
907 unsigned int closing_wait, close_delay;
908 int retval = 0;
909
910 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
911 return -EFAULT;
912
913 close_delay = new_serial.close_delay * 10;
914 closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
915 ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
916
917 mutex_lock(&acm->port.mutex);
918
919 if (!capable(CAP_SYS_ADMIN)) {
920 if ((close_delay != acm->port.close_delay) ||
921 (closing_wait != acm->port.closing_wait))
922 retval = -EPERM;
923 else
924 retval = -EOPNOTSUPP;
925 } else {
926 acm->port.close_delay = close_delay;
927 acm->port.closing_wait = closing_wait;
928 }
929
930 mutex_unlock(&acm->port.mutex);
931 return retval;
932}
933
Alan Cox6caa76b2011-02-14 16:27:22 +0000934static int acm_tty_ioctl(struct tty_struct *tty,
Alan Cox6e47e062009-06-11 12:37:06 +0100935 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936{
Oliver Neukum18c75722012-02-17 17:21:24 -0500937 struct acm *acm = tty->driver_data;
938 int rv = -ENOIOCTLCMD;
939
940 switch (cmd) {
941 case TIOCGSERIAL: /* gets serial port data */
942 rv = get_serial_info(acm, (struct serial_struct __user *) arg);
943 break;
Dan Williams1229a832012-11-08 12:47:41 -0600944 case TIOCSSERIAL:
945 rv = set_serial_info(acm, (struct serial_struct __user *) arg);
946 break;
Oliver Neukum18c75722012-02-17 17:21:24 -0500947 }
948
949 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950}
951
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100952static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 0, 50, 75, 110, 134, 150, 200, 300, 600,
954 1200, 1800, 2400, 4800, 9600, 19200, 38400,
955 57600, 115200, 230400, 460800, 500000, 576000,
956 921600, 1000000, 1152000, 1500000, 2000000,
957 2500000, 3000000, 3500000, 4000000
958};
959
Alan Cox6e47e062009-06-11 12:37:06 +0100960static void acm_tty_set_termios(struct tty_struct *tty,
961 struct ktermios *termios_old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
963 struct acm *acm = tty->driver_data;
Alan Cox606d0992006-12-08 02:38:45 -0800964 struct ktermios *termios = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 struct usb_cdc_line_coding newline;
966 int newctrl = acm->ctrlout;
967
Alan Cox9b80fee2009-09-19 13:13:23 -0700968 newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
970 newline.bParityType = termios->c_cflag & PARENB ?
Alan Cox6e47e062009-06-11 12:37:06 +0100971 (termios->c_cflag & PARODD ? 1 : 2) +
972 (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
Nicolas Boullisa5204462012-10-16 00:06:23 +0200973 switch (termios->c_cflag & CSIZE) {
974 case CS5:
975 newline.bDataBits = 5;
976 break;
977 case CS6:
978 newline.bDataBits = 6;
979 break;
980 case CS7:
981 newline.bDataBits = 7;
982 break;
983 case CS8:
984 default:
985 newline.bDataBits = 8;
986 break;
987 }
Alan Cox6e47e062009-06-11 12:37:06 +0100988 /* FIXME: Needs to clear unsupported bits in the termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
990
991 if (!newline.dwDTERate) {
992 newline.dwDTERate = acm->line.dwDTERate;
993 newctrl &= ~ACM_CTRL_DTR;
Alan Cox6e47e062009-06-11 12:37:06 +0100994 } else
995 newctrl |= ACM_CTRL_DTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996
997 if (newctrl != acm->ctrlout)
998 acm_set_control(acm, acm->ctrlout = newctrl);
999
1000 if (memcmp(&acm->line, &newline, sizeof newline)) {
1001 memcpy(&acm->line, &newline, sizeof newline);
Johan Hovolda5cc7ef2011-03-22 11:12:15 +01001002 dev_dbg(&acm->control->dev, "%s - set line: %d %d %d %d\n",
1003 __func__,
1004 le32_to_cpu(newline.dwDTERate),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 newline.bCharFormat, newline.bParityType,
1006 newline.bDataBits);
1007 acm_set_line(acm, &acm->line);
1008 }
1009}
1010
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001011static const struct tty_port_operations acm_port_ops = {
1012 .shutdown = acm_port_shutdown,
1013 .activate = acm_port_activate,
1014 .destruct = acm_port_destruct,
1015};
1016
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017/*
1018 * USB probe and disconnect routines.
1019 */
1020
Oliver Neukum830f4022008-06-25 14:17:16 +02001021/* Little helpers: write/read buffers free */
Oliver Neukum884b6002005-04-21 21:28:02 +02001022static void acm_write_buffers_free(struct acm *acm)
1023{
1024 int i;
1025 struct acm_wb *wb;
Oliver Neukuma496c642008-10-21 10:39:04 +02001026 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
Oliver Neukum884b6002005-04-21 21:28:02 +02001027
Alan Cox6e47e062009-06-11 12:37:06 +01001028 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++)
Daniel Mack997ea582010-04-12 13:17:25 +02001029 usb_free_coherent(usb_dev, acm->writesize, wb->buf, wb->dmah);
Oliver Neukum884b6002005-04-21 21:28:02 +02001030}
1031
Oliver Neukum830f4022008-06-25 14:17:16 +02001032static void acm_read_buffers_free(struct acm *acm)
1033{
1034 struct usb_device *usb_dev = interface_to_usbdev(acm->control);
Johan Hovolddab54c92011-03-22 11:12:21 +01001035 int i;
Oliver Neukum830f4022008-06-25 14:17:16 +02001036
Johan Hovolddab54c92011-03-22 11:12:21 +01001037 for (i = 0; i < acm->rx_buflimit; i++)
Daniel Mack997ea582010-04-12 13:17:25 +02001038 usb_free_coherent(usb_dev, acm->readsize,
Johan Hovold088c64f2011-03-25 11:06:02 +01001039 acm->read_buffers[i].base, acm->read_buffers[i].dma);
Oliver Neukum830f4022008-06-25 14:17:16 +02001040}
1041
Oliver Neukum884b6002005-04-21 21:28:02 +02001042/* Little helper: write buffers allocate */
1043static int acm_write_buffers_alloc(struct acm *acm)
1044{
1045 int i;
1046 struct acm_wb *wb;
1047
Oliver Neukum86478942006-05-13 22:50:47 +02001048 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Daniel Mack997ea582010-04-12 13:17:25 +02001049 wb->buf = usb_alloc_coherent(acm->dev, acm->writesize, GFP_KERNEL,
Oliver Neukum884b6002005-04-21 21:28:02 +02001050 &wb->dmah);
1051 if (!wb->buf) {
1052 while (i != 0) {
1053 --i;
1054 --wb;
Daniel Mack997ea582010-04-12 13:17:25 +02001055 usb_free_coherent(acm->dev, acm->writesize,
Oliver Neukum884b6002005-04-21 21:28:02 +02001056 wb->buf, wb->dmah);
1057 }
1058 return -ENOMEM;
1059 }
1060 }
1061 return 0;
1062}
1063
Alan Cox10077d42009-06-11 12:36:09 +01001064static int acm_probe(struct usb_interface *intf,
1065 const struct usb_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066{
1067 struct usb_cdc_union_desc *union_header = NULL;
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001068 struct usb_cdc_country_functional_desc *cfd = NULL;
David Brownellc6dbf552008-04-13 14:00:44 -07001069 unsigned char *buffer = intf->altsetting->extra;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 int buflen = intf->altsetting->extralen;
1071 struct usb_interface *control_interface;
1072 struct usb_interface *data_interface;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001073 struct usb_endpoint_descriptor *epctrl = NULL;
1074 struct usb_endpoint_descriptor *epread = NULL;
1075 struct usb_endpoint_descriptor *epwrite = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 struct usb_device *usb_dev = interface_to_usbdev(intf);
1077 struct acm *acm;
1078 int minor;
Alan Cox6e47e062009-06-11 12:37:06 +01001079 int ctrlsize, readsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 u8 *buf;
1081 u8 ac_management_function = 0;
1082 u8 call_management_function = 0;
1083 int call_interface_num = -1;
Erik Slagterfd5054c2011-05-11 12:06:55 +02001084 int data_interface_num = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 unsigned long quirks;
Oliver Neukum86478942006-05-13 22:50:47 +02001086 int num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +01001087 int i;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001088 int combined_interfaces = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
Oliver Neukum86478942006-05-13 22:50:47 +02001090 /* normal quirks */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 quirks = (unsigned long)id->driver_info;
Oliver Neukum86478942006-05-13 22:50:47 +02001092 num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
1093
flintmanc6dc72f2014-08-11 21:52:25 -04001094 /* MBM, Not a real CDC ACM device */
1095 if (quirks == NOT_REAL_ACM)
1096 return -ENODEV;
1097
Oliver Neukum86478942006-05-13 22:50:47 +02001098 /* handle quirks deadly to normal probing*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 if (quirks == NO_UNION_NORMAL) {
1100 data_interface = usb_ifnum_to_if(usb_dev, 1);
1101 control_interface = usb_ifnum_to_if(usb_dev, 0);
1102 goto skip_normal_probe;
1103 }
Alan Cox6e47e062009-06-11 12:37:06 +01001104
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 /* normal probing*/
1106 if (!buffer) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001107 dev_err(&intf->dev, "Weird descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 return -EINVAL;
1109 }
1110
1111 if (!buflen) {
flintmanc6dc72f2014-08-11 21:52:25 -04001112#ifndef CONFIG_MACH_TENDERLOIN
Toby Gray577045c2010-09-02 10:46:20 +01001113 if (intf->cur_altsetting->endpoint &&
1114 intf->cur_altsetting->endpoint->extralen &&
Alan Cox6e47e062009-06-11 12:37:06 +01001115 intf->cur_altsetting->endpoint->extra) {
flintmanc6dc72f2014-08-11 21:52:25 -04001116#else
1117 /* MBM */
1118 if (intf->cur_altsetting->endpoint->extralen &&
1119 intf->cur_altsetting->endpoint->extra) {
1120#endif
Alan Cox6e47e062009-06-11 12:37:06 +01001121 dev_dbg(&intf->dev,
1122 "Seeking extra descriptors on endpoint\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 buflen = intf->cur_altsetting->endpoint->extralen;
1124 buffer = intf->cur_altsetting->endpoint->extra;
1125 } else {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001126 dev_err(&intf->dev,
1127 "Zero length descriptor references\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 return -EINVAL;
1129 }
1130 }
1131
1132 while (buflen > 0) {
Alan Cox6e47e062009-06-11 12:37:06 +01001133 if (buffer[1] != USB_DT_CS_INTERFACE) {
Greg Kroah-Hartman9908a322008-08-14 09:37:34 -07001134 dev_err(&intf->dev, "skipping garbage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 goto next_desc;
1136 }
1137
Alan Cox6e47e062009-06-11 12:37:06 +01001138 switch (buffer[2]) {
1139 case USB_CDC_UNION_TYPE: /* we've found it */
1140 if (union_header) {
1141 dev_err(&intf->dev, "More than one "
1142 "union descriptor, skipping ...\n");
1143 goto next_desc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 }
Alan Cox6e47e062009-06-11 12:37:06 +01001145 union_header = (struct usb_cdc_union_desc *)buffer;
1146 break;
1147 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
1148 cfd = (struct usb_cdc_country_functional_desc *)buffer;
1149 break;
1150 case USB_CDC_HEADER_TYPE: /* maybe check version */
1151 break; /* for now we ignore it */
1152 case USB_CDC_ACM_TYPE:
1153 ac_management_function = buffer[3];
1154 break;
1155 case USB_CDC_CALL_MANAGEMENT_TYPE:
1156 call_management_function = buffer[3];
1157 call_interface_num = buffer[4];
Julian Calabyce126642010-01-05 23:58:20 +11001158 if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
Alan Cox6e47e062009-06-11 12:37:06 +01001159 dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
1160 break;
1161 default:
1162 /* there are LOTS more CDC descriptors that
1163 * could legitimately be found here.
1164 */
1165 dev_dbg(&intf->dev, "Ignoring descriptor: "
1166 "type %02x, length %d\n",
1167 buffer[2], buffer[0]);
1168 break;
1169 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170next_desc:
1171 buflen -= buffer[0];
1172 buffer += buffer[0];
1173 }
1174
1175 if (!union_header) {
1176 if (call_interface_num > 0) {
Alan Cox6e47e062009-06-11 12:37:06 +01001177 dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
Erik Slagterfd5054c2011-05-11 12:06:55 +02001178 /* quirks for Droids MuIn LCD */
1179 if (quirks & NO_DATA_INTERFACE)
1180 data_interface = usb_ifnum_to_if(usb_dev, 0);
1181 else
1182 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 control_interface = intf;
1184 } else {
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001185 if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
1186 dev_dbg(&intf->dev,"No union descriptor, giving up\n");
1187 return -ENODEV;
1188 } else {
1189 dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n");
1190 combined_interfaces = 1;
1191 control_interface = data_interface = intf;
1192 goto look_for_collapsed_interface;
1193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 }
1195 } else {
1196 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
1197 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
1198 if (!control_interface || !data_interface) {
Alan Cox6e47e062009-06-11 12:37:06 +01001199 dev_dbg(&intf->dev, "no interfaces\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 return -ENODEV;
1201 }
1202 }
Alan Cox6e47e062009-06-11 12:37:06 +01001203
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 if (data_interface_num != call_interface_num)
Alan Cox6e47e062009-06-11 12:37:06 +01001205 dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001207 if (control_interface == data_interface) {
1208 /* some broken devices designed for windows work this way */
1209 dev_warn(&intf->dev,"Control and data interfaces are not separated!\n");
1210 combined_interfaces = 1;
1211 /* a popular other OS doesn't use it */
1212 quirks |= NO_CAP_LINE;
1213 if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) {
1214 dev_err(&intf->dev, "This needs exactly 3 endpoints\n");
1215 return -EINVAL;
1216 }
1217look_for_collapsed_interface:
1218 for (i = 0; i < 3; i++) {
1219 struct usb_endpoint_descriptor *ep;
1220 ep = &data_interface->cur_altsetting->endpoint[i].desc;
1221
1222 if (usb_endpoint_is_int_in(ep))
1223 epctrl = ep;
1224 else if (usb_endpoint_is_bulk_out(ep))
1225 epwrite = ep;
1226 else if (usb_endpoint_is_bulk_in(ep))
1227 epread = ep;
1228 else
1229 return -EINVAL;
1230 }
1231 if (!epctrl || !epread || !epwrite)
1232 return -ENODEV;
1233 else
1234 goto made_compressed_probe;
1235 }
1236
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237skip_normal_probe:
1238
1239 /*workaround for switched interfaces */
Alan Cox6e47e062009-06-11 12:37:06 +01001240 if (data_interface->cur_altsetting->desc.bInterfaceClass
1241 != CDC_DATA_INTERFACE_TYPE) {
1242 if (control_interface->cur_altsetting->desc.bInterfaceClass
1243 == CDC_DATA_INTERFACE_TYPE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 struct usb_interface *t;
Alan Cox6e47e062009-06-11 12:37:06 +01001245 dev_dbg(&intf->dev,
1246 "Your device has switched interfaces.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 t = control_interface;
1248 control_interface = data_interface;
1249 data_interface = t;
1250 } else {
1251 return -EINVAL;
1252 }
1253 }
Alan Stern74da5d62007-08-02 13:29:10 -04001254
1255 /* Accept probe requests only for the control interface */
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001256 if (!combined_interfaces && intf != control_interface)
Alan Stern74da5d62007-08-02 13:29:10 -04001257 return -ENODEV;
Alan Cox6e47e062009-06-11 12:37:06 +01001258
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001259 if (!combined_interfaces && usb_interface_claimed(data_interface)) {
1260 /* valid in this context */
Alan Cox6e47e062009-06-11 12:37:06 +01001261 dev_dbg(&intf->dev, "The data interface isn't available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 return -EBUSY;
1263 }
1264
1265
Sven Schnellea9959bb2012-08-17 21:43:43 +02001266 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2 ||
1267 control_interface->cur_altsetting->desc.bNumEndpoints == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 return -EINVAL;
1269
1270 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
1271 epread = &data_interface->cur_altsetting->endpoint[0].desc;
1272 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
1273
1274
1275 /* workaround for switched endpoints */
Luiz Fernando N. Capitulino45aea702006-10-26 13:02:48 -03001276 if (!usb_endpoint_dir_in(epread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 /* descriptors are swapped */
1278 struct usb_endpoint_descriptor *t;
Alan Cox6e47e062009-06-11 12:37:06 +01001279 dev_dbg(&intf->dev,
1280 "The data interface has switched endpoints\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 t = epread;
1282 epread = epwrite;
1283 epwrite = t;
1284 }
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001285made_compressed_probe:
Johan Hovolda5cc7ef2011-03-22 11:12:15 +01001286 dev_dbg(&intf->dev, "interfaces are valid\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287
Alan Cox6e47e062009-06-11 12:37:06 +01001288 acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
1289 if (acm == NULL) {
Johan Hovold255ab562011-03-22 11:12:13 +01001290 dev_err(&intf->dev, "out of memory (acm kzalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 goto alloc_fail;
1292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001294 minor = acm_alloc_minor(acm);
1295 if (minor == ACM_TTY_MINORS) {
1296 dev_err(&intf->dev, "no more free acm devices\n");
1297 kfree(acm);
1298 return -ENODEV;
1299 }
1300
Kuninori Morimoto29cc8892011-08-23 03:12:03 -07001301 ctrlsize = usb_endpoint_maxp(epctrl);
1302 readsize = usb_endpoint_maxp(epread) *
flintmanc6dc72f2014-08-11 21:52:25 -04001303#ifndef CONFIG_MACH_TENDERLOIN
Alan Cox6e47e062009-06-11 12:37:06 +01001304 (quirks == SINGLE_RX_URB ? 1 : 2);
flintmanc6dc72f2014-08-11 21:52:25 -04001305#else
1306 /* MBM */
1307 (quirks == SINGLE_RX_URB ? 1 : 4);
1308#endif
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001309 acm->combined_interfaces = combined_interfaces;
Kuninori Morimoto29cc8892011-08-23 03:12:03 -07001310 acm->writesize = usb_endpoint_maxp(epwrite) * 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 acm->control = control_interface;
1312 acm->data = data_interface;
1313 acm->minor = minor;
1314 acm->dev = usb_dev;
1315 acm->ctrl_caps = ac_management_function;
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001316 if (quirks & NO_CAP_LINE)
1317 acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 acm->ctrlsize = ctrlsize;
1319 acm->readsize = readsize;
Oliver Neukum86478942006-05-13 22:50:47 +02001320 acm->rx_buflimit = num_rx_buf;
David Howellsc4028952006-11-22 14:57:56 +00001321 INIT_WORK(&acm->work, acm_softint);
Oliver Neukum884b6002005-04-21 21:28:02 +02001322 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +01001323 spin_lock_init(&acm->read_lock);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001324 mutex_init(&acm->mutex);
David Kubicek61a87ad2005-11-01 18:51:34 +01001325 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Oliver Neukumcf7fdd52009-08-04 23:52:09 +02001326 acm->is_int_ep = usb_endpoint_xfer_int(epread);
1327 if (acm->is_int_ep)
1328 acm->bInterval = epread->bInterval;
Alan Cox739e0282009-06-11 12:27:50 +01001329 tty_port_init(&acm->port);
1330 acm->port.ops = &acm_port_ops;
flintmanc6dc72f2014-08-11 21:52:25 -04001331#ifdef CONFIG_MACH_TENDERLOIN
1332 /* MBM */
1333 acm->response = usb_alloc_urb(0, GFP_KERNEL);
1334 if (!acm->response) {
1335 dev_dbg(&intf->dev, "out of memory (response kmalloc)\n");
1336 goto alloc_fail2;
1337 }
1338
1339 /* MBM */
1340 acm->bMaxPacketSize0 = usb_dev->descriptor.bMaxPacketSize0;
1341 acm->inbuf = usb_alloc_coherent(usb_dev,
1342 acm->bMaxPacketSize0,
1343 GFP_KERNEL,
1344 &acm->response->transfer_dma);
1345 /* MBM */
1346 if (!acm->inbuf) {
1347 dev_dbg(&intf->dev, "out of memory (inbuf kmalloc)\n");
1348 goto alloc_fail3;
1349 }
1350#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Daniel Mack997ea582010-04-12 13:17:25 +02001352 buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 if (!buf) {
Johan Hovold255ab562011-03-22 11:12:13 +01001354 dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n");
flintmanc6dc72f2014-08-11 21:52:25 -04001355#ifndef CONFIG_MACH_TENDERLOIN
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 goto alloc_fail2;
flintmanc6dc72f2014-08-11 21:52:25 -04001357#else
1358 /* MBM */
1359 goto alloc_fail3_1;
1360#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 }
1362 acm->ctrl_buffer = buf;
1363
Oliver Neukum884b6002005-04-21 21:28:02 +02001364 if (acm_write_buffers_alloc(acm) < 0) {
Johan Hovold255ab562011-03-22 11:12:13 +01001365 dev_err(&intf->dev, "out of memory (write buffer alloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 goto alloc_fail4;
1367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
1369 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
1370 if (!acm->ctrlurb) {
Johan Hovold255ab562011-03-22 11:12:13 +01001371 dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 goto alloc_fail5;
1373 }
Oliver Neukum86478942006-05-13 22:50:47 +02001374 for (i = 0; i < num_rx_buf; i++) {
Johan Hovold088c64f2011-03-25 11:06:02 +01001375 struct acm_rb *rb = &(acm->read_buffers[i]);
1376 struct urb *urb;
David Kubicek61a87ad2005-11-01 18:51:34 +01001377
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001378 rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
1379 &rb->dma);
1380 if (!rb->base) {
1381 dev_err(&intf->dev, "out of memory "
1382 "(read bufs usb_alloc_coherent)\n");
1383 goto alloc_fail6;
1384 }
Johan Hovold088c64f2011-03-25 11:06:02 +01001385 rb->index = i;
1386 rb->instance = acm;
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001387
Johan Hovold088c64f2011-03-25 11:06:02 +01001388 urb = usb_alloc_urb(0, GFP_KERNEL);
1389 if (!urb) {
Johan Hovold255ab562011-03-22 11:12:13 +01001390 dev_err(&intf->dev,
Alan Cox6e47e062009-06-11 12:37:06 +01001391 "out of memory (read urbs usb_alloc_urb)\n");
Axel Linc2572b72010-05-31 08:04:47 +08001392 goto alloc_fail6;
David Kubicek61a87ad2005-11-01 18:51:34 +01001393 }
Johan Hovold088c64f2011-03-25 11:06:02 +01001394 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1395 urb->transfer_dma = rb->dma;
1396 if (acm->is_int_ep) {
1397 usb_fill_int_urb(urb, acm->dev,
1398 acm->rx_endpoint,
1399 rb->base,
1400 acm->readsize,
1401 acm_read_bulk_callback, rb,
1402 acm->bInterval);
1403 } else {
1404 usb_fill_bulk_urb(urb, acm->dev,
1405 acm->rx_endpoint,
1406 rb->base,
1407 acm->readsize,
1408 acm_read_bulk_callback, rb);
1409 }
David Kubicek61a87ad2005-11-01 18:51:34 +01001410
Johan Hovold088c64f2011-03-25 11:06:02 +01001411 acm->read_urbs[i] = urb;
1412 __set_bit(i, &acm->read_urbs_free);
David Kubicek61a87ad2005-11-01 18:51:34 +01001413 }
Alan Cox6e47e062009-06-11 12:37:06 +01001414 for (i = 0; i < ACM_NW; i++) {
David Engrafe4cf3aa2008-03-20 10:01:34 +01001415 struct acm_wb *snd = &(acm->wb[i]);
1416
Alan Cox6e47e062009-06-11 12:37:06 +01001417 snd->urb = usb_alloc_urb(0, GFP_KERNEL);
1418 if (snd->urb == NULL) {
Johan Hovold255ab562011-03-22 11:12:13 +01001419 dev_err(&intf->dev,
Johan Hovold59d7fec2011-03-22 11:12:12 +01001420 "out of memory (write urbs usb_alloc_urb)\n");
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001421 goto alloc_fail7;
David Engrafe4cf3aa2008-03-20 10:01:34 +01001422 }
1423
Arseniy Lartsev5186ffe2009-07-01 16:27:26 +04001424 if (usb_endpoint_xfer_int(epwrite))
1425 usb_fill_int_urb(snd->urb, usb_dev,
Ming Leie83863d2012-10-16 21:21:21 +08001426 usb_sndintpipe(usb_dev, epwrite->bEndpointAddress),
Arseniy Lartsev5186ffe2009-07-01 16:27:26 +04001427 NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval);
1428 else
1429 usb_fill_bulk_urb(snd->urb, usb_dev,
1430 usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
1431 NULL, acm->writesize, acm_write_bulk, snd);
David Engrafe4cf3aa2008-03-20 10:01:34 +01001432 snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1433 snd->instance = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 }
1435
Alan Cox6e47e062009-06-11 12:37:06 +01001436 usb_set_intfdata(intf, acm);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001437
1438 i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
1439 if (i < 0)
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001440 goto alloc_fail7;
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001441
1442 if (cfd) { /* export the country data */
1443 acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
1444 if (!acm->country_codes)
1445 goto skip_countries;
1446 acm->country_code_size = cfd->bLength - 4;
Alan Cox6e47e062009-06-11 12:37:06 +01001447 memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0,
1448 cfd->bLength - 4);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001449 acm->country_rel_date = cfd->iCountryCodeRelDate;
1450
1451 i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
1452 if (i < 0) {
1453 kfree(acm->country_codes);
Julia Lawalle7c8e862011-12-23 14:02:55 +01001454 acm->country_codes = NULL;
1455 acm->country_code_size = 0;
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001456 goto skip_countries;
1457 }
1458
Alan Cox6e47e062009-06-11 12:37:06 +01001459 i = device_create_file(&intf->dev,
1460 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001461 if (i < 0) {
Axel Linc2572b72010-05-31 08:04:47 +08001462 device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001463 kfree(acm->country_codes);
Julia Lawalle7c8e862011-12-23 14:02:55 +01001464 acm->country_codes = NULL;
1465 acm->country_code_size = 0;
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001466 goto skip_countries;
1467 }
1468 }
1469
1470skip_countries:
Alan Cox6e47e062009-06-11 12:37:06 +01001471 usb_fill_int_urb(acm->ctrlurb, usb_dev,
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001472 usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
1473 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
1474 /* works around buggy devices */
1475 epctrl->bInterval ? epctrl->bInterval : 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1477 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
flintmanc6dc72f2014-08-11 21:52:25 -04001478#ifdef CONFIG_MACH_TENDERLOIN
1479 /* MBM */
1480 acm->ctrlurb->dev = acm->dev;
1481 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
1482 dev_err(&intf->dev, "usb_submit_urb(ctrl irq) failed");
1483 goto kill_urb;
1484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
flintmanc6dc72f2014-08-11 21:52:25 -04001486 /* MBM */
1487 acm->irq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
1488 if (!acm->irq)
1489 goto kill_urb;
1490#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
1492
1493 acm_set_control(acm, acm->ctrlout);
flintmanc6dc72f2014-08-11 21:52:25 -04001494#ifndef CONFIG_MACH_TENDERLOIN
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 acm->line.dwDTERate = cpu_to_le32(9600);
flintmanc6dc72f2014-08-11 21:52:25 -04001496#else
1497 acm->line.dwDTERate = cpu_to_le32(115200);
1498#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 acm->line.bDataBits = 8;
1500 acm_set_line(acm, &acm->line);
flintmanc6dc72f2014-08-11 21:52:25 -04001501#ifdef CONFIG_MACH_TENDERLOIN
1502 /* MBM */
1503 acm->state |= ACM_ABS_IDLE;
1504 acm_set_comm_feature(acm, ACM_ABSTRACT_STATE, &acm->state);
1505#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506
1507 usb_driver_claim_interface(&acm_driver, data_interface, acm);
David Brownell672c4e12008-08-06 18:41:12 -07001508 usb_set_intfdata(data_interface, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001510 usb_get_intf(control_interface);
1511 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001513 return 0;
flintmanc6dc72f2014-08-11 21:52:25 -04001514#ifdef CONFIG_MACH_TENDERLOIN
1515 /* MBM */
1516kill_urb:
1517 usb_kill_urb(acm->ctrlurb);
1518#endif
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001519alloc_fail7:
David Engrafe4cf3aa2008-03-20 10:01:34 +01001520 for (i = 0; i < ACM_NW; i++)
1521 usb_free_urb(acm->wb[i].urb);
Axel Linc2572b72010-05-31 08:04:47 +08001522alloc_fail6:
Oliver Neukum86478942006-05-13 22:50:47 +02001523 for (i = 0; i < num_rx_buf; i++)
Johan Hovold088c64f2011-03-25 11:06:02 +01001524 usb_free_urb(acm->read_urbs[i]);
Johan Hovold74f5e1b2011-03-22 11:12:23 +01001525 acm_read_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 usb_free_urb(acm->ctrlurb);
1527alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001528 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529alloc_fail4:
Daniel Mack997ea582010-04-12 13:17:25 +02001530 usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
flintmanc6dc72f2014-08-11 21:52:25 -04001531#ifdef CONFIG_MACH_TENDERLOIN
1532 /* MBM */
1533alloc_fail3_1:
1534 usb_free_coherent(usb_dev,acm->bMaxPacketSize0, acm->inbuf, acm->response->transfer_dma);
1535alloc_fail3:
1536 usb_free_urb(acm->response);
1537#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538alloc_fail2:
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001539 acm_release_minor(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 kfree(acm);
1541alloc_fail:
1542 return -ENOMEM;
1543}
1544
Oliver Neukum1365baf2007-10-12 17:24:28 +02001545static void stop_data_traffic(struct acm *acm)
1546{
1547 int i;
Johan Hovolda5cc7ef2011-03-22 11:12:15 +01001548
1549 dev_dbg(&acm->control->dev, "%s\n", __func__);
flintmanc6dc72f2014-08-11 21:52:25 -04001550#ifndef CONFIG_MACH_TENDERLOIN
Oliver Neukum1365baf2007-10-12 17:24:28 +02001551 usb_kill_urb(acm->ctrlurb);
flintmanc6dc72f2014-08-11 21:52:25 -04001552#endif
Alan Cox6e47e062009-06-11 12:37:06 +01001553 for (i = 0; i < ACM_NW; i++)
David Engrafe4cf3aa2008-03-20 10:01:34 +01001554 usb_kill_urb(acm->wb[i].urb);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001555 for (i = 0; i < acm->rx_buflimit; i++)
Johan Hovold088c64f2011-03-25 11:06:02 +01001556 usb_kill_urb(acm->read_urbs[i]);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001557
1558 cancel_work_sync(&acm->work);
1559}
1560
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561static void acm_disconnect(struct usb_interface *intf)
1562{
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001563 struct acm *acm = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 struct usb_device *usb_dev = interface_to_usbdev(intf);
Alan Cox10077d42009-06-11 12:36:09 +01001565 struct tty_struct *tty;
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001566 int i;
1567
1568 dev_dbg(&intf->dev, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569
David Brownell672c4e12008-08-06 18:41:12 -07001570 /* sibling interface is already cleaning up */
1571 if (!acm)
Oliver Neukum86067eea2006-01-08 12:39:13 +01001572 return;
David Brownell672c4e12008-08-06 18:41:12 -07001573
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001574 mutex_lock(&acm->mutex);
1575 acm->disconnected = true;
Alan Cox6e47e062009-06-11 12:37:06 +01001576 if (acm->country_codes) {
Alan Stern74da5d62007-08-02 13:29:10 -04001577 device_remove_file(&acm->control->dev,
1578 &dev_attr_wCountryCodes);
1579 device_remove_file(&acm->control->dev,
1580 &dev_attr_iCountryCodeRelDate);
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001581 }
Alan Stern74da5d62007-08-02 13:29:10 -04001582 device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
Oliver Neukum86067eea2006-01-08 12:39:13 +01001583 usb_set_intfdata(acm->control, NULL);
1584 usb_set_intfdata(acm->data, NULL);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001585 mutex_unlock(&acm->mutex);
1586
1587 tty = tty_port_tty_get(&acm->port);
1588 if (tty) {
1589 tty_vhangup(tty);
1590 tty_kref_put(tty);
1591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
Oliver Neukum1365baf2007-10-12 17:24:28 +02001593 stop_data_traffic(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594
Johan Hovold10a00e32013-03-19 09:21:06 +01001595 tty_unregister_device(acm_tty_driver, acm->minor);
1596
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001597 usb_free_urb(acm->ctrlurb);
1598 for (i = 0; i < ACM_NW; i++)
1599 usb_free_urb(acm->wb[i].urb);
1600 for (i = 0; i < acm->rx_buflimit; i++)
1601 usb_free_urb(acm->read_urbs[i]);
Oliver Neukum884b6002005-04-21 21:28:02 +02001602 acm_write_buffers_free(acm);
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001603 usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Oliver Neukum830f4022008-06-25 14:17:16 +02001604 acm_read_buffers_free(acm);
flintmanc6dc72f2014-08-11 21:52:25 -04001605#ifdef CONFIG_MACH_TENDERLOIN
1606 /* MBM */
1607 usb_free_coherent(usb_dev,acm->bMaxPacketSize0, acm->inbuf, acm->response->transfer_dma);
1608#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
Oliver Neukuma2bfb4a2009-05-16 21:13:19 +02001610 if (!acm->combined_interfaces)
1611 usb_driver_release_interface(&acm_driver, intf == acm->control ?
Oliver Neukum830f4022008-06-25 14:17:16 +02001612 acm->data : acm->control);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001614 tty_port_put(&acm->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615}
1616
Oliver Neukum35758582008-07-01 19:10:08 +02001617#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001618static int acm_suspend(struct usb_interface *intf, pm_message_t message)
1619{
1620 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001621 int cnt;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001622
Alan Stern5b1b0b82011-08-19 23:49:48 +02001623 if (PMSG_IS_AUTO(message)) {
Oliver Neukum11ea8592008-06-20 11:25:57 +02001624 int b;
1625
Johan Hovold088c64f2011-03-25 11:06:02 +01001626 spin_lock_irq(&acm->write_lock);
1627 b = acm->transmitting;
1628 spin_unlock_irq(&acm->write_lock);
Oliver Neukum11ea8592008-06-20 11:25:57 +02001629 if (b)
1630 return -EBUSY;
1631 }
1632
1633 spin_lock_irq(&acm->read_lock);
1634 spin_lock(&acm->write_lock);
1635 cnt = acm->susp_count++;
1636 spin_unlock(&acm->write_lock);
1637 spin_unlock_irq(&acm->read_lock);
1638
1639 if (cnt)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001640 return 0;
flintmanc6dc72f2014-08-11 21:52:25 -04001641#ifdef CONFIG_MACH_TENDERLOIN
1642 /* MBM, Kill URB here! */
1643 usb_kill_urb(acm->ctrlurb);
1644#endif
Oliver Neukum1365baf2007-10-12 17:24:28 +02001645
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001646 if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
Oliver Neukum1365baf2007-10-12 17:24:28 +02001647 stop_data_traffic(acm);
1648
Oliver Neukum1365baf2007-10-12 17:24:28 +02001649 return 0;
1650}
1651
1652static int acm_resume(struct usb_interface *intf)
1653{
1654 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum97d35f92009-12-16 17:05:57 +01001655 struct acm_wb *wb;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001656 int rv = 0;
Oliver Neukum11ea8592008-06-20 11:25:57 +02001657 int cnt;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001658
Oliver Neukum11ea8592008-06-20 11:25:57 +02001659 spin_lock_irq(&acm->read_lock);
1660 acm->susp_count -= 1;
1661 cnt = acm->susp_count;
1662 spin_unlock_irq(&acm->read_lock);
1663
1664 if (cnt)
Oliver Neukum1365baf2007-10-12 17:24:28 +02001665 return 0;
flintmanc6dc72f2014-08-11 21:52:25 -04001666#ifdef CONFIG_MACH_TENDERLOIN
1667 /* MBM, We have to resubmit the INT URB regardless of the port is open or not */
1668 if (usb_submit_urb(acm->ctrlurb, GFP_NOIO)) {
1669 dev_err(&intf->dev, "usb_submit_urb(ctrl irq) failed");
1670 }
1671#endif
Oliver Neukum1365baf2007-10-12 17:24:28 +02001672
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001673 if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
flintmanc6dc72f2014-08-11 21:52:25 -04001674#ifndef CONFIG_MACH_TENDERLOIN
Oliver Neukum1365baf2007-10-12 17:24:28 +02001675 rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
flintmanc6dc72f2014-08-11 21:52:25 -04001676#endif
Oliver Neukum97d35f92009-12-16 17:05:57 +01001677 spin_lock_irq(&acm->write_lock);
1678 if (acm->delayed_wb) {
1679 wb = acm->delayed_wb;
1680 acm->delayed_wb = NULL;
1681 spin_unlock_irq(&acm->write_lock);
Oliver Neukumf0730922010-03-03 00:37:56 +01001682 acm_start_wb(acm, wb);
Oliver Neukum97d35f92009-12-16 17:05:57 +01001683 } else {
1684 spin_unlock_irq(&acm->write_lock);
1685 }
1686
1687 /*
1688 * delayed error checking because we must
1689 * do the write path at all cost
1690 */
Oliver Neukum1365baf2007-10-12 17:24:28 +02001691 if (rv < 0)
Oliver Neukum11ea8592008-06-20 11:25:57 +02001692 goto err_out;
Oliver Neukum1365baf2007-10-12 17:24:28 +02001693
Johan Hovold088c64f2011-03-25 11:06:02 +01001694 rv = acm_submit_read_urbs(acm, GFP_NOIO);
Oliver Neukum1365baf2007-10-12 17:24:28 +02001695 }
1696
1697err_out:
Oliver Neukum1365baf2007-10-12 17:24:28 +02001698 return rv;
1699}
Oliver Neukum35758582008-07-01 19:10:08 +02001700
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001701static int acm_reset_resume(struct usb_interface *intf)
1702{
1703 struct acm *acm = usb_get_intfdata(intf);
1704 struct tty_struct *tty;
1705
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001706 if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001707 tty = tty_port_tty_get(&acm->port);
1708 if (tty) {
1709 tty_hangup(tty);
1710 tty_kref_put(tty);
1711 }
1712 }
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001713
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001714 return acm_resume(intf);
1715}
1716
Oliver Neukum35758582008-07-01 19:10:08 +02001717#endif /* CONFIG_PM */
Adrian Taylorc1479a92009-11-19 10:35:33 +00001718
1719#define NOKIA_PCSUITE_ACM_INFO(x) \
1720 USB_DEVICE_AND_INTERFACE_INFO(0x0421, x, \
1721 USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \
1722 USB_CDC_ACM_PROTO_VENDOR)
1723
Toby Gray4035e452010-09-01 16:01:19 +01001724#define SAMSUNG_PCSUITE_ACM_INFO(x) \
1725 USB_DEVICE_AND_INTERFACE_INFO(0x04e7, x, \
1726 USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \
1727 USB_CDC_ACM_PROTO_VENDOR)
1728
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729/*
1730 * USB driver structure.
1731 */
1732
Németh Márton6ef48522010-01-10 15:33:45 +01001733static const struct usb_device_id acm_ids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 /* quirky and broken devices */
David Cluytensbd73e382013-12-03 14:18:57 +01001735 { USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */
1736 .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1738 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1739 },
Andrey Arapovb0e2a702007-07-04 17:11:42 +02001740 { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
1741 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1742 },
Andrew Lunn0f9c7b42008-12-23 17:31:23 +01001743 { USB_DEVICE(0x0e8d, 0x3329), /* MediaTek Inc GPS */
1744 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1745 },
Masahito Omote8753e652005-07-29 12:17:25 -07001746 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1747 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1748 },
Chris Malley91a9c922006-10-03 10:08:28 +01001749 { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
1750 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1751 },
Alan Cox7abcf202009-04-06 17:35:01 +01001752 { USB_DEVICE(0x0ace, 0x1602), /* ZyDAS 56K USB MODEM */
1753 .driver_info = SINGLE_RX_URB,
1754 },
Oliver Neukum86478942006-05-13 22:50:47 +02001755 { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
1756 .driver_info = SINGLE_RX_URB, /* firmware bug */
1757 },
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001758 { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
1759 .driver_info = SINGLE_RX_URB, /* firmware bug */
1760 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001761 { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
1762 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1763 },
Iain McFarlane6149ed52008-05-04 00:13:49 +01001764 { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */
1765 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1766 },
Eric Sandeenc8fd2c32008-08-14 08:25:40 -05001767 { USB_DEVICE(0x0572, 0x1321), /* Conexant USB MODEM CX93010 */
1768 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1769 },
Alan Coxc89c60e2009-01-11 19:53:10 +00001770 { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */
1771 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1772 },
Xiao Kaijiancab98a02009-05-08 00:48:23 +08001773 { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */
1774 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1775 },
Dmitriy Taychenachev155df652009-02-25 12:36:51 +08001776 { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
1777 },
Krzysztof Hałasa6abff5d2011-12-12 14:51:00 +01001778 /* Motorola H24 HSPA module: */
1779 { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */
1780 { USB_DEVICE(0x22b8, 0x2d92) }, /* modem + diagnostics */
1781 { USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port */
1782 { USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics */
1783 { USB_DEVICE(0x22b8, 0x2d96) }, /* modem + NMEA */
1784 { USB_DEVICE(0x22b8, 0x2d97) }, /* modem + diagnostics + NMEA */
1785 { USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port + NMEA */
1786 { USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */
1787
Adam Richterc332b4e2009-02-18 16:17:15 -08001788 { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */
1789 .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on
1790 data interface instead of
1791 communications interface.
1792 Maybe we should define a new
1793 quirk for this. */
1794 },
Jean-Christian de Rivaz52538352012-10-10 12:49:02 +00001795 { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */
1796 .driver_info = NO_UNION_NORMAL,
1797 },
Denis N Ladinb756d752012-12-26 18:29:44 +05001798 { USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */
1799 .driver_info = NO_UNION_NORMAL,
1800 },
Kir Kolyshkin1f17c502009-05-28 20:33:58 +04001801 { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */
1802 .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
1803 },
Russ Nelsonc3baa192010-04-21 23:07:03 -04001804 { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */
1805 .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
1806 },
flintmanc6dc72f2014-08-11 21:52:25 -04001807 /* MBM */
1808 { USB_DEVICE(0x1519, 0x0020), /* IMC_MAIN - XMM6260, XMM6262 */
1809 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1810 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001811
Adrian Taylorc1479a92009-11-19 10:35:33 +00001812 /* Nokia S60 phones expose two ACM channels. The first is
1813 * a modem and is picked up by the standard AT-command
1814 * information below. The second is 'vendor-specific' but
1815 * is treated as a serial device at the S60 end, so we want
1816 * to expose it on Linux too. */
1817 { NOKIA_PCSUITE_ACM_INFO(0x042D), }, /* Nokia 3250 */
1818 { NOKIA_PCSUITE_ACM_INFO(0x04D8), }, /* Nokia 5500 Sport */
1819 { NOKIA_PCSUITE_ACM_INFO(0x04C9), }, /* Nokia E50 */
1820 { NOKIA_PCSUITE_ACM_INFO(0x0419), }, /* Nokia E60 */
1821 { NOKIA_PCSUITE_ACM_INFO(0x044D), }, /* Nokia E61 */
1822 { NOKIA_PCSUITE_ACM_INFO(0x0001), }, /* Nokia E61i */
1823 { NOKIA_PCSUITE_ACM_INFO(0x0475), }, /* Nokia E62 */
1824 { NOKIA_PCSUITE_ACM_INFO(0x0508), }, /* Nokia E65 */
1825 { NOKIA_PCSUITE_ACM_INFO(0x0418), }, /* Nokia E70 */
1826 { NOKIA_PCSUITE_ACM_INFO(0x0425), }, /* Nokia N71 */
1827 { NOKIA_PCSUITE_ACM_INFO(0x0486), }, /* Nokia N73 */
1828 { NOKIA_PCSUITE_ACM_INFO(0x04DF), }, /* Nokia N75 */
1829 { NOKIA_PCSUITE_ACM_INFO(0x000e), }, /* Nokia N77 */
1830 { NOKIA_PCSUITE_ACM_INFO(0x0445), }, /* Nokia N80 */
1831 { NOKIA_PCSUITE_ACM_INFO(0x042F), }, /* Nokia N91 & N91 8GB */
1832 { NOKIA_PCSUITE_ACM_INFO(0x048E), }, /* Nokia N92 */
1833 { NOKIA_PCSUITE_ACM_INFO(0x0420), }, /* Nokia N93 */
1834 { NOKIA_PCSUITE_ACM_INFO(0x04E6), }, /* Nokia N93i */
1835 { NOKIA_PCSUITE_ACM_INFO(0x04B2), }, /* Nokia 5700 XpressMusic */
1836 { NOKIA_PCSUITE_ACM_INFO(0x0134), }, /* Nokia 6110 Navigator (China) */
1837 { NOKIA_PCSUITE_ACM_INFO(0x046E), }, /* Nokia 6110 Navigator */
1838 { NOKIA_PCSUITE_ACM_INFO(0x002f), }, /* Nokia 6120 classic & */
1839 { NOKIA_PCSUITE_ACM_INFO(0x0088), }, /* Nokia 6121 classic */
1840 { NOKIA_PCSUITE_ACM_INFO(0x00fc), }, /* Nokia 6124 classic */
1841 { NOKIA_PCSUITE_ACM_INFO(0x0042), }, /* Nokia E51 */
1842 { NOKIA_PCSUITE_ACM_INFO(0x00b0), }, /* Nokia E66 */
1843 { NOKIA_PCSUITE_ACM_INFO(0x00ab), }, /* Nokia E71 */
1844 { NOKIA_PCSUITE_ACM_INFO(0x0481), }, /* Nokia N76 */
1845 { NOKIA_PCSUITE_ACM_INFO(0x0007), }, /* Nokia N81 & N81 8GB */
1846 { NOKIA_PCSUITE_ACM_INFO(0x0071), }, /* Nokia N82 */
1847 { NOKIA_PCSUITE_ACM_INFO(0x04F0), }, /* Nokia N95 & N95-3 NAM */
1848 { NOKIA_PCSUITE_ACM_INFO(0x0070), }, /* Nokia N95 8GB */
1849 { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */
1850 { NOKIA_PCSUITE_ACM_INFO(0x0099), }, /* Nokia 6210 Navigator, RM-367 */
1851 { NOKIA_PCSUITE_ACM_INFO(0x0128), }, /* Nokia 6210 Navigator, RM-419 */
1852 { NOKIA_PCSUITE_ACM_INFO(0x008f), }, /* Nokia 6220 Classic */
1853 { NOKIA_PCSUITE_ACM_INFO(0x00a0), }, /* Nokia 6650 */
1854 { NOKIA_PCSUITE_ACM_INFO(0x007b), }, /* Nokia N78 */
1855 { NOKIA_PCSUITE_ACM_INFO(0x0094), }, /* Nokia N85 */
1856 { NOKIA_PCSUITE_ACM_INFO(0x003a), }, /* Nokia N96 & N96-3 */
1857 { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */
1858 { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */
1859 { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */
Przemo Firszt83a4eae2010-06-28 21:29:34 +01001860 { NOKIA_PCSUITE_ACM_INFO(0x02e3), }, /* Nokia 5230, RM-588 */
Toby Gray4035e452010-09-01 16:01:19 +01001861 { NOKIA_PCSUITE_ACM_INFO(0x0178), }, /* Nokia E63 */
1862 { NOKIA_PCSUITE_ACM_INFO(0x010e), }, /* Nokia E75 */
1863 { NOKIA_PCSUITE_ACM_INFO(0x02d9), }, /* Nokia 6760 Slide */
1864 { NOKIA_PCSUITE_ACM_INFO(0x01d0), }, /* Nokia E52 */
1865 { NOKIA_PCSUITE_ACM_INFO(0x0223), }, /* Nokia E72 */
1866 { NOKIA_PCSUITE_ACM_INFO(0x0275), }, /* Nokia X6 */
1867 { NOKIA_PCSUITE_ACM_INFO(0x026c), }, /* Nokia N97 Mini */
1868 { NOKIA_PCSUITE_ACM_INFO(0x0154), }, /* Nokia 5800 XpressMusic */
1869 { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */
1870 { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */
Arvid Ephraim Picciani721d92f2011-01-25 15:58:40 +01001871 { NOKIA_PCSUITE_ACM_INFO(0x0302), }, /* Nokia N8 */
Toby Gray4061fde2011-06-06 14:52:48 +01001872 { NOKIA_PCSUITE_ACM_INFO(0x0335), }, /* Nokia E7 */
1873 { NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */
Toby Gray4035e452010-09-01 16:01:19 +01001874 { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */
Adrian Taylorc1479a92009-11-19 10:35:33 +00001875
Denis Pershin65e52f42011-09-04 17:37:21 +07001876 /* Support for Owen devices */
1877 { USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */
1878
Adrian Taylorc1479a92009-11-19 10:35:33 +00001879 /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
1880
Julian Calaby7c5d8c32010-01-05 23:57:46 +11001881 /* Support Lego NXT using pbLua firmware */
Julian Calabyce126642010-01-05 23:58:20 +11001882 { USB_DEVICE(0x0694, 0xff00),
1883 .driver_info = NOT_A_MODEM,
Otavio Salvador7893afc2010-09-26 23:35:05 -03001884 },
Julian Calaby7c5d8c32010-01-05 23:57:46 +11001885
Erik Slagterfd5054c2011-05-11 12:06:55 +02001886 /* Support for Droids MuIn LCD */
1887 { USB_DEVICE(0x04d8, 0x000b),
1888 .driver_info = NO_DATA_INTERFACE,
1889 },
flintmanc6dc72f2014-08-11 21:52:25 -04001890#ifndef CONFIG_MACH_TENDERLOIN
Philippe Corbes5b239f02010-08-31 19:31:32 +02001891 /* control interfaces without any protocol set */
1892 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1893 USB_CDC_PROTO_NONE) },
flintmanc6dc72f2014-08-11 21:52:25 -04001894#else
1895 /* Exclude XMM6260 boot rom (not running modem software yet) */
1896 { USB_DEVICE(0x058b, 0x0041),
1897 .driver_info = NOT_REAL_ACM,
1898 },
1899#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 /* control interfaces with various AT-command sets */
1901 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1902 USB_CDC_ACM_PROTO_AT_V25TER) },
1903 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1904 USB_CDC_ACM_PROTO_AT_PCCA101) },
1905 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1906 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1907 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1908 USB_CDC_ACM_PROTO_AT_GSM) },
1909 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
Alan Cox6e47e062009-06-11 12:37:06 +01001910 USB_CDC_ACM_PROTO_AT_3G) },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1912 USB_CDC_ACM_PROTO_AT_CDMA) },
1913
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 { }
1915};
1916
Alan Cox6e47e062009-06-11 12:37:06 +01001917MODULE_DEVICE_TABLE(usb, acm_ids);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
1919static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 .name = "cdc_acm",
1921 .probe = acm_probe,
1922 .disconnect = acm_disconnect,
Oliver Neukum35758582008-07-01 19:10:08 +02001923#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001924 .suspend = acm_suspend,
1925 .resume = acm_resume,
Francesco Lavraa91b0c52009-12-08 09:54:11 +01001926 .reset_resume = acm_reset_resume,
Oliver Neukum35758582008-07-01 19:10:08 +02001927#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 .id_table = acm_ids,
Oliver Neukum35758582008-07-01 19:10:08 +02001929#ifdef CONFIG_PM
Oliver Neukum1365baf2007-10-12 17:24:28 +02001930 .supports_autosuspend = 1,
Oliver Neukum35758582008-07-01 19:10:08 +02001931#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932};
1933
1934/*
1935 * TTY driver structures.
1936 */
1937
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001938static const struct tty_operations acm_ops = {
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001939 .install = acm_tty_install,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 .open = acm_tty_open,
1941 .close = acm_tty_close,
Havard Skinnemoen7fb57a02011-11-30 13:28:14 -08001942 .cleanup = acm_tty_cleanup,
Alan Cox10077d42009-06-11 12:36:09 +01001943 .hangup = acm_tty_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 .write = acm_tty_write,
1945 .write_room = acm_tty_write_room,
1946 .ioctl = acm_tty_ioctl,
1947 .throttle = acm_tty_throttle,
1948 .unthrottle = acm_tty_unthrottle,
1949 .chars_in_buffer = acm_tty_chars_in_buffer,
1950 .break_ctl = acm_tty_break_ctl,
1951 .set_termios = acm_tty_set_termios,
1952 .tiocmget = acm_tty_tiocmget,
1953 .tiocmset = acm_tty_tiocmset,
1954};
1955
1956/*
1957 * Init / exit.
1958 */
1959
1960static int __init acm_init(void)
1961{
1962 int retval;
1963 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1964 if (!acm_tty_driver)
1965 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 acm_tty_driver->driver_name = "acm",
1967 acm_tty_driver->name = "ttyACM",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 acm_tty_driver->major = ACM_TTY_MAJOR,
1969 acm_tty_driver->minor_start = 0,
1970 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1971 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001972 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 acm_tty_driver->init_termios = tty_std_termios;
Alan Cox6e47e062009-06-11 12:37:06 +01001974 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD |
1975 HUPCL | CLOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 tty_set_operations(acm_tty_driver, &acm_ops);
1977
1978 retval = tty_register_driver(acm_tty_driver);
1979 if (retval) {
1980 put_tty_driver(acm_tty_driver);
1981 return retval;
1982 }
1983
1984 retval = usb_register(&acm_driver);
1985 if (retval) {
1986 tty_unregister_driver(acm_tty_driver);
1987 put_tty_driver(acm_tty_driver);
1988 return retval;
1989 }
1990
Johan Hovolda2c7b932011-03-22 11:12:18 +01001991 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992
1993 return 0;
1994}
1995
1996static void __exit acm_exit(void)
1997{
1998 usb_deregister(&acm_driver);
1999 tty_unregister_driver(acm_tty_driver);
2000 put_tty_driver(acm_tty_driver);
2001}
2002
2003module_init(acm_init);
2004module_exit(acm_exit);
2005
Alan Cox6e47e062009-06-11 12:37:06 +01002006MODULE_AUTHOR(DRIVER_AUTHOR);
2007MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008MODULE_LICENSE("GPL");
Scott James Remnante766aeb2009-04-06 17:33:18 +01002009MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR);