LITMUS^RT and MC^2 V0 support for the pandaboard.
aboutsummaryrefslogblamecommitdiffstats
path: root/drivers/net/irda/au1k_ir.c
blob: a3d696a9456a10a9d4f659cc70ad1982f2a7e58d (plain) (tree)



















                                                                           

















                                                                
                                 














                                                                      
                                             
                                                 












                                                                     































































































































                                                                          





                                                           

  










                                                         
                                                































































                                                                              

                                                          



































































                                                                              
                                                                           




                                                              
                                                                           









































































































































                                                                              
                                    








                                                              
                                      




                                                                            
                                      












                                                             
                                                                     




















                                                                          
                            













































                                                              
                                                                






                                                      
                                                                            
                                       
                                                  












                                                                      





                 
                                                               
 
                                        




                                                          

                           

















































































                                                                        
                                                              





                                                              
                                                              









































































































                                                                               




                                                
/*
 * Alchemy Semi Au1000 IrDA driver
 *
 * Copyright 2001 MontaVista Software Inc.
 * Author: MontaVista Software, Inc.
 *         	ppopov@mvista.com or source@mvista.com
 *
 *  This program is free software; you can distribute it and/or modify it
 *  under the terms of the GNU General Public License (Version 2) as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope 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 the Free Software Foundation, Inc.,
 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
 */
#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/pm.h>
#include <linux/bitops.h>

#include <asm/irq.h>
#include <asm/io.h>
#include <asm/au1000.h>
#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100)
#include <asm/pb1000.h>
#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
#include <asm/db1x00.h>
#include <asm/mach-db1x00/bcsr.h>
#else 
#error au1k_ir: unsupported board
#endif

#include <net/irda/irda.h>
#include <net/irda/irmod.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda_device.h>
#include "au1000_ircc.h"

static int au1k_irda_net_init(struct net_device *);
static int au1k_irda_start(struct net_device *);
static int au1k_irda_stop(struct net_device *dev);
static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *);
static int au1k_irda_rx(struct net_device *);
static void au1k_irda_interrupt(int, void *);
static void au1k_tx_timeout(struct net_device *);
static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int);
static int au1k_irda_set_speed(struct net_device *dev, int speed);

static void *dma_alloc(size_t, dma_addr_t *);
static void dma_free(void *, size_t);

static int qos_mtt_bits = 0x07;  /* 1 ms or more */
static struct net_device *ir_devs[NUM_IR_IFF];
static char version[] __devinitdata =
    "au1k_ircc:1.2 ppopov@mvista.com\n";

#define RUN_AT(x) (jiffies + (x))

static DEFINE_SPINLOCK(ir_lock);

/*
 * IrDA peripheral bug. You have to read the register
 * twice to get the right value.
 */
u32 read_ir_reg(u32 addr) 
{ 
	readl(addr);
	return readl(addr);
}


/*
 * Buffer allocation/deallocation routines. The buffer descriptor returned
 * has the virtual and dma address of a buffer suitable for 
 * both, receive and transmit operations.
 */
static db_dest_t *GetFreeDB(struct au1k_private *aup)
{
	db_dest_t *pDB;
	pDB = aup->pDBfree;

	if (pDB) {
		aup->pDBfree = pDB->pnext;
	}
	return pDB;
}

static void ReleaseDB(struct au1k_private *aup, db_dest_t *pDB)
{
	db_dest_t *pDBfree = aup->pDBfree;
	if (pDBfree)
		pDBfree->pnext = pDB;
	aup->pDBfree = pDB;
}


/*
  DMA memory allocation, derived from pci_alloc_consistent.
  However, the Au1000 data cache is coherent (when programmed
  so), therefore we return KSEG0 address, not KSEG1.
*/
static void *dma_alloc(size_t size, dma_addr_t * dma_handle)
{
	void *ret;
	int gfp = GFP_ATOMIC | GFP_DMA;

	ret = (void *) __get_free_pages(gfp, get_order(size));

	if (ret != NULL) {
		memset(ret, 0, size);
		*dma_handle = virt_to_bus(ret);
		ret = (void *)KSEG0ADDR(ret);
	}
	return ret;
}


static void dma_free(void *vaddr, size_t size)
{
	vaddr = (void *)KSEG0ADDR(vaddr);
	free_pages((unsigned long) vaddr, get_order(size));
}


static void 
setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base)
{
	int i;
	for (i=0; i<NUM_IR_DESC; i++) {
		aup->rx_ring[i] = (volatile ring_dest_t *) 
			(rx_base + sizeof(ring_dest_t)*i);
	}
	for (i=0; i<NUM_IR_DESC; i++) {
		aup->tx_ring[i] = (volatile ring_dest_t *) 
			(tx_base + sizeof(ring_dest_t)*i);
	}
}

static int au1k_irda_init(void)
{
	static unsigned version_printed = 0;
	struct au1k_private *aup;
	struct net_device *dev;
	int err;

	if (version_printed++ == 0) printk(version);

	dev = alloc_irdadev(sizeof(struct au1k_private));
	if (!dev)
		return -ENOMEM;

	dev->irq = AU1000_IRDA_RX_INT; /* TX has its own interrupt */
	err = au1k_irda_net_init(dev);
	if (err)
		goto out;
	err = register_netdev(dev);
	if (err)
		goto out1;
	ir_devs[0] = dev;
	printk(KERN_INFO "IrDA: Registered device %s\n", dev->name);
	return 0;

out1:
	aup = netdev_priv(dev);