Linux串口驱动分析初始化

来源:互联网 发布:剑三军爷男神捏脸数据 编辑:程序博客网 时间:2024/05/29 09:11
  1. 代码来自:http://blog.csdn.net/longwang155069/article/details/42712551

  2. * uart分析 
  3.  * 
  4.  * 其实串口分析就两个重要的文件: S3c2440.c  Samsung.c 
  5.  * 
  6.  * **/  
  7.   
  8.   
  9. /*1. 首先从Samsung.c的模块初始化函数看起*/  
  10.   
  11. static int __init s3c24xx_serial_modinit(void)  
  12. {  
  13.     int ret;  
  14.   
  15.     ret = uart_register_driver(&s3c24xx_uart_drv);  
  16.     if (ret < 0) {  
  17.         printk(KERN_ERR "failed to register UART driver\n");  
  18.         return -1;  
  19.     }  
  20.   
  21.     return 0;  
  22. }  
  23.   
  24.   
  25. /*参数是需要程序员自己定义 */  
  26. /** s3c2440.c **/  
  27.   
  28. static struct s3c24xx_uart_info s3c2440_uart_inf = {  
  29.     .name       = "Samsung S3C2440 UART",  
  30.     .type       = PORT_S3C2440,             //端口类型  
  31.     .fifosize   = 64,                       //FIFO缓冲区大小  
  32.     .rx_fifomask    = S3C2440_UFSTAT_RXMASK,          
  33.     .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,  
  34.     .rx_fifofull    = S3C2440_UFSTAT_RXFULL,  
  35.     .tx_fifofull    = S3C2440_UFSTAT_TXFULL,  
  36.     .tx_fifomask    = S3C2440_UFSTAT_TXMASK,  
  37.     .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,  
  38.     .get_clksrc = s3c2440_serial_getsource,  
  39.     .set_clksrc = s3c2440_serial_setsource,  
  40.     .reset_port = s3c2440_serial_resetport,  
  41. };  
  42.   
  43. /*platform 驱动定义: s3c2440_serial_driver*/  
  44. static struct platform_driver s3c2440_serial_driver = {  
  45.     .probe      = s3c2440_serial_probe,             //匹配后设备调用  
  46.     .remove     = __devexit_p(s3c24xx_serial_remove),  
  47.     .driver     = {  
  48.         .name   = "s3c2440-uart",       //驱动的名字  
  49.         .owner  = THIS_MODULE,  
  50.     },  
  51. };  
  52.   
  53.   
  54. /*分析uart_register_driver函数*/  
  55. /* 这个函数的主要作用是初始化tty_driver结构体。 其实tty_driver的主要成员都是通过传进来的参数drv赋值的 
  56.  * 其次是初始化uart_driver中的uart_state成员。 
  57.  *  
  58.  * uart_state是一个结构体包含了tty_port和uart_port。 而uart_port主要是和硬件相关。 其实每一个串口都对应一个uart_port结构 
  59.  * 这里只初始化了tty_port结构。而uart_port是在等设备匹配上后在设备的ops中的probe函数中初始化 
  60.  */  
  61. int uart_register_driver(struct uart_driver *drv)  
  62. {  
  63.     /* 
  64.      * Maybe we should be using a slab cache for this, especially if 
  65.      * we have a large number of ports to handle. 
  66.      */  
  67.     drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);  
  68.     if (!drv->state)  
  69.         goto out;  
  70.   
  71.     normal = alloc_tty_driver(drv->nr);  
  72.     if (!normal)  
  73.         goto out_kfree;  
  74.   
  75.     drv->tty_driver = normal;  
  76.   
  77.     normal->owner        = drv->owner;  
  78.     normal->driver_name  = drv->driver_name;  
  79.     normal->name     = drv->dev_name;  
  80.     normal->major        = drv->major;  
  81.     normal->minor_start  = drv->minor;  
  82.     normal->type     = TTY_DRIVER_TYPE_SERIAL;  
  83.     normal->subtype      = SERIAL_TYPE_NORMAL;  
  84.     normal->init_termios = tty_std_termios;  
  85.     normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;  
  86.     normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;  
  87.     normal->flags        = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;  
  88.     normal->driver_state    = drv;  
  89.     tty_set_operations(normal, &uart_ops);  
  90.   
  91.     /* 
  92.      * Initialise the UART state(s). 
  93.      */  
  94.     for (i = 0; i < drv->nr; i++) {  
  95.         struct uart_state *state = drv->state + i;  
  96.         struct tty_port *port = &state->port;  
  97.   
  98.         tty_port_init(port);  
  99.         port->ops = &uart_port_ops;  
  100.         port->close_delay     = 500; /* .5 seconds */  
  101.         port->closing_wait    = 30000;   /* 30 seconds */  
  102.         tasklet_init(&state->tlet, uart_tasklet_action,  
  103.                  (unsigned long)state);  
  104.     }  
  105.   
  106.     retval = tty_register_driver(normal);  
  107. }  
  108.   
  109.   
  110. /* 当设备与驱动匹配后,会调用此函数。 
  111.  * 
  112.  *  probe函数一般就是做的硬件相关的初始化。 
  113.  *   
  114.  *  其实uart_port的初始化也是通过s3c24xx_uart_port来初始化的。 
  115.  * */  
  116. int s3c24xx_serial_probe(struct platform_device *dev,  
  117.              struct s3c24xx_uart_info *info)  
  118. {  
  119.     struct s3c24xx_uart_port *ourport;  
  120.     int ret;  
  121.   
  122.     dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);  
  123.   
  124.     /*取得相应的端口*/  
  125.     ourport = &s3c24xx_serial_ports[probe_index];  
  126.     probe_index++;  
  127.   
  128.     dbg("%s: initialising port %p...\n", __func__, ourport);  
  129.   
  130.     /*初始化端口*/  
  131.     ret = s3c24xx_serial_init_port(ourport, info, dev);  
  132.     if (ret < 0)  
  133.         goto probe_err;  
  134.   
  135.     dbg("%s: adding port\n", __func__);  
  136.   
  137.     /*这个函数的主要作用是: 将uart_port和uart_driver关联起来*/  
  138.   
  139.     uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);  
  140.     platform_set_drvdata(dev, &ourport->port);  
  141.   
  142.     ret = device_create_file(&dev->dev, &dev_attr_clock_source);  
  143.     if (ret < 0)  
  144.         printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);  
  145.   
  146.     ret = s3c24xx_serial_cpufreq_register(ourport);  
  147.     if (ret < 0)  
  148.         dev_err(&dev->dev, "failed to add cpufreq notifier\n");  
  149.   
  150.     return 0;  
  151.   
  152.  probe_err:  
  153.     return ret;  
  154. }  
  155. /* 
  156.  * 端口初始化函数 
  157.  * */  
  158. static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,  
  159.                     struct s3c24xx_uart_info *info,  
  160.                     struct platform_device *platdev)  
  161. {  
  162.     struct uart_port *port = &ourport->port;  
  163.     struct s3c2410_uartcfg *cfg;  
  164.     struct resource *res;  
  165.     int ret;  
  166.   
  167.     dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);  
  168.   
  169.     if (platdev == NULL)  
  170.         return -ENODEV;  
  171.   
  172.     /*获取设备的资源,详细解析见下面*/  
  173.     cfg = s3c24xx_dev_to_cfg(&platdev->dev);  
  174.   
  175.     if (port->mapbase != 0)  
  176.         return 0;  
  177.   
  178.     /*判断是否大于总数4个*/  
  179.     if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {  
  180.         printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,  
  181.                cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);  
  182.         return -ERANGE;  
  183.     }  
  184.   
  185.     port->dev    = &platdev->dev;  
  186.     ourport->info    = info;  
  187.   
  188.     /*初始化port的大小 = 64*/  
  189.     ourport->port.fifosize = info->fifosize;  
  190.   
  191.     dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);  
  192.   
  193.     port->uartclk = 1;  
  194.   
  195.     /*判断是否开启流控*/  
  196.     if (cfg->uart_flags & UPF_CONS_FLOW) {  
  197.         dbg("s3c24xx_serial_init_port: enabling flow control\n");  
  198.         port->flags |= UPF_CONS_FLOW;  
  199.     }  
  200.   
  201.     /*获取uart资源*/  
  202.     res = platform_get_resource(platdev, IORESOURCE_MEM, 0);  
  203.     if (res == NULL) {  
  204.         printk(KERN_ERR "failed to find memory resource for uart\n");  
  205.         return -EINVAL;  
  206.     }  
  207.   
  208.     dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);  
  209.   
  210.     /*初始化基地址等*/  
  211.     port->mapbase = res->start;  
  212.     port->membase = S3C_VA_UART + (res->start & 0xfffff);  
  213.     ret = platform_get_irq(platdev, 0);  
  214.     if (ret < 0)  
  215.         port->irq = 0;  
  216.     else {  
  217.         port->irq = ret;  
  218.         ourport->rx_irq = ret;  
  219.         ourport->tx_irq = ret + 1;  
  220.     }  
  221.       
  222.     ret = platform_get_irq(platdev, 1);  
  223.     if (ret > 0)  
  224.         ourport->tx_irq = ret;  
  225.   
  226.     /*获取时钟*/  
  227.     ourport->clk = clk_get(&platdev->dev, "uart");  
  228.   
  229.     dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",  
  230.         port->mapbase, port->membase, port->irq,  
  231.         ourport->rx_irq, ourport->tx_irq, port->uartclk);  
  232.   
  233.     /* reset the fifos (and setup the uart) */  
  234.     s3c24xx_serial_resetport(port, cfg);  
  235.     return 0;  
  236. }  
  237.   
  238.   
  239.   
  240.   
  241. #define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)  
  242. /* 
  243.  * cfg = s3c24xx_dev_to_cfg(&platdev->dev) 
  244.  *  
  245.  * 那么cfg到底是如何获得? 
  246.  * 
  247.  * 搜索s3c2410_uartcfg得到: 
  248.  */  
  249.   
  250. #define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK  
  251. #define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB  
  252. #define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE  
  253.   
  254. static struct s3c2410_uartcfg smdk2440_uartcfgs[] __initdata = {  
  255.     [0] = {  
  256.         .hwport      = 0,  
  257.         .flags       = 0,  
  258.         .ucon        = 0x3c5,  
  259.         .ulcon       = 0x03,  
  260.         .ufcon       = 0x51,  
  261.     },  
  262.     [1] = {  
  263.         .hwport      = 1,  
  264.         .flags       = 0,  
  265.         .ucon        = 0x3c5,  
  266.         .ulcon       = 0x03,  
  267.         .ufcon       = 0x51,  
  268.     },  
  269.   
  270.     [2] = {  
  271.         .hwport      = 2,  
  272.         .flags       = 0,  
  273.         .ucon        = 0x3c5,  
  274.         .ulcon       = 0x43,  
  275.         .ufcon       = 0x51,  
  276.     }  
  277.     };  
  278.   
  279.   
  280. void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)  
  281. {  
  282.     if (cpu == NULL)  
  283.         return;  
  284.   
  285.     if (cpu->init_uarts == NULL) {  
  286.         printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");  
  287.     } else  
  288.         (cpu->init_uarts)(cfg, no);  
  289. }  
  290.   
  291. /*初始化系统上的串口资源*/  
  292. void __init s3c24xx_init_uartdevs(char *name,  
  293.                   struct s3c24xx_uart_resources *res,  
  294.                   struct s3c2410_uartcfg *cfg, int no)  
  295. {  
  296.     struct platform_device *platdev;  
  297.     struct s3c2410_uartcfg *cfgptr = uart_cfgs;  
  298.     struct s3c24xx_uart_resources *resp;  
  299.     int uart;  
  300.   
  301.     memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);  
  302.   
  303.     for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {  
  304.         platdev = s3c24xx_uart_src[cfgptr->hwport];  
  305.   
  306.         resp = res + cfgptr->hwport;  
  307.   
  308.         s3c24xx_uart_devs[uart] = platdev;  
  309.   
  310.         platdev->name = name;  
  311.         platdev->resource = resp->resources;  
  312.         platdev->num_resources = resp->nr_resources;  
  313.   
  314.         /*从这里获取platform*/  
  315.         platdev->dev.platform_data = cfgptr;  
  316.     }  
  317.   
  318.     nr_uarts = no;  
  319. }  
  320.   
  321.   
  322. /*uart 所对应的资源 platform_get_resourced调用**/  
  323. /* Serial port registrations */  
  324.   
  325. static struct resource s3c2410_uart0_resource[] = {  
  326.     [0] = {  
  327.         .start = S3C2410_PA_UART0,  
  328.         .end   = S3C2410_PA_UART0 + 0x3fff,  
  329.         .flags = IORESOURCE_MEM,  
  330.     },  
  331.     [1] = {  
  332.         .start = IRQ_S3CUART_RX0,  
  333.         .end   = IRQ_S3CUART_ERR0,  
  334.         .flags = IORESOURCE_IRQ,  
  335.     }  
  336. };  
  337.   
  338. static struct resource s3c2410_uart1_resource[] = {  
  339.     [0] = {  
  340.         .start = S3C2410_PA_UART1,  
  341.         .end   = S3C2410_PA_UART1 + 0x3fff,  
  342.         .flags = IORESOURCE_MEM,  
  343.     },  
  344.     [1] = {  
  345.         .start = IRQ_S3CUART_RX1,  
  346.         .end   = IRQ_S3CUART_ERR1,  
  347.         .flags = IORESOURCE_IRQ,  
  348.     }  
  349. };  
  350.   
  351. static struct resource s3c2410_uart2_resource[] = {  
  352.     [0] = {  
  353.         .start = S3C2410_PA_UART2,  
  354.         .end   = S3C2410_PA_UART2 + 0x3fff,  
  355.         .flags = IORESOURCE_MEM,  
  356.     },  
  357.     [1] = {  
  358.         .start = IRQ_S3CUART_RX2,  
  359.         .end   = IRQ_S3CUART_ERR2,  
  360.         .flags = IORESOURCE_IRQ,  
  361.     }  
  362. };  
  363.   
  364. static struct resource s3c2410_uart3_resource[] = {  
  365.     [0] = {  
  366.         .start = S3C2443_PA_UART3,  
  367.         .end   = S3C2443_PA_UART3 + 0x3fff,  
  368.         .flags = IORESOURCE_MEM,  
  369.     },  
  370.     [1] = {  
  371.         .start = IRQ_S3CUART_RX3,  
  372.         .end   = IRQ_S3CUART_ERR3,  
  373.         .flags = IORESOURCE_IRQ,  
  374.     },  
  375. };  
  376.   
  377. struct s3c24xx_uart_resources s3c2410_uart_resources[] __initdata = {  
  378.     [0] = {  
  379.         .resources  = s3c2410_uart0_resource,  
  380.         .nr_resources   = ARRAY_SIZE(s3c2410_uart0_resource),  
  381.     },  
  382.     [1] = {  
  383.         .resources  = s3c2410_uart1_resource,  
  384.         .nr_resources   = ARRAY_SIZE(s3c2410_uart1_resource),  
  385.     },  
  386.     [2] = {  
  387.         .resources  = s3c2410_uart2_resource,  
  388.         .nr_resources   = ARRAY_SIZE(s3c2410_uart2_resource),  
  389.     },  
  390.     [3] = {  
  391.         .resources  = s3c2410_uart3_resource,  
  392.         .nr_resources   = ARRAY_SIZE(s3c2410_uart3_resource),  
  393.     },  
  394. };  
  395.   
  396. 总结: 修改驱动需要设计的数据结构  
  397.   
  398. 1. uart_driver:用于初始化tty_driver  
  399. 2. s3c24xx_uart_port: 用于初始化uart_port  
  400. 3. s3c24xx_serial_ops: 硬件的操作集  
  401. 4. s3c24xx_uart_info: 用于初始化uart_port  
  402.   
  403. 其实也就是:编写S3c2440.c这个串口文件。
0 0
原创粉丝点击