文章目录
一、概述
整机调试中,我们经常需要操作某些io,下面就io驱动添加,和input输入事件,以及ioctl的控制io,三个部分来实现完整的控制和调试io的过程。可以porting到任何linux平台。
二、gpio demo驱动详解
1、dts的pinctrl配置
文件:trinket-idp.dtsi
//add gpio demo
gpio_demo {
compatible = "sylon,gpio-demo";
sylon,test1-gpio = <&tlmm 57 GPIO_ACTIVE_HIGH>;
sylon,test2-gpio = <&tlmm 58 GPIO_ACTIVE_HIGH>;
pinctrl-names = "active","suspend";
pinctrl-0 = <&gpio_demo_active>;
pinctrl-1 = <&gpio_demo_suspend>;
};
文件:trinket-pinctrl.dtsi
/* gpio demo */
gpio_demo: gpio_demo {
gpio_demo_active: gpio_demo_active{
mux {
pins = "gpio57", "gpio58";
function = "gpio";
};
config {
pins = "gpio57", "gpio58";
drive-strength = <8>;
bias-disable;
};
};
gpio_demo_suspend: gpio_demo_suspend{
mux {
pins = "gpio57", "gpio58";
function = "gpio";
};
config {
pins = "gpio57", "gpio58";
drive-strength = <2>;
bias-pull-down;
};
};
};
input_key_default: input_key_default {
mux {
pins = "gpio123", "gpio124", "gpio130", "gpio132";
function = "gpio";
};
config {
pins = "gpio123", "gpio124", "gpio130", "gpio132";
bias-pull-down;
input-enable;
};
};
/* gpio demo */
2、注册平台驱动,创建字符设备并分配设备id号。
3、io初始化
static int gpio_demo_probe(struct platform_device *pdev)
{
int err,ret;
struct device *dev = &pdev->dev;
int gpio123_di0_irq,gpio124_di1_irq,gpio130_di2_irq,gpio132_di3_irq;
//申请gpio并上拉
test1_gpio = of_get_named_gpio(dev->of_node, "sylon,test1-gpio", 0);
if (gpio_is_valid(test1_gpio)) {
err = gpio_request(test1_gpio, "test1");
if (err<0) {
pr_err("test1 gpio request failed\n");
}
gpio_direction_output(test1_gpio, 0);
gpio_set_value(test1_gpio, 1);
}
test2_gpio = of_get_named_gpio(dev->of_node, "sylon,test2-gpio", 0);
if (gpio_is_valid(test2_gpio)) {
err = gpio_request(test2_gpio, "test2");
if (err<0) {
pr_err("test2 gpio request failed\n");
}
gpio_direction_output(test2_gpio, 0);
gpio_set_value(test2_gpio, 1);
}
test3_gpio = of_get_named_gpio(dev->of_node, "sylon,test3-gpio", 0);
if (gpio_is_valid(test3_gpio)) {
err = gpio_request(test3_gpio, "gpio130_in");
if (err<0) {
pr_err("test3 gpio request failed\n");
}
gpio_direction_input(test3_gpio);
gpio130_di2_irq = gpio_to_irq(test3_gpio);
request_irq(gpio130_di2_irq, di2_interrput_handler,
IRQ_TYPE_EDGE_FALLING|IRQ_TYPE_EDGE_RISING,
"gpio130_di2_irq", NULL);
enable_irq_wake(gpio130_di2_irq);
}
test4_gpio = of_get_named_gpio(dev->of_node, "sylon,test4-gpio", 0);
if (gpio_is_valid(test4_gpio)) {
err = gpio_request(test4_gpio, "gpio132_in");
if (err<0) {
pr_err("test4 gpio request failed\n");
}
gpio_direction_input(test4_gpio);
gpio132_di3_irq = gpio_to_irq(test4_gpio);
request_irq(gpio132_di3_irq, di3_interrput_handler,
IRQ_TYPE_EDGE_FALLING|IRQ_TYPE_EDGE_RISING,
"gpio132_di3_irq", NULL);
enable_irq_wake(gpio132_di3_irq);
}
test5_gpio = of_get_named_gpio(dev->of_node, "sylon,test5-gpio", 0);
if (gpio_is_valid(test5_gpio)) {
err = gpio_request(test5_gpio, "gpio123_in");
if (err<0) {
pr_err("test5 gpio request failed\n");
}
gpio_direction_input(test5_gpio);
gpio123_di0_irq = gpio_to_irq(test5_gpio);
request_irq(gpio123_di0_irq, di0_interrput_handler,
IRQ_TYPE_EDGE_FALLING|IRQ_TYPE_EDGE_RISING,
"gpio123_di0_irq", NULL);
enable_irq_wake(gpio123_di0_irq);
}
test6_gpio = of_get_named_gpio(dev->of_node, "sylon,test6-gpio", 0);
if (gpio_is_valid(test6_gpio)) {
err = gpio_request(test6_gpio, "gpio124_in");
if (err<0) {
pr_err("test6 gpio request failed\n");
}
gpio_direction_input(test6_gpio);
gpio124_di1_irq = gpio_to_irq(test6_gpio);
request_irq(gpio124_di1_irq, di1_interrput_handler,
IRQ_TYPE_EDGE_FALLING|IRQ_TYPE_EDGE_RISING,
"gpio124_di1_irq", NULL);
enable_irq_wake(gpio124_di1_irq);
}
inputdev = input_allocate_device();
inputdev->name = "input_device_bem";
__set_bit(EV_KEY, inputdev->evbit);
__set_bit(EV_SYN, inputdev->evbit);
__set_bit(EV_REP, inputdev->evbit);
__set_bit(KEY1, inputdev->keybit);
__set_bit(KEY2, inputdev->keybit);
__set_bit(KEY3, inputdev->keybit);
__set_bit(KEY4, inputdev->keybit);
ret = input_register_device(inputdev);
if (ret) {
printk("debug : register input device failed!\r\n");
return ret;
}
device_create_file(&pdev->dev, &dev_attr_gpio_demo);
pr_err("[]gpio_demo_probe end...\n");
return 0;
}
4、中断处理函数配置
static irqreturn_t di0_interrput_handler(int irq, void *dev_id)
{
static int KEY1_state = 0;
//int i;
// for(i=0; i<10; i++){ //debouncing 10us
// KEY1_state = gpio_get_value(test5_gpio);
// }
printk(" >>>>>>>>>>>>>> KEY1_state =%d,di0_interrput_handler interrput set gpio 123 \n",KEY1_state);
// if(KEY1_state){
// input_report_key(inputdev,KEY1,0);
// input_sync(inputdev);
// }
// else{
// input_report_key(inputdev,KEY1,1);
// input_sync(inputdev);
// }
return IRQ_HANDLED;
}
5、ioctl的函数配置
struct file_operations gpio_demo_ops={
.owner = THIS_MODULE,
.unlocked_ioctl = gpio_demo_ioctl,
};
三、ioctl操作io
四、input输入事件
1、dts配置
2、read配置的input io事件
3、输出input事件和类型
5、整体代码
1、input_event.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <linux/input.h>
#define INPUT_NAME "gpio-keys"
static struct input_event inputevent;
static int find_key_devpath(char *dev_path, int len)
{
int ret = -1;
int id = 0, event_name_fd;
char event_name_path[40];
char event_name[40];
if((NULL == dev_path) || (len < 32)){
printf("para error dev_path:%d len:%d\n", (int)dev_path, len);
return -1;
}
for(id = 0; id < 16; ++id) {
memset(event_name_path, 0, sizeof(event_name_path));
memset(event_name, 0, sizeof(event_name_path));
sprintf(event_name_path, "/sys/class/input/event%d/device/name", id);
event_name_fd = open(event_name_path, O_RDONLY);
if(event_name_fd < 0){
printf("can not open dev_path:%s ret = %d\n", dev_path, event_name_fd);
continue;
}
if(read(event_name_fd, &event_name, sizeof(event_name)) != -1 && (strstr(event_name, INPUT_NAME))) {
memset(dev_path, 0, len);
sprintf(dev_path, "/dev/input/event%d", id);
close(event_name_fd);
ret = 0;
break;
}
close(event_name_fd);
}
printf("find_input_devpath dev_path:%s \n", dev_path);
return ret;
}
/*
* @description : main主程序
* @param - argc : argv数组元素个数
* @param - argv : 具体参数
* @return : 0 成功;其他 失败
*/
//int main(int argc, char *argv[])
int main()
{
int fd;
int err = 0;
char filename[32];
if(find_key_devpath(filename, sizeof(filename))){
printf("can't find_input dev\r");
return 0;
}
printf("use input(%s)\r\n", filename);
fd = open(filename, O_RDWR);
if (fd < 0)
{
printf("Can't open file %s\r\n", filename);
return -1;
}
while (1)
{
err = read(fd, &inputevent, sizeof(inputevent));
if (err > 0)
{ /* 读取数据成功 */
switch (inputevent.type)
{
case EV_KEY:
printf("EV_KEY:code(%d) value:(%d) \r\n", inputevent.code, inputevent.value);
break;
case EV_REL:
break;
case EV_ABS:
break;
case EV_MSC:
break;
case EV_SW:
break;
default:
//printf("inputevent(%d):code(%d) value:(%d) \r\n", inputevent.type, inputevent.code, inputevent.value);
break;
}
}
else
{
printf("failed to read inputevent data.\r\n");
}
}
return 0;
}
2、gpio_ioctl.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define GPIO57_HIGH _IO('L', 0)
#define GPIO57_LOW _IO('L', 1)
#define GPIO58_HIGH _IO('L', 2)
#define GPIO58_LOW _IO('L', 3)
int main()
{
int fd,ch;
//char buff[64] = {0};
fd = open("/dev/gpio_device", O_RDWR);
if(fd < 0){
perror("open error\n");
return fd;
}
while(1)
{
printf("(0:GPIO57_HIGH; 1:GPIO57_LOW; \n");
printf("(2:GPIO58_HIGH; 3:GPIO58_LOW; \n");
scanf("%d",&ch);
while((getchar())!='\n');
switch (ch)
{
case 0:
ioctl(fd, GPIO57_HIGH);
break;
case 1:
ioctl(fd, GPIO57_LOW);
break;
case 2:
ioctl(fd, GPIO58_HIGH);
break;
case 3:
ioctl(fd, GPIO58_LOW);
break;
default:
printf("Not ctl any gpio\n");
break;
}
}
return 0;
}
3、gpio_demo.c
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/wait.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/miscdevice.h>
#include <linux/irq.h>
#include <linux/of_irq.h>
#include <linux/kernel.h>
#include <linux/dmi.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/of.h>
#include <asm/unaligned.h>
#define GPIO57_HIGH _IO('L', 0)
#define GPIO57_LOW _IO('L', 1)
#define GPIO58_HIGH _IO('L', 2)
#define GPIO58_LOW _IO('L', 3)
#define GPIO130_HIGH _IO('L', 4)
#define GPIO130_LOW _IO('L', 5)
#define GPIO132_HIGH _IO('L', 6)
#define GPIO132_LOW _IO('L', 7)
#define GPIO123_HIGH _IO('L', 8)
#define GPIO123_LOW _IO('L', 9)
#define GPIO124_HIGH _IO('L', 10)
#define GPIO124_LOW _IO('L', 11)
static int major;
static struct class *cls;
struct input_dev *inputdev;
int test1_gpio;
int test2_gpio;
int test3_gpio;
int test4_gpio;
int test5_gpio;
int test6_gpio;
static int show_gpio;
#define KEY1 '0'
#define KEY2 '1'
#define KEY3 '2'
#define KEY4 '3'
static ssize_t gpio_value_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", gpio_get_value(show_gpio));
}
static ssize_t gpio_value_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)
{
if ('0' == buf[0]) {
show_gpio = test1_gpio;
gpio_direction_output(test1_gpio, 0);
printk("echo gpio57 = 0 \n");
} else if ('1' == buf[0]) {
show_gpio = test1_gpio;
gpio_direction_output(test1_gpio, 1);
printk("echo gpio57 = 1 \n");
} else if ('0' == buf[0]) {
show_gpio = test2_gpio;
gpio_direction_output(test2_gpio, 0);
printk("echo gpio58 = 0 \n");
} else if ('1' == buf[0]) {
show_gpio = test2_gpio;
gpio_direction_output(test2_gpio, 1);
printk("echo gpio58 = 1 \n");
} else if ('0' == buf[0]) {
show_gpio = test3_gpio;
gpio_direction_output(test3_gpio, 0);
printk("echo gpio130 = 0 \n");
} else if ('1' == buf[0]) {
show_gpio = test3_gpio;
gpio_direction_output(test3_gpio, 1);
printk("echo gpio130 = 1 \n");
} else if ('0' == buf[0]) {
show_gpio = test4_gpio;
gpio_direction_output(test4_gpio, 0);
printk("echo gpio132 = 0 \n");
} else if ('1' == buf[0]) {
show_gpio = test4_gpio;
gpio_direction_output(test4_gpio, 1);
printk("echo gpio132 = 1 \n");
}else if ('0' == buf[0]) {
show_gpio = test5_gpio;
gpio_direction_output(test5_gpio, 0);
printk("echo gpio123 = 0 \n");
} else if ('1' == buf[0]) {
show_gpio = test5_gpio;
gpio_direction_output(test5_gpio, 1);
printk("echo gpio123 = 1 \n");
} else if ('0' == buf[0]) {
show_gpio = test6_gpio;
gpio_direction_output(test6_gpio, 0);
printk("echo gpio124 = 0 \n");
} else if ('1' == buf[0]) {
show_gpio = test6_gpio;
gpio_direction_output(test6_gpio, 1);
printk("echo gpio124 = 1 \n");
} else
pr_err("I only support 0 or 1 to ctrl gpio on or off\n");
return len;
}
static DEVICE_ATTR(gpio_demo, 0664, gpio_value_show, gpio_value_store);
long gpio_demo_ioctl( struct file *file, unsigned int cmd, unsigned long arg )
{
switch( cmd )
{
case GPIO57_HIGH:
gpio_direction_output(test1_gpio, 1);
printk("set gpio57 to 1 \n");
break;
case GPIO57_LOW:
gpio_direction_output(test1_gpio, 0);
printk("set gpio57 to 0 \n");
break;
case GPIO58_HIGH:
gpio_direction_output(test2_gpio, 1);
printk("set gpio58 to 1 \n");
break;
case GPIO58_LOW:
gpio_direction_output(test2_gpio, 0);
printk("set gpio58 to 0 \n");
break;
// case GPIO130_HIGH:
// gpio_direction_output(test3_gpio, 1);
// printk("set gpio130 to 1 \n");
// break;
// case GPIO130_LOW:
// gpio_direction_output(test3_gpio, 0);
// printk("set gpio130 to 0 \n");
// break;
// case GPIO132_HIGH:
// gpio_direction_output(test4_gpio, 1);
// printk("set gpio132 to 1 \n");
// break;
// case GPIO132_LOW:
// gpio_direction_output(test4_gpio, 0);
// printk("set gpio132 to 0 \n");
// break;
// case GPIO123_HIGH:
// gpio_direction_output(test5_gpio, 1);
// printk("set GPIO123 to 1 \n");
// break;
// case GPIO123_LOW:
// gpio_direction_output(test5_gpio, 0);
// printk("set GPIO123 to 0 \n");
// break;
// case GPIO124_HIGH:
// gpio_direction_output(test6_gpio, 1);
// printk("set GPIO124 to 1 \n");
// break;
// case GPIO124_LOW:
// gpio_direction_output(test6_gpio, 0);
// printk("set GPIO124 to 0 \n");
// break;
default:
return -EINVAL;
break;
}
return 0;
}
struct file_operations gpio_demo_ops={
.owner = THIS_MODULE,
.unlocked_ioctl = gpio_demo_ioctl,
};
static irqreturn_t di0_interrput_handler(int irq, void *dev_id)
{
static int KEY1_state = 0;
//int i;
// for(i=0; i<10; i++){ //debouncing 10us
// KEY1_state = gpio_get_value(test5_gpio);
// }
printk(" >>>>>>>>>>>>>> KEY1_state =%d,di0_interrput_handler interrput set gpio 123 \n",KEY1_state);
// if(KEY1_state){
// input_report_key(inputdev,KEY1,0);
// input_sync(inputdev);
// }
// else{
// input_report_key(inputdev,KEY1,1);
// input_sync(inputdev);
// }
return IRQ_HANDLED;
}
static irqreturn_t di1_interrput_handler(int irq, void *dev_id)
{
static int KEY2_state = 0;
//int i;
// for(i=0; i<10; i++){ //debouncing 10us
// KEY2_state = gpio_get_value(test5_gpio);
// }
printk(">>>>>>>>>>>>>> KEY2_state =%d,di1_interrput_handler interrput set gpio 124 \n",KEY2_state);
// if(KEY2_state){
// input_report_key(inputdev,KEY2,0);
// input_sync(inputdev);
// }
// else{
// input_report_key(inputdev,KEY2,1);
// input_sync(inputdev);
// }
return IRQ_HANDLED;
}
static irqreturn_t di2_interrput_handler(int irq, void *dev_id)
{
static int KEY3_state = 0;
//int i;
// for(i=0; i<10; i++){ //debouncing 10us
// KEY3_state = gpio_get_value(test5_gpio);
// }
printk(" >>>>>>>>>>>>>> KEY3_state =%d,di2_interrput_handler interrput set gpio 130 \n",KEY3_state);
// if(KEY3_state){
// input_report_key(inputdev,KEY3,0);
// input_sync(inputdev);
// }
// else{
// input_report_key(inputdev,KEY3,1);
// input_sync(inputdev);
// }
return IRQ_HANDLED;
}
static irqreturn_t di3_interrput_handler(int irq, void *dev_id)
{
static int KEY4_state = 0;
//int i;
// for(i=0; i<10; i++){ //debouncing 10us
// KEY4_state = gpio_get_value(test5_gpio);
// }
printk(">>>>>>>>>>>>>> KEY4_state =%d,di3_interrput_handler interrput set gpio 132\n",KEY4_state);
// if(KEY4_state){
// input_report_key(inputdev,KEY4,0);
// input_sync(inputdev);
// }
// else{
// input_report_key(inputdev,KEY4,1);
// input_sync(inputdev);
// }
return IRQ_HANDLED;
}
static int gpio_demo_probe(struct platform_device *pdev)
{
int err,ret;
struct device *dev = &pdev->dev;
int gpio123_di0_irq,gpio124_di1_irq,gpio130_di2_irq,gpio132_di3_irq;
//申请gpio并上拉
test1_gpio = of_get_named_gpio(dev->of_node, "sylon,test1-gpio", 0);
if (gpio_is_valid(test1_gpio)) {
err = gpio_request(test1_gpio, "test1");
if (err<0) {
pr_err("test1 gpio request failed\n");
}
gpio_direction_output(test1_gpio, 0);
gpio_set_value(test1_gpio, 1);
}
test2_gpio = of_get_named_gpio(dev->of_node, "sylon,test2-gpio", 0);
if (gpio_is_valid(test2_gpio)) {
err = gpio_request(test2_gpio, "test2");
if (err<0) {
pr_err("test2 gpio request failed\n");
}
gpio_direction_output(test2_gpio, 0);
gpio_set_value(test2_gpio, 1);
}
test3_gpio = of_get_named_gpio(dev->of_node, "sylon,test3-gpio", 0);
if (gpio_is_valid(test3_gpio)) {
err = gpio_request(test3_gpio, "gpio130_in");
if (err<0) {
pr_err("test3 gpio request failed\n");
}
gpio_direction_input(test3_gpio);
gpio130_di2_irq = gpio_to_irq(test3_gpio);
request_irq(gpio130_di2_irq, di2_interrput_handler,
IRQ_TYPE_EDGE_FALLING|IRQ_TYPE_EDGE_RISING,
"gpio130_di2_irq", NULL);
enable_irq_wake(gpio130_di2_irq);
}
test4_gpio = of_get_named_gpio(dev->of_node, "sylon,test4-gpio", 0);
if (gpio_is_valid(test4_gpio)) {
err = gpio_request(test4_gpio, "gpio132_in");
if (err<0) {
pr_err("test4 gpio request failed\n");
}
gpio_direction_input(test4_gpio);
gpio132_di3_irq = gpio_to_irq(test4_gpio);
request_irq(gpio132_di3_irq, di3_interrput_handler,
IRQ_TYPE_EDGE_FALLING|IRQ_TYPE_EDGE_RISING,
"gpio132_di3_irq", NULL);
enable_irq_wake(gpio132_di3_irq);
}
test5_gpio = of_get_named_gpio(dev->of_node, "sylon,test5-gpio", 0);
if (gpio_is_valid(test5_gpio)) {
err = gpio_request(test5_gpio, "gpio123_in");
if (err<0) {
pr_err("test5 gpio request failed\n");
}
gpio_direction_input(test5_gpio);
gpio123_di0_irq = gpio_to_irq(test5_gpio);
request_irq(gpio123_di0_irq, di0_interrput_handler,
IRQ_TYPE_EDGE_FALLING|IRQ_TYPE_EDGE_RISING,
"gpio123_di0_irq", NULL);
enable_irq_wake(gpio123_di0_irq);
}
test6_gpio = of_get_named_gpio(dev->of_node, "sylon,test6-gpio", 0);
if (gpio_is_valid(test6_gpio)) {
err = gpio_request(test6_gpio, "gpio124_in");
if (err<0) {
pr_err("test6 gpio request failed\n");
}
gpio_direction_input(test6_gpio);
gpio124_di1_irq = gpio_to_irq(test6_gpio);
request_irq(gpio124_di1_irq, di1_interrput_handler,
IRQ_TYPE_EDGE_FALLING|IRQ_TYPE_EDGE_RISING,
"gpio124_di1_irq", NULL);
enable_irq_wake(gpio124_di1_irq);
}
inputdev = input_allocate_device();
inputdev->name = "input_device_bem";
__set_bit(EV_KEY, inputdev->evbit);
__set_bit(EV_SYN, inputdev->evbit);
__set_bit(EV_REP, inputdev->evbit);
__set_bit(KEY1, inputdev->keybit);
__set_bit(KEY2, inputdev->keybit);
__set_bit(KEY3, inputdev->keybit);
__set_bit(KEY4, inputdev->keybit);
ret = input_register_device(inputdev);
if (ret) {
printk("debug : register input device failed!\r\n");
return ret;
}
device_create_file(&pdev->dev, &dev_attr_gpio_demo);
pr_err("[]gpio_demo_probe end...\n");
return 0;
}
static struct of_device_id gpio_demo_match_table[] = {
{ .compatible = "sylon,gpio-demo"},
{ }
};
static int gpio_demo_remove(struct platform_device *pdev)
{
pr_err("[]gpio_demo_remove...\n");
return 0;
}
static struct platform_driver gpio_demo_driver = {
.driver = {
.name = "gpio_demo",
.owner = THIS_MODULE,
.of_match_table = gpio_demo_match_table,
},
.probe = gpio_demo_probe,
.remove = gpio_demo_remove,
};
static int gpio_demo_init(void)
{
struct device *mydev;
pr_err("[]gpio_demo_init start...\n");
platform_driver_register(&gpio_demo_driver);
major=register_chrdev(0,"gpiotest", &gpio_demo_ops);
cls=class_create(THIS_MODULE, "gpio_demo_class");
mydev = device_create(cls, 0, MKDEV(major,0),NULL,"gpio_device");
if(sysfs_create_file(&(mydev->kobj), &dev_attr_gpio_demo.attr)){
return -1;
}
return 0;
}
static void gpio_demo_exit(void)
{
pr_err("[]gpio_demo_exit...\n");
platform_driver_unregister(&gpio_demo_driver);
device_destroy(cls, MKDEV(major,0));
class_destroy(cls);
unregister_chrdev(major, "gpiotest");
}
module_init(gpio_demo_init);
module_exit(gpio_demo_exit);
MODULE_AUTHOR("123");
MODULE_DESCRIPTION("Device_create Driver");
MODULE_LICENSE("GPL");