Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * USB Serial Converter Generic functions | |
3 | * | |
4 | * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License version | |
8 | * 2 as published by the Free Software Foundation. | |
9 | * | |
10 | */ | |
11 | ||
1da177e4 LT |
12 | #include <linux/kernel.h> |
13 | #include <linux/errno.h> | |
14 | #include <linux/slab.h> | |
15 | #include <linux/tty.h> | |
16 | #include <linux/tty_flip.h> | |
17 | #include <linux/module.h> | |
18 | #include <linux/moduleparam.h> | |
19 | #include <linux/usb.h> | |
a969888c | 20 | #include <linux/usb/serial.h> |
ae64387a | 21 | #include <linux/uaccess.h> |
1da177e4 | 22 | |
d9b1b787 | 23 | |
1da177e4 LT |
24 | static int debug; |
25 | ||
26 | #ifdef CONFIG_USB_SERIAL_GENERIC | |
b46d60fc DB |
27 | |
28 | static int generic_probe(struct usb_interface *interface, | |
29 | const struct usb_device_id *id); | |
30 | ||
1da177e4 LT |
31 | static __u16 vendor = 0x05f9; |
32 | static __u16 product = 0xffff; | |
33 | ||
34 | module_param(vendor, ushort, 0); | |
35 | MODULE_PARM_DESC(vendor, "User specified USB idVendor"); | |
36 | ||
37 | module_param(product, ushort, 0); | |
38 | MODULE_PARM_DESC(product, "User specified USB idProduct"); | |
39 | ||
40 | static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ | |
41 | ||
d9b1b787 JH |
42 | /* we want to look at all devices, as the vendor/product id can change |
43 | * depending on the command line argument */ | |
44 | static struct usb_device_id generic_serial_ids[] = { | |
45 | {.driver_info = 42}, | |
46 | {} | |
47 | }; | |
48 | ||
49 | static struct usb_driver generic_driver = { | |
50 | .name = "usbserial_generic", | |
51 | .probe = generic_probe, | |
52 | .disconnect = usb_serial_disconnect, | |
53 | .id_table = generic_serial_ids, | |
54 | .no_dynamic_id = 1, | |
55 | }; | |
56 | ||
1da177e4 | 57 | /* All of the device info needed for the Generic Serial Converter */ |
ea65370d | 58 | struct usb_serial_driver usb_serial_generic_device = { |
18fcac35 GKH |
59 | .driver = { |
60 | .owner = THIS_MODULE, | |
269bda1c | 61 | .name = "generic", |
18fcac35 | 62 | }, |
1da177e4 | 63 | .id_table = generic_device_ids, |
d9b1b787 | 64 | .usb_driver = &generic_driver, |
1da177e4 LT |
65 | .num_ports = 1, |
66 | .shutdown = usb_serial_generic_shutdown, | |
253ca923 JR |
67 | .throttle = usb_serial_generic_throttle, |
68 | .unthrottle = usb_serial_generic_unthrottle, | |
ec22559e | 69 | .resume = usb_serial_generic_resume, |
1da177e4 LT |
70 | }; |
71 | ||
1da177e4 LT |
72 | static int generic_probe(struct usb_interface *interface, |
73 | const struct usb_device_id *id) | |
74 | { | |
75 | const struct usb_device_id *id_pattern; | |
76 | ||
77 | id_pattern = usb_match_id(interface, generic_device_ids); | |
78 | if (id_pattern != NULL) | |
79 | return usb_serial_probe(interface, id); | |
80 | return -ENODEV; | |
81 | } | |
1da177e4 LT |
82 | #endif |
83 | ||
ae64387a | 84 | int usb_serial_generic_register(int _debug) |
1da177e4 LT |
85 | { |
86 | int retval = 0; | |
87 | ||
88 | debug = _debug; | |
89 | #ifdef CONFIG_USB_SERIAL_GENERIC | |
90 | generic_device_ids[0].idVendor = vendor; | |
91 | generic_device_ids[0].idProduct = product; | |
ae64387a AC |
92 | generic_device_ids[0].match_flags = |
93 | USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; | |
1da177e4 LT |
94 | |
95 | /* register our generic driver with ourselves */ | |
ae64387a | 96 | retval = usb_serial_register(&usb_serial_generic_device); |
1da177e4 LT |
97 | if (retval) |
98 | goto exit; | |
99 | retval = usb_register(&generic_driver); | |
100 | if (retval) | |
101 | usb_serial_deregister(&usb_serial_generic_device); | |
102 | exit: | |
103 | #endif | |
104 | return retval; | |
105 | } | |
106 | ||
ae64387a | 107 | void usb_serial_generic_deregister(void) |
1da177e4 LT |
108 | { |
109 | #ifdef CONFIG_USB_SERIAL_GENERIC | |
110 | /* remove our generic driver */ | |
111 | usb_deregister(&generic_driver); | |
ae64387a | 112 | usb_serial_deregister(&usb_serial_generic_device); |
1da177e4 LT |
113 | #endif |
114 | } | |
115 | ||
95da310e AC |
116 | int usb_serial_generic_open(struct tty_struct *tty, |
117 | struct usb_serial_port *port, struct file *filp) | |
1da177e4 LT |
118 | { |
119 | struct usb_serial *serial = port->serial; | |
120 | int result = 0; | |
253ca923 | 121 | unsigned long flags; |
1da177e4 | 122 | |
441b62c1 | 123 | dbg("%s - port %d", __func__, port->number); |
1da177e4 | 124 | |
253ca923 JR |
125 | /* clear the throttle flags */ |
126 | spin_lock_irqsave(&port->lock, flags); | |
127 | port->throttled = 0; | |
128 | port->throttle_req = 0; | |
129 | spin_unlock_irqrestore(&port->lock, flags); | |
130 | ||
131 | /* if we have a bulk endpoint, start reading from it */ | |
1da177e4 LT |
132 | if (serial->num_bulk_in) { |
133 | /* Start reading from the device */ | |
ae64387a AC |
134 | usb_fill_bulk_urb(port->read_urb, serial->dev, |
135 | usb_rcvbulkpipe(serial->dev, | |
136 | port->bulk_in_endpointAddress), | |
1da177e4 LT |
137 | port->read_urb->transfer_buffer, |
138 | port->read_urb->transfer_buffer_length, | |
139 | ((serial->type->read_bulk_callback) ? | |
140 | serial->type->read_bulk_callback : | |
141 | usb_serial_generic_read_bulk_callback), | |
142 | port); | |
143 | result = usb_submit_urb(port->read_urb, GFP_KERNEL); | |
144 | if (result) | |
ae64387a AC |
145 | dev_err(&port->dev, |
146 | "%s - failed resubmitting read urb, error %d\n", | |
147 | __func__, result); | |
1da177e4 LT |
148 | } |
149 | ||
150 | return result; | |
151 | } | |
815ddc99 | 152 | EXPORT_SYMBOL_GPL(usb_serial_generic_open); |
1da177e4 | 153 | |
95da310e | 154 | static void generic_cleanup(struct usb_serial_port *port) |
1da177e4 LT |
155 | { |
156 | struct usb_serial *serial = port->serial; | |
157 | ||
441b62c1 | 158 | dbg("%s - port %d", __func__, port->number); |
1da177e4 LT |
159 | |
160 | if (serial->dev) { | |
161 | /* shutdown any bulk reads that might be going on */ | |
162 | if (serial->num_bulk_out) | |
163 | usb_kill_urb(port->write_urb); | |
164 | if (serial->num_bulk_in) | |
165 | usb_kill_urb(port->read_urb); | |
166 | } | |
167 | } | |
168 | ||
ec22559e ON |
169 | int usb_serial_generic_resume(struct usb_serial *serial) |
170 | { | |
171 | struct usb_serial_port *port; | |
172 | int i, c = 0, r; | |
173 | ||
174 | for (i = 0; i < serial->num_ports; i++) { | |
175 | port = serial->port[i]; | |
95da310e | 176 | if (port->port.count && port->read_urb) { |
ec22559e ON |
177 | r = usb_submit_urb(port->read_urb, GFP_NOIO); |
178 | if (r < 0) | |
179 | c++; | |
180 | } | |
181 | } | |
182 | ||
183 | return c ? -EIO : 0; | |
184 | } | |
81d043c2 | 185 | EXPORT_SYMBOL_GPL(usb_serial_generic_resume); |
ec22559e | 186 | |
335f8514 | 187 | void usb_serial_generic_close(struct usb_serial_port *port) |
1da177e4 | 188 | { |
441b62c1 | 189 | dbg("%s - port %d", __func__, port->number); |
ae64387a | 190 | generic_cleanup(port); |
1da177e4 LT |
191 | } |
192 | ||
715b1dc0 JW |
193 | static int usb_serial_multi_urb_write(struct tty_struct *tty, |
194 | struct usb_serial_port *port, const unsigned char *buf, int count) | |
195 | { | |
196 | unsigned long flags; | |
197 | struct urb *urb; | |
198 | unsigned char *buffer; | |
199 | int status; | |
200 | int towrite; | |
201 | int bwrite = 0; | |
202 | ||
203 | dbg("%s - port %d", __func__, port->number); | |
204 | ||
205 | if (count == 0) | |
206 | dbg("%s - write request of 0 bytes", __func__); | |
207 | ||
208 | while (count > 0) { | |
209 | towrite = (count > port->bulk_out_size) ? | |
210 | port->bulk_out_size : count; | |
211 | spin_lock_irqsave(&port->lock, flags); | |
212 | if (port->urbs_in_flight > | |
213 | port->serial->type->max_in_flight_urbs) { | |
214 | spin_unlock_irqrestore(&port->lock, flags); | |
215 | dbg("%s - write limit hit\n", __func__); | |
216 | return bwrite; | |
217 | } | |
218 | port->tx_bytes_flight += towrite; | |
219 | port->urbs_in_flight++; | |
220 | spin_unlock_irqrestore(&port->lock, flags); | |
221 | ||
222 | buffer = kmalloc(towrite, GFP_ATOMIC); | |
223 | if (!buffer) { | |
224 | dev_err(&port->dev, | |
225 | "%s ran out of kernel memory for urb ...\n", __func__); | |
226 | goto error_no_buffer; | |
227 | } | |
228 | ||
229 | urb = usb_alloc_urb(0, GFP_ATOMIC); | |
230 | if (!urb) { | |
231 | dev_err(&port->dev, "%s - no more free urbs\n", | |
232 | __func__); | |
233 | goto error_no_urb; | |
234 | } | |
235 | ||
236 | /* Copy data */ | |
237 | memcpy(buffer, buf + bwrite, towrite); | |
238 | usb_serial_debug_data(debug, &port->dev, __func__, | |
239 | towrite, buffer); | |
240 | /* fill the buffer and send it */ | |
241 | usb_fill_bulk_urb(urb, port->serial->dev, | |
242 | usb_sndbulkpipe(port->serial->dev, | |
243 | port->bulk_out_endpointAddress), | |
244 | buffer, towrite, | |
245 | usb_serial_generic_write_bulk_callback, port); | |
246 | ||
247 | status = usb_submit_urb(urb, GFP_ATOMIC); | |
248 | if (status) { | |
249 | dev_err(&port->dev, | |
250 | "%s - failed submitting write urb, error %d\n", | |
251 | __func__, status); | |
252 | goto error; | |
253 | } | |
254 | ||
255 | /* This urb is the responsibility of the host driver now */ | |
256 | usb_free_urb(urb); | |
257 | dbg("%s write: %d", __func__, towrite); | |
258 | count -= towrite; | |
259 | bwrite += towrite; | |
260 | } | |
261 | return bwrite; | |
262 | ||
263 | error: | |
264 | usb_free_urb(urb); | |
265 | error_no_urb: | |
266 | kfree(buffer); | |
267 | error_no_buffer: | |
268 | spin_lock_irqsave(&port->lock, flags); | |
269 | port->urbs_in_flight--; | |
270 | port->tx_bytes_flight -= towrite; | |
271 | spin_unlock_irqrestore(&port->lock, flags); | |
272 | return bwrite; | |
273 | } | |
274 | ||
95da310e AC |
275 | int usb_serial_generic_write(struct tty_struct *tty, |
276 | struct usb_serial_port *port, const unsigned char *buf, int count) | |
1da177e4 LT |
277 | { |
278 | struct usb_serial *serial = port->serial; | |
279 | int result; | |
280 | unsigned char *data; | |
281 | ||
441b62c1 | 282 | dbg("%s - port %d", __func__, port->number); |
1da177e4 LT |
283 | |
284 | if (count == 0) { | |
441b62c1 | 285 | dbg("%s - write request of 0 bytes", __func__); |
ae64387a | 286 | return 0; |
1da177e4 LT |
287 | } |
288 | ||
289 | /* only do something if we have a bulk out endpoint */ | |
290 | if (serial->num_bulk_out) { | |
acd2a847 | 291 | unsigned long flags; |
715b1dc0 JW |
292 | |
293 | if (serial->type->max_in_flight_urbs) | |
294 | return usb_serial_multi_urb_write(tty, port, | |
295 | buf, count); | |
296 | ||
acd2a847 | 297 | spin_lock_irqsave(&port->lock, flags); |
507ca9bc | 298 | if (port->write_urb_busy) { |
acd2a847 | 299 | spin_unlock_irqrestore(&port->lock, flags); |
441b62c1 | 300 | dbg("%s - already writing", __func__); |
507ca9bc | 301 | return 0; |
1da177e4 | 302 | } |
507ca9bc | 303 | port->write_urb_busy = 1; |
acd2a847 | 304 | spin_unlock_irqrestore(&port->lock, flags); |
1da177e4 | 305 | |
ae64387a AC |
306 | count = (count > port->bulk_out_size) ? |
307 | port->bulk_out_size : count; | |
1da177e4 | 308 | |
ae64387a | 309 | memcpy(port->write_urb->transfer_buffer, buf, count); |
1da177e4 | 310 | data = port->write_urb->transfer_buffer; |
441b62c1 | 311 | usb_serial_debug_data(debug, &port->dev, __func__, count, data); |
1da177e4 LT |
312 | |
313 | /* set up our urb */ | |
ae64387a AC |
314 | usb_fill_bulk_urb(port->write_urb, serial->dev, |
315 | usb_sndbulkpipe(serial->dev, | |
316 | port->bulk_out_endpointAddress), | |
1da177e4 | 317 | port->write_urb->transfer_buffer, count, |
ae64387a | 318 | ((serial->type->write_bulk_callback) ? |
1da177e4 | 319 | serial->type->write_bulk_callback : |
ae64387a AC |
320 | usb_serial_generic_write_bulk_callback), |
321 | port); | |
1da177e4 LT |
322 | |
323 | /* send the data out the bulk port */ | |
507ca9bc | 324 | port->write_urb_busy = 1; |
1da177e4 | 325 | result = usb_submit_urb(port->write_urb, GFP_ATOMIC); |
507ca9bc | 326 | if (result) { |
ae64387a AC |
327 | dev_err(&port->dev, |
328 | "%s - failed submitting write urb, error %d\n", | |
329 | __func__, result); | |
330 | /* don't have to grab the lock here, as we will | |
331 | retry if != 0 */ | |
507ca9bc GKH |
332 | port->write_urb_busy = 0; |
333 | } else | |
1da177e4 LT |
334 | result = count; |
335 | ||
336 | return result; | |
337 | } | |
338 | ||
339 | /* no bulk out, so return 0 bytes written */ | |
507ca9bc | 340 | return 0; |
1da177e4 | 341 | } |
98fcb5f7 | 342 | EXPORT_SYMBOL_GPL(usb_serial_generic_write); |
1da177e4 | 343 | |
ae64387a | 344 | int usb_serial_generic_write_room(struct tty_struct *tty) |
1da177e4 | 345 | { |
95da310e | 346 | struct usb_serial_port *port = tty->driver_data; |
1da177e4 | 347 | struct usb_serial *serial = port->serial; |
715b1dc0 | 348 | unsigned long flags; |
1da177e4 LT |
349 | int room = 0; |
350 | ||
441b62c1 | 351 | dbg("%s - port %d", __func__, port->number); |
715b1dc0 JW |
352 | spin_lock_irqsave(&port->lock, flags); |
353 | if (serial->type->max_in_flight_urbs) { | |
354 | if (port->urbs_in_flight < serial->type->max_in_flight_urbs) | |
98fcb5f7 JW |
355 | room = port->bulk_out_size * |
356 | (serial->type->max_in_flight_urbs - | |
357 | port->urbs_in_flight); | |
715b1dc0 JW |
358 | } else if (serial->num_bulk_out && !(port->write_urb_busy)) { |
359 | room = port->bulk_out_size; | |
1da177e4 | 360 | } |
715b1dc0 | 361 | spin_unlock_irqrestore(&port->lock, flags); |
1da177e4 | 362 | |
441b62c1 | 363 | dbg("%s - returns %d", __func__, room); |
a5b6f60c | 364 | return room; |
1da177e4 LT |
365 | } |
366 | ||
95da310e | 367 | int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) |
1da177e4 | 368 | { |
95da310e | 369 | struct usb_serial_port *port = tty->driver_data; |
1da177e4 LT |
370 | struct usb_serial *serial = port->serial; |
371 | int chars = 0; | |
715b1dc0 | 372 | unsigned long flags; |
1da177e4 | 373 | |
441b62c1 | 374 | dbg("%s - port %d", __func__, port->number); |
1da177e4 | 375 | |
715b1dc0 JW |
376 | if (serial->type->max_in_flight_urbs) { |
377 | spin_lock_irqsave(&port->lock, flags); | |
378 | chars = port->tx_bytes_flight; | |
379 | spin_unlock_irqrestore(&port->lock, flags); | |
380 | } else if (serial->num_bulk_out) { | |
381 | /* FIXME: Locking */ | |
507ca9bc | 382 | if (port->write_urb_busy) |
1da177e4 LT |
383 | chars = port->write_urb->transfer_buffer_length; |
384 | } | |
385 | ||
441b62c1 | 386 | dbg("%s - returns %d", __func__, chars); |
95da310e | 387 | return chars; |
1da177e4 LT |
388 | } |
389 | ||
1abdeeb1 | 390 | |
98fcb5f7 JW |
391 | void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port, |
392 | gfp_t mem_flags) | |
1da177e4 | 393 | { |
253ca923 | 394 | struct urb *urb = port->read_urb; |
1abdeeb1 | 395 | struct usb_serial *serial = port->serial; |
1da177e4 LT |
396 | int result; |
397 | ||
253ca923 | 398 | /* Continue reading from device */ |
ae64387a AC |
399 | usb_fill_bulk_urb(urb, serial->dev, |
400 | usb_rcvbulkpipe(serial->dev, | |
401 | port->bulk_in_endpointAddress), | |
1abdeeb1 ON |
402 | urb->transfer_buffer, |
403 | urb->transfer_buffer_length, | |
ae64387a AC |
404 | ((serial->type->read_bulk_callback) ? |
405 | serial->type->read_bulk_callback : | |
1da177e4 | 406 | usb_serial_generic_read_bulk_callback), port); |
1abdeeb1 | 407 | result = usb_submit_urb(urb, mem_flags); |
1da177e4 | 408 | if (result) |
ae64387a AC |
409 | dev_err(&port->dev, |
410 | "%s - failed resubmitting read urb, error %d\n", | |
411 | __func__, result); | |
1da177e4 | 412 | } |
98fcb5f7 | 413 | EXPORT_SYMBOL_GPL(usb_serial_generic_resubmit_read_urb); |
253ca923 | 414 | |
1abdeeb1 | 415 | /* Push data to tty layer and resubmit the bulk read URB */ |
95da310e | 416 | static void flush_and_resubmit_read_urb(struct usb_serial_port *port) |
1abdeeb1 ON |
417 | { |
418 | struct urb *urb = port->read_urb; | |
4a90f09b | 419 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
98fcb5f7 JW |
420 | char *ch = (char *)urb->transfer_buffer; |
421 | int i; | |
422 | ||
423 | if (!tty) | |
424 | goto done; | |
1abdeeb1 ON |
425 | |
426 | /* Push data to tty */ | |
98fcb5f7 JW |
427 | for (i = 0; i < urb->actual_length; i++, ch++) { |
428 | if (!usb_serial_handle_sysrq_char(port, *ch)) | |
429 | tty_insert_flip_char(tty, *ch, TTY_NORMAL); | |
1abdeeb1 | 430 | } |
98fcb5f7 | 431 | tty_flip_buffer_push(tty); |
4a90f09b | 432 | tty_kref_put(tty); |
98fcb5f7 JW |
433 | done: |
434 | usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC); | |
1abdeeb1 ON |
435 | } |
436 | ||
95da310e | 437 | void usb_serial_generic_read_bulk_callback(struct urb *urb) |
253ca923 | 438 | { |
cdc97792 | 439 | struct usb_serial_port *port = urb->context; |
253ca923 | 440 | unsigned char *data = urb->transfer_buffer; |
fbd27225 | 441 | int status = urb->status; |
bfaeafcf | 442 | unsigned long flags; |
253ca923 | 443 | |
441b62c1 | 444 | dbg("%s - port %d", __func__, port->number); |
253ca923 | 445 | |
fbd27225 GKH |
446 | if (unlikely(status != 0)) { |
447 | dbg("%s - nonzero read bulk status received: %d", | |
441b62c1 | 448 | __func__, status); |
253ca923 JR |
449 | return; |
450 | } | |
451 | ||
ae64387a AC |
452 | usb_serial_debug_data(debug, &port->dev, __func__, |
453 | urb->actual_length, data); | |
253ca923 JR |
454 | |
455 | /* Throttle the device if requested by tty */ | |
bfaeafcf | 456 | spin_lock_irqsave(&port->lock, flags); |
ae64387a AC |
457 | port->throttled = port->throttle_req; |
458 | if (!port->throttled) { | |
b507cc97 | 459 | spin_unlock_irqrestore(&port->lock, flags); |
1abdeeb1 | 460 | flush_and_resubmit_read_urb(port); |
ae64387a | 461 | } else |
b507cc97 | 462 | spin_unlock_irqrestore(&port->lock, flags); |
253ca923 | 463 | } |
166ffccf | 464 | EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); |
1da177e4 | 465 | |
95da310e | 466 | void usb_serial_generic_write_bulk_callback(struct urb *urb) |
1da177e4 | 467 | { |
715b1dc0 | 468 | unsigned long flags; |
cdc97792 | 469 | struct usb_serial_port *port = urb->context; |
fbd27225 | 470 | int status = urb->status; |
1da177e4 | 471 | |
441b62c1 | 472 | dbg("%s - port %d", __func__, port->number); |
1da177e4 | 473 | |
715b1dc0 JW |
474 | if (port->serial->type->max_in_flight_urbs) { |
475 | spin_lock_irqsave(&port->lock, flags); | |
476 | --port->urbs_in_flight; | |
477 | port->tx_bytes_flight -= urb->transfer_buffer_length; | |
478 | if (port->urbs_in_flight < 0) | |
479 | port->urbs_in_flight = 0; | |
480 | spin_unlock_irqrestore(&port->lock, flags); | |
481 | } else { | |
482 | /* Handle the case for single urb mode */ | |
483 | port->write_urb_busy = 0; | |
484 | } | |
485 | ||
fbd27225 GKH |
486 | if (status) { |
487 | dbg("%s - nonzero write bulk status received: %d", | |
441b62c1 | 488 | __func__, status); |
1da177e4 LT |
489 | return; |
490 | } | |
cf2c7481 | 491 | usb_serial_port_softint(port); |
1da177e4 | 492 | } |
bb833986 | 493 | EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); |
1da177e4 | 494 | |
95da310e | 495 | void usb_serial_generic_throttle(struct tty_struct *tty) |
253ca923 | 496 | { |
95da310e | 497 | struct usb_serial_port *port = tty->driver_data; |
253ca923 JR |
498 | unsigned long flags; |
499 | ||
441b62c1 | 500 | dbg("%s - port %d", __func__, port->number); |
253ca923 JR |
501 | |
502 | /* Set the throttle request flag. It will be picked up | |
503 | * by usb_serial_generic_read_bulk_callback(). */ | |
504 | spin_lock_irqsave(&port->lock, flags); | |
505 | port->throttle_req = 1; | |
506 | spin_unlock_irqrestore(&port->lock, flags); | |
507 | } | |
508 | ||
95da310e | 509 | void usb_serial_generic_unthrottle(struct tty_struct *tty) |
253ca923 | 510 | { |
95da310e | 511 | struct usb_serial_port *port = tty->driver_data; |
253ca923 JR |
512 | int was_throttled; |
513 | unsigned long flags; | |
514 | ||
441b62c1 | 515 | dbg("%s - port %d", __func__, port->number); |
253ca923 JR |
516 | |
517 | /* Clear the throttle flags */ | |
518 | spin_lock_irqsave(&port->lock, flags); | |
519 | was_throttled = port->throttled; | |
520 | port->throttled = port->throttle_req = 0; | |
521 | spin_unlock_irqrestore(&port->lock, flags); | |
522 | ||
523 | if (was_throttled) { | |
1abdeeb1 | 524 | /* Resume reading from device */ |
98fcb5f7 | 525 | usb_serial_generic_resubmit_read_urb(port, GFP_KERNEL); |
253ca923 JR |
526 | } |
527 | } | |
528 | ||
98fcb5f7 JW |
529 | int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) |
530 | { | |
568d422e | 531 | if (port->sysrq && port->console) { |
98fcb5f7 JW |
532 | if (ch && time_before(jiffies, port->sysrq)) { |
533 | handle_sysrq(ch, tty_port_tty_get(&port->port)); | |
534 | port->sysrq = 0; | |
535 | return 1; | |
536 | } | |
537 | port->sysrq = 0; | |
538 | } | |
539 | return 0; | |
540 | } | |
541 | EXPORT_SYMBOL_GPL(usb_serial_handle_sysrq_char); | |
542 | ||
543 | int usb_serial_handle_break(struct usb_serial_port *port) | |
544 | { | |
545 | if (!port->sysrq) { | |
546 | port->sysrq = jiffies + HZ*5; | |
547 | return 1; | |
548 | } | |
549 | port->sysrq = 0; | |
550 | return 0; | |
551 | } | |
552 | EXPORT_SYMBOL_GPL(usb_serial_handle_break); | |
553 | ||
ae64387a | 554 | void usb_serial_generic_shutdown(struct usb_serial *serial) |
1da177e4 LT |
555 | { |
556 | int i; | |
557 | ||
441b62c1 | 558 | dbg("%s", __func__); |
1da177e4 LT |
559 | |
560 | /* stop reads and writes on all ports */ | |
ae64387a | 561 | for (i = 0; i < serial->num_ports; ++i) |
1da177e4 | 562 | generic_cleanup(serial->port[i]); |
1da177e4 LT |
563 | } |
564 |