Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3167959
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: 嵌入式

2014-12-19 12:52:08

原文地址:http://xl028.blog.163.com/blog/static/199730242201232610336687/

分析串口的平台设备注册

 这里直接从这里开始分析//arch/arm/mach-s3c2440/mach-mini2440.c

static void __init mini2440_map_io(void)//mini2440_map_io 的定义以及在系统启动过程中是怎么被调用的可以查看 内核时钟部分的分析
{
 s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc));
 s3c24xx_init_clocks(12000000);
 s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartcfgs));
}
参数定义
static struct s3c2410_uartcfg mini2440_uartcfgs[] __initdata = {
 [0] = {
  .hwport      = 0,
  .flags      = 0,
  .ucon      = 0x3c5,
  .ulcon      = 0x03,//一般串口
  .ufcon      = 0x51,
 },
 [1] = {
  .hwport      = 1,
  .flags      = 0,
  .ucon      = 0x3c5,
  .ulcon      = 0x03,
  .ufcon      = 0x51,
 },
 /* IR port */
 [2] = {
  .hwport      = 2,
  .flags      = 0,
  .ucon      = 0x3c5,
  .ulcon      = 0x43,//红外方式
  .ufcon      = 0x51,
 }
};
接着分析s3c24xx_init_uarts函数的具体执行
void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
{
 if (cpu == NULL)
  return;

 

 if (cpu->init_uarts == NULL) {
  printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");
 } else
  (cpu->init_uarts)(cfg, no);//这里就是调用cpu_table中init_uarts函数指针
}

cpu_table是一个很重要的数据结构,系统初始化过程中很多地方都要用到,其定义如下:
struct cpu_table {
 unsigned long idcode;
 unsigned long idmask;
 void  (*map_io)(void);
 void  (*init_uarts)(struct s3c2410_uartcfg *cfg, int no);  void  (*init_clocks)(int xtal);
 int  (*init)(void);
 const char *name;
};

我们继续分析cpu->init_uarts 函数指针具体是调用的哪个函数,这就要去看cpu_table这个全局结构体的定义了:
static struct cpu_table cpu_ids[] __initdata = {
 {
  .idcode  = 0x32410000,
  .idmask  = 0xffffffff,
  .map_io  = s3c2410_map_io,
  .init_clocks = s3c2410_init_clocks,
  .init_uarts = s3c2410_init_uarts,
  .init  = s3c2410_init,
  .name  = name_s3c2410
 },
 {
  .idcode  = 0x32410002,
  .idmask  = 0xffffffff,
  .map_io  = s3c2410_map_io,
  .init_clocks = s3c2410_init_clocks,
  .init_uarts = s3c2410_init_uarts,
  .init  = s3c2410a_init,
  .name  = name_s3c2410a
 },
 {
  .idcode  = 0x32440000,
  .idmask  = 0xffffffff,
  .map_io  = s3c244x_map_io,
  .init_clocks = s3c244x_init_clocks,
  .init_uarts = s3c244x_init_uarts,   //好在这里我们终于找到了具体函数的形式,接着我们对其进行剖析   .init  = s3c2440_init,
  .name  = name_s3c2440
 },
 {
  .idcode  = 0x32440001,
  .idmask  = 0xffffffff,
  .map_io  = s3c244x_map_io,
  .init_clocks = s3c244x_init_clocks,
  .init_uarts = s3c244x_init_uarts,
  .init  = s3c2440_init,
  .name  = name_s3c2440a
 },
 {
  .idcode  = 0x32440aaa,
  .idmask  = 0xffffffff,
  .map_io  = s3c244x_map_io,
  .init_clocks = s3c244x_init_clocks,
  .init_uarts = s3c244x_init_uarts,
  .init  = s3c2442_init,
  .name  = name_s3c2442
 },
 {
  .idcode  = 0x32440aab,
  .idmask  = 0xffffffff,
  .map_io  = s3c244x_map_io,
  .init_clocks = s3c244x_init_clocks,
  .init_uarts = s3c244x_init_uarts,
  .init  = s3c2442_init,
  .name  = name_s3c2442b
 },
 {
  .idcode  = 0x32412001,
  .idmask  = 0xffffffff,
  .map_io  = s3c2412_map_io,
  .init_clocks = s3c2412_init_clocks,
  .init_uarts = s3c2412_init_uarts,
  .init  = s3c2412_init,
  .name  = name_s3c2412,
 },
 {   /* a newer version of the s3c2412 */
  .idcode  = 0x32412003,
  .idmask  = 0xffffffff,
  .map_io  = s3c2412_map_io,
  .init_clocks = s3c2412_init_clocks,
  .init_uarts = s3c2412_init_uarts,
  .init  = s3c2412_init,
  .name  = name_s3c2412,
 },
 {
  .idcode  = 0x32443001,
  .idmask  = 0xffffffff,
  .map_io  = s3c2443_map_io,
  .init_clocks = s3c2443_init_clocks,
  .init_uarts = s3c2443_init_uarts,
  .init  = s3c2443_init,
  .name  = name_s3c2443,
 },
 {
  .idcode  = 0x0,   /* S3C2400 doesn't have an idcode */
  .idmask  = 0xffffffff,
  .map_io  = s3c2400_map_io,
  .init_clocks = s3c2400_init_clocks,
  .init_uarts = s3c2400_init_uarts,
  .init  = s3c2400_init,
  .name  = name_s3c2400
 },
};
void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)  //arch/arm/plat-s3c24xx/s3c244x.c
{
 s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no); //串口设备初始化
}
这里分析s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);参数
第一传入platform_device名字则不用说;
第二个s3c2410_uart_resources参数,是怎么定义的呢?
/* Serial port registrations */
static struct resource s3c2410_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,
 }
};

static struct resource s3c2410_uart1_resource[] = {
 [0] = {
  .start = S3C2410_PA_UART1,
  .end   = S3C2410_PA_UART1 + 0x3fff,
  .flags = IORESOURCE_MEM,
 },
 [1] = {
  .start = IRQ_S3CUART_RX1,
  .end   = IRQ_S3CUART_ERR1,
  .flags = IORESOURCE_IRQ,
 }
};

static struct resource s3c2410_uart2_resource[] = {
 [0] = {
  .start = S3C2410_PA_UART2,
  .end   = S3C2410_PA_UART2 + 0x3fff,
  .flags = IORESOURCE_MEM,
 },
 [1] = {
  .start = IRQ_S3CUART_RX2,
  .end   = IRQ_S3CUART_ERR2,
  .flags = IORESOURCE_IRQ,
 }
};

static struct resource s3c2410_uart3_resource[] = {
 [0] = {
  .start = S3C2443_PA_UART3,
  .end   = S3C2443_PA_UART3 + 0x3fff,
  .flags = IORESOURCE_MEM,
 },
 [1] = {
  .start = IRQ_S3CUART_RX3,
  .end   = IRQ_S3CUART_ERR3,
  .flags = IORESOURCE_IRQ,
 },
};

struct s3c24xx_uart_resources s3c2410_uart_resources[] __initdata = { //arch/arm/plat-s3c24xx/devs.c
 [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),
 },
};

/* yart devices */

static struct platform_device s3c24xx_uart_device0 = {
 .id  = 0,
};

static struct platform_device s3c24xx_uart_device1 = {
 .id  = 1,
};

static struct platform_device s3c24xx_uart_device2 = {
 .id  = 2,
};

static struct platform_device s3c24xx_uart_device3 = {
 .id  = 3,
};

struct platform_device *s3c24xx_uart_src[4] = {   //平台设备指针数组
 &s3c24xx_uart_device0,  //
 &s3c24xx_uart_device1,
 &s3c24xx_uart_device2,
 &s3c24xx_uart_device3,
};

struct platform_device *s3c24xx_uart_devs[4] = {
};

第三个参数cfg,可见最上面的分析,即为struct s3c2410_uartcfg mini2440_uartcfgs
接着分析s3c24xx_init_uartdevs平台设备的初始化过程
void __init s3c24xx_init_uartdevs(char *name,
      struct s3c24xx_uart_resources *res,
      struct s3c2410_uartcfg *cfg, int no)
{
 struct platform_device *platdev;
 struct s3c2410_uartcfg *cfgptr = uart_cfgs;
 struct s3c24xx_uart_resources *resp;
 int uart;
/*将arch/arm/mach-s3c2440/mach-mini2440.c下的mini2440_uartcfgs
拷入cfgptr指针,亦即装入uart_cfgs全局变量
*/
 memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);

 

 for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
  platdev = s3c24xx_uart_src[cfgptr->hwport];//取出已定义的platform_device指针

  resp = res + cfgptr->hwport; //取出各设备相关的设备资源数组

  s3c24xx_uart_devs[uart] = platdev; //最后再存入已定义好的设备指针数组

  platdev->name = name;
  platdev->resource = resp->resources;
  platdev->num_resources = resp->nr_resources;

  platdev->dev.platform_data = cfgptr;  //将配置信息存入平台结构中,驱动的probe函数中要用到
 }

 nr_uarts = no;
}

以上部分为平台设备的定义及初始化的坎坷过程

下面接着分析,平台设备的真正注册流程:
static int __init s3c_arch_init(void)
{
 int ret;
 // do the correct init for cpu
 if (cpu == NULL)
  panic("s3c_arch_init: NULL cpu\n");
 ret = (cpu->init)();
 if (ret != 0)
  return ret;
 ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts); //在此处进行注册  return ret;
}
从这里开始我们再分析s3c_arch_init函数又是如何被调用的呢,搜遍Source Insight只找到arch_initcall(s3c_arch_init);
这里的arch_initcall是一个宏定义

该宏定义位于..\include\linux\init.h,原型为:

#define arch_initcall(fn)  __define_initcall("3",fn,3)

 

而宏定义__define_initcall也位于该文件中,原型为:

#define __define_initcall(level,fn,id) \  static initcall_t __initcall_##fn##id __used \  __attribute__((__section__(".initcall" level ".init"))) = fn

可见这个宏定义是在函数前面和后面加上一定的前缀和后缀,并指定属性,最终是通过调用do_initcalls函数来按顺序执行。
static void __init do_initcalls(void)   //init/main.c
{
 initcall_t *call;

 

 for (call = __early_initcall_end; call < __initcall_end; call++)
  do_one_initcall(*call);

 /* Make sure there is no pending stuff from the initcall sequence */
 flush_scheduled_work();
}
执行顺序是什么呢?原来是按Systems.map中映射顺序执行。

串口驱动之平台设备的注册过程 - 直到永远 - 直到永远的博客

阅读(851) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~