⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smc-ircc.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 2 页
字号:
			   speed);		/* FALLTHROUGH */	case 9600:	case 19200:	case 38400:	case 57600:	case 115200:				ir_mode = IRCC_CFGA_IRDA_SIR_A;		ctrl = 0;		fast = 0;		break;	case 576000:				ir_mode = IRCC_CFGA_IRDA_HDLC;		ctrl = IRCC_CRC;		fast = 0;		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");		break;	case 1152000:		ir_mode = IRCC_CFGA_IRDA_HDLC;		ctrl = IRCC_1152 | IRCC_CRC;		fast = 0;		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");		break;	case 4000000:		ir_mode = IRCC_CFGA_IRDA_4PPM;		ctrl = IRCC_CRC;		fast = IRCC_LCR_A_FAST;		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");		break;	}		register_bank(iobase, 0);	outb(0, iobase+IRCC_IER);	outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);	/* Make special FIR init if necessary */	if (speed > 115200) {		irport_stop(self->irport);		/* Install FIR transmit handler */		dev->hard_start_xmit = &ircc_hard_xmit;		/* 		 * Don't know why we have to do this, but FIR interrupts 		 * stops working if we remove it.		 */		/* outb(UART_MCR_OUT2, self->io->sir_base + UART_MCR); */		/* Be ready for incoming frames */		ircc_dma_receive(self, iobase);	} else {		/* Install SIR transmit handler */		dev->hard_start_xmit = &irport_hard_xmit;		irport_start(self->irport);			        IRDA_DEBUG(0, __FUNCTION__ 			   "(), using irport to change speed to %d\n", speed);		irport_change_speed(self->irport, speed);	}		register_bank(iobase, 1);	outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode), 	     iobase+IRCC_SCE_CFGA);#ifdef SMC_669 /* Uses pin 88/89 for Rx/Tx */	outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), 	     iobase+IRCC_SCE_CFGB);#else		outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),	     iobase+IRCC_SCE_CFGB);#endif		(void) inb(iobase+IRCC_FIFO_THRESHOLD);	outb(64, iobase+IRCC_FIFO_THRESHOLD);		register_bank(iobase, 4);	outb((inb(iobase+IRCC_CONTROL) & 0x30) | ctrl, iobase+IRCC_CONTROL);		register_bank(iobase, 0);	outb(fast, iobase+IRCC_LCR_A);		netif_start_queue(dev);}/* * Function ircc_hard_xmit (skb, dev) * *    Transmit the frame! * */static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev){	struct irport_cb *irport;	struct ircc_cb *self;	unsigned long flags;	s32 speed;	int iobase;	int mtt;	irport = (struct irport_cb *) dev->priv;	self = (struct ircc_cb *) irport->priv;	ASSERT(self != NULL, return 0;);	iobase = self->io->fir_base;	netif_stop_queue(dev);	/* Check if we need to change the speed after this frame */	speed = irda_get_next_speed(skb);	if ((speed != self->io->speed) && (speed != -1)) {		/* Check for empty frame */		if (!skb->len) {			ircc_change_speed(self, speed); 			dev_kfree_skb(skb);			return 0;		} else			self->new_speed = speed;	}		spin_lock_irqsave(&self->lock, flags);	memcpy(self->tx_buff.head, skb->data, skb->len);	self->tx_buff.len = skb->len;	self->tx_buff.data = self->tx_buff.head;		mtt = irda_get_mtt(skb);		if (mtt) {		int bofs;		/* 		 * Compute how many BOFs (STA or PA's) we need to waste the		 * min turn time given the speed of the link.		 */		bofs = mtt * (self->io->speed / 1000) / 8000;		if (bofs > 4095)			bofs = 4095;		ircc_dma_xmit(self, iobase, bofs);	} else {		/* Transmit frame */		ircc_dma_xmit(self, iobase, 0);	}	spin_unlock_irqrestore(&self->lock, flags);	dev_kfree_skb(skb);	return 0;}/* * Function ircc_dma_xmit (self, iobase) * *    Transmit data using DMA * */static void ircc_dma_xmit(struct ircc_cb *self, int iobase, int bofs){	u8 ctrl;	IRDA_DEBUG(2, __FUNCTION__ "\n");#if 0		/* Disable Rx */	register_bank(iobase, 0);	outb(0x00, iobase+IRCC_LCR_B);#endif	register_bank(iobase, 1);	outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, 	     iobase+IRCC_SCE_CFGB);	self->io->direction = IO_XMIT;	/* Set BOF additional count for generating the min turn time */	register_bank(iobase, 4);	outb(bofs & 0xff, iobase+IRCC_BOF_COUNT_LO);	ctrl = inb(iobase+IRCC_CONTROL) & 0xf0;	outb(ctrl | ((bofs >> 8) & 0x0f), iobase+IRCC_BOF_COUNT_HI);	/* Set max Tx frame size */	outb(self->tx_buff.len >> 8, iobase+IRCC_TX_SIZE_HI);	outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO);	/* Setup DMA controller (must be done after enabling chip DMA) */	setup_dma(self->io->dma, self->tx_buff.data, self->tx_buff.len, 		  DMA_TX_MODE);	outb(UART_MCR_OUT2, self->io->sir_base + UART_MCR);	/* Enable burst mode chip Tx DMA */	register_bank(iobase, 1);	outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |	     IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);	/* Enable interrupt */	outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);	register_bank(iobase, 0);	outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);	/* Enable transmit */	outb(IRCC_LCR_B_SCE_TRANSMIT|IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B);}/* * Function ircc_dma_xmit_complete (self) * *    The transfer of a frame in finished. This function will only be called  *    by the interrupt handler * */static void ircc_dma_xmit_complete(struct ircc_cb *self, int iobase){	IRDA_DEBUG(2, __FUNCTION__ "\n");#if 0	/* Disable Tx */	register_bank(iobase, 0);	outb(0x00, iobase+IRCC_LCR_B);#endif	register_bank(self->io->fir_base, 1);	outb(inb(self->io->fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,	     self->io->fir_base+IRCC_SCE_CFGB);	/* Check for underrrun! */	register_bank(iobase, 0);	if (inb(iobase+IRCC_LSR) & IRCC_LSR_UNDERRUN) {		self->irport->stats.tx_errors++;		self->irport->stats.tx_fifo_errors++;		/* Reset error condition */		register_bank(iobase, 0);		outb(IRCC_MASTER_ERROR_RESET, iobase+IRCC_MASTER);		outb(0x00, iobase+IRCC_MASTER);	} else {		self->irport->stats.tx_packets++;		self->irport->stats.tx_bytes +=  self->tx_buff.len;	}	/* Check if it's time to change the speed */	if (self->new_speed) {		ircc_change_speed(self, self->new_speed);				self->new_speed = 0;	}	netif_wake_queue(self->netdev);}/* * Function 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 ircc_dma_receive(struct ircc_cb *self, int iobase) {	#if 0	/* Turn off chip DMA */	register_bank(iobase, 1);	outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, 	     iobase+IRCC_SCE_CFGB);#endif	setup_dma(self->io->dma, self->rx_buff.data, self->rx_buff.truesize, 		  DMA_RX_MODE);	/* Set max Rx frame size */	register_bank(iobase, 4);	outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI);	outb(2050 & 0xff, iobase+IRCC_RX_SIZE_LO);	self->io->direction = IO_RECV;	self->rx_buff.data = self->rx_buff.head;	/* Setup DMA controller */		/* Enable receiver */	register_bank(iobase, 0);	outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE, 	     iobase+IRCC_LCR_B);		/* Enable burst mode chip Rx DMA */	register_bank(iobase, 1);	outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | 	     IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);	return 0;}/* * Function ircc_dma_receive_complete (self) * *    Finished with receiving frames * */static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase){	struct sk_buff *skb;	int len, msgcnt;	IRDA_DEBUG(2, __FUNCTION__ "\n");#if 0	/* Disable Rx */	register_bank(iobase, 0);	outb(0x00, iobase+IRCC_LCR_B);#endif	register_bank(iobase, 0);	msgcnt = inb(iobase+IRCC_LCR_B) & 0x08;	IRDA_DEBUG(2, __FUNCTION__ ": dma count = %d\n",		   get_dma_residue(self->io->dma));	len = self->rx_buff.truesize - get_dma_residue(self->io->dma);		/* Remove CRC */	if (self->io->speed < 4000000)		len -= 2;	else		len -= 4;	if ((len < 2) || (len > 2050)) {		WARNING(__FUNCTION__ "(), bogus len=%d\n", len);		return;	}	IRDA_DEBUG(2, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len);	skb = dev_alloc_skb(len+1);	if (!skb)  {		WARNING(__FUNCTION__ "(), memory squeeze, dropping frame.\n");		return;	}				/* Make sure IP header gets aligned */	skb_reserve(skb, 1); 	memcpy(skb_put(skb, len), self->rx_buff.data, len);	self->irport->stats.rx_packets++;	self->irport->stats.rx_bytes += len;	skb->dev = self->netdev;	skb->mac.raw  = skb->data;	skb->protocol = htons(ETH_P_IRDA);	netif_rx(skb);}/* * Function ircc_interrupt (irq, dev_id, regs) * *    An interrupt from the chip has arrived. Time to do some work * */static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = (struct net_device *) dev_id;	struct irport_cb *irport;	struct ircc_cb *self;	int iobase, iir;	if (dev == NULL) {		printk(KERN_WARNING "%s: irq %d for unknown device.\n", 		       driver_name, irq);		return;	}	irport = (struct irport_cb *) dev->priv;	ASSERT(irport != NULL, return;);	self = (struct ircc_cb *) irport->priv;	ASSERT(self != NULL, return;);	/* Check if we should use the SIR interrupt handler */	if (self->io->speed < 576000) {		irport_interrupt(irq, dev_id, regs);		return;	}	iobase = self->io->fir_base;	spin_lock(&self->lock);		register_bank(iobase, 0);	iir = inb(iobase+IRCC_IIR);	/* Disable interrupts */	outb(0, iobase+IRCC_IER);	IRDA_DEBUG(2, __FUNCTION__ "(), iir = 0x%02x\n", iir);	if (iir & IRCC_IIR_EOM) {		if (self->io->direction == IO_RECV)			ircc_dma_receive_complete(self, iobase);		else			ircc_dma_xmit_complete(self, iobase);				ircc_dma_receive(self, iobase);	}	/* Enable interrupts again */	register_bank(iobase, 0);	outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER);	spin_unlock(&self->lock);}#if 0 /* unused *//* * Function ircc_is_receiving (self) * *    Return TRUE is we are currently receiving a frame * */static int ircc_is_receiving(struct ircc_cb *self){	int status = FALSE;	/* int iobase; */	IRDA_DEBUG(0, __FUNCTION__ "\n");	ASSERT(self != NULL, return FALSE;);	IRDA_DEBUG(0, __FUNCTION__ ": dma count = %d\n",		   get_dma_residue(self->io->dma));	status = (self->rx_buff.state != OUTSIDE_FRAME);		return status;}#endif /* unused *//* * Function ircc_net_open (dev) * *    Start the device * */static int ircc_net_open(struct net_device *dev){	struct irport_cb *irport;	struct ircc_cb *self;	int iobase;	IRDA_DEBUG(0, __FUNCTION__ "\n");		ASSERT(dev != NULL, return -1;);	irport = (struct irport_cb *) dev->priv;	self = (struct ircc_cb *) irport->priv;	ASSERT(self != NULL, return 0;);		iobase = self->io->fir_base;	irport_net_open(dev); /* irport allocates the irq */	/*	 * Always allocate the DMA channel after the IRQ,	 * and clean up on failure.	 */	if (request_dma(self->io->dma, dev->name)) {		irport_net_close(dev);		WARNING(__FUNCTION__ "(), unable to allocate DMA=%d\n", self->io->dma);		return -EAGAIN;	}		MOD_INC_USE_COUNT;	return 0;}/* * Function ircc_net_close (dev) * *    Stop the device * */static int ircc_net_close(struct net_device *dev){	struct irport_cb *irport;	struct ircc_cb *self;	int iobase;	IRDA_DEBUG(0, __FUNCTION__ "\n");		ASSERT(dev != NULL, return -1;);	irport = (struct irport_cb *) dev->priv;	self = (struct ircc_cb *) irport->priv;		ASSERT(self != NULL, return 0;);		iobase = self->io->fir_base;	irport_net_close(dev);	disable_dma(self->io->dma);	free_dma(self->io->dma);	MOD_DEC_USE_COUNT;	return 0;}static void ircc_suspend(struct ircc_cb *self){	MESSAGE("%s, Suspending\n", driver_name);	if (self->io->suspended)		return;	ircc_net_close(self->netdev);	self->io->suspended = 1;}static void ircc_wakeup(struct ircc_cb *self){	unsigned long flags;	if (!self->io->suspended)		return;	save_flags(flags);	cli();	ircc_net_open(self->netdev);		restore_flags(flags);	MESSAGE("%s, Waking up\n", driver_name);}static int ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data){        struct ircc_cb *self = (struct ircc_cb*) dev->data;        if (self) {                switch (rqst) {                case PM_SUSPEND:                        ircc_suspend(self);                        break;                case PM_RESUME:                        ircc_wakeup(self);                        break;                }        }	return 0;}#ifdef MODULE/* * Function ircc_close (self) * *    Close driver instance * */#ifdef MODULEstatic int __exit ircc_close(struct ircc_cb *self){	int iobase;	IRDA_DEBUG(0, __FUNCTION__ "\n");	ASSERT(self != NULL, return -1;);        iobase = self->irport->io.fir_base;	irport_close(self->irport);	/* Stop interrupts */	register_bank(iobase, 0);	outb(0, iobase+IRCC_IER);	outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);	outb(0x00, iobase+IRCC_MASTER);#if 0	/* Reset to SIR mode */	register_bank(iobase, 1);        outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA);        outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);#endif	/* Release the PORT that this driver is using */	IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", 		   self->io->fir_base);	release_region(self->io->fir_base, self->io->fir_ext);	if (self->tx_buff.head)		kfree(self->tx_buff.head);		if (self->rx_buff.head)		kfree(self->rx_buff.head);	kfree(self);	return 0;}#endif /* MODULE */int __init smc_init(void){	return ircc_init();}void __exit smc_cleanup(void){	int i;	IRDA_DEBUG(0, __FUNCTION__ "\n");	for (i=0; i < 2; i++) {		if (dev_self[i])			ircc_close(dev_self[i]);	}}module_init(smc_init);module_exit(smc_cleanup); MODULE_AUTHOR("Thomas Davis <tadavis@jps.net>");MODULE_DESCRIPTION("SMC IrCC controller driver");MODULE_LICENSE("GPL");MODULE_PARM(ircc_dma, "1i");MODULE_PARM_DESC(ircc_dma, "DMA channel");MODULE_PARM(ircc_irq, "1i");MODULE_PARM_DESC(ircc_irq, "IRQ line");MODULE_PARM(ircc_fir, "1-4i");MODULE_PARM_DESC(ircc_fir, "FIR Base Address");MODULE_PARM(ircc_sir, "1-4i");MODULE_PARM_DESC(ircc_sir, "SIR Base Address");MODULE_PARM(ircc_cfg, "1-4i");MODULE_PARM_DESC(ircc_cfg, "Configuration register base address");#endif /* MODULE */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -