RD之家欢迎你,立即注册 登录
RD之家 返回首页

jason_t的个人空间 https://www.rdzhijia.com/?13009 [收藏] [复制] [分享] [RSS]

日志

[转载]基于Linux2.6.22和s3c2440的串口驱动简析---(1)

已有 419 次阅读2018-8-2 19:21 |系统分类:Linux| Linux, 串口, 驱动, UART, tty

Linux的终端设备这一块,涉及的面还是比较多的。经过几天的分析,有点收获,就写出来和大家分享分享,如果有不对的地方,还希望大家提出来。

s3c2440
的串口驱动部分,分为platform/tty/console三部分。




既然是分析s3c2440uart部分那么第一个该看的就是drivers\serial\s3c2410.c文件。在此文件中,可以找到下面的代码:

  1. module_init(s3c24xx_serial_modinit);
  2. module_exit(s3c24xx_serial_modexit);

通过上面的两句代码,就很明确的告诉我们,首先需要关注的函数就是:s3c24xx_serial_modinit
  1. static int __init s3c24xx_serial_modinit(void)
  2. {
  3.     int ret;

  4.     ret = uart_register_driver(&s3c24xx_uart_drv);
  5.     if (ret < 0) {
  6.         printk(KERN_ERR "failed to register UART driver\n");
  7.         return -1;
  8.     }

  9.     s3c2400_serial_init(); //不需要关注
  10.     s3c2410_serial_init(); //不需要关注
  11.     s3c2412_serial_init(); //不需要关注
  12.     s3c2440_serial_init();

  13.     return 0;
  14. }

既然分为三部分,那么这次就只说一部分,那就是platform这一部分,通过前面博文中对platform的分析,可知,会有platform_driverplatform_device两个结构体会被定义。那么就让我们把他们找出来:

platform_driver部分:

通过分析s3c24xx_serial_modinit
函数,会发现如下的调用关系:

  1. s3c2410_serial_init
  2.         s3c24xx_serial_init(&s3c2410_serial_drv, &s3c2410_uart_inf);
  3.                 platform_driver_register(drv);
  4.                         driver_register(&drv->driver);
  5.                                 bus_add_driver(drv);
  6.                                         driver_attach(drv);
  7.                                                 bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
  8.                                                         fn(dev, data); ---> __driver_attach(dev, data);
  9.                                                                 driver_probe_device(drv, dev);
  10.                                                                         drv->bus->match(dev, drv) ---> platform_match
  11.                                                                                 (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0)
  12.                                                                         really_probe(dev, drv);

也就是说,s3c24xx_serial_modinits3c2410_serial_drv这个实例化的platform_driver结构体注册到了platform总线上。

  1. static struct platform_driver s3c2440_serial_drv = {
  2.     .probe        = s3c2440_serial_probe,
  3.     .remove        = s3c24xx_serial_remove,
  4.     .suspend    = s3c24xx_serial_suspend,
  5.     .resume        = s3c24xx_serial_resume,
  6.     .driver        = {
  7.         .name    = "s3c2440-uart",
  8.         .owner    = THIS_MODULE,
  9.     },
  10. };


platform_driver部分:

platform_driver,自然就有platform_device。我们可以arch\arm\plat-s3c24xx\Cpu.c文件中,找到如下函数:

  1.   
  2.   static int __init s3c_arch_init(void)
  3.   {
  4.       int ret;
  5.   
  6.       // do the correct init for cpu
  7.   
  8.       if (cpu == NULL)
  9.           panic("s3c_arch_init: NULL cpu\n");
  10.   
  11.       ret = (cpu->init)();
  12.       if (ret != 0)
  13.           return ret;
  14.   
  15.       ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);
  16.       return ret;
  17.   }
  18.   
  19.   arch_initcall(s3c_arch_init);

在查找s3c24xx_uart_devs这个东东时,发现arch\arm\plat-s3c24xx\Devs.c中有如下定义

  1. struct platform_device *s3c24xx_uart_devs[3] = {
  2. };

也就是它默认定义为指向platform_device的指针数组,那细想,自然会有地方会对其进行赋值。s3c24xx_uart_devs赋值的地方又在什么地方呢??在源码中搜索,会发下函数:
  1.   void __init s3c24xx_init_uartdevs(char *name,
  2.                    struct s3c24xx_uart_resources *res,
  3.                    struct s3c2410_uartcfg *cfg, int no)
  4.   {
  5.       struct platform_device *platdev;
  6.       struct s3c2410_uartcfg *cfgptr = uart_cfgs;
  7.       struct s3c24xx_uart_resources *resp;
  8.       int uart;
  9.   
  10.       memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);
  11.   
  12.       for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
  13.           platdev = s3c24xx_uart_src[cfgptr->hwport];
  14.   
  15.           resp = res + cfgptr->hwport;
  16.   
  17.           s3c24xx_uart_devs[uart] = platdev; //给s3c24xx_uart_devs进行赋值
  18.   
  19.           platdev->name = name;
  20.           platdev->resource = resp->resources;
  21.           platdev->num_resources = resp->nr_resources;
  22.   
  23.           platdev->dev.platform_data = cfgptr;
  24.       }
  25.   
  26.       nr_uarts = no; //给nr_uarts进行赋值
  27.   }

那么s3c24xx_init_uartdevs又是在什么地方被调用的呢?其调用关系如下:

  1.   smdk2440_map_io
  2.           s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
  3.                   cpu = s3c_lookup_cpu(idcode);
  4.                           tab = cpu_ids;
  5.                               for (count = 0; count < ARRAY_SIZE(cpu_ids); count++, tab++) {
  6.                                   if ((idcode & tab->idmask) == tab->idcode)
  7.                                       return tab;
  8.                               }
  9.                   (cpu->map_io)(mach_desc, size); ---> s3c244x_map_io
  10.           s3c24xx_init_clocks(12000000);
  11.           s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
  12.                   (cpu->init_uarts)(cfg, no); ---> s3c244x_init_uarts
  13.                           s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no); //初始化struct platform_device *s3c24xx_uart_devs[3]

smdk2440_map_io则是在内核启动的第二阶段被调用的:
  1.   start_kernel
  2.           setup_arch(&command_line);
  3.                   mdesc = setup_machine(machine_arch_type);
  4.                           lookup_machine_type(nr);
  5.                   machine_name = mdesc->name;
  6.                   paging_init(&meminfo, mdesc);
  7.                           devicemaps_init(mdesc);
  8.                                   mdesc->map_io();
  9.                   init_arch_irq = mdesc->init_irq;
  10.                   system_timer = mdesc->timer;
  11.                   init_machine = mdesc->init_machine;
  12.   
  13.                   
  14.   MACHINE_START(S3C2440, "SMDK2440")
  15.       /* Maintainer: Ben Dooks <ben@fluff.org> */
  16.       .phys_io    = S3C2410_PA_UART,
  17.       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
  18.       .boot_params    = S3C2410_SDRAM_PA + 0x100,
  19.   
  20.       .init_irq    = s3c24xx_init_irq,
  21.       .map_io        = smdk2440_map_io,
  22.       .init_machine    = smdk2440_machine_init,
  23.       .timer        = &s3c24xx_timer,
  24.   MACHINE_END

到此,s3c2440的串口的platform部分就说完了,系统在注册s3c24xx_init_uartdevs,又注册了s3c2410_serial_drv,之后就会自动调用s3c2440_serial_probe,其作用将在 基于Linux2.6.22和s3c2440的串口驱动简析---(2)中进行分析。

转载自http://blog.chinaunix.net/uid-27041925-id-3999810.html

路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | RD之家欢迎你,立即注册

QQ|Archiver|手机版|小黑屋|RD之家 - 研发工程师的伊甸园 ( 京ICP备18037383号 )
360导航 360安全浏览器 蚂蚁搜索 速搜全球 酷帝网站目录 搜狗导航 114啦网址导航

GMT+8, 2018-9-22 09:17

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

返回顶部