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 125ae64387aSAlan Cox /* force low_latency on so that our tty_push actually forces the data 126ae64387aSAlan Cox through, otherwise it is scheduled, and with high data rates (like 127ae64387aSAlan Cox with OHCI) data can get lost. */ 12895da310eSAlan Cox if (tty) 12995da310eSAlan Cox tty->low_latency = 1; 1301da177e4SLinus Torvalds 131253ca923SJoris van Rantwijk /* clear the throttle flags */ 132253ca923SJoris van Rantwijk spin_lock_irqsave(&port->lock, flags); 133253ca923SJoris van Rantwijk port->throttled = 0; 134253ca923SJoris van Rantwijk port->throttle_req = 0; 135253ca923SJoris van Rantwijk spin_unlock_irqrestore(&port->lock, flags); 136253ca923SJoris van Rantwijk 137253ca923SJoris van Rantwijk /* if we have a bulk endpoint, start reading from it */ 1381da177e4SLinus Torvalds if (serial->num_bulk_in) { 1391da177e4SLinus Torvalds /* Start reading from the device */ 1401da177e4SLinus Torvalds usb_fill_bulk_urb(port->read_urb, serial->dev, 141ae64387aSAlan Cox usb_rcvbulkpipe(serial->dev, 142ae64387aSAlan Cox port->bulk_in_endpointAddress), 1431da177e4SLinus Torvalds port->read_urb->transfer_buffer, 1441da177e4SLinus Torvalds port->read_urb->transfer_buffer_length, 1451da177e4SLinus Torvalds ((serial->type->read_bulk_callback) ? 1461da177e4SLinus Torvalds serial->type->read_bulk_callback : 1471da177e4SLinus Torvalds usb_serial_generic_read_bulk_callback), 1481da177e4SLinus Torvalds port); 1491da177e4SLinus Torvalds result = usb_submit_urb(port->read_urb, GFP_KERNEL); 1501da177e4SLinus Torvalds if (result) 151ae64387aSAlan Cox dev_err(&port->dev, 152ae64387aSAlan Cox "%s - failed resubmitting read urb, error %d\n", 153ae64387aSAlan Cox __func__, result); 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds return result; 1571da177e4SLinus Torvalds } 158815ddc99SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(usb_serial_generic_open); 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds static void generic_cleanup(struct usb_serial_port *port) 1611da177e4SLinus Torvalds { 1621da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 1631da177e4SLinus Torvalds 164441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds if (serial->dev) { 1671da177e4SLinus Torvalds /* shutdown any bulk reads that might be going on */ 1681da177e4SLinus Torvalds if (serial->num_bulk_out) 1691da177e4SLinus Torvalds usb_kill_urb(port->write_urb); 1701da177e4SLinus Torvalds if (serial->num_bulk_in) 1711da177e4SLinus Torvalds usb_kill_urb(port->read_urb); 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds 175ec22559eSOliver Neukum int usb_serial_generic_resume(struct usb_serial *serial) 176ec22559eSOliver Neukum { 177ec22559eSOliver Neukum struct usb_serial_port *port; 178ec22559eSOliver Neukum int i, c = 0, r; 179ec22559eSOliver Neukum 180f0fbd5b9SSarah Sharp #ifdef CONFIG_PM 181f0fbd5b9SSarah Sharp /* 182f0fbd5b9SSarah Sharp * If this is an autoresume, don't submit URBs. 183f0fbd5b9SSarah Sharp * They will be submitted in the open function instead. 184f0fbd5b9SSarah Sharp */ 185f0fbd5b9SSarah Sharp if (serial->dev->auto_pm) 186f0fbd5b9SSarah Sharp return 0; 187f0fbd5b9SSarah Sharp #endif 188ec22559eSOliver Neukum for (i = 0; i < serial->num_ports; i++) { 189ec22559eSOliver Neukum port = serial->port[i]; 19095da310eSAlan Cox if (port->port.count && port->read_urb) { 191ec22559eSOliver Neukum r = usb_submit_urb(port->read_urb, GFP_NOIO); 192ec22559eSOliver Neukum if (r < 0) 193ec22559eSOliver Neukum c++; 194ec22559eSOliver Neukum } 195ec22559eSOliver Neukum } 196ec22559eSOliver Neukum 197ec22559eSOliver Neukum return c ? -EIO : 0; 198ec22559eSOliver Neukum } 199ec22559eSOliver Neukum 20095da310eSAlan Cox void usb_serial_generic_close(struct tty_struct *tty, 20195da310eSAlan Cox struct usb_serial_port *port, struct file *filp) 2021da177e4SLinus Torvalds { 203441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 2041da177e4SLinus Torvalds generic_cleanup(port); 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds 20795da310eSAlan Cox int usb_serial_generic_write(struct tty_struct *tty, 20895da310eSAlan Cox struct usb_serial_port *port, const unsigned char *buf, int count) 2091da177e4SLinus Torvalds { 2101da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 2111da177e4SLinus Torvalds int result; 2121da177e4SLinus Torvalds unsigned char *data; 2131da177e4SLinus Torvalds 214441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds if (count == 0) { 217441b62c1SHarvey Harrison dbg("%s - write request of 0 bytes", __func__); 218ae64387aSAlan Cox return 0; 2191da177e4SLinus Torvalds } 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds /* only do something if we have a bulk out endpoint */ 2221da177e4SLinus Torvalds if (serial->num_bulk_out) { 223acd2a847SJiri Kosina unsigned long flags; 224acd2a847SJiri Kosina spin_lock_irqsave(&port->lock, flags); 225507ca9bcSGreg Kroah-Hartman if (port->write_urb_busy) { 226acd2a847SJiri Kosina spin_unlock_irqrestore(&port->lock, flags); 227441b62c1SHarvey Harrison dbg("%s - already writing", __func__); 228507ca9bcSGreg Kroah-Hartman return 0; 2291da177e4SLinus Torvalds } 230507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 1; 231acd2a847SJiri Kosina spin_unlock_irqrestore(&port->lock, flags); 2321da177e4SLinus Torvalds 233ae64387aSAlan Cox count = (count > port->bulk_out_size) ? 234ae64387aSAlan Cox port->bulk_out_size : count; 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds memcpy(port->write_urb->transfer_buffer, buf, count); 2371da177e4SLinus Torvalds data = port->write_urb->transfer_buffer; 238441b62c1SHarvey Harrison usb_serial_debug_data(debug, &port->dev, __func__, count, data); 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds /* set up our urb */ 2411da177e4SLinus Torvalds usb_fill_bulk_urb(port->write_urb, serial->dev, 2421da177e4SLinus Torvalds usb_sndbulkpipe(serial->dev, 2431da177e4SLinus Torvalds port->bulk_out_endpointAddress), 2441da177e4SLinus Torvalds port->write_urb->transfer_buffer, count, 2451da177e4SLinus Torvalds ((serial->type->write_bulk_callback) ? 2461da177e4SLinus Torvalds serial->type->write_bulk_callback : 247ae64387aSAlan Cox usb_serial_generic_write_bulk_callback), 248ae64387aSAlan Cox port); 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds /* send the data out the bulk port */ 251507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 1; 2521da177e4SLinus Torvalds result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 253507ca9bcSGreg Kroah-Hartman if (result) { 254ae64387aSAlan Cox dev_err(&port->dev, 255ae64387aSAlan Cox "%s - failed submitting write urb, error %d\n", 256ae64387aSAlan Cox __func__, result); 257ae64387aSAlan Cox /* don't have to grab the lock here, as we will 258ae64387aSAlan Cox retry if != 0 */ 259507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 0; 260507ca9bcSGreg Kroah-Hartman } else 2611da177e4SLinus Torvalds result = count; 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds return result; 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds /* no bulk out, so return 0 bytes written */ 267507ca9bcSGreg Kroah-Hartman return 0; 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds 27095da310eSAlan Cox int usb_serial_generic_write_room(struct tty_struct *tty) 2711da177e4SLinus Torvalds { 27295da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 2731da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 2741da177e4SLinus Torvalds int room = 0; 2751da177e4SLinus Torvalds 276441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 2771da177e4SLinus Torvalds 278a5b6f60cSAlan Cox /* FIXME: Locking */ 2791da177e4SLinus Torvalds if (serial->num_bulk_out) { 2807a3ca7d2SRandall Nortman if (!(port->write_urb_busy)) 2811da177e4SLinus Torvalds room = port->bulk_out_size; 2821da177e4SLinus Torvalds } 2831da177e4SLinus Torvalds 284441b62c1SHarvey Harrison dbg("%s - returns %d", __func__, room); 285a5b6f60cSAlan Cox return room; 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds 28895da310eSAlan Cox int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) 2891da177e4SLinus Torvalds { 29095da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 2911da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 2921da177e4SLinus Torvalds int chars = 0; 2931da177e4SLinus Torvalds 294441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 2951da177e4SLinus Torvalds 296a5b6f60cSAlan Cox /* FIXME: Locking */ 2971da177e4SLinus Torvalds if (serial->num_bulk_out) { 298507ca9bcSGreg Kroah-Hartman if (port->write_urb_busy) 2991da177e4SLinus Torvalds chars = port->write_urb->transfer_buffer_length; 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds 302441b62c1SHarvey Harrison dbg("%s - returns %d", __func__, chars); 30395da310eSAlan Cox return chars; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 3061abdeeb1SOliver Neukum 3071abdeeb1SOliver Neukum static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags) 3081da177e4SLinus Torvalds { 309253ca923SJoris van Rantwijk struct urb *urb = port->read_urb; 3101abdeeb1SOliver Neukum struct usb_serial *serial = port->serial; 3111da177e4SLinus Torvalds int result; 3121da177e4SLinus Torvalds 313253ca923SJoris van Rantwijk /* Continue reading from device */ 3141abdeeb1SOliver Neukum usb_fill_bulk_urb(urb, serial->dev, 3151da177e4SLinus Torvalds usb_rcvbulkpipe(serial->dev, 3161da177e4SLinus Torvalds port->bulk_in_endpointAddress), 3171abdeeb1SOliver Neukum urb->transfer_buffer, 3181abdeeb1SOliver Neukum urb->transfer_buffer_length, 3191da177e4SLinus Torvalds ((serial->type->read_bulk_callback) ? 3201da177e4SLinus Torvalds serial->type->read_bulk_callback : 3211da177e4SLinus Torvalds usb_serial_generic_read_bulk_callback), port); 3221abdeeb1SOliver Neukum result = usb_submit_urb(urb, mem_flags); 3231da177e4SLinus Torvalds if (result) 324ae64387aSAlan Cox dev_err(&port->dev, 325ae64387aSAlan Cox "%s - failed resubmitting read urb, error %d\n", 326ae64387aSAlan Cox __func__, result); 3271da177e4SLinus Torvalds } 328253ca923SJoris van Rantwijk 3291abdeeb1SOliver Neukum /* Push data to tty layer and resubmit the bulk read URB */ 3301abdeeb1SOliver Neukum static void flush_and_resubmit_read_urb(struct usb_serial_port *port) 3311abdeeb1SOliver Neukum { 3321abdeeb1SOliver Neukum struct urb *urb = port->read_urb; 3334a90f09bSAlan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 3341abdeeb1SOliver Neukum int room; 3351abdeeb1SOliver Neukum 3361abdeeb1SOliver Neukum /* Push data to tty */ 3371abdeeb1SOliver Neukum if (tty && urb->actual_length) { 3381abdeeb1SOliver Neukum room = tty_buffer_request_room(tty, urb->actual_length); 3391abdeeb1SOliver Neukum if (room) { 3401abdeeb1SOliver Neukum tty_insert_flip_string(tty, urb->transfer_buffer, room); 341b507cc97SPete Zaitcev tty_flip_buffer_push(tty); 3421abdeeb1SOliver Neukum } 3431abdeeb1SOliver Neukum } 3444a90f09bSAlan Cox tty_kref_put(tty); 3451abdeeb1SOliver Neukum 3461abdeeb1SOliver Neukum resubmit_read_urb(port, GFP_ATOMIC); 3471abdeeb1SOliver Neukum } 3481abdeeb1SOliver Neukum 349253ca923SJoris van Rantwijk void usb_serial_generic_read_bulk_callback(struct urb *urb) 350253ca923SJoris van Rantwijk { 351cdc97792SMing Lei struct usb_serial_port *port = urb->context; 352253ca923SJoris van Rantwijk unsigned char *data = urb->transfer_buffer; 353fbd27225SGreg Kroah-Hartman int status = urb->status; 354bfaeafcfSBorislav Petkov unsigned long flags; 355253ca923SJoris van Rantwijk 356441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 357253ca923SJoris van Rantwijk 358fbd27225SGreg Kroah-Hartman if (unlikely(status != 0)) { 359fbd27225SGreg Kroah-Hartman dbg("%s - nonzero read bulk status received: %d", 360441b62c1SHarvey Harrison __func__, status); 361253ca923SJoris van Rantwijk return; 362253ca923SJoris van Rantwijk } 363253ca923SJoris van Rantwijk 364ae64387aSAlan Cox usb_serial_debug_data(debug, &port->dev, __func__, 365ae64387aSAlan Cox urb->actual_length, data); 366253ca923SJoris van Rantwijk 367253ca923SJoris van Rantwijk /* Throttle the device if requested by tty */ 368bfaeafcfSBorislav Petkov spin_lock_irqsave(&port->lock, flags); 369ae64387aSAlan Cox port->throttled = port->throttle_req; 370ae64387aSAlan Cox if (!port->throttled) { 371bfaeafcfSBorislav Petkov spin_unlock_irqrestore(&port->lock, flags); 372b507cc97SPete Zaitcev flush_and_resubmit_read_urb(port); 373ae64387aSAlan Cox } else 374b507cc97SPete Zaitcev spin_unlock_irqrestore(&port->lock, flags); 375b507cc97SPete Zaitcev } 376166ffccfSLuiz Fernando N. Capitulino EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); 3771da177e4SLinus Torvalds 3787d12e780SDavid Howells void usb_serial_generic_write_bulk_callback(struct urb *urb) 3791da177e4SLinus Torvalds { 380cdc97792SMing Lei struct usb_serial_port *port = urb->context; 381fbd27225SGreg Kroah-Hartman int status = urb->status; 3821da177e4SLinus Torvalds 383441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 3841da177e4SLinus Torvalds 385507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 0; 386fbd27225SGreg Kroah-Hartman if (status) { 387fbd27225SGreg Kroah-Hartman dbg("%s - nonzero write bulk status received: %d", 388441b62c1SHarvey Harrison __func__, status); 3891da177e4SLinus Torvalds return; 3901da177e4SLinus Torvalds } 391cf2c7481SPete Zaitcev usb_serial_port_softint(port); 3921da177e4SLinus Torvalds } 393bb833986SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); 3941da177e4SLinus Torvalds 39595da310eSAlan Cox void usb_serial_generic_throttle(struct tty_struct *tty) 396253ca923SJoris van Rantwijk { 39795da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 398253ca923SJoris van Rantwijk unsigned long flags; 399253ca923SJoris van Rantwijk 400441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 401253ca923SJoris van Rantwijk 402253ca923SJoris van Rantwijk /* Set the throttle request flag. It will be picked up 403253ca923SJoris van Rantwijk * by usb_serial_generic_read_bulk_callback(). */ 404253ca923SJoris van Rantwijk spin_lock_irqsave(&port->lock, flags); 405253ca923SJoris van Rantwijk port->throttle_req = 1; 406253ca923SJoris van Rantwijk spin_unlock_irqrestore(&port->lock, flags); 407253ca923SJoris van Rantwijk } 408253ca923SJoris van Rantwijk 40995da310eSAlan Cox void usb_serial_generic_unthrottle(struct tty_struct *tty) 410253ca923SJoris van Rantwijk { 41195da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 412253ca923SJoris van Rantwijk int was_throttled; 413253ca923SJoris van Rantwijk unsigned long flags; 414253ca923SJoris van Rantwijk 415441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 416253ca923SJoris van Rantwijk 417253ca923SJoris van Rantwijk /* Clear the throttle flags */ 418253ca923SJoris van Rantwijk spin_lock_irqsave(&port->lock, flags); 419253ca923SJoris van Rantwijk was_throttled = port->throttled; 420253ca923SJoris van Rantwijk port->throttled = port->throttle_req = 0; 421253ca923SJoris van Rantwijk spin_unlock_irqrestore(&port->lock, flags); 422253ca923SJoris van Rantwijk 423253ca923SJoris van Rantwijk if (was_throttled) { 4241abdeeb1SOliver Neukum /* Resume reading from device */ 4251abdeeb1SOliver Neukum resubmit_read_urb(port, GFP_KERNEL); 426253ca923SJoris van Rantwijk } 427253ca923SJoris van Rantwijk } 428253ca923SJoris van Rantwijk 4291da177e4SLinus Torvalds void usb_serial_generic_shutdown(struct usb_serial *serial) 4301da177e4SLinus Torvalds { 4311da177e4SLinus Torvalds int i; 4321da177e4SLinus Torvalds 433441b62c1SHarvey Harrison dbg("%s", __func__); 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds /* stop reads and writes on all ports */ 436ae64387aSAlan Cox for (i = 0; i < serial->num_ports; ++i) 4371da177e4SLinus Torvalds generic_cleanup(serial->port[i]); 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds 440