📄 cpm_uart_core.c
字号:
.verify_port = cpm_uart_verify_port,};struct uart_cpm_port cpm_uart_ports[UART_NR] = { [UART_SMC1] = { .port = { .irq = SMC1_IRQ, .ops = &cpm_uart_pops, .iotype = UPIO_MEM, .lock = SPIN_LOCK_UNLOCKED, }, .flags = FLAG_SMC, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = smc1_lineif, }, [UART_SMC2] = { .port = { .irq = SMC2_IRQ, .ops = &cpm_uart_pops, .iotype = UPIO_MEM, .lock = SPIN_LOCK_UNLOCKED, }, .flags = FLAG_SMC, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = smc2_lineif,#ifdef CONFIG_SERIAL_CPM_ALT_SMC2 .is_portb = 1,#endif }, [UART_SCC1] = { .port = { .irq = SCC1_IRQ, .ops = &cpm_uart_pops, .iotype = UPIO_MEM, .lock = SPIN_LOCK_UNLOCKED, }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = scc1_lineif, .wait_closing = SCC_WAIT_CLOSING, }, [UART_SCC2] = { .port = { .irq = SCC2_IRQ, .ops = &cpm_uart_pops, .iotype = UPIO_MEM, .lock = SPIN_LOCK_UNLOCKED, }, .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, }, .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, }, .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 = pdata->fs_no; /* It is UART_SMCx or UART_SCCx index */ struct uart_cpm_port *pinfo; int line; u32 mem, pram; line = cpm_uart_id2nr(idx); if(line < 0) { printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx); return -1; } 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 = r->start; if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram"))) return -EINVAL; pram = r->start; 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;}#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){ struct uart_cpm_port *pinfo = &cpm_uart_ports[cpm_uart_port_map[co->index]]; unsigned int i; volatile cbd_t *bdp, *bdbase; volatile 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 ((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(bdp->cbd_bufaddr, pinfo); *cp = *s; bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; if (bdp->cbd_sc & BD_SC_WRAP) bdp = bdbase; else bdp++; /* if a LF, also do CR... */ if (*s == 10) { while ((bdp->cbd_sc & BD_SC_READY) != 0) ; cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); *cp = 13; bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; if (bdp->cbd_sc & BD_SC_WRAP) bdp = bdbase; else bdp++; } } /* * Finally, Wait for transmitter & holding register to empty * and restore the IER */ while ((bdp->cbd_sc & BD_SC_READY) != 0) ; pinfo->tx_cur = (volatile cbd_t *) bdp;}static int __init cpm_uart_console_setup(struct console *co, char *options){ struct uart_port *port; struct uart_cpm_port *pinfo; int baud = 38400; int bits = 8; int parity = 'n'; int flow = 'n'; int ret; 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(); cpm_uart_drv_get_platform_data(pdev, 1); } pinfo->flags |= FLAG_CONSOLE; if (options) { uart_parse_options(options, &baud, &parity, &bits, &flow); } else { bd_t *bd = (bd_t *) __res; if (bd->bi_baudrate) baud = bd->bi_baudrate; else baud = 9600; } if (IS_SMC(pinfo)) { pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); } else { pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); 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); 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,};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,};static 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; pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no)); if ((ret = cpm_uart_drv_get_platform_data(pdev, 0))) return ret; if (pdata->init_ioports) pdata->init_ioports(); 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");#ifndef CONFIG_SERIAL_CPM_CONSOLE ret = cpm_uart_init_portdesc(); if (ret) return ret;#endif 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; 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);}module_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 + -