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
lock_driver()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
unlock_driver()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
is_valid_device_index(int32 index)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
is_valid_data_device_index(int32 index)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
dev_index_for_path(const char * path)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
clear_device_info(int32 index)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
init_device_info(int32 index,virtual_drive_info * initInfo)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
uninit_device_info(int32 index)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
init_hardware(void)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
init_driver(void)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
uninit_driver(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 **
publish_devices(void)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 *
find_device(const char * name)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
virtualdrive_open(const char * name,uint32 flags,void ** cookie)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
virtualdrive_close(void * cookie)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
virtualdrive_read(void * cookie,off_t position,void * buffer,size_t * numBytes)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
virtualdrive_write(void * cookie,off_t position,const void * buffer,size_t * numBytes)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
virtualdrive_control(void * cookie,uint32 op,void * arg,size_t len)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
virtualdrive_free(void * cookie)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