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 193715b1dc0SJason Wessel static int usb_serial_multi_urb_write(struct tty_struct *tty, 194715b1dc0SJason Wessel struct usb_serial_port *port, const unsigned char *buf, int count) 195715b1dc0SJason Wessel { 196715b1dc0SJason Wessel unsigned long flags; 197715b1dc0SJason Wessel struct urb *urb; 198715b1dc0SJason Wessel unsigned char *buffer; 199715b1dc0SJason Wessel int status; 200715b1dc0SJason Wessel int towrite; 201715b1dc0SJason Wessel int bwrite = 0; 202715b1dc0SJason Wessel 203715b1dc0SJason Wessel dbg("%s - port %d", __func__, port->number); 204715b1dc0SJason Wessel 205715b1dc0SJason Wessel if (count == 0) 206715b1dc0SJason Wessel dbg("%s - write request of 0 bytes", __func__); 207715b1dc0SJason Wessel 208715b1dc0SJason Wessel while (count > 0) { 209715b1dc0SJason Wessel towrite = (count > port->bulk_out_size) ? 210715b1dc0SJason Wessel port->bulk_out_size : count; 211715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 212715b1dc0SJason Wessel if (port->urbs_in_flight > 213715b1dc0SJason Wessel port->serial->type->max_in_flight_urbs) { 214715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 215715b1dc0SJason Wessel dbg("%s - write limit hit\n", __func__); 216715b1dc0SJason Wessel return bwrite; 217715b1dc0SJason Wessel } 218715b1dc0SJason Wessel port->tx_bytes_flight += towrite; 219715b1dc0SJason Wessel port->urbs_in_flight++; 220715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 221715b1dc0SJason Wessel 222715b1dc0SJason Wessel buffer = kmalloc(towrite, GFP_ATOMIC); 223715b1dc0SJason Wessel if (!buffer) { 224715b1dc0SJason Wessel dev_err(&port->dev, 225715b1dc0SJason Wessel "%s ran out of kernel memory for urb ...\n", __func__); 226715b1dc0SJason Wessel goto error_no_buffer; 227715b1dc0SJason Wessel } 228715b1dc0SJason Wessel 229715b1dc0SJason Wessel urb = usb_alloc_urb(0, GFP_ATOMIC); 230715b1dc0SJason Wessel if (!urb) { 231715b1dc0SJason Wessel dev_err(&port->dev, "%s - no more free urbs\n", 232715b1dc0SJason Wessel __func__); 233715b1dc0SJason Wessel goto error_no_urb; 234715b1dc0SJason Wessel } 235715b1dc0SJason Wessel 236715b1dc0SJason Wessel /* Copy data */ 237715b1dc0SJason Wessel memcpy(buffer, buf + bwrite, towrite); 238715b1dc0SJason Wessel usb_serial_debug_data(debug, &port->dev, __func__, 239715b1dc0SJason Wessel towrite, buffer); 240715b1dc0SJason Wessel /* fill the buffer and send it */ 241715b1dc0SJason Wessel usb_fill_bulk_urb(urb, port->serial->dev, 242715b1dc0SJason Wessel usb_sndbulkpipe(port->serial->dev, 243715b1dc0SJason Wessel port->bulk_out_endpointAddress), 244715b1dc0SJason Wessel buffer, towrite, 245715b1dc0SJason Wessel usb_serial_generic_write_bulk_callback, port); 246715b1dc0SJason Wessel 247715b1dc0SJason Wessel status = usb_submit_urb(urb, GFP_ATOMIC); 248715b1dc0SJason Wessel if (status) { 249715b1dc0SJason Wessel dev_err(&port->dev, 250715b1dc0SJason Wessel "%s - failed submitting write urb, error %d\n", 251715b1dc0SJason Wessel __func__, status); 252715b1dc0SJason Wessel goto error; 253715b1dc0SJason Wessel } 254715b1dc0SJason Wessel 255715b1dc0SJason Wessel /* This urb is the responsibility of the host driver now */ 256715b1dc0SJason Wessel usb_free_urb(urb); 257715b1dc0SJason Wessel dbg("%s write: %d", __func__, towrite); 258715b1dc0SJason Wessel count -= towrite; 259715b1dc0SJason Wessel bwrite += towrite; 260715b1dc0SJason Wessel } 261715b1dc0SJason Wessel return bwrite; 262715b1dc0SJason Wessel 263715b1dc0SJason Wessel error: 264715b1dc0SJason Wessel usb_free_urb(urb); 265715b1dc0SJason Wessel error_no_urb: 266715b1dc0SJason Wessel kfree(buffer); 267715b1dc0SJason Wessel error_no_buffer: 268715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 269715b1dc0SJason Wessel port->urbs_in_flight--; 270715b1dc0SJason Wessel port->tx_bytes_flight -= towrite; 271715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 272715b1dc0SJason Wessel return bwrite; 273715b1dc0SJason Wessel } 274715b1dc0SJason Wessel 27595da310eSAlan Cox int usb_serial_generic_write(struct tty_struct *tty, 27695da310eSAlan Cox struct usb_serial_port *port, const unsigned char *buf, int count) 2771da177e4SLinus Torvalds { 2781da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 2791da177e4SLinus Torvalds int result; 2801da177e4SLinus Torvalds unsigned char *data; 2811da177e4SLinus Torvalds 282441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds if (count == 0) { 285441b62c1SHarvey Harrison dbg("%s - write request of 0 bytes", __func__); 286ae64387aSAlan Cox return 0; 2871da177e4SLinus Torvalds } 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds /* only do something if we have a bulk out endpoint */ 2901da177e4SLinus Torvalds if (serial->num_bulk_out) { 291acd2a847SJiri Kosina unsigned long flags; 292715b1dc0SJason Wessel 293715b1dc0SJason Wessel if (serial->type->max_in_flight_urbs) 294715b1dc0SJason Wessel return usb_serial_multi_urb_write(tty, port, 295715b1dc0SJason Wessel buf, count); 296715b1dc0SJason Wessel 297acd2a847SJiri Kosina spin_lock_irqsave(&port->lock, flags); 298507ca9bcSGreg Kroah-Hartman if (port->write_urb_busy) { 299acd2a847SJiri Kosina spin_unlock_irqrestore(&port->lock, flags); 300441b62c1SHarvey Harrison dbg("%s - already writing", __func__); 301507ca9bcSGreg Kroah-Hartman return 0; 3021da177e4SLinus Torvalds } 303507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 1; 304acd2a847SJiri Kosina spin_unlock_irqrestore(&port->lock, flags); 3051da177e4SLinus Torvalds 306ae64387aSAlan Cox count = (count > port->bulk_out_size) ? 307ae64387aSAlan Cox port->bulk_out_size : count; 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds memcpy(port->write_urb->transfer_buffer, buf, count); 3101da177e4SLinus Torvalds data = port->write_urb->transfer_buffer; 311441b62c1SHarvey Harrison usb_serial_debug_data(debug, &port->dev, __func__, count, data); 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds /* set up our urb */ 3141da177e4SLinus Torvalds usb_fill_bulk_urb(port->write_urb, serial->dev, 3151da177e4SLinus Torvalds usb_sndbulkpipe(serial->dev, 3161da177e4SLinus Torvalds port->bulk_out_endpointAddress), 3171da177e4SLinus Torvalds port->write_urb->transfer_buffer, count, 3181da177e4SLinus Torvalds ((serial->type->write_bulk_callback) ? 3191da177e4SLinus Torvalds serial->type->write_bulk_callback : 320ae64387aSAlan Cox usb_serial_generic_write_bulk_callback), 321ae64387aSAlan Cox port); 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds /* send the data out the bulk port */ 324507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 1; 3251da177e4SLinus Torvalds result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 326507ca9bcSGreg Kroah-Hartman if (result) { 327ae64387aSAlan Cox dev_err(&port->dev, 328ae64387aSAlan Cox "%s - failed submitting write urb, error %d\n", 329ae64387aSAlan Cox __func__, result); 330ae64387aSAlan Cox /* don't have to grab the lock here, as we will 331ae64387aSAlan Cox retry if != 0 */ 332507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 0; 333507ca9bcSGreg Kroah-Hartman } else 3341da177e4SLinus Torvalds result = count; 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds return result; 3371da177e4SLinus Torvalds } 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds /* no bulk out, so return 0 bytes written */ 340507ca9bcSGreg Kroah-Hartman return 0; 3411da177e4SLinus Torvalds } 34298fcb5f7SJason Wessel EXPORT_SYMBOL_GPL(usb_serial_generic_write); 3431da177e4SLinus Torvalds 34495da310eSAlan Cox int usb_serial_generic_write_room(struct tty_struct *tty) 3451da177e4SLinus Torvalds { 34695da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 3471da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 348715b1dc0SJason Wessel unsigned long flags; 3491da177e4SLinus Torvalds int room = 0; 3501da177e4SLinus Torvalds 351441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 352715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 353715b1dc0SJason Wessel if (serial->type->max_in_flight_urbs) { 354715b1dc0SJason Wessel if (port->urbs_in_flight < serial->type->max_in_flight_urbs) 35598fcb5f7SJason Wessel room = port->bulk_out_size * 35698fcb5f7SJason Wessel (serial->type->max_in_flight_urbs - 35798fcb5f7SJason Wessel port->urbs_in_flight); 358715b1dc0SJason Wessel } else if (serial->num_bulk_out && !(port->write_urb_busy)) { 3591da177e4SLinus Torvalds room = port->bulk_out_size; 3601da177e4SLinus Torvalds } 361715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 3621da177e4SLinus Torvalds 363441b62c1SHarvey Harrison dbg("%s - returns %d", __func__, room); 364a5b6f60cSAlan Cox return room; 3651da177e4SLinus Torvalds } 3661da177e4SLinus Torvalds 36795da310eSAlan Cox int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) 3681da177e4SLinus Torvalds { 36995da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 3701da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 3711da177e4SLinus Torvalds int chars = 0; 372715b1dc0SJason Wessel unsigned long flags; 3731da177e4SLinus Torvalds 374441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 3751da177e4SLinus Torvalds 376715b1dc0SJason Wessel if (serial->type->max_in_flight_urbs) { 377715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 378715b1dc0SJason Wessel chars = port->tx_bytes_flight; 379715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 380715b1dc0SJason Wessel } else if (serial->num_bulk_out) { 381a5b6f60cSAlan Cox /* FIXME: Locking */ 382507ca9bcSGreg Kroah-Hartman if (port->write_urb_busy) 3831da177e4SLinus Torvalds chars = port->write_urb->transfer_buffer_length; 3841da177e4SLinus Torvalds } 3851da177e4SLinus Torvalds 386441b62c1SHarvey Harrison dbg("%s - returns %d", __func__, chars); 38795da310eSAlan Cox return chars; 3881da177e4SLinus Torvalds } 3891da177e4SLinus Torvalds 3901abdeeb1SOliver Neukum 39198fcb5f7SJason Wessel void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port, 39298fcb5f7SJason Wessel gfp_t mem_flags) 3931da177e4SLinus Torvalds { 394253ca923SJoris van Rantwijk struct urb *urb = port->read_urb; 3951abdeeb1SOliver Neukum struct usb_serial *serial = port->serial; 3961da177e4SLinus Torvalds int result; 3971da177e4SLinus Torvalds 398253ca923SJoris van Rantwijk /* Continue reading from device */ 3991abdeeb1SOliver Neukum usb_fill_bulk_urb(urb, serial->dev, 4001da177e4SLinus Torvalds usb_rcvbulkpipe(serial->dev, 4011da177e4SLinus Torvalds port->bulk_in_endpointAddress), 4021abdeeb1SOliver Neukum urb->transfer_buffer, 4031abdeeb1SOliver Neukum urb->transfer_buffer_length, 4041da177e4SLinus Torvalds ((serial->type->read_bulk_callback) ? 4051da177e4SLinus Torvalds serial->type->read_bulk_callback : 4061da177e4SLinus Torvalds usb_serial_generic_read_bulk_callback), port); 4071abdeeb1SOliver Neukum result = usb_submit_urb(urb, mem_flags); 4081da177e4SLinus Torvalds if (result) 409ae64387aSAlan Cox dev_err(&port->dev, 410ae64387aSAlan Cox "%s - failed resubmitting read urb, error %d\n", 411ae64387aSAlan Cox __func__, result); 4121da177e4SLinus Torvalds } 41398fcb5f7SJason Wessel EXPORT_SYMBOL_GPL(usb_serial_generic_resubmit_read_urb); 414253ca923SJoris van Rantwijk 4151abdeeb1SOliver Neukum /* Push data to tty layer and resubmit the bulk read URB */ 4161abdeeb1SOliver Neukum static void flush_and_resubmit_read_urb(struct usb_serial_port *port) 4171abdeeb1SOliver Neukum { 4181abdeeb1SOliver Neukum struct urb *urb = port->read_urb; 4194a90f09bSAlan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 42098fcb5f7SJason Wessel char *ch = (char *)urb->transfer_buffer; 42198fcb5f7SJason Wessel int i; 42298fcb5f7SJason Wessel 42398fcb5f7SJason Wessel if (!tty) 42498fcb5f7SJason Wessel goto done; 4251abdeeb1SOliver Neukum 4261abdeeb1SOliver Neukum /* Push data to tty */ 42798fcb5f7SJason Wessel for (i = 0; i < urb->actual_length; i++, ch++) { 42898fcb5f7SJason Wessel if (!usb_serial_handle_sysrq_char(port, *ch)) 42998fcb5f7SJason Wessel tty_insert_flip_char(tty, *ch, TTY_NORMAL); 43098fcb5f7SJason Wessel } 431b507cc97SPete Zaitcev tty_flip_buffer_push(tty); 4324a90f09bSAlan Cox tty_kref_put(tty); 43398fcb5f7SJason Wessel done: 43498fcb5f7SJason Wessel usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC); 4351abdeeb1SOliver Neukum } 4361abdeeb1SOliver Neukum 437253ca923SJoris van Rantwijk void usb_serial_generic_read_bulk_callback(struct urb *urb) 438253ca923SJoris van Rantwijk { 439cdc97792SMing Lei struct usb_serial_port *port = urb->context; 440253ca923SJoris van Rantwijk unsigned char *data = urb->transfer_buffer; 441fbd27225SGreg Kroah-Hartman int status = urb->status; 442bfaeafcfSBorislav Petkov unsigned long flags; 443253ca923SJoris van Rantwijk 444441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 445253ca923SJoris van Rantwijk 446fbd27225SGreg Kroah-Hartman if (unlikely(status != 0)) { 447fbd27225SGreg Kroah-Hartman dbg("%s - nonzero read bulk status received: %d", 448441b62c1SHarvey Harrison __func__, status); 449253ca923SJoris van Rantwijk return; 450253ca923SJoris van Rantwijk } 451253ca923SJoris van Rantwijk 452ae64387aSAlan Cox usb_serial_debug_data(debug, &port->dev, __func__, 453ae64387aSAlan Cox urb->actual_length, data); 454253ca923SJoris van Rantwijk 455253ca923SJoris van Rantwijk /* Throttle the device if requested by tty */ 456bfaeafcfSBorislav Petkov spin_lock_irqsave(&port->lock, flags); 457ae64387aSAlan Cox port->throttled = port->throttle_req; 458ae64387aSAlan Cox if (!port->throttled) { 459bfaeafcfSBorislav Petkov spin_unlock_irqrestore(&port->lock, flags); 460b507cc97SPete Zaitcev flush_and_resubmit_read_urb(port); 461ae64387aSAlan Cox } else 462b507cc97SPete Zaitcev spin_unlock_irqrestore(&port->lock, flags); 463b507cc97SPete Zaitcev } 464166ffccfSLuiz Fernando N. Capitulino EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); 4651da177e4SLinus Torvalds 4667d12e780SDavid Howells void usb_serial_generic_write_bulk_callback(struct urb *urb) 4671da177e4SLinus Torvalds { 468715b1dc0SJason Wessel unsigned long flags; 469cdc97792SMing Lei struct usb_serial_port *port = urb->context; 470fbd27225SGreg Kroah-Hartman int status = urb->status; 4711da177e4SLinus Torvalds 472441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 4731da177e4SLinus Torvalds 474715b1dc0SJason Wessel if (port->serial->type->max_in_flight_urbs) { 475715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 476715b1dc0SJason Wessel --port->urbs_in_flight; 477715b1dc0SJason Wessel port->tx_bytes_flight -= urb->transfer_buffer_length; 478715b1dc0SJason Wessel if (port->urbs_in_flight < 0) 479715b1dc0SJason Wessel port->urbs_in_flight = 0; 480715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 481715b1dc0SJason Wessel } else { 482715b1dc0SJason Wessel /* Handle the case for single urb mode */ 483507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 0; 484715b1dc0SJason Wessel } 485715b1dc0SJason Wessel 486fbd27225SGreg Kroah-Hartman if (status) { 487fbd27225SGreg Kroah-Hartman dbg("%s - nonzero write bulk status received: %d", 488441b62c1SHarvey Harrison __func__, status); 4891da177e4SLinus Torvalds return; 4901da177e4SLinus Torvalds } 491cf2c7481SPete Zaitcev usb_serial_port_softint(port); 4921da177e4SLinus Torvalds } 493bb833986SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); 4941da177e4SLinus Torvalds 49595da310eSAlan Cox void usb_serial_generic_throttle(struct tty_struct *tty) 496253ca923SJoris van Rantwijk { 49795da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 498253ca923SJoris van Rantwijk unsigned long flags; 499253ca923SJoris van Rantwijk 500441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 501253ca923SJoris van Rantwijk 502253ca923SJoris van Rantwijk /* Set the throttle request flag. It will be picked up 503253ca923SJoris van Rantwijk * by usb_serial_generic_read_bulk_callback(). */ 504253ca923SJoris van Rantwijk spin_lock_irqsave(&port->lock, flags); 505253ca923SJoris van Rantwijk port->throttle_req = 1; 506253ca923SJoris van Rantwijk spin_unlock_irqrestore(&port->lock, flags); 507253ca923SJoris van Rantwijk } 508253ca923SJoris van Rantwijk 50995da310eSAlan Cox void usb_serial_generic_unthrottle(struct tty_struct *tty) 510253ca923SJoris van Rantwijk { 51195da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 512253ca923SJoris van Rantwijk int was_throttled; 513253ca923SJoris van Rantwijk unsigned long flags; 514253ca923SJoris van Rantwijk 515441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 516253ca923SJoris van Rantwijk 517253ca923SJoris van Rantwijk /* Clear the throttle flags */ 518253ca923SJoris van Rantwijk spin_lock_irqsave(&port->lock, flags); 519253ca923SJoris van Rantwijk was_throttled = port->throttled; 520253ca923SJoris van Rantwijk port->throttled = port->throttle_req = 0; 521253ca923SJoris van Rantwijk spin_unlock_irqrestore(&port->lock, flags); 522253ca923SJoris van Rantwijk 523253ca923SJoris van Rantwijk if (was_throttled) { 5241abdeeb1SOliver Neukum /* Resume reading from device */ 52598fcb5f7SJason Wessel usb_serial_generic_resubmit_read_urb(port, GFP_KERNEL); 526253ca923SJoris van Rantwijk } 527253ca923SJoris van Rantwijk } 528253ca923SJoris van Rantwijk 52998fcb5f7SJason Wessel int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) 53098fcb5f7SJason Wessel { 531568d422eSJason Wessel if (port->sysrq && port->console) { 53298fcb5f7SJason Wessel if (ch && time_before(jiffies, port->sysrq)) { 53398fcb5f7SJason Wessel handle_sysrq(ch, tty_port_tty_get(&port->port)); 53498fcb5f7SJason Wessel port->sysrq = 0; 53598fcb5f7SJason Wessel return 1; 53698fcb5f7SJason Wessel } 53798fcb5f7SJason Wessel port->sysrq = 0; 53898fcb5f7SJason Wessel } 53998fcb5f7SJason Wessel return 0; 54098fcb5f7SJason Wessel } 54198fcb5f7SJason Wessel EXPORT_SYMBOL_GPL(usb_serial_handle_sysrq_char); 54298fcb5f7SJason Wessel 54398fcb5f7SJason Wessel int usb_serial_handle_break(struct usb_serial_port *port) 54498fcb5f7SJason Wessel { 54598fcb5f7SJason Wessel if (!port->sysrq) { 54698fcb5f7SJason Wessel port->sysrq = jiffies + HZ*5; 54798fcb5f7SJason Wessel return 1; 54898fcb5f7SJason Wessel } 54998fcb5f7SJason Wessel port->sysrq = 0; 55098fcb5f7SJason Wessel return 0; 55198fcb5f7SJason Wessel } 55298fcb5f7SJason Wessel EXPORT_SYMBOL_GPL(usb_serial_handle_break); 55398fcb5f7SJason Wessel 5541da177e4SLinus Torvalds void usb_serial_generic_shutdown(struct usb_serial *serial) 5551da177e4SLinus Torvalds { 5561da177e4SLinus Torvalds int i; 5571da177e4SLinus Torvalds 558441b62c1SHarvey Harrison dbg("%s", __func__); 5591da177e4SLinus Torvalds 5601da177e4SLinus Torvalds /* stop reads and writes on all ports */ 561ae64387aSAlan Cox for (i = 0; i < serial->num_ports; ++i) 5621da177e4SLinus Torvalds generic_cleanup(serial->port[i]); 5631da177e4SLinus Torvalds } 5641da177e4SLinus Torvalds 565