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> 228e8dce06SDavid VomLehn #include <linux/kfifo.h> 231f87158eSAlan Stern #include <linux/serial.h> 24d9b1b787SJohannes Hölzl 251da177e4SLinus Torvalds static int debug; 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds #ifdef CONFIG_USB_SERIAL_GENERIC 28b46d60fcSDavid Brownell 29b46d60fcSDavid Brownell static int generic_probe(struct usb_interface *interface, 30b46d60fcSDavid Brownell const struct usb_device_id *id); 31b46d60fcSDavid Brownell 321da177e4SLinus Torvalds static __u16 vendor = 0x05f9; 331da177e4SLinus Torvalds static __u16 product = 0xffff; 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds module_param(vendor, ushort, 0); 361da177e4SLinus Torvalds MODULE_PARM_DESC(vendor, "User specified USB idVendor"); 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds module_param(product, ushort, 0); 391da177e4SLinus Torvalds MODULE_PARM_DESC(product, "User specified USB idProduct"); 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ 421da177e4SLinus Torvalds 43d9b1b787SJohannes Hölzl /* we want to look at all devices, as the vendor/product id can change 44d9b1b787SJohannes Hölzl * depending on the command line argument */ 457d40d7e8SNémeth Márton static const struct usb_device_id generic_serial_ids[] = { 46d9b1b787SJohannes Hölzl {.driver_info = 42}, 47d9b1b787SJohannes Hölzl {} 48d9b1b787SJohannes Hölzl }; 49d9b1b787SJohannes Hölzl 50d9b1b787SJohannes Hölzl static struct usb_driver generic_driver = { 51d9b1b787SJohannes Hölzl .name = "usbserial_generic", 52d9b1b787SJohannes Hölzl .probe = generic_probe, 53d9b1b787SJohannes Hölzl .disconnect = usb_serial_disconnect, 54d9b1b787SJohannes Hölzl .id_table = generic_serial_ids, 55d9b1b787SJohannes Hölzl .no_dynamic_id = 1, 56d9b1b787SJohannes Hölzl }; 57d9b1b787SJohannes Hölzl 581da177e4SLinus Torvalds /* All of the device info needed for the Generic Serial Converter */ 59ea65370dSGreg Kroah-Hartman struct usb_serial_driver usb_serial_generic_device = { 6018fcac35SGreg Kroah-Hartman .driver = { 611da177e4SLinus Torvalds .owner = THIS_MODULE, 62269bda1cSGreg Kroah-Hartman .name = "generic", 6318fcac35SGreg Kroah-Hartman }, 641da177e4SLinus Torvalds .id_table = generic_device_ids, 65d9b1b787SJohannes Hölzl .usb_driver = &generic_driver, 661da177e4SLinus Torvalds .num_ports = 1, 67f9c99bb8SAlan Stern .disconnect = usb_serial_generic_disconnect, 68f9c99bb8SAlan Stern .release = usb_serial_generic_release, 69253ca923SJoris van Rantwijk .throttle = usb_serial_generic_throttle, 70253ca923SJoris van Rantwijk .unthrottle = usb_serial_generic_unthrottle, 71ec22559eSOliver Neukum .resume = usb_serial_generic_resume, 721da177e4SLinus Torvalds }; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds static int generic_probe(struct usb_interface *interface, 751da177e4SLinus Torvalds const struct usb_device_id *id) 761da177e4SLinus Torvalds { 771da177e4SLinus Torvalds const struct usb_device_id *id_pattern; 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds id_pattern = usb_match_id(interface, generic_device_ids); 801da177e4SLinus Torvalds if (id_pattern != NULL) 811da177e4SLinus Torvalds return usb_serial_probe(interface, id); 821da177e4SLinus Torvalds return -ENODEV; 831da177e4SLinus Torvalds } 841da177e4SLinus Torvalds #endif 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds int usb_serial_generic_register(int _debug) 871da177e4SLinus Torvalds { 881da177e4SLinus Torvalds int retval = 0; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds debug = _debug; 911da177e4SLinus Torvalds #ifdef CONFIG_USB_SERIAL_GENERIC 921da177e4SLinus Torvalds generic_device_ids[0].idVendor = vendor; 931da177e4SLinus Torvalds generic_device_ids[0].idProduct = product; 94ae64387aSAlan Cox generic_device_ids[0].match_flags = 95ae64387aSAlan Cox USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds /* register our generic driver with ourselves */ 981da177e4SLinus Torvalds retval = usb_serial_register(&usb_serial_generic_device); 991da177e4SLinus Torvalds if (retval) 1001da177e4SLinus Torvalds goto exit; 1011da177e4SLinus Torvalds retval = usb_register(&generic_driver); 1021da177e4SLinus Torvalds if (retval) 1031da177e4SLinus Torvalds usb_serial_deregister(&usb_serial_generic_device); 1041da177e4SLinus Torvalds exit: 1051da177e4SLinus Torvalds #endif 1061da177e4SLinus Torvalds return retval; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds void usb_serial_generic_deregister(void) 1101da177e4SLinus Torvalds { 1111da177e4SLinus Torvalds #ifdef CONFIG_USB_SERIAL_GENERIC 1121da177e4SLinus Torvalds /* remove our generic driver */ 1131da177e4SLinus Torvalds usb_deregister(&generic_driver); 1141da177e4SLinus Torvalds usb_serial_deregister(&usb_serial_generic_device); 1151da177e4SLinus Torvalds #endif 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds 118a509a7e4SAlan Cox int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port) 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 170335f8514SAlan Cox void usb_serial_generic_close(struct usb_serial_port *port) 1711da177e4SLinus Torvalds { 172441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 1731da177e4SLinus Torvalds generic_cleanup(port); 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 176715b1dc0SJason Wessel static int usb_serial_multi_urb_write(struct tty_struct *tty, 177715b1dc0SJason Wessel struct usb_serial_port *port, const unsigned char *buf, int count) 178715b1dc0SJason Wessel { 179715b1dc0SJason Wessel unsigned long flags; 180715b1dc0SJason Wessel struct urb *urb; 181715b1dc0SJason Wessel unsigned char *buffer; 182715b1dc0SJason Wessel int status; 183715b1dc0SJason Wessel int towrite; 184715b1dc0SJason Wessel int bwrite = 0; 185715b1dc0SJason Wessel 186715b1dc0SJason Wessel dbg("%s - port %d", __func__, port->number); 187715b1dc0SJason Wessel 188715b1dc0SJason Wessel if (count == 0) 189715b1dc0SJason Wessel dbg("%s - write request of 0 bytes", __func__); 190715b1dc0SJason Wessel 191715b1dc0SJason Wessel while (count > 0) { 192715b1dc0SJason Wessel towrite = (count > port->bulk_out_size) ? 193715b1dc0SJason Wessel port->bulk_out_size : count; 194715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 195715b1dc0SJason Wessel if (port->urbs_in_flight > 196715b1dc0SJason Wessel port->serial->type->max_in_flight_urbs) { 197715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 198759f3634SJoe Perches dbg("%s - write limit hit", __func__); 199715b1dc0SJason Wessel return bwrite; 200715b1dc0SJason Wessel } 201715b1dc0SJason Wessel port->tx_bytes_flight += towrite; 202715b1dc0SJason Wessel port->urbs_in_flight++; 203715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 204715b1dc0SJason Wessel 205715b1dc0SJason Wessel buffer = kmalloc(towrite, GFP_ATOMIC); 206715b1dc0SJason Wessel if (!buffer) { 207715b1dc0SJason Wessel dev_err(&port->dev, 208715b1dc0SJason Wessel "%s ran out of kernel memory for urb ...\n", __func__); 209715b1dc0SJason Wessel goto error_no_buffer; 210715b1dc0SJason Wessel } 211715b1dc0SJason Wessel 212715b1dc0SJason Wessel urb = usb_alloc_urb(0, GFP_ATOMIC); 213715b1dc0SJason Wessel if (!urb) { 214715b1dc0SJason Wessel dev_err(&port->dev, "%s - no more free urbs\n", 215715b1dc0SJason Wessel __func__); 216715b1dc0SJason Wessel goto error_no_urb; 217715b1dc0SJason Wessel } 218715b1dc0SJason Wessel 219715b1dc0SJason Wessel /* Copy data */ 220715b1dc0SJason Wessel memcpy(buffer, buf + bwrite, towrite); 221715b1dc0SJason Wessel usb_serial_debug_data(debug, &port->dev, __func__, 222715b1dc0SJason Wessel towrite, buffer); 223715b1dc0SJason Wessel /* fill the buffer and send it */ 224715b1dc0SJason Wessel usb_fill_bulk_urb(urb, port->serial->dev, 225715b1dc0SJason Wessel usb_sndbulkpipe(port->serial->dev, 226715b1dc0SJason Wessel port->bulk_out_endpointAddress), 227715b1dc0SJason Wessel buffer, towrite, 228715b1dc0SJason Wessel usb_serial_generic_write_bulk_callback, port); 229715b1dc0SJason Wessel 230715b1dc0SJason Wessel status = usb_submit_urb(urb, GFP_ATOMIC); 231715b1dc0SJason Wessel if (status) { 232715b1dc0SJason Wessel dev_err(&port->dev, 233715b1dc0SJason Wessel "%s - failed submitting write urb, error %d\n", 234715b1dc0SJason Wessel __func__, status); 235715b1dc0SJason Wessel goto error; 236715b1dc0SJason Wessel } 237715b1dc0SJason Wessel 238715b1dc0SJason Wessel /* This urb is the responsibility of the host driver now */ 239715b1dc0SJason Wessel usb_free_urb(urb); 240715b1dc0SJason Wessel dbg("%s write: %d", __func__, towrite); 241715b1dc0SJason Wessel count -= towrite; 242715b1dc0SJason Wessel bwrite += towrite; 243715b1dc0SJason Wessel } 244715b1dc0SJason Wessel return bwrite; 245715b1dc0SJason Wessel 246715b1dc0SJason Wessel error: 247715b1dc0SJason Wessel usb_free_urb(urb); 248715b1dc0SJason Wessel error_no_urb: 249715b1dc0SJason Wessel kfree(buffer); 250715b1dc0SJason Wessel error_no_buffer: 251715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 252715b1dc0SJason Wessel port->urbs_in_flight--; 253715b1dc0SJason Wessel port->tx_bytes_flight -= towrite; 254715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 255715b1dc0SJason Wessel return bwrite; 256715b1dc0SJason Wessel } 257715b1dc0SJason Wessel 2588e8dce06SDavid VomLehn /** 2598e8dce06SDavid VomLehn * usb_serial_generic_write_start - kick off an URB write 2608e8dce06SDavid VomLehn * @port: Pointer to the &struct usb_serial_port data 2618e8dce06SDavid VomLehn * 2628e8dce06SDavid VomLehn * Returns the number of bytes queued on success. This will be zero if there 2638e8dce06SDavid VomLehn * was nothing to send. Otherwise, it returns a negative errno value 2648e8dce06SDavid VomLehn */ 2658e8dce06SDavid VomLehn static int usb_serial_generic_write_start(struct usb_serial_port *port) 2661da177e4SLinus Torvalds { 2671da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 2681da177e4SLinus Torvalds unsigned char *data; 2698e8dce06SDavid VomLehn int result; 2708e8dce06SDavid VomLehn int count; 271acd2a847SJiri Kosina unsigned long flags; 2728e8dce06SDavid VomLehn bool start_io; 273715b1dc0SJason Wessel 2748e8dce06SDavid VomLehn /* Atomically determine whether we can and need to start a USB 2758e8dce06SDavid VomLehn * operation. */ 276acd2a847SJiri Kosina spin_lock_irqsave(&port->lock, flags); 2778e8dce06SDavid VomLehn if (port->write_urb_busy) 2788e8dce06SDavid VomLehn start_io = false; 2798e8dce06SDavid VomLehn else { 280119eecc8SStefani Seibold start_io = (kfifo_len(&port->write_fifo) != 0); 2818e8dce06SDavid VomLehn port->write_urb_busy = start_io; 2821da177e4SLinus Torvalds } 283acd2a847SJiri Kosina spin_unlock_irqrestore(&port->lock, flags); 2841da177e4SLinus Torvalds 2858e8dce06SDavid VomLehn if (!start_io) 2868e8dce06SDavid VomLehn return 0; 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds data = port->write_urb->transfer_buffer; 289119eecc8SStefani Seibold count = kfifo_out_locked(&port->write_fifo, data, port->bulk_out_size, &port->lock); 290441b62c1SHarvey Harrison usb_serial_debug_data(debug, &port->dev, __func__, count, data); 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds /* set up our urb */ 2931da177e4SLinus Torvalds usb_fill_bulk_urb(port->write_urb, serial->dev, 2941da177e4SLinus Torvalds usb_sndbulkpipe(serial->dev, 2951da177e4SLinus Torvalds port->bulk_out_endpointAddress), 2961da177e4SLinus Torvalds port->write_urb->transfer_buffer, count, 2971da177e4SLinus Torvalds ((serial->type->write_bulk_callback) ? 2981da177e4SLinus Torvalds serial->type->write_bulk_callback : 299ae64387aSAlan Cox usb_serial_generic_write_bulk_callback), 300ae64387aSAlan Cox port); 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds /* send the data out the bulk port */ 3031da177e4SLinus Torvalds result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 304507ca9bcSGreg Kroah-Hartman if (result) { 305ae64387aSAlan Cox dev_err(&port->dev, 306ae64387aSAlan Cox "%s - failed submitting write urb, error %d\n", 307ae64387aSAlan Cox __func__, result); 308ae64387aSAlan Cox /* don't have to grab the lock here, as we will 309ae64387aSAlan Cox retry if != 0 */ 310507ca9bcSGreg Kroah-Hartman port->write_urb_busy = 0; 311507ca9bcSGreg Kroah-Hartman } else 3121da177e4SLinus Torvalds result = count; 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds return result; 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds 3178e8dce06SDavid VomLehn /** 3188e8dce06SDavid VomLehn * usb_serial_generic_write - generic write function for serial USB devices 3198e8dce06SDavid VomLehn * @tty: Pointer to &struct tty_struct for the device 3208e8dce06SDavid VomLehn * @port: Pointer to the &usb_serial_port structure for the device 3218e8dce06SDavid VomLehn * @buf: Pointer to the data to write 3228e8dce06SDavid VomLehn * @count: Number of bytes to write 3238e8dce06SDavid VomLehn * 3248e8dce06SDavid VomLehn * Returns the number of characters actually written, which may be anything 3258e8dce06SDavid VomLehn * from zero to @count. If an error occurs, it returns the negative errno 3268e8dce06SDavid VomLehn * value. 3278e8dce06SDavid VomLehn */ 3288e8dce06SDavid VomLehn int usb_serial_generic_write(struct tty_struct *tty, 3298e8dce06SDavid VomLehn struct usb_serial_port *port, const unsigned char *buf, int count) 3308e8dce06SDavid VomLehn { 3318e8dce06SDavid VomLehn struct usb_serial *serial = port->serial; 3328e8dce06SDavid VomLehn int result; 3338e8dce06SDavid VomLehn 3348e8dce06SDavid VomLehn dbg("%s - port %d", __func__, port->number); 3358e8dce06SDavid VomLehn 3368e8dce06SDavid VomLehn if (count == 0) { 3378e8dce06SDavid VomLehn dbg("%s - write request of 0 bytes", __func__); 338507ca9bcSGreg Kroah-Hartman return 0; 3391da177e4SLinus Torvalds } 3408e8dce06SDavid VomLehn 3418e8dce06SDavid VomLehn /* only do something if we have a bulk out endpoint */ 3428e8dce06SDavid VomLehn if (!serial->num_bulk_out) 3438e8dce06SDavid VomLehn return 0; 3448e8dce06SDavid VomLehn 3458e8dce06SDavid VomLehn if (serial->type->max_in_flight_urbs) 3468e8dce06SDavid VomLehn return usb_serial_multi_urb_write(tty, port, 3478e8dce06SDavid VomLehn buf, count); 3488e8dce06SDavid VomLehn 349119eecc8SStefani Seibold count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); 3508e8dce06SDavid VomLehn result = usb_serial_generic_write_start(port); 3518e8dce06SDavid VomLehn 3528e8dce06SDavid VomLehn if (result >= 0) 3538e8dce06SDavid VomLehn result = count; 3548e8dce06SDavid VomLehn 3558e8dce06SDavid VomLehn return result; 3568e8dce06SDavid VomLehn } 35798fcb5f7SJason Wessel EXPORT_SYMBOL_GPL(usb_serial_generic_write); 3581da177e4SLinus Torvalds 35995da310eSAlan Cox int usb_serial_generic_write_room(struct tty_struct *tty) 3601da177e4SLinus Torvalds { 36195da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 3621da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 363715b1dc0SJason Wessel unsigned long flags; 3641da177e4SLinus Torvalds int room = 0; 3651da177e4SLinus Torvalds 366441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 367715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 368715b1dc0SJason Wessel if (serial->type->max_in_flight_urbs) { 369715b1dc0SJason Wessel if (port->urbs_in_flight < serial->type->max_in_flight_urbs) 37098fcb5f7SJason Wessel room = port->bulk_out_size * 37198fcb5f7SJason Wessel (serial->type->max_in_flight_urbs - 37298fcb5f7SJason Wessel port->urbs_in_flight); 3738e8dce06SDavid VomLehn } else if (serial->num_bulk_out) 374119eecc8SStefani Seibold room = kfifo_avail(&port->write_fifo); 375715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 3761da177e4SLinus Torvalds 377441b62c1SHarvey Harrison dbg("%s - returns %d", __func__, room); 378a5b6f60cSAlan Cox return room; 3791da177e4SLinus Torvalds } 3801da177e4SLinus Torvalds 38195da310eSAlan Cox int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) 3821da177e4SLinus Torvalds { 38395da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 3841da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 3851da177e4SLinus Torvalds int chars = 0; 386715b1dc0SJason Wessel unsigned long flags; 3871da177e4SLinus Torvalds 388441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 3891da177e4SLinus Torvalds 390715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 39125719e6bSStefani Seibold if (serial->type->max_in_flight_urbs) 392715b1dc0SJason Wessel chars = port->tx_bytes_flight; 39325719e6bSStefani Seibold else if (serial->num_bulk_out) 394119eecc8SStefani Seibold chars = kfifo_len(&port->write_fifo); 39525719e6bSStefani Seibold spin_unlock_irqrestore(&port->lock, flags); 3961da177e4SLinus Torvalds 397441b62c1SHarvey Harrison dbg("%s - returns %d", __func__, chars); 39895da310eSAlan Cox return chars; 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds 4011abdeeb1SOliver Neukum 40298fcb5f7SJason Wessel void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port, 40398fcb5f7SJason Wessel gfp_t mem_flags) 4041da177e4SLinus Torvalds { 405253ca923SJoris van Rantwijk struct urb *urb = port->read_urb; 4061abdeeb1SOliver Neukum struct usb_serial *serial = port->serial; 4071da177e4SLinus Torvalds int result; 4081da177e4SLinus Torvalds 409253ca923SJoris van Rantwijk /* Continue reading from device */ 4101abdeeb1SOliver Neukum usb_fill_bulk_urb(urb, serial->dev, 4111da177e4SLinus Torvalds usb_rcvbulkpipe(serial->dev, 4121da177e4SLinus Torvalds port->bulk_in_endpointAddress), 4131abdeeb1SOliver Neukum urb->transfer_buffer, 4141abdeeb1SOliver Neukum urb->transfer_buffer_length, 4151da177e4SLinus Torvalds ((serial->type->read_bulk_callback) ? 4161da177e4SLinus Torvalds serial->type->read_bulk_callback : 4171da177e4SLinus Torvalds usb_serial_generic_read_bulk_callback), port); 4180ae14743SJohan Hovold 4191abdeeb1SOliver Neukum result = usb_submit_urb(urb, mem_flags); 4200ae14743SJohan Hovold if (result && result != -EPERM) { 421ae64387aSAlan Cox dev_err(&port->dev, 422ae64387aSAlan Cox "%s - failed resubmitting read urb, error %d\n", 423ae64387aSAlan Cox __func__, result); 4241da177e4SLinus Torvalds } 4250ae14743SJohan Hovold } 42698fcb5f7SJason Wessel EXPORT_SYMBOL_GPL(usb_serial_generic_resubmit_read_urb); 427253ca923SJoris van Rantwijk 4281abdeeb1SOliver Neukum /* Push data to tty layer and resubmit the bulk read URB */ 4291abdeeb1SOliver Neukum static void flush_and_resubmit_read_urb(struct usb_serial_port *port) 4301abdeeb1SOliver Neukum { 4311abdeeb1SOliver Neukum struct urb *urb = port->read_urb; 4324a90f09bSAlan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 43398fcb5f7SJason Wessel char *ch = (char *)urb->transfer_buffer; 43498fcb5f7SJason Wessel int i; 43598fcb5f7SJason Wessel 43698fcb5f7SJason Wessel if (!tty) 43798fcb5f7SJason Wessel goto done; 4381abdeeb1SOliver Neukum 4394cd1de0aSAlan Cox /* The per character mucking around with sysrq path it too slow for 4404cd1de0aSAlan Cox stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases 4414cd1de0aSAlan Cox where the USB serial is not a console anyway */ 4424cd1de0aSAlan Cox if (!port->console || !port->sysrq) 4434cd1de0aSAlan Cox tty_insert_flip_string(tty, ch, urb->actual_length); 4444cd1de0aSAlan Cox else { 4451abdeeb1SOliver Neukum /* Push data to tty */ 44698fcb5f7SJason Wessel for (i = 0; i < urb->actual_length; i++, ch++) { 44724a15a62SAlan Cox if (!usb_serial_handle_sysrq_char(tty, port, *ch)) 44898fcb5f7SJason Wessel tty_insert_flip_char(tty, *ch, TTY_NORMAL); 44998fcb5f7SJason Wessel } 4504cd1de0aSAlan Cox } 451b507cc97SPete Zaitcev tty_flip_buffer_push(tty); 4524a90f09bSAlan Cox tty_kref_put(tty); 45398fcb5f7SJason Wessel done: 45498fcb5f7SJason Wessel usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC); 4551abdeeb1SOliver Neukum } 4561abdeeb1SOliver Neukum 457253ca923SJoris van Rantwijk void usb_serial_generic_read_bulk_callback(struct urb *urb) 458253ca923SJoris van Rantwijk { 459cdc97792SMing Lei struct usb_serial_port *port = urb->context; 460253ca923SJoris van Rantwijk unsigned char *data = urb->transfer_buffer; 461fbd27225SGreg Kroah-Hartman int status = urb->status; 462bfaeafcfSBorislav Petkov unsigned long flags; 463253ca923SJoris van Rantwijk 464441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 465253ca923SJoris van Rantwijk 466fbd27225SGreg Kroah-Hartman if (unlikely(status != 0)) { 467fbd27225SGreg Kroah-Hartman dbg("%s - nonzero read bulk status received: %d", 468441b62c1SHarvey Harrison __func__, status); 469253ca923SJoris van Rantwijk return; 470253ca923SJoris van Rantwijk } 471253ca923SJoris van Rantwijk 472ae64387aSAlan Cox usb_serial_debug_data(debug, &port->dev, __func__, 473ae64387aSAlan Cox urb->actual_length, data); 474253ca923SJoris van Rantwijk 475253ca923SJoris van Rantwijk /* Throttle the device if requested by tty */ 476bfaeafcfSBorislav Petkov spin_lock_irqsave(&port->lock, flags); 477ae64387aSAlan Cox port->throttled = port->throttle_req; 478ae64387aSAlan Cox if (!port->throttled) { 479bfaeafcfSBorislav Petkov spin_unlock_irqrestore(&port->lock, flags); 480b507cc97SPete Zaitcev flush_and_resubmit_read_urb(port); 481ae64387aSAlan Cox } else 482b507cc97SPete Zaitcev spin_unlock_irqrestore(&port->lock, flags); 483b507cc97SPete Zaitcev } 484166ffccfSLuiz Fernando N. Capitulino EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); 4851da177e4SLinus Torvalds 4867d12e780SDavid Howells void usb_serial_generic_write_bulk_callback(struct urb *urb) 4871da177e4SLinus Torvalds { 488715b1dc0SJason Wessel unsigned long flags; 489cdc97792SMing Lei struct usb_serial_port *port = urb->context; 490fbd27225SGreg Kroah-Hartman int status = urb->status; 4911da177e4SLinus Torvalds 492441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 4931da177e4SLinus Torvalds 494715b1dc0SJason Wessel if (port->serial->type->max_in_flight_urbs) { 49525915302SJohan Hovold kfree(urb->transfer_buffer); 49625915302SJohan Hovold 497715b1dc0SJason Wessel spin_lock_irqsave(&port->lock, flags); 498715b1dc0SJason Wessel --port->urbs_in_flight; 499715b1dc0SJason Wessel port->tx_bytes_flight -= urb->transfer_buffer_length; 500715b1dc0SJason Wessel if (port->urbs_in_flight < 0) 501715b1dc0SJason Wessel port->urbs_in_flight = 0; 502715b1dc0SJason Wessel spin_unlock_irqrestore(&port->lock, flags); 5038e8dce06SDavid VomLehn } else { 5048e8dce06SDavid VomLehn port->write_urb_busy = 0; 5058e8dce06SDavid VomLehn 50663136202SJohan Hovold if (status) 507119eecc8SStefani Seibold kfifo_reset_out(&port->write_fifo); 50863136202SJohan Hovold else 5098e8dce06SDavid VomLehn usb_serial_generic_write_start(port); 5108e8dce06SDavid VomLehn } 5118e8dce06SDavid VomLehn 51263136202SJohan Hovold if (status) 51363136202SJohan Hovold dbg("%s - non-zero urb status: %d", __func__, status); 51463136202SJohan Hovold 515cf2c7481SPete Zaitcev usb_serial_port_softint(port); 5161da177e4SLinus Torvalds } 517bb833986SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); 5181da177e4SLinus Torvalds 51995da310eSAlan Cox void usb_serial_generic_throttle(struct tty_struct *tty) 520253ca923SJoris van Rantwijk { 52195da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 522253ca923SJoris van Rantwijk unsigned long flags; 523253ca923SJoris van Rantwijk 524441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 525253ca923SJoris van Rantwijk 526253ca923SJoris van Rantwijk /* Set the throttle request flag. It will be picked up 527253ca923SJoris van Rantwijk * by usb_serial_generic_read_bulk_callback(). */ 528253ca923SJoris van Rantwijk spin_lock_irqsave(&port->lock, flags); 529253ca923SJoris van Rantwijk port->throttle_req = 1; 530253ca923SJoris van Rantwijk spin_unlock_irqrestore(&port->lock, flags); 531253ca923SJoris van Rantwijk } 532253ca923SJoris van Rantwijk 53395da310eSAlan Cox void usb_serial_generic_unthrottle(struct tty_struct *tty) 534253ca923SJoris van Rantwijk { 53595da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 536253ca923SJoris van Rantwijk int was_throttled; 537253ca923SJoris van Rantwijk unsigned long flags; 538253ca923SJoris van Rantwijk 539441b62c1SHarvey Harrison dbg("%s - port %d", __func__, port->number); 540253ca923SJoris van Rantwijk 541253ca923SJoris van Rantwijk /* Clear the throttle flags */ 542253ca923SJoris van Rantwijk spin_lock_irqsave(&port->lock, flags); 543253ca923SJoris van Rantwijk was_throttled = port->throttled; 544253ca923SJoris van Rantwijk port->throttled = port->throttle_req = 0; 545253ca923SJoris van Rantwijk spin_unlock_irqrestore(&port->lock, flags); 546253ca923SJoris van Rantwijk 547253ca923SJoris van Rantwijk if (was_throttled) { 5481abdeeb1SOliver Neukum /* Resume reading from device */ 54963a96095SJoris van Rantwijk flush_and_resubmit_read_urb(port); 550253ca923SJoris van Rantwijk } 551253ca923SJoris van Rantwijk } 552253ca923SJoris van Rantwijk 55324a15a62SAlan Cox int usb_serial_handle_sysrq_char(struct tty_struct *tty, 55424a15a62SAlan Cox struct usb_serial_port *port, unsigned int ch) 55598fcb5f7SJason Wessel { 556568d422eSJason Wessel if (port->sysrq && port->console) { 55798fcb5f7SJason Wessel if (ch && time_before(jiffies, port->sysrq)) { 55824a15a62SAlan Cox handle_sysrq(ch, tty); 55998fcb5f7SJason Wessel port->sysrq = 0; 56098fcb5f7SJason Wessel return 1; 56198fcb5f7SJason Wessel } 56298fcb5f7SJason Wessel port->sysrq = 0; 56398fcb5f7SJason Wessel } 56498fcb5f7SJason Wessel return 0; 56598fcb5f7SJason Wessel } 56698fcb5f7SJason Wessel EXPORT_SYMBOL_GPL(usb_serial_handle_sysrq_char); 56798fcb5f7SJason Wessel 56898fcb5f7SJason Wessel int usb_serial_handle_break(struct usb_serial_port *port) 56998fcb5f7SJason Wessel { 57098fcb5f7SJason Wessel if (!port->sysrq) { 57198fcb5f7SJason Wessel port->sysrq = jiffies + HZ*5; 57298fcb5f7SJason Wessel return 1; 57398fcb5f7SJason Wessel } 57498fcb5f7SJason Wessel port->sysrq = 0; 57598fcb5f7SJason Wessel return 0; 57698fcb5f7SJason Wessel } 57798fcb5f7SJason Wessel EXPORT_SYMBOL_GPL(usb_serial_handle_break); 57898fcb5f7SJason Wessel 5798e8dce06SDavid VomLehn int usb_serial_generic_resume(struct usb_serial *serial) 5808e8dce06SDavid VomLehn { 5818e8dce06SDavid VomLehn struct usb_serial_port *port; 5828e8dce06SDavid VomLehn int i, c = 0, r; 5838e8dce06SDavid VomLehn 5848e8dce06SDavid VomLehn for (i = 0; i < serial->num_ports; i++) { 5858e8dce06SDavid VomLehn port = serial->port[i]; 5861f87158eSAlan Stern if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) 5878e8dce06SDavid VomLehn continue; 5888e8dce06SDavid VomLehn 5898e8dce06SDavid VomLehn if (port->read_urb) { 5908e8dce06SDavid VomLehn r = usb_submit_urb(port->read_urb, GFP_NOIO); 5918e8dce06SDavid VomLehn if (r < 0) 5928e8dce06SDavid VomLehn c++; 5938e8dce06SDavid VomLehn } 5948e8dce06SDavid VomLehn 5958e8dce06SDavid VomLehn if (port->write_urb) { 5968e8dce06SDavid VomLehn r = usb_serial_generic_write_start(port); 5978e8dce06SDavid VomLehn if (r < 0) 5988e8dce06SDavid VomLehn c++; 5998e8dce06SDavid VomLehn } 6008e8dce06SDavid VomLehn } 6018e8dce06SDavid VomLehn 6028e8dce06SDavid VomLehn return c ? -EIO : 0; 6038e8dce06SDavid VomLehn } 6048e8dce06SDavid VomLehn EXPORT_SYMBOL_GPL(usb_serial_generic_resume); 6058e8dce06SDavid VomLehn 606f9c99bb8SAlan Stern void usb_serial_generic_disconnect(struct usb_serial *serial) 6071da177e4SLinus Torvalds { 6081da177e4SLinus Torvalds int i; 6091da177e4SLinus Torvalds 610441b62c1SHarvey Harrison dbg("%s", __func__); 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds /* stop reads and writes on all ports */ 613ae64387aSAlan Cox for (i = 0; i < serial->num_ports; ++i) 6141da177e4SLinus Torvalds generic_cleanup(serial->port[i]); 6151da177e4SLinus Torvalds } 6161da177e4SLinus Torvalds 617f9c99bb8SAlan Stern void usb_serial_generic_release(struct usb_serial *serial) 618f9c99bb8SAlan Stern { 619f9c99bb8SAlan Stern dbg("%s", __func__); 620f9c99bb8SAlan Stern } 621