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

📄 serial_core.c

📁 宋宝华的《Linux设备驱动开发详解》第一版的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
				     ports[idx].membase == NULL))		for (idx = 0; idx < nr; idx++)			if (ports[idx].iobase != 0 ||			    ports[idx].membase != NULL)				break;	co->index = idx;	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;}struct baud_rates {	unsigned int rate;	unsigned int cflag;};static const struct baud_rates baud_rates[] = {	{ 921600, B921600 },	{ 460800, B460800 },	{ 230400, B230400 },	{ 115200, B115200 },	{  57600, B57600  },	{  38400, B38400  },	{  19200, B19200  },	{   9600, B9600   },	{   4800, B4800   },	{   2400, B2400   },	{   1200, B1200   },	{      0, B38400  }};/** *	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){	struct termios termios;	int i;	/*	 * Ensure that the serial console lock is initialised	 * early.	 */	spin_lock_init(&port->lock);	memset(&termios, 0, sizeof(struct termios));	termios.c_cflag = CREAD | HUPCL | CLOCAL;	/*	 * Construct a cflag setting.	 */	for (i = 0; baud_rates[i].rate; i++)		if (baud_rates[i].rate <= baud)			break;	termios.c_cflag |= baud_rates[i].cflag;	if (bits == 7)		termios.c_cflag |= CS7;	else		termios.c_cflag |= CS8;	switch (parity) {	case 'o': case 'O':		termios.c_cflag |= PARODD;		/*fall through*/	case 'e': case 'E':		termios.c_cflag |= PARENB;		break;	}	if (flow == 'r')		termios.c_cflag |= CRTSCTS;	port->ops->set_termios(port, &termios, NULL);	co->cflag = termios.c_cflag;	return 0;}#endif /* CONFIG_SERIAL_CORE_CONSOLE */static void uart_change_pm(struct uart_state *state, int pm_state){	struct uart_port *port = state->port;	if (port->ops->pm)		port->ops->pm(port, pm_state, state->pm_state);	state->pm_state = pm_state;}int uart_suspend_port(struct uart_driver *drv, struct uart_port *port){	struct uart_state *state = drv->state + port->line;	mutex_lock(&state->mutex);	if (state->info && state->info->flags & UIF_INITIALIZED) {		const struct uart_ops *ops = port->ops;		spin_lock_irq(&port->lock);		ops->stop_tx(port);		ops->set_mctrl(port, 0);		ops->stop_rx(port);		spin_unlock_irq(&port->lock);		/*		 * Wait for the transmitter to empty.		 */		while (!ops->tx_empty(port)) {			msleep(10);		}		ops->shutdown(port);	}	/*	 * Disable the console device before suspending.	 */	if (uart_console(port))		console_stop(port->cons);	uart_change_pm(state, 3);	mutex_unlock(&state->mutex);	return 0;}int uart_resume_port(struct uart_driver *drv, struct uart_port *port){	struct uart_state *state = drv->state + port->line;	mutex_lock(&state->mutex);	uart_change_pm(state, 0);	/*	 * Re-enable the console device after suspending.	 */	if (uart_console(port)) {		struct termios termios;		/*		 * First try to use the console cflag setting.		 */		memset(&termios, 0, sizeof(struct termios));		termios.c_cflag = port->cons->cflag;		/*		 * If that's unset, use the tty termios setting.		 */		if (state->info && state->info->tty && termios.c_cflag == 0)			termios = *state->info->tty->termios;		port->ops->set_termios(port, &termios, NULL);		console_start(port->cons);	}	if (state->info && state->info->flags & UIF_INITIALIZED) {		const struct uart_ops *ops = port->ops;		int ret;		ops->set_mctrl(port, 0);		ret = ops->startup(port);		if (ret == 0) {			uart_change_speed(state, NULL);			spin_lock_irq(&port->lock);			ops->set_mctrl(port, port->mctrl);			ops->start_tx(port);			spin_unlock_irq(&port->lock);		} else {			/*			 * Failed to resume - maybe hardware went away?			 * Clear the "initialized" flag so we won't try			 * to call the low level drivers shutdown method.			 */			state->info->flags &= ~UIF_INITIALIZED;			uart_shutdown(state);		}	}	mutex_unlock(&state->mutex);	return 0;}static inline voiduart_report_port(struct uart_driver *drv, struct uart_port *port){	char address[64];	switch (port->iotype) {	case UPIO_PORT:		snprintf(address, sizeof(address),			 "I/O 0x%x", port->iobase);		break;	case UPIO_HUB6:		snprintf(address, sizeof(address),			 "I/O 0x%x offset 0x%x", port->iobase, port->hub6);		break;	case UPIO_MEM:	case UPIO_MEM32:	case UPIO_AU:		snprintf(address, sizeof(address),			 "MMIO 0x%lx", port->mapbase);		break;	default:		strlcpy(address, "*unknown*", sizeof(address));		break;	}	printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",	       port->dev ? port->dev->bus_id : "",	       port->dev ? ": " : "",	       drv->dev_name, port->line, address, port->irq, uart_type(port));}static voiduart_configure_port(struct uart_driver *drv, struct uart_state *state,		    struct uart_port *port){	unsigned int flags;	/*	 * If there isn't a port here, don't do anything further.	 */	if (!port->iobase && !port->mapbase && !port->membase)		return;	/*	 * Now do the auto configuration stuff.  Note that config_port	 * is expected to claim the resources and map the port for us.	 */	flags = UART_CONFIG_TYPE;	if (port->flags & UPF_AUTO_IRQ)		flags |= UART_CONFIG_IRQ;	if (port->flags & UPF_BOOT_AUTOCONF) {		port->type = PORT_UNKNOWN;		port->ops->config_port(port, flags);	}	if (port->type != PORT_UNKNOWN) {		unsigned long flags;		uart_report_port(drv, port);		/*		 * Ensure that the modem control lines are de-activated.		 * We probably don't need a spinlock around this, but		 */		spin_lock_irqsave(&port->lock, flags);		port->ops->set_mctrl(port, 0);		spin_unlock_irqrestore(&port->lock, flags);		/*		 * Power down all ports by default, except the		 * console if we have one.		 */		if (!uart_console(port))			uart_change_pm(state, 3);	}}/* * This reverses the effects of uart_configure_port, hanging up the * port before removal. */static voiduart_unconfigure_port(struct uart_driver *drv, struct uart_state *state){	struct uart_port *port = state->port;	struct uart_info *info = state->info;	if (info && info->tty)		tty_vhangup(info->tty);	mutex_lock(&state->mutex);	state->info = NULL;	/*	 * Free the port IO and memory resources, if any.	 */	if (port->type != PORT_UNKNOWN)		port->ops->release_port(port);	/*	 * Indicate that there isn't a port here anymore.	 */	port->type = PORT_UNKNOWN;	/*	 * Kill the tasklet, and free resources.	 */	if (info) {		tasklet_kill(&info->tlet);		kfree(info);	}	mutex_unlock(&state->mutex);}static struct tty_operations uart_ops = {	.open		= uart_open,	.close		= uart_close,	.write		= uart_write,	.put_char	= uart_put_char,	.flush_chars	= uart_flush_chars,	.write_room	= uart_write_room,	.chars_in_buffer= uart_chars_in_buffer,	.flush_buffer	= uart_flush_buffer,	.ioctl		= uart_ioctl,	.throttle	= uart_throttle,	.unthrottle	= uart_unthrottle,	.send_xchar	= uart_send_xchar,	.set_termios	= uart_set_termios,	.stop		= uart_stop,	.start		= uart_start,	.hangup		= uart_hangup,	.break_ctl	= uart_break_ctl,	.wait_until_sent= uart_wait_until_sent,#ifdef CONFIG_PROC_FS	.read_proc	= uart_read_proc,#endif	.tiocmget	= uart_tiocmget,	.tiocmset	= uart_tiocmset,};/** *	uart_register_driver - register a driver with the uart core layer *	@drv: low level driver structure * *	Register a uart driver with the core driver.  We in turn register *	with the tty layer, and initialise the core driver per-port state. * *	We have a proc file in /proc/tty/driver which is named after the *	normal driver. * *	drv->port should be NULL, and the per-port structures should be *	registered using uart_add_one_port after this call has succeeded. */int uart_register_driver(struct uart_driver *drv){	struct tty_driver *normal = NULL;	int i, retval;	BUG_ON(drv->state);	/*	 * Maybe we should be using a slab cache for this, especially if	 * we have a large number of ports to handle.	 */	drv->state = kmalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);	retval = -ENOMEM;	if (!drv->state)		goto out;	memset(drv->state, 0, sizeof(struct uart_state) * drv->nr);	normal  = alloc_tty_driver(drv->nr);	if (!normal)		goto out;	drv->tty_driver = normal;	normal->owner		= drv->owner;	normal->driver_name	= drv->driver_name;	normal->devfs_name	= drv->devfs_name;	normal->name		= drv->dev_name;	normal->major		= drv->major;	normal->minor_start	= drv->minor;	normal->type		= TTY_DRIVER_TYPE_SERIAL;	normal->subtype		= SERIAL_TYPE_NORMAL;	normal->init_termios	= tty_std_termios;	normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;	normal->flags		= TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;	normal->driver_state    = drv;	tty_set_operations(normal, &uart_ops);	/*	 * Initialise the UART state(s).	 */	for (i = 0; i < drv->nr; i++) {		struct uart_state *state = drv->state + i;		state->close_delay     = 500;	/* .5 seconds */		state->closing_wait    = 30000;	/* 30 seconds */		mutex_init(&state->mutex);	}	retval = tty_register_driver(normal); out:	if (retval < 0) {		put_tty_driver(normal);		kfree(drv->state);	}	return retval;}/** *	uart_unregister_driver - remove a driver from the uart core layer *	@drv: low level driver structure * *	Remove all references to a driver from the core driver.  The low *	level driver must have removed all its ports via the *	uart_remove_one_port() if it registered them with uart_add_one_port(). *	(ie, drv->port == NULL) */void uart_unregister_driver(struct uart_driver *drv){	struct tty_driver *p = drv->tty_driver;	tty_unregister_driver(p);	put_tty_driver(p);	kfree(drv->state);	drv->tty_driver = NULL;}struct tty_driver *uart_console_device(struct console *co, int *index){	struct uart_driver *p = co->data;	*index = co->index;	return p->tty_driver;}/** *	uart_add_one_port - attach a driver-defined port structure *	@drv: pointer to the uart low level driver structure for this port *	@port: uart port structure to use for this port. * *	This allows the driver to register its own uart_port structure *	with the core driver.  The main purpose is to allow the low *	level uart drivers to expand uart_port, rather than having yet *	more levels of structures. */int uart_add_one_port(struct uart_driver *drv, struct uart_port *port){	struct uart_state *state;	int ret = 0;	BUG_ON(in_interrupt());	if (port->line >= drv->nr)		return -EINVAL;	state = drv->state + port->line;	mutex_lock(&port_mutex);	if (state->port) {		ret = -EINVAL;		goto out;	}	state->port = port;	port->cons = drv->cons;	port->info = state->info;	/*	 * If this port is a console, then the spinlock is already	 * initialised.	 */	if (!(uart_console(port) && (port->cons->flags & CON_ENABLED)))		spin_lock_init(&port->lock);	uart_configure_port(drv, state, port);	/*	 * Register the port whether it's detected or not.  This allows	 * setserial to be used to alter this ports parameters.	 */	tty_register_device(drv->tty_driver, port->line, port->dev);	/*	 * If this driver supports console, and it hasn't been	 * successfully registered yet, try to re-register it.	 * It may be that the port was not available.	 */	if (port->type != PORT_UNKNOWN &&	    port->cons && !(port->cons->flags & CON_ENABLED))		register_console(port->cons); out:	mutex_unlock(&port_mutex);	return ret;}/** *	uart_remove_one_port - detach a driver defined port structure *	@drv: pointer to the uart low level driver structure for this port *	@port: uart port structure for this port * *	This unhooks (and hangs up) the specified port structure from the *	core driver.  No further calls will be made to the low-level code *	for this port. */int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port){	struct uart_state *state = drv->state + port->line;	BUG_ON(in_interrupt());	if (state->port != port)		printk(KERN_ALERT "Removing wrong port: %p != %p\n",			state->port, port);	mutex_lock(&port_mutex);	/*	 * Remove the devices from devfs	 */	tty_unregister_device(drv->tty_driver, port->line);	uart_unconfigure_port(drv, state);	state->port = NULL;	mutex_unlock(&port_mutex);	return 0;}/* *	Are the two ports equivalent? */int uart_match_port(struct uart_port *port1, struct uart_port *port2){	if (port1->iotype != port2->iotype)		return 0;	switch (port1->iotype) {	case UPIO_PORT:		return (port1->iobase == port2->iobase);	case UPIO_HUB6:		return (port1->iobase == port2->iobase) &&		       (port1->hub6   == port2->hub6);	case UPIO_MEM:		return (port1->mapbase == port2->mapbase);	}	return 0;}EXPORT_SYMBOL(uart_match_port);EXPORT_SYMBOL(uart_write_wakeup);EXPORT_SYMBOL(uart_register_driver);EXPORT_SYMBOL(uart_unregister_driver);EXPORT_SYMBOL(uart_suspend_port);EXPORT_SYMBOL(uart_resume_port);EXPORT_SYMBOL(uart_add_one_port);EXPORT_SYMBOL(uart_remove_one_port);MODULE_DESCRIPTION("Serial driver core");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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