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

📄 serial_amba.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
			break;		if (timeout && time_after(jiffies, expire))			break;		status = UART_GET_FR(info->port);	}	set_current_state(TASK_RUNNING);}static void ambauart_hangup(struct tty_struct *tty){	struct amba_info *info = tty->driver_data;	struct amba_state *state = info->state;	ambauart_flush_buffer(tty);	if (info->flags & ASYNC_CLOSING)		return;	ambauart_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 block_til_ready(struct tty_struct *tty, struct file *filp,			   struct amba_info *info){	DECLARE_WAITQUEUE(wait, current);	struct amba_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.	 */	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);	save_flags(flags); cli();	if (!tty_hung_up_p(filp)) {		extra_count = 1;		state->count--;	}	restore_flags(flags);	info->blocked_open++;	while (1) {		save_flags(flags); cli();		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&		    (tty->termios->c_cflag & CBAUD)) {			info->mctrl = TIOCM_DTR | TIOCM_RTS;			info->port->set_mctrl(info->port, info->mctrl);		}		restore_flags(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 || (UART_GET_FR(info->port) & AMBA_UARTFR_DCD)))			break;		if (signal_pending(current)) {			retval = -ERESTARTSYS;			break;		}		schedule();	}	set_current_state(TASK_RUNNING);	remove_wait_queue(&info->open_wait, &wait);	if (extra_count)		state->count++;	info->blocked_open--;	if (retval)		return retval;	info->flags |= ASYNC_NORMAL_ACTIVE;	return 0;}static struct amba_info *ambauart_get(int line){	struct amba_info *info;	struct amba_state *state = amba_state + line;	state->count++;	if (state->info)		return state->info;	info = kmalloc(sizeof(struct amba_info), GFP_KERNEL);	if (info) {		memset(info, 0, sizeof(struct amba_info));		init_waitqueue_head(&info->open_wait);		init_waitqueue_head(&info->close_wait);		init_waitqueue_head(&info->delta_msr_wait);		info->flags = state->flags;		info->state = state;		info->port  = amba_ports + line;		tasklet_init(&info->tlet, ambauart_tasklet_action,			     (unsigned long)info);	}	if (state->info) {		kfree(info);		return state->info;	}	state->info = info;	return info;}static int ambauart_open(struct tty_struct *tty, struct file *filp){	struct amba_info *info;	int retval, line = MINOR(tty->device) - tty->driver.minor_start;#if DEBUG	printk("ambauart_open(%d) called\n", line);#endif	// is this a line that we've got?	MOD_INC_USE_COUNT;	if (line >= SERIAL_AMBA_NR) {		MOD_DEC_USE_COUNT;		return -ENODEV;	}	info = ambauart_get(line);	if (!info)		return -ENOMEM;	tty->driver_data = info;	info->tty = tty;	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;	/*	 * Make sure we have the temporary buffer allocated	 */	if (!tmp_buf) {		unsigned long page = get_zeroed_page(GFP_KERNEL);		if (tmp_buf)			free_page(page);		else if (!page) {			MOD_DEC_USE_COUNT;			return -ENOMEM;		}		tmp_buf = (u_char *)page;	}	/*	 * 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);		MOD_DEC_USE_COUNT;		return -EAGAIN;	}	/*	 * Start up the serial port	 */	retval = ambauart_startup(info);	if (retval) {		MOD_DEC_USE_COUNT;		return retval;	}	retval = block_til_ready(tty, filp, info);	if (retval) {		MOD_DEC_USE_COUNT;		return retval;	}	if ((info->state->count == 1) &&	    (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;	}#ifdef CONFIG_SERIAL_AMBA_CONSOLE	if (ambauart_cons.cflag && ambauart_cons.index == line) {		tty->termios->c_cflag = ambauart_cons.cflag;		ambauart_cons.cflag = 0;	}#endif	ambauart_change_speed(info, NULL);	info->session = current->session;	info->pgrp = current->pgrp;	return 0;}int __init ambauart_init(void){	int i;	ambanormal_driver.magic = TTY_DRIVER_MAGIC;	ambanormal_driver.driver_name = "serial_amba";	ambanormal_driver.name = SERIAL_AMBA_NAME;	ambanormal_driver.major = SERIAL_AMBA_MAJOR;	ambanormal_driver.minor_start = SERIAL_AMBA_MINOR;	ambanormal_driver.num = SERIAL_AMBA_NR;	ambanormal_driver.type = TTY_DRIVER_TYPE_SERIAL;	ambanormal_driver.subtype = SERIAL_TYPE_NORMAL;	ambanormal_driver.init_termios = tty_std_termios;	ambanormal_driver.init_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;	ambanormal_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;	ambanormal_driver.refcount = &ambauart_refcount;	ambanormal_driver.table = ambauart_table;	ambanormal_driver.termios = ambauart_termios;	ambanormal_driver.termios_locked = ambauart_termios_locked;	ambanormal_driver.open = ambauart_open;	ambanormal_driver.close = ambauart_close;	ambanormal_driver.write = ambauart_write;	ambanormal_driver.put_char = ambauart_put_char;	ambanormal_driver.flush_chars = ambauart_flush_chars;	ambanormal_driver.write_room = ambauart_write_room;	ambanormal_driver.chars_in_buffer = ambauart_chars_in_buffer;	ambanormal_driver.flush_buffer	= ambauart_flush_buffer;	ambanormal_driver.ioctl = ambauart_ioctl;	ambanormal_driver.throttle = ambauart_throttle;	ambanormal_driver.unthrottle = ambauart_unthrottle;	ambanormal_driver.send_xchar = ambauart_send_xchar;	ambanormal_driver.set_termios = ambauart_set_termios;	ambanormal_driver.stop = ambauart_stop;	ambanormal_driver.start = ambauart_start;	ambanormal_driver.hangup = ambauart_hangup;	ambanormal_driver.break_ctl = ambauart_break_ctl;	ambanormal_driver.wait_until_sent = ambauart_wait_until_sent;	ambanormal_driver.read_proc = NULL;	/*	 * The callout device is just like the normal device except for	 * the major number and the subtype code.	 */	ambacallout_driver = ambanormal_driver;	ambacallout_driver.name = CALLOUT_AMBA_NAME;	ambacallout_driver.major = CALLOUT_AMBA_MAJOR;	ambacallout_driver.subtype = SERIAL_TYPE_CALLOUT;	ambacallout_driver.read_proc = NULL;	ambacallout_driver.proc_entry = NULL;	if (tty_register_driver(&ambanormal_driver))		panic("Couldn't register AMBA serial driver\n");	if (tty_register_driver(&ambacallout_driver))		panic("Couldn't register AMBA callout driver\n");	for (i = 0; i < SERIAL_AMBA_NR; i++) {		struct amba_state *state = amba_state + i;		state->line		= i;		state->close_delay	= 5 * HZ / 10;		state->closing_wait	= 30 * HZ;		state->callout_termios	= ambacallout_driver.init_termios;		state->normal_termios	= ambanormal_driver.init_termios;	}	return 0;}__initcall(ambauart_init);#ifdef CONFIG_SERIAL_AMBA_CONSOLE/************** console driver *****************//* * This code is currently never used; console->read is never called. * Therefore, although we have an implementation, we don't use it. * FIXME: the "const char *s" should be fixed to "char *s" some day. * (when the definition in include/linux/console.h is also fixed) */#ifdef used_and_not_const_char_pointerstatic int ambauart_console_read(struct console *co, const char *s, u_int count){	struct amba_port *port = &amba_ports[co->index];	unsigned int status;	char *w;	int c;#if DEBUG	printk("ambauart_console_read() called\n");#endif	c = 0;	w = s;	while (c < count) {		status = UART_GET_FR(port);		if (UART_RX_DATA(status)) {			*w++ = UART_GET_CHAR(port);			c++;		} else {			// nothing more to get, return			return c;		}	}	// return the count	return c;}#endif/* *	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 void ambauart_console_write(struct console *co, const char *s, u_int count){	struct amba_port *port = &amba_ports[co->index];	unsigned int status, old_cr;	int i;	/*	 *	First save the CR then disable the interrupts	 */	old_cr = UART_GET_CR(port);	UART_PUT_CR(port, AMBA_UARTCR_UARTEN);	/*	 *	Now, do each character	 */	for (i = 0; i < count; i++) {		do {			status = UART_GET_FR(port);		} while (!UART_TX_READY(status));		UART_PUT_CHAR(port, s[i]);		if (s[i] == '\n') {			do {				status = UART_GET_FR(port);			} while (!UART_TX_READY(status));			UART_PUT_CHAR(port, '\r');		}	}	/*	 *	Finally, wait for transmitter to become empty	 *	and restore the TCR	 */	do {		status = UART_GET_FR(port);	} while (status & AMBA_UARTFR_BUSY);	UART_PUT_CR(port, old_cr);}/* *	Receive character from the serial port */static int ambauart_console_wait_key(struct console *co){	struct amba_port *port = &amba_ports[co->index];	unsigned int status;	int c;	do {		status = UART_GET_FR(port);	} while (!UART_RX_DATA(status));	c = UART_GET_CHAR(port);	return c;}static kdev_t ambauart_console_device(struct console *c){	return MKDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + c->index);}static int __init ambauart_console_setup(struct console *co, char *options){	struct amba_port *port;	int baud = 38400;	int bits = 8;	int parity = 'n';	u_int cflag = CREAD | HUPCL | CLOCAL;	u_int lcr_h, quot;	if (co->index >= SERIAL_AMBA_NR)		co->index = 0;	port = &amba_ports[co->index];	if (options) {		char *s = options;		baud = simple_strtoul(s, NULL, 10);		while (*s >= '0' && *s <= '9')			s++;		if (*s) parity = *s++;		if (*s) bits = *s - '0';	}	/*	 *    Now construct a cflag setting.	 */	switch (baud) {	case 1200:	cflag |= B1200;			break;	case 2400:	cflag |= B2400;			break;	case 4800:	cflag |= B4800;			break;	default:	cflag |= B9600;   baud = 9600;	break;	case 19200:	cflag |= B19200;		break;	case 38400:	cflag |= B38400;		break;	case 57600:	cflag |= B57600;		break;	case 115200:	cflag |= B115200;		break;	}	switch (bits) {	case 7:	  cflag |= CS7;	lcr_h = AMBA_UARTLCR_H_WLEN_7;	break;	default:  cflag |= CS8;	lcr_h = AMBA_UARTLCR_H_WLEN_8;	break;	}	switch (parity) {	case 'o':	case 'O': cflag |= PARODD; lcr_h |= AMBA_UARTLCR_H_PEN;	break;	case 'e':	case 'E': cflag |= PARENB; lcr_h |= AMBA_UARTLCR_H_PEN |					    AMBA_UARTLCR_H_EPS; break;	}	co->cflag = cflag;	if (port->fifosize > 1)		lcr_h |= AMBA_UARTLCR_H_FEN;	quot = (port->uartclk / (16 * baud)) - 1;	UART_PUT_LCRL(port, (quot & 0xff));	UART_PUT_LCRM(port, (quot >> 8));	UART_PUT_LCRH(port, lcr_h);	/* we will enable the port as we need it */	UART_PUT_CR(port, 0);	return 0;}static struct console ambauart_cons ={	name:		SERIAL_AMBA_NAME,	write:		ambauart_console_write,#ifdef used_and_not_const_char_pointer	read:		ambauart_console_read,#endif	device:		ambauart_console_device,	wait_key:	ambauart_console_wait_key,	setup:		ambauart_console_setup,	flags:		CON_PRINTBUFFER,	index:		-1,};void __init ambauart_console_init(void){	register_console(&ambauart_cons);}#endif /* CONFIG_SERIAL_AMBA_CONSOLE */

⌨️ 快捷键说明

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