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