📄 core.c
字号:
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;}extern void ambauart_console_init(void);extern void anakin_console_init(void);extern void clps711xuart_console_init(void);extern void rs285_console_init(void);extern void sa1100_rs_console_init(void);extern void serial8250_console_init(void);extern void ixp1200_console_init(void);/* * Central "initialise all serial consoles" container. Needs to be killed. */void __init uart_console_init(void){#ifdef CONFIG_SERIAL_AMBA_CONSOLE ambauart_console_init();#endif#ifdef CONFIG_SERIAL_ANAKIN_CONSOLE anakin_console_init();#endif#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE clps711xuart_console_init();#endif#ifdef CONFIG_SERIAL_21285_CONSOLE rs285_console_init();#endif#ifdef CONFIG_SERIAL_SA1100_CONSOLE sa1100_rs_console_init();#endif#ifdef CONFIG_SERIAL_8250_CONSOLE serial8250_console_init();#endif#ifdef CONFIG_SERIAL_UART00_CONSOLE uart00_console_init();#endif#ifdef CONFIG_SERIAL_IXP1200_CONSOLE ixp1200_console_init();#endif}#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_set_state(struct uart_state *state, int pm_state, int oldstate){ struct uart_port *port = state->port; struct uart_ops *ops = port->ops; 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, oldstate); 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, oldstate); } 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, oldstate); } return 0;}/* * Wakeup support. */static int uart_pm_set_wakeup(struct uart_state *state, int data){ int err = 0; if (state->port->ops->set_wake) err = state->port->ops->set_wake(state->port, data); return err;}static int uart_pm(struct pm_dev *dev, pm_request_t rqst, void *data){ struct uart_state *state = dev->data; int err = 0; switch (rqst) { case PM_SUSPEND: case PM_RESUME: err = uart_pm_set_state(state, (int)data, dev->state); break; case PM_SET_WAKEUP: err = uart_pm_set_wakeup(state, (int)data); break; } return err;}#endifstatic inline voiduart_report_port(struct uart_driver *drv, struct uart_port *port){ printk("%s%d at ", drv->normal_name, port->line); switch (port->iotype) { case SERIAL_IO_PORT: printk("I/O 0x%x", port->iobase); break; case SERIAL_IO_HUB6: printk("I/O 0x%x offset 0x%x", port->iobase, port->hub6); break; case SERIAL_IO_MEM: printk("MEM 0x%lx", port->mapbase); break; } printk(" (irq = %d) is a %s\n", port->irq, uart_type(port));}static 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); uart_report_port(drv, port); }#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; 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_COM, 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); uart_report_port(drv, state->port); 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);MODULE_DESCRIPTION("Serial driver core");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -