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

📄 core.c

📁 IXP425 平台下嵌入式LINUX的串口的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
		}		wake_up_interruptible(&info->open_wait);	} else {#ifdef CONFIG_PM		/*		 * Put device into D3 state.		 */		pm_send(info->state->pm, PM_SUSPEND, (void *)3);#else		if (info->ops->pm)			info->ops->pm(info->port, 3, 0);#endif	}	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|			 ASYNC_CLOSING);	wake_up_interruptible(&info->close_wait);done:	if (drv->owner)		__MOD_DEC_USE_COUNT(drv->owner);}static void uart_wait_until_sent(struct tty_struct *tty, int timeout){	struct uart_info *info = (struct uart_info *) tty->driver_data;	unsigned long char_time, expire;	if (info->port->type == PORT_UNKNOWN ||	    info->port->fifosize == 0)		return;	/*	 * Set the check interval to be 1/5 of the estimated time to	 * send a single character, and make it at least 1.  The check	 * interval should also be less than the timeout.	 *	 * Note: we have to use pretty tight timings here to satisfy	 * the NIST-PCTS.	 */	char_time = (info->timeout - HZ/50) / info->port->fifosize;	char_time = char_time / 5;	if (char_time == 0)		char_time = 1;	if (timeout && timeout < char_time)		char_time = timeout;	/*	 * If the transmitter hasn't cleared in twice the approximate	 * amount of time to send the entire FIFO, it probably won't	 * ever clear.  This assumes the UART isn't doing flow	 * control, which is currently the case.  Hence, if it ever	 * takes longer than info->timeout, this is probably due to a	 * UART bug of some kind.  So, we clamp the timeout parameter at	 * 2*info->timeout.	 */	if (!timeout || timeout > 2 * info->timeout)		timeout = 2 * info->timeout;	expire = jiffies + timeout;#ifdef DEBUG	printk("uart_wait_until_sent(%d), jiff=%lu, expire=%lu...\n",	       MINOR(tty->device) - tty->driver.minor_start, jiffies,	       expire);#endif	while (!info->ops->tx_empty(info->port)) {		set_current_state(TASK_INTERRUPTIBLE);		schedule_timeout(char_time);		if (signal_pending(current))			break;		if (timeout && time_after(jiffies, expire))			break;	}	set_current_state(TASK_RUNNING); /* might not be needed */}/* * This is called with the BKL in effect *  linux/drivers/char/tty_io.c:do_tty_hangup() */static void uart_hangup(struct tty_struct *tty){	struct uart_info *info = tty->driver_data;	struct uart_state *state = info->state;	uart_flush_buffer(tty);	if (info->flags & ASYNC_CLOSING)		return;	uart_shutdown(info);	info->event = 0;	state->count = 0;	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);	info->tty = NULL;	wake_up_interruptible(&info->open_wait);}static int uart_block_til_ready(struct tty_struct *tty, struct file *filp,				struct uart_info *info){	DECLARE_WAITQUEUE(wait, current);	struct uart_state *state = info->state;	unsigned long flags;	int do_clocal = 0, extra_count = 0, retval;	/*	 * If the device is in the middle of being closed, then block	 * until it's done, and then try again.	 */	if (tty_hung_up_p(filp) ||	    (info->flags & ASYNC_CLOSING)) {		if (info->flags & ASYNC_CLOSING)			interruptible_sleep_on(&info->close_wait);		return (info->flags & ASYNC_HUP_NOTIFY) ?			-EAGAIN : -ERESTARTSYS;	}	/*	 * If this is a callout device, then just make sure the normal	 * device isn't being used.	 */	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {		if (info->flags & ASYNC_NORMAL_ACTIVE)			return -EBUSY;		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&		    (info->flags & ASYNC_SESSION_LOCKOUT) &&		    (info->session != current->session))			return -EBUSY;		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&		    (info->flags & ASYNC_PGRP_LOCKOUT) &&		    (info->pgrp != current->pgrp))			return -EBUSY;		info->flags |= ASYNC_CALLOUT_ACTIVE;		return 0;	}	/*	 * If non-blocking mode is set, or the port is not enabled,	 * then make the check up front and then exit.  Note that	 * we have set TTY_IO_ERROR for a non-enabled port.	 */	if ((filp->f_flags & O_NONBLOCK) ||	    (tty->flags & (1 << TTY_IO_ERROR))) {		if (info->flags & ASYNC_CALLOUT_ACTIVE)			return -EBUSY;		info->flags |= ASYNC_NORMAL_ACTIVE;		return 0;	}	if (info->flags & ASYNC_CALLOUT_ACTIVE) {		if (state->normal_termios.c_cflag & CLOCAL)			do_clocal = 1;	} else {		if (tty->termios->c_cflag & CLOCAL)			do_clocal = 1;	}	/*	 * Block waiting for the carrier detect and the line to become	 * free (i.e., not in use by the callout).  While we are in	 * this loop, state->count is dropped by one, so that	 * rs_close() knows when to free things.  We restore it upon	 * exit, either normal or abnormal.	 */	retval = 0;	add_wait_queue(&info->open_wait, &wait);	down(&state->count_sem);	spin_lock_irqsave(&info->lock, flags);	if (!tty_hung_up_p(filp)) {		extra_count = 1;		state->count--;	}	spin_unlock_irqrestore(&info->lock, flags);	info->blocked_open++;	up(&state->count_sem);	while (1) {		spin_lock_irqsave(&info->lock, flags);		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&		    (tty->termios->c_cflag & CBAUD)) {			info->mctrl |= TIOCM_DTR | TIOCM_RTS;			info->ops->set_mctrl(info->port, info->mctrl);		}		spin_unlock_irqrestore(&info->lock, flags);		set_current_state(TASK_INTERRUPTIBLE);		if (tty_hung_up_p(filp) ||		    !(info->flags & ASYNC_INITIALIZED)) {			if (info->flags & ASYNC_HUP_NOTIFY)				retval = -EAGAIN;			else				retval = -ERESTARTSYS;			break;		}		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&		    !(info->flags & ASYNC_CLOSING) &&		    (do_clocal ||		     (info->ops->get_mctrl(info->port) & TIOCM_CAR)))			break;		if (signal_pending(current)) {			retval = -ERESTARTSYS;			break;		}		schedule();	}	set_current_state(TASK_RUNNING);	remove_wait_queue(&info->open_wait, &wait);	down(&state->count_sem);	if (extra_count)		state->count++;	info->blocked_open--;	up(&state->count_sem);	if (retval)		return retval;	info->flags |= ASYNC_NORMAL_ACTIVE;	return 0;}static struct uart_info *uart_get(struct uart_driver *drv, int line){	struct uart_state *state = drv->state + line;	struct uart_info *info;	down(&state->count_sem);	state->count++;	if (state->info)		goto out;	info = kmalloc(sizeof(struct uart_info), GFP_KERNEL);	if (info) {		memset(info, 0, sizeof(struct uart_info));		init_waitqueue_head(&info->open_wait);		init_waitqueue_head(&info->close_wait);		init_waitqueue_head(&info->delta_msr_wait);		info->port  = state->port;		info->flags = info->port->flags;		info->ops   = info->port->ops;		info->state = state;		tasklet_init(&info->tlet, uart_tasklet_action,			     (unsigned long)info);	}	if (state->info)		kfree(info);	else		state->info = info;out:	up(&state->count_sem);	return state->info;}/* * Make sure we have the temporary buffer allocated.  Note * that we set retval appropriately above, and we rely on * this. */static inline int uart_alloc_tmpbuf(void){	if (!tmp_buf) {		unsigned long buf = get_zeroed_page(GFP_KERNEL);		if (!tmp_buf) {			if (buf)				tmp_buf = (u_char *)buf;			else				return -ENOMEM;		} else			free_page(buf);	}	return 0;}/* * In 2.4.5, calls to uart_open are serialised by the BKL in *   linux/fs/devices.c:chrdev_open() * Note that if this fails, then uart_close() _will_ be called. */static int uart_open(struct tty_struct *tty, struct file *filp){	struct uart_driver *drv = (struct uart_driver *)tty->driver.driver_state;	struct uart_info *info;	int retval, line = MINOR(tty->device) - tty->driver.minor_start;#ifdef DEBUG	printk("uart_open(%d) called\n", line);#endif	retval = -ENODEV;	if (line >= tty->driver.num)		goto fail;	if (!try_inc_mod_count(drv->owner))		goto fail;	info = uart_get(drv, line);	retval = -ENOMEM;	if (!info)		goto out;	/*	 * Set the tty driver_data.  If we fail from this point on,	 * the generic tty layer will cause uart_close(), which will	 * decrement the module use count.	 */	tty->driver_data = info;	info->tty = tty;	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;	if (uart_alloc_tmpbuf())		goto fail;	/*	 * If the port is in the middle of closing, bail out now.	 */	if (tty_hung_up_p(filp) ||	    (info->flags & ASYNC_CLOSING)) {		if (info->flags & ASYNC_CLOSING)			interruptible_sleep_on(&info->close_wait);		retval = (info->flags & ASYNC_HUP_NOTIFY) ?			-EAGAIN : -ERESTARTSYS;		goto fail;	}	/*	 * Make sure the device is in D0 state.	 */	if (info->state->count == 1)#ifdef CONFIG_PM		pm_send(info->state->pm, PM_RESUME, (void *)0);#else		if (info->ops->pm)			info->ops->pm(info->port, 0, 3);#endif	/*	 * Start up the serial port	 */	retval = uart_startup(info);	if (retval)		goto fail;	retval = uart_block_til_ready(tty, filp, info);	if (retval)		goto fail;	if (info->state->count == 1) {		int changed_termios = 0;		if (info->flags & ASYNC_SPLIT_TERMIOS) {			if (tty->driver.subtype == SERIAL_TYPE_NORMAL)				*tty->termios = info->state->normal_termios;			else				*tty->termios = info->state->callout_termios;			changed_termios = 1;		}#ifdef CONFIG_SERIAL_CORE_CONSOLE		/*		 * Copy across the serial console cflag setting		 */		{			struct console *c = drv->cons;			if (c && c->cflag && c->index == line) {				tty->termios->c_cflag = c->cflag;				c->cflag = 0;				changed_termios = 1;			}		}#endif		if (changed_termios)			uart_change_speed(info, NULL);	}	info->session = current->session;	info->pgrp = current->pgrp;	return 0;out:	if (drv->owner)		__MOD_DEC_USE_COUNT(drv->owner);fail:	return retval;}#ifdef CONFIG_PROC_FSstatic const char *uart_type(struct uart_port *port){	const char *str = NULL;	if (port->ops->type)		str = port->ops->type(port);	if (!str)		str = "unknown";	return str;}static int uart_line_info(char *buf, struct uart_driver *drv, int i){	struct uart_state *state = drv->state + i;	struct uart_port *port = state->port;	char stat_buf[32];	u_int status;	int ret;	ret = sprintf(buf, "%d: uart:%s port:%08X irq:%d",			port->line, uart_type(port),			port->iobase, port->irq);	if (port->type == PORT_UNKNOWN) {		strcat(buf, "\n");		return ret + 1;	}	status = port->ops->get_mctrl(port);	ret += sprintf(buf + ret, " tx:%d rx:%d",			port->icount.tx, port->icount.rx);	if (port->icount.frame)		ret += sprintf(buf + ret, " fe:%d",			port->icount.frame);	if (port->icount.parity)		ret += sprintf(buf + ret, " pe:%d",			port->icount.parity);	if (port->icount.brk)		ret += sprintf(buf + ret, " brk:%d",			port->icount.brk);	if (port->icount.overrun)		ret += sprintf(buf + ret, " oe:%d",			port->icount.overrun);#define INFOBIT(bit,str) \	if (state->info && state->info->mctrl & (bit)) \		strcat(stat_buf, (str))#define STATBIT(bit,str) \	if (status & (bit)) \		strcat(stat_buf, (str))	stat_buf[0] = '\0';	stat_buf[1] = '\0';	INFOBIT(TIOCM_RTS, "|RTS");	STATBIT(TIOCM_CTS, "|CTS");	INFOBIT(TIOCM_DTR, "|DTR");	STATBIT(TIOCM_DSR, "|DSR");	STATBIT(TIOCM_CAR, "|CD");	STATBIT(TIOCM_RNG, "|RI");	if (stat_buf[0])		stat_buf[0] = ' ';	strcat(stat_buf, "\n");	ret += sprintf(buf + ret, stat_buf);	return ret;}static int uart_read_proc(char *page, char **start, off_t off,			  int count, int *eof, void *data){	struct tty_driver *ttydrv = data;	struct uart_driver *drv = ttydrv->driver_state;	int i, len = 0, l;	off_t begin = 0;	len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n",			"", "", "");	for (i = 0; i < drv->nr && len < PAGE_SIZE - 96; i++) {		l = uart_line_info(page + len, drv, i);		len += l;		if (len + begin > off + count)			goto done;		if (len + begin < off) {			begin += len;			len = 0;		}	}	*eof = 1;done:	if (off >= len + begin)		return 0;	*start = page + (off - begin);	return (count < begin + len - off) ? count : (begin + len - off);}#endif#ifdef CONFIG_SERIAL_CORE_CONSOLE/* *	Check whether an invalid uart number has been specified, and *	if so, search for the first available port that does have *	console support. */struct uart_port * __inituart_get_console(struct uart_port *ports, int nr, struct console *co){	int idx = co->index;	if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 &&				     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;}/** *	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)

⌨️ 快捷键说明

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