1.SD卡驱动架构
1.1Wince 下SD卡驱动协议栈
• OST硬件底层部分 (主控制端驱动) SDHC_XXX.DLLl
• BUS 中间逻辑命令层 (总线驱动) DBUS.DLL
• CLIENT上层(客户端驱动) SDMEMORY.DLL
1.1.1主控制端驱动
主控制端驱动控制包含主控制器硬件,遵循主控制端驱动接口,它被用于总线驱动通信和设置操作参数。主控制器驱动接口 提供一个硬件提取层,在总线和主控制端执行之间。即:SDHC_XXX.DLL是最底层,因为这层是硬件关联层,因此取名XXX便是为了对应的具体的硬件 BSP包(如本项目的硬件平台是ZYLONITE,其硬件供应商给的BSP包名即为ZYLONITE,在实际项目中我们便将SDHC_XXX.DLL取代 为SDHC_ZYLONITE.DLL),它负责具体的发命令,大多数情况下都需要修改。
1.1.2 总线驱动
总线驱动作为提取和管理层处于主控制驱动和客户端驱动之间。它包括在SDbus.dll文件。为客户端驱动提供了标准 的API,允许运行在任何的基于windows ce设备。总线驱动将是独立于应用程序和主控制端驱动,在不同的处理器之间移植,并不需要改动。SDBus.dll是中间层,负责整合命令和管理。
1.1.3 客户端驱动
客户端驱动和SD客户端驱动通信接口允许客户端驱动去和SD设备通信。客户端驱动接口是有计划地抽象SD总线物理设 备的执行,提供了客户端驱动最大的弹性。客户端驱动接口允许客户端驱动去衡量一个单一的,同步的访问存储卡驱动使用一个线程,异步通信设备驱动。 SDMemory.dll是最高层,类似于应用层。
对于SD卡信息读取,我们只需要把精力放在客户端驱动层就可以,尤其需要关注Sdmemmain文件,Sdmemmain提供了为系统提供SMC_Init、SMC_Open和SMC_IOControl等函数进行系统调用。
2.SD卡信息读取程序分析
2.1图形界面
•RegisterClass注册窗口
•CreateWindowEx 创建窗口
•ListBox控件
•Size位置设置
2.1.1RegisterClass 注册窗口
-
- wc.style = 0;
- wc.lpfnWndProc = MainWndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = hInstance;
- wc.hIcon = NULL,
- wc.hCursor = LoadCursor (NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = szAppName;
-
- if (RegisterClass (&wc) == 0) return 0;
2.1.2 CreateWindowEx 创建窗口
- hWnd = CreateWindow (szAppName,
- TEXT("SdInfo"),
-
- WS_VISIBLE | WS_CAPTION | WS_SYSMENU,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- NULL,
- NULL,
- hInstance,
- NULL);
-
- if (!IsWindow (hWnd)) return 0;
2.1.3ListBox控件
- hwndChild = CreateWindowEx (WS_EX_CLIENTEDGE, TEXT ("listbox"),
- TEXT (""), WS_VISIBLE | WS_CHILD | WS_VSCROLL |
- LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT, 0, 0,
- 100, 100,hWnd, (HMENU)IDC_RPTLIST, hInst, NULL);
-
-
- if (!IsWindow (hwndChild)) {
- DestroyWindow (hWnd);
- return 0;
- }
-
-
- int i = 24;
- SendMessage (hwndChild, LB_SETTABSTOPS, 1, (LPARAM)&i);
- return 0;
2.1.4 Size位置设置
- nWidth = LOWORD (lParam);
- nHeight = HIWORD (lParam);
-
- x = 0;
- y = 20;
- cx = nWidth;
- cy = nHeight - y;
-
- GetClientRect (hWnd, &rect);
-
- SetWindowPos (GetDlgItem (hWnd, IDC_RPTLIST), 0, x,y,cx,cy,SWP_NOZORDER);
3.SD卡信息读取程序
3.1思路
SD卡事件–->读取信息-–>字符处理—>发送到Listbox并显示
SD卡事件
SD卡事件很好解决,至于发送WM_DEVICECHANGE事件消息给程序就可以,依赖的头文件是<dbt.h>。
- const struct decodeUINT MainMessages[] = {
- WM_CREATE,DoCreateFrame,
- WM_SIZE, DoSizeFrame,
- WM_DEVICECHANGE, DoSdbianren,
- WM_DESTROY, DoDestroyMain,
- };
读取信息
利用DeviceIoControl发送相关CTL命令来控制需要读取的信息,CTL命令依赖的头文件是diskio.h,如果SDK不包含,可以到WINCE6000下的Public的INC文件夹里面查找相关的定义。
- HANDLE FileHandle = CreateFile (TEXT("DSK2:"), GENERIC_READ|GENERIC_WRITE
- , 0, NULL, OPEN_EXISTING, 0, NULL);
- if (FileHandle == INVALID_HANDLE_VALUE){
- Display(hWnd,L"-----------------------------------");
- Display(hWnd,L"DSK2 Load Faild");
- return 0;
- }
-
- int Res = DeviceIoControl(FileHandle, IOCTL_DISK_GET_STORAGEID, NULL
- , 0, SDIdent, BufferLength, &ReturnedBytes, NULL);
字符处理
这个步骤是我卡壳最久的地方,参考网上的程序写,发现老是读不出,最后,看到一篇文章说,SD卡的ID号是char型的,而不是WCHAR,两者间需要进行转换,不然无法显示。
- WCHAR WBuffer1[BufferLength];
- memset(WBuffer1, 0,BufferLength);
- char * SerialNo = (char *)((DWORD)SDIdent + SDIdent->dwManufactureIDOffset);
- int nLen = strlen(SerialNo) +1;
- int nwLen = MultiByteToWideChar(CP_ACP, 0,SerialNo,nLen, NULL, 0);
- MultiByteToWideChar(CP_ACP, 0, SerialNo, nLen, WBuffer1, nwLen);
-
- wsprintf(WBuffer,L"Serial=%s",WBuffer1);
- Display(hWnd,WBuffer);
发送到Listbox并显示
- void Display(HWND hWnd,PWCHAR Str)
- {
- TCHAR szOut[128];
- INT i;
-
- wsprintf(szOut,TEXT("%s"),(LPTSTR)Str);
- i= SendDlgItemMessage (hWnd, IDC_RPTLIST, LB_ADDSTRING, 0,
- (LPARAM)(LPCTSTR)szOut);
- if (i != LB_ERR)
- SendDlgItemMessage (hWnd, IDC_RPTLIST, LB_SETTOPINDEX,i,
- (LPARAM)(LPCTSTR)szOut);
- }
(youyudehexie) |