[HID] port to stable PluggableUSB API

This commit is contained in:
Martino Facchin 2015-10-12 14:41:23 +02:00
parent b4541209cb
commit ddae105dc3
2 changed files with 169 additions and 162 deletions

View File

@ -13,156 +13,134 @@
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
** SOFTWARE.
** SOFTWARE.
*/
#include "USB/PluggableUSB.h"
#include "HID.h"
HID_ HID;
#if defined(USBCON)
static uint8_t HID_ENDPOINT_INT;
//================================================================================
//================================================================================
// HID report descriptor
#define LSB(_x) ((_x) & 0xFF)
#define MSB(_x) ((_x) >> 8)
#define RAWHID_USAGE_PAGE 0xFFC0
#define RAWHID_USAGE 0x0C00
#define RAWHID_TX_SIZE 64
#define RAWHID_RX_SIZE 64
static uint8_t HID_INTERFACE;
HIDDescriptor _hidInterface;
static HIDDescriptorListNode* rootNode = NULL;
static uint8_t sizeof_hidReportDescriptor = 0;
static uint8_t modules_count = 0;
//================================================================================
//================================================================================
// Driver
uint8_t _hid_protocol = 1;
uint8_t _hid_idle = 1;
int HID_GetInterface(uint8_t* interfaceNum)
HID_& HID()
{
interfaceNum[0] += 1; // uses 1
_hidInterface =
{
D_INTERFACE(HID_INTERFACE,1,3,0,0),
D_HIDREPORT(sizeof_hidReportDescriptor),
D_ENDPOINT(USB_ENDPOINT_IN (HID_ENDPOINT_INT),USB_ENDPOINT_TYPE_INTERRUPT,0x40,0x01)
static HID_ obj;
return obj;
}
int HID_::getInterface(uint8_t* interfaceCount)
{
*interfaceCount += 1; // uses 1
HIDDescriptor hidInterface = {
D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE),
D_HIDREPORT(descriptorSize),
D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, 0x40, 0x01)
};
return USBD_SendControl(0,&_hidInterface,sizeof(_hidInterface));
return USBD_SendControl(0, &hidInterface, sizeof(hidInterface));
}
int HID_GetDescriptor(int8_t t)
int HID_::getDescriptor(USBSetup& setup)
{
if (HID_REPORT_DESCRIPTOR_TYPE == t) {
HIDDescriptorListNode* current = rootNode;
int total = 0;
while(current != NULL) {
total += USBD_SendControl(0,current->data,current->length);
current = current->next;
}
return total;
} else {
return 0;
// Check if this is a HID Class Descriptor request
if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; }
if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; }
// In a HID Class Descriptor wIndex cointains the interface number
if (setup.wIndex != pluggedInterface) { return 0; }
int total = 0;
HIDSubDescriptor* node;
for (node = rootNode; node; node = node->next) {
int res = USBD_SendControl(0, node->data, node->length);
if (res == -1)
return -1;
total += res;
}
return total;
}
void HID_::AppendDescriptor(HIDDescriptorListNode *node)
void HID_::AppendDescriptor(HIDSubDescriptor *node)
{
if (modules_count == 0) {
if (!rootNode) {
rootNode = node;
} else {
HIDDescriptorListNode *current = rootNode;
while(current->next != NULL) {
HIDSubDescriptor *current = rootNode;
while (current->next) {
current = current->next;
}
current->next = node;
}
modules_count++;
sizeof_hidReportDescriptor += node->length;
descriptorSize += node->length;
}
void HID_::SendReport(uint8_t id, const void* data, int len)
{
uint8_t p[64];
const uint8_t *d = reinterpret_cast<const uint8_t *>(data);
p[0] = id;
for (uint32_t i=0; i<len; i++)
p[i+1] = d[i];
USBD_Send(HID_TX, p, len+1);
memcpy(&p[1], data, len);
USBD_Send(pluggedEndpoint, p, len+1);
}
bool HID_Setup(USBSetup& setup, uint8_t i)
bool HID_::setup(USBSetup& setup)
{
if (HID_INTERFACE != i) {
return false;
} else {
uint8_t r = setup.bRequest;
uint8_t requestType = setup.bmRequestType;
if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType)
{
if (HID_GET_REPORT == r)
{
//HID_GetReport();
return true;
}
if (HID_GET_PROTOCOL == r)
{
//Send8(_hid_protocol); // TODO
return true;
}
}
if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
{
if (HID_SET_PROTOCOL == r)
{
_hid_protocol = setup.wValueL;
return true;
}
if (HID_SET_IDLE == r)
{
_hid_idle = setup.wValueL;
return true;
}
}
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_REPORT) {
// TODO: HID_GetReport();
return true;
}
if (request == HID_GET_PROTOCOL) {
// TODO: Send8(protocol);
return true;
}
if (request == HID_GET_IDLE) {
// TODO: Send8(idle);
}
}
if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE)
{
if (request == HID_SET_PROTOCOL) {
// The USB Host tells us if we are in boot or report mode.
// This only works with a real boot compatible device.
protocol = setup.wValueL;
return true;
}
if (request == HID_SET_IDLE) {
idle = setup.wValueL;
return true;
}
if (request == HID_SET_REPORT)
{
//uint8_t reportID = setup.wValueL;
//uint16_t length = setup.wLength;
//uint8_t data[length];
// Make sure to not read more data than USB_EP_SIZE.
// You can read multiple times through a loop.
// The first byte (may!) contain the reportID on a multreport.
//USB_RecvControl(data, length);
}
}
return false;
}
HID_::HID_(void)
HID_::HID_(void) : PluggableUSBModule(1, 1, epType),
rootNode(NULL), descriptorSize(0),
protocol(1), idle(1)
{
static uint32_t endpointType[1];
endpointType[0] = EP_TYPE_INTERRUPT_IN;
static PUSBCallbacks cb = {
.setup = &HID_Setup,
.getInterface = &HID_GetInterface,
.getDescriptor = &HID_GetDescriptor,
.numEndpoints = 1,
.numInterfaces = 1,
.endpointType = endpointType,
};
static PUSBListNode node(&cb);
HID_ENDPOINT_INT = PUSB_AddFunction(&node, &HID_INTERFACE);
epType[0] = EP_TYPE_INTERRUPT_IN;
PluggableUSB().plug(this);
}
int HID_::begin(void)
{
return 0;
}
#endif /* if defined(USBCON) */

View File

@ -1,36 +1,34 @@
/*
HID.h
Copyright (c) 2015, Arduino LLC
Original code (pre-library): Copyright (c) 2011, Peter Barrett
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
*/
#ifndef HID_h
#define HID_h
#include <stdint.h>
#include <Arduino.h>
#include "USB/PluggableUSB.h"
#if defined(USBCON)
#define _USING_HID
//================================================================================
//================================================================================
// HID 'Driver'
// HID 'Driver'
// ------------
#define HID_GET_REPORT 0x01
#define HID_GET_IDLE 0x02
#define HID_GET_PROTOCOL 0x03
@ -42,49 +40,80 @@
#define HID_REPORT_DESCRIPTOR_TYPE 0x22
#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23
class HIDDescriptorListNode {
// HID subclass HID1.11 Page 8 4.2 Subclass
#define HID_SUBCLASS_NONE 0
#define HID_SUBCLASS_BOOT_INTERFACE 1
// HID Keyboard/Mouse bios compatible protocols HID1.11 Page 9 4.3 Protocols
#define HID_PROTOCOL_NONE 0
#define HID_PROTOCOL_KEYBOARD 1
#define HID_PROTOCOL_MOUSE 2
// Normal or bios protocol (Keyboard/Mouse) HID1.11 Page 54 7.2.5 Get_Protocol Request
// "protocol" variable is used for this purpose.
#define HID_BOOT_PROTOCOL 0
#define HID_REPORT_PROTOCOL 1
typedef struct
{
uint8_t len; // 9
uint8_t dtype; // 0x21
uint8_t addr;
uint8_t versionL; // 0x101
uint8_t versionH; // 0x101
uint8_t country;
uint8_t desctype; // 0x22 report
uint8_t descLenL;
uint8_t descLenH;
} HIDDescDescriptor;
typedef struct
{
InterfaceDescriptor hid;
HIDDescDescriptor desc;
EndpointDescriptor in;
} HIDDescriptor;
class HIDSubDescriptor {
public:
HIDDescriptorListNode *next = NULL;
HIDDescriptorListNode(const void *d, const uint16_t l) : data(d), length(l) { }
HIDSubDescriptor *next = NULL;
HIDSubDescriptor(const void *d, const uint16_t l) : data(d), length(l) { }
const void* data;
const uint16_t length;
};
class HID_
class HID_ : public PluggableUSBModule
{
public:
HID_(void);
int begin(void);
void SendReport(uint8_t id, const void* data, int len);
void AppendDescriptor(HIDDescriptorListNode* node);
void AppendDescriptor(HIDSubDescriptor* node);
protected:
// Implementation of the PluggableUSBModule
int getInterface(uint8_t* interfaceCount);
int getDescriptor(USBSetup& setup);
bool setup(USBSetup& setup);
private:
uint32_t epType[1];
HIDSubDescriptor* rootNode;
uint16_t descriptorSize;
uint8_t protocol;
uint8_t idle;
};
typedef struct
{
uint8_t len; // 9
uint8_t dtype; // 0x21
uint8_t addr;
uint8_t versionL; // 0x101
uint8_t versionH; // 0x101
uint8_t country;
uint8_t desctype; // 0x22 report
uint8_t descLenL;
uint8_t descLenH;
} HIDDescDescriptor;
// Replacement for global singleton.
// This function prevents static-initialization-order-fiasco
// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use
HID_& HID();
typedef struct
{
InterfaceDescriptor hid;
HIDDescDescriptor desc;
EndpointDescriptor in;
} HIDDescriptor;
#define D_HIDREPORT(length) { 9, 0x21, 0x01, 0x01, 0, 1, 0x22, lowByte(length), highByte(length) }
#define HID_TX HID_ENDPOINT_INT
#endif // USBCON
#define D_HIDREPORT(_descriptorLength) \
{ 9, 0x21, 0x1, 0x1, 0, 1, 0x22, _descriptorLength, 0 }
#define WEAK __attribute__ ((weak))
#endif
#endif // HID_h