ledByMySelf.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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>
  7. #include <linux/gpio.h>
  8. #include <linux/of_gpio.h>
  9. const char *TAG = "MYNEWNODE";
  10. static int major_number = 0; // 默认自动分配主设备号
  11. static struct cdev my_cdev;
  12. static struct class *my_class;
  13. static int gpio_pin = -1; // GPIO 引脚号
  14. // 打开字符设备
  15. static int gpio_led_open(struct inode *inode, struct file *file)
  16. {
  17. int ret;
  18. printk("%s:open!\n", TAG);
  19. // 如果 GPIO 引脚没有初始化,先进行初始化
  20. if (gpio_pin < 0) {
  21. printk("%s:GPIO not initialized correctly.\n", TAG);
  22. return -EINVAL;
  23. }
  24. // 设置 GPIO 为输出模式,初始化时设置为低电平(关闭 LED)
  25. ret = gpio_direction_output(gpio_pin, 0); // 默认设置为低电平(LED 关闭)
  26. if (ret) {
  27. printk("%s:Failed to set GPIO direction\n", TAG);
  28. return ret;
  29. }
  30. // 可以根据需要设置 GPIO 的初始电平,比如点亮 LED
  31. gpio_set_value(gpio_pin, 1); // 设置为高电平,点亮 LED(假设低电平为关闭)
  32. return 0;
  33. }
  34. // 释放字符设备
  35. static int gpio_led_release(struct inode *inode, struct file *file)
  36. {
  37. printk("%s:release!\n", TAG);
  38. // 在设备释放时设置 GPIO 为低电平(关闭 LED)
  39. gpio_set_value(gpio_pin, 0); // 设置为低电平,关闭 LED
  40. return 0;
  41. }
  42. // 读取数据(此示例没有实际硬件操作)
  43. // 读取数据(控制 LED)
  44. static ssize_t gpio_led_read(struct file *file, char __user *buf, size_t len, loff_t *offset)
  45. {
  46. int gpio_value = 0;
  47. char read_buf[2]; // 用来存储读取的数据
  48. printk("%s:read!\n", TAG);
  49. // 模拟 LED 状态控制,循环写入 '0' 和 '1'
  50. if (*offset % 2 == 0) {
  51. gpio_value = 0; // 关闭 LED
  52. read_buf[0] = '0';
  53. } else {
  54. gpio_value = 1; // 点亮 LED
  55. read_buf[0] = '1';
  56. }
  57. // 设置 GPIO 引脚电平,控制 LED 开关
  58. gpio_set_value(gpio_pin, gpio_value);
  59. // 将 LED 状态写入到用户空间
  60. if (copy_to_user(buf, read_buf, 1)) {
  61. return -EFAULT;
  62. }
  63. // 更新偏移量,每次切换一次
  64. *offset += 1;
  65. return 1; // 返回读取的字节数
  66. }
  67. // 写入数据(控制 GPIO)
  68. static ssize_t gpio_led_write(struct file *file, const char __user *buf, size_t len, loff_t *offset)
  69. {
  70. char user_buf[10];
  71. int gpio_value = 0;
  72. printk("%s:write!\n", TAG);
  73. if (len > sizeof(user_buf) - 1) {
  74. len = sizeof(user_buf) - 1;
  75. }
  76. if (copy_from_user(user_buf, buf, len)) {
  77. return -EFAULT;
  78. }
  79. user_buf[len] = '\0';
  80. if (user_buf[0] == '1') {
  81. gpio_value = 1;
  82. } else if (user_buf[0] == '0') {
  83. gpio_value = 0;
  84. } else {
  85. return -EINVAL;
  86. }
  87. gpio_set_value(gpio_pin, gpio_value);
  88. return len;
  89. }
  90. static const struct file_operations gpio_led_fops = {
  91. .owner = THIS_MODULE,
  92. .open = gpio_led_open,
  93. .release = gpio_led_release,
  94. .read = gpio_led_read,
  95. .write = gpio_led_write,
  96. };
  97. // 设备probe函数
  98. static int gpio_led_probe(struct platform_device *pdev)
  99. {
  100. int ret;
  101. printk("%s:probe!\n", TAG);
  102. // 获取设备树中的 GPIO 引脚
  103. gpio_pin = of_get_named_gpio(pdev->dev.of_node, "gpios", 0);
  104. if (gpio_pin < 0) {
  105. printk("%s:Failed to get GPIO from device tree!\n", TAG);
  106. return gpio_pin;
  107. }
  108. // 申请 GPIO 引脚
  109. ret = gpio_request(gpio_pin, "gpio_led");
  110. if (ret) {
  111. printk("%s:Failed to request GPIO %d\n", TAG, gpio_pin);
  112. return ret;
  113. }
  114. // 初始化设备文件
  115. ret = alloc_chrdev_region(&major_number, 0, 1, "gpio_led");
  116. if (ret < 0) {
  117. printk("%s:alloc_chrdev_region failed!\n", TAG);
  118. return ret;
  119. }
  120. cdev_init(&my_cdev, &gpio_led_fops);
  121. my_cdev.owner = THIS_MODULE;
  122. ret = cdev_add(&my_cdev, major_number, 1);
  123. if (ret) {
  124. printk("%s:cdev_add failed!\n", TAG);
  125. unregister_chrdev_region(major_number, 1);
  126. return ret;
  127. }
  128. // 创建设备文件
  129. my_class = class_create(THIS_MODULE, "gpio_led_class");
  130. if (IS_ERR(my_class)) {
  131. ret = PTR_ERR(my_class);
  132. printk("%s:class_create failed!\n", TAG);
  133. cdev_del(&my_cdev);
  134. unregister_chrdev_region(major_number, 1);
  135. return ret;
  136. }
  137. if (IS_ERR(device_create(my_class, NULL, major_number, NULL, "gpio_led"))) {
  138. printk("%s:device_create failed!\n", TAG);
  139. class_destroy(my_class);
  140. cdev_del(&my_cdev);
  141. unregister_chrdev_region(major_number, 1);
  142. return -ENOMEM;
  143. }
  144. return 0;
  145. }
  146. // 设备remove函数
  147. static int gpio_led_remove(struct platform_device *pdev)
  148. {
  149. printk("%s:remove!\n", TAG);
  150. // 释放 GPIO 引脚
  151. gpio_free(gpio_pin);
  152. // 注销字符设备
  153. device_destroy(my_class, major_number);
  154. class_destroy(my_class);
  155. cdev_del(&my_cdev);
  156. unregister_chrdev_region(major_number, 1);
  157. return 0;
  158. }
  159. // 关机处理函数
  160. static void gpio_led_shutdown(struct platform_device *pdev)
  161. {
  162. printk("%s:shutdown!\n", TAG);
  163. }
  164. static const struct of_device_id of_gpio_leds_match[] = {
  165. { .compatible = "led-user", },
  166. {}
  167. };
  168. MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
  169. static struct platform_driver gpio_led_driver = {
  170. .probe = gpio_led_probe,
  171. .remove = gpio_led_remove,
  172. .shutdown = gpio_led_shutdown,
  173. .driver = {
  174. .name = "gpio_led_driver",
  175. .of_match_table = of_gpio_leds_match,
  176. },
  177. };
  178. module_platform_driver(gpio_led_driver);
  179. MODULE_LICENSE("GPL");
  180. MODULE_AUTHOR("Your Name");
  181. MODULE_DESCRIPTION("GPIO control driver with character device");