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

📄 w83977af_ir.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	outb(inb(iobase+HCR) & ~HCR_EN_DMA, iobase+HCR);		/* Check for underrrun! */	if (inb(iobase+AUDR) & AUDR_UNDR) {		DEBUG(0, __FUNCTION__ "(), Transmit underrun!\n");				idev->stats.tx_errors++;		idev->stats.tx_fifo_errors++;		/* Clear bit, by writing 1 to it */		outb(AUDR_UNDR, iobase+AUDR);	} else		idev->stats.tx_packets++;	/* Unlock tx_buff and request another frame */	idev->netdev.tbusy = 0; /* Unlock */	idev->media_busy = FALSE;		/* Tell the network layer, that we want more frames */	mark_bh(NET_BH);	/* Restore set */	outb(set, iobase+SSR);}/* * Function w83977af_dma_receive (idev) * *    Get ready for receiving a frame. The device will initiate a DMA *    if it starts to receive a frame. * */int w83977af_dma_receive(struct irda_device *idev) {	int iobase;	__u8 set;#ifdef NETWINDER	unsigned long flags;	__u8 hcr;#endif	ASSERT(idev != NULL, return -1;);	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);	DEBUG(0, __FUNCTION__ "\n");	iobase= idev->io.iobase;	/* Save current set */	set = inb( iobase+SSR);	/* Disable DMA */	switch_bank( iobase, SET0);	outb( inb( iobase+HCR) & ~HCR_EN_DMA, iobase+HCR);#ifdef NETWINDER	save_flags(flags);	cli();	disable_dma( idev->io.dma);	clear_dma_ff( idev->io.dma);	set_dma_mode( idev->io.dma, DMA_MODE_READ);	set_dma_addr( idev->io.dma, virt_to_bus(idev->rx_buff.data));	set_dma_count( idev->io.dma, idev->rx_buff.truesize);#else	setup_dma(idev->io.dma, idev->rx_buff.data, 		  idev->rx_buff.truesize, DMA_MODE_READ);#endif	/* driver->media_busy = FALSE; */	idev->io.direction = IO_RECV;	idev->rx_buff.head = idev->rx_buff.data;	idev->rx_buff.offset = 0;	/* 	 * Reset Rx FIFO. This will also flush the ST_FIFO, it's very 	 * important that we don't reset the Tx FIFO since it might not	 * be finished transmitting yet	 */	outb( UFR_RXTL|UFR_TXTL|UFR_RXF_RST|UFR_EN_FIFO, iobase+UFR);	prev.status = 0;	/* Choose DMA Rx, DMA Fairness, and Advanced mode */	switch_bank(iobase, SET2);	outb(( inb( iobase+ADCR1) & ~ADCR1_D_CHSW)|ADCR1_DMA_F|ADCR1_ADV_SL,	     iobase+ADCR1);		/* Enable DMA */	switch_bank(iobase, SET0);#ifdef NETWINDER	hcr = inb( iobase+HCR);	enable_dma( idev->io.dma);	outb( hcr | HCR_EN_DMA, iobase+HCR);	restore_flags(flags);#else		outb( inb( iobase+HCR) | HCR_EN_DMA, iobase+HCR);#endif		/* Restore set */	outb( set, iobase+SSR);	DEBUG( 4, __FUNCTION__ "(), done!\n");		return 0;}/* * Function w83977af_receive_complete (idev) * *    Finished with receiving a frame * */int w83977af_dma_receive_complete(struct irda_device *idev){	struct sk_buff *skb;	int len;	int iobase;	__u8 set;	__u8 status;	DEBUG( 0, __FUNCTION__ "\n");	iobase = idev->io.iobase;	/* Save current set */	set = inb( iobase+SSR);		iobase = idev->io.iobase;	switch_bank(iobase, SET5);	if ( prev.status & FS_FO_FSFDR) {		status = prev.status;		len = prev.len;		prev.status = 0;	} else {		status = inb( iobase+FS_FO);		len = inb( iobase+RFLFL);		len |= inb( iobase+RFLFH) << 8;	}	while ( status & FS_FO_FSFDR) {		/* Check for errors */		if ( status & FS_FO_ERR_MSK) {			if ( status & FS_FO_LST_FR) {				/* Add number of lost frames to stats */				idev->stats.rx_errors += len;				} else {				/* Skip frame */				idev->stats.rx_errors++;								idev->rx_buff.offset += len;				idev->rx_buff.head   += len;								if ( status & FS_FO_MX_LEX)					idev->stats.rx_length_errors++;								if ( status & FS_FO_PHY_ERR) 					idev->stats.rx_frame_errors++;								if ( status & FS_FO_CRC_ERR) 					idev->stats.rx_crc_errors++;			}			/* The errors below can be reported in both cases */			if ( status & FS_FO_RX_OV)				idev->stats.rx_fifo_errors++;						if ( status & FS_FO_FSF_OV)				idev->stats.rx_fifo_errors++;					} else {			/* Check if we have transfered all data to memory */			switch_bank(iobase, SET0);			if ( inb( iobase+USR) & USR_RDR) {				/* Put this entry back in fifo */				prev.status = status;				prev.len = len;				/* Restore set register */				outb( set, iobase+SSR);							return FALSE; 	/* I'll be back! */			}									skb = dev_alloc_skb( len+1);			if (skb == NULL)  {				printk( KERN_INFO __FUNCTION__ 					"(), memory squeeze, dropping frame.\n");				/* Restore set register */				outb( set, iobase+SSR);				return FALSE;			}						/*  Align to 20 bytes */			skb_reserve( skb, 1); 						/* Copy frame without CRC */			if ( idev->io.baudrate < 4000000) {				skb_put( skb, len-2);				memcpy( skb->data, idev->rx_buff.head, len-2);			} else {				skb_put( skb, len-4);				memcpy( skb->data, idev->rx_buff.head, len-4);			}			/* Move to next frame */			idev->rx_buff.offset += len;			idev->rx_buff.head += len;						skb->dev = &idev->netdev;			skb->mac.raw  = skb->data;			skb->protocol = htons(ETH_P_IRDA);			netif_rx( skb);			idev->stats.rx_packets++;		}		/* Read next entry in ST_FIFO */		switch_bank(iobase, SET5);		status = inb( iobase+FS_FO);		len = inb( iobase+RFLFL);		len |= inb( iobase+RFLFH) << 8;	}	/* Restore set register */	outb( set, iobase+SSR);	return TRUE;}/* * Function pc87108_pio_receive (idev) * *    Receive all data in receiver FIFO * */static void w83977af_pio_receive( struct irda_device *idev) {	__u8 byte = 0x00;	int iobase;	DEBUG( 4, __FUNCTION__ "()\n");	ASSERT( idev != NULL, return;);	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);		iobase = idev->io.iobase;		if ( idev->rx_buff.len == 0) {		idev->rx_buff.head = idev->rx_buff.data;	}	/*  Receive all characters in Rx FIFO */	do {		byte = inb( iobase+RBR);		async_unwrap_char( idev, byte);	} while ( inb( iobase+USR) & USR_RDR); /* Data available */	}/* * Function w83977af_sir_interrupt (idev, eir) * *    Handle SIR interrupt * */static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr){	int len;	int actual;	__u8 new_icr = 0;	DEBUG(4, __FUNCTION__ "(), isr=%#x\n", isr);		/* Transmit FIFO low on data */	if (isr & ISR_TXTH_I) {		/* Write data left in transmit buffer */		len = idev->tx_buff.len - idev->tx_buff.offset;		ASSERT(len > 0, return 0;);		actual = w83977af_pio_write(idev->io.iobase, 					    idev->tx_buff.head, 					    len, idev->io.fifo_size);		idev->tx_buff.offset += actual;		idev->tx_buff.head += actual;				idev->io.direction = IO_XMIT;		ASSERT( actual <= len, return 0;);		/* Check if finished */		if ( actual == len) { 			DEBUG( 4, __FUNCTION__ "(), finished with frame!\n");			idev->netdev.tbusy = 0; /* Unlock */			idev->stats.tx_packets++;			/* Schedule network layer */		        mark_bh(NET_BH);				new_icr |= ICR_ETBREI;		} else			new_icr |= ICR_ETXTHI;	}	/* Check if transmission has completed */	if (isr & ISR_TXEMP_I) {				/* Turn around and get ready to receive some data */		idev->io.direction = IO_RECV;		new_icr |= ICR_ERBRI;	}	/* Rx FIFO threshold or timeout */	if (isr & ISR_RXTH_I) {		w83977af_pio_receive(idev);		/* Keep receiving */		new_icr |= ICR_ERBRI;	}	return new_icr;}/* * Function pc87108_fir_interrupt (idev, eir) * *    Handle MIR/FIR interrupt * */static __u8 w83977af_fir_interrupt( struct irda_device *idev, int isr){	__u8 new_icr = 0;	__u8 set;	int iobase;	DEBUG( 4, __FUNCTION__ "(), isr=%#x\n", isr);	iobase = idev->io.iobase;	set = inb(iobase+SSR);		/* End of frame detected in FIFO */	if (isr & (ISR_FEND_I|ISR_FSF_I)) {		if (w83977af_dma_receive_complete(idev)) {						new_icr |= ICR_EFSFI;		} else {			/* DMA not finished yet */			/* Set timer value, resolution 1 ms */			switch_bank(iobase, SET4);			outb(0x01, iobase+TMRL); /* 1 ms */			outb(0x00, iobase+TMRH);			/* Start timer */			outb(IR_MSL_EN_TMR, iobase+IR_MSL);			new_icr |= ICR_ETMRI;		}	}	/* Timer finished */	if (isr & ISR_TMR_I) {		/* Disable timer */		switch_bank(iobase, SET4);		outb(0, iobase+IR_MSL);		/* Clear timer event */		/* switch_bank(iobase, SET0); *//* 		outb( ASCR_CTE, iobase+ASCR); */		/* Check if this is a TX timer interrupt */		if (idev->io.direction == IO_XMIT) {			w83977af_dma_write(idev, iobase);			new_icr |= ICR_EDMAI;		} else {			/* Check if DMA has now finished */			w83977af_dma_receive_complete(idev);			new_icr |= ICR_EFSFI;		}	}		/* Finished with DMA */	if (isr & ISR_DMA_I) {		w83977af_dma_xmit_complete( idev);				/* Check if there are more frames to be transmitted */		if (irda_device_txqueue_empty( idev)) {					/* Prepare for receive */			w83977af_dma_receive(idev);			new_icr = ICR_EFSFI;		}	}		/* Restore set */	outb(set, iobase+SSR);	return new_icr;}/* * Function pc87108_interrupt (irq, dev_id, regs) * *    An interrupt from the chip has arrived. Time to do some work * */static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs){	__u8 set, icr, isr;	int iobase;	struct irda_device *idev = (struct irda_device *) dev_id;	if (idev == NULL) {		printk(KERN_WARNING "%s: irq %d for unknown device.\n", 		       driver_name, irq);		return;	}	idev->netdev.interrupt = 1;	iobase = idev->io.iobase;	/* Save current bank */	set = inb(iobase+SSR);	switch_bank(iobase, SET0);		icr = inb(iobase+ICR); 	isr = inb(iobase+ISR) & icr; /* Mask out the interesting ones */ 	outb(0, iobase+ICR); /* Disable interrupts */		if (isr) {		/* Dispatch interrupt handler for the current speed */		if ( idev->io.baudrate > 115200)			icr = w83977af_fir_interrupt(idev, isr);		else			icr = w83977af_sir_interrupt(idev, isr);	}	outb(icr, iobase+ICR);    /* Restore (new) interrupts */	outb(set, iobase+SSR);    /* Restore bank register */	idev->netdev.interrupt = 0;}/* * Function w83977af_wait_until_sent (idev) * *    This function should put the current thread to sleep until all data  *    have been sent, so it is safe to f.eks. change the speed. */static void w83977af_wait_until_sent(struct irda_device *idev){	current->state = TASK_INTERRUPTIBLE;	schedule_timeout(6);}/* * Function w83977af_is_receiving (idev) * *    Return TRUE is we are currently receiving a frame * */static int w83977af_is_receiving(struct irda_device *idev){	int status = FALSE;	int iobase;	__u8 set;	ASSERT( idev != NULL, return FALSE;);	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return FALSE;);	if ( idev->io.baudrate > 115200) {		iobase = idev->io.iobase;		/* Check if rx FIFO is not empty */		set = inb(iobase+SSR);		switch_bank( iobase, SET2);		if (( inb( iobase+RXFDTH) & 0x3f) != 0) {			/* We are receiving something */			status =  TRUE;		}		outb(set, iobase+SSR);	} else 		status = (idev->rx_buff.state != OUTSIDE_FRAME);		return status;}/* * Function w83977af_net_init (dev) * *     * */static int w83977af_net_init( struct device *dev){	DEBUG(0, __FUNCTION__ "()\n");	/* Set up to be a normal IrDA network device driver */	irda_device_setup( dev);	/* Insert overrides below this line! */	return 0;}/* * Function w83977af_net_open (dev) * *    Start the device * */static int w83977af_net_open( struct device *dev){	struct irda_device *idev;	int iobase;	__u8 set;		DEBUG(0, __FUNCTION__ "()\n");		ASSERT(dev != NULL, return -1;);	idev = (struct irda_device *) dev->priv;		ASSERT(idev != NULL, return 0;);	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;);		iobase = idev->io.iobase;	if (request_irq(idev->io.irq, w83977af_interrupt, 0, idev->name, 			(void *) idev)) {		return -EAGAIN;	}	/*	 * Always allocate the DMA channel after the IRQ,	 * and clean up on failure.	 */	if (request_dma(idev->io.dma, idev->name)) {		free_irq(idev->io.irq, idev);		return -EAGAIN;	}			/* Ready to play! */	dev->tbusy = 0;	dev->interrupt = 0;	dev->start = 1;	/* Save current set */	set = inb(iobase+SSR); 	/* Enable some interrupts so we can receive frames again */ 	switch_bank(iobase, SET0); 	if (idev->io.baudrate > 115200) { 		outb( ICR_EFSFI, iobase+ICR); 		w83977af_dma_receive( idev); 	} else 		outb( ICR_ERBRI, iobase+ICR);	/* Restore bank register */	outb( set, iobase+SSR);	MOD_INC_USE_COUNT;	return 0;}/* * Function w83977af_net_close (dev) * *    Stop the device * */static int w83977af_net_close(struct device *dev){	struct irda_device *idev;	int iobase;	__u8 set;	DEBUG( 0, __FUNCTION__ "()\n");		/* Stop device */	dev->tbusy = 1;	dev->start = 0;	ASSERT( dev != NULL, return -1;);	idev = (struct irda_device *) dev->priv;		ASSERT( idev != NULL, return 0;);	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);		iobase = idev->io.iobase;	disable_dma( idev->io.dma);	/* Save current set */	set = inb( iobase+SSR);		/* Disable interrupts */	switch_bank( iobase, SET0);	outb( 0, iobase+ICR); 	free_irq( idev->io.irq, idev);	free_dma( idev->io.dma);	/* Restore bank register */	outb( set, iobase+SSR);	MOD_DEC_USE_COUNT;	return 0;}#ifdef MODULE/* * Function init_module (void) * *     * */int init_module(void){	return w83977af_init();}/* * Function cleanup_module (void) * *     * */void cleanup_module(void){	w83977af_cleanup();}#endif /* MODULE */

⌨️ 快捷键说明

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