usb_msctest.c revision 194677
1254721Semaste/* $FreeBSD: head/sys/dev/usb/usb_msctest.c 194677 2009-06-23 02:19:59Z thompsa $ */ 2254721Semaste/*- 3254721Semaste * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4254721Semaste * 5254721Semaste * Redistribution and use in source and binary forms, with or without 6254721Semaste * modification, are permitted provided that the following conditions 7254721Semaste * are met: 8254721Semaste * 1. Redistributions of source code must retain the above copyright 9254721Semaste * notice, this list of conditions and the following disclaimer. 10254721Semaste * 2. Redistributions in binary form must reproduce the above copyright 11254721Semaste * notice, this list of conditions and the following disclaimer in the 12254721Semaste * documentation and/or other materials provided with the distribution. 13254721Semaste * 14254721Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15254721Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16254721Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17254721Semaste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18254721Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19254721Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20254721Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21254721Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22254721Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23254721Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24254721Semaste * SUCH DAMAGE. 25254721Semaste */ 26254721Semaste 27254721Semaste/* 28254721Semaste * The following file contains code that will detect USB autoinstall 29254721Semaste * disks. 30254721Semaste * 31254721Semaste * TODO: Potentially we could add code to automatically detect USB 32254721Semaste * mass storage quirks for not supported SCSI commands! 33254721Semaste */ 34254721Semaste 35254721Semaste#include <sys/stdint.h> 36254721Semaste#include <sys/stddef.h> 37254721Semaste#include <sys/param.h> 38254721Semaste#include <sys/queue.h> 39254721Semaste#include <sys/types.h> 40254721Semaste#include <sys/systm.h> 41254721Semaste#include <sys/kernel.h> 42254721Semaste#include <sys/bus.h> 43254721Semaste#include <sys/linker_set.h> 44254721Semaste#include <sys/module.h> 45254721Semaste#include <sys/lock.h> 46254721Semaste#include <sys/mutex.h> 47254721Semaste#include <sys/condvar.h> 48254721Semaste#include <sys/sysctl.h> 49254721Semaste#include <sys/sx.h> 50254721Semaste#include <sys/unistd.h> 51254721Semaste#include <sys/callout.h> 52254721Semaste#include <sys/malloc.h> 53254721Semaste#include <sys/priv.h> 54254721Semaste 55254721Semaste#include <dev/usb/usb.h> 56254721Semaste#include <dev/usb/usbdi.h> 57254721Semaste#include <dev/usb/usbdi_util.h> 58254721Semaste 59254721Semaste#define USB_DEBUG_VAR usb_debug 60254721Semaste 61254721Semaste#include <dev/usb/usb_busdma.h> 62254721Semaste#include <dev/usb/usb_process.h> 63254721Semaste#include <dev/usb/usb_transfer.h> 64254721Semaste#include <dev/usb/usb_msctest.h> 65254721Semaste#include <dev/usb/usb_debug.h> 66254721Semaste#include <dev/usb/usb_busdma.h> 67254721Semaste#include <dev/usb/usb_device.h> 68254721Semaste#include <dev/usb/usb_request.h> 69254721Semaste#include <dev/usb/usb_util.h> 70254721Semaste 71254721Semaste#include <dev/usb/usb.h> 72254721Semaste 73254721Semasteenum { 74254721Semaste ST_COMMAND, 75254721Semaste ST_DATA_RD, 76254721Semaste ST_DATA_RD_CS, 77254721Semaste ST_DATA_WR, 78254721Semaste ST_DATA_WR_CS, 79254721Semaste ST_STATUS, 80254721Semaste ST_MAX, 81254721Semaste}; 82254721Semaste 83254721Semasteenum { 84254721Semaste DIR_IN, 85254721Semaste DIR_OUT, 86254721Semaste DIR_NONE, 87254721Semaste}; 88254721Semaste 89254721Semaste#define BULK_SIZE 64 /* dummy */ 90254721Semaste 91254721Semaste/* Command Block Wrapper */ 92254721Semastestruct bbb_cbw { 93254721Semaste uDWord dCBWSignature; 94254721Semaste#define CBWSIGNATURE 0x43425355 95254721Semaste uDWord dCBWTag; 96254721Semaste uDWord dCBWDataTransferLength; 97254721Semaste uByte bCBWFlags; 98254721Semaste#define CBWFLAGS_OUT 0x00 99254721Semaste#define CBWFLAGS_IN 0x80 100254721Semaste uByte bCBWLUN; 101254721Semaste uByte bCDBLength; 102254721Semaste#define CBWCDBLENGTH 16 103254721Semaste uByte CBWCDB[CBWCDBLENGTH]; 104254721Semaste} __packed; 105254721Semaste 106254721Semaste/* Command Status Wrapper */ 107254721Semastestruct bbb_csw { 108254721Semaste uDWord dCSWSignature; 109254721Semaste#define CSWSIGNATURE 0x53425355 110254721Semaste uDWord dCSWTag; 111254721Semaste uDWord dCSWDataResidue; 112254721Semaste uByte bCSWStatus; 113254721Semaste#define CSWSTATUS_GOOD 0x0 114254721Semaste#define CSWSTATUS_FAILED 0x1 115254721Semaste#define CSWSTATUS_PHASE 0x2 116254721Semaste} __packed; 117254721Semaste 118254721Semastestruct bbb_transfer { 119254721Semaste struct mtx mtx; 120254721Semaste struct cv cv; 121254721Semaste struct bbb_cbw cbw; 122254721Semaste struct bbb_csw csw; 123254721Semaste 124254721Semaste struct usb_xfer *xfer[ST_MAX]; 125254721Semaste 126254721Semaste uint8_t *data_ptr; 127254721Semaste 128254721Semaste usb_size_t data_len; /* bytes */ 129254721Semaste usb_size_t data_rem; /* bytes */ 130254721Semaste usb_timeout_t data_timeout; /* ms */ 131254721Semaste usb_frlength_t actlen; /* bytes */ 132254721Semaste 133254721Semaste uint8_t cmd_len; /* bytes */ 134254721Semaste uint8_t dir; 135254721Semaste uint8_t lun; 136254721Semaste uint8_t state; 137254721Semaste uint8_t error; 138254721Semaste uint8_t status_try; 139254721Semaste 140254721Semaste uint8_t buffer[256]; 141254721Semaste}; 142254721Semaste 143254721Semastestatic usb_callback_t bbb_command_callback; 144254721Semastestatic usb_callback_t bbb_data_read_callback; 145254721Semastestatic usb_callback_t bbb_data_rd_cs_callback; 146254721Semastestatic usb_callback_t bbb_data_write_callback; 147254721Semastestatic usb_callback_t bbb_data_wr_cs_callback; 148254721Semastestatic usb_callback_t bbb_status_callback; 149254721Semaste 150254721Semastestatic const struct usb_config bbb_config[ST_MAX] = { 151254721Semaste 152254721Semaste [ST_COMMAND] = { 153254721Semaste .type = UE_BULK, 154254721Semaste .endpoint = UE_ADDR_ANY, 155254721Semaste .direction = UE_DIR_OUT, 156254721Semaste .bufsize = sizeof(struct bbb_cbw), 157254721Semaste .callback = &bbb_command_callback, 158254721Semaste .timeout = 4 * USB_MS_HZ, /* 4 seconds */ 159254721Semaste }, 160254721Semaste 161254721Semaste [ST_DATA_RD] = { 162254721Semaste .type = UE_BULK, 163254721Semaste .endpoint = UE_ADDR_ANY, 164254721Semaste .direction = UE_DIR_IN, 165263363Semaste .bufsize = BULK_SIZE, 166254721Semaste .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,}, 167254721Semaste .callback = &bbb_data_read_callback, 168254721Semaste .timeout = 4 * USB_MS_HZ, /* 4 seconds */ 169254721Semaste }, 170254721Semaste 171254721Semaste [ST_DATA_RD_CS] = { 172254721Semaste .type = UE_CONTROL, 173254721Semaste .endpoint = 0x00, /* Control pipe */ 174254721Semaste .direction = UE_DIR_ANY, 175254721Semaste .bufsize = sizeof(struct usb_device_request), 176254721Semaste .callback = &bbb_data_rd_cs_callback, 177254721Semaste .timeout = 1 * USB_MS_HZ, /* 1 second */ 178254721Semaste }, 179254721Semaste 180254721Semaste [ST_DATA_WR] = { 181254721Semaste .type = UE_BULK, 182254721Semaste .endpoint = UE_ADDR_ANY, 183254721Semaste .direction = UE_DIR_OUT, 184254721Semaste .bufsize = BULK_SIZE, 185254721Semaste .flags = {.proxy_buffer = 1,}, 186263363Semaste .callback = &bbb_data_write_callback, 187254721Semaste .timeout = 4 * USB_MS_HZ, /* 4 seconds */ 188263363Semaste }, 189254721Semaste 190254721Semaste [ST_DATA_WR_CS] = { 191254721Semaste .type = UE_CONTROL, 192254721Semaste .endpoint = 0x00, /* Control pipe */ 193254721Semaste .direction = UE_DIR_ANY, 194254721Semaste .bufsize = sizeof(struct usb_device_request), 195254721Semaste .callback = &bbb_data_wr_cs_callback, 196254721Semaste .timeout = 1 * USB_MS_HZ, /* 1 second */ 197254721Semaste }, 198254721Semaste 199254721Semaste [ST_STATUS] = { 200254721Semaste .type = UE_BULK, 201254721Semaste .endpoint = UE_ADDR_ANY, 202254721Semaste .direction = UE_DIR_IN, 203254721Semaste .bufsize = sizeof(struct bbb_csw), 204254721Semaste .flags = {.short_xfer_ok = 1,}, 205254721Semaste .callback = &bbb_status_callback, 206254721Semaste .timeout = 1 * USB_MS_HZ, /* 1 second */ 207254721Semaste }, 208254721Semaste}; 209254721Semaste 210254721Semastestatic void 211254721Semastebbb_done(struct bbb_transfer *sc, uint8_t error) 212254721Semaste{ 213254721Semaste struct usb_xfer *xfer; 214254721Semaste 215254721Semaste xfer = sc->xfer[sc->state]; 216254721Semaste 217254721Semaste /* verify the error code */ 218254721Semaste 219254721Semaste if (error) { 220254721Semaste switch (USB_GET_STATE(xfer)) { 221254721Semaste case USB_ST_SETUP: 222254721Semaste case USB_ST_TRANSFERRED: 223254721Semaste error = 1; 224254721Semaste break; 225254721Semaste default: 226254721Semaste error = 2; 227254721Semaste break; 228254721Semaste } 229254721Semaste } 230254721Semaste sc->error = error; 231254721Semaste sc->state = ST_COMMAND; 232254721Semaste sc->status_try = 1; 233254721Semaste cv_signal(&sc->cv); 234254721Semaste} 235254721Semaste 236254721Semastestatic void 237254721Semastebbb_transfer_start(struct bbb_transfer *sc, uint8_t xfer_index) 238254721Semaste{ 239254721Semaste sc->state = xfer_index; 240254721Semaste usbd_transfer_start(sc->xfer[xfer_index]); 241254721Semaste} 242254721Semaste 243254721Semastestatic void 244254721Semastebbb_data_clear_stall_callback(struct usb_xfer *xfer, 245254721Semaste uint8_t next_xfer, uint8_t stall_xfer) 246254721Semaste{ 247254721Semaste struct bbb_transfer *sc = usbd_xfer_softc(xfer); 248254721Semaste 249254721Semaste if (usbd_clear_stall_callback(xfer, sc->xfer[stall_xfer])) { 250254721Semaste switch (USB_GET_STATE(xfer)) { 251254721Semaste case USB_ST_SETUP: 252254721Semaste case USB_ST_TRANSFERRED: 253254721Semaste bbb_transfer_start(sc, next_xfer); 254254721Semaste break; 255254721Semaste default: 256254721Semaste bbb_done(sc, 1); 257254721Semaste break; 258254721Semaste } 259254721Semaste } 260254721Semaste} 261254721Semaste 262254721Semastestatic void 263254721Semastebbb_command_callback(struct usb_xfer *xfer, usb_error_t error) 264254721Semaste{ 265254721Semaste struct bbb_transfer *sc = usbd_xfer_softc(xfer); 266254721Semaste uint32_t tag; 267254721Semaste 268254721Semaste switch (USB_GET_STATE(xfer)) { 269254721Semaste case USB_ST_TRANSFERRED: 270254721Semaste bbb_transfer_start 271254721Semaste (sc, ((sc->dir == DIR_IN) ? ST_DATA_RD : 272254721Semaste (sc->dir == DIR_OUT) ? ST_DATA_WR : 273254721Semaste ST_STATUS)); 274254721Semaste break; 275 276 case USB_ST_SETUP: 277 sc->status_try = 0; 278 tag = UGETDW(sc->cbw.dCBWTag) + 1; 279 USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE); 280 USETDW(sc->cbw.dCBWTag, tag); 281 USETDW(sc->cbw.dCBWDataTransferLength, (uint32_t)sc->data_len); 282 sc->cbw.bCBWFlags = ((sc->dir == DIR_IN) ? CBWFLAGS_IN : CBWFLAGS_OUT); 283 sc->cbw.bCBWLUN = sc->lun; 284 sc->cbw.bCDBLength = sc->cmd_len; 285 if (sc->cbw.bCDBLength > sizeof(sc->cbw.CBWCDB)) { 286 sc->cbw.bCDBLength = sizeof(sc->cbw.CBWCDB); 287 DPRINTFN(0, "Truncating long command!\n"); 288 } 289 usbd_xfer_set_frame_data(xfer, 0, &sc->cbw, sizeof(sc->cbw)); 290 usbd_transfer_submit(xfer); 291 break; 292 293 default: /* Error */ 294 bbb_done(sc, 1); 295 break; 296 } 297} 298 299static void 300bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error) 301{ 302 struct bbb_transfer *sc = usbd_xfer_softc(xfer); 303 usb_frlength_t max_bulk = usbd_xfer_max_len(xfer); 304 int actlen, sumlen; 305 306 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 307 308 switch (USB_GET_STATE(xfer)) { 309 case USB_ST_TRANSFERRED: 310 sc->data_rem -= actlen; 311 sc->data_ptr += actlen; 312 sc->actlen += actlen; 313 314 if (actlen < sumlen) { 315 /* short transfer */ 316 sc->data_rem = 0; 317 } 318 case USB_ST_SETUP: 319 DPRINTF("max_bulk=%d, data_rem=%d\n", 320 max_bulk, sc->data_rem); 321 322 if (sc->data_rem == 0) { 323 bbb_transfer_start(sc, ST_STATUS); 324 break; 325 } 326 if (max_bulk > sc->data_rem) { 327 max_bulk = sc->data_rem; 328 } 329 usbd_xfer_set_timeout(xfer, sc->data_timeout); 330 usbd_xfer_set_frame_data(xfer, 0, sc->data_ptr, max_bulk); 331 usbd_transfer_submit(xfer); 332 break; 333 334 default: /* Error */ 335 if (error == USB_ERR_CANCELLED) { 336 bbb_done(sc, 1); 337 } else { 338 bbb_transfer_start(sc, ST_DATA_RD_CS); 339 } 340 break; 341 } 342} 343 344static void 345bbb_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error) 346{ 347 bbb_data_clear_stall_callback(xfer, ST_STATUS, 348 ST_DATA_RD); 349} 350 351static void 352bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error) 353{ 354 struct bbb_transfer *sc = usbd_xfer_softc(xfer); 355 usb_frlength_t max_bulk = usbd_xfer_max_len(xfer); 356 int actlen, sumlen; 357 358 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 359 360 switch (USB_GET_STATE(xfer)) { 361 case USB_ST_TRANSFERRED: 362 sc->data_rem -= actlen; 363 sc->data_ptr += actlen; 364 sc->actlen += actlen; 365 366 if (actlen < sumlen) { 367 /* short transfer */ 368 sc->data_rem = 0; 369 } 370 case USB_ST_SETUP: 371 DPRINTF("max_bulk=%d, data_rem=%d\n", 372 max_bulk, sc->data_rem); 373 374 if (sc->data_rem == 0) { 375 bbb_transfer_start(sc, ST_STATUS); 376 return; 377 } 378 if (max_bulk > sc->data_rem) { 379 max_bulk = sc->data_rem; 380 } 381 usbd_xfer_set_timeout(xfer, sc->data_timeout); 382 usbd_xfer_set_frame_data(xfer, 0, sc->data_ptr, max_bulk); 383 usbd_transfer_submit(xfer); 384 return; 385 386 default: /* Error */ 387 if (error == USB_ERR_CANCELLED) { 388 bbb_done(sc, 1); 389 } else { 390 bbb_transfer_start(sc, ST_DATA_WR_CS); 391 } 392 return; 393 394 } 395} 396 397static void 398bbb_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error) 399{ 400 bbb_data_clear_stall_callback(xfer, ST_STATUS, 401 ST_DATA_WR); 402} 403 404static void 405bbb_status_callback(struct usb_xfer *xfer, usb_error_t error) 406{ 407 struct bbb_transfer *sc = usbd_xfer_softc(xfer); 408 int actlen, sumlen; 409 410 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 411 412 switch (USB_GET_STATE(xfer)) { 413 case USB_ST_TRANSFERRED: 414 415 /* very simple status check */ 416 417 if (actlen < sizeof(sc->csw)) { 418 bbb_done(sc, 1);/* error */ 419 } else if (sc->csw.bCSWStatus == CSWSTATUS_GOOD) { 420 bbb_done(sc, 0);/* success */ 421 } else { 422 bbb_done(sc, 1);/* error */ 423 } 424 break; 425 426 case USB_ST_SETUP: 427 usbd_xfer_set_frame_data(xfer, 0, &sc->csw, sizeof(sc->csw)); 428 usbd_transfer_submit(xfer); 429 break; 430 431 default: 432 DPRINTFN(0, "Failed to read CSW: %s, try %d\n", 433 usbd_errstr(error), sc->status_try); 434 435 if (error == USB_ERR_CANCELLED || sc->status_try) { 436 bbb_done(sc, 1); 437 } else { 438 sc->status_try = 1; 439 bbb_transfer_start(sc, ST_DATA_RD_CS); 440 } 441 break; 442 } 443} 444 445/*------------------------------------------------------------------------* 446 * bbb_command_start - execute a SCSI command synchronously 447 * 448 * Return values 449 * 0: Success 450 * Else: Failure 451 *------------------------------------------------------------------------*/ 452static uint8_t 453bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun, 454 void *data_ptr, usb_size_t data_len, uint8_t cmd_len, 455 usb_timeout_t data_timeout) 456{ 457 sc->lun = lun; 458 sc->dir = data_len ? dir : DIR_NONE; 459 sc->data_ptr = data_ptr; 460 sc->data_len = data_len; 461 sc->data_rem = data_len; 462 sc->data_timeout = (data_timeout + USB_MS_HZ); 463 sc->actlen = 0; 464 sc->cmd_len = cmd_len; 465 466 usbd_transfer_start(sc->xfer[sc->state]); 467 468 while (usbd_transfer_pending(sc->xfer[sc->state])) { 469 cv_wait(&sc->cv, &sc->mtx); 470 } 471 return (sc->error); 472} 473 474/*------------------------------------------------------------------------* 475 * usb_test_autoinstall 476 * 477 * Return values: 478 * 0: This interface is an auto install disk (CD-ROM) 479 * Else: Not an auto install disk. 480 *------------------------------------------------------------------------*/ 481usb_error_t 482usb_test_autoinstall(struct usb_device *udev, uint8_t iface_index, 483 uint8_t do_eject) 484{ 485 struct usb_interface *iface; 486 struct usb_interface_descriptor *id; 487 usb_error_t err; 488 uint8_t timeout; 489 uint8_t sid_type; 490 struct bbb_transfer *sc; 491 492 if (udev == NULL) { 493 return (USB_ERR_INVAL); 494 } 495 iface = usbd_get_iface(udev, iface_index); 496 if (iface == NULL) { 497 return (USB_ERR_INVAL); 498 } 499 id = iface->idesc; 500 if (id == NULL) { 501 return (USB_ERR_INVAL); 502 } 503 if (id->bInterfaceClass != UICLASS_MASS) { 504 return (USB_ERR_INVAL); 505 } 506 switch (id->bInterfaceSubClass) { 507 case UISUBCLASS_SCSI: 508 case UISUBCLASS_UFI: 509 break; 510 default: 511 return (USB_ERR_INVAL); 512 } 513 514 switch (id->bInterfaceProtocol) { 515 case UIPROTO_MASS_BBB_OLD: 516 case UIPROTO_MASS_BBB: 517 break; 518 default: 519 return (USB_ERR_INVAL); 520 } 521 522 sc = malloc(sizeof(*sc), M_USB, M_WAITOK | M_ZERO); 523 if (sc == NULL) { 524 return (USB_ERR_NOMEM); 525 } 526 mtx_init(&sc->mtx, "USB autoinstall", NULL, MTX_DEF); 527 cv_init(&sc->cv, "WBBB"); 528 529 err = usbd_transfer_setup(udev, 530 &iface_index, sc->xfer, bbb_config, 531 ST_MAX, sc, &sc->mtx); 532 533 if (err) { 534 goto done; 535 } 536 mtx_lock(&sc->mtx); 537 538 timeout = 4; /* tries */ 539 540repeat_inquiry: 541 542 sc->cbw.CBWCDB[0] = 0x12; /* INQUIRY */ 543 sc->cbw.CBWCDB[1] = 0; 544 sc->cbw.CBWCDB[2] = 0; 545 sc->cbw.CBWCDB[3] = 0; 546 sc->cbw.CBWCDB[4] = 0x24; /* length */ 547 sc->cbw.CBWCDB[5] = 0; 548 err = bbb_command_start(sc, DIR_IN, 0, 549 sc->buffer, 0x24, 6, USB_MS_HZ); 550 551 if ((sc->actlen != 0) && (err == 0)) { 552 sid_type = sc->buffer[0] & 0x1F; 553 if (sid_type == 0x05) { 554 /* CD-ROM */ 555 if (do_eject) { 556 /* 0: opcode: SCSI START/STOP */ 557 sc->cbw.CBWCDB[0] = 0x1b; 558 /* 1: byte2: Not immediate */ 559 sc->cbw.CBWCDB[1] = 0x00; 560 /* 2..3: reserved */ 561 sc->cbw.CBWCDB[2] = 0x00; 562 sc->cbw.CBWCDB[3] = 0x00; 563 /* 4: Load/Eject command */ 564 sc->cbw.CBWCDB[4] = 0x02; 565 /* 5: control */ 566 sc->cbw.CBWCDB[5] = 0x00; 567 err = bbb_command_start(sc, DIR_OUT, 0, 568 NULL, 0, 6, USB_MS_HZ); 569 570 DPRINTFN(0, "Eject CD command " 571 "status: %s\n", usbd_errstr(err)); 572 } 573 err = 0; 574 goto done; 575 } 576 } else if ((err != 2) && --timeout) { 577 usb_pause_mtx(&sc->mtx, hz); 578 goto repeat_inquiry; 579 } 580 err = USB_ERR_INVAL; 581 goto done; 582 583done: 584 mtx_unlock(&sc->mtx); 585 usbd_transfer_unsetup(sc->xfer, ST_MAX); 586 mtx_destroy(&sc->mtx); 587 cv_destroy(&sc->cv); 588 free(sc, M_USB); 589 return (err); 590} 591