xref: /haiku/src/tests/kits/storage/virtualdrive/virtualdrive.cpp (revision 8545b8bd8dbc419a86c0676a75fa0abc15f2ca27)
17a424c39SIngo Weinhold // ----------------------------------------------------------------------
27a424c39SIngo Weinhold //  This software is part of the OpenBeOS distribution and is covered
37a424c39SIngo Weinhold //  by the OpenBeOS 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 
41*8545b8bdSAxel Dörfler //#define TRACE(x) dprintf x
42*8545b8bdSAxel 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 {
156*8545b8bdSAxel 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 
248bc4f7808SAxel Dörfler 		// This is a special reserved ioctl() opcode not defined anywhere in
249bc4f7808SAxel Dörfler 		// the Be headers.
250bc4f7808SAxel Dörfler 		if (ioctl(fd, 10000) != 0) {
251*8545b8bdSAxel Dörfler 			dprintf("virtualdrive: disable caching ioctl failed\n");
252bc4f7808SAxel Dörfler 			return errno;
253bc4f7808SAxel Dörfler 		}
254bc4f7808SAxel Dörfler 	}
255bc4f7808SAxel Dörfler 
2567a424c39SIngo Weinhold 	// fill in the rest of the device_info structure
2577a424c39SIngo Weinhold 	if (error == B_OK) {
258bc4f7808SAxel Dörfler 		// open_count doesn't have to be changed here (virtualdrive_open() will do that for us)
2597a424c39SIngo Weinhold 		info.fd = fd;
2607a424c39SIngo Weinhold 		info.size = size;
2617a424c39SIngo Weinhold 		info.unused = false;
2627a424c39SIngo Weinhold 		info.registered = true;
2637a424c39SIngo Weinhold 		strcpy(info.file, initInfo->file_name);
264bc4f7808SAxel Dörfler 		info.device_path = sVirtualDriveName[index];
2657a424c39SIngo Weinhold 	} else {
2667a424c39SIngo Weinhold 		// cleanup on error
2677a424c39SIngo Weinhold 		close(fd);
268bc4f7808SAxel Dörfler 		if (info.open_count == 0)
2697a424c39SIngo Weinhold 			clear_device_info(index);
2707a424c39SIngo Weinhold 	}
2717a424c39SIngo Weinhold 	return error;
2727a424c39SIngo Weinhold }
2737a424c39SIngo Weinhold 
274bc4f7808SAxel Dörfler 
2757a424c39SIngo Weinhold // uninit_device_info
2767a424c39SIngo Weinhold static
2777a424c39SIngo Weinhold status_t
2787a424c39SIngo Weinhold uninit_device_info(int32 index)
2797a424c39SIngo Weinhold {
2807a424c39SIngo Weinhold 	if (!is_valid_data_device_index(index))
2817a424c39SIngo Weinhold 		return B_BAD_VALUE;
282bc4f7808SAxel Dörfler 
2837a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[index];
2847a424c39SIngo Weinhold 	if (info.unused)
2857a424c39SIngo Weinhold 		return B_BAD_VALUE;
286bc4f7808SAxel Dörfler 
2877a424c39SIngo Weinhold 	close(info.fd);
2887a424c39SIngo Weinhold 	clear_device_info(index);
2897a424c39SIngo Weinhold 	return B_OK;
2907a424c39SIngo Weinhold }
2917a424c39SIngo Weinhold 
292bc4f7808SAxel Dörfler 
293bc4f7808SAxel Dörfler //	#pragma mark -
294bc4f7808SAxel Dörfler //	public driver API
295bc4f7808SAxel Dörfler 
296bc4f7808SAxel Dörfler 
2977a424c39SIngo Weinhold status_t
2987a424c39SIngo Weinhold init_hardware(void)
2997a424c39SIngo Weinhold {
300*8545b8bdSAxel Dörfler 	TRACE(("virtualdrive: init_hardware\n"));
3017a424c39SIngo Weinhold 	return B_OK;
3027a424c39SIngo Weinhold }
3037a424c39SIngo Weinhold 
3047a424c39SIngo Weinhold 
3057a424c39SIngo Weinhold status_t
3067a424c39SIngo Weinhold init_driver(void)
3077a424c39SIngo Weinhold {
308*8545b8bdSAxel Dörfler 	TRACE(("virtualdrive: init\n"));
3097a424c39SIngo Weinhold 
3107a424c39SIngo Weinhold 	new_lock(&driverlock, "virtualdrive lock");
3117a424c39SIngo Weinhold 
3127a424c39SIngo Weinhold 	// init the device infos
3137a424c39SIngo Weinhold 	for (int32 i = 0; i < kDeviceCount; i++)
3147a424c39SIngo Weinhold 		clear_device_info(i);
3157a424c39SIngo Weinhold 
3167a424c39SIngo Weinhold 	return B_OK;
3177a424c39SIngo Weinhold }
3187a424c39SIngo Weinhold 
3197a424c39SIngo Weinhold 
3207a424c39SIngo Weinhold void
3217a424c39SIngo Weinhold uninit_driver(void)
3227a424c39SIngo Weinhold {
323*8545b8bdSAxel Dörfler 	TRACE(("virtualdrive: uninit\n"));
3247a424c39SIngo Weinhold 	free_lock(&driverlock);
3257a424c39SIngo Weinhold }
3267a424c39SIngo Weinhold 
3277a424c39SIngo Weinhold 
328bc4f7808SAxel Dörfler const char **
329bc4f7808SAxel Dörfler publish_devices(void)
330bc4f7808SAxel Dörfler {
331*8545b8bdSAxel Dörfler 	TRACE(("virtualdrive: publish_devices\n"));
332bc4f7808SAxel Dörfler 	return sVirtualDriveName;
333bc4f7808SAxel Dörfler }
334bc4f7808SAxel Dörfler 
335bc4f7808SAxel Dörfler 
336bc4f7808SAxel Dörfler device_hooks *
337bc4f7808SAxel Dörfler find_device(const char* name)
338bc4f7808SAxel Dörfler {
339*8545b8bdSAxel Dörfler 	TRACE(("virtualdrive: find_device(%s)\n", name));
340bc4f7808SAxel Dörfler 	return &sVirtualDriveHooks;
341bc4f7808SAxel Dörfler }
342bc4f7808SAxel Dörfler 
343bc4f7808SAxel Dörfler 
344bc4f7808SAxel Dörfler //	#pragma mark -
345bc4f7808SAxel Dörfler //	the device hooks
346bc4f7808SAxel Dörfler 
3477a424c39SIngo Weinhold 
3487a424c39SIngo Weinhold static status_t
3497a424c39SIngo Weinhold virtualdrive_open(const char *name, uint32 flags, void **cookie)
3507a424c39SIngo Weinhold {
351*8545b8bdSAxel Dörfler 	TRACE(("virtualdrive: open %s\n",name));
3527a424c39SIngo Weinhold 
3537a424c39SIngo Weinhold 	*cookie = (void *)-1;
3547a424c39SIngo Weinhold 
3557a424c39SIngo Weinhold 	lock_driver();
3567a424c39SIngo Weinhold 
3577a424c39SIngo Weinhold 	int32 devIndex = dev_index_for_path(name);
3587a424c39SIngo Weinhold 
359*8545b8bdSAxel Dörfler 	TRACE(("virtualdrive: devIndex %ld!\n", devIndex));
3607a424c39SIngo Weinhold 
3617a424c39SIngo Weinhold 	if (!is_valid_device_index(devIndex)) {
362*8545b8bdSAxel Dörfler 		TRACE(("virtualdrive: wrong index!\n"));
3637a424c39SIngo Weinhold 		unlock_driver();
3647a424c39SIngo Weinhold 		return B_ERROR;
3657a424c39SIngo Weinhold 	}
3667a424c39SIngo Weinhold 
3677a424c39SIngo Weinhold 	if (gDeviceInfos[devIndex].unused) {
368*8545b8bdSAxel Dörfler 		TRACE(("virtualdrive: device is unused!\n"));
3697a424c39SIngo Weinhold 		unlock_driver();
3707a424c39SIngo Weinhold 		return B_ERROR;
3717a424c39SIngo Weinhold 	}
3727a424c39SIngo Weinhold 
3737a424c39SIngo Weinhold 	if (!gDeviceInfos[devIndex].registered) {
374*8545b8bdSAxel Dörfler 		TRACE(("virtualdrive: device has been unregistered!\n"));
3757a424c39SIngo Weinhold 		unlock_driver();
3767a424c39SIngo Weinhold 		return B_ERROR;
3777a424c39SIngo Weinhold 	}
3787a424c39SIngo Weinhold 
3797a424c39SIngo Weinhold 	// store index in cookie
3807a424c39SIngo Weinhold 	*cookie = (void *)devIndex;
3817a424c39SIngo Weinhold 
382bc4f7808SAxel Dörfler 	gDeviceInfos[devIndex].open_count++;
3837a424c39SIngo Weinhold 
3847a424c39SIngo Weinhold 	unlock_driver();
3857a424c39SIngo Weinhold 	return B_OK;
3867a424c39SIngo Weinhold }
3877a424c39SIngo Weinhold 
3887a424c39SIngo Weinhold 
3897a424c39SIngo Weinhold static status_t
3907a424c39SIngo Weinhold virtualdrive_close(void *cookie)
3917a424c39SIngo Weinhold {
3927a424c39SIngo Weinhold 	int32 devIndex = (int)cookie;
3937a424c39SIngo Weinhold 
394*8545b8bdSAxel Dörfler 	TRACE(("virtualdrive: close() devIndex = %ld\n", devIndex));
3957a424c39SIngo Weinhold 	if (!is_valid_data_device_index(devIndex))
3967a424c39SIngo Weinhold 		return B_OK;
3977a424c39SIngo Weinhold 
3987a424c39SIngo Weinhold 	lock_driver();
3997a424c39SIngo Weinhold 
400bc4f7808SAxel Dörfler 	gDeviceInfos[devIndex].open_count--;
401bc4f7808SAxel Dörfler 	if (gDeviceInfos[devIndex].open_count == 0 && !gDeviceInfos[devIndex].registered) {
4027a424c39SIngo Weinhold 		// The last FD is closed and the device has been unregistered. Free its info.
4037a424c39SIngo Weinhold 		uninit_device_info(devIndex);
4047a424c39SIngo Weinhold 	}
4057a424c39SIngo Weinhold 
4067a424c39SIngo Weinhold 	unlock_driver();
4077a424c39SIngo Weinhold 
4087a424c39SIngo Weinhold 	return B_OK;
4097a424c39SIngo Weinhold }
4107a424c39SIngo Weinhold 
4117a424c39SIngo Weinhold 
4127a424c39SIngo Weinhold static status_t
4137a424c39SIngo Weinhold virtualdrive_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
4147a424c39SIngo Weinhold {
415*8545b8bdSAxel Dörfler 	TRACE(("virtualdrive: read pos = 0x%08Lx, bytes = 0x%08lx\n", position, *numBytes));
416*8545b8bdSAxel Dörfler 
4177a424c39SIngo Weinhold 	// check parameters
4187a424c39SIngo Weinhold 	int devIndex = (int)cookie;
4197a424c39SIngo Weinhold 	if (devIndex == kControlDevice) {
420*8545b8bdSAxel Dörfler 		TRACE(("virtualdrive: reading from control device not allowed\n"));
4217a424c39SIngo Weinhold 		return B_NOT_ALLOWED;
4227a424c39SIngo Weinhold 	}
4237a424c39SIngo Weinhold 	if (position < 0)
4247a424c39SIngo Weinhold 		return B_BAD_VALUE;
425*8545b8bdSAxel Dörfler 
4267a424c39SIngo Weinhold 	lock_driver();
4277a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[devIndex];
4287a424c39SIngo Weinhold 	// adjust position and numBytes according to the file size
4297a424c39SIngo Weinhold 	if (position > info.size)
4307a424c39SIngo Weinhold 		position = info.size;
4317a424c39SIngo Weinhold 	if (position + *numBytes > info.size)
4327a424c39SIngo Weinhold 		*numBytes = info.size - position;
4337a424c39SIngo Weinhold 	// read
4347a424c39SIngo Weinhold 	status_t error = B_OK;
4357a424c39SIngo Weinhold 	ssize_t bytesRead = read_pos(info.fd, position, buffer, *numBytes);
4367a424c39SIngo Weinhold 	if (bytesRead < 0)
4377a424c39SIngo Weinhold 		error = errno;
4387a424c39SIngo Weinhold 	else
4397a424c39SIngo Weinhold 		*numBytes = bytesRead;
4407a424c39SIngo Weinhold 	unlock_driver();
4417a424c39SIngo Weinhold 	return error;
4427a424c39SIngo Weinhold }
4437a424c39SIngo Weinhold 
4447a424c39SIngo Weinhold 
4457a424c39SIngo Weinhold static status_t
4467a424c39SIngo Weinhold virtualdrive_write(void *cookie, off_t position, const void *buffer, size_t *numBytes)
4477a424c39SIngo Weinhold {
448*8545b8bdSAxel Dörfler 	TRACE(("virtualdrive: write pos = 0x%08Lx, bytes = 0x%08lx\n", position, *numBytes));
449*8545b8bdSAxel Dörfler 
4507a424c39SIngo Weinhold 	// check parameters
4517a424c39SIngo Weinhold 	int devIndex = (int)cookie;
4527a424c39SIngo Weinhold 	if (devIndex == kControlDevice) {
453*8545b8bdSAxel Dörfler 		TRACE(("virtualdrive: writing to control device not allowed\n"));
4547a424c39SIngo Weinhold 		return B_NOT_ALLOWED;
4557a424c39SIngo Weinhold 	}
4567a424c39SIngo Weinhold 	if (position < 0)
4577a424c39SIngo Weinhold 		return B_BAD_VALUE;
458*8545b8bdSAxel Dörfler 
4597a424c39SIngo Weinhold 	lock_driver();
4607a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[devIndex];
4617a424c39SIngo Weinhold 	// adjust position and numBytes according to the file size
4627a424c39SIngo Weinhold 	if (position > info.size)
4637a424c39SIngo Weinhold 		position = info.size;
4647a424c39SIngo Weinhold 	if (position + *numBytes > info.size)
4657a424c39SIngo Weinhold 		*numBytes = info.size - position;
4667a424c39SIngo Weinhold 	// read
4677a424c39SIngo Weinhold 	status_t error = B_OK;
4687a424c39SIngo Weinhold 	ssize_t bytesRead = write_pos(info.fd, position, buffer, *numBytes);
4697a424c39SIngo Weinhold 	if (bytesRead < 0)
4707a424c39SIngo Weinhold 		error = errno;
4717a424c39SIngo Weinhold 	else
4727a424c39SIngo Weinhold 		*numBytes = bytesRead;
4737a424c39SIngo Weinhold 	unlock_driver();
4747a424c39SIngo Weinhold 	return error;
4757a424c39SIngo Weinhold }
4767a424c39SIngo Weinhold 
4777a424c39SIngo Weinhold 
4787a424c39SIngo Weinhold static status_t
4797a424c39SIngo Weinhold virtualdrive_control(void *cookie, uint32 op, void *arg, size_t len)
4807a424c39SIngo Weinhold {
481*8545b8bdSAxel Dörfler 	TRACE(("virtualdrive: ioctl\n"));
4827a424c39SIngo Weinhold 
4837a424c39SIngo Weinhold 	int devIndex = (int)cookie;
4847a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[devIndex];
4857a424c39SIngo Weinhold 
4867a424c39SIngo Weinhold 	if (devIndex == kControlDevice || info.unused) {
4877a424c39SIngo Weinhold 		// control device or unused data device
4887a424c39SIngo Weinhold 		switch (op) {
4897a424c39SIngo Weinhold 			case B_GET_DEVICE_SIZE:
4907a424c39SIngo Weinhold 			case B_SET_NONBLOCKING_IO:
4917a424c39SIngo Weinhold 			case B_SET_BLOCKING_IO:
4927a424c39SIngo Weinhold 			case B_GET_READ_STATUS:
4937a424c39SIngo Weinhold 			case B_GET_WRITE_STATUS:
4947a424c39SIngo Weinhold 			case B_GET_ICON:
4957a424c39SIngo Weinhold 			case B_GET_GEOMETRY:
4967a424c39SIngo Weinhold 			case B_GET_BIOS_GEOMETRY:
4977a424c39SIngo Weinhold 			case B_GET_MEDIA_STATUS:
4987a424c39SIngo Weinhold 			case B_SET_UNINTERRUPTABLE_IO:
4997a424c39SIngo Weinhold 			case B_SET_INTERRUPTABLE_IO:
5007a424c39SIngo Weinhold 			case B_FLUSH_DRIVE_CACHE:
5017a424c39SIngo Weinhold 			case B_GET_BIOS_DRIVE_ID:
5027a424c39SIngo Weinhold 			case B_GET_DRIVER_FOR_DEVICE:
5037a424c39SIngo Weinhold 			case B_SET_DEVICE_SIZE:
5047a424c39SIngo Weinhold 			case B_SET_PARTITION:
5057a424c39SIngo Weinhold 			case B_FORMAT_DEVICE:
5067a424c39SIngo Weinhold 			case B_EJECT_DEVICE:
5077a424c39SIngo Weinhold 			case B_LOAD_MEDIA:
5087a424c39SIngo Weinhold 			case B_GET_NEXT_OPEN_DEVICE:
509*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: another ioctl: %lx (%lu)\n", op, op));
5107a424c39SIngo Weinhold 				return B_BAD_VALUE;
511bc4f7808SAxel Dörfler 
5127a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_REGISTER_FILE:
5137a424c39SIngo Weinhold 			{
514*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: VIRTUAL_DRIVE_REGISTER_FILE\n"));
515bc4f7808SAxel Dörfler 
5167a424c39SIngo Weinhold 				virtual_drive_info *driveInfo = (virtual_drive_info *)arg;
517bc4f7808SAxel Dörfler 				if (devIndex != kControlDevice || driveInfo == NULL
518bc4f7808SAxel Dörfler 					|| driveInfo->magic != VIRTUAL_DRIVE_MAGIC
519bc4f7808SAxel Dörfler 					|| driveInfo->drive_info_size != sizeof(virtual_drive_info))
520bc4f7808SAxel Dörfler 					return B_BAD_VALUE;
521bc4f7808SAxel Dörfler 
5227a424c39SIngo Weinhold 				status_t error = B_ERROR;
523bc4f7808SAxel Dörfler 				int32 i;
524bc4f7808SAxel Dörfler 
5257a424c39SIngo Weinhold 				lock_driver();
526bc4f7808SAxel Dörfler 
527bc4f7808SAxel Dörfler 				// first, look if we already have opened that file and see
528bc4f7808SAxel Dörfler 				// if it's available to us which happens when it has been
529bc4f7808SAxel Dörfler 				// halted but is still in use by other components
530bc4f7808SAxel Dörfler 				for (i = 0; i < kDataDeviceCount; i++) {
531bc4f7808SAxel Dörfler 					if (!gDeviceInfos[i].unused
532bc4f7808SAxel Dörfler 						&& gDeviceInfos[i].fd == -1
533bc4f7808SAxel Dörfler 						&& !gDeviceInfos[i].registered
534bc4f7808SAxel Dörfler 						&& !strcmp(gDeviceInfos[i].file, driveInfo->file_name)) {
535bc4f7808SAxel Dörfler 						// mark device as unused, so that init_device_info() will succeed
536bc4f7808SAxel Dörfler 						gDeviceInfos[i].unused = true;
537bc4f7808SAxel Dörfler 						error = B_OK;
538bc4f7808SAxel Dörfler 						break;
539bc4f7808SAxel Dörfler 					}
540bc4f7808SAxel Dörfler 				}
541bc4f7808SAxel Dörfler 
542bc4f7808SAxel Dörfler 				if (error != B_OK) {
543bc4f7808SAxel Dörfler 					// find an unused data device
544bc4f7808SAxel Dörfler 					for (i = 0; i < kDataDeviceCount; i++) {
5457a424c39SIngo Weinhold 						if (gDeviceInfos[i].unused) {
546bc4f7808SAxel Dörfler 							error = B_OK;
547bc4f7808SAxel Dörfler 							break;
548bc4f7808SAxel Dörfler 						}
549bc4f7808SAxel Dörfler 					}
550bc4f7808SAxel Dörfler 				}
551bc4f7808SAxel Dörfler 
552bc4f7808SAxel Dörfler 				if (error == B_OK) {
553bc4f7808SAxel Dörfler 					// we found a device slot, let's initialize it
5547a424c39SIngo Weinhold 					error = init_device_info(i, driveInfo);
5557a424c39SIngo Weinhold 					if (error == B_OK) {
5567a424c39SIngo Weinhold 						// return the device path
5577a424c39SIngo Weinhold 						strcpy(driveInfo->device_name, "/dev/");
558bc4f7808SAxel Dörfler 						strcat(driveInfo->device_name, gDeviceInfos[i].device_path);
559bc4f7808SAxel Dörfler 
5607a424c39SIngo Weinhold 						// on the first registration we need to open the
5617a424c39SIngo Weinhold 						// control device to stay loaded
5627a424c39SIngo Weinhold 						if (gRegistrationCount++ == 0) {
5637a424c39SIngo Weinhold 							char path[B_PATH_NAME_LENGTH];
5647a424c39SIngo Weinhold 							strcpy(path, "/dev/");
5657a424c39SIngo Weinhold 							strcat(path, info.device_path);
5667a424c39SIngo Weinhold 							gControlDeviceFD = open(path, O_RDONLY);
5677a424c39SIngo Weinhold 						}
5687a424c39SIngo Weinhold 					}
5697a424c39SIngo Weinhold 				}
570bc4f7808SAxel Dörfler 
5717a424c39SIngo Weinhold 				unlock_driver();
5727a424c39SIngo Weinhold 				return error;
5737a424c39SIngo Weinhold 			}
5747a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_UNREGISTER_FILE:
5757a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_GET_INFO:
576*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: VIRTUAL_DRIVE_UNREGISTER_FILE/"
577*8545b8bdSAxel Dörfler 					  "VIRTUAL_DRIVE_GET_INFO on control device\n"));
578bc4f7808SAxel Dörfler 				// these are called on used data files only!
5797a424c39SIngo Weinhold 				return B_BAD_VALUE;
580bc4f7808SAxel Dörfler 
5817a424c39SIngo Weinhold 			default:
582*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: unknown ioctl: %lx (%lu)\n", op, op));
5837a424c39SIngo Weinhold 				return B_BAD_VALUE;
5847a424c39SIngo Weinhold 		}
5857a424c39SIngo Weinhold 	} else {
5867a424c39SIngo Weinhold 		// used data device
5877a424c39SIngo Weinhold 		switch (op) {
5887a424c39SIngo Weinhold 			case B_GET_DEVICE_SIZE:
589*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_DEVICE_SIZE\n"));
5907a424c39SIngo Weinhold 				*(size_t*)arg = info.size;
5917a424c39SIngo Weinhold 				return B_OK;
5927a424c39SIngo Weinhold 
5937a424c39SIngo Weinhold 			case B_SET_NONBLOCKING_IO:
594*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_SET_NONBLOCKING_IO\n"));
5957a424c39SIngo Weinhold 				return B_OK;
5967a424c39SIngo Weinhold 
5977a424c39SIngo Weinhold 			case B_SET_BLOCKING_IO:
598*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_SET_BLOCKING_IO\n"));
5997a424c39SIngo Weinhold 				return B_OK;
6007a424c39SIngo Weinhold 
6017a424c39SIngo Weinhold 			case B_GET_READ_STATUS:
602*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_READ_STATUS\n"));
6037a424c39SIngo Weinhold 				*(bool*)arg = true;
6047a424c39SIngo Weinhold 				return B_OK;
6057a424c39SIngo Weinhold 
6067a424c39SIngo Weinhold 			case B_GET_WRITE_STATUS:
607*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_WRITE_STATUS\n"));
6087a424c39SIngo Weinhold 				*(bool*)arg = true;
6097a424c39SIngo Weinhold 				return B_OK;
6107a424c39SIngo Weinhold 
6117a424c39SIngo Weinhold 			case B_GET_ICON:
612bc4f7808SAxel Dörfler 			{
613*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_ICON\n"));
614bc4f7808SAxel Dörfler 				device_icon *icon = (device_icon *)arg;
615bc4f7808SAxel Dörfler 
616bc4f7808SAxel Dörfler 				if (icon->icon_size == kPrimaryImageWidth) {
617bc4f7808SAxel Dörfler 					memcpy(icon->icon_data, kPrimaryImageBits, kPrimaryImageWidth * kPrimaryImageHeight);
618bc4f7808SAxel Dörfler 				} else if (icon->icon_size == kSecondaryImageWidth) {
619bc4f7808SAxel Dörfler 					memcpy(icon->icon_data, kSecondaryImageBits, kSecondaryImageWidth * kSecondaryImageHeight);
620bc4f7808SAxel Dörfler 				} else
621bc4f7808SAxel Dörfler 					return B_ERROR;
622bc4f7808SAxel Dörfler 
6237a424c39SIngo Weinhold 				return B_OK;
624bc4f7808SAxel Dörfler 			}
6257a424c39SIngo Weinhold 
6267a424c39SIngo Weinhold 			case B_GET_GEOMETRY:
627*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_GEOMETRY\n"));
6287a424c39SIngo Weinhold 				*(device_geometry *)arg = info.geometry;
6297a424c39SIngo Weinhold 				return B_OK;
6307a424c39SIngo Weinhold 
6317a424c39SIngo Weinhold 			case B_GET_BIOS_GEOMETRY:
6327a424c39SIngo Weinhold 			{
633*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_BIOS_GEOMETRY\n"));
6347a424c39SIngo Weinhold 				device_geometry *dg = (device_geometry *)arg;
6357a424c39SIngo Weinhold 				dg->bytes_per_sector = 512;
6367a424c39SIngo Weinhold 				dg->sectors_per_track = info.size / (512 * 1024);
6377a424c39SIngo Weinhold 				dg->cylinder_count = 1024;
6387a424c39SIngo Weinhold 				dg->head_count = 1;
6397a424c39SIngo Weinhold 				dg->device_type = info.geometry.device_type;
6407a424c39SIngo Weinhold 				dg->removable = info.geometry.removable;
6417a424c39SIngo Weinhold 				dg->read_only = info.geometry.read_only;
6427a424c39SIngo Weinhold 				dg->write_once = info.geometry.write_once;
6437a424c39SIngo Weinhold 				return B_OK;
6447a424c39SIngo Weinhold 			}
6457a424c39SIngo Weinhold 
6467a424c39SIngo Weinhold 			case B_GET_MEDIA_STATUS:
647*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_MEDIA_STATUS\n"));
6487a424c39SIngo Weinhold 				*(status_t*)arg = B_NO_ERROR;
6497a424c39SIngo Weinhold 				return B_OK;
6507a424c39SIngo Weinhold 
6517a424c39SIngo Weinhold 			case B_SET_UNINTERRUPTABLE_IO:
652*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_SET_UNINTERRUPTABLE_IO\n"));
6537a424c39SIngo Weinhold 				return B_OK;
6547a424c39SIngo Weinhold 
6557a424c39SIngo Weinhold 			case B_SET_INTERRUPTABLE_IO:
656*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_SET_INTERRUPTABLE_IO\n"));
6577a424c39SIngo Weinhold 				return B_OK;
6587a424c39SIngo Weinhold 
6597a424c39SIngo Weinhold 			case B_FLUSH_DRIVE_CACHE:
660*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_FLUSH_DRIVE_CACHE\n"));
6617a424c39SIngo Weinhold 				return B_OK;
6627a424c39SIngo Weinhold 
6637a424c39SIngo Weinhold 			case B_GET_BIOS_DRIVE_ID:
664*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: B_GET_BIOS_DRIVE_ID\n"));
6657a424c39SIngo Weinhold 				*(uint8*)arg = 0xF8;
6667a424c39SIngo Weinhold 				return B_OK;
6677a424c39SIngo Weinhold 
6687a424c39SIngo Weinhold 			case B_GET_DRIVER_FOR_DEVICE:
6697a424c39SIngo Weinhold 			case B_SET_DEVICE_SIZE:
6707a424c39SIngo Weinhold 			case B_SET_PARTITION:
6717a424c39SIngo Weinhold 			case B_FORMAT_DEVICE:
6727a424c39SIngo Weinhold 			case B_EJECT_DEVICE:
6737a424c39SIngo Weinhold 			case B_LOAD_MEDIA:
6747a424c39SIngo Weinhold 			case B_GET_NEXT_OPEN_DEVICE:
675*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: another ioctl: %lx (%lu)\n", op, op));
6767a424c39SIngo Weinhold 				return B_BAD_VALUE;
677bc4f7808SAxel Dörfler 
6787a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_REGISTER_FILE:
679*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: VIRTUAL_DRIVE_REGISTER_FILE (data)\n"));
6807a424c39SIngo Weinhold 				return B_BAD_VALUE;
6817a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_UNREGISTER_FILE:
6827a424c39SIngo Weinhold 			{
683*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: VIRTUAL_DRIVE_UNREGISTER_FILE\n"));
6847a424c39SIngo Weinhold 				lock_driver();
685bc4f7808SAxel Dörfler 
686bc4f7808SAxel Dörfler 				bool immediately = (bool)arg;
687bc4f7808SAxel Dörfler 				bool wasRegistered = info.registered;
688bc4f7808SAxel Dörfler 
689bc4f7808SAxel Dörfler 				info.registered = false;
690bc4f7808SAxel Dörfler 
6917a424c39SIngo Weinhold 				// on the last unregistration we need to close the
6927a424c39SIngo Weinhold 				// control device
6937a424c39SIngo Weinhold 				if (wasRegistered && --gRegistrationCount == 0) {
6947a424c39SIngo Weinhold 					close(gControlDeviceFD);
6957a424c39SIngo Weinhold 					gControlDeviceFD = -1;
6967a424c39SIngo Weinhold 				}
697bc4f7808SAxel Dörfler 
698bc4f7808SAxel Dörfler 				// if we "immediately" is true, we will stop our service immediately
699bc4f7808SAxel Dörfler 				// and close the underlying file, open it for other uses
700bc4f7808SAxel Dörfler 				if (immediately) {
701*8545b8bdSAxel Dörfler 					TRACE(("virtualdrive: close file descriptor\n"));
702bc4f7808SAxel Dörfler 					// we cannot use uninit_device_info() here, since that does
703bc4f7808SAxel Dörfler 					// a little too much and would open the device for other
704bc4f7808SAxel Dörfler 					// uses.
705bc4f7808SAxel Dörfler 					close(info.fd);
706bc4f7808SAxel Dörfler 					info.fd = -1;
707bc4f7808SAxel Dörfler 				}
708bc4f7808SAxel Dörfler 
7097a424c39SIngo Weinhold 				unlock_driver();
7107a424c39SIngo Weinhold 				return B_OK;
7117a424c39SIngo Weinhold 			}
7127a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_GET_INFO:
7137a424c39SIngo Weinhold 			{
714*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: VIRTUAL_DRIVE_GET_INFO\n"));
715bc4f7808SAxel Dörfler 
7167a424c39SIngo Weinhold 				virtual_drive_info *driveInfo = (virtual_drive_info *)arg;
717bc4f7808SAxel Dörfler 				if (driveInfo == NULL
718bc4f7808SAxel Dörfler 					|| driveInfo->magic != VIRTUAL_DRIVE_MAGIC
719bc4f7808SAxel Dörfler 					|| driveInfo->drive_info_size != sizeof(virtual_drive_info))
720bc4f7808SAxel Dörfler 					return B_BAD_VALUE;
721bc4f7808SAxel Dörfler 
7227a424c39SIngo Weinhold 				strcpy(driveInfo->file_name, info.file);
7237a424c39SIngo Weinhold 				strcpy(driveInfo->device_name, "/dev/");
7247a424c39SIngo Weinhold 				strcat(driveInfo->device_name, info.device_path);
7257a424c39SIngo Weinhold 				driveInfo->geometry = info.geometry;
7267a424c39SIngo Weinhold 				driveInfo->use_geometry = true;
727bc4f7808SAxel Dörfler 				driveInfo->halted = info.fd == -1;
7287a424c39SIngo Weinhold 				return B_OK;
7297a424c39SIngo Weinhold 			}
730bc4f7808SAxel Dörfler 
7317a424c39SIngo Weinhold 			default:
732*8545b8bdSAxel Dörfler 				TRACE(("virtualdrive: unknown ioctl: %lx (%lu)\n", op, op));
7337a424c39SIngo Weinhold 				return B_BAD_VALUE;
7347a424c39SIngo Weinhold 		}
7357a424c39SIngo Weinhold 	}
7367a424c39SIngo Weinhold 
7377a424c39SIngo Weinhold }
7387a424c39SIngo Weinhold 
7397a424c39SIngo Weinhold 
7407a424c39SIngo Weinhold static status_t
7417a424c39SIngo Weinhold virtualdrive_free(void *cookie)
7427a424c39SIngo Weinhold {
743*8545b8bdSAxel Dörfler 	TRACE(("virtualdrive: free cookie()\n"));
7447a424c39SIngo Weinhold 	return B_OK;
7457a424c39SIngo Weinhold }
7467a424c39SIngo Weinhold 
7477a424c39SIngo Weinhold 
7487a424c39SIngo Weinhold /* -----
7497a424c39SIngo Weinhold 	function pointers for the device hooks entry points
7507a424c39SIngo Weinhold ----- */
7517a424c39SIngo Weinhold 
752bc4f7808SAxel Dörfler device_hooks sVirtualDriveHooks = {
7537a424c39SIngo Weinhold 	virtualdrive_open, 			/* -> open entry point */
7547a424c39SIngo Weinhold 	virtualdrive_close, 		/* -> close entry point */
7557a424c39SIngo Weinhold 	virtualdrive_free,			/* -> free cookie */
7567a424c39SIngo Weinhold 	virtualdrive_control, 		/* -> control entry point */
7577a424c39SIngo Weinhold 	virtualdrive_read,			/* -> read entry point */
7587a424c39SIngo Weinhold 	virtualdrive_write			/* -> write entry point */
7597a424c39SIngo Weinhold };
7607a424c39SIngo Weinhold 
761