📄 w83977af_ir.c
字号:
} /* Set speed mode */ switch_bank(iobase, SET0); outb(ir_mode, iobase+HCR); /* set FIFO size to 32 */ switch_bank(iobase, SET2); outb(ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2); /* set FIFO threshold to TX17, RX16 */ switch_bank(iobase, SET0); outb(0x00, iobase+UFR); /* Reset */ outb(UFR_EN_FIFO, iobase+UFR); /* First we must enable FIFO */ outb(0xa7, iobase+UFR); netif_wake_queue(self->netdev); /* Enable some interrupts so we can receive frames */ switch_bank(iobase, SET0); if (speed > PIO_MAX_SPEED) { outb(ICR_EFSFI, iobase+ICR); w83977af_dma_receive(self); } else outb(ICR_ERBRI, iobase+ICR); /* Restore SSR */ outb(set, iobase+SSR);}/* * Function w83977af_hard_xmit (skb, dev) * * Sets up a DMA transfer to send the current frame. * */int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev){ struct w83977af_ir *self; __s32 speed; int iobase; __u8 set; int mtt; self = (struct w83977af_ir *) dev->priv; iobase = self->io.fir_base; IRDA_DEBUG(4, "%s(%ld), skb->len=%d\n", __FUNCTION__ , jiffies, (int) skb->len); /* Lock transmit buffer */ netif_stop_queue(dev); /* Check if we need to change the speed */ speed = irda_get_next_speed(skb); if ((speed != self->io.speed) && (speed != -1)) { /* Check for empty frame */ if (!skb->len) { w83977af_change_speed(self, speed); dev->trans_start = jiffies; dev_kfree_skb(skb); return 0; } else self->new_speed = speed; } /* Save current set */ set = inb(iobase+SSR); /* Decide if we should use PIO or DMA transfer */ if (self->io.speed > PIO_MAX_SPEED) { self->tx_buff.data = self->tx_buff.head; memcpy(self->tx_buff.data, skb->data, skb->len); self->tx_buff.len = skb->len; mtt = irda_get_mtt(skb);#ifdef CONFIG_USE_INTERNAL_TIMER if (mtt > 50) { /* Adjust for timer resolution */ mtt /= 1000+1; /* Setup timer */ switch_bank(iobase, SET4); outb(mtt & 0xff, iobase+TMRL); outb((mtt >> 8) & 0x0f, iobase+TMRH); /* Start timer */ outb(IR_MSL_EN_TMR, iobase+IR_MSL); self->io.direction = IO_XMIT; /* Enable timer interrupt */ switch_bank(iobase, SET0); outb(ICR_ETMRI, iobase+ICR); } else {#endif IRDA_DEBUG(4, "%s(%ld), mtt=%d\n", __FUNCTION__ , jiffies, mtt); if (mtt) udelay(mtt); /* Enable DMA interrupt */ switch_bank(iobase, SET0); outb(ICR_EDMAI, iobase+ICR); w83977af_dma_write(self, iobase);#ifdef CONFIG_USE_INTERNAL_TIMER }#endif } else { self->tx_buff.data = self->tx_buff.head; self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); /* Add interrupt on tx low level (will fire immediately) */ switch_bank(iobase, SET0); outb(ICR_ETXTHI, iobase+ICR); } dev->trans_start = jiffies; dev_kfree_skb(skb); /* Restore set register */ outb(set, iobase+SSR); return 0;}/* * Function w83977af_dma_write (self, iobase) * * Send frame using DMA * */static void w83977af_dma_write(struct w83977af_ir *self, int iobase){ __u8 set;#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS unsigned long flags; __u8 hcr;#endif IRDA_DEBUG(4, "%s(), len=%d\n", __FUNCTION__ , self->tx_buff.len); /* Save current set */ set = inb(iobase+SSR); /* Disable DMA */ switch_bank(iobase, SET0); outb(inb(iobase+HCR) & ~HCR_EN_DMA, iobase+HCR); /* Choose transmit DMA channel */ switch_bank(iobase, SET2); outb(ADCR1_D_CHSW|/*ADCR1_DMA_F|*/ADCR1_ADV_SL, iobase+ADCR1);#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS spin_lock_irqsave(&self->lock, flags); disable_dma(self->io.dma); clear_dma_ff(self->io.dma); set_dma_mode(self->io.dma, DMA_MODE_READ); set_dma_addr(self->io.dma, self->tx_buff_dma); set_dma_count(self->io.dma, self->tx_buff.len);#else irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len, DMA_MODE_WRITE); #endif self->io.direction = IO_XMIT; /* Enable DMA */ switch_bank(iobase, SET0);#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS hcr = inb(iobase+HCR); outb(hcr | HCR_EN_DMA, iobase+HCR); enable_dma(self->io.dma); spin_unlock_irqrestore(&self->lock, flags);#else outb(inb(iobase+HCR) | HCR_EN_DMA | HCR_TX_WT, iobase+HCR);#endif /* Restore set register */ outb(set, iobase+SSR);}/* * Function w83977af_pio_write (iobase, buf, len, fifo_size) * * * */static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size){ int actual = 0; __u8 set; IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); /* Save current bank */ set = inb(iobase+SSR); switch_bank(iobase, SET0); if (!(inb_p(iobase+USR) & USR_TSRE)) { IRDA_DEBUG(4, "%s(), warning, FIFO not empty yet!\n", __FUNCTION__ ); fifo_size -= 17; IRDA_DEBUG(4, "%s(), %d bytes left in tx fifo\n", __FUNCTION__ , fifo_size); } /* Fill FIFO with current frame */ while ((fifo_size-- > 0) && (actual < len)) { /* Transmit next byte */ outb(buf[actual++], iobase+TBR); } IRDA_DEBUG(4, "%s(), fifo_size %d ; %d sent of %d\n", __FUNCTION__ , fifo_size, actual, len); /* Restore bank */ outb(set, iobase+SSR); return actual;}/* * Function w83977af_dma_xmit_complete (self) * * The transfer of a frame in finished. So do the necessary things * * */static void w83977af_dma_xmit_complete(struct w83977af_ir *self){ int iobase; __u8 set; IRDA_DEBUG(4, "%s(%ld)\n", __FUNCTION__ , jiffies); IRDA_ASSERT(self != NULL, return;); iobase = self->io.fir_base; /* Save current set */ set = inb(iobase+SSR); /* Disable DMA */ switch_bank(iobase, SET0); outb(inb(iobase+HCR) & ~HCR_EN_DMA, iobase+HCR); /* Check for underrrun! */ if (inb(iobase+AUDR) & AUDR_UNDR) { IRDA_DEBUG(0, "%s(), Transmit underrun!\n", __FUNCTION__ ); self->stats.tx_errors++; self->stats.tx_fifo_errors++; /* Clear bit, by writing 1 to it */ outb(AUDR_UNDR, iobase+AUDR); } else self->stats.tx_packets++; if (self->new_speed) { w83977af_change_speed(self, self->new_speed); self->new_speed = 0; } /* Unlock tx_buff and request another frame */ /* Tell the network layer, that we want more frames */ netif_wake_queue(self->netdev); /* Restore set */ outb(set, iobase+SSR);}/* * Function w83977af_dma_receive (self) * * Get ready for receiving a frame. The device will initiate a DMA * if it starts to receive a frame. * */int w83977af_dma_receive(struct w83977af_ir *self) { int iobase; __u8 set;#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS unsigned long flags; __u8 hcr;#endif IRDA_ASSERT(self != NULL, return -1;); IRDA_DEBUG(4, "%s\n", __FUNCTION__ ); iobase= self->io.fir_base; /* Save current set */ set = inb(iobase+SSR); /* Disable DMA */ switch_bank(iobase, SET0); outb(inb(iobase+HCR) & ~HCR_EN_DMA, iobase+HCR); /* 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); self->io.direction = IO_RECV; self->rx_buff.data = self->rx_buff.head;#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS spin_lock_irqsave(&self->lock, flags); disable_dma(self->io.dma); clear_dma_ff(self->io.dma); set_dma_mode(self->io.dma, DMA_MODE_READ); set_dma_addr(self->io.dma, self->rx_buff_dma); set_dma_count(self->io.dma, self->rx_buff.truesize);#else irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize, DMA_MODE_READ);#endif /* * 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 */ switch_bank(iobase, SET0); outb(UFR_RXTL|UFR_TXTL|UFR_RXF_RST|UFR_EN_FIFO, iobase+UFR); self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0; /* Enable DMA */ switch_bank(iobase, SET0);#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS hcr = inb(iobase+HCR); outb(hcr | HCR_EN_DMA, iobase+HCR); enable_dma(self->io.dma); spin_unlock_irqrestore(&self->lock, flags);#else outb(inb(iobase+HCR) | HCR_EN_DMA, iobase+HCR);#endif /* Restore set */ outb(set, iobase+SSR); return 0;}/* * Function w83977af_receive_complete (self) * * Finished with receiving a frame * */int w83977af_dma_receive_complete(struct w83977af_ir *self){ struct sk_buff *skb; struct st_fifo *st_fifo; int len; int iobase; __u8 set; __u8 status; IRDA_DEBUG(4, "%s\n", __FUNCTION__ ); st_fifo = &self->st_fifo; iobase = self->io.fir_base; /* Save current set */ set = inb(iobase+SSR); iobase = self->io.fir_base; /* Read status FIFO */ switch_bank(iobase, SET5); while ((status = inb(iobase+FS_FO)) & FS_FO_FSFDR) { st_fifo->entries[st_fifo->tail].status = status; st_fifo->entries[st_fifo->tail].len = inb(iobase+RFLFL); st_fifo->entries[st_fifo->tail].len |= inb(iobase+RFLFH) << 8; st_fifo->tail++; st_fifo->len++; } while (st_fifo->len) { /* Get first entry */ status = st_fifo->entries[st_fifo->head].status; len = st_fifo->entries[st_fifo->head].len; st_fifo->head++; st_fifo->len--; /* Check for errors */ if (status & FS_FO_ERR_MSK) { if (status & FS_FO_LST_FR) { /* Add number of lost frames to stats */ self->stats.rx_errors += len; } else { /* Skip frame */ self->stats.rx_errors++; self->rx_buff.data += len; if (status & FS_FO_MX_LEX) self->stats.rx_length_errors++; if (status & FS_FO_PHY_ERR) self->stats.rx_frame_errors++; if (status & FS_FO_CRC_ERR) self->stats.rx_crc_errors++; } /* The errors below can be reported in both cases */ if (status & FS_FO_RX_OV) self->stats.rx_fifo_errors++; if (status & FS_FO_FSF_OV) self->stats.rx_fifo_errors++; } else { /* Check if we have transferred all data to memory */ switch_bank(iobase, SET0); if (inb(iobase+USR) & USR_RDR) {#ifdef CONFIG_USE_INTERNAL_TIMER /* Put this entry back in fifo */ st_fifo->head--; st_fifo->len++; st_fifo->entries[st_fifo->head].status = status; st_fifo->entries[st_fifo->head].len = len; /* Restore set register */ outb(set, iobase+SSR); return FALSE; /* I'll be back! */#else udelay(80); /* Should be enough!? */#endif } skb = dev_alloc_skb(len+1); if (skb == NULL) { printk(KERN_INFO "%s(), memory squeeze, dropping frame.\n", __FUNCTION__); /* Restore set register */ outb(set, iobase+SSR); return FALSE; } /* Align to 20 bytes */ skb_reserve(skb, 1); /* Copy frame without CRC */ if (self->io.speed < 4000000) { skb_put(skb, len-2); memcpy(skb->data, self->rx_buff.data, len-2); } else { skb_put(skb, len-4); memcpy(skb->data, self->rx_buff.data, len-4); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -