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

📄 smsc-ircc2.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	outb(0, iobase + IRCC_IER);	lcra = inb(iobase + IRCC_LCR_A);	lsr = inb(iobase + IRCC_LSR);	IRDA_DEBUG(2, "%s(), iir = 0x%02x\n", __FUNCTION__, iir);	if (iir & IRCC_IIR_EOM) {		if (self->io.direction == IO_RECV)			smsc_ircc_dma_receive_complete(self);		else			smsc_ircc_dma_xmit_complete(self);		smsc_ircc_dma_receive(self);	}	if (iir & IRCC_IIR_ACTIVE_FRAME) {		/*printk(KERN_WARNING "%s(): Active Frame\n", __FUNCTION__);*/	}	/* Enable interrupts again */	register_bank(iobase, 0);	outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER); irq_ret_unlock:	spin_unlock(&self->lock); irq_ret:	return ret;}/* * Function irport_interrupt_sir (irq, dev_id) * *    Interrupt handler for SIR modes */static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev){	struct smsc_ircc_cb *self = netdev_priv(dev);	int boguscount = 0;	int iobase;	int iir, lsr;	/* Already locked comming here in smsc_ircc_interrupt() */	/*spin_lock(&self->lock);*/	iobase = self->io.sir_base;	iir = inb(iobase + UART_IIR) & UART_IIR_ID;	if (iir == 0)		return IRQ_NONE;	while (iir) {		/* Clear interrupt */		lsr = inb(iobase + UART_LSR);		IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",			    __FUNCTION__, iir, lsr, iobase);		switch (iir) {		case UART_IIR_RLSI:			IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__);			break;		case UART_IIR_RDI:			/* Receive interrupt */			smsc_ircc_sir_receive(self);			break;		case UART_IIR_THRI:			if (lsr & UART_LSR_THRE)				/* Transmitter ready for data */				smsc_ircc_sir_write_wakeup(self);			break;		default:			IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n",				   __FUNCTION__, iir);			break;		}		/* Make sure we don't stay here to long */		if (boguscount++ > 100)			break;	        iir = inb(iobase + UART_IIR) & UART_IIR_ID;	}	/*spin_unlock(&self->lock);*/	return IRQ_HANDLED;}#if 0 /* unused *//* * Function ircc_is_receiving (self) * *    Return TRUE is we are currently receiving a frame * */static int ircc_is_receiving(struct smsc_ircc_cb *self){	int status = FALSE;	/* int iobase; */	IRDA_DEBUG(1, "%s\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return FALSE;);	IRDA_DEBUG(0, "%s: dma count = %d\n", __FUNCTION__,		   get_dma_residue(self->io.dma));	status = (self->rx_buff.state != OUTSIDE_FRAME);	return status;}#endif /* unused */static int smsc_ircc_request_irq(struct smsc_ircc_cb *self){	int error;	error = request_irq(self->io.irq, smsc_ircc_interrupt, 0,			    self->netdev->name, self->netdev);	if (error)		IRDA_DEBUG(0, "%s(), unable to allocate irq=%d, err=%d\n",			   __FUNCTION__, self->io.irq, error);	return error;}static void smsc_ircc_start_interrupts(struct smsc_ircc_cb *self){	unsigned long flags;	spin_lock_irqsave(&self->lock, flags);	self->io.speed = 0;	smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);	spin_unlock_irqrestore(&self->lock, flags);}static void smsc_ircc_stop_interrupts(struct smsc_ircc_cb *self){	int iobase = self->io.fir_base;	unsigned long flags;	spin_lock_irqsave(&self->lock, flags);	register_bank(iobase, 0);	outb(0, iobase + IRCC_IER);	outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER);	outb(0x00, iobase + IRCC_MASTER);	spin_unlock_irqrestore(&self->lock, flags);}/* * Function smsc_ircc_net_open (dev) * *    Start the device * */static int smsc_ircc_net_open(struct net_device *dev){	struct smsc_ircc_cb *self;	char hwname[16];	IRDA_DEBUG(1, "%s\n", __FUNCTION__);	IRDA_ASSERT(dev != NULL, return -1;);	self = netdev_priv(dev);	IRDA_ASSERT(self != NULL, return 0;);	if (self->io.suspended) {		IRDA_DEBUG(0, "%s(), device is suspended\n", __FUNCTION__);		return -EAGAIN;	}	if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name,			(void *) dev)) {		IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n",			   __FUNCTION__, self->io.irq);		return -EAGAIN;	}	smsc_ircc_start_interrupts(self);	/* Give self a hardware name */	/* It would be cool to offer the chip revision here - Jean II */	sprintf(hwname, "SMSC @ 0x%03x", self->io.fir_base);	/*	 * Open new IrLAP layer instance, now that everything should be	 * initialized properly	 */	self->irlap = irlap_open(dev, &self->qos, hwname);	/*	 * Always allocate the DMA channel after the IRQ,	 * and clean up on failure.	 */	if (request_dma(self->io.dma, dev->name)) {		smsc_ircc_net_close(dev);		IRDA_WARNING("%s(), unable to allocate DMA=%d\n",			     __FUNCTION__, self->io.dma);		return -EAGAIN;	}	netif_start_queue(dev);	return 0;}/* * Function smsc_ircc_net_close (dev) * *    Stop the device * */static int smsc_ircc_net_close(struct net_device *dev){	struct smsc_ircc_cb *self;	IRDA_DEBUG(1, "%s\n", __FUNCTION__);	IRDA_ASSERT(dev != NULL, return -1;);	self = netdev_priv(dev);	IRDA_ASSERT(self != NULL, return 0;);	/* Stop device */	netif_stop_queue(dev);	/* Stop and remove instance of IrLAP */	if (self->irlap)		irlap_close(self->irlap);	self->irlap = NULL;	smsc_ircc_stop_interrupts(self);	/* if we are called from smsc_ircc_resume we don't have IRQ reserved */	if (!self->io.suspended)		free_irq(self->io.irq, dev);	disable_dma(self->io.dma);	free_dma(self->io.dma);	return 0;}static int smsc_ircc_suspend(struct platform_device *dev, pm_message_t state){	struct smsc_ircc_cb *self = platform_get_drvdata(dev);	if (!self->io.suspended) {		IRDA_DEBUG(1, "%s, Suspending\n", driver_name);		rtnl_lock();		if (netif_running(self->netdev)) {			netif_device_detach(self->netdev);			smsc_ircc_stop_interrupts(self);			free_irq(self->io.irq, self->netdev);			disable_dma(self->io.dma);		}		self->io.suspended = 1;		rtnl_unlock();	}	return 0;}static int smsc_ircc_resume(struct platform_device *dev){	struct smsc_ircc_cb *self = platform_get_drvdata(dev);	if (self->io.suspended) {		IRDA_DEBUG(1, "%s, Waking up\n", driver_name);		rtnl_lock();		smsc_ircc_init_chip(self);		if (netif_running(self->netdev)) {			if (smsc_ircc_request_irq(self)) {				/*				 * Don't fail resume process, just kill this				 * network interface				 */				unregister_netdevice(self->netdev);			} else {				enable_dma(self->io.dma);				smsc_ircc_start_interrupts(self);				netif_device_attach(self->netdev);			}		}		self->io.suspended = 0;		rtnl_unlock();	}	return 0;}/* * Function smsc_ircc_close (self) * *    Close driver instance * */static int __exit smsc_ircc_close(struct smsc_ircc_cb *self){	IRDA_DEBUG(1, "%s\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return -1;);	platform_device_unregister(self->pldev);	/* Remove netdevice */	unregister_netdev(self->netdev);	smsc_ircc_stop_interrupts(self);	/* Release the PORTS that this driver is using */	IRDA_DEBUG(0, "%s(), releasing 0x%03x\n",  __FUNCTION__,		   self->io.fir_base);	release_region(self->io.fir_base, self->io.fir_ext);	IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__,		   self->io.sir_base);	release_region(self->io.sir_base, self->io.sir_ext);	if (self->tx_buff.head)		dma_free_coherent(NULL, self->tx_buff.truesize,				  self->tx_buff.head, self->tx_buff_dma);	if (self->rx_buff.head)		dma_free_coherent(NULL, self->rx_buff.truesize,				  self->rx_buff.head, self->rx_buff_dma);	free_netdev(self->netdev);	return 0;}static void __exit smsc_ircc_cleanup(void){	int i;	IRDA_DEBUG(1, "%s\n", __FUNCTION__);	for (i = 0; i < 2; i++) {		if (dev_self[i])			smsc_ircc_close(dev_self[i]);	}	platform_driver_unregister(&smsc_ircc_driver);}/* *	Start SIR operations * * This function *must* be called with spinlock held, because it may * be called from the irq handler (via smsc_ircc_change_speed()). - Jean II */void smsc_ircc_sir_start(struct smsc_ircc_cb *self){	struct net_device *dev;	int fir_base, sir_base;	IRDA_DEBUG(3, "%s\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return;);	dev = self->netdev;	IRDA_ASSERT(dev != NULL, return;);	dev->hard_start_xmit = &smsc_ircc_hard_xmit_sir;	fir_base = self->io.fir_base;	sir_base = self->io.sir_base;	/* Reset everything */	outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER);	#if SMSC_IRCC2_C_SIR_STOP	/*smsc_ircc_sir_stop(self);*/	#endif	register_bank(fir_base, 1);	outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base + IRCC_SCE_CFGA);	/* Initialize UART */	outb(UART_LCR_WLEN8, sir_base + UART_LCR);  /* Reset DLAB */	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base + UART_MCR);	/* Turn on interrups */	outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base + UART_IER);	IRDA_DEBUG(3, "%s() - exit\n", __FUNCTION__);	outb(0x00, fir_base + IRCC_MASTER);}#if SMSC_IRCC2_C_SIR_STOPvoid smsc_ircc_sir_stop(struct smsc_ircc_cb *self){	int iobase;	IRDA_DEBUG(3, "%s\n", __FUNCTION__);	iobase = self->io.sir_base;	/* Reset UART */	outb(0, iobase + UART_MCR);	/* Turn off interrupts */	outb(0, iobase + UART_IER);}#endif/* * Function smsc_sir_write_wakeup (self) * *    Called by the SIR interrupt handler when there's room for more data. *    If we have more packets to send, we send them here. * */static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self){	int actual = 0;	int iobase;	int fcr;	IRDA_ASSERT(self != NULL, return;);	IRDA_DEBUG(4, "%s\n", __FUNCTION__);	iobase = self->io.sir_base;	/* Finished with frame?  */	if (self->tx_buff.len > 0)  {		/* Write data left in transmit buffer */		actual = smsc_ircc_sir_write(iobase, self->io.fifo_size,				      self->tx_buff.data, self->tx_buff.len);		self->tx_buff.data += actual;		self->tx_buff.len  -= actual;	} else {	/*if (self->tx_buff.len ==0)  {*/		/*		 *  Now serial buffer is almost free & we can start		 *  transmission of another packet. But first we must check		 *  if we need to change the speed of the hardware		 */		if (self->new_speed) {			IRDA_DEBUG(5, "%s(), Changing speed to %d.\n",				   __FUNCTION__, self->new_speed);			smsc_ircc_sir_wait_hw_transmitter_finish(self);			smsc_ircc_change_speed(self, self->new_speed);			self->new_speed = 0;		} else {			/* Tell network layer that we want more frames */			netif_wake_queue(self->netdev);		}		self->stats.tx_packets++;		if (self->io.speed <= 115200) {			/*			 * Reset Rx FIFO to make sure that all reflected transmit data			 * is discarded. This is needed for half duplex operation			 */			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;			fcr |= self->io.speed < 38400 ?					UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14;			outb(fcr, iobase + UART_FCR);			/* Turn on receive interrupts */			outb(UART_IER_RDI, iobase + UART_IER);		}	}}/* * Function smsc_ircc_sir_write (iobase, fifo_size, buf, len) * *    Fill Tx FIFO with transmit data * */static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len){	int actual = 0;	/* Tx FIFO should be empty! */	if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) {		IRDA_WARNING("%s(), failed, fifo not empty!\n", __FUNCTION__);		return 0;	}	/* Fill FIFO with current frame */	while (fifo_size-- > 0 && actual < len) {		/* Transmit next byte */		outb(buf[actual], iobase + UART_TX);		actual++;

⌨️ 快捷键说明

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