ledUser.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #include <linux/module.h>
  2. #include <linux/platform_device.h>
  3. #include <linux/of.h>
  4. #include <linux/fs.h>
  5. #include <linux/cdev.h>
  6. #include <linux/uaccess.h> // for copy_to_user() and copy_from_user()
  7. const char *TAG = "MYNEWNODE";
  8. static int major_number = 0; // 默认自动分配主设备号
  9. static struct cdev my_cdev;
  10. static struct class *my_class;
  11. char data_buf[100] = "Hello from kernel space! .";
  12. char write_buf[100 = "Hello from user space!";
  13. // 打开字符设备
  14. static int gpio_led_open(struct inode *inode, struct file *file)
  15. {
  16. printk("%s: open!\n", TAG);
  17. return 0;
  18. }
  19. // 关闭字符设备
  20. static int gpio_led_release(struct inode *inode, struct file *file)
  21. {
  22. printk("%s: release!\n", TAG);
  23. return 0;
  24. }
  25. // 读取数据(从内核空间的 data_buf[] 数组中读取数据)
  26. static ssize_t gpio_led_read(struct file *file, char __user *buf, size_t len, loff_t *offset)
  27. {
  28. ssize_t ret;
  29. size_t to_read;
  30. printk("%s: read!\n", TAG);
  31. if (*offset >= sizeof(data_buf)) {
  32. return 0; // 没有更多数据可以读取
  33. }
  34. // 计算最多读取的数据长度,并确保不会越界
  35. to_read = min(len, (size_t)(sizeof(data_buf) - *offset)); // 强制转换为 size_t 类型
  36. // 从内核空间复制数据到用户空间
  37. ret = copy_to_user(buf, data_buf + *offset, to_read);
  38. if (ret != 0) {
  39. printk("%s: copy_to_user failed!\n", TAG);
  40. return -EFAULT;
  41. }
  42. // 更新偏移量
  43. *offset += to_read;
  44. return to_read; // 返回实际读取的字节数
  45. }
  46. // 写入数据(将数据保存到内核空间的 data_buf[] 数组)
  47. static ssize_t gpio_led_write(struct file *file, const char __user *buf, size_t len, loff_t *offset)
  48. {
  49. ssize_t ret;
  50. printk("%s: write!\n", TAG);
  51. // 确保写入的数据大小不超过缓冲区
  52. if (len > sizeof(data_buf)) {
  53. printk("%s: write data_buf too large!\n", TAG);
  54. return -EINVAL;
  55. }
  56. // 从用户空间复制数据到内核空间
  57. ret = copy_from_user(data_buf, buf, len);
  58. if (ret != 0) {
  59. printk("%s: copy_from_user failed!\n", TAG);
  60. return -EFAULT;
  61. }
  62. return len; // 返回实际写入的字节数
  63. }
  64. // 字符设备操作结构体
  65. static const struct file_operations gpio_led_fops = {
  66. .owner = THIS_MODULE,
  67. .open = gpio_led_open,
  68. .release = gpio_led_release,
  69. .read = gpio_led_read,
  70. .write = gpio_led_write,
  71. };
  72. // probe函数:设备初始化时调用
  73. static int gpio_led_probe(struct platform_device *pdev)
  74. {
  75. int ret;
  76. printk("%s: probe!\n", TAG);
  77. // 为字符设备分配主设备号
  78. ret = alloc_chrdev_region(&major_number, 0, 1, "gpio_led");
  79. if (ret < 0) {
  80. printk("%s: alloc_chrdev_region failed!\n", TAG);
  81. return ret;
  82. }
  83. // 注册字符设备
  84. cdev_init(&my_cdev, &gpio_led_fops);
  85. my_cdev.owner = THIS_MODULE;
  86. ret = cdev_add(&my_cdev, major_number, 1);
  87. if (ret) {
  88. printk("%s: cdev_add failed!\n", TAG);
  89. unregister_chrdev_region(major_number, 1);
  90. return ret;
  91. }
  92. // 创建设备类
  93. my_class = class_create(THIS_MODULE, "gpio_led_class");
  94. if (IS_ERR(my_class)) {
  95. ret = PTR_ERR(my_class);
  96. printk("%s: class_create failed!\n", TAG);
  97. cdev_del(&my_cdev);
  98. unregister_chrdev_region(major_number, 1);
  99. return ret;
  100. }
  101. // 创建设备节点
  102. if (IS_ERR(device_create(my_class, NULL, major_number, NULL, "gpio_led"))) {
  103. printk("%s: device_create failed!\n", TAG);
  104. class_destroy(my_class);
  105. cdev_del(&my_cdev);
  106. unregister_chrdev_region(major_number, 1);
  107. return -ENOMEM;
  108. }
  109. return 0;
  110. }
  111. // remove函数:设备卸载时调用
  112. static int gpio_led_remove(struct platform_device *pdev)
  113. {
  114. printk("%s: remove!\n", TAG);
  115. // 注销字符设备
  116. device_destroy(my_class, major_number);
  117. class_destroy(my_class);
  118. cdev_del(&my_cdev);
  119. unregister_chrdev_region(major_number, 1);
  120. return 0;
  121. }
  122. // shutdown函数:设备关闭时调用
  123. static void gpio_led_shutdown(struct platform_device *pdev)
  124. {
  125. printk("%s: shutdown!\n", TAG);
  126. }
  127. static const struct of_device_id of_gpio_leds_match[] = {
  128. { .compatible = "led-user", },
  129. {}
  130. };
  131. MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
  132. // 定义平台驱动
  133. static struct platform_driver gpio_led_driver = {
  134. .probe = gpio_led_probe,
  135. .remove = gpio_led_remove,
  136. .shutdown = gpio_led_shutdown,
  137. .driver = {
  138. .name = "led-user",
  139. .of_match_table = of_gpio_leds_match,
  140. },
  141. };
  142. module_platform_driver(gpio_led_driver);
  143. MODULE_LICENSE("GPL");
  144. MODULE_AUTHOR("Your Name");
  145. MODULE_DESCRIPTION("Simple GPIO LEDs driver");