📄 8250.c
字号:
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 + -