www.pudn.com > vxworks_usb.rar > ossLib.c


/* ossLib.c - O/S-independent services for vxWorks */

/* Copyright 2000-2002 Wind River Systems, Inc. */

/*
Modification history
--------------------
01f,22jan02,wef  All USB memory now comes from a cacheDmaMalloc'd partition.  
		 Instrument routines to get partition information.
01e,25oct01,wef  changed ossMalloc to call memalign instead of malloc - it now
		 returns buffers that are a multiple of a cache line size 
		 aligned on a cache line boundary
01d,18sep01,wef  merge from wrs.tor2_0.usb1_1-f for veloce
01c,01aug01,rcb  fixed manpage generation in comments
01b,07mar00,rcb  Cast handles as necessary to reflect change in handle
		 definition from UINT32 to pVOID.
01a,07jun99,rcb  First.
*/

/*
DESCRIPTION

Implements functions defined by ossLib.h.  See ossLib.h for
a complete description of these functions.
*/


/* includes */

#include "vxWorks.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

#include "errnoLib.h"           /* errno */
#include "sysLib.h"             /* sysClkRateGet(), etc. */
#include "taskLib.h"            /* taskSpawn(), etc. */
#include "semLib.h"             /* semCreate(), etc. */
#include "objLib.h"             /* S_objLib_OBJ_xxxx errors */
#include "tickLib.h"            /* tickGet(), etc. */
#include "cacheLib.h"           /* cacheDmaMalloc, Free */

#include "usb/usbPlatform.h"
#include "usb/ossLib.h"         /* Our API */


/* Defines */

                                /* #define  FILL_MEMORY *//* for debugging */


/* Definitions related to the creation of new threads. */

#define DEFAULT_OPTIONS     0   /* task options */
#define DEFAULT_STACK	    0x4000  /* Default stack size */


/* 
 * TIMEOUT() calculates the number of ticks for a timeout from a blockFlag
 * parameter to one of the ossLib functions.
 */

#define TIMEOUT(bf) (((bf) == OSS_BLOCK) ? \
    WAIT_FOREVER : ((bf) + msecsPerTick - 1) / msecsPerTick)

#define USB_MEM_PART_DEF_SIZE 0x10000   /* 0x10000  Default 
                                         * partition size - 64k 
                                         */

/* typedefs */

/* globals */

/* Default to using the partition method of malloc / free. */

FUNCPTR ossMallocFuncPtr;
FUNCPTR ossFreeFuncPtr;

/* locals */

LOCAL int msecsPerTick = 55;    /* milliseconds per system tick */

                    /* value updated by ossInitialize() */

LOCAL BOOL ossPartInitFlag = TRUE;

LOCAL char *pUsbMemSpace;

LOCAL PART_ID usbMemPartId;

LOCAL UINT32 usbMemPartSize = USB_MEM_PART_DEF_SIZE;

LOCAL UINT32 usbMemCount = 0;

LOCAL UINT32 ossOldInstallFlag = FALSE;

/* Functions */

/***************************************************************************
*
* translateError - translates vxWorks error to S_ossLib_xxxx
*
* Translates certain vxWorks errno values to an appropriate S_ossLib_xxxx.
* This function should only be invoked when the caller has already
* ascertained that a vxWorks function has returned an error.
*
* RETURNS: S_ossLib_xxxx
*
* ERRNO:
*  S_ossLib_BAD_HANDLE
*  S_ossLib_TIMEOUT
*  S_ossLib_GENERAL_FAULT
*/

LOCAL int
translateError (void)
{
    switch (errno) {
    case S_objLib_OBJ_ID_ERROR:
        return S_ossLib_BAD_HANDLE;
    case S_objLib_OBJ_TIMEOUT:
        return S_ossLib_TIMEOUT;
    default:
        return S_ossLib_GENERAL_FAULT;
    }
}


/***************************************************************************
*
* translatePriority - translates OSS_PRIORITY_xxx to vxWorks priority
*
* RETURNS: vxWorks task priority
*/

LOCAL int translatePriority (UINT16 priority)
{
    int curPriority;

    switch (priority) {
    case OSS_PRIORITY_LOW:
    case OSS_PRIORITY_TYPICAL:
    case OSS_PRIORITY_HIGH:
    case OSS_PRIORITY_INTERRUPT:

        return priority;

    case OSS_PRIORITY_INHERIT:
    default:

        taskPriorityGet (0, &curPriority);
        return curPriority;
    }
}


/***************************************************************************
*
* threadHead - vxWorks taskSpawn() compatible thread entry point
*
* ossThreadCreate() uses this intermediary function to spawn threads.  The
* vxWorks taskSpawn() function passes 10 int parameters to the task entry
* point.  By convention, ossThreadCreate passes the function's real entry
* point in  and the thread's  in ..
*/

LOCAL int threadHead (int arg1, /*  in this parameter */
                      int arg2, /*  in this parameter */
                      int arg3,
                      int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10)
{
    THREAD_PROTOTYPE func = (THREAD_PROTOTYPE) arg1;
    pVOID param = (pVOID) arg2;

    (*func) (param);

    return 0;
}


/***************************************************************************
*
* ossStatus - Returns OK or ERROR and sets errno based on status
*
* If  & 0xffff is not equal to zero, then sets errno to the
* indicated  and returns ERROR.  Otherwise, does not set errno
* and returns OK.
*
* RETURNS: OK or ERROR
*/

STATUS ossStatus (int status)
{
    if ((status & 0xffff) != 0) {
        errnoSet (status);
        return ERROR;
    }

    return OK;
}



/***************************************************************************
*
* ossShutdown - Shuts down ossLib
*
* This function should be called once at system shutdown if an only if
* the corresponding call to ossInitialize() was successful.
*
* RETURNS: OK or ERROR
*/

STATUS
ossShutdown (void)
{
    return OK;
}


/***************************************************************************
*
* ossThreadCreate - Spawns a new thread
*
* The ossThreadCreate() function creates a new thread which begins execution 
* with the specified .  The  argument will be passed to .  
* The ossThreadCreate() function creates the new thread with a stack of a 
* default size and with no security restrictions - that is, there are no 
* restrictions on the use of the returned  by other threads.  
* The newly created thread will execute in the same address space as the 
* calling thread.   specifies the thread's desired priority - in
* systems which implement thread priorities, as OSS_PRIORITY_xxxx.  
*
* RETURNS: OK or ERROR
*
* ERRNO:
*  S_ossLib_BAD_PARAMETER
*  S_ossLib_GENERAL_FAULT
*/

STATUS ossThreadCreate (THREAD_PROTOTYPE func,  /* function to spawn as new thread */
                        pVOID param,    /* Parameter to be passed to new thread */
                        UINT16 priority,    /* OSS_PRIORITY_xxxx */
                        pCHAR name, /* thread name or NULL */
                        pTHREAD_HANDLE pThreadHandle    /* Handle of newly spawned thread */
    )
{
    /* validate params */

    if (pThreadHandle == NULL)
        return ossStatus (S_ossLib_BAD_PARAMETER);


    /* Use vxWorks to spawn a new thread (task in vxWorks parlance). */

    if ((*pThreadHandle = (THREAD_HANDLE) taskSpawn (name,
                                                     translatePriority (priority), DEFAULT_OPTIONS,
                                                     DEFAULT_STACK, threadHead, (int) func,
                                                     (int) param, 0, 0, 0, 0, 0, 0, 0,
                                                     0)) == (THREAD_HANDLE) ERROR)
        return ossStatus (S_ossLib_GENERAL_FAULT);

    return OK;
}


/***************************************************************************
*
* ossThreadDestroy - Attempts to destroy a thread
*
* This function attempts to destroy the thread specified by .
*
* NOTE: Generally, this function should be called only after the given
* thread has terminated normally.  Destroying a running thread may result
* in a failure to release resources allocated by the thread.
*
* RETURNS: OK or ERROR
*
* ERRNO:
*  S_ossLib_GENERAL_FAULT
*/

STATUS ossThreadDestroy (THREAD_HANDLE threadHandle /* handle of thread to be destroyed */
    )
{
    if (taskDelete ((int) threadHandle) == ERROR)
        return ossStatus (S_ossLib_GENERAL_FAULT);

    return OK;
}


/***************************************************************************
*
* ossThreadSleep - Voluntarily relinquishes the CPU
*
* Threads may call ossThreadSleeph() to voluntarily release the CPU to
* another thread/process.  If the  argument is 0, then the thread will
* be reschuled for execution as soon as possible.  If the  argument is
* greater than 0, then the current thread will sleep for at least the number
* of milliseconds specified.
*
* RETURNS: OK or ERROR
*/

STATUS ossThreadSleep (UINT32 msec  /* Number of msec to sleep */
    )
{
    /* Delay for a number of ticks at least as long as the number of
       milliseconds requested by the caller. */

    taskDelay ((msec == 0) ? 0 : ((msec + msecsPerTick - 1) / msecsPerTick) + 1);

    return OK;
}


/***************************************************************************
*
* ossSemCreate - Creates a new semaphore
*
* This function creates a new semaphore and returns the handle of that
* semaphore in .  The semaphore's initial count is set to
*  and has a maximum count as specified by .
*
* RETURNS: OK or ERROR
* 
* ERRNO:
*  S_ossLib_BAD_PARAMETER
*  S_ossLib_GENERAL_FAULT
*/

STATUS ossSemCreate (UINT32 maxCount,   /* Max count allowed for semaphore */
                     UINT32 curCount,   /* initial count for semaphore */
                     pSEM_HANDLE pSemHandle /* newly created semaphore handle */
    )
{
    /* Validate parameters */

    if (pSemHandle == NULL)
        return ossStatus (S_ossLib_BAD_PARAMETER);

    if ((*pSemHandle = (SEM_HANDLE) semCCreate (SEM_Q_FIFO, curCount)) == NULL)
        return ossStatus (S_ossLib_GENERAL_FAULT);

    return OK;
}


/***************************************************************************
*
* ossSemDestroy - Destroys a semaphore
*
* Destroys the semaphore  created by ossSemCreate().
*
* RETURNS: OK or ERROR
*
* ERRNO:
*  S_ossLib_GENERAL_FAULT
*/

STATUS ossSemDestroy (SEM_HANDLE semHandle  /* Handle of semaphore to destroy */
    )
{
    if (semDelete ((SEM_ID) semHandle) != OK)
        return ossStatus (S_ossLib_GENERAL_FAULT);

    return OK;
}


/***************************************************************************
*
* ossSemGive - Signals a semaphore
*
* This function signals the sepcified semaphore.  A semaphore may have more
* than one outstanding signal, as specified by the maxCount parameter when
* the semaphore was created by ossSemCreate().	While the semaphore is at its
* maximum count, additional calls to ossSemSignal for that semaphore have no
* effect.
*
* RETURNS: OK or ERROR
*
* ERRNO:
*  S_ossLib_BAD_HANDLE
*/

STATUS ossSemGive (SEM_HANDLE semHandle /* semaphore to signal */
    )
{
    if (semGive ((SEM_ID) semHandle) != OK)
        return ossStatus (S_ossLib_BAD_HANDLE);

    return OK;
}



/***************************************************************************
*
* ossSemTake - Attempts to take a semaphore
*
* ossSemTake() attempts to "take" the semaphore specified by .
*  specifies the blocking behavior.	OSS_BLOCK blocks indefinitely
* waiting for the semaphore to be signalled.  OSS_DONT_BLOCK does not block
* and returns an error if the semaphore is not in the signalled state.	Other
* values of  are interpreted as a count of milliseconds to wait
* for the semaphore to enter the signalled state before declaring an error.
*
* RETURNS: OK or ERROR
*/

STATUS ossSemTake (SEM_HANDLE semHandle,    /* semaphore to take */
                   UINT32 blockFlag /* specifies blocking action */
    )
{
    if (semTake ((SEM_ID) semHandle, TIMEOUT (blockFlag)) != OK)
        return ossStatus (translateError ());

    return OK;
}


/***************************************************************************
*
* ossMutexCreate - Creates a new mutex
*
* This function creates a new mutex and returns the handle of that
* mutex in .  The mutex is created in the "untaken" state.
*
* RETURNS: OK or STATUS
*
* ERRNO:
*  S_ossLib_BAD_PARAMETER
*  S_ossLib_GENERAL_FAULT
*/

STATUS ossMutexCreate (pMUTEX_HANDLE pMutexHandle   /* Handle of newly created mutex */
    )
{

    /* Validate parameters */

    if (pMutexHandle == NULL)
        return ossStatus (S_ossLib_BAD_PARAMETER);

    if ((*pMutexHandle = (MUTEX_HANDLE) semMCreate (SEM_Q_FIFO)) == NULL)
        return ossStatus (S_ossLib_GENERAL_FAULT);

    return OK;
}


/***************************************************************************
*
* ossMutexDestroy - Destroys a mutex
*
* Destroys the mutex  created by ossMutexCreate().
*
* RETURNS: OK or ERROR
*
* ERRNO:
*  S_ossLib_GENERAL_FAULT
*/

STATUS ossMutexDestroy (MUTEX_HANDLE mutexHandle    /* Handle of mutex to destroy */
    )
{
    if (semDelete ((SEM_ID) mutexHandle) != OK)
        return ossStatus (S_ossLib_GENERAL_FAULT);

    return OK;
}


/***************************************************************************
*
* ossMutexTake - Attempts to take a mutex
*
* ossMutexTake() attempts to "take" the specified mutex.  The attempt will
* succeed if the mutex is not owned by any other threads.  If a thread
* attempts to take a mutex which it already owns, the attempt will succeed.
*  specifies the blocking behavior.	OSS_BLOCK blocks indefinitely
* waiting for the mutex to be released.  OSS_DONT_BLOCK does not block and
* returns an error if the mutex is not in the released state.  Other values
* of  are interpreted as a count of milliseconds to wait for the
* mutex to be released before declaring an error.
*
* RETURNS: OK or ERROR
*/

STATUS ossMutexTake (MUTEX_HANDLE mutexHandle,  /* Mutex to take */
                     UINT32 blockFlag   /* specifies blocking action */
    )
{
    if (semTake ((SEM_ID) mutexHandle, TIMEOUT (blockFlag)) != OK)
        return ossStatus (translateError ());

    return OK;
}


/***************************************************************************
*
* ossMutexRelease - Releases (gives) a mutex
*
* Release the mutex specified by .  This function will fail
* if the calling thread is not the owner of the mutex.
*
* RETURNS: OK or ERROR
*
* ERRNO:
*  S_ossLib_BAD_HANDLE
*/

STATUS ossMutexRelease (MUTEX_HANDLE mutexHandle    /* Mutex to be released */
    )
{
    if (semGive ((SEM_ID) mutexHandle) != OK)
        return ossStatus (S_ossLib_BAD_HANDLE);

    return OK;
}

/***************************************************************************
*
* ossPartSizeGet - Retrieves the size of the USB memory partition.
*
* Returns the size of the USB memory partition.  
*
* RETURNS: Size of partition.
*/

UINT32
ossPartSizeGet (void)
{

    return usbMemPartSize;

}

/***************************************************************************
*
* ossPartSizeSet - Sets the the initial size of the USB memory partition.
*
* Sets the size of the USB memory partition.  This must be called prior to 
* the first call to ossMalloc.  This will set the size that ossMalloc will
* use to do its allocation. Once ossMalloc has been called, the partition 
* size has been already allocated.  To add more memory to the USB partition, 
* you must retrieve the USB partition ID and add more memory via the 
* memPartLib routines.
*
* RETURNS: OK or ERROR
*
* SEE ALSO: memPartLib
*
*/

STATUS ossPartSizeSet (UINT32 numBytes)
{

    /* ossMalloc has already initialized the USB memory partition */

    if (ossPartInitFlag == FALSE)
        return ERROR;

    /* ossMalloc has not been called yet, so set the partition size.  */

    else
        usbMemPartSize = numBytes;

    return usbMemPartSize;

}

/***************************************************************************
*
* ossPartIdGet - Retrieves the partition ID of USB memory partition.
*
* Returns the partition ID of the USB memory partition.  
*
* RETURNS: The partition ID.
*/

PART_ID
ossPartIdGet (void)
{

    return usbMemPartId;

}

/***************************************************************************
*
* ossMemUsedGet - Retrieves amount of memory currently in use by USB.
*
* Returns the amount, in bytes, currently being used by USB.
*
* RETURNS: Number of bytes of memory in use.
*/

UINT32
ossMemUsedGet (void)
{

    return usbMemCount;

}


/***************************************************************************
*
* ossMalloc - Master USB memory allocation routine.
*
* ossMalloc() calls the malloc routine installed in the global variable
* .  These default to ossPartMalloc(), but can be changed
* by the user to their own defined malloc routine or to a non-partition
* method of malloc / free by calling ossOldInstall().
*
* RETURNS: Pointer to allocated buffer, or NULL 
*
*/

void *ossMalloc (UINT32 numBytes)
{
    return (void *) ((*ossMallocFuncPtr) (numBytes));
}

/***************************************************************************
*
* ossPartMalloc - USB memory allocation.
*
* ossPartMalloc() allocates cache-safe buffer of size  out of the USB 
* partition and returns a pointer to this buffer.  The buffer is allocated 
* from a local USB partition.  The size of this partition is defaulted to 
* 64k but can be modified to suit the users needs.  This partition will 
* dynamically grow based on additional need.  Memory allocated by this 
* function must be freed by calling ossFree().
*
* RETURNS: Pointer to allocated buffer, or NULL 
*
* INTERNAL:
*
* ossPartMalloc() is responsible for creating the USB partition.  This is 
* to allow full user control over the USB memory system.  The decision to
* put the partition creation here as opposed to ossInitialize() was because
* ossInitialize() is called from usbdInitialize().  Implementations of both
* these routines are not shipped in source.  Therefore the order in which
* ossInitialize() is called cannot be modified by users who do not have 
* source code.   Putting the partition creation in ossPartMalloc() allows
* the user to set the malloc / free pointers with a call to ossOldInstall()
* such that the partition is not created if need be.
*
*/

void *ossPartMalloc (UINT32 numBytes    /* Size of buffer to allocate */
    )
{
    void *pBfr;
    void *pMoreMemory;
    UINT32 growSize;

    /*  Create the USB memory partition from cache safe memory */

    if (ossPartInitFlag == TRUE) {

        /* on the first pass create 64k chunk of cache safe memory for usb */

        pUsbMemSpace = (char *) cacheDmaMalloc (usbMemPartSize);

        if (pUsbMemSpace == NULL) {
            printf ("ossLib.c: unable to allocate USB memory space.\n");
            return NULL;
        }

        /* make this chunk a partition */

        usbMemPartId = memPartCreate (pUsbMemSpace, usbMemPartSize);

        if (usbMemPartId == NULL) {
            printf ("ossLib.c: unable to create USB memory partition.\n");
            return NULL;
        }

        ossPartInitFlag = FALSE;

    }

    /* 
     * If this call to ossMalloc is going to allocate more memory than is 
     * available in the partition, then grow the partition by 8k, or if
     * numBytes is larger than 4k, then grow the partition by numBytes + 4k.
     */

    if ((usbMemCount + numBytes) > (usbMemPartSize - 0x1000)) {

        growSize = 0x2000;

        if (numBytes > 0x1000)
            growSize += numBytes;

        pMoreMemory = cacheDmaMalloc (growSize);

        if (pMoreMemory == NULL) {
            printf ("ossLib.c: ossPartMalloc could not cacheDmaMalloc() new" " memory.\n");
            return NULL;
        }

        if (memPartAddToPool (usbMemPartId, pMoreMemory, growSize) == ERROR) {
            printf ("ossLib.c: ossPartMalloc could not add new memory to" " pool.\n");
            return NULL;
        }

        usbMemPartSize += growSize;
    }

    /* From now on, use this partition for all USB mallocs */

    pBfr = memPartAlignedAlloc (usbMemPartId,
                                ROUND_UP (numBytes, _CACHE_ALIGN_SIZE), _CACHE_ALIGN_SIZE);

    if (pBfr == NULL) {
        printf ("ossLib.c: unable to malloc USB memory.\n");
        return NULL;
    }

    /* Update the amount of memory USB is currently using. */

    usbMemCount += ROUND_UP (numBytes, _CACHE_ALIGN_SIZE);

    return pBfr;

}

/***************************************************************************
*
* ossOldMalloc - Global memory allocation
*
* ossOldMalloc() allocates a buffer of  in length and returns a
* pointer to the allocated buffer.  The buffer i allocated from a global
* pool which can be made visible to all processes or drivers in the
* system.  Memory allocated by this function must be freed by calling
* ossFree().
*
* RETURNS: Pointer to allocated buffer, or NULL
*
*/

void *ossOldMalloc (UINT32 numBytes /* Size of buffer to allocate */
    )
{
#ifdef  FILL_MEMORY
    pVOID pBfr = memalign (_CACHE_ALIGN_SIZE,
                           ROUND_UP (numBytes, _CACHE_ALIGN_SIZE));

    memset (pBfr, 0xdd, numBytes);
    return pBfr;
#else
    return memalign (_CACHE_ALIGN_SIZE, ROUND_UP (numBytes, _CACHE_ALIGN_SIZE));
#endif
}

/***************************************************************************
*
* ossCalloc - Allocates memory initialized to zeros
*
* ossCalloc() uses ossMalloc() to allocate a block of memory and then
* initializes it to zeros.  Memory allocated using this function should
* be freed using ossFree().
*
* RETURNS: Pointer to allocated buffer, or NULL. 
*
*/

pVOID ossCalloc (UINT32 numBytes    /* size of buffer to allocate */
    )
{
    pVOID mem;

    if ((mem = ossMalloc (numBytes)) == NULL)
        return NULL;

    memset (mem, 0, numBytes);
    return mem;
}


/***************************************************************************
*
* ossFree - Master USB memory free routine.
*
* ossFree() calls the free routine installed in the global variable
* .  This defaults to ossPartFree(), but can be changed
* by the user to their own defined free routine or to a non-partition
* method of malloc / free by calling ossOldInstall().
*
* RETURNS: N/A
*/

void ossFree (pVOID bfr)
{

    (*ossFreeFuncPtr) (bfr);

}

/***************************************************************************
*
* ossPartFree - Frees globally allocated memory
*
* ossPartFree() frees memory allocated by ossMalloc().
*
* RETURNS: N/A
*/

void ossPartFree (pVOID bfr)
{
    if (bfr != NULL) {
        if (usbMemPartId == NULL) {
            printf ("ossFree: usbMemPartId is NULL.\n");
            return;
        }

        memPartFree (usbMemPartId, bfr);

        /* Update the amount of USB memory in use. */

        usbMemCount -= sizeof (bfr);

    }
}

/***************************************************************************
*
* ossOldFree - Frees globally allocated memory
*
* ossOldFree() frees memory allocated by ossMalloc().
*
* RETURNS: N/A
*/

void ossOldFree (void *bfr)
{
    if (bfr != NULL)
        free (bfr);
}

/***************************************************************************
*
* ossOldInstall - Installs old method of USB malloc and free. 
*
* Installs old method of USB malloc and free.  This must be called before
* the call to usbdInitialize().
*
* RETURNS: N/A
*/

void
ossOldInstall (void)
{

    ossMallocFuncPtr = (FUNCPTR) & ossOldMalloc;
    ossFreeFuncPtr = (FUNCPTR) & ossOldFree;

    ossOldInstallFlag = TRUE;

}

/***************************************************************************
*
* ossTime - Returns relative system time in msec
*
* Returns a count of milliseconds relative to the time the system was
* started.
*
* NOTE: The time will wrap approximately every 49 days, so time calucations
* should always be based on the difference between two time values.
*/

UINT32
ossTime (void)
{
    return tickGet () * msecsPerTick;
}


/***************************************************************************
*
* ossInitialize - Initializes ossLib
*
* This function should be called once at initialization in order
* to initialize the ossLib.  Calls to this function may be
* nested.  This permits multiple, indpendent libraries to use this library
* without need to coordinate the use of ossInitialize() and ossShutdown()
* across the libraries.
*
* RETURNS: OK or ERROR
*/

STATUS
ossInitialize (void)
{

    /* Get the system clock rate...used by ossThreadSleep */

    msecsPerTick = 1000 / sysClkRateGet ();

    /*  Default to using the partition method of malloc / free. */

    if (!ossOldInstallFlag) {
        ossMallocFuncPtr = (FUNCPTR) & ossPartMalloc;
        ossFreeFuncPtr = (FUNCPTR) & ossPartFree;
    }

    return OK;
}

/* End of file. */