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