A20串口驱动分析

串口驱动的整体框架实际上和显示驱动类似

驱动程序是一个字符设备,驱动的实质内容都是在一个平台总线设备驱动程序里


1.  串口驱动的分析,从"drivers/tty/serial/8250/8250.c"开始

     serial8250_init为入口函数,从这个函数一路分析下去,下面列出主要代码

             serial8250_reg.nr = UART_NR;          UART_NR为8,查看datasheet可知A20支持8个uart
             ret = uart_register_driver(&serial8250_reg);


     uart_register_driver在”drivers/tty/serial/serial_core.c“中可以找到

             normal->type  = TTY_DRIVER_TYPE_SERIAL; 

             normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;

             tty_register_driver


    tty_register_driver"drivers/tty/tty_io.c"这个文件中找到如下函数

           alloc_chrdev_region

           register_chrdev_region

           cdev_init

            cdev_add

           if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
                  for (i = 0; i < driver->num; i++) {
                          d = tty_register_device(driver, i, NULL);
                          if (IS_ERR(d)) {
                               error = PTR_ERR(d);
                              goto err;
                          }
                  }
          }

          前四个函数是创建一个字符设备驱动程序的典型函数,后面那段if语句之所以拿出来说一下,是因为

          tty_register_device这个函数是用来创建设备文件的,但是这个if语句是不会执行,因为从上面的分析可 

          知道这个驱动的flags里TTY_DRIVER_DYNAMIC_DEV。那么什么时候创建了设备文件呢。实际上,上面几个文件只是一个框架性的东西。


2.   接下来分析另一路主线

      ”drivers/tty/serial/8250/8250_sunxi.c"

       sw_serial_init

       这里注册了一个平台总线驱动和平台总线设备

             script_get_item(uart_para, "uart_used", &val);

             从配置文件中得到某一个串口是否可用如果可用的话,在调用如下函数

            platform_device_register

            platform_driver_register

           来完成平台总线驱动和平台总线设备的匹配

          分析device和driver 如下

          static struct platform_driver sw_serial_driver = {
                   .probe      = sw_serial_probe,
                   .remove     = sw_serial_remove,
                   .suspend    = sw_serial_suspend,
                   .resume     = sw_serial_resume,
                   .driver     = {
                            .name   = "sunxi-uart",
                            .owner  = THIS_MODULE,
                   },
          };

        struct platform_device sw_uart_dev[] = {
    [0] = {.name = "sunxi-uart", .id = 0, .num_resources = ARRAY_SIZE(sw_uart_res[0]), .resource = &sw_uart_res[0][0], .dev.release = sunxi_serial_release},
    [1] = {.name = "sunxi-uart", .id = 1, .num_resources = ARRAY_SIZE(sw_uart_res[1]), .resource = &sw_uart_res[1][0], .dev.release = sunxi_serial_release},
    [2] = {.name = "sunxi-uart", .id = 2, .num_resources = ARRAY_SIZE(sw_uart_res[2]), .resource = &sw_uart_res[2][0], .dev.release = sunxi_serial_release},
    [3] = {.name = "sunxi-uart", .id = 3, .num_resources = ARRAY_SIZE(sw_uart_res[3]), .resource = &sw_uart_res[3][0], .dev.release = sunxi_serial_release},
    [4] = {.name = "sunxi-uart", .id = 4, .num_resources = ARRAY_SIZE(sw_uart_res[4]), .resource = &sw_uart_res[4][0], .dev.release = sunxi_serial_release},
    [5] = {.name = "sunxi-uart", .id = 5, .num_resources = ARRAY_SIZE(sw_uart_res[5]), .resource = &sw_uart_res[5][0], .dev.release = sunxi_serial_release},
    [6] = {.name = "sunxi-uart", .id = 6, .num_resources = ARRAY_SIZE(sw_uart_res[6]), .resource = &sw_uart_res[6][0], .dev.release = sunxi_serial_release},
    [7] = {.name = "sunxi-uart", .id = 7, .num_resources = ARRAY_SIZE(sw_uart_res[7]), .resource = &sw_uart_res[7][0], .dev.release = sunxi_serial_release},
};

        从上面两个结构体可以看出,8个平台总线设备匹配了1个平台总线驱动。

       那么接下来我们看看平台总线驱动的probe函数实现了什么。

3. sw_serial_probe函数分析

              sw_serial_get_config这个函数从配置文件中得到type和port两个参数,type应该是管脚数目,比如基本的串口使用了tx,rx,那个type就是2,加两个流控,type就是4,全串口type就是8.

          sw_serial_get_resource这个函数,从配置文件中得到管脚的定义,并从平台设备的resources中得到,内存和中断资源。

          serial8250_register_port      serial8250_register_port定义8250.c中

          uart_add_one_port   定义在serial_core.c中

          tty_register_device  定义在tty_io.c中

          下面主要分析这个函数

4. struct device *tty_register_device(struct tty_driver *driver, unsigned index,
                   struct device *device)
    {
         char name[64];

         这句构造主次设备号

         dev_t dev = MKDEV(driver->major, driver->minor_start) + index;

        
          if (index >= driver->num) {
                printk(KERN_ERR "Attempt to register invalid tty line number "
                       " (%d).\n", index);
                 return ERR_PTR(-EINVAL);
         }

         if (driver->type == TTY_DRIVER_TYPE_PTY)
                  pty_line_name(driver, index, name);
         else

                  这句构造串口设备文件

                  tty_line_name(driver, index, name);

           这句用name来创建一个设备文件
          return device_create(tty_class, device, dev, NULL, name);
   }

     最终在这里创建了串口的设备文件,实际这个串口真正硬件资源相关的东西都是在这个平台总线设备和平台总线驱动里来管理的。

     最上面的那个串口字符设备驱动只是一个框架性的东西。实际和显示驱动类似,2.6内核以后的很多驱动程序都是这种分层的方式,用平台总线驱动程序来实现。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值