1184610Salfred/* $FreeBSD: stable/11/lib/libusb/libusb20.c 356398 2020-01-06 09:21:15Z 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 78246789Shselasky#define dummy_get_power_usage (void *)dummy_int 79356398Shselasky#define dummy_get_stats (void *)dummy_int 80184610Salfred#define dummy_kernel_driver_active (void *)dummy_int 81184610Salfred#define dummy_detach_kernel_driver (void *)dummy_int 82184610Salfred#define dummy_do_request_sync (void *)dummy_int 83184610Salfred#define dummy_tr_open (void *)dummy_int 84184610Salfred#define dummy_tr_close (void *)dummy_int 85184610Salfred#define dummy_tr_clear_stall_sync (void *)dummy_int 86184610Salfred#define dummy_process (void *)dummy_int 87188622Sthompsa#define dummy_dev_info (void *)dummy_int 88188622Sthompsa#define dummy_dev_get_iface_driver (void *)dummy_int 89184610Salfred 90184610Salfred#define dummy_tr_submit (void *)dummy_void 91184610Salfred#define dummy_tr_cancel_async (void *)dummy_void 92184610Salfred 93184610Salfredstatic const struct libusb20_device_methods libusb20_dummy_methods = { 94184610Salfred LIBUSB20_DEVICE(LIBUSB20_DECLARE, dummy) 95184610Salfred}; 96184610Salfred 97184610Salfredvoid 98184610Salfredlibusb20_tr_callback_wrapper(struct libusb20_transfer *xfer) 99184610Salfred{ 100184610Salfred ; /* style fix */ 101184610Salfred 102184610Salfredrepeat: 103184610Salfred 104184610Salfred if (!xfer->is_pending) { 105184610Salfred xfer->status = LIBUSB20_TRANSFER_START; 106184610Salfred } else { 107184610Salfred xfer->is_pending = 0; 108184610Salfred } 109184610Salfred 110188622Sthompsa xfer->callback(xfer); 111184610Salfred 112184610Salfred if (xfer->is_restart) { 113184610Salfred xfer->is_restart = 0; 114184610Salfred goto repeat; 115184610Salfred } 116184610Salfred if (xfer->is_draining && 117184610Salfred (!xfer->is_pending)) { 118184610Salfred xfer->is_draining = 0; 119184610Salfred xfer->status = LIBUSB20_TRANSFER_DRAINED; 120188622Sthompsa xfer->callback(xfer); 121184610Salfred } 122184610Salfred return; 123184610Salfred} 124184610Salfred 125184610Salfredint 126184610Salfredlibusb20_tr_close(struct libusb20_transfer *xfer) 127184610Salfred{ 128184610Salfred int error; 129184610Salfred 130184610Salfred if (!xfer->is_opened) { 131184610Salfred return (LIBUSB20_ERROR_OTHER); 132184610Salfred } 133188622Sthompsa error = xfer->pdev->methods->tr_close(xfer); 134184610Salfred 135184610Salfred if (xfer->pLength) { 136184610Salfred free(xfer->pLength); 137184610Salfred } 138184610Salfred if (xfer->ppBuffer) { 139184610Salfred free(xfer->ppBuffer); 140184610Salfred } 141202025Sthompsa /* reset variable fields in case the transfer is opened again */ 142297764Spfg xfer->priv_sc0 = NULL; 143297764Spfg xfer->priv_sc1 = NULL; 144184610Salfred xfer->is_opened = 0; 145202025Sthompsa xfer->is_pending = 0; 146202025Sthompsa xfer->is_cancel = 0; 147202025Sthompsa xfer->is_draining = 0; 148202025Sthompsa xfer->is_restart = 0; 149202025Sthompsa xfer->status = 0; 150202025Sthompsa xfer->flags = 0; 151202025Sthompsa xfer->nFrames = 0; 152202025Sthompsa xfer->aFrames = 0; 153202025Sthompsa xfer->timeout = 0; 154184610Salfred xfer->maxFrames = 0; 155184610Salfred xfer->maxTotalLength = 0; 156184610Salfred xfer->maxPacketLen = 0; 157184610Salfred return (error); 158184610Salfred} 159184610Salfred 160184610Salfredint 161184610Salfredlibusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 162184610Salfred uint32_t MaxFrameCount, uint8_t ep_no) 163184610Salfred{ 164239239Shselasky return (libusb20_tr_open_stream(xfer, MaxBufSize, MaxFrameCount, ep_no, 0)); 165239239Shselasky} 166239239Shselasky 167239239Shselaskyint 168239239Shselaskylibusb20_tr_open_stream(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 169239239Shselasky uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id) 170239239Shselasky{ 171184610Salfred uint32_t size; 172219100Shselasky uint8_t pre_scale; 173184610Salfred int error; 174184610Salfred 175219100Shselasky if (xfer->is_opened) 176184610Salfred return (LIBUSB20_ERROR_BUSY); 177219100Shselasky if (MaxFrameCount & LIBUSB20_MAX_FRAME_PRE_SCALE) { 178219100Shselasky MaxFrameCount &= ~LIBUSB20_MAX_FRAME_PRE_SCALE; 179305640Shselasky /* 180305640Shselasky * The kernel can setup 8 times more frames when 181305640Shselasky * pre-scaling ISOCHRONOUS transfers. Make sure the 182305640Shselasky * length and pointer buffers are big enough: 183305640Shselasky */ 184305640Shselasky MaxFrameCount *= 8; 185219100Shselasky pre_scale = 1; 186219100Shselasky } else { 187219100Shselasky pre_scale = 0; 188184610Salfred } 189219100Shselasky if (MaxFrameCount == 0) 190184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 191219100Shselasky 192184610Salfred xfer->maxFrames = MaxFrameCount; 193184610Salfred 194184610Salfred size = MaxFrameCount * sizeof(xfer->pLength[0]); 195184610Salfred xfer->pLength = malloc(size); 196184610Salfred if (xfer->pLength == NULL) { 197184610Salfred return (LIBUSB20_ERROR_NO_MEM); 198184610Salfred } 199184610Salfred memset(xfer->pLength, 0, size); 200184610Salfred 201184610Salfred size = MaxFrameCount * sizeof(xfer->ppBuffer[0]); 202184610Salfred xfer->ppBuffer = malloc(size); 203184610Salfred if (xfer->ppBuffer == NULL) { 204184610Salfred free(xfer->pLength); 205184610Salfred return (LIBUSB20_ERROR_NO_MEM); 206184610Salfred } 207184610Salfred memset(xfer->ppBuffer, 0, size); 208184610Salfred 209305640Shselasky if (pre_scale) { 210305640Shselasky error = xfer->pdev->methods->tr_open(xfer, MaxBufSize, 211305640Shselasky MaxFrameCount / 8, ep_no, stream_id, 1); 212305640Shselasky } else { 213305640Shselasky error = xfer->pdev->methods->tr_open(xfer, MaxBufSize, 214305640Shselasky MaxFrameCount, ep_no, stream_id, 0); 215305640Shselasky } 216184610Salfred 217184610Salfred if (error) { 218184610Salfred free(xfer->ppBuffer); 219184610Salfred free(xfer->pLength); 220184610Salfred } else { 221184610Salfred xfer->is_opened = 1; 222184610Salfred } 223184610Salfred return (error); 224184610Salfred} 225184610Salfred 226184610Salfredstruct libusb20_transfer * 227184610Salfredlibusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex) 228184610Salfred{ 229184610Salfred if (trIndex >= pdev->nTransfer) { 230184610Salfred return (NULL); 231184610Salfred } 232184610Salfred return (pdev->pTransfer + trIndex); 233184610Salfred} 234184610Salfred 235184610Salfreduint32_t 236184610Salfredlibusb20_tr_get_actual_frames(struct libusb20_transfer *xfer) 237184610Salfred{ 238184610Salfred return (xfer->aFrames); 239184610Salfred} 240184610Salfred 241184610Salfreduint16_t 242184610Salfredlibusb20_tr_get_time_complete(struct libusb20_transfer *xfer) 243184610Salfred{ 244184610Salfred return (xfer->timeComplete); 245184610Salfred} 246184610Salfred 247184610Salfreduint32_t 248184610Salfredlibusb20_tr_get_actual_length(struct libusb20_transfer *xfer) 249184610Salfred{ 250184610Salfred uint32_t x; 251184610Salfred uint32_t actlen = 0; 252184610Salfred 253184610Salfred for (x = 0; x != xfer->aFrames; x++) { 254184610Salfred actlen += xfer->pLength[x]; 255184610Salfred } 256184610Salfred return (actlen); 257184610Salfred} 258184610Salfred 259184610Salfreduint32_t 260184610Salfredlibusb20_tr_get_max_frames(struct libusb20_transfer *xfer) 261184610Salfred{ 262184610Salfred return (xfer->maxFrames); 263184610Salfred} 264184610Salfred 265184610Salfreduint32_t 266184610Salfredlibusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer) 267184610Salfred{ 268184610Salfred /* 269184610Salfred * Special Case NOTE: If the packet multiplier is non-zero for 270184610Salfred * High Speed USB, the value returned is equal to 271184610Salfred * "wMaxPacketSize * multiplier" ! 272184610Salfred */ 273184610Salfred return (xfer->maxPacketLen); 274184610Salfred} 275184610Salfred 276184610Salfreduint32_t 277184610Salfredlibusb20_tr_get_max_total_length(struct libusb20_transfer *xfer) 278184610Salfred{ 279184610Salfred return (xfer->maxTotalLength); 280184610Salfred} 281184610Salfred 282184610Salfreduint8_t 283184610Salfredlibusb20_tr_get_status(struct libusb20_transfer *xfer) 284184610Salfred{ 285184610Salfred return (xfer->status); 286184610Salfred} 287184610Salfred 288184610Salfreduint8_t 289184610Salfredlibusb20_tr_pending(struct libusb20_transfer *xfer) 290184610Salfred{ 291184610Salfred return (xfer->is_pending); 292184610Salfred} 293184610Salfred 294184610Salfredvoid * 295184610Salfredlibusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer) 296184610Salfred{ 297184610Salfred return (xfer->priv_sc0); 298184610Salfred} 299184610Salfred 300184610Salfredvoid * 301184610Salfredlibusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer) 302184610Salfred{ 303184610Salfred return (xfer->priv_sc1); 304184610Salfred} 305184610Salfred 306184610Salfredvoid 307184610Salfredlibusb20_tr_stop(struct libusb20_transfer *xfer) 308184610Salfred{ 309199575Sthompsa if (!xfer->is_opened) { 310199575Sthompsa /* transfer is not opened */ 311199575Sthompsa return; 312199575Sthompsa } 313184610Salfred if (!xfer->is_pending) { 314184610Salfred /* transfer not pending */ 315184610Salfred return; 316184610Salfred } 317184610Salfred if (xfer->is_cancel) { 318184610Salfred /* already cancelling */ 319184610Salfred return; 320184610Salfred } 321184610Salfred xfer->is_cancel = 1; /* we are cancelling */ 322184610Salfred 323188622Sthompsa xfer->pdev->methods->tr_cancel_async(xfer); 324184610Salfred return; 325184610Salfred} 326184610Salfred 327184610Salfredvoid 328184610Salfredlibusb20_tr_drain(struct libusb20_transfer *xfer) 329184610Salfred{ 330199575Sthompsa if (!xfer->is_opened) { 331199575Sthompsa /* transfer is not opened */ 332199575Sthompsa return; 333199575Sthompsa } 334184610Salfred /* make sure that we are cancelling */ 335184610Salfred libusb20_tr_stop(xfer); 336184610Salfred 337184610Salfred if (xfer->is_pending) { 338184610Salfred xfer->is_draining = 1; 339184610Salfred } 340184610Salfred return; 341184610Salfred} 342184610Salfred 343184610Salfredvoid 344184610Salfredlibusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 345184610Salfred{ 346188622Sthompsa xfer->pdev->methods->tr_clear_stall_sync(xfer); 347184610Salfred return; 348184610Salfred} 349184610Salfred 350184610Salfredvoid 351184610Salfredlibusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex) 352184610Salfred{ 353213852Shselasky xfer->ppBuffer[frIndex] = libusb20_pass_ptr(buffer); 354184610Salfred return; 355184610Salfred} 356184610Salfred 357184610Salfredvoid 358184610Salfredlibusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb) 359184610Salfred{ 360184610Salfred xfer->callback = cb; 361184610Salfred return; 362184610Salfred} 363184610Salfred 364184610Salfredvoid 365184610Salfredlibusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags) 366184610Salfred{ 367184610Salfred xfer->flags = flags; 368184610Salfred return; 369184610Salfred} 370184610Salfred 371193313Sthompsauint32_t 372193313Sthompsalibusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex) 373193313Sthompsa{ 374193313Sthompsa return (xfer->pLength[frIndex]); 375193313Sthompsa} 376193313Sthompsa 377184610Salfredvoid 378184610Salfredlibusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex) 379184610Salfred{ 380184610Salfred xfer->pLength[frIndex] = length; 381184610Salfred return; 382184610Salfred} 383184610Salfred 384184610Salfredvoid 385184610Salfredlibusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0) 386184610Salfred{ 387184610Salfred xfer->priv_sc0 = sc0; 388184610Salfred return; 389184610Salfred} 390184610Salfred 391184610Salfredvoid 392184610Salfredlibusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1) 393184610Salfred{ 394184610Salfred xfer->priv_sc1 = sc1; 395184610Salfred return; 396184610Salfred} 397184610Salfred 398184610Salfredvoid 399184610Salfredlibusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout) 400184610Salfred{ 401184610Salfred xfer->timeout = timeout; 402184610Salfred return; 403184610Salfred} 404184610Salfred 405184610Salfredvoid 406184610Salfredlibusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames) 407184610Salfred{ 408184610Salfred if (nFrames > xfer->maxFrames) { 409184610Salfred /* should not happen */ 410184610Salfred nFrames = xfer->maxFrames; 411184610Salfred } 412184610Salfred xfer->nFrames = nFrames; 413184610Salfred return; 414184610Salfred} 415184610Salfred 416184610Salfredvoid 417184610Salfredlibusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 418184610Salfred{ 419213852Shselasky xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf); 420184610Salfred xfer->pLength[0] = length; 421184610Salfred xfer->timeout = timeout; 422184610Salfred xfer->nFrames = 1; 423184610Salfred return; 424184610Salfred} 425184610Salfred 426184610Salfredvoid 427184610Salfredlibusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout) 428184610Salfred{ 429184610Salfred uint16_t len; 430184610Salfred 431213852Shselasky xfer->ppBuffer[0] = libusb20_pass_ptr(psetup); 432184610Salfred xfer->pLength[0] = 8; /* fixed */ 433184610Salfred xfer->timeout = timeout; 434184610Salfred 435184610Salfred len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8); 436184610Salfred 437184610Salfred if (len != 0) { 438184610Salfred xfer->nFrames = 2; 439213852Shselasky xfer->ppBuffer[1] = libusb20_pass_ptr(pBuf); 440184610Salfred xfer->pLength[1] = len; 441184610Salfred } else { 442184610Salfred xfer->nFrames = 1; 443184610Salfred } 444184610Salfred return; 445184610Salfred} 446184610Salfred 447184610Salfredvoid 448184610Salfredlibusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 449184610Salfred{ 450213852Shselasky xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf); 451184610Salfred xfer->pLength[0] = length; 452184610Salfred xfer->timeout = timeout; 453184610Salfred xfer->nFrames = 1; 454184610Salfred return; 455184610Salfred} 456184610Salfred 457184610Salfredvoid 458184610Salfredlibusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex) 459184610Salfred{ 460184610Salfred if (frIndex >= xfer->maxFrames) { 461184610Salfred /* should not happen */ 462184610Salfred return; 463184610Salfred } 464213852Shselasky xfer->ppBuffer[frIndex] = libusb20_pass_ptr(pBuf); 465184610Salfred xfer->pLength[frIndex] = length; 466184610Salfred return; 467184610Salfred} 468184610Salfred 469199575Sthompsauint8_t 470199575Sthompsalibusb20_tr_bulk_intr_sync(struct libusb20_transfer *xfer, 471199575Sthompsa void *pbuf, uint32_t length, uint32_t *pactlen, 472199575Sthompsa uint32_t timeout) 473199575Sthompsa{ 474199575Sthompsa struct libusb20_device *pdev = xfer->pdev; 475199575Sthompsa uint32_t transfer_max; 476199575Sthompsa uint32_t transfer_act; 477199575Sthompsa uint8_t retval; 478199575Sthompsa 479199575Sthompsa /* set some sensible default value */ 480199575Sthompsa if (pactlen != NULL) 481199575Sthompsa *pactlen = 0; 482199575Sthompsa 483199575Sthompsa /* check for error condition */ 484199575Sthompsa if (libusb20_tr_pending(xfer)) 485199575Sthompsa return (LIBUSB20_ERROR_OTHER); 486199575Sthompsa 487199575Sthompsa do { 488199575Sthompsa /* compute maximum transfer length */ 489199575Sthompsa transfer_max = 490199575Sthompsa libusb20_tr_get_max_total_length(xfer); 491199575Sthompsa 492199575Sthompsa if (transfer_max > length) 493199575Sthompsa transfer_max = length; 494199575Sthompsa 495199575Sthompsa /* setup bulk or interrupt transfer */ 496199575Sthompsa libusb20_tr_setup_bulk(xfer, pbuf, 497199575Sthompsa transfer_max, timeout); 498199575Sthompsa 499199575Sthompsa /* start the transfer */ 500199575Sthompsa libusb20_tr_start(xfer); 501199575Sthompsa 502199575Sthompsa /* wait for transfer completion */ 503199575Sthompsa while (libusb20_dev_process(pdev) == 0) { 504199575Sthompsa 505199575Sthompsa if (libusb20_tr_pending(xfer) == 0) 506199575Sthompsa break; 507199575Sthompsa 508199575Sthompsa libusb20_dev_wait_process(pdev, -1); 509199575Sthompsa } 510199575Sthompsa 511199575Sthompsa transfer_act = libusb20_tr_get_actual_length(xfer); 512199575Sthompsa 513199575Sthompsa /* update actual length, if any */ 514199575Sthompsa if (pactlen != NULL) 515199575Sthompsa pactlen[0] += transfer_act; 516199575Sthompsa 517199575Sthompsa /* check transfer status */ 518199575Sthompsa retval = libusb20_tr_get_status(xfer); 519199575Sthompsa if (retval) 520199575Sthompsa break; 521199575Sthompsa 522199575Sthompsa /* check for short transfer */ 523199575Sthompsa if (transfer_act != transfer_max) 524199575Sthompsa break; 525199575Sthompsa 526199575Sthompsa /* update buffer pointer and length */ 527199575Sthompsa pbuf = ((uint8_t *)pbuf) + transfer_max; 528199575Sthompsa length = length - transfer_max; 529199575Sthompsa 530199575Sthompsa } while (length != 0); 531199575Sthompsa 532199575Sthompsa return (retval); 533199575Sthompsa} 534199575Sthompsa 535184610Salfredvoid 536184610Salfredlibusb20_tr_submit(struct libusb20_transfer *xfer) 537184610Salfred{ 538199575Sthompsa if (!xfer->is_opened) { 539199575Sthompsa /* transfer is not opened */ 540199575Sthompsa return; 541199575Sthompsa } 542184610Salfred if (xfer->is_pending) { 543184610Salfred /* should not happen */ 544184610Salfred return; 545184610Salfred } 546184610Salfred xfer->is_pending = 1; /* we are pending */ 547184610Salfred xfer->is_cancel = 0; /* not cancelling */ 548184610Salfred xfer->is_restart = 0; /* not restarting */ 549184610Salfred 550188622Sthompsa xfer->pdev->methods->tr_submit(xfer); 551184610Salfred return; 552184610Salfred} 553184610Salfred 554184610Salfredvoid 555184610Salfredlibusb20_tr_start(struct libusb20_transfer *xfer) 556184610Salfred{ 557199575Sthompsa if (!xfer->is_opened) { 558199575Sthompsa /* transfer is not opened */ 559199575Sthompsa return; 560199575Sthompsa } 561184610Salfred if (xfer->is_pending) { 562184610Salfred if (xfer->is_cancel) { 563184610Salfred /* cancelling - restart */ 564184610Salfred xfer->is_restart = 1; 565184610Salfred } 566184610Salfred /* transfer not pending */ 567184610Salfred return; 568184610Salfred } 569184610Salfred /* get into the callback */ 570184610Salfred libusb20_tr_callback_wrapper(xfer); 571184610Salfred return; 572184610Salfred} 573184610Salfred 574184610Salfred/* USB device operations */ 575184610Salfred 576184610Salfredint 577184610Salfredlibusb20_dev_close(struct libusb20_device *pdev) 578184610Salfred{ 579184610Salfred struct libusb20_transfer *xfer; 580184610Salfred uint16_t x; 581184610Salfred int error = 0; 582184610Salfred 583184610Salfred if (!pdev->is_opened) { 584184610Salfred return (LIBUSB20_ERROR_OTHER); 585184610Salfred } 586184610Salfred for (x = 0; x != pdev->nTransfer; x++) { 587184610Salfred xfer = pdev->pTransfer + x; 588184610Salfred 589199575Sthompsa if (!xfer->is_opened) { 590199575Sthompsa /* transfer is not opened */ 591199575Sthompsa continue; 592199575Sthompsa } 593199575Sthompsa 594184610Salfred libusb20_tr_drain(xfer); 595199575Sthompsa 596199575Sthompsa libusb20_tr_close(xfer); 597184610Salfred } 598184610Salfred 599184610Salfred if (pdev->pTransfer != NULL) { 600184610Salfred free(pdev->pTransfer); 601184610Salfred pdev->pTransfer = NULL; 602184610Salfred } 603188622Sthompsa error = pdev->beMethods->close_device(pdev); 604184610Salfred 605184610Salfred pdev->methods = &libusb20_dummy_methods; 606184610Salfred 607184610Salfred pdev->is_opened = 0; 608184610Salfred 609194069Sthompsa /* 610194069Sthompsa * The following variable is only used by the libusb v0.1 611194069Sthompsa * compat layer: 612194069Sthompsa */ 613194069Sthompsa pdev->claimed_interface = 0; 614187184Sthompsa 615301966Shselasky /* 616301966Shselasky * The following variable is only used by the libusb v1.0 617301966Shselasky * compat layer: 618301966Shselasky */ 619301966Shselasky pdev->auto_detach = 0; 620301966Shselasky 621184610Salfred return (error); 622184610Salfred} 623184610Salfred 624184610Salfredint 625184610Salfredlibusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex) 626184610Salfred{ 627184610Salfred int error; 628184610Salfred 629188622Sthompsa error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex); 630184610Salfred return (error); 631184610Salfred} 632184610Salfred 633184610Salfredstruct LIBUSB20_DEVICE_DESC_DECODED * 634184610Salfredlibusb20_dev_get_device_desc(struct libusb20_device *pdev) 635184610Salfred{ 636184610Salfred return (&(pdev->ddesc)); 637184610Salfred} 638184610Salfred 639184610Salfredint 640184610Salfredlibusb20_dev_get_fd(struct libusb20_device *pdev) 641184610Salfred{ 642184610Salfred return (pdev->file); 643184610Salfred} 644184610Salfred 645184610Salfredint 646184610Salfredlibusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex) 647184610Salfred{ 648184610Salfred int error; 649184610Salfred 650188622Sthompsa error = pdev->methods->kernel_driver_active(pdev, ifaceIndex); 651184610Salfred return (error); 652184610Salfred} 653184610Salfred 654184610Salfredint 655184610Salfredlibusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax) 656184610Salfred{ 657184610Salfred struct libusb20_transfer *xfer; 658184610Salfred uint32_t size; 659184610Salfred uint16_t x; 660184610Salfred int error; 661184610Salfred 662184610Salfred if (pdev->is_opened) { 663184610Salfred return (LIBUSB20_ERROR_BUSY); 664184610Salfred } 665184610Salfred if (nTransferMax >= 256) { 666184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 667184610Salfred } else if (nTransferMax != 0) { 668184610Salfred size = sizeof(pdev->pTransfer[0]) * nTransferMax; 669184610Salfred pdev->pTransfer = malloc(size); 670184610Salfred if (pdev->pTransfer == NULL) { 671184610Salfred return (LIBUSB20_ERROR_NO_MEM); 672184610Salfred } 673184610Salfred memset(pdev->pTransfer, 0, size); 674184610Salfred } 675184610Salfred /* initialise all transfers */ 676184610Salfred for (x = 0; x != nTransferMax; x++) { 677184610Salfred 678184610Salfred xfer = pdev->pTransfer + x; 679184610Salfred 680184610Salfred xfer->pdev = pdev; 681184610Salfred xfer->trIndex = x; 682184610Salfred xfer->callback = &dummy_callback; 683184610Salfred } 684184610Salfred 685185087Salfred /* set "nTransfer" early */ 686185087Salfred pdev->nTransfer = nTransferMax; 687185087Salfred 688188622Sthompsa error = pdev->beMethods->open_device(pdev, nTransferMax); 689184610Salfred 690184610Salfred if (error) { 691184610Salfred if (pdev->pTransfer != NULL) { 692184610Salfred free(pdev->pTransfer); 693184610Salfred pdev->pTransfer = NULL; 694184610Salfred } 695184610Salfred pdev->file = -1; 696184610Salfred pdev->file_ctrl = -1; 697184610Salfred pdev->nTransfer = 0; 698184610Salfred } else { 699184610Salfred pdev->is_opened = 1; 700184610Salfred } 701184610Salfred return (error); 702184610Salfred} 703184610Salfred 704184610Salfredint 705184610Salfredlibusb20_dev_reset(struct libusb20_device *pdev) 706184610Salfred{ 707184610Salfred int error; 708184610Salfred 709188622Sthompsa error = pdev->methods->reset_device(pdev); 710184610Salfred return (error); 711184610Salfred} 712184610Salfred 713184610Salfredint 714203147Sthompsalibusb20_dev_check_connected(struct libusb20_device *pdev) 715203147Sthompsa{ 716203147Sthompsa int error; 717203147Sthompsa 718203147Sthompsa error = pdev->methods->check_connected(pdev); 719203147Sthompsa return (error); 720203147Sthompsa} 721203147Sthompsa 722203147Sthompsaint 723184610Salfredlibusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 724184610Salfred{ 725184610Salfred int error; 726184610Salfred 727188622Sthompsa error = pdev->methods->set_power_mode(pdev, power_mode); 728184610Salfred return (error); 729184610Salfred} 730184610Salfred 731184610Salfreduint8_t 732184610Salfredlibusb20_dev_get_power_mode(struct libusb20_device *pdev) 733184610Salfred{ 734184610Salfred int error; 735184610Salfred uint8_t power_mode; 736184610Salfred 737188622Sthompsa error = pdev->methods->get_power_mode(pdev, &power_mode); 738184610Salfred if (error) 739184610Salfred power_mode = LIBUSB20_POWER_ON; /* fake power mode */ 740184610Salfred return (power_mode); 741184610Salfred} 742184610Salfred 743250201Shselaskyint 744250201Shselaskylibusb20_dev_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize) 745250201Shselasky{ 746331771Shselasky 747331771Shselasky if (pdev->port_level == 0) { 748331771Shselasky /* 749331771Shselasky * Fallback for backends without port path: 750331771Shselasky */ 751331771Shselasky if (bufsize < 2) 752331771Shselasky return (LIBUSB20_ERROR_OVERFLOW); 753331771Shselasky buf[0] = pdev->parent_address; 754331771Shselasky buf[1] = pdev->parent_port; 755331771Shselasky return (2); 756331771Shselasky } 757331771Shselasky 758331771Shselasky /* check if client buffer is too small */ 759331771Shselasky if (pdev->port_level > bufsize) 760331771Shselasky return (LIBUSB20_ERROR_OVERFLOW); 761331771Shselasky 762331771Shselasky /* copy port number information */ 763331771Shselasky memcpy(buf, pdev->port_path, pdev->port_level); 764331771Shselasky 765331771Shselasky return (pdev->port_level); /* success */ 766250201Shselasky} 767250201Shselasky 768246789Shselaskyuint16_t 769246789Shselaskylibusb20_dev_get_power_usage(struct libusb20_device *pdev) 770246789Shselasky{ 771246789Shselasky int error; 772246789Shselasky uint16_t power_usage; 773246789Shselasky 774246789Shselasky error = pdev->methods->get_power_usage(pdev, &power_usage); 775246789Shselasky if (error) 776246789Shselasky power_usage = 0; 777246789Shselasky return (power_usage); 778246789Shselasky} 779246789Shselasky 780184610Salfredint 781184610Salfredlibusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex) 782184610Salfred{ 783184610Salfred int error; 784184610Salfred 785188622Sthompsa error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex); 786184610Salfred return (error); 787184610Salfred} 788184610Salfred 789184610Salfredint 790184610Salfredlibusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex) 791184610Salfred{ 792184610Salfred int error; 793184610Salfred 794188622Sthompsa error = pdev->methods->set_config_index(pdev, configIndex); 795184610Salfred return (error); 796184610Salfred} 797184610Salfred 798184610Salfredint 799184610Salfredlibusb20_dev_request_sync(struct libusb20_device *pdev, 800184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data, 801184610Salfred uint16_t *pactlen, uint32_t timeout, uint8_t flags) 802184610Salfred{ 803184610Salfred int error; 804184610Salfred 805188622Sthompsa error = pdev->methods->do_request_sync(pdev, 806184610Salfred setup, data, pactlen, timeout, flags); 807184610Salfred return (error); 808184610Salfred} 809184610Salfred 810184610Salfredint 811184610Salfredlibusb20_dev_req_string_sync(struct libusb20_device *pdev, 812185087Salfred uint8_t str_index, uint16_t langid, void *ptr, uint16_t len) 813184610Salfred{ 814184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED req; 815184610Salfred int error; 816336883Shselasky int flags; 817184610Salfred 818199055Sthompsa /* make sure memory is initialised */ 819199055Sthompsa memset(ptr, 0, len); 820199055Sthompsa 821184610Salfred if (len < 4) { 822184610Salfred /* invalid length */ 823184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 824184610Salfred } 825184610Salfred LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req); 826184610Salfred 827184610Salfred /* 828184610Salfred * We need to read the USB string in two steps else some USB 829184610Salfred * devices will complain. 830184610Salfred */ 831184610Salfred req.bmRequestType = 832184610Salfred LIBUSB20_REQUEST_TYPE_STANDARD | 833184610Salfred LIBUSB20_RECIPIENT_DEVICE | 834184610Salfred LIBUSB20_ENDPOINT_IN; 835184610Salfred req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR; 836185087Salfred req.wValue = (LIBUSB20_DT_STRING << 8) | str_index; 837184610Salfred req.wIndex = langid; 838184610Salfred req.wLength = 4; /* bytes */ 839184610Salfred 840184610Salfred error = libusb20_dev_request_sync(pdev, &req, 841184610Salfred ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 842184610Salfred if (error) { 843336883Shselasky /* try to request full string */ 844336883Shselasky req.wLength = 255; 845336883Shselasky flags = 0; 846336883Shselasky } else { 847336883Shselasky /* extract length and request full string */ 848336883Shselasky req.wLength = *(uint8_t *)ptr; 849336883Shselasky flags = LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK; 850184610Salfred } 851184610Salfred if (req.wLength > len) { 852184610Salfred /* partial string read */ 853184610Salfred req.wLength = len; 854184610Salfred } 855336883Shselasky error = libusb20_dev_request_sync(pdev, &req, ptr, NULL, 1000, flags); 856336883Shselasky if (error) 857336883Shselasky return (error); 858184610Salfred 859336883Shselasky if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) 860184610Salfred return (LIBUSB20_ERROR_OTHER); 861184610Salfred return (0); /* success */ 862184610Salfred} 863184610Salfred 864184610Salfredint 865184610Salfredlibusb20_dev_req_string_simple_sync(struct libusb20_device *pdev, 866185087Salfred uint8_t str_index, void *ptr, uint16_t len) 867184610Salfred{ 868184610Salfred char *buf; 869184610Salfred int error; 870184610Salfred uint16_t langid; 871184610Salfred uint16_t n; 872184610Salfred uint16_t i; 873184610Salfred uint16_t c; 874184610Salfred uint8_t temp[255]; 875184610Salfred uint8_t swap; 876184610Salfred 877184610Salfred /* the following code derives from the FreeBSD USB kernel */ 878184610Salfred 879184610Salfred if ((len < 1) || (ptr == NULL)) { 880184610Salfred /* too short buffer */ 881184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 882184610Salfred } 883184610Salfred error = libusb20_dev_req_string_sync(pdev, 884184610Salfred 0, 0, temp, sizeof(temp)); 885185087Salfred if (error < 0) { 886185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 887184610Salfred return (error); 888185087Salfred } 889184610Salfred langid = temp[2] | (temp[3] << 8); 890184610Salfred 891185087Salfred error = libusb20_dev_req_string_sync(pdev, str_index, 892184610Salfred langid, temp, sizeof(temp)); 893185087Salfred if (error < 0) { 894185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 895184610Salfred return (error); 896185087Salfred } 897184610Salfred if (temp[0] < 2) { 898184610Salfred /* string length is too short */ 899185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 900184610Salfred return (LIBUSB20_ERROR_OTHER); 901184610Salfred } 902184610Salfred /* reserve one byte for terminating zero */ 903184610Salfred len--; 904184610Salfred 905184610Salfred /* find maximum length */ 906184610Salfred n = (temp[0] / 2) - 1; 907184610Salfred if (n > len) { 908184610Salfred n = len; 909184610Salfred } 910184610Salfred /* reset swap state */ 911184610Salfred swap = 3; 912184610Salfred 913184610Salfred /* setup output buffer pointer */ 914184610Salfred buf = ptr; 915184610Salfred 916184610Salfred /* convert and filter */ 917184610Salfred for (i = 0; (i != n); i++) { 918184610Salfred c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8); 919184610Salfred 920184610Salfred /* convert from Unicode, handle buggy strings */ 921184610Salfred if (((c & 0xff00) == 0) && (swap & 1)) { 922184610Salfred /* Little Endian, default */ 923184610Salfred *buf = c; 924184610Salfred swap = 1; 925184610Salfred } else if (((c & 0x00ff) == 0) && (swap & 2)) { 926184610Salfred /* Big Endian */ 927184610Salfred *buf = c >> 8; 928184610Salfred swap = 2; 929184610Salfred } else { 930185087Salfred /* skip invalid character */ 931185087Salfred continue; 932184610Salfred } 933184610Salfred /* 934184610Salfred * Filter by default - we don't allow greater and less than 935184610Salfred * signs because they might confuse the dmesg printouts! 936184610Salfred */ 937184610Salfred if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) { 938185087Salfred /* skip invalid character */ 939185087Salfred continue; 940184610Salfred } 941184610Salfred buf++; 942184610Salfred } 943184610Salfred *buf = 0; /* zero terminate string */ 944184610Salfred 945184610Salfred return (0); 946184610Salfred} 947184610Salfred 948184610Salfredstruct libusb20_config * 949184610Salfredlibusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex) 950184610Salfred{ 951184610Salfred struct libusb20_config *retval = NULL; 952184610Salfred uint8_t *ptr; 953184610Salfred uint16_t len; 954184610Salfred uint8_t do_close; 955184610Salfred int error; 956184610Salfred 957348893Shselasky /* 958348893Shselasky * Catch invalid configuration descriptor reads early on to 959348893Shselasky * avoid issues with devices that don't check for a valid USB 960348893Shselasky * configuration read request. 961348893Shselasky */ 962348893Shselasky if (configIndex >= pdev->ddesc.bNumConfigurations) 963348893Shselasky return (NULL); 964348893Shselasky 965184610Salfred if (!pdev->is_opened) { 966184610Salfred error = libusb20_dev_open(pdev, 0); 967184610Salfred if (error) { 968184610Salfred return (NULL); 969184610Salfred } 970184610Salfred do_close = 1; 971184610Salfred } else { 972184610Salfred do_close = 0; 973184610Salfred } 974188622Sthompsa error = pdev->methods->get_config_desc_full(pdev, 975184610Salfred &ptr, &len, configIndex); 976184610Salfred 977184610Salfred if (error) { 978184610Salfred goto done; 979184610Salfred } 980184610Salfred /* parse new config descriptor */ 981184610Salfred retval = libusb20_parse_config_desc(ptr); 982184610Salfred 983184610Salfred /* free config descriptor */ 984184610Salfred free(ptr); 985184610Salfred 986184610Salfreddone: 987184610Salfred if (do_close) { 988184610Salfred error = libusb20_dev_close(pdev); 989184610Salfred } 990184610Salfred return (retval); 991184610Salfred} 992184610Salfred 993184610Salfredstruct libusb20_device * 994184610Salfredlibusb20_dev_alloc(void) 995184610Salfred{ 996184610Salfred struct libusb20_device *pdev; 997184610Salfred 998184610Salfred pdev = malloc(sizeof(*pdev)); 999184610Salfred if (pdev == NULL) { 1000184610Salfred return (NULL); 1001184610Salfred } 1002184610Salfred memset(pdev, 0, sizeof(*pdev)); 1003184610Salfred 1004184610Salfred pdev->file = -1; 1005184610Salfred pdev->file_ctrl = -1; 1006184610Salfred pdev->methods = &libusb20_dummy_methods; 1007184610Salfred return (pdev); 1008184610Salfred} 1009184610Salfred 1010184610Salfreduint8_t 1011184610Salfredlibusb20_dev_get_config_index(struct libusb20_device *pdev) 1012184610Salfred{ 1013184610Salfred int error; 1014185087Salfred uint8_t cfg_index; 1015184610Salfred uint8_t do_close; 1016184610Salfred 1017184610Salfred if (!pdev->is_opened) { 1018184610Salfred error = libusb20_dev_open(pdev, 0); 1019184610Salfred if (error == 0) { 1020184610Salfred do_close = 1; 1021184610Salfred } else { 1022184610Salfred do_close = 0; 1023184610Salfred } 1024184610Salfred } else { 1025184610Salfred do_close = 0; 1026184610Salfred } 1027184610Salfred 1028188622Sthompsa error = pdev->methods->get_config_index(pdev, &cfg_index); 1029234491Shselasky if (error) 1030234491Shselasky cfg_index = 0xFF; /* current config index */ 1031184610Salfred if (do_close) { 1032184610Salfred if (libusb20_dev_close(pdev)) { 1033184610Salfred /* ignore */ 1034184610Salfred } 1035184610Salfred } 1036185087Salfred return (cfg_index); 1037184610Salfred} 1038184610Salfred 1039184610Salfreduint8_t 1040184610Salfredlibusb20_dev_get_mode(struct libusb20_device *pdev) 1041184610Salfred{ 1042184610Salfred return (pdev->usb_mode); 1043184610Salfred} 1044184610Salfred 1045184610Salfreduint8_t 1046184610Salfredlibusb20_dev_get_speed(struct libusb20_device *pdev) 1047184610Salfred{ 1048184610Salfred return (pdev->usb_speed); 1049184610Salfred} 1050184610Salfred 1051356398Shselaskyint 1052356398Shselaskylibusb20_dev_get_stats(struct libusb20_device *pdev, struct libusb20_device_stats *pstats) 1053356398Shselasky{ 1054356398Shselasky uint8_t do_close; 1055356398Shselasky int error; 1056356398Shselasky 1057356398Shselasky if (!pdev->is_opened) { 1058356398Shselasky error = libusb20_dev_open(pdev, 0); 1059356398Shselasky if (error == 0) { 1060356398Shselasky do_close = 1; 1061356398Shselasky } else { 1062356398Shselasky do_close = 0; 1063356398Shselasky } 1064356398Shselasky } else { 1065356398Shselasky do_close = 0; 1066356398Shselasky } 1067356398Shselasky 1068356398Shselasky error = pdev->methods->get_stats(pdev, pstats); 1069356398Shselasky 1070356398Shselasky if (do_close) 1071356398Shselasky (void) libusb20_dev_close(pdev); 1072356398Shselasky 1073356398Shselasky return (error); 1074356398Shselasky} 1075356398Shselasky 1076184610Salfred/* if this function returns an error, the device is gone */ 1077184610Salfredint 1078184610Salfredlibusb20_dev_process(struct libusb20_device *pdev) 1079184610Salfred{ 1080184610Salfred int error; 1081184610Salfred 1082188622Sthompsa error = pdev->methods->process(pdev); 1083184610Salfred return (error); 1084184610Salfred} 1085184610Salfred 1086184610Salfredvoid 1087184610Salfredlibusb20_dev_wait_process(struct libusb20_device *pdev, int timeout) 1088184610Salfred{ 1089185087Salfred struct pollfd pfd[1]; 1090184610Salfred 1091184610Salfred if (!pdev->is_opened) { 1092184610Salfred return; 1093184610Salfred } 1094184610Salfred pfd[0].fd = pdev->file; 1095184610Salfred pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 1096184610Salfred pfd[0].revents = 0; 1097184610Salfred 1098185087Salfred if (poll(pfd, 1, timeout)) { 1099184610Salfred /* ignore any error */ 1100184610Salfred } 1101184610Salfred return; 1102184610Salfred} 1103184610Salfred 1104184610Salfredvoid 1105184610Salfredlibusb20_dev_free(struct libusb20_device *pdev) 1106184610Salfred{ 1107184610Salfred if (pdev == NULL) { 1108184610Salfred /* be NULL safe */ 1109184610Salfred return; 1110184610Salfred } 1111184610Salfred if (pdev->is_opened) { 1112184610Salfred if (libusb20_dev_close(pdev)) { 1113184610Salfred /* ignore any errors */ 1114184610Salfred } 1115184610Salfred } 1116184610Salfred free(pdev); 1117184610Salfred return; 1118184610Salfred} 1119184610Salfred 1120188622Sthompsaint 1121188622Sthompsalibusb20_dev_get_info(struct libusb20_device *pdev, 1122192984Sthompsa struct usb_device_info *pinfo) 1123188622Sthompsa{ 1124188622Sthompsa if (pinfo == NULL) 1125188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 1126188622Sthompsa 1127188622Sthompsa return (pdev->beMethods->dev_get_info(pdev, pinfo)); 1128188622Sthompsa} 1129188622Sthompsa 1130184610Salfredconst char * 1131184610Salfredlibusb20_dev_get_backend_name(struct libusb20_device *pdev) 1132184610Salfred{ 1133188622Sthompsa return (pdev->beMethods->get_backend_name()); 1134184610Salfred} 1135184610Salfred 1136184610Salfredconst char * 1137184610Salfredlibusb20_dev_get_desc(struct libusb20_device *pdev) 1138184610Salfred{ 1139184610Salfred return (pdev->usb_desc); 1140184610Salfred} 1141184610Salfred 1142184610Salfredvoid 1143184610Salfredlibusb20_dev_set_debug(struct libusb20_device *pdev, int debug) 1144184610Salfred{ 1145184610Salfred pdev->debug = debug; 1146184610Salfred return; 1147184610Salfred} 1148184610Salfred 1149184610Salfredint 1150184610Salfredlibusb20_dev_get_debug(struct libusb20_device *pdev) 1151184610Salfred{ 1152184610Salfred return (pdev->debug); 1153184610Salfred} 1154184610Salfred 1155184610Salfreduint8_t 1156184610Salfredlibusb20_dev_get_address(struct libusb20_device *pdev) 1157184610Salfred{ 1158184610Salfred return (pdev->device_address); 1159184610Salfred} 1160184610Salfred 1161184610Salfreduint8_t 1162223495Shselaskylibusb20_dev_get_parent_address(struct libusb20_device *pdev) 1163223495Shselasky{ 1164223495Shselasky return (pdev->parent_address); 1165223495Shselasky} 1166223495Shselasky 1167223495Shselaskyuint8_t 1168223495Shselaskylibusb20_dev_get_parent_port(struct libusb20_device *pdev) 1169223495Shselasky{ 1170223495Shselasky return (pdev->parent_port); 1171223495Shselasky} 1172223495Shselasky 1173223495Shselaskyuint8_t 1174184610Salfredlibusb20_dev_get_bus_number(struct libusb20_device *pdev) 1175184610Salfred{ 1176184610Salfred return (pdev->bus_number); 1177184610Salfred} 1178184610Salfred 1179184610Salfredint 1180188622Sthompsalibusb20_dev_get_iface_desc(struct libusb20_device *pdev, 1181188622Sthompsa uint8_t iface_index, char *buf, uint8_t len) 1182188622Sthompsa{ 1183188622Sthompsa if ((buf == NULL) || (len == 0)) 1184188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 1185188622Sthompsa 1186224085Shselasky buf[0] = 0; /* set default string value */ 1187224085Shselasky 1188188622Sthompsa return (pdev->beMethods->dev_get_iface_desc( 1189188622Sthompsa pdev, iface_index, buf, len)); 1190188622Sthompsa} 1191188622Sthompsa 1192184610Salfred/* USB backend operations */ 1193184610Salfred 1194184610Salfredint 1195184610Salfredlibusb20_be_get_dev_quirk(struct libusb20_backend *pbe, 1196185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 1197184610Salfred{ 1198188622Sthompsa return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq)); 1199184610Salfred} 1200184610Salfred 1201184610Salfredint 1202184610Salfredlibusb20_be_get_quirk_name(struct libusb20_backend *pbe, 1203185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 1204184610Salfred{ 1205188622Sthompsa return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq)); 1206184610Salfred} 1207184610Salfred 1208184610Salfredint 1209184610Salfredlibusb20_be_add_dev_quirk(struct libusb20_backend *pbe, 1210184610Salfred struct libusb20_quirk *pq) 1211184610Salfred{ 1212188622Sthompsa return (pbe->methods->root_add_dev_quirk(pbe, pq)); 1213184610Salfred} 1214184610Salfred 1215184610Salfredint 1216184610Salfredlibusb20_be_remove_dev_quirk(struct libusb20_backend *pbe, 1217184610Salfred struct libusb20_quirk *pq) 1218184610Salfred{ 1219188622Sthompsa return (pbe->methods->root_remove_dev_quirk(pbe, pq)); 1220184610Salfred} 1221184610Salfred 1222184610Salfredint 1223188987Sthompsalibusb20_be_set_template(struct libusb20_backend *pbe, int temp) 1224188987Sthompsa{ 1225188987Sthompsa return (pbe->methods->root_set_template(pbe, temp)); 1226188987Sthompsa} 1227188987Sthompsa 1228188987Sthompsaint 1229188987Sthompsalibusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp) 1230188987Sthompsa{ 1231188987Sthompsa int temp; 1232188987Sthompsa 1233188987Sthompsa if (ptemp == NULL) 1234188987Sthompsa ptemp = &temp; 1235188987Sthompsa 1236188987Sthompsa return (pbe->methods->root_get_template(pbe, ptemp)); 1237188987Sthompsa} 1238188987Sthompsa 1239184610Salfredstruct libusb20_device * 1240184610Salfredlibusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1241184610Salfred{ 1242184610Salfred if (pbe == NULL) { 1243184610Salfred pdev = NULL; 1244184610Salfred } else if (pdev == NULL) { 1245184610Salfred pdev = TAILQ_FIRST(&(pbe->usb_devs)); 1246184610Salfred } else { 1247184610Salfred pdev = TAILQ_NEXT(pdev, dev_entry); 1248184610Salfred } 1249184610Salfred return (pdev); 1250184610Salfred} 1251184610Salfred 1252184610Salfredstruct libusb20_backend * 1253184610Salfredlibusb20_be_alloc(const struct libusb20_backend_methods *methods) 1254184610Salfred{ 1255184610Salfred struct libusb20_backend *pbe; 1256184610Salfred 1257184610Salfred pbe = malloc(sizeof(*pbe)); 1258184610Salfred if (pbe == NULL) { 1259184610Salfred return (NULL); 1260184610Salfred } 1261184610Salfred memset(pbe, 0, sizeof(*pbe)); 1262184610Salfred 1263184610Salfred TAILQ_INIT(&(pbe->usb_devs)); 1264184610Salfred 1265184610Salfred pbe->methods = methods; /* set backend methods */ 1266184610Salfred 1267184610Salfred /* do the initial device scan */ 1268184610Salfred if (pbe->methods->init_backend) { 1269188622Sthompsa pbe->methods->init_backend(pbe); 1270184610Salfred } 1271184610Salfred return (pbe); 1272184610Salfred} 1273184610Salfred 1274184610Salfredstruct libusb20_backend * 1275184610Salfredlibusb20_be_alloc_linux(void) 1276184610Salfred{ 1277253339Shselasky return (NULL); 1278184610Salfred} 1279184610Salfred 1280184610Salfredstruct libusb20_backend * 1281184610Salfredlibusb20_be_alloc_ugen20(void) 1282184610Salfred{ 1283253339Shselasky return (libusb20_be_alloc(&libusb20_ugen20_backend)); 1284184610Salfred} 1285184610Salfred 1286184610Salfredstruct libusb20_backend * 1287184610Salfredlibusb20_be_alloc_default(void) 1288184610Salfred{ 1289184610Salfred struct libusb20_backend *pbe; 1290184610Salfred 1291253339Shselasky#ifdef __linux__ 1292184610Salfred pbe = libusb20_be_alloc_linux(); 1293184610Salfred if (pbe) { 1294184610Salfred return (pbe); 1295184610Salfred } 1296253339Shselasky#endif 1297184610Salfred pbe = libusb20_be_alloc_ugen20(); 1298184610Salfred if (pbe) { 1299184610Salfred return (pbe); 1300184610Salfred } 1301184610Salfred return (NULL); /* no backend found */ 1302184610Salfred} 1303184610Salfred 1304184610Salfredvoid 1305184610Salfredlibusb20_be_free(struct libusb20_backend *pbe) 1306184610Salfred{ 1307184610Salfred struct libusb20_device *pdev; 1308184610Salfred 1309184610Salfred if (pbe == NULL) { 1310184610Salfred /* be NULL safe */ 1311184610Salfred return; 1312184610Salfred } 1313184610Salfred while ((pdev = libusb20_be_device_foreach(pbe, NULL))) { 1314184610Salfred libusb20_be_dequeue_device(pbe, pdev); 1315184610Salfred libusb20_dev_free(pdev); 1316184610Salfred } 1317184610Salfred if (pbe->methods->exit_backend) { 1318188622Sthompsa pbe->methods->exit_backend(pbe); 1319184610Salfred } 1320199055Sthompsa /* free backend */ 1321199055Sthompsa free(pbe); 1322184610Salfred} 1323184610Salfred 1324184610Salfredvoid 1325184610Salfredlibusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1326184610Salfred{ 1327184610Salfred pdev->beMethods = pbe->methods; /* copy backend methods */ 1328184610Salfred TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry); 1329184610Salfred} 1330184610Salfred 1331184610Salfredvoid 1332184610Salfredlibusb20_be_dequeue_device(struct libusb20_backend *pbe, 1333184610Salfred struct libusb20_device *pdev) 1334184610Salfred{ 1335184610Salfred TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry); 1336184610Salfred} 1337225659Shselasky 1338225659Shselaskyconst char * 1339225659Shselaskylibusb20_strerror(int code) 1340225659Shselasky{ 1341225659Shselasky switch (code) { 1342225659Shselasky case LIBUSB20_SUCCESS: 1343225659Shselasky return ("Success"); 1344225659Shselasky case LIBUSB20_ERROR_IO: 1345225659Shselasky return ("I/O error"); 1346225659Shselasky case LIBUSB20_ERROR_INVALID_PARAM: 1347225659Shselasky return ("Invalid parameter"); 1348225659Shselasky case LIBUSB20_ERROR_ACCESS: 1349225659Shselasky return ("Permissions error"); 1350225659Shselasky case LIBUSB20_ERROR_NO_DEVICE: 1351225659Shselasky return ("No device"); 1352225659Shselasky case LIBUSB20_ERROR_NOT_FOUND: 1353225659Shselasky return ("Not found"); 1354225659Shselasky case LIBUSB20_ERROR_BUSY: 1355225659Shselasky return ("Device busy"); 1356225659Shselasky case LIBUSB20_ERROR_TIMEOUT: 1357225659Shselasky return ("Timeout"); 1358225659Shselasky case LIBUSB20_ERROR_OVERFLOW: 1359225659Shselasky return ("Overflow"); 1360225659Shselasky case LIBUSB20_ERROR_PIPE: 1361225659Shselasky return ("Pipe error"); 1362225659Shselasky case LIBUSB20_ERROR_INTERRUPTED: 1363225659Shselasky return ("Interrupted"); 1364225659Shselasky case LIBUSB20_ERROR_NO_MEM: 1365225659Shselasky return ("Out of memory"); 1366225659Shselasky case LIBUSB20_ERROR_NOT_SUPPORTED: 1367225659Shselasky return ("Not supported"); 1368225659Shselasky case LIBUSB20_ERROR_OTHER: 1369225659Shselasky return ("Other error"); 1370225659Shselasky default: 1371225659Shselasky return ("Unknown error"); 1372225659Shselasky } 1373225659Shselasky} 1374225659Shselasky 1375225659Shselaskyconst char * 1376225659Shselaskylibusb20_error_name(int code) 1377225659Shselasky{ 1378225659Shselasky switch (code) { 1379225659Shselasky case LIBUSB20_SUCCESS: 1380225659Shselasky return ("LIBUSB20_SUCCESS"); 1381225659Shselasky case LIBUSB20_ERROR_IO: 1382225659Shselasky return ("LIBUSB20_ERROR_IO"); 1383225659Shselasky case LIBUSB20_ERROR_INVALID_PARAM: 1384225659Shselasky return ("LIBUSB20_ERROR_INVALID_PARAM"); 1385225659Shselasky case LIBUSB20_ERROR_ACCESS: 1386225659Shselasky return ("LIBUSB20_ERROR_ACCESS"); 1387225659Shselasky case LIBUSB20_ERROR_NO_DEVICE: 1388225659Shselasky return ("LIBUSB20_ERROR_NO_DEVICE"); 1389225659Shselasky case LIBUSB20_ERROR_NOT_FOUND: 1390225659Shselasky return ("LIBUSB20_ERROR_NOT_FOUND"); 1391225659Shselasky case LIBUSB20_ERROR_BUSY: 1392225659Shselasky return ("LIBUSB20_ERROR_BUSY"); 1393225659Shselasky case LIBUSB20_ERROR_TIMEOUT: 1394225659Shselasky return ("LIBUSB20_ERROR_TIMEOUT"); 1395225659Shselasky case LIBUSB20_ERROR_OVERFLOW: 1396225659Shselasky return ("LIBUSB20_ERROR_OVERFLOW"); 1397225659Shselasky case LIBUSB20_ERROR_PIPE: 1398225659Shselasky return ("LIBUSB20_ERROR_PIPE"); 1399225659Shselasky case LIBUSB20_ERROR_INTERRUPTED: 1400225659Shselasky return ("LIBUSB20_ERROR_INTERRUPTED"); 1401225659Shselasky case LIBUSB20_ERROR_NO_MEM: 1402225659Shselasky return ("LIBUSB20_ERROR_NO_MEM"); 1403225659Shselasky case LIBUSB20_ERROR_NOT_SUPPORTED: 1404225659Shselasky return ("LIBUSB20_ERROR_NOT_SUPPORTED"); 1405225659Shselasky case LIBUSB20_ERROR_OTHER: 1406225659Shselasky return ("LIBUSB20_ERROR_OTHER"); 1407225659Shselasky default: 1408225659Shselasky return ("LIBUSB20_ERROR_UNKNOWN"); 1409225659Shselasky } 1410225659Shselasky} 1411