posts - 189,comments - 115,trackbacks - 0
          <2009年6月>
          31123456
          78910111213
          14151617181920
          21222324252627
          2829301234
          567891011

          常用鏈接

          留言簿(35)

          我參與的團隊

          隨筆檔案

          文章分類

          文章檔案

          相冊

          收藏夾

          Android

          BLOGS

          Econormic

          Friend-Blog

          Guitar

          J2ME

          JAVA

          Linux

          Linux_driver

          MUSIC

          MY--BLOG

          NET

          NEWS

          ORACLE

          Project

          SOFT

          STUDY

          Sutra<==>Research

          SVN

          Translate

          Vim

          在線翻譯

          娛樂

          文檔教程

          考研

          裝修

          軟件開發

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          linux下的GPIO驅動 2009-06-05 08:29

          字號:    

          編寫驅動程序,首先要了解是什么類型的設備。linux下的設備分為三類,分別為:字符設備,塊設備和網絡設備。字符設備類型是根據是否以字符流為數據的交換方式,大部分設備都是字符設備,如鍵盤,串口等,塊設備則是以塊為單位進行管理的設備,如,磁盤。網絡設備就是網卡等。

          其次要了解應用程序和驅動程序的區別,兩者的主要區別分為以下三點:

          1入口函數的任務不相同,應用程序完成一個任務,驅動只完成初始化工作,比如中斷

                申請,寄存器設置,定時器設置。

          2運行時的cpu模式不相同,驅動具有很高的權限,應用程序是在用戶態下運行,而驅

            動程序是在內核態下執行。

          3 驅動程序不能調用C庫函數,內核為驅動程序提供一些函數。如printk(KERN_NOTICE fmt, ##arg),第一個參數為打印級別,有如下的打印級別:

          KERN_EMERG 用于緊急事件,一般是系統崩潰前的提示信息

          KERN_ALERT 用于需要立即采取動作的場合

          KERN_CRIT 臨界狀態,通常設計驗證的硬件或軟件操作失敗

          KERN_ERR 用于報告錯誤狀態.設備驅動程序通常會用它報告來自硬件的問題

          KERN_WARNING 就可能出現的問題提出警告.這些問題通常不會對系統造成嚴重破壞

          KERN_NOTICE 有必要提示的正常情況.許多安全相關的情況用這個級別匯報

          KERN_INFO 提示性信息.有很多驅動程序在啟動時用這個級別打印相關信息

          KERN_DEBUG 用于調試的信息

          u_long copy_from_user(void *to, const void *from, u_long len),由用戶態拷貝到內核態;

          u_long copy_to_user(void * to, const void *from, u_long len),由內核態拷貝到用戶態。

          鑒于以上區別,驅動程序需要完成以下三點基本功能:

          1:要對設備進行初始化和釋放功能模塊,就如上面的寄存器設置,中斷的申請,向內核注 

             冊驅動程序(register_chrdev()),卸載驅動程序(unregister_chrdev())。

          2:能進行數據傳輸,在read(),write()函數里具體實現,數據傳輸工作。

          3:能進行控制操作,給用戶提供的ioctl()函數里可實現一些用戶的選擇性設置功能。

          確定一個設備的執行函數集(結構體)

          static struct file_operations myGPIO_fops = {

          owner: THIS_MODULE,

          write: myGPIO_write,

          read: myGPIO_read,

          ioctl: myGPIO_ioctl,

          open: myGPIO_open,

          release: myGPIO_release,

          };

          接下來是初始化工作,需要寫在一個init()函數中,這個函數是獨立的也是自動執行的,在這之中主要是對一些寄存器進行初始化操作。同樣需要完成卸載驅動模塊。

          myGPIO_Major = register_chrdev(0, DRIVER_NAME, &myDriver_fops);

          上面的程序完成設備號的注冊,第一個參數為主設備號,一般為0,由系統來分配。

          第二個參數為設備名,這需要在/dev/(/dev目錄下設備名由命令 <mknod  設備名 C 主設備號  從設備號>來生成)目錄下出現的設備名相符合。相反的在卸載中就取消注冊

          unregister_chrdev(myGPIO_Major, DRIVER_NAME);

          最后將這兩個模塊加入到內核中,由程序段的最后兩行完成。

          static int __init myGPIO_init(void)

          {

          PRINTK("GPIO init\n");

          myGPIO_Major = register_chrdev(0, DRIVER_NAME, &myGPIO_fops);

          if(myGPIO_Major < 0)

          {

          PRINTK("register char device fail!\n");

          return myGPIO_Major;

          }

          PRINTK("register myGPIO OK! Major = %d\n", myGPIO_Major);

          #ifdef CONFIG_DEVFS_FS

          devfs_myDriver_dir = devfs_mk_dir(NULL, "GPIO", NULL);

          devfs_myDriver_raw = devfs_register(devfs_myDriver_dir, "raw0", DEVFS_FL_DEFAULT, myGPIO_Major, 0, S_IFCHR | S_IRUSR | S_IWUSR, &myGPIO_fops, NULL);

          PRINTK("add dev file to devfs OK!\n");

          #endif

          return 0;

          }

          static void __exit myGPIO_exit(void)

          {

          /* Module exit code */

          PRINTK("GPIO exit\n");

          /* Driver unregister */

          if(myGPIO_Major > 0)

          {

          #ifdef CONFIG_DEVFS_FS

          devfs_unregister(devfs_myDriver_raw);

          devfs_unregister(devfs_myDriver_dir);

          #endif

          unregister_chrdev(myGPIO_Major, DRIVER_NAME);

          }

          return;

          }

          MODULE_AUTHOR("LiuFan");

          MODULE_LICENSE("Dual BSD/GPL");

          module_init(myGPIO_init);

          module_exit(myGPIO_exit);

          設備執行函數功能的實現將在下面完成。如結構體的函數,但并不是全都需要實現。open()函數中是執行一些設備工作前的初始化工作。rlease()則是將設備的相關寄存器恢復到原來的值。read()函數是將設備中的數據拷貝到內核,write()函數是將內核數據拷貝到對應的設備中。MOD_INC_USE_COUNT和MOD_DEC_USE_COUNT兩個宏是提供給系統對硬件資源進行控制訪問的。在open()和rlease()兩個函數中最基本的操作應是實現以上兩個宏的操作。

          static unsigned char myGPIO_Buffer[1024*1024];

          /* Driver Operation Functions */

          static int myGPIO_open(struct inode *inode, struct file *filp)

          {

          // int Minor = MINOR(inode->i_rdev);

          // filp->private_data = 0;

          MOD_INC_USE_COUNT;

          PRINTK("myDriver open called!\n");

          return 0;

          }

          static int myGPIO_release(struct inode *inode, struct file *filp)

          {

          // int Minor = MINOR(inode->i_rdev);

          MOD_DEC_USE_COUNT;

          PRINTK("myDriver release called!\n");

          return 0;

          }

          static ssize_t myGPIO_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)

          {

          char dat;

          size_t read_size = count;

          PRINTK("GPIO read called!\n");

          PRINTK("\tcount=%d, pos=%d\n", count, (int)*f_pos);

          /* if(*f_pos >= sizeof(myGPIO_Buffer))

          {

          PRINTK("[GPIO read]Buffer Overlap\n");

          *f_pos = sizeof(myGPIO_Buffer);

          return 0;

          }

          if((count + *f_pos) > sizeof(myGPIO_Buffer))

          {

          PRINTK("count + f_pos > sizeof buffer\n");

          read_size = sizeof(myGPIO_Buffer) - *f_pos;

          }*/

          dat= GPFDAT;

          copy_to_user(buf,&dat,1);

          // *f_pos += read_size;

          return read_size;

          }

          static ssize_t myGPIO_write(struct file *filp,const char *buf, size_t count, loff_t *f_pos)

          {

          char dat;

          size_t fill_size = count;

          PRINTK("myDriver write called!\n");

          PRINTK("\tcount=%d, pos=%d\n", count, (int)*f_pos);

          if(*f_pos >= sizeof(myGPIO_Buffer))

          {

          PRINTK("[myDriver write]Buffer Overlap\n");

          *f_pos = sizeof(myGPIO_Buffer);

          return 0;

          }

          if((count + *f_pos) > sizeof(myGPIO_Buffer))

          {

          PRINTK("count + f_pos > sizeof buffer\n");

          fill_size = sizeof(myGPIO_Buffer) - *f_pos;

          }

          copy_from_user(&dat,buf,fill_size);

          GPFDAT = dat;

          // *f_pos += fill_size;

          return fill_size;

          }

          控制ioctl() 函數則是提供給應用層的接口函數,功能并不是固定的,由開發者定義,一般都是對硬件的一些除過上述功能的其他操作。

          static int myGPIO_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)

          {

          int i;

          unsigned int mask=0x01;

          GPFUP = 0x00;

          PRINTK("myGPIO ioctl called(%d)!\n", cmd);

              switch(cmd)

          {

          case MOD_IN:

          for(i=0;i<8;i++)

          {

          if((mask & arg)!=0x0)

          {

          GPFCON &=~(3<<i*2); 

          }

          mask =mask << 1;

          }

          break;

          case MOD_OUT:

           PRINTK("IOCTRL 0 called(0x%lx)!\n", arg);

           for(i=0;i<8;i++)

           {

           if((mask & arg)!=0x00)

           {

                  GPFCON &= ~(3 <<( i*2));

          GPFCON |=(0x01<<(i*2));

           }

          mask=mask<<1;

           }

           break;

          case MOD_EXIT_INT:

          PRINTK("IOCTRL 1 called(0x%lx)!\n", arg);

          GPFDAT = 0xFFFFFF00;

          break;

          default:

          break;

          }

          return 0;

          }

          posted on 2009-06-11 21:30 MEYE 閱讀(2625) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 平顺县| 晋城| 昂仁县| 道孚县| 乌苏市| 蓬溪县| 齐齐哈尔市| 肥西县| 龙川县| 靖边县| 武义县| 独山县| 汾西县| 铅山县| 汶上县| 上饶县| 宿松县| 平山县| 古浪县| 昭苏县| 延长县| 揭西县| 淅川县| 嘉定区| 仁布县| 兴化市| 光泽县| 体育| 漯河市| 洮南市| 台北县| 于都县| 化隆| 炎陵县| 武山县| 卢湾区| 永春县| 钟祥市| 荃湾区| 临汾市| 景宁|