一、串口驱动框架简介
Linux 提供了串口驱动框架。串口驱动没有主机端和设备端之分,就只有一个串口驱动,而且这个驱动也是由处理器厂家编写好了。
我们真正要做的就是在设备树中添加所要使用的串口节点信息,当系统启动以后串口驱动和设备匹配成功,相应的串口就会被驱动起来,生成 /dev/ttymxcX ( X = 0….n) 文件。
二、uart_driver
Linux 内核使用 uart_driver 结构体表示UART 驱动, uart_driver 定义在 include/linux/serial_core.h 文件中。
struct uart_driver
{
struct module *owner;
const char *driver_name;
const char *dev_name;
int major;
int minor;
int nr;
struct console *cons;
struct uart_state *state;
struct tty_driver *tty_driver;
};
每个串口驱动都需要定义一个 uart_driver。
注册驱动
加载驱动的时候通过 uart_register_driver 函数向系统注册这个uart_driver
int uart_register_driver(struct uart_driver* drv);
注销驱动
注销驱动的时候需要注销掉前面注册的uart_driver , 注销函数原型如下:
void uart_unregister_driver( struct uart_driver* drv);
三、uart_port
uart_port 表示一个具体的port,uart_port 定义在 include/linux/serial_core.h 文件。
struct uart_port
{
spinlock_t lock; /* port lock */
unsigned long iobase; /* in/out[bwl] */
unsigned char __iomem *membase; /* read/write[bwl] */
unsigned int ( *serial_in )( struct uart_port *, int );
void ( *serial_out )( struct uart_port *, int, int );
....
const struct uart_ops *ops;
....
}
uart_port 中最主要的就是ops,ops 包含了串口的具体驱动函数。
3.1 uart_add_one_port
每个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 ,成功;负值,失败。
3.2 uart_remove_one_port
卸载uart 驱动的时候也需要将uart_port 从相应的uart_driver 中移除,需要用到uart_remove_one_port 函数,函数原型如下:
int uart_remove_one_port ( struct uart_driver* drv,struct uart_port* uport);
3.3 uart_ops 实现
uart_port 中的ops 成员变量包含了针对UART 具体的驱动函数,Linux 系统收发最终调用的都是ops 中的函数。 uart_ops 定义在 include/linux/serial_core.h 文件中。
struct uart_ops
{
unsigned int ( *tx_empty )( struct uart_port * );
void ( *set_mctrl )( struct uart_port *, unsigned int mctrl );
unsigned int ( *get_mctrl )( struct uart_port * );
void ( *stop_tx )( struct uart_port * );
void ( *start_tx )( struct uart_port * );
void ( *throttle )( struct uart_port * );
void ( *unthrottle )( struct uart_port * );
void ( *send_xchar )( struct uart_port *, char ch );
void ( *stop_rx )( struct uart_port * );
void ( *enable_ms )( struct uart_port * );
void ( *break_ctl )( struct uart_port *, int ctl );
int ( *startup )( struct uart_port * );
void ( *shutdown )( struct uart_port * );
void ( *flush_buffer )( struct uart_port * );
void ( *set_termios )( struct uart_port *, struct ktermios *new,
struct ktermios *old );
void ( *set_ldisc )( struct uart_port *, struct ktermios * );
void ( *pm )( struct uart_port *, unsigned int state,
unsigned int oldstate );
/*
* Return a string describing the type of the port
*/
const char *( *type )( struct uart_port * );
/*
* Release IO and memory resources used by the port.
* This includes iounmap if necessary.
*/
void ( *release_port )( struct uart_port * );
/*
* Request IO and memory resources used by the port.
* This includes iomapping the port if necessary.
*/
int ( *request_port )( struct uart_port * );
void ( *config_port )( struct uart_port *, int );
int ( *verify_port )( struct uart_port *, struct serial_struct * );
int ( *ioctl )( struct uart_port *, unsigned int, unsigned long );
#ifdef CONFIG_CONSOLE_POLL
int ( *poll_init )( struct uart_port * );
void ( *poll_put_char )( struct uart_port *, unsigned char );
int ( *poll_get_char )( struct uart_port * );
#endif
};
UART 驱动编写人员需要实现uart_ops ,因为uart_ops 是最底层的UART 驱动接口,是实实在在的和UART 寄存器打交道的。