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, 66f9c99bb8SAlan Stern .disconnect = usb_serial_generic_disconnect, 67f9c99bb8SAlan Stern .release = usb_serial_generic_release, 68253ca923SJoris van Rantwijk .throttle = usb_serial_generic_throttle, 69253ca923SJoris van Rantwijk .unthrottle = usb_serial_generic_unthrottle, 70ec22559eSOliver Neukum .resume = usb_serial_generic_resume, 711da177e4SLinus Torvalds }; 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds static int generic_probe(struct usb_interface *interface, 741da177e4SLinus Torvalds const struct usb_device_id *id) 751da177e4SLinus Torvalds { 761da177e4SLinus Torvalds const struct usb_device_id *id_pattern; 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds id_pattern = usb_match_id(interface, generic_device_ids); 791da177e4SLinus Torvalds if (id_pattern != NULL) 801da177e4SLinus Torvalds return usb_serial_probe(interface, id); 811da177e4SLinus Torvalds return -ENODEV; 821da177e4SLinus Torvalds } 831da177e4SLinus Torvalds #endif 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds int usb_serial_generic_register(int _debug) 861da177e4SLinus Torvalds { 871da177e4SLinus Torvalds int retval = 0; 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds debug = _debug; 901da177e4SLinus Torvalds #ifdef CONFIG_USB_SERIAL_GENERIC 911da177e4SLinus Torvalds generic_device_ids[0].idVendor = vendor; 921da177e4SLinus Torvalds generic_device_ids[0].idProduct = product; 93ae64387aSAlan Cox generic_device_ids[0].match_flags = 94ae64387aSAlan Cox USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds /* register our generic driver with ourselves */ 971da177e4SLinus Torvalds retval = usb_serial_register(&usb_serial_generic_device); 981da177e4SLinus Torvalds if (retval) 991da177e4SLinus Torvalds goto exit; 1001da177e4SLinus Torvalds retval = usb_register(&generic_driver); 1011da177e4SLinus Torvalds if (retval) 1021da177e4SLinus Torvalds usb_serial_deregister(&usb_serial_generic_device); 1031da177e4SLinus Torvalds exit: 1041da177e4SLinus Torvalds #endif 1051da177e4SLinus Torvalds return retval; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds void usb_serial_generic_deregister(void) 1091da177e4SLinus Torvalds { 1101da177e4SLinus Torvalds #ifdef CONFIG_USB_SERIAL_GENERIC 1111da177e4SLinus Torvalds /* remove our generic driver */ 1121da177e4SLinus Torvalds usb_deregister(&generic_driver); 1131da177e4SLinus Torvalds usb_serial_deregister(&usb_serial_generic_device); 1141da177e4SLinus Torvalds #endif 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds 11795da310eSAlan Cox int usb_serial_generic_open(struct tty_struct *tty, 11895da310eSAlan Cox struct usb_serial_port *port, struct file *filp) 1191da177e4SLinus Torvalds { 1201da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 1211da177e4SLinus Torvalds int result = 0; 122253ca923SJoris van Rantwijk unsigned long flags; 1231da177e4SLinus Torvalds 124441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 1251da177e4SLinus Torvalds 126253ca923SJoris van Rantwijk /* clear the throttle flags */ 127253ca923SJoris van Rantwijk spin_lock_irqsave(&port->lock, flags); 128253ca923SJoris van Rantwijk port->throttled = 0; 129253ca923SJoris van Rantwijk port->throttle_req = 0; 130253ca923SJoris van Rantwijk spin_unlock_irqrestore(&port->lock, flags); 131253ca923SJoris van Rantwijk 132253ca923SJoris van Rantwijk /* if we have a bulk endpoint, start reading from it */ 1331da177e4SLinus Torvalds if (serial->num_bulk_in) { 1341da177e4SLinus Torvalds /* Start reading from the device */ 1351da177e4SLinus Torvalds usb_fill_bulk_urb(port->read_urb, serial->dev, 136ae64387aSAlan Cox usb_rcvbulkpipe(serial->dev, 137ae64387aSAlan Cox port->bulk_in_endpointAddress), 1381da177e4SLinus Torvalds port->read_urb->transfer_buffer, 1391da177e4SLinus Torvalds port->read_urb->transfer_buffer_length, 1401da177e4SLinus Torvalds ((serial->type->read_bulk_callback) ? 1411da177e4SLinus Torvalds serial->type->read_bulk_callback : 1421da177e4SLinus Torvalds usb_serial_generic_read_bulk_callback), 1431da177e4SLinus Torvalds port); 1441da177e4SLinus Torvalds result = usb_submit_urb(port->read_urb, GFP_KERNEL); 1451da177e4SLinus Torvalds if (result) 146ae64387aSAlan Cox dev_err(&port->dev, 147ae64387aSAlan Cox "%s - failed resubmitting read urb, error %d\n", 148ae64387aSAlan Cox __func__, result); 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds return result; 1521da177e4SLinus Torvalds } 153815ddc99SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(usb_serial_generic_open); 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds static void generic_cleanup(struct usb_serial_port *port) 1561da177e4SLinus Torvalds { 1571da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 1581da177e4SLinus Torvalds 159441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds if (serial->dev) { 1621da177e4SLinus Torvalds /* shutdown any bulk reads that might be going on */ 1631da177e4SLinus Torvalds if (serial->num_bulk_out) 1641da177e4SLinus Torvalds usb_kill_urb(port->write_urb); 1651da177e4SLinus Torvalds if (serial->num_bulk_in) 1661da177e4SLinus Torvalds usb_kill_urb(port->read_urb); 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 170ec22559eSOliver Neukum int usb_serial_generic_resume(struct usb_serial *serial) 171ec22559eSOliver Neukum { 172ec22559eSOliver Neukum struct usb_serial_port *port; 173ec22559eSOliver Neukum int i, c = 0, r; 174ec22559eSOliver Neukum 175ec22559eSOliver Neukum for (i = 0; i < serial->num_ports; i++) { 176ec22559eSOliver Neukum port = serial->port[i]; 17795da310eSAlan Cox if (port->port.count && port->read_urb) { 178ec22559eSOliver Neukum r = usb_submit_urb(port->read_urb, GFP_NOIO); 179ec22559eSOliver Neukum if (r < 0) 180ec22559eSOliver Neukum c++; 181ec22559eSOliver Neukum } 182ec22559eSOliver Neukum } 183ec22559eSOliver Neukum 184ec22559eSOliver Neukum return c ? -EIO : 0; 185ec22559eSOliver Neukum } 18681d043c2SOliver Neukum EXPORT_SYMBOL_GPL(usb_serial_generic_resume); 187ec22559eSOliver Neukum 188335f8514SAlan Cox void usb_serial_generic_close(struct usb_serial_port *port) 1891da177e4SLinus Torvalds { 190441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 1911da177e4SLinus Torvalds generic_cleanup(port); 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds 194715b1dc0SJason Wessel static int usb_serial_multi_urb_write(struct tty_struct *tty, 195715b1dc0SJason Wessel struct usb_serial_port *port, const unsigned char *buf, int count) 196715b1dc0SJason Wessel { 197715b1dc0SJason Wessel unsigned long flags; 198715b1dc0SJason Wessel struct urb *urb; 199715b1dc0SJason Wessel unsigned char *buffer; 200715b1dc0SJason Wessel int status; 201715b1dc0SJason Wessel int towrite; 202715b1dc0SJason Wessel int bwrite = 0; 203715b1dc0SJason Wessel 204715b1dc0SJason Wessel dbg("%s - port %d", __func__, port->number); 205715b1dc0SJason Wessel 206715b1dc0SJason Wessel if (count == 0) 207715b1dc0SJason Wessel dbg("%s - write request of 0 bytes", __func__); 208715b1dc0SJason Wessel 209715b1dc0SJason Wessel while (count > 0) { 210715b1dc0SJason Wessel towrite = (count > port->bulk_out_size) ? 211715b1dc0SJason Wessel port->bulk_out_size : count; 212715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 213715b1dc0SJason Wessel if (port->urbs_in_flight > 214715b1dc0SJason Wessel port->serial->type->max_in_flight_urbs) { 215715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 216715b1dc0SJason Wessel dbg("%s - write limit hit\n", __func__); 217715b1dc0SJason Wessel return bwrite; 218715b1dc0SJason Wessel } 219715b1dc0SJason Wessel port->tx_bytes_flight += towrite; 220715b1dc0SJason Wessel port->urbs_in_flight++; 221715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 222715b1dc0SJason Wessel 223715b1dc0SJason Wessel buffer = kmalloc(towrite, GFP_ATOMIC); 224715b1dc0SJason Wessel if (!buffer) { 225715b1dc0SJason Wessel dev_err(&port->dev, 226715b1dc0SJason Wessel "%s ran out of kernel memory for urb ...\n", __func__); 227715b1dc0SJason Wessel goto error_no_buffer; 228715b1dc0SJason Wessel } 229715b1dc0SJason Wessel 230715b1dc0SJason Wessel urb = usb_alloc_urb(0, GFP_ATOMIC); 231715b1dc0SJason Wessel if (!urb) { 232715b1dc0SJason Wessel dev_err(&port->dev, "%s - no more free urbs\n", 233715b1dc0SJason Wessel __func__); 234715b1dc0SJason Wessel goto error_no_urb; 235715b1dc0SJason Wessel } 236715b1dc0SJason Wessel 237715b1dc0SJason Wessel /* Copy data */ 238715b1dc0SJason Wessel memcpy(buffer, buf + bwrite, towrite); 239715b1dc0SJason Wessel usb_serial_debug_data(debug, &port->dev, __func__, 240715b1dc0SJason Wessel towrite, buffer); 241715b1dc0SJason Wessel /* fill the buffer and send it */ 242715b1dc0SJason Wessel usb_fill_bulk_urb(urb, port->serial->dev, 243715b1dc0SJason Wessel usb_sndbulkpipe(port->serial->dev, 244715b1dc0SJason Wessel port->bulk_out_endpointAddress), 245715b1dc0SJason Wessel buffer, towrite, 246715b1dc0SJason Wessel usb_serial_generic_write_bulk_callback, port); 247715b1dc0SJason Wessel 248715b1dc0SJason Wessel status = usb_submit_urb(urb, GFP_ATOMIC); 249715b1dc0SJason Wessel if (status) { 250715b1dc0SJason Wessel dev_err(&port->dev, 251715b1dc0SJason Wessel "%s - failed submitting write urb, error %d\n", 252715b1dc0SJason Wessel __func__, status); 253715b1dc0SJason Wessel goto error; 254715b1dc0SJason Wessel } 255715b1dc0SJason Wessel 256715b1dc0SJason Wessel /* This urb is the responsibility of the host driver now */ 257715b1dc0SJason Wessel usb_free_urb(urb); 258715b1dc0SJason Wessel dbg("%s write: %d", __func__, towrite); 259715b1dc0SJason Wessel count -= towrite; 260715b1dc0SJason Wessel bwrite += towrite; 261715b1dc0SJason Wessel } 262715b1dc0SJason Wessel return bwrite; 263715b1dc0SJason Wessel 264715b1dc0SJason Wessel error: 265715b1dc0SJason Wessel usb_free_urb(urb); 266715b1dc0SJason Wessel error_no_urb: 267715b1dc0SJason Wessel kfree(buffer); 268715b1dc0SJason Wessel error_no_buffer: 269715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 270715b1dc0SJason Wessel port->urbs_in_flight--; 271715b1dc0SJason Wessel port->tx_bytes_flight -= towrite; 272715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 273715b1dc0SJason Wessel return bwrite; 274715b1dc0SJason Wessel } 275715b1dc0SJason Wessel 27695da310eSAlan Cox int usb_serial_generic_write(struct tty_struct *tty, 27795da310eSAlan Cox struct usb_serial_port *port, const unsigned char *buf, int count) 2781da177e4SLinus Torvalds { 2791da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 2801da177e4SLinus Torvalds int result; 2811da177e4SLinus Torvalds unsigned char *data; 2821da177e4SLinus Torvalds 283441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds if (count == 0) { 286441b62c1SHarvey Harrison dbg("%s - write request of 0 bytes", __func__); 287ae64387aSAlan Cox return 0; 2881da177e4SLinus Torvalds } 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds /* only do something if we have a bulk out endpoint */ 2911da177e4SLinus Torvalds if (serial->num_bulk_out) { 292acd2a847SJiri Kosina unsigned long flags; 293715b1dc0SJason Wessel 294715b1dc0SJason Wessel if (serial->type->max_in_flight_urbs) 295715b1dc0SJason Wessel return usb_serial_multi_urb_write(tty, port, 296715b1dc0SJason Wessel buf, count); 297715b1dc0SJason Wessel 298acd2a847SJiri Kosina spin_lock_irqsave(&port->lock, flags); 299507ca9bcSGreg Kroah-Hartman if (port->write_urb_busy) { 300acd2a847SJiri Kosina spin_unlock_irqrestore(&port->lock, flags); 301441b62c1SHarvey Harrison dbg("%s - already writing", __func__); 302507ca9bcSGreg Kroah-Hartman return 0; 3031da177e4SLinus Torvalds } 304507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 1; 305acd2a847SJiri Kosina spin_unlock_irqrestore(&port->lock, flags); 3061da177e4SLinus Torvalds 307ae64387aSAlan Cox count = (count > port->bulk_out_size) ? 308ae64387aSAlan Cox port->bulk_out_size : count; 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds memcpy(port->write_urb->transfer_buffer, buf, count); 3111da177e4SLinus Torvalds data = port->write_urb->transfer_buffer; 312441b62c1SHarvey Harrison usb_serial_debug_data(debug, &port->dev, __func__, count, data); 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds /* set up our urb */ 3151da177e4SLinus Torvalds usb_fill_bulk_urb(port->write_urb, serial->dev, 3161da177e4SLinus Torvalds usb_sndbulkpipe(serial->dev, 3171da177e4SLinus Torvalds port->bulk_out_endpointAddress), 3181da177e4SLinus Torvalds port->write_urb->transfer_buffer, count, 3191da177e4SLinus Torvalds ((serial->type->write_bulk_callback) ? 3201da177e4SLinus Torvalds serial->type->write_bulk_callback : 321ae64387aSAlan Cox usb_serial_generic_write_bulk_callback), 322ae64387aSAlan Cox port); 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds /* send the data out the bulk port */ 325507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 1; 3261da177e4SLinus Torvalds result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 327507ca9bcSGreg Kroah-Hartman if (result) { 328ae64387aSAlan Cox dev_err(&port->dev, 329ae64387aSAlan Cox "%s - failed submitting write urb, error %d\n", 330ae64387aSAlan Cox __func__, result); 331ae64387aSAlan Cox /* don't have to grab the lock here, as we will 332ae64387aSAlan Cox retry if != 0 */ 333507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 0; 334507ca9bcSGreg Kroah-Hartman } else 3351da177e4SLinus Torvalds result = count; 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds return result; 3381da177e4SLinus Torvalds } 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds /* no bulk out, so return 0 bytes written */ 341507ca9bcSGreg Kroah-Hartman return 0; 3421da177e4SLinus Torvalds } 34398fcb5f7SJason Wessel EXPORT_SYMBOL_GPL(usb_serial_generic_write); 3441da177e4SLinus Torvalds 34595da310eSAlan Cox int usb_serial_generic_write_room(struct tty_struct *tty) 3461da177e4SLinus Torvalds { 34795da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 3481da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 349715b1dc0SJason Wessel unsigned long flags; 3501da177e4SLinus Torvalds int room = 0; 3511da177e4SLinus Torvalds 352441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 353715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 354715b1dc0SJason Wessel if (serial->type->max_in_flight_urbs) { 355715b1dc0SJason Wessel if (port->urbs_in_flight < serial->type->max_in_flight_urbs) 35698fcb5f7SJason Wessel room = port->bulk_out_size * 35798fcb5f7SJason Wessel (serial->type->max_in_flight_urbs - 35898fcb5f7SJason Wessel port->urbs_in_flight); 359715b1dc0SJason Wessel } else if (serial->num_bulk_out && !(port->write_urb_busy)) { 3601da177e4SLinus Torvalds room = port->bulk_out_size; 3611da177e4SLinus Torvalds } 362715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 3631da177e4SLinus Torvalds 364441b62c1SHarvey Harrison dbg("%s - returns %d", __func__, room); 365a5b6f60cSAlan Cox return room; 3661da177e4SLinus Torvalds } 3671da177e4SLinus Torvalds 36895da310eSAlan Cox int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) 3691da177e4SLinus Torvalds { 37095da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 3711da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 3721da177e4SLinus Torvalds int chars = 0; 373715b1dc0SJason Wessel unsigned long flags; 3741da177e4SLinus Torvalds 375441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 3761da177e4SLinus Torvalds 377715b1dc0SJason Wessel if (serial->type->max_in_flight_urbs) { 378715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 379715b1dc0SJason Wessel chars = port->tx_bytes_flight; 380715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 381715b1dc0SJason Wessel } else if (serial->num_bulk_out) { 382a5b6f60cSAlan Cox /* FIXME: Locking */ 383507ca9bcSGreg Kroah-Hartman if (port->write_urb_busy) 3841da177e4SLinus Torvalds chars = port->write_urb->transfer_buffer_length; 3851da177e4SLinus Torvalds } 3861da177e4SLinus Torvalds 387441b62c1SHarvey Harrison dbg("%s - returns %d", __func__, chars); 38895da310eSAlan Cox return chars; 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds 3911abdeeb1SOliver Neukum 39298fcb5f7SJason Wessel void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port, 39398fcb5f7SJason Wessel gfp_t mem_flags) 3941da177e4SLinus Torvalds { 395253ca923SJoris van Rantwijk struct urb *urb = port->read_urb; 3961abdeeb1SOliver Neukum struct usb_serial *serial = port->serial; 3971da177e4SLinus Torvalds int result; 3981da177e4SLinus Torvalds 399253ca923SJoris van Rantwijk /* Continue reading from device */ 4001abdeeb1SOliver Neukum usb_fill_bulk_urb(urb, serial->dev, 4011da177e4SLinus Torvalds usb_rcvbulkpipe(serial->dev, 4021da177e4SLinus Torvalds port->bulk_in_endpointAddress), 4031abdeeb1SOliver Neukum urb->transfer_buffer, 4041abdeeb1SOliver Neukum urb->transfer_buffer_length, 4051da177e4SLinus Torvalds ((serial->type->read_bulk_callback) ? 4061da177e4SLinus Torvalds serial->type->read_bulk_callback : 4071da177e4SLinus Torvalds usb_serial_generic_read_bulk_callback), port); 4081abdeeb1SOliver Neukum result = usb_submit_urb(urb, mem_flags); 4091da177e4SLinus Torvalds if (result) 410ae64387aSAlan Cox dev_err(&port->dev, 411ae64387aSAlan Cox "%s - failed resubmitting read urb, error %d\n", 412ae64387aSAlan Cox __func__, result); 4131da177e4SLinus Torvalds } 41498fcb5f7SJason Wessel EXPORT_SYMBOL_GPL(usb_serial_generic_resubmit_read_urb); 415253ca923SJoris van Rantwijk 4161abdeeb1SOliver Neukum /* Push data to tty layer and resubmit the bulk read URB */ 4171abdeeb1SOliver Neukum static void flush_and_resubmit_read_urb(struct usb_serial_port *port) 4181abdeeb1SOliver Neukum { 4191abdeeb1SOliver Neukum struct urb *urb = port->read_urb; 4204a90f09bSAlan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 42198fcb5f7SJason Wessel char *ch = (char *)urb->transfer_buffer; 42298fcb5f7SJason Wessel int i; 42398fcb5f7SJason Wessel 42498fcb5f7SJason Wessel if (!tty) 42598fcb5f7SJason Wessel goto done; 4261abdeeb1SOliver Neukum 4274cd1de0aSAlan Cox /* The per character mucking around with sysrq path it too slow for 4284cd1de0aSAlan Cox stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases 4294cd1de0aSAlan Cox where the USB serial is not a console anyway */ 4304cd1de0aSAlan Cox if (!port->console || !port->sysrq) 4314cd1de0aSAlan Cox tty_insert_flip_string(tty, ch, urb->actual_length); 4324cd1de0aSAlan Cox else { 4331abdeeb1SOliver Neukum /* Push data to tty */ 43498fcb5f7SJason Wessel for (i = 0; i < urb->actual_length; i++, ch++) { 43598fcb5f7SJason Wessel if (!usb_serial_handle_sysrq_char(port, *ch)) 43698fcb5f7SJason Wessel tty_insert_flip_char(tty, *ch, TTY_NORMAL); 43798fcb5f7SJason Wessel } 4384cd1de0aSAlan Cox } 439b507cc97SPete Zaitcev tty_flip_buffer_push(tty); 4404a90f09bSAlan Cox tty_kref_put(tty); 44198fcb5f7SJason Wessel done: 44298fcb5f7SJason Wessel usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC); 4431abdeeb1SOliver Neukum } 4441abdeeb1SOliver Neukum 445253ca923SJoris van Rantwijk void usb_serial_generic_read_bulk_callback(struct urb *urb) 446253ca923SJoris van Rantwijk { 447cdc97792SMing Lei struct usb_serial_port *port = urb->context; 448253ca923SJoris van Rantwijk unsigned char *data = urb->transfer_buffer; 449fbd27225SGreg Kroah-Hartman int status = urb->status; 450bfaeafcfSBorislav Petkov unsigned long flags; 451253ca923SJoris van Rantwijk 452441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 453253ca923SJoris van Rantwijk 454fbd27225SGreg Kroah-Hartman if (unlikely(status != 0)) { 455fbd27225SGreg Kroah-Hartman dbg("%s - nonzero read bulk status received: %d", 456441b62c1SHarvey Harrison __func__, status); 457253ca923SJoris van Rantwijk return; 458253ca923SJoris van Rantwijk } 459253ca923SJoris van Rantwijk 460ae64387aSAlan Cox usb_serial_debug_data(debug, &port->dev, __func__, 461ae64387aSAlan Cox urb->actual_length, data); 462253ca923SJoris van Rantwijk 463253ca923SJoris van Rantwijk /* Throttle the device if requested by tty */ 464bfaeafcfSBorislav Petkov spin_lock_irqsave(&port->lock, flags); 465ae64387aSAlan Cox port->throttled = port->throttle_req; 466ae64387aSAlan Cox if (!port->throttled) { 467bfaeafcfSBorislav Petkov spin_unlock_irqrestore(&port->lock, flags); 468b507cc97SPete Zaitcev flush_and_resubmit_read_urb(port); 469ae64387aSAlan Cox } else 470b507cc97SPete Zaitcev spin_unlock_irqrestore(&port->lock, flags); 471b507cc97SPete Zaitcev } 472166ffccfSLuiz Fernando N. Capitulino EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); 4731da177e4SLinus Torvalds 4747d12e780SDavid Howells void usb_serial_generic_write_bulk_callback(struct urb *urb) 4751da177e4SLinus Torvalds { 476715b1dc0SJason Wessel unsigned long flags; 477cdc97792SMing Lei struct usb_serial_port *port = urb->context; 478fbd27225SGreg Kroah-Hartman int status = urb->status; 4791da177e4SLinus Torvalds 480441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 4811da177e4SLinus Torvalds 482715b1dc0SJason Wessel if (port->serial->type->max_in_flight_urbs) { 483715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 484715b1dc0SJason Wessel --port->urbs_in_flight; 485715b1dc0SJason Wessel port->tx_bytes_flight -= urb->transfer_buffer_length; 486715b1dc0SJason Wessel if (port->urbs_in_flight < 0) 487715b1dc0SJason Wessel port->urbs_in_flight = 0; 488715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 489715b1dc0SJason Wessel } else { 490715b1dc0SJason Wessel /* Handle the case for single urb mode */ 491507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 0; 492715b1dc0SJason Wessel } 493715b1dc0SJason Wessel 494fbd27225SGreg Kroah-Hartman if (status) { 495fbd27225SGreg Kroah-Hartman dbg("%s - nonzero write bulk status received: %d", 496441b62c1SHarvey Harrison __func__, status); 4971da177e4SLinus Torvalds return; 4981da177e4SLinus Torvalds } 499cf2c7481SPete Zaitcev usb_serial_port_softint(port); 5001da177e4SLinus Torvalds } 501bb833986SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); 5021da177e4SLinus Torvalds 50395da310eSAlan Cox void usb_serial_generic_throttle(struct tty_struct *tty) 504253ca923SJoris van Rantwijk { 50595da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 506253ca923SJoris van Rantwijk unsigned long flags; 507253ca923SJoris van Rantwijk 508441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 509253ca923SJoris van Rantwijk 510253ca923SJoris van Rantwijk /* Set the throttle request flag. It will be picked up 511253ca923SJoris van Rantwijk * by usb_serial_generic_read_bulk_callback(). */ 512253ca923SJoris van Rantwijk spin_lock_irqsave(&port->lock, flags); 513253ca923SJoris van Rantwijk port->throttle_req = 1; 514253ca923SJoris van Rantwijk spin_unlock_irqrestore(&port->lock, flags); 515253ca923SJoris van Rantwijk } 516253ca923SJoris van Rantwijk 51795da310eSAlan Cox void usb_serial_generic_unthrottle(struct tty_struct *tty) 518253ca923SJoris van Rantwijk { 51995da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 520253ca923SJoris van Rantwijk int was_throttled; 521253ca923SJoris van Rantwijk unsigned long flags; 522253ca923SJoris van Rantwijk 523441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 524253ca923SJoris van Rantwijk 525253ca923SJoris van Rantwijk /* Clear the throttle flags */ 526253ca923SJoris van Rantwijk spin_lock_irqsave(&port->lock, flags); 527253ca923SJoris van Rantwijk was_throttled = port->throttled; 528253ca923SJoris van Rantwijk port->throttled = port->throttle_req = 0; 529253ca923SJoris van Rantwijk spin_unlock_irqrestore(&port->lock, flags); 530253ca923SJoris van Rantwijk 531253ca923SJoris van Rantwijk if (was_throttled) { 5321abdeeb1SOliver Neukum /* Resume reading from device */ 53398fcb5f7SJason Wessel usb_serial_generic_resubmit_read_urb(port, GFP_KERNEL); 534253ca923SJoris van Rantwijk } 535253ca923SJoris van Rantwijk } 536253ca923SJoris van Rantwijk 53798fcb5f7SJason Wessel int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) 53898fcb5f7SJason Wessel { 539568d422eSJason Wessel if (port->sysrq && port->console) { 54098fcb5f7SJason Wessel if (ch && time_before(jiffies, port->sysrq)) { 54198fcb5f7SJason Wessel handle_sysrq(ch, tty_port_tty_get(&port->port)); 54298fcb5f7SJason Wessel port->sysrq = 0; 54398fcb5f7SJason Wessel return 1; 54498fcb5f7SJason Wessel } 54598fcb5f7SJason Wessel port->sysrq = 0; 54698fcb5f7SJason Wessel } 54798fcb5f7SJason Wessel return 0; 54898fcb5f7SJason Wessel } 54998fcb5f7SJason Wessel EXPORT_SYMBOL_GPL(usb_serial_handle_sysrq_char); 55098fcb5f7SJason Wessel 55198fcb5f7SJason Wessel int usb_serial_handle_break(struct usb_serial_port *port) 55298fcb5f7SJason Wessel { 55398fcb5f7SJason Wessel if (!port->sysrq) { 55498fcb5f7SJason Wessel port->sysrq = jiffies + HZ*5; 55598fcb5f7SJason Wessel return 1; 55698fcb5f7SJason Wessel } 55798fcb5f7SJason Wessel port->sysrq = 0; 55898fcb5f7SJason Wessel return 0; 55998fcb5f7SJason Wessel } 56098fcb5f7SJason Wessel EXPORT_SYMBOL_GPL(usb_serial_handle_break); 56198fcb5f7SJason Wessel 562f9c99bb8SAlan Stern void usb_serial_generic_disconnect(struct usb_serial *serial) 5631da177e4SLinus Torvalds { 5641da177e4SLinus Torvalds int i; 5651da177e4SLinus Torvalds 566441b62c1SHarvey Harrison dbg("%s", __func__); 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds /* stop reads and writes on all ports */ 569ae64387aSAlan Cox for (i = 0; i < serial->num_ports; ++i) 5701da177e4SLinus Torvalds generic_cleanup(serial->port[i]); 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds 573f9c99bb8SAlan Stern void usb_serial_generic_release(struct usb_serial *serial) 574f9c99bb8SAlan Stern { 575f9c99bb8SAlan Stern dbg("%s", __func__); 576f9c99bb8SAlan Stern } 577