首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

linux设备模型之uart驱动架构分析 03

linux设备模型之uart驱动架构分析 03

struct uart_state *state;
    int ret = 0;
    state = drv->state + line;
    if (mutex_lock_interruptible(&state->mutex)) {
    ret = -ERESTARTSYS;
    goto err;
    }
    state->count++;
    if (!state->port || state->port->flags & UPF_DEAD) {
    ret = -ENXIO;
    goto err_unlock;
    }
    if (!state->info) {
    state->info = kzalloc(sizeof(struct uart_info), GFP_KERNEL);
    if (state->info) {
    init_waitqueue_head(&state->info->open_wait);
    init_waitqueue_head(&state->info->delta_msr_wait);
    /*
    * Link the info into the other structures.
    */
    state->port->info = state->info;
    tasklet_init(&state->info->tlet, uart_tasklet_action,
    (unsigned long)state);
    } else {
    ret = -ENOMEM;
    goto err_unlock;
    }
    }
    return state;
    err_unlock:
    state->count--;
    mutex_unlock(&state->mutex);
    err:
    return ERR_PTR(ret);
    }
    从代码中可以看出。这里注要是操作是初始化state->info.注意port->info就是state->info的一个副本。即port直接通过port->info可以找到它要操作的缓存区。
    uart_startup()代码如下:
    static int uart_startup(struct uart_state *state, int init_hw)
    {
    struct uart_info *info = state->info;
    struct uart_port *port = state->port;
    unsigned long page;
    int retval = 0;
    if (info->flags & UIF_INITIALIZED)
    return 0;
    /*
    * Set the TTY IO error marker - we will only clear this
    * once we have successfully opened the port.  Also set
    * up the tty->alt_speed kludge
    */
    set_bit(TTY_IO_ERROR, &info->tty->flags);
    if (port->type == PORT_UNKNOWN)
    return 0;
    /*
    * Initialise and allocate the transmit and temporary
    * buffer.
    */
    if (!info->xmit.buf) {
    page = get_zeroed_page(GFP_KERNEL);
    if (!page)
    return -ENOMEM;
    info->xmit.buf = (unsigned char *) page;
    uart_circ_clear(&info->xmit);
    }
    retval = port->ops->startup(port);
    if (retval == 0) {
    if (init_hw) {
    /*
    * Initialise the hardware port settings.
    */
    uart_change_speed(state, NULL);
    /*
    * Setup the RTS and DTR signals once the
    * port is open and ready to respond.
    */
    if (info->tty->termios->c_cflag & CBAUD)
    uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
    }
    if (info->flags & UIF_CTS_FLOW) {
    spin_lock_irq(&port->lock);
    if (!(port->ops->get_mctrl(port) & TIOCM_CTS))
    info->tty->hw_stopped = 1;
    spin_unlock_irq(&port->lock);
    }
    info->flags |= UIF_INITIALIZED;
    clear_bit(TTY_IO_ERROR, &info->tty->flags);
    }
    if (retval && capable(CAP_SYS_ADMIN))
    retval = 0;
    return retval;
    }
    在这里,注要完成对环形缓冲,即info->xmit的初始化。然后调用port->ops->startup( )将这个port带入到工作状态。其它的是一个可调参数的设置,就不详细讲解了。
    七:设备节点的write操作
    Write操作对应的操作接口为uart_write( )。代码如下:
    static int
    uart_write(struct tty_struct *tty, const unsigned char *buf, int count)
    {
    struct uart_state *state = tty->driver_data;
    struct uart_port *port;
    struct circ_buf *circ;
    unsigned long flags;
    int c, ret = 0;
    /*
    * This means you called this function _after_ the port was
    * closed.  No cookie for you.
    */
    if (!state || !state->info) {
    WARN_ON(1);
    return -EL3HLT;
    }
    port = state->port;
    circ = &state->info->xmit;
    if (!circ->buf)
    return 0;
    spin_lock_irqsave(&port->lock, flags);
    while (1) {
    c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
    if (count < c)
    c = count;
    if (c <= 0)
    break;
    memcpy(circ->buf + circ->head, buf, c);
    circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
    buf += c;
    count -= c;
    ret += c;
    }
    spin_unlock_irqrestore(&port->lock, flags);
    uart_start(tty);
    return ret;
    }
    Uart_start()代码如下:
    static void uart_start(struct tty_struct *tty)
    {
    struct uart_state *state = tty->driver_data;
    struct uart_port *port = state->port;
    unsigned long flags;
    spin_lock_irqsave(&port->lock, flags);
    __uart_start(tty);
    spin_unlock_irqrestore(&port->lock, flags);
    }
    static void __uart_start(struct tty_struct *tty)
    {
    struct uart_state *state = tty->driver_data;
    struct uart_port *port = state->port;

    if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf &&
    !tty->stopped && !tty->hw_stopped)
    port->ops->start_tx(port);
    }
    显然,对于write操作而言,它就是将数据copy到环形缓存区。然后调用port->ops->start_tx()将数据写到硬件寄存器。
    八:Read操作
    Uart的read操作同Tty的read操作相同,即都是调用ldsic->read()读取read_buf中的内容。有对这部份内容不太清楚的,参阅《 linux设备模型之tty驱动架构》.
    九:小结
    本小节是分析serial驱动的基础。在理解了tty驱动架构之后,再来理解uart驱动架构应该不是很难。随着我们在linux设备驱动分析的深入,越来越深刻的体会到,linux的设备驱动架构很多都是相通的。只要深刻理解了一种驱动架构。举一反三。也就很容易分析出其它架构的驱动了。
返回列表