ircard_cs.c
来自「linux操作系统下的红外驱动的测试程序」· C语言 代码 · 共 1,368 行 · 第 1/3 页
C
1,368 行
* */static inline void ircard_xmit_complete(struct irda_device *idev){ struct ircard_cb *self; int iobase; int stat; __u8 bank; int paranoid = 0; self = idev->priv; iobase = idev->io.iobase; bank = switch_bank(iobase, 0); /* Read Tx status register and check for transmission completion */ stat = inb(iobase+TX_STAT); /* (bank 0) */ if (stat & TX_STAT_FIFO_UNDR) { DEBUG(0, __FUNCTION__ "() FIFO underrun!\n"); idev->stats.tx_errors++; idev->stats.tx_fifo_errors++; } else { /* Spin until EOM */ while (!(stat & TX_STAT_EOM)) { if (paranoid++ > 1000) { DEBUG(0, __FUNCTION__ "(), breaking!\n"); break; } stat = inb(iobase+TX_STAT); } idev->stats.tx_packets++; idev->stats.tx_bytes += idev->tx_buff.len; } /* This will reset transmit enable */ ircard_set_mcr(iobase, MCR_INTR_EN, bank); /* Disable DMA */ outb(0, iobase+MISC); /* Reset Tx special condition bits */ outb(RESET_TX_SPEC_BITS, iobase+RESET); /* Unlock tx_buff and request another frame */ idev->netdev.tbusy = 0; /* Unlock */ idev->media_busy = FALSE; /* Finished with this frame, so prepare for next */ self->tx_q.ptr++; self->tx_q.len--; /* Any frames to be sent back-to-back? */ if (self->tx_q.len) { ircard_dma_write(idev, iobase); } else if (irda_device_txqueue_empty(idev)) { /* Reset EOM and RTS bits */ outb(0, iobase+TX_CTRL1); /* (bank 0) */ /* * No frames queued at card, and no frames in tx queue, so * now we can get ready for receiving */ ircard_receive(idev, iobase); } /* Tell the network layer, that we can accept more frames */ mark_bh(NET_BH); /* No need to restore original bank! */}/* * Function ircard_receive (idev) * * Get ready for receiving a frame. The device will initiate a DMA * if it starts to receive a frame. * */static int ircard_receive(struct irda_device *idev, int iobase){ struct ircard_cb *self; __u8 bank; self = idev->priv; bank = switch_bank(iobase, 0); /* Disable Rx, Tx */ ircard_set_mcr(iobase, MCR_INTR_EN, bank); /* Reset Tx queue info */ self->tx_q.len = self->tx_q.ptr = self->tx_q.free = 0; self->tx_q.tail = SHMEM_TX_START + idev->io.membase;; /* Reset Rx special condition bits */ outb(RESET_RX_SPEC_BITS, iobase+RESET); /* Reset Rx receive frame pointer */ outb(RESET_RX_RFP, iobase+RESET); /* Set receive and interrupt enable bits (but keep original bank) */ ircard_set_mcr(iobase, MCR_RX_EN|MCR_INTR_EN, bank); /* Enable Rx ready interrupt */ switch_bank(iobase, 0); /* Enable Rx interrupts */ outb(RX_CTRL_EN_CRC|RX_CTRL_COND_I, iobase+RX_CTRL); /* Make sure DMA is set properly */ outb(0xc0, iobase+MISC); idev->io.direction = IO_RECV; return 0;}/* * Function ircard_receive_complete (idev, iobase) * * * */static int ircard_receive_complete(struct irda_device *idev, int iobase){ struct sk_buff *skb; struct ircard_cb *self; int len; int ptr; int stat; int start; self = idev->priv; /* Read receive ring frame pointer */ switch_bank(iobase, 1); ptr = inb(iobase+RX_RING_FRM_PTR_LOW); ptr |= ((inb(iobase+RX_RING_FRM_PTR_HIGH) & 0x3f) << 8); if (!ptr) return FALSE; stat = readb(idev->io.membase+ptr); len = (stat & 0x1f) << 8; len |= readb(idev->io.membase+ptr-1); if (stat & 0x80) { DEBUG(0, __FUNCTION__ "(), frame abort!\n"); /* switch_bank(iobase, 0); *//* outb(RESET_RX_SPEC_BITS, iobase+RESET); *//* outb(RESET_RX_FIFO_PTR, iobase+RESET); */ /* Skip frame */ idev->stats.rx_errors++; idev->stats.rx_frame_errors++; return FALSE; } if (stat & 0x40) { DEBUG(4, __FUNCTION__ "(), frame error!\n"); DEBUG(4, __FUNCTION__ "(), len=%d\n", len); /* Skip frame */ idev->stats.rx_errors++; idev->stats.rx_frame_errors++; return FALSE; } if (stat & 0x20) { DEBUG(4, __FUNCTION__ "(), overrun!\n"); DEBUG(4, __FUNCTION__ "(), len=%d\n", len); switch_bank(iobase, 0); outb(RESET_RX_SPEC_BITS, iobase+RESET); /* Skip frame */ idev->stats.rx_errors++; idev->stats.rx_fifo_errors++; return FALSE; } ASSERT(len>5, return FALSE;); /* Find start of frame */ start = idev->io.membase+ptr-len-1; if (start > self->data) { DEBUG(0, __FUNCTION__ "() Received Back-to-Back frames!!\n"); } /* Got a frame, so remember when */ do_gettimeofday(&self->stamp); /* Save pointer to start of next frame */ self->data = ptr+1; /* Remove CRC */ len -= 4; /* Limit frame to max data size + LAP header */ if (len > 2050) len = 2050; skb = dev_alloc_skb(len+1); if (skb == NULL) { printk(KERN_INFO __FUNCTION__ "(), memory squeeze, dropping frame.\n"); return FALSE; } /* Make sure IP header gets aligned */ skb_reserve(skb, 1); skb_put(skb, len); copy_from_pc(skb->data, (void *) start, len); idev->stats.rx_packets++; skb->dev = &idev->netdev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); return TRUE;}/* * Function ircard_interrupt (irq, dev_id, regs) * * An interrupt from the chip has arrived. Time to do some work * */static void ircard_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct irda_device *idev; __u8 msr, bank; int iobase; int bogus = 0; idev = (struct irda_device *) dev_id; if (idev == NULL) { WARNING("%s: irq %d for unknown device.\n", (char *) dev_info, irq); return; } if (idev->io.baudrate <= 115200) return irport_interrupt(irq, dev_id, regs); spin_lock(&idev->lock); idev->netdev.interrupt = 1; iobase = idev->io.iobase; /* Save bank, so the original bank is restored when we return */ bank = switch_bank(iobase, 0); /* Read interrupt status */ msr = inb(iobase+MSR) & MSR_ID_MASK; while (msr) { /* Check which interrupt this is */ switch (msr) { case MSR_TX_COND_ID: /* Tx special condition */ ircard_xmit_complete(idev); break; case MSR_RX_DATA_ID: /* Rx data available */ DEBUG(0, __FUNCTION__ "() should not get here!\n"); ircard_receive_complete(idev, iobase); break; case MSR_RX_COND_ID: /* Rx special condition */ ircard_receive_complete(idev, iobase); break; case MSR_TX_EMPTY_ID: /* Tx buffer empty */ DEBUG(0, __FUNCTION__ "() should not get here!\n"); break; default: DEBUG(0, __FUNCTION__ "(), unknown interrupt status=%#x\n", msr); break; }; if (bogus++ > 10) { WARNING(__FUNCTION__ "(), breaking!\n"); break; } msr = inb(iobase+MSR) & MSR_ID_MASK; } /* Restore bank */ restore_bank(iobase, bank); idev->netdev.interrupt = 0; spin_unlock(&idev->lock);}static int ircard_net_init(struct net_device *dev){ /* Setup to be a normal IrDA network device driver */ irda_device_setup(dev); /* Insert overrides below this line! */ return 0;}/* * Function ircard_net_open (dev) * * * */static int ircard_net_open(struct net_device *dev){ struct irda_device *idev; int iobase; ASSERT(dev != NULL, return -1;); idev = (struct irda_device *) dev->priv; ASSERT(idev != NULL, return 0;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;); iobase = idev->io.iobase; /* Ready to play! */#if LINUX_VERSION_CODE < VERSION(2,2,11) dev->tbusy = 0; dev->interrupt = 0; dev->start = 1;#else irda_device_net_open(dev);#endif /* Start SIR driver */ irport_start(idev, idev->io.iobase2); MOD_INC_USE_COUNT; return 0;}/* * Function ircard_net_close (dev) * * * */static int ircard_net_close(struct net_device *dev){ struct irda_device *idev; int iobase;#if LINUX_VERSION_CODE < VERSION(2,2,11) /* Stop device */ dev->tbusy = 1; dev->start = 0;#else irda_device_net_close(dev);#endif ASSERT(dev != NULL, return -1;); idev = (struct irda_device *) dev->priv; ASSERT(idev != NULL, return 0;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;); iobase = idev->io.iobase; /* Stop SIR driver */ irport_stop(idev, idev->io.iobase2); MOD_DEC_USE_COUNT; return 0;}/* * Function uircc_wait_until_sent (idev) * * This function should put the currently thread to sleep until all data * have been sent, so it is safe to change the speed. */static void ircard_wait_until_sent(struct irda_device *idev){ if (idev->io.baudrate > 115200) { /* Just delay 60 ms */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(MSECS_TO_JIFFIES(60)); } else irport_wait_until_sent(idev);}/* * Function uircc_is_receiving (idev) * * Return TRUE is we are currently receiving a frame * */static int ircard_is_receiving(struct irda_device *idev){ int status = FALSE; /* int iobase; */ ASSERT(idev != NULL, return FALSE;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return FALSE;); if (idev->io.baudrate > 115200) { /* Not impl yet */ } else status = (idev->rx_buff.state != OUTSIDE_FRAME); return status;}MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");MODULE_DESCRIPTION("IBM 31T1502 IrDA PCMCIA device driver");/* * Function init_module () * * * */int init_module(void){ servinfo_t serv; DEBUG(0, "%s\n", version); CardServices(GetCardServicesInfo, &serv); if (serv.Revision != CS_RELEASE_CODE) { printk(KERN_NOTICE "ircard_cs: Card Services release " "does not match!\n"); return -1; } register_pccard_driver(&dev_info, &ircard_attach, &ircard_detach); return 0;}/* * Function cleanup_module () * * * */void cleanup_module(void){ DEBUG(0, "ircard_cs: unloading\n"); unregister_pccard_driver(&dev_info); while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) ircard_release((u_long)dev_list); ircard_detach(dev_list); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?