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

📄 8250.c

📁 linux 2.6内核下8250串口设备驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (ret < 0)		probeflags &= ~PROBE_RSA;	if (flags & UART_CONFIG_TYPE)		autoconfig(up, probeflags);	if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)		autoconfig_irq(up);	if (up->port.type != PORT_RSA && probeflags & PROBE_RSA)		serial8250_release_rsa_resource(up);	if (up->port.type == PORT_UNKNOWN)		serial8250_release_std_resource(up);}static intserial8250_verify_port(struct uart_port *port, struct serial_struct *ser){	if (ser->irq >= NR_IRQS || ser->irq < 0 ||	    ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||	    ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS ||	    ser->type == PORT_STARTECH)		return -EINVAL;	return 0;}static const char *serial8250_type(struct uart_port *port){	int type = port->type;	if (type >= ARRAY_SIZE(uart_config))		type = 0;	return uart_config[type].name;}static struct uart_ops serial8250_pops = {	.tx_empty	= serial8250_tx_empty,	.set_mctrl	= serial8250_set_mctrl,	.get_mctrl	= serial8250_get_mctrl,	.stop_tx	= serial8250_stop_tx,	.start_tx	= serial8250_start_tx,	.stop_rx	= serial8250_stop_rx,	.enable_ms	= serial8250_enable_ms,	.break_ctl	= serial8250_break_ctl,	.startup	= serial8250_startup,	.shutdown	= serial8250_shutdown,	.set_termios	= serial8250_set_termios,	.pm		= serial8250_pm,	.type		= serial8250_type,	.release_port	= serial8250_release_port,	.request_port	= serial8250_request_port,	.config_port	= serial8250_config_port,	.verify_port	= serial8250_verify_port,};static struct uart_8250_port serial8250_ports[UART_NR];static void __init serial8250_isa_init_ports(void){	struct uart_8250_port *up;	static int first = 1;	int i;	if (!first)		return;	first = 0;	for (i = 0; i < nr_uarts; i++) {		struct uart_8250_port *up = &serial8250_ports[i];		up->port.line = i;		spin_lock_init(&up->port.lock);		init_timer(&up->timer);		up->timer.function = serial8250_timeout;		/*		 * ALPHA_KLUDGE_MCR needs to be killed.		 */		up->mcr_mask = ~ALPHA_KLUDGE_MCR;		up->mcr_force = ALPHA_KLUDGE_MCR;		up->port.ops = &serial8250_pops;	}	for (i = 0, up = serial8250_ports;	     i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;	     i++, up++) {		up->port.iobase   = old_serial_port[i].port;		up->port.irq      = irq_canonicalize(old_serial_port[i].irq);		up->port.uartclk  = old_serial_port[i].baud_base * 16;		up->port.flags    = old_serial_port[i].flags;		up->port.hub6     = old_serial_port[i].hub6;		up->port.membase  = old_serial_port[i].iomem_base;		up->port.iotype   = old_serial_port[i].io_type;		up->port.regshift = old_serial_port[i].iomem_reg_shift;		if (share_irqs)			up->port.flags |= UPF_SHARE_IRQ;	}}static void __initserial8250_register_ports(struct uart_driver *drv, struct device *dev){	int i;	serial8250_isa_init_ports();	for (i = 0; i < nr_uarts; i++) {		struct uart_8250_port *up = &serial8250_ports[i];		up->port.dev = dev;		uart_add_one_port(drv, &up->port);	}}#ifdef CONFIG_SERIAL_8250_CONSOLE#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)/* *	Wait for transmitter & holding register to empty */static inline void wait_for_xmitr(struct uart_8250_port *up, int bits){	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 & bits) != bits);	/* Wait up to 1s for flow control if necessary */	if (up->port.flags & UPF_CONS_FLOW) {		tmout = 1000000;		while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {			udelay(1);			touch_nmi_watchdog();		}	}}static void serial8250_console_putchar(struct uart_port *port, int ch){	struct uart_8250_port *up = (struct uart_8250_port *)port;	wait_for_xmitr(up, UART_LSR_THRE);	serial_out(up, UART_TX, ch);}/* *	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 voidserial8250_console_write(struct console *co, const char *s, unsigned int count){	struct uart_8250_port *up = &serial8250_ports[co->index];	unsigned long flags;	unsigned int ier;	int locked = 1;	touch_nmi_watchdog();	local_irq_save(flags);	if (up->port.sysrq) {		/* serial8250_handle_port() already took the lock */		locked = 0;	} else if (oops_in_progress) {		locked = spin_trylock(&up->port.lock);	} else		spin_lock(&up->port.lock);	/*	 *	First save the IER then disable the interrupts	 */	ier = serial_in(up, UART_IER);	if (up->capabilities & UART_CAP_UUE)		serial_out(up, UART_IER, UART_IER_UUE);	else		serial_out(up, UART_IER, 0);	uart_console_write(&up->port, s, count, serial8250_console_putchar);	/*	 *	Finally, wait for transmitter to become empty	 *	and restore the IER	 */	wait_for_xmitr(up, BOTH_EMPTY);	serial_out(up, UART_IER, ier);	if (locked)		spin_unlock(&up->port.lock);	local_irq_restore(flags);}static int __init serial8250_console_setup(struct console *co, char *options){	struct uart_port *port;	int baud = 9600;	int bits = 8;	int parity = 'n';	int flow = 'n';	/*	 * Check whether an invalid uart number has been specified, and	 * if so, search for the first available port that does have	 * console support.	 */	if (co->index >= nr_uarts)		co->index = 0;	port = &serial8250_ports[co->index].port;	if (!port->iobase && !port->membase)		return -ENODEV;	if (options)		uart_parse_options(options, &baud, &parity, &bits, &flow);	return uart_set_options(port, co, baud, parity, bits, flow);}static struct uart_driver serial8250_reg;static struct console serial8250_console = {	.name		= "ttyS",	.write		= serial8250_console_write,	.device		= uart_console_device,	.setup		= serial8250_console_setup,	.flags		= CON_PRINTBUFFER,	.index		= -1,	.data		= &serial8250_reg,};static int __init serial8250_console_init(void){	serial8250_isa_init_ports();	register_console(&serial8250_console);	return 0;}console_initcall(serial8250_console_init);static int __init find_port(struct uart_port *p){	int line;	struct uart_port *port;	for (line = 0; line < nr_uarts; line++) {		port = &serial8250_ports[line].port;		if (uart_match_port(p, port))			return line;	}	return -ENODEV;}int __init serial8250_start_console(struct uart_port *port, char *options){	int line;	line = find_port(port);	if (line < 0)		return -ENODEV;	add_preferred_console("ttyS", line, options);	printk("Adding console on ttyS%d at %s 0x%lx (options '%s')\n",		line, port->iotype == UPIO_MEM ? "MMIO" : "I/O port",		port->iotype == UPIO_MEM ? (unsigned long) port->mapbase :		    (unsigned long) port->iobase, options);	if (!(serial8250_console.flags & CON_ENABLED)) {		serial8250_console.flags &= ~CON_PRINTBUFFER;		register_console(&serial8250_console);	}	return line;}#define SERIAL8250_CONSOLE	&serial8250_console#else#define SERIAL8250_CONSOLE	NULL#endifstatic struct uart_driver serial8250_reg = {	.owner			= THIS_MODULE,	.driver_name		= "serial",	.dev_name		= "ttyS",	.major			= TTY_MAJOR,	.minor			= 64,	.nr			= UART_NR,	.cons			= SERIAL8250_CONSOLE,};/* * early_serial_setup - early registration for 8250 ports * * Setup an 8250 port structure prior to console initialisation.  Use * after console initialisation will cause undefined behaviour. */int __init early_serial_setup(struct uart_port *port){	if (port->line >= ARRAY_SIZE(serial8250_ports))		return -ENODEV;	serial8250_isa_init_ports();	serial8250_ports[port->line].port	= *port;	serial8250_ports[port->line].port.ops	= &serial8250_pops;	return 0;}/** *	serial8250_suspend_port - suspend one serial port *	@line:  serial line number * *	Suspend one serial port. */void serial8250_suspend_port(int line){	uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port);}/** *	serial8250_resume_port - resume one serial port *	@line:  serial line number * *	Resume one serial port. */void serial8250_resume_port(int line){	uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);}/* * Register a set of serial devices attached to a platform device.  The * list is terminated with a zero flags entry, which means we expect * all entries to have at least UPF_BOOT_AUTOCONF set. */static int __devinit serial8250_probe(struct platform_device *dev){	struct plat_serial8250_port *p = dev->dev.platform_data;	struct uart_port port;	int ret, i;	memset(&port, 0, sizeof(struct uart_port));	for (i = 0; p && p->flags != 0; p++, i++) {		port.iobase	= p->iobase;		port.membase	= p->membase;		port.irq	= p->irq;		port.uartclk	= p->uartclk;		port.regshift	= p->regshift;		port.iotype	= p->iotype;		port.flags	= p->flags;		port.mapbase	= p->mapbase;		port.hub6	= p->hub6;		port.dev	= &dev->dev;		if (share_irqs)			port.flags |= UPF_SHARE_IRQ;		ret = serial8250_register_port(&port);		if (ret < 0) {			dev_err(&dev->dev, "unable to register port at index %d "				"(IO%lx MEM%lx IRQ%d): %d\n", i,				p->iobase, p->mapbase, p->irq, ret);		}	}	return 0;}/* * Remove serial ports registered against a platform device. */static int __devexit serial8250_remove(struct platform_device *dev){	int i;	for (i = 0; i < nr_uarts; i++) {		struct uart_8250_port *up = &serial8250_ports[i];		if (up->port.dev == &dev->dev)			serial8250_unregister_port(i);	}	return 0;}static int serial8250_suspend(struct platform_device *dev, pm_message_t state){	int i;	for (i = 0; i < UART_NR; i++) {		struct uart_8250_port *up = &serial8250_ports[i];		if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)			uart_suspend_port(&serial8250_reg, &up->port);	}	return 0;}static int serial8250_resume(struct platform_device *dev){	int i;	for (i = 0; i < UART_NR; i++) {		struct uart_8250_port *up = &serial8250_ports[i];		if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)			uart_resume_port(&serial8250_reg, &up->port);	}	return 0;}static struct platform_driver serial8250_isa_driver = {	.probe		= serial8250_probe,	.remove		= __devexit_p(serial8250_remove),	.suspend	= serial8250_suspend,	.resume		= serial8250_resume,	.driver		= {		.name	= "serial8250",		.owner	= THIS_MODULE,	},};/* * This "device" covers _all_ ISA 8250-compatible serial devices listed * in the table in include/asm/serial.h */static struct platform_device *serial8250_isa_devs;/* * serial8250_register_port and serial8250_unregister_port allows for * 16x50 serial ports to be configured at run-time, to support PCMCIA * modems and PCI multiport cards. */static DEFINE_MUTEX(serial_mutex);static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port){	int i;	/*	 * First, find a port entry which matches.	 */	for (i = 0; i < nr_uarts; i++)		if (uart_match_port(&serial8250_ports[i].port, port))			return &serial8250_ports[i];	/*	 * We didn't find a matching entry, so look for the first	 * free entry.  We look for one which hasn't been previously	 * used (indicated by zero iobase).	 */	for (i = 0; i < nr_uarts; i++)		if (serial8250_ports[i].port.type == PORT_UNKNOWN &&		    serial8250_ports[i].port.iobase == 0)			return &serial8250_ports[i];	/*	 * That also failed.  Last resort is to find any entry which	 * doesn't have a real port associated with it.	 */	for (i = 0; i < nr_uarts; i++)		if (serial8250_ports[i].port.type == PORT_UNKNOWN)			return &serial8250_ports[i];	return NULL;}/** *	serial8250_register_port - register a serial port *	@port: serial port template * *	Configure the serial port specified by the request. If the *	port exists and is in use, it is hung up and unregistered *	first. * *	The port is then probed and if necessary the IRQ is autodetected *	If this fails an error is returned. * *	On success the port is ready to use and the line number is returned. */int serial8250_register_port(struct uart_port *port){	struct uart_8250_port *uart;	int ret = -ENOSPC;	if (port->uartclk == 0)		return -EINVAL;	mutex_lock(&serial_mutex);	uart = serial8250_find_match_or_unused(port);	if (uart) {		uart_remove_one_port(&serial8250_reg, &uart->port);		uart->port.iobase   = port->iobase;		uart->port.membase  = port->membase;		uart->port.irq      = port->irq;		uart->port.uartclk  = port->uartclk;		uart->port.fifosize = port->fifosize;		uart->port.regshift = port->regshift;		uart->port.iotype   = port->iotype;		uart->port.flags    = port->flags | UPF_BOOT_AUTOCONF;		uart->port.mapbase  = port->mapbase;		if (port->dev)			uart->port.dev = port->dev;		ret = uart_add_one_port(&serial8250_reg, &uart->port);		if (ret == 0)			ret = uart->port.line;	}	mutex_unlock(&serial_mutex);	

⌨️ 快捷键说明

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