1 /* 2 * Copyright 2023, Jérôme Duval, jerome.duval@gmail.com. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <new> 8 9 #include <graphic_driver.h> 10 11 #include <lock.h> 12 #include <virtio.h> 13 #include <virtio_info.h> 14 15 #include <util/AutoLock.h> 16 17 #include "viogpu.h" 18 19 20 #define VIRTIO_GPU_DRIVER_MODULE_NAME "drivers/graphics/virtio_gpu/driver_v1" 21 #define VIRTIO_GPU_DEVICE_MODULE_NAME "drivers/graphics/virtio_gpu/device_v1" 22 #define VIRTIO_GPU_DEVICE_ID_GENERATOR "virtio_gpu/device_id" 23 24 25 typedef struct { 26 device_node* node; 27 ::virtio_device virtio_device; 28 virtio_device_interface* virtio; 29 30 uint64 features; 31 32 ::virtio_queue controlQueue; 33 mutex commandLock; 34 area_id commandArea; 35 addr_t commandBuffer; 36 phys_addr_t commandPhysAddr; 37 sem_id commandDone; 38 uint64 fenceId; 39 40 ::virtio_queue cursorQueue; 41 42 int displayResourceId; 43 uint32 framebufferWidth; 44 uint32 framebufferHeight; 45 area_id framebufferArea; 46 addr_t framebuffer; 47 size_t framebufferSize; 48 uint32 displayWidth; 49 uint32 displayHeight; 50 51 thread_id updateThread; 52 bool updateThreadRunning; 53 54 area_id sharedArea; 55 virtio_gpu_shared_info* sharedInfo; 56 } virtio_gpu_driver_info; 57 58 59 typedef struct { 60 virtio_gpu_driver_info* info; 61 } virtio_gpu_handle; 62 63 64 #include <stdio.h> 65 #include <string.h> 66 #include <stdlib.h> 67 68 #include <fs/devfs.h> 69 70 #define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1)) 71 72 73 #define DEVICE_NAME "virtio_gpu" 74 #define ACCELERANT_NAME "virtio_gpu.accelerant" 75 //#define TRACE_VIRTIO_GPU 76 #ifdef TRACE_VIRTIO_GPU 77 # define TRACE(x...) dprintf(DEVICE_NAME ": " x) 78 #else 79 # define TRACE(x...) ; 80 #endif 81 #define ERROR(x...) dprintf("\33[33m" DEVICE_NAME ":\33[0m " x) 82 #define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 83 84 85 static device_manager_info* sDeviceManager; 86 87 88 static void virtio_gpu_vqwait(void* driverCookie, void* cookie); 89 90 91 const char* 92 get_feature_name(uint64 feature) 93 { 94 switch (feature) { 95 case VIRTIO_GPU_F_VIRGL: 96 return "virgl"; 97 case VIRTIO_GPU_F_EDID: 98 return "edid"; 99 case VIRTIO_GPU_F_RESOURCE_UUID: 100 return "res_uuid"; 101 case VIRTIO_GPU_F_RESOURCE_BLOB: 102 return "res_blob"; 103 } 104 return NULL; 105 } 106 107 108 static status_t 109 virtio_gpu_drain_queues(virtio_gpu_driver_info* info) 110 { 111 while (info->virtio->queue_dequeue(info->controlQueue, NULL, NULL)) 112 ; 113 114 while (info->virtio->queue_dequeue(info->cursorQueue, NULL, NULL)) 115 ; 116 117 return B_OK; 118 } 119 120 121 status_t 122 virtio_gpu_send_cmd(virtio_gpu_driver_info* info, void *cmd, size_t cmdSize, void *response, 123 size_t responseSize) 124 { 125 struct virtio_gpu_ctrl_hdr *hdr = (struct virtio_gpu_ctrl_hdr *)info->commandBuffer; 126 struct virtio_gpu_ctrl_hdr *responseHdr = (struct virtio_gpu_ctrl_hdr *)response; 127 128 memcpy((void*)info->commandBuffer, cmd, cmdSize); 129 memset((void*)(info->commandBuffer + cmdSize), 0, responseSize); 130 hdr->flags |= VIRTIO_GPU_FLAG_FENCE; 131 hdr->fence_id = ++info->fenceId; 132 133 physical_entry entries[] { 134 { info->commandPhysAddr, cmdSize }, 135 { info->commandPhysAddr + cmdSize, responseSize }, 136 }; 137 if (!info->virtio->queue_is_empty(info->controlQueue)) 138 return B_ERROR; 139 140 status_t status = info->virtio->queue_request_v(info->controlQueue, entries, 1, 1, NULL); 141 if (status != B_OK) 142 return status; 143 144 acquire_sem(info->commandDone); 145 146 while (!info->virtio->queue_dequeue(info->controlQueue, NULL, NULL)) 147 spin(10); 148 149 memcpy(response, (void*)(info->commandBuffer + cmdSize), responseSize); 150 151 if (responseHdr->fence_id != info->fenceId) { 152 ERROR("response fence id not right\n"); 153 } 154 return B_OK; 155 } 156 157 158 status_t 159 virtio_gpu_get_display_info(virtio_gpu_driver_info* info) 160 { 161 CALLED(); 162 struct virtio_gpu_ctrl_hdr hdr = {}; 163 struct virtio_gpu_resp_display_info displayInfo = {}; 164 165 hdr.type = VIRTIO_GPU_CMD_GET_DISPLAY_INFO; 166 167 virtio_gpu_send_cmd(info, &hdr, sizeof(hdr), &displayInfo, sizeof(displayInfo)); 168 169 if (displayInfo.hdr.type != VIRTIO_GPU_RESP_OK_DISPLAY_INFO) { 170 ERROR("failed getting display info\n"); 171 return B_ERROR; 172 } 173 174 if (!displayInfo.pmodes[0].enabled) { 175 ERROR("pmodes[0] is not enabled\n"); 176 return B_BAD_VALUE; 177 } 178 179 info->displayWidth = displayInfo.pmodes[0].r.width; 180 info->displayHeight = displayInfo.pmodes[0].r.height; 181 TRACE("virtio_gpu_get_display_info width %" B_PRIu32 " height %" B_PRIu32 "\n", 182 info->displayWidth, info->displayHeight); 183 184 return B_OK; 185 } 186 187 188 status_t 189 virtio_gpu_get_edids(virtio_gpu_driver_info* info, int scanout) 190 { 191 CALLED(); 192 struct virtio_gpu_cmd_get_edid getEdid = {}; 193 struct virtio_gpu_resp_edid response = {}; 194 getEdid.hdr.type = VIRTIO_GPU_CMD_GET_EDID; 195 getEdid.scanout = scanout; 196 197 virtio_gpu_send_cmd(info, &getEdid, sizeof(getEdid), &response, sizeof(response)); 198 199 if (response.hdr.type != VIRTIO_GPU_RESP_OK_EDID) { 200 ERROR("failed getting edids %d\n", response.hdr.type); 201 return B_ERROR; 202 } 203 204 info->sharedInfo->has_edid = true; 205 memcpy(&info->sharedInfo->edid_raw, response.edid, sizeof(edid1_raw)); 206 TRACE("virtio_gpu_get_edids success\n"); 207 208 return B_OK; 209 } 210 211 212 status_t 213 virtio_gpu_create_2d(virtio_gpu_driver_info* info, int resourceId, int width, int height) 214 { 215 CALLED(); 216 struct virtio_gpu_resource_create_2d resource = {}; 217 struct virtio_gpu_ctrl_hdr response = {}; 218 219 resource.hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D; 220 resource.resource_id = resourceId; 221 resource.format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM; 222 resource.width = width; 223 resource.height = height; 224 225 virtio_gpu_send_cmd(info, &resource, sizeof(resource), &response, sizeof(response)); 226 227 if (response.type != VIRTIO_GPU_RESP_OK_NODATA) { 228 ERROR("viogpu_create_2d: failed %d\n", response.type); 229 return B_ERROR; 230 } 231 232 return B_OK; 233 } 234 235 236 status_t 237 virtio_gpu_unref(virtio_gpu_driver_info* info, int resourceId) 238 { 239 CALLED(); 240 struct virtio_gpu_resource_unref resource = {}; 241 struct virtio_gpu_ctrl_hdr response = {}; 242 243 resource.hdr.type = VIRTIO_GPU_CMD_RESOURCE_UNREF; 244 resource.resource_id = resourceId; 245 246 virtio_gpu_send_cmd(info, &resource, sizeof(resource), &response, sizeof(response)); 247 248 if (response.type != VIRTIO_GPU_RESP_OK_NODATA) { 249 ERROR("virtio_gpu_unref: failed %d\n", response.type); 250 return B_ERROR; 251 } 252 253 return B_OK; 254 } 255 256 257 status_t 258 virtio_gpu_attach_backing(virtio_gpu_driver_info* info, int resourceId) 259 { 260 CALLED(); 261 struct virtio_gpu_resource_attach_backing_entries { 262 struct virtio_gpu_resource_attach_backing backing; 263 struct virtio_gpu_mem_entry entries[16]; 264 } _PACKED backing = {}; 265 struct virtio_gpu_ctrl_hdr response = {}; 266 267 physical_entry entries[16] = {}; 268 status_t status = get_memory_map((void*)info->framebuffer, info->framebufferSize, entries, 16); 269 if (status != B_OK) { 270 ERROR("virtio_gpu_attach_backing get_memory_map failed: %s\n", strerror(status)); 271 return status; 272 } 273 274 backing.backing.hdr.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING; 275 backing.backing.resource_id = resourceId; 276 for (int i = 0; i < 16; i++) { 277 if (entries[i].size == 0) 278 break; 279 TRACE("virtio_gpu_attach_backing %d %" B_PRIxPHYSADDR " %" B_PRIxPHYSADDR "\n", i, 280 entries[i].address, entries[i].size); 281 backing.entries[i].addr = entries[i].address; 282 backing.entries[i].length = entries[i].size; 283 backing.backing.nr_entries++; 284 } 285 286 virtio_gpu_send_cmd(info, &backing, sizeof(backing), &response, sizeof(response)); 287 288 if (response.type != VIRTIO_GPU_RESP_OK_NODATA) { 289 ERROR("virtio_gpu_attach_backing failed: %d\n", response.type); 290 return B_ERROR; 291 } 292 293 return B_OK; 294 } 295 296 297 status_t 298 virtio_gpu_detach_backing(virtio_gpu_driver_info* info, int resourceId) 299 { 300 CALLED(); 301 struct virtio_gpu_resource_detach_backing backing; 302 struct virtio_gpu_ctrl_hdr response = {}; 303 304 backing.hdr.type = VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING; 305 backing.resource_id = resourceId; 306 307 virtio_gpu_send_cmd(info, &backing, sizeof(backing), &response, sizeof(response)); 308 309 if (response.type != VIRTIO_GPU_RESP_OK_NODATA) { 310 ERROR("virtio_gpu_detach_backing failed: %d\n", response.type); 311 return B_ERROR; 312 } 313 314 return B_OK; 315 } 316 317 318 status_t 319 virtio_gpu_set_scanout(virtio_gpu_driver_info* info, int scanoutId, int resourceId, 320 uint32 width, uint32 height) 321 { 322 CALLED(); 323 struct virtio_gpu_set_scanout set_scanout = {}; 324 struct virtio_gpu_ctrl_hdr response = {}; 325 326 set_scanout.hdr.type = VIRTIO_GPU_CMD_SET_SCANOUT; 327 set_scanout.scanout_id = scanoutId; 328 set_scanout.resource_id = resourceId; 329 set_scanout.r.width = width; 330 set_scanout.r.height = height; 331 332 virtio_gpu_send_cmd(info, &set_scanout, sizeof(set_scanout), &response, sizeof(response)); 333 334 if (response.type != VIRTIO_GPU_RESP_OK_NODATA) { 335 ERROR("virtio_gpu_set_scanout failed %d\n", response.type); 336 return B_ERROR; 337 } 338 339 return B_OK; 340 } 341 342 343 status_t 344 virtio_gpu_transfer_to_host_2d(virtio_gpu_driver_info* info, int resourceId, 345 uint32 width, uint32 height) 346 { 347 struct virtio_gpu_transfer_to_host_2d transferToHost = {}; 348 struct virtio_gpu_ctrl_hdr response = {}; 349 350 transferToHost.hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D; 351 transferToHost.resource_id = resourceId; 352 transferToHost.r.width = width; 353 transferToHost.r.height = height; 354 355 virtio_gpu_send_cmd(info, &transferToHost, sizeof(transferToHost), &response, 356 sizeof(response)); 357 358 if (response.type != VIRTIO_GPU_RESP_OK_NODATA) { 359 ERROR("virtio_gpu_transfer_to_host_2d failed %d\n", response.type); 360 return B_ERROR; 361 } 362 363 return B_OK; 364 } 365 366 367 status_t 368 virtio_gpu_flush_resource(virtio_gpu_driver_info* info, int resourceId, uint32 width, 369 uint32 height) 370 { 371 struct virtio_gpu_resource_flush resourceFlush = {}; 372 struct virtio_gpu_ctrl_hdr response = {}; 373 374 resourceFlush.hdr.type = VIRTIO_GPU_CMD_RESOURCE_FLUSH; 375 resourceFlush.resource_id = resourceId; 376 resourceFlush.r.width = width; 377 resourceFlush.r.height = height; 378 379 virtio_gpu_send_cmd(info, &resourceFlush, sizeof(resourceFlush), &response, sizeof(response)); 380 381 if (response.type != VIRTIO_GPU_RESP_OK_NODATA) { 382 ERROR("virtio_gpu_flush_resource failed %d\n", response.type); 383 return B_ERROR; 384 } 385 386 return B_OK; 387 } 388 389 390 status_t 391 virtio_update_thread(void *arg) 392 { 393 virtio_gpu_driver_info* info = (virtio_gpu_driver_info*)arg; 394 395 while (info->updateThreadRunning) { 396 bigtime_t start = system_time(); 397 MutexLocker commandLocker(&info->commandLock); 398 virtio_gpu_transfer_to_host_2d(info, info->displayResourceId, info->displayWidth, 399 info->displayHeight); 400 virtio_gpu_flush_resource(info, info->displayResourceId, info->displayWidth, info->displayHeight); 401 bigtime_t delay = system_time() - start; 402 if (delay < 20000) 403 snooze(20000 - delay); 404 } 405 return B_OK; 406 } 407 408 409 status_t 410 virtio_gpu_set_display_mode(virtio_gpu_driver_info* info, display_mode *mode) 411 { 412 CALLED(); 413 414 int newResourceId = info->displayResourceId + 1; 415 416 // create framebuffer area 417 TRACE("virtio_gpu_set_display_mode %" B_PRIu16 " %" B_PRIu16 "\n", mode->virtual_width, 418 mode->virtual_height); 419 420 status_t status = virtio_gpu_create_2d(info, newResourceId, mode->virtual_width, mode->virtual_height); 421 if (status != B_OK) 422 return status; 423 424 status = virtio_gpu_attach_backing(info, newResourceId); 425 if (status != B_OK) 426 return status; 427 428 status = virtio_gpu_unref(info, info->displayResourceId); 429 if (status != B_OK) 430 return status; 431 432 info->displayResourceId = newResourceId; 433 info->displayWidth = mode->virtual_width; 434 info->displayHeight = mode->virtual_height; 435 436 status = virtio_gpu_set_scanout(info, 0, 0, 0, 0); 437 if (status != B_OK) 438 return status; 439 440 status = virtio_gpu_set_scanout(info, 0, info->displayResourceId, info->displayWidth, info->displayHeight); 441 if (status != B_OK) 442 return status; 443 444 status = virtio_gpu_transfer_to_host_2d(info, info->displayResourceId, info->displayWidth, info->displayHeight); 445 if (status != B_OK) 446 return status; 447 448 status = virtio_gpu_flush_resource(info, info->displayResourceId, info->displayWidth, info->displayHeight); 449 if (status != B_OK) 450 return status; 451 452 { 453 virtio_gpu_shared_info& sharedInfo = *info->sharedInfo; 454 sharedInfo.frame_buffer_area = info->framebufferArea; 455 sharedInfo.frame_buffer = (uint8*)info->framebuffer; 456 sharedInfo.bytes_per_row = info->displayWidth * 4; 457 sharedInfo.current_mode.virtual_width = info->displayWidth; 458 sharedInfo.current_mode.virtual_height = info->displayHeight; 459 sharedInfo.current_mode.space = B_RGB32; 460 } 461 462 return B_OK; 463 } 464 465 466 // #pragma mark - device module API 467 468 469 static status_t 470 virtio_gpu_init_device(void* _info, void** _cookie) 471 { 472 CALLED(); 473 virtio_gpu_driver_info* info = (virtio_gpu_driver_info*)_info; 474 475 device_node* parent = sDeviceManager->get_parent_node(info->node); 476 sDeviceManager->get_driver(parent, (driver_module_info**)&info->virtio, 477 (void**)&info->virtio_device); 478 sDeviceManager->put_node(parent); 479 480 info->virtio->negotiate_features(info->virtio_device, VIRTIO_GPU_F_EDID, 481 &info->features, &get_feature_name); 482 483 // TODO read config 484 485 // Setup queues 486 ::virtio_queue virtioQueues[2]; 487 status_t status = info->virtio->alloc_queues(info->virtio_device, 2, 488 virtioQueues, NULL); 489 if (status != B_OK) { 490 ERROR("queue allocation failed (%s)\n", strerror(status)); 491 return status; 492 } 493 494 info->controlQueue = virtioQueues[0]; 495 info->cursorQueue = virtioQueues[1]; 496 497 // create command buffer area 498 info->commandArea = create_area("virtiogpu command buffer", (void**)&info->commandBuffer, 499 B_ANY_KERNEL_BLOCK_ADDRESS, B_PAGE_SIZE, 500 B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 501 if (info->commandArea < B_OK) { 502 status = info->commandArea; 503 goto err1; 504 } 505 506 physical_entry entry; 507 status = get_memory_map((void*)info->commandBuffer, B_PAGE_SIZE, &entry, 1); 508 if (status != B_OK) 509 goto err2; 510 511 info->commandPhysAddr = entry.address; 512 mutex_init(&info->commandLock, "virtiogpu command lock"); 513 514 // Setup interrupt 515 status = info->virtio->setup_interrupt(info->virtio_device, NULL, info); 516 if (status != B_OK) { 517 ERROR("interrupt setup failed (%s)\n", strerror(status)); 518 goto err3; 519 } 520 521 status = info->virtio->queue_setup_interrupt(info->controlQueue, 522 virtio_gpu_vqwait, info); 523 if (status != B_OK) { 524 ERROR("queue interrupt setup failed (%s)\n", strerror(status)); 525 goto err3; 526 } 527 528 *_cookie = info; 529 return B_OK; 530 531 err3: 532 err2: 533 delete_area(info->commandArea); 534 err1: 535 return status; 536 } 537 538 539 static void 540 virtio_gpu_uninit_device(void* _cookie) 541 { 542 CALLED(); 543 virtio_gpu_driver_info* info = (virtio_gpu_driver_info*)_cookie; 544 545 info->virtio->free_interrupts(info->virtio_device); 546 547 mutex_destroy(&info->commandLock); 548 549 delete_area(info->commandArea); 550 info->commandArea = -1; 551 info->virtio->free_queues(info->virtio_device); 552 } 553 554 555 static status_t 556 virtio_gpu_open(void* _info, const char* path, int openMode, void** _cookie) 557 { 558 CALLED(); 559 virtio_gpu_driver_info* info = (virtio_gpu_driver_info*)_info; 560 status_t status; 561 size_t sharedSize = (sizeof(virtio_gpu_shared_info) + 7) & ~7; 562 MutexLocker commandLocker; 563 564 virtio_gpu_handle* handle = (virtio_gpu_handle*)malloc( 565 sizeof(virtio_gpu_handle)); 566 if (handle == NULL) 567 return B_NO_MEMORY; 568 569 info->commandDone = create_sem(1, "virtio_gpu_command"); 570 if (info->commandDone < B_OK) 571 goto error; 572 573 info->sharedArea = create_area("virtio_gpu shared info", 574 (void**)&info->sharedInfo, B_ANY_KERNEL_ADDRESS, 575 ROUND_TO_PAGE_SIZE(sharedSize), B_FULL_LOCK, 576 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA); 577 if (info->sharedArea < 0) 578 goto error; 579 memset(info->sharedInfo, 0, sizeof(virtio_gpu_shared_info)); 580 581 commandLocker.SetTo(&info->commandLock, false, true); 582 583 status = virtio_gpu_get_display_info(info); 584 if (status != B_OK) 585 goto error; 586 587 if ((info->features & VIRTIO_GPU_F_EDID) != 0) 588 virtio_gpu_get_edids(info, 0); 589 590 // so we can fit every mode 591 info->framebufferWidth = 3840; 592 info->framebufferHeight = 2160; 593 594 // create framebuffer area 595 info->framebufferSize = 4 * info->framebufferWidth * info->framebufferHeight; 596 info->framebufferArea = create_area("virtio_gpu framebuffer", (void**)&info->framebuffer, 597 B_ANY_KERNEL_ADDRESS, info->framebufferSize, 598 B_FULL_LOCK | B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA); 599 if (info->framebufferArea < B_OK) { 600 status = info->framebufferArea; 601 goto error; 602 } 603 604 info->displayResourceId = 1; 605 status = virtio_gpu_create_2d(info, info->displayResourceId, info->displayWidth, 606 info->displayHeight); 607 if (status != B_OK) 608 goto error; 609 610 status = virtio_gpu_attach_backing(info, info->displayResourceId); 611 if (status != B_OK) 612 goto error; 613 614 status = virtio_gpu_set_scanout(info, 0, info->displayResourceId, info->displayWidth, 615 info->displayHeight); 616 if (status != B_OK) 617 goto error; 618 619 { 620 virtio_gpu_shared_info& sharedInfo = *info->sharedInfo; 621 sharedInfo.frame_buffer_area = info->framebufferArea; 622 sharedInfo.frame_buffer = (uint8*)info->framebuffer; 623 sharedInfo.bytes_per_row = info->displayWidth * 4; 624 sharedInfo.current_mode.virtual_width = info->displayWidth; 625 sharedInfo.current_mode.virtual_height = info->displayHeight; 626 sharedInfo.current_mode.space = B_RGB32; 627 } 628 info->updateThreadRunning = true; 629 info->updateThread = spawn_kernel_thread(virtio_update_thread, "virtio_gpu update", 630 B_DISPLAY_PRIORITY, info); 631 if (info->updateThread < B_OK) 632 goto error; 633 resume_thread(info->updateThread); 634 635 handle->info = info; 636 637 *_cookie = handle; 638 return B_OK; 639 640 error: 641 delete_area(info->framebufferArea); 642 info->framebufferArea = -1; 643 delete_sem(info->commandDone); 644 info->commandDone = -1; 645 free(handle); 646 return B_ERROR; 647 } 648 649 650 static status_t 651 virtio_gpu_close(void* cookie) 652 { 653 virtio_gpu_handle* handle = (virtio_gpu_handle*)cookie; 654 CALLED(); 655 656 virtio_gpu_driver_info* info = handle->info; 657 info->updateThreadRunning = false; 658 delete_sem(info->commandDone); 659 info->commandDone = -1; 660 661 return B_OK; 662 } 663 664 665 static status_t 666 virtio_gpu_free(void* cookie) 667 { 668 CALLED(); 669 virtio_gpu_handle* handle = (virtio_gpu_handle*)cookie; 670 671 virtio_gpu_driver_info* info = handle->info; 672 int32 result; 673 wait_for_thread(info->updateThread, &result); 674 info->updateThread = -1; 675 virtio_gpu_drain_queues(info); 676 free(handle); 677 return B_OK; 678 } 679 680 681 static void 682 virtio_gpu_vqwait(void* driverCookie, void* cookie) 683 { 684 CALLED(); 685 virtio_gpu_driver_info* info = (virtio_gpu_driver_info*)cookie; 686 687 release_sem_etc(info->commandDone, 1, B_DO_NOT_RESCHEDULE); 688 } 689 690 691 static status_t 692 virtio_gpu_read(void* cookie, off_t pos, void* buffer, size_t* _length) 693 { 694 *_length = 0; 695 return B_NOT_ALLOWED; 696 } 697 698 699 static status_t 700 virtio_gpu_write(void* cookie, off_t pos, const void* buffer, 701 size_t* _length) 702 { 703 *_length = 0; 704 return B_NOT_ALLOWED; 705 } 706 707 708 static status_t 709 virtio_gpu_ioctl(void* cookie, uint32 op, void* buffer, size_t length) 710 { 711 CALLED(); 712 virtio_gpu_handle* handle = (virtio_gpu_handle*)cookie; 713 virtio_gpu_driver_info* info = handle->info; 714 715 // TRACE("ioctl(op = %lx)\n", op); 716 717 switch (op) { 718 case B_GET_ACCELERANT_SIGNATURE: 719 dprintf(DEVICE_NAME ": acc: %s\n", ACCELERANT_NAME); 720 if (user_strlcpy((char*)buffer, ACCELERANT_NAME, 721 B_FILE_NAME_LENGTH) < B_OK) 722 return B_BAD_ADDRESS; 723 724 return B_OK; 725 726 // needed to share data between kernel and accelerant 727 case VIRTIO_GPU_GET_PRIVATE_DATA: 728 return user_memcpy(buffer, &info->sharedArea, sizeof(area_id)); 729 730 case VIRTIO_GPU_SET_DISPLAY_MODE: 731 { 732 if (length != sizeof(display_mode)) 733 return B_BAD_VALUE; 734 735 display_mode mode; 736 if (user_memcpy(&mode, buffer, sizeof(display_mode)) != B_OK) 737 return B_BAD_ADDRESS; 738 739 MutexLocker commandLocker(&info->commandLock); 740 741 return virtio_gpu_set_display_mode(info, &mode); 742 } 743 default: 744 ERROR("ioctl: unknown message %" B_PRIx32 "\n", op); 745 break; 746 } 747 748 749 return B_DEV_INVALID_IOCTL; 750 } 751 752 753 // #pragma mark - driver module API 754 755 756 static float 757 virtio_gpu_supports_device(device_node* parent) 758 { 759 CALLED(); 760 const char* bus; 761 uint16 deviceType; 762 763 // make sure parent is really the Virtio bus manager 764 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 765 return -1; 766 767 if (strcmp(bus, "virtio")) 768 return 0.0; 769 770 // check whether it's really a Virtio GPU device 771 if (sDeviceManager->get_attr_uint16(parent, VIRTIO_DEVICE_TYPE_ITEM, 772 &deviceType, true) != B_OK || deviceType != VIRTIO_DEVICE_ID_GPU) 773 return 0.0; 774 775 TRACE("Virtio gpu device found!\n"); 776 777 return 0.6; 778 } 779 780 781 static status_t 782 virtio_gpu_register_device(device_node* node) 783 { 784 CALLED(); 785 786 device_attr attrs[] = { 787 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "Virtio GPU"} }, 788 { NULL } 789 }; 790 791 return sDeviceManager->register_node(node, VIRTIO_GPU_DRIVER_MODULE_NAME, 792 attrs, NULL, NULL); 793 } 794 795 796 static status_t 797 virtio_gpu_init_driver(device_node* node, void** cookie) 798 { 799 CALLED(); 800 801 virtio_gpu_driver_info* info = (virtio_gpu_driver_info*)malloc( 802 sizeof(virtio_gpu_driver_info)); 803 if (info == NULL) 804 return B_NO_MEMORY; 805 806 memset(info, 0, sizeof(*info)); 807 808 info->node = node; 809 810 *cookie = info; 811 return B_OK; 812 } 813 814 815 static void 816 virtio_gpu_uninit_driver(void* _cookie) 817 { 818 CALLED(); 819 virtio_gpu_driver_info* info = (virtio_gpu_driver_info*)_cookie; 820 free(info); 821 } 822 823 824 static status_t 825 virtio_gpu_register_child_devices(void* _cookie) 826 { 827 CALLED(); 828 virtio_gpu_driver_info* info = (virtio_gpu_driver_info*)_cookie; 829 status_t status; 830 831 int32 id = sDeviceManager->create_id(VIRTIO_GPU_DEVICE_ID_GENERATOR); 832 if (id < 0) 833 return id; 834 835 char name[64]; 836 snprintf(name, sizeof(name), "graphics/virtio/%" B_PRId32, 837 id); 838 839 status = sDeviceManager->publish_device(info->node, name, 840 VIRTIO_GPU_DEVICE_MODULE_NAME); 841 842 return status; 843 } 844 845 846 // #pragma mark - 847 848 849 module_dependency module_dependencies[] = { 850 {B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager}, 851 {} 852 }; 853 854 struct device_module_info sVirtioGpuDevice = { 855 { 856 VIRTIO_GPU_DEVICE_MODULE_NAME, 857 0, 858 NULL 859 }, 860 861 virtio_gpu_init_device, 862 virtio_gpu_uninit_device, 863 NULL, // remove, 864 865 virtio_gpu_open, 866 virtio_gpu_close, 867 virtio_gpu_free, 868 virtio_gpu_read, 869 virtio_gpu_write, 870 NULL, // io 871 virtio_gpu_ioctl, 872 873 NULL, // select 874 NULL, // deselect 875 }; 876 877 struct driver_module_info sVirtioGpuDriver = { 878 { 879 VIRTIO_GPU_DRIVER_MODULE_NAME, 880 0, 881 NULL 882 }, 883 884 virtio_gpu_supports_device, 885 virtio_gpu_register_device, 886 virtio_gpu_init_driver, 887 virtio_gpu_uninit_driver, 888 virtio_gpu_register_child_devices, 889 NULL, // rescan 890 NULL, // removed 891 }; 892 893 module_info* modules[] = { 894 (module_info*)&sVirtioGpuDriver, 895 (module_info*)&sVirtioGpuDevice, 896 NULL 897 }; 898