I2C驱动程序框架probe道路
基于Linux的I2C驅動器。采納probe道路。根據這個框架,如下面就可以寫任何支持I2C總線設備Linux驅動器。
I2C設備連接到cpu具體i2c接口。被安裝在cpu的i2c適配器。i2c設備和cpu信息交流需要通過cpu操作適配器互動。cpu上有1個或多個適配器。每一個適配器上能夠掛載256個設備地址不一樣的i2c器件,通過i2c驅動就能夠讓cpu和適配器上的多個不一樣的i2c器件通信而不會產生沖突。
驅動包含兩個文件,dev.c和drive.c,當中dev.c是構建I2C設備,即創建I2C_Client結構體。而driver.c是在probe中獲取dev.c中構建的i2c_client,然后構建fileoperation。詳細步驟結合代碼例如以下。
1、在dev的入口函數中構建I2C-CLient
static unsigned short addr_list[] = {0x60, 0x50, I2C_CLIENT_END //這個數組包括了設備地址,以I2C_CLIENT_END為數組結尾</span>}; static struct i2c_client *at24cxx_client; //創建I2C_Client結構體 static int at24cxx_dev_init(void) {/*構建I2C_Client*/struct i2c_adapter *adapter;struct i2c_board_info info; adapter=i2c_get_adapter(0); //獲取適配器,由于有些cpu有多個I2C適配器。參數0為適配器編號memset(&info, 0, sizeof(struct i2c_board_info));strlcpy(info.type, "at24cxx", I2C_NAME_SIZE); //這個是I2C_NAME,是和i2c_driver匹配的keywordat24cxx_client=i2c_new_probed_device(adapter, &info, addr_list);//假設數組中地址的設備存在則成功返回i2c_client結構體//這個函數終于會調用device_create創建設備i2c_put_adapter(adapter);if(at24cxx_client)return 0;else return -ENODEV; }2、在driver.c的入口函數中注冊I2C_driver結構體
static const struct i2c_device_id = { { "at24cxx", 0 }, { } }; static struct i2c_driver at24cxx_driver = {.driver = {.name = "100ask",.owner = THIS_MODULE,},.probe = at24cxx_probe,.remove = __devexit_p(at24cxx_remove),.id_table = at24cxx_ids,//id_table中name是和dev創建i2c_client的name匹配,若匹配則會調用probe設備方法 };static int at24cxx_drv_init(void) {/*×¢2ái2c_driver*/return i2c_add_driver(&at24cxx_driver);}3、在probe設備方法中構建file_operation注冊字符設備 static struct file_operations at24cxx_fops = {.owner = THIS_MODULE,.read = at24cxx_read,.write = at24cxx_write,};static int at24cxx_probe(struct i2c_client *client, const struct i2c_device_id *id) {printk("%s %s %d.\n",__FILE__,__FUNCTION__,__LINE__);at24cxx_client = client;//將dev中構建的i2c_client結構體傳遞過來,由于這個結構體在read,write等設備方法中傳遞信息時須要用到major = register_chrdev(0,"at24cxx",&at24cxx_fops);//注冊字符設備class = class_create(THIS_MODULE,"at24cxx");device_create(class,NULL,MKDEV(major,0),NULL,"at24cxx");return 0; }4、構建write和read等設備方法中傳遞I2C消息
static ssize_t at24cxx_read(struct file *file, char __user *buf, size_t count, loff_t *off) {unsigned char addr,data;copy_from_user(&addr,buf,1);data = i2c_smbus_read_byte_data(at24cxx_client,addr);//這里用i2c_smbus_read_byte_data函數來和實際的I2C設備進行信息交互</span> //這里詳細用哪個函數來傳遞消息須要結合詳細的器件的時序。不同的時序有不同的傳遞函數,查看Linux源代碼中的說明文檔有關于傳遞函數的說明。copy_to_user(buf,&data,1); return 0; } static ssize_t at24cxx_write(struct file *file, const char __user *buf, size_t count , loff_t *off) { unsigned char ker_buf[2]; unsigned char addr,data; copy_from_user(ker_buf,buf,2); addr = ker_buf[0]; data = ker_buf[1]; if(!i2c_smbus_write_byte_data(at24cxx_client,addr,data)) return 2; else return -EIO; }
假設i2c總線中掛載了實際的i2c設備,并且設備地址在以上的addr_list中,則不管是先載入dev.ko還是先載入driver.ko都會成功的運行probe函數,然后創建字符設備。在應用程序中open設備,并調用read和write則會對應的調用driver中的read和write設備方法。
測試應用程序 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>/* i2c_test r addr* i2c_test w addr val*/void print_usage(char *file) {printf("%s r addr\n", file);printf("%s w addr val\n", file); }int main(int argc, char **argv) {int fd;unsigned char buf[2];if ((argc != 3) && (argc != 4)){print_usage(argv[0]);return -1;}fd = open("/dev/at24cxx", O_RDWR);if (fd < 0){printf("can't open /dev/at24cxx\n");return -1;}if (strcmp(argv[1], "r") == 0){buf[0] = strtoul(argv[2], NULL, 0);printf("before data: %c, %d, 0x%2x\n", buf[0], buf[0], buf[0]);read(fd, buf, 1);printf("data: %c, %d, 0x%2x\n", buf[0], buf[0], buf[0]);}else if ((strcmp(argv[1], "w") == 0) && (argc == 4)){buf[0] = strtoul(argv[2], NULL, 0);buf[1] = strtoul(argv[3], NULL, 0);if (write(fd, buf, 2) != 2)printf("write err, addr = 0x%02x, data = 0x%02x\n", buf[0], buf[1]);}else{print_usage(argv[0]);return -1;}return 0; }2014--12--17
征途開始
興許補充
轉載于:https://www.cnblogs.com/mfrbuaa/p/4593267.html
總結
以上是生活随笔為你收集整理的I2C驱动程序框架probe道路的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP实现同服务器多个二级域名共享 SE
- 下一篇: aix下java程序运行问题