在分析tty层时,tty_driver中有一个ttys成员保存每个设备的tty_struct列表,在uart层uart_driver和uart_state的关系也类似,如图
1.uart_driver的注册
-
int uart_register_driver(struct uart_driver *drv)
-
{
-
struct tty_driver *normal = NULL;
-
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); //根据设备数申请uart_stata
-
retval = -ENOMEM;
-
if (!drv->state)
-
goto out;
-
-
normal = alloc_tty_driver(drv->nr); //分配tty_driver空间
-
if (!normal)
-
goto out;
-
-
drv->tty_driver = normal; //将申请的tty_driver,关联给uart_driver中的tty_driver成员
-
-
//像tty驱动程序那样设置tty_driver的成员参数,从uart_driver中复制给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; //TTY_DRIVER_DYNAMIC_DEV标志使得不会再tty_register_driver时注册device
-
normal->driver_state = drv;
-
tty_set_operations(normal, &uart_ops); //tty的操作函数设置成uart_ops
-
-
/*
-
* Initialise the UART state(s). 初始化uart_state
-
*/
-
for (i = 0; i < drv->nr; i++) {
-
struct uart_state *state = drv->state + i;
-
struct tty_port *port = &state->port;
-
-
tty_port_init(port); //初始化tty_port
-
port->close_delay = 500; /* .5 seconds */
-
port->closing_wait = 30000; /* 30 seconds */
-
tasklet_init(&state->tlet, uart_tasklet_action,
-
(unsigned long)state);
-
}
-
-
retval = tty_register_driver(normal); //注册tty_driver,最重要的环节
-
out:
-
if (retval < 0) {
-
put_tty_driver(normal);
-
kfree(drv->state);
-
}
-
return retval;
-
}
2.添加一个串口信息uart_add_one_port函数
-
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) //当然,uport的设备号,不能大于这个驱动中次设备数量
-
return -EINVAL;
-
-
state = drv->state + uport->line; //此uport对应的driver中的state
-
port = &state->port; //对应state中的tty_port
-
-
mutex_lock(&port_mutex);
-
mutex_lock(&port->mutex);
-
if (state->uart_port) { //此state不能已经关联了uport
-
ret = -EINVAL;
-
goto out;
-
}
-
-
state->uart_port = uport; //将此uport关联给此state的uport指针
-
state->pm_state = -1; //默认电源状态关闭
-
-
uport->cons = drv->cons; //驱动的控制台
-
uport->state = state; //互联uport的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); //配置一下串口
-
-
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) //必须有iobase,mapbase,membase
-
return;
-
-
/*
-
* Now do the auto configuration stuff. Note that config_port
-
* is expected to claim the resources and map the port for us.
-
*/
-
flags = 0;
-
if (port->flags & UPF_AUTO_IRQ)
-
flags |= UART_CONFIG_IRQ;
-
if (port->flags & UPF_BOOT_AUTOCONF) {
-
if (!(port->flags & UPF_FIXED_TYPE)) {
-
port->type = PORT_UNKNOWN;
-
flags |= UART_CONFIG_TYPE;
-
}
-
port->ops->config_port(port, flags); //调用操作集中的config_port函数
-
}
-
-
if (port->type != PORT_UNKNOWN) {
-
unsigned long flags;
-
-
uart_report_port(drv, port); //打印一些串口的信息
-
-
/* Power up port for set_mctrl() */
-
uart_change_pm(state, 0); //调用ops中驱动的pm函数上电
-
-
/*
-
* 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); //调用驱动的set_mctrl
-
spin_unlock_irqrestore(&port->lock, flags);
-
-
/*
-
* If this driver supports console, and it hasn't been
-
* successfully registered yet, try to re-register it.
-
* It may be that the port was not available.
-
*/
-
if (port->cons && !(port->cons->flags & CON_ENABLED))
-
register_console(port->cons); //如果是控制台 注册控制台
-
-
/*
-
* Power down all ports by default, except the
-
* console if we have one.
-
*/
-
if (!uart_console(port))
-
uart_change_pm(state, 3); //不是控制台,Power down
-
}
-
}
-
-
/*
-
* 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); //产生一个device设备,若有udev则将产生设备节点
-
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 %dn",
-
uport->line);
-
-
/*
-
* Ensure UPF_DEAD is not set.
-
*/
-
uport->flags &= ~UPF_DEAD;
-
-
out:
-
mutex_unlock(&port->mutex);
-
mutex_unlock(&port_mutex);
-
-
return ret;
-
}
3.uart函数操作集
uart_ops是uart层实现tty层提供的需要实现的操作,即实现一个tty_operations。
-
static const struct tty_operations uart_ops = {
-
.open = uart_open,
-
.close = uart_close,
-
.write = uart_write,
-
.put_char = uart_put_char,
-
.flush_chars = uart_flush_chars,
-
.write_room = uart_write_room,
-
.chars_in_buffer= uart_chars_in_buffer,
-
.flush_buffer = uart_flush_buffer,
-
.ioctl = uart_ioctl,
-
.throttle = uart_throttle,
-
.unthrottle = uart_unthrottle,
-
.send_xchar = uart_send_xchar,
-
.set_termios = uart_set_termios,
-
.set_ldisc = uart_set_ldisc,
-
.stop = uart_stop,
-
.start = uart_start,
-
.hangup = uart_hangup,
-
.break_ctl = uart_break_ctl,
-
.wait_until_sent= uart_wait_until_sent,
-
#ifdef CONFIG_PROC_FS
-
.proc_fops = &uart_proc_fops,
-
#endif
-
.tiocmget = uart_tiocmget,
-
.tiocmset = uart_tiocmset,
-
#ifdef CONFIG_CONSOLE_POLL
-
.poll_init = uart_poll_init,
-
.poll_get_char = uart_poll_get_char,
-
.poll_put_char = uart_poll_put_char,
-
#endif
-
};
下一节我们将分析这其中的一些函数
阅读(926) | 评论(0) | 转发(0) |