uPP Device Driver is dropping data from buffer

1

I have written code for a uPP device driver to be used with an OMAPL138 based custom board for data acquisition through a camera lens. The code for my device driver is:

    /* 
 *   A device driver for the Texas Instruments
 *   Universal Paralllel Port (UPP)
 *  
 *   Modified by: Ali Shehryar <github.com/sshehryar>
 *
 */

#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/fs.h>      
#include <linux/delay.h>      //for "mdelay(...)"
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <linux/moduleparam.h>
#include <mach/da8xx.h>
#include <asm/sizes.h>
#include <asm/io.h>       
#include <mach/mux.h>
#include <linux/gpio.h>
#include <mach/gpio.h>
#include <asm/gpio.h>

//SPRUH77A.PDF, Table 12-1. The Interrupt number assigned to the UPP module.
#define UPP_INTERRUPT   91

//SPRS586D.PDF, Table 2-4
#define DA850_UPP_BASE  0x01E16000

//SPRS586D.PDF, Table 5-117. Offsets from DA850_UPP_BASE
#define UPPCR           0x00000004
#define UPDLB           0x00000008
#define UPCTL           0x00000010
#define UPICR           0x00000014
#define UPIVR           0x00000018
#define UPTCR           0x0000001C
#define UPIER           0x00000024
#define UPIES           0x00000028
#define UPIEC           0x0000002C
#define UPEOI           0x00000030
#define UPID0           0x00000040
#define UPID1           0x00000044
#define UPID2           0x00000048
#define UPIS0           0x00000050
#define UPIS1           0x00000054
#define UPIS2           0x00000058


//SPRS586D.PDF, Table 2-4
#define DA850_PSC1_BASE 0x01E27000 

//SPRUH77A.PDF, Table 9-7. 
//"Power and Sleep Controller 1" (PSC1)  Revision ID Register.
#define PSC_REVID       0x00000000

//SPRUH77A.PDF, Table 9-7. 
//"Power Domain Transition Status" Register.
#define PSC_PTSTAT      0x00000128

//SPRUH77A.PDF, Table 9-2, Table 9-7. 
//NOTE that in Table 9-2, UPP module has an LPSC number of 19...
#define PSC1_MDCTL_19   0x00000A4C  //0xA00 + (19*4). 

//SPRUH77A.PDF, Table 9-7. 
//"Power Domain Transition Command Register" Register.
#define PSC_PTCMD       0x00000120




//DMA Status Register bitmasks used in the ISR handler.... 
#define EOLI   16
#define EOWI   8
#define ERRI   4
#define UORI   2 
#define DPEI   1

#define UPIES_MASK 0x0000001F
///#define UPIES_MASK 0x1717 ---> Reverted back to 1717 because Window interrupt is not used, for now its useless
//To Enable all interrupts --->  #define UPIES_MASK 0x1F1F



/// Shehryar: These Parameters are to be modified and tweaked according to reqirements in realtime.
//The DMA PARAMETERS 
#define UPP_BUF_SIZE       8192 //Need to lookup for an exact val (changed from 8192 on 2 DEc 14)
#define UPP_RX_LINE_COUNT  8    //Changed from 8 
#define UPP_RX_LINE_SIZE   1024
#define UPP_RX_LINE_OFFSET 1024 //value changed from 1024 to 0 on 2 DEC 2014

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//MODIFIED BY: SHEHRYAR ---> Pg 888 General-Purpose Input/Output (GPIO) SPRUH82A–December 2011. Added 25-Nov-2014           

#define DA850_GPIO_BASE       0x01E26000
//------------------------------------- 9/12/2014-----------------
//#define MY_BUFFER_SIZE        1048756
//----------------------------------------------------------------                                                  

//MODIFIED BY: SHEHRYAR. Offsets from GPIO_Base (SPRS653C.PDF TABLE 5-134)

#define DIR67       0x00000088
#define OUT_DATA67  0x0000008C
#define SET_DATA67  0x00000090
#define CLR_DATA67  0x00000094  
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void *rxBuf; 
static void __iomem *pinmux_base = 0;
static void __iomem *upp_base    = 0;
static void __iomem *psc1_base   = 0;
static void __iomem *gpio_base   = 0;

static DECLARE_WAIT_QUEUE_HEAD(read_queue);
static int32_t read_pending = 0; // changed from static int


//set to '1' when loading this module to use the Digital Loopback (DLB) 
//features,e.g:"insmod UPP_driver.ko loopbackMode=1"

static int loopbackMode = 0;

module_param( loopbackMode, int, S_IRUGO);

int EOWI_Count = 0; int UORI_count =0;

///////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////INTERRUPT SERVICE ROUTINE//////////////////////////////////////
//////////////////////////////////////SPRUH82A–December 2014 PAGE 1515////////////////////////////////

   //SPRUGJ5B.PDF, Section 2.6.4
static irqreturn_t upp_ISR_handler(int irq, void *dev_id)
{
   uint32_t regVal, status;

   if (pinmux_base == 0) 
   {
      return IRQ_HANDLED;
   }

   status = ioread32( upp_base + UPIER );


   while (status &  0x0000001F )  //0x1F1F is an interrupt bit-mask 
   {
      //
      //DMA Channel I (Channel A), Receiving data (We Need A (DMA Ch I ) to Rx Data instead of Tx ; 27th Nov 2014 - 10:38am)
      //
      if (status & EOLI) 
      {
    //Clear the interrupt. WRITING ZERO to any other bit has NO effect,
    //per SPRUH77A.PDF, section 33.3.9.
    iowrite32(EOLI, upp_base + UPIER );

    //printk(KERN_INFO "DMA:  EOLI\n");
    //printk(KERN_INFO "DMA:EOLI.  UPP_RX_LINE_SIZE[%d] UPP_RX_LINE_OFFSET[%d] UPP_RX_LINE_COUNT[%d] \n",       UPP_RX_LINE_SIZE,UPP_RX_LINE_OFFSET,UPP_RX_LINE_COUNT );
    //dump_Channel_regs();
    }

    if (status & EOWI) 
    {
         //Clear the interrupt. WRITING ZERO to any other bit has NO effect,
         //per SPRUH77A.PDF, section 33.3.9.
        //printk(KERN_INFO "DMA:  EOWI\n");
        iowrite32(EOWI, upp_base + UPIER );

        read_pending = 8192;
        wake_up_interruptible(&read_queue);
        //add 1 to EOWI counter
        EOWI_Count += 1;

     //    dump_Channel_regs();
    }

    if (status & ERRI) 
    {
         //Clear the interrupt. WRITING ZERO to any other bit has NO effect,
         //per SPRUH77A.PDF, section 33.3.9.
         iowrite32(ERRI, upp_base + UPIER );


         //dump_Channel_regs();
      }
      if (status & UORI) 
      {
         //Clear the interrupt. WRITING ZERO to any other bit has NO effect,
         //per SPRUH77A.PDF, section 33.3.9.
         iowrite32(UORI, upp_base + UPIER );
         UORI_count +=1;

         //dump_Channel_regs();
      }
      if (status & DPEI) 
      {
         //Clear the interrupt. WRITING ZERO to any other bit has NO effect,
         //per SPRUH77A.PDF, section 33.3.9.
         iowrite32(DPEI, upp_base + UPIER );


         //dump_Channel_regs();
      }
    //read again, and process if necessary.
      status = ioread32( upp_base + UPIER );
   }    
   //Clear UPEOI to allow future calls to this function.
   regVal = ioread32( upp_base + UPEOI);
   regVal &= 0xFFFFFF00;
   regVal = 0;// End of Interrupt

   iowrite32(regVal, upp_base + UPEOI);

   return IRQ_HANDLED;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void pin_mux_set( int index, unsigned int bits )
{
   static DEFINE_SPINLOCK(mux_spin_lock);
   unsigned long flags;
   unsigned int offset;

   if ((index < 0) || (index > 19))
   {
      printk(KERN_INFO "pin_mux_set:index is out of range.\n");
      return;
   }

   if (!pinmux_base) 
   {
      //SRPUH77A.PDF,Table 11-3
      if ((pinmux_base = ioremap(DA8XX_SYSCFG0_BASE, SZ_4K)) == 0) 
      {
         printk(KERN_INFO "pin_mux_set:Cannot fetch pinmux_base.\n");
         return;
      }
   }

   offset = 0x120 + (index * 4);
   spin_lock_irqsave(&mux_spin_lock, flags);
   iowrite32(bits, pinmux_base + offset);
   spin_unlock_irqrestore(&mux_spin_lock, flags);

   //NOTE: do NOT "iounmap" the pinmux_base pointer, as it is used
   //      in the ISR_handler.....
}



static void upp_pin_mux_init(void)
{
   pin_mux_set( 13, 0x44440000 );
   pin_mux_set( 14, 0x44444480 ); 
   pin_mux_set( 15, 0x44444444 );
   pin_mux_set( 16, 0x44444444 );
   pin_mux_set( 17, 0x44444444 );
   pin_mux_set( 18, 0x00444444 );
   pin_mux_set( 19, 0x08888800 );   
   //pin_mux_print() ;
}


   //SPRUGJ5B.PDF, Section 2.6.1.2.
static void upp_power_and_clocks( void )
{
   /* 
    * Refer to: 
    *   * Power and Sleep Controller (PSC), Chapter 9 in the TRM(SPRUH77A.PDF)
    *   * Device Clocking, Chapter 7 (esp Section 7.3.5) in the TRM. 
    *  
    *  
    */
    int regVal;


    if (!psc1_base) 
    {
       if ((psc1_base = ioremap(DA850_PSC1_BASE, SZ_4K)) == 0)
       {
          printk(KERN_INFO "upp_power_and_clocks:Cannot fetch psc1_base.\n");
          return;
       }
    }

    regVal = ioread32(psc1_base + PSC_REVID);

    //PSC Revision ID should be "44825A00" per SPRUH77A.PDF, section 9.6.1
    if (regVal == 0x44825A00) 
    {
       printk( KERN_INFO "PSC_REVID = 0x%08X....OK\n", regVal); 
    }
    else
    {
       printk( KERN_INFO "********ERROR: PSC_REVID = 0x%08X********\n", regVal); 
    }

    // SPRUH77A.PDF, 9.3.2.1, Table 9-6, 9.6.10 
    // wait for GOSTAT[0] in PSTAT to clear to 0 ("No transition in progress")
    while ( ioread32(psc1_base + PSC_PTSTAT) & 0x00000001 )
    ;   

    //
    //SPRUH77A.PDF, 9.3.2.2,  9.6.19.
    //Set NEXT bit in MDCTL19 to Enable(3h).
    regVal  = ioread32( psc1_base + PSC1_MDCTL_19 );
    regVal |= 0x00000003;
    iowrite32(regVal, psc1_base + PSC1_MDCTL_19);


    //
    //SPRUH77A.PDF, 9.3.2.3,  9.6.9. 
    //Set the GO[0] bit in PTCMD to 1 to initiate power-domain transition
    regVal  = ioread32(psc1_base + PSC_PTCMD);
    regVal |= 0x00000001;
    iowrite32(regVal, psc1_base + PSC_PTCMD);

    //
    // SPRUH77A.PDF, 9.3.2.4 
    // Wait for GOSTAT[0] in PTSTAT to clear to 0
    while ( ioread32(psc1_base + PSC_PTSTAT) & 0x00000001 )
    ;  

    iounmap( psc1_base );
    psc1_base = 0;


}

   //SPRUGJ5B.PDF, Section 2.6.1.3, 2.6.1.4
static void upp_swrst( void )
{
    int32_t reg_val;

    if (!upp_base)
    {
       if ((upp_base = ioremap(DA850_UPP_BASE, SZ_4K)) == 0) 
       {
          printk(KERN_INFO "upp_swrst:Cannot fetch upp_base.\n");
          return;
       }
    }
    //Fetch the UPP ID for the sake of sanity....Should be "44231100"
    reg_val = ioread32( upp_base + 0 );
    if (reg_val == 0x44231100 ) 
    {
       printk(KERN_INFO "UPP_UPPID = 0x%08X....OK\n", reg_val);
    }
    else
    {
       printk( KERN_INFO "********ERROR: UPP_UPPID = 0x%08X********\n", reg_val); 
    }



    // SPRUH77A.PDF, Section 33.2.7.1.1, Table 33-12.
    // clear EN bit of UPPCR to (temporarily) disable the UPP. 
    reg_val = ioread32( upp_base + UPPCR );
    reg_val &= ~(1 << 3);             //0xfffffff7;
    iowrite32( reg_val, upp_base + UPPCR );

    // SPRUH77A.PDF, Section 33.2.7.1.2, Table 33-12.
    //poll "DMA Burst" (DB) bit of UPPCR to ensure DMA controller is idle
    while ( ioread32( upp_base + UPPCR ) & (1 << 7) )
        ;


    // SPRUH77A.PDF, Section 33.2.7.1.3, Table 33-12.
    // assert SWRST bit (bit 4) of UPPCR
    reg_val  = ioread32( upp_base + UPPCR );
    reg_val |= 0x00000010;
    iowrite32( reg_val, upp_base + UPPCR );

    //
    // wait at least 200 clock cycles 
    // (SPRUGJ5B.PDF, 2.6.1.4)
    mdelay( 200 );  // abitrary choice of 200ms


    // SPRUH77A.PDF, Section 33.2.7.1.4  --AND--
    // SPRUGJ5B.PDF, 2.6.1.4
    // clear SWRST bit (bit 4) of UPPCR
    reg_val = ioread32( upp_base + UPPCR );
    reg_val &= 0xffffffef;
    iowrite32( reg_val, upp_base + UPPCR );


}


   //SPRUGJ5B.PDF, Section 2.6.1.5
static void upp_config( void )
{
   int32_t regVal;

   //-------------------------------------------------------------------------
   // UPPCTL - UPP Interface Channel Settings....SPRUH77A.PDF, Section 33.3.4.
   //        
   //        - DATA and XDATA Pin assignments to Channels A & B:
   //          Refer to SPRUGJ5B.PDF, Table 3: 
   //              
   //        ____PHYSICAL_PINS___|____CHANNEL_ASSIGNMENT___
   //          * DATA[7:0]       |       A[7:0]
   //          * DATA[15:8]      |       B[7:0]
   //-------------------------------------------------------------------------
   regVal = 0;
   regVal |= 1 << 17;       // IWA  - CHANNEL A 8/16bit MODE: Set Channel A to 16 bit mode


   iowrite32( regVal, upp_base + UPCTL );


   //-------------------------------------------------------------------------
   // UPPICR - signal enable, signal inversion, clk div (tx only), etc.
   //          SPRUH77A.PDF, Section 33.3.5
   //-------------------------------------------------------------------------

   regVal  = 0;        //Channel A: START is active-high

   regVal |= 1<<3;  //Channel A:STARTA is honored in Rev Mode
   regVal |= 1<<4;  //Channel A:ENABLEA is honored in Rev Mode
   regVal |= 1<<12;  //Channel A:(CLKINVA) Signal on rising edge of clock
   regVal |= 1<<13;  //Channel A:(TRISA) pins are High-impedence while idle

   iowrite32( regVal, upp_base + UPICR );


   //-------------------------------------------------------------------------
   // UPPIVR - Idle Value Register
   //          SPRUH77A.PDF, Section 33.3.5
   //-------------------------------------------------------------------------
   regVal = 0;
   regVal |= 0xab00;   //Channel B Idle Value
   regVal |= 0x00cd;   //Channel A Idle Value
   iowrite32( regVal, upp_base + UPIVR );


   //-------------------------------------------------------------------------
   // UPTCR - i/o tx thresh (tx only), dma read burst size
   //-------------------------------------------------------------------------
   regVal  = 0x00000003;            //DMA Channel I READ-threshold. 256 bytes (max)

   iowrite32(regVal, upp_base + UPTCR );
}

//SPRUGJ5B.PDF, Section 2.6.1.6
static void upp_interrupt_enable( void )
{
   int32_t regVal, status;

   // Register the ISR before enabling the interrupts....
   status = request_irq( UPP_INTERRUPT, upp_ISR_handler, 0, "upp_ISR", 0 );
   if( status < 0 ) 
   {

        return;
   }

   // clear all interrupts
   iowrite32( UPIES_MASK, upp_base + UPIEC );

   //------------------------------------------------------------------------
   //Dumping Registers again for debugging purpose  
   //dump_Channel_regs();
   //-------------------------------------------------------------------------


   //-------------------------------------------------------------------------
   // UPIES - Interrupt Enable. Interrupt events will generate a CPU interrupt
   //-------------------------------------------------------------------------
   // regVal  = 0x17;            //Enable ALL interrupts (but EOWI) for DMA Channel I
   //regVal |= 0x17 << 8;       //Enable ALL interrupts (but EOWQ) for DMA Channel Q 
   regVal = UPIES_MASK;
   iowrite32( regVal, upp_base + UPIES );


}


//SPRUGJ5B.PDF, Section 2.6.1.7
static void upp_enable( void )
{
    int32_t reg_val;

    // set EN bit in UPPCR. 
    // The EN bit (effectively disabling the UPP peripheral)...
    // was cleared in "upp_swrst()" function
    reg_val = ioread32( upp_base + UPPCR );
    reg_val |=  1 << 3;  
    iowrite32( reg_val, upp_base + UPPCR );


}

static void upp_disable( void )
{
    int32_t reg_val;

    reg_val = ioread32( upp_base + UPPCR );
    reg_val &= ~(1 << 3);             //0xfffffff7;
    iowrite32( reg_val, upp_base + UPPCR );


}

////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////MODIFIED BY: SHEHRYAR ; 25-NOV-2014 4:40pm PST (+5.00 GMT)///////////////////
static void setpin_GPIO (void)
{

    int32_t reg_val=0;

    if ((gpio_base = ioremap(DA850_GPIO_BASE, SZ_4K)) == 0) 
      {

         return;
      } 
    //reg_val = ioread32(gpio_base + SET_DATA67);
    reg_val |= (1<<6); ///Set Pin 6 of Bank 6 GP6P6 to 1 to drive GPIO high
    iowrite32(reg_val,gpio_base + SET_DATA67);
}

static void clrpin_GPIO(void)
{

    int32_t reg_val=0;
    if ((gpio_base = ioremap(DA850_GPIO_BASE, SZ_4K)) == 0) 
    {
        return;
    }   
    //reg_val = ioread32(gpio_base + CLR_DATA67);
    /*reg_val |= ~(1<<0);
    reg_val |= ~(1<<1);
    reg_val |= ~(1<<2);
    reg_val |= ~(1<<3);
    reg_val |= ~(1<<4);*/
    reg_val |= (1<<6); //Set Pin 6 of bank 6 GP6P6 of CLR_DATA67 Register to High to drive GPIO signals low

    iowrite32(reg_val,gpio_base + CLR_DATA67);

}
///////Function to set DIR to 1 for GP6P5//////////////////////////////////////////////////////////////

static void Config_GPIO(void)
{
     int32_t reg_val;   

     if ((gpio_base = ioremap(DA850_GPIO_BASE, SZ_4K)) == 0) 
     {
        return;
     }  
    //set dir 
    reg_val = ioread32(gpio_base + DIR67);
    reg_val &= ~(1<<0); 
    reg_val &= ~(1<<1);
    reg_val &= ~(1<<2);
    reg_val &= ~(1<<3);
    reg_val &= ~(1<<4);
    reg_val &= ~(1<<6);
    iowrite32(reg_val,gpio_base + DIR67);
    printk(KERN_INFO "DIR67 => [0x%08X]\n", reg_val);
    //set to high
    reg_val = ioread32(gpio_base + SET_DATA67);
    reg_val |= (1<<0); 
    reg_val |= (1<<1);
    reg_val |= (1<<2);
    reg_val |= (1<<3);
    reg_val |= (1<<4);
    iowrite32(reg_val,gpio_base + SET_DATA67);

}
//////////////////////////////////////////////////////////////////////////////////////////////////////

//SPRUGJ5B.PDF, Section 2.6.1.8
// Return false on error
static bool upp_mem_alloc( void )
{
    //rxBuf2 = kcalloc( 1 , UPP_BUF_SIZE, GFP_KERNEL | GFP_DMA  );   
    rxBuf = kcalloc( 1 , UPP_BUF_SIZE, GFP_KERNEL | GFP_DMA  );
    if (!rxBuf) //|| (!rxBuf2)
    {
        return false;
    }

    return true;
}

static void upp_program_DMA_channelA( void )
{
    while ( ioread32( upp_base + UPIS2 ) & 0x00000002 );
    //------------------------------------------------------------------------
    // Channel A (Rx), (DMA Channel I) //27th Nov 2014 - 11:08 am
    //------------------------------------------------------------------------
    iowrite32( rxBuf, upp_base + UPID0);  
    iowrite32( ( (UPP_RX_LINE_COUNT << 16) | UPP_RX_LINE_SIZE ), upp_base + UPID1);
    iowrite32( UPP_RX_LINE_OFFSET, upp_base + UPID2);
}


//------------------------------------------------------------------------
// User-mode functions read/write/open/close, etc.
//------------------------------------------------------------------------


int upp_open( struct inode *iPtr, struct file *fPtr )
{
    int minor,major;
    read_pending  = 0;

    minor=iminor(iPtr);
    major=imajor(iPtr);
    printk( KERN_INFO "upp_open: MAJOR(%d), MINOR(%d)\n", major, minor);

    upp_disable();
    upp_enable();

    return 0;

}

////////////////////////////////////////////////////////////READ FUNCTION STARTS HERE!!!!!!////
/*-------------------------------------------------------------------------------------------*/

//int count_missing_data=0;
//static int read_flag =0;

ssize_t upp_read( struct file *fPtr, char __user *buffer, size_t size, loff_t *offset )
{

    int readBytes = 0;
    int retVal=0; 
    void *bPtr = (void *)buffer;

    if (!bPtr) {return -1; printk(KERN_INFO "ERROR: bPtr not initilized\n");}

    printk(KERN_INFO "Reading %d Bytes ...\n",size );

    while (readBytes<size)  
    {
        //read_flag+=1;     
        read_pending = 0;   
        //mdelay(10);   

        memset(rxBuf,255,8192);
        //memset(rxBuf2,128,8192);

        upp_program_DMA_channelA();

        clrpin_GPIO(); 

        wait_event_interruptible( read_queue, read_pending > 0 );

        while ( ioread32( upp_base + UPIS2 ) & 0x00000001 )        
        {
            printk (KERN_INFO "DMA IS STILL ACTIVE! \n");       
        }
        setpin_GPIO(); // Set High 

        retVal = copy_to_user(bPtr,rxBuf,read_pending);

        if(retVal)
        {
            printk(KERN_INFO "ERROR: Copy to user failed!\n");
            return readBytes;
        }
        readBytes += read_pending;

        bPtr +=  8192;

    } //end of while loop

    printk(KERN_INFO"\nRead [%d] Bytes.\n",readBytes);

    printk(KERN_INFO"END OF WINDOW (EOWI) INTERRUPT Count = [%d]\n", EOWI_Count);   

    printk(KERN_INFO"DMA UNDERRUN OR OVERFLOW (UORI) Interrupt Count = %d\n", UORI_count);

    return readBytes;
    //read_flag += 1;

    //mdelay(9);
}

//////////////////////////////////////////////READ() FUNCTION ENDS HERE!!!!!!///////////////////////////
/*---------------------------------------------------------------------------------------------------*/
int upp_release( struct inode *iPtr, struct file *fPtr )
{

   return 0;
   printk(KERN_INFO "upp_release completed.\n");
}


static struct cdev *UPP_cdev;
static dev_t UPP_MajorMinorNumbers;

struct file_operations upp_fops = { 
  .owner        = THIS_MODULE,
  //.llseek     = no_llseek,
  //.poll       = upp_poll,
    .read       = upp_read,
  //.write      = upp_write,
  //.ioctl  = upp_ioctl,
    .open       = upp_open,
  //.release    = upp_release,
};


/*
 *  Return ZERO on success.
 *  
 */
static int __init upp_init(void)
{
   int retVal;

   //printk(KERN_INFO "Entering upp_init().\n"); 
   //SPRUGJ5B.PDF, Section 2.6.1.8
   // I'm doing this out-of-order...If the mem-allocation fails,
   // there is no sense in doing anything else, except to bail early... 
   if (upp_mem_alloc() == false)
   {
      printk(KERN_INFO "******ERROR: Could not allocate buffers. Bailing!******\n");
      return -1;
   }

   //--------------------------------------------------------

   //--------------------------------------------------------
   //SPRUGJ5B.PDF, Section 2.6.1.1
   upp_pin_mux_init();
   printk(KERN_INFO "upp_pin_mux_init()...OK.\n");



   //SPRUGJ5B.PDF, Section 2.6.1.2.
   upp_power_and_clocks();
   printk(KERN_INFO "upp_power_and_clocks()...OK.\n");  

   //SPRUGJ5B.PDF, Section 2.6.1.3, 2.6.1.4
   upp_swrst();
   printk(KERN_INFO "upp_swrst()...OK.\n");

   //SPRUGJ5B.PDF, Section 2.6.1.5
   upp_config();
   printk(KERN_INFO "upp_config()...OK.\n");

   //SPRUGJ5B.PDF, Section 2.6.1.6
   upp_interrupt_enable();
   printk(KERN_INFO "upp_interrupt_enable()...OK.\n");

   //SPRUGJ5B.PDF, Section 2.6.1.7
   upp_enable();
   printk(KERN_INFO "upp_enable()...OK.\n");

   //---------------------------SETTING GPIOS----------------   
    Config_GPIO();
   //--------------------------------------------------------   
    setpin_GPIO(); // Set High 


   UPP_MajorMinorNumbers = MKDEV( 0, 0);
   if ( (retVal = alloc_chrdev_region( &UPP_MajorMinorNumbers, 0, 1, "UPP" )) < 0)
   {
      printk(KERN_INFO "ERROR: Major/Minor number allocation failed.\n");
      return retVal;
   }


   UPP_cdev        = cdev_alloc();
   UPP_cdev->ops   = &upp_fops; 
   UPP_cdev->owner = THIS_MODULE;

   if (cdev_add( UPP_cdev, UPP_MajorMinorNumbers, 1) != 0) 
   {
      printk(KERN_INFO "ERROR: UPP driver NOT loaded. CDEV registration failed.\n");
   }
   else
   {
      printk(KERN_INFO "\nUPP Major: %d , Minor: %d \n", MAJOR(UPP_MajorMinorNumbers), MINOR(UPP_MajorMinorNumbers));
   }

   printk("UPP driver (1.8.0 - 5/January/2015) succesfully installed.\n"); 

   return 0;
}

/*
 * 
 *  
 *  
 */
static void __exit upp_exit(void)
{
   uint32_t regVal;
   printk(KERN_INFO "Exiting..Initializing upp_exit call......\n");

   // SPRUH77A.PDF, Section 33.2.7.1.1, Table 33-12.
   // clear EN bit of UPPCR to disable the UPP. 
   regVal = ioread32( upp_base + UPPCR );
   regVal &= 0xfffffff7;
   iowrite32( regVal, upp_base + UPPCR );


   free_irq( UPP_INTERRUPT, 0);


   if (rxBuf) 
   {
      kfree( rxBuf );
      rxBuf = 0;
   }

    /*if (rxBuf2)
    {
        kfree(rxBuf2);
        rxBuf2=0;
    }*/
   cdev_del( UPP_cdev );
   unregister_chrdev_region( UPP_MajorMinorNumbers, 1);
   clrpin_GPIO(); //added 2-Dec-2014
   printk(KERN_INFO "UPP driver unloaded (Successful Exit). \n");
}


MODULE_AUTHOR("Ali Shehryar & Umair Ali");
MODULE_DESCRIPTION("OMAP-L138/AM-1808 UPP bus driver");
MODULE_LICENSE("GPL");
module_init(upp_init)
module_exit(upp_exit)

With the code, I have made a tester application that writes a .264 based output file consisting of data acquired from my custom board which I call upp_tester.cpp :

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <string.h>

int main(int argc, char **argv )
{
    int count = 0;
    const int BytesToRead = 8192*4; //32kB
    int bytesRead  = -1;
    int bytesWritten = -1 ;
    int upp_fd,out_fd;
    char readBuff[BytesToRead] = {0,};
    int k = 0;


    readBuff[BytesToRead]={'\0'};
    upp_fd = open( "/dev/upp", O_RDWR);
    out_fd = open( "output_upp.264", O_RDWR|O_CREAT);

    for(count = 0; count<100; count++)
    {

        if (upp_fd == -1) 
        {
        fprintf( stderr , "OPEN failed [%d] - UPP\n" , errno );
        if (errno == 2) 
        {
        fprintf( stderr , "NOTE! Check that /dev/upp actually exists, and has the right permissions \n");
        }
        return errno;
        }
        if (out_fd == -1) 
        {
        fprintf( stderr , "OPEN /output_upp failed [%d] - Out.dat\n" , errno );
        }

        //fprintf( stderr , "UPP TESTER Version 1.0.17\n\n" ); 

        for (k=0;k<32;k++)
        {   
            bytesRead    = read( upp_fd, readBuff, sizeof (readBuff));
            fprintf( stderr , "READ  [%d] bytes out of [%d] bytes\n" , bytesRead    , sizeof(readBuff) );

            bytesWritten = write( out_fd, readBuff, bytesRead );
            fprintf( stderr , "WROTE [%d] bytes out of [%d] bytes\n" , bytesWritten , sizeof(readBuff) );
        }   
 }  
    close(upp_fd);
    close(out_fd);




    return 0;
}

Now when I explore the output file, I see that a lot of bytes are missing which I usually set to 255 using memset. This is because the core I have programmed for my dsp processor for the tester file is set to throw fixed data from 0-99. What could be causing this problem. I am a total newbie to device drivers and kernel level programming so any help would be deeply appreciated.

c
multithreading
arm
linux-device-driver
omap
asked on Stack Overflow Jan 5, 2015 by Shehryar • edited Jan 5, 2015 by Shehryar

1 Answer

0

In case you would like to submit the driver to upstream (which actually a right way to go), you probably may contact with TI guys who are working with DaVinci boards. I assume you already googled the link DaVinci Wiki.

Regarding to your driver it's hard to check due to its code style. Moreover you may check modern kernel APIs for stuff you are trying to program manually (voltage regulators, clocks, pin control, and so on). For many basic devices there are already drivers and setup. Also you have to describe you board configuration in device tree. Usually it means to create an additional (to the common) piece of configuration and put it under arch/arm/boot/dts/. There you may find da850 predefined data bases.

answered on Stack Overflow Jan 7, 2015 by 0andriy

User contributions licensed under CC BY-SA 3.0