微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Linux下的串口总线驱动(一)

Linux下的串口总线驱动(一)

时间:11-22 来源:互联网 点击:

ourport = &s3c24xx_serial_ports[probe_index]; //选择s3c24xx_uart_port

probe_index++; //索引号自增

dbg("%s: initialising port %p...\n", __func__, ourport);

ret = s3c24xx_serial_init_port(ourport, info, dev); //初始化串口

if (ret < 0)

goto probe_err;

dbg("%s: adding port\n", __func__);

uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); //向内核注册端口

platform_set_drvdata(dev, &ourport->port); //设置私有数据

ret = device_create_file(&dev->dev, &dev_attr_clock_source); //添加设备属性

if (ret < 0)

printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);

ret = s3c24xx_serial_cpufreq_register(ourport); //注册CPU频率

if (ret < 0)

dev_err(&dev->dev, "failed to add cpufreq notifier\n");

return 0;

probe_err:

return ret;

}

通过上面的函数,我们发现在UART层,我们调用了uart_add_one_port函数完成端口的添加,我们来看看添加了什么端口呢?

static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {

[0] = {

.port = {

.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),

.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(s3c24xx_serial_ports[1].port.lock),

.iotype = UPIO_MEM,

.irq = IRQ_S3CUART_RX1,

.uartclk = 0,

.fifosize = 16,

.ops = &s3c24xx_serial_ops, //对UART操作的函数

.flags = UPF_BOOT_AUTOCONF,

.line = 1,

}

},

#if CONFIG_SERIAL_SAMSUNG_UARTS > 2

[2] = {

.port = {

.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),

.iotype = UPIO_MEM,

.irq = IRQ_S3CUART_RX2,

.uartclk = 0,

.fifosize = 16,

.ops = &s3c24xx_serial_ops, //对UART操作的函数

.flags = UPF_BOOT_AUTOCONF,

.line = 2,

}

},

#endif

#if CONFIG_SERIAL_SAMSUNG_UARTS > 3

[3] = {

.port = {

.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),

.iotype = UPIO_MEM,

.irq = IRQ_S3CUART_RX3,

.uartclk = 0,

.fifosize = 16,

.ops = &s3c24xx_serial_ops, //对UART操作的函数

.flags = UPF_BOOT_AUTOCONF,

.line = 3,

}

}

#endif

};

在端口的定义中,我们知道s3c24xx_uart_port中定义了一个uart_port结构体,继续跟踪对UART的操作函数

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, //类似于write

.stop_rx = s3c24xx_serial_stop_rx,

.enable_ms = s3c24xx_serial_enable_ms,

.break_ctl = s3c24xx_serial_break_ctl,

.startup = s3c24xx_serial_startup, //类似于open

.shutdown = s3c24xx_serial_shutdown, //类似于close

.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_ops函数,我们需要自己去实现uart层的具体操作。

我们在UART层主要涉及uart_driver,uart_port,uart_ops三个结构体,并调用tty层的uart_register_driver和uart_add_one_port完成驱动和端口的注册,UART层具体操作函数需要用户自己设计。

好了,总结下UART驱动层需要完成的任务:

其一,定义uart_driver、uart_ops、uart_port等结构体的实例并在适当的地方根据具体硬件和驱动的情况初始化它们,当然具体设备XXX的驱动可以将这些结构套在新定义的XXX_uart_driver、XXX_uart_ops、XXX_uart_port之内。

其二,在模块初始化时调用uart_register_driver()和uart_add_one_port()以注册UART驱动并添加端口,在模块卸载时调用uart_unregister_driver()和uart_remove_one_port()以注销UART驱动并移除端口。

其三,根据具体硬件的datasheet实现uart_ops中的成员

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top