diff options
author | Ryan <fauxpark@gmail.com> | 2021-08-18 18:20:25 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-18 18:20:25 +1000 |
commit | b16091659cc9a724a8800f77e631643b4ab089ad (patch) | |
tree | e44933472c6d100bd4fc5d8a693d9d21e3c32f6f /lib/usbhost/USB_Host_Shield_2.0/adk.cpp | |
parent | cf5e40c25139ff64ff246f1c6280e983ef75551c (diff) | |
download | qmk_firmware-b16091659cc9a724a8800f77e631643b4ab089ad.tar.gz qmk_firmware-b16091659cc9a724a8800f77e631643b4ab089ad.zip |
Move USB Host Shield and Arduino core to `lib/` (#13973)
Diffstat (limited to 'lib/usbhost/USB_Host_Shield_2.0/adk.cpp')
-rw-r--r-- | lib/usbhost/USB_Host_Shield_2.0/adk.cpp | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/lib/usbhost/USB_Host_Shield_2.0/adk.cpp b/lib/usbhost/USB_Host_Shield_2.0/adk.cpp new file mode 100644 index 000000000..9e4e0c8d8 --- /dev/null +++ b/lib/usbhost/USB_Host_Shield_2.0/adk.cpp | |||
@@ -0,0 +1,371 @@ | |||
1 | /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. | ||
2 | |||
3 | This software may be distributed and modified under the terms of the GNU | ||
4 | General Public License version 2 (GPL2) as published by the Free Software | ||
5 | Foundation and appearing in the file GPL2.TXT included in the packaging of | ||
6 | this file. Please note that GPL2 Section 2[b] requires that all works based | ||
7 | on this software must also be made publicly available under the terms of | ||
8 | the GPL2 ("Copyleft"). | ||
9 | |||
10 | Contact information | ||
11 | ------------------- | ||
12 | |||
13 | Circuits At Home, LTD | ||
14 | Web : http://www.circuitsathome.com | ||
15 | e-mail : support@circuitsathome.com | ||
16 | */ | ||
17 | |||
18 | /* Google ADK interface */ | ||
19 | |||
20 | #include "adk.h" | ||
21 | |||
22 | const uint8_t ADK::epDataInIndex = 1; | ||
23 | const uint8_t ADK::epDataOutIndex = 2; | ||
24 | |||
25 | ADK::ADK(USB *p, const char* manufacturer, | ||
26 | const char* model, | ||
27 | const char* description, | ||
28 | const char* version, | ||
29 | const char* uri, | ||
30 | const char* serial) : | ||
31 | |||
32 | /* ADK ID Strings */ | ||
33 | manufacturer(manufacturer), | ||
34 | model(model), | ||
35 | description(description), | ||
36 | version(version), | ||
37 | uri(uri), | ||
38 | serial(serial), | ||
39 | pUsb(p), //pointer to USB class instance - mandatory | ||
40 | bAddress(0), //device address - mandatory | ||
41 | bConfNum(0), //configuration number | ||
42 | bNumEP(1), //if config descriptor needs to be parsed | ||
43 | ready(false) { | ||
44 | // initialize endpoint data structures | ||
45 | for(uint8_t i = 0; i < ADK_MAX_ENDPOINTS; i++) { | ||
46 | epInfo[i].epAddr = 0; | ||
47 | epInfo[i].maxPktSize = (i) ? 0 : 8; | ||
48 | epInfo[i].epAttribs = 0; | ||
49 | epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; | ||
50 | }//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++... | ||
51 | |||
52 | // register in USB subsystem | ||
53 | if(pUsb) { | ||
54 | pUsb->RegisterDeviceClass(this); //set devConfig[] entry | ||
55 | } | ||
56 | } | ||
57 | |||
58 | uint8_t ADK::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) { | ||
59 | return Init(parent, port, lowspeed); // Just call Init. Yes, really! | ||
60 | } | ||
61 | |||
62 | /* Connection initialization of an Android phone */ | ||
63 | uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) { | ||
64 | uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)]; | ||
65 | USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); | ||
66 | uint8_t rcode; | ||
67 | uint8_t num_of_conf; // number of configurations | ||
68 | UsbDevice *p = NULL; | ||
69 | EpInfo *oldep_ptr = NULL; | ||
70 | |||
71 | // get memory address of USB device address pool | ||
72 | AddressPool &addrPool = pUsb->GetAddressPool(); | ||
73 | |||
74 | USBTRACE("\r\nADK Init"); | ||
75 | |||
76 | // check if address has already been assigned to an instance | ||
77 | if(bAddress) { | ||
78 | USBTRACE("\r\nAddress in use"); | ||
79 | return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; | ||
80 | } | ||
81 | |||
82 | // Get pointer to pseudo device with address 0 assigned | ||
83 | p = addrPool.GetUsbDevicePtr(0); | ||
84 | |||
85 | if(!p) { | ||
86 | USBTRACE("\r\nAddress not found"); | ||
87 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||
88 | } | ||
89 | |||
90 | if(!p->epinfo) { | ||
91 | USBTRACE("epinfo is null\r\n"); | ||
92 | return USB_ERROR_EPINFO_IS_NULL; | ||
93 | } | ||
94 | |||
95 | // Save old pointer to EP_RECORD of address 0 | ||
96 | oldep_ptr = p->epinfo; | ||
97 | |||
98 | // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence | ||
99 | p->epinfo = epInfo; | ||
100 | |||
101 | p->lowspeed = lowspeed; | ||
102 | |||
103 | // Get device descriptor | ||
104 | rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); | ||
105 | |||
106 | // Restore p->epinfo | ||
107 | p->epinfo = oldep_ptr; | ||
108 | |||
109 | if(rcode) { | ||
110 | goto FailGetDevDescr; | ||
111 | } | ||
112 | |||
113 | // Allocate new address according to device class | ||
114 | bAddress = addrPool.AllocAddress(parent, false, port); | ||
115 | |||
116 | // Extract Max Packet Size from device descriptor | ||
117 | epInfo[0].maxPktSize = udd->bMaxPacketSize0; | ||
118 | |||
119 | // Assign new address to the device | ||
120 | rcode = pUsb->setAddr(0, 0, bAddress); | ||
121 | if(rcode) { | ||
122 | p->lowspeed = false; | ||
123 | addrPool.FreeAddress(bAddress); | ||
124 | bAddress = 0; | ||
125 | //USBTRACE2("setAddr:",rcode); | ||
126 | return rcode; | ||
127 | }//if (rcode... | ||
128 | |||
129 | //USBTRACE2("\r\nAddr:", bAddress); | ||
130 | // Spec says you should wait at least 200ms. | ||
131 | //delay(300); | ||
132 | |||
133 | p->lowspeed = false; | ||
134 | |||
135 | //get pointer to assigned address record | ||
136 | p = addrPool.GetUsbDevicePtr(bAddress); | ||
137 | if(!p) { | ||
138 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||
139 | } | ||
140 | |||
141 | p->lowspeed = lowspeed; | ||
142 | |||
143 | // Assign epInfo to epinfo pointer - only EP0 is known | ||
144 | rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); | ||
145 | if(rcode) { | ||
146 | goto FailSetDevTblEntry; | ||
147 | } | ||
148 | |||
149 | //check if ADK device is already in accessory mode; if yes, configure and exit | ||
150 | if(udd->idVendor == ADK_VID && | ||
151 | (udd->idProduct == ADK_PID || udd->idProduct == ADB_PID)) { | ||
152 | USBTRACE("\r\nAcc.mode device detected"); | ||
153 | /* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */ | ||
154 | num_of_conf = udd->bNumConfigurations; | ||
155 | |||
156 | //USBTRACE2("\r\nNC:",num_of_conf); | ||
157 | for(uint8_t i = 0; i < num_of_conf; i++) { | ||
158 | ConfigDescParser < 0, 0, 0, 0 > confDescrParser(this); | ||
159 | delay(1); | ||
160 | rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); | ||
161 | #if defined(XOOM) | ||
162 | //added by Jaylen Scott Vanorden | ||
163 | if(rcode) { | ||
164 | USBTRACE2("\r\nGot 1st bad code for config: ", rcode); | ||
165 | // Try once more | ||
166 | rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); | ||
167 | } | ||
168 | #endif | ||
169 | if(rcode) { | ||
170 | goto FailGetConfDescr; | ||
171 | } | ||
172 | if(bNumEP > 2) { | ||
173 | break; | ||
174 | } | ||
175 | } // for (uint8_t i=0; i<num_of_conf; i++... | ||
176 | |||
177 | if(bNumEP == 3) { | ||
178 | // Assign epInfo to epinfo pointer - this time all 3 endpoins | ||
179 | rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo); | ||
180 | if(rcode) { | ||
181 | goto FailSetDevTblEntry; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | // Set Configuration Value | ||
186 | rcode = pUsb->setConf(bAddress, 0, bConfNum); | ||
187 | if(rcode) { | ||
188 | goto FailSetConfDescr; | ||
189 | } | ||
190 | /* print endpoint structure */ | ||
191 | /* | ||
192 | USBTRACE("\r\nEndpoint Structure:"); | ||
193 | USBTRACE("\r\nEP0:"); | ||
194 | USBTRACE2("\r\nAddr: ", epInfo[0].epAddr); | ||
195 | USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize); | ||
196 | USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs); | ||
197 | USBTRACE("\r\nEpout:"); | ||
198 | USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr); | ||
199 | USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize); | ||
200 | USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs); | ||
201 | USBTRACE("\r\nEpin:"); | ||
202 | USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr); | ||
203 | USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize); | ||
204 | USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs); | ||
205 | */ | ||
206 | |||
207 | USBTRACE("\r\nConfiguration successful"); | ||
208 | ready = true; | ||
209 | return 0; //successful configuration | ||
210 | }//if( buf->idVendor == ADK_VID... | ||
211 | |||
212 | //probe device - get accessory protocol revision | ||
213 | { | ||
214 | uint16_t adkproto = -1; | ||
215 | delay(1); | ||
216 | rcode = getProto((uint8_t*) & adkproto); | ||
217 | #if defined(XOOM) | ||
218 | //added by Jaylen Scott Vanorden | ||
219 | if(rcode) { | ||
220 | USBTRACE2("\r\nGot 1st bad code for proto: ", rcode); | ||
221 | // Try once more | ||
222 | rcode = getProto((uint8_t*) & adkproto); | ||
223 | } | ||
224 | #endif | ||
225 | if(rcode) { | ||
226 | goto FailGetProto; //init fails | ||
227 | } | ||
228 | USBTRACE2("\r\nADK protocol rev. ", adkproto); | ||
229 | } | ||
230 | |||
231 | delay(100); | ||
232 | |||
233 | //sending ID strings | ||
234 | sendStr(ACCESSORY_STRING_MANUFACTURER, manufacturer); | ||
235 | delay(10); | ||
236 | sendStr(ACCESSORY_STRING_MODEL, model); | ||
237 | delay(10); | ||
238 | sendStr(ACCESSORY_STRING_DESCRIPTION, description); | ||
239 | delay(10); | ||
240 | sendStr(ACCESSORY_STRING_VERSION, version); | ||
241 | delay(10); | ||
242 | sendStr(ACCESSORY_STRING_URI, uri); | ||
243 | delay(10); | ||
244 | sendStr(ACCESSORY_STRING_SERIAL, serial); | ||
245 | |||
246 | delay(100); | ||
247 | |||
248 | //switch to accessory mode | ||
249 | //the Android phone will reset | ||
250 | rcode = switchAcc(); | ||
251 | if(rcode) { | ||
252 | goto FailSwAcc; //init fails | ||
253 | } | ||
254 | rcode = USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET; | ||
255 | delay(100); // Give Android a chance to do its reset. This is a guess, and possibly could be lower. | ||
256 | goto SwAttempt; //switch to accessory mode attempted | ||
257 | |||
258 | /* diagnostic messages */ | ||
259 | FailGetDevDescr: | ||
260 | #ifdef DEBUG_USB_HOST | ||
261 | NotifyFailGetDevDescr(rcode); | ||
262 | goto Fail; | ||
263 | #endif | ||
264 | |||
265 | FailSetDevTblEntry: | ||
266 | #ifdef DEBUG_USB_HOST | ||
267 | NotifyFailSetDevTblEntry(rcode); | ||
268 | goto Fail; | ||
269 | #endif | ||
270 | |||
271 | FailGetConfDescr: | ||
272 | #ifdef DEBUG_USB_HOST | ||
273 | NotifyFailGetConfDescr(rcode); | ||
274 | goto Fail; | ||
275 | #endif | ||
276 | |||
277 | FailSetConfDescr: | ||
278 | #ifdef DEBUG_USB_HOST | ||
279 | NotifyFailSetConfDescr(rcode); | ||
280 | goto Fail; | ||
281 | #endif | ||
282 | |||
283 | FailGetProto: | ||
284 | #ifdef DEBUG_USB_HOST | ||
285 | USBTRACE("\r\ngetProto:"); | ||
286 | goto Fail; | ||
287 | #endif | ||
288 | |||
289 | FailSwAcc: | ||
290 | #ifdef DEBUG_USB_HOST | ||
291 | USBTRACE("\r\nswAcc:"); | ||
292 | goto Fail; | ||
293 | #endif | ||
294 | |||
295 | //FailOnInit: | ||
296 | // USBTRACE("OnInit:"); | ||
297 | // goto Fail; | ||
298 | // | ||
299 | SwAttempt: | ||
300 | #ifdef DEBUG_USB_HOST | ||
301 | USBTRACE("\r\nAccessory mode switch attempt"); | ||
302 | Fail: | ||
303 | #endif | ||
304 | //USBTRACE2("\r\nADK Init Failed, error code: ", rcode); | ||
305 | //NotifyFail(rcode); | ||
306 | Release(); | ||
307 | return rcode; | ||
308 | } | ||
309 | |||
310 | /* Extracts bulk-IN and bulk-OUT endpoint information from config descriptor */ | ||
311 | void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) { | ||
312 | //ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf); | ||
313 | //ErrorMessage<uint8_t>(PSTR("Iface Num"), iface); | ||
314 | //ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt); | ||
315 | |||
316 | //added by Yuuichi Akagawa | ||
317 | if(bNumEP == 3) { | ||
318 | return; | ||
319 | } | ||
320 | |||
321 | bConfNum = conf; | ||
322 | |||
323 | if((pep->bmAttributes & 0x02) == 2) { | ||
324 | uint8_t index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; | ||
325 | // Fill in the endpoint info structure | ||
326 | epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); | ||
327 | epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; | ||
328 | |||
329 | bNumEP++; | ||
330 | |||
331 | //PrintEndpointDescriptor(pep); | ||
332 | } | ||
333 | } | ||
334 | |||
335 | /* Performs a cleanup after failed Init() attempt */ | ||
336 | uint8_t ADK::Release() { | ||
337 | pUsb->GetAddressPool().FreeAddress(bAddress); | ||
338 | |||
339 | bNumEP = 1; //must have to be reset to 1 | ||
340 | |||
341 | bAddress = 0; | ||
342 | ready = false; | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) { | ||
347 | //USBTRACE2("\r\nAddr: ", bAddress ); | ||
348 | //USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr); | ||
349 | return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr); | ||
350 | } | ||
351 | |||
352 | uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr) { | ||
353 | return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr); | ||
354 | } | ||
355 | |||
356 | void ADK::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) { | ||
357 | Notify(PSTR("Endpoint descriptor:"), 0x80); | ||
358 | Notify(PSTR("\r\nLength:\t\t"), 0x80); | ||
359 | D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80); | ||
360 | Notify(PSTR("\r\nType:\t\t"), 0x80); | ||
361 | D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80); | ||
362 | Notify(PSTR("\r\nAddress:\t"), 0x80); | ||
363 | D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80); | ||
364 | Notify(PSTR("\r\nAttributes:\t"), 0x80); | ||
365 | D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80); | ||
366 | Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); | ||
367 | D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80); | ||
368 | Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); | ||
369 | D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80); | ||
370 | Notify(PSTR("\r\n"), 0x80); | ||
371 | } | ||