linux用户空间和kernel空间是分开,所以上层需要和某个模块驱动交流的时候,就需要驱动来创建一个文件节点,当然input设备除外,已有非常成熟的上报流程。现在介绍3种驱动生成文件节点的方法:
1、在/dev下面创建节点
2、在/proc下面创建节点
上图中建的节点是/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相关关键字,看看手中原代码是如何实现的,必须能搜到大量的使用例程的。