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

📄 uart.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		      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/* I need this just so I can store the virtual addresses and have * common functions for the early console printing. */static ser_info_t consinfo;/* * Print a string to the serial port trying not to disturb any possible * real use of the port... */static void my_console_write(int idx, 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 + idx;	/* 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 *)&cpmp->cp_dparam[ser->port];		/* Get the address of the host memory buffer.		 */		bdp = bdbase = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];		info = &consinfo;	}	/*	 * 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.		 * If the buffer address is in the CPM DPRAM, don't		 * convert it.		 */		if ((uint)(bdp->cbd_bufaddr) > (uint)IMAP_ADDR)			cp = (u_char *)(bdp->cbd_bufaddr);		else			cp = info->tx_va_base + ((bdp - info->tx_bd_base) * TX_BUF_SIZE);		*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 = info->tx_va_base + ((bdp - info->tx_bd_base) * TX_BUF_SIZE);			*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;}static void serial_console_write(struct console *c, const char *s,				unsigned count){#ifdef CONFIG_KGDB_CONSOLE	/* Try to let stub handle output. Returns true if it did. */	if (kgdb_output_string(s, count))		return;#endif	my_console_write(c->index, s, count);}#ifdef CONFIG_XMONintxmon_8xx_write(const char *s, unsigned count){	my_console_write(0, s, count);	return(count);}#endif#ifdef CONFIG_KGDBvoidputDebugChar(char ch){	my_console_write(0, &ch, 1);}#endif/* * Receive character from the serial port.  This only works well * before the port is initialized for real use. */static int my_console_wait_key(int idx, int xmon, char *obuf){	struct serial_state		*ser;	u_char				c, *cp;	ser_info_t			*info;	volatile	cbd_t		*bdp;	volatile	smc_uart_t	*up;	int				i;	ser = rs_table + idx;	/* Pointer to UART in parameter ram.	*/	up = (smc_uart_t *)&cpmp->cp_dparam[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 *)&cpmp->cp_dpmem[up->smc_rbase];		info = &consinfo;	}	/*	 * We need to gracefully shut down the receiver, disable	 * interrupts, then read the input.	 * XMON just wants a poll.  If no character, return -1, else	 * return the character.	 */	if (!xmon) {		while (bdp->cbd_sc & BD_SC_EMPTY);	}	else {		if (bdp->cbd_sc & BD_SC_EMPTY)			return -1;	}	/* If the buffer address is in the CPM DPRAM, don't	 * convert it.	 */	if ((uint)(bdp->cbd_bufaddr) > (uint)IMAP_ADDR)		cp = (u_char *)(bdp->cbd_bufaddr);	else		cp = info->rx_va_base + ((bdp - info->rx_bd_base) * RX_BUF_SIZE);	if (obuf) {		i = c = bdp->cbd_datlen;		while (i-- > 0)			*obuf++ = *cp++;	}	else {		c = *cp;	}	bdp->cbd_sc |= BD_SC_EMPTY;	if (info) {		if (bdp->cbd_sc & BD_SC_WRAP) {			bdp = info->rx_bd_base;		}		else {			bdp++;		}		info->rx_cur = (cbd_t *)bdp;	}	return((int)c);}#ifdef CONFIG_XMONintxmon_8xx_read_poll(void){	return(my_console_wait_key(0, 1, NULL));}intxmon_8xx_read_char(void){	return(my_console_wait_key(0, 0, NULL));}#endif#ifdef CONFIG_KGDBstatic char kgdb_buf[RX_BUF_SIZE], *kgdp;static int kgdb_chars;chargetDebugChar(void){	if (kgdb_chars <= 0) {		kgdb_chars = my_console_wait_key(0, 0, kgdb_buf);		kgdp = kgdb_buf;	}	kgdb_chars--;	return(*kgdp++);}void kgdb_interruptible(int yes){	volatile smc_t	*smcp;	smcp = &cpmp->cp_smc[KGDB_SER_IDX];	if (yes == 1)		smcp->smc_smcm |= SMCM_RX;	else		smcp->smc_smcm &= ~SMCM_RX;}void kgdb_map_scc(void){	struct		serial_state *ser;	uint		mem_addr;	volatile	cbd_t		*bdp;	volatile	smc_uart_t	*up;	cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);	/* To avoid data cache CPM DMA coherency problems, allocate a	 * buffer in the CPM DPRAM.  This will work until the CPM and	 * serial ports are initialized.  At that time a memory buffer	 * will be allocated.	 * The port is already initialized from the boot procedure, all	 * we do here is give it a different buffer and make it a FIFO.	 */	ser = rs_table;	/* Right now, assume we are using SMCs.	*/	up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];	/* Allocate space for an input FIFO, plus a few bytes for output.	 * Allocate bytes to maintain word alignment.	 */	mem_addr = (uint)(&cpmp->cp_dpmem[0xa00]);	/* Set the physical address of the host memory buffers in	 * the buffer descriptors.	 */	bdp = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];	bdp->cbd_bufaddr = mem_addr;	bdp = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];	bdp->cbd_bufaddr = mem_addr+RX_BUF_SIZE;	up->smc_mrblr = RX_BUF_SIZE;		/* receive buffer length */	up->smc_maxidl = RX_BUF_SIZE;}#endifstatic struct tty_driver *serial_console_device(struct console *c, int *index){	*index = c->index;	return serial_driver;}/* *	Register console. */static void __init console_8xx_init(long kmem_start, long kmem_end){	register_console(&sercons);}console_initcall(console_8xx_init);#endif/* Index in baud rate table of the default console baud rate.*/static	int	baud_idx;static struct tty_operations rs_8xx_ops = {	.open = rs_8xx_open,	.close = rs_8xx_close,	.write = rs_8xx_write,	.put_char = rs_8xx_put_char,	.write_room = rs_8xx_write_room,	.chars_in_buffer = rs_8xx_chars_in_buffer,	.flush_buffer = rs_8xx_flush_buffer,	.ioctl = rs_8xx_ioctl,	.throttle = rs_8xx_throttle,	.unthrottle = rs_8xx_unthrottle,	.send_xchar = rs_8xx_send_xchar,	.set_termios = rs_8xx_set_termios,	.stop = rs_8xx_stop,	.start = rs_8xx_start,	.hangup = rs_8xx_hangup,	.wait_until_sent = rs_8xx_wait_until_sent,	.read_proc = rs_8xx_read_proc,};/* * The serial driver boot-time initialization code! */static int __init rs_8xx_init(void){	struct serial_state * state;	ser_info_t	*info;	uint		mem_addr, iobits, dp_offset;	int		i, j, idx;	ushort		chan;	volatile	cbd_t		*bdp;	volatile	cpm8xx_t	*cp;	volatile	smc_t		*sp;	volatile	smc_uart_t	*up;	volatile	scc_t		*scp;	volatile	scc_uart_t	*sup;	volatile	immap_t		*immap;	serial_driver = alloc_tty_driver(NR_PORTS);	if (!serial_driver)		return -ENOMEM;	init_bh(SERIAL_BH, do_serial_bh);	show_serial_version();	/* Initialize the tty_driver structure */	serial_driver->owner = THIS_MODULE;	serial_driver->driver_name = "serial";	serial_driver->devfs_name = "tts/";	serial_driver->name = "ttyS";	serial_driver->major = TTY_MAJOR;	serial_driver->minor_start = 64;	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;	tty_set_operations(serial_driver, &rs_8xx_ops);	if (tty_register_driver(serial_driver))		panic("Couldn't register serial driver\n");	cp = cpmp;	/* Get pointer to Communication Processor */	immap = (immap_t *)IMAP_ADDR;	/* and to internal registers */	/* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O.	 */#ifdef CONFIG_USE_SCC_IO#ifndef CONFIG_MBX	/* The "standard" configuration through the 860.	*/	immap->im_ioport.iop_papar |= 0x00fc;	immap->im_ioport.iop_padir &= ~0x00fc;	immap->im_ioport.iop_paodr &= ~0x00fc;#else	/* On the MBX, SCC3 is through Port D.	*/	immap->im_ioport.iop_papar |= 0x000c;	/* SCC2 on port A */	immap->im_ioport.iop_padir &= ~0x000c;	immap->im_ioport.iop_paodr &= ~0x000c;	immap->im_ioport.iop_pdpar |= 0x0030;	/* SCC3 on port D */#endif	/* Since we don't yet do modem control, connect the port C pins	 * as general purpose I/O.  This will assert CTS and CD for the	 * SCC ports.	 */	immap->im_ioport.iop_pcdir |= 0x03c6;	immap->im_ioport.iop_pcpar &= ~0x03c6;	/* Connect SCC2 and SCC3 to NMSI.  Connect BRG3 to SCC2 and	 * BRG4 to SCC3.	 */	cp->cp_sicr &= ~0x00ffff00;	cp->cp_sicr |= 0x001b1200;#ifdef CONFIG_PP04	/* Frequentis PP04 forced to RS-232 until we know better.	 * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4.	 */	immap->im_ioport.iop_pcdir |= 0x000c;	immap->im_ioport.iop_pcpar &= ~0x000c;	immap->im_ioport.iop_pcdat &= ~0x000c;	/* This enables the TX driver.	*/	cp->cp_pbpar &= ~0x6000;	cp->cp_pbdat &= ~0x6000;#endif#endif	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->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, (

⌨️ 快捷键说明

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