📄 pxa_ir.c
字号:
/* * linux/drivers/net/irda/pxa_ir.c * * Author: * Alexey Lugovskoy RTSoft. * lugovskoy@rtsoft.msk.ru * * Dmitrij Frasenyak RTSoft. * sed@mipt.sw.ru * * 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 SIR and FIR driver for the PXA 210/250 embedded microprocessors * Based on linux/drivers/net/irda/sa1100_ir.c * */#include <linux/config.h>#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/delay.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/dma-mapping.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/hardware.h>#include <asm/mach-types.h>#include <asm/arch/lubbock.h>static int rx_count = 0;static int tx_count = 0;/* * Our netdevice. There is only ever one of these. */ static struct net_device *netdev;struct pxa250_irda { unsigned char open; int speed; int newspeed; struct sk_buff *txskb; struct sk_buff *rxskb; /* => FIR */ unsigned int fir_irq; int txdma_ch; int rxdma_ch; dma_addr_t txbuf_dma; dma_addr_t rxbuf_dma; void* txbuf_dma_virt; void* rxbuf_dma_virt; /* <= FIR*/ struct net_device_stats stats; struct device *dev; struct irlap_cb *irlap; struct pm_dev *pmdev; struct qos_info qos; /* => SIR */ iobuff_t tx_buff; iobuff_t rx_buff; /* <= SIR */};#define IS_FIR(si) ((si)->speed >= 4000000)#define HPSIR_MAX_RXLEN 2050#define HPSIR_MAX_TXLEN 2050#define TXBUFF_MAX_SIZE HPSIR_MAX_TXLEN#define SET_SIR_MODE STISR = STISR_RCVEIR | STISR_XMITIR | STISR_XMODE/* * If you want to disable debug information * please uncomment line bellow */#define PXA_FIR_DUMP_ENABLE#undef PXA_FIR_DUMP_ENABLE #define PXA_FIR_DEBUG_ENABLE#undef PXA_FIR_DEBUG_ENABLE #define PXA_FIR_IRQ_DEBUG_ENABLE#undef PXA_FIR_IRQ_DEBUG_ENABLE #ifdef PXA_FIR_DEBUG_ENABLE#define __ECHO_IN printk(KERN_ERR "%s: enter\n",__FUNCTION__);#define __ECHO_OUT printk(KERN_ERR "%s: exit\n",__FUNCTION__);#define DBG(args...) printk(KERN_ERR __FUNCTION__"():"args);#else#define __ECHO_IN#define __ECHO_OUT#define DBG(args...)#endif#ifdef PXA_FIR_IRQ_DEBUG_ENABLE#define DBG_IRQ(args...) printk(KERN_ERR __FUNCTION__"():"args);#else#define DBG_IRQ(args...)#endifstatic int pxa250_irda_set_speed(struct net_device *dev,int speed);static void pxa250_start_rx_dma(struct net_device *dev);/************************************************************************** * Misc FIR/SIR functions * **************************************************************************//* * Allocate the receive buffer, unless it is already allocated. */static int pxa250_irda_rx_alloc(struct pxa250_irda *si){ __ECHO_IN; if (si->rxskb) return 0; si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC); if (!si->rxskb) { printk(KERN_ERR "pxa250_ir: out of memory for RX SKB\n"); return -ENOMEM; } /* * Align any IP headers that may be contained * within the frame. */ skb_reserve(si->rxskb, 1); __ECHO_OUT; return 0;}/************************************************************************** * FIR * **************************************************************************/static inline void pxa250_dma_stop(int ch){ __ECHO_IN; DCSR(ch) &= ~DCSR_RUN; __ECHO_OUT; }static void pxa250_ficp_rx_start(void){ ICCR0 = 0; ICCR2 = 1 << 2 | 0 << 3 ; ICCR0 = ICCR0_ITR ; ICCR0 |= ICCR0_RIE | ICCR0_RXE ; }/* * Change Alternative Function encoding * Enable ICP unit * Disabe STUART unit * Enable IRQ unit clock; * Configure direction of GPIO used by ICP */static void pxa250_do_fir_GPIO_config(void){ /* * Modify GPIO 46 and 47 Alternate Function */ __ECHO_IN; /*Switch AF*/ pxa_gpio_mode (GPIO46_ICPRXD_MD); pxa_gpio_mode (GPIO47_ICPTXD_MD);#ifndef CONFIG_ARCH_FS_PXA255 //we don't remap FPGA, so can't do this,hzh if (machine_is_lubbock()) LUB_MISC_WR |= 1 << 4;#endif /*init clock*/ CKEN |= CKEN13_FICP; __ECHO_OUT;}/* * Low level hardware configuration and startup. */static int pxa250_fir_irda_startup(struct pxa250_irda *si){ __ECHO_IN; /* * Disable STUART */ STIER &= ~IER_UUE; /*Disable STUART FIFO */ STFCR = 0; /* * Do low level configuration for HW AF and clock */ pxa250_do_fir_GPIO_config(); __ECHO_OUT; return 0;}/* * Aieeeeee .. we should never get here :( */static void pxa250_irda_rxdma_irq(int ch,void *id, struct pt_regs *regs){ struct net_device *dev=id; struct pxa250_irda *si=dev->priv; u_int dcsr; __ECHO_IN; /* * Make sure that irq is our. */ if ( ch != si->rxdma_ch ) /*just*/ return; /* * Check status */ dcsr = DCSR(ch); DBG("DCSR=%x\n",dcsr); if (dcsr & DCSR_STOPSTATE ) { DBG_IRQ("Chanel %d in stop state\n",ch); } if (dcsr & DCSR_BUSERR ) { /* * BUS Error we must restart reception */ DBG("PXA IrDA: bus error interrupt on channel %d\n", ch); DCSR(ch) |= DCSR_BUSERR; } if (dcsr & DCSR_ENDINTR ) { DBG("PXA IrDA: Normal end of dma channel %d - packet to big\n", ch); DCSR(ch) |= DCSR_ENDINTR; } /* no mater what restart rx*/ pxa250_start_rx_dma(dev); return ; }static void pxa250_irda_txdma_irq(int ch, void *id , struct pt_regs *regs){ struct net_device *dev=id; struct pxa250_irda *si=dev->priv; struct sk_buff *skb = si->txskb; u_int dcsr; __ECHO_IN; DBG_IRQ("transmit\n"); /* * Make sure that irq is our. */ if ( ch != si->txdma_ch ) /*just*/ return; /* * Check status */ dcsr = DCSR(ch); DBG("DCSR=%x",dcsr); if (dcsr & DCSR_STOPSTATE ) { DBG("Chanel %d in stop state\n",ch); } if (dcsr & DCSR_BUSERR ) { DBG("PXA IrDA: bus error interrupt on channel %d\n", ch); DCSR(ch) |= DCSR_BUSERR; si->txskb = NULL; } if (dcsr & DCSR_ENDINTR ) { DBG("PXA IrDA: Normal end of dma channel %d\n", ch); DCSR(ch) |= DCSR_ENDINTR; si->txskb = NULL; } /* * Account and free the packet. */ if (skb) { si->stats.tx_packets ++; si->stats.tx_bytes += skb->len; dev_kfree_skb_irq(skb); } /*Disable transceiver and enable receiver*/ if (si->newspeed) { pxa250_irda_set_speed(dev, si->newspeed); si->newspeed = 0; } while (ICSR1 & ICSR1_TBY) udelay(1); ICCR0 &= ~ICCR0_TXE; enable_irq(si->fir_irq); ICCR0 |= ICCR0_RXE; /* * Make sure that the TX queue is available for sending * (for retries). TX has priority over RX at all times. */ netif_wake_queue(dev); __ECHO_OUT;}static void pxa250_start_rx_dma(struct net_device *dev){ struct pxa250_irda *si = dev->priv; int ch=si->rxdma_ch; if (!si->rxskb) { DBG("rx buffer went missing\n");/* return; */ } DCSR(ch)=0; DCSR(ch)=DCSR_NODESC; DSADR(ch) = __PREG(ICDR); DTADR(ch) = si->rxbuf_dma; /* phisical address */; /* We should never do END_IRQ. !!!*/ DCMD(ch) = DCMD_ENDIRQEN| DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_BURST8 | DCMD_WIDTH1 | HPSIR_MAX_RXLEN; /* * All right information will be available as soon as we set RXE flag */ DCSR(ch) = DCSR_ENDINTR | DCSR_BUSERR; DCSR(ch) = DCSR_RUN | DCSR_NODESC ;}static int pxa250_get_rx_len(struct pxa250_irda *si){ /* * DMA have to be stoped here */ if ( ! (DCSR(si->rxdma_ch) & DCSR_STOPSTATE) ) printk("warning dma have to be stoped befor counting len\n"); return ( HPSIR_MAX_RXLEN - ( DCMD(si->rxdma_ch) & DCMD_LENGTH ) ); }static void pxa250_irda_fir_error(struct net_device *dev){ struct pxa250_irda *si = dev->priv; struct sk_buff *skb = si->rxskb; int len; int stat,data; __ECHO_IN; if (!skb) { printk("pxa250 fir_error: SKB is NULL!\n"); return; } /* * Get the current data position. */ len=pxa250_get_rx_len(si); DBG("RXLEN=%d\n",len); memcpy(skb->data, si->rxbuf_dma_virt, len); 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) si->stats.rx_crc_errors++; if (stat & ICSR1_ROR) si->stats.rx_frame_errors++; } else skb->data[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) { 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. */ si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC); if (!si->rxskb) { printk(KERN_ERR "pxa250_ir: out of memory for RX SKB\n"); return; } /* * Align any IP headers that may be contained * within the frame. */ skb_reserve(si->rxskb, 1); netif_rx(skb); }}/* * FIR format interrupt service routine. We only have to * handle RX events; transmit events go via the TX DMA irq handler. * * No matter what, we disable RX, process, and then restart RX. */static irqreturn_t pxa250_irda_fir_irq(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = dev_id; struct pxa250_irda *si = dev->priv; int status; /* * Stop RX */ __ECHO_IN; pxa250_dma_stop(si->rxdma_ch); /* * Framing error - we throw away the packet completely. * Clearing RXE flushes the error conditions and data * from the fifo. */ status=ICSR0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -