specialix.c

来自「linux 内核源代码」· C语言 代码 · 共 2,562 行 · 第 1/5 页

C
2,562
字号
#if 0	/* It's time to find IRQ for this board */	for (retries = 0; retries < 5 && irqs <= 0; retries++) {		irqs = probe_irq_on();		sx_init_CD186x(bp);	       		/* Reset CD186x chip       */		sx_out(bp, CD186x_CAR, 2);               /* Select port 2          */		sx_wait_CCR(bp);		sx_out(bp, CD186x_CCR, CCR_TXEN);        /* Enable transmitter     */		sx_out(bp, CD186x_IER, IER_TXRDY);       /* Enable tx empty intr   */		msleep(50);		irqs = probe_irq_off(irqs);		dprintk (SX_DEBUG_INIT, "SRSR = %02x, ", sx_in(bp, CD186x_SRSR));		dprintk (SX_DEBUG_INIT, "TRAR = %02x, ", sx_in(bp, CD186x_TRAR));		dprintk (SX_DEBUG_INIT, "GIVR = %02x, ", sx_in(bp, CD186x_GIVR));		dprintk (SX_DEBUG_INIT, "GICR = %02x, ", sx_in(bp, CD186x_GICR));		dprintk (SX_DEBUG_INIT, "\n");		/* Reset CD186x again      */		if (!sx_init_CD186x(bp)) {			/* Hmmm. This is dead code anyway. */		}		dprintk (SX_DEBUG_INIT "val1 = %02x, val2 = %02x, val3 = %02x.\n",		        val1, val2, val3);	}#if 0	if (irqs <= 0) {		printk(KERN_ERR "sx%d: Can't find IRQ for specialix IO8+ board at 0x%03x.\n",		       board_No(bp), bp->base);		sx_release_io_range(bp);		func_exit();		return 1;	}#endif	printk (KERN_INFO "Started with irq=%d, but now have irq=%d.\n", bp->irq, irqs);	if (irqs > 0)		bp->irq = irqs;#endif	/* Reset CD186x again  */	if (!sx_init_CD186x(bp)) {		sx_release_io_range(bp);		func_exit();		return 1;	}	sx_request_io_range(bp);	bp->flags |= SX_BOARD_PRESENT;	/* Chip           revcode   pkgtype	                  GFRCR     SRCR bit 7	   CD180 rev B    0x81      0	   CD180 rev C    0x82      0	   CD1864 rev A   0x82      1	   CD1865 rev A   0x83      1  -- Do not use!!! Does not work.	   CD1865 rev B   0x84      1	 -- Thanks to Gwen Wang, Cirrus Logic.	 */	switch (sx_in_off(bp, CD186x_GFRCR)) {	case 0x82:chip = 1864;rev='A';break;	case 0x83:chip = 1865;rev='A';break;	case 0x84:chip = 1865;rev='B';break;	case 0x85:chip = 1865;rev='C';break; /* Does not exist at this time */	default:chip=-1;rev='x';	}	dprintk (SX_DEBUG_INIT, " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR) );#ifdef SPECIALIX_TIMER	setup_timer(&missed_irq_timer, missed_irq, (unsigned long)bp);	mod_timer(&missed_irq_timer, jiffies + sx_poll);#endif	printk(KERN_INFO"sx%d: specialix IO8+ board detected at 0x%03x, IRQ %d, CD%d Rev. %c.\n",	       board_No(bp),	       bp->base, bp->irq,	       chip, rev);	func_exit();	return 0;}/* * *  Interrupt processing routines. * */static inline void sx_mark_event(struct specialix_port * port, int event){	func_enter();	set_bit(event, &port->event);	schedule_work(&port->tqueue);	func_exit();}static inline struct specialix_port * sx_get_port(struct specialix_board * bp,					       unsigned char const * what){	unsigned char channel;	struct specialix_port * port = NULL;	channel = sx_in(bp, CD186x_GICR) >> GICR_CHAN_OFF;	dprintk (SX_DEBUG_CHAN, "channel: %d\n", channel);	if (channel < CD186x_NCH) {		port = &sx_port[board_No(bp) * SX_NPORT + channel];		dprintk (SX_DEBUG_CHAN, "port: %d %p flags: 0x%x\n",board_No(bp) * SX_NPORT + channel,  port, port->flags & ASYNC_INITIALIZED);		if (port->flags & ASYNC_INITIALIZED) {			dprintk (SX_DEBUG_CHAN, "port: %d %p\n", channel, port);			func_exit();			return port;		}	}	printk(KERN_INFO "sx%d: %s interrupt from invalid port %d\n",	       board_No(bp), what, channel);	return NULL;}static inline void sx_receive_exc(struct specialix_board * bp){	struct specialix_port *port;	struct tty_struct *tty;	unsigned char status;	unsigned char ch, flag;	func_enter();	port = sx_get_port(bp, "Receive");	if (!port) {		dprintk (SX_DEBUG_RX, "Hmm, couldn't find port.\n");		func_exit();		return;	}	tty = port->tty;	status = sx_in(bp, CD186x_RCSR);	dprintk (SX_DEBUG_RX, "status: 0x%x\n", status);	if (status & RCSR_OE) {		port->overrun++;		dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Overrun. Total %ld overruns.\n",		       board_No(bp), port_No(port), port->overrun);	}	status &= port->mark_mask;	/* This flip buffer check needs to be below the reading of the	   status register to reset the chip's IRQ.... */	if (tty_buffer_request_room(tty, 1) == 0) {		dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Working around flip buffer overflow.\n",		       board_No(bp), port_No(port));		func_exit();		return;	}	ch = sx_in(bp, CD186x_RDR);	if (!status) {		func_exit();		return;	}	if (status & RCSR_TOUT) {		printk(KERN_INFO "sx%d: port %d: Receiver timeout. Hardware problems ?\n",		       board_No(bp), port_No(port));		func_exit();		return;	} else if (status & RCSR_BREAK) {		dprintk(SX_DEBUG_RX, "sx%d: port %d: Handling break...\n",		       board_No(bp), port_No(port));		flag = TTY_BREAK;		if (port->flags & ASYNC_SAK)			do_SAK(tty);	} else if (status & RCSR_PE)		flag = TTY_PARITY;	else if (status & RCSR_FE)		flag = TTY_FRAME;	else if (status & RCSR_OE)		flag = TTY_OVERRUN;	else		flag = TTY_NORMAL;	if(tty_insert_flip_char(tty, ch, flag))		tty_flip_buffer_push(tty);	func_exit();}static inline void sx_receive(struct specialix_board * bp){	struct specialix_port *port;	struct tty_struct *tty;	unsigned char count;	func_enter();	if (!(port = sx_get_port(bp, "Receive"))) {		dprintk (SX_DEBUG_RX, "Hmm, couldn't find port.\n");		func_exit();		return;	}	tty = port->tty;	count = sx_in(bp, CD186x_RDCR);	dprintk (SX_DEBUG_RX, "port: %p: count: %d\n", port, count);	port->hits[count > 8 ? 9 : count]++;	tty_buffer_request_room(tty, count);	while (count--)		tty_insert_flip_char(tty, sx_in(bp, CD186x_RDR), TTY_NORMAL);	tty_flip_buffer_push(tty);	func_exit();}static inline void sx_transmit(struct specialix_board * bp){	struct specialix_port *port;	struct tty_struct *tty;	unsigned char count;	func_enter();	if (!(port = sx_get_port(bp, "Transmit"))) {		func_exit();		return;	}	dprintk (SX_DEBUG_TX, "port: %p\n", port);	tty = port->tty;	if (port->IER & IER_TXEMPTY) {		/* FIFO drained */		sx_out(bp, CD186x_CAR, port_No(port));		port->IER &= ~IER_TXEMPTY;		sx_out(bp, CD186x_IER, port->IER);		func_exit();		return;	}	if ((port->xmit_cnt <= 0 && !port->break_length)	    || tty->stopped || tty->hw_stopped) {		sx_out(bp, CD186x_CAR, port_No(port));		port->IER &= ~IER_TXRDY;		sx_out(bp, CD186x_IER, port->IER);		func_exit();		return;	}	if (port->break_length) {		if (port->break_length > 0) {			if (port->COR2 & COR2_ETC) {				sx_out(bp, CD186x_TDR, CD186x_C_ESC);				sx_out(bp, CD186x_TDR, CD186x_C_SBRK);				port->COR2 &= ~COR2_ETC;			}			count = min_t(int, port->break_length, 0xff);			sx_out(bp, CD186x_TDR, CD186x_C_ESC);			sx_out(bp, CD186x_TDR, CD186x_C_DELAY);			sx_out(bp, CD186x_TDR, count);			if (!(port->break_length -= count))				port->break_length--;		} else {			sx_out(bp, CD186x_TDR, CD186x_C_ESC);			sx_out(bp, CD186x_TDR, CD186x_C_EBRK);			sx_out(bp, CD186x_COR2, port->COR2);			sx_wait_CCR(bp);			sx_out(bp, CD186x_CCR, CCR_CORCHG2);			port->break_length = 0;		}		func_exit();		return;	}	count = CD186x_NFIFO;	do {		sx_out(bp, CD186x_TDR, port->xmit_buf[port->xmit_tail++]);		port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);		if (--port->xmit_cnt <= 0)			break;	} while (--count > 0);	if (port->xmit_cnt <= 0) {		sx_out(bp, CD186x_CAR, port_No(port));		port->IER &= ~IER_TXRDY;		sx_out(bp, CD186x_IER, port->IER);	}	if (port->xmit_cnt <= port->wakeup_chars)		sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);	func_exit();}static inline void sx_check_modem(struct specialix_board * bp){	struct specialix_port *port;	struct tty_struct *tty;	unsigned char mcr;	int msvr_cd;	dprintk (SX_DEBUG_SIGNALS, "Modem intr. ");	if (!(port = sx_get_port(bp, "Modem")))		return;	tty = port->tty;	mcr = sx_in(bp, CD186x_MCR);	printk ("mcr = %02x.\n", mcr);	if ((mcr & MCR_CDCHG)) {		dprintk (SX_DEBUG_SIGNALS, "CD just changed... ");		msvr_cd = sx_in(bp, CD186x_MSVR) & MSVR_CD;		if (msvr_cd) {			dprintk (SX_DEBUG_SIGNALS, "Waking up guys in open.\n");			wake_up_interruptible(&port->open_wait);		} else {			dprintk (SX_DEBUG_SIGNALS, "Sending HUP.\n");			schedule_work(&port->tqueue_hangup);		}	}#ifdef SPECIALIX_BRAIN_DAMAGED_CTS	if (mcr & MCR_CTSCHG) {		if (sx_in(bp, CD186x_MSVR) & MSVR_CTS) {			tty->hw_stopped = 0;			port->IER |= IER_TXRDY;			if (port->xmit_cnt <= port->wakeup_chars)				sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);		} else {			tty->hw_stopped = 1;			port->IER &= ~IER_TXRDY;		}		sx_out(bp, CD186x_IER, port->IER);	}	if (mcr & MCR_DSSXHG) {		if (sx_in(bp, CD186x_MSVR) & MSVR_DSR) {			tty->hw_stopped = 0;			port->IER |= IER_TXRDY;			if (port->xmit_cnt <= port->wakeup_chars)				sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);		} else {			tty->hw_stopped = 1;			port->IER &= ~IER_TXRDY;		}		sx_out(bp, CD186x_IER, port->IER);	}#endif /* SPECIALIX_BRAIN_DAMAGED_CTS */	/* Clear change bits */	sx_out(bp, CD186x_MCR, 0);}/* The main interrupt processing routine */static irqreturn_t sx_interrupt(int irq, void *dev_id){	unsigned char status;	unsigned char ack;	struct specialix_board *bp;	unsigned long loop = 0;	int saved_reg;	unsigned long flags;	func_enter();	bp = dev_id;	spin_lock_irqsave(&bp->lock, flags);	dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __FUNCTION__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);	if (!(bp->flags & SX_BOARD_ACTIVE)) {		dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", irq);		spin_unlock_irqrestore(&bp->lock, flags);		func_exit();		return IRQ_NONE;	}	saved_reg = bp->reg;	while ((++loop < 16) && (status = (sx_in(bp, CD186x_SRSR) &	                                   (SRSR_RREQint |		                            SRSR_TREQint |	                                    SRSR_MREQint)))) {		if (status & SRSR_RREQint) {			ack = sx_in(bp, CD186x_RRAR);			if (ack == (SX_ID | GIVR_IT_RCV))				sx_receive(bp);			else if (ack == (SX_ID | GIVR_IT_REXC))				sx_receive_exc(bp);			else				printk(KERN_ERR "sx%d: status: 0x%x Bad receive ack 0x%02x.\n",				       board_No(bp), status, ack);		} else if (status & SRSR_TREQint) {			ack = sx_in(bp, CD186x_TRAR);			if (ack == (SX_ID | GIVR_IT_TX))				sx_transmit(bp);			else				printk(KERN_ERR "sx%d: status: 0x%x Bad transmit ack 0x%02x. port: %d\n",				       board_No(bp), status, ack, port_No (sx_get_port (bp, "Int")));		} else if (status & SRSR_MREQint) {			ack = sx_in(bp, CD186x_MRAR);			if (ack == (SX_ID | GIVR_IT_MODEM))				sx_check_modem(bp);			else				printk(KERN_ERR "sx%d: status: 0x%x Bad modem ack 0x%02x.\n",				       board_No(bp), status, ack);		}		sx_out(bp, CD186x_EOIR, 0);   /* Mark end of interrupt */	}	bp->reg = saved_reg;	outb (bp->reg, bp->base + SX_ADDR_REG);	spin_unlock_irqrestore(&bp->lock, flags);	func_exit();	return IRQ_HANDLED;}/* *  Routines for open & close processing. */static void turn_ints_off (struct specialix_board *bp){	unsigned long flags;	func_enter();	if (bp->flags & SX_BOARD_IS_PCI) {		/* This was intended for enabeling the interrupt on the		 * PCI card. However it seems that it's already enabled		 * and as PCI interrupts can be shared, there is no real		 * reason to have to turn it off. */	}	spin_lock_irqsave(&bp->lock, flags);	(void) sx_in_off (bp, 0); /* Turn off interrupts. */	spin_unlock_irqrestore(&bp->lock, flags);	func_exit();}static void turn_ints_on (struct specialix_board *bp){	unsigned long flags;	func_enter();	if (bp->flags & SX_BOARD_IS_PCI) {		/* play with the PCI chip. See comment above. */	}	spin_lock_irqsave(&bp->lock, flags);	(void) sx_in (bp, 0); /* Turn ON interrupts. */	spin_unlock_irqrestore(&bp->lock, flags);	func_exit();}/* Called with disabled interrupts */static inline int sx_setup_board(struct specialix_board * bp){	int error;	if (bp->flags & SX_BOARD_ACTIVE)		return 0;	if (bp->flags & SX_BOARD_IS_PCI)		error = request_irq(bp->irq, sx_interrupt, IRQF_DISABLED | IRQF_SHARED, "specialix IO8+", bp);	else		error = request_irq(bp->irq, sx_interrupt, IRQF_DISABLED, "specialix IO8+", bp);	if (error)		return error;	turn_ints_on (bp);	bp->flags |= SX_BOARD_ACTIVE;	return 0;}/* Called with disabled interrupts */static inline void sx_shutdown_board(struct specialix_board *bp){	func_enter();	if (!(bp->flags & SX_BOARD_ACTIVE)) {		func_exit();		return;	}	bp->flags &= ~SX_BOARD_ACTIVE;	dprintk (SX_DEBUG_IRQ, "Freeing IRQ%d for board %d.\n",		 bp->irq, board_No (bp));	free_irq(bp->irq, bp);	turn_ints_off (bp);

⌨️ 快捷键说明

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