📄 mpsc.c
字号:
else if (pi->port.uartclk / 16 != ser->baud_base) /* Not sure */ rc = -EINVAL; else if ((void *)pi->port.mapbase != ser->iomem_base) rc = -EINVAL; else if (pi->port.iobase != ser->port) rc = -EINVAL; else if (ser->hub6 != 0) rc = -EINVAL; return rc;}static struct uart_ops mpsc_pops = { .tx_empty = mpsc_tx_empty, .set_mctrl = mpsc_set_mctrl, .get_mctrl = mpsc_get_mctrl, .stop_tx = mpsc_stop_tx, .start_tx = mpsc_start_tx, .stop_rx = mpsc_stop_rx, .enable_ms = mpsc_enable_ms, .break_ctl = mpsc_break_ctl, .startup = mpsc_startup, .shutdown = mpsc_shutdown, .set_termios = mpsc_set_termios, .type = mpsc_type, .release_port = mpsc_release_port, .request_port = mpsc_request_port, .config_port = mpsc_config_port, .verify_port = mpsc_verify_port,};/* ****************************************************************************** * * Console Interface Routines * ****************************************************************************** */#ifdef CONFIG_SERIAL_MPSC_CONSOLEstatic void mpsc_console_write(struct console *co, const char *s, uint count){ struct mpsc_port_info *pi = &mpsc_ports[co->index]; u8 *bp, *dp, add_cr = 0; int i; unsigned long iflags; spin_lock_irqsave(&pi->tx_lock, iflags); while (pi->txr_head != pi->txr_tail) { while (mpsc_sdma_tx_active(pi)) udelay(100); mpsc_sdma_intr_ack(pi); mpsc_tx_intr(pi); } while (mpsc_sdma_tx_active(pi)) udelay(100); while (count > 0) { bp = dp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE); for (i = 0; i < MPSC_TXBE_SIZE; i++) { if (count == 0) break; if (add_cr) { *(dp++) = '\r'; add_cr = 0; } else { *(dp++) = *s; if (*(s++) == '\n') { /* add '\r' after '\n' */ add_cr = 1; count++; } } count--; } dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE, DMA_BIDIRECTIONAL);#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ flush_dcache_range((ulong)bp, (ulong)bp + MPSC_TXBE_SIZE);#endif mpsc_setup_tx_desc(pi, i, 0); pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1); mpsc_sdma_start_tx(pi); while (mpsc_sdma_tx_active(pi)) udelay(100); pi->txr_tail = (pi->txr_tail + 1) & (MPSC_TXR_ENTRIES - 1); } spin_unlock_irqrestore(&pi->tx_lock, iflags);}static int __init mpsc_console_setup(struct console *co, char *options){ struct mpsc_port_info *pi; int baud, bits, parity, flow; pr_debug("mpsc_console_setup[%d]: options: %s\n", co->index, options); if (co->index >= MPSC_NUM_CTLRS) co->index = 0; pi = &mpsc_ports[co->index]; baud = pi->default_baud; bits = pi->default_bits; parity = pi->default_parity; flow = pi->default_flow; if (!pi->port.ops) return -ENODEV; spin_lock_init(&pi->port.lock); /* Temporary fix--copied from 8250.c */ if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); return uart_set_options(&pi->port, co, baud, parity, bits, flow);}static struct console mpsc_console = { .name = MPSC_DEV_NAME, .write = mpsc_console_write, .device = uart_console_device, .setup = mpsc_console_setup, .flags = CON_PRINTBUFFER, .index = -1, .data = &mpsc_reg,};static int __init mpsc_late_console_init(void){ pr_debug("mpsc_late_console_init: Enter\n"); if (!(mpsc_console.flags & CON_ENABLED)) register_console(&mpsc_console); return 0;}late_initcall(mpsc_late_console_init);#define MPSC_CONSOLE &mpsc_console#else#define MPSC_CONSOLE NULL#endif/* ****************************************************************************** * * Dummy Platform Driver to extract & map shared register regions * ****************************************************************************** */static void mpsc_resource_err(char *s){ printk(KERN_WARNING "MPSC: Platform device resource error in %s\n", s);}static int mpsc_shared_map_regs(struct platform_device *pd){ struct resource *r; if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_ROUTING_BASE_ORDER)) && request_mem_region(r->start, MPSC_ROUTING_REG_BLOCK_SIZE, "mpsc_routing_regs")) { mpsc_shared_regs.mpsc_routing_base = ioremap(r->start, MPSC_ROUTING_REG_BLOCK_SIZE); mpsc_shared_regs.mpsc_routing_base_p = r->start; } else { mpsc_resource_err("MPSC routing base"); return -ENOMEM; } if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_SDMA_INTR_BASE_ORDER)) && request_mem_region(r->start, MPSC_SDMA_INTR_REG_BLOCK_SIZE, "sdma_intr_regs")) { mpsc_shared_regs.sdma_intr_base = ioremap(r->start, MPSC_SDMA_INTR_REG_BLOCK_SIZE); mpsc_shared_regs.sdma_intr_base_p = r->start; } else { iounmap(mpsc_shared_regs.mpsc_routing_base); release_mem_region(mpsc_shared_regs.mpsc_routing_base_p, MPSC_ROUTING_REG_BLOCK_SIZE); mpsc_resource_err("SDMA intr base"); return -ENOMEM; } return 0;}static void mpsc_shared_unmap_regs(void){ if (!mpsc_shared_regs.mpsc_routing_base) { iounmap(mpsc_shared_regs.mpsc_routing_base); release_mem_region(mpsc_shared_regs.mpsc_routing_base_p, MPSC_ROUTING_REG_BLOCK_SIZE); } if (!mpsc_shared_regs.sdma_intr_base) { iounmap(mpsc_shared_regs.sdma_intr_base); release_mem_region(mpsc_shared_regs.sdma_intr_base_p, MPSC_SDMA_INTR_REG_BLOCK_SIZE); } mpsc_shared_regs.mpsc_routing_base = NULL; mpsc_shared_regs.sdma_intr_base = NULL; mpsc_shared_regs.mpsc_routing_base_p = 0; mpsc_shared_regs.sdma_intr_base_p = 0;}static int mpsc_shared_drv_probe(struct platform_device *dev){ struct mpsc_shared_pdata *pdata; int rc = -ENODEV; if (dev->id == 0) { if (!(rc = mpsc_shared_map_regs(dev))) { pdata = (struct mpsc_shared_pdata *) dev->dev.platform_data; mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val; mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val; mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val; mpsc_shared_regs.SDMA_INTR_CAUSE_m = pdata->intr_cause_val; mpsc_shared_regs.SDMA_INTR_MASK_m = pdata->intr_mask_val; rc = 0; } } return rc;}static int mpsc_shared_drv_remove(struct platform_device *dev){ int rc = -ENODEV; if (dev->id == 0) { mpsc_shared_unmap_regs(); mpsc_shared_regs.MPSC_MRR_m = 0; mpsc_shared_regs.MPSC_RCRR_m = 0; mpsc_shared_regs.MPSC_TCRR_m = 0; mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0; mpsc_shared_regs.SDMA_INTR_MASK_m = 0; rc = 0; } return rc;}static struct platform_driver mpsc_shared_driver = { .probe = mpsc_shared_drv_probe, .remove = mpsc_shared_drv_remove, .driver = { .name = MPSC_SHARED_NAME, },};/* ****************************************************************************** * * Driver Interface Routines * ****************************************************************************** */static struct uart_driver mpsc_reg = { .owner = THIS_MODULE, .driver_name = MPSC_DRIVER_NAME, .dev_name = MPSC_DEV_NAME, .major = MPSC_MAJOR, .minor = MPSC_MINOR_START, .nr = MPSC_NUM_CTLRS, .cons = MPSC_CONSOLE,};static int mpsc_drv_map_regs(struct mpsc_port_info *pi, struct platform_device *pd){ struct resource *r; if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER)) && request_mem_region(r->start, MPSC_REG_BLOCK_SIZE, "mpsc_regs")) { pi->mpsc_base = ioremap(r->start, MPSC_REG_BLOCK_SIZE); pi->mpsc_base_p = r->start; } else { mpsc_resource_err("MPSC base"); goto err; } if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_SDMA_BASE_ORDER)) && request_mem_region(r->start, MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) { pi->sdma_base = ioremap(r->start,MPSC_SDMA_REG_BLOCK_SIZE); pi->sdma_base_p = r->start; } else { mpsc_resource_err("SDMA base"); if (pi->mpsc_base) { iounmap(pi->mpsc_base); pi->mpsc_base = NULL; } goto err; } if ((r = platform_get_resource(pd,IORESOURCE_MEM,MPSC_BRG_BASE_ORDER)) && request_mem_region(r->start, MPSC_BRG_REG_BLOCK_SIZE, "brg_regs")) { pi->brg_base = ioremap(r->start, MPSC_BRG_REG_BLOCK_SIZE); pi->brg_base_p = r->start; } else { mpsc_resource_err("BRG base"); if (pi->mpsc_base) { iounmap(pi->mpsc_base); pi->mpsc_base = NULL; } if (pi->sdma_base) { iounmap(pi->sdma_base); pi->sdma_base = NULL; } goto err; } return 0;err: return -ENOMEM;}static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi){ if (!pi->mpsc_base) { iounmap(pi->mpsc_base); release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE); } if (!pi->sdma_base) { iounmap(pi->sdma_base); release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE); } if (!pi->brg_base) { iounmap(pi->brg_base); release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE); } pi->mpsc_base = NULL; pi->sdma_base = NULL; pi->brg_base = NULL; pi->mpsc_base_p = 0; pi->sdma_base_p = 0; pi->brg_base_p = 0;}static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi, struct platform_device *pd, int num){ struct mpsc_pdata *pdata; pdata = (struct mpsc_pdata *)pd->dev.platform_data; pi->port.uartclk = pdata->brg_clk_freq; pi->port.iotype = UPIO_MEM; pi->port.line = num; pi->port.type = PORT_MPSC; pi->port.fifosize = MPSC_TXBE_SIZE; pi->port.membase = pi->mpsc_base; pi->port.mapbase = (ulong)pi->mpsc_base; pi->port.ops = &mpsc_pops; pi->mirror_regs = pdata->mirror_regs; pi->cache_mgmt = pdata->cache_mgmt; pi->brg_can_tune = pdata->brg_can_tune; pi->brg_clk_src = pdata->brg_clk_src; pi->mpsc_max_idle = pdata->max_idle; pi->default_baud = pdata->default_baud; pi->default_bits = pdata->default_bits; pi->default_parity = pdata->default_parity; pi->default_flow = pdata->default_flow; /* Initial values of mirrored regs */ pi->MPSC_CHR_1_m = pdata->chr_1_val; pi->MPSC_CHR_2_m = pdata->chr_2_val; pi->MPSC_CHR_10_m = pdata->chr_10_val; pi->MPSC_MPCR_m = pdata->mpcr_val; pi->BRG_BCR_m = pdata->bcr_val; pi->shared_regs = &mpsc_shared_regs; pi->port.irq = platform_get_irq(pd, 0);}static int mpsc_drv_probe(struct platform_device *dev){ struct mpsc_port_info *pi; int rc = -ENODEV; pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id); if (dev->id < MPSC_NUM_CTLRS) { pi = &mpsc_ports[dev->id]; if (!(rc = mpsc_drv_map_regs(pi, dev))) { mpsc_drv_get_platform_data(pi, dev, dev->id); if (!(rc = mpsc_make_ready(pi))) { spin_lock_init(&pi->tx_lock); if (!(rc = uart_add_one_port(&mpsc_reg, &pi->port))) { rc = 0; } else { mpsc_release_port((struct uart_port *) pi); mpsc_drv_unmap_regs(pi); } } else { mpsc_drv_unmap_regs(pi); } } } return rc;}static int mpsc_drv_remove(struct platform_device *dev){ pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id); if (dev->id < MPSC_NUM_CTLRS) { uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port); mpsc_release_port((struct uart_port *) &mpsc_ports[dev->id].port); mpsc_drv_unmap_regs(&mpsc_ports[dev->id]); return 0; } else { return -ENODEV; }}static struct platform_driver mpsc_driver = { .probe = mpsc_drv_probe, .remove = mpsc_drv_remove, .driver = { .name = MPSC_CTLR_NAME, },};static int __init mpsc_drv_init(void){ int rc; printk(KERN_INFO "Serial: MPSC driver $Revision: 1.00 $\n"); memset(mpsc_ports, 0, sizeof(mpsc_ports)); memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs)); if (!(rc = uart_register_driver(&mpsc_reg))) { if (!(rc = platform_driver_register(&mpsc_shared_driver))) { if ((rc = platform_driver_register(&mpsc_driver))) { platform_driver_unregister(&mpsc_shared_driver); uart_unregister_driver(&mpsc_reg); } } else { uart_unregister_driver(&mpsc_reg); } } return rc;}static void __exit mpsc_drv_exit(void){ platform_driver_unregister(&mpsc_driver); platform_driver_unregister(&mpsc_shared_driver); uart_unregister_driver(&mpsc_reg); memset(mpsc_ports, 0, sizeof(mpsc_ports)); memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));}module_init(mpsc_drv_init);module_exit(mpsc_drv_exit);MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver $Revision: 1.00 $");MODULE_VERSION(MPSC_VERSION);MODULE_LICENSE("GPL");MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -