USB Host Shield 2.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
adk.cpp
Go to the documentation of this file.
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 
34 manufacturer(manufacturer),
35 model(model),
36 description(description),
37 version(version),
38 uri(uri),
39 serial(serial),
40 pUsb(p), //pointer to USB class instance - mandatory
41 bAddress(0), //device address - mandatory
42 bConfNum(0), //configuration number
43 bNumEP(1), //if config descriptor needs to be parsed
44 ready(false) {
45  // initialize endpoint data structures
46  for (uint8_t i = 0; i < ADK_MAX_ENDPOINTS; i++) {
47  epInfo[i].epAddr = 0;
48  epInfo[i].maxPktSize = (i) ? 0 : 8;
49  epInfo[i].epAttribs = (0xfc & (USB_NAK_MAX_POWER << 2));
50  }//for(uint8_t i=0; i<ADK_MAX_ENDPOINTS; i++...
51 
52  //set bulk-IN EP naklimit to 1
53  epInfo[epDataInIndex].epAttribs = (0xfc & (USB_NAK_NOWAIT << 2));
54 
55  // register in USB subsystem
56  if (pUsb) {
57  pUsb->RegisterDeviceClass(this); //set devConfig[] entry
58  }
59 }
60 
61 /* Connection initialization of an Android phone */
62 uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
63 
64  uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
65  uint8_t rcode;
66  UsbDevice *p = NULL;
67  EpInfo *oldep_ptr = NULL;
68  uint8_t num_of_conf; // number of configurations
69 
70  // get memory address of USB device address pool
71  AddressPool &addrPool = pUsb->GetAddressPool();
72 
73  USBTRACE("\r\nADK Init");
74 
75  // check if address has already been assigned to an instance
76  if (bAddress) {
77  USBTRACE("\r\nAddress in use");
79  }
80 
81  // Get pointer to pseudo device with address 0 assigned
82  p = addrPool.GetUsbDevicePtr(0);
83 
84  if (!p) {
85  USBTRACE("\r\nAddress not found");
87  }
88 
89  if (!p->epinfo) {
90  USBTRACE("epinfo is null\r\n");
92  }
93 
94  // Save old pointer to EP_RECORD of address 0
95  oldep_ptr = p->epinfo;
96 
97  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
98  p->epinfo = epInfo;
99 
100  p->lowspeed = lowspeed;
101 
102  // Get device descriptor
103  rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
104 
105  // Restore p->epinfo
106  p->epinfo = oldep_ptr;
107 
108  if (rcode) {
109  goto FailGetDevDescr;
110  }
111 
112  // Allocate new address according to device class
113  bAddress = addrPool.AllocAddress(parent, false, port);
114 
115  // Extract Max Packet Size from device descriptor
116  epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
117 
118  // Assign new address to the device
119  rcode = pUsb->setAddr(0, 0, bAddress);
120  if (rcode) {
121  p->lowspeed = false;
122  addrPool.FreeAddress(bAddress);
123  bAddress = 0;
124  //USBTRACE2("setAddr:",rcode);
125  return rcode;
126  }//if (rcode...
127 
128  //USBTRACE2("\r\nAddr:", bAddress);
129 
130  p->lowspeed = false;
131 
132  //get pointer to assigned address record
133  p = addrPool.GetUsbDevicePtr(bAddress);
134  if (!p) {
136  }
137 
138  p->lowspeed = lowspeed;
139 
140  // Assign epInfo to epinfo pointer - only EP0 is known
141  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
142  if (rcode) {
143  goto FailSetDevTblEntry;
144  }
145 
146  //check if ADK device is already in accessory mode; if yes, configure and exit
147  if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor == ADK_VID &&
148  (((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADB_PID)) {
149  USBTRACE("\r\nAcc.mode device detected");
150  /* go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */
151  num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
152 
153  //USBTRACE2("\r\nNC:",num_of_conf);
154 
155  for (uint8_t i = 0; i < num_of_conf; i++) {
156  ConfigDescParser < 0, 0, 0, 0 > confDescrParser(this);
157  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
158  if (rcode) {
159  goto FailGetConfDescr;
160  }
161  if (bNumEP > 2) {
162  break;
163  }
164  } // for (uint8_t i=0; i<num_of_conf; i++...
165 
166  if (bNumEP == 3) {
167  // Assign epInfo to epinfo pointer - this time all 3 endpoins
168  rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
169  if (rcode) {
170  goto FailSetDevTblEntry;
171  }
172  }
173 
174 
175 
176  // Set Configuration Value
177  rcode = pUsb->setConf(bAddress, 0, bConfNum);
178  if (rcode) {
179  goto FailSetConfDescr;
180  }
181  /* print endpoint structure */
182  // USBTRACE("\r\nEndpoint Structure:");
183  // USBTRACE("\r\nEP0:");
184  // USBTRACE2("\r\nAddr: ", epInfo[0].epAddr );
185  // USBTRACE2("\r\nMax.pkt.size: ", epInfo[0].maxPktSize );
186  // USBTRACE2("\r\nAttr: ", epInfo[0].epAttribs );
187  // USBTRACE("\r\nEpout:");
188  // USBTRACE2("\r\nAddr: ", epInfo[epDataOutIndex].epAddr );
189  // USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataOutIndex].maxPktSize );
190  // USBTRACE2("\r\nAttr: ", epInfo[epDataOutIndex].epAttribs );
191  // USBTRACE("\r\nEpin:");
192  // USBTRACE2("\r\nAddr: ", epInfo[epDataInIndex].epAddr );
193  // USBTRACE2("\r\nMax.pkt.size: ", epInfo[epDataInIndex].maxPktSize );
194  // USBTRACE2("\r\nAttr: ", epInfo[epDataInIndex].epAttribs );
195 
196  USBTRACE("\r\nConfiguration successful");
197  ready = true;
198  return 0; //successful configuration
199  }//if( buf->idVendor == ADK_VID...
200 
201  //probe device - get accessory protocol revision
202  {
203  uint16_t adkproto = -1;
204  rcode = getProto((uint8_t*) & adkproto);
205  if (rcode) {
206  goto FailGetProto; //init fails
207  }
208  USBTRACE2("\r\nADK protocol rev. ", adkproto);
209  }
210 
211  //sending ID strings
212  sendStr(ACCESSORY_STRING_MANUFACTURER, manufacturer);
213  sendStr(ACCESSORY_STRING_MODEL, model);
214  sendStr(ACCESSORY_STRING_DESCRIPTION, description);
215  sendStr(ACCESSORY_STRING_VERSION, version);
216  sendStr(ACCESSORY_STRING_URI, uri);
217  sendStr(ACCESSORY_STRING_SERIAL, serial);
218 
219  //switch to accessory mode
220  //the Android phone will reset
221  rcode = switchAcc();
222  if (rcode) {
223  goto FailSwAcc; //init fails
224  }
225  rcode = -1;
226  goto SwAttempt; //switch to accessory mode attempted
227 
228  /* diagnostic messages */
229 FailGetDevDescr:
230 #ifdef DEBUG_USB_HOST
232  goto Fail;
233 #endif
234 
235 FailSetDevTblEntry:
236 #ifdef DEBUG_USB_HOST
238  goto Fail;
239 #endif
240 
241 FailGetConfDescr:
242 #ifdef DEBUG_USB_HOST
244  goto Fail;
245 #endif
246 
247 FailSetConfDescr:
248 #ifdef DEBUG_USB_HOST
250  goto Fail;
251 #endif
252 
253 FailGetProto:
254 #ifdef DEBUG_USB_HOST
255  USBTRACE("\r\ngetProto:");
256  goto Fail;
257 #endif
258 
259 FailSwAcc:
260 #ifdef DEBUG_USB_HOST
261  USBTRACE("\r\nswAcc:");
262  goto Fail;
263 #endif
264 
265 SwAttempt:
266 #ifdef DEBUG_USB_HOST
267  USBTRACE("\r\nAccessory mode switch attempt");
268 #endif
269 //FailOnInit:
270  // USBTRACE("OnInit:");
271  // goto Fail;
272  //
273 Fail:
274  //USBTRACE2("\r\nADK Init Failed, error code: ", rcode);
275  //NotifyFail(rcode);
276  Release();
277  return rcode;
278 }
279 
280 /* Extracts bulk-IN and bulk-OUT endpoint information from config descriptor */
281 void ADK::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
282  //ErrorMessage<uint8_t>(PSTR("Conf.Val"), conf);
283  //ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
284  //ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
285 
286  //added by Yuuichi Akagawa
287  if (bNumEP == 3) {
288  return;
289  }
290 
291  bConfNum = conf;
292 
293  uint8_t index;
294 
295  // if ((pep->bmAttributes & 0x02) == 2) {
296  index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
297  // }
298 
299  // Fill in the endpoint info structure
300  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
301  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
302 
303  bNumEP++;
304 
305  //PrintEndpointDescriptor(pep);
306 }
307 
308 /* Performs a cleanup after failed Init() attempt */
309 uint8_t ADK::Release() {
311 
312  bNumEP = 1; //must have to be reset to 1
313 
314  bAddress = 0;
315  ready = false;
316  return 0;
317 }
318 
319 uint8_t ADK::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
320  //USBTRACE2("\r\nAddr: ", bAddress );
321  //USBTRACE2("\r\nEP: ",epInfo[epDataInIndex].epAddr);
322  return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
323 }
324 
325 uint8_t ADK::SndData(uint16_t nbytes, uint8_t *dataptr) {
326  return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
327 }
328 
330  Notify(PSTR("Endpoint descriptor:"), 0x80);
331  Notify(PSTR("\r\nLength:\t\t"), 0x80);
332  PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
333  Notify(PSTR("\r\nType:\t\t"), 0x80);
334  PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
335  Notify(PSTR("\r\nAddress:\t"), 0x80);
336  PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
337  Notify(PSTR("\r\nAttributes:\t"), 0x80);
338  PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
339  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
340  PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
341  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
342  PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
343  Notify(PSTR("\r\n"), 0x80);
344 }