本文主要参考了以下连篇博文,并做了一定的扩展与整理,在此向原作者表示感谢。
tslib 1.4 在ARM板Micro2440上移植:http://wenku.baidu.com/view/2dec67d2240c844769eaee8e.html
linux-2.6.38内核移植的经验和疑惑:http://www.arm9home.net/simple/index.php?t11074.html
这里用到的linux-2.6.38.7相对于linux-2.6.32.2的主要变化有三点,一是ioctl成员变为两个,一是信号量中删除了DECLARE_MUTEX宏定义,最后是删除了S3C2440_GPJ0的定义。
DECLARE_MUTEX(ADC_LOCK);
DEFINE_SEMAPHORE(ADC_LOCK);
在我的内核中已经使用了LED1和LED2,这里已经修改成了控制剩余的两个LED,否则会导致内核崩溃。修改方法就是删除另两个LED相关的部分,比较简单,这里不再列举。
static int sbc2440_leds_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
……
}
改为
static long sbc2440_leds_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
……
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.ioctl = sbc2440_leds_ioctl,
.unlocked_ioctl = sbc2440_leds_ioctl,
};
static int s3c24xx_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
static long s3c24xx_pwm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
.ioctl = s3c24xx_pwm_ioctl,
.unlocked_ioctl = s3c24xx_pwm_ioctl,
init_MUTEX(&lock);
sema_init(&lock, 1);
无需做修改
CMOS摄像头涉及5个文件,分别是s3c2440camif.c、s3c2440camif.h、s3c2440_ov9650.c、sccb.c、sccb.h。
sccb.c
static DECLARE_MUTEX(bus_lock);
static DEFINE_SEMAPHORE(bus_lock);
s3c2440_ov9650.c
DECLARE_MUTEX(regs_mutex);
DEFINE_SEMAPHORE(regs_mutex);
s3c2440camif.c
内核中删除了S3C2440_GPJ0的定义,用S3C2410_GPJ(0),替换后发现也可以用。但是加载该模块后,IIC EEPROM 24C08不能再读取或写入,这里是因为sccb.c中将GPE14和GPE15设为IO方式,而不是IIC方式,在后来也没有改回去。但是在linux-2.6.32中该驱动是可以的,怀疑该问题同内核也有关系,暂时不清楚。这里只是在模块卸载程序的最后添加将GPE14和GPE15改为IIC模式的两条语句,这样修改的结果是,只有在该摄像头模块卸载后才能读写24C08。
s3c2410_gpio_cfgpin(S3C2440_GPJ0, S3C2440_GPJ0_CAMDATA0);
s3c2410_gpio_cfgpin(S3C2410_GPJ(0), S3C2440_GPJ0_CAMDATA0);
static void __exit camif_cleanup(void)
{
……
s3c2410_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);
s3c2410_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);
}
最后再提一点,关于多文件编译成一个模块的Makefile,如下:
ifneq ($(KERNELRELEASE),)
obj-m := s3c2440camera.o
s3c2440camera-objs := s3c2440_ov9650.o sccb.o s3c2440camif.o
else
KDIR := /home/408/linux-2.6.38.7
PWD := `pwd`
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
.PHONY: clean
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order
endif
触摸屏问题主要是tslib要检测内核input子系统的版本号,详细参考《linux-2.6.38内核移植的经验和疑惑》一文,代码在tslib-1.4/plugins/input-raw.c中,我这里并没有按照该文指出的方法修改,而是直接将比较部分注释掉,编译talib-1.4的方法参考《tslib 1.4 在ARM板Micro2440上移植》,编译完成后只需用编译的input.so(output/lib/ts/input.so)文件替换友善根文件系统中的input.so(/usr/local/lib/ts/input.so)文件即可。
static int check_fd(struct tslib_input *i)
{
……
if (! ((ioctl(ts->fd, EVIOCGVERSION, &version) >= 0) &&
/* (version == EV_VERSION) && */
……
}
再补充一个问题:
触摸屏驱动虽然移植成功了可是tslib没有作用,触摸屏还是没有用,
我用ts_test测试终端打印了
tslib: Selected device uses a different version of the event protocol than tslib was compiled for
查看tslib源代码发现打印该信息的语句在tslib的源代码的plugs文件夹中input-raw.c的static int check_fd(struct tslib_input *i)函数中,发现tslib在加载linux触摸屏驱动模块时会检查内核的输入子系统的版本号:
if (ioctl(ts->fd, EVIOCGVERSION, &version) < 0) {
fprintf(stderr, "tslib: Selected device is not a Linux input event device/n");
return -1;
}
上面程序段将驱动的版本号存放在整型的version中
if (version != EV_VERSION) {
fprintf(stderr, "tslib: Selected device uses a different version of the event protocol than tslib was compiled for/n");
return -1;
}
该程序将获得的版本号version与本tslib的面向的版本号匹配,若不同则打印:
tslib: Selected device uses a different version of the event protocol than tslib was compiled for
信息
再看arm交叉编译工具中的头文件库中的linux/input.h中的EV_VERSION定义为
#define EV_VERSION 0x010000
而linux内核include/linux/input.h中的EV_VERSION定义为
#define EV_VERSION 0x010001
由此可见问题就出现在内核的输入子系统的版本号不匹配的问题
解决办法:
1.将内核源代码里的include/linux/input.h中的
#define EV_VERSION 0x010001
改为:
#define EV_VERSION 0x010000
2.将arm交叉编译工具中的头文件库中的
linux/input.h中的
#define EV_VERSION 0x010000
改为
#define EV_VERSION 0x010001
再编译tslib库
1.首先从网上下载的tslib-1.4.tar.gz
2.解压 tar xvzf tslib-1.4.tar.gz ; cd tslib
3.生成configure,这里比一般的开源项目少做一步,要先运行解压目录下的脚本
./autogen.sh
4.用configure 生成Makefile.
生成脚本:
./configure --host=arm-linux --prefix=$PWD/../../output/arm-linux ac_cv_func_malloc_0_nonnull=yes --enable-inputapi=no
5.编译安装
make
make install-strip #安装strip后的库
#make install #安装没有strip库版本.