serial_tx3912.c

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

C
982
字号
		if ((CFLAG & CSIZE)==CS6)			printk(KERN_ERR "6 bits not supported\n");		if ((CFLAG & CSIZE)==CS5)			printk(KERN_ERR "5 bits not supported\n");		if ((CFLAG & CSIZE)==CS7)			UartA_Ctrl1 |= SER_SEVEN_BIT;		if (C_CSTOPB(port->gs.tty))			UartA_Ctrl1 |= SER_TWO_STOP;		outl(t, port->base + TX3912_UART_CTRL2);		outl(0, port->base + TX3912_UART_DMA_CTRL1);		outl(0, port->base + TX3912_UART_DMA_CTRL2);        	UartA_Ctrl1 |= TX3912_UART_CTRL1_UARTON;        /* wait until UARTA is stable */        while (~UartA_Ctrl1 & TX3912_UART_CTRL1_UARTON);	}	func_exit ();        return 0;}static int rs_chars_in_buffer (void * ptr) {	struct rs_port *port = ptr;	int scratch;	scratch = inl(port->base + TX3912_UART_CTRL1);	return ((scratch & UART_TX_EMPTY) ? 0 : 1);}/* ********************************************************************** * *                Here are the routines that actually                     * *               interface with the rest of the system                    * * ********************************************************************** */static int rs_open  (struct tty_struct * tty, struct file * filp){	struct rs_port *port;	int retval, line;	func_enter();	if (!rs_initialized) {		return -EIO;	}	line = tty->index;	rs_dprintk (TX3912_UART_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p)\n", 	            (int) current->pid, line, tty, current->tty);	if ((line < 0) || (line >= TX3912_UART_NPORTS))		return -ENODEV;	/* Pre-initialized already */	port = & rs_ports[line];	rs_dprintk (TX3912_UART_DEBUG_OPEN, "port = %p\n", port);	tty->driver_data = port;	port->gs.tty = tty;	port->gs.count++;	rs_dprintk (TX3912_UART_DEBUG_OPEN, "starting port\n");	/*	 * Start up serial port	 */	retval = gs_init_port(&port->gs);	rs_dprintk (TX3912_UART_DEBUG_OPEN, "done gs_init\n");	if (retval) {		port->gs.count--;		return retval;	}	port->gs.flags |= GS_ACTIVE;	rs_dprintk (TX3912_UART_DEBUG_OPEN, "before inc_use_count (count=%d.\n", 	            port->gs.count);	rs_dprintk (TX3912_UART_DEBUG_OPEN, "after inc_use_count\n");	/* Jim: Initialize port hardware here */	/* Enable high-priority interrupts for UARTA */	IntEnable6 |= INT6_UARTARXINT; 	rs_enable_rx_interrupts(&rs_ports[0]); 	retval = gs_block_til_ready(&port->gs, filp);	rs_dprintk (TX3912_UART_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n", 	            retval, port->gs.count);	if (retval) {		port->gs.count--;		return retval;	}	/* tty->low_latency = 1; */	func_exit();	/* Jim *//*	cli(); */	return 0;}static int rs_ioctl (struct tty_struct * tty, struct file * filp,                      unsigned int cmd, unsigned long arg){	int rc;	struct rs_port *port = tty->driver_data;	int ival;	rc = 0;	switch (cmd) {	case TIOCGSOFTCAR:		rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),		              (unsigned int *) arg);		break;	case TIOCSSOFTCAR:		if ((rc = get_user(ival, (unsigned int *) arg)) == 0) {			tty->termios->c_cflag =				(tty->termios->c_cflag & ~CLOCAL) |				(ival ? CLOCAL : 0);		}		break;	case TIOCGSERIAL:		if ((rc = verify_area(VERIFY_WRITE, (void *) arg,		                      sizeof(struct serial_struct))) == 0)			rc = gs_getserial(&port->gs, (struct serial_struct *) arg);		break;	case TIOCSSERIAL:		if ((rc = verify_area(VERIFY_READ, (void *) arg,		                      sizeof(struct serial_struct))) == 0)			rc = gs_setserial(&port->gs, (struct serial_struct *) arg);		break;	default:		rc = -ENOIOCTLCMD;		break;	}	/* func_exit(); */	return rc;}/* * This function is used to send a high-priority XON/XOFF character to * the device */static void rs_send_xchar(struct tty_struct * tty, char ch){	struct rs_port *port = (struct rs_port *)tty->driver_data;	func_enter ();		port->x_char = ch;	if (ch) {		/* Make sure transmit interrupts are on */		rs_enable_tx_interrupts(tty);	}	func_exit();}/* * ------------------------------------------------------------ * rs_throttle() *  * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. * ------------------------------------------------------------ */static void rs_throttle(struct tty_struct * tty){#ifdef TX3912_UART_DEBUG_THROTTLE	char	buf[64];		printk("throttle %s: %d....\n", tty_name(tty, buf),	       tty->ldisc.chars_in_buffer(tty));#endif	func_enter ();		if (I_IXOFF(tty))		rs_send_xchar(tty, STOP_CHAR(tty));	func_exit ();}static void rs_unthrottle(struct tty_struct * tty){	struct rs_port *port = (struct rs_port *)tty->driver_data;#ifdef TX3912_UART_DEBUG_THROTTLE	char	buf[64];		printk("unthrottle %s: %d....\n", tty_name(tty, buf),	       tty->ldisc.chars_in_buffer(tty));#endif	func_enter();		if (I_IXOFF(tty)) {		if (port->x_char)			port->x_char = 0;		else			rs_send_xchar(tty, START_CHAR(tty));	}	func_exit();}/* ********************************************************************** * *                    Here are the initialization routines.               * * ********************************************************************** */void * ckmalloc (int size){        void *p;        p = kmalloc(size, GFP_KERNEL);        if (p)                 memset(p, 0, size);        return p;}static int rs_init_portstructs(void){	struct rs_port *port;	int i;	/* Debugging */	func_enter();	rs_ports          = ckmalloc(TX3912_UART_NPORTS * sizeof (struct rs_port));	if (!rs_ports)		return -ENOMEM;	port = rs_ports;	for (i=0; i < TX3912_UART_NPORTS;i++) {		rs_dprintk (TX3912_UART_DEBUG_INIT, "initing port %d\n", i);		port->gs.magic = SERIAL_MAGIC;		port->gs.close_delay = HZ/2;		port->gs.closing_wait = 30 * HZ;		port->gs.rd = &rs_real_driver;#ifdef NEW_WRITE_LOCKING		port->gs.port_write_sem = MUTEX;#endif#ifdef DECLARE_WAITQUEUE		init_waitqueue_head(&port->gs.open_wait);		init_waitqueue_head(&port->gs.close_wait);#endif		port->base = (i == 0) ? TX3912_UARTA_BASE : TX3912_UARTB_BASE;		port->intshift = (i == 0) ? UARTA_SHIFT : UARTB_SHIFT;		rs_dprintk (TX3912_UART_DEBUG_INIT, "base 0x%08lx intshift %d\n",			    port->base, port->intshift);		port++;	}	func_exit();	return 0;}static struct tty_operations rs_ops = {	.open	= rs_open,	.close = gs_close,	.write = gs_write,	.put_char = gs_put_char, 	.flush_chars = gs_flush_chars,	.write_room = gs_write_room,	.chars_in_buffer = gs_chars_in_buffer,	.flush_buffer = gs_flush_buffer,	.ioctl = rs_ioctl,	.throttle = rs_throttle,	.unthrottle = rs_unthrottle,	.set_termios = gs_set_termios,	.stop = gs_stop,	.start = gs_start,	.hangup = gs_hangup,};static int rs_init_drivers(void){	int error;	func_enter();	rs_driver = alloc_tty_driver(TX3912_UART_NPORTS);	if (!rs_driver)		return -ENOMEM;	rs_driver->owner = THIS_MODULE;	rs_driver->driver_name = "serial";	rs_driver->name = "ttyS";	rs_driver->major = TTY_MAJOR;	rs_driver->minor_start = 64;	rs_driver->type = TTY_DRIVER_TYPE_SERIAL;	rs_driver->subtype = SERIAL_TYPE_NORMAL;	rs_driver->init_termios = tty_std_termios;	rs_driver->init_termios.c_cflag =		B115200 | CS8 | CREAD | HUPCL | CLOCAL;	tty_set_operations(rs_driver, &rs_ops);	if ((error = tty_register_driver(rs_driver))) {		printk(KERN_ERR "Couldn't register serial driver, error = %d\n",		       error);		put_tty_driver(rs_driver);		return 1;	}	return 0;}static void __init tx3912_rs_init(void){	int rc;	func_enter();	rs_dprintk (TX3912_UART_DEBUG_INIT, "Initing serial module... (rs_debug=%d)\n", rs_debug);	rc = rs_init_portstructs ();	rs_init_drivers ();	if (request_irq(2, rs_tx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT,			"serial", &rs_ports[0])) {		printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n");		rc = 0;	}	if (request_irq(3, rs_rx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT,			"serial", &rs_ports[0])) {		printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n");		rc = 0;	}	IntEnable6 |= INT6_UARTARXINT; 	rs_enable_rx_interrupts(&rs_ports[0]); #ifndef CONFIG_SERIAL_TX3912_CONSOLE{	unsigned int scratch = 0;	/* Setup master clock for UART */	scratch = inl(TX3912_CLK_CTRL_BASE);	scratch &= ~TX3912_CLK_CTRL_SIBMCLKDIV_MASK;	scratch |= ((0x2 << TX3912_CLK_CTRL_SIBMCLKDIV_SHIFT) &				TX3912_CLK_CTRL_SIBMCLKDIV_MASK)			| TX3912_CLK_CTRL_SIBMCLKDIR			| TX3912_CLK_CTRL_ENSIBMCLK			| TX3912_CLK_CTRL_CSERSEL;	outl(scratch, TX3912_CLK_CTRL_BASE);	/* Configure UARTA clock */	scratch = inl(TX3912_CLK_CTRL_BASE);	scratch |= ((0x3 << TX3912_CLK_CTRL_CSERDIV_SHIFT) &				TX3912_CLK_CTRL_CSERDIV_MASK)			| TX3912_CLK_CTRL_ENCSERCLK			| TX3912_CLK_CTRL_ENUARTACLK;	outl(scratch, TX3912_CLK_CTRL_BASE);			/* Setup UARTA for 115200,8N1 */	outl(0, TX3912_UARTA_BASE + TX3912_UART_CTRL1);	outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_BASE + TX3912_UART_CTRL2);	outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL1);	outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL2);	/* Enable UARTA */	outl(TX3912_UART_CTRL1_ENUART, TX3912_UARTA_BASE + TX3912_UART_CTRL1);	while (~inl(TX3912_UARTA_BASE + TX3912_UART_CTRL1) &		TX3912_UART_CTRL1_UARTON);}#endif	/* Note: I didn't do anything to enable the second UART */	if (rc >= 0) 		rs_initialized++;	func_exit();}module_init(tx3912_rs_init);/* * Begin serial console routines */#ifdef CONFIG_SERIAL_TX3912_CONSOLEvoid serial_outc(unsigned char c){	int i;	unsigned long int2;	#define BUSY_WAIT 10000	/*	 * Turn UARTA interrupts off	 */	int2 = IntEnable2;	IntEnable2 &=		~(INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY);	/*	 * The UART_TX_EMPTY bit in UartA_Ctrl1 seems	 * not to be very reliable :-(	 *	 * Wait for the Tx register to become empty	 */	for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < BUSY_WAIT); i++);	IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY;	UartA_Data = c;	for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < BUSY_WAIT); i++);	IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY;	IntEnable2 = int2;}static void serial_console_write(struct console *co, const char *s,		unsigned count){    	unsigned int i;	for (i = 0; i < count; i++) {		if (*s == '\n')			serial_outc('\r');		serial_outc(*s++);    	}}static struct tty_driver *serial_console_device(struct console *c, int *index){	*index = c->index;	return rs_driver;}static __init int serial_console_setup(struct console *co, char *options){	unsigned int scratch = 0;	/* Setup master clock for UART */	scratch = inl(TX3912_CLK_CTRL_BASE);	scratch &= ~TX3912_CLK_CTRL_SIBMCLKDIV_MASK;	scratch |= ((0x2 << TX3912_CLK_CTRL_SIBMCLKDIV_SHIFT) &				TX3912_CLK_CTRL_SIBMCLKDIV_MASK)			| TX3912_CLK_CTRL_SIBMCLKDIR			| TX3912_CLK_CTRL_ENSIBMCLK			| TX3912_CLK_CTRL_CSERSEL;	outl(scratch, TX3912_CLK_CTRL_BASE);	/* Configure UARTA clock */	scratch = inl(TX3912_CLK_CTRL_BASE);	scratch |= ((0x3 << TX3912_CLK_CTRL_CSERDIV_SHIFT) &				TX3912_CLK_CTRL_CSERDIV_MASK)			| TX3912_CLK_CTRL_ENCSERCLK			| TX3912_CLK_CTRL_ENUARTACLK;	outl(scratch, TX3912_CLK_CTRL_BASE);			/* Setup UARTA for 115200,8N1 */	outl(0, TX3912_UARTA_BASE + TX3912_UART_CTRL1);	outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_BASE + TX3912_UART_CTRL2);	outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL1);	outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL2);	/* Enable UARTA */	outl(TX3912_UART_CTRL1_ENUART, TX3912_UARTA_BASE + TX3912_UART_CTRL1);	while (~inl(TX3912_UARTA_BASE + TX3912_UART_CTRL1) &		TX3912_UART_CTRL1_UARTON);	return 0;}static struct console sercons = {	.name     = "ttyS",	.write    = serial_console_write,	.device   = serial_console_device,	.setup    = serial_console_setup,	.flags    = CON_PRINTBUFFER,	.index    = -1};static int __init tx3912_console_init(void){	register_console(&sercons);	return 0;}console_initcall(tx3912_console_init);#endif

⌨️ 快捷键说明

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