这几天移植在linux内核下调试16C554,扩展四串口驱动,用的是linux内核自带的8250.c驱动。
(1)8250.c内自带serial8250_init(),它在内核初始化时完成驱动的注册,所以我们需要添加的是设备资源。
(2)在arch/arm/mach-s3c2410/mach-smdk2410.c中添加四串口设备:
static struct plat_serial8250_port my2410_st16c554_8250_data[] = {
{ //ARM体系结构中将IO和MEMORY统一编址,
//因此这里使用的是Memory地址
.mapbase = (unsigned long)S3C2410_CS1 + 0x0FC0,
.irq = IRQ_EINT2,
.uartclk = 1843200,
.iotype = UPIO_MEM32,
.flags = (UPF_BOOT_AUTOCONF | UPF_IOREMAP),
.regshift = 0,
},
//PORT(S3C2410_CS1 + 0x0, IRQ_EINT0),
{ //ARM体系结构中将IO和MEMORY统一编址,
//因此这里使用的是Memory地址
.mapbase = (unsigned long)S3C2410_CS1 + 0x0FA0,
.irq = IRQ_EINT8,
.uartclk = 1843200,
.iotype = UPIO_MEM32,
.flags = (UPF_BOOT_AUTOCONF | UPF_IOREMAP),
.regshift = 0,
},
//PORT(S3C2410_CS2 + 0x0, IRQ_EINT1),
{ //ARM体系结构中将IO和MEMORY统一编址,
//因此这里使用的是Memory地址
.mapbase = (unsigned long)S3C2410_CS1 + 0x0F60,
.irq = IRQ_EINT11,
.uartclk = 1843200,
.iotype = UPIO_MEM32,
.flags = (UPF_BOOT_AUTOCONF | UPF_IOREMAP),
.regshift = 0,
},
//PORT(S3C2410_CS3 + 0x0, IRQ_EINT2),
{ //ARM体系结构中将IO和MEMORY统一编址,
//因此这里使用的是Memory地址
.mapbase = (unsigned long)S3C2410_CS1 + 0x0EE0,
.irq = IRQ_EINT19,
.uartclk = 1843200,
.iotype = UPIO_MEM32,
.flags = (UPF_BOOT_AUTOCONF | UPF_IOREMAP),
.regshift = 0,
},
//PORT(S3C2410_CS5 + 0x0, IRQ_EINT3),
{ },
};
static struct platform_device my2410_device_st16c554 = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM,
.dev = {
.platform_data = &my2410_st16c554_8250_data,
},
};
然后在smdk2410_devices中添加上面定义的设备。
static struct platform_device *smdk2410_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
&s3c_device_nand,
&my2410_device_st16c554,
};
(3)下面就要修改8250.c
首先在serial8250_init()中,serial8250_isa_devs = platform_device_register_simple("serial8250",PLAT8250_DEV_PLATFORM, NULL, 0)这个函数有点诡异,我起先对它没有修改,但是内核启动之后设备总是注册不成功,找了找原因,实在不知道其中的PLAT8250_DEV_PLATFORM是什么意思,故把它改成-1,再次启动内核,貌似有了点进展。
但是在内核启动的过程中,总是停止在serial8250_config_port()中autoconfig()中的serial_in()中,找到源代码查看,发现serial_in()中的readl()出了问题。readl()是访问内存空间虚拟地址的一个函数,在调用它之前必须将I/O空间映射到虚拟内存空间,所以估计是没有映射。
找到:
static int serial8250_request_std_resource(struct uart_8250_port *up)
{
unsigned int size = 8 << up->port.regshift;
int ret = 0;
printk("the port's size is %d",size);
switch (up->port.iotype) {
case UPIO_MEM:
if (!up->port.mapbase)
break;
if (!request_mem_region(up->port.mapbase, size, "serial")) {
ret = -EBUSY;
break;
}
if (up->port.flags & UPF_IOREMAP) {
up->port.membase = ioremap(up->port.mapbase, size);
if (!up->port.membase) {
release_mem_region(up->port.mapbase, size);
ret = -ENOMEM;
}
}
break;
case UPIO_HUB6:
case UPIO_PORT:
if (!request_region(up->port.iobase, size, "serial"))
ret = -EBUSY;
break;
}
return ret;
}
发现里面的iotype没有我们想要的UPIO_MEM32,所以没有进行request_mem_region和ioremap,故将UPIO_MEM改为UPIO_MEM32。
再次编译,启动,可以注册了,下一步就要进行测试。