static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)//传入参数是一个适配器指针,返回一个i2c_dev其adap成员指向传入的适配器指针
{
struct i2c_dev *i2c_dev; //声明一个i2c 设备指针,最终用于返回。
if (adap->nr >= I2C_MINORS) {//查看传入的适配器指针,看挂在上面的次设备号是否在允许范围内
printk(KERN_ERR "i2c-dev: Out of device minors (%d)\n",
adap->nr);
return ERR_PTR(-ENODEV);
}
i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL);//对i2c_dev 获取一块内存
if (!i2c_dev)
return ERR_PTR(-ENOMEM);
i2c_dev->adap = adap;//将新定义i2c_dev的适配器成员指向传入的适配器
spin_lock(&i2c_dev_list_lock); //获得自旋锁
list_add_tail(&i2c_dev->list, &i2c_dev_list);//将新定义的i2c-dev 加入到设备列表
spin_unlock(&i2c_dev_list_lock);//释放自旋锁
return i2c_dev;//返回得到的设备
}
static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
{
struct i2c_dev *i2c_dev; //声明一个i2c_dev结构指针用于最终返回
spin_lock(&i2c_dev_list_lock);//锁定i2c设备列表自旋锁(自旋锁锁定后其它进程无法访问,详情请google自旋锁或并发与竞态。
list_for_each_entry(i2c_dev, &i2c_dev_list, list) {//对i2c设备列表进行轮询,每次都把i2c_dev指针指向表上项
if (i2c_dev->adap->nr == index) // 如果设备列表上某一项的adap成员的nr(即次设备号)成员与转入此函数的次设备号一致,则找到了。
goto found;//转到found
}
i2c_dev = NULL;//如果遍历列表都找不到,将i2c_dev 置为空指针。
found:
spin_unlock(&i2c_dev_list_lock);//释放自旋锁
return i2c_dev;//返回这个i2c_dev指针,如果找到,则指向找到的i2c设备,否则为0。
}
另附:
struct i2c_dev {
struct list_head list;
struct i2c_adapter *adap;
struct device *dev;
};
i2c-core.c作为核心文件,肯定要复杂一些,但也不难,我们先只看函数名:
static int i2c_device_probe
static int i2c_device_remove(struct device *dev)
static void i2c_device_shutdown(struct device *dev)
static int i2c_device_suspend(struct device *dev, pm_message_t mesg)
static int i2c_device_resume(struct device *dev)
static void i2c_client_release(struct device *dev)
static void i2c_client_dev_release(struct device *dev)
static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
struct i2c_client *i2c_verify_client(struct device *dev)
struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
void i2c_unregister_device(struct i2c_client *client)
static int dummy_probe(struct i2c_client *client, const struct i2c_device_id *id)
static int dummy_remove(struct i2c_client *client)
static struct i2c_driver dummy_driver = {
.driver.name = "dummy",
.probe = dummy_probe,
.remove = dummy_remove,
.id_table = dummy_id,
};
struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address)
static void i2c_adapter_dev_release(struct device *dev)
static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
static int i2c_do_add_adapter(struct device_driver *d, void *data)
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
static int i2c_register_adapter(struct i2c_adapter *adap)
int i2c_add_adapter(struct i2c_adapter *adapter)
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
static int i2c_do_del_adapter(struct device_driver *d, void *data)
int i2c_del_adapter(struct i2c_adapter *adap)
static int __attach_adapter(struct device *dev, void *data)
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
static int __detach_adapter(struct device *dev, void *data)
void i2c_del_driver(struct i2c_driver *driver)
static int __i2c_check_addr(struct device *dev, void *addrp)
static int i2c_check_addr(struct i2c_adapter *adapter, int addr)
int i2c_attach_client(struct i2c_client *client)
int i2c_detach_client(struct i2c_client *client)
struct i2c_client *i2c_use_client(struct i2c_client *client)
void i2c_release_client(struct i2c_client *client)
static int i2c_cmd(struct device *dev, void *_arg)
void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
static int __init i2c_init(void)
static void __exit i2c_exit(void)
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind, int (*found_proc) (struct i2c_adapter *, int, int))
int i2c_probe(struct i2c_adapter *adapter, const struct i2c_client_address_data *address_data, int (*found_proc) (struct i2c_adapter *, int, int))
static int i2c_detect_address(struct i2c_client *temp_client, int kind, struct i2c_driver *driver)
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
i2c_new_probed_device(struct i2c_adapter *adap, struct i2c_board_info *info, unsigned short const *addr_list)
struct i2c_adapter* i2c_get_adapter(int id)
void i2c_put_adapter(struct i2c_adapter *adap)
static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg)
s32 i2c_smbus_read_byte(struct i2c_client *client)
s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)
s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)
s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command)
s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
s32 i2c_smbus_process_call(struct i2c_client *client, u8 command, u16 value)
s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, u8 *values)
s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, u8 length, const u8 *values)
s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 length, u8 *values)
s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, u8 length, const u8 *values)
static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data)
s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int protocol, union i2c_smbus_data *data)
我们可以看到,里面有很大一部分是关于driver的,一部分是关于client的,一部分是关于device的,一部分是关于adapter的。
driver和device是两个软件上的概念,每个driver对应一个主设备号,每个device对应一个次设备号。
adapter和client是两个硬件上的概念。
adapter对于嵌入式而言相当于我们板子上的 i2c控制器,这个控制器可以根据我们的要求产生i2c时序。
client是对于嵌入式而言相当于于个支持i2c的eeprom或是ov9650的sccb控制器。
可以看到,这些函数都是定义的一些对上述四类内容的操作,也就是说i2c-core.c相当于提供了一个可用的函数库,供处部调用,因此我们在里面经常看到的就是:
EXPORT_SYMBOL(。。。);这个宏将这些函数作为符号导出,使其它文件中的函数可以使用,而不必包含相应的头文件。
Linux内核中I2C系统代码比较简单,想想也是,本来I2C就是一个比较简单的总线协议,代码当然也简单了。
关于I2C的代码全部都在/driver/I2C目录下。
我们看这个目录下只有三个子目录和三个.c文件。
.h文件我们先不用管.
这三个目录是:
algos bus 和chip.
algos是英文"算法"(algorithm).下面提供的是I2C总线时序的算法。
bus下面是对应于不同平台的I2C总线。
chip则是提供的一些常用的支持IIC 的芯片的驱动方法。
打开algos目录,发现只有i2c-algo-bit.c被编译成了.o文件,也就是说其它文件现在是不起作用的。
打开bus目录,发现只有i2c-s3c2410.c编译成了.o文件,也就是说,对我的系统只和到了i2c-s3c2410.c文件。
打开chip目录,则发现没有.c文件被编译成.o文件。
这样一来,再加上i2c主目录下的三个 .c文件,总共就5个文件被用到。我们只有分析这个5个文件就可以了。他们是:
i2c-core.c i2c-boardinfo.c i2c-dev.c i2c-s3c2410.c i2c-algo-bit.c
我们打开主机目录下的Makefile:
obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o
obj-$(CONFIG_I2C) += i2c-core.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
obj-y += busses/ chips/ algos/
好,我们按顺序分析,先来看i2c-boardinfo.c
其代码如下:(下面是去掉了注释以后的全部代码)
#include <linux/kernel.h>
#include <linux/i2c.h>
#include "i2c-core.h"
DEFINE_MUTEX(__i2c_board_lock);
EXPORT_SYMBOL_GPL(__i2c_board_lock);
LIST_HEAD(__i2c_board_list);
EXPORT_SYMBOL_GPL(__i2c_board_list);
int __i2c_first_dynamic_bus_num;
EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);
int __init
i2c_register_board_info(int busnum, //这里面的唯一的函数:i2c_register_board_info.
struct i2c_board_info const *info, unsigned len)
{
int status;
mutex_lock(&__i2c_board_lock);
if (busnum >= __i2c_first_dynamic_bus_num)
__i2c_first_dynamic_bus_num = busnum + 1;
for (status = 0; len; len--, info++) {
struct i2c_devinfo *devinfo;
devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
if (!devinfo) {
pr_debug("i2c-core: can't register boardinfo!\n");
status = -ENOMEM;
break;
}
devinfo->busnum = busnum;
devinfo->board_info = *info;
list_add_tail(&devinfo->list, &__i2c_board_list);
}
mutex_unlock(&__i2c_board_lock);
return status;
}
我们来看一下i2c_board_info:
struct i2c_board_info {
char type[I2C_NAME_SIZE];
unsigned short flags;
unsigned short addr;
void * platform_data;
struct dev_archdata * archdata;
int irq;
};
再看一下,别人写驱动时调用这个函数的例子:
1. 在arch/arm/mach-s3c2410/mach-smdk2410.c
static struct i2c_board_info __initdata i2c_devices[] =
{
{
I2C_BOARD_INFO("rtc-s35390a", 0x30),
.platform_data = &s35390a,
},
{
I2C_BOARD_INFO("eeprom",0x50),
},
};
并且在smdk2410_init()函数后面调用
i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
添加i2c device信息
I2C_BOARD_INFO ( dev_type,
dev_addr);
显见,这里面只有两个成员是比较重要的。第一个是type这将用一个字符串描述。第二个是地址,就是你要控制的芯片的iic地址。
我们可以回头再看这个函数:它在内部声明了一个 struct i2c_devinfo *devinfo;然后用传进的参数i2c_board_info * info去初始化这个
devinfo的一个成员:board_info,从名字很容易看出就是来初始化一个表示设备信息的结构体的板级信息成员。
最后: list_add_tail(&devinfo->list, &__i2c_board_list);
不用这个那个list_add_tail函数原型也知道,这句就是把我们刚刚声明的那个devinfo加入到__i2c_board_list这个链表上。
到此这个函数就分析完了。
__i2c_board_list显然是一个维护设备i2c板级信息的链表。
static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_dev *i2c_dev = i2c_dev_get_by_minor(MINOR(dev->devt));//通设备的次设备号,找到设备的i2c_dev结构。
if (!i2c_dev)//查看该结构是否被找到,(找不到真正设备会返回0)
return -ENODEV;
return sprintf(buf, "%s\n", i2c_dev->adap->name);//将适配器名字传入buf
}
这个函数的作用就是把传入的设备的适配器的名称,传给一同传入的那个buf字符串。
static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count, loff_t *offset)//i2c设备的读操作
{
char *tmp;
int ret;
struct i2c_client *client = (struct i2c_client *)file->private_data; //从设备文件的私有信息中读出设备的i2c_client结构
if (count > 8192)//单次读出字符最大值
count = 8192;
tmp = kmalloc(count,GFP_KERNEL);//获得一片存储区
if (tmp==NULL)
return -ENOMEM;
pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
iminor(file->f_path.dentry->d_inode), count);
ret = i2c_master_recv(client,tmp,count); //调用i2c_master_recv函数,通过i2c操作读得数据。
if (ret >= 0)
ret = copy_to_user(buf,tmp,count)?-EFAULT:ret;//将从芯片中得到的数据拷到用户空间。
kfree(tmp);//释放申请 的内存。
return ret;
}
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)//将一个i2c_msg通过适配器传送出去
{
int ret;
if (adap->algo->master_xfer) { //适配器(adap)的算法(algo)中,有主机传送算法(master_xfer)吗?
#ifdef DEBUG
for (ret = 0; ret < num; ret++) {
dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0xx, "
"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
}
#endif
if (in_atomic() || irqs_disabled()) { //见这里http://www.linuxsir.org/bbs/thread298668.html
ret = mutex_trylock(&adap->bus_lock);//获取自旋锁
if (!ret)
return -EAGAIN;
} else {
mutex_lock_nested(&adap->bus_lock, adap->level);
}
ret = adap->algo->master_xfer(adap,msgs,num);//调用master_xfer传送信息
mutex_unlock(&adap->bus_lock);//解锁
return ret;
} else {
dev_dbg(&adap->dev, "I2C level transfers not supported\n");
return -EOPNOTSUPP;
}
}
EXPORT_SYMBOL(i2c_transfer);
//这个是I2C ioctl控制函数,命令有I2C_SLAVE,I2C_SLAVE_FORCE,I2C_TENBIT,I2C_PEC,I2C_FUNCS....
static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct i2c_client *client = (struct i2c_client *)file->private_data;//通过打开的文件获取在私有数据指针的client结构体
unsigned long funcs;
dev_dbg(&client->adapter->dev, "ioctl, cmd=0xx, arg=0xlx\n",
cmd, arg);
switch ( cmd ) {
case I2C_SLAVE://设置从设备地址的命令
case I2C_SLAVE_FORCE:
if ((arg > 0x3ff) ||
(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
return -EINVAL;
if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
return -EBUSY;
client->addr = arg;
return 0;//上面是判断从设备是否可用
case I2C_TENBIT://用于设定7位的地址还是10位的地址
if (arg)
client->flags |= I2C_M_TEN;
else
client->flags &= ~I2C_M_TEN;
return 0;
case I2C_PEC:// != 0 to use PEC with SMBus
if (arg)
client->flags |= I2C_CLIENT_PEC;
else
client->flags &= ~I2C_CLIENT_PEC;
return 0;
case I2C_FUNCS://返回能够实现的功能通过arg传递给用户空间
funcs = i2c_get_functionality(client->adapter);
return put_user(funcs, (unsigned long __user *)arg);
case I2C_RDWR://读写
return i2cdev_ioctl_rdrw(client, arg);
case I2C_SMBUS://ioctl的SMBUS传输
return i2cdev_ioctl_smbus(client, arg);
case I2C_RETRIES://设定重发次数
client->adapter->retries = arg;
break;
case I2C_TIMEOUT://设定过时时间
client->adapter->timeout = msecs_to_jiffies(arg * 10);
break;
default:
return -ENOTTY;
}
return 0;
}
一般来说,I2C不同过read和write 进行读写,通过ioctl进行传输。命令是I2C_SMBUS.
即要用到这个函数i2cdev_ioctl_smbus(client, arg)
static noinline int i2cdev_ioctl_smbus(struct i2c_client *client,
unsigned long arg)
{//函数传入的参数有i2c_client(代表一个设备),arg是struct i2c_smbus_ioctl_data类型的结构体(传输要用到的参数设置)
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;//如果从用户空间传入arg参数失败,出错
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;//进行data.size判断,传入的这个不等于其中的一个就会出错。也就是说这里判断支持的传输数据方式
}
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;
}//对传入的data.read_write判断,如果不等于I2C_SMBUS_READ或I2C_SMBUS_WRITE出错
if ((data_arg.size == I2C_SMBUS_QUICK) ||
((data_arg.size == I2C_SMBUS_BYTE) &&
(data_arg.read_write == I2C_SMBUS_WRITE)))
return i2c_smbus_xfer(client->adapter, client->addr,
client->flags, data_arg.read_write,
data_arg.command, data_arg.size, NULL);
//同理判断后进行写调用函数i2c_smbus_xfer()
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
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;
}//获取要传输的数据保存在temp中
if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) {
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;
}
下面是I2C_SMBUS ioctl call中关键的数据结构。
struct i2c_smbus_ioctl_data {
__u8 read_write;//读写
__u8 command;//命令
__u32 size;//大小
union i2c_smbus_data __user *data;//数据类型
};
#define I2C_SMBUS_BLOCK_MAX 32
union i2c_smbus_data {
__u8 byte;//字节
__u16 word;//字
__u8 block[I2C_SMBUS_BLOCK_MAX + 2]; 块
};
说来说去,大家还是不知道数据怎么传送的,到底在哪里传送了呢?关键的是这个函数i2c_smbus_xfer()
这个函数是哪里的,其实这个函数是总线驱动中的一个通信方式函数。在i2c_adapter结构体中的const struct i2c_algorithm *algo结构中的一个指针函数。
struct i2c_algorithm {
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num);
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data);
u32 (*functionality) (struct i2c_adapter *);
};
//其中master_xfer()也是通信方式之一,它通过struct i2c_msg *msgs传入需要的参数。
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data);在总线驱动中没有函数实例,它通过函数i2c_smbus_xfer_emulated()传输。如下:
s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
char read_write, u8 command, int protocol,
union i2c_smbus_data *data)
{
unsigned long orig_jiffies;
int try;
s32 res;
flags &= I2C_M_TEN | I2C_CLIENT_PEC;
if (adapter->algo->smbus_xfer) {
mutex_lock(&adapter->bus_lock);
orig_jiffies = jiffies;
for (res = 0, try = 0; try <= adapter->retries; try++) {
res = adapter->algo->smbus_xfer(adapter, addr, flags,
read_write, command,
protocol, data);
if (res != -EAGAIN)
break;
if (time_after(jiffies,
orig_jiffies + adapter->timeout))
break;
}
mutex_unlock(&adapter->bus_lock);
} else
res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
command, protocol, data);
return res;
}
下面讲解下i2c_smbus_xfer_emulated()函数,我也会是刚看
static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
unsigned short flags,
char read_write, u8 command, int size,
union i2c_smbus_data * data)
{
//参数有struct i2c_adapter * adapter适配器,addr,flags,read_write,size,union i2c_smbus_data * data,这些你懂的。
unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
int num = read_write == I2C_SMBUS_READ?2:1;//读命令num=2,否则为1.
struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
{ addr, flags | I2C_M_RD, 0, msgbuf1 }
};
__u16 flags;
#define I2C_M_TEN 0x0010
#define I2C_M_RD 0x0001
#define I2C_M_NOSTART 0x4000
#define I2C_M_REV_DIR_ADDR 0x2000
#define I2C_M_IGNORE_NAK 0x1000
#define I2C_M_NO_RD_ACK 0x0800
#define I2C_M_RECV_LEN 0x0400
__u16 len;
__u8 *buf;
};
*/
int i;
u8 partial_pec = 0;
int status;
msgbuf0[0] = command;
switch(size) {
case I2C_SMBUS_QUICK:
msg[0].len = 0;
msg[0].flags = flags | (read_write == I2C_SMBUS_READ ?
I2C_M_RD : 0);
num = 1;
break;
case I2C_SMBUS_BYTE:
if (read_write == I2C_SMBUS_READ) {
msg[0].flags = I2C_M_RD | flags;
num = 1;
}
break;
case I2C_SMBUS_BYTE_DATA:
if (read_write == I2C_SMBUS_READ)
msg[1].len = 1;
else {
msg[0].len = 2;
msgbuf0[1] = data->byte;
}
break;
case I2C_SMBUS_WORD_DATA:
if (read_write == I2C_SMBUS_READ)
msg[1].len = 2;
else {
msg[0].len=3;
msgbuf0[1] = data->word & 0xff;
msgbuf0[2] = data->word >> 8;
}
break;
case I2C_SMBUS_PROC_CALL:
num = 2;
read_write = I2C_SMBUS_READ;
msg[0].len = 3;
msg[1].len = 2;
msgbuf0[1] = data->word & 0xff;
msgbuf0[2] = data->word >> 8;
break;
case I2C_SMBUS_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
msg[1].flags |= I2C_M_RECV_LEN;
msg[1].len = 1;
} else {
msg[0].len = data->block[0] + 2;
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
dev_err(&adapter->dev,
"Invalid block write size %d\n",
data->block[0]);
return -EINVAL;
}
for (i = 1; i < msg[0].len; i++)
msgbuf0[i] = data->block[i-1];
}
break;
case I2C_SMBUS_BLOCK_PROC_CALL:
num = 2;
read_write = I2C_SMBUS_READ;
if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
dev_err(&adapter->dev,
"Invalid block write size %d\n",
data->block[0]);
return -EINVAL;
}
msg[0].len = data->block[0] + 2;
for (i = 1; i < msg[0].len; i++)
msgbuf0[i] = data->block[i-1];
msg[1].flags |= I2C_M_RECV_LEN;
msg[1].len = 1;
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
msg[1].len = data->block[0];
} else {
msg[0].len = data->block[0] + 1;
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
dev_err(&adapter->dev,
"Invalid block write size %d\n",
data->block[0]);
return -EINVAL;
}
for (i = 1; i <= data->block[0]; i++)
msgbuf0[i] = data->block[i];
}
break;
default:
dev_err(&adapter->dev, "Unsupported transaction %d\n", size);
return -EOPNOTSUPP;
}
i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK
&& size != I2C_SMBUS_I2C_BLOCK_DATA);
if (i) {
if (!(msg[0].flags & I2C_M_RD)) {
if (num == 1)
i2c_smbus_add_pec(&msg[0]);
else
partial_pec = i2c_smbus_msg_pec(0, &msg[0]);
}
if (msg[num-1].flags & I2C_M_RD)
msg[num-1].len++;
}
status = i2c_transfer(adapter, msg, num);
if (status < 0)
return status;
if (i && (msg[num-1].flags & I2C_M_RD)) {
status = i2c_smbus_check_pec(partial_pec, &msg[num-1]);
if (status < 0)
return status;
}
if (read_write == I2C_SMBUS_READ)
switch(size) {
case I2C_SMBUS_BYTE:
data->byte = msgbuf0[0];
break;
case I2C_SMBUS_BYTE_DATA:
data->byte = msgbuf1[0];
break;
case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_PROC_CALL:
data->word = msgbuf1[0] | (msgbuf1[1] << 8);
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
for (i = 0; i < data->block[0]; i++)
data->block[i+1] = msgbuf1[i];
break;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL:
for (i = 0; i < msgbuf1[0] + 1; i++)
data->block[i] = msgbuf1[i];
break;
}
return 0;
}