1184610Salfred/* $FreeBSD$ */ 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 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 */ 142202025Sthompsa xfer->priv_sc0 = 0; 143202025Sthompsa xfer->priv_sc1 = 0; 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; 179219100Shselasky pre_scale = 1; 180219100Shselasky } else { 181219100Shselasky pre_scale = 0; 182184610Salfred } 183219100Shselasky if (MaxFrameCount == 0) 184184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 185219100Shselasky 186184610Salfred xfer->maxFrames = MaxFrameCount; 187184610Salfred 188184610Salfred size = MaxFrameCount * sizeof(xfer->pLength[0]); 189184610Salfred xfer->pLength = malloc(size); 190184610Salfred if (xfer->pLength == NULL) { 191184610Salfred return (LIBUSB20_ERROR_NO_MEM); 192184610Salfred } 193184610Salfred memset(xfer->pLength, 0, size); 194184610Salfred 195184610Salfred size = MaxFrameCount * sizeof(xfer->ppBuffer[0]); 196184610Salfred xfer->ppBuffer = malloc(size); 197184610Salfred if (xfer->ppBuffer == NULL) { 198184610Salfred free(xfer->pLength); 199184610Salfred return (LIBUSB20_ERROR_NO_MEM); 200184610Salfred } 201184610Salfred memset(xfer->ppBuffer, 0, size); 202184610Salfred 203188622Sthompsa error = xfer->pdev->methods->tr_open(xfer, MaxBufSize, 204239239Shselasky MaxFrameCount, ep_no, stream_id, pre_scale); 205184610Salfred 206184610Salfred if (error) { 207184610Salfred free(xfer->ppBuffer); 208184610Salfred free(xfer->pLength); 209184610Salfred } else { 210184610Salfred xfer->is_opened = 1; 211184610Salfred } 212184610Salfred return (error); 213184610Salfred} 214184610Salfred 215184610Salfredstruct libusb20_transfer * 216184610Salfredlibusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex) 217184610Salfred{ 218184610Salfred if (trIndex >= pdev->nTransfer) { 219184610Salfred return (NULL); 220184610Salfred } 221184610Salfred return (pdev->pTransfer + trIndex); 222184610Salfred} 223184610Salfred 224184610Salfreduint32_t 225184610Salfredlibusb20_tr_get_actual_frames(struct libusb20_transfer *xfer) 226184610Salfred{ 227184610Salfred return (xfer->aFrames); 228184610Salfred} 229184610Salfred 230184610Salfreduint16_t 231184610Salfredlibusb20_tr_get_time_complete(struct libusb20_transfer *xfer) 232184610Salfred{ 233184610Salfred return (xfer->timeComplete); 234184610Salfred} 235184610Salfred 236184610Salfreduint32_t 237184610Salfredlibusb20_tr_get_actual_length(struct libusb20_transfer *xfer) 238184610Salfred{ 239184610Salfred uint32_t x; 240184610Salfred uint32_t actlen = 0; 241184610Salfred 242184610Salfred for (x = 0; x != xfer->aFrames; x++) { 243184610Salfred actlen += xfer->pLength[x]; 244184610Salfred } 245184610Salfred return (actlen); 246184610Salfred} 247184610Salfred 248184610Salfreduint32_t 249184610Salfredlibusb20_tr_get_max_frames(struct libusb20_transfer *xfer) 250184610Salfred{ 251184610Salfred return (xfer->maxFrames); 252184610Salfred} 253184610Salfred 254184610Salfreduint32_t 255184610Salfredlibusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer) 256184610Salfred{ 257184610Salfred /* 258184610Salfred * Special Case NOTE: If the packet multiplier is non-zero for 259184610Salfred * High Speed USB, the value returned is equal to 260184610Salfred * "wMaxPacketSize * multiplier" ! 261184610Salfred */ 262184610Salfred return (xfer->maxPacketLen); 263184610Salfred} 264184610Salfred 265184610Salfreduint32_t 266184610Salfredlibusb20_tr_get_max_total_length(struct libusb20_transfer *xfer) 267184610Salfred{ 268184610Salfred return (xfer->maxTotalLength); 269184610Salfred} 270184610Salfred 271184610Salfreduint8_t 272184610Salfredlibusb20_tr_get_status(struct libusb20_transfer *xfer) 273184610Salfred{ 274184610Salfred return (xfer->status); 275184610Salfred} 276184610Salfred 277184610Salfreduint8_t 278184610Salfredlibusb20_tr_pending(struct libusb20_transfer *xfer) 279184610Salfred{ 280184610Salfred return (xfer->is_pending); 281184610Salfred} 282184610Salfred 283184610Salfredvoid * 284184610Salfredlibusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer) 285184610Salfred{ 286184610Salfred return (xfer->priv_sc0); 287184610Salfred} 288184610Salfred 289184610Salfredvoid * 290184610Salfredlibusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer) 291184610Salfred{ 292184610Salfred return (xfer->priv_sc1); 293184610Salfred} 294184610Salfred 295184610Salfredvoid 296184610Salfredlibusb20_tr_stop(struct libusb20_transfer *xfer) 297184610Salfred{ 298199575Sthompsa if (!xfer->is_opened) { 299199575Sthompsa /* transfer is not opened */ 300199575Sthompsa return; 301199575Sthompsa } 302184610Salfred if (!xfer->is_pending) { 303184610Salfred /* transfer not pending */ 304184610Salfred return; 305184610Salfred } 306184610Salfred if (xfer->is_cancel) { 307184610Salfred /* already cancelling */ 308184610Salfred return; 309184610Salfred } 310184610Salfred xfer->is_cancel = 1; /* we are cancelling */ 311184610Salfred 312188622Sthompsa xfer->pdev->methods->tr_cancel_async(xfer); 313184610Salfred return; 314184610Salfred} 315184610Salfred 316184610Salfredvoid 317184610Salfredlibusb20_tr_drain(struct libusb20_transfer *xfer) 318184610Salfred{ 319199575Sthompsa if (!xfer->is_opened) { 320199575Sthompsa /* transfer is not opened */ 321199575Sthompsa return; 322199575Sthompsa } 323184610Salfred /* make sure that we are cancelling */ 324184610Salfred libusb20_tr_stop(xfer); 325184610Salfred 326184610Salfred if (xfer->is_pending) { 327184610Salfred xfer->is_draining = 1; 328184610Salfred } 329184610Salfred return; 330184610Salfred} 331184610Salfred 332184610Salfredvoid 333184610Salfredlibusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 334184610Salfred{ 335188622Sthompsa xfer->pdev->methods->tr_clear_stall_sync(xfer); 336184610Salfred return; 337184610Salfred} 338184610Salfred 339184610Salfredvoid 340184610Salfredlibusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex) 341184610Salfred{ 342213852Shselasky xfer->ppBuffer[frIndex] = libusb20_pass_ptr(buffer); 343184610Salfred return; 344184610Salfred} 345184610Salfred 346184610Salfredvoid 347184610Salfredlibusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb) 348184610Salfred{ 349184610Salfred xfer->callback = cb; 350184610Salfred return; 351184610Salfred} 352184610Salfred 353184610Salfredvoid 354184610Salfredlibusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags) 355184610Salfred{ 356184610Salfred xfer->flags = flags; 357184610Salfred return; 358184610Salfred} 359184610Salfred 360193313Sthompsauint32_t 361193313Sthompsalibusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex) 362193313Sthompsa{ 363193313Sthompsa return (xfer->pLength[frIndex]); 364193313Sthompsa} 365193313Sthompsa 366184610Salfredvoid 367184610Salfredlibusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex) 368184610Salfred{ 369184610Salfred xfer->pLength[frIndex] = length; 370184610Salfred return; 371184610Salfred} 372184610Salfred 373184610Salfredvoid 374184610Salfredlibusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0) 375184610Salfred{ 376184610Salfred xfer->priv_sc0 = sc0; 377184610Salfred return; 378184610Salfred} 379184610Salfred 380184610Salfredvoid 381184610Salfredlibusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1) 382184610Salfred{ 383184610Salfred xfer->priv_sc1 = sc1; 384184610Salfred return; 385184610Salfred} 386184610Salfred 387184610Salfredvoid 388184610Salfredlibusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout) 389184610Salfred{ 390184610Salfred xfer->timeout = timeout; 391184610Salfred return; 392184610Salfred} 393184610Salfred 394184610Salfredvoid 395184610Salfredlibusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames) 396184610Salfred{ 397184610Salfred if (nFrames > xfer->maxFrames) { 398184610Salfred /* should not happen */ 399184610Salfred nFrames = xfer->maxFrames; 400184610Salfred } 401184610Salfred xfer->nFrames = nFrames; 402184610Salfred return; 403184610Salfred} 404184610Salfred 405184610Salfredvoid 406184610Salfredlibusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 407184610Salfred{ 408213852Shselasky xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf); 409184610Salfred xfer->pLength[0] = length; 410184610Salfred xfer->timeout = timeout; 411184610Salfred xfer->nFrames = 1; 412184610Salfred return; 413184610Salfred} 414184610Salfred 415184610Salfredvoid 416184610Salfredlibusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout) 417184610Salfred{ 418184610Salfred uint16_t len; 419184610Salfred 420213852Shselasky xfer->ppBuffer[0] = libusb20_pass_ptr(psetup); 421184610Salfred xfer->pLength[0] = 8; /* fixed */ 422184610Salfred xfer->timeout = timeout; 423184610Salfred 424184610Salfred len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8); 425184610Salfred 426184610Salfred if (len != 0) { 427184610Salfred xfer->nFrames = 2; 428213852Shselasky xfer->ppBuffer[1] = libusb20_pass_ptr(pBuf); 429184610Salfred xfer->pLength[1] = len; 430184610Salfred } else { 431184610Salfred xfer->nFrames = 1; 432184610Salfred } 433184610Salfred return; 434184610Salfred} 435184610Salfred 436184610Salfredvoid 437184610Salfredlibusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 438184610Salfred{ 439213852Shselasky xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf); 440184610Salfred xfer->pLength[0] = length; 441184610Salfred xfer->timeout = timeout; 442184610Salfred xfer->nFrames = 1; 443184610Salfred return; 444184610Salfred} 445184610Salfred 446184610Salfredvoid 447184610Salfredlibusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex) 448184610Salfred{ 449184610Salfred if (frIndex >= xfer->maxFrames) { 450184610Salfred /* should not happen */ 451184610Salfred return; 452184610Salfred } 453213852Shselasky xfer->ppBuffer[frIndex] = libusb20_pass_ptr(pBuf); 454184610Salfred xfer->pLength[frIndex] = length; 455184610Salfred return; 456184610Salfred} 457184610Salfred 458199575Sthompsauint8_t 459199575Sthompsalibusb20_tr_bulk_intr_sync(struct libusb20_transfer *xfer, 460199575Sthompsa void *pbuf, uint32_t length, uint32_t *pactlen, 461199575Sthompsa uint32_t timeout) 462199575Sthompsa{ 463199575Sthompsa struct libusb20_device *pdev = xfer->pdev; 464199575Sthompsa uint32_t transfer_max; 465199575Sthompsa uint32_t transfer_act; 466199575Sthompsa uint8_t retval; 467199575Sthompsa 468199575Sthompsa /* set some sensible default value */ 469199575Sthompsa if (pactlen != NULL) 470199575Sthompsa *pactlen = 0; 471199575Sthompsa 472199575Sthompsa /* check for error condition */ 473199575Sthompsa if (libusb20_tr_pending(xfer)) 474199575Sthompsa return (LIBUSB20_ERROR_OTHER); 475199575Sthompsa 476199575Sthompsa do { 477199575Sthompsa /* compute maximum transfer length */ 478199575Sthompsa transfer_max = 479199575Sthompsa libusb20_tr_get_max_total_length(xfer); 480199575Sthompsa 481199575Sthompsa if (transfer_max > length) 482199575Sthompsa transfer_max = length; 483199575Sthompsa 484199575Sthompsa /* setup bulk or interrupt transfer */ 485199575Sthompsa libusb20_tr_setup_bulk(xfer, pbuf, 486199575Sthompsa transfer_max, timeout); 487199575Sthompsa 488199575Sthompsa /* start the transfer */ 489199575Sthompsa libusb20_tr_start(xfer); 490199575Sthompsa 491199575Sthompsa /* wait for transfer completion */ 492199575Sthompsa while (libusb20_dev_process(pdev) == 0) { 493199575Sthompsa 494199575Sthompsa if (libusb20_tr_pending(xfer) == 0) 495199575Sthompsa break; 496199575Sthompsa 497199575Sthompsa libusb20_dev_wait_process(pdev, -1); 498199575Sthompsa } 499199575Sthompsa 500199575Sthompsa transfer_act = libusb20_tr_get_actual_length(xfer); 501199575Sthompsa 502199575Sthompsa /* update actual length, if any */ 503199575Sthompsa if (pactlen != NULL) 504199575Sthompsa pactlen[0] += transfer_act; 505199575Sthompsa 506199575Sthompsa /* check transfer status */ 507199575Sthompsa retval = libusb20_tr_get_status(xfer); 508199575Sthompsa if (retval) 509199575Sthompsa break; 510199575Sthompsa 511199575Sthompsa /* check for short transfer */ 512199575Sthompsa if (transfer_act != transfer_max) 513199575Sthompsa break; 514199575Sthompsa 515199575Sthompsa /* update buffer pointer and length */ 516199575Sthompsa pbuf = ((uint8_t *)pbuf) + transfer_max; 517199575Sthompsa length = length - transfer_max; 518199575Sthompsa 519199575Sthompsa } while (length != 0); 520199575Sthompsa 521199575Sthompsa return (retval); 522199575Sthompsa} 523199575Sthompsa 524184610Salfredvoid 525184610Salfredlibusb20_tr_submit(struct libusb20_transfer *xfer) 526184610Salfred{ 527199575Sthompsa if (!xfer->is_opened) { 528199575Sthompsa /* transfer is not opened */ 529199575Sthompsa return; 530199575Sthompsa } 531184610Salfred if (xfer->is_pending) { 532184610Salfred /* should not happen */ 533184610Salfred return; 534184610Salfred } 535184610Salfred xfer->is_pending = 1; /* we are pending */ 536184610Salfred xfer->is_cancel = 0; /* not cancelling */ 537184610Salfred xfer->is_restart = 0; /* not restarting */ 538184610Salfred 539188622Sthompsa xfer->pdev->methods->tr_submit(xfer); 540184610Salfred return; 541184610Salfred} 542184610Salfred 543184610Salfredvoid 544184610Salfredlibusb20_tr_start(struct libusb20_transfer *xfer) 545184610Salfred{ 546199575Sthompsa if (!xfer->is_opened) { 547199575Sthompsa /* transfer is not opened */ 548199575Sthompsa return; 549199575Sthompsa } 550184610Salfred if (xfer->is_pending) { 551184610Salfred if (xfer->is_cancel) { 552184610Salfred /* cancelling - restart */ 553184610Salfred xfer->is_restart = 1; 554184610Salfred } 555184610Salfred /* transfer not pending */ 556184610Salfred return; 557184610Salfred } 558184610Salfred /* get into the callback */ 559184610Salfred libusb20_tr_callback_wrapper(xfer); 560184610Salfred return; 561184610Salfred} 562184610Salfred 563184610Salfred/* USB device operations */ 564184610Salfred 565184610Salfredint 566184610Salfredlibusb20_dev_close(struct libusb20_device *pdev) 567184610Salfred{ 568184610Salfred struct libusb20_transfer *xfer; 569184610Salfred uint16_t x; 570184610Salfred int error = 0; 571184610Salfred 572184610Salfred if (!pdev->is_opened) { 573184610Salfred return (LIBUSB20_ERROR_OTHER); 574184610Salfred } 575184610Salfred for (x = 0; x != pdev->nTransfer; x++) { 576184610Salfred xfer = pdev->pTransfer + x; 577184610Salfred 578199575Sthompsa if (!xfer->is_opened) { 579199575Sthompsa /* transfer is not opened */ 580199575Sthompsa continue; 581199575Sthompsa } 582199575Sthompsa 583184610Salfred libusb20_tr_drain(xfer); 584199575Sthompsa 585199575Sthompsa libusb20_tr_close(xfer); 586184610Salfred } 587184610Salfred 588184610Salfred if (pdev->pTransfer != NULL) { 589184610Salfred free(pdev->pTransfer); 590184610Salfred pdev->pTransfer = NULL; 591184610Salfred } 592188622Sthompsa error = pdev->beMethods->close_device(pdev); 593184610Salfred 594184610Salfred pdev->methods = &libusb20_dummy_methods; 595184610Salfred 596184610Salfred pdev->is_opened = 0; 597184610Salfred 598194069Sthompsa /* 599194069Sthompsa * The following variable is only used by the libusb v0.1 600194069Sthompsa * compat layer: 601194069Sthompsa */ 602194069Sthompsa pdev->claimed_interface = 0; 603187184Sthompsa 604184610Salfred return (error); 605184610Salfred} 606184610Salfred 607184610Salfredint 608184610Salfredlibusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex) 609184610Salfred{ 610184610Salfred int error; 611184610Salfred 612188622Sthompsa error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex); 613184610Salfred return (error); 614184610Salfred} 615184610Salfred 616184610Salfredstruct LIBUSB20_DEVICE_DESC_DECODED * 617184610Salfredlibusb20_dev_get_device_desc(struct libusb20_device *pdev) 618184610Salfred{ 619184610Salfred return (&(pdev->ddesc)); 620184610Salfred} 621184610Salfred 622184610Salfredint 623184610Salfredlibusb20_dev_get_fd(struct libusb20_device *pdev) 624184610Salfred{ 625184610Salfred return (pdev->file); 626184610Salfred} 627184610Salfred 628184610Salfredint 629184610Salfredlibusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex) 630184610Salfred{ 631184610Salfred int error; 632184610Salfred 633188622Sthompsa error = pdev->methods->kernel_driver_active(pdev, ifaceIndex); 634184610Salfred return (error); 635184610Salfred} 636184610Salfred 637184610Salfredint 638184610Salfredlibusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax) 639184610Salfred{ 640184610Salfred struct libusb20_transfer *xfer; 641184610Salfred uint32_t size; 642184610Salfred uint16_t x; 643184610Salfred int error; 644184610Salfred 645184610Salfred if (pdev->is_opened) { 646184610Salfred return (LIBUSB20_ERROR_BUSY); 647184610Salfred } 648184610Salfred if (nTransferMax >= 256) { 649184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 650184610Salfred } else if (nTransferMax != 0) { 651184610Salfred size = sizeof(pdev->pTransfer[0]) * nTransferMax; 652184610Salfred pdev->pTransfer = malloc(size); 653184610Salfred if (pdev->pTransfer == NULL) { 654184610Salfred return (LIBUSB20_ERROR_NO_MEM); 655184610Salfred } 656184610Salfred memset(pdev->pTransfer, 0, size); 657184610Salfred } 658184610Salfred /* initialise all transfers */ 659184610Salfred for (x = 0; x != nTransferMax; x++) { 660184610Salfred 661184610Salfred xfer = pdev->pTransfer + x; 662184610Salfred 663184610Salfred xfer->pdev = pdev; 664184610Salfred xfer->trIndex = x; 665184610Salfred xfer->callback = &dummy_callback; 666184610Salfred } 667184610Salfred 668185087Salfred /* set "nTransfer" early */ 669185087Salfred pdev->nTransfer = nTransferMax; 670185087Salfred 671188622Sthompsa error = pdev->beMethods->open_device(pdev, nTransferMax); 672184610Salfred 673184610Salfred if (error) { 674184610Salfred if (pdev->pTransfer != NULL) { 675184610Salfred free(pdev->pTransfer); 676184610Salfred pdev->pTransfer = NULL; 677184610Salfred } 678184610Salfred pdev->file = -1; 679184610Salfred pdev->file_ctrl = -1; 680184610Salfred pdev->nTransfer = 0; 681184610Salfred } else { 682184610Salfred pdev->is_opened = 1; 683184610Salfred } 684184610Salfred return (error); 685184610Salfred} 686184610Salfred 687184610Salfredint 688184610Salfredlibusb20_dev_reset(struct libusb20_device *pdev) 689184610Salfred{ 690184610Salfred int error; 691184610Salfred 692188622Sthompsa error = pdev->methods->reset_device(pdev); 693184610Salfred return (error); 694184610Salfred} 695184610Salfred 696184610Salfredint 697203147Sthompsalibusb20_dev_check_connected(struct libusb20_device *pdev) 698203147Sthompsa{ 699203147Sthompsa int error; 700203147Sthompsa 701203147Sthompsa error = pdev->methods->check_connected(pdev); 702203147Sthompsa return (error); 703203147Sthompsa} 704203147Sthompsa 705203147Sthompsaint 706184610Salfredlibusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 707184610Salfred{ 708184610Salfred int error; 709184610Salfred 710188622Sthompsa error = pdev->methods->set_power_mode(pdev, power_mode); 711184610Salfred return (error); 712184610Salfred} 713184610Salfred 714184610Salfreduint8_t 715184610Salfredlibusb20_dev_get_power_mode(struct libusb20_device *pdev) 716184610Salfred{ 717184610Salfred int error; 718184610Salfred uint8_t power_mode; 719184610Salfred 720188622Sthompsa error = pdev->methods->get_power_mode(pdev, &power_mode); 721184610Salfred if (error) 722184610Salfred power_mode = LIBUSB20_POWER_ON; /* fake power mode */ 723184610Salfred return (power_mode); 724184610Salfred} 725184610Salfred 726250201Shselaskyint 727250201Shselaskylibusb20_dev_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize) 728250201Shselasky{ 729250201Shselasky return (pdev->methods->get_port_path(pdev, buf, bufsize)); 730250201Shselasky} 731250201Shselasky 732246789Shselaskyuint16_t 733246789Shselaskylibusb20_dev_get_power_usage(struct libusb20_device *pdev) 734246789Shselasky{ 735246789Shselasky int error; 736246789Shselasky uint16_t power_usage; 737246789Shselasky 738246789Shselasky error = pdev->methods->get_power_usage(pdev, &power_usage); 739246789Shselasky if (error) 740246789Shselasky power_usage = 0; 741246789Shselasky return (power_usage); 742246789Shselasky} 743246789Shselasky 744184610Salfredint 745184610Salfredlibusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex) 746184610Salfred{ 747184610Salfred int error; 748184610Salfred 749188622Sthompsa error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex); 750184610Salfred return (error); 751184610Salfred} 752184610Salfred 753184610Salfredint 754184610Salfredlibusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex) 755184610Salfred{ 756184610Salfred int error; 757184610Salfred 758188622Sthompsa error = pdev->methods->set_config_index(pdev, configIndex); 759184610Salfred return (error); 760184610Salfred} 761184610Salfred 762184610Salfredint 763184610Salfredlibusb20_dev_request_sync(struct libusb20_device *pdev, 764184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data, 765184610Salfred uint16_t *pactlen, uint32_t timeout, uint8_t flags) 766184610Salfred{ 767184610Salfred int error; 768184610Salfred 769188622Sthompsa error = pdev->methods->do_request_sync(pdev, 770184610Salfred setup, data, pactlen, timeout, flags); 771184610Salfred return (error); 772184610Salfred} 773184610Salfred 774184610Salfredint 775184610Salfredlibusb20_dev_req_string_sync(struct libusb20_device *pdev, 776185087Salfred uint8_t str_index, uint16_t langid, void *ptr, uint16_t len) 777184610Salfred{ 778184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED req; 779184610Salfred int error; 780184610Salfred 781199055Sthompsa /* make sure memory is initialised */ 782199055Sthompsa memset(ptr, 0, len); 783199055Sthompsa 784184610Salfred if (len < 4) { 785184610Salfred /* invalid length */ 786184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 787184610Salfred } 788184610Salfred LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req); 789184610Salfred 790184610Salfred /* 791184610Salfred * We need to read the USB string in two steps else some USB 792184610Salfred * devices will complain. 793184610Salfred */ 794184610Salfred req.bmRequestType = 795184610Salfred LIBUSB20_REQUEST_TYPE_STANDARD | 796184610Salfred LIBUSB20_RECIPIENT_DEVICE | 797184610Salfred LIBUSB20_ENDPOINT_IN; 798184610Salfred req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR; 799185087Salfred req.wValue = (LIBUSB20_DT_STRING << 8) | str_index; 800184610Salfred req.wIndex = langid; 801184610Salfred req.wLength = 4; /* bytes */ 802184610Salfred 803184610Salfred error = libusb20_dev_request_sync(pdev, &req, 804184610Salfred ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 805184610Salfred if (error) { 806184610Salfred return (error); 807184610Salfred } 808184610Salfred req.wLength = *(uint8_t *)ptr; /* bytes */ 809184610Salfred if (req.wLength > len) { 810184610Salfred /* partial string read */ 811184610Salfred req.wLength = len; 812184610Salfred } 813184610Salfred error = libusb20_dev_request_sync(pdev, &req, 814184610Salfred ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 815184610Salfred 816184610Salfred if (error) { 817184610Salfred return (error); 818184610Salfred } 819184610Salfred if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) { 820184610Salfred return (LIBUSB20_ERROR_OTHER); 821184610Salfred } 822184610Salfred return (0); /* success */ 823184610Salfred} 824184610Salfred 825184610Salfredint 826184610Salfredlibusb20_dev_req_string_simple_sync(struct libusb20_device *pdev, 827185087Salfred uint8_t str_index, void *ptr, uint16_t len) 828184610Salfred{ 829184610Salfred char *buf; 830184610Salfred int error; 831184610Salfred uint16_t langid; 832184610Salfred uint16_t n; 833184610Salfred uint16_t i; 834184610Salfred uint16_t c; 835184610Salfred uint8_t temp[255]; 836184610Salfred uint8_t swap; 837184610Salfred 838184610Salfred /* the following code derives from the FreeBSD USB kernel */ 839184610Salfred 840184610Salfred if ((len < 1) || (ptr == NULL)) { 841184610Salfred /* too short buffer */ 842184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 843184610Salfred } 844184610Salfred error = libusb20_dev_req_string_sync(pdev, 845184610Salfred 0, 0, temp, sizeof(temp)); 846185087Salfred if (error < 0) { 847185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 848184610Salfred return (error); 849185087Salfred } 850184610Salfred langid = temp[2] | (temp[3] << 8); 851184610Salfred 852185087Salfred error = libusb20_dev_req_string_sync(pdev, str_index, 853184610Salfred langid, temp, sizeof(temp)); 854185087Salfred if (error < 0) { 855185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 856184610Salfred return (error); 857185087Salfred } 858184610Salfred if (temp[0] < 2) { 859184610Salfred /* string length is too short */ 860185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 861184610Salfred return (LIBUSB20_ERROR_OTHER); 862184610Salfred } 863184610Salfred /* reserve one byte for terminating zero */ 864184610Salfred len--; 865184610Salfred 866184610Salfred /* find maximum length */ 867184610Salfred n = (temp[0] / 2) - 1; 868184610Salfred if (n > len) { 869184610Salfred n = len; 870184610Salfred } 871184610Salfred /* reset swap state */ 872184610Salfred swap = 3; 873184610Salfred 874184610Salfred /* setup output buffer pointer */ 875184610Salfred buf = ptr; 876184610Salfred 877184610Salfred /* convert and filter */ 878184610Salfred for (i = 0; (i != n); i++) { 879184610Salfred c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8); 880184610Salfred 881184610Salfred /* convert from Unicode, handle buggy strings */ 882184610Salfred if (((c & 0xff00) == 0) && (swap & 1)) { 883184610Salfred /* Little Endian, default */ 884184610Salfred *buf = c; 885184610Salfred swap = 1; 886184610Salfred } else if (((c & 0x00ff) == 0) && (swap & 2)) { 887184610Salfred /* Big Endian */ 888184610Salfred *buf = c >> 8; 889184610Salfred swap = 2; 890184610Salfred } else { 891185087Salfred /* skip invalid character */ 892185087Salfred continue; 893184610Salfred } 894184610Salfred /* 895184610Salfred * Filter by default - we don't allow greater and less than 896184610Salfred * signs because they might confuse the dmesg printouts! 897184610Salfred */ 898184610Salfred if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) { 899185087Salfred /* skip invalid character */ 900185087Salfred continue; 901184610Salfred } 902184610Salfred buf++; 903184610Salfred } 904184610Salfred *buf = 0; /* zero terminate string */ 905184610Salfred 906184610Salfred return (0); 907184610Salfred} 908184610Salfred 909184610Salfredstruct libusb20_config * 910184610Salfredlibusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex) 911184610Salfred{ 912184610Salfred struct libusb20_config *retval = NULL; 913184610Salfred uint8_t *ptr; 914184610Salfred uint16_t len; 915184610Salfred uint8_t do_close; 916184610Salfred int error; 917184610Salfred 918184610Salfred if (!pdev->is_opened) { 919184610Salfred error = libusb20_dev_open(pdev, 0); 920184610Salfred if (error) { 921184610Salfred return (NULL); 922184610Salfred } 923184610Salfred do_close = 1; 924184610Salfred } else { 925184610Salfred do_close = 0; 926184610Salfred } 927188622Sthompsa error = pdev->methods->get_config_desc_full(pdev, 928184610Salfred &ptr, &len, configIndex); 929184610Salfred 930184610Salfred if (error) { 931184610Salfred goto done; 932184610Salfred } 933184610Salfred /* parse new config descriptor */ 934184610Salfred retval = libusb20_parse_config_desc(ptr); 935184610Salfred 936184610Salfred /* free config descriptor */ 937184610Salfred free(ptr); 938184610Salfred 939184610Salfreddone: 940184610Salfred if (do_close) { 941184610Salfred error = libusb20_dev_close(pdev); 942184610Salfred } 943184610Salfred return (retval); 944184610Salfred} 945184610Salfred 946184610Salfredstruct libusb20_device * 947184610Salfredlibusb20_dev_alloc(void) 948184610Salfred{ 949184610Salfred struct libusb20_device *pdev; 950184610Salfred 951184610Salfred pdev = malloc(sizeof(*pdev)); 952184610Salfred if (pdev == NULL) { 953184610Salfred return (NULL); 954184610Salfred } 955184610Salfred memset(pdev, 0, sizeof(*pdev)); 956184610Salfred 957184610Salfred pdev->file = -1; 958184610Salfred pdev->file_ctrl = -1; 959184610Salfred pdev->methods = &libusb20_dummy_methods; 960184610Salfred return (pdev); 961184610Salfred} 962184610Salfred 963184610Salfreduint8_t 964184610Salfredlibusb20_dev_get_config_index(struct libusb20_device *pdev) 965184610Salfred{ 966184610Salfred int error; 967185087Salfred uint8_t cfg_index; 968184610Salfred uint8_t do_close; 969184610Salfred 970184610Salfred if (!pdev->is_opened) { 971184610Salfred error = libusb20_dev_open(pdev, 0); 972184610Salfred if (error == 0) { 973184610Salfred do_close = 1; 974184610Salfred } else { 975184610Salfred do_close = 0; 976184610Salfred } 977184610Salfred } else { 978184610Salfred do_close = 0; 979184610Salfred } 980184610Salfred 981188622Sthompsa error = pdev->methods->get_config_index(pdev, &cfg_index); 982234491Shselasky if (error) 983234491Shselasky cfg_index = 0xFF; /* current config index */ 984184610Salfred if (do_close) { 985184610Salfred if (libusb20_dev_close(pdev)) { 986184610Salfred /* ignore */ 987184610Salfred } 988184610Salfred } 989185087Salfred return (cfg_index); 990184610Salfred} 991184610Salfred 992184610Salfreduint8_t 993184610Salfredlibusb20_dev_get_mode(struct libusb20_device *pdev) 994184610Salfred{ 995184610Salfred return (pdev->usb_mode); 996184610Salfred} 997184610Salfred 998184610Salfreduint8_t 999184610Salfredlibusb20_dev_get_speed(struct libusb20_device *pdev) 1000184610Salfred{ 1001184610Salfred return (pdev->usb_speed); 1002184610Salfred} 1003184610Salfred 1004184610Salfred/* if this function returns an error, the device is gone */ 1005184610Salfredint 1006184610Salfredlibusb20_dev_process(struct libusb20_device *pdev) 1007184610Salfred{ 1008184610Salfred int error; 1009184610Salfred 1010188622Sthompsa error = pdev->methods->process(pdev); 1011184610Salfred return (error); 1012184610Salfred} 1013184610Salfred 1014184610Salfredvoid 1015184610Salfredlibusb20_dev_wait_process(struct libusb20_device *pdev, int timeout) 1016184610Salfred{ 1017185087Salfred struct pollfd pfd[1]; 1018184610Salfred 1019184610Salfred if (!pdev->is_opened) { 1020184610Salfred return; 1021184610Salfred } 1022184610Salfred pfd[0].fd = pdev->file; 1023184610Salfred pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 1024184610Salfred pfd[0].revents = 0; 1025184610Salfred 1026185087Salfred if (poll(pfd, 1, timeout)) { 1027184610Salfred /* ignore any error */ 1028184610Salfred } 1029184610Salfred return; 1030184610Salfred} 1031184610Salfred 1032184610Salfredvoid 1033184610Salfredlibusb20_dev_free(struct libusb20_device *pdev) 1034184610Salfred{ 1035184610Salfred if (pdev == NULL) { 1036184610Salfred /* be NULL safe */ 1037184610Salfred return; 1038184610Salfred } 1039184610Salfred if (pdev->is_opened) { 1040184610Salfred if (libusb20_dev_close(pdev)) { 1041184610Salfred /* ignore any errors */ 1042184610Salfred } 1043184610Salfred } 1044184610Salfred free(pdev); 1045184610Salfred return; 1046184610Salfred} 1047184610Salfred 1048188622Sthompsaint 1049188622Sthompsalibusb20_dev_get_info(struct libusb20_device *pdev, 1050192984Sthompsa struct usb_device_info *pinfo) 1051188622Sthompsa{ 1052188622Sthompsa if (pinfo == NULL) 1053188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 1054188622Sthompsa 1055188622Sthompsa return (pdev->beMethods->dev_get_info(pdev, pinfo)); 1056188622Sthompsa} 1057188622Sthompsa 1058184610Salfredconst char * 1059184610Salfredlibusb20_dev_get_backend_name(struct libusb20_device *pdev) 1060184610Salfred{ 1061188622Sthompsa return (pdev->beMethods->get_backend_name()); 1062184610Salfred} 1063184610Salfred 1064184610Salfredconst char * 1065184610Salfredlibusb20_dev_get_desc(struct libusb20_device *pdev) 1066184610Salfred{ 1067184610Salfred return (pdev->usb_desc); 1068184610Salfred} 1069184610Salfred 1070184610Salfredvoid 1071184610Salfredlibusb20_dev_set_debug(struct libusb20_device *pdev, int debug) 1072184610Salfred{ 1073184610Salfred pdev->debug = debug; 1074184610Salfred return; 1075184610Salfred} 1076184610Salfred 1077184610Salfredint 1078184610Salfredlibusb20_dev_get_debug(struct libusb20_device *pdev) 1079184610Salfred{ 1080184610Salfred return (pdev->debug); 1081184610Salfred} 1082184610Salfred 1083184610Salfreduint8_t 1084184610Salfredlibusb20_dev_get_address(struct libusb20_device *pdev) 1085184610Salfred{ 1086184610Salfred return (pdev->device_address); 1087184610Salfred} 1088184610Salfred 1089184610Salfreduint8_t 1090223495Shselaskylibusb20_dev_get_parent_address(struct libusb20_device *pdev) 1091223495Shselasky{ 1092223495Shselasky return (pdev->parent_address); 1093223495Shselasky} 1094223495Shselasky 1095223495Shselaskyuint8_t 1096223495Shselaskylibusb20_dev_get_parent_port(struct libusb20_device *pdev) 1097223495Shselasky{ 1098223495Shselasky return (pdev->parent_port); 1099223495Shselasky} 1100223495Shselasky 1101223495Shselaskyuint8_t 1102184610Salfredlibusb20_dev_get_bus_number(struct libusb20_device *pdev) 1103184610Salfred{ 1104184610Salfred return (pdev->bus_number); 1105184610Salfred} 1106184610Salfred 1107184610Salfredint 1108188622Sthompsalibusb20_dev_get_iface_desc(struct libusb20_device *pdev, 1109188622Sthompsa uint8_t iface_index, char *buf, uint8_t len) 1110188622Sthompsa{ 1111188622Sthompsa if ((buf == NULL) || (len == 0)) 1112188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 1113188622Sthompsa 1114224085Shselasky buf[0] = 0; /* set default string value */ 1115224085Shselasky 1116188622Sthompsa return (pdev->beMethods->dev_get_iface_desc( 1117188622Sthompsa pdev, iface_index, buf, len)); 1118188622Sthompsa} 1119188622Sthompsa 1120184610Salfred/* USB backend operations */ 1121184610Salfred 1122184610Salfredint 1123184610Salfredlibusb20_be_get_dev_quirk(struct libusb20_backend *pbe, 1124185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 1125184610Salfred{ 1126188622Sthompsa return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq)); 1127184610Salfred} 1128184610Salfred 1129184610Salfredint 1130184610Salfredlibusb20_be_get_quirk_name(struct libusb20_backend *pbe, 1131185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 1132184610Salfred{ 1133188622Sthompsa return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq)); 1134184610Salfred} 1135184610Salfred 1136184610Salfredint 1137184610Salfredlibusb20_be_add_dev_quirk(struct libusb20_backend *pbe, 1138184610Salfred struct libusb20_quirk *pq) 1139184610Salfred{ 1140188622Sthompsa return (pbe->methods->root_add_dev_quirk(pbe, pq)); 1141184610Salfred} 1142184610Salfred 1143184610Salfredint 1144184610Salfredlibusb20_be_remove_dev_quirk(struct libusb20_backend *pbe, 1145184610Salfred struct libusb20_quirk *pq) 1146184610Salfred{ 1147188622Sthompsa return (pbe->methods->root_remove_dev_quirk(pbe, pq)); 1148184610Salfred} 1149184610Salfred 1150184610Salfredint 1151188987Sthompsalibusb20_be_set_template(struct libusb20_backend *pbe, int temp) 1152188987Sthompsa{ 1153188987Sthompsa return (pbe->methods->root_set_template(pbe, temp)); 1154188987Sthompsa} 1155188987Sthompsa 1156188987Sthompsaint 1157188987Sthompsalibusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp) 1158188987Sthompsa{ 1159188987Sthompsa int temp; 1160188987Sthompsa 1161188987Sthompsa if (ptemp == NULL) 1162188987Sthompsa ptemp = &temp; 1163188987Sthompsa 1164188987Sthompsa return (pbe->methods->root_get_template(pbe, ptemp)); 1165188987Sthompsa} 1166188987Sthompsa 1167184610Salfredstruct libusb20_device * 1168184610Salfredlibusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1169184610Salfred{ 1170184610Salfred if (pbe == NULL) { 1171184610Salfred pdev = NULL; 1172184610Salfred } else if (pdev == NULL) { 1173184610Salfred pdev = TAILQ_FIRST(&(pbe->usb_devs)); 1174184610Salfred } else { 1175184610Salfred pdev = TAILQ_NEXT(pdev, dev_entry); 1176184610Salfred } 1177184610Salfred return (pdev); 1178184610Salfred} 1179184610Salfred 1180184610Salfredstruct libusb20_backend * 1181184610Salfredlibusb20_be_alloc(const struct libusb20_backend_methods *methods) 1182184610Salfred{ 1183184610Salfred struct libusb20_backend *pbe; 1184184610Salfred 1185184610Salfred pbe = malloc(sizeof(*pbe)); 1186184610Salfred if (pbe == NULL) { 1187184610Salfred return (NULL); 1188184610Salfred } 1189184610Salfred memset(pbe, 0, sizeof(*pbe)); 1190184610Salfred 1191184610Salfred TAILQ_INIT(&(pbe->usb_devs)); 1192184610Salfred 1193184610Salfred pbe->methods = methods; /* set backend methods */ 1194184610Salfred 1195184610Salfred /* do the initial device scan */ 1196184610Salfred if (pbe->methods->init_backend) { 1197188622Sthompsa pbe->methods->init_backend(pbe); 1198184610Salfred } 1199184610Salfred return (pbe); 1200184610Salfred} 1201184610Salfred 1202184610Salfredstruct libusb20_backend * 1203184610Salfredlibusb20_be_alloc_linux(void) 1204184610Salfred{ 1205253339Shselasky return (NULL); 1206184610Salfred} 1207184610Salfred 1208184610Salfredstruct libusb20_backend * 1209184610Salfredlibusb20_be_alloc_ugen20(void) 1210184610Salfred{ 1211253339Shselasky return (libusb20_be_alloc(&libusb20_ugen20_backend)); 1212184610Salfred} 1213184610Salfred 1214184610Salfredstruct libusb20_backend * 1215184610Salfredlibusb20_be_alloc_default(void) 1216184610Salfred{ 1217184610Salfred struct libusb20_backend *pbe; 1218184610Salfred 1219253339Shselasky#ifdef __linux__ 1220184610Salfred pbe = libusb20_be_alloc_linux(); 1221184610Salfred if (pbe) { 1222184610Salfred return (pbe); 1223184610Salfred } 1224253339Shselasky#endif 1225184610Salfred pbe = libusb20_be_alloc_ugen20(); 1226184610Salfred if (pbe) { 1227184610Salfred return (pbe); 1228184610Salfred } 1229184610Salfred return (NULL); /* no backend found */ 1230184610Salfred} 1231184610Salfred 1232184610Salfredvoid 1233184610Salfredlibusb20_be_free(struct libusb20_backend *pbe) 1234184610Salfred{ 1235184610Salfred struct libusb20_device *pdev; 1236184610Salfred 1237184610Salfred if (pbe == NULL) { 1238184610Salfred /* be NULL safe */ 1239184610Salfred return; 1240184610Salfred } 1241184610Salfred while ((pdev = libusb20_be_device_foreach(pbe, NULL))) { 1242184610Salfred libusb20_be_dequeue_device(pbe, pdev); 1243184610Salfred libusb20_dev_free(pdev); 1244184610Salfred } 1245184610Salfred if (pbe->methods->exit_backend) { 1246188622Sthompsa pbe->methods->exit_backend(pbe); 1247184610Salfred } 1248199055Sthompsa /* free backend */ 1249199055Sthompsa free(pbe); 1250184610Salfred} 1251184610Salfred 1252184610Salfredvoid 1253184610Salfredlibusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1254184610Salfred{ 1255184610Salfred pdev->beMethods = pbe->methods; /* copy backend methods */ 1256184610Salfred TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry); 1257184610Salfred} 1258184610Salfred 1259184610Salfredvoid 1260184610Salfredlibusb20_be_dequeue_device(struct libusb20_backend *pbe, 1261184610Salfred struct libusb20_device *pdev) 1262184610Salfred{ 1263184610Salfred TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry); 1264184610Salfred} 1265225659Shselasky 1266225659Shselaskyconst char * 1267225659Shselaskylibusb20_strerror(int code) 1268225659Shselasky{ 1269225659Shselasky switch (code) { 1270225659Shselasky case LIBUSB20_SUCCESS: 1271225659Shselasky return ("Success"); 1272225659Shselasky case LIBUSB20_ERROR_IO: 1273225659Shselasky return ("I/O error"); 1274225659Shselasky case LIBUSB20_ERROR_INVALID_PARAM: 1275225659Shselasky return ("Invalid parameter"); 1276225659Shselasky case LIBUSB20_ERROR_ACCESS: 1277225659Shselasky return ("Permissions error"); 1278225659Shselasky case LIBUSB20_ERROR_NO_DEVICE: 1279225659Shselasky return ("No device"); 1280225659Shselasky case LIBUSB20_ERROR_NOT_FOUND: 1281225659Shselasky return ("Not found"); 1282225659Shselasky case LIBUSB20_ERROR_BUSY: 1283225659Shselasky return ("Device busy"); 1284225659Shselasky case LIBUSB20_ERROR_TIMEOUT: 1285225659Shselasky return ("Timeout"); 1286225659Shselasky case LIBUSB20_ERROR_OVERFLOW: 1287225659Shselasky return ("Overflow"); 1288225659Shselasky case LIBUSB20_ERROR_PIPE: 1289225659Shselasky return ("Pipe error"); 1290225659Shselasky case LIBUSB20_ERROR_INTERRUPTED: 1291225659Shselasky return ("Interrupted"); 1292225659Shselasky case LIBUSB20_ERROR_NO_MEM: 1293225659Shselasky return ("Out of memory"); 1294225659Shselasky case LIBUSB20_ERROR_NOT_SUPPORTED: 1295225659Shselasky return ("Not supported"); 1296225659Shselasky case LIBUSB20_ERROR_OTHER: 1297225659Shselasky return ("Other error"); 1298225659Shselasky default: 1299225659Shselasky return ("Unknown error"); 1300225659Shselasky } 1301225659Shselasky} 1302225659Shselasky 1303225659Shselaskyconst char * 1304225659Shselaskylibusb20_error_name(int code) 1305225659Shselasky{ 1306225659Shselasky switch (code) { 1307225659Shselasky case LIBUSB20_SUCCESS: 1308225659Shselasky return ("LIBUSB20_SUCCESS"); 1309225659Shselasky case LIBUSB20_ERROR_IO: 1310225659Shselasky return ("LIBUSB20_ERROR_IO"); 1311225659Shselasky case LIBUSB20_ERROR_INVALID_PARAM: 1312225659Shselasky return ("LIBUSB20_ERROR_INVALID_PARAM"); 1313225659Shselasky case LIBUSB20_ERROR_ACCESS: 1314225659Shselasky return ("LIBUSB20_ERROR_ACCESS"); 1315225659Shselasky case LIBUSB20_ERROR_NO_DEVICE: 1316225659Shselasky return ("LIBUSB20_ERROR_NO_DEVICE"); 1317225659Shselasky case LIBUSB20_ERROR_NOT_FOUND: 1318225659Shselasky return ("LIBUSB20_ERROR_NOT_FOUND"); 1319225659Shselasky case LIBUSB20_ERROR_BUSY: 1320225659Shselasky return ("LIBUSB20_ERROR_BUSY"); 1321225659Shselasky case LIBUSB20_ERROR_TIMEOUT: 1322225659Shselasky return ("LIBUSB20_ERROR_TIMEOUT"); 1323225659Shselasky case LIBUSB20_ERROR_OVERFLOW: 1324225659Shselasky return ("LIBUSB20_ERROR_OVERFLOW"); 1325225659Shselasky case LIBUSB20_ERROR_PIPE: 1326225659Shselasky return ("LIBUSB20_ERROR_PIPE"); 1327225659Shselasky case LIBUSB20_ERROR_INTERRUPTED: 1328225659Shselasky return ("LIBUSB20_ERROR_INTERRUPTED"); 1329225659Shselasky case LIBUSB20_ERROR_NO_MEM: 1330225659Shselasky return ("LIBUSB20_ERROR_NO_MEM"); 1331225659Shselasky case LIBUSB20_ERROR_NOT_SUPPORTED: 1332225659Shselasky return ("LIBUSB20_ERROR_NOT_SUPPORTED"); 1333225659Shselasky case LIBUSB20_ERROR_OTHER: 1334225659Shselasky return ("LIBUSB20_ERROR_OTHER"); 1335225659Shselasky default: 1336225659Shselasky return ("LIBUSB20_ERROR_UNKNOWN"); 1337225659Shselasky } 1338225659Shselasky} 1339