2017-11-03 11:28:30 +01:00
// SPDX-License-Identifier: GPL-2.0
2005-04-16 15:20:36 -07:00
/*
* USB Serial Converter Generic functions
*
2013-03-21 12:37:51 +01:00
* Copyright ( C ) 2010 - 2013 Johan Hovold ( jhovold @ gmail . com )
2005-04-16 15:20:36 -07:00
* Copyright ( C ) 1999 - 2002 Greg Kroah - Hartman ( greg @ kroah . com )
*/
# include <linux/kernel.h>
2017-02-02 19:15:33 +01:00
# include <linux/sched/signal.h>
2005-04-16 15:20:36 -07:00
# include <linux/errno.h>
# include <linux/slab.h>
2010-03-25 11:29:16 -07:00
# include <linux/sysrq.h>
2005-04-16 15:20:36 -07:00
# include <linux/tty.h>
# include <linux/tty_flip.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/usb.h>
2006-07-11 21:22:58 -07:00
# include <linux/usb/serial.h>
2008-07-22 11:11:55 +01:00
# include <linux/uaccess.h>
2009-08-28 12:54:27 -07:00
# include <linux/kfifo.h>
2010-02-17 10:05:47 -05:00
# include <linux/serial.h>
2006-12-17 21:50:24 +01:00
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_USB_SERIAL_GENERIC
2007-03-23 12:51:55 -07:00
2005-04-16 15:20:36 -07:00
static __u16 vendor = 0x05f9 ;
static __u16 product = 0xffff ;
module_param ( vendor , ushort , 0 ) ;
MODULE_PARM_DESC ( vendor , " User specified USB idVendor " ) ;
module_param ( product , ushort , 0 ) ;
MODULE_PARM_DESC ( product , " User specified USB idProduct " ) ;
static struct usb_device_id generic_device_ids [ 2 ] ; /* Initially all zeroes. */
2017-03-16 17:13:31 +01:00
static int usb_serial_generic_probe ( struct usb_serial * serial ,
const struct usb_device_id * id )
{
struct device * dev = & serial - > interface - > dev ;
dev_info ( dev , " The \" generic \" usb-serial driver is only for testing and one-off prototypes. \n " ) ;
dev_info ( dev , " Tell linux-usb@vger.kernel.org to add your device to a proper driver. \n " ) ;
return 0 ;
}
2017-03-16 17:13:32 +01:00
static int usb_serial_generic_calc_num_ports ( struct usb_serial * serial ,
struct usb_serial_endpoints * epds )
{
struct device * dev = & serial - > interface - > dev ;
2017-03-16 17:13:33 +01:00
int num_ports ;
num_ports = max ( epds - > num_bulk_in , epds - > num_bulk_out ) ;
2017-03-16 17:13:32 +01:00
if ( num_ports = = 0 ) {
2017-03-16 17:13:33 +01:00
dev_err ( dev , " device has no bulk endpoints \n " ) ;
2017-03-16 17:13:32 +01:00
return - ENODEV ;
}
return num_ports ;
}
static struct usb_serial_driver usb_serial_generic_device = {
2005-06-20 21:15:16 -07:00
. driver = {
. owner = THIS_MODULE ,
2005-06-20 21:15:16 -07:00
. name = " generic " ,
2005-06-20 21:15:16 -07:00
} ,
2005-04-16 15:20:36 -07:00
. id_table = generic_device_ids ,
2017-03-16 17:13:31 +01:00
. probe = usb_serial_generic_probe ,
2017-03-16 17:13:32 +01:00
. calc_num_ports = usb_serial_generic_calc_num_ports ,
2007-02-01 20:08:18 +01:00
. throttle = usb_serial_generic_throttle ,
. unthrottle = usb_serial_generic_unthrottle ,
2007-04-27 20:54:57 +02:00
. resume = usb_serial_generic_resume ,
2005-04-16 15:20:36 -07:00
} ;
2012-02-23 14:55:59 -05:00
static struct usb_serial_driver * const serial_drivers [ ] = {
& usb_serial_generic_device , NULL
} ;
2005-04-16 15:20:36 -07:00
# endif
2012-09-18 16:05:17 +01:00
int usb_serial_generic_register ( void )
2005-04-16 15:20:36 -07:00
{
int retval = 0 ;
# ifdef CONFIG_USB_SERIAL_GENERIC
generic_device_ids [ 0 ] . idVendor = vendor ;
generic_device_ids [ 0 ] . idProduct = product ;
2008-07-22 11:11:55 +01:00
generic_device_ids [ 0 ] . match_flags =
USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT ;
2005-04-16 15:20:36 -07:00
2012-05-31 17:03:52 -04:00
retval = usb_serial_register_drivers ( serial_drivers ,
" usbserial_generic " , generic_device_ids ) ;
2005-04-16 15:20:36 -07:00
# endif
return retval ;
}
2008-07-22 11:11:55 +01:00
void usb_serial_generic_deregister ( void )
2005-04-16 15:20:36 -07:00
{
# ifdef CONFIG_USB_SERIAL_GENERIC
2012-05-08 15:46:14 -07:00
usb_serial_deregister_drivers ( serial_drivers ) ;
2005-04-16 15:20:36 -07:00
# endif
}
2009-09-19 13:13:26 -07:00
int usb_serial_generic_open ( struct tty_struct * tty , struct usb_serial_port * port )
2005-04-16 15:20:36 -07:00
{
int result = 0 ;
2019-04-25 18:05:37 +02:00
clear_bit ( USB_SERIAL_THROTTLED , & port - > flags ) ;
2007-02-01 20:08:18 +01:00
2010-03-17 23:05:53 +01:00
if ( port - > bulk_in_size )
2011-11-06 19:06:37 +01:00
result = usb_serial_generic_submit_read_urbs ( port , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
return result ;
}
2006-05-12 11:05:29 -07:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_open ) ;
2005-04-16 15:20:36 -07:00
2013-03-21 12:36:41 +01:00
void usb_serial_generic_close ( struct usb_serial_port * port )
2005-04-16 15:20:36 -07:00
{
2010-03-17 23:00:44 +01:00
unsigned long flags ;
2010-05-05 23:57:37 +02:00
int i ;
2005-04-16 15:20:36 -07:00
2013-03-21 12:36:38 +01:00
if ( port - > bulk_out_size ) {
for ( i = 0 ; i < ARRAY_SIZE ( port - > write_urbs ) ; + + i )
usb_kill_urb ( port - > write_urbs [ i ] ) ;
spin_lock_irqsave ( & port - > lock , flags ) ;
kfifo_reset_out ( & port - > write_fifo ) ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
if ( port - > bulk_in_size ) {
for ( i = 0 ; i < ARRAY_SIZE ( port - > read_urbs ) ; + + i )
usb_kill_urb ( port - > read_urbs [ i ] ) ;
2005-04-16 15:20:36 -07:00
}
}
2010-03-17 23:00:45 +01:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_close ) ;
2005-04-16 15:20:36 -07:00
2010-03-17 23:06:08 +01:00
int usb_serial_generic_prepare_write_buffer ( struct usb_serial_port * port ,
2010-05-05 23:58:13 +02:00
void * dest , size_t size )
2010-03-17 23:06:08 +01:00
{
2010-05-05 23:58:13 +02:00
return kfifo_out_locked ( & port - > write_fifo , dest , size , & port - > lock ) ;
2009-05-11 15:24:07 -05:00
}
2009-08-28 12:54:27 -07:00
/**
2013-10-09 17:01:10 +02:00
* usb_serial_generic_write_start - start writing buffered data
* @ port : usb - serial port
2013-10-09 17:01:11 +02:00
* @ mem_flags : flags to use for memory allocations
2013-10-09 17:01:10 +02:00
*
* Serialised using USB_SERIAL_WRITE_BUSY flag .
2009-08-28 12:54:27 -07:00
*
2013-10-09 17:01:10 +02:00
* Return : Zero on success or if busy , otherwise a negative errno value .
2009-08-28 12:54:27 -07:00
*/
2013-10-09 17:01:12 +02:00
int usb_serial_generic_write_start ( struct usb_serial_port * port ,
2013-10-09 17:01:11 +02:00
gfp_t mem_flags )
2009-08-28 12:54:27 -07:00
{
2010-05-05 23:57:37 +02:00
struct urb * urb ;
int count , result ;
2009-08-28 12:54:27 -07:00
unsigned long flags ;
2010-05-05 23:57:37 +02:00
int i ;
2009-08-28 12:54:27 -07:00
2010-05-05 23:57:37 +02:00
if ( test_and_set_bit_lock ( USB_SERIAL_WRITE_BUSY , & port - > flags ) )
return 0 ;
retry :
2009-08-28 12:54:27 -07:00
spin_lock_irqsave ( & port - > lock , flags ) ;
2010-05-05 23:57:37 +02:00
if ( ! port - > write_urbs_free | | ! kfifo_len ( & port - > write_fifo ) ) {
clear_bit_unlock ( USB_SERIAL_WRITE_BUSY , & port - > flags ) ;
2010-03-17 23:06:02 +01:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
return 0 ;
2009-08-28 12:54:27 -07:00
}
2010-05-05 23:57:37 +02:00
i = ( int ) find_first_bit ( & port - > write_urbs_free ,
ARRAY_SIZE ( port - > write_urbs ) ) ;
2009-08-28 12:54:27 -07:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2010-05-05 23:57:37 +02:00
urb = port - > write_urbs [ i ] ;
2010-03-17 23:06:08 +01:00
count = port - > serial - > type - > prepare_write_buffer ( port ,
2010-05-05 23:58:13 +02:00
urb - > transfer_buffer ,
port - > bulk_out_size ) ;
2010-05-05 23:57:37 +02:00
urb - > transfer_buffer_length = count ;
2012-09-18 09:58:57 +01:00
usb_serial_debug_data ( & port - > dev , __func__ , count , urb - > transfer_buffer ) ;
2010-08-04 15:45:57 +02:00
spin_lock_irqsave ( & port - > lock , flags ) ;
port - > tx_bytes + = count ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
clear_bit ( i , & port - > write_urbs_free ) ;
2013-10-09 17:01:11 +02:00
result = usb_submit_urb ( urb , mem_flags ) ;
2009-08-28 12:54:27 -07:00
if ( result ) {
2012-02-10 13:20:50 +01:00
dev_err_console ( port , " %s - error submitting urb: %d \n " ,
2009-08-28 12:54:27 -07:00
__func__ , result ) ;
2010-08-04 15:45:57 +02:00
set_bit ( i , & port - > write_urbs_free ) ;
spin_lock_irqsave ( & port - > lock , flags ) ;
port - > tx_bytes - = count ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2010-05-05 23:57:37 +02:00
clear_bit_unlock ( USB_SERIAL_WRITE_BUSY , & port - > flags ) ;
2010-03-17 23:00:42 +01:00
return result ;
}
2010-05-05 23:57:37 +02:00
2013-11-09 12:38:09 +01:00
goto retry ; /* try sending off another urb */
2009-08-28 12:54:27 -07:00
}
2013-10-09 17:01:12 +02:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_write_start ) ;
2009-08-28 12:54:27 -07:00
/**
2013-10-09 17:01:10 +02:00
* usb_serial_generic_write - generic write function
* @ tty : tty for the port
* @ port : usb - serial port
* @ buf : data to write
* @ count : number of bytes to write
2009-08-28 12:54:27 -07:00
*
2013-10-09 17:01:10 +02:00
* Return : The number of characters buffered , which may be anything from
* zero to @ count , or a negative errno value .
2009-08-28 12:54:27 -07:00
*/
2008-07-22 11:09:07 +01:00
int usb_serial_generic_write ( struct tty_struct * tty ,
struct usb_serial_port * port , const unsigned char * buf , int count )
2005-04-16 15:20:36 -07:00
{
int result ;
2010-02-27 16:24:49 +01:00
if ( ! port - > bulk_out_size )
return - ENODEV ;
2010-03-17 23:06:01 +01:00
if ( ! count )
2008-07-22 11:11:55 +01:00
return 0 ;
2005-04-16 15:20:36 -07:00
2009-12-23 09:10:48 +01:00
count = kfifo_in_locked ( & port - > write_fifo , buf , count , & port - > lock ) ;
2013-11-09 12:38:10 +01:00
result = usb_serial_generic_write_start ( port , GFP_ATOMIC ) ;
2010-05-05 23:58:13 +02:00
if ( result )
return result ;
2005-04-16 15:20:36 -07:00
2010-05-05 23:58:13 +02:00
return count ;
2005-04-16 15:20:36 -07:00
}
2009-05-11 15:24:09 -05:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_write ) ;
2005-04-16 15:20:36 -07:00
2021-05-05 11:19:16 +02:00
unsigned int usb_serial_generic_write_room ( struct tty_struct * tty )
2005-04-16 15:20:36 -07:00
{
2008-07-22 11:09:07 +01:00
struct usb_serial_port * port = tty - > driver_data ;
2009-05-11 15:24:07 -05:00
unsigned long flags ;
2021-05-05 11:19:16 +02:00
unsigned int room ;
2005-04-16 15:20:36 -07:00
2010-02-27 16:24:49 +01:00
if ( ! port - > bulk_out_size )
return 0 ;
2009-05-11 15:24:07 -05:00
spin_lock_irqsave ( & port - > lock , flags ) ;
2010-05-05 23:58:13 +02:00
room = kfifo_avail ( & port - > write_fifo ) ;
2009-05-11 15:24:07 -05:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2005-04-16 15:20:36 -07:00
2021-05-05 11:19:16 +02:00
dev_dbg ( & port - > dev , " %s - returns %u \n " , __func__ , room ) ;
2008-04-08 17:16:06 +01:00
return room ;
2005-04-16 15:20:36 -07:00
}
2021-05-05 11:19:20 +02:00
unsigned int usb_serial_generic_chars_in_buffer ( struct tty_struct * tty )
2005-04-16 15:20:36 -07:00
{
2008-07-22 11:09:07 +01:00
struct usb_serial_port * port = tty - > driver_data ;
2009-05-11 15:24:07 -05:00
unsigned long flags ;
2021-05-05 11:19:20 +02:00
unsigned int chars ;
2005-04-16 15:20:36 -07:00
2010-02-27 16:24:49 +01:00
if ( ! port - > bulk_out_size )
return 0 ;
2010-01-05 14:30:31 +01:00
spin_lock_irqsave ( & port - > lock , flags ) ;
2010-05-05 23:58:13 +02:00
chars = kfifo_len ( & port - > write_fifo ) + port - > tx_bytes ;
2010-01-05 14:30:31 +01:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2005-04-16 15:20:36 -07:00
2021-05-05 11:19:20 +02:00
dev_dbg ( & port - > dev , " %s - returns %u \n " , __func__ , chars ) ;
2008-07-22 11:09:07 +01:00
return chars ;
2005-04-16 15:20:36 -07:00
}
2012-10-29 10:56:25 +01:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_chars_in_buffer ) ;
2005-04-16 15:20:36 -07:00
2013-05-08 17:51:43 +02:00
void usb_serial_generic_wait_until_sent ( struct tty_struct * tty , long timeout )
{
struct usb_serial_port * port = tty - > driver_data ;
unsigned int bps ;
unsigned long period ;
unsigned long expire ;
bps = tty_get_baud_rate ( tty ) ;
if ( ! bps )
bps = 9600 ; /* B0 */
/*
* Use a poll - period of roughly the time it takes to send one
* character or at least one jiffy .
*/
period = max_t ( unsigned long , ( 10 * HZ / bps ) , 1 ) ;
2015-03-04 10:39:05 +01:00
if ( timeout )
period = min_t ( unsigned long , period , timeout ) ;
2013-05-08 17:51:43 +02:00
dev_dbg ( & port - > dev , " %s - timeout = %u ms, period = %u ms \n " ,
__func__ , jiffies_to_msecs ( timeout ) ,
jiffies_to_msecs ( period ) ) ;
expire = jiffies + timeout ;
while ( ! port - > serial - > type - > tx_empty ( port ) ) {
schedule_timeout_interruptible ( period ) ;
if ( signal_pending ( current ) )
break ;
2015-03-04 10:39:05 +01:00
if ( timeout & & time_after ( jiffies , expire ) )
2013-05-08 17:51:43 +02:00
break ;
}
}
EXPORT_SYMBOL_GPL ( usb_serial_generic_wait_until_sent ) ;
2011-11-06 19:06:37 +01:00
static int usb_serial_generic_submit_read_urb ( struct usb_serial_port * port ,
int index , gfp_t mem_flags )
{
int res ;
if ( ! test_and_clear_bit ( index , & port - > read_urbs_free ) )
return 0 ;
2013-03-21 12:36:27 +01:00
dev_dbg ( & port - > dev , " %s - urb %d \n " , __func__ , index ) ;
2011-11-06 19:06:37 +01:00
res = usb_submit_urb ( port - > read_urbs [ index ] , mem_flags ) ;
if ( res ) {
2015-01-11 05:42:07 -08:00
if ( res ! = - EPERM & & res ! = - ENODEV ) {
2011-11-06 19:06:37 +01:00
dev_err ( & port - > dev ,
" %s - usb_submit_urb failed: %d \n " ,
__func__ , res ) ;
}
set_bit ( index , & port - > read_urbs_free ) ;
return res ;
}
return 0 ;
}
int usb_serial_generic_submit_read_urbs ( struct usb_serial_port * port ,
2010-03-17 23:05:53 +01:00
gfp_t mem_flags )
2005-04-16 15:20:36 -07:00
{
2011-11-06 19:06:37 +01:00
int res ;
int i ;
2005-04-16 15:20:36 -07:00
2011-11-06 19:06:37 +01:00
for ( i = 0 ; i < ARRAY_SIZE ( port - > read_urbs ) ; + + i ) {
res = usb_serial_generic_submit_read_urb ( port , i , mem_flags ) ;
if ( res )
goto err ;
2010-02-27 14:05:46 +01:00
}
2011-11-06 19:06:37 +01:00
return 0 ;
err :
for ( ; i > = 0 ; - - i )
usb_kill_urb ( port - > read_urbs [ i ] ) ;
return res ;
2005-04-16 15:20:36 -07:00
}
2011-11-06 19:06:37 +01:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_submit_read_urbs ) ;
2007-02-01 20:08:18 +01:00
2010-03-17 23:05:57 +01:00
void usb_serial_generic_process_read_urb ( struct urb * urb )
2007-05-07 12:09:33 +02:00
{
2010-03-17 23:05:56 +01:00
struct usb_serial_port * port = urb - > context ;
2020-07-08 14:50:00 +02:00
char * ch = urb - > transfer_buffer ;
2009-05-11 15:24:09 -05:00
int i ;
2010-05-15 17:53:44 +02:00
if ( ! urb - > actual_length )
return ;
2013-10-09 17:01:10 +02:00
/*
* The per character mucking around with sysrq path it too slow for
* stuff like 3 G modems , so shortcircuit it in the 99.9999999 % of
* cases where the USB serial is not a console anyway .
*/
2020-07-08 14:49:54 +02:00
if ( port - > sysrq ) {
2009-07-09 13:35:52 +01:00
for ( i = 0 ; i < urb - > actual_length ; i + + , ch + + ) {
2010-08-17 21:15:47 -07:00
if ( ! usb_serial_handle_sysrq_char ( port , * ch ) )
2013-01-03 15:53:03 +01:00
tty_insert_flip_char ( & port - > port , * ch , TTY_NORMAL ) ;
2009-07-09 13:35:52 +01:00
}
2020-07-08 14:49:54 +02:00
} else {
tty_insert_flip_string ( & port - > port , ch , urb - > actual_length ) ;
2007-05-07 12:09:33 +02:00
}
2013-01-03 15:53:06 +01:00
tty_flip_buffer_push ( & port - > port ) ;
2007-05-07 12:09:33 +02:00
}
2010-03-17 23:05:57 +01:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_process_read_urb ) ;
2007-05-07 12:09:33 +02:00
2008-07-22 11:09:07 +01:00
void usb_serial_generic_read_bulk_callback ( struct urb * urb )
2007-02-01 20:08:18 +01:00
{
2008-02-24 18:41:47 +08:00
struct usb_serial_port * port = urb - > context ;
2007-02-01 20:08:18 +01:00
unsigned char * data = urb - > transfer_buffer ;
2019-04-25 18:05:36 +02:00
bool stopped = false ;
2016-07-14 15:01:40 +02:00
int status = urb - > status ;
2011-11-06 19:06:37 +01:00
int i ;
2007-02-01 20:08:18 +01:00
2011-11-06 19:06:37 +01:00
for ( i = 0 ; i < ARRAY_SIZE ( port - > read_urbs ) ; + + i ) {
if ( urb = = port - > read_urbs [ i ] )
break ;
}
2007-02-01 20:08:18 +01:00
2013-03-21 12:36:27 +01:00
dev_dbg ( & port - > dev , " %s - urb %d, len %d \n " , __func__ , i ,
urb - > actual_length ) ;
2016-07-14 15:01:40 +02:00
switch ( status ) {
2014-03-12 19:09:39 +01:00
case 0 :
2019-04-25 18:05:36 +02:00
usb_serial_debug_data ( & port - > dev , __func__ , urb - > actual_length ,
data ) ;
port - > serial - > type - > process_read_urb ( urb ) ;
2014-03-12 19:09:39 +01:00
break ;
case - ENOENT :
case - ECONNRESET :
case - ESHUTDOWN :
dev_dbg ( & port - > dev , " %s - urb stopped: %d \n " ,
2016-07-14 15:01:40 +02:00
__func__ , status ) ;
2019-04-25 18:05:36 +02:00
stopped = true ;
break ;
2014-03-12 19:09:39 +01:00
case - EPIPE :
dev_err ( & port - > dev , " %s - urb stopped: %d \n " ,
2016-07-14 15:01:40 +02:00
__func__ , status ) ;
2019-04-25 18:05:36 +02:00
stopped = true ;
break ;
2014-03-12 19:09:39 +01:00
default :
2015-01-11 05:42:06 -08:00
dev_dbg ( & port - > dev , " %s - nonzero urb status: %d \n " ,
2016-07-14 15:01:40 +02:00
__func__ , status ) ;
2019-04-25 18:05:36 +02:00
break ;
2007-02-01 20:08:18 +01:00
}
2019-04-25 18:05:36 +02:00
/*
* Make sure URB processing is done before marking as free to avoid
* racing with unthrottle ( ) on another CPU . Matches the barriers
* implied by the test_and_clear_bit ( ) in
* usb_serial_generic_submit_read_urb ( ) .
*/
smp_mb__before_atomic ( ) ;
set_bit ( i , & port - > read_urbs_free ) ;
/*
* Make sure URB is marked as free before checking the throttled flag
* to avoid racing with unthrottle ( ) on another CPU . Matches the
2020-01-30 11:06:58 +01:00
* smp_mb__after_atomic ( ) in unthrottle ( ) .
2019-04-25 18:05:36 +02:00
*/
smp_mb__after_atomic ( ) ;
if ( stopped )
return ;
2007-02-01 20:08:18 +01:00
2019-04-25 18:05:37 +02:00
if ( test_bit ( USB_SERIAL_THROTTLED , & port - > flags ) )
return ;
usb_serial_generic_submit_read_urb ( port , i , GFP_ATOMIC ) ;
2007-02-01 20:08:18 +01:00
}
2006-07-11 14:19:25 -03:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_read_bulk_callback ) ;
2005-04-16 15:20:36 -07:00
2008-07-22 11:09:07 +01:00
void usb_serial_generic_write_bulk_callback ( struct urb * urb )
2005-04-16 15:20:36 -07:00
{
2009-05-11 15:24:07 -05:00
unsigned long flags ;
2008-02-24 18:41:47 +08:00
struct usb_serial_port * port = urb - > context ;
2016-07-14 15:01:40 +02:00
int status = urb - > status ;
2010-05-05 23:57:37 +02:00
int i ;
2005-04-16 15:20:36 -07:00
2014-03-12 19:09:41 +01:00
for ( i = 0 ; i < ARRAY_SIZE ( port - > write_urbs ) ; + + i ) {
2010-05-05 23:58:13 +02:00
if ( port - > write_urbs [ i ] = = urb )
break ;
2014-03-12 19:09:41 +01:00
}
2010-05-05 23:58:13 +02:00
spin_lock_irqsave ( & port - > lock , flags ) ;
port - > tx_bytes - = urb - > transfer_buffer_length ;
set_bit ( i , & port - > write_urbs_free ) ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2016-07-14 15:01:40 +02:00
switch ( status ) {
2014-03-12 19:09:40 +01:00
case 0 :
break ;
case - ENOENT :
case - ECONNRESET :
case - ESHUTDOWN :
dev_dbg ( & port - > dev , " %s - urb stopped: %d \n " ,
2016-07-14 15:01:40 +02:00
__func__ , status ) ;
2014-03-12 19:09:40 +01:00
return ;
case - EPIPE :
dev_err_console ( port , " %s - urb stopped: %d \n " ,
2016-07-14 15:01:40 +02:00
__func__ , status ) ;
2014-03-12 19:09:40 +01:00
return ;
default :
dev_err_console ( port , " %s - nonzero urb status: %d \n " ,
2016-07-14 15:01:40 +02:00
__func__ , status ) ;
2019-04-25 18:05:38 +02:00
break ;
2005-04-16 15:20:36 -07:00
}
2009-08-28 12:54:27 -07:00
2014-03-12 19:09:40 +01:00
usb_serial_generic_write_start ( port , GFP_ATOMIC ) ;
2006-05-22 21:58:49 -07:00
usb_serial_port_softint ( port ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-17 09:48:18 -08:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_write_bulk_callback ) ;
2005-04-16 15:20:36 -07:00
2008-07-22 11:09:07 +01:00
void usb_serial_generic_throttle ( struct tty_struct * tty )
2007-02-01 20:08:18 +01:00
{
2008-07-22 11:09:07 +01:00
struct usb_serial_port * port = tty - > driver_data ;
2007-02-01 20:08:18 +01:00
2019-04-25 18:05:37 +02:00
set_bit ( USB_SERIAL_THROTTLED , & port - > flags ) ;
2007-02-01 20:08:18 +01:00
}
2010-03-17 23:05:59 +01:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_throttle ) ;
2007-02-01 20:08:18 +01:00
2008-07-22 11:09:07 +01:00
void usb_serial_generic_unthrottle ( struct tty_struct * tty )
2007-02-01 20:08:18 +01:00
{
2008-07-22 11:09:07 +01:00
struct usb_serial_port * port = tty - > driver_data ;
2007-02-01 20:08:18 +01:00
2019-04-25 18:05:37 +02:00
clear_bit ( USB_SERIAL_THROTTLED , & port - > flags ) ;
2007-02-01 20:08:18 +01:00
2019-04-25 18:05:36 +02:00
/*
* Matches the smp_mb__after_atomic ( ) in
* usb_serial_generic_read_bulk_callback ( ) .
*/
2020-01-30 11:06:58 +01:00
smp_mb__after_atomic ( ) ;
2019-04-25 18:05:36 +02:00
2019-04-25 18:05:37 +02:00
usb_serial_generic_submit_read_urbs ( port , GFP_KERNEL ) ;
2007-02-01 20:08:18 +01:00
}
2010-03-17 23:05:59 +01:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_unthrottle ) ;
2007-02-01 20:08:18 +01:00
2013-03-21 12:36:52 +01:00
static bool usb_serial_generic_msr_changed ( struct tty_struct * tty ,
unsigned long arg , struct async_icount * cprev )
{
struct usb_serial_port * port = tty - > driver_data ;
struct async_icount cnow ;
unsigned long flags ;
bool ret ;
/*
* Use tty - port initialised flag to detect all hangups including the
* one generated at USB - device disconnect .
*/
2016-04-09 17:53:25 -07:00
if ( ! tty_port_initialized ( & port - > port ) )
2013-03-21 12:36:52 +01:00
return true ;
spin_lock_irqsave ( & port - > lock , flags ) ;
cnow = port - > icount ; /* atomic copy*/
spin_unlock_irqrestore ( & port - > lock , flags ) ;
ret = ( ( arg & TIOCM_RNG ) & & ( cnow . rng ! = cprev - > rng ) ) | |
( ( arg & TIOCM_DSR ) & & ( cnow . dsr ! = cprev - > dsr ) ) | |
( ( arg & TIOCM_CD ) & & ( cnow . dcd ! = cprev - > dcd ) ) | |
( ( arg & TIOCM_CTS ) & & ( cnow . cts ! = cprev - > cts ) ) ;
* cprev = cnow ;
return ret ;
}
int usb_serial_generic_tiocmiwait ( struct tty_struct * tty , unsigned long arg )
{
struct usb_serial_port * port = tty - > driver_data ;
struct async_icount cnow ;
unsigned long flags ;
int ret ;
spin_lock_irqsave ( & port - > lock , flags ) ;
cnow = port - > icount ; /* atomic copy */
spin_unlock_irqrestore ( & port - > lock , flags ) ;
ret = wait_event_interruptible ( port - > port . delta_msr_wait ,
usb_serial_generic_msr_changed ( tty , arg , & cnow ) ) ;
2016-04-09 17:53:25 -07:00
if ( ! ret & & ! tty_port_initialized ( & port - > port ) )
2013-06-26 16:47:21 +02:00
ret = - EIO ;
2013-03-21 12:36:52 +01:00
return ret ;
}
EXPORT_SYMBOL_GPL ( usb_serial_generic_tiocmiwait ) ;
2013-03-21 12:36:54 +01:00
int usb_serial_generic_get_icount ( struct tty_struct * tty ,
struct serial_icounter_struct * icount )
{
struct usb_serial_port * port = tty - > driver_data ;
struct async_icount cnow ;
unsigned long flags ;
spin_lock_irqsave ( & port - > lock , flags ) ;
cnow = port - > icount ; /* atomic copy */
spin_unlock_irqrestore ( & port - > lock , flags ) ;
icount - > cts = cnow . cts ;
icount - > dsr = cnow . dsr ;
icount - > rng = cnow . rng ;
icount - > dcd = cnow . dcd ;
icount - > tx = cnow . tx ;
icount - > rx = cnow . rx ;
icount - > frame = cnow . frame ;
icount - > parity = cnow . parity ;
icount - > overrun = cnow . overrun ;
icount - > brk = cnow . brk ;
icount - > buf_overrun = cnow . buf_overrun ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( usb_serial_generic_get_icount ) ;
2020-07-08 14:49:56 +02:00
# if defined(CONFIG_USB_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
2010-08-17 21:15:47 -07:00
int usb_serial_handle_sysrq_char ( struct usb_serial_port * port , unsigned int ch )
2009-05-11 15:24:09 -05:00
{
2020-07-08 14:49:54 +02:00
if ( port - > sysrq ) {
2009-05-11 15:24:09 -05:00
if ( ch & & time_before ( jiffies , port - > sysrq ) ) {
2010-08-17 21:15:47 -07:00
handle_sysrq ( ch ) ;
2009-05-11 15:24:09 -05:00
port - > sysrq = 0 ;
return 1 ;
}
port - > sysrq = 0 ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( usb_serial_handle_sysrq_char ) ;
int usb_serial_handle_break ( struct usb_serial_port * port )
{
2020-07-08 14:49:57 +02:00
if ( ! port - > port . console )
2020-07-08 14:49:54 +02:00
return 0 ;
2009-05-11 15:24:09 -05:00
if ( ! port - > sysrq ) {
port - > sysrq = jiffies + HZ * 5 ;
return 1 ;
}
port - > sysrq = 0 ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( usb_serial_handle_break ) ;
2020-07-08 14:49:57 +02:00
# endif
2009-05-11 15:24:09 -05:00
2011-01-14 14:30:21 +01:00
/**
2013-10-09 17:01:10 +02:00
* usb_serial_handle_dcd_change - handle a change of carrier detect state
* @ port : usb - serial port
* @ tty : tty for the port
* @ status : new carrier detect status , nonzero if active
2011-01-14 14:30:21 +01:00
*/
2020-02-25 11:24:20 +01:00
void usb_serial_handle_dcd_change ( struct usb_serial_port * port ,
2011-01-14 14:30:21 +01:00
struct tty_struct * tty , unsigned int status )
{
2020-02-25 11:24:20 +01:00
dev_dbg ( & port - > dev , " %s - status %d \n " , __func__ , status ) ;
2011-01-14 14:30:21 +01:00
2013-09-16 08:41:00 +02:00
if ( tty ) {
struct tty_ldisc * ld = tty_ldisc_ref ( tty ) ;
if ( ld ) {
if ( ld - > ops - > dcd_change )
ld - > ops - > dcd_change ( tty , status ) ;
tty_ldisc_deref ( ld ) ;
}
}
2011-01-14 14:30:21 +01:00
if ( status )
2020-02-25 11:24:20 +01:00
wake_up_interruptible ( & port - > port . open_wait ) ;
2011-01-14 14:30:21 +01:00
else if ( tty & & ! C_CLOCAL ( tty ) )
tty_hangup ( tty ) ;
}
EXPORT_SYMBOL_GPL ( usb_serial_handle_dcd_change ) ;
2009-08-28 12:54:27 -07:00
int usb_serial_generic_resume ( struct usb_serial * serial )
{
struct usb_serial_port * port ;
int i , c = 0 , r ;
for ( i = 0 ; i < serial - > num_ports ; i + + ) {
port = serial - > port [ i ] ;
2016-04-09 17:53:25 -07:00
if ( ! tty_port_initialized ( & port - > port ) )
2009-08-28 12:54:27 -07:00
continue ;
2011-11-06 19:06:37 +01:00
if ( port - > bulk_in_size ) {
r = usb_serial_generic_submit_read_urbs ( port ,
GFP_NOIO ) ;
2009-08-28 12:54:27 -07:00
if ( r < 0 )
c + + ;
}
2010-05-05 23:57:37 +02:00
if ( port - > bulk_out_size ) {
2013-10-09 17:01:11 +02:00
r = usb_serial_generic_write_start ( port , GFP_NOIO ) ;
2009-08-28 12:54:27 -07:00
if ( r < 0 )
c + + ;
}
}
return c ? - EIO : 0 ;
}
EXPORT_SYMBOL_GPL ( usb_serial_generic_resume ) ;