s3c6410的UART设备驱动(1)的链接地址
上一篇说到了第二部分,但没说完,这一篇接着说第二部分,如下这部分:
在模块初始化是调用uart_register_driver和uart_add_port注册UART驱动并添加端口,在模块卸载时调用uart_unregister_driver和uart_remove_one_port以注销UART驱动并移除端口。
1、先来看uart_add_one_port函数,源码如下:
/**
* uart_add_one_port - attach a driver-defined port structure
* @drv: pointer to the uart low level driver structure for this port
* @port: 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 s3c24xx_serial_probe(struct platform_device *dev,
struct s3c24xx_uart_info *info)函数中被调用,和平台设备有关的函数。
int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
{
struct uart_state *state;
int ret = 0;
struct device *tty_dev;
........
if (port->line >= drv->nr)
return -EINVAL;
state = drv->state + port->line;
mutex_lock(&port_mutex);
mutex_lock(&state->mutex);
if (state->port) {
ret = -EINVAL;
goto out;
}
state->port = port;对state结构体中的成员port赋值,部分源码如下:
struct uart_state {
........
struct uart_info*info;
struct uart_port*port;
struct mutex mutex;
};
state->pm_state = -1;
port->cons = drv->cons;
port->info = state->info;
info这个数据结构我们就不列出了,看下他的注释:
/*
* This is the state information which is only valid when the port
* is open; it may be freed by the core driver once the device has
* been closed. Either the low level driver or the core can modify
* stuff here.
*/
......
uart_configure_port(drv, state, port);看函数名就知道了干什么的。源码如下:先说下 struct uart_port *port结构体有什么用?在我看来,一个此种结构体的实例,就表示有一个串口可供我们使用。在列出在第一篇中列出的这个结构体的实例(其中的一部分),如下所示:
static struct s3c24xx_uart_ports3c24xx_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,
.flags = UPF_BOOT_AUTOCONF,
.line = 0,
}
}看这些都是什么?是不是和一个具体的串口很相关,如中断等等。
static void
uart_configure_port(struct uart_driver *drv, struct uart_state *state,
struct uart_port *port)
{
unsigned int flags;
/*
* If there isn't a port here, don't do anything further.
*/
if (!port->iobase && !port->mapbase && !port->membase)
return;
/*
* Now do the auto configuration stuff. Note that config_port
* is expected to claim the resources and map the port for us.
*/
有关的一些标志位,通过port->ops->config_port(port, flags)这个函数进行。是在下面这个结构中的函数,和具体硬件有关。这个结构体在第一篇中,也有说明。
/*
* 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);
......
void (*set_ldisc)(struct uart_port *);
void (*pm)(struct uart_port *, unsigned int state,
unsigned int oldstate);
int (*set_wake)(struct uart_port *, unsigned int state);
.....
/*
* 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 *);
........
};
};
flags = UART_CONFIG_TYPE;
if (port->flags & UPF_AUTO_IRQ)
flags |= UART_CONFIG_IRQ;
if (port->flags & UPF_BOOT_AUTOCONF) {
port->type = PORT_UNKNOWN;
port->ops->config_port(port, flags);
}
if (port->type != PORT_UNKNOWN) {
unsigned long flags;
......
/*Power up port for set_mctrl() */
uart_change_pm(state, 0);和电源管理有关
/*
*Ensure that the modem control lines are de-activated.
* keep the DTR setting that is set in uart_set_options()
* We probably don't need a spinlock around this, but
*/和流控制有关
spin_lock_irqsave(&port->lock, flags);
port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);
spin_unlock_irqrestore(&port->lock, flags);
.........
}
}
/*
* 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, port->line, port->dev);这个函数以前也说过,主要和sysfs文件系统有关。
.........
return ret;
}
对应的uart_remove_one_port函数就不讲了。源码如下:
/**
* uart_remove_one_port - detach a driver defined port structure
* @drv: pointer to the uart low level driver structure for this port
* @port: uart port structure for this port
*
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
{
......
/*
* Remove the devices from the tty layer
*/
tty_unregister_device(drv->tty_driver, port->line);
info = state->info;
if (info && info->port.tty)
tty_vhangup(info->port.tty);
/*
* All users of this port should now be disconnected from
* this driver, and the port shut down. We should be the
* only thread fiddling with this port from now on.
*/
state->info = NULL;
/*
* Free the port IO and memory resources, if any.
*/
if (port->type != PORT_UNKNOWN)
port->ops->release_port(port);
/*
* Indicate that there isn't a port here anymore.
*/
port->type = PORT_UNKNOWN;
/*
* Kill the tasklet, and free resources.
*/
.......
}
看这些注释,就可以明白个大概。