📄 via-ircc.c
字号:
// Move to next frame self->rx_buff.data += len; self->stats.rx_bytes += len; self->stats.rx_packets++; skb->dev = self->netdev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); return TRUE; } else { //FIR mode len = GetRecvByte(iobase, self); if (len == 0) return TRUE; //interrupt only, data maybe move by RxT if (((len - 4) < 2) || ((len - 4) > 2048)) { IRDA_DEBUG(1, "%s(): Trouble:len=%x,CurCount=%x,LastCount=%x..\n", __FUNCTION__, len, RxCurCount(iobase, self), self->RxLastCount); hwreset(self); return FALSE; } IRDA_DEBUG(2, "%s(): fifo.len=%x,len=%x,CurCount=%x..\n", __FUNCTION__, st_fifo->len, len - 4, RxCurCount(iobase, self)); st_fifo->entries[st_fifo->tail].status = status; st_fifo->entries[st_fifo->tail].len = len; st_fifo->pending_bytes += len; st_fifo->tail++; st_fifo->len++; if (st_fifo->tail > MAX_RX_WINDOW) st_fifo->tail = 0; self->RxDataReady = 0; // It maybe have MAX_RX_WINDOW package receive by // receive_complete before Timer IRQ/* F01_S if (st_fifo->len < (MAX_RX_WINDOW+2 )) { RXStart(iobase,ON); SetTimer(iobase,4); } else { F01_E */ EnableRX(iobase, OFF); EnRXDMA(iobase, OFF); RXStart(iobase, OFF);//F01_S // Put this entry back in fifo if (st_fifo->head > MAX_RX_WINDOW) st_fifo->head = 0; status = st_fifo->entries[st_fifo->head].status; len = st_fifo->entries[st_fifo->head].len; st_fifo->head++; st_fifo->len--; skb = dev_alloc_skb(len + 1 - 4); /* * if frame size,data ptr,or skb ptr are wrong ,the get next * entry. */ if ((skb == NULL) || (skb->data == NULL) || (self->rx_buff.data == NULL) || (len < 6)) { self->stats.rx_dropped++; return TRUE; } skb_reserve(skb, 1); skb_put(skb, len - 4); memcpy(skb->data, self->rx_buff.data, len - 4); IRDA_DEBUG(2, "%s(): len=%x.rx_buff=%p\n", __FUNCTION__, len - 4, self->rx_buff.data); // Move to next frame self->rx_buff.data += len; self->stats.rx_bytes += len; self->stats.rx_packets++; skb->dev = self->netdev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb);//F01_E } //FIR return TRUE;}/* * if frame is received , but no INT ,then use this routine to upload frame. */static int upload_rxdata(struct via_ircc_cb *self, int iobase){ struct sk_buff *skb; int len; struct st_fifo *st_fifo; st_fifo = &self->st_fifo; len = GetRecvByte(iobase, self); IRDA_DEBUG(2, "%s(): len=%x\n", __FUNCTION__, len); if ((len - 4) < 2) { self->stats.rx_dropped++; return FALSE; } skb = dev_alloc_skb(len + 1); if (skb == NULL) { self->stats.rx_dropped++; return FALSE; } skb_reserve(skb, 1); skb_put(skb, len - 4 + 1); memcpy(skb->data, self->rx_buff.data, len - 4 + 1); st_fifo->tail++; st_fifo->len++; if (st_fifo->tail > MAX_RX_WINDOW) st_fifo->tail = 0; // Move to next frame self->rx_buff.data += len; self->stats.rx_bytes += len; self->stats.rx_packets++; skb->dev = self->netdev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); if (st_fifo->len < (MAX_RX_WINDOW + 2)) { RXStart(iobase, ON); } else { EnableRX(iobase, OFF); EnRXDMA(iobase, OFF); RXStart(iobase, OFF); } return TRUE;}/* * Implement back to back receive , use this routine to upload data. */static int RxTimerHandler(struct via_ircc_cb *self, int iobase){ struct st_fifo *st_fifo; struct sk_buff *skb; int len; u8 status; st_fifo = &self->st_fifo; if (CkRxRecv(iobase, self)) { // if still receiving ,then return ,don't upload frame self->RetryCount = 0; SetTimer(iobase, 20); self->RxDataReady++; return FALSE; } else self->RetryCount++; if ((self->RetryCount >= 1) || ((st_fifo->pending_bytes + 2048) > self->rx_buff.truesize) || (st_fifo->len >= (MAX_RX_WINDOW))) { while (st_fifo->len > 0) { //upload frame // Put this entry back in fifo if (st_fifo->head > MAX_RX_WINDOW) st_fifo->head = 0; status = st_fifo->entries[st_fifo->head].status; len = st_fifo->entries[st_fifo->head].len; st_fifo->head++; st_fifo->len--; skb = dev_alloc_skb(len + 1 - 4); /* * if frame size, data ptr, or skb ptr are wrong, * then get next entry. */ if ((skb == NULL) || (skb->data == NULL) || (self->rx_buff.data == NULL) || (len < 6)) { self->stats.rx_dropped++; continue; } skb_reserve(skb, 1); skb_put(skb, len - 4); memcpy(skb->data, self->rx_buff.data, len - 4); IRDA_DEBUG(2, "%s(): len=%x.head=%x\n", __FUNCTION__, len - 4, st_fifo->head); // Move to next frame self->rx_buff.data += len; self->stats.rx_bytes += len; self->stats.rx_packets++; skb->dev = self->netdev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); } //while self->RetryCount = 0; IRDA_DEBUG(2, "%s(): End of upload HostStatus=%x,RxStatus=%x\n", __FUNCTION__, GetHostStatus(iobase), GetRXStatus(iobase)); /* * if frame is receive complete at this routine ,then upload * frame. */ if ((GetRXStatus(iobase) & 0x10) && (RxCurCount(iobase, self) != self->RxLastCount)) { upload_rxdata(self, iobase); if (irda_device_txqueue_empty(self->netdev)) via_ircc_dma_receive(self); } } // timer detect complete else SetTimer(iobase, 4); return TRUE;}/* * Function via_ircc_interrupt (irq, dev_id) * * An interrupt from the chip has arrived. Time to do some work * */static irqreturn_t via_ircc_interrupt(int irq, void *dev_id){ struct net_device *dev = (struct net_device *) dev_id; struct via_ircc_cb *self; int iobase; u8 iHostIntType, iRxIntType, iTxIntType; if (!dev) { IRDA_WARNING("%s: irq %d for unknown device.\n", driver_name, irq); return IRQ_NONE; } self = (struct via_ircc_cb *) dev->priv; iobase = self->io.fir_base; spin_lock(&self->lock); iHostIntType = GetHostStatus(iobase); IRDA_DEBUG(4, "%s(): iHostIntType %02x: %s %s %s %02x\n", __FUNCTION__, iHostIntType, (iHostIntType & 0x40) ? "Timer" : "", (iHostIntType & 0x20) ? "Tx" : "", (iHostIntType & 0x10) ? "Rx" : "", (iHostIntType & 0x0e) >> 1); if ((iHostIntType & 0x40) != 0) { //Timer Event self->EventFlag.TimeOut++; ClearTimerInt(iobase, 1); if (self->io.direction == IO_XMIT) { via_ircc_dma_xmit(self, iobase); } if (self->io.direction == IO_RECV) { /* * frame ready hold too long, must reset. */ if (self->RxDataReady > 30) { hwreset(self); if (irda_device_txqueue_empty(self->netdev)) { via_ircc_dma_receive(self); } } else { // call this to upload frame. RxTimerHandler(self, iobase); } } //RECV } //Timer Event if ((iHostIntType & 0x20) != 0) { //Tx Event iTxIntType = GetTXStatus(iobase); IRDA_DEBUG(4, "%s(): iTxIntType %02x: %s %s %s %s\n", __FUNCTION__, iTxIntType, (iTxIntType & 0x08) ? "FIFO underr." : "", (iTxIntType & 0x04) ? "EOM" : "", (iTxIntType & 0x02) ? "FIFO ready" : "", (iTxIntType & 0x01) ? "Early EOM" : ""); if (iTxIntType & 0x4) { self->EventFlag.EOMessage++; // read and will auto clean if (via_ircc_dma_xmit_complete(self)) { if (irda_device_txqueue_empty (self->netdev)) { via_ircc_dma_receive(self); } } else { self->EventFlag.Unknown++; } } //EOP } //Tx Event //---------------------------------------- if ((iHostIntType & 0x10) != 0) { //Rx Event /* Check if DMA has finished */ iRxIntType = GetRXStatus(iobase); IRDA_DEBUG(4, "%s(): iRxIntType %02x: %s %s %s %s %s %s %s\n", __FUNCTION__, iRxIntType, (iRxIntType & 0x80) ? "PHY err." : "", (iRxIntType & 0x40) ? "CRC err" : "", (iRxIntType & 0x20) ? "FIFO overr." : "", (iRxIntType & 0x10) ? "EOF" : "", (iRxIntType & 0x08) ? "RxData" : "", (iRxIntType & 0x02) ? "RxMaxLen" : "", (iRxIntType & 0x01) ? "SIR bad" : ""); if (!iRxIntType) IRDA_DEBUG(3, "%s(): RxIRQ =0\n", __FUNCTION__); if (iRxIntType & 0x10) { if (via_ircc_dma_receive_complete(self, iobase)) {//F01 if(!(IsFIROn(iobase))) via_ircc_dma_receive(self); via_ircc_dma_receive(self); } } // No ERR else { //ERR IRDA_DEBUG(4, "%s(): RxIRQ ERR:iRxIntType=%x,HostIntType=%x,CurCount=%x,RxLastCount=%x_____\n", __FUNCTION__, iRxIntType, iHostIntType, RxCurCount(iobase, self), self->RxLastCount); if (iRxIntType & 0x20) { //FIFO OverRun ERR ResetChip(iobase, 0); ResetChip(iobase, 1); } else { //PHY,CRC ERR if (iRxIntType != 0x08) hwreset(self); //F01 } via_ircc_dma_receive(self); } //ERR } //Rx Event spin_unlock(&self->lock); return IRQ_RETVAL(iHostIntType);}static void hwreset(struct via_ircc_cb *self){ int iobase; iobase = self->io.fir_base; IRDA_DEBUG(3, "%s()\n", __FUNCTION__); ResetChip(iobase, 5); EnableDMA(iobase, OFF); EnableTX(iobase, OFF); EnableRX(iobase, OFF); EnRXDMA(iobase, OFF); EnTXDMA(iobase, OFF); RXStart(iobase, OFF); TXStart(iobase, OFF); InitCard(iobase); CommonInit(iobase); SIRFilter(iobase, ON); SetSIR(iobase, ON); CRC16(iobase, ON); EnTXCRC(iobase, 0); WriteReg(iobase, I_ST_CT_0, 0x00); SetBaudRate(iobase, 9600); SetPulseWidth(iobase, 12); SetSendPreambleCount(iobase, 0); WriteReg(iobase, I_ST_CT_0, 0x80); /* Restore speed. */ via_ircc_change_speed(self, self->io.speed); self->st_fifo.len = 0;}/* * Function via_ircc_is_receiving (self) * * Return TRUE is we are currently receiving a frame * */static int via_ircc_is_receiving(struct via_ircc_cb *self){ int status = FALSE; int iobase; IRDA_ASSERT(self != NULL, return FALSE;); iobase = self->io.fir_base; if (CkRxRecv(iobase, self)) status = TRUE; IRDA_DEBUG(2, "%s(): status=%x....\n", __FUNCTION__, status); return status;}/* * Function via_ircc_net_open (dev) * * Start the device * */static int via_ircc_net_open(struct net_device *dev){ struct via_ircc_cb *self; int iobase; char hwname[32]; IRDA_DEBUG(3, "%s()\n", __FUNCTION__); IRDA_ASSERT(dev != NULL, return -1;); self = (struct via_ircc_cb *) dev->priv; self->stats.rx_packets = 0; IRDA_ASSERT(self != NULL, return 0;); iobase = self->io.fir_base; if (request_irq(self->io.irq, via_ircc_interrupt, 0, dev->name, dev)) { IRDA_WARNING("%s, unable to allocate irq=%d\n", driver_name, self->io.irq); return -EAGAIN; } /* * Always allocate the DMA channel after the IRQ, and clean up on * failure. */ if (request_dma(self->io.dma, dev->name)) { IRDA_WARNING("%s, unable to allocate dma=%d\n", driver_name, self->io.dma); free_irq(self->io.irq, self); return -EAGAIN; } if (self->io.dma2 != self->io.dma) { if (request_dma(self->io.dma2, dev->name)) { IRDA_WARNING("%s, unable to allocate dma2=%d\n", driver_name, self->io.dma2); free_irq(self->io.irq, self); return -EAGAIN; } } /* turn on interrupts */ EnAllInt(iobase, ON); EnInternalLoop(iobase, OFF); EnExternalLoop(iobase, OFF); /* */ via_ircc_dma_receive(self); /* Ready to play! */ netif_start_queue(dev); /* * Open new IrLAP layer instance, now that everything should be * initialized properly */ sprintf(hwname, "VIA @ 0x%x", iobase); self->irlap = irlap_open(dev, &self->qos, hwname); self->RxLastCount = 0; return 0;}/* * Function via_ircc_net_close (dev) * * Stop the device * */static int via_ircc_net_close(struct net_device *dev){ struct via_ircc_cb *self; int iobase; IRDA_DEBUG(3, "%s()\n", __FUNCTION__); IRDA_ASSERT(dev != NULL, return -1;); self = (struct via_ircc_cb *) dev->priv; IRDA_ASSERT(self != NULL, return 0;); /* Stop device */ netif_stop_queue(dev); /* Stop and remove instance of IrLAP */ if (self->irlap) irlap_close(self->irlap); self->irlap = NULL; iobase = self->io.fir_base; EnTXDMA(iobase, OFF); EnRXDMA(iobase, OFF); DisableDmaChannel(self->io.dma); /* Disable interrupts */ EnAllInt(iobase, OFF); free_irq(self->io.irq, dev); free_dma(self->io.dma); return 0;}/* * Function via_ircc_net_ioctl (dev, rq, cmd) * * Process IOCTL commands for this device * */static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct if_irda_req *irq = (struct if_irda_req *) rq; struct via_ircc_cb *self; unsigned long flags; int ret = 0; IRDA_ASSERT(dev != NULL, return -1;); self = dev->priv; IRDA_ASSERT(self != NULL, return -1;); IRDA_DEBUG(1, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); /* Disable interrupts & save flags */ spin_lock_irqsave(&self->lock, flags); switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ if (!capable(CAP_NET_ADMIN)) { ret = -EPERM; goto out; } via_ircc_change_speed(self, irq->ifr_baudrate); break; case SIOCSMEDIABUSY: /* Set media busy */ if (!capable(CAP_NET_ADMIN)) { ret = -EPERM; goto out; } irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ irq->ifr_receiving = via_ircc_is_receiving(self); break; default: ret = -EOPNOTSUPP; } out: spin_unlock_irqrestore(&self->lock, flags); return ret;}static struct net_device_stats *via_ircc_net_get_stats(struct net_device *dev){ struct via_ircc_cb *self = (struct via_ircc_cb *) dev->priv; return &self->stats;}MODULE_AUTHOR("VIA Technologies,inc");MODULE_DESCRIPTION("VIA IrDA Device Driver");MODULE_LICENSE("GPL");module_init(via_ircc_init);module_exit(via_ircc_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -