1 /* 2 * Copyright 2022, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT license. 4 */ 5 6 #include <sys/condvar.h> 7 8 extern "C" { 9 #include <sys/mutex.h> 10 #include <sys/systm.h> 11 #include <sys/taskqueue.h> 12 #include <sys/priority.h> 13 14 #include <dev/usb/usb.h> 15 #include <dev/usb/usbdi.h> 16 #include <dev/usb/usb_device.h> 17 18 #include "device.h" 19 } 20 21 // undo name remappings, so we can use both FreeBSD and Haiku ones in this file 22 #undef usb_device 23 #undef usb_interface 24 #undef usb_endpoint_descriptor 25 26 #include <USB3.h> 27 28 29 usb_module_info* sUSB = NULL; 30 struct taskqueue* sUSBTaskqueue = NULL; 31 32 33 status_t 34 init_usb() 35 { 36 if (sUSB != NULL) 37 return B_OK; 38 39 if (get_module(B_USB_MODULE_NAME, (module_info**)&sUSB) != B_OK) { 40 dprintf("cannot get module \"%s\"\n", B_USB_MODULE_NAME); 41 return B_ERROR; 42 } 43 return B_OK; 44 } 45 46 47 void 48 uninit_usb() 49 { 50 if (sUSB != NULL) 51 put_module(B_USB_MODULE_NAME); 52 if (sUSBTaskqueue != NULL) 53 taskqueue_free(sUSBTaskqueue); 54 55 sUSB = NULL; 56 sUSBTaskqueue = NULL; 57 } 58 59 60 status_t 61 get_next_usb_device(uint32* cookie, freebsd_usb_device* result) 62 { 63 // We cheat here: since USB IDs are sequential, instead of doing a 64 // complicated parent/child iteration dance, we simply request device 65 // descriptors and let the USB stack figure out the rest. 66 // 67 // It would be better if we used USB->register_driver, but that is not 68 // an option at present for a variety of reasons... 69 const usb_configuration_info* config; 70 usb_device current; 71 while (*cookie < 1024) { 72 current = *cookie; 73 *cookie = *cookie + 1; 74 75 config = sUSB->get_configuration(current); 76 if (config != NULL) 77 break; 78 } 79 if (config == NULL) 80 return ENODEV; 81 82 result->haiku_usb_device = current; 83 result->endpoints_max = 0; 84 for (size_t i = 0; i < config->interface_count; i++) { 85 usb_interface_info* iface = config->interface[i].active; 86 for (size_t j = 0; j < iface->endpoint_count; j++) { 87 const int rep = result->endpoints_max++; 88 result->endpoints[rep].iface_index = i; 89 90 static_assert(sizeof(freebsd_usb_endpoint_descriptor) 91 == sizeof(usb_endpoint_descriptor), "size mismatch"); 92 93 if (result->endpoints[rep].edesc == NULL) 94 result->endpoints[rep].edesc = new freebsd_usb_endpoint_descriptor; 95 96 memcpy(result->endpoints[rep].edesc, iface->endpoint[j].descr, 97 sizeof(usb_endpoint_descriptor)); 98 } 99 } 100 101 return B_OK; 102 } 103 104 105 status_t 106 get_usb_device_attach_arg(struct freebsd_usb_device* device, struct usb_attach_arg* uaa) 107 { 108 memset(uaa, 0, sizeof(struct usb_attach_arg)); 109 110 const usb_device_descriptor* device_desc = 111 sUSB->get_device_descriptor(device->haiku_usb_device); 112 if (!device_desc) 113 return B_BAD_VALUE; 114 115 uaa->info.idVendor = device_desc->vendor_id; 116 uaa->info.idProduct = device_desc->product_id; 117 uaa->info.bcdDevice = device_desc->device_version; 118 uaa->info.bDeviceClass = device_desc->device_class; 119 uaa->info.bDeviceSubClass = device_desc->device_subclass; 120 uaa->info.bDeviceProtocol = device_desc->device_protocol; 121 122 const usb_configuration_info* config = sUSB->get_configuration(device->haiku_usb_device); 123 if (!device_desc) 124 return B_BAD_VALUE; 125 126 // TODO: represent more than just interface[0], but how? 127 usb_interface_info* iface = config->interface[0].active; 128 129 uaa->info.bInterfaceClass = iface->descr->interface_class; 130 uaa->info.bInterfaceSubClass = iface->descr->interface_subclass; 131 uaa->info.bInterfaceProtocol = iface->descr->interface_protocol; 132 133 // TODO: bIface{Index,Num}, bConfig{Index,Num} 134 135 uaa->device = device; 136 uaa->iface = NULL; 137 138 // TODO: fetch values for these? 139 uaa->usb_mode = USB_MODE_HOST; 140 uaa->port = 1; 141 uaa->dev_state = UAA_DEV_READY; 142 143 return B_OK; 144 } 145 146 147 void 148 usb_cleanup_device(freebsd_usb_device* udev) 149 { 150 for (int i = 0; i < USB_MAX_EP_UNITS; i++) { 151 delete udev->endpoints[i].edesc; 152 udev->endpoints[i].edesc = NULL; 153 } 154 } 155 156 157 static usb_error_t 158 map_usb_error(status_t err) 159 { 160 switch (err) { 161 case B_OK: return USB_ERR_NORMAL_COMPLETION; 162 case B_DEV_STALLED: return USB_ERR_STALLED; 163 case B_CANCELED: return USB_ERR_CANCELLED; 164 } 165 return USB_ERR_INVAL; 166 } 167 168 169 extern "C" usb_error_t 170 usbd_do_request_flags(struct freebsd_usb_device* udev, struct mtx* mtx, 171 struct usb_device_request* req, void* data, uint16_t flags, 172 uint16_t* actlen, usb_timeout_t timeout) 173 { 174 if (mtx != NULL) 175 mtx_unlock(mtx); 176 177 // FIXME: timeouts 178 // TODO: flags 179 180 size_t actualLen = 0; 181 status_t ret = sUSB->send_request((usb_device)udev->haiku_usb_device, 182 req->bmRequestType, req->bRequest, 183 UGETW(req->wValue), UGETW(req->wIndex), UGETW(req->wLength), 184 data, &actualLen); 185 if (actlen) 186 *actlen = actualLen; 187 188 if (mtx != NULL) 189 mtx_lock(mtx); 190 191 return map_usb_error(ret); 192 } 193 194 195 enum usb_dev_speed 196 usbd_get_speed(struct freebsd_usb_device* udev) 197 { 198 const usb_device_descriptor* descriptor = sUSB->get_device_descriptor( 199 (usb_device)udev->haiku_usb_device); 200 KASSERT(descriptor != NULL, ("no device")); 201 202 if (descriptor->usb_version >= 0x0300) 203 return USB_SPEED_SUPER; 204 else if (descriptor->usb_version >= 0x200) 205 return USB_SPEED_HIGH; 206 else if (descriptor->usb_version >= 0x110) 207 return USB_SPEED_FULL; 208 else if (descriptor->usb_version >= 0x100) 209 return USB_SPEED_LOW; 210 211 panic("unknown USB version!"); 212 return (usb_dev_speed)-1; 213 } 214 215 216 struct usb_xfer { 217 struct mtx* mutex; 218 void* priv_sc; 219 usb_callback_t* callback; 220 usb_xfer_flags flags; 221 usb_frlength_t max_data_length; 222 223 usb_device device; 224 uint8 type; 225 usb_pipe pipe; 226 iovec* frames; 227 int nframes; 228 229 uint8 usb_state; 230 bool in_progress; 231 status_t result; 232 int transferred_length; 233 234 struct task invoker; 235 struct cv condition; 236 }; 237 238 239 extern "C" usb_error_t 240 usbd_transfer_setup(struct freebsd_usb_device* udev, 241 const uint8_t* ifaces, struct usb_xfer** ppxfer, 242 const struct usb_config* setup_start, uint16_t n_setup, 243 void* priv_sc, struct mtx* xfer_mtx) 244 { 245 if (xfer_mtx == NULL) 246 xfer_mtx = &Giant; 247 248 // Make sure the taskqueue exists. 249 if (sUSBTaskqueue == NULL) { 250 mtx_lock(&Giant); 251 if (sUSBTaskqueue == NULL) { 252 sUSBTaskqueue = taskqueue_create("usb taskq", 0, 253 taskqueue_thread_enqueue, &sUSBTaskqueue); 254 taskqueue_start_threads(&sUSBTaskqueue, 1, PZERO, "usb taskq"); 255 } 256 mtx_unlock(&Giant); 257 } 258 259 const usb_configuration_info* device_config = sUSB->get_configuration( 260 (usb_device)udev->haiku_usb_device); 261 262 for (const struct usb_config* setup = setup_start; 263 setup < (setup_start + n_setup); setup++) { 264 /* skip transfers w/o callbacks */ 265 if (setup->callback == NULL) 266 continue; 267 268 struct usb_xfer* xfer = new usb_xfer; 269 xfer->mutex = xfer_mtx; 270 xfer->priv_sc = priv_sc; 271 xfer->callback = setup->callback; 272 xfer->flags = setup->flags; 273 xfer->max_data_length = setup->bufsize; 274 275 xfer->device = (usb_device)udev->haiku_usb_device; 276 xfer->type = setup->type; 277 278 xfer->pipe = -1; 279 uint8_t endpoint = setup->endpoint; 280 uint8_t iface_index = ifaces[setup->if_index]; 281 if (endpoint == UE_ADDR_ANY) { 282 for (int i = 0; i < udev->endpoints_max; i++) { 283 if (UE_GET_XFERTYPE(udev->endpoints[i].edesc->bmAttributes) != xfer->type) 284 continue; 285 286 endpoint = udev->endpoints[i].edesc->bEndpointAddress; 287 break; 288 } 289 } 290 usb_interface_info* iface = device_config->interface[iface_index].active; 291 for (int i = 0; i < iface->endpoint_count; i++) { 292 if (iface->endpoint[i].descr->endpoint_address != endpoint) 293 continue; 294 295 xfer->pipe = iface->endpoint[i].handle; 296 break; 297 } 298 if (xfer->pipe == -1) 299 panic("failed to locate endpoint!"); 300 301 xfer->nframes = setup->frames; 302 if (xfer->nframes == 0) 303 xfer->nframes = 1; 304 xfer->frames = (iovec*)calloc(xfer->nframes, sizeof(iovec)); 305 306 xfer->usb_state = USB_ST_SETUP; 307 xfer->in_progress = false; 308 xfer->transferred_length = 0; 309 cv_init(&xfer->condition, "FreeBSD USB transfer"); 310 311 if (xfer->flags.proxy_buffer) 312 panic("not yet supported"); 313 314 ppxfer[setup - setup_start] = xfer; 315 } 316 317 return USB_ERR_NORMAL_COMPLETION; 318 } 319 320 321 extern "C" void 322 usbd_transfer_unsetup(struct usb_xfer** pxfer, uint16_t n_setup) 323 { 324 for (int i = 0; i < n_setup; i++) { 325 struct usb_xfer* xfer = pxfer[i]; 326 usbd_transfer_drain(xfer); 327 cv_destroy(&xfer->condition); 328 free(xfer->frames); 329 delete xfer; 330 } 331 } 332 333 334 extern "C" usb_frlength_t 335 usbd_xfer_max_len(struct usb_xfer* xfer) 336 { 337 return xfer->max_data_length; 338 } 339 340 341 extern "C" void* 342 usbd_xfer_softc(struct usb_xfer* xfer) 343 { 344 return xfer->priv_sc; 345 } 346 347 348 extern "C" uint8_t 349 usbd_xfer_state(struct usb_xfer* xfer) 350 { 351 return xfer->usb_state; 352 } 353 354 355 extern "C" void 356 usbd_xfer_set_frame_data(struct usb_xfer* xfer, 357 usb_frcount_t frindex, void* ptr, usb_frlength_t len) 358 { 359 KASSERT(frindex < uint32_t(xfer->nframes), ("frame index overflow")); 360 361 xfer->frames[frindex].iov_base = ptr; 362 xfer->frames[frindex].iov_len = len; 363 } 364 365 366 extern "C" void 367 usbd_xfer_set_stall(struct usb_xfer *xfer) 368 { 369 // Not needed? 370 } 371 372 373 static void 374 usbd_invoker(void* arg, int pending) 375 { 376 struct usb_xfer* xfer = (struct usb_xfer*)arg; 377 mtx_lock(xfer->mutex); 378 xfer->in_progress = false; 379 xfer->usb_state = (xfer->result == B_OK) ? USB_ST_TRANSFERRED : USB_ST_ERROR; 380 xfer->callback(xfer, map_usb_error(xfer->result)); 381 mtx_unlock(xfer->mutex); 382 cv_signal(&xfer->condition); 383 } 384 385 386 static void 387 usbd_callback(void* arg, status_t status, void* data, size_t actualLength) 388 { 389 struct usb_xfer* xfer = (struct usb_xfer*)arg; 390 xfer->result = status; 391 xfer->transferred_length = actualLength; 392 393 TASK_INIT(&xfer->invoker, 0, usbd_invoker, xfer); 394 taskqueue_enqueue(sUSBTaskqueue, &xfer->invoker); 395 } 396 397 398 extern "C" void 399 usbd_transfer_start(struct usb_xfer* xfer) 400 { 401 if (xfer->in_progress) 402 return; 403 404 xfer->usb_state = USB_ST_SETUP; 405 xfer->callback(xfer, USB_ERR_NOT_STARTED); 406 } 407 408 409 extern "C" void 410 usbd_transfer_submit(struct usb_xfer* xfer) 411 { 412 KASSERT(!xfer->in_progress, ("cannot submit in-progress transfer!")); 413 414 xfer->transferred_length = 0; 415 xfer->in_progress = true; 416 status_t status = B_NOT_SUPPORTED; 417 switch (xfer->type) { 418 case UE_BULK: 419 status = sUSB->queue_bulk_v(xfer->pipe, xfer->frames, xfer->nframes, usbd_callback, xfer); 420 break; 421 422 case UE_INTERRUPT: 423 KASSERT(xfer->nframes == 1, ("invalid frame count for interrupt transfer")); 424 status = sUSB->queue_interrupt(xfer->pipe, 425 xfer->frames[0].iov_base, xfer->frames[0].iov_len, 426 usbd_callback, xfer); 427 break; 428 429 default: 430 panic("unhandled pipe type %d", xfer->type); 431 } 432 433 if (status != B_OK) 434 usbd_callback(xfer, status, NULL, 0); 435 } 436 437 438 extern "C" void 439 usbd_transfer_stop(struct usb_xfer* xfer) 440 { 441 if (xfer == NULL) 442 return; 443 mtx_assert(xfer->mutex, MA_OWNED); 444 445 if (!xfer->in_progress) 446 return; 447 448 // Unfortunately we have no way of cancelling just one transfer. 449 sUSB->cancel_queued_transfers(xfer->pipe); 450 } 451 452 453 extern "C" void 454 usbd_transfer_drain(struct usb_xfer* xfer) 455 { 456 if (xfer == NULL) 457 return; 458 459 mtx_lock(xfer->mutex); 460 usbd_transfer_stop(xfer); 461 while (xfer->in_progress) 462 cv_wait(&xfer->condition, xfer->mutex); 463 mtx_unlock(xfer->mutex); 464 } 465 466 467 extern "C" void 468 usbd_xfer_status(struct usb_xfer* xfer, int* actlen, int* sumlen, int* aframes, int* nframes) 469 { 470 if (actlen) 471 *actlen = xfer->transferred_length; 472 if (sumlen) { 473 int sum = 0; 474 for (int i = 0; i < xfer->nframes; i++) 475 sum += xfer->frames[i].iov_len; 476 *sumlen = sum; 477 } 478 if (aframes) { 479 int length = xfer->transferred_length; 480 int frames = 0; 481 for (int i = 0; i < xfer->nframes && length > 0; i++) { 482 length -= xfer->frames[i].iov_len; 483 if (length >= 0) 484 frames++; 485 } 486 *aframes = frames; 487 } 488 if (nframes) 489 *nframes = xfer->nframes; 490 } 491