📄 smsc-ircc2.c
字号:
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]); } 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 * transmission of another packet. But first we must check * if we need to change the speed of the hardware */ if (self->new_speed) { IRDA_DEBUG(5, "%s(), Changing speed to %d.\n", __FUNCTION__, self->new_speed); smsc_ircc_sir_wait_hw_transmitter_finish(self); smsc_ircc_change_speed(self, self->new_speed); self->new_speed = 0; } else { /* Tell network layer that we want more frames */ netif_wake_queue(self->netdev); } self->stats.tx_packets++; if (self->io.speed <= 115200) { /* * Reset Rx FIFO to make sure that all reflected transmit data * is discarded. This is needed for half duplex operation */ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR; fcr |= self->io.speed < 38400 ? UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14; outb(fcr, iobase + UART_FCR); /* Turn on receive interrupts */ outb(UART_IER_RDI, iobase + UART_IER); } }}/* * Function smsc_ircc_sir_write (iobase, fifo_size, buf, len) * * Fill Tx FIFO with transmit data * */static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len){ int actual = 0; /* Tx FIFO should be empty! */ if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) { IRDA_WARNING("%s(), failed, fifo not empty!\n", __FUNCTION__); return 0; } /* Fill FIFO with current frame */ while (fifo_size-- > 0 && actual < len) { /* Transmit next byte */ outb(buf[actual], iobase + UART_TX); actual++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -