From 539aa85d6a88a4b913dbea2e694fa1faa110ea5c Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sun, 10 Dec 2017 00:39:57 +0100 Subject: [PATCH] Add a special `WakeupKeyboard`, to be able to wake the host up At least on Linux, for a device to be considered capable of waking the host up, it must be a boot keyboard. As we do not (yet) support a boot keyboard, we fake one. An USB node that does nothing else than report itself as a boot keyboard, and does the minimum amount of work to get recognised as such. Because of this, Linux - and hopefully the other OSes too - will consider the whole device capable of waking up the host. This addresses keyboardio/Kaleidoscope#237, if all goes well. Signed-off-by: Gergely Nagy --- README.md | 7 +++ examples/MyOldFriend/MyOldFriend.ino | 2 + src/Kaleidoscope/MyOldFriend.h | 2 + src/Kaleidoscope/WakeupKeyboard.cpp | 91 ++++++++++++++++++++++++++++ src/Kaleidoscope/WakeupKeyboard.h | 38 ++++++++++++ 5 files changed, 140 insertions(+) create mode 100644 src/Kaleidoscope/WakeupKeyboard.cpp create mode 100644 src/Kaleidoscope/WakeupKeyboard.h diff --git a/README.md b/README.md index 10a86b40..21bebdf6 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,13 @@ void setup () { The plugin provides the `MyOldFriend` object, which has the following methods: +### `.enableWakeup()` + +> Enables host wakeup support. When enabled, pressing any key on the keyboard +> will wake the host up. +> +> Once enabled, it **cannot** be disabled again. + ### `.toggleLEDs(event)` > Turns LEDs off on suspend, restores the previous LED mode on resume. This is diff --git a/examples/MyOldFriend/MyOldFriend.ino b/examples/MyOldFriend/MyOldFriend.ino index 30c2937a..93c0ebc4 100644 --- a/examples/MyOldFriend/MyOldFriend.ino +++ b/examples/MyOldFriend/MyOldFriend.ino @@ -45,6 +45,8 @@ void setup() { Kaleidoscope.setup(); Kaleidoscope.use(&MyOldFriend); + + MyOldFriend.enableWakeup(); } void loop() { diff --git a/src/Kaleidoscope/MyOldFriend.h b/src/Kaleidoscope/MyOldFriend.h index e49a7aaf..93d939ea 100644 --- a/src/Kaleidoscope/MyOldFriend.h +++ b/src/Kaleidoscope/MyOldFriend.h @@ -19,6 +19,7 @@ #pragma once #include +#include "WakeupKeyboard.h" namespace kaleidoscope { class MyOldFriend : public KaleidoscopePlugin { @@ -32,6 +33,7 @@ class MyOldFriend : public KaleidoscopePlugin { MyOldFriend(void) {}; void begin(void) final; + void enableWakeup(void) { WakeupKeyboard.begin(); }; void toggleLEDs(Event event); diff --git a/src/Kaleidoscope/WakeupKeyboard.cpp b/src/Kaleidoscope/WakeupKeyboard.cpp new file mode 100644 index 00000000..74fad060 --- /dev/null +++ b/src/Kaleidoscope/WakeupKeyboard.cpp @@ -0,0 +1,91 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-MyOldFriend -- Host sleep support plugin. + * Copyright (C) 2017 Gergely Nagy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "WakeupKeyboard.h" + +static const uint8_t _hidReportDescriptorKeyboard[] PROGMEM = { + // Keyboard + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ + 0x09, 0x06, /* USAGE (Keyboard) */ + 0xa1, 0x01, /* COLLECTION (Application) */ + 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ + + /* 0 LEDs, to have something the host can work with. */ + 0x05, 0x08, /* USAGE_PAGE (LEDs) */ + 0x19, 0x00, /* USAGE_MINIMUM (-) */ + 0x29, 0x00, /* USAGE_MAXIMUM (-) */ + 0x95, 0x00, /* REPORT_COUNT (0) */ + 0x75, 0x00, /* REPORT_SIZE (0) */ + 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ + + /* End */ + 0xc0 /* END_COLLECTION */ +}; + +WakeupKeyboard_::WakeupKeyboard_(void) : PluggableUSBModule(1, 1, epType) { + epType[0] = EP_TYPE_INTERRUPT_IN; + PluggableUSB().plug(this); +} + +int WakeupKeyboard_::getInterface(uint8_t* interfaceCount) { + *interfaceCount += 1; + HIDDescriptor hidInterface = { + D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_BOOT_INTERFACE, HID_PROTOCOL_KEYBOARD), + D_HIDREPORT(sizeof(_hidReportDescriptorKeyboard)), + D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) + }; + return USB_SendControl(0, &hidInterface, sizeof(hidInterface)); +} + +int WakeupKeyboard_::getDescriptor(USBSetup& setup) { + if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { + return 0; + } + if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { + return 0; + } + + if (setup.wIndex != pluggedInterface) { + return 0; + } + + return USB_SendControl(TRANSFER_PGM, _hidReportDescriptorKeyboard, sizeof(_hidReportDescriptorKeyboard)); +} + +bool WakeupKeyboard_::setup(USBSetup& setup) { + if (pluggedInterface != setup.wIndex) { + return false; + } + + uint8_t request = setup.bRequest; + uint8_t requestType = setup.bmRequestType; + + if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) { + if (request == HID_GET_PROTOCOL) { + UEDATX = HID_BOOT_PROTOCOL; + return true; + } + } + + return false; +} + +void WakeupKeyboard_::begin () { +} + +WakeupKeyboard_ WakeupKeyboard; diff --git a/src/Kaleidoscope/WakeupKeyboard.h b/src/Kaleidoscope/WakeupKeyboard.h new file mode 100644 index 00000000..6b127f9b --- /dev/null +++ b/src/Kaleidoscope/WakeupKeyboard.h @@ -0,0 +1,38 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-MyOldFriend -- Host sleep support plugin. + * Copyright (C) 2017 Gergely Nagy + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include "PluggableUSB.h" +#include "HID.h" + +class WakeupKeyboard_ : public PluggableUSBModule, public KaleidoscopePlugin { + public: + WakeupKeyboard_(void); + void begin() final; + + protected: + int getInterface(uint8_t* interfaceCount); + int getDescriptor(USBSetup& setup); + bool setup(USBSetup& setup); + + uint8_t epType[1]; +}; + +extern WakeupKeyboard_ WakeupKeyboard;