📄 serial_core.c
字号:
return ports + idx;}/** * uart_parse_options - Parse serial port baud/parity/bits/flow contro. * @options: pointer to option string * @baud: pointer to an 'int' variable for the baud rate. * @parity: pointer to an 'int' variable for the parity. * @bits: pointer to an 'int' variable for the number of data bits. * @flow: pointer to an 'int' variable for the flow control character. * * uart_parse_options decodes a string containing the serial console * options. The format of the string is <baud><parity><bits><flow>, * eg: 115200n8r */void __inituart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow){ char *s = options; *baud = simple_strtoul(s, NULL, 10); while (*s >= '0' && *s <= '9') s++; if (*s) *parity = *s++; if (*s) *bits = *s++ - '0'; if (*s) *flow = *s;}/** * uart_set_options - setup the serial console parameters * @port: pointer to the serial ports uart_port structure * @co: console pointer * @baud: baud rate * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) * @bits: number of data bits * @flow: flow control character - 'r' (rts) */int __inituart_set_options(struct uart_port *port, struct console *co, int baud, int parity, int bits, int flow){ u_int cflag = CREAD | HUPCL | CLOCAL; u_int quot; /* * Construct a cflag setting. */ switch (baud) { case 1200: cflag |= B1200; break; case 2400: cflag |= B2400; break; case 4800: cflag |= B4800; break; case 9600: cflag |= B9600; break; case 19200: cflag |= B19200; break; default: cflag |= B38400; baud = 38400; break; case 57600: cflag |= B57600; break; case 115200: cflag |= B115200; break; case 230400: cflag |= B230400; break; case 460800: cflag |= B460800; break; } if (bits == 7) cflag |= CS7; else cflag |= CS8; switch (parity) { case 'o': case 'O': cflag |= PARODD; /*fall through*/ case 'e': case 'E': cflag |= PARENB; break; } co->cflag = cflag; quot = (port->uartclk / (16 * baud)); port->ops->change_speed(port, cflag, 0, quot); return 0;}#endif /* CONFIG_SERIAL_CORE_CONSOLE */#ifdef CONFIG_PM/* * Serial port power management. * * This is pretty coarse at the moment - either all on or all off. We * should probably some day do finer power management here some day. * * We don't actually save any state; the serial driver has enough * state held internally to re-setup the port when we come out of D3. */static int uart_pm(struct pm_dev *dev, pm_request_t rqst, void *data){ if (rqst == PM_SUSPEND || rqst == PM_RESUME) { struct uart_state *state = dev->data; struct uart_port *port = state->port; struct uart_ops *ops = port->ops; int pm_state = (int)data; int running = state->info && state->info->flags & ASYNC_INITIALIZED; if (port->type == PORT_UNKNOWN) return 0;//printk("pm: %08x: %d -> %d, %srunning\n", port->iobase, dev->state, pm_state, running ? "" : "not "); if (pm_state == 0) { if (ops->pm) ops->pm(port, pm_state, dev->state); if (running) { ops->set_mctrl(port, 0); ops->startup(port, state->info); uart_change_speed(state->info, NULL); ops->set_mctrl(port, state->info->mctrl); ops->start_tx(port, 1, 0); } /* * Re-enable the console device after suspending. */ if (state->cons && state->cons->index == port->line) state->cons->flags |= CON_ENABLED; } else if (pm_state == 1) { if (ops->pm) ops->pm(port, pm_state, dev->state); } else { /* * Disable the console device before suspending. */ if (state->cons && state->cons->index == port->line) state->cons->flags &= ~CON_ENABLED; if (running) { ops->stop_tx(port, 0); ops->set_mctrl(port, 0); ops->stop_rx(port); ops->shutdown(port, state->info); } if (ops->pm) ops->pm(port, pm_state, dev->state); } } return 0;}#endifstatic voiduart_setup_port(struct uart_driver *drv, struct uart_state *state){ struct uart_port *port = state->port; int flags = UART_CONFIG_TYPE; init_MUTEX(&state->count_sem); state->close_delay = 5 * HZ / 10; state->closing_wait = 30 * HZ; port->type = PORT_UNKNOWN;#ifdef CONFIG_PM state->cons = drv->cons; state->pm = pm_register(PM_SYS_DEV, PM_SYS_COM, uart_pm); if (state->pm) state->pm->data = state;#endif /* * If there isn't a port here, don't do anything further. */ if (!port->iobase && !port->mapbase) return; /* * Now do the auto configuration stuff. Note that config_port * is expected to claim the resources and map the port for us. */ if (port->flags & ASYNC_AUTO_IRQ) flags |= UART_CONFIG_IRQ; if (port->flags & ASYNC_BOOT_AUTOCONF) port->ops->config_port(port, flags); /* * Only register this port if it is detected. */ if (port->type != PORT_UNKNOWN) { tty_register_devfs(drv->normal_driver, 0, drv->minor + state->port->line); tty_register_devfs(drv->callout_driver, 0, drv->minor + state->port->line); }#ifdef CONFIG_PM /* * Power down all ports by default, except the console if we have one. */ if (state->pm && (!drv->cons || port->line != drv->cons->index)) pm_send(state->pm, PM_SUSPEND, (void *)3);#endif}/* * Register a set of ports with the core driver. Note that we don't * printk any information about the ports; that is up to the low level * driver to do if they so wish. */int uart_register_driver(struct uart_driver *drv){ struct tty_driver *normal, *callout; int i, retval; if (drv->state) panic("drv->state already allocated\n"); /* * Maybe we should be using a slab cache for this, especially if * we have a large number of ports to handle. Note that we also * allocate space for an integer for reference counting. */ drv->state = kmalloc(sizeof(struct uart_state) * drv->nr + sizeof(int), GFP_KERNEL); retval = -ENOMEM; if (!drv->state) goto out; memset(drv->state, 0, sizeof(struct uart_state) * drv->nr + sizeof(int)); normal = drv->normal_driver; callout = drv->callout_driver; normal->magic = TTY_DRIVER_MAGIC; normal->driver_name = drv->normal_name; normal->name = drv->normal_name; normal->major = drv->normal_major; normal->minor_start = drv->minor; normal->num = drv->nr; normal->type = TTY_DRIVER_TYPE_SERIAL; normal->subtype = SERIAL_TYPE_NORMAL; normal->init_termios = tty_std_termios; normal->init_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; normal->refcount = (int *)(drv->state + drv->nr); normal->table = drv->table; normal->termios = drv->termios; normal->termios_locked = drv->termios_locked; normal->driver_state = drv; normal->open = uart_open; normal->close = uart_close; normal->write = uart_write; normal->put_char = uart_put_char; normal->flush_chars = uart_flush_chars; normal->write_room = uart_write_room; normal->chars_in_buffer = uart_chars_in_buffer; normal->flush_buffer = uart_flush_buffer; normal->ioctl = uart_ioctl; normal->throttle = uart_throttle; normal->unthrottle = uart_unthrottle; normal->send_xchar = uart_send_xchar; normal->set_termios = uart_set_termios; normal->stop = uart_stop; normal->start = uart_start; normal->hangup = uart_hangup; normal->break_ctl = uart_break_ctl; normal->wait_until_sent = uart_wait_until_sent;#ifdef CONFIG_PROC_FS normal->read_proc = uart_read_proc;#endif /* * The callout device is just like the normal device except for * the major number and the subtype code. */ callout = normal + 1; *callout = *normal; callout->name = drv->callout_name; callout->major = drv->callout_major; callout->subtype = SERIAL_TYPE_CALLOUT; callout->read_proc = NULL; callout->proc_entry = NULL; for (i = 0; i < drv->nr; i++) { struct uart_state *state = drv->state + i; state->callout_termios = callout->init_termios; state->normal_termios = normal->init_termios; state->port = drv->port + i; state->port->line = i; uart_setup_port(drv, state); } retval = tty_register_driver(normal); if (retval) goto out; retval = tty_register_driver(callout); if (retval) tty_unregister_driver(normal);out: if (retval && drv->state) kfree(drv->state); return retval;}void uart_unregister_driver(struct uart_driver *drv){ int i; for (i = 0; i < drv->nr; i++) { struct uart_state *state = drv->state + i; if (state->info && state->info->tty) tty_hangup(state->info->tty); pm_unregister(state->pm); if (state->port->type != PORT_UNKNOWN) state->port->ops->release_port(state->port); if (state->info) { tasklet_kill(&state->info->tlet); kfree(state->info); } } tty_unregister_driver(drv->normal_driver); tty_unregister_driver(drv->callout_driver); kfree(drv->state);}static int uart_match_port(struct uart_port *port1, struct uart_port *port2){ if (port1->iotype != port2->iotype) return 0; switch (port1->iotype) { case SERIAL_IO_PORT: return (port1->iobase == port2->iobase); case SERIAL_IO_MEM: return (port1->membase == port2->membase); } return 0;}/** * uart_register_port: register a port with the generic uart driver * @reg: pointer to the uart low level driver structure for this port * @port: uart port structure describing the port * * Register a UART with the specified low level driver. Detect the * type of the port if ASYNC_BOOT_AUTOCONF is set, and detect the IRQ * if ASYNC_AUTO_IRQ is set. * * Returns negative error, or positive line number. */int uart_register_port(struct uart_driver *drv, struct uart_port *port){ struct uart_state *state = NULL; int i, flags = UART_CONFIG_TYPE; /* * First, find a port entry which matches. Note: if we do * find a matching entry, and it has a non-zero use count, * then we can't register the port. */ down(&port_sem); for (i = 0; i < drv->nr; i++) { if (uart_match_port(drv->state[i].port, port)) { down(&drv->state[i].count_sem); state = &drv->state[i]; break; } } /* * If we didn't find a matching entry, look for the first * free entry. We look for one which hasn't been previously * used (indicated by zero iobase). */ if (!state) { for (i = 0; i < drv->nr; i++) { if (drv->state[i].port->type == PORT_UNKNOWN && drv->state[i].port->iobase == 0) { down(&drv->state[i].count_sem); if (drv->state[i].count == 0) { state = &drv->state[i]; break; } } } } /* * Ok, that also failed. Find the first unused entry, which * may be previously in use. */ if (!state) { for (i = 0; i < drv->nr; i++) { if (drv->state[i].port->type == PORT_UNKNOWN) { down(&drv->state[i].count_sem); if (drv->state[i].count == 0) { state = &drv->state[i]; break; } } } } up(&port_sem); if (!state) return -ENOSPC; /* * If we find a port that matches this one, and it appears to * be in-use (even if it doesn't have a type) we shouldn't alter * it underneath itself - the port may be open and trying to do * useful work. */ if (state->count != 0 || (state->info && state->info->blocked_open != 0)) { up(&state->count_sem); return -EBUSY; } /* * We're holding the lock for this port. Copy the relevant data * into the port structure. */ state->port->iobase = port->iobase; state->port->membase = port->membase; state->port->irq = port->irq; state->port->uartclk = port->uartclk; state->port->fifosize = port->fifosize; state->port->regshift = port->regshift; state->port->iotype = port->iotype; state->port->flags = port->flags;#if 0 //def CONFIG_PM /* we have already registered the power management handlers */ state->pm = pm_register(PM_SYS_DEV, PM_SYS_CON, uart_pm); if (state->pm) { state->pm->data = state; /* * Power down all ports by default, except * the console if we have one. */ if (!drv->cons || state->port->line != drv->cons->index) pm_send(state->pm, PM_SUSPEND, (void *)3); }#endif if (state->port->flags & ASYNC_AUTO_IRQ) flags |= UART_CONFIG_IRQ; if (state->port->flags & ASYNC_BOOT_AUTOCONF) state->port->ops->config_port(state->port, flags); tty_register_devfs(drv->normal_driver, 0, drv->minor + state->port->line); tty_register_devfs(drv->callout_driver, 0, drv->minor + state->port->line); up(&state->count_sem); return i;}/* * Unregister the specified port index on the specified driver. */void uart_unregister_port(struct uart_driver *drv, int line){ struct uart_state *state; if (line < 0 || line >= drv->nr) { printk(KERN_ERR "Attempt to unregister %s%d\n", drv->normal_name, line); return; } state = drv->state + line; down(&state->count_sem); /* * The port has already gone. We have to hang up the line * to kill all usage of this port. */ if (state->info && state->info->tty) tty_hangup(state->info->tty); /* * Free the ports resources, if any. */ state->port->ops->release_port(state->port); /* * Indicate that there isn't a port here anymore. */ state->port->type = PORT_UNKNOWN;#if 0 // not yet /* * No point in doing power management for hardware that * isn't present. */ pm_unregister(state->pm);#endif /* * Remove the devices from devfs */ tty_unregister_devfs(drv->normal_driver, drv->minor + line); tty_unregister_devfs(drv->callout_driver, drv->minor + line); up(&state->count_sem);}EXPORT_SYMBOL(uart_event);EXPORT_SYMBOL(uart_register_driver);EXPORT_SYMBOL(uart_unregister_driver);EXPORT_SYMBOL(uart_register_port);EXPORT_SYMBOL(uart_unregister_port);static int __init uart_init(void){ return 0;}static void __exit uart_exit(void){ free_page((unsigned long)tmp_buf); tmp_buf = NULL;}module_init(uart_init);module_exit(uart_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -