diff options
author | Dean Camera <dean@fourwalledcubicle.com> | 2010-05-08 03:12:14 +0000 |
---|---|---|
committer | Dean Camera <dean@fourwalledcubicle.com> | 2010-05-08 03:12:14 +0000 |
commit | 071e02c6b6b4837fa9cf0b6d4c749994e02638d7 (patch) | |
tree | 960446788703b69f0bb285450be80c5b3d8cc22c /LUFA/Drivers/USB/Class/Host | |
parent | e331b531c6e6d93eb0eee42b9002074e8090ad18 (diff) | |
download | lufa-071e02c6b6b4837fa9cf0b6d4c749994e02638d7.tar.gz lufa-071e02c6b6b4837fa9cf0b6d4c749994e02638d7.tar.bz2 lufa-071e02c6b6b4837fa9cf0b6d4c749994e02638d7.zip |
Add svn:eol-style property to source files, so that the line endings are correctly converted to the target system's native end of line style.
Diffstat (limited to 'LUFA/Drivers/USB/Class/Host')
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/CDC.c | 892 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/CDC.h | 672 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/HID.c | 724 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/HID.h | 624 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/HIDParser.c | 706 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/HIDParser.h | 710 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/HIDReportData.h | 282 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/MIDI.c | 372 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/MIDI.h | 408 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/MassStorage.c | 1188 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/MassStorage.h | 678 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/Printer.c | 500 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/Printer.h | 466 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/RNDIS.c | 934 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/RNDIS.h | 566 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/StillImage.c | 826 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/StillImage.h | 646 |
17 files changed, 5597 insertions, 5597 deletions
diff --git a/LUFA/Drivers/USB/Class/Host/CDC.c b/LUFA/Drivers/USB/Class/Host/CDC.c index 8a00616b4..3d158fb75 100644 --- a/LUFA/Drivers/USB/Class/Host/CDC.c +++ b/LUFA/Drivers/USB/Class/Host/CDC.c @@ -1,446 +1,446 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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_USB_DRIVER
-#include "../../HighLevel/USBMode.h"
-#if defined(USB_CAN_BE_HOST)
-
-#define __INCLUDE_FROM_CDC_CLASS_HOST_C
-#define __INCLUDE_FROM_CDC_DRIVER
-#include "CDC.h"
-
-uint8_t CDC_Host_ConfigurePipes(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* ConfigDescriptorData)
-{
- uint8_t FoundEndpoints = 0;
-
- memset(&CDCInterfaceInfo->State, 0x00, sizeof(CDCInterfaceInfo->State));
-
- if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
- return CDC_ENUMERROR_InvalidConfigDescriptor;
-
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_CDC_Host_NextCDCControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return CDC_ENUMERROR_NoCDCInterfaceFound;
- }
-
- CDCInterfaceInfo->State.ControlInterfaceNumber = DESCRIPTOR_CAST(ConfigDescriptorData, USB_Descriptor_Interface_t).InterfaceNumber;
-
- while (FoundEndpoints != (CDC_FOUND_NOTIFICATION_IN | CDC_FOUND_DATAPIPE_IN | CDC_FOUND_DATAPIPE_OUT))
- {
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_CDC_Host_NextCDCInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- if (FoundEndpoints & CDC_FOUND_NOTIFICATION_IN)
- {
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_CDC_Host_NextCDCDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return CDC_ENUMERROR_NoCDCInterfaceFound;
- }
- }
- else
- {
- FoundEndpoints = 0;
-
- Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
- Pipe_DisablePipe();
- Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_DisablePipe();
- Pipe_SelectPipe(CDCInterfaceInfo->Config.NotificationPipeNumber);
- Pipe_DisablePipe();
-
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_CDC_Host_NextCDCControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return CDC_ENUMERROR_NoCDCInterfaceFound;
- }
- }
-
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_CDC_Host_NextCDCInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return CDC_ENUMERROR_EndpointsNotFound;
- }
- }
-
- USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
-
- if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
- {
- if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
- {
- Pipe_ConfigurePipe(CDCInterfaceInfo->Config.NotificationPipeNumber, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- CDCInterfaceInfo->Config.NotificationPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- CDCInterfaceInfo->State.NotificationPipeSize = EndpointData->EndpointSize;
-
- Pipe_SetInterruptPeriod(EndpointData->PollingIntervalMS);
-
- FoundEndpoints |= CDC_FOUND_NOTIFICATION_IN;
- }
- }
- else
- {
- if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
- {
- Pipe_ConfigurePipe(CDCInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- CDCInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
-
- CDCInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize;
-
- FoundEndpoints |= CDC_FOUND_DATAPIPE_IN;
- }
- else
- {
- Pipe_ConfigurePipe(CDCInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- CDCInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
-
- CDCInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize;
-
- FoundEndpoints |= CDC_FOUND_DATAPIPE_OUT;
- }
- }
- }
-
- CDCInterfaceInfo->State.ControlLineStates.HostToDevice = (CDC_CONTROL_LINE_OUT_RTS | CDC_CONTROL_LINE_OUT_DTR);
- CDCInterfaceInfo->State.ControlLineStates.DeviceToHost = (CDC_CONTROL_LINE_IN_DCD | CDC_CONTROL_LINE_IN_DSR);
- CDCInterfaceInfo->State.IsActive = true;
- return CDC_ENUMERROR_NoError;
-}
-
-static uint8_t DComp_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Interface_t);
-
- if ((CurrentInterface->Class == CDC_CONTROL_CLASS) &&
- (CurrentInterface->SubClass == CDC_CONTROL_SUBCLASS) &&
- (CurrentInterface->Protocol == CDC_CONTROL_PROTOCOL))
- {
- return DESCRIPTOR_SEARCH_Found;
- }
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-static uint8_t DComp_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Interface_t);
-
- if ((CurrentInterface->Class == CDC_DATA_CLASS) &&
- (CurrentInterface->SubClass == CDC_DATA_SUBCLASS) &&
- (CurrentInterface->Protocol == CDC_DATA_PROTOCOL))
- {
- return DESCRIPTOR_SEARCH_Found;
- }
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-static uint8_t DComp_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
- {
- USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Endpoint_t);
-
- uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK);
-
- if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
- !(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress)))
- {
- return DESCRIPTOR_SEARCH_Found;
- }
- }
- else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- return DESCRIPTOR_SEARCH_Fail;
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
- return;
-
- Pipe_SelectPipe(CDCInterfaceInfo->Config.NotificationPipeNumber);
- Pipe_SetPipeToken(PIPE_TOKEN_IN);
- Pipe_Unfreeze();
-
- if (Pipe_IsINReceived())
- {
- USB_Request_Header_t Notification;
- Pipe_Read_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NO_STREAM_CALLBACK);
-
- if ((Notification.bRequest == NOTIF_SerialState) &&
- (Notification.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)))
- {
- Pipe_Read_Stream_LE(&CDCInterfaceInfo->State.ControlLineStates.DeviceToHost,
- sizeof(CDCInterfaceInfo->State.ControlLineStates.DeviceToHost),
- NO_STREAM_CALLBACK);
-
- }
-
- Pipe_ClearIN();
-
- EVENT_CDC_Host_ControLineStateChanged(CDCInterfaceInfo);
- }
-
- Pipe_Freeze();
-}
-
-uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
-{
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_SetLineEncoding,
- .wValue = 0,
- .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
- .wLength = sizeof(CDCInterfaceInfo->State.LineEncoding),
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
-
- return USB_Host_SendControlRequest(&CDCInterfaceInfo->State.LineEncoding);
-}
-
-uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
-{
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_SetControlLineState,
- .wValue = CDCInterfaceInfo->State.ControlLineStates.HostToDevice,
- .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
- .wLength = 0,
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
-
- return USB_Host_SendControlRequest(NULL);
-}
-
-uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, const uint8_t Duration)
-{
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_SendBreak,
- .wValue = Duration,
- .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
- .wLength = 0,
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
-
- return USB_Host_SendControlRequest(NULL);
-}
-
-uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, char* Data, const uint16_t Length)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
- return PIPE_READYWAIT_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
-
- Pipe_Unfreeze();
- ErrorCode = Pipe_Write_Stream_LE(Data, Length, NO_STREAM_CALLBACK);
- Pipe_Freeze();
-
- return ErrorCode;
-}
-
-uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, const uint8_t Data)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
- return PIPE_READYWAIT_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_Unfreeze();
-
- if (!(Pipe_IsReadWriteAllowed()))
- {
- Pipe_ClearOUT();
-
- if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
- return ErrorCode;
- }
-
- Pipe_Write_Byte(Data);
- Pipe_Freeze();
-
- return PIPE_READYWAIT_NoError;
-}
-
-uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
- return 0;
-
- Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
- Pipe_SetPipeToken(PIPE_TOKEN_IN);
- Pipe_Unfreeze();
-
- if (Pipe_IsINReceived())
- {
- if (!(Pipe_BytesInPipe()))
- {
- Pipe_ClearIN();
- Pipe_Freeze();
- return 0;
- }
- else
- {
- Pipe_Freeze();
- return Pipe_BytesInPipe();
- }
- }
- else
- {
- Pipe_Freeze();
-
- return 0;
- }
-}
-
-uint8_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
-{
- uint8_t ReceivedByte = 0;
-
- if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
- return 0;
-
- Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
- Pipe_SetPipeToken(PIPE_TOKEN_IN);
- Pipe_Unfreeze();
-
- ReceivedByte = Pipe_Read_Byte();
-
- if (!(Pipe_BytesInPipe()))
- Pipe_ClearIN();
-
- Pipe_Freeze();
-
- return ReceivedByte;
-}
-
-uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
- return PIPE_READYWAIT_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_Unfreeze();
-
- if (!(Pipe_BytesInPipe()))
- return PIPE_READYWAIT_NoError;
-
- bool BankFull = !(Pipe_IsReadWriteAllowed());
-
- Pipe_ClearOUT();
-
- if (BankFull)
- {
- if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
- return ErrorCode;
-
- Pipe_ClearOUT();
- }
-
- Pipe_Freeze();
-
- return PIPE_READYWAIT_NoError;
-}
-
-void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, FILE* Stream)
-{
- *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar, _FDEV_SETUP_RW);
- fdev_set_udata(Stream, CDCInterfaceInfo);
-}
-
-void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, FILE* Stream)
-{
- *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar_Blocking, _FDEV_SETUP_RW);
- fdev_set_udata(Stream, CDCInterfaceInfo);
-}
-
-static int CDC_Host_putchar(char c, FILE* Stream)
-{
- return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0;
-}
-
-static int CDC_Host_getchar(FILE* Stream)
-{
- if (!(CDC_Host_BytesReceived((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream))))
- return _FDEV_EOF;
-
- return CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
-}
-
-static int CDC_Host_getchar_Blocking(FILE* Stream)
-{
- while (!(CDC_Host_BytesReceived((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream))))
- {
- if (USB_HostState == HOST_STATE_Unattached)
- return _FDEV_EOF;
-
- CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
- USB_USBTask();
- }
-
- return CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
-}
-
-void CDC_Host_Event_Stub(void)
-{
-
-}
-
-#endif
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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_USB_DRIVER +#include "../../HighLevel/USBMode.h" +#if defined(USB_CAN_BE_HOST) + +#define __INCLUDE_FROM_CDC_CLASS_HOST_C +#define __INCLUDE_FROM_CDC_DRIVER +#include "CDC.h" + +uint8_t CDC_Host_ConfigurePipes(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, uint16_t ConfigDescriptorSize, + void* ConfigDescriptorData) +{ + uint8_t FoundEndpoints = 0; + + memset(&CDCInterfaceInfo->State, 0x00, sizeof(CDCInterfaceInfo->State)); + + if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration) + return CDC_ENUMERROR_InvalidConfigDescriptor; + + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_CDC_Host_NextCDCControlInterface) != DESCRIPTOR_SEARCH_COMP_Found) + { + return CDC_ENUMERROR_NoCDCInterfaceFound; + } + + CDCInterfaceInfo->State.ControlInterfaceNumber = DESCRIPTOR_CAST(ConfigDescriptorData, USB_Descriptor_Interface_t).InterfaceNumber; + + while (FoundEndpoints != (CDC_FOUND_NOTIFICATION_IN | CDC_FOUND_DATAPIPE_IN | CDC_FOUND_DATAPIPE_OUT)) + { + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_CDC_Host_NextCDCInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found) + { + if (FoundEndpoints & CDC_FOUND_NOTIFICATION_IN) + { + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_CDC_Host_NextCDCDataInterface) != DESCRIPTOR_SEARCH_COMP_Found) + { + return CDC_ENUMERROR_NoCDCInterfaceFound; + } + } + else + { + FoundEndpoints = 0; + + Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber); + Pipe_DisablePipe(); + Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_DisablePipe(); + Pipe_SelectPipe(CDCInterfaceInfo->Config.NotificationPipeNumber); + Pipe_DisablePipe(); + + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_CDC_Host_NextCDCControlInterface) != DESCRIPTOR_SEARCH_COMP_Found) + { + return CDC_ENUMERROR_NoCDCInterfaceFound; + } + } + + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_CDC_Host_NextCDCInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found) + { + return CDC_ENUMERROR_EndpointsNotFound; + } + } + + USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t); + + if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT) + { + if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN) + { + Pipe_ConfigurePipe(CDCInterfaceInfo->Config.NotificationPipeNumber, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + CDCInterfaceInfo->Config.NotificationPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + CDCInterfaceInfo->State.NotificationPipeSize = EndpointData->EndpointSize; + + Pipe_SetInterruptPeriod(EndpointData->PollingIntervalMS); + + FoundEndpoints |= CDC_FOUND_NOTIFICATION_IN; + } + } + else + { + if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN) + { + Pipe_ConfigurePipe(CDCInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + CDCInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + + CDCInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize; + + FoundEndpoints |= CDC_FOUND_DATAPIPE_IN; + } + else + { + Pipe_ConfigurePipe(CDCInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + CDCInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + + CDCInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize; + + FoundEndpoints |= CDC_FOUND_DATAPIPE_OUT; + } + } + } + + CDCInterfaceInfo->State.ControlLineStates.HostToDevice = (CDC_CONTROL_LINE_OUT_RTS | CDC_CONTROL_LINE_OUT_DTR); + CDCInterfaceInfo->State.ControlLineStates.DeviceToHost = (CDC_CONTROL_LINE_IN_DCD | CDC_CONTROL_LINE_IN_DSR); + CDCInterfaceInfo->State.IsActive = true; + return CDC_ENUMERROR_NoError; +} + +static uint8_t DComp_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Interface_t); + + if ((CurrentInterface->Class == CDC_CONTROL_CLASS) && + (CurrentInterface->SubClass == CDC_CONTROL_SUBCLASS) && + (CurrentInterface->Protocol == CDC_CONTROL_PROTOCOL)) + { + return DESCRIPTOR_SEARCH_Found; + } + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +static uint8_t DComp_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Interface_t); + + if ((CurrentInterface->Class == CDC_DATA_CLASS) && + (CurrentInterface->SubClass == CDC_DATA_SUBCLASS) && + (CurrentInterface->Protocol == CDC_DATA_PROTOCOL)) + { + return DESCRIPTOR_SEARCH_Found; + } + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +static uint8_t DComp_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint) + { + USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Endpoint_t); + + uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK); + + if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) && + !(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress))) + { + return DESCRIPTOR_SEARCH_Found; + } + } + else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + return DESCRIPTOR_SEARCH_Fail; + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive)) + return; + + Pipe_SelectPipe(CDCInterfaceInfo->Config.NotificationPipeNumber); + Pipe_SetPipeToken(PIPE_TOKEN_IN); + Pipe_Unfreeze(); + + if (Pipe_IsINReceived()) + { + USB_Request_Header_t Notification; + Pipe_Read_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NO_STREAM_CALLBACK); + + if ((Notification.bRequest == NOTIF_SerialState) && + (Notification.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))) + { + Pipe_Read_Stream_LE(&CDCInterfaceInfo->State.ControlLineStates.DeviceToHost, + sizeof(CDCInterfaceInfo->State.ControlLineStates.DeviceToHost), + NO_STREAM_CALLBACK); + + } + + Pipe_ClearIN(); + + EVENT_CDC_Host_ControLineStateChanged(CDCInterfaceInfo); + } + + Pipe_Freeze(); +} + +uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) +{ + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_SetLineEncoding, + .wValue = 0, + .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber, + .wLength = sizeof(CDCInterfaceInfo->State.LineEncoding), + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + return USB_Host_SendControlRequest(&CDCInterfaceInfo->State.LineEncoding); +} + +uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) +{ + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_SetControlLineState, + .wValue = CDCInterfaceInfo->State.ControlLineStates.HostToDevice, + .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber, + .wLength = 0, + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + return USB_Host_SendControlRequest(NULL); +} + +uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, const uint8_t Duration) +{ + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_SendBreak, + .wValue = Duration, + .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber, + .wLength = 0, + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + return USB_Host_SendControlRequest(NULL); +} + +uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, char* Data, const uint16_t Length) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive)) + return PIPE_READYWAIT_DeviceDisconnected; + + uint8_t ErrorCode; + + Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber); + + Pipe_Unfreeze(); + ErrorCode = Pipe_Write_Stream_LE(Data, Length, NO_STREAM_CALLBACK); + Pipe_Freeze(); + + return ErrorCode; +} + +uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, const uint8_t Data) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive)) + return PIPE_READYWAIT_DeviceDisconnected; + + uint8_t ErrorCode; + + Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_Unfreeze(); + + if (!(Pipe_IsReadWriteAllowed())) + { + Pipe_ClearOUT(); + + if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError) + return ErrorCode; + } + + Pipe_Write_Byte(Data); + Pipe_Freeze(); + + return PIPE_READYWAIT_NoError; +} + +uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive)) + return 0; + + Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber); + Pipe_SetPipeToken(PIPE_TOKEN_IN); + Pipe_Unfreeze(); + + if (Pipe_IsINReceived()) + { + if (!(Pipe_BytesInPipe())) + { + Pipe_ClearIN(); + Pipe_Freeze(); + return 0; + } + else + { + Pipe_Freeze(); + return Pipe_BytesInPipe(); + } + } + else + { + Pipe_Freeze(); + + return 0; + } +} + +uint8_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) +{ + uint8_t ReceivedByte = 0; + + if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive)) + return 0; + + Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber); + Pipe_SetPipeToken(PIPE_TOKEN_IN); + Pipe_Unfreeze(); + + ReceivedByte = Pipe_Read_Byte(); + + if (!(Pipe_BytesInPipe())) + Pipe_ClearIN(); + + Pipe_Freeze(); + + return ReceivedByte; +} + +uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive)) + return PIPE_READYWAIT_DeviceDisconnected; + + uint8_t ErrorCode; + + Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_Unfreeze(); + + if (!(Pipe_BytesInPipe())) + return PIPE_READYWAIT_NoError; + + bool BankFull = !(Pipe_IsReadWriteAllowed()); + + Pipe_ClearOUT(); + + if (BankFull) + { + if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError) + return ErrorCode; + + Pipe_ClearOUT(); + } + + Pipe_Freeze(); + + return PIPE_READYWAIT_NoError; +} + +void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, FILE* Stream) +{ + *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar, _FDEV_SETUP_RW); + fdev_set_udata(Stream, CDCInterfaceInfo); +} + +void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, FILE* Stream) +{ + *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar_Blocking, _FDEV_SETUP_RW); + fdev_set_udata(Stream, CDCInterfaceInfo); +} + +static int CDC_Host_putchar(char c, FILE* Stream) +{ + return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0; +} + +static int CDC_Host_getchar(FILE* Stream) +{ + if (!(CDC_Host_BytesReceived((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream)))) + return _FDEV_EOF; + + return CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream)); +} + +static int CDC_Host_getchar_Blocking(FILE* Stream) +{ + while (!(CDC_Host_BytesReceived((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream)))) + { + if (USB_HostState == HOST_STATE_Unattached) + return _FDEV_EOF; + + CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream)); + USB_USBTask(); + } + + return CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream)); +} + +void CDC_Host_Event_Stub(void) +{ + +} + +#endif diff --git a/LUFA/Drivers/USB/Class/Host/CDC.h b/LUFA/Drivers/USB/Class/Host/CDC.h index 3ea2d51d7..9c59ad343 100644 --- a/LUFA/Drivers/USB/Class/Host/CDC.h +++ b/LUFA/Drivers/USB/Class/Host/CDC.h @@ -1,336 +1,336 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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
- * \brief Host mode driver for the library USB CDC Class driver.
- *
- * Host mode driver for the library USB CDC Class driver.
- *
- * \note This file should not be included directly. It is automatically included as needed by the class driver
- * dispatch header located in LUFA/Drivers/USB/Class/CDC.h.
- */
-
-/** \ingroup Group_USBClassCDC
- * @defgroup Group_USBClassCDCHost CDC Class Host Mode Driver
- *
- * \section Sec_Dependencies Module Source Dependencies
- * The following files must be built with any user project that uses this module:
- * - LUFA/Drivers/USB/Class/Host/CDC.c
- *
- * \section Module Description
- * Host Mode USB Class driver framework interface, for the CDC USB Class driver.
- *
- * @{
- */
-
-#ifndef __CDC_CLASS_HOST_H__
-#define __CDC_CLASS_HOST_H__
-
- /* Includes: */
- #include "../../USB.h"
- #include "../Common/CDC.h"
-
- #include <stdio.h>
- #include <string.h>
-
- /* Enable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- extern "C" {
- #endif
-
- /* Preprocessor Checks: */
- #if !defined(__INCLUDE_FROM_CDC_DRIVER)
- #error Do not include this file directly. Include LUFA/Drivers/Class/CDC.h instead.
- #endif
-
- /* Public Interface - May be used in end-application: */
- /* Type Defines: */
- /** \brief CDC Class Host Mode Configuration and State Structure.
- *
- * Class state structure. An instance of this structure should be made within the user application,
- * and passed to each of the CDC class driver functions as the CDCInterfaceInfo parameter. This
- * stores each CDC interface's configuration and state information.
- */
- typedef struct
- {
- const struct
- {
- uint8_t DataINPipeNumber; /**< Pipe number of the CDC interface's IN data pipe */
- bool DataINPipeDoubleBank; /** Indicates if the CDC interface's IN data pipe should use double banking */
-
- uint8_t DataOUTPipeNumber; /**< Pipe number of the CDC interface's OUT data pipe */
- bool DataOUTPipeDoubleBank; /** Indicates if the CDC interface's OUT data pipe should use double banking */
-
- uint8_t NotificationPipeNumber; /**< Pipe number of the CDC interface's IN notification endpoint, if used */
- bool NotificationPipeDoubleBank; /** Indicates if the CDC interface's notification pipe should use double banking */
- } Config; /**< Config data for the USB class interface within the device. All elements in this section
- * <b>must</b> be set or the interface will fail to enumerate and operate correctly.
- */
- struct
- {
- bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
- * after \ref CDC_Host_ConfigurePipes() is called and the Host state machine is in the
- * Configured state
- */
- uint8_t ControlInterfaceNumber; /**< Interface index of the CDC-ACM control interface within the attached device */
-
- uint16_t DataINPipeSize; /**< Size in bytes of the CDC interface's IN data pipe */
- uint16_t DataOUTPipeSize; /**< Size in bytes of the CDC interface's OUT data pipe */
- uint16_t NotificationPipeSize; /**< Size in bytes of the CDC interface's IN notification pipe, if used */
-
- struct
- {
- uint8_t HostToDevice; /**< Control line states from the host to device, as a set of CDC_CONTROL_LINE_OUT_*
- * masks - to notify the device of changes to these values, call the
- * \ref CDC_Host_SendControlLineStateChange() function.
- */
- uint8_t DeviceToHost; /**< Control line states from the device to host, as a set of CDC_CONTROL_LINE_IN_*
- * masks. This value is updated each time \ref CDC_Host_USBTask() is called.
- */
- } ControlLineStates; /**< Current states of the virtual serial port's control lines between the device and host. */
-
- 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; /** Line encoding used in the virtual serial port, for the device's information. This is generally
- * only used if the virtual serial port data is to be reconstructed on a physical UART. When set
- * by the host application, the \ref CDC_Host_SetLineEncoding() function must be called to push
- * the changes to the device.
- */
- } State; /**< State data for the USB class interface within the device. All elements in this section
- * <b>may</b> be set to initial values, but may also be ignored to default to sane values when
- * the interface is enumerated.
- */
- } USB_ClassInfo_CDC_Host_t;
-
- /* Enums: */
- /** Enum for the possible error codes returned by the \ref CDC_Host_ConfigurePipes() function. */
- enum CDCHost_EnumerationFailure_ErrorCodes_t
- {
- CDC_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */
- CDC_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */
- CDC_ENUMERROR_NoCDCInterfaceFound = 2, /**< A compatible CDC interface was not found in the device's Configuration Descriptor */
- CDC_ENUMERROR_EndpointsNotFound = 3, /**< Compatible CDC endpoints were not found in the device's CDC interface */
- };
-
- /* Function Prototypes: */
- /** General management task for a given CDC host class interface, required for the correct operation of the interface. This should
- * be called frequently in the main program loop, before the master USB management task \ref USB_USBTask().
- *
- * \param[in,out] CDCInterfaceInfo Pointer to a structure containing an CDC Class host configuration and state
- */
- void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Host interface configuration routine, to configure a given CDC host interface instance using the Configuration
- * Descriptor read from an attached USB device. This function automatically updates the given CDC Host instance's
- * state values and configures the pipes required to communicate with the interface if it is found within the device.
- * This should be called once after the stack has enumerated the attached device, while the host state machine is in
- * the Addressed state.
- *
- * \param[in,out] CDCInterfaceInfo Pointer to a structure containing an CDC Class host configuration and state
- * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor
- * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor
- *
- * \return A value from the \ref CDCHost_EnumerationFailure_ErrorCodes_t enum
- */
- uint8_t CDC_Host_ConfigurePipes(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
-
- /** Sets the line encoding for the attached device's virtual serial port. This should be called when the LineEncoding
- * values of the interface have been changed to push the new settings to the USB device.
- *
- * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state
- *
- * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum
- */
- uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Sends a Serial Control Line State Change notification to the device. This should be called when the virtual serial
- * control lines (DTR, RTS, etc.) have changed states. Line states persist until they are cleared via a second
- * notification. This should be called each time the CDC class driver's ControlLineStates.HostToDevice value is updated
- * to push the new states to the USB device.
- *
- * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state
- *
- * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum
- */
- uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Sends a Send Break request to the device. This is generally used to seperate data data or to indicate a special condition
- * to the receiving device.
- *
- * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state
- * \param[in] Duration Duration of the break, in milliseconds
- *
- * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum
- */
- uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, const uint8_t Duration) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Sends a given string to the attached USB device, if connected. If a device is not connected when the function is called, the
- * string is discarded. Bytes will be queued for transmission to the device until either the pipe bank becomes full, or the
- * \ref CDC_Host_Flush() function is called to flush the pending data to the host. This allows for multiple bytes to be
- * packed into a single pipe packet, increasing data throughput.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state
- * \param[in] Data Pointer to the string to send to the device
- * \param[in] Length Size in bytes of the string to send to the device
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum
- */
- uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, char* Data, const uint16_t Length)
- ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
-
- /** Sends a given byte to the attached USB device, if connected. If a device is not connected when the function is called, the
- * byte is discarded. Bytes will be queued for transmission to the device until either the pipe bank becomes full, or the
- * \ref CDC_Host_Flush() function is called to flush the pending data to the host. This allows for multiple bytes to be
- * packed into a single pipe packet, increasing data throughput.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state
- * \param[in] Data Byte of data to send to the device
- *
- * \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum
- */
- uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, const uint8_t Data) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Determines the number of bytes received by the CDC interface from the device, waiting to be read.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state
- *
- * \return Total number of buffered bytes received from the device
- */
- uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Reads a byte of data from the device. If no data is waiting to be read of if a USB device is not connected, the function
- * returns 0. The \ref CDC_Host_BytesReceived() function should be queried before data is received to ensure that no data
- * underflow occurs.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state
- *
- * \return Next received byte from the device, or 0 if no data received
- */
- uint8_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Flushes any data waiting to be sent, ensuring that the send buffer is cleared.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state
- *
- * \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum
- */
- uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Creates a standard characer stream for the given CDC Device instance so that it can be used with all the regular
- * functions in the avr-libc <stdio.h> library that accept a FILE stream as a destination (e.g. fprintf). The created
- * stream is bidirectional and can be used for both input and output functions.
- *
- * \note The created stream can be given as stdout if desired to direct the standard output from all <stdio.h> functions
- * to the given CDC interface.
- *
- * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state
- * \param[in,out] Stream Pointer to a FILE structure where the created stream should be placed
- */
- void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, FILE* Stream);
-
- /** Identical to CDC_Host_CreateStream(), except that reads are blocking until the calling stream function terminates
- * the transfer. While blocking, the USB and CDC service tasks are called repeatedly to maintain USB communications.
- *
- * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state
- * \param[in,out] Stream Pointer to a FILE structure where the created stream should be placed
- */
- void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, FILE* Stream);
-
- /** CDC class driver event for a control line state change on a CDC host interface. This event fires each time the device notifies
- * the host of a control line state change (containing the virtual serial control line states, such as DCD) and may be hooked in the
- * user program by declaring a handler function with the same name and parameters listed here. The new control line states
- * are available in the ControlLineStates.DeviceToHost value inside the CDC host interface structure passed as a parameter, set as
- * a mask of CDC_CONTROL_LINE_IN_* masks.
- *
- * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state
- */
- void EVENT_CDC_Host_ControLineStateChanged(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /* Private Interface - For use in library only: */
- #if !defined(__DOXYGEN__)
- /* Macros: */
- #define CDC_CONTROL_CLASS 0x02
- #define CDC_CONTROL_SUBCLASS 0x02
- #define CDC_CONTROL_PROTOCOL 0x01
- #define CDC_DATA_CLASS 0x0A
- #define CDC_DATA_SUBCLASS 0x00
- #define CDC_DATA_PROTOCOL 0x00
-
- #define CDC_FOUND_DATAPIPE_IN (1 << 0)
- #define CDC_FOUND_DATAPIPE_OUT (1 << 1)
- #define CDC_FOUND_NOTIFICATION_IN (1 << 2)
-
- /* Function Prototypes: */
- #if defined(__INCLUDE_FROM_CDC_CLASS_HOST_C)
- static int CDC_Host_putchar(char c, FILE* Stream);
- static int CDC_Host_getchar(FILE* Stream);
- static int CDC_Host_getchar_Blocking(FILE* Stream);
-
- void CDC_Host_Event_Stub(void);
- void EVENT_CDC_Host_ControLineStateChanged(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
- ATTR_WEAK ATTR_NON_NULL_PTR_ARG(1) ATTR_ALIAS(CDC_Host_Event_Stub);
- static uint8_t DComp_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1);
- static uint8_t DComp_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1);
- static uint8_t DComp_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor);
- #endif
- #endif
-
- /* Disable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- }
- #endif
-
-#endif
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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 + * \brief Host mode driver for the library USB CDC Class driver. + * + * Host mode driver for the library USB CDC Class driver. + * + * \note This file should not be included directly. It is automatically included as needed by the class driver + * dispatch header located in LUFA/Drivers/USB/Class/CDC.h. + */ + +/** \ingroup Group_USBClassCDC + * @defgroup Group_USBClassCDCHost CDC Class Host Mode Driver + * + * \section Sec_Dependencies Module Source Dependencies + * The following files must be built with any user project that uses this module: + * - LUFA/Drivers/USB/Class/Host/CDC.c + * + * \section Module Description + * Host Mode USB Class driver framework interface, for the CDC USB Class driver. + * + * @{ + */ + +#ifndef __CDC_CLASS_HOST_H__ +#define __CDC_CLASS_HOST_H__ + + /* Includes: */ + #include "../../USB.h" + #include "../Common/CDC.h" + + #include <stdio.h> + #include <string.h> + + /* Enable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + extern "C" { + #endif + + /* Preprocessor Checks: */ + #if !defined(__INCLUDE_FROM_CDC_DRIVER) + #error Do not include this file directly. Include LUFA/Drivers/Class/CDC.h instead. + #endif + + /* Public Interface - May be used in end-application: */ + /* Type Defines: */ + /** \brief CDC Class Host Mode Configuration and State Structure. + * + * Class state structure. An instance of this structure should be made within the user application, + * and passed to each of the CDC class driver functions as the CDCInterfaceInfo parameter. This + * stores each CDC interface's configuration and state information. + */ + typedef struct + { + const struct + { + uint8_t DataINPipeNumber; /**< Pipe number of the CDC interface's IN data pipe */ + bool DataINPipeDoubleBank; /** Indicates if the CDC interface's IN data pipe should use double banking */ + + uint8_t DataOUTPipeNumber; /**< Pipe number of the CDC interface's OUT data pipe */ + bool DataOUTPipeDoubleBank; /** Indicates if the CDC interface's OUT data pipe should use double banking */ + + uint8_t NotificationPipeNumber; /**< Pipe number of the CDC interface's IN notification endpoint, if used */ + bool NotificationPipeDoubleBank; /** Indicates if the CDC interface's notification pipe should use double banking */ + } Config; /**< Config data for the USB class interface within the device. All elements in this section + * <b>must</b> be set or the interface will fail to enumerate and operate correctly. + */ + struct + { + bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid + * after \ref CDC_Host_ConfigurePipes() is called and the Host state machine is in the + * Configured state + */ + uint8_t ControlInterfaceNumber; /**< Interface index of the CDC-ACM control interface within the attached device */ + + uint16_t DataINPipeSize; /**< Size in bytes of the CDC interface's IN data pipe */ + uint16_t DataOUTPipeSize; /**< Size in bytes of the CDC interface's OUT data pipe */ + uint16_t NotificationPipeSize; /**< Size in bytes of the CDC interface's IN notification pipe, if used */ + + struct + { + uint8_t HostToDevice; /**< Control line states from the host to device, as a set of CDC_CONTROL_LINE_OUT_* + * masks - to notify the device of changes to these values, call the + * \ref CDC_Host_SendControlLineStateChange() function. + */ + uint8_t DeviceToHost; /**< Control line states from the device to host, as a set of CDC_CONTROL_LINE_IN_* + * masks. This value is updated each time \ref CDC_Host_USBTask() is called. + */ + } ControlLineStates; /**< Current states of the virtual serial port's control lines between the device and host. */ + + 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; /** Line encoding used in the virtual serial port, for the device's information. This is generally + * only used if the virtual serial port data is to be reconstructed on a physical UART. When set + * by the host application, the \ref CDC_Host_SetLineEncoding() function must be called to push + * the changes to the device. + */ + } State; /**< State data for the USB class interface within the device. All elements in this section + * <b>may</b> be set to initial values, but may also be ignored to default to sane values when + * the interface is enumerated. + */ + } USB_ClassInfo_CDC_Host_t; + + /* Enums: */ + /** Enum for the possible error codes returned by the \ref CDC_Host_ConfigurePipes() function. */ + enum CDCHost_EnumerationFailure_ErrorCodes_t + { + CDC_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */ + CDC_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */ + CDC_ENUMERROR_NoCDCInterfaceFound = 2, /**< A compatible CDC interface was not found in the device's Configuration Descriptor */ + CDC_ENUMERROR_EndpointsNotFound = 3, /**< Compatible CDC endpoints were not found in the device's CDC interface */ + }; + + /* Function Prototypes: */ + /** General management task for a given CDC host class interface, required for the correct operation of the interface. This should + * be called frequently in the main program loop, before the master USB management task \ref USB_USBTask(). + * + * \param[in,out] CDCInterfaceInfo Pointer to a structure containing an CDC Class host configuration and state + */ + void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Host interface configuration routine, to configure a given CDC host interface instance using the Configuration + * Descriptor read from an attached USB device. This function automatically updates the given CDC Host instance's + * state values and configures the pipes required to communicate with the interface if it is found within the device. + * This should be called once after the stack has enumerated the attached device, while the host state machine is in + * the Addressed state. + * + * \param[in,out] CDCInterfaceInfo Pointer to a structure containing an CDC Class host configuration and state + * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor + * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor + * + * \return A value from the \ref CDCHost_EnumerationFailure_ErrorCodes_t enum + */ + uint8_t CDC_Host_ConfigurePipes(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, uint16_t ConfigDescriptorSize, + void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3); + + /** Sets the line encoding for the attached device's virtual serial port. This should be called when the LineEncoding + * values of the interface have been changed to push the new settings to the USB device. + * + * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state + * + * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum + */ + uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Sends a Serial Control Line State Change notification to the device. This should be called when the virtual serial + * control lines (DTR, RTS, etc.) have changed states. Line states persist until they are cleared via a second + * notification. This should be called each time the CDC class driver's ControlLineStates.HostToDevice value is updated + * to push the new states to the USB device. + * + * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state + * + * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum + */ + uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Sends a Send Break request to the device. This is generally used to seperate data data or to indicate a special condition + * to the receiving device. + * + * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state + * \param[in] Duration Duration of the break, in milliseconds + * + * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum + */ + uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, const uint8_t Duration) ATTR_NON_NULL_PTR_ARG(1); + + /** Sends a given string to the attached USB device, if connected. If a device is not connected when the function is called, the + * string is discarded. Bytes will be queued for transmission to the device until either the pipe bank becomes full, or the + * \ref CDC_Host_Flush() function is called to flush the pending data to the host. This allows for multiple bytes to be + * packed into a single pipe packet, increasing data throughput. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state + * \param[in] Data Pointer to the string to send to the device + * \param[in] Length Size in bytes of the string to send to the device + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum + */ + uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, char* Data, const uint16_t Length) + ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + + /** Sends a given byte to the attached USB device, if connected. If a device is not connected when the function is called, the + * byte is discarded. Bytes will be queued for transmission to the device until either the pipe bank becomes full, or the + * \ref CDC_Host_Flush() function is called to flush the pending data to the host. This allows for multiple bytes to be + * packed into a single pipe packet, increasing data throughput. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state + * \param[in] Data Byte of data to send to the device + * + * \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum + */ + uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, const uint8_t Data) ATTR_NON_NULL_PTR_ARG(1); + + /** Determines the number of bytes received by the CDC interface from the device, waiting to be read. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state + * + * \return Total number of buffered bytes received from the device + */ + uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Reads a byte of data from the device. If no data is waiting to be read of if a USB device is not connected, the function + * returns 0. The \ref CDC_Host_BytesReceived() function should be queried before data is received to ensure that no data + * underflow occurs. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state + * + * \return Next received byte from the device, or 0 if no data received + */ + uint8_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Flushes any data waiting to be sent, ensuring that the send buffer is cleared. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state + * + * \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum + */ + uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Creates a standard characer stream for the given CDC Device instance so that it can be used with all the regular + * functions in the avr-libc <stdio.h> library that accept a FILE stream as a destination (e.g. fprintf). The created + * stream is bidirectional and can be used for both input and output functions. + * + * \note The created stream can be given as stdout if desired to direct the standard output from all <stdio.h> functions + * to the given CDC interface. + * + * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state + * \param[in,out] Stream Pointer to a FILE structure where the created stream should be placed + */ + void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, FILE* Stream); + + /** Identical to CDC_Host_CreateStream(), except that reads are blocking until the calling stream function terminates + * the transfer. While blocking, the USB and CDC service tasks are called repeatedly to maintain USB communications. + * + * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state + * \param[in,out] Stream Pointer to a FILE structure where the created stream should be placed + */ + void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, FILE* Stream); + + /** CDC class driver event for a control line state change on a CDC host interface. This event fires each time the device notifies + * the host of a control line state change (containing the virtual serial control line states, such as DCD) and may be hooked in the + * user program by declaring a handler function with the same name and parameters listed here. The new control line states + * are available in the ControlLineStates.DeviceToHost value inside the CDC host interface structure passed as a parameter, set as + * a mask of CDC_CONTROL_LINE_IN_* masks. + * + * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state + */ + void EVENT_CDC_Host_ControLineStateChanged(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /* Private Interface - For use in library only: */ + #if !defined(__DOXYGEN__) + /* Macros: */ + #define CDC_CONTROL_CLASS 0x02 + #define CDC_CONTROL_SUBCLASS 0x02 + #define CDC_CONTROL_PROTOCOL 0x01 + #define CDC_DATA_CLASS 0x0A + #define CDC_DATA_SUBCLASS 0x00 + #define CDC_DATA_PROTOCOL 0x00 + + #define CDC_FOUND_DATAPIPE_IN (1 << 0) + #define CDC_FOUND_DATAPIPE_OUT (1 << 1) + #define CDC_FOUND_NOTIFICATION_IN (1 << 2) + + /* Function Prototypes: */ + #if defined(__INCLUDE_FROM_CDC_CLASS_HOST_C) + static int CDC_Host_putchar(char c, FILE* Stream); + static int CDC_Host_getchar(FILE* Stream); + static int CDC_Host_getchar_Blocking(FILE* Stream); + + void CDC_Host_Event_Stub(void); + void EVENT_CDC_Host_ControLineStateChanged(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) + ATTR_WEAK ATTR_NON_NULL_PTR_ARG(1) ATTR_ALIAS(CDC_Host_Event_Stub); + static uint8_t DComp_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1); + static uint8_t DComp_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1); + static uint8_t DComp_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor); + #endif + #endif + + /* Disable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + } + #endif + +#endif + +/** @} */ diff --git a/LUFA/Drivers/USB/Class/Host/HID.c b/LUFA/Drivers/USB/Class/Host/HID.c index 24dcceb4d..f7292d742 100644 --- a/LUFA/Drivers/USB/Class/Host/HID.c +++ b/LUFA/Drivers/USB/Class/Host/HID.c @@ -1,362 +1,362 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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_USB_DRIVER
-#include "../../HighLevel/USBMode.h"
-#if defined(USB_CAN_BE_HOST)
-
-#define __INCLUDE_FROM_HID_CLASS_HOST_C
-#define __INCLUDE_FROM_HID_DRIVER
-#include "HID.h"
-
-uint8_t HID_Host_ConfigurePipes(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* ConfigDescriptorData)
-{
- uint8_t FoundEndpoints = 0;
-
- memset(&HIDInterfaceInfo->State, 0x00, sizeof(HIDInterfaceInfo->State));
-
- if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
- return HID_ENUMERROR_InvalidConfigDescriptor;
-
- USB_Descriptor_Interface_t* CurrentHIDInterface;
-
- do
- {
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_HID_Host_NextHIDInterface) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return HID_ENUMERROR_NoHIDInterfaceFound;
- }
-
- CurrentHIDInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
- } while (HIDInterfaceInfo->Config.HIDInterfaceProtocol &&
- (CurrentHIDInterface->Protocol != HIDInterfaceInfo->Config.HIDInterfaceProtocol));
-
- HIDInterfaceInfo->State.InterfaceNumber = CurrentHIDInterface->InterfaceNumber;
- HIDInterfaceInfo->State.SupportsBootProtocol = (CurrentHIDInterface->SubClass != HID_NON_BOOT_PROTOCOL);
-
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, DComp_NextHID) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return HID_ENUMERROR_NoHIDDescriptorFound;
- }
-
- HIDInterfaceInfo->State.HIDReportSize = DESCRIPTOR_CAST(ConfigDescriptorData, USB_HID_Descriptor_t).HIDReportLength;
-
- while (FoundEndpoints != (HID_FOUND_DATAPIPE_IN | HID_FOUND_DATAPIPE_OUT))
- {
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_HID_Host_NextHIDInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- if (FoundEndpoints & HID_FOUND_DATAPIPE_IN)
- break;
-
- return HID_ENUMERROR_EndpointsNotFound;
- }
-
- USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
-
- if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
- {
- Pipe_ConfigurePipe(HIDInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- HIDInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- HIDInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize;
-
- FoundEndpoints |= HID_FOUND_DATAPIPE_IN;
- }
- else
- {
- Pipe_ConfigurePipe(HIDInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_INTERRUPT, PIPE_TOKEN_OUT,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- HIDInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- HIDInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize;
-
- HIDInterfaceInfo->State.DeviceUsesOUTPipe = true;
-
- FoundEndpoints |= HID_FOUND_DATAPIPE_OUT;
- }
- }
-
- HIDInterfaceInfo->State.LargestReportSize = 8;
- HIDInterfaceInfo->State.IsActive = true;
- return HID_ENUMERROR_NoError;
-}
-
-static uint8_t DComp_HID_Host_NextHIDInterface(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Interface_t);
-
- if (CurrentInterface->Class == HID_INTERFACE_CLASS)
- return DESCRIPTOR_SEARCH_Found;
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-static uint8_t DComp_NextHID(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_HID)
- return DESCRIPTOR_SEARCH_Found;
- else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- return DESCRIPTOR_SEARCH_Fail;
- else
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-static uint8_t DComp_HID_Host_NextHIDInterfaceEndpoint(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
- {
- USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Endpoint_t);
-
- if (!(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress)))
- return DESCRIPTOR_SEARCH_Found;
- }
- else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- return DESCRIPTOR_SEARCH_Fail;
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
-uint8_t HID_Host_ReceiveReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, const uint8_t ReportID, void* Buffer)
-{
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_SetReport,
- .wValue = ((REPORT_ITEM_TYPE_In + 1) << 8) | ReportID,
- .wIndex = HIDInterfaceInfo->State.InterfaceNumber,
- .wLength = USB_GetHIDReportSize(HIDInterfaceInfo->Config.HIDParserData, ReportID, REPORT_ITEM_TYPE_In),
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
-
- return USB_Host_SendControlRequest(Buffer);
-}
-#endif
-
-uint8_t HID_Host_ReceiveReport(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, void* Buffer)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive))
- return PIPE_READYWAIT_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- Pipe_SelectPipe(HIDInterfaceInfo->Config.DataINPipeNumber);
- Pipe_Unfreeze();
-
- uint16_t ReportSize;
- uint8_t* BufferPos = Buffer;
-
-#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
- if (!(HIDInterfaceInfo->State.UsingBootProtocol))
- {
- uint8_t ReportID = 0;
-
- if (HIDInterfaceInfo->Config.HIDParserData->UsingReportIDs)
- {
- ReportID = Pipe_Read_Byte();
- *(BufferPos++) = ReportID;
- }
-
- ReportSize = USB_GetHIDReportSize(HIDInterfaceInfo->Config.HIDParserData, ReportID, REPORT_ITEM_TYPE_In);
- }
- else
-#endif
- {
- ReportSize = Pipe_BytesInPipe();
- }
-
- if ((ErrorCode = Pipe_Read_Stream_LE(BufferPos, ReportSize, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- Pipe_ClearIN();
- Pipe_Freeze();
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t HID_Host_SendReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,
-#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
- const uint8_t ReportID,
-#endif
- void* Buffer, const uint16_t ReportSize)
-{
-#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
- if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive))
- return false;
-
- if (HIDInterfaceInfo->State.DeviceUsesOUTPipe)
- {
- uint8_t ErrorCode;
-
- Pipe_SelectPipe(HIDInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_Unfreeze();
-
- if (ReportID)
- Pipe_Write_Stream_LE(&ReportID, sizeof(ReportID), NO_STREAM_CALLBACK);
-
- if ((ErrorCode = Pipe_Write_Stream_LE(Buffer, ReportSize, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- Pipe_ClearOUT();
- Pipe_Freeze();
-
- return PIPE_RWSTREAM_NoError;
- }
- else
-#endif
- {
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_SetReport,
-#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
- .wValue = ((REPORT_ITEM_TYPE_Out + 1) << 8) | ReportID,
-#else
- .wValue = ((REPORT_ITEM_TYPE_Out + 1) << 8),
-#endif
- .wIndex = HIDInterfaceInfo->State.InterfaceNumber,
- .wLength = ReportSize,
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
-
- return USB_Host_SendControlRequest(Buffer);
- }
-}
-
-bool HID_Host_IsReportReceived(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive))
- return false;
-
- bool ReportReceived;
-
- Pipe_SelectPipe(HIDInterfaceInfo->Config.DataINPipeNumber);
- Pipe_Unfreeze();
-
- ReportReceived = Pipe_IsINReceived();
-
- Pipe_Freeze();
-
- return ReportReceived;
-}
-
-uint8_t HID_Host_SetBootProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo)
-{
- uint8_t ErrorCode;
-
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_SetProtocol,
- .wValue = 0,
- .wIndex = HIDInterfaceInfo->State.InterfaceNumber,
- .wLength = 0,
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
-
- if (!(HIDInterfaceInfo->State.SupportsBootProtocol))
- return HID_ERROR_LOGICAL;
-
- if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
- return ErrorCode;
-
- HIDInterfaceInfo->State.LargestReportSize = 8;
- HIDInterfaceInfo->State.UsingBootProtocol = true;
-
- return HOST_SENDCONTROL_Successful;
-}
-
-#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
-uint8_t HID_Host_SetReportProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo)
-{
- uint8_t ErrorCode;
-
- uint8_t HIDReportData[HIDInterfaceInfo->State.HIDReportSize];
-
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_INTERFACE),
- .bRequest = REQ_GetDescriptor,
- .wValue = (DTYPE_Report << 8),
- .wIndex = HIDInterfaceInfo->State.InterfaceNumber,
- .wLength = HIDInterfaceInfo->State.HIDReportSize,
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
-
- if ((ErrorCode = USB_Host_SendControlRequest(HIDReportData)) != HOST_SENDCONTROL_Successful)
- return ErrorCode;
-
- if (HIDInterfaceInfo->State.UsingBootProtocol)
- {
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_SetProtocol,
- .wValue = 1,
- .wIndex = HIDInterfaceInfo->State.InterfaceNumber,
- .wLength = 0,
- };
-
- if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
- return ErrorCode;
-
- HIDInterfaceInfo->State.UsingBootProtocol = false;
- }
-
- if (HIDInterfaceInfo->Config.HIDParserData == NULL)
- return HID_ERROR_LOGICAL;
-
- if ((ErrorCode = USB_ProcessHIDReport(HIDReportData, HIDInterfaceInfo->State.HIDReportSize,
- HIDInterfaceInfo->Config.HIDParserData)) != HID_PARSE_Successful)
- {
- return HID_ERROR_LOGICAL | ErrorCode;
- }
-
- uint8_t LargestReportSizeBits = HIDInterfaceInfo->Config.HIDParserData->LargestReportSizeBits;
- HIDInterfaceInfo->State.LargestReportSize = (LargestReportSizeBits >> 3) + ((LargestReportSizeBits & 0x07) != 0);
-
- return 0;
-}
-#endif
-
-#endif
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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_USB_DRIVER +#include "../../HighLevel/USBMode.h" +#if defined(USB_CAN_BE_HOST) + +#define __INCLUDE_FROM_HID_CLASS_HOST_C +#define __INCLUDE_FROM_HID_DRIVER +#include "HID.h" + +uint8_t HID_Host_ConfigurePipes(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, uint16_t ConfigDescriptorSize, + void* ConfigDescriptorData) +{ + uint8_t FoundEndpoints = 0; + + memset(&HIDInterfaceInfo->State, 0x00, sizeof(HIDInterfaceInfo->State)); + + if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration) + return HID_ENUMERROR_InvalidConfigDescriptor; + + USB_Descriptor_Interface_t* CurrentHIDInterface; + + do + { + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_HID_Host_NextHIDInterface) != DESCRIPTOR_SEARCH_COMP_Found) + { + return HID_ENUMERROR_NoHIDInterfaceFound; + } + + CurrentHIDInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t); + } while (HIDInterfaceInfo->Config.HIDInterfaceProtocol && + (CurrentHIDInterface->Protocol != HIDInterfaceInfo->Config.HIDInterfaceProtocol)); + + HIDInterfaceInfo->State.InterfaceNumber = CurrentHIDInterface->InterfaceNumber; + HIDInterfaceInfo->State.SupportsBootProtocol = (CurrentHIDInterface->SubClass != HID_NON_BOOT_PROTOCOL); + + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, DComp_NextHID) != DESCRIPTOR_SEARCH_COMP_Found) + { + return HID_ENUMERROR_NoHIDDescriptorFound; + } + + HIDInterfaceInfo->State.HIDReportSize = DESCRIPTOR_CAST(ConfigDescriptorData, USB_HID_Descriptor_t).HIDReportLength; + + while (FoundEndpoints != (HID_FOUND_DATAPIPE_IN | HID_FOUND_DATAPIPE_OUT)) + { + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_HID_Host_NextHIDInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found) + { + if (FoundEndpoints & HID_FOUND_DATAPIPE_IN) + break; + + return HID_ENUMERROR_EndpointsNotFound; + } + + USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t); + + if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN) + { + Pipe_ConfigurePipe(HIDInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + HIDInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + HIDInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize; + + FoundEndpoints |= HID_FOUND_DATAPIPE_IN; + } + else + { + Pipe_ConfigurePipe(HIDInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_INTERRUPT, PIPE_TOKEN_OUT, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + HIDInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + HIDInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize; + + HIDInterfaceInfo->State.DeviceUsesOUTPipe = true; + + FoundEndpoints |= HID_FOUND_DATAPIPE_OUT; + } + } + + HIDInterfaceInfo->State.LargestReportSize = 8; + HIDInterfaceInfo->State.IsActive = true; + return HID_ENUMERROR_NoError; +} + +static uint8_t DComp_HID_Host_NextHIDInterface(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Interface_t); + + if (CurrentInterface->Class == HID_INTERFACE_CLASS) + return DESCRIPTOR_SEARCH_Found; + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +static uint8_t DComp_NextHID(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_HID) + return DESCRIPTOR_SEARCH_Found; + else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + return DESCRIPTOR_SEARCH_Fail; + else + return DESCRIPTOR_SEARCH_NotFound; +} + +static uint8_t DComp_HID_Host_NextHIDInterfaceEndpoint(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint) + { + USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Endpoint_t); + + if (!(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress))) + return DESCRIPTOR_SEARCH_Found; + } + else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + return DESCRIPTOR_SEARCH_Fail; + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) +uint8_t HID_Host_ReceiveReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, const uint8_t ReportID, void* Buffer) +{ + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_SetReport, + .wValue = ((REPORT_ITEM_TYPE_In + 1) << 8) | ReportID, + .wIndex = HIDInterfaceInfo->State.InterfaceNumber, + .wLength = USB_GetHIDReportSize(HIDInterfaceInfo->Config.HIDParserData, ReportID, REPORT_ITEM_TYPE_In), + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + return USB_Host_SendControlRequest(Buffer); +} +#endif + +uint8_t HID_Host_ReceiveReport(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, void* Buffer) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive)) + return PIPE_READYWAIT_DeviceDisconnected; + + uint8_t ErrorCode; + + Pipe_SelectPipe(HIDInterfaceInfo->Config.DataINPipeNumber); + Pipe_Unfreeze(); + + uint16_t ReportSize; + uint8_t* BufferPos = Buffer; + +#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) + if (!(HIDInterfaceInfo->State.UsingBootProtocol)) + { + uint8_t ReportID = 0; + + if (HIDInterfaceInfo->Config.HIDParserData->UsingReportIDs) + { + ReportID = Pipe_Read_Byte(); + *(BufferPos++) = ReportID; + } + + ReportSize = USB_GetHIDReportSize(HIDInterfaceInfo->Config.HIDParserData, ReportID, REPORT_ITEM_TYPE_In); + } + else +#endif + { + ReportSize = Pipe_BytesInPipe(); + } + + if ((ErrorCode = Pipe_Read_Stream_LE(BufferPos, ReportSize, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + Pipe_ClearIN(); + Pipe_Freeze(); + + return PIPE_RWSTREAM_NoError; +} + +uint8_t HID_Host_SendReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, +#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) + const uint8_t ReportID, +#endif + void* Buffer, const uint16_t ReportSize) +{ +#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) + if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive)) + return false; + + if (HIDInterfaceInfo->State.DeviceUsesOUTPipe) + { + uint8_t ErrorCode; + + Pipe_SelectPipe(HIDInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_Unfreeze(); + + if (ReportID) + Pipe_Write_Stream_LE(&ReportID, sizeof(ReportID), NO_STREAM_CALLBACK); + + if ((ErrorCode = Pipe_Write_Stream_LE(Buffer, ReportSize, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + Pipe_ClearOUT(); + Pipe_Freeze(); + + return PIPE_RWSTREAM_NoError; + } + else +#endif + { + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_SetReport, +#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) + .wValue = ((REPORT_ITEM_TYPE_Out + 1) << 8) | ReportID, +#else + .wValue = ((REPORT_ITEM_TYPE_Out + 1) << 8), +#endif + .wIndex = HIDInterfaceInfo->State.InterfaceNumber, + .wLength = ReportSize, + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + return USB_Host_SendControlRequest(Buffer); + } +} + +bool HID_Host_IsReportReceived(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive)) + return false; + + bool ReportReceived; + + Pipe_SelectPipe(HIDInterfaceInfo->Config.DataINPipeNumber); + Pipe_Unfreeze(); + + ReportReceived = Pipe_IsINReceived(); + + Pipe_Freeze(); + + return ReportReceived; +} + +uint8_t HID_Host_SetBootProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) +{ + uint8_t ErrorCode; + + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_SetProtocol, + .wValue = 0, + .wIndex = HIDInterfaceInfo->State.InterfaceNumber, + .wLength = 0, + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + if (!(HIDInterfaceInfo->State.SupportsBootProtocol)) + return HID_ERROR_LOGICAL; + + if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful) + return ErrorCode; + + HIDInterfaceInfo->State.LargestReportSize = 8; + HIDInterfaceInfo->State.UsingBootProtocol = true; + + return HOST_SENDCONTROL_Successful; +} + +#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) +uint8_t HID_Host_SetReportProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) +{ + uint8_t ErrorCode; + + uint8_t HIDReportData[HIDInterfaceInfo->State.HIDReportSize]; + + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_INTERFACE), + .bRequest = REQ_GetDescriptor, + .wValue = (DTYPE_Report << 8), + .wIndex = HIDInterfaceInfo->State.InterfaceNumber, + .wLength = HIDInterfaceInfo->State.HIDReportSize, + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + if ((ErrorCode = USB_Host_SendControlRequest(HIDReportData)) != HOST_SENDCONTROL_Successful) + return ErrorCode; + + if (HIDInterfaceInfo->State.UsingBootProtocol) + { + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_SetProtocol, + .wValue = 1, + .wIndex = HIDInterfaceInfo->State.InterfaceNumber, + .wLength = 0, + }; + + if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful) + return ErrorCode; + + HIDInterfaceInfo->State.UsingBootProtocol = false; + } + + if (HIDInterfaceInfo->Config.HIDParserData == NULL) + return HID_ERROR_LOGICAL; + + if ((ErrorCode = USB_ProcessHIDReport(HIDReportData, HIDInterfaceInfo->State.HIDReportSize, + HIDInterfaceInfo->Config.HIDParserData)) != HID_PARSE_Successful) + { + return HID_ERROR_LOGICAL | ErrorCode; + } + + uint8_t LargestReportSizeBits = HIDInterfaceInfo->Config.HIDParserData->LargestReportSizeBits; + HIDInterfaceInfo->State.LargestReportSize = (LargestReportSizeBits >> 3) + ((LargestReportSizeBits & 0x07) != 0); + + return 0; +} +#endif + +#endif diff --git a/LUFA/Drivers/USB/Class/Host/HID.h b/LUFA/Drivers/USB/Class/Host/HID.h index 9c0400640..1291bd2cf 100644 --- a/LUFA/Drivers/USB/Class/Host/HID.h +++ b/LUFA/Drivers/USB/Class/Host/HID.h @@ -1,312 +1,312 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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
- * \brief Host mode driver for the library USB HID Class driver.
- *
- * Host mode driver for the library USB HID Class driver.
- *
- * \note This file should not be included directly. It is automatically included as needed by the class driver
- * dispatch header located in LUFA/Drivers/USB/Class/HID.h.
- */
-
-/** \ingroup Group_USBClassHID
- * @defgroup Group_USBClassHIDHost HID Class Host Mode Driver
- *
- * \section Sec_Dependencies Module Source Dependencies
- * The following files must be built with any user project that uses this module:
- * - LUFA/Drivers/USB/Class/Host/HID.c
- * - LUFA/Drivers/USB/Class/Host/HIDParser.c
- *
- * \section Module Description
- * Host Mode USB Class driver framework interface, for the HID USB Class driver.
- *
- * @{
- */
-
-#ifndef __HID_CLASS_HOST_H__
-#define __HID_CLASS_HOST_H__
-
- /* Includes: */
- #include "../../USB.h"
- #include "../Common/HID.h"
- #include "HIDParser.h"
-
- /* Enable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- extern "C" {
- #endif
-
- /* Preprocessor Checks: */
- #if !defined(__INCLUDE_FROM_HID_DRIVER)
- #error Do not include this file directly. Include LUFA/Drivers/Class/HID.h instead.
- #endif
-
- /* Public Interface - May be used in end-application: */
- /* Macros: */
- /** Error code for some HID Host functions, indicating a logical (and not hardware) error */
- #define HID_ERROR_LOGICAL 0x80
-
- /* Type Defines: */
- /** \brief HID Class Host Mode Configuration and State Structure.
- *
- * Class state structure. An instance of this structure should be made within the user application,
- * and passed to each of the HID class driver functions as the HIDInterfaceInfo parameter. This
- * stores each HID interface's configuration and state information.
- */
- typedef struct
- {
- const struct
- {
- uint8_t DataINPipeNumber; /**< Pipe number of the HID interface's IN data pipe */
- bool DataINPipeDoubleBank; /** Indicates if the HID interface's IN data pipe should use double banking */
-
- uint8_t DataOUTPipeNumber; /**< Pipe number of the HID interface's OUT data pipe */
- bool DataOUTPipeDoubleBank; /** Indicates if the HID interface's OUT data pipe should use double banking */
-
- uint8_t HIDInterfaceProtocol; /**< HID interface protocol value to match against if a specific
- * boot subclass protocol is required, either \ref HID_BOOT_MOUSE_PROTOCOL,
- * \ref HID_BOOT_KEYBOARD_PROTOCOL or \ref HID_NON_BOOT_PROTOCOL if any
- * HID device should be enumerated by the interface
- */
- #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
- HID_ReportInfo_t* HIDParserData; /**< HID parser data to store the parsed HID report data, when boot protocol
- * is not used
- *
- * \note When the HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined,
- * this method is unavailable.
- */
- #endif
- } Config; /**< Config data for the USB class interface within the device. All elements in this section
- * <b>must</b> be set or the interface will fail to enumerate and operate correctly.
- */
- struct
- {
- bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
- * after \ref HID_Host_ConfigurePipes() is called and the Host state machine is in the
- * Configured state
- */
- uint8_t InterfaceNumber; /**< Interface index of the HID interface within the attached device */
-
- uint16_t DataINPipeSize; /**< Size in bytes of the HID interface's IN data pipe */
- uint16_t DataOUTPipeSize; /**< Size in bytes of the HID interface's OUT data pipe */
-
- bool SupportsBootProtocol; /**< Indicates if the current interface instance supports the HID Boot
- * Protocol when enabled via \ref HID_Host_SetBootProtocol()
- */
- bool DeviceUsesOUTPipe; /**< Indicates if the current interface instance uses a separate OUT data pipe for
- * OUT reports, or if OUT reports are sent via the control pipe instead.
- */
- bool UsingBootProtocol; /**< Indicates that the interface is currently initialized in Boot Protocol mode */
- uint16_t HIDReportSize; /**< Size in bytes of the HID report descriptor in the device */
-
- uint8_t LargestReportSize; /**< Largest report the device will send, in bytes */
- } State; /**< State data for the USB class interface within the device. All elements in this section
- * <b>may</b> be set to initial values, but may also be ignored to default to sane values when
- * the interface is enumerated.
- */
- } USB_ClassInfo_HID_Host_t;
-
- /* Enums: */
- /** Enum for the possible error codes returned by the \ref HID_Host_ConfigurePipes() function. */
- enum HIDHost_EnumerationFailure_ErrorCodes_t
- {
- HID_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */
- HID_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */
- HID_ENUMERROR_NoHIDInterfaceFound = 2, /**< A compatible HID interface was not found in the device's Configuration Descriptor */
- HID_ENUMERROR_NoHIDDescriptorFound = 3, /**< The HID descriptor was not found in the device's HID interface */
- HID_ENUMERROR_EndpointsNotFound = 4, /**< Compatible HID endpoints were not found in the device's HID interface */
- };
-
- /* Function Prototypes: */
- /** Host interface configuration routine, to configure a given HID host interface instance using the Configuration
- * Descriptor read from an attached USB device. This function automatically updates the given HID Host instance's
- * state values and configures the pipes required to communicate with the interface if it is found within the
- * device. This should be called once after the stack has enumerated the attached device, while the host state
- * machine is in the Addressed state.
- *
- * \note Once the device pipes are configured, the HID device's reporting protocol <b>must</b> be set via a call
- * to either the \ref HID_Host_SetBootProtocol() or \ref HID_Host_SetReportProtocol() function.
- *
- * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state
- * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor
- * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor
- *
- * \return A value from the \ref HIDHost_EnumerationFailure_ErrorCodes_t enum
- */
- uint8_t HID_Host_ConfigurePipes(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
-
-
- /** Receives a HID IN report from the attached HID device, when a report has been received on the HID IN Data pipe.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- * \n\n
- *
- * \note The destination buffer should be large enough to accommodate the largest report that the attached device
- * can generate.
- *
- * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state
- * \param[in] Buffer Buffer to store the received report into
- *
- * \return An error code from the \ref Pipe_Stream_RW_ErrorCodes_t enum
- */
- uint8_t HID_Host_ReceiveReport(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, void* Buffer)
- ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
-
- #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
- /** Receives a HID IN report from the attached device, by the report ID.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- * \n\n
- *
- * \note When the HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined, this method is unavailable.
- *
- * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state
- * \param[in] ReportID Report ID of the received report if ControlRequest is false, set by the to the Report ID to fetch
- * \param[in] Buffer Buffer to store the received report into
- *
- * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum
- */
- uint8_t HID_Host_ReceiveReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, const uint8_t ReportID,
- void* Buffer) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
- #endif
-
- /** Sends an OUT report to the currently attached HID device, using the device's OUT pipe if available or the device's
- * Control pipe if not.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- * \n\n
- *
- * \note When the HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined, the ReportID parameter is removed
- * from the parameter list of this function.
- *
- * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state
- * \param[in] ReportID Report ID of the report to send to the device, or 0 if the device does not use report IDs
- * \param[in] Buffer Buffer containing the report to send to the attached device
- * \param[in] ReportSize Report size in bytes to send to the attached device
- *
- * \return An error code from the \ref USB_Host_SendControlErrorCodes_t enum if the DeviceUsesOUTPipe flag is set in
- * the interface's state structure, a value from the \ref Pipe_Stream_RW_ErrorCodes_t enum otherwise
- */
- uint8_t HID_Host_SendReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,
- #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
- const uint8_t ReportID,
- #endif
- void* Buffer, const uint16_t ReportSize) ATTR_NON_NULL_PTR_ARG(1)
- #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
- ATTR_NON_NULL_PTR_ARG(3);
- #else
- ATTR_NON_NULL_PTR_ARG(2);
- #endif
-
- /** Determines if a HID IN report has been received from the attached device on the data IN pipe.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state
- *
- * \return Boolean true if a report has been received, false otherwise
- */
- bool HID_Host_IsReportReceived(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Switches the attached HID device's reporting protocol over to the Boot Report protocol mode, on supported devices.
- *
- * \note When the HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined, this method must still be called
- * to explicitly place the attached device into boot protocol mode before use.
- *
- * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state
- *
- * \return \ref HID_ERROR_LOGICAL if the device does not support Boot Protocol mode, a value from the
- * \ref USB_Host_SendControlErrorCodes_t enum otherwise
- */
- uint8_t HID_Host_SetBootProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
- /** Switches the attached HID device's reporting protocol over to the standard Report protocol mode. This also retrieves
- * and parses the device's HID report descriptor, so that the size of each report can be determined in advance.
- *
- * \note Whether this function is used or not, the \ref CALLBACK_HIDParser_FilterHIDReportItem() callback from the HID
- * Report Parser this function references <b>must</b> be implemented in the user code.
- * \n\n
- *
- * \note When the HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined, this method is unavailable.
- *
- * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state
- *
- * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum if an error occurs while retrieving the HID
- * Report descriptor or the setting of the Report protocol, \ref HID_ERROR_LOGICAL if the HID interface does
- * not have a valid \ref HID_ReportInfo_t structure set in its configuration, a mask of \ref HID_ERROR_LOGICAL
- * and a value from the \ref HID_Parse_ErrorCodes_t otherwise
- */
- uint8_t HID_Host_SetReportProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
- #endif
-
- /* Inline Functions: */
- /** General management task for a given Human Interface Class host class interface, required for the correct operation of
- * the interface. This should be called frequently in the main program loop, before the master USB management task
- * \ref USB_USBTask().
- *
- * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state
- */
- static inline void HID_Host_USBTask(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo);
- static inline void HID_Host_USBTask(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo)
- {
- (void)HIDInterfaceInfo;
- }
-
- /* Private Interface - For use in library only: */
- #if !defined(__DOXYGEN__)
- /* Macros: */
- #define HID_INTERFACE_CLASS 0x03
-
- #define HID_FOUND_DATAPIPE_IN (1 << 0)
- #define HID_FOUND_DATAPIPE_OUT (1 << 1)
-
- /* Function Prototypes: */
- #if defined(__INCLUDE_FROM_HID_CLASS_HOST_C)
- static uint8_t DComp_HID_Host_NextHIDInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1);
- static uint8_t DComp_NextHID(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1);
- static uint8_t DComp_HID_Host_NextHIDInterfaceEndpoint(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1);
- #endif
- #endif
-
- /* Disable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- }
- #endif
-
-#endif
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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 + * \brief Host mode driver for the library USB HID Class driver. + * + * Host mode driver for the library USB HID Class driver. + * + * \note This file should not be included directly. It is automatically included as needed by the class driver + * dispatch header located in LUFA/Drivers/USB/Class/HID.h. + */ + +/** \ingroup Group_USBClassHID + * @defgroup Group_USBClassHIDHost HID Class Host Mode Driver + * + * \section Sec_Dependencies Module Source Dependencies + * The following files must be built with any user project that uses this module: + * - LUFA/Drivers/USB/Class/Host/HID.c + * - LUFA/Drivers/USB/Class/Host/HIDParser.c + * + * \section Module Description + * Host Mode USB Class driver framework interface, for the HID USB Class driver. + * + * @{ + */ + +#ifndef __HID_CLASS_HOST_H__ +#define __HID_CLASS_HOST_H__ + + /* Includes: */ + #include "../../USB.h" + #include "../Common/HID.h" + #include "HIDParser.h" + + /* Enable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + extern "C" { + #endif + + /* Preprocessor Checks: */ + #if !defined(__INCLUDE_FROM_HID_DRIVER) + #error Do not include this file directly. Include LUFA/Drivers/Class/HID.h instead. + #endif + + /* Public Interface - May be used in end-application: */ + /* Macros: */ + /** Error code for some HID Host functions, indicating a logical (and not hardware) error */ + #define HID_ERROR_LOGICAL 0x80 + + /* Type Defines: */ + /** \brief HID Class Host Mode Configuration and State Structure. + * + * Class state structure. An instance of this structure should be made within the user application, + * and passed to each of the HID class driver functions as the HIDInterfaceInfo parameter. This + * stores each HID interface's configuration and state information. + */ + typedef struct + { + const struct + { + uint8_t DataINPipeNumber; /**< Pipe number of the HID interface's IN data pipe */ + bool DataINPipeDoubleBank; /** Indicates if the HID interface's IN data pipe should use double banking */ + + uint8_t DataOUTPipeNumber; /**< Pipe number of the HID interface's OUT data pipe */ + bool DataOUTPipeDoubleBank; /** Indicates if the HID interface's OUT data pipe should use double banking */ + + uint8_t HIDInterfaceProtocol; /**< HID interface protocol value to match against if a specific + * boot subclass protocol is required, either \ref HID_BOOT_MOUSE_PROTOCOL, + * \ref HID_BOOT_KEYBOARD_PROTOCOL or \ref HID_NON_BOOT_PROTOCOL if any + * HID device should be enumerated by the interface + */ + #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) + HID_ReportInfo_t* HIDParserData; /**< HID parser data to store the parsed HID report data, when boot protocol + * is not used + * + * \note When the HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined, + * this method is unavailable. + */ + #endif + } Config; /**< Config data for the USB class interface within the device. All elements in this section + * <b>must</b> be set or the interface will fail to enumerate and operate correctly. + */ + struct + { + bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid + * after \ref HID_Host_ConfigurePipes() is called and the Host state machine is in the + * Configured state + */ + uint8_t InterfaceNumber; /**< Interface index of the HID interface within the attached device */ + + uint16_t DataINPipeSize; /**< Size in bytes of the HID interface's IN data pipe */ + uint16_t DataOUTPipeSize; /**< Size in bytes of the HID interface's OUT data pipe */ + + bool SupportsBootProtocol; /**< Indicates if the current interface instance supports the HID Boot + * Protocol when enabled via \ref HID_Host_SetBootProtocol() + */ + bool DeviceUsesOUTPipe; /**< Indicates if the current interface instance uses a separate OUT data pipe for + * OUT reports, or if OUT reports are sent via the control pipe instead. + */ + bool UsingBootProtocol; /**< Indicates that the interface is currently initialized in Boot Protocol mode */ + uint16_t HIDReportSize; /**< Size in bytes of the HID report descriptor in the device */ + + uint8_t LargestReportSize; /**< Largest report the device will send, in bytes */ + } State; /**< State data for the USB class interface within the device. All elements in this section + * <b>may</b> be set to initial values, but may also be ignored to default to sane values when + * the interface is enumerated. + */ + } USB_ClassInfo_HID_Host_t; + + /* Enums: */ + /** Enum for the possible error codes returned by the \ref HID_Host_ConfigurePipes() function. */ + enum HIDHost_EnumerationFailure_ErrorCodes_t + { + HID_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */ + HID_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */ + HID_ENUMERROR_NoHIDInterfaceFound = 2, /**< A compatible HID interface was not found in the device's Configuration Descriptor */ + HID_ENUMERROR_NoHIDDescriptorFound = 3, /**< The HID descriptor was not found in the device's HID interface */ + HID_ENUMERROR_EndpointsNotFound = 4, /**< Compatible HID endpoints were not found in the device's HID interface */ + }; + + /* Function Prototypes: */ + /** Host interface configuration routine, to configure a given HID host interface instance using the Configuration + * Descriptor read from an attached USB device. This function automatically updates the given HID Host instance's + * state values and configures the pipes required to communicate with the interface if it is found within the + * device. This should be called once after the stack has enumerated the attached device, while the host state + * machine is in the Addressed state. + * + * \note Once the device pipes are configured, the HID device's reporting protocol <b>must</b> be set via a call + * to either the \ref HID_Host_SetBootProtocol() or \ref HID_Host_SetReportProtocol() function. + * + * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state + * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor + * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor + * + * \return A value from the \ref HIDHost_EnumerationFailure_ErrorCodes_t enum + */ + uint8_t HID_Host_ConfigurePipes(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, uint16_t ConfigDescriptorSize, + void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3); + + + /** Receives a HID IN report from the attached HID device, when a report has been received on the HID IN Data pipe. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * \n\n + * + * \note The destination buffer should be large enough to accommodate the largest report that the attached device + * can generate. + * + * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state + * \param[in] Buffer Buffer to store the received report into + * + * \return An error code from the \ref Pipe_Stream_RW_ErrorCodes_t enum + */ + uint8_t HID_Host_ReceiveReport(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, void* Buffer) + ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + + #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) + /** Receives a HID IN report from the attached device, by the report ID. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * \n\n + * + * \note When the HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined, this method is unavailable. + * + * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state + * \param[in] ReportID Report ID of the received report if ControlRequest is false, set by the to the Report ID to fetch + * \param[in] Buffer Buffer to store the received report into + * + * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum + */ + uint8_t HID_Host_ReceiveReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, const uint8_t ReportID, + void* Buffer) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3); + #endif + + /** Sends an OUT report to the currently attached HID device, using the device's OUT pipe if available or the device's + * Control pipe if not. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * \n\n + * + * \note When the HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined, the ReportID parameter is removed + * from the parameter list of this function. + * + * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state + * \param[in] ReportID Report ID of the report to send to the device, or 0 if the device does not use report IDs + * \param[in] Buffer Buffer containing the report to send to the attached device + * \param[in] ReportSize Report size in bytes to send to the attached device + * + * \return An error code from the \ref USB_Host_SendControlErrorCodes_t enum if the DeviceUsesOUTPipe flag is set in + * the interface's state structure, a value from the \ref Pipe_Stream_RW_ErrorCodes_t enum otherwise + */ + uint8_t HID_Host_SendReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo, + #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) + const uint8_t ReportID, + #endif + void* Buffer, const uint16_t ReportSize) ATTR_NON_NULL_PTR_ARG(1) + #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) + ATTR_NON_NULL_PTR_ARG(3); + #else + ATTR_NON_NULL_PTR_ARG(2); + #endif + + /** Determines if a HID IN report has been received from the attached device on the data IN pipe. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state + * + * \return Boolean true if a report has been received, false otherwise + */ + bool HID_Host_IsReportReceived(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Switches the attached HID device's reporting protocol over to the Boot Report protocol mode, on supported devices. + * + * \note When the HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined, this method must still be called + * to explicitly place the attached device into boot protocol mode before use. + * + * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state + * + * \return \ref HID_ERROR_LOGICAL if the device does not support Boot Protocol mode, a value from the + * \ref USB_Host_SendControlErrorCodes_t enum otherwise + */ + uint8_t HID_Host_SetBootProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) + /** Switches the attached HID device's reporting protocol over to the standard Report protocol mode. This also retrieves + * and parses the device's HID report descriptor, so that the size of each report can be determined in advance. + * + * \note Whether this function is used or not, the \ref CALLBACK_HIDParser_FilterHIDReportItem() callback from the HID + * Report Parser this function references <b>must</b> be implemented in the user code. + * \n\n + * + * \note When the HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined, this method is unavailable. + * + * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state + * + * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum if an error occurs while retrieving the HID + * Report descriptor or the setting of the Report protocol, \ref HID_ERROR_LOGICAL if the HID interface does + * not have a valid \ref HID_ReportInfo_t structure set in its configuration, a mask of \ref HID_ERROR_LOGICAL + * and a value from the \ref HID_Parse_ErrorCodes_t otherwise + */ + uint8_t HID_Host_SetReportProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + #endif + + /* Inline Functions: */ + /** General management task for a given Human Interface Class host class interface, required for the correct operation of + * the interface. This should be called frequently in the main program loop, before the master USB management task + * \ref USB_USBTask(). + * + * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state + */ + static inline void HID_Host_USBTask(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo); + static inline void HID_Host_USBTask(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) + { + (void)HIDInterfaceInfo; + } + + /* Private Interface - For use in library only: */ + #if !defined(__DOXYGEN__) + /* Macros: */ + #define HID_INTERFACE_CLASS 0x03 + + #define HID_FOUND_DATAPIPE_IN (1 << 0) + #define HID_FOUND_DATAPIPE_OUT (1 << 1) + + /* Function Prototypes: */ + #if defined(__INCLUDE_FROM_HID_CLASS_HOST_C) + static uint8_t DComp_HID_Host_NextHIDInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1); + static uint8_t DComp_NextHID(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1); + static uint8_t DComp_HID_Host_NextHIDInterfaceEndpoint(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1); + #endif + #endif + + /* Disable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + } + #endif + +#endif + +/** @} */ diff --git a/LUFA/Drivers/USB/Class/Host/HIDParser.c b/LUFA/Drivers/USB/Class/Host/HIDParser.c index 386c3b937..7116ed866 100644 --- a/LUFA/Drivers/USB/Class/Host/HIDParser.c +++ b/LUFA/Drivers/USB/Class/Host/HIDParser.c @@ -1,353 +1,353 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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_USB_DRIVER
-#include "../../HighLevel/USBMode.h"
-#if defined(USB_CAN_BE_HOST)
-
-#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];
- HID_CollectionPath_t* CurrCollectionPath = NULL;
- HID_ReportSizeInfo_t* CurrReportIDInfo = &ParserData->ReportIDSizes[0];
- uint16_t UsageList[HID_USAGE_STACK_DEPTH];
- uint8_t UsageListSize = 0;
- HID_MinMax_t UsageMinMax = {0, 0};
-
- memset(ParserData, 0x00, sizeof(HID_ReportInfo_t));
- memset(CurrStateTable, 0x00, sizeof(HID_StateTable_t));
- memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
-
- ParserData->TotalDeviceReports = 1;
-
- while (ReportSize)
- {
- uint8_t HIDReportItem = *ReportData;
- uint32_t ReportItemData = 0;
-
- ReportData++;
- ReportSize--;
-
- switch (HIDReportItem & DATA_SIZE_MASK)
- {
- case DATA_SIZE_4:
- ReportItemData = *((uint32_t*)ReportData);
- ReportSize -= 4;
- ReportData += 4;
- break;
- case DATA_SIZE_2:
- ReportItemData = *((uint16_t*)ReportData);
- ReportSize -= 2;
- ReportData += 2;
- break;
- case DATA_SIZE_1:
- ReportItemData = *((uint8_t*)ReportData);
- ReportSize -= 1;
- ReportData += 1;
- break;
- }
-
- switch (HIDReportItem & (TYPE_MASK | TAG_MASK))
- {
- case (TYPE_GLOBAL | TAG_GLOBAL_PUSH):
- if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1])
- 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;
-
- if (ParserData->UsingReportIDs)
- {
- CurrReportIDInfo = NULL;
-
- for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++)
- {
- if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID)
- {
- CurrReportIDInfo = &ParserData->ReportIDSizes[i];
- break;
- }
- }
-
- if (CurrReportIDInfo == NULL)
- {
- if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS)
- return HID_PARSE_InsufficientReportIDItems;
-
- CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++];
- memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
- }
- }
-
- ParserData->UsingReportIDs = true;
-
- CurrReportIDInfo->ReportID = CurrStateTable->ReportID;
- break;
- case (TYPE_LOCAL | TAG_LOCAL_USAGE):
- if (UsageListSize == HID_USAGE_STACK_DEPTH)
- return HID_PARSE_UsageListOverflow;
-
- UsageList[UsageListSize++] = ReportItemData;
- break;
- case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN):
- UsageMinMax.Minimum = ReportItemData;
- break;
- case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX):
- UsageMinMax.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 - 1])
- return HID_PARSE_InsufficientCollectionPaths;
-
- CurrCollectionPath++;
- }
-
- CurrCollectionPath->Parent = ParentCollectionPath;
- }
-
- CurrCollectionPath->Type = ReportItemData;
- CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page;
-
- if (UsageListSize)
- {
- CurrCollectionPath->Usage.Usage = UsageList[0];
-
- for (uint8_t i = 0; i < UsageListSize; i++)
- UsageList[i] = UsageList[i + 1];
-
- UsageListSize--;
- }
- else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
- {
- CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++;
- }
-
- 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):
- case (TYPE_MAIN | TAG_MAIN_FEATURE):
- for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++)
- {
- HID_ReportItem_t NewReportItem;
-
- memcpy(&NewReportItem.Attributes,
- &CurrStateTable->Attributes,
- sizeof(HID_ReportItem_Attributes_t));
-
- NewReportItem.ItemFlags = ReportItemData;
- NewReportItem.CollectionPath = CurrCollectionPath;
- NewReportItem.ReportID = CurrStateTable->ReportID;
-
- if (UsageListSize)
- {
- NewReportItem.Attributes.Usage.Usage = UsageList[0];
-
- for (uint8_t i = 0; i < UsageListSize; i++)
- UsageList[i] = UsageList[i + 1];
-
- UsageListSize--;
- }
- else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
- {
- NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++;
- }
-
- uint8_t ItemTag = (HIDReportItem & TAG_MASK);
-
- if (ItemTag == TAG_MAIN_INPUT)
- NewReportItem.ItemType = REPORT_ITEM_TYPE_In;
- else if (ItemTag == TAG_MAIN_OUTPUT)
- NewReportItem.ItemType = REPORT_ITEM_TYPE_Out;
- else
- NewReportItem.ItemType = REPORT_ITEM_TYPE_Feature;
-
- NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType];
-
- CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize;
-
- if (ParserData->LargestReportSizeBits < NewReportItem.BitOffset)
- ParserData->LargestReportSizeBits = NewReportItem.BitOffset;
-
- if (!(ReportItemData & IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem))
- {
- if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS)
- return HID_PARSE_InsufficientReportItems;
-
- memcpy(&ParserData->ReportItems[ParserData->TotalReportItems],
- &NewReportItem, sizeof(HID_ReportItem_t));
-
- ParserData->TotalReportItems++;
- }
- }
-
- break;
- }
-
- if ((HIDReportItem & TYPE_MASK) == TYPE_MAIN)
- {
- UsageMinMax.Minimum = 0;
- UsageMinMax.Maximum = 0;
- UsageListSize = 0;
- }
- }
-
- if (!(ParserData->TotalReportItems))
- return HID_PARSE_NoUnfilteredReportItems;
-
- 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->PreviousValue = ReportItem->Value;
- 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, HID_ReportItem_t* const 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++;
- }
-
- ReportItem->PreviousValue = ReportItem->Value;
-
- while (DataBitsRem--)
- {
- if (ReportItem->Value & (1 << (CurrentBit % 8)))
- ReportData[CurrentBit / 8] |= BitMask;
-
- CurrentBit++;
- BitMask <<= 1;
- }
-}
-
-uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData, const uint8_t ReportID, const uint8_t ReportType)
-{
- for (uint8_t i = 0; i < HID_MAX_REPORT_IDS; i++)
- {
- uint16_t ReportSizeBits = ParserData->ReportIDSizes[i].ReportSizeBits[ReportType];
-
- if (ParserData->ReportIDSizes[i].ReportID == ReportID)
- return ((ReportSizeBits >> 3) + ((ReportSizeBits & 0x07) ? 1 : 0));
- }
-
- return 0;
-}
-
-#endif
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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_USB_DRIVER +#include "../../HighLevel/USBMode.h" +#if defined(USB_CAN_BE_HOST) + +#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]; + HID_CollectionPath_t* CurrCollectionPath = NULL; + HID_ReportSizeInfo_t* CurrReportIDInfo = &ParserData->ReportIDSizes[0]; + uint16_t UsageList[HID_USAGE_STACK_DEPTH]; + uint8_t UsageListSize = 0; + HID_MinMax_t UsageMinMax = {0, 0}; + + memset(ParserData, 0x00, sizeof(HID_ReportInfo_t)); + memset(CurrStateTable, 0x00, sizeof(HID_StateTable_t)); + memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t)); + + ParserData->TotalDeviceReports = 1; + + while (ReportSize) + { + uint8_t HIDReportItem = *ReportData; + uint32_t ReportItemData = 0; + + ReportData++; + ReportSize--; + + switch (HIDReportItem & DATA_SIZE_MASK) + { + case DATA_SIZE_4: + ReportItemData = *((uint32_t*)ReportData); + ReportSize -= 4; + ReportData += 4; + break; + case DATA_SIZE_2: + ReportItemData = *((uint16_t*)ReportData); + ReportSize -= 2; + ReportData += 2; + break; + case DATA_SIZE_1: + ReportItemData = *((uint8_t*)ReportData); + ReportSize -= 1; + ReportData += 1; + break; + } + + switch (HIDReportItem & (TYPE_MASK | TAG_MASK)) + { + case (TYPE_GLOBAL | TAG_GLOBAL_PUSH): + if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1]) + 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; + + if (ParserData->UsingReportIDs) + { + CurrReportIDInfo = NULL; + + for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++) + { + if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID) + { + CurrReportIDInfo = &ParserData->ReportIDSizes[i]; + break; + } + } + + if (CurrReportIDInfo == NULL) + { + if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS) + return HID_PARSE_InsufficientReportIDItems; + + CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++]; + memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t)); + } + } + + ParserData->UsingReportIDs = true; + + CurrReportIDInfo->ReportID = CurrStateTable->ReportID; + break; + case (TYPE_LOCAL | TAG_LOCAL_USAGE): + if (UsageListSize == HID_USAGE_STACK_DEPTH) + return HID_PARSE_UsageListOverflow; + + UsageList[UsageListSize++] = ReportItemData; + break; + case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN): + UsageMinMax.Minimum = ReportItemData; + break; + case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX): + UsageMinMax.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 - 1]) + return HID_PARSE_InsufficientCollectionPaths; + + CurrCollectionPath++; + } + + CurrCollectionPath->Parent = ParentCollectionPath; + } + + CurrCollectionPath->Type = ReportItemData; + CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page; + + if (UsageListSize) + { + CurrCollectionPath->Usage.Usage = UsageList[0]; + + for (uint8_t i = 0; i < UsageListSize; i++) + UsageList[i] = UsageList[i + 1]; + + UsageListSize--; + } + else if (UsageMinMax.Minimum <= UsageMinMax.Maximum) + { + CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++; + } + + 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): + case (TYPE_MAIN | TAG_MAIN_FEATURE): + for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++) + { + HID_ReportItem_t NewReportItem; + + memcpy(&NewReportItem.Attributes, + &CurrStateTable->Attributes, + sizeof(HID_ReportItem_Attributes_t)); + + NewReportItem.ItemFlags = ReportItemData; + NewReportItem.CollectionPath = CurrCollectionPath; + NewReportItem.ReportID = CurrStateTable->ReportID; + + if (UsageListSize) + { + NewReportItem.Attributes.Usage.Usage = UsageList[0]; + + for (uint8_t i = 0; i < UsageListSize; i++) + UsageList[i] = UsageList[i + 1]; + + UsageListSize--; + } + else if (UsageMinMax.Minimum <= UsageMinMax.Maximum) + { + NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++; + } + + uint8_t ItemTag = (HIDReportItem & TAG_MASK); + + if (ItemTag == TAG_MAIN_INPUT) + NewReportItem.ItemType = REPORT_ITEM_TYPE_In; + else if (ItemTag == TAG_MAIN_OUTPUT) + NewReportItem.ItemType = REPORT_ITEM_TYPE_Out; + else + NewReportItem.ItemType = REPORT_ITEM_TYPE_Feature; + + NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType]; + + CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize; + + if (ParserData->LargestReportSizeBits < NewReportItem.BitOffset) + ParserData->LargestReportSizeBits = NewReportItem.BitOffset; + + if (!(ReportItemData & IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem)) + { + if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS) + return HID_PARSE_InsufficientReportItems; + + memcpy(&ParserData->ReportItems[ParserData->TotalReportItems], + &NewReportItem, sizeof(HID_ReportItem_t)); + + ParserData->TotalReportItems++; + } + } + + break; + } + + if ((HIDReportItem & TYPE_MASK) == TYPE_MAIN) + { + UsageMinMax.Minimum = 0; + UsageMinMax.Maximum = 0; + UsageListSize = 0; + } + } + + if (!(ParserData->TotalReportItems)) + return HID_PARSE_NoUnfilteredReportItems; + + 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->PreviousValue = ReportItem->Value; + 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, HID_ReportItem_t* const 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++; + } + + ReportItem->PreviousValue = ReportItem->Value; + + while (DataBitsRem--) + { + if (ReportItem->Value & (1 << (CurrentBit % 8))) + ReportData[CurrentBit / 8] |= BitMask; + + CurrentBit++; + BitMask <<= 1; + } +} + +uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData, const uint8_t ReportID, const uint8_t ReportType) +{ + for (uint8_t i = 0; i < HID_MAX_REPORT_IDS; i++) + { + uint16_t ReportSizeBits = ParserData->ReportIDSizes[i].ReportSizeBits[ReportType]; + + if (ParserData->ReportIDSizes[i].ReportID == ReportID) + return ((ReportSizeBits >> 3) + ((ReportSizeBits & 0x07) ? 1 : 0)); + } + + return 0; +} + +#endif diff --git a/LUFA/Drivers/USB/Class/Host/HIDParser.h b/LUFA/Drivers/USB/Class/Host/HIDParser.h index 13f68a045..6630750e6 100644 --- a/LUFA/Drivers/USB/Class/Host/HIDParser.h +++ b/LUFA/Drivers/USB/Class/Host/HIDParser.h @@ -1,355 +1,355 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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
- * \brief USB Human Interface Device (HID) Class report descriptor parser.
- *
- * This file allows for the easy parsing of complex HID report descriptors, which describes the data that
- * a HID device transmits to the host. It also provides an easy API for extracting and processing the data
- * elements inside a HID report sent from an attached HID device.
- */
-
-/** \ingroup Group_USB
- * @defgroup Group_HIDParser HID Report Parser
- *
- * \section Sec_Dependencies Module Source Dependencies
- * The following files must be built with any user project that uses this module:
- * - LUFA/Drivers/USB/Class/Host/HIDParser.c
- *
- * \section Module Description
- * 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 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.
- *
- * @{
- */
-
-#ifndef __HIDPARSER_H__
-#define __HIDPARSER_H__
-
- /* Macros: */
- #define __INCLUDE_FROM_USB_DRIVER
- #define __INCLUDE_FROM_HID_DRIVER
-
- /* Includes: */
- #include <string.h>
- #include <stdbool.h>
-
- #include "HIDReportData.h"
- #include "../Common/HID.h"
-
- #include "../../../../Common/Common.h"
-
- /* Enable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- extern "C" {
- #endif
-
- /* Macros: */
- #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 2 levels (allowing non-nested PUSH items) 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 2
- #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 10
- #endif
-
- #if !defined(HID_MAX_REPORTITEMS) || defined(__DOXYGEN__)
- /** Constant indicating the maximum number of report items (IN, OUT or FEATURE) that can be processed
- * in the report item descriptor and stored in the user HID Report Info structure. A large value allows
- * for more report items to be stored, but consumes more memory. By default this is set to 20 items,
- * but this can be overridden by defining HID_MAX_REPORTITEMS to another value in the user project
- * makefile, and passing the define to the compiler using the -D compiler switch.
- */
- #define HID_MAX_REPORTITEMS 20
- #endif
-
- #if !defined(HID_MAX_REPORT_IDS) || defined(__DOXYGEN__)
- /** Constant indicating the maximum number of unique report IDs that can be processed in the report item
- * descriptor for the report size information array in the user HID Report Info structure. A large value
- * allows for more report ID report sizes to be stored, but consumes more memory. By default this is set
- * to 5 items, but this can be overridden by defining HID_MAX_REPORT_IDS to another value in the user project
- * makefile, and passing the define to the compiler using the -D compiler switch. Note that IN, OUT and FEATURE
- * items sharing the same report ID consume only one size item in the array.
- */
- #define HID_MAX_REPORT_IDS 10
- #endif
-
- /** Returns the value a given HID report item (once its value has been fetched via \ref USB_GetHIDReportItemInfo())
- * left-aligned to the given data type. This allows for signed data to be interpreted correctly, by shifting the data
- * leftwards until the data's sign bit is in the correct position.
- *
- * \param[in] reportitem HID Report Item whose retrieved value is to be aligned
- * \param[in] type Data type to align the HID report item's value to
- *
- * \return Left-aligned data of the given report item's pre-retrived value for the given datatype
- */
- #define HID_ALIGN_DATA(reportitem, type) ((type)(reportitem->Value << ((8 * sizeof(type)) - reportitem->Attributes.BitSize)))
-
- /* Public Interface - May be used in end-application: */
- /* Enums: */
- /** 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, /**< An END COLLECTION item found without matching COLLECTION item. */
- HID_PARSE_InsufficientCollectionPaths = 5, /**< More than \ref HID_MAX_COLLECTIONS collections in the report. */
- HID_PARSE_UsageListOverflow = 6, /**< More than \ref HID_USAGE_STACK_DEPTH usages listed in a row. */
- HID_PARSE_InsufficientReportIDItems = 7, /**< More than \ref HID_MAX_REPORT_IDS report IDs in the device. */
- HID_PARSE_NoUnfilteredReportItems = 8, /**< All report items from the device were filtered by the filtering callback routine. */
- };
-
- /* Type Defines: */
- /** \brief HID Parser Report Item Min/Max Structure.
- *
- * 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;
-
- /** \brief HID Parser Report Item Unit Structure.
- *
- * 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;
-
- /** \brief HID Parser Report Item Usage Structure.
- *
- * 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_Usage_t;
-
- /** \brief HID Parser Report Item Collection Path Structure.
- *
- * 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;
-
- /** \brief HID Parser Report Item Attributes Structure.
- *
- * 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;
-
- /** \brief HID Parser Report Item Details Structure.
- *
- * Type define for a report item (IN, OUT or FEATURE) layout 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_ReportItemTypes_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 - use \ref HID_ALIGN_DATA() when processing
- * a retrieved value so that it is aligned to a specific type.
- */
- uint32_t PreviousValue; /**< Previous value of the report item. */
- } HID_ReportItem_t;
-
- /** \brief HID Parser Report Size Structure.
- *
- * Type define for a report item size information structure, to retain the size of a device's reports by ID.
- */
- typedef struct
- {
- uint8_t ReportID; /** Report ID of the report within the HID interface */
- uint16_t ReportSizeBits[3]; /** Total number of bits in each report type for the given Report ID,
- * indexed by the \ref HID_ReportItemTypes_t enum
- */
- } HID_ReportSizeInfo_t;
-
- /** \brief HID Parser State Structure.
- *
- * 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.
- */
- uint8_t TotalDeviceReports; /**< Number of reports within the HID interface */
- HID_ReportSizeInfo_t ReportIDSizes[HID_MAX_REPORT_IDS]; /**< Report sizes for each report in the interface */
- uint16_t LargestReportSizeBits; /**< Largest report that the attached device will generate, in bits */
- bool UsingReportIDs; /**< Indicates if the device has at least one REPORT ID
- * element in its HID report descriptor.
- */
- } 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[in] ReportData Buffer containing the device's HID report table
- * \param[in] ReportSize Size in bytes of the HID report table
- * \param[out] 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) ATTR_NON_NULL_PTR_ARG(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.
- *
- * When called, this copies the report item's Value element to it's PreviousValue element for easy
- * checking to see if an item's value has changed before processing a report.
- *
- * \param[in] ReportData Buffer containing an IN or FEATURE report from an attached device
- * \param[in,out] 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) ATTR_NON_NULL_PTR_ARG(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).
- *
- * When called, this copies the report item's Value element to it's PreviousValue element for easy
- * checking to see if an item's value has changed before sending a report.
- *
- * If the device has multiple HID reports, the first byte in the report is set to the report ID of the given item.
- *
- * \param[out] ReportData Buffer holding the current OUT or FEATURE report data
- * \param[in] ReportItem Pointer to the report item of interest in a \ref HID_ReportInfo_t ReportItem array
- */
- void USB_SetHIDReportItemInfo(uint8_t* ReportData, HID_ReportItem_t* const ReportItem)
- ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
-
- /** Retrieves the size of a given HID report in bytes from it's Report ID.
- *
- * \param[in] ParserData Pointer to a \ref HID_ReportInfo_t instance containing the parser output
- * \param[in] ReportID Report ID of the report whose size is to be retrieved
- * \param[in] ReportType Type of the report whose size is to be determined, a valued from the
- * \ref HID_ReportItemTypes_t enum
- *
- * \return Size of the report in bytes, or 0 if the report does not exist
- */
- uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData, const uint8_t ReportID,
- const uint8_t ReportType) ATTR_CONST ATTR_NON_NULL_PTR_ARG(1);
-
- /** Callback routine for the HID Report Parser. This callback <b>must</b> be implemented by the user code when
- * the parser is used, to determine what report IN, OUT and FEATURE item's information is stored into the user
- * HID_ReportInfo_t structure. This can be used to filter only those items the application will be using, so that
- * no RAM is wasted storing the attributes for report items which will never be referenced by the application.
- *
- * \param[in] CurrentItem Pointer to the current report item for user checking
- *
- * \return Boolean true if the item should be stored into the HID_ReportInfo_t structure, false if it should be ignored
- */
- bool CALLBACK_HIDParser_FilterHIDReportItem(HID_ReportItem_t* CurrentItem);
-
- /* 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
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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 + * \brief USB Human Interface Device (HID) Class report descriptor parser. + * + * This file allows for the easy parsing of complex HID report descriptors, which describes the data that + * a HID device transmits to the host. It also provides an easy API for extracting and processing the data + * elements inside a HID report sent from an attached HID device. + */ + +/** \ingroup Group_USB + * @defgroup Group_HIDParser HID Report Parser + * + * \section Sec_Dependencies Module Source Dependencies + * The following files must be built with any user project that uses this module: + * - LUFA/Drivers/USB/Class/Host/HIDParser.c + * + * \section Module Description + * 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 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. + * + * @{ + */ + +#ifndef __HIDPARSER_H__ +#define __HIDPARSER_H__ + + /* Macros: */ + #define __INCLUDE_FROM_USB_DRIVER + #define __INCLUDE_FROM_HID_DRIVER + + /* Includes: */ + #include <string.h> + #include <stdbool.h> + + #include "HIDReportData.h" + #include "../Common/HID.h" + + #include "../../../../Common/Common.h" + + /* Enable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + extern "C" { + #endif + + /* Macros: */ + #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 2 levels (allowing non-nested PUSH items) 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 2 + #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 10 + #endif + + #if !defined(HID_MAX_REPORTITEMS) || defined(__DOXYGEN__) + /** Constant indicating the maximum number of report items (IN, OUT or FEATURE) that can be processed + * in the report item descriptor and stored in the user HID Report Info structure. A large value allows + * for more report items to be stored, but consumes more memory. By default this is set to 20 items, + * but this can be overridden by defining HID_MAX_REPORTITEMS to another value in the user project + * makefile, and passing the define to the compiler using the -D compiler switch. + */ + #define HID_MAX_REPORTITEMS 20 + #endif + + #if !defined(HID_MAX_REPORT_IDS) || defined(__DOXYGEN__) + /** Constant indicating the maximum number of unique report IDs that can be processed in the report item + * descriptor for the report size information array in the user HID Report Info structure. A large value + * allows for more report ID report sizes to be stored, but consumes more memory. By default this is set + * to 5 items, but this can be overridden by defining HID_MAX_REPORT_IDS to another value in the user project + * makefile, and passing the define to the compiler using the -D compiler switch. Note that IN, OUT and FEATURE + * items sharing the same report ID consume only one size item in the array. + */ + #define HID_MAX_REPORT_IDS 10 + #endif + + /** Returns the value a given HID report item (once its value has been fetched via \ref USB_GetHIDReportItemInfo()) + * left-aligned to the given data type. This allows for signed data to be interpreted correctly, by shifting the data + * leftwards until the data's sign bit is in the correct position. + * + * \param[in] reportitem HID Report Item whose retrieved value is to be aligned + * \param[in] type Data type to align the HID report item's value to + * + * \return Left-aligned data of the given report item's pre-retrived value for the given datatype + */ + #define HID_ALIGN_DATA(reportitem, type) ((type)(reportitem->Value << ((8 * sizeof(type)) - reportitem->Attributes.BitSize))) + + /* Public Interface - May be used in end-application: */ + /* Enums: */ + /** 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, /**< An END COLLECTION item found without matching COLLECTION item. */ + HID_PARSE_InsufficientCollectionPaths = 5, /**< More than \ref HID_MAX_COLLECTIONS collections in the report. */ + HID_PARSE_UsageListOverflow = 6, /**< More than \ref HID_USAGE_STACK_DEPTH usages listed in a row. */ + HID_PARSE_InsufficientReportIDItems = 7, /**< More than \ref HID_MAX_REPORT_IDS report IDs in the device. */ + HID_PARSE_NoUnfilteredReportItems = 8, /**< All report items from the device were filtered by the filtering callback routine. */ + }; + + /* Type Defines: */ + /** \brief HID Parser Report Item Min/Max Structure. + * + * 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; + + /** \brief HID Parser Report Item Unit Structure. + * + * 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; + + /** \brief HID Parser Report Item Usage Structure. + * + * 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_Usage_t; + + /** \brief HID Parser Report Item Collection Path Structure. + * + * 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; + + /** \brief HID Parser Report Item Attributes Structure. + * + * 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; + + /** \brief HID Parser Report Item Details Structure. + * + * Type define for a report item (IN, OUT or FEATURE) layout 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_ReportItemTypes_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 - use \ref HID_ALIGN_DATA() when processing + * a retrieved value so that it is aligned to a specific type. + */ + uint32_t PreviousValue; /**< Previous value of the report item. */ + } HID_ReportItem_t; + + /** \brief HID Parser Report Size Structure. + * + * Type define for a report item size information structure, to retain the size of a device's reports by ID. + */ + typedef struct + { + uint8_t ReportID; /** Report ID of the report within the HID interface */ + uint16_t ReportSizeBits[3]; /** Total number of bits in each report type for the given Report ID, + * indexed by the \ref HID_ReportItemTypes_t enum + */ + } HID_ReportSizeInfo_t; + + /** \brief HID Parser State Structure. + * + * 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. + */ + uint8_t TotalDeviceReports; /**< Number of reports within the HID interface */ + HID_ReportSizeInfo_t ReportIDSizes[HID_MAX_REPORT_IDS]; /**< Report sizes for each report in the interface */ + uint16_t LargestReportSizeBits; /**< Largest report that the attached device will generate, in bits */ + bool UsingReportIDs; /**< Indicates if the device has at least one REPORT ID + * element in its HID report descriptor. + */ + } 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[in] ReportData Buffer containing the device's HID report table + * \param[in] ReportSize Size in bytes of the HID report table + * \param[out] 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) ATTR_NON_NULL_PTR_ARG(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. + * + * When called, this copies the report item's Value element to it's PreviousValue element for easy + * checking to see if an item's value has changed before processing a report. + * + * \param[in] ReportData Buffer containing an IN or FEATURE report from an attached device + * \param[in,out] 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) ATTR_NON_NULL_PTR_ARG(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). + * + * When called, this copies the report item's Value element to it's PreviousValue element for easy + * checking to see if an item's value has changed before sending a report. + * + * If the device has multiple HID reports, the first byte in the report is set to the report ID of the given item. + * + * \param[out] ReportData Buffer holding the current OUT or FEATURE report data + * \param[in] ReportItem Pointer to the report item of interest in a \ref HID_ReportInfo_t ReportItem array + */ + void USB_SetHIDReportItemInfo(uint8_t* ReportData, HID_ReportItem_t* const ReportItem) + ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + + /** Retrieves the size of a given HID report in bytes from it's Report ID. + * + * \param[in] ParserData Pointer to a \ref HID_ReportInfo_t instance containing the parser output + * \param[in] ReportID Report ID of the report whose size is to be retrieved + * \param[in] ReportType Type of the report whose size is to be determined, a valued from the + * \ref HID_ReportItemTypes_t enum + * + * \return Size of the report in bytes, or 0 if the report does not exist + */ + uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData, const uint8_t ReportID, + const uint8_t ReportType) ATTR_CONST ATTR_NON_NULL_PTR_ARG(1); + + /** Callback routine for the HID Report Parser. This callback <b>must</b> be implemented by the user code when + * the parser is used, to determine what report IN, OUT and FEATURE item's information is stored into the user + * HID_ReportInfo_t structure. This can be used to filter only those items the application will be using, so that + * no RAM is wasted storing the attributes for report items which will never be referenced by the application. + * + * \param[in] CurrentItem Pointer to the current report item for user checking + * + * \return Boolean true if the item should be stored into the HID_ReportInfo_t structure, false if it should be ignored + */ + bool CALLBACK_HIDParser_FilterHIDReportItem(HID_ReportItem_t* CurrentItem); + + /* 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 index 4f328c964..dca1ebb3a 100644 --- a/LUFA/Drivers/USB/Class/Host/HIDReportData.h +++ b/LUFA/Drivers/USB/Class/Host/HIDReportData.h @@ -1,141 +1,141 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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
- * \brief Constants for HID report item attributes.
- *
- * HID report item constants for 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
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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 + * \brief Constants for HID report item attributes. + * + * HID report item constants for 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/MIDI.c b/LUFA/Drivers/USB/Class/Host/MIDI.c index c2e6257c4..f5505959a 100644 --- a/LUFA/Drivers/USB/Class/Host/MIDI.c +++ b/LUFA/Drivers/USB/Class/Host/MIDI.c @@ -1,186 +1,186 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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_USB_DRIVER
-#include "../../HighLevel/USBMode.h"
-#if defined(USB_CAN_BE_HOST)
-
-#define __INCLUDE_FROM_MIDI_CLASS_HOST_C
-#define __INCLUDE_FROM_MIDI_DRIVER
-#include "MIDI.h"
-
-uint8_t MIDI_Host_ConfigurePipes(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* ConfigDescriptorData)
-{
- uint8_t FoundEndpoints = 0;
-
- memset(&MIDIInterfaceInfo->State, 0x00, sizeof(MIDIInterfaceInfo->State));
-
- if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
- return MIDI_ENUMERROR_InvalidConfigDescriptor;
-
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_MIDI_Host_NextMIDIStreamingInterface) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return MIDI_ENUMERROR_NoStreamingInterfaceFound;
- }
-
- while (FoundEndpoints != (MIDI_FOUND_DATAPIPE_IN | MIDI_FOUND_DATAPIPE_OUT))
- {
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_MIDI_Host_NextMIDIStreamingDataEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return MIDI_ENUMERROR_EndpointsNotFound;
- }
-
- USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
-
- if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
- {
- Pipe_ConfigurePipe(MIDIInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- MIDIInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- MIDIInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize;
-
- FoundEndpoints |= MIDI_FOUND_DATAPIPE_IN;
- }
- else
- {
- Pipe_ConfigurePipe(MIDIInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- MIDIInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- MIDIInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize;
-
- FoundEndpoints |= MIDI_FOUND_DATAPIPE_OUT;
- }
- }
-
- MIDIInterfaceInfo->State.IsActive = true;
- return MIDI_ENUMERROR_NoError;
-}
-
-static uint8_t DComp_MIDI_Host_NextMIDIStreamingInterface(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Interface_t);
-
- if ((CurrentInterface->Class == MIDI_STREAMING_CLASS) &&
- (CurrentInterface->SubClass == MIDI_STREAMING_SUBCLASS) &&
- (CurrentInterface->Protocol == MIDI_STREAMING_PROTOCOL))
- {
- return DESCRIPTOR_SEARCH_Found;
- }
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-static uint8_t DComp_MIDI_Host_NextMIDIStreamingDataEndpoint(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
- {
- USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Endpoint_t);
-
- uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK);
-
- if ((EndpointType == EP_TYPE_BULK) && !(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress)))
- return DESCRIPTOR_SEARCH_Found;
- }
- else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- return DESCRIPTOR_SEARCH_Fail;
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-uint8_t MIDI_Host_Flush(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo)
-{
- if (USB_HostState != HOST_STATE_Configured)
- return PIPE_RWSTREAM_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- Pipe_SelectPipe(MIDIInterfaceInfo->Config.DataOUTPipeNumber);
-
- if (Pipe_BytesInPipe())
- {
- Pipe_ClearOUT();
-
- if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
- return ErrorCode;
- }
-
- return PIPE_READYWAIT_NoError;
-}
-
-uint8_t MIDI_Host_SendEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo, MIDI_EventPacket_t* const Event)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(MIDIInterfaceInfo->State.IsActive))
- return HOST_SENDCONTROL_DeviceDisconnected;
-
- Pipe_SelectPipe(MIDIInterfaceInfo->Config.DataOUTPipeNumber);
-
- if (Pipe_IsReadWriteAllowed())
- {
- uint8_t ErrorCode;
-
- if ((ErrorCode = Pipe_Write_Stream_LE(Event, sizeof(MIDI_EventPacket_t), NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- if (!(Pipe_IsReadWriteAllowed()))
- Pipe_ClearOUT();
- }
-
- return PIPE_RWSTREAM_NoError;
-}
-
-bool MIDI_Host_ReceiveEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo, MIDI_EventPacket_t* const Event)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(MIDIInterfaceInfo->State.IsActive))
- return HOST_SENDCONTROL_DeviceDisconnected;
-
- Pipe_SelectPipe(MIDIInterfaceInfo->Config.DataINPipeNumber);
-
- if (!(Pipe_IsReadWriteAllowed()))
- return false;
-
- Pipe_Read_Stream_LE(Event, sizeof(MIDI_EventPacket_t), NO_STREAM_CALLBACK);
-
- if (!(Pipe_IsReadWriteAllowed()))
- Pipe_ClearIN();
-
- return true;
-}
-
-#endif
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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_USB_DRIVER +#include "../../HighLevel/USBMode.h" +#if defined(USB_CAN_BE_HOST) + +#define __INCLUDE_FROM_MIDI_CLASS_HOST_C +#define __INCLUDE_FROM_MIDI_DRIVER +#include "MIDI.h" + +uint8_t MIDI_Host_ConfigurePipes(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo, uint16_t ConfigDescriptorSize, + void* ConfigDescriptorData) +{ + uint8_t FoundEndpoints = 0; + + memset(&MIDIInterfaceInfo->State, 0x00, sizeof(MIDIInterfaceInfo->State)); + + if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration) + return MIDI_ENUMERROR_InvalidConfigDescriptor; + + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_MIDI_Host_NextMIDIStreamingInterface) != DESCRIPTOR_SEARCH_COMP_Found) + { + return MIDI_ENUMERROR_NoStreamingInterfaceFound; + } + + while (FoundEndpoints != (MIDI_FOUND_DATAPIPE_IN | MIDI_FOUND_DATAPIPE_OUT)) + { + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_MIDI_Host_NextMIDIStreamingDataEndpoint) != DESCRIPTOR_SEARCH_COMP_Found) + { + return MIDI_ENUMERROR_EndpointsNotFound; + } + + USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t); + + if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN) + { + Pipe_ConfigurePipe(MIDIInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + MIDIInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + MIDIInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize; + + FoundEndpoints |= MIDI_FOUND_DATAPIPE_IN; + } + else + { + Pipe_ConfigurePipe(MIDIInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + MIDIInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + MIDIInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize; + + FoundEndpoints |= MIDI_FOUND_DATAPIPE_OUT; + } + } + + MIDIInterfaceInfo->State.IsActive = true; + return MIDI_ENUMERROR_NoError; +} + +static uint8_t DComp_MIDI_Host_NextMIDIStreamingInterface(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Interface_t); + + if ((CurrentInterface->Class == MIDI_STREAMING_CLASS) && + (CurrentInterface->SubClass == MIDI_STREAMING_SUBCLASS) && + (CurrentInterface->Protocol == MIDI_STREAMING_PROTOCOL)) + { + return DESCRIPTOR_SEARCH_Found; + } + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +static uint8_t DComp_MIDI_Host_NextMIDIStreamingDataEndpoint(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint) + { + USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Endpoint_t); + + uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK); + + if ((EndpointType == EP_TYPE_BULK) && !(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress))) + return DESCRIPTOR_SEARCH_Found; + } + else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + return DESCRIPTOR_SEARCH_Fail; + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +uint8_t MIDI_Host_Flush(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo) +{ + if (USB_HostState != HOST_STATE_Configured) + return PIPE_RWSTREAM_DeviceDisconnected; + + uint8_t ErrorCode; + + Pipe_SelectPipe(MIDIInterfaceInfo->Config.DataOUTPipeNumber); + + if (Pipe_BytesInPipe()) + { + Pipe_ClearOUT(); + + if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError) + return ErrorCode; + } + + return PIPE_READYWAIT_NoError; +} + +uint8_t MIDI_Host_SendEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo, MIDI_EventPacket_t* const Event) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(MIDIInterfaceInfo->State.IsActive)) + return HOST_SENDCONTROL_DeviceDisconnected; + + Pipe_SelectPipe(MIDIInterfaceInfo->Config.DataOUTPipeNumber); + + if (Pipe_IsReadWriteAllowed()) + { + uint8_t ErrorCode; + + if ((ErrorCode = Pipe_Write_Stream_LE(Event, sizeof(MIDI_EventPacket_t), NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + if (!(Pipe_IsReadWriteAllowed())) + Pipe_ClearOUT(); + } + + return PIPE_RWSTREAM_NoError; +} + +bool MIDI_Host_ReceiveEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo, MIDI_EventPacket_t* const Event) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(MIDIInterfaceInfo->State.IsActive)) + return HOST_SENDCONTROL_DeviceDisconnected; + + Pipe_SelectPipe(MIDIInterfaceInfo->Config.DataINPipeNumber); + + if (!(Pipe_IsReadWriteAllowed())) + return false; + + Pipe_Read_Stream_LE(Event, sizeof(MIDI_EventPacket_t), NO_STREAM_CALLBACK); + + if (!(Pipe_IsReadWriteAllowed())) + Pipe_ClearIN(); + + return true; +} + +#endif diff --git a/LUFA/Drivers/USB/Class/Host/MIDI.h b/LUFA/Drivers/USB/Class/Host/MIDI.h index 0cd99bcca..dd064af19 100644 --- a/LUFA/Drivers/USB/Class/Host/MIDI.h +++ b/LUFA/Drivers/USB/Class/Host/MIDI.h @@ -1,204 +1,204 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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
- * \brief Host mode driver for the library USB MIDI Class driver.
- *
- * Host mode driver for the library USB MIDI Class driver.
- *
- * \note This file should not be included directly. It is automatically included as needed by the class driver
- * dispatch header located in LUFA/Drivers/USB/Class/MIDI.h.
- */
-
-/** \ingroup Group_USBClassMIDI
- * @defgroup Group_USBClassMIDIHost MIDI Class Host Mode Driver
- *
- * \section Sec_Dependencies Module Source Dependencies
- * The following files must be built with any user project that uses this module:
- * - LUFA/Drivers/USB/Class/Host/MIDI.c
- *
- * \section Module Description
- * Host Mode USB Class driver framework interface, for the MIDI USB Class driver.
- *
- * @{
- */
-
-#ifndef __MIDI_CLASS_HOST_H__
-#define __MIDI_CLASS_HOST_H__
-
- /* Includes: */
- #include "../../USB.h"
- #include "../Common/MIDI.h"
-
- /* Enable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- extern "C" {
- #endif
-
- /* Preprocessor Checks: */
- #if !defined(__INCLUDE_FROM_MIDI_DRIVER)
- #error Do not include this file directly. Include LUFA/Drivers/Class/MIDI.h instead.
- #endif
-
- /* Public Interface - May be used in end-application: */
- /* Type Defines: */
- /** \brief MIDI Class Host Mode Configuration and State Structure.
- *
- * Class state structure. An instance of this structure should be made within the user application,
- * and passed to each of the MIDI class driver functions as the MIDIInterfaceInfo parameter. This
- * stores each MIDI interface's configuration and state information.
- */
- typedef struct
- {
- const struct
- {
- uint8_t DataINPipeNumber; /**< Pipe number of the MIDI interface's streaming IN data pipe */
- bool DataINPipeDoubleBank; /** Indicates if the MIDI interface's IN data pipe should use double banking */
-
- uint8_t DataOUTPipeNumber; /**< Pipe number of the MIDI interface's streaming OUT data pipe */
- bool DataOUTPipeDoubleBank; /** Indicates if the MIDI interface's OUT data pipe should use double banking */
- } Config; /**< Config data for the USB class interface within the device. All elements in this section
- * <b>must</b> be set or the interface will fail to enumerate and operate correctly.
- */
- struct
- {
- bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
- * after \ref MIDI_Host_ConfigurePipes() is called and the Host state machine is in the
- * Configured state
- */
-
- uint16_t DataINPipeSize; /**< Size in bytes of the MIDI Streaming Data interface's IN data pipe */
- uint16_t DataOUTPipeSize; /**< Size in bytes of the MIDI Streaming Data interface's OUT data pipe */
- } State; /**< State data for the USB class interface within the device. All elements in this section
- * <b>may</b> be set to initial values, but may also be ignored to default to sane values when
- * the interface is enumerated.
- */
- } USB_ClassInfo_MIDI_Host_t;
-
- /* Enums: */
- /** Enum for the possible error codes returned by the \ref MIDI_Host_ConfigurePipes() function. */
- enum MIDIHost_EnumerationFailure_ErrorCodes_t
- {
- MIDI_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */
- MIDI_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */
- MIDI_ENUMERROR_NoStreamingInterfaceFound = 2, /**< A compatible MIDI interface was not found in the device's Configuration Descriptor */
- MIDI_ENUMERROR_EndpointsNotFound = 3, /**< Compatible MIDI data endpoints were not found in the device's MIDI interface */
- };
-
- /* Function Prototypes: */
- /** Host interface configuration routine, to configure a given MIDI host interface instance using the Configuration
- * Descriptor read from an attached USB device. This function automatically updates the given MIDI Host instance's
- * state values and configures the pipes required to communicate with the interface if it is found within the device.
- * This should be called once after the stack has enumerated the attached device, while the host state machine is in
- * the Addressed state.
- *
- * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing an MIDI Class host configuration and state
- * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor
- * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor
- *
- * \return A value from the \ref MIDIHost_EnumerationFailure_ErrorCodes_t enum
- */
- uint8_t MIDI_Host_ConfigurePipes(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
-
- /** Sends a MIDI event packet to the device. If no device is connected, the event packet is discarded.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing a MIDI Class configuration and state
- * \param[in] Event Pointer to a populated USB_MIDI_EventPacket_t structure containing the MIDI event to send
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum
- */
- uint8_t MIDI_Host_SendEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo,
- MIDI_EventPacket_t* const Event) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
-
- /** Flushes the MIDI send buffer, sending any queued MIDI events to the device. This should be called to override the
- * \ref MIDI_Host_SendEventPacket() function's packing behaviour, to flush queued events. Events are queued into the
- * pipe bank until either the pipe bank is full, or \ref MIDI_Host_Flush() is called. This allows for multiple MIDI
- * events to be packed into a single pipe packet, increasing data throughput.
- *
- * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing a MIDI Class configuration and state
- *
- * \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum
- */
- uint8_t MIDI_Host_Flush(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo);
-
- /** Receives a MIDI event packet from the device.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing a MIDI Class configuration and state
- * \param[out] Event Pointer to a USB_MIDI_EventPacket_t structure where the received MIDI event is to be placed
- *
- * \return Boolean true if a MIDI event packet was received, false otherwise
- */
- bool MIDI_Host_ReceiveEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo,
- MIDI_EventPacket_t* const Event) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
-
- /* Inline Functions: */
- /** General management task for a given MIDI host class interface, required for the correct operation of the interface. This should
- * be called frequently in the main program loop, before the master USB management task \ref USB_USBTask().
- *
- * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing an MIDI Class host configuration and state
- */
- static inline void MIDI_Host_USBTask(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo);
- static inline void MIDI_Host_USBTask(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo)
- {
- (void)MIDIInterfaceInfo;
- }
-
- /* Private Interface - For use in library only: */
- #if !defined(__DOXYGEN__)
- /* Macros: */
- #define MIDI_STREAMING_CLASS 0x01
- #define MIDI_STREAMING_SUBCLASS 0x03
- #define MIDI_STREAMING_PROTOCOL 0x00
-
- #define MIDI_FOUND_DATAPIPE_IN (1 << 0)
- #define MIDI_FOUND_DATAPIPE_OUT (1 << 1)
-
- /* Function Prototypes: */
- #if defined(__INCLUDE_FROM_MIDI_CLASS_HOST_C)
- static uint8_t DComp_MIDI_Host_NextMIDIStreamingInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1);
- static uint8_t DComp_MIDI_Host_NextMIDIStreamingDataEndpoint(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1);
- #endif
- #endif
-
- /* Disable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- }
- #endif
-
-#endif
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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 + * \brief Host mode driver for the library USB MIDI Class driver. + * + * Host mode driver for the library USB MIDI Class driver. + * + * \note This file should not be included directly. It is automatically included as needed by the class driver + * dispatch header located in LUFA/Drivers/USB/Class/MIDI.h. + */ + +/** \ingroup Group_USBClassMIDI + * @defgroup Group_USBClassMIDIHost MIDI Class Host Mode Driver + * + * \section Sec_Dependencies Module Source Dependencies + * The following files must be built with any user project that uses this module: + * - LUFA/Drivers/USB/Class/Host/MIDI.c + * + * \section Module Description + * Host Mode USB Class driver framework interface, for the MIDI USB Class driver. + * + * @{ + */ + +#ifndef __MIDI_CLASS_HOST_H__ +#define __MIDI_CLASS_HOST_H__ + + /* Includes: */ + #include "../../USB.h" + #include "../Common/MIDI.h" + + /* Enable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + extern "C" { + #endif + + /* Preprocessor Checks: */ + #if !defined(__INCLUDE_FROM_MIDI_DRIVER) + #error Do not include this file directly. Include LUFA/Drivers/Class/MIDI.h instead. + #endif + + /* Public Interface - May be used in end-application: */ + /* Type Defines: */ + /** \brief MIDI Class Host Mode Configuration and State Structure. + * + * Class state structure. An instance of this structure should be made within the user application, + * and passed to each of the MIDI class driver functions as the MIDIInterfaceInfo parameter. This + * stores each MIDI interface's configuration and state information. + */ + typedef struct + { + const struct + { + uint8_t DataINPipeNumber; /**< Pipe number of the MIDI interface's streaming IN data pipe */ + bool DataINPipeDoubleBank; /** Indicates if the MIDI interface's IN data pipe should use double banking */ + + uint8_t DataOUTPipeNumber; /**< Pipe number of the MIDI interface's streaming OUT data pipe */ + bool DataOUTPipeDoubleBank; /** Indicates if the MIDI interface's OUT data pipe should use double banking */ + } Config; /**< Config data for the USB class interface within the device. All elements in this section + * <b>must</b> be set or the interface will fail to enumerate and operate correctly. + */ + struct + { + bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid + * after \ref MIDI_Host_ConfigurePipes() is called and the Host state machine is in the + * Configured state + */ + + uint16_t DataINPipeSize; /**< Size in bytes of the MIDI Streaming Data interface's IN data pipe */ + uint16_t DataOUTPipeSize; /**< Size in bytes of the MIDI Streaming Data interface's OUT data pipe */ + } State; /**< State data for the USB class interface within the device. All elements in this section + * <b>may</b> be set to initial values, but may also be ignored to default to sane values when + * the interface is enumerated. + */ + } USB_ClassInfo_MIDI_Host_t; + + /* Enums: */ + /** Enum for the possible error codes returned by the \ref MIDI_Host_ConfigurePipes() function. */ + enum MIDIHost_EnumerationFailure_ErrorCodes_t + { + MIDI_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */ + MIDI_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */ + MIDI_ENUMERROR_NoStreamingInterfaceFound = 2, /**< A compatible MIDI interface was not found in the device's Configuration Descriptor */ + MIDI_ENUMERROR_EndpointsNotFound = 3, /**< Compatible MIDI data endpoints were not found in the device's MIDI interface */ + }; + + /* Function Prototypes: */ + /** Host interface configuration routine, to configure a given MIDI host interface instance using the Configuration + * Descriptor read from an attached USB device. This function automatically updates the given MIDI Host instance's + * state values and configures the pipes required to communicate with the interface if it is found within the device. + * This should be called once after the stack has enumerated the attached device, while the host state machine is in + * the Addressed state. + * + * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing an MIDI Class host configuration and state + * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor + * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor + * + * \return A value from the \ref MIDIHost_EnumerationFailure_ErrorCodes_t enum + */ + uint8_t MIDI_Host_ConfigurePipes(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo, uint16_t ConfigDescriptorSize, + void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3); + + /** Sends a MIDI event packet to the device. If no device is connected, the event packet is discarded. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing a MIDI Class configuration and state + * \param[in] Event Pointer to a populated USB_MIDI_EventPacket_t structure containing the MIDI event to send + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum + */ + uint8_t MIDI_Host_SendEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo, + MIDI_EventPacket_t* const Event) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + + /** Flushes the MIDI send buffer, sending any queued MIDI events to the device. This should be called to override the + * \ref MIDI_Host_SendEventPacket() function's packing behaviour, to flush queued events. Events are queued into the + * pipe bank until either the pipe bank is full, or \ref MIDI_Host_Flush() is called. This allows for multiple MIDI + * events to be packed into a single pipe packet, increasing data throughput. + * + * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing a MIDI Class configuration and state + * + * \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum + */ + uint8_t MIDI_Host_Flush(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo); + + /** Receives a MIDI event packet from the device. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing a MIDI Class configuration and state + * \param[out] Event Pointer to a USB_MIDI_EventPacket_t structure where the received MIDI event is to be placed + * + * \return Boolean true if a MIDI event packet was received, false otherwise + */ + bool MIDI_Host_ReceiveEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo, + MIDI_EventPacket_t* const Event) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + + /* Inline Functions: */ + /** General management task for a given MIDI host class interface, required for the correct operation of the interface. This should + * be called frequently in the main program loop, before the master USB management task \ref USB_USBTask(). + * + * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing an MIDI Class host configuration and state + */ + static inline void MIDI_Host_USBTask(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo); + static inline void MIDI_Host_USBTask(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo) + { + (void)MIDIInterfaceInfo; + } + + /* Private Interface - For use in library only: */ + #if !defined(__DOXYGEN__) + /* Macros: */ + #define MIDI_STREAMING_CLASS 0x01 + #define MIDI_STREAMING_SUBCLASS 0x03 + #define MIDI_STREAMING_PROTOCOL 0x00 + + #define MIDI_FOUND_DATAPIPE_IN (1 << 0) + #define MIDI_FOUND_DATAPIPE_OUT (1 << 1) + + /* Function Prototypes: */ + #if defined(__INCLUDE_FROM_MIDI_CLASS_HOST_C) + static uint8_t DComp_MIDI_Host_NextMIDIStreamingInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1); + static uint8_t DComp_MIDI_Host_NextMIDIStreamingDataEndpoint(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1); + #endif + #endif + + /* Disable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + } + #endif + +#endif + +/** @} */ diff --git a/LUFA/Drivers/USB/Class/Host/MassStorage.c b/LUFA/Drivers/USB/Class/Host/MassStorage.c index f148f4ecc..6e84d07b8 100644 --- a/LUFA/Drivers/USB/Class/Host/MassStorage.c +++ b/LUFA/Drivers/USB/Class/Host/MassStorage.c @@ -1,594 +1,594 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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_USB_DRIVER
-#include "../../HighLevel/USBMode.h"
-#if defined(USB_CAN_BE_HOST)
-
-#define __INCLUDE_FROM_MS_CLASS_HOST_C
-#define __INCLUDE_FROM_MS_DRIVER
-#include "MassStorage.h"
-
-uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* DeviceConfigDescriptor)
-{
- uint8_t FoundEndpoints = 0;
-
- memset(&MSInterfaceInfo->State, 0x00, sizeof(MSInterfaceInfo->State));
-
- if (DESCRIPTOR_TYPE(DeviceConfigDescriptor) != DTYPE_Configuration)
- return MS_ENUMERROR_InvalidConfigDescriptor;
-
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor,
- DComp_NextMSInterface) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return MS_ENUMERROR_NoMSInterfaceFound;
- }
-
- MSInterfaceInfo->State.InterfaceNumber = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Interface_t)->InterfaceNumber;
-
- while (FoundEndpoints != (MS_FOUND_DATAPIPE_IN | MS_FOUND_DATAPIPE_OUT))
- {
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor,
- DComp_NextMSInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return MS_ENUMERROR_EndpointsNotFound;
- }
-
- USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Endpoint_t);
-
- if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
- {
- Pipe_ConfigurePipe(MSInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- MSInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- MSInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize;
-
- FoundEndpoints |= MS_FOUND_DATAPIPE_IN;
- }
- else
- {
- Pipe_ConfigurePipe(MSInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- MSInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- MSInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize;
-
- FoundEndpoints |= MS_FOUND_DATAPIPE_OUT;
- }
- }
-
- MSInterfaceInfo->State.IsActive = true;
- return MS_ENUMERROR_NoError;
-}
-
-static uint8_t DComp_NextMSInterface(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Interface_t);
-
- if ((CurrentInterface->Class == MASS_STORE_CLASS) &&
- (CurrentInterface->SubClass == MASS_STORE_SUBCLASS) &&
- (CurrentInterface->Protocol == MASS_STORE_PROTOCOL))
- {
- return DESCRIPTOR_SEARCH_Found;
- }
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-static uint8_t DComp_NextMSInterfaceEndpoint(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
- {
- USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Endpoint_t);
-
- uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK);
-
- if ((EndpointType == EP_TYPE_BULK) &&
- (!(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress))))
- {
- return DESCRIPTOR_SEARCH_Found;
- }
- }
- else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- return DESCRIPTOR_SEARCH_Fail;
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, MS_CommandBlockWrapper_t* const SCSICommandBlock,
- const void* const BufferPtr)
-{
- uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
-
- SCSICommandBlock->Signature = CBW_SIGNATURE;
- SCSICommandBlock->Tag = ++MSInterfaceInfo->State.TransactionTag;
-
- if (MSInterfaceInfo->State.TransactionTag == 0xFFFFFFFF)
- MSInterfaceInfo->State.TransactionTag = 1;
-
- Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_Unfreeze();
-
- if ((ErrorCode = Pipe_Write_Stream_LE(SCSICommandBlock, sizeof(MS_CommandBlockWrapper_t),
- NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- Pipe_ClearOUT();
- Pipe_WaitUntilReady();
-
- Pipe_Freeze();
-
- if ((BufferPtr != NULL) &&
- ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, SCSICommandBlock, (void*)BufferPtr)) != PIPE_RWSTREAM_NoError))
- {
- Pipe_Freeze();
- return ErrorCode;
- }
-
- return ErrorCode;
-}
-
-static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
-{
- uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS;
-
- Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
- Pipe_Unfreeze();
-
- while (!(Pipe_IsINReceived()))
- {
- if (USB_INT_HasOccurred(USB_INT_HSOFI))
- {
- USB_INT_Clear(USB_INT_HSOFI);
- TimeoutMSRem--;
-
- if (!(TimeoutMSRem))
- return PIPE_RWSTREAM_Timeout;
- }
-
- Pipe_Freeze();
- Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_Unfreeze();
-
- if (Pipe_IsStalled())
- {
- USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataOUTPipeNumber);
-
- return PIPE_RWSTREAM_PipeStalled;
- }
-
- Pipe_Freeze();
- Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
- Pipe_Unfreeze();
-
- if (Pipe_IsStalled())
- {
- USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataINPipeNumber);
-
- return PIPE_RWSTREAM_PipeStalled;
- }
-
- if (USB_HostState == HOST_STATE_Unattached)
- return PIPE_RWSTREAM_DeviceDisconnected;
- };
-
- Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
- Pipe_Freeze();
-
- Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_Freeze();
-
- return PIPE_RWSTREAM_NoError;
-}
-
-static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
- MS_CommandBlockWrapper_t* const SCSICommandBlock, void* BufferPtr)
-{
- uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
- uint16_t BytesRem = SCSICommandBlock->DataTransferLength;
-
- if (SCSICommandBlock->Flags & COMMAND_DIRECTION_DATA_IN)
- {
- if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
- {
- Pipe_Freeze();
- return ErrorCode;
- }
-
- Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
- Pipe_Unfreeze();
-
- if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- Pipe_ClearIN();
- }
- else
- {
- Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_Unfreeze();
-
- if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- Pipe_ClearOUT();
-
- while (!(Pipe_IsOUTReady()))
- {
- if (USB_HostState == HOST_STATE_Unattached)
- return PIPE_RWSTREAM_DeviceDisconnected;
- }
- }
-
- Pipe_Freeze();
-
- return ErrorCode;
-}
-
-static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
- MS_CommandStatusWrapper_t* const SCSICommandStatus)
-{
- uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
-
- if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
- Pipe_Unfreeze();
-
- if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t),
- NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
- {
- return ErrorCode;
- }
-
- Pipe_ClearIN();
- Pipe_Freeze();
-
- if (SCSICommandStatus->Status != SCSI_Command_Pass)
- ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
-
- return ErrorCode;
-}
-
-uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
-{
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_MassStorageReset,
- .wValue = 0,
- .wIndex = MSInterfaceInfo->State.InterfaceNumber,
- .wLength = 0,
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
-
- return USB_Host_SendControlRequest(NULL);
-}
-
-uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, uint8_t* const MaxLUNIndex)
-{
- uint8_t ErrorCode = HOST_SENDCONTROL_Successful;
-
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_GetMaxLUN,
- .wValue = 0,
- .wIndex = MSInterfaceInfo->State.InterfaceNumber,
- .wLength = 1,
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
-
- if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) != HOST_SENDCONTROL_Successful)
- {
- *MaxLUNIndex = 0;
- ErrorCode = HOST_SENDCONTROL_Successful;
- }
-
- return ErrorCode;
-}
-
-uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
- SCSI_Inquiry_Response_t* const InquiryData)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
- return HOST_SENDCONTROL_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
- {
- .DataTransferLength = sizeof(SCSI_Inquiry_Response_t),
- .Flags = COMMAND_DIRECTION_DATA_IN,
- .LUN = LUNIndex,
- .SCSICommandLength = 6,
- .SCSICommandData =
- {
- SCSI_CMD_INQUIRY,
- 0x00, // Reserved
- 0x00, // Reserved
- 0x00, // Reserved
- sizeof(SCSI_Inquiry_Response_t), // Allocation Length
- 0x00 // Unused (control)
- }
- };
-
- MS_CommandStatusWrapper_t SCSICommandStatus;
-
- if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, InquiryData)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
- return HOST_SENDCONTROL_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
- {
- .DataTransferLength = 0,
- .Flags = COMMAND_DIRECTION_DATA_IN,
- .LUN = LUNIndex,
- .SCSICommandLength = 6,
- .SCSICommandData =
- {
- SCSI_CMD_TEST_UNIT_READY,
- 0x00, // Reserved
- 0x00, // Reserved
- 0x00, // Reserved
- 0x00, // Reserved
- 0x00 // Unused (control)
- }
- };
-
- MS_CommandStatusWrapper_t SCSICommandStatus;
-
- if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
- SCSI_Capacity_t* const DeviceCapacity)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
- return HOST_SENDCONTROL_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
- {
- .DataTransferLength = sizeof(SCSI_Capacity_t),
- .Flags = COMMAND_DIRECTION_DATA_IN,
- .LUN = LUNIndex,
- .SCSICommandLength = 10,
- .SCSICommandData =
- {
- SCSI_CMD_READ_CAPACITY_10,
- 0x00, // Reserved
- 0x00, // MSB of Logical block address
- 0x00,
- 0x00,
- 0x00, // LSB of Logical block address
- 0x00, // Reserved
- 0x00, // Reserved
- 0x00, // Partial Medium Indicator
- 0x00 // Unused (control)
- }
- };
-
- MS_CommandStatusWrapper_t SCSICommandStatus;
-
- if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- SwapEndian_n(&DeviceCapacity->Blocks, sizeof(DeviceCapacity->Blocks));
- SwapEndian_n(&DeviceCapacity->BlockSize, sizeof(DeviceCapacity->BlockSize));
-
- if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
- SCSI_Request_Sense_Response_t* const SenseData)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
- return HOST_SENDCONTROL_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
- {
- .DataTransferLength = sizeof(SCSI_Request_Sense_Response_t),
- .Flags = COMMAND_DIRECTION_DATA_IN,
- .LUN = LUNIndex,
- .SCSICommandLength = 6,
- .SCSICommandData =
- {
- SCSI_CMD_REQUEST_SENSE,
- 0x00, // Reserved
- 0x00, // Reserved
- 0x00, // Reserved
- sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
- 0x00 // Unused (control)
- }
- };
-
- MS_CommandStatusWrapper_t SCSICommandStatus;
-
- if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, SenseData)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
- const bool PreventRemoval)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
- return HOST_SENDCONTROL_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
- {
- .DataTransferLength = 0,
- .Flags = COMMAND_DIRECTION_DATA_OUT,
- .LUN = LUNIndex,
- .SCSICommandLength = 6,
- .SCSICommandData =
- {
- SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
- 0x00, // Reserved
- 0x00, // Reserved
- PreventRemoval, // Prevent flag
- 0x00, // Reserved
- 0x00 // Unused (control)
- }
- };
-
- MS_CommandStatusWrapper_t SCSICommandStatus;
-
- if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, const uint32_t BlockAddress,
- const uint8_t Blocks, const uint16_t BlockSize, void* BlockBuffer)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
- return HOST_SENDCONTROL_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
- {
- .DataTransferLength = ((uint32_t)Blocks * BlockSize),
- .Flags = COMMAND_DIRECTION_DATA_IN,
- .LUN = LUNIndex,
- .SCSICommandLength = 10,
- .SCSICommandData =
- {
- SCSI_CMD_READ_10,
- 0x00, // Unused (control bits, all off)
- (BlockAddress >> 24), // MSB of Block Address
- (BlockAddress >> 16),
- (BlockAddress >> 8),
- (BlockAddress & 0xFF), // LSB of Block Address
- 0x00, // Unused (reserved)
- 0x00, // MSB of Total Blocks to Read
- Blocks, // LSB of Total Blocks to Read
- 0x00 // Unused (control)
- }
- };
-
- MS_CommandStatusWrapper_t SCSICommandStatus;
-
- if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, const uint32_t BlockAddress,
- const uint8_t Blocks, const uint16_t BlockSize, const void* BlockBuffer)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
- return HOST_SENDCONTROL_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
- {
- .DataTransferLength = ((uint32_t)Blocks * BlockSize),
- .Flags = COMMAND_DIRECTION_DATA_OUT,
- .LUN = LUNIndex,
- .SCSICommandLength = 10,
- .SCSICommandData =
- {
- SCSI_CMD_WRITE_10,
- 0x00, // Unused (control bits, all off)
- (BlockAddress >> 24), // MSB of Block Address
- (BlockAddress >> 16),
- (BlockAddress >> 8),
- (BlockAddress & 0xFF), // LSB of Block Address
- 0x00, // Unused (reserved)
- 0x00, // MSB of Total Blocks to Write
- Blocks, // LSB of Total Blocks to Write
- 0x00 // Unused (control)
- }
- };
-
- MS_CommandStatusWrapper_t SCSICommandStatus;
-
- if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- return PIPE_RWSTREAM_NoError;
-}
-
-#endif
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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_USB_DRIVER +#include "../../HighLevel/USBMode.h" +#if defined(USB_CAN_BE_HOST) + +#define __INCLUDE_FROM_MS_CLASS_HOST_C +#define __INCLUDE_FROM_MS_DRIVER +#include "MassStorage.h" + +uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, uint16_t ConfigDescriptorSize, + void* DeviceConfigDescriptor) +{ + uint8_t FoundEndpoints = 0; + + memset(&MSInterfaceInfo->State, 0x00, sizeof(MSInterfaceInfo->State)); + + if (DESCRIPTOR_TYPE(DeviceConfigDescriptor) != DTYPE_Configuration) + return MS_ENUMERROR_InvalidConfigDescriptor; + + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor, + DComp_NextMSInterface) != DESCRIPTOR_SEARCH_COMP_Found) + { + return MS_ENUMERROR_NoMSInterfaceFound; + } + + MSInterfaceInfo->State.InterfaceNumber = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Interface_t)->InterfaceNumber; + + while (FoundEndpoints != (MS_FOUND_DATAPIPE_IN | MS_FOUND_DATAPIPE_OUT)) + { + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor, + DComp_NextMSInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found) + { + return MS_ENUMERROR_EndpointsNotFound; + } + + USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Endpoint_t); + + if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN) + { + Pipe_ConfigurePipe(MSInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + MSInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + MSInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize; + + FoundEndpoints |= MS_FOUND_DATAPIPE_IN; + } + else + { + Pipe_ConfigurePipe(MSInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + MSInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + MSInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize; + + FoundEndpoints |= MS_FOUND_DATAPIPE_OUT; + } + } + + MSInterfaceInfo->State.IsActive = true; + return MS_ENUMERROR_NoError; +} + +static uint8_t DComp_NextMSInterface(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Interface_t); + + if ((CurrentInterface->Class == MASS_STORE_CLASS) && + (CurrentInterface->SubClass == MASS_STORE_SUBCLASS) && + (CurrentInterface->Protocol == MASS_STORE_PROTOCOL)) + { + return DESCRIPTOR_SEARCH_Found; + } + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +static uint8_t DComp_NextMSInterfaceEndpoint(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint) + { + USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Endpoint_t); + + uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK); + + if ((EndpointType == EP_TYPE_BULK) && + (!(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress)))) + { + return DESCRIPTOR_SEARCH_Found; + } + } + else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + return DESCRIPTOR_SEARCH_Fail; + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, MS_CommandBlockWrapper_t* const SCSICommandBlock, + const void* const BufferPtr) +{ + uint8_t ErrorCode = PIPE_RWSTREAM_NoError; + + SCSICommandBlock->Signature = CBW_SIGNATURE; + SCSICommandBlock->Tag = ++MSInterfaceInfo->State.TransactionTag; + + if (MSInterfaceInfo->State.TransactionTag == 0xFFFFFFFF) + MSInterfaceInfo->State.TransactionTag = 1; + + Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_Unfreeze(); + + if ((ErrorCode = Pipe_Write_Stream_LE(SCSICommandBlock, sizeof(MS_CommandBlockWrapper_t), + NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + Pipe_ClearOUT(); + Pipe_WaitUntilReady(); + + Pipe_Freeze(); + + if ((BufferPtr != NULL) && + ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, SCSICommandBlock, (void*)BufferPtr)) != PIPE_RWSTREAM_NoError)) + { + Pipe_Freeze(); + return ErrorCode; + } + + return ErrorCode; +} + +static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo) +{ + uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS; + + Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber); + Pipe_Unfreeze(); + + while (!(Pipe_IsINReceived())) + { + if (USB_INT_HasOccurred(USB_INT_HSOFI)) + { + USB_INT_Clear(USB_INT_HSOFI); + TimeoutMSRem--; + + if (!(TimeoutMSRem)) + return PIPE_RWSTREAM_Timeout; + } + + Pipe_Freeze(); + Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_Unfreeze(); + + if (Pipe_IsStalled()) + { + USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataOUTPipeNumber); + + return PIPE_RWSTREAM_PipeStalled; + } + + Pipe_Freeze(); + Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber); + Pipe_Unfreeze(); + + if (Pipe_IsStalled()) + { + USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataINPipeNumber); + + return PIPE_RWSTREAM_PipeStalled; + } + + if (USB_HostState == HOST_STATE_Unattached) + return PIPE_RWSTREAM_DeviceDisconnected; + }; + + Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber); + Pipe_Freeze(); + + Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_Freeze(); + + return PIPE_RWSTREAM_NoError; +} + +static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, + MS_CommandBlockWrapper_t* const SCSICommandBlock, void* BufferPtr) +{ + uint8_t ErrorCode = PIPE_RWSTREAM_NoError; + uint16_t BytesRem = SCSICommandBlock->DataTransferLength; + + if (SCSICommandBlock->Flags & COMMAND_DIRECTION_DATA_IN) + { + if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError) + { + Pipe_Freeze(); + return ErrorCode; + } + + Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber); + Pipe_Unfreeze(); + + if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + Pipe_ClearIN(); + } + else + { + Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_Unfreeze(); + + if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + Pipe_ClearOUT(); + + while (!(Pipe_IsOUTReady())) + { + if (USB_HostState == HOST_STATE_Unattached) + return PIPE_RWSTREAM_DeviceDisconnected; + } + } + + Pipe_Freeze(); + + return ErrorCode; +} + +static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, + MS_CommandStatusWrapper_t* const SCSICommandStatus) +{ + uint8_t ErrorCode = PIPE_RWSTREAM_NoError; + + if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber); + Pipe_Unfreeze(); + + if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t), + NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError) + { + return ErrorCode; + } + + Pipe_ClearIN(); + Pipe_Freeze(); + + if (SCSICommandStatus->Status != SCSI_Command_Pass) + ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED; + + return ErrorCode; +} + +uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo) +{ + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_MassStorageReset, + .wValue = 0, + .wIndex = MSInterfaceInfo->State.InterfaceNumber, + .wLength = 0, + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + return USB_Host_SendControlRequest(NULL); +} + +uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, uint8_t* const MaxLUNIndex) +{ + uint8_t ErrorCode = HOST_SENDCONTROL_Successful; + + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_GetMaxLUN, + .wValue = 0, + .wIndex = MSInterfaceInfo->State.InterfaceNumber, + .wLength = 1, + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) != HOST_SENDCONTROL_Successful) + { + *MaxLUNIndex = 0; + ErrorCode = HOST_SENDCONTROL_Successful; + } + + return ErrorCode; +} + +uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, + SCSI_Inquiry_Response_t* const InquiryData) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive)) + return HOST_SENDCONTROL_DeviceDisconnected; + + uint8_t ErrorCode; + + MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t) + { + .DataTransferLength = sizeof(SCSI_Inquiry_Response_t), + .Flags = COMMAND_DIRECTION_DATA_IN, + .LUN = LUNIndex, + .SCSICommandLength = 6, + .SCSICommandData = + { + SCSI_CMD_INQUIRY, + 0x00, // Reserved + 0x00, // Reserved + 0x00, // Reserved + sizeof(SCSI_Inquiry_Response_t), // Allocation Length + 0x00 // Unused (control) + } + }; + + MS_CommandStatusWrapper_t SCSICommandStatus; + + if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, InquiryData)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + return PIPE_RWSTREAM_NoError; +} + +uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive)) + return HOST_SENDCONTROL_DeviceDisconnected; + + uint8_t ErrorCode; + + MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t) + { + .DataTransferLength = 0, + .Flags = COMMAND_DIRECTION_DATA_IN, + .LUN = LUNIndex, + .SCSICommandLength = 6, + .SCSICommandData = + { + SCSI_CMD_TEST_UNIT_READY, + 0x00, // Reserved + 0x00, // Reserved + 0x00, // Reserved + 0x00, // Reserved + 0x00 // Unused (control) + } + }; + + MS_CommandStatusWrapper_t SCSICommandStatus; + + if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + return PIPE_RWSTREAM_NoError; +} + +uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, + SCSI_Capacity_t* const DeviceCapacity) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive)) + return HOST_SENDCONTROL_DeviceDisconnected; + + uint8_t ErrorCode; + + MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t) + { + .DataTransferLength = sizeof(SCSI_Capacity_t), + .Flags = COMMAND_DIRECTION_DATA_IN, + .LUN = LUNIndex, + .SCSICommandLength = 10, + .SCSICommandData = + { + SCSI_CMD_READ_CAPACITY_10, + 0x00, // Reserved + 0x00, // MSB of Logical block address + 0x00, + 0x00, + 0x00, // LSB of Logical block address + 0x00, // Reserved + 0x00, // Reserved + 0x00, // Partial Medium Indicator + 0x00 // Unused (control) + } + }; + + MS_CommandStatusWrapper_t SCSICommandStatus; + + if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + SwapEndian_n(&DeviceCapacity->Blocks, sizeof(DeviceCapacity->Blocks)); + SwapEndian_n(&DeviceCapacity->BlockSize, sizeof(DeviceCapacity->BlockSize)); + + if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + return PIPE_RWSTREAM_NoError; +} + +uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, + SCSI_Request_Sense_Response_t* const SenseData) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive)) + return HOST_SENDCONTROL_DeviceDisconnected; + + uint8_t ErrorCode; + + MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t) + { + .DataTransferLength = sizeof(SCSI_Request_Sense_Response_t), + .Flags = COMMAND_DIRECTION_DATA_IN, + .LUN = LUNIndex, + .SCSICommandLength = 6, + .SCSICommandData = + { + SCSI_CMD_REQUEST_SENSE, + 0x00, // Reserved + 0x00, // Reserved + 0x00, // Reserved + sizeof(SCSI_Request_Sense_Response_t), // Allocation Length + 0x00 // Unused (control) + } + }; + + MS_CommandStatusWrapper_t SCSICommandStatus; + + if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, SenseData)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + return PIPE_RWSTREAM_NoError; +} + +uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, + const bool PreventRemoval) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive)) + return HOST_SENDCONTROL_DeviceDisconnected; + + uint8_t ErrorCode; + + MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t) + { + .DataTransferLength = 0, + .Flags = COMMAND_DIRECTION_DATA_OUT, + .LUN = LUNIndex, + .SCSICommandLength = 6, + .SCSICommandData = + { + SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL, + 0x00, // Reserved + 0x00, // Reserved + PreventRemoval, // Prevent flag + 0x00, // Reserved + 0x00 // Unused (control) + } + }; + + MS_CommandStatusWrapper_t SCSICommandStatus; + + if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + return PIPE_RWSTREAM_NoError; +} + +uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, const uint32_t BlockAddress, + const uint8_t Blocks, const uint16_t BlockSize, void* BlockBuffer) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive)) + return HOST_SENDCONTROL_DeviceDisconnected; + + uint8_t ErrorCode; + + MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t) + { + .DataTransferLength = ((uint32_t)Blocks * BlockSize), + .Flags = COMMAND_DIRECTION_DATA_IN, + .LUN = LUNIndex, + .SCSICommandLength = 10, + .SCSICommandData = + { + SCSI_CMD_READ_10, + 0x00, // Unused (control bits, all off) + (BlockAddress >> 24), // MSB of Block Address + (BlockAddress >> 16), + (BlockAddress >> 8), + (BlockAddress & 0xFF), // LSB of Block Address + 0x00, // Unused (reserved) + 0x00, // MSB of Total Blocks to Read + Blocks, // LSB of Total Blocks to Read + 0x00 // Unused (control) + } + }; + + MS_CommandStatusWrapper_t SCSICommandStatus; + + if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + return PIPE_RWSTREAM_NoError; +} + +uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, const uint32_t BlockAddress, + const uint8_t Blocks, const uint16_t BlockSize, const void* BlockBuffer) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive)) + return HOST_SENDCONTROL_DeviceDisconnected; + + uint8_t ErrorCode; + + MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t) + { + .DataTransferLength = ((uint32_t)Blocks * BlockSize), + .Flags = COMMAND_DIRECTION_DATA_OUT, + .LUN = LUNIndex, + .SCSICommandLength = 10, + .SCSICommandData = + { + SCSI_CMD_WRITE_10, + 0x00, // Unused (control bits, all off) + (BlockAddress >> 24), // MSB of Block Address + (BlockAddress >> 16), + (BlockAddress >> 8), + (BlockAddress & 0xFF), // LSB of Block Address + 0x00, // Unused (reserved) + 0x00, // MSB of Total Blocks to Write + Blocks, // LSB of Total Blocks to Write + 0x00 // Unused (control) + } + }; + + MS_CommandStatusWrapper_t SCSICommandStatus; + + if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + return PIPE_RWSTREAM_NoError; +} + +#endif diff --git a/LUFA/Drivers/USB/Class/Host/MassStorage.h b/LUFA/Drivers/USB/Class/Host/MassStorage.h index d2ab97009..992c5a0a6 100644 --- a/LUFA/Drivers/USB/Class/Host/MassStorage.h +++ b/LUFA/Drivers/USB/Class/Host/MassStorage.h @@ -1,339 +1,339 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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
- * \brief Host mode driver for the library USB Mass Storage Class driver.
- *
- * Host mode driver for the library USB Mass Storage Class driver.
- *
- * \note This file should not be included directly. It is automatically included as needed by the class driver
- * dispatch header located in LUFA/Drivers/USB/Class/MassStorage.h.
- */
-
-/** \ingroup Group_USBClassMS
- * @defgroup Group_USBClassMassStorageHost Mass Storage Class Host Mode Driver
- *
- * \section Sec_Dependencies Module Source Dependencies
- * The following files must be built with any user project that uses this module:
- * - LUFA/Drivers/USB/Class/Host/MassStorage.c
- *
- * \section Module Description
- * Host Mode USB Class driver framework interface, for the Mass Storage USB Class driver.
- *
- * @{
- */
-
-#ifndef __MS_CLASS_HOST_H__
-#define __MS_CLASS_HOST_H__
-
- /* Includes: */
- #include "../../USB.h"
- #include "../Common/MassStorage.h"
-
- /* Enable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- extern "C" {
- #endif
-
- /* Preprocessor Checks: */
- #if !defined(__INCLUDE_FROM_MS_DRIVER)
- #error Do not include this file directly. Include LUFA/Drivers/Class/MassStorage.h instead.
- #endif
-
- /* Public Interface - May be used in end-application: */
- /* Macros: */
- /** Error code for some Mass Storage Host functions, indicating a logical (and not hardware) error */
- #define MS_ERROR_LOGICAL_CMD_FAILED 0x80
-
- /* Type Defines: */
- /** \brief Mass Storage Class Host Mode Configuration and State Structure.
- *
- * Class state structure. An instance of this structure should be made within the user application,
- * and passed to each of the Mass Storage class driver functions as the MSInterfaceInfo parameter. This
- * stores each Mass Storage interface's configuration and state information.
- */
- typedef struct
- {
- const struct
- {
- uint8_t DataINPipeNumber; /**< Pipe number of the Mass Storage interface's IN data pipe */
- bool DataINPipeDoubleBank; /** Indicates if the Mass Storage interface's IN data pipe should use double banking */
-
- uint8_t DataOUTPipeNumber; /**< Pipe number of the Mass Storage interface's OUT data pipe */
- bool DataOUTPipeDoubleBank; /** Indicates if the Mass Storage interface's OUT data pipe should use double banking */
- } Config; /**< Config data for the USB class interface within the device. All elements in this section
- * <b>must</b> be set or the interface will fail to enumerate and operate correctly.
- */
- struct
- {
- bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
- * after \ref MS_Host_ConfigurePipes() is called and the Host state machine is in the
- * Configured state
- */
- uint8_t InterfaceNumber; /**< Interface index of the Mass Storage interface within the attached device */
-
- uint16_t DataINPipeSize; /**< Size in bytes of the Mass Storage interface's IN data pipe */
- uint16_t DataOUTPipeSize; /**< Size in bytes of the Mass Storage interface's OUT data pipe */
-
- uint32_t TransactionTag; /**< Current transaction tag for data synchronizing of packets */
- } State; /**< State data for the USB class interface within the device. All elements in this section
- * <b>may</b> be set to initial values, but may also be ignored to default to sane values when
- * the interface is enumerated.
- */
- } USB_ClassInfo_MS_Host_t;
-
- /** \brief SCSI Device LUN Capacity Structure.
- *
- * SCSI capacity structure, to hold the total capacity of the device in both the number
- * of blocks in the current LUN, and the size of each block. This structure is filled by
- * the device when the MassStore_ReadCapacity() function is called.
- */
- typedef struct
- {
- uint32_t Blocks; /**< Number of blocks in the addressed LUN of the device */
- uint32_t BlockSize; /**< Number of bytes in each block in the addressed LUN */
- } SCSI_Capacity_t;
-
- /* Enums: */
- enum MSHost_EnumerationFailure_ErrorCodes_t
- {
- MS_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */
- MS_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */
- MS_ENUMERROR_NoMSInterfaceFound = 2, /**< A compatible Mass Storage interface was not found in the device's Configuration Descriptor */
- MS_ENUMERROR_EndpointsNotFound = 3, /**< Compatible Mass Storage endpoints were not found in the device's interfaces */
- };
-
- /* Function Prototypes: */
- /** Host interface configuration routine, to configure a given Mass Storage host interface instance using the
- * Configuration Descriptor read from an attached USB device. This function automatically updates the given Mass
- * Storage Host instance's state values and configures the pipes required to communicate with the interface if it
- * is found within the device. This should be called once after the stack has enumerated the attached device, while
- * the host state machine is in the Addressed state.
- *
- * \param[in,out] MSInterfaceInfo Pointer to a structure containing an MS Class host configuration and state
- * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor
- * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor
- *
- * \return A value from the \ref MSHost_EnumerationFailure_ErrorCodes_t enum
- */
- uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
-
- /** Sends a MASS STORAGE RESET control request to the attached device, resetting the Mass Storage Interface
- * and readying it for the next Mass Storage command.
- *
- * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
- *
- * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum
- */
- uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Sends a GET MAX LUN control request to the attached device, retrieving the index of the highest LUN (Logical
- * UNit, a logical drive) in the device. This value can then be used in the other functions of the Mass Storage
- * Host mode Class driver to address a specific LUN within the device.
- *
- * \note Some devices do not support this request, and will STALL it when issued. To get around this,
- * on unsupported devices the max LUN index will be reported as zero and no error will be returned
- * if the device STALLs the request.
- *
- * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
- * \param[out] MaxLUNIndex Pointer to a location where the highest LUN index value should be stored
- *
- * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum
- */
- uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, uint8_t* const MaxLUNIndex)
- ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
-
- /** Retrieves the Mass Storage device's inquiry data for the specified LUN, indicating the device characteristics and
- * properties.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
- * \param[in] LUNIndex LUN index within the device the command is being issued to
- * \param[out] InquiryData Location where the read inquiry data should be stored
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED
- */
- uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
- SCSI_Inquiry_Response_t* const InquiryData) ATTR_NON_NULL_PTR_ARG(1)
- ATTR_NON_NULL_PTR_ARG(3);
-
- /** Sends a TEST UNIT READY command to the device, to determine if it is ready to accept other SCSI commands.
- *
- * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
- * \param[in] LUNIndex LUN index within the device the command is being issued to
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready
- */
- uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex)
- ATTR_NON_NULL_PTR_ARG(1);
-
- /** Retrieves the total capacity of the attached USB Mass Storage device, in blocks, and block size.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
- * \param[in] LUNIndex LUN index within the device the command is being issued to
- * \param[out] DeviceCapacity Pointer to the location where the capacity information should be stored
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready
- */
- uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
- SCSI_Capacity_t* const DeviceCapacity) ATTR_NON_NULL_PTR_ARG(1)
- ATTR_NON_NULL_PTR_ARG(3);
-
- /** Retrieves the device sense data, indicating the current device state and error codes for the previously
- * issued command.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
- * \param[in] LUNIndex LUN index within the device the command is being issued to
- * \param[out] SenseData Pointer to the location where the sense information should be stored
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready
- */
- uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
- SCSI_Request_Sense_Response_t* const SenseData) ATTR_NON_NULL_PTR_ARG(1)
- ATTR_NON_NULL_PTR_ARG(3);
-
- /** Issues a PREVENT MEDIUM REMOVAL command, to logically (or, depending on the type of device, physically) lock
- * the device from removal so that blocks of data on the medium can be read or altered.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
- * \param[in] LUNIndex LUN index within the device the command is being issued to
- * \param[in] PreventRemoval Boolean true if the device should be locked from removal, false otherwise
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready
- */
- uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
- const bool PreventRemoval) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Reads blocks of data from the attached Mass Storage device's medium.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
- * \param[in] LUNIndex LUN index within the device the command is being issued to
- * \param[in] BlockAddress Starting block address within the device to read from
- * \param[in] Blocks Total number of blocks to read
- * \param[in] BlockSize Size in bytes of each block within the device
- * \param[out] BlockBuffer Pointer to where the read data from the device should be stored
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready
- */
- uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
- const uint32_t BlockAddress, const uint8_t Blocks, const uint16_t BlockSize,
- void* BlockBuffer) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(6);
-
- /** Writes blocks of data to the attached Mass Storage device's medium.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
- * \param[in] LUNIndex LUN index within the device the command is being issued to
- * \param[in] BlockAddress Starting block address within the device to write to
- * \param[in] Blocks Total number of blocks to read
- * \param[in] BlockSize Size in bytes of each block within the device
- * \param[in] BlockBuffer Pointer to where the data to write should be sourced from
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready
- */
- uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
- const uint32_t BlockAddress, const uint8_t Blocks, const uint16_t BlockSize,
- const void* BlockBuffer) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(6);
-
- /* Inline Functions: */
- /** General management task for a given Mass Storage host class interface, required for the correct operation of
- * the interface. This should be called frequently in the main program loop, before the master USB management task
- * \ref USB_USBTask().
- *
- * \param[in,out] MSInterfaceInfo Pointer to a structure containing an MS Class host configuration and state
- */
- static inline void MS_Host_USBTask(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo);
- static inline void MS_Host_USBTask(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
- {
- (void)MSInterfaceInfo;
- }
-
- /* Private Interface - For use in library only: */
- #if !defined(__DOXYGEN__)
- /* Macros: */
- #define MASS_STORE_CLASS 0x08
- #define MASS_STORE_SUBCLASS 0x06
- #define MASS_STORE_PROTOCOL 0x50
-
- #define REQ_MassStorageReset 0xFF
- #define REQ_GetMaxLUN 0xFE
-
- #define CBW_SIGNATURE 0x43425355UL
- #define CSW_SIGNATURE 0x53425355UL
-
- #define COMMAND_DIRECTION_DATA_OUT (0 << 7)
- #define COMMAND_DIRECTION_DATA_IN (1 << 7)
-
- #define COMMAND_DATA_TIMEOUT_MS 10000
-
- #define MS_FOUND_DATAPIPE_IN (1 << 0)
- #define MS_FOUND_DATAPIPE_OUT (1 << 1)
-
- /* Function Prototypes: */
- #if defined(__INCLUDE_FROM_MS_CLASS_HOST_C)
- static uint8_t DComp_NextMSInterface(void* const CurrentDescriptor);
- static uint8_t DComp_NextMSInterfaceEndpoint(void* const CurrentDescriptor);
-
- static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
- MS_CommandBlockWrapper_t* const SCSICommandBlock,
- const void* const BufferPtr);
- static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo);
- static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
- MS_CommandBlockWrapper_t* const SCSICommandBlock, void* BufferPtr);
- static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
- MS_CommandStatusWrapper_t* const SCSICommandStatus);
- #endif
- #endif
-
- /* Disable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- }
- #endif
-
-#endif
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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 + * \brief Host mode driver for the library USB Mass Storage Class driver. + * + * Host mode driver for the library USB Mass Storage Class driver. + * + * \note This file should not be included directly. It is automatically included as needed by the class driver + * dispatch header located in LUFA/Drivers/USB/Class/MassStorage.h. + */ + +/** \ingroup Group_USBClassMS + * @defgroup Group_USBClassMassStorageHost Mass Storage Class Host Mode Driver + * + * \section Sec_Dependencies Module Source Dependencies + * The following files must be built with any user project that uses this module: + * - LUFA/Drivers/USB/Class/Host/MassStorage.c + * + * \section Module Description + * Host Mode USB Class driver framework interface, for the Mass Storage USB Class driver. + * + * @{ + */ + +#ifndef __MS_CLASS_HOST_H__ +#define __MS_CLASS_HOST_H__ + + /* Includes: */ + #include "../../USB.h" + #include "../Common/MassStorage.h" + + /* Enable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + extern "C" { + #endif + + /* Preprocessor Checks: */ + #if !defined(__INCLUDE_FROM_MS_DRIVER) + #error Do not include this file directly. Include LUFA/Drivers/Class/MassStorage.h instead. + #endif + + /* Public Interface - May be used in end-application: */ + /* Macros: */ + /** Error code for some Mass Storage Host functions, indicating a logical (and not hardware) error */ + #define MS_ERROR_LOGICAL_CMD_FAILED 0x80 + + /* Type Defines: */ + /** \brief Mass Storage Class Host Mode Configuration and State Structure. + * + * Class state structure. An instance of this structure should be made within the user application, + * and passed to each of the Mass Storage class driver functions as the MSInterfaceInfo parameter. This + * stores each Mass Storage interface's configuration and state information. + */ + typedef struct + { + const struct + { + uint8_t DataINPipeNumber; /**< Pipe number of the Mass Storage interface's IN data pipe */ + bool DataINPipeDoubleBank; /** Indicates if the Mass Storage interface's IN data pipe should use double banking */ + + uint8_t DataOUTPipeNumber; /**< Pipe number of the Mass Storage interface's OUT data pipe */ + bool DataOUTPipeDoubleBank; /** Indicates if the Mass Storage interface's OUT data pipe should use double banking */ + } Config; /**< Config data for the USB class interface within the device. All elements in this section + * <b>must</b> be set or the interface will fail to enumerate and operate correctly. + */ + struct + { + bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid + * after \ref MS_Host_ConfigurePipes() is called and the Host state machine is in the + * Configured state + */ + uint8_t InterfaceNumber; /**< Interface index of the Mass Storage interface within the attached device */ + + uint16_t DataINPipeSize; /**< Size in bytes of the Mass Storage interface's IN data pipe */ + uint16_t DataOUTPipeSize; /**< Size in bytes of the Mass Storage interface's OUT data pipe */ + + uint32_t TransactionTag; /**< Current transaction tag for data synchronizing of packets */ + } State; /**< State data for the USB class interface within the device. All elements in this section + * <b>may</b> be set to initial values, but may also be ignored to default to sane values when + * the interface is enumerated. + */ + } USB_ClassInfo_MS_Host_t; + + /** \brief SCSI Device LUN Capacity Structure. + * + * SCSI capacity structure, to hold the total capacity of the device in both the number + * of blocks in the current LUN, and the size of each block. This structure is filled by + * the device when the MassStore_ReadCapacity() function is called. + */ + typedef struct + { + uint32_t Blocks; /**< Number of blocks in the addressed LUN of the device */ + uint32_t BlockSize; /**< Number of bytes in each block in the addressed LUN */ + } SCSI_Capacity_t; + + /* Enums: */ + enum MSHost_EnumerationFailure_ErrorCodes_t + { + MS_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */ + MS_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */ + MS_ENUMERROR_NoMSInterfaceFound = 2, /**< A compatible Mass Storage interface was not found in the device's Configuration Descriptor */ + MS_ENUMERROR_EndpointsNotFound = 3, /**< Compatible Mass Storage endpoints were not found in the device's interfaces */ + }; + + /* Function Prototypes: */ + /** Host interface configuration routine, to configure a given Mass Storage host interface instance using the + * Configuration Descriptor read from an attached USB device. This function automatically updates the given Mass + * Storage Host instance's state values and configures the pipes required to communicate with the interface if it + * is found within the device. This should be called once after the stack has enumerated the attached device, while + * the host state machine is in the Addressed state. + * + * \param[in,out] MSInterfaceInfo Pointer to a structure containing an MS Class host configuration and state + * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor + * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor + * + * \return A value from the \ref MSHost_EnumerationFailure_ErrorCodes_t enum + */ + uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, uint16_t ConfigDescriptorSize, + void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3); + + /** Sends a MASS STORAGE RESET control request to the attached device, resetting the Mass Storage Interface + * and readying it for the next Mass Storage command. + * + * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state + * + * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum + */ + uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Sends a GET MAX LUN control request to the attached device, retrieving the index of the highest LUN (Logical + * UNit, a logical drive) in the device. This value can then be used in the other functions of the Mass Storage + * Host mode Class driver to address a specific LUN within the device. + * + * \note Some devices do not support this request, and will STALL it when issued. To get around this, + * on unsupported devices the max LUN index will be reported as zero and no error will be returned + * if the device STALLs the request. + * + * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state + * \param[out] MaxLUNIndex Pointer to a location where the highest LUN index value should be stored + * + * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum + */ + uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, uint8_t* const MaxLUNIndex) + ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + + /** Retrieves the Mass Storage device's inquiry data for the specified LUN, indicating the device characteristics and + * properties. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state + * \param[in] LUNIndex LUN index within the device the command is being issued to + * \param[out] InquiryData Location where the read inquiry data should be stored + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED + */ + uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, + SCSI_Inquiry_Response_t* const InquiryData) ATTR_NON_NULL_PTR_ARG(1) + ATTR_NON_NULL_PTR_ARG(3); + + /** Sends a TEST UNIT READY command to the device, to determine if it is ready to accept other SCSI commands. + * + * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state + * \param[in] LUNIndex LUN index within the device the command is being issued to + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready + */ + uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex) + ATTR_NON_NULL_PTR_ARG(1); + + /** Retrieves the total capacity of the attached USB Mass Storage device, in blocks, and block size. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state + * \param[in] LUNIndex LUN index within the device the command is being issued to + * \param[out] DeviceCapacity Pointer to the location where the capacity information should be stored + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready + */ + uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, + SCSI_Capacity_t* const DeviceCapacity) ATTR_NON_NULL_PTR_ARG(1) + ATTR_NON_NULL_PTR_ARG(3); + + /** Retrieves the device sense data, indicating the current device state and error codes for the previously + * issued command. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state + * \param[in] LUNIndex LUN index within the device the command is being issued to + * \param[out] SenseData Pointer to the location where the sense information should be stored + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready + */ + uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, + SCSI_Request_Sense_Response_t* const SenseData) ATTR_NON_NULL_PTR_ARG(1) + ATTR_NON_NULL_PTR_ARG(3); + + /** Issues a PREVENT MEDIUM REMOVAL command, to logically (or, depending on the type of device, physically) lock + * the device from removal so that blocks of data on the medium can be read or altered. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state + * \param[in] LUNIndex LUN index within the device the command is being issued to + * \param[in] PreventRemoval Boolean true if the device should be locked from removal, false otherwise + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready + */ + uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, + const bool PreventRemoval) ATTR_NON_NULL_PTR_ARG(1); + + /** Reads blocks of data from the attached Mass Storage device's medium. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state + * \param[in] LUNIndex LUN index within the device the command is being issued to + * \param[in] BlockAddress Starting block address within the device to read from + * \param[in] Blocks Total number of blocks to read + * \param[in] BlockSize Size in bytes of each block within the device + * \param[out] BlockBuffer Pointer to where the read data from the device should be stored + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready + */ + uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, + const uint32_t BlockAddress, const uint8_t Blocks, const uint16_t BlockSize, + void* BlockBuffer) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(6); + + /** Writes blocks of data to the attached Mass Storage device's medium. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state + * \param[in] LUNIndex LUN index within the device the command is being issued to + * \param[in] BlockAddress Starting block address within the device to write to + * \param[in] Blocks Total number of blocks to read + * \param[in] BlockSize Size in bytes of each block within the device + * \param[in] BlockBuffer Pointer to where the data to write should be sourced from + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready + */ + uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, + const uint32_t BlockAddress, const uint8_t Blocks, const uint16_t BlockSize, + const void* BlockBuffer) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(6); + + /* Inline Functions: */ + /** General management task for a given Mass Storage host class interface, required for the correct operation of + * the interface. This should be called frequently in the main program loop, before the master USB management task + * \ref USB_USBTask(). + * + * \param[in,out] MSInterfaceInfo Pointer to a structure containing an MS Class host configuration and state + */ + static inline void MS_Host_USBTask(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo); + static inline void MS_Host_USBTask(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo) + { + (void)MSInterfaceInfo; + } + + /* Private Interface - For use in library only: */ + #if !defined(__DOXYGEN__) + /* Macros: */ + #define MASS_STORE_CLASS 0x08 + #define MASS_STORE_SUBCLASS 0x06 + #define MASS_STORE_PROTOCOL 0x50 + + #define REQ_MassStorageReset 0xFF + #define REQ_GetMaxLUN 0xFE + + #define CBW_SIGNATURE 0x43425355UL + #define CSW_SIGNATURE 0x53425355UL + + #define COMMAND_DIRECTION_DATA_OUT (0 << 7) + #define COMMAND_DIRECTION_DATA_IN (1 << 7) + + #define COMMAND_DATA_TIMEOUT_MS 10000 + + #define MS_FOUND_DATAPIPE_IN (1 << 0) + #define MS_FOUND_DATAPIPE_OUT (1 << 1) + + /* Function Prototypes: */ + #if defined(__INCLUDE_FROM_MS_CLASS_HOST_C) + static uint8_t DComp_NextMSInterface(void* const CurrentDescriptor); + static uint8_t DComp_NextMSInterfaceEndpoint(void* const CurrentDescriptor); + + static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, + MS_CommandBlockWrapper_t* const SCSICommandBlock, + const void* const BufferPtr); + static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo); + static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, + MS_CommandBlockWrapper_t* const SCSICommandBlock, void* BufferPtr); + static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, + MS_CommandStatusWrapper_t* const SCSICommandStatus); + #endif + #endif + + /* Disable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + } + #endif + +#endif + +/** @} */ diff --git a/LUFA/Drivers/USB/Class/Host/Printer.c b/LUFA/Drivers/USB/Class/Host/Printer.c index 2d41a0c39..e291ae398 100644 --- a/LUFA/Drivers/USB/Class/Host/Printer.c +++ b/LUFA/Drivers/USB/Class/Host/Printer.c @@ -1,250 +1,250 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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_USB_DRIVER
-#include "../../HighLevel/USBMode.h"
-#if defined(USB_CAN_BE_HOST)
-
-#define __INCLUDE_FROM_PRINTER_CLASS_HOST_C
-#define __INCLUDE_FROM_PRINTER_DRIVER
-#include "Printer.h"
-
-uint8_t PRNT_Host_ConfigurePipes(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* DeviceConfigDescriptor)
-{
- uint8_t FoundEndpoints = 0;
-
- memset(&PRNTInterfaceInfo->State, 0x00, sizeof(PRNTInterfaceInfo->State));
-
- if (DESCRIPTOR_TYPE(DeviceConfigDescriptor) != DTYPE_Configuration)
- return PRNT_ENUMERROR_InvalidConfigDescriptor;
-
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor,
- DComp_NextPRNTInterface) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return PRNT_ENUMERROR_NoPrinterInterfaceFound;
- }
-
- USB_Descriptor_Interface_t* PrinterInterface = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Interface_t);
-
- PRNTInterfaceInfo->State.InterfaceNumber = PrinterInterface->InterfaceNumber;
- PRNTInterfaceInfo->State.AlternateSetting = PrinterInterface->AlternateSetting;
-
- while (FoundEndpoints != (PRNT_FOUND_DATAPIPE_IN | PRNT_FOUND_DATAPIPE_OUT))
- {
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor,
- DComp_NextPRNTInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return PRNT_ENUMERROR_EndpointsNotFound;
- }
-
- USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Endpoint_t);
-
- if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
- {
- Pipe_ConfigurePipe(PRNTInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- PRNTInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- PRNTInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize;
-
- FoundEndpoints |= PRNT_FOUND_DATAPIPE_IN;
- }
- else
- {
- Pipe_ConfigurePipe(PRNTInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- PRNTInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- PRNTInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize;
-
- FoundEndpoints |= PRNT_FOUND_DATAPIPE_OUT;
- }
- }
-
- PRNTInterfaceInfo->State.IsActive = true;
- return PRNT_ENUMERROR_NoError;
-}
-
-static uint8_t DComp_NextPRNTInterface(void* CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- if ((DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Class == PRINTER_CLASS) &&
- (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).SubClass == PRINTER_SUBCLASS) &&
- (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Protocol == PRINTER_PROTOCOL))
- {
- return DESCRIPTOR_SEARCH_Found;
- }
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-static uint8_t DComp_NextPRNTInterfaceEndpoint(void* CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
- {
- uint8_t EndpointType = (DESCRIPTOR_CAST(CurrentDescriptor,
- USB_Descriptor_Endpoint_t).Attributes & EP_TYPE_MASK);
-
- if (EndpointType == EP_TYPE_BULK)
- return DESCRIPTOR_SEARCH_Found;
- }
- else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- return DESCRIPTOR_SEARCH_Fail;
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-uint8_t PRNT_Host_SetBidirectionalMode(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo)
-{
- if (PRNTInterfaceInfo->State.AlternateSetting)
- {
- uint8_t ErrorCode;
-
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE),
- .bRequest = REQ_SetInterface,
- .wValue = PRNTInterfaceInfo->State.AlternateSetting,
- .wIndex = PRNTInterfaceInfo->State.InterfaceNumber,
- .wLength = 0,
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
-
- if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
- return ErrorCode;
- }
-
- return HOST_SENDCONTROL_Successful;
-}
-
-uint8_t PRNT_Host_GetPortStatus(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, uint8_t* const PortStatus)
-{
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_GetPortStatus,
- .wValue = 0,
- .wIndex = PRNTInterfaceInfo->State.InterfaceNumber,
- .wLength = sizeof(uint8_t),
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
-
- return USB_Host_SendControlRequest(PortStatus);
-}
-
-uint8_t PRNT_Host_SoftReset(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo)
-{
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_SoftReset,
- .wValue = 0,
- .wIndex = PRNTInterfaceInfo->State.InterfaceNumber,
- .wLength = 0,
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
-
- return USB_Host_SendControlRequest(NULL);
-}
-
-uint8_t PRNT_Host_SendData(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, void* PrinterCommands, uint16_t CommandSize)
-{
- uint8_t ErrorCode;
-
- if ((USB_HostState != HOST_STATE_Configured) || !(PRNTInterfaceInfo->State.IsActive))
- return PIPE_RWSTREAM_DeviceDisconnected;
-
- Pipe_SelectPipe(PRNTInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_Unfreeze();
-
- if ((ErrorCode = Pipe_Write_Stream_LE(PrinterCommands, CommandSize, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- Pipe_ClearOUT();
- while (!(Pipe_IsOUTReady()))
- {
- if (USB_HostState == HOST_STATE_Unattached)
- return PIPE_RWSTREAM_DeviceDisconnected;
- }
-
- Pipe_Freeze();
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t PRNT_Host_GetDeviceID(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, char* DeviceIDString, uint16_t BufferSize)
-{
- uint8_t ErrorCode = HOST_SENDCONTROL_Successful;
- uint16_t DeviceIDStringLength = 0;
-
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_GetDeviceID,
- .wValue = 0,
- .wIndex = PRNTInterfaceInfo->State.InterfaceNumber,
- .wLength = sizeof(DeviceIDStringLength),
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
-
- if ((ErrorCode = USB_Host_SendControlRequest(&DeviceIDStringLength)) != HOST_SENDCONTROL_Successful)
- return ErrorCode;
-
- if (!(DeviceIDStringLength))
- {
- DeviceIDString[0] = 0x00;
- return HOST_SENDCONTROL_Successful;
- }
-
- DeviceIDStringLength = SwapEndian_16(DeviceIDStringLength);
-
- if (DeviceIDStringLength > BufferSize)
- DeviceIDStringLength = BufferSize;
-
- USB_ControlRequest.wLength = DeviceIDStringLength;
-
- if ((ErrorCode = USB_Host_SendControlRequest(DeviceIDString)) != HOST_SENDCONTROL_Successful)
- return ErrorCode;
-
- memmove(&DeviceIDString[0], &DeviceIDString[2], DeviceIDStringLength - 2);
-
- DeviceIDString[DeviceIDStringLength - 2] = 0x00;
-
- return HOST_SENDCONTROL_Successful;
-}
-
-#endif
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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_USB_DRIVER +#include "../../HighLevel/USBMode.h" +#if defined(USB_CAN_BE_HOST) + +#define __INCLUDE_FROM_PRINTER_CLASS_HOST_C +#define __INCLUDE_FROM_PRINTER_DRIVER +#include "Printer.h" + +uint8_t PRNT_Host_ConfigurePipes(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, uint16_t ConfigDescriptorSize, + void* DeviceConfigDescriptor) +{ + uint8_t FoundEndpoints = 0; + + memset(&PRNTInterfaceInfo->State, 0x00, sizeof(PRNTInterfaceInfo->State)); + + if (DESCRIPTOR_TYPE(DeviceConfigDescriptor) != DTYPE_Configuration) + return PRNT_ENUMERROR_InvalidConfigDescriptor; + + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor, + DComp_NextPRNTInterface) != DESCRIPTOR_SEARCH_COMP_Found) + { + return PRNT_ENUMERROR_NoPrinterInterfaceFound; + } + + USB_Descriptor_Interface_t* PrinterInterface = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Interface_t); + + PRNTInterfaceInfo->State.InterfaceNumber = PrinterInterface->InterfaceNumber; + PRNTInterfaceInfo->State.AlternateSetting = PrinterInterface->AlternateSetting; + + while (FoundEndpoints != (PRNT_FOUND_DATAPIPE_IN | PRNT_FOUND_DATAPIPE_OUT)) + { + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor, + DComp_NextPRNTInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found) + { + return PRNT_ENUMERROR_EndpointsNotFound; + } + + USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Endpoint_t); + + if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN) + { + Pipe_ConfigurePipe(PRNTInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + PRNTInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + PRNTInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize; + + FoundEndpoints |= PRNT_FOUND_DATAPIPE_IN; + } + else + { + Pipe_ConfigurePipe(PRNTInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + PRNTInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + PRNTInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize; + + FoundEndpoints |= PRNT_FOUND_DATAPIPE_OUT; + } + } + + PRNTInterfaceInfo->State.IsActive = true; + return PRNT_ENUMERROR_NoError; +} + +static uint8_t DComp_NextPRNTInterface(void* CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + if ((DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Class == PRINTER_CLASS) && + (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).SubClass == PRINTER_SUBCLASS) && + (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Protocol == PRINTER_PROTOCOL)) + { + return DESCRIPTOR_SEARCH_Found; + } + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +static uint8_t DComp_NextPRNTInterfaceEndpoint(void* CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint) + { + uint8_t EndpointType = (DESCRIPTOR_CAST(CurrentDescriptor, + USB_Descriptor_Endpoint_t).Attributes & EP_TYPE_MASK); + + if (EndpointType == EP_TYPE_BULK) + return DESCRIPTOR_SEARCH_Found; + } + else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + return DESCRIPTOR_SEARCH_Fail; + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +uint8_t PRNT_Host_SetBidirectionalMode(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo) +{ + if (PRNTInterfaceInfo->State.AlternateSetting) + { + uint8_t ErrorCode; + + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE), + .bRequest = REQ_SetInterface, + .wValue = PRNTInterfaceInfo->State.AlternateSetting, + .wIndex = PRNTInterfaceInfo->State.InterfaceNumber, + .wLength = 0, + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful) + return ErrorCode; + } + + return HOST_SENDCONTROL_Successful; +} + +uint8_t PRNT_Host_GetPortStatus(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, uint8_t* const PortStatus) +{ + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_GetPortStatus, + .wValue = 0, + .wIndex = PRNTInterfaceInfo->State.InterfaceNumber, + .wLength = sizeof(uint8_t), + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + return USB_Host_SendControlRequest(PortStatus); +} + +uint8_t PRNT_Host_SoftReset(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo) +{ + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_SoftReset, + .wValue = 0, + .wIndex = PRNTInterfaceInfo->State.InterfaceNumber, + .wLength = 0, + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + return USB_Host_SendControlRequest(NULL); +} + +uint8_t PRNT_Host_SendData(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, void* PrinterCommands, uint16_t CommandSize) +{ + uint8_t ErrorCode; + + if ((USB_HostState != HOST_STATE_Configured) || !(PRNTInterfaceInfo->State.IsActive)) + return PIPE_RWSTREAM_DeviceDisconnected; + + Pipe_SelectPipe(PRNTInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_Unfreeze(); + + if ((ErrorCode = Pipe_Write_Stream_LE(PrinterCommands, CommandSize, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + Pipe_ClearOUT(); + while (!(Pipe_IsOUTReady())) + { + if (USB_HostState == HOST_STATE_Unattached) + return PIPE_RWSTREAM_DeviceDisconnected; + } + + Pipe_Freeze(); + + return PIPE_RWSTREAM_NoError; +} + +uint8_t PRNT_Host_GetDeviceID(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, char* DeviceIDString, uint16_t BufferSize) +{ + uint8_t ErrorCode = HOST_SENDCONTROL_Successful; + uint16_t DeviceIDStringLength = 0; + + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_GetDeviceID, + .wValue = 0, + .wIndex = PRNTInterfaceInfo->State.InterfaceNumber, + .wLength = sizeof(DeviceIDStringLength), + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + + if ((ErrorCode = USB_Host_SendControlRequest(&DeviceIDStringLength)) != HOST_SENDCONTROL_Successful) + return ErrorCode; + + if (!(DeviceIDStringLength)) + { + DeviceIDString[0] = 0x00; + return HOST_SENDCONTROL_Successful; + } + + DeviceIDStringLength = SwapEndian_16(DeviceIDStringLength); + + if (DeviceIDStringLength > BufferSize) + DeviceIDStringLength = BufferSize; + + USB_ControlRequest.wLength = DeviceIDStringLength; + + if ((ErrorCode = USB_Host_SendControlRequest(DeviceIDString)) != HOST_SENDCONTROL_Successful) + return ErrorCode; + + memmove(&DeviceIDString[0], &DeviceIDString[2], DeviceIDStringLength - 2); + + DeviceIDString[DeviceIDStringLength - 2] = 0x00; + + return HOST_SENDCONTROL_Successful; +} + +#endif diff --git a/LUFA/Drivers/USB/Class/Host/Printer.h b/LUFA/Drivers/USB/Class/Host/Printer.h index 04286ca32..92f1f22ae 100644 --- a/LUFA/Drivers/USB/Class/Host/Printer.h +++ b/LUFA/Drivers/USB/Class/Host/Printer.h @@ -1,233 +1,233 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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
- * \brief Host mode driver for the library USB Printer Class driver.
- *
- * Host mode driver for the library USB Printer Class driver.
- *
- * \note This file should not be included directly. It is automatically included as needed by the class driver
- * dispatch header located in LUFA/Drivers/USB/Class/Printer.h.
- */
-
-/** \ingroup Group_USBClassPrinter
- * @defgroup Group_USBClassPrinterHost Printer Class Host Mode Driver
- *
- * \section Sec_Dependencies Module Source Dependencies
- * The following files must be built with any user project that uses this module:
- * - LUFA/Drivers/USB/Class/Host/Printer.c
- *
- * \section Module Description
- * Host Mode USB Class driver framework interface, for the Printer USB Class driver.
- *
- * @{
- */
-
-#ifndef __PRINTER_CLASS_HOST_H__
-#define __PRINTER_CLASS_HOST_H__
-
- /* Includes: */
- #include "../../USB.h"
- #include "../Common/Printer.h"
-
- /* Enable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- extern "C" {
- #endif
-
- /* Preprocessor Checks: */
- #if !defined(__INCLUDE_FROM_PRINTER_DRIVER)
- #error Do not include this file directly. Include LUFA/Drivers/Class/Printer.h instead.
- #endif
-
- /* Public Interface - May be used in end-application: */
- /* Type Defines: */
- /** \brief Printer Class Host Mode Configuration and State Structure.
- *
- * Class state structure. An instance of this structure should be made within the user application,
- * and passed to each of the Printer class driver functions as the PRNTInterfaceInfo parameter. This
- * stores each Printer interface's configuration and state information.
- */
- typedef struct
- {
- const struct
- {
- uint8_t DataINPipeNumber; /**< Pipe number of the Printer interface's IN data pipe */
- bool DataINPipeDoubleBank; /** Indicates if the Printer interface's IN data pipe should use double banking */
-
- uint8_t DataOUTPipeNumber; /**< Pipe number of the Printer interface's OUT data pipe */
- bool DataOUTPipeDoubleBank; /** Indicates if the Printer interface's OUT data pipe should use double banking */
- } Config; /**< Config data for the USB class interface within the device. All elements in this section
- * <b>must</b> be set or the interface will fail to enumerate and operate correctly.
- */
- struct
- {
- bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
- * after \ref PRNT_Host_ConfigurePipes() is called and the Host state machine is in the
- * Configured state
- */
- uint8_t InterfaceNumber; /**< Interface index of the Printer interface within the attached device */
- uint8_t AlternateSetting; /**< Alternate setting within the Printer Interface in the attached device */
-
- uint16_t DataINPipeSize; /**< Size in bytes of the Printer interface's IN data pipe */
- uint16_t DataOUTPipeSize; /**< Size in bytes of the Printer interface's OUT data pipe */
- } State; /**< State data for the USB class interface within the device. All elements in this section
- * <b>may</b> be set to initial values, but may also be ignored to default to sane values when
- * the interface is enumerated.
- */
- } USB_ClassInfo_PRNT_Host_t;
-
- /* Enums: */
- enum PRNTHost_EnumerationFailure_ErrorCodes_t
- {
- PRNT_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */
- PRNT_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */
- PRNT_ENUMERROR_NoPrinterInterfaceFound = 2, /**< A compatible Printer interface was not found in the device's Configuration Descriptor */
- PRNT_ENUMERROR_EndpointsNotFound = 3, /**< Compatible Printer endpoints were not found in the device's interfaces */
- };
-
- /* Function Prototypes: */
- /** Host interface configuration routine, to configure a given Printer host interface instance using the
- * Configuration Descriptor read from an attached USB device. This function automatically updates the given Printer
- * instance's state values and configures the pipes required to communicate with the interface if it is found within
- * the device. This should be called once after the stack has enumerated the attached device, while the host state
- * machine is in the Addressed state.
- *
- * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state
- * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor
- * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor
- *
- * \return A value from the \ref PRNTHost_EnumerationFailure_ErrorCodes_t enum
- */
- uint8_t PRNT_Host_ConfigurePipes(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
-
- /** Configures the printer to enable Bidirectional mode, if it is not already in this mode. This should be called
- * once the connected device's configuration has been set, to ensure the printer is ready to accept commands.
- *
- * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state
- *
- * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum
- */
- uint8_t PRNT_Host_SetBidirectionalMode(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Retrieves the status of the virtual Printer port's inbound status lines. The result can then be masked against the
- * PRNT_PORTSTATUS_* macros to determine the printer port's status.
- *
- * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state
- * \param[out] PortStatus Location where the retrieved port status should be stored
- *
- * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum
- */
- uint8_t PRNT_Host_GetPortStatus(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, uint8_t* const PortStatus)
- ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
-
- /** Soft-resets the attached printer, readying it for new commands.
- *
- * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state
- *
- * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum
- */
- uint8_t PRNT_Host_SoftReset(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Sends the given raw data stream to the attached printer's input endpoint. This should contain commands that the
- * printer is able to understand - for example, PCL data. Not all printers accept all printer languages; see
- * \ref PRNT_Host_GetDeviceID() for details on determining acceptable languages for an attached printer.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state
- * \param[in] PrinterCommands Pointer to a buffer containing the raw command stream to send to the printer
- * \param[in] CommandSize Size in bytes of the command stream to be sent
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum
- */
- uint8_t PRNT_Host_SendData(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, void* PrinterCommands,
- uint16_t CommandSize) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
-
- /** Retrieves the attached printer device's ID string, formatted according to IEEE 1284. This string is sent as a
- * Unicode string from the device and is automatically converted to an ASCII encoded C string by this function, thus
- * the maximum reportable string length is two less than the size given (to accommodate the Unicode string length
- * bytes which are removed).
- *
- * This string, when supported, contains the model, manufacturer and acceptable printer languages for the attached device.
- *
- * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state
- * \param[out] DeviceIDString Pointer to a buffer where the Device ID string should be stored, in ASCII format
- * \param[in] BufferSize Size in bytes of the buffer allocated for the Device ID string
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum
- */
- uint8_t PRNT_Host_GetDeviceID(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, char* DeviceIDString,
- uint16_t BufferSize) ATTR_NON_NULL_PTR_ARG(1);
-
- /* Inline Functions: */
- /** General management task for a given Printer host class interface, required for the correct operation of
- * the interface. This should be called frequently in the main program loop, before the master USB management task
- * \ref USB_USBTask().
- *
- * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state
- */
- static inline void PRNT_Host_USBTask(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo);
- static inline void PRNT_Host_USBTask(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo)
- {
- (void)PRNTInterfaceInfo;
- }
-
- /* Private Interface - For use in library only: */
- #if !defined(__DOXYGEN__)
- /* Macros: */
- #define PRINTER_CLASS 0x07
- #define PRINTER_SUBCLASS 0x01
- #define PRINTER_PROTOCOL 0x02
-
- #define REQ_GetDeviceID 0
- #define REQ_GetPortStatus 1
- #define REQ_SoftReset 2
-
- #define PRNT_FOUND_DATAPIPE_IN (1 << 0)
- #define PRNT_FOUND_DATAPIPE_OUT (1 << 1)
-
- /* Function Prototypes: */
- #if defined(__INCLUDE_FROM_PRINTER_CLASS_HOST_C)
- static uint8_t DComp_NextPRNTInterface(void* const CurrentDescriptor);
- static uint8_t DComp_NextPRNTInterfaceEndpoint(void* const CurrentDescriptor);
- #endif
- #endif
-
- /* Disable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- }
- #endif
-
-#endif
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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 + * \brief Host mode driver for the library USB Printer Class driver. + * + * Host mode driver for the library USB Printer Class driver. + * + * \note This file should not be included directly. It is automatically included as needed by the class driver + * dispatch header located in LUFA/Drivers/USB/Class/Printer.h. + */ + +/** \ingroup Group_USBClassPrinter + * @defgroup Group_USBClassPrinterHost Printer Class Host Mode Driver + * + * \section Sec_Dependencies Module Source Dependencies + * The following files must be built with any user project that uses this module: + * - LUFA/Drivers/USB/Class/Host/Printer.c + * + * \section Module Description + * Host Mode USB Class driver framework interface, for the Printer USB Class driver. + * + * @{ + */ + +#ifndef __PRINTER_CLASS_HOST_H__ +#define __PRINTER_CLASS_HOST_H__ + + /* Includes: */ + #include "../../USB.h" + #include "../Common/Printer.h" + + /* Enable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + extern "C" { + #endif + + /* Preprocessor Checks: */ + #if !defined(__INCLUDE_FROM_PRINTER_DRIVER) + #error Do not include this file directly. Include LUFA/Drivers/Class/Printer.h instead. + #endif + + /* Public Interface - May be used in end-application: */ + /* Type Defines: */ + /** \brief Printer Class Host Mode Configuration and State Structure. + * + * Class state structure. An instance of this structure should be made within the user application, + * and passed to each of the Printer class driver functions as the PRNTInterfaceInfo parameter. This + * stores each Printer interface's configuration and state information. + */ + typedef struct + { + const struct + { + uint8_t DataINPipeNumber; /**< Pipe number of the Printer interface's IN data pipe */ + bool DataINPipeDoubleBank; /** Indicates if the Printer interface's IN data pipe should use double banking */ + + uint8_t DataOUTPipeNumber; /**< Pipe number of the Printer interface's OUT data pipe */ + bool DataOUTPipeDoubleBank; /** Indicates if the Printer interface's OUT data pipe should use double banking */ + } Config; /**< Config data for the USB class interface within the device. All elements in this section + * <b>must</b> be set or the interface will fail to enumerate and operate correctly. + */ + struct + { + bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid + * after \ref PRNT_Host_ConfigurePipes() is called and the Host state machine is in the + * Configured state + */ + uint8_t InterfaceNumber; /**< Interface index of the Printer interface within the attached device */ + uint8_t AlternateSetting; /**< Alternate setting within the Printer Interface in the attached device */ + + uint16_t DataINPipeSize; /**< Size in bytes of the Printer interface's IN data pipe */ + uint16_t DataOUTPipeSize; /**< Size in bytes of the Printer interface's OUT data pipe */ + } State; /**< State data for the USB class interface within the device. All elements in this section + * <b>may</b> be set to initial values, but may also be ignored to default to sane values when + * the interface is enumerated. + */ + } USB_ClassInfo_PRNT_Host_t; + + /* Enums: */ + enum PRNTHost_EnumerationFailure_ErrorCodes_t + { + PRNT_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */ + PRNT_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */ + PRNT_ENUMERROR_NoPrinterInterfaceFound = 2, /**< A compatible Printer interface was not found in the device's Configuration Descriptor */ + PRNT_ENUMERROR_EndpointsNotFound = 3, /**< Compatible Printer endpoints were not found in the device's interfaces */ + }; + + /* Function Prototypes: */ + /** Host interface configuration routine, to configure a given Printer host interface instance using the + * Configuration Descriptor read from an attached USB device. This function automatically updates the given Printer + * instance's state values and configures the pipes required to communicate with the interface if it is found within + * the device. This should be called once after the stack has enumerated the attached device, while the host state + * machine is in the Addressed state. + * + * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state + * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor + * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor + * + * \return A value from the \ref PRNTHost_EnumerationFailure_ErrorCodes_t enum + */ + uint8_t PRNT_Host_ConfigurePipes(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, uint16_t ConfigDescriptorSize, + void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3); + + /** Configures the printer to enable Bidirectional mode, if it is not already in this mode. This should be called + * once the connected device's configuration has been set, to ensure the printer is ready to accept commands. + * + * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state + * + * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum + */ + uint8_t PRNT_Host_SetBidirectionalMode(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Retrieves the status of the virtual Printer port's inbound status lines. The result can then be masked against the + * PRNT_PORTSTATUS_* macros to determine the printer port's status. + * + * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state + * \param[out] PortStatus Location where the retrieved port status should be stored + * + * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum + */ + uint8_t PRNT_Host_GetPortStatus(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, uint8_t* const PortStatus) + ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + + /** Soft-resets the attached printer, readying it for new commands. + * + * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state + * + * \return A value from the \ref USB_Host_SendControlErrorCodes_t enum + */ + uint8_t PRNT_Host_SoftReset(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Sends the given raw data stream to the attached printer's input endpoint. This should contain commands that the + * printer is able to understand - for example, PCL data. Not all printers accept all printer languages; see + * \ref PRNT_Host_GetDeviceID() for details on determining acceptable languages for an attached printer. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state + * \param[in] PrinterCommands Pointer to a buffer containing the raw command stream to send to the printer + * \param[in] CommandSize Size in bytes of the command stream to be sent + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum + */ + uint8_t PRNT_Host_SendData(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, void* PrinterCommands, + uint16_t CommandSize) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + + /** Retrieves the attached printer device's ID string, formatted according to IEEE 1284. This string is sent as a + * Unicode string from the device and is automatically converted to an ASCII encoded C string by this function, thus + * the maximum reportable string length is two less than the size given (to accommodate the Unicode string length + * bytes which are removed). + * + * This string, when supported, contains the model, manufacturer and acceptable printer languages for the attached device. + * + * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state + * \param[out] DeviceIDString Pointer to a buffer where the Device ID string should be stored, in ASCII format + * \param[in] BufferSize Size in bytes of the buffer allocated for the Device ID string + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum + */ + uint8_t PRNT_Host_GetDeviceID(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo, char* DeviceIDString, + uint16_t BufferSize) ATTR_NON_NULL_PTR_ARG(1); + + /* Inline Functions: */ + /** General management task for a given Printer host class interface, required for the correct operation of + * the interface. This should be called frequently in the main program loop, before the master USB management task + * \ref USB_USBTask(). + * + * \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state + */ + static inline void PRNT_Host_USBTask(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo); + static inline void PRNT_Host_USBTask(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo) + { + (void)PRNTInterfaceInfo; + } + + /* Private Interface - For use in library only: */ + #if !defined(__DOXYGEN__) + /* Macros: */ + #define PRINTER_CLASS 0x07 + #define PRINTER_SUBCLASS 0x01 + #define PRINTER_PROTOCOL 0x02 + + #define REQ_GetDeviceID 0 + #define REQ_GetPortStatus 1 + #define REQ_SoftReset 2 + + #define PRNT_FOUND_DATAPIPE_IN (1 << 0) + #define PRNT_FOUND_DATAPIPE_OUT (1 << 1) + + /* Function Prototypes: */ + #if defined(__INCLUDE_FROM_PRINTER_CLASS_HOST_C) + static uint8_t DComp_NextPRNTInterface(void* const CurrentDescriptor); + static uint8_t DComp_NextPRNTInterfaceEndpoint(void* const CurrentDescriptor); + #endif + #endif + + /* Disable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + } + #endif + +#endif + +/** @} */ diff --git a/LUFA/Drivers/USB/Class/Host/RNDIS.c b/LUFA/Drivers/USB/Class/Host/RNDIS.c index b81c6af58..06175d237 100644 --- a/LUFA/Drivers/USB/Class/Host/RNDIS.c +++ b/LUFA/Drivers/USB/Class/Host/RNDIS.c @@ -1,467 +1,467 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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_USB_DRIVER
-#include "../../HighLevel/USBMode.h"
-#if defined(USB_CAN_BE_HOST)
-
-#define __INCLUDE_FROM_RNDIS_CLASS_HOST_C
-#define __INCLUDE_FROM_RNDIS_DRIVER
-#include "RNDIS.h"
-
-uint8_t RNDIS_Host_ConfigurePipes(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* ConfigDescriptorData)
-{
- uint8_t FoundEndpoints = 0;
-
- memset(&RNDISInterfaceInfo->State, 0x00, sizeof(RNDISInterfaceInfo->State));
-
- if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
- return RNDIS_ENUMERROR_InvalidConfigDescriptor;
-
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_RNDIS_Host_NextRNDISControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return RNDIS_ENUMERROR_NoRNDISInterfaceFound;
- }
-
- RNDISInterfaceInfo->State.ControlInterfaceNumber = DESCRIPTOR_CAST(ConfigDescriptorData, USB_Descriptor_Interface_t).InterfaceNumber;
-
- while (FoundEndpoints != (RNDIS_FOUND_NOTIFICATION_IN | RNDIS_FOUND_DATAPIPE_IN | RNDIS_FOUND_DATAPIPE_OUT))
- {
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_RNDIS_Host_NextRNDISInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- if (FoundEndpoints & RNDIS_FOUND_NOTIFICATION_IN)
- {
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_RNDIS_Host_NextRNDISDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return RNDIS_ENUMERROR_NoRNDISInterfaceFound;
- }
- }
- else
- {
- FoundEndpoints = 0;
-
- Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataINPipeNumber);
- Pipe_DisablePipe();
- Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_DisablePipe();
- Pipe_SelectPipe(RNDISInterfaceInfo->Config.NotificationPipeNumber);
- Pipe_DisablePipe();
-
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_RNDIS_Host_NextRNDISControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return RNDIS_ENUMERROR_NoRNDISInterfaceFound;
- }
- }
-
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
- DComp_RNDIS_Host_NextRNDISInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return RNDIS_ENUMERROR_EndpointsNotFound;
- }
- }
-
- USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
-
- if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
- {
- if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
- {
- Pipe_ConfigurePipe(RNDISInterfaceInfo->Config.NotificationPipeNumber, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- RNDISInterfaceInfo->Config.NotificationPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- RNDISInterfaceInfo->State.NotificationPipeSize = EndpointData->EndpointSize;
-
- Pipe_SetInterruptPeriod(EndpointData->PollingIntervalMS);
-
- FoundEndpoints |= RNDIS_FOUND_NOTIFICATION_IN;
- }
- }
- else
- {
- if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
- {
- Pipe_ConfigurePipe(RNDISInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- RNDISInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- RNDISInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize;
-
- FoundEndpoints |= RNDIS_FOUND_DATAPIPE_IN;
- }
- else
- {
- Pipe_ConfigurePipe(RNDISInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- RNDISInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- RNDISInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize;
-
- FoundEndpoints |= RNDIS_FOUND_DATAPIPE_OUT;
- }
- }
- }
-
- RNDISInterfaceInfo->State.IsActive = true;
- return RNDIS_ENUMERROR_NoError;
-}
-
-static uint8_t DComp_RNDIS_Host_NextRNDISControlInterface(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Interface_t);
-
- if ((CurrentInterface->Class == RNDIS_CONTROL_CLASS) &&
- (CurrentInterface->SubClass == RNDIS_CONTROL_SUBCLASS) &&
- (CurrentInterface->Protocol == RNDIS_CONTROL_PROTOCOL))
- {
- return DESCRIPTOR_SEARCH_Found;
- }
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-static uint8_t DComp_RNDIS_Host_NextRNDISDataInterface(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Interface_t);
-
- if ((CurrentInterface->Class == RNDIS_DATA_CLASS) &&
- (CurrentInterface->SubClass == RNDIS_DATA_SUBCLASS) &&
- (CurrentInterface->Protocol == RNDIS_DATA_PROTOCOL))
- {
- return DESCRIPTOR_SEARCH_Found;
- }
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-static uint8_t DComp_RNDIS_Host_NextRNDISInterfaceEndpoint(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
- {
- USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Endpoint_t);
-
- uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK);
-
- if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
- !(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress)))
- {
- return DESCRIPTOR_SEARCH_Found;
- }
- }
- else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- return DESCRIPTOR_SEARCH_Fail;
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-static uint8_t RNDIS_SendEncapsulatedCommand(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
- void* Buffer, uint16_t Length)
-{
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_SendEncapsulatedCommand,
- .wValue = 0,
- .wIndex = RNDISInterfaceInfo->State.ControlInterfaceNumber,
- .wLength = Length,
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
- return USB_Host_SendControlRequest(Buffer);
-}
-
-static uint8_t RNDIS_GetEncapsulatedResponse(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
- void* Buffer, uint16_t Length)
-{
- USB_ControlRequest = (USB_Request_Header_t)
- {
- .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
- .bRequest = REQ_GetEncapsulatedResponse,
- .wValue = 0,
- .wIndex = RNDISInterfaceInfo->State.ControlInterfaceNumber,
- .wLength = Length,
- };
-
- Pipe_SelectPipe(PIPE_CONTROLPIPE);
- return USB_Host_SendControlRequest(Buffer);
-}
-
-uint8_t RNDIS_Host_SendKeepAlive(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
-{
- uint8_t ErrorCode;
-
- RNDIS_KeepAlive_Message_t KeepAliveMessage;
- RNDIS_KeepAlive_Complete_t KeepAliveMessageResponse;
-
- KeepAliveMessage.MessageType = REMOTE_NDIS_KEEPALIVE_MSG;
- KeepAliveMessage.MessageLength = sizeof(RNDIS_KeepAlive_Message_t);
- KeepAliveMessage.RequestId = RNDISInterfaceInfo->State.RequestID++;
-
- if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &KeepAliveMessage,
- sizeof(RNDIS_KeepAlive_Message_t))) != HOST_SENDCONTROL_Successful)
- {
- return ErrorCode;
- }
-
- if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &KeepAliveMessageResponse,
- sizeof(RNDIS_KeepAlive_Complete_t))) != HOST_SENDCONTROL_Successful)
- {
- return ErrorCode;
- }
-
- return HOST_SENDCONTROL_Successful;
-}
-
-uint8_t RNDIS_Host_InitializeDevice(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
-{
- uint8_t ErrorCode;
-
- RNDIS_Initialize_Message_t InitMessage;
- RNDIS_Initialize_Complete_t InitMessageResponse;
-
- InitMessage.MessageType = REMOTE_NDIS_INITIALIZE_MSG;
- InitMessage.MessageLength = sizeof(RNDIS_Initialize_Message_t);
- InitMessage.RequestId = RNDISInterfaceInfo->State.RequestID++;
-
- InitMessage.MajorVersion = REMOTE_NDIS_VERSION_MAJOR;
- InitMessage.MinorVersion = REMOTE_NDIS_VERSION_MINOR;
- InitMessage.MaxTransferSize = RNDISInterfaceInfo->Config.HostMaxPacketSize;
-
- if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &InitMessage,
- sizeof(RNDIS_Initialize_Message_t))) != HOST_SENDCONTROL_Successful)
- {
- return ErrorCode;
- }
-
- if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &InitMessageResponse,
- sizeof(RNDIS_Initialize_Complete_t))) != HOST_SENDCONTROL_Successful)
- {
- return ErrorCode;
- }
-
- if (InitMessageResponse.Status != REMOTE_NDIS_STATUS_SUCCESS)
- return RNDIS_COMMAND_FAILED;
-
- RNDISInterfaceInfo->State.DeviceMaxPacketSize = InitMessageResponse.MaxTransferSize;
-
- return HOST_SENDCONTROL_Successful;
-}
-
-uint8_t RNDIS_Host_SetRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, uint32_t Oid, void* Buffer, uint16_t Length)
-{
- uint8_t ErrorCode;
-
- struct
- {
- RNDIS_Set_Message_t SetMessage;
- uint8_t ContigiousBuffer[Length];
- } SetMessageData;
-
- RNDIS_Set_Complete_t SetMessageResponse;
-
- SetMessageData.SetMessage.MessageType = REMOTE_NDIS_SET_MSG;
- SetMessageData.SetMessage.MessageLength = sizeof(RNDIS_Set_Message_t) + Length;
- SetMessageData.SetMessage.RequestId = RNDISInterfaceInfo->State.RequestID++;
-
- SetMessageData.SetMessage.Oid = Oid;
- SetMessageData.SetMessage.InformationBufferLength = Length;
- SetMessageData.SetMessage.InformationBufferOffset = (sizeof(RNDIS_Set_Message_t) - sizeof(RNDIS_Message_Header_t));
- SetMessageData.SetMessage.DeviceVcHandle = 0;
-
- memcpy(&SetMessageData.ContigiousBuffer, Buffer, Length);
-
- if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &SetMessageData,
- SetMessageData.SetMessage.MessageLength)) != HOST_SENDCONTROL_Successful)
- {
- return ErrorCode;
- }
-
- if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &SetMessageResponse,
- sizeof(RNDIS_Set_Complete_t))) != HOST_SENDCONTROL_Successful)
- {
- return ErrorCode;
- }
-
- if (SetMessageResponse.Status != REMOTE_NDIS_STATUS_SUCCESS)
- return RNDIS_COMMAND_FAILED;
-
- return HOST_SENDCONTROL_Successful;
-}
-
-uint8_t RNDIS_Host_QueryRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, uint32_t Oid, void* Buffer, uint16_t MaxLength)
-{
- uint8_t ErrorCode;
-
- RNDIS_Query_Message_t QueryMessage;
-
- struct
- {
- RNDIS_Query_Complete_t QueryMessageResponse;
- uint8_t ContigiousBuffer[MaxLength];
- } QueryMessageResponseData;
-
- QueryMessage.MessageType = REMOTE_NDIS_QUERY_MSG;
- QueryMessage.MessageLength = sizeof(RNDIS_Query_Message_t);
- QueryMessage.RequestId = RNDISInterfaceInfo->State.RequestID++;
-
- QueryMessage.Oid = Oid;
- QueryMessage.InformationBufferLength = 0;
- QueryMessage.InformationBufferOffset = 0;
- QueryMessage.DeviceVcHandle = 0;
-
- if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &QueryMessage,
- sizeof(RNDIS_Query_Message_t))) != HOST_SENDCONTROL_Successful)
- {
- return ErrorCode;
- }
-
- if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &QueryMessageResponseData,
- sizeof(QueryMessageResponseData))) != HOST_SENDCONTROL_Successful)
- {
- return ErrorCode;
- }
-
- if (QueryMessageResponseData.QueryMessageResponse.Status != REMOTE_NDIS_STATUS_SUCCESS)
- return RNDIS_COMMAND_FAILED;
-
- memcpy(Buffer, &QueryMessageResponseData.ContigiousBuffer, MaxLength);
-
- return HOST_SENDCONTROL_Successful;
-}
-
-bool RNDIS_Host_IsPacketReceived(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
-{
- bool PacketWaiting;
-
- if ((USB_HostState != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive))
- return false;
-
- Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataINPipeNumber);
- Pipe_SetPipeToken(PIPE_TOKEN_IN);
-
- Pipe_Unfreeze();
-
- PacketWaiting = Pipe_IsINReceived();
-
- Pipe_Freeze();
-
- return PacketWaiting;
-}
-
-uint8_t RNDIS_Host_ReadPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, void* Buffer, uint16_t* PacketLength)
-{
- uint8_t ErrorCode;
-
- if ((USB_HostState != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive))
- return PIPE_READYWAIT_DeviceDisconnected;
-
- Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataINPipeNumber);
- Pipe_SetPipeToken(PIPE_TOKEN_IN);
- Pipe_Unfreeze();
-
- if (!(Pipe_IsReadWriteAllowed()))
- {
- if (Pipe_IsINReceived())
- Pipe_ClearIN();
-
- *PacketLength = 0;
- Pipe_Freeze();
- return PIPE_RWSTREAM_NoError;
- }
-
- RNDIS_Packet_Message_t DeviceMessage;
-
- if ((ErrorCode = Pipe_Read_Stream_LE(&DeviceMessage, sizeof(RNDIS_Packet_Message_t),
- NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
- {
- return ErrorCode;
- }
-
- *PacketLength = (uint16_t)DeviceMessage.DataLength;
-
- Pipe_Discard_Stream(DeviceMessage.DataOffset - (sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t)),
- NO_STREAM_CALLBACK);
-
- Pipe_Read_Stream_LE(Buffer, *PacketLength, NO_STREAM_CALLBACK);
-
- if (!(Pipe_BytesInPipe()))
- Pipe_ClearIN();
-
- Pipe_Freeze();
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t RNDIS_Host_SendPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, void* Buffer, uint16_t PacketLength)
-{
- uint8_t ErrorCode;
-
- if ((USB_HostState != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive))
- return PIPE_READYWAIT_DeviceDisconnected;
-
- RNDIS_Packet_Message_t DeviceMessage;
-
- memset(&DeviceMessage, 0, sizeof(RNDIS_Packet_Message_t));
- DeviceMessage.MessageType = REMOTE_NDIS_PACKET_MSG;
- DeviceMessage.MessageLength = (sizeof(RNDIS_Packet_Message_t) + PacketLength);
- DeviceMessage.DataOffset = (sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t));
- DeviceMessage.DataLength = PacketLength;
-
- Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_Unfreeze();
-
- if ((ErrorCode = Pipe_Write_Stream_LE(&DeviceMessage, sizeof(RNDIS_Packet_Message_t),
- NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
- {
- return ErrorCode;
- }
-
- Pipe_Write_Stream_LE(Buffer, PacketLength, NO_STREAM_CALLBACK);
- Pipe_ClearOUT();
-
- Pipe_Freeze();
-
- return PIPE_RWSTREAM_NoError;
-}
-
-#endif
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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_USB_DRIVER +#include "../../HighLevel/USBMode.h" +#if defined(USB_CAN_BE_HOST) + +#define __INCLUDE_FROM_RNDIS_CLASS_HOST_C +#define __INCLUDE_FROM_RNDIS_DRIVER +#include "RNDIS.h" + +uint8_t RNDIS_Host_ConfigurePipes(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, uint16_t ConfigDescriptorSize, + void* ConfigDescriptorData) +{ + uint8_t FoundEndpoints = 0; + + memset(&RNDISInterfaceInfo->State, 0x00, sizeof(RNDISInterfaceInfo->State)); + + if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration) + return RNDIS_ENUMERROR_InvalidConfigDescriptor; + + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_RNDIS_Host_NextRNDISControlInterface) != DESCRIPTOR_SEARCH_COMP_Found) + { + return RNDIS_ENUMERROR_NoRNDISInterfaceFound; + } + + RNDISInterfaceInfo->State.ControlInterfaceNumber = DESCRIPTOR_CAST(ConfigDescriptorData, USB_Descriptor_Interface_t).InterfaceNumber; + + while (FoundEndpoints != (RNDIS_FOUND_NOTIFICATION_IN | RNDIS_FOUND_DATAPIPE_IN | RNDIS_FOUND_DATAPIPE_OUT)) + { + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_RNDIS_Host_NextRNDISInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found) + { + if (FoundEndpoints & RNDIS_FOUND_NOTIFICATION_IN) + { + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_RNDIS_Host_NextRNDISDataInterface) != DESCRIPTOR_SEARCH_COMP_Found) + { + return RNDIS_ENUMERROR_NoRNDISInterfaceFound; + } + } + else + { + FoundEndpoints = 0; + + Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataINPipeNumber); + Pipe_DisablePipe(); + Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_DisablePipe(); + Pipe_SelectPipe(RNDISInterfaceInfo->Config.NotificationPipeNumber); + Pipe_DisablePipe(); + + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_RNDIS_Host_NextRNDISControlInterface) != DESCRIPTOR_SEARCH_COMP_Found) + { + return RNDIS_ENUMERROR_NoRNDISInterfaceFound; + } + } + + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, + DComp_RNDIS_Host_NextRNDISInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found) + { + return RNDIS_ENUMERROR_EndpointsNotFound; + } + } + + USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t); + + if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT) + { + if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN) + { + Pipe_ConfigurePipe(RNDISInterfaceInfo->Config.NotificationPipeNumber, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + RNDISInterfaceInfo->Config.NotificationPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + RNDISInterfaceInfo->State.NotificationPipeSize = EndpointData->EndpointSize; + + Pipe_SetInterruptPeriod(EndpointData->PollingIntervalMS); + + FoundEndpoints |= RNDIS_FOUND_NOTIFICATION_IN; + } + } + else + { + if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN) + { + Pipe_ConfigurePipe(RNDISInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + RNDISInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + RNDISInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize; + + FoundEndpoints |= RNDIS_FOUND_DATAPIPE_IN; + } + else + { + Pipe_ConfigurePipe(RNDISInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + RNDISInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + RNDISInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize; + + FoundEndpoints |= RNDIS_FOUND_DATAPIPE_OUT; + } + } + } + + RNDISInterfaceInfo->State.IsActive = true; + return RNDIS_ENUMERROR_NoError; +} + +static uint8_t DComp_RNDIS_Host_NextRNDISControlInterface(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Interface_t); + + if ((CurrentInterface->Class == RNDIS_CONTROL_CLASS) && + (CurrentInterface->SubClass == RNDIS_CONTROL_SUBCLASS) && + (CurrentInterface->Protocol == RNDIS_CONTROL_PROTOCOL)) + { + return DESCRIPTOR_SEARCH_Found; + } + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +static uint8_t DComp_RNDIS_Host_NextRNDISDataInterface(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Interface_t); + + if ((CurrentInterface->Class == RNDIS_DATA_CLASS) && + (CurrentInterface->SubClass == RNDIS_DATA_SUBCLASS) && + (CurrentInterface->Protocol == RNDIS_DATA_PROTOCOL)) + { + return DESCRIPTOR_SEARCH_Found; + } + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +static uint8_t DComp_RNDIS_Host_NextRNDISInterfaceEndpoint(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint) + { + USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Endpoint_t); + + uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK); + + if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) && + !(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress))) + { + return DESCRIPTOR_SEARCH_Found; + } + } + else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + return DESCRIPTOR_SEARCH_Fail; + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +static uint8_t RNDIS_SendEncapsulatedCommand(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, + void* Buffer, uint16_t Length) +{ + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_SendEncapsulatedCommand, + .wValue = 0, + .wIndex = RNDISInterfaceInfo->State.ControlInterfaceNumber, + .wLength = Length, + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + return USB_Host_SendControlRequest(Buffer); +} + +static uint8_t RNDIS_GetEncapsulatedResponse(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, + void* Buffer, uint16_t Length) +{ + USB_ControlRequest = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = REQ_GetEncapsulatedResponse, + .wValue = 0, + .wIndex = RNDISInterfaceInfo->State.ControlInterfaceNumber, + .wLength = Length, + }; + + Pipe_SelectPipe(PIPE_CONTROLPIPE); + return USB_Host_SendControlRequest(Buffer); +} + +uint8_t RNDIS_Host_SendKeepAlive(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo) +{ + uint8_t ErrorCode; + + RNDIS_KeepAlive_Message_t KeepAliveMessage; + RNDIS_KeepAlive_Complete_t KeepAliveMessageResponse; + + KeepAliveMessage.MessageType = REMOTE_NDIS_KEEPALIVE_MSG; + KeepAliveMessage.MessageLength = sizeof(RNDIS_KeepAlive_Message_t); + KeepAliveMessage.RequestId = RNDISInterfaceInfo->State.RequestID++; + + if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &KeepAliveMessage, + sizeof(RNDIS_KeepAlive_Message_t))) != HOST_SENDCONTROL_Successful) + { + return ErrorCode; + } + + if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &KeepAliveMessageResponse, + sizeof(RNDIS_KeepAlive_Complete_t))) != HOST_SENDCONTROL_Successful) + { + return ErrorCode; + } + + return HOST_SENDCONTROL_Successful; +} + +uint8_t RNDIS_Host_InitializeDevice(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo) +{ + uint8_t ErrorCode; + + RNDIS_Initialize_Message_t InitMessage; + RNDIS_Initialize_Complete_t InitMessageResponse; + + InitMessage.MessageType = REMOTE_NDIS_INITIALIZE_MSG; + InitMessage.MessageLength = sizeof(RNDIS_Initialize_Message_t); + InitMessage.RequestId = RNDISInterfaceInfo->State.RequestID++; + + InitMessage.MajorVersion = REMOTE_NDIS_VERSION_MAJOR; + InitMessage.MinorVersion = REMOTE_NDIS_VERSION_MINOR; + InitMessage.MaxTransferSize = RNDISInterfaceInfo->Config.HostMaxPacketSize; + + if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &InitMessage, + sizeof(RNDIS_Initialize_Message_t))) != HOST_SENDCONTROL_Successful) + { + return ErrorCode; + } + + if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &InitMessageResponse, + sizeof(RNDIS_Initialize_Complete_t))) != HOST_SENDCONTROL_Successful) + { + return ErrorCode; + } + + if (InitMessageResponse.Status != REMOTE_NDIS_STATUS_SUCCESS) + return RNDIS_COMMAND_FAILED; + + RNDISInterfaceInfo->State.DeviceMaxPacketSize = InitMessageResponse.MaxTransferSize; + + return HOST_SENDCONTROL_Successful; +} + +uint8_t RNDIS_Host_SetRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, uint32_t Oid, void* Buffer, uint16_t Length) +{ + uint8_t ErrorCode; + + struct + { + RNDIS_Set_Message_t SetMessage; + uint8_t ContigiousBuffer[Length]; + } SetMessageData; + + RNDIS_Set_Complete_t SetMessageResponse; + + SetMessageData.SetMessage.MessageType = REMOTE_NDIS_SET_MSG; + SetMessageData.SetMessage.MessageLength = sizeof(RNDIS_Set_Message_t) + Length; + SetMessageData.SetMessage.RequestId = RNDISInterfaceInfo->State.RequestID++; + + SetMessageData.SetMessage.Oid = Oid; + SetMessageData.SetMessage.InformationBufferLength = Length; + SetMessageData.SetMessage.InformationBufferOffset = (sizeof(RNDIS_Set_Message_t) - sizeof(RNDIS_Message_Header_t)); + SetMessageData.SetMessage.DeviceVcHandle = 0; + + memcpy(&SetMessageData.ContigiousBuffer, Buffer, Length); + + if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &SetMessageData, + SetMessageData.SetMessage.MessageLength)) != HOST_SENDCONTROL_Successful) + { + return ErrorCode; + } + + if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &SetMessageResponse, + sizeof(RNDIS_Set_Complete_t))) != HOST_SENDCONTROL_Successful) + { + return ErrorCode; + } + + if (SetMessageResponse.Status != REMOTE_NDIS_STATUS_SUCCESS) + return RNDIS_COMMAND_FAILED; + + return HOST_SENDCONTROL_Successful; +} + +uint8_t RNDIS_Host_QueryRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, uint32_t Oid, void* Buffer, uint16_t MaxLength) +{ + uint8_t ErrorCode; + + RNDIS_Query_Message_t QueryMessage; + + struct + { + RNDIS_Query_Complete_t QueryMessageResponse; + uint8_t ContigiousBuffer[MaxLength]; + } QueryMessageResponseData; + + QueryMessage.MessageType = REMOTE_NDIS_QUERY_MSG; + QueryMessage.MessageLength = sizeof(RNDIS_Query_Message_t); + QueryMessage.RequestId = RNDISInterfaceInfo->State.RequestID++; + + QueryMessage.Oid = Oid; + QueryMessage.InformationBufferLength = 0; + QueryMessage.InformationBufferOffset = 0; + QueryMessage.DeviceVcHandle = 0; + + if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &QueryMessage, + sizeof(RNDIS_Query_Message_t))) != HOST_SENDCONTROL_Successful) + { + return ErrorCode; + } + + if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &QueryMessageResponseData, + sizeof(QueryMessageResponseData))) != HOST_SENDCONTROL_Successful) + { + return ErrorCode; + } + + if (QueryMessageResponseData.QueryMessageResponse.Status != REMOTE_NDIS_STATUS_SUCCESS) + return RNDIS_COMMAND_FAILED; + + memcpy(Buffer, &QueryMessageResponseData.ContigiousBuffer, MaxLength); + + return HOST_SENDCONTROL_Successful; +} + +bool RNDIS_Host_IsPacketReceived(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo) +{ + bool PacketWaiting; + + if ((USB_HostState != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive)) + return false; + + Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataINPipeNumber); + Pipe_SetPipeToken(PIPE_TOKEN_IN); + + Pipe_Unfreeze(); + + PacketWaiting = Pipe_IsINReceived(); + + Pipe_Freeze(); + + return PacketWaiting; +} + +uint8_t RNDIS_Host_ReadPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, void* Buffer, uint16_t* PacketLength) +{ + uint8_t ErrorCode; + + if ((USB_HostState != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive)) + return PIPE_READYWAIT_DeviceDisconnected; + + Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataINPipeNumber); + Pipe_SetPipeToken(PIPE_TOKEN_IN); + Pipe_Unfreeze(); + + if (!(Pipe_IsReadWriteAllowed())) + { + if (Pipe_IsINReceived()) + Pipe_ClearIN(); + + *PacketLength = 0; + Pipe_Freeze(); + return PIPE_RWSTREAM_NoError; + } + + RNDIS_Packet_Message_t DeviceMessage; + + if ((ErrorCode = Pipe_Read_Stream_LE(&DeviceMessage, sizeof(RNDIS_Packet_Message_t), + NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError) + { + return ErrorCode; + } + + *PacketLength = (uint16_t)DeviceMessage.DataLength; + + Pipe_Discard_Stream(DeviceMessage.DataOffset - (sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t)), + NO_STREAM_CALLBACK); + + Pipe_Read_Stream_LE(Buffer, *PacketLength, NO_STREAM_CALLBACK); + + if (!(Pipe_BytesInPipe())) + Pipe_ClearIN(); + + Pipe_Freeze(); + + return PIPE_RWSTREAM_NoError; +} + +uint8_t RNDIS_Host_SendPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, void* Buffer, uint16_t PacketLength) +{ + uint8_t ErrorCode; + + if ((USB_HostState != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive)) + return PIPE_READYWAIT_DeviceDisconnected; + + RNDIS_Packet_Message_t DeviceMessage; + + memset(&DeviceMessage, 0, sizeof(RNDIS_Packet_Message_t)); + DeviceMessage.MessageType = REMOTE_NDIS_PACKET_MSG; + DeviceMessage.MessageLength = (sizeof(RNDIS_Packet_Message_t) + PacketLength); + DeviceMessage.DataOffset = (sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t)); + DeviceMessage.DataLength = PacketLength; + + Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_Unfreeze(); + + if ((ErrorCode = Pipe_Write_Stream_LE(&DeviceMessage, sizeof(RNDIS_Packet_Message_t), + NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError) + { + return ErrorCode; + } + + Pipe_Write_Stream_LE(Buffer, PacketLength, NO_STREAM_CALLBACK); + Pipe_ClearOUT(); + + Pipe_Freeze(); + + return PIPE_RWSTREAM_NoError; +} + +#endif diff --git a/LUFA/Drivers/USB/Class/Host/RNDIS.h b/LUFA/Drivers/USB/Class/Host/RNDIS.h index f64710d5b..7daaca869 100644 --- a/LUFA/Drivers/USB/Class/Host/RNDIS.h +++ b/LUFA/Drivers/USB/Class/Host/RNDIS.h @@ -1,283 +1,283 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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
- * \brief Host mode driver for the library USB RNDIS Class driver.
- *
- * Host mode driver for the library USB RNDIS Class driver.
- *
- * \note This file should not be included directly. It is automatically included as needed by the class driver
- * dispatch header located in LUFA/Drivers/USB/Class/RNDIS.h.
- */
-
-/** \ingroup Group_USBClassRNDIS
- * @defgroup Group_USBClassRNDISHost RNDIS Class Host Mode Driver
- *
- * \section Sec_Dependencies Module Source Dependencies
- * The following files must be built with any user project that uses this module:
- * - LUFA/Drivers/USB/Class/Host/RNDIS.c
- *
- * \section Module Description
- * Host Mode USB Class driver framework interface, for the Microsoft RNDIS Ethernet
- * USB Class driver.
- *
- * @{
- */
-
-#ifndef __RNDIS_CLASS_HOST_H__
-#define __RNDIS_CLASS_HOST_H__
-
- /* Includes: */
- #include "../../USB.h"
- #include "../Common/RNDIS.h"
-
- #include <stdio.h>
- #include <string.h>
-
- /* Enable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- extern "C" {
- #endif
-
- /* Preprocessor Checks: */
- #if !defined(__INCLUDE_FROM_RNDIS_DRIVER)
- #error Do not include this file directly. Include LUFA/Drivers/Class/RNDIS.h instead.
- #endif
-
- /* Public Interface - May be used in end-application: */
- /* Type Defines: */
- /** \brief RNDIS Class Host Mode Configuration and State Structure.
- *
- * Class state structure. An instance of this structure should be made within the user application,
- * and passed to each of the RNDIS class driver functions as the RNDISInterfaceInfo parameter. This
- * stores each RNDIS interface's configuration and state information.
- */
- typedef struct
- {
- const struct
- {
- uint8_t DataINPipeNumber; /**< Pipe number of the RNDIS interface's IN data pipe */
- bool DataINPipeDoubleBank; /** Indicates if the RNDIS interface's IN data pipe should use double banking */
-
- uint8_t DataOUTPipeNumber; /**< Pipe number of the RNDIS interface's OUT data pipe */
- bool DataOUTPipeDoubleBank; /** Indicates if the RNDIS interface's OUT data pipe should use double banking */
-
- uint8_t NotificationPipeNumber; /**< Pipe number of the RNDIS interface's IN notification endpoint, if used */
- bool NotificationPipeDoubleBank; /** Indicates if the RNDIS interface's notification pipe should use double banking */
-
- uint32_t HostMaxPacketSize; /**< Maximum size of a packet which can be buffered by the host */
- } Config; /**< Config data for the USB class interface within the device. All elements in this section
- * <b>must</b> be set or the interface will fail to enumerate and operate correctly.
- */
- struct
- {
- bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
- * after \ref RNDIS_Host_ConfigurePipes() is called and the Host state machine is in the
- * Configured state
- */
- uint8_t ControlInterfaceNumber; /**< Interface index of the RNDIS control interface within the attached device */
-
- uint16_t DataINPipeSize; /**< Size in bytes of the RNDIS interface's IN data pipe */
- uint16_t DataOUTPipeSize; /**< Size in bytes of the RNDIS interface's OUT data pipe */
- uint16_t NotificationPipeSize; /**< Size in bytes of the RNDIS interface's IN notification pipe, if used */
-
- uint32_t DeviceMaxPacketSize; /**< Maximum size of a packet which can be buffered by the attached RNDIS device */
-
- uint32_t RequestID; /**< Request ID counter to give a unique ID for each command/response pair */
- } State; /**< State data for the USB class interface within the device. All elements in this section
- * <b>may</b> be set to initial values, but may also be ignored to default to sane values when
- * the interface is enumerated.
- */
- } USB_ClassInfo_RNDIS_Host_t;
-
- /* Enums: */
- /** Enum for the possible error codes returned by the \ref RNDIS_Host_ConfigurePipes() function. */
- enum RNDISHost_EnumerationFailure_ErrorCodes_t
- {
- RNDIS_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */
- RNDIS_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */
- RNDIS_ENUMERROR_NoRNDISInterfaceFound = 2, /**< A compatible RNDIS interface was not found in the device's Configuration Descriptor */
- RNDIS_ENUMERROR_EndpointsNotFound = 3, /**< Compatible RNDIS endpoints were not found in the device's RNDIS interface */
- };
-
- /* Macros: */
- /** Additional error code for RNDIS functions when a device returns a logical command failure */
- #define RNDIS_COMMAND_FAILED 0xC0
-
- /* Function Prototypes: */
- /** Host interface configuration routine, to configure a given RNDIS host interface instance using the Configuration
- * Descriptor read from an attached USB device. This function automatically updates the given RNDIS Host instance's
- * state values and configures the pipes required to communicate with the interface if it is found within the device.
- * This should be called once after the stack has enumerated the attached device, while the host state machine is in
- * the Addressed state.
- *
- * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state
- * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor
- * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor
- *
- * \return A value from the \ref RNDISHost_EnumerationFailure_ErrorCodes_t enum
- */
- uint8_t RNDIS_Host_ConfigurePipes(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
-
- /** Sends a RNDIS KEEPALIVE command to the device, to ensure that it does not enter standby mode after periods
- * of long inactivity.
- *
- * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state
- *
- * \return A value from the USB_Host_SendControlErrorCodes_t enum or RNDIS_COMMAND_FAILED if the device returned a
- * logical command failure
- */
- uint8_t RNDIS_Host_SendKeepAlive(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Initializes the attached RNDIS device's RNDIS interface. This should be called after the device's pipes have been
- * configured via the call to \ref RNDIS_Host_ConfigurePipes().
- *
- * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state
- *
- * \return A value from the USB_Host_SendControlErrorCodes_t enum or RNDIS_COMMAND_FAILED if the device returned a
- * logical command failure
- */
- uint8_t RNDIS_Host_InitializeDevice(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Sets a given RNDIS property of an attached RNDIS device.
- *
- * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state
- * \param[in] Oid OID number of the parameter to set
- * \param[in] Buffer Pointer to where the property data is to be sourced from
- * \param[in] Length Length in bytes of the property data to sent to the device
- *
- * \return A value from the USB_Host_SendControlErrorCodes_t enum or RNDIS_COMMAND_FAILED if the device returned a
- * logical command failure
- */
- uint8_t RNDIS_Host_SetRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, uint32_t Oid, void* Buffer,
- uint16_t Length) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
-
- /** Gets a given RNDIS property of an attached RNDIS device.
- *
- * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state
- * \param[in] Oid OID number of the parameter to get
- * \param[in] Buffer Pointer to where the property data is to be written to
- * \param[in] MaxLength Length in bytes of the destination buffer size
- *
- * \return A value from the USB_Host_SendControlErrorCodes_t enum or RNDIS_COMMAND_FAILED if the device returned a
- * logical command failure
- */
- uint8_t RNDIS_Host_QueryRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, uint32_t Oid, void* Buffer,
- uint16_t MaxLength) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
-
- /** Determines if a packet is currently waiting for the host to read in and process.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state
- *
- * \return Boolean true if a packet is waiting to be read in by the host, false otherwise
- */
-
- bool RNDIS_Host_IsPacketReceived(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo);
-
- /** Retrieves the next pending packet from the device, discarding the remainder of the RNDIS packet header to leave
- * only the packet contents for processing by the host in the nominated buffer.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state
- * \param[out] Buffer Pointer to a buffer where the packer data is to be written to
- * \param[out] PacketLength Pointer to where the length in bytes of the read packet is to be stored
- *
- * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum
- */
- uint8_t RNDIS_Host_ReadPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, void* Buffer, uint16_t* PacketLength)
- ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2) ATTR_NON_NULL_PTR_ARG(3);
-
- /** Sends the given packet to the attached RNDIS device, after adding a RNDIS packet message header.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state
- * \param[in] Buffer Pointer to a buffer where the packer data is to be read from
- * \param[in] PacketLength Length in bytes of the packet to send
- *
- * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum
- */
- uint8_t RNDIS_Host_SendPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, void* Buffer, uint16_t PacketLength)
- ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
-
- /* Inline Functions: */
- /** General management task for a given RNDIS host class interface, required for the correct operation of the interface. This should
- * be called frequently in the main program loop, before the master USB management task \ref USB_USBTask().
- *
- * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state
- */
- static inline void RNDIS_Host_USBTask(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo);
- static inline void RNDIS_Host_USBTask(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
- {
- (void)RNDISInterfaceInfo;
- }
-
- /* Private Interface - For use in library only: */
- #if !defined(__DOXYGEN__)
- /* Macros: */
- #define RNDIS_CONTROL_CLASS 0x02
- #define RNDIS_CONTROL_SUBCLASS 0x02
- #define RNDIS_CONTROL_PROTOCOL 0xFF
- #define RNDIS_DATA_CLASS 0x0A
- #define RNDIS_DATA_SUBCLASS 0x00
- #define RNDIS_DATA_PROTOCOL 0x00
-
- #define RNDIS_FOUND_DATAPIPE_IN (1 << 0)
- #define RNDIS_FOUND_DATAPIPE_OUT (1 << 1)
- #define RNDIS_FOUND_NOTIFICATION_IN (1 << 2)
-
- /* Function Prototypes: */
- #if defined(__INCLUDE_FROM_RNDIS_CLASS_HOST_C)
- static uint8_t RNDIS_SendEncapsulatedCommand(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
- void* Buffer, uint16_t Length) ATTR_NON_NULL_PTR_ARG(1);
- static uint8_t RNDIS_GetEncapsulatedResponse(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
- void* Buffer, uint16_t Length) ATTR_NON_NULL_PTR_ARG(1);
-
- static uint8_t DComp_RNDIS_Host_NextRNDISControlInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1);
- static uint8_t DComp_RNDIS_Host_NextRNDISDataInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1);
- static uint8_t DComp_RNDIS_Host_NextRNDISInterfaceEndpoint(void* const CurrentDescriptor);
- #endif
- #endif
-
- /* Disable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- }
- #endif
-
-#endif
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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 + * \brief Host mode driver for the library USB RNDIS Class driver. + * + * Host mode driver for the library USB RNDIS Class driver. + * + * \note This file should not be included directly. It is automatically included as needed by the class driver + * dispatch header located in LUFA/Drivers/USB/Class/RNDIS.h. + */ + +/** \ingroup Group_USBClassRNDIS + * @defgroup Group_USBClassRNDISHost RNDIS Class Host Mode Driver + * + * \section Sec_Dependencies Module Source Dependencies + * The following files must be built with any user project that uses this module: + * - LUFA/Drivers/USB/Class/Host/RNDIS.c + * + * \section Module Description + * Host Mode USB Class driver framework interface, for the Microsoft RNDIS Ethernet + * USB Class driver. + * + * @{ + */ + +#ifndef __RNDIS_CLASS_HOST_H__ +#define __RNDIS_CLASS_HOST_H__ + + /* Includes: */ + #include "../../USB.h" + #include "../Common/RNDIS.h" + + #include <stdio.h> + #include <string.h> + + /* Enable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + extern "C" { + #endif + + /* Preprocessor Checks: */ + #if !defined(__INCLUDE_FROM_RNDIS_DRIVER) + #error Do not include this file directly. Include LUFA/Drivers/Class/RNDIS.h instead. + #endif + + /* Public Interface - May be used in end-application: */ + /* Type Defines: */ + /** \brief RNDIS Class Host Mode Configuration and State Structure. + * + * Class state structure. An instance of this structure should be made within the user application, + * and passed to each of the RNDIS class driver functions as the RNDISInterfaceInfo parameter. This + * stores each RNDIS interface's configuration and state information. + */ + typedef struct + { + const struct + { + uint8_t DataINPipeNumber; /**< Pipe number of the RNDIS interface's IN data pipe */ + bool DataINPipeDoubleBank; /** Indicates if the RNDIS interface's IN data pipe should use double banking */ + + uint8_t DataOUTPipeNumber; /**< Pipe number of the RNDIS interface's OUT data pipe */ + bool DataOUTPipeDoubleBank; /** Indicates if the RNDIS interface's OUT data pipe should use double banking */ + + uint8_t NotificationPipeNumber; /**< Pipe number of the RNDIS interface's IN notification endpoint, if used */ + bool NotificationPipeDoubleBank; /** Indicates if the RNDIS interface's notification pipe should use double banking */ + + uint32_t HostMaxPacketSize; /**< Maximum size of a packet which can be buffered by the host */ + } Config; /**< Config data for the USB class interface within the device. All elements in this section + * <b>must</b> be set or the interface will fail to enumerate and operate correctly. + */ + struct + { + bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid + * after \ref RNDIS_Host_ConfigurePipes() is called and the Host state machine is in the + * Configured state + */ + uint8_t ControlInterfaceNumber; /**< Interface index of the RNDIS control interface within the attached device */ + + uint16_t DataINPipeSize; /**< Size in bytes of the RNDIS interface's IN data pipe */ + uint16_t DataOUTPipeSize; /**< Size in bytes of the RNDIS interface's OUT data pipe */ + uint16_t NotificationPipeSize; /**< Size in bytes of the RNDIS interface's IN notification pipe, if used */ + + uint32_t DeviceMaxPacketSize; /**< Maximum size of a packet which can be buffered by the attached RNDIS device */ + + uint32_t RequestID; /**< Request ID counter to give a unique ID for each command/response pair */ + } State; /**< State data for the USB class interface within the device. All elements in this section + * <b>may</b> be set to initial values, but may also be ignored to default to sane values when + * the interface is enumerated. + */ + } USB_ClassInfo_RNDIS_Host_t; + + /* Enums: */ + /** Enum for the possible error codes returned by the \ref RNDIS_Host_ConfigurePipes() function. */ + enum RNDISHost_EnumerationFailure_ErrorCodes_t + { + RNDIS_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */ + RNDIS_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */ + RNDIS_ENUMERROR_NoRNDISInterfaceFound = 2, /**< A compatible RNDIS interface was not found in the device's Configuration Descriptor */ + RNDIS_ENUMERROR_EndpointsNotFound = 3, /**< Compatible RNDIS endpoints were not found in the device's RNDIS interface */ + }; + + /* Macros: */ + /** Additional error code for RNDIS functions when a device returns a logical command failure */ + #define RNDIS_COMMAND_FAILED 0xC0 + + /* Function Prototypes: */ + /** Host interface configuration routine, to configure a given RNDIS host interface instance using the Configuration + * Descriptor read from an attached USB device. This function automatically updates the given RNDIS Host instance's + * state values and configures the pipes required to communicate with the interface if it is found within the device. + * This should be called once after the stack has enumerated the attached device, while the host state machine is in + * the Addressed state. + * + * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state + * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor + * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor + * + * \return A value from the \ref RNDISHost_EnumerationFailure_ErrorCodes_t enum + */ + uint8_t RNDIS_Host_ConfigurePipes(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, uint16_t ConfigDescriptorSize, + void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3); + + /** Sends a RNDIS KEEPALIVE command to the device, to ensure that it does not enter standby mode after periods + * of long inactivity. + * + * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state + * + * \return A value from the USB_Host_SendControlErrorCodes_t enum or RNDIS_COMMAND_FAILED if the device returned a + * logical command failure + */ + uint8_t RNDIS_Host_SendKeepAlive(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Initializes the attached RNDIS device's RNDIS interface. This should be called after the device's pipes have been + * configured via the call to \ref RNDIS_Host_ConfigurePipes(). + * + * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state + * + * \return A value from the USB_Host_SendControlErrorCodes_t enum or RNDIS_COMMAND_FAILED if the device returned a + * logical command failure + */ + uint8_t RNDIS_Host_InitializeDevice(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Sets a given RNDIS property of an attached RNDIS device. + * + * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state + * \param[in] Oid OID number of the parameter to set + * \param[in] Buffer Pointer to where the property data is to be sourced from + * \param[in] Length Length in bytes of the property data to sent to the device + * + * \return A value from the USB_Host_SendControlErrorCodes_t enum or RNDIS_COMMAND_FAILED if the device returned a + * logical command failure + */ + uint8_t RNDIS_Host_SetRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, uint32_t Oid, void* Buffer, + uint16_t Length) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3); + + /** Gets a given RNDIS property of an attached RNDIS device. + * + * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state + * \param[in] Oid OID number of the parameter to get + * \param[in] Buffer Pointer to where the property data is to be written to + * \param[in] MaxLength Length in bytes of the destination buffer size + * + * \return A value from the USB_Host_SendControlErrorCodes_t enum or RNDIS_COMMAND_FAILED if the device returned a + * logical command failure + */ + uint8_t RNDIS_Host_QueryRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, uint32_t Oid, void* Buffer, + uint16_t MaxLength) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3); + + /** Determines if a packet is currently waiting for the host to read in and process. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state + * + * \return Boolean true if a packet is waiting to be read in by the host, false otherwise + */ + + bool RNDIS_Host_IsPacketReceived(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo); + + /** Retrieves the next pending packet from the device, discarding the remainder of the RNDIS packet header to leave + * only the packet contents for processing by the host in the nominated buffer. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state + * \param[out] Buffer Pointer to a buffer where the packer data is to be written to + * \param[out] PacketLength Pointer to where the length in bytes of the read packet is to be stored + * + * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum + */ + uint8_t RNDIS_Host_ReadPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, void* Buffer, uint16_t* PacketLength) + ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2) ATTR_NON_NULL_PTR_ARG(3); + + /** Sends the given packet to the attached RNDIS device, after adding a RNDIS packet message header. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state + * \param[in] Buffer Pointer to a buffer where the packer data is to be read from + * \param[in] PacketLength Length in bytes of the packet to send + * + * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum + */ + uint8_t RNDIS_Host_SendPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, void* Buffer, uint16_t PacketLength) + ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + + /* Inline Functions: */ + /** General management task for a given RNDIS host class interface, required for the correct operation of the interface. This should + * be called frequently in the main program loop, before the master USB management task \ref USB_USBTask(). + * + * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state + */ + static inline void RNDIS_Host_USBTask(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo); + static inline void RNDIS_Host_USBTask(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo) + { + (void)RNDISInterfaceInfo; + } + + /* Private Interface - For use in library only: */ + #if !defined(__DOXYGEN__) + /* Macros: */ + #define RNDIS_CONTROL_CLASS 0x02 + #define RNDIS_CONTROL_SUBCLASS 0x02 + #define RNDIS_CONTROL_PROTOCOL 0xFF + #define RNDIS_DATA_CLASS 0x0A + #define RNDIS_DATA_SUBCLASS 0x00 + #define RNDIS_DATA_PROTOCOL 0x00 + + #define RNDIS_FOUND_DATAPIPE_IN (1 << 0) + #define RNDIS_FOUND_DATAPIPE_OUT (1 << 1) + #define RNDIS_FOUND_NOTIFICATION_IN (1 << 2) + + /* Function Prototypes: */ + #if defined(__INCLUDE_FROM_RNDIS_CLASS_HOST_C) + static uint8_t RNDIS_SendEncapsulatedCommand(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, + void* Buffer, uint16_t Length) ATTR_NON_NULL_PTR_ARG(1); + static uint8_t RNDIS_GetEncapsulatedResponse(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo, + void* Buffer, uint16_t Length) ATTR_NON_NULL_PTR_ARG(1); + + static uint8_t DComp_RNDIS_Host_NextRNDISControlInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1); + static uint8_t DComp_RNDIS_Host_NextRNDISDataInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1); + static uint8_t DComp_RNDIS_Host_NextRNDISInterfaceEndpoint(void* const CurrentDescriptor); + #endif + #endif + + /* Disable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + } + #endif + +#endif + +/** @} */ diff --git a/LUFA/Drivers/USB/Class/Host/StillImage.c b/LUFA/Drivers/USB/Class/Host/StillImage.c index 50be7d6d2..4b2c6eab7 100644 --- a/LUFA/Drivers/USB/Class/Host/StillImage.c +++ b/LUFA/Drivers/USB/Class/Host/StillImage.c @@ -1,413 +1,413 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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_USB_DRIVER
-#include "../../HighLevel/USBMode.h"
-#if defined(USB_CAN_BE_HOST)
-
-#define __INCLUDE_FROM_SI_CLASS_HOST_C
-#define __INCLUDE_FROM_SI_DRIVER
-#include "StillImage.h"
-
-uint8_t SImage_Host_ConfigurePipes(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* DeviceConfigDescriptor)
-{
- uint8_t FoundEndpoints = 0;
-
- memset(&SIInterfaceInfo->State, 0x00, sizeof(SIInterfaceInfo->State));
-
- if (DESCRIPTOR_TYPE(DeviceConfigDescriptor) != DTYPE_Configuration)
- return SI_ENUMERROR_InvalidConfigDescriptor;
-
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor,
- DComp_SI_Host_NextSIInterface) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return SI_ENUMERROR_NoSIInterfaceFound;
- }
-
- while (FoundEndpoints != (SI_FOUND_EVENTS_IN | SI_FOUND_DATAPIPE_IN | SI_FOUND_DATAPIPE_OUT))
- {
- if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor,
- DComp_SI_Host_NextSIInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
- {
- return SI_ENUMERROR_EndpointsNotFound;
- }
-
- USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Endpoint_t);
-
- if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
- {
- if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
- {
- Pipe_ConfigurePipe(SIInterfaceInfo->Config.EventsPipeNumber, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- SIInterfaceInfo->Config.EventsPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- SIInterfaceInfo->State.EventsPipeSize = EndpointData->EndpointSize;
-
- Pipe_SetInterruptPeriod(EndpointData->PollingIntervalMS);
-
- FoundEndpoints |= SI_FOUND_EVENTS_IN;
- }
- }
- else
- {
- if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
- {
- Pipe_ConfigurePipe(SIInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- SIInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- SIInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize;
-
- FoundEndpoints |= SI_FOUND_DATAPIPE_IN;
- }
- else
- {
- Pipe_ConfigurePipe(SIInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT,
- EndpointData->EndpointAddress, EndpointData->EndpointSize,
- SIInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
- SIInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize;
-
- FoundEndpoints |= SI_FOUND_DATAPIPE_OUT;
- }
- }
- }
-
- SIInterfaceInfo->State.IsActive = true;
- return SI_ENUMERROR_NoError;
-}
-
-uint8_t DComp_SI_Host_NextSIInterface(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Interface_t);
-
- if ((CurrentInterface->Class == STILL_IMAGE_CLASS) &&
- (CurrentInterface->SubClass == STILL_IMAGE_SUBCLASS) &&
- (CurrentInterface->Protocol == STILL_IMAGE_PROTOCOL))
- {
- return DESCRIPTOR_SEARCH_Found;
- }
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-uint8_t DComp_SI_Host_NextSIInterfaceEndpoint(void* const CurrentDescriptor)
-{
- if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
- {
- USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,
- USB_Descriptor_Endpoint_t);
-
- uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK);
-
- if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
- (!(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress))))
- {
- return DESCRIPTOR_SEARCH_Found;
- }
- }
- else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
- {
- return DESCRIPTOR_SEARCH_Fail;
- }
-
- return DESCRIPTOR_SEARCH_NotFound;
-}
-
-uint8_t SImage_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, SI_PIMA_Container_t* const PIMAHeader)
-{
- uint8_t ErrorCode;
-
- if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
- return PIPE_RWSTREAM_DeviceDisconnected;
-
- if (SIInterfaceInfo->State.IsSessionOpen)
- PIMAHeader->TransactionID = SIInterfaceInfo->State.TransactionID++;
-
- Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_Unfreeze();
-
- if ((ErrorCode = Pipe_Write_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0));
-
- if (ParamBytes)
- {
- if ((ErrorCode = Pipe_Write_Stream_LE(&PIMAHeader->Params, ParamBytes, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
- }
-
- Pipe_ClearOUT();
- Pipe_Freeze();
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t SImage_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, SI_PIMA_Container_t* const PIMAHeader)
-{
- uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS;
-
- if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
- return PIPE_RWSTREAM_DeviceDisconnected;
-
- Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
- Pipe_Unfreeze();
-
- while (!(Pipe_IsReadWriteAllowed()))
- {
- if (USB_INT_HasOccurred(USB_INT_HSOFI))
- {
- USB_INT_Clear(USB_INT_HSOFI);
- TimeoutMSRem--;
-
- if (!(TimeoutMSRem))
- {
- return PIPE_RWSTREAM_Timeout;
- }
- }
-
- Pipe_Freeze();
- Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_Unfreeze();
-
- if (Pipe_IsStalled())
- {
- USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataOUTPipeNumber);
- return PIPE_RWSTREAM_PipeStalled;
- }
-
- Pipe_Freeze();
- Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
- Pipe_Unfreeze();
-
- if (Pipe_IsStalled())
- {
- USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataINPipeNumber);
- return PIPE_RWSTREAM_PipeStalled;
- }
-
- if (USB_HostState == HOST_STATE_Unattached)
- return PIPE_RWSTREAM_DeviceDisconnected;
- }
-
- Pipe_Read_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK);
-
- if (PIMAHeader->Type == CType_ResponseBlock)
- {
- uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0));
-
- if (ParamBytes)
- Pipe_Read_Stream_LE(&PIMAHeader->Params, ParamBytes, NO_STREAM_CALLBACK);
-
- Pipe_ClearIN();
- }
-
- Pipe_Freeze();
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t SImage_Host_SendData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, void* Buffer, const uint16_t Bytes)
-{
- uint8_t ErrorCode;
-
- if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
- return PIPE_RWSTREAM_DeviceDisconnected;
-
- Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
- Pipe_Unfreeze();
-
- ErrorCode = Pipe_Write_Stream_LE(Buffer, Bytes, NO_STREAM_CALLBACK);
-
- Pipe_ClearOUT();
- Pipe_Freeze();
-
- return ErrorCode;
-}
-
-uint8_t SImage_Host_ReadData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, void* Buffer, const uint16_t Bytes)
-{
- uint8_t ErrorCode;
-
- if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
- return PIPE_RWSTREAM_DeviceDisconnected;
-
- Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
- Pipe_Unfreeze();
-
- ErrorCode = Pipe_Read_Stream_LE(Buffer, Bytes, NO_STREAM_CALLBACK);
-
- Pipe_Freeze();
-
- return ErrorCode;
-}
-
-bool SImage_Host_IsEventReceived(USB_ClassInfo_SI_Host_t* SIInterfaceInfo)
-{
- bool IsEventReceived = false;
-
- if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
- return false;
-
- Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipeNumber);
- Pipe_Unfreeze();
-
- if (Pipe_BytesInPipe())
- IsEventReceived = true;
-
- Pipe_Freeze();
-
- return IsEventReceived;
-}
-
-uint8_t SImage_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, SI_PIMA_Container_t* const PIMAHeader)
-{
- uint8_t ErrorCode;
-
- if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
- return PIPE_RWSTREAM_DeviceDisconnected;
-
- Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipeNumber);
- Pipe_Unfreeze();
-
- ErrorCode = Pipe_Read_Stream_LE(PIMAHeader, sizeof(SI_PIMA_Container_t), NO_STREAM_CALLBACK);
-
- Pipe_ClearIN();
- Pipe_Freeze();
-
- return ErrorCode;
-}
-
-uint8_t SImage_Host_OpenSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
- return HOST_SENDCONTROL_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- SIInterfaceInfo->State.TransactionID = 0;
- SIInterfaceInfo->State.IsSessionOpen = false;
-
- SI_PIMA_Container_t PIMABlock = (SI_PIMA_Container_t)
- {
- .DataLength = PIMA_COMMAND_SIZE(1),
- .Type = CType_CommandBlock,
- .Code = 0x1002,
- .Params = {1},
- };
-
- if ((ErrorCode = SImage_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- if ((ErrorCode = SImage_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- if ((PIMABlock.Type != CType_ResponseBlock) || (PIMABlock.Code != 0x2001))
- return SI_ERROR_LOGICAL_CMD_FAILED;
-
- SIInterfaceInfo->State.IsSessionOpen = true;
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t SImage_Host_CloseSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
- return HOST_SENDCONTROL_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- SI_PIMA_Container_t PIMABlock = (SI_PIMA_Container_t)
- {
- .DataLength = PIMA_COMMAND_SIZE(1),
- .Type = CType_CommandBlock,
- .Code = 0x1003,
- .Params = {1},
- };
-
- if ((ErrorCode = SImage_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- if ((ErrorCode = SImage_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- SIInterfaceInfo->State.IsSessionOpen = false;
-
- if ((PIMABlock.Type != CType_ResponseBlock) || (PIMABlock.Code != 0x2001))
- return SI_ERROR_LOGICAL_CMD_FAILED;
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t SImage_Host_SendCommand(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, const uint16_t Operation,
- const uint8_t TotalParams, uint32_t* Params)
-{
- if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
- return HOST_SENDCONTROL_DeviceDisconnected;
-
- uint8_t ErrorCode;
-
- SI_PIMA_Container_t PIMABlock = (SI_PIMA_Container_t)
- {
- .DataLength = PIMA_COMMAND_SIZE(TotalParams),
- .Type = CType_CommandBlock,
- .Code = Operation,
- };
-
- memcpy(&PIMABlock.Params, Params, sizeof(uint32_t) * TotalParams);
-
- if ((ErrorCode = SImage_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- return PIPE_RWSTREAM_NoError;
-}
-
-uint8_t SImage_Host_ReceiveResponse(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
-{
- uint8_t ErrorCode;
- SI_PIMA_Container_t PIMABlock;
-
- if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
- return HOST_SENDCONTROL_DeviceDisconnected;
-
- if ((ErrorCode = SImage_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
- return ErrorCode;
-
- if ((PIMABlock.Type != CType_ResponseBlock) || (PIMABlock.Code != 0x2001))
- return SI_ERROR_LOGICAL_CMD_FAILED;
-
- return PIPE_RWSTREAM_NoError;
-}
-
-#endif
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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_USB_DRIVER +#include "../../HighLevel/USBMode.h" +#if defined(USB_CAN_BE_HOST) + +#define __INCLUDE_FROM_SI_CLASS_HOST_C +#define __INCLUDE_FROM_SI_DRIVER +#include "StillImage.h" + +uint8_t SImage_Host_ConfigurePipes(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, uint16_t ConfigDescriptorSize, + void* DeviceConfigDescriptor) +{ + uint8_t FoundEndpoints = 0; + + memset(&SIInterfaceInfo->State, 0x00, sizeof(SIInterfaceInfo->State)); + + if (DESCRIPTOR_TYPE(DeviceConfigDescriptor) != DTYPE_Configuration) + return SI_ENUMERROR_InvalidConfigDescriptor; + + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor, + DComp_SI_Host_NextSIInterface) != DESCRIPTOR_SEARCH_COMP_Found) + { + return SI_ENUMERROR_NoSIInterfaceFound; + } + + while (FoundEndpoints != (SI_FOUND_EVENTS_IN | SI_FOUND_DATAPIPE_IN | SI_FOUND_DATAPIPE_OUT)) + { + if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor, + DComp_SI_Host_NextSIInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found) + { + return SI_ENUMERROR_EndpointsNotFound; + } + + USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Endpoint_t); + + if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT) + { + if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN) + { + Pipe_ConfigurePipe(SIInterfaceInfo->Config.EventsPipeNumber, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + SIInterfaceInfo->Config.EventsPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + SIInterfaceInfo->State.EventsPipeSize = EndpointData->EndpointSize; + + Pipe_SetInterruptPeriod(EndpointData->PollingIntervalMS); + + FoundEndpoints |= SI_FOUND_EVENTS_IN; + } + } + else + { + if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN) + { + Pipe_ConfigurePipe(SIInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + SIInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + SIInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize; + + FoundEndpoints |= SI_FOUND_DATAPIPE_IN; + } + else + { + Pipe_ConfigurePipe(SIInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT, + EndpointData->EndpointAddress, EndpointData->EndpointSize, + SIInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE); + SIInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize; + + FoundEndpoints |= SI_FOUND_DATAPIPE_OUT; + } + } + } + + SIInterfaceInfo->State.IsActive = true; + return SI_ENUMERROR_NoError; +} + +uint8_t DComp_SI_Host_NextSIInterface(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Interface_t); + + if ((CurrentInterface->Class == STILL_IMAGE_CLASS) && + (CurrentInterface->SubClass == STILL_IMAGE_SUBCLASS) && + (CurrentInterface->Protocol == STILL_IMAGE_PROTOCOL)) + { + return DESCRIPTOR_SEARCH_Found; + } + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +uint8_t DComp_SI_Host_NextSIInterfaceEndpoint(void* const CurrentDescriptor) +{ + if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint) + { + USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor, + USB_Descriptor_Endpoint_t); + + uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK); + + if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) && + (!(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress)))) + { + return DESCRIPTOR_SEARCH_Found; + } + } + else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) + { + return DESCRIPTOR_SEARCH_Fail; + } + + return DESCRIPTOR_SEARCH_NotFound; +} + +uint8_t SImage_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, SI_PIMA_Container_t* const PIMAHeader) +{ + uint8_t ErrorCode; + + if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive)) + return PIPE_RWSTREAM_DeviceDisconnected; + + if (SIInterfaceInfo->State.IsSessionOpen) + PIMAHeader->TransactionID = SIInterfaceInfo->State.TransactionID++; + + Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_Unfreeze(); + + if ((ErrorCode = Pipe_Write_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0)); + + if (ParamBytes) + { + if ((ErrorCode = Pipe_Write_Stream_LE(&PIMAHeader->Params, ParamBytes, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + } + + Pipe_ClearOUT(); + Pipe_Freeze(); + + return PIPE_RWSTREAM_NoError; +} + +uint8_t SImage_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, SI_PIMA_Container_t* const PIMAHeader) +{ + uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS; + + if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive)) + return PIPE_RWSTREAM_DeviceDisconnected; + + Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber); + Pipe_Unfreeze(); + + while (!(Pipe_IsReadWriteAllowed())) + { + if (USB_INT_HasOccurred(USB_INT_HSOFI)) + { + USB_INT_Clear(USB_INT_HSOFI); + TimeoutMSRem--; + + if (!(TimeoutMSRem)) + { + return PIPE_RWSTREAM_Timeout; + } + } + + Pipe_Freeze(); + Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_Unfreeze(); + + if (Pipe_IsStalled()) + { + USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataOUTPipeNumber); + return PIPE_RWSTREAM_PipeStalled; + } + + Pipe_Freeze(); + Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber); + Pipe_Unfreeze(); + + if (Pipe_IsStalled()) + { + USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataINPipeNumber); + return PIPE_RWSTREAM_PipeStalled; + } + + if (USB_HostState == HOST_STATE_Unattached) + return PIPE_RWSTREAM_DeviceDisconnected; + } + + Pipe_Read_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK); + + if (PIMAHeader->Type == CType_ResponseBlock) + { + uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0)); + + if (ParamBytes) + Pipe_Read_Stream_LE(&PIMAHeader->Params, ParamBytes, NO_STREAM_CALLBACK); + + Pipe_ClearIN(); + } + + Pipe_Freeze(); + + return PIPE_RWSTREAM_NoError; +} + +uint8_t SImage_Host_SendData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, void* Buffer, const uint16_t Bytes) +{ + uint8_t ErrorCode; + + if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive)) + return PIPE_RWSTREAM_DeviceDisconnected; + + Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber); + Pipe_Unfreeze(); + + ErrorCode = Pipe_Write_Stream_LE(Buffer, Bytes, NO_STREAM_CALLBACK); + + Pipe_ClearOUT(); + Pipe_Freeze(); + + return ErrorCode; +} + +uint8_t SImage_Host_ReadData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, void* Buffer, const uint16_t Bytes) +{ + uint8_t ErrorCode; + + if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive)) + return PIPE_RWSTREAM_DeviceDisconnected; + + Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber); + Pipe_Unfreeze(); + + ErrorCode = Pipe_Read_Stream_LE(Buffer, Bytes, NO_STREAM_CALLBACK); + + Pipe_Freeze(); + + return ErrorCode; +} + +bool SImage_Host_IsEventReceived(USB_ClassInfo_SI_Host_t* SIInterfaceInfo) +{ + bool IsEventReceived = false; + + if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive)) + return false; + + Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipeNumber); + Pipe_Unfreeze(); + + if (Pipe_BytesInPipe()) + IsEventReceived = true; + + Pipe_Freeze(); + + return IsEventReceived; +} + +uint8_t SImage_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, SI_PIMA_Container_t* const PIMAHeader) +{ + uint8_t ErrorCode; + + if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive)) + return PIPE_RWSTREAM_DeviceDisconnected; + + Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipeNumber); + Pipe_Unfreeze(); + + ErrorCode = Pipe_Read_Stream_LE(PIMAHeader, sizeof(SI_PIMA_Container_t), NO_STREAM_CALLBACK); + + Pipe_ClearIN(); + Pipe_Freeze(); + + return ErrorCode; +} + +uint8_t SImage_Host_OpenSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive)) + return HOST_SENDCONTROL_DeviceDisconnected; + + uint8_t ErrorCode; + + SIInterfaceInfo->State.TransactionID = 0; + SIInterfaceInfo->State.IsSessionOpen = false; + + SI_PIMA_Container_t PIMABlock = (SI_PIMA_Container_t) + { + .DataLength = PIMA_COMMAND_SIZE(1), + .Type = CType_CommandBlock, + .Code = 0x1002, + .Params = {1}, + }; + + if ((ErrorCode = SImage_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + if ((ErrorCode = SImage_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + if ((PIMABlock.Type != CType_ResponseBlock) || (PIMABlock.Code != 0x2001)) + return SI_ERROR_LOGICAL_CMD_FAILED; + + SIInterfaceInfo->State.IsSessionOpen = true; + + return PIPE_RWSTREAM_NoError; +} + +uint8_t SImage_Host_CloseSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive)) + return HOST_SENDCONTROL_DeviceDisconnected; + + uint8_t ErrorCode; + + SI_PIMA_Container_t PIMABlock = (SI_PIMA_Container_t) + { + .DataLength = PIMA_COMMAND_SIZE(1), + .Type = CType_CommandBlock, + .Code = 0x1003, + .Params = {1}, + }; + + if ((ErrorCode = SImage_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + if ((ErrorCode = SImage_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + SIInterfaceInfo->State.IsSessionOpen = false; + + if ((PIMABlock.Type != CType_ResponseBlock) || (PIMABlock.Code != 0x2001)) + return SI_ERROR_LOGICAL_CMD_FAILED; + + return PIPE_RWSTREAM_NoError; +} + +uint8_t SImage_Host_SendCommand(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, const uint16_t Operation, + const uint8_t TotalParams, uint32_t* Params) +{ + if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive)) + return HOST_SENDCONTROL_DeviceDisconnected; + + uint8_t ErrorCode; + + SI_PIMA_Container_t PIMABlock = (SI_PIMA_Container_t) + { + .DataLength = PIMA_COMMAND_SIZE(TotalParams), + .Type = CType_CommandBlock, + .Code = Operation, + }; + + memcpy(&PIMABlock.Params, Params, sizeof(uint32_t) * TotalParams); + + if ((ErrorCode = SImage_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + return PIPE_RWSTREAM_NoError; +} + +uint8_t SImage_Host_ReceiveResponse(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) +{ + uint8_t ErrorCode; + SI_PIMA_Container_t PIMABlock; + + if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive)) + return HOST_SENDCONTROL_DeviceDisconnected; + + if ((ErrorCode = SImage_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError) + return ErrorCode; + + if ((PIMABlock.Type != CType_ResponseBlock) || (PIMABlock.Code != 0x2001)) + return SI_ERROR_LOGICAL_CMD_FAILED; + + return PIPE_RWSTREAM_NoError; +} + +#endif diff --git a/LUFA/Drivers/USB/Class/Host/StillImage.h b/LUFA/Drivers/USB/Class/Host/StillImage.h index 4a5ccfabd..be3357969 100644 --- a/LUFA/Drivers/USB/Class/Host/StillImage.h +++ b/LUFA/Drivers/USB/Class/Host/StillImage.h @@ -1,323 +1,323 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, 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
- * \brief Host mode driver for the library USB Still Image Class driver.
- *
- * Host mode driver for the library USB Still Image Class driver.
- *
- * \note This file should not be included directly. It is automatically included as needed by the class driver
- * dispatch header located in LUFA/Drivers/USB/Class/StillImage.h.
- */
-
-/** \ingroup Group_USBClassSI
- * @defgroup Group_USBClassStillImageHost Still Image Class Host Mode Driver
- *
- * \section Sec_Dependencies Module Source Dependencies
- * The following files must be built with any user project that uses this module:
- * - LUFA/Drivers/USB/Class/Host/StillImage.c
- *
- * \section Module Description
- * Host Mode USB Class driver framework interface, for the Still Image USB Class driver.
- *
- * @{
- */
-
-#ifndef __SI_CLASS_HOST_H__
-#define __SI_CLASS_HOST_H__
-
- /* Includes: */
- #include "../../USB.h"
- #include "../Common/StillImage.h"
-
- /* Enable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- extern "C" {
- #endif
-
- /* Preprocessor Checks: */
- #if !defined(__INCLUDE_FROM_SI_DRIVER)
- #error Do not include this file directly. Include LUFA/Drivers/Class/StillImage.h instead.
- #endif
-
- /* Public Interface - May be used in end-application: */
- /* Macros: */
- /** Error code for some Still Image Host functions, indicating a logical (and not hardware) error */
- #define SI_ERROR_LOGICAL_CMD_FAILED 0x80
-
- /* Type Defines: */
- /** \brief Still Image Class Host Mode Configuration and State Structure.
- *
- * Class state structure. An instance of this structure should be made within the user application,
- * and passed to each of the Still Image class driver functions as the SIInterfaceInfo parameter. This
- * stores each Still Image interface's configuration and state information.
- */
- typedef struct
- {
- const struct
- {
- uint8_t DataINPipeNumber; /**< Pipe number of the Still Image interface's IN data pipe */
- bool DataINPipeDoubleBank; /** Indicates if the Still Image interface's IN data pipe should use double banking */
-
- uint8_t DataOUTPipeNumber; /**< Pipe number of the Still Image interface's OUT data pipe */
- bool DataOUTPipeDoubleBank; /** Indicates if the Still Image interface's OUT data pipe should use double banking */
-
- uint8_t EventsPipeNumber; /**< Pipe number of the Still Image interface's IN events endpoint, if used */
- bool EventsPipeDoubleBank; /** Indicates if the Still Image interface's events data pipe should use double banking */
- } Config; /**< Config data for the USB class interface within the device. All elements in this section
- * <b>must</b> be set or the interface will fail to enumerate and operate correctly.
- */
- struct
- {
- bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
- * after \ref SImage_Host_ConfigurePipes() is called and the Host state machine is in the
- * Configured state
- */
-
- uint16_t DataINPipeSize; /**< Size in bytes of the Still Image interface's IN data pipe */
- uint16_t DataOUTPipeSize; /**< Size in bytes of the Still Image interface's OUT data pipe */
- uint16_t EventsPipeSize; /**< Size in bytes of the Still Image interface's IN events pipe */
-
- bool IsSessionOpen; /**< Indicates if a PIMA session is currently open with the attached device */
- uint32_t TransactionID; /**< Transaction ID for the next transaction to send to the device */
- } State; /**< State data for the USB class interface within the device. All elements in this section
- * <b>may</b> be set to initial values, but may also be ignored to default to sane values when
- * the interface is enumerated.
- */
- } USB_ClassInfo_SI_Host_t;
-
- /* Enums: */
- /** Enum for the possible error codes returned by the \ref SImage_Host_ConfigurePipes() function. */
- enum SIHost_EnumerationFailure_ErrorCodes_t
- {
- SI_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */
- SI_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */
- SI_ENUMERROR_NoSIInterfaceFound = 2, /**< A compatible Still Image interface was not found in the device's
- * Configuration Descriptor
- */
- SI_ENUMERROR_EndpointsNotFound = 3, /**< Compatible Still Image data endpoints were not found in the
- * device's Still Image interface
- */
- };
-
- /* Function Prototypes: */
- /** Host interface configuration routine, to configure a given Still Image host interface instance using the
- * Configuration Descriptor read from an attached USB device. This function automatically updates the given Still
- * Image Host instance's state values and configures the pipes required to communicate with the interface if it is
- * found within the device. This should be called once after the stack has enumerated the attached device, while
- * the host state machine is in the Addressed state.
- *
- * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state
- * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor
- * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor
- *
- * \return A value from the \ref SIHost_EnumerationFailure_ErrorCodes_t enum
- */
- uint8_t SImage_Host_ConfigurePipes(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, uint16_t ConfigDescriptorSize,
- void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
-
- /** Opens a new PIMA session with the attached device. This should be used before any session-orientated PIMA commands
- * are issued to the device. Only one session can be open at the one time.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device
- * returned a logical command failure
- */
- uint8_t SImage_Host_OpenSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Closes an already opened PIMA session with the attached device. This should be used after all session-orientated
- * PIMA commands have been issued to the device.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device
- * returned a logical command failure
- */
- uint8_t SImage_Host_CloseSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Sends a raw PIMA block header to the device, filling out the transaction ID automatically. This can be used to send
- * arbitrary PIMA blocks to the device with or without parameters.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state
- * \param[in] PIMAHeader Pointer to a PIMA container structure that is to be sent
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum
- */
- uint8_t SImage_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, SI_PIMA_Container_t* const PIMAHeader);
-
- /** Receives a raw PIMA block header to the device. This can be used to receive arbitrary PIMA blocks from the device with
- * or without parameters.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state
- * \param[out] PIMAHeader Pointer to a PIMA container structure where the received block is to be stored
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum
- */
- uint8_t SImage_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, SI_PIMA_Container_t* const PIMAHeader);
-
- /** Sends a given PIMA command to the attached device, filling out the PIMA command header's Transaction ID automatically.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state
- * \param[in] Operation PIMA operation code to issue to the device
- * \param[in] TotalParams Total number of 32-bit parameters to send to the device in the issued command block
- * \param[in] Params Pointer to an array of 32-bit values containing the parameters to send in the command block
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device
- * returned a logical command failure
- */
- uint8_t SImage_Host_SendCommand(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, const uint16_t Operation,
- const uint8_t TotalParams, uint32_t* Params) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Receives and checks a response block from the attached PIMA device, once a command has been issued and all data
- * associated with the command has been transferred.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device
- * returned a logical command failure
- */
- uint8_t SImage_Host_ReceiveResponse(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Indicates if the device has issued a PIMA event block to the host via the asynchronous events pipe.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state
- *
- * \return Boolean true if an event is waiting to be read, false otherwise
- */
- bool SImage_Host_IsEventReceived(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
-
- /** Receives an asynchronous event block from the device via the asynchronous events pipe.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state
- * \param[out] PIMAHeader Pointer to a PIMA container structure where the event should be stored
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device
- * returned a logical command failure
- */
- uint8_t SImage_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
- SI_PIMA_Container_t* const PIMAHeader) ATTR_NON_NULL_PTR_ARG(1)
- ATTR_NON_NULL_PTR_ARG(2);
-
- /** Sends arbitrary data to the attached device, for use in the data phase of PIMA commands which require data
- * transfer beyond the regular PIMA command block parameters.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state
- * \param[in] Buffer Pointer to a buffer where the data to send has been stored
- * \param[in] Bytes Length in bytes of the data in the buffer to send to the attached device
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum
- */
- uint8_t SImage_Host_SendData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, void* Buffer,
- const uint16_t Bytes) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
-
- /** Receives arbitrary data from the attached device, for use in the data phase of PIMA commands which require data
- * transfer beyond the regular PIMA command block parameters.
- *
- * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the
- * call will fail.
- *
- * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state
- * \param[out] Buffer Pointer to a buffer where the received data is to be stored
- * \param[in] Bytes Length in bytes of the data to read
- *
- * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum
- */
- uint8_t SImage_Host_ReadData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, void* Buffer,
- const uint16_t Bytes) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
-
- /* Inline Functions: */
- /** General management task for a given Still Image host class interface, required for the correct operation of the
- * interface. This should be called frequently in the main program loop, before the master USB management task
- * \ref USB_USBTask().
- *
- * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state
- */
- static inline void SImage_Host_USBTask(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo);
- static inline void SImage_Host_USBTask(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
- {
- (void)SIInterfaceInfo;
- }
-
- /* Private Interface - For use in library only: */
- #if !defined(__DOXYGEN__)
- /* Macros: */
- #define STILL_IMAGE_CLASS 0x06
- #define STILL_IMAGE_SUBCLASS 0x01
- #define STILL_IMAGE_PROTOCOL 0x01
-
- #define SI_FOUND_EVENTS_IN (1 << 0)
- #define SI_FOUND_DATAPIPE_IN (1 << 1)
- #define SI_FOUND_DATAPIPE_OUT (1 << 2)
-
- #define COMMAND_DATA_TIMEOUT_MS 10000
-
- /* Function Prototypes: */
- #if defined(__INCLUDE_FROM_SI_CLASS_HOST_C)
- static uint8_t DComp_SI_Host_NextSIInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1);
- static uint8_t DComp_SI_Host_NextSIInterfaceEndpoint(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1);
- #endif
- #endif
-
- /* Disable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- }
- #endif
-
-#endif
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, 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 + * \brief Host mode driver for the library USB Still Image Class driver. + * + * Host mode driver for the library USB Still Image Class driver. + * + * \note This file should not be included directly. It is automatically included as needed by the class driver + * dispatch header located in LUFA/Drivers/USB/Class/StillImage.h. + */ + +/** \ingroup Group_USBClassSI + * @defgroup Group_USBClassStillImageHost Still Image Class Host Mode Driver + * + * \section Sec_Dependencies Module Source Dependencies + * The following files must be built with any user project that uses this module: + * - LUFA/Drivers/USB/Class/Host/StillImage.c + * + * \section Module Description + * Host Mode USB Class driver framework interface, for the Still Image USB Class driver. + * + * @{ + */ + +#ifndef __SI_CLASS_HOST_H__ +#define __SI_CLASS_HOST_H__ + + /* Includes: */ + #include "../../USB.h" + #include "../Common/StillImage.h" + + /* Enable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + extern "C" { + #endif + + /* Preprocessor Checks: */ + #if !defined(__INCLUDE_FROM_SI_DRIVER) + #error Do not include this file directly. Include LUFA/Drivers/Class/StillImage.h instead. + #endif + + /* Public Interface - May be used in end-application: */ + /* Macros: */ + /** Error code for some Still Image Host functions, indicating a logical (and not hardware) error */ + #define SI_ERROR_LOGICAL_CMD_FAILED 0x80 + + /* Type Defines: */ + /** \brief Still Image Class Host Mode Configuration and State Structure. + * + * Class state structure. An instance of this structure should be made within the user application, + * and passed to each of the Still Image class driver functions as the SIInterfaceInfo parameter. This + * stores each Still Image interface's configuration and state information. + */ + typedef struct + { + const struct + { + uint8_t DataINPipeNumber; /**< Pipe number of the Still Image interface's IN data pipe */ + bool DataINPipeDoubleBank; /** Indicates if the Still Image interface's IN data pipe should use double banking */ + + uint8_t DataOUTPipeNumber; /**< Pipe number of the Still Image interface's OUT data pipe */ + bool DataOUTPipeDoubleBank; /** Indicates if the Still Image interface's OUT data pipe should use double banking */ + + uint8_t EventsPipeNumber; /**< Pipe number of the Still Image interface's IN events endpoint, if used */ + bool EventsPipeDoubleBank; /** Indicates if the Still Image interface's events data pipe should use double banking */ + } Config; /**< Config data for the USB class interface within the device. All elements in this section + * <b>must</b> be set or the interface will fail to enumerate and operate correctly. + */ + struct + { + bool IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid + * after \ref SImage_Host_ConfigurePipes() is called and the Host state machine is in the + * Configured state + */ + + uint16_t DataINPipeSize; /**< Size in bytes of the Still Image interface's IN data pipe */ + uint16_t DataOUTPipeSize; /**< Size in bytes of the Still Image interface's OUT data pipe */ + uint16_t EventsPipeSize; /**< Size in bytes of the Still Image interface's IN events pipe */ + + bool IsSessionOpen; /**< Indicates if a PIMA session is currently open with the attached device */ + uint32_t TransactionID; /**< Transaction ID for the next transaction to send to the device */ + } State; /**< State data for the USB class interface within the device. All elements in this section + * <b>may</b> be set to initial values, but may also be ignored to default to sane values when + * the interface is enumerated. + */ + } USB_ClassInfo_SI_Host_t; + + /* Enums: */ + /** Enum for the possible error codes returned by the \ref SImage_Host_ConfigurePipes() function. */ + enum SIHost_EnumerationFailure_ErrorCodes_t + { + SI_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully */ + SI_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor */ + SI_ENUMERROR_NoSIInterfaceFound = 2, /**< A compatible Still Image interface was not found in the device's + * Configuration Descriptor + */ + SI_ENUMERROR_EndpointsNotFound = 3, /**< Compatible Still Image data endpoints were not found in the + * device's Still Image interface + */ + }; + + /* Function Prototypes: */ + /** Host interface configuration routine, to configure a given Still Image host interface instance using the + * Configuration Descriptor read from an attached USB device. This function automatically updates the given Still + * Image Host instance's state values and configures the pipes required to communicate with the interface if it is + * found within the device. This should be called once after the stack has enumerated the attached device, while + * the host state machine is in the Addressed state. + * + * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state + * \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor + * \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor + * + * \return A value from the \ref SIHost_EnumerationFailure_ErrorCodes_t enum + */ + uint8_t SImage_Host_ConfigurePipes(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, uint16_t ConfigDescriptorSize, + void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3); + + /** Opens a new PIMA session with the attached device. This should be used before any session-orientated PIMA commands + * are issued to the device. Only one session can be open at the one time. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device + * returned a logical command failure + */ + uint8_t SImage_Host_OpenSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Closes an already opened PIMA session with the attached device. This should be used after all session-orientated + * PIMA commands have been issued to the device. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device + * returned a logical command failure + */ + uint8_t SImage_Host_CloseSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Sends a raw PIMA block header to the device, filling out the transaction ID automatically. This can be used to send + * arbitrary PIMA blocks to the device with or without parameters. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state + * \param[in] PIMAHeader Pointer to a PIMA container structure that is to be sent + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum + */ + uint8_t SImage_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, SI_PIMA_Container_t* const PIMAHeader); + + /** Receives a raw PIMA block header to the device. This can be used to receive arbitrary PIMA blocks from the device with + * or without parameters. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state + * \param[out] PIMAHeader Pointer to a PIMA container structure where the received block is to be stored + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum + */ + uint8_t SImage_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, SI_PIMA_Container_t* const PIMAHeader); + + /** Sends a given PIMA command to the attached device, filling out the PIMA command header's Transaction ID automatically. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state + * \param[in] Operation PIMA operation code to issue to the device + * \param[in] TotalParams Total number of 32-bit parameters to send to the device in the issued command block + * \param[in] Params Pointer to an array of 32-bit values containing the parameters to send in the command block + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device + * returned a logical command failure + */ + uint8_t SImage_Host_SendCommand(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, const uint16_t Operation, + const uint8_t TotalParams, uint32_t* Params) ATTR_NON_NULL_PTR_ARG(1); + + /** Receives and checks a response block from the attached PIMA device, once a command has been issued and all data + * associated with the command has been transferred. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device + * returned a logical command failure + */ + uint8_t SImage_Host_ReceiveResponse(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Indicates if the device has issued a PIMA event block to the host via the asynchronous events pipe. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state + * + * \return Boolean true if an event is waiting to be read, false otherwise + */ + bool SImage_Host_IsEventReceived(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Receives an asynchronous event block from the device via the asynchronous events pipe. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state + * \param[out] PIMAHeader Pointer to a PIMA container structure where the event should be stored + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device + * returned a logical command failure + */ + uint8_t SImage_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, + SI_PIMA_Container_t* const PIMAHeader) ATTR_NON_NULL_PTR_ARG(1) + ATTR_NON_NULL_PTR_ARG(2); + + /** Sends arbitrary data to the attached device, for use in the data phase of PIMA commands which require data + * transfer beyond the regular PIMA command block parameters. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state + * \param[in] Buffer Pointer to a buffer where the data to send has been stored + * \param[in] Bytes Length in bytes of the data in the buffer to send to the attached device + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum + */ + uint8_t SImage_Host_SendData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, void* Buffer, + const uint16_t Bytes) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + + /** Receives arbitrary data from the attached device, for use in the data phase of PIMA commands which require data + * transfer beyond the regular PIMA command block parameters. + * + * \note This function must only be called when the Host state machine is in the HOST_STATE_Configured state or the + * call will fail. + * + * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state + * \param[out] Buffer Pointer to a buffer where the received data is to be stored + * \param[in] Bytes Length in bytes of the data to read + * + * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum + */ + uint8_t SImage_Host_ReadData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, void* Buffer, + const uint16_t Bytes) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + + /* Inline Functions: */ + /** General management task for a given Still Image host class interface, required for the correct operation of the + * interface. This should be called frequently in the main program loop, before the master USB management task + * \ref USB_USBTask(). + * + * \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state + */ + static inline void SImage_Host_USBTask(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo); + static inline void SImage_Host_USBTask(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) + { + (void)SIInterfaceInfo; + } + + /* Private Interface - For use in library only: */ + #if !defined(__DOXYGEN__) + /* Macros: */ + #define STILL_IMAGE_CLASS 0x06 + #define STILL_IMAGE_SUBCLASS 0x01 + #define STILL_IMAGE_PROTOCOL 0x01 + + #define SI_FOUND_EVENTS_IN (1 << 0) + #define SI_FOUND_DATAPIPE_IN (1 << 1) + #define SI_FOUND_DATAPIPE_OUT (1 << 2) + + #define COMMAND_DATA_TIMEOUT_MS 10000 + + /* Function Prototypes: */ + #if defined(__INCLUDE_FROM_SI_CLASS_HOST_C) + static uint8_t DComp_SI_Host_NextSIInterface(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1); + static uint8_t DComp_SI_Host_NextSIInterfaceEndpoint(void* const CurrentDescriptor) ATTR_NON_NULL_PTR_ARG(1); + #endif + #endif + + /* Disable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + } + #endif + +#endif + +/** @} */ |