2005-04-17 02:20:36 +04:00
/*
* USB Serial Converter Generic functions
*
2013-03-21 15:37:51 +04:00
* Copyright ( C ) 2010 - 2013 Johan Hovold ( jhovold @ gmail . com )
2005-04-17 02:20:36 +04:00
* Copyright ( C ) 1999 - 2002 Greg Kroah - Hartman ( greg @ kroah . com )
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation .
*/
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/slab.h>
2010-03-25 21:29:16 +03:00
# include <linux/sysrq.h>
2005-04-17 02:20:36 +04:00
# include <linux/tty.h>
# include <linux/tty_flip.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/usb.h>
2006-07-12 08:22:58 +04:00
# include <linux/usb/serial.h>
2008-07-22 14:11:55 +04:00
# include <linux/uaccess.h>
2009-08-28 23:54:27 +04:00
# include <linux/kfifo.h>
2010-02-17 18:05:47 +03:00
# include <linux/serial.h>
2006-12-17 23:50:24 +03:00
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_USB_SERIAL_GENERIC
2007-03-23 22:51:55 +03:00
2005-04-17 02:20:36 +04: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. */
2005-06-21 08:15:16 +04:00
struct usb_serial_driver usb_serial_generic_device = {
2005-06-21 08:15:16 +04:00
. driver = {
. owner = THIS_MODULE ,
2005-06-21 08:15:16 +04:00
. name = " generic " ,
2005-06-21 08:15:16 +04:00
} ,
2005-04-17 02:20:36 +04:00
. id_table = generic_device_ids ,
. num_ports = 1 ,
2007-02-01 22:08:18 +03:00
. throttle = usb_serial_generic_throttle ,
. unthrottle = usb_serial_generic_unthrottle ,
2007-04-27 22:54:57 +04:00
. resume = usb_serial_generic_resume ,
2005-04-17 02:20:36 +04:00
} ;
2012-02-23 23:55:59 +04:00
static struct usb_serial_driver * const serial_drivers [ ] = {
& usb_serial_generic_device , NULL
} ;
2005-04-17 02:20:36 +04:00
# endif
2012-09-18 19:05:17 +04:00
int usb_serial_generic_register ( void )
2005-04-17 02:20:36 +04:00
{
int retval = 0 ;
# ifdef CONFIG_USB_SERIAL_GENERIC
generic_device_ids [ 0 ] . idVendor = vendor ;
generic_device_ids [ 0 ] . idProduct = product ;
2008-07-22 14:11:55 +04:00
generic_device_ids [ 0 ] . match_flags =
USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT ;
2005-04-17 02:20:36 +04:00
2012-06-01 01:03:52 +04:00
retval = usb_serial_register_drivers ( serial_drivers ,
" usbserial_generic " , generic_device_ids ) ;
2005-04-17 02:20:36 +04:00
# endif
return retval ;
}
2008-07-22 14:11:55 +04:00
void usb_serial_generic_deregister ( void )
2005-04-17 02:20:36 +04:00
{
# ifdef CONFIG_USB_SERIAL_GENERIC
2012-05-09 02:46:14 +04:00
usb_serial_deregister_drivers ( serial_drivers ) ;
2005-04-17 02:20:36 +04:00
# endif
}
2009-09-20 00:13:26 +04:00
int usb_serial_generic_open ( struct tty_struct * tty , struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
int result = 0 ;
2007-02-01 22:08:18 +03:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
2007-02-01 22:08:18 +03:00
spin_lock_irqsave ( & port - > lock , flags ) ;
port - > throttled = 0 ;
port - > throttle_req = 0 ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2010-03-18 01:05:53 +03:00
if ( port - > bulk_in_size )
2011-11-06 22:06:37 +04:00
result = usb_serial_generic_submit_read_urbs ( port , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
2006-05-12 22:05:29 +04:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_open ) ;
2005-04-17 02:20:36 +04:00
2013-03-21 15:36:41 +04:00
void usb_serial_generic_close ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2010-03-18 01:00:44 +03:00
unsigned long flags ;
2010-05-06 01:57:37 +04:00
int i ;
2005-04-17 02:20:36 +04:00
2013-03-21 15:36:38 +04: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-17 02:20:36 +04:00
}
}
2010-03-18 01:00:45 +03:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_close ) ;
2005-04-17 02:20:36 +04:00
2010-03-18 01:06:08 +03:00
int usb_serial_generic_prepare_write_buffer ( struct usb_serial_port * port ,
2010-05-06 01:58:13 +04:00
void * dest , size_t size )
2010-03-18 01:06:08 +03:00
{
2010-05-06 01:58:13 +04:00
return kfifo_out_locked ( & port - > write_fifo , dest , size , & port - > lock ) ;
2009-05-12 00:24:07 +04:00
}
2009-08-28 23:54:27 +04:00
/**
2013-10-09 19:01:10 +04:00
* usb_serial_generic_write_start - start writing buffered data
* @ port : usb - serial port
2013-10-09 19:01:11 +04:00
* @ mem_flags : flags to use for memory allocations
2013-10-09 19:01:10 +04:00
*
* Serialised using USB_SERIAL_WRITE_BUSY flag .
2009-08-28 23:54:27 +04:00
*
2013-10-09 19:01:10 +04:00
* Return : Zero on success or if busy , otherwise a negative errno value .
2009-08-28 23:54:27 +04:00
*/
2013-10-09 19:01:12 +04:00
int usb_serial_generic_write_start ( struct usb_serial_port * port ,
2013-10-09 19:01:11 +04:00
gfp_t mem_flags )
2009-08-28 23:54:27 +04:00
{
2010-05-06 01:57:37 +04:00
struct urb * urb ;
int count , result ;
2009-08-28 23:54:27 +04:00
unsigned long flags ;
2010-05-06 01:57:37 +04:00
int i ;
2009-08-28 23:54:27 +04:00
2010-05-06 01:57:37 +04:00
if ( test_and_set_bit_lock ( USB_SERIAL_WRITE_BUSY , & port - > flags ) )
return 0 ;
retry :
2009-08-28 23:54:27 +04:00
spin_lock_irqsave ( & port - > lock , flags ) ;
2010-05-06 01:57:37 +04:00
if ( ! port - > write_urbs_free | | ! kfifo_len ( & port - > write_fifo ) ) {
clear_bit_unlock ( USB_SERIAL_WRITE_BUSY , & port - > flags ) ;
2010-03-18 01:06:02 +03:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
return 0 ;
2009-08-28 23:54:27 +04:00
}
2010-05-06 01:57:37 +04:00
i = ( int ) find_first_bit ( & port - > write_urbs_free ,
ARRAY_SIZE ( port - > write_urbs ) ) ;
2009-08-28 23:54:27 +04:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2010-05-06 01:57:37 +04:00
urb = port - > write_urbs [ i ] ;
2010-03-18 01:06:08 +03:00
count = port - > serial - > type - > prepare_write_buffer ( port ,
2010-05-06 01:58:13 +04:00
urb - > transfer_buffer ,
port - > bulk_out_size ) ;
2010-05-06 01:57:37 +04:00
urb - > transfer_buffer_length = count ;
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( & port - > dev , __func__ , count , urb - > transfer_buffer ) ;
2010-08-04 17:45:57 +04: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 19:01:11 +04:00
result = usb_submit_urb ( urb , mem_flags ) ;
2009-08-28 23:54:27 +04:00
if ( result ) {
2012-02-10 16:20:50 +04:00
dev_err_console ( port , " %s - error submitting urb: %d \n " ,
2009-08-28 23:54:27 +04:00
__func__ , result ) ;
2010-08-04 17:45:57 +04: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-06 01:57:37 +04:00
clear_bit_unlock ( USB_SERIAL_WRITE_BUSY , & port - > flags ) ;
2010-03-18 01:00:42 +03:00
return result ;
}
2010-05-06 01:57:37 +04:00
2013-11-09 15:38:09 +04:00
goto retry ; /* try sending off another urb */
2009-08-28 23:54:27 +04:00
}
2013-10-09 19:01:12 +04:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_write_start ) ;
2009-08-28 23:54:27 +04:00
/**
2013-10-09 19:01:10 +04: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 23:54:27 +04:00
*
2013-10-09 19:01:10 +04:00
* Return : The number of characters buffered , which may be anything from
* zero to @ count , or a negative errno value .
2009-08-28 23:54:27 +04:00
*/
2008-07-22 14:09:07 +04:00
int usb_serial_generic_write ( struct tty_struct * tty ,
struct usb_serial_port * port , const unsigned char * buf , int count )
2005-04-17 02:20:36 +04:00
{
int result ;
2010-02-27 18:24:49 +03:00
if ( ! port - > bulk_out_size )
return - ENODEV ;
2010-03-18 01:06:01 +03:00
if ( ! count )
2008-07-22 14:11:55 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2009-12-23 11:10:48 +03:00
count = kfifo_in_locked ( & port - > write_fifo , buf , count , & port - > lock ) ;
2013-11-09 15:38:10 +04:00
result = usb_serial_generic_write_start ( port , GFP_ATOMIC ) ;
2010-05-06 01:58:13 +04:00
if ( result )
return result ;
2005-04-17 02:20:36 +04:00
2010-05-06 01:58:13 +04:00
return count ;
2005-04-17 02:20:36 +04:00
}
2009-05-12 00:24:09 +04:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_write ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:55 +04:00
int usb_serial_generic_write_room ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2009-05-12 00:24:07 +04:00
unsigned long flags ;
2010-03-18 01:06:07 +03:00
int room ;
2005-04-17 02:20:36 +04:00
2010-02-27 18:24:49 +03:00
if ( ! port - > bulk_out_size )
return 0 ;
2009-05-12 00:24:07 +04:00
spin_lock_irqsave ( & port - > lock , flags ) ;
2010-05-06 01:58:13 +04:00
room = kfifo_avail ( & port - > write_fifo ) ;
2009-05-12 00:24:07 +04:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
2012-05-16 03:27:18 +04:00
dev_dbg ( & port - > dev , " %s - returns %d \n " , __func__ , room ) ;
2008-04-08 20:16:06 +04:00
return room ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:09:07 +04:00
int usb_serial_generic_chars_in_buffer ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2009-05-12 00:24:07 +04:00
unsigned long flags ;
2010-02-27 18:24:49 +03:00
int chars ;
2005-04-17 02:20:36 +04:00
2010-02-27 18:24:49 +03:00
if ( ! port - > bulk_out_size )
return 0 ;
2010-01-05 16:30:31 +03:00
spin_lock_irqsave ( & port - > lock , flags ) ;
2010-05-06 01:58:13 +04:00
chars = kfifo_len ( & port - > write_fifo ) + port - > tx_bytes ;
2010-01-05 16:30:31 +03:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
2012-05-16 03:27:18 +04:00
dev_dbg ( & port - > dev , " %s - returns %d \n " , __func__ , chars ) ;
2008-07-22 14:09:07 +04:00
return chars ;
2005-04-17 02:20:36 +04:00
}
2012-10-29 13:56:25 +04:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_chars_in_buffer ) ;
2005-04-17 02:20:36 +04:00
2013-05-08 19:51:43 +04: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 12:39:05 +03:00
if ( timeout )
period = min_t ( unsigned long , period , timeout ) ;
2013-05-08 19:51:43 +04: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 12:39:05 +03:00
if ( timeout & & time_after ( jiffies , expire ) )
2013-05-08 19:51:43 +04:00
break ;
}
}
EXPORT_SYMBOL_GPL ( usb_serial_generic_wait_until_sent ) ;
2011-11-06 22:06:37 +04: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 15:36:27 +04:00
dev_dbg ( & port - > dev , " %s - urb %d \n " , __func__ , index ) ;
2011-11-06 22:06:37 +04:00
res = usb_submit_urb ( port - > read_urbs [ index ] , mem_flags ) ;
if ( res ) {
2015-01-11 16:42:07 +03:00
if ( res ! = - EPERM & & res ! = - ENODEV ) {
2011-11-06 22:06:37 +04: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-18 01:05:53 +03:00
gfp_t mem_flags )
2005-04-17 02:20:36 +04:00
{
2011-11-06 22:06:37 +04:00
int res ;
int i ;
2005-04-17 02:20:36 +04:00
2011-11-06 22:06:37 +04: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 16:05:46 +03:00
}
2011-11-06 22:06:37 +04:00
return 0 ;
err :
for ( ; i > = 0 ; - - i )
usb_kill_urb ( port - > read_urbs [ i ] ) ;
return res ;
2005-04-17 02:20:36 +04:00
}
2011-11-06 22:06:37 +04:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_submit_read_urbs ) ;
2007-02-01 22:08:18 +03:00
2010-03-18 01:05:57 +03:00
void usb_serial_generic_process_read_urb ( struct urb * urb )
2007-05-07 14:09:33 +04:00
{
2010-03-18 01:05:56 +03:00
struct usb_serial_port * port = urb - > context ;
2009-05-12 00:24:09 +04:00
char * ch = ( char * ) urb - > transfer_buffer ;
int i ;
2010-05-15 19:53:44 +04:00
if ( ! urb - > actual_length )
return ;
2013-10-09 19:01:10 +04: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 .
*/
2014-03-12 22:09:41 +04:00
if ( ! port - > port . console | | ! port - > sysrq ) {
2013-01-03 18:53:04 +04:00
tty_insert_flip_string ( & port - > port , ch , urb - > actual_length ) ;
2014-03-12 22:09:41 +04:00
} else {
2009-07-09 16:35:52 +04:00
for ( i = 0 ; i < urb - > actual_length ; i + + , ch + + ) {
2010-08-18 08:15:47 +04:00
if ( ! usb_serial_handle_sysrq_char ( port , * ch ) )
2013-01-03 18:53:03 +04:00
tty_insert_flip_char ( & port - > port , * ch , TTY_NORMAL ) ;
2009-07-09 16:35:52 +04:00
}
2007-05-07 14:09:33 +04:00
}
2013-01-03 18:53:06 +04:00
tty_flip_buffer_push ( & port - > port ) ;
2007-05-07 14:09:33 +04:00
}
2010-03-18 01:05:57 +03:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_process_read_urb ) ;
2007-05-07 14:09:33 +04:00
2008-07-22 14:09:07 +04:00
void usb_serial_generic_read_bulk_callback ( struct urb * urb )
2007-02-01 22:08:18 +03:00
{
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2007-02-01 22:08:18 +03:00
unsigned char * data = urb - > transfer_buffer ;
2007-10-28 15:24:16 +03:00
unsigned long flags ;
2011-11-06 22:06:37 +04:00
int i ;
2007-02-01 22:08:18 +03:00
2011-11-06 22:06:37 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( port - > read_urbs ) ; + + i ) {
if ( urb = = port - > read_urbs [ i ] )
break ;
}
set_bit ( i , & port - > read_urbs_free ) ;
2007-02-01 22:08:18 +03:00
2013-03-21 15:36:27 +04:00
dev_dbg ( & port - > dev , " %s - urb %d, len %d \n " , __func__ , i ,
urb - > actual_length ) ;
2014-03-12 22:09:39 +04:00
switch ( urb - > status ) {
case 0 :
break ;
case - ENOENT :
case - ECONNRESET :
case - ESHUTDOWN :
dev_dbg ( & port - > dev , " %s - urb stopped: %d \n " ,
__func__ , urb - > status ) ;
return ;
case - EPIPE :
dev_err ( & port - > dev , " %s - urb stopped: %d \n " ,
__func__ , urb - > status ) ;
2007-02-01 22:08:18 +03:00
return ;
2014-03-12 22:09:39 +04:00
default :
2015-01-11 16:42:06 +03:00
dev_dbg ( & port - > dev , " %s - nonzero urb status: %d \n " ,
2014-03-12 22:09:39 +04:00
__func__ , urb - > status ) ;
goto resubmit ;
2007-02-01 22:08:18 +03:00
}
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( & port - > dev , __func__ , urb - > actual_length , data ) ;
2010-03-18 01:05:57 +03:00
port - > serial - > type - > process_read_urb ( urb ) ;
2007-02-01 22:08:18 +03:00
2014-03-12 22:09:39 +04:00
resubmit :
2007-02-01 22:08:18 +03:00
/* Throttle the device if requested by tty */
2007-10-28 15:24:16 +03:00
spin_lock_irqsave ( & port - > lock , flags ) ;
2008-07-22 14:11:55 +04:00
port - > throttled = port - > throttle_req ;
if ( ! port - > throttled ) {
2008-03-05 10:28:42 +03:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2011-11-06 22:06:37 +04:00
usb_serial_generic_submit_read_urb ( port , i , GFP_ATOMIC ) ;
2014-03-12 22:09:41 +04:00
} else {
2008-03-05 10:28:42 +03:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2014-03-12 22:09:41 +04:00
}
2007-02-01 22:08:18 +03:00
}
2006-07-11 21:19:25 +04:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_read_bulk_callback ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:09:07 +04:00
void usb_serial_generic_write_bulk_callback ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
2009-05-12 00:24:07 +04:00
unsigned long flags ;
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2010-05-06 01:57:37 +04:00
int i ;
2005-04-17 02:20:36 +04:00
2014-03-12 22:09:41 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( port - > write_urbs ) ; + + i ) {
2010-05-06 01:58:13 +04:00
if ( port - > write_urbs [ i ] = = urb )
break ;
2014-03-12 22:09:41 +04:00
}
2010-05-06 01:58:13 +04: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 ) ;
2014-03-12 22:09:40 +04:00
switch ( urb - > status ) {
case 0 :
break ;
case - ENOENT :
case - ECONNRESET :
case - ESHUTDOWN :
dev_dbg ( & port - > dev , " %s - urb stopped: %d \n " ,
__func__ , urb - > status ) ;
return ;
case - EPIPE :
dev_err_console ( port , " %s - urb stopped: %d \n " ,
__func__ , urb - > status ) ;
return ;
default :
dev_err_console ( port , " %s - nonzero urb status: %d \n " ,
__func__ , urb - > status ) ;
goto resubmit ;
2005-04-17 02:20:36 +04:00
}
2009-08-28 23:54:27 +04:00
2014-03-12 22:09:40 +04:00
resubmit :
usb_serial_generic_write_start ( port , GFP_ATOMIC ) ;
2006-05-23 08:58:49 +04:00
usb_serial_port_softint ( port ) ;
2005-04-17 02:20:36 +04:00
}
2005-11-17 20:48:18 +03:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_write_bulk_callback ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:09:07 +04:00
void usb_serial_generic_throttle ( struct tty_struct * tty )
2007-02-01 22:08:18 +03:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2007-02-01 22:08:18 +03:00
unsigned long flags ;
spin_lock_irqsave ( & port - > lock , flags ) ;
port - > throttle_req = 1 ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
2010-03-18 01:05:59 +03:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_throttle ) ;
2007-02-01 22:08:18 +03:00
2008-07-22 14:09:07 +04:00
void usb_serial_generic_unthrottle ( struct tty_struct * tty )
2007-02-01 22:08:18 +03:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2007-02-01 22:08:18 +03:00
int was_throttled ;
2010-03-18 01:05:56 +03:00
spin_lock_irq ( & port - > lock ) ;
2007-02-01 22:08:18 +03:00
was_throttled = port - > throttled ;
port - > throttled = port - > throttle_req = 0 ;
2010-03-18 01:05:56 +03:00
spin_unlock_irq ( & port - > lock ) ;
2007-02-01 22:08:18 +03:00
2010-03-18 01:05:56 +03:00
if ( was_throttled )
2011-11-06 22:06:37 +04:00
usb_serial_generic_submit_read_urbs ( port , GFP_KERNEL ) ;
2007-02-01 22:08:18 +03:00
}
2010-03-18 01:05:59 +03:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_unthrottle ) ;
2007-02-01 22:08:18 +03:00
2013-03-21 15:36:52 +04: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 .
*/
if ( ! test_bit ( ASYNCB_INITIALIZED , & port - > port . flags ) )
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 ) ) ;
2013-06-26 18:47:21 +04:00
if ( ! ret & & ! test_bit ( ASYNCB_INITIALIZED , & port - > port . flags ) )
ret = - EIO ;
2013-03-21 15:36:52 +04:00
return ret ;
}
EXPORT_SYMBOL_GPL ( usb_serial_generic_tiocmiwait ) ;
2013-03-21 15:36:54 +04: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 ) ;
2010-03-25 21:29:16 +03:00
# ifdef CONFIG_MAGIC_SYSRQ
2010-08-18 08:15:47 +04:00
int usb_serial_handle_sysrq_char ( struct usb_serial_port * port , unsigned int ch )
2009-05-12 00:24:09 +04:00
{
2010-03-09 06:50:12 +03:00
if ( port - > sysrq & & port - > port . console ) {
2009-05-12 00:24:09 +04:00
if ( ch & & time_before ( jiffies , port - > sysrq ) ) {
2010-08-18 08:15:47 +04:00
handle_sysrq ( ch ) ;
2009-05-12 00:24:09 +04:00
port - > sysrq = 0 ;
return 1 ;
}
port - > sysrq = 0 ;
}
return 0 ;
}
2010-03-25 21:29:16 +03:00
# else
2010-08-18 08:15:47 +04:00
int usb_serial_handle_sysrq_char ( struct usb_serial_port * port , unsigned int ch )
2010-03-25 21:29:16 +03:00
{
return 0 ;
}
# endif
2009-05-12 00:24:09 +04:00
EXPORT_SYMBOL_GPL ( usb_serial_handle_sysrq_char ) ;
int usb_serial_handle_break ( struct usb_serial_port * port )
{
if ( ! port - > sysrq ) {
port - > sysrq = jiffies + HZ * 5 ;
return 1 ;
}
port - > sysrq = 0 ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( usb_serial_handle_break ) ;
2011-01-14 16:30:21 +03:00
/**
2013-10-09 19:01:10 +04: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 16:30:21 +03:00
*/
void usb_serial_handle_dcd_change ( struct usb_serial_port * usb_port ,
struct tty_struct * tty , unsigned int status )
{
struct tty_port * port = & usb_port - > port ;
2013-03-21 15:36:27 +04:00
dev_dbg ( & usb_port - > dev , " %s - status %d \n " , __func__ , status ) ;
2011-01-14 16:30:21 +03:00
2013-09-16 10:41:00 +04: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 16:30:21 +03:00
if ( status )
wake_up_interruptible ( & port - > open_wait ) ;
else if ( tty & & ! C_CLOCAL ( tty ) )
tty_hangup ( tty ) ;
}
EXPORT_SYMBOL_GPL ( usb_serial_handle_dcd_change ) ;
2009-08-28 23:54:27 +04: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 ] ;
2010-02-17 18:05:47 +03:00
if ( ! test_bit ( ASYNCB_INITIALIZED , & port - > port . flags ) )
2009-08-28 23:54:27 +04:00
continue ;
2011-11-06 22:06:37 +04:00
if ( port - > bulk_in_size ) {
r = usb_serial_generic_submit_read_urbs ( port ,
GFP_NOIO ) ;
2009-08-28 23:54:27 +04:00
if ( r < 0 )
c + + ;
}
2010-05-06 01:57:37 +04:00
if ( port - > bulk_out_size ) {
2013-10-09 19:01:11 +04:00
r = usb_serial_generic_write_start ( port , GFP_NOIO ) ;
2009-08-28 23:54:27 +04:00
if ( r < 0 )
c + + ;
}
}
return c ? - EIO : 0 ;
}
EXPORT_SYMBOL_GPL ( usb_serial_generic_resume ) ;