On 05/05/2016 12:30 PM, Greg KH wrote: > On Thu, May 05, 2016 at 06:23:12PM +0000, Andy Falanga (afalanga) wrote: >> I'm writing my first serial driver for a UART (AXI UART Lite from >> Xilinx). Yes, I know there's one in the kernel but the hardware in this >> case isn't embedded. >> >> Using the documentation in <kernel_src>/Documentation/serial/driver and >> the existing code for references, I've implemented my driver. However, >> I cannot validate the my startup or request_port functions are being >> called. >> >> I'm calling uart_register_driver() and then uart_register_port() and I'm >> sure these functions are passing. I'm seeing my device handles show in >> /dev. The documentation states that the startup() function, "... will >> only be called when the port is initially opened." Yet, I'm not seeing >> pr_info() messages that I should be. What should I look for in order to >> determine why the setup functions aren't being called? > Are you sure that some other driver isn't being called instead of yours? > > Without seeing the code, it's impossible to debug, please just send a > patch. > > Hi Greg, I had to jump through some hoops in order to send the code. Here's what I've got for driver registration/initialization. #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; } -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html