📄 vlsi_ir.c
字号:
if (baudrate == 4000000) { mode = IFF_FIR; config = IRCFG_FIR; nphyctl = PHYCTL_FIR; } else if (baudrate == 1152000) { mode = IFF_MIR; config = IRCFG_MIR | IRCFG_CRC16; nphyctl = PHYCTL_MIR(clksrc==3); } else { mode = IFF_SIR; config = IRCFG_SIR | IRCFG_SIRFILT | IRCFG_RXANY; switch(baudrate) { default: printk(KERN_ERR "%s: undefined baudrate %d - fallback to 9600!\n", __FUNCTION__, baudrate); baudrate = 9600; /* fallthru */ case 2400: case 9600: case 19200: case 38400: case 57600: case 115200: nphyctl = PHYCTL_SIR(baudrate,sirpulse,clksrc==3); break; } } config |= IRCFG_MSTR | IRCFG_ENRX; outw(config, iobase+VLSI_PIO_IRCFG); outw(nphyctl, iobase+VLSI_PIO_NPHYCTL); wmb(); outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE); /* chip fetches IRCFG on next rising edge of its 8MHz clock */ mb(); config = inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_MASK; if (mode == IFF_FIR) config ^= IRENABLE_FIR_ON; else if (mode == IFF_MIR) config ^= (IRENABLE_MIR_ON|IRENABLE_CRC16_ON); else config ^= IRENABLE_SIR_ON; if (config != (IRENABLE_IREN|IRENABLE_ENRXST)) { printk(KERN_ERR "%s: failed to set %s mode!\n", __FUNCTION__, (mode==IFF_SIR)?"SIR":((mode==IFF_MIR)?"MIR":"FIR")); ret = -1; } else { if (inw(iobase+VLSI_PIO_PHYCTL) != nphyctl) { printk(KERN_ERR "%s: failed to apply baudrate %d\n", __FUNCTION__, baudrate); ret = -1; } else { idev->mode = mode; idev->baud = baudrate; idev->new_baud = 0; ret = 0; } } spin_unlock_irqrestore(&idev->lock, flags); if (ret) vlsi_reg_debug(iobase,__FUNCTION__); return ret;}static int vlsi_init_chip(struct net_device *ndev){ vlsi_irda_dev_t *idev = ndev->priv; unsigned iobase; u16 ptr; iobase = ndev->base_addr; outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); /* w/c pending IRQ, disable all INT */ outw(0, iobase+VLSI_PIO_IRENABLE); /* disable IrPHY-interface */ /* disable everything, particularly IRCFG_MSTR - which resets the RING_PTR */ outw(0, iobase+VLSI_PIO_IRCFG); wmb(); outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE); mb(); outw(0, iobase+VLSI_PIO_IRENABLE); outw(MAX_PACKET_LENGTH, iobase+VLSI_PIO_MAXPKT); /* max possible value=0x0fff */ outw(BUS_TO_RINGBASE(idev->busaddr), iobase+VLSI_PIO_RINGBASE); outw(TX_RX_TO_RINGSIZE(idev->tx_ring.size, idev->rx_ring.size), iobase+VLSI_PIO_RINGSIZE); ptr = inw(iobase+VLSI_PIO_RINGPTR); idev->rx_ring.head = idev->rx_ring.tail = RINGPTR_GET_RX(ptr); idev->tx_ring.head = idev->tx_ring.tail = RINGPTR_GET_TX(ptr); outw(IRCFG_MSTR, iobase+VLSI_PIO_IRCFG); /* ready for memory access */ wmb(); outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE); mb(); idev->new_baud = 9600; /* start with IrPHY using 9600(SIR) mode */ vlsi_set_baud(ndev); outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); /* just in case - w/c pending IRQ's */ wmb(); /* DO NOT BLINDLY ENABLE IRINTR_ACTEN! * basically every received pulse fires an ACTIVITY-INT * leading to >>1000 INT's per second instead of few 10 */ outb(IRINTR_RPKTEN|IRINTR_TPKTEN, iobase+VLSI_PIO_IRINTR); wmb(); return 0;}/**************************************************************/static void vlsi_refill_rx(struct vlsi_ring *r){ do { if (rd_is_active(r, r->head)) BUG(); rd_activate(r, r->head); ring_put(r); } while (r->head != r->tail);}static int vlsi_rx_interrupt(struct net_device *ndev){ vlsi_irda_dev_t *idev = ndev->priv; struct vlsi_ring *r; int len; u8 status; struct sk_buff *skb; int crclen; r = &idev->rx_ring; while (!rd_is_active(r, r->tail)) { status = rd_get_status(r, r->tail); if (status & RX_STAT_ERROR) { idev->stats.rx_errors++; if (status & RX_STAT_OVER) idev->stats.rx_over_errors++; if (status & RX_STAT_LENGTH) idev->stats.rx_length_errors++; if (status & RX_STAT_PHYERR) idev->stats.rx_frame_errors++; if (status & RX_STAT_CRCERR) idev->stats.rx_crc_errors++; } else { len = rd_get_count(r, r->tail); crclen = (idev->mode==IFF_FIR) ? sizeof(u32) : sizeof(u16); if (len < crclen) printk(KERN_ERR "%s: strange frame (len=%d)\n", __FUNCTION__, len); else len -= crclen; /* remove trailing CRC */ skb = dev_alloc_skb(len+1); if (skb) { skb->dev = ndev; skb_reserve(skb,1); memcpy(skb_put(skb,len), r->buf[r->tail].data, len); idev->stats.rx_packets++; idev->stats.rx_bytes += len; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); } else { idev->stats.rx_dropped++; printk(KERN_ERR "%s: rx packet dropped\n", __FUNCTION__); } } rd_set_count(r, r->tail, 0); rd_set_status(r, r->tail, 0); ring_get(r); if (r->tail == r->head) { printk(KERN_WARNING "%s: rx ring exhausted\n", __FUNCTION__); break; } } do_gettimeofday(&idev->last_rx); /* remember "now" for later mtt delay */ vlsi_refill_rx(r); mb(); outw(0, ndev->base_addr+VLSI_PIO_PROMPT); return 0;}static int vlsi_tx_interrupt(struct net_device *ndev){ vlsi_irda_dev_t *idev = ndev->priv; struct vlsi_ring *r; unsigned iobase; int ret; u16 config; u16 status; r = &idev->tx_ring; while (!rd_is_active(r, r->tail)) { if (r->tail == r->head) break; /* tx ring empty - nothing to send anymore */ status = rd_get_status(r, r->tail); if (status & TX_STAT_UNDRN) { idev->stats.tx_errors++; idev->stats.tx_fifo_errors++; } else { idev->stats.tx_packets++; idev->stats.tx_bytes += rd_get_count(r, r->tail); /* not correct for SIR */ } rd_set_count(r, r->tail, 0); rd_set_status(r, r->tail, 0); if (r->buf[r->tail].skb) { rd_set_addr_status(r, r->tail, 0, 0); dev_kfree_skb(r->buf[r->tail].skb); r->buf[r->tail].skb = NULL; r->buf[r->tail].data = NULL; } ring_get(r); } ret = 0; iobase = ndev->base_addr; if (r->head == r->tail) { /* tx ring empty: re-enable rx */ outw(0, iobase+VLSI_PIO_IRENABLE); config = inw(iobase+VLSI_PIO_IRCFG); mb(); outw((config & ~IRCFG_ENTX) | IRCFG_ENRX, iobase+VLSI_PIO_IRCFG); wmb(); outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE); } else ret = 1; /* no speed-change-check */ mb(); outw(0, iobase+VLSI_PIO_PROMPT); if (netif_queue_stopped(ndev)) { netif_wake_queue(ndev); printk(KERN_DEBUG "%s: queue awoken\n", __FUNCTION__); } return ret;}#if 0 /* disable ACTIVITY handling for now */static int vlsi_act_interrupt(struct net_device *ndev){ printk(KERN_DEBUG "%s\n", __FUNCTION__); return 0;}#endifstatic void vlsi_interrupt(int irq, void *dev_instance, struct pt_regs *regs){ struct net_device *ndev = dev_instance; vlsi_irda_dev_t *idev = ndev->priv; unsigned iobase; u8 irintr; int boguscount = 32; int no_speed_check = 0; unsigned got_act; unsigned long flags; got_act = 0; iobase = ndev->base_addr; spin_lock_irqsave(&idev->lock,flags); do { irintr = inb(iobase+VLSI_PIO_IRINTR); rmb(); outb(irintr, iobase+VLSI_PIO_IRINTR); /* acknowledge asap */ wmb(); if (!(irintr&=IRINTR_INT_MASK)) /* not our INT - probably shared */ break;// vlsi_reg_debug(iobase,__FUNCTION__); if (irintr&IRINTR_RPKTINT) no_speed_check |= vlsi_rx_interrupt(ndev); if (irintr&IRINTR_TPKTINT) no_speed_check |= vlsi_tx_interrupt(ndev);#if 0 /* disable ACTIVITY handling for now */ if (got_act && irintr==IRINTR_ACTIVITY) /* nothing new */ break; if ((irintr&IRINTR_ACTIVITY) && !(irintr^IRINTR_ACTIVITY) ) { no_speed_check |= vlsi_act_interrupt(ndev); got_act = 1; }#endif if (irintr & ~(IRINTR_RPKTINT|IRINTR_TPKTINT|IRINTR_ACTIVITY)) printk(KERN_DEBUG "%s: IRINTR = %02x\n", __FUNCTION__, (unsigned)irintr); } while (--boguscount > 0); spin_unlock_irqrestore(&idev->lock,flags); if (boguscount <= 0) printk(KERN_ERR "%s: too much work in interrupt!\n", __FUNCTION__); else if (!no_speed_check) { if (idev->new_baud) vlsi_set_baud(ndev); }}/**************************************************************//* writing all-zero to the VLSI PCI IO register area seems to prevent * some occasional situations where the hardware fails (symptoms are * what appears as stalled tx/rx state machines, i.e. everything ok for * receive or transmit but hw makes no progress or is unable to access * the bus memory locations). * Best place to call this is immediately after/before the internal clock * gets started/stopped. */static inline void vlsi_clear_regs(unsigned iobase){ unsigned i; const unsigned chip_io_extent = 32; for (i = 0; i < chip_io_extent; i += sizeof(u16)) outw(0, iobase + i);}static int vlsi_open(struct net_device *ndev){ vlsi_irda_dev_t *idev = ndev->priv; struct pci_dev *pdev = idev->pdev; int err; char hwname[32]; if (pci_request_regions(pdev,drivername)) { printk(KERN_ERR "%s: io resource busy\n", __FUNCTION__); return -EAGAIN; } /* under some rare occasions the chip apparently comes up * with IRQ's pending. So we get interrupts invoked much too early * which will immediately kill us again :-( * so we better w/c pending IRQ and disable them all */ outb(IRINTR_INT_MASK, ndev->base_addr+VLSI_PIO_IRINTR); if (request_irq(ndev->irq, vlsi_interrupt, SA_SHIRQ, drivername, ndev)) { printk(KERN_ERR "%s: couldn't get IRQ: %d\n", __FUNCTION__, ndev->irq); pci_release_regions(pdev); return -EAGAIN; } printk(KERN_INFO "%s: got resources for %s - irq=%d / io=%04lx\n", __FUNCTION__, ndev->name, ndev->irq, ndev->base_addr ); if (vlsi_set_clock(pdev)) { printk(KERN_ERR "%s: no valid clock source\n", __FUNCTION__); free_irq(ndev->irq,ndev); pci_release_regions(pdev); return -EIO; } vlsi_start_clock(pdev); vlsi_clear_regs(ndev->base_addr); err = vlsi_init_ring(idev); if (err) { vlsi_unset_clock(pdev); free_irq(ndev->irq,ndev); pci_release_regions(pdev); return err; } vlsi_init_chip(ndev); printk(KERN_INFO "%s: IrPHY setup: %d baud (%s), %s SIR-pulses\n", __FUNCTION__, idev->baud, (idev->mode==IFF_SIR)?"SIR":((idev->mode==IFF_MIR)?"MIR":"FIR"), (sirpulse)?"3/16 bittime":"short"); vlsi_arm_rx(&idev->rx_ring); do_gettimeofday(&idev->last_rx); /* first mtt may start from now on */ sprintf(hwname, "VLSI-FIR @ 0x%04x", (unsigned)ndev->base_addr); idev->irlap = irlap_open(ndev,&idev->qos,hwname); netif_start_queue(ndev); outw(0, ndev->base_addr+VLSI_PIO_PROMPT); /* kick hw state machine */ printk(KERN_INFO "%s: device %s operational using (%d,%d) tx,rx-ring\n", __FUNCTION__, ndev->name, ringsize[0], ringsize[1]); return 0;}static int vlsi_close(struct net_device *ndev){ vlsi_irda_dev_t *idev = ndev->priv; struct pci_dev *pdev = idev->pdev;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -