📄 cpm_uart_core.c
字号:
.ops = &cpm_uart_pops, .iotype = UPIO_MEM, .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC2].port.lock), }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = scc2_lineif, .wait_closing = SCC_WAIT_CLOSING, }, [UART_SCC3] = { .port = { .irq = SCC3_IRQ, .ops = &cpm_uart_pops, .iotype = UPIO_MEM, .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC3].port.lock), }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = scc3_lineif, .wait_closing = SCC_WAIT_CLOSING, }, [UART_SCC4] = { .port = { .irq = SCC4_IRQ, .ops = &cpm_uart_pops, .iotype = UPIO_MEM, .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC4].port.lock), }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = scc4_lineif, .wait_closing = SCC_WAIT_CLOSING, },};int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con){ struct resource *r; struct fs_uart_platform_info *pdata = pdev->dev.platform_data; int idx; /* It is UART_SMCx or UART_SCCx index */ struct uart_cpm_port *pinfo; int line; u32 mem, pram; idx = pdata->fs_no = fs_uart_get_id(pdata); line = cpm_uart_id2nr(idx); if(line < 0) { printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx); return -EINVAL; } pinfo = (struct uart_cpm_port *) &cpm_uart_ports[idx]; pinfo->brg = pdata->brg; if (!is_con) { pinfo->port.line = line; pinfo->port.flags = UPF_BOOT_AUTOCONF; } if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"))) return -EINVAL; mem = (u32)ioremap(r->start, r->end - r->start + 1); if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram"))) return -EINVAL; pram = (u32)ioremap(r->start, r->end - r->start + 1); if(idx > fsid_smc2_uart) { pinfo->sccp = (scc_t *)mem; pinfo->sccup = (scc_uart_t *)pram; } else { pinfo->smcp = (smc_t *)mem; pinfo->smcup = (smc_uart_t *)pram; } pinfo->tx_nrfifos = pdata->tx_num_fifo; pinfo->tx_fifosize = pdata->tx_buf_size; pinfo->rx_nrfifos = pdata->rx_num_fifo; pinfo->rx_fifosize = pdata->rx_buf_size; pinfo->port.uartclk = pdata->uart_clk; pinfo->port.mapbase = (unsigned long)mem; pinfo->port.irq = platform_get_irq(pdev, 0); return 0;}#endif#ifdef CONFIG_SERIAL_CPM_CONSOLE/* * Print a string to the serial port trying not to disturb * any possible real use of the port... * * Note that this is called with interrupts already disabled */static void cpm_uart_console_write(struct console *co, const char *s, u_int count){#ifdef CONFIG_PPC_CPM_NEW_BINDING struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index];#else struct uart_cpm_port *pinfo = &cpm_uart_ports[cpm_uart_port_map[co->index]];#endif unsigned int i; cbd_t __iomem *bdp, *bdbase; unsigned char *cp; /* Get the address of the host memory buffer. */ bdp = pinfo->tx_cur; bdbase = pinfo->tx_bd_base; /* * Now, do each character. This is not as bad as it looks * since this is a holding FIFO and not a transmitting FIFO. * We could add the complexity of filling the entire transmit * buffer, but we would just wait longer between accesses...... */ for (i = 0; i < count; i++, s++) { /* Wait for transmitter fifo to empty. * Ready indicates output is ready, and xmt is doing * that, not that it is ready for us to send. */ while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; /* Send the character out. * If the buffer address is in the CPM DPRAM, don't * convert it. */ cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); *cp = *s; out_be16(&bdp->cbd_datlen, 1); setbits16(&bdp->cbd_sc, BD_SC_READY); if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = bdbase; else bdp++; /* if a LF, also do CR... */ if (*s == 10) { while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); *cp = 13; out_be16(&bdp->cbd_datlen, 1); setbits16(&bdp->cbd_sc, BD_SC_READY); if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = bdbase; else bdp++; } } /* * Finally, Wait for transmitter & holding register to empty * and restore the IER */ while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; pinfo->tx_cur = bdp;}static int __init cpm_uart_console_setup(struct console *co, char *options){ int baud = 38400; int bits = 8; int parity = 'n'; int flow = 'n'; int ret; struct uart_cpm_port *pinfo; struct uart_port *port;#ifdef CONFIG_PPC_CPM_NEW_BINDING struct device_node *np = NULL; int i = 0; if (co->index >= UART_NR) { printk(KERN_ERR "cpm_uart: console index %d too high\n", co->index); return -ENODEV; } do { np = of_find_node_by_type(np, "serial"); if (!np) return -ENODEV; if (!of_device_is_compatible(np, "fsl,cpm1-smc-uart") && !of_device_is_compatible(np, "fsl,cpm1-scc-uart") && !of_device_is_compatible(np, "fsl,cpm2-smc-uart") && !of_device_is_compatible(np, "fsl,cpm2-scc-uart")) i--; } while (i++ != co->index); pinfo = &cpm_uart_ports[co->index]; pinfo->flags |= FLAG_CONSOLE; port = &pinfo->port; ret = cpm_uart_init_port(np, pinfo); of_node_put(np); if (ret) return ret;#else struct fs_uart_platform_info *pdata; struct platform_device* pdev = early_uart_get_pdev(co->index); if (!pdev) { pr_info("cpm_uart: console: compat mode\n"); /* compatibility - will be cleaned up */ cpm_uart_init_portdesc(); } port = (struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]]; pinfo = (struct uart_cpm_port *)port; if (!pdev) { if (pinfo->set_lineif) pinfo->set_lineif(pinfo); } else { pdata = pdev->dev.platform_data; if (pdata) if (pdata->init_ioports) pdata->init_ioports(pdata); cpm_uart_drv_get_platform_data(pdev, 1); } pinfo->flags |= FLAG_CONSOLE;#endif if (options) { uart_parse_options(options, &baud, &parity, &bits, &flow); } else { if ((baud = uart_baudrate()) == -1) baud = 9600; }#ifdef CONFIG_PPC_EARLY_DEBUG_CPM udbg_putc = NULL;#endif cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); if (IS_SMC(pinfo)) { clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX); clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); } else { clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX); clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); } ret = cpm_uart_allocbuf(pinfo, 1); if (ret) return ret; cpm_uart_initbd(pinfo); if (IS_SMC(pinfo)) cpm_uart_init_smc(pinfo); else cpm_uart_init_scc(pinfo); uart_set_options(port, co, baud, parity, bits, flow); cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX); return 0;}static struct uart_driver cpm_reg;static struct console cpm_scc_uart_console = { .name = "ttyCPM", .write = cpm_uart_console_write, .device = uart_console_device, .setup = cpm_uart_console_setup, .flags = CON_PRINTBUFFER, .index = -1, .data = &cpm_reg,};static int __init cpm_uart_console_init(void){ register_console(&cpm_scc_uart_console); return 0;}console_initcall(cpm_uart_console_init);#define CPM_UART_CONSOLE &cpm_scc_uart_console#else#define CPM_UART_CONSOLE NULL#endifstatic struct uart_driver cpm_reg = { .owner = THIS_MODULE, .driver_name = "ttyCPM", .dev_name = "ttyCPM", .major = SERIAL_CPM_MAJOR, .minor = SERIAL_CPM_MINOR, .cons = CPM_UART_CONSOLE, .nr = UART_NR,};#ifdef CONFIG_PPC_CPM_NEW_BINDINGstatic int probe_index;static int __devinit cpm_uart_probe(struct of_device *ofdev, const struct of_device_id *match){ int index = probe_index++; struct uart_cpm_port *pinfo = &cpm_uart_ports[index]; int ret; pinfo->port.line = index; if (index >= UART_NR) return -ENODEV; dev_set_drvdata(&ofdev->dev, pinfo); ret = cpm_uart_init_port(ofdev->node, pinfo); if (ret) return ret; return uart_add_one_port(&cpm_reg, &pinfo->port);}static int __devexit cpm_uart_remove(struct of_device *ofdev){ struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev); return uart_remove_one_port(&cpm_reg, &pinfo->port);}static struct of_device_id cpm_uart_match[] = { { .compatible = "fsl,cpm1-smc-uart", }, { .compatible = "fsl,cpm1-scc-uart", }, { .compatible = "fsl,cpm2-smc-uart", }, { .compatible = "fsl,cpm2-scc-uart", }, {}};static struct of_platform_driver cpm_uart_driver = { .name = "cpm_uart", .match_table = cpm_uart_match, .probe = cpm_uart_probe, .remove = cpm_uart_remove, };static int __init cpm_uart_init(void){ int ret = uart_register_driver(&cpm_reg); if (ret) return ret; ret = of_register_platform_driver(&cpm_uart_driver); if (ret) uart_unregister_driver(&cpm_reg); return ret;}static void __exit cpm_uart_exit(void){ of_unregister_platform_driver(&cpm_uart_driver); uart_unregister_driver(&cpm_reg);}#elsestatic int cpm_uart_drv_probe(struct device *dev){ struct platform_device *pdev = to_platform_device(dev); struct fs_uart_platform_info *pdata; int ret = -ENODEV; if(!pdev) { printk(KERN_ERR"CPM UART: platform data missing!\n"); return ret; } pdata = pdev->dev.platform_data; if ((ret = cpm_uart_drv_get_platform_data(pdev, 0))) return ret; pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no)); if (pdata->init_ioports) pdata->init_ioports(pdata); ret = uart_add_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port); return ret;}static int cpm_uart_drv_remove(struct device *dev){ struct platform_device *pdev = to_platform_device(dev); struct fs_uart_platform_info *pdata = pdev->dev.platform_data; pr_debug("cpm_uart_drv_remove: Removing CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no)); uart_remove_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port); return 0;}static struct device_driver cpm_smc_uart_driver = { .name = "fsl-cpm-smc:uart", .bus = &platform_bus_type, .probe = cpm_uart_drv_probe, .remove = cpm_uart_drv_remove,};static struct device_driver cpm_scc_uart_driver = { .name = "fsl-cpm-scc:uart", .bus = &platform_bus_type, .probe = cpm_uart_drv_probe, .remove = cpm_uart_drv_remove,};/* This is supposed to match uart devices on platform bus, */static int match_is_uart (struct device* dev, void* data){ struct platform_device* pdev = container_of(dev, struct platform_device, dev); int ret = 0; /* this was setfunc as uart */ if(strstr(pdev->name,":uart")) { ret = 1; } return ret;}static int cpm_uart_init(void) { int ret; int i; struct device *dev; printk(KERN_INFO "Serial: CPM driver $Revision: 0.02 $\n"); /* lookup the bus for uart devices */ dev = bus_find_device(&platform_bus_type, NULL, 0, match_is_uart); /* There are devices on the bus - all should be OK */ if (dev) { cpm_uart_count(); cpm_reg.nr = cpm_uart_nr; if (!(ret = uart_register_driver(&cpm_reg))) { if ((ret = driver_register(&cpm_smc_uart_driver))) { uart_unregister_driver(&cpm_reg); return ret; } if ((ret = driver_register(&cpm_scc_uart_driver))) { driver_unregister(&cpm_scc_uart_driver); uart_unregister_driver(&cpm_reg); } } } else { /* No capable platform devices found - falling back to legacy mode */ pr_info("cpm_uart: WARNING: no UART devices found on platform bus!\n"); pr_info( "cpm_uart: the driver will guess configuration, but this mode is no longer supported.\n"); /* Don't run this again, if the console driver did it already */ if (cpm_uart_nr == 0) cpm_uart_init_portdesc(); cpm_reg.nr = cpm_uart_nr; ret = uart_register_driver(&cpm_reg); if (ret) return ret; for (i = 0; i < cpm_uart_nr; i++) { int con = cpm_uart_port_map[i]; cpm_uart_ports[con].port.line = i; cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF; if (cpm_uart_ports[con].set_lineif) cpm_uart_ports[con].set_lineif(&cpm_uart_ports[con]); uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port); } } return ret;}static void __exit cpm_uart_exit(void){ driver_unregister(&cpm_scc_uart_driver); driver_unregister(&cpm_smc_uart_driver); uart_unregister_driver(&cpm_reg);}#endifmodule_init(cpm_uart_init);module_exit(cpm_uart_exit);MODULE_AUTHOR("Kumar Gala/Antoniou Pantelis");MODULE_DESCRIPTION("CPM SCC/SMC port driver $Revision: 0.01 $");MODULE_LICENSE("GPL");MODULE_ALIAS_CHARDEV(SERIAL_CPM_MAJOR, SERIAL_CPM_MINOR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -