11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * USB Serial Converter Generic functions 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License version 81da177e4SLinus Torvalds * 2 as published by the Free Software Foundation. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/kernel.h> 131da177e4SLinus Torvalds #include <linux/errno.h> 141da177e4SLinus Torvalds #include <linux/slab.h> 151da177e4SLinus Torvalds #include <linux/tty.h> 161da177e4SLinus Torvalds #include <linux/tty_flip.h> 171da177e4SLinus Torvalds #include <linux/module.h> 181da177e4SLinus Torvalds #include <linux/moduleparam.h> 191da177e4SLinus Torvalds #include <linux/usb.h> 20a969888cSGreg Kroah-Hartman #include <linux/usb/serial.h> 21ae64387aSAlan Cox #include <linux/uaccess.h> 221da177e4SLinus Torvalds 23d9b1b787SJohannes Hölzl 241da177e4SLinus Torvalds static int debug; 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #ifdef CONFIG_USB_SERIAL_GENERIC 27b46d60fcSDavid Brownell 28b46d60fcSDavid Brownell static int generic_probe(struct usb_interface *interface, 29b46d60fcSDavid Brownell const struct usb_device_id *id); 30b46d60fcSDavid Brownell 311da177e4SLinus Torvalds static __u16 vendor = 0x05f9; 321da177e4SLinus Torvalds static __u16 product = 0xffff; 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds module_param(vendor, ushort, 0); 351da177e4SLinus Torvalds MODULE_PARM_DESC(vendor, "User specified USB idVendor"); 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds module_param(product, ushort, 0); 381da177e4SLinus Torvalds MODULE_PARM_DESC(product, "User specified USB idProduct"); 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ 411da177e4SLinus Torvalds 42d9b1b787SJohannes Hölzl /* we want to look at all devices, as the vendor/product id can change 43d9b1b787SJohannes Hölzl * depending on the command line argument */ 44d9b1b787SJohannes Hölzl static struct usb_device_id generic_serial_ids[] = { 45d9b1b787SJohannes Hölzl {.driver_info = 42}, 46d9b1b787SJohannes Hölzl {} 47d9b1b787SJohannes Hölzl }; 48d9b1b787SJohannes Hölzl 49d9b1b787SJohannes Hölzl static struct usb_driver generic_driver = { 50d9b1b787SJohannes Hölzl .name = "usbserial_generic", 51d9b1b787SJohannes Hölzl .probe = generic_probe, 52d9b1b787SJohannes Hölzl .disconnect = usb_serial_disconnect, 53d9b1b787SJohannes Hölzl .id_table = generic_serial_ids, 54d9b1b787SJohannes Hölzl .no_dynamic_id = 1, 55d9b1b787SJohannes Hölzl }; 56d9b1b787SJohannes Hölzl 571da177e4SLinus Torvalds /* All of the device info needed for the Generic Serial Converter */ 58ea65370dSGreg Kroah-Hartman struct usb_serial_driver usb_serial_generic_device = { 5918fcac35SGreg Kroah-Hartman .driver = { 601da177e4SLinus Torvalds .owner = THIS_MODULE, 61269bda1cSGreg Kroah-Hartman .name = "generic", 6218fcac35SGreg Kroah-Hartman }, 631da177e4SLinus Torvalds .id_table = generic_device_ids, 64d9b1b787SJohannes Hölzl .usb_driver = &generic_driver, 651da177e4SLinus Torvalds .num_ports = 1, 661da177e4SLinus Torvalds .shutdown = usb_serial_generic_shutdown, 67253ca923SJoris van Rantwijk .throttle = usb_serial_generic_throttle, 68253ca923SJoris van Rantwijk .unthrottle = usb_serial_generic_unthrottle, 69ec22559eSOliver Neukum .resume = usb_serial_generic_resume, 701da177e4SLinus Torvalds }; 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds static int generic_probe(struct usb_interface *interface, 731da177e4SLinus Torvalds const struct usb_device_id *id) 741da177e4SLinus Torvalds { 751da177e4SLinus Torvalds const struct usb_device_id *id_pattern; 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds id_pattern = usb_match_id(interface, generic_device_ids); 781da177e4SLinus Torvalds if (id_pattern != NULL) 791da177e4SLinus Torvalds return usb_serial_probe(interface, id); 801da177e4SLinus Torvalds return -ENODEV; 811da177e4SLinus Torvalds } 821da177e4SLinus Torvalds #endif 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds int usb_serial_generic_register(int _debug) 851da177e4SLinus Torvalds { 861da177e4SLinus Torvalds int retval = 0; 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds debug = _debug; 891da177e4SLinus Torvalds #ifdef CONFIG_USB_SERIAL_GENERIC 901da177e4SLinus Torvalds generic_device_ids[0].idVendor = vendor; 911da177e4SLinus Torvalds generic_device_ids[0].idProduct = product; 92ae64387aSAlan Cox generic_device_ids[0].match_flags = 93ae64387aSAlan Cox USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds /* register our generic driver with ourselves */ 961da177e4SLinus Torvalds retval = usb_serial_register(&usb_serial_generic_device); 971da177e4SLinus Torvalds if (retval) 981da177e4SLinus Torvalds goto exit; 991da177e4SLinus Torvalds retval = usb_register(&generic_driver); 1001da177e4SLinus Torvalds if (retval) 1011da177e4SLinus Torvalds usb_serial_deregister(&usb_serial_generic_device); 1021da177e4SLinus Torvalds exit: 1031da177e4SLinus Torvalds #endif 1041da177e4SLinus Torvalds return retval; 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds void usb_serial_generic_deregister(void) 1081da177e4SLinus Torvalds { 1091da177e4SLinus Torvalds #ifdef CONFIG_USB_SERIAL_GENERIC 1101da177e4SLinus Torvalds /* remove our generic driver */ 1111da177e4SLinus Torvalds usb_deregister(&generic_driver); 1121da177e4SLinus Torvalds usb_serial_deregister(&usb_serial_generic_device); 1131da177e4SLinus Torvalds #endif 1141da177e4SLinus Torvalds } 1151da177e4SLinus Torvalds 11695da310eSAlan Cox int usb_serial_generic_open(struct tty_struct *tty, 11795da310eSAlan Cox struct usb_serial_port *port, struct file *filp) 1181da177e4SLinus Torvalds { 1191da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 1201da177e4SLinus Torvalds int result = 0; 121253ca923SJoris van Rantwijk unsigned long flags; 1221da177e4SLinus Torvalds 123441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 1241da177e4SLinus Torvalds 125253ca923SJoris van Rantwijk /* clear the throttle flags */ 126253ca923SJoris van Rantwijk spin_lock_irqsave(&port->lock, flags); 127253ca923SJoris van Rantwijk port->throttled = 0; 128253ca923SJoris van Rantwijk port->throttle_req = 0; 129253ca923SJoris van Rantwijk spin_unlock_irqrestore(&port->lock, flags); 130253ca923SJoris van Rantwijk 131253ca923SJoris van Rantwijk /* if we have a bulk endpoint, start reading from it */ 1321da177e4SLinus Torvalds if (serial->num_bulk_in) { 1331da177e4SLinus Torvalds /* Start reading from the device */ 1341da177e4SLinus Torvalds usb_fill_bulk_urb(port->read_urb, serial->dev, 135ae64387aSAlan Cox usb_rcvbulkpipe(serial->dev, 136ae64387aSAlan Cox port->bulk_in_endpointAddress), 1371da177e4SLinus Torvalds port->read_urb->transfer_buffer, 1381da177e4SLinus Torvalds port->read_urb->transfer_buffer_length, 1391da177e4SLinus Torvalds ((serial->type->read_bulk_callback) ? 1401da177e4SLinus Torvalds serial->type->read_bulk_callback : 1411da177e4SLinus Torvalds usb_serial_generic_read_bulk_callback), 1421da177e4SLinus Torvalds port); 1431da177e4SLinus Torvalds result = usb_submit_urb(port->read_urb, GFP_KERNEL); 1441da177e4SLinus Torvalds if (result) 145ae64387aSAlan Cox dev_err(&port->dev, 146ae64387aSAlan Cox "%s - failed resubmitting read urb, error %d\n", 147ae64387aSAlan Cox __func__, result); 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds return result; 1511da177e4SLinus Torvalds } 152815ddc99SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(usb_serial_generic_open); 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds static void generic_cleanup(struct usb_serial_port *port) 1551da177e4SLinus Torvalds { 1561da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 1571da177e4SLinus Torvalds 158441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds if (serial->dev) { 1611da177e4SLinus Torvalds /* shutdown any bulk reads that might be going on */ 1621da177e4SLinus Torvalds if (serial->num_bulk_out) 1631da177e4SLinus Torvalds usb_kill_urb(port->write_urb); 1641da177e4SLinus Torvalds if (serial->num_bulk_in) 1651da177e4SLinus Torvalds usb_kill_urb(port->read_urb); 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds 169ec22559eSOliver Neukum int usb_serial_generic_resume(struct usb_serial *serial) 170ec22559eSOliver Neukum { 171ec22559eSOliver Neukum struct usb_serial_port *port; 172ec22559eSOliver Neukum int i, c = 0, r; 173ec22559eSOliver Neukum 174ec22559eSOliver Neukum for (i = 0; i < serial->num_ports; i++) { 175ec22559eSOliver Neukum port = serial->port[i]; 17695da310eSAlan Cox if (port->port.count && port->read_urb) { 177ec22559eSOliver Neukum r = usb_submit_urb(port->read_urb, GFP_NOIO); 178ec22559eSOliver Neukum if (r < 0) 179ec22559eSOliver Neukum c++; 180ec22559eSOliver Neukum } 181ec22559eSOliver Neukum } 182ec22559eSOliver Neukum 183ec22559eSOliver Neukum return c ? -EIO : 0; 184ec22559eSOliver Neukum } 18581d043c2SOliver Neukum EXPORT_SYMBOL_GPL(usb_serial_generic_resume); 186ec22559eSOliver Neukum 187335f8514SAlan Cox void usb_serial_generic_close(struct usb_serial_port *port) 1881da177e4SLinus Torvalds { 189441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 1901da177e4SLinus Torvalds generic_cleanup(port); 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds 19395da310eSAlan Cox int usb_serial_generic_write(struct tty_struct *tty, 19495da310eSAlan Cox struct usb_serial_port *port, const unsigned char *buf, int count) 1951da177e4SLinus Torvalds { 1961da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 1971da177e4SLinus Torvalds int result; 1981da177e4SLinus Torvalds unsigned char *data; 1991da177e4SLinus Torvalds 200441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds if (count == 0) { 203441b62c1SHarvey Harrison dbg("%s - write request of 0 bytes", __func__); 204ae64387aSAlan Cox return 0; 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds /* only do something if we have a bulk out endpoint */ 2081da177e4SLinus Torvalds if (serial->num_bulk_out) { 209acd2a847SJiri Kosina unsigned long flags; 210acd2a847SJiri Kosina spin_lock_irqsave(&port->lock, flags); 211507ca9bcSGreg Kroah-Hartman if (port->write_urb_busy) { 212acd2a847SJiri Kosina spin_unlock_irqrestore(&port->lock, flags); 213441b62c1SHarvey Harrison dbg("%s - already writing", __func__); 214507ca9bcSGreg Kroah-Hartman return 0; 2151da177e4SLinus Torvalds } 216507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 1; 217acd2a847SJiri Kosina spin_unlock_irqrestore(&port->lock, flags); 2181da177e4SLinus Torvalds 219ae64387aSAlan Cox count = (count > port->bulk_out_size) ? 220ae64387aSAlan Cox port->bulk_out_size : count; 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds memcpy(port->write_urb->transfer_buffer, buf, count); 2231da177e4SLinus Torvalds data = port->write_urb->transfer_buffer; 224441b62c1SHarvey Harrison usb_serial_debug_data(debug, &port->dev, __func__, count, data); 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds /* set up our urb */ 2271da177e4SLinus Torvalds usb_fill_bulk_urb(port->write_urb, serial->dev, 2281da177e4SLinus Torvalds usb_sndbulkpipe(serial->dev, 2291da177e4SLinus Torvalds port->bulk_out_endpointAddress), 2301da177e4SLinus Torvalds port->write_urb->transfer_buffer, count, 2311da177e4SLinus Torvalds ((serial->type->write_bulk_callback) ? 2321da177e4SLinus Torvalds serial->type->write_bulk_callback : 233ae64387aSAlan Cox usb_serial_generic_write_bulk_callback), 234ae64387aSAlan Cox port); 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds /* send the data out the bulk port */ 237507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 1; 2381da177e4SLinus Torvalds result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 239507ca9bcSGreg Kroah-Hartman if (result) { 240ae64387aSAlan Cox dev_err(&port->dev, 241ae64387aSAlan Cox "%s - failed submitting write urb, error %d\n", 242ae64387aSAlan Cox __func__, result); 243ae64387aSAlan Cox /* don't have to grab the lock here, as we will 244ae64387aSAlan Cox retry if != 0 */ 245507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 0; 246507ca9bcSGreg Kroah-Hartman } else 2471da177e4SLinus Torvalds result = count; 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds return result; 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds /* no bulk out, so return 0 bytes written */ 253507ca9bcSGreg Kroah-Hartman return 0; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 25695da310eSAlan Cox int usb_serial_generic_write_room(struct tty_struct *tty) 2571da177e4SLinus Torvalds { 25895da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 2591da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 2601da177e4SLinus Torvalds int room = 0; 2611da177e4SLinus Torvalds 262441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 2631da177e4SLinus Torvalds 264a5b6f60cSAlan Cox /* FIXME: Locking */ 2651da177e4SLinus Torvalds if (serial->num_bulk_out) { 2667a3ca7d2SRandall Nortman if (!(port->write_urb_busy)) 2671da177e4SLinus Torvalds room = port->bulk_out_size; 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds 270441b62c1SHarvey Harrison dbg("%s - returns %d", __func__, room); 271a5b6f60cSAlan Cox return room; 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds 27495da310eSAlan Cox int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) 2751da177e4SLinus Torvalds { 27695da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 2771da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 2781da177e4SLinus Torvalds int chars = 0; 2791da177e4SLinus Torvalds 280441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 2811da177e4SLinus Torvalds 282a5b6f60cSAlan Cox /* FIXME: Locking */ 2831da177e4SLinus Torvalds if (serial->num_bulk_out) { 284507ca9bcSGreg Kroah-Hartman if (port->write_urb_busy) 2851da177e4SLinus Torvalds chars = port->write_urb->transfer_buffer_length; 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds 288441b62c1SHarvey Harrison dbg("%s - returns %d", __func__, chars); 28995da310eSAlan Cox return chars; 2901da177e4SLinus Torvalds } 2911da177e4SLinus Torvalds 2921abdeeb1SOliver Neukum 2931abdeeb1SOliver Neukum static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags) 2941da177e4SLinus Torvalds { 295253ca923SJoris van Rantwijk struct urb *urb = port->read_urb; 2961abdeeb1SOliver Neukum struct usb_serial *serial = port->serial; 2971da177e4SLinus Torvalds int result; 2981da177e4SLinus Torvalds 299253ca923SJoris van Rantwijk /* Continue reading from device */ 3001abdeeb1SOliver Neukum usb_fill_bulk_urb(urb, serial->dev, 3011da177e4SLinus Torvalds usb_rcvbulkpipe(serial->dev, 3021da177e4SLinus Torvalds port->bulk_in_endpointAddress), 3031abdeeb1SOliver Neukum urb->transfer_buffer, 3041abdeeb1SOliver Neukum urb->transfer_buffer_length, 3051da177e4SLinus Torvalds ((serial->type->read_bulk_callback) ? 3061da177e4SLinus Torvalds serial->type->read_bulk_callback : 3071da177e4SLinus Torvalds usb_serial_generic_read_bulk_callback), port); 3081abdeeb1SOliver Neukum result = usb_submit_urb(urb, mem_flags); 3091da177e4SLinus Torvalds if (result) 310ae64387aSAlan Cox dev_err(&port->dev, 311ae64387aSAlan Cox "%s - failed resubmitting read urb, error %d\n", 312ae64387aSAlan Cox __func__, result); 3131da177e4SLinus Torvalds } 314253ca923SJoris van Rantwijk 3151abdeeb1SOliver Neukum /* Push data to tty layer and resubmit the bulk read URB */ 3161abdeeb1SOliver Neukum static void flush_and_resubmit_read_urb(struct usb_serial_port *port) 3171abdeeb1SOliver Neukum { 3181abdeeb1SOliver Neukum struct urb *urb = port->read_urb; 3194a90f09bSAlan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 3201abdeeb1SOliver Neukum int room; 3211abdeeb1SOliver Neukum 3221abdeeb1SOliver Neukum /* Push data to tty */ 3231abdeeb1SOliver Neukum if (tty && urb->actual_length) { 3241abdeeb1SOliver Neukum room = tty_buffer_request_room(tty, urb->actual_length); 3251abdeeb1SOliver Neukum if (room) { 3261abdeeb1SOliver Neukum tty_insert_flip_string(tty, urb->transfer_buffer, room); 327b507cc97SPete Zaitcev tty_flip_buffer_push(tty); 3281abdeeb1SOliver Neukum } 3291abdeeb1SOliver Neukum } 3304a90f09bSAlan Cox tty_kref_put(tty); 3311abdeeb1SOliver Neukum 3321abdeeb1SOliver Neukum resubmit_read_urb(port, GFP_ATOMIC); 3331abdeeb1SOliver Neukum } 3341abdeeb1SOliver Neukum 335253ca923SJoris van Rantwijk void usb_serial_generic_read_bulk_callback(struct urb *urb) 336253ca923SJoris van Rantwijk { 337cdc97792SMing Lei struct usb_serial_port *port = urb->context; 338253ca923SJoris van Rantwijk unsigned char *data = urb->transfer_buffer; 339fbd27225SGreg Kroah-Hartman int status = urb->status; 340bfaeafcfSBorislav Petkov unsigned long flags; 341253ca923SJoris van Rantwijk 342441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 343253ca923SJoris van Rantwijk 344fbd27225SGreg Kroah-Hartman if (unlikely(status != 0)) { 345fbd27225SGreg Kroah-Hartman dbg("%s - nonzero read bulk status received: %d", 346441b62c1SHarvey Harrison __func__, status); 347253ca923SJoris van Rantwijk return; 348253ca923SJoris van Rantwijk } 349253ca923SJoris van Rantwijk 350ae64387aSAlan Cox usb_serial_debug_data(debug, &port->dev, __func__, 351ae64387aSAlan Cox urb->actual_length, data); 352253ca923SJoris van Rantwijk 353253ca923SJoris van Rantwijk /* Throttle the device if requested by tty */ 354bfaeafcfSBorislav Petkov spin_lock_irqsave(&port->lock, flags); 355ae64387aSAlan Cox port->throttled = port->throttle_req; 356ae64387aSAlan Cox if (!port->throttled) { 357bfaeafcfSBorislav Petkov spin_unlock_irqrestore(&port->lock, flags); 358b507cc97SPete Zaitcev flush_and_resubmit_read_urb(port); 359ae64387aSAlan Cox } else 360b507cc97SPete Zaitcev spin_unlock_irqrestore(&port->lock, flags); 361b507cc97SPete Zaitcev } 362166ffccfSLuiz Fernando N. Capitulino EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); 3631da177e4SLinus Torvalds 3647d12e780SDavid Howells void usb_serial_generic_write_bulk_callback(struct urb *urb) 3651da177e4SLinus Torvalds { 366cdc97792SMing Lei struct usb_serial_port *port = urb->context; 367fbd27225SGreg Kroah-Hartman int status = urb->status; 3681da177e4SLinus Torvalds 369441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 3701da177e4SLinus Torvalds 371507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 0; 372fbd27225SGreg Kroah-Hartman if (status) { 373fbd27225SGreg Kroah-Hartman dbg("%s - nonzero write bulk status received: %d", 374441b62c1SHarvey Harrison __func__, status); 3751da177e4SLinus Torvalds return; 3761da177e4SLinus Torvalds } 377cf2c7481SPete Zaitcev usb_serial_port_softint(port); 3781da177e4SLinus Torvalds } 379bb833986SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); 3801da177e4SLinus Torvalds 38195da310eSAlan Cox void usb_serial_generic_throttle(struct tty_struct *tty) 382253ca923SJoris van Rantwijk { 38395da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 384253ca923SJoris van Rantwijk unsigned long flags; 385253ca923SJoris van Rantwijk 386441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 387253ca923SJoris van Rantwijk 388253ca923SJoris van Rantwijk /* Set the throttle request flag. It will be picked up 389253ca923SJoris van Rantwijk * by usb_serial_generic_read_bulk_callback(). */ 390253ca923SJoris van Rantwijk spin_lock_irqsave(&port->lock, flags); 391253ca923SJoris van Rantwijk port->throttle_req = 1; 392253ca923SJoris van Rantwijk spin_unlock_irqrestore(&port->lock, flags); 393253ca923SJoris van Rantwijk } 394253ca923SJoris van Rantwijk 39595da310eSAlan Cox void usb_serial_generic_unthrottle(struct tty_struct *tty) 396253ca923SJoris van Rantwijk { 39795da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 398253ca923SJoris van Rantwijk int was_throttled; 399253ca923SJoris van Rantwijk unsigned long flags; 400253ca923SJoris van Rantwijk 401441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 402253ca923SJoris van Rantwijk 403253ca923SJoris van Rantwijk /* Clear the throttle flags */ 404253ca923SJoris van Rantwijk spin_lock_irqsave(&port->lock, flags); 405253ca923SJoris van Rantwijk was_throttled = port->throttled; 406253ca923SJoris van Rantwijk port->throttled = port->throttle_req = 0; 407253ca923SJoris van Rantwijk spin_unlock_irqrestore(&port->lock, flags); 408253ca923SJoris van Rantwijk 409253ca923SJoris van Rantwijk if (was_throttled) { 4101abdeeb1SOliver Neukum /* Resume reading from device */ 4111abdeeb1SOliver Neukum resubmit_read_urb(port, GFP_KERNEL); 412253ca923SJoris van Rantwijk } 413253ca923SJoris van Rantwijk } 414253ca923SJoris van Rantwijk 4151da177e4SLinus Torvalds void usb_serial_generic_shutdown(struct usb_serial *serial) 4161da177e4SLinus Torvalds { 4171da177e4SLinus Torvalds int i; 4181da177e4SLinus Torvalds 419441b62c1SHarvey Harrison dbg("%s", __func__); 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds /* stop reads and writes on all ports */ 422ae64387aSAlan Cox for (i = 0; i < serial->num_ports; ++i) 4231da177e4SLinus Torvalds generic_cleanup(serial->port[i]); 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 426