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