3 Copyright (C) Dean Camera, 2013.
5 dean [at] fourwalledcubicle [dot] com
10 Copyright 2013 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 disclaims 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 "../../Core/USBMode.h"
34 #if defined(USB_CAN_BE_HOST)
36 #define __INCLUDE_FROM_HID_DRIVER
37 #define __INCLUDE_FROM_HID_HOST_C
38 #include "HIDClassHost.h"
40 uint8_t HID_Host_ConfigurePipes(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
,
41 uint16_t ConfigDescriptorSize
,
42 void* ConfigDescriptorData
)
44 USB_Descriptor_Endpoint_t
* DataINEndpoint
= NULL
;
45 USB_Descriptor_Endpoint_t
* DataOUTEndpoint
= NULL
;
46 USB_Descriptor_Interface_t
* HIDInterface
= NULL
;
47 USB_HID_Descriptor_HID_t
* HIDDescriptor
= NULL
;
49 memset(&HIDInterfaceInfo
->State
, 0x00, sizeof(HIDInterfaceInfo
->State
));
51 if (DESCRIPTOR_TYPE(ConfigDescriptorData
) != DTYPE_Configuration
)
52 return HID_ENUMERROR_InvalidConfigDescriptor
;
54 while (!(DataINEndpoint
) || !(DataOUTEndpoint
))
56 if (!(HIDInterface
) ||
57 USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
,
58 DCOMP_HID_Host_NextHIDInterfaceEndpoint
) != DESCRIPTOR_SEARCH_COMP_Found
)
60 if (DataINEndpoint
|| DataOUTEndpoint
)
65 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
,
66 DCOMP_HID_Host_NextHIDInterface
) != DESCRIPTOR_SEARCH_COMP_Found
)
68 return HID_ENUMERROR_NoCompatibleInterfaceFound
;
71 HIDInterface
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Interface_t
);
72 } while (HIDInterfaceInfo
->Config
.HIDInterfaceProtocol
&&
73 (HIDInterface
->Protocol
!= HIDInterfaceInfo
->Config
.HIDInterfaceProtocol
));
75 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
,
76 DCOMP_HID_Host_NextHIDDescriptor
) != DESCRIPTOR_SEARCH_COMP_Found
)
78 return HID_ENUMERROR_NoCompatibleInterfaceFound
;
81 HIDDescriptor
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_HID_Descriptor_HID_t
);
83 DataINEndpoint
= NULL
;
84 DataOUTEndpoint
= NULL
;
89 USB_Descriptor_Endpoint_t
* EndpointData
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Endpoint_t
);
91 if ((EndpointData
->EndpointAddress
& ENDPOINT_DIR_MASK
) == ENDPOINT_DIR_IN
)
92 DataINEndpoint
= EndpointData
;
94 DataOUTEndpoint
= EndpointData
;
97 HIDInterfaceInfo
->Config
.DataINPipe
.Size
= le16_to_cpu(DataINEndpoint
->EndpointSize
);
98 HIDInterfaceInfo
->Config
.DataINPipe
.EndpointAddress
= DataINEndpoint
->EndpointAddress
;
99 HIDInterfaceInfo
->Config
.DataINPipe
.Type
= EP_TYPE_INTERRUPT
;
101 HIDInterfaceInfo
->Config
.DataOUTPipe
.Size
= le16_to_cpu(DataOUTEndpoint
->EndpointSize
);
102 HIDInterfaceInfo
->Config
.DataOUTPipe
.EndpointAddress
= DataOUTEndpoint
->EndpointAddress
;
103 HIDInterfaceInfo
->Config
.DataOUTPipe
.Type
= EP_TYPE_INTERRUPT
;
105 if (!(Pipe_ConfigurePipeTable(&HIDInterfaceInfo
->Config
.DataINPipe
, 1)))
108 if (!(Pipe_ConfigurePipeTable(&HIDInterfaceInfo
->Config
.DataOUTPipe
, 1)))
111 HIDInterfaceInfo
->State
.InterfaceNumber
= HIDInterface
->InterfaceNumber
;
112 HIDInterfaceInfo
->State
.HIDReportSize
= LE16_TO_CPU(HIDDescriptor
->HIDReportLength
);
113 HIDInterfaceInfo
->State
.SupportsBootProtocol
= (HIDInterface
->SubClass
!= HID_CSCP_NonBootProtocol
);
114 HIDInterfaceInfo
->State
.LargestReportSize
= 8;
115 HIDInterfaceInfo
->State
.IsActive
= true;
117 return HID_ENUMERROR_NoError
;
120 static uint8_t DCOMP_HID_Host_NextHIDInterface(void* const CurrentDescriptor
)
122 USB_Descriptor_Header_t
* Header
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
);
124 if (Header
->Type
== DTYPE_Interface
)
126 USB_Descriptor_Interface_t
* Interface
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Interface_t
);
128 if (Interface
->Class
== HID_CSCP_HIDClass
)
129 return DESCRIPTOR_SEARCH_Found
;
132 return DESCRIPTOR_SEARCH_NotFound
;
135 static uint8_t DCOMP_HID_Host_NextHIDDescriptor(void* const CurrentDescriptor
)
137 USB_Descriptor_Header_t
* Header
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
);
139 if (Header
->Type
== HID_DTYPE_HID
)
140 return DESCRIPTOR_SEARCH_Found
;
141 else if (Header
->Type
== DTYPE_Interface
)
142 return DESCRIPTOR_SEARCH_Fail
;
144 return DESCRIPTOR_SEARCH_NotFound
;
147 static uint8_t DCOMP_HID_Host_NextHIDInterfaceEndpoint(void* const CurrentDescriptor
)
149 USB_Descriptor_Header_t
* Header
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
);
151 if (Header
->Type
== DTYPE_Endpoint
)
153 USB_Descriptor_Endpoint_t
* Endpoint
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Endpoint_t
);
155 if (!(Pipe_IsEndpointBound(Endpoint
->EndpointAddress
)))
156 return DESCRIPTOR_SEARCH_Found
;
158 else if (Header
->Type
== DTYPE_Interface
)
160 return DESCRIPTOR_SEARCH_Fail
;
163 return DESCRIPTOR_SEARCH_NotFound
;
166 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
167 uint8_t HID_Host_ReceiveReportByID(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
,
168 const uint8_t ReportID
,
171 USB_ControlRequest
= (USB_Request_Header_t
)
173 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
174 .bRequest
= HID_REQ_SetReport
,
175 .wValue
= ((HID_REPORT_ITEM_In
+ 1) << 8) | ReportID
,
176 .wIndex
= HIDInterfaceInfo
->State
.InterfaceNumber
,
177 .wLength
= USB_GetHIDReportSize(HIDInterfaceInfo
->Config
.HIDParserData
, ReportID
, HID_REPORT_ITEM_In
),
180 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
182 return USB_Host_SendControlRequest(Buffer
);
186 uint8_t HID_Host_ReceiveReport(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
,
189 if ((USB_HostState
!= HOST_STATE_Configured
) || !(HIDInterfaceInfo
->State
.IsActive
))
190 return PIPE_READYWAIT_DeviceDisconnected
;
194 Pipe_SelectPipe(HIDInterfaceInfo
->Config
.DataINPipe
.Address
);
198 uint8_t* BufferPos
= Buffer
;
200 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
201 if (!(HIDInterfaceInfo
->State
.UsingBootProtocol
))
203 uint8_t ReportID
= 0;
205 if (HIDInterfaceInfo
->Config
.HIDParserData
->UsingReportIDs
)
207 ReportID
= Pipe_Read_8();
208 *(BufferPos
++) = ReportID
;
211 ReportSize
= USB_GetHIDReportSize(HIDInterfaceInfo
->Config
.HIDParserData
, ReportID
, HID_REPORT_ITEM_In
);
216 ReportSize
= Pipe_BytesInPipe();
219 if ((ErrorCode
= Pipe_Read_Stream_LE(BufferPos
, ReportSize
, NULL
)) != PIPE_RWSTREAM_NoError
)
225 return PIPE_RWSTREAM_NoError
;
228 uint8_t HID_Host_SendReportByID(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
,
229 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
230 const uint8_t ReportID
,
232 const uint8_t ReportType
,
234 const uint16_t ReportSize
)
236 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
237 if ((USB_HostState
!= HOST_STATE_Configured
) || !(HIDInterfaceInfo
->State
.IsActive
))
240 if (HIDInterfaceInfo
->State
.DeviceUsesOUTPipe
&& (ReportType
== HID_REPORT_ITEM_Out
))
244 Pipe_SelectPipe(HIDInterfaceInfo
->Config
.DataOUTPipe
.Address
);
248 Pipe_Write_Stream_LE(&ReportID
, sizeof(ReportID
), NULL
);
250 if ((ErrorCode
= Pipe_Write_Stream_LE(Buffer
, ReportSize
, NULL
)) != PIPE_RWSTREAM_NoError
)
256 return PIPE_RWSTREAM_NoError
;
261 USB_ControlRequest
= (USB_Request_Header_t
)
263 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
264 .bRequest
= HID_REQ_SetReport
,
265 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
266 .wValue
= ((ReportType
+ 1) << 8) | ReportID
,
268 .wValue
= ((ReportType
+ 1) << 8),
270 .wIndex
= HIDInterfaceInfo
->State
.InterfaceNumber
,
271 .wLength
= ReportSize
,
274 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
276 return USB_Host_SendControlRequest(Buffer
);
280 bool HID_Host_IsReportReceived(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
)
282 if ((USB_HostState
!= HOST_STATE_Configured
) || !(HIDInterfaceInfo
->State
.IsActive
))
287 Pipe_SelectPipe(HIDInterfaceInfo
->Config
.DataINPipe
.Address
);
290 ReportReceived
= Pipe_IsINReceived();
294 return ReportReceived
;
297 uint8_t HID_Host_SetBootProtocol(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
)
301 if (!(HIDInterfaceInfo
->State
.SupportsBootProtocol
))
302 return HID_ERROR_LOGICAL
;
304 USB_ControlRequest
= (USB_Request_Header_t
)
306 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
307 .bRequest
= HID_REQ_SetProtocol
,
309 .wIndex
= HIDInterfaceInfo
->State
.InterfaceNumber
,
313 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
315 if ((ErrorCode
= USB_Host_SendControlRequest(NULL
)) != HOST_SENDCONTROL_Successful
)
318 HIDInterfaceInfo
->State
.LargestReportSize
= 8;
319 HIDInterfaceInfo
->State
.UsingBootProtocol
= true;
321 return HOST_SENDCONTROL_Successful
;
324 uint8_t HID_Host_SetIdlePeriod(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
,
327 USB_ControlRequest
= (USB_Request_Header_t
)
329 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
330 .bRequest
= HID_REQ_SetIdle
,
331 .wValue
= ((MS
<< 6) & 0xFF00),
332 .wIndex
= HIDInterfaceInfo
->State
.InterfaceNumber
,
336 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
338 return USB_Host_SendControlRequest(NULL
);
341 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
342 uint8_t HID_Host_SetReportProtocol(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
)
346 uint8_t HIDReportData
[HIDInterfaceInfo
->State
.HIDReportSize
];
348 USB_ControlRequest
= (USB_Request_Header_t
)
350 .bmRequestType
= (REQDIR_DEVICETOHOST
| REQTYPE_STANDARD
| REQREC_INTERFACE
),
351 .bRequest
= REQ_GetDescriptor
,
352 .wValue
= (HID_DTYPE_Report
<< 8),
353 .wIndex
= HIDInterfaceInfo
->State
.InterfaceNumber
,
354 .wLength
= HIDInterfaceInfo
->State
.HIDReportSize
,
357 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
359 if ((ErrorCode
= USB_Host_SendControlRequest(HIDReportData
)) != HOST_SENDCONTROL_Successful
)
362 if (HIDInterfaceInfo
->State
.UsingBootProtocol
)
364 USB_ControlRequest
= (USB_Request_Header_t
)
366 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
367 .bRequest
= HID_REQ_SetProtocol
,
369 .wIndex
= HIDInterfaceInfo
->State
.InterfaceNumber
,
373 if ((ErrorCode
= USB_Host_SendControlRequest(NULL
)) != HOST_SENDCONTROL_Successful
)
376 HIDInterfaceInfo
->State
.UsingBootProtocol
= false;
379 if (HIDInterfaceInfo
->Config
.HIDParserData
== NULL
)
380 return HID_ERROR_LOGICAL
;
382 if ((ErrorCode
= USB_ProcessHIDReport(HIDReportData
, HIDInterfaceInfo
->State
.HIDReportSize
,
383 HIDInterfaceInfo
->Config
.HIDParserData
)) != HID_PARSE_Successful
)
385 return HID_ERROR_LOGICAL
| ErrorCode
;
388 uint16_t LargestReportSizeBits
= HIDInterfaceInfo
->Config
.HIDParserData
->LargestReportSizeBits
;
389 HIDInterfaceInfo
->State
.LargestReportSize
= (LargestReportSizeBits
>> 3) + ((LargestReportSizeBits
& 0x07) != 0);