📄 ali-ircc.c
字号:
// IRTX __ __| |__ // T1 T2 T3 T4 T5 tmp &= ~IRDA_CR_HDLC; // HDLC=0 tmp |= IRDA_CR_CRC; // CRC=1 switch_bank(iobase, BANK2); outb(tmp, iobase+FIR_IRDA_CR); // T1 -> SD/MODE:0 IRTX:0 tmp &= ~0x09; tmp |= 0x02; outb(tmp, iobase+FIR_IRDA_CR); udelay(2); // T2 -> SD/MODE:1 IRTX:0 tmp &= ~0x01; tmp |= 0x0a; outb(tmp, iobase+FIR_IRDA_CR); udelay(2); // T3 -> SD/MODE:1 IRTX:1 tmp |= 0x0b; outb(tmp, iobase+FIR_IRDA_CR); udelay(2); // T4 -> SD/MODE:0 IRTX:1 tmp &= ~0x08; tmp |= 0x03; outb(tmp, iobase+FIR_IRDA_CR); udelay(2); // T5 -> SD/MODE:0 IRTX:0 tmp &= ~0x09; tmp |= 0x02; outb(tmp, iobase+FIR_IRDA_CR); udelay(2); // reset -> Normal TX output Signal outb(tmp & ~0x02, iobase+FIR_IRDA_CR); } else /* speed <=1152000 */ { // __ // SD/MODE __| |__ // // IRTX ________ // T1 T2 T3 /* MIR 115200, 57600 */ if (speed==1152000) { tmp |= 0xA0; //HDLC=1, 1.152Mbps=1 } else { tmp &=~0x80; //HDLC 0.576Mbps tmp |= 0x20; //HDLC=1, } tmp |= IRDA_CR_CRC; // CRC=1 switch_bank(iobase, BANK2); outb(tmp, iobase+FIR_IRDA_CR); /* MIR 115200, 57600 */ //switch_bank(iobase, BANK2); // T1 -> SD/MODE:0 IRTX:0 tmp &= ~0x09; tmp |= 0x02; outb(tmp, iobase+FIR_IRDA_CR); udelay(2); // T2 -> SD/MODE:1 IRTX:0 tmp &= ~0x01; tmp |= 0x0a; outb(tmp, iobase+FIR_IRDA_CR); // T3 -> SD/MODE:0 IRTX:0 tmp &= ~0x09; tmp |= 0x02; outb(tmp, iobase+FIR_IRDA_CR); udelay(2); // reset -> Normal TX output Signal outb(tmp & ~0x02, iobase+FIR_IRDA_CR); } } else if (dongle_id == 1) /* HP HDSL-3600 */ { switch(speed) { case 4000000: tmp &= ~IRDA_CR_HDLC; // HDLC=0 break; case 1152000: tmp |= 0xA0; // HDLC=1, 1.152Mbps=1 break; case 576000: tmp &=~0x80; // HDLC 0.576Mbps tmp |= 0x20; // HDLC=1, break; } tmp |= IRDA_CR_CRC; // CRC=1 switch_bank(iobase, BANK2); outb(tmp, iobase+FIR_IRDA_CR); } else /* HP HDSL-1100 */ { if(speed <= 115200) /* SIR */ { tmp &= ~IRDA_CR_FIR_SIN; // HP sin select = 0 switch_bank(iobase, BANK2); outb(tmp, iobase+FIR_IRDA_CR); } else /* MIR FIR */ { switch(speed) { case 4000000: tmp &= ~IRDA_CR_HDLC; // HDLC=0 break; case 1152000: tmp |= 0xA0; // HDLC=1, 1.152Mbps=1 break; case 576000: tmp &=~0x80; // HDLC 0.576Mbps tmp |= 0x20; // HDLC=1, break; } tmp |= IRDA_CR_CRC; // CRC=1 tmp |= IRDA_CR_FIR_SIN; // HP sin select = 1 switch_bank(iobase, BANK2); outb(tmp, iobase+FIR_IRDA_CR); } } switch_bank(iobase, BANK0); IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); }/* * Function ali_ircc_sir_write (driver) * * Fill Tx FIFO with transmit data * */static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len){ int actual = 0; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); /* Tx FIFO should be empty! */ if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { IRDA_DEBUG(0, "%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++; } IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); return actual;}/* * Function ali_ircc_net_open (dev) * * Start the device * */static int ali_ircc_net_open(struct net_device *dev){ struct ali_ircc_cb *self; int iobase; char hwname[32]; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); IRDA_ASSERT(dev != NULL, return -1;); self = (struct ali_ircc_cb *) dev->priv; IRDA_ASSERT(self != NULL, return 0;); iobase = self->io.fir_base; /* Request IRQ and install Interrupt Handler */ if (request_irq(self->io.irq, ali_ircc_interrupt, 0, dev->name, dev)) { IRDA_WARNING("%s, unable to allocate irq=%d\n", ALI_IRCC_DRIVER_NAME, self->io.irq); return -EAGAIN; } /* * Always allocate the DMA channel after the IRQ, and clean up on * failure. */ if (request_dma(self->io.dma, dev->name)) { IRDA_WARNING("%s, unable to allocate dma=%d\n", ALI_IRCC_DRIVER_NAME, self->io.dma); free_irq(self->io.irq, self); return -EAGAIN; } /* Turn on interrups */ outb(UART_IER_RDI , iobase+UART_IER); /* Ready to play! */ netif_start_queue(dev); //benjamin by irport /* Give self a hardware name */ sprintf(hwname, "ALI-FIR @ 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); IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); return 0;}/* * Function ali_ircc_net_close (dev) * * Stop the device * */static int ali_ircc_net_close(struct net_device *dev){ struct ali_ircc_cb *self; //int iobase; IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); IRDA_ASSERT(dev != NULL, return -1;); self = (struct ali_ircc_cb *) dev->priv; 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; disable_dma(self->io.dma); /* Disable interrupts */ SetCOMInterrupts(self, FALSE); free_irq(self->io.irq, dev); free_dma(self->io.dma); IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); return 0;}/* * Function ali_ircc_fir_hard_xmit (skb, dev) * * Transmit the frame * */static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev){ struct ali_ircc_cb *self; unsigned long flags; int iobase; __u32 speed; int mtt, diff; IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__ ); self = (struct ali_ircc_cb *) dev->priv; iobase = self->io.fir_base; netif_stop_queue(dev); /* Make sure tests *& speed change are atomic */ spin_lock_irqsave(&self->lock, flags); /* 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 */ /* 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) { ali_ircc_change_speed(self, speed); dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); return 0; } else self->new_speed = speed; } /* Register and copy this frame to DMA memory */ self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail; self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; self->tx_fifo.tail += skb->len; self->stats.tx_bytes += skb->len; memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, skb->len); self->tx_fifo.len++; self->tx_fifo.free++; /* Start transmit only if there is currently no transmit going on */ if (self->tx_fifo.len == 1) { /* Check if we must wait the min turn time or not */ mtt = irda_get_mtt(skb); if (mtt) { /* Check how much time we have used already */ do_gettimeofday(&self->now); diff = self->now.tv_usec - self->stamp.tv_usec; /* self->stamp is set from ali_ircc_dma_receive_complete() */ IRDA_DEBUG(1, "%s(), ******* diff = %d ******* \n", __FUNCTION__ , diff); if (diff < 0) diff += 1000000; /* Check if the mtt is larger than the time we have * already used by all the protocol processing */ if (mtt > diff) { mtt -= diff; /* * Use timer if delay larger than 1000 us, and * use udelay for smaller values which should * be acceptable */ if (mtt > 500) { /* Adjust for timer resolution */ mtt = (mtt+250) / 500; /* 4 discard, 5 get advanced, Let's round off */ IRDA_DEBUG(1, "%s(), ************** mtt = %d ***********\n", __FUNCTION__ , mtt); /* Setup timer */ if (mtt == 1) /* 500 us */ { switch_bank(iobase, BANK1); outb(TIMER_IIR_500, iobase+FIR_TIMER_IIR); } else if (mtt == 2) /* 1 ms */ { switch_bank(iobase, BANK1); outb(TIMER_IIR_1ms, iobase+FIR_TIMER_IIR); } else /* > 2ms -> 4ms */ { switch_bank(iobase, BANK1); outb(TIMER_IIR_2ms, iobase+FIR_TIMER_IIR); } /* Start timer */ outb(inb(iobase+FIR_CR) | CR_TIMER_EN, iobase+FIR_CR); self->io.direction = IO_XMIT; /* Enable timer interrupt */ self->ier = IER_TIMER; SetCOMInterrupts(self, TRUE); /* Timer will take care of the rest */ goto out; } else udelay(mtt); } // if (if (mtt > diff) }// if (mtt) /* Enable EOM interrupt */ self->ier = IER_EOM; SetCOMInterrupts(self, TRUE); /* Transmit frame */ ali_ircc_dma_xmit(self); } // if (self->tx_fifo.len == 1) out: /* Not busy transmitting anymore if window is not full */ if (self->tx_fifo.free < MAX_TX_WINDOW) netif_wake_queue(self->netdev); /* Restore bank register */ switch_bank(iobase, BANK0); dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); return 0; }static void ali_ircc_dma_xmit(struct ali_ircc_cb *self){ int iobase, tmp; unsigned char FIFO_OPTI, Hi, Lo; IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__ ); iobase = self->io.fir_base; /* FIFO threshold , this method comes from NDIS5 code */ if(self->tx_fifo.queue[self->tx_fifo.ptr].len < TX_FIFO_Threshold) FIFO_OPTI = self->tx_fifo.queue[self->tx_fifo.ptr].len-1; else FIFO_OPTI = TX_FIFO_Threshold; /* Disable DMA */ switch_bank(iobase, BANK1); outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR); self->io.direction = IO_XMIT; irda_setup_dma(self->io.dma, ((u8 *)self->tx_fifo.queue[self->tx_fifo.ptr].start - self->tx_buff.head) + self->tx_buff_dma, self->tx_fifo.queue[self->tx_fifo.ptr].len, DMA_TX_MODE); /* Reset Tx FIFO */ switch_bank(iobase, BANK0); outb(LCR_A_FIFO_RESET, iobase+FIR_LCR_A); /* Set Tx FIFO threshold */ if (self->fifo_opti_buf!=FIFO_OPTI) { switch_bank(iobase, BANK1); outb(FIFO_OPTI, iobase+FIR_FIFO_TR) ; self->fifo_opti_buf=FIFO_OPTI; } /* Set Tx DMA threshold */ switch_bank(iobase, BANK1); outb(TX_DMA_Threshold, iobase+FIR_DMA_TR); /* Set max Tx frame size */ Hi = (self->tx_fifo.queue[self->tx_fifo.ptr].len >> 8) & 0x0f; Lo = self->tx_fifo.queue[self->tx_fifo.ptr].len & 0xff; switch_bank(iobase, BANK2); outb(Hi, iobase+FIR_TX_DSR_HI); outb(Lo, iobase+FIR_TX_DSR_LO); /* Disable SIP , Disable Brick Wall (we don't support in TX mode), Change to TX mode */ switch_bank(iobase, BANK0); tmp = inb(iobase+FIR_LCR_B); tmp &= ~0x20; // Disable SIP outb(((unsigned char)(tmp & 0x3f) | LCR_B_TX_MODE) & ~LCR_B_BW, iobase+FIR_LCR_B); IRDA_DEBUG(1, "%s(), ******* Change to TX mode: FIR_LCR_B = 0x%x ******* \n", __FUNCTION__ , inb(iobase+FIR_LCR_B)); outb(0, iobase+FIR_LSR); /* Enable DMA and Burst Mode */ switch_bank(iobase, BANK1); outb(inb(iobase+FIR_CR) | CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR); switch_bank(iobase, BANK0); IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ );}static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self){ int iobase; int ret = TRUE; IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__ ); iobase = self->io.fir_base; /* Disable DMA */ switch_bank(iobase, BANK1); outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR); /* Check for underrun! */ switch_bank(iobase, BANK0); if((inb(iobase+FIR_LSR) & LSR_FRAME_ABORT) == LSR_FRAME_ABORT) { IRDA_ERROR("%s(), ********* LSR_FRAME_ABORT *********\n", __FUNCTION__); self->stats.tx_errors++; self->stats.tx_fifo_errors++; } else { self->stats.tx_packets++; } /* Check if we need to change the speed */ if (self->new_speed) { ali_ircc_change_speed(self, self->new_speed); self->new_speed = 0; } /* Finished with this frame, so prepare for next */ self->tx_fifo.ptr++; self->tx_fifo.len--; /* Any frames to be sent back-to-back? */ if (self->tx_fifo.len) { ali_ircc_dma_xmit(self); /* Not finished yet! */ ret = FALSE; } else { /* Reset Tx FIFO info */ self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; self->tx_fifo.tail = self->tx_buff.head; } /* Make sure we have room for more frames */ if (self->tx_fifo.free < MAX_TX_WINDOW) { /* Not busy transmitting anymore */ /* Tell the network layer, that we can accept more frames */ netif_wake_queue(self->netdev); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -