pxa.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 887 行 · 第 1/2 页

C
887
字号
	 */	up->ier = 0;	serial_out(up, UART_IER, 0);	spin_lock_irqsave(&up->port.lock, flags);	up->port.mctrl &= ~TIOCM_OUT2;	serial_pxa_set_mctrl(&up->port, up->port.mctrl);	spin_unlock_irqrestore(&up->port.lock, flags);	/*	 * Disable break condition and FIFOs	 */	serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |				  UART_FCR_CLEAR_RCVR |				  UART_FCR_CLEAR_XMIT);	serial_out(up, UART_FCR, 0);}static voidserial_pxa_set_termios(struct uart_port *port, struct termios *termios,		       struct termios *old){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	unsigned char cval, fcr = 0;	unsigned long flags;	unsigned int baud, quot;	switch (termios->c_cflag & CSIZE) {	case CS5:		cval = 0x00;		break;	case CS6:		cval = 0x01;		break;	case CS7:		cval = 0x02;		break;	default:	case CS8:		cval = 0x03;		break;	}	if (termios->c_cflag & CSTOPB)		cval |= 0x04;	if (termios->c_cflag & PARENB)		cval |= UART_LCR_PARITY;	if (!(termios->c_cflag & PARODD))		cval |= UART_LCR_EPAR;	/*	 * Ask the core to calculate the divisor for us.	 */	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);	quot = uart_get_divisor(port, baud);	if ((up->port.uartclk / quot) < (2400 * 16))		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1;	else		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8;	/*	 * Ok, we're now changing the port state.  Do it with	 * interrupts disabled.	 */	spin_lock_irqsave(&up->port.lock, flags);	/*	 * Ensure the port will be enabled.	 * This is required especially for serial console.	 */	up->ier |= IER_UUE;	/*	 * Update the per-port timeout.	 */	uart_update_timeout(port, termios->c_cflag, quot);	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;	if (termios->c_iflag & INPCK)		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;	if (termios->c_iflag & (BRKINT | PARMRK))		up->port.read_status_mask |= UART_LSR_BI;	/*	 * Characters to ignore	 */	up->port.ignore_status_mask = 0;	if (termios->c_iflag & IGNPAR)		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;	if (termios->c_iflag & IGNBRK) {		up->port.ignore_status_mask |= UART_LSR_BI;		/*		 * If we're ignoring parity and break indicators,		 * ignore overruns too (for real raw support).		 */		if (termios->c_iflag & IGNPAR)			up->port.ignore_status_mask |= UART_LSR_OE;	}	/*	 * ignore all characters if CREAD is not set	 */	if ((termios->c_cflag & CREAD) == 0)		up->port.ignore_status_mask |= UART_LSR_DR;	/*	 * CTS flow control flag and modem status interrupts	 */	up->ier &= ~UART_IER_MSI;	if (UART_ENABLE_MS(&up->port, termios->c_cflag))		up->ier |= UART_IER_MSI;	serial_out(up, UART_IER, up->ier);	serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */	serial_out(up, UART_DLL, quot & 0xff);		/* LS of divisor */	serial_out(up, UART_DLM, quot >> 8);		/* MS of divisor */	serial_out(up, UART_LCR, cval);		/* reset DLAB */	up->lcr = cval;					/* Save LCR */	serial_pxa_set_mctrl(&up->port, up->port.mctrl);	serial_out(up, UART_FCR, fcr);	spin_unlock_irqrestore(&up->port.lock, flags);}static voidserial_pxa_pm(struct uart_port *port, unsigned int state,	      unsigned int oldstate){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	pxa_set_cken(up->cken, !state);	if (!state)		udelay(1);}static void serial_pxa_release_port(struct uart_port *port){}static int serial_pxa_request_port(struct uart_port *port){	return 0;}static void serial_pxa_config_port(struct uart_port *port, int flags){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	up->port.type = PORT_PXA;}static intserial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser){	/* we don't want the core code to modify any port params */	return -EINVAL;}static const char *serial_pxa_type(struct uart_port *port){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	return up->name;}#ifdef CONFIG_SERIAL_PXA_CONSOLEextern struct uart_pxa_port serial_pxa_ports[];extern struct uart_driver serial_pxa_reg;#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)/* *	Wait for transmitter & holding register to empty */static inline void wait_for_xmitr(struct uart_pxa_port *up){	unsigned int status, tmout = 10000;	/* Wait up to 10ms for the character(s) to be sent. */	do {		status = serial_in(up, UART_LSR);		if (status & UART_LSR_BI)			up->lsr_break_flag = UART_LSR_BI;		if (--tmout == 0)			break;		udelay(1);	} while ((status & BOTH_EMPTY) != BOTH_EMPTY);	/* Wait up to 1s for flow control if necessary */	if (up->port.flags & UPF_CONS_FLOW) {		tmout = 1000000;		while (--tmout &&		       ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))			udelay(1);	}}/* * Print a string to the serial port trying not to disturb * any possible real use of the port... * *	The console_lock must be held when we get here. */static voidserial_pxa_console_write(struct console *co, const char *s, unsigned int count){	struct uart_pxa_port *up = &serial_pxa_ports[co->index];	unsigned int ier;	int i;	/*	 *	First save the UER then disable the interrupts	 */	ier = serial_in(up, UART_IER);	serial_out(up, UART_IER, UART_IER_UUE);	/*	 *	Now, do each character	 */	for (i = 0; i < count; i++, s++) {		wait_for_xmitr(up);		/*		 *	Send the character out.		 *	If a LF, also do CR...		 */		serial_out(up, UART_TX, *s);		if (*s == 10) {			wait_for_xmitr(up);			serial_out(up, UART_TX, 13);		}	}	/*	 *	Finally, wait for transmitter to become empty	 *	and restore the IER	 */	wait_for_xmitr(up);	serial_out(up, UART_IER, ier);}static int __initserial_pxa_console_setup(struct console *co, char *options){	struct uart_pxa_port *up;	int baud = 9600;	int bits = 8;	int parity = 'n';	int flow = 'n';	if (co->index == -1 || co->index >= serial_pxa_reg.nr)		co->index = 0;       	up = &serial_pxa_ports[co->index];	if (options)		uart_parse_options(options, &baud, &parity, &bits, &flow);	return uart_set_options(&up->port, co, baud, parity, bits, flow);}static struct console serial_pxa_console = {	.name		= "ttyS",	.write		= serial_pxa_console_write,	.device		= uart_console_device,	.setup		= serial_pxa_console_setup,	.flags		= CON_PRINTBUFFER,	.index		= -1,	.data		= &serial_pxa_reg,};static int __initserial_pxa_console_init(void){	register_console(&serial_pxa_console);	return 0;}console_initcall(serial_pxa_console_init);#define PXA_CONSOLE	&serial_pxa_console#else#define PXA_CONSOLE	NULL#endifstruct uart_ops serial_pxa_pops = {	.tx_empty	= serial_pxa_tx_empty,	.set_mctrl	= serial_pxa_set_mctrl,	.get_mctrl	= serial_pxa_get_mctrl,	.stop_tx	= serial_pxa_stop_tx,	.start_tx	= serial_pxa_start_tx,	.stop_rx	= serial_pxa_stop_rx,	.enable_ms	= serial_pxa_enable_ms,	.break_ctl	= serial_pxa_break_ctl,	.startup	= serial_pxa_startup,	.shutdown	= serial_pxa_shutdown,	.set_termios	= serial_pxa_set_termios,	.pm		= serial_pxa_pm,	.type		= serial_pxa_type,	.release_port	= serial_pxa_release_port,	.request_port	= serial_pxa_request_port,	.config_port	= serial_pxa_config_port,	.verify_port	= serial_pxa_verify_port,};static struct uart_pxa_port serial_pxa_ports[] = {     {	/* FFUART */	.name	= "FFUART",	.cken	= CKEN6_FFUART,	.port	= {		.type		= PORT_PXA,		.iotype		= UPIO_MEM,		.membase	= (void *)&FFUART,		.mapbase	= __PREG(FFUART),		.irq		= IRQ_FFUART,		.uartclk	= 921600 * 16,		.fifosize	= 64,		.ops		= &serial_pxa_pops,		.line		= 0,	},  }, {	/* BTUART */	.name	= "BTUART",	.cken	= CKEN7_BTUART,	.port	= {		.type		= PORT_PXA,		.iotype		= UPIO_MEM,		.membase	= (void *)&BTUART,		.mapbase	= __PREG(BTUART),		.irq		= IRQ_BTUART,		.uartclk	= 921600 * 16,		.fifosize	= 64,		.ops		= &serial_pxa_pops,		.line		= 1,	},  }, {	/* STUART */	.name	= "STUART",	.cken	= CKEN5_STUART,	.port	= {		.type		= PORT_PXA,		.iotype		= UPIO_MEM,		.membase	= (void *)&STUART,		.mapbase	= __PREG(STUART),		.irq		= IRQ_STUART,		.uartclk	= 921600 * 16,		.fifosize	= 64,		.ops		= &serial_pxa_pops,		.line		= 2,	},  }};static struct uart_driver serial_pxa_reg = {	.owner		= THIS_MODULE,	.driver_name	= "PXA serial",	.devfs_name	= "tts/",	.dev_name	= "ttyS",	.major		= TTY_MAJOR,	.minor		= 64,	.nr		= ARRAY_SIZE(serial_pxa_ports),	.cons		= PXA_CONSOLE,};static int serial_pxa_suspend(struct device *_dev, u32 state, u32 level){        struct uart_pxa_port *sport = dev_get_drvdata(_dev);        if (sport && level == SUSPEND_DISABLE)                uart_suspend_port(&serial_pxa_reg, &sport->port);        return 0;}static int serial_pxa_resume(struct device *_dev, u32 level){        struct uart_pxa_port *sport = dev_get_drvdata(_dev);        if (sport && level == RESUME_ENABLE)                uart_resume_port(&serial_pxa_reg, &sport->port);        return 0;}static int serial_pxa_probe(struct device *_dev){	struct platform_device *dev = to_platform_device(_dev);	serial_pxa_ports[dev->id].port.dev = _dev;	uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[dev->id].port);	dev_set_drvdata(_dev, &serial_pxa_ports[dev->id]);	return 0;}static int serial_pxa_remove(struct device *_dev){	struct uart_pxa_port *sport = dev_get_drvdata(_dev);	dev_set_drvdata(_dev, NULL);	if (sport)		uart_remove_one_port(&serial_pxa_reg, &sport->port);	return 0;}static struct device_driver serial_pxa_driver = {        .name           = "pxa2xx-uart",        .bus            = &platform_bus_type,        .probe          = serial_pxa_probe,        .remove         = serial_pxa_remove,	.suspend	= serial_pxa_suspend,	.resume		= serial_pxa_resume,};int __init serial_pxa_init(void){	int ret;	ret = uart_register_driver(&serial_pxa_reg);	if (ret != 0)		return ret;	ret = driver_register(&serial_pxa_driver);	if (ret != 0)		uart_unregister_driver(&serial_pxa_reg);	return ret;}void __exit serial_pxa_exit(void){        driver_unregister(&serial_pxa_driver);	uart_unregister_driver(&serial_pxa_reg);}module_init(serial_pxa_init);module_exit(serial_pxa_exit);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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