From cb0081f07881844f97f24c4d37b470f180718ca7 Mon Sep 17 00:00:00 2001
From: Philip Balister <balister@moose.(none)>
Date: Wed, 13 Jan 2010 14:35:39 -0500
Subject: [PATCH] usrp-embedded : Add driver for USRP Embedded FPGA interface.

---
 arch/arm/mach-omap2/board-overo.c |  176 +++++-
 drivers/misc/Kconfig              |    9 +
 drivers/misc/Makefile             |    1 +
 drivers/misc/usrp_e.c             | 1481 +++++++++++++++++++++++++++++++++++++
 include/linux/usrp_e.h            |   87 +++
 5 files changed, 1750 insertions(+), 4 deletions(-)
 create mode 100644 drivers/misc/usrp_e.c
 create mode 100644 include/linux/usrp_e.h

diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 8a44c17..8686015 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -35,6 +35,8 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mmc/host.h>
 
+#include <linux/spi/spi.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
@@ -63,6 +65,8 @@
 #define OVERO_GPIO_USBH_NRESET	183
 
 #define NAND_BLOCK_SIZE SZ_128K
+#define GPMC_CS0_BASE  0x60
+#define GPMC_CS_SIZE   0x30
 
 #define OVERO_SMSC911X_CS      5
 #define OVERO_SMSC911X_GPIO    176
@@ -164,7 +168,9 @@ static struct platform_device overo_smsc911x2_device = {
 
 static struct platform_device *smsc911x_devices[] = {
 	&overo_smsc911x_device,
+#if 0
 	&overo_smsc911x2_device,
+#endif
 };
 
 static inline void __init overo_init_smsc911x(void)
@@ -194,6 +200,7 @@ static inline void __init overo_init_smsc911x(void)
 
 	/* set up second smsc911x chip */
 
+#if 0
 	if (gpmc_cs_request(OVERO_SMSC911X2_CS, SZ_16M, &cs_mem_base2) < 0) {
 		printk(KERN_ERR "Failed request for GPMC mem for smsc911x2\n");
 		return;
@@ -213,6 +220,7 @@ static inline void __init overo_init_smsc911x(void)
 	overo_smsc911x2_resources[1].start = OMAP_GPIO_IRQ(OVERO_SMSC911X2_GPIO);
 	overo_smsc911x2_resources[1].end   = 0;
 
+#endif
 	platform_add_devices(smsc911x_devices, ARRAY_SIZE(smsc911x_devices));
 }
 
@@ -353,6 +361,16 @@ static struct regulator_consumer_supply overo_vdda_dac_supply =
 static struct regulator_consumer_supply overo_vdds_dsi_supply =
 	REGULATOR_SUPPLY("vdds_dsi", "omapdss");
 
+static struct spi_board_info overo_mcspi_board_info[] = {
+	{
+		.modalias	= "spidev",
+		.max_speed_hz	= 12000000, // 12 MHz
+		.bus_num	= 1,
+		.chip_select	= 0,
+		.mode		= SPI_MODE_1,
+	},
+};
+
 static struct mtd_partition overo_nand_partitions[] = {
 	{
 		.name           = "xloader",
@@ -432,8 +450,8 @@ static struct omap2_hsmmc_info mmc[] = {
 		.mmc		= 2,
 		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
-		.gpio_wp	= -EINVAL,
-		.transceiver	= true,
+		.transceiver    = true,
+		.gpio_wp	= 150,
 		.ocr_mask	= 0x00100000,	/* 3.3V */
 	},
 	{}	/* Terminator */
@@ -612,6 +630,8 @@ static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
 static struct omap_board_mux board_mux[] __initdata = {
 	{ .reg_offset = OMAP_MUX_TERMINATOR },
 };
+#else
+#define board_mux	NULL
 #endif
 
 static struct omap_musb_board_data musb_board_data = {
@@ -626,6 +646,148 @@ static struct omap_musb_board_data musb_board_data = {
 	.power			= 100,
 };
 
+static void __init usrp1_e_init(void)
+{
+	unsigned int tmp;
+
+	printk("Setup up gpmc timing.\n");
+
+// Set up CS4, data read/write
+
+#if 1
+	// Signal control parameters per chip select
+	tmp = gpmc_cs_read_reg(4, GPMC_CS_CONFIG1);
+//	tmp |= (GPMC_CONFIG1_MUXADDDATA);
+//	tmp |= (GPMC_CONFIG1_WRITETYPE_SYNC);
+//	tmp |= (GPMC_CONFIG1_READTYPE_SYNC);
+	tmp |= (GPMC_CONFIG1_FCLK_DIV(0));
+	gpmc_cs_write_reg(4, GPMC_CS_CONFIG1, tmp);
+	printk("GPMC_CONFIG1 reg: %x\n", tmp);
+#endif
+
+#if 1 
+	// CS signal timing parameter configuration
+	tmp = 0;
+	tmp |= GPMC_CONFIG2_CSONTIME(1);         /*  1 */
+	tmp |= GPMC_CONFIG2_CSWROFFTIME(16);     /* 16 */
+	tmp |= GPMC_CONFIG2_CSRDOFFTIME(16);     /* 16 */
+	printk("GPMC_CONFIG2 reg: %x\n", tmp);
+	gpmc_cs_write_reg(4, GPMC_CS_CONFIG2, tmp);
+#endif 
+
+#if 0
+	// nADV signal timing parameter configuration
+        tmp = 0;
+        tmp |= GPMC_CONFIG3_ADVONTIME(1);
+        tmp |= GPMC_CONFIG3_ADVRDOFFTIME(2);
+        tmp |= GPMC_CONFIG3_ADVWROFFTIME(2);
+        printk("GPMC_CONFIG3 reg: %x\n", tmp);
+        gpmc_cs_write_reg(4, GPMC_CS_CONFIG3, tmp);
+#endif
+
+#if 1
+	// nWE and nOE signals timing parameter configuration
+	tmp = 0;
+	tmp |= GPMC_CONFIG4_WEONTIME(3);      /*  3 */
+	tmp |= GPMC_CONFIG4_WEOFFTIME(16);     /* 16 */
+	tmp |= GPMC_CONFIG4_OEONTIME(3);      /*  3 */
+	tmp |= GPMC_CONFIG4_OEOFFTIME(16);     /* 16 */
+	printk("GPMC_CONFIG4 reg: %x\n", tmp);
+	gpmc_cs_write_reg(4, GPMC_CS_CONFIG4, tmp);
+#endif
+
+#if 1
+	// RdAccess time and Cycle time timing parameters configuration
+	tmp = 0;
+	tmp |= GPMC_CONFIG5_PAGEBURSTACCESSTIME(1);
+	tmp |= GPMC_CONFIG5_RDACCESSTIME(15);           /* 15 */
+	tmp |= GPMC_CONFIG5_WRCYCLETIME(17);           /* 17 */
+	tmp |= GPMC_CONFIG5_RDCYCLETIME(17);           /* 17 */
+	printk("GPMC_CONFIG5 reg: %x\n", tmp);
+
+	gpmc_cs_write_reg(4, GPMC_CS_CONFIG5, tmp);
+#endif
+
+#if 1
+	// WrAccessTime WrDataOnADmuxBus, Cycle2Cycle, and BusTurnAround params
+	tmp = (1<<31);
+	tmp |= GPMC_CONFIG6_WRACCESSTIME(15);          /* 15 */
+	tmp |= GPMC_CONFIG6_WRDATAONADMUXBUS(3);
+	tmp |= GPMC_CONFIG6_CYCLE2CYCLEDELAY(0);
+	tmp |= GPMC_CONFIG6_BUSTURNAROUND(0);
+	printk("GPMC_CONFIG6 reg: %x\n", tmp);
+	gpmc_cs_write_reg(4, GPMC_CS_CONFIG6, tmp);
+#endif
+
+// Configure timing for CS6, wishbone access
+
+#if 1
+	// Signal control parameters per chip select
+	tmp = gpmc_cs_read_reg(6, GPMC_CS_CONFIG1);
+//	tmp |= (GPMC_CONFIG1_MUXADDDATA);
+	tmp |= (GPMC_CONFIG1_WRITETYPE_SYNC);
+	tmp |= (GPMC_CONFIG1_READTYPE_SYNC);
+	tmp |= (GPMC_CONFIG1_FCLK_DIV(0));
+	gpmc_cs_write_reg(6, GPMC_CS_CONFIG1, tmp);
+	printk("GPMC_CONFIG1 reg: %x\n", tmp);
+#endif
+
+#if 1 
+	// CS signal timing parameter configuration
+	tmp = 0;
+	tmp |= GPMC_CONFIG2_CSONTIME(1);
+	tmp |= GPMC_CONFIG2_CSWROFFTIME(17);
+	tmp |= GPMC_CONFIG2_CSRDOFFTIME(17);
+	printk("GPMC_CONFIG2 reg: %x\n", tmp);
+	gpmc_cs_write_reg(6, GPMC_CS_CONFIG2, tmp);
+#endif 
+
+#if 0
+	// nADV signal timing parameter configuration
+        tmp = 0;
+        tmp |= GPMC_CONFIG3_ADVONTIME(1);
+        tmp |= GPMC_CONFIG3_ADVRDOFFTIME(2);
+        tmp |= GPMC_CONFIG3_ADVWROFFTIME(2);
+        printk("GPMC_CONFIG3 reg: %x\n", tmp);
+        gpmc_cs_write_reg(6, GPMC_CS_CONFIG3, tmp);
+#endif
+
+#if 0
+	// nWE and nOE signals timing parameter configuration
+	tmp = 0;
+	tmp |= GPMC_CONFIG4_WEONTIME(3);
+	tmp |= GPMC_CONFIG4_WEOFFTIME(4);
+	tmp |= GPMC_CONFIG4_OEONTIME(3);
+	tmp |= GPMC_CONFIG4_OEOFFTIME(4);
+	printk("GPMC_CONFIG4 reg: %x\n", tmp);
+	gpmc_cs_write_reg(6, GPMC_CS_CONFIG4, tmp);
+#endif
+
+#if 0
+	// RdAccess time and Cycle time timing paraters configuration
+	tmp = 0;
+	tmp |= GPMC_CONFIG5_PAGEBURSTACCESSTIME(1);
+	tmp |= GPMC_CONFIG5_RDACCESSTIME(4);
+	tmp |= GPMC_CONFIG5_WRCYCLETIME(5);
+	tmp |= GPMC_CONFIG5_RDCYCLETIME(5);
+	printk("GPMC_CONFIG5 reg: %x\n", tmp);
+	gpmc_cs_write_reg(6, GPMC_CS_CONFIG5, tmp);
+#endif
+
+#if 1
+	// WrAccessTime WrDataOnADmuxBus, Cycle2Cycle, and BusTurnAround params
+	tmp = 0;
+	tmp |= GPMC_CONFIG6_WRACCESSTIME(15);
+	tmp |= GPMC_CONFIG6_WRDATAONADMUXBUS(3);
+	tmp |= GPMC_CONFIG6_CYCLE2CYCLEDELAY(3);
+	tmp |= GPMC_CONFIG6_CYCLE2CYCLESAMECSEN;
+	tmp |= GPMC_CONFIG6_BUSTURNAROUND(0);
+	printk("GPMC_CONFIG6 reg: %x\n", tmp);
+	gpmc_cs_write_reg(6, GPMC_CS_CONFIG6, tmp);
+#endif
+
+}
+
 static void __init overo_init(void)
 {
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
@@ -637,8 +799,14 @@ static void __init overo_init(void)
 	usb_ehci_init(&ehci_pdata);
 	overo_spi_init();
 	overo_init_smsc911x();
+#if 0
 	overo_display_init();
-
+#endif
+	usrp1_e_init();
+#if 1
+	spi_register_board_info(overo_mcspi_board_info,
+		ARRAY_SIZE(overo_mcspi_board_info));
+#endif
 	/* Ensure SDRC pins are mux'd for self-refresh */
 	omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
 	omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
@@ -680,7 +848,7 @@ static void __init overo_init(void)
 					"OVERO_GPIO_USBH_CPEN\n");
 }
 
-MACHINE_START(OVERO, "Gumstsix Overo")
+MACHINE_START(OVERO, "Gumstix Overo")
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 4d073f1..8bd6dfb 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -452,6 +452,15 @@ config PCH_PHUB
 	  To compile this driver as a module, choose M here: the module will
 	  be called pch_phub.
 
+config USRP_E
+	tristate "USRP-E FPGA interface driver"
+	default n
+	help
+	 This driver is for the Ettus Research USRP Embedded Software
+	 Defined Radio platform.
+
+	 If you do not plan to run this kernel on that hardware choose N.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 98009cc..f43483e 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_TI_DAC7512)	+= ti_dac7512.o
 obj-$(CONFIG_C2PORT)		+= c2port/
 obj-$(CONFIG_IWMC3200TOP)      += iwmc3200top/
 obj-$(CONFIG_HMC6352)		+= hmc6352.o
+obj-$(CONFIG_USRP_E)		+= usrp_e.o
 obj-y				+= eeprom/
 obj-y				+= cb710/
 obj-$(CONFIG_VMWARE_BALLOON)	+= vmw_balloon.o
diff --git a/drivers/misc/usrp_e.c b/drivers/misc/usrp_e.c
new file mode 100644
index 0000000..aea1887
--- /dev/null
+++ b/drivers/misc/usrp_e.c
@@ -0,0 +1,1481 @@
+/*
+ * -*- linux-c -*-
+ * Interface for USRP Embedded from Ettus Research, LLC.
+ * This driver uses the GPMC interface on the OMAP3 to pass data
+ * to/from a Spartan 3 FPGA.
+ *
+ * Copyright (C) Ettus Research, LLC
+ *
+ * Written by Philip Balister <philip@opensdr.com>
+ *
+ * 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.
+ */
+
+#include "linux/fs.h"
+#include "linux/module.h"
+#include "linux/cdev.h"
+#include "linux/device.h"
+#include "linux/spinlock.h"
+#include "linux/errno.h"
+#include "linux/irq.h"
+#include "linux/interrupt.h"
+#include "linux/wait.h"
+#include "linux/sched.h"
+#include "linux/dma-mapping.h"
+#include "linux/semaphore.h"
+#include "linux/kthread.h"
+#include "linux/poll.h"
+#include "linux/slab.h"
+
+#include "plat/gpmc.h"
+#include "plat/gpio.h"
+#include "plat/dma.h"
+
+#include "asm/uaccess.h"
+#include "asm/io.h"
+#include "asm/atomic.h"
+
+#include "linux/usrp_e.h"
+
+#define TX_SPACE_AVAILABLE_GPIO	144
+#define RX_DATA_READY_GPIO	146
+
+static atomic_t use_count = ATOMIC_INIT(0);
+static atomic_t mapped = ATOMIC_INIT(0);
+static int shutting_down;
+
+struct spi_regs_wb;
+struct i2c_regs_wb;
+
+struct usrp_e_dev {
+	struct cdev cdev;
+	unsigned long mem_base;
+	unsigned long control_mem_base;
+	u32 *ioaddr;
+	u8 *ctl_addr;
+	struct spi_regs_wb *ctl_spi;
+	struct i2c_regs_wb *ctl_i2c;
+	spinlock_t fpga_lock;
+
+	atomic_t n_overruns;
+	atomic_t n_underruns;
+
+} *usrp_e_devp;
+
+struct dma_data {
+	int ch;
+	struct omap_dma_channel_params params;
+
+	unsigned long virt_from;
+	unsigned long virt_to;
+	unsigned long phys_from;
+	unsigned long phys_to;
+};
+
+#define MISC_REGS_BASE 0x0
+
+#define UE_REG_MISC_LED (MISC_REGS_BASE + 0)
+
+#define UE_REG_MISC_RX_LEN (MISC_REGS_BASE + 10)
+#define UE_REG_MISC_TX_LEN (MISC_REGS_BASE + 12)
+
+#define UE_REG_SLAVE(n) ((n)<<7)
+#define UE_REG_SR_ADDR(n) ((UE_REG_SLAVE(5)) + (4*(n)))
+
+#define UE_REG_CTRL_TX_CLEAR_UNDERRUN UE_REG_SR_ADDR(25)
+#define UE_SR_CLEAR_FIFO UE_REG_SR_ADDR(6)
+
+#define CTL_SPI_BASE 0x100
+
+struct spi_regs_wb {
+	u32 txrx0;
+	u32 txrx1;
+	u32 txrx2;
+	u32 txrx3;
+	u32 ctrl;
+	u32 div;
+	u32 ss;
+};
+
+/* Defines for spi ctrl register */
+#define UE_SPI_CTRL_ASS		(BIT(13))
+#define UE_SPI_CTRL_IE		(BIT(12))
+#define UE_SPI_CTRL_LSB		(BIT(11))
+/* defines for TXNEG and RXNEG in usrp_e.h so user can pass them to driver. */
+#define UE_SPI_CTRL_GO_BSY	(BIT(8))
+#define UE_SPI_CTRL_CHAR_LEN_MASK	0x7f
+
+
+#define CTL_I2C_BASE 0x180
+#if 1
+struct i2c_regs_wb {
+	u8 prescalar_lo;
+	u8 dummy;
+	u8 dummy1;
+	u8 dummy2;
+	u8 prescalar_hi;
+	u8 dummy3;
+	u8 dummy4;
+	u8 dummy5;
+	u8 ctrl;
+	u8 dummy6;
+	u8 dummy7;
+	u8 dummy8;
+	u8 data;
+	u8 dummy9;
+	u8 dummy10;
+	u8 dummy11;
+	u8 cmd_status;
+};
+#else
+struct i2c_regs_wb {
+	u16 prescalar_lo;
+	u16 dummy2;
+	u16 prescalar_hi;
+	u16 dummy3;
+	u16 ctrl;
+	u16 dummy6;
+	u16 data;
+	u16 dummy9;
+	u16 cmd_status;
+};
+#endif
+
+#define I2C_CTRL_EN	(BIT(7))		/* core enable */
+#define I2C_CTRL_IE	(BIT(6))		/* interrupt enable */
+
+/* STA, STO, RD, WR, and IACK bits are cleared automatically */
+
+#define I2C_CMD_START	(BIT(7))
+#define I2C_CMD_STOP	(BIT(6))
+#define I2C_CMD_RD	(BIT(5))
+#define I2C_CMD_WR	(BIT(4))
+#define I2C_CMD_NACK	(BIT(3))
+#define I2C_CMD_RSVD_2	(BIT(2))
+#define I2C_CMD_RSVD_1	(BIT(1))
+#define I2C_CMD_IACK	(BIT(0))
+
+#define I2C_ST_RXACK	(BIT(7))
+#define I2C_ST_BUSY	(BIT(6))
+#define I2C_ST_AL	(BIT(5))
+#define I2C_RSVD_4	(BIT(4))
+#define I2C_RSVD_3	(BIT(3))
+#define I2C_RSVD_2	(BIT(2))
+#define I2C_ST_TIP	(BIT(1))
+#define I2C_ST_IP	(BIT(0))
+
+#define MAX_WB_DIV 4
+#define MASTER_CLK_RATE 64000000
+#define PRESCALAR(wb_div) (((MASTER_CLK_RATE/(wb_div)) / (5 * 100000)) - 1)
+
+static __u16 prescalar_values[MAX_WB_DIV+1] = {
+	0xffff,
+	PRESCALAR(1),
+	PRESCALAR(2),
+	PRESCALAR(3),
+	PRESCALAR(4),
+};
+
+static struct dma_data *rx_dma;
+static struct dma_data *tx_dma;
+
+struct ring_buffer_entry {
+	unsigned long dma_addr;
+	__u8 *frame_addr;
+};
+
+struct ring_buffer {
+	struct ring_buffer_info (*rbi)[];
+	struct ring_buffer_entry (*rbe)[];
+	int num_pages;
+	unsigned long (*pages)[];
+};
+
+static struct ring_buffer tx_rb;
+static struct ring_buffer rx_rb;
+
+static struct usrp_e_ring_buffer_size_t rb_size;
+
+#define NUM_PAGES_RX_FLAGS 1
+#define NUM_RX_FRAMES 100
+#define NUM_PAGES_TX_FLAGS 1
+#define NUM_TX_FRAMES 100
+
+static int tx_rb_write;
+static int tx_rb_read;
+static int rx_rb_write;
+static int rx_rb_read;
+
+static int alloc_ring_buffer(struct ring_buffer *rb,
+			unsigned int num_bufs, enum dma_data_direction direction);
+static void delete_ring_buffer(struct ring_buffer *rb,
+			unsigned int num_bufs, enum dma_data_direction direction);
+static int alloc_ring_buffers(void);
+static void init_ring_buffer(struct ring_buffer *rb, int num_bufs,
+			int init_flags, enum dma_data_direction direction);
+
+static dev_t usrp_e_dev_number;
+static struct class *usrp_e_class;
+
+#define DEVICE_NAME	"usrp_e"
+
+static const struct file_operations usrp_e_fops;
+
+static irqreturn_t space_available_irqhandler(int irq, void *dev_id);
+static irqreturn_t data_ready_irqhandler(int irq, void *dev_id);
+static void usrp_rx_dma_irq(int ch, u16 stat, void *data);
+static void usrp_tx_dma_irq(int ch, u16 stat, void *data);
+
+static DECLARE_WAIT_QUEUE_HEAD(data_received_queue);
+static DECLARE_WAIT_QUEUE_HEAD(space_available_queue);
+static DECLARE_WAIT_QUEUE_HEAD(received_data_from_user);
+static DECLARE_WAIT_QUEUE_HEAD(tx_rb_space_available);
+
+static int tx_dma_waiting_for_data;
+static int waiting_for_space_in_tx_rb;
+
+#define DEBUG_RX 1
+
+static DECLARE_MUTEX(dma_lock);
+
+static void usrp_e_spi_init(void);
+static void usrp_e_i2c_init(void);
+
+static int init_dma_controller(void);
+static void release_dma_controller(void);
+static int get_frame_from_fpga_start(void);
+static int get_frame_from_fpga_finish(void);
+static int send_frame_to_fpga_start(void);
+static int send_frame_to_fpga_finish(void);
+
+static int rx_dma_active;
+static int tx_dma_active;
+
+static int  __init
+usrp_e_init(void)
+{
+	int ret;
+	struct usrp_e_dev *p;
+
+	printk(KERN_DEBUG "usrp_e entering driver initialization\n");
+
+	if (alloc_chrdev_region(&usrp_e_dev_number, 0, 1, DEVICE_NAME) < 0) {
+		printk(KERN_DEBUG "Can't register device\n");
+		return -1;
+	}
+
+	usrp_e_class = class_create(THIS_MODULE, DEVICE_NAME);
+
+	usrp_e_devp = kzalloc(sizeof(struct usrp_e_dev), GFP_KERNEL);
+	if (!usrp_e_devp) {
+		printk(KERN_ERR "Bad kmalloc\n");
+		return -ENOMEM;
+	}
+
+	p = usrp_e_devp; /* Shorten var name so I stay sane. */
+
+	printk(KERN_DEBUG "usrp_e data struct malloc'd.\n");
+
+	atomic_set(&p->n_underruns, 0);
+	atomic_set(&p->n_overruns, 0);
+
+	printk(KERN_DEBUG "usrp_e Data initialized..\n");
+
+	cdev_init(&p->cdev, &usrp_e_fops);
+	p->cdev.owner = THIS_MODULE;
+
+	ret = cdev_add(&p->cdev, MKDEV(MAJOR(usrp_e_dev_number), 0), 1);
+	if (ret) {
+		printk(KERN_ERR "Bad cdev\n");
+		return ret;
+	}
+
+	printk(KERN_DEBUG "usrp_e major number : %d\n",
+		MAJOR(usrp_e_dev_number));
+	device_create(usrp_e_class, NULL, MKDEV(MAJOR(usrp_e_dev_number), 0),
+		      NULL, "usrp_e%d", 0);
+
+	printk(KERN_DEBUG "Getting Chip Select\n");
+
+	if (gpmc_cs_request(4, SZ_2K, &p->mem_base) < 0) {
+		printk(KERN_ERR "Failed request for GPMC mem for usrp_e\n");
+		return -1;
+	}
+	printk(KERN_DEBUG "Got CS4, address = %lx\n", p->mem_base);
+
+	if (!request_mem_region(p->mem_base, SZ_2K, "usrp_e")) {
+		printk(KERN_ERR "Request_mem_region failed.\n");
+		gpmc_cs_free(4);
+		return -1;
+	}
+
+	p->ioaddr = ioremap(p->mem_base, SZ_2K);
+	spin_lock_init(&p->fpga_lock);
+
+	if (gpmc_cs_request(6, SZ_2K, &p->control_mem_base) < 0) {
+		printk(KERN_ERR "Failed request for GPMC control mem for usrp_e\n");
+		return -1;
+	}
+	printk(KERN_DEBUG "Got CS6, address = %lx\n", p->control_mem_base);
+
+	if (!request_mem_region(p->control_mem_base, SZ_2K, "usrp_e_c")) {
+		printk(KERN_ERR "Request_mem_region failed.\n");
+		gpmc_cs_free(6);
+		return -1;
+	}
+
+	p->ctl_addr = ioremap_nocache(p->control_mem_base, SZ_2K);
+
+	/* Initialize wishbone SPI and I2C interfaces */
+
+	usrp_e_spi_init();
+	usrp_e_i2c_init();
+
+	/* Configure GPIO's */
+
+	if (!(((gpio_request(TX_SPACE_AVAILABLE_GPIO,
+				    "TX_SPACE_AVAILABLE_GPIO") == 0) &&
+		(gpio_direction_input(TX_SPACE_AVAILABLE_GPIO) == 0)))) {
+		printk(KERN_ERR "Could not claim GPIO for TX_SPACE_AVAILABLE_GPIO\n");
+		return -1;
+	}
+
+	if (!(((gpio_request(RX_DATA_READY_GPIO, "RX_DATA_READY_GPIO") == 0) &&
+		(gpio_direction_input(RX_DATA_READY_GPIO) == 0)))) {
+		printk(KERN_ERR "Could not claim GPIO for RX_DATA_READY_GPIO\n");
+		return -1;
+	}
+
+	/* Debug gpios */
+	if (!(((gpio_request(14, "Debug0") == 0) &&
+				(gpio_direction_output(14, 0) == 0)))) {
+		printk(KERN_ERR "Could not claim GPIO for Debug0\n");
+		return -1;
+	}
+
+	if (!(((gpio_request(21, "Debug1") == 0) &&
+				(gpio_direction_output(21, 0) == 0)))) {
+		printk(KERN_ERR "Could not claim GPIO for Debug1\n");
+		return -1;
+	}
+
+	if (!(((gpio_request(22, "Debug2") == 0) &&
+				(gpio_direction_output(22, 0) == 0)))) {
+		printk(KERN_ERR "Could not claim GPIO for Debug2\n");
+		return -1;
+	}
+
+	if (!(((gpio_request(23, "Debug3") == 0) &&
+				(gpio_direction_output(23, 0) == 0)))) {
+		printk(KERN_ERR "Could not claim GPIO for Debug3\n");
+		return -1;
+	}
+
+
+	rb_size.num_pages_rx_flags = NUM_PAGES_RX_FLAGS;
+	rb_size.num_rx_frames = NUM_RX_FRAMES;
+	rb_size.num_pages_tx_flags = NUM_PAGES_TX_FLAGS;
+	rb_size.num_tx_frames = NUM_TX_FRAMES;
+
+	ret = alloc_ring_buffers();
+	if (ret < 0)
+		return ret;
+
+	/* Initialize various DMA related flags */
+	rx_dma_active = 0;
+	tx_dma_active = 0;
+	shutting_down = 0;
+
+	printk(KERN_DEBUG "usrp_e Driver Initialized.\n");
+
+	return 0;
+}
+
+static void __exit
+usrp_e_cleanup(void)
+{
+	struct usrp_e_dev *p = usrp_e_devp;
+
+	unregister_chrdev_region(usrp_e_dev_number, 1);
+
+	release_mem_region(p->mem_base, SZ_2K);
+	release_mem_region(p->control_mem_base, SZ_2K);
+
+	device_destroy(usrp_e_class, MKDEV(MAJOR(usrp_e_dev_number), 0));
+	cdev_del(&p->cdev);
+
+	class_destroy(usrp_e_class);
+
+	iounmap(p->ioaddr);
+	iounmap(p->ctl_addr);
+
+	gpmc_cs_free(4);
+	gpmc_cs_free(6);
+
+	printk(KERN_DEBUG "Freeing gpios\n");
+
+	gpio_free(TX_SPACE_AVAILABLE_GPIO);
+	gpio_free(RX_DATA_READY_GPIO);
+
+	/* debug */
+	gpio_free(14);
+	gpio_free(21);
+	gpio_free(22);
+	gpio_free(23);
+
+	delete_ring_buffer(&tx_rb, rb_size.num_tx_frames, DMA_TO_DEVICE);
+	delete_ring_buffer(&rx_rb, rb_size.num_rx_frames, DMA_FROM_DEVICE);
+
+	kfree(p);
+
+	printk(KERN_DEBUG "Leaving cleanup\n");
+}
+
+static int
+usrp_e_open(struct inode *inode, struct file *file)
+{
+	struct usrp_e_dev *p = usrp_e_devp;
+	int ret;
+
+	printk(KERN_DEBUG "usrp_e open called, use_count = %d\n",
+		atomic_read(&use_count));
+	if (atomic_add_return(1, &use_count) != 1) {
+		printk(KERN_ERR "use_count = %d\n", atomic_read(&use_count));
+		atomic_dec(&use_count);
+		return -EBUSY;
+	}
+
+	/* Clear rx and tx fifos in the fpga */
+	writel(1, p->ctl_addr + UE_SR_CLEAR_FIFO);
+	writel(2, p->ctl_addr + UE_SR_CLEAR_FIFO);
+
+#if 0
+	usrp_e_devp = container_of(inode->i_cdev, struct usrp_e_dev, cdev);
+
+	file->private_data = usrp_e_devp;
+#endif
+
+	ret = init_dma_controller();
+	if (ret < 0)
+		return ret;
+
+	tx_rb_write = 0;
+	tx_rb_read = 0;
+
+	rx_rb_write = 0;
+	rx_rb_read = 0;
+
+	tx_dma_active = 0;
+	rx_dma_active = 0;
+	shutting_down = 0;
+
+	init_ring_buffer(&rx_rb, rb_size.num_rx_frames, RB_KERNEL, DMA_FROM_DEVICE);
+	init_ring_buffer(&tx_rb, rb_size.num_tx_frames, RB_KERNEL, DMA_TO_DEVICE);
+
+	/* Configure interrupts for GPIO pins */
+
+	ret = request_irq(gpio_to_irq(TX_SPACE_AVAILABLE_GPIO),
+			space_available_irqhandler,
+		IRQF_TRIGGER_RISING, "usrp_e_space_available", NULL);
+
+	ret = request_irq(gpio_to_irq(RX_DATA_READY_GPIO),
+			data_ready_irqhandler,
+			IRQF_TRIGGER_RISING, "usrp_e_data_ready", NULL);
+
+	printk(KERN_DEBUG "usrp: leaving open\n");
+	return 0;
+}
+
+static int
+usrp_e_release(struct inode *inode, struct file *file)
+{
+	struct usrp_e_dev *usrp_e_devp = file->private_data;
+
+	printk(KERN_DEBUG "usrp_e release called\n");
+
+	if (atomic_read(&use_count) != 1) {
+		printk(KERN_ERR "Attempt to close usrp_e driver that is not open");
+		return -ENOENT;
+	}
+
+	printk(KERN_DEBUG "Waiting for DMA to become inactive\n");
+	shutting_down = 0;
+	while (tx_dma_active || rx_dma_active)
+		cpu_relax();
+
+	/* Freeing gpio irq's */
+	printk(KERN_DEBUG "Freeing gpio irq's\n");
+
+	free_irq(gpio_to_irq(TX_SPACE_AVAILABLE_GPIO), NULL);
+	free_irq(gpio_to_irq(RX_DATA_READY_GPIO), NULL);
+
+	printk(KERN_DEBUG "Freeing DMA channels\n");
+
+	release_dma_controller();
+
+	usrp_e_devp = 0;
+
+	atomic_dec(&use_count);
+
+	return 0;
+}
+
+static ssize_t
+usrp_e_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	size_t ret;
+	int rx_pkt_len;
+
+	if (count > SZ_2K)
+		return -EMSGSIZE;
+
+	if (!((*rx_rb.rbi)[rx_rb_read].flags & RB_USER)) {
+		if (wait_event_interruptible(data_received_queue,
+			      (((*rx_rb.rbi)[rx_rb_read].flags & RB_USER))))
+			return -EINTR;
+	}
+
+	rx_pkt_len = (*rx_rb.rbi)[rx_rb_read].len;
+	ret = copy_to_user(buf, (*rx_rb.rbe)[rx_rb_read].frame_addr, rx_pkt_len);
+
+	(*rx_rb.rbi)[rx_rb_read].flags = RB_KERNEL;
+
+	rx_rb_read++;
+	if (rx_rb_read == rb_size.num_rx_frames)
+		rx_rb_read = 0;
+
+	get_frame_from_fpga_start();
+
+	return ((ret == 0) ?  rx_pkt_len : -ret);
+}
+
+static ssize_t
+usrp_e_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	size_t ret;
+
+#if 0
+//	printk("In write.\n");
+
+	/* Trigger a DMA transfer. Used to start transmit after writing */
+	/* data into the transmit ring buffer from user space */
+	if (count < 0) {
+		send_frame_to_fpga_start();
+		return 0;
+	}
+
+	if (count > SZ_2K)
+		return -EMSGSIZE;
+
+//	printk("Write flags: %d\n", (*tx_rb.rbe)[tx_rb_write].flags);
+	if (!((*tx_rb.rbi)[tx_rb_write].flags & RB_KERNEL)) {
+		waiting_for_space_in_tx_rb = 1;
+//		printk("Sleeping\n");
+		if (wait_event_interruptible(tx_rb_space_available,
+			       ((*tx_rb.rbi)[tx_rb_write].flags & RB_KERNEL)))
+			return -EINTR;
+//		printk("Waking\n");
+	}
+
+	ret = copy_from_user((*tx_rb.rbe)[tx_rb_write].frame_addr, buf, count);
+	if (ret)
+		return -ret;
+
+	(*tx_rb.rbi)[tx_rb_write].len = count;
+	(*tx_rb.rbi)[tx_rb_write].flags = RB_USER;
+
+	tx_rb_write++;
+	if (tx_rb_write == rb_size.num_tx_frames)
+		tx_rb_write = 0;
+
+//	printk("Calling send_to_fpga_start from write\n");
+#endif
+	send_frame_to_fpga_start();
+
+	return count;
+}
+
+static loff_t
+usrp_e_llseek(struct file *file, loff_t offest, int orig)
+{
+	printk(KERN_DEBUG "usrp_e llseek called\n");
+
+	return 0;
+}
+
+static int usrp_e_ctl16(unsigned long arg, int direction)
+{
+	struct usrp_e_ctl16 __user *argp = (struct usrp_e_ctl16 __user *) arg;
+	int i;
+	struct usrp_e_ctl16 ctl;
+
+	if (copy_from_user(&ctl, argp, sizeof(struct usrp_e_ctl16)))
+		return -EFAULT;
+
+	if (ctl.count > 10)
+		return -EINVAL;
+
+	if (direction == 0) {
+		for (i = 0; i < ctl.count; i++)
+			writew(ctl.buf[i], &usrp_e_devp->ctl_addr \
+				[i + ctl.offset]);
+	} else if (direction == 1) {
+		for (i = 0; i < ctl.count; i++)
+			ctl.buf[i] = readw(&usrp_e_devp->ctl_addr \
+				[i + ctl.offset]);
+
+		if (copy_to_user(argp, &ctl, sizeof(struct usrp_e_ctl16)))
+			return -EFAULT;
+	} else
+		return -EFAULT;
+
+	return 0;
+}
+
+static int usrp_e_ctl32(unsigned long arg, int direction)
+{
+	struct usrp_e_ctl32 __user *argp = (struct usrp_e_ctl32 __user *) arg;
+	int i;
+	struct usrp_e_ctl32 ctl;
+
+	if (copy_from_user(&ctl, argp, sizeof(struct usrp_e_ctl32)))
+		return -EFAULT;
+
+	if (ctl.count > 20)
+		return -EINVAL;
+
+	if (direction == 0) {
+		for (i = 0; i < ctl.count; i++)
+			writel(ctl.buf[i], &usrp_e_devp->ctl_addr \
+				[i + ctl.offset]);
+	} else if (direction == 1) {
+		for (i = 0; i < ctl.count; i++)
+			ctl.buf[i] = readl(&usrp_e_devp->ctl_addr \
+				[i + ctl.offset]);
+
+		if (copy_to_user(argp, &ctl, sizeof(struct usrp_e_ctl16)))
+			return -EFAULT;
+
+	} else
+		return -EFAULT;
+
+	return 0;
+}
+
+static int usrp_e_get_rb_info(unsigned long arg)
+{
+	struct usrp_e_ring_buffer_size_t __user *argp = (struct usrp_e_ring_buffer_size_t __user *) arg;
+	int i;
+
+	if (copy_to_user(argp, &rb_size, sizeof(rb_size)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static void usrp_e_spi_init()
+{
+	struct usrp_e_dev *p = usrp_e_devp;
+
+	p->ctl_spi = (struct spi_regs_wb *)(p->ctl_addr + CTL_SPI_BASE);
+	p->ctl_spi->div = 64; /* 1 = Div by 4 (12.5 MHz) */
+}
+
+static int usrp_e_spi_wait(void)
+{
+	struct usrp_e_dev *p = usrp_e_devp;
+
+	while (p->ctl_spi->ctrl & UE_SPI_CTRL_GO_BSY) {
+		if (signal_pending(current)) {
+			printk(KERN_DEBUG "Signal received.\n");
+			set_current_state(TASK_RUNNING);
+			return -EINTR;
+		}
+		schedule();
+	}
+
+	return 0;
+}
+
+static int usrp_e_spi(unsigned long __user arg)
+{
+	struct usrp_e_dev *p = usrp_e_devp;
+	struct usrp_e_spi __user *argp = (struct usrp_e_spi __user *) arg;
+	struct usrp_e_spi spi_cmd;
+	int ctrl, ret;
+
+	if (copy_from_user(&spi_cmd, argp, sizeof(struct usrp_e_spi)))
+		return -EFAULT;
+
+	spi_cmd.flags &= (UE_SPI_CTRL_TXNEG | UE_SPI_CTRL_RXNEG);
+	ctrl = UE_SPI_CTRL_ASS | (UE_SPI_CTRL_CHAR_LEN_MASK & spi_cmd.length) \
+		| spi_cmd.flags;
+
+	ret = usrp_e_spi_wait();
+	if (ret < 0)
+		return ret;
+
+	p->ctl_spi->ss = spi_cmd.slave & 0xff;
+
+	p->ctl_spi->txrx0 = spi_cmd.data;
+
+	p->ctl_spi->ctrl = ctrl;
+	p->ctl_spi->ctrl = ctrl | UE_SPI_CTRL_GO_BSY;
+
+	if (spi_cmd.readback) {
+		usrp_e_spi_wait();
+		if (copy_to_user(&argp->data, &p->ctl_spi->txrx0,
+					sizeof(__u32)))
+			return -EFAULT;
+		else
+			return 0;
+	} else
+		return 0;
+
+}
+
+static void usrp_e_i2c_init()
+{
+	struct usrp_e_dev *p = usrp_e_devp;
+	int wb_div;
+
+	p->ctl_i2c = (struct i2c_regs_wb *)(p->ctl_addr + CTL_I2C_BASE);
+
+	writeb(0, &p->ctl_i2c->ctrl);	/* disable core */
+
+	/* Assume wb_div is 4, deal with this later */
+	wb_div = 4;
+	if (wb_div > MAX_WB_DIV)
+		wb_div = MAX_WB_DIV;
+
+	writeb((prescalar_values[wb_div] & 0xff), &p->ctl_i2c->prescalar_lo);
+	writeb(((prescalar_values[wb_div] >> 8) & 0xff),
+		&p->ctl_i2c->prescalar_hi);
+	writeb(I2C_CTRL_EN, &p->ctl_i2c->ctrl);	/* enable core */
+}
+
+static int usrp_e_i2c_wait(__u32 mask, int chk_ack)
+{
+	struct usrp_e_dev *p = usrp_e_devp;
+
+	while (readb(&p->ctl_i2c->cmd_status) & mask) {
+		if (signal_pending(current)) {
+			printk(KERN_DEBUG "Signal received.\n");
+			set_current_state(TASK_RUNNING);
+			return -EINTR;
+		}
+		schedule();
+	}
+
+	if (chk_ack) {
+		if ((readb(&p->ctl_i2c->cmd_status) & I2C_ST_RXACK) == 0)
+			return 1;
+		else
+			return 0;
+	}
+
+	return 0;
+}
+
+static int usrp_e_i2c(unsigned long arg, int direction)
+{
+	struct usrp_e_dev *p = usrp_e_devp;
+	struct usrp_e_i2c __user *argp = (struct usrp_e_i2c __user *) arg;
+	struct usrp_e_i2c tmp;
+	struct usrp_e_i2c *i2c_msg;
+	int ret, len, i;
+
+	if (copy_from_user(&tmp, argp, sizeof(struct usrp_e_i2c)))
+		return -EFAULT;
+
+	i2c_msg = kmalloc(sizeof(struct usrp_e_i2c) + tmp.len, GFP_KERNEL);
+	if (!i2c_msg)
+		return -ENOMEM;
+
+	if (copy_from_user(i2c_msg, argp,
+				(sizeof(struct usrp_e_i2c) + tmp.len)))
+		return -EFAULT;
+
+	if (direction) {
+		/* read */
+		if (i2c_msg->len == 0)
+			return 1;
+
+		usrp_e_i2c_wait(I2C_ST_BUSY, 0);
+
+		writeb(((i2c_msg->addr << 1) | 1), &p->ctl_i2c->data);
+		writeb((I2C_CMD_WR | I2C_CMD_START), &p->ctl_i2c->cmd_status);
+		ret = usrp_e_i2c_wait(I2C_ST_TIP, 1);
+		if (ret < 0) {
+			return ret;
+		} else if (ret == 0) {
+			writeb(I2C_CMD_STOP, &p->ctl_i2c->cmd_status);
+			return 2;
+		}
+
+		for (len = i2c_msg->len, i = 0; len > 0; i++, len--) {
+			writeb((I2C_CMD_RD | ((len == 1) ?
+				(I2C_CMD_NACK | I2C_CMD_STOP) : 0)),
+				&p->ctl_i2c->cmd_status);
+			usrp_e_i2c_wait(I2C_ST_TIP, 0);
+			i2c_msg->data[i] = readb(&p->ctl_i2c->data);
+		}
+		if (copy_to_user(argp, i2c_msg, (sizeof(struct usrp_e_i2c) +
+				tmp.len)))
+			return -EFAULT;
+	} else {
+		/* write */
+		usrp_e_i2c_wait(I2C_ST_BUSY, 0);
+		writeb(((i2c_msg->addr << 1) | 0), &p->ctl_i2c->data);
+		writeb((I2C_CMD_WR | I2C_CMD_START |
+				(i2c_msg->len == 0 ? I2C_CMD_STOP : 0)),
+			        &p->ctl_i2c->cmd_status);
+		ret = usrp_e_i2c_wait(I2C_ST_TIP, 1);
+		if (ret < 0) {
+			return ret;
+		} else if (ret == 0) {
+			writeb(I2C_CMD_STOP, &p->ctl_i2c->cmd_status);
+			return 2;
+		}
+		for (len = i2c_msg->len, i = 0; len > 0; i++, len--) {
+			writeb(i2c_msg->data[i], &p->ctl_i2c->data);
+			writeb((I2C_CMD_WR | (len == 1 ? I2C_CMD_STOP : 0)),
+				&p->ctl_i2c->cmd_status);
+			ret = usrp_e_i2c_wait(I2C_ST_TIP, 1);
+			if (ret < 0) {
+				return ret;
+			} else if (ret == 0) {
+				writeb(I2C_CMD_STOP, &p->ctl_i2c->cmd_status);
+				return 2;
+			}
+		}
+
+	}
+
+
+	return 1;
+}
+
+static int usrp_e_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+
+	switch (cmd) {
+	case USRP_E_WRITE_CTL16:
+		return usrp_e_ctl16(arg, 0);
+
+	case USRP_E_READ_CTL16:
+		return usrp_e_ctl16(arg, 1);
+
+	case USRP_E_WRITE_CTL32:
+		return usrp_e_ctl32(arg, 0);
+
+	case USRP_E_READ_CTL32:
+		return usrp_e_ctl32(arg, 1);
+
+	case USRP_E_SPI:
+		return usrp_e_spi(arg);
+
+	case USRP_E_I2C_WRITE:
+		return usrp_e_i2c(arg, 0);
+
+	case USRP_E_I2C_READ:
+		return usrp_e_i2c(arg, 1);
+
+	case USRP_E_GET_RB_INFO:
+		return usrp_e_get_rb_info(arg);
+
+	default:
+		return -ENOTTY;
+	}
+
+	return 0;
+}
+
+static unsigned int usrp_e_poll(struct file *filp, poll_table *wait)
+{
+	unsigned int mask = 0;
+
+	poll_wait(filp, &data_received_queue, wait);
+	poll_wait(filp, &tx_rb_space_available, wait);
+
+	// Make sure write is active before sleeping
+	send_frame_to_fpga_start();
+
+	/* Make sure to read in case the rx ring buffer is full */
+	get_frame_from_fpga_start();
+
+	// This likely needs some locking. The pointer is incremented
+	// before the flag state is updated.
+
+	if (rx_rb_write == 0) {
+		if ((*rx_rb.rbi)[rb_size.num_rx_frames - 1].flags & RB_USER)
+			mask |= POLLIN | POLLRDNORM;
+	} else {
+		if ((*rx_rb.rbi)[rx_rb_write - 1].flags & RB_USER)
+			mask |= POLLIN | POLLRDNORM;
+	}
+
+	if (tx_rb_read == 0) {
+		if ((*tx_rb.rbi)[rb_size.num_tx_frames - 1].flags & RB_KERNEL)
+			mask |= POLLOUT | POLLWRNORM;
+	} else {
+		if ((*tx_rb.rbi)[tx_rb_read - 1].flags & RB_KERNEL)
+			mask |= POLLOUT | POLLWRNORM;
+	}
+
+	return mask;
+
+}
+
+/* The mmap code is based on code in af_packet.c */
+
+static void usrp_e_mm_open(struct vm_area_struct *vma)
+{
+
+	atomic_inc(&mapped);
+}
+
+static void usrp_e_mm_close(struct vm_area_struct *vma)
+{
+
+	atomic_dec(&mapped);
+}
+
+static const struct vm_operations_struct usrp_e_mmap_ops = {
+	.open   = usrp_e_mm_open,
+	.close  = usrp_e_mm_close,
+};
+
+static int usrp_e_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	unsigned long size, expected_size;
+	unsigned int i;
+	unsigned long start;
+	int err;
+	struct page *page;
+
+	printk("In mmap\n");
+
+	if (vma->vm_pgoff)
+		return -EINVAL;
+
+	/* Verify the user will map the entire tx and rx ring buffer space */
+	expected_size = (rb_size.num_rx_frames + rb_size.num_tx_frames) * (PAGE_SIZE >> 1)
+		+ (rb_size.num_pages_rx_flags + rb_size.num_pages_tx_flags) * PAGE_SIZE;
+
+	size = vma->vm_end - vma->vm_start;
+	printk(KERN_DEBUG "Size = %d, expected sixe = %d\n", size, expected_size);
+
+	if (size != expected_size)
+		return -EINVAL;
+
+	start = vma->vm_start;
+
+	page = virt_to_page(rx_rb.rbi);
+	err = vm_insert_page(vma, start, page);
+	if (err)
+		return -EINVAL;
+	
+	start += PAGE_SIZE;
+	
+	for (i = 0; i < rx_rb.num_pages; ++i) {
+		struct page *page = virt_to_page((*rx_rb.pages)[i]);
+		err = vm_insert_page(vma, start, page);
+		if (err)
+			return -EINVAL;
+
+		start += PAGE_SIZE;
+	}
+
+	page = virt_to_page(tx_rb.rbi);
+	err = vm_insert_page(vma, start, page);
+	if (err)
+		return -EINVAL;
+	
+	start += PAGE_SIZE;
+	
+	for (i = 0; i < tx_rb.num_pages; ++i) {
+		struct page *page = virt_to_page((*tx_rb.pages)[i]);
+
+		err = vm_insert_page(vma, start, page);
+		if (err)
+			return err;
+
+		start += PAGE_SIZE;
+	}
+
+	vma->vm_ops = &usrp_e_mmap_ops;
+
+	return 0;
+}
+
+static const struct file_operations usrp_e_fops = {
+	.owner		=	THIS_MODULE,
+	.open		=	usrp_e_open,
+	.release 	=	usrp_e_release,
+	.read		=	usrp_e_read,
+	.write		=	usrp_e_write,
+	.llseek		=	usrp_e_llseek,
+	.ioctl		=	usrp_e_ioctl,
+	.poll           =       usrp_e_poll,
+	.mmap           =       usrp_e_mmap,
+};
+
+MODULE_VERSION("0.1");
+MODULE_ALIAS(DEVICE_NAME);
+MODULE_DESCRIPTION(DEVICE_NAME);
+MODULE_AUTHOR("Philip Balister <philip@opensdr.com>");
+MODULE_LICENSE("GPL v2");
+
+module_init(usrp_e_init);
+module_exit(usrp_e_cleanup);
+
+static irqreturn_t space_available_irqhandler(int irq, void *dev_id)
+{
+	int serviced = IRQ_NONE;
+
+#ifdef DEBUG_TX
+	gpio_set_value(22, 1);
+#endif
+
+//	printk("Calling send_to_fpga_start from space_available irq\n");
+	send_frame_to_fpga_start();
+
+	serviced = IRQ_HANDLED;
+
+#ifdef DEBUG_TX
+	gpio_set_value(22, 0);
+#endif
+
+	return serviced;
+}
+
+static void usrp_rx_dma_irq(int ch, u16 stat, void *data)
+{
+
+#ifdef DEBUG_RX
+	gpio_set_value(23, 1);
+#endif
+
+	rx_dma_active = 0;
+
+	get_frame_from_fpga_finish();
+
+#ifdef DEBUG_RX
+	gpio_set_value(23, 0);
+#endif
+}
+
+static void usrp_tx_dma_irq(int ch, u16 stat, void *data)
+{
+
+#ifdef DEBUG_TX
+	gpio_set_value(23, 1);
+#endif
+	tx_dma_active = 0;
+
+	send_frame_to_fpga_finish();
+
+#ifdef DEBUG_TX
+	gpio_set_value(23, 0);
+#endif
+
+/* Save
+	gpio_set_value(21, 1);
+	gpio_set_value(21, 0);
+*/
+
+}
+
+static irqreturn_t data_ready_irqhandler(int irq, void *dev_id)
+{
+	int serviced = IRQ_NONE;
+
+#ifdef DEBUG_RX
+	gpio_set_value(22, 1);
+#endif
+
+	get_frame_from_fpga_start();
+
+	serviced = IRQ_HANDLED;
+
+#ifdef DEBUG_RX
+	gpio_set_value(22, 0);
+#endif
+	return serviced;
+}
+
+static int init_dma_controller()
+{
+	struct usrp_e_dev *p = usrp_e_devp;
+
+	rx_dma = kzalloc(sizeof(struct dma_data), GFP_KERNEL);
+	if (!rx_dma) {
+		printk(KERN_ERR "Failed to allocate memory for rx_dma struct.");
+		return -ENOMEM;
+	}
+
+	if (omap_request_dma(OMAP_DMA_NO_DEVICE, "usrp-e-rx",
+			usrp_rx_dma_irq, (void *) rx_dma, &rx_dma->ch)) {
+		printk(KERN_ERR "Could not get rx DMA channel for usrp_e\n");
+		return -ENOMEM;
+	}
+	printk(KERN_DEBUG "rx_dma->ch %d\n", rx_dma->ch);
+
+	rx_dma->phys_from = p->mem_base;
+
+	memset(&rx_dma->params, 0, sizeof(rx_dma->params));
+	rx_dma->params.data_type	= OMAP_DMA_DATA_TYPE_S16;
+
+	rx_dma->params.src_amode	= OMAP_DMA_AMODE_CONSTANT;
+	rx_dma->params.dst_amode	= OMAP_DMA_AMODE_POST_INC;
+
+	rx_dma->params.src_start	= p->mem_base;
+	rx_dma->params.dst_start	= rx_dma->phys_to;
+
+	rx_dma->params.src_ei		= 1;
+	rx_dma->params.src_fi		= 1;
+	rx_dma->params.dst_ei		= 1;
+	rx_dma->params.dst_fi		= 1;
+
+	rx_dma->params.elem_count	= 1024;
+	rx_dma->params.frame_count	= 1;
+
+	rx_dma->params.read_prio        = DMA_CH_PRIO_HIGH;
+	rx_dma->params.write_prio       = DMA_CH_PRIO_LOW;
+
+	omap_set_dma_params(rx_dma->ch, &rx_dma->params);
+
+// Play with these with a real application
+//G	omap_set_dma_src_burst_mode(rx_dma->ch, OMAP_DMA_DATA_BURST_16);
+//	omap_set_dma_dest_burst_mode(rx_dma->ch, OMAP_DMA_DATA_BURST_16);
+
+#if 0 // Need to find implentations of the endian calls
+	omap_set_dma_src_endian_type(rx_dma->ch, OMAP_DMA_BIG_ENDIAN);
+	omap_set_dma_dst_endian_type(rx_dma->ch, OMAP_DMA_LITTLE_ENDIAN);
+#endif
+
+	tx_dma = kzalloc(sizeof(struct dma_data), GFP_KERNEL);
+	if (!tx_dma) {
+		printk(KERN_ERR "Failed to allocate memory for tx_dma struct.");
+		return -ENOMEM;
+	}
+
+	if (omap_request_dma(OMAP_DMA_NO_DEVICE, "usrp-e-tx",
+			usrp_tx_dma_irq, (void *) tx_dma, &tx_dma->ch)) {
+		printk(KERN_ERR "Could not get tx DMA channel for usrp_e\n");
+		return -ENOMEM;
+	}
+
+	printk(KERN_DEBUG "tx_dma->ch %d\n", tx_dma->ch);
+
+	tx_dma->phys_from = p->mem_base;
+
+	memset(&tx_dma->params, 0, sizeof(tx_dma->params));
+	tx_dma->params.data_type	= OMAP_DMA_DATA_TYPE_S16;
+
+	tx_dma->params.src_amode	= OMAP_DMA_AMODE_POST_INC;
+	tx_dma->params.dst_amode	= OMAP_DMA_AMODE_CONSTANT;
+
+	tx_dma->params.src_start	= tx_dma->phys_from;
+	tx_dma->params.dst_start	= p->mem_base;
+
+	tx_dma->params.src_ei		= 1;
+	tx_dma->params.src_fi		= 1;
+	tx_dma->params.dst_ei		= 1;
+	tx_dma->params.dst_fi		= 1;
+
+	tx_dma->params.elem_count	= 1024;
+	tx_dma->params.frame_count	= 1;
+
+	tx_dma->params.read_prio        = DMA_CH_PRIO_LOW;
+	tx_dma->params.write_prio       = DMA_CH_PRIO_HIGH;
+
+	omap_set_dma_params(tx_dma->ch, &tx_dma->params);
+
+// Play with these with a real application
+//G	omap_set_dma_src_burst_mode(tx_dma->ch, OMAP_DMA_DATA_BURST_16);
+//	omap_set_dma_dest_burst_mode(tx_dma->ch, OMAP_DMA_DATA_BURST_16);
+
+	return 0;
+}
+
+static void release_dma_controller()
+{
+
+	omap_free_dma(rx_dma->ch);
+	omap_free_dma(tx_dma->ch);
+
+	kfree(rx_dma);
+	kfree(tx_dma);
+}
+
+static int get_frame_from_fpga_start()
+{
+	struct usrp_e_dev *p = usrp_e_devp;
+	struct ring_buffer_info *rbi = &(*rx_rb.rbi)[rx_rb_write];
+	struct ring_buffer_entry *rbe = &(*rx_rb.rbe)[rx_rb_write];
+	u16 elements_to_read;
+
+	/* Check for space available in the ring buffer */
+	/* If no space, drop data. A read call will restart dma transfers. */
+	if (((*rx_rb.rbi)[rx_rb_write].flags & RB_KERNEL) && (gpio_get_value(RX_DATA_READY_GPIO)) && !rx_dma_active  && !shutting_down) {
+
+		rx_dma_active = 1;
+#ifdef DEBUG_RX
+		gpio_set_value(14, 1);
+#endif
+
+		elements_to_read = readw(p->ctl_addr + UE_REG_MISC_RX_LEN);
+		
+		rbi->flags = RB_DMA_ACTIVE;
+		
+		rbi->len = elements_to_read << 1;
+		
+		omap_set_dma_dest_addr_size(rx_dma->ch, rbe->dma_addr,
+					elements_to_read);
+		
+		dma_sync_single_for_device(NULL, rbe->dma_addr, SZ_2K, DMA_FROM_DEVICE);
+		
+		omap_start_dma(rx_dma->ch);
+	}
+
+	return 0;
+}
+
+
+static int get_frame_from_fpga_finish()
+{
+	dma_sync_single_for_cpu(NULL, (*rx_rb.rbe)[rx_rb_write].dma_addr, SZ_2K, DMA_FROM_DEVICE);
+
+	(*rx_rb.rbi)[rx_rb_write].flags = RB_USER;
+	rx_rb_write++;
+	if (rx_rb_write == rb_size.num_rx_frames)
+		rx_rb_write = 0;
+
+	wake_up_interruptible(&data_received_queue);
+
+	rx_dma_active = 0;
+
+	get_frame_from_fpga_start();
+
+#ifdef DEBUG_RX
+	gpio_set_value(14, 0);
+#endif
+
+	return 0;
+}
+
+static int send_frame_to_fpga_start()
+{
+	struct usrp_e_dev *p = usrp_e_devp;
+	struct ring_buffer_info *rbi = &(*tx_rb.rbi)[tx_rb_read];
+	struct ring_buffer_entry *rbe = &(*tx_rb.rbe)[tx_rb_read];
+	u16 elements_to_write;
+
+//	printk("In send_frame_to_fpga_start.\n");
+
+	/* Check if there is data to write to the FPGA, if so send it */
+	/* Otherwise, do nothing. Process is restarted by calls to write */
+	if (((*tx_rb.rbi)[tx_rb_read].flags & RB_USER) && !tx_dma_active && (gpio_get_value(TX_SPACE_AVAILABLE_GPIO)) && !shutting_down) {
+//		printk("In send_frame_to_fpga_start, past if.\n");
+		tx_dma_active = 1;
+#ifdef DEBUG_TX
+		gpio_set_value(14, 1);
+#endif
+
+		elements_to_write = ((rbi->len) >> 1);
+		
+		writew(elements_to_write, p->ctl_addr + UE_REG_MISC_TX_LEN);
+		
+		rbi->flags = RB_DMA_ACTIVE;
+		
+		omap_set_dma_src_addr_size(tx_dma->ch, rbe->dma_addr,
+					elements_to_write);
+		
+		dma_sync_single_for_device(NULL, rbe->dma_addr, SZ_2K, DMA_TO_DEVICE);
+		
+		omap_start_dma(tx_dma->ch);
+	}
+
+	return 0;
+}
+
+static int send_frame_to_fpga_finish()
+{
+
+	dma_sync_single_for_cpu(NULL, (*tx_rb.rbe)[tx_rb_read].dma_addr, SZ_2K, DMA_TO_DEVICE);
+	
+	(*tx_rb.rbi)[tx_rb_read].flags = RB_KERNEL;
+	
+	tx_rb_read++;
+	if (tx_rb_read == rb_size.num_tx_frames)
+		tx_rb_read = 0;
+	
+	wake_up_interruptible(&tx_rb_space_available);
+
+	tx_dma_active = 0;
+
+	send_frame_to_fpga_start();
+
+#ifdef DEBUG_TX
+	gpio_set_value(14, 0);
+#endif
+
+	return 0;
+}
+
+static int alloc_ring_buffer(struct ring_buffer *rb,
+			unsigned int num_bufs, enum dma_data_direction direction)
+{
+	int i;
+
+	rb->rbi = __get_free_page(GFP_KERNEL | __GFP_COMP | __GFP_ZERO | __GFP_NOWARN);
+
+	rb->rbe = kzalloc(sizeof(struct ring_buffer_entry) * num_bufs, GFP_KERNEL);
+	if (!rb) {
+		printk(KERN_ERR "Failed to allocate memory for rb entries\n");
+		return -ENOMEM;
+	}
+
+	rb->num_pages = (num_bufs & 1) ? ((num_bufs + 1) / 2) : (num_bufs / 2);
+
+	rb->pages = kzalloc(sizeof(unsigned long) * rb->num_pages, GFP_KERNEL);
+	if (!(rb->pages)) {
+		printk(KERN_ERR "Failed to allocate memory for rb page entries\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < rb->num_pages; i++) {
+		(*rb->pages)[i] = __get_free_page(GFP_KERNEL | __GFP_DMA | __GFP_COMP | __GFP_ZERO | __GFP_NOWARN);
+
+		(*(rb->rbe))[i*2].frame_addr =
+			(*(rb->pages))[i];
+		(*(rb->rbe))[i*2 + 1].frame_addr =
+			((*(rb->pages))[i] + SZ_2K);
+		if (!(*(rb->rbe))[i*2].frame_addr || !(*(rb->rbe))[i*2 + 1].frame_addr) {
+			printk(KERN_ERR "Failed to allocate memory dma buf\n");
+			return -ENOMEM;
+		}
+
+		(*(rb->rbe))[i*2].dma_addr = dma_map_single(NULL, (*(rb->rbe))[i*2].frame_addr, SZ_2K, direction);
+		(*(rb->rbe))[i*2 + 1].dma_addr = dma_map_single(NULL, (*(rb->rbe))[i*2 + 1].frame_addr, SZ_2K, direction);
+		if (!(*(rb->rbe))[i*2].dma_addr || !(*(rb->rbe))[i*2 + 1].dma_addr) {
+			printk(KERN_ERR "Failed to get physical address for dma buf\n");
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+static void delete_ring_buffer(struct ring_buffer *rb,
+			unsigned int num_bufs, enum dma_data_direction direction)
+{
+	unsigned int i;
+	unsigned int num_pages;
+
+	printk(KERN_DEBUG "Entering delete_ring_buffer\n");
+
+	num_pages = (num_bufs & 1) ? ((num_bufs + 1) / 2) : (num_bufs / 2);
+
+	for (i = 0; i < num_pages; i++) {
+		dma_unmap_single(NULL, (*rb->rbe)[i*2].dma_addr, SZ_2K, direction);
+		dma_unmap_single(NULL, (*rb->rbe)[i*2 + 1].dma_addr, SZ_2K, direction);
+		free_page((*rb->pages)[i]);
+	}
+
+	free_page(rb->rbi);
+
+	kfree(rb->pages);
+	kfree(rb->rbe);
+
+	printk(KERN_DEBUG "Leaving delete_ring_buffer\n");
+}
+
+static int alloc_ring_buffers()
+{
+
+	if (alloc_ring_buffer(&tx_rb, rb_size.num_rx_frames, DMA_TO_DEVICE) < 0)
+		return -ENOMEM;
+	if (alloc_ring_buffer(&rx_rb, rb_size.num_tx_frames, DMA_FROM_DEVICE) < 0)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void init_ring_buffer(struct ring_buffer *rb, int num_bufs,
+			int initial_flags, enum dma_data_direction direction)
+{
+	int i;
+
+	for (i = 0; i < num_bufs; i++) {
+		dma_sync_single_for_device(NULL, (*rb->rbe)[i].dma_addr,
+					SZ_2K, direction);
+		dma_sync_single_for_cpu(NULL, (*rb->rbe)[i].dma_addr,
+					SZ_2K, direction);
+		(*rb->rbi)[i].flags = initial_flags;
+	}
+
+}
+
+#if 0
+static int tx_dma_func(void *data)
+{
+	int ret;
+	struct sched_param s = { .sched_priority = 1};
+
+	printk(KERN_DEBUG "In tx_dma_func\n");
+
+	allow_signal(SIGSTOP);
+
+	sched_setscheduler(current, SCHED_FIFO, &s);
+
+	while (!kthread_should_stop() && !closing_driver) {
+
+		if (!((*tx_rb.rbe)[tx_rb_read].flags & RB_USER)) {
+			tx_dma_waiting_for_data = 1;
+			ret = wait_event_interruptible(received_data_from_user,
+				     (*tx_rb.rbe)[tx_rb_read].flags & RB_USER);
+			if (ret) {
+				printk(KERN_DEBUG
+					"tx_dma_func received signal %d\n",
+					ret);
+				if (closing_driver)
+					break;
+
+			}
+			tx_dma_waiting_for_data = 0;
+		}
+
+		if (wait_event_interruptible(space_available_queue,
+				gpio_get_value(TX_SPACE_AVAILABLE_GPIO))) {
+			printk(KERN_DEBUG "tx_dma received signal waiting for space.\n");
+			if (closing_driver)
+				break;
+		}
+
+		if (send_frame_to_fpga(&(*tx_rb.rbe)[tx_rb_read]) != 0) {
+			printk(KERN_DEBUG "send_frame received signal.\n");
+			if (closing_driver)
+				break;
+		}
+
+		(*tx_rb.rbe)[tx_rb_read].flags = RB_KERNEL;
+
+		tx_rb_read++;
+		if (tx_rb_read == RB_SIZE)
+			tx_rb_read = 0;
+
+#if 0
+		if (waiting_for_space_in_tx_rb)
+#endif
+			wake_up_interruptible(&tx_rb_space_queue);
+
+	}
+	return 0;
+}
+#endif
diff --git a/include/linux/usrp_e.h b/include/linux/usrp_e.h
new file mode 100644
index 0000000..e52f709
--- /dev/null
+++ b/include/linux/usrp_e.h
@@ -0,0 +1,87 @@
+
+/*
+ *  Copyright (C) 2010 Ettus Research, LLC
+ *
+ *  Written by Philip Balister <philip@opensdr.com>
+ *
+ *  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.
+ */
+
+#ifndef __USRP_E_H
+#define __USRP_E_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+struct usrp_e_ctl16 {
+	__u32 offset;
+	__u32 count;
+	__u16 buf[20];
+};
+
+struct usrp_e_ctl32 {
+	__u32 offset;
+	__u32 count;
+	__u32 buf[10];
+};
+
+/* SPI interface */
+
+#define UE_SPI_TXONLY	0
+#define UE_SPI_TXRX	1
+
+/* Defines for spi ctrl register */
+#define UE_SPI_CTRL_TXNEG	(BIT(10))
+#define UE_SPI_CTRL_RXNEG	(BIT(9))
+
+#define UE_SPI_PUSH_RISE	0
+#define UE_SPI_PUSH_FALL	UE_SPI_CTRL_TXNEG
+#define UE_SPI_LATCH_RISE	0
+#define UE_SPI_LATCH_FALL	UE_SPI_CTRL_RXNEG
+
+struct usrp_e_spi {
+	__u8 readback;
+	__u32 slave;
+	__u32 data;
+	__u32 length;
+	__u32 flags;
+};
+
+struct usrp_e_i2c {
+	__u8 addr;
+	__u32 len;
+	__u8 data[];
+};
+
+#define USRP_E_IOC_MAGIC	'u'
+#define USRP_E_WRITE_CTL16	_IOW(USRP_E_IOC_MAGIC, 0x20, struct usrp_e_ctl16)
+#define USRP_E_READ_CTL16	_IOWR(USRP_E_IOC_MAGIC, 0x21, struct usrp_e_ctl16)
+#define USRP_E_WRITE_CTL32	_IOW(USRP_E_IOC_MAGIC, 0x22, struct usrp_e_ctl32)
+#define USRP_E_READ_CTL32	_IOWR(USRP_E_IOC_MAGIC, 0x23, struct usrp_e_ctl32)
+#define USRP_E_SPI		_IOWR(USRP_E_IOC_MAGIC, 0x24, struct usrp_e_spi)
+#define USRP_E_I2C_READ		_IOWR(USRP_E_IOC_MAGIC, 0x25, struct usrp_e_i2c)
+#define USRP_E_I2C_WRITE	_IOW(USRP_E_IOC_MAGIC, 0x26, struct usrp_e_i2c)
+#define USRP_E_GET_RB_INFO      _IOR(USRP_E_IOC_MAGIC, 0x27, struct usrp_e_ring_buffer_size_t)
+
+/* Flag defines */
+#define RB_USER (BIT(0))
+#define RB_KERNEL (BIT(1))
+#define RB_OVERRUN (BIT(2))
+#define RB_DMA_ACTIVE (BIT(3))
+
+struct ring_buffer_info {
+	int flags;
+	int len;
+};
+
+struct usrp_e_ring_buffer_size_t {
+	int num_pages_rx_flags;
+	int num_rx_frames;
+	int num_pages_tx_flags;
+	int num_tx_frames;
+};
+
+#endif
-- 
1.6.6.1

