driver.cΒΆ

/*
 driver.c
 Main file for driver model
 This is an example of extending an operating system, in this case UCOS 2.85,
 to include simply driver model.
 Paul Lever
 May 01,2001

 Feb. 26,2003 PDL
 Fixed and improved error checking in the Open() function
 Added checks for invalid handle
 Oct. 13, 2003
 Add additional error checks for calls to non-existent functions.
 Placed in with DEBUG for execution speed.
 Oct. 22, 2003 DMI
 Made changes within DEBUG to fix compiler errors:
 1) OSDRV_pDriverTable index
 2) return values for some functions are INT8U, fixed return values.
 3) commented out #define DEBUG 1 and forgot to uncomment it... reverted to default #define DEBUG 1.
 Aug. 16, 2004 PDL
 Change the way the sempahore is freeded in the Close operation and use #defined memory allocate.
 Dec. 2007  PDL - updated for 2.85

 */

#include "includes.h"  // OS includes
#include "driver.h"

/* is driver subsystem initialized? Save the number of drivers in table and the table*/
static INT8U OSDRV_DriverCount = 0;
static POSDRV_DRIVER_ENTRY OSDRV_pDriverTable = NULL;

/*
 OSDRV_SubsysInit - initialize the driver subsystem
 pDriverTable - table of drivers to be initialized
 Count        - number of entries in pDriverTable
 return - status

 Notes: OSDRV_Init must be called prior to using any driver
 */
INT8U OSDRV_SubsysInit(POSDRV_DRIVER_ENTRY pDriverTable, INT8U Count)
{
    INT8U status;

    // save the tables
    OSDRV_DriverCount = Count;
    OSDRV_pDriverTable = pDriverTable;

    // initialize each driver in the system
    for (; Count > 0; Count--)
    {
            if (pDriverTable[Count - 1].Dispatch.pInit != NULL)
            {
                    // call the drivers initialization routine
                    status = pDriverTable[Count - 1].Dispatch.pInit(
                                                                    &(pDriverTable[Count - 1].Dispatch),
                                                                    &(pDriverTable[Count - 1].pContext),
                                                                    &(pDriverTable[Count - 1].Config));

                    // save initialization status of driver
                    if (status == OS_DRV_NO_ERR)
                    {
                            pDriverTable[Count - 1].Initialized = TRUE;
                    }
                    else
                    {
                            pDriverTable[Count - 1].Initialized = FALSE;
                    }
            }
    }

    DEBUGMSG(TRUE, ("OSDRV:SubsysInit Initialized %d driver(s)\n\r", OSDRV_DriverCount));
    return OS_DRV_NO_ERR;
}

/*
 Application interface functions
 */
/*
 Open - open a handle to a driver
 */
HANDLE Open(char *pName, INT8U Flags)
{
    INT8U count;
    POSDRV_NAME pNameItem;
    INT8U index;
    INT8U err;
    POSDRV_HANDLE_INTERNAL pHandle;

    // first find the name of the device by walking the list of
    // drivers and registered names
    // for each driver
    for (count = 0; count < OSDRV_DriverCount; count++)
    {
            // walk the names list of this driver, tracking the index number
            for (index = 0, pNameItem = &OSDRV_pDriverTable[count].Config.Name; pNameItem
                            != NULL; pNameItem = pNameItem->pNext, index++)
            {
                    if (strcmp(pNameItem->pName, pName) == 0)
                    {
                            // we have a match
                            // call the drivers open
#ifdef DEBUG
                            if (OSDRV_pDriverTable[count].Dispatch.pOpen == NULL)
                            {
                                    // driver has no open
                                    DEBUGMSG(TRUE, ("OSDRV:Open open not supported: driver %s, error: %d\n\r", pName, OS_DRV_UNSUPPORTED));
                                    return (HANDLE)OS_DRV_UNSUPPORTED;
                            }
#endif //DEBUG
                            err = OSDRV_pDriverTable[count].Dispatch.pOpen(index,
                                            OSDRV_pDriverTable[count].pContext, Flags);

                            if (err != OS_DRV_NO_ERR)
                            {
                                    // driver failed open, tell user
                                    DEBUGMSG(TRUE, ("OSDRV:Open Failed to open driver %s, error: %d\n\r", pName, err));
                                    return (HANDLE) OS_DRV_INVALID_HANDLE;
                            }

                            // allocate the Handle for this open
                            pHandle = DRV_MEMALLOC(sizeof(OSDRV_HANDLE_INTERNAL));
                            if (pHandle == NULL)
                            {
                                    DEBUGMSG(TRUE, ("OSDRV:Open Could not obtain handle for driver %s\n\r", pName));
                                    return (HANDLE) OS_DRV_INVALID_HANDLE;
                            }

                            // initialize the handle
                            pHandle->DrvIndex = count;
                            pHandle->DevIndex = index;
                            pHandle->RefCount = 1;

                            // only allocate a semaphore if this device requested exclusive access
                            if (OSDRV_pDriverTable[pHandle->DrvIndex].Config.Exclusive)
                            {
                                    pHandle->Event = OSSemCreate(1);
                                    if (pHandle->Event == NULL)
                                    {
                                            DEBUGMSG(TRUE, ("OSDRV:Open Could not create semphore for driver %s\n\r", pName));
                                            DRV_MEMFREE(pHandle);
                                            return (HANDLE) OS_DRV_INVALID_HANDLE;
                                    }
                            }
                            else
                            {
                                    pHandle->Event = NULL;
                            }
                            // give handle to user
                            return ((HANDLE) pHandle);
                    }
            }
    }
    // not found
    DEBUGMSG(TRUE, ("OSDRV:Open Could not find driver %s\n\r", pName));
    return (HANDLE) OS_DRV_INVALID_HANDLE;
}

/*
 Close - close a handle to a driver
 */
INT8U Close(HANDLE H)
{
    INT8U err;
    INT8U errsem;

    // check for invalid handle
    if (H == OS_DRV_INVALID_HANDLE)
    {
            DEBUGMSG(TRUE, ("OSDRV:Close Invalid handle\n\r"));
            return OS_DRV_NO_DEVICE;
    }
    // check for serialization
    if (OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].Config.Exclusive)
    {
            // serialize
            OSSemPend(((POSDRV_HANDLE_INTERNAL) H)->Event, 0, &errsem);
    }
#ifdef DEBUG
    if (OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL)H)->DrvIndex].Dispatch.pClose == NULL)
    {
            // driver has no close
            DEBUGMSG(TRUE, ("OSDRV:Close close not supported, error: %d\n\r", OS_DRV_UNSUPPORTED));
            return OS_DRV_UNSUPPORTED;
    }
#endif //DEBUG
    // call the drivers close
    err
                    = OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].Dispatch.pClose(
                                                                    ((POSDRV_HANDLE_INTERNAL) H)->DevIndex,
                                                                    OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].pContext);

    // undo serialization
    if (OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].Config.Exclusive)
    {
            /* ?? do you see any holes in the approach below of deleting the sempahore? How would you get around these problems? ??*/
#ifdef DEBUG
            // delete the semaphore if it is not in use
            ((POSDRV_HANDLE_INTERNAL)H)->Event = OSSemDel(((POSDRV_HANDLE_INTERNAL)H)->Event, OS_DEL_NO_PEND, &errsem);
            if (errsem != OS_NO_ERR)
            {
                    //error deleting sempahore, see if another task is waiting on the semaphore
                    if (errsem == OS_ERR_TASK_WAITING)
                    {
                            //an application tried to close the device while one of its threads was waiting on the semaphore
                            DEBUGMSG(TRUE, ("OSDRV:Close attemp to close device while task is waiting on I/O request serialization.\n\r"));
                    }
                    // delete the semaphore. If anyone is waiting on it, they will be readied.
                    ((POSDRV_HANDLE_INTERNAL)H)->Event = OSSemDel(((POSDRV_HANDLE_INTERNAL)H)->Event, OS_DEL_ALWAYS, &errsem);
            }
#else  //DEBUG
            // delete the semaphore. If anyone is waiting on it, they will be readied.
            ((POSDRV_HANDLE_INTERNAL) H)->Event = OSSemDel(((POSDRV_HANDLE_INTERNAL) H)->Event,
                                                                                                            OS_DEL_ALWAYS, &errsem);
#endif //DEBUG
    }
    // free up the handle
    DRV_MEMFREE((POSDRV_HANDLE_INTERNAL)H);

    return err;
}

/*
 Read - read a buffer from the driver
 */
INT8U Read(HANDLE H, PVOID pBuffer, INT32U* pLength)
{
    INT8U err;
    INT8U errsem;

    // check for invalid handle
    if (H == OS_DRV_INVALID_HANDLE)
    {
            DEBUGMSG(TRUE, ("OSDRV:Read Invalid handle\n\r"));
            return OS_DRV_NO_DEVICE;
    }
    // check for serialization
    if (OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].Config.Exclusive)
    {
            // serialize
            OSSemPend(((POSDRV_HANDLE_INTERNAL) H)->Event, 0, &errsem);
    }
#ifdef DEBUG
    if (OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL)H)->DrvIndex].Dispatch.pRead == NULL)
    {
            // driver has no close
            DEBUGMSG(TRUE, ("OSDRV:Read read not supported, error: %d\n\r", OS_DRV_UNSUPPORTED));
            return OS_DRV_UNSUPPORTED;
    }
#endif //DEBUG
    // call the drivers close
    err     = OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].Dispatch.pRead(
                                                                    ((POSDRV_HANDLE_INTERNAL) H)->DevIndex,
                                                                    OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].pContext,
                                                                    pBuffer, pLength);

    // undo serialization
    if (OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].Config.Exclusive)
    {
            // serialize
            errsem = OSSemPost(((POSDRV_HANDLE_INTERNAL) H)->Event);
    }

    return err;
}

/*
 Write - wead a buffer to the driver
 */
INT8U Write(HANDLE H, PVOID pBuffer, INT32U* pLength)
{
    INT8U err;
    INT8U errsem;

    // check for invalid handle
    if (H == OS_DRV_INVALID_HANDLE)
    {
            DEBUGMSG(TRUE, ("OSDRV:Write Invalid handle\n\r"));
            return OS_DRV_NO_DEVICE;
    }
    // check for serialization
    if (OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].Config.Exclusive)
    {
            // serialize
            OSSemPend(((POSDRV_HANDLE_INTERNAL) H)->Event, 0, &errsem);
    }
#ifdef DEBUG
    if (OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL)H)->DrvIndex].Dispatch.pWrite == NULL)
    {
            // driver has no write
            DEBUGMSG(TRUE, ("OSDRV:Write write not supported, error: %d\n\r", OS_DRV_UNSUPPORTED));
            return OS_DRV_UNSUPPORTED;
    }
#endif //DEBUG
    // call the drivers write
    err     = OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].Dispatch.pWrite(
                                                            ((POSDRV_HANDLE_INTERNAL) H)->DevIndex,
                                                            OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].pContext,
                                                            pBuffer, pLength);

    // undo serialization
    if (OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].Config.Exclusive)
    {
            // serialize
            errsem = OSSemPost(((POSDRV_HANDLE_INTERNAL) H)->Event);
    }

    return err;
}

/*
 Ioctl - IOCTL to the driver
 */
INT8U Ioctl(HANDLE H, INT8U Control, PVOID pBuffer, INT32U* pLength)
{
    INT8U err;
    INT8U errsem;

    // check for invalid handle
    if (H == OS_DRV_INVALID_HANDLE)
    {
            DEBUGMSG(TRUE, ("OSDRV:Ioctl Invalid handle\n\r"));
            return OS_DRV_NO_DEVICE;
    }
    // check for serialization
    if (OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].Config.Exclusive)
    {
            // serialize
            OSSemPend(((POSDRV_HANDLE_INTERNAL) H)->Event, 0, &errsem);
    }
#ifdef DEBUG
    if (OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL)H)->DrvIndex].Dispatch.pIoctl == NULL)
    {
            // driver has no close
            DEBUGMSG(TRUE, ("OSDRV:Ioctl ioctl not supported, error: %d\n\r", OS_DRV_UNSUPPORTED));
            return OS_DRV_UNSUPPORTED;
    }
#endif //DEBUG
    // call the drivers close
    err     = OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].Dispatch.pIoctl(
                                                            ((POSDRV_HANDLE_INTERNAL) H)->DevIndex,
                                                            OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].pContext,
                                                            Control, pBuffer, pLength);

    // undo serialization
    if (OSDRV_pDriverTable[((POSDRV_HANDLE_INTERNAL) H)->DrvIndex].Config.Exclusive)
    {
            // serialize
            errsem = OSSemPost(((POSDRV_HANDLE_INTERNAL) H)->Event);
    }

    return err;
}

/*
 Utility Functions
 */
/*
 OSDRV_AddName - utility function to add device name to devices supported list of devices
 */
INT8U OSDRV_AddName(POSDRV_CONFIG pConfig, char * pName)
{
    POSDRV_NAME pNextItem;

    // find first empty list entry
    for (pNextItem = &pConfig->Name; (pNextItem->pNext != NULL)
                    && (pNextItem->pName != NULL); pNextItem = pNextItem->pNext)
    {
            ; // nothing to do
    }

    if ((pNextItem->pNext == NULL) && (pNextItem->pName != NULL))
    {
            // name in use, allocate the next buffer
            // allocate a buffer the next entry and initialize
            pNextItem->pNext = DRV_MEMALLOC(sizeof(OSDRV_CONFIG));
            pNextItem = pNextItem->pNext;
            if (pNextItem == NULL)
            {
                    return OS_DRV_BUFFER_SIZE; // no memory available
            }
            pNextItem->pNext = NULL;
    }

    // allocate a buffer for the name, saving space for our prefix
    pNextItem->pName = DRV_MEMALLOC(strlen(pName) + strlen("\\dev\\") + 1);

    // copy and concatinate the name
    // the name ends up as \dev\devname
    strcpy(pNextItem->pName, "\\dev\\");
    strcat(pNextItem->pName, pName);

    return OS_DRV_NO_ERR;
}

Previous topic

driver.h

Next topic

drv_mp3.h

This Page