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

📄 ep93xx_irda.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 5 页
字号:
/********************************************************************* *                 * Filename:      ep93xx_irda.c * Version:       0.2 * Description:   Driver for the EP93xx SOC IrDA. * Status:        Experimental. * * Copyright 2003 Cirrus Logic, Inc. * * Based loosely on the ali-ircc.c implementation: * *      Author:        Benjamin Kong <benjamin_kong@ali.com.tw> *      Created at:    2000/10/16 03:46PM *      Modified at:   2001/1/3 02:55PM *      Modified by:   Benjamin Kong <benjamin_kong@ali.com.tw> *  *      Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw> *      All Rights Reserved *       *      This program is free software; you can redistribute it and/or  *      modify it under the terms of the GNU General Public License as  *      published by the Free Software Foundation; either version 2 of  *      the License, or (at your option) any later version. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to: *      Free Software Foundation, Inc. *      59 Temple Place, Suite 330  *      Boston, MA  02111-1307  USA ********************************************************************/#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/rtnetlink.h>#include <linux/serial_reg.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/byteorder.h>#include <linux/pm.h>#include <net/irda/wrapper.h>#include <net/irda/irda.h>#include <net/irda/irmod.h>#include <net/irda/irlap_frame.h>#include <net/irda/irda_device.h>#include <asm/arch/dma.h>#include <net/irda/ep93xx_irda.h>#include <asm/arch/irqs.h>static char *driver_name = "ep93xx-irda";static char *SIR_str = "SIR only";static char *SIRMIR_str = "SIR/MIR only";static char *SIRFIR_str = "SIR/MIR only";static char *SIRMFIR_str = "SIR/MIR/FIR";/*  * Turnaround time:   * Min. time the HW can respond. *  * Interestingly, most drivers set this value to * 0x1.  That would mean the index in bits_to_value * would end up with a value of 0 and the min_turn_times * array's [0] value is '10000'(us).  * * 0-7 are the only valid index positions for the  * min_turn_times array.  With the bitshift discovery  * method used (and the IrDA spec wanting contiguous bits),  * only values of 0xFF, 0x7f, 0x3F, 0x1F, 0xF, 0x7, 0x3,  * & 0x1 are valid assignments for this variable. *  * (look at qos.c's min_turn_times array, bits_to_value and * msb_index functions to validate) */static int qos_mtt_bits = 0x7;/* * Modes the clock settings will support. */static int g_iClkSupport = 0;/* * Initialization prototypes. */static int ep93xx_irda_init_9312(ep93xx_chip_t *chip);/* * Currently known EP93xx SOC packages. */static ep93xx_chip_t chips[] ={    	/* name|irqs|sir dmatx|sir dmarx|mfir dmatx|mfir dmarx|init func */	{ "EP9312", IRQ_UART2, IRQ_IRDA, DMATx_UART2, DMATx_IRDA, DMARx_IRDA, ep93xx_irda_init_9312 },	{ NULL }};/*  * Max 4 instances (as is "standard" for an IrDA driver). */static struct ep93xx_irda_cb *dev_self[] = { NULL, NULL, NULL, NULL };/*  * Prototypes.  */ /*  * General ep93xx family.  */ static int  ep93xx_irda_open(int i, ep93xx_chip_t *chip); #ifdef MODULE static int  ep93xx_irda_close(struct ep93xx_irda_cb *self); #endif /* MODULE */ static int  ep93xx_irda_setup(ep93xx_chip_t *chip); static int  ep93xx_irda_is_receiving(struct ep93xx_irda_cb *self); static int  ep93xx_irda_net_init(struct net_device *dev); static int  ep93xx_irda_net_open(struct net_device *dev); static int  ep93xx_irda_net_close(struct net_device *dev); static int  ep93xx_irda_net_ioctl(struct net_device *dev, struct ifreq *rq,      int cmd); static void ep93xx_irda_change_speed(struct ep93xx_irda_cb *self,      __u32 baud); static void ep93xx_irda_interrupt(int irq, void *dev_id,      struct pt_regs *regs);#ifdef POWER_SAVING static int ep93xx_irda_pmproc(struct pm_dev *dev, pm_request_t rqst, 		 void *data); static void ep93xx_irda_suspend(struct ep93xx_irda_cb *self); static void ep93xx _irda_wakeup(struct ep93xx_irda_cb *self);#endif  static struct net_device_stats *ep93xx_irda_net_get_stats(struct net_device *dev);/*  * Driver SIR functions  */static void ep93xx_irda_sir_change_speed(struct ep93xx_irda_cb *priv,                                          __u32 speed);static void ep93xx_irda_sir_interrupt(int irq, struct ep93xx_irda_cb *self,                                       struct pt_regs *regs);static void ep93xx_irda_sir_receive(struct ep93xx_irda_cb *self);static void ep93xx_irda_sir_write_wakeup(struct ep93xx_irda_cb *self);static int ep93xx_irda_sir_write(int iFifo_size, __u8 *pBuf, int iLen);/*  * Driver MIR/FIR functions  */static void ep93xx_irda_mfir_change_speed(struct ep93xx_irda_cb *priv,                                           __u32 speed);static void ep93xx_irda_mfir_interrupt(int irq, struct ep93xx_irda_cb *self,                                        struct pt_regs *regs);/* * Driver DMA functions */static int  ep93xx_irda_dma_receive(struct ep93xx_irda_cb *self); static int  ep93xx_irda_dma_receive_complete(struct ep93xx_irda_cb *self, unsigned int frameSize);static int  ep93xx_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev);static void ep93xx_irda_dma_xmit(struct ep93xx_irda_cb *self);static int  ep93xx_irda_dma_xmit_complete(struct ep93xx_irda_cb *self, int irqID);/*  * State change functions  */static void SIR2MFIR(struct ep93xx_irda_cb *self, __u32 TargetSpeed);static void MFIR2SIR(struct ep93xx_irda_cb *self, __u32 TargetSpeed);static void SetInterrupts(struct ep93xx_irda_cb *self, unsigned char enable);static void SetIR_Transmit(unsigned char ucEnable);static void SetIR_Receive(unsigned char ucEnable);static void SetDMA(struct ep93xx_irda_cb *self, unsigned char direction,                    unsigned char enable);/* * Local DEFINES  *//* * Define to signal usage of PIO mode only for transmits. */#define PIO_TX/* * Define to signal console printing of debug statements. *///#define DEBUG#ifdef DEBUG	/* 	 * DEBUG_LEVEL determines which DEBUG statements to print.	 */	#define DEBUG_LEVEL 1	#define EP93XX_DEBUG(x,y...) (x <= DEBUG_LEVEL) ? printk( ##y ) : 0#else	#define EP93XX_DEBUG(x,y...)#endif/* * Function ep93xx_irda_init () * *    Initialize block.  Verify some basic knowns before proceding setup/load. *     */int __init ep93xx_irda_init(void){    ep93xx_chip_t *chip;    unsigned long ulRegValue;    int ret = -ENODEV;    int i = 0;	    EP93XX_DEBUG(2, "%s(), ---------------- Start ----------------\n",         __FUNCTION__);    /*      * Check for all the EP93xx SOC packages we know about .     */    for(chip = chips; chip->name; chip++, i++)     {	EP93XX_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__, chip->name);				 	/*          * Prepare to test some knowns for the SOC.          */        ulRegValue = 0;        /*         *   Read the CHIP_ID register to make sure the family is correct.         */         ulRegValue = inl(SYSCON_CHIPID);        EP93XX_DEBUG(1, "SYSCON_CHIPID = 0x%x\n", ulRegValue);        if(chip->name)	{	    EP93XX_DEBUG(2, "%s(), Found %s SOC IrDA block, at 0x%03x\n",				__FUNCTION__, chip->name, IRDA_BASE);					            /*             * Resource usage is fixed.  Initialize and open.             */            chip->init(chip);				    if(ep93xx_irda_open(i, chip) == 0)            {				ret = 0;            }	    i++;					}	else	{	    EP93XX_DEBUG(2, "%s(), No %s SOC IrDA block found.\n",                 __FUNCTION__, chip->name);	}    }					EP93XX_DEBUG(2, "%s(), ----------------- End -----------------\n",         __FUNCTION__);	return(ret);}/* * Function ep93xx_irda_cleanup () * *    Close all configured chips * */#ifdef MODULEstatic void ep93xx_irda_cleanup(void){	int i;	EP93XX_DEBUG(2, "%s(), ---------------- Start ----------------\n",         __FUNCTION__);			pm_unregister_all(ep93xx_irda_pmproc);	for(i = 0; i < 4; i++)         {		if(dev_self[i])        	{			ep93xx_irda_close(dev_self[i]);         	}	}		EP93XX_DEBUG(2, "%s(), ----------------- End -----------------\n",         __FUNCTION__);}#endif /* MODULE *//* * Function ep93xx_irda_open (int i, ep93xx_chip_t *info) * *    Open driver instance. * */static int ep93xx_irda_open(int i, ep93xx_chip_t *info){	struct net_device *dev;	struct ep93xx_irda_cb *self;#ifdef POWER_SAVING		struct pm_dev *pmdev;#endif		int err;	dma_addr_t rxdmaphys, txdmaphys;				EP93XX_DEBUG(2, "%s(), ---------------- Start ----------------\n",         __FUNCTION__);		    /*      * Get setup for the attack run...      */    if((ep93xx_irda_setup(info)) == -1)    {	return(-1);    }		    /*      * Allocate a new instance of the driver      */    self = kmalloc(sizeof(struct ep93xx_irda_cb), GFP_KERNEL);    if(self == NULL)     { 	ERROR("%s(), can't allocate memory for control block!\n",             __FUNCTION__);	return(-ENOMEM);    }    memset(self, 0, sizeof(struct ep93xx_irda_cb));    spin_lock_init(&self->lock);       /*      * Track 'self' pointer      */    dev_self[i] = self;    self->index = i;    /*      * Save important SOC data, starting with IRQs used      */    self->iSIR_irq = info->iSIR_IRQ;    self->iMFIR_irq = info->iMFIR_IRQ;    /*      * ep93xx DMA port ids      */    self->ePorts[DMA_SIR_TX] = info->eSIR_DMATx;    self->ePorts[DMA_MFIR_TX] = info->eMFIR_DMATx;    self->ePorts[DMA_MFIR_RX] = info->eMFIR_DMARx;    self->fifo_size = 16;    /*      * Initialize QoS for this device      */    irda_init_max_qos_capabilies(&self->qos);	    /*      * Override some values returned by max_qos      */    self->qos.baud_rate.bits = 0;        if(g_iClkSupport & CLK_SIR)    {       self->qos.baud_rate.bits |= IR_9600|IR_19200|IR_38400|IR_57600|	       IR_115200;    }    if(g_iClkSupport & CLK_MIR)    {	self->qos.baud_rate.bits |= IR_576000|IR_1152000;    }    if(g_iClkSupport & CLK_FIR)    {	self->qos.baud_rate.bits |= (IR_4000000 << 8);    }        /*      * Turnaround time      */    self->qos.min_turn_time.bits = qos_mtt_bits;			    irda_qos_bits_to_value(&self->qos);	    self->flags = IFF_SIR|IFF_MIR|IFF_FIR|IFF_DMA|IFF_PIO; 	    /*      * Max DMA buffer size needed = (data_size + 6) * (window_size) + 6;     */    self->rx_buff.truesize = 14384;     self->tx_buff.truesize = 14384;        /*      * Allocate memory      */    self->rx_buff.head = (__u8 *)consistent_alloc(GFP_KERNEL|GFP_DMA, 		    self->rx_buff.truesize, &rxdmaphys);        if(self->rx_buff.head == NULL)     { 	kfree(self);	return(-ENOMEM);    }    memcpy(&self->rx_dmaphysh, &rxdmaphys, sizeof(dma_addr_t));    memset(self->rx_buff.head, 0, self->rx_buff.truesize);	    self->tx_buff.head = (__u8 *) consistent_alloc(GFP_KERNEL|GFP_DMA,		    self->tx_buff.truesize, &txdmaphys);        if(self->tx_buff.head == NULL)     {	consistent_free(self->rx_buff.head, self->rx_buff.truesize, rxdmaphys);	kfree(self);	return(-ENOMEM);    }    memcpy(&self->tx_dmaphysh, &txdmaphys, sizeof(dma_addr_t));    memset(self->tx_buff.head, 0, self->tx_buff.truesize);        /*     * Conversion buffer.  Temp holding space for DMA buffers.     * Needed for SIR RX.     */    self->conv_buf = (__u8 *) kmalloc(self->rx_buff.truesize,                        GFP_KERNEL);    memset(self->conv_buf, 0, self->rx_buff.truesize);    self->rx_buff.in_frame = FALSE;    self->rx_buff.state = OUTSIDE_FRAME;    self->tx_buff.data = self->tx_buff.head;    self->rx_buff.data = self->rx_buff.head;	    /*      * Reset Tx queue info      */    self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;    self->tx_fifo.tail = self->tx_buff.head;    if(!(dev = dev_alloc("irda%d", &err)))     { 	ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);	return(-ENOMEM);    }    dev->priv = (void *) self;    self->netdev = dev;	    /*     * Override the network functions we need to use      */    dev->init            = ep93xx_irda_net_init;    dev->hard_start_xmit = ep93xx_irda_hard_xmit;    dev->open            = ep93xx_irda_net_open;    dev->stop            = ep93xx_irda_net_close;    dev->do_ioctl        = ep93xx_irda_net_ioctl;    dev->get_stats	     = ep93xx_irda_net_get_stats;    rtnl_lock();    err = register_netdevice(dev);    rtnl_unlock();	    if(err)     {	ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);	return(-1);    }       MESSAGE("IrDA: Registered device %s\n", dev->name);#ifdef POWER_SAVING	pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, ep93xx_irda_pmproc);    if(pmdev)    {            pmdev->data = self;    }#endif    EP93XX_DEBUG(2, "%s(), ----------------- End -----------------\n",         __FUNCTION__);	    return(0);}#ifdef MODULE/* * Function ep93xx_irda_close (self) * *    Close driver instance. * */static int ep93xx_irda_close(struct ep93xx_irda_cb *self){    EP93XX_DEBUG(2, "%s(), ---------------- Start ----------------\n",         __FUNCTION__);    ASSERT(self != NULL, return -1;);    /*     * Remove netdevice      */    if(self->netdev)     {	rtnl_lock();	unregister_netdevice(self->netdev);	rtnl_unlock();    }    if(self->tx_buff.head)    {	consistent_free(self->tx_buff.head, self->tx_buff.truesize, 			self->tx_dmaphysh);    }	    if(self->rx_buff.head)    {	consistent_free(self->rx_buff.head, self->rx_buff.truesize, 			self->rx_dmaphysh);    }    dev_self[self->index] = NULL;    kfree(self);	    EP93XX_DEBUG(2, "%s(), ----------------- End -----------------\n",         __FUNCTION__);	    return(0);

⌨️ 快捷键说明

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