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

📄 pxaficp_ir.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	 * 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;			pxa_irda_set_speed(si, speed);		}		dev_kfree_skb(skb);		return 0;	}	netif_stop_queue(dev);	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);		/* Disable STUART interrupts and switch to transmit mode. */		STIER = 0;		STISR = IrSR_IR_TRANSMIT_ON | IrSR_XMODE_PULSE_1_6;		/* enable STUART and transmit interrupts */		STIER = IER_UUE | IER_TIE;	} else {		unsigned long mtt = irda_get_mtt(skb);		si->dma_tx_buff_len = skb->len;		memcpy(si->dma_tx_buff, skb->data, skb->len);		if (mtt)			while ((unsigned)(OSCR - si->last_oscr)/4 < mtt)				cpu_relax();		/* stop RX DMA,  disable FICP */		DCSR(si->rxdma) &= ~DCSR_RUN;		ICCR0 = 0;		pxa_irda_fir_dma_tx_start(si);		ICCR0 = ICCR0_ITR | ICCR0_TXE;	}	dev_kfree_skb(skb);	dev->trans_start = jiffies;	return 0;}static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd){	struct if_irda_req *rq = (struct if_irda_req *)ifreq;	struct pxa_irda *si = netdev_priv(dev);	int ret;	switch (cmd) {	case SIOCSBANDWIDTH:		ret = -EPERM;		if (capable(CAP_NET_ADMIN)) {			/*			 * We are unable to set the speed if the			 * device is not running.			 */			if (netif_running(dev)) {				ret = pxa_irda_set_speed(si,						rq->ifr_baudrate);			} else {				printk(KERN_INFO "pxa_ir: 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:		ret = 0;		rq->ifr_receiving = IS_FIR(si) ? 0					: si->rx_buff.state != OUTSIDE_FRAME;		break;	default:		ret = -EOPNOTSUPP;		break;	}	return ret;}static struct net_device_stats *pxa_irda_stats(struct net_device *dev){	struct pxa_irda *si = netdev_priv(dev);	return &si->stats;}static void pxa_irda_startup(struct pxa_irda *si){	/* Disable STUART interrupts */	STIER = 0;	/* enable STUART interrupt to the processor */	STMCR = MCR_OUT2;	/* configure SIR frame format: StartBit - Data 7 ... Data 0 - Stop Bit */	STLCR = LCR_WLS0 | LCR_WLS1;	/* enable FIFO, we use FIFO to improve performance */	STFCR = FCR_TRFIFOE | FCR_ITL_32;	/* disable FICP */	ICCR0 = 0;	/* configure FICP ICCR2 */	ICCR2 = ICCR2_TXP | ICCR2_TRIG_32;	/* configure DMAC */	DRCMR17 = si->rxdma | DRCMR_MAPVLD;	DRCMR18 = si->txdma | DRCMR_MAPVLD;	/* force SIR reinitialization */	si->speed = 4000000;	pxa_irda_set_speed(si, 9600);	printk(KERN_DEBUG "pxa_ir: irda startup\n");}static void pxa_irda_shutdown(struct pxa_irda *si){	unsigned long flags;	local_irq_save(flags);	/* disable STUART and interrupt */	STIER = 0;	/* disable STUART SIR mode */	STISR = 0;	/* disable the STUART clock */	pxa_set_cken(CKEN5_STUART, 0);	/* disable DMA */	DCSR(si->txdma) &= ~DCSR_RUN;	DCSR(si->rxdma) &= ~DCSR_RUN;	/* disable FICP */	ICCR0 = 0;	/* disable the FICP clock */	pxa_set_cken(CKEN13_FICP, 0);	DRCMR17 = 0;	DRCMR18 = 0;	local_irq_restore(flags);	/* power off board transceiver */	si->pdata->transceiver_mode(si->dev, IR_OFF);	printk(KERN_DEBUG "pxa_ir: irda shutdown\n");}static int pxa_irda_start(struct net_device *dev){	struct pxa_irda *si = netdev_priv(dev);	int err;	si->speed = 9600;	err = request_irq(IRQ_STUART, pxa_irda_sir_irq, 0, dev->name, dev);	if (err)		goto err_irq1;	err = request_irq(IRQ_ICP, pxa_irda_fir_irq, 0, dev->name, dev);	if (err)		goto err_irq2;	/*	 * The interrupt must remain disabled for now.	 */	disable_irq(IRQ_STUART);	disable_irq(IRQ_ICP);	err = -EBUSY;	si->rxdma = pxa_request_dma("FICP_RX",DMA_PRIO_LOW, pxa_irda_fir_dma_rx_irq, dev);	if (si->rxdma < 0)		goto err_rx_dma;	si->txdma = pxa_request_dma("FICP_TX",DMA_PRIO_LOW, pxa_irda_fir_dma_tx_irq, dev);	if (si->txdma < 0)		goto err_tx_dma;	err = -ENOMEM;	si->dma_rx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT,					     &si->dma_rx_buff_phy, GFP_KERNEL );	if (!si->dma_rx_buff)		goto err_dma_rx_buff;	si->dma_tx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT,					     &si->dma_tx_buff_phy, GFP_KERNEL );	if (!si->dma_tx_buff)		goto err_dma_tx_buff;	/* Setup the serial port for the initial speed. */	pxa_irda_startup(si);	/*	 * Open a new IrLAP layer instance.	 */	si->irlap = irlap_open(dev, &si->qos, "pxa");	err = -ENOMEM;	if (!si->irlap)		goto err_irlap;	/*	 * Now enable the interrupt and start the queue	 */	enable_irq(IRQ_STUART);	enable_irq(IRQ_ICP);	netif_start_queue(dev);	printk(KERN_DEBUG "pxa_ir: irda driver opened\n");	return 0;err_irlap:	pxa_irda_shutdown(si);	dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy);err_dma_tx_buff:	dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy);err_dma_rx_buff:	pxa_free_dma(si->txdma);err_tx_dma:	pxa_free_dma(si->rxdma);err_rx_dma:	free_irq(IRQ_ICP, dev);err_irq2:	free_irq(IRQ_STUART, dev);err_irq1:	return err;}static int pxa_irda_stop(struct net_device *dev){	struct pxa_irda *si = netdev_priv(dev);	netif_stop_queue(dev);	pxa_irda_shutdown(si);	/* Stop IrLAP */	if (si->irlap) {		irlap_close(si->irlap);		si->irlap = NULL;	}	free_irq(IRQ_STUART, dev);	free_irq(IRQ_ICP, dev);	pxa_free_dma(si->rxdma);	pxa_free_dma(si->txdma);	if (si->dma_rx_buff)		dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy);	if (si->dma_tx_buff)		dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy);	printk(KERN_DEBUG "pxa_ir: irda driver closed\n");	return 0;}static int pxa_irda_suspend(struct platform_device *_dev, pm_message_t state){	struct net_device *dev = platform_get_drvdata(_dev);	struct pxa_irda *si;	if (dev && netif_running(dev)) {		si = netdev_priv(dev);		netif_device_detach(dev);		pxa_irda_shutdown(si);	}	return 0;}static int pxa_irda_resume(struct platform_device *_dev){	struct net_device *dev = platform_get_drvdata(_dev);	struct pxa_irda *si;	if (dev && netif_running(dev)) {		si = netdev_priv(dev);		pxa_irda_startup(si);		netif_device_attach(dev);		netif_wake_queue(dev);	}	return 0;}static int pxa_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 pxa_irda_probe(struct platform_device *pdev){	struct net_device *dev;	struct pxa_irda *si;	unsigned int baudrate_mask;	int err;	if (!pdev->dev.platform_data)		return -ENODEV;	err = request_mem_region(__PREG(STUART), 0x24, "IrDA") ? 0 : -EBUSY;	if (err)		goto err_mem_1;	err = request_mem_region(__PREG(FICP), 0x1c, "IrDA") ? 0 : -EBUSY;	if (err)		goto err_mem_2;	dev = alloc_irdadev(sizeof(struct pxa_irda));	if (!dev)		goto err_mem_3;	si = netdev_priv(dev);	si->dev = &pdev->dev;	si->pdata = pdev->dev.platform_data;	/*	 * Initialise the SIR buffers	 */	err = pxa_irda_init_iobuf(&si->rx_buff, 14384);	if (err)		goto err_mem_4;	err = pxa_irda_init_iobuf(&si->tx_buff, 4000);	if (err)		goto err_mem_5;	dev->hard_start_xmit	= pxa_irda_hard_xmit;	dev->open		= pxa_irda_start;	dev->stop		= pxa_irda_stop;	dev->do_ioctl		= pxa_irda_ioctl;	dev->get_stats		= pxa_irda_stats;	irda_init_max_qos_capabilies(&si->qos);	baudrate_mask = 0;	if (si->pdata->transceiver_cap & IR_SIRMODE)		baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;	if (si->pdata->transceiver_cap & IR_FIRMODE)		baudrate_mask |= IR_4000000 << 8;	si->qos.baud_rate.bits &= baudrate_mask;	si->qos.min_turn_time.bits = 7;  /* 1ms or more */	irda_qos_bits_to_value(&si->qos);	err = register_netdev(dev);	if (err == 0)		dev_set_drvdata(&pdev->dev, dev);	if (err) {		kfree(si->tx_buff.head);err_mem_5:		kfree(si->rx_buff.head);err_mem_4:		free_netdev(dev);err_mem_3:		release_mem_region(__PREG(FICP), 0x1c);err_mem_2:		release_mem_region(__PREG(STUART), 0x24);	}err_mem_1:	return err;}static int pxa_irda_remove(struct platform_device *_dev){	struct net_device *dev = platform_get_drvdata(_dev);	if (dev) {		struct pxa_irda *si = netdev_priv(dev);		unregister_netdev(dev);		kfree(si->tx_buff.head);		kfree(si->rx_buff.head);		free_netdev(dev);	}	release_mem_region(__PREG(STUART), 0x24);	release_mem_region(__PREG(FICP), 0x1c);	return 0;}static struct platform_driver pxa_ir_driver = {	.driver         = {		.name   = "pxa2xx-ir",	},	.probe		= pxa_irda_probe,	.remove		= pxa_irda_remove,	.suspend	= pxa_irda_suspend,	.resume		= pxa_irda_resume,};static int __init pxa_irda_init(void){	return platform_driver_register(&pxa_ir_driver);}static void __exit pxa_irda_exit(void){	platform_driver_unregister(&pxa_ir_driver);}module_init(pxa_irda_init);module_exit(pxa_irda_exit);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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