⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sb1250-duart.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	/* Clear the interrupt registers.  */	write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT);	read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2));	/* Set rx/tx interrupt to FIFO available.  */	mode1 = read_sbdchn(sport, R_DUART_MODE_REG_1);	mode1 &= ~(M_DUART_RX_IRQ_SEL_RXFULL | M_DUART_TX_IRQ_SEL_TXEMPT);	write_sbdchn(sport, R_DUART_MODE_REG_1, mode1);	/* Disable tx, enable rx.  */	write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_EN);	sport->tx_stopped = 1;	/* Enable interrupts.  */	write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2),		     M_DUART_IMR_IN | M_DUART_IMR_RX);	return 0;}static void sbd_shutdown(struct uart_port *uport){	struct sbd_port *sport = to_sport(uport);	write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS);	sport->tx_stopped = 1;	free_irq(sport->port.irq, sport);}static void sbd_init_port(struct sbd_port *sport){	struct uart_port *uport = &sport->port;	if (sport->initialised)		return;	/* There is no DUART reset feature, so just set some sane defaults.  */	write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_TX);	write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_RX);	write_sbdchn(sport, R_DUART_MODE_REG_1, V_DUART_BITS_PER_CHAR_8);	write_sbdchn(sport, R_DUART_MODE_REG_2, 0);	write_sbdchn(sport, R_DUART_FULL_CTL,		     V_DUART_INT_TIME(0) | V_DUART_SIG_FULL(15));	write_sbdchn(sport, R_DUART_OPCR_X, 0);	write_sbdchn(sport, R_DUART_AUXCTL_X, 0);	write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0);	sport->initialised = 1;}static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios,			    struct ktermios *old_termios){	struct sbd_port *sport = to_sport(uport);	unsigned int mode1 = 0, mode2 = 0, aux = 0;	unsigned int mode1mask = 0, mode2mask = 0, auxmask = 0;	unsigned int oldmode1, oldmode2, oldaux;	unsigned int baud, brg;	unsigned int command;	mode1mask |= ~(M_DUART_PARITY_MODE | M_DUART_PARITY_TYPE_ODD |		       M_DUART_BITS_PER_CHAR);	mode2mask |= ~M_DUART_STOP_BIT_LEN_2;	auxmask |= ~M_DUART_CTS_CHNG_ENA;	/* Byte size.  */	switch (termios->c_cflag & CSIZE) {	case CS5:	case CS6:		/* Unsupported, leave unchanged.  */		mode1mask |= M_DUART_PARITY_MODE;		break;	case CS7:		mode1 |= V_DUART_BITS_PER_CHAR_7;		break;	case CS8:	default:		mode1 |= V_DUART_BITS_PER_CHAR_8;		break;	}	/* Parity and stop bits.  */	if (termios->c_cflag & CSTOPB)		mode2 |= M_DUART_STOP_BIT_LEN_2;	else		mode2 |= M_DUART_STOP_BIT_LEN_1;	if (termios->c_cflag & PARENB)		mode1 |= V_DUART_PARITY_MODE_ADD;	else		mode1 |= V_DUART_PARITY_MODE_NONE;	if (termios->c_cflag & PARODD)		mode1 |= M_DUART_PARITY_TYPE_ODD;	else		mode1 |= M_DUART_PARITY_TYPE_EVEN;	baud = uart_get_baud_rate(uport, termios, old_termios, 1200, 5000000);	brg = V_DUART_BAUD_RATE(baud);	/* The actual lower bound is 1221bps, so compensate.  */	if (brg > M_DUART_CLK_COUNTER)		brg = M_DUART_CLK_COUNTER;	uart_update_timeout(uport, termios->c_cflag, baud);	uport->read_status_mask = M_DUART_OVRUN_ERR;	if (termios->c_iflag & INPCK)		uport->read_status_mask |= M_DUART_FRM_ERR |					   M_DUART_PARITY_ERR;	if (termios->c_iflag & (BRKINT | PARMRK))		uport->read_status_mask |= M_DUART_RCVD_BRK;	uport->ignore_status_mask = 0;	if (termios->c_iflag & IGNPAR)		uport->ignore_status_mask |= M_DUART_FRM_ERR |					     M_DUART_PARITY_ERR;	if (termios->c_iflag & IGNBRK) {		uport->ignore_status_mask |= M_DUART_RCVD_BRK;		if (termios->c_iflag & IGNPAR)			uport->ignore_status_mask |= M_DUART_OVRUN_ERR;	}	if (termios->c_cflag & CREAD)		command = M_DUART_RX_EN;	else		command = M_DUART_RX_DIS;	if (termios->c_cflag & CRTSCTS)		aux |= M_DUART_CTS_CHNG_ENA;	else		aux &= ~M_DUART_CTS_CHNG_ENA;	spin_lock(&uport->lock);	if (sport->tx_stopped)		command |= M_DUART_TX_DIS;	else		command |= M_DUART_TX_EN;	oldmode1 = read_sbdchn(sport, R_DUART_MODE_REG_1) & mode1mask;	oldmode2 = read_sbdchn(sport, R_DUART_MODE_REG_2) & mode2mask;	oldaux = read_sbdchn(sport, R_DUART_AUXCTL_X) & auxmask;	if (!sport->tx_stopped)		sbd_line_drain(sport);	write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS);	write_sbdchn(sport, R_DUART_MODE_REG_1, mode1 | oldmode1);	write_sbdchn(sport, R_DUART_MODE_REG_2, mode2 | oldmode2);	write_sbdchn(sport, R_DUART_CLK_SEL, brg);	write_sbdchn(sport, R_DUART_AUXCTL_X, aux | oldaux);	write_sbdchn(sport, R_DUART_CMD, command);	spin_unlock(&uport->lock);}static const char *sbd_type(struct uart_port *uport){	return "SB1250 DUART";}static void sbd_release_port(struct uart_port *uport){	struct sbd_port *sport = to_sport(uport);	struct sbd_duart *duart = sport->duart;	int map_guard;	iounmap(sport->memctrl);	sport->memctrl = NULL;	iounmap(uport->membase);	uport->membase = NULL;	map_guard = atomic_add_return(-1, &duart->map_guard);	if (!map_guard)		release_mem_region(duart->mapctrl, DUART_CHANREG_SPACING);	release_mem_region(uport->mapbase, DUART_CHANREG_SPACING);}static int sbd_map_port(struct uart_port *uport){	const char *err = KERN_ERR "sbd: Cannot map MMIO\n";	struct sbd_port *sport = to_sport(uport);	struct sbd_duart *duart = sport->duart;	if (!uport->membase)		uport->membase = ioremap_nocache(uport->mapbase,						 DUART_CHANREG_SPACING);	if (!uport->membase) {		printk(err);		return -ENOMEM;	}	if (!sport->memctrl)		sport->memctrl = ioremap_nocache(duart->mapctrl,						 DUART_CHANREG_SPACING);	if (!sport->memctrl) {		printk(err);		iounmap(uport->membase);		uport->membase = NULL;		return -ENOMEM;	}	return 0;}static int sbd_request_port(struct uart_port *uport){	const char *err = KERN_ERR "sbd: Unable to reserve MMIO resource\n";	struct sbd_duart *duart = to_sport(uport)->duart;	int map_guard;	int ret = 0;	if (!request_mem_region(uport->mapbase, DUART_CHANREG_SPACING,				"sb1250-duart")) {		printk(err);		return -EBUSY;	}	map_guard = atomic_add_return(1, &duart->map_guard);	if (map_guard == 1) {		if (!request_mem_region(duart->mapctrl, DUART_CHANREG_SPACING,					"sb1250-duart")) {			atomic_add(-1, &duart->map_guard);			printk(err);			ret = -EBUSY;		}	}	if (!ret) {		ret = sbd_map_port(uport);		if (ret) {			map_guard = atomic_add_return(-1, &duart->map_guard);			if (!map_guard)				release_mem_region(duart->mapctrl,						   DUART_CHANREG_SPACING);		}	}	if (ret) {		release_mem_region(uport->mapbase, DUART_CHANREG_SPACING);		return ret;	}	return 0;}static void sbd_config_port(struct uart_port *uport, int flags){	struct sbd_port *sport = to_sport(uport);	if (flags & UART_CONFIG_TYPE) {		if (sbd_request_port(uport))			return;		uport->type = PORT_SB1250_DUART;		sbd_init_port(sport);	}}static int sbd_verify_port(struct uart_port *uport, struct serial_struct *ser){	int ret = 0;	if (ser->type != PORT_UNKNOWN && ser->type != PORT_SB1250_DUART)		ret = -EINVAL;	if (ser->irq != uport->irq)		ret = -EINVAL;	if (ser->baud_base != uport->uartclk / 16)		ret = -EINVAL;	return ret;}static const struct uart_ops sbd_ops = {	.tx_empty	= sbd_tx_empty,	.set_mctrl	= sbd_set_mctrl,	.get_mctrl	= sbd_get_mctrl,	.stop_tx	= sbd_stop_tx,	.start_tx	= sbd_start_tx,	.stop_rx	= sbd_stop_rx,	.enable_ms	= sbd_enable_ms,	.break_ctl	= sbd_break_ctl,	.startup	= sbd_startup,	.shutdown	= sbd_shutdown,	.set_termios	= sbd_set_termios,	.type		= sbd_type,	.release_port	= sbd_release_port,	.request_port	= sbd_request_port,	.config_port	= sbd_config_port,	.verify_port	= sbd_verify_port,};/* Initialize SB1250 DUART port structures.  */static void __init sbd_probe_duarts(void){	static int probed;	int chip, side;	int max_lines, line;	if (probed)		return;	/* Set the number of available units based on the SOC type.  */	switch (soc_type) {	case K_SYS_SOC_TYPE_BCM1x55:	case K_SYS_SOC_TYPE_BCM1x80:		max_lines = 4;		break;	default:		/* Assume at least two serial ports at the normal address.  */		max_lines = 2;		break;	}	probed = 1;	for (chip = 0, line = 0; chip < DUART_MAX_CHIP && line < max_lines;	     chip++) {		sbd_duarts[chip].mapctrl = SBD_CTRLREGS(line);		for (side = 0; side < DUART_MAX_SIDE && line < max_lines;		     side++, line++) {			struct sbd_port *sport = &sbd_duarts[chip].sport[side];			struct uart_port *uport = &sport->port;			sport->duart	= &sbd_duarts[chip];			uport->irq	= SBD_INT(line);			uport->uartclk	= 100000000 / 20 * 16;			uport->fifosize	= 16;			uport->iotype	= UPIO_MEM;			uport->flags	= UPF_BOOT_AUTOCONF;			uport->ops	= &sbd_ops;			uport->line	= line;			uport->mapbase	= SBD_CHANREGS(line);		}	}}#ifdef CONFIG_SERIAL_SB1250_DUART_CONSOLE/* * Serial console stuff.  Very basic, polling driver for doing serial * console output.  The console_sem is held by the caller, so we * shouldn't be interrupted for more console activity. */static void sbd_console_putchar(struct uart_port *uport, int ch){	struct sbd_port *sport = to_sport(uport);	sbd_transmit_drain(sport);	write_sbdchn(sport, R_DUART_TX_HOLD, ch);}static void sbd_console_write(struct console *co, const char *s,			      unsigned int count){	int chip = co->index / DUART_MAX_SIDE;	int side = co->index % DUART_MAX_SIDE;	struct sbd_port *sport = &sbd_duarts[chip].sport[side];	struct uart_port *uport = &sport->port;	unsigned long flags;	unsigned int mask;	/* Disable transmit interrupts and enable the transmitter. */	spin_lock_irqsave(&uport->lock, flags);	mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));	write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2),		     mask & ~M_DUART_IMR_TX);	write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN);	spin_unlock_irqrestore(&uport->lock, flags);	uart_console_write(&sport->port, s, count, sbd_console_putchar);	/* Restore transmit interrupts and the transmitter enable. */	spin_lock_irqsave(&uport->lock, flags);	sbd_line_drain(sport);	if (sport->tx_stopped)		write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS);	write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);	spin_unlock_irqrestore(&uport->lock, flags);}static int __init sbd_console_setup(struct console *co, char *options){	int chip = co->index / DUART_MAX_SIDE;	int side = co->index % DUART_MAX_SIDE;	struct sbd_port *sport = &sbd_duarts[chip].sport[side];	struct uart_port *uport = &sport->port;	int baud = 115200;	int bits = 8;	int parity = 'n';	int flow = 'n';	int ret;	if (!sport->duart)		return -ENXIO;	ret = sbd_map_port(uport);	if (ret)		return ret;	sbd_init_port(sport);	if (options)		uart_parse_options(options, &baud, &parity, &bits, &flow);	return uart_set_options(uport, co, baud, parity, bits, flow);}static struct uart_driver sbd_reg;static struct console sbd_console = {	.name	= "duart",	.write	= sbd_console_write,	.device	= uart_console_device,	.setup	= sbd_console_setup,	.flags	= CON_PRINTBUFFER,	.index	= -1,	.data	= &sbd_reg};static int __init sbd_serial_console_init(void){	sbd_probe_duarts();	register_console(&sbd_console);	return 0;}console_initcall(sbd_serial_console_init);#define SERIAL_SB1250_DUART_CONSOLE	&sbd_console#else#define SERIAL_SB1250_DUART_CONSOLE	NULL#endif /* CONFIG_SERIAL_SB1250_DUART_CONSOLE */static struct uart_driver sbd_reg = {	.owner		= THIS_MODULE,	.driver_name	= "serial",	.dev_name	= "duart",	.major		= TTY_MAJOR,	.minor		= SB1250_DUART_MINOR_BASE,	.nr		= DUART_MAX_CHIP * DUART_MAX_SIDE,	.cons		= SERIAL_SB1250_DUART_CONSOLE,};/* Set up the driver and register it.  */static int __init sbd_init(void){	int i, ret;	sbd_probe_duarts();	ret = uart_register_driver(&sbd_reg);	if (ret)		return ret;	for (i = 0; i < DUART_MAX_CHIP * DUART_MAX_SIDE; i++) {		struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE];		struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE];		struct uart_port *uport = &sport->port;		if (sport->duart)			uart_add_one_port(&sbd_reg, uport);	}	return 0;}/* Unload the driver.  Unregister stuff, get ready to go away.  */static void __exit sbd_exit(void){	int i;	for (i = DUART_MAX_CHIP * DUART_MAX_SIDE - 1; i >= 0; i--) {		struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE];		struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE];		struct uart_port *uport = &sport->port;		if (sport->duart)			uart_remove_one_port(&sbd_reg, uport);	}	uart_unregister_driver(&sbd_reg);}module_init(sbd_init);module_exit(sbd_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -