android驱动分析

    因为年后工作需要,预先对Android 驱动做一些了解,以下以 I2C 接口的 多点电容触摸屏 驱动为例,简单总结下Android 驱动

1.首先编写驱动模块的 Kconfig 和 Makefile 两个文件


################################# lfl add 20160819  ####################################
obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx.o
obj-$(CONFIG_TOUCHSCREEN_SSD254X) += ssd254x.o
################################# lfl add 20160819  ####################################

如上的makefile 文件 同时支持两种I2C 接口的触摸屏 ,编译时依据 如下 Kconfig 文件的配置 选择一种硬件 


################################# lfl add 20160819  ####################################
config TOUCHSCREEN_GT9XX
tristate "GT9XX I2C Touchscreen"
depends on I2C
help
  Say Y here if you have GT9XX series I2C touchscreen,
  connected to your system.

  If unsure, say N.

 To compile this driver as a module, choose M here: the
  module will be called gt9xx_ts.


config TOUCHSCREEN_SSD254X
tristate "SSD254X I2C Touchscreen"
depends on I2C
help
  Say Y here if you have SSD254X series I2C touchscreen,
  connected to your system.

 If unsure, say N.

  To compile this driver as a module, choose M here: the
module will be called ssd254x_ts.
################################# lfl add 20160819  ####################################


系统在编译时选择其中一种有效, ./kernel_imx/arch/arm/configs/imx6_android_defconfig 对应项目的配置文件 

CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_GT9XX=y
CONFIG_TOUCHSCREEN_SSD254X=y

所以 ssd254x.o 参加编译。

2. 打开 ssd254x.c  最下部  都有模块的

module_init(ssd254x_ts_init);
module_exit(ssd254x_ts_exit);

注册模块的初始化和退出函数

static int __init ssd254x_ts_init(void)

static void __exit ssd254x_ts_exit(void)

其中 linux就是这样做的,对只需要初始化运行一次的函数都加上__init属性,__init 宏告诉编译器如果这个模块被编译到内核则把这个函数放到(.init.text)段,module_exit的参数卸载时同__init类似,如果驱动被编译进内核,则__exit宏会忽略清理函数,因为编译进内核的模块不需要做清理工作,显然__init和__exit对动态加载的模块是无效的,只支持完全编译进内核。 


3. ssd254x_ts_init  和  ssd254x_ts_exit 具体分析

3.1 ssd254x_ts_init 包括如下几个核心步骤

//创建内核工作线程

ssd254x_wq = create_singlethread_workqueue("ssd254x_wq");


//依据设备信息 创建设备

client = i2c_new_device(adapter, i2c_board_info);

//设置

Ssd254x_ts->client = client;

i2c_set_clientdata(client, Ssd254x_ts);

//添加 I2C 驱动  驱动和设备通过相同的 ssd254x_ts_id 相关联

ret=i2c_add_driver(&ssd254x_ts_driver);


3.2 ssd254x_ts_exit 基本是 对应 init 操作的反向,即各种资源的释放 主要步骤如下


i2c_del_driver(&ssd254x_ts_driver);




if (ssd254x_wq) {

destroy_workqueue(ssd254x_wq);

}



4. 驱动结构体的 定义如下 

static struct i2c_driver ssd254x_ts_driver = {


. driver = {


.owner = THIS_MODULE,


.name = TYPE_NAME,


},


.probe = ssd254x_ts_probe,

.remove = ssd254x_ts_remove,


.id_table = ssd254x_ts_id,

};

其中 最关键的是 黑色加粗的两个函数指针  系统会在初始化过程中 调用 ssd254x_ts_probe,所以这才是驱动真正的初始化

static int ssd254x_ts_probe(struct i2c_client *client,const struct i2c_device_id *idp)


{

if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))

{........}

//申请资源 并初始化

ssl_priv = kzalloc(sizeof(*ssl_priv), GFP_KERNEL);

dev_set_drvdata(&client->dev, ssl_priv);



//申请资源 并初始化
ssl_input = input_allocate_device();

input_set_drvdata(ssl_input, ssl_priv);

  

//申请硬件资源 GPIO ,并且设置

ret = gpio_request(ON_TOUCH_INT, "ssd254x-irq");

gpio_direction_input(ON_TOUCH_INT);


//注册主工作函数

INIT_WORK(&ssl_priv->ssl_work, ssd254x_ts_work);


//注册硬件中断或者 定时器,特定条件下运行一下驱动主函数 ,不能像单片机那样独占CPU资源

if((ssl_priv->use_irq==1)||(ssl_priv->use_irq==2))
{
ssl_priv->irq = gpio_to_irq(ON_TOUCH_INT);
error = request_irq(ssl_priv->irq, ssd254x_ts_isr, IRQF_TRIGGER_LOW, client->name,ssl_priv);

}


if((ssl_priv->use_irq==0)||(ssl_priv->use_irq==2))
{
hrtimer_init(&ssl_priv->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ssl_priv->timer.function = ssd254x_ts_timer;

}

}


ssd254x_ts_remove的工作与  ssd254x_ts_probe 基本反向 ,

static int ssd254x_ts_remove(struct i2c_client *client)


{


struct ssl_ts_priv *ssl_priv = dev_get_drvdata(&client->dev);


#ifdef CONFIG_TOUCHSCREEN_SSL_DEBUG


printk("+-----------------------------------------+\n");


printk("| ssd254x_ts_remove !               |\n");


printk("+-----------------------------------------+\n");


#endif


if((ssl_priv->use_irq==0)||(ssl_priv->use_irq==2)) hrtimer_cancel(&ssl_priv->timer);


//if((ssl_priv->use_irq==1)||(ssl_priv->use_irq==2)) free_irq(ssl_priv->irq, ssl_priv);


input_unregister_device(ssl_priv->input);


input_free_device(ssl_priv->input);


kfree(ssl_priv);


dev_set_drvdata(&client->dev, NULL);


return 0;


}




5. 无论是上面注册中断处理函数还是 定时器函数 ,所做的工作都一样 ,让本模块的内核线程运行一次 

中断处理函数,先关中断,启动线程运行驱动程序,驱动程序中再次打开中断,定时器类似

static irqreturn_t ssd254x_ts_isr(int irq, void *dev_id)


{


struct ssl_ts_priv *ssl_priv = dev_id;




disable_irq_nosync(ssl_priv->irq);
queue_work(ssd254x_wq, &ssl_priv->ssl_work);
return IRQ_HANDLED;


}



static enum hrtimer_restart ssd254x_ts_timer(struct hrtimer *timer)
{
struct ssl_ts_priv *ssl_priv = container_of(timer, struct ssl_ts_priv, timer);


queue_work(ssd254x_wq, &ssl_priv->ssl_work);

if(ssl_priv->use_irq==0)

hrtimer_start(&ssl_priv->timer, ktime_set(0, MicroTimeTInterupt), HRTIMER_MODE_REL);

return HRTIMER_NORESTART;


}


6. 真正的驱动程序 

static void ssd254x_ts_work(struct work_struct *work)

{

例如  触摸屏 会一直读取屏幕信息,然后反馈给系统 

gtp_touch_down

gtp_touch_up

}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值