1. 结构体定义和实例化
// 这个结构体样式并不固定,按需增减成员,可以参考内核的其他驱动代码
struct leddev_dev{dev_t devid; /* 设备号*/struct cdev cdev; /* cdev*/struct class *class; /* 类*/struct device *device; /* 设备*/int major; /* 主设备号*/ struct device_node *node; /* LED设备节点*/int led0; /* LED灯GPIO标号*/
}leddev;/*这个结构体最少也要有这些成员,可以参考内核的驱动代码*/
struct platform_driver led_platform_driver = {.probe = led_probe,.driver = {.name = "leds-platform_gpio",.owner = THIS_MODULE,.of_match_table = led_ids,}
};
2. 注册与卸载配套API
注意:顺序注册,逆序卸载
- 执行
led_platform_driver_init
、led_platform_driver_exit
函数
module_init(led_platform_driver_init);
module_exit(led_platform_driver_exit);
- 注册卸载平台驱动
DriverState = platform_driver_register(&led_platform_driver);
platform_driver_unregister(&led_platform_driver);
- 在
/proc/devices/LEDDEV_NAME
下生成名称对应LEDDEV_NAME
的主设备号
alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);
unregister_chrdev_region(leddev.devid, LEDDEV_CNT);
cdev_init(&leddev.cdev, &led_fops);
cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);
cdev_del(&leddev.cdev);
- 在
/sys/class/LEDDEV_NAME
下创建类
leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);
class_destroy(leddev.class);
- 在
/dev/LEDDEV_NAME
下创建设备节点,在/sys/devices/virtual/gpio_lab_led
下创建设备
leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);
device_destroy(leddev.class, leddev.devid);
- 试验了一下,现在的内核不需要显式释放
leddev.led0
leddev.led0 = of_get_named_gpio(leddev.node, "led-gpio", 0);
gpio_direction_output(leddev.led0, 1);
3. 完整代码(仅供参考)
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/of_gpio.h>
#define LEDDEV_CNT 1
#define LEDDEV_NAME "gpio_lab_led"
/* leddev设备结构体 */
struct leddev_dev{dev_t devid; /* 设备号 */struct cdev cdev; /* cdev */struct class *class; /* 类 */struct device *device; /* 设备 */int major; /* 主设备号 */ struct device_node *node; /* LED设备节点 */int led0; /* LED灯GPIO标号 */
};struct leddev_dev leddev; /* led设备 */static int led_open(struct inode *inode, struct file *filp)
{return 0;
}static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{return 0;
}// /* 设备操作函数 */
static struct file_operations led_fops = {.owner = THIS_MODULE,.open = led_open,.write = led_write,
};/*----------------平台驱动函数集-----------------*/
static int led_probe(struct platform_device *pdv)
{printk(KERN_EMERG "led driver and device was matched!\r\n");// 注册的设备ID保存到leddev.devid// LEDDEV_NAME对应/proc/devices下的名字alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);leddev.major = MAJOR(leddev.devid);printk(KERN_EMERG "\tleddev.major = %d\n",leddev.major);// 绑定操作函数cdev_init(&leddev.cdev, &led_fops);// 绑定设备IDcdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);/* 3、创建类 */leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);if (IS_ERR(leddev.class)) {return PTR_ERR(leddev.class);}/* 4、创建设备 */leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);if (IS_ERR(leddev.device)) {return PTR_ERR(leddev.device);}leddev.node = of_find_node_by_path("/lab_led");if(leddev.node == NULL){printk(KERN_EMERG "get lab_led failed! \n");}leddev.led0 = of_get_named_gpio(leddev.node, "gpios", 0);printk("led = %d \n",leddev.led0);/*设置gpio输出高电平*/gpio_direction_output(leddev.led0, 1);return 0;
}static const struct of_device_id led_ids[] = {{ .compatible = "gpio_lab_led"},{ /* sentinel */ }
};/*定义平台设备结构体*/
struct platform_driver led_platform_driver = {.probe = led_probe,.driver = {.name = "leds-platform_gpio",.owner = THIS_MODULE,.of_match_table = led_ids,}
};/*
*驱动初始化函数
*/
static int __init led_platform_driver_init(void)
{int DriverState;DriverState = platform_driver_register(&led_platform_driver);printk(KERN_EMERG "\tDriverState is %d\n",DriverState);return 0;
}/*
*驱动注销函数
*/
static void __exit led_platform_driver_exit(void)
{printk(KERN_EMERG "led_test exit!\n");gpio_direction_output(leddev.led0, 0);device_destroy(leddev.class, leddev.devid);class_destroy(leddev.class);cdev_del(&leddev.cdev); /* 删除cdev */unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /* 注销设备号 */platform_driver_unregister(&led_platform_driver);
}
module_init(led_platform_driver_init);
module_exit(led_platform_driver_exit);MODULE_LICENSE("GPL");