| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: ISC |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2011 Broadcom Corporation |
|---|
| 3 | | - * |
|---|
| 4 | | - * Permission to use, copy, modify, and/or distribute this software for any |
|---|
| 5 | | - * purpose with or without fee is hereby granted, provided that the above |
|---|
| 6 | | - * copyright notice and this permission notice appear in all copies. |
|---|
| 7 | | - * |
|---|
| 8 | | - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|---|
| 9 | | - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|---|
| 10 | | - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|---|
| 11 | | - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|---|
| 12 | | - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|---|
| 13 | | - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|---|
| 14 | | - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|---|
| 15 | 4 | */ |
|---|
| 16 | 5 | |
|---|
| 17 | 6 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 175 | 164 | |
|---|
| 176 | 165 | struct urb *bulk_urb; /* used for FW download */ |
|---|
| 177 | 166 | |
|---|
| 178 | | - bool wowl_enabled; |
|---|
| 179 | 167 | struct brcmf_mp_device *settings; |
|---|
| 180 | 168 | }; |
|---|
| 181 | 169 | |
|---|
| .. | .. |
|---|
| 323 | 311 | int err = 0; |
|---|
| 324 | 312 | int timeout = 0; |
|---|
| 325 | 313 | struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); |
|---|
| 314 | + struct usb_interface *intf = to_usb_interface(dev); |
|---|
| 326 | 315 | |
|---|
| 327 | 316 | brcmf_dbg(USB, "Enter\n"); |
|---|
| 328 | | - if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) |
|---|
| 329 | | - return -EIO; |
|---|
| 330 | 317 | |
|---|
| 331 | | - if (test_and_set_bit(0, &devinfo->ctl_op)) |
|---|
| 332 | | - return -EIO; |
|---|
| 318 | + err = usb_autopm_get_interface(intf); |
|---|
| 319 | + if (err) |
|---|
| 320 | + goto out; |
|---|
| 321 | + |
|---|
| 322 | + if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) { |
|---|
| 323 | + err = -EIO; |
|---|
| 324 | + goto fail; |
|---|
| 325 | + } |
|---|
| 326 | + |
|---|
| 327 | + if (test_and_set_bit(0, &devinfo->ctl_op)) { |
|---|
| 328 | + err = -EIO; |
|---|
| 329 | + goto fail; |
|---|
| 330 | + } |
|---|
| 333 | 331 | |
|---|
| 334 | 332 | devinfo->ctl_completed = false; |
|---|
| 335 | 333 | err = brcmf_usb_send_ctl(devinfo, buf, len); |
|---|
| 336 | 334 | if (err) { |
|---|
| 337 | 335 | brcmf_err("fail %d bytes: %d\n", err, len); |
|---|
| 338 | 336 | clear_bit(0, &devinfo->ctl_op); |
|---|
| 339 | | - return err; |
|---|
| 337 | + goto fail; |
|---|
| 340 | 338 | } |
|---|
| 341 | 339 | timeout = brcmf_usb_ioctl_resp_wait(devinfo); |
|---|
| 342 | | - clear_bit(0, &devinfo->ctl_op); |
|---|
| 343 | 340 | if (!timeout) { |
|---|
| 344 | 341 | brcmf_err("Txctl wait timed out\n"); |
|---|
| 342 | + usb_kill_urb(devinfo->ctl_urb); |
|---|
| 345 | 343 | err = -EIO; |
|---|
| 344 | + goto fail; |
|---|
| 346 | 345 | } |
|---|
| 346 | + clear_bit(0, &devinfo->ctl_op); |
|---|
| 347 | + |
|---|
| 348 | +fail: |
|---|
| 349 | + usb_autopm_put_interface(intf); |
|---|
| 350 | +out: |
|---|
| 347 | 351 | return err; |
|---|
| 348 | 352 | } |
|---|
| 349 | 353 | |
|---|
| .. | .. |
|---|
| 352 | 356 | int err = 0; |
|---|
| 353 | 357 | int timeout = 0; |
|---|
| 354 | 358 | struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); |
|---|
| 359 | + struct usb_interface *intf = to_usb_interface(dev); |
|---|
| 355 | 360 | |
|---|
| 356 | 361 | brcmf_dbg(USB, "Enter\n"); |
|---|
| 357 | | - if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) |
|---|
| 358 | | - return -EIO; |
|---|
| 359 | 362 | |
|---|
| 360 | | - if (test_and_set_bit(0, &devinfo->ctl_op)) |
|---|
| 361 | | - return -EIO; |
|---|
| 363 | + err = usb_autopm_get_interface(intf); |
|---|
| 364 | + if (err) |
|---|
| 365 | + goto out; |
|---|
| 366 | + |
|---|
| 367 | + if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) { |
|---|
| 368 | + err = -EIO; |
|---|
| 369 | + goto fail; |
|---|
| 370 | + } |
|---|
| 371 | + |
|---|
| 372 | + if (test_and_set_bit(0, &devinfo->ctl_op)) { |
|---|
| 373 | + err = -EIO; |
|---|
| 374 | + goto fail; |
|---|
| 375 | + } |
|---|
| 362 | 376 | |
|---|
| 363 | 377 | devinfo->ctl_completed = false; |
|---|
| 364 | 378 | err = brcmf_usb_recv_ctl(devinfo, buf, len); |
|---|
| 365 | 379 | if (err) { |
|---|
| 366 | 380 | brcmf_err("fail %d bytes: %d\n", err, len); |
|---|
| 367 | 381 | clear_bit(0, &devinfo->ctl_op); |
|---|
| 368 | | - return err; |
|---|
| 382 | + goto fail; |
|---|
| 369 | 383 | } |
|---|
| 370 | 384 | timeout = brcmf_usb_ioctl_resp_wait(devinfo); |
|---|
| 371 | 385 | err = devinfo->ctl_urb_status; |
|---|
| 372 | | - clear_bit(0, &devinfo->ctl_op); |
|---|
| 373 | 386 | if (!timeout) { |
|---|
| 374 | 387 | brcmf_err("rxctl wait timed out\n"); |
|---|
| 388 | + usb_kill_urb(devinfo->ctl_urb); |
|---|
| 375 | 389 | err = -EIO; |
|---|
| 390 | + goto fail; |
|---|
| 376 | 391 | } |
|---|
| 392 | + clear_bit(0, &devinfo->ctl_op); |
|---|
| 393 | +fail: |
|---|
| 394 | + usb_autopm_put_interface(intf); |
|---|
| 377 | 395 | if (!err) |
|---|
| 378 | 396 | return devinfo->ctl_urb_actual_length; |
|---|
| 379 | | - else |
|---|
| 380 | | - return err; |
|---|
| 397 | +out: |
|---|
| 398 | + return err; |
|---|
| 381 | 399 | } |
|---|
| 382 | 400 | |
|---|
| 383 | 401 | static struct brcmf_usbreq *brcmf_usb_deq(struct brcmf_usbdev_info *devinfo, |
|---|
| .. | .. |
|---|
| 446 | 464 | |
|---|
| 447 | 465 | } |
|---|
| 448 | 466 | |
|---|
| 449 | | -static void brcmf_usb_free_q(struct list_head *q, bool pending) |
|---|
| 467 | +static void brcmf_usb_free_q(struct list_head *q) |
|---|
| 450 | 468 | { |
|---|
| 451 | 469 | struct brcmf_usbreq *req, *next; |
|---|
| 452 | | - int i = 0; |
|---|
| 470 | + |
|---|
| 453 | 471 | list_for_each_entry_safe(req, next, q, list) { |
|---|
| 454 | 472 | if (!req->urb) { |
|---|
| 455 | 473 | brcmf_err("bad req\n"); |
|---|
| 456 | 474 | break; |
|---|
| 457 | 475 | } |
|---|
| 458 | | - i++; |
|---|
| 459 | | - if (pending) { |
|---|
| 460 | | - usb_kill_urb(req->urb); |
|---|
| 461 | | - } else { |
|---|
| 462 | | - usb_free_urb(req->urb); |
|---|
| 463 | | - list_del_init(&req->list); |
|---|
| 464 | | - } |
|---|
| 476 | + usb_free_urb(req->urb); |
|---|
| 477 | + list_del_init(&req->list); |
|---|
| 465 | 478 | } |
|---|
| 466 | 479 | } |
|---|
| 467 | 480 | |
|---|
| .. | .. |
|---|
| 509 | 522 | skb = req->skb; |
|---|
| 510 | 523 | req->skb = NULL; |
|---|
| 511 | 524 | |
|---|
| 512 | | - /* zero lenght packets indicate usb "failure". Do not refill */ |
|---|
| 525 | + /* zero length packets indicate usb "failure". Do not refill */ |
|---|
| 513 | 526 | if (urb->status != 0 || !urb->actual_length) { |
|---|
| 514 | 527 | brcmu_pkt_buf_free_skb(skb); |
|---|
| 515 | 528 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); |
|---|
| 516 | 529 | return; |
|---|
| 517 | 530 | } |
|---|
| 518 | 531 | |
|---|
| 519 | | - if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) { |
|---|
| 532 | + if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP || |
|---|
| 533 | + devinfo->bus_pub.state == BRCMFMAC_USB_STATE_SLEEP) { |
|---|
| 520 | 534 | skb_put(skb, urb->actual_length); |
|---|
| 521 | | - brcmf_rx_frame(devinfo->dev, skb, true); |
|---|
| 535 | + brcmf_rx_frame(devinfo->dev, skb, true, true); |
|---|
| 522 | 536 | brcmf_usb_rx_refill(devinfo, req); |
|---|
| 537 | + usb_mark_last_busy(urb->dev); |
|---|
| 523 | 538 | } else { |
|---|
| 524 | 539 | brcmu_pkt_buf_free_skb(skb); |
|---|
| 525 | 540 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); |
|---|
| .. | .. |
|---|
| 576 | 591 | brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state) |
|---|
| 577 | 592 | { |
|---|
| 578 | 593 | struct brcmf_bus *bcmf_bus = devinfo->bus_pub.bus; |
|---|
| 579 | | - int old_state; |
|---|
| 580 | 594 | |
|---|
| 581 | 595 | brcmf_dbg(USB, "Enter, current state=%d, new state=%d\n", |
|---|
| 582 | 596 | devinfo->bus_pub.state, state); |
|---|
| .. | .. |
|---|
| 584 | 598 | if (devinfo->bus_pub.state == state) |
|---|
| 585 | 599 | return; |
|---|
| 586 | 600 | |
|---|
| 587 | | - old_state = devinfo->bus_pub.state; |
|---|
| 588 | 601 | devinfo->bus_pub.state = state; |
|---|
| 589 | 602 | |
|---|
| 590 | 603 | /* update state of upper layer */ |
|---|
| .. | .. |
|---|
| 605 | 618 | struct brcmf_usbreq *req; |
|---|
| 606 | 619 | int ret; |
|---|
| 607 | 620 | unsigned long flags; |
|---|
| 621 | + struct usb_interface *intf = to_usb_interface(dev); |
|---|
| 622 | + |
|---|
| 623 | + ret = usb_autopm_get_interface(intf); |
|---|
| 624 | + if (ret) |
|---|
| 625 | + goto out; |
|---|
| 608 | 626 | |
|---|
| 609 | 627 | brcmf_dbg(USB, "Enter, skb=%p\n", skb); |
|---|
| 610 | 628 | if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) { |
|---|
| .. | .. |
|---|
| 643 | 661 | devinfo->tx_flowblock = true; |
|---|
| 644 | 662 | } |
|---|
| 645 | 663 | spin_unlock_irqrestore(&devinfo->tx_flowblock_lock, flags); |
|---|
| 646 | | - return 0; |
|---|
| 647 | 664 | |
|---|
| 648 | 665 | fail: |
|---|
| 666 | + usb_autopm_put_interface(intf); |
|---|
| 667 | +out: |
|---|
| 649 | 668 | return ret; |
|---|
| 650 | 669 | } |
|---|
| 651 | 670 | |
|---|
| .. | .. |
|---|
| 1009 | 1028 | brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo) |
|---|
| 1010 | 1029 | { |
|---|
| 1011 | 1030 | int err; |
|---|
| 1031 | + struct usb_interface *intf; |
|---|
| 1012 | 1032 | |
|---|
| 1013 | 1033 | brcmf_dbg(USB, "Enter\n"); |
|---|
| 1014 | | - if (devinfo == NULL) |
|---|
| 1015 | | - return -ENODEV; |
|---|
| 1034 | + if (!devinfo) { |
|---|
| 1035 | + err = -ENODEV; |
|---|
| 1036 | + goto out; |
|---|
| 1037 | + } |
|---|
| 1016 | 1038 | |
|---|
| 1017 | 1039 | if (!devinfo->image) { |
|---|
| 1018 | 1040 | brcmf_err("No firmware!\n"); |
|---|
| 1019 | | - return -ENOENT; |
|---|
| 1041 | + err = -ENOENT; |
|---|
| 1042 | + goto out; |
|---|
| 1020 | 1043 | } |
|---|
| 1044 | + |
|---|
| 1045 | + intf = to_usb_interface(devinfo->dev); |
|---|
| 1046 | + err = usb_autopm_get_interface(intf); |
|---|
| 1047 | + if (err) |
|---|
| 1048 | + goto out; |
|---|
| 1021 | 1049 | |
|---|
| 1022 | 1050 | err = brcmf_usb_dlstart(devinfo, |
|---|
| 1023 | 1051 | (u8 *)devinfo->image, devinfo->image_len); |
|---|
| 1024 | 1052 | if (err == 0) |
|---|
| 1025 | 1053 | err = brcmf_usb_dlrun(devinfo); |
|---|
| 1054 | + |
|---|
| 1055 | + usb_autopm_put_interface(intf); |
|---|
| 1056 | +out: |
|---|
| 1026 | 1057 | return err; |
|---|
| 1027 | 1058 | } |
|---|
| 1028 | 1059 | |
|---|
| .. | .. |
|---|
| 1032 | 1063 | brcmf_dbg(USB, "Enter, devinfo %p\n", devinfo); |
|---|
| 1033 | 1064 | |
|---|
| 1034 | 1065 | /* free the URBS */ |
|---|
| 1035 | | - brcmf_usb_free_q(&devinfo->rx_freeq, false); |
|---|
| 1036 | | - brcmf_usb_free_q(&devinfo->tx_freeq, false); |
|---|
| 1066 | + brcmf_usb_free_q(&devinfo->rx_freeq); |
|---|
| 1067 | + brcmf_usb_free_q(&devinfo->tx_freeq); |
|---|
| 1037 | 1068 | |
|---|
| 1038 | 1069 | usb_free_urb(devinfo->ctl_urb); |
|---|
| 1039 | 1070 | usb_free_urb(devinfo->bulk_urb); |
|---|
| .. | .. |
|---|
| 1123 | 1154 | return NULL; |
|---|
| 1124 | 1155 | } |
|---|
| 1125 | 1156 | |
|---|
| 1126 | | -static void brcmf_usb_wowl_config(struct device *dev, bool enabled) |
|---|
| 1127 | | -{ |
|---|
| 1128 | | - struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); |
|---|
| 1129 | | - |
|---|
| 1130 | | - brcmf_dbg(USB, "Configuring WOWL, enabled=%d\n", enabled); |
|---|
| 1131 | | - devinfo->wowl_enabled = enabled; |
|---|
| 1132 | | - if (enabled) |
|---|
| 1133 | | - device_set_wakeup_enable(devinfo->dev, true); |
|---|
| 1134 | | - else |
|---|
| 1135 | | - device_set_wakeup_enable(devinfo->dev, false); |
|---|
| 1136 | | -} |
|---|
| 1137 | | - |
|---|
| 1138 | 1157 | static |
|---|
| 1139 | 1158 | int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name) |
|---|
| 1140 | 1159 | { |
|---|
| .. | .. |
|---|
| 1161 | 1180 | .txdata = brcmf_usb_tx, |
|---|
| 1162 | 1181 | .txctl = brcmf_usb_tx_ctlpkt, |
|---|
| 1163 | 1182 | .rxctl = brcmf_usb_rx_ctlpkt, |
|---|
| 1164 | | - .wowl_config = brcmf_usb_wowl_config, |
|---|
| 1165 | 1183 | .get_fwname = brcmf_usb_get_fwname, |
|---|
| 1166 | 1184 | }; |
|---|
| 1167 | 1185 | |
|---|
| .. | .. |
|---|
| 1197 | 1215 | if (ret) |
|---|
| 1198 | 1216 | goto error; |
|---|
| 1199 | 1217 | |
|---|
| 1218 | + ret = brcmf_alloc(devinfo->dev, devinfo->settings); |
|---|
| 1219 | + if (ret) |
|---|
| 1220 | + goto error; |
|---|
| 1221 | + |
|---|
| 1200 | 1222 | /* Attach to the common driver interface */ |
|---|
| 1201 | | - ret = brcmf_attach(devinfo->dev, devinfo->settings); |
|---|
| 1223 | + ret = brcmf_attach(devinfo->dev); |
|---|
| 1202 | 1224 | if (ret) |
|---|
| 1203 | 1225 | goto error; |
|---|
| 1204 | 1226 | |
|---|
| .. | .. |
|---|
| 1270 | 1292 | } |
|---|
| 1271 | 1293 | |
|---|
| 1272 | 1294 | if (!brcmf_usb_dlneeded(devinfo)) { |
|---|
| 1273 | | - ret = brcmf_attach(devinfo->dev, devinfo->settings); |
|---|
| 1295 | + ret = brcmf_alloc(devinfo->dev, devinfo->settings); |
|---|
| 1296 | + if (ret) |
|---|
| 1297 | + goto fail; |
|---|
| 1298 | + ret = brcmf_attach(devinfo->dev); |
|---|
| 1274 | 1299 | if (ret) |
|---|
| 1275 | 1300 | goto fail; |
|---|
| 1276 | 1301 | /* we are done */ |
|---|
| .. | .. |
|---|
| 1298 | 1323 | |
|---|
| 1299 | 1324 | fail: |
|---|
| 1300 | 1325 | /* Release resources in reverse order */ |
|---|
| 1326 | + brcmf_free(devinfo->dev); |
|---|
| 1301 | 1327 | kfree(bus); |
|---|
| 1302 | 1328 | brcmf_usb_detach(devinfo); |
|---|
| 1303 | 1329 | return ret; |
|---|
| .. | .. |
|---|
| 1311 | 1337 | brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo); |
|---|
| 1312 | 1338 | |
|---|
| 1313 | 1339 | brcmf_detach(devinfo->dev); |
|---|
| 1340 | + brcmf_free(devinfo->dev); |
|---|
| 1314 | 1341 | kfree(devinfo->bus_pub.bus); |
|---|
| 1315 | 1342 | brcmf_usb_detach(devinfo); |
|---|
| 1316 | 1343 | } |
|---|
| .. | .. |
|---|
| 1340 | 1367 | init_completion(&devinfo->dev_init_done); |
|---|
| 1341 | 1368 | |
|---|
| 1342 | 1369 | usb_set_intfdata(intf, devinfo); |
|---|
| 1370 | + |
|---|
| 1371 | + intf->needs_remote_wakeup = 1; |
|---|
| 1343 | 1372 | |
|---|
| 1344 | 1373 | /* Check that the device supports only one configuration */ |
|---|
| 1345 | 1374 | if (usb->descriptor.bNumConfigurations != 1) { |
|---|
| .. | .. |
|---|
| 1454 | 1483 | |
|---|
| 1455 | 1484 | brcmf_dbg(USB, "Enter\n"); |
|---|
| 1456 | 1485 | devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP; |
|---|
| 1457 | | - if (devinfo->wowl_enabled) |
|---|
| 1458 | | - brcmf_cancel_all_urbs(devinfo); |
|---|
| 1459 | | - else |
|---|
| 1460 | | - brcmf_detach(&usb->dev); |
|---|
| 1486 | + brcmf_cancel_all_urbs(devinfo); |
|---|
| 1487 | + device_set_wakeup_enable(devinfo->dev, true); |
|---|
| 1461 | 1488 | return 0; |
|---|
| 1462 | 1489 | } |
|---|
| 1463 | 1490 | |
|---|
| .. | .. |
|---|
| 1470 | 1497 | struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); |
|---|
| 1471 | 1498 | |
|---|
| 1472 | 1499 | brcmf_dbg(USB, "Enter\n"); |
|---|
| 1473 | | - if (!devinfo->wowl_enabled) |
|---|
| 1474 | | - return brcmf_attach(devinfo->dev, devinfo->settings); |
|---|
| 1475 | 1500 | |
|---|
| 1476 | 1501 | devinfo->bus_pub.state = BRCMFMAC_USB_STATE_UP; |
|---|
| 1477 | 1502 | brcmf_usb_rx_fill_all(devinfo); |
|---|
| 1503 | + device_set_wakeup_enable(devinfo->dev, false); |
|---|
| 1478 | 1504 | return 0; |
|---|
| 1479 | 1505 | } |
|---|
| 1480 | 1506 | |
|---|
| .. | .. |
|---|
| 1531 | 1557 | .suspend = brcmf_usb_suspend, |
|---|
| 1532 | 1558 | .resume = brcmf_usb_resume, |
|---|
| 1533 | 1559 | .reset_resume = brcmf_usb_reset_resume, |
|---|
| 1560 | + .supports_autosuspend = true, |
|---|
| 1534 | 1561 | .disable_hub_initiated_lpm = 1, |
|---|
| 1535 | 1562 | }; |
|---|
| 1536 | 1563 | |
|---|
| .. | .. |
|---|
| 1551 | 1578 | brcmf_dbg(USB, "Enter\n"); |
|---|
| 1552 | 1579 | ret = driver_for_each_device(drv, NULL, NULL, |
|---|
| 1553 | 1580 | brcmf_usb_reset_device); |
|---|
| 1581 | + if (ret) |
|---|
| 1582 | + brcmf_err("failed to reset all usb devices %d\n", ret); |
|---|
| 1583 | + |
|---|
| 1554 | 1584 | usb_deregister(&brcmf_usbdrvr); |
|---|
| 1555 | 1585 | } |
|---|
| 1556 | 1586 | |
|---|
| 1557 | | -void brcmf_usb_register(void) |
|---|
| 1587 | +int brcmf_usb_register(void) |
|---|
| 1558 | 1588 | { |
|---|
| 1559 | 1589 | brcmf_dbg(USB, "Enter\n"); |
|---|
| 1560 | | - usb_register(&brcmf_usbdrvr); |
|---|
| 1590 | + return usb_register(&brcmf_usbdrvr); |
|---|
| 1561 | 1591 | } |
|---|