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

📄 serial_atmel.c

📁 这是一个SIGMA方案的PMP播放器的UCLINUX程序,可播放DVD,VCD,CD MP3...有很好的参考价值.
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * This is the serial driver's generic interrupt routine */static void rs_interrupta(int irq, void *dev_id, struct pt_regs *regs){	rs_interrupt(&atmel_info[0]);}static void rs_interruptb(int irq, void *dev_id, struct pt_regs *regs){	rs_interrupt(&atmel_info[1]);}static void rs_interrupt(struct atmel_serial *info){	unsigned long status;	status = info->usart->csr;	if (status & (US_ENDRX | US_TIMEOUT)) {		receive_chars(info, status);	}	if (status & (US_TXEMPTY)) {		transmit_chars(info);	}	status_handle(info, status);#ifdef US_RTS	if (!info->cts_state) {		if (info->tty->flip.count < TTY_FLIPBUF_SIZE - RX_SERIAL_SIZE) {			atmel_cts_on(info);		}	}#endif	if (!info->use_ints) {		serialpoll.data = (void *) info;		queue_task(&serialpoll, &tq_timer);	}	return;}static void serpoll(void *data){	struct atmel_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_atmel_serial);}static void do_softint(void *private_){	struct atmel_serial *info = (struct atmel_serial *) private_;	struct tty_struct *tty;	tty = info->tty;	if (!tty)		return;#if 0 	// FIXME - CHECK	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);	}#endif}/* * 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 atmel_serial *info = (struct atmel_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. */#if 0static void rs_timer(void){	panic("rs_timer called\n");	return;}#endifstatic unsigned long calcCD(unsigned long br){	return (UART_CLOCK / br);}static void uart_init(struct atmel_serial *info){	volatile struct atmel_usart_regs *uart;	if (info) {		uart = info->usart;	} else {		uart = usarts[0];	}	/* Reset the USART */	uart->cr = US_TXDIS | US_RXDIS | US_RSTTX | US_RSTRX;	/* clear Rx receive and Tx sent counters */	uart->rcr = 0;	uart->tcr = 0;	/* Disable interrups till we say we want them */	tx_disable(info->usart);	rx_disable(info->usart);		/* Set the serial port into a safe sane state */	uart->mr = US_USCLKS(0) | US_CLK0 | US_CHMODE(0) | US_NBSTOP(0) |		    US_PAR(4) | US_CHRL(3);#ifndef FORCE_57600	uart->brgr = calcCD(9600);#else	uart->brgr = calcCD(57600);#endif	uart->rtor = 20;			// timeout = value * 4 *bit period	uart->ttgr = 0;				// no guard time	uart->rcr = 0;	uart->rpr = 0;	uart->tcr = 0;	uart->tpr = 0;#ifdef US_RTS	uart->mc = 0; #endif}/* It is the responsibilty of whoever calls this function to be sure * that that have called *	tx_stop(uart); rx_stop(uart); * before calling the function.  Failure to do this will cause messy * things to happen.  You have been warned.   */static void uart_speed(struct atmel_serial *info, unsigned cflag){	unsigned baud = info->baud;	volatile struct atmel_usart_regs *uart = info->usart;	// disable tx and rx	uart->cr = US_TXDIS | US_RXDIS;		// disable interrupts	tx_disable(uart);	rx_disable(uart);	#ifndef FORCE_57600	uart->brgr = calcCD(baud);#else	uart->brgr = calcCD(57600);#endif/* FIXME */#if 0	/* probably not needed */	uart->US_RTOR = 20;			// timeout = value * 4 *bit period	uart->US_TTGR = 0;				// no guard time	uart->US_RPR = 0;	uart->US_RCR = 0;	uart->US_TPR = 0;	uart->US_TCR = 0;#endif/* FIXME */#if 0	uart->mc = 0;	if (cflag != 0xffff) {		uart->mr = US_USCLKS(0) | US_CLK0 | US_CHMODE(0) | US_NBSTOP(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	}#endif		/* FIXME */#if 0	// enable tx and rx	uart->cr = US_TXEN | US_RXEN;		// enable interrupts	tx_enable();	rx_enable();#endif	tx_start(uart, info->use_ints);	start_rx(info);}static void wait_EOT(volatile struct atmel_usart_regs *uart){	// make sure tx is enabled	uart->cr = US_TXEN;		// wait until all chars sent FIXME - is this sane ?	while (1) {		if (uart->csr & US_TXEMPTY)			break;	}}static int startup(struct atmel_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);		//info->rx_buf = rx_buf1;		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(0, 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 atmel_serial *info){	unsigned long flags;	tx_disable(info->usart);	rx_disable(info->usart);	rx_stop(info->usart);		/* 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 atmel_serial *info){	unsigned cflag;	int      i;	if (!info->tty || !info->tty->termios)		return;	cflag = info->tty->termios->c_cflag;	// disable tx and rx	info->usart->cr = US_TXDIS | US_RXDIS;		/* First disable the interrupts */	tx_stop(info->usart);	rx_stop(info->usart);	/* set the baudrate */	i = cflag & CBAUD;	info->baud = baud_table[i];	uart_speed(info, cflag);	tx_start(info->usart, info->use_ints);	rx_start(info->usart, info->use_ints);	// enable tx and rx	info->usart->cr = US_TXEN | US_RXEN;		return;}static void start_rx(struct atmel_serial *info){	volatile struct atmel_usart_regs *uart = info->usart;	rx_stop(uart);/*  FIXME - rehnberg	if (info->rx_buf == rx_buf1) {		info->rx_buf = rx_buf2;	} else {		info->rx_buf = rx_buf1;	}*/	uart->rpr = (unsigned long) info->rx_buf;	uart->rcr = (unsigned long) RX_SERIAL_SIZE;	rx_start(uart, info->use_ints);}static void xmit_char(struct atmel_serial *info, char ch){	prompt0 = ch;	xmit_string(info, &prompt0, 1);}static void xmit_string(struct atmel_serial *info, char *p, int len){	info->usart->tcr = 0;	info->usart->tpr = (unsigned long) p;	info->usart->tcr = (unsigned long) len;	tx_start(info->usart, info->use_ints);}/* * atmel_console_print is registered for printk. */int atmel_console_initialized;static void init_console(struct atmel_serial *info){	memset(info, 0, sizeof(struct atmel_serial));#ifdef CONFIG_SWAP_ATMEL_PORTS	info->usart = (volatile struct atmel_usart_regs *) AT91_USART1_BASE;	info->irqmask = AIC_URT1;	info->irq = IRQ_USART1;#else	info->usart = (volatile struct atmel_usart_regs *) AT91_USART0_BASE;	info->irqmask = 1<<IRQ_USART0;	info->irq = IRQ_USART0;#endif	info->tty = 0;	info->port = 0;	info->use_ints = 0;	info->cts_state = 1;	info->is_cons = 1;	atmel_console_initialized = 1;}void console_print_atmel(const char *p){	char c;	struct atmel_serial *info;#ifdef CONFIG_SWAP_ATMEL_PORTS	info = &atmel_info[1];#else	info = &atmel_info[0];#endif	if (!atmel_console_initialized) {		init_console(info);		uart_init(info);		info->baud = 9600;		tx_stop(info->usart);		rx_stop(info->usart);		uart_speed(info, 0xffff);		tx_start(info->usart, info->use_ints);		rx_start(info->usart, info->use_ints);	}	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 0	if (!info->use_ints)	    rs_fair_output(info);#endif	return;}static void rs_set_ldisc(struct tty_struct *tty){	struct atmel_serial *info = (struct atmel_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 atmel_serial *info = (struct atmel_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->usart, 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->usart, info->use_ints);	}	if (!info->use_ints)		wait_EOT(info->usart);	/* 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 atmel_serial *info = (struct atmel_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;	save_flags(flags);	while (1) {		cli();		c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,						   SERIAL_XMIT_SIZE - info->xmit_head));		if (c <= 0)			break;		if (from_user) {			down(&tmp_buf_sem);			copy_from_user(tmp_buf, buf, c);			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);			up(&tmp_buf_sem);		} else {

⌨️ 快捷键说明

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