Commit e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4
Committed by
Greg Kroah-Hartman
1 parent
28d1dfadd3
Exists in
master
and in
7 other branches
USB: increase cdc-acm write throughput
the following patch uses 16 write urbs and a writsize of wMaxPacketSize * 20. With this patch I get the maximum througput from my linux system with 20MB/sec read and 15 MB/sec write (full speed 1 MB/sec both) I also deleted the flag URB_NO_FSBR for the writeurbs, because this makes my full speed devices significant slower. Signed-off-by: David Engraf <david.engraf@netcom.eu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 2 changed files with 45 additions and 43 deletions Inline Diff
drivers/usb/class/cdc-acm.c
1 | /* | 1 | /* |
2 | * cdc-acm.c | 2 | * cdc-acm.c |
3 | * | 3 | * |
4 | * Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de> | 4 | * Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de> |
5 | * Copyright (c) 1999 Pavel Machek <pavel@suse.cz> | 5 | * Copyright (c) 1999 Pavel Machek <pavel@suse.cz> |
6 | * Copyright (c) 1999 Johannes Erdfelt <johannes@erdfelt.com> | 6 | * Copyright (c) 1999 Johannes Erdfelt <johannes@erdfelt.com> |
7 | * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> | 7 | * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> |
8 | * Copyright (c) 2004 Oliver Neukum <oliver@neukum.name> | 8 | * Copyright (c) 2004 Oliver Neukum <oliver@neukum.name> |
9 | * Copyright (c) 2005 David Kubicek <dave@awk.cz> | 9 | * Copyright (c) 2005 David Kubicek <dave@awk.cz> |
10 | * | 10 | * |
11 | * USB Abstract Control Model driver for USB modems and ISDN adapters | 11 | * USB Abstract Control Model driver for USB modems and ISDN adapters |
12 | * | 12 | * |
13 | * Sponsored by SuSE | 13 | * Sponsored by SuSE |
14 | * | 14 | * |
15 | * ChangeLog: | 15 | * ChangeLog: |
16 | * v0.9 - thorough cleaning, URBification, almost a rewrite | 16 | * v0.9 - thorough cleaning, URBification, almost a rewrite |
17 | * v0.10 - some more cleanups | 17 | * v0.10 - some more cleanups |
18 | * v0.11 - fixed flow control, read error doesn't stop reads | 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 | 19 | * v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced |
20 | * v0.13 - added termios, added hangup | 20 | * v0.13 - added termios, added hangup |
21 | * v0.14 - sized down struct acm | 21 | * v0.14 - sized down struct acm |
22 | * v0.15 - fixed flow control again - characters could be lost | 22 | * v0.15 - fixed flow control again - characters could be lost |
23 | * v0.16 - added code for modems with swapped data and control interfaces | 23 | * v0.16 - added code for modems with swapped data and control interfaces |
24 | * v0.17 - added new style probing | 24 | * v0.17 - added new style probing |
25 | * v0.18 - fixed new style probing for devices with more configurations | 25 | * v0.18 - fixed new style probing for devices with more configurations |
26 | * v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan) | 26 | * v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan) |
27 | * v0.20 - switched to probing on interface (rather than device) class | 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 | 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 | 29 | * v0.22 - probe only the control interface. if usbcore doesn't choose the |
30 | * config we want, sysadmin changes bConfigurationValue in sysfs. | 30 | * config we want, sysadmin changes bConfigurationValue in sysfs. |
31 | * v0.23 - use softirq for rx processing, as needed by tty layer | 31 | * v0.23 - use softirq for rx processing, as needed by tty layer |
32 | * v0.24 - change probe method to evaluate CDC union descriptor | 32 | * v0.24 - change probe method to evaluate CDC union descriptor |
33 | * v0.25 - downstream tasks paralelized to maximize throughput | 33 | * v0.25 - downstream tasks paralelized to maximize throughput |
34 | * v0.26 - multiple write urbs, writesize increased | ||
34 | */ | 35 | */ |
35 | 36 | ||
36 | /* | 37 | /* |
37 | * This program is free software; you can redistribute it and/or modify | 38 | * 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 | * 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 | * the Free Software Foundation; either version 2 of the License, or |
40 | * (at your option) any later version. | 41 | * (at your option) any later version. |
41 | * | 42 | * |
42 | * This program is distributed in the hope that it will be useful, | 43 | * This program is distributed in the hope that it will be useful, |
43 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 44 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
44 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 45 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
45 | * GNU General Public License for more details. | 46 | * GNU General Public License for more details. |
46 | * | 47 | * |
47 | * You should have received a copy of the GNU General Public License | 48 | * 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 | * 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 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
50 | */ | 51 | */ |
51 | 52 | ||
52 | #undef DEBUG | 53 | #undef DEBUG |
53 | 54 | ||
54 | #include <linux/kernel.h> | 55 | #include <linux/kernel.h> |
55 | #include <linux/errno.h> | 56 | #include <linux/errno.h> |
56 | #include <linux/init.h> | 57 | #include <linux/init.h> |
57 | #include <linux/slab.h> | 58 | #include <linux/slab.h> |
58 | #include <linux/tty.h> | 59 | #include <linux/tty.h> |
59 | #include <linux/tty_driver.h> | 60 | #include <linux/tty_driver.h> |
60 | #include <linux/tty_flip.h> | 61 | #include <linux/tty_flip.h> |
61 | #include <linux/module.h> | 62 | #include <linux/module.h> |
62 | #include <linux/mutex.h> | 63 | #include <linux/mutex.h> |
63 | #include <asm/uaccess.h> | 64 | #include <asm/uaccess.h> |
64 | #include <linux/usb.h> | 65 | #include <linux/usb.h> |
65 | #include <linux/usb/cdc.h> | 66 | #include <linux/usb/cdc.h> |
66 | #include <asm/byteorder.h> | 67 | #include <asm/byteorder.h> |
67 | #include <asm/unaligned.h> | 68 | #include <asm/unaligned.h> |
68 | #include <linux/list.h> | 69 | #include <linux/list.h> |
69 | 70 | ||
70 | #include "cdc-acm.h" | 71 | #include "cdc-acm.h" |
71 | 72 | ||
72 | /* | 73 | /* |
73 | * Version Information | 74 | * Version Information |
74 | */ | 75 | */ |
75 | #define DRIVER_VERSION "v0.25" | 76 | #define DRIVER_VERSION "v0.26" |
76 | #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek" | 77 | #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek" |
77 | #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" | 78 | #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" |
78 | 79 | ||
79 | static struct usb_driver acm_driver; | 80 | static struct usb_driver acm_driver; |
80 | static struct tty_driver *acm_tty_driver; | 81 | static struct tty_driver *acm_tty_driver; |
81 | static struct acm *acm_table[ACM_TTY_MINORS]; | 82 | static struct acm *acm_table[ACM_TTY_MINORS]; |
82 | 83 | ||
83 | static DEFINE_MUTEX(open_mutex); | 84 | static DEFINE_MUTEX(open_mutex); |
84 | 85 | ||
85 | #define ACM_READY(acm) (acm && acm->dev && acm->used) | 86 | #define ACM_READY(acm) (acm && acm->dev && acm->used) |
86 | 87 | ||
87 | /* | 88 | /* |
88 | * Functions for ACM control messages. | 89 | * Functions for ACM control messages. |
89 | */ | 90 | */ |
90 | 91 | ||
91 | static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len) | 92 | static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len) |
92 | { | 93 | { |
93 | int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), | 94 | int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), |
94 | request, USB_RT_ACM, value, | 95 | request, USB_RT_ACM, value, |
95 | acm->control->altsetting[0].desc.bInterfaceNumber, | 96 | acm->control->altsetting[0].desc.bInterfaceNumber, |
96 | buf, len, 5000); | 97 | buf, len, 5000); |
97 | dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval); | 98 | dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval); |
98 | return retval < 0 ? retval : 0; | 99 | return retval < 0 ? retval : 0; |
99 | } | 100 | } |
100 | 101 | ||
101 | /* devices aren't required to support these requests. | 102 | /* devices aren't required to support these requests. |
102 | * the cdc acm descriptor tells whether they do... | 103 | * the cdc acm descriptor tells whether they do... |
103 | */ | 104 | */ |
104 | #define acm_set_control(acm, control) \ | 105 | #define acm_set_control(acm, control) \ |
105 | acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0) | 106 | acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0) |
106 | #define acm_set_line(acm, line) \ | 107 | #define acm_set_line(acm, line) \ |
107 | acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line)) | 108 | acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line)) |
108 | #define acm_send_break(acm, ms) \ | 109 | #define acm_send_break(acm, ms) \ |
109 | acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0) | 110 | acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0) |
110 | 111 | ||
111 | /* | 112 | /* |
112 | * Write buffer management. | 113 | * Write buffer management. |
113 | * All of these assume proper locks taken by the caller. | 114 | * All of these assume proper locks taken by the caller. |
114 | */ | 115 | */ |
115 | 116 | ||
116 | static int acm_wb_alloc(struct acm *acm) | 117 | static int acm_wb_alloc(struct acm *acm) |
117 | { | 118 | { |
118 | int i, wbn; | 119 | int i, wbn; |
119 | struct acm_wb *wb; | 120 | struct acm_wb *wb; |
120 | 121 | ||
121 | wbn = acm->write_current; | 122 | wbn = 0; |
122 | i = 0; | 123 | i = 0; |
123 | for (;;) { | 124 | for (;;) { |
124 | wb = &acm->wb[wbn]; | 125 | wb = &acm->wb[wbn]; |
125 | if (!wb->use) { | 126 | if (!wb->use) { |
126 | wb->use = 1; | 127 | wb->use = 1; |
127 | return wbn; | 128 | return wbn; |
128 | } | 129 | } |
129 | wbn = (wbn + 1) % ACM_NW; | 130 | wbn = (wbn + 1) % ACM_NW; |
130 | if (++i >= ACM_NW) | 131 | if (++i >= ACM_NW) |
131 | return -1; | 132 | return -1; |
132 | } | 133 | } |
133 | } | 134 | } |
134 | 135 | ||
135 | static void acm_wb_free(struct acm *acm, int wbn) | ||
136 | { | ||
137 | acm->wb[wbn].use = 0; | ||
138 | } | ||
139 | |||
140 | static int acm_wb_is_avail(struct acm *acm) | 136 | static int acm_wb_is_avail(struct acm *acm) |
141 | { | 137 | { |
142 | int i, n; | 138 | int i, n; |
143 | 139 | ||
144 | n = ACM_NW; | 140 | n = ACM_NW; |
145 | for (i = 0; i < ACM_NW; i++) { | 141 | for (i = 0; i < ACM_NW; i++) { |
146 | n -= acm->wb[i].use; | 142 | n -= acm->wb[i].use; |
147 | } | 143 | } |
148 | return n; | 144 | return n; |
149 | } | 145 | } |
150 | 146 | ||
151 | static inline int acm_wb_is_used(struct acm *acm, int wbn) | 147 | static inline int acm_wb_is_used(struct acm *acm, int wbn) |
152 | { | 148 | { |
153 | return acm->wb[wbn].use; | 149 | return acm->wb[wbn].use; |
154 | } | 150 | } |
155 | 151 | ||
156 | /* | 152 | /* |
157 | * Finish write. | 153 | * Finish write. |
158 | */ | 154 | */ |
159 | static void acm_write_done(struct acm *acm) | 155 | static void acm_write_done(struct acm *acm, struct acm_wb *wb) |
160 | { | 156 | { |
161 | unsigned long flags; | 157 | unsigned long flags; |
162 | int wbn; | ||
163 | 158 | ||
164 | spin_lock_irqsave(&acm->write_lock, flags); | 159 | spin_lock_irqsave(&acm->write_lock, flags); |
165 | acm->write_ready = 1; | 160 | acm->write_ready = 1; |
166 | wbn = acm->write_current; | 161 | wb->use = 0; |
167 | acm_wb_free(acm, wbn); | ||
168 | acm->write_current = (wbn + 1) % ACM_NW; | ||
169 | spin_unlock_irqrestore(&acm->write_lock, flags); | 162 | spin_unlock_irqrestore(&acm->write_lock, flags); |
170 | } | 163 | } |
171 | 164 | ||
172 | /* | 165 | /* |
173 | * Poke write. | 166 | * Poke write. |
174 | */ | 167 | */ |
175 | static int acm_write_start(struct acm *acm) | 168 | static int acm_write_start(struct acm *acm, int wbn) |
176 | { | 169 | { |
177 | unsigned long flags; | 170 | unsigned long flags; |
178 | int wbn; | ||
179 | struct acm_wb *wb; | 171 | struct acm_wb *wb; |
180 | int rc; | 172 | int rc; |
181 | 173 | ||
182 | spin_lock_irqsave(&acm->write_lock, flags); | 174 | spin_lock_irqsave(&acm->write_lock, flags); |
183 | if (!acm->dev) { | 175 | if (!acm->dev) { |
184 | spin_unlock_irqrestore(&acm->write_lock, flags); | 176 | spin_unlock_irqrestore(&acm->write_lock, flags); |
185 | return -ENODEV; | 177 | return -ENODEV; |
186 | } | 178 | } |
187 | 179 | ||
188 | if (!acm->write_ready) { | 180 | if (!acm->write_ready) { |
189 | spin_unlock_irqrestore(&acm->write_lock, flags); | 181 | spin_unlock_irqrestore(&acm->write_lock, flags); |
190 | return 0; /* A white lie */ | 182 | return 0; /* A white lie */ |
191 | } | 183 | } |
192 | 184 | ||
193 | wbn = acm->write_current; | ||
194 | if (!acm_wb_is_used(acm, wbn)) { | 185 | if (!acm_wb_is_used(acm, wbn)) { |
195 | spin_unlock_irqrestore(&acm->write_lock, flags); | 186 | spin_unlock_irqrestore(&acm->write_lock, flags); |
196 | return 0; | 187 | return 0; |
197 | } | 188 | } |
198 | wb = &acm->wb[wbn]; | 189 | wb = &acm->wb[wbn]; |
199 | 190 | ||
200 | acm->write_ready = 0; | 191 | if(acm_wb_is_avail(acm) <= 1) |
192 | acm->write_ready = 0; | ||
201 | spin_unlock_irqrestore(&acm->write_lock, flags); | 193 | spin_unlock_irqrestore(&acm->write_lock, flags); |
202 | 194 | ||
203 | acm->writeurb->transfer_buffer = wb->buf; | 195 | wb->urb->transfer_buffer = wb->buf; |
204 | acm->writeurb->transfer_dma = wb->dmah; | 196 | wb->urb->transfer_dma = wb->dmah; |
205 | acm->writeurb->transfer_buffer_length = wb->len; | 197 | wb->urb->transfer_buffer_length = wb->len; |
206 | acm->writeurb->dev = acm->dev; | 198 | wb->urb->dev = acm->dev; |
207 | 199 | ||
208 | if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) { | 200 | if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) { |
209 | dbg("usb_submit_urb(write bulk) failed: %d", rc); | 201 | dbg("usb_submit_urb(write bulk) failed: %d", rc); |
210 | acm_write_done(acm); | 202 | acm_write_done(acm, wb); |
211 | } | 203 | } |
212 | return rc; | 204 | return rc; |
213 | } | 205 | } |
214 | /* | 206 | /* |
215 | * attributes exported through sysfs | 207 | * attributes exported through sysfs |
216 | */ | 208 | */ |
217 | static ssize_t show_caps | 209 | static ssize_t show_caps |
218 | (struct device *dev, struct device_attribute *attr, char *buf) | 210 | (struct device *dev, struct device_attribute *attr, char *buf) |
219 | { | 211 | { |
220 | struct usb_interface *intf = to_usb_interface(dev); | 212 | struct usb_interface *intf = to_usb_interface(dev); |
221 | struct acm *acm = usb_get_intfdata(intf); | 213 | struct acm *acm = usb_get_intfdata(intf); |
222 | 214 | ||
223 | return sprintf(buf, "%d", acm->ctrl_caps); | 215 | return sprintf(buf, "%d", acm->ctrl_caps); |
224 | } | 216 | } |
225 | static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL); | 217 | static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL); |
226 | 218 | ||
227 | static ssize_t show_country_codes | 219 | static ssize_t show_country_codes |
228 | (struct device *dev, struct device_attribute *attr, char *buf) | 220 | (struct device *dev, struct device_attribute *attr, char *buf) |
229 | { | 221 | { |
230 | struct usb_interface *intf = to_usb_interface(dev); | 222 | struct usb_interface *intf = to_usb_interface(dev); |
231 | struct acm *acm = usb_get_intfdata(intf); | 223 | struct acm *acm = usb_get_intfdata(intf); |
232 | 224 | ||
233 | memcpy(buf, acm->country_codes, acm->country_code_size); | 225 | memcpy(buf, acm->country_codes, acm->country_code_size); |
234 | return acm->country_code_size; | 226 | return acm->country_code_size; |
235 | } | 227 | } |
236 | 228 | ||
237 | static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL); | 229 | static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL); |
238 | 230 | ||
239 | static ssize_t show_country_rel_date | 231 | static ssize_t show_country_rel_date |
240 | (struct device *dev, struct device_attribute *attr, char *buf) | 232 | (struct device *dev, struct device_attribute *attr, char *buf) |
241 | { | 233 | { |
242 | struct usb_interface *intf = to_usb_interface(dev); | 234 | struct usb_interface *intf = to_usb_interface(dev); |
243 | struct acm *acm = usb_get_intfdata(intf); | 235 | struct acm *acm = usb_get_intfdata(intf); |
244 | 236 | ||
245 | return sprintf(buf, "%d", acm->country_rel_date); | 237 | return sprintf(buf, "%d", acm->country_rel_date); |
246 | } | 238 | } |
247 | 239 | ||
248 | static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL); | 240 | static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL); |
249 | /* | 241 | /* |
250 | * Interrupt handlers for various ACM device responses | 242 | * Interrupt handlers for various ACM device responses |
251 | */ | 243 | */ |
252 | 244 | ||
253 | /* control interface reports status changes with "interrupt" transfers */ | 245 | /* control interface reports status changes with "interrupt" transfers */ |
254 | static void acm_ctrl_irq(struct urb *urb) | 246 | static void acm_ctrl_irq(struct urb *urb) |
255 | { | 247 | { |
256 | struct acm *acm = urb->context; | 248 | struct acm *acm = urb->context; |
257 | struct usb_cdc_notification *dr = urb->transfer_buffer; | 249 | struct usb_cdc_notification *dr = urb->transfer_buffer; |
258 | unsigned char *data; | 250 | unsigned char *data; |
259 | int newctrl; | 251 | int newctrl; |
260 | int retval; | 252 | int retval; |
261 | int status = urb->status; | 253 | int status = urb->status; |
262 | 254 | ||
263 | switch (status) { | 255 | switch (status) { |
264 | case 0: | 256 | case 0: |
265 | /* success */ | 257 | /* success */ |
266 | break; | 258 | break; |
267 | case -ECONNRESET: | 259 | case -ECONNRESET: |
268 | case -ENOENT: | 260 | case -ENOENT: |
269 | case -ESHUTDOWN: | 261 | case -ESHUTDOWN: |
270 | /* this urb is terminated, clean up */ | 262 | /* this urb is terminated, clean up */ |
271 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, status); | 263 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, status); |
272 | return; | 264 | return; |
273 | default: | 265 | default: |
274 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, status); | 266 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, status); |
275 | goto exit; | 267 | goto exit; |
276 | } | 268 | } |
277 | 269 | ||
278 | if (!ACM_READY(acm)) | 270 | if (!ACM_READY(acm)) |
279 | goto exit; | 271 | goto exit; |
280 | 272 | ||
281 | data = (unsigned char *)(dr + 1); | 273 | data = (unsigned char *)(dr + 1); |
282 | switch (dr->bNotificationType) { | 274 | switch (dr->bNotificationType) { |
283 | 275 | ||
284 | case USB_CDC_NOTIFY_NETWORK_CONNECTION: | 276 | case USB_CDC_NOTIFY_NETWORK_CONNECTION: |
285 | 277 | ||
286 | dbg("%s network", dr->wValue ? "connected to" : "disconnected from"); | 278 | dbg("%s network", dr->wValue ? "connected to" : "disconnected from"); |
287 | break; | 279 | break; |
288 | 280 | ||
289 | case USB_CDC_NOTIFY_SERIAL_STATE: | 281 | case USB_CDC_NOTIFY_SERIAL_STATE: |
290 | 282 | ||
291 | newctrl = le16_to_cpu(get_unaligned((__le16 *) data)); | 283 | newctrl = le16_to_cpu(get_unaligned((__le16 *) data)); |
292 | 284 | ||
293 | if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { | 285 | if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { |
294 | dbg("calling hangup"); | 286 | dbg("calling hangup"); |
295 | tty_hangup(acm->tty); | 287 | tty_hangup(acm->tty); |
296 | } | 288 | } |
297 | 289 | ||
298 | acm->ctrlin = newctrl; | 290 | acm->ctrlin = newctrl; |
299 | 291 | ||
300 | dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c", | 292 | 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 ? '+' : '-', | 293 | acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-', |
302 | acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-', | 294 | acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-', |
303 | acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-', | 295 | acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-', |
304 | acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-'); | 296 | acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-'); |
305 | 297 | ||
306 | break; | 298 | break; |
307 | 299 | ||
308 | default: | 300 | default: |
309 | dbg("unknown notification %d received: index %d len %d data0 %d data1 %d", | 301 | dbg("unknown notification %d received: index %d len %d data0 %d data1 %d", |
310 | dr->bNotificationType, dr->wIndex, | 302 | dr->bNotificationType, dr->wIndex, |
311 | dr->wLength, data[0], data[1]); | 303 | dr->wLength, data[0], data[1]); |
312 | break; | 304 | break; |
313 | } | 305 | } |
314 | exit: | 306 | exit: |
315 | retval = usb_submit_urb (urb, GFP_ATOMIC); | 307 | retval = usb_submit_urb (urb, GFP_ATOMIC); |
316 | if (retval) | 308 | if (retval) |
317 | err ("%s - usb_submit_urb failed with result %d", | 309 | err ("%s - usb_submit_urb failed with result %d", |
318 | __FUNCTION__, retval); | 310 | __FUNCTION__, retval); |
319 | } | 311 | } |
320 | 312 | ||
321 | /* data interface returns incoming bytes, or we got unthrottled */ | 313 | /* data interface returns incoming bytes, or we got unthrottled */ |
322 | static void acm_read_bulk(struct urb *urb) | 314 | static void acm_read_bulk(struct urb *urb) |
323 | { | 315 | { |
324 | struct acm_rb *buf; | 316 | struct acm_rb *buf; |
325 | struct acm_ru *rcv = urb->context; | 317 | struct acm_ru *rcv = urb->context; |
326 | struct acm *acm = rcv->instance; | 318 | struct acm *acm = rcv->instance; |
327 | int status = urb->status; | 319 | int status = urb->status; |
328 | 320 | ||
329 | dbg("Entering acm_read_bulk with status %d", status); | 321 | dbg("Entering acm_read_bulk with status %d", status); |
330 | 322 | ||
331 | if (!ACM_READY(acm)) | 323 | if (!ACM_READY(acm)) |
332 | return; | 324 | return; |
333 | 325 | ||
334 | if (status) | 326 | if (status) |
335 | dev_dbg(&acm->data->dev, "bulk rx status %d\n", status); | 327 | dev_dbg(&acm->data->dev, "bulk rx status %d\n", status); |
336 | 328 | ||
337 | buf = rcv->buffer; | 329 | buf = rcv->buffer; |
338 | buf->size = urb->actual_length; | 330 | buf->size = urb->actual_length; |
339 | 331 | ||
340 | if (likely(status == 0)) { | 332 | if (likely(status == 0)) { |
341 | spin_lock(&acm->read_lock); | 333 | spin_lock(&acm->read_lock); |
342 | list_add_tail(&rcv->list, &acm->spare_read_urbs); | 334 | list_add_tail(&rcv->list, &acm->spare_read_urbs); |
343 | list_add_tail(&buf->list, &acm->filled_read_bufs); | 335 | list_add_tail(&buf->list, &acm->filled_read_bufs); |
344 | spin_unlock(&acm->read_lock); | 336 | spin_unlock(&acm->read_lock); |
345 | } else { | 337 | } else { |
346 | /* we drop the buffer due to an error */ | 338 | /* we drop the buffer due to an error */ |
347 | spin_lock(&acm->read_lock); | 339 | spin_lock(&acm->read_lock); |
348 | list_add_tail(&rcv->list, &acm->spare_read_urbs); | 340 | list_add_tail(&rcv->list, &acm->spare_read_urbs); |
349 | list_add(&buf->list, &acm->spare_read_bufs); | 341 | list_add(&buf->list, &acm->spare_read_bufs); |
350 | spin_unlock(&acm->read_lock); | 342 | spin_unlock(&acm->read_lock); |
351 | /* nevertheless the tasklet must be kicked unconditionally | 343 | /* nevertheless the tasklet must be kicked unconditionally |
352 | so the queue cannot dry up */ | 344 | so the queue cannot dry up */ |
353 | } | 345 | } |
354 | tasklet_schedule(&acm->urb_task); | 346 | tasklet_schedule(&acm->urb_task); |
355 | } | 347 | } |
356 | 348 | ||
357 | static void acm_rx_tasklet(unsigned long _acm) | 349 | static void acm_rx_tasklet(unsigned long _acm) |
358 | { | 350 | { |
359 | struct acm *acm = (void *)_acm; | 351 | struct acm *acm = (void *)_acm; |
360 | struct acm_rb *buf; | 352 | struct acm_rb *buf; |
361 | struct tty_struct *tty = acm->tty; | 353 | struct tty_struct *tty = acm->tty; |
362 | struct acm_ru *rcv; | 354 | struct acm_ru *rcv; |
363 | unsigned long flags; | 355 | unsigned long flags; |
364 | unsigned char throttled; | 356 | unsigned char throttled; |
365 | dbg("Entering acm_rx_tasklet"); | 357 | dbg("Entering acm_rx_tasklet"); |
366 | 358 | ||
367 | if (!ACM_READY(acm)) | 359 | if (!ACM_READY(acm)) |
368 | return; | 360 | return; |
369 | 361 | ||
370 | spin_lock_irqsave(&acm->throttle_lock, flags); | 362 | spin_lock_irqsave(&acm->throttle_lock, flags); |
371 | throttled = acm->throttle; | 363 | throttled = acm->throttle; |
372 | spin_unlock_irqrestore(&acm->throttle_lock, flags); | 364 | spin_unlock_irqrestore(&acm->throttle_lock, flags); |
373 | if (throttled) | 365 | if (throttled) |
374 | return; | 366 | return; |
375 | 367 | ||
376 | next_buffer: | 368 | next_buffer: |
377 | spin_lock_irqsave(&acm->read_lock, flags); | 369 | spin_lock_irqsave(&acm->read_lock, flags); |
378 | if (list_empty(&acm->filled_read_bufs)) { | 370 | if (list_empty(&acm->filled_read_bufs)) { |
379 | spin_unlock_irqrestore(&acm->read_lock, flags); | 371 | spin_unlock_irqrestore(&acm->read_lock, flags); |
380 | goto urbs; | 372 | goto urbs; |
381 | } | 373 | } |
382 | buf = list_entry(acm->filled_read_bufs.next, | 374 | buf = list_entry(acm->filled_read_bufs.next, |
383 | struct acm_rb, list); | 375 | struct acm_rb, list); |
384 | list_del(&buf->list); | 376 | list_del(&buf->list); |
385 | spin_unlock_irqrestore(&acm->read_lock, flags); | 377 | spin_unlock_irqrestore(&acm->read_lock, flags); |
386 | 378 | ||
387 | dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); | 379 | dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); |
388 | 380 | ||
389 | tty_buffer_request_room(tty, buf->size); | 381 | tty_buffer_request_room(tty, buf->size); |
390 | spin_lock_irqsave(&acm->throttle_lock, flags); | 382 | spin_lock_irqsave(&acm->throttle_lock, flags); |
391 | throttled = acm->throttle; | 383 | throttled = acm->throttle; |
392 | spin_unlock_irqrestore(&acm->throttle_lock, flags); | 384 | spin_unlock_irqrestore(&acm->throttle_lock, flags); |
393 | if (!throttled) | 385 | if (!throttled) |
394 | tty_insert_flip_string(tty, buf->base, buf->size); | 386 | tty_insert_flip_string(tty, buf->base, buf->size); |
395 | tty_flip_buffer_push(tty); | 387 | tty_flip_buffer_push(tty); |
396 | 388 | ||
397 | if (throttled) { | 389 | if (throttled) { |
398 | dbg("Throttling noticed"); | 390 | dbg("Throttling noticed"); |
399 | spin_lock_irqsave(&acm->read_lock, flags); | 391 | spin_lock_irqsave(&acm->read_lock, flags); |
400 | list_add(&buf->list, &acm->filled_read_bufs); | 392 | list_add(&buf->list, &acm->filled_read_bufs); |
401 | spin_unlock_irqrestore(&acm->read_lock, flags); | 393 | spin_unlock_irqrestore(&acm->read_lock, flags); |
402 | return; | 394 | return; |
403 | } | 395 | } |
404 | 396 | ||
405 | spin_lock_irqsave(&acm->read_lock, flags); | 397 | spin_lock_irqsave(&acm->read_lock, flags); |
406 | list_add(&buf->list, &acm->spare_read_bufs); | 398 | list_add(&buf->list, &acm->spare_read_bufs); |
407 | spin_unlock_irqrestore(&acm->read_lock, flags); | 399 | spin_unlock_irqrestore(&acm->read_lock, flags); |
408 | goto next_buffer; | 400 | goto next_buffer; |
409 | 401 | ||
410 | urbs: | 402 | urbs: |
411 | while (!list_empty(&acm->spare_read_bufs)) { | 403 | while (!list_empty(&acm->spare_read_bufs)) { |
412 | spin_lock_irqsave(&acm->read_lock, flags); | 404 | spin_lock_irqsave(&acm->read_lock, flags); |
413 | if (list_empty(&acm->spare_read_urbs)) { | 405 | if (list_empty(&acm->spare_read_urbs)) { |
414 | spin_unlock_irqrestore(&acm->read_lock, flags); | 406 | spin_unlock_irqrestore(&acm->read_lock, flags); |
415 | return; | 407 | return; |
416 | } | 408 | } |
417 | rcv = list_entry(acm->spare_read_urbs.next, | 409 | rcv = list_entry(acm->spare_read_urbs.next, |
418 | struct acm_ru, list); | 410 | struct acm_ru, list); |
419 | list_del(&rcv->list); | 411 | list_del(&rcv->list); |
420 | spin_unlock_irqrestore(&acm->read_lock, flags); | 412 | spin_unlock_irqrestore(&acm->read_lock, flags); |
421 | 413 | ||
422 | buf = list_entry(acm->spare_read_bufs.next, | 414 | buf = list_entry(acm->spare_read_bufs.next, |
423 | struct acm_rb, list); | 415 | struct acm_rb, list); |
424 | list_del(&buf->list); | 416 | list_del(&buf->list); |
425 | 417 | ||
426 | rcv->buffer = buf; | 418 | rcv->buffer = buf; |
427 | 419 | ||
428 | usb_fill_bulk_urb(rcv->urb, acm->dev, | 420 | usb_fill_bulk_urb(rcv->urb, acm->dev, |
429 | acm->rx_endpoint, | 421 | acm->rx_endpoint, |
430 | buf->base, | 422 | buf->base, |
431 | acm->readsize, | 423 | acm->readsize, |
432 | acm_read_bulk, rcv); | 424 | acm_read_bulk, rcv); |
433 | rcv->urb->transfer_dma = buf->dma; | 425 | rcv->urb->transfer_dma = buf->dma; |
434 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 426 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
435 | 427 | ||
436 | dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf); | 428 | dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf); |
437 | 429 | ||
438 | /* This shouldn't kill the driver as unsuccessful URBs are returned to the | 430 | /* This shouldn't kill the driver as unsuccessful URBs are returned to the |
439 | free-urbs-pool and resubmited ASAP */ | 431 | free-urbs-pool and resubmited ASAP */ |
440 | if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { | 432 | if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { |
441 | list_add(&buf->list, &acm->spare_read_bufs); | 433 | list_add(&buf->list, &acm->spare_read_bufs); |
442 | spin_lock_irqsave(&acm->read_lock, flags); | 434 | spin_lock_irqsave(&acm->read_lock, flags); |
443 | list_add(&rcv->list, &acm->spare_read_urbs); | 435 | list_add(&rcv->list, &acm->spare_read_urbs); |
444 | spin_unlock_irqrestore(&acm->read_lock, flags); | 436 | spin_unlock_irqrestore(&acm->read_lock, flags); |
445 | return; | 437 | return; |
446 | } | 438 | } |
447 | } | 439 | } |
448 | } | 440 | } |
449 | 441 | ||
450 | /* data interface wrote those outgoing bytes */ | 442 | /* data interface wrote those outgoing bytes */ |
451 | static void acm_write_bulk(struct urb *urb) | 443 | static void acm_write_bulk(struct urb *urb) |
452 | { | 444 | { |
453 | struct acm *acm = (struct acm *)urb->context; | 445 | struct acm *acm; |
446 | struct acm_wb *wb = (struct acm_wb *)urb->context; | ||
454 | 447 | ||
455 | dbg("Entering acm_write_bulk with status %d", urb->status); | 448 | dbg("Entering acm_write_bulk with status %d", urb->status); |
456 | 449 | ||
457 | acm_write_done(acm); | 450 | acm = wb->instance; |
458 | acm_write_start(acm); | 451 | acm_write_done(acm, wb); |
459 | if (ACM_READY(acm)) | 452 | if (ACM_READY(acm)) |
460 | schedule_work(&acm->work); | 453 | schedule_work(&acm->work); |
461 | } | 454 | } |
462 | 455 | ||
463 | static void acm_softint(struct work_struct *work) | 456 | static void acm_softint(struct work_struct *work) |
464 | { | 457 | { |
465 | struct acm *acm = container_of(work, struct acm, work); | 458 | struct acm *acm = container_of(work, struct acm, work); |
466 | dbg("Entering acm_softint."); | 459 | dbg("Entering acm_softint."); |
467 | 460 | ||
468 | if (!ACM_READY(acm)) | 461 | if (!ACM_READY(acm)) |
469 | return; | 462 | return; |
470 | tty_wakeup(acm->tty); | 463 | tty_wakeup(acm->tty); |
471 | } | 464 | } |
472 | 465 | ||
473 | /* | 466 | /* |
474 | * TTY handlers | 467 | * TTY handlers |
475 | */ | 468 | */ |
476 | 469 | ||
477 | static int acm_tty_open(struct tty_struct *tty, struct file *filp) | 470 | static int acm_tty_open(struct tty_struct *tty, struct file *filp) |
478 | { | 471 | { |
479 | struct acm *acm; | 472 | struct acm *acm; |
480 | int rv = -EINVAL; | 473 | int rv = -EINVAL; |
481 | int i; | 474 | int i; |
482 | dbg("Entering acm_tty_open."); | 475 | dbg("Entering acm_tty_open."); |
483 | 476 | ||
484 | mutex_lock(&open_mutex); | 477 | mutex_lock(&open_mutex); |
485 | 478 | ||
486 | acm = acm_table[tty->index]; | 479 | acm = acm_table[tty->index]; |
487 | if (!acm || !acm->dev) | 480 | if (!acm || !acm->dev) |
488 | goto err_out; | 481 | goto err_out; |
489 | else | 482 | else |
490 | rv = 0; | 483 | rv = 0; |
491 | 484 | ||
492 | set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); | 485 | set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); |
493 | tty->driver_data = acm; | 486 | tty->driver_data = acm; |
494 | acm->tty = tty; | 487 | acm->tty = tty; |
495 | 488 | ||
496 | /* force low_latency on so that our tty_push actually forces the data through, | 489 | /* force low_latency on so that our tty_push actually forces the data through, |
497 | otherwise it is scheduled, and with high data rates data can get lost. */ | 490 | otherwise it is scheduled, and with high data rates data can get lost. */ |
498 | tty->low_latency = 1; | 491 | tty->low_latency = 1; |
499 | 492 | ||
500 | if (usb_autopm_get_interface(acm->control) < 0) | 493 | if (usb_autopm_get_interface(acm->control) < 0) |
501 | goto early_bail; | 494 | goto early_bail; |
502 | 495 | ||
503 | mutex_lock(&acm->mutex); | 496 | mutex_lock(&acm->mutex); |
504 | if (acm->used++) { | 497 | if (acm->used++) { |
505 | usb_autopm_put_interface(acm->control); | 498 | usb_autopm_put_interface(acm->control); |
506 | goto done; | 499 | goto done; |
507 | } | 500 | } |
508 | 501 | ||
509 | 502 | ||
510 | acm->ctrlurb->dev = acm->dev; | 503 | acm->ctrlurb->dev = acm->dev; |
511 | if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { | 504 | if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { |
512 | dbg("usb_submit_urb(ctrl irq) failed"); | 505 | dbg("usb_submit_urb(ctrl irq) failed"); |
513 | goto bail_out; | 506 | goto bail_out; |
514 | } | 507 | } |
515 | 508 | ||
516 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && | 509 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && |
517 | (acm->ctrl_caps & USB_CDC_CAP_LINE)) | 510 | (acm->ctrl_caps & USB_CDC_CAP_LINE)) |
518 | goto full_bailout; | 511 | goto full_bailout; |
519 | 512 | ||
520 | INIT_LIST_HEAD(&acm->spare_read_urbs); | 513 | INIT_LIST_HEAD(&acm->spare_read_urbs); |
521 | INIT_LIST_HEAD(&acm->spare_read_bufs); | 514 | INIT_LIST_HEAD(&acm->spare_read_bufs); |
522 | INIT_LIST_HEAD(&acm->filled_read_bufs); | 515 | INIT_LIST_HEAD(&acm->filled_read_bufs); |
523 | for (i = 0; i < acm->rx_buflimit; i++) { | 516 | for (i = 0; i < acm->rx_buflimit; i++) { |
524 | list_add(&(acm->ru[i].list), &acm->spare_read_urbs); | 517 | list_add(&(acm->ru[i].list), &acm->spare_read_urbs); |
525 | } | 518 | } |
526 | for (i = 0; i < acm->rx_buflimit; i++) { | 519 | for (i = 0; i < acm->rx_buflimit; i++) { |
527 | list_add(&(acm->rb[i].list), &acm->spare_read_bufs); | 520 | list_add(&(acm->rb[i].list), &acm->spare_read_bufs); |
528 | } | 521 | } |
529 | 522 | ||
530 | acm->throttle = 0; | 523 | acm->throttle = 0; |
531 | 524 | ||
532 | tasklet_schedule(&acm->urb_task); | 525 | tasklet_schedule(&acm->urb_task); |
533 | 526 | ||
534 | done: | 527 | done: |
535 | err_out: | 528 | err_out: |
536 | mutex_unlock(&acm->mutex); | 529 | mutex_unlock(&acm->mutex); |
537 | mutex_unlock(&open_mutex); | 530 | mutex_unlock(&open_mutex); |
538 | return rv; | 531 | return rv; |
539 | 532 | ||
540 | full_bailout: | 533 | full_bailout: |
541 | usb_kill_urb(acm->ctrlurb); | 534 | usb_kill_urb(acm->ctrlurb); |
542 | bail_out: | 535 | bail_out: |
543 | usb_autopm_put_interface(acm->control); | 536 | usb_autopm_put_interface(acm->control); |
544 | acm->used--; | 537 | acm->used--; |
545 | mutex_unlock(&acm->mutex); | 538 | mutex_unlock(&acm->mutex); |
546 | early_bail: | 539 | early_bail: |
547 | mutex_unlock(&open_mutex); | 540 | mutex_unlock(&open_mutex); |
548 | return -EIO; | 541 | return -EIO; |
549 | } | 542 | } |
550 | 543 | ||
551 | static void acm_tty_unregister(struct acm *acm) | 544 | static void acm_tty_unregister(struct acm *acm) |
552 | { | 545 | { |
553 | int i,nr; | 546 | int i,nr; |
554 | 547 | ||
555 | nr = acm->rx_buflimit; | 548 | nr = acm->rx_buflimit; |
556 | tty_unregister_device(acm_tty_driver, acm->minor); | 549 | tty_unregister_device(acm_tty_driver, acm->minor); |
557 | usb_put_intf(acm->control); | 550 | usb_put_intf(acm->control); |
558 | acm_table[acm->minor] = NULL; | 551 | acm_table[acm->minor] = NULL; |
559 | usb_free_urb(acm->ctrlurb); | 552 | usb_free_urb(acm->ctrlurb); |
560 | usb_free_urb(acm->writeurb); | 553 | for (i = 0; i < ACM_NW; i++) |
554 | usb_free_urb(acm->wb[i].urb); | ||
561 | for (i = 0; i < nr; i++) | 555 | for (i = 0; i < nr; i++) |
562 | usb_free_urb(acm->ru[i].urb); | 556 | usb_free_urb(acm->ru[i].urb); |
563 | kfree(acm->country_codes); | 557 | kfree(acm->country_codes); |
564 | kfree(acm); | 558 | kfree(acm); |
565 | } | 559 | } |
566 | 560 | ||
567 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) | 561 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) |
568 | { | 562 | { |
569 | struct acm *acm = tty->driver_data; | 563 | struct acm *acm = tty->driver_data; |
570 | int i,nr; | 564 | int i,nr; |
571 | 565 | ||
572 | if (!acm || !acm->used) | 566 | if (!acm || !acm->used) |
573 | return; | 567 | return; |
574 | 568 | ||
575 | nr = acm->rx_buflimit; | 569 | nr = acm->rx_buflimit; |
576 | mutex_lock(&open_mutex); | 570 | mutex_lock(&open_mutex); |
577 | if (!--acm->used) { | 571 | if (!--acm->used) { |
578 | if (acm->dev) { | 572 | if (acm->dev) { |
579 | acm_set_control(acm, acm->ctrlout = 0); | 573 | acm_set_control(acm, acm->ctrlout = 0); |
580 | usb_kill_urb(acm->ctrlurb); | 574 | usb_kill_urb(acm->ctrlurb); |
581 | usb_kill_urb(acm->writeurb); | 575 | for (i = 0; i < ACM_NW; i++) |
576 | usb_kill_urb(acm->wb[i].urb); | ||
582 | for (i = 0; i < nr; i++) | 577 | for (i = 0; i < nr; i++) |
583 | usb_kill_urb(acm->ru[i].urb); | 578 | usb_kill_urb(acm->ru[i].urb); |
584 | usb_autopm_put_interface(acm->control); | 579 | usb_autopm_put_interface(acm->control); |
585 | } else | 580 | } else |
586 | acm_tty_unregister(acm); | 581 | acm_tty_unregister(acm); |
587 | } | 582 | } |
588 | mutex_unlock(&open_mutex); | 583 | mutex_unlock(&open_mutex); |
589 | } | 584 | } |
590 | 585 | ||
591 | static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) | 586 | static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) |
592 | { | 587 | { |
593 | struct acm *acm = tty->driver_data; | 588 | struct acm *acm = tty->driver_data; |
594 | int stat; | 589 | int stat; |
595 | unsigned long flags; | 590 | unsigned long flags; |
596 | int wbn; | 591 | int wbn; |
597 | struct acm_wb *wb; | 592 | struct acm_wb *wb; |
598 | 593 | ||
599 | dbg("Entering acm_tty_write to write %d bytes,", count); | 594 | dbg("Entering acm_tty_write to write %d bytes,", count); |
600 | 595 | ||
601 | if (!ACM_READY(acm)) | 596 | if (!ACM_READY(acm)) |
602 | return -EINVAL; | 597 | return -EINVAL; |
603 | if (!count) | 598 | if (!count) |
604 | return 0; | 599 | return 0; |
605 | 600 | ||
606 | spin_lock_irqsave(&acm->write_lock, flags); | 601 | spin_lock_irqsave(&acm->write_lock, flags); |
607 | if ((wbn = acm_wb_alloc(acm)) < 0) { | 602 | if ((wbn = acm_wb_alloc(acm)) < 0) { |
608 | spin_unlock_irqrestore(&acm->write_lock, flags); | 603 | spin_unlock_irqrestore(&acm->write_lock, flags); |
609 | acm_write_start(acm); | ||
610 | return 0; | 604 | return 0; |
611 | } | 605 | } |
612 | wb = &acm->wb[wbn]; | 606 | wb = &acm->wb[wbn]; |
613 | 607 | ||
614 | count = (count > acm->writesize) ? acm->writesize : count; | 608 | count = (count > acm->writesize) ? acm->writesize : count; |
615 | dbg("Get %d bytes...", count); | 609 | dbg("Get %d bytes...", count); |
616 | memcpy(wb->buf, buf, count); | 610 | memcpy(wb->buf, buf, count); |
617 | wb->len = count; | 611 | wb->len = count; |
618 | spin_unlock_irqrestore(&acm->write_lock, flags); | 612 | spin_unlock_irqrestore(&acm->write_lock, flags); |
619 | 613 | ||
620 | if ((stat = acm_write_start(acm)) < 0) | 614 | if ((stat = acm_write_start(acm, wbn)) < 0) |
621 | return stat; | 615 | return stat; |
622 | return count; | 616 | return count; |
623 | } | 617 | } |
624 | 618 | ||
625 | static int acm_tty_write_room(struct tty_struct *tty) | 619 | static int acm_tty_write_room(struct tty_struct *tty) |
626 | { | 620 | { |
627 | struct acm *acm = tty->driver_data; | 621 | struct acm *acm = tty->driver_data; |
628 | if (!ACM_READY(acm)) | 622 | if (!ACM_READY(acm)) |
629 | return -EINVAL; | 623 | return -EINVAL; |
630 | /* | 624 | /* |
631 | * Do not let the line discipline to know that we have a reserve, | 625 | * Do not let the line discipline to know that we have a reserve, |
632 | * or it might get too enthusiastic. | 626 | * or it might get too enthusiastic. |
633 | */ | 627 | */ |
634 | return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0; | 628 | return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0; |
635 | } | 629 | } |
636 | 630 | ||
637 | static int acm_tty_chars_in_buffer(struct tty_struct *tty) | 631 | static int acm_tty_chars_in_buffer(struct tty_struct *tty) |
638 | { | 632 | { |
639 | struct acm *acm = tty->driver_data; | 633 | struct acm *acm = tty->driver_data; |
640 | if (!ACM_READY(acm)) | 634 | if (!ACM_READY(acm)) |
641 | return -EINVAL; | 635 | return -EINVAL; |
642 | /* | 636 | /* |
643 | * This is inaccurate (overcounts), but it works. | 637 | * This is inaccurate (overcounts), but it works. |
644 | */ | 638 | */ |
645 | return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize; | 639 | return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize; |
646 | } | 640 | } |
647 | 641 | ||
648 | static void acm_tty_throttle(struct tty_struct *tty) | 642 | static void acm_tty_throttle(struct tty_struct *tty) |
649 | { | 643 | { |
650 | struct acm *acm = tty->driver_data; | 644 | struct acm *acm = tty->driver_data; |
651 | if (!ACM_READY(acm)) | 645 | if (!ACM_READY(acm)) |
652 | return; | 646 | return; |
653 | spin_lock_bh(&acm->throttle_lock); | 647 | spin_lock_bh(&acm->throttle_lock); |
654 | acm->throttle = 1; | 648 | acm->throttle = 1; |
655 | spin_unlock_bh(&acm->throttle_lock); | 649 | spin_unlock_bh(&acm->throttle_lock); |
656 | } | 650 | } |
657 | 651 | ||
658 | static void acm_tty_unthrottle(struct tty_struct *tty) | 652 | static void acm_tty_unthrottle(struct tty_struct *tty) |
659 | { | 653 | { |
660 | struct acm *acm = tty->driver_data; | 654 | struct acm *acm = tty->driver_data; |
661 | if (!ACM_READY(acm)) | 655 | if (!ACM_READY(acm)) |
662 | return; | 656 | return; |
663 | spin_lock_bh(&acm->throttle_lock); | 657 | spin_lock_bh(&acm->throttle_lock); |
664 | acm->throttle = 0; | 658 | acm->throttle = 0; |
665 | spin_unlock_bh(&acm->throttle_lock); | 659 | spin_unlock_bh(&acm->throttle_lock); |
666 | tasklet_schedule(&acm->urb_task); | 660 | tasklet_schedule(&acm->urb_task); |
667 | } | 661 | } |
668 | 662 | ||
669 | static void acm_tty_break_ctl(struct tty_struct *tty, int state) | 663 | static void acm_tty_break_ctl(struct tty_struct *tty, int state) |
670 | { | 664 | { |
671 | struct acm *acm = tty->driver_data; | 665 | struct acm *acm = tty->driver_data; |
672 | if (!ACM_READY(acm)) | 666 | if (!ACM_READY(acm)) |
673 | return; | 667 | return; |
674 | if (acm_send_break(acm, state ? 0xffff : 0)) | 668 | if (acm_send_break(acm, state ? 0xffff : 0)) |
675 | dbg("send break failed"); | 669 | dbg("send break failed"); |
676 | } | 670 | } |
677 | 671 | ||
678 | static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file) | 672 | static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file) |
679 | { | 673 | { |
680 | struct acm *acm = tty->driver_data; | 674 | struct acm *acm = tty->driver_data; |
681 | 675 | ||
682 | if (!ACM_READY(acm)) | 676 | if (!ACM_READY(acm)) |
683 | return -EINVAL; | 677 | return -EINVAL; |
684 | 678 | ||
685 | return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) | | 679 | return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) | |
686 | (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) | | 680 | (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) | |
687 | (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) | | 681 | (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) | |
688 | (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) | | 682 | (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) | |
689 | (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) | | 683 | (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) | |
690 | TIOCM_CTS; | 684 | TIOCM_CTS; |
691 | } | 685 | } |
692 | 686 | ||
693 | static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file, | 687 | static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file, |
694 | unsigned int set, unsigned int clear) | 688 | unsigned int set, unsigned int clear) |
695 | { | 689 | { |
696 | struct acm *acm = tty->driver_data; | 690 | struct acm *acm = tty->driver_data; |
697 | unsigned int newctrl; | 691 | unsigned int newctrl; |
698 | 692 | ||
699 | if (!ACM_READY(acm)) | 693 | if (!ACM_READY(acm)) |
700 | return -EINVAL; | 694 | return -EINVAL; |
701 | 695 | ||
702 | newctrl = acm->ctrlout; | 696 | newctrl = acm->ctrlout; |
703 | set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); | 697 | set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); |
704 | clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0); | 698 | clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0); |
705 | 699 | ||
706 | newctrl = (newctrl & ~clear) | set; | 700 | newctrl = (newctrl & ~clear) | set; |
707 | 701 | ||
708 | if (acm->ctrlout == newctrl) | 702 | if (acm->ctrlout == newctrl) |
709 | return 0; | 703 | return 0; |
710 | return acm_set_control(acm, acm->ctrlout = newctrl); | 704 | return acm_set_control(acm, acm->ctrlout = newctrl); |
711 | } | 705 | } |
712 | 706 | ||
713 | static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) | 707 | static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) |
714 | { | 708 | { |
715 | struct acm *acm = tty->driver_data; | 709 | struct acm *acm = tty->driver_data; |
716 | 710 | ||
717 | if (!ACM_READY(acm)) | 711 | if (!ACM_READY(acm)) |
718 | return -EINVAL; | 712 | return -EINVAL; |
719 | 713 | ||
720 | return -ENOIOCTLCMD; | 714 | return -ENOIOCTLCMD; |
721 | } | 715 | } |
722 | 716 | ||
723 | static const __u32 acm_tty_speed[] = { | 717 | static const __u32 acm_tty_speed[] = { |
724 | 0, 50, 75, 110, 134, 150, 200, 300, 600, | 718 | 0, 50, 75, 110, 134, 150, 200, 300, 600, |
725 | 1200, 1800, 2400, 4800, 9600, 19200, 38400, | 719 | 1200, 1800, 2400, 4800, 9600, 19200, 38400, |
726 | 57600, 115200, 230400, 460800, 500000, 576000, | 720 | 57600, 115200, 230400, 460800, 500000, 576000, |
727 | 921600, 1000000, 1152000, 1500000, 2000000, | 721 | 921600, 1000000, 1152000, 1500000, 2000000, |
728 | 2500000, 3000000, 3500000, 4000000 | 722 | 2500000, 3000000, 3500000, 4000000 |
729 | }; | 723 | }; |
730 | 724 | ||
731 | static const __u8 acm_tty_size[] = { | 725 | static const __u8 acm_tty_size[] = { |
732 | 5, 6, 7, 8 | 726 | 5, 6, 7, 8 |
733 | }; | 727 | }; |
734 | 728 | ||
735 | static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old) | 729 | static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old) |
736 | { | 730 | { |
737 | struct acm *acm = tty->driver_data; | 731 | struct acm *acm = tty->driver_data; |
738 | struct ktermios *termios = tty->termios; | 732 | struct ktermios *termios = tty->termios; |
739 | struct usb_cdc_line_coding newline; | 733 | struct usb_cdc_line_coding newline; |
740 | int newctrl = acm->ctrlout; | 734 | int newctrl = acm->ctrlout; |
741 | 735 | ||
742 | if (!ACM_READY(acm)) | 736 | if (!ACM_READY(acm)) |
743 | return; | 737 | return; |
744 | 738 | ||
745 | newline.dwDTERate = cpu_to_le32p(acm_tty_speed + | 739 | newline.dwDTERate = cpu_to_le32p(acm_tty_speed + |
746 | (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0)); | 740 | (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0)); |
747 | newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; | 741 | newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; |
748 | newline.bParityType = termios->c_cflag & PARENB ? | 742 | newline.bParityType = termios->c_cflag & PARENB ? |
749 | (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0; | 743 | (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0; |
750 | newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4]; | 744 | newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4]; |
751 | 745 | ||
752 | acm->clocal = ((termios->c_cflag & CLOCAL) != 0); | 746 | acm->clocal = ((termios->c_cflag & CLOCAL) != 0); |
753 | 747 | ||
754 | if (!newline.dwDTERate) { | 748 | if (!newline.dwDTERate) { |
755 | newline.dwDTERate = acm->line.dwDTERate; | 749 | newline.dwDTERate = acm->line.dwDTERate; |
756 | newctrl &= ~ACM_CTRL_DTR; | 750 | newctrl &= ~ACM_CTRL_DTR; |
757 | } else newctrl |= ACM_CTRL_DTR; | 751 | } else newctrl |= ACM_CTRL_DTR; |
758 | 752 | ||
759 | if (newctrl != acm->ctrlout) | 753 | if (newctrl != acm->ctrlout) |
760 | acm_set_control(acm, acm->ctrlout = newctrl); | 754 | acm_set_control(acm, acm->ctrlout = newctrl); |
761 | 755 | ||
762 | if (memcmp(&acm->line, &newline, sizeof newline)) { | 756 | if (memcmp(&acm->line, &newline, sizeof newline)) { |
763 | memcpy(&acm->line, &newline, sizeof newline); | 757 | memcpy(&acm->line, &newline, sizeof newline); |
764 | dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate), | 758 | dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate), |
765 | newline.bCharFormat, newline.bParityType, | 759 | newline.bCharFormat, newline.bParityType, |
766 | newline.bDataBits); | 760 | newline.bDataBits); |
767 | acm_set_line(acm, &acm->line); | 761 | acm_set_line(acm, &acm->line); |
768 | } | 762 | } |
769 | } | 763 | } |
770 | 764 | ||
771 | /* | 765 | /* |
772 | * USB probe and disconnect routines. | 766 | * USB probe and disconnect routines. |
773 | */ | 767 | */ |
774 | 768 | ||
775 | /* Little helper: write buffers free */ | 769 | /* Little helper: write buffers free */ |
776 | static void acm_write_buffers_free(struct acm *acm) | 770 | static void acm_write_buffers_free(struct acm *acm) |
777 | { | 771 | { |
778 | int i; | 772 | int i; |
779 | struct acm_wb *wb; | 773 | struct acm_wb *wb; |
780 | 774 | ||
781 | for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) { | 775 | for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) { |
782 | usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah); | 776 | usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah); |
783 | } | 777 | } |
784 | } | 778 | } |
785 | 779 | ||
786 | /* Little helper: write buffers allocate */ | 780 | /* Little helper: write buffers allocate */ |
787 | static int acm_write_buffers_alloc(struct acm *acm) | 781 | static int acm_write_buffers_alloc(struct acm *acm) |
788 | { | 782 | { |
789 | int i; | 783 | int i; |
790 | struct acm_wb *wb; | 784 | struct acm_wb *wb; |
791 | 785 | ||
792 | for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) { | 786 | for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) { |
793 | wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL, | 787 | wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL, |
794 | &wb->dmah); | 788 | &wb->dmah); |
795 | if (!wb->buf) { | 789 | if (!wb->buf) { |
796 | while (i != 0) { | 790 | while (i != 0) { |
797 | --i; | 791 | --i; |
798 | --wb; | 792 | --wb; |
799 | usb_buffer_free(acm->dev, acm->writesize, | 793 | usb_buffer_free(acm->dev, acm->writesize, |
800 | wb->buf, wb->dmah); | 794 | wb->buf, wb->dmah); |
801 | } | 795 | } |
802 | return -ENOMEM; | 796 | return -ENOMEM; |
803 | } | 797 | } |
804 | } | 798 | } |
805 | return 0; | 799 | return 0; |
806 | } | 800 | } |
807 | 801 | ||
808 | static int acm_probe (struct usb_interface *intf, | 802 | static int acm_probe (struct usb_interface *intf, |
809 | const struct usb_device_id *id) | 803 | const struct usb_device_id *id) |
810 | { | 804 | { |
811 | struct usb_cdc_union_desc *union_header = NULL; | 805 | struct usb_cdc_union_desc *union_header = NULL; |
812 | struct usb_cdc_country_functional_desc *cfd = NULL; | 806 | struct usb_cdc_country_functional_desc *cfd = NULL; |
813 | char *buffer = intf->altsetting->extra; | 807 | char *buffer = intf->altsetting->extra; |
814 | int buflen = intf->altsetting->extralen; | 808 | int buflen = intf->altsetting->extralen; |
815 | struct usb_interface *control_interface; | 809 | struct usb_interface *control_interface; |
816 | struct usb_interface *data_interface; | 810 | struct usb_interface *data_interface; |
817 | struct usb_endpoint_descriptor *epctrl; | 811 | struct usb_endpoint_descriptor *epctrl; |
818 | struct usb_endpoint_descriptor *epread; | 812 | struct usb_endpoint_descriptor *epread; |
819 | struct usb_endpoint_descriptor *epwrite; | 813 | struct usb_endpoint_descriptor *epwrite; |
820 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 814 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
821 | struct acm *acm; | 815 | struct acm *acm; |
822 | int minor; | 816 | int minor; |
823 | int ctrlsize,readsize; | 817 | int ctrlsize,readsize; |
824 | u8 *buf; | 818 | u8 *buf; |
825 | u8 ac_management_function = 0; | 819 | u8 ac_management_function = 0; |
826 | u8 call_management_function = 0; | 820 | u8 call_management_function = 0; |
827 | int call_interface_num = -1; | 821 | int call_interface_num = -1; |
828 | int data_interface_num; | 822 | int data_interface_num; |
829 | unsigned long quirks; | 823 | unsigned long quirks; |
830 | int num_rx_buf; | 824 | int num_rx_buf; |
831 | int i; | 825 | int i; |
832 | 826 | ||
833 | /* normal quirks */ | 827 | /* normal quirks */ |
834 | quirks = (unsigned long)id->driver_info; | 828 | quirks = (unsigned long)id->driver_info; |
835 | num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; | 829 | num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; |
836 | 830 | ||
837 | /* handle quirks deadly to normal probing*/ | 831 | /* handle quirks deadly to normal probing*/ |
838 | if (quirks == NO_UNION_NORMAL) { | 832 | if (quirks == NO_UNION_NORMAL) { |
839 | data_interface = usb_ifnum_to_if(usb_dev, 1); | 833 | data_interface = usb_ifnum_to_if(usb_dev, 1); |
840 | control_interface = usb_ifnum_to_if(usb_dev, 0); | 834 | control_interface = usb_ifnum_to_if(usb_dev, 0); |
841 | goto skip_normal_probe; | 835 | goto skip_normal_probe; |
842 | } | 836 | } |
843 | 837 | ||
844 | /* normal probing*/ | 838 | /* normal probing*/ |
845 | if (!buffer) { | 839 | if (!buffer) { |
846 | err("Weird descriptor references\n"); | 840 | err("Weird descriptor references\n"); |
847 | return -EINVAL; | 841 | return -EINVAL; |
848 | } | 842 | } |
849 | 843 | ||
850 | if (!buflen) { | 844 | if (!buflen) { |
851 | if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { | 845 | if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { |
852 | dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n"); | 846 | dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n"); |
853 | buflen = intf->cur_altsetting->endpoint->extralen; | 847 | buflen = intf->cur_altsetting->endpoint->extralen; |
854 | buffer = intf->cur_altsetting->endpoint->extra; | 848 | buffer = intf->cur_altsetting->endpoint->extra; |
855 | } else { | 849 | } else { |
856 | err("Zero length descriptor references\n"); | 850 | err("Zero length descriptor references\n"); |
857 | return -EINVAL; | 851 | return -EINVAL; |
858 | } | 852 | } |
859 | } | 853 | } |
860 | 854 | ||
861 | while (buflen > 0) { | 855 | while (buflen > 0) { |
862 | if (buffer [1] != USB_DT_CS_INTERFACE) { | 856 | if (buffer [1] != USB_DT_CS_INTERFACE) { |
863 | err("skipping garbage\n"); | 857 | err("skipping garbage\n"); |
864 | goto next_desc; | 858 | goto next_desc; |
865 | } | 859 | } |
866 | 860 | ||
867 | switch (buffer [2]) { | 861 | switch (buffer [2]) { |
868 | case USB_CDC_UNION_TYPE: /* we've found it */ | 862 | case USB_CDC_UNION_TYPE: /* we've found it */ |
869 | if (union_header) { | 863 | if (union_header) { |
870 | err("More than one union descriptor, skipping ..."); | 864 | err("More than one union descriptor, skipping ..."); |
871 | goto next_desc; | 865 | goto next_desc; |
872 | } | 866 | } |
873 | union_header = (struct usb_cdc_union_desc *) | 867 | union_header = (struct usb_cdc_union_desc *) |
874 | buffer; | 868 | buffer; |
875 | break; | 869 | break; |
876 | case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ | 870 | case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ |
877 | cfd = (struct usb_cdc_country_functional_desc *)buffer; | 871 | cfd = (struct usb_cdc_country_functional_desc *)buffer; |
878 | break; | 872 | break; |
879 | case USB_CDC_HEADER_TYPE: /* maybe check version */ | 873 | case USB_CDC_HEADER_TYPE: /* maybe check version */ |
880 | break; /* for now we ignore it */ | 874 | break; /* for now we ignore it */ |
881 | case USB_CDC_ACM_TYPE: | 875 | case USB_CDC_ACM_TYPE: |
882 | ac_management_function = buffer[3]; | 876 | ac_management_function = buffer[3]; |
883 | break; | 877 | break; |
884 | case USB_CDC_CALL_MANAGEMENT_TYPE: | 878 | case USB_CDC_CALL_MANAGEMENT_TYPE: |
885 | call_management_function = buffer[3]; | 879 | call_management_function = buffer[3]; |
886 | call_interface_num = buffer[4]; | 880 | call_interface_num = buffer[4]; |
887 | if ((call_management_function & 3) != 3) | 881 | if ((call_management_function & 3) != 3) |
888 | err("This device cannot do calls on its own. It is no modem."); | 882 | err("This device cannot do calls on its own. It is no modem."); |
889 | break; | 883 | break; |
890 | 884 | ||
891 | default: | 885 | default: |
892 | err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]); | 886 | err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]); |
893 | break; | 887 | break; |
894 | } | 888 | } |
895 | next_desc: | 889 | next_desc: |
896 | buflen -= buffer[0]; | 890 | buflen -= buffer[0]; |
897 | buffer += buffer[0]; | 891 | buffer += buffer[0]; |
898 | } | 892 | } |
899 | 893 | ||
900 | if (!union_header) { | 894 | if (!union_header) { |
901 | if (call_interface_num > 0) { | 895 | if (call_interface_num > 0) { |
902 | dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n"); | 896 | dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n"); |
903 | data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); | 897 | data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); |
904 | control_interface = intf; | 898 | control_interface = intf; |
905 | } else { | 899 | } else { |
906 | dev_dbg(&intf->dev,"No union descriptor, giving up\n"); | 900 | dev_dbg(&intf->dev,"No union descriptor, giving up\n"); |
907 | return -ENODEV; | 901 | return -ENODEV; |
908 | } | 902 | } |
909 | } else { | 903 | } else { |
910 | control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); | 904 | control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); |
911 | data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); | 905 | data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); |
912 | if (!control_interface || !data_interface) { | 906 | if (!control_interface || !data_interface) { |
913 | dev_dbg(&intf->dev,"no interfaces\n"); | 907 | dev_dbg(&intf->dev,"no interfaces\n"); |
914 | return -ENODEV; | 908 | return -ENODEV; |
915 | } | 909 | } |
916 | } | 910 | } |
917 | 911 | ||
918 | if (data_interface_num != call_interface_num) | 912 | if (data_interface_num != call_interface_num) |
919 | dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n"); | 913 | dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n"); |
920 | 914 | ||
921 | skip_normal_probe: | 915 | skip_normal_probe: |
922 | 916 | ||
923 | /*workaround for switched interfaces */ | 917 | /*workaround for switched interfaces */ |
924 | if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) { | 918 | if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) { |
925 | if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) { | 919 | if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) { |
926 | struct usb_interface *t; | 920 | struct usb_interface *t; |
927 | dev_dbg(&intf->dev,"Your device has switched interfaces.\n"); | 921 | dev_dbg(&intf->dev,"Your device has switched interfaces.\n"); |
928 | 922 | ||
929 | t = control_interface; | 923 | t = control_interface; |
930 | control_interface = data_interface; | 924 | control_interface = data_interface; |
931 | data_interface = t; | 925 | data_interface = t; |
932 | } else { | 926 | } else { |
933 | return -EINVAL; | 927 | return -EINVAL; |
934 | } | 928 | } |
935 | } | 929 | } |
936 | 930 | ||
937 | /* Accept probe requests only for the control interface */ | 931 | /* Accept probe requests only for the control interface */ |
938 | if (intf != control_interface) | 932 | if (intf != control_interface) |
939 | return -ENODEV; | 933 | return -ENODEV; |
940 | 934 | ||
941 | if (usb_interface_claimed(data_interface)) { /* valid in this context */ | 935 | if (usb_interface_claimed(data_interface)) { /* valid in this context */ |
942 | dev_dbg(&intf->dev,"The data interface isn't available\n"); | 936 | dev_dbg(&intf->dev,"The data interface isn't available\n"); |
943 | return -EBUSY; | 937 | return -EBUSY; |
944 | } | 938 | } |
945 | 939 | ||
946 | 940 | ||
947 | if (data_interface->cur_altsetting->desc.bNumEndpoints < 2) | 941 | if (data_interface->cur_altsetting->desc.bNumEndpoints < 2) |
948 | return -EINVAL; | 942 | return -EINVAL; |
949 | 943 | ||
950 | epctrl = &control_interface->cur_altsetting->endpoint[0].desc; | 944 | epctrl = &control_interface->cur_altsetting->endpoint[0].desc; |
951 | epread = &data_interface->cur_altsetting->endpoint[0].desc; | 945 | epread = &data_interface->cur_altsetting->endpoint[0].desc; |
952 | epwrite = &data_interface->cur_altsetting->endpoint[1].desc; | 946 | epwrite = &data_interface->cur_altsetting->endpoint[1].desc; |
953 | 947 | ||
954 | 948 | ||
955 | /* workaround for switched endpoints */ | 949 | /* workaround for switched endpoints */ |
956 | if (!usb_endpoint_dir_in(epread)) { | 950 | if (!usb_endpoint_dir_in(epread)) { |
957 | /* descriptors are swapped */ | 951 | /* descriptors are swapped */ |
958 | struct usb_endpoint_descriptor *t; | 952 | struct usb_endpoint_descriptor *t; |
959 | dev_dbg(&intf->dev,"The data interface has switched endpoints\n"); | 953 | dev_dbg(&intf->dev,"The data interface has switched endpoints\n"); |
960 | 954 | ||
961 | t = epread; | 955 | t = epread; |
962 | epread = epwrite; | 956 | epread = epwrite; |
963 | epwrite = t; | 957 | epwrite = t; |
964 | } | 958 | } |
965 | dbg("interfaces are valid"); | 959 | dbg("interfaces are valid"); |
966 | for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); | 960 | for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); |
967 | 961 | ||
968 | if (minor == ACM_TTY_MINORS) { | 962 | if (minor == ACM_TTY_MINORS) { |
969 | err("no more free acm devices"); | 963 | err("no more free acm devices"); |
970 | return -ENODEV; | 964 | return -ENODEV; |
971 | } | 965 | } |
972 | 966 | ||
973 | if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) { | 967 | if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) { |
974 | dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n"); | 968 | dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n"); |
975 | goto alloc_fail; | 969 | goto alloc_fail; |
976 | } | 970 | } |
977 | 971 | ||
978 | ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); | 972 | ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); |
979 | readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2); | 973 | readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2); |
980 | acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize); | 974 | acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20; |
981 | acm->control = control_interface; | 975 | acm->control = control_interface; |
982 | acm->data = data_interface; | 976 | acm->data = data_interface; |
983 | acm->minor = minor; | 977 | acm->minor = minor; |
984 | acm->dev = usb_dev; | 978 | acm->dev = usb_dev; |
985 | acm->ctrl_caps = ac_management_function; | 979 | acm->ctrl_caps = ac_management_function; |
986 | acm->ctrlsize = ctrlsize; | 980 | acm->ctrlsize = ctrlsize; |
987 | acm->readsize = readsize; | 981 | acm->readsize = readsize; |
988 | acm->rx_buflimit = num_rx_buf; | 982 | acm->rx_buflimit = num_rx_buf; |
989 | acm->urb_task.func = acm_rx_tasklet; | 983 | acm->urb_task.func = acm_rx_tasklet; |
990 | acm->urb_task.data = (unsigned long) acm; | 984 | acm->urb_task.data = (unsigned long) acm; |
991 | INIT_WORK(&acm->work, acm_softint); | 985 | INIT_WORK(&acm->work, acm_softint); |
992 | spin_lock_init(&acm->throttle_lock); | 986 | spin_lock_init(&acm->throttle_lock); |
993 | spin_lock_init(&acm->write_lock); | 987 | spin_lock_init(&acm->write_lock); |
994 | spin_lock_init(&acm->read_lock); | 988 | spin_lock_init(&acm->read_lock); |
995 | mutex_init(&acm->mutex); | 989 | mutex_init(&acm->mutex); |
996 | acm->write_ready = 1; | 990 | acm->write_ready = 1; |
997 | acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); | 991 | acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); |
998 | 992 | ||
999 | buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); | 993 | buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); |
1000 | if (!buf) { | 994 | if (!buf) { |
1001 | dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n"); | 995 | dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n"); |
1002 | goto alloc_fail2; | 996 | goto alloc_fail2; |
1003 | } | 997 | } |
1004 | acm->ctrl_buffer = buf; | 998 | acm->ctrl_buffer = buf; |
1005 | 999 | ||
1006 | if (acm_write_buffers_alloc(acm) < 0) { | 1000 | if (acm_write_buffers_alloc(acm) < 0) { |
1007 | dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n"); | 1001 | dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n"); |
1008 | goto alloc_fail4; | 1002 | goto alloc_fail4; |
1009 | } | 1003 | } |
1010 | 1004 | ||
1011 | acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); | 1005 | acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); |
1012 | if (!acm->ctrlurb) { | 1006 | if (!acm->ctrlurb) { |
1013 | dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); | 1007 | dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); |
1014 | goto alloc_fail5; | 1008 | goto alloc_fail5; |
1015 | } | 1009 | } |
1016 | for (i = 0; i < num_rx_buf; i++) { | 1010 | for (i = 0; i < num_rx_buf; i++) { |
1017 | struct acm_ru *rcv = &(acm->ru[i]); | 1011 | struct acm_ru *rcv = &(acm->ru[i]); |
1018 | 1012 | ||
1019 | if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { | 1013 | if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { |
1020 | dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); | 1014 | dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); |
1021 | goto alloc_fail7; | 1015 | goto alloc_fail7; |
1022 | } | 1016 | } |
1023 | 1017 | ||
1024 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 1018 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
1025 | rcv->instance = acm; | 1019 | rcv->instance = acm; |
1026 | } | 1020 | } |
1027 | for (i = 0; i < num_rx_buf; i++) { | 1021 | for (i = 0; i < num_rx_buf; i++) { |
1028 | struct acm_rb *buf = &(acm->rb[i]); | 1022 | struct acm_rb *buf = &(acm->rb[i]); |
1029 | 1023 | ||
1030 | if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) { | 1024 | if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) { |
1031 | dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n"); | 1025 | dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n"); |
1032 | goto alloc_fail7; | 1026 | goto alloc_fail7; |
1033 | } | 1027 | } |
1034 | } | 1028 | } |
1035 | acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); | 1029 | for(i = 0; i < ACM_NW; i++) |
1036 | if (!acm->writeurb) { | 1030 | { |
1037 | dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n"); | 1031 | struct acm_wb *snd = &(acm->wb[i]); |
1038 | goto alloc_fail7; | 1032 | |
1033 | if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) { | ||
1034 | dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)"); | ||
1035 | goto alloc_fail7; | ||
1036 | } | ||
1037 | |||
1038 | usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), | ||
1039 | NULL, acm->writesize, acm_write_bulk, snd); | ||
1040 | snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
1041 | snd->instance = acm; | ||
1039 | } | 1042 | } |
1040 | 1043 | ||
1041 | usb_set_intfdata (intf, acm); | 1044 | usb_set_intfdata (intf, acm); |
1042 | 1045 | ||
1043 | i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); | 1046 | i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); |
1044 | if (i < 0) | 1047 | if (i < 0) |
1045 | goto alloc_fail8; | 1048 | goto alloc_fail8; |
1046 | 1049 | ||
1047 | if (cfd) { /* export the country data */ | 1050 | if (cfd) { /* export the country data */ |
1048 | acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); | 1051 | acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); |
1049 | if (!acm->country_codes) | 1052 | if (!acm->country_codes) |
1050 | goto skip_countries; | 1053 | goto skip_countries; |
1051 | acm->country_code_size = cfd->bLength - 4; | 1054 | acm->country_code_size = cfd->bLength - 4; |
1052 | memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4); | 1055 | memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4); |
1053 | acm->country_rel_date = cfd->iCountryCodeRelDate; | 1056 | acm->country_rel_date = cfd->iCountryCodeRelDate; |
1054 | 1057 | ||
1055 | i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); | 1058 | i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); |
1056 | if (i < 0) { | 1059 | if (i < 0) { |
1057 | kfree(acm->country_codes); | 1060 | kfree(acm->country_codes); |
1058 | goto skip_countries; | 1061 | goto skip_countries; |
1059 | } | 1062 | } |
1060 | 1063 | ||
1061 | i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); | 1064 | i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); |
1062 | if (i < 0) { | 1065 | if (i < 0) { |
1063 | kfree(acm->country_codes); | 1066 | kfree(acm->country_codes); |
1064 | goto skip_countries; | 1067 | goto skip_countries; |
1065 | } | 1068 | } |
1066 | } | 1069 | } |
1067 | 1070 | ||
1068 | skip_countries: | 1071 | skip_countries: |
1069 | usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), | 1072 | usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), |
1070 | acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); | 1073 | acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); |
1071 | acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 1074 | acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
1072 | acm->ctrlurb->transfer_dma = acm->ctrl_dma; | 1075 | acm->ctrlurb->transfer_dma = acm->ctrl_dma; |
1073 | 1076 | ||
1074 | usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), | ||
1075 | NULL, acm->writesize, acm_write_bulk, acm); | ||
1076 | acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP; | ||
1077 | |||
1078 | dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); | 1077 | dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); |
1079 | 1078 | ||
1080 | acm_set_control(acm, acm->ctrlout); | 1079 | acm_set_control(acm, acm->ctrlout); |
1081 | 1080 | ||
1082 | acm->line.dwDTERate = cpu_to_le32(9600); | 1081 | acm->line.dwDTERate = cpu_to_le32(9600); |
1083 | acm->line.bDataBits = 8; | 1082 | acm->line.bDataBits = 8; |
1084 | acm_set_line(acm, &acm->line); | 1083 | acm_set_line(acm, &acm->line); |
1085 | 1084 | ||
1086 | usb_driver_claim_interface(&acm_driver, data_interface, acm); | 1085 | usb_driver_claim_interface(&acm_driver, data_interface, acm); |
1087 | 1086 | ||
1088 | usb_get_intf(control_interface); | 1087 | usb_get_intf(control_interface); |
1089 | tty_register_device(acm_tty_driver, minor, &control_interface->dev); | 1088 | tty_register_device(acm_tty_driver, minor, &control_interface->dev); |
1090 | 1089 | ||
1091 | acm_table[minor] = acm; | 1090 | acm_table[minor] = acm; |
1092 | 1091 | ||
1093 | return 0; | 1092 | return 0; |
1094 | alloc_fail8: | 1093 | alloc_fail8: |
1095 | usb_free_urb(acm->writeurb); | 1094 | for (i = 0; i < ACM_NW; i++) |
1095 | usb_free_urb(acm->wb[i].urb); | ||
1096 | alloc_fail7: | 1096 | alloc_fail7: |
1097 | for (i = 0; i < num_rx_buf; i++) | 1097 | for (i = 0; i < num_rx_buf; i++) |
1098 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | 1098 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); |
1099 | for (i = 0; i < num_rx_buf; i++) | 1099 | for (i = 0; i < num_rx_buf; i++) |
1100 | usb_free_urb(acm->ru[i].urb); | 1100 | usb_free_urb(acm->ru[i].urb); |
1101 | usb_free_urb(acm->ctrlurb); | 1101 | usb_free_urb(acm->ctrlurb); |
1102 | alloc_fail5: | 1102 | alloc_fail5: |
1103 | acm_write_buffers_free(acm); | 1103 | acm_write_buffers_free(acm); |
1104 | alloc_fail4: | 1104 | alloc_fail4: |
1105 | usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); | 1105 | usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
1106 | alloc_fail2: | 1106 | alloc_fail2: |
1107 | kfree(acm); | 1107 | kfree(acm); |
1108 | alloc_fail: | 1108 | alloc_fail: |
1109 | return -ENOMEM; | 1109 | return -ENOMEM; |
1110 | } | 1110 | } |
1111 | 1111 | ||
1112 | static void stop_data_traffic(struct acm *acm) | 1112 | static void stop_data_traffic(struct acm *acm) |
1113 | { | 1113 | { |
1114 | int i; | 1114 | int i; |
1115 | 1115 | ||
1116 | tasklet_disable(&acm->urb_task); | 1116 | tasklet_disable(&acm->urb_task); |
1117 | 1117 | ||
1118 | usb_kill_urb(acm->ctrlurb); | 1118 | usb_kill_urb(acm->ctrlurb); |
1119 | usb_kill_urb(acm->writeurb); | 1119 | for(i = 0; i < ACM_NW; i++) |
1120 | usb_kill_urb(acm->wb[i].urb); | ||
1120 | for (i = 0; i < acm->rx_buflimit; i++) | 1121 | for (i = 0; i < acm->rx_buflimit; i++) |
1121 | usb_kill_urb(acm->ru[i].urb); | 1122 | usb_kill_urb(acm->ru[i].urb); |
1122 | 1123 | ||
1123 | INIT_LIST_HEAD(&acm->filled_read_bufs); | 1124 | INIT_LIST_HEAD(&acm->filled_read_bufs); |
1124 | INIT_LIST_HEAD(&acm->spare_read_bufs); | 1125 | INIT_LIST_HEAD(&acm->spare_read_bufs); |
1125 | 1126 | ||
1126 | tasklet_enable(&acm->urb_task); | 1127 | tasklet_enable(&acm->urb_task); |
1127 | 1128 | ||
1128 | cancel_work_sync(&acm->work); | 1129 | cancel_work_sync(&acm->work); |
1129 | } | 1130 | } |
1130 | 1131 | ||
1131 | static void acm_disconnect(struct usb_interface *intf) | 1132 | static void acm_disconnect(struct usb_interface *intf) |
1132 | { | 1133 | { |
1133 | struct acm *acm = usb_get_intfdata(intf); | 1134 | struct acm *acm = usb_get_intfdata(intf); |
1134 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 1135 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
1135 | int i; | 1136 | int i; |
1136 | 1137 | ||
1137 | if (!acm || !acm->dev) { | 1138 | if (!acm || !acm->dev) { |
1138 | dbg("disconnect on nonexisting interface"); | 1139 | dbg("disconnect on nonexisting interface"); |
1139 | return; | 1140 | return; |
1140 | } | 1141 | } |
1141 | 1142 | ||
1142 | mutex_lock(&open_mutex); | 1143 | mutex_lock(&open_mutex); |
1143 | if (!usb_get_intfdata(intf)) { | 1144 | if (!usb_get_intfdata(intf)) { |
1144 | mutex_unlock(&open_mutex); | 1145 | mutex_unlock(&open_mutex); |
1145 | return; | 1146 | return; |
1146 | } | 1147 | } |
1147 | if (acm->country_codes){ | 1148 | if (acm->country_codes){ |
1148 | device_remove_file(&acm->control->dev, | 1149 | device_remove_file(&acm->control->dev, |
1149 | &dev_attr_wCountryCodes); | 1150 | &dev_attr_wCountryCodes); |
1150 | device_remove_file(&acm->control->dev, | 1151 | device_remove_file(&acm->control->dev, |
1151 | &dev_attr_iCountryCodeRelDate); | 1152 | &dev_attr_iCountryCodeRelDate); |
1152 | } | 1153 | } |
1153 | device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); | 1154 | device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); |
1154 | acm->dev = NULL; | 1155 | acm->dev = NULL; |
1155 | usb_set_intfdata(acm->control, NULL); | 1156 | usb_set_intfdata(acm->control, NULL); |
1156 | usb_set_intfdata(acm->data, NULL); | 1157 | usb_set_intfdata(acm->data, NULL); |
1157 | 1158 | ||
1158 | stop_data_traffic(acm); | 1159 | stop_data_traffic(acm); |
1159 | 1160 | ||
1160 | acm_write_buffers_free(acm); | 1161 | acm_write_buffers_free(acm); |
1161 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); | 1162 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
1162 | for (i = 0; i < acm->rx_buflimit; i++) | 1163 | for (i = 0; i < acm->rx_buflimit; i++) |
1163 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | 1164 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); |
1164 | 1165 | ||
1165 | usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf); | 1166 | usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf); |
1166 | 1167 | ||
1167 | if (!acm->used) { | 1168 | if (!acm->used) { |
1168 | acm_tty_unregister(acm); | 1169 | acm_tty_unregister(acm); |
1169 | mutex_unlock(&open_mutex); | 1170 | mutex_unlock(&open_mutex); |
1170 | return; | 1171 | return; |
1171 | } | 1172 | } |
1172 | 1173 | ||
1173 | mutex_unlock(&open_mutex); | 1174 | mutex_unlock(&open_mutex); |
1174 | 1175 | ||
1175 | if (acm->tty) | 1176 | if (acm->tty) |
1176 | tty_hangup(acm->tty); | 1177 | tty_hangup(acm->tty); |
1177 | } | 1178 | } |
1178 | 1179 | ||
1179 | static int acm_suspend(struct usb_interface *intf, pm_message_t message) | 1180 | static int acm_suspend(struct usb_interface *intf, pm_message_t message) |
1180 | { | 1181 | { |
1181 | struct acm *acm = usb_get_intfdata(intf); | 1182 | struct acm *acm = usb_get_intfdata(intf); |
1182 | 1183 | ||
1183 | if (acm->susp_count++) | 1184 | if (acm->susp_count++) |
1184 | return 0; | 1185 | return 0; |
1185 | /* | 1186 | /* |
1186 | we treat opened interfaces differently, | 1187 | we treat opened interfaces differently, |
1187 | we must guard against open | 1188 | we must guard against open |
1188 | */ | 1189 | */ |
1189 | mutex_lock(&acm->mutex); | 1190 | mutex_lock(&acm->mutex); |
1190 | 1191 | ||
1191 | if (acm->used) | 1192 | if (acm->used) |
1192 | stop_data_traffic(acm); | 1193 | stop_data_traffic(acm); |
1193 | 1194 | ||
1194 | mutex_unlock(&acm->mutex); | 1195 | mutex_unlock(&acm->mutex); |
1195 | return 0; | 1196 | return 0; |
1196 | } | 1197 | } |
1197 | 1198 | ||
1198 | static int acm_resume(struct usb_interface *intf) | 1199 | static int acm_resume(struct usb_interface *intf) |
1199 | { | 1200 | { |
1200 | struct acm *acm = usb_get_intfdata(intf); | 1201 | struct acm *acm = usb_get_intfdata(intf); |
1201 | int rv = 0; | 1202 | int rv = 0; |
1202 | 1203 | ||
1203 | if (--acm->susp_count) | 1204 | if (--acm->susp_count) |
1204 | return 0; | 1205 | return 0; |
1205 | 1206 | ||
1206 | mutex_lock(&acm->mutex); | 1207 | mutex_lock(&acm->mutex); |
1207 | if (acm->used) { | 1208 | if (acm->used) { |
1208 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); | 1209 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); |
1209 | if (rv < 0) | 1210 | if (rv < 0) |
1210 | goto err_out; | 1211 | goto err_out; |
1211 | 1212 | ||
1212 | tasklet_schedule(&acm->urb_task); | 1213 | tasklet_schedule(&acm->urb_task); |
1213 | } | 1214 | } |
1214 | 1215 | ||
1215 | err_out: | 1216 | err_out: |
1216 | mutex_unlock(&acm->mutex); | 1217 | mutex_unlock(&acm->mutex); |
1217 | return rv; | 1218 | return rv; |
1218 | } | 1219 | } |
1219 | /* | 1220 | /* |
1220 | * USB driver structure. | 1221 | * USB driver structure. |
1221 | */ | 1222 | */ |
1222 | 1223 | ||
1223 | static struct usb_device_id acm_ids[] = { | 1224 | static struct usb_device_id acm_ids[] = { |
1224 | /* quirky and broken devices */ | 1225 | /* quirky and broken devices */ |
1225 | { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ | 1226 | { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ |
1226 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ | 1227 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ |
1227 | }, | 1228 | }, |
1228 | { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */ | 1229 | { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */ |
1229 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ | 1230 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ |
1230 | }, | 1231 | }, |
1231 | { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */ | 1232 | { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */ |
1232 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ | 1233 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ |
1233 | }, | 1234 | }, |
1234 | { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */ | 1235 | { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */ |
1235 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ | 1236 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ |
1236 | }, | 1237 | }, |
1237 | { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */ | 1238 | { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */ |
1238 | .driver_info = SINGLE_RX_URB, /* firmware bug */ | 1239 | .driver_info = SINGLE_RX_URB, /* firmware bug */ |
1239 | }, | 1240 | }, |
1240 | { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */ | 1241 | { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */ |
1241 | .driver_info = SINGLE_RX_URB, /* firmware bug */ | 1242 | .driver_info = SINGLE_RX_URB, /* firmware bug */ |
1242 | }, | 1243 | }, |
1243 | { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */ | 1244 | { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */ |
1244 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ | 1245 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ |
1245 | }, | 1246 | }, |
1246 | 1247 | ||
1247 | /* control interfaces with various AT-command sets */ | 1248 | /* control interfaces with various AT-command sets */ |
1248 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1249 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1249 | USB_CDC_ACM_PROTO_AT_V25TER) }, | 1250 | USB_CDC_ACM_PROTO_AT_V25TER) }, |
1250 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1251 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1251 | USB_CDC_ACM_PROTO_AT_PCCA101) }, | 1252 | USB_CDC_ACM_PROTO_AT_PCCA101) }, |
1252 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1253 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1253 | USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) }, | 1254 | USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) }, |
1254 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1255 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1255 | USB_CDC_ACM_PROTO_AT_GSM) }, | 1256 | USB_CDC_ACM_PROTO_AT_GSM) }, |
1256 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1257 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1257 | USB_CDC_ACM_PROTO_AT_3G ) }, | 1258 | USB_CDC_ACM_PROTO_AT_3G ) }, |
1258 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1259 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1259 | USB_CDC_ACM_PROTO_AT_CDMA) }, | 1260 | USB_CDC_ACM_PROTO_AT_CDMA) }, |
1260 | 1261 | ||
1261 | /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */ | 1262 | /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */ |
1262 | { } | 1263 | { } |
1263 | }; | 1264 | }; |
1264 | 1265 | ||
1265 | MODULE_DEVICE_TABLE (usb, acm_ids); | 1266 | MODULE_DEVICE_TABLE (usb, acm_ids); |
1266 | 1267 | ||
1267 | static struct usb_driver acm_driver = { | 1268 | static struct usb_driver acm_driver = { |
1268 | .name = "cdc_acm", | 1269 | .name = "cdc_acm", |
1269 | .probe = acm_probe, | 1270 | .probe = acm_probe, |
1270 | .disconnect = acm_disconnect, | 1271 | .disconnect = acm_disconnect, |
1271 | .suspend = acm_suspend, | 1272 | .suspend = acm_suspend, |
1272 | .resume = acm_resume, | 1273 | .resume = acm_resume, |
1273 | .id_table = acm_ids, | 1274 | .id_table = acm_ids, |
1274 | .supports_autosuspend = 1, | 1275 | .supports_autosuspend = 1, |
1275 | }; | 1276 | }; |
1276 | 1277 | ||
1277 | /* | 1278 | /* |
1278 | * TTY driver structures. | 1279 | * TTY driver structures. |
1279 | */ | 1280 | */ |
1280 | 1281 | ||
1281 | static const struct tty_operations acm_ops = { | 1282 | static const struct tty_operations acm_ops = { |
1282 | .open = acm_tty_open, | 1283 | .open = acm_tty_open, |
1283 | .close = acm_tty_close, | 1284 | .close = acm_tty_close, |
1284 | .write = acm_tty_write, | 1285 | .write = acm_tty_write, |
1285 | .write_room = acm_tty_write_room, | 1286 | .write_room = acm_tty_write_room, |
1286 | .ioctl = acm_tty_ioctl, | 1287 | .ioctl = acm_tty_ioctl, |
1287 | .throttle = acm_tty_throttle, | 1288 | .throttle = acm_tty_throttle, |
1288 | .unthrottle = acm_tty_unthrottle, | 1289 | .unthrottle = acm_tty_unthrottle, |
1289 | .chars_in_buffer = acm_tty_chars_in_buffer, | 1290 | .chars_in_buffer = acm_tty_chars_in_buffer, |
1290 | .break_ctl = acm_tty_break_ctl, | 1291 | .break_ctl = acm_tty_break_ctl, |
1291 | .set_termios = acm_tty_set_termios, | 1292 | .set_termios = acm_tty_set_termios, |
1292 | .tiocmget = acm_tty_tiocmget, | 1293 | .tiocmget = acm_tty_tiocmget, |
1293 | .tiocmset = acm_tty_tiocmset, | 1294 | .tiocmset = acm_tty_tiocmset, |
1294 | }; | 1295 | }; |
1295 | 1296 | ||
1296 | /* | 1297 | /* |
1297 | * Init / exit. | 1298 | * Init / exit. |
1298 | */ | 1299 | */ |
1299 | 1300 | ||
1300 | static int __init acm_init(void) | 1301 | static int __init acm_init(void) |
1301 | { | 1302 | { |
1302 | int retval; | 1303 | int retval; |
1303 | acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS); | 1304 | acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS); |
1304 | if (!acm_tty_driver) | 1305 | if (!acm_tty_driver) |
1305 | return -ENOMEM; | 1306 | return -ENOMEM; |
1306 | acm_tty_driver->owner = THIS_MODULE, | 1307 | acm_tty_driver->owner = THIS_MODULE, |
1307 | acm_tty_driver->driver_name = "acm", | 1308 | acm_tty_driver->driver_name = "acm", |
1308 | acm_tty_driver->name = "ttyACM", | 1309 | acm_tty_driver->name = "ttyACM", |
1309 | acm_tty_driver->major = ACM_TTY_MAJOR, | 1310 | acm_tty_driver->major = ACM_TTY_MAJOR, |
1310 | acm_tty_driver->minor_start = 0, | 1311 | acm_tty_driver->minor_start = 0, |
1311 | acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL, | 1312 | acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL, |
1312 | acm_tty_driver->subtype = SERIAL_TYPE_NORMAL, | 1313 | acm_tty_driver->subtype = SERIAL_TYPE_NORMAL, |
1313 | acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | 1314 | acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; |
1314 | acm_tty_driver->init_termios = tty_std_termios; | 1315 | acm_tty_driver->init_termios = tty_std_termios; |
1315 | acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; | 1316 | acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; |
1316 | tty_set_operations(acm_tty_driver, &acm_ops); | 1317 | tty_set_operations(acm_tty_driver, &acm_ops); |
1317 | 1318 | ||
1318 | retval = tty_register_driver(acm_tty_driver); | 1319 | retval = tty_register_driver(acm_tty_driver); |
1319 | if (retval) { | 1320 | if (retval) { |
1320 | put_tty_driver(acm_tty_driver); | 1321 | put_tty_driver(acm_tty_driver); |
1321 | return retval; | 1322 | return retval; |
1322 | } | 1323 | } |
1323 | 1324 | ||
1324 | retval = usb_register(&acm_driver); | 1325 | retval = usb_register(&acm_driver); |
1325 | if (retval) { | 1326 | if (retval) { |
1326 | tty_unregister_driver(acm_tty_driver); | 1327 | tty_unregister_driver(acm_tty_driver); |
1327 | put_tty_driver(acm_tty_driver); | 1328 | put_tty_driver(acm_tty_driver); |
1328 | return retval; | 1329 | return retval; |
1329 | } | 1330 | } |
1330 | 1331 | ||
1331 | info(DRIVER_VERSION ":" DRIVER_DESC); | 1332 | info(DRIVER_VERSION ":" DRIVER_DESC); |
1332 | 1333 | ||
1333 | return 0; | 1334 | return 0; |
1334 | } | 1335 | } |
1335 | 1336 |
drivers/usb/class/cdc-acm.h
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * Includes for cdc-acm.c | 3 | * Includes for cdc-acm.c |
4 | * | 4 | * |
5 | * Mainly take from usbnet's cdc-ether part | 5 | * Mainly take from usbnet's cdc-ether part |
6 | * | 6 | * |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * CMSPAR, some architectures can't have space and mark parity. | 10 | * CMSPAR, some architectures can't have space and mark parity. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #ifndef CMSPAR | 13 | #ifndef CMSPAR |
14 | #define CMSPAR 0 | 14 | #define CMSPAR 0 |
15 | #endif | 15 | #endif |
16 | 16 | ||
17 | /* | 17 | /* |
18 | * Major and minor numbers. | 18 | * Major and minor numbers. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #define ACM_TTY_MAJOR 166 | 21 | #define ACM_TTY_MAJOR 166 |
22 | #define ACM_TTY_MINORS 32 | 22 | #define ACM_TTY_MINORS 32 |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * Requests. | 25 | * Requests. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE) | 28 | #define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE) |
29 | 29 | ||
30 | /* | 30 | /* |
31 | * Output control lines. | 31 | * Output control lines. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #define ACM_CTRL_DTR 0x01 | 34 | #define ACM_CTRL_DTR 0x01 |
35 | #define ACM_CTRL_RTS 0x02 | 35 | #define ACM_CTRL_RTS 0x02 |
36 | 36 | ||
37 | /* | 37 | /* |
38 | * Input control lines and line errors. | 38 | * Input control lines and line errors. |
39 | */ | 39 | */ |
40 | 40 | ||
41 | #define ACM_CTRL_DCD 0x01 | 41 | #define ACM_CTRL_DCD 0x01 |
42 | #define ACM_CTRL_DSR 0x02 | 42 | #define ACM_CTRL_DSR 0x02 |
43 | #define ACM_CTRL_BRK 0x04 | 43 | #define ACM_CTRL_BRK 0x04 |
44 | #define ACM_CTRL_RI 0x08 | 44 | #define ACM_CTRL_RI 0x08 |
45 | 45 | ||
46 | #define ACM_CTRL_FRAMING 0x10 | 46 | #define ACM_CTRL_FRAMING 0x10 |
47 | #define ACM_CTRL_PARITY 0x20 | 47 | #define ACM_CTRL_PARITY 0x20 |
48 | #define ACM_CTRL_OVERRUN 0x40 | 48 | #define ACM_CTRL_OVERRUN 0x40 |
49 | 49 | ||
50 | /* | 50 | /* |
51 | * Internal driver structures. | 51 | * Internal driver structures. |
52 | */ | 52 | */ |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * The only reason to have several buffers is to accomodate assumptions | 55 | * The only reason to have several buffers is to accomodate assumptions |
56 | * in line disciplines. They ask for empty space amount, receive our URB size, | 56 | * in line disciplines. They ask for empty space amount, receive our URB size, |
57 | * and proceed to issue several 1-character writes, assuming they will fit. | 57 | * and proceed to issue several 1-character writes, assuming they will fit. |
58 | * The very first write takes a complete URB. Fortunately, this only happens | 58 | * The very first write takes a complete URB. Fortunately, this only happens |
59 | * when processing onlcr, so we only need 2 buffers. These values must be | 59 | * when processing onlcr, so we only need 2 buffers. These values must be |
60 | * powers of 2. | 60 | * powers of 2. |
61 | */ | 61 | */ |
62 | #define ACM_NW 2 | 62 | #define ACM_NW 16 |
63 | #define ACM_NR 16 | 63 | #define ACM_NR 16 |
64 | 64 | ||
65 | struct acm_wb { | 65 | struct acm_wb { |
66 | unsigned char *buf; | 66 | unsigned char *buf; |
67 | dma_addr_t dmah; | 67 | dma_addr_t dmah; |
68 | int len; | 68 | int len; |
69 | int use; | 69 | int use; |
70 | struct urb *urb; | ||
71 | struct acm *instance; | ||
70 | }; | 72 | }; |
71 | 73 | ||
72 | struct acm_rb { | 74 | struct acm_rb { |
73 | struct list_head list; | 75 | struct list_head list; |
74 | int size; | 76 | int size; |
75 | unsigned char *base; | 77 | unsigned char *base; |
76 | dma_addr_t dma; | 78 | dma_addr_t dma; |
77 | }; | 79 | }; |
78 | 80 | ||
79 | struct acm_ru { | 81 | struct acm_ru { |
80 | struct list_head list; | 82 | struct list_head list; |
81 | struct acm_rb *buffer; | 83 | struct acm_rb *buffer; |
82 | struct urb *urb; | 84 | struct urb *urb; |
83 | struct acm *instance; | 85 | struct acm *instance; |
84 | }; | 86 | }; |
85 | 87 | ||
86 | struct acm { | 88 | struct acm { |
87 | struct usb_device *dev; /* the corresponding usb device */ | 89 | struct usb_device *dev; /* the corresponding usb device */ |
88 | struct usb_interface *control; /* control interface */ | 90 | struct usb_interface *control; /* control interface */ |
89 | struct usb_interface *data; /* data interface */ | 91 | struct usb_interface *data; /* data interface */ |
90 | struct tty_struct *tty; /* the corresponding tty */ | 92 | struct tty_struct *tty; /* the corresponding tty */ |
91 | struct urb *ctrlurb, *writeurb; /* urbs */ | 93 | struct urb *ctrlurb; /* urbs */ |
92 | u8 *ctrl_buffer; /* buffers of urbs */ | 94 | u8 *ctrl_buffer; /* buffers of urbs */ |
93 | dma_addr_t ctrl_dma; /* dma handles of buffers */ | 95 | dma_addr_t ctrl_dma; /* dma handles of buffers */ |
94 | u8 *country_codes; /* country codes from device */ | 96 | u8 *country_codes; /* country codes from device */ |
95 | unsigned int country_code_size; /* size of this buffer */ | 97 | unsigned int country_code_size; /* size of this buffer */ |
96 | unsigned int country_rel_date; /* release date of version */ | 98 | unsigned int country_rel_date; /* release date of version */ |
97 | struct acm_wb wb[ACM_NW]; | 99 | struct acm_wb wb[ACM_NW]; |
98 | struct acm_ru ru[ACM_NR]; | 100 | struct acm_ru ru[ACM_NR]; |
99 | struct acm_rb rb[ACM_NR]; | 101 | struct acm_rb rb[ACM_NR]; |
100 | int rx_buflimit; | 102 | int rx_buflimit; |
101 | int rx_endpoint; | 103 | int rx_endpoint; |
102 | spinlock_t read_lock; | 104 | spinlock_t read_lock; |
103 | struct list_head spare_read_urbs; | 105 | struct list_head spare_read_urbs; |
104 | struct list_head spare_read_bufs; | 106 | struct list_head spare_read_bufs; |
105 | struct list_head filled_read_bufs; | 107 | struct list_head filled_read_bufs; |
106 | int write_current; /* current write buffer */ | ||
107 | int write_used; /* number of non-empty write buffers */ | 108 | int write_used; /* number of non-empty write buffers */ |
108 | int write_ready; /* write urb is not running */ | 109 | int write_ready; /* write urb is not running */ |
109 | spinlock_t write_lock; | 110 | spinlock_t write_lock; |
110 | struct mutex mutex; | 111 | struct mutex mutex; |
111 | struct usb_cdc_line_coding line; /* bits, stop, parity */ | 112 | struct usb_cdc_line_coding line; /* bits, stop, parity */ |
112 | struct work_struct work; /* work queue entry for line discipline waking up */ | 113 | struct work_struct work; /* work queue entry for line discipline waking up */ |
113 | struct tasklet_struct urb_task; /* rx processing */ | 114 | struct tasklet_struct urb_task; /* rx processing */ |
114 | spinlock_t throttle_lock; /* synchronize throtteling and read callback */ | 115 | spinlock_t throttle_lock; /* synchronize throtteling and read callback */ |
115 | unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ | 116 | unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ |
116 | unsigned int ctrlout; /* output control lines (DTR, RTS) */ | 117 | unsigned int ctrlout; /* output control lines (DTR, RTS) */ |
117 | unsigned int writesize; /* max packet size for the output bulk endpoint */ | 118 | unsigned int writesize; /* max packet size for the output bulk endpoint */ |
118 | unsigned int readsize,ctrlsize; /* buffer sizes for freeing */ | 119 | unsigned int readsize,ctrlsize; /* buffer sizes for freeing */ |
119 | unsigned int used; /* someone has this acm's device open */ | 120 | unsigned int used; /* someone has this acm's device open */ |
120 | unsigned int minor; /* acm minor number */ | 121 | unsigned int minor; /* acm minor number */ |
121 | unsigned char throttle; /* throttled by tty layer */ | 122 | unsigned char throttle; /* throttled by tty layer */ |
122 | unsigned char clocal; /* termios CLOCAL */ | 123 | unsigned char clocal; /* termios CLOCAL */ |
123 | unsigned int ctrl_caps; /* control capabilities from the class specific header */ | 124 | unsigned int ctrl_caps; /* control capabilities from the class specific header */ |
124 | unsigned int susp_count; /* number of suspended interfaces */ | 125 | unsigned int susp_count; /* number of suspended interfaces */ |
125 | }; | 126 | }; |
126 | 127 | ||
127 | #define CDC_DATA_INTERFACE_TYPE 0x0a | 128 | #define CDC_DATA_INTERFACE_TYPE 0x0a |
128 | 129 | ||
129 | /* constants describing various quirks and errors */ | 130 | /* constants describing various quirks and errors */ |
130 | #define NO_UNION_NORMAL 1 | 131 | #define NO_UNION_NORMAL 1 |
131 | #define SINGLE_RX_URB 2 | 132 | #define SINGLE_RX_URB 2 |