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

📄 specialix.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
		printk(KERN_INFO "sx%d: specialix IO8+ Board at 0x%03x not found.\n",		       board_No(bp), bp->base);		return 1;	}	/* Check the DSR lines that Specialix uses as board 	   identification */	val1 = read_cross_byte (bp, CD186x_MSVR, MSVR_DSR);	val2 = read_cross_byte (bp, CD186x_MSVR, MSVR_RTS);#ifdef SPECIALIX_DEBUG	printk (KERN_DEBUG "sx%d: DSR lines are: %02x, rts lines are: %02x\n", 	        board_No(bp),  val1, val2);#endif	/* They managed to switch the bit order between the docs and	   the IO8+ card. The new PCI card now conforms to old docs.	   They changed the PCI docs to reflect the situation on the	   old card. */	val2 = (bp->flags & SX_BOARD_IS_PCI)?0x4d : 0xb2;	if (val1 != val2) {		printk(KERN_INFO "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n",		       board_No(bp), val2, bp->base, val1);		return 1;	}#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   */		sx_long_delay(HZ/20);	       				irqs = probe_irq_off(irqs);#if SPECIALIX_DEBUG > 2		printk (KERN_DEBUG "SRSR = %02x, ",  sx_in(bp, CD186x_SRSR));		printk (           "TRAR = %02x, ",  sx_in(bp, CD186x_TRAR));		printk (           "GIVR = %02x, ",  sx_in(bp, CD186x_GIVR));		printk (           "GICR = %02x, ",  sx_in(bp, CD186x_GICR));		printk (           "\n");#endif		/* Reset CD186x again      */		if (!sx_init_CD186x(bp)) {			/* Hmmm. This is dead code anyway. */		}#if SPECIALIX_DEBUG > 2		printk (KERN_DEBUG "val1 = %02x, val2 = %02x, val3 = %02x.\n", 		        val1, val2, val3); #endif		}	#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);		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)) {		return -EIO;	}	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';	}#if SPECIALIX_DEBUG > 2	printk (KERN_DEBUG " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR) );#endif#ifdef SPECIALIX_TIMER	init_timer (&missed_irq_timer);	missed_irq_timer.function = missed_irq;	missed_irq_timer.data = (unsigned long) bp;	missed_irq_timer.expires = jiffies + HZ;	add_timer (&missed_irq_timer);#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);	return 0;}/*  *  *  Interrupt processing routines. * */extern inline void sx_mark_event(struct specialix_port * port, int event){	/* 	 * I'm not quite happy with current scheme all serial	 * drivers use their own BH routine.	 * It seems this easily can be done with one BH routine	 * serving for all serial drivers.	 * For now I must introduce another one - SPECIALIX_BH.	 * Still hope this will be changed in near future.	 * -- Dmitry.	 */	set_bit(event, &port->event);	queue_task(&port->tqueue, &tq_specialix);	mark_bh(SPECIALIX_BH);}extern inline struct specialix_port * sx_get_port(struct specialix_board * bp,					       unsigned char const * what){	unsigned char channel;	struct specialix_port * port;		channel = sx_in(bp, CD186x_GICR) >> GICR_CHAN_OFF;	if (channel < CD186x_NCH) {		port = &sx_port[board_No(bp) * SX_NPORT + channel];		if (port->flags & ASYNC_INITIALIZED) {			return port;		}	}	printk(KERN_INFO "sx%d: %s interrupt from invalid port %d\n", 	       board_No(bp), what, channel);	return NULL;}extern inline void sx_receive_exc(struct specialix_board * bp){	struct specialix_port *port;	struct tty_struct *tty;	unsigned char status;	unsigned char ch;	if (!(port = sx_get_port(bp, "Receive")))		return;	tty = port->tty;	if (tty->flip.count >= TTY_FLIPBUF_SIZE) {		printk(KERN_INFO "sx%d: port %d: Working around flip buffer overflow.\n",		       board_No(bp), port_No(port));		return;	}	#ifdef SX_REPORT_OVERRUN		status = sx_in(bp, CD186x_RCSR);	if (status & RCSR_OE) {		port->overrun++;#if SPECIALIX_DEBUG 		printk(KERN_DEBUG "sx%d: port %d: Overrun. Total %ld overruns.\n", 		       board_No(bp), port_No(port), port->overrun);#endif			}	status &= port->mark_mask;#else		status = sx_in(bp, CD186x_RCSR) & port->mark_mask;#endif		ch = sx_in(bp, CD186x_RDR);	if (!status) {		return;	}	if (status & RCSR_TOUT) {		printk(KERN_INFO "sx%d: port %d: Receiver timeout. Hardware problems ?\n", 		       board_No(bp), port_No(port));		return;			} else if (status & RCSR_BREAK) {#ifdef SPECIALIX_DEBUG		printk(KERN_DEBUG "sx%d: port %d: Handling break...\n",		       board_No(bp), port_No(port));#endif		*tty->flip.flag_buf_ptr++ = TTY_BREAK;		if (port->flags & ASYNC_SAK)			do_SAK(tty);			} else if (status & RCSR_PE) 		*tty->flip.flag_buf_ptr++ = TTY_PARITY;		else if (status & RCSR_FE) 		*tty->flip.flag_buf_ptr++ = TTY_FRAME;		else if (status & RCSR_OE)		*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;		else		*tty->flip.flag_buf_ptr++ = 0;		*tty->flip.char_buf_ptr++ = ch;	tty->flip.count++;	queue_task(&tty->flip.tqueue, &tq_timer);}extern inline void sx_receive(struct specialix_board * bp){	struct specialix_port *port;	struct tty_struct *tty;	unsigned char count;		if (!(port = sx_get_port(bp, "Receive")))		return;		tty = port->tty;		count = sx_in(bp, CD186x_RDCR);	#ifdef SX_REPORT_FIFO	port->hits[count > 8 ? 9 : count]++;#endif			while (count--) {		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {			printk(KERN_INFO "sx%d: port %d: Working around flip buffer overflow.\n",			       board_No(bp), port_No(port));			break;		}		*tty->flip.char_buf_ptr++ = sx_in(bp, CD186x_RDR);		*tty->flip.flag_buf_ptr++ = 0;		tty->flip.count++;	}	queue_task(&tty->flip.tqueue, &tq_timer);}extern inline void sx_transmit(struct specialix_board * bp){	struct specialix_port *port;	struct tty_struct *tty;	unsigned char count;			if (!(port = sx_get_port(bp, "Transmit")))		return;		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);		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);		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(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;		}		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);}extern inline void sx_check_modem(struct specialix_board * bp){	struct specialix_port *port;	struct tty_struct *tty;	unsigned char mcr;#ifdef SPECIALIX_DEBUG	printk (KERN_DEBUG "Modem intr. ");#endif	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)) {#ifdef SPECIALIX_DEBUG 		printk (KERN_DEBUG "CD just changed... ");#endif		if (sx_in(bp, CD186x_MSVR) & MSVR_CD) {#ifdef SPECIALIX_DEBUG			printk ( "Waking up guys in open.\n");#endif			wake_up_interruptible(&port->open_wait);		}		else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) &&		           (port->flags & ASYNC_CALLOUT_NOHUP))) {#ifdef SPECIALIX_DEBUG			printk ( "Sending HUP.\n");#endif			MOD_INC_USE_COUNT;			if (schedule_task(&port->tqueue_hangup) == 0)				MOD_DEC_USE_COUNT;		} else {#ifdef SPECIALIX_DEBUG			printk ( "Don't need to send HUP.\n");#endif		}	}	#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 void sx_interrupt(int irq, void * dev_id, struct pt_regs * regs){	unsigned char status;	unsigned char ack;	struct specialix_board *bp;	unsigned long loop = 0;	int saved_reg;	bp = dev_id;		if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) {#ifdef SPECIALIX_DEBUG 		printk (KERN_DEBUG "sx: False interrupt. irq %d.\n", irq);#endif		return;	}	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: Bad receive ack 0x%02x.\n",				       board_No(bp), 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: Bad transmit ack 0x%02x.\n",				       board_No(bp), ack);		} 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: Bad modem ack 0x%02x.\n",				       board_No(bp), ack);				} 		sx_out(bp, CD186x_EOIR, 0);   /* Mark end of interrupt */	}	bp->reg = saved_reg;	outb (bp->reg, bp->base + SX_ADDR_REG);}/* *  Routines for open & close processing. */void turn_ints_off (struct specialix_board *bp){	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. */	}	(void) sx_in_off (bp, 0); /* Turn off interrupts. */}void turn_ints_on (struct specialix_board *bp){	if (bp->flags & SX_BOARD_IS_PCI) {		/* play with the PCI chip. See comment above. */	}	(void) sx_in (bp, 0); /* Turn ON interrupts. */}/* Called with disabled interrupts */extern inline int sx_setup_board(struct specialix_board * bp){	int error;

⌨️ 快捷键说明

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