基于input子系统的sensor驱动调试(二)
继上一篇:http://www.cnblogs.com/linhaostudy/p/8303628.html#_label1_1
一、驱动流程解析:
1、模块加载:
static struct of_device_id stk_match_table[] = {
{ .compatible = "stk,stk3x1x", },
{ },
};
static struct i2c_driver stk_ps_driver =
{
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
.of_match_table = stk_match_table,
},
.probe = stk3x1x_probe,
.remove = stk3x1x_remove,
.id_table = stk_ps_id,
};
static int __init stk3x1x_init(void)
{
int ret;
ret = i2c_add_driver(&stk_ps_driver);
if (ret)
return ret;
return ;
}
static void __exit stk3x1x_exit(void)
{
i2c_del_driver(&stk_ps_driver);
}
of_device_id与DTS中的匹配,这与内核2.6以前的i2c_board_info不一样;
内核加载驱动模块的时候将调用到stk3x1x_init()方法:
初始化了i2c_driver结构体给stk_ps_driver变量,将用于将设备注册到IIC。关键在于结构体中的probe()方法,注册完成的时候将调用;
2、stk3x1x驱动初始化-probe函数:
static int stk3x1x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err = -ENODEV;
struct stk3x1x_data *ps_data;
struct stk3x1x_platform_data *plat_data;
printk(KERN_INFO "%s: driver version = %s\n", __func__, DRIVER_VERSION); if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
{
printk(KERN_ERR "%s: No Support for I2C_FUNC_SMBUS_BYTE_DATA\n", __func__);
return -ENODEV;
}
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
{
printk(KERN_ERR "%s: No Support for I2C_FUNC_SMBUS_WORD_DATA\n", __func__);
return -ENODEV;
} ps_data = kzalloc(sizeof(struct stk3x1x_data),GFP_KERNEL);
if(!ps_data)
{
printk(KERN_ERR "%s: failed to allocate stk3x1x_data\n", __func__);
return -ENOMEM;
}
ps_data->client = client;
i2c_set_clientdata(client,ps_data);
mutex_init(&ps_data->io_lock);
wake_lock_init(&ps_data->ps_wakelock,WAKE_LOCK_SUSPEND, "stk_input_wakelock"); #ifdef STK_POLL_PS
wake_lock_init(&ps_data->ps_nosuspend_wl,WAKE_LOCK_SUSPEND, "stk_nosuspend_wakelock");
#endif
if (client->dev.of_node) {
plat_data = devm_kzalloc(&client->dev,
sizeof(struct stk3x1x_platform_data), GFP_KERNEL);
if (!plat_data) {
dev_err(&client->dev, "Failed to allocate memory\n");
return -ENOMEM;
} err = stk3x1x_parse_dt(&client->dev, plat_data);
dev_err(&client->dev,
"%s: stk3x1x_parse_dt ret=%d\n", __func__, err);
if (err)
return err;
} else
plat_data = client->dev.platform_data; if (!plat_data) {
dev_err(&client->dev,
"%s: no stk3x1x platform data!\n", __func__);
goto err_als_input_allocate;
}
ps_data->als_transmittance = plat_data->transmittance;
ps_data->int_pin = plat_data->int_pin;
ps_data->use_fir = plat_data->use_fir;
ps_data->pdata = plat_data; if (ps_data->als_transmittance == ) {
dev_err(&client->dev,
"%s: Please set als_transmittance\n", __func__);
goto err_als_input_allocate;
} ps_data->als_input_dev = devm_input_allocate_device(&client->dev);
if (ps_data->als_input_dev==NULL)
{
printk(KERN_ERR "%s: could not allocate als device\n", __func__);
err = -ENOMEM;
goto err_als_input_allocate;
}
ps_data->ps_input_dev = devm_input_allocate_device(&client->dev);
if (ps_data->ps_input_dev==NULL)
{
printk(KERN_ERR "%s: could not allocate ps device\n", __func__);
err = -ENOMEM;
goto err_als_input_allocate;
}
ps_data->als_input_dev->name = ALS_NAME;
ps_data->ps_input_dev->name = PS_NAME;
set_bit(EV_ABS, ps_data->als_input_dev->evbit);
set_bit(EV_ABS, ps_data->ps_input_dev->evbit);
input_set_abs_params(ps_data->als_input_dev, ABS_MISC, , stk_alscode2lux(ps_data, (<<)-), , );
input_set_abs_params(ps_data->ps_input_dev, ABS_DISTANCE, ,, , );
err = input_register_device(ps_data->als_input_dev);
if (err<)
{
printk(KERN_ERR "%s: can not register als input device\n", __func__);
goto err_als_input_allocate;
}
err = input_register_device(ps_data->ps_input_dev);
if (err<)
{
printk(KERN_ERR "%s: can not register ps input device\n", __func__);
goto err_als_input_allocate;
} err = sysfs_create_group(&ps_data->als_input_dev->dev.kobj, &stk_als_attribute_group);
if (err < )
{
printk(KERN_ERR "%s:could not create sysfs group for als\n", __func__);
goto err_als_input_allocate;
}
err = sysfs_create_group(&ps_data->ps_input_dev->dev.kobj, &stk_ps_attribute_group);
if (err < )
{
printk(KERN_ERR "%s:could not create sysfs group for ps\n", __func__);
goto err_ps_sysfs_create_group;
}
input_set_drvdata(ps_data->als_input_dev, ps_data);
input_set_drvdata(ps_data->ps_input_dev, ps_data); #ifdef STK_POLL_ALS
ps_data->stk_als_wq = create_singlethread_workqueue("stk_als_wq");
INIT_WORK(&ps_data->stk_als_work, stk_als_work_func);
hrtimer_init(&ps_data->als_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ps_data->als_poll_delay = ns_to_ktime( * NSEC_PER_MSEC);
ps_data->als_timer.function = stk_als_timer_func;
#endif ps_data->stk_ps_wq = create_singlethread_workqueue("stk_ps_wq");
INIT_WORK(&ps_data->stk_ps_work, stk_ps_work_func);
hrtimer_init(&ps_data->ps_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ps_data->ps_poll_delay = ns_to_ktime( * NSEC_PER_MSEC);
ps_data->ps_timer.function = stk_ps_timer_func;
#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS))
ps_data->stk_wq = create_singlethread_workqueue("stk_wq");
INIT_WORK(&ps_data->stk_work, stk_work_func);
err = stk3x1x_setup_irq(client);
if(err < )
goto err_stk3x1x_setup_irq;
#endif err = stk3x1x_power_init(ps_data, true);
if (err)
goto err_power_init; err = stk3x1x_power_ctl(ps_data, true);
if (err)
goto err_power_on; ps_data->als_enabled = false;
ps_data->ps_enabled = false;
#ifdef CONFIG_HAS_EARLYSUSPEND
ps_data->stk_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + ;
ps_data->stk_early_suspend.suspend = stk3x1x_early_suspend;
ps_data->stk_early_suspend.resume = stk3x1x_late_resume;
register_early_suspend(&ps_data->stk_early_suspend);
#endif
/* make sure everything is ok before registering the class device */
ps_data->als_cdev = sensors_light_cdev;
ps_data->als_cdev.sensors_enable = stk_als_enable_set;
ps_data->als_cdev.sensors_poll_delay = stk_als_poll_delay_set;
err = sensors_classdev_register(&client->dev, &ps_data->als_cdev);
if (err)
goto err_power_on; ps_data->ps_cdev = sensors_proximity_cdev;
ps_data->ps_cdev.sensors_enable = stk_ps_enable_set;
err = sensors_classdev_register(&client->dev, &ps_data->ps_cdev);
if (err)
goto err_class_sysfs; /* enable device power only when it is enabled */
err = stk3x1x_power_ctl(ps_data, false);
if (err)
goto err_init_all_setting; dev_dbg(&client->dev, "%s: probe successfully", __func__); return ; err_init_all_setting:
stk3x1x_power_ctl(ps_data, false);
sensors_classdev_unregister(&ps_data->ps_cdev);
err_class_sysfs:
sensors_classdev_unregister(&ps_data->als_cdev);
err_power_on:
stk3x1x_power_init(ps_data, false);
err_power_init:
#ifndef STK_POLL_PS
free_irq(ps_data->irq, ps_data);
gpio_free(plat_data->int_pin);
#endif
#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS))
err_stk3x1x_setup_irq:
#endif
#ifdef STK_POLL_ALS
hrtimer_try_to_cancel(&ps_data->als_timer);
destroy_workqueue(ps_data->stk_als_wq);
#endif
destroy_workqueue(ps_data->stk_ps_wq);
#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS))
destroy_workqueue(ps_data->stk_wq);
#endif
sysfs_remove_group(&ps_data->ps_input_dev->dev.kobj, &stk_ps_attribute_group);
err_ps_sysfs_create_group:
sysfs_remove_group(&ps_data->als_input_dev->dev.kobj, &stk_als_attribute_group);
err_als_input_allocate:
#ifdef STK_POLL_PS
wake_lock_destroy(&ps_data->ps_nosuspend_wl);
#endif
wake_lock_destroy(&ps_data->ps_wakelock);
mutex_destroy(&ps_data->io_lock);
kfree(ps_data);
return err;
}
在stk3x1x_probe函数中主要做了:
1、为驱动私有数据结构体stk3x1x_data分配内存空间;
2、 将设备驱动的私有数据(stk3x1x_data)连接到设备client(i2c_client)中;(bma255会增加一步:读取i2c的id);
3、将stk3x1x驱动注册到linux input子系统;
4、创建工作队列(主要是对sensor的数据采集);
5、创建sysfs接口;
2.1 创建input子系统:
http://blog.csdn.net/ielife/article/details/7798952
1、 在驱动加载模块中,设置你的input设备支持的事件类型;
2、 注册中断处理函数,例如键盘设备需要编写按键的抬起、放下,触摸屏设备需要编写按下、抬起、绝对移动,鼠标设备需要编写单击、抬起、相对移动,并且需要在必要的时候提交硬件数据(键值/坐标/状态等等);
3、将输入设备注册到输入子系统中;
ps_data->als_input_dev = devm_input_allocate_device(&client->dev); //分配内存空间
if (ps_data->als_input_dev==NULL)
{
printk(KERN_ERR "%s: could not allocate als device\n", __func__);
err = -ENOMEM;
goto err_als_input_allocate;
}
ps_data->ps_input_dev = devm_input_allocate_device(&client->dev);
if (ps_data->ps_input_dev==NULL)
{
printk(KERN_ERR "%s: could not allocate ps device\n", __func__);
err = -ENOMEM;
goto err_als_input_allocate;
}
ps_data->als_input_dev->name = ALS_NAME;
ps_data->ps_input_dev->name = PS_NAME;
set_bit(EV_ABS, ps_data->als_input_dev->evbit);
set_bit(EV_ABS, ps_data->ps_input_dev->evbit);
input_set_abs_params(ps_data->als_input_dev, ABS_MISC, , stk_alscode2lux(ps_data, (<<)-), , ); //设置input加载类型;
input_set_abs_params(ps_data->ps_input_dev, ABS_DISTANCE, ,, , );
err = input_register_device(ps_data->als_input_dev);
if (err<)
{
printk(KERN_ERR "%s: can not register als input device\n", __func__);
goto err_als_input_allocate;
}
err = input_register_device(ps_data->ps_input_dev);
if (err<)
{
printk(KERN_ERR "%s: can not register ps input device\n", __func__);
goto err_als_input_allocate;
}
err = stk3x1x_setup_irq(client); //设置驱动中断函数
if(err < )
goto err_stk3x1x_setup_irq;
2.2 创建工作队列:
先提一个问题,为什么要创建工作队列?在前面的介绍中我们知道,sensor传感器获取数据后,将数据传给controller的寄存器中,供主控去查询读取数据。所以这里创建的工作队列,就是在一个工作者线程,通过IIC不断的去查询读取controller上的数据。
工作队列的作用就是把工作推后,交由一个内核线程去执行,更直接的说就是如果写了一个函数,而现在不想马上执行它,想在将来某个时刻去执行它,那用工作队列准没错.大概会想到中断也是这样,提供一个中断服务函数,在发生中断的时候去执行,没错,和中断相比,工作队列最大的好处就是可以调度可以睡眠,灵活性更好。
上面代码中我们看到INIT_WORK(&ps_data->stk_ps_work, stk_ps_work_func);,其实是一个宏的定义,在include/linux/workqueue.h中。stk_ps_work_func()就是我们定义的功能函数,用于查询读取Sensor的距离传感器数据的,并上报Input子系统,代码如下:
static void stk_ps_work_func(struct work_struct *work)
{
struct stk3x1x_data *ps_data = container_of(work, struct stk3x1x_data, stk_ps_work);
uint32_t reading;
int32_t near_far_state;
uint8_t org_flag_reg;
int32_t ret;
uint8_t disable_flag = ;
mutex_lock(&ps_data->io_lock); org_flag_reg = stk3x1x_get_flag(ps_data);
if(org_flag_reg < )
{
printk(KERN_ERR "%s: get_status_reg fail, ret=%d", __func__, org_flag_reg);
goto err_i2c_rw;
}
near_far_state = (org_flag_reg & STK_FLG_NF_MASK)?:;
reading = stk3x1x_get_ps_reading(ps_data);
if(ps_data->ps_distance_last != near_far_state)
{
ps_data->ps_distance_last = near_far_state;
input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state); //input上报数据
input_sync(ps_data->ps_input_dev); //input_sync()在这里不起关键作用。但如果是一个触摸屏,即有x坐标和y坐标,则需要通过input_sync()函数把x和y坐标完整地传递给输入子系统。
wake_lock_timeout(&ps_data->ps_wakelock, *HZ);
#ifdef STK_DEBUG_PRINTF
printk(KERN_INFO "%s: ps input event %d cm, ps code = %d\n",__func__, near_far_state, reading);
#endif
}
ret = stk3x1x_set_flag(ps_data, org_flag_reg, disable_flag);
if(ret < )
{
printk(KERN_ERR "%s:stk3x1x_set_flag fail, ret=%d\n", __func__, ret);
goto err_i2c_rw;
} mutex_unlock(&ps_data->io_lock);
return; err_i2c_rw:
mutex_unlock(&ps_data->io_lock);
msleep();
return;
}
2.3 创建sysfs接口:
为什么要创建sysfs接口?在驱动层创建了sysfs接口,HAL层通过这些sysfs接口,对Sensor进行操作,如使能、设置delay等。
DEVICE_ATTR的使用:http://blog.csdn.net/njuitjf/article/details/16849333
函数宏DEVICE_ATTR内封装的是__ATTR(_name,_mode,_show,_stroe)方法:
_show:表示的是读方法,_stroe表示的是写方法。
1、 调用宏DEVICE_ATTR完成对功能函数的注册:
static struct device_attribute ps_enable_attribute = __ATTR(enable,,stk_ps_enable_show,stk_ps_enable_store);
static struct device_attribute ps_enable_aso_attribute = __ATTR(enableaso,,stk_ps_enable_aso_show,stk_ps_enable_aso_store);
static struct device_attribute ps_distance_attribute = __ATTR(distance,,stk_ps_distance_show, stk_ps_distance_store);
static struct device_attribute ps_offset_attribute = __ATTR(offset,,stk_ps_offset_show, stk_ps_offset_store);
static struct device_attribute ps_code_attribute = __ATTR(code, , stk_ps_code_show, NULL);
static struct device_attribute ps_code_thd_l_attribute = __ATTR(codethdl,,stk_ps_code_thd_l_show,stk_ps_code_thd_l_store);
static struct device_attribute ps_code_thd_h_attribute = __ATTR(codethdh,,stk_ps_code_thd_h_show,stk_ps_code_thd_h_store);
static struct device_attribute recv_attribute = __ATTR(recv,,stk_recv_show,stk_recv_store);
static struct device_attribute send_attribute = __ATTR(send,,stk_send_show, stk_send_store);
static struct device_attribute all_reg_attribute = __ATTR(allreg, , stk_all_reg_show, NULL); static struct attribute *stk_ps_attrs [] =
{
&ps_enable_attribute.attr,
&ps_enable_aso_attribute.attr,
&ps_distance_attribute.attr,
&ps_offset_attribute.attr,
&ps_code_attribute.attr,
&ps_code_thd_l_attribute.attr,
&ps_code_thd_h_attribute.attr,
&recv_attribute.attr,
&send_attribute.attr,
&all_reg_attribute.attr,
NULL
}; static struct attribute_group stk_ps_attribute_group = {
.attrs = stk_ps_attrs,
};
在probe函数中:
err = sysfs_create_group(&ps_data->als_input_dev->dev.kobj, &stk_als_attribute_group);
if (err < )
{
printk(KERN_ERR "%s:could not create sysfs group for als\n", __func__);
goto err_als_input_allocate;
}
err = sysfs_create_group(&ps_data->ps_input_dev->dev.kobj, &stk_ps_attribute_group);
if (err < )
{
printk(KERN_ERR "%s:could not create sysfs group for ps\n", __func__);
goto err_ps_sysfs_create_group;
}
到此,完成了sysfs接口的创建,我们可以在根文件系统中看到/sys/class/input/input1/目录,在该目录下我们可以看到多个节点,其中就包含了enable和delay。我们以enable为例子,可以有两种方法完成对Gsensor的使能工作:

3、读取上报数据:
在Android的HAL层,通过对/sys/class/input/input3/enable节点的写操作,使能sensor。调用到的方法是stk_ps_enable_store函数:
static struct device_attribute ps_enable_attribute = __ATTR(enable,,stk_ps_enable_show,stk_ps_enable_store);
static struct device_attribute ps_enable_aso_attribute = __ATTR(enableaso,,stk_ps_enable_aso_show,stk_ps_enable_aso_store);
static struct device_attribute ps_distance_attribute = __ATTR(distance,,stk_ps_distance_show, stk_ps_distance_store);
static struct device_attribute ps_offset_attribute = __ATTR(offset,,stk_ps_offset_show, stk_ps_offset_store);
static struct device_attribute ps_code_attribute = __ATTR(code, , stk_ps_code_show, NULL);
static struct device_attribute ps_code_thd_l_attribute = __ATTR(codethdl,,stk_ps_code_thd_l_show,stk_ps_code_thd_l_store);
static struct device_attribute ps_code_thd_h_attribute = __ATTR(codethdh,,stk_ps_code_thd_h_show,stk_ps_code_thd_h_store);
static struct device_attribute recv_attribute = __ATTR(recv,,stk_recv_show,stk_recv_store);
static struct device_attribute send_attribute = __ATTR(send,,stk_send_show, stk_send_store);
static struct device_attribute all_reg_attribute = __ATTR(allreg, , stk_all_reg_show, NULL);
里面的show和store函数;
static ssize_t stk_ps_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
uint8_t en;
if (sysfs_streq(buf, ""))
en = ;
else if (sysfs_streq(buf, ""))
en = ;
else
{
printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf);
return -EINVAL;
}
dev_dbg(dev, "%s: Enable PS : %d\n", __func__, en);
mutex_lock(&ps_data->io_lock);
stk3x1x_enable_ps(ps_data, en);
mutex_unlock(&ps_data->io_lock);
return size;
}
static int32_t stk3x1x_enable_ps(struct stk3x1x_data *ps_data, uint8_t enable)
{
int32_t ret;
uint8_t w_state_reg;
uint8_t curr_ps_enable;
curr_ps_enable = ps_data->ps_enabled?:;
if(curr_ps_enable == enable)
return ; if (enable) {
ret = stk3x1x_device_ctl(ps_data, enable);
if (ret)
return ret;
} ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
if (ret < )
{
printk(KERN_ERR "%s: write i2c error, ret=%d\n", __func__, ret);
return ret;
}
w_state_reg = ret;
w_state_reg &= ~(STK_STATE_EN_PS_MASK | STK_STATE_EN_WAIT_MASK | 0x60);
if(enable)
{
w_state_reg |= STK_STATE_EN_PS_MASK;
if(!(ps_data->als_enabled))
w_state_reg |= STK_STATE_EN_WAIT_MASK;
}
ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg);
if (ret < )
{
printk(KERN_ERR "%s: write i2c error, ret=%d\n", __func__, ret);
return ret;
} if(enable)
{
#ifdef STK_POLL_PS
hrtimer_start(&ps_data->ps_timer, ps_data->ps_poll_delay, HRTIMER_MODE_REL); //定时一段时间后,开始开启工作队列
ps_data->ps_distance_last = -;
#endif
ps_data->ps_enabled = true;
#ifndef STK_POLL_PS
#ifndef STK_POLL_ALS
if(!(ps_data->als_enabled))
#endif /* #ifndef STK_POLL_ALS */
enable_irq(ps_data->irq);
msleep();
ret = stk3x1x_get_flag(ps_data);
if (ret < )
{
printk(KERN_ERR "%s: read i2c error, ret=%d\n", __func__, ret);
return ret;
} near_far_state = ret & STK_FLG_NF_MASK;
ps_data->ps_distance_last = near_far_state;
input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state);
input_sync(ps_data->ps_input_dev);
wake_lock_timeout(&ps_data->ps_wakelock, *HZ);
reading = stk3x1x_get_ps_reading(ps_data);
dev_dbg(&ps_data->client->dev,
"%s: ps input event=%d, ps code = %d\n",
__func__, near_far_state, reading);
#endif /* #ifndef STK_POLL_PS */
}
else
{
#ifdef STK_POLL_PS
hrtimer_cancel(&ps_data->ps_timer);
#else
#ifndef STK_POLL_ALS
if(!(ps_data->als_enabled))
#endif
disable_irq(ps_data->irq);
#endif
ps_data->ps_enabled = false;
}
if (!enable) {
ret = stk3x1x_device_ctl(ps_data, enable);
if (ret)
return ret;
} return ret;
}
static enum hrtimer_restart stk_als_timer_func(struct hrtimer *timer)
{
struct stk3x1x_data *ps_data = container_of(timer, struct stk3x1x_data, als_timer);
queue_work(ps_data->stk_als_wq, &ps_data->stk_als_work); //开启工作队列
hrtimer_forward_now(&ps_data->als_timer, ps_data->als_poll_delay);
return HRTIMER_RESTART;
}
那么对于HAL层,将通过/dev/input/event1设备节点读取到sensor数据。到此,sensor驱动的工作流程完毕。应该很好理解吧!
基于input子系统的sensor驱动调试(二)的更多相关文章
- 基于input子系统的sensor驱动调试(一)
要想弄明白世界的本质,就要追根溯源:代码也是一样的道理: 最近调试几个sensor驱动,alps sensor驱动.compass sensor驱动.G-sensor驱动都是一样的架构: 一.基于in ...
- Linux驱动编程--基于I2C子系统的I2C驱动
代码中,我添加了很多注释,应该不难理解,有错误大家可以指出来,我再改正 #include <linux/kernel.h> #include <linux/module.h> ...
- ARM Linux 驱动Input子系统之按键驱动测试
上一篇已经谈过,在现内核的中引入设备树之后对于内核驱动的编写,主要集中在硬件接口的配置上了即xxxx.dts文件的编写. 在自己的开发板上移植按键驱动: 1.根据开发板的原理图 确定按键的硬件接口为: ...
- Linux驱动编程--基于I2C子系统的I2C驱动的Makefile
ifeq ($(KERNELRELEASE),) KERNELDIR ?= /lib/modules/$(shell uname -r)/buildPWD := $(shell pwd) TEST = ...
- 【Linux高级驱动】input子系统框架
[1.input子系统框架(drivers\input)] 如何得出某个驱动所遵循的框架? 1) 通过网络搜索 2) 自己想办法跟内核代码! 2.1 定位此驱动是属于哪种类 ...
- 【Linux高级驱动】input子系统框架【转】
转自:http://www.cnblogs.com/lcw/p/3802617.html [1.input子系统框架(drivers\input)] 如何得出某个驱动所遵循的框架? 1) 通过网 ...
- input子系统驱动
input子系统驱动 框架分析 核心层 文件为:/drivers/input/input.c: 首先找到入口函数为**static int __init input_init(void)**,在该函数 ...
- linux kernel input 子系统分析
Linux 内核为了处理各种不同类型的的输入设备 , 比如说鼠标 , 键盘 , 操纵杆 , 触摸屏 , 设计并实现了一个对上层应用统一的试图的抽象层 , 即是Linux 输入子系统 . 输入子系统的层 ...
- android 电容屏(二):驱动调试之基本概念篇
平台信息: 内核:linux3.4.39系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新浪博 ...
随机推荐
- JavaScript导航树
JS导航树 整理之前的小代码片段,放到博客,便于以后完善查看: 该JS导航树实际效果,[GSP+社区网站专题课程页面导航树]地址:http://gsp.inspur.com/knowledge/zhu ...
- SQL Server 全文索引的管理
全文索引不同于常见的聚集索引或非聚集索引,这些索引的内部实现是平衡树(B-Tree)结构,而全文索引在物理上是由一系列的内部表(Internal tables)构成的,这些内部表称作全文索引片段(Fr ...
- json api
from flask import Flask, redirect, url_for, jsonify, request app = Flask(__name__) users = [] ''' RE ...
- 【转载】解决refreshing gradle project 和Building gradle project info 一直卡住\速度慢
转载: http://blog.csdn.net/xx326664162/article/details/52002616 文章出自:薛瑄的博客 分析原因: 更改Gradle的版本后,或者更新AS后, ...
- CentOS中安装配置Nginx
一.安装Nginx '首先我们需要在nginx官网中下载nginx安装包,在这就下载最新版 nginx-1.13.7版本 下载完成以后我们进入下载页面进行查看 下载文件目录为 home/userNam ...
- PL/SQL Developer使用技巧(部分)
PL/SQL Developer使用技巧(部分) 关键字自动大写 在sql命令窗口中输入SQL语句时,想要关键字自动大写,引人注目该怎么办呢? 一步设置就可以达成了.点击Tools->Prefe ...
- iOS OC应用异常捕获,崩溃退出前返回信息给后台
第三方的了,有友盟,腾讯的bugly 查了一下网上类似的代码很多,在借鉴前辈的代码后,组合了一下: 1.捕获异常信息 2.获得当前日期,版本,系统 3.获得出bug的视图控制器转为字符串 4.将前3条 ...
- C++11新语法糖之尾置返回类型
C++11的尾置返回类型初衷是为了方便复杂函数的声明和定义,但是当复杂度稍微提升一些的时候很明显能注意到这种设计的作用微乎其微. 首先考虑如下代码: C++ //返回指向数组的指针 auto func ...
- 用js筛选数据排序
题目 参考以下示例代码,页面加载后,将提供的空气质量数据数组,按照某种逻辑(比如空气质量大于60)进行过滤筛选,最后将符合条件的数据按照一定的格式要求显示 <!DOCTYPE html> ...
- 5.前端基于react,后端基于.net core2.0的开发之路(5) 配置node层,session设置、获取,请求拦截
1.总结一下 今年,2月份从深圳来到广州,工作到现在,回头看,完成的项目4-5个,公司基本没有懂技术的领导,所以在技术选型上,我们非常的自由,所以内心一直都不满足现状,加上一起工作的小伙伴给力(哈哈哈 ...