xref: /haiku/src/tests/kits/storage/virtualdrive/virtualdrive.cpp (revision bc4f78089ec1217674a737140a288539cb4a42d3)
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>
11*bc4f7808SAxel 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"
27*bc4f7808SAxel 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 
417a424c39SIngo Weinhold #define TRACE dprintf
427a424c39SIngo Weinhold //#define TRACE (void)
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 
51*bc4f7808SAxel 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;
67*bc4f7808SAxel Dörfler extern device_hooks sVirtualDriveHooks;
687a424c39SIngo Weinhold 
697a424c39SIngo Weinhold lock driverlock;
707a424c39SIngo Weinhold 
717a424c39SIngo Weinhold typedef struct device_info {
72*bc4f7808SAxel 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 
93*bc4f7808SAxel 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 
106*bc4f7808SAxel 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 
127*bc4f7808SAxel 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 
136*bc4f7808SAxel Dörfler 
137*bc4f7808SAxel Dörfler // dev_index_for_path
138*bc4f7808SAxel Dörfler static
139*bc4f7808SAxel Dörfler int
140*bc4f7808SAxel Dörfler dev_index_for_path(const char *path)
141*bc4f7808SAxel Dörfler {
142*bc4f7808SAxel Dörfler 	int i;
143*bc4f7808SAxel Dörfler 	for (i = 0; i < kDeviceCount; i++) {
144*bc4f7808SAxel Dörfler 		if (!strcmp(path, gDeviceInfos[i].device_path))
145*bc4f7808SAxel Dörfler 			return i;
146*bc4f7808SAxel Dörfler 	}
147*bc4f7808SAxel Dörfler 	return -1;
148*bc4f7808SAxel Dörfler }
149*bc4f7808SAxel Dörfler 
150*bc4f7808SAxel Dörfler 
1517a424c39SIngo Weinhold // clear_device_info
1527a424c39SIngo Weinhold static
1537a424c39SIngo Weinhold void
1547a424c39SIngo Weinhold clear_device_info(int32 index)
1557a424c39SIngo Weinhold {
1567a424c39SIngo Weinhold 	TRACE("virtualdrive: clear_device_info(%ld)\n", index);
157*bc4f7808SAxel Dörfler 
1587a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[index];
159*bc4f7808SAxel 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';
165*bc4f7808SAxel Dörfler 	info.device_path = sVirtualDriveName[index];
1667a424c39SIngo Weinhold 	info.geometry.read_only = true;
1677a424c39SIngo Weinhold }
1687a424c39SIngo Weinhold 
169*bc4f7808SAxel 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;
177*bc4f7808SAxel Dörfler 
1787a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[index];
1797a424c39SIngo Weinhold 	if (!info.unused)
1807a424c39SIngo Weinhold 		return B_BAD_VALUE;
181*bc4f7808SAxel Dörfler 
1827a424c39SIngo Weinhold 	bool readOnly = (initInfo->use_geometry && initInfo->geometry.read_only);
183*bc4f7808SAxel 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;
188*bc4f7808SAxel Dörfler 
1897a424c39SIngo Weinhold 	status_t error = B_OK;
190*bc4f7808SAxel 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;
198*bc4f7808SAxel 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 	}
243*bc4f7808SAxel Dörfler 
244*bc4f7808SAxel Dörfler 	if (error == B_OK) {
245*bc4f7808SAxel Dörfler 		// Disable caching for underlying file! (else this driver will deadlock)
246*bc4f7808SAxel Dörfler 		// We probably cannot resize the file once the cache has been disabled!
247*bc4f7808SAxel Dörfler 
248*bc4f7808SAxel Dörfler 		// This is a special reserved ioctl() opcode not defined anywhere in
249*bc4f7808SAxel Dörfler 		// the Be headers.
250*bc4f7808SAxel Dörfler 		if (ioctl(fd, 10000) != 0) {
251*bc4f7808SAxel Dörfler 			TRACE("virtualdrive: disable caching ioctl failed\n");
252*bc4f7808SAxel Dörfler 			return errno;
253*bc4f7808SAxel Dörfler 		}
254*bc4f7808SAxel Dörfler 	}
255*bc4f7808SAxel Dörfler 
2567a424c39SIngo Weinhold 	// fill in the rest of the device_info structure
2577a424c39SIngo Weinhold 	if (error == B_OK) {
258*bc4f7808SAxel 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);
264*bc4f7808SAxel Dörfler 		info.device_path = sVirtualDriveName[index];
2657a424c39SIngo Weinhold 	} else {
2667a424c39SIngo Weinhold 		// cleanup on error
2677a424c39SIngo Weinhold 		close(fd);
268*bc4f7808SAxel Dörfler 		if (info.open_count == 0)
2697a424c39SIngo Weinhold 			clear_device_info(index);
2707a424c39SIngo Weinhold 	}
2717a424c39SIngo Weinhold 	return error;
2727a424c39SIngo Weinhold }
2737a424c39SIngo Weinhold 
274*bc4f7808SAxel 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;
282*bc4f7808SAxel Dörfler 
2837a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[index];
2847a424c39SIngo Weinhold 	if (info.unused)
2857a424c39SIngo Weinhold 		return B_BAD_VALUE;
286*bc4f7808SAxel Dörfler 
2877a424c39SIngo Weinhold 	close(info.fd);
2887a424c39SIngo Weinhold 	clear_device_info(index);
2897a424c39SIngo Weinhold 	return B_OK;
2907a424c39SIngo Weinhold }
2917a424c39SIngo Weinhold 
292*bc4f7808SAxel Dörfler 
293*bc4f7808SAxel Dörfler //	#pragma mark -
294*bc4f7808SAxel Dörfler //	public driver API
295*bc4f7808SAxel Dörfler 
296*bc4f7808SAxel Dörfler 
2977a424c39SIngo Weinhold status_t
2987a424c39SIngo Weinhold init_hardware(void)
2997a424c39SIngo Weinhold {
3007a424c39SIngo Weinhold 	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 {
3087a424c39SIngo Weinhold 	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 {
3237a424c39SIngo Weinhold 	TRACE("virtualdrive: uninit\n");
3247a424c39SIngo Weinhold 	free_lock(&driverlock);
3257a424c39SIngo Weinhold }
3267a424c39SIngo Weinhold 
3277a424c39SIngo Weinhold 
328*bc4f7808SAxel Dörfler const char **
329*bc4f7808SAxel Dörfler publish_devices(void)
330*bc4f7808SAxel Dörfler {
331*bc4f7808SAxel Dörfler 	TRACE("virtualdrive: publish_devices\n");
332*bc4f7808SAxel Dörfler 	return sVirtualDriveName;
333*bc4f7808SAxel Dörfler }
334*bc4f7808SAxel Dörfler 
335*bc4f7808SAxel Dörfler 
336*bc4f7808SAxel Dörfler device_hooks *
337*bc4f7808SAxel Dörfler find_device(const char* name)
338*bc4f7808SAxel Dörfler {
339*bc4f7808SAxel Dörfler 	TRACE("virtualdrive: find_device(%s)\n", name);
340*bc4f7808SAxel Dörfler 	return &sVirtualDriveHooks;
341*bc4f7808SAxel Dörfler }
342*bc4f7808SAxel Dörfler 
343*bc4f7808SAxel Dörfler 
344*bc4f7808SAxel Dörfler //	#pragma mark -
345*bc4f7808SAxel Dörfler //	the device hooks
346*bc4f7808SAxel Dörfler 
3477a424c39SIngo Weinhold 
3487a424c39SIngo Weinhold static status_t
3497a424c39SIngo Weinhold virtualdrive_open(const char *name, uint32 flags, void **cookie)
3507a424c39SIngo Weinhold {
3517a424c39SIngo Weinhold 	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 
3597a424c39SIngo Weinhold 	TRACE("virtualdrive: devIndex %ld!\n", devIndex);
3607a424c39SIngo Weinhold 
3617a424c39SIngo Weinhold 	if (!is_valid_device_index(devIndex)) {
3627a424c39SIngo Weinhold 		TRACE("virtualdrive: wrong index!\n");
3637a424c39SIngo Weinhold 		unlock_driver();
3647a424c39SIngo Weinhold 		return B_ERROR;
3657a424c39SIngo Weinhold 	}
3667a424c39SIngo Weinhold 
3677a424c39SIngo Weinhold 	if (gDeviceInfos[devIndex].unused) {
3687a424c39SIngo Weinhold 		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) {
3747a424c39SIngo Weinhold 		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 
382*bc4f7808SAxel 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 	TRACE("virtualdrive: close\n");
3937a424c39SIngo Weinhold 
3947a424c39SIngo Weinhold 	int32 devIndex = (int)cookie;
3957a424c39SIngo Weinhold 
3967a424c39SIngo Weinhold 	TRACE("virtualdrive: devIndex = %ld\n", devIndex);
3977a424c39SIngo Weinhold 	if (!is_valid_data_device_index(devIndex))
3987a424c39SIngo Weinhold 		return B_OK;
3997a424c39SIngo Weinhold 
4007a424c39SIngo Weinhold 	lock_driver();
4017a424c39SIngo Weinhold 
402*bc4f7808SAxel Dörfler 	gDeviceInfos[devIndex].open_count--;
403*bc4f7808SAxel Dörfler 	if (gDeviceInfos[devIndex].open_count == 0 && !gDeviceInfos[devIndex].registered) {
4047a424c39SIngo Weinhold 		// The last FD is closed and the device has been unregistered. Free its info.
4057a424c39SIngo Weinhold 		uninit_device_info(devIndex);
4067a424c39SIngo Weinhold 	}
4077a424c39SIngo Weinhold 
4087a424c39SIngo Weinhold 	unlock_driver();
4097a424c39SIngo Weinhold 
4107a424c39SIngo Weinhold 	return B_OK;
4117a424c39SIngo Weinhold }
4127a424c39SIngo Weinhold 
4137a424c39SIngo Weinhold 
4147a424c39SIngo Weinhold static status_t
4157a424c39SIngo Weinhold virtualdrive_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
4167a424c39SIngo Weinhold {
4177a424c39SIngo Weinhold 	TRACE("virtualdrive: read pos = 0x%08Lx, bytes = 0x%08lx\n",position,*numBytes);
4187a424c39SIngo Weinhold 	// check parameters
4197a424c39SIngo Weinhold 	int devIndex = (int)cookie;
4207a424c39SIngo Weinhold 	if (devIndex == kControlDevice) {
4217a424c39SIngo Weinhold 		TRACE("virtualdrive: reading from control device not allowed\n");
4227a424c39SIngo Weinhold 		return B_NOT_ALLOWED;
4237a424c39SIngo Weinhold 	}
4247a424c39SIngo Weinhold 	if (position < 0)
4257a424c39SIngo Weinhold 		return B_BAD_VALUE;
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 {
4487a424c39SIngo Weinhold 	TRACE("virtualdrive: write pos = 0x%08Lx, bytes = 0x%08lx\n",position,*numBytes);
4497a424c39SIngo Weinhold 	// check parameters
4507a424c39SIngo Weinhold 	int devIndex = (int)cookie;
4517a424c39SIngo Weinhold 	if (devIndex == kControlDevice) {
4527a424c39SIngo Weinhold 		TRACE("virtualdrive: writing to control device not allowed\n");
4537a424c39SIngo Weinhold 		return B_NOT_ALLOWED;
4547a424c39SIngo Weinhold 	}
4557a424c39SIngo Weinhold 	if (position < 0)
4567a424c39SIngo Weinhold 		return B_BAD_VALUE;
4577a424c39SIngo Weinhold 	lock_driver();
4587a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[devIndex];
4597a424c39SIngo Weinhold 	// adjust position and numBytes according to the file size
4607a424c39SIngo Weinhold 	if (position > info.size)
4617a424c39SIngo Weinhold 		position = info.size;
4627a424c39SIngo Weinhold 	if (position + *numBytes > info.size)
4637a424c39SIngo Weinhold 		*numBytes = info.size - position;
4647a424c39SIngo Weinhold 	// read
4657a424c39SIngo Weinhold 	status_t error = B_OK;
4667a424c39SIngo Weinhold 	ssize_t bytesRead = write_pos(info.fd, position, buffer, *numBytes);
4677a424c39SIngo Weinhold 	if (bytesRead < 0)
4687a424c39SIngo Weinhold 		error = errno;
4697a424c39SIngo Weinhold 	else
4707a424c39SIngo Weinhold 		*numBytes = bytesRead;
4717a424c39SIngo Weinhold 	unlock_driver();
4727a424c39SIngo Weinhold 	return error;
4737a424c39SIngo Weinhold }
4747a424c39SIngo Weinhold 
4757a424c39SIngo Weinhold 
4767a424c39SIngo Weinhold static status_t
4777a424c39SIngo Weinhold virtualdrive_control(void *cookie, uint32 op, void *arg, size_t len)
4787a424c39SIngo Weinhold {
4797a424c39SIngo Weinhold 	TRACE("virtualdrive: ioctl\n");
4807a424c39SIngo Weinhold 
4817a424c39SIngo Weinhold 	int devIndex = (int)cookie;
4827a424c39SIngo Weinhold 	device_info &info = gDeviceInfos[devIndex];
4837a424c39SIngo Weinhold 
4847a424c39SIngo Weinhold 	if (devIndex == kControlDevice || info.unused) {
4857a424c39SIngo Weinhold 		// control device or unused data device
4867a424c39SIngo Weinhold 		switch (op) {
4877a424c39SIngo Weinhold 			case B_GET_DEVICE_SIZE:
4887a424c39SIngo Weinhold 			case B_SET_NONBLOCKING_IO:
4897a424c39SIngo Weinhold 			case B_SET_BLOCKING_IO:
4907a424c39SIngo Weinhold 			case B_GET_READ_STATUS:
4917a424c39SIngo Weinhold 			case B_GET_WRITE_STATUS:
4927a424c39SIngo Weinhold 			case B_GET_ICON:
4937a424c39SIngo Weinhold 			case B_GET_GEOMETRY:
4947a424c39SIngo Weinhold 			case B_GET_BIOS_GEOMETRY:
4957a424c39SIngo Weinhold 			case B_GET_MEDIA_STATUS:
4967a424c39SIngo Weinhold 			case B_SET_UNINTERRUPTABLE_IO:
4977a424c39SIngo Weinhold 			case B_SET_INTERRUPTABLE_IO:
4987a424c39SIngo Weinhold 			case B_FLUSH_DRIVE_CACHE:
4997a424c39SIngo Weinhold 			case B_GET_BIOS_DRIVE_ID:
5007a424c39SIngo Weinhold 			case B_GET_DRIVER_FOR_DEVICE:
5017a424c39SIngo Weinhold 			case B_SET_DEVICE_SIZE:
5027a424c39SIngo Weinhold 			case B_SET_PARTITION:
5037a424c39SIngo Weinhold 			case B_FORMAT_DEVICE:
5047a424c39SIngo Weinhold 			case B_EJECT_DEVICE:
5057a424c39SIngo Weinhold 			case B_LOAD_MEDIA:
5067a424c39SIngo Weinhold 			case B_GET_NEXT_OPEN_DEVICE:
5077a424c39SIngo Weinhold 				TRACE("virtualdrive: another ioctl: %lx (%lu)\n", op, op);
5087a424c39SIngo Weinhold 				return B_BAD_VALUE;
509*bc4f7808SAxel Dörfler 
5107a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_REGISTER_FILE:
5117a424c39SIngo Weinhold 			{
5127a424c39SIngo Weinhold 				TRACE("virtualdrive: VIRTUAL_DRIVE_REGISTER_FILE\n");
513*bc4f7808SAxel Dörfler 
5147a424c39SIngo Weinhold 				virtual_drive_info *driveInfo = (virtual_drive_info *)arg;
515*bc4f7808SAxel Dörfler 				if (devIndex != kControlDevice || driveInfo == NULL
516*bc4f7808SAxel Dörfler 					|| driveInfo->magic != VIRTUAL_DRIVE_MAGIC
517*bc4f7808SAxel Dörfler 					|| driveInfo->drive_info_size != sizeof(virtual_drive_info))
518*bc4f7808SAxel Dörfler 					return B_BAD_VALUE;
519*bc4f7808SAxel Dörfler 
5207a424c39SIngo Weinhold 				status_t error = B_ERROR;
521*bc4f7808SAxel Dörfler 				int32 i;
522*bc4f7808SAxel Dörfler 
5237a424c39SIngo Weinhold 				lock_driver();
524*bc4f7808SAxel Dörfler 
525*bc4f7808SAxel Dörfler 				// first, look if we already have opened that file and see
526*bc4f7808SAxel Dörfler 				// if it's available to us which happens when it has been
527*bc4f7808SAxel Dörfler 				// halted but is still in use by other components
528*bc4f7808SAxel Dörfler 				for (i = 0; i < kDataDeviceCount; i++) {
529*bc4f7808SAxel Dörfler 					if (!gDeviceInfos[i].unused
530*bc4f7808SAxel Dörfler 						&& gDeviceInfos[i].fd == -1
531*bc4f7808SAxel Dörfler 						&& !gDeviceInfos[i].registered
532*bc4f7808SAxel Dörfler 						&& !strcmp(gDeviceInfos[i].file, driveInfo->file_name)) {
533*bc4f7808SAxel Dörfler 						// mark device as unused, so that init_device_info() will succeed
534*bc4f7808SAxel Dörfler 						gDeviceInfos[i].unused = true;
535*bc4f7808SAxel Dörfler 						error = B_OK;
536*bc4f7808SAxel Dörfler 						break;
537*bc4f7808SAxel Dörfler 					}
538*bc4f7808SAxel Dörfler 				}
539*bc4f7808SAxel Dörfler 
540*bc4f7808SAxel Dörfler 				if (error != B_OK) {
541*bc4f7808SAxel Dörfler 					// find an unused data device
542*bc4f7808SAxel Dörfler 					for (i = 0; i < kDataDeviceCount; i++) {
5437a424c39SIngo Weinhold 						if (gDeviceInfos[i].unused) {
544*bc4f7808SAxel Dörfler 							error = B_OK;
545*bc4f7808SAxel Dörfler 							break;
546*bc4f7808SAxel Dörfler 						}
547*bc4f7808SAxel Dörfler 					}
548*bc4f7808SAxel Dörfler 				}
549*bc4f7808SAxel Dörfler 
550*bc4f7808SAxel Dörfler 				if (error == B_OK) {
551*bc4f7808SAxel Dörfler 					// we found a device slot, let's initialize it
5527a424c39SIngo Weinhold 					error = init_device_info(i, driveInfo);
5537a424c39SIngo Weinhold 					if (error == B_OK) {
5547a424c39SIngo Weinhold 						// return the device path
5557a424c39SIngo Weinhold 						strcpy(driveInfo->device_name, "/dev/");
556*bc4f7808SAxel Dörfler 						strcat(driveInfo->device_name, gDeviceInfos[i].device_path);
557*bc4f7808SAxel Dörfler 
5587a424c39SIngo Weinhold 						// on the first registration we need to open the
5597a424c39SIngo Weinhold 						// control device to stay loaded
5607a424c39SIngo Weinhold 						if (gRegistrationCount++ == 0) {
5617a424c39SIngo Weinhold 							char path[B_PATH_NAME_LENGTH];
5627a424c39SIngo Weinhold 							strcpy(path, "/dev/");
5637a424c39SIngo Weinhold 							strcat(path, info.device_path);
5647a424c39SIngo Weinhold 							gControlDeviceFD = open(path, O_RDONLY);
5657a424c39SIngo Weinhold 						}
5667a424c39SIngo Weinhold 					}
5677a424c39SIngo Weinhold 				}
568*bc4f7808SAxel Dörfler 
5697a424c39SIngo Weinhold 				unlock_driver();
5707a424c39SIngo Weinhold 				return error;
5717a424c39SIngo Weinhold 			}
5727a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_UNREGISTER_FILE:
5737a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_GET_INFO:
5747a424c39SIngo Weinhold 				TRACE("virtualdrive: VIRTUAL_DRIVE_UNREGISTER_FILE/"
5757a424c39SIngo Weinhold 					  "VIRTUAL_DRIVE_GET_INFO\n");
576*bc4f7808SAxel Dörfler 				// these are called on used data files only!
5777a424c39SIngo Weinhold 				return B_BAD_VALUE;
578*bc4f7808SAxel Dörfler 
5797a424c39SIngo Weinhold 			default:
5807a424c39SIngo Weinhold 				TRACE("virtualdrive: unknown ioctl: %lx (%lu)\n", op, op);
5817a424c39SIngo Weinhold 				return B_BAD_VALUE;
5827a424c39SIngo Weinhold 		}
5837a424c39SIngo Weinhold 	} else {
5847a424c39SIngo Weinhold 		// used data device
5857a424c39SIngo Weinhold 		switch (op) {
5867a424c39SIngo Weinhold 			case B_GET_DEVICE_SIZE:
5877a424c39SIngo Weinhold 				TRACE("virtualdrive: B_GET_DEVICE_SIZE\n");
5887a424c39SIngo Weinhold 				*(size_t*)arg = info.size;
5897a424c39SIngo Weinhold 				return B_OK;
5907a424c39SIngo Weinhold 
5917a424c39SIngo Weinhold 			case B_SET_NONBLOCKING_IO:
5927a424c39SIngo Weinhold 				TRACE("virtualdrive: B_SET_NONBLOCKING_IO\n");
5937a424c39SIngo Weinhold 				return B_OK;
5947a424c39SIngo Weinhold 
5957a424c39SIngo Weinhold 			case B_SET_BLOCKING_IO:
5967a424c39SIngo Weinhold 				TRACE("virtualdrive: B_SET_BLOCKING_IO\n");
5977a424c39SIngo Weinhold 				return B_OK;
5987a424c39SIngo Weinhold 
5997a424c39SIngo Weinhold 			case B_GET_READ_STATUS:
6007a424c39SIngo Weinhold 				TRACE("virtualdrive: B_GET_READ_STATUS\n");
6017a424c39SIngo Weinhold 				*(bool*)arg = true;
6027a424c39SIngo Weinhold 				return B_OK;
6037a424c39SIngo Weinhold 
6047a424c39SIngo Weinhold 			case B_GET_WRITE_STATUS:
6057a424c39SIngo Weinhold 				TRACE("virtualdrive: B_GET_WRITE_STATUS\n");
6067a424c39SIngo Weinhold 				*(bool*)arg = true;
6077a424c39SIngo Weinhold 				return B_OK;
6087a424c39SIngo Weinhold 
6097a424c39SIngo Weinhold 			case B_GET_ICON:
610*bc4f7808SAxel Dörfler 			{
6117a424c39SIngo Weinhold 				TRACE("virtualdrive: B_GET_ICON\n");
612*bc4f7808SAxel Dörfler 				device_icon *icon = (device_icon *)arg;
613*bc4f7808SAxel Dörfler 
614*bc4f7808SAxel Dörfler 				if (icon->icon_size == kPrimaryImageWidth) {
615*bc4f7808SAxel Dörfler 					memcpy(icon->icon_data, kPrimaryImageBits, kPrimaryImageWidth * kPrimaryImageHeight);
616*bc4f7808SAxel Dörfler 				} else if (icon->icon_size == kSecondaryImageWidth) {
617*bc4f7808SAxel Dörfler 					memcpy(icon->icon_data, kSecondaryImageBits, kSecondaryImageWidth * kSecondaryImageHeight);
618*bc4f7808SAxel Dörfler 				} else
619*bc4f7808SAxel Dörfler 					return B_ERROR;
620*bc4f7808SAxel Dörfler 
6217a424c39SIngo Weinhold 				return B_OK;
622*bc4f7808SAxel Dörfler 			}
6237a424c39SIngo Weinhold 
6247a424c39SIngo Weinhold 			case B_GET_GEOMETRY:
6257a424c39SIngo Weinhold 				TRACE("virtualdrive: B_GET_GEOMETRY\n");
6267a424c39SIngo Weinhold 				*(device_geometry *)arg = info.geometry;
6277a424c39SIngo Weinhold 				return B_OK;
6287a424c39SIngo Weinhold 
6297a424c39SIngo Weinhold 			case B_GET_BIOS_GEOMETRY:
6307a424c39SIngo Weinhold 			{
6317a424c39SIngo Weinhold 				TRACE("virtualdrive: B_GET_BIOS_GEOMETRY\n");
6327a424c39SIngo Weinhold 				device_geometry *dg = (device_geometry *)arg;
6337a424c39SIngo Weinhold 				dg->bytes_per_sector = 512;
6347a424c39SIngo Weinhold 				dg->sectors_per_track = info.size / (512 * 1024);
6357a424c39SIngo Weinhold 				dg->cylinder_count = 1024;
6367a424c39SIngo Weinhold 				dg->head_count = 1;
6377a424c39SIngo Weinhold 				dg->device_type = info.geometry.device_type;
6387a424c39SIngo Weinhold 				dg->removable = info.geometry.removable;
6397a424c39SIngo Weinhold 				dg->read_only = info.geometry.read_only;
6407a424c39SIngo Weinhold 				dg->write_once = info.geometry.write_once;
6417a424c39SIngo Weinhold 				return B_OK;
6427a424c39SIngo Weinhold 			}
6437a424c39SIngo Weinhold 
6447a424c39SIngo Weinhold 			case B_GET_MEDIA_STATUS:
6457a424c39SIngo Weinhold 				TRACE("virtualdrive: B_GET_MEDIA_STATUS\n");
6467a424c39SIngo Weinhold 				*(status_t*)arg = B_NO_ERROR;
6477a424c39SIngo Weinhold 				return B_OK;
6487a424c39SIngo Weinhold 
6497a424c39SIngo Weinhold 			case B_SET_UNINTERRUPTABLE_IO:
6507a424c39SIngo Weinhold 				TRACE("virtualdrive: B_SET_UNINTERRUPTABLE_IO\n");
6517a424c39SIngo Weinhold 				return B_OK;
6527a424c39SIngo Weinhold 
6537a424c39SIngo Weinhold 			case B_SET_INTERRUPTABLE_IO:
6547a424c39SIngo Weinhold 				TRACE("virtualdrive: B_SET_INTERRUPTABLE_IO\n");
6557a424c39SIngo Weinhold 				return B_OK;
6567a424c39SIngo Weinhold 
6577a424c39SIngo Weinhold 			case B_FLUSH_DRIVE_CACHE:
6587a424c39SIngo Weinhold 				TRACE("virtualdrive: B_FLUSH_DRIVE_CACHE\n");
6597a424c39SIngo Weinhold 				return B_OK;
6607a424c39SIngo Weinhold 
6617a424c39SIngo Weinhold 			case B_GET_BIOS_DRIVE_ID:
6627a424c39SIngo Weinhold 				TRACE("virtualdrive: B_GET_BIOS_DRIVE_ID\n");
6637a424c39SIngo Weinhold 				*(uint8*)arg = 0xF8;
6647a424c39SIngo Weinhold 				return B_OK;
6657a424c39SIngo Weinhold 
6667a424c39SIngo Weinhold 			case B_GET_DRIVER_FOR_DEVICE:
6677a424c39SIngo Weinhold 			case B_SET_DEVICE_SIZE:
6687a424c39SIngo Weinhold 			case B_SET_PARTITION:
6697a424c39SIngo Weinhold 			case B_FORMAT_DEVICE:
6707a424c39SIngo Weinhold 			case B_EJECT_DEVICE:
6717a424c39SIngo Weinhold 			case B_LOAD_MEDIA:
6727a424c39SIngo Weinhold 			case B_GET_NEXT_OPEN_DEVICE:
6737a424c39SIngo Weinhold 				TRACE("virtualdrive: another ioctl: %lx (%lu)\n", op, op);
6747a424c39SIngo Weinhold 				return B_BAD_VALUE;
675*bc4f7808SAxel Dörfler 
6767a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_REGISTER_FILE:
6777a424c39SIngo Weinhold 				TRACE("virtualdrive: VIRTUAL_DRIVE_REGISTER_FILE (data)\n");
6787a424c39SIngo Weinhold 				return B_BAD_VALUE;
6797a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_UNREGISTER_FILE:
6807a424c39SIngo Weinhold 			{
6817a424c39SIngo Weinhold 				TRACE("virtualdrive: VIRTUAL_DRIVE_UNREGISTER_FILE\n");
6827a424c39SIngo Weinhold 				lock_driver();
683*bc4f7808SAxel Dörfler 
684*bc4f7808SAxel Dörfler 				bool immediately = (bool)arg;
685*bc4f7808SAxel Dörfler 				bool wasRegistered = info.registered;
686*bc4f7808SAxel Dörfler 
687*bc4f7808SAxel Dörfler 				info.registered = false;
688*bc4f7808SAxel Dörfler 
6897a424c39SIngo Weinhold 				// on the last unregistration we need to close the
6907a424c39SIngo Weinhold 				// control device
6917a424c39SIngo Weinhold 				if (wasRegistered && --gRegistrationCount == 0) {
6927a424c39SIngo Weinhold 					close(gControlDeviceFD);
6937a424c39SIngo Weinhold 					gControlDeviceFD = -1;
6947a424c39SIngo Weinhold 				}
695*bc4f7808SAxel Dörfler 
696*bc4f7808SAxel Dörfler 				// if we "immediately" is true, we will stop our service immediately
697*bc4f7808SAxel Dörfler 				// and close the underlying file, open it for other uses
698*bc4f7808SAxel Dörfler 				if (immediately) {
699*bc4f7808SAxel Dörfler 					TRACE("virtualdrive: close file descriptor\n");
700*bc4f7808SAxel Dörfler 					// we cannot use uninit_device_info() here, since that does
701*bc4f7808SAxel Dörfler 					// a little too much and would open the device for other
702*bc4f7808SAxel Dörfler 					// uses.
703*bc4f7808SAxel Dörfler 					close(info.fd);
704*bc4f7808SAxel Dörfler 					info.fd = -1;
705*bc4f7808SAxel Dörfler 				}
706*bc4f7808SAxel Dörfler 
7077a424c39SIngo Weinhold 				unlock_driver();
7087a424c39SIngo Weinhold 				return B_OK;
7097a424c39SIngo Weinhold 			}
7107a424c39SIngo Weinhold 			case VIRTUAL_DRIVE_GET_INFO:
7117a424c39SIngo Weinhold 			{
7127a424c39SIngo Weinhold 				TRACE("virtualdrive: VIRTUAL_DRIVE_GET_INFO\n");
713*bc4f7808SAxel Dörfler 
7147a424c39SIngo Weinhold 				virtual_drive_info *driveInfo = (virtual_drive_info *)arg;
715*bc4f7808SAxel Dörfler 				if (driveInfo == NULL
716*bc4f7808SAxel Dörfler 					|| driveInfo->magic != VIRTUAL_DRIVE_MAGIC
717*bc4f7808SAxel Dörfler 					|| driveInfo->drive_info_size != sizeof(virtual_drive_info))
718*bc4f7808SAxel Dörfler 					return B_BAD_VALUE;
719*bc4f7808SAxel Dörfler 
7207a424c39SIngo Weinhold 				strcpy(driveInfo->file_name, info.file);
7217a424c39SIngo Weinhold 				strcpy(driveInfo->device_name, "/dev/");
7227a424c39SIngo Weinhold 				strcat(driveInfo->device_name, info.device_path);
7237a424c39SIngo Weinhold 				driveInfo->geometry = info.geometry;
7247a424c39SIngo Weinhold 				driveInfo->use_geometry = true;
725*bc4f7808SAxel Dörfler 				driveInfo->halted = info.fd == -1;
7267a424c39SIngo Weinhold 				return B_OK;
7277a424c39SIngo Weinhold 			}
728*bc4f7808SAxel Dörfler 
7297a424c39SIngo Weinhold 			default:
7307a424c39SIngo Weinhold 				TRACE("virtualdrive: unknown ioctl: %lx (%lu)\n", op, op);
7317a424c39SIngo Weinhold 				return B_BAD_VALUE;
7327a424c39SIngo Weinhold 		}
7337a424c39SIngo Weinhold 	}
7347a424c39SIngo Weinhold 
7357a424c39SIngo Weinhold }
7367a424c39SIngo Weinhold 
7377a424c39SIngo Weinhold 
7387a424c39SIngo Weinhold static status_t
7397a424c39SIngo Weinhold virtualdrive_free(void *cookie)
7407a424c39SIngo Weinhold {
7417a424c39SIngo Weinhold 	TRACE("virtualdrive: free\n");
7427a424c39SIngo Weinhold 	return B_OK;
7437a424c39SIngo Weinhold }
7447a424c39SIngo Weinhold 
7457a424c39SIngo Weinhold 
7467a424c39SIngo Weinhold /* -----
7477a424c39SIngo Weinhold 	function pointers for the device hooks entry points
7487a424c39SIngo Weinhold ----- */
7497a424c39SIngo Weinhold 
750*bc4f7808SAxel Dörfler device_hooks sVirtualDriveHooks = {
7517a424c39SIngo Weinhold 	virtualdrive_open, 			/* -> open entry point */
7527a424c39SIngo Weinhold 	virtualdrive_close, 		/* -> close entry point */
7537a424c39SIngo Weinhold 	virtualdrive_free,			/* -> free cookie */
7547a424c39SIngo Weinhold 	virtualdrive_control, 		/* -> control entry point */
7557a424c39SIngo Weinhold 	virtualdrive_read,			/* -> read entry point */
7567a424c39SIngo Weinhold 	virtualdrive_write			/* -> write entry point */
7577a424c39SIngo Weinhold };
7587a424c39SIngo Weinhold 
759