OK6410矩阵键盘驱动问题(linux-2.6.36.2)

飞凌键盘驱动怎么老是出问题阿。。。

涉及的文件:(内核版本linux-2.6.36.2)

file1: driver/input/keyboard/samsung-keypad.c

file2: arch/arm/plat-samsung/include/plat/keypad.h

file3: arch/arm/mach-s3c64xx/mach-s3c64xx.c

file4: arch/arm/plat-samsung/Dev-keypad.c

其中键盘的驱动代码主要为file1: samsung-keypad.c

在内核根目录,make menuconfig查看了内核的配置,默认使用了gpio-keys驱动,也就是开发板上的6个一排的小红色按键的驱动。而在此我们使用的矩阵键盘驱动应该使用samsung-keypad。内核默认没有编译,因此我们可以单独编译该模块加载运行。

照理说将file1拿出来单独编译成模块samsung-keypad.ko然后加载,就可以使用键盘了,但是世事难料,编译成功通过,但是加载后没有丝毫反应,于是在file1中的几个主要函数中添加了打印调试信息。再次加载发现,加载过程只进行到samsung_keypad_init()。

也就是只是调用了  platform_driver_register(&samsung_keypad_driver);

而probe函数没用运行,由此发出疑问:是不是矩阵键盘对应的设备数据没有在Platformbus 总线上安装?

使用source insight 查看源代码 ,找到file3中定义的6410的设备列表:

staticstruct platform_device *smdk6410_devices[] __initdata = {

.。。。

&s3c_device_fb,

&s3c_device_ohci,

&s3c_device_usb_hsotg,

#if 0

&s3c64xx_device_iisv4,

&samsung_device_keypad,

#endif

 


&s3c64xx_device_ac97,

&s3c_device_adc,

。。。

};

发现其中果然将&samsung_device_keypad,给屏蔽掉了。

找到症结所在,去掉屏蔽,然后重新编译内核,编译驱动模块,加载运行,此时进入了probe函数,但是又出现了新的问题,内存错误,程序直接死掉。

通过加入调试信息,将问题锁定在probe函数中调用的matrix_keypad_build_keymap()函数中,即:

matrix_keypad_build_keymap(keymap_data,row_shift, input_dev->keycode, input_dev->keybit);

 

使用source insight 查看,该函数如下:

staticinline void

matrix_keypad_build_keymap(conststruct matrix_keymap_data *keymap_data,unsigned int row_shift,unsigned short *keymap, unsigned long *keybit)

{

inti;

for(i = 0; i < keymap_data->keymap_size; i++) {

unsignedint key = keymap_data->keymap[i];

unsignedint row = KEY_ROW(key);

unsignedint col = KEY_COL(key);

unsignedshort code = KEY_VAL(key);

 


keymap[MATRIX_SCAN_CODE(row,col, row_shift)] = code;

__set_bit(code,keybit);

}

__clear_bit(KEY_RESERVED,keybit);

}

在调试时,我试图打印keymap_data->keymap_size发现结果很小的负数,打印keymap_data->keymap[i]的时候就会报内存出错,由此可见,keymap_data初始化出了问题。

 

继续查看源代码,在probe函数中,keymap_data= pdata->keymap_data; 而pdata= pdev->dev.platform_data;

即:keymap_data=pdev->dev.platform_data->keymap_data

其中,pdev也就是probe函数的参数:platform_device。.在这个模块中,应该就是file4:Dev-keypad.c文件中定义的:samsung_device_keypad,也即上面提到的6410设备列表中的samsung_device_keypad

structplatform_device samsung_device_keypad = {

.name ="samsung-keypad",

.id =-1,

.num_resources =ARRAY_SIZE(samsung_keypad_resources),

.resource =samsung_keypad_resources,

};

在系统开机时调用smdk6410_machine_init函数,在此函数中调用了

samsung_keypad_set_platdata(&smdk6410_keypad_data);

函数定义如下:

void__init samsung_keypad_set_platdata(struct samsung_keypad_platdata*pd)

{

structsamsung_keypad_platdata *npd;

npd= s3c_set_platdata(pd, sizeof(struct samsung_keypad_platdata),

&samsung_device_keypad);

 


if(!npd->cfg_gpio)

npd->cfg_gpio= samsung_keypad_cfg_gpio;

}

其中调用:

void__init *s3c_set_platdata(void *pd, size_t pdsize,

struct platform_device *pdev)

{

。。。

pdev->dev.platform_data= npd;

returnnpd;

}

所以pdev->dev.platform_data= &smdk6410_keypad_data

smdk6410_keypad_data及相关的数据结构定义如下:(在file3中)

 

static uint32_t smdk6410_keymap[] __initdata = {

/*KEY(row, col, keycode) */

KEY(0,3, KEY_1), KEY(0, 4, KEY_2), KEY(0, 5, KEY_3),

KEY(0,6, KEY_4), KEY(0, 7, KEY_5),

KEY(1,3, KEY_A), KEY(1, 4, KEY_B), KEY(1, 5, KEY_C),

KEY(1,6, KEY_D), KEY(1, 7, KEY_E)

};


static struct matrix_keymap_data smdk6410_keymap_data __initdata = { 
.keymap =smdk6410_keymap,

.keymap_size =ARRAY_SIZE(smdk6410_keymap),

};


static struct samsung_keypad_platdata smdk6410_keypad_data __initdata = { 
.keymap_data =&smdk6410_keymap_data,

.rows =2,

.cols =8,

};

到这里,我们可以知道,上面说的初始化有问题的keymap_data应该就是这里的smdk6410_keymap_data 了,如果说初始化有问题,那就是smdk6410_keypad_data有问题了,也即probe函数中的pdata有问题。

但是奇怪的是,我在probe函数中打印了pdata->rows,和pdata->cols确实是打印出2 & 8,那说明smdk6410_keymap_data没有问题阿。为何单独smdk6410_keymap_data的keymap_data字段出了问题呢,百思不得其解。有心去调试,可是发现该代码在内核代码中,不是模块可加载的代码,每次都需要编译内核、烧写内核,然后才能测试,比较麻烦。于是想在probe函数中动动手脚,绕过这块代码。

上面的这三个数据结构,主要就是提供了两方面的信息,一个是行和列的个数,第二个则是矩阵键盘的映射表。因此在probe函数中我们可以提供自己定义的行列值以及键盘映射表。

再看probe函数,该函数主要任务就是申请分配一些资源,以及对structsamsung_keypad *keypad; 和structinput_dev *input_dev; 两个数据结构进行初始化。

这里我定义了两个参数rows和cols代替原来的pdata->rows,pdata->cols.并全部初始化为8,假设64个键盘都用到了,当然以后可以按照需要随时改动。

之前调试遇到的内存错误问题出现在matrix_keypad_build_keymap(keymap_data,row_shift,input_dev->keycode,input_dev->keybit);函数中,

查看源代码发现该函数的主要功能就是对input_dev->keycode 和input_dev->keybit进行赋值初始化,因此我使用如下的代码代替该函数:

for(key= 0; key < keycodes_size; key++){

code= keypad->keycodes[key] = keypad_keycode[key];

if(code<=0)

continue;

__set_bit(code,input_dev->keybit);

}

__clear_bit(0,input_dev->keybit);

 


其中keycodes_size = rows ×cols = 8×8 =64

keypad->keycodes =input_dev->keycode

keypad_keycode·[]则是自己定义的键盘映射表,表内容如下:

unsignedshort keypad_keycode[] = {

KEY_A,KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H,

KEY_I,KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P,

KEY_Q,KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X,

KEY_Y,KEY_Z, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6,

KEY_7,KEY_8, KEY_9, KEY_0, KEY_ENTER, KEY_ENTER, KEY_ENTER, KEY_ENTER,

KEY_F3,KEY_ENTER,KEY_6,KEY_Y, KEY_H, KEY_SPACE, 47, 48,

KEY_BACKSPACE,KEY_DOWN,KEY_7,KEY_U, KEY_J, KEY_N, 55, KEY_ENTER,

KEY_LEFT,KEY_RIGHT,KEY_9,KEY_8, KEY_I, KEY_K, KEY_B, 63, KEY_COMMA

};

为了方便管理,该表定义在file2: arch/arm/plat-samsung/include/plat/keypad.h中,表的内容以及排序可以根据自己需要随意改动。

至此,probe函数就可以检测成功了。。。

此外在samsung_keypad_scan还会遇到内存错误,该函数如下:

staticvoid samsung_keypad_scan(struct samsung_keypad *keypad,

unsignedint *row_state)

{

//structdevice *dev;

unsignedint col;

unsignedint val;

xyl_dbg("keypad_scanning...\n");

//dev= keypad->input_dev->dev.parent;


for(col = 0; col < keypad->cols; col++) {

/*if(samsung_keypad_is_s5pv210(dev))

{

xyl_dbg("is_s5pv210\n");

val= S5PV210_KEYIFCOLEN_MASK;

val&= ~(1 << col) << 8;

}

else

{*/

//xyl_dbg("is_not_s5pv210\n");

val= SAMSUNG_KEYIFCOL_MASK;

val&= ~(1 << col);

//}


writel(val,keypad->base + SAMSUNG_KEYIFCOL);

mdelay(1);


val= readl(keypad->base + SAMSUNG_KEYIFROW);

row_state[col]= ~val & ((1 << keypad->rows) - 1);

}


/*KEYIFCOL reg clear */

writel(0,keypad->base + SAMSUNG_KEYIFCOL);

}

出现内存错误的是dev= keypad->input_dev->dev.parent;语句,简单的处理办法为:注释调该语句,以及下面和s5pv210g相关的所有语句即可,如上面红色部分。

注意:2.6.28版本中键盘驱动存在的问题,该版本中依然存在,即:

voidsamsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols)

{

unsignedint gpio;

unsignedint end;

 


/*Set all the necessary GPK pins to special-function 3: KP_ROW[x] */

end= S3C64XX_GPK(8 + rows);

for(gpio = S3C64XX_GPK(8); gpio < end; gpio++) {

s3c_gpio_cfgpin(gpio,S3C_GPIO_SFN(3));

s3c_gpio_setpull(gpio,S3C_GPIO_PULL_NONE);

}

 

/*Set all the necessary GPL pins to special-function 3: KP_COL[x] */

end= S3C64XX_GPL(0 + cols);

for(gpio = S3C64XX_GPL(0); gpio < end; gpio++) {

s3c_gpio_cfgpin(gpio,S3C_GPIO_SFN(3));

s3c_gpio_setpull(gpio,S3C_GPIO_PULL_NONE);

}

}

其中S3C_GPIO_PULL_NONE需要改成S3C_GPIO_PULL_UP

驱动终于可以用了。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值