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

📄 smsc-ircc2.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 5 页
字号:
				   &self->rx_buff_dma, GFP_KERNEL);	if (self->rx_buff.head == NULL) {		IRDA_ERROR("%s, Can't allocate memory for receive buffer!\n",			   driver_name);		goto err_out2;	}	self->tx_buff.head =		dma_alloc_coherent(NULL, self->tx_buff.truesize,				   &self->tx_buff_dma, GFP_KERNEL);	if (self->tx_buff.head == NULL) {		IRDA_ERROR("%s, Can't allocate memory for transmit buffer!\n",			   driver_name);		goto err_out3;	}	memset(self->rx_buff.head, 0, self->rx_buff.truesize);	memset(self->tx_buff.head, 0, self->tx_buff.truesize);	self->rx_buff.in_frame = FALSE;	self->rx_buff.state = OUTSIDE_FRAME;	self->tx_buff.data = self->tx_buff.head;	self->rx_buff.data = self->rx_buff.head;	smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq);	smsc_ircc_setup_qos(self);	smsc_ircc_init_chip(self);	if (ircc_transceiver > 0  &&	    ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS)		self->transceiver = ircc_transceiver;	else		smsc_ircc_probe_transceiver(self);	err = register_netdev(self->netdev);	if (err) {		IRDA_ERROR("%s, Network device registration failed!\n",			   driver_name);		goto err_out4;	}	self->pldev = platform_device_register_simple(SMSC_IRCC2_DRIVER_NAME,						      dev_count, NULL, 0);	if (IS_ERR(self->pldev)) {		err = PTR_ERR(self->pldev);		goto err_out5;	}	platform_set_drvdata(self->pldev, self);	IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);	dev_count++;	return 0; err_out5:	unregister_netdev(self->netdev); err_out4:	dma_free_coherent(NULL, self->tx_buff.truesize,			  self->tx_buff.head, self->tx_buff_dma); err_out3:	dma_free_coherent(NULL, self->rx_buff.truesize,			  self->rx_buff.head, self->rx_buff_dma); err_out2:	free_netdev(self->netdev);	dev_self[dev_count] = NULL; err_out1:	release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT);	release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT); err_out:	return err;}/* * Function smsc_ircc_present(fir_base, sir_base) * *    Check the smsc-ircc chip presence * */static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base){	unsigned char low, high, chip, config, dma, irq, version;	if (!request_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT,			    driver_name)) {		IRDA_WARNING("%s: can't get fir_base of 0x%03x\n",			     __FUNCTION__, fir_base);		goto out1;	}	if (!request_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT,			    driver_name)) {		IRDA_WARNING("%s: can't get sir_base of 0x%03x\n",			     __FUNCTION__, sir_base);		goto out2;	}	register_bank(fir_base, 3);	high    = inb(fir_base + IRCC_ID_HIGH);	low     = inb(fir_base + IRCC_ID_LOW);	chip    = inb(fir_base + IRCC_CHIP_ID);	version = inb(fir_base + IRCC_VERSION);	config  = inb(fir_base + IRCC_INTERFACE);	dma     = config & IRCC_INTERFACE_DMA_MASK;	irq     = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;	if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) {		IRDA_WARNING("%s(), addr 0x%04x - no device found!\n",			     __FUNCTION__, fir_base);		goto out3;	}	IRDA_MESSAGE("SMsC IrDA Controller found\n IrCC version %d.%d, "		     "firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n",		     chip & 0x0f, version, fir_base, sir_base, dma, irq);	return 0; out3:	release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT); out2:	release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT); out1:	return -ENODEV;}/* * Function smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq) * *    Setup I/O * */static void smsc_ircc_setup_io(struct smsc_ircc_cb *self,			       unsigned int fir_base, unsigned int sir_base,			       u8 dma, u8 irq){	unsigned char config, chip_dma, chip_irq;	register_bank(fir_base, 3);	config = inb(fir_base + IRCC_INTERFACE);	chip_dma = config & IRCC_INTERFACE_DMA_MASK;	chip_irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;	self->io.fir_base  = fir_base;	self->io.sir_base  = sir_base;	self->io.fir_ext   = SMSC_IRCC2_FIR_CHIP_IO_EXTENT;	self->io.sir_ext   = SMSC_IRCC2_SIR_CHIP_IO_EXTENT;	self->io.fifo_size = SMSC_IRCC2_FIFO_SIZE;	self->io.speed = SMSC_IRCC2_C_IRDA_FALLBACK_SPEED;	if (irq < 255) {		if (irq != chip_irq)			IRDA_MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",				     driver_name, chip_irq, irq);		self->io.irq = irq;	} else		self->io.irq = chip_irq;	if (dma < 255) {		if (dma != chip_dma)			IRDA_MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",				     driver_name, chip_dma, dma);		self->io.dma = dma;	} else		self->io.dma = chip_dma;}/* * Function smsc_ircc_setup_qos(self) * *    Setup qos * */static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self){	/* Initialize QoS for this device */	irda_init_max_qos_capabilies(&self->qos);	self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|		IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);	self->qos.min_turn_time.bits = SMSC_IRCC2_MIN_TURN_TIME;	self->qos.window_size.bits = SMSC_IRCC2_WINDOW_SIZE;	irda_qos_bits_to_value(&self->qos);}/* * Function smsc_ircc_init_chip(self) * *    Init chip * */static void smsc_ircc_init_chip(struct smsc_ircc_cb *self){	int iobase = self->io.fir_base;	register_bank(iobase, 0);	outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER);	outb(0x00, iobase + IRCC_MASTER);	register_bank(iobase, 1);	outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | IRCC_CFGA_IRDA_SIR_A),	     iobase + IRCC_SCE_CFGA);#ifdef smsc_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(SMSC_IRCC2_FIFO_THRESHOLD, iobase + IRCC_FIFO_THRESHOLD);	register_bank(iobase, 4);	outb((inb(iobase + IRCC_CONTROL) & 0x30), iobase + IRCC_CONTROL);	register_bank(iobase, 0);	outb(0, iobase + IRCC_LCR_A);	smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);	/* Power on device */	outb(0x00, iobase + IRCC_MASTER);}/* * Function smsc_ircc_net_ioctl (dev, rq, cmd) * *    Process IOCTL commands for this device * */static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct if_irda_req *irq = (struct if_irda_req *) rq;	struct smsc_ircc_cb *self;	unsigned long flags;	int ret = 0;	IRDA_ASSERT(dev != NULL, return -1;);	self = netdev_priv(dev);	IRDA_ASSERT(self != NULL, return -1;);	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);	switch (cmd) {	case SIOCSBANDWIDTH: /* Set bandwidth */		if (!capable(CAP_NET_ADMIN))			ret = -EPERM;                else {			/* Make sure we are the only one touching			 * self->io.speed and the hardware - Jean II */			spin_lock_irqsave(&self->lock, flags);			smsc_ircc_change_speed(self, irq->ifr_baudrate);			spin_unlock_irqrestore(&self->lock, flags);		}		break;	case SIOCSMEDIABUSY: /* Set media busy */		if (!capable(CAP_NET_ADMIN)) {			ret = -EPERM;			break;		}		irda_device_set_media_busy(self->netdev, TRUE);		break;	case SIOCGRECEIVING: /* Check if we are receiving right now */		irq->ifr_receiving = smsc_ircc_is_receiving(self);		break;	#if 0	case SIOCSDTRRTS:		if (!capable(CAP_NET_ADMIN)) {			ret = -EPERM;			break;		}		smsc_ircc_sir_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);		break;	#endif	default:		ret = -EOPNOTSUPP;	}	return ret;}static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev){	struct smsc_ircc_cb *self = netdev_priv(dev);	return &self->stats;}#if SMSC_IRCC2_C_NET_TIMEOUT/* * Function smsc_ircc_timeout (struct net_device *dev) * *    The networking timeout management. * */static void smsc_ircc_timeout(struct net_device *dev){	struct smsc_ircc_cb *self = netdev_priv(dev);	unsigned long flags;	IRDA_WARNING("%s: transmit timed out, changing speed to: %d\n",		     dev->name, self->io.speed);	spin_lock_irqsave(&self->lock, flags);	smsc_ircc_sir_start(self);	smsc_ircc_change_speed(self, self->io.speed);	dev->trans_start = jiffies;	netif_wake_queue(dev);	spin_unlock_irqrestore(&self->lock, flags);}#endif/* * Function smsc_ircc_hard_xmit_sir (struct sk_buff *skb, struct net_device *dev) * *    Transmits the current frame until FIFO is full, then *    waits until the next transmit interrupt, and continues until the *    frame is transmitted. */int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev){	struct smsc_ircc_cb *self;	unsigned long flags;	s32 speed;	IRDA_DEBUG(1, "%s\n", __FUNCTION__);	IRDA_ASSERT(dev != NULL, return 0;);	self = netdev_priv(dev);	IRDA_ASSERT(self != NULL, return 0;);	netif_stop_queue(dev);	/* Make sure test of self->io.speed & speed change are atomic */	spin_lock_irqsave(&self->lock, flags);	/* Check if we need to change the speed */	speed = irda_get_next_speed(skb);	if (speed != self->io.speed && speed != -1) {		/* Check for empty frame */		if (!skb->len) {			/*			 * We send frames one by one in SIR mode (no			 * pipelining), so at this point, if we were sending			 * a previous frame, we just received the interrupt			 * telling us it is finished (UART_IIR_THRI).			 * Therefore, waiting for the transmitter to really			 * finish draining the fifo won't take too long.			 * And the interrupt handler is not expected to run.			 * - Jean II */			smsc_ircc_sir_wait_hw_transmitter_finish(self);			smsc_ircc_change_speed(self, speed);			spin_unlock_irqrestore(&self->lock, flags);			dev_kfree_skb(skb);			return 0;		}		self->new_speed = speed;	}	/* Init tx buffer */	self->tx_buff.data = self->tx_buff.head;	/* Copy skb to tx_buff while wrapping, stuffing and making CRC */	self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,					   self->tx_buff.truesize);	self->stats.tx_bytes += self->tx_buff.len;	/* Turn on transmit finished interrupt. Will fire immediately!  */	outb(UART_IER_THRI, self->io.sir_base + UART_IER);	spin_unlock_irqrestore(&self->lock, flags);	dev_kfree_skb(skb);	return 0;}/* * Function smsc_ircc_set_fir_speed (self, baud) * *    Change the speed of the device * */static void smsc_ircc_set_fir_speed(struct smsc_ircc_cb *self, u32 speed){	int fir_base, ir_mode, ctrl, fast;	IRDA_ASSERT(self != NULL, return;);	fir_base = self->io.fir_base;	self->io.speed = speed;	switch (speed) {	default:	case 576000:		ir_mode = IRCC_CFGA_IRDA_HDLC;		ctrl = IRCC_CRC;		fast = 0;		IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__);		break;	case 1152000:		ir_mode = IRCC_CFGA_IRDA_HDLC;		ctrl = IRCC_1152 | IRCC_CRC;		fast = IRCC_LCR_A_FAST | IRCC_LCR_A_GP_DATA;		IRDA_DEBUG(0, "%s(), handling baud of 1152000\n",			   __FUNCTION__);		break;	case 4000000:		ir_mode = IRCC_CFGA_IRDA_4PPM;		ctrl = IRCC_CRC;		fast = IRCC_LCR_A_FAST;		IRDA_DEBUG(0, "%s(), handling baud of 4000000\n",			   __FUNCTION__);		break;	}	#if 0	Now in tranceiver!	/* This causes an interrupt */	register_bank(fir_base, 0);	outb((inb(fir_base + IRCC_LCR_A) &  0xbf) | fast, fir_base + IRCC_LCR_A);	#endif	register_bank(fir_base, 1);	outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base + IRCC_SCE_CFGA);	register_bank(fir_base, 4);	outb((inb(fir_base + IRCC_CONTROL) & 0x30) | ctrl, fir_base + IRCC_CONTROL);}/* * Function smsc_ircc_fir_start(self) * *    Change the speed of the device * */static void smsc_ircc_fir_start(struct smsc_ircc_cb *self){	struct net_device *dev;	int fir_base;	IRDA_DEBUG(1, "%s\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return;);	dev = self->netdev;	IRDA_ASSERT(dev != NULL, return;);	fir_base = self->io.fir_base;	/* Reset everything */	/* Install FIR transmit handler */	dev->hard_start_xmit = smsc_ircc_hard_xmit_fir;	/* Clear FIFO */	outb(inb(fir_base + IRCC_LCR_A) | IRCC_LCR_A_FIFO_RESET, fir_base + IRCC_LCR_A);	/* Enable interrupt */	/*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base + IRCC_IER);*/	register_bank(fir_base, 1);	/* Select the TX/RX interface */#ifdef SMSC_669 /* Uses pin 88/89 for Rx/Tx */	outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),	     fir_base + IRCC_SCE_CFGB);#else	outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),	     fir_base + IRCC_SCE_CFGB);#endif	(void) inb(fir_base + IRCC_FIFO_THRESHOLD);	/* Enable SCE interrupts */	outb(0, fir_base + IRCC_MASTER);	register_bank(fir_base, 0);	outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, fir_base + IRCC_IER);	outb(IRCC_MASTER_INT_EN, fir_base + IRCC_MASTER);}/* * Function smsc_ircc_fir_stop(self, baud) * *    Change the speed of the device * */static void smsc_ircc_fir_stop(struct smsc_ircc_cb *self){	int fir_base;	IRDA_DEBUG(1, "%s\n", __FUNCTION__);

⌨️ 快捷键说明

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