mcfserial.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,892 行 · 第 1/4 页

C
1,892
字号
		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 (!tty_hung_up_p(filp))		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 structure into * the IRQ chain.   It also performs the serial-specific * initialization for the tty structure. */int mcfrs_open(struct tty_struct *tty, struct file * filp){	struct mcf_serial	*info;	int 			retval, line;	line = tty->index;	if ((line < 0) || (line >= NR_PORTS))		return -ENODEV;	info = mcfrs_table + line;	if (serial_paranoia_check(info, tty->name, "mcfrs_open"))		return -ENODEV;#ifdef SERIAL_DEBUG_OPEN	printk("mcfrs_open %s, count = %d\n", tty->name, info->count);#endif	info->count++;	tty->driver_data = info;	info->tty = tty;	/*	 * Start up serial port	 */	retval = startup(info);	if (retval)		return retval;	retval = block_til_ready(tty, filp, info);	if (retval) {#ifdef SERIAL_DEBUG_OPEN		printk("mcfrs_open returning after block_til_ready with %d\n",		       retval);#endif		return retval;	}#ifdef SERIAL_DEBUG_OPEN	printk("mcfrs_open %s successful...\n", tty->name);#endif	return 0;}/* *	Based on the line number set up the internal interrupt stuff. */static void mcfrs_irqinit(struct mcf_serial *info){#if defined(CONFIG_M5272)	volatile unsigned long	*icrp;	volatile unsigned long	*portp;	volatile unsigned char	*uartp;	uartp = info->addr;	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2);	switch (info->line) {	case 0:		*icrp = 0xe0000000;		break;	case 1:		*icrp = 0x0e000000;		break;	default:		printk("MCFRS: don't know how to handle UART %d interrupt?\n",			info->line);		return;	}	/* Enable the output lines for the serial ports */	portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PBCNT);	*portp = (*portp & ~0x000000ff) | 0x00000055;	portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT);	*portp = (*portp & ~0x000003fc) | 0x000002a8;#elif defined(CONFIG_M5282)	volatile unsigned char *icrp, *uartp;	volatile unsigned long *imrp;	uartp = info->addr;	icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +		MCFINTC_ICR0 + MCFINT_UART0 + info->line);	*icrp = 0x33; /* UART0 with level 6, priority 3 */	imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 +		MCFINTC_IMRL);	*imrp &= ~((1 << (info->irq - 64)) | 1);#else	volatile unsigned char	*icrp, *uartp;	switch (info->line) {	case 0:		icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART1ICR);		*icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |			MCFSIM_ICR_PRI1;		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);		break;	case 1:		icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART2ICR);		*icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |			MCFSIM_ICR_PRI2;		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);		break;	default:		printk("MCFRS: don't know how to handle UART %d interrupt?\n",			info->line);		return;	}	uartp = info->addr;	uartp[MCFUART_UIVR] = info->irq;#endif	/* Clear mask, so no surprise interrupts. */	uartp[MCFUART_UIMR] = 0;	if (request_irq(info->irq, mcfrs_interrupt, SA_INTERRUPT,	    "ColdFire UART", NULL)) {		printk("MCFRS: Unable to attach ColdFire UART %d interrupt "			"vector=%d\n", info->line, info->irq);	}	return;}char *mcfrs_drivername = "ColdFire internal UART serial driver version 1.00\n";/* * Serial stats reporting... */int mcfrs_readproc(char *page, char **start, off_t off, int count,		         int *eof, void *data){	struct mcf_serial	*info;	char			str[20];	int			len, sigs, i;	len = sprintf(page, mcfrs_drivername);	for (i = 0; (i < NR_PORTS); i++) {		info = &mcfrs_table[i];		len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ",			i, (unsigned int) info->addr, info->irq, info->baud);		if (info->stats.rx || info->stats.tx)			len += sprintf((page + len), "tx:%d rx:%d ",			info->stats.tx, info->stats.rx);		if (info->stats.rxframing)			len += sprintf((page + len), "fe:%d ",			info->stats.rxframing);		if (info->stats.rxparity)			len += sprintf((page + len), "pe:%d ",			info->stats.rxparity);		if (info->stats.rxbreak)			len += sprintf((page + len), "brk:%d ",			info->stats.rxbreak);		if (info->stats.rxoverrun)			len += sprintf((page + len), "oe:%d ",			info->stats.rxoverrun);		str[0] = str[1] = 0;		if ((sigs = mcfrs_getsignals(info))) {			if (sigs & TIOCM_RTS)				strcat(str, "|RTS");			if (sigs & TIOCM_CTS)				strcat(str, "|CTS");			if (sigs & TIOCM_DTR)				strcat(str, "|DTR");			if (sigs & TIOCM_CD)				strcat(str, "|CD");		}		len += sprintf((page + len), "%s\n", &str[1]);	}	return(len);}/* Finally, routines used to initialize the serial driver. */static void show_serial_version(void){	printk(mcfrs_drivername);}static struct tty_operations mcfrs_ops = {	.open = mcfrs_open,	.close = mcfrs_close,	.write = mcfrs_write,	.flush_chars = mcfrs_flush_chars,	.write_room = mcfrs_write_room,	.chars_in_buffer = mcfrs_chars_in_buffer,	.flush_buffer = mcfrs_flush_buffer,	.ioctl = mcfrs_ioctl,	.throttle = mcfrs_throttle,	.unthrottle = mcfrs_unthrottle,	.set_termios = mcfrs_set_termios,	.stop = mcfrs_stop,	.start = mcfrs_start,	.hangup = mcfrs_hangup,	.read_proc = mcfrs_readproc,	.wait_until_sent = mcfrs_wait_until_sent, 	.tiocmget = mcfrs_tiocmget,	.tiocmset = mcfrs_tiocmset,};/* mcfrs_init inits the driver */static int __initmcfrs_init(void){	struct mcf_serial	*info;	unsigned long		flags;	int			i;	/* Setup base handler, and timer table. */#ifdef MCFPP_DCD0	init_timer(&mcfrs_timer_struct);	mcfrs_timer_struct.function = mcfrs_timer;	mcfrs_timer_struct.data = 0;	mcfrs_timer_struct.expires = jiffies + HZ/25;	add_timer(&mcfrs_timer_struct);	mcfrs_ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);#endif	mcfrs_serial_driver = alloc_tty_driver(NR_PORTS);	if (!mcfrs_serial_driver)		return -ENOMEM;	show_serial_version();	/* Initialize the tty_driver structure */	mcfrs_serial_driver->owner = THIS_MODULE;	mcfrs_serial_driver->name = "ttyS";	mcfrs_serial_driver->devfs_name = "ttys/";	mcfrs_serial_driver->driver_name = "serial";	mcfrs_serial_driver->major = TTY_MAJOR;	mcfrs_serial_driver->minor_start = 64;	mcfrs_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;	mcfrs_serial_driver->subtype = SERIAL_TYPE_NORMAL;	mcfrs_serial_driver->init_termios = tty_std_termios;	mcfrs_serial_driver->init_termios.c_cflag =		mcfrs_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;	mcfrs_serial_driver->flags = TTY_DRIVER_REAL_RAW;	tty_set_operations(mcfrs_serial_driver, &mcfrs_ops);	if (tty_register_driver(mcfrs_serial_driver)) {		printk("MCFRS: Couldn't register serial driver\n");		put_tty_driver(mcfrs_serial_driver);		return(-EBUSY);	}	local_irq_save(flags);	/*	 *	Configure all the attached serial ports.	 */	for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) {		info->magic = SERIAL_MAGIC;		info->line = i;		info->tty = 0;		info->custom_divisor = 16;		info->close_delay = 50;		info->closing_wait = 3000;		info->x_char = 0;		info->event = 0;		info->count = 0;		info->blocked_open = 0;		INIT_WORK(&info->tqueue, mcfrs_offintr, info);		INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);		init_waitqueue_head(&info->open_wait);		init_waitqueue_head(&info->close_wait);		info->imr = 0;		mcfrs_setsignals(info, 0, 0);		mcfrs_irqinit(info);		printk("ttyS%d at 0x%04x (irq = %d)", info->line,			(unsigned int) info->addr, info->irq);		printk(" is a builtin ColdFire UART\n");	}	local_irq_restore(flags);	return 0;}module_init(mcfrs_init);/****************************************************************************//*                          Serial Console                                  *//****************************************************************************//* *	Quick and dirty UART initialization, for console output. */void mcfrs_init_console(void){	volatile unsigned char	*uartp;	unsigned int		clk;	/*	 *	Reset UART, get it into known state...	 */	uartp = (volatile unsigned char *) (MCF_MBAR +		(mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR;  /* reset MR pointer */	/*	 * Set port for defined baud , 8 data bits, 1 stop bit, no parity.	 */	uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8;	uartp[MCFUART_UMR] = MCFUART_MR2_STOP1;	clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */	uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8;  /* set msb baud */	uartp[MCFUART_UBG2] = (clk & 0xff);  /* set lsb baud */	uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;	uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;	mcfrs_console_inited++;	return;}/* *	Setup for console. Argument comes from the boot command line. */int mcfrs_console_setup(struct console *cp, char *arg){	int		i, n = CONSOLE_BAUD_RATE;	if (!cp)		return(-1);	if (!strncmp(cp->name, "ttyS", 4))		mcfrs_console_port = cp->index;	else if (!strncmp(cp->name, "cua", 3))		mcfrs_console_port = cp->index;	else		return(-1);	if (arg)		n = simple_strtoul(arg,NULL,0);	for (i = 0; i < MCFRS_BAUD_TABLE_SIZE; i++)		if (mcfrs_baud_table[i] == n)			break;	if (i < MCFRS_BAUD_TABLE_SIZE) {		mcfrs_console_baud = n;		mcfrs_console_cbaud = 0;		if (i > 15) {			mcfrs_console_cbaud |= CBAUDEX;			i -= 15;		}		mcfrs_console_cbaud |= i;	}	mcfrs_init_console(); /* make sure baud rate changes */	return(0);}static struct tty_driver *mcfrs_console_device(struct console *c, int *index){	*index = c->index;	return mcfrs_serial_driver;}/* *	Output a single character, using UART polled mode. *	This is used for console output. */void mcfrs_put_char(char ch){	volatile unsigned char	*uartp;	unsigned long		flags;	int			i;	uartp = (volatile unsigned char *) (MCF_MBAR +		(mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));	local_irq_save(flags);	for (i = 0; (i < 0x10000); i++) {		if (uartp[MCFUART_USR] & MCFUART_USR_TXREADY)			break;	}	if (i < 0x10000) {		uartp[MCFUART_UTB] = ch;		for (i = 0; (i < 0x10000); i++)			if (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY)				break;	}	if (i >= 0x10000)		mcfrs_init_console(); /* try and get it back */	local_irq_restore(flags);	return;}/* * rs_console_write is registered for printk output. */void mcfrs_console_write(struct console *cp, const char *p, unsigned len){	if (!mcfrs_console_inited)		mcfrs_init_console();	while (len-- > 0) {		if (*p == '\n')			mcfrs_put_char('\r');		mcfrs_put_char(*p++);	}}/* * declare our consoles */struct console mcfrs_console = {	.name		= "ttyS",	.write		= mcfrs_console_write,	.device		= mcfrs_console_device,	.setup		= mcfrs_console_setup,	.flags		= CON_PRINTBUFFER,	.index		= -1,};static int __init mcfrs_console_init(void){	register_console(&mcfrs_console);	return 0;}console_initcall(mcfrs_console_init);/****************************************************************************/

⌨️ 快捷键说明

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