diff options
Diffstat (limited to 'libraries/HID')
| -rw-r--r-- | libraries/HID/HID.cpp | 246 | ||||
| -rw-r--r-- | libraries/HID/HID.h | 133 | ||||
| -rw-r--r-- | libraries/HID/library.properties | 3 | 
3 files changed, 201 insertions, 181 deletions
diff --git a/libraries/HID/HID.cpp b/libraries/HID/HID.cpp index 0d2133e..21ede26 100644 --- a/libraries/HID/HID.cpp +++ b/libraries/HID/HID.cpp @@ -1,166 +1,162 @@ -/* Copyright (c) 2015, Arduino LLC -** -** Original code (pre-library): Copyright (c) 2011, Peter Barrett -** -** 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.   -**  -** 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.   -*/ - -#include "PluggableUSB.h" +/* +   Copyright (c) 2015, Arduino LLC +   Original code (pre-library): Copyright (c) 2011, Peter Barrett + +   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. + +   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. + */ +  #include "HID.h"  #if defined(USBCON) -HID_ HID; - -static u8 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 u8 HID_INTERFACE; - -HIDDescriptor _hidInterface; - -static HIDDescriptorListNode* rootNode = NULL; -static uint8_t sizeof_hidReportDescriptor = 0; -static uint8_t modules_count = 0; -//================================================================================ -//================================================================================ -//	Driver - -u8 _hid_protocol = 1; -u8 _hid_idle = 1; +HID_& HID() +{ +	static HID_ obj; +	return obj; +} -int HID_GetInterface(u8* interfaceNum) +int HID_::getInterface(uint8_t* interfaceCount)  { -	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) +	*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, USB_EP_SIZE, 0x01)  	}; -	return USB_SendControl(0,&_hidInterface,sizeof(_hidInterface)); +	return USB_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 += USB_SendControl(TRANSFER_PGM,current->cb->descriptor,current->cb->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 = USB_SendControl(TRANSFER_PGM, node->data, node->length); +		if (res == -1) +			return -1; +		total += res;  	} +	 +	// Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol +	// due to the USB specs, but Windows and Linux just assumes its in report mode. +	protocol = HID_REPORT_PROTOCOL; +	 +	return total;  } -void HID_::AppendDescriptor(HIDDescriptorListNode *node) +uint8_t HID_::getShortName(char *name)  { -	if (modules_count == 0) { +	name[0] = 'H'; +	name[1] = 'I'; +	name[2] = 'D'; +	name[3] = 'A' + (descriptorSize & 0x0F); +	name[4] = 'A' + ((descriptorSize >> 4) & 0x0F); +	return 5; +} + +void HID_::AppendDescriptor(HIDSubDescriptor *node) +{ +	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->cb->length; +	descriptorSize += node->length;  } -void HID_::SendReport(u8 id, const void* data, int len) +int HID_::SendReport(uint8_t id, const void* data, int len)  { -	USB_Send(HID_TX, &id, 1); -	USB_Send(HID_TX | TRANSFER_RELEASE,data,len); +	auto ret = USB_Send(pluggedEndpoint, &id, 1); +	if (ret < 0) return ret; +	auto ret2 = USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, len); +	if (ret2 < 0) return ret2; +	return ret + ret2;  } -bool HID_Setup(USBSetup& setup, u8 i) +bool HID_::setup(USBSetup& setup)  { -	if (HID_INTERFACE != i) { +	if (pluggedInterface != setup.wIndex) {  		return false; -	} else { -		u8 r = setup.bRequest; -		u8 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; -			} +	} + +	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_HOSTTODEVICE_CLASS_INTERFACE == requestType) +		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)  		{ -			if (HID_SET_PROTOCOL == r) -			{ -				_hid_protocol = setup.wValueL; -				return true; -			} - -			if (HID_SET_IDLE == r) -			{ -				_hid_idle = setup.wValueL; -				return true; -			} +			//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;  	} + +	return false;  } -HID_::HID_(void) +HID_::HID_(void) : PluggableUSBModule(1, 1, epType), +                   rootNode(NULL), descriptorSize(0), +                   protocol(HID_REPORT_PROTOCOL), idle(1)  { -	static uint8_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) */ diff --git a/libraries/HID/HID.h b/libraries/HID/HID.h index 89832a9..a9b3f58 100644 --- a/libraries/HID/HID.h +++ b/libraries/HID/HID.h @@ -1,38 +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. - -  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. +  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. -  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 "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 @@ -44,54 +40,81 @@  #define HID_REPORT_DESCRIPTOR_TYPE      0x22  #define HID_PHYSICAL_DESCRIPTOR_TYPE    0x23 -typedef struct __attribute__((packed)) { -  u8 length; -  const void* descriptor; -} HID_Descriptor; +// HID subclass HID1.11 Page 8 4.2 Subclass +#define HID_SUBCLASS_NONE 0 +#define HID_SUBCLASS_BOOT_INTERFACE 1 -class HIDDescriptorListNode { -public: -  HIDDescriptorListNode *next = NULL; -  const HID_Descriptor * cb; -  HIDDescriptorListNode(const HID_Descriptor *ncb) {cb = ncb;} -}; +// 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 -class HID_ -{ -public: -  HID_(void); -  int begin(void); -  void SendReport(uint8_t id, const void* data, int len); -  void AppendDescriptor(HIDDescriptorListNode* node); -}; +// 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  { -  u8 len;     // 9 -  u8 dtype;   // 0x21 -  u8 addr; -  u8  versionL; // 0x101 -  u8  versionH; // 0x101 -  u8  country; -  u8  desctype; // 0x22 report -  u8  descLenL; -  u8  descLenH; +  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; +  InterfaceDescriptor hid; +  HIDDescDescriptor   desc; +  EndpointDescriptor  in;  } HIDDescriptor; -#define HID_TX HID_ENDPOINT_INT +class HIDSubDescriptor { +public: +  HIDSubDescriptor *next = NULL; +  HIDSubDescriptor(const void *d, const uint16_t l) : data(d), length(l) { } + +  const void* data; +  const uint16_t length; +}; + +class HID_ : public PluggableUSBModule +{ +public: +  HID_(void); +  int begin(void); +  int SendReport(uint8_t id, const void* data, int len); +  void AppendDescriptor(HIDSubDescriptor* node); + +protected: +  // Implementation of the PluggableUSBModule +  int getInterface(uint8_t* interfaceCount); +  int getDescriptor(USBSetup& setup); +  bool setup(USBSetup& setup); +  uint8_t getShortName(char* name); + +private: +  uint8_t epType[1]; + +  HIDSubDescriptor* rootNode; +  uint16_t descriptorSize; + +  uint8_t protocol; +  uint8_t idle; +}; -#define D_HIDREPORT(_descriptorLength) \ -  { 9, 0x21, 0x1, 0x1, 0, 1, 0x22, _descriptorLength, 0 } +// 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(); -#define WEAK __attribute__ ((weak)) +#define D_HIDREPORT(length) { 9, 0x21, 0x01, 0x01, 0, 1, 0x22, lowByte(length), highByte(length) } -#endif +#endif // USBCON -#endif
\ No newline at end of file +#endif // HID_h diff --git a/libraries/HID/library.properties b/libraries/HID/library.properties index 20a1e7f..5cbb5d7 100644 --- a/libraries/HID/library.properties +++ b/libraries/HID/library.properties @@ -4,5 +4,6 @@ author=Arduino  maintainer=Arduino <info@arduino.cc>  sentence=Module for PluggableUSB infrastructure. Exposes an API for devices like Keyboards, Mice and Gamepads  paragraph= +category=Communication  url=http://www.arduino.cc/en/Reference/HID -architectures=avr
\ No newline at end of file +architectures=avr  | 
