2016年(80)
分类: LINUX
2016-03-29 17:58:28
我们看到Linux dev目录下面ttyS系列的串口设备的终端,现在用一个uart 控制器的程序来分析下怎么实现的
首先是定义了uart driver
static struct uart_driver XX_uart_driver = {
.owner = THIS_MODULE,
.driver_name = XX_UART_DEV_NAME, //名字,实际是uart
.dev_name = "ttyS",
.nr = XX_UART_NUM,
.cons = XX_CONSOLE,
};
通过uart 核心层提供的接口先上层注册
uart_register_driver(&XX_uart_driver);
它原型是这样的
int uart_register_driver(struct uart_driver *drv)
{
struct tty_driver *normal;
int i, retval;
BUG_ON(drv->state);
/*
* Maybe we should be using a slab cache for this, especially if
* we have a large number of ports to handle.
*/
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
if (!drv->state)
goto out;
normal = alloc_tty_driver(drv->nr); //由此可以看出来是通过tty设备来抽象的
if (!normal)
goto out_kfree;
drv->tty_driver = normal;
normal->driver_name= drv->driver_name;
normal->name = drv->dev_name;
normal->major = drv->major;
normal->minor_start= drv->minor;
normal->type = TTY_DRIVER_TYPE_SERIAL;
normal->subtype= SERIAL_TYPE_NORMAL;
normal->init_termios= tty_std_termios;
normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
normal->driver_state = drv;
tty_set_operations(normal, &uart_ops);
/*
* Initialise the UART state(s).
*/
for (i = 0; i < drv->nr; i++) { //cpu的串口多少组串口
struct uart_state *state = drv->state + i;
struct tty_port *port = &state->port;
tty_port_init(port);
port->ops = &uart_port_ops;
port->close_delay = HZ / 2;/* .5 seconds */
port->closing_wait = 30 * HZ;/* 30 seconds */
}
retval = tty_register_driver(normal); //注册tty设备驱动
if (retval >= 0)
return retval;
put_tty_driver(normal);
out_kfree:
kfree(drv->state);
out:
return -ENOMEM;
}
注册相应的devices,由于一个CPU有多组串口
for (i=0; i
if (!pdata->used)
continue;
platform_device_register(&XX_uport_device[i]);
}
XX_uport_device里面包含了很多resource
struct XX_uart_pdata {
unsigned int used;
unsigned int base;
unsigned int irq; //中断号
unsigned int max_ios;
unsigned int io_num;//io内存
};
流程走到了注册
static struct platform_driver XX_uport_platform_driver = {
.probe = XX_uart_probe,
.remove = XX_uart_remove,
.driver = {
.name = XX_UART_DEV_NAME,
.pm = SERIAL_XX_PM_OPS,
.owner = THIS_MODULE,
},
};
static int __devinit XX_uart_probe(struct platform_device *pdev)
{
struct uart_port *port;
struct XX_uart_port *XX_uport;
int ret = -1;
port = &XX_uart_ports[pdev->id].port;
port->dev = &pdev->dev;
sw_uport = UART_TO_SPORT(port);
sw_uport->id = pdev->id;
sw_uport->ier = 0;
sw_uport->lcr = 0;
sw_uport->mcr = 0;
sw_uport->fcr = 0;
sw_uport->dll = 0;
sw_uport->dlh = 0;
snprintf(XX_uport->name, 16, XX_UART_DEV_NAME"%d", pdev->id);
pdev->dev.init_name = XX_uport->name;
SERIAL_DBG("uart.%d probe ... \n", pdev->id);
/* request system resource and init them */
ret = XX_uart_request_resource(XX_uport);
if (unlikely(ret)) {
SERIAL_MSG("uart%d error to get resource\n", pdev->id);
return -ENXIO;
}
port->uartclk = clk_get_rate(sw_uport->mclk);
port->type = PORT_XX;
port->flags = UPF_BOOT_AUTOCONF;
port->mapbase = XX_uport->pdata->base;
port->irq = XX_uport->pdata->irq;
platform_set_drvdata(pdev, port);
SERIAL_DBG("add uart%d port, port_type %d, uartclk %d\n",
pdev->id, port->type, port->uartclk);
return uart_add_one_port(&XX_uart_driver, port);
}
我们来看一下linux内核是如何相应收数据,和发送数据的。 首先看驱动向内核注册的串口操作集合 static struct uart_ops _uart_ops = { .tx_empty = _uart_tx_empty, .set_mctrl = _uart_set_mctrl, .get_mctrl = _uart_get_mctrl, .stop_tx = _uart_stop_tx,//停止发送 .start_tx = _uart_start_tx,//应用层最终通过tty的驱动发送数据会掉到这个接口 .stop_rx = _uart_stop_rx,//停止接受 .enable_ms = _uart_enable_ms, .break_ctl = _uart_break_ctl, .startup = _uart_startup, //这个接口通常会做一些初始化一个串口 比如 注册串口中断,打开中断。 .shutdown = _uart_shutdown, .set_termios = _uart_set_termios,//设置串口的属性 .type = _uart_type,//串口类型 .release_port = _uart_release_port, .request_port = _uart_request_port, .config_port = _uart_config_port, .verify_port = _uart_verify_port, .pm = _uart_pm, }; 首先我们看一下发送: 发送时cpu主动发起的数据,相对比较简单,由应用程序直接调用到_uart_start_tx,把相应的数据写到相应的寄存器,通常数据发送完以后会产生中断,这个中断对应的了startup函数里面注册中断。 接收数据过程: 接收数据cpu是被动接收的,只能听过中断来检测数据的到来,当中断到来时,产生中断。void uart_insert_char(struct uart_port *port, unsigned int status,unsigned int overrun, unsigned int ch, unsigned int flag)接口把接收到数据推送到上层去。 |