📄 smsc-ircc2.c
字号:
/* 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 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 = netdev_priv(dev); IRDA_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); else smsc_ircc_dma_xmit_complete(self); smsc_ircc_dma_receive(self); } 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) * * Interrupt handler for SIR modes */static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev){ struct smsc_ircc_cb *self = netdev_priv(dev); 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__); IRDA_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 */static int smsc_ircc_request_irq(struct smsc_ircc_cb *self){ int error; error = request_irq(self->io.irq, smsc_ircc_interrupt, 0, self->netdev->name, self->netdev); if (error) IRDA_DEBUG(0, "%s(), unable to allocate irq=%d, err=%d\n", __FUNCTION__, self->io.irq, error); return error;}static void smsc_ircc_start_interrupts(struct smsc_ircc_cb *self){ unsigned long flags; spin_lock_irqsave(&self->lock, flags); self->io.speed = 0; smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); spin_unlock_irqrestore(&self->lock, flags);}static void smsc_ircc_stop_interrupts(struct smsc_ircc_cb *self){ int iobase = self->io.fir_base; unsigned long flags; spin_lock_irqsave(&self->lock, flags); register_bank(iobase, 0); outb(0, iobase + IRCC_IER); outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER); outb(0x00, iobase + IRCC_MASTER); spin_unlock_irqrestore(&self->lock, flags);}/* * Function smsc_ircc_net_open (dev) * * Start the device * */static int smsc_ircc_net_open(struct net_device *dev){ struct smsc_ircc_cb *self; char hwname[16]; IRDA_DEBUG(1, "%s\n", __FUNCTION__); IRDA_ASSERT(dev != NULL, return -1;); self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); if (self->io.suspended) { IRDA_DEBUG(0, "%s(), device is suspended\n", __FUNCTION__); return -EAGAIN; } 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; } smsc_ircc_start_interrupts(self); /* 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); IRDA_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; IRDA_DEBUG(1, "%s\n", __FUNCTION__); IRDA_ASSERT(dev != NULL, return -1;); self = netdev_priv(dev); 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; smsc_ircc_stop_interrupts(self); /* if we are called from smsc_ircc_resume we don't have IRQ reserved */ if (!self->io.suspended) free_irq(self->io.irq, dev); disable_dma(self->io.dma); free_dma(self->io.dma); return 0;}static int smsc_ircc_suspend(struct platform_device *dev, pm_message_t state){ struct smsc_ircc_cb *self = platform_get_drvdata(dev); if (!self->io.suspended) { IRDA_DEBUG(1, "%s, Suspending\n", driver_name); rtnl_lock(); if (netif_running(self->netdev)) { netif_device_detach(self->netdev); smsc_ircc_stop_interrupts(self); free_irq(self->io.irq, self->netdev); disable_dma(self->io.dma); } self->io.suspended = 1; rtnl_unlock(); } return 0;}static int smsc_ircc_resume(struct platform_device *dev){ struct smsc_ircc_cb *self = platform_get_drvdata(dev); if (self->io.suspended) { IRDA_DEBUG(1, "%s, Waking up\n", driver_name); rtnl_lock(); smsc_ircc_init_chip(self); if (netif_running(self->netdev)) { if (smsc_ircc_request_irq(self)) { /* * Don't fail resume process, just kill this * network interface */ unregister_netdevice(self->netdev); } else { enable_dma(self->io.dma); smsc_ircc_start_interrupts(self); netif_device_attach(self->netdev); } } self->io.suspended = 0; rtnl_unlock(); } return 0;}/* * Function smsc_ircc_close (self) * * Close driver instance * */static int __exit smsc_ircc_close(struct smsc_ircc_cb *self){ IRDA_DEBUG(1, "%s\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return -1;); platform_device_unregister(self->pldev); /* Remove netdevice */ unregister_netdev(self->netdev); smsc_ircc_stop_interrupts(self); /* 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]); } if (pnp_driver_registered) pnp_unregister_driver(&smsc_ircc_pnp_driver); platform_driver_unregister(&smsc_ircc_driver);}/* * 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__); IRDA_ASSERT(self != NULL, return;); dev = self->netdev; IRDA_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; IRDA_DEBUG(3, "%s\n", __FUNCTION__); iobase = self->io.sir_base; /* Reset UART */ outb(0, iobase + UART_MCR); /* Turn off interrupts */ outb(0, iobase + UART_IER);}#endif/* * Function smsc_sir_write_wakeup (self) * * Called by the SIR interrupt handler when there's room for more data. * If we have more packets to send, we send them here. * */static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self){ int actual = 0; int iobase; int fcr; IRDA_ASSERT(self != NULL, return;); IRDA_DEBUG(4, "%s\n", __FUNCTION__); iobase = self->io.sir_base; /* Finished with frame? */ if (self->tx_buff.len > 0) { /* Write data left in transmit buffer */ actual = smsc_ircc_sir_write(iobase, self->io.fifo_size, self->tx_buff.data, self->tx_buff.len); self->tx_buff.data += actual; self->tx_buff.len -= actual; } else { /*if (self->tx_buff.len ==0) {*/ /* * Now serial buffer is almost free & we can start
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -