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 + -
显示快捷键?