====本文系本站原创,欢迎转载! 转载请注明出处:http://blog.youkuaiyun.com/yyplc====
从上面四篇介绍文章中,已经清楚了串口设备与串口驱动实现的各层次关系流程。是一种从上而下的关系,从第二篇的层次流程图中可以看出。之前说过串口设备是一种platform device,下面看看串口作为platform device的实现细节。
串口的硬件平台实现smdk2440_map_io()初始化入口:
static void __init smdk2440_map_io(void)
{
s3c24xx_init_io(smdk2440_iodesc,ARRAY_SIZE(smdk2440_iodesc));
s3c24xx_init_clocks(12000000);
s3c24xx_init_uarts(smdk2440_uartcfgs,ARRAY_SIZE(smdk2440_uartcfgs)); //串口初始化
}
s3c24xx_init_uarts()初始化串口, 主要完成platform device结构相关参数的赋值,如IO,中断,以及platform device私有数据赋值等。
串口platform_device结构:
static struct platform_device s3c24xx_uart_device0= {
.id = 0, // ID号
};
static struct platform_devices3c24xx_uart_device1 = {
.id = 1,
};
static struct platform_devices3c24xx_uart_device2 = {
.id = 2,
};
要完成platform_device参数初始化,主要涉及到一下数据结构:
串口配置数据结构:
static struct s3c2410_uartcfgtq2440_uartcfgs[] __initdata = {
[0]= {
.hwport =0,
.flags = 0,
.ucon = 0x3c5, // rx,tx采用中断方式
.ulcon = 0x03, //数据长度设置为8-bits
.ufcon = 0x51, //开启FIFO,并设置rx,tx触发字节数
},
[1]= {
.hwport =1,
.flags = 0,
.ucon = 0x3c5,
.ulcon = 0x03,
.ufcon = 0x51,
},
[2]= {
.hwport =2,
.flags = 0,
.ucon = 0x3c5,
.ulcon = 0x03,
.ufcon = 0x51,
}
};
串口资源:
static struct resources3c2410_uart0_resource[] = {
[0]= {
.start= S3C2410_PA_UART0,
.end = S3C2410_PA_UART0 + 0x3fff,
.flags= IORESOURCE_MEM,
},
[1]= {
.start= IRQ_S3CUART_RX0,
.end = IRQ_S3CUART_ERR0,
.flags= IORESOURCE_IRQ,
}
};
struct s3c24xx_uart_resourcess3c2410_uart_resources[] __initdata = {
[0]= {
.resources = s3c2410_uart0_resource,
.nr_resources = ARRAY_SIZE(s3c2410_uart0_resource),
},
[1]= {
.resources = s3c2410_uart1_resource,
.nr_resources = ARRAY_SIZE(s3c2410_uart1_resource),
},
[2]= {
.resources = s3c2410_uart2_resource,
.nr_resources = ARRAY_SIZE(s3c2410_uart2_resource),
},
[3]= {
.resources = s3c2410_uart3_resource,
.nr_resources = ARRAY_SIZE(s3c2410_uart3_resource),
},
};
最后通过函数s3c24xx_init_uartdevs()完成 串口platform_device的初始化:
void __init s3c24xx_init_uartdevs(char*name,
struct s3c24xx_uart_resources *res,
struct s3c2410_uartcfg *cfg, int no)
{//name = s3c2440-uart, res =s3c2410_uart_resources[], cfg = tq2440_uartcfgs, no = 3
structplatform_device *platdev;
structs3c2410_uartcfg *cfgptr = uart_cfgs;
structs3c24xx_uart_resources *resp;
intuart;
memcpy(cfgptr,cfg, sizeof(struct s3c2410_uartcfg) * no);
for(uart = 0; uart < no; uart++, cfg++, cfgptr++) {
platdev= s3c24xx_uart_src[cfgptr->hwport]; //platdev = s3c24xx_uart_device0
resp= res + cfgptr->hwport; //resp =s3c2410_uart_resources[] + tq2440_uartcfgs.hwport
s3c24xx_uart_devs[uart]= platdev; //
platdev->name= name;
platdev->resource= resp->resources;
platdev->num_resources= resp->nr_resources;
platdev->dev.platform_data= cfgptr;//plat_form_data = cfgptr = tq2440_uartcfgs
}
nr_uarts= no;
}
最终在platform_add_device()中完成注册
platform_add_devices(s3c24xx_uart_devs,nr_uarts);
int platform_add_devices(structplatform_device **devs, int num)
{
inti, ret = 0;
for(i = 0; i < num; i++) {
ret= platform_device_register(devs[i]);
if(ret) {
while(--i >= 0)
platform_device_unregister(devs[i]);
break;
}
}
return ret;
}