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

📄 trioserial.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * This is the serial driver's generic interrupt routine */void rs_interrupta(int irq, void *dev_id, struct pt_regs * regs){	rs_interrupt(&trio_info[0]);}void rs_interruptb(int irq, void *dev_id, struct pt_regs * regs){	rs_interrupt(&trio_info[1]);}static void rs_interrupt(struct trio_serial *info){	u_32 status;	status = info->uart->csr;		if (status & US_TXRDY) {		transmit_chars(info);	}	if (status & US_RXRDY){		receive_chars(info, status);	}	status_handle(info, status);		if(!info->use_ints){		serialpoll.data = (void *)info;				queue_task_irq_off(&serialpoll, &tq_timer);	}	return;}static void serpoll(void *data){	struct trio_serial * info = data;	rs_interrupt(info);}/* * ------------------------------------------------------------------- * Here ends the serial interrupt routines. * ------------------------------------------------------------------- *//* * This routine is used to handle the "bottom half" processing for the * serial driver, known also the "software interrupt" processing. * This processing is done at the kernel interrupt level, after the * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This * is where time-consuming activities which can not be done in the * interrupt driver proper are done; the interrupt driver schedules * them using rs_sched_event(), and they get done here. */static void do_serial_bh(void){	run_task_queue(&tq_serial);}static void do_softint(void *private_){	struct trio_serial	*info = (struct trio_serial *) private_;	struct tty_struct	*tty;		tty = info->tty;	if (!tty)		return;	if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&		    tty->ldisc.write_wakeup)			(tty->ldisc.write_wakeup)(tty);		wake_up_interruptible(&tty->write_wait);	}}/* * This routine is called from the scheduler tqueue when the interrupt * routine has signalled that a hangup has occurred.  The path of * hangup processing is: * * 	serial interrupt routine -> (scheduler tqueue) -> * 	do_serial_hangup() -> tty->hangup() -> rs_hangup() *  */static void do_serial_hangup(void *private_){	struct trio_serial	*info = (struct trio_serial *) private_;	struct tty_struct	*tty;		tty = info->tty;	if (!tty)		return;	tty_hangup(tty);}/* * This subroutine is called when the RS_TIMER goes off.  It is used * by the serial driver to handle ports that do not have an interrupt * (irq=0).  This doesn't work at all for 16450's, as a sun has a Z8530. */ static void rs_timer(void){	panic("rs_timer called\n");	return;}static u_32 calcCD(u_32 br){	return(UART_CLOCK/br);}static void uart_init(struct trio_serial *info){	struct uart_regs* uart;	if(info){		uart = info->uart;	}else{		uart = uarts[0];	}	uart->cr	= US_RSTRX|US_RSTTX|US_RSTSTA|US_TXDIS|US_RXDIS;	uart->mr	= US_USCLKS(0)|US_CLK0|US_CHMODE(0)|US_NBSTOP(0)|US_PAR(4)|US_CHRL(3);	uart->ier	= 0;	uart->idr	= US_ALL_INTS;	uart->brgr	= calcCD(9600);	uart->rtor	= 100;	// timeout = value * 4 * bit period	uart->ttgr	= 0;	// no guard time	uart->rpr	= 0;	uart->rcr	= 0;	uart->tpr	= 0;	uart->tcr	= 0;	uart->mc	= 0;}static void uart_speed(struct trio_serial *info, unsigned cflag){	unsigned baud = info->baud;	struct uart_regs *uart = info->uart;	uart->cr	= US_TXDIS|US_RXDIS;	uart->ier	= 0;	uart->idr	= US_ALL_INTS;	uart->brgr	= calcCD(baud);	uart->rtor	= 100;	// timeout = value * 4 *bit period		uart->ttgr	= 0;	// no guard time		uart->rpr	= 0;	uart->rcr	= 0;	uart->tpr	= 0;	uart->tcr	=0;	uart->mc	= 0;	if (cflag != 0xffff){		uart->mr	= US_USCLKS(0)|US_CLK0|US_CHMODE(0)|US_PAR(0);				if ((cflag & CSIZE) == CS8)			uart->mr |= US_CHRL(3);		// 8 bit char		else			uart->mr |= US_CHRL(2);		// 7 bit char				if (cflag & CSTOPB)			uart->mr |= US_NBSTOP(2);	// 2 stop bits				if (!(cflag & PARENB))			uart->mr |= US_PAR(4);		// parity disabled		else			if (cflag & PARODD)				uart->mr |= US_PAR(1);	// odd parity	}	tx_start(uart, info->use_ints);	start_rx(info);}static void wait_EOT(struct uart_regs *uart){	volatile u_32 status;	volatile struct uart_regs* puart;	puart = (volatile struct uart_regs*)uart;	while(1){		status = puart->csr;		if(status & US_TXRDY)			break;	}}static int startup(struct trio_serial * info){	unsigned long flags;	if (info->flags & S_INITIALIZED)		return 0;	if (!info->xmit_buf) {		info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);		if (!info->xmit_buf)			return -ENOMEM;	}	if (!info->rx_buf) {		info->rx_buf = (unsigned char *) get_free_page(GFP_KERNEL);		if (!info->rx_buf)			return -ENOMEM;	}	save_flags(flags); cli();#ifdef SERIAL_DEBUG_OPEN	printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq);#endif	/*	 * Clear the FIFO buffers and disable them	 * (they will be reenabled in change_speed())	 */		if (info->tty)		clear_bit(TTY_IO_ERROR, &info->tty->flags);	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;	/*	 * and set the speed of the serial port	 */	uart_init(info);	set_ints_mode(1, info);	change_speed(info);	info->flags |= S_INITIALIZED;	restore_flags(flags);	return 0;}/* * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */static void shutdown(struct trio_serial * info){	unsigned long	flags;	tx_disable(info->uart);	rx_disable(info->uart);	rx_stop(info->uart); /* All off! */	if (!(info->flags & S_INITIALIZED))		return;#ifdef SERIAL_DEBUG_OPEN	printk("Shutting down serial port %d (irq %d)....\n", info->line,	       info->irq);#endif		save_flags(flags); cli(); /* Disable interrupts */		if (info->xmit_buf) {		free_page((unsigned long) info->xmit_buf);		info->xmit_buf = 0;	}	if (info->tty)		set_bit(TTY_IO_ERROR, &info->tty->flags);		info->flags &= ~S_INITIALIZED;	restore_flags(flags);}/* rate = 1036800 / ((65 - prescale) * (1<<divider)) */static int baud_table[] = {	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,	9600, 19200, 38400, 57600, 115200, 0 };/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */static void change_speed(struct trio_serial *info){	unsigned cflag;	int	i;	if (!info->tty || !info->tty->termios)		return;	cflag = info->tty->termios->c_cflag;	/* First disable the interrupts */	tx_stop(info->uart);	rx_stop(info->uart);	/* set the baudrate */	i = cflag & CBAUD;	info->baud = baud_table[i];	uart_speed(info, cflag);	start_rx(info);	tx_start(info->uart, info->use_ints);	return;}static void start_rx(struct trio_serial *info){	struct uart_regs *uart = info->uart;	uart->rcr = (u_32)RX_SERIAL_SIZE;	uart->rpr = (u_32)info->rx_buf;		rx_start(uart, info->use_ints);}static void xmit_char(struct trio_serial *info, char ch){	prompt0 = ch;	xmit_string(info, &prompt0, 1);}static void xmit_string(struct trio_serial *info, char *p, int len){	info->uart->tcr = (u_32)len;	info->uart->tpr = (u_32)p;		tx_start(info->uart, info->use_ints);}#if 0/* These are for receiving and sending characters under the kgdb * source level kernel debugger. */void putDebugChar(char kgdb_char){	struct sun_zschannel *chan = trio_kgdbchan;	while((chan->control & Tx_BUF_EMP)==0)		udelay(5);	chan->data = kgdb_char;}char getDebugChar(void){	struct sun_zschannel *chan = trio_kgdbchan;	while((chan->control & Rx_CH_AV)==0)		barrier();	return chan->data;}#endif/* * Fair output driver allows a process to speak. */static void rs_fair_output(	struct trio_serial *info){	int left;		/* Output no more than that */	unsigned long flags;	char c;	if (info == 0) return;	if (info->xmit_buf == 0) return;	save_flags(flags);  cli();	left = info->xmit_cnt;	while (left != 0) {		c = info->xmit_buf[info->xmit_tail];		info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);		info->xmit_cnt--;		restore_flags(flags);		rs_put_char(info, c);		save_flags(flags);  cli();		left = MIN(info->xmit_cnt, left-1);	}	/* Last character is being transmitted now (hopefully). *///	udelay(20);	wait_EOT(info->uart);	restore_flags(flags);	return;}/* * trio_console_print is registered for printk. */static int console_initialized = 0;static void init_console(void){	struct trio_serial *info;	info = &trio_info[0];	memset(info, 0, sizeof(struct trio_serial));#if 0		info->uart = uarts[0];#else		info->uart = (struct uart_regs*)USARTA_BASE;#endif	info->tty = 0;	info->irqmask = AIC_UA;	info->irq = IRQ_USARTA;	info->port = 1;	info->use_ints = 0;	info->is_cons = 1;	console_initialized = 1;}void console_print_trio(const char *p){	char c;	struct trio_serial *info;	info = &trio_info[0];//	if (!(info->flags & S_INITIALIZED)){	if(!console_initialized){		init_console();		uart_init(info);		info->baud = 9600;		uart_speed(info,0xffff);	}	while((c=*(p++)) != 0) {		if(c == '\n')			rs_put_char(info, '\r');		rs_put_char(info, c);	}	/* Comment this if you want to have a strict interrupt-driven output *///	if (!info->use_ints)//		rs_fair_output(info);	return;}static void rs_set_ldisc(struct tty_struct *tty){	struct trio_serial *info = (struct trio_serial *)tty->driver_data;	if (serial_paranoia_check(info, tty->device, "rs_set_ldisc"))		return;	info->is_cons = (tty->termios->c_line == N_TTY);		printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");}static void rs_flush_chars(struct tty_struct *tty){	struct trio_serial *info = (struct trio_serial *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))		return;	if(!info->use_ints){			for(;;) {			if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||				!info->xmit_buf)				return;			/* Enable transmitter */			save_flags(flags); cli();			tx_start(info->uart,info->use_ints);		}	}else{		if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||			!info->xmit_buf)			return;			/* Enable transmitter */		save_flags(flags); cli();		tx_start(info->uart, info->use_ints);	}	if(!info->use_ints)			wait_EOT(info->uart);		/* Send char */	xmit_char(info, info->xmit_buf[info->xmit_tail++]);	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);	info->xmit_cnt--;		restore_flags(flags);}extern void console_printn(const char * b, int count);static int rs_write(struct tty_struct * tty, int from_user,		    const unsigned char *buf, int count){	int	c, total = 0;	struct trio_serial *info = (struct trio_serial *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "rs_write"))		return 0;	if (!tty || !info->xmit_buf)		return 0;		/*buf = "123456";	count = 6;		printk("Writing '%s' to serial port\n", buf);*/

⌨️ 快捷键说明

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