]> git.donarmstrong.com Git - qmk_firmware.git/blob - protocol/lufa/LUFA-120730/LUFA/Drivers/USB/Class/Host/HIDClassHost.c
Now includes LUFA-120730 in repository
[qmk_firmware.git] / protocol / lufa / LUFA-120730 / LUFA / Drivers / USB / Class / Host / HIDClassHost.c
1 /*\r
2              LUFA Library\r
3      Copyright (C) Dean Camera, 2012.\r
4 \r
5   dean [at] fourwalledcubicle [dot] com\r
6            www.lufa-lib.org\r
7 */\r
8 \r
9 /*\r
10   Copyright 2012  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
11 \r
12   Permission to use, copy, modify, distribute, and sell this\r
13   software and its documentation for any purpose is hereby granted\r
14   without fee, provided that the above copyright notice appear in\r
15   all copies and that both that the copyright notice and this\r
16   permission notice and warranty disclaimer appear in supporting\r
17   documentation, and that the name of the author not be used in\r
18   advertising or publicity pertaining to distribution of the\r
19   software without specific, written prior permission.\r
20 \r
21   The author disclaim all warranties with regard to this\r
22   software, including all implied warranties of merchantability\r
23   and fitness.  In no event shall the author be liable for any\r
24   special, indirect or consequential damages or any damages\r
25   whatsoever resulting from loss of use, data or profits, whether\r
26   in an action of contract, negligence or other tortious action,\r
27   arising out of or in connection with the use or performance of\r
28   this software.\r
29 */\r
30 \r
31 #define  __INCLUDE_FROM_USB_DRIVER\r
32 #include "../../Core/USBMode.h"\r
33 \r
34 #if defined(USB_CAN_BE_HOST)\r
35 \r
36 #define  __INCLUDE_FROM_HID_DRIVER\r
37 #define  __INCLUDE_FROM_HID_HOST_C\r
38 #include "HIDClassHost.h"\r
39 \r
40 uint8_t HID_Host_ConfigurePipes(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,\r
41                                 uint16_t ConfigDescriptorSize,\r
42                                 void* ConfigDescriptorData)\r
43 {\r
44         USB_Descriptor_Endpoint_t*  DataINEndpoint  = NULL;\r
45         USB_Descriptor_Endpoint_t*  DataOUTEndpoint = NULL;\r
46         USB_Descriptor_Interface_t* HIDInterface    = NULL;\r
47         USB_HID_Descriptor_HID_t*   HIDDescriptor   = NULL;\r
48 \r
49         memset(&HIDInterfaceInfo->State, 0x00, sizeof(HIDInterfaceInfo->State));\r
50 \r
51         if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)\r
52           return HID_ENUMERROR_InvalidConfigDescriptor;\r
53 \r
54         while (!(DataINEndpoint) || !(DataOUTEndpoint))\r
55         {\r
56                 if (!(HIDInterface) ||\r
57                     USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,\r
58                                               DCOMP_HID_Host_NextHIDInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)\r
59                 {\r
60                         if (DataINEndpoint || DataOUTEndpoint)\r
61                           break;\r
62 \r
63                         do\r
64                         {\r
65                                 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,\r
66                                                               DCOMP_HID_Host_NextHIDInterface) != DESCRIPTOR_SEARCH_COMP_Found)\r
67                                 {\r
68                                         return HID_ENUMERROR_NoCompatibleInterfaceFound;\r
69                                 }\r
70 \r
71                                 HIDInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);\r
72                         } while (HIDInterfaceInfo->Config.HIDInterfaceProtocol &&\r
73                                          (HIDInterface->Protocol != HIDInterfaceInfo->Config.HIDInterfaceProtocol));\r
74 \r
75                         if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,\r
76                                                       DCOMP_HID_Host_NextHIDDescriptor) != DESCRIPTOR_SEARCH_COMP_Found)\r
77                         {\r
78                                 return HID_ENUMERROR_NoCompatibleInterfaceFound;\r
79                         }\r
80 \r
81                         HIDDescriptor = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_HID_Descriptor_HID_t);\r
82 \r
83                         DataINEndpoint  = NULL;\r
84                         DataOUTEndpoint = NULL;\r
85 \r
86                         continue;\r
87                 }\r
88 \r
89                 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);\r
90 \r
91                 if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)\r
92                   DataINEndpoint  = EndpointData;\r
93                 else\r
94                   DataOUTEndpoint = EndpointData;\r
95         }\r
96 \r
97         HIDInterfaceInfo->Config.DataINPipe.Size  = le16_to_cpu(DataINEndpoint->EndpointSize);\r
98         HIDInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;\r
99         HIDInterfaceInfo->Config.DataINPipe.Type  = EP_TYPE_INTERRUPT;\r
100         \r
101         HIDInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);\r
102         HIDInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;\r
103         HIDInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_INTERRUPT;\r
104         \r
105         if (!(Pipe_ConfigurePipeTable(&HIDInterfaceInfo->Config.DataINPipe, 1)))\r
106           return false;\r
107         \r
108         if (!(Pipe_ConfigurePipeTable(&HIDInterfaceInfo->Config.DataOUTPipe, 1)))\r
109           return false;\r
110 \r
111         HIDInterfaceInfo->State.InterfaceNumber      = HIDInterface->InterfaceNumber;\r
112         HIDInterfaceInfo->State.HIDReportSize        = LE16_TO_CPU(HIDDescriptor->HIDReportLength);\r
113         HIDInterfaceInfo->State.SupportsBootProtocol = (HIDInterface->SubClass != HID_CSCP_NonBootProtocol);\r
114         HIDInterfaceInfo->State.LargestReportSize    = 8;\r
115         HIDInterfaceInfo->State.IsActive             = true;\r
116 \r
117         return HID_ENUMERROR_NoError;\r
118 }\r
119 \r
120 static uint8_t DCOMP_HID_Host_NextHIDInterface(void* const CurrentDescriptor)\r
121 {\r
122         USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);\r
123 \r
124         if (Header->Type == DTYPE_Interface)\r
125         {\r
126                 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);\r
127 \r
128                 if (Interface->Class == HID_CSCP_HIDClass)\r
129                   return DESCRIPTOR_SEARCH_Found;\r
130         }\r
131 \r
132         return DESCRIPTOR_SEARCH_NotFound;\r
133 }\r
134 \r
135 static uint8_t DCOMP_HID_Host_NextHIDDescriptor(void* const CurrentDescriptor)\r
136 {\r
137         USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);\r
138 \r
139         if (Header->Type == HID_DTYPE_HID)\r
140           return DESCRIPTOR_SEARCH_Found;\r
141         else if (Header->Type == DTYPE_Interface)\r
142           return DESCRIPTOR_SEARCH_Fail;\r
143         else\r
144           return DESCRIPTOR_SEARCH_NotFound;\r
145 }\r
146 \r
147 static uint8_t DCOMP_HID_Host_NextHIDInterfaceEndpoint(void* const CurrentDescriptor)\r
148 {\r
149         USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);\r
150 \r
151         if (Header->Type == DTYPE_Endpoint)\r
152         {\r
153                 USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);\r
154 \r
155                 if (!(Pipe_IsEndpointBound(Endpoint->EndpointAddress)))\r
156                   return DESCRIPTOR_SEARCH_Found;\r
157         }\r
158         else if (Header->Type == DTYPE_Interface)\r
159         {\r
160                 return DESCRIPTOR_SEARCH_Fail;\r
161         }\r
162 \r
163         return DESCRIPTOR_SEARCH_NotFound;\r
164 }\r
165 \r
166 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)\r
167 uint8_t HID_Host_ReceiveReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,\r
168                                    const uint8_t ReportID,\r
169                                    void* Buffer)\r
170 {\r
171         USB_ControlRequest = (USB_Request_Header_t)\r
172         {\r
173                 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),\r
174                 .bRequest      = HID_REQ_SetReport,\r
175                 .wValue        = ((HID_REPORT_ITEM_In + 1) << 8) | ReportID,\r
176                 .wIndex        = HIDInterfaceInfo->State.InterfaceNumber,\r
177                 .wLength       = USB_GetHIDReportSize(HIDInterfaceInfo->Config.HIDParserData, ReportID, HID_REPORT_ITEM_In),\r
178         };\r
179 \r
180         Pipe_SelectPipe(PIPE_CONTROLPIPE);\r
181 \r
182         return USB_Host_SendControlRequest(Buffer);\r
183 }\r
184 #endif\r
185 \r
186 uint8_t HID_Host_ReceiveReport(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,\r
187                                void* Buffer)\r
188 {\r
189         if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive))\r
190           return PIPE_READYWAIT_DeviceDisconnected;\r
191 \r
192         uint8_t ErrorCode;\r
193 \r
194         Pipe_SelectPipe(HIDInterfaceInfo->Config.DataINPipe.Address);\r
195         Pipe_Unfreeze();\r
196 \r
197         uint16_t ReportSize;\r
198         uint8_t* BufferPos = Buffer;\r
199 \r
200 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)\r
201         if (!(HIDInterfaceInfo->State.UsingBootProtocol))\r
202         {\r
203                 uint8_t ReportID = 0;\r
204 \r
205                 if (HIDInterfaceInfo->Config.HIDParserData->UsingReportIDs)\r
206                 {\r
207                         ReportID = Pipe_Read_8();\r
208                         *(BufferPos++) = ReportID;\r
209                 }\r
210 \r
211                 ReportSize = USB_GetHIDReportSize(HIDInterfaceInfo->Config.HIDParserData, ReportID, HID_REPORT_ITEM_In);\r
212         }\r
213         else\r
214 #endif\r
215         {\r
216                 ReportSize = Pipe_BytesInPipe();\r
217         }\r
218 \r
219         if ((ErrorCode = Pipe_Read_Stream_LE(BufferPos, ReportSize, NULL)) != PIPE_RWSTREAM_NoError)\r
220           return ErrorCode;\r
221 \r
222         Pipe_ClearIN();\r
223         Pipe_Freeze();\r
224 \r
225         return PIPE_RWSTREAM_NoError;\r
226 }\r
227 \r
228 uint8_t HID_Host_SendReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,\r
229 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)\r
230                                 const uint8_t ReportID,\r
231 #endif\r
232                                 const uint8_t ReportType,\r
233                                 void* Buffer,\r
234                                 const uint16_t ReportSize)\r
235 {\r
236 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)\r
237         if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive))\r
238           return false;\r
239 \r
240         if (HIDInterfaceInfo->State.DeviceUsesOUTPipe && (ReportType == HID_REPORT_ITEM_Out))\r
241         {\r
242                 uint8_t ErrorCode;\r
243 \r
244                 Pipe_SelectPipe(HIDInterfaceInfo->Config.DataOUTPipe.Address);\r
245                 Pipe_Unfreeze();\r
246 \r
247                 if (ReportID)\r
248                   Pipe_Write_Stream_LE(&ReportID, sizeof(ReportID), NULL);\r
249 \r
250                 if ((ErrorCode = Pipe_Write_Stream_LE(Buffer, ReportSize, NULL)) != PIPE_RWSTREAM_NoError)\r
251                   return ErrorCode;\r
252 \r
253                 Pipe_ClearOUT();\r
254                 Pipe_Freeze();\r
255 \r
256                 return PIPE_RWSTREAM_NoError;\r
257         }\r
258         else\r
259 #endif\r
260         {\r
261                 USB_ControlRequest = (USB_Request_Header_t)\r
262                 {\r
263                         .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),\r
264                         .bRequest      = HID_REQ_SetReport,\r
265 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)\r
266                         .wValue        = ((ReportType + 1) << 8) | ReportID,\r
267 #else\r
268                         .wValue        = ((ReportType + 1) << 8),\r
269 #endif\r
270                         .wIndex        = HIDInterfaceInfo->State.InterfaceNumber,\r
271                         .wLength       = ReportSize,\r
272                 };\r
273 \r
274                 Pipe_SelectPipe(PIPE_CONTROLPIPE);\r
275 \r
276                 return USB_Host_SendControlRequest(Buffer);\r
277         }\r
278 }\r
279 \r
280 bool HID_Host_IsReportReceived(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo)\r
281 {\r
282         if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive))\r
283           return false;\r
284 \r
285         bool ReportReceived;\r
286 \r
287         Pipe_SelectPipe(HIDInterfaceInfo->Config.DataINPipe.Address);\r
288         Pipe_Unfreeze();\r
289 \r
290         ReportReceived = Pipe_IsINReceived();\r
291 \r
292         Pipe_Freeze();\r
293 \r
294         return ReportReceived;\r
295 }\r
296 \r
297 uint8_t HID_Host_SetBootProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo)\r
298 {\r
299         uint8_t ErrorCode;\r
300 \r
301         if (!(HIDInterfaceInfo->State.SupportsBootProtocol))\r
302           return HID_ERROR_LOGICAL;\r
303 \r
304         USB_ControlRequest = (USB_Request_Header_t)\r
305                 {\r
306                         .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),\r
307                         .bRequest      = HID_REQ_SetProtocol,\r
308                         .wValue        = 0,\r
309                         .wIndex        = HIDInterfaceInfo->State.InterfaceNumber,\r
310                         .wLength       = 0,\r
311                 };\r
312 \r
313         Pipe_SelectPipe(PIPE_CONTROLPIPE);\r
314 \r
315         if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)\r
316           return ErrorCode;\r
317 \r
318         HIDInterfaceInfo->State.LargestReportSize = 8;\r
319         HIDInterfaceInfo->State.UsingBootProtocol = true;\r
320 \r
321         return HOST_SENDCONTROL_Successful;\r
322 }\r
323 \r
324 uint8_t HID_Host_SetIdlePeriod(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,\r
325                                const uint16_t MS)\r
326 {\r
327         USB_ControlRequest = (USB_Request_Header_t)\r
328                 {\r
329                         .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),\r
330                         .bRequest      = HID_REQ_SetIdle,\r
331                         .wValue        = ((MS << 6) & 0xFF00),\r
332                         .wIndex        = HIDInterfaceInfo->State.InterfaceNumber,\r
333                         .wLength       = 0,\r
334                 };\r
335 \r
336         Pipe_SelectPipe(PIPE_CONTROLPIPE);\r
337 \r
338         return USB_Host_SendControlRequest(NULL);\r
339 }\r
340 \r
341 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)\r
342 uint8_t HID_Host_SetReportProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo)\r
343 {\r
344         uint8_t ErrorCode;\r
345 \r
346         uint8_t HIDReportData[HIDInterfaceInfo->State.HIDReportSize];\r
347 \r
348         USB_ControlRequest = (USB_Request_Header_t)\r
349                 {\r
350                         .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_INTERFACE),\r
351                         .bRequest      = REQ_GetDescriptor,\r
352                         .wValue        = (HID_DTYPE_Report << 8),\r
353                         .wIndex        = HIDInterfaceInfo->State.InterfaceNumber,\r
354                         .wLength       = HIDInterfaceInfo->State.HIDReportSize,\r
355                 };\r
356 \r
357         Pipe_SelectPipe(PIPE_CONTROLPIPE);\r
358 \r
359         if ((ErrorCode = USB_Host_SendControlRequest(HIDReportData)) != HOST_SENDCONTROL_Successful)\r
360           return ErrorCode;\r
361 \r
362         if (HIDInterfaceInfo->State.UsingBootProtocol)\r
363         {\r
364                 USB_ControlRequest = (USB_Request_Header_t)\r
365                         {\r
366                                 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),\r
367                                 .bRequest      = HID_REQ_SetProtocol,\r
368                                 .wValue        = 1,\r
369                                 .wIndex        = HIDInterfaceInfo->State.InterfaceNumber,\r
370                                 .wLength       = 0,\r
371                         };\r
372 \r
373                 if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)\r
374                   return ErrorCode;\r
375 \r
376                 HIDInterfaceInfo->State.UsingBootProtocol = false;\r
377         }\r
378 \r
379         if (HIDInterfaceInfo->Config.HIDParserData == NULL)\r
380           return HID_ERROR_LOGICAL;\r
381 \r
382         if ((ErrorCode = USB_ProcessHIDReport(HIDReportData, HIDInterfaceInfo->State.HIDReportSize,\r
383                                               HIDInterfaceInfo->Config.HIDParserData)) != HID_PARSE_Successful)\r
384         {\r
385                 return HID_ERROR_LOGICAL | ErrorCode;\r
386         }\r
387 \r
388         uint16_t LargestReportSizeBits = HIDInterfaceInfo->Config.HIDParserData->LargestReportSizeBits;\r
389         HIDInterfaceInfo->State.LargestReportSize = (LargestReportSizeBits >> 3) + ((LargestReportSizeBits & 0x07) != 0);\r
390 \r
391         return 0;\r
392 }\r
393 #endif\r
394 \r
395 #endif\r
396 \r