做中间件,最首要的原则就是内聚,由于驱动程序的特殊性,不可避免的要开源,这对知识产权与中间件的可移植性都有负面的影响。但很多情况下,Kernel对于通用设备都提供了User Space的访问接口,可以在应用程序中直接访问设备,例如,本文将要提到的i2c-dev,就避免的在中间件发布时,提供驱动程序的问题。
i2c-dev提供了i2c设备的/dev接口,该用户层接口基于i2c adapter访问连接的i2c设备。要使用i2c的/dev接口,要在kernel中的打开i2c device interface的支持:driver->I2C support->I2C device interface,加载新的kernel后,可以在/dev目录下找到i2c的adapter,命名方式采用i2c-%d(i2c-0, i2c-1, etc.)
User Space程序编写:
int file;
int adapter_nr = 2; /* probably dynamically determined */
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
file = open(filename, O_RDWR);
if (file < 0) {
/* ERROR HANDLING; you can check errno to see what went wrong */
exit(1);
}
采用SMBus方式访问的i2c设备,要单独设置i2c设备的地址:
int addr = 0x40; /* The I2C address */
if (ioctl(file, I2C_SLAVE, addr) < 0) {
/* ERROR HANDLING; you can check errno to see what went wrong */
exit(1);
}
__u8 register = 0x10; /* Device register to access */
__s32 res;
char buf[10];
/* Using SMBus commands */
res = i2c_smbus_read_word_data(file, register);
if (res < 0) {
/* ERROR HANDLING: i2c transaction failed */
} else {
/* res contains the read word */
}
/* Using I2C Write, equivalent of
i2c_smbus_write_word_data(file, register, 0x6543) */
buf[0] = register;
buf[1] = 0x43;
buf[2] = 0x65;
if (write(file, buf, 3) ! =3) {
/* ERROR HANDLING: i2c transaction failed */
}
/* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
if (read(file, buf, 1) != 1) {
/* ERROR HANDLING: i2c transaction failed */
} else {
/* buf[0] contains the read byte */
}
上面代码中用到的smbus系列接口在标准kernel中未提供,原型在i2c-tools这个工具里面。
同时,i2c device interface还支持i2c协议直接操作,例程如下:
bool I2cReadBlock( int fd, uint8_t reg, uint8_t * data, int16_t len )
{
struct i2c_rdwr_ioctl_data _data;
struct i2c_msg _msg[2];
int _retry = 0, _len;
_data.nmsgs = 2;
_data.msgs = &_msg;
_data.msgs[0].addr = I2C_DEV_ADDR;
_data.msgs[0].flags = 0;
_data.msgs[0].len = 1;
_data.msgs[0].buf = ®
_data.msgs[1].addr = I2C_DEV_ADDR;
_data.msgs[1].flags = I2C_M_RD;
_data.msgs[1].len = len;
_data.msgs[1].buf = data;
ioctl( fd, I2C_RDWR, ( unsigned long )&_data );
return TRUE;
}
bool I2cWriteBlock( int fd, uint8_t reg, uint8_t * data, int16_t len )
{
struct i2c_rdwr_ioctl_data _data;
struct i2c_msg _msg;
uint8_t _buf[ 1 + len ];
int _retry = 0;
_data.nmsgs = 1;
_data.msgs = &_msg;
_buf[0] = reg;
memcpy( _buf + 1, data, len );
_data.msgs[0].addr = I2C_DEV_ADDR;
_data.msgs[0].flags = 0;
_data.msgs[0].len = 1 + len;
_data.msgs[0].buf = _buf;
ioctl( fd, I2C_RDWR, ( unsigned long )&_data );
return TRUE;
}