0

这是来自的代码rt_imx_uart.c

static ssize_t rt_imx_uart_write(struct rtdm_fd *fd, const void *buf,
                size_t nbyte)
{
    struct rt_imx_uart_ctx *ctx;
    rtdm_lockctx_t lock_ctx;
    size_t written = 0;
    int free;
    int block;
    int subblock;
    int out_pos;
    char *in_pos = (char *)buf;
    rtdm_toseq_t timeout_seq;
    ssize_t ret;

    if (nbyte == 0)
        return 0;

    if (rtdm_fd_is_user(fd) && !rtdm_read_user_ok(fd, buf, nbyte))
        return -EFAULT;

    ctx = rtdm_fd_to_private(fd);

    rtdm_toseq_init(&timeout_seq, ctx->config.rx_timeout);

    /* Make write operation atomic. */
    ret = rtdm_mutex_timedlock(&ctx->out_lock, ctx->config.rx_timeout,
                   &timeout_seq);
    if (ret)
        return ret;

    while (nbyte > 0) {
        rtdm_lock_get_irqsave(&ctx->lock, lock_ctx);

        free = OUT_BUFFER_SIZE - ctx->out_npend;

        if (free > 0) {
            block = subblock = (nbyte <= free) ? nbyte : free;
            out_pos = ctx->out_tail;

            rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);

            /* Do we have to wrap around the buffer end? */
            if (out_pos + subblock > OUT_BUFFER_SIZE) {
                /* Treat the block between head and buffer
                 * end separately.
                 */
                subblock = OUT_BUFFER_SIZE - out_pos;

                if (rtdm_fd_is_user(fd)) {
                    if (rtdm_copy_from_user
                        (fd,
                         &ctx->out_buf[out_pos],
                         in_pos, subblock) != 0) {
                        ret = -EFAULT;
                        break;
                    }
                } else
                    memcpy(&ctx->out_buf[out_pos], in_pos,
                           subblock);

                written += subblock;
                in_pos += subblock;

                subblock = block - subblock;
                out_pos = 0;
            }

            if (rtdm_fd_is_user(fd)) {
                if (rtdm_copy_from_user
                    (fd, &ctx->out_buf[out_pos],
                     in_pos, subblock) != 0) {
                    ret = -EFAULT;
                    break;
                }
            } else
                memcpy(&ctx->out_buf[out_pos], in_pos, block);

            written += subblock;
            in_pos += subblock;
            nbyte -= block;

            rtdm_lock_get_irqsave(&ctx->lock, lock_ctx);

            ctx->out_tail =
                (ctx->out_tail + block) & (OUT_BUFFER_SIZE - 1);
            ctx->out_npend += block;

            ctx->ier_status |= IER_TX;
            rt_imx_uart_start_tx(ctx);

            rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);
            continue;
        }

        rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);

        ret = rtdm_event_timedwait(&ctx->out_event,
                       ctx->config.tx_timeout,
                       &timeout_seq);
        if (ret < 0) {
            if (ret == -EIDRM) {
                /* Device has been closed -
                 * return immediately.
                 */
                ret = -EBADF;
            }
            break;
        }
    }

    rtdm_mutex_unlock(&ctx->out_lock);

    if ((written > 0) && ((ret == 0) || (ret == -EAGAIN) ||
                  (ret == -ETIMEDOUT)))
        ret = written;

    return ret;
}

我了解此功能是在用户空间程序想要写入设备时使用的。但是我不明白这个函数是如何做到的,因为我们在程序中没有任何地方写入发送器寄存器。使用的 start_tx 函数仅启用一个标志,仅此而已。

PS:这里是这个驱动的链接:链接到驱动

4

1 回答 1

1

看起来该函数将字节放入缓冲区并启用发送中断。中断服务程序可能会写入 uart 发送寄存器。

于 2020-04-11T18:30:55.317 回答