/driver/serial/serial-core.c 中实现了UART设备的通用tty驱动层,称为串口核心层。
UART驱动的主要任务是 实现serial-core.c中定义的一组uart_xxx接口。
serial-core.c串口核心层完全可以当做一个tty设备驱动的实例,它是实现了UART设备的tty驱动。
串口核心层为串口设备驱动提供了3个结构体。
1. uart_driver
包含了串口设备的驱动名,设备名,设备号等信息。
它封装了tty_driver,使得底层UART驱动无需关心tty_driver.
struct uart_driver {
struct module *owner;
const char *driver_name; //驱动名 /sys, /proc 下名称
const char *dev_name; //设备名, /dev 下名称
int major;
int minor;
int nr;
struct console *cons;
/*
* these are private; the low level driver should not
* touch these; they should be initialised to NULL
*/
struct uart_state *state;
struct tty_driver *tty_driver;
};
int uart_register_driver(struct uart_driver *drv)
void uart_unregister_driver(struct uart_driver*drv)
一个tty驱动必须注册/注销tty_driver,而一个UART驱动则必须注册/注销uart_driver:
/**
* uart_register_driver - register a driver with the uart core layer
* @drv: low level driver structure
*
* Register a uart driver with the core driver. We in turn register
* with the tty layer, and initialise the core driver per-port state.
*
* We have a proc file in /proc/tty/driver which is named after the
* normal driver.
*
* drv->port should be NULL, and the per-port structures should be
* registered using uart_add_one_port after this call has succeeded.
*/
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_driver.
if (!normal)
goto out_kfree;
drv->tty_driver = normal;
//初始化tty_driver
normal->owner = drv->owner;
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++) {
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 = 500; /* .5 seconds */
port->closing_wait = 30000; /* 30 seconds */
tasklet_init(&state->tlet, uart_tasklet_action, //初始化一个tasklet延时执行机制
(unsigned long)state);
}
retval = tty_register_driver(normal); //注册tty驱动
if (retval >= 0)
return retval;
put_tty_driver(normal);
out_kfree:
kfree(drv->state);
out:
return -ENOMEM;
}
/**
* uart_unregister_driver - remove a driver from the uart core layer
* @drv: low level driver structure
*
* Remove all references to a driver from the core driver. The low
* level driver must have removed all its ports via the
* uart_remove_one_port() if it registered them with uart_add_one_port().
* (ie, drv->port == NULL)
*/
void uart_unregister_driver(struct uart_driver *drv)
{
struct tty_driver *p = drv->tty_driver;
tty_unregister_driver(p); //注销tty驱动
put_tty_driver(p);
kfree(drv->state);
drv->tty_driver = NULL;
}
2 uart_port
用于描述一个UART端口的I/O端口或I/O内存地址,FIFO大小,端口类型等。
typedef unsigned int __bitwise__ upf_t;
struct uart_port {
spinlock_t lock; /* port lock */ //端口锁
unsigned long iobase; /* in/out[bwl] */ //I/O端口基地址
unsigned char __iomem *membase; /* read/write[bwl] */ //I/O内存及地址
unsigned int (*serial_in)(struct uart_port *, int);
void (*serial_out)(struct uart_port *, int, int);
void (*set_termios)(struct uart_port *,
struct ktermios *new,
struct ktermios *old);
void (*pm)(struct uart_port *, unsigned int state,
unsigned int old);
unsigned int irq; /* irq number */ //中断号
unsigned long irqflags; /* irq flags */
unsigned int uartclk; /* base uart clock */ //UART时钟
unsigned int fifosize; /* tx fifo size */ //传输的FIFO大小
unsigned char x_char; /* xon/xoff char */ //xon/xoff字节
unsigned char regshift; /* reg offset shift */ //寄存器移位
unsigned char iotype; /* io access style */ //I/O存取类型
unsigned char unused1;
#define UPIO_PORT (0) //I/O 端口
#define UPIO_HUB6 (1)
#define UPIO_MEM (2) //I/O内存
#define UPIO_MEM32 (3)
#define UPIO_AU (4) /* Au1x00 type IO */
#define UPIO_TSI (5) /* Tsi108/109 type IO */
#define UPIO_DWAPB (6) /* DesignWare APB UART */
#define UPIO_RM9000 (7) /* RM9000 type IO */
unsigned int read_status_mask; /* driver specific */ //驱动特定的读状态掩码
unsigned int ignore_status_mask; /* driver specific */ //驱动特定的忽略状态掩码
struct uart_state *state; /* pointer to parent state */ //指向parent状态信息
struct uart_icount icount; /* statistics */ //计数
struct console *cons; /* struct console, if any */ //console结构体
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
unsigned long sysrq; /* sysrq timeout */ //sysrq超时
#endif
upf_t flags;
#define UPF_FOURPORT ((__force upf_t) (1 << 1))
#define UPF_SAK ((__force upf_t) (1 << 2))
#define UPF_SPD_MASK ((__force upf_t) (0x1030))
#define UPF_SPD_HI ((__force upf_t) (0x0010))
#define UPF_SPD_VHI ((__force upf_t) (0x0020))
#define UPF_SPD_CUST ((__force upf_t) (0x0030))
#define UPF_SPD_SHI ((__force upf_t) (0x1000))
#define UPF_SPD_WARP ((__force upf_t) (0x1010))
#define UPF_SKIP_TEST ((__force upf_t) (1 << 6))
#define UPF_AUTO_IRQ ((__force upf_t) (1 << 7))
#define UPF_HARDPPS_CD ((__force upf_t) (1 << 11))
#define UPF_LOW_LATENCY ((__force upf_t) (1 << 13))
#define UPF_BUGGY_UART ((__force upf_t) (1 << 14))
#define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15))
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16))
#define UPF_CONS_FLOW ((__force upf_t) (1 << 23))
#define UPF_SHARE_IRQ ((__force upf_t) (1 << 24))
/* The exact UART type is known and should not be probed. */
#define UPF_FIXED_TYPE ((__force upf_t) (1 << 27))
#define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28))
#define UPF_FIXED_PORT ((__force upf_t) (1 << 29))
#define UPF_DEAD ((__force upf_t) (1 << 30))
#define UPF_IOREMAP ((__force upf_t) (1 << 31))
#define UPF_CHANGE_MASK ((__force upf_t) (0x17fff))
#define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))
unsigned int mctrl; /* current modem ctrl settings */ //目前modem控制设置
unsigned int timeout; /* character-based timeout */ //基于字符的超时
unsigned int type; /* port type */ //端口类型
const struct uart_ops *ops; //UART 操作符
unsigned int custom_divisor;
unsigned int line; /* port index */ //端口索引
resource_size_t mapbase; /* for ioremap */ //ioremap后基地址
struct device *dev; /* parent device */ //parent设备
unsigned char hub6; /* this should be in the 8250 driver */
unsigned char suspended;
unsigned char unused[2];
void *private_data; /* generic platform data pointer */
};
串口核心层提供如下函数用来添加/删除一个端口:
int uart_add_one_port(struct uart_driver*drv,struct uart_port*uport);
int uart_remove_one_port(struct uart_driver*drv,struct uart_port *uport);
/**
* uart_add_one_port - attach a driver-defined port structure
* @drv: pointer to the uart low level driver structure for this port
* @uport: uart port structure to use for this port.
*
* This allows the driver to register its own uart_port structure
* with the core driver. The main purpose is to allow the low
* level uart drivers to expand uart_port, rather than having yet
* more levels of structures.
*/
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
{
struct uart_state *state;
struct tty_port *port;
int ret = 0;
struct device *tty_dev;
BUG_ON(in_interrupt());
if (uport->line >= drv->nr)
return -EINVAL;
state = drv->state + uport->line;
port = &state->port;
mutex_lock(&port_mutex);
mutex_lock(&port->mutex);
if (state->uart_port) {
ret = -EINVAL;
goto out;
}
state->uart_port = uport;
state->pm_state = -1;
uport->cons = drv->cons;
uport->state = state;
/*
* If this port is a console, then the spinlock is already
* initialised.
*/
if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
spin_lock_init(&uport->lock);
lockdep_set_class(&uport->lock, &port_lock_key);
}
uart_configure_port(drv, state, uport);
/*
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this ports parameters.
*/
tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);
if (likely(!IS_ERR(tty_dev))) {
device_init_wakeup(tty_dev, 1);
device_set_wakeup_enable(tty_dev, 0);
} else
printk(KERN_ERR "Cannot register tty device on line %d\n",
uport->line);
/*
* Ensure UPF_DEAD is not set.
*/
uport->flags &= ~UPF_DEAD;
out:
mutex_unlock(&port->mutex);
mutex_unlock(&port_mutex);
return ret;
}
/**
* uart_remove_one_port - detach a driver defined port structure
* @drv: pointer to the uart low level driver structure for this port
* @uport: uart port structure for this port
*
* This unhooks (and hangs up) the specified port structure from the
* core driver. No further calls will be made to the low-level code
* for this port.
*/
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
{
struct uart_state *state = drv->state + uport->line;
struct tty_port *port = &state->port;
BUG_ON(in_interrupt());
if (state->uart_port != uport)
printk(KERN_ALERT "Removing wrong port: %p != %p\n",
state->uart_port, uport);
mutex_lock(&port_mutex);
/*
* Mark the port "dead" - this prevents any opens from
* succeeding while we shut down the port.
*/
mutex_lock(&port->mutex);
uport->flags |= UPF_DEAD;
mutex_unlock(&port->mutex);
/*
* Remove the devices from the tty layer
*/
tty_unregister_device(drv->tty_driver, uport->line);
if (port->tty)
tty_vhangup(port->tty);
/*
* Free the port IO and memory resources, if any.
*/
if (uport->type != PORT_UNKNOWN)
uport->ops->release_port(uport);
/*
* Indicate that there isn't a port here anymore.
*/
uport->type = PORT_UNKNOWN;
/*
* Kill the tasklet, and free resources.
*/
tasklet_kill(&state->tlet);
state->uart_port = NULL;
mutex_unlock(&port_mutex);
return 0;
}
3. uart_ops:
定义了对UART的一系列操作,包括发送,接收和线路设置等。
uart_ops直接面向串口的UART,类似于面向对象中的基类、派生类的关系。
派生类针对特定的事物会更加具体,而基类则处于更高的抽象层次。
/*
* This structure describes all the operations that can be
* done on the physical hardware.
*/
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 (*send_xchar)(struct uart_port *, char ch); //发送xchar
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); //设置termios
void (*set_ldisc)(struct uart_port *, int new);
void (*pm)(struct uart_port *, unsigned int state,
unsigned int oldstate);
int (*set_wake)(struct uart_port *, unsigned int state);
/*
* 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 *); //释放端口使用的I/O和内存资源,必要的情况下,应该进行iounmap操作。
/*
* Request IO and memory resources used by the port.
* This includes iomapping the port if necessary.
*/
int (*request_port)(struct uart_port *); //申请端口使用的I/O和内存资源。
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
void (*poll_put_char)(struct uart_port *, unsigned char);
int (*poll_get_char)(struct uart_port *);
#endif
};
一个串口驱动要完成主要工作如下:
a. 定义 uart_driver, uart_ops, uart_port 等结构体的实例,并在适当的地方根据硬件和驱动的情况初始化它们,具体设备xxx的驱动可以将这些结构套接在新定义的xxx_uart_driver, xxx_uart_ops, xxx_uart_port内。
b. 在模块初始化时调用uart_register_driver()和uart_add_one_port()来注册UART驱动并添加端口,在模块卸载时调用uart_unregister_driver()和uart_remove_one_port()来注销UART驱动并移除端口。
c. 根据具体的硬件Datasheet来实现uart_ops中的成员函数,这些函数的实现是UART驱动的主体工作。