#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "vk3344"
static dev_t vk3344_number;
static struct class *vk3344_class;
int vk3344_attach( struct i2c_adapter *adapter, int address, int kind );
static int vk3344_probe( struct i2c_adapter *adapter );
static int vk3344_detach(struct i2c_adapter *adap);
int vk3344_open( struct inode *inode, struct file *file );
ssize_t vk3344_read( struct file *file, char *buf, size_t count, loff_t *ppos );
static long vk3344_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static int vk3344_release(struct inode *inode, struct file *file);
ssize_t vk3344_write( struct file *file, char *buf, size_t count, loff_t *ppos );
static const struct file_operations vk3344_fops = {
.owner = THIS_MODULE,
.open = vk3344_open,
.read = vk3344_read,
.write = vk3344_write,
.ioctl = vk3344_ioctl,
.release = vk3344_release,
};
const struct i2c_device_id vk3344_id[] = {
{ "vk3344", 0 },
{ }
};
struct vk3344_bank{
struct i2c_client client;
unsigned int addr;
unsigned short current_pointer;
int bank_number;
struct cdev dev;
char name[30];
}*p_bank;
static unsigned short normal_i2c[] = {
0x48, I2C_CLIENT_END
};
static unsigned short ignore[2] = {
I2C_CLIENT_END, I2C_CLIENT_END
};
static unsigned short probe[2] = {
I2C_CLIENT_END, I2C_CLIENT_END
};
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
.probe = probe,
.ignore = ignore,
.forces = NULL,
};
static struct i2c_driver vk3344_driver = {
.driver = {
.name = "vk3344",
.owner = THIS_MODULE,
},
.id_table = vk3344_id,
.attach_adapter = vk3344_probe,
.detach_client = vk3344_detach,
};
int vk3344_attach( struct i2c_adapter *adapter, int address, int kind )
{
printk( KERN_INFO "----vk3344_attach()--start--\r\n" );
p_bank->client.driver = &vk3344_driver;
p_bank->client.addr = address;
p_bank->client.adapter = adapter;
p_bank->client.flags = 0;
strlcpy( p_bank->client.name, "vk3344", I2C_NAME_SIZE );
printk( KERN_INFO "----address=%d--name=%s--\r\n", p_bank->client.addr, p_bank->client.name );
if( 0 != i2c_attach_client( &p_bank->client ) )
{
printk( KERN_INFO "----i2c_attach_client()--error--\r\n" );
}
printk( KERN_INFO "----vk3344_attach()--end--\r\n" );
return 0;
}
static int vk3344_probe( struct i2c_adapter *adapter )
{
printk( KERN_INFO "----vk3344_probe()--start--\r\n" );
int ret = i2c_probe( adapter, &addr_data, vk3344_attach );
printk( KERN_INFO "----vk3344_probe()--end--ret=%d--\r\n", ret );
return ret;
}
static int vk3344_detach(struct i2c_adapter *adap)
{
return 0;
}
int vk3344_open( struct inode *inode, struct file *file )
{
printk( KERN_INFO "----vk3344_open()--start--\r\n" );
// unsigned int minor = iminor(inode);
printk( KERN_INFO "----iminor()--end--\r\n" );
file->private_data = (struct vk3344_bank*)p_bank;
printk( KERN_INFO "----vk3344_open()--end--\r\n" );
return 0;
}
ssize_t vk3344_read( struct file *file, char *buf, size_t count, loff_t *ppos )
{
#if 0
int ret;
struct i2c_adapter *adap=p_bank->client.adapter;
struct i2c_msg msg[2];
int nmsg = 2;
printk( KERN_INFO "----vk3344_read()--start--\r\n" );
if (count > 8192)
count = 8192;
char *tmp = kmalloc(count,GFP_KERNEL);
char *reg_addr = kmalloc(count,GFP_KERNEL);
if (NULL == tmp && NULL != reg_addr ){
kfree( reg_addr );
printk( KERN_INFO "----kmalloc()--error--\r\n" );
return -ENOMEM;
}
if (NULL == reg_addr && NULL != tmp ){
kfree( tmp );
printk( KERN_INFO "----kmalloc()--error--\r\n" );
return -ENOMEM;
}
memset( tmp, 0x00, count );
memset( reg_addr, 0x00, count );
reg_addr[0] = buf[0];
tmp[0] = buf[0];
msg[0].addr = p_bank->client.addr;
msg[0].flags = p_bank->client.flags & I2C_M_TEN;
msg[0].len = 1;
msg[0].buf = (char *)reg_addr;
printk( KERN_INFO "----kmalloc()msg[0].addr=%d--\r\n", msg[0].addr );
printk( KERN_INFO "----kmalloc()msg[0].flags=%d--\r\n", msg[0].flags );
printk( KERN_INFO "----kmalloc()msg[0].len=%d--\r\n", msg[0].len );
printk( KERN_INFO "----kmalloc()msg[0].buf=%s--\r\n", *msg[0].buf );
msg[1].addr = p_bank->client.addr;
msg[1].flags = p_bank->client.flags & I2C_M_TEN;
msg[1].flags |= I2C_M_RD;
msg[1].len = count;
msg[1].buf = (char *)tmp;
printk( KERN_INFO "----kmalloc()msg[1].addr=%d--\r\n", msg[1].addr );
printk( KERN_INFO "----kmalloc()msg[1].flags=%d--\r\n", msg[1].flags );
printk( KERN_INFO "----kmalloc()msg[1].len=%d--\r\n", msg[1].len );
printk( KERN_INFO "----kmalloc()msg[1].buf=%s--\r\n", *msg[1].buf );
ret = i2c_transfer(adap, msg, nmsg );
printk( KERN_INFO "----i2c_transfer--over--\r\n" );
if (ret >= 0)
{
printk( KERN_INFO "----i2c_transfer--ok--\r\n" );
ret = copy_to_user(buf,tmp,count)?-EFAULT:ret;
printk( KERN_INFO "----copy_to_user--ok--\r\n" );
}
else
{
printk( KERN_INFO "----i2c_transfer--000--\r\n" );
}
kfree(tmp);
kfree( reg_addr );
printk( KERN_INFO "----kfree--ok--\r\n" );
#else
printk( KERN_INFO "----vk3344_read()--start--\r\n" );
// if (count > 8192)
// count = 8192;
unsigned char reg_addr[2] = {0};
unsigned char tmp[2] = {0};//kmalloc(count,GFP_KERNEL);
int len = 1;//count > 1 ? count-1 : 0;
int ret = 0;
// send the reg addr
reg_addr[0] = buf[0];
printk( KERN_INFO "----reg_addr[0]=%d----\r\n", reg_addr[0] );
ret = i2c_master_send( &p_bank->client, reg_addr, 1 );
if (ret != 1)
{
printk( KERN_INFO "----i2c_read()--i2c_master_send--error--ret=%d\r\n", ret );
// kfree( tmp );
return -EIO;
}
else
{
printk( KERN_INFO "----i2c_read()--i2c_master_send--ok--ret=%d\r\n", ret );
}
msleep( 20 );
// read data
ret = i2c_master_recv(&p_bank->client,tmp,len);
if (ret >= 0)
{
printk( KERN_INFO "----i2c_read()--rcv--ok--tmp[0]=%d,tmp[1]=%d--len=%d--ret=%d\r\n", ret, tmp[0],
tmp[1], len );
ret = copy_to_user(buf,tmp,len)?-EFAULT:ret;
printk( KERN_INFO "--copy_to_user()--ret=%d\r\n", ret );
return len;
}
else
{
printk( KERN_INFO "----i2c_read()--i2c_master_recv--error--ret=%d\r\n", ret );
}
// kfree(tmp);
#endif
return 0;
}
ssize_t vk3344_write( struct file *file, char *buf, size_t count, loff_t *ppos )
{
#if 0
int ret;
struct i2c_msg msg;
struct i2c_adapter *adap=p_bank->client.adapter;
char *tmp = kmalloc(count,GFP_KERNEL);
if (count > 8192)
count = 8192;
if (tmp==NULL)
return -ENOMEM;
if (copy_from_user(tmp,buf,count)) {
kfree(tmp);
return -EFAULT;
}
msg.addr = p_bank->client.addr;
msg.flags = p_bank->client.flags & I2C_M_TEN;
msg.len = count;
msg.buf = (char *)tmp;
ret = i2c_transfer(adap, &msg, 1);
kfree(tmp);
#else
int ret = 0;
unsigned char reg_data[2]={buf[0],buf[1]};
msleep( 20 );
ret = i2c_master_send( &p_bank->client, reg_data, 2 );
if (ret != sizeof(reg_data))
{
printk( KERN_INFO "----vk3344_write()--i2c_master_send--error--ret=%d\r\n", ret );
return -EIO;
}
else
{
printk( KERN_INFO "----vk3344_write()--i2c_master_send--ok--reg_data[0]=%d,reg_data[1]=%d\r\n",
reg_data[0], reg_data[1] );
}
#endif
return (ret == 1) ? count : ret;
}
static long vk3344_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return 0;
}
static int vk3344_release(struct inode *inode, struct file *file)
{
// struct i2c_client *client = file->private_data->client;
// i2c_put_adapter(client.adapter);
// kfree(client);
file->private_data = NULL;
return 0;
}
int __init vk3344_init(void)
{
printk( KERN_INFO "--vk3344_init()-- start--\r\n" );
p_bank = kmalloc( sizeof( struct vk3344_bank ), GFP_KERNEL );
if( !p_bank )
{
printk( KERN_INFO "--kmalloc()-- ERROR--\r\n" );
return -1;
}
memset( p_bank, 0x00, sizeof( struct vk3344_bank ) );
vk3344_number = 0;
//register_chrdev_region( vk3344_number, 1, "vk3344");
printk( KERN_INFO "--class_create()-- start--\r\n" );
if ( alloc_chrdev_region( &vk3344_number, 0, 1, "vk3344") < 0 )
{
printk( KERN_INFO "Can`t register device\n" );
return -1;
}
printk( KERN_INFO "--class_create()-- start vk3344_number = %d--\r\n", vk3344_number );
printk( KERN_INFO "--vk3344_number = %d--MAJOR=%d--MINOR=%d--\r\n", vk3344_number, MAJOR(vk3344_number),
MINOR(vk3344_number) );
printk( KERN_INFO "--MAKDEV=%d-- vk3344_number=%d--\r\n", MKDEV( MAJOR(vk3344_number), 0 ), MKDEV( MAJOR
(vk3344_number), MINOR(vk3344_number) ));
vk3344_class = class_create( THIS_MODULE, "vk3344" );
if (IS_ERR(vk3344_class)) {
printk( KERN_INFO "--class_create()--error()\n");
return -1;
}
cdev_init( &p_bank->dev, &vk3344_fops );
strlcpy( p_bank->name, DEVICE_NAME, 6 );
kobject_set_name(&p_bank->dev.kobj, p_bank->name);
p_bank->dev.owner = THIS_MODULE;
p_bank->dev.ops = &vk3344_fops;
printk( KERN_INFO "--cdev_add()-- start--\r\n" );
if ( cdev_add( &(p_bank->dev), vk3344_number, 1 ) )
{
kfree( p_bank );
printk( KERN_INFO "cdev_add() error\r\n" );
return 1;
}
printk( KERN_INFO "--device_create()-- start--\r\n" );
device_create( vk3344_class, NULL, MKDEV( MAJOR(vk3344_number), 0 ), NULL, "vk3344" );
printk( KERN_INFO "--device_create()-- end--\r\n" );
printk( KERN_INFO "-----vk3344 driver initialized.------\r\n" );
i2c_add_driver( &vk3344_driver );
return 0;
}
static void __exit vk3344_exit(void)
{
i2c_del_driver(&vk3344_driver);
cdev_del( &p_bank->dev );
unregister_chrdev_region( vk3344_number, 1 );
//class_device_destroy( vk3344_class, vk334_number );
class_destroy(vk3344_class);
kfree( p_bank );
return;
}
MODULE_DESCRIPTION("vk3344 /dev entries driver");
MODULE_LICENSE("GPL");
module_init(vk3344_init);
module_exit(vk3344_exit);