linux触摸屏驱动开发中的s3c

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的bitmapunsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //此设备所拥有的相对轴的bitmapunsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //此设别所拥有的绝对轴的bitmapunsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; //设备所支持的杂项事件的bitmapunsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; //设备上的led的bitmapunsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; //设备所支持的声音效果的bitmapunsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; //设备所支持的强制反馈效果的bitmap(force feedback)unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; //设备上的开关的bitmapunsigned 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后再没有新的事件时设置为1int 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 devicestruct 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结构体注册中断函数

劝君更尽一杯酒,西出阳关无故人。

linux触摸屏驱动开发中的s3c

相关文章:

你感兴趣的文章:

标签云: