xref: /haiku/src/tests/kits/storage/virtualdrive/virtualdrive.cpp (revision 2ca1376080f866aafba1edc95eaa036b92ed2078)
17a424c39SIngo Weinhold // ----------------------------------------------------------------------
2*2ca13760SColdfirex //  This software is part of the Haiku distribution and is covered
3b6f76ebeSAugustin Cavalier //  by the MIT License.
47a424c39SIngo Weinhold //
57a424c39SIngo Weinhold //  File Name:		virtualdrive.c
67a424c39SIngo Weinhold //
77a424c39SIngo Weinhold //	Description:	Driver that emulates virtual drives.
87a424c39SIngo Weinhold //
97a424c39SIngo Weinhold //	Author:			Marcus Overhagen <Marcus@Overhagen.de>
107a424c39SIngo Weinhold //					Ingo Weinhold <bonefish@users.sf.net>
11bc4f7808SAxel Dörfler //					Axel Doerfler <axeld@pinc-software.de>
127a424c39SIngo Weinhold // ----------------------------------------------------------------------
137a424c39SIngo Weinhold 
147a424c39SIngo Weinhold #include <fcntl.h>
157a424c39SIngo Weinhold #include <errno.h>
167a424c39SIngo Weinhold #include <malloc.h>
177a424c39SIngo Weinhold #include <stdio.h>
187a424c39SIngo Weinhold #include <string.h>
197a424c39SIngo Weinhold #include <unistd.h>
207a424c39SIngo Weinhold 
217a424c39SIngo Weinhold #include <KernelExport.h>
227a424c39SIngo Weinhold #include <Drivers.h>
237a424c39SIngo Weinhold #include <Errors.h>
247a424c39SIngo Weinhold 
257a424c39SIngo Weinhold #include "lock.h"
267a424c39SIngo Weinhold #include "virtualdrive.h"
27bc4f7808SAxel Dörfler #include "virtualdrive_icon.h"
287a424c39SIngo Weinhold 
297a424c39SIngo Weinhold /*
307a424c39SIngo Weinhold [2:07] <geist> when you open the file in the driver, use stat() to see if it's a file. if it is, call ioctl 10000 on the underlying file
317a424c39SIngo Weinhold [2:07] <geist> that's the disable-cache ioctl
327a424c39SIngo Weinhold [2:08] <geist> bfs is probably doing the same algorithm, and seeing that you are a device and not a file, and so it doesn't call 10000 on you
337a424c39SIngo Weinhold [2:08] <marcus_o> thanks, I will try calling it
347a424c39SIngo Weinhold [2:08] <geist> and dont bother using dosfs as a host fs, it wont work
357a424c39SIngo Weinhold [2:09] <geist> bfs is the only fs that's reasonably safe being reentered like that, but only if the underlying one is opened with the cache disabled on that file
367a424c39SIngo Weinhold [2:09] <geist> that ioctl is used on the swap file as well
377a424c39SIngo Weinhold [2:10] <marcus_o> I'm currently allocating memory in the driver's write() function hook
387a424c39SIngo Weinhold [2:10] <geist> cant do that
397a424c39SIngo Weinhold */
407a424c39SIngo Weinhold 
418545b8bdSAxel Dörfler //#define TRACE(x) dprintf x
428545b8bdSAxel Dörfler #define TRACE(x) ;
437a424c39SIngo Weinhold #define MB (1024LL * 1024LL)
447a424c39SIngo Weinhold 
457a424c39SIngo Weinhold static int dev_index_for_path(const char *path);
467a424c39SIngo Weinhold 
477a424c39SIngo Weinhold /* -----
487a424c39SIngo Weinhold 	null-terminated array of device names supported by this driver
497a424c39SIngo Weinhold ----- */
507a424c39SIngo Weinhold 
51bc4f7808SAxel Dörfler static const char *sVirtualDriveName[] = {
527a424c39SIngo Weinhold 	VIRTUAL_DRIVE_DIRECTORY_REL "/0",
537a424c39SIngo Weinhold 	VIRTUAL_DRIVE_DIRECTORY_REL "/1",
547a424c39SIngo Weinhold 	VIRTUAL_DRIVE_DIRECTORY_REL "/2",
557a424c39SIngo Weinhold 	VIRTUAL_DRIVE_DIRECTORY_REL "/3",
567a424c39SIngo Weinhold 	VIRTUAL_DRIVE_DIRECTORY_REL "/4",
577a424c39SIngo Weinhold 	VIRTUAL_DRIVE_DIRECTORY_REL "/5",
587a424c39SIngo Weinhold 	VIRTUAL_DRIVE_DIRECTORY_REL "/6",
597a424c39SIngo Weinhold 	VIRTUAL_DRIVE_DIRECTORY_REL "/7",
607a424c39SIngo Weinhold 	VIRTUAL_DRIVE_DIRECTORY_REL "/8",
617a424c39SIngo Weinhold 	VIRTUAL_DRIVE_DIRECTORY_REL "/9",
627a424c39SIngo Weinhold 	VIRTUAL_DRIVE_CONTROL_DEVICE_REL,
637a424c39SIngo Weinhold 	NULL
647a424c39SIngo Weinhold };
657a424c39SIngo Weinhold 
667a424c39SIngo Weinhold int32 api_version = B_CUR_DRIVER_API_VERSION;
67bc4f7808SAxel Dörfler extern device_hooks sVirtualDriveHooks;
687a424c39SIngo Weinhold 
697a424c39SIngo Weinhold lock driverlock;
707a424c39SIngo Weinhold 
717a424c39SIngo Weinhold typedef struct device_info {
72bc4f7808SAxel Dörfler 	int32			open_count;
737a424c39SIngo Weinhold 	int				fd;
747a424c39SIngo Weinhold 	off_t			size;
757a424c39SIngo Weinhold 	bool			unused;
767a424c39SIngo Weinhold 	bool			registered;
777a424c39SIngo Weinhold 	char			file[B_PATH_NAME_LENGTH];
787a424c39SIngo Weinhold 	const char		*device_path;
797a424c39SIngo Weinhold 	device_geometry	geometry;
807a424c39SIngo Weinhold } device_info;
817a424c39SIngo Weinhold 
827a424c39SIngo Weinhold #define kDeviceCount		11
837a424c39SIngo Weinhold #define kDataDeviceCount	(kDeviceCount - 1)
847a424c39SIngo Weinhold #define kControlDevice		(kDeviceCount - 1)
857a424c39SIngo Weinhold struct device_info			gDeviceInfos[kDeviceCount];
867a424c39SIngo Weinhold 
877a424c39SIngo Weinhold static int32		gRegistrationCount	= 0;
887a424c39SIngo Weinhold static int			gControlDeviceFD	= -1;
897a424c39SIngo Weinhold 
907a424c39SIngo Weinhold static thread_id	gLockOwner			= -1;
917a424c39SIngo Weinhold static int32		gLockOwnerNesting	= 0;
927a424c39SIngo Weinhold 
93bc4f7808SAxel Dörfler 
947a424c39SIngo Weinhold // lock_driver
957a424c39SIngo Weinhold void
967a424c39SIngo Weinhold lock_driver()
977a424c39SIngo Weinhold {
987a424c39SIngo Weinhold 	thread_id thread = find_thread(NULL);
997a424c39SIngo Weinhold 	if (gLockOwner != thread) {
1007a424c39SIngo Weinhold 		LOCK(driverlock);
1017a424c39SIngo Weinhold 		gLockOwner = thread;
1027a424c39SIngo Weinhold 	}
1037a424c39SIngo Weinhold 	gLockOwnerNesting++;
1047a424c39SIngo Weinhold }
1057a424c39SIngo Weinhold 
106bc4f7808SAxel Dörfler 
1077a424c39SIngo Weinhold // unlock_driver
1087a424c39SIngo Weinhold void
1097a424c39SIngo Weinhold unlock_driver()
1107a424c39SIngo Weinhold {
1117a424c39SIngo Weinhold 	thread_id thread = find_thread(NULL);
1127a424c39SIngo Weinhold 	if (gLockOwner == thread && --gLockOwnerNesting == 0) {
1137a424c39SIngo Weinhold 		gLockOwner = -1;
1147a424c39SIngo Weinhold 		UNLOCK(driverlock);
1157a424c39SIngo Weinhold 	}
1167a424c39SIngo Weinhold }
1177a424c39SIngo Weinhold 
1187a424c39SIngo Weinhold 
1197a424c39SIngo Weinhold // is_valid_device_index
1207a424c39SIngo Weinhold static inline
1217a424c39SIngo Weinhold bool
1227a424c39SIngo Weinhold is_valid_device_index(int32 index)
1237a424c39SIngo Weinhold {
1247a424c39SIngo Weinhold 	return (index >= 0 && index < kDeviceCount);
1257a424c39SIngo Weinhold }
1267a424c39SIngo Weinhold 
127bc4f7808SAxel Dörfler 
1287a424c39SIngo Weinhold // is_valid_data_device_index
1297a424c39SIngo Weinhold static inline
1307a424c39SIngo Weinhold bool
1317a424c39SIngo Weinhold is_valid_data_device_index(int32 index)
1327a424c39SIngo Weinhold {
1337a424c39SIngo Weinhold 	return (is_valid_device_index(index) && index != kControlDevice);
1347a424c39SIngo Weinhold }
1357a424c39SIngo Weinhold 
136bc4f7808SAxel Dörfler 
137bc4f7808SAxel Dörfler // dev_index_for_path
138bc4f7808SAxel Dörfler static
139bc4f7808SAxel Dörfler int
140bc4f7808SAxel Dörfler dev_index_for_path(const char *path)
141bc4f7808SAxel Dörfler {
142bc4f7808SAxel Dörfler 	int i;
143bc4f7808SAxel Dörfler 	for (i = 0; i < kDeviceCount; i++) {
144bc4f7808SAxel Dörfler 		if (!strcmp(path, gDeviceInfos[i].device_path))
145bc4f7808SAxel Dörfler 			return i;
146bc4f7808SAxel Dörfler 	}
147bc4f7808SAxel Dörfler 	return -1;
148bc4f7808SAxel Dörfler }
149bc4f7808SAxel Dörfler 
150bc4f7808SAxel Dörfler 
1517a424c39SIngo Weinhold // clear_device_info
1527a424c39SIngo Weinhold static
1537a424c39SIngo Weinhold void
1547a424c39SIngo Weinhold clear_device_info(int32 index)
1557a424c39SIngo Weinhold {
1568545b8bdSAxel Dörfler 	TRACE(("virtualdrive: clear_device_info(%ld)\n", index));
157bc4f7808SAxel Dörfler 
1587a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[index];
159bc4f7808SAxel Dörfler 	info.open_count = 0;
1607a424c39SIngo Weinhold 	info.fd = -1;
1617a424c39SIngo Weinhold 	info.size = 0;
1627a424c39SIngo Weinhold 	info.unused = (index != kDeviceCount - 1);
1637a424c39SIngo Weinhold 	info.registered = !info.unused;
1647a424c39SIngo Weinhold 	info.file[0] = '\0';
165bc4f7808SAxel Dörfler 	info.device_path = sVirtualDriveName[index];
1667a424c39SIngo Weinhold 	info.geometry.read_only = true;
1677a424c39SIngo Weinhold }
1687a424c39SIngo Weinhold 
169bc4f7808SAxel Dörfler 
1707a424c39SIngo Weinhold // init_device_info
1717a424c39SIngo Weinhold static
1727a424c39SIngo Weinhold status_t
1737a424c39SIngo Weinhold init_device_info(int32 index, virtual_drive_info *initInfo)
1747a424c39SIngo Weinhold {
1757a424c39SIngo Weinhold 	if (!is_valid_data_device_index(index) || !initInfo)
1767a424c39SIngo Weinhold 		return B_BAD_VALUE;
177bc4f7808SAxel Dörfler 
1787a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[index];
1797a424c39SIngo Weinhold 	if (!info.unused)
1807a424c39SIngo Weinhold 		return B_BAD_VALUE;
181bc4f7808SAxel Dörfler 
1827a424c39SIngo Weinhold 	bool readOnly = (initInfo->use_geometry && initInfo->geometry.read_only);
183bc4f7808SAxel Dörfler 
1847a424c39SIngo Weinhold 	// open the file
1857a424c39SIngo Weinhold 	int fd = open(initInfo->file_name, (readOnly ? O_RDONLY : O_RDWR));
1867a424c39SIngo Weinhold 	if (fd < 0)
1877a424c39SIngo Weinhold 		return errno;
188bc4f7808SAxel Dörfler 
1897a424c39SIngo Weinhold 	status_t error = B_OK;
190bc4f7808SAxel Dörfler 
1917a424c39SIngo Weinhold 	// get the file size
1927a424c39SIngo Weinhold 	off_t fileSize = 0;
1937a424c39SIngo Weinhold 	struct stat st;
1947a424c39SIngo Weinhold 	if (fstat(fd, &st) == 0)
1957a424c39SIngo Weinhold 		fileSize = st.st_size;
1967a424c39SIngo Weinhold 	else
1977a424c39SIngo Weinhold 		error = errno;
198bc4f7808SAxel Dörfler 
1997a424c39SIngo Weinhold 	// If we shall use the supplied geometry, we enlarge the file, if
2007a424c39SIngo Weinhold 	// necessary. Otherwise we fill in the geometry according to the size of the file.
2017a424c39SIngo Weinhold 	off_t size = 0;
2027a424c39SIngo Weinhold 	if (error == B_OK) {
2037a424c39SIngo Weinhold 		if (initInfo->use_geometry) {
2047a424c39SIngo Weinhold 			// use the supplied geometry
2057a424c39SIngo Weinhold 			info.geometry = initInfo->geometry;
2067a424c39SIngo Weinhold 			size = (off_t)info.geometry.bytes_per_sector
2077a424c39SIngo Weinhold 				* info.geometry.sectors_per_track
2087a424c39SIngo Weinhold 				* info.geometry.cylinder_count
2097a424c39SIngo Weinhold 				* info.geometry.head_count;
2107a424c39SIngo Weinhold 			if (size > fileSize) {
2117a424c39SIngo Weinhold 				if (!readOnly) {
2127a424c39SIngo Weinhold 					if (ftruncate(fd, size) != 0)
2137a424c39SIngo Weinhold 						error = errno;
2147a424c39SIngo Weinhold 				} else
2157a424c39SIngo Weinhold 					error = B_NOT_ALLOWED;
2167a424c39SIngo Weinhold 			}
2177a424c39SIngo Weinhold 		} else {
2187a424c39SIngo Weinhold 			// fill in the geometry
2197a424c39SIngo Weinhold 			// default to 512 bytes block size
2207a424c39SIngo Weinhold 			uint32 blockSize = 512;
2217a424c39SIngo Weinhold 			// Optimally we have only 1 block per sector and only one head.
2227a424c39SIngo Weinhold 			// Since we have only a uint32 for the cylinder count, this won't work
2237a424c39SIngo Weinhold 			// for files > 2TB. So, we set the head count to the minimally possible
2247a424c39SIngo Weinhold 			// value.
2257a424c39SIngo Weinhold 			off_t blocks = fileSize / blockSize;
2267a424c39SIngo Weinhold 			uint32 heads = (blocks + ULONG_MAX - 1) / ULONG_MAX;
2277a424c39SIngo Weinhold 			if (heads == 0)
2287a424c39SIngo Weinhold 				heads = 1;
2297a424c39SIngo Weinhold 			info.geometry.bytes_per_sector = blockSize;
2307a424c39SIngo Weinhold 		    info.geometry.sectors_per_track = 1;
2317a424c39SIngo Weinhold 		    info.geometry.cylinder_count = blocks / heads;
2327a424c39SIngo Weinhold 		    info.geometry.head_count = heads;
2337a424c39SIngo Weinhold 		    info.geometry.device_type = B_DISK;	// TODO: Add a new constant.
2347a424c39SIngo Weinhold 		    info.geometry.removable = false;
2357a424c39SIngo Weinhold 		    info.geometry.read_only = false;
2367a424c39SIngo Weinhold 		    info.geometry.write_once = false;
2377a424c39SIngo Weinhold 			size = (off_t)info.geometry.bytes_per_sector
2387a424c39SIngo Weinhold 				* info.geometry.sectors_per_track
2397a424c39SIngo Weinhold 				* info.geometry.cylinder_count
2407a424c39SIngo Weinhold 				* info.geometry.head_count;
2417a424c39SIngo Weinhold 		}
2427a424c39SIngo Weinhold 	}
243bc4f7808SAxel Dörfler 
244bc4f7808SAxel Dörfler 	if (error == B_OK) {
245bc4f7808SAxel Dörfler 		// Disable caching for underlying file! (else this driver will deadlock)
246bc4f7808SAxel Dörfler 		// We probably cannot resize the file once the cache has been disabled!
247bc4f7808SAxel Dörfler 
248b4f58628SAxel Dörfler 		// This applies to BeOS only:
249b4f58628SAxel Dörfler 		// Work around a bug in BFS: the file is not synced before the cache is
250b4f58628SAxel Dörfler 		// turned off, and thus causing possible inconsistencies.
251b4f58628SAxel Dörfler 		// Unfortunately, this only solves one half of the issue; there is
252b4f58628SAxel Dörfler 		// no way to remove the blocks in the cache, so changes made to the
253b4f58628SAxel Dörfler 		// image have the chance to get lost.
254b4f58628SAxel Dörfler 		fsync(fd);
255b4f58628SAxel Dörfler 
256bc4f7808SAxel Dörfler 		// This is a special reserved ioctl() opcode not defined anywhere in
257bc4f7808SAxel Dörfler 		// the Be headers.
258bc4f7808SAxel Dörfler 		if (ioctl(fd, 10000) != 0) {
2598545b8bdSAxel Dörfler 			dprintf("virtualdrive: disable caching ioctl failed\n");
260bc4f7808SAxel Dörfler 			return errno;
261bc4f7808SAxel Dörfler 		}
262bc4f7808SAxel Dörfler 	}
263bc4f7808SAxel Dörfler 
2647a424c39SIngo Weinhold 	// fill in the rest of the device_info structure
2657a424c39SIngo Weinhold 	if (error == B_OK) {
266bc4f7808SAxel Dörfler 		// open_count doesn't have to be changed here (virtualdrive_open() will do that for us)
2677a424c39SIngo Weinhold 		info.fd = fd;
2687a424c39SIngo Weinhold 		info.size = size;
2697a424c39SIngo Weinhold 		info.unused = false;
2707a424c39SIngo Weinhold 		info.registered = true;
2717a424c39SIngo Weinhold 		strcpy(info.file, initInfo->file_name);
272bc4f7808SAxel Dörfler 		info.device_path = sVirtualDriveName[index];
2737a424c39SIngo Weinhold 	} else {
2747a424c39SIngo Weinhold 		// cleanup on error
2757a424c39SIngo Weinhold 		close(fd);
276bc4f7808SAxel Dörfler 		if (info.open_count == 0)
2777a424c39SIngo Weinhold 			clear_device_info(index);
2787a424c39SIngo Weinhold 	}
2797a424c39SIngo Weinhold 	return error;
2807a424c39SIngo Weinhold }
2817a424c39SIngo Weinhold 
282bc4f7808SAxel Dörfler 
2837a424c39SIngo Weinhold // uninit_device_info
2847a424c39SIngo Weinhold static
2857a424c39SIngo Weinhold status_t
2867a424c39SIngo Weinhold uninit_device_info(int32 index)
2877a424c39SIngo Weinhold {
2887a424c39SIngo Weinhold 	if (!is_valid_data_device_index(index))
2897a424c39SIngo Weinhold 		return B_BAD_VALUE;
290bc4f7808SAxel Dörfler 
2917a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[index];
2927a424c39SIngo Weinhold 	if (info.unused)
2937a424c39SIngo Weinhold 		return B_BAD_VALUE;
294bc4f7808SAxel Dörfler 
2957a424c39SIngo Weinhold 	close(info.fd);
2967a424c39SIngo Weinhold 	clear_device_info(index);
2977a424c39SIngo Weinhold 	return B_OK;
2987a424c39SIngo Weinhold }
2997a424c39SIngo Weinhold 
300bc4f7808SAxel Dörfler 
301bc4f7808SAxel Dörfler //	#pragma mark -
302bc4f7808SAxel Dörfler //	public driver API
303bc4f7808SAxel Dörfler 
304bc4f7808SAxel Dörfler 
3057a424c39SIngo Weinhold status_t
3067a424c39SIngo Weinhold init_hardware(void)
3077a424c39SIngo Weinhold {
3088545b8bdSAxel Dörfler 	TRACE(("virtualdrive: init_hardware\n"));
3097a424c39SIngo Weinhold 	return B_OK;
3107a424c39SIngo Weinhold }
3117a424c39SIngo Weinhold 
3127a424c39SIngo Weinhold 
3137a424c39SIngo Weinhold status_t
3147a424c39SIngo Weinhold init_driver(void)
3157a424c39SIngo Weinhold {
3168545b8bdSAxel Dörfler 	TRACE(("virtualdrive: init\n"));
3177a424c39SIngo Weinhold 
3187a424c39SIngo Weinhold 	new_lock(&driverlock, "virtualdrive lock");
3197a424c39SIngo Weinhold 
3207a424c39SIngo Weinhold 	// init the device infos
3217a424c39SIngo Weinhold 	for (int32 i = 0; i < kDeviceCount; i++)
3227a424c39SIngo Weinhold 		clear_device_info(i);
3237a424c39SIngo Weinhold 
3247a424c39SIngo Weinhold 	return B_OK;
3257a424c39SIngo Weinhold }
3267a424c39SIngo Weinhold 
3277a424c39SIngo Weinhold 
3287a424c39SIngo Weinhold void
3297a424c39SIngo Weinhold uninit_driver(void)
3307a424c39SIngo Weinhold {
3318545b8bdSAxel Dörfler 	TRACE(("virtualdrive: uninit\n"));
3327a424c39SIngo Weinhold 	free_lock(&driverlock);
3337a424c39SIngo Weinhold }
3347a424c39SIngo Weinhold 
3357a424c39SIngo Weinhold 
336bc4f7808SAxel Dörfler const char **
337bc4f7808SAxel Dörfler publish_devices(void)
338bc4f7808SAxel Dörfler {
3398545b8bdSAxel Dörfler 	TRACE(("virtualdrive: publish_devices\n"));
340bc4f7808SAxel Dörfler 	return sVirtualDriveName;
341bc4f7808SAxel Dörfler }
342bc4f7808SAxel Dörfler 
343bc4f7808SAxel Dörfler 
344bc4f7808SAxel Dörfler device_hooks *
345bc4f7808SAxel Dörfler find_device(const char* name)
346bc4f7808SAxel Dörfler {
3478545b8bdSAxel Dörfler 	TRACE(("virtualdrive: find_device(%s)\n", name));
348bc4f7808SAxel Dörfler 	return &sVirtualDriveHooks;
349bc4f7808SAxel Dörfler }
350bc4f7808SAxel Dörfler 
351bc4f7808SAxel Dörfler 
352bc4f7808SAxel Dörfler //	#pragma mark -
353bc4f7808SAxel Dörfler //	the device hooks
354bc4f7808SAxel Dörfler 
3557a424c39SIngo Weinhold 
3567a424c39SIngo Weinhold static status_t
3577a424c39SIngo Weinhold virtualdrive_open(const char *name, uint32 flags, void **cookie)
3587a424c39SIngo Weinhold {
3598545b8bdSAxel Dörfler 	TRACE(("virtualdrive: open %s\n",name));
3607a424c39SIngo Weinhold 
3617a424c39SIngo Weinhold 	*cookie = (void *)-1;
3627a424c39SIngo Weinhold 
3637a424c39SIngo Weinhold 	lock_driver();
3647a424c39SIngo Weinhold 
3657a424c39SIngo Weinhold 	int32 devIndex = dev_index_for_path(name);
3667a424c39SIngo Weinhold 
3678545b8bdSAxel Dörfler 	TRACE(("virtualdrive: devIndex %ld!\n", devIndex));
3687a424c39SIngo Weinhold 
3697a424c39SIngo Weinhold 	if (!is_valid_device_index(devIndex)) {
3708545b8bdSAxel Dörfler 		TRACE(("virtualdrive: wrong index!\n"));
3717a424c39SIngo Weinhold 		unlock_driver();
3727a424c39SIngo Weinhold 		return B_ERROR;
3737a424c39SIngo Weinhold 	}
3747a424c39SIngo Weinhold 
3757a424c39SIngo Weinhold 	if (gDeviceInfos[devIndex].unused) {
3768545b8bdSAxel Dörfler 		TRACE(("virtualdrive: device is unused!\n"));
3777a424c39SIngo Weinhold 		unlock_driver();
3787a424c39SIngo Weinhold 		return B_ERROR;
3797a424c39SIngo Weinhold 	}
3807a424c39SIngo Weinhold 
3817a424c39SIngo Weinhold 	if (!gDeviceInfos[devIndex].registered) {
3828545b8bdSAxel Dörfler 		TRACE(("virtualdrive: device has been unregistered!\n"));
3837a424c39SIngo Weinhold 		unlock_driver();
3847a424c39SIngo Weinhold 		return B_ERROR;
3857a424c39SIngo Weinhold 	}
3867a424c39SIngo Weinhold 
3877a424c39SIngo Weinhold 	// store index in cookie
3887a424c39SIngo Weinhold 	*cookie = (void *)devIndex;
3897a424c39SIngo Weinhold 
390bc4f7808SAxel Dörfler 	gDeviceInfos[devIndex].open_count++;
3917a424c39SIngo Weinhold 
3927a424c39SIngo Weinhold 	unlock_driver();
3937a424c39SIngo Weinhold 	return B_OK;
3947a424c39SIngo Weinhold }
3957a424c39SIngo Weinhold 
3967a424c39SIngo Weinhold 
3977a424c39SIngo Weinhold static status_t
3987a424c39SIngo Weinhold virtualdrive_close(void *cookie)
3997a424c39SIngo Weinhold {
4007a424c39SIngo Weinhold 	int32 devIndex = (int)cookie;
4017a424c39SIngo Weinhold 
4028545b8bdSAxel Dörfler 	TRACE(("virtualdrive: close() devIndex = %ld\n", devIndex));
4037a424c39SIngo Weinhold 	if (!is_valid_data_device_index(devIndex))
4047a424c39SIngo Weinhold 		return B_OK;
4057a424c39SIngo Weinhold 
4067a424c39SIngo Weinhold 	lock_driver();
4077a424c39SIngo Weinhold 
408bc4f7808SAxel Dörfler 	gDeviceInfos[devIndex].open_count--;
409bc4f7808SAxel Dörfler 	if (gDeviceInfos[devIndex].open_count == 0 && !gDeviceInfos[devIndex].registered) {
4107a424c39SIngo Weinhold 		// The last FD is closed and the device has been unregistered. Free its info.
4117a424c39SIngo Weinhold 		uninit_device_info(devIndex);
4127a424c39SIngo Weinhold 	}
4137a424c39SIngo Weinhold 
4147a424c39SIngo Weinhold 	unlock_driver();
4157a424c39SIngo Weinhold 
4167a424c39SIngo Weinhold 	return B_OK;
4177a424c39SIngo Weinhold }
4187a424c39SIngo Weinhold 
4197a424c39SIngo Weinhold 
4207a424c39SIngo Weinhold static status_t
4217a424c39SIngo Weinhold virtualdrive_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
4227a424c39SIngo Weinhold {
4238545b8bdSAxel Dörfler 	TRACE(("virtualdrive: read pos = 0x%08Lx, bytes = 0x%08lx\n", position, *numBytes));
4248545b8bdSAxel Dörfler 
4257a424c39SIngo Weinhold 	// check parameters
4267a424c39SIngo Weinhold 	int devIndex = (int)cookie;
4277a424c39SIngo Weinhold 	if (devIndex == kControlDevice) {
4288545b8bdSAxel Dörfler 		TRACE(("virtualdrive: reading from control device not allowed\n"));
4297a424c39SIngo Weinhold 		return B_NOT_ALLOWED;
4307a424c39SIngo Weinhold 	}
4317a424c39SIngo Weinhold 	if (position < 0)
4327a424c39SIngo Weinhold 		return B_BAD_VALUE;
4338545b8bdSAxel Dörfler 
4347a424c39SIngo Weinhold 	lock_driver();
4357a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[devIndex];
4367a424c39SIngo Weinhold 	// adjust position and numBytes according to the file size
4377a424c39SIngo Weinhold 	if (position > info.size)
4387a424c39SIngo Weinhold 		position = info.size;
4397a424c39SIngo Weinhold 	if (position + *numBytes > info.size)
4407a424c39SIngo Weinhold 		*numBytes = info.size - position;
4417a424c39SIngo Weinhold 	// read
4427a424c39SIngo Weinhold 	status_t error = B_OK;
4437a424c39SIngo Weinhold 	ssize_t bytesRead = read_pos(info.fd, position, buffer, *numBytes);
4447a424c39SIngo Weinhold 	if (bytesRead < 0)
4457a424c39SIngo Weinhold 		error = errno;
4467a424c39SIngo Weinhold 	else
4477a424c39SIngo Weinhold 		*numBytes = bytesRead;
4487a424c39SIngo Weinhold 	unlock_driver();
4497a424c39SIngo Weinhold 	return error;
4507a424c39SIngo Weinhold }
4517a424c39SIngo Weinhold 
4527a424c39SIngo Weinhold 
4537a424c39SIngo Weinhold static status_t
4547a424c39SIngo Weinhold virtualdrive_write(void *cookie, off_t position, const void *buffer, size_t *numBytes)
4557a424c39SIngo Weinhold {
4568545b8bdSAxel Dörfler 	TRACE(("virtualdrive: write pos = 0x%08Lx, bytes = 0x%08lx\n", position, *numBytes));
4578545b8bdSAxel Dörfler 
4587a424c39SIngo Weinhold 	// check parameters
4597a424c39SIngo Weinhold 	int devIndex = (int)cookie;
4607a424c39SIngo Weinhold 	if (devIndex == kControlDevice) {
4618545b8bdSAxel Dörfler 		TRACE(("virtualdrive: writing to control device not allowed\n"));
4627a424c39SIngo Weinhold 		return B_NOT_ALLOWED;
4637a424c39SIngo Weinhold 	}
4647a424c39SIngo Weinhold 	if (position < 0)
4657a424c39SIngo Weinhold 		return B_BAD_VALUE;
4668545b8bdSAxel Dörfler 
4677a424c39SIngo Weinhold 	lock_driver();
4687a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[devIndex];
4697a424c39SIngo Weinhold 	// adjust position and numBytes according to the file size
4707a424c39SIngo Weinhold 	if (position > info.size)
4717a424c39SIngo Weinhold 		position = info.size;
4727a424c39SIngo Weinhold 	if (position + *numBytes > info.size)
4737a424c39SIngo Weinhold 		*numBytes = info.size - position;
4747a424c39SIngo Weinhold 	// read
4757a424c39SIngo Weinhold 	status_t error = B_OK;
4767a424c39SIngo Weinhold 	ssize_t bytesRead = write_pos(info.fd, position, buffer, *numBytes);
4777a424c39SIngo Weinhold 	if (bytesRead < 0)
4787a424c39SIngo Weinhold 		error = errno;
4797a424c39SIngo Weinhold 	else
4807a424c39SIngo Weinhold 		*numBytes = bytesRead;
4817a424c39SIngo Weinhold 	unlock_driver();
4827a424c39SIngo Weinhold 	return error;
4837a424c39SIngo Weinhold }
4847a424c39SIngo Weinhold 
4857a424c39SIngo Weinhold 
4867a424c39SIngo Weinhold static status_t
4877a424c39SIngo Weinhold virtualdrive_control(void *cookie, uint32 op, void *arg, size_t len)
4887a424c39SIngo Weinhold {
4898545b8bdSAxel Dörfler 	TRACE(("virtualdrive: ioctl\n"));
4907a424c39SIngo Weinhold 
4917a424c39SIngo Weinhold 	int devIndex = (int)cookie;
4927a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[devIndex];
4937a424c39SIngo Weinhold 
4947a424c39SIngo Weinhold 	if (devIndex == kControlDevice || info.unused) {
4957a424c39SIngo Weinhold 		// control device or unused data device
4967a424c39SIngo Weinhold 		switch (op) {
4977a424c39SIngo Weinhold 			case B_GET_DEVICE_SIZE:
4987a424c39SIngo Weinhold 			case B_SET_NONBLOCKING_IO:
4997a424c39SIngo Weinhold 			case B_SET_BLOCKING_IO:
5007a424c39SIngo Weinhold 			case B_GET_READ_STATUS:
5017a424c39SIngo Weinhold 			case B_GET_WRITE_STATUS:
5027a424c39SIngo Weinhold 			case B_GET_ICON:
5037a424c39SIngo Weinhold 			case B_GET_GEOMETRY:
5047a424c39SIngo Weinhold 			case B_GET_BIOS_GEOMETRY:
5057a424c39SIngo Weinhold 			case B_GET_MEDIA_STATUS:
5067a424c39SIngo Weinhold 			case B_SET_UNINTERRUPTABLE_IO:
5077a424c39SIngo Weinhold 			case B_SET_INTERRUPTABLE_IO:
5087a424c39SIngo Weinhold 			case B_FLUSH_DRIVE_CACHE:
5097a424c39SIngo Weinhold 			case B_GET_BIOS_DRIVE_ID:
5107a424c39SIngo Weinhold 			case B_GET_DRIVER_FOR_DEVICE:
5117a424c39SIngo Weinhold 			case B_SET_DEVICE_SIZE:
5127a424c39SIngo Weinhold 			case B_SET_PARTITION:
5137a424c39SIngo Weinhold 			case B_FORMAT_DEVICE:
5147a424c39SIngo Weinhold 			case B_EJECT_DEVICE:
5157a424c39SIngo Weinhold 			case B_LOAD_MEDIA:
5167a424c39SIngo Weinhold 			case B_GET_NEXT_OPEN_DEVICE:
5178545b8bdSAxel Dörfler 				TRACE(("virtualdrive: another ioctl: %lx (%lu)\n", op, op));
5187a424c39SIngo Weinhold 				return B_BAD_VALUE;
519bc4f7808SAxel Dörfler 
5207a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_REGISTER_FILE:
5217a424c39SIngo Weinhold 			{
5228545b8bdSAxel Dörfler 				TRACE(("virtualdrive: VIRTUAL_DRIVE_REGISTER_FILE\n"));
523bc4f7808SAxel Dörfler 
5247a424c39SIngo Weinhold 				virtual_drive_info *driveInfo = (virtual_drive_info *)arg;
525bc4f7808SAxel Dörfler 				if (devIndex != kControlDevice || driveInfo == NULL
526bc4f7808SAxel Dörfler 					|| driveInfo->magic != VIRTUAL_DRIVE_MAGIC
527bc4f7808SAxel Dörfler 					|| driveInfo->drive_info_size != sizeof(virtual_drive_info))
528bc4f7808SAxel Dörfler 					return B_BAD_VALUE;
529bc4f7808SAxel Dörfler 
5307a424c39SIngo Weinhold 				status_t error = B_ERROR;
531bc4f7808SAxel Dörfler 				int32 i;
532bc4f7808SAxel Dörfler 
5337a424c39SIngo Weinhold 				lock_driver();
534bc4f7808SAxel Dörfler 
535bc4f7808SAxel Dörfler 				// first, look if we already have opened that file and see
536bc4f7808SAxel Dörfler 				// if it's available to us which happens when it has been
537bc4f7808SAxel Dörfler 				// halted but is still in use by other components
538bc4f7808SAxel Dörfler 				for (i = 0; i < kDataDeviceCount; i++) {
539bc4f7808SAxel Dörfler 					if (!gDeviceInfos[i].unused
540bc4f7808SAxel Dörfler 						&& gDeviceInfos[i].fd == -1
541bc4f7808SAxel Dörfler 						&& !gDeviceInfos[i].registered
542bc4f7808SAxel Dörfler 						&& !strcmp(gDeviceInfos[i].file, driveInfo->file_name)) {
543bc4f7808SAxel Dörfler 						// mark device as unused, so that init_device_info() will succeed
544bc4f7808SAxel Dörfler 						gDeviceInfos[i].unused = true;
545bc4f7808SAxel Dörfler 						error = B_OK;
546bc4f7808SAxel Dörfler 						break;
547bc4f7808SAxel Dörfler 					}
548bc4f7808SAxel Dörfler 				}
549bc4f7808SAxel Dörfler 
550bc4f7808SAxel Dörfler 				if (error != B_OK) {
551bc4f7808SAxel Dörfler 					// find an unused data device
552bc4f7808SAxel Dörfler 					for (i = 0; i < kDataDeviceCount; i++) {
5537a424c39SIngo Weinhold 						if (gDeviceInfos[i].unused) {
554bc4f7808SAxel Dörfler 							error = B_OK;
555bc4f7808SAxel Dörfler 							break;
556bc4f7808SAxel Dörfler 						}
557bc4f7808SAxel Dörfler 					}
558bc4f7808SAxel Dörfler 				}
559bc4f7808SAxel Dörfler 
560bc4f7808SAxel Dörfler 				if (error == B_OK) {
561bc4f7808SAxel Dörfler 					// we found a device slot, let's initialize it
5627a424c39SIngo Weinhold 					error = init_device_info(i, driveInfo);
5637a424c39SIngo Weinhold 					if (error == B_OK) {
5647a424c39SIngo Weinhold 						// return the device path
5657a424c39SIngo Weinhold 						strcpy(driveInfo->device_name, "/dev/");
566bc4f7808SAxel Dörfler 						strcat(driveInfo->device_name, gDeviceInfos[i].device_path);
567bc4f7808SAxel Dörfler 
5687a424c39SIngo Weinhold 						// on the first registration we need to open the
5697a424c39SIngo Weinhold 						// control device to stay loaded
5707a424c39SIngo Weinhold 						if (gRegistrationCount++ == 0) {
5717a424c39SIngo Weinhold 							char path[B_PATH_NAME_LENGTH];
5727a424c39SIngo Weinhold 							strcpy(path, "/dev/");
5737a424c39SIngo Weinhold 							strcat(path, info.device_path);
5747a424c39SIngo Weinhold 							gControlDeviceFD = open(path, O_RDONLY);
5757a424c39SIngo Weinhold 						}
5767a424c39SIngo Weinhold 					}
5777a424c39SIngo Weinhold 				}
578bc4f7808SAxel Dörfler 
5797a424c39SIngo Weinhold 				unlock_driver();
5807a424c39SIngo Weinhold 				return error;
5817a424c39SIngo Weinhold 			}
5827a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_UNREGISTER_FILE:
5837a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_GET_INFO:
5848545b8bdSAxel Dörfler 				TRACE(("virtualdrive: VIRTUAL_DRIVE_UNREGISTER_FILE/"
5858545b8bdSAxel Dörfler 					  "VIRTUAL_DRIVE_GET_INFO on control device\n"));
586bc4f7808SAxel Dörfler 				// these are called on used data files only!
5877a424c39SIngo Weinhold 				return B_BAD_VALUE;
588bc4f7808SAxel Dörfler 
5897a424c39SIngo Weinhold 			default:
5908545b8bdSAxel Dörfler 				TRACE(("virtualdrive: unknown ioctl: %lx (%lu)\n", op, op));
5917a424c39SIngo Weinhold 				return B_BAD_VALUE;
5927a424c39SIngo Weinhold 		}
5937a424c39SIngo Weinhold 	} else {
5947a424c39SIngo Weinhold 		// used data device
5957a424c39SIngo Weinhold 		switch (op) {
5967a424c39SIngo Weinhold 			case B_GET_DEVICE_SIZE:
5978545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_DEVICE_SIZE\n"));
5987a424c39SIngo Weinhold 				*(size_t*)arg = info.size;
5997a424c39SIngo Weinhold 				return B_OK;
6007a424c39SIngo Weinhold 
6017a424c39SIngo Weinhold 			case B_SET_NONBLOCKING_IO:
6028545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_SET_NONBLOCKING_IO\n"));
6037a424c39SIngo Weinhold 				return B_OK;
6047a424c39SIngo Weinhold 
6057a424c39SIngo Weinhold 			case B_SET_BLOCKING_IO:
6068545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_SET_BLOCKING_IO\n"));
6077a424c39SIngo Weinhold 				return B_OK;
6087a424c39SIngo Weinhold 
6097a424c39SIngo Weinhold 			case B_GET_READ_STATUS:
6108545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_READ_STATUS\n"));
6117a424c39SIngo Weinhold 				*(bool*)arg = true;
6127a424c39SIngo Weinhold 				return B_OK;
6137a424c39SIngo Weinhold 
6147a424c39SIngo Weinhold 			case B_GET_WRITE_STATUS:
6158545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_WRITE_STATUS\n"));
6167a424c39SIngo Weinhold 				*(bool*)arg = true;
6177a424c39SIngo Weinhold 				return B_OK;
6187a424c39SIngo Weinhold 
6197a424c39SIngo Weinhold 			case B_GET_ICON:
620bc4f7808SAxel Dörfler 			{
6218545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_ICON\n"));
622bc4f7808SAxel Dörfler 				device_icon *icon = (device_icon *)arg;
623bc4f7808SAxel Dörfler 
624bc4f7808SAxel Dörfler 				if (icon->icon_size == kPrimaryImageWidth) {
625bc4f7808SAxel Dörfler 					memcpy(icon->icon_data, kPrimaryImageBits, kPrimaryImageWidth * kPrimaryImageHeight);
626bc4f7808SAxel Dörfler 				} else if (icon->icon_size == kSecondaryImageWidth) {
627bc4f7808SAxel Dörfler 					memcpy(icon->icon_data, kSecondaryImageBits, kSecondaryImageWidth * kSecondaryImageHeight);
628bc4f7808SAxel Dörfler 				} else
629bc4f7808SAxel Dörfler 					return B_ERROR;
630bc4f7808SAxel Dörfler 
6317a424c39SIngo Weinhold 				return B_OK;
632bc4f7808SAxel Dörfler 			}
6337a424c39SIngo Weinhold 
6347a424c39SIngo Weinhold 			case B_GET_GEOMETRY:
6358545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_GEOMETRY\n"));
6367a424c39SIngo Weinhold 				*(device_geometry *)arg = info.geometry;
6377a424c39SIngo Weinhold 				return B_OK;
6387a424c39SIngo Weinhold 
6397a424c39SIngo Weinhold 			case B_GET_BIOS_GEOMETRY:
6407a424c39SIngo Weinhold 			{
6418545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_BIOS_GEOMETRY\n"));
6427a424c39SIngo Weinhold 				device_geometry *dg = (device_geometry *)arg;
6437a424c39SIngo Weinhold 				dg->bytes_per_sector = 512;
6447a424c39SIngo Weinhold 				dg->sectors_per_track = info.size / (512 * 1024);
6457a424c39SIngo Weinhold 				dg->cylinder_count = 1024;
6467a424c39SIngo Weinhold 				dg->head_count = 1;
6477a424c39SIngo Weinhold 				dg->device_type = info.geometry.device_type;
6487a424c39SIngo Weinhold 				dg->removable = info.geometry.removable;
6497a424c39SIngo Weinhold 				dg->read_only = info.geometry.read_only;
6507a424c39SIngo Weinhold 				dg->write_once = info.geometry.write_once;
6517a424c39SIngo Weinhold 				return B_OK;
6527a424c39SIngo Weinhold 			}
6537a424c39SIngo Weinhold 
6547a424c39SIngo Weinhold 			case B_GET_MEDIA_STATUS:
6558545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_MEDIA_STATUS\n"));
6567a424c39SIngo Weinhold 				*(status_t*)arg = B_NO_ERROR;
6577a424c39SIngo Weinhold 				return B_OK;
6587a424c39SIngo Weinhold 
6597a424c39SIngo Weinhold 			case B_SET_UNINTERRUPTABLE_IO:
6608545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_SET_UNINTERRUPTABLE_IO\n"));
6617a424c39SIngo Weinhold 				return B_OK;
6627a424c39SIngo Weinhold 
6637a424c39SIngo Weinhold 			case B_SET_INTERRUPTABLE_IO:
6648545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_SET_INTERRUPTABLE_IO\n"));
6657a424c39SIngo Weinhold 				return B_OK;
6667a424c39SIngo Weinhold 
6677a424c39SIngo Weinhold 			case B_FLUSH_DRIVE_CACHE:
6688545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_FLUSH_DRIVE_CACHE\n"));
6697a424c39SIngo Weinhold 				return B_OK;
6707a424c39SIngo Weinhold 
6717a424c39SIngo Weinhold 			case B_GET_BIOS_DRIVE_ID:
6728545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_BIOS_DRIVE_ID\n"));
6737a424c39SIngo Weinhold 				*(uint8*)arg = 0xF8;
6747a424c39SIngo Weinhold 				return B_OK;
6757a424c39SIngo Weinhold 
6767a424c39SIngo Weinhold 			case B_GET_DRIVER_FOR_DEVICE:
6777a424c39SIngo Weinhold 			case B_SET_DEVICE_SIZE:
6787a424c39SIngo Weinhold 			case B_SET_PARTITION:
6797a424c39SIngo Weinhold 			case B_FORMAT_DEVICE:
6807a424c39SIngo Weinhold 			case B_EJECT_DEVICE:
6817a424c39SIngo Weinhold 			case B_LOAD_MEDIA:
6827a424c39SIngo Weinhold 			case B_GET_NEXT_OPEN_DEVICE:
6838545b8bdSAxel Dörfler 				TRACE(("virtualdrive: another ioctl: %lx (%lu)\n", op, op));
6847a424c39SIngo Weinhold 				return B_BAD_VALUE;
685bc4f7808SAxel Dörfler 
6867a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_REGISTER_FILE:
6878545b8bdSAxel Dörfler 				TRACE(("virtualdrive: VIRTUAL_DRIVE_REGISTER_FILE (data)\n"));
6887a424c39SIngo Weinhold 				return B_BAD_VALUE;
6897a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_UNREGISTER_FILE:
6907a424c39SIngo Weinhold 			{
6918545b8bdSAxel Dörfler 				TRACE(("virtualdrive: VIRTUAL_DRIVE_UNREGISTER_FILE\n"));
6927a424c39SIngo Weinhold 				lock_driver();
693bc4f7808SAxel Dörfler 
694bc4f7808SAxel Dörfler 				bool immediately = (bool)arg;
695bc4f7808SAxel Dörfler 				bool wasRegistered = info.registered;
696bc4f7808SAxel Dörfler 
697bc4f7808SAxel Dörfler 				info.registered = false;
698bc4f7808SAxel Dörfler 
6997a424c39SIngo Weinhold 				// on the last unregistration we need to close the
7007a424c39SIngo Weinhold 				// control device
7017a424c39SIngo Weinhold 				if (wasRegistered && --gRegistrationCount == 0) {
7027a424c39SIngo Weinhold 					close(gControlDeviceFD);
7037a424c39SIngo Weinhold 					gControlDeviceFD = -1;
7047a424c39SIngo Weinhold 				}
705bc4f7808SAxel Dörfler 
706bc4f7808SAxel Dörfler 				// if we "immediately" is true, we will stop our service immediately
707bc4f7808SAxel Dörfler 				// and close the underlying file, open it for other uses
708bc4f7808SAxel Dörfler 				if (immediately) {
7098545b8bdSAxel Dörfler 					TRACE(("virtualdrive: close file descriptor\n"));
710bc4f7808SAxel Dörfler 					// we cannot use uninit_device_info() here, since that does
711bc4f7808SAxel Dörfler 					// a little too much and would open the device for other
712bc4f7808SAxel Dörfler 					// uses.
713bc4f7808SAxel Dörfler 					close(info.fd);
714bc4f7808SAxel Dörfler 					info.fd = -1;
715bc4f7808SAxel Dörfler 				}
716bc4f7808SAxel Dörfler 
7177a424c39SIngo Weinhold 				unlock_driver();
7187a424c39SIngo Weinhold 				return B_OK;
7197a424c39SIngo Weinhold 			}
7207a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_GET_INFO:
7217a424c39SIngo Weinhold 			{
7228545b8bdSAxel Dörfler 				TRACE(("virtualdrive: VIRTUAL_DRIVE_GET_INFO\n"));
723bc4f7808SAxel Dörfler 
7247a424c39SIngo Weinhold 				virtual_drive_info *driveInfo = (virtual_drive_info *)arg;
725bc4f7808SAxel Dörfler 				if (driveInfo == NULL
726bc4f7808SAxel Dörfler 					|| driveInfo->magic != VIRTUAL_DRIVE_MAGIC
727bc4f7808SAxel Dörfler 					|| driveInfo->drive_info_size != sizeof(virtual_drive_info))
728bc4f7808SAxel Dörfler 					return B_BAD_VALUE;
729bc4f7808SAxel Dörfler 
7307a424c39SIngo Weinhold 				strcpy(driveInfo->file_name, info.file);
7317a424c39SIngo Weinhold 				strcpy(driveInfo->device_name, "/dev/");
7327a424c39SIngo Weinhold 				strcat(driveInfo->device_name, info.device_path);
7337a424c39SIngo Weinhold 				driveInfo->geometry = info.geometry;
7347a424c39SIngo Weinhold 				driveInfo->use_geometry = true;
735bc4f7808SAxel Dörfler 				driveInfo->halted = info.fd == -1;
7367a424c39SIngo Weinhold 				return B_OK;
7377a424c39SIngo Weinhold 			}
738bc4f7808SAxel Dörfler 
7397a424c39SIngo Weinhold 			default:
7408545b8bdSAxel Dörfler 				TRACE(("virtualdrive: unknown ioctl: %lx (%lu)\n", op, op));
7417a424c39SIngo Weinhold 				return B_BAD_VALUE;
7427a424c39SIngo Weinhold 		}
7437a424c39SIngo Weinhold 	}
7447a424c39SIngo Weinhold 
7457a424c39SIngo Weinhold }
7467a424c39SIngo Weinhold 
7477a424c39SIngo Weinhold 
7487a424c39SIngo Weinhold static status_t
7497a424c39SIngo Weinhold virtualdrive_free(void *cookie)
7507a424c39SIngo Weinhold {
7518545b8bdSAxel Dörfler 	TRACE(("virtualdrive: free cookie()\n"));
7527a424c39SIngo Weinhold 	return B_OK;
7537a424c39SIngo Weinhold }
7547a424c39SIngo Weinhold 
7557a424c39SIngo Weinhold 
7567a424c39SIngo Weinhold /* -----
7577a424c39SIngo Weinhold 	function pointers for the device hooks entry points
7587a424c39SIngo Weinhold ----- */
7597a424c39SIngo Weinhold 
760bc4f7808SAxel Dörfler device_hooks sVirtualDriveHooks = {
7617a424c39SIngo Weinhold 	virtualdrive_open, 			/* -> open entry point */
7627a424c39SIngo Weinhold 	virtualdrive_close, 		/* -> close entry point */
7637a424c39SIngo Weinhold 	virtualdrive_free,			/* -> free cookie */
7647a424c39SIngo Weinhold 	virtualdrive_control, 		/* -> control entry point */
7657a424c39SIngo Weinhold 	virtualdrive_read,			/* -> read entry point */
7667a424c39SIngo Weinhold 	virtualdrive_write			/* -> write entry point */
7677a424c39SIngo Weinhold };
7687a424c39SIngo Weinhold 
769