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

📄 sa1100_ir.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (stat & HSSR1_EOF) {		si->rxskb = NULL;		skb_put(skb, len);		skb->dev = dev;		skb->mac.raw = skb->data;		skb->protocol = htons(ETH_P_IRDA);		si->stats.rx_packets++;		si->stats.rx_bytes += len;		/*		 * Before we pass the buffer up, allocate a new one.		 */		sa1100_irda_rx_alloc(si);		netif_rx(skb);	} else {		/*		 * Remap the buffer.		 */		si->rxbuf_dma = pci_map_single(NULL, si->rxskb->data,						HPSIR_MAX_RXLEN,						PCI_DMA_FROMDEVICE);	}}/* * FIR format interrupt service routine.  We only have to * handle RX events; transmit events go via the TX DMA handler. * * No matter what, we disable RX, process, and the restart RX. */static void sa1100_irda_fir_irq(struct net_device *dev){	struct sa1100_irda *si = dev->priv;	/*	 * Stop RX DMA	 */	sa1100_dma_stop(si->rxdma);	/*	 * Framing error - we throw away the packet completely.	 * Clearing RXE flushes the error conditions and data	 * from the fifo.	 */	if (Ser2HSSR0 & (HSSR0_FRE | HSSR0_RAB)) {		si->stats.rx_errors++;		if (Ser2HSSR0 & HSSR0_FRE)			si->stats.rx_frame_errors++;		/*		 * Clear out the DMA...		 */		Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;		/*		 * Clear selected status bits now, so we		 * don't miss them next time around.		 */		Ser2HSSR0 = HSSR0_FRE | HSSR0_RAB;	}	/*	 * Deal with any receive errors.  The any of the lowest	 * 8 bytes in the FIFO may contain an error.  We must read	 * them one by one.  The "error" could even be the end of	 * packet!	 */	if (Ser2HSSR0 & HSSR0_EIF)		sa1100_irda_fir_error(si, dev);	/*	 * No matter what happens, we must restart reception.	 */	sa1100_irda_rx_dma_start(si);}static void sa1100_irda_irq(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	if (IS_FIR(((struct sa1100_irda *)dev->priv)))		sa1100_irda_fir_irq(dev);	else		sa1100_irda_hpsir_irq(dev);}/* * TX DMA completion handler. */static void sa1100_irda_txdma_irq(void *id, int len){	struct net_device *dev = id;	struct sa1100_irda *si = dev->priv;	struct sk_buff *skb = si->txskb;	si->txskb = NULL;	/*	 * Wait for the transmission to complete.  Unfortunately,	 * the hardware doesn't give us an interrupt to indicate	 * "end of frame".	 */	do		rmb();	while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY);	/*	 * Clear the transmit underrun bit.	 */	Ser2HSSR0 = HSSR0_TUR;	/*	 * Do we need to change speed?  Note that we're lazy	 * here - we don't free the old rxskb.  We don't need	 * to allocate a buffer either.	 */	if (si->newspeed) {		sa1100_irda_set_speed(si, si->newspeed);		si->newspeed = 0;	}	/*	 * Start reception.  This disables the transmitter for	 * us.  This will be using the existing RX buffer.	 */	sa1100_irda_rx_dma_start(si);	/*	 * Account and free the packet.	 */	if (skb) {		pci_unmap_single(NULL, si->txbuf_dma, len, PCI_DMA_TODEVICE);		si->stats.tx_packets ++;		si->stats.tx_bytes += len;		dev_kfree_skb_irq(skb);	}	/*	 * Make sure that the TX queue is available for sending	 * (for retries).  TX has priority over RX at all times.	 */	netif_wake_queue(dev);}/* * Note that we will never build up a backlog of frames; the protocol is a * half duplex protocol which basically means we transmit a frame, we * receive a frame, we transmit the next frame etc. */static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev){	struct sa1100_irda *si = dev->priv;	int speed = irda_get_next_speed(skb);	/*	 * Does this packet contain a request to change the interface	 * speed?  If so, remember it until we complete the transmission	 * of this frame.	 */	if (speed != si->speed && speed != -1)		si->newspeed = speed;	/*	 * If this is an empty frame, we can bypass a lot.	 */	if (skb->len == 0) {		if (si->newspeed) {			si->newspeed = 0;			sa1100_irda_set_speed(si, speed);		}		dev_kfree_skb(skb);		return 0;	}	if (!IS_FIR(si)) {		si->tx_buff.data = si->tx_buff.head;		si->tx_buff.len  = async_wrap_skb(skb, si->tx_buff.data,						  si->tx_buff.truesize);		/*		 * Set the transmit interrupt enable.  This will fire		 * off an interrupt immediately.  Note that we disable		 * the receiver so we won't get spurious characteres		 * received.		 */		Ser2UTCR3 = UTCR3_TIE | UTCR3_TXE;		dev_kfree_skb(skb);	} else {		int mtt = irda_get_mtt(skb);		/*		 * We must not be transmitting...		 */		if (si->txskb)			BUG();		netif_stop_queue(dev);		si->txskb = skb;		si->txbuf_dma = pci_map_single(NULL, skb->data,					 skb->len, PCI_DMA_TODEVICE);		sa1100_dma_queue_buffer(si->txdma, dev, si->txbuf_dma,					skb->len);		/*		 * If we have a mean turn-around time, impose the specified		 * specified delay.  We could shorten this by timing from		 * the point we received the packet.		 */		if (mtt)			udelay(mtt);		Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE;	}	dev->trans_start = jiffies;	return 0;}static intsa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd){	struct if_irda_req *rq = (struct if_irda_req *)ifreq;	struct sa1100_irda *si = dev->priv;	int ret = -EOPNOTSUPP;	switch (cmd) {	case SIOCSBANDWIDTH:		if (capable(CAP_NET_ADMIN)) {			/*			 * We are unable to set the speed if the			 * device is not running.			 */			if (si->open) {				ret = sa1100_irda_set_speed(si,						rq->ifr_baudrate);			} else {				printk("sa1100_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n");				ret = 0;			}		}		break;	case SIOCSMEDIABUSY:		ret = -EPERM;		if (capable(CAP_NET_ADMIN)) {			irda_device_set_media_busy(dev, TRUE);			ret = 0;		}		break;	case SIOCGRECEIVING:		rq->ifr_receiving = IS_FIR(si) ? 0					: si->rx_buff.state != OUTSIDE_FRAME;		break;	default:		break;	}			return ret;}static struct net_device_stats *sa1100_irda_stats(struct net_device *dev){	struct sa1100_irda *si = dev->priv;	return &si->stats;}static int sa1100_irda_start(struct net_device *dev){	struct sa1100_irda *si = dev->priv;	int err;	MOD_INC_USE_COUNT;	si->speed = 9600;	err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev);	if (err)		goto err_irq;	err = sa1100_request_dma(&si->rxdma, "IrDA receive", DMA_Ser2HSSPRd);	if (err)		goto err_rx_dma;	err = sa1100_request_dma(&si->txdma, "IrDA transmit", DMA_Ser2HSSPWr);	if (err)		goto err_tx_dma;	/*	 * The interrupt must remain disabled for now.	 */	disable_irq(dev->irq);	/*	 * Setup the serial port for the specified speed.	 */	err = sa1100_irda_startup(si);	if (err)		goto err_startup;	/*	 * Open a new IrLAP layer instance.	 */	si->irlap = irlap_open(dev, &si->qos, "sa1100");	err = -ENOMEM;	if (!si->irlap)		goto err_irlap;	sa1100_dma_set_callback(si->txdma, sa1100_irda_txdma_irq);	/*	 * Now enable the interrupt and start the queue	 */	si->open = 1;	sa1100_set_power(si, power_level); /* low power mode */	enable_irq(dev->irq);	netif_start_queue(dev);	return 0;err_irlap:	si->open = 0;	sa1100_irda_shutdown(si);err_startup:	sa1100_free_dma(si->txdma);err_tx_dma:	sa1100_free_dma(si->rxdma);err_rx_dma:	free_irq(dev->irq, dev);err_irq:	MOD_DEC_USE_COUNT;	return err;}static int sa1100_irda_stop(struct net_device *dev){	struct sa1100_irda *si = dev->priv;	disable_irq(dev->irq);	sa1100_irda_shutdown(si);	/*	 * If we have been doing DMA receive, make sure we	 * tidy that up cleanly.	 */	if (si->rxskb) {		pci_unmap_single(NULL, si->rxbuf_dma, HPSIR_MAX_RXLEN,				 PCI_DMA_FROMDEVICE);		dev_kfree_skb(si->rxskb);		si->rxskb = NULL;	}	/* Stop IrLAP */	if (si->irlap) {		irlap_close(si->irlap);		si->irlap = NULL;	}	netif_stop_queue(dev);	si->open = 0;	/*	 * Free resources	 */	sa1100_free_dma(si->txdma);	sa1100_free_dma(si->rxdma);	free_irq(dev->irq, dev);	sa1100_set_power(si, 0);	MOD_DEC_USE_COUNT;	return 0;}static int sa1100_irda_init_iobuf(iobuff_t *io, int size){	io->head = kmalloc(size, GFP_KERNEL | GFP_DMA);	if (io->head != NULL) {		io->truesize = size;		io->in_frame = FALSE;		io->state    = OUTSIDE_FRAME;		io->data     = io->head;	}	return io->head ? 0 : -ENOMEM;}static int sa1100_irda_net_init(struct net_device *dev){	struct sa1100_irda *si = dev->priv;	unsigned int baudrate_mask;	int err = -ENOMEM;	si = kmalloc(sizeof(struct sa1100_irda), GFP_KERNEL);	if (!si)		goto out;	memset(si, 0, sizeof(*si));	/*	 * Initialise the HP-SIR buffers	 */	err = sa1100_irda_init_iobuf(&si->rx_buff, 14384);	if (err)		goto out;	err = sa1100_irda_init_iobuf(&si->tx_buff, 4000);	if (err)		goto out_free_rx;	dev->priv = si;	dev->hard_start_xmit	= sa1100_irda_hard_xmit;	dev->open		= sa1100_irda_start;	dev->stop		= sa1100_irda_stop;	dev->do_ioctl		= sa1100_irda_ioctl;	dev->get_stats		= sa1100_irda_stats;	irda_device_setup(dev);	irda_init_max_qos_capabilies(&si->qos);	/*	 * We support original IRDA up to 115k2. (we don't currently	 * support 4Mbps).  Min Turn Time set to 1ms or greater.	 */	baudrate_mask = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;	baudrate_mask |= IR_4000000 << 8;	si->qos.baud_rate.bits &= baudrate_mask;	si->qos.min_turn_time.bits = 7;	irda_qos_bits_to_value(&si->qos);	si->utcr4 = UTCR4_HPSIR;	if (tx_lpm)		si->utcr4 |= UTCR4_Z1_6us;	/*	 * Initially enable HP-SIR modulation, and ensure that the port	 * is disabled.	 */	Ser2UTCR3 = 0;	Ser2UTCR4 = si->utcr4;	Ser2HSCR0 = HSCR0_UART;#ifdef CONFIG_PM	/*	 * Power-Management is optional.	 */	si->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, sa1100_irda_pmproc);	if (si->pmdev)		si->pmdev->data = dev;#endif	return 0;	kfree(si->tx_buff.head);out_free_rx:	kfree(si->rx_buff.head);out:	kfree(si);	return err;}/* * Remove all traces of this driver module from the kernel, so we can't be * called.  Note that the device has already been stopped, so we don't have * to worry about interrupts or dma. */static void sa1100_irda_net_uninit(struct net_device *dev){	struct sa1100_irda *si = dev->priv;	dev->hard_start_xmit	= NULL;	dev->open		= NULL;	dev->stop		= NULL;	dev->do_ioctl		= NULL;	dev->get_stats		= NULL;	dev->priv		= NULL;	pm_unregister(si->pmdev);	kfree(si->tx_buff.head);	kfree(si->rx_buff.head);	kfree(si);}#ifdef MODULEstatic#endifint __init sa1100_irda_init(void){	struct net_device *dev;	int err;	/*	 * Limit power level a sensible range.	 */	if (power_level < 1)		power_level = 1;	if (power_level > 3)		power_level = 3;	err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY;	if (err)		goto err_mem_1;	err = request_mem_region(__PREG(Ser2HSCR0), 0x1c, "IrDA") ? 0 : -EBUSY;	if (err)		goto err_mem_2;	err = request_mem_region(__PREG(Ser2HSCR2), 0x04, "IrDA") ? 0 : -EBUSY;	if (err)		goto err_mem_3;	rtnl_lock();	dev = dev_alloc("irda%d", &err);	if (dev) {		dev->irq    = IRQ_Ser2ICP;		dev->init   = sa1100_irda_net_init;		dev->uninit = sa1100_irda_net_uninit;		err = register_netdevice(dev);		if (err)			kfree(dev);		else			netdev = dev;	}	rtnl_unlock();	if (err) {		release_mem_region(__PREG(Ser2HSCR2), 0x04);err_mem_3:		release_mem_region(__PREG(Ser2HSCR0), 0x1c);err_mem_2:		release_mem_region(__PREG(Ser2UTCR0), 0x24);	}err_mem_1:	return err;}static void __exit sa1100_irda_exit(void){	struct net_device *dev = netdev;	netdev = NULL;	if (dev) {		rtnl_lock();		unregister_netdevice(dev);		rtnl_unlock();	}	release_mem_region(__PREG(Ser2HSCR2), 0x04);	release_mem_region(__PREG(Ser2HSCR0), 0x1c);	release_mem_region(__PREG(Ser2UTCR0), 0x24);	/*	 * We now know that the netdevice is no longer in use, and all	 * references to our driver have been removed.  The only structure	 * which may still be present is the netdevice, which will get	 * cleaned up by net/core/dev.c	 */}#ifdef MODULEmodule_init(sa1100_irda_init);module_exit(sa1100_irda_exit);#endifMODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");MODULE_DESCRIPTION("StrongARM SA1100 IrDA driver");MODULE_LICENSE("GPL");MODULE_PARM(power_level, "i");MODULE_PARM_DESC(power_level, "IrDA power level, 1 (low) to 3 (high)");MODULE_PARM(tx_lpm, "i");MODULE_PARM_DESC(tx_lpm, "Enable transmitter low power (1.6us) mode");EXPORT_NO_SYMBOLS;

⌨️ 快捷键说明

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