1184610Salfred/* $FreeBSD: stable/10/lib/libusb/libusb20.c 356399 2020-01-06 09:22:33Z hselasky $ */ 2184610Salfred/*- 3199575Sthompsa * Copyright (c) 2008-2009 Hans Petter Selasky. All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24184610Salfred * SUCH DAMAGE. 25184610Salfred */ 26184610Salfred 27248236Shselasky#ifdef LIBUSB_GLOBAL_INCLUDE_FILE 28248236Shselasky#include LIBUSB_GLOBAL_INCLUDE_FILE 29248236Shselasky#else 30203815Swkoszek#include <ctype.h> 31203815Swkoszek#include <poll.h> 32184610Salfred#include <stdio.h> 33184610Salfred#include <stdlib.h> 34184610Salfred#include <string.h> 35248236Shselasky#include <time.h> 36248236Shselasky#include <sys/queue.h> 37248236Shselasky#endif 38184610Salfred 39184610Salfred#include "libusb20.h" 40184610Salfred#include "libusb20_desc.h" 41184610Salfred#include "libusb20_int.h" 42184610Salfred 43184610Salfredstatic int 44184610Salfreddummy_int(void) 45184610Salfred{ 46184610Salfred return (LIBUSB20_ERROR_NOT_SUPPORTED); 47184610Salfred} 48184610Salfred 49184610Salfredstatic void 50184610Salfreddummy_void(void) 51184610Salfred{ 52184610Salfred return; 53184610Salfred} 54184610Salfred 55184610Salfredstatic void 56184610Salfreddummy_callback(struct libusb20_transfer *xfer) 57184610Salfred{ 58184610Salfred ; /* style fix */ 59184610Salfred switch (libusb20_tr_get_status(xfer)) { 60184610Salfred case LIBUSB20_TRANSFER_START: 61184610Salfred libusb20_tr_submit(xfer); 62184610Salfred break; 63184610Salfred default: 64184610Salfred /* complete or error */ 65184610Salfred break; 66184610Salfred } 67184610Salfred return; 68184610Salfred} 69184610Salfred 70184610Salfred#define dummy_get_config_desc_full (void *)dummy_int 71184610Salfred#define dummy_get_config_index (void *)dummy_int 72184610Salfred#define dummy_set_config_index (void *)dummy_int 73184610Salfred#define dummy_set_alt_index (void *)dummy_int 74184610Salfred#define dummy_reset_device (void *)dummy_int 75203147Sthompsa#define dummy_check_connected (void *)dummy_int 76184610Salfred#define dummy_set_power_mode (void *)dummy_int 77184610Salfred#define dummy_get_power_mode (void *)dummy_int 78250201Shselasky#define dummy_get_port_path (void *)dummy_int 79246789Shselasky#define dummy_get_power_usage (void *)dummy_int 80356399Shselasky#define dummy_get_stats (void *)dummy_int 81184610Salfred#define dummy_kernel_driver_active (void *)dummy_int 82184610Salfred#define dummy_detach_kernel_driver (void *)dummy_int 83184610Salfred#define dummy_do_request_sync (void *)dummy_int 84184610Salfred#define dummy_tr_open (void *)dummy_int 85184610Salfred#define dummy_tr_close (void *)dummy_int 86184610Salfred#define dummy_tr_clear_stall_sync (void *)dummy_int 87184610Salfred#define dummy_process (void *)dummy_int 88188622Sthompsa#define dummy_dev_info (void *)dummy_int 89188622Sthompsa#define dummy_dev_get_iface_driver (void *)dummy_int 90184610Salfred 91184610Salfred#define dummy_tr_submit (void *)dummy_void 92184610Salfred#define dummy_tr_cancel_async (void *)dummy_void 93184610Salfred 94184610Salfredstatic const struct libusb20_device_methods libusb20_dummy_methods = { 95184610Salfred LIBUSB20_DEVICE(LIBUSB20_DECLARE, dummy) 96184610Salfred}; 97184610Salfred 98184610Salfredvoid 99184610Salfredlibusb20_tr_callback_wrapper(struct libusb20_transfer *xfer) 100184610Salfred{ 101184610Salfred ; /* style fix */ 102184610Salfred 103184610Salfredrepeat: 104184610Salfred 105184610Salfred if (!xfer->is_pending) { 106184610Salfred xfer->status = LIBUSB20_TRANSFER_START; 107184610Salfred } else { 108184610Salfred xfer->is_pending = 0; 109184610Salfred } 110184610Salfred 111188622Sthompsa xfer->callback(xfer); 112184610Salfred 113184610Salfred if (xfer->is_restart) { 114184610Salfred xfer->is_restart = 0; 115184610Salfred goto repeat; 116184610Salfred } 117184610Salfred if (xfer->is_draining && 118184610Salfred (!xfer->is_pending)) { 119184610Salfred xfer->is_draining = 0; 120184610Salfred xfer->status = LIBUSB20_TRANSFER_DRAINED; 121188622Sthompsa xfer->callback(xfer); 122184610Salfred } 123184610Salfred return; 124184610Salfred} 125184610Salfred 126184610Salfredint 127184610Salfredlibusb20_tr_close(struct libusb20_transfer *xfer) 128184610Salfred{ 129184610Salfred int error; 130184610Salfred 131184610Salfred if (!xfer->is_opened) { 132184610Salfred return (LIBUSB20_ERROR_OTHER); 133184610Salfred } 134188622Sthompsa error = xfer->pdev->methods->tr_close(xfer); 135184610Salfred 136184610Salfred if (xfer->pLength) { 137184610Salfred free(xfer->pLength); 138184610Salfred } 139184610Salfred if (xfer->ppBuffer) { 140184610Salfred free(xfer->ppBuffer); 141184610Salfred } 142202025Sthompsa /* reset variable fields in case the transfer is opened again */ 143202025Sthompsa xfer->priv_sc0 = 0; 144202025Sthompsa xfer->priv_sc1 = 0; 145184610Salfred xfer->is_opened = 0; 146202025Sthompsa xfer->is_pending = 0; 147202025Sthompsa xfer->is_cancel = 0; 148202025Sthompsa xfer->is_draining = 0; 149202025Sthompsa xfer->is_restart = 0; 150202025Sthompsa xfer->status = 0; 151202025Sthompsa xfer->flags = 0; 152202025Sthompsa xfer->nFrames = 0; 153202025Sthompsa xfer->aFrames = 0; 154202025Sthompsa xfer->timeout = 0; 155184610Salfred xfer->maxFrames = 0; 156184610Salfred xfer->maxTotalLength = 0; 157184610Salfred xfer->maxPacketLen = 0; 158184610Salfred return (error); 159184610Salfred} 160184610Salfred 161184610Salfredint 162184610Salfredlibusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 163184610Salfred uint32_t MaxFrameCount, uint8_t ep_no) 164184610Salfred{ 165239239Shselasky return (libusb20_tr_open_stream(xfer, MaxBufSize, MaxFrameCount, ep_no, 0)); 166239239Shselasky} 167239239Shselasky 168239239Shselaskyint 169239239Shselaskylibusb20_tr_open_stream(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 170239239Shselasky uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id) 171239239Shselasky{ 172184610Salfred uint32_t size; 173219100Shselasky uint8_t pre_scale; 174184610Salfred int error; 175184610Salfred 176219100Shselasky if (xfer->is_opened) 177184610Salfred return (LIBUSB20_ERROR_BUSY); 178219100Shselasky if (MaxFrameCount & LIBUSB20_MAX_FRAME_PRE_SCALE) { 179219100Shselasky MaxFrameCount &= ~LIBUSB20_MAX_FRAME_PRE_SCALE; 180305641Shselasky /* 181305641Shselasky * The kernel can setup 8 times more frames when 182305641Shselasky * pre-scaling ISOCHRONOUS transfers. Make sure the 183305641Shselasky * length and pointer buffers are big enough: 184305641Shselasky */ 185305641Shselasky MaxFrameCount *= 8; 186219100Shselasky pre_scale = 1; 187219100Shselasky } else { 188219100Shselasky pre_scale = 0; 189184610Salfred } 190219100Shselasky if (MaxFrameCount == 0) 191184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 192219100Shselasky 193184610Salfred xfer->maxFrames = MaxFrameCount; 194184610Salfred 195184610Salfred size = MaxFrameCount * sizeof(xfer->pLength[0]); 196184610Salfred xfer->pLength = malloc(size); 197184610Salfred if (xfer->pLength == NULL) { 198184610Salfred return (LIBUSB20_ERROR_NO_MEM); 199184610Salfred } 200184610Salfred memset(xfer->pLength, 0, size); 201184610Salfred 202184610Salfred size = MaxFrameCount * sizeof(xfer->ppBuffer[0]); 203184610Salfred xfer->ppBuffer = malloc(size); 204184610Salfred if (xfer->ppBuffer == NULL) { 205184610Salfred free(xfer->pLength); 206184610Salfred return (LIBUSB20_ERROR_NO_MEM); 207184610Salfred } 208184610Salfred memset(xfer->ppBuffer, 0, size); 209184610Salfred 210305641Shselasky if (pre_scale) { 211305641Shselasky error = xfer->pdev->methods->tr_open(xfer, MaxBufSize, 212305641Shselasky MaxFrameCount / 8, ep_no, stream_id, 1); 213305641Shselasky } else { 214305641Shselasky error = xfer->pdev->methods->tr_open(xfer, MaxBufSize, 215305641Shselasky MaxFrameCount, ep_no, stream_id, 0); 216305641Shselasky } 217184610Salfred 218184610Salfred if (error) { 219184610Salfred free(xfer->ppBuffer); 220184610Salfred free(xfer->pLength); 221184610Salfred } else { 222184610Salfred xfer->is_opened = 1; 223184610Salfred } 224184610Salfred return (error); 225184610Salfred} 226184610Salfred 227184610Salfredstruct libusb20_transfer * 228184610Salfredlibusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex) 229184610Salfred{ 230184610Salfred if (trIndex >= pdev->nTransfer) { 231184610Salfred return (NULL); 232184610Salfred } 233184610Salfred return (pdev->pTransfer + trIndex); 234184610Salfred} 235184610Salfred 236184610Salfreduint32_t 237184610Salfredlibusb20_tr_get_actual_frames(struct libusb20_transfer *xfer) 238184610Salfred{ 239184610Salfred return (xfer->aFrames); 240184610Salfred} 241184610Salfred 242184610Salfreduint16_t 243184610Salfredlibusb20_tr_get_time_complete(struct libusb20_transfer *xfer) 244184610Salfred{ 245184610Salfred return (xfer->timeComplete); 246184610Salfred} 247184610Salfred 248184610Salfreduint32_t 249184610Salfredlibusb20_tr_get_actual_length(struct libusb20_transfer *xfer) 250184610Salfred{ 251184610Salfred uint32_t x; 252184610Salfred uint32_t actlen = 0; 253184610Salfred 254184610Salfred for (x = 0; x != xfer->aFrames; x++) { 255184610Salfred actlen += xfer->pLength[x]; 256184610Salfred } 257184610Salfred return (actlen); 258184610Salfred} 259184610Salfred 260184610Salfreduint32_t 261184610Salfredlibusb20_tr_get_max_frames(struct libusb20_transfer *xfer) 262184610Salfred{ 263184610Salfred return (xfer->maxFrames); 264184610Salfred} 265184610Salfred 266184610Salfreduint32_t 267184610Salfredlibusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer) 268184610Salfred{ 269184610Salfred /* 270184610Salfred * Special Case NOTE: If the packet multiplier is non-zero for 271184610Salfred * High Speed USB, the value returned is equal to 272184610Salfred * "wMaxPacketSize * multiplier" ! 273184610Salfred */ 274184610Salfred return (xfer->maxPacketLen); 275184610Salfred} 276184610Salfred 277184610Salfreduint32_t 278184610Salfredlibusb20_tr_get_max_total_length(struct libusb20_transfer *xfer) 279184610Salfred{ 280184610Salfred return (xfer->maxTotalLength); 281184610Salfred} 282184610Salfred 283184610Salfreduint8_t 284184610Salfredlibusb20_tr_get_status(struct libusb20_transfer *xfer) 285184610Salfred{ 286184610Salfred return (xfer->status); 287184610Salfred} 288184610Salfred 289184610Salfreduint8_t 290184610Salfredlibusb20_tr_pending(struct libusb20_transfer *xfer) 291184610Salfred{ 292184610Salfred return (xfer->is_pending); 293184610Salfred} 294184610Salfred 295184610Salfredvoid * 296184610Salfredlibusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer) 297184610Salfred{ 298184610Salfred return (xfer->priv_sc0); 299184610Salfred} 300184610Salfred 301184610Salfredvoid * 302184610Salfredlibusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer) 303184610Salfred{ 304184610Salfred return (xfer->priv_sc1); 305184610Salfred} 306184610Salfred 307184610Salfredvoid 308184610Salfredlibusb20_tr_stop(struct libusb20_transfer *xfer) 309184610Salfred{ 310199575Sthompsa if (!xfer->is_opened) { 311199575Sthompsa /* transfer is not opened */ 312199575Sthompsa return; 313199575Sthompsa } 314184610Salfred if (!xfer->is_pending) { 315184610Salfred /* transfer not pending */ 316184610Salfred return; 317184610Salfred } 318184610Salfred if (xfer->is_cancel) { 319184610Salfred /* already cancelling */ 320184610Salfred return; 321184610Salfred } 322184610Salfred xfer->is_cancel = 1; /* we are cancelling */ 323184610Salfred 324188622Sthompsa xfer->pdev->methods->tr_cancel_async(xfer); 325184610Salfred return; 326184610Salfred} 327184610Salfred 328184610Salfredvoid 329184610Salfredlibusb20_tr_drain(struct libusb20_transfer *xfer) 330184610Salfred{ 331199575Sthompsa if (!xfer->is_opened) { 332199575Sthompsa /* transfer is not opened */ 333199575Sthompsa return; 334199575Sthompsa } 335184610Salfred /* make sure that we are cancelling */ 336184610Salfred libusb20_tr_stop(xfer); 337184610Salfred 338184610Salfred if (xfer->is_pending) { 339184610Salfred xfer->is_draining = 1; 340184610Salfred } 341184610Salfred return; 342184610Salfred} 343184610Salfred 344184610Salfredvoid 345184610Salfredlibusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 346184610Salfred{ 347188622Sthompsa xfer->pdev->methods->tr_clear_stall_sync(xfer); 348184610Salfred return; 349184610Salfred} 350184610Salfred 351184610Salfredvoid 352184610Salfredlibusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex) 353184610Salfred{ 354213852Shselasky xfer->ppBuffer[frIndex] = libusb20_pass_ptr(buffer); 355184610Salfred return; 356184610Salfred} 357184610Salfred 358184610Salfredvoid 359184610Salfredlibusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb) 360184610Salfred{ 361184610Salfred xfer->callback = cb; 362184610Salfred return; 363184610Salfred} 364184610Salfred 365184610Salfredvoid 366184610Salfredlibusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags) 367184610Salfred{ 368184610Salfred xfer->flags = flags; 369184610Salfred return; 370184610Salfred} 371184610Salfred 372193313Sthompsauint32_t 373193313Sthompsalibusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex) 374193313Sthompsa{ 375193313Sthompsa return (xfer->pLength[frIndex]); 376193313Sthompsa} 377193313Sthompsa 378184610Salfredvoid 379184610Salfredlibusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex) 380184610Salfred{ 381184610Salfred xfer->pLength[frIndex] = length; 382184610Salfred return; 383184610Salfred} 384184610Salfred 385184610Salfredvoid 386184610Salfredlibusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0) 387184610Salfred{ 388184610Salfred xfer->priv_sc0 = sc0; 389184610Salfred return; 390184610Salfred} 391184610Salfred 392184610Salfredvoid 393184610Salfredlibusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1) 394184610Salfred{ 395184610Salfred xfer->priv_sc1 = sc1; 396184610Salfred return; 397184610Salfred} 398184610Salfred 399184610Salfredvoid 400184610Salfredlibusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout) 401184610Salfred{ 402184610Salfred xfer->timeout = timeout; 403184610Salfred return; 404184610Salfred} 405184610Salfred 406184610Salfredvoid 407184610Salfredlibusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames) 408184610Salfred{ 409184610Salfred if (nFrames > xfer->maxFrames) { 410184610Salfred /* should not happen */ 411184610Salfred nFrames = xfer->maxFrames; 412184610Salfred } 413184610Salfred xfer->nFrames = nFrames; 414184610Salfred return; 415184610Salfred} 416184610Salfred 417184610Salfredvoid 418184610Salfredlibusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 419184610Salfred{ 420213852Shselasky xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf); 421184610Salfred xfer->pLength[0] = length; 422184610Salfred xfer->timeout = timeout; 423184610Salfred xfer->nFrames = 1; 424184610Salfred return; 425184610Salfred} 426184610Salfred 427184610Salfredvoid 428184610Salfredlibusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout) 429184610Salfred{ 430184610Salfred uint16_t len; 431184610Salfred 432213852Shselasky xfer->ppBuffer[0] = libusb20_pass_ptr(psetup); 433184610Salfred xfer->pLength[0] = 8; /* fixed */ 434184610Salfred xfer->timeout = timeout; 435184610Salfred 436184610Salfred len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8); 437184610Salfred 438184610Salfred if (len != 0) { 439184610Salfred xfer->nFrames = 2; 440213852Shselasky xfer->ppBuffer[1] = libusb20_pass_ptr(pBuf); 441184610Salfred xfer->pLength[1] = len; 442184610Salfred } else { 443184610Salfred xfer->nFrames = 1; 444184610Salfred } 445184610Salfred return; 446184610Salfred} 447184610Salfred 448184610Salfredvoid 449184610Salfredlibusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 450184610Salfred{ 451213852Shselasky xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf); 452184610Salfred xfer->pLength[0] = length; 453184610Salfred xfer->timeout = timeout; 454184610Salfred xfer->nFrames = 1; 455184610Salfred return; 456184610Salfred} 457184610Salfred 458184610Salfredvoid 459184610Salfredlibusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex) 460184610Salfred{ 461184610Salfred if (frIndex >= xfer->maxFrames) { 462184610Salfred /* should not happen */ 463184610Salfred return; 464184610Salfred } 465213852Shselasky xfer->ppBuffer[frIndex] = libusb20_pass_ptr(pBuf); 466184610Salfred xfer->pLength[frIndex] = length; 467184610Salfred return; 468184610Salfred} 469184610Salfred 470199575Sthompsauint8_t 471199575Sthompsalibusb20_tr_bulk_intr_sync(struct libusb20_transfer *xfer, 472199575Sthompsa void *pbuf, uint32_t length, uint32_t *pactlen, 473199575Sthompsa uint32_t timeout) 474199575Sthompsa{ 475199575Sthompsa struct libusb20_device *pdev = xfer->pdev; 476199575Sthompsa uint32_t transfer_max; 477199575Sthompsa uint32_t transfer_act; 478199575Sthompsa uint8_t retval; 479199575Sthompsa 480199575Sthompsa /* set some sensible default value */ 481199575Sthompsa if (pactlen != NULL) 482199575Sthompsa *pactlen = 0; 483199575Sthompsa 484199575Sthompsa /* check for error condition */ 485199575Sthompsa if (libusb20_tr_pending(xfer)) 486199575Sthompsa return (LIBUSB20_ERROR_OTHER); 487199575Sthompsa 488199575Sthompsa do { 489199575Sthompsa /* compute maximum transfer length */ 490199575Sthompsa transfer_max = 491199575Sthompsa libusb20_tr_get_max_total_length(xfer); 492199575Sthompsa 493199575Sthompsa if (transfer_max > length) 494199575Sthompsa transfer_max = length; 495199575Sthompsa 496199575Sthompsa /* setup bulk or interrupt transfer */ 497199575Sthompsa libusb20_tr_setup_bulk(xfer, pbuf, 498199575Sthompsa transfer_max, timeout); 499199575Sthompsa 500199575Sthompsa /* start the transfer */ 501199575Sthompsa libusb20_tr_start(xfer); 502199575Sthompsa 503199575Sthompsa /* wait for transfer completion */ 504199575Sthompsa while (libusb20_dev_process(pdev) == 0) { 505199575Sthompsa 506199575Sthompsa if (libusb20_tr_pending(xfer) == 0) 507199575Sthompsa break; 508199575Sthompsa 509199575Sthompsa libusb20_dev_wait_process(pdev, -1); 510199575Sthompsa } 511199575Sthompsa 512199575Sthompsa transfer_act = libusb20_tr_get_actual_length(xfer); 513199575Sthompsa 514199575Sthompsa /* update actual length, if any */ 515199575Sthompsa if (pactlen != NULL) 516199575Sthompsa pactlen[0] += transfer_act; 517199575Sthompsa 518199575Sthompsa /* check transfer status */ 519199575Sthompsa retval = libusb20_tr_get_status(xfer); 520199575Sthompsa if (retval) 521199575Sthompsa break; 522199575Sthompsa 523199575Sthompsa /* check for short transfer */ 524199575Sthompsa if (transfer_act != transfer_max) 525199575Sthompsa break; 526199575Sthompsa 527199575Sthompsa /* update buffer pointer and length */ 528199575Sthompsa pbuf = ((uint8_t *)pbuf) + transfer_max; 529199575Sthompsa length = length - transfer_max; 530199575Sthompsa 531199575Sthompsa } while (length != 0); 532199575Sthompsa 533199575Sthompsa return (retval); 534199575Sthompsa} 535199575Sthompsa 536184610Salfredvoid 537184610Salfredlibusb20_tr_submit(struct libusb20_transfer *xfer) 538184610Salfred{ 539199575Sthompsa if (!xfer->is_opened) { 540199575Sthompsa /* transfer is not opened */ 541199575Sthompsa return; 542199575Sthompsa } 543184610Salfred if (xfer->is_pending) { 544184610Salfred /* should not happen */ 545184610Salfred return; 546184610Salfred } 547184610Salfred xfer->is_pending = 1; /* we are pending */ 548184610Salfred xfer->is_cancel = 0; /* not cancelling */ 549184610Salfred xfer->is_restart = 0; /* not restarting */ 550184610Salfred 551188622Sthompsa xfer->pdev->methods->tr_submit(xfer); 552184610Salfred return; 553184610Salfred} 554184610Salfred 555184610Salfredvoid 556184610Salfredlibusb20_tr_start(struct libusb20_transfer *xfer) 557184610Salfred{ 558199575Sthompsa if (!xfer->is_opened) { 559199575Sthompsa /* transfer is not opened */ 560199575Sthompsa return; 561199575Sthompsa } 562184610Salfred if (xfer->is_pending) { 563184610Salfred if (xfer->is_cancel) { 564184610Salfred /* cancelling - restart */ 565184610Salfred xfer->is_restart = 1; 566184610Salfred } 567184610Salfred /* transfer not pending */ 568184610Salfred return; 569184610Salfred } 570184610Salfred /* get into the callback */ 571184610Salfred libusb20_tr_callback_wrapper(xfer); 572184610Salfred return; 573184610Salfred} 574184610Salfred 575184610Salfred/* USB device operations */ 576184610Salfred 577184610Salfredint 578184610Salfredlibusb20_dev_close(struct libusb20_device *pdev) 579184610Salfred{ 580184610Salfred struct libusb20_transfer *xfer; 581184610Salfred uint16_t x; 582184610Salfred int error = 0; 583184610Salfred 584184610Salfred if (!pdev->is_opened) { 585184610Salfred return (LIBUSB20_ERROR_OTHER); 586184610Salfred } 587184610Salfred for (x = 0; x != pdev->nTransfer; x++) { 588184610Salfred xfer = pdev->pTransfer + x; 589184610Salfred 590199575Sthompsa if (!xfer->is_opened) { 591199575Sthompsa /* transfer is not opened */ 592199575Sthompsa continue; 593199575Sthompsa } 594199575Sthompsa 595184610Salfred libusb20_tr_drain(xfer); 596199575Sthompsa 597199575Sthompsa libusb20_tr_close(xfer); 598184610Salfred } 599184610Salfred 600184610Salfred if (pdev->pTransfer != NULL) { 601184610Salfred free(pdev->pTransfer); 602184610Salfred pdev->pTransfer = NULL; 603184610Salfred } 604188622Sthompsa error = pdev->beMethods->close_device(pdev); 605184610Salfred 606184610Salfred pdev->methods = &libusb20_dummy_methods; 607184610Salfred 608184610Salfred pdev->is_opened = 0; 609184610Salfred 610194069Sthompsa /* 611194069Sthompsa * The following variable is only used by the libusb v0.1 612194069Sthompsa * compat layer: 613194069Sthompsa */ 614194069Sthompsa pdev->claimed_interface = 0; 615187184Sthompsa 616302275Shselasky /* 617302275Shselasky * The following variable is only used by the libusb v1.0 618302275Shselasky * compat layer: 619302275Shselasky */ 620302275Shselasky pdev->auto_detach = 0; 621302275Shselasky 622184610Salfred return (error); 623184610Salfred} 624184610Salfred 625184610Salfredint 626184610Salfredlibusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex) 627184610Salfred{ 628184610Salfred int error; 629184610Salfred 630188622Sthompsa error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex); 631184610Salfred return (error); 632184610Salfred} 633184610Salfred 634184610Salfredstruct LIBUSB20_DEVICE_DESC_DECODED * 635184610Salfredlibusb20_dev_get_device_desc(struct libusb20_device *pdev) 636184610Salfred{ 637184610Salfred return (&(pdev->ddesc)); 638184610Salfred} 639184610Salfred 640184610Salfredint 641184610Salfredlibusb20_dev_get_fd(struct libusb20_device *pdev) 642184610Salfred{ 643184610Salfred return (pdev->file); 644184610Salfred} 645184610Salfred 646184610Salfredint 647184610Salfredlibusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex) 648184610Salfred{ 649184610Salfred int error; 650184610Salfred 651188622Sthompsa error = pdev->methods->kernel_driver_active(pdev, ifaceIndex); 652184610Salfred return (error); 653184610Salfred} 654184610Salfred 655184610Salfredint 656184610Salfredlibusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax) 657184610Salfred{ 658184610Salfred struct libusb20_transfer *xfer; 659184610Salfred uint32_t size; 660184610Salfred uint16_t x; 661184610Salfred int error; 662184610Salfred 663184610Salfred if (pdev->is_opened) { 664184610Salfred return (LIBUSB20_ERROR_BUSY); 665184610Salfred } 666184610Salfred if (nTransferMax >= 256) { 667184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 668184610Salfred } else if (nTransferMax != 0) { 669184610Salfred size = sizeof(pdev->pTransfer[0]) * nTransferMax; 670184610Salfred pdev->pTransfer = malloc(size); 671184610Salfred if (pdev->pTransfer == NULL) { 672184610Salfred return (LIBUSB20_ERROR_NO_MEM); 673184610Salfred } 674184610Salfred memset(pdev->pTransfer, 0, size); 675184610Salfred } 676184610Salfred /* initialise all transfers */ 677184610Salfred for (x = 0; x != nTransferMax; x++) { 678184610Salfred 679184610Salfred xfer = pdev->pTransfer + x; 680184610Salfred 681184610Salfred xfer->pdev = pdev; 682184610Salfred xfer->trIndex = x; 683184610Salfred xfer->callback = &dummy_callback; 684184610Salfred } 685184610Salfred 686185087Salfred /* set "nTransfer" early */ 687185087Salfred pdev->nTransfer = nTransferMax; 688185087Salfred 689188622Sthompsa error = pdev->beMethods->open_device(pdev, nTransferMax); 690184610Salfred 691184610Salfred if (error) { 692184610Salfred if (pdev->pTransfer != NULL) { 693184610Salfred free(pdev->pTransfer); 694184610Salfred pdev->pTransfer = NULL; 695184610Salfred } 696184610Salfred pdev->file = -1; 697184610Salfred pdev->file_ctrl = -1; 698184610Salfred pdev->nTransfer = 0; 699184610Salfred } else { 700184610Salfred pdev->is_opened = 1; 701184610Salfred } 702184610Salfred return (error); 703184610Salfred} 704184610Salfred 705184610Salfredint 706184610Salfredlibusb20_dev_reset(struct libusb20_device *pdev) 707184610Salfred{ 708184610Salfred int error; 709184610Salfred 710188622Sthompsa error = pdev->methods->reset_device(pdev); 711184610Salfred return (error); 712184610Salfred} 713184610Salfred 714184610Salfredint 715203147Sthompsalibusb20_dev_check_connected(struct libusb20_device *pdev) 716203147Sthompsa{ 717203147Sthompsa int error; 718203147Sthompsa 719203147Sthompsa error = pdev->methods->check_connected(pdev); 720203147Sthompsa return (error); 721203147Sthompsa} 722203147Sthompsa 723203147Sthompsaint 724184610Salfredlibusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 725184610Salfred{ 726184610Salfred int error; 727184610Salfred 728188622Sthompsa error = pdev->methods->set_power_mode(pdev, power_mode); 729184610Salfred return (error); 730184610Salfred} 731184610Salfred 732184610Salfreduint8_t 733184610Salfredlibusb20_dev_get_power_mode(struct libusb20_device *pdev) 734184610Salfred{ 735184610Salfred int error; 736184610Salfred uint8_t power_mode; 737184610Salfred 738188622Sthompsa error = pdev->methods->get_power_mode(pdev, &power_mode); 739184610Salfred if (error) 740184610Salfred power_mode = LIBUSB20_POWER_ON; /* fake power mode */ 741184610Salfred return (power_mode); 742184610Salfred} 743184610Salfred 744250201Shselaskyint 745250201Shselaskylibusb20_dev_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize) 746250201Shselasky{ 747250201Shselasky return (pdev->methods->get_port_path(pdev, buf, bufsize)); 748250201Shselasky} 749250201Shselasky 750246789Shselaskyuint16_t 751246789Shselaskylibusb20_dev_get_power_usage(struct libusb20_device *pdev) 752246789Shselasky{ 753246789Shselasky int error; 754246789Shselasky uint16_t power_usage; 755246789Shselasky 756246789Shselasky error = pdev->methods->get_power_usage(pdev, &power_usage); 757246789Shselasky if (error) 758246789Shselasky power_usage = 0; 759246789Shselasky return (power_usage); 760246789Shselasky} 761246789Shselasky 762184610Salfredint 763184610Salfredlibusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex) 764184610Salfred{ 765184610Salfred int error; 766184610Salfred 767188622Sthompsa error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex); 768184610Salfred return (error); 769184610Salfred} 770184610Salfred 771184610Salfredint 772184610Salfredlibusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex) 773184610Salfred{ 774184610Salfred int error; 775184610Salfred 776188622Sthompsa error = pdev->methods->set_config_index(pdev, configIndex); 777184610Salfred return (error); 778184610Salfred} 779184610Salfred 780184610Salfredint 781184610Salfredlibusb20_dev_request_sync(struct libusb20_device *pdev, 782184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data, 783184610Salfred uint16_t *pactlen, uint32_t timeout, uint8_t flags) 784184610Salfred{ 785184610Salfred int error; 786184610Salfred 787188622Sthompsa error = pdev->methods->do_request_sync(pdev, 788184610Salfred setup, data, pactlen, timeout, flags); 789184610Salfred return (error); 790184610Salfred} 791184610Salfred 792184610Salfredint 793184610Salfredlibusb20_dev_req_string_sync(struct libusb20_device *pdev, 794185087Salfred uint8_t str_index, uint16_t langid, void *ptr, uint16_t len) 795184610Salfred{ 796184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED req; 797184610Salfred int error; 798336884Shselasky int flags; 799184610Salfred 800199055Sthompsa /* make sure memory is initialised */ 801199055Sthompsa memset(ptr, 0, len); 802199055Sthompsa 803184610Salfred if (len < 4) { 804184610Salfred /* invalid length */ 805184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 806184610Salfred } 807184610Salfred LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req); 808184610Salfred 809184610Salfred /* 810184610Salfred * We need to read the USB string in two steps else some USB 811184610Salfred * devices will complain. 812184610Salfred */ 813184610Salfred req.bmRequestType = 814184610Salfred LIBUSB20_REQUEST_TYPE_STANDARD | 815184610Salfred LIBUSB20_RECIPIENT_DEVICE | 816184610Salfred LIBUSB20_ENDPOINT_IN; 817184610Salfred req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR; 818185087Salfred req.wValue = (LIBUSB20_DT_STRING << 8) | str_index; 819184610Salfred req.wIndex = langid; 820184610Salfred req.wLength = 4; /* bytes */ 821184610Salfred 822184610Salfred error = libusb20_dev_request_sync(pdev, &req, 823184610Salfred ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 824184610Salfred if (error) { 825336884Shselasky /* try to request full string */ 826336884Shselasky req.wLength = 255; 827336884Shselasky flags = 0; 828336884Shselasky } else { 829336884Shselasky /* extract length and request full string */ 830336884Shselasky req.wLength = *(uint8_t *)ptr; 831336884Shselasky flags = LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK; 832184610Salfred } 833184610Salfred if (req.wLength > len) { 834184610Salfred /* partial string read */ 835184610Salfred req.wLength = len; 836184610Salfred } 837336884Shselasky error = libusb20_dev_request_sync(pdev, &req, ptr, NULL, 1000, flags); 838336884Shselasky if (error) 839336884Shselasky return (error); 840184610Salfred 841336884Shselasky if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) 842184610Salfred return (LIBUSB20_ERROR_OTHER); 843184610Salfred return (0); /* success */ 844184610Salfred} 845184610Salfred 846184610Salfredint 847184610Salfredlibusb20_dev_req_string_simple_sync(struct libusb20_device *pdev, 848185087Salfred uint8_t str_index, void *ptr, uint16_t len) 849184610Salfred{ 850184610Salfred char *buf; 851184610Salfred int error; 852184610Salfred uint16_t langid; 853184610Salfred uint16_t n; 854184610Salfred uint16_t i; 855184610Salfred uint16_t c; 856184610Salfred uint8_t temp[255]; 857184610Salfred uint8_t swap; 858184610Salfred 859184610Salfred /* the following code derives from the FreeBSD USB kernel */ 860184610Salfred 861184610Salfred if ((len < 1) || (ptr == NULL)) { 862184610Salfred /* too short buffer */ 863184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 864184610Salfred } 865184610Salfred error = libusb20_dev_req_string_sync(pdev, 866184610Salfred 0, 0, temp, sizeof(temp)); 867185087Salfred if (error < 0) { 868185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 869184610Salfred return (error); 870185087Salfred } 871184610Salfred langid = temp[2] | (temp[3] << 8); 872184610Salfred 873185087Salfred error = libusb20_dev_req_string_sync(pdev, str_index, 874184610Salfred langid, temp, sizeof(temp)); 875185087Salfred if (error < 0) { 876185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 877184610Salfred return (error); 878185087Salfred } 879184610Salfred if (temp[0] < 2) { 880184610Salfred /* string length is too short */ 881185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 882184610Salfred return (LIBUSB20_ERROR_OTHER); 883184610Salfred } 884184610Salfred /* reserve one byte for terminating zero */ 885184610Salfred len--; 886184610Salfred 887184610Salfred /* find maximum length */ 888184610Salfred n = (temp[0] / 2) - 1; 889184610Salfred if (n > len) { 890184610Salfred n = len; 891184610Salfred } 892184610Salfred /* reset swap state */ 893184610Salfred swap = 3; 894184610Salfred 895184610Salfred /* setup output buffer pointer */ 896184610Salfred buf = ptr; 897184610Salfred 898184610Salfred /* convert and filter */ 899184610Salfred for (i = 0; (i != n); i++) { 900184610Salfred c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8); 901184610Salfred 902184610Salfred /* convert from Unicode, handle buggy strings */ 903184610Salfred if (((c & 0xff00) == 0) && (swap & 1)) { 904184610Salfred /* Little Endian, default */ 905184610Salfred *buf = c; 906184610Salfred swap = 1; 907184610Salfred } else if (((c & 0x00ff) == 0) && (swap & 2)) { 908184610Salfred /* Big Endian */ 909184610Salfred *buf = c >> 8; 910184610Salfred swap = 2; 911184610Salfred } else { 912185087Salfred /* skip invalid character */ 913185087Salfred continue; 914184610Salfred } 915184610Salfred /* 916184610Salfred * Filter by default - we don't allow greater and less than 917184610Salfred * signs because they might confuse the dmesg printouts! 918184610Salfred */ 919184610Salfred if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) { 920185087Salfred /* skip invalid character */ 921185087Salfred continue; 922184610Salfred } 923184610Salfred buf++; 924184610Salfred } 925184610Salfred *buf = 0; /* zero terminate string */ 926184610Salfred 927184610Salfred return (0); 928184610Salfred} 929184610Salfred 930184610Salfredstruct libusb20_config * 931184610Salfredlibusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex) 932184610Salfred{ 933184610Salfred struct libusb20_config *retval = NULL; 934184610Salfred uint8_t *ptr; 935184610Salfred uint16_t len; 936184610Salfred uint8_t do_close; 937184610Salfred int error; 938184610Salfred 939348895Shselasky /* 940348895Shselasky * Catch invalid configuration descriptor reads early on to 941348895Shselasky * avoid issues with devices that don't check for a valid USB 942348895Shselasky * configuration read request. 943348895Shselasky */ 944348895Shselasky if (configIndex >= pdev->ddesc.bNumConfigurations) 945348895Shselasky return (NULL); 946348895Shselasky 947184610Salfred if (!pdev->is_opened) { 948184610Salfred error = libusb20_dev_open(pdev, 0); 949184610Salfred if (error) { 950184610Salfred return (NULL); 951184610Salfred } 952184610Salfred do_close = 1; 953184610Salfred } else { 954184610Salfred do_close = 0; 955184610Salfred } 956188622Sthompsa error = pdev->methods->get_config_desc_full(pdev, 957184610Salfred &ptr, &len, configIndex); 958184610Salfred 959184610Salfred if (error) { 960184610Salfred goto done; 961184610Salfred } 962184610Salfred /* parse new config descriptor */ 963184610Salfred retval = libusb20_parse_config_desc(ptr); 964184610Salfred 965184610Salfred /* free config descriptor */ 966184610Salfred free(ptr); 967184610Salfred 968184610Salfreddone: 969184610Salfred if (do_close) { 970184610Salfred error = libusb20_dev_close(pdev); 971184610Salfred } 972184610Salfred return (retval); 973184610Salfred} 974184610Salfred 975184610Salfredstruct libusb20_device * 976184610Salfredlibusb20_dev_alloc(void) 977184610Salfred{ 978184610Salfred struct libusb20_device *pdev; 979184610Salfred 980184610Salfred pdev = malloc(sizeof(*pdev)); 981184610Salfred if (pdev == NULL) { 982184610Salfred return (NULL); 983184610Salfred } 984184610Salfred memset(pdev, 0, sizeof(*pdev)); 985184610Salfred 986184610Salfred pdev->file = -1; 987184610Salfred pdev->file_ctrl = -1; 988184610Salfred pdev->methods = &libusb20_dummy_methods; 989184610Salfred return (pdev); 990184610Salfred} 991184610Salfred 992184610Salfreduint8_t 993184610Salfredlibusb20_dev_get_config_index(struct libusb20_device *pdev) 994184610Salfred{ 995184610Salfred int error; 996185087Salfred uint8_t cfg_index; 997184610Salfred uint8_t do_close; 998184610Salfred 999184610Salfred if (!pdev->is_opened) { 1000184610Salfred error = libusb20_dev_open(pdev, 0); 1001184610Salfred if (error == 0) { 1002184610Salfred do_close = 1; 1003184610Salfred } else { 1004184610Salfred do_close = 0; 1005184610Salfred } 1006184610Salfred } else { 1007184610Salfred do_close = 0; 1008184610Salfred } 1009184610Salfred 1010188622Sthompsa error = pdev->methods->get_config_index(pdev, &cfg_index); 1011234491Shselasky if (error) 1012234491Shselasky cfg_index = 0xFF; /* current config index */ 1013184610Salfred if (do_close) { 1014184610Salfred if (libusb20_dev_close(pdev)) { 1015184610Salfred /* ignore */ 1016184610Salfred } 1017184610Salfred } 1018185087Salfred return (cfg_index); 1019184610Salfred} 1020184610Salfred 1021184610Salfreduint8_t 1022184610Salfredlibusb20_dev_get_mode(struct libusb20_device *pdev) 1023184610Salfred{ 1024184610Salfred return (pdev->usb_mode); 1025184610Salfred} 1026184610Salfred 1027184610Salfreduint8_t 1028184610Salfredlibusb20_dev_get_speed(struct libusb20_device *pdev) 1029184610Salfred{ 1030184610Salfred return (pdev->usb_speed); 1031184610Salfred} 1032184610Salfred 1033356399Shselaskyint 1034356399Shselaskylibusb20_dev_get_stats(struct libusb20_device *pdev, struct libusb20_device_stats *pstats) 1035356399Shselasky{ 1036356399Shselasky uint8_t do_close; 1037356399Shselasky int error; 1038356399Shselasky 1039356399Shselasky if (!pdev->is_opened) { 1040356399Shselasky error = libusb20_dev_open(pdev, 0); 1041356399Shselasky if (error == 0) { 1042356399Shselasky do_close = 1; 1043356399Shselasky } else { 1044356399Shselasky do_close = 0; 1045356399Shselasky } 1046356399Shselasky } else { 1047356399Shselasky do_close = 0; 1048356399Shselasky } 1049356399Shselasky 1050356399Shselasky error = pdev->methods->get_stats(pdev, pstats); 1051356399Shselasky 1052356399Shselasky if (do_close) 1053356399Shselasky (void) libusb20_dev_close(pdev); 1054356399Shselasky 1055356399Shselasky return (error); 1056356399Shselasky} 1057356399Shselasky 1058184610Salfred/* if this function returns an error, the device is gone */ 1059184610Salfredint 1060184610Salfredlibusb20_dev_process(struct libusb20_device *pdev) 1061184610Salfred{ 1062184610Salfred int error; 1063184610Salfred 1064188622Sthompsa error = pdev->methods->process(pdev); 1065184610Salfred return (error); 1066184610Salfred} 1067184610Salfred 1068184610Salfredvoid 1069184610Salfredlibusb20_dev_wait_process(struct libusb20_device *pdev, int timeout) 1070184610Salfred{ 1071185087Salfred struct pollfd pfd[1]; 1072184610Salfred 1073184610Salfred if (!pdev->is_opened) { 1074184610Salfred return; 1075184610Salfred } 1076184610Salfred pfd[0].fd = pdev->file; 1077184610Salfred pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 1078184610Salfred pfd[0].revents = 0; 1079184610Salfred 1080185087Salfred if (poll(pfd, 1, timeout)) { 1081184610Salfred /* ignore any error */ 1082184610Salfred } 1083184610Salfred return; 1084184610Salfred} 1085184610Salfred 1086184610Salfredvoid 1087184610Salfredlibusb20_dev_free(struct libusb20_device *pdev) 1088184610Salfred{ 1089184610Salfred if (pdev == NULL) { 1090184610Salfred /* be NULL safe */ 1091184610Salfred return; 1092184610Salfred } 1093184610Salfred if (pdev->is_opened) { 1094184610Salfred if (libusb20_dev_close(pdev)) { 1095184610Salfred /* ignore any errors */ 1096184610Salfred } 1097184610Salfred } 1098184610Salfred free(pdev); 1099184610Salfred return; 1100184610Salfred} 1101184610Salfred 1102188622Sthompsaint 1103188622Sthompsalibusb20_dev_get_info(struct libusb20_device *pdev, 1104192984Sthompsa struct usb_device_info *pinfo) 1105188622Sthompsa{ 1106188622Sthompsa if (pinfo == NULL) 1107188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 1108188622Sthompsa 1109188622Sthompsa return (pdev->beMethods->dev_get_info(pdev, pinfo)); 1110188622Sthompsa} 1111188622Sthompsa 1112184610Salfredconst char * 1113184610Salfredlibusb20_dev_get_backend_name(struct libusb20_device *pdev) 1114184610Salfred{ 1115188622Sthompsa return (pdev->beMethods->get_backend_name()); 1116184610Salfred} 1117184610Salfred 1118184610Salfredconst char * 1119184610Salfredlibusb20_dev_get_desc(struct libusb20_device *pdev) 1120184610Salfred{ 1121184610Salfred return (pdev->usb_desc); 1122184610Salfred} 1123184610Salfred 1124184610Salfredvoid 1125184610Salfredlibusb20_dev_set_debug(struct libusb20_device *pdev, int debug) 1126184610Salfred{ 1127184610Salfred pdev->debug = debug; 1128184610Salfred return; 1129184610Salfred} 1130184610Salfred 1131184610Salfredint 1132184610Salfredlibusb20_dev_get_debug(struct libusb20_device *pdev) 1133184610Salfred{ 1134184610Salfred return (pdev->debug); 1135184610Salfred} 1136184610Salfred 1137184610Salfreduint8_t 1138184610Salfredlibusb20_dev_get_address(struct libusb20_device *pdev) 1139184610Salfred{ 1140184610Salfred return (pdev->device_address); 1141184610Salfred} 1142184610Salfred 1143184610Salfreduint8_t 1144223495Shselaskylibusb20_dev_get_parent_address(struct libusb20_device *pdev) 1145223495Shselasky{ 1146223495Shselasky return (pdev->parent_address); 1147223495Shselasky} 1148223495Shselasky 1149223495Shselaskyuint8_t 1150223495Shselaskylibusb20_dev_get_parent_port(struct libusb20_device *pdev) 1151223495Shselasky{ 1152223495Shselasky return (pdev->parent_port); 1153223495Shselasky} 1154223495Shselasky 1155223495Shselaskyuint8_t 1156184610Salfredlibusb20_dev_get_bus_number(struct libusb20_device *pdev) 1157184610Salfred{ 1158184610Salfred return (pdev->bus_number); 1159184610Salfred} 1160184610Salfred 1161184610Salfredint 1162188622Sthompsalibusb20_dev_get_iface_desc(struct libusb20_device *pdev, 1163188622Sthompsa uint8_t iface_index, char *buf, uint8_t len) 1164188622Sthompsa{ 1165188622Sthompsa if ((buf == NULL) || (len == 0)) 1166188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 1167188622Sthompsa 1168224085Shselasky buf[0] = 0; /* set default string value */ 1169224085Shselasky 1170188622Sthompsa return (pdev->beMethods->dev_get_iface_desc( 1171188622Sthompsa pdev, iface_index, buf, len)); 1172188622Sthompsa} 1173188622Sthompsa 1174184610Salfred/* USB backend operations */ 1175184610Salfred 1176184610Salfredint 1177184610Salfredlibusb20_be_get_dev_quirk(struct libusb20_backend *pbe, 1178185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 1179184610Salfred{ 1180188622Sthompsa return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq)); 1181184610Salfred} 1182184610Salfred 1183184610Salfredint 1184184610Salfredlibusb20_be_get_quirk_name(struct libusb20_backend *pbe, 1185185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 1186184610Salfred{ 1187188622Sthompsa return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq)); 1188184610Salfred} 1189184610Salfred 1190184610Salfredint 1191184610Salfredlibusb20_be_add_dev_quirk(struct libusb20_backend *pbe, 1192184610Salfred struct libusb20_quirk *pq) 1193184610Salfred{ 1194188622Sthompsa return (pbe->methods->root_add_dev_quirk(pbe, pq)); 1195184610Salfred} 1196184610Salfred 1197184610Salfredint 1198184610Salfredlibusb20_be_remove_dev_quirk(struct libusb20_backend *pbe, 1199184610Salfred struct libusb20_quirk *pq) 1200184610Salfred{ 1201188622Sthompsa return (pbe->methods->root_remove_dev_quirk(pbe, pq)); 1202184610Salfred} 1203184610Salfred 1204184610Salfredint 1205188987Sthompsalibusb20_be_set_template(struct libusb20_backend *pbe, int temp) 1206188987Sthompsa{ 1207188987Sthompsa return (pbe->methods->root_set_template(pbe, temp)); 1208188987Sthompsa} 1209188987Sthompsa 1210188987Sthompsaint 1211188987Sthompsalibusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp) 1212188987Sthompsa{ 1213188987Sthompsa int temp; 1214188987Sthompsa 1215188987Sthompsa if (ptemp == NULL) 1216188987Sthompsa ptemp = &temp; 1217188987Sthompsa 1218188987Sthompsa return (pbe->methods->root_get_template(pbe, ptemp)); 1219188987Sthompsa} 1220188987Sthompsa 1221184610Salfredstruct libusb20_device * 1222184610Salfredlibusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1223184610Salfred{ 1224184610Salfred if (pbe == NULL) { 1225184610Salfred pdev = NULL; 1226184610Salfred } else if (pdev == NULL) { 1227184610Salfred pdev = TAILQ_FIRST(&(pbe->usb_devs)); 1228184610Salfred } else { 1229184610Salfred pdev = TAILQ_NEXT(pdev, dev_entry); 1230184610Salfred } 1231184610Salfred return (pdev); 1232184610Salfred} 1233184610Salfred 1234184610Salfredstruct libusb20_backend * 1235184610Salfredlibusb20_be_alloc(const struct libusb20_backend_methods *methods) 1236184610Salfred{ 1237184610Salfred struct libusb20_backend *pbe; 1238184610Salfred 1239184610Salfred pbe = malloc(sizeof(*pbe)); 1240184610Salfred if (pbe == NULL) { 1241184610Salfred return (NULL); 1242184610Salfred } 1243184610Salfred memset(pbe, 0, sizeof(*pbe)); 1244184610Salfred 1245184610Salfred TAILQ_INIT(&(pbe->usb_devs)); 1246184610Salfred 1247184610Salfred pbe->methods = methods; /* set backend methods */ 1248184610Salfred 1249184610Salfred /* do the initial device scan */ 1250184610Salfred if (pbe->methods->init_backend) { 1251188622Sthompsa pbe->methods->init_backend(pbe); 1252184610Salfred } 1253184610Salfred return (pbe); 1254184610Salfred} 1255184610Salfred 1256184610Salfredstruct libusb20_backend * 1257184610Salfredlibusb20_be_alloc_linux(void) 1258184610Salfred{ 1259253339Shselasky return (NULL); 1260184610Salfred} 1261184610Salfred 1262184610Salfredstruct libusb20_backend * 1263184610Salfredlibusb20_be_alloc_ugen20(void) 1264184610Salfred{ 1265253339Shselasky return (libusb20_be_alloc(&libusb20_ugen20_backend)); 1266184610Salfred} 1267184610Salfred 1268184610Salfredstruct libusb20_backend * 1269184610Salfredlibusb20_be_alloc_default(void) 1270184610Salfred{ 1271184610Salfred struct libusb20_backend *pbe; 1272184610Salfred 1273253339Shselasky#ifdef __linux__ 1274184610Salfred pbe = libusb20_be_alloc_linux(); 1275184610Salfred if (pbe) { 1276184610Salfred return (pbe); 1277184610Salfred } 1278253339Shselasky#endif 1279184610Salfred pbe = libusb20_be_alloc_ugen20(); 1280184610Salfred if (pbe) { 1281184610Salfred return (pbe); 1282184610Salfred } 1283184610Salfred return (NULL); /* no backend found */ 1284184610Salfred} 1285184610Salfred 1286184610Salfredvoid 1287184610Salfredlibusb20_be_free(struct libusb20_backend *pbe) 1288184610Salfred{ 1289184610Salfred struct libusb20_device *pdev; 1290184610Salfred 1291184610Salfred if (pbe == NULL) { 1292184610Salfred /* be NULL safe */ 1293184610Salfred return; 1294184610Salfred } 1295184610Salfred while ((pdev = libusb20_be_device_foreach(pbe, NULL))) { 1296184610Salfred libusb20_be_dequeue_device(pbe, pdev); 1297184610Salfred libusb20_dev_free(pdev); 1298184610Salfred } 1299184610Salfred if (pbe->methods->exit_backend) { 1300188622Sthompsa pbe->methods->exit_backend(pbe); 1301184610Salfred } 1302199055Sthompsa /* free backend */ 1303199055Sthompsa free(pbe); 1304184610Salfred} 1305184610Salfred 1306184610Salfredvoid 1307184610Salfredlibusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1308184610Salfred{ 1309184610Salfred pdev->beMethods = pbe->methods; /* copy backend methods */ 1310184610Salfred TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry); 1311184610Salfred} 1312184610Salfred 1313184610Salfredvoid 1314184610Salfredlibusb20_be_dequeue_device(struct libusb20_backend *pbe, 1315184610Salfred struct libusb20_device *pdev) 1316184610Salfred{ 1317184610Salfred TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry); 1318184610Salfred} 1319225659Shselasky 1320225659Shselaskyconst char * 1321225659Shselaskylibusb20_strerror(int code) 1322225659Shselasky{ 1323225659Shselasky switch (code) { 1324225659Shselasky case LIBUSB20_SUCCESS: 1325225659Shselasky return ("Success"); 1326225659Shselasky case LIBUSB20_ERROR_IO: 1327225659Shselasky return ("I/O error"); 1328225659Shselasky case LIBUSB20_ERROR_INVALID_PARAM: 1329225659Shselasky return ("Invalid parameter"); 1330225659Shselasky case LIBUSB20_ERROR_ACCESS: 1331225659Shselasky return ("Permissions error"); 1332225659Shselasky case LIBUSB20_ERROR_NO_DEVICE: 1333225659Shselasky return ("No device"); 1334225659Shselasky case LIBUSB20_ERROR_NOT_FOUND: 1335225659Shselasky return ("Not found"); 1336225659Shselasky case LIBUSB20_ERROR_BUSY: 1337225659Shselasky return ("Device busy"); 1338225659Shselasky case LIBUSB20_ERROR_TIMEOUT: 1339225659Shselasky return ("Timeout"); 1340225659Shselasky case LIBUSB20_ERROR_OVERFLOW: 1341225659Shselasky return ("Overflow"); 1342225659Shselasky case LIBUSB20_ERROR_PIPE: 1343225659Shselasky return ("Pipe error"); 1344225659Shselasky case LIBUSB20_ERROR_INTERRUPTED: 1345225659Shselasky return ("Interrupted"); 1346225659Shselasky case LIBUSB20_ERROR_NO_MEM: 1347225659Shselasky return ("Out of memory"); 1348225659Shselasky case LIBUSB20_ERROR_NOT_SUPPORTED: 1349225659Shselasky return ("Not supported"); 1350225659Shselasky case LIBUSB20_ERROR_OTHER: 1351225659Shselasky return ("Other error"); 1352225659Shselasky default: 1353225659Shselasky return ("Unknown error"); 1354225659Shselasky } 1355225659Shselasky} 1356225659Shselasky 1357225659Shselaskyconst char * 1358225659Shselaskylibusb20_error_name(int code) 1359225659Shselasky{ 1360225659Shselasky switch (code) { 1361225659Shselasky case LIBUSB20_SUCCESS: 1362225659Shselasky return ("LIBUSB20_SUCCESS"); 1363225659Shselasky case LIBUSB20_ERROR_IO: 1364225659Shselasky return ("LIBUSB20_ERROR_IO"); 1365225659Shselasky case LIBUSB20_ERROR_INVALID_PARAM: 1366225659Shselasky return ("LIBUSB20_ERROR_INVALID_PARAM"); 1367225659Shselasky case LIBUSB20_ERROR_ACCESS: 1368225659Shselasky return ("LIBUSB20_ERROR_ACCESS"); 1369225659Shselasky case LIBUSB20_ERROR_NO_DEVICE: 1370225659Shselasky return ("LIBUSB20_ERROR_NO_DEVICE"); 1371225659Shselasky case LIBUSB20_ERROR_NOT_FOUND: 1372225659Shselasky return ("LIBUSB20_ERROR_NOT_FOUND"); 1373225659Shselasky case LIBUSB20_ERROR_BUSY: 1374225659Shselasky return ("LIBUSB20_ERROR_BUSY"); 1375225659Shselasky case LIBUSB20_ERROR_TIMEOUT: 1376225659Shselasky return ("LIBUSB20_ERROR_TIMEOUT"); 1377225659Shselasky case LIBUSB20_ERROR_OVERFLOW: 1378225659Shselasky return ("LIBUSB20_ERROR_OVERFLOW"); 1379225659Shselasky case LIBUSB20_ERROR_PIPE: 1380225659Shselasky return ("LIBUSB20_ERROR_PIPE"); 1381225659Shselasky case LIBUSB20_ERROR_INTERRUPTED: 1382225659Shselasky return ("LIBUSB20_ERROR_INTERRUPTED"); 1383225659Shselasky case LIBUSB20_ERROR_NO_MEM: 1384225659Shselasky return ("LIBUSB20_ERROR_NO_MEM"); 1385225659Shselasky case LIBUSB20_ERROR_NOT_SUPPORTED: 1386225659Shselasky return ("LIBUSB20_ERROR_NOT_SUPPORTED"); 1387225659Shselasky case LIBUSB20_ERROR_OTHER: 1388225659Shselasky return ("LIBUSB20_ERROR_OTHER"); 1389225659Shselasky default: 1390225659Shselasky return ("LIBUSB20_ERROR_UNKNOWN"); 1391225659Shselasky } 1392225659Shselasky} 1393