结合源码,详细讲解一下struct uart_driver控制uart口的全过程
时间: 2024-02-21 16:01:50 浏览: 27
在 Linux 内核中,`struct uart_driver` 结构体是用来描述串口驱动的。它定义了一组函数指针,这些函数指针需要由串口驱动程序实现,以便与 Linux 内核进行交互。
下面是 `struct uart_driver` 结构体的定义:
```c
struct uart_driver {
struct module *owner;
const char *driver_name;
struct uart_ops *ops;
int minor;
bool nr;
struct uart_state *state;
struct uart_port *ports[UART_NR]; /* MAX number of ports */
...
};
```
其中,`owner` 指向拥有此驱动程序的内核模块。`driver_name` 是驱动程序的名称。`ops` 是一个指向 `struct uart_ops` 结构体的指针,它包含了一组函数指针,这些指针定义了串口驱动程序需要实现的函数。`minor` 是指定驱动程序使用的最小设备号。`nr` 表示此驱动程序支持的串口数量。`state` 是一个指向保存驱动程序状态的结构体的指针。`ports` 数组包含了此驱动程序所支持的所有串口设备的 `struct uart_port` 结构体指针。
下面是 `struct uart_ops` 结构体的定义:
```c
struct uart_ops {
unsigned int (*tx_empty)(struct uart_port *port);
void (*set_mctrl)(struct uart_port *port, unsigned int mctrl);
unsigned int (*get_mctrl)(struct uart_port *port);
void (*stop_tx)(struct uart_port *port);
void (*start_tx)(struct uart_port *port);
void (*stop_rx)(struct uart_port *port);
void (*enable_ms)(struct uart_port *port);
void (*break_ctl)(struct uart_port *port, int break_state);
int (*startup)(struct uart_port *port);
void (*shutdown)(struct uart_port *port);
void (*flush_buffer)(struct uart_port *port);
void (*set_termios)(struct uart_port *port, struct ktermios *termios, struct ktermios *old);
void (*pm)(struct uart_port *port, unsigned int state, unsigned int oldstate);
...
};
```
这些函数指针定义了串口驱动程序需要实现的函数,以便与 Linux 内核进行交互,包括数据的发送和接收、控制信号的设置和读取,以及串口设备的启动和关闭等操作。
在驱动程序初始化时,需要完成以下几个步骤:
1. 分配并初始化 `struct uart_driver` 结构体。
2. 注册驱动程序,调用 `uart_register_driver()` 函数完成注册。
3. 分配并初始化 `struct uart_port` 结构体,用于描述每个串口设备。
4. 注册串口设备,调用 `uart_add_one_port()` 函数完成注册。
5. 启动串口设备,调用 `startup()` 函数完成启动。
6. 在驱动程序退出时,需要调用 `shutdown()` 函数关闭串口设备。
下面是一个示例代码,展示了如何使用 `struct uart_driver` 结构体控制串口设备:
```c
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/serial.h>
static struct uart_driver my_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "my_uart_driver",
.nr = 1,
.ops = &my_uart_ops,
};
static struct uart_port my_uart_port = {
.type = PORT_UART,
.iotype = UPIO_MEM,
.mapbase = 0x3f8,
.irq = 4,
.flags = UPF_BOOT_AUTOCONF,
.uartclk = 1843200,
};
static int __init my_uart_init(void)
{
int ret;
ret = uart_register_driver(&my_uart_driver);
if (ret)
return ret;
my_uart_port.uartclk = clk_get_rate(my_uart_port.uartclk);
ret = uart_add_one_port(&my_uart_driver, &my_uart_port);
if (ret)
uart_unregister_driver(&my_uart_driver);
return ret;
}
static void __exit my_uart_exit(void)
{
uart_remove_one_port(&my_uart_driver, &my_uart_port);
uart_unregister_driver(&my_uart_driver);
}
module_init(my_uart_init);
module_exit(my_uart_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Author");
MODULE_DESCRIPTION("My UART Driver");
```
在上面的示例代码中,我们定义了一个名为 `my_uart_driver` 的 `struct uart_driver` 结构体,用于描述串口驱动程序。我们还定义了一个名为 `my_uart_port` 的 `struct uart_port` 结构体,用于描述串口设备。我们在 `my_uart_init()` 函数中,首先调用 `uart_register_driver()` 函数注册驱动程序。然后,我们设置了 `my_uart_port` 结构体中的一些字段,包括串口设备的基地址、中断号等信息。最后,我们调用 `uart_add_one_port()` 函数将此串口设备注册到内核中。
在驱动程序退出时,我们首先调用 `uart_remove_one_port()` 函数将此串口设备从内核中删除,然后调用 `uart_unregister_driver()` 函数注销驱动程序。