介绍三种linux驱动生成文件节点的方法

linux用户空间和kernel空间是分开,所以上层需要和某个模块驱动交流的时候,就需要驱动来创建一个文件节点,当然input设备除外,已有非常成熟的上报流程。现在介绍3种驱动生成文件节点的方法:

1、在/dev下面创建节点

介绍三种linux驱动生成文件节点的方法_第1张图片

2、在/proc下面创建节点

介绍三种linux驱动生成文件节点的方法_第2张图片


介绍三种linux驱动生成文件节点的方法_第3张图片

上图中建的节点是/proc/onekey_recovery/last_pressed,如果不用proc_mkdir而只用proc_create的话,则生成的节点是/proc/last_pressed

3、在/sys下面创建节点

重点参考md_gpiox_write,md_gpiox_read,DEVICE_ATTR,device_create_file,这里生成的节点在/sys/devices/...

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#ifdef CONFIG_OF
#include 
#include 
#endif
#include 
//#include 
//#include 

#define USE_INTERRUPT 1

#define D1_RST_PIN 84
struct md_gpio_eint_data {
	struct switch_dev sdev84;
	unsigned gpio84; //alarm输入
	const char *state_on;
	const char *state_off;
	int irq84;
	struct work_struct work84;
#ifdef CONFIG_OF
	struct device_node *irq_node84;
#endif
};
static char last_pressed =0;

#ifdef USE_INTERRUPT
static void md_gpio_eint_work84(struct work_struct *work)
{
	int state;
	struct md_gpio_eint_data	*data =
		container_of(work, struct md_gpio_eint_data, work84);

	msleep(3000);	//3s

	state = gpio_get_value(data->gpio84);
	pr_err("%s: state=%d\n", __FUNCTION__, state);
	switch_set_state(&data->sdev84, state);

	/*
	if(state)
		irq_set_irq_type(data->irq84, IRQF_TRIGGER_LOW);
	else
		irq_set_irq_type(data->irq84, IRQF_TRIGGER_HIGH);
	 */

	enable_irq(data->irq84);
}

static irqreturn_t gpio_irq_handler84(int irq, void *dev_id)
{
	struct md_gpio_eint_data *switch_data =
	    (struct md_gpio_eint_data *)dev_id;
	
	disable_irq_nosync(switch_data->irq84);
	printk(KERN_ERR "vision_d:RST-KEY work84 irq handler \n");
	last_pressed =1;
	schedule_work(&switch_data->work84);
	return IRQ_HANDLED;
}

#endif
/*
static int d1_reset_thread(void *x)
{
	int gpio84;
	msleep(2000);		//2s

	do{
		//printk("vision_d:%s \n",__func__);
		gpio84 = gpio_get_value(D1_RST_PIN);
		if(gpio84 ==0){
			msleep(2000);	//2s
			gpio84 = gpio_get_value(D1_RST_PIN);
			if(gpio84 ==0)
				kernel_restart(NULL);
		}else
			msleep(100);	//100ms
	}while (!kthread_should_stop());
	
	return 0;
}
*/
static int rgpio = -1;
static ssize_t md_gpiox_write(struct device *dev, struct device_attribute *attr, char *buffer, size_t count)
{
	int ret;
	int gpio_num = -1;
	int gpio_val = -1;
	int value;
	int n =0;
	
	ret = sscanf(buffer, "%d", &value);
	if(!ret) {
		pr_err("%s: intput error!\n", __FUNCTION__);
		return -1;
	}
	gpio_num = value;
	//printk(KERN_ERR "vision_d %s: gpio num %d\n", __FUNCTION__, gpio_num);
	while(value)
	{
		value = value / 10;
		n++;
	}
	buffer +=n;	
	if(*buffer ==32){
		ret = sscanf(buffer, "%d", &value);
		if(!ret) {
			pr_err("%s: intput error!\n", __FUNCTION__);
			return -1;
		}
		gpio_val = value;	
		//printk(KERN_ERR "vision_d %s: gpio set value %d\n", __FUNCTION__, gpio_val);
	}
	printk(KERN_ERR "vision_d %s:set gpio%d  %d\n", __FUNCTION__, gpio_num,gpio_val);
	
	if(gpio_val ==0)
		gpio_set_value(gpio_num, 0);
	else if(gpio_val ==1)
		gpio_set_value(gpio_num, 1);
	else
		rgpio = gpio_num;
	
	//gpio_free(gpio);
		
	return count;

}

static ssize_t md_gpiox_read(struct device *dev, struct device_attribute *attr, char *buffer)
{
	if(rgpio > 0)
		return snprintf(buffer,PAGE_SIZE,"gpio%d=%d\n",rgpio,gpio_get_value(rgpio));
	else
		return -1;
}
static DEVICE_ATTR(pinctl, S_IWUSR | S_IRUGO, md_gpiox_read, md_gpiox_write);

static ssize_t rst_key_status_r(struct device *dev, struct device_attribute *attr, char *buff)
{
	return snprintf(buff,PAGE_SIZE,"%d\n",last_pressed);
}
static ssize_t rst_key_status_w(struct device *dev, struct device_attribute *attr, char *buf, size_t count)
{
	last_pressed =0;
	return count;
}

static DEVICE_ATTR(RstKeyStatus, S_IWUSR | S_IRUGO, rst_key_status_r, rst_key_status_w);

static int md_gpio_eint_probe(struct platform_device *pdev)
{
	struct md_gpio_eint_data *switch_data;
	int ret = 0;
#if defined(CONFIG_OF)
	u32 ints[2] = { 0, 0 };
#endif

	ret = device_create_file(&pdev->dev,&dev_attr_RstKeyStatus);
	if(ret)
		printk(KERN_ERR "vision_d:create attr failed \n");
	ret = device_create_file(&pdev->dev,&dev_attr_pinctl);
	if(ret)
		printk(KERN_ERR "vision_d:create attr failed \n");
	
	pr_err("%s: start!\n", __FUNCTION__);
	switch_data = kzalloc(sizeof(struct md_gpio_eint_data), GFP_KERNEL);
	if (!switch_data) {
		pr_err("%s: kzalloc error!\n", __FUNCTION__);
		return -ENOMEM;
	}
	
	platform_set_drvdata(pdev, switch_data);

	switch_data->sdev84.name = "onekey_recovery"; //gpio84
	
	switch_data->sdev84.index = 0;
	switch_data->sdev84.state = 0;
	
	switch_data->gpio84 = D1_RST_PIN; 
	switch_data->state_on = "on";
	switch_data->state_off = "off";

	ret = switch_dev_register(&switch_data->sdev84);
	if (ret < 0) {
		pr_err("%s: fail to register sdev84!\n", __FUNCTION__);
		goto err_switch_dev_register;
	}
	
	ret = gpio_request(switch_data->gpio84, "gpio84");
	if (ret < 0) {
		pr_err("%s: fail gpio_request 84!\n", __FUNCTION__);
		goto err_request_gpio;
	}

/*	ret = gpio_request(D1_RST_PIN, "gpio84");
	if (ret < 0) {
		pr_err("%s: fail gpio_request 84!\n", __FUNCTION__);
		goto err_request_gpio;
	}
*/
	ret = gpio_direction_input(switch_data->gpio84);
	if (ret < 0) {
		pr_err("%s: fail gpio_direction_input 84!\n", __FUNCTION__);
		goto err_set_gpio_input;
	}
	gpio_set_debounce(switch_data->gpio84, 100);
/*	
	ret = gpio_direction_input(D1_RST_PIN);
	if (ret < 0) {
		pr_err("%s: fail gpio_direction_input 84!\n", __FUNCTION__);
		goto err_set_gpio_input;
	}
	gpio_set_debounce(D1_RST_PIN, 100);
*/
#ifdef USE_INTERRUPT
	INIT_WORK(&switch_data->work84, md_gpio_eint_work84);
#ifdef CONFIG_OF
	printk(KERN_ERR "vision_d:md_gpio_eint find node from dts \n");
	switch_data->irq_node84 = of_find_compatible_node(NULL, NULL, "mediatek, gpio84-eint");
	if(switch_data->irq_node84)
		switch_data->irq84 = irq_of_parse_and_map(switch_data->irq_node84, 0);
#else
	switch_data->irq84 = gpio_to_irq(switch_data->gpio84);
	if (switch_data->irq84 < 0) {
		pr_err("%s: fail gpio_to_irq 84!\n", __FUNCTION__);
		ret = switch_data->irq84;
		goto err_detect_irq_num_failed;
	}
	
#endif
	ret = request_irq(switch_data->irq84, gpio_irq_handler84,
			  IRQF_TRIGGER_LOW |IRQF_ONESHOT, "gpio84_eint", switch_data);
	if (ret < 0) {
		pr_err("%s: fail request_irq 84!\n", __FUNCTION__);
		goto err_request_irq;
	}
	//irq_set_irq_type(switch_data->irq84, IRQF_TRIGGER_LOW |IRQF_ONESHOT);
	
#endif
//#ifndef USE_INTERRUPT
//	kthread_run(d1_reset_thread, NULL, "d1_reset_thread");
//#endif
	switch_set_state(&switch_data->sdev84, 1);	//init state status
	pr_err("%s: ok\n", __FUNCTION__);
	return 0;

err_request_irq:
err_detect_irq_num_failed:
err_set_gpio_input:
	gpio_free(switch_data->gpio84);
	//gpio_free(D1_RST_PIN);
err_request_gpio:
	switch_dev_unregister(&switch_data->sdev84);
err_switch_dev_register:
	kfree(switch_data);
	
	pr_err("%s: fail, ret=%d\n", __FUNCTION__, ret);
	return ret;
}

static int md_gpio_eint_remove(struct platform_device *pdev)
{
	struct md_gpio_eint_data *switch_data = platform_get_drvdata(pdev);

	//cancel_work_sync(&switch_data->work84);
	gpio_free(switch_data->gpio84);
	switch_dev_unregister(&switch_data->sdev84);
	
	kfree(switch_data);

	return 0;
}


static const struct of_device_id md_gpio_eint_ids[] = {
	{.compatible = "mediatek,md_gpio_eint",},
	{},
};
static struct platform_driver md_gpio_eint_driver = {
	.probe		= md_gpio_eint_probe,
	.remove		= md_gpio_eint_remove,
	.driver		= {
		.name	= "md-gpio-eint",
		.owner	= THIS_MODULE,
#ifdef CONFIG_OF
		.of_match_table = md_gpio_eint_ids,
#endif
	},
};

static int __init md_gpio_eint_init(void)
{
	pr_err("%s: start!\n", __FUNCTION__);
	return platform_driver_register(&md_gpio_eint_driver);
}

static void __exit md_gpio_eint_exit(void)
{
	platform_driver_unregister(&md_gpio_eint_driver);
}

module_init(md_gpio_eint_init);
module_exit(md_gpio_eint_exit);

MODULE_AUTHOR("deli.sun <[email protected]>");
MODULE_DESCRIPTION("md gpio eint driver");
MODULE_LICENSE("GPL");

上述三种方法,第一种和第二种方法使用时一般流程就是open、read/write、ioctl等,第三种方法则可以通过echo/cat命令来读写。另外以上方法具体实现时可以在kernel目录下grep相关关键字,看看手中原代码是如何实现的,必须能搜到大量的使用例程的。

你可能感兴趣的:(linux,android)