Linux字符设备驱动——杂项设备驱动模型

系统管理员 2022-01-13 09:51 595阅读 0赞

文章目录

  • 杂项设备驱动模型
    • 杂项设备驱动的特征
    • 头文件
    • 核心结构
    • 杂项设备注册函数
    • 杂项设备注销函数
    • 总结:编写杂项设备驱动的基本步骤:
    • 杂项设备驱动示例代码
    • 杂项设备的驱动编写方法
  • 杂项设备驱动模型示例
    • 驱动程序zx_misc_led.c源代码
    • 应用程序app.c源代码
    • 实例代码测试

杂项设备驱动模型

杂项设备驱动的特征

1、 主设备号固定不变,为10
2、 注册后会自动在/dev目录下生成设备文件
3、 使用一个核心结构struct miscdevive封装起来

杂项设备的设备号
主设备号:固定为10
次设备号:0~255

头文件

include

核心结构

需要关注的几项

  1. struct miscdevive
  2. {
  3. int minor; //次设备号
  4. coust char *name; //设备名,在/dev下的设备节点
  5. const struct file_operations *fops; //设备文件操作方法指针(文件操作集合)
  6. }

当次设备号为255时,会自动由内核分配一个可用的次设备号
特点:安装后,会自动在dev/目录下创建设备节点。

杂项设备注册函数

int misc_register(struct miscdevice * misc)

例:misc_register(&misc_dev);

杂项设备注销函数

int misc_deregister(struct miscdevice *misc)

例:misc_deregister (&misc_dev);

总结:编写杂项设备驱动的基本步骤:

1、 先写一个模块基本代码;
2、 增加设备模型所需要的头文件;
3、 在模块的初始化函数注册设备对应的结构体;
4、 在模块的出口注销设备对应的结构;
5、 按照对应设备模型:注册函数需要的参数,反向退出应该的结构体成员。

杂项设备驱动示例代码

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/fs.h>
  4. #include <linux/miscdevice.h>
  5. static int misc_open(struct inode *pinode, struct file *pfile)
  6. {
  7. printk(KERN_EMERG "line:%d,%s is called\n",__LINE__,__FUNCTION__);
  8. return 0;
  9. }
  10. static ssize_t misc_read (struct file *pfile, char __user *buff, size_t size, loff_t *off)
  11. {
  12. printk(KERN_EMERG "line:%d,%s is called\n",__LINE__,__FUNCTION__);
  13. return 0;
  14. }
  15. static ssize_t misc_write(struct file *pfile, const char __user *buff, size_t size, loff_t *off)
  16. {
  17. printk(KERN_EMERG "line:%d,%s is called\n",__LINE__,__FUNCTION__);
  18. return 0;
  19. }
  20. static int misc_release(struct inode *pinode, struct file *pfile)
  21. {
  22. printk(KERN_EMERG "line:%d,%s is called\n",__LINE__,__FUNCTION__);
  23. return 0;
  24. }
  25. /*文件操作方法集合,名为:misc_fops*/
  26. static const struct file_operations misc_fops = {
  27. .read = misc_read,
  28. .write = misc_write,
  29. .release = misc_release,
  30. .open = misc_open,
  31. };
  32. /*杂项设备核心结构,名为:misc_dev*/
  33. static struct miscdevice misc_dev = {
  34. .fops = &misc_fops, /* 设备文件操作方法 */
  35. .minor = 255, /* 次设备号 */
  36. .name = zxlinux”, /* 设备名/dev/下的设备节点名*/
  37. };
  38. static int __init misc_init(void)
  39. {
  40. misc_register(&misc_dev); //杂项设备注册函数
  41. printk(KERN_EMERG "misc init = 0\n");
  42. return 0;
  43. }
  44. static void __exit misc_exit(void)
  45. {
  46. misc_deregister(&misc_dev); //杂项设备注销函数
  47. printk(KERN_EMERG "Goodbye,misc\n");
  48. }
  49. module_init(misc_init);
  50. module_exit(misc_exit);
  51. MODULE_LICENSE("GPL");

开发板上运行结果

  1. [root@ZX20150811 /home]# ls
  2. misc.ko
  3. [root@ZX20150811 /home]# insmod misc.ko
  4. [ 5145.395000] misc init = 0
  5. [root@ZX20150811 /home]# lsmod
  6. Tainted: P
  7. misc 1701 0 - Live 0xbf024000 (O)
  8. [root@ZX20150811 /home]# ls /dev/ | grep zxlinux
  9. zxlinux

杂项设备的驱动编写方法

针对驱动编写
1、 定义一个file_operations
2、 定义一个miscdevice
3、 在入口函数中调用 misc_register
4、 在出口函数中调用misc_deregister
5、 写一个应用程序,测试这个驱动是否按照计划运行,对比结果

核心工作是实现:file_operation
file_operations中的接口函数

杂项设备驱动模型示例

驱动程序zx_misc_led.c源代码

  1. #include <linux/module.h> /* 驱动模块头文件 */
  2. #include <linux/init.h>
  3. #include <linux/fs.h>
  4. #include <linux/miscdevice.h>
  5. #include <asm/io.h> /*开发板引脚支持头文件*/
  6. #include <asm/uaccess.h> /*copy_from_user ,copy_to_user*/
  7. #include<linux/gpio.h> // GPIO头文件
  8. #define DEVICE_NAME "zx_misc_led"
  9. #define LED_NUM (4)
  10. static unsigned int LED_pin[4] = {
  11. EXYNOS4X12_GPM4(0),
  12. EXYNOS4X12_GPM4(1),
  13. EXYNOS4X12_GPM4(2),
  14. EXYNOS4X12_GPM4(3),
  15. };
  16. static ssize_t misc_read (struct file *pfile, char __user *buff, size_t size, loff_t *off)
  17. {
  18. printk(KERN_EMERG "line:%d,%s is call\n", __LINE__, __FUNCTION__);
  19. return 0;
  20. }
  21. static ssize_t misc_write(struct file *filp,
  22. const char __user *user_buf,
  23. size_t count,
  24. loff_t *off)
  25. {
  26. int ret = 0;
  27. char buf[LED_NUM] = {0};
  28. int i = 0;
  29. printk(KERN_EMERG "line:%d,%s is call\n", __LINE__, __FUNCTION__);
  30. if(count == 0) //应用程序传递count=0下来,并不是错误,应该返回0
  31. {
  32. return 0;
  33. }
  34. if(count > LED_NUM) //因为板子只有4个灯,所以防止用户程序恶意破坏系统。
  35. {
  36. count = LED_NUM;
  37. }
  38. ret = copy_from_user(buf, user_buf, count); //用户空间传数据到内核空间
  39. if(ret) //如果复制失败返回-1;
  40. {
  41. return -1;
  42. }
  43. for(i = 0; i < count; i++)
  44. {
  45. if(buf[i] == 1)
  46. {
  47. gpio_set_value(LED_pin[i],0);/* 亮 */
  48. }
  49. else if(buf[i] == 0)
  50. {
  51. gpio_set_value(LED_pin[i],1);/* 灭 */
  52. }
  53. }
  54. return count;
  55. }
  56. static int misc_open(struct inode *pinode, struct file *pfile)
  57. {
  58. printk(KERN_EMERG "line:%d,%s is call\n", __LINE__, __FUNCTION__);
  59. return 0;
  60. }
  61. static int misc_release(struct inode *pinode, struct file *pfile)
  62. {
  63. printk(KERN_EMERG "line:%d,%s is call\n", __LINE__, __FUNCTION__);
  64. return 0;
  65. }
  66. static const struct file_operations misc_led_fops =
  67. {
  68. .read = misc_read,
  69. .write = misc_write,
  70. .release = misc_release,
  71. .open = misc_open,
  72. };
  73. static struct miscdevice misc_led_dev =
  74. {
  75. .fops = &misc_led_fops,
  76. .minor = 255,
  77. .name = DEVICE_NAME,
  78. };
  79. static int __init misc_led__init(void)
  80. {
  81. int ret;
  82. int i;
  83. for(i = 0;i < 4; i++)
  84. {
  85. ret = gpio_request(LED_pin[i],"leds");
  86. if(ret < 0)
  87. {
  88. printk(KERN_EMERG "gpio_request is error\n");
  89. goto gpio_request_err;
  90. }
  91. gpio_direction_output(LED_pin[i],1); //设置为输出功能,并且输出高电平
  92. }
  93. ret = misc_register(&misc_led_dev);
  94. if(ret)
  95. {
  96. goto gpio_request_err;
  97. }
  98. printk(KERN_EMERG "%s is OK!!!\n",__FUNCTION__);
  99. return 0;
  100. gpio_request_err:
  101. for(--i;i>=0;i--)
  102. {
  103. gpio_free(LED_pin[i]);
  104. }
  105. return ret ;
  106. }
  107. static void __exit zx_misc_led_exit(void)
  108. {
  109. int i = 0;
  110. for(i=0;i<4;i++)
  111. {
  112. gpio_set_value(LED_pin[i],1); //灭灯
  113. gpio_free(LED_pin[i]); //释放GPIO
  114. }
  115. misc_deregister(&misc_led_dev);
  116. printk(KERN_EMERG "Goodbye,zx_misc_led\n");
  117. }
  118. module_init(zx_misc_led_init);
  119. module_exit(zx_misc_led_exit);
  120. MODULE_LICENSE("GPL");

应用程序app.c源代码

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #define DEV_NAME "/dev/zx_misc_led"
  9. int main(void)
  10. {
  11. char buf[] = {1, 0, 0, 0}; //1,亮,0表示灭,
  12. int i = 0;
  13. int fd;
  14. //打开设备文件 O_RDWR, O_RDONLY, O_WRONLY,
  15. fd = open(DEV_NAME, O_RDWR);
  16. if(fd < 0)
  17. {
  18. printf("open :%s failt!\r\n", DEV_NAME);
  19. }
  20. while(1)
  21. {
  22. write(fd, buf, 4);
  23. memset(buf, 0, 4);
  24. buf[i++ % 4] = 1;
  25. sleep(1);
  26. }
  27. return 0;
  28. }

实例代码测试

  1. [root@ZX20150811 /home]# ls
  2. [root@ZX20150811 /home]# insmod zx_misc_led.ko
  3. [ 2247.770000] zx_misc_led_init is OK!!!
  4. [root@ZX20150811 /home]# ./app
  5. [ 2252.910000] line:59,misc_open is call
  6. [ 2252.910000] line:34,misc_write is call
  7. [ 2253.910000] line:34,misc_write is call
  8. [ 2254.910000] line:34,misc_write is call
  9. [ 2255.915000] line:34,misc_write is call
  10. ^C[ 2256.190000] line:66,misc_release is call
  11. [root@ZX20150811 /home]#

发表评论

表情:
评论列表 (有 0 条评论,595人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Linux字符设备驱动模型(一)

    从事Linux开发也有几年时间了,期间也写了一些比较简单的驱动,但一直没有做系统的整理,今天终于想静下心来做一些整理,首先就从最基本的字符设备驱动开始。先贴出一个简单的字符设备