libusb20.c revision 202025
1184610Salfred/* $FreeBSD: head/lib/libusb/libusb20.c 202025 2010-01-10 19:18:49Z 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 70184610Salfred#define dummy_set_power_mode (void *)dummy_int 71184610Salfred#define dummy_get_power_mode (void *)dummy_int 72184610Salfred#define dummy_kernel_driver_active (void *)dummy_int 73184610Salfred#define dummy_detach_kernel_driver (void *)dummy_int 74184610Salfred#define dummy_do_request_sync (void *)dummy_int 75184610Salfred#define dummy_tr_open (void *)dummy_int 76184610Salfred#define dummy_tr_close (void *)dummy_int 77184610Salfred#define dummy_tr_clear_stall_sync (void *)dummy_int 78184610Salfred#define dummy_process (void *)dummy_int 79188622Sthompsa#define dummy_dev_info (void *)dummy_int 80188622Sthompsa#define dummy_dev_get_iface_driver (void *)dummy_int 81184610Salfred 82184610Salfred#define dummy_tr_submit (void *)dummy_void 83184610Salfred#define dummy_tr_cancel_async (void *)dummy_void 84184610Salfred 85184610Salfredstatic const struct libusb20_device_methods libusb20_dummy_methods = { 86184610Salfred LIBUSB20_DEVICE(LIBUSB20_DECLARE, dummy) 87184610Salfred}; 88184610Salfred 89184610Salfredvoid 90184610Salfredlibusb20_tr_callback_wrapper(struct libusb20_transfer *xfer) 91184610Salfred{ 92184610Salfred ; /* style fix */ 93184610Salfred 94184610Salfredrepeat: 95184610Salfred 96184610Salfred if (!xfer->is_pending) { 97184610Salfred xfer->status = LIBUSB20_TRANSFER_START; 98184610Salfred } else { 99184610Salfred xfer->is_pending = 0; 100184610Salfred } 101184610Salfred 102188622Sthompsa xfer->callback(xfer); 103184610Salfred 104184610Salfred if (xfer->is_restart) { 105184610Salfred xfer->is_restart = 0; 106184610Salfred goto repeat; 107184610Salfred } 108184610Salfred if (xfer->is_draining && 109184610Salfred (!xfer->is_pending)) { 110184610Salfred xfer->is_draining = 0; 111184610Salfred xfer->status = LIBUSB20_TRANSFER_DRAINED; 112188622Sthompsa xfer->callback(xfer); 113184610Salfred } 114184610Salfred return; 115184610Salfred} 116184610Salfred 117184610Salfredint 118184610Salfredlibusb20_tr_close(struct libusb20_transfer *xfer) 119184610Salfred{ 120184610Salfred int error; 121184610Salfred 122184610Salfred if (!xfer->is_opened) { 123184610Salfred return (LIBUSB20_ERROR_OTHER); 124184610Salfred } 125188622Sthompsa error = xfer->pdev->methods->tr_close(xfer); 126184610Salfred 127184610Salfred if (xfer->pLength) { 128184610Salfred free(xfer->pLength); 129184610Salfred } 130184610Salfred if (xfer->ppBuffer) { 131184610Salfred free(xfer->ppBuffer); 132184610Salfred } 133202025Sthompsa /* reset variable fields in case the transfer is opened again */ 134202025Sthompsa xfer->priv_sc0 = 0; 135202025Sthompsa xfer->priv_sc1 = 0; 136184610Salfred xfer->is_opened = 0; 137202025Sthompsa xfer->is_pending = 0; 138202025Sthompsa xfer->is_cancel = 0; 139202025Sthompsa xfer->is_draining = 0; 140202025Sthompsa xfer->is_restart = 0; 141202025Sthompsa xfer->status = 0; 142202025Sthompsa xfer->flags = 0; 143202025Sthompsa xfer->nFrames = 0; 144202025Sthompsa xfer->aFrames = 0; 145202025Sthompsa xfer->timeout = 0; 146184610Salfred xfer->maxFrames = 0; 147184610Salfred xfer->maxTotalLength = 0; 148184610Salfred xfer->maxPacketLen = 0; 149184610Salfred return (error); 150184610Salfred} 151184610Salfred 152184610Salfredint 153184610Salfredlibusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 154184610Salfred uint32_t MaxFrameCount, uint8_t ep_no) 155184610Salfred{ 156184610Salfred uint32_t size; 157184610Salfred int error; 158184610Salfred 159184610Salfred if (xfer->is_opened) { 160184610Salfred return (LIBUSB20_ERROR_BUSY); 161184610Salfred } 162184610Salfred if (MaxFrameCount == 0) { 163184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 164184610Salfred } 165184610Salfred xfer->maxFrames = MaxFrameCount; 166184610Salfred 167184610Salfred size = MaxFrameCount * sizeof(xfer->pLength[0]); 168184610Salfred xfer->pLength = malloc(size); 169184610Salfred if (xfer->pLength == NULL) { 170184610Salfred return (LIBUSB20_ERROR_NO_MEM); 171184610Salfred } 172184610Salfred memset(xfer->pLength, 0, size); 173184610Salfred 174184610Salfred size = MaxFrameCount * sizeof(xfer->ppBuffer[0]); 175184610Salfred xfer->ppBuffer = malloc(size); 176184610Salfred if (xfer->ppBuffer == NULL) { 177184610Salfred free(xfer->pLength); 178184610Salfred return (LIBUSB20_ERROR_NO_MEM); 179184610Salfred } 180184610Salfred memset(xfer->ppBuffer, 0, size); 181184610Salfred 182188622Sthompsa error = xfer->pdev->methods->tr_open(xfer, MaxBufSize, 183184610Salfred MaxFrameCount, ep_no); 184184610Salfred 185184610Salfred if (error) { 186184610Salfred free(xfer->ppBuffer); 187184610Salfred free(xfer->pLength); 188184610Salfred } else { 189184610Salfred xfer->is_opened = 1; 190184610Salfred } 191184610Salfred return (error); 192184610Salfred} 193184610Salfred 194184610Salfredstruct libusb20_transfer * 195184610Salfredlibusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex) 196184610Salfred{ 197184610Salfred if (trIndex >= pdev->nTransfer) { 198184610Salfred return (NULL); 199184610Salfred } 200184610Salfred return (pdev->pTransfer + trIndex); 201184610Salfred} 202184610Salfred 203184610Salfreduint32_t 204184610Salfredlibusb20_tr_get_actual_frames(struct libusb20_transfer *xfer) 205184610Salfred{ 206184610Salfred return (xfer->aFrames); 207184610Salfred} 208184610Salfred 209184610Salfreduint16_t 210184610Salfredlibusb20_tr_get_time_complete(struct libusb20_transfer *xfer) 211184610Salfred{ 212184610Salfred return (xfer->timeComplete); 213184610Salfred} 214184610Salfred 215184610Salfreduint32_t 216184610Salfredlibusb20_tr_get_actual_length(struct libusb20_transfer *xfer) 217184610Salfred{ 218184610Salfred uint32_t x; 219184610Salfred uint32_t actlen = 0; 220184610Salfred 221184610Salfred for (x = 0; x != xfer->aFrames; x++) { 222184610Salfred actlen += xfer->pLength[x]; 223184610Salfred } 224184610Salfred return (actlen); 225184610Salfred} 226184610Salfred 227184610Salfreduint32_t 228184610Salfredlibusb20_tr_get_max_frames(struct libusb20_transfer *xfer) 229184610Salfred{ 230184610Salfred return (xfer->maxFrames); 231184610Salfred} 232184610Salfred 233184610Salfreduint32_t 234184610Salfredlibusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer) 235184610Salfred{ 236184610Salfred /* 237184610Salfred * Special Case NOTE: If the packet multiplier is non-zero for 238184610Salfred * High Speed USB, the value returned is equal to 239184610Salfred * "wMaxPacketSize * multiplier" ! 240184610Salfred */ 241184610Salfred return (xfer->maxPacketLen); 242184610Salfred} 243184610Salfred 244184610Salfreduint32_t 245184610Salfredlibusb20_tr_get_max_total_length(struct libusb20_transfer *xfer) 246184610Salfred{ 247184610Salfred return (xfer->maxTotalLength); 248184610Salfred} 249184610Salfred 250184610Salfreduint8_t 251184610Salfredlibusb20_tr_get_status(struct libusb20_transfer *xfer) 252184610Salfred{ 253184610Salfred return (xfer->status); 254184610Salfred} 255184610Salfred 256184610Salfreduint8_t 257184610Salfredlibusb20_tr_pending(struct libusb20_transfer *xfer) 258184610Salfred{ 259184610Salfred return (xfer->is_pending); 260184610Salfred} 261184610Salfred 262184610Salfredvoid * 263184610Salfredlibusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer) 264184610Salfred{ 265184610Salfred return (xfer->priv_sc0); 266184610Salfred} 267184610Salfred 268184610Salfredvoid * 269184610Salfredlibusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer) 270184610Salfred{ 271184610Salfred return (xfer->priv_sc1); 272184610Salfred} 273184610Salfred 274184610Salfredvoid 275184610Salfredlibusb20_tr_stop(struct libusb20_transfer *xfer) 276184610Salfred{ 277199575Sthompsa if (!xfer->is_opened) { 278199575Sthompsa /* transfer is not opened */ 279199575Sthompsa return; 280199575Sthompsa } 281184610Salfred if (!xfer->is_pending) { 282184610Salfred /* transfer not pending */ 283184610Salfred return; 284184610Salfred } 285184610Salfred if (xfer->is_cancel) { 286184610Salfred /* already cancelling */ 287184610Salfred return; 288184610Salfred } 289184610Salfred xfer->is_cancel = 1; /* we are cancelling */ 290184610Salfred 291188622Sthompsa xfer->pdev->methods->tr_cancel_async(xfer); 292184610Salfred return; 293184610Salfred} 294184610Salfred 295184610Salfredvoid 296184610Salfredlibusb20_tr_drain(struct libusb20_transfer *xfer) 297184610Salfred{ 298199575Sthompsa if (!xfer->is_opened) { 299199575Sthompsa /* transfer is not opened */ 300199575Sthompsa return; 301199575Sthompsa } 302184610Salfred /* make sure that we are cancelling */ 303184610Salfred libusb20_tr_stop(xfer); 304184610Salfred 305184610Salfred if (xfer->is_pending) { 306184610Salfred xfer->is_draining = 1; 307184610Salfred } 308184610Salfred return; 309184610Salfred} 310184610Salfred 311184610Salfredvoid 312184610Salfredlibusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 313184610Salfred{ 314188622Sthompsa xfer->pdev->methods->tr_clear_stall_sync(xfer); 315184610Salfred return; 316184610Salfred} 317184610Salfred 318184610Salfredvoid 319184610Salfredlibusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex) 320184610Salfred{ 321184610Salfred xfer->ppBuffer[frIndex] = buffer; 322184610Salfred return; 323184610Salfred} 324184610Salfred 325184610Salfredvoid 326184610Salfredlibusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb) 327184610Salfred{ 328184610Salfred xfer->callback = cb; 329184610Salfred return; 330184610Salfred} 331184610Salfred 332184610Salfredvoid 333184610Salfredlibusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags) 334184610Salfred{ 335184610Salfred xfer->flags = flags; 336184610Salfred return; 337184610Salfred} 338184610Salfred 339193313Sthompsauint32_t 340193313Sthompsalibusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex) 341193313Sthompsa{ 342193313Sthompsa return (xfer->pLength[frIndex]); 343193313Sthompsa} 344193313Sthompsa 345184610Salfredvoid 346184610Salfredlibusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex) 347184610Salfred{ 348184610Salfred xfer->pLength[frIndex] = length; 349184610Salfred return; 350184610Salfred} 351184610Salfred 352184610Salfredvoid 353184610Salfredlibusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0) 354184610Salfred{ 355184610Salfred xfer->priv_sc0 = sc0; 356184610Salfred return; 357184610Salfred} 358184610Salfred 359184610Salfredvoid 360184610Salfredlibusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1) 361184610Salfred{ 362184610Salfred xfer->priv_sc1 = sc1; 363184610Salfred return; 364184610Salfred} 365184610Salfred 366184610Salfredvoid 367184610Salfredlibusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout) 368184610Salfred{ 369184610Salfred xfer->timeout = timeout; 370184610Salfred return; 371184610Salfred} 372184610Salfred 373184610Salfredvoid 374184610Salfredlibusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames) 375184610Salfred{ 376184610Salfred if (nFrames > xfer->maxFrames) { 377184610Salfred /* should not happen */ 378184610Salfred nFrames = xfer->maxFrames; 379184610Salfred } 380184610Salfred xfer->nFrames = nFrames; 381184610Salfred return; 382184610Salfred} 383184610Salfred 384184610Salfredvoid 385184610Salfredlibusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 386184610Salfred{ 387184610Salfred xfer->ppBuffer[0] = pBuf; 388184610Salfred xfer->pLength[0] = length; 389184610Salfred xfer->timeout = timeout; 390184610Salfred xfer->nFrames = 1; 391184610Salfred return; 392184610Salfred} 393184610Salfred 394184610Salfredvoid 395184610Salfredlibusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout) 396184610Salfred{ 397184610Salfred uint16_t len; 398184610Salfred 399184610Salfred xfer->ppBuffer[0] = psetup; 400184610Salfred xfer->pLength[0] = 8; /* fixed */ 401184610Salfred xfer->timeout = timeout; 402184610Salfred 403184610Salfred len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8); 404184610Salfred 405184610Salfred if (len != 0) { 406184610Salfred xfer->nFrames = 2; 407184610Salfred xfer->ppBuffer[1] = pBuf; 408184610Salfred xfer->pLength[1] = len; 409184610Salfred } else { 410184610Salfred xfer->nFrames = 1; 411184610Salfred } 412184610Salfred return; 413184610Salfred} 414184610Salfred 415184610Salfredvoid 416184610Salfredlibusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 417184610Salfred{ 418184610Salfred xfer->ppBuffer[0] = pBuf; 419184610Salfred xfer->pLength[0] = length; 420184610Salfred xfer->timeout = timeout; 421184610Salfred xfer->nFrames = 1; 422184610Salfred return; 423184610Salfred} 424184610Salfred 425184610Salfredvoid 426184610Salfredlibusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex) 427184610Salfred{ 428184610Salfred if (frIndex >= xfer->maxFrames) { 429184610Salfred /* should not happen */ 430184610Salfred return; 431184610Salfred } 432184610Salfred xfer->ppBuffer[frIndex] = pBuf; 433184610Salfred xfer->pLength[frIndex] = length; 434184610Salfred return; 435184610Salfred} 436184610Salfred 437199575Sthompsauint8_t 438199575Sthompsalibusb20_tr_bulk_intr_sync(struct libusb20_transfer *xfer, 439199575Sthompsa void *pbuf, uint32_t length, uint32_t *pactlen, 440199575Sthompsa uint32_t timeout) 441199575Sthompsa{ 442199575Sthompsa struct libusb20_device *pdev = xfer->pdev; 443199575Sthompsa uint32_t transfer_max; 444199575Sthompsa uint32_t transfer_act; 445199575Sthompsa uint8_t retval; 446199575Sthompsa 447199575Sthompsa /* set some sensible default value */ 448199575Sthompsa if (pactlen != NULL) 449199575Sthompsa *pactlen = 0; 450199575Sthompsa 451199575Sthompsa /* check for error condition */ 452199575Sthompsa if (libusb20_tr_pending(xfer)) 453199575Sthompsa return (LIBUSB20_ERROR_OTHER); 454199575Sthompsa 455199575Sthompsa do { 456199575Sthompsa /* compute maximum transfer length */ 457199575Sthompsa transfer_max = 458199575Sthompsa libusb20_tr_get_max_total_length(xfer); 459199575Sthompsa 460199575Sthompsa if (transfer_max > length) 461199575Sthompsa transfer_max = length; 462199575Sthompsa 463199575Sthompsa /* setup bulk or interrupt transfer */ 464199575Sthompsa libusb20_tr_setup_bulk(xfer, pbuf, 465199575Sthompsa transfer_max, timeout); 466199575Sthompsa 467199575Sthompsa /* start the transfer */ 468199575Sthompsa libusb20_tr_start(xfer); 469199575Sthompsa 470199575Sthompsa /* wait for transfer completion */ 471199575Sthompsa while (libusb20_dev_process(pdev) == 0) { 472199575Sthompsa 473199575Sthompsa if (libusb20_tr_pending(xfer) == 0) 474199575Sthompsa break; 475199575Sthompsa 476199575Sthompsa libusb20_dev_wait_process(pdev, -1); 477199575Sthompsa } 478199575Sthompsa 479199575Sthompsa transfer_act = libusb20_tr_get_actual_length(xfer); 480199575Sthompsa 481199575Sthompsa /* update actual length, if any */ 482199575Sthompsa if (pactlen != NULL) 483199575Sthompsa pactlen[0] += transfer_act; 484199575Sthompsa 485199575Sthompsa /* check transfer status */ 486199575Sthompsa retval = libusb20_tr_get_status(xfer); 487199575Sthompsa if (retval) 488199575Sthompsa break; 489199575Sthompsa 490199575Sthompsa /* check for short transfer */ 491199575Sthompsa if (transfer_act != transfer_max) 492199575Sthompsa break; 493199575Sthompsa 494199575Sthompsa /* update buffer pointer and length */ 495199575Sthompsa pbuf = ((uint8_t *)pbuf) + transfer_max; 496199575Sthompsa length = length - transfer_max; 497199575Sthompsa 498199575Sthompsa } while (length != 0); 499199575Sthompsa 500199575Sthompsa return (retval); 501199575Sthompsa} 502199575Sthompsa 503184610Salfredvoid 504184610Salfredlibusb20_tr_submit(struct libusb20_transfer *xfer) 505184610Salfred{ 506199575Sthompsa if (!xfer->is_opened) { 507199575Sthompsa /* transfer is not opened */ 508199575Sthompsa return; 509199575Sthompsa } 510184610Salfred if (xfer->is_pending) { 511184610Salfred /* should not happen */ 512184610Salfred return; 513184610Salfred } 514184610Salfred xfer->is_pending = 1; /* we are pending */ 515184610Salfred xfer->is_cancel = 0; /* not cancelling */ 516184610Salfred xfer->is_restart = 0; /* not restarting */ 517184610Salfred 518188622Sthompsa xfer->pdev->methods->tr_submit(xfer); 519184610Salfred return; 520184610Salfred} 521184610Salfred 522184610Salfredvoid 523184610Salfredlibusb20_tr_start(struct libusb20_transfer *xfer) 524184610Salfred{ 525199575Sthompsa if (!xfer->is_opened) { 526199575Sthompsa /* transfer is not opened */ 527199575Sthompsa return; 528199575Sthompsa } 529184610Salfred if (xfer->is_pending) { 530184610Salfred if (xfer->is_cancel) { 531184610Salfred /* cancelling - restart */ 532184610Salfred xfer->is_restart = 1; 533184610Salfred } 534184610Salfred /* transfer not pending */ 535184610Salfred return; 536184610Salfred } 537184610Salfred /* get into the callback */ 538184610Salfred libusb20_tr_callback_wrapper(xfer); 539184610Salfred return; 540184610Salfred} 541184610Salfred 542184610Salfred/* USB device operations */ 543184610Salfred 544184610Salfredint 545184610Salfredlibusb20_dev_close(struct libusb20_device *pdev) 546184610Salfred{ 547184610Salfred struct libusb20_transfer *xfer; 548184610Salfred uint16_t x; 549184610Salfred int error = 0; 550184610Salfred 551184610Salfred if (!pdev->is_opened) { 552184610Salfred return (LIBUSB20_ERROR_OTHER); 553184610Salfred } 554184610Salfred for (x = 0; x != pdev->nTransfer; x++) { 555184610Salfred xfer = pdev->pTransfer + x; 556184610Salfred 557199575Sthompsa if (!xfer->is_opened) { 558199575Sthompsa /* transfer is not opened */ 559199575Sthompsa continue; 560199575Sthompsa } 561199575Sthompsa 562184610Salfred libusb20_tr_drain(xfer); 563199575Sthompsa 564199575Sthompsa libusb20_tr_close(xfer); 565184610Salfred } 566184610Salfred 567184610Salfred if (pdev->pTransfer != NULL) { 568184610Salfred free(pdev->pTransfer); 569184610Salfred pdev->pTransfer = NULL; 570184610Salfred } 571188622Sthompsa error = pdev->beMethods->close_device(pdev); 572184610Salfred 573184610Salfred pdev->methods = &libusb20_dummy_methods; 574184610Salfred 575184610Salfred pdev->is_opened = 0; 576184610Salfred 577194069Sthompsa /* 578194069Sthompsa * The following variable is only used by the libusb v0.1 579194069Sthompsa * compat layer: 580194069Sthompsa */ 581194069Sthompsa pdev->claimed_interface = 0; 582187184Sthompsa 583184610Salfred return (error); 584184610Salfred} 585184610Salfred 586184610Salfredint 587184610Salfredlibusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex) 588184610Salfred{ 589184610Salfred int error; 590184610Salfred 591188622Sthompsa error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex); 592184610Salfred return (error); 593184610Salfred} 594184610Salfred 595184610Salfredstruct LIBUSB20_DEVICE_DESC_DECODED * 596184610Salfredlibusb20_dev_get_device_desc(struct libusb20_device *pdev) 597184610Salfred{ 598184610Salfred return (&(pdev->ddesc)); 599184610Salfred} 600184610Salfred 601184610Salfredint 602184610Salfredlibusb20_dev_get_fd(struct libusb20_device *pdev) 603184610Salfred{ 604184610Salfred return (pdev->file); 605184610Salfred} 606184610Salfred 607184610Salfredint 608184610Salfredlibusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex) 609184610Salfred{ 610184610Salfred int error; 611184610Salfred 612188622Sthompsa error = pdev->methods->kernel_driver_active(pdev, ifaceIndex); 613184610Salfred return (error); 614184610Salfred} 615184610Salfred 616184610Salfredint 617184610Salfredlibusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax) 618184610Salfred{ 619184610Salfred struct libusb20_transfer *xfer; 620184610Salfred uint32_t size; 621184610Salfred uint16_t x; 622184610Salfred int error; 623184610Salfred 624184610Salfred if (pdev->is_opened) { 625184610Salfred return (LIBUSB20_ERROR_BUSY); 626184610Salfred } 627184610Salfred if (nTransferMax >= 256) { 628184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 629184610Salfred } else if (nTransferMax != 0) { 630184610Salfred size = sizeof(pdev->pTransfer[0]) * nTransferMax; 631184610Salfred pdev->pTransfer = malloc(size); 632184610Salfred if (pdev->pTransfer == NULL) { 633184610Salfred return (LIBUSB20_ERROR_NO_MEM); 634184610Salfred } 635184610Salfred memset(pdev->pTransfer, 0, size); 636184610Salfred } 637184610Salfred /* initialise all transfers */ 638184610Salfred for (x = 0; x != nTransferMax; x++) { 639184610Salfred 640184610Salfred xfer = pdev->pTransfer + x; 641184610Salfred 642184610Salfred xfer->pdev = pdev; 643184610Salfred xfer->trIndex = x; 644184610Salfred xfer->callback = &dummy_callback; 645184610Salfred } 646184610Salfred 647185087Salfred /* set "nTransfer" early */ 648185087Salfred pdev->nTransfer = nTransferMax; 649185087Salfred 650188622Sthompsa error = pdev->beMethods->open_device(pdev, nTransferMax); 651184610Salfred 652184610Salfred if (error) { 653184610Salfred if (pdev->pTransfer != NULL) { 654184610Salfred free(pdev->pTransfer); 655184610Salfred pdev->pTransfer = NULL; 656184610Salfred } 657184610Salfred pdev->file = -1; 658184610Salfred pdev->file_ctrl = -1; 659184610Salfred pdev->nTransfer = 0; 660184610Salfred } else { 661184610Salfred pdev->is_opened = 1; 662184610Salfred } 663184610Salfred return (error); 664184610Salfred} 665184610Salfred 666184610Salfredint 667184610Salfredlibusb20_dev_reset(struct libusb20_device *pdev) 668184610Salfred{ 669184610Salfred int error; 670184610Salfred 671188622Sthompsa error = pdev->methods->reset_device(pdev); 672184610Salfred return (error); 673184610Salfred} 674184610Salfred 675184610Salfredint 676184610Salfredlibusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 677184610Salfred{ 678184610Salfred int error; 679184610Salfred 680188622Sthompsa error = pdev->methods->set_power_mode(pdev, power_mode); 681184610Salfred return (error); 682184610Salfred} 683184610Salfred 684184610Salfreduint8_t 685184610Salfredlibusb20_dev_get_power_mode(struct libusb20_device *pdev) 686184610Salfred{ 687184610Salfred int error; 688184610Salfred uint8_t power_mode; 689184610Salfred 690188622Sthompsa error = pdev->methods->get_power_mode(pdev, &power_mode); 691184610Salfred if (error) 692184610Salfred power_mode = LIBUSB20_POWER_ON; /* fake power mode */ 693184610Salfred return (power_mode); 694184610Salfred} 695184610Salfred 696184610Salfredint 697184610Salfredlibusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex) 698184610Salfred{ 699184610Salfred int error; 700184610Salfred 701188622Sthompsa error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex); 702184610Salfred return (error); 703184610Salfred} 704184610Salfred 705184610Salfredint 706184610Salfredlibusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex) 707184610Salfred{ 708184610Salfred int error; 709184610Salfred 710188622Sthompsa error = pdev->methods->set_config_index(pdev, configIndex); 711184610Salfred return (error); 712184610Salfred} 713184610Salfred 714184610Salfredint 715184610Salfredlibusb20_dev_request_sync(struct libusb20_device *pdev, 716184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data, 717184610Salfred uint16_t *pactlen, uint32_t timeout, uint8_t flags) 718184610Salfred{ 719184610Salfred int error; 720184610Salfred 721188622Sthompsa error = pdev->methods->do_request_sync(pdev, 722184610Salfred setup, data, pactlen, timeout, flags); 723184610Salfred return (error); 724184610Salfred} 725184610Salfred 726184610Salfredint 727184610Salfredlibusb20_dev_req_string_sync(struct libusb20_device *pdev, 728185087Salfred uint8_t str_index, uint16_t langid, void *ptr, uint16_t len) 729184610Salfred{ 730184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED req; 731184610Salfred int error; 732184610Salfred 733199055Sthompsa /* make sure memory is initialised */ 734199055Sthompsa memset(ptr, 0, len); 735199055Sthompsa 736184610Salfred if (len < 4) { 737184610Salfred /* invalid length */ 738184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 739184610Salfred } 740184610Salfred LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req); 741184610Salfred 742184610Salfred /* 743184610Salfred * We need to read the USB string in two steps else some USB 744184610Salfred * devices will complain. 745184610Salfred */ 746184610Salfred req.bmRequestType = 747184610Salfred LIBUSB20_REQUEST_TYPE_STANDARD | 748184610Salfred LIBUSB20_RECIPIENT_DEVICE | 749184610Salfred LIBUSB20_ENDPOINT_IN; 750184610Salfred req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR; 751185087Salfred req.wValue = (LIBUSB20_DT_STRING << 8) | str_index; 752184610Salfred req.wIndex = langid; 753184610Salfred req.wLength = 4; /* bytes */ 754184610Salfred 755184610Salfred error = libusb20_dev_request_sync(pdev, &req, 756184610Salfred ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 757184610Salfred if (error) { 758184610Salfred return (error); 759184610Salfred } 760184610Salfred req.wLength = *(uint8_t *)ptr; /* bytes */ 761184610Salfred if (req.wLength > len) { 762184610Salfred /* partial string read */ 763184610Salfred req.wLength = len; 764184610Salfred } 765184610Salfred error = libusb20_dev_request_sync(pdev, &req, 766184610Salfred ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 767184610Salfred 768184610Salfred if (error) { 769184610Salfred return (error); 770184610Salfred } 771184610Salfred if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) { 772184610Salfred return (LIBUSB20_ERROR_OTHER); 773184610Salfred } 774184610Salfred return (0); /* success */ 775184610Salfred} 776184610Salfred 777184610Salfredint 778184610Salfredlibusb20_dev_req_string_simple_sync(struct libusb20_device *pdev, 779185087Salfred uint8_t str_index, void *ptr, uint16_t len) 780184610Salfred{ 781184610Salfred char *buf; 782184610Salfred int error; 783184610Salfred uint16_t langid; 784184610Salfred uint16_t n; 785184610Salfred uint16_t i; 786184610Salfred uint16_t c; 787184610Salfred uint8_t temp[255]; 788184610Salfred uint8_t swap; 789184610Salfred 790184610Salfred /* the following code derives from the FreeBSD USB kernel */ 791184610Salfred 792184610Salfred if ((len < 1) || (ptr == NULL)) { 793184610Salfred /* too short buffer */ 794184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 795184610Salfred } 796184610Salfred error = libusb20_dev_req_string_sync(pdev, 797184610Salfred 0, 0, temp, sizeof(temp)); 798185087Salfred if (error < 0) { 799185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 800184610Salfred return (error); 801185087Salfred } 802184610Salfred langid = temp[2] | (temp[3] << 8); 803184610Salfred 804185087Salfred error = libusb20_dev_req_string_sync(pdev, str_index, 805184610Salfred langid, temp, sizeof(temp)); 806185087Salfred if (error < 0) { 807185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 808184610Salfred return (error); 809185087Salfred } 810184610Salfred if (temp[0] < 2) { 811184610Salfred /* string length is too short */ 812185087Salfred *(uint8_t *)ptr = 0; /* zero terminate */ 813184610Salfred return (LIBUSB20_ERROR_OTHER); 814184610Salfred } 815184610Salfred /* reserve one byte for terminating zero */ 816184610Salfred len--; 817184610Salfred 818184610Salfred /* find maximum length */ 819184610Salfred n = (temp[0] / 2) - 1; 820184610Salfred if (n > len) { 821184610Salfred n = len; 822184610Salfred } 823184610Salfred /* reset swap state */ 824184610Salfred swap = 3; 825184610Salfred 826184610Salfred /* setup output buffer pointer */ 827184610Salfred buf = ptr; 828184610Salfred 829184610Salfred /* convert and filter */ 830184610Salfred for (i = 0; (i != n); i++) { 831184610Salfred c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8); 832184610Salfred 833184610Salfred /* convert from Unicode, handle buggy strings */ 834184610Salfred if (((c & 0xff00) == 0) && (swap & 1)) { 835184610Salfred /* Little Endian, default */ 836184610Salfred *buf = c; 837184610Salfred swap = 1; 838184610Salfred } else if (((c & 0x00ff) == 0) && (swap & 2)) { 839184610Salfred /* Big Endian */ 840184610Salfred *buf = c >> 8; 841184610Salfred swap = 2; 842184610Salfred } else { 843185087Salfred /* skip invalid character */ 844185087Salfred continue; 845184610Salfred } 846184610Salfred /* 847184610Salfred * Filter by default - we don't allow greater and less than 848184610Salfred * signs because they might confuse the dmesg printouts! 849184610Salfred */ 850184610Salfred if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) { 851185087Salfred /* skip invalid character */ 852185087Salfred continue; 853184610Salfred } 854184610Salfred buf++; 855184610Salfred } 856184610Salfred *buf = 0; /* zero terminate string */ 857184610Salfred 858184610Salfred return (0); 859184610Salfred} 860184610Salfred 861184610Salfredstruct libusb20_config * 862184610Salfredlibusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex) 863184610Salfred{ 864184610Salfred struct libusb20_config *retval = NULL; 865184610Salfred uint8_t *ptr; 866184610Salfred uint16_t len; 867184610Salfred uint8_t do_close; 868184610Salfred int error; 869184610Salfred 870184610Salfred if (!pdev->is_opened) { 871184610Salfred error = libusb20_dev_open(pdev, 0); 872184610Salfred if (error) { 873184610Salfred return (NULL); 874184610Salfred } 875184610Salfred do_close = 1; 876184610Salfred } else { 877184610Salfred do_close = 0; 878184610Salfred } 879188622Sthompsa error = pdev->methods->get_config_desc_full(pdev, 880184610Salfred &ptr, &len, configIndex); 881184610Salfred 882184610Salfred if (error) { 883184610Salfred goto done; 884184610Salfred } 885184610Salfred /* parse new config descriptor */ 886184610Salfred retval = libusb20_parse_config_desc(ptr); 887184610Salfred 888184610Salfred /* free config descriptor */ 889184610Salfred free(ptr); 890184610Salfred 891184610Salfreddone: 892184610Salfred if (do_close) { 893184610Salfred error = libusb20_dev_close(pdev); 894184610Salfred } 895184610Salfred return (retval); 896184610Salfred} 897184610Salfred 898184610Salfredstruct libusb20_device * 899184610Salfredlibusb20_dev_alloc(void) 900184610Salfred{ 901184610Salfred struct libusb20_device *pdev; 902184610Salfred 903184610Salfred pdev = malloc(sizeof(*pdev)); 904184610Salfred if (pdev == NULL) { 905184610Salfred return (NULL); 906184610Salfred } 907184610Salfred memset(pdev, 0, sizeof(*pdev)); 908184610Salfred 909184610Salfred pdev->file = -1; 910184610Salfred pdev->file_ctrl = -1; 911184610Salfred pdev->methods = &libusb20_dummy_methods; 912184610Salfred return (pdev); 913184610Salfred} 914184610Salfred 915184610Salfreduint8_t 916184610Salfredlibusb20_dev_get_config_index(struct libusb20_device *pdev) 917184610Salfred{ 918184610Salfred int error; 919185087Salfred uint8_t cfg_index; 920184610Salfred uint8_t do_close; 921184610Salfred 922184610Salfred if (!pdev->is_opened) { 923184610Salfred error = libusb20_dev_open(pdev, 0); 924184610Salfred if (error == 0) { 925184610Salfred do_close = 1; 926184610Salfred } else { 927184610Salfred do_close = 0; 928184610Salfred } 929184610Salfred } else { 930184610Salfred do_close = 0; 931184610Salfred } 932184610Salfred 933188622Sthompsa error = pdev->methods->get_config_index(pdev, &cfg_index); 934184610Salfred if (error) { 935185087Salfred cfg_index = 0 - 1; /* current config index */ 936184610Salfred } 937184610Salfred if (do_close) { 938184610Salfred if (libusb20_dev_close(pdev)) { 939184610Salfred /* ignore */ 940184610Salfred } 941184610Salfred } 942185087Salfred return (cfg_index); 943184610Salfred} 944184610Salfred 945184610Salfreduint8_t 946184610Salfredlibusb20_dev_get_mode(struct libusb20_device *pdev) 947184610Salfred{ 948184610Salfred return (pdev->usb_mode); 949184610Salfred} 950184610Salfred 951184610Salfreduint8_t 952184610Salfredlibusb20_dev_get_speed(struct libusb20_device *pdev) 953184610Salfred{ 954184610Salfred return (pdev->usb_speed); 955184610Salfred} 956184610Salfred 957184610Salfred/* if this function returns an error, the device is gone */ 958184610Salfredint 959184610Salfredlibusb20_dev_process(struct libusb20_device *pdev) 960184610Salfred{ 961184610Salfred int error; 962184610Salfred 963188622Sthompsa error = pdev->methods->process(pdev); 964184610Salfred return (error); 965184610Salfred} 966184610Salfred 967184610Salfredvoid 968184610Salfredlibusb20_dev_wait_process(struct libusb20_device *pdev, int timeout) 969184610Salfred{ 970185087Salfred struct pollfd pfd[1]; 971184610Salfred 972184610Salfred if (!pdev->is_opened) { 973184610Salfred return; 974184610Salfred } 975184610Salfred pfd[0].fd = pdev->file; 976184610Salfred pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 977184610Salfred pfd[0].revents = 0; 978184610Salfred 979185087Salfred if (poll(pfd, 1, timeout)) { 980184610Salfred /* ignore any error */ 981184610Salfred } 982184610Salfred return; 983184610Salfred} 984184610Salfred 985184610Salfredvoid 986184610Salfredlibusb20_dev_free(struct libusb20_device *pdev) 987184610Salfred{ 988184610Salfred if (pdev == NULL) { 989184610Salfred /* be NULL safe */ 990184610Salfred return; 991184610Salfred } 992184610Salfred if (pdev->is_opened) { 993184610Salfred if (libusb20_dev_close(pdev)) { 994184610Salfred /* ignore any errors */ 995184610Salfred } 996184610Salfred } 997184610Salfred free(pdev); 998184610Salfred return; 999184610Salfred} 1000184610Salfred 1001188622Sthompsaint 1002188622Sthompsalibusb20_dev_get_info(struct libusb20_device *pdev, 1003192984Sthompsa struct usb_device_info *pinfo) 1004188622Sthompsa{ 1005188622Sthompsa if (pinfo == NULL) 1006188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 1007188622Sthompsa 1008188622Sthompsa return (pdev->beMethods->dev_get_info(pdev, pinfo)); 1009188622Sthompsa} 1010188622Sthompsa 1011184610Salfredconst char * 1012184610Salfredlibusb20_dev_get_backend_name(struct libusb20_device *pdev) 1013184610Salfred{ 1014188622Sthompsa return (pdev->beMethods->get_backend_name()); 1015184610Salfred} 1016184610Salfred 1017184610Salfredconst char * 1018184610Salfredlibusb20_dev_get_desc(struct libusb20_device *pdev) 1019184610Salfred{ 1020184610Salfred return (pdev->usb_desc); 1021184610Salfred} 1022184610Salfred 1023184610Salfredvoid 1024184610Salfredlibusb20_dev_set_debug(struct libusb20_device *pdev, int debug) 1025184610Salfred{ 1026184610Salfred pdev->debug = debug; 1027184610Salfred return; 1028184610Salfred} 1029184610Salfred 1030184610Salfredint 1031184610Salfredlibusb20_dev_get_debug(struct libusb20_device *pdev) 1032184610Salfred{ 1033184610Salfred return (pdev->debug); 1034184610Salfred} 1035184610Salfred 1036184610Salfreduint8_t 1037184610Salfredlibusb20_dev_get_address(struct libusb20_device *pdev) 1038184610Salfred{ 1039184610Salfred return (pdev->device_address); 1040184610Salfred} 1041184610Salfred 1042184610Salfreduint8_t 1043184610Salfredlibusb20_dev_get_bus_number(struct libusb20_device *pdev) 1044184610Salfred{ 1045184610Salfred return (pdev->bus_number); 1046184610Salfred} 1047184610Salfred 1048184610Salfredint 1049188622Sthompsalibusb20_dev_get_iface_desc(struct libusb20_device *pdev, 1050188622Sthompsa uint8_t iface_index, char *buf, uint8_t len) 1051188622Sthompsa{ 1052188622Sthompsa if ((buf == NULL) || (len == 0)) 1053188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 1054188622Sthompsa 1055188622Sthompsa return (pdev->beMethods->dev_get_iface_desc( 1056188622Sthompsa pdev, iface_index, buf, len)); 1057188622Sthompsa} 1058188622Sthompsa 1059184610Salfred/* USB backend operations */ 1060184610Salfred 1061184610Salfredint 1062184610Salfredlibusb20_be_get_dev_quirk(struct libusb20_backend *pbe, 1063185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 1064184610Salfred{ 1065188622Sthompsa return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq)); 1066184610Salfred} 1067184610Salfred 1068184610Salfredint 1069184610Salfredlibusb20_be_get_quirk_name(struct libusb20_backend *pbe, 1070185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 1071184610Salfred{ 1072188622Sthompsa return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq)); 1073184610Salfred} 1074184610Salfred 1075184610Salfredint 1076184610Salfredlibusb20_be_add_dev_quirk(struct libusb20_backend *pbe, 1077184610Salfred struct libusb20_quirk *pq) 1078184610Salfred{ 1079188622Sthompsa return (pbe->methods->root_add_dev_quirk(pbe, pq)); 1080184610Salfred} 1081184610Salfred 1082184610Salfredint 1083184610Salfredlibusb20_be_remove_dev_quirk(struct libusb20_backend *pbe, 1084184610Salfred struct libusb20_quirk *pq) 1085184610Salfred{ 1086188622Sthompsa return (pbe->methods->root_remove_dev_quirk(pbe, pq)); 1087184610Salfred} 1088184610Salfred 1089184610Salfredint 1090188987Sthompsalibusb20_be_set_template(struct libusb20_backend *pbe, int temp) 1091188987Sthompsa{ 1092188987Sthompsa return (pbe->methods->root_set_template(pbe, temp)); 1093188987Sthompsa} 1094188987Sthompsa 1095188987Sthompsaint 1096188987Sthompsalibusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp) 1097188987Sthompsa{ 1098188987Sthompsa int temp; 1099188987Sthompsa 1100188987Sthompsa if (ptemp == NULL) 1101188987Sthompsa ptemp = &temp; 1102188987Sthompsa 1103188987Sthompsa return (pbe->methods->root_get_template(pbe, ptemp)); 1104188987Sthompsa} 1105188987Sthompsa 1106184610Salfredstruct libusb20_device * 1107184610Salfredlibusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1108184610Salfred{ 1109184610Salfred if (pbe == NULL) { 1110184610Salfred pdev = NULL; 1111184610Salfred } else if (pdev == NULL) { 1112184610Salfred pdev = TAILQ_FIRST(&(pbe->usb_devs)); 1113184610Salfred } else { 1114184610Salfred pdev = TAILQ_NEXT(pdev, dev_entry); 1115184610Salfred } 1116184610Salfred return (pdev); 1117184610Salfred} 1118184610Salfred 1119184610Salfredstruct libusb20_backend * 1120184610Salfredlibusb20_be_alloc(const struct libusb20_backend_methods *methods) 1121184610Salfred{ 1122184610Salfred struct libusb20_backend *pbe; 1123184610Salfred 1124184610Salfred pbe = malloc(sizeof(*pbe)); 1125184610Salfred if (pbe == NULL) { 1126184610Salfred return (NULL); 1127184610Salfred } 1128184610Salfred memset(pbe, 0, sizeof(*pbe)); 1129184610Salfred 1130184610Salfred TAILQ_INIT(&(pbe->usb_devs)); 1131184610Salfred 1132184610Salfred pbe->methods = methods; /* set backend methods */ 1133184610Salfred 1134184610Salfred /* do the initial device scan */ 1135184610Salfred if (pbe->methods->init_backend) { 1136188622Sthompsa pbe->methods->init_backend(pbe); 1137184610Salfred } 1138184610Salfred return (pbe); 1139184610Salfred} 1140184610Salfred 1141184610Salfredstruct libusb20_backend * 1142184610Salfredlibusb20_be_alloc_linux(void) 1143184610Salfred{ 1144184610Salfred struct libusb20_backend *pbe; 1145184610Salfred 1146184610Salfred#ifdef __linux__ 1147184610Salfred pbe = libusb20_be_alloc(&libusb20_linux_backend); 1148184610Salfred#else 1149184610Salfred pbe = NULL; 1150184610Salfred#endif 1151184610Salfred return (pbe); 1152184610Salfred} 1153184610Salfred 1154184610Salfredstruct libusb20_backend * 1155184610Salfredlibusb20_be_alloc_ugen20(void) 1156184610Salfred{ 1157184610Salfred struct libusb20_backend *pbe; 1158184610Salfred 1159184610Salfred#ifdef __FreeBSD__ 1160184610Salfred pbe = libusb20_be_alloc(&libusb20_ugen20_backend); 1161184610Salfred#else 1162184610Salfred pbe = NULL; 1163184610Salfred#endif 1164184610Salfred return (pbe); 1165184610Salfred} 1166184610Salfred 1167184610Salfredstruct libusb20_backend * 1168184610Salfredlibusb20_be_alloc_default(void) 1169184610Salfred{ 1170184610Salfred struct libusb20_backend *pbe; 1171184610Salfred 1172184610Salfred pbe = libusb20_be_alloc_linux(); 1173184610Salfred if (pbe) { 1174184610Salfred return (pbe); 1175184610Salfred } 1176184610Salfred pbe = libusb20_be_alloc_ugen20(); 1177184610Salfred if (pbe) { 1178184610Salfred return (pbe); 1179184610Salfred } 1180184610Salfred return (NULL); /* no backend found */ 1181184610Salfred} 1182184610Salfred 1183184610Salfredvoid 1184184610Salfredlibusb20_be_free(struct libusb20_backend *pbe) 1185184610Salfred{ 1186184610Salfred struct libusb20_device *pdev; 1187184610Salfred 1188184610Salfred if (pbe == NULL) { 1189184610Salfred /* be NULL safe */ 1190184610Salfred return; 1191184610Salfred } 1192184610Salfred while ((pdev = libusb20_be_device_foreach(pbe, NULL))) { 1193184610Salfred libusb20_be_dequeue_device(pbe, pdev); 1194184610Salfred libusb20_dev_free(pdev); 1195184610Salfred } 1196184610Salfred if (pbe->methods->exit_backend) { 1197188622Sthompsa pbe->methods->exit_backend(pbe); 1198184610Salfred } 1199199055Sthompsa /* free backend */ 1200199055Sthompsa free(pbe); 1201184610Salfred} 1202184610Salfred 1203184610Salfredvoid 1204184610Salfredlibusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1205184610Salfred{ 1206184610Salfred pdev->beMethods = pbe->methods; /* copy backend methods */ 1207184610Salfred TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry); 1208184610Salfred} 1209184610Salfred 1210184610Salfredvoid 1211184610Salfredlibusb20_be_dequeue_device(struct libusb20_backend *pbe, 1212184610Salfred struct libusb20_device *pdev) 1213184610Salfred{ 1214184610Salfred TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry); 1215184610Salfred} 1216