我已经为uPP设备驱动程序编写了代码,该驱动程序将与基于OMAPL138的自定义板一起使用,用于通过相机镜头进行数据采集。我的设备驱动程序的代码是:
/*
* 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: EOLIn");
//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: EOWIn");
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....OKn", 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....OKn", 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 initilizedn");}
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 = %dn", 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)
有了这些代码,我制作了一个测试应用程序,它编写了一个基于.264的输出文件,其中包含从我的自定义板上获取的数据,我称之为upp_tester.cp:
#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]={' '};
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] - UPPn" , 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.datn" , errno );
}
//fprintf( stderr , "UPP TESTER Version 1.0.17nn" );
for (k=0;k<32;k++)
{
bytesRead = read( upp_fd, readBuff, sizeof (readBuff));
fprintf( stderr , "READ [%d] bytes out of [%d] bytesn" , bytesRead , sizeof(readBuff) );
bytesWritten = write( out_fd, readBuff, bytesRead );
fprintf( stderr , "WROTE [%d] bytes out of [%d] bytesn" , bytesWritten , sizeof(readBuff) );
}
}
close(upp_fd);
close(out_fd);
return 0;
}
现在,当我浏览输出文件时,我发现丢失了很多字节,我通常使用memset将其设置为255。这是因为我为测试文件的dsp处理器编程的核心设置为从0-99抛出固定数据。是什么导致了这个问题。我是一个设备驱动程序和内核级编程的新手,所以任何帮助都将不胜感激。
如果您想将驱动程序提交给上游(这实际上是一条正确的道路(,您可能会联系使用DaVinci板的TI人员。我想你已经在谷歌上搜索了链接达维基。
关于你的驱动程序,由于它的代码风格,很难检查。此外,您可以查看现代内核API,以了解您试图手动编程的内容(电压调节器、时钟、引脚控制等(。对于许多基本设备,已经有了驱动程序和设置。此外,您还必须在设备树中描述您的板配置。通常,这意味着创建一个附加的(通用的(配置,并将其放在arch/arm/boot/dts/下。在那里你可以找到da850预定义的数据库。