实验平台:Jz2440开发板
一、移植DM9000C网卡驱动
1.移植步骤
1)编译
2) 解决错误
2.1) 头文件不对:去掉或改名
2.2) 宏不对:改名使用新宏
2.3) 有些函数没有了:改名使用新函数
2.移植内核自带的网卡驱动程序
在移植之前,首先我们来看一下mini2440(对应的机器ID为:set machid 7CF)中,是如何支持dm9000网卡的。进入到入口函数,找到结构体:
static struct platform_driver dm9000_driver = {
.driver = {
.name = "dm9000",
.owner = THIS_MODULE,
.pm = &dm9000_drv_pm_ops,
},
.probe = dm9000_probe,
.remove = __devexit_p(dm9000_drv_remove),
};
一般是通过.name这个成员进行匹配的,搜索字符串"dm9000",找到如下结构体(在平台文件中:arch\arm\mach-s3c24xx\mach-mini2440.c
):
static struct platform_device mini2440_device_eth = {
.name = "dm9000",
.id = -1,
.num_resources = ARRAY_SIZE(mini2440_dm9k_resource),
.resource = mini2440_dm9k_resource,
.dev = {
.platform_data = &mini2440_dm9k_pdata,
},
};
然后搜索结构体mini2440_device_eth
,找到:
static struct platform_device *mini2440_devices[] __initdata = {
&s3c_device_ohci,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_rtc,
&s3c_device_usbgadget,
&mini2440_device_eth, //在这里
&mini2440_led1,
&mini2440_led2,
&mini2440_led3,
&mini2440_led4,
&mini2440_button_device,
&s3c_device_nand,
&s3c_device_sdi,
&s3c_device_iis,
&uda1340_codec,
&mini2440_audio,
&samsung_asoc_dma,
};
然后再搜索:mini2440_devices
,找到:
platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
这就是把结构体mini2440_devices
添加到内核,里面的关于网卡的结构在里面,最终匹配驱动程序,就可以使用驱动程序了。
(这就是所谓的平台设备平台驱动的东西了,把可变的东西抽象出来放到平台相关的文件中定义,而我们的驱动程序,基本上是不需要改变的,它是稳定的内容,我们移植的时候,只需要把平台层可变的相关结构体加上,需要修改的资源,进行修改就可以了)。
而我们用的是smdk2440(对应的机器ID为:set machid 16a),然后我在mach-smdk2440.c中添加以下函数:
/*
* The DM9000 has no eeprom, and it's MAC address is set by
* the bootloader before starting the kernel.
*/
/* DM9000AEP 10/100 ethernet controller */
#define MACH_SMDK2440_DM9K_BASE (S3C2410_CS4 + 0x300)
static struct resource smdk2440_dm9k_resource[] = {
[0] = {
.start = MACH_SMDK2440_DM9K_BASE,
.end = MACH_SMDK2440_DM9K_BASE + 3,
.flags = IORESOURCE_MEM
},
[1] = {
.start = MACH_SMDK2440_DM9K_BASE + 4,
.end = MACH_SMDK2440_DM9K_BASE + 7,
.flags = IORESOURCE_MEM
},
[2] = {
.start = IRQ_EINT7,
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
}
};
static struct dm9000_plat_data smdk2440_dm9k_pdata = {
.flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
};
static struct platform_device smdk2440_device_eth = {
.name = "dm9000",
.id = -1,
.num_resources = ARRAY_SIZE(smdk2440_dm9k_resource),
.resource = smdk2440_dm9k_resource,
.dev = {
.platform_data = &smdk2440_dm9k_pdata,
},
};
在结构体smdk2440_devices中添加网卡成员:
static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_ohci,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&smdk2440_device_eth, /* 添加 */
};
添加头文件:
#include <linux/dm9000.h>
然后重新编译内核,成功。设置机器id,烧写新内核:
set machid 16a
save
nfs 32000000 192.168.2.122:/home/book/works/first_fs/uImage_new
nand erase.part kernel
nand write 32000000 60000 $filesize
重启开发板,成功启动内核,设置开发IP地址,进行ping测试,成功。
同时使用以下命令挂载网络文件系统,挂载成功。
mount -t nfs -o nolock,vers=2 192.168.2.122:/home/book/works/first_fs /mnt
成功移植DM9000网卡后,从启动内核打印的信息可以发现之前一直存在的ifconfig: SIOCSIFADDR: No such device
也消失了。
二、移植LED、按键驱动
1.移植LED驱动
把之前写好的LED驱动(基于linux2.6内核)拷贝到ubuntu服务器,修改Makefile,把内核路径改为linux3.4.2内核的路径:
KERN_DIR = /home/book/works/linux-3.4.2
然后保存退出,直接make
编译,发现如下错误。
把#include <asm/arch/regs-gpio.h>
、#include <asm/hardware.h>
两个头文件去掉,重新make
编译,结果如下:
从编译的结果可以看出,头文件相关的错误已经消失。接下来继续解决class_create
、class_device_create
、class_device_unregister
、class_destroy
等函数的错误。这个我们可以参考一下别的驱动程序时怎么做的。
参考dsp56k.c
驱动程序发现缺少了头文件:#include <linux/device.h>
,重新编译,结果如下:
从上图可知剩下的就是class_device_create
、class_device_unregister
两个函数相关的错误了,继续解决问题。
从dsp56k.c
驱动程序的入口与出口函数发现,linux3.4.2内核用的是device_create
与device_destroy
l两个函数,所以,把
first_class_dev = class_device_create(first_drv_class,NULL,MKDEV(major,0),NULL,"first_dev");
class_device_unregister(first_class_dev);
改为:
first_class_dev = device_create(first_drv_class,NULL,MKDEV(major,0),NULL,"first_dev");
device_destroy(first_drv_class,MKDEV(major,0));
重新编译,结果如下,编译成功。
重新编译以下测试程序:arm-linux-gcc -o first_drv_test first_drv_test.c
把first_drv.ko
、first_drv_test
拷贝到网络文件系统,测试。
装载驱动程序:insmod first_drv.ko
查看设备:cat cat /proc/devices
、lsmod
,驱动程序装载成功。
测试:./first_drv_test on
、./first_drv_test off
,开灯、关灯正常。
2. 移植按键驱动
按键驱动的移植与LED驱动移植的步骤相同,移植的过程主要是解决编译出现的错误,添加头文件,修改函数名。
3.移植按键中断驱动程序
驱动程序的移植,主要看编译出现的错误,然后一个个的解决这些错误。
在第三个驱动程序third_drv.c
里:
添加的头文件:
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <mach/gpio-nrs.h>
#include <plat/gpio-fns.h>
把下面代码
static struct pin_desc pins_desc[4] ={
{S3C2410_GPF0,0x01},
{S3C2410_GPF2,0x02},
{S3C2410_GPG3,0x03},
{S3C2410_GPG11,0x04},
};
改为:
static struct pin_desc pins_desc[4] ={
{S3C2410_GPF(0),0x01},
{S3C2410_GPF(2),0x02},
{S3C2410_GPG(3),0x03},
{S3C2410_GPG(11),0x04},
};
把这个函数
static int third_drv_open (struct inode *inode, struct file *file)
{
request_irq(IRQ_EINT0,buttons_irq,IRQT_BOTHEDGE,"S2",&pins_desc[0]);
request_irq(IRQ_EINT2,buttons_irq,IRQT_BOTHEDGE,"S3",&pins_desc[1]);
request_irq(IRQ_EINT11,buttons_irq,IRQT_BOTHEDGE,"S4",&pins_desc[2]);
request_irq(IRQ_EINT19,buttons_irq,IRQT_BOTHEDGE,"S5",&pins_desc[3]);
return 0;
}
改为:
static int third_drv_open (struct inode *inode, struct file *file)
{
request_irq(IRQ_EINT0,buttons_irq,(IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING ),"S2",&pins_desc[0]);
request_irq(IRQ_EINT2,buttons_irq,(IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING ),"S3",&pins_desc[1]);
request_irq(IRQ_EINT11,buttons_irq,(IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING),"S4",&pins_desc[2]);
request_irq(IRQ_EINT19,buttons_irq,(IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING),"S5",&pins_desc[3]);
return 0;
}
其他出现的错误解决方法与LED驱动程序移植的方法一样。
注:卸载驱动时出现错误:rmmod: chdir(/lib/modules): No such file or directory
解决办法:在/lib/
目录下创建modules
目录:mkdir -p /lib/modules/$(uname -r)
三、LCD驱动移植
1. LCD 驱动移植
同样,在基于linux2.6内核编写的LCD驱动移植到linux3.4.2内核的过程主要是解决编译的错误,解决完错误之后,测试时需要去掉内核自带的LCD驱动程序。
在linux3.4.2内核顶层目录下输入:make menuconfig
依次选择:
Device Drivers --->
Graphics support --->
<*> Support for frame buffer devices --->
<*> S3C2410 LCD framebuffer support
把<*> S3C2410 LCD framebuffer support
改为<M> S3C2410 LCD framebuffer support
然后依次:make uImage
、make modules
把编译好的uImage
改为为uImage_nolcd
拷贝到/home/book/works/first_fs/
目录,并下载到开发板:
nfs 32000000 192.168.2.122:/home/book/works/first_fs/uImage_nolcd
bootm 32000000
mount -t nfs -o nolock,vers=2 192.168.2.122:/home/book/works/first_fs/ /mnt
cd /mnt
insmod lcd_drv.ko
驱动装载成功后,会弹出:Console: switching to colour frame buffer device 60x34
注:韦东山第二期毕业班视频里make modules
,后可以在drivers/video/
目录找到这三个文件:cfbcopyarea.ko
、cfbfillrect.ko
、cfbimgblt.ko
,但是我make modules
后,在drivers/video/
目录只找到了s3c2410fb.ko
,最后装载LCD驱动程序时并没有弹出缺少这个三个函数:cfb_fillrect
、cfb_copyarea
、cfb_imageblit
成功启动内核后,输入命令:echo hello > /dev/tty1
,会在LCD打印hello
字符串。