📄 ali-ircc.c
字号:
/* Should be 0x00 in the M1535/M1535D */ if(version != 0x00) { IRDA_ERROR("%s, Wrong chip version %02x\n", ALI_IRCC_DRIVER_NAME, version); return -1; } /* Set FIR FIFO Threshold Register */ switch_bank(iobase, BANK1); outb(RX_FIFO_Threshold, iobase+FIR_FIFO_TR); /* Set FIR DMA Threshold Register */ outb(RX_DMA_Threshold, iobase+FIR_DMA_TR); /* CRC enable */ switch_bank(iobase, BANK2); outb(inb(iobase+FIR_IRDA_CR) | IRDA_CR_CRC, iobase+FIR_IRDA_CR); /* NDIS driver set TX Length here BANK2 Alias 3, Alias4*/ /* Switch to Bank 0 */ switch_bank(iobase, BANK0); tmp = inb(iobase+FIR_LCR_B); tmp &=~0x20; // disable SIP tmp |= 0x80; // these two steps make RX mode tmp &= 0xbf; outb(tmp, iobase+FIR_LCR_B); /* Disable Interrupt */ outb(0x00, iobase+FIR_IER); /* Switch to SIR space */ FIR2SIR(iobase); IRDA_MESSAGE("%s, driver loaded (Benjamin Kong)\n", ALI_IRCC_DRIVER_NAME); /* Enable receive interrupts */ // outb(UART_IER_RDI, iobase+UART_IER); //benjamin 2000/11/23 01:25PM // Turn on the interrupts in ali_ircc_net_open IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); return 0;}/* * Function ali_ircc_read_dongle_id (int index, info) * * Try to read dongle indentification. This procedure needs to be executed * once after power-on/reset. It also needs to be used whenever you suspect * that the user may have plugged/unplugged the IrDA Dongle. */static int ali_ircc_read_dongle_id (int i, chipio_t *info){ int dongle_id, reg; int cfg_base = info->cfg_base; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); /* Enter Configuration */ outb(chips[i].entr1, cfg_base); outb(chips[i].entr2, cfg_base); /* Select Logical Device 5 Registers (UART2) */ outb(0x07, cfg_base); outb(0x05, cfg_base+1); /* Read Dongle ID */ outb(0xf0, cfg_base); reg = inb(cfg_base+1); dongle_id = ((reg>>6)&0x02) | ((reg>>5)&0x01); IRDA_DEBUG(2, "%s(), probing dongle_id=%d, dongle_types=%s\n", __FUNCTION__, dongle_id, dongle_types[dongle_id]); /* Exit configuration */ outb(0xbb, cfg_base); IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); return dongle_id;}/* * Function ali_ircc_interrupt (irq, dev_id, regs) * * An interrupt from the chip has arrived. Time to do some work * */static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id){ struct net_device *dev = dev_id; struct ali_ircc_cb *self; int ret; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); self = dev->priv; spin_lock(&self->lock); /* Dispatch interrupt handler for the current speed */ if (self->io.speed > 115200) ret = ali_ircc_fir_interrupt(self); else ret = ali_ircc_sir_interrupt(self); spin_unlock(&self->lock); IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); return ret;}/* * Function ali_ircc_fir_interrupt(irq, struct ali_ircc_cb *self) * * Handle MIR/FIR interrupt * */static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self){ __u8 eir, OldMessageCount; int iobase, tmp; IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__); iobase = self->io.fir_base; switch_bank(iobase, BANK0); self->InterruptID = inb(iobase+FIR_IIR); self->BusStatus = inb(iobase+FIR_BSR); OldMessageCount = (self->LineStatus + 1) & 0x07; self->LineStatus = inb(iobase+FIR_LSR); //self->ier = inb(iobase+FIR_IER); 2000/12/1 04:32PM eir = self->InterruptID & self->ier; /* Mask out the interesting ones */ IRDA_DEBUG(1, "%s(), self->InterruptID = %x\n", __FUNCTION__,self->InterruptID); IRDA_DEBUG(1, "%s(), self->LineStatus = %x\n", __FUNCTION__,self->LineStatus); IRDA_DEBUG(1, "%s(), self->ier = %x\n", __FUNCTION__,self->ier); IRDA_DEBUG(1, "%s(), eir = %x\n", __FUNCTION__,eir); /* Disable interrupts */ SetCOMInterrupts(self, FALSE); /* Tx or Rx Interrupt */ if (eir & IIR_EOM) { if (self->io.direction == IO_XMIT) /* TX */ { IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Tx) *******\n", __FUNCTION__); if(ali_ircc_dma_xmit_complete(self)) { if (irda_device_txqueue_empty(self->netdev)) { /* Prepare for receive */ ali_ircc_dma_receive(self); self->ier = IER_EOM; } } else { self->ier = IER_EOM; } } else /* RX */ { IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Rx) *******\n", __FUNCTION__); if(OldMessageCount > ((self->LineStatus+1) & 0x07)) { self->rcvFramesOverflow = TRUE; IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******** \n", __FUNCTION__); } if (ali_ircc_dma_receive_complete(self)) { IRDA_DEBUG(1, "%s(), ******* receive complete ******** \n", __FUNCTION__); self->ier = IER_EOM; } else { IRDA_DEBUG(1, "%s(), ******* Not receive complete ******** \n", __FUNCTION__); self->ier = IER_EOM | IER_TIMER; } } } /* Timer Interrupt */ else if (eir & IIR_TIMER) { if(OldMessageCount > ((self->LineStatus+1) & 0x07)) { self->rcvFramesOverflow = TRUE; IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******* \n", __FUNCTION__); } /* Disable Timer */ switch_bank(iobase, BANK1); tmp = inb(iobase+FIR_CR); outb( tmp& ~CR_TIMER_EN, iobase+FIR_CR); /* Check if this is a Tx timer interrupt */ if (self->io.direction == IO_XMIT) { ali_ircc_dma_xmit(self); /* Interrupt on EOM */ self->ier = IER_EOM; } else /* Rx */ { if(ali_ircc_dma_receive_complete(self)) { self->ier = IER_EOM; } else { self->ier = IER_EOM | IER_TIMER; } } } /* Restore Interrupt */ SetCOMInterrupts(self, TRUE); IRDA_DEBUG(1, "%s(), ----------------- End ---------------\n", __FUNCTION__); return IRQ_RETVAL(eir);}/* * Function ali_ircc_sir_interrupt (irq, self, eir) * * Handle SIR interrupt * */static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self){ int iobase; int iir, lsr; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); iobase = self->io.sir_base; iir = inb(iobase+UART_IIR) & UART_IIR_ID; if (iir) { /* Clear interrupt */ lsr = inb(iobase+UART_LSR); IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", __FUNCTION__, iir, lsr, iobase); switch (iir) { case UART_IIR_RLSI: IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__); break; case UART_IIR_RDI: /* Receive interrupt */ ali_ircc_sir_receive(self); break; case UART_IIR_THRI: if (lsr & UART_LSR_THRE) { /* Transmitter ready for data */ ali_ircc_sir_write_wakeup(self); } break; default: IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __FUNCTION__, iir); break; } } IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); return IRQ_RETVAL(iir);}/* * Function ali_ircc_sir_receive (self) * * Receive one frame from the infrared port * */static void ali_ircc_sir_receive(struct ali_ircc_cb *self) { int boguscount = 0; int iobase; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); iobase = self->io.sir_base; /* * Receive all characters in Rx FIFO, unwrap and unstuff them. * async_unwrap_char will deliver all found frames */ do { async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, inb(iobase+UART_RX)); /* Make sure we don't stay here too long */ if (boguscount++ > 32) { IRDA_DEBUG(2,"%s(), breaking!\n", __FUNCTION__); break; } } while (inb(iobase+UART_LSR) & UART_LSR_DR); IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); }/* * Function ali_ircc_sir_write_wakeup (tty) * * Called by the driver when there's room for more data. If we have * more packets to send, we send them here. * */static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self){ int actual = 0; int iobase; IRDA_ASSERT(self != NULL, return;); IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); iobase = self->io.sir_base; /* Finished with frame? */ if (self->tx_buff.len > 0) { /* Write data left in transmit buffer */ actual = ali_ircc_sir_write(iobase, self->io.fifo_size, self->tx_buff.data, self->tx_buff.len); self->tx_buff.data += actual; self->tx_buff.len -= actual; } else { if (self->new_speed) { /* We must wait until all data are gone */ while(!(inb(iobase+UART_LSR) & UART_LSR_TEMT)) IRDA_DEBUG(1, "%s(), UART_LSR_THRE\n", __FUNCTION__ ); IRDA_DEBUG(1, "%s(), Changing speed! self->new_speed = %d\n", __FUNCTION__ , self->new_speed); ali_ircc_change_speed(self, self->new_speed); self->new_speed = 0; // benjamin 2000/11/10 06:32PM if (self->io.speed > 115200) { IRDA_DEBUG(2, "%s(), ali_ircc_change_speed from UART_LSR_TEMT \n", __FUNCTION__ ); self->ier = IER_EOM; // SetCOMInterrupts(self, TRUE); return; } } else { netif_wake_queue(self->netdev); } self->stats.tx_packets++; /* Turn on receive interrupts */ outb(UART_IER_RDI, iobase+UART_IER); } IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); }static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud){ struct net_device *dev = self->netdev; int iobase; IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); IRDA_DEBUG(2, "%s(), setting speed = %d \n", __FUNCTION__ , baud); /* This function *must* be called with irq off and spin-lock. * - Jean II */ iobase = self->io.fir_base; SetCOMInterrupts(self, FALSE); // 2000/11/24 11:43AM /* Go to MIR, FIR Speed */ if (baud > 115200) { ali_ircc_fir_change_speed(self, baud); /* Install FIR xmit handler*/ dev->hard_start_xmit = ali_ircc_fir_hard_xmit; /* Enable Interuupt */ self->ier = IER_EOM; // benjamin 2000/11/20 07:24PM /* Be ready for incomming frames */ ali_ircc_dma_receive(self); // benajmin 2000/11/8 07:46PM not complete } /* Go to SIR Speed */ else { ali_ircc_sir_change_speed(self, baud); /* Install SIR xmit handler*/ dev->hard_start_xmit = ali_ircc_sir_hard_xmit; } SetCOMInterrupts(self, TRUE); // 2000/11/24 11:43AM netif_wake_queue(self->netdev); IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); }static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud){ int iobase; struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv; struct net_device *dev; IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); IRDA_ASSERT(self != NULL, return;); dev = self->netdev; iobase = self->io.fir_base; IRDA_DEBUG(1, "%s(), self->io.speed = %d, change to speed = %d\n", __FUNCTION__ ,self->io.speed,baud); /* Come from SIR speed */ if(self->io.speed <=115200) { SIR2FIR(iobase); } /* Update accounting for new speed */ self->io.speed = baud; // Set Dongle Speed mode ali_ircc_change_dongle_speed(self, baud); IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); }/* * Function ali_sir_change_speed (self, speed) * * Set speed of IrDA port to specified baudrate * */static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed){ struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv; unsigned long flags; int iobase; int fcr; /* FIFO control reg */ int lcr; /* Line control reg */ int divisor; IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); IRDA_DEBUG(1, "%s(), Setting speed to: %d\n", __FUNCTION__ , speed); IRDA_ASSERT(self != NULL, return;); iobase = self->io.sir_base; /* Come from MIR or FIR speed */ if(self->io.speed >115200) { // Set Dongle Speed mode first ali_ircc_change_dongle_speed(self, speed); FIR2SIR(iobase); } // Clear Line and Auxiluary status registers 2000/11/24 11:47AM inb(iobase+UART_LSR); inb(iobase+UART_SCR); /* Update accounting for new speed */ self->io.speed = speed; spin_lock_irqsave(&self->lock, flags); divisor = 115200/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. */ if (self->io.speed < 38400) fcr |= UART_FCR_TRIGGER_1; else fcr |= 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 */ /* without this, the conection will be broken after come back from FIR speed, but with this, the SIR connection is harder to established */ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR); spin_unlock_irqrestore(&self->lock, flags); IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); }static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed){ struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv; int iobase,dongle_id; int tmp = 0; IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); iobase = self->io.fir_base; /* or iobase = self->io.sir_base; */ dongle_id = self->io.dongle_id; /* We are already locked, no need to do it again */ IRDA_DEBUG(1, "%s(), Set Speed for %s , Speed = %d\n", __FUNCTION__ , dongle_types[dongle_id], speed); switch_bank(iobase, BANK2); tmp = inb(iobase+FIR_IRDA_CR); /* IBM type dongle */ if(dongle_id == 0) { if(speed == 4000000) { // __ __ // SD/MODE __| |__ __ // __ __
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -