1df4b8c2aSAndrew Thompson /* $FreeBSD$ */ 2df4b8c2aSAndrew Thompson /*- 3df4b8c2aSAndrew Thompson * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4df4b8c2aSAndrew Thompson * 5df4b8c2aSAndrew Thompson * Redistribution and use in source and binary forms, with or without 6df4b8c2aSAndrew Thompson * modification, are permitted provided that the following conditions 7df4b8c2aSAndrew Thompson * are met: 8df4b8c2aSAndrew Thompson * 1. Redistributions of source code must retain the above copyright 9df4b8c2aSAndrew Thompson * notice, this list of conditions and the following disclaimer. 10df4b8c2aSAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 11df4b8c2aSAndrew Thompson * notice, this list of conditions and the following disclaimer in the 12df4b8c2aSAndrew Thompson * documentation and/or other materials provided with the distribution. 13df4b8c2aSAndrew Thompson * 14df4b8c2aSAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15df4b8c2aSAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16df4b8c2aSAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17df4b8c2aSAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18df4b8c2aSAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19df4b8c2aSAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20df4b8c2aSAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21df4b8c2aSAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22df4b8c2aSAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23df4b8c2aSAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24df4b8c2aSAndrew Thompson * SUCH DAMAGE. 25df4b8c2aSAndrew Thompson */ 26df4b8c2aSAndrew Thompson 27df4b8c2aSAndrew Thompson #include <stdio.h> 28df4b8c2aSAndrew Thompson #include <stdlib.h> 29df4b8c2aSAndrew Thompson #include <string.h> 30df4b8c2aSAndrew Thompson #include <poll.h> 31df4b8c2aSAndrew Thompson #include <ctype.h> 32df4b8c2aSAndrew Thompson #include <sys/queue.h> 33df4b8c2aSAndrew Thompson 34df4b8c2aSAndrew Thompson #include "libusb20.h" 35df4b8c2aSAndrew Thompson #include "libusb20_desc.h" 36df4b8c2aSAndrew Thompson #include "libusb20_int.h" 37df4b8c2aSAndrew Thompson 38df4b8c2aSAndrew Thompson static int 39df4b8c2aSAndrew Thompson dummy_int(void) 40df4b8c2aSAndrew Thompson { 41df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_NOT_SUPPORTED); 42df4b8c2aSAndrew Thompson } 43df4b8c2aSAndrew Thompson 44df4b8c2aSAndrew Thompson static void 45df4b8c2aSAndrew Thompson dummy_void(void) 46df4b8c2aSAndrew Thompson { 47df4b8c2aSAndrew Thompson return; 48df4b8c2aSAndrew Thompson } 49df4b8c2aSAndrew Thompson 50df4b8c2aSAndrew Thompson static void 51df4b8c2aSAndrew Thompson dummy_callback(struct libusb20_transfer *xfer) 52df4b8c2aSAndrew Thompson { 53df4b8c2aSAndrew Thompson ; /* style fix */ 54df4b8c2aSAndrew Thompson switch (libusb20_tr_get_status(xfer)) { 55df4b8c2aSAndrew Thompson case LIBUSB20_TRANSFER_START: 56df4b8c2aSAndrew Thompson libusb20_tr_submit(xfer); 57df4b8c2aSAndrew Thompson break; 58df4b8c2aSAndrew Thompson default: 59df4b8c2aSAndrew Thompson /* complete or error */ 60df4b8c2aSAndrew Thompson break; 61df4b8c2aSAndrew Thompson } 62df4b8c2aSAndrew Thompson return; 63df4b8c2aSAndrew Thompson } 64df4b8c2aSAndrew Thompson 65df4b8c2aSAndrew Thompson #define dummy_get_config_desc_full (void *)dummy_int 66df4b8c2aSAndrew Thompson #define dummy_get_config_index (void *)dummy_int 67df4b8c2aSAndrew Thompson #define dummy_set_config_index (void *)dummy_int 68df4b8c2aSAndrew Thompson #define dummy_set_alt_index (void *)dummy_int 69df4b8c2aSAndrew Thompson #define dummy_reset_device (void *)dummy_int 70df4b8c2aSAndrew Thompson #define dummy_set_power_mode (void *)dummy_int 71df4b8c2aSAndrew Thompson #define dummy_get_power_mode (void *)dummy_int 72df4b8c2aSAndrew Thompson #define dummy_kernel_driver_active (void *)dummy_int 73df4b8c2aSAndrew Thompson #define dummy_detach_kernel_driver (void *)dummy_int 74df4b8c2aSAndrew Thompson #define dummy_do_request_sync (void *)dummy_int 75df4b8c2aSAndrew Thompson #define dummy_tr_open (void *)dummy_int 76df4b8c2aSAndrew Thompson #define dummy_tr_close (void *)dummy_int 77df4b8c2aSAndrew Thompson #define dummy_tr_clear_stall_sync (void *)dummy_int 78df4b8c2aSAndrew Thompson #define dummy_process (void *)dummy_int 79df4b8c2aSAndrew Thompson #define dummy_dev_info (void *)dummy_int 80df4b8c2aSAndrew Thompson #define dummy_dev_get_iface_driver (void *)dummy_int 81df4b8c2aSAndrew Thompson 82df4b8c2aSAndrew Thompson #define dummy_tr_submit (void *)dummy_void 83df4b8c2aSAndrew Thompson #define dummy_tr_cancel_async (void *)dummy_void 84df4b8c2aSAndrew Thompson 85df4b8c2aSAndrew Thompson static const struct libusb20_device_methods libusb20_dummy_methods = { 86df4b8c2aSAndrew Thompson LIBUSB20_DEVICE(LIBUSB20_DECLARE, dummy) 87df4b8c2aSAndrew Thompson }; 88df4b8c2aSAndrew Thompson 89df4b8c2aSAndrew Thompson void 90df4b8c2aSAndrew Thompson libusb20_tr_callback_wrapper(struct libusb20_transfer *xfer) 91df4b8c2aSAndrew Thompson { 92df4b8c2aSAndrew Thompson ; /* style fix */ 93df4b8c2aSAndrew Thompson 94df4b8c2aSAndrew Thompson repeat: 95df4b8c2aSAndrew Thompson 96df4b8c2aSAndrew Thompson if (!xfer->is_pending) { 97df4b8c2aSAndrew Thompson xfer->status = LIBUSB20_TRANSFER_START; 98df4b8c2aSAndrew Thompson } else { 99df4b8c2aSAndrew Thompson xfer->is_pending = 0; 100df4b8c2aSAndrew Thompson } 101df4b8c2aSAndrew Thompson 102df4b8c2aSAndrew Thompson xfer->callback(xfer); 103df4b8c2aSAndrew Thompson 104df4b8c2aSAndrew Thompson if (xfer->is_restart) { 105df4b8c2aSAndrew Thompson xfer->is_restart = 0; 106df4b8c2aSAndrew Thompson goto repeat; 107df4b8c2aSAndrew Thompson } 108df4b8c2aSAndrew Thompson if (xfer->is_draining && 109df4b8c2aSAndrew Thompson (!xfer->is_pending)) { 110df4b8c2aSAndrew Thompson xfer->is_draining = 0; 111df4b8c2aSAndrew Thompson xfer->status = LIBUSB20_TRANSFER_DRAINED; 112df4b8c2aSAndrew Thompson xfer->callback(xfer); 113df4b8c2aSAndrew Thompson } 114df4b8c2aSAndrew Thompson return; 115df4b8c2aSAndrew Thompson } 116df4b8c2aSAndrew Thompson 117df4b8c2aSAndrew Thompson int 118df4b8c2aSAndrew Thompson libusb20_tr_close(struct libusb20_transfer *xfer) 119df4b8c2aSAndrew Thompson { 120df4b8c2aSAndrew Thompson int error; 121df4b8c2aSAndrew Thompson 122df4b8c2aSAndrew Thompson if (!xfer->is_opened) { 123df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_OTHER); 124df4b8c2aSAndrew Thompson } 125df4b8c2aSAndrew Thompson error = xfer->pdev->methods->tr_close(xfer); 126df4b8c2aSAndrew Thompson 127df4b8c2aSAndrew Thompson if (xfer->pLength) { 128df4b8c2aSAndrew Thompson free(xfer->pLength); 129df4b8c2aSAndrew Thompson } 130df4b8c2aSAndrew Thompson if (xfer->ppBuffer) { 131df4b8c2aSAndrew Thompson free(xfer->ppBuffer); 132df4b8c2aSAndrew Thompson } 133df4b8c2aSAndrew Thompson /* clear some fields */ 134df4b8c2aSAndrew Thompson xfer->is_opened = 0; 135df4b8c2aSAndrew Thompson xfer->maxFrames = 0; 136df4b8c2aSAndrew Thompson xfer->maxTotalLength = 0; 137df4b8c2aSAndrew Thompson xfer->maxPacketLen = 0; 138df4b8c2aSAndrew Thompson return (error); 139df4b8c2aSAndrew Thompson } 140df4b8c2aSAndrew Thompson 141df4b8c2aSAndrew Thompson int 142df4b8c2aSAndrew Thompson libusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 143df4b8c2aSAndrew Thompson uint32_t MaxFrameCount, uint8_t ep_no) 144df4b8c2aSAndrew Thompson { 145df4b8c2aSAndrew Thompson uint32_t size; 146df4b8c2aSAndrew Thompson int error; 147df4b8c2aSAndrew Thompson 148df4b8c2aSAndrew Thompson if (xfer->is_opened) { 149df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_BUSY); 150df4b8c2aSAndrew Thompson } 151df4b8c2aSAndrew Thompson if (MaxFrameCount == 0) { 152df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_INVALID_PARAM); 153df4b8c2aSAndrew Thompson } 154df4b8c2aSAndrew Thompson xfer->maxFrames = MaxFrameCount; 155df4b8c2aSAndrew Thompson 156df4b8c2aSAndrew Thompson size = MaxFrameCount * sizeof(xfer->pLength[0]); 157df4b8c2aSAndrew Thompson xfer->pLength = malloc(size); 158df4b8c2aSAndrew Thompson if (xfer->pLength == NULL) { 159df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_NO_MEM); 160df4b8c2aSAndrew Thompson } 161df4b8c2aSAndrew Thompson memset(xfer->pLength, 0, size); 162df4b8c2aSAndrew Thompson 163df4b8c2aSAndrew Thompson size = MaxFrameCount * sizeof(xfer->ppBuffer[0]); 164df4b8c2aSAndrew Thompson xfer->ppBuffer = malloc(size); 165df4b8c2aSAndrew Thompson if (xfer->ppBuffer == NULL) { 166df4b8c2aSAndrew Thompson free(xfer->pLength); 167df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_NO_MEM); 168df4b8c2aSAndrew Thompson } 169df4b8c2aSAndrew Thompson memset(xfer->ppBuffer, 0, size); 170df4b8c2aSAndrew Thompson 171df4b8c2aSAndrew Thompson error = xfer->pdev->methods->tr_open(xfer, MaxBufSize, 172df4b8c2aSAndrew Thompson MaxFrameCount, ep_no); 173df4b8c2aSAndrew Thompson 174df4b8c2aSAndrew Thompson if (error) { 175df4b8c2aSAndrew Thompson free(xfer->ppBuffer); 176df4b8c2aSAndrew Thompson free(xfer->pLength); 177df4b8c2aSAndrew Thompson } else { 178df4b8c2aSAndrew Thompson xfer->is_opened = 1; 179df4b8c2aSAndrew Thompson } 180df4b8c2aSAndrew Thompson return (error); 181df4b8c2aSAndrew Thompson } 182df4b8c2aSAndrew Thompson 183df4b8c2aSAndrew Thompson struct libusb20_transfer * 184df4b8c2aSAndrew Thompson libusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex) 185df4b8c2aSAndrew Thompson { 186df4b8c2aSAndrew Thompson if (trIndex >= pdev->nTransfer) { 187df4b8c2aSAndrew Thompson return (NULL); 188df4b8c2aSAndrew Thompson } 189df4b8c2aSAndrew Thompson return (pdev->pTransfer + trIndex); 190df4b8c2aSAndrew Thompson } 191df4b8c2aSAndrew Thompson 192df4b8c2aSAndrew Thompson uint32_t 193df4b8c2aSAndrew Thompson libusb20_tr_get_actual_frames(struct libusb20_transfer *xfer) 194df4b8c2aSAndrew Thompson { 195df4b8c2aSAndrew Thompson return (xfer->aFrames); 196df4b8c2aSAndrew Thompson } 197df4b8c2aSAndrew Thompson 198df4b8c2aSAndrew Thompson uint16_t 199df4b8c2aSAndrew Thompson libusb20_tr_get_time_complete(struct libusb20_transfer *xfer) 200df4b8c2aSAndrew Thompson { 201df4b8c2aSAndrew Thompson return (xfer->timeComplete); 202df4b8c2aSAndrew Thompson } 203df4b8c2aSAndrew Thompson 204df4b8c2aSAndrew Thompson uint32_t 205df4b8c2aSAndrew Thompson libusb20_tr_get_actual_length(struct libusb20_transfer *xfer) 206df4b8c2aSAndrew Thompson { 207df4b8c2aSAndrew Thompson uint32_t x; 208df4b8c2aSAndrew Thompson uint32_t actlen = 0; 209df4b8c2aSAndrew Thompson 210df4b8c2aSAndrew Thompson for (x = 0; x != xfer->aFrames; x++) { 211df4b8c2aSAndrew Thompson actlen += xfer->pLength[x]; 212df4b8c2aSAndrew Thompson } 213df4b8c2aSAndrew Thompson return (actlen); 214df4b8c2aSAndrew Thompson } 215df4b8c2aSAndrew Thompson 216df4b8c2aSAndrew Thompson uint32_t 217df4b8c2aSAndrew Thompson libusb20_tr_get_max_frames(struct libusb20_transfer *xfer) 218df4b8c2aSAndrew Thompson { 219df4b8c2aSAndrew Thompson return (xfer->maxFrames); 220df4b8c2aSAndrew Thompson } 221df4b8c2aSAndrew Thompson 222df4b8c2aSAndrew Thompson uint32_t 223df4b8c2aSAndrew Thompson libusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer) 224df4b8c2aSAndrew Thompson { 225df4b8c2aSAndrew Thompson /* 226df4b8c2aSAndrew Thompson * Special Case NOTE: If the packet multiplier is non-zero for 227df4b8c2aSAndrew Thompson * High Speed USB, the value returned is equal to 228df4b8c2aSAndrew Thompson * "wMaxPacketSize * multiplier" ! 229df4b8c2aSAndrew Thompson */ 230df4b8c2aSAndrew Thompson return (xfer->maxPacketLen); 231df4b8c2aSAndrew Thompson } 232df4b8c2aSAndrew Thompson 233df4b8c2aSAndrew Thompson uint32_t 234df4b8c2aSAndrew Thompson libusb20_tr_get_max_total_length(struct libusb20_transfer *xfer) 235df4b8c2aSAndrew Thompson { 236df4b8c2aSAndrew Thompson return (xfer->maxTotalLength); 237df4b8c2aSAndrew Thompson } 238df4b8c2aSAndrew Thompson 239df4b8c2aSAndrew Thompson uint8_t 240df4b8c2aSAndrew Thompson libusb20_tr_get_status(struct libusb20_transfer *xfer) 241df4b8c2aSAndrew Thompson { 242df4b8c2aSAndrew Thompson return (xfer->status); 243df4b8c2aSAndrew Thompson } 244df4b8c2aSAndrew Thompson 245df4b8c2aSAndrew Thompson uint8_t 246df4b8c2aSAndrew Thompson libusb20_tr_pending(struct libusb20_transfer *xfer) 247df4b8c2aSAndrew Thompson { 248df4b8c2aSAndrew Thompson return (xfer->is_pending); 249df4b8c2aSAndrew Thompson } 250df4b8c2aSAndrew Thompson 251df4b8c2aSAndrew Thompson void * 252df4b8c2aSAndrew Thompson libusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer) 253df4b8c2aSAndrew Thompson { 254df4b8c2aSAndrew Thompson return (xfer->priv_sc0); 255df4b8c2aSAndrew Thompson } 256df4b8c2aSAndrew Thompson 257df4b8c2aSAndrew Thompson void * 258df4b8c2aSAndrew Thompson libusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer) 259df4b8c2aSAndrew Thompson { 260df4b8c2aSAndrew Thompson return (xfer->priv_sc1); 261df4b8c2aSAndrew Thompson } 262df4b8c2aSAndrew Thompson 263df4b8c2aSAndrew Thompson void 264df4b8c2aSAndrew Thompson libusb20_tr_stop(struct libusb20_transfer *xfer) 265df4b8c2aSAndrew Thompson { 266df4b8c2aSAndrew Thompson if (!xfer->is_pending) { 267df4b8c2aSAndrew Thompson /* transfer not pending */ 268df4b8c2aSAndrew Thompson return; 269df4b8c2aSAndrew Thompson } 270df4b8c2aSAndrew Thompson if (xfer->is_cancel) { 271df4b8c2aSAndrew Thompson /* already cancelling */ 272df4b8c2aSAndrew Thompson return; 273df4b8c2aSAndrew Thompson } 274df4b8c2aSAndrew Thompson xfer->is_cancel = 1; /* we are cancelling */ 275df4b8c2aSAndrew Thompson 276df4b8c2aSAndrew Thompson xfer->pdev->methods->tr_cancel_async(xfer); 277df4b8c2aSAndrew Thompson return; 278df4b8c2aSAndrew Thompson } 279df4b8c2aSAndrew Thompson 280df4b8c2aSAndrew Thompson void 281df4b8c2aSAndrew Thompson libusb20_tr_drain(struct libusb20_transfer *xfer) 282df4b8c2aSAndrew Thompson { 283df4b8c2aSAndrew Thompson /* make sure that we are cancelling */ 284df4b8c2aSAndrew Thompson libusb20_tr_stop(xfer); 285df4b8c2aSAndrew Thompson 286df4b8c2aSAndrew Thompson if (xfer->is_pending) { 287df4b8c2aSAndrew Thompson xfer->is_draining = 1; 288df4b8c2aSAndrew Thompson } 289df4b8c2aSAndrew Thompson return; 290df4b8c2aSAndrew Thompson } 291df4b8c2aSAndrew Thompson 292df4b8c2aSAndrew Thompson void 293df4b8c2aSAndrew Thompson libusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 294df4b8c2aSAndrew Thompson { 295df4b8c2aSAndrew Thompson xfer->pdev->methods->tr_clear_stall_sync(xfer); 296df4b8c2aSAndrew Thompson return; 297df4b8c2aSAndrew Thompson } 298df4b8c2aSAndrew Thompson 299df4b8c2aSAndrew Thompson void 300df4b8c2aSAndrew Thompson libusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex) 301df4b8c2aSAndrew Thompson { 302df4b8c2aSAndrew Thompson xfer->ppBuffer[frIndex] = buffer; 303df4b8c2aSAndrew Thompson return; 304df4b8c2aSAndrew Thompson } 305df4b8c2aSAndrew Thompson 306df4b8c2aSAndrew Thompson void 307df4b8c2aSAndrew Thompson libusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb) 308df4b8c2aSAndrew Thompson { 309df4b8c2aSAndrew Thompson xfer->callback = cb; 310df4b8c2aSAndrew Thompson return; 311df4b8c2aSAndrew Thompson } 312df4b8c2aSAndrew Thompson 313df4b8c2aSAndrew Thompson void 314df4b8c2aSAndrew Thompson libusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags) 315df4b8c2aSAndrew Thompson { 316df4b8c2aSAndrew Thompson xfer->flags = flags; 317df4b8c2aSAndrew Thompson return; 318df4b8c2aSAndrew Thompson } 319df4b8c2aSAndrew Thompson 320545b01adSAndrew Thompson uint32_t 321545b01adSAndrew Thompson libusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex) 322545b01adSAndrew Thompson { 323545b01adSAndrew Thompson return (xfer->pLength[frIndex]); 324545b01adSAndrew Thompson } 325545b01adSAndrew Thompson 326df4b8c2aSAndrew Thompson void 327df4b8c2aSAndrew Thompson libusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex) 328df4b8c2aSAndrew Thompson { 329df4b8c2aSAndrew Thompson xfer->pLength[frIndex] = length; 330df4b8c2aSAndrew Thompson return; 331df4b8c2aSAndrew Thompson } 332df4b8c2aSAndrew Thompson 333df4b8c2aSAndrew Thompson void 334df4b8c2aSAndrew Thompson libusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0) 335df4b8c2aSAndrew Thompson { 336df4b8c2aSAndrew Thompson xfer->priv_sc0 = sc0; 337df4b8c2aSAndrew Thompson return; 338df4b8c2aSAndrew Thompson } 339df4b8c2aSAndrew Thompson 340df4b8c2aSAndrew Thompson void 341df4b8c2aSAndrew Thompson libusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1) 342df4b8c2aSAndrew Thompson { 343df4b8c2aSAndrew Thompson xfer->priv_sc1 = sc1; 344df4b8c2aSAndrew Thompson return; 345df4b8c2aSAndrew Thompson } 346df4b8c2aSAndrew Thompson 347df4b8c2aSAndrew Thompson void 348df4b8c2aSAndrew Thompson libusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout) 349df4b8c2aSAndrew Thompson { 350df4b8c2aSAndrew Thompson xfer->timeout = timeout; 351df4b8c2aSAndrew Thompson return; 352df4b8c2aSAndrew Thompson } 353df4b8c2aSAndrew Thompson 354df4b8c2aSAndrew Thompson void 355df4b8c2aSAndrew Thompson libusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames) 356df4b8c2aSAndrew Thompson { 357df4b8c2aSAndrew Thompson if (nFrames > xfer->maxFrames) { 358df4b8c2aSAndrew Thompson /* should not happen */ 359df4b8c2aSAndrew Thompson nFrames = xfer->maxFrames; 360df4b8c2aSAndrew Thompson } 361df4b8c2aSAndrew Thompson xfer->nFrames = nFrames; 362df4b8c2aSAndrew Thompson return; 363df4b8c2aSAndrew Thompson } 364df4b8c2aSAndrew Thompson 365df4b8c2aSAndrew Thompson void 366df4b8c2aSAndrew Thompson libusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 367df4b8c2aSAndrew Thompson { 368df4b8c2aSAndrew Thompson xfer->ppBuffer[0] = pBuf; 369df4b8c2aSAndrew Thompson xfer->pLength[0] = length; 370df4b8c2aSAndrew Thompson xfer->timeout = timeout; 371df4b8c2aSAndrew Thompson xfer->nFrames = 1; 372df4b8c2aSAndrew Thompson return; 373df4b8c2aSAndrew Thompson } 374df4b8c2aSAndrew Thompson 375df4b8c2aSAndrew Thompson void 376df4b8c2aSAndrew Thompson libusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout) 377df4b8c2aSAndrew Thompson { 378df4b8c2aSAndrew Thompson uint16_t len; 379df4b8c2aSAndrew Thompson 380df4b8c2aSAndrew Thompson xfer->ppBuffer[0] = psetup; 381df4b8c2aSAndrew Thompson xfer->pLength[0] = 8; /* fixed */ 382df4b8c2aSAndrew Thompson xfer->timeout = timeout; 383df4b8c2aSAndrew Thompson 384df4b8c2aSAndrew Thompson len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8); 385df4b8c2aSAndrew Thompson 386df4b8c2aSAndrew Thompson if (len != 0) { 387df4b8c2aSAndrew Thompson xfer->nFrames = 2; 388df4b8c2aSAndrew Thompson xfer->ppBuffer[1] = pBuf; 389df4b8c2aSAndrew Thompson xfer->pLength[1] = len; 390df4b8c2aSAndrew Thompson } else { 391df4b8c2aSAndrew Thompson xfer->nFrames = 1; 392df4b8c2aSAndrew Thompson } 393df4b8c2aSAndrew Thompson return; 394df4b8c2aSAndrew Thompson } 395df4b8c2aSAndrew Thompson 396df4b8c2aSAndrew Thompson void 397df4b8c2aSAndrew Thompson libusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 398df4b8c2aSAndrew Thompson { 399df4b8c2aSAndrew Thompson xfer->ppBuffer[0] = pBuf; 400df4b8c2aSAndrew Thompson xfer->pLength[0] = length; 401df4b8c2aSAndrew Thompson xfer->timeout = timeout; 402df4b8c2aSAndrew Thompson xfer->nFrames = 1; 403df4b8c2aSAndrew Thompson return; 404df4b8c2aSAndrew Thompson } 405df4b8c2aSAndrew Thompson 406df4b8c2aSAndrew Thompson void 407df4b8c2aSAndrew Thompson libusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex) 408df4b8c2aSAndrew Thompson { 409df4b8c2aSAndrew Thompson if (frIndex >= xfer->maxFrames) { 410df4b8c2aSAndrew Thompson /* should not happen */ 411df4b8c2aSAndrew Thompson return; 412df4b8c2aSAndrew Thompson } 413df4b8c2aSAndrew Thompson xfer->ppBuffer[frIndex] = pBuf; 414df4b8c2aSAndrew Thompson xfer->pLength[frIndex] = length; 415df4b8c2aSAndrew Thompson return; 416df4b8c2aSAndrew Thompson } 417df4b8c2aSAndrew Thompson 418df4b8c2aSAndrew Thompson void 419df4b8c2aSAndrew Thompson libusb20_tr_submit(struct libusb20_transfer *xfer) 420df4b8c2aSAndrew Thompson { 421df4b8c2aSAndrew Thompson if (xfer->is_pending) { 422df4b8c2aSAndrew Thompson /* should not happen */ 423df4b8c2aSAndrew Thompson return; 424df4b8c2aSAndrew Thompson } 425df4b8c2aSAndrew Thompson xfer->is_pending = 1; /* we are pending */ 426df4b8c2aSAndrew Thompson xfer->is_cancel = 0; /* not cancelling */ 427df4b8c2aSAndrew Thompson xfer->is_restart = 0; /* not restarting */ 428df4b8c2aSAndrew Thompson 429df4b8c2aSAndrew Thompson xfer->pdev->methods->tr_submit(xfer); 430df4b8c2aSAndrew Thompson return; 431df4b8c2aSAndrew Thompson } 432df4b8c2aSAndrew Thompson 433df4b8c2aSAndrew Thompson void 434df4b8c2aSAndrew Thompson libusb20_tr_start(struct libusb20_transfer *xfer) 435df4b8c2aSAndrew Thompson { 436df4b8c2aSAndrew Thompson if (xfer->is_pending) { 437df4b8c2aSAndrew Thompson if (xfer->is_cancel) { 438df4b8c2aSAndrew Thompson /* cancelling - restart */ 439df4b8c2aSAndrew Thompson xfer->is_restart = 1; 440df4b8c2aSAndrew Thompson } 441df4b8c2aSAndrew Thompson /* transfer not pending */ 442df4b8c2aSAndrew Thompson return; 443df4b8c2aSAndrew Thompson } 444df4b8c2aSAndrew Thompson /* get into the callback */ 445df4b8c2aSAndrew Thompson libusb20_tr_callback_wrapper(xfer); 446df4b8c2aSAndrew Thompson return; 447df4b8c2aSAndrew Thompson } 448df4b8c2aSAndrew Thompson 449df4b8c2aSAndrew Thompson /* USB device operations */ 450df4b8c2aSAndrew Thompson 451df4b8c2aSAndrew Thompson int 452df4b8c2aSAndrew Thompson libusb20_dev_close(struct libusb20_device *pdev) 453df4b8c2aSAndrew Thompson { 454df4b8c2aSAndrew Thompson struct libusb20_transfer *xfer; 455df4b8c2aSAndrew Thompson uint16_t x; 456df4b8c2aSAndrew Thompson int error = 0; 457df4b8c2aSAndrew Thompson 458df4b8c2aSAndrew Thompson if (!pdev->is_opened) { 459df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_OTHER); 460df4b8c2aSAndrew Thompson } 461df4b8c2aSAndrew Thompson for (x = 0; x != pdev->nTransfer; x++) { 462df4b8c2aSAndrew Thompson xfer = pdev->pTransfer + x; 463df4b8c2aSAndrew Thompson 464df4b8c2aSAndrew Thompson libusb20_tr_drain(xfer); 465df4b8c2aSAndrew Thompson } 466df4b8c2aSAndrew Thompson 467df4b8c2aSAndrew Thompson if (pdev->pTransfer != NULL) { 468df4b8c2aSAndrew Thompson free(pdev->pTransfer); 469df4b8c2aSAndrew Thompson pdev->pTransfer = NULL; 470df4b8c2aSAndrew Thompson } 471df4b8c2aSAndrew Thompson error = pdev->beMethods->close_device(pdev); 472df4b8c2aSAndrew Thompson 473df4b8c2aSAndrew Thompson pdev->methods = &libusb20_dummy_methods; 474df4b8c2aSAndrew Thompson 475df4b8c2aSAndrew Thompson pdev->is_opened = 0; 476df4b8c2aSAndrew Thompson 4774315b3c9SAndrew Thompson /* 4784315b3c9SAndrew Thompson * The following variable is only used by the libusb v0.1 4794315b3c9SAndrew Thompson * compat layer: 4804315b3c9SAndrew Thompson */ 4814315b3c9SAndrew Thompson pdev->claimed_interface = 0; 482df4b8c2aSAndrew Thompson 483df4b8c2aSAndrew Thompson return (error); 484df4b8c2aSAndrew Thompson } 485df4b8c2aSAndrew Thompson 486df4b8c2aSAndrew Thompson int 487df4b8c2aSAndrew Thompson libusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex) 488df4b8c2aSAndrew Thompson { 489df4b8c2aSAndrew Thompson int error; 490df4b8c2aSAndrew Thompson 491df4b8c2aSAndrew Thompson error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex); 492df4b8c2aSAndrew Thompson return (error); 493df4b8c2aSAndrew Thompson } 494df4b8c2aSAndrew Thompson 495df4b8c2aSAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED * 496df4b8c2aSAndrew Thompson libusb20_dev_get_device_desc(struct libusb20_device *pdev) 497df4b8c2aSAndrew Thompson { 498df4b8c2aSAndrew Thompson return (&(pdev->ddesc)); 499df4b8c2aSAndrew Thompson } 500df4b8c2aSAndrew Thompson 501df4b8c2aSAndrew Thompson int 502df4b8c2aSAndrew Thompson libusb20_dev_get_fd(struct libusb20_device *pdev) 503df4b8c2aSAndrew Thompson { 504df4b8c2aSAndrew Thompson return (pdev->file); 505df4b8c2aSAndrew Thompson } 506df4b8c2aSAndrew Thompson 507df4b8c2aSAndrew Thompson int 508df4b8c2aSAndrew Thompson libusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex) 509df4b8c2aSAndrew Thompson { 510df4b8c2aSAndrew Thompson int error; 511df4b8c2aSAndrew Thompson 512df4b8c2aSAndrew Thompson error = pdev->methods->kernel_driver_active(pdev, ifaceIndex); 513df4b8c2aSAndrew Thompson return (error); 514df4b8c2aSAndrew Thompson } 515df4b8c2aSAndrew Thompson 516df4b8c2aSAndrew Thompson int 517df4b8c2aSAndrew Thompson libusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax) 518df4b8c2aSAndrew Thompson { 519df4b8c2aSAndrew Thompson struct libusb20_transfer *xfer; 520df4b8c2aSAndrew Thompson uint32_t size; 521df4b8c2aSAndrew Thompson uint16_t x; 522df4b8c2aSAndrew Thompson int error; 523df4b8c2aSAndrew Thompson 524df4b8c2aSAndrew Thompson if (pdev->is_opened) { 525df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_BUSY); 526df4b8c2aSAndrew Thompson } 527df4b8c2aSAndrew Thompson if (nTransferMax >= 256) { 528df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_INVALID_PARAM); 529df4b8c2aSAndrew Thompson } else if (nTransferMax != 0) { 530df4b8c2aSAndrew Thompson size = sizeof(pdev->pTransfer[0]) * nTransferMax; 531df4b8c2aSAndrew Thompson pdev->pTransfer = malloc(size); 532df4b8c2aSAndrew Thompson if (pdev->pTransfer == NULL) { 533df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_NO_MEM); 534df4b8c2aSAndrew Thompson } 535df4b8c2aSAndrew Thompson memset(pdev->pTransfer, 0, size); 536df4b8c2aSAndrew Thompson } 537df4b8c2aSAndrew Thompson /* initialise all transfers */ 538df4b8c2aSAndrew Thompson for (x = 0; x != nTransferMax; x++) { 539df4b8c2aSAndrew Thompson 540df4b8c2aSAndrew Thompson xfer = pdev->pTransfer + x; 541df4b8c2aSAndrew Thompson 542df4b8c2aSAndrew Thompson xfer->pdev = pdev; 543df4b8c2aSAndrew Thompson xfer->trIndex = x; 544df4b8c2aSAndrew Thompson xfer->callback = &dummy_callback; 545df4b8c2aSAndrew Thompson } 546df4b8c2aSAndrew Thompson 547df4b8c2aSAndrew Thompson /* set "nTransfer" early */ 548df4b8c2aSAndrew Thompson pdev->nTransfer = nTransferMax; 549df4b8c2aSAndrew Thompson 550df4b8c2aSAndrew Thompson error = pdev->beMethods->open_device(pdev, nTransferMax); 551df4b8c2aSAndrew Thompson 552df4b8c2aSAndrew Thompson if (error) { 553df4b8c2aSAndrew Thompson if (pdev->pTransfer != NULL) { 554df4b8c2aSAndrew Thompson free(pdev->pTransfer); 555df4b8c2aSAndrew Thompson pdev->pTransfer = NULL; 556df4b8c2aSAndrew Thompson } 557df4b8c2aSAndrew Thompson pdev->file = -1; 558df4b8c2aSAndrew Thompson pdev->file_ctrl = -1; 559df4b8c2aSAndrew Thompson pdev->nTransfer = 0; 560df4b8c2aSAndrew Thompson } else { 561df4b8c2aSAndrew Thompson pdev->is_opened = 1; 562df4b8c2aSAndrew Thompson } 563df4b8c2aSAndrew Thompson return (error); 564df4b8c2aSAndrew Thompson } 565df4b8c2aSAndrew Thompson 566df4b8c2aSAndrew Thompson int 567df4b8c2aSAndrew Thompson libusb20_dev_reset(struct libusb20_device *pdev) 568df4b8c2aSAndrew Thompson { 569df4b8c2aSAndrew Thompson int error; 570df4b8c2aSAndrew Thompson 571df4b8c2aSAndrew Thompson error = pdev->methods->reset_device(pdev); 572df4b8c2aSAndrew Thompson return (error); 573df4b8c2aSAndrew Thompson } 574df4b8c2aSAndrew Thompson 575df4b8c2aSAndrew Thompson int 576df4b8c2aSAndrew Thompson libusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 577df4b8c2aSAndrew Thompson { 578df4b8c2aSAndrew Thompson int error; 579df4b8c2aSAndrew Thompson 580df4b8c2aSAndrew Thompson error = pdev->methods->set_power_mode(pdev, power_mode); 581df4b8c2aSAndrew Thompson return (error); 582df4b8c2aSAndrew Thompson } 583df4b8c2aSAndrew Thompson 584df4b8c2aSAndrew Thompson uint8_t 585df4b8c2aSAndrew Thompson libusb20_dev_get_power_mode(struct libusb20_device *pdev) 586df4b8c2aSAndrew Thompson { 587df4b8c2aSAndrew Thompson int error; 588df4b8c2aSAndrew Thompson uint8_t power_mode; 589df4b8c2aSAndrew Thompson 590df4b8c2aSAndrew Thompson error = pdev->methods->get_power_mode(pdev, &power_mode); 591df4b8c2aSAndrew Thompson if (error) 592df4b8c2aSAndrew Thompson power_mode = LIBUSB20_POWER_ON; /* fake power mode */ 593df4b8c2aSAndrew Thompson return (power_mode); 594df4b8c2aSAndrew Thompson } 595df4b8c2aSAndrew Thompson 596df4b8c2aSAndrew Thompson int 597df4b8c2aSAndrew Thompson libusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex) 598df4b8c2aSAndrew Thompson { 599df4b8c2aSAndrew Thompson int error; 600df4b8c2aSAndrew Thompson 601df4b8c2aSAndrew Thompson error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex); 602df4b8c2aSAndrew Thompson return (error); 603df4b8c2aSAndrew Thompson } 604df4b8c2aSAndrew Thompson 605df4b8c2aSAndrew Thompson int 606df4b8c2aSAndrew Thompson libusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex) 607df4b8c2aSAndrew Thompson { 608df4b8c2aSAndrew Thompson int error; 609df4b8c2aSAndrew Thompson 610df4b8c2aSAndrew Thompson error = pdev->methods->set_config_index(pdev, configIndex); 611df4b8c2aSAndrew Thompson return (error); 612df4b8c2aSAndrew Thompson } 613df4b8c2aSAndrew Thompson 614df4b8c2aSAndrew Thompson int 615df4b8c2aSAndrew Thompson libusb20_dev_request_sync(struct libusb20_device *pdev, 616df4b8c2aSAndrew Thompson struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data, 617df4b8c2aSAndrew Thompson uint16_t *pactlen, uint32_t timeout, uint8_t flags) 618df4b8c2aSAndrew Thompson { 619df4b8c2aSAndrew Thompson int error; 620df4b8c2aSAndrew Thompson 621df4b8c2aSAndrew Thompson error = pdev->methods->do_request_sync(pdev, 622df4b8c2aSAndrew Thompson setup, data, pactlen, timeout, flags); 623df4b8c2aSAndrew Thompson return (error); 624df4b8c2aSAndrew Thompson } 625df4b8c2aSAndrew Thompson 626df4b8c2aSAndrew Thompson int 627df4b8c2aSAndrew Thompson libusb20_dev_req_string_sync(struct libusb20_device *pdev, 628df4b8c2aSAndrew Thompson uint8_t str_index, uint16_t langid, void *ptr, uint16_t len) 629df4b8c2aSAndrew Thompson { 630df4b8c2aSAndrew Thompson struct LIBUSB20_CONTROL_SETUP_DECODED req; 631df4b8c2aSAndrew Thompson int error; 632df4b8c2aSAndrew Thompson 633df4b8c2aSAndrew Thompson if (len < 4) { 634df4b8c2aSAndrew Thompson /* invalid length */ 635df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_INVALID_PARAM); 636df4b8c2aSAndrew Thompson } 637df4b8c2aSAndrew Thompson LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req); 638df4b8c2aSAndrew Thompson 639df4b8c2aSAndrew Thompson /* 640df4b8c2aSAndrew Thompson * We need to read the USB string in two steps else some USB 641df4b8c2aSAndrew Thompson * devices will complain. 642df4b8c2aSAndrew Thompson */ 643df4b8c2aSAndrew Thompson req.bmRequestType = 644df4b8c2aSAndrew Thompson LIBUSB20_REQUEST_TYPE_STANDARD | 645df4b8c2aSAndrew Thompson LIBUSB20_RECIPIENT_DEVICE | 646df4b8c2aSAndrew Thompson LIBUSB20_ENDPOINT_IN; 647df4b8c2aSAndrew Thompson req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR; 648df4b8c2aSAndrew Thompson req.wValue = (LIBUSB20_DT_STRING << 8) | str_index; 649df4b8c2aSAndrew Thompson req.wIndex = langid; 650df4b8c2aSAndrew Thompson req.wLength = 4; /* bytes */ 651df4b8c2aSAndrew Thompson 652df4b8c2aSAndrew Thompson error = libusb20_dev_request_sync(pdev, &req, 653df4b8c2aSAndrew Thompson ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 654df4b8c2aSAndrew Thompson if (error) { 655df4b8c2aSAndrew Thompson return (error); 656df4b8c2aSAndrew Thompson } 657df4b8c2aSAndrew Thompson req.wLength = *(uint8_t *)ptr; /* bytes */ 658df4b8c2aSAndrew Thompson if (req.wLength > len) { 659df4b8c2aSAndrew Thompson /* partial string read */ 660df4b8c2aSAndrew Thompson req.wLength = len; 661df4b8c2aSAndrew Thompson } 662df4b8c2aSAndrew Thompson error = libusb20_dev_request_sync(pdev, &req, 663df4b8c2aSAndrew Thompson ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 664df4b8c2aSAndrew Thompson 665df4b8c2aSAndrew Thompson if (error) { 666df4b8c2aSAndrew Thompson return (error); 667df4b8c2aSAndrew Thompson } 668df4b8c2aSAndrew Thompson if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) { 669df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_OTHER); 670df4b8c2aSAndrew Thompson } 671df4b8c2aSAndrew Thompson return (0); /* success */ 672df4b8c2aSAndrew Thompson } 673df4b8c2aSAndrew Thompson 674df4b8c2aSAndrew Thompson int 675df4b8c2aSAndrew Thompson libusb20_dev_req_string_simple_sync(struct libusb20_device *pdev, 676df4b8c2aSAndrew Thompson uint8_t str_index, void *ptr, uint16_t len) 677df4b8c2aSAndrew Thompson { 678df4b8c2aSAndrew Thompson char *buf; 679df4b8c2aSAndrew Thompson int error; 680df4b8c2aSAndrew Thompson uint16_t langid; 681df4b8c2aSAndrew Thompson uint16_t n; 682df4b8c2aSAndrew Thompson uint16_t i; 683df4b8c2aSAndrew Thompson uint16_t c; 684df4b8c2aSAndrew Thompson uint8_t temp[255]; 685df4b8c2aSAndrew Thompson uint8_t swap; 686df4b8c2aSAndrew Thompson 687df4b8c2aSAndrew Thompson /* the following code derives from the FreeBSD USB kernel */ 688df4b8c2aSAndrew Thompson 689df4b8c2aSAndrew Thompson if ((len < 1) || (ptr == NULL)) { 690df4b8c2aSAndrew Thompson /* too short buffer */ 691df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_INVALID_PARAM); 692df4b8c2aSAndrew Thompson } 693df4b8c2aSAndrew Thompson error = libusb20_dev_req_string_sync(pdev, 694df4b8c2aSAndrew Thompson 0, 0, temp, sizeof(temp)); 695df4b8c2aSAndrew Thompson if (error < 0) { 696df4b8c2aSAndrew Thompson *(uint8_t *)ptr = 0; /* zero terminate */ 697df4b8c2aSAndrew Thompson return (error); 698df4b8c2aSAndrew Thompson } 699df4b8c2aSAndrew Thompson langid = temp[2] | (temp[3] << 8); 700df4b8c2aSAndrew Thompson 701df4b8c2aSAndrew Thompson error = libusb20_dev_req_string_sync(pdev, str_index, 702df4b8c2aSAndrew Thompson langid, temp, sizeof(temp)); 703df4b8c2aSAndrew Thompson if (error < 0) { 704df4b8c2aSAndrew Thompson *(uint8_t *)ptr = 0; /* zero terminate */ 705df4b8c2aSAndrew Thompson return (error); 706df4b8c2aSAndrew Thompson } 707df4b8c2aSAndrew Thompson if (temp[0] < 2) { 708df4b8c2aSAndrew Thompson /* string length is too short */ 709df4b8c2aSAndrew Thompson *(uint8_t *)ptr = 0; /* zero terminate */ 710df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_OTHER); 711df4b8c2aSAndrew Thompson } 712df4b8c2aSAndrew Thompson /* reserve one byte for terminating zero */ 713df4b8c2aSAndrew Thompson len--; 714df4b8c2aSAndrew Thompson 715df4b8c2aSAndrew Thompson /* find maximum length */ 716df4b8c2aSAndrew Thompson n = (temp[0] / 2) - 1; 717df4b8c2aSAndrew Thompson if (n > len) { 718df4b8c2aSAndrew Thompson n = len; 719df4b8c2aSAndrew Thompson } 720df4b8c2aSAndrew Thompson /* reset swap state */ 721df4b8c2aSAndrew Thompson swap = 3; 722df4b8c2aSAndrew Thompson 723df4b8c2aSAndrew Thompson /* setup output buffer pointer */ 724df4b8c2aSAndrew Thompson buf = ptr; 725df4b8c2aSAndrew Thompson 726df4b8c2aSAndrew Thompson /* convert and filter */ 727df4b8c2aSAndrew Thompson for (i = 0; (i != n); i++) { 728df4b8c2aSAndrew Thompson c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8); 729df4b8c2aSAndrew Thompson 730df4b8c2aSAndrew Thompson /* convert from Unicode, handle buggy strings */ 731df4b8c2aSAndrew Thompson if (((c & 0xff00) == 0) && (swap & 1)) { 732df4b8c2aSAndrew Thompson /* Little Endian, default */ 733df4b8c2aSAndrew Thompson *buf = c; 734df4b8c2aSAndrew Thompson swap = 1; 735df4b8c2aSAndrew Thompson } else if (((c & 0x00ff) == 0) && (swap & 2)) { 736df4b8c2aSAndrew Thompson /* Big Endian */ 737df4b8c2aSAndrew Thompson *buf = c >> 8; 738df4b8c2aSAndrew Thompson swap = 2; 739df4b8c2aSAndrew Thompson } else { 740df4b8c2aSAndrew Thompson /* skip invalid character */ 741df4b8c2aSAndrew Thompson continue; 742df4b8c2aSAndrew Thompson } 743df4b8c2aSAndrew Thompson /* 744df4b8c2aSAndrew Thompson * Filter by default - we don't allow greater and less than 745df4b8c2aSAndrew Thompson * signs because they might confuse the dmesg printouts! 746df4b8c2aSAndrew Thompson */ 747df4b8c2aSAndrew Thompson if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) { 748df4b8c2aSAndrew Thompson /* skip invalid character */ 749df4b8c2aSAndrew Thompson continue; 750df4b8c2aSAndrew Thompson } 751df4b8c2aSAndrew Thompson buf++; 752df4b8c2aSAndrew Thompson } 753df4b8c2aSAndrew Thompson *buf = 0; /* zero terminate string */ 754df4b8c2aSAndrew Thompson 755df4b8c2aSAndrew Thompson return (0); 756df4b8c2aSAndrew Thompson } 757df4b8c2aSAndrew Thompson 758df4b8c2aSAndrew Thompson struct libusb20_config * 759df4b8c2aSAndrew Thompson libusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex) 760df4b8c2aSAndrew Thompson { 761df4b8c2aSAndrew Thompson struct libusb20_config *retval = NULL; 762df4b8c2aSAndrew Thompson uint8_t *ptr; 763df4b8c2aSAndrew Thompson uint16_t len; 764df4b8c2aSAndrew Thompson uint8_t do_close; 765df4b8c2aSAndrew Thompson int error; 766df4b8c2aSAndrew Thompson 767df4b8c2aSAndrew Thompson if (!pdev->is_opened) { 768df4b8c2aSAndrew Thompson error = libusb20_dev_open(pdev, 0); 769df4b8c2aSAndrew Thompson if (error) { 770df4b8c2aSAndrew Thompson return (NULL); 771df4b8c2aSAndrew Thompson } 772df4b8c2aSAndrew Thompson do_close = 1; 773df4b8c2aSAndrew Thompson } else { 774df4b8c2aSAndrew Thompson do_close = 0; 775df4b8c2aSAndrew Thompson } 776df4b8c2aSAndrew Thompson error = pdev->methods->get_config_desc_full(pdev, 777df4b8c2aSAndrew Thompson &ptr, &len, configIndex); 778df4b8c2aSAndrew Thompson 779df4b8c2aSAndrew Thompson if (error) { 780df4b8c2aSAndrew Thompson goto done; 781df4b8c2aSAndrew Thompson } 782df4b8c2aSAndrew Thompson /* parse new config descriptor */ 783df4b8c2aSAndrew Thompson retval = libusb20_parse_config_desc(ptr); 784df4b8c2aSAndrew Thompson 785df4b8c2aSAndrew Thompson /* free config descriptor */ 786df4b8c2aSAndrew Thompson free(ptr); 787df4b8c2aSAndrew Thompson 788df4b8c2aSAndrew Thompson done: 789df4b8c2aSAndrew Thompson if (do_close) { 790df4b8c2aSAndrew Thompson error = libusb20_dev_close(pdev); 791df4b8c2aSAndrew Thompson } 792df4b8c2aSAndrew Thompson return (retval); 793df4b8c2aSAndrew Thompson } 794df4b8c2aSAndrew Thompson 795df4b8c2aSAndrew Thompson struct libusb20_device * 796df4b8c2aSAndrew Thompson libusb20_dev_alloc(void) 797df4b8c2aSAndrew Thompson { 798df4b8c2aSAndrew Thompson struct libusb20_device *pdev; 799df4b8c2aSAndrew Thompson 800df4b8c2aSAndrew Thompson pdev = malloc(sizeof(*pdev)); 801df4b8c2aSAndrew Thompson if (pdev == NULL) { 802df4b8c2aSAndrew Thompson return (NULL); 803df4b8c2aSAndrew Thompson } 804df4b8c2aSAndrew Thompson memset(pdev, 0, sizeof(*pdev)); 805df4b8c2aSAndrew Thompson 806df4b8c2aSAndrew Thompson pdev->file = -1; 807df4b8c2aSAndrew Thompson pdev->file_ctrl = -1; 808df4b8c2aSAndrew Thompson pdev->methods = &libusb20_dummy_methods; 809df4b8c2aSAndrew Thompson return (pdev); 810df4b8c2aSAndrew Thompson } 811df4b8c2aSAndrew Thompson 812df4b8c2aSAndrew Thompson uint8_t 813df4b8c2aSAndrew Thompson libusb20_dev_get_config_index(struct libusb20_device *pdev) 814df4b8c2aSAndrew Thompson { 815df4b8c2aSAndrew Thompson int error; 816df4b8c2aSAndrew Thompson uint8_t cfg_index; 817df4b8c2aSAndrew Thompson uint8_t do_close; 818df4b8c2aSAndrew Thompson 819df4b8c2aSAndrew Thompson if (!pdev->is_opened) { 820df4b8c2aSAndrew Thompson error = libusb20_dev_open(pdev, 0); 821df4b8c2aSAndrew Thompson if (error == 0) { 822df4b8c2aSAndrew Thompson do_close = 1; 823df4b8c2aSAndrew Thompson } else { 824df4b8c2aSAndrew Thompson do_close = 0; 825df4b8c2aSAndrew Thompson } 826df4b8c2aSAndrew Thompson } else { 827df4b8c2aSAndrew Thompson do_close = 0; 828df4b8c2aSAndrew Thompson } 829df4b8c2aSAndrew Thompson 830df4b8c2aSAndrew Thompson error = pdev->methods->get_config_index(pdev, &cfg_index); 831df4b8c2aSAndrew Thompson if (error) { 832df4b8c2aSAndrew Thompson cfg_index = 0 - 1; /* current config index */ 833df4b8c2aSAndrew Thompson } 834df4b8c2aSAndrew Thompson if (do_close) { 835df4b8c2aSAndrew Thompson if (libusb20_dev_close(pdev)) { 836df4b8c2aSAndrew Thompson /* ignore */ 837df4b8c2aSAndrew Thompson } 838df4b8c2aSAndrew Thompson } 839df4b8c2aSAndrew Thompson return (cfg_index); 840df4b8c2aSAndrew Thompson } 841df4b8c2aSAndrew Thompson 842df4b8c2aSAndrew Thompson uint8_t 843df4b8c2aSAndrew Thompson libusb20_dev_get_mode(struct libusb20_device *pdev) 844df4b8c2aSAndrew Thompson { 845df4b8c2aSAndrew Thompson return (pdev->usb_mode); 846df4b8c2aSAndrew Thompson } 847df4b8c2aSAndrew Thompson 848df4b8c2aSAndrew Thompson uint8_t 849df4b8c2aSAndrew Thompson libusb20_dev_get_speed(struct libusb20_device *pdev) 850df4b8c2aSAndrew Thompson { 851df4b8c2aSAndrew Thompson return (pdev->usb_speed); 852df4b8c2aSAndrew Thompson } 853df4b8c2aSAndrew Thompson 854df4b8c2aSAndrew Thompson /* if this function returns an error, the device is gone */ 855df4b8c2aSAndrew Thompson int 856df4b8c2aSAndrew Thompson libusb20_dev_process(struct libusb20_device *pdev) 857df4b8c2aSAndrew Thompson { 858df4b8c2aSAndrew Thompson int error; 859df4b8c2aSAndrew Thompson 860df4b8c2aSAndrew Thompson error = pdev->methods->process(pdev); 861df4b8c2aSAndrew Thompson return (error); 862df4b8c2aSAndrew Thompson } 863df4b8c2aSAndrew Thompson 864df4b8c2aSAndrew Thompson void 865df4b8c2aSAndrew Thompson libusb20_dev_wait_process(struct libusb20_device *pdev, int timeout) 866df4b8c2aSAndrew Thompson { 867df4b8c2aSAndrew Thompson struct pollfd pfd[1]; 868df4b8c2aSAndrew Thompson 869df4b8c2aSAndrew Thompson if (!pdev->is_opened) { 870df4b8c2aSAndrew Thompson return; 871df4b8c2aSAndrew Thompson } 872df4b8c2aSAndrew Thompson pfd[0].fd = pdev->file; 873df4b8c2aSAndrew Thompson pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 874df4b8c2aSAndrew Thompson pfd[0].revents = 0; 875df4b8c2aSAndrew Thompson 876df4b8c2aSAndrew Thompson if (poll(pfd, 1, timeout)) { 877df4b8c2aSAndrew Thompson /* ignore any error */ 878df4b8c2aSAndrew Thompson } 879df4b8c2aSAndrew Thompson return; 880df4b8c2aSAndrew Thompson } 881df4b8c2aSAndrew Thompson 882df4b8c2aSAndrew Thompson void 883df4b8c2aSAndrew Thompson libusb20_dev_free(struct libusb20_device *pdev) 884df4b8c2aSAndrew Thompson { 885df4b8c2aSAndrew Thompson if (pdev == NULL) { 886df4b8c2aSAndrew Thompson /* be NULL safe */ 887df4b8c2aSAndrew Thompson return; 888df4b8c2aSAndrew Thompson } 889df4b8c2aSAndrew Thompson if (pdev->is_opened) { 890df4b8c2aSAndrew Thompson if (libusb20_dev_close(pdev)) { 891df4b8c2aSAndrew Thompson /* ignore any errors */ 892df4b8c2aSAndrew Thompson } 893df4b8c2aSAndrew Thompson } 894df4b8c2aSAndrew Thompson free(pdev); 895df4b8c2aSAndrew Thompson return; 896df4b8c2aSAndrew Thompson } 897df4b8c2aSAndrew Thompson 898df4b8c2aSAndrew Thompson int 899df4b8c2aSAndrew Thompson libusb20_dev_get_info(struct libusb20_device *pdev, 900760bc48eSAndrew Thompson struct usb_device_info *pinfo) 901df4b8c2aSAndrew Thompson { 902df4b8c2aSAndrew Thompson if (pinfo == NULL) 903df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_INVALID_PARAM); 904df4b8c2aSAndrew Thompson 905df4b8c2aSAndrew Thompson return (pdev->beMethods->dev_get_info(pdev, pinfo)); 906df4b8c2aSAndrew Thompson } 907df4b8c2aSAndrew Thompson 908df4b8c2aSAndrew Thompson const char * 909df4b8c2aSAndrew Thompson libusb20_dev_get_backend_name(struct libusb20_device *pdev) 910df4b8c2aSAndrew Thompson { 911df4b8c2aSAndrew Thompson return (pdev->beMethods->get_backend_name()); 912df4b8c2aSAndrew Thompson } 913df4b8c2aSAndrew Thompson 914df4b8c2aSAndrew Thompson const char * 915df4b8c2aSAndrew Thompson libusb20_dev_get_desc(struct libusb20_device *pdev) 916df4b8c2aSAndrew Thompson { 917df4b8c2aSAndrew Thompson return (pdev->usb_desc); 918df4b8c2aSAndrew Thompson } 919df4b8c2aSAndrew Thompson 920df4b8c2aSAndrew Thompson void 921df4b8c2aSAndrew Thompson libusb20_dev_set_debug(struct libusb20_device *pdev, int debug) 922df4b8c2aSAndrew Thompson { 923df4b8c2aSAndrew Thompson pdev->debug = debug; 924df4b8c2aSAndrew Thompson return; 925df4b8c2aSAndrew Thompson } 926df4b8c2aSAndrew Thompson 927df4b8c2aSAndrew Thompson int 928df4b8c2aSAndrew Thompson libusb20_dev_get_debug(struct libusb20_device *pdev) 929df4b8c2aSAndrew Thompson { 930df4b8c2aSAndrew Thompson return (pdev->debug); 931df4b8c2aSAndrew Thompson } 932df4b8c2aSAndrew Thompson 933df4b8c2aSAndrew Thompson uint8_t 934df4b8c2aSAndrew Thompson libusb20_dev_get_address(struct libusb20_device *pdev) 935df4b8c2aSAndrew Thompson { 936df4b8c2aSAndrew Thompson return (pdev->device_address); 937df4b8c2aSAndrew Thompson } 938df4b8c2aSAndrew Thompson 939df4b8c2aSAndrew Thompson uint8_t 940df4b8c2aSAndrew Thompson libusb20_dev_get_bus_number(struct libusb20_device *pdev) 941df4b8c2aSAndrew Thompson { 942df4b8c2aSAndrew Thompson return (pdev->bus_number); 943df4b8c2aSAndrew Thompson } 944df4b8c2aSAndrew Thompson 945df4b8c2aSAndrew Thompson int 946df4b8c2aSAndrew Thompson libusb20_dev_get_iface_desc(struct libusb20_device *pdev, 947df4b8c2aSAndrew Thompson uint8_t iface_index, char *buf, uint8_t len) 948df4b8c2aSAndrew Thompson { 949df4b8c2aSAndrew Thompson if ((buf == NULL) || (len == 0)) 950df4b8c2aSAndrew Thompson return (LIBUSB20_ERROR_INVALID_PARAM); 951df4b8c2aSAndrew Thompson 952df4b8c2aSAndrew Thompson return (pdev->beMethods->dev_get_iface_desc( 953df4b8c2aSAndrew Thompson pdev, iface_index, buf, len)); 954df4b8c2aSAndrew Thompson } 955df4b8c2aSAndrew Thompson 956df4b8c2aSAndrew Thompson /* USB backend operations */ 957df4b8c2aSAndrew Thompson 958df4b8c2aSAndrew Thompson int 959df4b8c2aSAndrew Thompson libusb20_be_get_dev_quirk(struct libusb20_backend *pbe, 960df4b8c2aSAndrew Thompson uint16_t quirk_index, struct libusb20_quirk *pq) 961df4b8c2aSAndrew Thompson { 962df4b8c2aSAndrew Thompson return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq)); 963df4b8c2aSAndrew Thompson } 964df4b8c2aSAndrew Thompson 965df4b8c2aSAndrew Thompson int 966df4b8c2aSAndrew Thompson libusb20_be_get_quirk_name(struct libusb20_backend *pbe, 967df4b8c2aSAndrew Thompson uint16_t quirk_index, struct libusb20_quirk *pq) 968df4b8c2aSAndrew Thompson { 969df4b8c2aSAndrew Thompson return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq)); 970df4b8c2aSAndrew Thompson } 971df4b8c2aSAndrew Thompson 972df4b8c2aSAndrew Thompson int 973df4b8c2aSAndrew Thompson libusb20_be_add_dev_quirk(struct libusb20_backend *pbe, 974df4b8c2aSAndrew Thompson struct libusb20_quirk *pq) 975df4b8c2aSAndrew Thompson { 976df4b8c2aSAndrew Thompson return (pbe->methods->root_add_dev_quirk(pbe, pq)); 977df4b8c2aSAndrew Thompson } 978df4b8c2aSAndrew Thompson 979df4b8c2aSAndrew Thompson int 980df4b8c2aSAndrew Thompson libusb20_be_remove_dev_quirk(struct libusb20_backend *pbe, 981df4b8c2aSAndrew Thompson struct libusb20_quirk *pq) 982df4b8c2aSAndrew Thompson { 983df4b8c2aSAndrew Thompson return (pbe->methods->root_remove_dev_quirk(pbe, pq)); 984df4b8c2aSAndrew Thompson } 985df4b8c2aSAndrew Thompson 986df4b8c2aSAndrew Thompson int 987df4b8c2aSAndrew Thompson libusb20_be_set_template(struct libusb20_backend *pbe, int temp) 988df4b8c2aSAndrew Thompson { 989df4b8c2aSAndrew Thompson return (pbe->methods->root_set_template(pbe, temp)); 990df4b8c2aSAndrew Thompson } 991df4b8c2aSAndrew Thompson 992df4b8c2aSAndrew Thompson int 993df4b8c2aSAndrew Thompson libusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp) 994df4b8c2aSAndrew Thompson { 995df4b8c2aSAndrew Thompson int temp; 996df4b8c2aSAndrew Thompson 997df4b8c2aSAndrew Thompson if (ptemp == NULL) 998df4b8c2aSAndrew Thompson ptemp = &temp; 999df4b8c2aSAndrew Thompson 1000df4b8c2aSAndrew Thompson return (pbe->methods->root_get_template(pbe, ptemp)); 1001df4b8c2aSAndrew Thompson } 1002df4b8c2aSAndrew Thompson 1003df4b8c2aSAndrew Thompson struct libusb20_device * 1004df4b8c2aSAndrew Thompson libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1005df4b8c2aSAndrew Thompson { 1006df4b8c2aSAndrew Thompson if (pbe == NULL) { 1007df4b8c2aSAndrew Thompson pdev = NULL; 1008df4b8c2aSAndrew Thompson } else if (pdev == NULL) { 1009df4b8c2aSAndrew Thompson pdev = TAILQ_FIRST(&(pbe->usb_devs)); 1010df4b8c2aSAndrew Thompson } else { 1011df4b8c2aSAndrew Thompson pdev = TAILQ_NEXT(pdev, dev_entry); 1012df4b8c2aSAndrew Thompson } 1013df4b8c2aSAndrew Thompson return (pdev); 1014df4b8c2aSAndrew Thompson } 1015df4b8c2aSAndrew Thompson 1016df4b8c2aSAndrew Thompson struct libusb20_backend * 1017df4b8c2aSAndrew Thompson libusb20_be_alloc(const struct libusb20_backend_methods *methods) 1018df4b8c2aSAndrew Thompson { 1019df4b8c2aSAndrew Thompson struct libusb20_backend *pbe; 1020df4b8c2aSAndrew Thompson 1021df4b8c2aSAndrew Thompson pbe = malloc(sizeof(*pbe)); 1022df4b8c2aSAndrew Thompson if (pbe == NULL) { 1023df4b8c2aSAndrew Thompson return (NULL); 1024df4b8c2aSAndrew Thompson } 1025df4b8c2aSAndrew Thompson memset(pbe, 0, sizeof(*pbe)); 1026df4b8c2aSAndrew Thompson 1027df4b8c2aSAndrew Thompson TAILQ_INIT(&(pbe->usb_devs)); 1028df4b8c2aSAndrew Thompson 1029df4b8c2aSAndrew Thompson pbe->methods = methods; /* set backend methods */ 1030df4b8c2aSAndrew Thompson 1031df4b8c2aSAndrew Thompson /* do the initial device scan */ 1032df4b8c2aSAndrew Thompson if (pbe->methods->init_backend) { 1033df4b8c2aSAndrew Thompson pbe->methods->init_backend(pbe); 1034df4b8c2aSAndrew Thompson } 1035df4b8c2aSAndrew Thompson return (pbe); 1036df4b8c2aSAndrew Thompson } 1037df4b8c2aSAndrew Thompson 1038df4b8c2aSAndrew Thompson struct libusb20_backend * 1039df4b8c2aSAndrew Thompson libusb20_be_alloc_linux(void) 1040df4b8c2aSAndrew Thompson { 1041df4b8c2aSAndrew Thompson struct libusb20_backend *pbe; 1042df4b8c2aSAndrew Thompson 1043df4b8c2aSAndrew Thompson #ifdef __linux__ 1044df4b8c2aSAndrew Thompson pbe = libusb20_be_alloc(&libusb20_linux_backend); 1045df4b8c2aSAndrew Thompson #else 1046df4b8c2aSAndrew Thompson pbe = NULL; 1047df4b8c2aSAndrew Thompson #endif 1048df4b8c2aSAndrew Thompson return (pbe); 1049df4b8c2aSAndrew Thompson } 1050df4b8c2aSAndrew Thompson 1051df4b8c2aSAndrew Thompson struct libusb20_backend * 1052df4b8c2aSAndrew Thompson libusb20_be_alloc_ugen20(void) 1053df4b8c2aSAndrew Thompson { 1054df4b8c2aSAndrew Thompson struct libusb20_backend *pbe; 1055df4b8c2aSAndrew Thompson 1056df4b8c2aSAndrew Thompson #ifdef __FreeBSD__ 1057df4b8c2aSAndrew Thompson pbe = libusb20_be_alloc(&libusb20_ugen20_backend); 1058df4b8c2aSAndrew Thompson #else 1059df4b8c2aSAndrew Thompson pbe = NULL; 1060df4b8c2aSAndrew Thompson #endif 1061df4b8c2aSAndrew Thompson return (pbe); 1062df4b8c2aSAndrew Thompson } 1063df4b8c2aSAndrew Thompson 1064df4b8c2aSAndrew Thompson struct libusb20_backend * 1065df4b8c2aSAndrew Thompson libusb20_be_alloc_default(void) 1066df4b8c2aSAndrew Thompson { 1067df4b8c2aSAndrew Thompson struct libusb20_backend *pbe; 1068df4b8c2aSAndrew Thompson 1069df4b8c2aSAndrew Thompson pbe = libusb20_be_alloc_linux(); 1070df4b8c2aSAndrew Thompson if (pbe) { 1071df4b8c2aSAndrew Thompson return (pbe); 1072df4b8c2aSAndrew Thompson } 1073df4b8c2aSAndrew Thompson pbe = libusb20_be_alloc_ugen20(); 1074df4b8c2aSAndrew Thompson if (pbe) { 1075df4b8c2aSAndrew Thompson return (pbe); 1076df4b8c2aSAndrew Thompson } 1077df4b8c2aSAndrew Thompson return (NULL); /* no backend found */ 1078df4b8c2aSAndrew Thompson } 1079df4b8c2aSAndrew Thompson 1080df4b8c2aSAndrew Thompson void 1081df4b8c2aSAndrew Thompson libusb20_be_free(struct libusb20_backend *pbe) 1082df4b8c2aSAndrew Thompson { 1083df4b8c2aSAndrew Thompson struct libusb20_device *pdev; 1084df4b8c2aSAndrew Thompson 1085df4b8c2aSAndrew Thompson if (pbe == NULL) { 1086df4b8c2aSAndrew Thompson /* be NULL safe */ 1087df4b8c2aSAndrew Thompson return; 1088df4b8c2aSAndrew Thompson } 1089df4b8c2aSAndrew Thompson while ((pdev = libusb20_be_device_foreach(pbe, NULL))) { 1090df4b8c2aSAndrew Thompson libusb20_be_dequeue_device(pbe, pdev); 1091df4b8c2aSAndrew Thompson libusb20_dev_free(pdev); 1092df4b8c2aSAndrew Thompson } 1093df4b8c2aSAndrew Thompson if (pbe->methods->exit_backend) { 1094df4b8c2aSAndrew Thompson pbe->methods->exit_backend(pbe); 1095df4b8c2aSAndrew Thompson } 1096df4b8c2aSAndrew Thompson return; 1097df4b8c2aSAndrew Thompson } 1098df4b8c2aSAndrew Thompson 1099df4b8c2aSAndrew Thompson void 1100df4b8c2aSAndrew Thompson libusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1101df4b8c2aSAndrew Thompson { 1102df4b8c2aSAndrew Thompson pdev->beMethods = pbe->methods; /* copy backend methods */ 1103df4b8c2aSAndrew Thompson TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry); 1104df4b8c2aSAndrew Thompson return; 1105df4b8c2aSAndrew Thompson } 1106df4b8c2aSAndrew Thompson 1107df4b8c2aSAndrew Thompson void 1108df4b8c2aSAndrew Thompson libusb20_be_dequeue_device(struct libusb20_backend *pbe, 1109df4b8c2aSAndrew Thompson struct libusb20_device *pdev) 1110df4b8c2aSAndrew Thompson { 1111df4b8c2aSAndrew Thompson TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry); 1112df4b8c2aSAndrew Thompson return; 1113df4b8c2aSAndrew Thompson } 1114