/* hard_xmit interface of irda device */ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) { struct pxa_irda *si = netdev_priv(dev); int speed = irda_get_next_speed(skb); /* * Does this packet contain a request to change the interface * speed? If so, remember it until we complete the transmission * of this frame. */ if (speed != si->speed && speed != -1) si->newspeed = speed; /* * If this is an empty frame, we can bypass a lot. */ if (skb->len == 0) { if (si->newspeed) { si->newspeed = 0; pxa_irda_set_speed(si, speed); } dev_kfree_skb(skb); return 0; } netif_stop_queue(dev); if (!IS_FIR(si)) { si->tx_buff.data = si->tx_buff.head; si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize); /* Disable STUART interrupts and switch to transmit mode. */ STIER = 0; STISR = IrSR_IR_TRANSMIT_ON | IrSR_XMODE_PULSE_1_6; /* enable STUART and transmit interrupts */ STIER = IER_UUE | IER_TIE; } else { unsigned long mtt = irda_get_mtt(skb); si->dma_tx_buff_len = skb->len; skb_copy_from_linear_data(skb, si->dma_tx_buff, skb->len); if (mtt) while ((unsigned)(OSCR - si->last_oscr)/4 < mtt) cpu_relax(); /* stop RX DMA, disable FICP */ DCSR(si->rxdma) &= ~DCSR_RUN; ICCR0 = 0; pxa_irda_fir_dma_tx_start(si); ICCR0 = ICCR0_ITR | ICCR0_TXE; } dev_kfree_skb(skb); dev->trans_start = jiffies; return 0; }
static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) { struct pxa_irda *si = netdev_priv(dev); int speed = irda_get_next_speed(skb); if (speed != si->speed && speed != -1) si->newspeed = speed; if (skb->len == 0) { if (si->newspeed) { si->newspeed = 0; pxa_irda_set_speed(si, speed); } dev_kfree_skb(skb); return NETDEV_TX_OK; } netif_stop_queue(dev); if (!IS_FIR(si)) { si->tx_buff.data = si->tx_buff.head; si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize); STIER = 0; STISR = IrSR_IR_TRANSMIT_ON | IrSR_XMODE_PULSE_1_6; STIER = IER_UUE | IER_TIE; } else { unsigned long mtt = irda_get_mtt(skb); si->dma_tx_buff_len = skb->len; skb_copy_from_linear_data(skb, si->dma_tx_buff, skb->len); if (mtt) while ((unsigned)(OSCR - si->last_oscr)/4 < mtt) cpu_relax(); DCSR(si->rxdma) &= ~DCSR_RUN; ICCR0 = 0; pxa_irda_fir_dma_tx_start(si); ICCR0 = ICCR0_ITR | ICCR0_TXE; } dev_kfree_skb(skb); return NETDEV_TX_OK; }
static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) { struct if_irda_req *rq = (struct if_irda_req *)ifreq; struct pxa_irda *si = netdev_priv(dev); int ret; switch (cmd) { case SIOCSBANDWIDTH: ret = -EPERM; if (capable(CAP_NET_ADMIN)) { /* * We are unable to set the speed if the * device is not running. */ if (netif_running(dev)) { ret = pxa_irda_set_speed(si, rq->ifr_baudrate); } else { printk(KERN_INFO "pxa_ir: SIOCSBANDWIDTH: !netif_running\n"); ret = 0; } } break; case SIOCSMEDIABUSY: ret = -EPERM; if (capable(CAP_NET_ADMIN)) { irda_device_set_media_busy(dev, TRUE); ret = 0; } break; case SIOCGRECEIVING: ret = 0; rq->ifr_receiving = IS_FIR(si) ? 0 : si->rx_buff.state != OUTSIDE_FRAME; break; default: ret = -EOPNOTSUPP; break; } return ret; }
/* FIR Transmit DMA interrupt handler */ static void pxa_irda_fir_dma_tx_irq(int channel, void *data) { struct net_device *dev = data; struct pxa_irda *si = netdev_priv(dev); int dcsr; dcsr = DCSR(channel); DCSR(channel) = dcsr & ~DCSR_RUN; if (dcsr & DCSR_ENDINTR) { si->stats.tx_packets++; si->stats.tx_bytes += si->dma_tx_buff_len; } else { si->stats.tx_errors++; } while (ICSR1 & ICSR1_TBY) cpu_relax(); si->last_oscr = OSCR; /* * HACK: It looks like the TBY bit is dropped too soon. * Without this delay things break. */ udelay(120); if (si->newspeed) { pxa_irda_set_speed(si, si->newspeed); si->newspeed = 0; } else { int i = 64; ICCR0 = 0; pxa_irda_fir_dma_rx_start(si); while ((ICSR1 & ICSR1_RNE) && i--) (void)ICDR; ICCR0 = ICCR0_ITR | ICCR0_RXE; if (i < 0) printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n"); } netif_wake_queue(dev); }
/* SIR interrupt service routine. */ static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id) { struct net_device *dev = dev_id; struct pxa_irda *si = netdev_priv(dev); int iir, lsr, data; iir = STIIR; switch (iir & 0x0F) { case 0x06: /* Receiver Line Status */ lsr = STLSR; while (lsr & LSR_FIFOE) { data = STRBR; if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) { printk(KERN_DEBUG "pxa_ir: sir receiving error\n"); si->stats.rx_errors++; if (lsr & LSR_FE) si->stats.rx_frame_errors++; if (lsr & LSR_OE) si->stats.rx_fifo_errors++; } else { si->stats.rx_bytes++; async_unwrap_char(dev, &si->stats, &si->rx_buff, data); } lsr = STLSR; } dev->last_rx = jiffies; si->last_oscr = OSCR; break; case 0x04: /* Received Data Available */ /* forth through */ case 0x0C: /* Character Timeout Indication */ do { si->stats.rx_bytes++; async_unwrap_char(dev, &si->stats, &si->rx_buff, STRBR); } while (STLSR & LSR_DR); dev->last_rx = jiffies; si->last_oscr = OSCR; break; case 0x02: /* Transmit FIFO Data Request */ while ((si->tx_buff.len) && (STLSR & LSR_TDRQ)) { STTHR = *si->tx_buff.data++; si->tx_buff.len -= 1; } if (si->tx_buff.len == 0) { si->stats.tx_packets++; si->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head; /* We need to ensure that the transmitter has finished. */ while ((STLSR & LSR_TEMT) == 0) cpu_relax(); si->last_oscr = OSCR; /* * Ok, we've finished transmitting. Now enable * the receiver. Sometimes we get a receive IRQ * immediately after a transmit... */ if (si->newspeed) { pxa_irda_set_speed(si, si->newspeed); si->newspeed = 0; } else { /* enable IR Receiver, disable IR Transmitter */ STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6; /* enable STUART and receive interrupts */ STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE; } /* I'm hungry! */ netif_wake_queue(dev); } break; } return IRQ_HANDLED; }
static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id) { struct net_device *dev = dev_id; struct pxa_irda *si = netdev_priv(dev); int iir, lsr, data; iir = STIIR; switch (iir & 0x0F) { case 0x06: lsr = STLSR; while (lsr & LSR_FIFOE) { data = STRBR; if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) { printk(KERN_DEBUG "pxa_ir: sir receiving error\n"); dev->stats.rx_errors++; if (lsr & LSR_FE) dev->stats.rx_frame_errors++; if (lsr & LSR_OE) dev->stats.rx_fifo_errors++; } else { dev->stats.rx_bytes++; async_unwrap_char(dev, &dev->stats, &si->rx_buff, data); } lsr = STLSR; } si->last_oscr = OSCR; break; case 0x04: case 0x0C: do { dev->stats.rx_bytes++; async_unwrap_char(dev, &dev->stats, &si->rx_buff, STRBR); } while (STLSR & LSR_DR); si->last_oscr = OSCR; break; case 0x02: while ((si->tx_buff.len) && (STLSR & LSR_TDRQ)) { STTHR = *si->tx_buff.data++; si->tx_buff.len -= 1; } if (si->tx_buff.len == 0) { dev->stats.tx_packets++; dev->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head; while ((STLSR & LSR_TEMT) == 0) cpu_relax(); si->last_oscr = OSCR; if (si->newspeed) { pxa_irda_set_speed(si, si->newspeed); si->newspeed = 0; } else { STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6; STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE; } netif_wake_queue(dev); } break; } return IRQ_HANDLED; }