• 驱动开发,IO模型,信号驱动IO实现过程


     1.信号驱动IO框架图

    分析:

            信号驱动IO是一种异步IO方式。linux预留了一个信号SIGIO用于进行信号驱动IO。进程主程序注册一个SIGIO信号的信号处理函数,当硬件数据准备就绪后会发起一个硬件中断,在中断的处理函数中向当前进程发送一个SIGIO信号。进程收到SIGIO信号后执行信号处理函数,在信号处理函数中将数据读走即可。

    应用层:1.打开设备文件,2注册SIGIO信号处理函数,3回调驱动中的fasync方法,4设置fd对应的驱动程序发送SIGIO信号只发送给当前进程

    驱动层:完成异步对象的空间分配和初始化

    硬件层:中断处理函数:发送SIGIO信号(用到异步对象的二级指针)

    2.实现代码

    ---pro1.c---应用程序(信号驱动IO)
    1. #include <sys/types.h>
    2. #include <sys/stat.h>
    3. #include <fcntl.h>
    4. #include <stdio.h>
    5. #include <string.h>
    6. #include <unistd.h>
    7. #include <stdlib.h>
    8. #include <sys/ioctl.h>
    9. #include <sys/select.h>
    10. #include <sys/time.h>
    11. #include <signal.h>
    12. char buf[128] = {0};
    13. int fd;
    14. void sigio_handler(int sig)
    15. {
    16. read(fd, buf, sizeof(buf));
    17. printf("buf:%s\n", buf);
    18. }
    19. int main(int argc, const char *argv[])
    20. {
    21. // 1打开设备文件
    22. fd = open("/dev/mmyled0", O_RDWR);
    23. if (fd < 0)
    24. {
    25. printf("自定义事件文件失败\n");
    26. exit(-1);
    27. }
    28. // 2注册SIGIO信号的处理函数
    29. signal(SIGIO, sigio_handler);
    30. // 3回调驱动中的fasync方法,完成发送信号之前的准备工作
    31. int flags = fcntl(fd,F_GETFL); //获取文件描述符属性
    32. fcntl(fd,F_SETFL,flags|FASYNC); //添加FASYNC属性就可以回调fasync操作方法
    33. // 4驱动发送信号只发送给当前进程
    34. fcntl(fd,F_SETOWN,getpid());
    35. while(1)
    36. {
    37. printf("...等待信号驱动IO事件...\n");
    38. sleep(1);
    39. }
    40. close(fd);
    41. return 0;
    42. }
    ---pro2.c---应用程序(模拟模拟硬件数据到达)
    1. #include <sys/types.h>
    2. #include <sys/stat.h>
    3. #include <fcntl.h>
    4. #include <stdio.h>
    5. #include <string.h>
    6. #include <unistd.h>
    7. #include <stdlib.h>
    8. int main(int argc, const char *argv[])
    9. {
    10. char buf[128] = "hello world";
    11. int fd = open("/dev/mmyled0", O_RDWR);
    12. if (fd < 0)
    13. {
    14. printf("打开设备文件失败\n");
    15. exit(-1);
    16. }
    17. write(fd, buf, sizeof(buf));
    18. close(fd);
    19. return 0;
    20. }
    ---driceio.c---驱动程序
    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/fs.h>
    4. #include <linux/io.h>
    5. #include <linux/device.h>
    6. #include <linux/uaccess.h>
    7. #include <linux/wait.h>
    8. #include<linux/poll.h>
    9. char kbuf[128] = {0};
    10. unsigned int major;
    11. struct class *cls;
    12. struct device *dev;
    13. struct fasync_struct *fp; //定义一个异步对象指针
    14. // 封装操作方法
    15. int mycdev_open(struct inode *inode, struct file *file)
    16. {
    17. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    18. return 0;
    19. }
    20. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
    21. {
    22. int ret;
    23. ret = copy_to_user(ubuf, kbuf, size);
    24. if (ret)
    25. {
    26. printk("copy_to_ user err\n");
    27. return -EIO;
    28. }
    29. return 0;
    30. }
    31. ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
    32. {
    33. int ret;
    34. // 从用户拷贝数据,模拟硬件数据
    35. ret = copy_from_user(kbuf, ubuf, size);
    36. if (ret)
    37. {
    38. printk("copy_from_user err\n");
    39. return -EIO;
    40. }
    41. //内核模块发送信号
    42. kill_fasync(&fp,SIGIO,POLL_IN);
    43. return 0;
    44. }
    45. int mycdev_fasync(int fd,struct file *file,int on) //异步操作方法
    46. {
    47. //完成发送信号之前的准备工作
    48. //异步对象空间的分配语言初始化
    49. fasync_helper(fd,file,on,&fp);
    50. return 0;
    51. }
    52. int mycdev_close(struct inode *inode, struct file *file)
    53. {
    54. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    55. return 0;
    56. }
    57. struct file_operations fops = {
    58. .open = mycdev_open,
    59. .read = mycdev_read,
    60. .fasync = mycdev_fasync,
    61. .write = mycdev_write,
    62. .release = mycdev_close,
    63. };
    64. // 入口函数
    65. static int __init mycdev_init(void)
    66. {
    67. major = register_chrdev(0, "myled", &fops);
    68. if (major < 0)
    69. {
    70. printk("字符设备驱动注册失败\n");
    71. return major;
    72. }
    73. printk("字符设备驱动注册成功:major=%d\n", major);
    74. // 向上提交目录
    75. cls = class_create(THIS_MODULE, "MYLED");
    76. if (IS_ERR(cls))
    77. {
    78. printk("向上提交目录失败\n");
    79. return -PTR_ERR(cls);
    80. }
    81. printk("向上提交目录成功\n");
    82. // 向上提交设备节点信息
    83. int i;
    84. for (i = 0; i < 3; i++)
    85. {
    86. dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mmyled%d", i);
    87. if (IS_ERR(dev))
    88. {
    89. printk("向上提交设备节点信息失败\n");
    90. return -PTR_ERR(dev);
    91. }
    92. }
    93. printk("向上提交设备节点信息成功\n");
    94. return 0;
    95. }
    96. // 出口函数
    97. static void __exit mycdev_exit(void)
    98. {
    99. // 销毁设备节点信息
    100. int i;
    101. for (i = 0; i < 3; i++)
    102. {
    103. device_destroy(cls, MKDEV(major, i));
    104. }
    105. // 销毁目录信息
    106. class_destroy(cls);
    107. // 字符设备驱动注销
    108. unregister_chrdev(major, "myled");
    109. }
    110. // 声明
    111. // 入口函数地址
    112. module_init(mycdev_init);
    113. // 出口函数地址
    114. module_exit(mycdev_exit);
    115. // 遵循的GPL协议
    116. MODULE_LICENSE("GPL");

     

    3.测试结果

  • 相关阅读:
    【ML】K-Means 聚类
    多版本node的安装与切换详细操作
    Scala
    C#向RichTextbox中复制内容时去除源文本格式
    VSCode 的安装与插件配置
    mall-1-搭建环境
    C#-WinForm-发送邮件
    华为FinalMLP
    ProCAST 2016 warning-8 = invalid inconsistent license key
    网络编程的学习
  • 原文地址:https://blog.csdn.net/weixin_46260677/article/details/132918505