1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12#include "otgusbtty.h"
13#include <usb/usb.h>
14#include "../services.h"
15
16#include <stdio.h>
17#include <string.h>
18
19struct otg_usbtty {
20    usb_otg_t otg;
21    ps_dma_man_t* dman;
22    void* desc;
23    uintptr_t pdesc;
24};
25
26struct free_token {
27    void* vaddr;
28    size_t size;
29    ps_dma_man_t* dman;
30};
31
32static struct device_desc otg_usbtty_device_desc = {
33    .bLength                = 0x12,
34    .bDescriptorType        = 0x1,
35    .bcdUSB                 = 0x110,
36    .bDeviceClass           = 0x0,
37    .bDeviceSubClass        = 0x0,
38    .bDeviceProtocol        = 0x0,
39    .bMaxPacketSize0        = 0x40,
40    .idVendor               = 0x067b,
41    .idProduct              = 0x2303,
42    .bcdDevice              = 0x300,
43    .iManufacturer          = 0x0 /* 0x1 */,
44    .iProduct               = 0x0 /* 0x2 */,
45    .iSerialNumber          = 0x0,
46    .bNumConfigurations     = 0x1
47};
48
49static struct config_desc otg_usbtty_config_desc = {
50    .bLength                = 0x9,
51    .bDescriptorType        = 0x2,
52    .wTotalLength           = 0x27,
53    .bNumInterfaces         = 0x1,
54    .bConfigurationValue    = 0x1,
55    .iConfigurationIndex    = 0x0,
56    .bmAttributes           = 0x80,
57    .bMaxPower              = 0x32
58};
59
60static struct iface_desc otg_usbtty_iface_desc = {
61    .bLength                = 0x9,
62    .bDescriptorType        = 0x4,
63    .bInterfaceNumber       = 0x0,
64    .bAlternateSetting      = 0x0,
65    .bNumEndpoints          = 0x3,
66    .bInterfaceClass        = 0xff,
67    .bInterfaceSubClass     = 0x0,
68    .bInterfaceProtocol     = 0x0,
69    .iInterface             = 0x0
70};
71
72static struct endpoint_desc otg_usbtty_ep1_desc = {
73    .bLength                = 0x7,
74    .bDescriptorType        = 0x5,
75    .bEndpointAddress       = 0x81,
76    .bmAttributes           = 0x3,
77    .wMaxPacketSize         = 0xa,
78    .bInterval              = 0x1
79};
80
81static struct endpoint_desc otg_usbtty_ep2_desc = {
82    .bLength                = 0x7,
83    .bDescriptorType        = 0x5,
84    .bEndpointAddress       = 0x2,
85    .bmAttributes           = 0x2,
86    .wMaxPacketSize         = 0x40,
87    .bInterval              = 0x0
88};
89
90static struct endpoint_desc otg_usbtty_ep3_desc = {
91    .bLength                = 0x7,
92    .bDescriptorType        = 0x5,
93    .bEndpointAddress       = 0x83,
94    .bmAttributes           = 0x2,
95    .wMaxPacketSize         = 0x40,
96    .bInterval              = 0x0
97};
98
99
100static void
101freebuf_cb(usb_otg_t otg, void* token,
102           enum usb_xact_status stat)
103{
104    struct free_token* t;
105
106    if (stat != XACTSTAT_SUCCESS) {
107	    ZF_LOGF("Transaction failed\n");
108    }
109    t = (struct free_token*)token;
110    ps_dma_free_pinned(t->dman, t->vaddr, t->size);
111    usb_free(t);
112}
113
114static void
115send_desc(otg_usbtty_t tty, enum DescriptorType type, int index,
116          int maxlen)
117{
118    struct anon_desc* d = NULL;
119    /* Not handling index yet... */
120    if (index != 0) {
121	    ZF_LOGF("Index not implemented\n");
122    }
123    /* Find the descriptor */
124    switch (type) {
125    case DEVICE:
126        d = (struct anon_desc*)&otg_usbtty_device_desc;
127        printf("device descriptor read/");
128        if (maxlen >= d->bLength) {
129            printf("all\n");
130        } else {
131            printf("%d\n", maxlen);
132        }
133        break;
134    case CONFIGURATION:
135        printf("config\n");
136        break;
137    case STRING:
138        printf("string\n");
139        break;
140    case INTERFACE:
141        printf("interface\n");
142        break;
143    case ENDPOINT:
144        printf("endpoint\n");
145        break;
146    case DEVICE_QUALIFIER:
147        printf("device qualifier\n");
148        break;
149    case OTHER_SPEED_CONFIGURATION:
150        printf("other speed\n");
151        break;
152    case INTERFACE_POWER:
153        printf("interface power\n");
154        break;
155    case HID:
156        printf("hid\n");
157        break;
158    case HUB:
159        printf("Hub\n");
160        break;
161    default:
162        printf("Unhandled descriptor request\n");
163    }
164    /* Send the descriptor */
165    if (d != NULL) {
166        struct free_token* t;
167        uintptr_t pbuf;
168        int err;
169
170        t = usb_malloc(sizeof(*t));
171	if (!t) {
172		ZF_LOGF("Out of memory\n");
173	}
174        t->dman = tty->dman;
175
176        /* limit size to prevent babble */
177        t->size = d->bLength;
178        if (maxlen < t->size) {
179            t->size = maxlen;
180        }
181        /* Copy in */
182        t->vaddr = ps_dma_alloc_pinned(tty->dman, t->size, 32, 0, PS_MEM_NORMAL, &pbuf);
183        if (t->vaddr == NULL) {
184            ZF_LOGF("Out of DMA memory\n");
185        }
186        memcpy(t->vaddr, d, t->size);
187
188        /* Send the packet */
189        err = otg_prime(tty->otg, 0, PID_IN, t->vaddr, pbuf, t->size, freebuf_cb, t);
190        if (err) {
191            ps_dma_free_pinned(tty->dman, t->vaddr, t->size);
192            ZF_LOGF("OTG device error\n");
193        }
194        /* Status phase */
195        err = otg_prime(tty->otg, 0, PID_OUT, NULL, 0, 0, freebuf_cb, t);
196        if (err) {
197            ps_dma_free_pinned(tty->dman, t->vaddr, t->size);
198            ZF_LOGF("OTG device error\n");
199        }
200    }
201}
202
203static void
204usbtty_setup_cb(usb_otg_t otg, void* token, struct usbreq* req)
205{
206    otg_usbtty_t tty = (otg_usbtty_t)token;
207    (void)otg_usbtty_config_desc;
208    (void)otg_usbtty_iface_desc;
209    (void)otg_usbtty_ep1_desc;
210    (void)otg_usbtty_ep2_desc;
211    (void)otg_usbtty_ep3_desc;
212    switch (req->bRequest) {
213    case GET_DESCRIPTOR:
214        send_desc(tty, req->wValue >> 8, req->wValue & 0xff,
215                  req->wLength);
216        break;
217    case GET_CONFIGURATION:
218        printf("get conf\n");
219        break;
220    case GET_STATUS:
221        printf("get stat\n");
222        break;
223    case CLR_FEATURE:
224        printf("Clear feat\n");
225        break;
226    case SET_FEATURE:
227        printf("Set feature\n");
228        break;
229    case SET_ADDRESS:
230        printf("Set address\n");
231        break;
232    case SET_DESCRIPTOR:
233        printf("Set descriptor\n");
234        break;
235    case SET_CONFIGURATION:
236        printf("Set config\n");
237        break;
238    case GET_INTERFACE:
239        printf("Get interface\n");
240        break;
241    case SET_INTERFACE:
242        printf("Set interface\n");
243        break;
244    default:
245        printf("Unhandled request %d\n", req->bRequest);
246    }
247}
248
249int
250otg_usbtty_init(usb_otg_t otg, ps_dma_man_t* dman,
251                otg_usbtty_t* usbtty)
252{
253    otg_usbtty_t tty;
254    int err;
255
256    if (!dman || !usbtty || !otg) {
257        ZF_LOGF("Invalid arguments\n");
258    }
259
260    /* Allocate memory */
261    tty = usb_malloc(sizeof(*tty));
262    if (tty == NULL) {
263        return -1;
264    }
265    tty->dman = dman;
266    tty->otg = otg;
267    /* Initialise the control endpoint */
268    err = otg_ep0_setup(otg, usbtty_setup_cb, tty);
269    if (err) {
270        usb_free(tty);
271        return -1;
272    }
273    *usbtty = tty;
274    return 0;
275}
276
277