2009-06-17 14:16:54 +04:00
/*
2010-03-19 03:13:59 +03:00
* Mobile action cable mode switcher
2009-06-17 14:16:54 +04:00
*
2010-03-19 03:13:59 +03:00
* Copyright ( C ) 2008 - 2010 Dan Williams < dcbw @ redhat . com >
2009-06-17 14:16:54 +04:00
* Copyright ( C ) 2008 Peter Henn < support @ option . com >
*
* Heavily based on the ' ozerocdoff ' tool by Peter Henn .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details :
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <signal.h>
# include <stdarg.h>
# include <getopt.h>
# include <usb.h>
# include "utils.h"
# include "ma8280p_us.h"
struct usb_dev_handle * handle = NULL ;
typedef struct usb_device * ( * FindFunc ) ( int vid , int pid ) ;
typedef int ( * SwitchFunc ) ( struct usb_dev_handle * dh , struct usb_device * dev ) ;
typedef enum {
ST_UNKNOWN = 0 ,
ST_MA8280P
} SwitchType ;
typedef struct SwitchEntry {
SwitchType st ;
const char * clopt ;
FindFunc find_func ;
SwitchFunc switch_func ;
} SwitchEntry ;
static SwitchEntry switch_types [ ] = {
{ ST_MA8280P , " mobile-action-8280p " , NULL , ma8280p_switch } ,
{ ST_UNKNOWN , NULL , NULL }
} ;
static struct usb_device *
generic_find ( int vid , int pid )
{
struct usb_bus * bus ;
struct usb_device * dev ;
for ( bus = usb_get_busses ( ) ; bus ; bus = bus - > next ) {
for ( dev = bus - > devices ; dev ; dev = dev - > next ) {
if ( dev - > descriptor . idVendor = = vid & & dev - > descriptor . idProduct = = pid ) {
debug ( " Found device '%s' " , dev - > filename ) ;
return dev ;
}
}
}
return NULL ;
}
static void
release_usb_device ( int param )
{
usb_release_interface ( handle , 0 ) ;
usb_close ( handle ) ;
}
static void
print_usage ( void )
{
2010-03-19 03:13:59 +03:00
printf ( " Usage: mobile-action-modeswitch [-hdq] [-l <file>] -v <vendor-id> -p <product-id> -t <type> \n "
2009-06-17 14:16:54 +04:00
" -h, --help show this help message \n "
" -v, --vendor <n> target USB vendor ID \n "
" -p, --product <n> target USB product ID \n "
" -t, --type <type> type of switch to attempt, varies by device: \n "
" mobile-action-8280p - For Mobile Action 8xxxP USB cables \n "
" -l, --log <file> log output to a file \n "
" -q, --quiet don't print anything to stdout \n "
" -d, --debug display debugging messages \n \n "
" Examples: \n "
2010-03-19 03:13:59 +03:00
" mobile-action-modeswitch -v 0x0df7 -p 0x8000 -t mobile-action-8280p \n " ) ;
2009-06-17 14:16:54 +04:00
}
static SwitchEntry *
parse_type ( const char * s )
{
SwitchEntry * entry = & switch_types [ 0 ] ;
while ( entry - > clopt ) {
if ( ! strcmp ( entry - > clopt , s ) )
return entry ;
entry + + ;
}
return NULL ;
}
static void
do_exit ( int val )
{
log_shutdown ( ) ;
exit ( val ) ;
}
int main ( int argc , char * * argv )
{
static struct option options [ ] = {
{ " help " , no_argument , NULL , ' h ' } ,
{ " vendor " , required_argument , NULL , ' v ' } ,
{ " product " , required_argument , NULL , ' p ' } ,
{ " type " , required_argument , NULL , ' t ' } ,
{ " log " , required_argument , NULL , ' l ' } ,
{ " debug " , no_argument , NULL , ' d ' } ,
{ " quiet " , no_argument , NULL , ' q ' } ,
{ NULL , 0 , NULL , 0 }
} ;
struct usb_device * dev ;
int vid = 0 , pid = 0 ;
const char * logpath = NULL ;
char buffer [ 256 ] ;
int ret , quiet = 0 , debug = 0 ;
SwitchEntry * sentry = NULL ;
while ( 1 ) {
int option ;
option = getopt_long ( argc , argv , " hv:p:l:t:dq " , options , NULL ) ;
if ( option = = - 1 )
break ;
switch ( option ) {
case ' v ' :
vid = strtol ( optarg , NULL , 0 ) ;
break ;
case ' p ' :
pid = strtol ( optarg , NULL , 0 ) ;
break ;
case ' t ' :
sentry = parse_type ( optarg ) ;
if ( ! sentry ) {
error ( " unknown switch type '%s' " , optarg ) ;
print_usage ( ) ;
exit ( 1 ) ;
}
break ;
case ' l ' :
logpath = optarg ;
break ;
case ' q ' :
quiet = 1 ;
break ;
case ' d ' :
debug = 1 ;
break ;
case ' h ' :
default :
print_usage ( ) ;
exit ( 1 ) ;
}
}
if ( log_startup ( logpath , debug , quiet ) ) {
fprintf ( stderr , " Couldn't open/create logfile %s " , logpath ) ;
exit ( 2 ) ;
}
if ( ! sentry ) {
if ( ! quiet )
print_usage ( ) ;
else
error ( " missing device switch type. " ) ;
do_exit ( 3 ) ;
}
if ( ! vid | | ! pid ) {
if ( ! quiet )
print_usage ( ) ;
else
error ( " missing vendor and device IDs. " ) ;
do_exit ( 3 ) ;
}
usb_init ( ) ;
if ( usb_find_busses ( ) < 0 ) {
error ( " no USB busses found. " ) ;
do_exit ( 4 ) ;
}
if ( usb_find_devices ( ) < 0 ) {
error ( " no USB devices found. " ) ;
do_exit ( 4 ) ;
}
if ( sentry - > find_func )
dev = ( * sentry - > find_func ) ( vid , pid ) ;
else
dev = generic_find ( vid , pid ) ;
if ( dev = = NULL ) {
error ( " no device found. " ) ;
do_exit ( 5 ) ;
}
handle = usb_open ( dev ) ;
if ( handle = = NULL ) {
error ( " %s: could not access the device. " ,
dev - > filename ) ;
do_exit ( 6 ) ;
}
/* detach running default driver */
signal ( SIGTERM , release_usb_device ) ;
ret = usb_get_driver_np ( handle , 0 , buffer , sizeof ( buffer ) ) ;
if ( ret = = 0 ) {
debug ( " %s: found already attached driver '%s' " , dev - > filename , buffer ) ;
ret = usb_detach_kernel_driver_np ( handle , 0 ) ;
if ( ret ! = 0 ) {
debug ( " %s: error: unable to detach current driver. " , dev - > filename ) ;
usb_close ( handle ) ;
do_exit ( 7 ) ;
}
}
ret = usb_claim_interface ( handle , 0 ) ;
if ( ret ! = 0 ) {
debug ( " %s: couldn't claim device's USB interface: %d. " ,
dev - > filename , ret ) ;
usb_close ( handle ) ;
do_exit ( 8 ) ;
}
ret = ( * sentry - > switch_func ) ( handle , dev ) ;
if ( ret < 0 ) {
2010-03-19 03:13:59 +03:00
debug ( " %s: failed to switch device to serial mode. " , dev - > filename ) ;
2009-06-17 14:16:54 +04:00
usb_release_interface ( handle , 0 ) ;
usb_close ( handle ) ;
do_exit ( 9 ) ;
}
usb_release_interface ( handle , 0 ) ;
ret = usb_close ( handle ) ;
if ( ret < 0 )
debug ( " %s: failed to close the device. " , dev - > filename ) ;
do_exit ( 0 ) ;
return 0 ;
}