linux触摸屏驱动开发中的s3c_ts_probe()函数的分析

来源:互联网 发布:java date gethour 编辑:程序博客网 时间:2024/06/06 04:32

linux触摸屏驱动开发中的s3c_ts_probe()函数的分析


static int __init s3c_ts_probe(struct platform_device *pdev)
{
struct resource *res;
struct device *dev;
struct input_dev *input_dev;
struct s3c_ts_mach_info * s3c_ts_cfg;
int ret, size;

dev = &pdev->dev;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {

dev_err(dev,"no memory resource specified\n");
return -ENOENT;
}



size = (res->end - res->start) + 1;
ts_mem = request_mem_region(res->start, size, pdev->name);

if (ts_mem == NULL) {
dev_err(dev, "failed to get memory region\n");
ret = -ENOENT;
goto err_req;
}



ts_base = ioremap(res->start, size);
if (ts_base == NULL) {

dev_err(dev, "failed to ioremap() region\n");
ret = -EINVAL;
goto err_map;
}


ts_clock = clk_get(&pdev->dev, "adc");

if (IS_ERR(ts_clock)) {
dev_err(dev, "failed to find watchdog clock source\n");
ret = PTR_ERR(ts_clock);
goto err_clk;
}



clk_enable(ts_clock);


s3c_ts_cfg = s3c_ts_get_platdata(&pdev->dev);

if ((s3c_ts_cfg->presc&0xff) > 0)

writel(S3C_ADCCON_PRSCEN | S3C_ADCCON_PRSCVL(s3c_ts_cfg->presc&0xFF),\
ts_base+S3C_ADCCON);

else

writel(0, ts_base+S3C_ADCCON);


/* Initialise registers */
if ((s3c_ts_cfg->delay&0xffff) > 0)
writel(s3c_ts_cfg->delay & 0xffff, ts_base+S3C_ADCDLY);


if (s3c_ts_cfg->resol_bit==12) {

switch(s3c_ts_cfg->s3c_adc_con) {
case ADC_TYPE_2:
writel(readl(ts_base+S3C_ADCCON)|S3C_ADCCON_RESSEL_12BIT, ts_base+S3C_ADCCON);
break;


case ADC_TYPE_1:
writel(readl(ts_base+S3C_ADCCON)|S3C_ADCCON_RESSEL_12BIT_1, ts_base+S3C_ADCCON);
break;

default:
dev_err(dev, "Touchscreen over this type of AP isn't supported !\n");
break;
}
}


writel(WAIT4INT(0), ts_base+S3C_ADCTSC);


ts = kzalloc(sizeof(struct s3c_ts_info), GFP_KERNEL);
input_dev = input_allocate_device();

if (!input_dev) {

ret = -ENOMEM;
goto err_alloc;
}


ts->dev = input_dev;


ts->dev->evbit[0] = ts->dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
ts->dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);


if (s3c_ts_cfg->resol_bit==12) {

input_set_abs_params(ts->dev, ABS_X, 0, 0xFFF, 0, 0);
input_set_abs_params(ts->dev, ABS_Y, 0, 0xFFF, 0, 0);
}

else {

input_set_abs_params(ts->dev, ABS_X, 0, 0x3FF, 0, 0);
input_set_abs_params(ts->dev, ABS_Y, 0, 0x3FF, 0, 0);
}


input_set_abs_params(ts->dev, ABS_PRESSURE, 0, 1, 0, 0);

sprintf(ts->phys, "input(ts)");

ts->dev->name = s3c_ts_name;
ts->dev->phys = ts->phys;
ts->dev->id.bustype = BUS_RS232;
ts->dev->id.vendor = 0xDEAD;
ts->dev->id.product = 0xBEEF;
ts->dev->id.version = S3C_TSVERSION;


ts->shift = s3c_ts_cfg->oversampling_shift;
ts->resol_bit = s3c_ts_cfg->resol_bit;
ts->s3c_adc_con = s3c_ts_cfg->s3c_adc_con;

/* For IRQ_PENDUP */
ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (ts_irq == NULL) {

dev_err(dev, "no irq resource specified\n");
ret = -ENOENT;
goto err_irq;
}



ret = request_irq(ts_irq->start, stylus_updown, IRQF_SAMPLE_RANDOM, "s3c_updown", ts);
if (ret != 0) {

dev_err(dev,"s3c_ts.c: Could not allocate ts IRQ_PENDN !\n");
ret = -EIO;
goto err_irq;
}



/* For IRQ_ADC */
ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
if (ts_irq == NULL) {

dev_err(dev, "no irq resource specified\n");
ret = -ENOENT;
goto err_irq;
}


ret = request_irq(ts_irq->start, stylus_action, IRQF_SAMPLE_RANDOM, "s3c_action", ts);
if (ret != 0) {

dev_err(dev, "s3c_ts.c: Could not allocate ts IRQ_ADC !\n");
ret =  -EIO;
goto err_irq;
}


printk(KERN_INFO "%s got loaded successfully : %d bits\n", s3c_ts_name, s3c_ts_cfg->resol_bit);

/* All went ok, so register to the input system */
ret = input_register_device(ts->dev);

if(ret) {

dev_err(dev, "s3c_ts.c: Could not register input device(touchscreen)!\n");
ret = -EIO;
goto fail;
}


return 0;

fail:

free_irq(ts_irq->start, ts->dev);
free_irq(ts_irq->end, ts->dev);


err_irq:

input_free_device(input_dev);
kfree(ts);


err_alloc:

clk_disable(ts_clock);
clk_put(ts_clock);


err_clk:

iounmap(ts_base);

err_map:

release_resource(ts_mem);
kfree(ts_mem);

err_req:

return ret;

}


首先向说一下函数中的前几个变量:
1.第一个局部变量是struct resource类型的指针res变量,这个变量使用来描述设备的资源结构体(include\linux\ioport.h)
struct resource 
{

resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;

};
其中的flags位表示的是资源的类型,start和end分别表示资源的起始地址和结束地址
2.device这里就不细讲了,大家知道它是对于设备的一个封装就行了

3.struct input_dev类型指针变量input_dev   

 input_dev 结构体成员注释:

 struct input_dev — represents an input device//说明:下面出现的bitmap是指“位映像”
struct input_dev 

const char * name; //设备名
const char * phys; //系统层次架构中设备的物理路径 
const char * uniq; //设备的唯一标示码(如果设备有的话) 
struct input_id id; //设备的id (struct input_id) 
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //设备所支持的事件类型的bitmap (EV_KEY, EV_REL, etc.) 
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //此设备所拥有的keys或者buttons的bitmap 
unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //此设备所拥有的相对轴的bitmap 
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //此设别所拥有的绝对轴的bitmap 
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; //设备所支持的杂项事件的bitmap 
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; //设备上的led的bitmap 
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; //设备所支持的声音效果的bitmap 
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; //设备所支持的强制反馈效果的bitmap(force feedback) 
unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; //设备上的开关的bitmap 
unsigned int keycodemax; //键码表的大小(keycode table) 
unsigned int keycodesize; //键码表元素的大小 
void * keycode; //此设备的扫描码到键码的映射 
/*修改现有键映射的可选方法, 曾用来实现稀疏键映射. 若没有提供则使用缺省的 */ 
int (* setkeycode) (struct input_dev *dev, int scancode, int keycode); 
/*获取当前键映射的可选方法. 若未提供则使用缺省的*/ 
int (* getkeycode) (struct input_dev *dev, int scancode, int *keycode); struct ff_device * ff; 
//设备关联的强制反馈结构体(如果设备支持强制反馈效果的话) 
unsigned int repeat_key; //存储上个按下的键的键码; 用于实现软件自动重复 
struct timer_list timer; //软件自动重复的定时器 
int sync; //自上一次EV_SYNC后再没有新的事件时设置为1 
int abs[ABS_MAX + 1]; //要上报的绝对坐标下的当前值 
int rep[REP_MAX + 1]; //自动重复参数的当前值 (delay, rate) 
unsigned long key[BITS_TO_LONGS(KEY_CNT)]; //反映设备的keys/buttons的当前状态 
unsigned long led[BITS_TO_LONGS(LED_CNT)]; //反映设备LED的当前状态 
unsigned long snd[BITS_TO_LONGS(SND_CNT)]; //反映声音效果的当前状态 
unsigned long sw[BITS_TO_LONGS(SW_CNT)]; //反映设备开关的当前状态 
int absmax[ABS_MAX + 1]; //来自绝对轴事件的最大值 
int absmin[ABS_MAX + 1]; //来自绝对轴事件的最小值 
int absfuzz[ABS_MAX + 1]; //描述轴的噪声 
int absflat[ABS_MAX + 1]; //中央平坦位置的大小 (used by joydev) 
/*这个方法在第一个用户调用input_event_device时调用。驱动必须让设备准备好开始产生事件 (开始轮询线程,请求一个IRQ,提交URB,等等) */ 
int (* open) (struct input_dev *dev); 
void (* close) (struct input_dev *dev); //这个方法在最后一个用户调用input_close_device时被调用.
/*清空设备. 常用于清空失连的(disconnect)加载进设备的强制反馈效果 */ 
int (* flush) (struct input_dev *dev, struct file *file);
/*事件处理方法, 如 EV_LED 或者 EV_SND. 设备将执行一些要求的动作 (开启 LED, 放声音, 等等.) 此调用由event_lock保护并且不能够休眠 */ int (* event) (struct input_dev *dev, unsigned int type, unsigned int code, int value);
/*当前占有设备的输入句柄 (via EVIOCGRAB ioctl). 当设备对应一个句柄,这个句柄就是来自此设备所有输入事件的唯一接受者*/ 
struct input_handle * grab;/*当输入核接受处理设备的心事件时此spinlock锁定 (in input_event). */ 
spinlock_t event_lock; struct mutex mutex; //序列化对open、close、flush方法的调用
/* 存储打开此设备的用户数量(input handlers). 通过input_open_device和input_close_device来确保dev->open只能在被第一个用户打开设备时调用并且确保dev->close只能在最后一个用户关闭设备时被调用*/ 
unsigned int users; 
int going_away; //标示设备属于未注册的一类并且会导致input_open_device*()返回-ENODEV错误. 
struct device dev; //设备的驱动模型视图 
struct list_head h_list; //和设备关联的输入句柄链表。当读取链表时需要锁定dev->mutex。 
struct list_head node; //用来把设备放入input_dev_list

}; 
//AutoRepeat:用来配置对按住某键不放的处理,格式为:
//AutoRepeat 毫秒数 次数
//如:AutoRepeat 500 5,表示当按住某键500毫秒(0.5秒)后,开始自动送出该按键信号,每秒5次。
4.struct s3c_ts_mach_info指针变量s3c_ts_cfg(arch\arm\plat-s3c\include\plat\ts.h)
struct s3c_ts_mach_info 
{

int delay;//延迟时间
int presc;//预分频值
int oversampling_shift;//转化次数
int resol_bit;//分辨率
enum s3c_adc_type s3c_adc_con;//adc类型,跟板子的型号有关,见下面

};
其中有
enum s3c_adc_type 
{

ADC_TYPE_0,ADC_TYPE_1, /* S3C2416, S3C2450 */
ADC_TYPE_2,/* S3C64XX, S5PC1XX */

};
以上是几个局部变量的声明。
接下来用struct platform_device结构体参数的dev来初始化刚刚声明的dev变量
struct platform_device 
{

const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;

};
然后初始化res变量对应的平台设备资源:在Dev-ts.c (linux2.6.28\arch\arm\plat-s3c)文件中
/* Touch srcreen */
static struct resource s3c_ts_resource[] = 
{

[0] = {
.start = S3C_PA_ADC, I/O端口
.end = S3C_PA_ADC + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_PENDN, 中断
.end = IRQ_PENDN,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_ADC, 中断
.end = IRQ_ADC,
.flags = IORESOURCE_IRQ,
}
};
struct platform_device s3c_device_ts = 
{
.name = "s3c-ts",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_ts_resource),
.resource = s3c_ts_resource,

};
再为驱动申请内存。ioremap是把物理地址重映射为虚拟地址,便于操作系统操作。
接着申请时钟,时钟使能。获取s3c6410 touchscreen machine infomation,s3c_ts_mach_info结构体(delay、presc、oversampling_shift、resol_bit)设置预分频接口寄存器、设置delay接口寄存器、设置resol_bit接口寄存器
writel(WAIT4INT(0), ts_base+S3C_ADCTSC);设置为等待中断模式
ts = kzalloc(sizeof(struct s3c_ts_info), GFP_KERNEL);//申请内存
input_dev = input_allocate_device();//申请input device
struct s3c_ts_info {

struct input_dev *dev;
long xp;
long yp;
int count;
int shift;
char phys[32];
int resol_bit;
enum s3c_adc_type s3c_adc_con;

};
这就是ts的结构体,结构体的第一个元素就是input_dev结构体接着初始化input device结构体、初始化ts结构体注册中断函数


0 0
原创粉丝点击