2005-04-17 02:20:36 +04:00
/*
* USB Serial Converter Generic functions
*
* 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>
# 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>
2005-04-17 02:20:36 +04:00
2006-12-17 23:50:24 +03:00
2005-04-17 02:20:36 +04:00
static int debug ;
# ifdef CONFIG_USB_SERIAL_GENERIC
2007-03-23 22:51:55 +03:00
static int generic_probe ( struct usb_interface * interface ,
const struct usb_device_id * id ) ;
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. */
2006-12-17 23:50:24 +03:00
/* we want to look at all devices, as the vendor/product id can change
* depending on the command line argument */
static struct usb_device_id generic_serial_ids [ ] = {
{ . driver_info = 42 } ,
{ }
} ;
static struct usb_driver generic_driver = {
. name = " usbserial_generic " ,
. probe = generic_probe ,
. disconnect = usb_serial_disconnect ,
. id_table = generic_serial_ids ,
. no_dynamic_id = 1 ,
} ;
2005-04-17 02:20:36 +04:00
/* All of the device info needed for the Generic Serial Converter */
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 ,
2006-12-17 23:50:24 +03:00
. usb_driver = & generic_driver ,
2005-04-17 02:20:36 +04:00
. num_ports = 1 ,
. shutdown = usb_serial_generic_shutdown ,
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
} ;
static int generic_probe ( struct usb_interface * interface ,
const struct usb_device_id * id )
{
const struct usb_device_id * id_pattern ;
id_pattern = usb_match_id ( interface , generic_device_ids ) ;
if ( id_pattern ! = NULL )
return usb_serial_probe ( interface , id ) ;
return - ENODEV ;
}
# endif
2008-07-22 14:11:55 +04:00
int usb_serial_generic_register ( int _debug )
2005-04-17 02:20:36 +04:00
{
int retval = 0 ;
debug = _debug ;
# 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
/* register our generic driver with ourselves */
2008-07-22 14:11:55 +04:00
retval = usb_serial_register ( & usb_serial_generic_device ) ;
2005-04-17 02:20:36 +04:00
if ( retval )
goto exit ;
retval = usb_register ( & generic_driver ) ;
if ( retval )
usb_serial_deregister ( & usb_serial_generic_device ) ;
exit :
# 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
/* remove our generic driver */
usb_deregister ( & generic_driver ) ;
2008-07-22 14:11:55 +04:00
usb_serial_deregister ( & usb_serial_generic_device ) ;
2005-04-17 02:20:36 +04:00
# endif
}
2008-07-22 14:09:07 +04:00
int usb_serial_generic_open ( struct tty_struct * tty ,
struct usb_serial_port * port , struct file * filp )
2005-04-17 02:20:36 +04:00
{
struct usb_serial * serial = port - > serial ;
int result = 0 ;
2007-02-01 22:08:18 +03:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:55 +04:00
/* force low_latency on so that our tty_push actually forces the data
through , otherwise it is scheduled , and with high data rates ( like
with OHCI ) data can get lost . */
2008-07-22 14:09:07 +04:00
if ( tty )
tty - > low_latency = 1 ;
2005-04-17 02:20:36 +04:00
2007-02-01 22:08:18 +03:00
/* clear the throttle flags */
spin_lock_irqsave ( & port - > lock , flags ) ;
port - > throttled = 0 ;
port - > throttle_req = 0 ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
/* if we have a bulk endpoint, start reading from it */
2005-04-17 02:20:36 +04:00
if ( serial - > num_bulk_in ) {
/* Start reading from the device */
2008-07-22 14:11:55 +04:00
usb_fill_bulk_urb ( port - > read_urb , serial - > dev ,
usb_rcvbulkpipe ( serial - > dev ,
port - > bulk_in_endpointAddress ) ,
2005-04-17 02:20:36 +04:00
port - > read_urb - > transfer_buffer ,
port - > read_urb - > transfer_buffer_length ,
( ( serial - > type - > read_bulk_callback ) ?
serial - > type - > read_bulk_callback :
usb_serial_generic_read_bulk_callback ) ,
port ) ;
result = usb_submit_urb ( port - > read_urb , GFP_KERNEL ) ;
if ( result )
2008-07-22 14:11:55 +04:00
dev_err ( & port - > dev ,
" %s - failed resubmitting read urb, error %d \n " ,
__func__ , result ) ;
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
2008-07-22 14:09:07 +04:00
static void generic_cleanup ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
struct usb_serial * serial = port - > serial ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2005-04-17 02:20:36 +04:00
if ( serial - > dev ) {
/* shutdown any bulk reads that might be going on */
if ( serial - > num_bulk_out )
usb_kill_urb ( port - > write_urb ) ;
if ( serial - > num_bulk_in )
usb_kill_urb ( port - > read_urb ) ;
}
}
2007-04-27 22:54:57 +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 ] ;
2008-07-22 14:09:07 +04:00
if ( port - > port . count & & port - > read_urb ) {
2007-04-27 22:54:57 +04:00
r = usb_submit_urb ( port - > read_urb , GFP_NOIO ) ;
if ( r < 0 )
c + + ;
}
}
return c ? - EIO : 0 ;
}
2009-02-06 17:37:14 +03:00
EXPORT_SYMBOL_GPL ( usb_serial_generic_resume ) ;
2007-04-27 22:54:57 +04:00
2008-07-22 14:09:07 +04:00
void usb_serial_generic_close ( struct tty_struct * tty ,
2008-07-22 14:11:55 +04:00
struct usb_serial_port * port , struct file * filp )
2005-04-17 02:20:36 +04:00
{
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2008-07-22 14:11:55 +04:00
generic_cleanup ( port ) ;
2005-04-17 02:20:36 +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
{
struct usb_serial * serial = port - > serial ;
int result ;
unsigned char * data ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2005-04-17 02:20:36 +04:00
if ( count = = 0 ) {
2008-03-04 03:08:34 +03:00
dbg ( " %s - write request of 0 bytes " , __func__ ) ;
2008-07-22 14:11:55 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/* only do something if we have a bulk out endpoint */
if ( serial - > num_bulk_out ) {
2007-10-20 02:05:19 +04:00
unsigned long flags ;
spin_lock_irqsave ( & port - > lock , flags ) ;
2005-04-23 23:49:16 +04:00
if ( port - > write_urb_busy ) {
2007-10-20 02:05:19 +04:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - already writing " , __func__ ) ;
2005-04-23 23:49:16 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-04-23 23:49:16 +04:00
port - > write_urb_busy = 1 ;
2007-10-20 02:05:19 +04:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:55 +04:00
count = ( count > port - > bulk_out_size ) ?
port - > bulk_out_size : count ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:11:55 +04:00
memcpy ( port - > write_urb - > transfer_buffer , buf , count ) ;
2005-04-17 02:20:36 +04:00
data = port - > write_urb - > transfer_buffer ;
2008-03-04 03:08:34 +03:00
usb_serial_debug_data ( debug , & port - > dev , __func__ , count , data ) ;
2005-04-17 02:20:36 +04:00
/* set up our urb */
2008-07-22 14:11:55 +04:00
usb_fill_bulk_urb ( port - > write_urb , serial - > dev ,
usb_sndbulkpipe ( serial - > dev ,
port - > bulk_out_endpointAddress ) ,
2005-04-17 02:20:36 +04:00
port - > write_urb - > transfer_buffer , count ,
2008-07-22 14:11:55 +04:00
( ( serial - > type - > write_bulk_callback ) ?
2005-04-17 02:20:36 +04:00
serial - > type - > write_bulk_callback :
2008-07-22 14:11:55 +04:00
usb_serial_generic_write_bulk_callback ) ,
port ) ;
2005-04-17 02:20:36 +04:00
/* send the data out the bulk port */
2005-04-23 23:49:16 +04:00
port - > write_urb_busy = 1 ;
2005-04-17 02:20:36 +04:00
result = usb_submit_urb ( port - > write_urb , GFP_ATOMIC ) ;
2005-04-23 23:49:16 +04:00
if ( result ) {
2008-07-22 14:11:55 +04:00
dev_err ( & port - > dev ,
" %s - failed submitting write urb, error %d \n " ,
__func__ , result ) ;
/* don't have to grab the lock here, as we will
retry if ! = 0 */
2005-04-23 23:49:16 +04:00
port - > write_urb_busy = 0 ;
} else
2005-04-17 02:20:36 +04:00
result = count ;
return result ;
}
/* no bulk out, so return 0 bytes written */
2005-04-23 23:49:16 +04:00
return 0 ;
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 ;
2005-04-17 02:20:36 +04:00
struct usb_serial * serial = port - > serial ;
int room = 0 ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2005-04-23 23:49:16 +04:00
2008-04-08 20:16:06 +04:00
/* FIXME: Locking */
2005-04-17 02:20:36 +04:00
if ( serial - > num_bulk_out ) {
2005-10-15 04:21:50 +04:00
if ( ! ( port - > write_urb_busy ) )
2005-04-17 02:20:36 +04:00
room = port - > bulk_out_size ;
}
2008-03-04 03:08:34 +03:00
dbg ( " %s - returns %d " , __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 ;
2005-04-17 02:20:36 +04:00
struct usb_serial * serial = port - > serial ;
int chars = 0 ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2005-04-17 02:20:36 +04:00
2008-04-08 20:16:06 +04:00
/* FIXME: Locking */
2005-04-17 02:20:36 +04:00
if ( serial - > num_bulk_out ) {
2005-04-23 23:49:16 +04:00
if ( port - > write_urb_busy )
2005-04-17 02:20:36 +04:00
chars = port - > write_urb - > transfer_buffer_length ;
}
2008-03-04 03:08:34 +03:00
dbg ( " %s - returns %d " , __func__ , chars ) ;
2008-07-22 14:09:07 +04:00
return chars ;
2005-04-17 02:20:36 +04:00
}
2007-05-07 14:09:33 +04:00
static void resubmit_read_urb ( struct usb_serial_port * port , gfp_t mem_flags )
2005-04-17 02:20:36 +04:00
{
2007-02-01 22:08:18 +03:00
struct urb * urb = port - > read_urb ;
2007-05-07 14:09:33 +04:00
struct usb_serial * serial = port - > serial ;
2005-04-17 02:20:36 +04:00
int result ;
2007-02-01 22:08:18 +03:00
/* Continue reading from device */
2008-07-22 14:11:55 +04:00
usb_fill_bulk_urb ( urb , serial - > dev ,
usb_rcvbulkpipe ( serial - > dev ,
port - > bulk_in_endpointAddress ) ,
2007-05-07 14:09:33 +04:00
urb - > transfer_buffer ,
urb - > transfer_buffer_length ,
2008-07-22 14:11:55 +04:00
( ( serial - > type - > read_bulk_callback ) ?
serial - > type - > read_bulk_callback :
2005-04-17 02:20:36 +04:00
usb_serial_generic_read_bulk_callback ) , port ) ;
2007-05-07 14:09:33 +04:00
result = usb_submit_urb ( urb , mem_flags ) ;
2005-04-17 02:20:36 +04:00
if ( result )
2008-07-22 14:11:55 +04:00
dev_err ( & port - > dev ,
" %s - failed resubmitting read urb, error %d \n " ,
__func__ , result ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-01 22:08:18 +03:00
2007-05-07 14:09:33 +04:00
/* Push data to tty layer and resubmit the bulk read URB */
2008-07-22 14:09:07 +04:00
static void flush_and_resubmit_read_urb ( struct usb_serial_port * port )
2007-05-07 14:09:33 +04:00
{
struct urb * urb = port - > read_urb ;
2008-10-13 13:39:46 +04:00
struct tty_struct * tty = tty_port_tty_get ( & port - > port ) ;
2007-05-07 14:09:33 +04:00
int room ;
/* Push data to tty */
if ( tty & & urb - > actual_length ) {
room = tty_buffer_request_room ( tty , urb - > actual_length ) ;
if ( room ) {
tty_insert_flip_string ( tty , urb - > transfer_buffer , room ) ;
2008-03-05 10:28:42 +03:00
tty_flip_buffer_push ( tty ) ;
2007-05-07 14:09:33 +04:00
}
}
2008-10-13 13:39:46 +04:00
tty_kref_put ( tty ) ;
2007-05-07 14:09:33 +04:00
resubmit_read_urb ( port , GFP_ATOMIC ) ;
}
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-06-16 02:44:13 +04:00
int status = urb - > status ;
2007-10-28 15:24:16 +03:00
unsigned long flags ;
2007-02-01 22:08:18 +03:00
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2007-02-01 22:08:18 +03:00
2007-06-16 02:44:13 +04:00
if ( unlikely ( status ! = 0 ) ) {
dbg ( " %s - nonzero read bulk status received: %d " ,
2008-03-04 03:08:34 +03:00
__func__ , status ) ;
2007-02-01 22:08:18 +03:00
return ;
}
2008-07-22 14:11:55 +04:00
usb_serial_debug_data ( debug , & port - > dev , __func__ ,
urb - > actual_length , data ) ;
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 ) ;
2007-05-07 14:09:33 +04:00
flush_and_resubmit_read_urb ( port ) ;
2008-07-22 14:11:55 +04:00
} else
2008-03-05 10:28:42 +03:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
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
{
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2007-06-16 02:44:13 +04:00
int status = urb - > status ;
2005-04-17 02:20:36 +04:00
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2005-04-17 02:20:36 +04:00
2005-04-23 23:49:16 +04:00
port - > write_urb_busy = 0 ;
2007-06-16 02:44:13 +04:00
if ( status ) {
dbg ( " %s - nonzero write bulk status received: %d " ,
2008-03-04 03:08:34 +03:00
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
return ;
}
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 ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2007-02-01 22:08:18 +03:00
/* Set the throttle request flag. It will be picked up
* by usb_serial_generic_read_bulk_callback ( ) . */
spin_lock_irqsave ( & port - > lock , flags ) ;
port - > throttle_req = 1 ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
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 ;
unsigned long flags ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2007-02-01 22:08:18 +03:00
/* Clear the throttle flags */
spin_lock_irqsave ( & port - > lock , flags ) ;
was_throttled = port - > throttled ;
port - > throttled = port - > throttle_req = 0 ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
if ( was_throttled ) {
2007-05-07 14:09:33 +04:00
/* Resume reading from device */
resubmit_read_urb ( port , GFP_KERNEL ) ;
2007-02-01 22:08:18 +03:00
}
}
2008-07-22 14:11:55 +04:00
void usb_serial_generic_shutdown ( struct usb_serial * serial )
2005-04-17 02:20:36 +04:00
{
int i ;
2008-03-04 03:08:34 +03:00
dbg ( " %s " , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* stop reads and writes on all ports */
2008-07-22 14:11:55 +04:00
for ( i = 0 ; i < serial - > num_ports ; + + i )
2005-04-17 02:20:36 +04:00
generic_cleanup ( serial - > port [ i ] ) ;
}