]> git.donarmstrong.com Git - qmk_firmware.git/blob - protocol/lufa/LUFA-120730/LUFA/Drivers/USB/Class/Host/AndroidAccessoryClassHost.c
67a1352b3485ba5857c50be8c78f34253a791105
[qmk_firmware.git] / protocol / lufa / LUFA-120730 / LUFA / Drivers / USB / Class / Host / AndroidAccessoryClassHost.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_AOA_DRIVER\r
37 #define  __INCLUDE_FROM_ANDROIDACCESSORY_HOST_C\r
38 #include "AndroidAccessoryClassHost.h"\r
39 \r
40 bool AOA_Host_ValidateAccessoryDevice(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,\r
41                                       const USB_Descriptor_Device_t* const DeviceDescriptor,\r
42                                       bool* const NeedModeSwitch)\r
43 {\r
44         (void)AOAInterfaceInfo;\r
45 \r
46         if (DeviceDescriptor->Header.Type != DTYPE_Device)\r
47           return false;\r
48 \r
49         *NeedModeSwitch = ((DeviceDescriptor->ProductID != ANDROID_ACCESSORY_PRODUCT_ID) &&\r
50                            (DeviceDescriptor->ProductID != ANDROID_ACCESSORY_ADB_PRODUCT_ID));\r
51 \r
52         return true;\r
53 }\r
54 \r
55 uint8_t AOA_Host_ConfigurePipes(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,\r
56                                 uint16_t ConfigDescriptorSize,\r
57                                 void* ConfigDescriptorData)\r
58 {\r
59         USB_Descriptor_Endpoint_t*  DataINEndpoint  = NULL;\r
60         USB_Descriptor_Endpoint_t*  DataOUTEndpoint = NULL;\r
61         USB_Descriptor_Interface_t* AOAInterface    = NULL;\r
62 \r
63         memset(&AOAInterfaceInfo->State, 0x00, sizeof(AOAInterfaceInfo->State));\r
64 \r
65         if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)\r
66           return AOA_ENUMERROR_InvalidConfigDescriptor;\r
67         \r
68         if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,\r
69                                       DCOMP_AOA_Host_NextAndroidAccessoryInterface) != DESCRIPTOR_SEARCH_COMP_Found)\r
70         {\r
71                 return AOA_ENUMERROR_NoCompatibleInterfaceFound;\r
72         }\r
73         \r
74         AOAInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);\r
75 \r
76         while (!(DataINEndpoint) || !(DataOUTEndpoint))\r
77         {\r
78                 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,\r
79                                               DCOMP_AOA_Host_NextInterfaceBulkEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)\r
80                 {\r
81                         return AOA_ENUMERROR_NoCompatibleInterfaceFound;\r
82                 }\r
83 \r
84                 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);\r
85 \r
86                 if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)\r
87                   DataINEndpoint  = EndpointData;\r
88                 else\r
89                   DataOUTEndpoint = EndpointData;\r
90         }\r
91 \r
92         AOAInterfaceInfo->Config.DataINPipe.Size  = le16_to_cpu(DataINEndpoint->EndpointSize);\r
93         AOAInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;\r
94         AOAInterfaceInfo->Config.DataINPipe.Type  = EP_TYPE_BULK;\r
95         \r
96         AOAInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);\r
97         AOAInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;\r
98         AOAInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_BULK;\r
99         \r
100         if (!(Pipe_ConfigurePipeTable(&AOAInterfaceInfo->Config.DataINPipe, 1)))\r
101           return false;\r
102         \r
103         if (!(Pipe_ConfigurePipeTable(&AOAInterfaceInfo->Config.DataOUTPipe, 1)))\r
104           return false;\r
105 \r
106         AOAInterfaceInfo->State.IsActive        = true;\r
107         AOAInterfaceInfo->State.InterfaceNumber = AOAInterface->InterfaceNumber;\r
108 \r
109         return AOA_ENUMERROR_NoError;\r
110 }\r
111 \r
112 static uint8_t DCOMP_AOA_Host_NextAndroidAccessoryInterface(void* const CurrentDescriptor)\r
113 {\r
114         USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);\r
115 \r
116         if (Header->Type == DTYPE_Interface)\r
117         {\r
118                 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);\r
119 \r
120                 if ((Interface->Class    == AOA_CSCP_AOADataClass)    &&\r
121                     (Interface->SubClass == AOA_CSCP_AOADataSubclass) &&\r
122                     (Interface->Protocol == AOA_CSCP_AOADataProtocol))\r
123                 {\r
124                         return DESCRIPTOR_SEARCH_Found;\r
125                 }\r
126         }\r
127 \r
128         return DESCRIPTOR_SEARCH_NotFound;\r
129 }\r
130 \r
131 static uint8_t DCOMP_AOA_Host_NextInterfaceBulkEndpoint(void* const CurrentDescriptor)\r
132 {\r
133         USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);\r
134 \r
135         if (Header->Type == DTYPE_Endpoint)\r
136         {\r
137                 USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);\r
138 \r
139                 uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);\r
140 \r
141                 if ((EndpointType == EP_TYPE_BULK) && (!(Pipe_IsEndpointBound(Endpoint->EndpointAddress))))\r
142                   return DESCRIPTOR_SEARCH_Found;\r
143         }\r
144         else if (Header->Type == DTYPE_Interface)\r
145         {\r
146                 return DESCRIPTOR_SEARCH_Fail;\r
147         }\r
148 \r
149         return DESCRIPTOR_SEARCH_NotFound;\r
150 }\r
151 \r
152 void AOA_Host_USBTask(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo)\r
153 {\r
154         if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))\r
155           return;\r
156 \r
157         #if !defined(NO_CLASS_DRIVER_AUTOFLUSH)\r
158         AOA_Host_Flush(AOAInterfaceInfo);\r
159         #endif\r
160 }\r
161 \r
162 uint8_t AOA_Host_StartAccessoryMode(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo)\r
163 {\r
164         uint8_t ErrorCode;\r
165         \r
166         uint16_t AccessoryProtocol;\r
167         if ((ErrorCode = AOA_Host_GetAccessoryProtocol(&AccessoryProtocol)) != HOST_WAITERROR_Successful)\r
168           return ErrorCode;\r
169 \r
170         if (AccessoryProtocol != CPU_TO_LE16(AOA_PROTOCOL_AccessoryV1))\r
171           return AOA_ERROR_LOGICAL_CMD_FAILED;\r
172 \r
173         for (uint8_t PropertyIndex = 0; PropertyIndex < AOA_STRING_TOTAL_STRINGS; PropertyIndex++)\r
174         {\r
175                 if ((ErrorCode = AOA_Host_SendPropertyString(AOAInterfaceInfo, PropertyIndex)) != HOST_WAITERROR_Successful)\r
176                   return ErrorCode;\r
177         }\r
178 \r
179         USB_ControlRequest = (USB_Request_Header_t)\r
180         {\r
181                 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_VENDOR | REQREC_DEVICE),\r
182                 .bRequest      = AOA_REQ_StartAccessoryMode,\r
183                 .wValue        = 0,\r
184                 .wIndex        = 0,\r
185                 .wLength       = 0,\r
186         };\r
187 \r
188         Pipe_SelectPipe(PIPE_CONTROLPIPE);\r
189         return USB_Host_SendControlRequest(NULL);       \r
190 }\r
191 \r
192 static uint8_t AOA_Host_GetAccessoryProtocol(uint16_t* const Protocol)\r
193 {\r
194         USB_ControlRequest = (USB_Request_Header_t)\r
195         {\r
196                 .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_VENDOR | REQREC_DEVICE),\r
197                 .bRequest      = AOA_REQ_GetAccessoryProtocol,\r
198                 .wValue        = 0,\r
199                 .wIndex        = 0,\r
200                 .wLength       = sizeof(uint16_t),\r
201         };\r
202 \r
203         Pipe_SelectPipe(PIPE_CONTROLPIPE);\r
204         return USB_Host_SendControlRequest(Protocol);\r
205 }\r
206 \r
207 static uint8_t AOA_Host_SendPropertyString(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,\r
208                                            const uint8_t StringIndex)\r
209 {       \r
210         const char* String = AOAInterfaceInfo->Config.PropertyStrings[StringIndex];\r
211         \r
212         if (String == NULL)\r
213           String = "";\r
214 \r
215         USB_ControlRequest = (USB_Request_Header_t)\r
216         {\r
217                 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_VENDOR | REQREC_DEVICE),\r
218                 .bRequest      = AOA_REQ_SendString,\r
219                 .wValue        = 0,\r
220                 .wIndex        = StringIndex,\r
221                 .wLength       = (strlen(String) + 1),\r
222         };\r
223 \r
224         Pipe_SelectPipe(PIPE_CONTROLPIPE);\r
225         return USB_Host_SendControlRequest((char*)String);\r
226 }\r
227 \r
228 uint8_t AOA_Host_SendData(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,\r
229                           const uint8_t* const Buffer,\r
230                           const uint16_t Length)\r
231 {\r
232         if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))\r
233           return PIPE_READYWAIT_DeviceDisconnected;\r
234 \r
235         uint8_t ErrorCode;\r
236 \r
237         Pipe_SelectPipe(AOAInterfaceInfo->Config.DataOUTPipe.Address);\r
238 \r
239         Pipe_Unfreeze();\r
240         ErrorCode = Pipe_Write_Stream_LE(Buffer, Length, NULL);\r
241         Pipe_Freeze();\r
242 \r
243         return ErrorCode;\r
244 }\r
245 \r
246 uint8_t AOA_Host_SendString(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,\r
247                             const char* const String)\r
248 {\r
249         if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))\r
250           return PIPE_READYWAIT_DeviceDisconnected;\r
251 \r
252         uint8_t ErrorCode;\r
253 \r
254         Pipe_SelectPipe(AOAInterfaceInfo->Config.DataOUTPipe.Address);\r
255 \r
256         Pipe_Unfreeze();\r
257         ErrorCode = Pipe_Write_Stream_LE(String, strlen(String), NULL);\r
258         Pipe_Freeze();\r
259 \r
260         return ErrorCode;\r
261 }\r
262 \r
263 uint8_t AOA_Host_SendByte(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,\r
264                           const uint8_t Data)\r
265 {\r
266         if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))\r
267           return PIPE_READYWAIT_DeviceDisconnected;\r
268 \r
269         uint8_t ErrorCode;\r
270 \r
271         Pipe_SelectPipe(AOAInterfaceInfo->Config.DataOUTPipe.Address);\r
272         Pipe_Unfreeze();\r
273 \r
274         if (!(Pipe_IsReadWriteAllowed()))\r
275         {\r
276                 Pipe_ClearOUT();\r
277 \r
278                 if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)\r
279                   return ErrorCode;\r
280         }\r
281 \r
282         Pipe_Write_8(Data);\r
283         Pipe_Freeze();\r
284 \r
285         return PIPE_READYWAIT_NoError;\r
286 }\r
287 \r
288 uint16_t AOA_Host_BytesReceived(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo)\r
289 {\r
290         if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))\r
291           return 0;\r
292 \r
293         Pipe_SelectPipe(AOAInterfaceInfo->Config.DataINPipe.Address);\r
294         Pipe_Unfreeze();\r
295 \r
296         if (Pipe_IsINReceived())\r
297         {\r
298                 if (!(Pipe_BytesInPipe()))\r
299                 {\r
300                         Pipe_ClearIN();\r
301                         Pipe_Freeze();\r
302                         return 0;\r
303                 }\r
304                 else\r
305                 {\r
306                         Pipe_Freeze();\r
307                         return Pipe_BytesInPipe();\r
308                 }\r
309         }\r
310         else\r
311         {\r
312                 Pipe_Freeze();\r
313 \r
314                 return 0;\r
315         }\r
316 }\r
317 \r
318 int16_t AOA_Host_ReceiveByte(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo)\r
319 {\r
320         if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))\r
321           return -1;\r
322 \r
323         int16_t ReceivedByte = -1;\r
324 \r
325         Pipe_SelectPipe(AOAInterfaceInfo->Config.DataINPipe.Address);\r
326         Pipe_Unfreeze();\r
327 \r
328         if (Pipe_IsINReceived())\r
329         {\r
330                 if (Pipe_BytesInPipe())\r
331                   ReceivedByte = Pipe_Read_8();\r
332 \r
333                 if (!(Pipe_BytesInPipe()))\r
334                   Pipe_ClearIN();\r
335         }\r
336 \r
337         Pipe_Freeze();\r
338 \r
339         return ReceivedByte;\r
340 }\r
341 \r
342 uint8_t AOA_Host_Flush(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo)\r
343 {\r
344         if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))\r
345           return PIPE_READYWAIT_DeviceDisconnected;\r
346 \r
347         uint8_t ErrorCode;\r
348 \r
349         Pipe_SelectPipe(AOAInterfaceInfo->Config.DataOUTPipe.Address);\r
350         Pipe_Unfreeze();\r
351 \r
352         if (!(Pipe_BytesInPipe()))\r
353           return PIPE_READYWAIT_NoError;\r
354 \r
355         bool BankFull = !(Pipe_IsReadWriteAllowed());\r
356 \r
357         Pipe_ClearOUT();\r
358 \r
359         if (BankFull)\r
360         {\r
361                 if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)\r
362                   return ErrorCode;\r
363 \r
364                 Pipe_ClearOUT();\r
365         }\r
366 \r
367         Pipe_Freeze();\r
368 \r
369         return PIPE_READYWAIT_NoError;\r
370 }\r
371 \r
372 #if defined(FDEV_SETUP_STREAM)\r
373 void AOA_Host_CreateStream(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,\r
374                            FILE* const Stream)\r
375 {\r
376         *Stream = (FILE)FDEV_SETUP_STREAM(AOA_Host_putchar, AOA_Host_getchar, _FDEV_SETUP_RW);\r
377         fdev_set_udata(Stream, AOAInterfaceInfo);\r
378 }\r
379 \r
380 void AOA_Host_CreateBlockingStream(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,\r
381                                    FILE* const Stream)\r
382 {\r
383         *Stream = (FILE)FDEV_SETUP_STREAM(AOA_Host_putchar, AOA_Host_getchar_Blocking, _FDEV_SETUP_RW);\r
384         fdev_set_udata(Stream, AOAInterfaceInfo);\r
385 }\r
386 \r
387 static int AOA_Host_putchar(char c,\r
388                             FILE* Stream)\r
389 {\r
390         return AOA_Host_SendByte((USB_ClassInfo_AOA_Host_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0;\r
391 }\r
392 \r
393 static int AOA_Host_getchar(FILE* Stream)\r
394 {\r
395         int16_t ReceivedByte = AOA_Host_ReceiveByte((USB_ClassInfo_AOA_Host_t*)fdev_get_udata(Stream));\r
396 \r
397         if (ReceivedByte < 0)\r
398           return _FDEV_EOF;\r
399 \r
400         return ReceivedByte;\r
401 }\r
402 \r
403 static int AOA_Host_getchar_Blocking(FILE* Stream)\r
404 {\r
405         int16_t ReceivedByte;\r
406 \r
407         while ((ReceivedByte = AOA_Host_ReceiveByte((USB_ClassInfo_AOA_Host_t*)fdev_get_udata(Stream))) < 0)\r
408         {\r
409                 if (USB_HostState == HOST_STATE_Unattached)\r
410                   return _FDEV_EOF;\r
411 \r
412                 AOA_Host_USBTask((USB_ClassInfo_AOA_Host_t*)fdev_get_udata(Stream));\r
413                 USB_USBTask();\r
414         }\r
415 \r
416         return ReceivedByte;\r
417 }\r
418 #endif\r
419 \r
420 #endif\r
421 \r
422 \r