150120Swpaul/* 250120Swpaul * Copyright 2018-2021 Haiku, Inc. All rights reserved. 350120Swpaul * Copyright 2020, Viveris Technologies. 450120Swpaul * Distributed under the terms of the MIT License. 550120Swpaul * 650120Swpaul * Authors: 750120Swpaul * B Krishnan Iyer, krishnaniyer97@gmail.com 850120Swpaul * Adrien Destugues, pulkomandy@pulkomandy.tk 950120Swpaul */ 1050120Swpaul 1150120Swpaul#include <new> 1250120Swpaul 1350120Swpaul#include <ctype.h> 1450120Swpaul#include <stdlib.h> 1550120Swpaul#include <stdio.h> 1650120Swpaul#include <string.h> 1750120Swpaul 1850120Swpaul#include "mmc_disk.h" 1950120Swpaul#include "mmc_icon.h" 2050120Swpaul#include "mmc.h" 2150120Swpaul 2250120Swpaul#include <drivers/device_manager.h> 2350120Swpaul#include <drivers/KernelExport.h> 2450120Swpaul#include <drivers/Drivers.h> 2550120Swpaul#include <kernel/OS.h> 2650120Swpaul#include <util/fs_trim_support.h> 2750120Swpaul 2850120Swpaul#include <AutoDeleter.h> 2950120Swpaul 3050120Swpaul 3150120Swpaul#define TRACE_MMC_DISK 3250120Swpaul#ifdef TRACE_MMC_DISK 33139749Simp# define TRACE(x...) dprintf("\33[33mmmc_disk:\33[0m " x) 3450120Swpaul#else 3550120Swpaul# define TRACE(x...) ; 3650120Swpaul#endif 3750120Swpaul#define ERROR(x...) dprintf("\33[33mmmc_disk:\33[0m " x) 3850120Swpaul#define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 3950120Swpaul 4050120Swpaul#define MMC_DISK_DRIVER_MODULE_NAME "drivers/disk/mmc/mmc_disk/driver_v1" 4150120Swpaul#define MMC_DISK_DEVICE_MODULE_NAME "drivers/disk/mmc/mmc_disk/device_v1" 4250120Swpaul#define MMC_DEVICE_ID_GENERATOR "mmc/device_id" 4350120Swpaul 4450120Swpaul 4550120Swpaulstatic const uint32 kBlockSize = 512; // FIXME get it from the CSD 4650120Swpaul 4750120Swpaulstatic device_manager_info* sDeviceManager; 4850120Swpaul 4950120Swpaul 5050120Swpaulstruct mmc_disk_csd { 5150120Swpaul // The content of this register is described in Physical Layer Simplified 5250120Swpaul // Specification Version 8.00, section 5.3 5350120Swpaul uint64 bits[2]; 5450120Swpaul 5550120Swpaul uint8 structure_version() { return bits[1] >> 54; } 5650120Swpaul uint8 read_bl_len() { return (bits[1] >> 8) & 0xF; } 57129844Smarius uint32 c_size() 58129844Smarius { 59129844Smarius if (structure_version() == 0) 6050120Swpaul return ((bits[0] >> 54) & 0x3FF) | ((bits[1] & 0x3) << 10); 6150120Swpaul if (structure_version() == 1) 6250120Swpaul return (bits[0] >> 40) & 0x3FFFFF; 6350120Swpaul return ((bits[0] >> 40) & 0xFFFFFF) | ((bits[1] & 0xF) << 24); 6450120Swpaul } 6550120Swpaul 6650120Swpaul uint8 c_size_mult() 6750120Swpaul { 6850120Swpaul if (structure_version() == 0) 6950120Swpaul return (bits[0] >> 39) & 0x7; 7050120Swpaul // In later versions this field is not present in the structure and a 7150120Swpaul // fixed value is used. 7250120Swpaul return 8; 7350120Swpaul } 7450120Swpaul}; 7550120Swpaul 7650120Swpaul 7750120Swpaulstatic float 78109514Sobrienmmc_disk_supports_device(device_node* parent) 7950120Swpaul{ 8050120Swpaul // Filter all devices that are not on an MMC bus 8150120Swpaul const char* bus; 8250120Swpaul if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, 8350120Swpaul true) != B_OK) 84105135Salfred return -1; 85105135Salfred 8650120Swpaul if (strcmp(bus, "mmc") != 0) 8750120Swpaul return 0.0; 8850120Swpaul 8950120Swpaul CALLED(); 9050120Swpaul 9195722Sphk // Filter all devices that are not of the known types 9250120Swpaul uint8_t deviceType; 93229093Shselasky if (sDeviceManager->get_attr_uint8(parent, kMmcTypeAttribute, 9450120Swpaul &deviceType, true) != B_OK) 9550120Swpaul { 9650120Swpaul ERROR("Could not get device type\n"); 9750120Swpaul return -1; 9850120Swpaul } 9950120Swpaul 10050120Swpaul if (deviceType == CARD_TYPE_SD) 10150120Swpaul TRACE("SD card found, parent: %p\n", parent); 10250120Swpaul else if (deviceType == CARD_TYPE_SDHC) 10350120Swpaul TRACE("SDHC card found, parent: %p\n", parent); 10450120Swpaul else 10550120Swpaul return 0.0; 10692739Salfred 10792739Salfred return 0.8; 108164708Smarius} 10950120Swpaul 110164827Smarius 111221407Smariusstatic status_t 112164827Smariusmmc_disk_register_device(device_node* node) 113164827Smarius{ 114164827Smarius CALLED(); 115221407Smarius 116221407Smarius device_attr attrs[] = { 117221407Smarius { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "SD Card" }}, 118221407Smarius { NULL } 119221407Smarius }; 120221407Smarius 121105135Salfred return sDeviceManager->register_node(node, MMC_DISK_DRIVER_MODULE_NAME, 122150763Simp attrs, NULL, NULL); 12350120Swpaul} 12450120Swpaul 125164827Smarius 12650120Swpaulstatic status_t 12750120Swpaulmmc_disk_execute_iorequest(void* data, IOOperation* operation) 128105135Salfred{ 129150763Simp mmc_disk_driver_info* info = (mmc_disk_driver_info*)data; 13050120Swpaul status_t error; 131164708Smarius 132221407Smarius uint8_t command; 13350120Swpaul if (operation->IsWrite()) 134221407Smarius command = SD_WRITE_MULTIPLE_BLOCKS; 135221407Smarius else 13650120Swpaul command = SD_READ_MULTIPLE_BLOCKS; 137213893Smarius error = info->mmc->do_io(info->parent, info->parentCookie, info->rca, 13850120Swpaul command, operation, (info->flags & kIoCommandOffsetAsSectors) != 0); 139213893Smarius 140221407Smarius if (error != B_OK) { 141221407Smarius info->scheduler->OperationCompleted(operation, error, 0); 142164708Smarius return error; 14350120Swpaul } 14450120Swpaul 14584145Sjlemon info->scheduler->OperationCompleted(operation, B_OK, operation->Length()); 146150763Simp return B_OK; 14750120Swpaul} 14850120Swpaul 14950120Swpaul 15050120Swpaulstatic status_t 15150120Swpaulmmc_block_get_geometry(mmc_disk_driver_info* info, device_geometry* geometry) 15250120Swpaul{ 15350120Swpaul struct mmc_disk_csd csd; 15450120Swpaul TRACE("Get geometry\n"); 15550120Swpaul status_t error = info->mmc->execute_command(info->parent, 15650120Swpaul info->parentCookie, 0, SD_SEND_CSD, info->rca << 16, (uint32_t*)&csd); 15750120Swpaul if (error != B_OK) { 15850120Swpaul TRACE("Could not get CSD! %s\n", strerror(error)); 15950120Swpaul return error; 16050120Swpaul } 16150120Swpaul 16250120Swpaul TRACE("CSD: %" PRIx64 " %" PRIx64 "\n", csd.bits[0], csd.bits[1]); 16350120Swpaul 16450120Swpaul if (csd.structure_version() >= 3) { 16550120Swpaul TRACE("unknown CSD version %d\n", csd.structure_version()); 16650120Swpaul return B_NOT_SUPPORTED; 16750120Swpaul } 16850120Swpaul 16950120Swpaul geometry->bytes_per_sector = 1 << csd.read_bl_len(); 170129842Smarius geometry->sectors_per_track = csd.c_size() + 1; 17150120Swpaul geometry->cylinder_count = 1 << (csd.c_size_mult() + 2); 17250120Swpaul geometry->head_count = 1; 17350120Swpaul geometry->device_type = B_DISK; 17450120Swpaul geometry->removable = true; // TODO detect eMMC which isn't 17550120Swpaul geometry->read_only = false; // TODO check write protect switch? 17650120Swpaul geometry->write_once = false; 17750120Swpaul 17850120Swpaul // This function will be called before all data transfers, so we use this 17950120Swpaul // opportunity to switch the card to 4-bit data transfers (instead of the 18050120Swpaul // default 1 bit mode) 18150120Swpaul uint32_t cardStatus; 18250120Swpaul const uint32 k4BitMode = 2; 18350120Swpaul info->mmc->execute_command(info->parent, info->parentCookie, info->rca, 18450120Swpaul SD_APP_CMD, info->rca << 16, &cardStatus); 18574353Sjlemon info->mmc->execute_command(info->parent, info->parentCookie, info->rca, 18674353Sjlemon SD_SET_BUS_WIDTH, k4BitMode, &cardStatus); 18774353Sjlemon 18874353Sjlemon // From now on we use 4 bit mode 18974353Sjlemon info->mmc->set_bus_width(info->parent, info->parentCookie, 4); 19074353Sjlemon 19150120Swpaul return B_OK; 19250120Swpaul} 19374353Sjlemon 194164708Smarius 19577634Sjlemonstatic status_t 19674353Sjlemonmmc_disk_init_driver(device_node* node, void** cookie) 197164708Smarius{ 19850120Swpaul CALLED(); 19950120Swpaul mmc_disk_driver_info* info = (mmc_disk_driver_info*)malloc( 20050120Swpaul sizeof(mmc_disk_driver_info)); 20184145Sjlemon 20250120Swpaul if (info == NULL) 20350120Swpaul return B_NO_MEMORY; 20450120Swpaul 20550120Swpaul memset(info, 0, sizeof(*info)); 20650120Swpaul 207221407Smarius void* unused2; 20850120Swpaul info->node = node; 20950120Swpaul info->parent = sDeviceManager->get_parent_node(info->node); 21084145Sjlemon sDeviceManager->get_driver(info->parent, (driver_module_info **)&info->mmc, 21150120Swpaul &unused2); 21250120Swpaul 21350120Swpaul // We need to grab the bus cookie as well 21484145Sjlemon // FIXME it would be easier if that was available from the get_driver call 215150763Simp // above directly, but currently it isn't. 21650120Swpaul device_node* busNode = sDeviceManager->get_parent_node(info->parent); 21750120Swpaul driver_module_info* unused; 218164708Smarius sDeviceManager->get_driver(busNode, &unused, &info->parentCookie); 21950120Swpaul sDeviceManager->put_node(busNode); 22050120Swpaul 22150120Swpaul TRACE("MMC bus handle: %p %s\n", info->mmc, info->mmc->info.info.name); 22250120Swpaul 22350120Swpaul if (sDeviceManager->get_attr_uint16(node, kMmcRcaAttribute, &info->rca, 22450120Swpaul true) != B_OK) { 22550120Swpaul TRACE("MMC card node has no RCA attribute\n"); 22650120Swpaul free(info); 22750120Swpaul return B_BAD_DATA; 22850120Swpaul } 22950120Swpaul 23050120Swpaul uint8_t deviceType; 23150120Swpaul if (sDeviceManager->get_attr_uint8(info->parent, kMmcTypeAttribute, 23250120Swpaul &deviceType, true) != B_OK) { 23350120Swpaul ERROR("Could not get device type\n"); 23450120Swpaul free(info); 23550120Swpaul return B_BAD_DATA; 23650120Swpaul } 23750120Swpaul 23850120Swpaul // SD and MMC cards use byte offsets for IO commands, later ones (SDHC, 23950120Swpaul // SDXC, ...) use sectors. 24050120Swpaul if (deviceType == CARD_TYPE_SD || deviceType == CARD_TYPE_MMC) 241175705Smarius info->flags = 0; 24250120Swpaul else 24350120Swpaul info->flags = kIoCommandOffsetAsSectors; 24450120Swpaul 24550120Swpaul status_t error; 24650120Swpaul 24750120Swpaul static const uint32 kDMAResourceBufferCount = 16; 24850120Swpaul static const uint32 kDMAResourceBounceBufferCount = 16; 24950120Swpaul 25050120Swpaul info->dmaResource = new(std::nothrow) DMAResource; 25150120Swpaul if (info->dmaResource == NULL) { 25250120Swpaul TRACE("Failed to allocate DMA resource"); 25350120Swpaul free(info); 25450120Swpaul return B_NO_MEMORY; 25550120Swpaul } 25650120Swpaul 25750120Swpaul error = info->dmaResource->Init(info->node, kBlockSize, 258173665Syongari kDMAResourceBufferCount, kDMAResourceBounceBufferCount); 259173665Syongari if (error != B_OK) { 260173665Syongari TRACE("Failed to init DMA resource"); 261213384Smarius delete info->dmaResource; 26250120Swpaul free(info); 263213384Smarius return error; 26450120Swpaul } 26550120Swpaul 26650120Swpaul info->scheduler = new(std::nothrow) IOSchedulerSimple(info->dmaResource); 267213384Smarius if (info->scheduler == NULL) { 26850120Swpaul TRACE("Failed to allocate scheduler"); 26950120Swpaul delete info->dmaResource; 270221407Smarius free(info); 271221407Smarius return B_NO_MEMORY; 272221407Smarius } 27350120Swpaul 27450120Swpaul error = info->scheduler->Init("mmc storage"); 27550120Swpaul if (error != B_OK) { 27650120Swpaul TRACE("Failed to init scheduler"); 27750120Swpaul delete info->scheduler; 27850120Swpaul delete info->dmaResource; 27950120Swpaul free(info); 28050120Swpaul return error; 28150120Swpaul } 28250120Swpaul info->scheduler->SetCallback(&mmc_disk_execute_iorequest, info); 28350120Swpaul 28450120Swpaul memset(&info->geometry, 0, sizeof(info->geometry)); 28550120Swpaul 286213384Smarius TRACE("MMC card device initialized for RCA %x\n", info->rca); 28750120Swpaul *cookie = info; 288164708Smarius return B_OK; 28950120Swpaul} 290164708Smarius 291164708Smarius 292164708Smariusstatic void 293164708Smariusmmc_disk_uninit_driver(void* _cookie) 294164708Smarius{ 295164708Smarius CALLED(); 296164708Smarius mmc_disk_driver_info* info = (mmc_disk_driver_info*)_cookie; 297164708Smarius delete info->scheduler; 298164708Smarius delete info->dmaResource; 299164708Smarius sDeviceManager->put_node(info->parent); 300164708Smarius free(info); 301164708Smarius} 302164708Smarius 303164708Smarius 304175705Smariusstatic status_t 305175705Smariusmmc_disk_register_child_devices(void* _cookie) 306175705Smarius{ 307175705Smarius CALLED(); 308175705Smarius mmc_disk_driver_info* info = (mmc_disk_driver_info*)_cookie; 309164708Smarius status_t status; 310164708Smarius 311164708Smarius int32 id = sDeviceManager->create_id(MMC_DEVICE_ID_GENERATOR); 312164708Smarius if (id < 0) 313164708Smarius return id; 314164708Smarius 315164708Smarius char name[64]; 316164708Smarius snprintf(name, sizeof(name), "disk/mmc/%" B_PRId32 "/raw", id); 317164708Smarius 318164708Smarius status = sDeviceManager->publish_device(info->node, name, 319164708Smarius MMC_DISK_DEVICE_MODULE_NAME); 320164708Smarius 321164708Smarius return status; 322164708Smarius} 323164708Smarius 324164708Smarius 325164708Smarius// #pragma mark - device module API 326164708Smarius 327164708Smarius 328164708Smariusstatic status_t 329164708Smariusmmc_block_init_device(void* _info, void** _cookie) 330164708Smarius{ 331164708Smarius CALLED(); 332164708Smarius 333 // No additional context, so just reuse the same data as the disk device 334 mmc_disk_driver_info* info = (mmc_disk_driver_info*)_info; 335 *_cookie = info; 336 337 // Note: it is not possible to execute commands here, because this is called 338 // with the mmc_bus locked for enumeration (and still using slow clock). 339 340 return B_OK; 341} 342 343 344static void 345mmc_block_uninit_device(void* _cookie) 346{ 347 CALLED(); 348 //mmc_disk_driver_info* info = (mmc_disk_driver_info*)_cookie; 349 350 // TODO cleanup whatever is relevant 351} 352 353 354static status_t 355mmc_block_open(void* _info, const char* path, int openMode, void** _cookie) 356{ 357 CALLED(); 358 mmc_disk_driver_info* info = (mmc_disk_driver_info*)_info; 359 360 // allocate cookie 361 mmc_disk_handle* handle = new(std::nothrow) mmc_disk_handle; 362 *_cookie = handle; 363 if (handle == NULL) 364 return B_NO_MEMORY; 365 366 handle->info = info; 367 368 if (handle->info->geometry.bytes_per_sector == 0) { 369 status_t error = mmc_block_get_geometry(handle->info, 370 &handle->info->geometry); 371 if (error != B_OK) { 372 TRACE("Failed to get disk capacity"); 373 delete handle; 374 *_cookie = NULL; 375 return error; 376 } 377 } 378 379 return B_OK; 380} 381 382 383static status_t 384mmc_block_close(void* cookie) 385{ 386 //mmc_disk_handle* handle = (mmc_disk_handle*)cookie; 387 CALLED(); 388 389 return B_OK; 390} 391 392 393static status_t 394mmc_block_free(void* cookie) 395{ 396 CALLED(); 397 mmc_disk_handle* handle = (mmc_disk_handle*)cookie; 398 399 delete handle; 400 return B_OK; 401} 402 403 404static status_t 405mmc_block_read(void* cookie, off_t position, void* buffer, size_t* _length) 406{ 407 CALLED(); 408 mmc_disk_handle* handle = (mmc_disk_handle*)cookie; 409 410 size_t length = *_length; 411 if (position >= handle->info->DeviceSize()) 412 return ERANGE; 413 if ((position + (off_t)length) > handle->info->DeviceSize()) 414 length = (handle->info->DeviceSize() - position); 415 416 IORequest request; 417 status_t status = request.Init(position, (addr_t)buffer, length, false, 0); 418 if (status != B_OK) 419 return status; 420 421 status = handle->info->scheduler->ScheduleRequest(&request); 422 if (status != B_OK) 423 return status; 424 425 status = request.Wait(0, 0); 426 *_length = request.TransferredBytes(); 427 return status; 428} 429 430 431static status_t 432mmc_block_write(void* cookie, off_t position, const void* buffer, 433 size_t* _length) 434{ 435 CALLED(); 436 mmc_disk_handle* handle = (mmc_disk_handle*)cookie; 437 438 size_t length = *_length; 439 if (position >= handle->info->DeviceSize()) 440 return ERANGE; 441 if ((position + (off_t)length) > handle->info->DeviceSize()) 442 length = (handle->info->DeviceSize() - position); 443 444 IORequest request; 445 status_t status = request.Init(position, (addr_t)buffer, length, true, 0); 446 if (status != B_OK) 447 return status; 448 449 status = handle->info->scheduler->ScheduleRequest(&request); 450 if (status != B_OK) 451 return status; 452 453 status = request.Wait(0, 0); 454 *_length = request.TransferredBytes(); 455 return status; 456} 457 458 459static status_t 460mmc_block_io(void* cookie, io_request* request) 461{ 462 CALLED(); 463 mmc_disk_handle* handle = (mmc_disk_handle*)cookie; 464 465 if ((request->Offset() + (off_t)request->Length()) > handle->info->DeviceSize()) 466 return ERANGE; 467 468 return handle->info->scheduler->ScheduleRequest(request); 469} 470 471 472static status_t 473mmc_block_trim(mmc_disk_driver_info* info, fs_trim_data* trimData) 474{ 475 enum { 476 kEraseModeErase = 0, // force to actually erase the data 477 kEraseModeDiscard = 1, 478 // just mark the data as unused for internal wear leveling 479 // algorithms 480 kEraseModeFullErase = 2, // erase the whole card 481 }; 482 TRACE("trim_device()\n"); 483 484 trimData->trimmed_size = 0; 485 486 const off_t deviceSize = info->DeviceSize(); // in bytes 487 if (deviceSize < 0) 488 return B_BAD_VALUE; 489 490 STATIC_ASSERT(sizeof(deviceSize) <= sizeof(uint64)); 491 ASSERT(deviceSize >= 0); 492 493 // Do not trim past device end 494 for (uint32 i = 0; i < trimData->range_count; i++) { 495 uint64 offset = trimData->ranges[i].offset; 496 uint64& size = trimData->ranges[i].size; 497 498 if (offset >= (uint64)deviceSize) 499 return B_BAD_VALUE; 500 size = min_c(size, (uint64)deviceSize - offset); 501 } 502 503 uint64 trimmedSize = 0; 504 status_t result = B_OK; 505 for (uint32 i = 0; i < trimData->range_count; i++) { 506 uint64 offset = trimData->ranges[i].offset; 507 uint64 length = trimData->ranges[i].size; 508 509 // Round up offset and length to multiple of the sector size 510 // The offset is rounded up, so some space may be left 511 // (not trimmed) at the start of the range. 512 offset = ROUNDUP(offset, kBlockSize); 513 // Adjust the length for the possibly skipped range 514 length -= offset - trimData->ranges[i].offset; 515 // The length is rounded down, so some space at the end may also 516 // be left (not trimmed). 517 length &= ~(kBlockSize - 1); 518 519 if (length == 0) 520 continue; 521 522 TRACE("trim %" B_PRIu64 " bytes from %" B_PRIu64 "\n", 523 length, offset); 524 525 ASSERT(offset % kBlockSize == 0); 526 ASSERT(length % kBlockSize == 0); 527 528 if ((info->flags & kIoCommandOffsetAsSectors) != 0) { 529 offset /= kBlockSize; 530 length /= kBlockSize; 531 } 532 533 // Parameter of execute_command is uint32_t 534 if (offset > UINT32_MAX 535 || length > UINT32_MAX - offset) { 536 result = B_BAD_VALUE; 537 break; 538 } 539 540 uint32_t response; 541 result = info->mmc->execute_command(info->parent, info->parentCookie, 542 info->rca, SD_ERASE_WR_BLK_START, offset, &response); 543 if (result != B_OK) 544 break; 545 result = info->mmc->execute_command(info->parent, info->parentCookie, 546 info->rca, SD_ERASE_WR_BLK_END, offset + length, &response); 547 if (result != B_OK) 548 break; 549 result = info->mmc->execute_command(info->parent, info->parentCookie, 550 info->rca, SD_ERASE, kEraseModeDiscard, &response); 551 if (result != B_OK) 552 break; 553 554 trimmedSize += (info->flags & kIoCommandOffsetAsSectors) != 0 555 ? length * kBlockSize : length; 556 } 557 558 trimData->trimmed_size = trimmedSize; 559 560 return result; 561} 562 563 564static status_t 565mmc_block_ioctl(void* cookie, uint32 op, void* buffer, size_t length) 566{ 567 mmc_disk_handle* handle = (mmc_disk_handle*)cookie; 568 mmc_disk_driver_info* info = handle->info; 569 570 switch (op) { 571 case B_GET_MEDIA_STATUS: 572 { 573 if (buffer == NULL || length < sizeof(status_t)) 574 return B_BAD_VALUE; 575 576 status_t status = B_OK; 577 return user_memcpy(buffer, &status, sizeof(status_t)); 578 } 579 580 case B_GET_DEVICE_SIZE: 581 { 582 // Legacy ioctl, use B_GET_GEOMETRY 583 584 uint64_t size = info->DeviceSize(); 585 if (size > SIZE_MAX) 586 return B_NOT_SUPPORTED; 587 size_t size32 = size; 588 return user_memcpy(buffer, &size32, sizeof(size_t)); 589 } 590 591 case B_GET_GEOMETRY: 592 { 593 if (buffer == NULL || length > sizeof(device_geometry)) 594 return B_BAD_VALUE; 595 596 return user_memcpy(buffer, &info->geometry, length); 597 } 598 599 case B_GET_ICON_NAME: 600 return user_strlcpy((char*)buffer, "devices/drive-harddisk", 601 B_FILE_NAME_LENGTH); 602 603 case B_GET_VECTOR_ICON: 604 { 605 // TODO: take device type into account! 606 device_icon iconData; 607 if (length != sizeof(device_icon)) 608 return B_BAD_VALUE; 609 if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) 610 return B_BAD_ADDRESS; 611 612 if (iconData.icon_size >= (int32)sizeof(kDriveIcon)) { 613 if (user_memcpy(iconData.icon_data, kDriveIcon, 614 sizeof(kDriveIcon)) != B_OK) 615 return B_BAD_ADDRESS; 616 } 617 618 iconData.icon_size = sizeof(kDriveIcon); 619 return user_memcpy(buffer, &iconData, sizeof(device_icon)); 620 } 621 622 case B_TRIM_DEVICE: 623 { 624 // We know the buffer is kernel-side because it has been 625 // preprocessed in devfs 626 return mmc_block_trim(info, (fs_trim_data*)buffer); 627 } 628 629 /*case B_FLUSH_DRIVE_CACHE: 630 return synchronize_cache(info);*/ 631 } 632 633 return B_DEV_INVALID_IOCTL; 634} 635 636 637module_dependency module_dependencies[] = { 638 {B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager}, 639 {} 640}; 641 642 643// The "block device" associated with the device file. It can be open() 644// multiple times, eash allocating an mmc_disk_handle. It does not interact 645// with the hardware directly, instead it forwards all IO requests to the 646// disk driver through the IO scheduler. 647struct device_module_info sMMCBlockDevice = { 648 { 649 MMC_DISK_DEVICE_MODULE_NAME, 650 0, 651 NULL 652 }, 653 654 mmc_block_init_device, 655 mmc_block_uninit_device, 656 NULL, // remove, 657 658 mmc_block_open, 659 mmc_block_close, 660 mmc_block_free, 661 mmc_block_read, 662 mmc_block_write, 663 mmc_block_io, 664 mmc_block_ioctl, 665 666 NULL, // select 667 NULL, // deselect 668}; 669 670 671// Driver for the disk devices itself. This is paired with an 672// mmc_disk_driver_info instanciated once per device. Handles the actual disk 673// I/O operations 674struct driver_module_info sMMCDiskDriver = { 675 { 676 MMC_DISK_DRIVER_MODULE_NAME, 677 0, 678 NULL 679 }, 680 mmc_disk_supports_device, 681 mmc_disk_register_device, 682 mmc_disk_init_driver, 683 mmc_disk_uninit_driver, 684 mmc_disk_register_child_devices, 685 NULL, // mmc_disk_rescan_child_devices, 686 NULL, 687}; 688 689 690module_info* modules[] = { 691 (module_info*)&sMMCDiskDriver, 692 (module_info*)&sMMCBlockDevice, 693 NULL 694}; 695