2005-04-17 02:20:36 +04:00
/*
* USB HandSpring Visor , Palm m50x , and Sony Clie driver
* ( supports all of the Palm OS USB devices )
*
* Copyright ( C ) 1999 - 2004
* Greg Kroah - Hartman ( greg @ kroah . com )
*
2007-06-12 22:43:37 +04:00
* 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 .
2005-04-17 02:20:36 +04:00
*
2008-07-22 14:12:15 +04:00
* See Documentation / usb / usb - serial . txt for more information on using this
* driver
2005-04-17 02:20:36 +04:00
*
*/
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/tty.h>
# include <linux/tty_driver.h>
# include <linux/tty_flip.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/spinlock.h>
2008-07-22 14:12:15 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <linux/usb.h>
2006-07-12 08:22:58 +04:00
# include <linux/usb/serial.h>
2011-02-07 14:42:36 +03:00
# include <linux/usb/cdc.h>
2005-04-17 02:20:36 +04:00
# include "visor.h"
/*
* Version Information
*/
# define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
# define DRIVER_DESC "USB HandSpring Visor / Palm OS driver"
/* function prototypes for a handspring visor */
2009-09-20 00:13:26 +04:00
static int visor_open ( struct tty_struct * tty , struct usb_serial_port * port ) ;
2009-06-11 15:26:29 +04:00
static void visor_close ( struct usb_serial_port * port ) ;
2008-07-22 14:12:15 +04:00
static int visor_probe ( struct usb_serial * serial ,
const struct usb_device_id * id ) ;
2005-04-17 02:20:36 +04:00
static int visor_calc_num_ports ( struct usb_serial * serial ) ;
2008-07-22 14:12:15 +04:00
static void visor_read_int_callback ( struct urb * urb ) ;
static int clie_3_5_startup ( struct usb_serial * serial ) ;
static int treo_attach ( struct usb_serial * serial ) ;
static int clie_5_attach ( struct usb_serial * serial ) ;
static int palm_os_3_probe ( struct usb_serial * serial ,
const struct usb_device_id * id ) ;
static int palm_os_4_probe ( struct usb_serial * serial ,
const struct usb_device_id * id ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 22:22:54 +04:00
static const struct usb_device_id id_table [ ] = {
2005-04-17 02:20:36 +04:00
{ USB_DEVICE ( HANDSPRING_VENDOR_ID , HANDSPRING_VISOR_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_3_probe } ,
{ USB_DEVICE ( HANDSPRING_VENDOR_ID , HANDSPRING_TREO_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( HANDSPRING_VENDOR_ID , HANDSPRING_TREO600_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
2006-02-19 21:00:04 +03:00
{ USB_DEVICE ( GSPDA_VENDOR_ID , GSPDA_XPLORE_M68_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
2005-04-17 02:20:36 +04:00
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_M500_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_M505_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_M515_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_I705_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_M100_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_M125_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_M130_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_TUNGSTEN_T_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
2005-04-19 04:39:20 +04:00
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_TREO_650 ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
2005-04-17 02:20:36 +04:00
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_TUNGSTEN_Z_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_ZIRE_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_4_0_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_S360_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_4_1_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_NX60_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_NZ90V_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_TJ25_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
2007-08-04 12:19:41 +04:00
{ USB_DEVICE ( ACER_VENDOR_ID , ACER_S10_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
2015-04-22 15:35:09 +03:00
{ USB_DEVICE_INTERFACE_CLASS ( SAMSUNG_VENDOR_ID , SAMSUNG_SCH_I330_ID , 0xff ) ,
2005-04-17 02:20:36 +04:00
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
2008-07-22 14:12:15 +04:00
{ USB_DEVICE ( SAMSUNG_VENDOR_ID , SAMSUNG_SPH_I500_ID ) ,
2005-04-17 02:20:36 +04:00
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
2005-04-19 04:39:20 +04:00
{ USB_DEVICE ( TAPWAVE_VENDOR_ID , TAPWAVE_ZODIAC_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
2008-07-22 14:12:15 +04:00
{ USB_DEVICE ( GARMIN_VENDOR_ID , GARMIN_IQUE_3600_ID ) ,
2005-04-17 02:20:36 +04:00
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( ACEECA_VENDOR_ID , ACEECA_MEZ1000_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( KYOCERA_VENDOR_ID , KYOCERA_7135_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ USB_DEVICE ( FOSSIL_VENDOR_ID , FOSSIL_ABACUS_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ } /* Terminating entry */
} ;
2013-12-29 22:22:54 +04:00
static const struct usb_device_id clie_id_5_table [ ] = {
2005-04-17 02:20:36 +04:00
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_UX50_ID ) ,
. driver_info = ( kernel_ulong_t ) & palm_os_4_probe } ,
{ } /* Terminating entry */
} ;
2013-12-29 22:22:54 +04:00
static const struct usb_device_id clie_id_3_5_table [ ] = {
2005-04-17 02:20:36 +04:00
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_3_5_ID ) } ,
{ } /* Terminating entry */
} ;
2013-12-29 22:22:54 +04:00
static const struct usb_device_id id_table_combined [ ] = {
2005-04-17 02:20:36 +04:00
{ USB_DEVICE ( HANDSPRING_VENDOR_ID , HANDSPRING_VISOR_ID ) } ,
{ USB_DEVICE ( HANDSPRING_VENDOR_ID , HANDSPRING_TREO_ID ) } ,
{ USB_DEVICE ( HANDSPRING_VENDOR_ID , HANDSPRING_TREO600_ID ) } ,
2006-02-19 21:00:04 +03:00
{ USB_DEVICE ( GSPDA_VENDOR_ID , GSPDA_XPLORE_M68_ID ) } ,
2005-04-17 02:20:36 +04:00
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_M500_ID ) } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_M505_ID ) } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_M515_ID ) } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_I705_ID ) } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_M100_ID ) } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_M125_ID ) } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_M130_ID ) } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_TUNGSTEN_T_ID ) } ,
2005-04-19 04:39:20 +04:00
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_TREO_650 ) } ,
2005-04-17 02:20:36 +04:00
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_TUNGSTEN_Z_ID ) } ,
{ USB_DEVICE ( PALM_VENDOR_ID , PALM_ZIRE_ID ) } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_3_5_ID ) } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_4_0_ID ) } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_S360_ID ) } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_4_1_ID ) } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_NX60_ID ) } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_NZ90V_ID ) } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_UX50_ID ) } ,
{ USB_DEVICE ( SONY_VENDOR_ID , SONY_CLIE_TJ25_ID ) } ,
{ USB_DEVICE ( SAMSUNG_VENDOR_ID , SAMSUNG_SCH_I330_ID ) } ,
{ USB_DEVICE ( SAMSUNG_VENDOR_ID , SAMSUNG_SPH_I500_ID ) } ,
2005-04-19 04:39:20 +04:00
{ USB_DEVICE ( TAPWAVE_VENDOR_ID , TAPWAVE_ZODIAC_ID ) } ,
2005-04-17 02:20:36 +04:00
{ USB_DEVICE ( GARMIN_VENDOR_ID , GARMIN_IQUE_3600_ID ) } ,
{ USB_DEVICE ( ACEECA_VENDOR_ID , ACEECA_MEZ1000_ID ) } ,
{ USB_DEVICE ( KYOCERA_VENDOR_ID , KYOCERA_7135_ID ) } ,
{ USB_DEVICE ( FOSSIL_VENDOR_ID , FOSSIL_ABACUS_ID ) } ,
{ } /* Terminating entry */
} ;
2008-07-22 14:12:15 +04:00
MODULE_DEVICE_TABLE ( usb , id_table_combined ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:12:15 +04:00
/* All of the device info needed for the Handspring Visor,
and Palm 4.0 devices */
2005-06-21 08:15:16 +04:00
static struct usb_serial_driver handspring_device = {
2005-06-21 08:15:16 +04:00
. driver = {
. owner = THIS_MODULE ,
2005-06-21 08:15:16 +04:00
. name = " visor " ,
2005-06-21 08:15:16 +04:00
} ,
2005-06-21 08:15:16 +04:00
. description = " Handspring Visor / Palm OS " ,
2005-04-17 02:20:36 +04:00
. id_table = id_table ,
. num_ports = 2 ,
2010-05-16 17:06:55 +04:00
. bulk_out_size = 256 ,
2005-04-17 02:20:36 +04:00
. open = visor_open ,
. close = visor_close ,
2010-05-15 19:53:49 +04:00
. throttle = usb_serial_generic_throttle ,
. unthrottle = usb_serial_generic_unthrottle ,
2005-04-17 02:20:36 +04:00
. attach = treo_attach ,
. probe = visor_probe ,
. calc_num_ports = visor_calc_num_ports ,
. read_int_callback = visor_read_int_callback ,
} ;
/* All of the device info needed for the Clie UX50, TH55 Palm 5.0 devices */
2005-06-21 08:15:16 +04:00
static struct usb_serial_driver clie_5_device = {
2005-06-21 08:15:16 +04:00
. driver = {
. owner = THIS_MODULE ,
2005-06-21 08:15:16 +04:00
. name = " clie_5 " ,
2005-06-21 08:15:16 +04:00
} ,
2005-06-21 08:15:16 +04:00
. description = " Sony Clie 5.0 " ,
2005-04-17 02:20:36 +04:00
. id_table = clie_id_5_table ,
. num_ports = 2 ,
2010-05-16 17:06:55 +04:00
. bulk_out_size = 256 ,
2005-04-17 02:20:36 +04:00
. open = visor_open ,
. close = visor_close ,
2010-05-15 19:53:49 +04:00
. throttle = usb_serial_generic_throttle ,
. unthrottle = usb_serial_generic_unthrottle ,
2005-04-17 02:20:36 +04:00
. attach = clie_5_attach ,
. probe = visor_probe ,
. calc_num_ports = visor_calc_num_ports ,
. read_int_callback = visor_read_int_callback ,
} ;
/* device info for the Sony Clie OS version 3.5 */
2005-06-21 08:15:16 +04:00
static struct usb_serial_driver clie_3_5_device = {
2005-06-21 08:15:16 +04:00
. driver = {
. owner = THIS_MODULE ,
2005-06-21 08:15:16 +04:00
. name = " clie_3.5 " ,
2005-06-21 08:15:16 +04:00
} ,
2005-06-21 08:15:16 +04:00
. description = " Sony Clie 3.5 " ,
2005-04-17 02:20:36 +04:00
. id_table = clie_id_3_5_table ,
. num_ports = 1 ,
2010-05-16 17:06:55 +04:00
. bulk_out_size = 256 ,
2005-04-17 02:20:36 +04:00
. open = visor_open ,
. close = visor_close ,
2010-05-15 19:53:49 +04:00
. throttle = usb_serial_generic_throttle ,
. unthrottle = usb_serial_generic_unthrottle ,
2005-04-17 02:20:36 +04:00
. attach = clie_3_5_startup ,
} ;
2012-02-23 23:57:32 +04:00
static struct usb_serial_driver * const serial_drivers [ ] = {
& handspring_device , & clie_5_device , & clie_3_5_device , NULL
} ;
2005-04-17 02:20:36 +04:00
/******************************************************************************
* Handspring Visor specific driver functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-09-20 00:13:26 +04:00
static int visor_open ( struct tty_struct * tty , struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
int result = 0 ;
if ( ! port - > read_urb ) {
/* this is needed for some brain dead Sony devices */
dev_err ( & port - > dev , " Device lied about number of ports, please use a lower one. \n " ) ;
return - ENODEV ;
}
/* Start reading from the device */
2010-05-15 19:53:49 +04:00
result = usb_serial_generic_open ( tty , port ) ;
if ( result )
2005-04-17 02:20:36 +04:00
goto exit ;
2008-07-22 14:12:15 +04:00
2005-04-17 02:20:36 +04:00
if ( port - > interrupt_in_urb ) {
2012-05-04 03:40:45 +04:00
dev_dbg ( & port - > dev , " adding interrupt input for treo \n " ) ;
2005-04-17 02:20:36 +04:00
result = usb_submit_urb ( port - > interrupt_in_urb , GFP_KERNEL ) ;
if ( result )
2008-07-22 14:12:15 +04:00
dev_err ( & port - > dev ,
" %s - failed submitting interrupt urb, error %d \n " ,
__func__ , result ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:12:15 +04:00
exit :
2005-04-17 02:20:36 +04:00
return result ;
}
2009-06-11 15:26:29 +04:00
static void visor_close ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
unsigned char * transfer_buffer ;
2010-05-15 19:53:49 +04:00
usb_serial_generic_close ( port ) ;
2006-11-08 17:36:55 +03:00
usb_kill_urb ( port - > interrupt_in_urb ) ;
2005-04-17 02:20:36 +04:00
2013-03-21 15:37:47 +04:00
transfer_buffer = kmalloc ( 0x12 , GFP_KERNEL ) ;
if ( ! transfer_buffer )
return ;
usb_control_msg ( port - > serial - > dev ,
2008-01-21 19:44:10 +03:00
usb_rcvctrlpipe ( port - > serial - > dev , 0 ) ,
VISOR_CLOSE_NOTIFICATION , 0xc2 ,
0x0000 , 0x0000 ,
transfer_buffer , 0x12 , 300 ) ;
2013-03-21 15:37:47 +04:00
kfree ( transfer_buffer ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:12:15 +04:00
static void visor_read_int_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
int result ;
2007-06-16 02:44:13 +04:00
switch ( status ) {
2005-04-17 02:20:36 +04:00
case 0 :
/* success */
break ;
case - ECONNRESET :
case - ENOENT :
case - ESHUTDOWN :
/* this urb is terminated, clean up */
2012-05-04 03:40:45 +04:00
dev_dbg ( & port - > dev , " %s - urb shutting down with status: %d \n " ,
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
return ;
default :
2012-05-04 03:40:45 +04:00
dev_dbg ( & port - > dev , " %s - nonzero urb status received: %d \n " ,
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
goto exit ;
}
/*
* This information is still unknown what it can be used for .
* If anyone has an idea , please let the author know . . .
*
* Rumor has it this endpoint is used to notify when data
* is ready to be read from the bulk ones .
*/
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( & port - > dev , __func__ , urb - > actual_length ,
urb - > transfer_buffer ) ;
2005-04-17 02:20:36 +04:00
exit :
2008-07-22 14:12:15 +04:00
result = usb_submit_urb ( urb , GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( result )
2008-07-22 14:12:15 +04:00
dev_err ( & urb - > dev - > dev ,
" %s - Error %d submitting interrupt urb \n " ,
__func__ , result ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:12:15 +04:00
static int palm_os_3_probe ( struct usb_serial * serial ,
const struct usb_device_id * id )
2005-04-17 02:20:36 +04:00
{
struct device * dev = & serial - > dev - > dev ;
struct visor_connection_info * connection_info ;
unsigned char * transfer_buffer ;
char * string ;
int retval = 0 ;
int i ;
int num_ports = 0 ;
2008-07-22 14:12:15 +04:00
transfer_buffer = kmalloc ( sizeof ( * connection_info ) , GFP_KERNEL ) ;
2013-12-29 22:22:56 +04:00
if ( ! transfer_buffer )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
/* send a get connection info request */
2008-07-22 14:12:15 +04:00
retval = usb_control_msg ( serial - > dev ,
2005-04-17 02:20:36 +04:00
usb_rcvctrlpipe ( serial - > dev , 0 ) ,
VISOR_GET_CONNECTION_INFORMATION ,
0xc2 , 0x0000 , 0x0000 , transfer_buffer ,
sizeof ( * connection_info ) , 300 ) ;
if ( retval < 0 ) {
dev_err ( dev , " %s - error %d getting connection information \n " ,
2008-03-04 03:08:34 +03:00
__func__ , retval ) ;
2005-04-17 02:20:36 +04:00
goto exit ;
}
if ( retval = = sizeof ( * connection_info ) ) {
2008-07-22 14:12:15 +04:00
connection_info = ( struct visor_connection_info * )
transfer_buffer ;
2005-04-17 02:20:36 +04:00
num_ports = le16_to_cpu ( connection_info - > num_ports ) ;
for ( i = 0 ; i < num_ports ; + + i ) {
2008-07-22 14:12:15 +04:00
switch (
connection_info - > connections [ i ] . port_function_id ) {
case VISOR_FUNCTION_GENERIC :
string = " Generic " ;
break ;
case VISOR_FUNCTION_DEBUGGER :
string = " Debugger " ;
break ;
case VISOR_FUNCTION_HOTSYNC :
string = " HotSync " ;
break ;
case VISOR_FUNCTION_CONSOLE :
string = " Console " ;
break ;
case VISOR_FUNCTION_REMOTE_FILE_SYS :
string = " Remote File System " ;
break ;
default :
string = " unknown " ;
break ;
2005-04-17 02:20:36 +04:00
}
dev_info ( dev , " %s: port %d, is for %s use \n " ,
2005-06-21 08:15:16 +04:00
serial - > type - > description ,
2005-04-17 02:20:36 +04:00
connection_info - > connections [ i ] . port , string ) ;
}
}
/*
* Handle devices that report invalid stuff here .
*/
if ( num_ports = = 0 | | num_ports > 2 ) {
2008-07-22 14:12:15 +04:00
dev_warn ( dev , " %s: No valid connect info available \n " ,
2005-06-21 08:15:16 +04:00
serial - > type - > description ) ;
2005-04-17 02:20:36 +04:00
num_ports = 2 ;
}
2008-07-22 14:12:15 +04:00
2005-06-21 08:15:16 +04:00
dev_info ( dev , " %s: Number of ports: %d \n " , serial - > type - > description ,
2005-04-17 02:20:36 +04:00
num_ports ) ;
/*
* save off our num_ports info so that we can use it in the
* calc_num_ports callback
*/
usb_set_serial_data ( serial , ( void * ) ( long ) num_ports ) ;
2008-07-22 14:12:15 +04:00
/* ask for the number of bytes available, but ignore the
response as it is broken */
retval = usb_control_msg ( serial - > dev ,
2005-04-17 02:20:36 +04:00
usb_rcvctrlpipe ( serial - > dev , 0 ) ,
VISOR_REQUEST_BYTES_AVAILABLE ,
0xc2 , 0x0000 , 0x0005 , transfer_buffer ,
0x02 , 300 ) ;
if ( retval < 0 )
dev_err ( dev , " %s - error %d getting bytes available request \n " ,
2008-03-04 03:08:34 +03:00
__func__ , retval ) ;
2005-04-17 02:20:36 +04:00
retval = 0 ;
exit :
2008-07-22 14:12:15 +04:00
kfree ( transfer_buffer ) ;
2005-04-17 02:20:36 +04:00
return retval ;
}
2008-07-22 14:12:15 +04:00
static int palm_os_4_probe ( struct usb_serial * serial ,
const struct usb_device_id * id )
2005-04-17 02:20:36 +04:00
{
struct device * dev = & serial - > dev - > dev ;
struct palm_ext_connection_info * connection_info ;
unsigned char * transfer_buffer ;
int retval ;
2008-07-22 14:12:15 +04:00
transfer_buffer = kmalloc ( sizeof ( * connection_info ) , GFP_KERNEL ) ;
2013-12-29 22:22:56 +04:00
if ( ! transfer_buffer )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2008-07-22 14:12:15 +04:00
retval = usb_control_msg ( serial - > dev ,
usb_rcvctrlpipe ( serial - > dev , 0 ) ,
2005-04-17 02:20:36 +04:00
PALM_GET_EXT_CONNECTION_INFORMATION ,
0xc2 , 0x0000 , 0x0000 , transfer_buffer ,
2008-07-22 14:12:15 +04:00
sizeof ( * connection_info ) , 300 ) ;
2005-04-17 02:20:36 +04:00
if ( retval < 0 )
dev_err ( dev , " %s - error %d getting connection info \n " ,
2008-03-04 03:08:34 +03:00
__func__ , retval ) ;
2005-04-17 02:20:36 +04:00
else
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( dev , __func__ , retval , transfer_buffer ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:12:15 +04:00
kfree ( transfer_buffer ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-07-22 14:12:15 +04:00
static int visor_probe ( struct usb_serial * serial ,
const struct usb_device_id * id )
2005-04-17 02:20:36 +04:00
{
int retval = 0 ;
2008-07-22 14:12:15 +04:00
int ( * startup ) ( struct usb_serial * serial ,
const struct usb_device_id * id ) ;
2005-04-17 02:20:36 +04:00
2011-02-07 14:42:36 +03:00
/*
* some Samsung Android phones in modem mode have the same ID
* as SPH - I500 , but they are ACM devices , so dont bind to them
*/
if ( id - > idVendor = = SAMSUNG_VENDOR_ID & &
id - > idProduct = = SAMSUNG_SPH_I500_ID & &
serial - > dev - > descriptor . bDeviceClass = = USB_CLASS_COMM & &
serial - > dev - > descriptor . bDeviceSubClass = =
USB_CDC_SUBCLASS_ACM )
return - ENODEV ;
2005-04-17 02:20:36 +04:00
if ( serial - > dev - > actconfig - > desc . bConfigurationValue ! = 1 ) {
2008-08-21 03:56:34 +04:00
dev_err ( & serial - > dev - > dev , " active config #%d != 1 ?? \n " ,
2005-04-17 02:20:36 +04:00
serial - > dev - > actconfig - > desc . bConfigurationValue ) ;
return - ENODEV ;
}
if ( id - > driver_info ) {
startup = ( void * ) id - > driver_info ;
retval = startup ( serial , id ) ;
}
return retval ;
}
2008-07-22 14:12:15 +04:00
static int visor_calc_num_ports ( struct usb_serial * serial )
2005-04-17 02:20:36 +04:00
{
int num_ports = ( int ) ( long ) ( usb_get_serial_data ( serial ) ) ;
if ( num_ports )
usb_set_serial_data ( serial , NULL ) ;
return num_ports ;
}
2008-07-22 14:12:15 +04:00
static int clie_3_5_startup ( struct usb_serial * serial )
2005-04-17 02:20:36 +04:00
{
struct device * dev = & serial - > dev - > dev ;
int result ;
2009-12-29 01:01:57 +03:00
u8 * data ;
2005-04-17 02:20:36 +04:00
2009-12-29 01:01:57 +03:00
data = kmalloc ( 1 , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
/*
* Note that PEG - 300 series devices expect the following two calls .
*/
/* get the config number */
2008-07-22 14:12:15 +04:00
result = usb_control_msg ( serial - > dev , usb_rcvctrlpipe ( serial - > dev , 0 ) ,
2005-04-17 02:20:36 +04:00
USB_REQ_GET_CONFIGURATION , USB_DIR_IN ,
2009-12-29 01:01:57 +03:00
0 , 0 , data , 1 , 3000 ) ;
2005-04-17 02:20:36 +04:00
if ( result < 0 ) {
2008-07-22 14:12:15 +04:00
dev_err ( dev , " %s: get config number failed: %d \n " ,
__func__ , result ) ;
2009-12-29 01:01:57 +03:00
goto out ;
2005-04-17 02:20:36 +04:00
}
if ( result ! = 1 ) {
2008-07-22 14:12:15 +04:00
dev_err ( dev , " %s: get config number bad return length: %d \n " ,
__func__ , result ) ;
2009-12-29 01:01:57 +03:00
result = - EIO ;
goto out ;
2005-04-17 02:20:36 +04:00
}
/* get the interface number */
2008-07-22 14:12:15 +04:00
result = usb_control_msg ( serial - > dev , usb_rcvctrlpipe ( serial - > dev , 0 ) ,
USB_REQ_GET_INTERFACE ,
2005-04-17 02:20:36 +04:00
USB_DIR_IN | USB_RECIP_INTERFACE ,
2009-12-29 01:01:57 +03:00
0 , 0 , data , 1 , 3000 ) ;
2005-04-17 02:20:36 +04:00
if ( result < 0 ) {
2008-07-22 14:12:15 +04:00
dev_err ( dev , " %s: get interface number failed: %d \n " ,
__func__ , result ) ;
2009-12-29 01:01:57 +03:00
goto out ;
2005-04-17 02:20:36 +04:00
}
if ( result ! = 1 ) {
2008-07-22 14:12:15 +04:00
dev_err ( dev ,
" %s: get interface number bad return length: %d \n " ,
__func__ , result ) ;
2009-12-29 01:01:57 +03:00
result = - EIO ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2010-05-15 19:53:49 +04:00
result = 0 ;
2009-12-29 01:01:57 +03:00
out :
kfree ( data ) ;
return result ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:12:15 +04:00
static int treo_attach ( struct usb_serial * serial )
2005-04-17 02:20:36 +04:00
{
struct usb_serial_port * swap_port ;
/* Only do this endpoint hack for the Handspring devices with
* interrupt in endpoints , which for now are the Treo devices . */
2008-07-22 14:12:15 +04:00
if ( ! ( ( le16_to_cpu ( serial - > dev - > descriptor . idVendor )
= = HANDSPRING_VENDOR_ID ) | |
( le16_to_cpu ( serial - > dev - > descriptor . idVendor )
= = KYOCERA_VENDOR_ID ) ) | |
( serial - > num_interrupt_in = = 0 ) )
2010-05-15 19:53:49 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
/*
2008-07-22 14:12:15 +04:00
* It appears that Treos and Kyoceras want to use the
* 1 st bulk in endpoint to communicate with the 2 nd bulk out endpoint ,
* so let ' s swap the 1 st and 2 nd bulk in and interrupt endpoints .
* Note that swapping the bulk out endpoints would break lots of
2005-04-17 02:20:36 +04:00
* apps that want to communicate on the second port .
*/
# define COPY_PORT(dest, src) \
2008-07-22 14:12:15 +04:00
do { \
2013-05-27 16:44:38 +04:00
int i ; \
\
for ( i = 0 ; i < ARRAY_SIZE ( src - > read_urbs ) ; + + i ) { \
dest - > read_urbs [ i ] = src - > read_urbs [ i ] ; \
dest - > read_urbs [ i ] - > context = dest ; \
dest - > bulk_in_buffers [ i ] = src - > bulk_in_buffers [ i ] ; \
} \
2008-07-22 14:12:15 +04:00
dest - > read_urb = src - > read_urb ; \
dest - > bulk_in_endpointAddress = src - > bulk_in_endpointAddress ; \
dest - > bulk_in_buffer = src - > bulk_in_buffer ; \
2013-05-27 16:44:38 +04:00
dest - > bulk_in_size = src - > bulk_in_size ; \
2008-07-22 14:12:15 +04:00
dest - > interrupt_in_urb = src - > interrupt_in_urb ; \
2013-05-27 16:44:37 +04:00
dest - > interrupt_in_urb - > context = dest ; \
2008-07-22 14:12:15 +04:00
dest - > interrupt_in_endpointAddress = \
src - > interrupt_in_endpointAddress ; \
dest - > interrupt_in_buffer = src - > interrupt_in_buffer ; \
} while ( 0 ) ;
2005-04-17 02:20:36 +04:00
swap_port = kmalloc ( sizeof ( * swap_port ) , GFP_KERNEL ) ;
if ( ! swap_port )
return - ENOMEM ;
COPY_PORT ( swap_port , serial - > port [ 0 ] ) ;
COPY_PORT ( serial - > port [ 0 ] , serial - > port [ 1 ] ) ;
COPY_PORT ( serial - > port [ 1 ] , swap_port ) ;
kfree ( swap_port ) ;
2010-05-15 19:53:49 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:12:15 +04:00
static int clie_5_attach ( struct usb_serial * serial )
2005-04-17 02:20:36 +04:00
{
2010-10-12 03:07:05 +04:00
struct usb_serial_port * port ;
unsigned int pipe ;
int j ;
2008-07-22 14:12:15 +04:00
/* TH55 registers 2 ports.
Communication in from the UX50 / TH55 uses bulk_in_endpointAddress
from port 0. Communication out to the UX50 / TH55 uses
bulk_out_endpointAddress from port 1
2005-04-17 02:20:36 +04:00
Lets do a quick and dirty mapping
*/
2008-07-22 14:12:15 +04:00
2005-04-17 02:20:36 +04:00
/* some sanity check */
if ( serial - > num_ports < 2 )
return - 1 ;
2008-07-22 14:12:15 +04:00
2005-04-17 02:20:36 +04:00
/* port 0 now uses the modified endpoint Address */
2010-10-12 03:07:05 +04:00
port = serial - > port [ 0 ] ;
port - > bulk_out_endpointAddress =
2008-07-22 14:12:15 +04:00
serial - > port [ 1 ] - > bulk_out_endpointAddress ;
2005-04-17 02:20:36 +04:00
2010-10-12 03:07:05 +04:00
pipe = usb_sndbulkpipe ( serial - > dev , port - > bulk_out_endpointAddress ) ;
for ( j = 0 ; j < ARRAY_SIZE ( port - > write_urbs ) ; + + j )
port - > write_urbs [ j ] - > pipe = pipe ;
2010-05-15 19:53:49 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2012-05-09 02:46:14 +04:00
module_usb_serial_driver ( serial_drivers , id_table_combined ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:12:15 +04:00
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;