2005-04-17 02:20:36 +04:00
/*
2006-12-10 23:21:31 +03:00
i2c - dev . c - i2c - bus driver , char device interface
2005-04-17 02:20:36 +04:00
Copyright ( C ) 1995 - 97 Simon G . Vogl
Copyright ( C ) 1998 - 99 Frodo Looijaard < frodol @ dds . nl >
Copyright ( C ) 2003 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 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 .
*/
/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
But I have used so much of his original code and ideas that it seems
only fair to recognize him as co - author - - Frodo */
/* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
# include <linux/kernel.h>
# include <linux/module.h>
2011-03-20 16:50:52 +03:00
# include <linux/device.h>
# include <linux/notifier.h>
2005-04-17 02:20:36 +04:00
# include <linux/fs.h>
# include <linux/slab.h>
# include <linux/init.h>
2006-07-01 19:17:38 +04:00
# include <linux/list.h>
2005-04-17 02:20:36 +04:00
# include <linux/i2c.h>
# include <linux/i2c-dev.h>
2009-02-24 21:19:49 +03:00
# include <linux/jiffies.h>
2010-05-21 20:40:59 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
2007-11-15 21:24:01 +03:00
/*
* An i2c_dev represents an i2c_adapter . . . an I2C or SMBus master , not a
* slave ( i2c_client ) with which messages will be exchanged . It ' s coupled
* with a character special file which is accessed by user mode drivers .
*
* The list of i2c_dev structures is parallel to the i2c_adapter lists
2011-03-20 16:50:52 +03:00
* maintained by the driver model , and is updated using bus notifications .
2007-11-15 21:24:01 +03:00
*/
2005-04-17 02:20:36 +04:00
struct i2c_dev {
2006-07-01 19:17:38 +04:00
struct list_head list ;
2005-04-17 02:20:36 +04:00
struct i2c_adapter * adap ;
2006-07-04 00:46:24 +04:00
struct device * dev ;
2005-04-17 02:20:36 +04:00
} ;
# define I2C_MINORS 256
2006-07-01 19:17:38 +04:00
static LIST_HEAD ( i2c_dev_list ) ;
static DEFINE_SPINLOCK ( i2c_dev_list_lock ) ;
2005-04-17 02:20:36 +04:00
static struct i2c_dev * i2c_dev_get_by_minor ( unsigned index )
{
struct i2c_dev * i2c_dev ;
2006-07-01 19:17:38 +04:00
spin_lock ( & i2c_dev_list_lock ) ;
list_for_each_entry ( i2c_dev , & i2c_dev_list , list ) {
if ( i2c_dev - > adap - > nr = = index )
goto found ;
}
i2c_dev = NULL ;
found :
spin_unlock ( & i2c_dev_list_lock ) ;
2005-04-17 02:20:36 +04:00
return i2c_dev ;
}
static struct i2c_dev * get_free_i2c_dev ( struct i2c_adapter * adap )
{
struct i2c_dev * i2c_dev ;
2006-07-01 19:17:38 +04:00
if ( adap - > nr > = I2C_MINORS ) {
printk ( KERN_ERR " i2c-dev: Out of device minors (%d) \n " ,
adap - > nr ) ;
return ERR_PTR ( - ENODEV ) ;
}
2005-10-18 01:09:43 +04:00
i2c_dev = kzalloc ( sizeof ( * i2c_dev ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! i2c_dev )
return ERR_PTR ( - ENOMEM ) ;
2006-07-01 19:16:57 +04:00
i2c_dev - > adap = adap ;
2006-07-01 19:17:38 +04:00
spin_lock ( & i2c_dev_list_lock ) ;
list_add_tail ( & i2c_dev - > list , & i2c_dev_list ) ;
spin_unlock ( & i2c_dev_list_lock ) ;
2005-04-17 02:20:36 +04:00
return i2c_dev ;
}
static void return_i2c_dev ( struct i2c_dev * i2c_dev )
{
2006-07-01 19:17:38 +04:00
spin_lock ( & i2c_dev_list_lock ) ;
list_del ( & i2c_dev - > list ) ;
spin_unlock ( & i2c_dev_list_lock ) ;
2006-12-10 23:21:33 +03:00
kfree ( i2c_dev ) ;
2005-04-17 02:20:36 +04:00
}
2013-09-27 06:36:11 +04:00
static ssize_t name_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2006-07-04 00:46:24 +04:00
struct i2c_dev * i2c_dev = i2c_dev_get_by_minor ( MINOR ( dev - > devt ) ) ;
2005-12-07 02:33:15 +03:00
if ( ! i2c_dev )
return - ENODEV ;
2005-04-17 02:20:36 +04:00
return sprintf ( buf , " %s \n " , i2c_dev - > adap - > name ) ;
}
2013-09-27 06:36:11 +04:00
static DEVICE_ATTR_RO ( name ) ;
static struct attribute * i2c_attrs [ ] = {
& dev_attr_name . attr ,
NULL ,
} ;
ATTRIBUTE_GROUPS ( i2c ) ;
2005-04-17 02:20:36 +04:00
2007-11-15 21:24:01 +03:00
/* ------------------------------------------------------------------------- */
/*
* After opening an instance of this character special file , a file
* descriptor starts out associated only with an i2c_adapter ( and bus ) .
*
* Using the I2C_RDWR ioctl ( ) , you can then * immediately * issue i2c_msg
* traffic to any devices on the bus used by that adapter . That ' s because
* the i2c_msg vectors embed all the addressing information they need , and
* are submitted directly to an i2c_adapter . However , SMBus - only adapters
* don ' t support that interface .
*
* To use read ( ) / write ( ) system calls on that file descriptor , or to use
* SMBus interfaces ( and work with SMBus - only hosts ! ) , you must first issue
* an I2C_SLAVE ( or I2C_SLAVE_FORCE ) ioctl . That configures an anonymous
* ( never registered ) i2c_client so it holds the addressing information
* needed by those system calls and by this SMBus interface .
*/
2010-05-21 20:40:59 +04:00
static ssize_t i2cdev_read ( struct file * file , char __user * buf , size_t count ,
loff_t * offset )
2005-04-17 02:20:36 +04:00
{
char * tmp ;
int ret ;
2010-05-21 20:40:57 +04:00
struct i2c_client * client = file - > private_data ;
2005-04-17 02:20:36 +04:00
if ( count > 8192 )
count = 8192 ;
2010-05-21 20:40:59 +04:00
tmp = kmalloc ( count , GFP_KERNEL ) ;
if ( tmp = = NULL )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2008-08-11 00:56:16 +04:00
pr_debug ( " i2c-dev: i2c-%d reading %zu bytes. \n " ,
2013-01-24 02:07:38 +04:00
iminor ( file_inode ( file ) ) , count ) ;
2005-04-17 02:20:36 +04:00
2010-05-21 20:40:59 +04:00
ret = i2c_master_recv ( client , tmp , count ) ;
2005-04-17 02:20:36 +04:00
if ( ret > = 0 )
2010-05-21 20:40:59 +04:00
ret = copy_to_user ( buf , tmp , count ) ? - EFAULT : ret ;
2005-04-17 02:20:36 +04:00
kfree ( tmp ) ;
return ret ;
}
2010-05-21 20:40:59 +04:00
static ssize_t i2cdev_write ( struct file * file , const char __user * buf ,
size_t count , loff_t * offset )
2005-04-17 02:20:36 +04:00
{
int ret ;
char * tmp ;
2010-05-21 20:40:57 +04:00
struct i2c_client * client = file - > private_data ;
2005-04-17 02:20:36 +04:00
if ( count > 8192 )
count = 8192 ;
i2c-dev: Use memdup_user
Use memdup_user when user data is immediately copied into the allocated
region. Note that in the second case, the ++i is no longer necessary, as
the last value is already freed if needed by the call to memdup_user.
The semantic patch that makes this change is as follows:
(http://coccinelle.lip6.fr/)
// <smpl>
@@
expression from,to,size,flag;
position p;
identifier l1,l2;
@@
- to = \(kmalloc@p\|kzalloc@p\)(size,flag);
+ to = memdup_user(from,size);
if (
- to==NULL
+ IS_ERR(to)
|| ...) {
<+... when != goto l1;
- -ENOMEM
+ PTR_ERR(to)
...+>
}
- if (copy_from_user(to, from, size) != 0) {
- <+... when != goto l2;
- -EFAULT
- ...+>
- }
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
2010-08-11 20:20:55 +04:00
tmp = memdup_user ( buf , count ) ;
if ( IS_ERR ( tmp ) )
return PTR_ERR ( tmp ) ;
2005-04-17 02:20:36 +04:00
2008-08-11 00:56:16 +04:00
pr_debug ( " i2c-dev: i2c-%d writing %zu bytes. \n " ,
2013-01-24 02:07:38 +04:00
iminor ( file_inode ( file ) ) , count ) ;
2005-04-17 02:20:36 +04:00
2010-05-21 20:40:59 +04:00
ret = i2c_master_send ( client , tmp , count ) ;
2005-04-17 02:20:36 +04:00
kfree ( tmp ) ;
return ret ;
}
2008-01-27 20:14:51 +03:00
static int i2cdev_check ( struct device * dev , void * addrp )
{
struct i2c_client * client = i2c_verify_client ( dev ) ;
if ( ! client | | client - > addr ! = * ( unsigned int * ) addrp )
return 0 ;
return dev - > driver ? - EBUSY : 0 ;
}
2010-08-11 20:21:02 +04:00
/* walk up mux tree */
static int i2cdev_check_mux_parents ( struct i2c_adapter * adapter , int addr )
{
2010-10-24 20:16:57 +04:00
struct i2c_adapter * parent = i2c_parent_is_i2c_adapter ( adapter ) ;
2010-08-11 20:21:02 +04:00
int result ;
result = device_for_each_child ( & adapter - > dev , & addr , i2cdev_check ) ;
2010-10-24 20:16:57 +04:00
if ( ! result & & parent )
result = i2cdev_check_mux_parents ( parent , addr ) ;
2010-08-11 20:21:02 +04:00
return result ;
}
/* recurse down mux tree */
static int i2cdev_check_mux_children ( struct device * dev , void * addrp )
{
int result ;
if ( dev - > type = = & i2c_adapter_type )
result = device_for_each_child ( dev , addrp ,
i2cdev_check_mux_children ) ;
else
result = i2cdev_check ( dev , addrp ) ;
return result ;
}
2007-11-15 21:24:01 +03:00
/* This address checking function differs from the one in i2c-core
in that it considers an address with a registered device , but no
2008-01-27 20:14:51 +03:00
driver bound to it , as NOT busy . */
2007-11-15 21:24:01 +03:00
static int i2cdev_check_addr ( struct i2c_adapter * adapter , unsigned int addr )
{
2010-10-24 20:16:57 +04:00
struct i2c_adapter * parent = i2c_parent_is_i2c_adapter ( adapter ) ;
2010-08-11 20:21:02 +04:00
int result = 0 ;
2010-10-24 20:16:57 +04:00
if ( parent )
result = i2cdev_check_mux_parents ( parent , addr ) ;
2010-08-11 20:21:02 +04:00
if ( ! result )
result = device_for_each_child ( & adapter - > dev , & addr ,
i2cdev_check_mux_children ) ;
return result ;
2007-11-15 21:24:01 +03:00
}
2015-09-08 12:05:49 +03:00
static noinline int i2cdev_ioctl_rdwr ( struct i2c_client * client ,
2008-04-23 00:16:47 +04:00
unsigned long arg )
2005-04-17 02:20:36 +04:00
{
struct i2c_rdwr_ioctl_data rdwr_arg ;
struct i2c_msg * rdwr_pa ;
u8 __user * * data_ptrs ;
2008-04-23 00:16:47 +04:00
int i , res ;
if ( copy_from_user ( & rdwr_arg ,
( struct i2c_rdwr_ioctl_data __user * ) arg ,
sizeof ( rdwr_arg ) ) )
return - EFAULT ;
/* Put an arbitrary limit on the number of messages that can
* be sent at once */
2015-09-08 12:05:49 +03:00
if ( rdwr_arg . nmsgs > I2C_RDWR_IOCTL_MAX_MSGS )
2008-04-23 00:16:47 +04:00
return - EINVAL ;
2012-01-12 23:32:04 +04:00
rdwr_pa = memdup_user ( rdwr_arg . msgs ,
rdwr_arg . nmsgs * sizeof ( struct i2c_msg ) ) ;
if ( IS_ERR ( rdwr_pa ) )
return PTR_ERR ( rdwr_pa ) ;
2008-04-23 00:16:47 +04:00
data_ptrs = kmalloc ( rdwr_arg . nmsgs * sizeof ( u8 __user * ) , GFP_KERNEL ) ;
if ( data_ptrs = = NULL ) {
kfree ( rdwr_pa ) ;
return - ENOMEM ;
}
res = 0 ;
for ( i = 0 ; i < rdwr_arg . nmsgs ; i + + ) {
2012-05-30 12:55:34 +04:00
/* Limit the size of the message to a sane amount */
if ( rdwr_pa [ i ] . len > 8192 ) {
2008-04-23 00:16:47 +04:00
res = - EINVAL ;
break ;
}
2012-05-30 12:55:34 +04:00
2008-04-23 00:16:47 +04:00
data_ptrs [ i ] = ( u8 __user * ) rdwr_pa [ i ] . buf ;
i2c-dev: Use memdup_user
Use memdup_user when user data is immediately copied into the allocated
region. Note that in the second case, the ++i is no longer necessary, as
the last value is already freed if needed by the call to memdup_user.
The semantic patch that makes this change is as follows:
(http://coccinelle.lip6.fr/)
// <smpl>
@@
expression from,to,size,flag;
position p;
identifier l1,l2;
@@
- to = \(kmalloc@p\|kzalloc@p\)(size,flag);
+ to = memdup_user(from,size);
if (
- to==NULL
+ IS_ERR(to)
|| ...) {
<+... when != goto l1;
- -ENOMEM
+ PTR_ERR(to)
...+>
}
- if (copy_from_user(to, from, size) != 0) {
- <+... when != goto l2;
- -EFAULT
- ...+>
- }
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
2010-08-11 20:20:55 +04:00
rdwr_pa [ i ] . buf = memdup_user ( data_ptrs [ i ] , rdwr_pa [ i ] . len ) ;
if ( IS_ERR ( rdwr_pa [ i ] . buf ) ) {
res = PTR_ERR ( rdwr_pa [ i ] . buf ) ;
2008-04-23 00:16:47 +04:00
break ;
}
2012-05-30 12:55:34 +04:00
/*
* If the message length is received from the slave ( similar
* to SMBus block read ) , we must ensure that the buffer will
* be large enough to cope with a message length of
* I2C_SMBUS_BLOCK_MAX as this is the maximum underlying bus
* drivers allow . The first byte in the buffer must be
* pre - filled with the number of extra bytes , which must be
* at least one to hold the message length , but can be
* greater ( for example to account for a checksum byte at
* the end of the message . )
*/
if ( rdwr_pa [ i ] . flags & I2C_M_RECV_LEN ) {
if ( ! ( rdwr_pa [ i ] . flags & I2C_M_RD ) | |
rdwr_pa [ i ] . buf [ 0 ] < 1 | |
rdwr_pa [ i ] . len < rdwr_pa [ i ] . buf [ 0 ] +
I2C_SMBUS_BLOCK_MAX ) {
res = - EINVAL ;
break ;
}
rdwr_pa [ i ] . len = rdwr_pa [ i ] . buf [ 0 ] ;
}
2008-04-23 00:16:47 +04:00
}
if ( res < 0 ) {
int j ;
for ( j = 0 ; j < i ; + + j )
kfree ( rdwr_pa [ j ] . buf ) ;
kfree ( data_ptrs ) ;
kfree ( rdwr_pa ) ;
return res ;
}
res = i2c_transfer ( client - > adapter , rdwr_pa , rdwr_arg . nmsgs ) ;
while ( i - - > 0 ) {
if ( res > = 0 & & ( rdwr_pa [ i ] . flags & I2C_M_RD ) ) {
if ( copy_to_user ( data_ptrs [ i ] , rdwr_pa [ i ] . buf ,
rdwr_pa [ i ] . len ) )
res = - EFAULT ;
}
kfree ( rdwr_pa [ i ] . buf ) ;
}
kfree ( data_ptrs ) ;
kfree ( rdwr_pa ) ;
return res ;
}
static noinline int i2cdev_ioctl_smbus ( struct i2c_client * client ,
unsigned long arg )
{
struct i2c_smbus_ioctl_data data_arg ;
union i2c_smbus_data temp ;
int datasize , res ;
if ( copy_from_user ( & data_arg ,
( struct i2c_smbus_ioctl_data __user * ) arg ,
sizeof ( struct i2c_smbus_ioctl_data ) ) )
return - EFAULT ;
if ( ( data_arg . size ! = I2C_SMBUS_BYTE ) & &
( data_arg . size ! = I2C_SMBUS_QUICK ) & &
( data_arg . size ! = I2C_SMBUS_BYTE_DATA ) & &
( data_arg . size ! = I2C_SMBUS_WORD_DATA ) & &
( data_arg . size ! = I2C_SMBUS_PROC_CALL ) & &
( data_arg . size ! = I2C_SMBUS_BLOCK_DATA ) & &
( data_arg . size ! = I2C_SMBUS_I2C_BLOCK_BROKEN ) & &
( data_arg . size ! = I2C_SMBUS_I2C_BLOCK_DATA ) & &
( data_arg . size ! = I2C_SMBUS_BLOCK_PROC_CALL ) ) {
dev_dbg ( & client - > adapter - > dev ,
" size out of range (%x) in ioctl I2C_SMBUS. \n " ,
data_arg . size ) ;
return - EINVAL ;
}
/* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
so the check is valid if size = = I2C_SMBUS_QUICK too . */
if ( ( data_arg . read_write ! = I2C_SMBUS_READ ) & &
( data_arg . read_write ! = I2C_SMBUS_WRITE ) ) {
dev_dbg ( & client - > adapter - > dev ,
" read_write out of range (%x) in ioctl I2C_SMBUS. \n " ,
data_arg . read_write ) ;
return - EINVAL ;
}
/* Note that command values are always valid! */
if ( ( data_arg . size = = I2C_SMBUS_QUICK ) | |
( ( data_arg . size = = I2C_SMBUS_BYTE ) & &
( data_arg . read_write = = I2C_SMBUS_WRITE ) ) )
/* These are special: we do not use data */
return i2c_smbus_xfer ( client - > adapter , client - > addr ,
client - > flags , data_arg . read_write ,
data_arg . command , data_arg . size , NULL ) ;
if ( data_arg . data = = NULL ) {
dev_dbg ( & client - > adapter - > dev ,
" data is NULL pointer in ioctl I2C_SMBUS. \n " ) ;
return - EINVAL ;
}
if ( ( data_arg . size = = I2C_SMBUS_BYTE_DATA ) | |
( data_arg . size = = I2C_SMBUS_BYTE ) )
datasize = sizeof ( data_arg . data - > byte ) ;
else if ( ( data_arg . size = = I2C_SMBUS_WORD_DATA ) | |
( data_arg . size = = I2C_SMBUS_PROC_CALL ) )
datasize = sizeof ( data_arg . data - > word ) ;
else /* size == smbus block, i2c block, or block proc. call */
datasize = sizeof ( data_arg . data - > block ) ;
if ( ( data_arg . size = = I2C_SMBUS_PROC_CALL ) | |
( data_arg . size = = I2C_SMBUS_BLOCK_PROC_CALL ) | |
( data_arg . size = = I2C_SMBUS_I2C_BLOCK_DATA ) | |
( data_arg . read_write = = I2C_SMBUS_WRITE ) ) {
if ( copy_from_user ( & temp , data_arg . data , datasize ) )
return - EFAULT ;
}
if ( data_arg . size = = I2C_SMBUS_I2C_BLOCK_BROKEN ) {
/* Convert old I2C block commands to the new
convention . This preserves binary compatibility . */
data_arg . size = I2C_SMBUS_I2C_BLOCK_DATA ;
if ( data_arg . read_write = = I2C_SMBUS_READ )
temp . block [ 0 ] = I2C_SMBUS_BLOCK_MAX ;
}
res = i2c_smbus_xfer ( client - > adapter , client - > addr , client - > flags ,
data_arg . read_write , data_arg . command , data_arg . size , & temp ) ;
if ( ! res & & ( ( data_arg . size = = I2C_SMBUS_PROC_CALL ) | |
( data_arg . size = = I2C_SMBUS_BLOCK_PROC_CALL ) | |
( data_arg . read_write = = I2C_SMBUS_READ ) ) ) {
if ( copy_to_user ( data_arg . data , & temp , datasize ) )
return - EFAULT ;
}
return res ;
}
2008-07-15 00:38:27 +04:00
static long i2cdev_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
2008-04-23 00:16:47 +04:00
{
2010-05-21 20:40:57 +04:00
struct i2c_client * client = file - > private_data ;
2005-04-17 02:20:36 +04:00
unsigned long funcs ;
2005-10-08 01:06:27 +04:00
dev_dbg ( & client - > adapter - > dev , " ioctl, cmd=0x%02x, arg=0x%02lx \n " ,
cmd , arg ) ;
2005-04-17 02:20:36 +04:00
2010-05-21 20:40:59 +04:00
switch ( cmd ) {
2005-04-17 02:20:36 +04:00
case I2C_SLAVE :
case I2C_SLAVE_FORCE :
2006-12-10 23:21:31 +03:00
if ( ( arg > 0x3ff ) | |
2005-04-17 02:20:36 +04:00
( ( ( client - > flags & I2C_M_TEN ) = = 0 ) & & arg > 0x7f ) )
return - EINVAL ;
2007-11-15 21:24:01 +03:00
if ( cmd = = I2C_SLAVE & & i2cdev_check_addr ( client - > adapter , arg ) )
2005-04-17 02:20:36 +04:00
return - EBUSY ;
2007-11-15 21:24:01 +03:00
/* REVISIT: address could become busy later */
2005-04-17 02:20:36 +04:00
client - > addr = arg ;
return 0 ;
case I2C_TENBIT :
if ( arg )
client - > flags | = I2C_M_TEN ;
else
client - > flags & = ~ I2C_M_TEN ;
return 0 ;
case I2C_PEC :
2015-09-11 12:27:18 +03:00
/*
* Setting the PEC flag here won ' t affect kernel drivers ,
* which will be using the i2c_client node registered with
* the driver model core . Likewise , when that client has
* the PEC flag already set , the i2c - dev driver won ' t see
* ( or use ) this setting .
*/
2005-04-17 02:20:36 +04:00
if ( arg )
client - > flags | = I2C_CLIENT_PEC ;
else
client - > flags & = ~ I2C_CLIENT_PEC ;
return 0 ;
case I2C_FUNCS :
funcs = i2c_get_functionality ( client - > adapter ) ;
2006-12-10 23:21:30 +03:00
return put_user ( funcs , ( unsigned long __user * ) arg ) ;
2005-04-17 02:20:36 +04:00
case I2C_RDWR :
2015-09-08 12:05:49 +03:00
return i2cdev_ioctl_rdwr ( client , arg ) ;
2005-04-17 02:20:36 +04:00
case I2C_SMBUS :
2008-04-23 00:16:47 +04:00
return i2cdev_ioctl_smbus ( client , arg ) ;
2005-04-17 02:20:36 +04:00
2007-10-14 01:56:32 +04:00
case I2C_RETRIES :
client - > adapter - > retries = arg ;
break ;
case I2C_TIMEOUT :
2009-02-24 21:19:49 +03:00
/* For historical reasons, user-space sets the timeout
* value in units of 10 ms .
*/
client - > adapter - > timeout = msecs_to_jiffies ( arg * 10 ) ;
2007-10-14 01:56:32 +04:00
break ;
2005-04-17 02:20:36 +04:00
default :
2007-10-14 01:56:32 +04:00
/* NOTE: returning a fault code here could cause trouble
* in buggy userspace code . Some old kernel bugs returned
* zero in this case , and userspace code might accidentally
* have depended on that bug .
*/
return - ENOTTY ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
static int i2cdev_open ( struct inode * inode , struct file * file )
{
unsigned int minor = iminor ( inode ) ;
struct i2c_client * client ;
struct i2c_adapter * adap ;
struct i2c_dev * i2c_dev ;
i2c_dev = i2c_dev_get_by_minor ( minor ) ;
2009-12-06 19:06:26 +03:00
if ( ! i2c_dev )
return - ENODEV ;
2005-04-17 02:20:36 +04:00
adap = i2c_get_adapter ( i2c_dev - > adap - > nr ) ;
2009-12-06 19:06:26 +03:00
if ( ! adap )
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2007-11-15 21:24:01 +03:00
/* This creates an anonymous i2c_client, which may later be
* pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE .
*
* This client is * * NEVER REGISTERED * * with the driver model
* or I2C core code ! ! It just holds private copies of addressing
* information and maybe a PEC flag .
*/
2006-07-01 19:20:57 +04:00
client = kzalloc ( sizeof ( * client ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! client ) {
i2c_put_adapter ( adap ) ;
2009-12-06 19:06:26 +03:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
2006-07-01 19:20:57 +04:00
snprintf ( client - > name , I2C_NAME_SIZE , " i2c-dev %d " , adap - > nr ) ;
2005-04-17 02:20:36 +04:00
client - > adapter = adap ;
file - > private_data = client ;
2009-12-06 19:06:26 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int i2cdev_release ( struct inode * inode , struct file * file )
{
struct i2c_client * client = file - > private_data ;
i2c_put_adapter ( client - > adapter ) ;
kfree ( client ) ;
file - > private_data = NULL ;
return 0 ;
}
2007-02-12 11:55:32 +03:00
static const struct file_operations i2cdev_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. llseek = no_llseek ,
. read = i2cdev_read ,
. write = i2cdev_write ,
2008-07-15 00:38:27 +04:00
. unlocked_ioctl = i2cdev_ioctl ,
2005-04-17 02:20:36 +04:00
. open = i2cdev_open ,
. release = i2cdev_release ,
} ;
2007-11-15 21:24:01 +03:00
/* ------------------------------------------------------------------------- */
2005-12-07 02:33:15 +03:00
static struct class * i2c_dev_class ;
2005-04-17 02:20:36 +04:00
2011-03-20 16:50:52 +03:00
static int i2cdev_attach_adapter ( struct device * dev , void * dummy )
2005-04-17 02:20:36 +04:00
{
2011-03-20 16:50:52 +03:00
struct i2c_adapter * adap ;
2005-04-17 02:20:36 +04:00
struct i2c_dev * i2c_dev ;
2006-08-15 20:30:24 +04:00
int res ;
2005-04-17 02:20:36 +04:00
2011-03-20 16:50:52 +03:00
if ( dev - > type ! = & i2c_adapter_type )
return 0 ;
adap = to_i2c_adapter ( dev ) ;
2005-04-17 02:20:36 +04:00
i2c_dev = get_free_i2c_dev ( adap ) ;
if ( IS_ERR ( i2c_dev ) )
return PTR_ERR ( i2c_dev ) ;
/* register this i2c device with the driver core */
2008-07-22 07:03:34 +04:00
i2c_dev - > dev = device_create ( i2c_dev_class , & adap - > dev ,
MKDEV ( I2C_MAJOR , adap - > nr ) , NULL ,
" i2c-%d " , adap - > nr ) ;
2006-12-10 23:21:33 +03:00
if ( IS_ERR ( i2c_dev - > dev ) ) {
res = PTR_ERR ( i2c_dev - > dev ) ;
2005-04-17 02:20:36 +04:00
goto error ;
2006-08-15 20:30:24 +04:00
}
2006-09-04 00:19:25 +04:00
pr_debug ( " i2c-dev: adapter [%s] registered as minor %d \n " ,
adap - > name , adap - > nr ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
error :
return_i2c_dev ( i2c_dev ) ;
2006-08-15 20:30:24 +04:00
return res ;
2005-04-17 02:20:36 +04:00
}
2011-03-20 16:50:52 +03:00
static int i2cdev_detach_adapter ( struct device * dev , void * dummy )
2005-04-17 02:20:36 +04:00
{
2011-03-20 16:50:52 +03:00
struct i2c_adapter * adap ;
2005-04-17 02:20:36 +04:00
struct i2c_dev * i2c_dev ;
2011-03-20 16:50:52 +03:00
if ( dev - > type ! = & i2c_adapter_type )
return 0 ;
adap = to_i2c_adapter ( dev ) ;
2006-07-01 19:16:57 +04:00
i2c_dev = i2c_dev_get_by_minor ( adap - > nr ) ;
2006-09-04 00:19:25 +04:00
if ( ! i2c_dev ) /* attach_adapter must have failed */
return 0 ;
2005-04-17 02:20:36 +04:00
return_i2c_dev ( i2c_dev ) ;
2006-07-04 00:46:24 +04:00
device_destroy ( i2c_dev_class , MKDEV ( I2C_MAJOR , adap - > nr ) ) ;
2005-04-17 02:20:36 +04:00
2005-07-31 21:02:53 +04:00
pr_debug ( " i2c-dev: adapter [%s] unregistered \n " , adap - > name ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-11-23 14:33:07 +04:00
static int i2cdev_notifier_call ( struct notifier_block * nb , unsigned long action ,
2011-03-20 16:50:52 +03:00
void * data )
{
struct device * dev = data ;
switch ( action ) {
case BUS_NOTIFY_ADD_DEVICE :
return i2cdev_attach_adapter ( dev , NULL ) ;
case BUS_NOTIFY_DEL_DEVICE :
return i2cdev_detach_adapter ( dev , NULL ) ;
}
return 0 ;
}
static struct notifier_block i2cdev_notifier = {
. notifier_call = i2cdev_notifier_call ,
2005-04-17 02:20:36 +04:00
} ;
2007-11-15 21:24:01 +03:00
/* ------------------------------------------------------------------------- */
/*
* module load / unload record keeping
*/
2005-04-17 02:20:36 +04:00
static int __init i2c_dev_init ( void )
{
int res ;
printk ( KERN_INFO " i2c /dev entries driver \n " ) ;
res = register_chrdev ( I2C_MAJOR , " i2c " , & i2cdev_fops ) ;
if ( res )
goto out ;
2005-12-07 02:33:15 +03:00
i2c_dev_class = class_create ( THIS_MODULE , " i2c-dev " ) ;
2008-09-24 15:39:21 +04:00
if ( IS_ERR ( i2c_dev_class ) ) {
res = PTR_ERR ( i2c_dev_class ) ;
2005-04-17 02:20:36 +04:00
goto out_unreg_chrdev ;
2008-09-24 15:39:21 +04:00
}
2013-09-27 06:36:11 +04:00
i2c_dev_class - > dev_groups = i2c_groups ;
2005-04-17 02:20:36 +04:00
2011-03-20 16:50:52 +03:00
/* Keep track of adapters which will be added or removed later */
res = bus_register_notifier ( & i2c_bus_type , & i2cdev_notifier ) ;
2005-04-17 02:20:36 +04:00
if ( res )
goto out_unreg_class ;
2011-03-20 16:50:52 +03:00
/* Bind to already existing adapters right away */
i2c_for_each_dev ( NULL , i2cdev_attach_adapter ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
out_unreg_class :
2005-12-07 02:33:15 +03:00
class_destroy ( i2c_dev_class ) ;
2005-04-17 02:20:36 +04:00
out_unreg_chrdev :
unregister_chrdev ( I2C_MAJOR , " i2c " ) ;
out :
printk ( KERN_ERR " %s: Driver Initialisation failed \n " , __FILE__ ) ;
return res ;
}
static void __exit i2c_dev_exit ( void )
{
2011-03-20 16:50:52 +03:00
bus_unregister_notifier ( & i2c_bus_type , & i2cdev_notifier ) ;
i2c_for_each_dev ( NULL , i2cdev_detach_adapter ) ;
2005-12-07 02:33:15 +03:00
class_destroy ( i2c_dev_class ) ;
2010-05-21 20:40:59 +04:00
unregister_chrdev ( I2C_MAJOR , " i2c " ) ;
2005-04-17 02:20:36 +04:00
}
MODULE_AUTHOR ( " Frodo Looijaard <frodol@dds.nl> and "
" Simon G. Vogl <simon@tk.uni-linz.ac.at> " ) ;
MODULE_DESCRIPTION ( " I2C /dev entries driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_init ( i2c_dev_init ) ;
module_exit ( i2c_dev_exit ) ;