1 /* $NetBSD: vcprop_subr.c,v 1.10 2021/03/08 13:53:08 mlelstv Exp $ */ 2 3 /* 4 * Copyright (c) 2014 Michael Lorenz 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * Mailbox property interface wrapper functions 30 */ 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: vcprop_subr.c,v 1.10 2021/03/08 13:53:08 mlelstv Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/bus.h> 36 #include <sys/device.h> 37 #include <sys/endian.h> 38 39 #include <uvm/uvm_extern.h> 40 41 #include <arm/broadcom/bcm2835reg.h> 42 #include <arm/broadcom/bcm2835var.h> 43 #include <arm/broadcom/bcm2835_mbox.h> 44 45 #include <evbarm/rpi/vcio.h> 46 #include <evbarm/rpi/vcpm.h> 47 #include <evbarm/rpi/vcprop.h> 48 49 #include <dev/wscons/wsconsio.h> 50 51 int 52 rpi_fb_set_video(int b) 53 { 54 int error; 55 uint32_t res; 56 57 /* 58 * might as well put it here since we need to re-init it every time 59 * and it's not like this is going to be called very often anyway 60 */ 61 struct __aligned(16) { 62 struct vcprop_buffer_hdr vb_hdr; 63 struct vcprop_tag_blankscreen vbt_blank; 64 struct vcprop_tag end; 65 } vb_setblank = 66 { 67 .vb_hdr = { 68 .vpb_len = htole32(sizeof(vb_setblank)), 69 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST), 70 }, 71 .vbt_blank = { 72 .tag = { 73 .vpt_tag = htole32(VCPROPTAG_BLANK_SCREEN), 74 .vpt_len = htole32(VCPROPTAG_LEN( 75 vb_setblank.vbt_blank)), 76 .vpt_rcode = htole32(VCPROPTAG_REQUEST), 77 }, 78 .state = htole32((b != 0) ? 79 VCPROP_BLANK_OFF : VCPROP_BLANK_ON), 80 }, 81 .end = { 82 .vpt_tag = htole32(VCPROPTAG_NULL), 83 }, 84 }; 85 86 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_setblank, 87 sizeof(vb_setblank), &res); 88 #ifdef RPI_IOCTL_DEBUG 89 printf("%s: %d %d %d %08x %08x\n", __func__, b, 90 le32toh(vb_setblank.vbt_blank.state), error, res, 91 le32toh(vb_setblank.vbt_blank.tag.vpt_rcode)); 92 #endif 93 if (error) 94 return error; 95 96 if (!vcprop_buffer_success_p(&vb_setblank.vb_hdr) || 97 !vcprop_tag_success_p(&vb_setblank.vbt_blank.tag)) { 98 return EIO; 99 } 100 101 return 0; 102 } 103 104 uint32_t 105 rpi_alloc_mem(uint32_t size, uint32_t align, uint32_t flags) 106 { 107 int error; 108 uint32_t res; 109 110 struct __aligned(16) { 111 struct vcprop_buffer_hdr vb_hdr; 112 struct vcprop_tag_allocmem vbt_am; 113 struct vcprop_tag end; 114 } vb_allocmem = 115 { 116 .vb_hdr = { 117 .vpb_len = htole32(sizeof(vb_allocmem)), 118 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST), 119 }, 120 .vbt_am = { 121 .tag = { 122 .vpt_tag = htole32(VCPROPTAG_ALLOCMEM), 123 .vpt_len = 124 htole32(VCPROPTAG_LEN(vb_allocmem.vbt_am)), 125 .vpt_rcode = htole32(VCPROPTAG_REQUEST), 126 }, 127 .size = htole32(size), 128 .align = htole32(align), 129 .flags = htole32(flags), 130 }, 131 .end = { 132 .vpt_tag = htole32(VCPROPTAG_NULL), 133 }, 134 }; 135 136 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_allocmem, 137 sizeof(vb_allocmem), &res); 138 #ifdef RPI_IOCTL_DEBUG 139 printf("%s: %d %d %08x %08x\n", __func__, 140 le32toh(vb_allocmem.vbt_am.size), error, res, 141 le32toh(vb_allocmem.vbt_am.tag.vpt_rcode)); 142 #endif 143 if (error) 144 return error; 145 146 if (!vcprop_buffer_success_p(&vb_allocmem.vb_hdr) || 147 !vcprop_tag_success_p(&vb_allocmem.vbt_am.tag)) { 148 return EIO; 149 } 150 151 /* Return the handle from the VC */ 152 return le32toh(vb_allocmem.vbt_am.size); 153 } 154 155 bus_addr_t 156 rpi_lock_mem(uint32_t handle) 157 { 158 int error; 159 uint32_t res; 160 161 struct __aligned(16) { 162 struct vcprop_buffer_hdr vb_hdr; 163 struct vcprop_tag_lockmem vbt_lm; 164 struct vcprop_tag end; 165 } vb_lockmem = 166 { 167 .vb_hdr = { 168 .vpb_len = htole32(sizeof(vb_lockmem)), 169 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST), 170 }, 171 .vbt_lm = { 172 .tag = { 173 .vpt_tag = htole32(VCPROPTAG_LOCKMEM), 174 .vpt_len = 175 htole32(VCPROPTAG_LEN(vb_lockmem.vbt_lm)), 176 .vpt_rcode = htole32(VCPROPTAG_REQUEST), 177 }, 178 .handle = htole32(handle), 179 }, 180 .end = { 181 .vpt_tag = htole32(VCPROPTAG_NULL), 182 }, 183 }; 184 185 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_lockmem, 186 sizeof(vb_lockmem), &res); 187 #ifdef RPI_IOCTL_DEBUG 188 printf("%s: %d %d %08x %08x\n", __func__, 189 le32toh(vb_lockmem.vbt_lm.handle), error, res, 190 le32toh(vb_lockmem.vbt_lm.tag.vpt_rcode)); 191 #endif 192 if (error) 193 return 0; 194 195 if (!vcprop_buffer_success_p(&vb_lockmem.vb_hdr) || 196 !vcprop_tag_success_p(&vb_lockmem.vbt_lm.tag)) { 197 return 0; 198 } 199 200 return le32toh(vb_lockmem.vbt_lm.handle); 201 } 202 203 int 204 rpi_unlock_mem(uint32_t handle) 205 { 206 int error; 207 uint32_t res; 208 209 struct __aligned(16) { 210 struct vcprop_buffer_hdr vb_hdr; 211 struct vcprop_tag_lockmem vbt_lm; 212 struct vcprop_tag end; 213 } vb_unlockmem = 214 { 215 .vb_hdr = { 216 .vpb_len = htole32(sizeof(vb_unlockmem)), 217 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST), 218 }, 219 .vbt_lm = { 220 .tag = { 221 .vpt_tag = htole32(VCPROPTAG_UNLOCKMEM), 222 .vpt_len = 223 htole32(VCPROPTAG_LEN(vb_unlockmem.vbt_lm)), 224 .vpt_rcode = htole32(VCPROPTAG_REQUEST), 225 }, 226 .handle = htole32(handle), 227 }, 228 .end = { 229 .vpt_tag = htole32(VCPROPTAG_NULL), 230 }, 231 }; 232 233 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_unlockmem, 234 sizeof(vb_unlockmem), &res); 235 #ifdef RPI_IOCTL_DEBUG 236 printf("%s: %d %d %08x %08x\n", __func__, 237 le32toh(vb_unlockmem.vbt_lm.handle), error, res, 238 le32toh(vb_unlockmem.vbt_lm.tag.vpt_rcode)); 239 #endif 240 if (error) 241 return error; 242 243 if (!vcprop_buffer_success_p(&vb_unlockmem.vb_hdr) || 244 !vcprop_tag_success_p(&vb_unlockmem.vbt_lm.tag)) { 245 return EIO; 246 } 247 248 return 0; 249 } 250 251 int 252 rpi_release_mem(uint32_t handle) 253 { 254 int error; 255 uint32_t res; 256 257 struct __aligned(16) { 258 struct vcprop_buffer_hdr vb_hdr; 259 struct vcprop_tag_lockmem vbt_lm; 260 struct vcprop_tag end; 261 } vb_releasemem = 262 { 263 .vb_hdr = { 264 .vpb_len = htole32(sizeof(vb_releasemem)), 265 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST), 266 }, 267 .vbt_lm = { 268 .tag = { 269 .vpt_tag = htole32(VCPROPTAG_RELEASEMEM), 270 .vpt_len = htole32(VCPROPTAG_LEN( 271 vb_releasemem.vbt_lm)), 272 .vpt_rcode = htole32(VCPROPTAG_REQUEST), 273 }, 274 .handle = htole32(handle), 275 }, 276 .end = { 277 .vpt_tag = htole32(VCPROPTAG_NULL), 278 }, 279 }; 280 281 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_releasemem, 282 sizeof(vb_releasemem), &res); 283 #ifdef RPI_IOCTL_DEBUG 284 printf("%s: %d %d %08x %08x\n", __func__, 285 le32toh(vb_releasemem.vbt_lm.handle), error, res, 286 le32toh(vb_releasemem.vbt_lm.tag.vpt_rcode)); 287 #endif 288 if (error) 289 return error; 290 291 if (!vcprop_buffer_success_p(&vb_releasemem.vb_hdr) || 292 !vcprop_tag_success_p(&vb_releasemem.vbt_lm.tag)) { 293 return EIO; 294 } 295 296 return 0; 297 } 298 299 int 300 rpi_fb_movecursor(int x, int y, int on) 301 { 302 int error; 303 uint32_t res; 304 305 struct __aligned(16) { 306 struct vcprop_buffer_hdr vb_hdr; 307 struct vcprop_tag_cursorstate vbt_cs; 308 struct vcprop_tag end; 309 } vb_cursorstate = 310 { 311 .vb_hdr = { 312 .vpb_len = htole32(sizeof(vb_cursorstate)), 313 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST), 314 }, 315 .vbt_cs = { 316 .tag = { 317 .vpt_tag = htole32(VCPROPTAG_SET_CURSOR_STATE), 318 .vpt_len = htole32(VCPROPTAG_LEN( 319 vb_cursorstate.vbt_cs)), 320 .vpt_rcode = htole32(VCPROPTAG_REQUEST), 321 }, 322 .enable = htole32((on != 0) ? 1 : 0), 323 .x = htole32(x), 324 .y = htole32(y), 325 .flags = htole32(1), 326 }, 327 .end = { 328 .vpt_tag = htole32(VCPROPTAG_NULL), 329 }, 330 }; 331 332 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_cursorstate, 333 sizeof(vb_cursorstate), &res); 334 #ifdef RPI_IOCTL_DEBUG 335 printf("%s: %08x %d %08x %08x\n", __func__, 336 le32toh(vb_cursorstate.vbt_cs.enable), error, res, 337 le32toh(vb_cursorstate.vbt_cs.tag.vpt_rcode)); 338 #endif 339 if (error) 340 return error; 341 342 if (!vcprop_buffer_success_p(&vb_cursorstate.vb_hdr) || 343 !vcprop_tag_success_p(&vb_cursorstate.vbt_cs.tag)) { 344 return EIO; 345 } 346 347 return 0; 348 } 349 350 int 351 rpi_fb_initcursor(bus_addr_t pixels, int hx, int hy) 352 { 353 int error; 354 uint32_t res; 355 356 357 struct __aligned(16) { 358 struct vcprop_buffer_hdr vb_hdr; 359 struct vcprop_tag_cursorinfo vbt_ci; 360 struct vcprop_tag end; 361 } vb_cursorinfo = 362 { 363 .vb_hdr = { 364 .vpb_len = htole32(sizeof(vb_cursorinfo)), 365 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST), 366 }, 367 .vbt_ci = { 368 .tag = { 369 .vpt_tag = htole32(VCPROPTAG_SET_CURSOR_INFO), 370 .vpt_len = htole32(VCPROPTAG_LEN( 371 vb_cursorinfo.vbt_ci)), 372 .vpt_rcode = htole32(VCPROPTAG_REQUEST), 373 }, 374 .width = htole32(64), 375 .height = htole32(64), 376 .format = htole32(0), 377 .pixels = htole32(pixels), 378 .hotspot_x = htole32(hx), 379 .hotspot_y = htole32(hy), 380 }, 381 .end = { 382 .vpt_tag = htole32(VCPROPTAG_NULL), 383 }, 384 }; 385 386 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_cursorinfo, 387 sizeof(vb_cursorinfo), &res); 388 #ifdef RPI_IOCTL_DEBUG 389 printf("%s: %d %d %08x %08x\n", __func__, 390 le32toh(vb_cursorinfo.vbt_ci.width), error, res, 391 le32toh(vb_cursorinfo.vbt_ci.tag.vpt_rcode)); 392 #endif 393 if (error) 394 return error; 395 396 if (!vcprop_buffer_success_p(&vb_cursorinfo.vb_hdr) || 397 !vcprop_tag_success_p(&vb_cursorinfo.vbt_ci.tag)) { 398 return EIO; 399 } 400 401 return 0; 402 } 403 404 int 405 rpi_fb_get_pixelorder(uint32_t *orderp) 406 { 407 int error; 408 uint32_t res; 409 410 411 struct __aligned(16) { 412 struct vcprop_buffer_hdr vb_hdr; 413 struct vcprop_tag_fbpixelorder vbt_po; 414 struct vcprop_tag end; 415 } vb_pixelorder = 416 { 417 .vb_hdr = { 418 .vpb_len = htole32(sizeof(vb_pixelorder)), 419 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST), 420 }, 421 .vbt_po = { 422 .tag = { 423 .vpt_tag = htole32(VCPROPTAG_GET_FB_PIXEL_ORDER), 424 .vpt_len = htole32(VCPROPTAG_LEN( 425 vb_pixelorder.vbt_po)), 426 .vpt_rcode = htole32(VCPROPTAG_REQUEST), 427 }, 428 }, 429 .end = { 430 .vpt_tag = htole32(VCPROPTAG_NULL), 431 }, 432 }; 433 434 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_pixelorder, 435 sizeof(vb_pixelorder), &res); 436 #ifdef RPI_IOCTL_DEBUG 437 printf("%s: %d %d %08x %08x\n", __func__, 438 le32toh(vb_pixelorder.vbt_po.order), error, res, 439 le32toh(vb_pixelorder.vbt_po.tag.vpt_rcode)); 440 #endif 441 if (error) 442 return error; 443 444 if (!vcprop_buffer_success_p(&vb_pixelorder.vb_hdr) || 445 !vcprop_tag_success_p(&vb_pixelorder.vbt_po.tag)) { 446 return EIO; 447 } 448 449 *orderp = vb_pixelorder.vbt_po.order; 450 451 return 0; 452 } 453 454 int 455 rpi_fb_set_pixelorder(uint32_t order) 456 { 457 int error; 458 uint32_t res; 459 460 461 struct __aligned(16) { 462 struct vcprop_buffer_hdr vb_hdr; 463 struct vcprop_tag_fbpixelorder vbt_po; 464 struct vcprop_tag end; 465 } vb_pixelorder = 466 { 467 .vb_hdr = { 468 .vpb_len = htole32(sizeof(vb_pixelorder)), 469 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST), 470 }, 471 .vbt_po = { 472 .tag = { 473 .vpt_tag = htole32(VCPROPTAG_SET_FB_PIXEL_ORDER), 474 .vpt_len = htole32(VCPROPTAG_LEN( 475 vb_pixelorder.vbt_po)), 476 .vpt_rcode = htole32(VCPROPTAG_REQUEST), 477 }, 478 .order = order 479 }, 480 .end = { 481 .vpt_tag = htole32(VCPROPTAG_NULL), 482 }, 483 }; 484 485 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_pixelorder, 486 sizeof(vb_pixelorder), &res); 487 #ifdef RPI_IOCTL_DEBUG 488 printf("%s: %d %d %08x %08x\n", __func__, 489 le32toh(vb_pixelorder.vbt_po.order), error, res, 490 le32toh(vb_pixelorder.vbt_po.tag.vpt_rcode)); 491 #endif 492 if (error) 493 return error; 494 495 if (!vcprop_buffer_success_p(&vb_pixelorder.vb_hdr) || 496 !vcprop_tag_success_p(&vb_pixelorder.vbt_po.tag)) { 497 return EIO; 498 } 499 500 return 0; 501 } 502 503 int 504 rpi_set_domain(uint32_t domain, uint32_t state) 505 { 506 int error; 507 uint32_t tag, res; 508 509 tag = VCPROPTAG_SET_DOMAIN_STATE; 510 if (domain == VCPROP_DOMAIN_USB) { 511 /* use old interface */ 512 tag = VCPROPTAG_SET_POWERSTATE; 513 domain = VCPROP_POWER_USB; 514 } 515 516 /* 517 * might as well put it here since we need to re-init it every time 518 * and it's not like this is going to be called very often anyway 519 */ 520 struct __aligned(16) { 521 struct vcprop_buffer_hdr vb_hdr; 522 struct vcprop_tag_powerstate vbt_power; 523 struct vcprop_tag end; 524 } vb_setpower = 525 { 526 .vb_hdr = { 527 .vpb_len = sizeof(vb_setpower), 528 .vpb_rcode = VCPROP_PROCESS_REQUEST, 529 }, 530 .vbt_power = { 531 .tag = { 532 .vpt_tag = tag, 533 .vpt_len = VCPROPTAG_LEN(vb_setpower.vbt_power), 534 .vpt_rcode = VCPROPTAG_REQUEST, 535 }, 536 .id = domain, 537 .state = state 538 }, 539 .end = { 540 .vpt_tag = VCPROPTAG_NULL, 541 }, 542 }; 543 544 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_setpower, 545 sizeof(vb_setpower), &res); 546 #ifdef RPI_IOCTL_DEBUG 547 printf("%s: %08x %08x %d %08x %08x %d %d %08x %08x\n", __func__, 548 tag, domain, state, 549 vb_setpower.vbt_power.tag.vpt_tag, 550 vb_setpower.vbt_power.id, 551 vb_setpower.vbt_power.state, 552 error, res, 553 vb_setpower.vbt_power.tag.vpt_rcode); 554 #endif 555 if (error) 556 return error; 557 558 if (!vcprop_buffer_success_p(&vb_setpower.vb_hdr) || 559 !vcprop_tag_success_p(&vb_setpower.vbt_power.tag)) { 560 return EIO; 561 } 562 563 return 0; 564 } 565 566 int 567 rpi_get_domain(uint32_t domain, uint32_t *statep) 568 { 569 int error; 570 uint32_t tag, res; 571 572 tag = VCPROPTAG_GET_DOMAIN_STATE; 573 if (domain == VCPROP_DOMAIN_USB) { 574 /* use old interface */ 575 tag = VCPROPTAG_GET_POWERSTATE; 576 domain = VCPROP_POWER_USB; 577 } 578 579 /* 580 * might as well put it here since we need to re-init it every time 581 * and it's not like this is going to be called very often anyway 582 */ 583 struct __aligned(16) { 584 struct vcprop_buffer_hdr vb_hdr; 585 struct vcprop_tag_powerstate vbt_power; 586 struct vcprop_tag end; 587 } vb_setpower = 588 { 589 .vb_hdr = { 590 .vpb_len = sizeof(vb_setpower), 591 .vpb_rcode = VCPROP_PROCESS_REQUEST, 592 }, 593 .vbt_power = { 594 .tag = { 595 .vpt_tag = tag, 596 .vpt_len = VCPROPTAG_LEN(vb_setpower.vbt_power), 597 .vpt_rcode = VCPROPTAG_REQUEST, 598 }, 599 .id = domain, 600 .state = ~0 601 }, 602 .end = { 603 .vpt_tag = VCPROPTAG_NULL, 604 }, 605 }; 606 607 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_setpower, 608 sizeof(vb_setpower), &res); 609 #ifdef RPI_IOCTL_DEBUG 610 printf("%s: %08x %08x %d %08x %08x %d %d %08x %08x\n", __func__, 611 tag, domain, *statep, 612 vb_setpower.vbt_power.tag.vpt_tag, 613 vb_setpower.vbt_power.id, 614 vb_setpower.vbt_power.state, 615 error, res, 616 vb_setpower.vbt_power.tag.vpt_rcode); 617 #endif 618 if (error) 619 return error; 620 621 if (!vcprop_buffer_success_p(&vb_setpower.vb_hdr) || 622 !vcprop_tag_success_p(&vb_setpower.vbt_power.tag)) { 623 return EIO; 624 } 625 626 *statep = vb_setpower.vbt_power.state; 627 628 return 0; 629 } 630 631 int 632 rpi_vchiq_init(uint32_t *channelbasep) 633 { 634 int error; 635 uint32_t tag, res; 636 struct __aligned(16) { 637 struct vcprop_buffer_hdr vb_hdr; 638 struct vcprop_tag_vchiqinit vbt_vchiq; 639 struct vcprop_tag end; 640 } vb; 641 642 tag = VCPROPTAG_VCHIQ_INIT; 643 644 VCPROP_INIT_REQUEST(vb); 645 VCPROP_INIT_TAG(vb.vbt_vchiq, tag); 646 vb.vbt_vchiq.base = *channelbasep; 647 648 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb, sizeof(vb), &res); 649 if (error) 650 return error; 651 652 if (!vcprop_buffer_success_p(&vb.vb_hdr) || 653 !vcprop_tag_success_p(&vb.vbt_vchiq.tag)) { 654 return EIO; 655 } 656 *channelbasep = vb.vbt_vchiq.base; 657 658 return 0; 659 } 660 661 int 662 rpi_notify_xhci_reset(uint32_t address) 663 { 664 int error; 665 uint32_t tag, res; 666 struct __aligned(16) { 667 struct vcprop_buffer_hdr vb_hdr; 668 struct vcprop_tag_notifyxhcireset vbt_nhr; 669 struct vcprop_tag end; 670 } vb; 671 672 tag = VCPROPTAG_NOTIFY_XHCI_RESET; 673 674 VCPROP_INIT_REQUEST(vb); 675 VCPROP_INIT_TAG(vb.vbt_nhr, tag); 676 vb.vbt_nhr.deviceaddress = address; 677 678 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb, sizeof(vb), &res); 679 if (error) 680 return error; 681 682 if (!vcprop_buffer_success_p(&vb.vb_hdr) || 683 !vcprop_tag_success_p(&vb.vbt_nhr.tag)) { 684 return EIO; 685 } 686 687 return 0; 688 } 689 690