Как эта функция может выполнить операцию записи без записи в «Регистр передатчика»? - PullRequest
0 голосов
/ 11 апреля 2020

Вот код из 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: вот ссылка на этот драйвер: Ссылка на драйвер

1 Ответ

1 голос
/ 11 апреля 2020

Похоже, что функция помещает байты в буфер и разрешает прерывание передачи. Программа обработки прерываний, вероятно, записывает данные в регистр передачи UART.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...