用 OMAP CPU 的用户可能知道 OMAP Clock 可以超频。但由于 OMAP CPU 本身的特性,在超频之后如果设备关闭(设备不使用,一般是两分钟后),再次开启时,频率又恢复成默认的了。
OMAPCLock 本身没有对这些行为作出相关操作,导致 OMAP Clock 用的非常不爽。
我稍微分析了一下 OMAP Clock 的代码,感觉精心构造一小段的代码,应该可以解决这些问题。方案如下:
1. 在原来程序提示设置频率的MessageBox处加入代码,总共11条指令,刚刚好够空间。
2. 由于增加导入表不方便,干脆取消掉 About 显示功能,然后修改 LoadResource、DialogBoxindirectParam 和 EndDialog 的导入函数为 DeleteFileW、SHCreateShortcut 和 CeRunAppAtEven,这样我们就可以调用这三个函数了。
2. 修改代码,调用 SHCreateShortcut 创建快捷方式(之前还要调用DeleteFile掉快捷方式否则无法创建,我晕倒!)。\Windows\Startup\OMAPClock.lnk,指向 \Windows\OMAPClock.exe -clock <频率>
3. 调用 CeRunAppAtEnent 清除掉所有的 \Windows\Startup\OMAPClock.lnk 事件。(否则事件通知会越来越多)
3. 调用 CeRunAppAtEnent 设置在设备唤醒时调用 \Windows\Startup\OMAPClock.lnk。
4.CeRunAppEnent 正好返回 R0 为 1,所以会继续以设置主频。
经过一天下午的调试分析和实际操作,终于解决了OMAPClock的这个问题。
.text:0001165C sub_1165C ; CODE XREF: sub_11358+30p
.text:0001165C ; sub_11B8C+C0p
.text:0001165C
.text:0001165C szTarget = -0x198
.text:0001165C arg_8 = 8
.text:0001165C
.text:0001165C MOV R12, SP
.text:00011660 STMFD SP!, {R0-R3}
.text:00011664 STMFD SP!, {R12,LR}
.text:00011668 SUB SP, SP, #0x190
.text:0001166C MOV R2, R1 ; wchar_t *
.text:00011670 ADD R3, SP, #0x198+arg_8 ; va_list
.text:00011674 MOV R1, #0xC8 ; size_t
.text:00011678 ADD R0, SP, #0x198+szTarget ; wchar_t *
.text:0001167C BL _vsnwprintf
.text:0001167C
.text:00011680 LDR R0, =s_WindowsStartu ; lpFileName
.text:00011684 BL DeleteFileW
.text:00011684
.text:00011688 LDR R0, =s_WindowsStartu ; szShortcut
.text:0001168C ADD R1, SP, #0x198+szTarget ; szTarget
.text:00011690 BL SHCreateShortcut
.text:00011690
.text:00011694 MOV R1, #0 ; lWhichEvent
.text:00011698 LDR R0, =s_WindowsStartu ; pwszAppName
.text:0001169C BL CeRunAppAtEvent
.text:0001169C
.text:000116A0 MOV R1, #0xB ; lWhichEvent
.text:000116A4 LDR R0, =s_WindowsStartu ; pwszAppName
.text:000116A8 BL CeRunAppAtEvent
.text:000116A8
.text:000116AC ADD SP, SP, #0x190
.text:000116B0 LDMFD SP, {SP,PC}
.text:000116B0
.text:000116B0 ; End of function sub_1165C
.text:000116B0
.text:000116B0 ; ---------------------------------------------------------------------------
.text:000116B4 DCD unk_1480C
.text:000116B8 ; LPCWSTR lpFileName
.text:000116B8 lpFileName DCD s_WindowsStartu ; DATA XREF: sub_1165C+24r
.text:000116B8 ; sub_1165C+2Cr
.text:000116B8 ; sub_1165C+3Cr
.text:000116B8 ; sub_1165C+48r
.text:000116B8 ; "\\Windows\\Startup\\OMAPClock.lnk"
理论上 OMAPClock 支持 TI OMAP CPU 的 Smartphone 和 Pocket PC。但后来发现 Smartphone 的 CeRunAppAtEvent 的 Wakeup 事件竟然无效,又是一个弱智 API,Windows Mobile Team 的这些头脑进水的垃圾工程师,总是让我们有不断的“惊喜”发现——Smartphone 不支持唤醒事件,换句话说,新增功能不支持Smartphone,Smrtphone SDK 的文档上没说,但是全世界的论坛都在说这样的问题(http://www.pcreview.co.uk/forums/thread-2467990.php,http://www.pdastreet.com/forums/showthread.php?t=32346)。
由于以上代码修改的原因,此版本 OMAPClock 具有以下局限和特性:
1. 取消了 About 对话框(不影响使用)。
2. 取消了 设置频率的警告(不影响使用)。
3. 文件夹 \Windows\Startup 必须存在。
4. OMAPClock 程序路径必须是 \Windows\OMAPClock.exe。
5. 新增功能无法支持 Smartphone。
以上要求很容易满足(几乎所有系统中默认就是这样,只要把我修改的OMAPClock.exe 放在\Windows中即可),所以这次修改可以看成“完美”了,哈哈……
注意,以上关机代码,仅针对 DOPOD 830 有效,不同的设备的关机KernelIOCode不同,我调试出了很多机器的Code,但都忘了记录下来。有心人可以分析一下一HTC 机器的PowerOffWarning.exe可得出。另外下面是我CeleCmd中关机和硬启的函数部分,已经有一些特定设备的关机和硬启功能(ASUS P527、HTC Diamond、HTC Prophet):
// SHUTdown
#include <PM.h>
#define IOCTL_HAL_REBOOT 0x101003C
#define IOCTL_HAL_SHUTDOWN 0x1012000
#define IOCTL_COLDBOOT_P527 0x1012004
#define IOCTL_COLDBOOT_Prophet 0x1012594
#define IOCTL_COLDBOOT_Diamond 0x1012048
extern "C" BOOL WINAPI SetCleanRebootFlag();
extern "C" BOOL WINAPI GwesPowerOffSystem();
extern "C" BOOL WINAPI ExitWindowsEx(UINT uFlags, DWORD dwReason);
extern "C" BOOL KernelIoControl(DWORD dwIoControlCode, PVOID pInBuf, DWORD nInBufSize, PVOID pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned);
HRESULT SHUT(PCTSTR ptzCmd)
{
BOOL bResult;
switch (UChrToUpper(*ptzCmd))
{
case 'S':
// HTC
KernelIoControl(IOCTL_HAL_SHUTDOWN, NULL, 0, NULL, 0, NULL);
case 'G':
bResult = GwesPowerOffSystem();
break;
case 'P':
bResult = ExitWindowsEx(EWX_POWEROFF, 0);
break;
case 'K':
keybd_event(VK_OFF, 0, KEYEVENTF_SILENT, 0);
keybd_event(VK_OFF, 0, KEYEVENTF_SILENT | KEYEVENTF_KEYUP, 0);
bResult = TRUE;
break;
case 'H':
// HTC
KernelIoControl((ptzCmd[1] == '0') ? UStrToInt(ptzCmd + 1) : IOCTL_COLDBOOT_Diamond, NULL, 0, NULL, 0, NULL);
case 'C':
SetCleanRebootFlag();
case 'R':
bResult = KernelIoControl(IOCTL_HAL_REBOOT, NULL, 0, NULL, 0, NULL);
break;
default:
bResult = ExitWindowsEx(EWX_REBOOT, 0);
break;
}
return !bResult;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课