1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
18 #include <Max3421e.h>
19 #include <Usb.h>
20 #include <AndroidAccessory.h>
21 
22 #define USB_ACCESSORY_VENDOR_ID         0x18D1
23 #define USB_ACCESSORY_PRODUCT_ID        0x2D00
24 
25 #define USB_ACCESSORY_ADB_PRODUCT_ID    0x2D01
26 #define ACCESSORY_STRING_MANUFACTURER   0
27 #define ACCESSORY_STRING_MODEL          1
28 #define ACCESSORY_STRING_DESCRIPTION    2
29 #define ACCESSORY_STRING_VERSION        3
30 #define ACCESSORY_STRING_URI            4
31 #define ACCESSORY_STRING_SERIAL         5
32 
33 #define ACCESSORY_GET_PROTOCOL          51
34 #define ACCESSORY_SEND_STRING           52
35 #define ACCESSORY_START                 53
36 
37 
AndroidAccessory(const char * manufacturer,const char * model,const char * description,const char * version,const char * uri,const char * serial)38 AndroidAccessory::AndroidAccessory(const char *manufacturer,
39                                    const char *model,
40                                    const char *description,
41                                    const char *version,
42                                    const char *uri,
43                                    const char *serial) : manufacturer(manufacturer),
44                                                          model(model),
45                                                          description(description),
46                                                          version(version),
47                                                          uri(uri),
48                                                          serial(serial),
49                                                          connected(false)
50 {
51 
52 }
53 
powerOn(void)54 void AndroidAccessory::powerOn(void)
55 {
56     max.powerOn();
57     delay(200);
58 }
59 
getProtocol(byte addr)60 int AndroidAccessory::getProtocol(byte addr)
61 {
62     uint16_t protocol = -1;
63     usb.ctrlReq(addr, 0,
64                 USB_SETUP_DEVICE_TO_HOST |
65                 USB_SETUP_TYPE_VENDOR |
66                 USB_SETUP_RECIPIENT_DEVICE,
67                 ACCESSORY_GET_PROTOCOL, 0, 0, 0, 2, (char *)&protocol);
68     return protocol;
69 }
70 
sendString(byte addr,int index,const char * str)71 void AndroidAccessory::sendString(byte addr, int index, const char *str)
72 {
73     usb.ctrlReq(addr, 0,
74                 USB_SETUP_HOST_TO_DEVICE |
75                 USB_SETUP_TYPE_VENDOR |
76                 USB_SETUP_RECIPIENT_DEVICE,
77                 ACCESSORY_SEND_STRING, 0, 0, index,
78                 strlen(str) + 1, (char *)str);
79 }
80 
81 
switchDevice(byte addr)82 bool AndroidAccessory::switchDevice(byte addr)
83 {
84     int protocol = getProtocol(addr);
85 
86     if (protocol >= 1) {
87         Serial.print("device supports protocol 1 or higher\n");
88     } else {
89         Serial.print("could not read device protocol version\n");
90         return false;
91     }
92 
93     sendString(addr, ACCESSORY_STRING_MANUFACTURER, manufacturer);
94     sendString(addr, ACCESSORY_STRING_MODEL, model);
95     sendString(addr, ACCESSORY_STRING_DESCRIPTION, description);
96     sendString(addr, ACCESSORY_STRING_VERSION, version);
97     sendString(addr, ACCESSORY_STRING_URI, uri);
98     sendString(addr, ACCESSORY_STRING_SERIAL, serial);
99 
100     usb.ctrlReq(addr, 0,
101                 USB_SETUP_HOST_TO_DEVICE |
102                 USB_SETUP_TYPE_VENDOR |
103                 USB_SETUP_RECIPIENT_DEVICE,
104                 ACCESSORY_START, 0, 0, 0, 0, NULL);
105 
106     while (usb.getUsbTaskState() != USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) {
107         max.Task();
108         usb.Task();
109     }
110 
111     return true;
112 }
113 
114 // Finds the first bulk IN and bulk OUT endpoints
findEndpoints(byte addr,EP_RECORD * inEp,EP_RECORD * outEp)115 bool AndroidAccessory::findEndpoints(byte addr, EP_RECORD *inEp, EP_RECORD *outEp)
116 {
117     int len;
118     byte err;
119     uint8_t *p;
120 
121     err = usb.getConfDescr(addr, 0, 4, 0, (char *)descBuff);
122     if (err) {
123         Serial.print("Can't get config descriptor length\n");
124         return false;
125     }
126 
127 
128     len = descBuff[2] | ((int)descBuff[3] << 8);
129     if (len > sizeof(descBuff)) {
130         Serial.print("config descriptor too large\n");
131             /* might want to truncate here */
132         return false;
133     }
134 
135     err = usb.getConfDescr(addr, 0, len, 0, (char *)descBuff);
136     if (err) {
137         Serial.print("Can't get config descriptor\n");
138         return false;
139     }
140 
141     p = descBuff;
142     inEp->epAddr = 0;
143     outEp->epAddr = 0;
144     while (p < (descBuff + len)){
145         uint8_t descLen = p[0];
146         uint8_t descType = p[1];
147         USB_ENDPOINT_DESCRIPTOR *epDesc;
148         EP_RECORD *ep;
149 
150         switch (descType) {
151         case USB_DESCRIPTOR_CONFIGURATION:
152             Serial.print("config desc\n");
153             break;
154 
155         case USB_DESCRIPTOR_INTERFACE:
156             Serial.print("interface desc\n");
157             break;
158 
159         case USB_DESCRIPTOR_ENDPOINT:
160             epDesc = (USB_ENDPOINT_DESCRIPTOR *)p;
161             if (!inEp->epAddr && (epDesc->bEndpointAddress & 0x80))
162                 ep = inEp;
163             else if (!outEp->epAddr)
164                 ep = outEp;
165             else
166                 ep = NULL;
167 
168             if (ep) {
169                 ep->epAddr = epDesc->bEndpointAddress & 0x7f;
170                 ep->Attr = epDesc->bmAttributes;
171                 ep->MaxPktSize = epDesc->wMaxPacketSize;
172                 ep->sndToggle = bmSNDTOG0;
173                 ep->rcvToggle = bmRCVTOG0;
174             }
175             break;
176 
177         default:
178             Serial.print("unkown desc type ");
179             Serial.println( descType, HEX);
180             break;
181         }
182 
183         p += descLen;
184     }
185 
186     if (!(inEp->epAddr && outEp->epAddr))
187         Serial.println("can't find accessory endpoints");
188 
189     return inEp->epAddr && outEp->epAddr;
190 }
191 
configureAndroid(void)192 bool AndroidAccessory::configureAndroid(void)
193 {
194     byte err;
195     EP_RECORD inEp, outEp;
196 
197     if (!findEndpoints(1, &inEp, &outEp))
198         return false;
199 
200     memset(&epRecord, 0x0, sizeof(epRecord));
201 
202     epRecord[inEp.epAddr] = inEp;
203     if (outEp.epAddr != inEp.epAddr)
204         epRecord[outEp.epAddr] = outEp;
205 
206     in = inEp.epAddr;
207     out = outEp.epAddr;
208 
209     Serial.println(inEp.epAddr, HEX);
210     Serial.println(outEp.epAddr, HEX);
211 
212     epRecord[0] = *(usb.getDevTableEntry(0,0));
213     usb.setDevTableEntry(1, epRecord);
214 
215     err = usb.setConf( 1, 0, 1 );
216     if (err) {
217         Serial.print("Can't set config to 1\n");
218         return false;
219     }
220 
221     usb.setUsbTaskState( USB_STATE_RUNNING );
222 
223     return true;
224 }
225 
isConnected(void)226 bool AndroidAccessory::isConnected(void)
227 {
228     USB_DEVICE_DESCRIPTOR *devDesc = (USB_DEVICE_DESCRIPTOR *) descBuff;
229     byte err;
230 
231     max.Task();
232     usb.Task();
233 
234     if (!connected &&
235         usb.getUsbTaskState() >= USB_STATE_CONFIGURING &&
236         usb.getUsbTaskState() != USB_STATE_RUNNING) {
237         Serial.print("\nDevice addressed... ");
238         Serial.print("Requesting device descriptor.\n");
239 
240         err = usb.getDevDescr(1, 0, 0x12, (char *) devDesc);
241         if (err) {
242             Serial.print("\nDevice descriptor cannot be retrieved. Trying again\n");
243             return false;
244         }
245 
246         if (isAccessoryDevice(devDesc)) {
247             Serial.print("found android acessory device\n");
248 
249             connected = configureAndroid();
250         } else {
251             Serial.print("found possible device. swithcing to serial mode\n");
252             switchDevice(1);
253         }
254     } else if (usb.getUsbTaskState() == USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) {
255         if (connected)
256             Serial.println("disconnect\n");
257         connected = false;
258     }
259 
260     return connected;
261 }
262 
read(void * buff,int len,unsigned int nakLimit)263 int AndroidAccessory::read(void *buff, int len, unsigned int nakLimit)
264 {
265     return usb.newInTransfer(1, in, len, (char *)buff, nakLimit);
266 }
267 
write(void * buff,int len)268 int AndroidAccessory::write(void *buff, int len)
269 {
270     usb.outTransfer(1, out, len, (char *)buff);
271     return len;
272 }
273 
274