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

📄 simserial.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	struct serial_state *state;	int		retval;	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	save_flags(flags); cli(); /* Disable interrupts */	/*	 * 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 = 0;	}	if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);	info->flags &= ~ASYNC_INITIALIZED;	restore_flags(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;	save_flags(flags); cli();	if (tty_hung_up_p(filp)) {#ifdef SIMSERIAL_DEBUG		printk("rs_close: hung_up\n");#endif		MOD_DEC_USE_COUNT;		restore_flags(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) {		MOD_DEC_USE_COUNT;		restore_flags(flags);		return;	}	info->flags |= ASYNC_CLOSING;	restore_flags(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 = 0;	if (info->blocked_open) {		if (info->close_delay) {			current->state = TASK_INTERRUPTIBLE;			schedule_timeout(info->close_delay);		}		wake_up_interruptible(&info->open_wait);	}	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);	wake_up_interruptible(&info->close_wait);	MOD_DEC_USE_COUNT;}/* * 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|ASYNC_CALLOUT_ACTIVE);	info->tty = 0;	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 = kmalloc(sizeof(struct async_struct), GFP_KERNEL);	if (!info) {		sstate->count--;		return -ENOMEM;	}	memset(info, 0, sizeof(struct async_struct));	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;	info->tqueue.routine = do_softint;	info->tqueue.data = info;	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;	void (*handler)(int, void *, struct pt_regs *);	struct serial_state *state= info->state;	unsigned long page;	page = get_free_page(GFP_KERNEL);	if (!page)		return -ENOMEM;	save_flags(flags); cli();	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 = 0;	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;	restore_flags(flags);	return 0;errout:	restore_flags(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;	MOD_INC_USE_COUNT;	line = MINOR(tty->device) - tty->driver.minor_start;	if ((line < 0) || (line >= NR_PORTS)) {		MOD_DEC_USE_COUNT;		return -ENODEV;	}	retval = get_async_struct(line, &info);	if (retval) {		MOD_DEC_USE_COUNT;		return retval;	}	tty->driver_data = info;	info->tty = tty;#ifdef SIMSERIAL_DEBUG	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,	       info->state->count);#endif	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;	if (!tmp_buf) {		page = get_free_page(GFP_KERNEL);		if (!page) {			/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */			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);		/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */#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) {		/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */		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;	}	/*	 * 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;	}	info->session = current->session;	info->pgrp = current->pgrp;#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");}/* * The serial driver boot-time initialization code! */static int __initsimrs_init (void){	int			i;	struct serial_state	*state;	show_serial_version();	/* Initialize the tty_driver structure */	memset(&serial_driver, 0, sizeof(struct tty_driver));	serial_driver.magic = TTY_DRIVER_MAGIC;	serial_driver.driver_name = "simserial";	serial_driver.name = "ttyS";	serial_driver.major = TTY_MAJOR;	serial_driver.minor_start = 64;	serial_driver.num = 1;	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;	serial_driver.subtype = SERIAL_TYPE_NORMAL;	serial_driver.init_termios = tty_std_termios;	serial_driver.init_termios.c_cflag =		B9600 | CS8 | CREAD | HUPCL | CLOCAL;	serial_driver.flags = TTY_DRIVER_REAL_RAW;	serial_driver.refcount = &serial_refcount;	serial_driver.table = serial_table;	serial_driver.termios = serial_termios;	serial_driver.termios_locked = serial_termios_locked;	serial_driver.open = rs_open;	serial_driver.close = rs_close;	serial_driver.write = rs_write;	serial_driver.put_char = rs_put_char;	serial_driver.flush_chars = rs_flush_chars;	serial_driver.write_room = rs_write_room;	serial_driver.chars_in_buffer = rs_chars_in_buffer;	serial_driver.flush_buffer = rs_flush_buffer;	serial_driver.ioctl = rs_ioctl;	serial_driver.throttle = rs_throttle;	serial_driver.unthrottle = rs_unthrottle;	serial_driver.send_xchar = rs_send_xchar;	serial_driver.set_termios = rs_set_termios;	serial_driver.stop = rs_stop;	serial_driver.start = rs_start;	serial_driver.hangup = rs_hangup;	serial_driver.break_ctl = rs_break;	serial_driver.wait_until_sent = rs_wait_until_sent;	serial_driver.read_proc = rs_read_proc;	/*	 * 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) {			state->irq = ia64_alloc_vector();			ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq);		}		printk(KERN_INFO "ttyS%02d at 0x%04lx (irq = %d) is a %s\n",		       state->line,		       state->port, state->irq,		       uart_config[state->type].name);	}	/*	 * The callout device is just like normal device except for	 * major number and the subtype code.	 */	callout_driver = serial_driver;	callout_driver.name = "cua";	callout_driver.major = TTYAUX_MAJOR;	callout_driver.subtype = SERIAL_TYPE_CALLOUT;	callout_driver.read_proc = 0;	callout_driver.proc_entry = 0;	if (tty_register_driver(&serial_driver))		panic("Couldn't register simserial driver\n");	if (tty_register_driver(&callout_driver))		panic("Couldn't register callout driver\n");	return 0;}#ifndef MODULE__initcall(simrs_init);#endif

⌨️ 快捷键说明

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