创客神器NanoPi
直播中

左宗棠

8年用户 31经验值
擅长:可编程逻辑
私信 关注
[经验]

【NanoPi M2试用体验】字符类GPIO的驱动源码

作为初学者,笔者尝试了“hello world”——点灯。然而鉴于william hill官网 和百度中许多大神用了杂项设备的方法,笔者自己尝试了下字符型设备,编译方法就略过了,以下是源码:
char_driver_leds.h
  1. #ifndef _CHAR_DRIVER_LEDS_H_
  2. #define _CHAR_DRIVER_LEDS_H_

  3. #ifndef DEVICE_NAME
  4. #define DEVICE_NAME "charGPIO"
  5. #endif

  6. #ifndef DEVICE_MINOR_NUM
  7. #define DEVICE_MINOR_NUM 2
  8. #endif

  9. #ifndef DEV_MAJOR
  10. #define DEV_MAJOR 0
  11. #endif

  12. #ifndef DEV_MINOR
  13. #define DEV_MINOR 0
  14. #endif

  15. #ifndef REGDEV_SIZE
  16. #define REGDEV_SIZE 3000
  17. #endif

  18. struct reg_dev
  19. {
  20.         char *data;
  21.         struct cdev cdev;
  22. };
  23. #endif
char_driver_leds.c
  1. /*包含初始化宏定义的头文件,代码中的module_init和module_exit在此文件中*/
  2. #include
  3. /*包含初始化加载模块的头文件,代码中的MODULE_LICENSE在此头文件中*/
  4. #include
  5. /*定义module_param module_param_array的头文件*/
  6. #include
  7. /*定义module_param module_param_array中perm的头文件*/
  8. #include
  9. /*三个字符设备函数*/
  10. #include
  11. /*MKDEV转换设备号数据类型的宏定义*/
  12. #include
  13. /*定义字符设备的结构体*/
  14. #include
  15. /*分配内存空间函数头文件*/
  16. #include
  17. /*包含函数device_create 结构体class等头文件*/
  18. #include

  19. #include
  20. #include //包含prink等函数
  21. #include //与c++相关的东西
  22. #include //Linux中申请GPIO的头文件
  23. /*自定义头文件*/
  24. #include "char_driver_leds.h"

  25. #include //不同平台使用的文件
  26. #include


  27. MODULE_LICENSE("Dual BSD/GPL");
  28. /*声明是开源的,没有内核版本限制*/
  29. MODULE_AUTHOR("XIE_dz");
  30. /*声明作者*/

  31. static int led_gpios[] = {
  32.         PAD_GPIO_C + 11,PAD_GPIO_C + 10,
  33. };
  34. #define LED_NUM                ARRAY_SIZE(led_gpios)


  35. int numdev_major = DEV_MAJOR;
  36. int numdev_minor = DEV_MINOR;

  37. /*输入主设备号*/
  38. module_param(numdev_major,int,S_IRUSR);
  39. /*输入次设备号*/
  40. module_param(numdev_minor,int,S_IRUSR);

  41. static struct class *myclass;
  42. struct reg_dev *my_devices;

  43. /*打开操作*/
  44. static int chardevnode_open(struct inode *inode, struct file *file){
  45.         printk(KERN_EMERG "chardevnode_open is success!n");
  46.        
  47.         return 0;
  48. }
  49. /*关闭操作*/
  50. static int chardevnode_release(struct inode *inode, struct file *file){
  51.         printk(KERN_EMERG "chardevnode_release is success!n");
  52.        
  53.         return 0;
  54. }
  55. /*IO操作*/
  56. static long chardevnode_ioctl(struct file *file, unsigned int cmd, unsigned long arg){
  57.        
  58.         switch(cmd)
  59.         {
  60.                 case 0:
  61.                 case 1:
  62.                         if (arg > LED_NUM) {
  63.                                 return -EINVAL;
  64.                         }

  65.                         gpio_set_value(led_gpios[arg], cmd);
  66.                         break;

  67.                 default:
  68.                         return -EINVAL;
  69.         }
  70.        
  71.         printk(KERN_EMERG "chardevnode_ioctl is success! cmd is %d,arg is %d n",cmd,arg);
  72.        
  73.         return 0;
  74. }

  75. ssize_t chardevnode_read(struct file *file, char __user *buf, size_t count, loff_t *f_ops){
  76.         return 0;
  77. }

  78. ssize_t chardevnode_write(struct file *file, const char __user *buf, size_t count, loff_t *f_ops){
  79.         return 0;
  80. }

  81. loff_t chardevnode_llseek(struct file *file, loff_t offset, int ence){
  82.         return 0;
  83. }
  84. struct file_operations my_fops = {
  85.         .owner = THIS_MODULE,
  86.         .open = chardevnode_open,
  87.         .release = chardevnode_release,
  88.         .unlocked_ioctl = chardevnode_ioctl,
  89.         .read = chardevnode_read,
  90.         .write = chardevnode_write,
  91.         .llseek = chardevnode_llseek,
  92. };


  93. /*设备注册到系统*/
  94. static void reg_init_cdev(struct reg_dev *dev,int index){
  95.         int err;
  96.         int devno = MKDEV(numdev_major,numdev_minor+index);

  97.         /*数据初始化*/
  98.         cdev_init(&dev->cdev,&my_fops);
  99.         dev->cdev.owner = THIS_MODULE;
  100.        
  101.        
  102.         /*注册到系统*/
  103.         err = cdev_add(&dev->cdev,devno,1);
  104.         if(err){
  105.                 printk(KERN_EMERG "cdev_add %d is fail! %dn",index,err);
  106.         }
  107.         else{
  108.                 printk(KERN_EMERG "cdev_add %d is success!n",numdev_minor+index);
  109.         }
  110. }

  111. static int gpio_init(void){
  112.         int i=0,ret;
  113.        
  114.         for(i=0;i
  115.                 ret = gpio_request(led_gpios[i], "LED");
  116.                 if (ret) {
  117.                         printk("%s: request GPIO %d for LED failed, ret = %dn", DEVICE_NAME,i,ret);
  118.                         return -1;
  119.                 }
  120.                 else{
  121.                         gpio_direction_output(led_gpios[i], 1);
  122.                         //gpio_set_value(led_gpios[i], 1);                       
  123.                 }
  124.         }
  125.        
  126.         return 0;
  127. }


  128. static int scdev_init(void)
  129. {
  130.         int ret = 0,i;
  131.         dev_t num_dev;
  132.        
  133.        
  134.         printk(KERN_EMERG "numdev_major is %d!n",numdev_major);//主设备号
  135.         printk(KERN_EMERG "numdev_minor is %d!n",numdev_minor);//次设备号
  136.        
  137.         if(numdev_major){
  138.                 num_dev = MKDEV(numdev_major,numdev_minor);//生成设备号
  139.                 ret = register_chrdev_region(num_dev,DEVICE_MINOR_NUM,DEVICE_NAME);//向系统申请设备号(已知设备号)
  140.         }
  141.         else{
  142.                 /*动态注册设备号*/
  143.                 ret = alloc_chrdev_region(&num_dev,numdev_minor,DEVICE_MINOR_NUM,DEVICE_NAME);//向系统申请设备号(动态申请)
  144.                 /*获得主设备号*/
  145.                 numdev_major = MAJOR(num_dev);
  146.                 printk(KERN_EMERG "adev_region req %d !n",numdev_major);
  147.         }
  148.         if(ret<0){
  149.                 printk(KERN_EMERG "register_chrdev_region req %d is failed!n",numdev_major);               
  150.         }
  151.         myclass = class_create(THIS_MODULE,DEVICE_NAME);//创建设备类别文件
  152.        
  153.        
  154.         my_devices = kmalloc(DEVICE_MINOR_NUM * sizeof(struct reg_dev),GFP_KERNEL);//分配内存
  155.         if(!my_devices){
  156.                 ret = -ENOMEM;
  157.                 goto fail;
  158.         }
  159.         memset(my_devices,0,DEVICE_MINOR_NUM * sizeof(struct reg_dev));//将s中前n个字节用 ch 替换并返回 s 。
  160.        
  161.         /*设备初始化*/
  162.         for(i=0;i
  163.                 my_devices[i].data = kmalloc(REGDEV_SIZE,GFP_KERNEL);//GFP_KERNEL是一个宏,分配内核空间
  164.                 memset(my_devices[i].data,0,REGDEV_SIZE);
  165.                 /*设备注册到系统*/
  166.                 reg_init_cdev(&my_devices[i],i);
  167.                
  168.                 /*创建设备节点*/
  169.                 device_create(myclass,NULL,MKDEV(numdev_major,numdev_minor+i),NULL,DEVICE_NAME"%d",i);
  170.         }
  171.        
  172.         ret = gpio_init();
  173.         if(ret){
  174.                 printk(KERN_EMERG "gpio_init failed!n");
  175.         }       
  176.                
  177.         printk(KERN_EMERG "scdev_init!n");
  178.         /*打印信息,KERN_EMERG表示紧急信息*/
  179.         return 0;

  180. fail:
  181.         /*注销设备号*/
  182.         unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);
  183.         printk(KERN_EMERG "kmalloc is fail!n");
  184.        
  185.         return ret;
  186. }

  187. static void scdev_exit(void)
  188. {
  189.         int i;
  190.         printk(KERN_EMERG "scdev_exit!n");
  191.        
  192.         /*除去字符设备*/
  193.         for(i=0;i
  194.                 cdev_del(&(my_devices[i].cdev));//这个函数会干掉cdev_map 散列表及dev本身
  195.                 /*摧毁设备节点函数d*/
  196.                 device_destroy(myclass,MKDEV(numdev_major,numdev_minor+i));
  197.         }
  198.         /*释放设备class*/
  199.         class_destroy(myclass);
  200.         /*释放内存*/
  201.         kfree(my_devices);
  202.        
  203.         /*释放GPIO*/
  204.         for(i=0;i
  205.                 gpio_free(led_gpios[i]);
  206.         }
  207.         //释放设备号       
  208.         unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);
  209. }


  210. module_init(scdev_init);
  211. /*初始化函数*/
  212. module_exit(scdev_exit);
  213. /*卸载函数*/
还有调用该驱动的文件invoke_char_gpios.c
  1. #include
  2. //#include //根据环境变化的长度,各种_t
  3. //#include //获取文件属性函数,各种_t
  4. #include
  5. #include //各种系统api如read,write
  6. #include

  7. /*argv[1] is cmd , argv[2] is io_arg*/
  8. int main()
  9. {
  10.         int fd,i;
  11.         char *lednode = "/dev/charGPIO0";

  12.         /*O_RDWR只读打开,O_NDELAY非阻塞方式*/       
  13.         if((fd = open(lednode,O_RDWR|O_NDELAY))<0){
  14.                 printf("APP open %s failed!n",lednode);
  15.         }
  16.         else{
  17.                 printf("APP open %s success!n",lednode);
  18.                 //ioctl(fd,atoi(argv[1]),atoi(argv[2]));
  19.                 //printf("APP ioctl %s ,cmd is %s! io_arg is %s!n",lednode,argv[1],argv[2]);
  20.                 for(i=0;i<10;i++){
  21.                 ioctl(fd, 1, 0);
  22.                 ioctl(fd, 1, 1);
  23.                 sleep(1);

  24.                 ioctl(fd, 0, 0);
  25.                 ioctl(fd, 0, 1);
  26.                 sleep(1);
  27.             }
  28.         }
  29.        
  30.         close(fd);
  31.         return 0;
  32. }
以上就是全部的源码了,望各位大神指教咯。



回帖(1)

电子工程师2014

2016-9-3 22:06:30
这个好学吗
举报

更多回帖

发帖
×
20
完善资料,
赚取积分