1 /* 2 * Copyright 2010-2013, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <ctype.h> 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <stdio.h> 11 #include <string.h> 12 #include <unistd.h> 13 14 #include <algorithm> 15 16 #include <device_manager.h> 17 #include <Drivers.h> 18 19 #include <AutoDeleter.h> 20 #include <util/AutoLock.h> 21 #include <util/DoublyLinkedList.h> 22 23 #include <fs/KPath.h> 24 #include <lock.h> 25 #include <vm/vm.h> 26 #include <vm/VMCache.h> 27 #include <vm/vm_page.h> 28 29 #include "dma_resources.h" 30 #include "io_requests.h" 31 #include "IOSchedulerSimple.h" 32 33 34 //#define TRACE_CHECK_SUM_DEVICE 35 #ifdef TRACE_CHECK_SUM_DEVICE 36 # define TRACE(x...) dprintf(x) 37 #else 38 # define TRACE(x) do {} while (false) 39 #endif 40 41 42 // parameters for the DMA resource 43 static const uint32 kDMAResourceBufferCount = 16; 44 static const uint32 kDMAResourceBounceBufferCount = 16; 45 46 static const char* const kDriverModuleName 47 = "drivers/disk/virtual/ram_disk/driver_v1"; 48 static const char* const kControlDeviceModuleName 49 = "drivers/disk/virtual/ram_disk/control/device_v1"; 50 static const char* const kRawDeviceModuleName 51 = "drivers/disk/virtual/ram_disk/raw/device_v1"; 52 53 static const char* const kControlDeviceName 54 = "disk/virtual/ram/control"; 55 static const char* const kRawDeviceBaseName = "disk/virtual/ram"; 56 57 static const char* const kFilePathItem = "ram_disk/file_path"; 58 static const char* const kDeviceSizeItem = "ram_disk/device_size"; 59 60 61 struct RawDevice; 62 typedef DoublyLinkedList<RawDevice> RawDeviceList; 63 64 struct device_manager_info* sDeviceManager; 65 66 static RawDeviceList sDeviceList; 67 static mutex sDeviceListLock = MUTEX_INITIALIZER("ram disk device list"); 68 69 70 struct Device { 71 Device(device_node* node) 72 : 73 fNode(node) 74 { 75 mutex_init(&fLock, "ram disk device"); 76 } 77 78 virtual ~Device() 79 { 80 mutex_destroy(&fLock); 81 } 82 83 bool Lock() { mutex_lock(&fLock); return true; } 84 void Unlock() { mutex_unlock(&fLock); } 85 86 device_node* Node() const { return fNode; } 87 88 virtual status_t PublishDevice() = 0; 89 90 protected: 91 mutex fLock; 92 device_node* fNode; 93 }; 94 95 96 struct ControlDevice : Device { 97 ControlDevice(device_node* node) 98 : 99 Device(node) 100 { 101 } 102 103 status_t Register(const char* fileName, uint64 deviceSize) 104 { 105 device_attr attrs[] = { 106 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, 107 {string: "RAM Disk Raw Device"}}, 108 {kFilePathItem, B_STRING_TYPE, {string: fileName}}, 109 {kDeviceSizeItem, B_UINT64_TYPE, {ui64: deviceSize}}, 110 {NULL} 111 }; 112 113 return sDeviceManager->register_node( 114 sDeviceManager->get_parent_node(Node()), kDriverModuleName, attrs, 115 NULL, NULL); 116 } 117 118 virtual status_t PublishDevice() 119 { 120 return sDeviceManager->publish_device(Node(), kControlDeviceName, 121 kControlDeviceModuleName); 122 } 123 }; 124 125 126 struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> { 127 RawDevice(device_node* node) 128 : 129 Device(node), 130 fIndex(-1), 131 fDeviceSize(0), 132 fDeviceName(NULL), 133 fCache(NULL), 134 fDMAResource(NULL), 135 fIOScheduler(NULL) 136 { 137 } 138 139 virtual ~RawDevice() 140 { 141 if (fIndex >= 0) { 142 MutexLocker locker(sDeviceListLock); 143 sDeviceList.Remove(this); 144 } 145 146 free(fDeviceName); 147 } 148 149 int32 Index() const { return fIndex; } 150 off_t DeviceSize() const { return fDeviceSize; } 151 const char* DeviceName() const { return fDeviceName; } 152 153 status_t Init(uint64 deviceSize) 154 { 155 fDeviceSize = (deviceSize + B_PAGE_SIZE - 1) / B_PAGE_SIZE 156 * B_PAGE_SIZE; 157 158 if (fDeviceSize < B_PAGE_SIZE 159 || (uint64)fDeviceSize / B_PAGE_SIZE 160 > vm_page_num_pages() * 2 / 3) { 161 return B_BAD_VALUE; 162 } 163 164 // find a free slot 165 fIndex = 0; 166 RawDevice* nextDevice = NULL; 167 MutexLocker locker(sDeviceListLock); 168 for (RawDeviceList::Iterator it = sDeviceList.GetIterator(); 169 (nextDevice = it.Next()) != NULL;) { 170 if (nextDevice->Index() > fIndex) 171 break; 172 fIndex = nextDevice->Index() + 1; 173 } 174 175 sDeviceList.InsertBefore(nextDevice, this); 176 177 // construct our device path 178 KPath path(kRawDeviceBaseName); 179 char buffer[32]; 180 snprintf(buffer, sizeof(buffer), "%" B_PRId32 "/raw", fIndex); 181 182 status_t error = path.Append(buffer); 183 if (error != B_OK) 184 return error; 185 186 fDeviceName = path.DetachBuffer(); 187 188 return B_OK; 189 } 190 191 status_t Prepare() 192 { 193 status_t error = VMCacheFactory::CreateAnonymousCache(fCache, false, 0, 194 0, false, VM_PRIORITY_SYSTEM); 195 if (error != B_OK) { 196 Unprepare(); 197 return error; 198 } 199 200 fCache->temporary = 1; 201 fCache->virtual_end = fDeviceSize; 202 203 error = fCache->Commit(fDeviceSize, VM_PRIORITY_SYSTEM); 204 if (error != B_OK) { 205 Unprepare(); 206 return error; 207 } 208 209 // no DMA restrictions 210 const dma_restrictions restrictions = {}; 211 212 fDMAResource = new(std::nothrow) DMAResource; 213 if (fDMAResource == NULL) { 214 Unprepare(); 215 return B_NO_MEMORY; 216 } 217 218 error = fDMAResource->Init(restrictions, B_PAGE_SIZE, 219 kDMAResourceBufferCount, kDMAResourceBounceBufferCount); 220 if (error != B_OK) { 221 Unprepare(); 222 return error; 223 } 224 225 fIOScheduler = new(std::nothrow) IOSchedulerSimple(fDMAResource); 226 if (fIOScheduler == NULL) { 227 Unprepare(); 228 return B_NO_MEMORY; 229 } 230 231 error = fIOScheduler->Init("ram disk device scheduler"); 232 if (error != B_OK) { 233 Unprepare(); 234 return error; 235 } 236 237 fIOScheduler->SetCallback(&_DoIOEntry, this); 238 239 return B_OK; 240 } 241 242 void Unprepare() 243 { 244 delete fIOScheduler; 245 fIOScheduler = NULL; 246 247 delete fDMAResource; 248 fDMAResource = NULL; 249 250 if (fCache != NULL) { 251 fCache->Lock(); 252 fCache->ReleaseRefAndUnlock(); 253 fCache = NULL; 254 } 255 } 256 257 status_t DoIO(IORequest* request) 258 { 259 return fIOScheduler->ScheduleRequest(request); 260 } 261 262 virtual status_t PublishDevice() 263 { 264 return sDeviceManager->publish_device(Node(), fDeviceName, 265 kRawDeviceModuleName); 266 } 267 268 private: 269 static status_t _DoIOEntry(void* data, IOOperation* operation) 270 { 271 return ((RawDevice*)data)->_DoIO(operation); 272 } 273 274 status_t _DoIO(IOOperation* operation) 275 { 276 off_t offset = operation->Offset(); 277 generic_size_t length = operation->Length(); 278 279 ASSERT(offset % B_PAGE_SIZE == 0); 280 ASSERT(length % B_PAGE_SIZE == 0); 281 282 const generic_io_vec* vecs = operation->Vecs(); 283 generic_size_t vecOffset = 0; 284 bool isWrite = operation->IsWrite(); 285 286 vm_page** pages = new(std::nothrow) vm_page*[length / B_PAGE_SIZE]; 287 if (pages == NULL) 288 return B_NO_MEMORY; 289 ArrayDeleter<vm_page*> pagesDeleter(pages); 290 291 _GetPages(offset, length, isWrite, pages); 292 293 status_t error = B_OK; 294 size_t index = 0; 295 296 while (length > 0) { 297 vm_page* page = pages[index]; 298 299 error = _CopyData(page, vecs, vecOffset, isWrite); 300 if (error != B_OK) 301 break; 302 303 offset += B_PAGE_SIZE; 304 length -= B_PAGE_SIZE; 305 index++; 306 } 307 308 _PutPages(operation->Offset(), operation->Length(), pages, 309 error == B_OK); 310 311 if (error != B_OK) { 312 fIOScheduler->OperationCompleted(operation, error, 0); 313 return error; 314 } 315 316 fIOScheduler->OperationCompleted(operation, B_OK, operation->Length()); 317 return B_OK; 318 } 319 320 void _GetPages(off_t offset, off_t length, bool isWrite, vm_page** pages) 321 { 322 // get the pages, we already have 323 AutoLocker<VMCache> locker(fCache); 324 325 size_t pageCount = length / B_PAGE_SIZE; 326 size_t index = 0; 327 size_t missingPages = 0; 328 329 while (length > 0) { 330 vm_page* page = fCache->LookupPage(offset); 331 if (page != NULL) { 332 if (page->busy) { 333 fCache->WaitForPageEvents(page, PAGE_EVENT_NOT_BUSY, true); 334 continue; 335 } 336 337 page->busy = true; 338 } else 339 missingPages++; 340 341 pages[index++] = page; 342 offset += B_PAGE_SIZE; 343 length -= B_PAGE_SIZE; 344 } 345 346 locker.Unlock(); 347 348 // For a write we need to reserve the missing pages. 349 if (isWrite && missingPages > 0) { 350 vm_page_reservation reservation; 351 vm_page_reserve_pages(&reservation, missingPages, 352 VM_PRIORITY_SYSTEM); 353 354 for (size_t i = 0; i < pageCount; i++) { 355 if (pages[i] != NULL) 356 continue; 357 358 pages[i] = vm_page_allocate_page(&reservation, 359 PAGE_STATE_WIRED | VM_PAGE_ALLOC_BUSY); 360 361 if (--missingPages == 0) 362 break; 363 } 364 365 vm_page_unreserve_pages(&reservation); 366 } 367 } 368 369 void _PutPages(off_t offset, off_t length, vm_page** pages, bool success) 370 { 371 AutoLocker<VMCache> locker(fCache); 372 373 // Mark all pages unbusy. On error free the newly allocated pages. 374 size_t index = 0; 375 376 while (length > 0) { 377 vm_page* page = pages[index++]; 378 if (page != NULL) { 379 if (page->CacheRef() == NULL) { 380 if (success) { 381 fCache->InsertPage(page, offset); 382 fCache->MarkPageUnbusy(page); 383 } else 384 vm_page_free(NULL, page); 385 } else 386 fCache->MarkPageUnbusy(page); 387 } 388 389 offset += B_PAGE_SIZE; 390 length -= B_PAGE_SIZE; 391 } 392 } 393 394 status_t _CopyData(vm_page* page, const generic_io_vec*& vecs, 395 generic_size_t& vecOffset, bool toPage) 396 { 397 // map page to virtual memory 398 Thread* thread = thread_get_current_thread(); 399 uint8* pageData = NULL; 400 void* handle; 401 if (page != NULL) { 402 thread_pin_to_current_cpu(thread); 403 addr_t virtualAddress; 404 status_t error = vm_get_physical_page_current_cpu( 405 page->physical_page_number * B_PAGE_SIZE, &virtualAddress, 406 &handle); 407 if (error != B_OK) { 408 thread_unpin_from_current_cpu(thread); 409 return error; 410 } 411 412 pageData = (uint8*)virtualAddress; 413 } 414 415 size_t length = B_PAGE_SIZE; 416 while (length > 0) { 417 size_t toCopy = std::min((generic_size_t)length, 418 vecs->length - vecOffset); 419 420 if (toCopy == 0) { 421 vecs++; 422 vecOffset = 0; 423 continue; 424 } 425 426 phys_addr_t vecAddress = vecs->base + vecOffset; 427 428 status_t error = toPage 429 ? vm_memcpy_from_physical(pageData, vecAddress, toCopy, false) 430 : (page != NULL 431 ? vm_memcpy_to_physical(vecAddress, pageData, toCopy, false) 432 : vm_memset_physical(vecAddress, 0, toCopy)); 433 if (error != B_OK) 434 return error; 435 436 pageData += toCopy; 437 length -= toCopy; 438 vecOffset += toCopy; 439 } 440 441 if (page != NULL) { 442 vm_put_physical_page_current_cpu((addr_t)pageData, handle); 443 thread_unpin_from_current_cpu(thread); 444 } 445 446 return B_OK; 447 } 448 449 private: 450 int32 fIndex; 451 off_t fDeviceSize; 452 char* fDeviceName; 453 VMCache* fCache; 454 DMAResource* fDMAResource; 455 IOScheduler* fIOScheduler; 456 }; 457 458 459 struct RawDeviceCookie { 460 RawDeviceCookie(RawDevice* device, int openMode) 461 : 462 fDevice(device), 463 fOpenMode(openMode) 464 { 465 } 466 467 RawDevice* Device() const { return fDevice; } 468 int OpenMode() const { return fOpenMode; } 469 470 private: 471 RawDevice* fDevice; 472 int fOpenMode; 473 }; 474 475 476 // #pragma mark - 477 478 479 static bool 480 parse_command_line(char* buffer, char**& _argv, int& _argc) 481 { 482 // Process the argument string. We split at whitespace, heeding quotes and 483 // escaped characters. The processed arguments are written to the given 484 // buffer, separated by single null chars. 485 char* start = buffer; 486 char* out = buffer; 487 bool pendingArgument = false; 488 int argc = 0; 489 while (*start != '\0') { 490 // ignore whitespace 491 if (isspace(*start)) { 492 if (pendingArgument) { 493 *out = '\0'; 494 out++; 495 argc++; 496 pendingArgument = false; 497 } 498 start++; 499 continue; 500 } 501 502 pendingArgument = true; 503 504 if (*start == '"' || *start == '\'') { 505 // quoted text -- continue until closing quote 506 char quote = *start; 507 start++; 508 while (*start != '\0' && *start != quote) { 509 if (*start == '\\' && quote == '"') { 510 start++; 511 if (*start == '\0') 512 break; 513 } 514 *out = *start; 515 start++; 516 out++; 517 } 518 519 if (*start != '\0') 520 start++; 521 } else { 522 // unquoted text 523 if (*start == '\\') { 524 // escaped char 525 start++; 526 if (start == '\0') 527 break; 528 } 529 530 *out = *start; 531 start++; 532 out++; 533 } 534 } 535 536 if (pendingArgument) { 537 *out = '\0'; 538 argc++; 539 } 540 541 // allocate argument vector 542 char** argv = new(std::nothrow) char*[argc + 1]; 543 if (argv == NULL) 544 return false; 545 546 // fill vector 547 start = buffer; 548 for (int i = 0; i < argc; i++) { 549 argv[i] = start; 550 start += strlen(start) + 1; 551 } 552 argv[argc] = NULL; 553 554 _argv = argv; 555 _argc = argc; 556 return true; 557 } 558 559 560 // #pragma mark - driver 561 562 563 static float 564 ram_disk_driver_supports_device(device_node* parent) 565 { 566 const char* bus = NULL; 567 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) 568 == B_OK 569 && strcmp(bus, "generic") == 0) { 570 return 0.8; 571 } 572 573 return -1; 574 } 575 576 577 static status_t 578 ram_disk_driver_register_device(device_node* parent) 579 { 580 device_attr attrs[] = { 581 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, 582 {string: "RAM Disk Control Device"}}, 583 {NULL} 584 }; 585 586 return sDeviceManager->register_node(parent, kDriverModuleName, attrs, NULL, 587 NULL); 588 } 589 590 591 static status_t 592 ram_disk_driver_init_driver(device_node* node, void** _driverCookie) 593 { 594 // const char* fileName; 595 uint64 deviceSize; 596 // if (sDeviceManager->get_attr_string(node, kFilePathItem, &fileName, false) 597 // == B_OK) { 598 if (sDeviceManager->get_attr_uint64(node, kDeviceSizeItem, &deviceSize, 599 false) == B_OK) { 600 RawDevice* device = new(std::nothrow) RawDevice(node); 601 if (device == NULL) 602 return B_NO_MEMORY; 603 604 // status_t error = device->Init(fileName); 605 status_t error = device->Init(deviceSize); 606 if (error != B_OK) { 607 delete device; 608 return error; 609 } 610 611 *_driverCookie = (Device*)device; 612 } else { 613 ControlDevice* device = new(std::nothrow) ControlDevice(node); 614 if (device == NULL) 615 return B_NO_MEMORY; 616 617 *_driverCookie = (Device*)device; 618 } 619 620 return B_OK; 621 } 622 623 624 static void 625 ram_disk_driver_uninit_driver(void* driverCookie) 626 { 627 Device* device = (Device*)driverCookie; 628 delete device; 629 } 630 631 632 static status_t 633 ram_disk_driver_register_child_devices(void* driverCookie) 634 { 635 Device* device = (Device*)driverCookie; 636 return device->PublishDevice(); 637 } 638 639 640 // #pragma mark - control device 641 642 643 static status_t 644 ram_disk_control_device_init_device(void* driverCookie, void** _deviceCookie) 645 { 646 *_deviceCookie = driverCookie; 647 return B_OK; 648 } 649 650 651 static void 652 ram_disk_control_device_uninit_device(void* deviceCookie) 653 { 654 } 655 656 657 static status_t 658 ram_disk_control_device_open(void* deviceCookie, const char* path, int openMode, 659 void** _cookie) 660 { 661 *_cookie = deviceCookie; 662 return B_OK; 663 } 664 665 666 static status_t 667 ram_disk_control_device_close(void* cookie) 668 { 669 return B_OK; 670 } 671 672 673 static status_t 674 ram_disk_control_device_free(void* cookie) 675 { 676 return B_OK; 677 } 678 679 680 static status_t 681 ram_disk_control_device_read(void* cookie, off_t position, void* buffer, 682 size_t* _length) 683 { 684 *_length = 0; 685 return B_OK; 686 } 687 688 689 static status_t 690 ram_disk_control_device_write(void* cookie, off_t position, const void* data, 691 size_t* _length) 692 { 693 ControlDevice* device = (ControlDevice*)cookie; 694 695 if (position != 0) 696 return B_BAD_VALUE; 697 698 // copy data to stack buffer 699 char* buffer = (char*)malloc(*_length + 1); 700 if (buffer == NULL) 701 return B_NO_MEMORY; 702 MemoryDeleter bufferDeleter(buffer); 703 704 if (IS_USER_ADDRESS(data)) { 705 if (user_memcpy(buffer, data, *_length) != B_OK) 706 return B_BAD_ADDRESS; 707 } else 708 memcpy(buffer, data, *_length); 709 710 buffer[*_length] = '\0'; 711 712 // parse arguments 713 char** argv; 714 int argc; 715 if (!parse_command_line(buffer, argv, argc)) 716 return B_NO_MEMORY; 717 ArrayDeleter<char*> argvDeleter(argv); 718 719 if (argc == 0) { 720 dprintf("\"help\" for usage!\n"); 721 return B_BAD_VALUE; 722 } 723 724 // execute command 725 if (strcmp(argv[0], "help") == 0) { 726 // help 727 // dprintf("register <path>\n"); 728 // dprintf(" Registers file <path> as a new ram disk device.\n"); 729 dprintf("register <size>\n"); 730 dprintf(" Registers a new ram disk device with size <size>.\n"); 731 dprintf("unregister <device>\n"); 732 dprintf(" Unregisters <device>.\n"); 733 } else if (strcmp(argv[0], "register") == 0) { 734 // register 735 if (argc != 2) { 736 dprintf("Usage: register <size>\n"); 737 return B_BAD_VALUE; 738 } 739 740 // parse size argument 741 char* end; 742 uint64 deviceSize = strtoll(argv[1], &end, 0); 743 if (end == argv[1]) { 744 dprintf("Invalid size argument: \"%s\"\n", argv[1]); 745 return B_BAD_VALUE; 746 } 747 748 switch (*end) { 749 case 'g': 750 deviceSize *= 1024; 751 case 'm': 752 deviceSize *= 1024; 753 case 'k': 754 deviceSize *= 1024; 755 break; 756 } 757 758 return device->Register(NULL, deviceSize); 759 } else if (strcmp(argv[0], "unregister") == 0) { 760 // unregister 761 if (argc != 2) { 762 dprintf("Usage: unregister <device>\n"); 763 return B_BAD_VALUE; 764 } 765 766 const char* deviceName = argv[1]; 767 if (strncmp(deviceName, "/dev/", 5) == 0) 768 deviceName += 5; 769 770 // find the device in the list and unregister it 771 MutexLocker locker(sDeviceListLock); 772 for (RawDeviceList::Iterator it = sDeviceList.GetIterator(); 773 RawDevice* device = it.Next();) { 774 if (strcmp(device->DeviceName(), deviceName) == 0) { 775 // TODO: Race condition: We should mark the device as going to 776 // be unregistered, so no one else can try the same after we 777 // unlock! 778 locker.Unlock(); 779 // TODO: The following doesn't work! unpublish_device(), as per implementation 780 // (partially commented out) and unregister_node() returns B_BUSY. 781 status_t error = sDeviceManager->unpublish_device( 782 device->Node(), device->DeviceName()); 783 if (error != B_OK) { 784 dprintf("Failed to unpublish device \"%s\": %s\n", 785 deviceName, strerror(error)); 786 return error; 787 } 788 789 error = sDeviceManager->unregister_node(device->Node()); 790 if (error != B_OK) { 791 dprintf("Failed to unregister node \"%s\": %s\n", 792 deviceName, strerror(error)); 793 return error; 794 } 795 796 return B_OK; 797 } 798 } 799 800 dprintf("Device \"%s\" not found!\n", deviceName); 801 return B_BAD_VALUE; 802 } else { 803 dprintf("Invalid command \"%s\"!\n", argv[0]); 804 return B_BAD_VALUE; 805 } 806 807 return B_OK; 808 } 809 810 811 static status_t 812 ram_disk_control_device_control(void* cookie, uint32 op, void* buffer, 813 size_t length) 814 { 815 return B_BAD_VALUE; 816 } 817 818 819 // #pragma mark - raw device 820 821 822 static status_t 823 ram_disk_raw_device_init_device(void* driverCookie, void** _deviceCookie) 824 { 825 RawDevice* device = static_cast<RawDevice*>((Device*)driverCookie); 826 827 status_t error = device->Prepare(); 828 if (error != B_OK) 829 return error; 830 831 *_deviceCookie = device; 832 return B_OK; 833 } 834 835 836 static void 837 ram_disk_raw_device_uninit_device(void* deviceCookie) 838 { 839 RawDevice* device = (RawDevice*)deviceCookie; 840 device->Unprepare(); 841 } 842 843 844 static status_t 845 ram_disk_raw_device_open(void* deviceCookie, const char* path, int openMode, 846 void** _cookie) 847 { 848 RawDevice* device = (RawDevice*)deviceCookie; 849 850 RawDeviceCookie* cookie = new(std::nothrow) RawDeviceCookie(device, 851 openMode); 852 if (cookie == NULL) 853 return B_NO_MEMORY; 854 855 *_cookie = cookie; 856 return B_OK; 857 } 858 859 860 static status_t 861 ram_disk_raw_device_close(void* cookie) 862 { 863 return B_OK; 864 } 865 866 867 static status_t 868 ram_disk_raw_device_free(void* _cookie) 869 { 870 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie; 871 delete cookie; 872 return B_OK; 873 } 874 875 876 static status_t 877 ram_disk_raw_device_read(void* _cookie, off_t pos, void* buffer, 878 size_t* _length) 879 { 880 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie; 881 RawDevice* device = cookie->Device(); 882 883 size_t length = *_length; 884 885 if (pos >= device->DeviceSize()) 886 return B_BAD_VALUE; 887 if (pos + length > device->DeviceSize()) 888 length = device->DeviceSize() - pos; 889 890 IORequest request; 891 status_t status = request.Init(pos, (addr_t)buffer, length, false, 0); 892 if (status != B_OK) 893 return status; 894 895 status = device->DoIO(&request); 896 if (status != B_OK) 897 return status; 898 899 status = request.Wait(0, 0); 900 if (status == B_OK) 901 *_length = length; 902 return status; 903 } 904 905 906 static status_t 907 ram_disk_raw_device_write(void* _cookie, off_t pos, const void* buffer, 908 size_t* _length) 909 { 910 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie; 911 RawDevice* device = cookie->Device(); 912 913 size_t length = *_length; 914 915 if (pos >= device->DeviceSize()) 916 return B_BAD_VALUE; 917 if (pos + length > device->DeviceSize()) 918 length = device->DeviceSize() - pos; 919 920 IORequest request; 921 status_t status = request.Init(pos, (addr_t)buffer, length, true, 0); 922 if (status != B_OK) 923 return status; 924 925 status = device->DoIO(&request); 926 if (status != B_OK) 927 return status; 928 929 status = request.Wait(0, 0); 930 if (status == B_OK) 931 *_length = length; 932 933 return status; 934 } 935 936 937 static status_t 938 ram_disk_raw_device_io(void* _cookie, io_request* request) 939 { 940 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie; 941 RawDevice* device = cookie->Device(); 942 943 return device->DoIO(request); 944 } 945 946 947 static status_t 948 ram_disk_raw_device_control(void* _cookie, uint32 op, void* buffer, 949 size_t length) 950 { 951 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie; 952 RawDevice* device = cookie->Device(); 953 954 switch (op) { 955 case B_GET_DEVICE_SIZE: 956 { 957 size_t size = device->DeviceSize(); 958 return user_memcpy(buffer, &size, sizeof(size_t)); 959 } 960 961 case B_SET_NONBLOCKING_IO: 962 case B_SET_BLOCKING_IO: 963 return B_OK; 964 965 case B_GET_READ_STATUS: 966 case B_GET_WRITE_STATUS: 967 { 968 bool value = true; 969 return user_memcpy(buffer, &value, sizeof(bool)); 970 } 971 972 case B_GET_GEOMETRY: 973 case B_GET_BIOS_GEOMETRY: 974 { 975 device_geometry geometry; 976 geometry.bytes_per_sector = B_PAGE_SIZE; 977 geometry.sectors_per_track = 1; 978 geometry.cylinder_count = device->DeviceSize() / B_PAGE_SIZE; 979 // TODO: We're limited to 2^32 * B_PAGE_SIZE, if we don't use 980 // sectors_per_track and head_count. 981 geometry.head_count = 1; 982 geometry.device_type = B_DISK; 983 geometry.removable = true; 984 geometry.read_only = false; 985 geometry.write_once = false; 986 987 return user_memcpy(buffer, &geometry, sizeof(device_geometry)); 988 } 989 990 case B_GET_MEDIA_STATUS: 991 { 992 status_t status = B_OK; 993 return user_memcpy(buffer, &status, sizeof(status_t)); 994 } 995 996 case B_SET_UNINTERRUPTABLE_IO: 997 case B_SET_INTERRUPTABLE_IO: 998 case B_FLUSH_DRIVE_CACHE: 999 return B_OK; 1000 } 1001 1002 return B_BAD_VALUE; 1003 } 1004 1005 1006 // #pragma mark - 1007 1008 1009 module_dependency module_dependencies[] = { 1010 {B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager}, 1011 {} 1012 }; 1013 1014 1015 static const struct driver_module_info sChecksumDeviceDriverModule = { 1016 { 1017 kDriverModuleName, 1018 0, 1019 NULL 1020 }, 1021 1022 ram_disk_driver_supports_device, 1023 ram_disk_driver_register_device, 1024 ram_disk_driver_init_driver, 1025 ram_disk_driver_uninit_driver, 1026 ram_disk_driver_register_child_devices 1027 }; 1028 1029 static const struct device_module_info sChecksumControlDeviceModule = { 1030 { 1031 kControlDeviceModuleName, 1032 0, 1033 NULL 1034 }, 1035 1036 ram_disk_control_device_init_device, 1037 ram_disk_control_device_uninit_device, 1038 NULL, 1039 1040 ram_disk_control_device_open, 1041 ram_disk_control_device_close, 1042 ram_disk_control_device_free, 1043 1044 ram_disk_control_device_read, 1045 ram_disk_control_device_write, 1046 NULL, // io 1047 1048 ram_disk_control_device_control, 1049 1050 NULL, // select 1051 NULL // deselect 1052 }; 1053 1054 static const struct device_module_info sChecksumRawDeviceModule = { 1055 { 1056 kRawDeviceModuleName, 1057 0, 1058 NULL 1059 }, 1060 1061 ram_disk_raw_device_init_device, 1062 ram_disk_raw_device_uninit_device, 1063 NULL, 1064 1065 ram_disk_raw_device_open, 1066 ram_disk_raw_device_close, 1067 ram_disk_raw_device_free, 1068 1069 ram_disk_raw_device_read, 1070 ram_disk_raw_device_write, 1071 ram_disk_raw_device_io, 1072 1073 ram_disk_raw_device_control, 1074 1075 NULL, // select 1076 NULL // deselect 1077 }; 1078 1079 const module_info* modules[] = { 1080 (module_info*)&sChecksumDeviceDriverModule, 1081 (module_info*)&sChecksumControlDeviceModule, 1082 (module_info*)&sChecksumRawDeviceModule, 1083 NULL 1084 }; 1085