1 /* $NetBSD: utoppy.c,v 1.27 2016/08/20 19:44:46 jdolecek Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Steve C. Woodford. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: utoppy.c,v 1.27 2016/08/20 19:44:46 jdolecek Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/proc.h> 38 #include <sys/kernel.h> 39 #include <sys/fcntl.h> 40 #include <sys/device.h> 41 #include <sys/ioctl.h> 42 #include <sys/uio.h> 43 #include <sys/conf.h> 44 #include <sys/vnode.h> 45 #include <sys/bus.h> 46 47 #include <lib/libkern/crc16.h> 48 49 #include <dev/usb/usb.h> 50 #include <dev/usb/usbdi.h> 51 #include <dev/usb/usbdivar.h> 52 #include <dev/usb/usbdi_util.h> 53 #include <dev/usb/usbdevs.h> 54 #include <dev/usb/usb_quirks.h> 55 #include <dev/usb/utoppy.h> 56 57 #undef UTOPPY_DEBUG 58 #ifdef UTOPPY_DEBUG 59 #define UTOPPY_DBG_OPEN 0x0001 60 #define UTOPPY_DBG_CLOSE 0x0002 61 #define UTOPPY_DBG_READ 0x0004 62 #define UTOPPY_DBG_WRITE 0x0008 63 #define UTOPPY_DBG_IOCTL 0x0010 64 #define UTOPPY_DBG_SEND_PACKET 0x0020 65 #define UTOPPY_DBG_RECV_PACKET 0x0040 66 #define UTOPPY_DBG_ADDPATH 0x0080 67 #define UTOPPY_DBG_READDIR 0x0100 68 #define UTOPPY_DBG_DUMP 0x0200 69 #define DPRINTF(l, m) \ 70 do { \ 71 if (utoppy_debug & l) \ 72 printf m; \ 73 } while (/*CONSTCOND*/0) 74 static int utoppy_debug = 0; 75 static void utoppy_dump_packet(const void *, size_t); 76 #define DDUMP_PACKET(p, l) \ 77 do { \ 78 if (utoppy_debug & UTOPPY_DBG_DUMP) \ 79 utoppy_dump_packet((p), (l)); \ 80 } while (/*CONSTCOND*/0) 81 #else 82 #define DPRINTF(l, m) /* nothing */ 83 #define DDUMP_PACKET(p, l) /* nothing */ 84 #endif 85 86 87 #define UTOPPY_CONFIG_NO 1 88 #define UTOPPY_NUMENDPOINTS 2 89 90 #define UTOPPY_BSIZE 0xffff 91 #define UTOPPY_FRAG_SIZE 0x1000 92 #define UTOPPY_HEADER_SIZE 8 93 #define UTOPPY_SHORT_TIMEOUT (500) /* 0.5 seconds */ 94 #define UTOPPY_LONG_TIMEOUT (10 * 1000) /* 10 seconds */ 95 96 /* Protocol Commands and Responses */ 97 #define UTOPPY_RESP_ERROR 0x0001 98 #define UTOPPY_CMD_ACK 0x0002 99 #define UTOPPY_RESP_SUCCESS UTOPPY_CMD_ACK 100 #define UTOPPY_CMD_CANCEL 0x0003 101 #define UTOPPY_CMD_READY 0x0100 102 #define UTOPPY_CMD_RESET 0x0101 103 #define UTOPPY_CMD_TURBO 0x0102 104 #define UTOPPY_CMD_STATS 0x1000 105 #define UTOPPY_RESP_STATS_DATA 0x1001 106 #define UTOPPY_CMD_READDIR 0x1002 107 #define UTOPPY_RESP_READDIR_DATA 0x1003 108 #define UTOPPY_RESP_READDIR_END 0x1004 109 #define UTOPPY_CMD_DELETE 0x1005 110 #define UTOPPY_CMD_RENAME 0x1006 111 #define UTOPPY_CMD_MKDIR 0x1007 112 #define UTOPPY_CMD_FILE 0x1008 113 #define UTOPPY_FILE_WRITE 0 114 #define UTOPPY_FILE_READ 1 115 #define UTOPPY_RESP_FILE_HEADER 0x1009 116 #define UTOPPY_RESP_FILE_DATA 0x100a 117 #define UTOPPY_RESP_FILE_END 0x100b 118 119 enum utoppy_state { 120 UTOPPY_STATE_CLOSED, 121 UTOPPY_STATE_OPENING, 122 UTOPPY_STATE_IDLE, 123 UTOPPY_STATE_READDIR, 124 UTOPPY_STATE_READFILE, 125 UTOPPY_STATE_WRITEFILE 126 }; 127 128 struct utoppy_softc { 129 device_t sc_dev; 130 struct usbd_device *sc_udev; /* device */ 131 struct usbd_interface *sc_iface; /* interface */ 132 int sc_dying; 133 int sc_refcnt; 134 135 enum utoppy_state sc_state; 136 u_int sc_turbo_mode; 137 138 int sc_out; 139 struct usbd_pipe *sc_out_pipe; /* bulk out pipe */ 140 struct usbd_xfer *sc_out_xfer; 141 void *sc_out_buf; 142 void *sc_out_data; 143 uint64_t sc_wr_offset; 144 uint64_t sc_wr_size; 145 146 int sc_in; 147 struct usbd_pipe *sc_in_pipe; /* bulk in pipe */ 148 struct usbd_xfer *sc_in_xfer; 149 void *sc_in_buf; 150 void *sc_in_data; 151 size_t sc_in_len; 152 u_int sc_in_offset; 153 }; 154 155 struct utoppy_header { 156 uint16_t h_len; 157 uint16_t h_crc; 158 uint16_t h_cmd2; 159 uint16_t h_cmd; 160 uint8_t h_data[0]; 161 }; 162 #define UTOPPY_OUT_INIT(sc) \ 163 do { \ 164 struct utoppy_header *_h = sc->sc_out_data; \ 165 _h->h_len = 0; \ 166 } while (/*CONSTCOND*/0) 167 168 #define UTOPPY_MJD_1970 40587u /* MJD value for Jan 1 00:00:00 1970 */ 169 170 #define UTOPPY_FTYPE_DIR 1 171 #define UTOPPY_FTYPE_FILE 2 172 173 #define UTOPPY_IN_DATA(sc) \ 174 ((void*)&(((uint8_t*)(sc)->sc_in_data)[(sc)->sc_in_offset+UTOPPY_HEADER_SIZE])) 175 176 dev_type_open(utoppyopen); 177 dev_type_close(utoppyclose); 178 dev_type_read(utoppyread); 179 dev_type_write(utoppywrite); 180 dev_type_ioctl(utoppyioctl); 181 182 const struct cdevsw utoppy_cdevsw = { 183 .d_open = utoppyopen, 184 .d_close = utoppyclose, 185 .d_read = utoppyread, 186 .d_write = utoppywrite, 187 .d_ioctl = utoppyioctl, 188 .d_stop = nostop, 189 .d_tty = notty, 190 .d_poll = nopoll, 191 .d_mmap = nommap, 192 .d_kqfilter = nokqfilter, 193 .d_discard = nodiscard, 194 .d_flag = D_OTHER 195 }; 196 197 #define UTOPPYUNIT(n) (minor(n)) 198 199 int utoppy_match(device_t, cfdata_t, void *); 200 void utoppy_attach(device_t, device_t, void *); 201 int utoppy_detach(device_t, int); 202 int utoppy_activate(device_t, enum devact); 203 extern struct cfdriver utoppy_cd; 204 CFATTACH_DECL_NEW(utoppy, sizeof(struct utoppy_softc), utoppy_match, 205 utoppy_attach, utoppy_detach, utoppy_activate); 206 207 int 208 utoppy_match(device_t parent, cfdata_t match, void *aux) 209 { 210 struct usb_attach_arg *uaa = aux; 211 212 if (uaa->uaa_vendor == USB_VENDOR_TOPFIELD && 213 uaa->uaa_product == USB_PRODUCT_TOPFIELD_TF5000PVR) 214 return UMATCH_VENDOR_PRODUCT; 215 216 return UMATCH_NONE; 217 } 218 219 void 220 utoppy_attach(device_t parent, device_t self, void *aux) 221 { 222 struct utoppy_softc *sc = device_private(self); 223 struct usb_attach_arg *uaa = aux; 224 struct usbd_device *dev = uaa->uaa_device; 225 struct usbd_interface *iface; 226 usb_endpoint_descriptor_t *ed; 227 char *devinfop; 228 uint8_t epcount; 229 int i; 230 231 sc->sc_dev = self; 232 233 aprint_naive("\n"); 234 aprint_normal("\n"); 235 236 devinfop = usbd_devinfo_alloc(dev, 0); 237 aprint_normal_dev(self, "%s\n", devinfop); 238 usbd_devinfo_free(devinfop); 239 240 sc->sc_dying = 0; 241 sc->sc_refcnt = 0; 242 sc->sc_udev = dev; 243 244 if (usbd_set_config_index(dev, 0, 1) 245 || usbd_device2interface_handle(dev, 0, &iface)) { 246 aprint_error_dev(self, "Configuration failed\n"); 247 return; 248 } 249 250 epcount = 0; 251 (void) usbd_endpoint_count(iface, &epcount); 252 if (epcount != UTOPPY_NUMENDPOINTS) { 253 aprint_error_dev(self, "Expected %d endpoints, got %d\n", 254 UTOPPY_NUMENDPOINTS, epcount); 255 return; 256 } 257 258 sc->sc_in = -1; 259 sc->sc_out = -1; 260 261 for (i = 0; i < epcount; i++) { 262 ed = usbd_interface2endpoint_descriptor(iface, i); 263 if (ed == NULL) { 264 aprint_error_dev(self, "couldn't get ep %d\n", i); 265 return; 266 } 267 268 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 269 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 270 sc->sc_in = ed->bEndpointAddress; 271 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 272 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 273 sc->sc_out = ed->bEndpointAddress; 274 } 275 } 276 277 if (sc->sc_out == -1 || sc->sc_in == -1) { 278 aprint_error_dev(self, 279 "could not find bulk in/out endpoints\n"); 280 sc->sc_dying = 1; 281 return; 282 } 283 284 sc->sc_iface = iface; 285 sc->sc_udev = dev; 286 287 sc->sc_out_pipe = NULL; 288 sc->sc_in_pipe = NULL; 289 290 if (usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe)) { 291 DPRINTF(UTOPPY_DBG_OPEN, ("%s: usbd_open_pipe(OUT) failed\n", 292 device_xname(sc->sc_dev))); 293 aprint_error_dev(self, "could not open OUT pipe\n"); 294 sc->sc_dying = 1; 295 return; 296 } 297 298 if (usbd_open_pipe(sc->sc_iface, sc->sc_in, 0, &sc->sc_in_pipe)) { 299 DPRINTF(UTOPPY_DBG_OPEN, ("%s: usbd_open_pipe(IN) failed\n", 300 device_xname(sc->sc_dev))); 301 aprint_error_dev(self, "could not open IN pipe\n"); 302 303 usbd_close_pipe(sc->sc_out_pipe); 304 sc->sc_out_pipe = NULL; 305 sc->sc_dying = 1; 306 return; 307 } 308 309 int error; 310 error = usbd_create_xfer(sc->sc_out_pipe, UTOPPY_FRAG_SIZE, 0, 0, 311 &sc->sc_out_xfer); 312 if (error) { 313 aprint_error_dev(self, "could not allocate bulk out xfer\n"); 314 goto fail0; 315 } 316 317 error = usbd_create_xfer(sc->sc_in_pipe, UTOPPY_FRAG_SIZE, 318 USBD_SHORT_XFER_OK, 0, &sc->sc_in_xfer); 319 if (error) { 320 aprint_error_dev(self, "could not allocate bulk in xfer\n"); 321 goto fail1; 322 } 323 324 sc->sc_out_buf = usbd_get_buffer(sc->sc_out_xfer); 325 sc->sc_in_buf = usbd_get_buffer(sc->sc_in_xfer); 326 327 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); 328 329 return; 330 331 fail1: usbd_destroy_xfer(sc->sc_out_xfer); 332 sc->sc_out_xfer = NULL; 333 334 fail0: sc->sc_dying = 1; 335 return; 336 } 337 338 int 339 utoppy_activate(device_t self, enum devact act) 340 { 341 struct utoppy_softc *sc = device_private(self); 342 343 switch (act) { 344 case DVACT_DEACTIVATE: 345 sc->sc_dying = 1; 346 return 0; 347 default: 348 return EOPNOTSUPP; 349 } 350 } 351 352 int 353 utoppy_detach(device_t self, int flags) 354 { 355 struct utoppy_softc *sc = device_private(self); 356 int maj, mn; 357 int s; 358 359 sc->sc_dying = 1; 360 if (sc->sc_out_pipe != NULL) 361 usbd_abort_pipe(sc->sc_out_pipe); 362 if (sc->sc_in_pipe != NULL) 363 usbd_abort_pipe(sc->sc_in_pipe); 364 365 if (sc->sc_in_xfer != NULL) 366 usbd_destroy_xfer(sc->sc_in_xfer); 367 if (sc->sc_out_xfer != NULL) 368 usbd_destroy_xfer(sc->sc_out_xfer); 369 370 if (sc->sc_out_pipe != NULL) 371 usbd_close_pipe(sc->sc_out_pipe); 372 if (sc->sc_in_pipe != NULL) 373 usbd_close_pipe(sc->sc_in_pipe); 374 375 s = splusb(); 376 if (--sc->sc_refcnt >= 0) 377 usb_detach_waitold(sc->sc_dev); 378 splx(s); 379 380 /* locate the major number */ 381 maj = cdevsw_lookup_major(&utoppy_cdevsw); 382 383 /* Nuke the vnodes for any open instances (calls close). */ 384 mn = device_unit(self); 385 vdevgone(maj, mn, mn, VCHR); 386 387 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); 388 389 return 0; 390 } 391 392 #define UTOPPY_CRC16(ccrc,b) crc16_byte((ccrc), (b)) /* from crc16.h */ 393 394 static const int utoppy_usbdstatus_lookup[] = { 395 0, /* USBD_NORMAL_COMPLETION */ 396 EINPROGRESS, /* USBD_IN_PROGRESS */ 397 EALREADY, /* USBD_PENDING_REQUESTS */ 398 EAGAIN, /* USBD_NOT_STARTED */ 399 EINVAL, /* USBD_INVAL */ 400 ENOMEM, /* USBD_NOMEM */ 401 ECONNRESET, /* USBD_CANCELLED */ 402 EFAULT, /* USBD_BAD_ADDRESS */ 403 EBUSY, /* USBD_IN_USE */ 404 EADDRNOTAVAIL, /* USBD_NO_ADDR */ 405 ENETDOWN, /* USBD_SET_ADDR_FAILED */ 406 EIO, /* USBD_NO_POWER */ 407 EMLINK, /* USBD_TOO_DEEP */ 408 EIO, /* USBD_IOERROR */ 409 ENXIO, /* USBD_NOT_CONFIGURED */ 410 ETIMEDOUT, /* USBD_TIMEOUT */ 411 EBADMSG, /* USBD_SHORT_XFER */ 412 EHOSTDOWN, /* USBD_STALLED */ 413 EINTR /* USBD_INTERRUPTED */ 414 }; 415 416 static __inline int 417 utoppy_usbd_status2errno(usbd_status err) 418 { 419 420 if (err >= USBD_ERROR_MAX) 421 return EFAULT; 422 return utoppy_usbdstatus_lookup[err]; 423 } 424 425 #ifdef UTOPPY_DEBUG 426 static const char * 427 utoppy_state_string(enum utoppy_state state) 428 { 429 const char *str; 430 431 switch (state) { 432 case UTOPPY_STATE_CLOSED: 433 str = "CLOSED"; 434 break; 435 case UTOPPY_STATE_OPENING: 436 str = "OPENING"; 437 break; 438 case UTOPPY_STATE_IDLE: 439 str = "IDLE"; 440 break; 441 case UTOPPY_STATE_READDIR: 442 str = "READ DIRECTORY"; 443 break; 444 case UTOPPY_STATE_READFILE: 445 str = "READ FILE"; 446 break; 447 case UTOPPY_STATE_WRITEFILE: 448 str = "WRITE FILE"; 449 break; 450 default: 451 str = "INVALID!"; 452 break; 453 } 454 455 return str; 456 } 457 458 static void 459 utoppy_dump_packet(const void *b, size_t len) 460 { 461 const uint8_t *buf = b, *l; 462 uint8_t c; 463 size_t i, j; 464 465 if (len == 0) 466 return; 467 468 len = min(len, 256); 469 470 printf("00: "); 471 472 for (i = 0, l = buf; i < len; i++) { 473 printf("%02x ", *buf++); 474 475 if ((i % 16) == 15) { 476 for (j = 0; j < 16; j++) { 477 c = *l++; 478 if (c < ' ' || c > 0x7e) 479 c = '.'; 480 printf("%c", c); 481 } 482 483 printf("\n"); 484 l = buf; 485 486 if ((i + 1) < len) 487 printf("%02x: ", (u_int)i + 1); 488 } 489 } 490 491 while ((i++ % 16) != 0) 492 printf(" "); 493 494 if (l < buf) { 495 while (l < buf) { 496 c = *l++; 497 if (c < ' ' || c > 0x7e) 498 c = '.'; 499 printf("%c", c); 500 } 501 502 printf("\n"); 503 } 504 } 505 #endif 506 507 static usbd_status 508 utoppy_bulk_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe, 509 uint16_t flags, uint32_t timeout, void *buf, uint32_t *size) 510 { 511 usbd_status err; 512 513 usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL); 514 515 err = usbd_sync_transfer_sig(xfer); 516 517 usbd_get_xfer_status(xfer, NULL, NULL, size, NULL); 518 return err; 519 } 520 521 static int 522 utoppy_send_packet(struct utoppy_softc *sc, uint16_t cmd, uint32_t timeout) 523 { 524 struct utoppy_header *h; 525 usbd_status err; 526 uint32_t len; 527 uint16_t dlen, crc; 528 uint8_t *data, *e, t1, t2; 529 530 h = sc->sc_out_data; 531 532 DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: cmd 0x%04x, " 533 "len %d\n", device_xname(sc->sc_dev), (u_int)cmd, h->h_len)); 534 535 dlen = h->h_len; 536 len = dlen + UTOPPY_HEADER_SIZE; 537 538 if (len & 1) 539 len++; 540 if ((len % 64) == 0) 541 len += 2; 542 543 if (len >= UTOPPY_BSIZE) { 544 DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: " 545 "packet too big (%d)\n", device_xname(sc->sc_dev), 546 (int)len)); 547 return EINVAL; 548 } 549 550 h->h_len = htole16(dlen + UTOPPY_HEADER_SIZE); 551 h->h_cmd2 = 0; 552 h->h_cmd = htole16(cmd); 553 554 /* The command word is part of the CRC */ 555 crc = UTOPPY_CRC16(0, 0); 556 crc = UTOPPY_CRC16(crc, 0); 557 crc = UTOPPY_CRC16(crc, cmd >> 8); 558 crc = UTOPPY_CRC16(crc, cmd); 559 560 /* 561 * If there is data following the header, calculate the CRC and 562 * byte-swap as we go. 563 */ 564 if (dlen) { 565 data = h->h_data; 566 e = data + (dlen & ~1); 567 568 do { 569 t1 = data[0]; 570 t2 = data[1]; 571 crc = UTOPPY_CRC16(crc, t1); 572 crc = UTOPPY_CRC16(crc, t2); 573 *data++ = t2; 574 *data++ = t1; 575 } while (data < e); 576 577 if (dlen & 1) { 578 t1 = data[0]; 579 crc = UTOPPY_CRC16(crc, t1); 580 data[1] = t1; 581 } 582 } 583 584 h->h_crc = htole16(crc); 585 data = sc->sc_out_data; 586 587 DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: total len " 588 "%d...\n", device_xname(sc->sc_dev), (int)len)); 589 DDUMP_PACKET(data, len); 590 591 do { 592 uint32_t thislen; 593 594 thislen = min(len, UTOPPY_FRAG_SIZE); 595 596 memcpy(sc->sc_out_buf, data, thislen); 597 598 err = utoppy_bulk_transfer(sc->sc_out_xfer, sc->sc_out_pipe, 599 0, timeout, sc->sc_out_buf, &thislen); 600 601 if (thislen != min(len, UTOPPY_FRAG_SIZE)) { 602 DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: " 603 "utoppy_send_packet: sent %ld, err %d\n", 604 device_xname(sc->sc_dev), (u_long)thislen, err)); 605 } 606 607 if (err == 0) { 608 len -= thislen; 609 data += thislen; 610 } 611 } while (err == 0 && len); 612 613 DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: " 614 "usbd_bulk_transfer() returned %d.\n", 615 device_xname(sc->sc_dev),err)); 616 617 return err ? utoppy_usbd_status2errno(err) : 0; 618 } 619 620 static int 621 utoppy_recv_packet(struct utoppy_softc *sc, uint16_t *respp, uint32_t timeout) 622 { 623 struct utoppy_header *h; 624 usbd_status err; 625 uint32_t len, thislen, requested, bytesleft; 626 uint16_t crc; 627 uint8_t *data, *e, t1, t2; 628 629 data = sc->sc_in_data; 630 len = 0; 631 bytesleft = UTOPPY_BSIZE; 632 633 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: ...\n", 634 device_xname(sc->sc_dev))); 635 636 do { 637 requested = thislen = min(bytesleft, UTOPPY_FRAG_SIZE); 638 639 err = utoppy_bulk_transfer(sc->sc_in_xfer, sc->sc_in_pipe, 640 USBD_SHORT_XFER_OK, timeout, sc->sc_in_buf, 641 &thislen); 642 643 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: " 644 "usbd_bulk_transfer() returned %d, thislen %d, data %p\n", 645 device_xname(sc->sc_dev), err, (u_int)thislen, data)); 646 647 if (err == 0) { 648 memcpy(data, sc->sc_in_buf, thislen); 649 DDUMP_PACKET(data, thislen); 650 len += thislen; 651 bytesleft -= thislen; 652 data += thislen; 653 } 654 } while (err == 0 && bytesleft && thislen == requested); 655 656 if (err) 657 return utoppy_usbd_status2errno(err); 658 659 h = sc->sc_in_data; 660 661 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: received %d " 662 "bytes in total to %p\n", device_xname(sc->sc_dev), (u_int)len, h)); 663 DDUMP_PACKET(h, len); 664 665 if (len < UTOPPY_HEADER_SIZE || len < (uint32_t)le16toh(h->h_len)) { 666 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: bad " 667 " length (len %d, h_len %d)\n", device_xname(sc->sc_dev), 668 (int)len, le16toh(h->h_len))); 669 return EIO; 670 } 671 672 len = h->h_len = le16toh(h->h_len); 673 h->h_crc = le16toh(h->h_crc); 674 *respp = h->h_cmd = le16toh(h->h_cmd); 675 h->h_cmd2 = le16toh(h->h_cmd2); 676 677 /* 678 * To maximise data throughput when transferring files, acknowledge 679 * data blocks as soon as we receive them. If we detect an error 680 * later on, we can always cancel. 681 */ 682 if (*respp == UTOPPY_RESP_FILE_DATA) { 683 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: " 684 "ACKing file data\n", device_xname(sc->sc_dev))); 685 686 UTOPPY_OUT_INIT(sc); 687 err = utoppy_send_packet(sc, UTOPPY_CMD_ACK, 688 UTOPPY_SHORT_TIMEOUT); 689 if (err) { 690 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: " 691 "utoppy_recv_packet: failed to ACK file data: %d\n", 692 device_xname(sc->sc_dev), err)); 693 return err; 694 } 695 } 696 697 /* The command word is part of the CRC */ 698 crc = UTOPPY_CRC16(0, h->h_cmd2 >> 8); 699 crc = UTOPPY_CRC16(crc, h->h_cmd2); 700 crc = UTOPPY_CRC16(crc, h->h_cmd >> 8); 701 crc = UTOPPY_CRC16(crc, h->h_cmd); 702 703 /* 704 * Extract any payload, byte-swapping and calculating the CRC16 705 * as we go. 706 */ 707 if (len > UTOPPY_HEADER_SIZE) { 708 data = h->h_data; 709 e = data + ((len & ~1) - UTOPPY_HEADER_SIZE); 710 711 while (data < e) { 712 t1 = data[0]; 713 t2 = data[1]; 714 crc = UTOPPY_CRC16(crc, t2); 715 crc = UTOPPY_CRC16(crc, t1); 716 *data++ = t2; 717 *data++ = t1; 718 } 719 720 if (len & 1) { 721 t1 = data[1]; 722 crc = UTOPPY_CRC16(crc, t1); 723 *data = t1; 724 } 725 } 726 727 sc->sc_in_len = (size_t) len - UTOPPY_HEADER_SIZE; 728 sc->sc_in_offset = 0; 729 730 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: len %d, " 731 "crc 0x%04x, hdrcrc 0x%04x\n", device_xname(sc->sc_dev), 732 (int)len, crc, h->h_crc)); 733 DDUMP_PACKET(h, len); 734 735 return (crc == h->h_crc) ? 0 : EBADMSG; 736 } 737 738 static __inline void * 739 utoppy_current_ptr(void *b) 740 { 741 struct utoppy_header *h = b; 742 743 return &h->h_data[h->h_len]; 744 } 745 746 static __inline void 747 utoppy_advance_ptr(void *b, size_t len) 748 { 749 struct utoppy_header *h = b; 750 751 h->h_len += len; 752 } 753 754 static __inline void 755 utoppy_add_8(struct utoppy_softc *sc, uint8_t v) 756 { 757 struct utoppy_header *h = sc->sc_out_data; 758 uint8_t *p; 759 760 p = utoppy_current_ptr(h); 761 *p = v; 762 utoppy_advance_ptr(h, sizeof(v)); 763 } 764 765 static __inline void 766 utoppy_add_16(struct utoppy_softc *sc, uint16_t v) 767 { 768 struct utoppy_header *h = sc->sc_out_data; 769 uint8_t *p; 770 771 p = utoppy_current_ptr(h); 772 *p++ = (uint8_t)(v >> 8); 773 *p = (uint8_t)v; 774 utoppy_advance_ptr(h, sizeof(v)); 775 } 776 777 static __inline void 778 utoppy_add_32(struct utoppy_softc *sc, uint32_t v) 779 { 780 struct utoppy_header *h = sc->sc_out_data; 781 uint8_t *p; 782 783 p = utoppy_current_ptr(h); 784 *p++ = (uint8_t)(v >> 24); 785 *p++ = (uint8_t)(v >> 16); 786 *p++ = (uint8_t)(v >> 8); 787 *p = (uint8_t)v; 788 utoppy_advance_ptr(h, sizeof(v)); 789 } 790 791 static __inline void 792 utoppy_add_64(struct utoppy_softc *sc, uint64_t v) 793 { 794 struct utoppy_header *h = sc->sc_out_data; 795 uint8_t *p; 796 797 p = utoppy_current_ptr(h); 798 *p++ = (uint8_t)(v >> 56); 799 *p++ = (uint8_t)(v >> 48); 800 *p++ = (uint8_t)(v >> 40); 801 *p++ = (uint8_t)(v >> 32); 802 *p++ = (uint8_t)(v >> 24); 803 *p++ = (uint8_t)(v >> 16); 804 *p++ = (uint8_t)(v >> 8); 805 *p = (uint8_t)v; 806 utoppy_advance_ptr(h, sizeof(v)); 807 } 808 809 static __inline void 810 utoppy_add_string(struct utoppy_softc *sc, const char *str, size_t len) 811 { 812 struct utoppy_header *h = sc->sc_out_data; 813 char *p; 814 815 p = utoppy_current_ptr(h); 816 memset(p, 0, len); 817 strncpy(p, str, len); 818 utoppy_advance_ptr(h, len); 819 } 820 821 static int 822 utoppy_add_path(struct utoppy_softc *sc, const char *path, int putlen) 823 { 824 struct utoppy_header *h = sc->sc_out_data; 825 uint8_t *p, *str, *s; 826 size_t len; 827 int err; 828 829 p = utoppy_current_ptr(h); 830 831 str = putlen ? (p + sizeof(uint16_t)) : p; 832 833 err = copyinstr(path, str, UTOPPY_MAX_FILENAME_LEN, &len); 834 835 DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: err %d, len %d\n", 836 err, (int)len)); 837 838 if (err) 839 return err; 840 841 if (len < 2) 842 return EINVAL; 843 844 /* 845 * copyinstr(9) has already copied the terminating NUL character, 846 * but we append another one in case we have to pad the length 847 * later on. 848 */ 849 str[len] = '\0'; 850 851 /* 852 * The Toppy uses backslash as the directory separator, so convert 853 * all forward slashes. 854 */ 855 for (s = &str[len - 2]; s >= str; s--) 856 if (*s == '/') 857 *s = '\\'; 858 859 if ((len + h->h_len) & 1) 860 len++; 861 862 if (putlen) 863 utoppy_add_16(sc, len); 864 865 utoppy_advance_ptr(h, len); 866 867 DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: final len %d\n", 868 (u_int)len)); 869 870 return 0; 871 } 872 873 static __inline int 874 utoppy_get_8(struct utoppy_softc *sc, uint8_t *vp) 875 { 876 uint8_t *p; 877 878 if (sc->sc_in_len < sizeof(*vp)) 879 return 1; 880 881 p = UTOPPY_IN_DATA(sc); 882 *vp = *p; 883 sc->sc_in_offset += sizeof(*vp); 884 sc->sc_in_len -= sizeof(*vp); 885 return 0; 886 } 887 888 static __inline int 889 utoppy_get_16(struct utoppy_softc *sc, uint16_t *vp) 890 { 891 uint16_t v; 892 uint8_t *p; 893 894 if (sc->sc_in_len < sizeof(v)) 895 return 1; 896 897 p = UTOPPY_IN_DATA(sc); 898 v = *p++; 899 v = (v << 8) | *p; 900 *vp = v; 901 sc->sc_in_offset += sizeof(v); 902 sc->sc_in_len -= sizeof(v); 903 return 0; 904 } 905 906 static __inline int 907 utoppy_get_32(struct utoppy_softc *sc, uint32_t *vp) 908 { 909 uint32_t v; 910 uint8_t *p; 911 912 if (sc->sc_in_len < sizeof(v)) 913 return 1; 914 915 p = UTOPPY_IN_DATA(sc); 916 v = *p++; 917 v = (v << 8) | *p++; 918 v = (v << 8) | *p++; 919 v = (v << 8) | *p; 920 *vp = v; 921 sc->sc_in_offset += sizeof(v); 922 sc->sc_in_len -= sizeof(v); 923 return 0; 924 } 925 926 static __inline int 927 utoppy_get_64(struct utoppy_softc *sc, uint64_t *vp) 928 { 929 uint64_t v; 930 uint8_t *p; 931 932 if (sc->sc_in_len < sizeof(v)) 933 return 1; 934 935 p = UTOPPY_IN_DATA(sc); 936 v = *p++; 937 v = (v << 8) | *p++; 938 v = (v << 8) | *p++; 939 v = (v << 8) | *p++; 940 v = (v << 8) | *p++; 941 v = (v << 8) | *p++; 942 v = (v << 8) | *p++; 943 v = (v << 8) | *p; 944 *vp = v; 945 sc->sc_in_offset += sizeof(v); 946 sc->sc_in_len -= sizeof(v); 947 return 0; 948 } 949 950 static __inline int 951 utoppy_get_string(struct utoppy_softc *sc, char *str, size_t len) 952 { 953 char *p; 954 955 if (sc->sc_in_len < len) 956 return 1; 957 958 memset(str, 0, len); 959 p = UTOPPY_IN_DATA(sc); 960 strncpy(str, p, len); 961 sc->sc_in_offset += len; 962 sc->sc_in_len -= len; 963 return 0; 964 } 965 966 static int 967 utoppy_command(struct utoppy_softc *sc, uint16_t cmd, int timeout, 968 uint16_t *presp) 969 { 970 int err; 971 972 err = utoppy_send_packet(sc, cmd, timeout); 973 if (err) 974 return err; 975 976 err = utoppy_recv_packet(sc, presp, timeout); 977 if (err == EBADMSG) { 978 UTOPPY_OUT_INIT(sc); 979 utoppy_send_packet(sc, UTOPPY_RESP_ERROR, timeout); 980 } 981 982 return err; 983 } 984 985 static int 986 utoppy_timestamp_decode(struct utoppy_softc *sc, time_t *tp) 987 { 988 uint16_t mjd; 989 uint8_t hour, minute, sec; 990 uint32_t rv; 991 992 if (utoppy_get_16(sc, &mjd) || utoppy_get_8(sc, &hour) || 993 utoppy_get_8(sc, &minute) || utoppy_get_8(sc, &sec)) 994 return 1; 995 996 if (mjd == 0xffffu && hour == 0xffu && minute == 0xffu && sec == 0xffu){ 997 *tp = 0; 998 return 0; 999 } 1000 1001 rv = (mjd < UTOPPY_MJD_1970) ? UTOPPY_MJD_1970 : (uint32_t) mjd; 1002 1003 /* Calculate seconds since 1970 */ 1004 rv = (rv - UTOPPY_MJD_1970) * 60 * 60 * 24; 1005 1006 /* Add in the hours, minutes, and seconds */ 1007 rv += (uint32_t)hour * 60 * 60; 1008 rv += (uint32_t)minute * 60; 1009 rv += sec; 1010 *tp = (time_t)rv; 1011 1012 return 0; 1013 } 1014 1015 static void 1016 utoppy_timestamp_encode(struct utoppy_softc *sc, time_t t) 1017 { 1018 u_int mjd, hour, minute; 1019 1020 mjd = t / (60 * 60 * 24); 1021 t -= mjd * 60 * 60 * 24; 1022 1023 hour = t / (60 * 60); 1024 t -= hour * 60 * 60; 1025 1026 minute = t / 60; 1027 t -= minute * 60; 1028 1029 utoppy_add_16(sc, mjd + UTOPPY_MJD_1970); 1030 utoppy_add_8(sc, hour); 1031 utoppy_add_8(sc, minute); 1032 utoppy_add_8(sc, t); 1033 } 1034 1035 static int 1036 utoppy_turbo_mode(struct utoppy_softc *sc, int state) 1037 { 1038 uint16_t r; 1039 int err; 1040 1041 UTOPPY_OUT_INIT(sc); 1042 utoppy_add_32(sc, state); 1043 1044 err = utoppy_command(sc, UTOPPY_CMD_TURBO, UTOPPY_SHORT_TIMEOUT, &r); 1045 if (err) 1046 return err; 1047 1048 return (r == UTOPPY_RESP_SUCCESS) ? 0 : EIO; 1049 } 1050 1051 static int 1052 utoppy_check_ready(struct utoppy_softc *sc) 1053 { 1054 uint16_t r; 1055 int err; 1056 1057 UTOPPY_OUT_INIT(sc); 1058 1059 err = utoppy_command(sc, UTOPPY_CMD_READY, UTOPPY_LONG_TIMEOUT, &r); 1060 if (err) 1061 return err; 1062 1063 return (r == UTOPPY_RESP_SUCCESS) ? 0 : EIO; 1064 } 1065 1066 static int 1067 utoppy_cancel(struct utoppy_softc *sc) 1068 { 1069 uint16_t r; 1070 int err, i; 1071 1072 /* 1073 * Issue the cancel command serveral times. the Toppy doesn't 1074 * always respond to the first. 1075 */ 1076 for (i = 0; i < 3; i++) { 1077 UTOPPY_OUT_INIT(sc); 1078 err = utoppy_command(sc, UTOPPY_CMD_CANCEL, 1079 UTOPPY_SHORT_TIMEOUT, &r); 1080 if (err == 0 && r == UTOPPY_RESP_SUCCESS) 1081 break; 1082 err = ETIMEDOUT; 1083 } 1084 1085 if (err) 1086 return err; 1087 1088 /* 1089 * Make sure turbo mode is off, otherwise the Toppy will not 1090 * respond to remote control input. 1091 */ 1092 (void) utoppy_turbo_mode(sc, 0); 1093 1094 sc->sc_state = UTOPPY_STATE_IDLE; 1095 return 0; 1096 } 1097 1098 static int 1099 utoppy_stats(struct utoppy_softc *sc, struct utoppy_stats *us) 1100 { 1101 uint32_t hsize, hfree; 1102 uint16_t r; 1103 int err; 1104 1105 UTOPPY_OUT_INIT(sc); 1106 err = utoppy_command(sc, UTOPPY_CMD_STATS, UTOPPY_LONG_TIMEOUT, &r); 1107 if (err) 1108 return err; 1109 1110 if (r != UTOPPY_RESP_STATS_DATA) 1111 return EIO; 1112 1113 if (utoppy_get_32(sc, &hsize) || utoppy_get_32(sc, &hfree)) 1114 return EIO; 1115 1116 us->us_hdd_size = hsize; 1117 us->us_hdd_size *= 1024; 1118 us->us_hdd_free = hfree; 1119 us->us_hdd_free *= 1024; 1120 1121 return 0; 1122 } 1123 1124 static int 1125 utoppy_readdir_next(struct utoppy_softc *sc) 1126 { 1127 uint16_t resp; 1128 int err; 1129 1130 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: running...\n", 1131 device_xname(sc->sc_dev))); 1132 1133 /* 1134 * Fetch the next READDIR response 1135 */ 1136 err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT); 1137 if (err) { 1138 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " 1139 "utoppy_recv_packet() returned %d\n", 1140 device_xname(sc->sc_dev), err)); 1141 if (err == EBADMSG) { 1142 UTOPPY_OUT_INIT(sc); 1143 utoppy_send_packet(sc, UTOPPY_RESP_ERROR, 1144 UTOPPY_LONG_TIMEOUT); 1145 } 1146 utoppy_cancel(sc); 1147 return err; 1148 } 1149 1150 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " 1151 "utoppy_recv_packet() returned %d, len %ld\n", 1152 device_xname(sc->sc_dev), err, (u_long)sc->sc_in_len)); 1153 1154 switch (resp) { 1155 case UTOPPY_RESP_READDIR_DATA: 1156 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " 1157 "UTOPPY_RESP_READDIR_DATA\n", device_xname(sc->sc_dev))); 1158 1159 UTOPPY_OUT_INIT(sc); 1160 err = utoppy_send_packet(sc, UTOPPY_CMD_ACK, 1161 UTOPPY_LONG_TIMEOUT); 1162 if (err) { 1163 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " 1164 "utoppy_send_packet(ACK) returned %d\n", 1165 device_xname(sc->sc_dev), err)); 1166 utoppy_cancel(sc); 1167 return err; 1168 } 1169 sc->sc_state = UTOPPY_STATE_READDIR; 1170 sc->sc_in_offset = 0; 1171 break; 1172 1173 case UTOPPY_RESP_READDIR_END: 1174 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " 1175 "UTOPPY_RESP_READDIR_END\n", device_xname(sc->sc_dev))); 1176 1177 UTOPPY_OUT_INIT(sc); 1178 utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT); 1179 sc->sc_state = UTOPPY_STATE_IDLE; 1180 sc->sc_in_len = 0; 1181 break; 1182 1183 default: 1184 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: " 1185 "bad response: 0x%x\n", device_xname(sc->sc_dev), resp)); 1186 sc->sc_state = UTOPPY_STATE_IDLE; 1187 sc->sc_in_len = 0; 1188 return EIO; 1189 } 1190 1191 return 0; 1192 } 1193 1194 static size_t 1195 utoppy_readdir_decode(struct utoppy_softc *sc, struct utoppy_dirent *ud) 1196 { 1197 uint8_t ftype; 1198 1199 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: bytes left" 1200 " %d\n", device_xname(sc->sc_dev), (int)sc->sc_in_len)); 1201 1202 if (utoppy_timestamp_decode(sc, &ud->ud_mtime) || 1203 utoppy_get_8(sc, &ftype) || utoppy_get_64(sc, &ud->ud_size) || 1204 utoppy_get_string(sc, ud->ud_path, UTOPPY_MAX_FILENAME_LEN + 1) || 1205 utoppy_get_32(sc, &ud->ud_attributes)) { 1206 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: no " 1207 "more to decode\n", device_xname(sc->sc_dev))); 1208 return 0; 1209 } 1210 1211 switch (ftype) { 1212 case UTOPPY_FTYPE_DIR: 1213 ud->ud_type = UTOPPY_DIRENT_DIRECTORY; 1214 break; 1215 case UTOPPY_FTYPE_FILE: 1216 ud->ud_type = UTOPPY_DIRENT_FILE; 1217 break; 1218 default: 1219 ud->ud_type = UTOPPY_DIRENT_UNKNOWN; 1220 break; 1221 } 1222 1223 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: %s '%s', " 1224 "size %lld, time 0x%08lx, attr 0x%08x\n", device_xname(sc->sc_dev), 1225 (ftype == UTOPPY_FTYPE_DIR) ? "DIR" : 1226 ((ftype == UTOPPY_FTYPE_FILE) ? "FILE" : "UNKNOWN"), ud->ud_path, 1227 ud->ud_size, (u_long)ud->ud_mtime, ud->ud_attributes)); 1228 1229 return 1; 1230 } 1231 1232 static int 1233 utoppy_readfile_next(struct utoppy_softc *sc) 1234 { 1235 uint64_t off; 1236 uint16_t resp; 1237 int err; 1238 1239 err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT); 1240 if (err) { 1241 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " 1242 "utoppy_recv_packet() returned %d\n", 1243 device_xname(sc->sc_dev), err)); 1244 utoppy_cancel(sc); 1245 return err; 1246 } 1247 1248 switch (resp) { 1249 case UTOPPY_RESP_FILE_HEADER: 1250 /* ACK it */ 1251 UTOPPY_OUT_INIT(sc); 1252 err = utoppy_send_packet(sc, UTOPPY_CMD_ACK, 1253 UTOPPY_LONG_TIMEOUT); 1254 if (err) { 1255 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " 1256 "utoppy_send_packet(UTOPPY_CMD_ACK) returned %d\n", 1257 device_xname(sc->sc_dev), err)); 1258 utoppy_cancel(sc); 1259 return err; 1260 } 1261 1262 sc->sc_in_len = 0; 1263 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " 1264 "FILE_HEADER done\n", device_xname(sc->sc_dev))); 1265 break; 1266 1267 case UTOPPY_RESP_FILE_DATA: 1268 /* Already ACK'd */ 1269 if (utoppy_get_64(sc, &off)) { 1270 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " 1271 "UTOPPY_RESP_FILE_DATA did not provide offset\n", 1272 device_xname(sc->sc_dev))); 1273 utoppy_cancel(sc); 1274 return EBADMSG; 1275 } 1276 1277 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " 1278 "UTOPPY_RESP_FILE_DATA: offset %lld, bytes left %ld\n", 1279 device_xname(sc->sc_dev), off, (u_long)sc->sc_in_len)); 1280 break; 1281 1282 case UTOPPY_RESP_FILE_END: 1283 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: " 1284 "UTOPPY_RESP_FILE_END: sending ACK\n", 1285 device_xname(sc->sc_dev))); 1286 UTOPPY_OUT_INIT(sc); 1287 utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT); 1288 /*FALLTHROUGH*/ 1289 1290 case UTOPPY_RESP_SUCCESS: 1291 sc->sc_state = UTOPPY_STATE_IDLE; 1292 (void) utoppy_turbo_mode(sc, 0); 1293 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: all " 1294 "done\n", device_xname(sc->sc_dev))); 1295 break; 1296 1297 case UTOPPY_RESP_ERROR: 1298 default: 1299 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: bad " 1300 "response code 0x%0x\n", device_xname(sc->sc_dev), resp)); 1301 utoppy_cancel(sc); 1302 return EIO; 1303 } 1304 1305 return 0; 1306 } 1307 1308 int 1309 utoppyopen(dev_t dev, int flag, int mode, 1310 struct lwp *l) 1311 { 1312 struct utoppy_softc *sc; 1313 int error = 0; 1314 1315 sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); 1316 if (sc == NULL) 1317 return ENXIO; 1318 1319 if (sc == NULL || sc->sc_iface == NULL || sc->sc_dying) 1320 return ENXIO; 1321 1322 if (sc->sc_state != UTOPPY_STATE_CLOSED) { 1323 DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: already open\n", 1324 device_xname(sc->sc_dev))); 1325 return EBUSY; 1326 } 1327 1328 DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: opening...\n", 1329 device_xname(sc->sc_dev))); 1330 1331 sc->sc_refcnt++; 1332 sc->sc_state = UTOPPY_STATE_OPENING; 1333 sc->sc_turbo_mode = 0; 1334 sc->sc_out_data = kmem_alloc(UTOPPY_BSIZE + 1, KM_SLEEP); 1335 if (sc->sc_out_data == NULL) { 1336 error = ENOMEM; 1337 goto error; 1338 } 1339 1340 sc->sc_in_data = kmem_alloc(UTOPPY_BSIZE + 1, KM_SLEEP); 1341 if (sc->sc_in_data == NULL) { 1342 kmem_free(sc->sc_out_data, UTOPPY_BSIZE + 1); 1343 sc->sc_out_data = NULL; 1344 error = ENOMEM; 1345 goto error; 1346 } 1347 1348 if ((error = utoppy_cancel(sc)) != 0) 1349 goto error; 1350 1351 if ((error = utoppy_check_ready(sc)) != 0) { 1352 DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: utoppy_check_ready()" 1353 " returned %d\n", device_xname(sc->sc_dev), error)); 1354 } 1355 1356 error: 1357 sc->sc_state = error ? UTOPPY_STATE_CLOSED : UTOPPY_STATE_IDLE; 1358 1359 DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: done. error %d, new state " 1360 "'%s'\n", device_xname(sc->sc_dev), error, 1361 utoppy_state_string(sc->sc_state))); 1362 1363 if (--sc->sc_refcnt < 0) 1364 usb_detach_wakeupold(sc->sc_dev); 1365 1366 return error; 1367 } 1368 1369 int 1370 utoppyclose(dev_t dev, int flag, int mode, struct lwp *l) 1371 { 1372 struct utoppy_softc *sc; 1373 usbd_status err; 1374 1375 sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); 1376 1377 DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: closing...\n", 1378 device_xname(sc->sc_dev))); 1379 1380 if (sc->sc_state < UTOPPY_STATE_IDLE) { 1381 /* We are being forced to close before the open completed. */ 1382 DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: not properly " 1383 "open: %s\n", device_xname(sc->sc_dev), 1384 utoppy_state_string(sc->sc_state))); 1385 return 0; 1386 } 1387 1388 if (sc->sc_out_data) 1389 (void) utoppy_cancel(sc); 1390 1391 if (sc->sc_out_pipe != NULL) { 1392 if ((err = usbd_abort_pipe(sc->sc_out_pipe)) != 0) 1393 printf("usbd_abort_pipe(OUT) returned %d\n", err); 1394 sc->sc_out_pipe = NULL; 1395 } 1396 1397 if (sc->sc_in_pipe != NULL) { 1398 if ((err = usbd_abort_pipe(sc->sc_in_pipe)) != 0) 1399 printf("usbd_abort_pipe(IN) returned %d\n", err); 1400 sc->sc_in_pipe = NULL; 1401 } 1402 1403 if (sc->sc_out_data) { 1404 kmem_free(sc->sc_out_data, UTOPPY_BSIZE + 1); 1405 sc->sc_out_data = NULL; 1406 } 1407 1408 if (sc->sc_in_data) { 1409 kmem_free(sc->sc_in_data, UTOPPY_BSIZE + 1); 1410 sc->sc_in_data = NULL; 1411 } 1412 1413 sc->sc_state = UTOPPY_STATE_CLOSED; 1414 1415 DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: done.\n", 1416 device_xname(sc->sc_dev))); 1417 1418 return 0; 1419 } 1420 1421 int 1422 utoppyread(dev_t dev, struct uio *uio, int flags) 1423 { 1424 struct utoppy_softc *sc; 1425 struct utoppy_dirent ud; 1426 size_t len; 1427 int err; 1428 1429 sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); 1430 1431 if (sc->sc_dying) 1432 return EIO; 1433 1434 sc->sc_refcnt++; 1435 1436 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: reading: state '%s'\n", 1437 device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state))); 1438 1439 switch (sc->sc_state) { 1440 case UTOPPY_STATE_READDIR: 1441 err = 0; 1442 while (err == 0 && uio->uio_resid >= sizeof(ud) && 1443 sc->sc_state != UTOPPY_STATE_IDLE) { 1444 if (utoppy_readdir_decode(sc, &ud) == 0) 1445 err = utoppy_readdir_next(sc); 1446 else 1447 if ((err = uiomove(&ud, sizeof(ud), uio)) != 0) 1448 utoppy_cancel(sc); 1449 } 1450 break; 1451 1452 case UTOPPY_STATE_READFILE: 1453 err = 0; 1454 while (err == 0 && uio->uio_resid > 0 && 1455 sc->sc_state != UTOPPY_STATE_IDLE) { 1456 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: READFILE: " 1457 "resid %ld, bytes_left %ld\n", 1458 device_xname(sc->sc_dev), (u_long)uio->uio_resid, 1459 (u_long)sc->sc_in_len)); 1460 1461 if (sc->sc_in_len == 0 && 1462 (err = utoppy_readfile_next(sc)) != 0) { 1463 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: " 1464 "READFILE: utoppy_readfile_next returned " 1465 "%d\n", device_xname(sc->sc_dev), err)); 1466 break; 1467 } 1468 1469 len = min(uio->uio_resid, sc->sc_in_len); 1470 if (len) { 1471 err = uiomove(UTOPPY_IN_DATA(sc), len, uio); 1472 if (err == 0) { 1473 sc->sc_in_offset += len; 1474 sc->sc_in_len -= len; 1475 } 1476 } 1477 } 1478 break; 1479 1480 case UTOPPY_STATE_IDLE: 1481 err = 0; 1482 break; 1483 1484 case UTOPPY_STATE_WRITEFILE: 1485 err = EBUSY; 1486 break; 1487 1488 default: 1489 err = EIO; 1490 break; 1491 } 1492 1493 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: done. err %d, state '%s'\n", 1494 device_xname(sc->sc_dev), err, utoppy_state_string(sc->sc_state))); 1495 1496 if (--sc->sc_refcnt < 0) 1497 usb_detach_wakeupold(sc->sc_dev); 1498 1499 return err; 1500 } 1501 1502 int 1503 utoppywrite(dev_t dev, struct uio *uio, int flags) 1504 { 1505 struct utoppy_softc *sc; 1506 uint16_t resp; 1507 size_t len; 1508 int err; 1509 1510 sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); 1511 1512 if (sc->sc_dying) 1513 return EIO; 1514 1515 switch(sc->sc_state) { 1516 case UTOPPY_STATE_WRITEFILE: 1517 break; 1518 1519 case UTOPPY_STATE_IDLE: 1520 return 0; 1521 1522 default: 1523 return EIO; 1524 } 1525 1526 sc->sc_refcnt++; 1527 err = 0; 1528 1529 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: PRE-WRITEFILE: resid " 1530 "%ld, wr_size %lld, wr_offset %lld\n", device_xname(sc->sc_dev), 1531 (u_long)uio->uio_resid, sc->sc_wr_size, sc->sc_wr_offset)); 1532 1533 while (sc->sc_state == UTOPPY_STATE_WRITEFILE && 1534 (len = min(uio->uio_resid, sc->sc_wr_size)) != 0) { 1535 1536 len = min(len, UTOPPY_BSIZE - (UTOPPY_HEADER_SIZE + 1537 sizeof(uint64_t) + 3)); 1538 1539 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove(%ld)\n", 1540 device_xname(sc->sc_dev), (u_long)len)); 1541 1542 UTOPPY_OUT_INIT(sc); 1543 utoppy_add_64(sc, sc->sc_wr_offset); 1544 1545 err = uiomove(utoppy_current_ptr(sc->sc_out_data), len, uio); 1546 if (err) { 1547 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove()" 1548 " returned %d\n", device_xname(sc->sc_dev), err)); 1549 break; 1550 } 1551 1552 utoppy_advance_ptr(sc->sc_out_data, len); 1553 1554 err = utoppy_command(sc, UTOPPY_RESP_FILE_DATA, 1555 UTOPPY_LONG_TIMEOUT, &resp); 1556 if (err) { 1557 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: " 1558 "utoppy_command(UTOPPY_RESP_FILE_DATA) " 1559 "returned %d\n", device_xname(sc->sc_dev), err)); 1560 break; 1561 } 1562 if (resp != UTOPPY_RESP_SUCCESS) { 1563 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: " 1564 "utoppy_command(UTOPPY_RESP_FILE_DATA) returned " 1565 "bad response 0x%x\n", device_xname(sc->sc_dev), 1566 resp)); 1567 utoppy_cancel(sc); 1568 err = EIO; 1569 break; 1570 } 1571 1572 sc->sc_wr_offset += len; 1573 sc->sc_wr_size -= len; 1574 } 1575 1576 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: POST-WRITEFILE: resid " 1577 "%ld, wr_size %lld, wr_offset %lld, err %d\n", 1578 device_xname(sc->sc_dev), (u_long)uio->uio_resid, sc->sc_wr_size, 1579 sc->sc_wr_offset, err)); 1580 1581 if (err == 0 && sc->sc_wr_size == 0) { 1582 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: sending " 1583 "FILE_END...\n", device_xname(sc->sc_dev))); 1584 UTOPPY_OUT_INIT(sc); 1585 err = utoppy_command(sc, UTOPPY_RESP_FILE_END, 1586 UTOPPY_LONG_TIMEOUT, &resp); 1587 if (err) { 1588 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: " 1589 "utoppy_command(UTOPPY_RESP_FILE_END) returned " 1590 "%d\n", device_xname(sc->sc_dev), err)); 1591 1592 utoppy_cancel(sc); 1593 } 1594 1595 sc->sc_state = UTOPPY_STATE_IDLE; 1596 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: state %s\n", 1597 device_xname(sc->sc_dev), 1598 utoppy_state_string(sc->sc_state))); 1599 } 1600 1601 if (--sc->sc_refcnt < 0) 1602 usb_detach_wakeupold(sc->sc_dev); 1603 1604 return err; 1605 } 1606 1607 int 1608 utoppyioctl(dev_t dev, u_long cmd, void *data, int flag, 1609 struct lwp *l) 1610 { 1611 struct utoppy_softc *sc; 1612 struct utoppy_rename *ur; 1613 struct utoppy_readfile *urf; 1614 struct utoppy_writefile *uw; 1615 char uwf[UTOPPY_MAX_FILENAME_LEN + 1], *uwfp; 1616 uint16_t resp; 1617 int err; 1618 1619 sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev)); 1620 1621 if (sc->sc_dying) 1622 return EIO; 1623 1624 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: cmd 0x%08lx, state '%s'\n", 1625 device_xname(sc->sc_dev), cmd, utoppy_state_string(sc->sc_state))); 1626 1627 if (sc->sc_state != UTOPPY_STATE_IDLE && cmd != UTOPPYIOCANCEL) { 1628 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: still busy.\n", 1629 device_xname(sc->sc_dev))); 1630 return EBUSY; 1631 } 1632 1633 sc->sc_refcnt++; 1634 1635 switch (cmd) { 1636 case UTOPPYIOTURBO: 1637 err = 0; 1638 sc->sc_turbo_mode = *((int *)data) ? 1 : 0; 1639 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOTURBO: " 1640 "%s\n", device_xname(sc->sc_dev), 1641 sc->sc_turbo_mode ? "On" : "Off")); 1642 break; 1643 1644 case UTOPPYIOCANCEL: 1645 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOCANCEL\n", 1646 device_xname(sc->sc_dev))); 1647 err = utoppy_cancel(sc); 1648 break; 1649 1650 case UTOPPYIOREBOOT: 1651 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREBOOT\n", 1652 device_xname(sc->sc_dev))); 1653 UTOPPY_OUT_INIT(sc); 1654 err = utoppy_command(sc, UTOPPY_CMD_RESET, UTOPPY_LONG_TIMEOUT, 1655 &resp); 1656 if (err) 1657 break; 1658 1659 if (resp != UTOPPY_RESP_SUCCESS) 1660 err = EIO; 1661 break; 1662 1663 case UTOPPYIOSTATS: 1664 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOSTATS\n", 1665 device_xname(sc->sc_dev))); 1666 err = utoppy_stats(sc, (struct utoppy_stats *)data); 1667 break; 1668 1669 case UTOPPYIORENAME: 1670 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIORENAME\n", 1671 device_xname(sc->sc_dev))); 1672 ur = (struct utoppy_rename *)data; 1673 UTOPPY_OUT_INIT(sc); 1674 1675 if ((err = utoppy_add_path(sc, ur->ur_old_path, 1)) != 0) 1676 break; 1677 if ((err = utoppy_add_path(sc, ur->ur_new_path, 1)) != 0) 1678 break; 1679 1680 err = utoppy_command(sc, UTOPPY_CMD_RENAME, 1681 UTOPPY_LONG_TIMEOUT, &resp); 1682 if (err) 1683 break; 1684 1685 if (resp != UTOPPY_RESP_SUCCESS) 1686 err = EIO; 1687 break; 1688 1689 case UTOPPYIOMKDIR: 1690 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOMKDIR\n", 1691 device_xname(sc->sc_dev))); 1692 UTOPPY_OUT_INIT(sc); 1693 err = utoppy_add_path(sc, *((const char **)data), 1); 1694 if (err) 1695 break; 1696 1697 err = utoppy_command(sc, UTOPPY_CMD_MKDIR, UTOPPY_LONG_TIMEOUT, 1698 &resp); 1699 if (err) 1700 break; 1701 1702 if (resp != UTOPPY_RESP_SUCCESS) 1703 err = EIO; 1704 break; 1705 1706 case UTOPPYIODELETE: 1707 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIODELETE\n", 1708 device_xname(sc->sc_dev))); 1709 UTOPPY_OUT_INIT(sc); 1710 err = utoppy_add_path(sc, *((const char **)data), 0); 1711 if (err) 1712 break; 1713 1714 err = utoppy_command(sc, UTOPPY_CMD_DELETE, UTOPPY_LONG_TIMEOUT, 1715 &resp); 1716 if (err) 1717 break; 1718 1719 if (resp != UTOPPY_RESP_SUCCESS) 1720 err = EIO; 1721 break; 1722 1723 case UTOPPYIOREADDIR: 1724 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREADDIR\n", 1725 device_xname(sc->sc_dev))); 1726 UTOPPY_OUT_INIT(sc); 1727 err = utoppy_add_path(sc, *((const char **)data), 0); 1728 if (err) { 1729 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: " 1730 "utoppy_add_path() returned %d\n", 1731 device_xname(sc->sc_dev), err)); 1732 break; 1733 } 1734 1735 err = utoppy_send_packet(sc, UTOPPY_CMD_READDIR, 1736 UTOPPY_LONG_TIMEOUT); 1737 if (err != 0) { 1738 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: " 1739 "UTOPPY_CMD_READDIR returned %d\n", 1740 device_xname(sc->sc_dev), err)); 1741 break; 1742 } 1743 1744 err = utoppy_readdir_next(sc); 1745 if (err) { 1746 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: " 1747 "utoppy_readdir_next() returned %d\n", 1748 device_xname(sc->sc_dev), err)); 1749 } 1750 break; 1751 1752 case UTOPPYIOREADFILE: 1753 urf = (struct utoppy_readfile *)data; 1754 1755 DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOREADFILE " 1756 "%s, offset %lld\n", device_xname(sc->sc_dev), 1757 urf->ur_path, urf->ur_offset)); 1758 1759 if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0) 1760 break; 1761 1762 UTOPPY_OUT_INIT(sc); 1763 utoppy_add_8(sc, UTOPPY_FILE_READ); 1764 1765 if ((err = utoppy_add_path(sc, urf->ur_path, 1)) != 0) 1766 break; 1767 1768 utoppy_add_64(sc, urf->ur_offset); 1769 1770 sc->sc_state = UTOPPY_STATE_READFILE; 1771 sc->sc_in_offset = 0; 1772 1773 err = utoppy_send_packet(sc, UTOPPY_CMD_FILE, 1774 UTOPPY_LONG_TIMEOUT); 1775 if (err == 0) 1776 err = utoppy_readfile_next(sc); 1777 break; 1778 1779 case UTOPPYIOWRITEFILE: 1780 uw = (struct utoppy_writefile *)data; 1781 1782 DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOWRITEFILE " 1783 "%s, size %lld, offset %lld\n", device_xname(sc->sc_dev), 1784 uw->uw_path, uw->uw_size, uw->uw_offset)); 1785 1786 if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0) 1787 break; 1788 1789 UTOPPY_OUT_INIT(sc); 1790 utoppy_add_8(sc, UTOPPY_FILE_WRITE); 1791 uwfp = utoppy_current_ptr(sc->sc_out_data); 1792 1793 if ((err = utoppy_add_path(sc, uw->uw_path, 1)) != 0) { 1794 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: add_path()" 1795 " returned %d\n", device_xname(sc->sc_dev), err)); 1796 break; 1797 } 1798 1799 strncpy(uwf, &uwfp[2], sizeof(uwf)); 1800 utoppy_add_64(sc, uw->uw_offset); 1801 1802 err = utoppy_command(sc, UTOPPY_CMD_FILE, UTOPPY_LONG_TIMEOUT, 1803 &resp); 1804 if (err) { 1805 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: " 1806 "utoppy_command(UTOPPY_CMD_FILE) returned " 1807 "%d\n", device_xname(sc->sc_dev), err)); 1808 break; 1809 } 1810 if (resp != UTOPPY_RESP_SUCCESS) { 1811 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: " 1812 "utoppy_command(UTOPPY_CMD_FILE) returned " 1813 "bad response 0x%x\n", device_xname(sc->sc_dev), 1814 resp)); 1815 err = EIO; 1816 break; 1817 } 1818 1819 UTOPPY_OUT_INIT(sc); 1820 utoppy_timestamp_encode(sc, uw->uw_mtime); 1821 utoppy_add_8(sc, UTOPPY_FTYPE_FILE); 1822 utoppy_add_64(sc, uw->uw_size); 1823 utoppy_add_string(sc, uwf, sizeof(uwf)); 1824 utoppy_add_32(sc, 0); 1825 1826 err = utoppy_command(sc, UTOPPY_RESP_FILE_HEADER, 1827 UTOPPY_LONG_TIMEOUT, &resp); 1828 if (err) { 1829 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: " 1830 "utoppy_command(UTOPPY_RESP_FILE_HEADER) " 1831 "returned %d\n", device_xname(sc->sc_dev), err)); 1832 break; 1833 } 1834 if (resp != UTOPPY_RESP_SUCCESS) { 1835 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: " 1836 "utoppy_command(UTOPPY_RESP_FILE_HEADER) " 1837 "returned bad response 0x%x\n", 1838 device_xname(sc->sc_dev), resp)); 1839 err = EIO; 1840 break; 1841 } 1842 1843 sc->sc_wr_offset = uw->uw_offset; 1844 sc->sc_wr_size = uw->uw_size; 1845 sc->sc_state = UTOPPY_STATE_WRITEFILE; 1846 1847 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: Changing state to " 1848 "%s. wr_offset %lld, wr_size %lld\n", 1849 device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state), 1850 sc->sc_wr_offset, sc->sc_wr_size)); 1851 break; 1852 1853 default: 1854 DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: Invalid cmd\n", 1855 device_xname(sc->sc_dev))); 1856 err = ENODEV; 1857 break; 1858 } 1859 1860 DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: done. err %d, state '%s'\n", 1861 device_xname(sc->sc_dev), err, utoppy_state_string(sc->sc_state))); 1862 1863 if (err) 1864 utoppy_cancel(sc); 1865 1866 if (--sc->sc_refcnt < 0) 1867 usb_detach_wakeupold(sc->sc_dev); 1868 1869 return err; 1870 } 1871