xref: /haiku/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp (revision 60b39cd7416028e61e3d30bb3ba28bd3526e6001)
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