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

📄 su.c

📁 自己根据lkd和情境分析
💻 C
📖 第 1 页 / 共 5 页
字号:
			retval = -EAGAIN;#endif			break;		}		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&		    !(info->flags & ASYNC_CLOSING) &&		    (do_clocal || (serial_in(info, UART_MSR) &				   UART_MSR_DCD)))			break;		if (signal_pending(current)) {			retval = -ERESTARTSYS;			break;		}#ifdef SERIAL_DEBUG_OPEN		printk("block_til_ready blocking: ttys%d, count = %d\n",		       info->line, info->count);#endif		schedule();	}	current->state = TASK_RUNNING;	remove_wait_queue(&info->open_wait, &wait);	if (extra_count)		info->count++;	info->blocked_open--;#ifdef SERIAL_DEBUG_OPEN	printk("block_til_ready after blocking: ttys%d, count = %d\n",	       info->line, info->count);#endif	if (retval)		return retval;	info->flags |= ASYNC_NORMAL_ACTIVE;	return 0;}/* * 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 intsu_open(struct tty_struct *tty, struct file * filp){	struct su_struct	*info;	int 			retval, line;	unsigned long		page;	line = MINOR(tty->device) - tty->driver.minor_start;	if ((line < 0) || (line >= NR_PORTS))		return -ENODEV;	info = su_table + line;	info->count++;	tty->driver_data = info;	info->tty = tty;	if (serial_paranoia_check(info, tty->device, "su_open")) {		info->count--;		return -ENODEV;	}#ifdef SERIAL_DEBUG_OPEN	printk("su_open %s%d, count = %d\n", tty->driver.name, info->line,	       info->count);#endif	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;	if (!tmp_buf) {		page = get_free_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;	MOD_INC_USE_COUNT;	retval = block_til_ready(tty, filp, info);	if (retval) {#ifdef SERIAL_DEBUG_OPEN		printk("su_open returning after block_til_ready with %d\n",		       retval);#endif		return retval;	}	if ((info->count == 1) &&	    (info->flags & ASYNC_SPLIT_TERMIOS)) {		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)			*tty->termios = info->normal_termios;		else 			*tty->termios = info->callout_termios;		change_speed(info, 0);	}#ifdef CONFIG_SERIAL_CONSOLE	if (sercons.cflag && sercons.index == line) {		tty->termios->c_cflag = sercons.cflag;		sercons.cflag = 0;		change_speed(info, 0);	}#endif	info->session = current->session;	info->pgrp = current->pgrp;#ifdef SERIAL_DEBUG_OPEN	printk("su_open ttys%d successful...", info->line);#endif	return 0;}/* * /proc fs routines.... */static intline_info(char *buf, struct su_struct *info){	char		stat_buf[30], control, status;	int		ret;	unsigned long	flags;	if (info->port == 0 || info->type == PORT_UNKNOWN)		return 0;	ret = sprintf(buf, "%u: uart:%s port:%lX irq:%s",		      info->line, uart_config[info->type].name, 		      (unsigned long)info->port, __irq_itoa(info->irq));	/*	 * Figure out the current RS-232 lines	 */	save_flags(flags); cli();	status = serial_in(info, UART_MSR);	control = info ? info->MCR : serial_in(info, UART_MCR);	restore_flags(flags);	stat_buf[0] = 0;	stat_buf[1] = 0;	if (control & UART_MCR_RTS)		strcat(stat_buf, "|RTS");	if (status & UART_MSR_CTS)		strcat(stat_buf, "|CTS");	if (control & UART_MCR_DTR)		strcat(stat_buf, "|DTR");	if (status & UART_MSR_DSR)		strcat(stat_buf, "|DSR");	if (status & UART_MSR_DCD)		strcat(stat_buf, "|CD");	if (status & UART_MSR_RI)		strcat(stat_buf, "|RI");	if (info->quot) {		ret += sprintf(buf+ret, " baud:%u",			       info->baud_base / info->quot);	}	ret += sprintf(buf+ret, " tx:%u rx:%u",		       info->icount.tx, info->icount.rx);	if (info->icount.frame)		ret += sprintf(buf+ret, " fe:%u", info->icount.frame);	if (info->icount.parity)		ret += sprintf(buf+ret, " pe:%u", info->icount.parity);	if (info->icount.brk)		ret += sprintf(buf+ret, " brk:%u", info->icount.brk);		if (info->icount.overrun)		ret += sprintf(buf+ret, " oe:%u", info->icount.overrun);	/*	 * Last thing is the RS-232 status lines	 */	ret += sprintf(buf+ret, " %s\n", stat_buf+1);	return ret;}int su_read_proc(char *page, char **start, off_t off, int count,		 int *eof, void *data){	int i, len = 0;	off_t	begin = 0;	len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);	for (i = 0; i < NR_PORTS && len < 4000; i++) {		len += line_info(page + len, &su_table[i]);		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);}/* * --------------------------------------------------------------------- * su_XXX_init() and friends * * su_XXX_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 __init show_su_version(void){	char *revision = "$Revision: 1.1.1.1 $";	char *version, *p;	version = strchr(revision, ' ');	strcpy(serial_version, ++version);	p = strchr(serial_version, ' ');	*p = '\0'; 	printk(KERN_INFO "%s version %s\n", serial_name, serial_version);}/* * This routine is called by su_{serial|kbd_ms}_init() to initialize a specific * serial port.  It determines what type of UART chip this serial port is * using: 8250, 16450, 16550, 16550A.  The important question is * whether or not this UART is a 16550A, since this will determine * whether or not we can use its FIFO features. */static voidautoconfig(struct su_struct *info){	unsigned char status1, status2, scratch, scratch2;	struct linux_ebus_device *dev = 0;	struct linux_ebus *ebus;#ifdef CONFIG_SPARC64	struct isa_bridge *isa_br;	struct isa_device *isa_dev;#endif#ifndef __sparc_v9__	struct linux_prom_registers reg0;#endif	unsigned long flags;	if (!info->port_node || !info->port_type)		return;	/*	 * First we look for Ebus-bases su's	 */	for_each_ebus(ebus) {		for_each_ebusdev(dev, ebus) {			if (dev->prom_node == info->port_node) {				info->port = dev->resource[0].start;				info->irq = dev->irqs[0];				goto ebus_done;			}		}	}#ifdef CONFIG_SPARC64	for_each_isa(isa_br) {		for_each_isadev(isa_dev, isa_br) {			if (isa_dev->prom_node == info->port_node) {				info->port = isa_dev->resource.start;				info->irq = isa_dev->irq;				goto ebus_done;			}		}	}#endif#ifdef __sparc_v9__	/*	 * Not on Ebus, bailing.	 */	return;#else	/*	 * Not on Ebus, must be OBIO.	 */	if (prom_getproperty(info->port_node, "reg",	    (char *)&reg0, sizeof(reg0)) == -1) {		prom_printf("su: no \"reg\" property\n");		return;	}	prom_apply_obio_ranges(&reg0, 1);	if (reg0.which_io != 0) {	/* Just in case... */		prom_printf("su: bus number nonzero: 0x%x:%x\n",		    reg0.which_io, reg0.phys_addr);		return;	}	if ((info->port = (unsigned long) ioremap(reg0.phys_addr,	    reg0.reg_size)) == 0) {		prom_printf("su: cannot map\n");		return;	}	/*	 * There is no intr property on MrCoffee, so hardwire it.	 */	info->irq = IRQ_4M(13);#endifebus_done:#ifdef SERIAL_DEBUG_OPEN	printk("Found 'su' at %016lx IRQ %s\n", info->port,		__irq_itoa(info->irq));#endif	info->magic = SERIAL_MAGIC;	save_flags(flags); cli();	/*	 * Do a simple existence test first; if we fail this, there's	 * no point trying anything else.	 *	 * 0x80 is used as a nonsense port to prevent against false	 * positives due to ISA bus float.  The assumption is that	 * 0x80 is a non-existent port; which should be safe since	 * include/asm/io.h also makes this assumption.	 */	scratch = serial_inp(info, UART_IER);	serial_outp(info, UART_IER, 0);	scratch2 = serial_inp(info, UART_IER);	serial_outp(info, UART_IER, scratch);	if (scratch2) {		restore_flags(flags);		return;		/* We failed; there's nothing here */	}	scratch = serial_inp(info, UART_MCR);	serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);	serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);	status1 = serial_inp(info, UART_MSR) & 0xF0;	serial_outp(info, UART_MCR, scratch);	if (status1 != 0x90) {		/*		 * This code fragment used to fail, now it fixed itself.		 * We keep the printout for a case.		 */		printk("su: loopback returned status 0x%02x\n", status1);		restore_flags(flags);		return;	} 	scratch2 = serial_in(info, UART_LCR);	serial_outp(info, UART_LCR, 0xBF);	/* set up for StarTech test */	serial_outp(info, UART_EFR, 0);		/* EFR is the same as FCR */	serial_outp(info, UART_LCR, 0);	serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);	scratch = serial_in(info, UART_IIR) >> 6;	switch (scratch) {		case 0:			info->type = PORT_16450;			break;		case 1:			info->type = PORT_UNKNOWN;			break;		case 2:			info->type = PORT_16550;			break;		case 3:			info->type = PORT_16550A;			break;	}	if (info->type == PORT_16550A) {		/* Check for Startech UART's */		serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);		if (serial_in(info, UART_EFR) == 0) {			info->type = PORT_16650;		} else {			serial_outp(info, UART_LCR, 0xBF);			if (serial_in(info, UART_EFR) == 0)				info->type = PORT_16650V2;		}	}	if (info->type == PORT_16550A) {		/* Check for TI 16750 */		serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);		serial_outp(info, UART_FCR,			    UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);		scratch = serial_in(info, UART_IIR) >> 5;		if (scratch == 7) {			serial_outp(info, UART_LCR, 0);			serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);			scratch = serial_in(info, UART_IIR) >> 5;			if (scratch == 6)				info->type = PORT_16750;		}		serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);	}	serial_outp(info, UART_LCR, scratch2);	if (info->type == PORT_16450) {		scratch = serial_in(info, UART_SCR);		serial_outp(info, UART_SCR, 0xa5);		status1 = serial_in(info, UART_SCR);		serial_outp(info, UART_SCR, 0x5a);		status2 = serial_in(info, UART_SCR);		serial_outp(info, UART_SCR, scratch);		if ((status1 != 0xa5) || (status2 != 0x5a))			info->type = PORT_8250;	}	info->xmit_fifo_size = uart_config[info->type].dfl_xmit_fifo_size;	if (info->type == PORT_UNKNOWN) {		restore_flags(flags);		return;	}	sprintf(info->name, "su(%s)", su_typev[info->port_type]);	/*	 * Reset the UART.	 */	serial_outp(info, UART_MCR, 0x00);	serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT));	(void)serial_in(info, UART_RX);	serial_outp(info, UART_IER, 0x00);	restore_flags(flags);}/* This is used by the SAB driver to adjust where its minor * numbers start, we always are probed for first. */int su_num_ports = 0;EXPORT_SYMBOL(su_num_ports);/* * The serial driver boot-time initialization code! */int __init su_serial_init(void){	int i;	struct su_struct *info;	init_bh(SERIAL_BH, do_serial_bh);	show_su_version();	/* Initialize the tty_driver structure */	memset(&serial_driver, 0, sizeof(struct tty_driver));	serial_driver.magic = TTY_DRIVER_MAGIC;	serial_driver.driver_name = "su";#ifdef CONFIG_DEVFS_FS	serial_driver.name = "tts/%d";#else	serial_driver.name = "ttyS";#endif	serial_driver.major = TTY_MAJOR;	serial_driver.minor_start = 64;	serial_driver.num = NR_PORTS;	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 = su_open;	serial_driver.close = su_close;	serial_driver.write = su_write;	serial_driver.put_char = su_put_char;	serial_driver.flush_chars = su_flush_chars;	serial_driver.write_room = su_write_room;	serial_driver.chars_in_buffer = su_chars_in_buffer;	serial_driver.flush_buffer = su_flush_buffer;	serial_driver.ioctl = su_ioctl;	serial_driver.throttle = su_throttle;	serial_driver.unthrottle = su_unth

⌨️ 快捷键说明

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