?? device.c
字號:
/* File: device.c
*
* Purpose: WinCE device manager
*
* Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved.
*/
//
// This module contains these functions:
// FS_RegisterDevice
// RegisterDeviceEx
// DoFreeFSD
// DoFreeDevice
// WaitForFSDs
// NotifyFSDs
// IsValidDevice
// FS_DeregisterDevice
// FS_ActivateDevice
// FindActiveByHandle
// FS_DeactivateDevice
// GetFSD
// FormatDeviceName
// LoadFSDThread
// FS_LoadFSD
// FS_LoadFSDEx
// FS_CeResyncFilesys
// FS_PowerAllDevices
// FS_GetDeviceByIndex
// FS_CreateDeviceHandle
// FS_DevCloseFileHandle
// FS_DevReadFile
// FS_DevWriteFile
// FS_DevSetFilePointer
// FS_DevDeviceIoControl
// FS_DevGetFileSize
// FS_DevGetFileInformation
// FS_DevFlushFileBuffers
// FS_DevGetFileTime
// FS_DevSetFileTime
// FS_DevSetEndOfFile
// FS_DevProcNotify
// FS_CloseAllDeviceHandles
// WinMain
//
#include <device.h>
#include <devload.h>
#include <devloadp.h>
#include <cardserv.h>
#include <console.h>
#ifdef TARGET_NT
#include <devemul.h>
#include "proxy.h"
#endif
#ifdef INSTRUM_DEV
#include <instrumd.h>
#else
#define ENTER_INSTRUM
#define EXIT_INSTRUM_INIT
#define EXIT_INSTRUM_DEINIT
#define EXIT_INSTRUM_POWERDOWN
#define EXIT_INSTRUM_POWERUP
#define EXIT_INSTRUM_OPEN
#define EXIT_INSTRUM_CLOSE
#define EXIT_INSTRUM_READ
#define EXIT_INSTRUM_WRITE
#define EXIT_INSTRUM_SEEK
#define EXIT_INSTRUM_IOCONTROL
#endif // INSTRUM_DEV
/* Device driver implementation */
// @doc EXTERNAL OSDEVICE KERNEL
// @module device.c - device driver support | Device driver support functions.
// @topic WinCE Device Drivers | There are two types of device drivers. The
// first type are specialized drivers. These are keyboard, mouse/touch screen,
// and display drivers. These drivers have specialized interfaces. The other
// type of driver is the stream based device driver model. Drivers following the
// stream based model will need to export several functions and be initialized
// before they can be used. They can be accessed through standard file APIs such
// as OpenFile. The driver dll must export a set of entrypoints of the form
// ttt_api, where ttt is the device id passed in lpszType to RegisterDevice, and
// api is a required or optional API. The APIs required are: Init, Deinit, Open,
// Close, Read, Write, Seek, and IOCtl.
// Drivers which need interrupts can use kernel exported interrupt support
// routines. To understand the interrupt model and functions please look at
// <l Interrupt Support.Kernel Interrupt Support>
// @xref <f RegisterDevice> <f DeregisterDevice>
// <l Interrupt Support.Kernel Interrupt Support>
// notes on handling of unloading of dlls while threads are in those dlls:
// 1> routines which take the device critical section before calling into a dll do not need to
// adjust the reference count since the deregister call takes the critical section
// 2> routines which do not take the device critical section do the following:
// a> check if the device is still valid [ if (fsodev->lpDev) ]
// b> if so, increment the reference count, so dodec = 1, make call, decrement the reference count,
// set dodec = 0
// c> we assume we will not fault in the interlockedDecrement, since once we've succeeded in the
// increment, we know we won't fault on the decrement since nobody will be LocalFree'ing the device
// d> if we fault inside the actual function call, we'll do the decrement due to the dodec flag
// 3> We signal an event when we put someone on the DyingDevs list. We can just poll from that point onwards
// since (1) it's a rare case and (2) it's cheaper than always doing a SetEvent if you decrement the
// reference count to 0.
CRITICAL_SECTION g_devcs;
LIST_ENTRY g_DevChain;
LIST_ENTRY g_DyingDevs;
fsopendev_t *g_lpOpenDevs;
fsopendev_t *g_lpDyingOpens;
HANDLE g_hDevApiHandle, g_hDevFileApiHandle, g_hCleanEvt, g_hCleanDoneEvt;
fsd_t *g_lpFSDChain;
//
// Devload.c and pcmcia.c
//
typedef DWORD (*SYSTEMPOWER)(DWORD);
extern SYSTEMPOWER pfnSystemPower;
extern void DevloadInit(void);
extern void DevloadPostInit(void);
extern BOOL I_DeactivateDevice(HANDLE hDevice, LPWSTR ActivePath);
extern HANDLE StartOneDriver(LPTSTR RegPath, LPTSTR PnpId,
DWORD LoadOrder, DWORD ClientInfo, CARD_SOCKET_HANDLE hSock);
#ifndef TARGET_NT
const PFNVOID FDevApiMethods[] = {
(PFNVOID)FS_DevProcNotify,
(PFNVOID)0,
(PFNVOID)FS_RegisterDevice,
(PFNVOID)FS_DeregisterDevice,
(PFNVOID)FS_CloseAllDeviceHandles,
(PFNVOID)FS_CreateDeviceHandle,
(PFNVOID)FS_LoadFSD,
(PFNVOID)FS_ActivateDevice,
(PFNVOID)FS_DeactivateDevice,
(PFNVOID)FS_LoadFSDEx,
(PFNVOID)FS_GetDeviceByIndex,
(PFNVOID)FS_CeResyncFilesys,
};
#define NUM_FDEV_APIS (sizeof(FDevApiMethods)/sizeof(FDevApiMethods[0]))
const DWORD FDevApiSigs[NUM_FDEV_APIS] = {
FNSIG3(DW, DW, DW), // ProcNotify
FNSIG0(),
FNSIG4(PTR, DW, PTR, DW), // RegisterDevice
FNSIG1(DW), // DeregisterDevice
FNSIG0(), // CloseAllDeviceHandles
FNSIG4(PTR, DW, DW, DW), // CreateDeviceHandle
FNSIG2(PTR, PTR), // LoadFSD
FNSIG2(PTR, DW), // ActivateDevice
FNSIG1(DW), // DeactivateDevice
FNSIG3(PTR, PTR, DW), //LoadFSDEx
FNSIG2(DW, PTR), // GetDeviceByIndex
FNSIG1(DW), // CeResyncFilesys
};
const PFNVOID DevFileApiMethods[] = {
(PFNVOID)FS_DevCloseFileHandle,
(PFNVOID)0,
(PFNVOID)FS_DevReadFile,
(PFNVOID)FS_DevWriteFile,
(PFNVOID)FS_DevGetFileSize,
(PFNVOID)FS_DevSetFilePointer,
(PFNVOID)FS_DevGetFileInformationByHandle,
(PFNVOID)FS_DevFlushFileBuffers,
(PFNVOID)FS_DevGetFileTime,
(PFNVOID)FS_DevSetFileTime,
(PFNVOID)FS_DevSetEndOfFile,
(PFNVOID)FS_DevDeviceIoControl,
};
#define NUM_FAPIS (sizeof(DevFileApiMethods)/sizeof(DevFileApiMethods[0]))
const DWORD DevFileApiSigs[NUM_FAPIS] = {
FNSIG1(DW), // CloseFileHandle
FNSIG0(),
FNSIG5(DW,PTR,DW,PTR,PTR), // ReadFile
FNSIG5(DW,PTR,DW,PTR,PTR), // WriteFile
FNSIG2(DW,PTR), // GetFileSize
FNSIG4(DW,DW,PTR,DW), // SetFilePointer
FNSIG2(DW,PTR), // GetFileInformationByHandle
FNSIG1(DW), // FlushFileBuffers
FNSIG4(DW,PTR,PTR,PTR), // GetFileTime
FNSIG4(DW,PTR,PTR,PTR), // SetFileTime
FNSIG1(DW), // SetEndOfFile,
FNSIG8(DW, DW, PTR, DW, PTR, DW, PTR, PTR), // DeviceIoControl
};
#endif // TARGET_NT
PFNVOID FS_GetProcAddr(LPCWSTR type, LPCWSTR lpszName, HINSTANCE hInst) {
WCHAR fullname[32];
memcpy(fullname,type,3*sizeof(WCHAR));
fullname[3] = L'_';
wcscpy(&fullname[4],lpszName);
return (PFNVOID)GetProcAddress(hInst,fullname);
}
// @func HANDLE | RegisterDevice | Register a new device
// @parm LPCWSTR | lpszType | device id (SER, PAR, AUD, etc) - must be 3 characters long
// @parm DWORD | dwIndex | index between 0 and 9, ie: COM2 would be 2
// @parm LPCWSTR | lpszLib | dll containing driver code
// @parm DWORD | dwInfo | instance information
// @rdesc Returns a handle to a device, or 0 for failure. This handle should
// only be passed to DeregisterDevice.
// @comm For stream based devices, the drivers will be .dll or .drv files.
// Each driver is initialized by
// a call to the RegisterDevice API (performed by the server process).
// The lpszLib parameter is what will be to open the device. The
// lpszType is a three character string which is used to identify the
// function entry points in the DLL, so that multiple devices can exist
// in one DLL. The lpszLib is the name of the DLL which contains the
// entry points. Finally, dwInfo is passed in to the init routine. So,
// if there were two serial ports on a device, and comm.dll was the DLL
// implementing the serial driver, it would be likely that there would be
// the following init calls:<nl>
// <tab>h1 = RegisterDevice(L"COM", 1, L"comm.dll",0x3f8);<nl>
// <tab>h2 = RegisterDevice(L"COM", 2, L"comm.dll",0x378);<nl>
// Most likely, the server process will read this information out of a
// table or registry in order to initialize all devices at startup time.
// @xref <f DeregisterDevice> <l Overview.WinCE Device Drivers>
//
HANDLE
FS_RegisterDevice(
LPCWSTR lpszType,
DWORD dwIndex,
LPCWSTR lpszLib,
DWORD dwInfo
)
{
return RegisterDeviceEx(
lpszType,
dwIndex,
lpszLib,
dwInfo,
MAX_LOAD_ORDER+1
);
}
HANDLE
RegisterDeviceEx(
LPCWSTR lpszType,
DWORD dwIndex,
LPCWSTR lpszLib,
DWORD dwInfo,
DWORD dwLoadOrder
)
{
HANDLE hDev = 0;
fsdev_t *lpdev = 0, *lpTrav;
DWORD retval = 0;
DEBUGMSG(ZONE_DYING, (TEXT("DEVICE: About to wait on CleanDoneEvt.\r\n")));
// Need to wait for any filesystem devices to finish getting deregistered
// before we go ahead and register them again. This gets around problems
// with storage card naming.
retval = WaitForSingleObject(g_hCleanDoneEvt, 5000);
DEBUGMSG(ZONE_DYING, (TEXT("DEVICE: Got CleanDoneEvt.\r\n")));
ASSERT(retval != WAIT_TIMEOUT);
retval = ERROR_SUCCESS; // Initialize for success
if (dwIndex > 9) {
retval = ERROR_INVALID_PARAMETER;
goto errret;
}
if (!(lpdev = LocalAlloc(LPTR,sizeof(fsdev_t)))) {
retval = ERROR_OUTOFMEMORY;
goto errret;
}
__try {
memset(lpdev, 0, sizeof(fsdev_t));
memcpy(lpdev->type,lpszType,sizeof(lpdev->type));
lpdev->index = dwIndex;
if (!(lpdev->hLib = LoadDriver(lpszLib))) {
retval = ERROR_FILE_NOT_FOUND;
} else {
if (!(lpdev->fnInit = (pInitFn)FS_GetProcAddr(lpdev->type,L"Init",lpdev->hLib)) ||
!(lpdev->fnDeinit = (pDeinitFn)FS_GetProcAddr(lpdev->type,L"Deinit",lpdev->hLib)) ||
!(lpdev->fnOpen = (pOpenFn)FS_GetProcAddr(lpdev->type,L"Open",lpdev->hLib)) ||
!(lpdev->fnClose = (pCloseFn)FS_GetProcAddr(lpdev->type,L"Close",lpdev->hLib)) ||
!(lpdev->fnRead = (pReadFn)FS_GetProcAddr(lpdev->type,L"Read",lpdev->hLib)) ||
!(lpdev->fnWrite = (pWriteFn)FS_GetProcAddr(lpdev->type,L"Write",lpdev->hLib)) ||
!(lpdev->fnSeek = (pSeekFn)FS_GetProcAddr(lpdev->type,L"Seek",lpdev->hLib)) ||
!(lpdev->fnControl = (pControlFn)FS_GetProcAddr(lpdev->type,L"IOControl",lpdev->hLib))) {
retval = ERROR_INVALID_FUNCTION;
} else {
// Got all the required functions. Now let's get the optional ones
lpdev->fnPowerup = (pPowerupFn)FS_GetProcAddr(lpdev->type,L"PowerUp",lpdev->hLib);
lpdev->fnPowerdn = (pPowerupFn)FS_GetProcAddr(lpdev->type,L"PowerDown",lpdev->hLib);
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
retval = ERROR_INVALID_PARAMETER;
}
if (retval) {
goto errret;
}
// Now enter the critical section to look for it in the device list
EnterCriticalSection (&g_devcs);
__try {
//
// check for uniqueness
//
for (lpTrav = (fsdev_t *)g_DevChain.Flink;
lpTrav != (fsdev_t *)&g_DevChain;
lpTrav = (fsdev_t *)(lpTrav->list.Flink)) {
if (!memcmp(lpTrav->type,lpdev->type,sizeof(lpdev->type)) &&
(lpTrav->index == lpdev->index)) {
retval = ERROR_DEVICE_IN_USE;
break;
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
retval = ERROR_INVALID_PARAMETER;
}
LeaveCriticalSection(&g_devcs);
if (retval) {
goto errret;
}
__try {
ENTER_INSTRUM {
lpdev->dwData = lpdev->fnInit(dwInfo);
} EXIT_INSTRUM_INIT;
if (!(lpdev->dwData)) {
retval = ERROR_OPEN_FAILED;
} else {
// Sucess
lpdev->PwrOn = TRUE;
lpdev->dwLoadOrder = dwLoadOrder;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
retval = ERROR_INVALID_PARAMETER;
}
if (retval) {
goto errret;
}
EnterCriticalSection(&g_devcs);
__try {
//
// Insert according to LoadOrder
//
for (lpTrav = (fsdev_t *)g_DevChain.Flink;
lpTrav != (fsdev_t *)&g_DevChain;
lpTrav = (fsdev_t *)(lpTrav->list.Flink)) {
if (lpTrav->dwLoadOrder >= dwLoadOrder) {
InsertHeadList((PLIST_ENTRY)lpTrav, (PLIST_ENTRY)lpdev);
break;
}
}
if (lpTrav == (fsdev_t *)&g_DevChain) {
// insert at the end
InsertTailList(&g_DevChain, (PLIST_ENTRY)lpdev);
}
hDev = (HANDLE)lpdev;
} __except (EXCEPTION_EXECUTE_HANDLER) {
retval = ERROR_INVALID_PARAMETER;
}
LeaveCriticalSection(&g_devcs);
errret:
#ifdef DEBUG
if (ZONE_ACTIVE) {
if (hDev != NULL) {
DEBUGMSG(ZONE_ACTIVE, (TEXT("DEVICE: Name Load Order\r\n")));
//
// Display the list of devices in ascending load order.
//
EnterCriticalSection(&g_devcs);
for (lpTrav = (fsdev_t *)g_DevChain.Flink;
lpTrav != (fsdev_t *)&g_DevChain;
lpTrav = (fsdev_t *)(lpTrav->list.Flink)) {
DEBUGMSG(ZONE_ACTIVE, (TEXT("DEVICE: %c%c%c%d: %d\r\n"),
lpTrav->type[0], lpTrav->type[1], lpTrav->type[2],
lpTrav->index, lpTrav->dwLoadOrder));
}
LeaveCriticalSection(&g_devcs);
}
}
#endif
// If we failed then let's clean up the module and data
if (retval) {
SetLastError (retval);
if (lpdev) {
if (lpdev->hLib) {
FreeLibrary(lpdev->hLib);
}
LocalFree (lpdev);
}
}
return hDev;
}
void DoFreeFSD(pfsd_t pfsd)
{
pfsd_t pfsd1;
if (pfsd->cFSDDevices <= 0) {
FreeLibrary(pfsd->hFSDLib);
if (pfsd == g_lpFSDChain) {
g_lpFSDChain = pfsd->next;
LocalFree(pfsd);
return;
} else {
pfsd1 = g_lpFSDChain;
while (pfsd1) {
if (pfsd1->next == pfsd) {
pfsd1->next = pfsd->next;
LocalFree(pfsd);
return;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -