📄 ali-ircc.c
字号:
switch_bank(iobase, BANK0); IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); return ret;}/* * Function ali_ircc_dma_receive (self) * * Get ready for receiving a frame. The device will initiate a DMA * if it starts to receive a frame. * */static int ali_ircc_dma_receive(struct ali_ircc_cb *self) { int iobase, tmp; IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__ ); iobase = self->io.fir_base; /* 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; /* Disable DMA */ switch_bank(iobase, BANK1); outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR); /* Reset Message Count */ switch_bank(iobase, BANK0); outb(0x07, iobase+FIR_LSR); self->rcvFramesOverflow = FALSE; self->LineStatus = inb(iobase+FIR_LSR) ; /* Reset Rx FIFO info */ self->io.direction = IO_RECV; self->rx_buff.data = self->rx_buff.head; /* Reset Rx FIFO */ // switch_bank(iobase, BANK0); outb(LCR_A_FIFO_RESET, iobase+FIR_LCR_A); self->st_fifo.len = self->st_fifo.pending_bytes = 0; self->st_fifo.tail = self->st_fifo.head = 0; irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize, DMA_RX_MODE); /* Set Receive Mode,Brick Wall */ //switch_bank(iobase, BANK0); tmp = inb(iobase+FIR_LCR_B); outb((unsigned char)(tmp &0x3f) | LCR_B_RX_MODE | LCR_B_BW , iobase + FIR_LCR_B); // 2000/12/1 05:16PM IRDA_DEBUG(1, "%s(), *** Change To RX mode: FIR_LCR_B = 0x%x *** \n", __FUNCTION__ , inb(iobase+FIR_LCR_B)); /* Set Rx Threshold */ switch_bank(iobase, BANK1); outb(RX_FIFO_Threshold, iobase+FIR_FIFO_TR); outb(RX_DMA_Threshold, iobase+FIR_DMA_TR); /* Enable DMA and Burst Mode */ // switch_bank(iobase, BANK1); outb(CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR); switch_bank(iobase, BANK0); IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); return 0;}static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self){ struct st_fifo *st_fifo; struct sk_buff *skb; __u8 status, MessageCount; int len, i, iobase, val; IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__ ); st_fifo = &self->st_fifo; iobase = self->io.fir_base; switch_bank(iobase, BANK0); MessageCount = inb(iobase+ FIR_LSR)&0x07; if (MessageCount > 0) IRDA_DEBUG(0, "%s(), Messsage count = %d,\n", __FUNCTION__ , MessageCount); for (i=0; i<=MessageCount; i++) { /* Bank 0 */ switch_bank(iobase, BANK0); status = inb(iobase+FIR_LSR); switch_bank(iobase, BANK2); len = inb(iobase+FIR_RX_DSR_HI) & 0x0f; len = len << 8; len |= inb(iobase+FIR_RX_DSR_LO); IRDA_DEBUG(1, "%s(), RX Length = 0x%.2x,\n", __FUNCTION__ , len); IRDA_DEBUG(1, "%s(), RX Status = 0x%.2x,\n", __FUNCTION__ , status); if (st_fifo->tail >= MAX_RX_WINDOW) { IRDA_DEBUG(0, "%s(), window is full!\n", __FUNCTION__ ); continue; } st_fifo->entries[st_fifo->tail].status = status; st_fifo->entries[st_fifo->tail].len = len; st_fifo->pending_bytes += len; st_fifo->tail++; st_fifo->len++; } for (i=0; i<=MessageCount; i++) { /* Get first entry */ status = st_fifo->entries[st_fifo->head].status; len = st_fifo->entries[st_fifo->head].len; st_fifo->pending_bytes -= len; st_fifo->head++; st_fifo->len--; /* Check for errors */ if ((status & 0xd8) || self->rcvFramesOverflow || (len==0)) { IRDA_DEBUG(0,"%s(), ************* RX Errors ************ \n", __FUNCTION__ ); /* Skip frame */ self->stats.rx_errors++; self->rx_buff.data += len; if (status & LSR_FIFO_UR) { self->stats.rx_frame_errors++; IRDA_DEBUG(0,"%s(), ************* FIFO Errors ************ \n", __FUNCTION__ ); } if (status & LSR_FRAME_ERROR) { self->stats.rx_frame_errors++; IRDA_DEBUG(0,"%s(), ************* FRAME Errors ************ \n", __FUNCTION__ ); } if (status & LSR_CRC_ERROR) { self->stats.rx_crc_errors++; IRDA_DEBUG(0,"%s(), ************* CRC Errors ************ \n", __FUNCTION__ ); } if(self->rcvFramesOverflow) { self->stats.rx_frame_errors++; IRDA_DEBUG(0,"%s(), ************* Overran DMA buffer ************ \n", __FUNCTION__ ); } if(len == 0) { self->stats.rx_frame_errors++; IRDA_DEBUG(0,"%s(), ********** Receive Frame Size = 0 ********* \n", __FUNCTION__ ); } } else { if (st_fifo->pending_bytes < 32) { switch_bank(iobase, BANK0); val = inb(iobase+FIR_BSR); if ((val& BSR_FIFO_NOT_EMPTY)== 0x80) { IRDA_DEBUG(0, "%s(), ************* BSR_FIFO_NOT_EMPTY ************ \n", __FUNCTION__ ); /* Put this entry back in fifo */ st_fifo->head--; st_fifo->len++; st_fifo->pending_bytes += len; st_fifo->entries[st_fifo->head].status = status; st_fifo->entries[st_fifo->head].len = len; /* * DMA not finished yet, so try again * later, set timer value, resolution * 500 us */ switch_bank(iobase, BANK1); outb(TIMER_IIR_500, iobase+FIR_TIMER_IIR); // 2001/1/2 05:07PM /* Enable Timer */ outb(inb(iobase+FIR_CR) | CR_TIMER_EN, iobase+FIR_CR); return FALSE; /* I'll be back! */ } } /* * Remember the time we received this frame, so we can * reduce the min turn time a bit since we will know * how much time we have used for protocol processing */ do_gettimeofday(&self->stamp); skb = dev_alloc_skb(len+1); if (skb == NULL) { IRDA_WARNING("%s(), memory squeeze, " "dropping frame.\n", __FUNCTION__); self->stats.rx_dropped++; return FALSE; } /* Make sure IP header gets aligned */ skb_reserve(skb, 1); /* Copy frame without CRC, CRC is removed by hardware*/ skb_put(skb, len); memcpy(skb->data, self->rx_buff.data, len); /* Move to next frame */ self->rx_buff.data += len; self->stats.rx_bytes += 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; } } switch_bank(iobase, BANK0); IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); return TRUE;}/* * Function ali_ircc_sir_hard_xmit (skb, dev) * * Transmit the frame! * */static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev){ struct ali_ircc_cb *self; unsigned long flags; int iobase; __u32 speed; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); IRDA_ASSERT(dev != NULL, return 0;); self = (struct ali_ircc_cb *) dev->priv; IRDA_ASSERT(self != NULL, return 0;); iobase = self->io.sir_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; } /* 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, iobase+UART_IER); dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); return 0; }/* * Function ali_ircc_net_ioctl (dev, rq, cmd) * * Process IOCTL commands for this device * */static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct if_irda_req *irq = (struct if_irda_req *) rq; struct ali_ircc_cb *self; unsigned long flags; int ret = 0; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); 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); switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ IRDA_DEBUG(1, "%s(), SIOCSBANDWIDTH\n", __FUNCTION__ ); /* * This function will also be used by IrLAP to change the * speed, so we still must allow for speed change within * interrupt context. */ if (!in_interrupt() && !capable(CAP_NET_ADMIN)) return -EPERM; spin_lock_irqsave(&self->lock, flags); ali_ircc_change_speed(self, irq->ifr_baudrate); spin_unlock_irqrestore(&self->lock, flags); break; case SIOCSMEDIABUSY: /* Set media busy */ IRDA_DEBUG(1, "%s(), SIOCSMEDIABUSY\n", __FUNCTION__ ); if (!capable(CAP_NET_ADMIN)) return -EPERM; irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ IRDA_DEBUG(2, "%s(), SIOCGRECEIVING\n", __FUNCTION__ ); /* This is protected */ irq->ifr_receiving = ali_ircc_is_receiving(self); break; default: ret = -EOPNOTSUPP; } IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); return ret;}/* * Function ali_ircc_is_receiving (self) * * Return TRUE is we are currently receiving a frame * */static int ali_ircc_is_receiving(struct ali_ircc_cb *self){ unsigned long flags; int status = FALSE; int iobase; IRDA_DEBUG(2, "%s(), ---------------- Start -----------------\n", __FUNCTION__ ); IRDA_ASSERT(self != NULL, return FALSE;); spin_lock_irqsave(&self->lock, flags); if (self->io.speed > 115200) { iobase = self->io.fir_base; switch_bank(iobase, BANK1); if((inb(iobase+FIR_FIFO_FR) & 0x3f) != 0) { /* We are receiving something */ IRDA_DEBUG(1, "%s(), We are receiving something\n", __FUNCTION__ ); status = TRUE; } switch_bank(iobase, BANK0); } else { status = (self->rx_buff.state != OUTSIDE_FRAME); } spin_unlock_irqrestore(&self->lock, flags); IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); return status;}static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev){ struct ali_ircc_cb *self = (struct ali_ircc_cb *) dev->priv; IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); return &self->stats;}static int ali_ircc_suspend(struct platform_device *dev, pm_message_t state){ struct ali_ircc_cb *self = platform_get_drvdata(dev); IRDA_MESSAGE("%s, Suspending\n", ALI_IRCC_DRIVER_NAME); if (self->io.suspended) return 0; ali_ircc_net_close(self->netdev); self->io.suspended = 1; return 0;}static int ali_ircc_resume(struct platform_device *dev){ struct ali_ircc_cb *self = platform_get_drvdata(dev); if (!self->io.suspended) return 0; ali_ircc_net_open(self->netdev); IRDA_MESSAGE("%s, Waking up\n", ALI_IRCC_DRIVER_NAME); self->io.suspended = 0; return 0;}/* ALi Chip Function */static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable){ unsigned char newMask; int iobase = self->io.fir_base; /* or sir_base */ IRDA_DEBUG(2, "%s(), -------- Start -------- ( Enable = %d )\n", __FUNCTION__ , enable); /* Enable the interrupt which we wish to */ if (enable){ if (self->io.direction == IO_XMIT) { if (self->io.speed > 115200) /* FIR, MIR */ { newMask = self->ier; } else /* SIR */ { newMask = UART_IER_THRI | UART_IER_RDI; } } else { if (self->io.speed > 115200) /* FIR, MIR */ { newMask = self->ier; } else /* SIR */ { newMask = UART_IER_RDI; } } } else /* Disable all the interrupts */ { newMask = 0x00; } //SIR and FIR has different registers if (self->io.speed > 115200) { switch_bank(iobase, BANK0); outb(newMask, iobase+FIR_IER); } else outb(newMask, iobase+UART_IER); IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); }static void SIR2FIR(int iobase){ //unsigned char tmp; IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); /* Already protected (change_speed() or setup()), no need to lock. * Jean II */ outb(0x28, iobase+UART_MCR); outb(0x68, iobase+UART_MCR); outb(0x88, iobase+UART_MCR); outb(0x60, iobase+FIR_MCR); /* Master Reset */ outb(0x20, iobase+FIR_MCR); /* Master Interrupt Enable */ //tmp = inb(iobase+FIR_LCR_B); /* SIP enable */ //tmp |= 0x20; //outb(tmp, iobase+FIR_LCR_B); IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); }static void FIR2SIR(int iobase){ unsigned char val; IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); /* Already protected (change_speed() or setup()), no need to lock. * Jean II */ outb(0x20, iobase+FIR_MCR); /* IRQ to low */ outb(0x00, iobase+UART_IER); outb(0xA0, iobase+FIR_MCR); /* Don't set master reset */ outb(0x00, iobase+UART_FCR); outb(0x07, iobase+UART_FCR); val = inb(iobase+UART_RX); val = inb(iobase+UART_LSR); val = inb(iobase+UART_MSR); IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ );}MODULE_AUTHOR("Benjamin Kong <benjamin_kong@ali.com.tw>");MODULE_DESCRIPTION("ALi FIR Controller Driver");MODULE_LICENSE("GPL");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");module_param_array(dma, int, NULL, 0);MODULE_PARM_DESC(dma, "DMA channels");module_init(ali_ircc_init);module_exit(ali_ircc_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -