向应用程序提供Flash读写接口

网上有一篇文章,介绍应用程序如何操作flash的:

http://blog.csdn.net/nanjianhui/archive/2008/03/19/2196466.aspx

按照上述文章的做法做好之后,在非multi-bin的系统下,CreateFile(_T("DSK0:"),...)是没有任何问题的,但是如果是在multi-bin的系统下,则得不到句柄,经过大量的实验方法得知,在multi-bin系统下,用hFlash = OpenStore(L"MSFlash");方能打开,这是什么原因呢?

查看MSDN得知,OpenStore是微软提供的一个关于StorageManager 的API,在ARMCE论坛的Walle大哥的帮助下,追踪了OpenStore:

HANDLE WINAPI STG_OpenStore(LPCTSTR szDeviceName, HANDLE hProc)
{
    HANDLE hStore = INVALID_HANDLE_VALUE;
    DEBUGMSG( ZONE_STOREAPI, (L"FSDMGR:STG_OpenStore(%s)/r/n", szDeviceName));
    STOREHANDLE *pStoreHandle = new STOREHANDLE;
    // NOTE: szDeviceName pointer was already mapped by filesys
    if (pStoreHandle) {
        LockStoreMgr();
        pStoreHandle->pStore = g_pStoreRoot;
        pStoreHandle->pPartition = INVALID_PARTITION;
        pStoreHandle->pNext = NULL;
        pStoreHandle->dwFlags = 0;
        pStoreHandle->hProc = hProc;
        pStoreHandle->dwSig = STORE_HANDLE_SIG;
        if (hProc == reinterpret_cast<HANDLE> (GetCurrentProcessId())) {
            pStoreHandle->dwFlags |= STOREHANDLE_TYPE_INTERNAL;
        }
        __try {
            while(pStoreHandle->pStore && (pStoreHandle->pStore != INVALID_STORE)) {
                if (wcsicmp( szDeviceName, pStoreHandle->pStore->m_szDeviceName) == 0) {
                    break;
                }   
                pStoreHandle->pStore = pStoreHandle->pStore->m_pNextStore;
            }
            if (pStoreHandle->pStore && (pStoreHandle->pStore != INVALID_STORE)) {
                hStore = CreateAPIHandle(g_hStoreApi, pStoreHandle);
                if (hStore != INVALID_HANDLE_VALUE) {
                    AddHandleToList(&g_pRootHandle, pStoreHandle);
                 } else {
                    delete pStoreHandle;
                    pStoreHandle = NULL;
                }  
            } else {
                SetLastError(ERROR_DEVICE_NOT_AVAILABLE);
            }
        } __except(EXCEPTION_EXECUTE_HANDLER) {
            SetLastError(ERROR_BAD_ARGUMENTS);
        }
        UnlockStoreMgr();
    }   
    if ((hStore == INVALID_HANDLE_VALUE) && pStoreHandle){
        delete pStoreHandle;
    }  
    return hStore;
}

 

这个API在内部是在找寻一个storehandle的链表,如果找到名字和你提供的参数名字相同的,就返回对应的handle,否则就报错。storehandle链表应该是在mountstore的时候进行一个一个创建的。找到storehandle之后,就给你再创建一个Apihandle给你用来做后续API的参数了。

 

BOOL MountStore (const WCHAR* pDeviceName, const GUID* pDeviceGuid, const WCHAR* pDriverPath, __out StoreDisk_t** ppStore)
{
    LRESULT lResult;
   
    LockStoreMgr ();

    StoreDisk_t* pStoreNew = FindStore (pDeviceName);
    if (pStoreNew && !(STORE_FLAG_DETACHED & pStoreNew->m_dwFlags)) {
        // There is an attached store with the same name as the new one
        // so we are unable to mount it (we can't have name conflicts).
        DEBUGMSG (ZONE_ERRORS, (L"FSDMGR: Store /"%s/" already exists ...skipping/r/n", pDeviceName));
        lResult = ERROR_ALREADY_EXISTS;
        goto exit;
    }

    // Look for a currently detached store.
    StoreDisk_t *pStoreExisting = g_pStoreRoot;
    while (pStoreExisting) {
        if (STORE_FLAG_DETACHED & pStoreExisting->m_dwFlags) {
            // Found a detached store.
            break;
        }
        pStoreExisting = pStoreExisting->m_pNextStore;
    }  

    // Allocate a new store.
    pStoreNew = new StoreDisk_t(pDeviceName, pDeviceGuid);
    if (!pStoreNew) {
        lResult = ERROR_NOT_ENOUGH_MEMORY;
        goto exit;
    }

    // Add the new store to our list of stores. It isn't ready for I/O yet because it
    // isn't completely mounted, but we need to open a handle to it to pass to the
    // partition driver so it must be on the list.
    AddStore (pStoreNew);
。。。。。。。
}


void AddStore(StoreDisk_t *pStore)
{
// TODO: Add in the order of Disk Index ???
    if (g_pStoreRoot) {
        StoreDisk_t *pTemp = g_pStoreRoot;
        while(pTemp->m_pNextStore) {
            pTemp = pTemp->m_pNextStore;
        }
        pTemp->m_pNextStore = pStore;
    } else {
        g_pStoreRoot = pStore;
    }   
}

 

一般BINFS的block驱动会在device.exe加载之前被加载,微软的文件系统是用这个API来做这件事情的注意这里有调用mountstore,记住名字的参数。

 

static LRESULT AutoLoadBlockDevice (const WCHAR* pName, HKEY hDeviceKey)
{
    WCHAR DriverPath[MAX_PATH];
    if (!FsdGetRegistryString (hDeviceKey, g_szFILE_SYSTEM_DRIVER_STRING, DriverPath, MAX_PATH)) {
        return ERROR_FILE_NOT_FOUND;
    }
   
    DEBUGMSG (ZONE_INIT, (L"FSDMGR!AutoLoadBlockDevice: Auto-loading block driver from /"%s/"",
        DriverPath));

    LRESULT lResult = ERROR_SUCCESS;
    if (!MountStore (pName, &BLOCK_DRIVER_GUID, DriverPath)) {
        lResult = FsdGetLastError ();
    }
    return lResult;
}

 

这是文件系统在启动初期,去读取autoload注册表项,然后决定如何加载binfs的:

static LRESULT AutoLoadFileSystem (DWORD CurrentBootPhase, HKEY hRootKey,
    const WCHAR* pRootKeyName, const WCHAR* pFileSystemName)
{
    HKEY hKeyFSD = NULL;
    LRESULT lResult;

    // Open the key for this file system under the specified root auto-load key.
    lResult = FsdRegOpenSubKey (hRootKey, pFileSystemName, &hKeyFSD);
    if (ERROR_SUCCESS != lResult) {
        return lResult;
    }

    // Detect whether or not this is the proper boot phase to load this driver.
    // If there is no boot phase specified in the registry, default to 1.
    DWORD BootPhase = 0;
    if (!FsdGetRegistryValue (hKeyFSD, g_szFSD_BOOTPHASE_STRING, &BootPhase)) {
        if (CurrentBootPhase != 0) {
            BootPhase = CurrentBootPhase;
        } else {
            BootPhase = 1;
        }  
        RegSetValueExW (hKeyFSD, g_szFSD_BOOTPHASE_STRING, 0, REG_DWORD,
            (LPBYTE)&BootPhase, sizeof(DWORD));
    }

    if (CurrentBootPhase != BootPhase) {
        // The driver is not to be loaded during this boot phase.
        lResult = ERROR_NOT_READY;
        goto exit;
    }

    DEBUGMSG (ZONE_INIT, (L"FSDMGR!AutoLoadFileSystem: CurrentBootPhase=%u, RootKey=%s, FileSystem_t=%s/r/n",
        CurrentBootPhase, pRootKeyName, pFileSystemName));

    // Query the name of the FSD dll.
    WCHAR FSDName[MAX_PATH];
    if (FsdGetRegistryString(hKeyFSD, g_szFILE_SYSTEM_MODULE_STRING, FSDName, MAX_PATH)) {

        // Get the "MountAsXXX" and/or MountFlags settings for this FSD instance.
        DWORD MountFlags = 0;
        g_pMountTable->GetMountSettings(hKeyFSD, &MountFlags);

        // Get the name of a power manager activity event to associate with this FSD.
        WCHAR ActivityName[MAX_PATH];
        if (!FsdGetRegistryString(hKeyFSD, g_szACTIVITY_TIMER_STRING, ActivityName, MAX_PATH)) {
            VERIFY (SUCCEEDED (StringCchCopy (ActivityName, MAX_PATH, g_szDEFAULT_ACTIVITY_NAME)));
        }

        // Allocate a NullDisk_t object for this FSD.
        NullDisk_t* pDisk = new NullDisk_t (ActivityName);
        if (!pDisk) {
            lResult = ERROR_NOT_ENOUGH_MEMORY;
            goto exit;
        }

        // Use the storage path as the base root reg key.
        lResult = pDisk->AddRootRegKey (g_szSTORAGE_PATH);
        if (ERROR_SUCCESS != lResult) {
            delete pDisk;
            goto exit;
        }

        // The secondary registry key for this FSD is the root auto-load key.
        lResult = pDisk->AddRootRegKey (pRootKeyName);
        if (ERROR_SUCCESS != lResult) {
            delete pDisk;
            goto exit;
        }

        // The sub key for this FSD is the name of the file system.
        lResult = pDisk->SetRegSubKey (pFileSystemName);
        if (ERROR_SUCCESS != lResult) {
            delete pDisk;
            goto exit;
        }

        // Allocate a FileSystemDriver_t object.
        FileSystemDriver_t* pFileSystem = new FileSystemDriver_t (pDisk, FSDName);
        if (!pFileSystem) {
            delete pDisk;
            lResult = ERROR_NOT_ENOUGH_MEMORY;
            goto exit;
        }

        // Finally, mount the file system
        lResult = MountFileSystemDriver (pDisk, pFileSystem, MountFlags, FALSE);
        if (ERROR_SUCCESS != lResult) {
            delete pFileSystem;
            delete pDisk;
            goto exit;
        }

    } else {

        // No "FSD" was specified in the registry, so try to load as an auto-load
        // block device instead.
        lResult = AutoLoadBlockDevice (pFileSystemName, hKeyFSD);
    }

exit:
    if (hKeyFSD) {
        FsdRegCloseKey (hKeyFSD);
    }
    return lResult;
}

 

 所以我们看到,如果只有一个block驱动,而且有binfs的时候,系统是通过
[HKEY_LOCAL_MACHINE/System/StorageManager/AutoLoad/MSFlash]来mountstore的,名字就是MSFlash。如果在非mutibin的时候,flashdisk不会通过autoload来加载会,走普通的流程:
1.被设备管理器加载。
2.device.exe根据注册表的iclass告诉storagemanager这是个block驱动
3.存储管理器调用mountstore来加载这个块设备驱动即flashdisk

下面这个IST是storagemanager的一个监视线程,即等待设备管理器发现iclass为block的驱动后发event给这个PNPThread,这个线程会根据设备列表得到devicename为DSK0:。

DWORD PNPThread(LPVOID lParam)
{
    DWORD dwFlags, dwSize;
//    HKEY hDevKey;
    HANDLE hReg;
    DEVDETAIL * pd = (DEVDETAIL *)g_pPNPBuf;
    GUID guid = {0};
    HANDLE pHandles[3];
    TCHAR szGuid[MAX_PATH];
    HMODULE hCoreDll;   
    DWORD dwTimeOut = INFINITE, dwTimeOutReset = DEFAULT_TIMEOUT_RESET;
    PSTOPDEVICENOT pStopDeviceNotification = NULL;
    PREQUESTDEVICENOT pRequestDeviceNotification = NULL;

    pHandles[0] = g_hPNPQueue;
    pHandles[1] = g_hPNPUpdateEvent;
    pHandles[2] = g_hAutoLoadEvent;

    HKEY hKey;
    if (ERROR_SUCCESS == FsdRegOpenKey( g_szSTORAGE_PATH, &hKey)) {
        DWORD dwPriority;
        if (!FsdGetRegistryValue(hKey, g_szReloadTimeOut, &dwTimeOutReset)) {
            dwTimeOutReset = DEFAULT_TIMEOUT_RESET;
        }
        if (!FsdGetRegistryValue( hKey, g_szWaitDelay, &g_dwWaitIODelay)) {
            g_dwWaitIODelay = dwTimeOutReset * DEFAULT_WAITIO_MULTIPLIER;
        }
        if (FsdGetRegistryValue( hKey, g_szPNPThreadPrio, &dwPriority)) {
            CeSetThreadPriority(GetCurrentThread(), dwPriority);
        }
        FsdRegCloseKey( hKey);
    }
    DEBUGMSG( ZONE_INIT, (L"STOREMGR: Using PNP unload delay of %ld/r/n", dwTimeOutReset));

    hCoreDll = (HMODULE)LoadLibrary(L"coredll.dll");
    if (hCoreDll) {
        pRequestDeviceNotification = (PREQUESTDEVICENOT)FsdGetProcAddress( hCoreDll, L"RequestDeviceNotifications");
        pStopDeviceNotification = (PSTOPDEVICENOT)FsdGetProcAddress( hCoreDll, L"StopDeviceNotifications");
    }
    FreeLibrary( hCoreDll); // This is okay since we should already have a reference to coredll

    if (pRequestDeviceNotification) {
        DEBUGMSG( ZONE_INIT, (L"STOREMGR: PNPThread Created/r/n"));
        hReg = pRequestDeviceNotification(&BLOCK_DRIVER_GUID, g_hPNPQueue, TRUE);
    }
   
    while(TRUE) {
        DWORD dwWaitCode;
        dwWaitCode = WaitForMultipleObjects( 3, pHandles, FALSE, dwTimeOut);
        if (dwWaitCode == WAIT_TIMEOUT) {
            DEBUGMSG( ZONE_INIT, (L"STOREMGR: Scavenging stores/r/n"));
            LockStoreMgr();
            dwTimeOut = INFINITE;
            g_dwUpdateState &= ~STOREMGR_EVENT_UPDATETIMEOUT;
            UnlockStoreMgr();
            DetachStores(STORE_FLAG_DETACHED);                 
        } else {
            DWORD dwEvent = dwWaitCode - WAIT_OBJECT_0;
            switch(dwEvent) {
                case 0: {
                    if (ReadMsgQueue(g_hPNPQueue, pd, sizeof(g_pPNPBuf), &dwSize, INFINITE, &dwFlags)) {
                        FsdStringFromGuid(&pd->guidDevClass, szGuid);
                        DEBUGMSG( ZONE_INIT, (L"STOREMGR: Got a plug and play event %s Class(%s) Attached=%s!!!/r/n", pd->szName, szGuid, pd->fAttached ? L"TRUE":L"FALSE"));
                        if (memcmp( &pd->guidDevClass, &BLOCK_DRIVER_GUID, sizeof(GUID)) == 0) {
                            if (pd->fAttached) {
                                MountStore( pd->szName, pd->guidDevClass);
                            } else {
                                UnmountStore(pd->szName);
                            }   
                        }   
                    }            
                    break;
                }
                case 1: {
                    if (g_dwUpdateState & STOREMGR_EVENT_UPDATETIMEOUT) {
                        dwTimeOut = dwTimeOutReset;
                    }
                    if (g_dwUpdateState & STOREMGR_EVENT_REFRESHSTORE) {
                        LockStoreMgr();
                        BOOL fRet;
                        CStore *pStore = g_pStoreRoot;
                        TCHAR szName[MAX_PATH];
                        while(pStore) {
                            if (pStore->m_dwFlags & STORE_FLAG_REFRESHED) {
                                CStore *pStoreTemp = pStore;
                                wcscpy( szName, pStore->m_szDeviceName);
                                pStoreTemp->Lock();
                                DEBUGMSG( ZONE_INIT, (L"Refreshing store %s is happenning !!!/r/n", pStore->m_szOldDeviceName));
                                fRet = pStoreTemp->UnmountStore();
                                pStoreTemp->Unlock();
                                pStore = pStoreTemp->m_pNextStore;
                                if (fRet) {
                                    UpdateHandleFromList(g_pRootHandle, pStoreTemp, NULL);
                                    FSDMGR_AdvertiseInterface( &STORE_MOUNT_GUID, pStoreTemp->m_szDeviceName, FALSE);
                                    DeleteStore( pStoreTemp);
                                    MountStore( szName, BLOCK_DRIVER_GUID);
                                }
                            } else {
                                pStore = pStore->m_pNextStore;
                            }
                        }
                        UnlockStoreMgr();
                    }
                    break;
                }
                case 2:
                    ResetEvent( g_hAutoLoadEvent);
                    AutoLoadFileSystems( 2, LOAD_FLAG_ASYNC);
                    break;
                default:
                    break;
            }  
        }   
    }   
    // SHould never get here !!!
    if (pStopDeviceNotification)
        pStopDeviceNotification(hReg);
    return 0;
}

 

这个结构体包含device.exe动态加载的所有的驱动列表,那个的szname就是xxx0:之类的名字。

typedef struct {
  GUID guidDevClass;
  DWORD dwReserved;
  BOOL fAttached;
  int cbName;
  TCHAR szName[1];
} DEVDETAIL, *PDEVDETAIL;Members
guidDevClass
Device interface identifier for this notification.
dwReserved
Do not use.
fAttached
TRUE if the device interface is present, otherwise, FALSE.
cbName
Byte count of the interface name.
szName
Beginning of the name of the interface.
Requirements
OS Versions: Windows CE .NET 4.0 and later.
Header: Pnp.h.

 

总结:
1. 在mutibin的时候这个block有两个分区binfs+fatfs.
2. 在非mutibin的时候只有一个分区fatfs(bootsection是不会被加载的,reserved而已)
3. 在非mutibin的时候,没有binfs,所以磁盘驱动是在第二阶段用设备管理器加载的,mount的name是DSK0:。
4. 在mutibin的时候因为有binfs,注册表会有autoload,系统会在第一阶段加载磁盘驱动,mount的name是MSFLASH。之所以为什么要用autoload是因为binfs需要在比较早些的时候加载,因为很多时候设备管理器是在binfs分区放着,binfs不起来,设备管理器就起不了,系统死机。因为你的fatfs会在autoload的时候一并加载,后续应该就不会在第二阶段加载了。
5. mount的名字决定了后续应该用什么名字来openstore.

********************************************************************************************

以上内容是根据Walle的指点,自己重复跟踪了下代码,有了比较深刻的理解!

 

只要解决了打开设备的问题,那么接下来提供接口就比较容易了,在fmd.c文件中的FMD_OEMIoControl函数中添加case即可。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值