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

📄 pxaficp_ir.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/drivers/net/irda/pxaficp_ir.c * * Based on sa1100_ir.c by Russell King * * Changes copyright (C) 2003-2005 MontaVista Software, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Infra-red driver (SIR/FIR) for the PXA2xx embedded microprocessor * */#include <linux/module.h>#include <linux/types.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/netdevice.h>#include <linux/slab.h>#include <linux/rtnetlink.h>#include <linux/interrupt.h>#include <linux/dma-mapping.h>#include <linux/platform_device.h>#include <linux/pm.h>#include <net/irda/irda.h>#include <net/irda/irmod.h>#include <net/irda/wrapper.h>#include <net/irda/irda_device.h>#include <asm/irq.h>#include <asm/dma.h>#include <asm/delay.h>#include <asm/hardware.h>#include <asm/arch/irda.h>#include <asm/arch/pxa-regs.h>#ifdef CONFIG_MACH_MAINSTONE#include <asm/arch/mainstone.h>#endif#define IrSR_RXPL_NEG_IS_ZERO (1<<4)#define IrSR_RXPL_POS_IS_ZERO 0x0#define IrSR_TXPL_NEG_IS_ZERO (1<<3)#define IrSR_TXPL_POS_IS_ZERO 0x0#define IrSR_XMODE_PULSE_1_6  (1<<2)#define IrSR_XMODE_PULSE_3_16 0x0#define IrSR_RCVEIR_IR_MODE   (1<<1)#define IrSR_RCVEIR_UART_MODE 0x0#define IrSR_XMITIR_IR_MODE   (1<<0)#define IrSR_XMITIR_UART_MODE 0x0#define IrSR_IR_RECEIVE_ON (\                IrSR_RXPL_NEG_IS_ZERO | \                IrSR_TXPL_POS_IS_ZERO | \                IrSR_XMODE_PULSE_3_16 | \                IrSR_RCVEIR_IR_MODE   | \                IrSR_XMITIR_UART_MODE)#define IrSR_IR_TRANSMIT_ON (\                IrSR_RXPL_NEG_IS_ZERO | \                IrSR_TXPL_POS_IS_ZERO | \                IrSR_XMODE_PULSE_3_16 | \                IrSR_RCVEIR_UART_MODE | \                IrSR_XMITIR_IR_MODE)struct pxa_irda {	int			speed;	int			newspeed;	unsigned long		last_oscr;	unsigned char		*dma_rx_buff;	unsigned char		*dma_tx_buff;	dma_addr_t		dma_rx_buff_phy;	dma_addr_t		dma_tx_buff_phy;	unsigned int		dma_tx_buff_len;	int			txdma;	int			rxdma;	struct net_device_stats	stats;	struct irlap_cb		*irlap;	struct qos_info		qos;	iobuff_t		tx_buff;	iobuff_t		rx_buff;	struct device		*dev;	struct pxaficp_platform_data *pdata;};#define IS_FIR(si)		((si)->speed >= 4000000)#define IRDA_FRAME_SIZE_LIMIT	2047inline static void pxa_irda_fir_dma_rx_start(struct pxa_irda *si){	DCSR(si->rxdma)  = DCSR_NODESC;	DSADR(si->rxdma) = __PREG(ICDR);	DTADR(si->rxdma) = si->dma_rx_buff_phy;	DCMD(si->rxdma) = DCMD_INCTRGADDR | DCMD_FLOWSRC |  DCMD_WIDTH1 | DCMD_BURST32 | IRDA_FRAME_SIZE_LIMIT;	DCSR(si->rxdma) |= DCSR_RUN;}inline static void pxa_irda_fir_dma_tx_start(struct pxa_irda *si){	DCSR(si->txdma)  = DCSR_NODESC;	DSADR(si->txdma) = si->dma_tx_buff_phy;	DTADR(si->txdma) = __PREG(ICDR);	DCMD(si->txdma) = DCMD_INCSRCADDR | DCMD_FLOWTRG |  DCMD_ENDIRQEN | DCMD_WIDTH1 | DCMD_BURST32 | si->dma_tx_buff_len;	DCSR(si->txdma) |= DCSR_RUN;}/* * Set the IrDA communications speed. */static int pxa_irda_set_speed(struct pxa_irda *si, int speed){	unsigned long flags;	unsigned int divisor;	switch (speed) {	case 9600:	case 19200:	case 38400:	case 57600:	case 115200:		/* refer to PXA250/210 Developer's Manual 10-7 */		/*  BaudRate = 14.7456 MHz / (16*Divisor) */		divisor = 14745600 / (16 * speed);		local_irq_save(flags);		if (IS_FIR(si)) {			/* stop RX DMA */			DCSR(si->rxdma) &= ~DCSR_RUN;			/* disable FICP */			ICCR0 = 0;			pxa_set_cken(CKEN13_FICP, 0);			/* set board transceiver to SIR mode */			si->pdata->transceiver_mode(si->dev, IR_SIRMODE);			/* configure GPIO46/47 */			pxa_gpio_mode(GPIO46_STRXD_MD);			pxa_gpio_mode(GPIO47_STTXD_MD);			/* enable the STUART clock */			pxa_set_cken(CKEN5_STUART, 1);		}		/* disable STUART first */		STIER = 0;		/* access DLL & DLH */		STLCR |= LCR_DLAB;		STDLL = divisor & 0xff;		STDLH = divisor >> 8;		STLCR &= ~LCR_DLAB;		si->speed = speed;		STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6;		STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE;		local_irq_restore(flags);		break;	case 4000000:		local_irq_save(flags);		/* disable STUART */		STIER = 0;		STISR = 0;		pxa_set_cken(CKEN5_STUART, 0);		/* disable FICP first */		ICCR0 = 0;		/* set board transceiver to FIR mode */		si->pdata->transceiver_mode(si->dev, IR_FIRMODE);		/* configure GPIO46/47 */		pxa_gpio_mode(GPIO46_ICPRXD_MD);		pxa_gpio_mode(GPIO47_ICPTXD_MD);		/* enable the FICP clock */		pxa_set_cken(CKEN13_FICP, 1);		si->speed = speed;		pxa_irda_fir_dma_rx_start(si);		ICCR0 = ICCR0_ITR | ICCR0_RXE;		local_irq_restore(flags);		break;	default:		return -EINVAL;	}	return 0;}/* SIR interrupt service routine. */static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id){	struct net_device *dev = dev_id;	struct pxa_irda *si = netdev_priv(dev);	int iir, lsr, data;	iir = STIIR;	switch  (iir & 0x0F) {	case 0x06: /* Receiver Line Status */	  	lsr = STLSR;		while (lsr & LSR_FIFOE) {			data = STRBR;			if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) {				printk(KERN_DEBUG "pxa_ir: sir receiving error\n");				si->stats.rx_errors++;				if (lsr & LSR_FE)					si->stats.rx_frame_errors++;				if (lsr & LSR_OE)					si->stats.rx_fifo_errors++;			} else {				si->stats.rx_bytes++;				async_unwrap_char(dev, &si->stats, &si->rx_buff, data);			}			lsr = STLSR;		}		dev->last_rx = jiffies;		si->last_oscr = OSCR;		break;	case 0x04: /* Received Data Available */	  	   /* forth through */	case 0x0C: /* Character Timeout Indication */	  	do  {		    si->stats.rx_bytes++;	            async_unwrap_char(dev, &si->stats, &si->rx_buff, STRBR);	  	} while (STLSR & LSR_DR);	  	dev->last_rx = jiffies;		si->last_oscr = OSCR;	  	break;	case 0x02: /* Transmit FIFO Data Request */	    	while ((si->tx_buff.len) && (STLSR & LSR_TDRQ)) {	    		STTHR = *si->tx_buff.data++;			si->tx_buff.len -= 1;	    	}		if (si->tx_buff.len == 0) {			si->stats.tx_packets++;			si->stats.tx_bytes += si->tx_buff.data -					      si->tx_buff.head;                        /* We need to ensure that the transmitter has finished. */			while ((STLSR & LSR_TEMT) == 0)				cpu_relax();			si->last_oscr = OSCR;			/*		 	* Ok, we've finished transmitting.  Now enable		 	* the receiver.  Sometimes we get a receive IRQ		 	* immediately after a transmit...		 	*/			if (si->newspeed) {				pxa_irda_set_speed(si, si->newspeed);				si->newspeed = 0;			} else {				/* enable IR Receiver, disable IR Transmitter */				STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6;				/* enable STUART and receive interrupts */				STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE;			}			/* I'm hungry! */			netif_wake_queue(dev);		}		break;	}	return IRQ_HANDLED;}/* FIR Receive DMA interrupt handler */static void pxa_irda_fir_dma_rx_irq(int channel, void *data){	int dcsr = DCSR(channel);	DCSR(channel) = dcsr & ~DCSR_RUN;	printk(KERN_DEBUG "pxa_ir: fir rx dma bus error %#x\n", dcsr);}/* FIR Transmit DMA interrupt handler */static void pxa_irda_fir_dma_tx_irq(int channel, void *data){	struct net_device *dev = data;	struct pxa_irda *si = netdev_priv(dev);	int dcsr;	dcsr = DCSR(channel);	DCSR(channel) = dcsr & ~DCSR_RUN;	if (dcsr & DCSR_ENDINTR)  {		si->stats.tx_packets++;		si->stats.tx_bytes += si->dma_tx_buff_len;	} else {		si->stats.tx_errors++;	}	while (ICSR1 & ICSR1_TBY)		cpu_relax();	si->last_oscr = OSCR;	/*	 * HACK: It looks like the TBY bit is dropped too soon.	 * Without this delay things break.	 */	udelay(120);	if (si->newspeed) {		pxa_irda_set_speed(si, si->newspeed);		si->newspeed = 0;	} else {		ICCR0 = 0;		pxa_irda_fir_dma_rx_start(si);		ICCR0 = ICCR0_ITR | ICCR0_RXE;	}	netif_wake_queue(dev);}/* EIF(Error in FIFO/End in Frame) handler for FIR */static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev){	unsigned int len, stat, data;	/* Get the current data position. */	len = DTADR(si->rxdma) - si->dma_rx_buff_phy;	do {		/* Read Status, and then Data. 	 */		stat = ICSR1;		rmb();		data = ICDR;		if (stat & (ICSR1_CRE | ICSR1_ROR)) {			si->stats.rx_errors++;			if (stat & ICSR1_CRE) {				printk(KERN_DEBUG "pxa_ir: fir receive CRC error\n");				si->stats.rx_crc_errors++;			}			if (stat & ICSR1_ROR) {				printk(KERN_DEBUG "pxa_ir: fir receive overrun\n");				si->stats.rx_frame_errors++;			}		} else	{			si->dma_rx_buff[len++] = data;		}		/* If we hit the end of frame, there's no point in continuing. */		if (stat & ICSR1_EOF)			break;	} while (ICSR0 & ICSR0_EIF);	if (stat & ICSR1_EOF) {		/* end of frame. */		struct sk_buff *skb = alloc_skb(len+1,GFP_ATOMIC);		if (!skb)  {			printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n");			si->stats.rx_dropped++;			return;		}		/* Align IP header to 20 bytes  */		skb_reserve(skb, 1);		memcpy(skb->data, si->dma_rx_buff, len);		skb_put(skb, len);		/* Feed it to IrLAP  */		skb->dev = dev;		skb->mac.raw  = skb->data;		skb->protocol = htons(ETH_P_IRDA);		netif_rx(skb);		si->stats.rx_packets++;		si->stats.rx_bytes += len;		dev->last_rx = jiffies;	}}/* FIR interrupt handler */static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id){	struct net_device *dev = dev_id;	struct pxa_irda *si = netdev_priv(dev);	int icsr0;	/* stop RX DMA */	DCSR(si->rxdma) &= ~DCSR_RUN;	si->last_oscr = OSCR;	icsr0 = ICSR0;	if (icsr0 & (ICSR0_FRE | ICSR0_RAB)) {		if (icsr0 & ICSR0_FRE) {		        printk(KERN_DEBUG "pxa_ir: fir receive frame error\n");			si->stats.rx_frame_errors++;		} else {			printk(KERN_DEBUG "pxa_ir: fir receive abort\n");			si->stats.rx_errors++;		}		ICSR0 = icsr0 & (ICSR0_FRE | ICSR0_RAB);	}	if (icsr0 & ICSR0_EIF) {		/* An error in FIFO occured, or there is a end of frame */		pxa_irda_fir_irq_eif(si, dev);	}	ICCR0 = 0;	pxa_irda_fir_dma_rx_start(si);	ICCR0 = ICCR0_ITR | ICCR0_RXE;	return IRQ_HANDLED;}/* hard_xmit interface of irda device */static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev){	struct pxa_irda *si = netdev_priv(dev);	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

⌨️ 快捷键说明

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