linux设备驱动之8250串口驱动

2019-04-08 22:11

linux设备驱动之8250串口驱动 一:前言

前一段时间自己实践了一下8250芯片串口驱动的编写。今天就在此基础上分析一下linux kernel自带的串口驱动。毕竟只有对比专业的驱动代码才能更好的进步,同以往一样,基于linix kernel2.6.25.相应驱动代码位于:linux-2.6.25/drivers/serial/8250.c。 二:8250串口驱动初始化

相应的初始化函数为serial8250_init().代码如下: static int __init serial8250_init(void) {

int ret, i;

if (nr_uarts > UART_NR) nr_uarts = UART_NR;

printk(KERN_INFO \ \ share_irqs ? \

for (i = 0; i < NR_IRQS; i++) spin_lock_init(&irq_lists[i].lock);

ret = uart_register_driver(&serial8250_reg); if (ret)

goto out;

serial8250_isa_devs = platform_device_alloc(\ PLAT8250_DEV_LEGACY); if (!serial8250_isa_devs) { ret = -ENOMEM; goto unreg_uart_drv; }

ret = platform_device_add(serial8250_isa_devs); if (ret)

goto put_dev;

serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);

ret = platform_driver_register(&serial8250_isa_driver); if (ret == 0)

goto out;

platform_device_del(serial8250_isa_devs);

put_dev:

platform_device_put(serial8250_isa_devs); unreg_uart_drv:

uart_unregister_driver(&serial8250_reg); out:

return ret;

}

这段代码涉及到的知识要求,如platform ,uart等我们在之前都已经做过详细的分析。这里不再重复。在代码中UART_NR:表示串口的个数。这个参数在编译内核的时候可以自己配置,默认为32。

我们按照代码中的流程一步一步进行研究。 1:注册uart_driver.

对应uart-driver的结构为serial8250_reg.定义如下: static struct uart_driver serial8250_reg = { .owner = THIS_MODULE, .driver_name = \ .dev_name = \

.major = TTY_MAJOR, .minor = 64, .nr = UART_NR,

.cons = SERIAL8250_CONSOLE, };

TTY_MAJOR定义如下:

#define TTY_MAJOR 4

从上面可以看出。串口对应的设备节点为/dev/ ttyS0 ~ /dev/ ttyS0(UART_NR).设备节点号为(4。64)起始的UART_NR个节点..

2:初始化并注册platform_device 相关代码如下:

serial8250_isa_devs = platform_device_alloc(\ PAT8250_DEV_LEGACY); platform_device_add(serial8250_isa_devs);

可以看出。serial8250_isa_devs.->name为serial8250。这个参数是在匹配platform_device和platform_driver使用的.

3:为uart-driver添加port. 相关代码如下:

serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev) 跟进这个函数看一下: static void __init

serial8250_register_ports(struct uart_driver *drv, struct device *dev) {

int i;

serial8250_isa_init_ports();

for (i = 0; i < nr_uarts; i++) {

struct uart_8250_port *up = &serial8250_ports[i];

up->port.dev = dev;

uart_add_one_port(drv, &up->port); }

}

在这里函数里,初始化了port.然后将挂添加到uart-driver中。我们还注意到。生成的deivce节点,在sysfs中是位于platform_deivce对应目录的下面. serial8250_isa_init_ports()代码如下所示: static void __init serial8250_isa_init_ports(void) {

struct uart_8250_port *up; static int first = 1; int i;

if (!first) return; first = 0;

for (i = 0; i < nr_uarts; i++) {

struct uart_8250_port *up = &serial8250_ports[i];

up->port.line = i;

spin_lock_init(&up->port.lock);

init_timer(&up->timer);

up->timer.function = serial8250_timeout;

/*

* ALPHA_KLUDGE_MCR needs to be killed. */

up->mcr_mask = ~ALPHA_KLUDGE_MCR; up->mcr_force = ALPHA_KLUDGE_MCR;

up->port.ops = &serial8250_pops; }

for (i = 0, up = serial8250_ports;

i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; i++, up++) {

up->port.iobase = old_serial_port[i].port;

up->port.irq = irq_canonicalize(old_serial_port[i].irq);

up->port.uartclk = old_serial_port[i].baud_base * 16;

up->port.flags = old_serial_port[i].flags; up->port.hub6 = old_serial_port[i].hub6;

up->port.membase = old_serial_port[i].iomem_base; up->port.iotype = old_serial_port[i].io_type;

up->port.regshift = old_serial_port[i].iomem_reg_shift; if (share_irqs)

up->port.flags |= UPF_SHARE_IRQ; }

}

在这里,我们关注一下注要成员的初始化。Uart_port的各项操作位于serial8250_pops中.iobase irq等成员是从old_serial_por这个结构中得来的,这个结构如下所示: static const struct old_serial_port old_serial_port[] = { SERIAL_PORT_DFNS /* defined in asm/serial.h */ }

#define SERIAL_PORT_DFNS

/* UART CLK PORT IRQ FLAGS */ { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */

{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */

从上面看到。前两项对应了com1 com2的各项参数。如寄存器首始地址,Irq号等。后面两项不太清楚。

在上面的代码中,我们看到了uart_port各项成员的初始化。在后面很多操作中需要用到这个成员。我们等分析相关部份的时候,再到这个地方来看相关成员的值。

4:注册platform_driver 相关代码如下:

platform_driver_register(&serial8250_isa_driver); serial8250_isa_driver定义如下:

static struct platform_driver serial8250_isa_driver = { .probe = serial8250_probe,

.remove = __devexit_p(serial8250_remove), .suspend = serial8250_suspend,

.resume = serial8250_resume, .driver = {

.name = \ .owner = THIS_MODULE, }, }

为了以后把分析集中到具体的驱动部份.我们先把这个platform_driver引会的事件讲述完. 经过前面有关platform的分析我们知道.这个platform的name为” serial8250”.刚好跟前面

注册的platform_device相匹配.会调用platform_driver-> probe.在这里,对应的接口为: serial8250_probe().代码如下:

static int __devinit serial8250_probe(struct platform_device *dev) {

struct plat_serial8250_port *p = dev->dev.platform_data; struct uart_port port; int ret, i;

memset(&port, 0, sizeof(struct uart_port));

for (i = 0; p && p->flags != 0; p++, i++) { port.iobase = p->iobase; port.membase = p->membase; port.irq = p->irq; port.uartclk = p->uartclk; port.regshift = p->regshift; port.iotype = p->iotype; port.flags = p->flags;

port.mapbase = p->mapbase; port.hub6 = p->hub6;

port.private_data = p->private_data; port.dev = &dev->dev; if (share_irqs)

port.flags |= UPF_SHARE_IRQ; ret = serial8250_register_port(&port);

if (ret < 0) {

dev_err(&dev->dev, \ \

p->iobase, (unsigned long long)p->mapbase, p->irq, ret); } }

return 0; }

从上述代码可以看出.会将dev->dev.platform_data所代表的port添加到uart_driver中.这个dev->dev.platform_data究竟代表什么.我们在看到的时候再来研究它. 现在,我们把精力集中到uart_port的操作上.

三:config_port过程

在初始化uart_port的过程中,在以下代码片段: serial8250_isa_init_ports(void) {

…… ……


linux设备驱动之8250串口驱动.doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:曾仕强经典语录

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: