Linux
下
UART
驱动框架
1
、
uart_driver
注册与注销
uart_driver需要驱动编写人员实现,并使用uart_register_driver注册到内核,卸载驱动的时候,使用uart_unregister_driver卸载。同 I2C、SPI 一样,Linux 也提供了串口驱动框架,我们只需要按照相应的串口框架编写驱动程序即可。串口驱动没有什么主机端和设备端之分,就只有一个串口驱动,而且这个驱动也已经由NXP 官方已经编写好了,我们真正要做的就是在设备树中添加所要使用的串口节点信息。当系统启动以后串口驱动和设备匹配成功,相应的串口就会被驱动起来,生成 /dev/ttymxcX(X=0….n)文件。虽然串口驱动不需要我们去写,但是串口驱动框架我们还是需要了解的,uart_driver 结构体表示 UART 驱动,uart_driver 定义在 include/linux/serial_core.h 文件中,内容如下:
295 struct uart_driver {
296 struct module *owner; /* 模块所属者 */
297 const char *driver_name; /* 驱动名字 */
298 const char *dev_name; /* 设备名字 */
299 int major; /* 主设备号 */
300 int minor; /* 次设备号 */
301 int nr; /* 设备数 */
302 struct console *cons; /* 控制台 */
303
304 /*
305 * these are private; the low level driver should not
306 * touch these; they should be initialised to NULL
307 */
308 struct uart_state *state;
309 struct tty_driver *tty_driver;
310 };
每个串口驱动都需要定义一个
uart_driver
,加载驱动的时候通过
uart_register_driver
函数向
系统注册这个
uart_driver
,此函数原型如下:
int uart_register_driver(struct uart_driver *drv)
函数参数和返回值含义如下:
drv
:
要注册的
uart_driver
。
返回值:
0
,成功;负值,失败。
注销驱动的时候也需要注销掉前面注册的
uart_driver
,需要用到
uart_unregister_driver
函数,
函数原型如下:
void uart_unregister_driver(struct uart_driver *drv)
函数参数和返回值含义如下:
drv
:
要注销的
uart_driver
。
返回值:
无。
2
、
uart_port
的添加与移除
用于描述一个具体的串口端口,驱动编写人员需要实现uart_port,然后使用uart_add_one_port函数向内核添加一个uart端口,卸载的时候uart_remove_one_port卸载。uart_port里面有个非常重要的成员变量uart_ops,此结构体包含了针对uart端口进行的所有操作,需要驱动编写人员实现。
uart_port
表示一个具体的
port
,
uart_port
定义在
include/linux/serial_core.h
文件,内容部分如下
117 struct uart_port {
118 spinlock_t lock; /* port lock */
119 unsigned long iobase; /* in/out[bwl] */
120 unsigned char __iomem *membase; /* read/write[bwl] */
......
235 const struct uart_ops *ops;
236 unsigned int custom_divisor;
237 unsigned int line; /* port index */
238 unsigned int minor;
239 resource_size_t mapbase; /* for ioremap */
240 resource_size_t mapsize;
241 struct device *dev; /* parent device */
......
250 };
uart_port
中最主要的就是第
235
行的
ops
,
ops
包含了串口的具体驱动函数,这个我们稍后
再看。每个
UART
都有一个
uart_port
,那么
uart_port
是怎么和
uart_driver
结合起来的呢?这里
要用到
uart_add_one_port
函数,函数原型如下:
int uart_add_one_port(struct uart_driver *drv,
struct uart_port *uport)
函数参数和返回值含义如下:
drv
:此
port
对应的
uart_driver
。
uport
:
要添加到
uart_driver
中的
port
。
返回值:
0
,成功;负值,失败。
卸载
UART
驱动的时候也需要将
uart_port
从相应的
uart_driver
中移除,需要用到
uart_remove_one_port
函数,函数原型如下:
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
函数参数和返回值含义如下:
drv
:要卸载的
port
所对应的
uart_driver
。
uport
:
要卸载的
uart_port
。
返回值:
0
,成功;负值,失败。
3
、
uart_ops
实现
在上面讲解
uart_port
的时候说过,
uart_port
中的
ops
成员变量很重要,因为
ops
包含了针
对
UART
具体的驱动函数,
Linux
系统收发数据最终调用的都是
ops
中的函数。
ops
是
uart_ops
类型的结构体指针变量,
uart_ops
定义在
include/linux/serial_core.h
文件中,内容如下:
49 struct uart_ops {
50 unsigned int (*tx_empty)(struct uart_port *);
51 void (*set_mctrl)(struct uart_port *, unsigned int mctrl);
52 unsigned int (*get_mctrl)(struct uart_port *);
53 void (*stop_tx)(struct uart_port *);
54 void (*start_tx)(struct uart_port *);
55 void (*throttle)(struct uart_port *);
56 void (*unthrottle)(struct uart_port *);
57 void (*send_xchar)(struct uart_port *, char ch);
58 void (*stop_rx)(struct uart_port *);
59 void (*enable_ms)(struct uart_port *);
60 void (*break_ctl)(struct uart_port *, int ctl);
61 int (*startup)(struct uart_port *);
62 void (*shutdown)(struct uart_port *);
63 void (*flush_buffer)(struct uart_port *);
64 void (*set_termios)(struct uart_port *, struct ktermios *new,
65 struct ktermios *old);
66 void (*set_ldisc)(struct uart_port *, struct ktermios *);
67 void (*pm)(struct uart_port *, unsigned int state,
68 unsigned int oldstate);
69
70 /*
71 * Return a string describing the type of the port
72 */
73 const char *(*type)(struct uart_port *);
74
75 /*
76 * Release IO and memory resources used by the port.
77 * This includes iounmap if necessary.
78 */
79 void (*release_port)(struct uart_port *);
80
81 /*
82 * Request IO and memory resources used by the port.
83 * This includes iomapping the port if necessary.
84 */
85 int (*request_port)(struct uart_port *);
86 void (*config_port)(struct uart_port *, int);
87 int (*verify_port)(struct uart_port *, struct serial_struct *);
88 int (*ioctl)(struct uart_port *, unsigned int, unsigned long);
89 #ifdef CONFIG_CONSOLE_POLL
90 int (*poll_init)(struct uart_port *);
91 void (*poll_put_char)(struct uart_port *, unsigned char);
92 int (*poll_get_char)(struct uart_port *);
93 #endif
94 };
UART
驱动编写人员需要实现
uart_ops
,因为
uart_ops
是最底层的
UART
驱动接口,是实
实在在的和
UART
寄存器打交道的。关于
uart_ops
结构体中的这些函数的具体含义请参考
Documentation/serial/driver
这个文档。