| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- #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>
- #include <linux/gpio.h>
- #include <linux/of_gpio.h>
- const char *TAG = "MYNEWNODE";
- static int major_number = 0; // 默认自动分配主设备号
- static struct cdev my_cdev;
- static struct class *my_class;
- static int gpio_pin = -1; // GPIO 引脚号
- // 打开字符设备
- static int gpio_led_open(struct inode *inode, struct file *file)
- {
- int ret;
- printk("%s:open!\n", TAG);
- // 如果 GPIO 引脚没有初始化,先进行初始化
- if (gpio_pin < 0) {
- printk("%s:GPIO not initialized correctly.\n", TAG);
- return -EINVAL;
- }
- // 设置 GPIO 为输出模式,初始化时设置为低电平(关闭 LED)
- ret = gpio_direction_output(gpio_pin, 0); // 默认设置为低电平(LED 关闭)
- if (ret) {
- printk("%s:Failed to set GPIO direction\n", TAG);
- return ret;
- }
- // 可以根据需要设置 GPIO 的初始电平,比如点亮 LED
- gpio_set_value(gpio_pin, 1); // 设置为高电平,点亮 LED(假设低电平为关闭)
- return 0;
- }
- // 释放字符设备
- static int gpio_led_release(struct inode *inode, struct file *file)
- {
- printk("%s:release!\n", TAG);
- // 在设备释放时设置 GPIO 为低电平(关闭 LED)
- gpio_set_value(gpio_pin, 0); // 设置为低电平,关闭 LED
- return 0;
- }
- // 读取数据(此示例没有实际硬件操作)
- // 读取数据(控制 LED)
- static ssize_t gpio_led_read(struct file *file, char __user *buf, size_t len, loff_t *offset)
- {
- int gpio_value = 0;
- char read_buf[2]; // 用来存储读取的数据
- printk("%s:read!\n", TAG);
- // 模拟 LED 状态控制,循环写入 '0' 和 '1'
- if (*offset % 2 == 0) {
- gpio_value = 0; // 关闭 LED
- read_buf[0] = '0';
- } else {
- gpio_value = 1; // 点亮 LED
- read_buf[0] = '1';
- }
- // 设置 GPIO 引脚电平,控制 LED 开关
- gpio_set_value(gpio_pin, gpio_value);
- // 将 LED 状态写入到用户空间
- if (copy_to_user(buf, read_buf, 1)) {
- return -EFAULT;
- }
- // 更新偏移量,每次切换一次
- *offset += 1;
- return 1; // 返回读取的字节数
- }
- // 写入数据(控制 GPIO)
- static ssize_t gpio_led_write(struct file *file, const char __user *buf, size_t len, loff_t *offset)
- {
- char user_buf[10];
- int gpio_value = 0;
- printk("%s:write!\n", TAG);
- if (len > sizeof(user_buf) - 1) {
- len = sizeof(user_buf) - 1;
- }
- if (copy_from_user(user_buf, buf, len)) {
- return -EFAULT;
- }
- user_buf[len] = '\0';
- if (user_buf[0] == '1') {
- gpio_value = 1;
- } else if (user_buf[0] == '0') {
- gpio_value = 0;
- } else {
- return -EINVAL;
- }
- gpio_set_value(gpio_pin, gpio_value);
- 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,
- };
- // 设备probe函数
- static int gpio_led_probe(struct platform_device *pdev)
- {
- int ret;
- printk("%s:probe!\n", TAG);
- // 获取设备树中的 GPIO 引脚
- gpio_pin = of_get_named_gpio(pdev->dev.of_node, "gpios", 0);
- if (gpio_pin < 0) {
- printk("%s:Failed to get GPIO from device tree!\n", TAG);
- return gpio_pin;
- }
- // 申请 GPIO 引脚
- ret = gpio_request(gpio_pin, "gpio_led");
- if (ret) {
- printk("%s:Failed to request GPIO %d\n", TAG, gpio_pin);
- return ret;
- }
- // 初始化设备文件
- 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;
- }
- // 设备remove函数
- static int gpio_led_remove(struct platform_device *pdev)
- {
- printk("%s:remove!\n", TAG);
- // 释放 GPIO 引脚
- gpio_free(gpio_pin);
- // 注销字符设备
- 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 = "gpio_led_driver",
- .of_match_table = of_gpio_leds_match,
- },
- };
- module_platform_driver(gpio_led_driver);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Your Name");
- MODULE_DESCRIPTION("GPIO control driver with character device");
|