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