Arduino 互換の Digispark という小型ボードを利用して Windows PC の USB 端子に接続する大きな電源ボタンを作りました。 接続すると「HID 準拠システムコントローラ」として認識されます。 ボタンを長押しすると、キーボードの SLEEP ボタンを押した時の信号が出力されて、PC がスリープ状態になります。ボタンを短く押すと、PC がスリープ状態から復帰します。
Windows PC の動作を調べたところ、USB 接続のキーボードからスリープさせる方法と、スリープからのウェイクアップをさせる方法は全く異なっていました。
Windows7,8,10 では [Power][Sleep][Wake] のキーがあるキーボード(日本語112キーボード) の [Sleep] キーを押すとスリープ状態になります(この挙動はコントロールパネルの[電源オプション][電源ボタンの動作を選択する] から変更できます)。
通常の USB キーボードを Windows PC に接続すると、デバイスマネージャ上に [キーボード]-[HIDキーボードデバイス] として表示されますが、[Sleep] キーが付いているキーボードの場合は、これに加えて [ヒューマンインタフェースデバイス]-[HID 準拠システムコントローラ] という項目が追加されます。Windows はこのデバイスから [Sleep] キーのキーコードを受け取るとスリープ状態になります。
PC がスリープ状態になった後で、同じくキーボードの [Wake] キーを押すとウェイクアップします。ただしスリープ状態では OS 側からどのキーを押したかを判定できません。
そこで、キーボード側から USB の信号線の電圧レベルを一定のパターンで変化させることでウェイクアップさせるようになっているのですが、この手順がなかなか見つからずに苦労しました。
(参考) USB1.1仕様書 の"7.1.7.5 Resume" に書いてありますが複雑です。また "Table 9-8. Standard Configuration Descriptor (Continued)" にある bmAttributes の "D5: Remote Wakeup" を有効にする必要がありました。今回は関係ありませんでしたが、HID 仕様書 に出てくる "Boot Keyboard" とは BIOS 画面の操作に使えるキーボードのことだそうです。
最終的には PS2USB というプロジェクトの sendRemoteWakeUp() 関数内で実現できているのを見つけて、これを真似して実装しました。
[HID Report Descriptor] Usage Page (Generic Desktop) 05 01 Usage (System Control) 09 80 Collection (Application) A1 01 Report ID (1) 85 01 Usage Minimum (System Power Down) 19 81 Usage Maximum (System Wake Up) 29 83 Logical Minimum (0) 15 00 Logical Maximum (1) 25 01 Report Count (3) 95 03 Report Size (1) 75 01 Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02 Report Count (1) 95 01 Report Size (5) 75 05 Input (Cnst,Ary,Abs) 81 01 End Collection C0 Usage Page (Consumer Devices) 05 0C Usage (Consumer Control) 09 01 Collection (Application) A1 01 Report ID (2) 85 02 Logical Minimum (0) 15 00 Logical Maximum (1) 25 01 Usage (Volume Increment) 09 E9 Usage (Volume Decrement) 09 EA Usage (Mute) 09 E2 Usage (Play/Pause) 09 CD Usage Minimum (Scan Next Track) 19 B5 Usage Maximum (Eject) 29 B8 Report Size (1) 75 01 Report Count (8) 95 08 Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02 Usage (AL Email Reader) 0A 8A 01 Usage (AC Search) 0A 21 02 Usage (AC Bookmarks) 0A 2A 02 Usage Minimum (AC Home) 1A 23 02 Usage Maximum (AC Refresh) 2A 27 02 Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02 Usage (AL Consumer Control Configuration) 0A 83 01 Usage (AL Internet Browser) 0A 96 01 Usage (AL Calculator) 0A 92 01 Usage (AL Terminal Lock/Screensaver) 0A 9E 01 Usage (AL Local Machine Browser) 0A 94 01 Usage (AC Minimize) 0A 06 02 Usage (Record) 09 B2 Usage (Rewind) 09 B4 Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02 End Collection C0
[usbdrv.c : ウェイクアップ可能デバイスにするための変更箇所] #if USB_CFG_IS_SELF_POWERED (1 << 5) | (1 << 7) | USBATTR_SELFPOWER, /* 変更後 */ // (1 << 7) | USBATTR_SELFPOWER, /* 変更前 */ #else (1 << 5) | (1 << 7), /* 変更後 */ // (1 << 7), /* 変更前 */ #endif