<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > linux 一個(gè)簡(jiǎn)單的字符設(shè)備驅(qū)動(dòng)例子

          linux 一個(gè)簡(jiǎn)單的字符設(shè)備驅(qū)動(dòng)例子

          作者: 時(shí)間:2011-06-30 來(lái)源:網(wǎng)絡(luò) 收藏

          先包含這些頭文件
          #include linux/module.h>
          #include linux/types.h>
          #include linux/fs.h>
          #include linux/errno.h>
          #include linux/mm.h>
          #include linux/sched.h>
          #include linux/init.h>
          #include linux/cdev.h>
          #include asm/io.h>
          #include asm/system.h>
          #include asm/uaccess.h>

          #define BUFFERSIZE 200
          #define DEVICE_MAJOR 250 /*設(shè)置一個(gè)主設(shè)備號(hào)*/


          static int device_major = DEVICE_MAJOR;
          定義一個(gè)與字符設(shè)備對(duì)應(yīng)的結(jié)構(gòu)體
          struct my_cdev
          {
          struct cdev cdev; /*cdev結(jié)構(gòu)體,與字符設(shè)備對(duì)應(yīng)*/

          /*下面可以定義一些與字符設(shè)備相關(guān)的數(shù)據(jù)*/
          usigned char mem[BUFFERSIZE];
          };

          struct my_cdev *my_cdevp; /*設(shè)備結(jié)構(gòu)體指針*/

          int my_cdev_open( struct inode *node, struct file *filp )
          {
          /*將設(shè)備結(jié)構(gòu)體指針賦給文件私有數(shù)據(jù)指針*/
          filp->private_data = my_cdevp /*這樣可以通過(guò)文件私有數(shù)據(jù)指針得到設(shè)備結(jié)構(gòu)體*/
          return 0;
          }

          int my_cdev_release( struct inode *node, struct file *filp )
          {
          return 0;
          }

          static size_t my_cdev_read( struct file *filp, char __user *buf, size_t size, loff_t *ppos )
          {
          unsigned long p = *ppos; /*文件當(dāng)前位置*/
          unsigned int count = size; /*要讀取的長(zhǎng)度*/
          int ret = 0;

          struct my_cdev *dev = filp->private_data; /*通過(guò)文件私有數(shù)據(jù)指針得到設(shè)備結(jié)構(gòu)體,和前面的open對(duì)應(yīng)*/

          if ( p >= BUFFERSIZE )
          return count ? -ENXIO:0;
          if ( count > BUFFERSIZE - p )
          count = BUFFERSIZE - p;

          /*內(nèi)核空間->用戶空間*/
          if ( copy_to_user(buf, (void *)(dev->mem + p), count) )
          {
          ret = -EFAULT;
          }
          else
          {
          *ppos += count;
          ret = count;
          }

          return ret;
          }

          static size_t my_cdev_write( struct file *filp, const char __user *buf, size_t size, loff_t *ppos )
          {
          unsigned long p = *ppos;
          unsigned int count = size;
          int ret = 0;

          struce my_cdev *dev = filp->private_data;

          if( p >= BUFFERSIZE )
          return count ? -ENIX : 0;
          if (count > BUFFERSIZE - p )
          count = BUFFERSIZE - p;

          if ( copy_from_user( dev->mem + p, buf, count))
          {
          ret = -EFAULT;
          }
          else
          {
          *ppos += count;
          ret = count;
          }

          return ret
          }

          static loff_t my_cdev_llseek(struct file *filp, loff_t offset, int orig)
          {
          loff_t ret = 0;
          switch (orig)
          {
          case 0:
          if ( offset 0 )
          {
          ret = -EINVAL;
          break;
          }
          if (offset > BUFFERSIZE)
          {
          ret = -EINVAL;
          break;
          }
          filp->f_pos = (unsigned int)offset;
          ret = fips->f_pos;
          break;
          default:
          ret = -EINVAL;
          break;
          }

          return ret;
          }

          /*文件操作結(jié)構(gòu)體*/
          static const struct file_operstions my_cdev_fops =
          {
          .owner = THIS_MODULE,
          .open = my_cdev_open,
          .release = my_cdev_release,
          .read = my_cdev_read,
          .write = my_cdev_write,
          .llseek = my_cdev_llseek,
          };

          /*初始化并注冊(cè)cdev,就是注冊(cè)我們自己的字符設(shè)備*/
          static void my_cdev_setup( struct my_cdev *dev, int index )
          {
          int err;
          dev_t devno = MKDEV(DEVICE_MAJOR, index);

          cdev_init( dev->cdev, my_cdev_fops );
          dev->cdev.owner = THIS_MODULE;
          dev->cdev.ops = my_cdev_fops; /*我認(rèn)為在cdev_init里應(yīng)該做過(guò)賦值,應(yīng)該可以不用寫*/
          err = cdev_add( dev->cdev, devno, 1 );
          if (err)
          printk(KERN_NOTICE "Error %d adding LED%d", err, index);
          }

          static int __init my_cdev_init(void)
          {
          int result;
          dev_t devno = MKDEV(DEVICE_MAJOR, index);

          /*申請(qǐng)?jiān)O(shè)備號(hào)*/
          if ( device_major )
          {
          result = register_chrdev_region(devno, 1, "my_cdev");
          }
          else
          {
          result = alloc_chrdev_region( devno, 0, 1, "my_cdev");
          device_major = MAJOR(devno);
          }
          if ( result 0 )
          {
          return result;
          }

          my_cdevp = kmalloc(sizeof(struct my_cdev), GFP_KERNEL);
          if ( !my_cdevp )
          {
          result = -ENOMEM;
          goto fail_malloc;
          }
          memset(my_cdevp, 0, sizeof(struct my_cdev));

          my_cdev_setup(my_cdevp, 0);
          return 0;

          fail_malloc:
          unregister_chrdev_region(devno, 1);
          return result;
          }

          static void __exit my_cdev_exit(void)
          {
          cdev_del(my_cdevp->cdev);
          kfree(my_cdevp);
          unregister_chrdev_region(MKDEV(device_major, 0), 1);
          }

          MODULE_AUTHOR("Song Baohua");
          MODULE_LICENSE("Dual BSD/GPL");

          module_init(my_cdev_init);
          module_exit(my_cdev_exit);

          *********************************************************************************
          然后可以寫一個(gè)簡(jiǎn)單的內(nèi)核模塊的Makefile,編譯make后生成mycdev.ko文件,insmod mycdev.ko,
          裝上我們自己的驅(qū)動(dòng),注意有可能在裝的時(shí)候提示說(shuō)device busy什么的,這就是我們前面指定的主設(shè)備號(hào)現(xiàn)在
          有設(shè)備在用,我們就在重新指定一個(gè)在編譯。
          那怎么看有那些設(shè)備呢?可以用cat /proc/devices,就可以查看已經(jīng)有哪些主設(shè)備號(hào)已被占用。

          然后就可以自己先創(chuàng)建一個(gè)虛擬的字符設(shè)備mknod /dev/mycdev c 250 0

          ******************************************************
          下面就可以自己寫一個(gè)應(yīng)用程序來(lái)看我們自己的字符設(shè)備驅(qū)動(dòng)是否OK。

          #include stdio.h>
          #include fctl.h>
          #include string.h>
          #include sys/stat.h>

          #define BUFFERSIZE 200

          int main( void )
          {
          int fp = 0 ;
          char str[BUFFERSIZE];

          fp = open( "/dev/mycdev", O_RDWR, S_IRUSR|S_IWUSR );
          if ( !fp )
          {
          printf("Open device failedn");
          return -1;
          }

          write( fp, "Hello, my devices", strlen("Hello, my devices") );

          lseek( fp, 0, 0 );/*修改字符設(shè)備里字符數(shù)組的位置,將字符數(shù)據(jù)位置設(shè)到開始的位置,不然下面的read操作將讀不到數(shù)據(jù)*/

          read( fp, str, BUFFERSIZE );

          printf("Read content: %sn", str );

          close(fp);
          }

          gcc -o sample sample.c

          最后運(yùn)行./sample

          應(yīng)該會(huì)輸出:Read content: Hello, my devices

          總結(jié)一下,我個(gè)人覺(jué)得字符設(shè)備驅(qū)動(dòng)相關(guān)的API和數(shù)據(jù)結(jié)構(gòu)。
          1. struct cdev 一個(gè)設(shè)備對(duì)應(yīng)一個(gè)這個(gè)的數(shù)據(jù)結(jié)構(gòu),結(jié)構(gòu)體是重要的兩個(gè)字段ops 和dev(設(shè)備號(hào))
          2. struct file_opertions 文件操作結(jié)構(gòu)體
          3. cdev_init(struct cdev *, struct file_opertions *) 主要就是把字符設(shè)備和對(duì)這個(gè)設(shè)備的文件操作結(jié)構(gòu)體對(duì)應(yīng)起來(lái)
          4. cdev_add(struct cdev *, dev_t, unsigned) 注冊(cè)設(shè)備
          5. register_chrdev_region(dev_t, unsigned, const char *name)/alloc_chrdev_region() 申請(qǐng)?jiān)O(shè)備號(hào),為注冊(cè)設(shè)備(cdev_add())準(zhǔn)備
          6. 就是內(nèi)核空間的數(shù)據(jù)和用戶空間的數(shù)據(jù)交換

          本文有粵嵌教育(www.gec-edu.org)培訓(xùn)機(jī)構(gòu)提供。

          linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)

          linux相關(guān)文章:linux教程


          電機(jī)保護(hù)器相關(guān)文章:電機(jī)保護(hù)器原理


          評(píng)論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();