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

📄 sx.c

📁 这是一个SIGMA方案的PMP播放器的UCLINUX程序,可播放DVD,VCD,CD MP3...有很好的参考价值.
💻 C
📖 第 1 页 / 共 5 页
字号:
	   if you've dropped it with stty 0. Moved to set_baud, where it	   belongs (next to the drop dtr if baud == 0) -- REW */	/* sx_setsignals (port, 1, -1); */	sx_set_baud (port);#define CFLAG port->gs.tty->termios->c_cflag	sx_write_channel_byte (port, hi_mr1,	                       (C_PARENB (port->gs.tty)? MR1_WITH:MR1_NONE) |	                       (C_PARODD (port->gs.tty)? MR1_ODD:MR1_EVEN) |	                       (C_CRTSCTS(port->gs.tty)? MR1_RTS_RXFLOW:0) |	                       (((CFLAG & CSIZE)==CS8) ? MR1_8_BITS:0) |	                       (((CFLAG & CSIZE)==CS7) ? MR1_7_BITS:0) |	                       (((CFLAG & CSIZE)==CS6) ? MR1_6_BITS:0) |	                       (((CFLAG & CSIZE)==CS5) ? MR1_5_BITS:0) );	sx_write_channel_byte (port, hi_mr2,	                       (C_CRTSCTS(port->gs.tty)?MR2_CTS_TXFLOW:0) |	                       (C_CSTOPB (port->gs.tty)?MR2_2_STOP:MR2_1_STOP));	switch (CFLAG & CSIZE) {	case CS8:sx_write_channel_byte (port, hi_mask, 0xff);break;	case CS7:sx_write_channel_byte (port, hi_mask, 0x7f);break;	case CS6:sx_write_channel_byte (port, hi_mask, 0x3f);break;	case CS5:sx_write_channel_byte (port, hi_mask, 0x1f);break;	default:		printk (KERN_INFO "sx: Invalid wordsize: %d\n", CFLAG & CSIZE);		break;	}	sx_write_channel_byte (port, hi_prtcl, 	                       (I_IXON   (port->gs.tty)?SP_TXEN:0) |	                       (I_IXOFF  (port->gs.tty)?SP_RXEN:0) |	                       (I_IXANY  (port->gs.tty)?SP_TANY:0) |	                       SP_DCEN);	sx_write_channel_byte (port, hi_break, 	                       (I_IGNBRK(port->gs.tty)?BR_IGN:0 |	                        I_BRKINT(port->gs.tty)?BR_INT:0));	sx_write_channel_byte (port, hi_txon,  START_CHAR (port->gs.tty));	sx_write_channel_byte (port, hi_rxon,  START_CHAR (port->gs.tty));	sx_write_channel_byte (port, hi_txoff, STOP_CHAR  (port->gs.tty));	sx_write_channel_byte (port, hi_rxoff, STOP_CHAR  (port->gs.tty));	sx_reconfigure_port(port);	/* Tell line discipline whether we will do input cooking */	if(I_OTHER(port->gs.tty)) {		clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);	} else {		set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);	}	sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ", 	            port->gs.tty->termios->c_iflag, 	            I_OTHER(port->gs.tty));/* Tell line discipline whether we will do output cooking. * If OPOST is set and no other output flags are set then we can do output * processing.  Even if only *one* other flag in the O_OTHER group is set * we do cooking in software. */	if(O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) {		set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);	} else {		clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);	}	sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n", 	            port->gs.tty->termios->c_oflag, 	            O_OTHER(port->gs.tty));	/* port->c_dcd = sx_get_CD (port); */	func_exit ();	return 0;}/* ********************************************************************** * *                   the interrupt related routines                       * * ********************************************************************** *//* Note:   Other drivers use the macro "MIN" to calculate how much to copy.   This has the disadvantage that it will evaluate parts twice. That's   expensive when it's IO (and the compiler cannot optimize those away!).   Moreover, I'm not sure that you're race-free.    I assign a value, and then only allow the value to decrease. This   is always safe. This makes the code a few lines longer, and you   know I'm dead against that, but I think it is required in this   case.  */static void sx_transmit_chars (struct sx_port *port){	int c;	int tx_ip;	int txroom;	func_enter2 ();	sx_dprintk (SX_DEBUG_TRANSMIT, "Port %p: transmit %d chars\n", 	            port, port->gs.xmit_cnt);	if (test_and_set_bit (SX_PORT_TRANSMIT_LOCK, &port->locks)) {		return;	}	while (1) {		c = port->gs.xmit_cnt;		sx_dprintk (SX_DEBUG_TRANSMIT, "Copying %d ", c);		tx_ip  = sx_read_channel_byte (port, hi_txipos);		/* Took me 5 minutes to deduce this formula. 		   Luckily it is literally in the manual in section 6.5.4.3.5 */		txroom = (sx_read_channel_byte (port, hi_txopos) - tx_ip - 1) & 0xff;		/* Don't copy more bytes than there is room for in the buffer */		if (c > txroom)			c = txroom;		sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, txroom );		/* Don't copy past the end of the hardware transmit buffer */		if (c > 0x100 - tx_ip) 			c = 0x100 - tx_ip;		sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, 0x100-tx_ip );		/* Don't copy pas the end of the source buffer */		if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail) 			c = SERIAL_XMIT_SIZE - port->gs.xmit_tail;		sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%ld) \n", 		            c, SERIAL_XMIT_SIZE- port->gs.xmit_tail);		/* If for one reason or another, we can't copy more data, we're done! */		if (c == 0) break;		memcpy_toio (port->board->base + CHAN_OFFSET(port,hi_txbuf) + tx_ip, 		             port->gs.xmit_buf + port->gs.xmit_tail, c);		/* Update the pointer in the card */		sx_write_channel_byte (port, hi_txipos, (tx_ip+c) & 0xff);		/* Update the kernel buffer end */		port->gs.xmit_tail = (port->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE-1);		/* This one last. (this is essential)		   It would allow others to start putting more data into the buffer! */		port->gs.xmit_cnt -= c;	}	if (port->gs.xmit_cnt == 0) {		sx_disable_tx_interrupts (port);	}	if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) {		if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&		    port->gs.tty->ldisc.write_wakeup)			(port->gs.tty->ldisc.write_wakeup)(port->gs.tty);		sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",		            port->gs.wakeup_chars); 		wake_up_interruptible(&port->gs.tty->write_wait);	}	clear_bit (SX_PORT_TRANSMIT_LOCK, &port->locks);	func_exit ();}/* Note the symmetry between receiving chars and transmitting them!   Note: The kernel should have implemented both a receive buffer and   a transmit buffer. *//* Inlined: Called only once. Remove the inline when you add another call */static inline void sx_receive_chars (struct sx_port *port){	int c;	int rx_op;	struct tty_struct *tty;	int copied=0;	func_enter2 ();	tty = port->gs.tty;	while (1) {		rx_op = sx_read_channel_byte (port, hi_rxopos);		c = (sx_read_channel_byte (port, hi_rxipos) - rx_op) & 0xff;		sx_dprintk (SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c); 		/* Don't copy more bytes than there is room for in the buffer */		if (tty->flip.count + c > TTY_FLIPBUF_SIZE) 			c = TTY_FLIPBUF_SIZE - tty->flip.count;		sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c); 		/* Don't copy past the end of the hardware receive buffer */		if (rx_op + c > 0x100) c = 0x100 - rx_op;		sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c);		/* If for one reason or another, we can't copy more data, we're done! */		if (c == 0) break;		sx_dprintk (SX_DEBUG_RECEIVE , "Copying over %d chars. First is %d at %lx\n", c, 		            read_sx_byte (port->board, CHAN_OFFSET(port,hi_rxbuf) + rx_op),		            CHAN_OFFSET(port, hi_rxbuf)); 		memcpy_fromio (tty->flip.char_buf_ptr, 		               port->board->base + CHAN_OFFSET(port,hi_rxbuf) + rx_op, c);		memset(tty->flip.flag_buf_ptr, TTY_NORMAL, c);		/* Update the kernel buffer end */		tty->flip.count += c;		tty->flip.char_buf_ptr += c;		tty->flip.flag_buf_ptr += c;		/* This one last. ( Not essential.)		   It allows the card to start putting more data into the buffer! 		   Update the pointer in the card */		sx_write_channel_byte (port, hi_rxopos, (rx_op + c) & 0xff);		copied += c;	}	if (copied) {		struct timeval tv;		do_gettimeofday (&tv);		sx_dprintk (SX_DEBUG_RECEIVE, 		            "pushing flipq port %d (%3d chars): %d.%06d  (%d/%d)\n", 		            port->line, copied, 		            (int) (tv.tv_sec % 60), (int)tv.tv_usec, tty->raw, tty->real_raw);		/* Tell the rest of the system the news. Great news. New characters! */		tty_flip_buffer_push (tty);		/*    tty_schedule_flip (tty); */	}	func_exit ();}/* Inlined: it is called only once. Remove the inline if you add another    call */static inline void sx_check_modem_signals (struct sx_port *port){	int hi_state;	int c_dcd;	hi_state = sx_read_channel_byte (port, hi_state);	sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n",	            port->c_dcd, sx_get_CD (port));	if (hi_state & ST_BREAK) {		hi_state &= ~ST_BREAK;		sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a break.\n");		sx_write_channel_byte (port, hi_state, hi_state);		gs_got_break (&port->gs);	}	if (hi_state & ST_DCD) {		hi_state &= ~ST_DCD;		sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n");		sx_write_channel_byte (port, hi_state, hi_state);		c_dcd = sx_get_CD (port);		sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd);		if (c_dcd != port->c_dcd) {			port->c_dcd = c_dcd;			if (sx_get_CD (port)) {				/* DCD went UP */				if( (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || 						 ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) &&						(sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED)) {					/* Are we blocking in open?*/					sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD active, unblocking open\n");					wake_up_interruptible(&port->gs.open_wait);				} else {					sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD raised. Ignoring.\n");				}			} else {				/* DCD went down! */				if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) &&				      (port->gs.flags & ASYNC_CALLOUT_NOHUP))) {					sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. hanging up....\n");					tty_hangup (port->gs.tty);				} else {					sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. ignoring.\n");				}			}		} else {			sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Hmmm. card told us DCD changed, but it didn't.\n");		}	}}/* This is what an interrupt routine should look like.  * Small, elegant, clear. */static void sx_interrupt (int irq, void *ptr, struct pt_regs *regs){	struct sx_board *board = ptr;	struct sx_port *port;	int i;	/*   func_enter ();  */	sx_dprintk (SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq, board->irq); 	/* AAargh! The order in which to do these things is essential and	   not trivial. 	   - Rate limit goes before "recursive". Otherwise a series of	     recursive calls will hang the machine in the interrupt routine. 	   - hardware twiddling goes before "recursive". Otherwise when we	     poll the card, and a recursive interrupt happens, we wont	     ack the card, so it might keep on interrupting us. (especially	     level sensitive interrupt systems like PCI).	   - Rate limit goes before hardware twiddling. Otherwise we won't	     catch a card that has gone bonkers.	   - The "initialized" test goes after the hardware twiddling. Otherwise	     the card will stick us in the interrupt routine again.	   - The initialized test goes before recursive. 	*/#ifdef IRQ_RATE_LIMIT	/* Aaargh! I'm ashamed. This costs more lines-of-code than the	   actual interrupt routine!. (Well, used to when I wrote that comment) */	{		static int lastjif;		static int nintr=0;		if (lastjif == jiffies) {			if (++nintr > IRQ_RATE_LIMIT) {				free_irq (board->irq, board);				printk (KERN_ERR "sx: Too many interrupts. Turning off interrupt %d.\n", 					      board->irq);			}		} else {			lastjif = jiffies;			nintr = 0;		}	}#endif	if (board->irq == irq) {		/* Tell the card we've noticed the interrupt. */		sx_write_board_word (board, cc_int_pending, 0);		if (IS_SX_BOARD (board)) {			write_sx_byte (board, SX_RESET_IRQ, 1);		} else if (IS_EISA_BOARD(board)) {			inb(board->eisa_base+0xc03);			write_sx_word(board, 8, 0); 		} else {			write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR);			write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);		}	}	if (!sx_initialized) return;	if (!(board->flags & SX_BOARD_INITIALIZED)) return;	if (test_and_set_bit (SX_BOARD_INTR_LOCK, &board->locks)) {		printk (KERN_ERR "Recursive interrupt! (%d)\n", board->irq);		return;	}	 for (i=0;i<board->nports;i++) {		port = &board->ports[i];		if (port->gs.flags & GS_ACTIVE) {			if (sx_read_channel_byte (port, hi_state)) {				sx_dprintk (SX_DEBUG_INTERRUPTS, 				            "Port %d: modem signal change?... \n", i);				sx_check_modem_signals (port); 			}			if (port->gs.xmit_cnt) {				sx_transmit_chars (port);			}			if (!(port->gs.flags & SX_RX_THROTTLE)) {				sx_receive_chars (port);			}		}	}	clear_bit (SX_BOARD_INTR_LOCK, &board->locks);	sx_dprintk (SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq, board->irq); 	/*  func_exit ();  */}static void sx_pollfunc (unsigned long data){	struct sx_board *board = (struct sx_board *) data;	func_enter ();	sx_interrupt (0, board, NULL);	init_timer(&board->timer);	board->timer.expires = jiffies + sx_poll;	add_timer (&board->timer);	func_exit ();}/* ********************************************************************** * *                Here are the routines that actually                     * *              interface with the generic_serial driver                  * * ********************************************************************** *//* Ehhm. I don't know how to fiddle with interrupts on the SX card. --REW *//* Hmm. Ok I figured it out. You don't.  */static void sx_disable_tx_interrupts (void * ptr) {	struct sx_port *port = ptr; 	func_enter2();	port->gs.flags &= ~GS_TX_INTEN;	func_exit();}static void sx_enable_tx_interrupts (void * ptr) {	struct sx_port *port = ptr; 	int data_in_buffer;	func_enter2();	/* First transmit the characters that we're supposed to */	sx_transmit_chars (port);	/* The sx card will never interrupt us if we don't fill the buffer	   past 25%. So we keep considering interrupts off if that's the case. */

⌨️ 快捷键说明

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