libusb20.c revision 213852
1184610Salfred/* $FreeBSD: head/lib/libusb/libusb20.c 213852 2010-10-14 20:38:18Z 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 27203815Swkoszek#include <sys/queue.h> 28203815Swkoszek 29203815Swkoszek#include <ctype.h> 30203815Swkoszek#include <poll.h> 31184610Salfred#include <stdio.h> 32184610Salfred#include <stdlib.h> 33184610Salfred#include <string.h> 34184610Salfred 35184610Salfred#include "libusb20.h" 36184610Salfred#include "libusb20_desc.h" 37184610Salfred#include "libusb20_int.h" 38184610Salfred 39184610Salfredstatic int 40184610Salfreddummy_int(void) 41184610Salfred{ 42184610Salfred return (LIBUSB20_ERROR_NOT_SUPPORTED); 43184610Salfred} 44184610Salfred 45184610Salfredstatic void 46184610Salfreddummy_void(void) 47184610Salfred{ 48184610Salfred return; 49184610Salfred} 50184610Salfred 51184610Salfredstatic void 52184610Salfreddummy_callback(struct libusb20_transfer *xfer) 53184610Salfred{ 54184610Salfred ; /* style fix */ 55184610Salfred switch (libusb20_tr_get_status(xfer)) { 56184610Salfred case LIBUSB20_TRANSFER_START: 57184610Salfred libusb20_tr_submit(xfer); 58184610Salfred break; 59184610Salfred default: 60184610Salfred /* complete or error */ 61184610Salfred break; 62184610Salfred } 63184610Salfred return; 64184610Salfred} 65184610Salfred 66184610Salfred#define dummy_get_config_desc_full (void *)dummy_int 67184610Salfred#define dummy_get_config_index (void *)dummy_int 68184610Salfred#define dummy_set_config_index (void *)dummy_int 69184610Salfred#define dummy_set_alt_index (void *)dummy_int 70184610Salfred#define dummy_reset_device (void *)dummy_int 71203147Sthompsa#define dummy_check_connected (void *)dummy_int 72184610Salfred#define dummy_set_power_mode (void *)dummy_int 73184610Salfred#define dummy_get_power_mode (void *)dummy_int 74184610Salfred#define dummy_kernel_driver_active (void *)dummy_int 75184610Salfred#define dummy_detach_kernel_driver (void *)dummy_int 76184610Salfred#define dummy_do_request_sync (void *)dummy_int 77184610Salfred#define dummy_tr_open (void *)dummy_int 78184610Salfred#define dummy_tr_close (void *)dummy_int 79184610Salfred#define dummy_tr_clear_stall_sync (void *)dummy_int 80184610Salfred#define dummy_process (void *)dummy_int 81188622Sthompsa#define dummy_dev_info (void *)dummy_int 82188622Sthompsa#define dummy_dev_get_iface_driver (void *)dummy_int 83184610Salfred 84184610Salfred#define dummy_tr_submit (void *)dummy_void 85184610Salfred#define dummy_tr_cancel_async (void *)dummy_void 86184610Salfred 87184610Salfredstatic const struct libusb20_device_methods libusb20_dummy_methods = { 88184610Salfred LIBUSB20_DEVICE(LIBUSB20_DECLARE, dummy) 89184610Salfred}; 90184610Salfred 91184610Salfredvoid 92184610Salfredlibusb20_tr_callback_wrapper(struct libusb20_transfer *xfer) 93184610Salfred{ 94184610Salfred ; /* style fix */ 95184610Salfred 96184610Salfredrepeat: 97184610Salfred 98184610Salfred if (!xfer->is_pending) { 99184610Salfred xfer->status = LIBUSB20_TRANSFER_START; 100184610Salfred } else { 101184610Salfred xfer->is_pending = 0; 102184610Salfred } 103184610Salfred 104188622Sthompsa xfer->callback(xfer); 105184610Salfred 106184610Salfred if (xfer->is_restart) { 107184610Salfred xfer->is_restart = 0; 108184610Salfred goto repeat; 109184610Salfred } 110184610Salfred if (xfer->is_draining && 111184610Salfred (!xfer->is_pending)) { 112184610Salfred xfer->is_draining = 0; 113184610Salfred xfer->status = LIBUSB20_TRANSFER_DRAINED; 114188622Sthompsa xfer->callback(xfer); 115184610Salfred } 116184610Salfred return; 117184610Salfred} 118184610Salfred 119184610Salfredint 120184610Salfredlibusb20_tr_close(struct libusb20_transfer *xfer) 121184610Salfred{ 122184610Salfred int error; 123184610Salfred 124184610Salfred if (!xfer->is_opened) { 125184610Salfred return (LIBUSB20_ERROR_OTHER); 126184610Salfred } 127188622Sthompsa error = xfer->pdev->methods->tr_close(xfer); 128184610Salfred 129184610Salfred if (xfer->pLength) { 130184610Salfred free(xfer->pLength); 131184610Salfred } 132184610Salfred if (xfer->ppBuffer) { 133184610Salfred free(xfer->ppBuffer); 134184610Salfred } 135202025Sthompsa /* reset variable fields in case the transfer is opened again */ 136202025Sthompsa xfer->priv_sc0 = 0; 137202025Sthompsa xfer->priv_sc1 = 0; 138184610Salfred xfer->is_opened = 0; 139202025Sthompsa xfer->is_pending = 0; 140202025Sthompsa xfer->is_cancel = 0; 141202025Sthompsa xfer->is_draining = 0; 142202025Sthompsa xfer->is_restart = 0; 143202025Sthompsa xfer->status = 0; 144202025Sthompsa xfer->flags = 0; 145202025Sthompsa xfer->nFrames = 0; 146202025Sthompsa xfer->aFrames = 0; 147202025Sthompsa xfer->timeout = 0; 148184610Salfred xfer->maxFrames = 0; 149184610Salfred xfer->maxTotalLength = 0; 150184610Salfred xfer->maxPacketLen = 0; 151184610Salfred return (error); 152184610Salfred} 153184610Salfred 154184610Salfredint 155184610Salfredlibusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 156184610Salfred uint32_t MaxFrameCount, uint8_t ep_no) 157184610Salfred{ 158184610Salfred uint32_t size; 159184610Salfred int error; 160184610Salfred 161184610Salfred if (xfer->is_opened) { 162184610Salfred return (LIBUSB20_ERROR_BUSY); 163184610Salfred } 164184610Salfred if (MaxFrameCount == 0) { 165184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 166184610Salfred } 167184610Salfred xfer->maxFrames = MaxFrameCount; 168184610Salfred 169184610Salfred size = MaxFrameCount * sizeof(xfer->pLength[0]); 170184610Salfred xfer->pLength = malloc(size); 171184610Salfred if (xfer->pLength == NULL) { 172184610Salfred return (LIBUSB20_ERROR_NO_MEM); 173184610Salfred } 174184610Salfred memset(xfer->pLength, 0, size); 175184610Salfred 176184610Salfred size = MaxFrameCount * sizeof(xfer->ppBuffer[0]); 177184610Salfred xfer->ppBuffer = malloc(size); 178184610Salfred if (xfer->ppBuffer == NULL) { 179184610Salfred free(xfer->pLength); 180184610Salfred return (LIBUSB20_ERROR_NO_MEM); 181184610Salfred } 182184610Salfred memset(xfer->ppBuffer, 0, size); 183184610Salfred 184188622Sthompsa error = xfer->pdev->methods->tr_open(xfer, MaxBufSize, 185184610Salfred MaxFrameCount, ep_no); 186184610Salfred 187184610Salfred if (error) { 188184610Salfred free(xfer->ppBuffer); 189184610Salfred free(xfer->pLength); 190184610Salfred } else { 191184610Salfred xfer->is_opened = 1; 192184610Salfred } 193184610Salfred return (error); 194184610Salfred} 195184610Salfred 196184610Salfredstruct libusb20_transfer * 197184610Salfredlibusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex) 198184610Salfred{ 199184610Salfred if (trIndex >= pdev->nTransfer) { 200184610Salfred return (NULL); 201184610Salfred } 202184610Salfred return (pdev->pTransfer + trIndex); 203184610Salfred} 204184610Salfred 205184610Salfreduint32_t 206184610Salfredlibusb20_tr_get_actual_frames(struct libusb20_transfer *xfer) 207184610Salfred{ 208184610Salfred return (xfer->aFrames); 209184610Salfred} 210184610Salfred 211184610Salfreduint16_t 212184610Salfredlibusb20_tr_get_time_complete(struct libusb20_transfer *xfer) 213184610Salfred{ 214184610Salfred return (xfer->timeComplete); 215184610Salfred} 216184610Salfred 217184610Salfreduint32_t 218184610Salfredlibusb20_tr_get_actual_length(struct libusb20_transfer *xfer) 219184610Salfred{ 220184610Salfred uint32_t x; 221184610Salfred uint32_t actlen = 0; 222184610Salfred 223184610Salfred for (x = 0; x != xfer->aFrames; x++) { 224184610Salfred actlen += xfer->pLength[x]; 225184610Salfred } 226184610Salfred return (actlen); 227184610Salfred} 228184610Salfred 229184610Salfreduint32_t 230184610Salfredlibusb20_tr_get_max_frames(struct libusb20_transfer *xfer) 231184610Salfred{ 232184610Salfred return (xfer->maxFrames); 233184610Salfred} 234184610Salfred 235184610Salfreduint32_t 236184610Salfredlibusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer) 237184610Salfred{ 238184610Salfred /* 239184610Salfred * Special Case NOTE: If the packet multiplier is non-zero for 240184610Salfred * High Speed USB, the value returned is equal to 241184610Salfred * "wMaxPacketSize * multiplier" ! 242184610Salfred */ 243184610Salfred return (xfer->maxPacketLen); 244184610Salfred} 245184610Salfred 246184610Salfreduint32_t 247184610Salfredlibusb20_tr_get_max_total_length(struct libusb20_transfer *xfer) 248184610Salfred{ 249184610Salfred return (xfer->maxTotalLength); 250184610Salfred} 251184610Salfred 252184610Salfreduint8_t 253184610Salfredlibusb20_tr_get_status(struct libusb20_transfer *xfer) 254184610Salfred{ 255184610Salfred return (xfer->status); 256184610Salfred} 257184610Salfred 258184610Salfreduint8_t 259184610Salfredlibusb20_tr_pending(struct libusb20_transfer *xfer) 260184610Salfred{ 261184610Salfred return (xfer->is_pending); 262184610Salfred} 263184610Salfred 264184610Salfredvoid * 265184610Salfredlibusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer) 266184610Salfred{ 267184610Salfred return (xfer->priv_sc0); 268184610Salfred} 269184610Salfred 270184610Salfredvoid * 271184610Salfredlibusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer) 272184610Salfred{ 273184610Salfred return (xfer->priv_sc1); 274184610Salfred} 275184610Salfred 276184610Salfredvoid 277184610Salfredlibusb20_tr_stop(struct libusb20_transfer *xfer) 278184610Salfred{ 279199575Sthompsa if (!xfer->is_opened) { 280199575Sthompsa /* transfer is not opened */ 281199575Sthompsa return; 282199575Sthompsa } 283184610Salfred if (!xfer->is_pending) { 284184610Salfred /* transfer not pending */ 285184610Salfred return; 286184610Salfred } 287184610Salfred if (xfer->is_cancel) { 288184610Salfred /* already cancelling */ 289184610Salfred return; 290184610Salfred } 291184610Salfred xfer->is_cancel = 1; /* we are cancelling */ 292184610Salfred 293188622Sthompsa xfer->pdev->methods->tr_cancel_async(xfer); 294184610Salfred return; 295184610Salfred} 296184610Salfred 297184610Salfredvoid 298184610Salfredlibusb20_tr_drain(struct libusb20_transfer *xfer) 299184610Salfred{ 300199575Sthompsa if (!xfer->is_opened) { 301199575Sthompsa /* transfer is not opened */ 302199575Sthompsa return; 303199575Sthompsa } 304184610Salfred /* make sure that we are cancelling */ 305184610Salfred libusb20_tr_stop(xfer); 306184610Salfred 307184610Salfred if (xfer->is_pending) { 308184610Salfred xfer->is_draining = 1; 309184610Salfred } 310184610Salfred return; 311184610Salfred} 312184610Salfred 313184610Salfredvoid 314184610Salfredlibusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 315184610Salfred{ 316188622Sthompsa xfer->pdev->methods->tr_clear_stall_sync(xfer); 317184610Salfred return; 318184610Salfred} 319184610Salfred 320184610Salfredvoid 321184610Salfredlibusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex) 322184610Salfred{ 323213852Shselasky xfer->ppBuffer[frIndex] = libusb20_pass_ptr(buffer); 324184610Salfred return; 325184610Salfred} 326184610Salfred 327184610Salfredvoid 328184610Salfredlibusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb) 329184610Salfred{ 330184610Salfred xfer->callback = cb; 331184610Salfred return; 332184610Salfred} 333184610Salfred 334184610Salfredvoid 335184610Salfredlibusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags) 336184610Salfred{ 337184610Salfred xfer->flags = flags; 338184610Salfred return; 339184610Salfred} 340184610Salfred 341193313Sthompsauint32_t 342193313Sthompsalibusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex) 343193313Sthompsa{ 344193313Sthompsa return (xfer->pLength[frIndex]); 345193313Sthompsa} 346193313Sthompsa 347184610Salfredvoid 348184610Salfredlibusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex) 349184610Salfred{ 350184610Salfred xfer->pLength[frIndex] = length; 351184610Salfred return; 352184610Salfred} 353184610Salfred 354184610Salfredvoid 355184610Salfredlibusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0) 356184610Salfred{ 357184610Salfred xfer->priv_sc0 = sc0; 358184610Salfred return; 359184610Salfred} 360184610Salfred 361184610Salfredvoid 362184610Salfredlibusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1) 363184610Salfred{ 364184610Salfred xfer->priv_sc1 = sc1; 365184610Salfred return; 366184610Salfred} 367184610Salfred 368184610Salfredvoid 369184610Salfredlibusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout) 370184610Salfred{ 371184610Salfred xfer->timeout = timeout; 372184610Salfred return; 373184610Salfred} 374184610Salfred 375184610Salfredvoid 376184610Salfredlibusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames) 377184610Salfred{ 378184610Salfred if (nFrames > xfer->maxFrames) { 379184610Salfred /* should not happen */ 380184610Salfred nFrames = xfer->maxFrames; 381184610Salfred } 382184610Salfred xfer->nFrames = nFrames; 383184610Salfred return; 384184610Salfred} 385184610Salfred 386184610Salfredvoid 387184610Salfredlibusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 388184610Salfred{ 389213852Shselasky xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf); 390184610Salfred xfer->pLength[0] = length; 391184610Salfred xfer->timeout = timeout; 392184610Salfred xfer->nFrames = 1; 393184610Salfred return; 394184610Salfred} 395184610Salfred 396184610Salfredvoid 397184610Salfredlibusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout) 398184610Salfred{ 399184610Salfred uint16_t len; 400184610Salfred 401213852Shselasky xfer->ppBuffer[0] = libusb20_pass_ptr(psetup); 402184610Salfred xfer->pLength[0] = 8; /* fixed */ 403184610Salfred xfer->timeout = timeout; 404184610Salfred 405184610Salfred len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8); 406184610Salfred 407184610Salfred if (len != 0) { 408184610Salfred xfer->nFrames = 2; 409213852Shselasky xfer->ppBuffer[1] = libusb20_pass_ptr(pBuf); 410184610Salfred xfer->pLength[1] = len; 411184610Salfred } else { 412184610Salfred xfer->nFrames = 1; 413184610Salfred } 414184610Salfred return; 415184610Salfred} 416184610Salfred 417184610Salfredvoid 418184610Salfredlibusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 419184610Salfred{ 420213852Shselasky xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf); 421184610Salfred xfer->pLength[0] = length; 422184610Salfred xfer->timeout = timeout; 423184610Salfred xfer->nFrames = 1; 424184610Salfred return; 425184610Salfred} 426184610Salfred 427184610Salfredvoid 428184610Salfredlibusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex) 429184610Salfred{ 430184610Salfred if (frIndex >= xfer->maxFrames) { 431184610Salfred /* should not happen */ 432184610Salfred return; 433184610Salfred } 434213852Shselasky xfer->ppBuffer[frIndex] = libusb20_pass_ptr(pBuf); 435184610Salfred xfer->pLength[frIndex] = length; 436184610Salfred return; 437184610Salfred} 438184610Salfred 439199575Sthompsauint8_t 440199575Sthompsalibusb20_tr_bulk_intr_sync(struct libusb20_transfer *xfer, 441199575Sthompsa void *pbuf, uint32_t length, uint32_t *pactlen, 442199575Sthompsa uint32_t timeout) 443199575Sthompsa{ 444199575Sthompsa struct libusb20_device *pdev = xfer->pdev; 445199575Sthompsa uint32_t transfer_max; 446199575Sthompsa uint32_t transfer_act; 447199575Sthompsa uint8_t retval; 448199575Sthompsa 449199575Sthompsa /* set some sensible default value */ 450199575Sthompsa if (pactlen != NULL) 451199575Sthompsa *pactlen = 0; 452199575Sthompsa 453199575Sthompsa /* check for error condition */ 454199575Sthompsa if (libusb20_tr_pending(xfer)) 455199575Sthompsa return (LIBUSB20_ERROR_OTHER); 456199575Sthompsa 457199575Sthompsa do { 458199575Sthompsa /* compute maximum transfer length */ 459199575Sthompsa transfer_max = 460199575Sthompsa libusb20_tr_get_max_total_length(xfer); 461199575Sthompsa 462199575Sthompsa if (transfer_max > length) 463199575Sthompsa transfer_max = length; 464199575Sthompsa 465199575Sthompsa /* setup bulk or interrupt transfer */ 466199575Sthompsa libusb20_tr_setup_bulk(xfer, pbuf, 467199575Sthompsa transfer_max, timeout); 468199575Sthompsa 469199575Sthompsa /* start the transfer */ 470199575Sthompsa libusb20_tr_start(xfer); 471199575Sthompsa 472199575Sthompsa /* wait for transfer completion */ 473199575Sthompsa while (libusb20_dev_process(pdev) == 0) { 474199575Sthompsa 475199575Sthompsa if (libusb20_tr_pending(xfer) == 0) 476199575Sthompsa break; 477199575Sthompsa 478199575Sthompsa libusb20_dev_wait_process(pdev, -1); 479199575Sthompsa } 480199575Sthompsa 481199575Sthompsa transfer_act = libusb20_tr_get_actual_length(xfer); 482199575Sthompsa 483199575Sthompsa /* update actual length, if any */ 484199575Sthompsa if (pactlen != NULL) 485199575Sthompsa pactlen[0] += transfer_act; 486199575Sthompsa 487199575Sthompsa /* check transfer status */ 488199575Sthompsa retval = libusb20_tr_get_status(xfer); 489199575Sthompsa if (retval) 490199575Sthompsa break; 491199575Sthompsa 492199575Sthompsa /* check for short transfer */ 493199575Sthompsa if (transfer_act != transfer_max) 494199575Sthompsa break; 495199575Sthompsa 496199575Sthompsa /* update buffer pointer and length */ 497199575Sthompsa pbuf = ((uint8_t *)pbuf) + transfer_max; 498199575Sthompsa length = length - transfer_max; 499199575Sthompsa 500199575Sthompsa } while (length != 0); 501199575Sthompsa 502199575Sthompsa return (retval); 503199575Sthompsa} 504199575Sthompsa 505184610Salfredvoid 506184610Salfredlibusb20_tr_submit(struct libusb20_transfer *xfer) 507184610Salfred{ 508199575Sthompsa if (!xfer->is_opened) { 509199575Sthompsa /* transfer is not opened */ 510199575Sthompsa return; 511199575Sthompsa } 512184610Salfred if (xfer->is_pending) { 513184610Salfred /* should not happen */ 514184610Salfred return; 515184610Salfred } 516184610Salfred xfer->is_pending = 1; /* we are pending */ 517184610Salfred xfer->is_cancel = 0; /* not cancelling */ 518184610Salfred xfer->is_restart = 0; /* not restarting */ 519184610Salfred 520188622Sthompsa xfer->pdev->methods->tr_submit(xfer); 521184610Salfred return; 522184610Salfred} 523184610Salfred 524184610Salfredvoid 525184610Salfredlibusb20_tr_start(struct libusb20_transfer *xfer) 526184610Salfred{ 527199575Sthompsa if (!xfer->is_opened) { 528199575Sthompsa /* transfer is not opened */ 529199575Sthompsa return; 530199575Sthompsa } 531184610Salfred if (xfer->is_pending) { 532184610Salfred if (xfer->is_cancel) { 533184610Salfred /* cancelling - restart */ 534184610Salfred xfer->is_restart = 1; 535184610Salfred } 536184610Salfred /* transfer not pending */ 537184610Salfred return; 538184610Salfred } 539184610Salfred /* get into the callback */ 540184610Salfred libusb20_tr_callback_wrapper(xfer); 541184610Salfred return; 542184610Salfred} 543184610Salfred 544184610Salfred/* USB device operations */ 545184610Salfred 546184610Salfredint 547184610Salfredlibusb20_dev_close(struct libusb20_device *pdev) 548184610Salfred{ 549184610Salfred struct libusb20_transfer *xfer; 550184610Salfred uint16_t x; 551184610Salfred int error = 0; 552184610Salfred 553184610Salfred if (!pdev->is_opened) { 554184610Salfred return (LIBUSB20_ERROR_OTHER); 555184610Salfred } 556184610Salfred for (x = 0; x != pdev->nTransfer; x++) { 557184610Salfred xfer = pdev->pTransfer + x; 558184610Salfred 559199575Sthompsa if (!xfer->is_opened) { 560199575Sthompsa /* transfer is not opened */ 561199575Sthompsa continue; 562199575Sthompsa } 563199575Sthompsa 564184610Salfred libusb20_tr_drain(xfer); 565199575Sthompsa 566199575Sthompsa libusb20_tr_close(xfer); 567184610Salfred } 568184610Salfred 569184610Salfred if (pdev->pTransfer != NULL) { 570184610Salfred free(pdev->pTransfer); 571184610Salfred pdev->pTransfer = NULL; 572184610Salfred } 573188622Sthompsa error = pdev->beMethods->close_device(pdev); 574184610Salfred 575184610Salfred pdev->methods = &libusb20_dummy_methods; 576184610Salfred 577184610Salfred pdev->is_opened = 0; 578184610Salfred 579194069Sthompsa /* 580194069Sthompsa * The following variable is only used by the libusb v0.1 581194069Sthompsa * compat layer: 582194069Sthompsa */ 583194069Sthompsa pdev->claimed_interface = 0; 584187184Sthompsa 585184610Salfred return (error); 586184610Salfred} 587184610Salfred 588184610Salfredint 589184610Salfredlibusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex) 590184610Salfred{ 591184610Salfred int error; 592184610Salfred 593188622Sthompsa error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex); 594184610Salfred return (error); 595184610Salfred} 596184610Salfred 597184610Salfredstruct LIBUSB20_DEVICE_DESC_DECODED * 598184610Salfredlibusb20_dev_get_device_desc(struct libusb20_device *pdev) 599184610Salfred{ 600184610Salfred return (&(pdev->ddesc)); 601184610Salfred} 602184610Salfred 603184610Salfredint 604184610Salfredlibusb20_dev_get_fd(struct libusb20_device *pdev) 605184610Salfred{ 606184610Salfred return (pdev->file); 607184610Salfred} 608184610Salfred 609184610Salfredint 610184610Salfredlibusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex) 611184610Salfred{ 612184610Salfred int error; 613184610Salfred 614188622Sthompsa error = pdev->methods->kernel_driver_active(pdev, ifaceIndex); 615184610Salfred return (error); 616184610Salfred} 617184610Salfred 618184610Salfredint 619184610Salfredlibusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax) 620184610Salfred{ 621184610Salfred struct libusb20_transfer *xfer; 622184610Salfred uint32_t size; 623184610Salfred uint16_t x; 624184610Salfred int error; 625184610Salfred 626184610Salfred if (pdev->is_opened) { 627184610Salfred return (LIBUSB20_ERROR_BUSY); 628184610Salfred } 629184610Salfred if (nTransferMax >= 256) { 630184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 631184610Salfred } else if (nTransferMax != 0) { 632184610Salfred size = sizeof(pdev->pTransfer[0]) * nTransferMax; 633184610Salfred pdev->pTransfer = malloc(size); 634184610Salfred if (pdev->pTransfer == NULL) { 635184610Salfred return (LIBUSB20_ERROR_NO_MEM); 636184610Salfred } 637184610Salfred memset(pdev->pTransfer, 0, size); 638184610Salfred } 639184610Salfred /* initialise all transfers */ 640184610Salfred for (x = 0; x != nTransferMax; x++) { 641184610Salfred 642184610Salfred xfer = pdev->pTransfer + x; 643184610Salfred 644184610Salfred xfer->pdev = pdev; 645184610Salfred xfer->trIndex = x; 646184610Salfred xfer->callback = &dummy_callback; 647184610Salfred } 648184610Salfred 649185087Salfred /* set "nTransfer" early */ 650185087Salfred pdev->nTransfer = nTransferMax; 651185087Salfred 652188622Sthompsa error = pdev->beMethods->open_device(pdev, nTransferMax); 653184610Salfred 654184610Salfred if (error) { 655184610Salfred if (pdev->pTransfer != NULL) { 656184610Salfred free(pdev->pTransfer); 657184610Salfred pdev->pTransfer = NULL; 658184610Salfred } 659184610Salfred pdev->file = -1; 660184610Salfred pdev->file_ctrl = -1; 661184610Salfred pdev->nTransfer = 0; 662184610Salfred } else { 663184610Salfred pdev->is_opened = 1; 664184610Salfred } 665184610Salfred return (error); 666184610Salfred} 667184610Salfred 668184610Salfredint 669184610Salfredlibusb20_dev_reset(struct libusb20_device *pdev) 670184610Salfred{ 671184610Salfred int error; 672184610Salfred 673188622Sthompsa error = pdev->methods->reset_device(pdev); 674184610Salfred return (error); 675184610Salfred} 676184610Salfred 677184610Salfredint 678203147Sthompsalibusb20_dev_check_connected(struct libusb20_device *pdev) 679203147Sthompsa{ 680203147Sthompsa int error; 681203147Sthompsa 682203147Sthompsa error = pdev->methods->check_connected(pdev); 683203147Sthompsa return (error); 684203147Sthompsa} 685203147Sthompsa 686203147Sthompsaint 687184610Salfredlibusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 688184610Salfred{ 689184610Salfred int error; 690184610Salfred 691188622Sthompsa error = pdev->methods->set_power_mode(pdev, power_mode); 692184610Salfred return (error); 693184610Salfred} 694184610Salfred 695184610Salfreduint8_t 696184610Salfredlibusb20_dev_get_power_mode(struct libusb20_device *pdev) 697184610Salfred{ 698184610Salfred int error; 699184610Salfred uint8_t power_mode; 700184610Salfred 701188622Sthompsa error = pdev->methods->get_power_mode(pdev, &power_mode); 702184610Salfred if (error) 703184610Salfred power_mode = LIBUSB20_POWER_ON; /* fake power mode */ 704184610Salfred return (power_mode); 705184610Salfred} 706184610Salfred 707184610Salfredint 708184610Salfredlibusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex) 709184610Salfred{ 710184610Salfred int error; 711184610Salfred 712188622Sthompsa error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex); 713184610Salfred return (error); 714184610Salfred} 715184610Salfred 716184610Salfredint 717184610Salfredlibusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex) 718184610Salfred{ 719184610Salfred int error; 720184610Salfred 721188622Sthompsa error = pdev->methods->set_config_index(pdev, configIndex); 722184610Salfred return (error); 723184610Salfred} 724184610Salfred 725184610Salfredint 726184610Salfredlibusb20_dev_request_sync(struct libusb20_device *pdev, 727184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data, 728184610Salfred uint16_t *pactlen, uint32_t timeout, uint8_t flags) 729184610Salfred{ 730184610Salfred int error; 731184610Salfred 732188622Sthompsa error = pdev->methods->do_request_sync(pdev, 733184610Salfred setup, data, pactlen, timeout, flags); 734184610Salfred return (error); 735184610Salfred} 736184610Salfred 737184610Salfredint 738184610Salfredlibusb20_dev_req_string_sync(struct libusb20_device *pdev, 739185087Salfred uint8_t str_index, uint16_t langid, void *ptr, uint16_t len) 740184610Salfred{ 741184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED req; 742184610Salfred int error; 743184610Salfred 744199055Sthompsa /* make sure memory is initialised */ 745199055Sthompsa memset(ptr, 0, len); 746199055Sthompsa 747184610Salfred if (len < 4) { 748184610Salfred /* invalid length */ 749184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 750184610Salfred } 751184610Salfred LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req); 752184610Salfred 753184610Salfred /* 754184610Salfred * We need to read the USB string in two steps else some USB 755184610Salfred * devices will complain. 756184610Salfred */ 757184610Salfred req.bmRequestType = 758184610Salfred LIBUSB20_REQUEST_TYPE_STANDARD | 759184610Salfred LIBUSB20_RECIPIENT_DEVICE | 760184610Salfred LIBUSB20_ENDPOINT_IN; 761184610Salfred req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR; 762185087Salfred req.wValue = (LIBUSB20_DT_STRING << 8) | str_index; 763184610Salfred req.wIndex = langid; 764184610Salfred req.wLength = 4; /* bytes */ 765184610Salfred 766184610Salfred error = libusb20_dev_request_sync(pdev, &req, 767184610Salfred ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 768184610Salfred if (error) { 769184610Salfred return (error); 770184610Salfred } 771184610Salfred req.wLength = *(uint8_t *)ptr; /* bytes */ 772184610Salfred if (req.wLength > len) { 773184610Salfred /* partial string read */ 774184610Salfred req.wLength = len; 775184610Salfred } 776184610Salfred error = libusb20_dev_request_sync(pdev, &req, 777184610Salfred ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 778184610Salfred 779184610Salfred if (error) { 780184610Salfred return (error); 781184610Salfred } 782184610Salfred if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) { 783184610Salfred return (LIBUSB20_ERROR_OTHER); 784184610Salfred } 785184610Salfred return (0); /* success */ 786184610Salfred} 787184610Salfred 788184610Salfredint 789184610Salfredlibusb20_dev_req_string_simple_sync(struct libusb20_device *pdev, 790185087Salfred uint8_t str_index, void *ptr, uint16_t len) 791184610Salfred{ 792184610Salfred char *buf; 793184610Salfred int error; 794184610Salfred uint16_t langid; 795184610Salfred uint16_t n; 796184610Salfred uint16_t i; 797184610Salfred uint16_t c; 798184610Salfred uint8_t temp[255]; 799184610Salfred uint8_t swap; 800184610Salfred 801184610Salfred /* the following code derives from the FreeBSD USB kernel */ 802184610Salfred 803184610Salfred if ((len < 1) || (ptr == NULL)) { 804184610Salfred /* too short buffer */ 805184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 806184610Salfred } 807184610Salfred error = libusb20_dev_req_string_sync(pdev, 808184610Salfred 0, 0, temp, sizeof(temp)); 809185087Salfred if (error < 0) { 810185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 811184610Salfred return (error); 812185087Salfred } 813184610Salfred langid = temp[2] | (temp[3] << 8); 814184610Salfred 815185087Salfred error = libusb20_dev_req_string_sync(pdev, str_index, 816184610Salfred langid, temp, sizeof(temp)); 817185087Salfred if (error < 0) { 818185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 819184610Salfred return (error); 820185087Salfred } 821184610Salfred if (temp[0] < 2) { 822184610Salfred /* string length is too short */ 823185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 824184610Salfred return (LIBUSB20_ERROR_OTHER); 825184610Salfred } 826184610Salfred /* reserve one byte for terminating zero */ 827184610Salfred len--; 828184610Salfred 829184610Salfred /* find maximum length */ 830184610Salfred n = (temp[0] / 2) - 1; 831184610Salfred if (n > len) { 832184610Salfred n = len; 833184610Salfred } 834184610Salfred /* reset swap state */ 835184610Salfred swap = 3; 836184610Salfred 837184610Salfred /* setup output buffer pointer */ 838184610Salfred buf = ptr; 839184610Salfred 840184610Salfred /* convert and filter */ 841184610Salfred for (i = 0; (i != n); i++) { 842184610Salfred c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8); 843184610Salfred 844184610Salfred /* convert from Unicode, handle buggy strings */ 845184610Salfred if (((c & 0xff00) == 0) && (swap & 1)) { 846184610Salfred /* Little Endian, default */ 847184610Salfred *buf = c; 848184610Salfred swap = 1; 849184610Salfred } else if (((c & 0x00ff) == 0) && (swap & 2)) { 850184610Salfred /* Big Endian */ 851184610Salfred *buf = c >> 8; 852184610Salfred swap = 2; 853184610Salfred } else { 854185087Salfred /* skip invalid character */ 855185087Salfred continue; 856184610Salfred } 857184610Salfred /* 858184610Salfred * Filter by default - we don't allow greater and less than 859184610Salfred * signs because they might confuse the dmesg printouts! 860184610Salfred */ 861184610Salfred if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) { 862185087Salfred /* skip invalid character */ 863185087Salfred continue; 864184610Salfred } 865184610Salfred buf++; 866184610Salfred } 867184610Salfred *buf = 0; /* zero terminate string */ 868184610Salfred 869184610Salfred return (0); 870184610Salfred} 871184610Salfred 872184610Salfredstruct libusb20_config * 873184610Salfredlibusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex) 874184610Salfred{ 875184610Salfred struct libusb20_config *retval = NULL; 876184610Salfred uint8_t *ptr; 877184610Salfred uint16_t len; 878184610Salfred uint8_t do_close; 879184610Salfred int error; 880184610Salfred 881184610Salfred if (!pdev->is_opened) { 882184610Salfred error = libusb20_dev_open(pdev, 0); 883184610Salfred if (error) { 884184610Salfred return (NULL); 885184610Salfred } 886184610Salfred do_close = 1; 887184610Salfred } else { 888184610Salfred do_close = 0; 889184610Salfred } 890188622Sthompsa error = pdev->methods->get_config_desc_full(pdev, 891184610Salfred &ptr, &len, configIndex); 892184610Salfred 893184610Salfred if (error) { 894184610Salfred goto done; 895184610Salfred } 896184610Salfred /* parse new config descriptor */ 897184610Salfred retval = libusb20_parse_config_desc(ptr); 898184610Salfred 899184610Salfred /* free config descriptor */ 900184610Salfred free(ptr); 901184610Salfred 902184610Salfreddone: 903184610Salfred if (do_close) { 904184610Salfred error = libusb20_dev_close(pdev); 905184610Salfred } 906184610Salfred return (retval); 907184610Salfred} 908184610Salfred 909184610Salfredstruct libusb20_device * 910184610Salfredlibusb20_dev_alloc(void) 911184610Salfred{ 912184610Salfred struct libusb20_device *pdev; 913184610Salfred 914184610Salfred pdev = malloc(sizeof(*pdev)); 915184610Salfred if (pdev == NULL) { 916184610Salfred return (NULL); 917184610Salfred } 918184610Salfred memset(pdev, 0, sizeof(*pdev)); 919184610Salfred 920184610Salfred pdev->file = -1; 921184610Salfred pdev->file_ctrl = -1; 922184610Salfred pdev->methods = &libusb20_dummy_methods; 923184610Salfred return (pdev); 924184610Salfred} 925184610Salfred 926184610Salfreduint8_t 927184610Salfredlibusb20_dev_get_config_index(struct libusb20_device *pdev) 928184610Salfred{ 929184610Salfred int error; 930185087Salfred uint8_t cfg_index; 931184610Salfred uint8_t do_close; 932184610Salfred 933184610Salfred if (!pdev->is_opened) { 934184610Salfred error = libusb20_dev_open(pdev, 0); 935184610Salfred if (error == 0) { 936184610Salfred do_close = 1; 937184610Salfred } else { 938184610Salfred do_close = 0; 939184610Salfred } 940184610Salfred } else { 941184610Salfred do_close = 0; 942184610Salfred } 943184610Salfred 944188622Sthompsa error = pdev->methods->get_config_index(pdev, &cfg_index); 945184610Salfred if (error) { 946185087Salfred cfg_index = 0 - 1; /* current config index */ 947184610Salfred } 948184610Salfred if (do_close) { 949184610Salfred if (libusb20_dev_close(pdev)) { 950184610Salfred /* ignore */ 951184610Salfred } 952184610Salfred } 953185087Salfred return (cfg_index); 954184610Salfred} 955184610Salfred 956184610Salfreduint8_t 957184610Salfredlibusb20_dev_get_mode(struct libusb20_device *pdev) 958184610Salfred{ 959184610Salfred return (pdev->usb_mode); 960184610Salfred} 961184610Salfred 962184610Salfreduint8_t 963184610Salfredlibusb20_dev_get_speed(struct libusb20_device *pdev) 964184610Salfred{ 965184610Salfred return (pdev->usb_speed); 966184610Salfred} 967184610Salfred 968184610Salfred/* if this function returns an error, the device is gone */ 969184610Salfredint 970184610Salfredlibusb20_dev_process(struct libusb20_device *pdev) 971184610Salfred{ 972184610Salfred int error; 973184610Salfred 974188622Sthompsa error = pdev->methods->process(pdev); 975184610Salfred return (error); 976184610Salfred} 977184610Salfred 978184610Salfredvoid 979184610Salfredlibusb20_dev_wait_process(struct libusb20_device *pdev, int timeout) 980184610Salfred{ 981185087Salfred struct pollfd pfd[1]; 982184610Salfred 983184610Salfred if (!pdev->is_opened) { 984184610Salfred return; 985184610Salfred } 986184610Salfred pfd[0].fd = pdev->file; 987184610Salfred pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 988184610Salfred pfd[0].revents = 0; 989184610Salfred 990185087Salfred if (poll(pfd, 1, timeout)) { 991184610Salfred /* ignore any error */ 992184610Salfred } 993184610Salfred return; 994184610Salfred} 995184610Salfred 996184610Salfredvoid 997184610Salfredlibusb20_dev_free(struct libusb20_device *pdev) 998184610Salfred{ 999184610Salfred if (pdev == NULL) { 1000184610Salfred /* be NULL safe */ 1001184610Salfred return; 1002184610Salfred } 1003184610Salfred if (pdev->is_opened) { 1004184610Salfred if (libusb20_dev_close(pdev)) { 1005184610Salfred /* ignore any errors */ 1006184610Salfred } 1007184610Salfred } 1008184610Salfred free(pdev); 1009184610Salfred return; 1010184610Salfred} 1011184610Salfred 1012188622Sthompsaint 1013188622Sthompsalibusb20_dev_get_info(struct libusb20_device *pdev, 1014192984Sthompsa struct usb_device_info *pinfo) 1015188622Sthompsa{ 1016188622Sthompsa if (pinfo == NULL) 1017188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 1018188622Sthompsa 1019188622Sthompsa return (pdev->beMethods->dev_get_info(pdev, pinfo)); 1020188622Sthompsa} 1021188622Sthompsa 1022184610Salfredconst char * 1023184610Salfredlibusb20_dev_get_backend_name(struct libusb20_device *pdev) 1024184610Salfred{ 1025188622Sthompsa return (pdev->beMethods->get_backend_name()); 1026184610Salfred} 1027184610Salfred 1028184610Salfredconst char * 1029184610Salfredlibusb20_dev_get_desc(struct libusb20_device *pdev) 1030184610Salfred{ 1031184610Salfred return (pdev->usb_desc); 1032184610Salfred} 1033184610Salfred 1034184610Salfredvoid 1035184610Salfredlibusb20_dev_set_debug(struct libusb20_device *pdev, int debug) 1036184610Salfred{ 1037184610Salfred pdev->debug = debug; 1038184610Salfred return; 1039184610Salfred} 1040184610Salfred 1041184610Salfredint 1042184610Salfredlibusb20_dev_get_debug(struct libusb20_device *pdev) 1043184610Salfred{ 1044184610Salfred return (pdev->debug); 1045184610Salfred} 1046184610Salfred 1047184610Salfreduint8_t 1048184610Salfredlibusb20_dev_get_address(struct libusb20_device *pdev) 1049184610Salfred{ 1050184610Salfred return (pdev->device_address); 1051184610Salfred} 1052184610Salfred 1053184610Salfreduint8_t 1054184610Salfredlibusb20_dev_get_bus_number(struct libusb20_device *pdev) 1055184610Salfred{ 1056184610Salfred return (pdev->bus_number); 1057184610Salfred} 1058184610Salfred 1059184610Salfredint 1060188622Sthompsalibusb20_dev_get_iface_desc(struct libusb20_device *pdev, 1061188622Sthompsa uint8_t iface_index, char *buf, uint8_t len) 1062188622Sthompsa{ 1063188622Sthompsa if ((buf == NULL) || (len == 0)) 1064188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 1065188622Sthompsa 1066188622Sthompsa return (pdev->beMethods->dev_get_iface_desc( 1067188622Sthompsa pdev, iface_index, buf, len)); 1068188622Sthompsa} 1069188622Sthompsa 1070184610Salfred/* USB backend operations */ 1071184610Salfred 1072184610Salfredint 1073184610Salfredlibusb20_be_get_dev_quirk(struct libusb20_backend *pbe, 1074185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 1075184610Salfred{ 1076188622Sthompsa return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq)); 1077184610Salfred} 1078184610Salfred 1079184610Salfredint 1080184610Salfredlibusb20_be_get_quirk_name(struct libusb20_backend *pbe, 1081185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 1082184610Salfred{ 1083188622Sthompsa return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq)); 1084184610Salfred} 1085184610Salfred 1086184610Salfredint 1087184610Salfredlibusb20_be_add_dev_quirk(struct libusb20_backend *pbe, 1088184610Salfred struct libusb20_quirk *pq) 1089184610Salfred{ 1090188622Sthompsa return (pbe->methods->root_add_dev_quirk(pbe, pq)); 1091184610Salfred} 1092184610Salfred 1093184610Salfredint 1094184610Salfredlibusb20_be_remove_dev_quirk(struct libusb20_backend *pbe, 1095184610Salfred struct libusb20_quirk *pq) 1096184610Salfred{ 1097188622Sthompsa return (pbe->methods->root_remove_dev_quirk(pbe, pq)); 1098184610Salfred} 1099184610Salfred 1100184610Salfredint 1101188987Sthompsalibusb20_be_set_template(struct libusb20_backend *pbe, int temp) 1102188987Sthompsa{ 1103188987Sthompsa return (pbe->methods->root_set_template(pbe, temp)); 1104188987Sthompsa} 1105188987Sthompsa 1106188987Sthompsaint 1107188987Sthompsalibusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp) 1108188987Sthompsa{ 1109188987Sthompsa int temp; 1110188987Sthompsa 1111188987Sthompsa if (ptemp == NULL) 1112188987Sthompsa ptemp = &temp; 1113188987Sthompsa 1114188987Sthompsa return (pbe->methods->root_get_template(pbe, ptemp)); 1115188987Sthompsa} 1116188987Sthompsa 1117184610Salfredstruct libusb20_device * 1118184610Salfredlibusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1119184610Salfred{ 1120184610Salfred if (pbe == NULL) { 1121184610Salfred pdev = NULL; 1122184610Salfred } else if (pdev == NULL) { 1123184610Salfred pdev = TAILQ_FIRST(&(pbe->usb_devs)); 1124184610Salfred } else { 1125184610Salfred pdev = TAILQ_NEXT(pdev, dev_entry); 1126184610Salfred } 1127184610Salfred return (pdev); 1128184610Salfred} 1129184610Salfred 1130184610Salfredstruct libusb20_backend * 1131184610Salfredlibusb20_be_alloc(const struct libusb20_backend_methods *methods) 1132184610Salfred{ 1133184610Salfred struct libusb20_backend *pbe; 1134184610Salfred 1135184610Salfred pbe = malloc(sizeof(*pbe)); 1136184610Salfred if (pbe == NULL) { 1137184610Salfred return (NULL); 1138184610Salfred } 1139184610Salfred memset(pbe, 0, sizeof(*pbe)); 1140184610Salfred 1141184610Salfred TAILQ_INIT(&(pbe->usb_devs)); 1142184610Salfred 1143184610Salfred pbe->methods = methods; /* set backend methods */ 1144184610Salfred 1145184610Salfred /* do the initial device scan */ 1146184610Salfred if (pbe->methods->init_backend) { 1147188622Sthompsa pbe->methods->init_backend(pbe); 1148184610Salfred } 1149184610Salfred return (pbe); 1150184610Salfred} 1151184610Salfred 1152184610Salfredstruct libusb20_backend * 1153184610Salfredlibusb20_be_alloc_linux(void) 1154184610Salfred{ 1155184610Salfred struct libusb20_backend *pbe; 1156184610Salfred 1157184610Salfred#ifdef __linux__ 1158184610Salfred pbe = libusb20_be_alloc(&libusb20_linux_backend); 1159184610Salfred#else 1160184610Salfred pbe = NULL; 1161184610Salfred#endif 1162184610Salfred return (pbe); 1163184610Salfred} 1164184610Salfred 1165184610Salfredstruct libusb20_backend * 1166184610Salfredlibusb20_be_alloc_ugen20(void) 1167184610Salfred{ 1168184610Salfred struct libusb20_backend *pbe; 1169184610Salfred 1170213852Shselasky#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 1171184610Salfred pbe = libusb20_be_alloc(&libusb20_ugen20_backend); 1172184610Salfred#else 1173184610Salfred pbe = NULL; 1174184610Salfred#endif 1175184610Salfred return (pbe); 1176184610Salfred} 1177184610Salfred 1178184610Salfredstruct libusb20_backend * 1179184610Salfredlibusb20_be_alloc_default(void) 1180184610Salfred{ 1181184610Salfred struct libusb20_backend *pbe; 1182184610Salfred 1183184610Salfred pbe = libusb20_be_alloc_linux(); 1184184610Salfred if (pbe) { 1185184610Salfred return (pbe); 1186184610Salfred } 1187184610Salfred pbe = libusb20_be_alloc_ugen20(); 1188184610Salfred if (pbe) { 1189184610Salfred return (pbe); 1190184610Salfred } 1191184610Salfred return (NULL); /* no backend found */ 1192184610Salfred} 1193184610Salfred 1194184610Salfredvoid 1195184610Salfredlibusb20_be_free(struct libusb20_backend *pbe) 1196184610Salfred{ 1197184610Salfred struct libusb20_device *pdev; 1198184610Salfred 1199184610Salfred if (pbe == NULL) { 1200184610Salfred /* be NULL safe */ 1201184610Salfred return; 1202184610Salfred } 1203184610Salfred while ((pdev = libusb20_be_device_foreach(pbe, NULL))) { 1204184610Salfred libusb20_be_dequeue_device(pbe, pdev); 1205184610Salfred libusb20_dev_free(pdev); 1206184610Salfred } 1207184610Salfred if (pbe->methods->exit_backend) { 1208188622Sthompsa pbe->methods->exit_backend(pbe); 1209184610Salfred } 1210199055Sthompsa /* free backend */ 1211199055Sthompsa free(pbe); 1212184610Salfred} 1213184610Salfred 1214184610Salfredvoid 1215184610Salfredlibusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1216184610Salfred{ 1217184610Salfred pdev->beMethods = pbe->methods; /* copy backend methods */ 1218184610Salfred TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry); 1219184610Salfred} 1220184610Salfred 1221184610Salfredvoid 1222184610Salfredlibusb20_be_dequeue_device(struct libusb20_backend *pbe, 1223184610Salfred struct libusb20_device *pdev) 1224184610Salfred{ 1225184610Salfred TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry); 1226184610Salfred} 1227