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

📄 simserial.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (!(info->flags & ASYNC_INITIALIZED)) return;	state = info->state;#ifdef SIMSERIAL_DEBUG	printk("Shutting down serial port %d (irq %d)....", info->line,	       state->irq);#endif	local_irq_save(flags);	{		/*		 * First unlink the serial port from the IRQ chain...		 */		if (info->next_port)			info->next_port->prev_port = info->prev_port;		if (info->prev_port)			info->prev_port->next_port = info->next_port;		else			IRQ_ports[state->irq] = info->next_port;		/*		 * Free the IRQ, if necessary		 */		if (state->irq && (!IRQ_ports[state->irq] ||				   !IRQ_ports[state->irq]->next_port)) {			if (IRQ_ports[state->irq]) {				free_irq(state->irq, NULL);				retval = request_irq(state->irq, rs_interrupt_single,						     IRQ_T(info), "serial", NULL);				if (retval)					printk(KERN_ERR "serial shutdown: request_irq: error %d"					       "  Couldn't reacquire IRQ.\n", retval);			} else				free_irq(state->irq, NULL);		}		if (info->xmit.buf) {			free_page((unsigned long) info->xmit.buf);			info->xmit.buf = NULL;		}		if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);		info->flags &= ~ASYNC_INITIALIZED;	}	local_irq_restore(flags);}/* * ------------------------------------------------------------ * rs_close() * * This routine is called when the serial port gets closed.  First, we * wait for the last remaining data to be sent.  Then, we unlink its * async structure from the interrupt chain if necessary, and we free * that IRQ if nothing is left in the chain. * ------------------------------------------------------------ */static void rs_close(struct tty_struct *tty, struct file * filp){	struct async_struct * info = (struct async_struct *)tty->driver_data;	struct serial_state *state;	unsigned long flags;	if (!info ) return;	state = info->state;	local_irq_save(flags);	if (tty_hung_up_p(filp)) {#ifdef SIMSERIAL_DEBUG		printk("rs_close: hung_up\n");#endif		local_irq_restore(flags);		return;	}#ifdef SIMSERIAL_DEBUG	printk("rs_close ttys%d, count = %d\n", info->line, state->count);#endif	if ((tty->count == 1) && (state->count != 1)) {		/*		 * Uh, oh.  tty->count is 1, which means that the tty		 * structure will be freed.  state->count should always		 * be one in these conditions.  If it's greater than		 * one, we've got real problems, since it means the		 * serial port won't be shutdown.		 */		printk(KERN_ERR "rs_close: bad serial port count; tty->count is 1, "		       "state->count is %d\n", state->count);		state->count = 1;	}	if (--state->count < 0) {		printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n",		       info->line, state->count);		state->count = 0;	}	if (state->count) {		local_irq_restore(flags);		return;	}	info->flags |= ASYNC_CLOSING;	local_irq_restore(flags);	/*	 * Now we wait for the transmit buffer to clear; and we notify	 * the line discipline to only process XON/XOFF characters.	 */	shutdown(info);	if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty);	if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty);	info->event = 0;	info->tty = NULL;	if (info->blocked_open) {		if (info->close_delay)			schedule_timeout_interruptible(info->close_delay);		wake_up_interruptible(&info->open_wait);	}	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);	wake_up_interruptible(&info->close_wait);}/* * rs_wait_until_sent() --- wait until the transmitter is empty */static void rs_wait_until_sent(struct tty_struct *tty, int timeout){}/* * rs_hangup() --- called by tty_hangup() when a hangup is signaled. */static void rs_hangup(struct tty_struct *tty){	struct async_struct * info = (struct async_struct *)tty->driver_data;	struct serial_state *state = info->state;#ifdef SIMSERIAL_DEBUG	printk("rs_hangup: called\n");#endif	state = info->state;	rs_flush_buffer(tty);	if (info->flags & ASYNC_CLOSING)		return;	shutdown(info);	info->event = 0;	state->count = 0;	info->flags &= ~ASYNC_NORMAL_ACTIVE;	info->tty = NULL;	wake_up_interruptible(&info->open_wait);}static int get_async_struct(int line, struct async_struct **ret_info){	struct async_struct *info;	struct serial_state *sstate;	sstate = rs_table + line;	sstate->count++;	if (sstate->info) {		*ret_info = sstate->info;		return 0;	}	info = kzalloc(sizeof(struct async_struct), GFP_KERNEL);	if (!info) {		sstate->count--;		return -ENOMEM;	}	init_waitqueue_head(&info->open_wait);	init_waitqueue_head(&info->close_wait);	init_waitqueue_head(&info->delta_msr_wait);	info->magic = SERIAL_MAGIC;	info->port = sstate->port;	info->flags = sstate->flags;	info->xmit_fifo_size = sstate->xmit_fifo_size;	info->line = line;	INIT_WORK(&info->work, do_softint);	info->state = sstate;	if (sstate->info) {		kfree(info);		*ret_info = sstate->info;		return 0;	}	*ret_info = sstate->info = info;	return 0;}static intstartup(struct async_struct *info){	unsigned long flags;	int	retval=0;	irq_handler_t handler;	struct serial_state *state= info->state;	unsigned long page;	page = get_zeroed_page(GFP_KERNEL);	if (!page)		return -ENOMEM;	local_irq_save(flags);	if (info->flags & ASYNC_INITIALIZED) {		free_page(page);		goto errout;	}	if (!state->port || !state->type) {		if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);		free_page(page);		goto errout;	}	if (info->xmit.buf)		free_page(page);	else		info->xmit.buf = (unsigned char *) page;#ifdef SIMSERIAL_DEBUG	printk("startup: ttys%d (irq %d)...", info->line, state->irq);#endif	/*	 * Allocate the IRQ if necessary	 */	if (state->irq && (!IRQ_ports[state->irq] ||			  !IRQ_ports[state->irq]->next_port)) {		if (IRQ_ports[state->irq]) {			retval = -EBUSY;			goto errout;		} else			handler = rs_interrupt_single;		retval = request_irq(state->irq, handler, IRQ_T(info), "simserial", NULL);		if (retval) {			if (capable(CAP_SYS_ADMIN)) {				if (info->tty)					set_bit(TTY_IO_ERROR,						&info->tty->flags);				retval = 0;			}			goto errout;		}	}	/*	 * Insert serial port into IRQ chain.	 */	info->prev_port = NULL;	info->next_port = IRQ_ports[state->irq];	if (info->next_port)		info->next_port->prev_port = info;	IRQ_ports[state->irq] = info;	if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags);	info->xmit.head = info->xmit.tail = 0;#if 0	/*	 * Set up serial timers...	 */	timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;	timer_active |= 1 << RS_TIMER;#endif	/*	 * Set up the tty->alt_speed kludge	 */	if (info->tty) {		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)			info->tty->alt_speed = 57600;		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)			info->tty->alt_speed = 115200;		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)			info->tty->alt_speed = 230400;		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)			info->tty->alt_speed = 460800;	}	info->flags |= ASYNC_INITIALIZED;	local_irq_restore(flags);	return 0;errout:	local_irq_restore(flags);	return retval;}/* * This routine is called whenever a serial port is opened.  It * enables interrupts for a serial port, linking in its async structure into * the IRQ chain.   It also performs the serial-specific * initialization for the tty structure. */static int rs_open(struct tty_struct *tty, struct file * filp){	struct async_struct	*info;	int			retval, line;	unsigned long		page;	line = tty->index;	if ((line < 0) || (line >= NR_PORTS))		return -ENODEV;	retval = get_async_struct(line, &info);	if (retval)		return retval;	tty->driver_data = info;	info->tty = tty;#ifdef SIMSERIAL_DEBUG	printk("rs_open %s, count = %d\n", tty->name, info->state->count);#endif	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;	if (!tmp_buf) {		page = get_zeroed_page(GFP_KERNEL);		if (!page)			return -ENOMEM;		if (tmp_buf)			free_page(page);		else			tmp_buf = (unsigned char *) page;	}	/*	 * If the port is 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);#ifdef SERIAL_DO_RESTART		return ((info->flags & ASYNC_HUP_NOTIFY) ?			-EAGAIN : -ERESTARTSYS);#else		return -EAGAIN;#endif	}	/*	 * Start up serial port	 */	retval = startup(info);	if (retval) {		return retval;	}	/*	 * figure out which console to use (should be one already)	 */	console = console_drivers;	while (console) {		if ((console->flags & CON_ENABLED) && console->write) break;		console = console->next;	}#ifdef SIMSERIAL_DEBUG	printk("rs_open ttys%d successful\n", info->line);#endif	return 0;}/* * /proc fs routines.... */static inline int line_info(char *buf, struct serial_state *state){	return sprintf(buf, "%d: uart:%s port:%lX irq:%d\n",		       state->line, uart_config[state->type].name,		       state->port, state->irq);}static int rs_read_proc(char *page, char **start, off_t off, int count,		 int *eof, void *data){	int i, len = 0, l;	off_t	begin = 0;	len += sprintf(page, "simserinfo:1.0 driver:%s\n", serial_version);	for (i = 0; i < NR_PORTS && len < 4000; i++) {		l = line_info(page + len, &rs_table[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 + (begin-off);	return ((count < begin+len-off) ? count : begin+len-off);}/* * --------------------------------------------------------------------- * rs_init() and friends * * rs_init() is called at boot-time to initialize the serial driver. * --------------------------------------------------------------------- *//* * This routine prints out the appropriate serial driver version * number, and identifies which options were configured into this * driver. */static inline void show_serial_version(void){	printk(KERN_INFO "%s version %s with", serial_name, serial_version);	printk(KERN_INFO " no serial options enabled\n");}static const struct tty_operations hp_ops = {	.open = rs_open,	.close = rs_close,	.write = rs_write,	.put_char = rs_put_char,	.flush_chars = rs_flush_chars,	.write_room = rs_write_room,	.chars_in_buffer = rs_chars_in_buffer,	.flush_buffer = rs_flush_buffer,	.ioctl = rs_ioctl,	.throttle = rs_throttle,	.unthrottle = rs_unthrottle,	.send_xchar = rs_send_xchar,	.set_termios = rs_set_termios,	.stop = rs_stop,	.start = rs_start,	.hangup = rs_hangup,	.break_ctl = rs_break,	.wait_until_sent = rs_wait_until_sent,	.read_proc = rs_read_proc,};/* * The serial driver boot-time initialization code! */static int __initsimrs_init (void){	int			i, rc;	struct serial_state	*state;	if (!ia64_platform_is("hpsim"))		return -ENODEV;	hp_simserial_driver = alloc_tty_driver(1);	if (!hp_simserial_driver)		return -ENOMEM;	show_serial_version();	/* Initialize the tty_driver structure */	hp_simserial_driver->owner = THIS_MODULE;	hp_simserial_driver->driver_name = "simserial";	hp_simserial_driver->name = "ttyS";	hp_simserial_driver->major = TTY_MAJOR;	hp_simserial_driver->minor_start = 64;	hp_simserial_driver->type = TTY_DRIVER_TYPE_SERIAL;	hp_simserial_driver->subtype = SERIAL_TYPE_NORMAL;	hp_simserial_driver->init_termios = tty_std_termios;	hp_simserial_driver->init_termios.c_cflag =		B9600 | CS8 | CREAD | HUPCL | CLOCAL;	hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW;	tty_set_operations(hp_simserial_driver, &hp_ops);	/*	 * Let's have a little bit of fun !	 */	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {		if (state->type == PORT_UNKNOWN) continue;		if (!state->irq) {			if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0)				panic("%s: out of interrupt vectors!\n",				      __FUNCTION__);			state->irq = rc;			ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq);		}		printk(KERN_INFO "ttyS%d at 0x%04lx (irq = %d) is a %s\n",		       state->line,		       state->port, state->irq,		       uart_config[state->type].name);	}	if (tty_register_driver(hp_simserial_driver))		panic("Couldn't register simserial driver\n");	return 0;}#ifndef MODULE__initcall(simrs_init);#endif

⌨️ 快捷键说明

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