📄 smsc-ircc2.c
字号:
self->io.fir_base+IRCC_SCE_CFGB); /* Check for underrun! */ register_bank(iobase, 0); if (inb(iobase+IRCC_LSR) & IRCC_LSR_UNDERRUN) { self->stats.tx_errors++; self->stats.tx_fifo_errors++; /* Reset error condition */ register_bank(iobase, 0); outb(IRCC_MASTER_ERROR_RESET, iobase+IRCC_MASTER); outb(0x00, iobase+IRCC_MASTER); } else { self->stats.tx_packets++; self->stats.tx_bytes += self->tx_buff.len; } /* Check if it's time to change the speed */ if (self->new_speed) { smsc_ircc_change_speed(self, self->new_speed); self->new_speed = 0; } netif_wake_queue(self->netdev);}/* * Function smsc_ircc_dma_receive(self) * * Get ready for receiving a frame. The device will initiate a DMA * if it starts to receive a frame. * */static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase) {#if 0 /* Turn off chip DMA */ register_bank(iobase, 1); outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, iobase+IRCC_SCE_CFGB);#endif /* Disable Tx */ register_bank(iobase, 0); outb(0x00, iobase+IRCC_LCR_B); /* Turn off chip DMA */ register_bank(iobase, 1); outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, iobase+IRCC_SCE_CFGB); self->io.direction = IO_RECV; self->rx_buff.data = self->rx_buff.head; /* Set max Rx frame size */ register_bank(iobase, 4); outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI); outb(2050 & 0xff, iobase+IRCC_RX_SIZE_LO); /* Setup DMA controller */ irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize, DMA_RX_MODE); /* Enable burst mode chip Rx DMA */ register_bank(iobase, 1); outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB); /* Enable interrupt */ register_bank(iobase, 0); outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER); outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER); /* Enable receiver */ register_bank(iobase, 0); outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B); return 0;}/* * Function smsc_ircc_dma_receive_complete(self, iobase) * * Finished with receiving frames * */static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase){ struct sk_buff *skb; int len, msgcnt, lsr; register_bank(iobase, 0); IRDA_DEBUG(3, "%s\n", __FUNCTION__);#if 0 /* Disable Rx */ register_bank(iobase, 0); outb(0x00, iobase+IRCC_LCR_B);#endif register_bank(iobase, 0); outb(inb(iobase+IRCC_LSAR) & ~IRCC_LSAR_ADDRESS_MASK, iobase+IRCC_LSAR); lsr= inb(iobase+IRCC_LSR); msgcnt = inb(iobase+IRCC_LCR_B) & 0x08; IRDA_DEBUG(2, "%s: dma count = %d\n", __FUNCTION__, get_dma_residue(self->io.dma)); len = self->rx_buff.truesize - get_dma_residue(self->io.dma); /* Look for errors */ if(lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) { self->stats.rx_errors++; if(lsr & IRCC_LSR_FRAME_ERROR) self->stats.rx_frame_errors++; if(lsr & IRCC_LSR_CRC_ERROR) self->stats.rx_crc_errors++; if(lsr & IRCC_LSR_SIZE_ERROR) self->stats.rx_length_errors++; if(lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN)) self->stats.rx_length_errors++; return; } /* Remove CRC */ if (self->io.speed < 4000000) len -= 2; else len -= 4; if ((len < 2) || (len > 2050)) { WARNING("%s(), bogus len=%d\n", __FUNCTION__, len); return; } IRDA_DEBUG(2, "%s: msgcnt = %d, len=%d\n", __FUNCTION__, msgcnt, len); skb = dev_alloc_skb(len+1); if (!skb) { WARNING("%s(), memory squeeze, dropping frame.\n", __FUNCTION__); return; } /* Make sure IP header gets aligned */ skb_reserve(skb, 1); memcpy(skb_put(skb, len), self->rx_buff.data, len); self->stats.rx_packets++; self->stats.rx_bytes += len; skb->dev = self->netdev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb);}/* * Function smsc_ircc_sir_receive (self) * * Receive one frame from the infrared port * */static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self) { int boguscount = 0; int iobase; ASSERT(self != NULL, return;); iobase = self->io.sir_base; /* * Receive all characters in Rx FIFO, unwrap and unstuff them. * async_unwrap_char will deliver all found frames */ do { async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, inb(iobase+UART_RX)); /* Make sure we don't stay here to long */ if (boguscount++ > 32) { IRDA_DEBUG(2, "%s(), breaking!\n", __FUNCTION__); break; } } while (inb(iobase+UART_LSR) & UART_LSR_DR); }/* * Function smsc_ircc_interrupt (irq, dev_id, regs) * * An interrupt from the chip has arrived. Time to do some work * */static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *) dev_id; struct smsc_ircc_cb *self; int iobase, iir, lcra, lsr; irqreturn_t ret = IRQ_NONE; if (dev == NULL) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", driver_name, irq); goto irq_ret; } self = (struct smsc_ircc_cb *) dev->priv; ASSERT(self != NULL, return IRQ_NONE;); /* Serialise the interrupt handler in various CPUs, stop Tx path */ spin_lock(&self->lock); /* Check if we should use the SIR interrupt handler */ if (self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED) { ret = smsc_ircc_interrupt_sir(dev); goto irq_ret_unlock; } iobase = self->io.fir_base; register_bank(iobase, 0); iir = inb(iobase+IRCC_IIR); if (iir == 0) goto irq_ret_unlock; ret = IRQ_HANDLED; /* Disable interrupts */ outb(0, iobase+IRCC_IER); lcra = inb(iobase+IRCC_LCR_A); lsr = inb(iobase+IRCC_LSR); IRDA_DEBUG(2, "%s(), iir = 0x%02x\n", __FUNCTION__, iir); if (iir & IRCC_IIR_EOM) { if (self->io.direction == IO_RECV) smsc_ircc_dma_receive_complete(self, iobase); else smsc_ircc_dma_xmit_complete(self, iobase); smsc_ircc_dma_receive(self, iobase); } if (iir & IRCC_IIR_ACTIVE_FRAME) { /*printk(KERN_WARNING "%s(): Active Frame\n", __FUNCTION__);*/ } /* Enable interrupts again */ register_bank(iobase, 0); outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER); irq_ret_unlock: spin_unlock(&self->lock); irq_ret: return ret;}/* * Function irport_interrupt_sir (irq, dev_id, regs) * * Interrupt handler for SIR modes */static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev){ struct smsc_ircc_cb *self = dev->priv; int boguscount = 0; int iobase; int iir, lsr; /* Already locked comming here in smsc_ircc_interrupt() */ /*spin_lock(&self->lock);*/ iobase = self->io.sir_base; iir = inb(iobase+UART_IIR) & UART_IIR_ID; if (iir == 0) return IRQ_NONE; while (iir) { /* Clear interrupt */ lsr = inb(iobase+UART_LSR); IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", __FUNCTION__, iir, lsr, iobase); switch (iir) { case UART_IIR_RLSI: IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__); break; case UART_IIR_RDI: /* Receive interrupt */ smsc_ircc_sir_receive(self); break; case UART_IIR_THRI: if (lsr & UART_LSR_THRE) /* Transmitter ready for data */ smsc_ircc_sir_write_wakeup(self); break; default: IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __FUNCTION__, iir); break; } /* Make sure we don't stay here to long */ if (boguscount++ > 100) break; iir = inb(iobase + UART_IIR) & UART_IIR_ID; } /*spin_unlock(&self->lock);*/ return IRQ_HANDLED;}#if 0 /* unused *//* * Function ircc_is_receiving (self) * * Return TRUE is we are currently receiving a frame * */static int ircc_is_receiving(struct smsc_ircc_cb *self){ int status = FALSE; /* int iobase; */ IRDA_DEBUG(1, "%s\n", __FUNCTION__); ASSERT(self != NULL, return FALSE;); IRDA_DEBUG(0, "%s: dma count = %d\n", __FUNCTION__, get_dma_residue(self->io.dma)); status = (self->rx_buff.state != OUTSIDE_FRAME); return status;}#endif /* unused *//* * Function smsc_ircc_net_open (dev) * * Start the device * */static int smsc_ircc_net_open(struct net_device *dev){ struct smsc_ircc_cb *self; int iobase; char hwname[16]; unsigned long flags; IRDA_DEBUG(1, "%s\n", __FUNCTION__); ASSERT(dev != NULL, return -1;); self = (struct smsc_ircc_cb *) dev->priv; ASSERT(self != NULL, return 0;); iobase = self->io.fir_base; if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name, (void *) dev)) { IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n", __FUNCTION__, self->io.irq); return -EAGAIN; } spin_lock_irqsave(&self->lock, flags); /*smsc_ircc_sir_start(self);*/ self->io.speed = 0; smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); spin_unlock_irqrestore(&self->lock, flags); /* Give self a hardware name */ /* It would be cool to offer the chip revision here - Jean II */ sprintf(hwname, "SMSC @ 0x%03x", self->io.fir_base); /* * Open new IrLAP layer instance, now that everything should be * initialized properly */ self->irlap = irlap_open(dev, &self->qos, hwname); /* * Always allocate the DMA channel after the IRQ, * and clean up on failure. */ if (request_dma(self->io.dma, dev->name)) { smsc_ircc_net_close(dev); WARNING("%s(), unable to allocate DMA=%d\n", __FUNCTION__, self->io.dma); return -EAGAIN; } netif_start_queue(dev); return 0;}/* * Function smsc_ircc_net_close (dev) * * Stop the device * */static int smsc_ircc_net_close(struct net_device *dev){ struct smsc_ircc_cb *self; int iobase; IRDA_DEBUG(1, "%s\n", __FUNCTION__); ASSERT(dev != NULL, return -1;); self = (struct smsc_ircc_cb *) dev->priv; ASSERT(self != NULL, return 0;); iobase = self->io.fir_base; /* Stop device */ netif_stop_queue(dev); /* Stop and remove instance of IrLAP */ if (self->irlap) irlap_close(self->irlap); self->irlap = NULL; free_irq(self->io.irq, dev); disable_dma(self->io.dma); free_dma(self->io.dma); return 0;}static void smsc_ircc_suspend(struct smsc_ircc_cb *self){ MESSAGE("%s, Suspending\n", driver_name); if (self->io.suspended) return; smsc_ircc_net_close(self->netdev); self->io.suspended = 1;}static void smsc_ircc_wakeup(struct smsc_ircc_cb *self){ if (!self->io.suspended) return; /* The code was doing a "cli()" here, but this can't be right. * If you need protection, do it in net_open with a spinlock * or give a good reason. - Jean II */ smsc_ircc_net_open(self->netdev); MESSAGE("%s, Waking up\n", driver_name);}static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data){ struct smsc_ircc_cb *self = (struct smsc_ircc_cb*) dev->data; if (self) { switch (rqst) { case PM_SUSPEND: smsc_ircc_suspend(self); break; case PM_RESUME: smsc_ircc_wakeup(self); break; } } return 0;}/* * Function smsc_ircc_close (self) * * Close driver instance * */static int __exit smsc_ircc_close(struct smsc_ircc_cb *self){ int iobase; unsigned long flags; IRDA_DEBUG(1, "%s\n", __FUNCTION__); ASSERT(self != NULL, return -1;); iobase = self->io.fir_base; if (self->pmdev) pm_unregister(self->pmdev); /* Remove netdevice */ unregister_netdev(self->netdev); /* Make sure the irq handler is not exectuting */ spin_lock_irqsave(&self->lock, flags); /* Stop interrupts */ register_bank(iobase, 0); outb(0, iobase+IRCC_IER); outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER); outb(0x00, iobase+IRCC_MASTER);#if 0 /* Reset to SIR mode */ register_bank(iobase, 1); outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA); outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);#endif spin_unlock_irqrestore(&self->lock, flags); /* Release the PORTS that this driver is using */ IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__, self->io.fir_base); release_region(self->io.fir_base, self->io.fir_ext); IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__, self->io.sir_base); release_region(self->io.sir_base, self->io.sir_ext); if (self->tx_buff.head) dma_free_coherent(NULL, self->tx_buff.truesize, self->tx_buff.head, self->tx_buff_dma); if (self->rx_buff.head) dma_free_coherent(NULL, self->rx_buff.truesize, self->rx_buff.head, self->rx_buff_dma); free_netdev(self->netdev); return 0;}static void __exit smsc_ircc_cleanup(void){ int i; IRDA_DEBUG(1, "%s\n", __FUNCTION__); for (i=0; i < 2; i++) { if (dev_self[i]) smsc_ircc_close(dev_self[i]); }}/* * Start SIR operations * * This function *must* be called with spinlock held, because it may * be called from the irq handler (via smsc_ircc_change_speed()). - Jean II */void smsc_ircc_sir_start(struct smsc_ircc_cb *self){ struct net_device *dev; int fir_base, sir_base; IRDA_DEBUG(3, "%s\n", __FUNCTION__); ASSERT(self != NULL, return;); dev= self->netdev; ASSERT(dev != NULL, return;); dev->hard_start_xmit = &smsc_ircc_hard_xmit_sir; fir_base = self->io.fir_base; sir_base = self->io.sir_base; /* Reset everything */ outb(IRCC_MASTER_RESET, fir_base+IRCC_MASTER); #if SMSC_IRCC2_C_SIR_STOP /*smsc_ircc_sir_stop(self);*/ #endif register_bank(fir_base, 1); outb(((inb(fir_base+IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base+IRCC_SCE_CFGA); /* Initialize UART */ outb(UART_LCR_WLEN8, sir_base+UART_LCR); /* Reset DLAB */ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base+UART_MCR); /* Turn on interrups */ outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base+UART_IER); IRDA_DEBUG(3, "%s() - exit\n", __FUNCTION__); outb(0x00, fir_base+IRCC_MASTER);}#if SMSC_IRCC2_C_SIR_STOPvoid smsc_ircc_sir_stop(struct smsc_ircc_cb *self){ int iobase;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -