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
38AndroidAccessory::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
54void AndroidAccessory::powerOn(void)
55{
56    max.powerOn();
57    delay(200);
58}
59
60int 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
71void 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
82bool 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
115bool 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
192bool 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
226bool 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
263int AndroidAccessory::read(void *buff, int len, unsigned int nakLimit)
264{
265    return usb.newInTransfer(1, in, len, (char *)buff, nakLimit);
266}
267
268int AndroidAccessory::write(void *buff, int len)
269{
270    usb.outTransfer(1, out, len, (char *)buff);
271    return len;
272}
273
274