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

📄 sa1100_ir.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 2 页
字号:
		si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,						HPSIR_MAX_RXLEN,						DMA_FROM_DEVICE);	}}/* * 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_stop_dma(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 irqreturn_t sa1100_irda_irq(int irq, void *dev_id){	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);	return IRQ_HANDLED;}/* * TX DMA completion handler. */static void sa1100_irda_txdma_irq(void *id){	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) {		dma_unmap_single(si->dev, si->txbuf_dma, skb->len, DMA_TO_DEVICE);		si->stats.tx_packets ++;		si->stats.tx_bytes += skb->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);}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)) {		netif_stop_queue(dev);		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...		 */		BUG_ON(si->txskb);		netif_stop_queue(dev);		si->txskb = skb;		si->txbuf_dma = dma_map_single(si->dev, skb->data,					 skb->len, DMA_TO_DEVICE);		sa1100_start_dma(si->txdma, 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;	si->speed = 9600;	err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev);	if (err)		goto err_irq;	err = sa1100_request_dma(DMA_Ser2HSSPRd, "IrDA receive",				 NULL, NULL, &si->rxdma);	if (err)		goto err_rx_dma;	err = sa1100_request_dma(DMA_Ser2HSSPWr, "IrDA transmit",				 sa1100_irda_txdma_irq, dev, &si->txdma);	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;	/*	 * 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:	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) {		dma_unmap_single(si->dev, si->rxbuf_dma, HPSIR_MAX_RXLEN,				 DMA_FROM_DEVICE);		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);	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_probe(struct platform_device *pdev){	struct net_device *dev;	struct sa1100_irda *si;	unsigned int baudrate_mask;	int err;	if (!pdev->dev.platform_data)		return -EINVAL;	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;	dev = alloc_irdadev(sizeof(struct sa1100_irda));	if (!dev)		goto err_mem_4;	si = dev->priv;	si->dev = &pdev->dev;	si->pdata = pdev->dev.platform_data;	/*	 * Initialise the HP-SIR buffers	 */	err = sa1100_irda_init_iobuf(&si->rx_buff, 14384);	if (err)		goto err_mem_5;	err = sa1100_irda_init_iobuf(&si->tx_buff, 4000);	if (err)		goto err_mem_5;	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;	dev->irq		= IRQ_Ser2ICP;	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;	switch (max_rate) {	case 4000000:		baudrate_mask |= IR_4000000 << 8;	case 115200:		baudrate_mask |= IR_115200;	case 57600:		baudrate_mask |= IR_57600;	case 38400:		baudrate_mask |= IR_38400;	case 19200:		baudrate_mask |= IR_19200;	}			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;	err = register_netdev(dev);	if (err == 0)		platform_set_drvdata(pdev, dev);	if (err) { err_mem_5:		kfree(si->tx_buff.head);		kfree(si->rx_buff.head);		free_netdev(dev); err_mem_4:		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 int sa1100_irda_remove(struct platform_device *pdev){	struct net_device *dev = platform_get_drvdata(pdev);	if (dev) {		struct sa1100_irda *si = dev->priv;		unregister_netdev(dev);		kfree(si->tx_buff.head);		kfree(si->rx_buff.head);		free_netdev(dev);	}	release_mem_region(__PREG(Ser2HSCR2), 0x04);	release_mem_region(__PREG(Ser2HSCR0), 0x1c);	release_mem_region(__PREG(Ser2UTCR0), 0x24);	return 0;}static struct platform_driver sa1100ir_driver = {	.probe		= sa1100_irda_probe,	.remove		= sa1100_irda_remove,	.suspend	= sa1100_irda_suspend,	.resume		= sa1100_irda_resume,	.driver		= {		.name	= "sa11x0-ir",	},};static int __init sa1100_irda_init(void){	/*	 * Limit power level a sensible range.	 */	if (power_level < 1)		power_level = 1;	if (power_level > 3)		power_level = 3;	return platform_driver_register(&sa1100ir_driver);}static void __exit sa1100_irda_exit(void){	platform_driver_unregister(&sa1100ir_driver);}module_init(sa1100_irda_init);module_exit(sa1100_irda_exit);module_param(power_level, int, 0);module_param(tx_lpm, int, 0);module_param(max_rate, int, 0);MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");MODULE_DESCRIPTION("StrongARM SA1100 IrDA driver");MODULE_LICENSE("GPL");MODULE_PARM_DESC(power_level, "IrDA power level, 1 (low) to 3 (high)");MODULE_PARM_DESC(tx_lpm, "Enable transmitter low power (1.6us) mode");MODULE_PARM_DESC(max_rate, "Maximum baud rate (4000000, 115200, 57600, 38400, 19200, 9600)");

⌨️ 快捷键说明

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