2011年9月5日 星期一

[筆記] Windows CE 硬體中斷處理

這裡只講 IST, 不是 ISR, 而實際上我覺的 IST 稍稍好用一點, 雖然它比較不即時.

構成硬體中斷通知總共須要四樣東西, 產生步驟大概是這樣:
1.硬體的中斷向量值, 這個要 chip design vendor 提供. 這裡稱 A.
2.CreateEvent 產生的 Event handle, 這裡稱 B.
3.KernelIoControl 用 IOCTL_HAL_REQUEST_SYSINTR, 這裡是傳入 A, 產生 C.
4.InterruptInitialize function 傳入 C 和 B, 到這裡才算是把中斷跟事件連接起來.
5.用 CreateThread 產生一個 IST (Interrupt Service Thread) (稱為D) 去等那個 C.

example. IRQ_GPIO2_PIN20 這個是 BSP 裡提供的一個定義值, 也就是 A.

static DWORD WINAPI ThreadHDS(LPVOID lpParam);

HANDLE hHND = CreateEvent(0, 0, 0, 0); //這個是B.
HANDLE hThread = 0; //要被產生的 D.
DWORD dwSysIntr = 0; //要被產生的 C.

if(hHND && hHND!=INVALID_HANDLE_VALUE)
{
DWORD dwIRQ = IRQ_GPIO2_PIN20;

if(KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIRQ, sizeof(dwIRQ), &dwSysIntr, sizeof(DWORD), 0))
{ //這裡開始把中斷向量掛上去, 在 dwIRQ 裡傳回一個系統裡的對應代號.
if(InterruptInitialize(dwSysIntr, hHND, NULL, 0))
{ //當這個中斷進來後, 就去 SetEvent(hHND).
//開一個 thread (D) 下去等那個 event (
hThrea =
CreateThread( 0,
0,
(LPTHREAD_START_ROUTINE)ThreadHDS
hHND, //在這裡只傳入被產生的那個 handle.
0,
&dwThreadID
);
}
}
}

static DWORD WINAPI ThreadHDS(LPVOID lpParam)
{
HANDLE hHND = (HANDLE)hHND; //HANDLE 本身是 void* 所以可以這樣玩..

while(WaitForSingleObject(hHND, INFINITE) != WAIT_FAILED)
{ //以下是如果有等到事件觸發時才會有的動作.
Sleep(100);
//這邊就可以再塞 SendMessage 這類的東西把事件傳給 MFC 的 AP 使用.
}
return 0;
}

WaitForMultipleObject 我沒有實驗成功, 有人說 CE 底下這個 function 不 work, 等哪天試出來時再丟上來修改範例...

2011年9月4日 星期日

同樣是看電影...

有兩個國家, 各自拍兩部電影, 然後去問這兩個這兩個國家的人, 他們會不會去看自己國家的電影.. 一個人說: "我們自己國產的片子拍的這麼爛, 我為什麼要去看?? 我寧可去看____國出的電影!!" 一個人說: "這部片看起來不錯, 我會去看". 如果你追問他說 "可是這部片聽說影評很差耶??, 他還是會說 "不用阻止我, 我會去看國產的電影".

這兩個國家, 約莫25年前時, 前一個國家的電影在東南亞圈還撐起一片天, 但是這個國家的人很媚外, 始終會認為外國電影才是好. 另一個國家完全的默默無聞, 這個國家的國民, 看自己家的電影, 即使踩到地雷片, 看的幹不絕口, 下一次看電影仍然會選擇國片. 25年後, 那個默默耕云的國家把電影外銷給那個 25 年前電影很丘的國家.

也許市場淘汰機制是促使產業進步的動力之一, 但這些自以為良禽擇木而棲的人始終沒有想過, 國內這些產業蕭條了, 這些人失業了, 這些人失業後也就沒有收入來支撐這些所謂高知識份子的產物, 循環下去沒有多久, 這些高知識份子也失業了, 不一樣的是後者這些人始終對著自己人指著鼻子罵: "景氣就是被你們這些人搞差的" ....

某個也曾被看不起的東南亞半島國, 現在全球 DRAM 跟 Flash 都是他們在掌控, 有人有想過背後真正的原因是什麼嗎... ?

我不想明講說哪個國家是哪個, 哪個人是哪個, 我只希望大家能團結一點, 敵人最想看到的就是一個國家的人, 內鬥內行外鬥外行.


2011年9月2日 星期五

Windows CE 的 debug console

一般來講, Windows CE (或 mobile 或 phone, ...) 都會用到一個 UART port 當 debug console, 因為最少 e-boot 裡會用到 debug console, 進 OS 後也會在 debug console 裡秀一些錯誤訊息.

OK, 有人提議說把這個 debug console 拿掉, 還原回一般 UART 的功能. 怎麼做咧? 一開始想到的就是改掉整個 BSP 裡對 OALMSG, DEBUGMSG, RETAILMSG 的定義, 我的 BSP 裡是被轉向到 printf_exp 這個東西, 但我找不到 printf_exp 的進入點在哪裡...

於是我轉而去改另一樣東西, 也就是 e-boot 跟 kernel 在啟始時都會啟始的 debug console, 這個 function 一般是 "OEMDebugInit" (BOOL OEMDebugInit(void)), 在 blcommon.c 中 BootloadertMain 裡會呼叫它, 如果都追不到這些 function name 也沒關係, 因為這些都還不算重點, 我覺的重點在 "OALLogSetZones" 這個 function 上, 用 ultraedit 搜尋 BSP 裡有沒有地方用上, 有用上就是了.

一般 BSP 會用 OALLogSetZones(initialOALLogZones); 的方式向系統告知有 debug console 可用, 如果可以的話, 在這之前做點要不要 debug console 的判斷, 來打開或關掉 (移作它用) 它吧.

後記:
OALLogSetZones 設定的是要輸出哪些 debug message, 設 0 就是不輸出任何訊息, 而 console debug message 的實作是 call 兩個東西:
int OEMReadDebugByte();
VOID OEMWriteDebugByte(UINT8 ch);
(ps.它本來就沒有佔用任何 COM 的 file header)
要在這裡直接攔掉 debug console 的操作.

至於要不要把 output console message 轉向到 IPU, input 指去 keyboard array, 那又是另一段工程了....

2011/11/15 update:
這樣做還有另一個副作用, 就是進 suspend 會死當, 不過這種情況要滿足兩種條件:
1.UART1 為 debug port, 而且 OALLogSetZones() 設定時不為 0 (message enable)
2.UART1 設定可以被 OS 使用.

這樣在進 suspend 時, UART1 也當然會 power-off, 但當 power-off 時, debug message 也就跟著送不出去, 然後系統就 hang 住.

可以靠修改 code 解這個問題.
------------------
\\WINCE600\PLATFORM\COMMON\src\soc\COMMON_FSL_V2_PDK1_7\SERIAL\serial.c
extern DWORD initialOALLogZones;
static BOOL SerPowerOff(PVOID pContext)
{
PUART_INFO pHWHead = (PUART_INFO)pContext;
if(pHWHead->HwAddr == 0x43f90000L && initialOALLogZones != 0) return TRUE;
...
}
------------------
在這兩個 sources 檔案的 link 裡加上 "$(_PLATCOMMONLIB)\$(_CPUDEPPATH)\oal_log.lib":
\\WINCE600\PLATFORM\COMMON\src\soc\COMMON_FSL_V2_PDK1_7\SERIAL\sources
\\WINCE600\PLATFORM\iMX35-3DS-PDK1_7\src\DRIVERS\SERIAL\sources

2011年8月24日 星期三

Windows CE 的 kernelIoControl


這些是 KernelIoControl 中 FILE_DEVICE_HAL 用的 control code, 號碼是十進位, 這些是從 FreeScale 的 BSP 裡挖出來的, 還不是全部的 Control Code..

CTL_CODE(FILE_DEVICE_HAL, xx, METHOD_BUFFERED, FILE_ANY_ACCESS)

xx:
01 HAL_GET_DEVICE_INFO
03 HAL_GET_IP_ADDR
04 HAL_RADIO_CNTRL
05 HAL_DDK_CALL
06 EDBG_REGISTER_CLIENT
07 EDBG_DEREGISTER_CLIENT
08 EDBG_REGISTER_DFLT_CLIENT
09 EDBG_SEND
10 EDBG_RECV
11 EDBG_SET_DEBUG
78 KITL_STARTUP
79 KITL_INTRINIT
80 KITL_IS_KDBG_REGISTERED

// KITL PowerOn/Off ioctl, *lpInBuf = 0 for off, 1 for on.
81 KITL_POWER_CALL
12 SET_KERNEL_COMM_DEV
13 HAL_GET_UUID
14 HAL_INIT_RTC
15 HAL_REBOOT
16 HAL_HALT
17 SET_KERNEL_DEV_PORT
18 HAL_TRANSLATE_IRQ
19 HAL_GET_RIO_INFO
20 HAL_ILTIMING
21 HAL_GET_DEVICEID
22 HAL_PROFILE
23 HAL_SET_DEVICE_INFO
24 QUERY_PHYSICALMEM
25 PROCESSOR_INFORMATION
35 HAL_GETREGSECUREKEYS
36 HAL_REQUEST_IRQ
38 HAL_REQUEST_SYSINTR
54 HAL_RELEASE_SYSINTR
// IOCTL to get KITL transport info
37 KITL_GET_INFO
40 HAL_ENABLE_WAKE
41 HAL_DISABLE_WAKE
42 HAL_GET_WAKE_SOURCE
61 HAL_PRESUSPEND
// IOCTL to tell OEM to initialize registry on boot
44 HAL_INITREGISTRY

// IOCTL to give OEM a more full-featured init when the kernel is ready to go
// and before any apps are started
45 HAL_POSTINIT

// IOCTL to ask OEM whether to force clean registry hive
49 HAL_GET_HIVE_CLEAN_FLAG

// IOCTL to ask OEM the reason for power on
50 HAL_GET_POWERONREASON

// IOCTL to get random hardware seed
52 HAL_GET_RANDOM_SEED

// IOCTL to ask OEM for a RAM region to put the registry hive into
53 GET_HIVE_RAM_REGION

// IOCTL to tell OEM to save the RAM region where the registry hive is stored
55 SAVE_HIVE_RAM_REGION

// IOCTL to write XIP section.
46 HAL_WRITE_XIP
47 HAL_XIPCHAIN

// IOCTL for authenticate device
60 HAL_AUTHENTICATE_DEVICE

// IOCTL for WHQL testing (used to check whether hardware is in a jumpered test mode)
56 WHQL_TEST_MODE

// IOCTL for retrieving location and size of bootloader in flash
57 HAL_GET_BOOTLOADER_PARAMS

// IOCTL for retrieving the signed state of an OS image
58 HAL_GET_IMAGE_SIGNED_STATE

// IOCTL to query for a default display resolution.
63 HAL_QUERY_DISPLAYSETTINGS

// IOCTL to query device for device-specific information
64 HAL_QUERY_DEVICE_SETTINGS

// IOCTL to allow the HAL to override the extension region
65 HAL_GET_BIN_CHAIN

// IOCTL to retrieve cache information
66 HAL_GET_CACHE_INFO

// IOCTL to control OEM-specified profiler
67 HAL_OEM_PROFILER

// IOCTL to allow the networking component interrupts to use one SYSINTR_NETWORK_SHARED
68 HAL_SYSINTR_NETWORK_SHARED

// IOCTL to allow OEM specify MAC address for RNDIS
69 HAL_GET_RNDIS_MACADDR

// IOCTL to allow OEM's to specify if a partition is to be formated before being mounted.
70 HAL_QUERY_FORMAT_PARTITION

// IOCTL used by halflat display driver
71 HAL_DDI

// This IOCTL enables/disables update mode. It's used when updating system images and it sets/clears a flag in
// an OEM-defined location that's interpreted by the initial program loader (IPL) at boot time. Based on the
// flag, the IPL will either boot the OS image or it'll load the update loader which starts the update process.
//
// The IOCTL takes a single boolean input parameter: TRUE == update mode and FALSE == normal OS
//
77 HAL_UPDATE_MODE

// IOCTL used by kernel to query page pool parameters from the OAL
// The IOCTL takes no input parameters but returns an NKPoolParameters struct as output.
82 HAL_GET_POOL_PARAMETERS

////////////////////////////////////////////////////////////////////////////////
// VBridge support in kernel, used by VMini (Null miniport driver).
//
26 VBRIDGE_GET_TX_PACKET
27 VBRIDGE_GET_TX_PACKET_COMPLETE
28 VBRIDGE_GET_RX_PACKET
29 VBRIDGE_GET_RX_PACKET_COMPLETE
30 VBRIDGE_GET_ETHERNET_MAC
31 VBRIDGE_ADD_MAC
32 VBRIDGE_SHARED_ETHERNET
33 VBRIDGE_CURRENT_PACKET_FILTER
34 VBRIDGE_802_3_MULTICAST_LIST
39 VBRIDGE_WILD_CARD

//
// These are only handled in vbridge.lib
//

42 VBRIDGE_WILD_CARD_RESET_BUFFER
43 VBRIDGE_WILD_CARD_VB_INITIALIZED
// Ioctl to retrieve OutputDebugString
48 EDBG_GET_OUTPUT_DEBUG_FN
51 EDBG_IS_STARTED
// IOCTL to retrieve hardware-generated entropy
62 HAL_GET_HWENTROPY

例如呼叫已經被串接好的 RTC_init 就像這樣:
SYSTEMTIME tTIME = { 0 };
KernelIoControl(CTL_CODE(FILE_DEVICE_HAL, 14, METHOD_BUFFERED, FILE_ANY_ACCESS), &tTIME, sizeof(SYSTEMTIME), NULL, 0, NULL);

至於串接到 OEM function 這個是在 WinCE 裡被定義好的, 能不能改我就不確定了..
{WINCE_ROOT}\\PLATFORM\\COMMON\\SRC\\INC\\oal_ioctl_tab.h :

{ IOCTL_HAL_INIT_RTC, 0, OALIoCtlHalInitRTC },

2011年8月12日 星期五

嗯, 真的, why so serious?

我現在不會想那麼好心跟客戶打招呼, 我只是想告訴客戶, 前面有水雷, 不要過去.

2011年8月5日 星期五

Windows CE 輸入法...

先寫在這做筆記, 我不確定完全正確...
在做 windows CE 的東西時, 只要碰上非英語語系界面時都會碰上這個問題:

ERROR: C:\WINCE600\public\common\oak\drivers\keybd\LAYMGR\.\LayMgr.cpp line 1600: MapVirtualKey: No input language installed
ERROR: C:\WINCE600\public\common\oak\drivers\keybd\LAYMGR\.\LayMgr.cpp line 1411: KeybdDriverVKeyToUnicode: No input language installed

google 半天的結果當然是無解.. (google 能找到答案的問題本來就不叫問題..), 如 debug console 所說, 這是欠輸入法, 但只講對 1/5, 實際上這除了欠輸入法以外, 還欠 keyboard layout. 而更奇怪的是, CE 上 keyboard layout 竟然是用輸入法所用的代號..

以下假設是日文環境, 輸入法用 IME 3.1, BSP會這樣設定:
[HKEY_CURRENT_USER\Keyboard Layout\Preload]
@="00000411"
[HKEY_CURRENT_USER\Keyboard Layout\Preload\1]
@="00000411"

這個在 \wince600\PUBLIC\COMMON\OAK\DRIVERS\KEYBD\LAYMGR.reg 裡, 而被 BSP 用的 platform.reg include 進來:

[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Layouts\00000411]
"Layout File"="kbdmouse.dll"
"Layout Text"="Japanese"
"PS2_AT"="kbdmouse.dll"

但實際上這樣做有幾個問題在於
1.實際上沒有一個輸入法叫 00000411, 這是國家代碼, 當然不會是輸入法代碼..
2.IME 3.1 的輸入法代號叫 e001, 所以在 laymgr.cpp 中尋找的是 e0010411....
3.這個 e0010411 會在以上的 Preload 裡尋找, 如果沒有的話, 表示預設就沒有它..
4.這個 e0010411 也會 在 Layouts 裡尋找, 如果沒有, 就沒有對應表..

這個問題源自於 laymgr.cpp GetDefaultInputMethodName()中的一行
_tcsicmp( szTempInputMethodName, szTempDefaultInputMethodName)
(line 2963 at wince 6.0 R3 patch 2011-06-30) 中的判斷, 傳進去的是輸入法代碼 + 國碼一起比較, 也就所以為什麼英語語系 (00000409) 都沒有問題, 因為英語語系沒有輸入法, 前面都是0, 所以不會有找不到的問題.
(實際上我會建議在 laymgr.cpp 中安插自己的 debug message 把輸入法的代號 dump 出來, 以利日後 registery 值的建立.)

也就是說, 如果是用日文語系+IME的話, laymgr 會去找一個叫 "日文語系+IME" 的鍵盤, 實際上當然是不會有這種東西, 但我們要在 registery 裡造個假的去騙過檢查...

所以我現在用的設定是這樣子, 平臺是 FreeScale i.MX35

i.MX35 用的 platform registery key 在:
C:\WINCE600\PLATFORM\iMX35-3DS-PDK1_7\FILES\platform.reg
修改幾個:
; #include "$(DRIVERS_DIR)\keybd\LayMgr.reg" ;<= mark 掉
因為全域變數不一定 100% work, 所以被 include 進去的東西
往往會被設定成預設的 0409 而非想要的其它語系.

在最後面加上:
[HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\KEYBD]
"DriverName"="kbdmouse.dll" ;這是預設 driver.
[HKEY_CURRENT_USER\Keyboard Layout\Preload]
@="e0010411" ;預設使用的輸入法
[HKEY_CURRENT_USER\Keyboard Layout\Preload\1]
@="00000409" ;有這三個可以備選
[HKEY_CURRENT_USER\Keyboard Layout\Preload\2]
@="e0010411"
[HKEY_CURRENT_USER\Keyboard Layout\Preload\3]
@="00000411" ;這個是被列給 keyboard layout 用的.
[HKEY_LOCAL_MACHINE\Security\Policies]
@="00000411" ;這個不確定幹麻的.
[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Layouts\00000409]
"Layout File"="kbdmouse.dll" ;其實這裡指的都是對應表.
"Layout Text"="US"
"PS2_AT"="kbdmouse.dll"
[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Layouts\e0010411]
"Layout File"="KbdNopJpn1.dll" ;JPN IBM layout 是 jpn1, NEC 是 jpn2.
"Layout Text"="Japanese"
"PS2_AT"="KbdNopJpn1.dll"
[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Layouts\00000411]
"Layout File"="KbdNopJpn1.dll" ;這裡也要再設定一個.
"Layout Text"="Japanese"

其中指定用 kbdnopjpn1.dll 的主要原因, 是因為它有 export PS2AT_00000411 跟 IL_00000411 兩個 function 出來, 這個是 CE 一拿到就會有已經建好的東西, 其它像法文鍵盤等, 就要參考網路上的文章 (也是被找到最多的文章..)

開機進 CE 裡後, 還要先把輸入法切回英數再切回 IME 才可以兩個都載入進來.

ps. OS component 中, international->locale_specific_support->Japanese->Keyboard 確定要選. 而 NOP-en., NOP keyboard/mouse japan2 這兩個其實一定要選, 才會有 kbdnopjpn1.dll 被包進 kernel image 中, 圖中是因為 BSP 還啥的影響不能全選:


不過仍有繞路走的解法. 在 sysgen 時, 會幾乎把所有不管你有用到沒用到的 .DLL 全部編譯, 先盡可能浪費你所有的時間後, 然後再看要不要加進來... 也就是說, 編好後, 用搜尋是可以搜尋的到這些 .DLL 檔案的. 把這些 .DLL 檔案抓出來後, 可以用內建檔案的玩法給它內建在 kernel image 裡.
也就是修改 platform.bib, 加上
KbdNopJpn1.dll $(_FLATRELEASEDIR)\KbdNopJpn1.dll NK U
這樣在執行時, 會擺在 \\windows\\ 下, 輸入法檔案是可以找的到的.

先這樣, 這還不是很好的解法...

2011年7月29日 星期五

穩定

也許只是一秒, 我想要有陸地, 有一個立足點可以站, 這樣我的雙手才可以穩定的做別的事.

也許只是一小時, 我想要安靜, 只因為我想要思考下一步該怎麼走.

也許只是一天, 我想要有個僻護所, 只因為我每天都需要睡幾小時, 否則沒有體力面對明天.

也許只是幾年, 我只想要有個穩定的工作, 因為我要有穩定的經濟來源來支配生活所需.

也許時間長, 也許時間短, 我一直覺的, 不管做什麼事, 總要有個穩固的基礎, 才能往上爬, 然而..



我今天才意識到, 這些只是一時的穩定, 它不但只是一時, 而且可能還只是一場巧合, 而且更有失去這些辛苦打起來基礎的機會. 我以前以為在這個世界上要找到能一直存活下去的方法是存在的, 長大後才慢慢明瞭到這種學能並不存在, 用上這些學能的那一天, 我開始發現然還是要一直學習一直成長, 才能在人群中走下去, 當在人群中行走數年, 我才發現能幫助你的人是一時的, 人群更不會是永遠存在的, 而我卻需要這些人群換得我日常所需...

我知道這世界上唯一不變的就是 "一直在改變", 只是真正面對時, 那又是另一種心情...