代碼中,我添加了不少註釋,應該不難理解,有錯誤你們能夠指出來,我再改正node
#include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/cdev.h> #include <linux/i2c.h> #include <linux/fs.h> #include <asm/uaccess.h> #define I2C_MAJOR 365 //主設備號 #define I2C_MINOR 0 //從設備號 #define I2C_COUNT 1 //設備數量 MODULE_LICENSE("Dual BSD/GPL"); /* 函數聲明 */ int s5pc100_i2c_probe(struct i2c_client *, const struct i2c_device_id *); int s5pc100_i2c_remove(struct i2c_client *); int s5pc100_i2c_open(struct inode *, struct file *); int s5pc100_i2c_release(struct inode *, struct file *); ssize_t s5pc100_i2c_read(struct file *, char __user *, size_t, loff_t *); /* 定義設備結構體 */ typedef struct s5pc100_i2c { struct i2c_client client; struct cdev cdev; }s5pc100_i2c; /* 使用設備結構體 */ s5pc100_i2c *i2c; /* 設備信息struct i2c_device_id結構體,保存i2c設備的設備信息,因爲可能 * 存在多個i2c設備因此將它定義爲一個結構體數組,方便添加新增設備 struct i2c_device_id { char name[I2C_NAME_SIZE]; 設備的名字,這是一個宏定義2.6.35中默認是20個字符 ulong driver_data; 設備的私有數據,能夠本身隨便填寫 } */ struct i2c_device_id i2c_id[] = { { "lm75", 0 }, }; /* 構建i2c子系統的設備驅動結構體i2c_driver * .driver.name 表示驅動程序的名字,這個名字能夠由本身任意取 * .id_table 是一個struct i2c_device_id的結構體,保存着i2c的設備信息 struct i2c_device_id { char name[I2C_NAME_SIZE]; 設備的名字,這是一個宏定義2.6.35中默認是20個字符 ulong driver_data; 設備的私有數據,能夠本身隨便填寫 } * .probe 表示匹配成功後要執行的函數 * .remove 表示移除設備的時候要執行的函數 */ struct i2c_driver i2c_driver = { .driver.name = "lm75", .id_table = i2c_id, .probe = s5pc100_i2c_probe, .remove = s5pc100_i2c_remove, }; /* 方法綁定結構體 */ struct file_operations i2c_fops = { .owner = THIS_MODULE, .open = s5pc100_i2c_open, .release = s5pc100_i2c_release, .read = s5pc100_i2c_read, }; int s5pc100_i2c_open(struct inode * inode, struct file *filp) { printk("open\n"); return 0; } int s5pc100_i2c_release(struct inode * inode, struct file *filp) { printk("close\n"); return 0; } /* 讀取設備數據,涉及到struct i2c_msg消息結構體的實現和使用 */ ssize_t s5pc100_i2c_read(struct file *filp, char __user *buf, size_t count, loff_t *loff) { int ret = 0; //定義讀寫緩衝區 char txbuf[1] = {0}; char rxbuf[2] = {0}; /* i2c設備通信是經過系統定義的消息結構體實現的,這樣能夠簡化驅動人員的工做,實現驅動的良好移植性. struct i2c_msg { __u16 addr; 從機地址,從struct i2c_client中獲取 __u16 flags; 標誌位,使用下面的宏,其中寫數據能夠直接傳遞0進去 #define I2C_M_TEN 0x0010 表明i2c地址爲10位地址數據 #define I2C_M_RD 0x0001 讀數據,從從機到主機 #define I2C_M_NOSTART 0x4000 if I2C_FUNC_PROTOCOL_MANGLING #define I2C_M_REV_DIR_ADDR 0x2000 if I2C_FUNC_PROTOCOL_MANGLING #define I2C_M_IGNORE_NAK 0x1000 if I2C_FUNC_PROTOCOL_MANGLING #define I2C_M_NO_RD_ACK 0x0800 if I2C_FUNC_PROTOCOL_MANGLING #define I2C_M_RECV_LEN 0x0400 首先受到的字節表示長度 __u16 len; 消息長度 __u8 *buf; 指向消息數據的指針 }; */ struct i2c_msg msg[2] = { { i2c->client.addr, 0, 1, txbuf }, { i2c->client.addr, I2C_M_RD, 2, rxbuf}, }; if (sizeof(rxbuf) != count) count = sizeof(rxbuf); ret = i2c_transfer(i2c->client.adapter, msg, ARRAY_SIZE(msg)); if (ret < 0) { printk("failure:i2c_transfer\n"); return -EFAULT; } if (copy_to_user(buf, rxbuf, count)) return -EFAULT; return count; } /* 匹配函數,設備成功配對並取得設備信息struct i2c_client結構體後執行的函數 */ int s5pc100_i2c_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { int ret = 0; dev_t devno = MKDEV(I2C_MAJOR, I2C_MINOR); //獲取設備號 ret = register_chrdev_region(devno, I2C_COUNT, "i2c"); //註冊設備 if (ret < 0) { printk("failure:register_chrdev_region\n"); return ret; } /* 申請空間 * 使用函數void *kmalloc(size_t size, gfp_t flags) size 表明申請的內存大小 flags 表示該函數的操做類型,使用系統提供的宏實現,用到的主要有下面這些: GFP_ATOMIC 能申請到內存則申請,不能申請到內存則當即返回錯誤碼 GFP_KERNEL 能申請則申請,不能申請則睡眠,直到申請到爲止 */ i2c = (s5pc100_i2c *)kmalloc(sizeof(*i2c), GFP_KERNEL); if (NULL == i2c) { printk("failure:i2c.kmalloc\n"); return -ENOMEM; } /* 設備初始化,將cdev和file_operations綁定,將設備信息和實現方法進行綁定 */ cdev_init(&i2c->cdev, &i2c_fops); i2c->cdev.owner = THIS_MODULE; /* 添加設備 */ ret = cdev_add(&i2c->cdev, devno, I2C_COUNT); if (ret < 0) { ret = -EFAULT; printk("failure:cdev_add\n"); goto err1; } /* 導出client,獲取系統提供的具體的i2c的設備信息,這樣就實現了設備和驅動的關聯*/ i2c->client = *client; return 0; err1: kfree(i2c); unregister_chrdev_region(devno, I2C_COUNT); return ret; } /* remove處理函數 */ int s5pc100_i2c_remove(struct i2c_client *client) { /* 釋放須要釋放的數據 */ int ret = 0; dev_t devno = MKDEV(I2C_MAJOR, I2C_MINOR); cdev_del(&i2c->cdev); kfree(i2c); unregister_chrdev_region(devno, I2C_COUNT); return ret; } /* 加載函數 */ static int __init s5pc100_i2c_init(void) { /* 註冊i2c的設備驅動 * 使用函數int i2c_add_driver(struct i2c_driver *i2c_driver) * 成功返回0,失敗返回錯誤碼 */ return i2c_add_driver(&i2c_driver); } /* 卸載函數 */ static void __exit s5pc100_i2c_cleanup(void) { /* 刪除i2c的設備驅動 * 使用函數void i2c_del_driver(struct i2c_driver *i2c_driver) */ i2c_del_driver(&i2c_driver); } module_init(s5pc100_i2c_init); module_exit(s5pc100_i2c_cleanup);