久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

LINUX的IIC驅(qū)動(dòng)從這開始(三)

 enchen008 2014-04-16

這一篇主要是在友善的Smart210開發(fā)板上寫一個(gè)符合linux的iic驅(qū)動(dòng)模型的設(shè)備驅(qū)動(dòng)程序,這樣能有一個(gè)更感性的認(rèn)識(shí),。

開發(fā)環(huán)境介紹:

主機(jī)linux版本:fedora14

開發(fā)板:友善的Smart210

嵌入式linux版本:linux-3.0.8(友善光盤自帶的)

交叉編譯器:arm-linux-gcc-4.5.1(友善光盤自帶的)

硬件簡單介紹:

,、

這是從友善的原理圖上截下的圖,這個(gè)圖沒有什么復(fù)雜的,,從圖可以看出來EEPROM是和s5pv210上的第0個(gè)iic適配器連接的,,但我是用第1個(gè)適配器寫的,所以用線直接把適配器1的引腳和EEPROM相連的,,我這邊正好有這個(gè)項(xiàng)目需要,,所以這樣寫了,你可以直接用適配器0就行了,,在寫驅(qū)動(dòng)的時(shí)候我會(huì)說怎么選iic適配器0和iic適配器1,。

我們前面說過iic驅(qū)動(dòng)模型是采用分層思想的,也即總線驅(qū)動(dòng)和設(shè)備驅(qū)動(dòng)是分開的,。那它們?cè)趺聪嗷ヂ?lián)系了,?總得要一個(gè)什么東西來做個(gè)匹配吧,就像以前的地下工作者,,需要接頭暗號(hào),,要不然就亂套了,哈哈,!iic總線和設(shè)備之間是用名字做匹配的,,那好了,那就先得把設(shè)備的名字告訴總線吧,,下面就是如何在總線上注冊(cè)設(shè)備信息了,。

注冊(cè)設(shè)備信息

閱讀linux下的Documentation/i2c/instantiating-devices 文檔可以知道有兩種方式可以注冊(cè),,咱們只說前一種。打開:linux-3.0.8/arch/arm/mach-s5pv210/mach-mini210.c這個(gè).c文件,。就是在這個(gè)文件中填寫咱們?cè)O(shè)備的信息的,,這就是所說的bsp文件。首先添加頭文件#include <linux/i2c/at24.h> 因?yàn)閘inux專門問iic接口的eeprom提供了相應(yīng)的數(shù)據(jù)結(jié)構(gòu),,要是不加,,肯定要報(bào)錯(cuò)。接下來添加如下信息:

  1. static struct at24_platform_data at24c08 = {  
  2. .byte_len = SZ_8K / 8,  //eeprom的容量大?。ǖ刂返目倲?shù))  
  3. .page_size = 16,        //eeprom的一頁中包含的字節(jié)數(shù)  
  1. };   

然后添加如下的信息,,主要把eeprom的信息包裝成符合iic模型中的設(shè)備信息的格式

  1. static struct i2c_board_info i2c_devices[] __initdata = {  
  2.     {   
  1.     I2C_BOARD_INFO("at24c08b", 0x50),  //后邊的0x50是eeprom的地址,可能有人說應(yīng)該是0xa0,,但linux中需要的是7bit的地址,,所以向右移一位,正好是0x50,。當(dāng)然了,,最終會(huì)在linux的iic的讀函數(shù)和寫函數(shù)中變成0xa0和0xa1的格式  
  2.     .platform_data = &at24c08,   
  3. },  

最后在mini210_machine_init函數(shù)中把上面寫的信息注冊(cè)到iic總線上

  1. static void __init mini210_machine_init(void)  
  2. {  
  3.         ...  
  4.     s3c_i2c2_set_platdata(&i2c2_data);  
  5.     i2c_register_board_info(0, mini210_i2c_devs0,  
  6.             ARRAY_SIZE(mini210_i2c_devs0));  
  7.     //i2c_register_board_info(1, mini210_i2c_devs1,  
  8.             //ARRAY_SIZE(mini210_i2c_devs1));  //把友善原來帶的屏蔽掉  
  9.         <span style="color:#ff0000;">i2c_register_board_info(1, i2c_devices,            //仿照上面的添加如下的,主要這里分為0,、1和2,,你可以修改適配器0的,這樣不需要連線  
  10.                         ARRAY_SIZE(i2c_devices));</span>  
  11.     i2c_register_board_info(2, mini210_i2c_devs2,  
  12.             ARRAY_SIZE(mini210_i2c_devs2));  
  1. ...  
  1. }  
這就算把設(shè)備信息注冊(cè)上了,,重新編譯一下你的linux內(nèi)核吧,,然后把編譯好的內(nèi)核燒進(jìn)開發(fā)板,下面開始就是真真的驅(qū)動(dòng)部分了,。

設(shè)備驅(qū)動(dòng)編寫

首先咱們是用eeprom讀寫一些數(shù)據(jù),,數(shù)據(jù)量不會(huì)很大,,所以它應(yīng)該是個(gè)字符設(shè)備,,盡管它從iic驅(qū)動(dòng)模型的角度說,是iic設(shè)備,,起始這并不矛盾,。因?yàn)樽址O(shè)備里包括了一部分的iic設(shè)備,,下面就是整個(gè)驅(qū)動(dòng)了

  1. #include<linux/module.h>  
  2. #include<linux/init.h>  
  3. #include<linux/kernel.h>  
  4. #include<linux/fs.h>  
  5. #include<asm/uaccess.h>  
  6. #include<linux/i2c.h>  
  7. #include<linux/miscdevice.h>  
  8. #include<linux/slab.h>  
  9. #include<linux/list.h>  
  10. #include<linux/delay.h>  
  11.   
  12. #define DEVICE_NAME  "at24c08"  
  13. //#define DEBUG  
  14.   
  15. struct At24c08_dev  
  16. {  
  17.   char name[30];  
  18.   struct i2c_client *at24c08_client;  
  19.   struct miscdevice  at24c08_miscdev;  //因?yàn)楸旧硎且粋€(gè)字符設(shè)備,所以定義成一個(gè)雜項(xiàng)設(shè)備  
  20.   unsigned short current_pointer;  
  21. };  
  22.   
  23. struct At24c08_dev *At24c08_devp;  //定義一個(gè)全局的,,因?yàn)榻Y(jié)構(gòu)體力里面的atc08_client需要從probe函數(shù)中獲得  
  1. //open函數(shù)主要是把全局的At24c08_devp賦給file文件的私有數(shù)據(jù),,這樣在其他的函數(shù)中調(diào)用方便  
  2. static int at24c08_open(struct inode *inode,struct file *file){  
  3.     
  4.   file->private_data = At24c08_devp;  
  5.   return 0;  
  6. }  
  1. //這就是雜項(xiàng)設(shè)備的read方法,跟普通的雜項(xiàng)設(shè)備的read方法沒什么不一樣的,,只是調(diào)用的i2c_read_byte_data用來實(shí)際傳輸數(shù)據(jù)  
  2. static ssize_t  
  3. at24c08_read(struct file *file,char *buf,size_t count,loff_t *ppos)  
  4. {  
  5.   int i = 0;  
  6.   int transferred = 0;  
  7.   char value;  
  8.   char my_buff[50];  
  9.   
  10.   struct At24c08_dev *dev = (struct At24c08_dev *)file->private_data;  
  11.   
  12.   dev->current_pointer = 0;  
  13.   if(i2c_check_functionality(dev->at24c08_client->adapter,I2C_FUNC_SMBUS_READ_BYTE_DATA))  
  14.   {  
  15.     while(transferred < count)  
  16.     {  
  17.       msleep(10);    //這里一定注意,,要不這個(gè)延時(shí)加上,因?yàn)閏pu速度比較快,,eeprom速度比較慢,,所以不加會(huì)出問題,,我調(diào)試時(shí)就出問題了,,后加的  
  18.       value = i2c_smbus_read_byte_data(dev->at24c08_client,dev->current_pointer +i);  
  19.       my_buff[i++] = value;  
  20.       transferred ++;  
  21.     }  
  22.     if(!copy_to_user(buf,(void *)my_buff,transferred))  
  23.       printk("The data copying from kernel to userspace success!\n");  
  24.     else  
  25.       printk("Mybe some errors has occured\n");  
  26.     dev->current_pointer +=transferred;  
  27.   }  
  28.   return transferred;  
  29. }  
  1. //這就是注冊(cè)的雜項(xiàng)設(shè)備的write方法  
  2. static ssize_t  
  3. at24c08_write(struct file *file,const char *buf,size_t count,loff_t *ppos)  
  4. {  
  5.   int i = 0;  
  6.   int transferred = 0;  
  7.   char  my_buff[50];  
  8.   
  9.   struct At24c08_dev *dev = (struct At24c08_dev *)file->private_data;  
  10.   dev->current_pointer = 0;  
  11.   if(i2c_check_functionality(dev->at24c08_client->adapter,I2C_FUNC_SMBUS_BYTE_DATA))  
  12.   {  
  13.     if(!copy_from_user(my_buff,buf,count))  
  14.     {  
  15.       printk("The data copying from userspace to kernel success!\n");  
  16.       while(transferred < count)  
  17.       {  
  18.          msleep(10);//與上面的read函數(shù)中的類似  
  19.          i2c_smbus_write_byte_data(dev->at24c08_client,dev->current_pointer + i,my_buff[i]); //這個(gè)函數(shù)通過adapter的通信方法把一個(gè)字節(jié)的數(shù)據(jù)發(fā)送          //到iic設(shè)備中去  
  20.          i ++;  
  21.          transferred ++;  
  22.       }  
  23.       dev->current_pointer +=transferred;  
  24.     }  
  25.     else  
  26.       printk("Mybe some errors has occured\n");  
  27.   }  
  28.   return transferred;  
  29. }  
  30.   
  31. static const struct file_operations at24c08_fops ={  
  32.   .owner = THIS_MODULE,  
  33.   .open = at24c08_open,  
  34.   .read = at24c08_read,  
  35.   .write = at24c08_write,  
  36. };  
  1. //當(dāng)把設(shè)備掛接到總線上時(shí),,只有當(dāng)at24c08b_id所起的名字和之前注冊(cè)到總線當(dāng)中的名字一樣時(shí),才會(huì)調(diào)用probe函數(shù),。在probe函數(shù)里會(huì)分配i2c_client,,通過這個(gè)//i2c_client,當(dāng)調(diào)用注冊(cè)的字符設(shè)備時(shí),,iic適配器就知道把數(shù)據(jù)跟那個(gè)iic設(shè)備交互,。  
  2. static int __devinit at24c08b_probe(struct i2c_client *client,const struct i2c_device_id *id)  
  3. {  
  4.   int ret;  
  5.     
  6.   #ifdef DEBUG  
  7.     printk("The routine of probe has started(for binding device)\n");  
  8.   #endif  
  9.     
  10.   At24c08_devp = kmalloc(sizeof(struct At24c08_dev),GFP_KERNEL);  
  11.   if(!At24c08_devp)  
  12.   {  
  13.     return ret = -ENOMEM;  
  14.   }  
  15.   memset(At24c08_devp,0,sizeof(struct At24c08_dev));  
  16.   
  17.   At24c08_devp->at24c08_client = client; //把分配的i2c_client賦給定義的全局變量  
  18.   
  19.   At24c08_devp->at24c08_miscdev.minor = MISC_DYNAMIC_MINOR;   
  20.   At24c08_devp->at24c08_miscdev.name = DEVICE_NAME;  
  21.   At24c08_devp->at24c08_miscdev.fops = &at24c08_fops; //把雜項(xiàng)設(shè)備的一些域用我們具體的方法定義  
  22.     
  23.   ret = misc_register(&At24c08_devp->at24c08_miscdev);  //注冊(cè)雜項(xiàng)設(shè)備  
  24.   #ifdef DEBUG  
  25.     printk("The driver of at24c08 has registered!\n");  
  26.   #endif  
  27.   return ret;  
  28. }  
  29.   
  30. static int __devexit at24c08b_remove(struct i2c_client *client)  
  31. {  
  32.   misc_deregister(&At24c08_devp->at24c08_miscdev);  
  33.   #ifdef DEBUG  
  34.     printk("The routine of remove has implemented!\n");  
  35.   #endif  
  36.   return 0;  
  37. }  
  38. static const struct i2c_device_id at24c08b_id[]={  
  39.   {"at24c08",0},  
  40.   {}  
  41. };   //當(dāng)把設(shè)備掛接到總線上時(shí),就調(diào)用這里面的名字和注冊(cè)在總線里的名字比對(duì),,如果一樣就會(huì)調(diào)用probe函數(shù),,同時(shí)給掛接的設(shè)備分配i2c_client結(jié)構(gòu)體  
  42.   
  43. MODULE_DEVICE_TABLE(i2c,at24c08b_id);  
  44.   
  45. static struct i2c_driver at24c08b_driver = {  
  46.   
  47.   .driver = {  
  48.      .name = "at24c08",  
  49.      .owner=THIS_MODULE,  
  50.   },  
  51.   .probe = at24c08b_probe,  
  52.   .remove=__devexit_p(at24c08b_remove),  
  53.   .id_table =at24c08b_id,  
  54. };  
  55.   
  56. static int __init at24c08b_init(void)  
  57. {  
  58.   #ifdef DEBUG  
  59.     printk(KERN_NOTICE"The driver of at24c08 is insmod!\n");  
  60.   #endif  
  61.   return i2c_add_driver(&at24c08b_driver);  //把iic設(shè)備掛接到總線上  
  62. }  
  63.   
  64. void at24c08b_exit(void)  
  65. {  
  66.   #ifdef DEBUG  
  67.     printk(KERN_NOTICE"at24c0b is rmmod!\n");  
  68.   #endif  
  69.   i2c_del_driver(&at24c08b_driver); //把iic設(shè)備移除,這時(shí)會(huì)調(diào)用remove函數(shù),,所以在remove函數(shù)中一般會(huì)干一些注銷設(shè)備的工作等  
  70. }  
  71.   
  72.   
  73. MODULE_DESCRIPTION("at24c08b eeprom driver");  
  74. MODULE_LICENSE("Dual BSD/GPL");  
  75. MODULE_AUTHOR("xie yingdong");  
  76.   
  77. module_init(at24c08b_init);  
  78. module_exit(at24c08b_exit);  
上面就是完整的eeprom驅(qū)動(dòng),,當(dāng)然驅(qū)動(dòng)寫完了,需要寫個(gè)簡單的Makefile來編譯這個(gè)驅(qū)動(dòng),,好吧,,下面就是Makefile文件的內(nèi)容

  1. obj-m:=eeprom-driver.o  
  2. KDIR = /tmp/linux-3.0.8  //這里需要你根據(jù)自己的實(shí)際的linux源碼放的位置來設(shè)置  
  3.   
  4. all:  
  5.     $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) modules ARCH=arm CROSS_COMPILE=arm-linux-  
  6. clean:  
  7.     @rm -rf eeprom-driver*.o  
上面的Makefile文件很是簡單,就不做過多的解釋了,。當(dāng)把驅(qū)動(dòng)編譯好了,,用動(dòng)態(tài)的方式掛載到了linux內(nèi)核上后,你還得做個(gè)簡單的測(cè)試程序,,來驗(yàn)證咱們寫的驅(qū)動(dòng)工作是否正常,,下面就直接貼出來吧。

  1. #include<stdio.h>  
  2. #include<linux/types.h>  
  3. #include<stdlib.h>  
  4. #include<fcntl.h>  
  5. #include<unistd.h>  
  6. #include<sys/types.h>  
  7.   
  8. int main(void)  
  9. {  
  10.   int i;  
  11.   char value[19] = "eeprom-driver test!";  
  12.   char backvalue[19];  
  13.   
  14.   int fd;  
  15.   fd = open("/dev/at24c08",O_RDWR);  //這里的名字一定要和驅(qū)動(dòng)里注冊(cè)的雜項(xiàng)設(shè)備的名字一樣,,但跟iic設(shè)備的名字無關(guān),,這里只是正好取的一樣而已  
  16.   if(fd<0){  
  17.     printf("Open at24c08 device failed!\n");  
  18.     exit(1);  
  19.   }  
  20.   write(fd,value,19);  
  21.   printf("The string writing to eeprom : %s\n",value);  
  22.   printf("##################################################\n");  
  23.   sleep(1);  
  24.   read(fd,backvalue,19);  
  25.   printf("The string reading from eeprom : %s\n",backvalue);  
  26.   close(fd);  
  27.   return 0;}  

哈哈,驅(qū)動(dòng)就寫完了,,我自己測(cè)試了,,沒問題,你可以試試,,下一篇我們會(huì)分析iic總線驅(qū)動(dòng),。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多