zs.c
来自「linux 内核源代码」· C语言 代码 · 共 1,288 行 · 第 1/3 页
C
1,288 行
spin_lock_irqsave(&scc->zlock, flags); irq = !irqs_disabled_flags(flags); /* Byte size. */ zport->regs[3] &= ~RxNBITS_MASK; zport->regs[5] &= ~TxNBITS_MASK; switch (termios->c_cflag & CSIZE) { case CS5: zport->regs[3] |= Rx5; zport->regs[5] |= Tx5; break; case CS6: zport->regs[3] |= Rx6; zport->regs[5] |= Tx6; break; case CS7: zport->regs[3] |= Rx7; zport->regs[5] |= Tx7; break; case CS8: default: zport->regs[3] |= Rx8; zport->regs[5] |= Tx8; break; } /* Parity and stop bits. */ zport->regs[4] &= ~(XCLK_MASK | SB_MASK | PAR_ENA | PAR_EVEN); if (termios->c_cflag & CSTOPB) zport->regs[4] |= SB2; else zport->regs[4] |= SB1; if (termios->c_cflag & PARENB) zport->regs[4] |= PAR_ENA; if (!(termios->c_cflag & PARODD)) zport->regs[4] |= PAR_EVEN; switch (zport->clk_mode) { case 64: zport->regs[4] |= X64CLK; break; case 32: zport->regs[4] |= X32CLK; break; case 16: zport->regs[4] |= X16CLK; break; case 1: zport->regs[4] |= X1CLK; break; default: BUG(); } baud = uart_get_baud_rate(uport, termios, old_termios, 0, uport->uartclk / zport->clk_mode / 4); brg = ZS_BPS_TO_BRG(baud, uport->uartclk / zport->clk_mode); zport->regs[12] = brg & 0xff; zport->regs[13] = (brg >> 8) & 0xff; uart_update_timeout(uport, termios->c_cflag, baud); uport->read_status_mask = Rx_OVR; if (termios->c_iflag & INPCK) uport->read_status_mask |= FRM_ERR | PAR_ERR; if (termios->c_iflag & (BRKINT | PARMRK)) uport->read_status_mask |= Rx_BRK; uport->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) uport->ignore_status_mask |= FRM_ERR | PAR_ERR; if (termios->c_iflag & IGNBRK) { uport->ignore_status_mask |= Rx_BRK; if (termios->c_iflag & IGNPAR) uport->ignore_status_mask |= Rx_OVR; } if (termios->c_cflag & CREAD) zport->regs[3] |= RxENABLE; else zport->regs[3] &= ~RxENABLE; if (zport != zport_a) { if (!(termios->c_cflag & CLOCAL)) { zport->regs[15] |= DCDIE; } else zport->regs[15] &= ~DCDIE; if (termios->c_cflag & CRTSCTS) { zport->regs[15] |= CTSIE; } else zport->regs[15] &= ~CTSIE; zs_raw_xor_mctrl(zport); } /* Load up the new values. */ load_zsregs(zport, zport->regs, irq); spin_unlock_irqrestore(&scc->zlock, flags);}static const char *zs_type(struct uart_port *uport){ return "Z85C30 SCC";}static void zs_release_port(struct uart_port *uport){ iounmap(uport->membase); uport->membase = 0; release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);}static int zs_map_port(struct uart_port *uport){ if (!uport->membase) uport->membase = ioremap_nocache(uport->mapbase, ZS_CHAN_IO_SIZE); if (!uport->membase) { printk(KERN_ERR "zs: Cannot map MMIO\n"); return -ENOMEM; } return 0;}static int zs_request_port(struct uart_port *uport){ int ret; if (!request_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE, "scc")) { printk(KERN_ERR "zs: Unable to reserve MMIO resource\n"); return -EBUSY; } ret = zs_map_port(uport); if (ret) { release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE); return ret; } return 0;}static void zs_config_port(struct uart_port *uport, int flags){ struct zs_port *zport = to_zport(uport); if (flags & UART_CONFIG_TYPE) { if (zs_request_port(uport)) return; uport->type = PORT_ZS; zs_reset(zport); }}static int zs_verify_port(struct uart_port *uport, struct serial_struct *ser){ struct zs_port *zport = to_zport(uport); int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_ZS) ret = -EINVAL; if (ser->irq != uport->irq) ret = -EINVAL; if (ser->baud_base != uport->uartclk / zport->clk_mode / 4) ret = -EINVAL; return ret;}static struct uart_ops zs_ops = { .tx_empty = zs_tx_empty, .set_mctrl = zs_set_mctrl, .get_mctrl = zs_get_mctrl, .stop_tx = zs_stop_tx, .start_tx = zs_start_tx, .stop_rx = zs_stop_rx, .enable_ms = zs_enable_ms, .break_ctl = zs_break_ctl, .startup = zs_startup, .shutdown = zs_shutdown, .set_termios = zs_set_termios, .type = zs_type, .release_port = zs_release_port, .request_port = zs_request_port, .config_port = zs_config_port, .verify_port = zs_verify_port,};/* * Initialize Z85C30 port structures. */static int __init zs_probe_sccs(void){ static int probed; struct zs_parms zs_parms; int chip, side, irq; int n_chips = 0; int i; if (probed) return 0; irq = dec_interrupt[DEC_IRQ_SCC0]; if (irq >= 0) { zs_parms.scc[n_chips] = IOASIC_SCC0; zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0]; n_chips++; } irq = dec_interrupt[DEC_IRQ_SCC1]; if (irq >= 0) { zs_parms.scc[n_chips] = IOASIC_SCC1; zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1]; n_chips++; } if (!n_chips) return -ENXIO; probed = 1; for (chip = 0; chip < n_chips; chip++) { spin_lock_init(&zs_sccs[chip].zlock); for (side = 0; side < ZS_NUM_CHAN; side++) { struct zs_port *zport = &zs_sccs[chip].zport[side]; struct uart_port *uport = &zport->port; zport->scc = &zs_sccs[chip]; zport->clk_mode = 16; uport->irq = zs_parms.irq[chip]; uport->uartclk = ZS_CLOCK; uport->fifosize = 1; uport->iotype = UPIO_MEM; uport->flags = UPF_BOOT_AUTOCONF; uport->ops = &zs_ops; uport->line = chip * ZS_NUM_CHAN + side; uport->mapbase = dec_kn_slot_base + zs_parms.scc[chip] + (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE; for (i = 0; i < ZS_NUM_REGS; i++) zport->regs[i] = zs_init_regs[i]; } } return 0;}#ifdef CONFIG_SERIAL_ZS_CONSOLEstatic void zs_console_putchar(struct uart_port *uport, int ch){ struct zs_port *zport = to_zport(uport); struct zs_scc *scc = zport->scc; int irq; unsigned long flags; spin_lock_irqsave(&scc->zlock, flags); irq = !irqs_disabled_flags(flags); if (zs_transmit_drain(zport, irq)) write_zsdata(zport, ch); spin_unlock_irqrestore(&scc->zlock, flags);}/* * Print a string to the serial port trying not to disturb * any possible real use of the port... */static void zs_console_write(struct console *co, const char *s, unsigned int count){ int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN; struct zs_port *zport = &zs_sccs[chip].zport[side]; struct zs_scc *scc = zport->scc; unsigned long flags; u8 txint, txenb; int irq; /* Disable transmit interrupts and enable the transmitter. */ spin_lock_irqsave(&scc->zlock, flags); txint = zport->regs[1]; txenb = zport->regs[5]; if (txint & TxINT_ENAB) { zport->regs[1] = txint & ~TxINT_ENAB; write_zsreg(zport, R1, zport->regs[1]); } if (!(txenb & TxENAB)) { zport->regs[5] = txenb | TxENAB; write_zsreg(zport, R5, zport->regs[5]); } spin_unlock_irqrestore(&scc->zlock, flags); uart_console_write(&zport->port, s, count, zs_console_putchar); /* Restore transmit interrupts and the transmitter enable. */ spin_lock_irqsave(&scc->zlock, flags); irq = !irqs_disabled_flags(flags); zs_line_drain(zport, irq); if (!(txenb & TxENAB)) { zport->regs[5] &= ~TxENAB; write_zsreg(zport, R5, zport->regs[5]); } if (txint & TxINT_ENAB) { zport->regs[1] |= TxINT_ENAB; write_zsreg(zport, R1, zport->regs[1]); } spin_unlock_irqrestore(&scc->zlock, flags);}/* * Setup serial console baud/bits/parity. We do two things here: * - construct a cflag setting for the first uart_open() * - initialise the serial port * Return non-zero if we didn't find a serial port. */static int __init zs_console_setup(struct console *co, char *options){ int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN; struct zs_port *zport = &zs_sccs[chip].zport[side]; struct uart_port *uport = &zport->port; int baud = 9600; int bits = 8; int parity = 'n'; int flow = 'n'; int ret; ret = zs_map_port(uport); if (ret) return ret; zs_reset(zport); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); return uart_set_options(uport, co, baud, parity, bits, flow);}static struct uart_driver zs_reg;static struct console zs_console = { .name = "ttyS", .write = zs_console_write, .device = uart_console_device, .setup = zs_console_setup, .flags = CON_PRINTBUFFER, .index = -1, .data = &zs_reg,};/* * Register console. */static int __init zs_serial_console_init(void){ int ret; ret = zs_probe_sccs(); if (ret) return ret; register_console(&zs_console); return 0;}console_initcall(zs_serial_console_init);#define SERIAL_ZS_CONSOLE &zs_console#else#define SERIAL_ZS_CONSOLE NULL#endif /* CONFIG_SERIAL_ZS_CONSOLE */static struct uart_driver zs_reg = { .owner = THIS_MODULE, .driver_name = "serial", .dev_name = "ttyS", .major = TTY_MAJOR, .minor = 64, .nr = ZS_NUM_SCCS * ZS_NUM_CHAN, .cons = SERIAL_ZS_CONSOLE,};/* zs_init inits the driver. */static int __init zs_init(void){ int i, ret; pr_info("%s%s\n", zs_name, zs_version); /* Find out how many Z85C30 SCCs we have. */ ret = zs_probe_sccs(); if (ret) return ret; ret = uart_register_driver(&zs_reg); if (ret) return ret; for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) { struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN]; struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN]; struct uart_port *uport = &zport->port; if (zport->scc) uart_add_one_port(&zs_reg, uport); } return 0;}static void __exit zs_exit(void){ int i; for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) { struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN]; struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN]; struct uart_port *uport = &zport->port; if (zport->scc) uart_remove_one_port(&zs_reg, uport); } uart_unregister_driver(&zs_reg);}module_init(zs_init);module_exit(zs_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?