?? spd.c
字號:
#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/jiffies.h>#include <linux/i2c.h>#include <linux/mutex.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/delay.h>#include <linux/types.h>#include <asm/uaccess_32.h>#define CREATE_AUTO 1/* Addresses to scan *///static unsigned short normal_i2c[] = { 0xA4,0xA5, I2C_CLIENT_END };static unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };/* Insmod parameters */I2C_CLIENT_INSMOD_1(SPD);/* device number */#define SPD_MAJOR (225)#define SPD_MINOR (0)/* device node */#define NODE_NAME ("spd") /* command mode */#define SPD_READ (1)#define SPD_WRITE (0) /* functon prototype declaration */static int spd_attach_adapter(struct i2c_adapter *adapter);static int spd_detect(struct i2c_adapter *adapter, int address, int kind);static int spd_detach_client(struct i2c_client *client);int spd_open(struct inode *inode,struct file *flip);int spd_release(struct inode *inode,struct file *filp);int spd_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg);int spd_command(struct i2c_client *client,unsigned int cmd,void *arg);ssize_t spd_read(struct file *filp,unsigned char __user *buf,size_t count,loff_t *f_pos);ssize_t spd_write(struct file *filp,const unsigned char __user *buf,size_t count,loff_t *f_pos);/* file interface */struct file_operations SPD_fops={ .owner = THIS_MODULE, .ioctl = spd_ioctl, .read = spd_read, .write = spd_write, .open = spd_open, .release = spd_release,};/* device struct */struct spd_dev{ struct cdev cdev;};/* Each client has this additional data */struct spd_data { struct i2c_client client; struct mutex update_lock;};/* This is the driver that will be inserted */static struct i2c_driver spd_driver = { .driver = { .name = "spd", }, .attach_adapter = spd_attach_adapter, .detach_client = spd_detach_client, .command = spd_command,};/* the glogal variable definition */struct spd_dev *SPD_cdev = NULL;struct spd_data *SPD_data = NULL;#ifdef CREATE_AUTOstruct class *SPD_class = NULL;struct class_device *SPD_class_device =NULL;#endif/* the function implement *//* typedef long ssize_t */#define COUNT (1)ssize_t spd_read(struct file *filp,unsigned char __user *buf,size_t count,loff_t *f_pos){ struct i2c_client client; int i; unsigned char result; client = SPD_data->client;#if 0 result = i2c_smbus_read_byte(&client); if(result<0) { printk(KERN_ALERT " read data failed.\n"); goto out; } if(copy_to_user(buf,&result,COUNT)) { result = -EFAULT; goto out; }#else for(i=0;i<count;i++) { result = i2c_smbus_read_byte_data(&client,i); if(result < 0) { printk(KERN_ALERT " read data failed.\n"); goto out; } if(copy_to_user(buf+i,&result,COUNT)) { result = -EFAULT; goto out; } }#endifout: return result;}ssize_t spd_write(struct file *filp,const unsigned char __user *buf,size_t count,loff_t *f_pos){ struct i2c_client client; unsigned char temp; client = SPD_data->client; if(copy_from_user(&temp,buf,COUNT)) { return -EFAULT; } return i2c_smbus_write_byte(&client,temp);}int spd_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg){ struct i2c_adapter *adap; adap = SPD_data-> client.adapter; switch(cmd) { case SPD_WRITE: case SPD_READ: i2c_clients_command(adap,cmd,arg); while(1) { printk("Just a test!\n"); ssleep(1000); } break; default:-EINVAL; } return 0;}int spd_command(struct i2c_client *client,unsigned int cmd,void *arg){ printk(KERN_ALERT " ==>sign:%s\n",__FUNCTION__); switch(cmd) { case SPD_READ: return i2c_smbus_read_byte(client); break; case SPD_WRITE: return i2c_smbus_write_byte(client,arg); // break; default: return -EINVAL; }}int spd_open(struct inode *inode, struct file *filp){ struct spd_dev *dev; printk(KERN_ALERT " ==>sign:%s\n",__FUNCTION__); dev = container_of(inode->i_cdev,struct spd_dev,cdev); filp -> private_data = dev; return 0;}int spd_release(struct inode *inode,struct file *filp){ printk(KERN_ALERT " ==>sign:%s\n",__FUNCTION__); return 0;}static int spd_attach_adapter(struct i2c_adapter *adapter){ printk(KERN_ALERT " ==>sign:%s\n",__FUNCTION__); return i2c_probe(adapter, &addr_data, spd_detect);}/* This function is called by i2c_probe */static int spd_detect(struct i2c_adapter *adapter, int address, int kind){ struct i2c_client *new_client; int err = 0; printk(KERN_ALERT " ==>sign:%s\n",__FUNCTION__); if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_BYTE)) goto exit; if (!(SPD_data = kzalloc(sizeof(struct spd_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } new_client = &SPD_data->client; i2c_set_clientdata(new_client, SPD_data); new_client->addr = address; new_client->adapter = adapter; new_client->driver = &spd_driver; new_client->flags = 0; /* Fill in the remaining client fields */ strlcpy(new_client->name, "spd", I2C_NAME_SIZE); mutex_init(&SPD_data->update_lock); /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) goto exit_kfree; /* Detect the Vaio nature of EEPROMs. We use the "PCG-" or "VGN-" prefix as the signature. */ if (address == 0x57) { char name[4]; name[0] = i2c_smbus_read_byte_data(new_client, 0x80); name[1] = i2c_smbus_read_byte(new_client); name[2] = i2c_smbus_read_byte(new_client); name[3] = i2c_smbus_read_byte(new_client); } return 0;exit_kfree: kfree(SPD_data);exit: return err;}static int spd_detach_client(struct i2c_client *client){ int err; printk(KERN_ALERT " ==>sign:%s\n",__FUNCTION__);/* sysfs_remove_bin_file(&client->dev.kobj, &spd_attr);*/ err = i2c_detach_client(client); if (err) return err; kfree(i2c_get_clientdata(client)); return 0;}static int __init spd_init(void){ int result; dev_t dev = 0; printk(KERN_ALERT " ==>Welcome to %s fuction.\n",__FUNCTION__); /* Get the device number */ dev = MKDEV(SPD_MAJOR,SPD_MINOR); if(SPD_MAJOR) { result = register_chrdev_region(dev,1,"SPD"); // apply the device number to system } else { result = alloc_chrdev_region(&dev,0,1,"SPD"); } if(result ) { printk(KERN_ALERT "SPD: can't get major %d\n",SPD_MAJOR); return result; } SPD_cdev = kmalloc(sizeof(struct spd_dev),GFP_KERNEL); if(!SPD_cdev) { result = -ENOMEM; goto out_unregister_device_number; } memset(SPD_cdev,0,sizeof(struct spd_dev)); cdev_init(&SPD_cdev->cdev,&SPD_fops); SPD_cdev->cdev.owner = THIS_MODULE; SPD_cdev->cdev.ops = &SPD_fops; result = cdev_add(&SPD_cdev->cdev,dev,1); if(result) { printk(KERN_ALERT "Error %d adding SPD\n",result); goto out_free_dev; } #ifdef CREATE_AUTO /* creating my own class */ SPD_class = class_create(THIS_MODULE,"SPD"); if(IS_ERR(SPD_class)) { printk(KERN_ALERT "ERR:failed in creating class.\n"); goto out_del_dev; } /* register your own device in sysfs,and this will casue udeved to create corresponding device node */ SPD_class_device = class_device_create(SPD_class,NULL,MKDEV(SPD_MAJOR,SPD_MINOR),NULL, NODE_NAME); if(IS_ERR(SPD_class_device)) { printk(KERN_ALERT "ERR:failed in creating class device.\n"); goto out_uncreate_class; }#endif /* add the i2c_driver */ result = i2c_add_driver(&spd_driver); if(result) { printk(KERN_ALERT "ERR:failed in adding i2c_driver.\n"); goto out_uncreate_device; } printk(KERN_ALERT " ==>The %s fuction is OK.\n",__FUNCTION__); return result;out_uncreate_device: class_device_destroy(SPD_class,MKDEV(SPD_MAJOR,SPD_MINOR));out_uncreate_class: class_destroy(SPD_class);out_del_dev: cdev_del(&SPD_cdev->cdev);out_free_dev: kfree(SPD_cdev);out_unregister_device_number: unregister_chrdev_region(dev,1); return result;}static void __exit spd_exit(void){ printk(KERN_ALERT " ==>Goodby to %s fuction.\n",__FUNCTION__); i2c_del_driver(&spd_driver);#ifdef CREATE_AUTO class_device_destroy(SPD_class,MKDEV(SPD_MAJOR,SPD_MINOR)); class_destroy(SPD_class);#endif dev_t devno = MKDEV(SPD_MAJOR,SPD_MINOR); cdev_del(&SPD_cdev->cdev); kfree(SPD_cdev); unregister_chrdev_region(devno,1);}module_init(spd_init);module_exit(spd_exit);MODULE_AUTHOR("Wshenglin <wshenglin@gmail.com>");MODULE_DESCRIPTION("SMBUS EEPROM driver");MODULE_LICENSE("Dual BSD/GPL");
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -