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 + -
显示快捷键?