qmk_firmware/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c
James Laird-Wah 39bd760faf Use a single endpoint for HID reports (#3951)
* Unify multiple HID interfaces into one

This reduces the number of USB endpoints required, which frees them up
for other things.

NKRO and EXTRAKEY always use the shared endpoint.

By default, MOUSEKEY also uses it. This means it won't work as a Boot
Procotol mouse in some BIOSes, etc. If you really think your
keyboard needs to work as a mouse in your BIOS, set
MOUSE_SHARED_EP = no in your rules.mk.

By default, the core keyboard does not use the shared endpoint, as not
all BIOSes are standards compliant and that's one place you don't want
to find out your keyboard doesn't work.. If you are really confident,
you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here
too.

* unify endpoints: ChibiOS protocol implementation

* fixup: missing #ifdef EXTRAKEY_ENABLEs

broke build on AVR with EXTRAKEY disabled

* endpoints: restore error when too many endpoints required

* lufa: wait up to 10ms to send keyboard input

This avoids packets being dropped when two reports are sent in quick
succession (eg. releasing a dual role key).

* endpoints: fix compile on ARM_ATSAM

* endpoint: ARM_ATSAM fixes

No longer use wrong or unexpected endpoint IDs

* endpoints: accommodate VUSB protocol

V-USB has its own, understandably simple ideas about the report formats.
It already blasts the mouse and extrakeys through one endpoint with
report IDs. We just stay out of its way.

* endpoints: document new endpoint configuration options

* endpoints: respect keyboard_report->mods in NKRO

The caller(s) of host_keyboard_send expect to be able to just drop
modifiers in the mods field and not worry about whether NKRO is in use.
This is a good thing. So we just shift it over if needs be.

* endpoints: report.c: update for new keyboard_report format
2018-11-15 22:22:05 -08:00

993 lines
30 KiB
C

/**
* \file
*
* \brief USB Device Human Interface Device (HID) keyboard interface.
*
* Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#include "samd51j18a.h"
#include "d51_util.h"
#include "conf_usb.h"
#include "usb_protocol.h"
#include "udd.h"
#include "udc.h"
#include "udi_device_conf.h"
#include "udi_hid.h"
#include "udi_hid_kbd.h"
#include <string.h>
#include "report.h"
//***************************************************************************
// KBD
//***************************************************************************
#ifdef KBD
bool udi_hid_kbd_enable(void);
void udi_hid_kbd_disable(void);
bool udi_hid_kbd_setup(void);
uint8_t udi_hid_kbd_getsetting(void);
UDC_DESC_STORAGE udi_api_t udi_api_hid_kbd = {
.enable = (bool(*)(void))udi_hid_kbd_enable,
.disable = (void (*)(void))udi_hid_kbd_disable,
.setup = (bool(*)(void))udi_hid_kbd_setup,
.getsetting = (uint8_t(*)(void))udi_hid_kbd_getsetting,
.sof_notify = NULL,
};
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_kbd_rate;
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_kbd_protocol;
COMPILER_WORD_ALIGNED
uint8_t udi_hid_kbd_report_set;
bool udi_hid_kbd_b_report_valid;
COMPILER_WORD_ALIGNED
uint8_t udi_hid_kbd_report[UDI_HID_KBD_REPORT_SIZE];
volatile bool udi_hid_kbd_b_report_trans_ongoing;
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_kbd_report_trans[UDI_HID_KBD_REPORT_SIZE];
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE udi_hid_kbd_report_desc_t udi_hid_kbd_report_desc = {
{
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x05, 0x07, // Usage Page (Keyboard)
0x19, 0xE0, // Usage Minimum (224)
0x29, 0xE7, // Usage Maximum (231)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data, Variable, Absolute)
0x81, 0x01, // Input (Constant)
0x19, 0x00, // Usage Minimum (0)
0x29, 0x65, // Usage Maximum (101)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x65, // Logical Maximum (101)
0x75, 0x08, // Report Size (8)
0x95, 0x06, // Report Count (6)
0x81, 0x00, // Input (Data, Array)
0x05, 0x08, // Usage Page (LED)
0x19, 0x01, // Usage Minimum (1)
0x29, 0x05, // Usage Maximum (5)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x05, // Report Count (5)
0x91, 0x02, // Output (Data, Variable, Absolute)
0x95, 0x03, // Report Count (3)
0x91, 0x01, // Output (Constant)
0xC0 // End Collection
}
};
static bool udi_hid_kbd_setreport(void);
static void udi_hid_kbd_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep);
static void udi_hid_kbd_setreport_valid(void);
bool udi_hid_kbd_enable(void)
{
// Initialize internal values
udi_hid_kbd_rate = 0;
udi_hid_kbd_protocol = 0;
udi_hid_kbd_b_report_trans_ongoing = false;
memset(udi_hid_kbd_report, 0, UDI_HID_KBD_REPORT_SIZE);
udi_hid_kbd_b_report_valid = false;
return UDI_HID_KBD_ENABLE_EXT();
}
void udi_hid_kbd_disable(void)
{
UDI_HID_KBD_DISABLE_EXT();
}
bool udi_hid_kbd_setup(void)
{
return udi_hid_setup(&udi_hid_kbd_rate,
&udi_hid_kbd_protocol,
(uint8_t *) &udi_hid_kbd_report_desc,
udi_hid_kbd_setreport);
}
uint8_t udi_hid_kbd_getsetting(void)
{
return 0;
}
static bool udi_hid_kbd_setreport(void)
{
if ((USB_HID_REPORT_TYPE_OUTPUT == (udd_g_ctrlreq.req.wValue >> 8))
&& (0 == (0xFF & udd_g_ctrlreq.req.wValue))
&& (1 == udd_g_ctrlreq.req.wLength)) {
// Report OUT type on report ID 0 from USB Host
udd_g_ctrlreq.payload = &udi_hid_kbd_report_set;
udd_g_ctrlreq.callback = udi_hid_kbd_setreport_valid;
udd_g_ctrlreq.payload_size = 1;
return true;
}
return false;
}
bool udi_hid_kbd_send_report(void)
{
if (!main_b_kbd_enable) {
return false;
}
if (udi_hid_kbd_b_report_trans_ongoing) {
return false;
}
memcpy(udi_hid_kbd_report_trans, udi_hid_kbd_report, UDI_HID_KBD_REPORT_SIZE);
udi_hid_kbd_b_report_valid = false;
udi_hid_kbd_b_report_trans_ongoing =
udd_ep_run(UDI_HID_KBD_EP_IN | USB_EP_DIR_IN,
false,
udi_hid_kbd_report_trans,
UDI_HID_KBD_REPORT_SIZE,
udi_hid_kbd_report_sent);
return udi_hid_kbd_b_report_trans_ongoing;
}
static void udi_hid_kbd_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep)
{
UNUSED(status);
UNUSED(nb_sent);
UNUSED(ep);
udi_hid_kbd_b_report_trans_ongoing = false;
if (udi_hid_kbd_b_report_valid) {
udi_hid_kbd_send_report();
}
}
static void udi_hid_kbd_setreport_valid(void)
{
//UDI_HID_KBD_CHANGE_LED(udi_hid_kbd_report_set);
}
#endif //KBD
//********************************************************************************************
// NKRO Keyboard
//********************************************************************************************
#ifdef NKRO
bool udi_hid_nkro_enable(void);
void udi_hid_nkro_disable(void);
bool udi_hid_nkro_setup(void);
uint8_t udi_hid_nkro_getsetting(void);
UDC_DESC_STORAGE udi_api_t udi_api_hid_nkro = {
.enable = (bool(*)(void))udi_hid_nkro_enable,
.disable = (void (*)(void))udi_hid_nkro_disable,
.setup = (bool(*)(void))udi_hid_nkro_setup,
.getsetting = (uint8_t(*)(void))udi_hid_nkro_getsetting,
.sof_notify = NULL,
};
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_nkro_rate;
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_nkro_protocol;
COMPILER_WORD_ALIGNED
uint8_t udi_hid_nkro_report_set;
bool udi_hid_nkro_b_report_valid;
COMPILER_WORD_ALIGNED
uint8_t udi_hid_nkro_report[UDI_HID_NKRO_REPORT_SIZE];
volatile bool udi_hid_nkro_b_report_trans_ongoing;
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_nkro_report_trans[UDI_HID_NKRO_REPORT_SIZE];
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE udi_hid_nkro_report_desc_t udi_hid_nkro_report_desc = {
{
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x06, // Usage (Keyboard),
0xA1, 0x01, // Collection (Application) - Keyboard,
//Mods
0x75, 0x01, // Report Size (1),
0x95, 0x08, // Report Count (8),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0xE0, // Usage Minimum (224),
0x29, 0xE7, // Usage Maximum (231),
0x81, 0x02, // Input (Data, Variable, Absolute),
//LED Report
0x75, 0x01, // Report Size (1),
0x95, 0x05, // Report Count (5),
0x05, 0x08, // Usage Page (LEDs),
0x19, 0x01, // Usage Minimum (1),
0x29, 0x05, // Usage Maximum (5),
0x91, 0x02, // Output (Data, Variable, Absolute),
//LED Report Padding
0x75, 0x03, // Report Size (3),
0x95, 0x01, // Report Count (1),
0x91, 0x03, // Output (Constant),
//Main keys
0x75, 0x01, // Report Size (1),
0x95, 0xF8, // Report Count (248),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0x00, // Usage Minimum (0),
0x29, 0xF7, // Usage Maximum (247),
0x81, 0x02, // Input (Data, Variable, Absolute, Bitfield),
0xc0, // End Collection - Keyboard
}
};
static bool udi_hid_nkro_setreport(void);
static void udi_hid_nkro_setreport_valid(void);
static void udi_hid_nkro_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep);
bool udi_hid_nkro_enable(void)
{
// Initialize internal values
udi_hid_nkro_rate = 0;
udi_hid_nkro_protocol = 0;
udi_hid_nkro_b_report_trans_ongoing = false;
memset(udi_hid_nkro_report, 0, UDI_HID_NKRO_REPORT_SIZE);
udi_hid_nkro_b_report_valid = false;
return UDI_HID_NKRO_ENABLE_EXT();
}
void udi_hid_nkro_disable(void)
{
UDI_HID_NKRO_DISABLE_EXT();
}
bool udi_hid_nkro_setup(void)
{
return udi_hid_setup(&udi_hid_nkro_rate,
&udi_hid_nkro_protocol,
(uint8_t *) &udi_hid_nkro_report_desc,
udi_hid_nkro_setreport);
}
uint8_t udi_hid_nkro_getsetting(void)
{
return 0;
}
//keyboard receives LED report here
static bool udi_hid_nkro_setreport(void)
{
if ((USB_HID_REPORT_TYPE_OUTPUT == (udd_g_ctrlreq.req.wValue >> 8))
&& (0 == (0xFF & udd_g_ctrlreq.req.wValue))
&& (1 == udd_g_ctrlreq.req.wLength)) {
// Report OUT type on report ID 0 from USB Host
udd_g_ctrlreq.payload = &udi_hid_nkro_report_set;
udd_g_ctrlreq.callback = udi_hid_nkro_setreport_valid; //must call routine to transform setreport to LED state
udd_g_ctrlreq.payload_size = 1;
return true;
}
return false;
}
bool udi_hid_nkro_send_report(void)
{
if (!main_b_nkro_enable) {
return false;
}
if (udi_hid_nkro_b_report_trans_ongoing) {
return false;
}
memcpy(udi_hid_nkro_report_trans, udi_hid_nkro_report, UDI_HID_NKRO_REPORT_SIZE);
udi_hid_nkro_b_report_valid = false;
udi_hid_nkro_b_report_trans_ongoing =
udd_ep_run(UDI_HID_NKRO_EP_IN | USB_EP_DIR_IN,
false,
udi_hid_nkro_report_trans,
UDI_HID_NKRO_REPORT_SIZE,
udi_hid_nkro_report_sent);
return udi_hid_nkro_b_report_trans_ongoing;
}
static void udi_hid_nkro_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep)
{
UNUSED(status);
UNUSED(nb_sent);
UNUSED(ep);
udi_hid_nkro_b_report_trans_ongoing = false;
if (udi_hid_nkro_b_report_valid) {
udi_hid_nkro_send_report();
}
}
static void udi_hid_nkro_setreport_valid(void)
{
//UDI_HID_NKRO_CHANGE_LED(udi_hid_nkro_report_set);
}
#endif //NKRO
//********************************************************************************************
// EXK (extra-keys) SYS-CTRL Keyboard
//********************************************************************************************
#ifdef EXK
bool udi_hid_exk_enable(void);
void udi_hid_exk_disable(void);
bool udi_hid_exk_setup(void);
uint8_t udi_hid_exk_getsetting(void);
UDC_DESC_STORAGE udi_api_t udi_api_hid_exk = {
.enable = (bool(*)(void))udi_hid_exk_enable,
.disable = (void (*)(void))udi_hid_exk_disable,
.setup = (bool(*)(void))udi_hid_exk_setup,
.getsetting = (uint8_t(*)(void))udi_hid_exk_getsetting,
.sof_notify = NULL,
};
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_exk_rate;
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_exk_protocol;
COMPILER_WORD_ALIGNED
uint8_t udi_hid_exk_report_set;
bool udi_hid_exk_b_report_valid;
COMPILER_WORD_ALIGNED
udi_hid_exk_report_t udi_hid_exk_report;
static bool udi_hid_exk_b_report_trans_ongoing;
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_exk_report_trans[UDI_HID_EXK_REPORT_SIZE];
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE udi_hid_exk_report_desc_t udi_hid_exk_report_desc = {
{
// System Control Collection (8 bits)
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x80, // Usage (System Control),
0xA1, 0x01, // Collection (Application),
0x85, REPORT_ID_SYSTEM, // Report ID (2) (System),
0x16, 0x01, 0x00, // Logical Minimum (1),
0x26, 0x03, 0x00, // Logical Maximum (3),
0x1A, 0x81, 0x00, // Usage Minimum (81) (System Power Down),
0x2A, 0x83, 0x00, // Usage Maximum (83) (System Wake Up),
0x75, 0x10, // Report Size (16),
0x95, 0x01, // Report Count (1),
0x81, 0x00, // Input (Data, Array),
0xC0, // End Collection - System Control
// Consumer Control Collection - Media Keys (16 bits)
0x05, 0x0C, // Usage Page (Consumer),
0x09, 0x01, // Usage (Consumer Control),
0xA1, 0x01, // Collection (Application),
0x85, REPORT_ID_CONSUMER, // Report ID (3) (Consumer),
0x16, 0x01, 0x00, // Logical Minimum (1),
0x26, 0x9C, 0x02, // Logical Maximum (668),
0x1A, 0x01, 0x00, // Usage Minimum (1),
0x2A, 0x9C, 0x02, // Usage Maximum (668),
0x75, 0x10, // Report Size (16),
0x95, 0x01, // Report Count (1),
0x81, 0x00, // Input (Data, Array),
0xC0, // End Collection - Consumer Control
}
};
static bool udi_hid_exk_setreport(void);
static void udi_hid_exk_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep);
static void udi_hid_exk_setreport_valid(void);
bool udi_hid_exk_enable(void)
{
// Initialize internal values
udi_hid_exk_rate = 0;
udi_hid_exk_protocol = 0;
udi_hid_exk_b_report_trans_ongoing = false;
memset(udi_hid_exk_report.raw, 0, UDI_HID_EXK_REPORT_SIZE);
udi_hid_exk_b_report_valid = false;
return UDI_HID_EXK_ENABLE_EXT();
}
void udi_hid_exk_disable(void)
{
UDI_HID_EXK_DISABLE_EXT();
}
bool udi_hid_exk_setup(void)
{
return udi_hid_setup(&udi_hid_exk_rate,
&udi_hid_exk_protocol,
(uint8_t *) &udi_hid_exk_report_desc,
udi_hid_exk_setreport);
}
uint8_t udi_hid_exk_getsetting(void)
{
return 0;
}
static bool udi_hid_exk_setreport(void)
{
if ((USB_HID_REPORT_TYPE_OUTPUT == (udd_g_ctrlreq.req.wValue >> 8))
&& (0 == (0xFF & udd_g_ctrlreq.req.wValue))
&& (1 == udd_g_ctrlreq.req.wLength)) {
// Report OUT type on report ID 0 from USB Host
udd_g_ctrlreq.payload = &udi_hid_exk_report_set;
udd_g_ctrlreq.callback = udi_hid_exk_setreport_valid;
udd_g_ctrlreq.payload_size = 1;
return true;
}
return false;
}
bool udi_hid_exk_send_report(void)
{
if (!main_b_exk_enable) {
return false;
}
if (udi_hid_exk_b_report_trans_ongoing) {
return false;
}
memcpy(udi_hid_exk_report_trans, udi_hid_exk_report.raw, UDI_HID_EXK_REPORT_SIZE);
udi_hid_exk_b_report_valid = false;
udi_hid_exk_b_report_trans_ongoing =
udd_ep_run(UDI_HID_EXK_EP_IN | USB_EP_DIR_IN,
false,
udi_hid_exk_report_trans,
UDI_HID_EXK_REPORT_SIZE,
udi_hid_exk_report_sent);
return udi_hid_exk_b_report_trans_ongoing;
}
static void udi_hid_exk_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep)
{
UNUSED(status);
UNUSED(nb_sent);
UNUSED(ep);
udi_hid_exk_b_report_trans_ongoing = false;
if (udi_hid_exk_b_report_valid) {
udi_hid_exk_send_report();
}
}
static void udi_hid_exk_setreport_valid(void)
{
}
#endif //EXK
//********************************************************************************************
// MOU Mouse
//********************************************************************************************
#ifdef MOU
bool udi_hid_mou_enable(void);
void udi_hid_mou_disable(void);
bool udi_hid_mou_setup(void);
uint8_t udi_hid_mou_getsetting(void);
UDC_DESC_STORAGE udi_api_t udi_api_hid_mou = {
.enable = (bool(*)(void))udi_hid_mou_enable,
.disable = (void (*)(void))udi_hid_mou_disable,
.setup = (bool(*)(void))udi_hid_mou_setup,
.getsetting = (uint8_t(*)(void))udi_hid_mou_getsetting,
.sof_notify = NULL,
};
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_mou_rate;
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_mou_protocol;
//COMPILER_WORD_ALIGNED
//uint8_t udi_hid_mou_report_set; //No set report
bool udi_hid_mou_b_report_valid;
COMPILER_WORD_ALIGNED
uint8_t udi_hid_mou_report[UDI_HID_MOU_REPORT_SIZE];
static bool udi_hid_mou_b_report_trans_ongoing;
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_mou_report_trans[UDI_HID_MOU_REPORT_SIZE];
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE udi_hid_mou_report_desc_t udi_hid_mou_report_desc = {
{
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x02, // Usage (Mouse),
0xA1, 0x01, // Collection (Application),
0x09, 0x01, // Usage (Pointer),
0xA1, 0x00, // Collection (Physical),
0x05, 0x09, // Usage Page (Buttons),
0x19, 0x01, // Usage Minimum (01),
0x29, 0x05, // Usage Maximun (05),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x95, 0x05, // Report Count (5),
0x75, 0x01, // Report Size (1),
0x81, 0x02, // Input (Data, Variable, Absolute), ;5 button bits
0x95, 0x01, // Report Count (1),
0x75, 0x03, // Report Size (3),
0x81, 0x01, // Input (Constant), ;3 bit padding,
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x30, // Usage (X),
0x09, 0x31, // Usage (Y),
0x15, 0x81, // Logical Minimum (-127),
0x25, 0x7F, // Logical Maximum (127),
0x95, 0x02, // Report Count (2),
0x75, 0x08, // Report Size (8),
0x81, 0x06, // Input (Data, Variable, Relative), ;2 position bytes (X & Y),
0x09, 0x38, // Usage (Wheel),
0x15, 0x81, // Logical Minimum (-127),
0x25, 0x7F, // Logical Maximum (127),
0x95, 0x01, // Report Count (1),
0x75, 0x08, // Report Size (8),
0x81, 0x06, // Input (Data, Variable, Relative),
0x05, 0x0C, // Usage Page (Consumer),
0x0A, 0x38, 0x02, // Usage (AC Pan (Horizontal wheel)),
0x15, 0x81, // Logical Minimum (-127),
0x25, 0x7F, // Logical Maximum (127),
0x95, 0x01, // Report Count (1),
0x75, 0x08, // Report Size (8),
0x81, 0x06, // Input (Data, Variable, Relative),
0xC0, // End Collection,
0xC0, // End Collection
}
};
static void udi_hid_mou_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep);
bool udi_hid_mou_enable(void)
{
// Initialize internal values
udi_hid_mou_rate = 0;
udi_hid_mou_protocol = 0;
udi_hid_mou_b_report_trans_ongoing = false;
memset(udi_hid_mou_report, 0, UDI_HID_MOU_REPORT_SIZE);
udi_hid_mou_b_report_valid = false;
return UDI_HID_MOU_ENABLE_EXT();
}
void udi_hid_mou_disable(void)
{
UDI_HID_MOU_DISABLE_EXT();
}
bool udi_hid_mou_setup(void)
{
return udi_hid_setup(&udi_hid_mou_rate,
&udi_hid_mou_protocol,
(uint8_t *) &udi_hid_mou_report_desc,
NULL);
}
uint8_t udi_hid_mou_getsetting(void)
{
return 0;
}
bool udi_hid_mou_send_report(void)
{
if (!main_b_mou_enable) {
return false;
}
if (udi_hid_mou_b_report_trans_ongoing) {
return false;
}
memcpy(udi_hid_mou_report_trans, udi_hid_mou_report, UDI_HID_MOU_REPORT_SIZE);
udi_hid_mou_b_report_valid = false;
udi_hid_mou_b_report_trans_ongoing =
udd_ep_run(UDI_HID_MOU_EP_IN | USB_EP_DIR_IN,
false,
udi_hid_mou_report_trans,
UDI_HID_MOU_REPORT_SIZE,
udi_hid_mou_report_sent);
return udi_hid_mou_b_report_trans_ongoing;
}
static void udi_hid_mou_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep)
{
UNUSED(status);
UNUSED(nb_sent);
UNUSED(ep);
udi_hid_mou_b_report_trans_ongoing = false;
if (udi_hid_mou_b_report_valid) {
udi_hid_mou_send_report();
}
}
#endif //MOU
//********************************************************************************************
// RAW
//********************************************************************************************
#ifdef RAW
bool udi_hid_raw_enable(void);
void udi_hid_raw_disable(void);
bool udi_hid_raw_setup(void);
uint8_t udi_hid_raw_getsetting(void);
UDC_DESC_STORAGE udi_api_t udi_api_hid_raw = {
.enable = (bool(*)(void))udi_hid_raw_enable,
.disable = (void (*)(void))udi_hid_raw_disable,
.setup = (bool(*)(void))udi_hid_raw_setup,
.getsetting = (uint8_t(*)(void))udi_hid_raw_getsetting,
.sof_notify = NULL,
};
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_raw_rate;
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_raw_protocol;
COMPILER_WORD_ALIGNED
uint8_t udi_hid_raw_report_set[UDI_HID_RAW_REPORT_SIZE];
static bool udi_hid_raw_b_report_valid;
COMPILER_WORD_ALIGNED
uint8_t udi_hid_raw_report[UDI_HID_RAW_REPORT_SIZE];
static bool udi_hid_raw_b_report_trans_ongoing;
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_raw_report_trans[UDI_HID_RAW_REPORT_SIZE];
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE udi_hid_raw_report_desc_t udi_hid_raw_report_desc = {
{
0x06, // Usage Page (Vendor Defined)
0xFF, 0xFF,
0x0A, // Usage (Mouse)
0xFF, 0xFF,
0xA1, 0x01, // Collection (Application)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0xFF, // Logical Maximum (255)
0x95, 0x40, // Report Count
0x09, 0x01, // Usage (Input)
0x81, 0x02, // Input (Data
0x95, 0x40, // Report Count
0x09, 0x02, // Usage (Output)
0x91, 0x02, // Output (Data
0xC0, // End Collection - Consumer Control
}
};
static bool udi_hid_raw_setreport(void);
static void udi_hid_raw_setreport_valid(void);
static void udi_hid_raw_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep);
bool udi_hid_raw_enable(void)
{
// Initialize internal values
udi_hid_raw_rate = 0;
udi_hid_raw_protocol = 0;
udi_hid_raw_b_report_trans_ongoing = false;
memset(udi_hid_raw_report, 0, UDI_HID_RAW_REPORT_SIZE);
udi_hid_raw_b_report_valid = false;
return UDI_HID_RAW_ENABLE_EXT();
}
void udi_hid_raw_disable(void)
{
UDI_HID_RAW_DISABLE_EXT();
}
bool udi_hid_raw_setup(void)
{
return udi_hid_setup(&udi_hid_raw_rate,
&udi_hid_raw_protocol,
(uint8_t *) &udi_hid_raw_report_desc,
udi_hid_raw_setreport);
}
uint8_t udi_hid_raw_getsetting(void)
{
return 0;
}
static bool udi_hid_raw_setreport(void)
{
if ((USB_HID_REPORT_TYPE_OUTPUT == (udd_g_ctrlreq.req.wValue >> 8))
&& (0 == (0xFF & udd_g_ctrlreq.req.wValue))
&& (UDI_HID_RAW_REPORT_SIZE == udd_g_ctrlreq.req.wLength)) {
// Report OUT type on report ID 0 from USB Host
udd_g_ctrlreq.payload = udi_hid_raw_report_set;
udd_g_ctrlreq.callback = udi_hid_raw_setreport_valid; //must call routine to transform setreport to LED state
udd_g_ctrlreq.payload_size = UDI_HID_RAW_REPORT_SIZE;
return true;
}
return false;
}
bool udi_hid_raw_send_report(void)
{
if (!main_b_raw_enable) {
return false;
}
if (udi_hid_raw_b_report_trans_ongoing) {
return false;
}
memcpy(udi_hid_raw_report_trans, udi_hid_raw_report,UDI_HID_RAW_REPORT_SIZE);
udi_hid_raw_b_report_valid = false;
udi_hid_raw_b_report_trans_ongoing =
udd_ep_run(UDI_HID_RAW_EP_IN | USB_EP_DIR_IN,
false,
udi_hid_raw_report_trans,
UDI_HID_RAW_REPORT_SIZE,
udi_hid_raw_report_sent);
return udi_hid_raw_b_report_trans_ongoing;
}
static void udi_hid_raw_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep)
{
UNUSED(status);
UNUSED(nb_sent);
UNUSED(ep);
udi_hid_raw_b_report_trans_ongoing = false;
if (udi_hid_raw_b_report_valid) {
udi_hid_raw_send_report();
}
}
static void udi_hid_raw_setreport_valid(void)
{
}
#endif //RAW
//********************************************************************************************
// CON
//********************************************************************************************
#ifdef CON
bool udi_hid_con_enable(void);
void udi_hid_con_disable(void);
bool udi_hid_con_setup(void);
uint8_t udi_hid_con_getsetting(void);
UDC_DESC_STORAGE udi_api_t udi_api_hid_con = {
.enable = (bool(*)(void))udi_hid_con_enable,
.disable = (void (*)(void))udi_hid_con_disable,
.setup = (bool(*)(void))udi_hid_con_setup,
.getsetting = (uint8_t(*)(void))udi_hid_con_getsetting,
.sof_notify = NULL,
};
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_con_rate;
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_con_protocol;
COMPILER_WORD_ALIGNED
uint8_t udi_hid_con_report_set[UDI_HID_CON_REPORT_SIZE];
bool udi_hid_con_b_report_valid;
COMPILER_WORD_ALIGNED
uint8_t udi_hid_con_report[UDI_HID_CON_REPORT_SIZE];
volatile bool udi_hid_con_b_report_trans_ongoing;
COMPILER_WORD_ALIGNED
static uint8_t udi_hid_con_report_trans[UDI_HID_CON_REPORT_SIZE];
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE udi_hid_con_report_desc_t udi_hid_con_report_desc = {
{
0x06, 0x31, 0xFF, // Vendor Page (PJRC Teensy compatible)
0x09, 0x74, // Vendor Usage (PJRC Teensy compatible)
0xA1, 0x01, // Collection (Application)
0x09, 0x75, // Usage (Vendor)
0x15, 0x00, // Logical Minimum (0x00)
0x26, 0xFF, 0x00, // Logical Maximum (0x00FF)
0x95, CONSOLE_EPSIZE, // Report Count
0x75, 0x08, // Report Size (8)
0x81, 0x02, // Input (Data)
0x09, 0x76, // Usage (Vendor)
0x15, 0x00, // Logical Minimum (0x00)
0x26, 0xFF, 0x00, // Logical Maximum (0x00FF)
0x95, CONSOLE_EPSIZE, // Report Count
0x75, 0x08, // Report Size (8)
0x91, 0x02, // Output (Data)
0xC0, // End Collection
}
};
static bool udi_hid_con_setreport(void);
static void udi_hid_con_setreport_valid(void);
static void udi_hid_con_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep);
bool udi_hid_con_enable(void)
{
// Initialize internal values
udi_hid_con_rate = 0;
udi_hid_con_protocol = 0;
udi_hid_con_b_report_trans_ongoing = false;
memset(udi_hid_con_report, 0, UDI_HID_CON_REPORT_SIZE);
udi_hid_con_b_report_valid = false;
return UDI_HID_CON_ENABLE_EXT();
}
void udi_hid_con_disable(void)
{
UDI_HID_CON_DISABLE_EXT();
}
bool udi_hid_con_setup(void)
{
return udi_hid_setup(&udi_hid_con_rate,
&udi_hid_con_protocol,
(uint8_t *) &udi_hid_con_report_desc,
udi_hid_con_setreport);
}
uint8_t udi_hid_con_getsetting(void)
{
return 0;
}
static bool udi_hid_con_setreport(void)
{
if ((USB_HID_REPORT_TYPE_OUTPUT == (udd_g_ctrlreq.req.wValue >> 8))
&& (0 == (0xFF & udd_g_ctrlreq.req.wValue))
&& (UDI_HID_CON_REPORT_SIZE == udd_g_ctrlreq.req.wLength)) {
udd_g_ctrlreq.payload = udi_hid_con_report_set;
udd_g_ctrlreq.callback = udi_hid_con_setreport_valid;
udd_g_ctrlreq.payload_size = UDI_HID_CON_REPORT_SIZE;
return true;
}
return false;
}
bool udi_hid_con_send_report(void)
{
if (!main_b_con_enable) {
return false;
}
if (udi_hid_con_b_report_trans_ongoing) {
return false;
}
memcpy(udi_hid_con_report_trans, udi_hid_con_report,UDI_HID_CON_REPORT_SIZE);
udi_hid_con_b_report_valid = false;
udi_hid_con_b_report_trans_ongoing =
udd_ep_run(UDI_HID_CON_EP_IN | USB_EP_DIR_IN,
false,
udi_hid_con_report_trans,
UDI_HID_CON_REPORT_SIZE,
udi_hid_con_report_sent);
return udi_hid_con_b_report_trans_ongoing;
}
static void udi_hid_con_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep)
{
UNUSED(status);
UNUSED(nb_sent);
UNUSED(ep);
udi_hid_con_b_report_trans_ongoing = false;
if (udi_hid_con_b_report_valid) {
udi_hid_con_send_report();
}
}
static void udi_hid_con_setreport_valid(void)
{
}
#endif //CON