📄 smsc-ircc2.c
字号:
self->io.speed = SMSC_IRCC2_C_IRDA_FALLBACK_SPEED; if (irq < 255) { if (irq != chip_irq) IRDA_MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n", driver_name, chip_irq, irq); self->io.irq = irq; } else self->io.irq = chip_irq; if (dma < 255) { if (dma != chip_dma) IRDA_MESSAGE("%s, Overriding DMA - chip says %d, using %d\n", driver_name, chip_dma, dma); self->io.dma = dma; } else self->io.dma = chip_dma;}/* * Function smsc_ircc_setup_qos(self) * * Setup qos * */static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self){ /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); self->qos.min_turn_time.bits = SMSC_IRCC2_MIN_TURN_TIME; self->qos.window_size.bits = SMSC_IRCC2_WINDOW_SIZE; irda_qos_bits_to_value(&self->qos);}/* * Function smsc_ircc_init_chip(self) * * Init chip * */static void smsc_ircc_init_chip(struct smsc_ircc_cb *self){ int iobase, ir_mode, ctrl, fast; IRDA_ASSERT(self != NULL, return;); iobase = self->io.fir_base; ir_mode = IRCC_CFGA_IRDA_SIR_A; ctrl = 0; fast = 0; register_bank(iobase, 0); outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER); outb(0x00, iobase + IRCC_MASTER); register_bank(iobase, 1); outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | ir_mode), iobase + IRCC_SCE_CFGA);#ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */ outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), iobase + IRCC_SCE_CFGB);#else outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR), iobase + IRCC_SCE_CFGB);#endif (void) inb(iobase + IRCC_FIFO_THRESHOLD); outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase + IRCC_FIFO_THRESHOLD); register_bank(iobase, 4); outb((inb(iobase + IRCC_CONTROL) & 0x30) | ctrl, iobase + IRCC_CONTROL); register_bank(iobase, 0); outb(fast, iobase + IRCC_LCR_A); smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); /* Power on device */ outb(0x00, iobase + IRCC_MASTER);}/* * Function smsc_ircc_net_ioctl (dev, rq, cmd) * * Process IOCTL commands for this device * */static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct if_irda_req *irq = (struct if_irda_req *) rq; struct smsc_ircc_cb *self; unsigned long flags; int ret = 0; IRDA_ASSERT(dev != NULL, return -1;); self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return -1;); IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ if (!capable(CAP_NET_ADMIN)) ret = -EPERM; else { /* Make sure we are the only one touching * self->io.speed and the hardware - Jean II */ spin_lock_irqsave(&self->lock, flags); smsc_ircc_change_speed(self, irq->ifr_baudrate); spin_unlock_irqrestore(&self->lock, flags); } break; case SIOCSMEDIABUSY: /* Set media busy */ if (!capable(CAP_NET_ADMIN)) { ret = -EPERM; break; } irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ irq->ifr_receiving = smsc_ircc_is_receiving(self); break; #if 0 case SIOCSDTRRTS: if (!capable(CAP_NET_ADMIN)) { ret = -EPERM; break; } smsc_ircc_sir_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); break; #endif default: ret = -EOPNOTSUPP; } return ret;}static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev){ struct smsc_ircc_cb *self = netdev_priv(dev); return &self->stats;}#if SMSC_IRCC2_C_NET_TIMEOUT/* * Function smsc_ircc_timeout (struct net_device *dev) * * The networking timeout management. * */static void smsc_ircc_timeout(struct net_device *dev){ struct smsc_ircc_cb *self = netdev_priv(dev); unsigned long flags; IRDA_WARNING("%s: transmit timed out, changing speed to: %d\n", dev->name, self->io.speed); spin_lock_irqsave(&self->lock, flags); smsc_ircc_sir_start(self); smsc_ircc_change_speed(self, self->io.speed); dev->trans_start = jiffies; netif_wake_queue(dev); spin_unlock_irqrestore(&self->lock, flags);}#endif/* * Function smsc_ircc_hard_xmit_sir (struct sk_buff *skb, struct net_device *dev) * * Transmits the current frame until FIFO is full, then * waits until the next transmit interrupt, and continues until the * frame is transmitted. */int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev){ struct smsc_ircc_cb *self; unsigned long flags; s32 speed; IRDA_DEBUG(1, "%s\n", __FUNCTION__); IRDA_ASSERT(dev != NULL, return 0;); self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); netif_stop_queue(dev); /* Make sure test of self->io.speed & speed change are atomic */ spin_lock_irqsave(&self->lock, flags); /* Check if we need to change the speed */ speed = irda_get_next_speed(skb); if (speed != self->io.speed && speed != -1) { /* Check for empty frame */ if (!skb->len) { /* * We send frames one by one in SIR mode (no * pipelining), so at this point, if we were sending * a previous frame, we just received the interrupt * telling us it is finished (UART_IIR_THRI). * Therefore, waiting for the transmitter to really * finish draining the fifo won't take too long. * And the interrupt handler is not expected to run. * - Jean II */ smsc_ircc_sir_wait_hw_transmitter_finish(self); smsc_ircc_change_speed(self, speed); spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0; } self->new_speed = speed; } /* Init tx buffer */ self->tx_buff.data = self->tx_buff.head; /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); self->stats.tx_bytes += self->tx_buff.len; /* Turn on transmit finished interrupt. Will fire immediately! */ outb(UART_IER_THRI, self->io.sir_base + UART_IER); spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0;}/* * Function smsc_ircc_set_fir_speed (self, baud) * * Change the speed of the device * */static void smsc_ircc_set_fir_speed(struct smsc_ircc_cb *self, u32 speed){ int fir_base, ir_mode, ctrl, fast; IRDA_ASSERT(self != NULL, return;); fir_base = self->io.fir_base; self->io.speed = speed; switch (speed) { default: case 576000: ir_mode = IRCC_CFGA_IRDA_HDLC; ctrl = IRCC_CRC; fast = 0; IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__); break; case 1152000: ir_mode = IRCC_CFGA_IRDA_HDLC; ctrl = IRCC_1152 | IRCC_CRC; fast = IRCC_LCR_A_FAST | IRCC_LCR_A_GP_DATA; IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __FUNCTION__); break; case 4000000: ir_mode = IRCC_CFGA_IRDA_4PPM; ctrl = IRCC_CRC; fast = IRCC_LCR_A_FAST; IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __FUNCTION__); break; } #if 0 Now in tranceiver! /* This causes an interrupt */ register_bank(fir_base, 0); outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast, fir_base + IRCC_LCR_A); #endif register_bank(fir_base, 1); outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base + IRCC_SCE_CFGA); register_bank(fir_base, 4); outb((inb(fir_base + IRCC_CONTROL) & 0x30) | ctrl, fir_base + IRCC_CONTROL);}/* * Function smsc_ircc_fir_start(self) * * Change the speed of the device * */static void smsc_ircc_fir_start(struct smsc_ircc_cb *self){ struct net_device *dev; int fir_base; IRDA_DEBUG(1, "%s\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); dev = self->netdev; IRDA_ASSERT(dev != NULL, return;); fir_base = self->io.fir_base; /* Reset everything */ /* Install FIR transmit handler */ dev->hard_start_xmit = smsc_ircc_hard_xmit_fir; /* Clear FIFO */ outb(inb(fir_base + IRCC_LCR_A) | IRCC_LCR_A_FIFO_RESET, fir_base + IRCC_LCR_A); /* Enable interrupt */ /*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base + IRCC_IER);*/ register_bank(fir_base, 1); /* Select the TX/RX interface */#ifdef SMSC_669 /* Uses pin 88/89 for Rx/Tx */ outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), fir_base + IRCC_SCE_CFGB);#else outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR), fir_base + IRCC_SCE_CFGB);#endif (void) inb(fir_base + IRCC_FIFO_THRESHOLD); /* Enable SCE interrupts */ outb(0, fir_base + IRCC_MASTER); register_bank(fir_base, 0); outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, fir_base + IRCC_IER); outb(IRCC_MASTER_INT_EN, fir_base + IRCC_MASTER);}/* * Function smsc_ircc_fir_stop(self, baud) * * Change the speed of the device * */static void smsc_ircc_fir_stop(struct smsc_ircc_cb *self){ int fir_base; IRDA_DEBUG(1, "%s\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); fir_base = self->io.fir_base; register_bank(fir_base, 0); /*outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER);*/ outb(inb(fir_base + IRCC_LCR_B) & IRCC_LCR_B_SIP_ENABLE, fir_base + IRCC_LCR_B);}/* * Function smsc_ircc_change_speed(self, baud) * * Change the speed of the device * * This function *must* be called with spinlock held, because it may * be called from the irq handler. - Jean II */static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed){ struct net_device *dev; int last_speed_was_sir; IRDA_DEBUG(0, "%s() changing speed to: %d\n", __FUNCTION__, speed); IRDA_ASSERT(self != NULL, return;); dev = self->netdev; last_speed_was_sir = self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED; #if 0 /* Temp Hack */ speed= 1152000; self->io.speed = speed; last_speed_was_sir = 0; smsc_ircc_fir_start(self); #endif if (self->io.speed == 0) smsc_ircc_sir_start(self); #if 0 if (!last_speed_was_sir) speed = self->io.speed; #endif if (self->io.speed != speed) smsc_ircc_set_transceiver_for_speed(self, speed); self->io.speed = speed; if (speed <= SMSC_IRCC2_MAX_SIR_SPEED) { if (!last_speed_was_sir) { smsc_ircc_fir_stop(self); smsc_ircc_sir_start(self); } smsc_ircc_set_sir_speed(self, speed); } else { if (last_speed_was_sir) { #if SMSC_IRCC2_C_SIR_STOP smsc_ircc_sir_stop(self); #endif smsc_ircc_fir_start(self); } smsc_ircc_set_fir_speed(self, speed); #if 0 self->tx_buff.len = 10; self->tx_buff.data = self->tx_buff.head; smsc_ircc_dma_xmit(self, 4000); #endif /* Be ready for incoming frames */ smsc_ircc_dma_receive(self); } netif_wake_queue(dev);}/* * Function smsc_ircc_set_sir_speed (self, speed) * * Set speed of IrDA port to specified baudrate * */void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed){ int iobase; int fcr; /* FIFO control reg */ int lcr; /* Line control reg */ int divisor; IRDA_DEBUG(0, "%s(), Setting speed to: %d\n", __FUNCTION__, speed); IRDA_ASSERT(self != NULL, return;); iobase = self->io.sir_base; /* Update accounting for new speed */ self->io.speed = speed; /* Turn off interrupts */ outb(0, iobase + UART_IER); divisor = SMSC_IRCC2_MAX_SIR_SPEED / speed; fcr = UART_FCR_ENABLE_FIFO; /* * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and * almost 1,7 ms at 19200 bps. At speeds above that we can just forget * about this timeout since it will always be fast enough. */ fcr |= self->io.speed < 38400 ? UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14; /* IrDA ports use 8N1 */ lcr = UART_LCR_WLEN8; outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */ outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */ outb(divisor >> 8, iobase + UART_DLM); outb(lcr, iobase + UART_LCR); /* Set 8N1 */ outb(fcr, iobase + UART_FCR); /* Enable FIFO's */ /* Turn on interrups */ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); IRDA_DEBUG(2, "%s() speed changed to: %d\n", __FUNCTION__, speed);}/* * Function smsc_ircc_hard_xmit_fir (skb, dev) * * Transmit the frame! * */static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev){ struct smsc_ircc_cb *self; unsigned long flags; s32 speed; int mtt; IRDA_ASSERT(dev != NULL, return 0;); self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); netif_stop_queue(dev); /* Make sure test of self->io.speed & speed change are atomic */ spin_lock_irqsave(&self->lock, flags); /* Check if we need to change the speed after this frame */ speed = irda_get_next_speed(skb); if (speed != self->io.speed && speed != -1) { /* Check for empty frame */ if (!skb->len) { /* Note : you should make sure that speed changes * are not going to corrupt any outgoing frame. * Look at nsc-ircc for the gory details - Jean II */ smsc_ircc_change_speed(self, speed); spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0; } self->new_speed = speed; } memcpy(self->tx_buff.head, skb->data, skb->len); self->tx_buff.len = skb->len; self->tx_buff.data = self->tx_buff.head; mtt = irda_get_mtt(skb); if (mtt) { int bofs; /* * Compute how many BOFs (STA or PA's) we need to waste the * min turn time given the speed of the link. */ bofs = mtt * (self->io.speed / 1000) / 8000; if (bofs > 4095) bofs = 4095; smsc_ircc_dma_xmit(self, bofs); } else { /* Transmit frame */ smsc_ircc_dma_xmit(self, 0); } spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0;}/* * Function smsc_ircc_dma_xmit (self, bofs) * * Transmit data using DMA * */static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs){ int iobase = self->io.fir_base; u8 ctrl; IRDA_DEBUG(3, "%s\n", __FUNCTION__);#if 1 /* Disable Rx */ register_bank(iobase, 0); outb(0x00, iobase + IRCC_LCR_B);#endif register_bank(iobase, 1); outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, iobase + IRCC_SCE_CFGB); self->io.direction = IO_XMIT; /* Set BOF additional count for generating the min turn time */ register_bank(iobase, 4); outb(bofs & 0xff, iobase + IRCC_BOF_COUNT_LO); ctrl = inb(iobase + IRCC_CONTROL) & 0xf0; outb(ctrl | ((bofs >> 8) & 0x0f), iobase + IRCC_BOF_COUNT_HI); /* Set max Tx frame size */ outb(self->tx_buff.len >> 8, iobase + IRCC_TX_SIZE_HI); outb(self->tx_buff.len & 0xff, iobase + IRCC_TX_SIZE_LO); /*outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR);*/ /* Enable burst mode chip Tx DMA */ register_bank(iobase, 1); outb(inb(iobase + IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | IRCC_CFGB_DMA_BURST, iobase + IRCC_SCE_CFGB);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -