串行驱动程序启动/请求函数未被执行

时间:2016-05-05 18:51:58

标签: linux linux-kernel driver linux-device-driver uart

我正在为UART编写第一个串行驱动程序(Xilinx的AXI UART Lite)。我知道内核中有一个,但我不是在嵌入式Linux环境中工作。

使用the documentation和现有的引用代码,我实现了我的驱动程序。但是,我无法验证我的startuprequest_port函数是否正在被调用。 启动功能基本上是what this does。但是,我没有使用IRQ进行轮询。同样,我的request_port函数非常相似to this function

文档说明在打开端口时调用the startup function一次。因为我确实在/ dev中有设备节点,所以我想我需要打开端口。在步骤minicom和我打开文件(用lsof验证)。但是,我在dmesg中找不到任何我已放入startuprequest_port函数的邮件。

对于延迟回复感到抱歉,但在发布代码之前我不得不跳过一些箍。这就是我所拥有的:

#define MAX_SUPPORTED_UARTS 1
#define DRIVER_MAJOR_NUM  243  /* local/experimental */
#define DRIVER_MINOR_NUM  0

static int request_port(struct uart_port *);
static void release_port(struct uart_port *);
static int startup(struct uart_port *);
static void shutdown(struct uart_port *);

static struct uart_ops axilite_ops = {
    .release_port = release_port,
    .request_port = request_port,
    .startup = startup,
    .shutdown = shutdown,
};

static struct uart_port axilite_ports[MAX_SUPPORTED_UARTS] = {
    {
        .mapbase = 0, /* determined during discovery */
        .membase = 0, /* calcuated after learning mapbase */
        .iotype = UPIO_MEM, /* from serial_core.c */
        .irq = 0,  /* currently, device doesn't use an IRQ, just polling */
        .fifosize = 16,  /* directly Xilinx documentation */
        .ops = &axilite_ops,
        .flags = UPF_FIXED_TYPE | UPF_FIXED_PORT | UPF_SPD_VHI,
        .mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR, /* from uartlite.c in kernel tree */
    },
};

static struct uart_driver axilite_driver = {
    .owner = THIS_MODULE,
    .driver_name = "axilite",
    .dev_name = "ttyAUL",
    .major = DRIVER_MAJOR_NUM,
    .minor = DRIVER_MINOR_NUM,
    .nr = MAX_SUPPORTED_UARTS,
};

static int startup(struct uart_port *pup)
{
    void __iomem* pmem = pup->membase;
    uint32_t ctlreg = 0;
    pr_info("%s:%d entry point\n", __func__, __LINE__);

    ctlreg = ioread32(CTL_REG_ADDR(pmem));
    pr_info("DEBUG: %s:%d CTL Reg is 0x%08x\n",
            __func__, __LINE__, ctlreg);
    /* clear the FIFO's */
    ctlreg |= CTL_REG_RST_TX | CTL_REG_RST_RX;
    iowrite32(ctlreg, CTL_REG_ADDR(pmem));

    return 0;
}

static void shutdown(struct uart_port *pup)
{
    void __iomem* pmem = pup->membase;

    pr_info("%s:%d entry point\n", __func__, __LINE__);

    /* Using a queue from the axilite driver in the kernel */
    iowrite32(0, CTL_REG_ADDR(pmem));
}

static void release_port(struct uart_port *pup)
{
    pr_info("%s:%d entry point\n", __func__, __LINE__);

    if (pup->membase)
        iounmap(pup->membase);

    pup->membase = NULL;
}

static int request_port(struct uart_port *pup)
{
    int result = 0;
    uint32_t bus_addr = pup->mapbase;
    void __iomem* pmem = NULL;

    pr_info("%s:%d mapping bus addr to virtual space\n",
            __func__, __LINE__);
    pmem = ioremap_nocache(bus_addr, UART_REGISTER_REGION);
    if (IS_ERR_OR_NULL(pmem)) {
        pr_err("%s:%d ioremap_nocache failed\n",
                __func__, __LINE__);
        result = PTR_ERR(pmem);
        goto startup_exit;
    }

    pup->membase = pmem;
    pr_info("%s:%d busaddr 0x%08x mapped to %p\n",
            __func__, __LINE__, bus_addr, pmem);

startup_exit:
    return result;
}

static int add_uart_ports(void)
{
    int result = 0;
    uint32_t i = 0, baseaddr = 0;

    pr_info("%s:%d adding %d port(s) to the system\n",
            __func__, __LINE__, uart_count);

    /* calls into code which learns the base address,
     * verified that it works
     */
    baseaddr = get_uart_base(i);

    if ((int)baseaddr == -EINVAL) {
        pr_err("%s:%d Invalid index used\n", __func__, __LINE__);
        result = (int)baseaddr; 
        goto add_ports_exit;
    }
    else if (0 == baseaddr) {
        pr_err("%s:%d Invalid bus address encountered, port add stopped\n",
                __func__, __LINE__);
        result = -ENODEV;
        goto add_ports_exit;
    }
    else
        axilite_port[i].mapbase = baseaddr;

    result = uart_add_one_port(&axilite_driver, &axilite_port[i]);
    if (result) {
        pr_err("%s:%d uart_add_one_port failed for port %d\n",
                __func__, __LINE__, i);
        goto add_ports_exit;
    }

    /* TODO think of a better way to track whether the port
     * is registered.  this will work for now.
     */
    axilite_port[i].private_data = &uart_count;

    init_stage |= UART_PORT_REGISTERED;

add_ports_exit:

    return result;
}

static int add_uart_driver(void)
{
    int result = 0;
    pr_info("%s:%d adding the driver\n", __func__, __LINE__);

    uart_count = get_uart_count();
    axilite_driver.nr = (int)uart_count;

    result = uart_register_driver(&axilite_driver);
    if (result) {
        pr_err("%s:%d uart_register_driver failed\n",
                __func__, __LINE__);
        goto add_driver_exit;
    }

    init_stage |= DRIVER_REGISTERED;

add_driver_exit:
    return result;
}

修改

我没有添加平台驱动程序。虽然这是Xilinx系统,但我的驱动程序不会在嵌入式Linux中运行。鉴于此,我认为驱动程序启动类似于the driver for 21285。这是错误的吗?

结束编辑

可能导致这种情况的原因是什么?我应该做什么或检查?

安迪

2 个答案:

答案 0 :(得分:1)

http://schemas.xmlsoap.org/ws/2003/06/secext方法中,开头有代码:

serial_core.c uart_port_startup

这就是为什么不调用启动方法的原因。您需要将 if (uport->type == PORT_UNKNOWN) return 1; 设置为非未知值。至少它对我有用。您可能需要添加新的PORT_类型或使用现有类型 - 不确定冲突。 对于我的虚拟设备,这有效:

struct uart_port.type

答案 1 :(得分:0)

您是否提供平台数据?驱动程序本身是不够的,你必须向内核提供硬件所在的信息,映射到特定基址的内存,连接到特定的中断等等......在现代ARM系统上,你这样做通过设备树,其他系统有不同的手段。只有在提供这些数据后才会加载并启动驱动程序。