2014-01-11 00:23:59 +01:00
/*
* Driver for RobotFuzz OSIF
*
* Copyright ( c ) 2013 Andrew Lunn < andrew @ lunn . ch >
* Copyright ( c ) 2007 Barry Carter < Barry . Carter @ robotfuzz . com >
*
* Based on the i2c - tiny - usb by
*
* Copyright ( C ) 2006 Til Harbaum ( Till @ Harbaum . org )
*
* 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 , version 2.
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/i2c.h>
# include <linux/slab.h>
# include <linux/usb.h>
# define OSIFI2C_READ 20
# define OSIFI2C_WRITE 21
# define OSIFI2C_STOP 22
# define OSIFI2C_STATUS 23
# define OSIFI2C_SET_BIT_RATE 24
# define STATUS_ADDRESS_ACK 0
# define STATUS_ADDRESS_NAK 2
struct osif_priv {
struct usb_device * usb_dev ;
struct usb_interface * interface ;
struct i2c_adapter adapter ;
unsigned char status ;
} ;
static int osif_usb_read ( struct i2c_adapter * adapter , int cmd ,
int value , int index , void * data , int len )
{
struct osif_priv * priv = adapter - > algo_data ;
return usb_control_msg ( priv - > usb_dev , usb_rcvctrlpipe ( priv - > usb_dev , 0 ) ,
cmd , USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
USB_DIR_IN , value , index , data , len , 2000 ) ;
}
static int osif_usb_write ( struct i2c_adapter * adapter , int cmd ,
int value , int index , void * data , int len )
{
struct osif_priv * priv = adapter - > algo_data ;
return usb_control_msg ( priv - > usb_dev , usb_sndctrlpipe ( priv - > usb_dev , 0 ) ,
cmd , USB_TYPE_VENDOR | USB_RECIP_INTERFACE ,
value , index , data , len , 2000 ) ;
}
static int osif_xfer ( struct i2c_adapter * adapter , struct i2c_msg * msgs ,
int num )
{
struct osif_priv * priv = adapter - > algo_data ;
struct i2c_msg * pmsg ;
2018-05-09 21:46:58 +02:00
int ret ;
2018-05-09 21:46:57 +02:00
int i ;
2014-01-11 00:23:59 +01:00
2018-05-09 21:46:58 +02:00
for ( i = 0 ; i < num ; i + + ) {
2014-01-11 00:23:59 +01:00
pmsg = & msgs [ i ] ;
if ( pmsg - > flags & I2C_M_RD ) {
2018-05-09 21:46:57 +02:00
ret = osif_usb_read ( adapter , OSIFI2C_READ ,
pmsg - > flags , pmsg - > addr ,
pmsg - > buf , pmsg - > len ) ;
2014-01-11 00:23:59 +01:00
if ( ret ! = pmsg - > len ) {
dev_err ( & adapter - > dev , " failure reading data \n " ) ;
return - EREMOTEIO ;
}
} else {
2018-05-09 21:46:57 +02:00
ret = osif_usb_write ( adapter , OSIFI2C_WRITE ,
pmsg - > flags , pmsg - > addr ,
pmsg - > buf , pmsg - > len ) ;
2014-01-11 00:23:59 +01:00
if ( ret ! = pmsg - > len ) {
dev_err ( & adapter - > dev , " failure writing data \n " ) ;
return - EREMOTEIO ;
}
}
ret = osif_usb_read ( adapter , OSIFI2C_STOP , 0 , 0 , NULL , 0 ) ;
if ( ret ) {
dev_err ( & adapter - > dev , " failure sending STOP \n " ) ;
return - EREMOTEIO ;
}
/* read status */
ret = osif_usb_read ( adapter , OSIFI2C_STATUS , 0 , 0 ,
& priv - > status , 1 ) ;
if ( ret ! = 1 ) {
dev_err ( & adapter - > dev , " failure reading status \n " ) ;
return - EREMOTEIO ;
}
if ( priv - > status ! = STATUS_ADDRESS_ACK ) {
dev_dbg ( & adapter - > dev , " status = %d \n " , priv - > status ) ;
return - EREMOTEIO ;
}
}
return i ;
}
static u32 osif_func ( struct i2c_adapter * adapter )
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL ;
}
2017-01-27 23:36:17 +05:30
static const struct i2c_algorithm osif_algorithm = {
2014-01-11 00:23:59 +01:00
. master_xfer = osif_xfer ,
. functionality = osif_func ,
} ;
# define USB_OSIF_VENDOR_ID 0x1964
# define USB_OSIF_PRODUCT_ID 0x0001
2016-06-02 13:28:48 +08:00
static const struct usb_device_id osif_table [ ] = {
2014-01-11 00:23:59 +01:00
{ USB_DEVICE ( USB_OSIF_VENDOR_ID , USB_OSIF_PRODUCT_ID ) } ,
{ }
} ;
MODULE_DEVICE_TABLE ( usb , osif_table ) ;
static int osif_probe ( struct usb_interface * interface ,
const struct usb_device_id * id )
{
int ret ;
struct osif_priv * priv ;
u16 version ;
priv = devm_kzalloc ( & interface - > dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
priv - > usb_dev = usb_get_dev ( interface_to_usbdev ( interface ) ) ;
priv - > interface = interface ;
usb_set_intfdata ( interface , priv ) ;
priv - > adapter . owner = THIS_MODULE ;
priv - > adapter . class = I2C_CLASS_HWMON ;
priv - > adapter . algo = & osif_algorithm ;
priv - > adapter . algo_data = priv ;
snprintf ( priv - > adapter . name , sizeof ( priv - > adapter . name ) ,
" OSIF at bus %03d device %03d " ,
priv - > usb_dev - > bus - > busnum , priv - > usb_dev - > devnum ) ;
/*
* Set bus frequency . The frequency is :
* 120 , 000 , 000 / ( 16 + 2 * div * 4 ^ prescale ) .
* Using dev = 52 , prescale = 0 give 100 KHz */
ret = osif_usb_read ( & priv - > adapter , OSIFI2C_SET_BIT_RATE , 52 , 0 ,
NULL , 0 ) ;
if ( ret ) {
dev_err ( & interface - > dev , " failure sending bit rate " ) ;
usb_put_dev ( priv - > usb_dev ) ;
return ret ;
}
i2c_add_adapter ( & ( priv - > adapter ) ) ;
version = le16_to_cpu ( priv - > usb_dev - > descriptor . bcdDevice ) ;
dev_info ( & interface - > dev ,
" version %x.%02x found at bus %03d address %03d " ,
version > > 8 , version & 0xff ,
priv - > usb_dev - > bus - > busnum , priv - > usb_dev - > devnum ) ;
return 0 ;
}
static void osif_disconnect ( struct usb_interface * interface )
{
struct osif_priv * priv = usb_get_intfdata ( interface ) ;
i2c_del_adapter ( & ( priv - > adapter ) ) ;
usb_set_intfdata ( interface , NULL ) ;
usb_put_dev ( priv - > usb_dev ) ;
}
static struct usb_driver osif_driver = {
. name = " RobotFuzz Open Source InterFace, OSIF " ,
. probe = osif_probe ,
. disconnect = osif_disconnect ,
. id_table = osif_table ,
} ;
module_usb_driver ( osif_driver ) ;
MODULE_AUTHOR ( " Andrew Lunn <andrew@lunn.ch> " ) ;
MODULE_AUTHOR ( " Barry Carter <barry.carter@robotfuzz.com> " ) ;
MODULE_DESCRIPTION ( " RobotFuzz OSIF driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;