UART控制器也属于片上设备, 因此它的流程也如其他的片上设备类似,流程可参考《2410下soc上的设备的驱动流程(RTC, watchdog等)》。首先是静态的初始化好这个设备的相关信息,包括中断号,寄存器地址等 在arch/arm/mach-s3c2410/devs.c下 /* Serial port registrations */ static struct resource s3c2410_uart0_resource[] = { [0] = { .start = S3C2410_PA_UART0, /*UART0的寄存器地址*/ .end = S3C2410_PA_UART0 + 0x3fff, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_S3CUART_RX0, /*UART0的中断号*/ .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, } }; struct s3c24xx_uart_resources s3c2410_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), }, }; /* 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, }; struct platform_device *s3c24xx_uart_src[3] = { &s3c24xx_uart_device0, &s3c24xx_uart_device1, &s3c24xx_uart_device2, }; 首先看一下驱动的init函数: /* module initialisation code */ static int __init s3c24xx_serial_modinit(void) { int ret; /*注册一个UART驱动,以后会手动关联到相应的设备*/ ret = uart_register_driver(&s3c24xx_uart_drv); if (ret < 0) { printk(KERN_ERR "failed to register UART driver/n"); return -1; } /*注册一个代表UART的platform_driver*/ s3c2400_serial_init(); s3c2410_serial_init(); s3c2412_serial_init(); s3c2440_serial_init(); return 0; } static inline int s3c2400_serial_init(void) { return s3c24xx_serial_init(&s3c2400_serial_drv, &s3c2400_uart_inf); } static int s3c24xx_serial_init(struct platform_driver *drv, struct s3c24xx_uart_info *info) { dbg("s3c24xx_serial_init(%p,%p)/n", drv, info); return platform_driver_register(drv); } 可以看到init函数仅仅是注册了两个驱动对象, s3c24xx_uart_drv代表UART系统模型中的对象,用于将UART设备和UART的ops关联起来, 而另一个驱动对象即platform_driver对象则在系统中代表UART驱动实体, 当系统在匹配到合适的设备后会调用它的probe函数。 我们重点看下platform_driver对象 static struct platform_driver s3c2400_serial_drv = { .probe = s3c2400_serial_probe, /*probe函数*/ .remove = s3c24xx_serial_remove, .suspend = s3c24xx_serial_suspend, .resume = s3c24xx_serial_resume, .driver = { .name = "s3c2400-uart", .owner = THIS_MODULE, }, }; 当系统匹配到UART后,接着调用s3c2400_serial_probe static int s3c2400_serial_probe(struct platform_device *dev) { return s3c24xx_serial_probe(dev, &s3c2400_uart_inf); } /* Device driver serial port probe */ static int probe_index = 0; static int s3c24xx_serial_probe(struct platform_device *dev, struct s3c24xx_uart_info *info) { struct s3c24xx_uart_port *ourport; int ret; dbg("s3c24xx_serial_probe(%p, %p) %d/n", dev, info, probe_index); /*找到静态定义好的相关UART口的信息*/ ourport = &s3c24xx_serial_ports[probe_index]; probe_index++; dbg("%s: initialising port %p.../n", __FUNCTION__, ourport); /*初始化UART硬件接口*/ ret = s3c24xx_serial_init_port(ourport, info, dev); if (ret < 0) goto probe_err; dbg("%s: adding port/n", __FUNCTION__); /*关联uart_driver和这个设备,即让上层找到uart驱动层的fops*/ uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); platform_set_drvdata(dev, &ourport->port); /*存数据*/ return 0; probe_err: return ret; } Probe函数一般就是初始化硬件设备,并关联好fops等操作。 static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = { [0] = { .port = { .lock = SPIN_LOCK_UNLOCKED, .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX0, .uartclk = 0, .fifosize = 16, .ops = &s3c24xx_serial_ops, /*这个就是uart在驱动层的操作函数*/ .flags = UPF_BOOT_AUTOCONF, .line = 0, } }, [1] = { .port = { .lock = SPIN_LOCK_UNLOCKED, .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX1, .uartclk = 0, .fifosize = 16, .ops = &s3c24xx_serial_ops, .flags = UPF_BOOT_AUTOCONF, .line = 1, } }, #if NR_PORTS > 2 [2] = { .port = { .lock = SPIN_LOCK_UNLOCKED, .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX2, .uartclk = 0, .fifosize = 16, .ops = &s3c24xx_serial_ops, .flags = UPF_BOOT_AUTOCONF, .line = 2, } } #endif }; 这个数组为每个口保存信息。 /* s3c24xx_serial_init_port * * initialise a single serial port from the platform device given */ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, struct s3c24xx_uart_info *info, struct platform_device *platdev) { struct uart_port *port = &ourport->port; struct s3c2410_uartcfg *cfg; struct resource *res; dbg("s3c24xx_serial_init_port: port=%p, platdev=%p/n", port, platdev); if (platdev == NULL) return -ENODEV; cfg = s3c24xx_dev_to_cfg(&platdev->dev); /*获取UART的配置信息*/ if (port->mapbase != 0) return 0; if (cfg->hwport > 3) return -EINVAL; /* setup info for port */ port->dev = &platdev->dev; ourport->info = info; /* copy the info in from provided structure */ ourport->port.fifosize = info->fifosize; dbg("s3c24xx_serial_init_port: %p (hw %d).../n", port, cfg->hwport); port->uartclk = 1; if (cfg->uart_flags & UPF_CONS_FLOW) { dbg("s3c24xx_serial_init_port: enabling flow control/n"); port->flags |= UPF_CONS_FLOW; } /* sort our the physical and virtual addresses for each UART */ /*获取UART的资源信息,上面讲过*/ res = platform_get_resource(platdev, IORESOURCE_MEM, 0); if (res == NULL) { printk(KERN_ERR "failed to find memory resource for uart/n"); return -EINVAL; } dbg("resource %p (%lx..%lx)/n", res, res->start, res->end); port->mapbase = res->start; port->membase = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART); port->irq = platform_get_irq(platdev, 0); if (port->irq < 0) port->irq = 0; ourport->clk = clk_get(&platdev->dev, "uart"); dbg("port: map=%08x, mem=%08x, irq=%d, clock=%ld/n", port->mapbase, port->membase, port->irq, port->uartclk); /* reset the fifos (and setup the uart) */ s3c24xx_serial_resetport(port, cfg); /*硬件初始化*/ return 0; } 这个函数获取并初始化好UART硬件,并为驱动操作硬件做好准备。 最后我们看一下s3c24xx_serial_ops static struct uart_ops s3c24xx_serial_ops = { .pm = s3c24xx_serial_pm, .tx_empty = s3c24xx_serial_tx_empty, .get_mctrl = s3c24xx_serial_get_mctrl, .set_mctrl = s3c24xx_serial_set_mctrl, .stop_tx = s3c24xx_serial_stop_tx, .start_tx = s3c24xx_serial_start_tx, .stop_rx = s3c24xx_serial_stop_rx, .enable_ms = s3c24xx_serial_enable_ms, .break_ctl = s3c24xx_serial_break_ctl, .startup = s3c24xx_serial_startup, .shutdown = s3c24xx_serial_shutdown, .set_termios = s3c24xx_serial_set_termios, .type = s3c24xx_serial_type, .release_port = s3c24xx_serial_release_port, .request_port = s3c24xx_serial_request_port, .config_port = s3c24xx_serial_config_port, .verify_port = s3c24xx_serial_verify_port, }; 这个就是驱动层的UART操作函数集。 当上面的probe函数完成后, UART口就处于就绪状态,用户可以通过设备文件来打开,读写这个设备,而相关的操作函数最终会调用这里定义的驱动层的操作函数。 而驱动要做的就是完成这些接口, 具体就不叙述了, 可以参考代码来获取深入的了解。
UART控制器驱动流程
最新推荐文章于 2025-01-26 09:56:05 发布

2426

被折叠的 条评论
为什么被折叠?



