pcDuino Linux驱动开发三 -- 最简单的GPIO驱动

作者: tjcfeng
上传时间为: 2014-11-30 11:12 PM
2014-11-30
阅读:

本着从易到难的过程,现有程序完全基于那个最精简的驱动程序框架来实现,也就是字符设备+寄存器操作的方式,以后有时间再改为总线设备驱动。

pcDuino上有两个LED,TX和RX,就用它们来做实验了。


下面上代码,可参照《pcDuino Linux驱动开发二 -- 最简单的驱动程序框架》这个最精简的框架来看看增加的部分,无非就是多了些寄存器的操作:

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/fs.h>
  4. #include <linux/cdev.h>
  5. #include <linux/device.h>
  6. #include <asm/io.h>
  7. #include <asm/uaccess.h>
  8. #include "../A10.h"
  9. /**********************************************************************/
  10. #define LED_TX 15
  11. #define LED_RX 16
  12. #define LED_ON(Pin) (*REG_PH_DAT &= ~(0x1 << Pin))
  13. #define LED_OFF(Pin) (*REG_PH_DAT |= (0x1 << Pin) )
  14. #define LED_REVERSE(Pin) (*REG_PH_DAT ^= (0x1 << Pin) )
  15. volatile static unsigned long* REG_PH_CFG1;
  16. volatile static unsigned long* REG_PH_DAT;
  17. int Inited = 0;
  18. int LED_open(struct inode* n, struct file* f)
  19. {
  20. Inited++;
  21. if (Inited > 1) return Inited;
  22. REG_PH_CFG1 = (volatile unsigned long*) ioremap(PH_CFG1, 4);
  23. REG_PH_DAT = (volatile unsigned long*) ioremap(PH_DAT, 4);
  24. *REG_PH_CFG1 &= ~(0xF << 28);
  25. *REG_PH_CFG1 |= (0x1 << 28);
  26. LED_OFF(LED_TX);
  27. LED_OFF(LED_RX);
  28. printk("Open Finished!\n");
  29. return 0;
  30. }
  31. ssize_t LED_write(struct file* f, const char __user* buf, size_t len, loff_t* l)
  32. {
  33. unsigned char Buf[2];
  34. if (copy_from_user(&Buf, buf, len)) return -1;
  35. if ((Buf[0] != LED_TX) && (Buf[0] != LED_RX)) return -1;
  36. switch (Buf[1])
  37. {
  38. case 0:
  39. LED_OFF(Buf[0]);
  40. break;
  41. case 1:
  42. LED_ON(Buf[0]);
  43. break;
  44. case 2:
  45. LED_REVERSE(Buf[0]);
  46. break;
  47. default:
  48. return -1;
  49. }
  50. return len;
  51. }
  52. ssize_t LED_read(struct file* f, char __user* buf, size_t len, loff_t* l)
  53. {
  54. //int Buf;
  55. //copy_to_user(&Buf, buf, sizeof(int));
  56. printk("Read Finished!\n");
  57. return 0;
  58. }
  59. int LED_release(struct inode* n, struct file* f)
  60. {
  61. Inited--;
  62. if (Inited <= 0)
  63. {
  64. Inited = 0;
  65. return 0;
  66. }
  67. iounmap(REG_PH_CFG1);
  68. iounmap(REG_PH_DAT);
  69. printk("Release Finished!\n");
  70. return 0;
  71. }
  72. /**********************************************************************/
  73. #define DEV_NAME "LED"
  74. #define DEV_COUNT 1
  75. static dev_t Dev_Num;
  76. static struct cdev* pDev;
  77. static struct class* pClass;
  78. static struct file_operations fops =
  79. {
  80. .owner = THIS_MODULE,
  81. .open = LED_open,
  82. .write = LED_write,
  83. .read = LED_read,
  84. .release = LED_release,
  85. };
  86. static int __init LED_init(void)
  87. {
  88. int Result;
  89. Result = alloc_chrdev_region(&Dev_Num, 0, DEV_COUNT, DEV_NAME);
  90. if (Result)
  91. {
  92. printk("alloc_chrdev_region fail!\n");
  93. return Result;
  94. }
  95. pDev = cdev_alloc();
  96. if (pDev == NULL)
  97. {
  98. printk("cdev_alloc fail!\n");
  99. unregister_chrdev_region(Dev_Num, DEV_COUNT);
  100. return -1;
  101. }
  102. cdev_init(pDev, &fops);
  103. Result = cdev_add(pDev, Dev_Num, DEV_COUNT);
  104. if (Result)
  105. {
  106. printk("cdev_add fail!\n");
  107. cdev_del(pDev);
  108. return Result;
  109. }
  110. pClass = class_create(THIS_MODULE, DEV_NAME);
  111. if (pClass == NULL)
  112. {
  113. printk("class_create fail!\n");
  114. cdev_del(pDev);
  115. unregister_chrdev_region(Dev_Num, DEV_COUNT);
  116. return -1;
  117. }
  118. device_create(pClass, NULL, Dev_Num, "%s", DEV_NAME);
  119. printk("Init Finished!\n");
  120. return 0;
  121. }
  122. static void __exit LED_exit(void)
  123. {
  124. if (pClass)
  125. {
  126. device_destroy(pClass, Dev_Num);
  127. class_destroy(pClass);
  128. }
  129. if (pDev)
  130. {
  131. cdev_del(pDev);
  132. }
  133. unregister_chrdev_region(Dev_Num, DEV_COUNT);
  134. printk("Exit Finished!\n");
  135. }
  136. MODULE_LICENSE("GPL");
  137. MODULE_AUTHOR("LiuYang");
  138. module_init(LED_init);
  139. module_exit(LED_exit);

复制代码

这里没有实现Read函数,可以略过。

make 后生成LED.ko,使用insmod LED.ko加载模块,可以在/dev文件夹中看到,或者使用cat /proc/devices也可以看到。
调用rmmod LED后,该设备驱动模块被卸载,使用dmesg | tail -10来观察各个接口的加载情况,调试用。

全部评论 ()
条评论
写评论

创建讨论帖子

登录 后参与评论
系统提示