blob: 14de3b1b6a20699194c60b9cb21c60e1e3aedde3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * cdc-acm.c
3 *
4 * Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de>
5 * Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
6 * Copyright (c) 1999 Johannes Erdfelt <johannes@erdfelt.com>
7 * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
8 * Copyright (c) 2004 Oliver Neukum <oliver@neukum.name>
David Kubicek61a87ad2005-11-01 18:51:34 +01009 * Copyright (c) 2005 David Kubicek <dave@awk.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * USB Abstract Control Model driver for USB modems and ISDN adapters
12 *
13 * Sponsored by SuSE
14 *
15 * ChangeLog:
16 * v0.9 - thorough cleaning, URBification, almost a rewrite
17 * v0.10 - some more cleanups
18 * v0.11 - fixed flow control, read error doesn't stop reads
19 * v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced
20 * v0.13 - added termios, added hangup
21 * v0.14 - sized down struct acm
22 * v0.15 - fixed flow control again - characters could be lost
23 * v0.16 - added code for modems with swapped data and control interfaces
24 * v0.17 - added new style probing
25 * v0.18 - fixed new style probing for devices with more configurations
26 * v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan)
27 * v0.20 - switched to probing on interface (rather than device) class
28 * v0.21 - revert to probing on device for devices with multiple configs
29 * v0.22 - probe only the control interface. if usbcore doesn't choose the
30 * config we want, sysadmin changes bConfigurationValue in sysfs.
31 * v0.23 - use softirq for rx processing, as needed by tty layer
32 * v0.24 - change probe method to evaluate CDC union descriptor
David Kubicek61a87ad2005-11-01 18:51:34 +010033 * v0.25 - downstream tasks paralelized to maximize throughput
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 */
35
36/*
37 * This program is free software; you can redistribute it and/or modify
38 * it under the terms of the GNU General Public License as published by
39 * the Free Software Foundation; either version 2 of the License, or
40 * (at your option) any later version.
41 *
42 * This program is distributed in the hope that it will be useful,
43 * but WITHOUT ANY WARRANTY; without even the implied warranty of
44 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45 * GNU General Public License for more details.
46 *
47 * You should have received a copy of the GNU General Public License
48 * along with this program; if not, write to the Free Software
49 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
50 */
51
52#undef DEBUG
53
54#include <linux/kernel.h>
55#include <linux/errno.h>
56#include <linux/init.h>
57#include <linux/slab.h>
58#include <linux/tty.h>
59#include <linux/tty_driver.h>
60#include <linux/tty_flip.h>
61#include <linux/module.h>
62#include <linux/smp_lock.h>
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010063#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include <asm/uaccess.h>
65#include <linux/usb.h>
David Brownella8c28f22006-06-13 09:57:47 -070066#include <linux/usb/cdc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#include <asm/byteorder.h>
68#include <asm/unaligned.h>
David Kubicek61a87ad2005-11-01 18:51:34 +010069#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71#include "cdc-acm.h"
72
73/*
74 * Version Information
75 */
David Kubicek61a87ad2005-11-01 18:51:34 +010076#define DRIVER_VERSION "v0.25"
77#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
Linus Torvalds1da177e2005-04-16 15:20:36 -070078#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
79
80static struct usb_driver acm_driver;
81static struct tty_driver *acm_tty_driver;
82static struct acm *acm_table[ACM_TTY_MINORS];
83
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010084static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86#define ACM_READY(acm) (acm && acm->dev && acm->used)
87
88/*
89 * Functions for ACM control messages.
90 */
91
92static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
93{
94 int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
95 request, USB_RT_ACM, value,
96 acm->control->altsetting[0].desc.bInterfaceNumber,
97 buf, len, 5000);
98 dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
99 return retval < 0 ? retval : 0;
100}
101
102/* devices aren't required to support these requests.
103 * the cdc acm descriptor tells whether they do...
104 */
105#define acm_set_control(acm, control) \
106 acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
107#define acm_set_line(acm, line) \
108 acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
109#define acm_send_break(acm, ms) \
110 acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
111
112/*
Oliver Neukum884b6002005-04-21 21:28:02 +0200113 * Write buffer management.
114 * All of these assume proper locks taken by the caller.
115 */
116
117static int acm_wb_alloc(struct acm *acm)
118{
119 int i, wbn;
120 struct acm_wb *wb;
121
122 wbn = acm->write_current;
123 i = 0;
124 for (;;) {
125 wb = &acm->wb[wbn];
126 if (!wb->use) {
127 wb->use = 1;
128 return wbn;
129 }
Oliver Neukum86478942006-05-13 22:50:47 +0200130 wbn = (wbn + 1) % ACM_NW;
131 if (++i >= ACM_NW)
Oliver Neukum884b6002005-04-21 21:28:02 +0200132 return -1;
133 }
134}
135
136static void acm_wb_free(struct acm *acm, int wbn)
137{
138 acm->wb[wbn].use = 0;
139}
140
141static int acm_wb_is_avail(struct acm *acm)
142{
143 int i, n;
144
Oliver Neukum86478942006-05-13 22:50:47 +0200145 n = ACM_NW;
146 for (i = 0; i < ACM_NW; i++) {
147 n -= acm->wb[i].use;
Oliver Neukum884b6002005-04-21 21:28:02 +0200148 }
149 return n;
150}
151
152static inline int acm_wb_is_used(struct acm *acm, int wbn)
153{
154 return acm->wb[wbn].use;
155}
156
157/*
158 * Finish write.
159 */
160static void acm_write_done(struct acm *acm)
161{
162 unsigned long flags;
163 int wbn;
164
165 spin_lock_irqsave(&acm->write_lock, flags);
166 acm->write_ready = 1;
167 wbn = acm->write_current;
168 acm_wb_free(acm, wbn);
Oliver Neukum86478942006-05-13 22:50:47 +0200169 acm->write_current = (wbn + 1) % ACM_NW;
Oliver Neukum884b6002005-04-21 21:28:02 +0200170 spin_unlock_irqrestore(&acm->write_lock, flags);
171}
172
173/*
174 * Poke write.
175 */
176static int acm_write_start(struct acm *acm)
177{
178 unsigned long flags;
179 int wbn;
180 struct acm_wb *wb;
181 int rc;
182
183 spin_lock_irqsave(&acm->write_lock, flags);
184 if (!acm->dev) {
185 spin_unlock_irqrestore(&acm->write_lock, flags);
186 return -ENODEV;
187 }
188
189 if (!acm->write_ready) {
190 spin_unlock_irqrestore(&acm->write_lock, flags);
191 return 0; /* A white lie */
192 }
193
194 wbn = acm->write_current;
195 if (!acm_wb_is_used(acm, wbn)) {
196 spin_unlock_irqrestore(&acm->write_lock, flags);
197 return 0;
198 }
199 wb = &acm->wb[wbn];
200
201 acm->write_ready = 0;
202 spin_unlock_irqrestore(&acm->write_lock, flags);
203
204 acm->writeurb->transfer_buffer = wb->buf;
205 acm->writeurb->transfer_dma = wb->dmah;
206 acm->writeurb->transfer_buffer_length = wb->len;
207 acm->writeurb->dev = acm->dev;
208
209 if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) {
210 dbg("usb_submit_urb(write bulk) failed: %d", rc);
211 acm_write_done(acm);
212 }
213 return rc;
214}
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100215/*
216 * attributes exported through sysfs
217 */
218static ssize_t show_caps
219(struct device *dev, struct device_attribute *attr, char *buf)
220{
221 struct usb_interface *intf = to_usb_interface(dev);
222 struct acm *acm = usb_get_intfdata(intf);
Oliver Neukum884b6002005-04-21 21:28:02 +0200223
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100224 return sprintf(buf, "%d", acm->ctrl_caps);
225}
226static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
227
228static ssize_t show_country_codes
229(struct device *dev, struct device_attribute *attr, char *buf)
230{
231 struct usb_interface *intf = to_usb_interface(dev);
232 struct acm *acm = usb_get_intfdata(intf);
233
234 memcpy(buf, acm->country_codes, acm->country_code_size);
235 return acm->country_code_size;
236}
237
238static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
239
240static ssize_t show_country_rel_date
241(struct device *dev, struct device_attribute *attr, char *buf)
242{
243 struct usb_interface *intf = to_usb_interface(dev);
244 struct acm *acm = usb_get_intfdata(intf);
245
246 return sprintf(buf, "%d", acm->country_rel_date);
247}
248
249static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
Oliver Neukum884b6002005-04-21 21:28:02 +0200250/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 * Interrupt handlers for various ACM device responses
252 */
253
254/* control interface reports status changes with "interrupt" transfers */
David Howells7d12e782006-10-05 14:55:46 +0100255static void acm_ctrl_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256{
257 struct acm *acm = urb->context;
258 struct usb_cdc_notification *dr = urb->transfer_buffer;
259 unsigned char *data;
260 int newctrl;
261 int status;
262
263 switch (urb->status) {
264 case 0:
265 /* success */
266 break;
267 case -ECONNRESET:
268 case -ENOENT:
269 case -ESHUTDOWN:
270 /* this urb is terminated, clean up */
271 dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
272 return;
273 default:
274 dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
275 goto exit;
276 }
277
278 if (!ACM_READY(acm))
279 goto exit;
280
281 data = (unsigned char *)(dr + 1);
282 switch (dr->bNotificationType) {
283
284 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
285
286 dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
287 break;
288
289 case USB_CDC_NOTIFY_SERIAL_STATE:
290
291 newctrl = le16_to_cpu(get_unaligned((__le16 *) data));
292
293 if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
294 dbg("calling hangup");
295 tty_hangup(acm->tty);
296 }
297
298 acm->ctrlin = newctrl;
299
300 dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
301 acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
302 acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
303 acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
304 acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
305
306 break;
307
308 default:
309 dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
310 dr->bNotificationType, dr->wIndex,
311 dr->wLength, data[0], data[1]);
312 break;
313 }
314exit:
315 status = usb_submit_urb (urb, GFP_ATOMIC);
316 if (status)
317 err ("%s - usb_submit_urb failed with result %d",
318 __FUNCTION__, status);
319}
320
321/* data interface returns incoming bytes, or we got unthrottled */
David Howells7d12e782006-10-05 14:55:46 +0100322static void acm_read_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323{
David Kubicek61a87ad2005-11-01 18:51:34 +0100324 struct acm_rb *buf;
325 struct acm_ru *rcv = urb->context;
326 struct acm *acm = rcv->instance;
Oliver Neukum86478942006-05-13 22:50:47 +0200327 int status = urb->status;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200328 dbg("Entering acm_read_bulk with status %d", urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 if (!ACM_READY(acm))
331 return;
332
Oliver Neukum86478942006-05-13 22:50:47 +0200333 if (status)
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200334 dev_dbg(&acm->data->dev, "bulk rx status %d", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
David Kubicek61a87ad2005-11-01 18:51:34 +0100336 buf = rcv->buffer;
337 buf->size = urb->actual_length;
338
Oliver Neukum86478942006-05-13 22:50:47 +0200339 if (likely(status == 0)) {
340 spin_lock(&acm->read_lock);
341 list_add_tail(&rcv->list, &acm->spare_read_urbs);
342 list_add_tail(&buf->list, &acm->filled_read_bufs);
343 spin_unlock(&acm->read_lock);
344 } else {
345 /* we drop the buffer due to an error */
346 spin_lock(&acm->read_lock);
347 list_add_tail(&rcv->list, &acm->spare_read_urbs);
348 list_add(&buf->list, &acm->spare_read_bufs);
349 spin_unlock(&acm->read_lock);
350 /* nevertheless the tasklet must be kicked unconditionally
351 so the queue cannot dry up */
352 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100353 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354}
355
356static void acm_rx_tasklet(unsigned long _acm)
357{
358 struct acm *acm = (void *)_acm;
David Kubicek61a87ad2005-11-01 18:51:34 +0100359 struct acm_rb *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 struct tty_struct *tty = acm->tty;
David Kubicek61a87ad2005-11-01 18:51:34 +0100361 struct acm_ru *rcv;
Jarek Poplawski762f0072006-10-06 07:23:11 +0200362 unsigned long flags;
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100363 unsigned char throttled;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 dbg("Entering acm_rx_tasklet");
365
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100366 if (!ACM_READY(acm))
367 return;
368
Oliver Neukum834dbca2007-03-06 10:47:04 +0100369 spin_lock_irqsave(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100370 throttled = acm->throttle;
Oliver Neukum834dbca2007-03-06 10:47:04 +0100371 spin_unlock_irqrestore(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100372 if (throttled)
David Kubicek61a87ad2005-11-01 18:51:34 +0100373 return;
374
375next_buffer:
Jarek Poplawski762f0072006-10-06 07:23:11 +0200376 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100377 if (list_empty(&acm->filled_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200378 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100379 goto urbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 }
David Kubicek61a87ad2005-11-01 18:51:34 +0100381 buf = list_entry(acm->filled_read_bufs.next,
382 struct acm_rb, list);
383 list_del(&buf->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200384 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100385
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200386 dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100387
Alan Cox33f0f882006-01-09 20:54:13 -0800388 tty_buffer_request_room(tty, buf->size);
Oliver Neukum834dbca2007-03-06 10:47:04 +0100389 spin_lock_irqsave(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100390 throttled = acm->throttle;
Oliver Neukum834dbca2007-03-06 10:47:04 +0100391 spin_unlock_irqrestore(&acm->throttle_lock, flags);
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100392 if (!throttled)
Alan Cox33f0f882006-01-09 20:54:13 -0800393 tty_insert_flip_string(tty, buf->base, buf->size);
David Kubicek61a87ad2005-11-01 18:51:34 +0100394 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100396 if (throttled) {
397 dbg("Throttling noticed");
Jarek Poplawski762f0072006-10-06 07:23:11 +0200398 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100399 list_add(&buf->list, &acm->filled_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200400 spin_unlock_irqrestore(&acm->read_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 return;
402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Jarek Poplawski762f0072006-10-06 07:23:11 +0200404 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100405 list_add(&buf->list, &acm->spare_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200406 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100407 goto next_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
David Kubicek61a87ad2005-11-01 18:51:34 +0100409urbs:
410 while (!list_empty(&acm->spare_read_bufs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200411 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100412 if (list_empty(&acm->spare_read_urbs)) {
Jarek Poplawski762f0072006-10-06 07:23:11 +0200413 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100414 return;
415 }
416 rcv = list_entry(acm->spare_read_urbs.next,
417 struct acm_ru, list);
418 list_del(&rcv->list);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200419 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100420
421 buf = list_entry(acm->spare_read_bufs.next,
422 struct acm_rb, list);
423 list_del(&buf->list);
424
425 rcv->buffer = buf;
426
427 usb_fill_bulk_urb(rcv->urb, acm->dev,
428 acm->rx_endpoint,
429 buf->base,
430 acm->readsize,
431 acm_read_bulk, rcv);
432 rcv->urb->transfer_dma = buf->dma;
433 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
434
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200435 dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf);
David Kubicek61a87ad2005-11-01 18:51:34 +0100436
437 /* This shouldn't kill the driver as unsuccessful URBs are returned to the
438 free-urbs-pool and resubmited ASAP */
439 if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
440 list_add(&buf->list, &acm->spare_read_bufs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200441 spin_lock_irqsave(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100442 list_add(&rcv->list, &acm->spare_read_urbs);
Jarek Poplawski762f0072006-10-06 07:23:11 +0200443 spin_unlock_irqrestore(&acm->read_lock, flags);
David Kubicek61a87ad2005-11-01 18:51:34 +0100444 return;
445 }
446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447}
448
449/* data interface wrote those outgoing bytes */
David Howells7d12e782006-10-05 14:55:46 +0100450static void acm_write_bulk(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
452 struct acm *acm = (struct acm *)urb->context;
Oliver Neukum884b6002005-04-21 21:28:02 +0200453
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200454 dbg("Entering acm_write_bulk with status %d", urb->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
Oliver Neukum884b6002005-04-21 21:28:02 +0200456 acm_write_done(acm);
457 acm_write_start(acm);
458 if (ACM_READY(acm))
459 schedule_work(&acm->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460}
461
David Howellsc4028952006-11-22 14:57:56 +0000462static void acm_softint(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463{
David Howellsc4028952006-11-22 14:57:56 +0000464 struct acm *acm = container_of(work, struct acm, work);
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200465 dbg("Entering acm_softint.");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
467 if (!ACM_READY(acm))
468 return;
469 tty_wakeup(acm->tty);
470}
471
472/*
473 * TTY handlers
474 */
475
476static int acm_tty_open(struct tty_struct *tty, struct file *filp)
477{
478 struct acm *acm;
479 int rv = -EINVAL;
David Kubicek61a87ad2005-11-01 18:51:34 +0100480 int i;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200481 dbg("Entering acm_tty_open.");
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100482
483 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
485 acm = acm_table[tty->index];
486 if (!acm || !acm->dev)
487 goto err_out;
488 else
489 rv = 0;
490
491 tty->driver_data = acm;
492 acm->tty = tty;
493
David Kubicek61a87ad2005-11-01 18:51:34 +0100494 /* force low_latency on so that our tty_push actually forces the data through,
495 otherwise it is scheduled, and with high data rates data can get lost. */
496 tty->low_latency = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
498 if (acm->used++) {
499 goto done;
500 }
501
502 acm->ctrlurb->dev = acm->dev;
503 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
504 dbg("usb_submit_urb(ctrl irq) failed");
505 goto bail_out;
506 }
507
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100508 if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
509 (acm->ctrl_caps & USB_CDC_CAP_LINE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 goto full_bailout;
511
David Kubicek61a87ad2005-11-01 18:51:34 +0100512 INIT_LIST_HEAD(&acm->spare_read_urbs);
513 INIT_LIST_HEAD(&acm->spare_read_bufs);
514 INIT_LIST_HEAD(&acm->filled_read_bufs);
Oliver Neukum86478942006-05-13 22:50:47 +0200515 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100516 list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
517 }
Oliver Neukum86478942006-05-13 22:50:47 +0200518 for (i = 0; i < acm->rx_buflimit; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100519 list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
520 }
521
Oliver Neukumca79b7b2007-02-12 08:41:35 +0100522 acm->throttle = 0;
523
David Kubicek61a87ad2005-11-01 18:51:34 +0100524 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
526done:
527err_out:
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100528 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 return rv;
530
531full_bailout:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 usb_kill_urb(acm->ctrlurb);
533bail_out:
534 acm->used--;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100535 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 return -EIO;
537}
538
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700539static void acm_tty_unregister(struct acm *acm)
540{
Oliver Neukum86478942006-05-13 22:50:47 +0200541 int i,nr;
David Kubicek61a87ad2005-11-01 18:51:34 +0100542
Oliver Neukum86478942006-05-13 22:50:47 +0200543 nr = acm->rx_buflimit;
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700544 tty_unregister_device(acm_tty_driver, acm->minor);
545 usb_put_intf(acm->control);
546 acm_table[acm->minor] = NULL;
547 usb_free_urb(acm->ctrlurb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700548 usb_free_urb(acm->writeurb);
Oliver Neukum86478942006-05-13 22:50:47 +0200549 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100550 usb_free_urb(acm->ru[i].urb);
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100551 kfree(acm->country_codes);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700552 kfree(acm);
553}
554
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555static void acm_tty_close(struct tty_struct *tty, struct file *filp)
556{
557 struct acm *acm = tty->driver_data;
Oliver Neukum86478942006-05-13 22:50:47 +0200558 int i,nr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
560 if (!acm || !acm->used)
561 return;
562
Oliver Neukum86478942006-05-13 22:50:47 +0200563 nr = acm->rx_buflimit;
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100564 mutex_lock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 if (!--acm->used) {
566 if (acm->dev) {
567 acm_set_control(acm, acm->ctrlout = 0);
568 usb_kill_urb(acm->ctrlurb);
569 usb_kill_urb(acm->writeurb);
Oliver Neukum86478942006-05-13 22:50:47 +0200570 for (i = 0; i < nr; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +0100571 usb_kill_urb(acm->ru[i].urb);
brian@murphy.dk83ef3442005-06-29 16:53:29 -0700572 } else
573 acm_tty_unregister(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 }
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100575 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576}
577
578static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
579{
580 struct acm *acm = tty->driver_data;
581 int stat;
Oliver Neukum884b6002005-04-21 21:28:02 +0200582 unsigned long flags;
583 int wbn;
584 struct acm_wb *wb;
585
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200586 dbg("Entering acm_tty_write to write %d bytes,", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
588 if (!ACM_READY(acm))
589 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 if (!count)
591 return 0;
592
Oliver Neukum884b6002005-04-21 21:28:02 +0200593 spin_lock_irqsave(&acm->write_lock, flags);
594 if ((wbn = acm_wb_alloc(acm)) < 0) {
595 spin_unlock_irqrestore(&acm->write_lock, flags);
596 acm_write_start(acm);
597 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 }
Oliver Neukum884b6002005-04-21 21:28:02 +0200599 wb = &acm->wb[wbn];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
Oliver Neukum884b6002005-04-21 21:28:02 +0200601 count = (count > acm->writesize) ? acm->writesize : count;
602 dbg("Get %d bytes...", count);
603 memcpy(wb->buf, buf, count);
604 wb->len = count;
605 spin_unlock_irqrestore(&acm->write_lock, flags);
606
607 if ((stat = acm_write_start(acm)) < 0)
608 return stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 return count;
610}
611
612static int acm_tty_write_room(struct tty_struct *tty)
613{
614 struct acm *acm = tty->driver_data;
615 if (!ACM_READY(acm))
616 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200617 /*
618 * Do not let the line discipline to know that we have a reserve,
619 * or it might get too enthusiastic.
620 */
621 return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622}
623
624static int acm_tty_chars_in_buffer(struct tty_struct *tty)
625{
626 struct acm *acm = tty->driver_data;
627 if (!ACM_READY(acm))
628 return -EINVAL;
Oliver Neukum884b6002005-04-21 21:28:02 +0200629 /*
630 * This is inaccurate (overcounts), but it works.
631 */
Oliver Neukum86478942006-05-13 22:50:47 +0200632 return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633}
634
635static void acm_tty_throttle(struct tty_struct *tty)
636{
637 struct acm *acm = tty->driver_data;
638 if (!ACM_READY(acm))
639 return;
640 spin_lock_bh(&acm->throttle_lock);
641 acm->throttle = 1;
642 spin_unlock_bh(&acm->throttle_lock);
643}
644
645static void acm_tty_unthrottle(struct tty_struct *tty)
646{
647 struct acm *acm = tty->driver_data;
648 if (!ACM_READY(acm))
649 return;
650 spin_lock_bh(&acm->throttle_lock);
651 acm->throttle = 0;
652 spin_unlock_bh(&acm->throttle_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100653 tasklet_schedule(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654}
655
656static void acm_tty_break_ctl(struct tty_struct *tty, int state)
657{
658 struct acm *acm = tty->driver_data;
659 if (!ACM_READY(acm))
660 return;
661 if (acm_send_break(acm, state ? 0xffff : 0))
662 dbg("send break failed");
663}
664
665static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file)
666{
667 struct acm *acm = tty->driver_data;
668
669 if (!ACM_READY(acm))
670 return -EINVAL;
671
672 return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
673 (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
674 (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
675 (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) |
676 (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) |
677 TIOCM_CTS;
678}
679
680static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
681 unsigned int set, unsigned int clear)
682{
683 struct acm *acm = tty->driver_data;
684 unsigned int newctrl;
685
686 if (!ACM_READY(acm))
687 return -EINVAL;
688
689 newctrl = acm->ctrlout;
690 set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
691 clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
692
693 newctrl = (newctrl & ~clear) | set;
694
695 if (acm->ctrlout == newctrl)
696 return 0;
697 return acm_set_control(acm, acm->ctrlout = newctrl);
698}
699
700static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
701{
702 struct acm *acm = tty->driver_data;
703
704 if (!ACM_READY(acm))
705 return -EINVAL;
706
707 return -ENOIOCTLCMD;
708}
709
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100710static const __u32 acm_tty_speed[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 0, 50, 75, 110, 134, 150, 200, 300, 600,
712 1200, 1800, 2400, 4800, 9600, 19200, 38400,
713 57600, 115200, 230400, 460800, 500000, 576000,
714 921600, 1000000, 1152000, 1500000, 2000000,
715 2500000, 3000000, 3500000, 4000000
716};
717
Arjan van de Ven4c4c9432005-11-29 09:43:42 +0100718static const __u8 acm_tty_size[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 5, 6, 7, 8
720};
721
Alan Cox606d0992006-12-08 02:38:45 -0800722static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723{
724 struct acm *acm = tty->driver_data;
Alan Cox606d0992006-12-08 02:38:45 -0800725 struct ktermios *termios = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 struct usb_cdc_line_coding newline;
727 int newctrl = acm->ctrlout;
728
729 if (!ACM_READY(acm))
730 return;
731
732 newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
733 (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
734 newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
735 newline.bParityType = termios->c_cflag & PARENB ?
736 (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
737 newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
738
739 acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
740
741 if (!newline.dwDTERate) {
742 newline.dwDTERate = acm->line.dwDTERate;
743 newctrl &= ~ACM_CTRL_DTR;
744 } else newctrl |= ACM_CTRL_DTR;
745
746 if (newctrl != acm->ctrlout)
747 acm_set_control(acm, acm->ctrlout = newctrl);
748
749 if (memcmp(&acm->line, &newline, sizeof newline)) {
750 memcpy(&acm->line, &newline, sizeof newline);
751 dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),
752 newline.bCharFormat, newline.bParityType,
753 newline.bDataBits);
754 acm_set_line(acm, &acm->line);
755 }
756}
757
758/*
759 * USB probe and disconnect routines.
760 */
761
Oliver Neukum884b6002005-04-21 21:28:02 +0200762/* Little helper: write buffers free */
763static void acm_write_buffers_free(struct acm *acm)
764{
765 int i;
766 struct acm_wb *wb;
767
Oliver Neukum86478942006-05-13 22:50:47 +0200768 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200769 usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
770 }
771}
772
773/* Little helper: write buffers allocate */
774static int acm_write_buffers_alloc(struct acm *acm)
775{
776 int i;
777 struct acm_wb *wb;
778
Oliver Neukum86478942006-05-13 22:50:47 +0200779 for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
Oliver Neukum884b6002005-04-21 21:28:02 +0200780 wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
781 &wb->dmah);
782 if (!wb->buf) {
783 while (i != 0) {
784 --i;
785 --wb;
786 usb_buffer_free(acm->dev, acm->writesize,
787 wb->buf, wb->dmah);
788 }
789 return -ENOMEM;
790 }
791 }
792 return 0;
793}
794
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795static int acm_probe (struct usb_interface *intf,
796 const struct usb_device_id *id)
797{
798 struct usb_cdc_union_desc *union_header = NULL;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100799 struct usb_cdc_country_functional_desc *cfd = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 char *buffer = intf->altsetting->extra;
801 int buflen = intf->altsetting->extralen;
802 struct usb_interface *control_interface;
803 struct usb_interface *data_interface;
804 struct usb_endpoint_descriptor *epctrl;
805 struct usb_endpoint_descriptor *epread;
806 struct usb_endpoint_descriptor *epwrite;
807 struct usb_device *usb_dev = interface_to_usbdev(intf);
808 struct acm *acm;
809 int minor;
810 int ctrlsize,readsize;
811 u8 *buf;
812 u8 ac_management_function = 0;
813 u8 call_management_function = 0;
814 int call_interface_num = -1;
815 int data_interface_num;
816 unsigned long quirks;
Oliver Neukum86478942006-05-13 22:50:47 +0200817 int num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +0100818 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Oliver Neukum86478942006-05-13 22:50:47 +0200820 /* normal quirks */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 quirks = (unsigned long)id->driver_info;
Oliver Neukum86478942006-05-13 22:50:47 +0200822 num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
823
824 /* handle quirks deadly to normal probing*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 if (quirks == NO_UNION_NORMAL) {
826 data_interface = usb_ifnum_to_if(usb_dev, 1);
827 control_interface = usb_ifnum_to_if(usb_dev, 0);
828 goto skip_normal_probe;
829 }
830
831 /* normal probing*/
832 if (!buffer) {
833 err("Wierd descriptor references\n");
834 return -EINVAL;
835 }
836
837 if (!buflen) {
838 if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200839 dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 buflen = intf->cur_altsetting->endpoint->extralen;
841 buffer = intf->cur_altsetting->endpoint->extra;
842 } else {
843 err("Zero length descriptor references\n");
844 return -EINVAL;
845 }
846 }
847
848 while (buflen > 0) {
849 if (buffer [1] != USB_DT_CS_INTERFACE) {
850 err("skipping garbage\n");
851 goto next_desc;
852 }
853
854 switch (buffer [2]) {
855 case USB_CDC_UNION_TYPE: /* we've found it */
856 if (union_header) {
857 err("More than one union descriptor, skipping ...");
858 goto next_desc;
859 }
860 union_header = (struct usb_cdc_union_desc *)
861 buffer;
862 break;
Oliver Neukumc4cabd22007-02-27 15:28:55 +0100863 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
864 cfd = (struct usb_cdc_country_functional_desc *)buffer;
865 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 case USB_CDC_HEADER_TYPE: /* maybe check version */
867 break; /* for now we ignore it */
868 case USB_CDC_ACM_TYPE:
869 ac_management_function = buffer[3];
870 break;
871 case USB_CDC_CALL_MANAGEMENT_TYPE:
872 call_management_function = buffer[3];
873 call_interface_num = buffer[4];
874 if ((call_management_function & 3) != 3)
875 err("This device cannot do calls on its own. It is no modem.");
876 break;
877
878 default:
879 err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]);
880 break;
881 }
882next_desc:
883 buflen -= buffer[0];
884 buffer += buffer[0];
885 }
886
887 if (!union_header) {
888 if (call_interface_num > 0) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200889 dev_dbg(&intf->dev,"No union descriptor, using call management descriptor");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
891 control_interface = intf;
892 } else {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200893 dev_dbg(&intf->dev,"No union descriptor, giving up");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 return -ENODEV;
895 }
896 } else {
897 control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
898 data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
899 if (!control_interface || !data_interface) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200900 dev_dbg(&intf->dev,"no interfaces");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 return -ENODEV;
902 }
903 }
904
905 if (data_interface_num != call_interface_num)
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200906 dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
908skip_normal_probe:
909
910 /*workaround for switched interfaces */
911 if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
912 if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
913 struct usb_interface *t;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200914 dev_dbg(&intf->dev,"Your device has switched interfaces.");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
916 t = control_interface;
917 control_interface = data_interface;
918 data_interface = t;
919 } else {
920 return -EINVAL;
921 }
922 }
923
924 if (usb_interface_claimed(data_interface)) { /* valid in this context */
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200925 dev_dbg(&intf->dev,"The data interface isn't available");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 return -EBUSY;
927 }
928
929
930 if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
931 return -EINVAL;
932
933 epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
934 epread = &data_interface->cur_altsetting->endpoint[0].desc;
935 epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
936
937
938 /* workaround for switched endpoints */
Luiz Fernando N. Capitulino45aea702006-10-26 13:02:48 -0300939 if (!usb_endpoint_dir_in(epread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 /* descriptors are swapped */
941 struct usb_endpoint_descriptor *t;
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200942 dev_dbg(&intf->dev,"The data interface has switched endpoints");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
944 t = epread;
945 epread = epwrite;
946 epwrite = t;
947 }
948 dbg("interfaces are valid");
949 for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
950
951 if (minor == ACM_TTY_MINORS) {
952 err("no more free acm devices");
953 return -ENODEV;
954 }
955
Oliver Neukum46f116e2005-10-24 22:42:35 +0200956 if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200957 dev_dbg(&intf->dev, "out of memory (acm kzalloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 goto alloc_fail;
959 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
Oliver Neukum86478942006-05-13 22:50:47 +0200962 readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize);
964 acm->control = control_interface;
965 acm->data = data_interface;
966 acm->minor = minor;
967 acm->dev = usb_dev;
968 acm->ctrl_caps = ac_management_function;
969 acm->ctrlsize = ctrlsize;
970 acm->readsize = readsize;
Oliver Neukum86478942006-05-13 22:50:47 +0200971 acm->rx_buflimit = num_rx_buf;
David Kubicek61a87ad2005-11-01 18:51:34 +0100972 acm->urb_task.func = acm_rx_tasklet;
973 acm->urb_task.data = (unsigned long) acm;
David Howellsc4028952006-11-22 14:57:56 +0000974 INIT_WORK(&acm->work, acm_softint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 spin_lock_init(&acm->throttle_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +0200976 spin_lock_init(&acm->write_lock);
David Kubicek61a87ad2005-11-01 18:51:34 +0100977 spin_lock_init(&acm->read_lock);
Oliver Neukum884b6002005-04-21 21:28:02 +0200978 acm->write_ready = 1;
David Kubicek61a87ad2005-11-01 18:51:34 +0100979 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
981 buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
982 if (!buf) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200983 dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 goto alloc_fail2;
985 }
986 acm->ctrl_buffer = buf;
987
Oliver Neukum884b6002005-04-21 21:28:02 +0200988 if (acm_write_buffers_alloc(acm) < 0) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200989 dev_dbg(&intf->dev, "out of memory (write buffer alloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 goto alloc_fail4;
991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
994 if (!acm->ctrlurb) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +0200995 dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 goto alloc_fail5;
997 }
Oliver Neukum86478942006-05-13 22:50:47 +0200998 for (i = 0; i < num_rx_buf; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +0100999 struct acm_ru *rcv = &(acm->ru[i]);
1000
1001 if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001002 dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)");
David Kubicek61a87ad2005-11-01 18:51:34 +01001003 goto alloc_fail7;
1004 }
1005
1006 rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1007 rcv->instance = acm;
1008 }
Oliver Neukum86478942006-05-13 22:50:47 +02001009 for (i = 0; i < num_rx_buf; i++) {
David Kubicek61a87ad2005-11-01 18:51:34 +01001010 struct acm_rb *buf = &(acm->rb[i]);
1011
David Kubicek61a87ad2005-11-01 18:51:34 +01001012 if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001013 dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)");
David Kubicek61a87ad2005-11-01 18:51:34 +01001014 goto alloc_fail7;
1015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 }
1017 acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
1018 if (!acm->writeurb) {
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001019 dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 goto alloc_fail7;
1021 }
1022
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001023 usb_set_intfdata (intf, acm);
1024
1025 i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
1026 if (i < 0)
1027 goto alloc_fail8;
1028
1029 if (cfd) { /* export the country data */
1030 acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
1031 if (!acm->country_codes)
1032 goto skip_countries;
1033 acm->country_code_size = cfd->bLength - 4;
1034 memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4);
1035 acm->country_rel_date = cfd->iCountryCodeRelDate;
1036
1037 i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
1038 if (i < 0) {
1039 kfree(acm->country_codes);
1040 goto skip_countries;
1041 }
1042
1043 i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
1044 if (i < 0) {
1045 kfree(acm->country_codes);
1046 goto skip_countries;
1047 }
1048 }
1049
1050skip_countries:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
1052 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
1053 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1054 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
1055
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
Oliver Neukum884b6002005-04-21 21:28:02 +02001057 NULL, acm->writesize, acm_write_bulk, acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
1061
1062 acm_set_control(acm, acm->ctrlout);
1063
1064 acm->line.dwDTERate = cpu_to_le32(9600);
1065 acm->line.bDataBits = 8;
1066 acm_set_line(acm, &acm->line);
1067
1068 usb_driver_claim_interface(&acm_driver, data_interface, acm);
1069
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001070 usb_get_intf(control_interface);
1071 tty_register_device(acm_tty_driver, minor, &control_interface->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
1073 acm_table[minor] = acm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001075 return 0;
1076alloc_fail8:
1077 usb_free_urb(acm->writeurb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078alloc_fail7:
Oliver Neukum86478942006-05-13 22:50:47 +02001079 for (i = 0; i < num_rx_buf; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001080 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
Oliver Neukum86478942006-05-13 22:50:47 +02001081 for (i = 0; i < num_rx_buf; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001082 usb_free_urb(acm->ru[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 usb_free_urb(acm->ctrlurb);
1084alloc_fail5:
Oliver Neukum884b6002005-04-21 21:28:02 +02001085 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086alloc_fail4:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
1088alloc_fail2:
1089 kfree(acm);
1090alloc_fail:
1091 return -ENOMEM;
1092}
1093
1094static void acm_disconnect(struct usb_interface *intf)
1095{
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001096 struct acm *acm = usb_get_intfdata(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 struct usb_device *usb_dev = interface_to_usbdev(intf);
David Kubicek61a87ad2005-11-01 18:51:34 +01001098 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
1100 if (!acm || !acm->dev) {
1101 dbg("disconnect on nonexisting interface");
1102 return;
1103 }
1104
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001105 mutex_lock(&open_mutex);
Oliver Neukum86067eea2006-01-08 12:39:13 +01001106 if (!usb_get_intfdata(intf)) {
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001107 mutex_unlock(&open_mutex);
Oliver Neukum86067eea2006-01-08 12:39:13 +01001108 return;
1109 }
Oliver Neukumc4cabd22007-02-27 15:28:55 +01001110 if (acm->country_codes){
1111 device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
1112 device_remove_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
1113 }
1114 device_remove_file(&intf->dev, &dev_attr_bmCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 acm->dev = NULL;
Oliver Neukum86067eea2006-01-08 12:39:13 +01001116 usb_set_intfdata(acm->control, NULL);
1117 usb_set_intfdata(acm->data, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
David Kubicek61a87ad2005-11-01 18:51:34 +01001119 tasklet_disable(&acm->urb_task);
1120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 usb_kill_urb(acm->ctrlurb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 usb_kill_urb(acm->writeurb);
Oliver Neukum86478942006-05-13 22:50:47 +02001123 for (i = 0; i < acm->rx_buflimit; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001124 usb_kill_urb(acm->ru[i].urb);
1125
1126 INIT_LIST_HEAD(&acm->filled_read_bufs);
1127 INIT_LIST_HEAD(&acm->spare_read_bufs);
1128
1129 tasklet_enable(&acm->urb_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
1131 flush_scheduled_work(); /* wait for acm_softint */
1132
Oliver Neukum884b6002005-04-21 21:28:02 +02001133 acm_write_buffers_free(acm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
Oliver Neukum86478942006-05-13 22:50:47 +02001135 for (i = 0; i < acm->rx_buflimit; i++)
David Kubicek61a87ad2005-11-01 18:51:34 +01001136 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
Oliver Neukum86067eea2006-01-08 12:39:13 +01001138 usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
1140 if (!acm->used) {
brian@murphy.dk83ef3442005-06-29 16:53:29 -07001141 acm_tty_unregister(acm);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001142 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 return;
1144 }
1145
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001146 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
1148 if (acm->tty)
1149 tty_hangup(acm->tty);
1150}
1151
1152/*
1153 * USB driver structure.
1154 */
1155
1156static struct usb_device_id acm_ids[] = {
1157 /* quirky and broken devices */
1158 { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
1159 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1160 },
Masahito Omote8753e652005-07-29 12:17:25 -07001161 { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
1162 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1163 },
Chris Malley91a9c922006-10-03 10:08:28 +01001164 { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
1165 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1166 },
Oliver Neukum86478942006-05-13 22:50:47 +02001167 { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
1168 .driver_info = SINGLE_RX_URB, /* firmware bug */
1169 },
Oliver Neukum3dd2ae82006-06-23 09:14:17 +02001170 { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
1171 .driver_info = SINGLE_RX_URB, /* firmware bug */
1172 },
Oliver Neukum9be84562007-02-12 08:50:03 +01001173 { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
1174 .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
1175 },
1176
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 /* control interfaces with various AT-command sets */
1178 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1179 USB_CDC_ACM_PROTO_AT_V25TER) },
1180 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1181 USB_CDC_ACM_PROTO_AT_PCCA101) },
1182 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1183 USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },
1184 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1185 USB_CDC_ACM_PROTO_AT_GSM) },
1186 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1187 USB_CDC_ACM_PROTO_AT_3G ) },
1188 { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
1189 USB_CDC_ACM_PROTO_AT_CDMA) },
1190
1191 /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */
1192 { }
1193};
1194
1195MODULE_DEVICE_TABLE (usb, acm_ids);
1196
1197static struct usb_driver acm_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 .name = "cdc_acm",
1199 .probe = acm_probe,
1200 .disconnect = acm_disconnect,
1201 .id_table = acm_ids,
1202};
1203
1204/*
1205 * TTY driver structures.
1206 */
1207
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001208static const struct tty_operations acm_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 .open = acm_tty_open,
1210 .close = acm_tty_close,
1211 .write = acm_tty_write,
1212 .write_room = acm_tty_write_room,
1213 .ioctl = acm_tty_ioctl,
1214 .throttle = acm_tty_throttle,
1215 .unthrottle = acm_tty_unthrottle,
1216 .chars_in_buffer = acm_tty_chars_in_buffer,
1217 .break_ctl = acm_tty_break_ctl,
1218 .set_termios = acm_tty_set_termios,
1219 .tiocmget = acm_tty_tiocmget,
1220 .tiocmset = acm_tty_tiocmset,
1221};
1222
1223/*
1224 * Init / exit.
1225 */
1226
1227static int __init acm_init(void)
1228{
1229 int retval;
1230 acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
1231 if (!acm_tty_driver)
1232 return -ENOMEM;
1233 acm_tty_driver->owner = THIS_MODULE,
1234 acm_tty_driver->driver_name = "acm",
1235 acm_tty_driver->name = "ttyACM",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 acm_tty_driver->major = ACM_TTY_MAJOR,
1237 acm_tty_driver->minor_start = 0,
1238 acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
1239 acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001240 acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 acm_tty_driver->init_termios = tty_std_termios;
1242 acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1243 tty_set_operations(acm_tty_driver, &acm_ops);
1244
1245 retval = tty_register_driver(acm_tty_driver);
1246 if (retval) {
1247 put_tty_driver(acm_tty_driver);
1248 return retval;
1249 }
1250
1251 retval = usb_register(&acm_driver);
1252 if (retval) {
1253 tty_unregister_driver(acm_tty_driver);
1254 put_tty_driver(acm_tty_driver);
1255 return retval;
1256 }
1257
1258 info(DRIVER_VERSION ":" DRIVER_DESC);
1259
1260 return 0;
1261}
1262
1263static void __exit acm_exit(void)
1264{
1265 usb_deregister(&acm_driver);
1266 tty_unregister_driver(acm_tty_driver);
1267 put_tty_driver(acm_tty_driver);
1268}
1269
1270module_init(acm_init);
1271module_exit(acm_exit);
1272
1273MODULE_AUTHOR( DRIVER_AUTHOR );
1274MODULE_DESCRIPTION( DRIVER_DESC );
1275MODULE_LICENSE("GPL");
1276