继上一篇: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驱动调试(二)的更多相关文章

  1. 基于input子系统的sensor驱动调试(一)

    要想弄明白世界的本质,就要追根溯源:代码也是一样的道理: 最近调试几个sensor驱动,alps sensor驱动.compass sensor驱动.G-sensor驱动都是一样的架构: 一.基于in ...

  2. Linux驱动编程--基于I2C子系统的I2C驱动

    代码中,我添加了很多注释,应该不难理解,有错误大家可以指出来,我再改正 #include <linux/kernel.h> #include <linux/module.h> ...

  3. ARM Linux 驱动Input子系统之按键驱动测试

    上一篇已经谈过,在现内核的中引入设备树之后对于内核驱动的编写,主要集中在硬件接口的配置上了即xxxx.dts文件的编写. 在自己的开发板上移植按键驱动: 1.根据开发板的原理图 确定按键的硬件接口为: ...

  4. Linux驱动编程--基于I2C子系统的I2C驱动的Makefile

    ifeq ($(KERNELRELEASE),) KERNELDIR ?= /lib/modules/$(shell uname -r)/buildPWD := $(shell pwd) TEST = ...

  5. 【Linux高级驱动】input子系统框架

    [1.input子系统框架(drivers\input)] 如何得出某个驱动所遵循的框架?    1) 通过网络搜索    2) 自己想办法跟内核代码!         2.1 定位此驱动是属于哪种类 ...

  6. 【Linux高级驱动】input子系统框架【转】

    转自:http://www.cnblogs.com/lcw/p/3802617.html [1.input子系统框架(drivers\input)] 如何得出某个驱动所遵循的框架?    1) 通过网 ...

  7. input子系统驱动

    input子系统驱动 框架分析 核心层 文件为:/drivers/input/input.c: 首先找到入口函数为**static int __init input_init(void)**,在该函数 ...

  8. linux kernel input 子系统分析

    Linux 内核为了处理各种不同类型的的输入设备 , 比如说鼠标 , 键盘 , 操纵杆 , 触摸屏 , 设计并实现了一个对上层应用统一的试图的抽象层 , 即是Linux 输入子系统 . 输入子系统的层 ...

  9. android 电容屏(二):驱动调试之基本概念篇

    平台信息: 内核:linux3.4.39系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新浪博 ...

随机推荐

  1. Ubuntu 下 libgps 库的使用

    简介 一般 GPS 接收器会遵循美国国家海洋电子协会(National Marine Electronics Association)所指定的标准规格,其中包含传输资料的格式以及传输资料的通讯协议.那 ...

  2. 前后端分离ueditor富文本编辑器的使用-Java版本

    最近在写一个自己的后台管理系统(主要是写着玩的,用来熟悉后端java的知识,目前只是会简单的写点接口),想在项目中编写一个发布新闻文章的功能,想到了使用百度的ueditor富文本编辑器,网上找了很多j ...

  3. 下篇: php 微商城 基于Thinkphp3.2框架开发

    (12)微信商城 ① 前台模板引入 a.引入微信商城模板的css+js+Images+img+bootstrap b.引入微商城的首页index.html及详情页detail.html页面模板 注意: ...

  4. ucore lab1练习2 qemu+gdb 不能协作调试的问题make lab1-mon

    本练习是qemu结合gdb调试,但是我做实验的时候并不能像视频输入make lab1-mon那样顺利调试,期间有各种error,后来我找到原因,请看解决方法. 请先把ucore_lab文件删除,以下全 ...

  5. 598. Range Addition II

    Given an m * n matrixMinitialized with all0's and several update operations. Operations are represen ...

  6. MST系列

    1.POJ2485 Highways 蛮水的 数组一开始开小了卡了一会儿 我可能是个傻逼 #include<iostream> #include<cstdio> #includ ...

  7. lesson - 7 vim 详解

    1. vim简介vim是从vi发展出来 ,第一个版本由布莱姆·米勒在1991年发布 ,它基于VIM许可证,兼容GPL. 官网 www.vim.org 2. 安装vim: yum install -y ...

  8. 前端MVC Vue2学习总结(五)——表单输入绑定、组件

    一.表单输入绑定 1.1.基础用法 你可以用 v-model 指令在表单控件元素上创建双向数据绑定.它会根据控件类型自动选取正确的方法来更新元素.尽管有些神奇,但 v-model 本质上不过是语法糖, ...

  9. 《Create Your own PHP Framework》笔记

    前言 大力推荐该教程:<Create Your own PHP Framework> Symfony的学习蛮累的,官方文档虽然很丰富,但是组织方式像参考书而不是指南,一些不错的指导性文档常 ...

  10. 跟我一起读postgresql源码(七)——Executor(查询执行模块之——数据定义语句的执行)

    1.数据定义语句的执行 数据定义语句(也就是之前我提到的非可优化语句)是一类用于定义数据模式.函数等的功能性语句.不同于元组增删査改的操作,其处理方式是为每一种类型的描述语句调用相应的处理函数. 数据 ...