======== driver.c ======== .. code-block:: 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; }