📄 smsc-ircc2.c
字号:
&self->rx_buff_dma, GFP_KERNEL); if (self->rx_buff.head == NULL) { IRDA_ERROR("%s, Can't allocate memory for receive buffer!\n", driver_name); goto err_out2; } self->tx_buff.head = dma_alloc_coherent(NULL, self->tx_buff.truesize, &self->tx_buff_dma, GFP_KERNEL); if (self->tx_buff.head == NULL) { IRDA_ERROR("%s, Can't allocate memory for transmit buffer!\n", driver_name); goto err_out3; } memset(self->rx_buff.head, 0, self->rx_buff.truesize); memset(self->tx_buff.head, 0, self->tx_buff.truesize); self->rx_buff.in_frame = FALSE; self->rx_buff.state = OUTSIDE_FRAME; self->tx_buff.data = self->tx_buff.head; self->rx_buff.data = self->rx_buff.head; smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq); smsc_ircc_setup_qos(self); smsc_ircc_init_chip(self); if (ircc_transceiver > 0 && ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS) self->transceiver = ircc_transceiver; else smsc_ircc_probe_transceiver(self); err = register_netdev(self->netdev); if (err) { IRDA_ERROR("%s, Network device registration failed!\n", driver_name); goto err_out4; } self->pldev = platform_device_register_simple(SMSC_IRCC2_DRIVER_NAME, dev_count, NULL, 0); if (IS_ERR(self->pldev)) { err = PTR_ERR(self->pldev); goto err_out5; } platform_set_drvdata(self->pldev, self); IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name); dev_count++; return 0; err_out5: unregister_netdev(self->netdev); err_out4: dma_free_coherent(NULL, self->tx_buff.truesize, self->tx_buff.head, self->tx_buff_dma); err_out3: dma_free_coherent(NULL, self->rx_buff.truesize, self->rx_buff.head, self->rx_buff_dma); err_out2: free_netdev(self->netdev); dev_self[dev_count] = NULL; err_out1: release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT); release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT); err_out: return err;}/* * Function smsc_ircc_present(fir_base, sir_base) * * Check the smsc-ircc chip presence * */static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base){ unsigned char low, high, chip, config, dma, irq, version; if (!request_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT, driver_name)) { IRDA_WARNING("%s: can't get fir_base of 0x%03x\n", __FUNCTION__, fir_base); goto out1; } if (!request_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT, driver_name)) { IRDA_WARNING("%s: can't get sir_base of 0x%03x\n", __FUNCTION__, sir_base); goto out2; } register_bank(fir_base, 3); high = inb(fir_base + IRCC_ID_HIGH); low = inb(fir_base + IRCC_ID_LOW); chip = inb(fir_base + IRCC_CHIP_ID); version = inb(fir_base + IRCC_VERSION); config = inb(fir_base + IRCC_INTERFACE); dma = config & IRCC_INTERFACE_DMA_MASK; irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4; if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) { IRDA_WARNING("%s(), addr 0x%04x - no device found!\n", __FUNCTION__, fir_base); goto out3; } IRDA_MESSAGE("SMsC IrDA Controller found\n IrCC version %d.%d, " "firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n", chip & 0x0f, version, fir_base, sir_base, dma, irq); return 0; out3: release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT); out2: release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT); out1: return -ENODEV;}/* * Function smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq) * * Setup I/O * */static void smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq){ unsigned char config, chip_dma, chip_irq; register_bank(fir_base, 3); config = inb(fir_base + IRCC_INTERFACE); chip_dma = config & IRCC_INTERFACE_DMA_MASK; chip_irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4; self->io.fir_base = fir_base; self->io.sir_base = sir_base; self->io.fir_ext = SMSC_IRCC2_FIR_CHIP_IO_EXTENT; self->io.sir_ext = SMSC_IRCC2_SIR_CHIP_IO_EXTENT; self->io.fifo_size = SMSC_IRCC2_FIFO_SIZE; 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 = self->io.fir_base; 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) | IRCC_CFGA_IRDA_SIR_A), 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), iobase + IRCC_CONTROL); register_bank(iobase, 0); outb(0, 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__);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -