xref: /haiku/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp (revision 553f3f2309e87d95345220463fa865d5fd8cf28d)
1 /*
2  * Copyright 2018-2020 Haiku, Inc. All rights reserved.
3  * Copyright 2020, Viveris Technologies.
4  * Distributed under the terms of the MIT License.
5  *
6  * Authors:
7  *		B Krishnan Iyer, krishnaniyer97@gmail.com
8  *		Adrien Destugues, pulkomandy@pulkomandy.tk
9  */
10 
11 #include <new>
12 
13 #include <string.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <ctype.h>
17 
18 #include "mmc_disk.h"
19 #include "mmc_icon.h"
20 #include "mmc.h"
21 
22 #include <drivers/device_manager.h>
23 #include <drivers/KernelExport.h>
24 #include <drivers/Drivers.h>
25 #include <kernel/OS.h>
26 
27 // #include <fs/devfs.h>
28 
29 #define TRACE_MMC_DISK
30 #ifdef TRACE_MMC_DISK
31 #	define TRACE(x...) dprintf("\33[33mmmc_disk:\33[0m " x)
32 #else
33 #	define TRACE(x...) ;
34 #endif
35 #define ERROR(x...)			dprintf("\33[33mmmc_disk:\33[0m " x)
36 #define CALLED() 			TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
37 
38 #define MMC_DISK_DRIVER_MODULE_NAME "drivers/disk/mmc/mmc_disk/driver_v1"
39 #define MMC_DISK_DEVICE_MODULE_NAME "drivers/disk/mmc/mmc_disk/device_v1"
40 #define MMC_DEVICE_ID_GENERATOR "mmc/device_id"
41 
42 static device_manager_info* sDeviceManager;
43 
44 
45 struct mmc_disk_csd {
46 	uint64 bits[2];
47 
48 	uint8 structure_version() { return bits[1] >> 60; }
49 	uint8 read_bl_len() { return (bits[1] >> 8) & 0xF; }
50 	uint16 c_size()
51 	{
52 		return ((bits[0] >> 54) & 0x3FF) | ((bits[1] & 0x3) << 10);
53 	}
54 	uint8 c_size_mult() { return (bits[0] >> 39) & 0x7; }
55 };
56 
57 
58 static float
59 mmc_disk_supports_device(device_node* parent)
60 {
61 	// Filter all devices that are not on an MMC bus
62 	const char* bus;
63 	if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus,
64 			true) != B_OK)
65 		return -1;
66 
67 	if (strcmp(bus, "mmc") != 0)
68 		return 0.0;
69 
70 	CALLED();
71 
72 	// Filter all devices that are not of the known types
73 	uint8_t deviceType;
74 	if (sDeviceManager->get_attr_uint8(parent, kMmcTypeAttribute,
75 			&deviceType, true) != B_OK)
76 	{
77 		ERROR("Could not get device type\n");
78 		return -1;
79 	}
80 
81 	if (deviceType == CARD_TYPE_SD)
82 		TRACE("SD card found, parent: %p\n", parent);
83 	else if (deviceType == CARD_TYPE_SDHC)
84 		TRACE("SDHC card found, parent: %p\n", parent);
85 	else
86 		return 0.0;
87 
88 	return 0.8;
89 }
90 
91 
92 static status_t
93 mmc_disk_register_device(device_node* node)
94 {
95 	CALLED();
96 
97 	device_attr attrs[] = {
98 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "SD Card" }},
99 		{ NULL }
100 	};
101 
102 	return sDeviceManager->register_node(node
103 		, MMC_DISK_DRIVER_MODULE_NAME, attrs, NULL, NULL);
104 }
105 
106 
107 static status_t
108 mmc_disk_init_driver(device_node* node, void** cookie)
109 {
110 	CALLED();
111 	mmc_disk_driver_info* info = (mmc_disk_driver_info*)malloc(
112 		sizeof(mmc_disk_driver_info));
113 
114 	if (info == NULL)
115 		return B_NO_MEMORY;
116 
117 	memset(info, 0, sizeof(*info));
118 
119 	void* unused;
120 	info->node = node;
121 	info->parent = sDeviceManager->get_parent_node(info->node);
122 	sDeviceManager->get_driver(info->parent, (driver_module_info **)&info->mmc,
123 		&unused);
124 
125 	TRACE("MMC bus handle: %p %s\n", info->mmc, info->mmc->info.info.name);
126 
127 	if (sDeviceManager->get_attr_uint16(node, kMmcRcaAttribute, &info->rca,
128 			true) != B_OK) {
129 		TRACE("MMC card node has no RCA attribute\n");
130 		free(info);
131 		return B_BAD_DATA;
132 	}
133 
134 	TRACE("MMC card device initialized for RCA %x\n", info->rca);
135 
136 	*cookie = info;
137 	return B_OK;
138 }
139 
140 
141 static void
142 mmc_disk_uninit_driver(void* _cookie)
143 {
144 	CALLED();
145 	mmc_disk_driver_info* info = (mmc_disk_driver_info*)_cookie;
146 	sDeviceManager->put_node(info->parent);
147 	free(info);
148 }
149 
150 
151 static status_t
152 mmc_disk_register_child_devices(void* _cookie)
153 {
154 	CALLED();
155 	mmc_disk_driver_info* info = (mmc_disk_driver_info*)_cookie;
156 	status_t status;
157 
158 	int32 id = sDeviceManager->create_id(MMC_DEVICE_ID_GENERATOR);
159 	if (id < 0)
160 		return id;
161 
162 	char name[64];
163 	snprintf(name, sizeof(name), "disk/mmc/%" B_PRId32 "/raw", id);
164 
165 	status = sDeviceManager->publish_device(info->node, name,
166 		MMC_DISK_DEVICE_MODULE_NAME);
167 
168 	return status;
169 }
170 
171 
172 //	#pragma mark - device module API
173 
174 
175 static status_t
176 mmc_block_init_device(void* _info, void** _cookie)
177 {
178 	CALLED();
179 
180 	// No additional context, so just reuse the same data as the disk device
181 	mmc_disk_driver_info* info = (mmc_disk_driver_info*)_info;
182 	*_cookie = info;
183 
184 	return B_OK;
185 }
186 
187 
188 static void
189 mmc_block_uninit_device(void* _cookie)
190 {
191 	CALLED();
192 	//mmc_disk_driver_info* info = (mmc_disk_driver_info*)_cookie;
193 
194 	// TODO cleanup whatever is relevant
195 }
196 
197 
198 static status_t
199 mmc_block_open(void* _info, const char* path, int openMode, void** _cookie)
200 {
201 	CALLED();
202 	mmc_disk_driver_info* info = (mmc_disk_driver_info*)_info;
203 
204 	// allocate cookie
205 	mmc_disk_handle* handle = new(std::nothrow) mmc_disk_handle;
206 	*_cookie = handle;
207 	if (handle == NULL) {
208 		return B_NO_MEMORY;
209 	}
210 	handle->info = info;
211 
212 	return B_OK;
213 }
214 
215 
216 static status_t
217 mmc_block_close(void* cookie)
218 {
219 	mmc_disk_handle* handle = (mmc_disk_handle*)cookie;
220 	CALLED();
221 
222 	return B_OK;
223 }
224 
225 
226 static status_t
227 mmc_block_free(void* cookie)
228 {
229 	CALLED();
230 	mmc_disk_handle* handle = (mmc_disk_handle*)cookie;
231 
232 	delete handle;
233 	return B_OK;
234 }
235 
236 
237 static status_t
238 mmc_block_read(void* cookie, off_t pos, void* buffer, size_t* _length)
239 {
240 	CALLED();
241 	mmc_disk_handle* handle = (mmc_disk_handle*)cookie;
242 	TRACE("Ready to execute %p\n", handle->info->mmc->read_naive);
243 	return handle->info->mmc->read_naive(handle->info->parent, handle->info->rca, pos, buffer, _length);
244 }
245 
246 
247 static status_t
248 mmc_block_write(void* cookie, off_t position, const void* buffer,
249 	size_t* length)
250 {
251 	CALLED();
252 	mmc_disk_handle* handle = (mmc_disk_handle*)cookie;
253 
254 	return B_NOT_SUPPORTED;
255 }
256 
257 
258 static status_t
259 mmc_block_io(void* cookie, io_request* request)
260 {
261 	CALLED();
262 	mmc_disk_handle* handle = (mmc_disk_handle*)cookie;
263 
264 	return B_NOT_SUPPORTED;
265 }
266 
267 
268 static status_t
269 mmc_block_get_geometry(mmc_disk_handle* handle, device_geometry* geometry)
270 {
271 	struct mmc_disk_csd csd;
272 	TRACE("Ready to execute %p\n", handle->info->mmc->execute_command);
273 	handle->info->mmc->execute_command(handle->info->parent, SD_SEND_CSD,
274 		handle->info->rca << 16, (uint32_t*)&csd);
275 
276 	TRACE("CSD: %lx %lx\n", csd.bits[0], csd.bits[1]);
277 
278 	if (csd.structure_version() == 0) {
279 		geometry->bytes_per_sector = 1 << csd.read_bl_len();
280 		geometry->sectors_per_track = csd.c_size() + 1;
281 		geometry->cylinder_count = 1 << (csd.c_size_mult() + 2);
282 		geometry->head_count = 1;
283 		geometry->device_type = B_DISK;
284 		geometry->removable = true; // TODO detect eMMC which isn't
285 		geometry->read_only = true; // TODO add write support
286 		geometry->write_once = false;
287 		return B_OK;
288 	}
289 
290 	TRACE("unknown CSD version %d\n", csd.structure_version());
291 	return B_NOT_SUPPORTED;
292 }
293 
294 
295 static status_t
296 mmc_block_ioctl(void* cookie, uint32 op, void* buffer, size_t length)
297 {
298 	CALLED();
299 	mmc_disk_handle* handle = (mmc_disk_handle*)cookie;
300 	mmc_disk_driver_info* info = handle->info;
301 
302 	TRACE("ioctl(op = %" B_PRId32 ")\n", op);
303 
304 	switch (op) {
305 		case B_GET_MEDIA_STATUS:
306 		{
307 			if (buffer == NULL || length < sizeof(status_t))
308 				return B_BAD_VALUE;
309 
310 			*(status_t *)buffer = B_OK;
311 			TRACE("B_GET_MEDIA_STATUS: 0x%08" B_PRIx32 "\n",
312 				*(status_t *)buffer);
313 			return B_OK;
314 			break;
315 		}
316 
317 		case B_GET_DEVICE_SIZE:
318 		{
319 			//size_t size = info->capacity * info->block_size;
320 			//return user_memcpy(buffer, &size, sizeof(size_t));
321 			return B_NOT_SUPPORTED;
322 		}
323 
324 		case B_GET_GEOMETRY:
325 		{
326 			if (buffer == NULL || length < sizeof(device_geometry))
327 				return B_BAD_VALUE;
328 
329 		 	device_geometry geometry;
330 			status_t status = mmc_block_get_geometry(handle, &geometry);
331 			if (status != B_OK)
332 				return status;
333 
334 			return user_memcpy(buffer, &geometry, sizeof(device_geometry));
335 		}
336 
337 		case B_GET_ICON_NAME:
338 			return user_strlcpy((char*)buffer, "devices/drive-harddisk",
339 				B_FILE_NAME_LENGTH);
340 
341 		case B_GET_VECTOR_ICON:
342 		{
343 			// TODO: take device type into account!
344 			device_icon iconData;
345 			if (length != sizeof(device_icon))
346 				return B_BAD_VALUE;
347 			if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK)
348 				return B_BAD_ADDRESS;
349 
350 			if (iconData.icon_size >= (int32)sizeof(kDriveIcon)) {
351 				if (user_memcpy(iconData.icon_data, kDriveIcon,
352 						sizeof(kDriveIcon)) != B_OK)
353 					return B_BAD_ADDRESS;
354 			}
355 
356 			iconData.icon_size = sizeof(kDriveIcon);
357 			return user_memcpy(buffer, &iconData, sizeof(device_icon));
358 		}
359 
360 		/*case B_FLUSH_DRIVE_CACHE:
361 			return synchronize_cache(info);*/
362 	}
363 
364 	return B_DEV_INVALID_IOCTL;
365 }
366 
367 
368 module_dependency module_dependencies[] = {
369 	{B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager},
370 	{}
371 };
372 
373 
374 // The "block device" associated with the device file. It can be open()
375 // multiple times, eash allocating an mmc_disk_handle. It does not interact
376 // with the hardware directly, instead it forwards all IO requests to the
377 // disk driver through the IO scheduler.
378 struct device_module_info sMMCBlockDevice = {
379 	{
380 		MMC_DISK_DEVICE_MODULE_NAME,
381 		0,
382 		NULL
383 	},
384 
385 	mmc_block_init_device,
386 	mmc_block_uninit_device,
387 	NULL, // remove,
388 
389 	mmc_block_open,
390 	mmc_block_close,
391 	mmc_block_free,
392 	mmc_block_read,
393 	mmc_block_write,
394 	mmc_block_io,
395 	mmc_block_ioctl,
396 
397 	NULL,	// select
398 	NULL,	// deselect
399 };
400 
401 
402 // Driver for the disk devices itself. This is paired with an
403 // mmc_disk_driver_info instanciated once per device. Handles the actual disk
404 // I/O operations
405 struct driver_module_info sMMCDiskDriver = {
406 	{
407 		MMC_DISK_DRIVER_MODULE_NAME,
408 		0,
409 		NULL
410 	},
411 	mmc_disk_supports_device,
412 	mmc_disk_register_device,
413 	mmc_disk_init_driver,
414 	mmc_disk_uninit_driver,
415 	mmc_disk_register_child_devices,
416 	NULL, // mmc_disk_rescan_child_devices,
417 	NULL,
418 };
419 
420 
421 module_info* modules[] = {
422 	(module_info*)&sMMCDiskDriver,
423 	(module_info*)&sMMCBlockDevice,
424 	NULL
425 };
426