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

📄 uart.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	cli();	status = serial_in(info, UART_MSR);	control = info ? info->MCR : serial_in(info, UART_MCR);	sti();		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:%d",			       state->baud_base / info->quot);	}	ret += sprintf(buf+ret, " tx:%d rx:%d",		      state->icount.tx, state->icount.rx);	if (state->icount.frame)		ret += sprintf(buf+ret, " fe:%d", state->icount.frame);		if (state->icount.parity)		ret += sprintf(buf+ret, " pe:%d", state->icount.parity);		if (state->icount.brk)		ret += sprintf(buf+ret, " brk:%d", state->icount.brk);		if (state->icount.overrun)		ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);	/*	 * Last thing is the RS-232 status lines	 */	ret += sprintf(buf+ret, " %s\n", stat_buf+1);#endif	return ret;}int rs_8xx_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, &rs_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 + (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\n", serial_name, serial_version);}/* * The serial console driver used during boot.  Note that these names * clash with those found in "serial.c", so we currently can't support * the 16xxx uarts and these at the same time.  I will fix this to become * an indirect function call from tty_io.c (or something). */#ifdef CONFIG_SERIAL_CONSOLE/* * Print a string to the serial port trying not to disturb any possible * real use of the port... */static void serial_console_write(struct console *c, const char *s,				unsigned count){	struct		serial_state	*ser;	ser_info_t			*info;	unsigned			i;	volatile	cbd_t		*bdp, *bdbase;	volatile	smc_uart_t	*up;	volatile	u_char		*cp;	ser = rs_table + c->index;	/* If the port has been initialized for general use, we have	 * to use the buffer descriptors allocated there.  Otherwise,	 * we simply use the single buffer allocated.	 */	if ((info = (ser_info_t *)ser->info) != NULL) {		bdp = info->tx_cur;		bdbase = info->tx_bd_base;	}	else {		/* Pointer to UART in parameter ram.		*/		up = (smc_uart_t *)&immr->im_dprambase[ser->port];		/* Get the address of the host memory buffer.		 */		bdp = bdbase = (cbd_t *)&immr->im_dprambase[up->smc_tbase];	}	/*	 * We need to gracefully shut down the transmitter, disable	 * interrupts, then send our bytes out.	 */	/*	 * Now, do each character.  This is not as bad as it looks	 * since this is a holding FIFO and not a transmitting FIFO.	 * We could add the complexity of filling the entire transmit	 * buffer, but we would just wait longer between accesses......	 */	for (i = 0; i < count; i++, s++) {		/* Wait for transmitter fifo to empty.		 * Ready indicates output is ready, and xmt is doing		 * that, not that it is ready for us to send.		 */		while (bdp->cbd_sc & BD_SC_READY);		/* Send the character out. */		cp = __va(bdp->cbd_bufaddr);		*cp = *s;				bdp->cbd_datlen = 1;		bdp->cbd_sc |= BD_SC_READY;		if (bdp->cbd_sc & BD_SC_WRAP)			bdp = bdbase;		else			bdp++;		/* if a LF, also do CR... */		if (*s == 10) {			while (bdp->cbd_sc & BD_SC_READY);			cp = __va(bdp->cbd_bufaddr);			*cp = 13;			bdp->cbd_datlen = 1;			bdp->cbd_sc |= BD_SC_READY;			if (bdp->cbd_sc & BD_SC_WRAP) {				bdp = bdbase;			}			else {				bdp++;			}		}	}	/*	 * Finally, Wait for transmitter & holding register to empty	 *  and restore the IER	 */	while (bdp->cbd_sc & BD_SC_READY);	if (info)		info->tx_cur = (cbd_t *)bdp;}/* * Receive character from the serial port.  This only works well * before the port is initialize for real use. */static int serial_console_wait_key(struct console *co){	struct serial_state		*ser;	u_char				c, *cp;	ser_info_t			*info;	volatile	cbd_t		*bdp;	volatile	smc_uart_t	*up;	ser = rs_table + co->index;	/* Pointer to UART in parameter ram.	*/	up = (smc_uart_t *)&immr->im_dprambase[ser->port];	/* Get the address of the host memory buffer.	 * If the port has been initialized for general use, we must	 * use information from the port structure.	 */	if ((info = (ser_info_t *)ser->info))		bdp = info->rx_cur;	else		bdp = (cbd_t *)&immr->im_dprambase[up->smc_rbase];	/*	 * We need to gracefully shut down the receiver, disable	 * interrupts, then read the input.	 */	while (bdp->cbd_sc & BD_SC_EMPTY);	/* Wait for a character */	cp = __va(bdp->cbd_bufaddr);	if (info) {		if (bdp->cbd_sc & BD_SC_WRAP) {			bdp = info->rx_bd_base;		}		else {			bdp++;		}		info->rx_cur = (cbd_t *)bdp;	}	c = *cp;	return((int)c);}static kdev_t serial_console_device(struct console *c){	return MKDEV(TTYAUX_MAJOR, 64 + c->index);}static struct console sercons = {	name:		"ttyS",	write:		serial_console_write,	device:		serial_console_device,	wait_key:	serial_console_wait_key,	setup:		serial_console_setup,	flags:		CON_PRINTBUFFER,	index:		CONFIG_SERIAL_CONSOLE_PORT,};/* *	Register console. */long __init console_8xx_init(long kmem_start, long kmem_end){	register_console(&sercons);	return kmem_start;}#endif/* Default console baud rate as determined by the board information * structure. */static	int	baud_idx;/* * The serial driver boot-time initialization code! */int __init rs_8xx_init(void){	struct serial_state * state;	ser_info_t	*info;	uint		mem_addr, dp_addr;	int		i, j, idx;	uint		page, sblock;	volatile	cbd_t		*bdp;	volatile	cpm8260_t	*cp;	volatile	smc_t		*sp;	volatile	smc_uart_t	*up;	volatile	scc_t		*scp;	volatile	scc_uart_t	*sup;	volatile	immap_t		*immap;	volatile	iop8260_t	*io;		init_bh(SERIAL_BH, do_serial_bh);	show_serial_version();	/* Initialize the tty_driver structure */		/*memset(&serial_driver, 0, sizeof(struct tty_driver));*/	__clear_user(&serial_driver,sizeof(struct tty_driver));	serial_driver.magic = TTY_DRIVER_MAGIC;	serial_driver.driver_name = "serial";	serial_driver.name = "ttyS";	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 =		baud_idx | 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_8xx_open;	serial_driver.close = rs_8xx_close;	serial_driver.write = rs_8xx_write;	serial_driver.put_char = rs_8xx_put_char;	serial_driver.write_room = rs_8xx_write_room;	serial_driver.chars_in_buffer = rs_8xx_chars_in_buffer;	serial_driver.flush_buffer = rs_8xx_flush_buffer;	serial_driver.ioctl = rs_8xx_ioctl;	serial_driver.throttle = rs_8xx_throttle;	serial_driver.unthrottle = rs_8xx_unthrottle;	serial_driver.send_xchar = rs_8xx_send_xchar;	serial_driver.set_termios = rs_8xx_set_termios;	serial_driver.stop = rs_8xx_stop;	serial_driver.start = rs_8xx_start;	serial_driver.hangup = rs_8xx_hangup;	serial_driver.wait_until_sent = rs_8xx_wait_until_sent;	serial_driver.read_proc = rs_8xx_read_proc;		/*	 * 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 serial driver\n");	if (tty_register_driver(&callout_driver))		panic("Couldn't register callout driver\n");		immap = immr;	cp = &immap->im_cpm;	io = &immap->im_ioport;	/* This should have been done long ago by the early boot code,	 * but do it again to make sure.	 */	*(ushort *)(&immap->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1;	*(ushort *)(&immap->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2;	/* Geeze, here we go....Picking I/O port bits....Lots of	 * choices.  If you don't like mine, pick your own.	 * Configure SMCs Tx/Rx.  SMC1 is only on Port D, SMC2 is	 * only on Port A.  You either pick 'em, or not.	 */	io->iop_ppard |= 0x00c00000;	io->iop_pdird |= 0x00400000;	io->iop_pdird &= ~0x00800000;	io->iop_psord &= ~0x00c00000;#if USE_SMC2	io->iop_ppara |= 0x00c00000;	io->iop_pdira |= 0x00400000;	io->iop_pdira &= ~0x00800000;	io->iop_psora &= ~0x00c00000;#endif	/* Configure SCC2 and SCC3.  Be careful about the fine print.	 * Secondary options are only available when you take away	 * the primary option.  Unless the pins are used for something	 * else, SCC2 and SCC3 are on Port B.	 *	Port B,  8 - SCC3 TxD	 *	Port B, 12 - SCC2 TxD	 *	Port B, 14 - SCC3 RxD	 *	Port B, 15 - SCC2 RxD	 */	io->iop_pparb |= 0x008b0000;	io->iop_pdirb |= 0x00880000;	io->iop_psorb |= 0x00880000;	io->iop_pdirb &= ~0x00030000;	io->iop_psorb &= ~0x00030000;	/* Wire BRG1 to SMC1 and BRG2 to SMC2.	*/	immap->im_cpmux.cmx_smr = 0;	/* Connect SCC2 and SCC3 to NMSI.  Connect BRG3 to SCC2 and	 * BRG4 to SCC3.	 */	immap->im_cpmux.cmx_scr &= ~0x00ffff00;	immap->im_cpmux.cmx_scr |= 0x00121b00;	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {		state->magic = SSTATE_MAGIC;		state->line = i;		state->type = PORT_UNKNOWN;		state->custom_divisor = 0;		state->close_delay = 5*HZ/10;		state->closing_wait = 30*HZ;		state->callout_termios = callout_driver.init_termios;		state->normal_termios = serial_driver.init_termios;		state->icount.cts = state->icount.dsr = 			state->icount.rng = state->icount.dcd = 0;		state->icount.rx = state->icount.tx = 0;		state->icount.frame = state->icount.parity = 0;		state->icount.overrun = state->icount.brk = 0;		printk(KERN_INFO "ttyS%02d at 0x%04x is a %s\n",		       i, state->port,		       (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC");#ifdef CONFIG_SERIAL_CONSOLE		/* If we just printed the message on the console port, and		 * we are about to initialize it for general use, we have		 * to wait a couple of character times for the CR/NL to		 * make it out of the transmit buffer.		 */		if (i == CONFIG_SERIAL_CONSOLE_PORT)			mdelay(2);#endif		info = kmalloc(sizeof(ser_info_t), GFP_KERNEL);		if (info) {			/*memset(info, 0, sizeof(ser_info_t));*/			__clear_user(info,sizeof(ser_info_t));			init_waitqueue_head(&info->open_wait);			init_waitqueue_head(&info->close_wait);			info->magic = SERIAL_MAGIC;			info->flags = state->flags;			info->tqueue.routine = do_softint;			info->tqueue.data = info;			info->tqueue_hangup.routine = do_serial_hangup;			info->tqueue_hangup.data = info;			info->line = i;			info->state = state;			state->info = (struct async_struct *)info;			/* We need to allocate a transmit and receive buffer			 * descriptors from dual port ram, and a character			 * buffer area from host mem.			 */			dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO, 8);			/* Allocate space for FIFOs in the host memory.			*/			mem_addr = m8260_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE, 1);			/* Set the physical address of the host memory			 * buffers in the buffer descriptors, and the			 * virtual address for us to work with.			 */			bdp = (cbd_t *)&immap->im_dprambase[dp_addr];			info->rx_cur = info->rx_bd_base = (cbd_t *)bdp;			for (j=0; j<(RX_NUM_FIFO-1); j++) {				bdp->cbd_bufaddr = __pa(mem_addr);				bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;				mem_addr += RX_BUF_SIZE;				bdp++;			}			bdp->cbd_bufaddr = __pa(mem_addr);			bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;			if ((idx = state->smc_scc_num) < SCC_NUM_BASE) {				sp = &immap->im_smc[idx];				up = (smc_uart_t *)&immap->im_dprambase[state->port];				up->smc_rbase = dp_addr;			}			else {				scp = &immap->im_scc[idx - SCC_IDX_BASE];				sup = (scc_uart_t *)&immap->im_dprambase[state->port];				sup->scc_genscc.scc_rbase = dp_addr;			}			dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO, 8);			/* Allocate space for FIFOs in the host memory.			*/			mem_addr = m8260_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE, 1);			/* Set the physical address of the host memory			 * buffers in the buffer descriptors, and the			 * virtual address for us to work with.			 */			bdp = (cbd_t *)&immap->im_dprambase[dp_addr];			info->tx_cur = info->tx_bd_base = (cbd_t *)bdp;			for (j=0; j<(TX_NUM_FIFO-1); j++) {				bdp->cbd_bufaddr = __pa(mem_addr);				bdp->cbd_sc = BD_SC_INTRPT;				mem_addr += TX_BUF_SIZE;				bdp++;			}			bdp->cbd_bufaddr = __pa(mem_addr);			bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);			if (idx < SCC_NUM_BASE) {				up->smc_tbase = dp_addr;				/* Set up the uart parameters in the				 * param

⌨️ 快捷键说明

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