From d1e52660368d34d693131f6aff3c8fd8584162e5 Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Mon, 1 Jun 2009 11:03:39 +0000 Subject: Commit of new class abstraction APIs for all device demos other than the MIDI demo - not documented yet. Removed scheduler and memory allocation libraries. Added new EVENT_USB_StartOfFrame event in the library to indicate the start of each USB frame (when generated). Removed Tx interrupt from the USBtoSerial demo; now sends characters via polling to ensure more time for the Rx interrupt. --- LUFA/ChangeLog.txt | 10 + LUFA/DirectorySummaries.txt | 13 - LUFA/Drivers/USB/Class/Device/Audio.c | 154 +++++++++ LUFA/Drivers/USB/Class/Device/Audio.h | 70 ++++ LUFA/Drivers/USB/Class/Device/CDC.c | 185 ++++++++++ LUFA/Drivers/USB/Class/Device/CDC.h | 188 ++++++++++ LUFA/Drivers/USB/Class/Device/HID.c | 211 ++++++++++++ LUFA/Drivers/USB/Class/Device/HID.h | 115 +++++++ LUFA/Drivers/USB/Class/Device/MassStorage.c | 208 +++++++++++ LUFA/Drivers/USB/Class/Device/MassStorage.h | 127 +++++++ LUFA/Drivers/USB/Class/Device/RNDIS.c | 456 +++++++++++++++++++++++++ LUFA/Drivers/USB/Class/Device/RNDIS.h | 260 ++++++++++++++ LUFA/Drivers/USB/Class/Device/RNDISConstants.h | 99 ++++++ LUFA/Drivers/USB/Class/HIDParser.c | 326 ------------------ LUFA/Drivers/USB/Class/HIDParser.h | 263 -------------- LUFA/Drivers/USB/Class/HIDReportData.h | 140 -------- LUFA/Drivers/USB/Class/Host/HIDParser.c | 326 ++++++++++++++++++ LUFA/Drivers/USB/Class/Host/HIDParser.h | 263 ++++++++++++++ LUFA/Drivers/USB/Class/Host/HIDReportData.h | 140 ++++++++ LUFA/Drivers/USB/HighLevel/Events.h | 6 + LUFA/Drivers/USB/HighLevel/USBInterrupt.c | 18 + LUFA/Drivers/USB/HighLevel/USBTask.c | 2 +- LUFA/Drivers/USB/HighLevel/USBTask.h | 7 +- LUFA/Drivers/USB/LowLevel/Endpoint.c | 6 +- LUFA/Drivers/USB/LowLevel/Host.c | 12 +- LUFA/Drivers/USB/LowLevel/LowLevel.c | 8 + LUFA/Drivers/USB/LowLevel/LowLevel.h | 3 + LUFA/Drivers/USB/LowLevel/Pipe.c | 6 +- LUFA/Drivers/USB/USB.h | 2 - LUFA/MemoryAllocator/DynAlloc.c | 226 ------------ LUFA/MemoryAllocator/DynAlloc.h | 198 ----------- LUFA/Scheduler/Scheduler.c | 95 ------ LUFA/Scheduler/Scheduler.h | 285 ---------------- LUFA/SchedulerOverview.txt | 31 -- LUFA/makefile | 6 +- 35 files changed, 2863 insertions(+), 1602 deletions(-) create mode 100644 LUFA/Drivers/USB/Class/Device/Audio.c create mode 100644 LUFA/Drivers/USB/Class/Device/Audio.h create mode 100644 LUFA/Drivers/USB/Class/Device/CDC.c create mode 100644 LUFA/Drivers/USB/Class/Device/CDC.h create mode 100644 LUFA/Drivers/USB/Class/Device/HID.c create mode 100644 LUFA/Drivers/USB/Class/Device/HID.h create mode 100644 LUFA/Drivers/USB/Class/Device/MassStorage.c create mode 100644 LUFA/Drivers/USB/Class/Device/MassStorage.h create mode 100644 LUFA/Drivers/USB/Class/Device/RNDIS.c create mode 100644 LUFA/Drivers/USB/Class/Device/RNDIS.h create mode 100644 LUFA/Drivers/USB/Class/Device/RNDISConstants.h delete mode 100644 LUFA/Drivers/USB/Class/HIDParser.c delete mode 100644 LUFA/Drivers/USB/Class/HIDParser.h delete mode 100644 LUFA/Drivers/USB/Class/HIDReportData.h create mode 100644 LUFA/Drivers/USB/Class/Host/HIDParser.c create mode 100644 LUFA/Drivers/USB/Class/Host/HIDParser.h create mode 100644 LUFA/Drivers/USB/Class/Host/HIDReportData.h delete mode 100644 LUFA/MemoryAllocator/DynAlloc.c delete mode 100644 LUFA/MemoryAllocator/DynAlloc.h delete mode 100644 LUFA/Scheduler/Scheduler.c delete mode 100644 LUFA/Scheduler/Scheduler.h delete mode 100644 LUFA/SchedulerOverview.txt (limited to 'LUFA') diff --git a/LUFA/ChangeLog.txt b/LUFA/ChangeLog.txt index ac675348bf..fe3b633609 100644 --- a/LUFA/ChangeLog.txt +++ b/LUFA/ChangeLog.txt @@ -4,6 +4,14 @@ * documentation pages. It is not a project source file. */ +========== TODO: =========== + - Document new class drivers + - Re-document all demos now that they have changed + - Add standardized descriptor names to class driver structures, controlled by USE_NONSTANDARD_DESCRIPTOR_NAMES + - Add C++ compatibility to class drivers + - Disable JTAG in demos +============================ + /** \page Page_ChangeLog Project Changelog * * \section Sec_ChangeLogXXXXXX Version XXXXXX @@ -30,6 +38,8 @@ * LUFA/Drivers/USB/Class/ directory to LUFA/Drivers/USB/HighLevel/ in preperation for the new USB class APIs * - Moved out each demos' functionality library files (e.g. Ring Buffer library) to /Lib directories for a better directory structure * - Removed Tx interrupt from the USBtoSerial demo; now sends characters via polling to ensure more time for the Rx interrupt + * - Added new EVENT_USB_StartOfFrame event in the library to indicate the start of each USB frame (when generated) + * - Removed psuedo-scheduler, dynamic memory block allocator from the library (no longer needed and not used respectively) * * * \section Sec_ChangeLog090510 Version 090510 diff --git a/LUFA/DirectorySummaries.txt b/LUFA/DirectorySummaries.txt index f439847608..3fae9c18ee 100644 --- a/LUFA/DirectorySummaries.txt +++ b/LUFA/DirectorySummaries.txt @@ -10,19 +10,6 @@ * This folder contains header files which are common to all parts of the LUFA library. They may be used freely in * user applications. * - * \dir MemoryAllocator - * \brief Auto-defragmenting dynamic memory allocation library. - * - * This folder contains a simple handle-based dynamic memory allocation library, capable of handing out memory in - * block chunks. As new memory is allocated, the library will defragment the already allocated memory to ensure - * optimal memory usage. It is not used within the LUFA library, and is provided as a convenience for user applications. - * - * \dir Scheduler - * \brief Simple round-robbin scheduler. - * - * This folder contains the simple LUFA round-robbin scheduler, provided as a convenience for user applications. It - * is very simple in design, and is intended to make code easier to read, rather than providing a complete RTOS kernel. - * * \dir Drivers * \brief Library hardware and software drivers. * diff --git a/LUFA/Drivers/USB/Class/Device/Audio.c b/LUFA/Drivers/USB/Class/Device/Audio.c new file mode 100644 index 0000000000..b0800ba0f6 --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/Audio.c @@ -0,0 +1,154 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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 "Audio.h" + +void USB_Audio_ProcessControlPacket(USB_ClassInfo_Audio_t* AudioInterfaceInfo) +{ + if (!(Endpoint_IsSETUPReceived())) + return; + +// if (USB_ControlRequest.wIndex != AudioInterfaceInfo->InterfaceNumber) +// return; + + switch (USB_ControlRequest.bRequest) + { + case REQ_SetInterface: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + AudioInterfaceInfo->InterfaceEnabled = (USB_ControlRequest.wValue != 0); + + while (!(Endpoint_IsINReady())); + Endpoint_ClearIN(); + } + + break; + } +} + +bool USB_Audio_ConfigureEndpoints(USB_ClassInfo_Audio_t* AudioInterfaceInfo) +{ + if (AudioInterfaceInfo->DataINEndpointNumber) + { + if (!(Endpoint_ConfigureEndpoint(AudioInterfaceInfo->DataINEndpointNumber, EP_TYPE_ISOCHRONOUS, + ENDPOINT_DIR_IN, AudioInterfaceInfo->DataINEndpointSize, + ENDPOINT_BANK_DOUBLE))) + { + return false; + } + } + + if (AudioInterfaceInfo->DataOUTEndpointNumber) + { + if (!(Endpoint_ConfigureEndpoint(AudioInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_ISOCHRONOUS, + ENDPOINT_DIR_OUT, AudioInterfaceInfo->DataOUTEndpointSize, + ENDPOINT_BANK_DOUBLE))) + { + return false; + } + } + + return true; +} + +int8_t USB_Audio_ReadSample8(void) +{ + int8_t Sample; + + Sample = Endpoint_Read_Byte(); + + if (!(Endpoint_IsReadWriteAllowed())) + Endpoint_ClearOUT(); + + return Sample; +} + +int16_t USB_Audio_ReadSample16(void) +{ + int16_t Sample; + + Sample = (int16_t)Endpoint_Read_Word_LE(); + + if (!(Endpoint_IsReadWriteAllowed())) + Endpoint_ClearOUT(); + + return Sample; +} + +int32_t USB_Audio_ReadSample24(void) +{ + int32_t Sample; + + Sample = (((uint32_t)Endpoint_Read_Byte() << 16) | Endpoint_Read_Word_LE()); + + if (!(Endpoint_IsReadWriteAllowed())) + Endpoint_ClearOUT(); + + return Sample; +} + +void USB_Audio_WriteSample8(int8_t Sample) +{ + Endpoint_Write_Byte(Sample); + + if (!(Endpoint_IsReadWriteAllowed())) + Endpoint_ClearIN(); +} + +void USB_Audio_WriteSample16(int16_t Sample) +{ + Endpoint_Write_Word_LE(Sample); + + if (!(Endpoint_IsReadWriteAllowed())) + Endpoint_ClearIN(); +} + +void USB_Audio_WriteSample24(int32_t Sample) +{ + Endpoint_Write_Byte(Sample >> 16); + Endpoint_Write_Word_LE(Sample); + + if (!(Endpoint_IsReadWriteAllowed())) + Endpoint_ClearIN(); +} + +bool USB_Audio_IsSampleReceived(USB_ClassInfo_Audio_t* AudioInterfaceInfo) +{ + Endpoint_SelectEndpoint(AudioInterfaceInfo->DataOUTEndpointNumber); + return Endpoint_IsOUTReceived(); +} + +bool USB_Audio_IsReadyForNextSample(USB_ClassInfo_Audio_t* AudioInterfaceInfo) +{ + Endpoint_SelectEndpoint(AudioInterfaceInfo->DataINEndpointNumber); + return Endpoint_IsINReady(); +} diff --git a/LUFA/Drivers/USB/Class/Device/Audio.h b/LUFA/Drivers/USB/Class/Device/Audio.h new file mode 100644 index 0000000000..aa7b4069c6 --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/Audio.h @@ -0,0 +1,70 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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 _AUDIO_CLASS_H_ +#define _AUDIO_CLASS_H_ + + /* Includes: */ + #include "../../USB.h" + + #include + + /* Macros: */ + + /* Enums: */ + + /* Type Defines: */ + typedef struct + { + uint8_t InterfaceNumber; + + uint8_t DataINEndpointNumber; + uint16_t DataINEndpointSize; + + uint8_t DataOUTEndpointNumber; + uint16_t DataOUTEndpointSize; + + bool InterfaceEnabled; + } USB_ClassInfo_Audio_t; + + /* Function Prototypes: */ + bool USB_Audio_ConfigureEndpoints(USB_ClassInfo_Audio_t* AudioInterfaceInfo); + void USB_Audio_ProcessControlPacket(USB_ClassInfo_Audio_t* AudioInterfaceInfo); + void USB_Audio_USBTask(USB_ClassInfo_Audio_t* AudioInterfaceInfo); + + int8_t USB_Audio_ReadSample8(void); + int16_t USB_Audio_ReadSample16(void); + int32_t USB_Audio_ReadSample24(void); + void USB_Audio_WriteSample8(int8_t Sample); + void USB_Audio_WriteSample16(int16_t Sample); + void USB_Audio_WriteSample24(int32_t Sample); + bool USB_Audio_IsSampleReceived(USB_ClassInfo_Audio_t* AudioInterfaceInfo); + bool USB_Audio_IsReadyForNextSample(USB_ClassInfo_Audio_t* AudioInterfaceInfo); +#endif diff --git a/LUFA/Drivers/USB/Class/Device/CDC.c b/LUFA/Drivers/USB/Class/Device/CDC.c new file mode 100644 index 0000000000..8acaac7a1c --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/CDC.c @@ -0,0 +1,185 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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. +*/ + +#define INCLUDE_FROM_CDC_CLASS_C +#include "CDC.h" + +void USB_CDC_Event_Stub(void) +{ + +} + +void USB_CDC_ProcessControlPacket(USB_ClassInfo_CDC_t* CDCInterfaceInfo) +{ + if (!(Endpoint_IsSETUPReceived())) + return; + + if (USB_ControlRequest.wIndex != CDCInterfaceInfo->ControlInterfaceNumber) + return; + + switch (USB_ControlRequest.bRequest) + { + case REQ_GetLineEncoding: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + Endpoint_Write_Control_Stream_LE(&CDCInterfaceInfo->LineEncoding, sizeof(CDCInterfaceInfo->LineEncoding)); + Endpoint_ClearOUT(); + } + + break; + case REQ_SetLineEncoding: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + Endpoint_Read_Control_Stream_LE(&CDCInterfaceInfo->LineEncoding, sizeof(CDCInterfaceInfo->LineEncoding)); + Endpoint_ClearIN(); + + EVENT_USB_CDC_LineEncodingChanged(CDCInterfaceInfo); + } + + break; + case REQ_SetControlLineState: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + CDCInterfaceInfo->ControlLineState = USB_ControlRequest.wValue; + + EVENT_USB_CDC_ControLineStateChanged(); + + while (!(Endpoint_IsINReady())); + Endpoint_ClearIN(); + } + + break; + } +} + +bool USB_CDC_ConfigureEndpoints(USB_ClassInfo_CDC_t* CDCInterfaceInfo) +{ + if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->DataINEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_IN, CDCInterfaceInfo->DataINEndpointSize, + ENDPOINT_BANK_SINGLE))) + { + return false; + } + + if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_OUT, CDCInterfaceInfo->DataOUTEndpointSize, + ENDPOINT_BANK_SINGLE))) + { + return false; + } + + if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->NotificationEndpointNumber, EP_TYPE_INTERRUPT, + ENDPOINT_DIR_IN, CDCInterfaceInfo->NotificationEndpointSize, + ENDPOINT_BANK_SINGLE))) + { + return false; + } + + return true; +} + +void USB_CDC_USBTask(USB_ClassInfo_CDC_t* CDCInterfaceInfo) +{ + if (!(USB_IsConnected)) + return; + + Endpoint_SelectEndpoint(CDCInterfaceInfo->DataINEndpointNumber); + + if (!(Endpoint_BytesInEndpoint())) + return; + + if (!(Endpoint_IsReadWriteAllowed())) + { + Endpoint_ClearIN(); + while (!(Endpoint_IsReadWriteAllowed())); + } + + Endpoint_ClearIN(); +} + +void USB_CDC_SendString(USB_ClassInfo_CDC_t* CDCInterfaceInfo, char* Data, uint16_t Length) +{ + Endpoint_SelectEndpoint(CDCInterfaceInfo->DataINEndpointNumber); + Endpoint_Write_Stream_LE(Data, Length, NO_STREAM_CALLBACK); +} + +void USB_CDC_SendByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint8_t Data) +{ + Endpoint_SelectEndpoint(CDCInterfaceInfo->DataINEndpointNumber); + + if (!(Endpoint_IsReadWriteAllowed())) + { + Endpoint_ClearIN(); + while (!(Endpoint_IsReadWriteAllowed())); + } + + Endpoint_Write_Byte(Data); +} + +uint16_t USB_CDC_BytesReceived(USB_ClassInfo_CDC_t* CDCInterfaceInfo) +{ + Endpoint_SelectEndpoint(CDCInterfaceInfo->DataOUTEndpointNumber); + + return Endpoint_BytesInEndpoint(); +} + +uint8_t USB_CDC_ReceiveByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo) +{ + Endpoint_SelectEndpoint(CDCInterfaceInfo->DataOUTEndpointNumber); + + uint8_t DataByte = Endpoint_Read_Byte(); + + if (!(Endpoint_BytesInEndpoint())) + Endpoint_ClearOUT(); + + return DataByte; +} + +void USB_CDC_SendSerialLineStateChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint16_t LineStateMask) +{ + Endpoint_SelectEndpoint(CDCInterfaceInfo->NotificationEndpointNumber); + + USB_Request_Header_t Notification = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = NOTIF_SerialState, + .wValue = 0, + .wIndex = 0, + .wLength = sizeof(uint16_t), + }; + + Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK); + Endpoint_Write_Stream_LE(&LineStateMask, sizeof(LineStateMask), NO_STREAM_CALLBACK); + Endpoint_ClearIN(); +} diff --git a/LUFA/Drivers/USB/Class/Device/CDC.h b/LUFA/Drivers/USB/Class/Device/CDC.h new file mode 100644 index 0000000000..bbe1c9838d --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/CDC.h @@ -0,0 +1,188 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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 _CDC_CLASS_H_ +#define _CDC_CLASS_H_ + + /* Includes: */ + #include "../../USB.h" + + #include + + /* Macros: */ + /** CDC Class specific request to get the current virtual serial port configuration settings. */ + #define REQ_GetLineEncoding 0x21 + + /** CDC Class specific request to set the current virtual serial port configuration settings. */ + #define REQ_SetLineEncoding 0x20 + + /** CDC Class specific request to set the current virtual serial port handshake line states. */ + #define REQ_SetControlLineState 0x22 + + /** Notification type constant for a change in the virtual serial port handshake line states, for + * use with a USB_Notification_Header_t notification structure when sent to the host via the CDC + * notification endpoint. + */ + #define NOTIF_SerialState 0x20 + + /** Mask for the DTR handshake line for use with the REQ_SetControlLineState class specific request + * from the host, to indicate that the DTR line state should be high. + */ + #define CONTROL_LINE_OUT_DTR (1 << 0) + + /** Mask for the RTS handshake line for use with the REQ_SetControlLineState class specific request + * from the host, to indicate that theRTS line state should be high. + */ + #define CONTROL_LINE_OUT_RTS (1 << 1) + + /** Mask for the DCD handshake line for use with the a NOTIF_SerialState class specific notification + * from the device to the host, to indicate that the DCD line state is currently high. + */ + #define CONTROL_LINE_IN_DCD (1 << 0) + + /** Mask for the DSR handshake line for use with the a NOTIF_SerialState class specific notification + * from the device to the host, to indicate that the DSR line state is currently high. + */ + #define CONTROL_LINE_IN_DSR (1 << 1) + + /** Mask for the BREAK handshake line for use with the a NOTIF_SerialState class specific notification + * from the device to the host, to indicate that the BREAK line state is currently high. + */ + #define CONTROL_LINE_IN_BREAK (1 << 2) + + /** Mask for the RING handshake line for use with the a NOTIF_SerialState class specific notification + * from the device to the host, to indicate that the RING line state is currently high. + */ + #define CONTROL_LINE_IN_RING (1 << 3) + + /** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host, + * to indicate that a framing error has occurred on the virtual serial port. + */ + #define CONTROL_LINE_IN_FRAMEERROR (1 << 4) + + /** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host, + * to indicate that a parity error has occurred on the virtual serial port. + */ + #define CONTROL_LINE_IN_PARITYERROR (1 << 5) + + /** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host, + * to indicate that a data overrun error has occurred on the virtual serial port. + */ + #define CONTROL_LINE_IN_OVERRUNERROR (1 << 6) + + /** Macro to define a CDC class-specific functional descriptor. CDC functional descriptors have a + * uniform structure but variable sized data payloads, thus cannot be represented accurately by + * a single typedef struct. A macro is used instead so that functional descriptors can be created + * easily by specifying the size of the payload. This allows sizeof() to work correctly. + * + * \param DataSize Size in bytes of the CDC functional descriptor's data payload + */ + #define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \ + struct \ + { \ + USB_Descriptor_Header_t Header; \ + uint8_t SubType; \ + uint8_t Data[DataSize]; \ + } + + /* Enums: */ + /** Enum for the possible line encoding formats of a virtual serial port. */ + enum CDCDevice_CDC_LineCodingFormats_t + { + OneStopBit = 0, /**< Each frame contains one stop bit */ + OneAndAHalfStopBits = 1, /**< Each frame contains one and a half stop bits */ + TwoStopBits = 2, /**< Each frame contains two stop bits */ + }; + + /** Enum for the possible line encoding parity settings of a virtual serial port. */ + enum CDCDevice_LineCodingParity_t + { + Parity_None = 0, /**< No parity bit mode on each frame */ + Parity_Odd = 1, /**< Odd parity bit mode on each frame */ + Parity_Even = 2, /**< Even parity bit mode on each frame */ + Parity_Mark = 3, /**< Mark parity bit mode on each frame */ + Parity_Space = 4, /**< Space parity bit mode on each frame */ + }; + + /* Type Defines: */ + /** Type define for the virtual serial port line encoding settings, for storing the current USART configuration + * as set by the host via a class specific request. + */ + typedef struct + { + uint8_t ControlInterfaceNumber; /**< Interface number of the CDC control interface within the device */ + + uint8_t DataINEndpointNumber; /**< Endpoint number of the CDC interface's IN data endpoint */ + uint16_t DataINEndpointSize; /**< Size in bytes of the CDC interface's IN data endpoint */ + + uint8_t DataOUTEndpointNumber; /**< Endpoint number of the CDC interface's OUT data endpoint */ + uint16_t DataOUTEndpointSize; /**< Size in bytes of the CDC interface's OUT data endpoint */ + + uint8_t NotificationEndpointNumber; /**< Endpoint number of the CDC interface's IN notification endpoint, if used */ + uint16_t NotificationEndpointSize; /**< Size in bytes of the CDC interface's IN notification endpoint, if used */ + + uint8_t ControlLineState; + + struct + { + uint32_t BaudRateBPS; /**< Baud rate of the virtual serial port, in bits per second */ + uint8_t CharFormat; /**< Character format of the virtual serial port, a value from the + * CDCDevice_CDC_LineCodingFormats_t enum + */ + uint8_t ParityType; /**< Parity setting of the virtual serial port, a value from the + * CDCDevice_LineCodingParity_t enum + */ + uint8_t DataBits; /**< Bits of data per character of the virtual serial port */ + } LineEncoding; + } USB_ClassInfo_CDC_t; + + /* Function Prototypes: */ + #if defined(INCLUDE_FROM_CDC_CLASS_C) + void USB_CDC_Event_Stub(void); + void EVENT_USB_CDC_LineEncodingChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo) + ATTR_WEAK ATTR_ALIAS(USB_CDC_Event_Stub); + void EVENT_USB_CDC_ControLineStateChanged(void) ATTR_WEAK ATTR_ALIAS(USB_CDC_Event_Stub);; + #endif + + void USB_CDC_USBTask(USB_ClassInfo_CDC_t* CDCInterfaceInfo); + bool USB_CDC_ConfigureEndpoints(USB_ClassInfo_CDC_t* CDCInterfaceInfo); + void USB_CDC_ProcessControlPacket(USB_ClassInfo_CDC_t* CDCInterfaceInfo); + void USB_CDC_USBTask(USB_ClassInfo_CDC_t* CDCInterfaceInfo); + + void EVENT_USB_CDC_LineEncodingChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo); + void EVENT_USB_CDC_ControLineStateChanged(void); + + void USB_CDC_SendString(USB_ClassInfo_CDC_t* CDCInterfaceInfo, char* Data, uint16_t Length); + void USB_CDC_SendByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint8_t Data); + uint16_t USB_CDC_BytesReceived(USB_ClassInfo_CDC_t* CDCInterfaceInfo); + uint8_t USB_CDC_ReceiveByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo); + void USB_CDC_SendSerialLineStateChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint16_t LineStateMask); + +#endif diff --git a/LUFA/Drivers/USB/Class/Device/HID.c b/LUFA/Drivers/USB/Class/Device/HID.c new file mode 100644 index 0000000000..fbc5e3a5c9 --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/HID.c @@ -0,0 +1,211 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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" + +void USB_HID_ProcessControlPacket(USB_ClassInfo_HID_t* HIDInterfaceInfo) +{ + if (!(Endpoint_IsSETUPReceived())) + return; + + if (USB_ControlRequest.wIndex != HIDInterfaceInfo->InterfaceNumber) + return; + + switch (USB_ControlRequest.bRequest) + { + case REQ_GetReport: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + uint8_t ReportINData[HIDInterfaceInfo->ReportBufferSize]; + uint16_t ReportINSize; + + memset(ReportINData, 0, sizeof(ReportINData)); + + ReportINSize = CALLBACK_USB_HID_CreateNextHIDReport(HIDInterfaceInfo, ReportINData); + + Endpoint_Write_Control_Stream_LE(ReportINData, ReportINSize); + Endpoint_ClearOUT(); + } + + break; + case REQ_SetReport: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + uint16_t ReportOUTSize = USB_ControlRequest.wLength; + uint8_t ReportOUTData[ReportOUTSize]; + + Endpoint_Read_Control_Stream_LE(ReportOUTData, ReportOUTSize); + Endpoint_ClearIN(); + + CALLBACK_USB_HID_ProcessReceivedHIDReport(HIDInterfaceInfo, ReportOUTData, ReportOUTSize); + } + + break; + case REQ_GetProtocol: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + Endpoint_Write_Byte(HIDInterfaceInfo->UsingReportProtocol); + Endpoint_ClearIN(); + + while (!(Endpoint_IsOUTReceived())); + Endpoint_ClearOUT(); + } + + break; + case REQ_SetProtocol: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + HIDInterfaceInfo->UsingReportProtocol = (USB_ControlRequest.wValue != 0x0000); + + while (!(Endpoint_IsINReady())); + Endpoint_ClearIN(); + } + + break; + case REQ_SetIdle: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + HIDInterfaceInfo->IdleCount = ((USB_ControlRequest.wValue >> 8) << 2); + + while (!(Endpoint_IsINReady())); + Endpoint_ClearIN(); + } + + break; + case REQ_GetIdle: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + Endpoint_Write_Byte(HIDInterfaceInfo->IdleCount >> 2); + Endpoint_ClearIN(); + + while (!(Endpoint_IsOUTReceived())); + Endpoint_ClearOUT(); + } + + break; + } +} + +bool USB_HID_ConfigureEndpoints(USB_ClassInfo_HID_t* HIDInterfaceInfo) +{ + HIDInterfaceInfo->UsingReportProtocol = true; + + if (!(Endpoint_ConfigureEndpoint(HIDInterfaceInfo->ReportINEndpointNumber, EP_TYPE_INTERRUPT, + ENDPOINT_DIR_IN, HIDInterfaceInfo->ReportINEndpointSize, ENDPOINT_BANK_SINGLE))) + { + return false; + } + + if (HIDInterfaceInfo->ReportOUTEndpointNumber) + { + if (!(Endpoint_ConfigureEndpoint(HIDInterfaceInfo->ReportOUTEndpointNumber, EP_TYPE_INTERRUPT, + ENDPOINT_DIR_OUT, HIDInterfaceInfo->ReportOUTEndpointSize, ENDPOINT_BANK_SINGLE))) + { + return false; + } + } + + return true; +} + +void USB_HID_RegisterStartOfFrame(USB_ClassInfo_HID_t* HIDInterfaceInfo) +{ + if (HIDInterfaceInfo->IdleMSRemaining) + HIDInterfaceInfo->IdleMSRemaining--; +} + +void USB_HID_USBTask(USB_ClassInfo_HID_t* HIDInterfaceInfo) +{ + if (!(USB_IsConnected)) + return; + + Endpoint_SelectEndpoint(HIDInterfaceInfo->ReportINEndpointNumber); + + if (Endpoint_IsReadWriteAllowed() && + !(HIDInterfaceInfo->IdleCount && HIDInterfaceInfo->IdleMSRemaining)) + { + if (HIDInterfaceInfo->IdleCount && !(HIDInterfaceInfo->IdleMSRemaining)) + HIDInterfaceInfo->IdleMSRemaining = HIDInterfaceInfo->IdleCount; + + uint8_t ReportINData[HIDInterfaceInfo->ReportBufferSize]; + uint16_t ReportINSize; + + memset(ReportINData, 0, sizeof(ReportINData)); + + ReportINSize = CALLBACK_USB_HID_CreateNextHIDReport(HIDInterfaceInfo, ReportINData); + + if (ReportINSize) + { + Endpoint_Write_Stream_LE(ReportINData, ReportINSize + #if !defined(NO_STREAM_CALLBACKS) + , NO_STREAM_CALLBACK + #endif + ); + } + + Endpoint_ClearIN(); + } + + if (HIDInterfaceInfo->ReportOUTEndpointNumber) + { + Endpoint_SelectEndpoint(HIDInterfaceInfo->ReportOUTEndpointNumber); + + if (Endpoint_IsOUTReceived()) + { + uint16_t ReportOUTSize = Endpoint_BytesInEndpoint(); + uint8_t ReportOUTData[ReportOUTSize]; + + if (ReportOUTSize) + { + Endpoint_Read_Stream_LE(ReportOUTData, ReportOUTSize + #if !defined(NO_STREAM_CALLBACKS) + , NO_STREAM_CALLBACK + #endif + ); + } + + CALLBACK_USB_HID_ProcessReceivedHIDReport(HIDInterfaceInfo, ReportOUTData, ReportOUTSize); + + Endpoint_ClearOUT(); + } + } +} diff --git a/LUFA/Drivers/USB/Class/Device/HID.h b/LUFA/Drivers/USB/Class/Device/HID.h new file mode 100644 index 0000000000..8fdeb064a0 --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/HID.h @@ -0,0 +1,115 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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_CLASS_H_ +#define _HID_CLASS_H_ + + /* Includes: */ + #include "../../USB.h" + + #include + + /* Macros: */ + /** HID Class Specific Request to get the current HID report from the device. */ + #define REQ_GetReport 0x01 + + /** HID Class Specific Request to get the current device idle count. */ + #define REQ_GetIdle 0x02 + + /** HID Class Specific Request to set the current HID report to the device. */ + #define REQ_SetReport 0x09 + + /** HID Class Specific Request to set the device's idle count. */ + #define REQ_SetIdle 0x0A + + /** HID Class Specific Request to get the current HID report protocol mode. */ + #define REQ_GetProtocol 0x03 + + /** HID Class Specific Request to set the current HID report protocol mode. */ + #define REQ_SetProtocol 0x0B + + /** Descriptor header type value, to indicate a HID class HID descriptor. */ + #define DTYPE_HID 0x21 + + /** Descriptor header type value, to indicate a HID class HID report descriptor. */ + #define DTYPE_Report 0x22 + + /* Type Defines: */ + /** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID + * specification for details on the structure elements. + */ + typedef struct + { + USB_Descriptor_Header_t Header; + + uint16_t HIDSpec; + uint8_t CountryCode; + + uint8_t TotalReportDescriptors; + + uint8_t HIDReportType; + uint16_t HIDReportLength; + } USB_Descriptor_HID_t; + + /** Type define for the data type used to store HID report descriptor elements. */ + typedef uint8_t USB_Descriptor_HIDReport_Datatype_t; + + /** Class state structure. An instance of this structure should be made for each HID interface + * within the user application, and passed to each of the HID class driver functions as the + * HIDInterfaceInfo parameter. The contents of this structure should be set to their correct + * values when used, or ommitted to force the library to use default values. + */ + typedef struct + { + uint8_t InterfaceNumber; /**< Interface number of the HID interface within the device */ + + uint8_t ReportINEndpointNumber; /**< Endpoint number of the HID interface's IN report endpoint */ + uint16_t ReportINEndpointSize; /**< Size in bytes of the HID interface's IN report endpoint */ + + uint8_t ReportOUTEndpointNumber; /**< Endpoint number of the HID interface's OUT report endpoint, if used */ + uint16_t ReportOUTEndpointSize; /**< Size in bytes of the HID interface's OUT report endpoint, if used */ + + uint8_t ReportBufferSize; + + bool UsingReportProtocol; /**< Indicates if the HID interface is set to Boot or Report protocol mode */ + uint16_t IdleCount; /**< Report idle period, in ms, set by the host */ + uint16_t IdleMSRemaining; /**< Total number of ms remaining before the idle period elapses */ + } USB_ClassInfo_HID_t; + + /* Function Prototypes: */ + bool USB_HID_ConfigureEndpoints(USB_ClassInfo_HID_t* HIDInterfaceInfo); + void USB_HID_ProcessControlPacket(USB_ClassInfo_HID_t* HIDInterfaceInfo); + void USB_HID_RegisterStartOfFrame(USB_ClassInfo_HID_t* HIDInterfaceInfo); + void USB_HID_USBTask(USB_ClassInfo_HID_t* HIDInterfaceInfo); + + uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData); + void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize); + +#endif diff --git a/LUFA/Drivers/USB/Class/Device/MassStorage.c b/LUFA/Drivers/USB/Class/Device/MassStorage.c new file mode 100644 index 0000000000..1c41f6046d --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/MassStorage.c @@ -0,0 +1,208 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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. +*/ + +#define INCLUDE_FROM_MS_CLASS_C +#include "MassStorage.h" + +static USB_ClassInfo_MS_t* CallbackMSInterfaceInfo; + +void USB_MS_ProcessControlPacket(USB_ClassInfo_MS_t* MSInterfaceInfo) +{ + if (!(Endpoint_IsSETUPReceived())) + return; + + if (USB_ControlRequest.wIndex != MSInterfaceInfo->InterfaceNumber) + return; + + switch (USB_ControlRequest.bRequest) + { + case REQ_MassStorageReset: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + MSInterfaceInfo->IsMassStoreReset = true; + + while (!(Endpoint_IsINReady())); + Endpoint_ClearIN(); + } + + break; + case REQ_GetMaxLUN: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + Endpoint_Write_Byte(MSInterfaceInfo->TotalLUNs - 1); + + Endpoint_ClearIN(); + + while (!(Endpoint_IsOUTReceived())); + Endpoint_ClearOUT(); + } + + break; + } +} + +bool USB_MS_ConfigureEndpoints(USB_ClassInfo_MS_t* MSInterfaceInfo) +{ + if (!(Endpoint_ConfigureEndpoint(MSInterfaceInfo->DataINEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_IN, MSInterfaceInfo->DataINEndpointSize, + ENDPOINT_BANK_SINGLE))) + { + return false; + } + + if (!(Endpoint_ConfigureEndpoint(MSInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_OUT, MSInterfaceInfo->DataOUTEndpointSize, + ENDPOINT_BANK_SINGLE))) + { + return false; + } + + return true; +} + +void USB_MS_USBTask(USB_ClassInfo_MS_t* MSInterfaceInfo) +{ + if (!(USB_IsConnected)) + return; + + Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber); + + if (Endpoint_IsReadWriteAllowed()) + { + if (USB_MS_ReadInCommandBlock(MSInterfaceInfo)) + { + if (MSInterfaceInfo->CommandBlock.Flags & COMMAND_DIRECTION_DATA_IN) + Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber); + + MSInterfaceInfo->CommandStatus.Status = CALLBACK_USB_MS_SCSICommandReceived(MSInterfaceInfo) ? + Command_Pass : Command_Fail; + MSInterfaceInfo->CommandStatus.Signature = CSW_SIGNATURE; + MSInterfaceInfo->CommandStatus.Tag = MSInterfaceInfo->CommandBlock.Tag; + MSInterfaceInfo->CommandStatus.DataTransferResidue = MSInterfaceInfo->CommandBlock.DataTransferLength; + + if ((MSInterfaceInfo->CommandStatus.Status == Command_Fail) && (MSInterfaceInfo->CommandStatus.DataTransferResidue)) + Endpoint_StallTransaction(); + + USB_MS_ReturnCommandStatus(MSInterfaceInfo); + + if (MSInterfaceInfo->IsMassStoreReset) + { + Endpoint_ResetFIFO(MSInterfaceInfo->DataOUTEndpointNumber); + Endpoint_ResetFIFO(MSInterfaceInfo->DataINEndpointNumber); + + Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber); + Endpoint_ClearStall(); + Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber); + Endpoint_ClearStall(); + + MSInterfaceInfo->IsMassStoreReset = false; + } + } + } +} + +static bool USB_MS_ReadInCommandBlock(USB_ClassInfo_MS_t* MSInterfaceInfo) +{ + Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber); + + CallbackMSInterfaceInfo = MSInterfaceInfo; + Endpoint_Read_Stream_LE(&MSInterfaceInfo->CommandBlock, + (sizeof(CommandBlockWrapper_t) - MAX_SCSI_COMMAND_LENGTH), + StreamCallback_AbortOnMassStoreReset); + + if ((MSInterfaceInfo->CommandBlock.Signature != CBW_SIGNATURE) || + (MSInterfaceInfo->CommandBlock.LUN >= MSInterfaceInfo->TotalLUNs) || + (MSInterfaceInfo->CommandBlock.SCSICommandLength > MAX_SCSI_COMMAND_LENGTH)) + { + Endpoint_StallTransaction(); + Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber); + Endpoint_StallTransaction(); + + return false; + } + + CallbackMSInterfaceInfo = MSInterfaceInfo; + Endpoint_Read_Stream_LE(&MSInterfaceInfo->CommandBlock.SCSICommandData, + MSInterfaceInfo->CommandBlock.SCSICommandLength, + StreamCallback_AbortOnMassStoreReset); + + Endpoint_ClearOUT(); + + if (MSInterfaceInfo->IsMassStoreReset) + return false; + + return true; +} + +static void USB_MS_ReturnCommandStatus(USB_ClassInfo_MS_t* MSInterfaceInfo) +{ + Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber); + + while (Endpoint_IsStalled()) + { + USB_USBTask(); + + if (MSInterfaceInfo->IsMassStoreReset) + return; + } + + Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber); + + while (Endpoint_IsStalled()) + { + USB_USBTask(); + + if (MSInterfaceInfo->IsMassStoreReset) + return; + } + + CallbackMSInterfaceInfo = MSInterfaceInfo; + Endpoint_Write_Stream_LE(&MSInterfaceInfo->CommandStatus, sizeof(CommandStatusWrapper_t), + StreamCallback_AbortOnMassStoreReset); + + Endpoint_ClearIN(); + + if (MSInterfaceInfo->IsMassStoreReset) + return; +} + +static uint8_t StreamCallback_AbortOnMassStoreReset(void) +{ + USB_MS_USBTask(CallbackMSInterfaceInfo); + + if (CallbackMSInterfaceInfo->IsMassStoreReset) + return STREAMCALLBACK_Abort; + else + return STREAMCALLBACK_Continue; +} diff --git a/LUFA/Drivers/USB/Class/Device/MassStorage.h b/LUFA/Drivers/USB/Class/Device/MassStorage.h new file mode 100644 index 0000000000..c1874b218e --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/MassStorage.h @@ -0,0 +1,127 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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 _MS_CLASS_H_ +#define _MS_CLASS_H_ + + /* Includes: */ + #include "../../USB.h" + + #include + + /* Macros: */ + /** Mass Storage Class specific request to reset the Mass Storage interface, ready for the next command. */ + #define REQ_MassStorageReset 0xFF + + /** Mass Storage Class specific request to retrieve the total number of Logical Units (drives) in the SCSI device. */ + #define REQ_GetMaxLUN 0xFE + + /** Maximum length of a SCSI command which can be issued by the device or host in a Mass Storage bulk wrapper. */ + #define MAX_SCSI_COMMAND_LENGTH 16 + + /** Magic signature for a Command Block Wrapper used in the Mass Storage Bulk-Only transport protocol. */ + #define CBW_SIGNATURE 0x43425355UL + + /** Magic signature for a Command Status Wrapper used in the Mass Storage Bulk-Only transport protocol. */ + #define CSW_SIGNATURE 0x53425355UL + + /** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from host-to-device. */ + #define COMMAND_DIRECTION_DATA_OUT (0 << 7) + + /** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from device-to-host. */ + #define COMMAND_DIRECTION_DATA_IN (1 << 7) + + /* Type defines: */ + /** Type define for a Command Block Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */ + typedef struct + { + uint32_t Signature; /**< Command block signature, must be CBW_SIGNATURE to indicate a valid Command Block */ + uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */ + uint32_t DataTransferLength; /** Length of the optional data portion of the issued command, in bytes */ + uint8_t Flags; /**< Command block flags, indicating command data direction */ + uint8_t LUN; /**< Logical Unit number this command is issued to */ + uint8_t SCSICommandLength; /**< Length of the issued SCSI command within the SCSI command data array */ + uint8_t SCSICommandData[MAX_SCSI_COMMAND_LENGTH]; /**< Issued SCSI command in the Command Block */ + } CommandBlockWrapper_t; + + /** Type define for a Command Status Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */ + typedef struct + { + uint32_t Signature; /**< Status block signature, must be CSW_SIGNATURE to indicate a valid Command Status */ + uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */ + uint32_t DataTransferResidue; /**< Number of bytes of data not processed in the SCSI command */ + uint8_t Status; /**< Status code of the issued command - a value from the MassStorage_CommandStatusCodes_t enum */ + } CommandStatusWrapper_t; + + /* Enums: */ + /** Enum for the possible command status wrapper return status codes. */ + enum MassStorage_CommandStatusCodes_t + { + Command_Pass = 0, /**< Command completed with no error */ + Command_Fail = 1, /**< Command failed to complete - host may check the exact error via a SCSI REQUEST SENSE command */ + Phase_Error = 2 /**< Command failed due to being invalid in the current phase */ + }; + + /* Type Defines: */ + /** Type define for the virtual serial port line encoding settings, for storing the current USART configuration + * as set by the host via a class specific request. + */ + typedef struct + { + uint8_t InterfaceNumber; /**< Interface number of the Mass Storage interface within the device */ + + uint8_t DataINEndpointNumber; /**< Endpoint number of the Mass Storage interface's IN data endpoint */ + uint16_t DataINEndpointSize; /**< Size in bytes of the Mass Storage interface's IN data endpoint */ + + uint8_t DataOUTEndpointNumber; /**< Endpoint number of the Mass Storage interface's OUT data endpoint */ + uint16_t DataOUTEndpointSize; /**< Size in bytes of the Mass Storage interface's OUT data endpoint */ + + uint8_t TotalLUNs; + + CommandBlockWrapper_t CommandBlock; + CommandStatusWrapper_t CommandStatus; + + bool IsMassStoreReset; + } USB_ClassInfo_MS_t; + + /* Function Prototypes: */ + #if defined(INCLUDE_FROM_MS_CLASS_C) + static void USB_MS_ReturnCommandStatus(USB_ClassInfo_MS_t* MSInterfaceInfo); + static bool USB_MS_ReadInCommandBlock(USB_ClassInfo_MS_t* MSInterfaceInfo); + static uint8_t StreamCallback_AbortOnMassStoreReset(void); + #endif + + void USB_MS_USBTask(USB_ClassInfo_MS_t* MSInterfaceInfo); + bool USB_MS_ConfigureEndpoints(USB_ClassInfo_MS_t* MSInterfaceInfo); + void USB_MS_ProcessControlPacket(USB_ClassInfo_MS_t* MSInterfaceInfo); + + bool CALLBACK_USB_MS_SCSICommandReceived(USB_ClassInfo_MS_t* MSInterfaceInfo); + +#endif diff --git a/LUFA/Drivers/USB/Class/Device/RNDIS.c b/LUFA/Drivers/USB/Class/Device/RNDIS.c new file mode 100644 index 0000000000..49c7df01da --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/RNDIS.c @@ -0,0 +1,456 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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. +*/ + +#define INCLUDE_FROM_RNDIS_CLASS_C +#include "RNDIS.h" + +static const uint32_t PROGMEM AdapterSupportedOIDList[] = + { + OID_GEN_SUPPORTED_LIST, + OID_GEN_PHYSICAL_MEDIUM, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_MEDIA_CONNECT_STATUS, + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAXIMUM_LIST_SIZE, + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, + }; + +void USB_RNDIS_ProcessControlPacket(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo) +{ + if (!(Endpoint_IsSETUPReceived())) + return; + + if (USB_ControlRequest.wIndex != RNDISInterfaceInfo->ControlInterfaceNumber) + return; + + switch (USB_ControlRequest.bRequest) + { + case REQ_SendEncapsulatedCommand: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + Endpoint_Read_Control_Stream_LE(RNDISInterfaceInfo->RNDISMessageBuffer, USB_ControlRequest.wLength); + Endpoint_ClearIN(); + + USB_RNDIS_ProcessRNDISControlMessage(RNDISInterfaceInfo); + } + + break; + case REQ_GetEncapsulatedResponse: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; + + if (!(MessageHeader->MessageLength)) + { + RNDISInterfaceInfo->RNDISMessageBuffer[0] = 0; + MessageHeader->MessageLength = 1; + } + + Endpoint_Write_Control_Stream_LE(RNDISInterfaceInfo->RNDISMessageBuffer, MessageHeader->MessageLength); + Endpoint_ClearOUT(); + + MessageHeader->MessageLength = 0; + } + + break; + } +} + +bool USB_RNDIS_ConfigureEndpoints(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo) +{ + if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->DataINEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_IN, RNDISInterfaceInfo->DataINEndpointSize, + ENDPOINT_BANK_SINGLE))) + { + return false; + } + + if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_OUT, RNDISInterfaceInfo->DataOUTEndpointSize, + ENDPOINT_BANK_SINGLE))) + { + return false; + } + + if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->NotificationEndpointNumber, EP_TYPE_INTERRUPT, + ENDPOINT_DIR_IN, RNDISInterfaceInfo->NotificationEndpointSize, + ENDPOINT_BANK_SINGLE))) + { + return false; + } + + return true; +} + +void USB_RNDIS_USBTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo) +{ + if (!(USB_IsConnected)) + return; + + RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; + + Endpoint_SelectEndpoint(RNDISInterfaceInfo->NotificationEndpointNumber); + + if (Endpoint_IsINReady() && RNDISInterfaceInfo->ResponseReady) + { + USB_Request_Header_t Notification = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = NOTIF_ResponseAvailable, + .wValue = 0, + .wIndex = 0, + .wLength = 0, + }; + + Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK); + + Endpoint_ClearIN(); + + RNDISInterfaceInfo->ResponseReady = false; + } + + if ((RNDISInterfaceInfo->CurrRNDISState == RNDIS_Data_Initialized) && !(MessageHeader->MessageLength)) + { + RNDIS_PACKET_MSG_t RNDISPacketHeader; + + Endpoint_SelectEndpoint(RNDISInterfaceInfo->DataOUTEndpointNumber); + + if (Endpoint_IsOUTReceived() && !(RNDISInterfaceInfo->FrameIN.FrameInBuffer)) + { + Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t), NO_STREAM_CALLBACK); + + if (RNDISPacketHeader.DataLength > ETHERNET_FRAME_SIZE_MAX) + { + Endpoint_StallTransaction(); + return; + } + + Endpoint_Read_Stream_LE(RNDISInterfaceInfo->FrameIN.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK); + + Endpoint_ClearOUT(); + + RNDISInterfaceInfo->FrameIN.FrameLength = RNDISPacketHeader.DataLength; + + RNDISInterfaceInfo->FrameIN.FrameInBuffer = true; + } + + Endpoint_SelectEndpoint(RNDISInterfaceInfo->DataINEndpointNumber); + + if (Endpoint_IsINReady() && RNDISInterfaceInfo->FrameOUT.FrameInBuffer) + { + memset(&RNDISPacketHeader, 0, sizeof(RNDIS_PACKET_MSG_t)); + + RNDISPacketHeader.MessageType = REMOTE_NDIS_PACKET_MSG; + RNDISPacketHeader.MessageLength = (sizeof(RNDIS_PACKET_MSG_t) + RNDISInterfaceInfo->FrameOUT.FrameLength); + RNDISPacketHeader.DataOffset = (sizeof(RNDIS_PACKET_MSG_t) - sizeof(RNDIS_Message_Header_t)); + RNDISPacketHeader.DataLength = RNDISInterfaceInfo->FrameOUT.FrameLength; + + Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t), NO_STREAM_CALLBACK); + Endpoint_Write_Stream_LE(RNDISInterfaceInfo->FrameOUT.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK); + Endpoint_ClearIN(); + + RNDISInterfaceInfo->FrameOUT.FrameInBuffer = false; + } + } +} + +void USB_RNDIS_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo) +{ + /* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of + this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */ + + RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; + + switch (MessageHeader->MessageType) + { + case REMOTE_NDIS_INITIALIZE_MSG: + RNDISInterfaceInfo->ResponseReady = true; + + RNDIS_INITIALIZE_MSG_t* INITIALIZE_Message = (RNDIS_INITIALIZE_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; + RNDIS_INITIALIZE_CMPLT_t* INITIALIZE_Response = (RNDIS_INITIALIZE_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; + + INITIALIZE_Response->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT; + INITIALIZE_Response->MessageLength = sizeof(RNDIS_INITIALIZE_CMPLT_t); + INITIALIZE_Response->RequestId = INITIALIZE_Message->RequestId; + INITIALIZE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS; + + INITIALIZE_Response->MajorVersion = REMOTE_NDIS_VERSION_MAJOR; + INITIALIZE_Response->MinorVersion = REMOTE_NDIS_VERSION_MINOR; + INITIALIZE_Response->DeviceFlags = REMOTE_NDIS_DF_CONNECTIONLESS; + INITIALIZE_Response->Medium = REMOTE_NDIS_MEDIUM_802_3; + INITIALIZE_Response->MaxPacketsPerTransfer = 1; + INITIALIZE_Response->MaxTransferSize = (sizeof(RNDIS_PACKET_MSG_t) + ETHERNET_FRAME_SIZE_MAX); + INITIALIZE_Response->PacketAlignmentFactor = 0; + INITIALIZE_Response->AFListOffset = 0; + INITIALIZE_Response->AFListSize = 0; + + RNDISInterfaceInfo->CurrRNDISState = RNDIS_Initialized; + + break; + case REMOTE_NDIS_HALT_MSG: + RNDISInterfaceInfo->ResponseReady = false; + MessageHeader->MessageLength = 0; + + RNDISInterfaceInfo->CurrRNDISState = RNDIS_Uninitialized; + + break; + case REMOTE_NDIS_QUERY_MSG: + RNDISInterfaceInfo->ResponseReady = true; + + RNDIS_QUERY_MSG_t* QUERY_Message = (RNDIS_QUERY_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; + RNDIS_QUERY_CMPLT_t* QUERY_Response = (RNDIS_QUERY_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; + uint32_t Query_Oid = QUERY_Message->Oid; + + void* QueryData = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) + + QUERY_Message->InformationBufferOffset]; + void* ResponseData = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_QUERY_CMPLT_t)]; + uint16_t ResponseSize; + + QUERY_Response->MessageType = REMOTE_NDIS_QUERY_CMPLT; + QUERY_Response->MessageLength = sizeof(RNDIS_QUERY_CMPLT_t); + + if (USB_RNDIS_ProcessNDISQuery(RNDISInterfaceInfo, Query_Oid, QueryData, QUERY_Message->InformationBufferLength, + ResponseData, &ResponseSize)) + { + QUERY_Response->Status = REMOTE_NDIS_STATUS_SUCCESS; + QUERY_Response->MessageLength += ResponseSize; + + QUERY_Response->InformationBufferLength = ResponseSize; + QUERY_Response->InformationBufferOffset = (sizeof(RNDIS_QUERY_CMPLT_t) - sizeof(RNDIS_Message_Header_t)); + } + else + { + QUERY_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED; + + QUERY_Response->InformationBufferLength = 0; + QUERY_Response->InformationBufferOffset = 0; + } + + break; + case REMOTE_NDIS_SET_MSG: + RNDISInterfaceInfo->ResponseReady = true; + + RNDIS_SET_MSG_t* SET_Message = (RNDIS_SET_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; + RNDIS_SET_CMPLT_t* SET_Response = (RNDIS_SET_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; + uint32_t SET_Oid = SET_Message->Oid; + + SET_Response->MessageType = REMOTE_NDIS_SET_CMPLT; + SET_Response->MessageLength = sizeof(RNDIS_SET_CMPLT_t); + SET_Response->RequestId = SET_Message->RequestId; + + void* SetData = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) + + SET_Message->InformationBufferOffset]; + + if (USB_RNDIS_ProcessNDISSet(RNDISInterfaceInfo, SET_Oid, SetData, SET_Message->InformationBufferLength)) + SET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS; + else + SET_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED; + + break; + case REMOTE_NDIS_RESET_MSG: + RNDISInterfaceInfo->ResponseReady = true; + + RNDIS_RESET_CMPLT_t* RESET_Response = (RNDIS_RESET_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; + + RESET_Response->MessageType = REMOTE_NDIS_RESET_CMPLT; + RESET_Response->MessageLength = sizeof(RNDIS_RESET_CMPLT_t); + RESET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS; + RESET_Response->AddressingReset = 0; + + break; + case REMOTE_NDIS_KEEPALIVE_MSG: + RNDISInterfaceInfo->ResponseReady = true; + + RNDIS_KEEPALIVE_MSG_t* KEEPALIVE_Message = (RNDIS_KEEPALIVE_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; + RNDIS_KEEPALIVE_CMPLT_t* KEEPALIVE_Response = (RNDIS_KEEPALIVE_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer; + + KEEPALIVE_Response->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT; + KEEPALIVE_Response->MessageLength = sizeof(RNDIS_KEEPALIVE_CMPLT_t); + KEEPALIVE_Response->RequestId = KEEPALIVE_Message->RequestId; + KEEPALIVE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS; + + break; + } +} + +static bool USB_RNDIS_ProcessNDISQuery(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo, + uint32_t OId, void* QueryData, uint16_t QuerySize, + void* ResponseData, uint16_t* ResponseSize) +{ + switch (OId) + { + case OID_GEN_SUPPORTED_LIST: + *ResponseSize = sizeof(AdapterSupportedOIDList); + + memcpy_P(ResponseData, AdapterSupportedOIDList, sizeof(AdapterSupportedOIDList)); + + return true; + case OID_GEN_PHYSICAL_MEDIUM: + *ResponseSize = sizeof(uint32_t); + + /* Indicate that the device is a true ethernet link */ + *((uint32_t*)ResponseData) = 0; + + return true; + case OID_GEN_HARDWARE_STATUS: + *ResponseSize = sizeof(uint32_t); + + *((uint32_t*)ResponseData) = NdisHardwareStatusReady; + + return true; + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + *ResponseSize = sizeof(uint32_t); + + *((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIUM_802_3; + + return true; + case OID_GEN_VENDOR_ID: + *ResponseSize = sizeof(uint32_t); + + /* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */ + *((uint32_t*)ResponseData) = 0x00FFFFFF; + + return true; + case OID_GEN_MAXIMUM_FRAME_SIZE: + case OID_GEN_TRANSMIT_BLOCK_SIZE: + case OID_GEN_RECEIVE_BLOCK_SIZE: + *ResponseSize = sizeof(uint32_t); + + *((uint32_t*)ResponseData) = ETHERNET_FRAME_SIZE_MAX; + + return true; + case OID_GEN_VENDOR_DESCRIPTION: + *ResponseSize = (strlen(RNDISInterfaceInfo->AdapterVendorDescription) + 1); + + memcpy(ResponseData, RNDISInterfaceInfo->AdapterVendorDescription, *ResponseSize); + + return true; + case OID_GEN_MEDIA_CONNECT_STATUS: + *ResponseSize = sizeof(uint32_t); + + *((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIA_STATE_CONNECTED; + + return true; + case OID_GEN_LINK_SPEED: + *ResponseSize = sizeof(uint32_t); + + /* Indicate 10Mb/s link speed */ + *((uint32_t*)ResponseData) = 100000; + + return true; + case OID_802_3_PERMANENT_ADDRESS: + case OID_802_3_CURRENT_ADDRESS: + *ResponseSize = sizeof(MAC_Address_t); + + memcpy(ResponseData, &RNDISInterfaceInfo->AdapterMACAddress, sizeof(MAC_Address_t)); + + return true; + case OID_802_3_MAXIMUM_LIST_SIZE: + *ResponseSize = sizeof(uint32_t); + + /* Indicate only one multicast address supported */ + *((uint32_t*)ResponseData) = 1; + + return true; + case OID_GEN_CURRENT_PACKET_FILTER: + *ResponseSize = sizeof(uint32_t); + + *((uint32_t*)ResponseData) = RNDISInterfaceInfo->CurrPacketFilter; + + return true; + case OID_GEN_XMIT_OK: + case OID_GEN_RCV_OK: + case OID_GEN_XMIT_ERROR: + case OID_GEN_RCV_ERROR: + case OID_GEN_RCV_NO_BUFFER: + case OID_802_3_RCV_ERROR_ALIGNMENT: + case OID_802_3_XMIT_ONE_COLLISION: + case OID_802_3_XMIT_MORE_COLLISIONS: + *ResponseSize = sizeof(uint32_t); + + /* Unused statistic OIDs - always return 0 for each */ + *((uint32_t*)ResponseData) = 0; + + return true; + case OID_GEN_MAXIMUM_TOTAL_SIZE: + *ResponseSize = sizeof(uint32_t); + + /* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */ + *((uint32_t*)ResponseData) = (RNDIS_MESSAGE_BUFFER_SIZE + ETHERNET_FRAME_SIZE_MAX); + + return true; + default: + return false; + } +} + +static bool USB_RNDIS_ProcessNDISSet(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo, uint32_t OId, void* SetData, uint16_t SetSize) +{ + switch (OId) + { + case OID_GEN_CURRENT_PACKET_FILTER: + RNDISInterfaceInfo->CurrPacketFilter = *((uint32_t*)SetData); + RNDISInterfaceInfo->CurrRNDISState = ((RNDISInterfaceInfo->CurrPacketFilter) ? + RNDIS_Data_Initialized : RNDIS_Data_Initialized); + + return true; + case OID_802_3_MULTICAST_LIST: + /* Do nothing - throw away the value from the host as it is unused */ + + return true; + default: + return false; + } +} diff --git a/LUFA/Drivers/USB/Class/Device/RNDIS.h b/LUFA/Drivers/USB/Class/Device/RNDIS.h new file mode 100644 index 0000000000..73622a4dc0 --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/RNDIS.h @@ -0,0 +1,260 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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 _RNDIS_CLASS_H_ +#define _RNDIS_CLASS_H_ + + /* Includes: */ + #include + + #include "../../USB.h" + #include "RNDISConstants.h" + + /* Macros: */ + /** Implemented RNDIS Version Major */ + #define REMOTE_NDIS_VERSION_MAJOR 0x01 + + /** Implemented RNDIS Version Minor */ + #define REMOTE_NDIS_VERSION_MINOR 0x00 + + /** RNDIS request to issue a host-to-device NDIS command */ + #define REQ_SendEncapsulatedCommand 0x00 + + /** RNDIS request to issue a device-to-host NDIS response */ + #define REQ_GetEncapsulatedResponse 0x01 + + #define RNDIS_MESSAGE_BUFFER_SIZE 128 + + #define ETHERNET_FRAME_SIZE_MAX 1500 + + #define NOTIF_ResponseAvailable 1 + + /* Enums: */ + /** Enum for the possible NDIS adapter states. */ + enum RNDIS_States_t + { + RNDIS_Uninitialized = 0, /**< Adapter currently uninitialized */ + RNDIS_Initialized = 1, /**< Adapter currently initialized but not ready for data transfers */ + RNDIS_Data_Initialized = 2, /**< Adapter currently initialized and ready for data transfers */ + }; + + /** Enum for the NDIS hardware states */ + enum NDIS_Hardware_Status_t + { + NdisHardwareStatusReady, /**< Hardware Ready to accept commands from the host */ + NdisHardwareStatusInitializing, /**< Hardware busy initializing */ + NdisHardwareStatusReset, /**< Hardware reset */ + NdisHardwareStatusClosing, /**< Hardware currently closing */ + NdisHardwareStatusNotReady /**< Hardware not ready to accept commands from the host */ + }; + + /* Type Defines: */ + /** Type define for a physical MAC address of a device on a network */ + typedef struct + { + uint8_t Octets[6]; /**< Individual bytes of a MAC address */ + } MAC_Address_t; + + /** Type define for a RNDIS message header, sent before RNDIS messages */ + typedef struct + { + uint32_t MessageType; /**< RNDIS message type, a REMOTE_NDIS_*_MSG constant */ + uint32_t MessageLength; /**< Total length of the RNDIS message, in bytes */ + } RNDIS_Message_Header_t; + + /** Type define for an Ethernet frame buffer. */ + typedef struct + { + uint8_t FrameData[ETHERNET_FRAME_SIZE_MAX]; /**< Ethernet frame contents */ + uint16_t FrameLength; /**< Length in bytes of the Ethernet frame stored in the buffer */ + bool FrameInBuffer; /**< Indicates if a frame is currently stored in the buffer */ + } Ethernet_Frame_Info_t; + + /** Type define for a RNDIS packet message, used to encapsulate Ethernet packets sent to and from the adapter */ + typedef struct + { + uint32_t MessageType; + uint32_t MessageLength; + uint32_t DataOffset; + uint32_t DataLength; + uint32_t OOBDataOffset; + uint32_t OOBDataLength; + uint32_t NumOOBDataElements; + uint32_t PerPacketInfoOffset; + uint32_t PerPacketInfoLength; + uint32_t VcHandle; + uint32_t Reserved; + } RNDIS_PACKET_MSG_t; + + typedef struct + { + uint8_t ControlInterfaceNumber; /**< Interface number of the CDC control interface within the device */ + + uint8_t DataINEndpointNumber; /**< Endpoint number of the CDC interface's IN data endpoint */ + uint16_t DataINEndpointSize; /**< Size in bytes of the CDC interface's IN data endpoint */ + + uint8_t DataOUTEndpointNumber; /**< Endpoint number of the CDC interface's OUT data endpoint */ + uint16_t DataOUTEndpointSize; /**< Size in bytes of the CDC interface's OUT data endpoint */ + + uint8_t NotificationEndpointNumber; /**< Endpoint number of the CDC interface's IN notification endpoint, if used */ + uint16_t NotificationEndpointSize; /**< Size in bytes of the CDC interface's IN notification endpoint, if used */ + + char* AdapterVendorDescription; + MAC_Address_t AdapterMACAddress; + + uint8_t RNDISMessageBuffer[RNDIS_MESSAGE_BUFFER_SIZE]; + bool ResponseReady; + uint8_t CurrRNDISState; + uint32_t CurrPacketFilter; + Ethernet_Frame_Info_t FrameIN; + Ethernet_Frame_Info_t FrameOUT; + } USB_ClassInfo_RNDIS_t; + + /** Type define for a RNDIS Initialize command message */ + typedef struct + { + uint32_t MessageType; + uint32_t MessageLength; + uint32_t RequestId; + + uint32_t MajorVersion; + uint32_t MinorVersion; + uint32_t MaxTransferSize; + } RNDIS_INITIALIZE_MSG_t; + + /** Type define for a RNDIS Initialize complete response message */ + typedef struct + { + uint32_t MessageType; + uint32_t MessageLength; + uint32_t RequestId; + uint32_t Status; + + uint32_t MajorVersion; + uint32_t MinorVersion; + uint32_t DeviceFlags; + uint32_t Medium; + uint32_t MaxPacketsPerTransfer; + uint32_t MaxTransferSize; + uint32_t PacketAlignmentFactor; + uint32_t AFListOffset; + uint32_t AFListSize; + } RNDIS_INITIALIZE_CMPLT_t; + + /** Type define for a RNDIS Keepalive command message */ + typedef struct + { + uint32_t MessageType; + uint32_t MessageLength; + uint32_t RequestId; + } RNDIS_KEEPALIVE_MSG_t; + + /** Type define for a RNDIS Keepalive complete message */ + typedef struct + { + uint32_t MessageType; + uint32_t MessageLength; + uint32_t RequestId; + uint32_t Status; + } RNDIS_KEEPALIVE_CMPLT_t; + + /** Type define for a RNDIS Reset complete message */ + typedef struct + { + uint32_t MessageType; + uint32_t MessageLength; + uint32_t Status; + + uint32_t AddressingReset; + } RNDIS_RESET_CMPLT_t; + + /** Type define for a RNDIS Set command message */ + typedef struct + { + uint32_t MessageType; + uint32_t MessageLength; + uint32_t RequestId; + + uint32_t Oid; + uint32_t InformationBufferLength; + uint32_t InformationBufferOffset; + uint32_t DeviceVcHandle; + } RNDIS_SET_MSG_t; + + /** Type define for a RNDIS Set complete response message */ + typedef struct + { + uint32_t MessageType; + uint32_t MessageLength; + uint32_t RequestId; + uint32_t Status; + } RNDIS_SET_CMPLT_t; + + /** Type define for a RNDIS Query command message */ + typedef struct + { + uint32_t MessageType; + uint32_t MessageLength; + uint32_t RequestId; + + uint32_t Oid; + uint32_t InformationBufferLength; + uint32_t InformationBufferOffset; + uint32_t DeviceVcHandle; + } RNDIS_QUERY_MSG_t; + + /** Type define for a RNDIS Query complete response message */ + typedef struct + { + uint32_t MessageType; + uint32_t MessageLength; + uint32_t RequestId; + uint32_t Status; + + uint32_t InformationBufferLength; + uint32_t InformationBufferOffset; + } RNDIS_QUERY_CMPLT_t; + + /* Function Prototypes: */ + #if defined(INCLUDE_FROM_RNDIS_CLASS_C) + static void USB_RNDIS_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); + static bool USB_RNDIS_ProcessNDISQuery(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo, + uint32_t OId, void* QueryData, uint16_t QuerySize, + void* ResponseData, uint16_t* ResponseSize); + static bool USB_RNDIS_ProcessNDISSet(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo, uint32_t OId, + void* SetData, uint16_t SetSize); + #endif + + void USB_RNDIS_USBTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); + bool USB_RNDIS_ConfigureEndpoints(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); + void USB_RNDIS_ProcessControlPacket(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); + void USB_RNDIS_USBTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo); + +#endif diff --git a/LUFA/Drivers/USB/Class/Device/RNDISConstants.h b/LUFA/Drivers/USB/Class/Device/RNDISConstants.h new file mode 100644 index 0000000000..ad66f62db7 --- /dev/null +++ b/LUFA/Drivers/USB/Class/Device/RNDISConstants.h @@ -0,0 +1,99 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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. +*/ + +/** \file + * + * RNDIS specification related constants. For more information on these + * constants, please refer to the Microsoft RNDIS specification. + */ + +#ifndef _RNDIS_CONSTANTS_H_ +#define _RNDIS_CONSTANTS_H_ + + /* Macros: */ + #define REMOTE_NDIS_PACKET_MSG 0x00000001UL + #define REMOTE_NDIS_INITIALIZE_MSG 0x00000002UL + #define REMOTE_NDIS_HALT_MSG 0x00000003UL + #define REMOTE_NDIS_QUERY_MSG 0x00000004UL + #define REMOTE_NDIS_SET_MSG 0x00000005UL + #define REMOTE_NDIS_RESET_MSG 0x00000006UL + #define REMOTE_NDIS_INDICATE_STATUS_MSG 0x00000007UL + #define REMOTE_NDIS_KEEPALIVE_MSG 0x00000008UL + + #define REMOTE_NDIS_INITIALIZE_CMPLT 0x80000002UL + #define REMOTE_NDIS_QUERY_CMPLT 0x80000004UL + #define REMOTE_NDIS_SET_CMPLT 0x80000005UL + #define REMOTE_NDIS_RESET_CMPLT 0x80000006UL + #define REMOTE_NDIS_KEEPALIVE_CMPLT 0x80000008UL + + #define REMOTE_NDIS_STATUS_SUCCESS 0x00000000UL + #define REMOTE_NDIS_STATUS_FAILURE 0xC0000001UL + #define REMOTE_NDIS_STATUS_INVALID_DATA 0xC0010015UL + #define REMOTE_NDIS_STATUS_NOT_SUPPORTED 0xC00000BBUL + #define REMOTE_NDIS_STATUS_MEDIA_CONNECT 0x4001000BUL + #define REMOTE_NDIS_STATUS_MEDIA_DISCONNECT 0x4001000CUL + + #define REMOTE_NDIS_MEDIA_STATE_CONNECTED 0x00000000UL + #define REMOTE_NDIS_MEDIA_STATE_DISCONNECTED 0x00000001UL + + #define REMOTE_NDIS_MEDIUM_802_3 0x00000000UL + + #define REMOTE_NDIS_DF_CONNECTIONLESS 0x00000001UL + #define REMOTE_NDIS_DF_CONNECTION_ORIENTED 0x00000002UL + + #define OID_GEN_SUPPORTED_LIST 0x00010101UL + #define OID_GEN_HARDWARE_STATUS 0x00010102UL + #define OID_GEN_MEDIA_SUPPORTED 0x00010103UL + #define OID_GEN_MEDIA_IN_USE 0x00010104UL + #define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106UL + #define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111UL + #define OID_GEN_LINK_SPEED 0x00010107UL + #define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010AUL + #define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010BUL + #define OID_GEN_VENDOR_ID 0x0001010CUL + #define OID_GEN_VENDOR_DESCRIPTION 0x0001010DUL + #define OID_GEN_CURRENT_PACKET_FILTER 0x0001010EUL + #define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111UL + #define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114UL + #define OID_GEN_PHYSICAL_MEDIUM 0x00010202UL + #define OID_GEN_XMIT_OK 0x00020101UL + #define OID_GEN_RCV_OK 0x00020102UL + #define OID_GEN_XMIT_ERROR 0x00020103UL + #define OID_GEN_RCV_ERROR 0x00020104UL + #define OID_GEN_RCV_NO_BUFFER 0x00020105UL + #define OID_802_3_PERMANENT_ADDRESS 0x01010101UL + #define OID_802_3_CURRENT_ADDRESS 0x01010102UL + #define OID_802_3_MULTICAST_LIST 0x01010103UL + #define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104UL + #define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101UL + #define OID_802_3_XMIT_ONE_COLLISION 0x01020102UL + #define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103UL + +#endif diff --git a/LUFA/Drivers/USB/Class/HIDParser.c b/LUFA/Drivers/USB/Class/HIDParser.c deleted file mode 100644 index 5fb29aa0a6..0000000000 --- a/LUFA/Drivers/USB/Class/HIDParser.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2009. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, provided that the above copyright notice appear in all - copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - The author disclaim 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, 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 "HIDParser.h" - -uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, HID_ReportInfo_t* const ParserData) -{ - HID_StateTable_t StateTable[HID_STATETABLE_STACK_DEPTH]; - HID_StateTable_t* CurrStateTable = &StateTable[0]; - uint16_t UsageStack[HID_USAGE_STACK_DEPTH]; - uint8_t UsageStackSize = 0; - uint16_t BitOffsetIn = 0; - uint16_t BitOffsetOut = 0; -#if defined(HID_ENABLE_FEATURE_PROCESSING) - uint16_t BitOffsetFeature = 0; -#endif - HID_CollectionPath_t* CurrCollectionPath = NULL; - - memset((void*)ParserData, 0x00, sizeof(HID_ReportInfo_t)); - memset((void*)StateTable, 0x00, sizeof(StateTable)); - - while (ReportSize) - { - uint32_t ReportItemData = 0; - - switch (*ReportData & DATA_SIZE_MASK) - { - case DATA_SIZE_4: - ReportItemData = *((uint32_t*)(ReportData + 1)); - break; - case DATA_SIZE_2: - ReportItemData = *((uint16_t*)(ReportData + 1)); - break; - case DATA_SIZE_1: - ReportItemData = *((uint8_t*)(ReportData + 1)); - break; - } - - switch (*ReportData & (TYPE_MASK | TAG_MASK)) - { - case (TYPE_GLOBAL | TAG_GLOBAL_PUSH): - if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH]) - return HID_PARSE_HIDStackOverflow; - - memcpy((CurrStateTable - 1), - CurrStateTable, - sizeof(HID_ReportItem_t)); - - CurrStateTable++; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_POP): - if (CurrStateTable == &StateTable[0]) - return HID_PARSE_HIDStackUnderflow; - - CurrStateTable--; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE): - CurrStateTable->Attributes.Usage.Page = ReportItemData; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN): - CurrStateTable->Attributes.Logical.Minimum = ReportItemData; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX): - CurrStateTable->Attributes.Logical.Maximum = ReportItemData; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN): - CurrStateTable->Attributes.Physical.Minimum = ReportItemData; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX): - CurrStateTable->Attributes.Physical.Maximum = ReportItemData; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP): - CurrStateTable->Attributes.Unit.Exponent = ReportItemData; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_UNIT): - CurrStateTable->Attributes.Unit.Type = ReportItemData; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE): - CurrStateTable->Attributes.BitSize = ReportItemData; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT): - CurrStateTable->ReportCount = ReportItemData; - break; - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID): - CurrStateTable->ReportID = ReportItemData; - break; - case (TYPE_LOCAL | TAG_LOCAL_USAGE): - if (UsageStackSize == HID_USAGE_STACK_DEPTH) - return HID_PARSE_UsageStackOverflow; - - UsageStack[UsageStackSize++] = ReportItemData; - break; - case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN): - CurrStateTable->Attributes.Usage.MinMax.Minimum = ReportItemData; - break; - case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX): - CurrStateTable->Attributes.Usage.MinMax.Maximum = ReportItemData; - break; - case (TYPE_MAIN | TAG_MAIN_COLLECTION): - if (CurrCollectionPath == NULL) - { - CurrCollectionPath = &ParserData->CollectionPaths[0]; - } - else - { - HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath; - - CurrCollectionPath = &ParserData->CollectionPaths[1]; - - while (CurrCollectionPath->Parent != NULL); - { - if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS]) - return HID_PARSE_InsufficientCollectionPaths; - - CurrCollectionPath++; - } - - CurrCollectionPath->Parent = ParentCollectionPath; - } - - CurrCollectionPath->Type = ReportItemData; - CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page; - - if (UsageStackSize) - { - CurrCollectionPath->Usage.Usage = UsageStack[0]; - - for (uint8_t i = 0; i < UsageStackSize; i++) - UsageStack[i] = UsageStack[i + 1]; - - UsageStackSize--; - } - else - { - CurrCollectionPath->Usage.Usage = 0; - } - - break; - case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION): - if (CurrCollectionPath == NULL) - return HID_PARSE_UnexpectedEndCollection; - - CurrCollectionPath = CurrCollectionPath->Parent; - - break; - case (TYPE_MAIN | TAG_MAIN_INPUT): - case (TYPE_MAIN | TAG_MAIN_OUTPUT): -#if defined(HID_ENABLE_FEATURE_PROCESSING) - case (TYPE_MAIN | TAG_MAIN_FEATURE): -#endif - for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++) - { - HID_ReportItem_t* CurrReportItem = &ParserData->ReportItems[ParserData->TotalReportItems]; - - if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS) - return HID_PARSE_InsufficientReportItems; - - memcpy(&CurrReportItem->Attributes, - &CurrStateTable->Attributes, - sizeof(HID_ReportItem_Attributes_t)); - - CurrReportItem->ItemFlags = ReportItemData; - CurrReportItem->CollectionPath = CurrCollectionPath; - CurrReportItem->ReportID = CurrStateTable->ReportID; - - if (UsageStackSize) - { - CurrReportItem->Attributes.Usage.Usage = UsageStack[0]; - - for (uint8_t i = 0; i < UsageStackSize; i++) - UsageStack[i] = UsageStack[i + 1]; - - UsageStackSize--; - } - else - { - CurrReportItem->Attributes.Usage.Usage = 0; - } - - switch (*ReportData & TAG_MASK) - { - case TAG_MAIN_INPUT: - CurrReportItem->ItemType = REPORT_ITEM_TYPE_In; - CurrReportItem->BitOffset = BitOffsetIn; - - BitOffsetIn += CurrStateTable->Attributes.BitSize; - - break; - case TAG_MAIN_OUTPUT: - CurrReportItem->ItemType = REPORT_ITEM_TYPE_Out; - CurrReportItem->BitOffset = BitOffsetOut; - - BitOffsetOut += CurrStateTable->Attributes.BitSize; - - break; -#if defined(HID_ENABLE_FEATURE_PROCESSING) - case TAG_MAIN_FEATURE: - CurrReportItem->ItemType = REPORT_ITEM_TYPE_Feature; - CurrReportItem->BitOffset = BitOffsetFeature; - - BitOffsetFeature += CurrStateTable->Attributes.BitSize; - - break; -#endif - } - -#if !defined(HID_INCLUDE_CONSTANT_DATA_ITEMS) - if (!(ReportItemData & IOF_CONSTANT)) - ParserData->TotalReportItems++; -#else - ParserData->TotalReportItems++; -#endif - } - - UsageStackSize = 0; - - break; - } - - if ((*ReportData & TYPE_MASK) == TYPE_MAIN) - { - CurrStateTable->Attributes.Usage.MinMax.Minimum = 0; - CurrStateTable->Attributes.Usage.MinMax.Maximum = 0; - UsageStackSize = 0; - } - - switch (*ReportData & DATA_SIZE_MASK) - { - case DATA_SIZE_4: - ReportSize -= 5; - ReportData += 5; - break; - case DATA_SIZE_2: - ReportSize -= 3; - ReportData += 3; - break; - case DATA_SIZE_1: - ReportSize -= 2; - ReportData += 2; - break; - case DATA_SIZE_0: - ReportSize -= 1; - ReportData += 1; - break; - } - } - - return HID_PARSE_Successful; -} - -bool USB_GetHIDReportItemInfo(const uint8_t* ReportData, HID_ReportItem_t* const ReportItem) -{ - uint16_t DataBitsRem = ReportItem->Attributes.BitSize; - uint16_t CurrentBit = ReportItem->BitOffset; - uint32_t BitMask = (1 << 0); - - ReportItem->Value = 0; - - if (ReportItem->ReportID) - { - if (ReportItem->ReportID != ReportData[0]) - return false; - - ReportData++; - } - - while (DataBitsRem--) - { - if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8))) - ReportItem->Value |= BitMask; - - CurrentBit++; - BitMask <<= 1; - } - - return true; -} - -void USB_SetHIDReportItemInfo(uint8_t* ReportData, const HID_ReportItem_t* ReportItem) -{ - uint16_t DataBitsRem = ReportItem->Attributes.BitSize; - uint16_t CurrentBit = ReportItem->BitOffset; - uint32_t BitMask = (1 << 0); - - if (ReportItem->ReportID) - { - ReportData[0] = ReportItem->ReportID; - ReportData++; - } - - while (DataBitsRem--) - { - if (ReportItem->Value & (1 << (CurrentBit % 8))) - ReportData[CurrentBit / 8] |= BitMask; - - CurrentBit++; - BitMask <<= 1; - } -} diff --git a/LUFA/Drivers/USB/Class/HIDParser.h b/LUFA/Drivers/USB/Class/HIDParser.h deleted file mode 100644 index 49e57c2958..0000000000 --- a/LUFA/Drivers/USB/Class/HIDParser.h +++ /dev/null @@ -1,263 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2009. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, provided that the above copyright notice appear in all - copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - The author disclaim 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, 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. -*/ - -/** \file - * - * USB Human Interface Device (HID) Class report descriptor processing routines. This file allows for the easy - * parsing of the complex HID report descriptor, which describes the data that the device transmits to the host. - * - */ - -/** \ingroup Group_USB - * @defgroup Group_HIDParser HID Report Parser - * - * Functions, macros, variables, enums and types related to the parsing of HID class device report descriptors. - * - * The processed HID report is presented back to the user application as a flat structure containing each report - * item's IN, OUT and FEATURE (if desired) items along with each item's attributes. - * - * This library portion also allows for easy setting and retrieval of data from a HID report, including devices - * with multiple reports on the one HID interface. - * - * By default, FEATURE reports and IN/OUT reports with constant data are ignored in the HID report when processed - * to save on memory. This can be overridden by defining the HID_ENABLE_FEATURE_PROCESSING or - * HID_INCLUDE_CONSTANT_DATA_ITEMS tokens in the user project makefile, passing them to the compiler via the -D - * switch. - * - * @{ - */ - -#ifndef __HIDPARSER_H__ -#define __HIDPARSER_H__ - - /* Includes: */ - #include - #include - - #include "HIDReportData.h" - - #include "../../../Common/Common.h" - - /* Enable C linkage for C++ Compilers: */ - #if defined(__cplusplus) - extern "C" { - #endif - - /* Preprocessor checks and defines: */ - #if !defined(HID_STATETABLE_STACK_DEPTH) || defined(__DOXYGEN__) - /** Constant indicating the maximum stack depth of the state table. A larger state table - * allows for more PUSH/POP report items to be nested, but consumes more memory. By default - * this is set to 3 levels (allowing for two PUSHes to be nested) but this can be overridden by - * defining HID_STATETABLE_STACK_DEPTH to another value in the user project makefile, passing the - * define to the compiler using the -D compiler switch. - */ - #define HID_STATETABLE_STACK_DEPTH 3 - #endif - - #if !defined(HID_USAGE_STACK_DEPTH) || defined(__DOXYGEN__) - /** Constant indicating the maximum stack depth of the usage table. A larger usage table - * allows for more USAGE items to be indicated sequentially for REPORT COUNT entries of more than - * one, but requires more stack space. By default this is set to 8 levels (allowing for a report - * item with a count of 8) but this can be overridden by defining HID_USAGE_STACK_DEPTH to another - * value in the user project makefile, passing the define to the compiler using the -D compiler - * switch. - */ - #define HID_USAGE_STACK_DEPTH 8 - #endif - - #if !defined(HID_MAX_COLLECTIONS) || defined(__DOXYGEN__) - /** Constant indicating the maximum number of COLLECTION items (nested or unnested) that can be - * processed in the report item descriptor. A large value allows for more COLLECTION items to be - * processed, but consumes more memory. By default this is set to 5 collections, but this can be - * overridden by defining HID_MAX_COLLECTIONS to another value in the user project makefile, passing - * the define to the compiler using the -D compiler switch. - */ - #define HID_MAX_COLLECTIONS 5 - #endif - - #if !defined(HID_MAX_REPORTITEMS) || defined(__DOXYGEN__) - /** Constant indicating the maximum number of report items (IN, OUT or FEATURE if enabled) that can be - * processed in the report item descriptor. A large value allows for more report items to be - * processed, but consumes more memory. By default this is set to 30 items, but this can be - * overridden by defining HID_MAX_REPORTITEMS to another value in the user project makefile, passing - * the define to the compiler using the -D compiler switch. - */ - #define HID_MAX_REPORTITEMS 30 - #endif - - /* Public Interface - May be used in end-application: */ - /* Enums: */ - /** Enum for indicating what type of report item an entry in a \ref HID_ReportInfo_t ReportItem array is */ - enum HID_ReportItemTypes_t - { - REPORT_ITEM_TYPE_In = 0, /**< Indicates that the item is an IN report type. */ - REPORT_ITEM_TYPE_Out = 1, /**< Indicates that the item is an OUT report type. */ - REPORT_ITEM_TYPE_Feature = 2, /**< Indicates that the item is a FEATURE report type. */ - }; - - /** Enum for the possible error codes in the return value of the \ref USB_ProcessHIDReport() function */ - enum HID_Parse_ErrorCodes_t - { - HID_PARSE_Successful = 0, /**< Successful parse of the HID report descriptor, no error. */ - HID_PARSE_HIDStackOverflow = 1, /**< More than \ref HID_STATETABLE_STACK_DEPTH nested PUSHes in the report. */ - HID_PARSE_HIDStackUnderflow = 2, /**< A POP was found when the state table stack was empty. */ - HID_PARSE_InsufficientReportItems = 3, /**< More than \ref HID_MAX_REPORTITEMS report items in the report. */ - HID_PARSE_UnexpectedEndCollection = 4, /**< END COLLECTION found without matching COLLECTION item. */ - HID_PARSE_InsufficientCollectionPaths = 5, /**< More than \ref HID_MAX_COLLECTIONS collections in the report. */ - HID_PARSE_UsageStackOverflow = 6, /**< More than \ref HID_USAGE_STACK_DEPTH usages listed in a row. */ - }; - - /* Type Defines: */ - /** Type define for an attribute with both minimum and maximum values (e.g. Logical Min/Max). */ - typedef struct - { - uint32_t Minimum; /**< Minimum value for the attribute. */ - uint32_t Maximum; /**< Maximum value for the attribute. */ - } HID_MinMax_t; - - /** Type define for the Unit attributes of a report item. */ - typedef struct - { - uint32_t Type; /**< Unit type (refer to HID specifications for details). */ - uint8_t Exponent; /**< Unit exponent (refer to HID specifications for details). */ - } HID_Unit_t; - - /** Type define for the Usage attributes of a report item. */ - typedef struct - { - uint16_t Page; /**< Usage page of the report item. */ - uint16_t Usage; /**< Usage of the report item. */ - HID_MinMax_t MinMax; /**< Usage minimum and maximum of the report item. */ - } HID_Usage_t; - - /** Type define for a COLLECTION object. Contains the collection attributes and a reference to the - * parent collection if any. - */ - typedef struct CollectionPath - { - uint8_t Type; /**< Collection type (e.g. "Generic Desktop"). */ - HID_Usage_t Usage; /**< Collection usage. */ - struct CollectionPath* Parent; /**< Reference to parent collection, or NULL if root collection. */ - } HID_CollectionPath_t; - - /** Type define for all the data attributes of a report item, except flags. */ - typedef struct - { - uint8_t BitSize; /**< Size in bits of the report item's data. */ - - HID_Usage_t Usage; /**< Usage of the report item. */ - HID_Unit_t Unit; /**< Unit type and exponent of the report item. */ - HID_MinMax_t Logical; /**< Logical minimum and maximum of the report item. */ - HID_MinMax_t Physical; /**< Physical minimum and maximum of the report item. */ - } HID_ReportItem_Attributes_t; - - /** Type define for a report item (IN, OUT or FEATURE) attributes and other details. */ - typedef struct - { - uint16_t BitOffset; /**< Bit offset in the IN, OUT or FEATURE report of the item. */ - uint8_t ItemType; /**< Report item type, a value in HID_Types_t. */ - uint16_t ItemFlags; /**< Item data flags, such as constant/variable, etc. */ - uint8_t ReportID; /**< Report ID this item belongs to, or 0x00 if device has only one report */ - HID_CollectionPath_t* CollectionPath; /**< Collection path of the item. */ - - HID_ReportItem_Attributes_t Attributes; /**< Report item attributes. */ - - uint32_t Value; /**< Current value of the report item. */ - } HID_ReportItem_t; - - /** Type define for a complete processed HID report, including all report item data and collections. */ - typedef struct - { - uint8_t TotalReportItems; /**< Total number of report items stored in the - * ReportItems array. */ - - HID_ReportItem_t ReportItems[HID_MAX_REPORTITEMS]; /**< Report items array, including - * all IN, OUT and FEATURE items. */ - - HID_CollectionPath_t CollectionPaths[HID_MAX_COLLECTIONS]; /**< All collection items, referenced - * by the report items. */ - } HID_ReportInfo_t; - - /* Function Prototypes: */ - /** Function to process a given HID report returned from an attached device, and store it into a given - * \ref HID_ReportInfo_t structure. - * - * \param ReportData Buffer containing the device's HID report table - * \param ReportSize Size in bytes of the HID report table - * \param ParserData Pointer to a \ref HID_ReportInfo_t instance for the parser output - * - * \return A value in the \ref HID_Parse_ErrorCodes_t enum - */ - uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, HID_ReportInfo_t* const ParserData) - ATTR_NON_NULL_PTR_ARG(1, 3); - - /** Extracts the given report item's value out of the given HID report and places it into the Value - * member of the report item's \ref HID_ReportItem_t structure. - * - * \param ReportData Buffer containing an IN or FEATURE report from an attached device - * \param ReportItem Pointer to the report item of interest in a \ref HID_ReportInfo_t ReportItem array - * - * \returns Boolean true if the item to retrieve was located in the given report, false otherwise - */ - bool USB_GetHIDReportItemInfo(const uint8_t* ReportData, HID_ReportItem_t* const ReportItem) - ATTR_NON_NULL_PTR_ARG(1, 2); - - /** Retrieves the given report item's value out of the Value member of the report item's - * \ref HID_ReportItem_t structure and places it into the correct position in the HID report - * buffer. The report buffer is assumed to have the appropriate bits cleared before calling - * this function (i.e., the buffer should be explicitly cleared before report values are added). - * - * If the device has multiple HID reports, the report ID is set to the report ID of the given item. - * - * \param ReportData Buffer holding the current OUT report data - * \param ReportItem Pointer to the report item of interest in a \ref HID_ReportInfo_t ReportItem array - */ - void USB_SetHIDReportItemInfo(uint8_t* ReportData, const HID_ReportItem_t* ReportItem) - ATTR_NON_NULL_PTR_ARG(1, 2); - - /* Private Interface - For use in library only: */ - #if !defined(__DOXYGEN__) - /* Type Defines: */ - typedef struct - { - HID_ReportItem_Attributes_t Attributes; - uint8_t ReportCount; - uint8_t ReportID; - } HID_StateTable_t; - #endif - - /* Disable C linkage for C++ Compilers: */ - #if defined(__cplusplus) - } - #endif - -#endif - -/** @} */ diff --git a/LUFA/Drivers/USB/Class/HIDReportData.h b/LUFA/Drivers/USB/Class/HIDReportData.h deleted file mode 100644 index eee38be04d..0000000000 --- a/LUFA/Drivers/USB/Class/HIDReportData.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2009. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, provided that the above copyright notice appear in all - copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - The author disclaim 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, 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. -*/ - -/** \file - * - * Constants for HID report item attributes. Refer to the HID specification for details on each - * flag's meaning when applied to an IN, OUT or FEATURE item. - */ - -/** \ingroup Group_HIDParser - * @defgroup Group_HIDIOFConst Input/Output/Feature Masks - * - * Masks indicating the type of Input, Output of Feature HID report item. - * - * @{ - */ - -#ifndef __HIDREPORTDATA_H__ -#define __HIDREPORTDATA_H__ - - /* Public Interface - May be used in end-application: */ - /* Macros: */ - /** HID_ReportItem_t.ItemFlags flag for constant data. */ - #define IOF_CONSTANT (1 << 0) - - /** HID_ReportItem_t.ItemFlags flag for data. */ - #define IOF_DATA (0 << 0) - - /** HID_ReportItem_t.ItemFlags flag for variable data. */ - #define IOF_VARIABLE (1 << 1) - - /** HID_ReportItem_t.ItemFlags flag for array data. */ - #define IOF_ARRAY (0 << 1) - - /** HID_ReportItem_t.ItemFlags flag for relative data. */ - #define IOF_RELATIVE (1 << 2) - - /** HID_ReportItem_t.ItemFlags flag for absolute data. */ - #define IOF_ABSOLUTE (0 << 2) - - /** HID_ReportItem_t.ItemFlags flag for wrapped value data. */ - #define IOF_WRAP (1 << 3) - - /** HID_ReportItem_t.ItemFlags flag for non-wrapped value data. */ - #define IOF_NOWRAP (0 << 3) - - /** HID_ReportItem_t.ItemFlags flag for non linear data. */ - #define IOF_NONLINEAR (1 << 4) - - /** HID_ReportItem_t.ItemFlags flag for linear data. */ - #define IOF_LINEAR (0 << 4) - - /** HID_ReportItem_t.ItemFlags flag for no preferred state. */ - #define IOF_NOPREFERRED (1 << 5) - - /** HID_ReportItem_t.ItemFlags flag for preferred state items. */ - #define IOF_PREFERREDSTATE (0 << 5) - - /** HID_ReportItem_t.ItemFlags flag for null state items. */ - #define IOF_NULLSTATE (1 << 6) - - /** HID_ReportItem_t.ItemFlags flag for no null position data. */ - #define IOF_NONULLPOSITION (0 << 6) - - /** HID_ReportItem_t.ItemFlags flag for buffered bytes. */ - #define IOF_BUFFEREDBYTES (1 << 8) - - /** HID_ReportItem_t.ItemFlags flag for bit field data. */ - #define IOF_BITFIELD (0 << 8) - - /* Private Interface - For use in library only: */ - #if !defined(__DOXYGEN__) - /* Macros: */ - #define DATA_SIZE_MASK 0x03 - #define TYPE_MASK 0x0C - #define TAG_MASK 0xF0 - - #define DATA_SIZE_0 0x00 - #define DATA_SIZE_1 0x01 - #define DATA_SIZE_2 0x02 - #define DATA_SIZE_4 0x03 - - #define TYPE_MAIN 0x00 - #define TYPE_GLOBAL 0x04 - #define TYPE_LOCAL 0x08 - - #define TAG_MAIN_INPUT 0x80 - #define TAG_MAIN_OUTPUT 0x90 - #define TAG_MAIN_COLLECTION 0xA0 - #define TAG_MAIN_FEATURE 0xB0 - #define TAG_MAIN_ENDCOLLECTION 0xC0 - - #define TAG_GLOBAL_USAGEPAGE 0x00 - #define TAG_GLOBAL_LOGICALMIN 0x10 - #define TAG_GLOBAL_LOGICALMAX 0x20 - #define TAG_GLOBAL_PHYSMIN 0x30 - #define TAG_GLOBAL_PHYSMAX 0x40 - #define TAG_GLOBAL_UNITEXP 0x50 - #define TAG_GLOBAL_UNIT 0x60 - #define TAG_GLOBAL_REPORTSIZE 0x70 - #define TAG_GLOBAL_REPORTID 0x80 - #define TAG_GLOBAL_REPORTCOUNT 0x90 - #define TAG_GLOBAL_PUSH 0xA0 - #define TAG_GLOBAL_POP 0xB0 - - #define TAG_LOCAL_USAGE 0x00 - #define TAG_LOCAL_USAGEMIN 0x10 - #define TAG_LOCAL_USAGEMAX 0x20 - #endif - -/** @} */ - -#endif diff --git a/LUFA/Drivers/USB/Class/Host/HIDParser.c b/LUFA/Drivers/USB/Class/Host/HIDParser.c new file mode 100644 index 0000000000..5fb29aa0a6 --- /dev/null +++ b/LUFA/Drivers/USB/Class/Host/HIDParser.c @@ -0,0 +1,326 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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 "HIDParser.h" + +uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, HID_ReportInfo_t* const ParserData) +{ + HID_StateTable_t StateTable[HID_STATETABLE_STACK_DEPTH]; + HID_StateTable_t* CurrStateTable = &StateTable[0]; + uint16_t UsageStack[HID_USAGE_STACK_DEPTH]; + uint8_t UsageStackSize = 0; + uint16_t BitOffsetIn = 0; + uint16_t BitOffsetOut = 0; +#if defined(HID_ENABLE_FEATURE_PROCESSING) + uint16_t BitOffsetFeature = 0; +#endif + HID_CollectionPath_t* CurrCollectionPath = NULL; + + memset((void*)ParserData, 0x00, sizeof(HID_ReportInfo_t)); + memset((void*)StateTable, 0x00, sizeof(StateTable)); + + while (ReportSize) + { + uint32_t ReportItemData = 0; + + switch (*ReportData & DATA_SIZE_MASK) + { + case DATA_SIZE_4: + ReportItemData = *((uint32_t*)(ReportData + 1)); + break; + case DATA_SIZE_2: + ReportItemData = *((uint16_t*)(ReportData + 1)); + break; + case DATA_SIZE_1: + ReportItemData = *((uint8_t*)(ReportData + 1)); + break; + } + + switch (*ReportData & (TYPE_MASK | TAG_MASK)) + { + case (TYPE_GLOBAL | TAG_GLOBAL_PUSH): + if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH]) + return HID_PARSE_HIDStackOverflow; + + memcpy((CurrStateTable - 1), + CurrStateTable, + sizeof(HID_ReportItem_t)); + + CurrStateTable++; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_POP): + if (CurrStateTable == &StateTable[0]) + return HID_PARSE_HIDStackUnderflow; + + CurrStateTable--; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE): + CurrStateTable->Attributes.Usage.Page = ReportItemData; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN): + CurrStateTable->Attributes.Logical.Minimum = ReportItemData; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX): + CurrStateTable->Attributes.Logical.Maximum = ReportItemData; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN): + CurrStateTable->Attributes.Physical.Minimum = ReportItemData; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX): + CurrStateTable->Attributes.Physical.Maximum = ReportItemData; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP): + CurrStateTable->Attributes.Unit.Exponent = ReportItemData; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_UNIT): + CurrStateTable->Attributes.Unit.Type = ReportItemData; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE): + CurrStateTable->Attributes.BitSize = ReportItemData; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT): + CurrStateTable->ReportCount = ReportItemData; + break; + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID): + CurrStateTable->ReportID = ReportItemData; + break; + case (TYPE_LOCAL | TAG_LOCAL_USAGE): + if (UsageStackSize == HID_USAGE_STACK_DEPTH) + return HID_PARSE_UsageStackOverflow; + + UsageStack[UsageStackSize++] = ReportItemData; + break; + case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN): + CurrStateTable->Attributes.Usage.MinMax.Minimum = ReportItemData; + break; + case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX): + CurrStateTable->Attributes.Usage.MinMax.Maximum = ReportItemData; + break; + case (TYPE_MAIN | TAG_MAIN_COLLECTION): + if (CurrCollectionPath == NULL) + { + CurrCollectionPath = &ParserData->CollectionPaths[0]; + } + else + { + HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath; + + CurrCollectionPath = &ParserData->CollectionPaths[1]; + + while (CurrCollectionPath->Parent != NULL); + { + if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS]) + return HID_PARSE_InsufficientCollectionPaths; + + CurrCollectionPath++; + } + + CurrCollectionPath->Parent = ParentCollectionPath; + } + + CurrCollectionPath->Type = ReportItemData; + CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page; + + if (UsageStackSize) + { + CurrCollectionPath->Usage.Usage = UsageStack[0]; + + for (uint8_t i = 0; i < UsageStackSize; i++) + UsageStack[i] = UsageStack[i + 1]; + + UsageStackSize--; + } + else + { + CurrCollectionPath->Usage.Usage = 0; + } + + break; + case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION): + if (CurrCollectionPath == NULL) + return HID_PARSE_UnexpectedEndCollection; + + CurrCollectionPath = CurrCollectionPath->Parent; + + break; + case (TYPE_MAIN | TAG_MAIN_INPUT): + case (TYPE_MAIN | TAG_MAIN_OUTPUT): +#if defined(HID_ENABLE_FEATURE_PROCESSING) + case (TYPE_MAIN | TAG_MAIN_FEATURE): +#endif + for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++) + { + HID_ReportItem_t* CurrReportItem = &ParserData->ReportItems[ParserData->TotalReportItems]; + + if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS) + return HID_PARSE_InsufficientReportItems; + + memcpy(&CurrReportItem->Attributes, + &CurrStateTable->Attributes, + sizeof(HID_ReportItem_Attributes_t)); + + CurrReportItem->ItemFlags = ReportItemData; + CurrReportItem->CollectionPath = CurrCollectionPath; + CurrReportItem->ReportID = CurrStateTable->ReportID; + + if (UsageStackSize) + { + CurrReportItem->Attributes.Usage.Usage = UsageStack[0]; + + for (uint8_t i = 0; i < UsageStackSize; i++) + UsageStack[i] = UsageStack[i + 1]; + + UsageStackSize--; + } + else + { + CurrReportItem->Attributes.Usage.Usage = 0; + } + + switch (*ReportData & TAG_MASK) + { + case TAG_MAIN_INPUT: + CurrReportItem->ItemType = REPORT_ITEM_TYPE_In; + CurrReportItem->BitOffset = BitOffsetIn; + + BitOffsetIn += CurrStateTable->Attributes.BitSize; + + break; + case TAG_MAIN_OUTPUT: + CurrReportItem->ItemType = REPORT_ITEM_TYPE_Out; + CurrReportItem->BitOffset = BitOffsetOut; + + BitOffsetOut += CurrStateTable->Attributes.BitSize; + + break; +#if defined(HID_ENABLE_FEATURE_PROCESSING) + case TAG_MAIN_FEATURE: + CurrReportItem->ItemType = REPORT_ITEM_TYPE_Feature; + CurrReportItem->BitOffset = BitOffsetFeature; + + BitOffsetFeature += CurrStateTable->Attributes.BitSize; + + break; +#endif + } + +#if !defined(HID_INCLUDE_CONSTANT_DATA_ITEMS) + if (!(ReportItemData & IOF_CONSTANT)) + ParserData->TotalReportItems++; +#else + ParserData->TotalReportItems++; +#endif + } + + UsageStackSize = 0; + + break; + } + + if ((*ReportData & TYPE_MASK) == TYPE_MAIN) + { + CurrStateTable->Attributes.Usage.MinMax.Minimum = 0; + CurrStateTable->Attributes.Usage.MinMax.Maximum = 0; + UsageStackSize = 0; + } + + switch (*ReportData & DATA_SIZE_MASK) + { + case DATA_SIZE_4: + ReportSize -= 5; + ReportData += 5; + break; + case DATA_SIZE_2: + ReportSize -= 3; + ReportData += 3; + break; + case DATA_SIZE_1: + ReportSize -= 2; + ReportData += 2; + break; + case DATA_SIZE_0: + ReportSize -= 1; + ReportData += 1; + break; + } + } + + return HID_PARSE_Successful; +} + +bool USB_GetHIDReportItemInfo(const uint8_t* ReportData, HID_ReportItem_t* const ReportItem) +{ + uint16_t DataBitsRem = ReportItem->Attributes.BitSize; + uint16_t CurrentBit = ReportItem->BitOffset; + uint32_t BitMask = (1 << 0); + + ReportItem->Value = 0; + + if (ReportItem->ReportID) + { + if (ReportItem->ReportID != ReportData[0]) + return false; + + ReportData++; + } + + while (DataBitsRem--) + { + if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8))) + ReportItem->Value |= BitMask; + + CurrentBit++; + BitMask <<= 1; + } + + return true; +} + +void USB_SetHIDReportItemInfo(uint8_t* ReportData, const HID_ReportItem_t* ReportItem) +{ + uint16_t DataBitsRem = ReportItem->Attributes.BitSize; + uint16_t CurrentBit = ReportItem->BitOffset; + uint32_t BitMask = (1 << 0); + + if (ReportItem->ReportID) + { + ReportData[0] = ReportItem->ReportID; + ReportData++; + } + + while (DataBitsRem--) + { + if (ReportItem->Value & (1 << (CurrentBit % 8))) + ReportData[CurrentBit / 8] |= BitMask; + + CurrentBit++; + BitMask <<= 1; + } +} diff --git a/LUFA/Drivers/USB/Class/Host/HIDParser.h b/LUFA/Drivers/USB/Class/Host/HIDParser.h new file mode 100644 index 0000000000..4acce2462e --- /dev/null +++ b/LUFA/Drivers/USB/Class/Host/HIDParser.h @@ -0,0 +1,263 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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. +*/ + +/** \file + * + * USB Human Interface Device (HID) Class report descriptor processing routines. This file allows for the easy + * parsing of the complex HID report descriptor, which describes the data that the device transmits to the host. + * + */ + +/** \ingroup Group_USB + * @defgroup Group_HIDParser HID Report Parser + * + * Functions, macros, variables, enums and types related to the parsing of HID class device report descriptors. + * + * The processed HID report is presented back to the user application as a flat structure containing each report + * item's IN, OUT and FEATURE (if desired) items along with each item's attributes. + * + * This library portion also allows for easy setting and retrieval of data from a HID report, including devices + * with multiple reports on the one HID interface. + * + * By default, FEATURE reports and IN/OUT reports with constant data are ignored in the HID report when processed + * to save on memory. This can be overridden by defining the HID_ENABLE_FEATURE_PROCESSING or + * HID_INCLUDE_CONSTANT_DATA_ITEMS tokens in the user project makefile, passing them to the compiler via the -D + * switch. + * + * @{ + */ + +#ifndef __HIDPARSER_H__ +#define __HIDPARSER_H__ + + /* Includes: */ + #include + #include + + #include "HIDReportData.h" + + #include "../../../../Common/Common.h" + + /* Enable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + extern "C" { + #endif + + /* Preprocessor checks and defines: */ + #if !defined(HID_STATETABLE_STACK_DEPTH) || defined(__DOXYGEN__) + /** Constant indicating the maximum stack depth of the state table. A larger state table + * allows for more PUSH/POP report items to be nested, but consumes more memory. By default + * this is set to 3 levels (allowing for two PUSHes to be nested) but this can be overridden by + * defining HID_STATETABLE_STACK_DEPTH to another value in the user project makefile, passing the + * define to the compiler using the -D compiler switch. + */ + #define HID_STATETABLE_STACK_DEPTH 3 + #endif + + #if !defined(HID_USAGE_STACK_DEPTH) || defined(__DOXYGEN__) + /** Constant indicating the maximum stack depth of the usage table. A larger usage table + * allows for more USAGE items to be indicated sequentially for REPORT COUNT entries of more than + * one, but requires more stack space. By default this is set to 8 levels (allowing for a report + * item with a count of 8) but this can be overridden by defining HID_USAGE_STACK_DEPTH to another + * value in the user project makefile, passing the define to the compiler using the -D compiler + * switch. + */ + #define HID_USAGE_STACK_DEPTH 8 + #endif + + #if !defined(HID_MAX_COLLECTIONS) || defined(__DOXYGEN__) + /** Constant indicating the maximum number of COLLECTION items (nested or unnested) that can be + * processed in the report item descriptor. A large value allows for more COLLECTION items to be + * processed, but consumes more memory. By default this is set to 5 collections, but this can be + * overridden by defining HID_MAX_COLLECTIONS to another value in the user project makefile, passing + * the define to the compiler using the -D compiler switch. + */ + #define HID_MAX_COLLECTIONS 5 + #endif + + #if !defined(HID_MAX_REPORTITEMS) || defined(__DOXYGEN__) + /** Constant indicating the maximum number of report items (IN, OUT or FEATURE if enabled) that can be + * processed in the report item descriptor. A large value allows for more report items to be + * processed, but consumes more memory. By default this is set to 30 items, but this can be + * overridden by defining HID_MAX_REPORTITEMS to another value in the user project makefile, passing + * the define to the compiler using the -D compiler switch. + */ + #define HID_MAX_REPORTITEMS 30 + #endif + + /* Public Interface - May be used in end-application: */ + /* Enums: */ + /** Enum for indicating what type of report item an entry in a \ref HID_ReportInfo_t ReportItem array is */ + enum HID_ReportItemTypes_t + { + REPORT_ITEM_TYPE_In = 0, /**< Indicates that the item is an IN report type. */ + REPORT_ITEM_TYPE_Out = 1, /**< Indicates that the item is an OUT report type. */ + REPORT_ITEM_TYPE_Feature = 2, /**< Indicates that the item is a FEATURE report type. */ + }; + + /** Enum for the possible error codes in the return value of the \ref USB_ProcessHIDReport() function */ + enum HID_Parse_ErrorCodes_t + { + HID_PARSE_Successful = 0, /**< Successful parse of the HID report descriptor, no error. */ + HID_PARSE_HIDStackOverflow = 1, /**< More than \ref HID_STATETABLE_STACK_DEPTH nested PUSHes in the report. */ + HID_PARSE_HIDStackUnderflow = 2, /**< A POP was found when the state table stack was empty. */ + HID_PARSE_InsufficientReportItems = 3, /**< More than \ref HID_MAX_REPORTITEMS report items in the report. */ + HID_PARSE_UnexpectedEndCollection = 4, /**< END COLLECTION found without matching COLLECTION item. */ + HID_PARSE_InsufficientCollectionPaths = 5, /**< More than \ref HID_MAX_COLLECTIONS collections in the report. */ + HID_PARSE_UsageStackOverflow = 6, /**< More than \ref HID_USAGE_STACK_DEPTH usages listed in a row. */ + }; + + /* Type Defines: */ + /** Type define for an attribute with both minimum and maximum values (e.g. Logical Min/Max). */ + typedef struct + { + uint32_t Minimum; /**< Minimum value for the attribute. */ + uint32_t Maximum; /**< Maximum value for the attribute. */ + } HID_MinMax_t; + + /** Type define for the Unit attributes of a report item. */ + typedef struct + { + uint32_t Type; /**< Unit type (refer to HID specifications for details). */ + uint8_t Exponent; /**< Unit exponent (refer to HID specifications for details). */ + } HID_Unit_t; + + /** Type define for the Usage attributes of a report item. */ + typedef struct + { + uint16_t Page; /**< Usage page of the report item. */ + uint16_t Usage; /**< Usage of the report item. */ + HID_MinMax_t MinMax; /**< Usage minimum and maximum of the report item. */ + } HID_Usage_t; + + /** Type define for a COLLECTION object. Contains the collection attributes and a reference to the + * parent collection if any. + */ + typedef struct CollectionPath + { + uint8_t Type; /**< Collection type (e.g. "Generic Desktop"). */ + HID_Usage_t Usage; /**< Collection usage. */ + struct CollectionPath* Parent; /**< Reference to parent collection, or NULL if root collection. */ + } HID_CollectionPath_t; + + /** Type define for all the data attributes of a report item, except flags. */ + typedef struct + { + uint8_t BitSize; /**< Size in bits of the report item's data. */ + + HID_Usage_t Usage; /**< Usage of the report item. */ + HID_Unit_t Unit; /**< Unit type and exponent of the report item. */ + HID_MinMax_t Logical; /**< Logical minimum and maximum of the report item. */ + HID_MinMax_t Physical; /**< Physical minimum and maximum of the report item. */ + } HID_ReportItem_Attributes_t; + + /** Type define for a report item (IN, OUT or FEATURE) attributes and other details. */ + typedef struct + { + uint16_t BitOffset; /**< Bit offset in the IN, OUT or FEATURE report of the item. */ + uint8_t ItemType; /**< Report item type, a value in HID_Types_t. */ + uint16_t ItemFlags; /**< Item data flags, such as constant/variable, etc. */ + uint8_t ReportID; /**< Report ID this item belongs to, or 0x00 if device has only one report */ + HID_CollectionPath_t* CollectionPath; /**< Collection path of the item. */ + + HID_ReportItem_Attributes_t Attributes; /**< Report item attributes. */ + + uint32_t Value; /**< Current value of the report item. */ + } HID_ReportItem_t; + + /** Type define for a complete processed HID report, including all report item data and collections. */ + typedef struct + { + uint8_t TotalReportItems; /**< Total number of report items stored in the + * ReportItems array. */ + + HID_ReportItem_t ReportItems[HID_MAX_REPORTITEMS]; /**< Report items array, including + * all IN, OUT and FEATURE items. */ + + HID_CollectionPath_t CollectionPaths[HID_MAX_COLLECTIONS]; /**< All collection items, referenced + * by the report items. */ + } HID_ReportInfo_t; + + /* Function Prototypes: */ + /** Function to process a given HID report returned from an attached device, and store it into a given + * \ref HID_ReportInfo_t structure. + * + * \param ReportData Buffer containing the device's HID report table + * \param ReportSize Size in bytes of the HID report table + * \param ParserData Pointer to a \ref HID_ReportInfo_t instance for the parser output + * + * \return A value in the \ref HID_Parse_ErrorCodes_t enum + */ + uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, HID_ReportInfo_t* const ParserData) + ATTR_NON_NULL_PTR_ARG(1, 3); + + /** Extracts the given report item's value out of the given HID report and places it into the Value + * member of the report item's \ref HID_ReportItem_t structure. + * + * \param ReportData Buffer containing an IN or FEATURE report from an attached device + * \param ReportItem Pointer to the report item of interest in a \ref HID_ReportInfo_t ReportItem array + * + * \returns Boolean true if the item to retrieve was located in the given report, false otherwise + */ + bool USB_GetHIDReportItemInfo(const uint8_t* ReportData, HID_ReportItem_t* const ReportItem) + ATTR_NON_NULL_PTR_ARG(1, 2); + + /** Retrieves the given report item's value out of the Value member of the report item's + * \ref HID_ReportItem_t structure and places it into the correct position in the HID report + * buffer. The report buffer is assumed to have the appropriate bits cleared before calling + * this function (i.e., the buffer should be explicitly cleared before report values are added). + * + * If the device has multiple HID reports, the report ID is set to the report ID of the given item. + * + * \param ReportData Buffer holding the current OUT report data + * \param ReportItem Pointer to the report item of interest in a \ref HID_ReportInfo_t ReportItem array + */ + void USB_SetHIDReportItemInfo(uint8_t* ReportData, const HID_ReportItem_t* ReportItem) + ATTR_NON_NULL_PTR_ARG(1, 2); + + /* Private Interface - For use in library only: */ + #if !defined(__DOXYGEN__) + /* Type Defines: */ + typedef struct + { + HID_ReportItem_Attributes_t Attributes; + uint8_t ReportCount; + uint8_t ReportID; + } HID_StateTable_t; + #endif + + /* Disable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + } + #endif + +#endif + +/** @} */ diff --git a/LUFA/Drivers/USB/Class/Host/HIDReportData.h b/LUFA/Drivers/USB/Class/Host/HIDReportData.h new file mode 100644 index 0000000000..eee38be04d --- /dev/null +++ b/LUFA/Drivers/USB/Class/Host/HIDReportData.h @@ -0,0 +1,140 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim 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, 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. +*/ + +/** \file + * + * Constants for HID report item attributes. Refer to the HID specification for details on each + * flag's meaning when applied to an IN, OUT or FEATURE item. + */ + +/** \ingroup Group_HIDParser + * @defgroup Group_HIDIOFConst Input/Output/Feature Masks + * + * Masks indicating the type of Input, Output of Feature HID report item. + * + * @{ + */ + +#ifndef __HIDREPORTDATA_H__ +#define __HIDREPORTDATA_H__ + + /* Public Interface - May be used in end-application: */ + /* Macros: */ + /** HID_ReportItem_t.ItemFlags flag for constant data. */ + #define IOF_CONSTANT (1 << 0) + + /** HID_ReportItem_t.ItemFlags flag for data. */ + #define IOF_DATA (0 << 0) + + /** HID_ReportItem_t.ItemFlags flag for variable data. */ + #define IOF_VARIABLE (1 << 1) + + /** HID_ReportItem_t.ItemFlags flag for array data. */ + #define IOF_ARRAY (0 << 1) + + /** HID_ReportItem_t.ItemFlags flag for relative data. */ + #define IOF_RELATIVE (1 << 2) + + /** HID_ReportItem_t.ItemFlags flag for absolute data. */ + #define IOF_ABSOLUTE (0 << 2) + + /** HID_ReportItem_t.ItemFlags flag for wrapped value data. */ + #define IOF_WRAP (1 << 3) + + /** HID_ReportItem_t.ItemFlags flag for non-wrapped value data. */ + #define IOF_NOWRAP (0 << 3) + + /** HID_ReportItem_t.ItemFlags flag for non linear data. */ + #define IOF_NONLINEAR (1 << 4) + + /** HID_ReportItem_t.ItemFlags flag for linear data. */ + #define IOF_LINEAR (0 << 4) + + /** HID_ReportItem_t.ItemFlags flag for no preferred state. */ + #define IOF_NOPREFERRED (1 << 5) + + /** HID_ReportItem_t.ItemFlags flag for preferred state items. */ + #define IOF_PREFERREDSTATE (0 << 5) + + /** HID_ReportItem_t.ItemFlags flag for null state items. */ + #define IOF_NULLSTATE (1 << 6) + + /** HID_ReportItem_t.ItemFlags flag for no null position data. */ + #define IOF_NONULLPOSITION (0 << 6) + + /** HID_ReportItem_t.ItemFlags flag for buffered bytes. */ + #define IOF_BUFFEREDBYTES (1 << 8) + + /** HID_ReportItem_t.ItemFlags flag for bit field data. */ + #define IOF_BITFIELD (0 << 8) + + /* Private Interface - For use in library only: */ + #if !defined(__DOXYGEN__) + /* Macros: */ + #define DATA_SIZE_MASK 0x03 + #define TYPE_MASK 0x0C + #define TAG_MASK 0xF0 + + #define DATA_SIZE_0 0x00 + #define DATA_SIZE_1 0x01 + #define DATA_SIZE_2 0x02 + #define DATA_SIZE_4 0x03 + + #define TYPE_MAIN 0x00 + #define TYPE_GLOBAL 0x04 + #define TYPE_LOCAL 0x08 + + #define TAG_MAIN_INPUT 0x80 + #define TAG_MAIN_OUTPUT 0x90 + #define TAG_MAIN_COLLECTION 0xA0 + #define TAG_MAIN_FEATURE 0xB0 + #define TAG_MAIN_ENDCOLLECTION 0xC0 + + #define TAG_GLOBAL_USAGEPAGE 0x00 + #define TAG_GLOBAL_LOGICALMIN 0x10 + #define TAG_GLOBAL_LOGICALMAX 0x20 + #define TAG_GLOBAL_PHYSMIN 0x30 + #define TAG_GLOBAL_PHYSMAX 0x40 + #define TAG_GLOBAL_UNITEXP 0x50 + #define TAG_GLOBAL_UNIT 0x60 + #define TAG_GLOBAL_REPORTSIZE 0x70 + #define TAG_GLOBAL_REPORTID 0x80 + #define TAG_GLOBAL_REPORTCOUNT 0x90 + #define TAG_GLOBAL_PUSH 0xA0 + #define TAG_GLOBAL_POP 0xB0 + + #define TAG_LOCAL_USAGE 0x00 + #define TAG_LOCAL_USAGEMIN 0x10 + #define TAG_LOCAL_USAGEMAX 0x20 + #endif + +/** @} */ + +#endif diff --git a/LUFA/Drivers/USB/HighLevel/Events.h b/LUFA/Drivers/USB/HighLevel/Events.h index e6d2beaa77..ded027b12e 100644 --- a/LUFA/Drivers/USB/HighLevel/Events.h +++ b/LUFA/Drivers/USB/HighLevel/Events.h @@ -267,6 +267,11 @@ * \ref Group_USBManagement documentation). */ void EVENT_USB_Reset(void); + + /** Event for the USB start of frame interrupt, firing once each millisecond in either device or host + * mode, while USB frames are being generated or recieved. + */ + void EVENT_USB_StartOfFrame(void); #endif /* Private Interface - For use in library only: */ @@ -303,6 +308,7 @@ void EVENT_USB_Suspend(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub); void EVENT_USB_WakeUp(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub); void EVENT_USB_Reset(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub); + void EVENT_USB_StartOfFrame(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub); #endif #endif diff --git a/LUFA/Drivers/USB/HighLevel/USBInterrupt.c b/LUFA/Drivers/USB/HighLevel/USBInterrupt.c index 0b9d082236..0ccbe61557 100644 --- a/LUFA/Drivers/USB/HighLevel/USBInterrupt.c +++ b/LUFA/Drivers/USB/HighLevel/USBInterrupt.c @@ -180,6 +180,15 @@ ISR(USB_GEN_vect, ISR_BLOCK) EVENT_USB_Reset(); } + + if (USB_INT_HasOccurred(USB_INT_SOFI) && USB_INT_IsEnabled(USB_INT_SOFI)) + { + USB_INT_Clear(USB_INT_SOFI); + + FrameElapsed = true; + + EVENT_USB_StartOfFrame(); + } #endif #if defined(USB_CAN_BE_HOST) @@ -232,6 +241,15 @@ ISR(USB_GEN_vect, ISR_BLOCK) USB_ResetInterface(); } + + if (USB_INT_HasOccurred(USB_INT_HSOFI) && USB_INT_IsEnabled(USB_INT_HSOFI)) + { + USB_INT_Clear(USB_INT_HSOFI); + + FrameElapsed = true; + + EVENT_USB_StartOfFrame(); + } #endif #if defined(USB_CAN_BE_BOTH) diff --git a/LUFA/Drivers/USB/HighLevel/USBTask.c b/LUFA/Drivers/USB/HighLevel/USBTask.c index e2b7e91d50..46fcd57096 100644 --- a/LUFA/Drivers/USB/HighLevel/USBTask.c +++ b/LUFA/Drivers/USB/HighLevel/USBTask.c @@ -42,7 +42,7 @@ USB_Request_Header_t USB_ControlRequest; volatile uint8_t USB_HostState; #endif -TASK(USB_USBTask) +void USB_USBTask(void) { #if defined(USB_HOST_ONLY) USB_HostTask(); diff --git a/LUFA/Drivers/USB/HighLevel/USBTask.h b/LUFA/Drivers/USB/HighLevel/USBTask.h index 1e1209a5f3..e4c8a02ae5 100644 --- a/LUFA/Drivers/USB/HighLevel/USBTask.h +++ b/LUFA/Drivers/USB/HighLevel/USBTask.h @@ -38,7 +38,6 @@ #include #include - #include "../../../Scheduler/Scheduler.h" #include "../LowLevel/LowLevel.h" #include "StdRequestType.h" #include "USBMode.h" @@ -122,11 +121,11 @@ extern volatile uint8_t USB_HostState; #endif - /* Tasks: */ + /* Function Prototypes: */ /** This is the main USB management task. The USB driver requires that this task be executed * continuously when the USB system is active (device attached in host mode, or attached to a host * in device mode) in order to manage USB communications. This task may be executed inside an RTOS, - * scheduler (e.g. the simple LUFA Scheduler), fast timer ISR or the main user application loop. + * fast timer ISR or the main user application loop. * * The USB task must be serviced within 30ms while in device mode, or within 1ms while in host mode. * The task may be serviced at all times, or (for minimum CPU consumption): @@ -145,7 +144,7 @@ * * \ingroup Group_USBManagement */ - TASK(USB_USBTask); + void USB_USBTask(void); /* Private Interface - For use in library only: */ #if !defined(__DOXYGEN__) diff --git a/LUFA/Drivers/USB/LowLevel/Endpoint.c b/LUFA/Drivers/USB/LowLevel/Endpoint.c index 099022c1cf..d02071bbd5 100644 --- a/LUFA/Drivers/USB/LowLevel/Endpoint.c +++ b/LUFA/Drivers/USB/LowLevel/Endpoint.c @@ -80,8 +80,6 @@ uint8_t Endpoint_WaitUntilReady(void) uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS; #endif - USB_INT_Clear(USB_INT_SOFI); - for (;;) { if (Endpoint_GetEndpointDirection() == ENDPOINT_DIR_IN) @@ -100,9 +98,9 @@ uint8_t Endpoint_WaitUntilReady(void) else if (Endpoint_IsStalled()) return ENDPOINT_READYWAIT_EndpointStalled; - if (USB_INT_HasOccurred(USB_INT_SOFI)) + if (FrameElapsed) { - USB_INT_Clear(USB_INT_SOFI); + FrameElapsed = false; if (!(TimeoutMSRem--)) return ENDPOINT_READYWAIT_Timeout; diff --git a/LUFA/Drivers/USB/LowLevel/Host.c b/LUFA/Drivers/USB/LowLevel/Host.c index b606515e60..02a1c2171c 100644 --- a/LUFA/Drivers/USB/LowLevel/Host.c +++ b/LUFA/Drivers/USB/LowLevel/Host.c @@ -210,14 +210,13 @@ uint8_t USB_Host_WaitMS(uint8_t MS) bool BusSuspended = USB_Host_IsBusSuspended(); uint8_t ErrorCode = HOST_WAITERROR_Successful; - USB_INT_Clear(USB_INT_HSOFI); USB_Host_ResumeBus(); while (MS) { - if (USB_INT_HasOccurred(USB_INT_HSOFI)) + if (FrameElapsed) { - USB_INT_Clear(USB_INT_HSOFI); + FrameElapsed = false; MS--; } @@ -260,9 +259,10 @@ static void USB_Host_ResetDevice(void) USB_Host_ResetBus(); while (!(USB_Host_IsBusResetComplete())); - USB_INT_Clear(USB_INT_HSOFI); USB_Host_ResumeBus(); + FrameElapsed = false; + for (uint8_t MSRem = 10; MSRem != 0; MSRem--) { /* Workaround for powerless-pull-up devices. After a USB bus reset, @@ -270,8 +270,10 @@ static void USB_Host_ResetDevice(void) looked for - if it is found within 10ms, the device is still present. */ - if (USB_INT_HasOccurred(USB_INT_HSOFI)) + if (FrameElapsed) { + FrameElapsed = false; + USB_INT_Clear(USB_INT_DDISCI); break; } diff --git a/LUFA/Drivers/USB/LowLevel/LowLevel.c b/LUFA/Drivers/USB/LowLevel/LowLevel.c index 8b395be98c..255a6ef299 100644 --- a/LUFA/Drivers/USB/LowLevel/LowLevel.c +++ b/LUFA/Drivers/USB/LowLevel/LowLevel.c @@ -38,6 +38,8 @@ volatile uint8_t USB_CurrentMode = USB_MODE_NONE; volatile uint8_t USB_Options; #endif +volatile bool FrameElapsed; + void USB_Init( #if defined(USB_CAN_BE_BOTH) const uint8_t Mode @@ -150,6 +152,8 @@ void USB_ResetInterface(void) USB_INT_DisableAllInterrupts(); USB_INT_ClearAllInterrupts(); + FrameElapsed = false; + USB_IsConnected = false; #if defined(USB_CAN_BE_HOST) @@ -224,6 +228,7 @@ void USB_ResetInterface(void) #if defined(USB_DEVICE_ONLY) USB_INT_Enable(USB_INT_SUSPEND); USB_INT_Enable(USB_INT_EORSTI); + USB_INT_Enable(USB_INT_SOFI); #if defined(CONTROL_ONLY_DEVICE) UENUM = ENDPOINT_CONTROLEP; @@ -240,11 +245,13 @@ void USB_ResetInterface(void) USB_INT_Enable(USB_INT_SRPI); USB_INT_Enable(USB_INT_BCERRI); + USB_INT_Enable(USB_INT_HSOFI); #else if (USB_CurrentMode == USB_MODE_DEVICE) { USB_INT_Enable(USB_INT_SUSPEND); USB_INT_Enable(USB_INT_EORSTI); + USB_INT_Enable(USB_INT_SOFI); #if defined(CONTROL_ONLY_DEVICE) UENUM = ENDPOINT_CONTROLEP; @@ -262,6 +269,7 @@ void USB_ResetInterface(void) USB_INT_Enable(USB_INT_SRPI); USB_INT_Enable(USB_INT_BCERRI); + USB_INT_Enable(USB_INT_HSOFI); } #endif } diff --git a/LUFA/Drivers/USB/LowLevel/LowLevel.h b/LUFA/Drivers/USB/LowLevel/LowLevel.h index 41b0ff5f67..4279ca3159 100644 --- a/LUFA/Drivers/USB/LowLevel/LowLevel.h +++ b/LUFA/Drivers/USB/LowLevel/LowLevel.h @@ -350,6 +350,9 @@ return USB_MODE_HOST; } #endif + + /* External Variables: */ + extern volatile bool FrameElapsed; #endif diff --git a/LUFA/Drivers/USB/LowLevel/Pipe.c b/LUFA/Drivers/USB/LowLevel/Pipe.c index 71a33d62f2..720da17723 100644 --- a/LUFA/Drivers/USB/LowLevel/Pipe.c +++ b/LUFA/Drivers/USB/LowLevel/Pipe.c @@ -76,8 +76,6 @@ uint8_t Pipe_WaitUntilReady(void) uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS; #endif - USB_INT_Clear(USB_INT_HSOFI); - for (;;) { if (Pipe_GetPipeToken() == PIPE_TOKEN_IN) @@ -96,9 +94,9 @@ uint8_t Pipe_WaitUntilReady(void) else if (!(USB_IsConnected)) return PIPE_READYWAIT_DeviceDisconnected; - if (USB_INT_HasOccurred(USB_INT_HSOFI)) + if (FrameElapsed) { - USB_INT_Clear(USB_INT_HSOFI); + FrameElapsed = false; if (!(TimeoutMSRem--)) return PIPE_READYWAIT_Timeout; diff --git a/LUFA/Drivers/USB/USB.h b/LUFA/Drivers/USB/USB.h index 6d66c4d143..3c8f062372 100644 --- a/LUFA/Drivers/USB/USB.h +++ b/LUFA/Drivers/USB/USB.h @@ -49,7 +49,6 @@ * - LUFA/Drivers/USB/HighLevel/USBInterrupt.c * - LUFA/Drivers/USB/HighLevel/USBTask.c * - LUFA/Drivers/USB/HighLevel/ConfigDescriptor.c - * - LUFA/Drivers/USB/Class/HIDParser.c * * \section Module Description * Functions, macros, variables, enums and types related to the management of USB communications. @@ -97,7 +96,6 @@ #endif #include "HighLevel/ConfigDescriptor.h" - #include "Class/HIDParser.h" #endif diff --git a/LUFA/MemoryAllocator/DynAlloc.c b/LUFA/MemoryAllocator/DynAlloc.c deleted file mode 100644 index 4f1c82241b..0000000000 --- a/LUFA/MemoryAllocator/DynAlloc.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2009. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, provided that the above copyright notice appear in all - copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - The author disclaim 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, 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. -*/ - -#define INCLUDE_FROM_DYNALLOC_C -#include "DynAlloc.h" - -struct -{ - char Mem_Heap[NUM_BLOCKS * BLOCK_SIZE]; - void* Mem_Handles[NUM_HANDLES]; - uint8_t Mem_Block_Flags[(NUM_BLOCKS / 4) + ((NUM_BLOCKS % 4) ? 1 : 0)]; - uint8_t FlagMaskLookupMask[4]; - uint8_t FlagMaskLookupNum[4]; -} Mem_MemData = {.FlagMaskLookupMask = {(3 << 0), (3 << 2), (3 << 4), (3 << 6)}, - .FlagMaskLookupNum = { 0, 2, 4, 6}}; - -static uint8_t Mem_GetBlockFlags(const Block_Number_t BlockNum) -{ - const Block_Number_t BlockIndex = (BlockNum >> 2); - const uint8_t FlagMask = Mem_MemData.FlagMaskLookupMask[BlockNum & 0x03]; - const uint8_t FlagMaskShift = Mem_MemData.FlagMaskLookupNum[BlockNum & 0x03]; - - return ((Mem_MemData.Mem_Block_Flags[BlockIndex] & FlagMask) >> FlagMaskShift); -} - -static void Mem_SetBlockFlags(const Block_Number_t BlockNum, const uint8_t Flags) -{ - const Block_Number_t BlockIndex = (BlockNum >> 2); - const uint8_t FlagMask = Mem_MemData.FlagMaskLookupMask[BlockNum & 0x03]; - const uint8_t FlagMaskShift = Mem_MemData.FlagMaskLookupNum[BlockNum & 0x03]; - - Mem_MemData.Mem_Block_Flags[BlockIndex] &= ~FlagMask; - Mem_MemData.Mem_Block_Flags[BlockIndex] |= (Flags << FlagMaskShift); -} - -static inline void Mem_Defrag(void) -{ - Block_Number_t FreeStartBlock = 0; - char* FreeStartPtr = NULL; - char* UsedStartPtr = NULL; - Block_Number_t CurrBlock; - - for (CurrBlock = 0; CurrBlock < NUM_BLOCKS; CurrBlock++) - { - if (!(Mem_GetBlockFlags(CurrBlock) & BLOCK_USED_MASK)) - { - FreeStartPtr = &Mem_MemData.Mem_Heap[CurrBlock * BLOCK_SIZE]; - FreeStartBlock = CurrBlock; - break; - } - } - - if (FreeStartPtr == NULL) - return; - - while (++CurrBlock < NUM_BLOCKS) - { - uint8_t CurrBlockFlags = Mem_GetBlockFlags(CurrBlock); - - if (CurrBlockFlags & BLOCK_USED_MASK) - { - UsedStartPtr = &Mem_MemData.Mem_Heap[CurrBlock * BLOCK_SIZE]; - - for (Handle_Number_t HandleNum = 0; HandleNum < NUM_HANDLES; HandleNum++) - { - if (Mem_MemData.Mem_Handles[HandleNum] == UsedStartPtr) - { - Mem_MemData.Mem_Handles[HandleNum] = FreeStartPtr; - break; - } - } - - memcpy(FreeStartPtr, UsedStartPtr, BLOCK_SIZE); - FreeStartPtr += BLOCK_SIZE; - - Mem_SetBlockFlags(FreeStartBlock++, CurrBlockFlags); - Mem_SetBlockFlags(CurrBlock, 0); - } - } -} - -static inline bool Mem_FindFreeBlocks(Block_Number_t* const RetStartPtr, const Block_Number_t Blocks) -{ - Block_Number_t FreeInCurrSec = 0; - - for (Block_Number_t CurrBlock = 0; CurrBlock < NUM_BLOCKS; CurrBlock++) - { - if (Mem_GetBlockFlags(CurrBlock) & BLOCK_USED_MASK) - FreeInCurrSec = 0; - else - FreeInCurrSec++; - - if (FreeInCurrSec >= Blocks) - { - *RetStartPtr = CurrBlock; - return true; - } - } - - return false; -} - -Mem_Handle_t Mem_Alloc(const Alloc_Size_t Bytes) -{ - Block_Number_t ReqBlocks = (Bytes / BLOCK_SIZE); - Block_Number_t StartBlock; - - if (Bytes % BLOCK_SIZE) - ReqBlocks++; - - if (!(Mem_FindFreeBlocks(&StartBlock, ReqBlocks))) - { - Mem_Defrag(); - - if (!(Mem_FindFreeBlocks(&StartBlock, ReqBlocks))) - return NULL; - } - - for (Block_Number_t UsedBlock = 0; UsedBlock < (ReqBlocks - 1); UsedBlock++) - Mem_SetBlockFlags((StartBlock + UsedBlock), (BLOCK_USED_MASK | BLOCK_LINKED_MASK)); - - Mem_SetBlockFlags((StartBlock + (ReqBlocks - 1)), BLOCK_USED_MASK); - - for (Handle_Number_t AllocEntry = 0; AllocEntry < NUM_HANDLES; AllocEntry++) - { - Mem_Handle_t CurrHdl = (Mem_Handle_t)&Mem_MemData.Mem_Handles[AllocEntry]; - - if (DEREF(CurrHdl, void*) == NULL) - { - DEREF(CurrHdl, void*) = &Mem_MemData.Mem_Heap[StartBlock * BLOCK_SIZE]; - return CurrHdl; - } - } - - return NULL; -} - -Mem_Handle_t Mem_Realloc(Mem_Handle_t CurrAllocHdl, const Alloc_Size_t Bytes) -{ - Mem_Free(CurrAllocHdl); - return Mem_Alloc(Bytes); -} - -Mem_Handle_t Mem_Calloc(const Alloc_Size_t Bytes) -{ - Mem_Handle_t AllocHdl = Mem_Alloc(Bytes); - - if (AllocHdl != NULL) - memset(DEREF(AllocHdl, void*), 0x00, Bytes); - - return AllocHdl; -} - -void Mem_Free(Mem_Handle_t CurrAllocHdl) -{ - char* MemBlockPtr = DEREF(CurrAllocHdl, char*); - Block_Number_t CurrBlock = ((uint16_t)(MemBlockPtr - Mem_MemData.Mem_Heap) / BLOCK_SIZE); - uint8_t CurrBlockFlags; - - if ((CurrAllocHdl == NULL) || (MemBlockPtr == NULL)) - return; - - do - { - CurrBlockFlags = Mem_GetBlockFlags(CurrBlock); - Mem_SetBlockFlags(CurrBlock, 0); - - CurrBlock++; - } - while (CurrBlockFlags & BLOCK_LINKED_MASK); - - DEREF(CurrAllocHdl, void*) = NULL; -} - -Block_Number_t Mem_TotalFreeBlocks(void) -{ - Block_Number_t FreeBlocks = 0; - - for (Block_Number_t CurrBlock = 0; CurrBlock < NUM_BLOCKS; CurrBlock++) - { - if (!(Mem_GetBlockFlags(CurrBlock) & BLOCK_USED_MASK)) - FreeBlocks++; - } - - return FreeBlocks; -} - -Handle_Number_t Mem_TotalFreeHandles(void) -{ - Handle_Number_t FreeHandles = 0; - - for (Handle_Number_t CurrHandle = 0; CurrHandle < NUM_HANDLES; CurrHandle++) - { - if (Mem_MemData.Mem_Handles[CurrHandle] == NULL) - FreeHandles++; - } - - return FreeHandles; -} diff --git a/LUFA/MemoryAllocator/DynAlloc.h b/LUFA/MemoryAllocator/DynAlloc.h deleted file mode 100644 index acbfbd18a6..0000000000 --- a/LUFA/MemoryAllocator/DynAlloc.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2009. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, provided that the above copyright notice appear in all - copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - The author disclaim 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, 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. -*/ - -/** \file - * - * Dynamic, auto-defragmenting block memory allocator library. This library provides a convenient replacement for - * the standard avr-libc dynamic memory allocation routines. Memory is handed out in block chunks, to reduce the - * management memory overhead. - */ - -/** @defgroup Group_MemoryAllocator Dynamic Block Memory Allocator - LUFA/MemoryAllocator/DynAlloc.h - * - * \section Sec_Dependencies Module Source Dependencies - * The following files must be built with any user project that uses this module: - * - LUFA/MemoryAllocator/DynAlloc.c - * - * \section Module Description - * Dynamic, auto-defragmenting block memory allocator library. This library provides a convenient replacement for - * the standard avr-libc dynamic memory allocation routines. Memory is handed out in block chunks, to reduce the - * management memory overhead. - * - * Unlike the normal memory allocation routines, this library gives out handles to memory which must be dereferenced - * at the exact time of use, rather than handing back direct memory pointers. By using library managed handles - * instead of pointers, allocated memory blocks can be shifted around as needed transparently to defragment the - * memory as more blocks are requested. - * - * The memory heap is static, thus the total memory usage of the compiled application (as reported by the avr-size - * tool of the AVR-GCC toolchain) includes the dynamic memory heap. - * - * The constants NUM_BLOCKS, BLOCK_SIZE and NUM_HANDLES must be defined in the project makefile (and passed to the - * preprocessor via the -D GCC switch) for this library to compile. - * - * NUM_BLOCKS indicates the number of memory blocks in the memory psudoheap which can be chained together and handed - * to the application via a memory handle. NUM_HANDLES is the maximum number of memory handles (pointing to one or - * more chained memory blocks) which can be handed out simultaneously before requiring a handle (and its associated - * memory) to be freed. BLOCK_SIZE gives the number of bytes in each memory block. - * - * @{ - */ - -#ifndef __DYN_ALLOC__ -#define __DYN_ALLOC__ - - /* Includes : */ - #include - #include - #include - - /* Preprocessor Checks: */ - #if (!defined(NUM_BLOCKS) || !defined(BLOCK_SIZE) || !defined(NUM_HANDLES)) - #error NUM_BLOCKS, BLOCK_SIZE and NUM_HANDLES must be defined before use via makefile. - #endif - - /* Public Interface - May be used in end-application: */ - /* Macros: */ - /** Macro to dereference a given memory handle into the given type. The given type should be a pointer - * if the memory is to contain an array of items, or should be a standard type (such as a primitive or - * structure) if the memory is to hold a single item of a single type. */ - #define DEREF(handle, type) (*(type*)handle) - - /** Constant, giving the total heap size in bytes. */ - #define ALLOCABLE_BYTES (1UL * NUM_BLOCKS * BLOCK_SIZE) - - /* Type Defines: */ - /** Memory handle type, used to store handles given by the library functions. */ - typedef const void** Mem_Handle_t; - - #if (ALLOCABLE_BYTES > 0xFFFF) || defined(__DOXYGEN__) - /** Type define for the size (in bytes) for an allocation for passing to the library functions. - * The exact type width varies depending on the value of ALLOCABLE_BYTES to ensure that a single - * allocation can request the entire heap if needed. - */ - typedef uint32_t Alloc_Size_t; - #elif (ALLOCABLE_BYTES > 0xFF) - typedef uint16_t Alloc_Size_t; - #else - typedef uint8_t Alloc_Size_t; - #endif - - #if (NUM_BLOCKS > 0xFFFF) || defined(__DOXYGEN__) - /** Type define for a block number in the heap. The exact type width varies depending on the - * value of NUM_BLOCKS to ensure that the type can store an index to any block in the block pool. - */ - typedef uint32_t Block_Number_t; - #elif (NUM_BLOCKS > 0xFF) - typedef uint16_t Block_Number_t; - #else - typedef uint8_t Block_Number_t; - #endif - - #if (NUM_HANDLES > 0xFFFF) || defined(__DOXYGEN__) - /** Type define for a handle number. The exact type width varies depending on the value of NUM_HANDLES - * to ensure that the type can store the index of any handle in the handle pool. - */ - typedef uint32_t Handle_Number_t; - #elif (NUM_HANDLES > 0xFF) - typedef uint16_t Handle_Number_t; - #else - typedef uint8_t Handle_Number_t; - #endif - - /* Function Prototypes: */ - /** Allocates a given number of blocks from the heap (calculated from the requested number of bytes) and - * returns a handle to the newly allocated memory. - * - * \param Bytes The number of bytes requested to be allocated from the heap - * - * \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds - */ - Mem_Handle_t Mem_Alloc(const Alloc_Size_t Bytes); - - /** Allocates a given number of blocks from the heap (calculated from the requested number of bytes) and - * returns a handle to the newly allocated memory. Calloced memory is automatically cleared to all 0x00 - * values at the time of allocation. - * - * \param Bytes The number of pre-cleared bytes requested to be allocated from the heap - * - * \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds - */ - Mem_Handle_t Mem_Calloc(const Alloc_Size_t Bytes); - - /** Deallocates a given memory handle, and attempts to allocates the given number of blocks from the heap - * (calculated from the requested number of bytes) immediately following the deallocation. The new memory - * may be located in the same area as the previous memory, but this is not guaranteed. - * - * \param CurrAllocHdl Handle to an already allocated section of memory in the heap to deallocate - * \param Bytes The number of bytes requested to be allocated from the heap following the - * deallocation - * - * \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds - * - * \warning Even if the allocation fails, the deallocation will still occur. Care should be taken to ensure - * that the previously allocated memory is not used following an unsuccessful realloc(). - */ - Mem_Handle_t Mem_Realloc(Mem_Handle_t CurrAllocHdl, const Alloc_Size_t Bytes); - - /** Deallocates a given previously allocated section of memory from the heap. - * - * \param CurrAllocHdl Handle to a previously allocated section of memory in the heap - */ - void Mem_Free(Mem_Handle_t CurrAllocHdl); - - /** Returns the total number of unallocated blocks in the heap. - * - * \return Number of free blocks in the heap, as a Block_Number_t integer - */ - Block_Number_t Mem_TotalFreeBlocks(void); - - /** Returns the total number of unallocated handles in the handle pool. - * - * \return Number of free handles in the handle pool, as a Handle_Number_t integer - */ - Handle_Number_t Mem_TotalFreeHandles(void); - - /* Private Interface - For use in library only: */ - #if !defined(__DOXYGEN__) - /* Macros: */ - #define BLOCK_USED_MASK (1 << 0) - #define BLOCK_LINKED_MASK (1 << 1) - - /* Function Prototypes: */ - #if defined(INCLUDE_FROM_DYNALLOC_C) - static uint8_t Mem_GetBlockFlags(const Block_Number_t BlockNum); - static void Mem_SetBlockFlags(const Block_Number_t BlockNum, const uint8_t Flags); - static void Mem_Defrag(void); - #endif - #endif - -#endif - -/** @} */ diff --git a/LUFA/Scheduler/Scheduler.c b/LUFA/Scheduler/Scheduler.c deleted file mode 100644 index ff8946a0d2..0000000000 --- a/LUFA/Scheduler/Scheduler.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2009. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, provided that the above copyright notice appear in all - copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - The author disclaim 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, 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 "Scheduler.h" - -volatile SchedulerDelayCounter_t Scheduler_TickCounter; -volatile uint8_t Scheduler_TotalTasks; - -bool Scheduler_HasDelayElapsed(const uint16_t Delay, SchedulerDelayCounter_t* const DelayCounter) -{ - SchedulerDelayCounter_t CurrentTickValue_LCL; - SchedulerDelayCounter_t DelayCounter_LCL; - - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - CurrentTickValue_LCL = Scheduler_TickCounter; - } - - DelayCounter_LCL = *DelayCounter; - - if (CurrentTickValue_LCL >= DelayCounter_LCL) - { - if ((CurrentTickValue_LCL - DelayCounter_LCL) >= Delay) - { - *DelayCounter = CurrentTickValue_LCL; - return true; - } - } - else - { - if (((MAX_DELAYCTR_COUNT - DelayCounter_LCL) + CurrentTickValue_LCL) >= Delay) - { - *DelayCounter = CurrentTickValue_LCL; - return true; - } - } - - return false; -} - -void Scheduler_SetTaskMode(const TaskPtr_t Task, const bool TaskStatus) -{ - TaskEntry_t* CurrTask = &Scheduler_TaskList[0]; - - while (CurrTask != &Scheduler_TaskList[Scheduler_TotalTasks]) - { - if (CurrTask->Task == Task) - { - CurrTask->TaskStatus = TaskStatus; - break; - } - - CurrTask++; - } -} - -void Scheduler_SetGroupTaskMode(const uint8_t GroupID, const bool TaskStatus) -{ - TaskEntry_t* CurrTask = &Scheduler_TaskList[0]; - - while (CurrTask != &Scheduler_TaskList[Scheduler_TotalTasks]) - { - if (CurrTask->GroupID == GroupID) - CurrTask->TaskStatus = TaskStatus; - - CurrTask++; - } -} diff --git a/LUFA/Scheduler/Scheduler.h b/LUFA/Scheduler/Scheduler.h deleted file mode 100644 index 0da80bb275..0000000000 --- a/LUFA/Scheduler/Scheduler.h +++ /dev/null @@ -1,285 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2009. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, provided that the above copyright notice appear in all - copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - The author disclaim 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, 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. -*/ - -/** \file - * - * Simple round-robbin cooperative scheduler for use in basic projects where non real-time tasks need - * to be executed. Each task is executed in sequence, and can be enabled or disabled individually or as a group. - */ - -/** @defgroup Group_Scheduler Simple Task Scheduler - LUFA/Scheduler/Scheduler.h - * - * \section Sec_Dependencies Module Source Dependencies - * The following files must be built with any user project that uses this module: - * - LUFA/Scheduler/Scheduler.c - * - * \section Module Description - * Simple round-robbin cooperative scheduler for use in basic projects where non real-time tasks need - * to be executed. Each task is executed in sequence, and can be enabled or disabled individually or as a group. - * - * For a task to yield it must return, thus each task should have persistent data marked with the static attribute. - * - * Usage Example: - * \code - * #include - * - * TASK(MyTask1); - * TASK(MyTask2); - * - * TASK_LIST - * { - * { .Task = MyTask1, .TaskStatus = TASK_RUN, .GroupID = 1 }, - * { .Task = MyTask2, .TaskStatus = TASK_RUN, .GroupID = 1 }, - * } - * - * int main(void) - * { - * Scheduler_Start(); - * } - * - * TASK(MyTask1) - * { - * // Implementation Here - * } - * - * TASK(MyTask2) - * { - * // Implementation Here - * } - * \endcode - * - * @{ - */ - -#ifndef __SCHEDULER_H__ -#define __SCHEDULER_H__ - - /* Includes: */ - #include - #include - - #include - - #include "../Common/Common.h" - - /* Enable C linkage for C++ Compilers: */ - #if defined(__cplusplus) - extern "C" { - #endif - - /* Public Interface - May be used in end-application: */ - /* Macros: */ - /** Creates a new scheduler task body or prototype. Should be used in the form: - * \code - * TASK(TaskName); // Prototype - * - * TASK(TaskName) - * { - * // Task body - * } - * \endcode - */ - #define TASK(name) void name (void) - - /** Defines a task list array, containing one or more task entries of the type TaskEntry_t. Each task list - * should be encased in curly braces and ended with a comma. - * - * Usage Example: - * \code - * TASK_LIST - * { - * { .Task = MyTask1, .TaskStatus = TASK_RUN, .GroupID = 1 }, - * // More task entries here - * } - * \endcode - */ - #define TASK_LIST TaskEntry_t Scheduler_TaskList[] = - - /** Constant, giving the maximum delay in scheduler ticks which can be stored in a variable of type - * SchedulerDelayCounter_t. - */ - #define TASK_MAX_DELAY (MAX_DELAYCTR_COUNT - 1) - - /** Task status mode constant, for passing to Scheduler_SetTaskMode() or Scheduler_SetGroupTaskMode(). */ - #define TASK_RUN true - - /** Task status mode constant, for passing to Scheduler_SetTaskMode() or Scheduler_SetGroupTaskMode(). */ - #define TASK_STOP false - - /* Pseudo-Function Macros: */ - #if defined(__DOXYGEN__) - /** Starts the scheduler in its infinite loop, executing running tasks. This should be placed at the end - * of the user application's main() function, as it can never return to the calling function. - */ - void Scheduler_Start(void); - - /** Initializes the scheduler so that the scheduler functions can be called before the scheduler itself - * is started. This must be executed before any scheduler function calls other than Scheduler_Start(), - * and can be omitted if no such functions could be called before the scheduler is started. - */ - void Scheduler_Init(void); - #else - #define Scheduler_Start() Scheduler_GoSchedule(TOTAL_TASKS); - - #define Scheduler_Init() Scheduler_InitScheduler(TOTAL_TASKS); - #endif - - /* Type Defines: */ - /** Type define for a pointer to a scheduler task. */ - typedef void (*TaskPtr_t)(void); - - /** Type define for a variable which can hold a tick delay value for the scheduler up to the maximum delay - * possible. - */ - typedef uint16_t SchedulerDelayCounter_t; - - /** Structure for holding a single task's information in the scheduler task list. */ - typedef struct - { - TaskPtr_t Task; /**< Pointer to the task to execute. */ - bool TaskStatus; /**< Status of the task (either TASK_RUN or TASK_STOP). */ - uint8_t GroupID; /**< Group ID of the task so that its status can be changed as a group. */ - } TaskEntry_t; - - /* Global Variables: */ - /** Task entry list, containing the scheduler tasks, task statuses and group IDs. Each entry is of type - * TaskEntry_t and can be manipulated as desired, although it is preferential that the proper Scheduler - * functions should be used instead of direct manipulation. - */ - extern TaskEntry_t Scheduler_TaskList[]; - - /** Contains the total number of tasks in the task list, irrespective of if the task's status is set to - * TASK_RUN or TASK_STOP. - * - * \note This value should be treated as read-only, and never altered in user-code. - */ - extern volatile uint8_t Scheduler_TotalTasks; - - /** Contains the current scheduler tick count, for use with the delay functions. If the delay functions - * are used in the user code, this should be incremented each tick period so that the delays can be - * calculated. - */ - extern volatile SchedulerDelayCounter_t Scheduler_TickCounter; - - /* Inline Functions: */ - /** Resets the delay counter value to the current tick count. This should be called to reset the period - * for a delay in a task which is dependant on the current tick value. - * - * \param DelayCounter Counter which is storing the starting tick count for a given delay. - */ - static inline void Scheduler_ResetDelay(SchedulerDelayCounter_t* const DelayCounter) - ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; - static inline void Scheduler_ResetDelay(SchedulerDelayCounter_t* const DelayCounter) - { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - *DelayCounter = Scheduler_TickCounter; - } - } - - /* Function Prototypes: */ - /** Determines if the given tick delay has elapsed, based on the given . - * - * \param Delay The delay to test for, measured in ticks - * \param DelayCounter The counter which is storing the starting tick value for the delay - * - * \return Boolean true if the delay has elapsed, false otherwise - * - * Usage Example: - * \code - * static SchedulerDelayCounter_t DelayCounter = 10000; // Force immediate run on start-up - * - * // Task runs every 10000 ticks, 10 seconds for this demo - * if (Scheduler_HasDelayElapsed(10000, &DelayCounter)) - * { - * // Code to execute after delay interval elapsed here - * } - * \endcode - */ - bool Scheduler_HasDelayElapsed(const uint16_t Delay, - SchedulerDelayCounter_t* const DelayCounter) - ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(2); - - /** Sets the task mode for a given task. - * - * \param Task Name of the task whose status is to be changed - * \param TaskStatus New task status for the task (TASK_RUN or TASK_STOP) - */ - void Scheduler_SetTaskMode(const TaskPtr_t Task, const bool TaskStatus); - - /** Sets the task mode for a given task group ID, allowing for an entire group of tasks to have their - * statuses changed at once. - * - * \param GroupID Value of the task group ID whose status is to be changed - * \param TaskStatus New task status for tasks in the specified group (TASK_RUN or TASK_STOP) - */ - void Scheduler_SetGroupTaskMode(const uint8_t GroupID, const bool TaskStatus); - - /* Private Interface - For use in library only: */ - #if !defined(__DOXYGEN__) - /* Macros: */ - #define TOTAL_TASKS (sizeof(Scheduler_TaskList) / sizeof(TaskEntry_t)) - #define MAX_DELAYCTR_COUNT 0xFFFF - - /* Inline Functions: */ - static inline void Scheduler_InitScheduler(const uint8_t TotalTasks) ATTR_ALWAYS_INLINE; - static inline void Scheduler_InitScheduler(const uint8_t TotalTasks) - { - Scheduler_TotalTasks = TotalTasks; - } - - static inline void Scheduler_GoSchedule(const uint8_t TotalTasks) ATTR_NO_RETURN ATTR_ALWAYS_INLINE; - static inline void Scheduler_GoSchedule(const uint8_t TotalTasks) - { - Scheduler_InitScheduler(TotalTasks); - - for (;;) - { - TaskEntry_t* CurrTask = &Scheduler_TaskList[0]; - - while (CurrTask != &Scheduler_TaskList[TotalTasks]) - { - if (CurrTask->TaskStatus == TASK_RUN) - CurrTask->Task(); - - CurrTask++; - } - } - } - #endif - - /* Disable C linkage for C++ Compilers: */ - #if defined(__cplusplus) - } - #endif - -#endif - -/** @} */ diff --git a/LUFA/SchedulerOverview.txt b/LUFA/SchedulerOverview.txt deleted file mode 100644 index 5c031feac6..0000000000 --- a/LUFA/SchedulerOverview.txt +++ /dev/null @@ -1,31 +0,0 @@ -/** \file - * - * This file contains special DoxyGen information for the generation of the main page and other special - * documentation pages. It is not a project source file. - */ - -/** \page Page_SchedulerOverview LUFA Scheduler Overview - * - * The LUFA library comes with a small, basic round-robbin scheduler which allows for small "tasks" to be executed - * continuously in sequence, and enabled/disabled at runtime. Unlike a conventional, complex RTOS scheduler, the - * LUFA scheduler is very simple in design and operation and is essentially a loop conditionally executing a series - * of functions. - * - * Each LUFA scheduler task should be written similar to an ISR; it should execute quickly (so that no one task - * hogs the processor, preventing another from running before some sort of timeout is exceeded). Unlike normal RTOS - * tasks, each LUFA scheduler task is a regular function, and thus must be designed to be called, and designed to - * return to the calling scheduler function repeatedly. Data which must be preserved between task calls should be - * declared as global or (preferably) as a static local variable inside the task. - * - * The scheduler consists of a task list, listing all the tasks which can be executed by the scheduler. Once started, - * each task is then called one after another, unless the task is stopped by another running task or interrupt. - * - * - * If desired, the LUFA scheduler does not need to be used in a LUFA powered application. A more conventional - * approach to application design can be used, or a proper scheduling RTOS inserted in the place of the LUFA scheduler. - * In the case of the former the USB task must be run manually repeatedly to maintain USB communications, and in the - * case of the latter a proper RTOS task must be set up to do the same. - * - * - * For more information on the LUFA scheduler, see the Scheduler.h file documentation. - */ diff --git a/LUFA/makefile b/LUFA/makefile index fc00097935..20f943aa03 100644 --- a/LUFA/makefile +++ b/LUFA/makefile @@ -15,13 +15,9 @@ LUFA_SRC_FILES = ./Drivers/USB/LowLevel/DevChapter9.c \ ./Drivers/USB/LowLevel/LowLevel.c \ ./Drivers/USB/LowLevel/Pipe.c \ ./Drivers/USB/HighLevel/Events.c \ - ./Drivers/USB/HighLevel/StdDescriptors.c \ ./Drivers/USB/HighLevel/USBInterrupt.c \ ./Drivers/USB/HighLevel/USBTask.c \ - ./Drivers/USB/Class/ConfigDescriptor.c \ - ./Drivers/USB/Class/HIDParser.c \ - ./Scheduler/Scheduler.c \ - ./MemoryAllocator/DynAlloc.c \ + ./Drivers/USB/HighLevel/ConfigDescriptor.c \ ./Drivers/Board/Temperature.c \ ./Drivers/Peripheral/Serial.c \ ./Drivers/Peripheral/SerialStream.c \ -- cgit v1.2.3