3 Copyright (C) Dean Camera, 2011.
5 dean [at] fourwalledcubicle [dot] com
10 Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
31 #define __INCLUDE_FROM_USB_DRIVER
32 #include "../../HighLevel/USBMode.h"
33 #if defined(USB_CAN_BE_HOST)
35 #define __INCLUDE_FROM_HID_DRIVER
36 #define __INCLUDE_FROM_HID_HOST_C
39 uint8_t HID_Host_ConfigurePipes(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
,
40 uint16_t ConfigDescriptorSize
,
41 void* ConfigDescriptorData
)
43 USB_Descriptor_Endpoint_t
* DataINEndpoint
= NULL
;
44 USB_Descriptor_Endpoint_t
* DataOUTEndpoint
= NULL
;
45 USB_Descriptor_Interface_t
* HIDInterface
= NULL
;
46 USB_HID_Descriptor_HID_t
* HIDDescriptor
= NULL
;
48 memset(&HIDInterfaceInfo
->State
, 0x00, sizeof(HIDInterfaceInfo
->State
));
50 if (DESCRIPTOR_TYPE(ConfigDescriptorData
) != DTYPE_Configuration
)
51 return HID_ENUMERROR_InvalidConfigDescriptor
;
53 while (!(DataINEndpoint
) || !(DataOUTEndpoint
))
55 if (!(HIDInterface
) ||
56 USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
,
57 DCOMP_HID_Host_NextHIDInterfaceEndpoint
) != DESCRIPTOR_SEARCH_COMP_Found
)
59 if (DataINEndpoint
|| DataOUTEndpoint
)
64 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
,
65 DCOMP_HID_Host_NextHIDInterface
) != DESCRIPTOR_SEARCH_COMP_Found
)
67 return HID_ENUMERROR_NoCompatibleInterfaceFound
;
70 HIDInterface
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Interface_t
);
71 } while (HIDInterfaceInfo
->Config
.HIDInterfaceProtocol
&&
72 (HIDInterface
->Protocol
!= HIDInterfaceInfo
->Config
.HIDInterfaceProtocol
));
74 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
,
75 DCOMP_HID_Host_NextHID
) != DESCRIPTOR_SEARCH_COMP_Found
)
77 return HID_ENUMERROR_NoCompatibleInterfaceFound
;
80 HIDDescriptor
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_HID_Descriptor_HID_t
);
82 DataINEndpoint
= NULL
;
83 DataOUTEndpoint
= NULL
;
88 USB_Descriptor_Endpoint_t
* EndpointData
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Endpoint_t
);
90 if (EndpointData
->EndpointAddress
& ENDPOINT_DESCRIPTOR_DIR_IN
)
91 DataINEndpoint
= EndpointData
;
93 DataOUTEndpoint
= EndpointData
;
96 for (uint8_t PipeNum
= 1; PipeNum
< PIPE_TOTAL_PIPES
; PipeNum
++)
101 uint8_t EndpointAddress
;
102 uint8_t InterruptPeriod
;
105 if (PipeNum
== HIDInterfaceInfo
->Config
.DataINPipeNumber
)
107 Size
= DataINEndpoint
->EndpointSize
;
108 EndpointAddress
= DataINEndpoint
->EndpointAddress
;
109 Token
= PIPE_TOKEN_IN
;
110 Type
= EP_TYPE_INTERRUPT
;
111 DoubleBanked
= HIDInterfaceInfo
->Config
.DataINPipeDoubleBank
;
112 InterruptPeriod
= DataINEndpoint
->PollingIntervalMS
;
114 HIDInterfaceInfo
->State
.DataINPipeSize
= DataINEndpoint
->EndpointSize
;
116 else if (PipeNum
== HIDInterfaceInfo
->Config
.DataOUTPipeNumber
)
118 if (DataOUTEndpoint
== NULL
)
121 Size
= DataOUTEndpoint
->EndpointSize
;
122 EndpointAddress
= DataOUTEndpoint
->EndpointAddress
;
123 Token
= PIPE_TOKEN_OUT
;
124 Type
= EP_TYPE_INTERRUPT
;
125 DoubleBanked
= HIDInterfaceInfo
->Config
.DataOUTPipeDoubleBank
;
126 InterruptPeriod
= DataOUTEndpoint
->PollingIntervalMS
;
128 HIDInterfaceInfo
->State
.DataOUTPipeSize
= DataOUTEndpoint
->EndpointSize
;
129 HIDInterfaceInfo
->State
.DeviceUsesOUTPipe
= true;
136 if (!(Pipe_ConfigurePipe(PipeNum
, Type
, Token
, EndpointAddress
, Size
,
137 DoubleBanked ? PIPE_BANK_DOUBLE
: PIPE_BANK_SINGLE
)))
139 return HID_ENUMERROR_PipeConfigurationFailed
;
143 Pipe_SetInterruptPeriod(InterruptPeriod
);
146 HIDInterfaceInfo
->State
.InterfaceNumber
= HIDInterface
->InterfaceNumber
;
147 HIDInterfaceInfo
->State
.HIDReportSize
= HIDDescriptor
->HIDReportLength
;
148 HIDInterfaceInfo
->State
.SupportsBootProtocol
= (HIDInterface
->SubClass
!= HID_CSCP_NonBootProtocol
);
149 HIDInterfaceInfo
->State
.LargestReportSize
= 8;
150 HIDInterfaceInfo
->State
.IsActive
= true;
152 return HID_ENUMERROR_NoError
;
155 static uint8_t DCOMP_HID_Host_NextHIDInterface(void* const CurrentDescriptor
)
157 USB_Descriptor_Header_t
* Header
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
);
159 if (Header
->Type
== DTYPE_Interface
)
161 USB_Descriptor_Interface_t
* Interface
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Interface_t
);
163 if (Interface
->Class
== HID_CSCP_HIDClass
)
164 return DESCRIPTOR_SEARCH_Found
;
167 return DESCRIPTOR_SEARCH_NotFound
;
170 static uint8_t DCOMP_HID_Host_NextHID(void* const CurrentDescriptor
)
172 USB_Descriptor_Header_t
* Header
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
);
174 if (Header
->Type
== HID_DTYPE_HID
)
175 return DESCRIPTOR_SEARCH_Found
;
176 else if (Header
->Type
== DTYPE_Interface
)
177 return DESCRIPTOR_SEARCH_Fail
;
179 return DESCRIPTOR_SEARCH_NotFound
;
182 static uint8_t DCOMP_HID_Host_NextHIDInterfaceEndpoint(void* const CurrentDescriptor
)
184 USB_Descriptor_Header_t
* Header
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
);
186 if (Header
->Type
== DTYPE_Endpoint
)
188 USB_Descriptor_Endpoint_t
* Endpoint
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Endpoint_t
);
190 if (!(Pipe_IsEndpointBound(Endpoint
->EndpointAddress
)))
191 return DESCRIPTOR_SEARCH_Found
;
193 else if (Header
->Type
== DTYPE_Interface
)
195 return DESCRIPTOR_SEARCH_Fail
;
198 return DESCRIPTOR_SEARCH_NotFound
;
201 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
202 uint8_t HID_Host_ReceiveReportByID(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
,
203 const uint8_t ReportID
,
206 USB_ControlRequest
= (USB_Request_Header_t
)
208 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
209 .bRequest
= HID_REQ_SetReport
,
210 .wValue
= ((HID_REPORT_ITEM_In
+ 1) << 8) | ReportID
,
211 .wIndex
= HIDInterfaceInfo
->State
.InterfaceNumber
,
212 .wLength
= USB_GetHIDReportSize(HIDInterfaceInfo
->Config
.HIDParserData
, ReportID
, HID_REPORT_ITEM_In
),
215 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
217 return USB_Host_SendControlRequest(Buffer
);
221 uint8_t HID_Host_ReceiveReport(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
,
224 if ((USB_HostState
!= HOST_STATE_Configured
) || !(HIDInterfaceInfo
->State
.IsActive
))
225 return PIPE_READYWAIT_DeviceDisconnected
;
229 Pipe_SelectPipe(HIDInterfaceInfo
->Config
.DataINPipeNumber
);
233 uint8_t* BufferPos
= Buffer
;
235 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
236 if (!(HIDInterfaceInfo
->State
.UsingBootProtocol
))
238 uint8_t ReportID
= 0;
240 if (HIDInterfaceInfo
->Config
.HIDParserData
->UsingReportIDs
)
242 ReportID
= Pipe_Read_Byte();
243 *(BufferPos
++) = ReportID
;
246 ReportSize
= USB_GetHIDReportSize(HIDInterfaceInfo
->Config
.HIDParserData
, ReportID
, HID_REPORT_ITEM_In
);
251 ReportSize
= Pipe_BytesInPipe();
254 if ((ErrorCode
= Pipe_Read_Stream_LE(BufferPos
, ReportSize
, NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
)
260 return PIPE_RWSTREAM_NoError
;
263 uint8_t HID_Host_SendReportByID(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
,
264 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
265 const uint8_t ReportID
,
267 const uint8_t ReportType
,
269 const uint16_t ReportSize
)
271 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
272 if ((USB_HostState
!= HOST_STATE_Configured
) || !(HIDInterfaceInfo
->State
.IsActive
))
275 if (HIDInterfaceInfo
->State
.DeviceUsesOUTPipe
&& (ReportType
== HID_REPORT_ITEM_Out
))
279 Pipe_SelectPipe(HIDInterfaceInfo
->Config
.DataOUTPipeNumber
);
283 Pipe_Write_Stream_LE(&ReportID
, sizeof(ReportID
), NO_STREAM_CALLBACK
);
285 if ((ErrorCode
= Pipe_Write_Stream_LE(Buffer
, ReportSize
, NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
)
291 return PIPE_RWSTREAM_NoError
;
296 USB_ControlRequest
= (USB_Request_Header_t
)
298 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
299 .bRequest
= HID_REQ_SetReport
,
300 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
301 .wValue
= ((ReportType
+ 1) << 8) | ReportID
,
303 .wValue
= ((ReportType
+ 1) << 8),
305 .wIndex
= HIDInterfaceInfo
->State
.InterfaceNumber
,
306 .wLength
= ReportSize
,
309 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
311 return USB_Host_SendControlRequest(Buffer
);
315 bool HID_Host_IsReportReceived(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
)
317 if ((USB_HostState
!= HOST_STATE_Configured
) || !(HIDInterfaceInfo
->State
.IsActive
))
322 Pipe_SelectPipe(HIDInterfaceInfo
->Config
.DataINPipeNumber
);
325 ReportReceived
= Pipe_IsINReceived();
329 return ReportReceived
;
332 uint8_t HID_Host_SetBootProtocol(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
)
336 USB_ControlRequest
= (USB_Request_Header_t
)
338 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
339 .bRequest
= HID_REQ_SetProtocol
,
341 .wIndex
= HIDInterfaceInfo
->State
.InterfaceNumber
,
345 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
347 if (!(HIDInterfaceInfo
->State
.SupportsBootProtocol
))
348 return HID_ERROR_LOGICAL
;
350 if ((ErrorCode
= USB_Host_SendControlRequest(NULL
)) != HOST_SENDCONTROL_Successful
)
353 HIDInterfaceInfo
->State
.LargestReportSize
= 8;
354 HIDInterfaceInfo
->State
.UsingBootProtocol
= true;
356 return HOST_SENDCONTROL_Successful
;
359 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
360 uint8_t HID_Host_SetReportProtocol(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
)
364 uint8_t HIDReportData
[HIDInterfaceInfo
->State
.HIDReportSize
];
366 USB_ControlRequest
= (USB_Request_Header_t
)
368 .bmRequestType
= (REQDIR_DEVICETOHOST
| REQTYPE_STANDARD
| REQREC_INTERFACE
),
369 .bRequest
= REQ_GetDescriptor
,
370 .wValue
= (HID_DTYPE_Report
<< 8),
371 .wIndex
= HIDInterfaceInfo
->State
.InterfaceNumber
,
372 .wLength
= HIDInterfaceInfo
->State
.HIDReportSize
,
375 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
377 if ((ErrorCode
= USB_Host_SendControlRequest(HIDReportData
)) != HOST_SENDCONTROL_Successful
)
380 if (HIDInterfaceInfo
->State
.UsingBootProtocol
)
382 USB_ControlRequest
= (USB_Request_Header_t
)
384 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
385 .bRequest
= HID_REQ_SetProtocol
,
387 .wIndex
= HIDInterfaceInfo
->State
.InterfaceNumber
,
391 if ((ErrorCode
= USB_Host_SendControlRequest(NULL
)) != HOST_SENDCONTROL_Successful
)
394 HIDInterfaceInfo
->State
.UsingBootProtocol
= false;
397 if (HIDInterfaceInfo
->Config
.HIDParserData
== NULL
)
398 return HID_ERROR_LOGICAL
;
400 if ((ErrorCode
= USB_ProcessHIDReport(HIDReportData
, HIDInterfaceInfo
->State
.HIDReportSize
,
401 HIDInterfaceInfo
->Config
.HIDParserData
)) != HID_PARSE_Successful
)
403 return HID_ERROR_LOGICAL
| ErrorCode
;
406 uint8_t LargestReportSizeBits
= HIDInterfaceInfo
->Config
.HIDParserData
->LargestReportSizeBits
;
407 HIDInterfaceInfo
->State
.LargestReportSize
= (LargestReportSizeBits
>> 3) + ((LargestReportSizeBits
& 0x07) != 0);