📄 w83977af_ir.c
字号:
/* Move to next frame */ self->rx_buff.data += len; self->stats.rx_packets++; skb->dev = self->netdev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); self->netdev->last_rx = jiffies; } } /* Restore set register */ outb(set, iobase+SSR); return TRUE;}/* * Function pc87108_pio_receive (self) * * Receive all data in receiver FIFO * */static void w83977af_pio_receive(struct w83977af_ir *self) { __u8 byte = 0x00; int iobase; IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); IRDA_ASSERT(self != NULL, return;); iobase = self->io.fir_base; /* Receive all characters in Rx FIFO */ do { byte = inb(iobase+RBR); async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, byte); } while (inb(iobase+USR) & USR_RDR); /* Data available */ }/* * Function w83977af_sir_interrupt (self, eir) * * Handle SIR interrupt * */static __u8 w83977af_sir_interrupt(struct w83977af_ir *self, int isr){ int actual; __u8 new_icr = 0; __u8 set; int iobase; IRDA_DEBUG(4, "%s(), isr=%#x\n", __FUNCTION__ , isr); iobase = self->io.fir_base; /* Transmit FIFO low on data */ if (isr & ISR_TXTH_I) { /* Write data left in transmit buffer */ actual = w83977af_pio_write(self->io.fir_base, self->tx_buff.data, self->tx_buff.len, self->io.fifo_size); self->tx_buff.data += actual; self->tx_buff.len -= actual; self->io.direction = IO_XMIT; /* Check if finished */ if (self->tx_buff.len > 0) { new_icr |= ICR_ETXTHI; } else { set = inb(iobase+SSR); switch_bank(iobase, SET0); outb(AUDR_SFEND, iobase+AUDR); outb(set, iobase+SSR); self->stats.tx_packets++; /* Feed me more packets */ netif_wake_queue(self->netdev); new_icr |= ICR_ETBREI; } } /* Check if transmission has completed */ if (isr & ISR_TXEMP_I) { /* Check if we need to change the speed? */ if (self->new_speed) { IRDA_DEBUG(2, "%s(), Changing speed!\n", __FUNCTION__ ); w83977af_change_speed(self, self->new_speed); self->new_speed = 0; } /* Turn around and get ready to receive some data */ self->io.direction = IO_RECV; new_icr |= ICR_ERBRI; } /* Rx FIFO threshold or timeout */ if (isr & ISR_RXTH_I) { w83977af_pio_receive(self); /* Keep receiving */ new_icr |= ICR_ERBRI; } return new_icr;}/* * Function pc87108_fir_interrupt (self, eir) * * Handle MIR/FIR interrupt * */static __u8 w83977af_fir_interrupt(struct w83977af_ir *self, int isr){ __u8 new_icr = 0; __u8 set; int iobase; iobase = self->io.fir_base; set = inb(iobase+SSR); /* End of frame detected in FIFO */ if (isr & (ISR_FEND_I|ISR_FSF_I)) { if (w83977af_dma_receive_complete(self)) { /* Wait for next status FIFO interrupt */ new_icr |= ICR_EFSFI; } else { /* DMA not finished yet */ /* Set timer value, resolution 1 ms */ switch_bank(iobase, SET4); outb(0x01, iobase+TMRL); /* 1 ms */ outb(0x00, iobase+TMRH); /* Start timer */ outb(IR_MSL_EN_TMR, iobase+IR_MSL); new_icr |= ICR_ETMRI; } } /* Timer finished */ if (isr & ISR_TMR_I) { /* Disable timer */ switch_bank(iobase, SET4); outb(0, iobase+IR_MSL); /* Clear timer event */ /* switch_bank(iobase, SET0); *//* outb(ASCR_CTE, iobase+ASCR); */ /* Check if this is a TX timer interrupt */ if (self->io.direction == IO_XMIT) { w83977af_dma_write(self, iobase); new_icr |= ICR_EDMAI; } else { /* Check if DMA has now finished */ w83977af_dma_receive_complete(self); new_icr |= ICR_EFSFI; } } /* Finished with DMA */ if (isr & ISR_DMA_I) { w83977af_dma_xmit_complete(self); /* Check if there are more frames to be transmitted */ /* if (irda_device_txqueue_empty(self)) { */ /* Prepare for receive * * ** Netwinder Tx DMA likes that we do this anyway ** */ w83977af_dma_receive(self); new_icr = ICR_EFSFI; /* } */ } /* Restore set */ outb(set, iobase+SSR); return new_icr;}/* * Function w83977af_interrupt (irq, dev_id, regs) * * An interrupt from the chip has arrived. Time to do some work * */static irqreturn_t w83977af_interrupt(int irq, void *dev_id){ struct net_device *dev = dev_id; struct w83977af_ir *self; __u8 set, icr, isr; int iobase; self = dev->priv; iobase = self->io.fir_base; /* Save current bank */ set = inb(iobase+SSR); switch_bank(iobase, SET0); icr = inb(iobase+ICR); isr = inb(iobase+ISR) & icr; /* Mask out the interesting ones */ outb(0, iobase+ICR); /* Disable interrupts */ if (isr) { /* Dispatch interrupt handler for the current speed */ if (self->io.speed > PIO_MAX_SPEED ) icr = w83977af_fir_interrupt(self, isr); else icr = w83977af_sir_interrupt(self, isr); } outb(icr, iobase+ICR); /* Restore (new) interrupts */ outb(set, iobase+SSR); /* Restore bank register */ return IRQ_RETVAL(isr);}/* * Function w83977af_is_receiving (self) * * Return TRUE is we are currently receiving a frame * */static int w83977af_is_receiving(struct w83977af_ir *self){ int status = FALSE; int iobase; __u8 set; IRDA_ASSERT(self != NULL, return FALSE;); if (self->io.speed > 115200) { iobase = self->io.fir_base; /* Check if rx FIFO is not empty */ set = inb(iobase+SSR); switch_bank(iobase, SET2); if ((inb(iobase+RXFDTH) & 0x3f) != 0) { /* We are receiving something */ status = TRUE; } outb(set, iobase+SSR); } else status = (self->rx_buff.state != OUTSIDE_FRAME); return status;}/* * Function w83977af_net_open (dev) * * Start the device * */static int w83977af_net_open(struct net_device *dev){ struct w83977af_ir *self; int iobase; char hwname[32]; __u8 set; IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); IRDA_ASSERT(dev != NULL, return -1;); self = (struct w83977af_ir *) dev->priv; IRDA_ASSERT(self != NULL, return 0;); iobase = self->io.fir_base; if (request_irq(self->io.irq, w83977af_interrupt, 0, dev->name, (void *) dev)) { return -EAGAIN; } /* * Always allocate the DMA channel after the IRQ, * and clean up on failure. */ if (request_dma(self->io.dma, dev->name)) { free_irq(self->io.irq, self); return -EAGAIN; } /* Save current set */ set = inb(iobase+SSR); /* Enable some interrupts so we can receive frames again */ switch_bank(iobase, SET0); if (self->io.speed > 115200) { outb(ICR_EFSFI, iobase+ICR); w83977af_dma_receive(self); } else outb(ICR_ERBRI, iobase+ICR); /* Restore bank register */ outb(set, iobase+SSR); /* Ready to play! */ netif_start_queue(dev); /* Give self a hardware name */ sprintf(hwname, "w83977af @ 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); return 0;}/* * Function w83977af_net_close (dev) * * Stop the device * */static int w83977af_net_close(struct net_device *dev){ struct w83977af_ir *self; int iobase; __u8 set; IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); IRDA_ASSERT(dev != NULL, return -1;); self = (struct w83977af_ir *) dev->priv; IRDA_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; disable_dma(self->io.dma); /* Save current set */ set = inb(iobase+SSR); /* Disable interrupts */ switch_bank(iobase, SET0); outb(0, iobase+ICR); free_irq(self->io.irq, dev); free_dma(self->io.dma); /* Restore bank register */ outb(set, iobase+SSR); return 0;}/* * Function w83977af_net_ioctl (dev, rq, cmd) * * Process IOCTL commands for this device * */static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct if_irda_req *irq = (struct if_irda_req *) rq; struct w83977af_ir *self; unsigned long flags; int ret = 0; IRDA_ASSERT(dev != NULL, return -1;); self = dev->priv; IRDA_ASSERT(self != NULL, return -1;); IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__ , dev->name, cmd); spin_lock_irqsave(&self->lock, flags); switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ if (!capable(CAP_NET_ADMIN)) { ret = -EPERM; goto out; } w83977af_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 = w83977af_is_receiving(self); break; default: ret = -EOPNOTSUPP; }out: spin_unlock_irqrestore(&self->lock, flags); return ret;}static struct net_device_stats *w83977af_net_get_stats(struct net_device *dev){ struct w83977af_ir *self = (struct w83977af_ir *) dev->priv; return &self->stats;}MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");MODULE_DESCRIPTION("Winbond W83977AF IrDA Device Driver");MODULE_LICENSE("GPL");module_param(qos_mtt_bits, int, 0);MODULE_PARM_DESC(qos_mtt_bits, "Mimimum Turn Time");module_param_array(io, int, NULL, 0);MODULE_PARM_DESC(io, "Base I/O addresses");module_param_array(irq, int, NULL, 0);MODULE_PARM_DESC(irq, "IRQ lines");/* * Function init_module (void) * * * */module_init(w83977af_init);/* * Function cleanup_module (void) * * * */module_exit(w83977af_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -