9.29.2009

花在 Tuner driver 的時間

使用單心線跳線導致第2個byte後資料錯亂 - 3 days.
使用新板子,KITL 連不上 - 1 day
fopen 未使用 binary mode,導致 0x0A 變成 0x0D, 0x0A - 3 days.

實際上真正用在 program Tuner I2C, SPI 的部份 - 大約 2 days.


唉~~引以為戒呀!!

9.17.2009

ReadFile Fail

太白痴..

HANDLE CreateFile(
LPCTSTR
lpFileName,
DWORD
dwDesiredAccess,
DWORD
dwShareMode,
LPSECURITY_ATTRIBUTES
lpSecurityAttributes,
DWORD
dwCreationDisposition,
DWORD
dwFlagsAndAttributes,
HANDLE
hTemplateFile
);
dwDesiredAccess 如果沒有設GENERIC_READ,之後對這個 file handle 作 ReadFile( ) 的話,會fail 。

這是在做 Driver 的時候,明明有作 XXX_READ,也有宣告在 XXX.def 中,但是 ReadFile( ) 卻老是return fail,也沒有進入到 XXX_READ function

總而言之,就是自己白痴。
VS2005 直接開啟 NK.BIN 可以看到裡面包的 Registry 和 所有的 檔案(bib)
在 DeviceDriver 中,幾乎所有的 Driver Interface 第一個 argument 都是 pContext。

這個pContext 是交給 programmer 自己處理的:

在 XXX_Init( ) 中, return 的 pointer,在以後 所有 interface 呼叫時,都會被傳進來 - 也就是 pContext。

9.16.2009

Source : Load Unload Device Driver

很對不起,這個code是base on http://www.ucancode.net/Visual_C_Codes/Loading-DLLs-LoadLibrary-GetProcAddress-FreeLibrary-VC-Example.htm
的 load dll function 寫的,竟然沒有提到,真是抱歉。

我猜原 po 應該是在 Bruce Eitman 的 WINCE Blog:

Windows CE: Loading a Driver with ActivateDeviceEx



這個code是以 load unload driver : SST
cpp

#include "stdafx.h"

#include "resource.h"

#define SST_REG_KEY (TEXT("Drivers\\Builtin\\SST"))

typedef struct {
TCHAR *ValueName;
DWORD Type;
DWORD DwordValue;
TCHAR *StringValue;
} RegEntry;

RegEntry RegEntries[]={
{TEXT("Dll"), REG_SZ, 0,TEXT("SST.DLL")},
{TEXT("Prefix"),REG_SZ, 0,TEXT("SST")},
{TEXT("Order"), REG_DWORD,4,NULL},
{TEXT("Index"), REG_DWORD,1,NULL},
{NULL,NULL,NULL,NULL}
};

void AddDriverSSTToRegistry()
{
HKEY hTargetKey;
DWORD dwDisposition;
DWORD RetVal;
DWORD Index=0;
BYTE *Value;
DWORD uSize;

RetVal = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
SST_REG_KEY,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hTargetKey,
&dwDisposition
);
if(RetVal == ERROR_SUCCESS)
{
while(RegEntries[Index].ValueName!=NULL)
{
if(RegEntries[Index].Type == REG_DWORD)
{
RegSetValueEx(hTargetKey,
RegEntries[Index].ValueName,
0,
REG_DWORD,
(const BYTE*)&RegEntries[Index].DwordValue,
sizeof(DWORD));
}
else
{
Value = (BYTE *)RegEntries[Index].StringValue;
uSize = (wcslen(RegEntries[Index].StringValue)+1)*sizeof(TCHAR);

RegSetValueEx(hTargetKey,
RegEntries[Index].ValueName,
0,
REG_SZ,
(const BYTE*)RegEntries[Index].StringValue,
(wcslen(RegEntries[Index].StringValue)+1) * sizeof(TCHAR));

}
Index++;
}
}
}

HANDLE hDriverSST=INVALID_HANDLE_VALUE;

BOOL LoadDriverSST(void)
{
BOOL RetVal = NULL;

if(hDriverSST == INVALID_HANDLE_VALUE)
{
hDriverSST = ActivateDeviceEx( SST_REG_KEY,
NULL,
0,
NULL);
if(hDriverSST != INVALID_HANDLE_VALUE && hDriverSST != 0)
RetVal = TRUE;
else
{
RETAILMSG(1,(TEXT("Fail to load Driver SST\n")));
}
}
return RetVal;
}

void UnloadDriverSST(void)
{
if(hDriverSST!= INVALID_HANDLE_VALUE)
{
DeactivateDevice(hDriverSST);
hDriverSST=INVALID_HANDLE_VALUE;
}
}

BOOL CALLBACK DialogProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg) {
case WM_INITDIALOG:
return TRUE;
case WM_CLOSE:
EndDialog(hWnd,0);
return FALSE;
case WM_COMMAND:
switch(wParam){
case IDC_BTNLOAD:
LoadDriverSST();
printf("LOAD!");
return TRUE;
case IDC_BTNUNLOAD:
UnloadDriverSST();
printf("UNLOAD");
return TRUE;
case IDC_RESISTRY:
printf("Registry");
AddDriverSSTToRegistry();
return TRUE;
}
break;
default:
return FALSE;
}
}

int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.

return DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,DialogProc);

return 0;
}

Load Unload Device Driver

要開發 device driver就算是有 Kitl,可以把 driver dll 屏除在 os image 之外。
但是每次 rebuild driver,還是要重新 load OS。
這樣有點麻煩。

所以,需要一個 在runtime load/unload device driver 的方法,配合 kitl 的 "Release Directory Module" 功能。
這樣,每次rebuild driver,就只要 unload, load driver 一次就可以。

但是要unload drive ,必須要有 driver 的 handle:
DeactivateDeviceEx

BOOL DeactivateDevice(
HANDLE hDevice
);

hDevice

[in] Handle to an active device. The ActivateDevice and ActivateDeviceEx functions return this value.

要得到 hDevice 就要作 ActivateDevice。
所以Driver 不可以是 buildin active,要自己 activate,才有辦法拿到。

要把Driver 從 registry 的builtin 拿掉,才不會自動 load進來。

但是 ActivateDeviceEx 又需要Registry 作為 Driver active 的依據:

所以就要在程式中create registry key..

整個就參考這個 : Loading a Driver with ActivateDeviceEx

9.15.2009

Telit 的 application note 有 CMUX 的說明:Telit_CMUX_User_Guide_r3

超複雜,aynchronize buffer between user and kernel space

繼續上一個,從 Memory Marshalling in Windows CE 這一篇,有更囉唆的東西..

上一篇提到的是單純的由 Io control 傳 pointer 給 kernel space。
但是這只適用再 iocontrol function 裡。

如果這個 driver 有 另開 thread,而由 io control 傳進來的 pointer 要給這個 thread 使用。
這樣會導致:

iocontrol 已經 return 了,可以 剛剛傳進來的 pointer ,kernel space 的 thread 依然會用到。

這樣因為權限的問題,要呼叫另一組 funciton 來 remap pointer:
來處理這類的 pointer

MDSN 的最後一段話:
If you are running inside the kernel process and you are using an ARM microprocessor with a virtually tagged cache, you can pass MARSHAL_FORCE_ALIAS as the ArgumentDescriptor. On all other CPUs, inside the kernel process, CeAllocAsynchronousBuffer always creates an alias to the memory with VirtualCopy. On ARM CPUs that use a virtually tagged cache inside the kernel process, CeAllocAsynchronousBuffer will creates a duplicate copy of the memory on the heap by default. On large buffers, creating the duplicate heap can have an effect on performance. To prevent duplication, pass the MARSHAL_FORCE_ALIAS flag to cause CeAllocAsynchronousBuffer to create an alias, instead. However, the creation of aliased memory on ARM CPUs that use a virtually tagged cache cause both the source and destination memory to be accessed as uncached, until the alias is destroyed by CeFreeAsynchronousBuffer. This means that memory accesses become slower at both the source and destination.

Do not use the MARSHAL_FORCE_ALIAS flag unless you are using buffers greater than 16 KB.
大概是說,配合 ARM 的 virtual tagged cache,allocasynch 會用 'copy 一份到 kernel heap' 的方式來實作。 但是這樣就會有 overhead - copy 的動作。

所以 buffer 很大的時候,可以用 MARSHAL_FORCE_ALIAS option 來強迫 Ce 用 alias的方式。
但是因為 ARM 的架構,被alias 的 memory 區塊將無法被 cache,所以 access 的效能會比較差 (應該是差很多)。

所以建議 16k 以上的 size 再指定 MARSHARL_FORCE_ALIAS 比較合算。
其實這個值應該要看 cpu 和 memory 速度的比值比較正卻



--好複雜,好複雜..

Pointer Marshalling in CE 6

就是 這一篇 Windows CE 6 Memory Architecture 的最後一個 section 說的.

CE 6.0 的 memory (addressing space) 管理改變了。
以往 5.0 有 slot 架構,每個 process 佔一個 slot,只有 running process 會switch 到 slot 0。

CE 6.0 沒有 slot,所有 process 都'共用 bottom 2G 的 memory space',但是只有running process 會實際 佔據 memory space。

Kernel 部份, 5.0 和 6.0 一樣,都是佔用 upper 2G space,恆久存在。

這樣的架構,在 user process 和 kernel process 共用 pointer (space) 時會發生問題。
例如 iocontrol 送 pointer 進 kernel driver 處理


雖然 user process 在 call io control 時,他自己一定是在 running state,所以他實際佔有 bottom 2G 的 memory space。
但是萬一在 io control service 中,user process 被 switch 掉了。那麼原來 iocontrol code 拿到的 address 將不再有效(因為 botton 2G 已經換人用了)。

這樣就會發生問題。

所以 6.0 就修改了 mapping user/kernel space 的 方法 (和新function call)。
Manage 的動作就叫 marshalling pointer.
(在MSDN 中可以在很多地方看到這個名字)



其實就是 重新 alloc 一份在 kernel space (所以那一塊 physical memory 被 mapping 到兩個 memory address - 一個在 user space, 一個在 kernel space)。

這樣會佔用 kernel address space,所以 kernel 在'用完' (不再需要 access 那一塊 memory) 時,要呼叫 free? ,釋放掉 kernel address space

這一篇 Memory Marshalling in Windows CE 有圖示的說明。

可以傳遞DWORD資料的 event

CE 的 Event 可以'關聯' 一個DWORD data。

example code , from norains 的 '事件和进程间的数据交换 ' :
# 进程A: 
# DWORD NotifyProc(LPVOID pParam)
# {
# while(TRUE)
# {
# if(IsDataChange() != FALSE)
# {
# //设置关联数据
# SetEventData(hEventNotify,dwData);
#
# PulseEvent(hEventNotify);
# }
# }
# }
#
# 进程B:
# DWORD WaitNotifyProc(LPVOID pParam)
# {
# while(TRUE)
# {
# DWORD dwReturn = WaitForSingleObject(hEventNotify);
# if(dwReturn != WAIT_TIMEOUT)
# {
# //获取关联数据
# dwData = GetEventData(hEventNotify);
# }
# }
# }

從這裡來看, SetEventData/GetEventData的用法有點問題。
因為Set 和 Get 都要分成兩個動作:
  1. SetEventData
  2. PluseEvent

  1. WaitForSingleObject
  2. GetEventData
所以萬一在 WaitForSingleObject 後,GetEventData前被 preempt 掉,讓 A又執行一次 SetEvent Data再 switch 回來,那麼,GetEventData( ) 取得的就是'新'的 data,而不是'上一個' PluseEvent 前 Set 的 Data 了。

而且接下來 又會有一次 PluseEvent。
所以又會再收一次 -- 這樣的結果就是 Get 的 Thread 會收到兩次相同的 EventData 而漏掉 一個 Data。

9.11.2009

GetProcAddresses one time - DLL

蓄上篇 DLL。
這一篇VC++ Example: Loading DLLs LoadLibrary and GetProcAddress and FreeLibrary文章就有用這樣的方法:

BOOL GetProcAddresses( HINSTANCE *hLibrary,
LPCSTR lpszLibrary, INT nCount, ... )
{
va_list va;
va_start( va, nCount );

if ( ( *hLibrary = LoadLibrary( lpszLibrary ) )
!= NULL )
{
FARPROC * lpfProcFunction = NULL;
LPSTR lpszFuncName = NULL;
INT nIdxCount = 0;
while ( nIdxCount < nCount )
{
lpfProcFunction = va_arg( va, FARPROC* );
lpszFuncName = va_arg( va, LPSTR );
if ( ( *lpfProcFunction =
GetProcAddress( *hLibrary,
lpszFuncName ) ) == NULL )
{
lpfProcFunction = NULL;
return FALSE;
}
nIdxCount++;
}
}
else
{
va_end( va );
return FALSE;
}
va_end( va );
return TRUE;
}

使用方法就是:

#include <windows.h>

typedef int ( WINAPI *MESSAGEBOX )
( HWND , LPCSTR, LPCSTR, DWORD );
typedef int ( WINAPI *MESSAGEBOXEX )
( HWND , LPCSTR, LPCSTR, DWORD , WORD );

void main(void)
{
MESSAGEBOX lpfMsgBox = NULL;
MESSAGEBOXEX lpfMsgBoxEx = NULL;
HINSTANCE hLib;
if(GetProcAddresses( &hLib, "User32.dll", 2,
&lpfMsgBox, "MessageBoxA",
&lpfMsgBoxEx, "MessageBoxExA" ) )
{
lpfMsgBox( 0, "Test1", "Test1", MB_OK );
lpfMsgBoxEx( 0, "Test2", "Test2", MB_OK,
MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ) );
}
if ( hLib != NULL )
FreeLibrary( hLib );
}

但是他還是用了typedef,其實直接宣告function pointer就可以了。

DLL invoking - by LoadLibrary

使用 platform builder 作 DLL 的話,不能作auto load 的動作。
只能用 LoadLibrary( ) 來把 DLL 載入。
同時不要用的時候還可以用FreeLibrary( ) Free 掉。

但是要call DLL 中的 funciton 就比較麻煩了。

要用GetProcAddress ( ) 取出 DLL export 的 funciton address。
然後 cast 成 對應的 funciton ,才能使用。

為了..宣告 function pointer,cast funciton pointer,, 所以還是為每一個 export funciton typedef 一個 型別好了!!
所以好麻煩喔!


example 可以用 MSDN 的:
DLL 部份:Creatint a simple dynamic link library

#include <windows.h>
#define EOF (-1)

#ifdef __cplusplus // If used by C++ code,
extern "C" { // we need to export the C interface
#endif

__declspec(dllexport) int __cdecl myPuts(LPWSTR lpszMsg)
{
DWORD cchWritten;
HANDLE hConout;
BOOL fRet;

// Get a handle to the console output device.

hConout = CreateFileW(L"CONOUT$",
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if (INVALID_HANDLE_VALUE == hConout)
return EOF;

// Write a null-terminated string to the console output device.

while (*lpszMsg != L'\0')
{
fRet = WriteConsole(hConout, lpszMsg, 1, &cchWritten, NULL);
if( (FALSE == fRet) || (1 != cchWritten) )
return EOF;
lpszMsg++;
}
return 1;
}

#ifdef __cplusplus
}
#endif

Call AP 要參考:
Using Run-Time dynamic Linking:

#include <windows.h>
#include <stdio.h&t;

typedef int (__cdecl *MYPROC)(LPWSTR);

VOID main(VOID)
{
HINSTANCE hinstLib;
MYPROC ProcAdd;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;

// Get a handle to the DLL module.

hinstLib = LoadLibrary(TEXT("MyPuts.dll"));

// If the handle is valid, try to get the function address.

if (hinstLib != NULL)
{
ProcAdd = (MYPROC) GetProcAddress(hinstLib, "myPuts");

// If the function address is valid, call the function.

if (NULL != ProcAdd)
{
fRunTimeLinkSuccess = TRUE;
(ProcAdd) (L"Message sent to the DLL function\n");
}
// Free the DLL module.

fFreeResult = FreeLibrary(hinstLib);
}

// If unable to call the DLL function, use an alternative.
if (! fRunTimeLinkSuccess)
printf("Message printed from executable\n");
}
其實為了用那幾次的typedef 很麻煩,到不如反過來:

int (__cdecl *myPuts)(LPWSTR);

然後

*(FARPROC*)&myPuts = GetProcAddress(hinstLib, "myPuts");

CAST a number to function




(*((void(*)(void))0x0))();

function pointer.
case

KITL download -- no progress

有時候使用KITL download 一直不能成功。
通常是更改過ip address 錯誤後,又改正回來以後造成

就是 connection option 有找到 device,ip。
device 也持續吐出 bootme 255.255.255.255...
但是 download progress 一直沒進步,一直在等待..


這時候就要把MAC Address 也更改一下,才能夠正常download。

是 ARP cache 的關係?

9.10.2009

變更 ActiveSync 裝置在管理員裡的裝置名稱


就是在pc control panel - hardware device 顯示的名字:

usb ActiveSync driver 是依靠 usb 的 PID, VID 來決定 driver 的。

CE 的 USB PID,VID 是在..common.reg:
[HKEY_LOCAL_MACHINE\Drivers\USB\FunctionDrivers\Serial_Class]
; idVendor must be changed. 045E belongs to Microsoft and is only to be used for
; prototype devices in your labs. Visit http://www.usb.org to obtain a vendor id.
"idVendor"=dword:045E
"Manufacturer"="Generic Manufacturer (PROTOTYPE--Remember to change idVendor)"
"idProduct"=dword:00ce
"Product"="Generic Serial (PROTOTYPE--Remember to change idVendor)"
"bcdDevice"=dword:0


PC ActiveSync Driver 要到 MS 去download .. setup.msi。

然後手動解開(不要安裝)..

D:\>msiexec /a d:\setup.msi /qb TARGETDIR=d:\ats

這樣就解開到 d:\ats下..

然後去修改.. d:\ats\Windows\INF\wceusbsh.inf

可以看到一堆廠商的 vid, pid...

9.01.2009

bookmark : install msys and minGW

install mingw + msys 的最佳教學。竟然是 ffmpeg 的文件:Msys MinGW