|
|
@@ -0,0 +1,135 @@
|
|
|
+#include <linux/module.h>
|
|
|
+#include <linux/platform_device.h>
|
|
|
+#include <linux/of.h>
|
|
|
+#include <linux/fs.h>
|
|
|
+#include <linux/cdev.h>
|
|
|
+#include <linux/uaccess.h> // for copy_to_user() and copy_from_user()
|
|
|
+const char *TAG = "MYNEWNODE";\
|
|
|
+
|
|
|
+static int major_number = 0; // 默认自动分配主设备号
|
|
|
+static struct cdev my_cdev;
|
|
|
+static struct class *my_class;
|
|
|
+
|
|
|
+
|
|
|
+// 打开字符设备
|
|
|
+static int gpio_led_open(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ printk("%s:open!\n", TAG);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+// 关闭字符设备
|
|
|
+static int gpio_led_release(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ printk("%s:release!\n", TAG);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+// 读取数据(此示例没有实际硬件操作)
|
|
|
+static ssize_t gpio_led_read(struct file *file, char __user *buf, size_t len, loff_t *offset)
|
|
|
+{
|
|
|
+ printk("%s:read!\n", TAG);
|
|
|
+ // 这里可以填充实际的读取逻辑,如果需要从硬件读取数据
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+// 写入数据(此示例没有实际硬件操作)
|
|
|
+static ssize_t gpio_led_write(struct file *file, const char __user *buf, size_t len, loff_t *offset)
|
|
|
+{
|
|
|
+ printk("%s:write!\n", TAG);
|
|
|
+ // 这里可以填充实际的写入逻辑,如果需要控制硬件
|
|
|
+ return len; // 返回实际写入的字节数
|
|
|
+}
|
|
|
+
|
|
|
+// 字符设备操作结构体
|
|
|
+static const struct file_operations gpio_led_fops = {
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+ .open = gpio_led_open,
|
|
|
+ .release = gpio_led_release,
|
|
|
+ .read = gpio_led_read,
|
|
|
+ .write = gpio_led_write,
|
|
|
+};
|
|
|
+
|
|
|
+static int gpio_led_probe(struct platform_device *pdev)
|
|
|
+{ int ret;
|
|
|
+ // 这里可以添加初始化代码
|
|
|
+ printk("%s:probe!\n",TAG);
|
|
|
+
|
|
|
+ ret = alloc_chrdev_region(&major_number,0,1,"gpio_led");
|
|
|
+ if(ret < 0){
|
|
|
+ printk("%s:alloc_chrdev_region failed!\n", TAG);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 注册字符设备
|
|
|
+ cdev_init(&my_cdev, &gpio_led_fops);
|
|
|
+ my_cdev.owner = THIS_MODULE;
|
|
|
+ ret = cdev_add(&my_cdev, major_number, 1);
|
|
|
+ if (ret) {
|
|
|
+ printk("%s:cdev_add failed!\n", TAG);
|
|
|
+ unregister_chrdev_region(major_number, 1);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建设备文件
|
|
|
+ my_class = class_create(THIS_MODULE, "gpio_led_class");
|
|
|
+ if (IS_ERR(my_class)) {
|
|
|
+ ret = PTR_ERR(my_class);
|
|
|
+ printk("%s:class_create failed!\n", TAG);
|
|
|
+ cdev_del(&my_cdev);
|
|
|
+ unregister_chrdev_region(major_number, 1);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (IS_ERR(device_create(my_class, NULL, major_number, NULL, "gpio_led"))) {
|
|
|
+ printk("%s:device_create failed!\n", TAG);
|
|
|
+ class_destroy(my_class);
|
|
|
+ cdev_del(&my_cdev);
|
|
|
+ unregister_chrdev_region(major_number, 1);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0; // 返回 0 表示成功
|
|
|
+}
|
|
|
+
|
|
|
+// 设备remove函数
|
|
|
+static int gpio_led_remove(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ printk("%s:remove!\n", TAG);
|
|
|
+
|
|
|
+ // 注销字符设备
|
|
|
+ device_destroy(my_class, major_number);
|
|
|
+ class_destroy(my_class);
|
|
|
+ cdev_del(&my_cdev);
|
|
|
+ unregister_chrdev_region(major_number, 1);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void gpio_led_shutdown(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ printk("%s:shutdown!\n", TAG);
|
|
|
+}
|
|
|
+
|
|
|
+static const struct of_device_id of_gpio_leds_match[] = {
|
|
|
+ { .compatible = "led-user", },
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
+MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
|
|
|
+
|
|
|
+static struct platform_driver gpio_led_driver = {
|
|
|
+ .probe = gpio_led_probe,
|
|
|
+ .remove = gpio_led_remove,
|
|
|
+ .shutdown = gpio_led_shutdown,
|
|
|
+ .driver = {
|
|
|
+ .name = "led-user",
|
|
|
+ .of_match_table = of_gpio_leds_match,
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+module_platform_driver(gpio_led_driver);
|
|
|
+
|
|
|
+MODULE_LICENSE("GPL");
|
|
|
+MODULE_AUTHOR("Your Name");
|
|
|
+MODULE_DESCRIPTION("Simple GPIO LEDs driver");
|