From 7ba3142d971290297a1ca7d2d4751cfc9d5713fd Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 15 Jul 2007 00:13:14 +0000 Subject: [PATCH] Kernel driver my home-brewn remote disk protocol. I actually intended to remove it completely, but I had no luck with the NBD driver. :-/ git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21603 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../drivers/disk/virtual/remote_disk/Jamfile | 12 + .../disk/virtual/remote_disk/RemoteDisk.cpp | 404 ++++++++++++++++++ .../disk/virtual/remote_disk/RemoteDisk.h | 65 +++ .../disk/virtual/remote_disk/remote_disk.cpp | 379 ++++++++++++++++ 4 files changed, 860 insertions(+) create mode 100644 src/add-ons/kernel/drivers/disk/virtual/remote_disk/Jamfile create mode 100644 src/add-ons/kernel/drivers/disk/virtual/remote_disk/RemoteDisk.cpp create mode 100644 src/add-ons/kernel/drivers/disk/virtual/remote_disk/RemoteDisk.h create mode 100644 src/add-ons/kernel/drivers/disk/virtual/remote_disk/remote_disk.cpp diff --git a/src/add-ons/kernel/drivers/disk/virtual/remote_disk/Jamfile b/src/add-ons/kernel/drivers/disk/virtual/remote_disk/Jamfile new file mode 100644 index 0000000000..de55ad9a08 --- /dev/null +++ b/src/add-ons/kernel/drivers/disk/virtual/remote_disk/Jamfile @@ -0,0 +1,12 @@ +SubDir HAIKU_TOP src add-ons kernel drivers disk virtual remote_disk ; + +UsePrivateHeaders kernel ; +UseArchHeaders $(TARGET_ARCH) ; +UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ; + # TODO: Ugly! + +KernelAddon remote_disk : + remote_disk.cpp + + RemoteDisk.cpp +; diff --git a/src/add-ons/kernel/drivers/disk/virtual/remote_disk/RemoteDisk.cpp b/src/add-ons/kernel/drivers/disk/virtual/remote_disk/RemoteDisk.cpp new file mode 100644 index 0000000000..5cbb0a831f --- /dev/null +++ b/src/add-ons/kernel/drivers/disk/virtual/remote_disk/RemoteDisk.cpp @@ -0,0 +1,404 @@ +/* + * Copyright 2005-2007, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "RemoteDisk.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include // for IS_USER_ADDRESS() + + +//#define TRACE_REMOTE_DISK +#ifdef TRACE_REMOTE_DISK +# define TRACE(x) dprintf x +#else +# define TRACE(x) do {} while (false) +#endif + + +static const bigtime_t kReceiveTimeout = 30000LL; +static const bigtime_t kRequestTimeout = 100000LL; + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +static inline +uint64_t swap_uint64(uint64_t data) +{ + return ((data & 0xff) << 56) + | ((data & 0xff00) << 40) + | ((data & 0xff0000) << 24) + | ((data & 0xff000000) << 8) + | ((data >> 8) & 0xff000000) + | ((data >> 24) & 0xff0000) + | ((data >> 40) & 0xff00) + | ((data >> 56) & 0xff); +} + +#define host_to_net64(data) swap_uint64(data) +#define net_to_host64(data) swap_uint64(data) + +#endif + +#if __BYTE_ORDER == __BIG_ENDIAN +#define host_to_net64(data) (data) +#define net_to_host64(data) (data) +#endif + +#undef htonll +#undef ntohll +#define htonll(data) host_to_net64(data) +#define ntohll(data) net_to_host64(data) + + +enum { + BUFFER_SIZE = 2048 +}; + + +// constructor +RemoteDisk::RemoteDisk() + : fImageSize(0), + fRequestID(0), + fSocket(-1), + fPacket(NULL), + fPacketSize(0) +{ +} + + +// destructor +RemoteDisk::~RemoteDisk() +{ + if (fSocket >= 0) + close(fSocket); + + free(fPacket); +} + + +// Init +status_t +RemoteDisk::Init(uint32 serverAddress, uint16 serverPort, off_t imageSize) +{ + status_t error = _Init(); + if (error != B_OK) + return error; + + fServerAddress.sin_family = AF_INET; + fServerAddress.sin_port = htons(serverPort); + fServerAddress.sin_addr.s_addr = htonl(serverAddress); + + fImageSize = imageSize; + + return B_OK; +} + + +// FindAnyRemoteDisk +status_t +RemoteDisk::FindAnyRemoteDisk() +{ + status_t error = _Init(); + if (error != B_OK) + return error; + + // prepare request + remote_disk_header request; + request.command = REMOTE_DISK_HELLO_REQUEST; + + // init server address to broadcast + fServerAddress.sin_family = AF_INET; + fServerAddress.sin_port = htons(REMOTE_DISK_SERVER_PORT); + fServerAddress.sin_addr.s_addr = htonl(INADDR_BROADCAST); + + // set SO_BROADCAST on socket + int soBroadcastValue = 1; + if (fSocketModule->setsockopt(fSocket, SOL_SOCKET, SO_BROADCAST, + &soBroadcastValue, sizeof(soBroadcastValue)) < 0) { + dprintf("RemoteDisk::Init(): Failed to set SO_BROADCAST on socket: " + "%s\n", strerror(errno)); + } + + // send request + sockaddr_in serverAddress; + error = _SendRequest(&request, sizeof(request), REMOTE_DISK_HELLO_REPLY, + &serverAddress); + if (error != B_OK) { + dprintf("RemoteDisk::FindAnyRemoteDisk(): Got no server reply.\n"); + return error; + } + remote_disk_header* reply = (remote_disk_header*)fPacket; + + // unset SO_BROADCAST on socket + soBroadcastValue = 0; + if (fSocketModule->setsockopt(fSocket, SOL_SOCKET, SO_BROADCAST, + &soBroadcastValue, sizeof(soBroadcastValue)) < 0) { + dprintf("RemoteDisk::Init(): Failed to unset SO_BROADCAST on socket: " + "%s\n", strerror(errno)); + } + + // init server address and size + fServerAddress = serverAddress; + fServerAddress.sin_port = reply->port; + + fImageSize = ntohll(reply->offset); + + return B_OK; +} + + +// ReadAt +ssize_t +RemoteDisk::ReadAt(off_t pos, void *_buffer, size_t bufferSize) +{ + if (fSocket < 0) + return B_NO_INIT; + + uint8 *buffer = (uint8*)_buffer; + if (!buffer || pos < 0) + return B_BAD_VALUE; + + if (bufferSize == 0) + return 0; + + // Check whether the current packet already contains the beginning of the + // data to read. + ssize_t bytesRead = _ReadFromPacket(pos, buffer, bufferSize); + if (bytesRead < 0) + return bytesRead; + + // If there still remains something to be read, we need to get it from the + // server. + status_t error = B_OK; + while (bufferSize > 0) { + // prepare request + remote_disk_header request; + request.offset = htonll(pos); + uint32 toRead = min_c(bufferSize, REMOTE_DISK_BLOCK_SIZE); + request.size = htons(toRead); + request.command = REMOTE_DISK_READ_REQUEST; + + // send request + error = _SendRequest(&request, sizeof(request), REMOTE_DISK_READ_REPLY); + if (error != B_OK) + break; + + // check for errors + int16 packetSize = ntohs(((remote_disk_header*)fPacket)->size); + if (packetSize < 0) { + if (packetSize == REMOTE_DISK_IO_ERROR) + error = B_IO_ERROR; + else if (packetSize == REMOTE_DISK_BAD_REQUEST) + error = B_BAD_VALUE; + fPacketSize = 0; + break; + } + + // read from the packet + size_t packetBytesRead = _ReadFromPacket(pos, buffer, bufferSize); + if (packetBytesRead <= 0) { + if (packetBytesRead < 0) + error = packetBytesRead; + break; + } + bytesRead += packetBytesRead; + } + + // only return an error, when we were not able to read anything at all + return (bytesRead == 0 ? error : bytesRead); +} + + +// WriteAt +ssize_t +RemoteDisk::WriteAt(off_t pos, const void *buffer, size_t bufferSize) +{ + // TODO: Implement! + return B_PERMISSION_DENIED; +} + + +// _Init +status_t +RemoteDisk::_Init() +{ + // get the socket module + status_t error = get_module(B_SOCKET_MODULE_NAME, + (module_info**)&fSocketModule); + if (error != B_OK) { + dprintf("RemoteDisk::Init(): Failed to load socket module: %s\n", + strerror(error)); + return error; + } + + // open a control socket for playing with the stack + fSocket = fSocketModule->socket(AF_INET, SOCK_DGRAM, 0); + if (fSocket < 0) { + dprintf("RemoteDisk::Init(): Failed to open socket: %s\n", + strerror(errno)); + return errno; + } + + // bind socket + fSocketAddress.sin_family = AF_INET; + fSocketAddress.sin_port = 0; + fSocketAddress.sin_addr.s_addr = INADDR_ANY; + if (fSocketModule->bind(fSocket, (sockaddr*)&fSocketAddress, + sizeof(fSocketAddress)) < 0) { + dprintf("RemoteDisk::Init(): Failed to bind socket: %s\n", + strerror(errno)); + return errno; + } + + // get the port + socklen_t addrSize = sizeof(fSocketAddress); + if (fSocketModule->getsockname(fSocket, (sockaddr*)&fSocketAddress, + &addrSize) < 0) { + dprintf("RemoteDisk::Init(): Failed to get socket address: %s\n", + strerror(errno)); + return errno; + } + + // set receive timeout + timeval timeout; + timeout.tv_sec = time_t(kReceiveTimeout / 1000000LL); + timeout.tv_usec = suseconds_t(kReceiveTimeout % 1000000LL); + if (fSocketModule->setsockopt(fSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, + sizeof(timeout)) < 0) { + dprintf("RemoteDisk::Init(): Failed to set socket receive timeout: " + "%s\n", strerror(errno)); + return errno; + } + + // allocate buffer + fPacket = malloc(BUFFER_SIZE); + if (!fPacket) + return B_NO_MEMORY; + + return B_OK; +} + + +// _ReadFromPacket +ssize_t +RemoteDisk::_ReadFromPacket(off_t& pos, uint8*& buffer, size_t& bufferSize) +{ + if (fPacketSize == 0) + return 0; + + // check whether the cached packet is indeed a read reply + remote_disk_header* header = (remote_disk_header*)fPacket; + if (header->command != REMOTE_DISK_READ_REPLY) + return 0; + + uint64 packetOffset = ntohll(header->offset); + uint32 packetSize = ntohs(header->size); + if (packetOffset > (uint64)pos || packetOffset + packetSize <= (uint64)pos) + return 0; + + // we have something to copy + size_t toCopy = size_t(packetOffset + packetSize - (uint64)pos); + if (toCopy > bufferSize) + toCopy = bufferSize; + + if (IS_USER_ADDRESS(buffer)) { + status_t error = user_memcpy(buffer, + header->data + (pos - packetOffset), toCopy); + if (error != B_OK) + return error; + } else + memcpy(buffer, header->data + (pos - packetOffset), toCopy); + + pos += toCopy; + buffer += toCopy; + bufferSize -= toCopy; + return toCopy; +} + + +// _SendRequest +status_t +RemoteDisk::_SendRequest(remote_disk_header* request, size_t size, + uint8 expectedReply, sockaddr_in* peerAddress) +{ + request->request_id = fRequestID++; + request->port = fSocketAddress.sin_port; + + // try sending the request 3 times at most + for (int i = 0; i < 3; i++) { + // send request +//bool debug = false; +//{ +//thread_info threadInfo; +//get_thread_info(find_thread(NULL), &threadInfo); +////debug = (strcmp(threadInfo.name, "AddOnMonitor") == 0); +//debug = (find_thread(NULL) >= 60); +//if (debug) { +////panic("RemoteDisk::_SendRequest(): AddOnMonitor\n"); +//TRACE(("[%ld: %s] RemoteDisk::_SendRequest(): sendto(%d, %p, %lu, 0, %p, %lu)\n", +//find_thread(NULL), threadInfo.name, fSocket, request, size, (sockaddr*)&fServerAddress, sizeof(fServerAddress))); +//} +//} + ssize_t bytesSent = fSocketModule->sendto(fSocket, request, size, + 0, (sockaddr*)&fServerAddress, sizeof(fServerAddress)); + if (bytesSent < 0) + return errno; + if (bytesSent != (ssize_t)size) { + dprintf("RemoteDisk::_SendRequest(): sent less bytes than desired"); + return B_ERROR; + } + + // receive reply + bigtime_t timeout = system_time() + kRequestTimeout; + do { + fPacketSize = 0; + socklen_t addrSize = sizeof(sockaddr_in); +//if (debug) { +//TRACE(("[%ld] RemoteDisk::_SendRequest(): recvfrom(%d, %p, %u, 0, %p, %p)\n", +//find_thread(NULL), fSocket, fPacket, BUFFER_SIZE, (sockaddr*)&peerAddress, (peerAddress ? &addrSize : 0))); +//} + ssize_t bytesReceived = fSocketModule->recvfrom(fSocket, + fPacket, BUFFER_SIZE, 0, (sockaddr*)peerAddress, + (peerAddress ? &addrSize : 0)); + if (bytesReceived < 0) { +//if (debug) { +//TRACE(("[%ld] RemoteDisk::_SendRequest(): recvfrom() failed: %s\n", find_thread(NULL), strerror(errno))); +//} + status_t error = errno; + if (error != B_TIMED_OUT && error != B_WOULD_BLOCK) + return error; + continue; + } + + // got something; check, if it is looks good + if (bytesReceived >= (ssize_t)sizeof(remote_disk_header)) { + remote_disk_header* reply = (remote_disk_header*)fPacket; + if (reply->request_id == request->request_id + && reply->command == expectedReply) { + fPacketSize = bytesReceived; +//if (debug) { +//TRACE(("[%ld] RemoteDisk::_SendRequest(): done: packet size: %ld\n", find_thread(NULL), bytesReceived)); +//} + return B_OK; + } + } + } while (timeout > system_time()); + } + + // no reply + return B_ERROR; +} diff --git a/src/add-ons/kernel/drivers/disk/virtual/remote_disk/RemoteDisk.h b/src/add-ons/kernel/drivers/disk/virtual/remote_disk/RemoteDisk.h new file mode 100644 index 0000000000..cd4592d30a --- /dev/null +++ b/src/add-ons/kernel/drivers/disk/virtual/remote_disk/RemoteDisk.h @@ -0,0 +1,65 @@ +/* + * Copyright 2005-2007, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#ifndef _BOOT_REMOTE_DISK_H +#define _BOOT_REMOTE_DISK_H + +#include + +#include + +#include + +#include + + +class RemoteDisk { +public: + RemoteDisk(); + ~RemoteDisk(); + + status_t Init(uint32 serverAddress, uint16 serverPort, + off_t imageSize); + + status_t FindAnyRemoteDisk(); + + ssize_t ReadAt(off_t pos, void *buffer, + size_t bufferSize); + ssize_t WriteAt(off_t pos, const void *buffer, + size_t bufferSize); + + off_t Size() const + { return fImageSize; } + + bool IsReadOnly() const + { return true; } // TODO:... + +// uint32 ServerIPAddress() const +// { return fServerAddress; } +// uint16 ServerPort() const +// { return fServerPort; } + +private: + status_t _Init(); + + ssize_t _ReadFromPacket(off_t& pos, uint8*& buffer, + size_t& bufferSize); + + status_t _SendRequest(remote_disk_header *request, + size_t size, uint8 expectedReply, + sockaddr_in* peerAddress = NULL); + +private: + socket_module_info* fSocketModule; + sockaddr_in fSocketAddress; + sockaddr_in fServerAddress; + off_t fImageSize; + uint64 fRequestID; + int fSocket; + void* fPacket; + int32 fPacketSize; +}; + +#endif // _BOOT_REMOTE_DISK_H diff --git a/src/add-ons/kernel/drivers/disk/virtual/remote_disk/remote_disk.cpp b/src/add-ons/kernel/drivers/disk/virtual/remote_disk/remote_disk.cpp new file mode 100644 index 0000000000..df6be19679 --- /dev/null +++ b/src/add-ons/kernel/drivers/disk/virtual/remote_disk/remote_disk.cpp @@ -0,0 +1,379 @@ +/* + * Copyright 2007, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include +#include + +#include +#include +#include + +#include "RemoteDisk.h" + + +//#define TRACE_REMOTE_DISK +#ifdef TRACE_REMOTE_DISK +# define TRACE(x) dprintf x +#else +# define TRACE(x) do {} while (false) +#endif + + +const bigtime_t kInitRetryDelay = 10 * 1000000LL; // 10 s + +enum { + MAX_REMOTE_DISKS = 1 +}; + + +struct RemoteDiskDevice : recursive_lock { + RemoteDisk* remoteDisk; + bigtime_t lastInitRetryTime; + + RemoteDiskDevice() + : remoteDisk(NULL), + lastInitRetryTime(-1) + { + sem = -1; + } + + ~RemoteDiskDevice() + { + delete remoteDisk; + Uninit(); + } + + status_t Init() + { + return recursive_lock_init(this, "remote disk device"); + } + + void Uninit() + { + recursive_lock_destroy(this); + } + + status_t LazyInitDisk() + { + if (remoteDisk) + return B_OK; + + // don't try to init, if the last attempt wasn't long enough ago + if (lastInitRetryTime >= 0 + && system_time() < lastInitRetryTime + kInitRetryDelay) { + return B_ERROR; + } + + // create the object + remoteDisk = new(nothrow) RemoteDisk; + if (!remoteDisk) { + lastInitRetryTime = system_time(); + return B_NO_MEMORY; + } + + // find a server + TRACE(("remote_disk: FindAnyRemoteDisk()\n")); + status_t error = remoteDisk->FindAnyRemoteDisk(); + if (error != B_OK) { + delete remoteDisk; + remoteDisk = NULL; + lastInitRetryTime = system_time(); + return B_NO_MEMORY; + } + + return B_OK; + } + + void GetGeometry(device_geometry* geometry, bool bios) + { + // TODO: Respect "bios" argument! + geometry->bytes_per_sector = REMOTE_DISK_BLOCK_SIZE; + geometry->sectors_per_track = 1; + geometry->cylinder_count = remoteDisk->Size() / REMOTE_DISK_BLOCK_SIZE; + geometry->head_count = 1; + geometry->device_type = B_DISK; + geometry->removable = true; + geometry->read_only = remoteDisk->IsReadOnly(); + geometry->write_once = false; + } +}; + +typedef RecursiveLocker DeviceLocker; + + +static const char* kPublishedNames[] = { + "disk/virtual/remote_disk/0/raw", +// "misc/remote_disk_control", + NULL +}; + +static RemoteDiskDevice* sDevices; + + +// #pragma mark - internal functions + + +// device_for_name +static RemoteDiskDevice* +device_for_name(const char* name) +{ + for (int i = 0; i < MAX_REMOTE_DISKS; i++) { + if (strcmp(name, kPublishedNames[i]) == 0) + return sDevices + i; + } + return NULL; +} + + +// #pragma mark - data device hooks + + +static status_t +remote_disk_open(const char* name, uint32 flags, void** cookie) +{ + RemoteDiskDevice* device = device_for_name(name); + TRACE(("remote_disk_open(\"%s\") -> %p\n", name, device)); + if (!device) + return B_BAD_VALUE; + + DeviceLocker locker(device); + status_t error = device->LazyInitDisk(); + if (error != B_OK) + return error; + + *cookie = device; + + return B_OK; +} + + +static status_t +remote_disk_close(void* cookie) +{ + TRACE(("remote_disk_close(%p)\n", cookie)); + + // nothing to do + return B_OK; +} + + +static status_t +remote_disk_read(void* cookie, off_t position, void* buffer, size_t* numBytes) +{ + TRACE(("remote_disk_read(%p, %lld, %p, %lu)\n", cookie, position, buffer, + *numBytes)); + + RemoteDiskDevice* device = (RemoteDiskDevice*)cookie; + DeviceLocker locker(device); + + ssize_t bytesRead = device->remoteDisk->ReadAt(position, buffer, *numBytes); + if (bytesRead < 0) { + *numBytes = 0; +TRACE(("remote_disk_read() failed: %s\n", strerror(bytesRead))); + return bytesRead; + } + + *numBytes = bytesRead; +TRACE(("remote_disk_read() done: %ld\n", bytesRead)); + return B_OK; +} + + +static status_t +remote_disk_write(void* cookie, off_t position, const void* buffer, + size_t* numBytes) +{ + TRACE(("remote_disk_write(%p, %lld, %p, %lu)\n", cookie, position, buffer, + *numBytes)); + + RemoteDiskDevice* device = (RemoteDiskDevice*)cookie; + DeviceLocker locker(device); + + ssize_t bytesWritten = device->remoteDisk->WriteAt(position, buffer, + *numBytes); + if (bytesWritten < 0) { + *numBytes = 0; + return bytesWritten; + } + + *numBytes = bytesWritten; + return B_OK; +} + + +static status_t +remote_disk_control(void* cookie, uint32 op, void* arg, size_t len) +{ + TRACE(("remote_disk_control(%p, %lu, %p, %lu)\n", cookie, op, arg, len)); + + RemoteDiskDevice* device = (RemoteDiskDevice*)cookie; + DeviceLocker locker(device); + + // used data device + switch (op) { + case B_GET_DEVICE_SIZE: + TRACE(("remote_disk: B_GET_DEVICE_SIZE\n")); + *(size_t*)arg = device->remoteDisk->Size(); + return B_OK; + + case B_SET_NONBLOCKING_IO: + TRACE(("remote_disk: B_SET_NONBLOCKING_IO\n")); + return B_OK; + + case B_SET_BLOCKING_IO: + TRACE(("remote_disk: B_SET_BLOCKING_IO\n")); + return B_OK; + + case B_GET_READ_STATUS: + TRACE(("remote_disk: B_GET_READ_STATUS\n")); + *(bool*)arg = true; + return B_OK; + + case B_GET_WRITE_STATUS: + TRACE(("remote_disk: B_GET_WRITE_STATUS\n")); + *(bool*)arg = true; + return B_OK; + + case B_GET_ICON: + { + TRACE(("remote_disk: B_GET_ICON\n")); + return B_BAD_VALUE; + } + + case B_GET_GEOMETRY: + TRACE(("remote_disk: B_GET_GEOMETRY\n")); + device->GetGeometry((device_geometry*)arg, false); + return B_OK; + + case B_GET_BIOS_GEOMETRY: + { + TRACE(("remote_disk: B_GET_BIOS_GEOMETRY\n")); + device->GetGeometry((device_geometry*)arg, true); + return B_OK; + } + + case B_GET_MEDIA_STATUS: + TRACE(("remote_disk: B_GET_MEDIA_STATUS\n")); + *(status_t*)arg = B_NO_ERROR; + return B_OK; + + case B_SET_UNINTERRUPTABLE_IO: + TRACE(("remote_disk: B_SET_UNINTERRUPTABLE_IO\n")); + return B_OK; + + case B_SET_INTERRUPTABLE_IO: + TRACE(("remote_disk: B_SET_INTERRUPTABLE_IO\n")); + return B_OK; + + case B_FLUSH_DRIVE_CACHE: + TRACE(("remote_disk: B_FLUSH_DRIVE_CACHE\n")); + return B_OK; + + case B_GET_BIOS_DRIVE_ID: + TRACE(("remote_disk: B_GET_BIOS_DRIVE_ID\n")); + *(uint8*)arg = 0xF8; + return B_OK; + + case B_GET_DRIVER_FOR_DEVICE: + case B_SET_DEVICE_SIZE: + case B_SET_PARTITION: + case B_FORMAT_DEVICE: + case B_EJECT_DEVICE: + case B_LOAD_MEDIA: + case B_GET_NEXT_OPEN_DEVICE: + TRACE(("remote_disk: another ioctl: %lx (%lu)\n", op, op)); + return B_BAD_VALUE; + + default: + TRACE(("remote_disk: unknown ioctl: %lx (%lu)\n", op, op)); + return B_BAD_VALUE; + } +} + + +static status_t +remote_disk_free(void* cookie) +{ + TRACE(("remote_disk_free(%p)\n", cookie)); + + // nothing to do + return B_OK; +} + + +static device_hooks sDataDeviceHooks = { + remote_disk_open, + remote_disk_close, + remote_disk_free, + remote_disk_control, + remote_disk_read, + remote_disk_write +}; + + +// #pragma mark - public API + + +int32 api_version = B_CUR_DRIVER_API_VERSION; + + +status_t +init_hardware(void) +{ + TRACE(("remote_disk: init_hardware()\n")); + + return B_OK; +} + + +status_t +init_driver(void) +{ + TRACE(("remote_disk: init_driver()\n")); + + sDevices = new(nothrow) RemoteDiskDevice[MAX_REMOTE_DISKS]; + if (!sDevices) + return B_NO_MEMORY; + + status_t error = B_OK; + for (int i = 0; error == B_OK && i < MAX_REMOTE_DISKS; i++) + error = sDevices[i].Init(); + + if (error != B_OK) { + delete[] sDevices; + sDevices = NULL; + return error; + } + + return B_OK; +} + + +void +uninit_driver(void) +{ + TRACE(("remote_disk: uninit_driver()\n")); + + delete[] sDevices; +} + + +const char** +publish_devices(void) +{ + TRACE(("remote_disk: publish_devices()\n")); + return kPublishedNames; +} + + +device_hooks* +find_device(const char* name) +{ + TRACE(("remote_disk: find_device(%s)\n", name)); + return &sDataDeviceHooks; +} +