diff options
Diffstat (limited to 'src/VBox/Additions/haiku')
36 files changed, 6678 insertions, 0 deletions
diff --git a/src/VBox/Additions/haiku/.scm-settings b/src/VBox/Additions/haiku/.scm-settings new file mode 100644 index 00000000..12be50ac --- /dev/null +++ b/src/VBox/Additions/haiku/.scm-settings @@ -0,0 +1,30 @@ +# $Id: .scm-settings $ +## @file +# Source code massager settings for haiku guest additions. +# + +# +# Copyright (C) 2010-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + + +/VBoxTray/VBoxTray.rdef: --treat-as .rc + diff --git a/src/VBox/Additions/haiku/Makefile.kmk b/src/VBox/Additions/haiku/Makefile.kmk new file mode 100644 index 00000000..77c9dc0f --- /dev/null +++ b/src/VBox/Additions/haiku/Makefile.kmk @@ -0,0 +1,73 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for Haiku Guest Additions. +# + +# +# Copyright (C) 2012-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +# +# This code is based on: +# +# VirtualBox Guest Additions for Haiku. +# Copyright (c) 2011 Mike Smith <mike@scgtrp.net> +# François Revol <revol@free.fr> +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +SUB_DEPTH = ../../../.. +include $(KBUILD_PATH)/subheader.kmk + +ifneq ($(KBUILD_HOST),haiku) + $(error "The Haiku guest additions installer can only be built on Haiku!") +endif + +# +# Include sub-makefiles. +# +include $(PATH_SUB_CURRENT)/SharedFolders/Makefile.kmk +include $(PATH_SUB_CURRENT)/VBoxMouse/Makefile.kmk +include $(PATH_SUB_CURRENT)/VBoxTray/Makefile.kmk +include $(PATH_SUB_CURRENT)/VBoxVideo/Makefile.kmk + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/haiku/SharedFolders/Makefile.kmk b/src/VBox/Additions/haiku/SharedFolders/Makefile.kmk new file mode 100644 index 00000000..daa5d002 --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/Makefile.kmk @@ -0,0 +1,89 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for shared folders, Haiku Guest Additions. +# + +# +# Copyright (C) 2012-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +# +# This code is based on: +# +# VirtualBox Guest Additions for Haiku. +# Copyright (c) 2011 Mike Smith <mike@scgtrp.net> +# François Revol <revol@free.fr> +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +ifdef VBOX_WITH_ADDITION_DRIVERS + SYSMODS += vboxsf +endif + +# +# Populate FILES_VBOXSF_NOBIN +# +#include $(PATH_SUB_CURRENT)/files_vboxsf + +# +# The module (for syntax checking). +# The DEBUG_HASH* stuff is for CONFIG_DYNAMIC_DEBUG-enabled kernels +# +vboxsf_TEMPLATE = VBoxGuestR0Drv +vboxsf_DEFS = \ + MODULE IN_RT_R0 VBOXGUEST VBOX_WITH_HGCM \ + KBUILD_MODNAME=KBUILD_STR\(vboxsf\) \ + KBUILD_BASENAME=KBUILD_STR\(vboxsf\) +vboxsf_INCS = \ + $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest \ + $(PATH_ROOT)/src/VBox/Runtime/r0drv/haiku +vboxsf_SOURCES = \ + vboxsf.c \ + vnode_cache.cpp \ + $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku-stubs.c +vboxsf_LIBS = \ + $(VBOX_LIB_VBGL_R0) + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/haiku/SharedFolders/OpenHashTable.h b/src/VBox/Additions/haiku/SharedFolders/OpenHashTable.h new file mode 100644 index 00000000..ac01704d --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/OpenHashTable.h @@ -0,0 +1,515 @@ +/* $Id: OpenHashTable.h $ */ +/** @file + * OpenHashTable, Haiku Guest Additions. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * + * Copyright 2007, Hugo Santos. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + +#ifndef GA_INCLUDED_SRC_haiku_SharedFolders_OpenHashTable_h +#define GA_INCLUDED_SRC_haiku_SharedFolders_OpenHashTable_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include <OS.h> +#include <stdlib.h> +#include <string.h> + +#ifdef _KERNEL_MODE +# include <KernelExport.h> +# include "kernel_cpp.h" +#endif + +/*! + The Definition template must have four methods: `HashKey', `Hash', + `Compare' and `GetLink;. It must also define several types as shown in the + following example: + + struct Foo { + int bar; + + Foo* fNext; + }; + + struct HashTableDefinition { + typedef int KeyType; + typedef Foo ValueType; + + size_t HashKey(int key) const + { + return key >> 1; + } + + size_t Hash(Foo* value) const + { + return HashKey(value->bar); + } + + bool Compare(int key, Foo* value) const + { + return value->bar == key; + } + + Foo*& GetLink(Foo* value) const + { + return value->fNext; + } + }; +*/ + + +struct MallocAllocator +{ + void* Allocate(size_t size) const + { + return malloc(size); + } + + void Free(void* memory) const + { + free(memory); + } +}; + + +template<typename Definition, bool AutoExpand = true, + bool CheckDuplicates = false, typename Allocator = MallocAllocator> +class BOpenHashTable +{ +public: + typedef BOpenHashTable<Definition, AutoExpand, CheckDuplicates> HashTable; + typedef typename Definition::KeyType KeyType; + typedef typename Definition::ValueType ValueType; + + static const size_t kMinimumSize = 8; + + // All allocations are of power of 2 lengths. + + // regrowth factor: 200 / 256 = 78.125% + // 50 / 256 = 19.53125% + + BOpenHashTable() + : + fTableSize(0), + fItemCount(0), + fTable(NULL) + { + } + + BOpenHashTable(const Definition& definition) + : + fDefinition(definition), + fTableSize(0), + fItemCount(0), + fTable(NULL) + { + } + + BOpenHashTable(const Definition& definition, const Allocator& allocator) + : + fDefinition(definition), + fAllocator(allocator), + fTableSize(0), + fItemCount(0), + fTable(NULL) + { + } + + ~BOpenHashTable() + { + fAllocator.Free(fTable); + } + + status_t Init(size_t initialSize = kMinimumSize) + { + if (initialSize > 0 && !_Resize(initialSize)) + return B_NO_MEMORY; + return B_OK; + } + + size_t TableSize() const + { + return fTableSize; + } + + size_t CountElements() const + { + return fItemCount; + } + + ValueType* Lookup(const KeyType& key) const + { + if (fTableSize == 0) + return NULL; + + size_t index = fDefinition.HashKey(key) & (fTableSize - 1); + ValueType* slot = fTable[index]; + + while (slot) + { + if (fDefinition.Compare(key, slot)) + break; + slot = _Link(slot); + } + + return slot; + } + + status_t Insert(ValueType* value) + { + if (fTableSize == 0) + { + if (!_Resize(kMinimumSize)) + return B_NO_MEMORY; + } + else if (AutoExpand && fItemCount >= (fTableSize * 200 / 256)) + _Resize(fTableSize * 2); + + InsertUnchecked(value); + return B_OK; + } + + void InsertUnchecked(ValueType* value) + { + if (CheckDuplicates && _ExhaustiveSearch(value)) + { +#ifdef _KERNEL_MODE + panic("Hash Table: value already in table."); +#else + debugger("Hash Table: value already in table."); +#endif + } + + _Insert(fTable, fTableSize, value); + fItemCount++; + } + + // TODO: a ValueType* Remove(const KeyType& key) method is missing + + bool Remove(ValueType* value) + { + if (!RemoveUnchecked(value)) + return false; + + if (AutoExpand && fTableSize > kMinimumSize + && fItemCount < (fTableSize * 50 / 256)) + _Resize(fTableSize / 2); + + return true; + } + + bool RemoveUnchecked(ValueType* value) + { + size_t index = fDefinition.Hash(value) & (fTableSize - 1); + ValueType* previous = NULL; + ValueType* slot = fTable[index]; + + while (slot) + { + ValueType* next = _Link(slot); + + if (value == slot) + { + if (previous) + _Link(previous) = next; + else + fTable[index] = next; + break; + } + + previous = slot; + slot = next; + } + + if (slot == NULL) + return false; + + if (CheckDuplicates && _ExhaustiveSearch(value)) + { +#ifdef _KERNEL_MODE + panic("Hash Table: duplicate detected."); +#else + debugger("Hash Table: duplicate detected."); +#endif + } + + fItemCount--; + return true; + } + + /*! Removes all elements from the hash table. No resizing happens. The + elements are not deleted. If \a returnElements is \c true, the method + returns all elements chained via their hash table link. + */ + ValueType* Clear(bool returnElements = false) + { + if (this->fItemCount == 0) + return NULL; + + ValueType* result = NULL; + + if (returnElements) + { + ValueType** nextPointer = &result; + + // iterate through all buckets + for (size_t i = 0; i < fTableSize; i++) + { + ValueType* element = fTable[i]; + if (element != NULL) + { + // add the bucket to the list + *nextPointer = element; + + // update nextPointer to point to the fNext of the last + // element in the bucket + while (element != NULL) + { + nextPointer = &_Link(element); + element = *nextPointer; + } + } + } + } + + memset(this->fTable, 0, sizeof(ValueType*) * this->fTableSize); + + return result; + } + + /*! If the table needs resizing, the number of bytes for the required + allocation is returned. If no resizing is needed, 0 is returned. + */ + size_t ResizeNeeded() const + { + size_t size = fTableSize; + if (size == 0 || fItemCount >= (size * 200 / 256)) + { + // grow table + if (size == 0) + size = kMinimumSize; + while (fItemCount >= size * 200 / 256) + size <<= 1; + } + else if (size > kMinimumSize && fItemCount < size * 50 / 256) + { + // shrink table + while (fItemCount < size * 50 / 256) + size >>= 1; + if (size < kMinimumSize) + size = kMinimumSize; + } + + if (size == fTableSize) + return 0; + + return size * sizeof(ValueType*); + } + + /*! Resizes the table using the given allocation. The allocation must not + be \c NULL. It must be of size \a size, which must a value returned + earlier by ResizeNeeded(). If the size requirements have changed in the + meantime, the method free()s the given allocation and returns \c false, + unless \a force is \c true, in which case the supplied allocation is + used in any event. + Otherwise \c true is returned. + If \a oldTable is non-null and resizing is successful, the old table + will not be freed, but will be returned via this parameter instead. + */ + bool Resize(void* allocation, size_t size, bool force = false, + void** oldTable = NULL) + { + if (!force && size != ResizeNeeded()) + { + fAllocator.Free(allocation); + return false; + } + + _Resize((ValueType**)allocation, size / sizeof(ValueType*), oldTable); + return true; + } + + class Iterator + { + public: + Iterator(const HashTable* table) + : fTable(table) + { + Rewind(); + } + + Iterator(const HashTable* table, size_t index, ValueType* value) + : fTable(table), fIndex(index), fNext(value) {} + + bool HasNext() const { return fNext != NULL; } + + ValueType* Next() + { + ValueType* current = fNext; + _GetNext(); + return current; + } + + void Rewind() + { + // get the first one + fIndex = 0; + fNext = NULL; + _GetNext(); + } + + protected: + Iterator() {} + + void _GetNext() + { + if (fNext) + fNext = fTable->_Link(fNext); + + while (fNext == NULL && fIndex < fTable->fTableSize) + fNext = fTable->fTable[fIndex++]; + } + + const HashTable* fTable; + size_t fIndex; + ValueType* fNext; + }; + + Iterator GetIterator() const + { + return Iterator(this); + } + + Iterator GetIterator(const KeyType& key) const + { + if (fTableSize == 0) + return Iterator(this, fTableSize, NULL); + + size_t index = fDefinition.HashKey(key) & (fTableSize - 1); + ValueType* slot = fTable[index]; + + while (slot) + { + if (fDefinition.Compare(key, slot)) + break; + slot = _Link(slot); + } + + if (slot == NULL) + return Iterator(this, fTableSize, NULL); + + return Iterator(this, index + 1, slot); + } + +protected: + // for g++ 2.95 + friend class Iterator; + + void _Insert(ValueType** table, size_t tableSize, ValueType* value) + { + size_t index = fDefinition.Hash(value) & (tableSize - 1); + + _Link(value) = table[index]; + table[index] = value; + } + + bool _Resize(size_t newSize) + { + ValueType** newTable + = (ValueType**)fAllocator.Allocate(sizeof(ValueType*) * newSize); + if (newTable == NULL) + return false; + + _Resize(newTable, newSize); + return true; + } + + void _Resize(ValueType** newTable, size_t newSize, void** _oldTable = NULL) + { + for (size_t i = 0; i < newSize; i++) + newTable[i] = NULL; + + if (fTable) + { + for (size_t i = 0; i < fTableSize; i++) + { + ValueType* bucket = fTable[i]; + while (bucket) + { + ValueType* next = _Link(bucket); + _Insert(newTable, newSize, bucket); + bucket = next; + } + } + + if (_oldTable != NULL) + *_oldTable = fTable; + else + fAllocator.Free(fTable); + } + else if (_oldTable != NULL) + *_oldTable = NULL; + + fTableSize = newSize; + fTable = newTable; + } + + ValueType*& _Link(ValueType* bucket) const + { + return fDefinition.GetLink(bucket); + } + + bool _ExhaustiveSearch(ValueType* value) const + { + for (size_t i = 0; i < fTableSize; i++) + { + ValueType* bucket = fTable[i]; + while (bucket) { + if (bucket == value) + return true; + bucket = _Link(bucket); + } + } + + return false; + } + + Definition fDefinition; + Allocator fAllocator; + size_t fTableSize; + size_t fItemCount; + ValueType** fTable; +}; + +#endif /* !GA_INCLUDED_SRC_haiku_SharedFolders_OpenHashTable_h */ + diff --git a/src/VBox/Additions/haiku/SharedFolders/kernel_cpp.h b/src/VBox/Additions/haiku/SharedFolders/kernel_cpp.h new file mode 100644 index 00000000..7cc3093f --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/kernel_cpp.h @@ -0,0 +1,122 @@ +/* $Id: kernel_cpp.h $ */ +/** @file + * Kernel C++, Haiku private. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. C++ in the kernel. + * + * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + +#ifndef GA_INCLUDED_SRC_haiku_SharedFolders_kernel_cpp_h +#define GA_INCLUDED_SRC_haiku_SharedFolders_kernel_cpp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef __cplusplus + +#include <new> +#include <stdlib.h> + +#if _KERNEL_MODE || _LOADER_MODE + +using namespace std; +extern const nothrow_t std::nothrow; + +// We need new() versions we can use when also linking against libgcc. +// std::nothrow can't be used since it's defined in both libgcc and +// kernel_cpp.cpp. +typedef struct {} mynothrow_t; +extern const mynothrow_t mynothrow; + + +inline void * +operator new(size_t size) throw (std::bad_alloc) +{ + // we don't actually throw any exceptions, but we have to + // keep the prototype as specified in <new>, or else GCC 3 + // won't like us + return malloc(size); +} + + +inline void * +operator new[](size_t size) throw (std::bad_alloc) +{ + return malloc(size); +} + + +inline void * +operator new(size_t size, const std::nothrow_t &) throw () +{ + return malloc(size); +} + + +inline void * +operator new[](size_t size, const std::nothrow_t &) throw () +{ + return malloc(size); +} + + +inline void * +operator new(size_t size, const mynothrow_t &) throw () +{ + return malloc(size); +} + + +inline void * +operator new[](size_t size, const mynothrow_t &) throw () +{ + return malloc(size); +} + + +inline void +operator delete(void *ptr) throw () +{ + free(ptr); +} + + +inline void +operator delete[](void *ptr) throw () +{ + free(ptr); +} + +#endif // #if _KERNEL_MODE + +#endif // __cplusplus + +#endif /* !GA_INCLUDED_SRC_haiku_SharedFolders_kernel_cpp_h */ diff --git a/src/VBox/Additions/haiku/SharedFolders/lock.h b/src/VBox/Additions/haiku/SharedFolders/lock.h new file mode 100644 index 00000000..4bca6a3f --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/lock.h @@ -0,0 +1,315 @@ +/* $Id: lock.h $ */ +/** @file + * Lock.h - Haiku, private locking internals. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * + * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#ifndef GA_INCLUDED_SRC_haiku_SharedFolders_lock_h +#define GA_INCLUDED_SRC_haiku_SharedFolders_lock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <OS.h> + + +struct mutex_waiter; + +typedef struct mutex { + const char* name; + struct mutex_waiter* waiters; +#if KDEBUG + thread_id holder; +#else + int32 count; + uint16 ignore_unlock_count; +#endif + uint8 flags; +} mutex; + +#define MUTEX_FLAG_CLONE_NAME 0x1 + + +typedef struct recursive_lock { + mutex lock; +#if !KDEBUG + thread_id holder; +#endif + int recursion; +} recursive_lock; + + +struct rw_lock_waiter; + +typedef struct rw_lock { + const char* name; + struct rw_lock_waiter* waiters; + thread_id holder; + vint32 count; + int32 owner_count; + int16 active_readers; + // Only > 0 while a writer is waiting: number + // of active readers when the first waiting + // writer started waiting. + int16 pending_readers; + // Number of readers that have already + // incremented "count", but have not yet started + // to wait at the time the last writer unlocked. + uint32 flags; +} rw_lock; + +#define RW_LOCK_WRITER_COUNT_BASE 0x10000 + +#define RW_LOCK_FLAG_CLONE_NAME 0x1 + + +#if KDEBUG +# define KDEBUG_RW_LOCK_DEBUG 0 + // Define to 1 if you want to use ASSERT_READ_LOCKED_RW_LOCK(). + // The rw_lock will just behave like a recursive locker then. +# define ASSERT_LOCKED_RECURSIVE(r) \ + { ASSERT(find_thread(NULL) == (r)->lock.holder); } +# define ASSERT_LOCKED_MUTEX(m) { ASSERT(find_thread(NULL) == (m)->holder); } +# define ASSERT_WRITE_LOCKED_RW_LOCK(l) \ + { ASSERT(find_thread(NULL) == (l)->holder); } +# if KDEBUG_RW_LOCK_DEBUG +# define ASSERT_READ_LOCKED_RW_LOCK(l) \ + { ASSERT(find_thread(NULL) == (l)->holder); } +# else +# define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false) +# endif +#else +# define ASSERT_LOCKED_RECURSIVE(r) do {} while (false) +# define ASSERT_LOCKED_MUTEX(m) do {} while (false) +# define ASSERT_WRITE_LOCKED_RW_LOCK(m) do {} while (false) +# define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false) +#endif + + +// static initializers +#if KDEBUG +# define MUTEX_INITIALIZER(name) { name, NULL, -1, 0 } +# define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), 0 } +#else +# define MUTEX_INITIALIZER(name) { name, NULL, 0, 0, 0 } +# define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), -1, 0 } +#endif + +#define RW_LOCK_INITIALIZER(name) { name, NULL, -1, 0, 0, 0 } + + +#if KDEBUG +# define RECURSIVE_LOCK_HOLDER(recursiveLock) ((recursiveLock)->lock.holder) +#else +# define RECURSIVE_LOCK_HOLDER(recursiveLock) ((recursiveLock)->holder) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +extern void recursive_lock_init(recursive_lock *lock, const char *name); + // name is *not* cloned nor freed in recursive_lock_destroy() +extern void recursive_lock_init_etc(recursive_lock *lock, const char *name, + uint32 flags); +extern void recursive_lock_destroy(recursive_lock *lock); +extern status_t recursive_lock_lock(recursive_lock *lock); +extern status_t recursive_lock_trylock(recursive_lock *lock); +extern void recursive_lock_unlock(recursive_lock *lock); +extern int32 recursive_lock_get_recursion(recursive_lock *lock); + +extern void rw_lock_init(rw_lock* lock, const char* name); + // name is *not* cloned nor freed in rw_lock_destroy() +extern void rw_lock_init_etc(rw_lock* lock, const char* name, uint32 flags); +extern void rw_lock_destroy(rw_lock* lock); +extern status_t rw_lock_write_lock(rw_lock* lock); + +extern void mutex_init(mutex* lock, const char* name); + // name is *not* cloned nor freed in mutex_destroy() +extern void mutex_init_etc(mutex* lock, const char* name, uint32 flags); +extern void mutex_destroy(mutex* lock); +extern status_t mutex_switch_lock(mutex* from, mutex* to); + // Unlocks "from" and locks "to" such that unlocking and starting to wait + // for the lock is atomically. I.e. if "from" guards the object "to" belongs + // to, the operation is safe as long as "from" is held while destroying + // "to". +extern status_t mutex_switch_from_read_lock(rw_lock* from, mutex* to); + // Like mutex_switch_lock(), just for a switching from a read-locked + // rw_lock. + + +// implementation private: + +extern status_t _rw_lock_read_lock(rw_lock* lock); +extern status_t _rw_lock_read_lock_with_timeout(rw_lock* lock, + uint32 timeoutFlags, bigtime_t timeout); +extern void _rw_lock_read_unlock(rw_lock* lock, bool threadsLocked); +extern void _rw_lock_write_unlock(rw_lock* lock, bool threadsLocked); + +extern status_t _mutex_lock(mutex* lock, bool threadsLocked); +extern void _mutex_unlock(mutex* lock, bool threadsLocked); +extern status_t _mutex_trylock(mutex* lock); +extern status_t _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, + bigtime_t timeout); + + +static inline status_t +rw_lock_read_lock(rw_lock* lock) +{ +#if KDEBUG_RW_LOCK_DEBUG + return rw_lock_write_lock(lock); +#else + int32 oldCount = atomic_add(&lock->count, 1); + if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) + return _rw_lock_read_lock(lock); + return B_OK; +#endif +} + + +static inline status_t +rw_lock_read_lock_with_timeout(rw_lock* lock, uint32 timeoutFlags, + bigtime_t timeout) +{ +#if KDEBUG_RW_LOCK_DEBUG + return mutex_lock_with_timeout(lock, timeoutFlags, timeout); +#else + int32 oldCount = atomic_add(&lock->count, 1); + if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) + return _rw_lock_read_lock_with_timeout(lock, timeoutFlags, timeout); + return B_OK; +#endif +} + + +static inline void +rw_lock_read_unlock(rw_lock* lock) +{ +#if KDEBUG_RW_LOCK_DEBUG + rw_lock_write_unlock(lock); +#else + int32 oldCount = atomic_add(&lock->count, -1); + if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) + _rw_lock_read_unlock(lock, false); +#endif +} + + +static inline void +rw_lock_write_unlock(rw_lock* lock) +{ + _rw_lock_write_unlock(lock, false); +} + + +static inline status_t +mutex_lock(mutex* lock) +{ +#if KDEBUG + return _mutex_lock(lock, false); +#else + if (atomic_add(&lock->count, -1) < 0) + return _mutex_lock(lock, false); + return B_OK; +#endif +} + + +static inline status_t +mutex_lock_threads_locked(mutex* lock) +{ +#if KDEBUG + return _mutex_lock(lock, true); +#else + if (atomic_add(&lock->count, -1) < 0) + return _mutex_lock(lock, true); + return B_OK; +#endif +} + + +static inline status_t +mutex_trylock(mutex* lock) +{ +#if KDEBUG + return _mutex_trylock(lock); +#else + if (atomic_test_and_set(&lock->count, -1, 0) != 0) + return B_WOULD_BLOCK; + return B_OK; +#endif +} + + +static inline status_t +mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout) +{ +#if KDEBUG + return _mutex_lock_with_timeout(lock, timeoutFlags, timeout); +#else + if (atomic_add(&lock->count, -1) < 0) + return _mutex_lock_with_timeout(lock, timeoutFlags, timeout); + return B_OK; +#endif +} + + +static inline void +mutex_unlock(mutex* lock) +{ +#if !KDEBUG + if (atomic_add(&lock->count, 1) < -1) +#endif + _mutex_unlock(lock, false); +} + + +static inline void +mutex_transfer_lock(mutex* lock, thread_id thread) +{ +#if KDEBUG + lock->holder = thread; +#endif +} + + +extern void lock_debug_init(); + +#ifdef __cplusplus +} +#endif + +#endif /* !GA_INCLUDED_SRC_haiku_SharedFolders_lock_h */ diff --git a/src/VBox/Additions/haiku/SharedFolders/vboxsf.c b/src/VBox/Additions/haiku/SharedFolders/vboxsf.c new file mode 100644 index 00000000..26182d42 --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/vboxsf.c @@ -0,0 +1,1055 @@ +/* $Id: vboxsf.c $ */ +/** @file + * Shared folders - Haiku Guest Additions, implementation. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "vboxsf.h" + +#define MODULE_NAME "file_systems/vboxsf" +#define FS_NAME "vboxsf" +#define FS_PRETTY_NAME "VirtualBox Shared Folders" + +VBGLSFCLIENT g_clientHandle; +static fs_volume_ops vboxsf_volume_ops; +static fs_vnode_ops vboxsf_vnode_ops; + +status_t init_module(void) +{ +#if 0 + /** @todo enable this soon */ + int rc = get_module(VBOXGUEST_MODULE_NAME, (module_info **)&g_VBoxGuest); + if (RT_LIKELY(rc == B_OK) + { + rc = VbglR0SfInit(); + if (RT_SUCCESS(rc)) + { + rc = VbglR0SfConnect(&g_clientHandle); + if (RT_SUCCESS(rc)) + { + rc = VbglR0SfSetUtf8(&g_clientHandle); + if (RT_SUCCESS(rc)) + { + rc = VbglR0SfSetSymlinks(&g_clientHandle); + if (RT_FAILURE(rc)) + LogRel((FS_NAME ": Warning! VbglR0SfSetSymlinks failed (rc=%d) - symlink will appear as copies.\n", rc)); + + mutex_init(&g_vnodeCacheLock, "vboxsf vnode cache lock"); + Log((FS_NAME ": init_module succeeded.\n"); + return B_OK; + } + else + LogRel((FS_NAME ": VbglR0SfSetUtf8 failed. rc=%d\n", rc)); + } + else + LogRel((FS_NAME ": VbglR0SfConnect failed. rc=%d\n", rc)); + } + else + LogRel((FS_NAME ": VbglR0SfInit failed. rc=%d\n", rc)); + } + else + LogRel((FS_NAME ": get_module failed for '%s'. rc=%d\n", VBOXGUEST_MODULE_NAME, rc)); + + return B_ERROR; +#endif + + if (get_module(VBOXGUEST_MODULE_NAME, (module_info **)&g_VBoxGuest) != B_OK) + { + dprintf("get_module(%s) failed\n", VBOXGUEST_MODULE_NAME); + return B_ERROR; + } + + if (RT_FAILURE(VbglR0SfInit())) + { + dprintf("VbglR0SfInit failed\n"); + return B_ERROR; + } + + if (RT_FAILURE(VbglR0SfConnect(&g_clientHandle))) + { + dprintf("VbglR0SfConnect failed\n"); + return B_ERROR; + } + + if (RT_FAILURE(VbglR0SfSetUtf8(&g_clientHandle))) + { + dprintf("VbglR0SfSetUtf8 failed\n"); + return B_ERROR; + } + + if (RT_FAILURE(VbglR0SfSetSymlinks(&g_clientHandle))) + { + dprintf("warning: VbglR0SfSetSymlinks failed (old vbox?) - symlinks will appear as copies\n"); + } + + mutex_init(&g_vnodeCacheLock, "vboxsf vnode cache lock"); + + dprintf(FS_NAME ": inited successfully\n"); + return B_OK; +} + +void uninit_module(void) +{ + mutex_destroy(&g_vnodeCacheLock); + put_module(VBOXGUEST_MODULE_NAME); +} + + +PSHFLSTRING make_shflstring(const char* const s) +{ + int len = strlen(s); + if (len > 0xFFFE) + { + dprintf(FS_NAME ": make_shflstring: string too long\n"); + return NULL; + } + + PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + len); + if (!rv) + return NULL; + + rv->u16Length = len; + rv->u16Size = len + 1; + strcpy(rv->String.utf8, s); + return rv; +} + + +PSHFLSTRING clone_shflstring(PSHFLSTRING s) +{ + PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + s->u16Length); + if (rv) + memcpy(rv, s, sizeof(SHFLSTRING) + s->u16Length); + return rv; +} + +PSHFLSTRING concat_shflstring_cstr(PSHFLSTRING s1, const char* const s2) +{ + size_t s2len = strlen(s2); + PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + s1->u16Length + s2len); + if (rv) + { + memcpy(rv, s1, sizeof(SHFLSTRING) + s1->u16Length); + strcat(rv->String.utf8, s2); + rv->u16Length += s2len; + rv->u16Size += s2len; + } + return rv; +} + + +PSHFLSTRING concat_cstr_shflstring(const char* const s1, PSHFLSTRING s2) +{ + size_t s1len = strlen(s1); + PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + s1len + s2->u16Length); + if (rv) + { + strcpy(rv->String.utf8, s1); + strcat(rv->String.utf8, s2->String.utf8); + rv->u16Length = s1len + s2->u16Length; + rv->u16Size = rv->u16Length + 1; + } + return rv; +} + + +PSHFLSTRING build_path(vboxsf_vnode* dir, const char* const name) +{ + dprintf("*** build_path(%p, %p)\n", dir, name); + if (!dir || !name) + return NULL; + + size_t len = dir->path->u16Length + strlen(name) + 1; + PSHFLSTRING rv = malloc(sizeof(SHFLSTRING) + len); + if (rv) + { + strcpy(rv->String.utf8, dir->path->String.utf8); + strcat(rv->String.utf8, "/"); + strcat(rv->String.utf8, name); + rv->u16Length = len; + rv->u16Size = rv->u16Length + 1; + } + return rv; +} + + +status_t mount(fs_volume *volume, const char *device, uint32 flags, const char *args, ino_t *_rootVnodeID) +{ + if (device) + { + dprintf(FS_NAME ": trying to mount a real device as a vbox share is silly\n"); + return B_BAD_TYPE; + } + + dprintf(FS_NAME ": mount(%s)\n", args); + + PSHFLSTRING sharename = make_shflstring(args); + + vboxsf_volume* vbsfvolume = malloc(sizeof(vboxsf_volume)); + volume->private_volume = vbsfvolume; + int rv = VbglR0SfMapFolder(&g_clientHandle, sharename, &(vbsfvolume->map)); + free(sharename); + + if (rv == 0) + { + vboxsf_vnode* root_vnode; + + PSHFLSTRING name = make_shflstring(""); + if (!name) + { + dprintf(FS_NAME ": make_shflstring() failed\n"); + return B_NO_MEMORY; + } + + status_t rs = vboxsf_new_vnode(&vbsfvolume->map, name, name, &root_vnode); + dprintf(FS_NAME ": allocated %p (path=%p name=%p)\n", root_vnode, root_vnode->path, root_vnode->name); + + if (rs != B_OK) + { + dprintf(FS_NAME ": vboxsf_new_vnode() failed (%d)\n", (int)rs); + return rs; + } + + rs = publish_vnode(volume, root_vnode->vnode, root_vnode, &vboxsf_vnode_ops, S_IFDIR, 0); + dprintf(FS_NAME ": publish_vnode(): %d\n", (int)rs); + *_rootVnodeID = root_vnode->vnode; + volume->ops = &vboxsf_volume_ops; + return B_OK; + } + else + { + dprintf(FS_NAME ": VbglR0SfMapFolder failed (%d)\n", rv); + free(volume->private_volume); + return vbox_err_to_haiku_err(rv); + } +} + + +status_t unmount(fs_volume *volume) +{ + dprintf(FS_NAME ": unmount\n"); + VbglR0SfUnmapFolder(&g_clientHandle, volume->private_volume); + return B_OK; +} + + +status_t vboxsf_read_stat(fs_volume* _volume, fs_vnode* _vnode, struct stat* st) +{ + vboxsf_vnode* vnode = _vnode->private_node; + vboxsf_volume* volume = _volume->private_volume; + SHFLCREATEPARMS params; + int rc; + + dprintf("vboxsf_read_stat (_vnode=%p, vnode=%p, path=%p (%s))\n", _vnode, vnode, vnode->path->String.utf8, vnode->path->String.utf8); + + params.Handle = SHFL_HANDLE_NIL; + params.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW; + dprintf("sf_stat: calling VbglR0SfCreate, file %s, flags %x\n", vnode->path->String.utf8, params.CreateFlags); + rc = VbglR0SfCreate(&g_clientHandle, &volume->map, vnode->path, ¶ms); + if (rc == VERR_INVALID_NAME) + { + /* this can happen for names like 'foo*' on a Windows host */ + return B_ENTRY_NOT_FOUND; + } + if (RT_FAILURE(rc)) + { + dprintf("VbglR0SfCreate: %d\n", params.Result); + return vbox_err_to_haiku_err(params.Result); + } + if (params.Result != SHFL_FILE_EXISTS) + { + dprintf("VbglR0SfCreate: %d\n", params.Result); + return B_ENTRY_NOT_FOUND; + } + + st->st_dev = 0; + st->st_ino = vnode->vnode; + st->st_mode = mode_from_fmode(params.Info.Attr.fMode); + st->st_nlink = 1; + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + st->st_size = params.Info.cbObject; + st->st_blksize = 1; + st->st_blocks = params.Info.cbAllocated; + st->st_atime = RTTimeSpecGetSeconds(¶ms.Info.AccessTime); + st->st_mtime = RTTimeSpecGetSeconds(¶ms.Info.ModificationTime); + st->st_ctime = RTTimeSpecGetSeconds(¶ms.Info.BirthTime); + return B_OK; +} + + +status_t vboxsf_open_dir(fs_volume* _volume, fs_vnode* _vnode, void** _cookie) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_vnode* vnode = _vnode->private_node; + SHFLCREATEPARMS params; + + RT_ZERO(params); + params.Handle = SHFL_HANDLE_NIL; + params.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ; + + int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, vnode->path, ¶ms); + if (RT_SUCCESS(rc)) + { + if (params.Result == SHFL_FILE_EXISTS && params.Handle != SHFL_HANDLE_NIL) + { + vboxsf_dir_cookie* cookie = malloc(sizeof(vboxsf_dir_cookie)); + *_cookie = cookie; + cookie->index = 0; + cookie->path = build_path(vnode, "*"); + cookie->handle = params.Handle; + cookie->has_more_files = true; + cookie->buffer_start = cookie->buffer = NULL; + cookie->buffer_length = cookie->num_files = 0; + return B_OK; + } + else + return B_ENTRY_NOT_FOUND; + } + else + { + dprintf(FS_NAME ": VbglR0SfCreate: %d\n", rc); + return vbox_err_to_haiku_err(rc); + } +} + + +/** read a single entry from a dir */ +status_t vboxsf_read_dir_1(vboxsf_volume* volume, vboxsf_vnode* vnode, vboxsf_dir_cookie* cookie, + struct dirent* buffer, size_t bufferSize) +{ + dprintf("%p, %d, %p\n", cookie, cookie->has_more_files, cookie->buffer); + if (!cookie->has_more_files) + return B_ENTRY_NOT_FOUND; + + if (!cookie->buffer) + { + cookie->buffer_length = 16384; + cookie->buffer_start = cookie->buffer = malloc(cookie->buffer_length); + + int rc = VbglR0SfDirInfo(&g_clientHandle, &volume->map, cookie->handle, cookie->path, 0, cookie->index, + &cookie->buffer_length, cookie->buffer, &cookie->num_files); + + if (rc != 0 && rc != VERR_NO_MORE_FILES) + { + dprintf(FS_NAME ": VbglR0SfDirInfo failed: %d\n", rc); + free(cookie->buffer_start); + cookie->buffer_start = NULL; + return vbox_err_to_haiku_err(rc); + } + + if (rc == VERR_NO_MORE_FILES) + { + free(cookie->buffer_start); + cookie->buffer_start = NULL; + cookie->has_more_files = false; + return B_ENTRY_NOT_FOUND; + } + } + + if (bufferSize <= sizeof(struct dirent) + cookie->buffer->name.u16Length) + { + dprintf("hit end of buffer\n"); + return B_BUFFER_OVERFLOW; + } + + PSHFLSTRING name1 = clone_shflstring(&cookie->buffer->name); + if (!name1) + { + dprintf(FS_NAME ": make_shflstring() failed\n"); + return B_NO_MEMORY; + } + + vboxsf_vnode* new_vnode; + int rv = vboxsf_new_vnode(&volume->map, build_path(vnode, name1->String.utf8), name1, &new_vnode); + if (rv != B_OK) + { + dprintf(FS_NAME ": vboxsf_new_vnode() failed\n"); + return rv; + } + + buffer->d_dev = 0; + buffer->d_pdev = 0; + buffer->d_ino = new_vnode->vnode; + buffer->d_pino = vnode->vnode; + buffer->d_reclen = sizeof(struct dirent) + cookie->buffer->name.u16Length; + strncpy(buffer->d_name, cookie->buffer->name.String.utf8, NAME_MAX); + + size_t size = offsetof(SHFLDIRINFO, name.String) + cookie->buffer->name.u16Size; + cookie->buffer = ((void*)cookie->buffer + size); + cookie->index++; + + if (cookie->index >= cookie->num_files) + { + // hit end of this buffer, next call will reallocate a new one + free(cookie->buffer_start); + cookie->buffer_start = cookie->buffer = NULL; + } + return B_OK; +} + + +status_t vboxsf_read_dir(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, + struct dirent* buffer, size_t bufferSize, uint32* _num) +{ + vboxsf_dir_cookie* cookie = _cookie; + vboxsf_volume* volume = _volume->private_volume; + vboxsf_vnode* vnode = _vnode->private_node; + uint32 num_read = 0; + status_t rv = B_OK; + + for (num_read = 0; num_read < *_num && cookie->has_more_files; num_read++) + { + rv = vboxsf_read_dir_1(volume, vnode, cookie, buffer, bufferSize); + if (rv == B_BUFFER_OVERFLOW || rv == B_ENTRY_NOT_FOUND) + { + // hit end of at least one of the buffers - not really an error + rv = B_OK; + break; + } + bufferSize -= buffer->d_reclen; + buffer = ((void*)(buffer)) + buffer->d_reclen; + } + + *_num = num_read; + return rv; +} + + +status_t vboxsf_free_dir_cookie(fs_volume* _volume, fs_vnode* vnode, void* _cookie) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_dir_cookie* cookie = _cookie; + + VbglR0SfClose(&g_clientHandle, &volume->map, cookie->handle); + free(cookie->path); + free(cookie); + + return B_OK; +} + + +status_t vboxsf_read_fs_info(fs_volume* _volume, struct fs_info* info) +{ + vboxsf_volume* volume = _volume->private_volume; + + SHFLVOLINFO volume_info; + uint32_t bytes = sizeof(SHFLVOLINFO); + + int rc = VbglR0SfFsInfo(&g_clientHandle, &volume->map, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME, + &bytes, (PSHFLDIRINFO)&volume_info); + if (RT_FAILURE(rc)) + { + dprintf(FS_NAME ": VbglR0SfFsInfo failed (%d)\n", rc); + return vbox_err_to_haiku_err(rc); + } + + info->flags = B_FS_IS_PERSISTENT; + if (volume_info.fsProperties.fReadOnly) + info->flags |= B_FS_IS_READONLY; + + info->dev = 0; + info->root = 1; + info->block_size = volume_info.ulBytesPerAllocationUnit; + info->io_size = volume_info.ulBytesPerAllocationUnit; + info->total_blocks = volume_info.ullTotalAllocationBytes / info->block_size; + info->free_blocks = volume_info.ullAvailableAllocationBytes / info->block_size; + info->total_nodes = LONGLONG_MAX; + info->free_nodes = LONGLONG_MAX; + strcpy(info->volume_name, "VBox share"); + return B_OK; +} + + +status_t vboxsf_lookup(fs_volume* _volume, fs_vnode* dir, const char* name, ino_t* _id) +{ + dprintf(FS_NAME ": lookup %s\n", name); + vboxsf_volume* volume = _volume->private_volume; + SHFLCREATEPARMS params; + + RT_ZERO(params); + params.Handle = SHFL_HANDLE_NIL; + params.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW; + + PSHFLSTRING path = build_path(dir->private_node, name); + if (!path) + { + dprintf(FS_NAME ": make_shflstring() failed\n"); + return B_NO_MEMORY; + } + + int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, path, ¶ms); + if (RT_SUCCESS(rc)) + { + if (params.Result == SHFL_FILE_EXISTS) + { + vboxsf_vnode* vn; + status_t rv = vboxsf_new_vnode(&volume->map, path, path, &vn); + if (rv == B_OK) + { + *_id = vn->vnode; + rv = publish_vnode(_volume, vn->vnode, vn, &vboxsf_vnode_ops, mode_from_fmode(params.Info.Attr.fMode), 0); + } + return rv; + } + else + { + free(path); + return B_ENTRY_NOT_FOUND; + } + } + else + { + free(path); + dprintf(FS_NAME ": VbglR0SfCreate: %d\n", rc); + return vbox_err_to_haiku_err(rc); + } +} + + +mode_t mode_from_fmode(RTFMODE fMode) +{ + mode_t m = 0; + + if (RTFS_IS_DIRECTORY(fMode)) + m |= S_IFDIR; + else if (RTFS_IS_FILE(fMode)) + m |= S_IFREG; + else if (RTFS_IS_FIFO(fMode)) + m |= S_IFIFO; + else if (RTFS_IS_DEV_CHAR(fMode)) + m |= S_IFCHR; + else if (RTFS_IS_DEV_BLOCK(fMode)) + m |= S_IFBLK; + else if (RTFS_IS_SYMLINK(fMode)) + m |= S_IFLNK; + else if (RTFS_IS_SOCKET(fMode)) + m |= S_IFSOCK; + + if (fMode & RTFS_UNIX_IRUSR) + m |= S_IRUSR; + if (fMode & RTFS_UNIX_IWUSR) + m |= S_IWUSR; + if (fMode & RTFS_UNIX_IXUSR) + m |= S_IXUSR; + if (fMode & RTFS_UNIX_IRGRP) + m |= S_IRGRP; + if (fMode & RTFS_UNIX_IWGRP) + m |= S_IWGRP; + if (fMode & RTFS_UNIX_IXGRP) + m |= S_IXGRP; + if (fMode & RTFS_UNIX_IROTH) + m |= S_IROTH; + if (fMode & RTFS_UNIX_IWOTH) + m |= S_IWOTH; + if (fMode & RTFS_UNIX_IXOTH) + m |= S_IXOTH; + if (fMode & RTFS_UNIX_ISUID) + m |= S_ISUID; + if (fMode & RTFS_UNIX_ISGID) + m |= S_ISGID; + if (fMode & RTFS_UNIX_ISTXT) + m |= S_ISVTX; + + return m; +} + + +status_t vboxsf_open(fs_volume* _volume, fs_vnode* _vnode, int openMode, void** _cookie) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_vnode* vnode = _vnode->private_node; + + dprintf(FS_NAME ": open %s (mode=%x)\n", vnode->path->String.utf8, openMode); + + SHFLCREATEPARMS params; + + RT_ZERO(params); + params.Handle = SHFL_HANDLE_NIL; + + if (openMode & O_RDWR) + params.CreateFlags |= SHFL_CF_ACCESS_READWRITE; + else if (openMode & O_RDONLY) + params.CreateFlags |= SHFL_CF_ACCESS_READ; + else if (openMode & O_WRONLY) + params.CreateFlags |= SHFL_CF_ACCESS_WRITE; + + if (openMode & O_APPEND) + params.CreateFlags |= SHFL_CF_ACCESS_APPEND; + + if (openMode & O_CREAT) + { + params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW; + if (openMode & O_EXCL) + params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS; + else if (openMode & O_TRUNC) + params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; + else + params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS; + } + else + { + params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW; + if (openMode & O_TRUNC) + params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; + else + params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS; + } + + int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, vnode->path, ¶ms); + if (!RT_SUCCESS(rc)) + { + dprintf("VbglR0SfCreate returned %d\n", rc); + return vbox_err_to_haiku_err(rc); + } + + vboxsf_file_cookie* cookie = malloc(sizeof(vboxsf_file_cookie)); + if (!cookie) + { + dprintf("couldn't allocate file cookie\n"); + return B_NO_MEMORY; + } + + cookie->handle = params.Handle; + cookie->path = vnode->path; + + *_cookie = cookie; + + return B_OK; +} + + +status_t vboxsf_create(fs_volume* _volume, fs_vnode* _dir, const char *name, int openMode, int perms, void **_cookie, ino_t *_newVnodeID) +{ + vboxsf_volume* volume = _volume->private_volume; + + SHFLCREATEPARMS params; + + RT_ZERO(params); + params.Handle = SHFL_HANDLE_NIL; + + if (openMode & O_RDWR) + params.CreateFlags |= SHFL_CF_ACCESS_READWRITE; + else if (openMode & O_RDONLY) + params.CreateFlags |= SHFL_CF_ACCESS_READ; + else if (openMode & O_WRONLY) + params.CreateFlags |= SHFL_CF_ACCESS_WRITE; + + if (openMode & O_APPEND) + params.CreateFlags |= SHFL_CF_ACCESS_APPEND; + + if (openMode & O_CREAT) + { + params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW; + if (openMode & O_EXCL) + params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS; + else if (openMode & O_TRUNC) + params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; + else + params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS; + } + else + { + params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW; + if (openMode & O_TRUNC) + params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; + else + params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS; + } + + PSHFLSTRING path = build_path(_dir->private_node, name); + int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, path, ¶ms); + + if (!RT_SUCCESS(rc)) + { + dprintf("VbglR0SfCreate returned %d\n", rc); + free(path); + return vbox_err_to_haiku_err(rc); + } + + vboxsf_file_cookie* cookie = malloc(sizeof(vboxsf_file_cookie)); + if (!cookie) + { + dprintf("couldn't allocate file cookie\n"); + free(path); + return B_NO_MEMORY; + } + + cookie->handle = params.Handle; + cookie->path = path; + + *_cookie = cookie; + return vboxsf_lookup(_volume, _dir, name, _newVnodeID); +} + + +status_t vboxsf_close(fs_volume* _volume, fs_vnode* _vnode, void* _cookie) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_file_cookie* cookie = _cookie; + + int rc = VbglR0SfClose(&g_clientHandle, &volume->map, cookie->handle); + dprintf("VbglR0SfClose returned %d\n", rc); + return vbox_err_to_haiku_err(rc); +} + + +status_t vboxsf_rewind_dir(fs_volume* _volume, fs_vnode* _vnode, void* _cookie) +{ + vboxsf_dir_cookie* cookie = _cookie; + cookie->index = 0; + return B_OK; +} + + +status_t vboxsf_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + return B_OK; +} + + +status_t vboxsf_free_cookie(fs_volume *volume, fs_vnode *vnode, void *_cookie) +{ + vboxsf_dir_cookie* cookie = _cookie; + free(cookie); + return B_OK; +} + +status_t vboxsf_read(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, void *buffer, size_t *length) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_vnode* vnode = _vnode->private_node; + vboxsf_file_cookie* cookie = _cookie; + + if (*length > 0xFFFFFFFF) + *length = 0xFFFFFFFF; + + uint32_t l = *length; + void* other_buffer = malloc(l); /** @todo map the user memory into kernel space here for efficiency */ + int rc = VbglR0SfRead(&g_clientHandle, &volume->map, cookie->handle, pos, &l, other_buffer, false /*fLocked*/); + memcpy(buffer, other_buffer, l); + free(other_buffer); + + dprintf("VbglR0SfRead returned %d\n", rc); + *length = l; + return vbox_err_to_haiku_err(rc); +} + + +status_t vboxsf_write(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, const void *buffer, size_t *length) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_vnode* vnode = _vnode->private_node; + vboxsf_file_cookie* cookie = _cookie; + + if (*length > 0xFFFFFFFF) + *length = 0xFFFFFFFF; + + uint32_t l = *length; + void* other_buffer = malloc(l); /** @todo map the user memory into kernel space here for efficiency */ + memcpy(other_buffer, buffer, l); + int rc = VbglR0SfWrite(&g_clientHandle, &volume->map, cookie->handle, pos, &l, other_buffer, false /*fLocked*/); + free(other_buffer); + + *length = l; + return vbox_err_to_haiku_err(rc); +} + + +status_t vboxsf_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat, uint32 statMask) +{ + /* The host handles updating the stat info - in the guest, this is a no-op */ + return B_OK; +} + + +status_t vboxsf_create_dir(fs_volume *_volume, fs_vnode *parent, const char *name, int perms) +{ + vboxsf_volume* volume = _volume->private_volume; + + SHFLCREATEPARMS params; + params.Handle = 0; + params.Info.cbObject = 0; + params.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_CREATE_IF_NEW | + SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACCESS_READ; + + PSHFLSTRING path = build_path(parent->private_node, name); + int rc = VbglR0SfCreate(&g_clientHandle, &volume->map, path, ¶ms); + free(path); + /** @todo r=ramshankar: we should perhaps also check rc here and change + * Handle initialization from 0 to SHFL_HANDLE_NIL. */ + if (params.Handle == SHFL_HANDLE_NIL) + return vbox_err_to_haiku_err(rc); + VbglR0SfClose(&g_clientHandle, &volume->map, params.Handle); + return B_OK; +} + + +status_t vboxsf_remove_dir(fs_volume *_volume, fs_vnode *parent, const char *name) +{ + vboxsf_volume* volume = _volume->private_volume; + + PSHFLSTRING path = build_path(parent->private_node, name); + int rc = VbglR0SfRemove(&g_clientHandle, &volume->map, path, SHFL_REMOVE_DIR); + free(path); + + return vbox_err_to_haiku_err(rc); +} + + +status_t vboxsf_unlink(fs_volume *_volume, fs_vnode *parent, const char *name) +{ + vboxsf_volume* volume = _volume->private_volume; + + PSHFLSTRING path = build_path(parent->private_node, name); + int rc = VbglR0SfRemove(&g_clientHandle, &volume->map, path, SHFL_REMOVE_FILE); + free(path); + + return vbox_err_to_haiku_err(rc); +} + +status_t vboxsf_link(fs_volume *volume, fs_vnode *dir, const char *name, fs_vnode *vnode) +{ + return B_UNSUPPORTED; +} + + +status_t vboxsf_rename(fs_volume* _volume, fs_vnode* fromDir, const char* fromName, fs_vnode* toDir, const char* toName) +{ + vboxsf_volume* volume = _volume->private_volume; + + PSHFLSTRING oldpath = build_path(fromDir->private_node, fromName); + PSHFLSTRING newpath = build_path(toDir->private_node, toName); + int rc = VbglR0SfRename(&g_clientHandle, &volume->map, oldpath, newpath, SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS); + free(oldpath); + free(newpath); + + return vbox_err_to_haiku_err(rc); +} + + +status_t vboxsf_create_symlink(fs_volume* _volume, fs_vnode* dir, const char* name, const char* path, int mode) +{ + vboxsf_volume* volume = _volume->private_volume; + + PSHFLSTRING target = make_shflstring(path); + PSHFLSTRING linkpath = build_path(dir->private_node, name); + SHFLFSOBJINFO stuff; + RT_ZERO(stuff); + + int rc = VbglR0SfSymlink(&g_clientHandle, &volume->map, linkpath, target, &stuff); + + free(target); + free(linkpath); + + return vbox_err_to_haiku_err(rc); +} + + +status_t vboxsf_read_symlink(fs_volume* _volume, fs_vnode* link, char* buffer, size_t* _bufferSize) +{ + vboxsf_volume* volume = _volume->private_volume; + vboxsf_vnode* vnode = link->private_node; + + int rc = VbglR0SfReadLink(&g_clientHandle, &volume->map, vnode->path, *_bufferSize, buffer); + *_bufferSize = strlen(buffer); + + return vbox_err_to_haiku_err(rc); +} + + +/** @todo move this into the runtime */ +status_t vbox_err_to_haiku_err(int rc) +{ + switch (rc) + { + case VINF_SUCCESS: return B_OK; + case VERR_INVALID_POINTER: return B_BAD_ADDRESS; + case VERR_INVALID_PARAMETER: return B_BAD_VALUE; + case VERR_PERMISSION_DENIED: return B_PERMISSION_DENIED; + case VERR_NOT_IMPLEMENTED: return B_UNSUPPORTED; + case VERR_FILE_NOT_FOUND: return B_ENTRY_NOT_FOUND; + + case SHFL_PATH_NOT_FOUND: + case SHFL_FILE_NOT_FOUND: return B_ENTRY_NOT_FOUND; + case SHFL_FILE_EXISTS: return B_FILE_EXISTS; + + default: + return B_ERROR; + } +} + + +static status_t std_ops(int32 op, ...) +{ + switch(op) + { + case B_MODULE_INIT: + dprintf(MODULE_NAME ": B_MODULE_INIT\n"); + return init_module(); + case B_MODULE_UNINIT: + dprintf(MODULE_NAME ": B_MODULE_UNINIT\n"); + uninit_module(); + return B_OK; + default: + return B_ERROR; + } +} + + +static fs_volume_ops vboxsf_volume_ops = +{ + unmount, + vboxsf_read_fs_info, + NULL, /* write_fs_info */ + NULL, /* sync */ + vboxsf_get_vnode, + NULL, /* open_index_dir */ + NULL, /* close_index_dir */ + NULL, /* free_index_dir_cookie */ + NULL, /* read_index_dir */ + NULL, /* rewind_index_dir */ + NULL, /* create_index */ + NULL, /* remove_index */ + NULL, /* read_index_stat */ + NULL, /* open_query */ + NULL, /* close_query */ + NULL, /* free_query_cookie */ + NULL, /* read_query */ + NULL, /* rewind_query */ + NULL, /* all_layers_mounted */ + NULL, /* create_sub_vnode */ + NULL, /* delete_sub_vnode */ +}; + +static fs_vnode_ops vboxsf_vnode_ops = +{ + vboxsf_lookup, + NULL, /* get_vnode_name */ + vboxsf_put_vnode, + NULL, /* remove_vnode */ + NULL, /* can_page */ + NULL, /* read_pages */ + NULL, /* write_pages */ + NULL, /* io */ + NULL, /* cancel_io */ + NULL, /* get_file_map */ + NULL, /* ioctl */ + NULL, /* set_flags */ + NULL, /* select */ + NULL, /* deselect */ + NULL, /* fsync */ + vboxsf_read_symlink, + vboxsf_create_symlink, + vboxsf_link, + vboxsf_unlink, + vboxsf_rename, + NULL, /* access */ + vboxsf_read_stat, + vboxsf_write_stat, + NULL, /* preallocate */ + vboxsf_create, + vboxsf_open, + vboxsf_close, + vboxsf_free_cookie, + vboxsf_read, + vboxsf_write, + vboxsf_create_dir, + vboxsf_remove_dir, + vboxsf_open_dir, + vboxsf_close_dir, + vboxsf_free_dir_cookie, + vboxsf_read_dir, + vboxsf_rewind_dir, + NULL, /* open_attr_dir */ + NULL, /* close_attr_dir */ + NULL, /* free_attr_dir_cookie */ + NULL, /* read_attr_dir */ + NULL, /* rewind_attr_dir */ + NULL, /* create_attr */ + NULL, /* open_attr */ + NULL, /* close_attr */ + NULL, /* free_attr_cookie */ + NULL, /* read_attr */ + NULL, /* write_attr */ + NULL, /* read_attr_stat */ + NULL, /* write_attr_stat */ + NULL, /* rename_attr */ + NULL, /* remove_attr */ + NULL, /* create_special_node */ + NULL, /* get_super_vnode */ +}; + +static file_system_module_info sVBoxSharedFileSystem = +{ + { + MODULE_NAME B_CURRENT_FS_API_VERSION, + 0, + std_ops, + }, + FS_NAME, + FS_PRETTY_NAME, + 0, /* DDM flags */ + NULL, /* identify_partition */ + NULL, /* scan_partition */ + NULL, /* free_identify_partition_cookie */ + NULL, /* free_partition_content_cookie */ + mount, +}; + +module_info *modules[] = +{ + (module_info *)&sVBoxSharedFileSystem, + NULL, +}; + diff --git a/src/VBox/Additions/haiku/SharedFolders/vboxsf.h b/src/VBox/Additions/haiku/SharedFolders/vboxsf.h new file mode 100644 index 00000000..d8449987 --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/vboxsf.h @@ -0,0 +1,120 @@ +/* $Id: vboxsf.h $ */ +/** @file + * Shared folders - Haiku Guest Additions, header. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GA_INCLUDED_SRC_haiku_SharedFolders_vboxsf_h +#define GA_INCLUDED_SRC_haiku_SharedFolders_vboxsf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <malloc.h> +#include <dirent.h> +#include <fs_info.h> +#include <sys/stat.h> +#include <fs_interface.h> +#include <KernelExport.h> +#include <VBoxGuest-haiku.h> +#include <VBox/VBoxGuestLibSharedFolders.h> +#include "lock.h" + +typedef struct vboxsf_volume +{ + VBGLSFMAP map; + ino_t rootid; +} vboxsf_volume; + +typedef struct vboxsf_vnode +{ + PVBGLSFMAP map; + PSHFLSTRING name; + PSHFLSTRING path; + ino_t vnode; + struct vboxsf_vnode* next; +} vboxsf_vnode; + +typedef struct vboxsf_dir_cookie +{ + SHFLHANDLE handle; + PSHFLSTRING path; + uint32_t index; + bool has_more_files; + PSHFLDIRINFO buffer_start, buffer; + uint32_t buffer_length, num_files; +} vboxsf_dir_cookie; + +typedef struct vboxsf_file_cookie +{ + SHFLHANDLE handle; + PSHFLSTRING path; +} vboxsf_file_cookie; + +#ifdef __cplusplus +extern "C" { +#endif + +status_t vboxsf_new_vnode(PVBGLSFMAP map, PSHFLSTRING path, PSHFLSTRING name, vboxsf_vnode** p); +status_t vboxsf_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type, uint32* _flags, bool reenter); +status_t vboxsf_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter); +PSHFLSTRING make_shflstring(const char* const s); +mode_t mode_from_fmode(RTFMODE fMode); +status_t vbox_err_to_haiku_err(int rc); +extern mutex g_vnodeCacheLock; + +#ifdef __cplusplus +} +#endif + +#endif /* !GA_INCLUDED_SRC_haiku_SharedFolders_vboxsf_h */ + diff --git a/src/VBox/Additions/haiku/SharedFolders/vnode_cache.cpp b/src/VBox/Additions/haiku/SharedFolders/vnode_cache.cpp new file mode 100644 index 00000000..05221606 --- /dev/null +++ b/src/VBox/Additions/haiku/SharedFolders/vnode_cache.cpp @@ -0,0 +1,144 @@ +/* $Id: vnode_cache.cpp $ */ +/** @file + * Shared folders - Haiku Guest Additions, vnode cache header. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "vboxsf.h" +#include "OpenHashTable.h" + +struct HashTableDefinition +{ + typedef uint32 KeyType; + typedef vboxsf_vnode ValueType; + + size_t HashKey(uint32 key) const + { + return key; + } + + size_t Hash(vboxsf_vnode* value) const + { + return HashKey(value->vnode); + } + + bool Compare(uint32 key, vboxsf_vnode* value) const + { + return value->vnode == key; + } + + vboxsf_vnode*& GetLink(vboxsf_vnode* value) const + { + return value->next; + } +}; + +static BOpenHashTable<HashTableDefinition> g_cache; +static ino_t g_nextVnid = 1; +mutex g_vnodeCacheLock; + + +extern "C" status_t vboxsf_new_vnode(PVBSFMAP map, PSHFLSTRING path, PSHFLSTRING name, vboxsf_vnode** p) +{ + vboxsf_vnode* vn = (vboxsf_vnode*)malloc(sizeof(vboxsf_vnode)); + if (vn == NULL) + return B_NO_MEMORY; + + dprintf("creating new vnode at %p with path=%p (%s)\n", vn, path->String.utf8, path->String.utf8); + vn->map = map; + vn->path = path; + if (name) + vn->name = name; + else + { + const char* cname = strrchr((char*)path->String.utf8, '/'); + if (!cname) + vn->name = path; // no slash, assume this *is* the filename + else + vn->name = make_shflstring(cname); + } + + if (mutex_lock(&g_vnodeCacheLock) < B_OK) + { + free(vn); + return B_ERROR; + } + + vn->vnode = g_nextVnid++; + *p = vn; + dprintf("vboxsf: allocated %p (path=%p name=%p)\n", vn, vn->path, vn->name); + status_t rv = g_cache.Insert(vn); + + mutex_unlock(&g_vnodeCacheLock); + + return rv; +} + + +extern "C" status_t vboxsf_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, + int* _type, uint32* _flags, bool reenter) +{ + vboxsf_vnode* vn = g_cache.Lookup(id); + if (vn) + { + vnode->private_node = vn; + return B_OK; + } + return B_ERROR; +} + + +extern "C" status_t vboxsf_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) +{ + g_cache.Remove((vboxsf_vnode*)vnode->private_node); +} + diff --git a/src/VBox/Additions/haiku/VBoxMouse/Makefile.kmk b/src/VBox/Additions/haiku/VBoxMouse/Makefile.kmk new file mode 100644 index 00000000..f8089e11 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxMouse/Makefile.kmk @@ -0,0 +1,90 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for VBoxMouse, Haiku Additions. +# + +# +# Copyright (C) 2012-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +# +# This code is based on: +# +# VirtualBox Guest Additions for Haiku. +# Copyright (c) 2011 Mike Smith <mike@scgtrp.net> +# François Revol <revol@free.fr> +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +# @todo split the mouse code to communicate with VBoxMouse/VBoxService +# to allow building with gcc2. +# R1 will need gcc2-built input_server add-ons. + +PROGRAMS += VBoxMouse +VBoxMouse_TEMPLATE = VBoxGuestR3Exe +VBoxMouse_DEFS = VBOX_WITH_HGCM LOG_TO_BACKDOOR +VBoxMouse_DEFS += LOG_ENABLED +VBoxMouse_INCS = ../include +VBoxMouse_SOURCES = \ + VBoxMouse.cpp + +VBoxMouse_LIBS = \ + be \ + device \ + $(VBOX_LIB_IPRT_GUEST_R3) \ + $(VBOX_LIB_VBGL_R3) \ + /system/servers/input_server + +PROGRAMS += VBoxMouseFilter +VBoxMouseFilter_TEMPLATE = VBoxGuestR3Exe +VBoxMouseFilter_DEFS = VBOX_WITH_HGCM LOG_TO_BACKDOOR +VBoxMouseFilter_DEFS += LOG_ENABLED +VBoxMouseFilter_INCS = ../include +VBoxMouseFilter_SOURCES = \ + VBoxMouseFilter.cpp + +VBoxMouseFilter_LIBS = $(VBoxMouse_LIBS) + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.cpp b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.cpp new file mode 100644 index 00000000..50261a45 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.cpp @@ -0,0 +1,318 @@ +/* $Id: VBoxMouse.cpp $ */ +/** @file + * VBoxMouse; input_server add-on - Haiku Guest Additions, implementation. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <Clipboard.h> +#include <Debug.h> +#include <Message.h> +#include <String.h> + +#include "VBoxMouse.h" +#include <VBox/VBoxGuest.h> /** @todo use the VbglR3 interface! */ +#include <VBox/VBoxGuestLib.h> +#include <VBoxGuestInternal.h> +#include <VBox/VMMDev.h> +#include <VBox/log.h> +#include <iprt/errcore.h> + +/* Export as global symbol with C linkage, RTDECL is necessary. */ +RTDECL(BInputServerDevice *) +instantiate_input_device() +{ + return new VBoxMouse(); +} + + +static inline int vboxMouseAcquire() +{ + uint32_t fFeatures = 0; + int rc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL); + if (RT_SUCCESS(rc)) + { + rc = VbglR3SetMouseStatus(fFeatures | VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_NEW_PROTOCOL); + if (RT_FAILURE(rc)) + LogRel(("VbglR3SetMouseStatus failed. rc=%d\n", rc)); + } + else + LogRel(("VbglR3GetMouseStatus failed. rc=%d\n", rc)); + return rc; +} + + +static inline int vboxMouseRelease() +{ + uint32_t fFeatures = 0; + int rc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL); + if (RT_SUCCESS(rc)) + { + rc = VbglR3SetMouseStatus(fFeatures & ~VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE & ~VMMDEV_MOUSE_NEW_PROTOCOL); + if (RT_FAILURE(rc)) + LogRel(("VbglR3SetMouseStatus failed. rc=%d\n", rc)); + } + else + LogRel(("VbglR3GetMouseStatus failed. rc=%d\n", rc)); + return rc; +} + + +VBoxMouse::VBoxMouse() + : BInputServerDevice(), + fDriverFD(-1), + fServiceThreadID(-1), + fExiting(false) +{ +} + + +VBoxMouse::~VBoxMouse() +{ +} + + +status_t VBoxMouse::InitCheck() +{ + int rc = VbglR3Init(); + if (!RT_SUCCESS(rc)) + return ENXIO; + + input_device_ref device = { (char *)"VBoxMouse", B_POINTING_DEVICE, (void *)this }; + input_device_ref *deviceList[2] = { &device, NULL }; + RegisterDevices(deviceList); + + return B_OK; +} + + +status_t VBoxMouse::SystemShuttingDown() +{ + VbglR3Term(); + + return B_OK; +} + + +status_t VBoxMouse::Start(const char *device, void *cookie) +{ +#if 0 + status_t err; + int rc; + uint32_t fFeatures = 0; + Log(("VBoxMouse::%s()\n", __FUNCTION__)); + + rc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL); + if (RT_SUCCESS(rc)) + rc = VbglR3SetMouseStatus(fFeatures + | VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE + | VMMDEV_MOUSE_NEW_PROTOCOL); + if (!RT_SUCCESS(rc)) + { + LogRel(("VBoxMouse: Error switching guest mouse into absolute mode: %d\n", rc)); + return B_DEVICE_NOT_FOUND; + } + + err = fServiceThreadID = spawn_thread(_ServiceThreadNub, + "VBoxMouse", B_NORMAL_PRIORITY, this); + if (err >= B_OK) + { + resume_thread(fServiceThreadID); + return B_OK; + } + else + LogRel(("VBoxMouse: Error starting service thread: 0x%08lx\n", + err)); + + // release the mouse + rc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL); + if (RT_SUCCESS(rc)) + rc = VbglR3SetMouseStatus(fFeatures + & ~VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE + & ~VMMDEV_MOUSE_NEW_PROTOCOL); + + return B_ERROR; +#endif + + status_t err = B_OK; + int rc; + uint32_t fFeatures = 0; + LogFlowFunc(("device=%s cookie=%p\n", device, cookie)); + + rc = vboxMouseAcquire(); + if (RT_SUCCESS(rc)) + { + err = fServiceThreadID = spawn_thread(_ServiceThreadNub, "VBoxMouse", B_NORMAL_PRIORITY, this); + if (err >= B_OK) + { + resume_thread(fServiceThreadID); + return B_OK; + } + else + LogRel(("VBoxMouse::Start Error starting service thread: 0x%08lx\n", err)); + + vboxMouseRelease(); + err = B_ERROR; + } + else + { + LogRel(("VBoxMouse::Start vboxMouseAcquire failed. rc=%d\n", rc)); + err = B_DEVICE_NOT_FOUND; + } + + return err; +} + + +status_t VBoxMouse::Stop(const char *device, void *cookie) +{ + status_t status; + int rc; + uint32_t fFeatures = 0; + Log(("VBoxMouse::%s()\n", __FUNCTION__)); + + fExiting = true; + + vboxMouseRelease(); + + close(fDriverFD); + fDriverFD = -1; + //XXX WTF ? + suspend_thread(fServiceThreadID); + resume_thread(fServiceThreadID); + wait_for_thread(fServiceThreadID, &status); + fServiceThreadID = -1; + fExiting = false; + return B_OK; +} + + +status_t VBoxMouse::Control(const char *device, void *cookie, uint32 code, BMessage *message) +{ + switch (code) + { + case B_MOUSE_SPEED_CHANGED: + case B_CLICK_SPEED_CHANGED: + case B_MOUSE_ACCELERATION_CHANGED: + default: + return BInputServerDevice::Control(device, cookie, code, message); + } + return B_OK; +} + + +status_t VBoxMouse::_ServiceThreadNub(void *_this) +{ + VBoxMouse *service = (VBoxMouse *)_this; + return service->_ServiceThread(); +} + + +status_t VBoxMouse::_ServiceThread() +{ + Log(("VBoxMouse::%s()\n", __FUNCTION__)); + + fDriverFD = open(VBOXGUEST_DEVICE_NAME, O_RDWR); + if (fDriverFD < 0) + return ENXIO; + + /* The thread waits for incoming messages from the host. */ + while (!fExiting) + { + uint32_t cx, cy, fFeatures; + int rc; + + fd_set readSet, writeSet, errorSet; + FD_ZERO(&readSet); + FD_ZERO(&writeSet); + FD_ZERO(&errorSet); + FD_SET(fDriverFD, &readSet); + if (fDriverFD < 0) + break; + rc = select(fDriverFD + 1, &readSet, &writeSet, &errorSet, NULL); + if (rc < 0) + { + if (errno == EINTR || errno == EAGAIN) + continue; + break; + } + + rc = VbglR3GetMouseStatus(&fFeatures, &cx, &cy); + if ( RT_SUCCESS(rc) + && (fFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE)) + { + float x = cx * 1.0 / 65535; + float y = cy * 1.0 / 65535; + + _debugPrintf("VBoxMouse: at %d,%d %f,%f\n", cx, cy, x, y); + + /* Send absolute movement */ + bigtime_t now = system_time(); + BMessage *event = new BMessage(B_MOUSE_MOVED); + event->AddInt64("when", now); + event->AddFloat("x", x); + event->AddFloat("y", y); + event->AddFloat("be:tablet_x", x); + event->AddFloat("be:tablet_y", y); + //event->PrintToStream(); + EnqueueMessage(event); + + //LogRelFlow(("processed host event rc = %d\n", rc)); + } + } + return 0; +} + diff --git a/src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.h b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.h new file mode 100644 index 00000000..69a62b8a --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouse.h @@ -0,0 +1,91 @@ +/* $Id: VBoxMouse.h $ */ +/** @file + * VBoxMouse; input_server add-on - Haiku Guest Additions, header. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GA_INCLUDED_SRC_haiku_VBoxMouse_VBoxMouse_h +#define GA_INCLUDED_SRC_haiku_VBoxMouse_VBoxMouse_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <InputServerDevice.h> + +extern "C" _EXPORT BInputServerDevice* instantiate_input_device(); + +class VBoxMouse : public BInputServerDevice +{ + public: + VBoxMouse(); + virtual ~VBoxMouse(); + + virtual status_t InitCheck(); + virtual status_t SystemShuttingDown(); + + virtual status_t Start(const char *device, void *cookie); + virtual status_t Stop(const char *device, void *cookie); + virtual status_t Control(const char *device, void *cookie, uint32 code, BMessage *message); + + private: + + static status_t _ServiceThreadNub(void *_this); + status_t _ServiceThread(); + + int fDriverFD; + thread_id fServiceThreadID; + bool fExiting; +}; + +#endif /* !GA_INCLUDED_SRC_haiku_VBoxMouse_VBoxMouse_h */ + diff --git a/src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.cpp b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.cpp new file mode 100644 index 00000000..5f0158ba --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.cpp @@ -0,0 +1,117 @@ +/* $Id: VBoxMouseFilter.cpp $ */ +/** @file + * VBoxMouse; input_server filter - Haiku Guest Additions, implementation. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <Clipboard.h> +#include <Debug.h> +#include <Message.h> +#include <String.h> + +#include "VBoxMouseFilter.h" +#include <VBox/VBoxGuestLib.h> +#include <VBoxGuestInternal.h> +#include <VBox/log.h> +#include <iprt/errcore.h> + +/** @todo can this be merged with VBoxMouse? */ + +RTDECL(BInputServerFilter *) +instantiate_input_filter() +{ + return new VBoxMouseFilter(); +} + +VBoxMouseFilter::VBoxMouseFilter() + : BInputServerFilter(), + fDriverFD(-1), + fServiceThreadID(-1), + fExiting(false), + fCurrentButtons(0) +{ +} + + +VBoxMouseFilter::~VBoxMouseFilter() +{ +} + + +filter_result VBoxMouseFilter::Filter(BMessage *message, BList *outList) +{ + switch (message->what) + { + case B_MOUSE_UP: + case B_MOUSE_DOWN: + { + printf("click|release\n"); + message->FindInt32("buttons", &fCurrentButtons); + /** @todo r=ramshankar this looks wrong, no 'break' here? */ + } + + case B_MOUSE_MOVED: + { + printf("mouse moved\n"); + message->ReplaceInt32("buttons", fCurrentButtons); + /** @todo r=ramshankar: 'break' or explicit comment please. */ + } + } + + return B_DISPATCH_MESSAGE; +} + diff --git a/src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.h b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.h new file mode 100644 index 00000000..64996a2f --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxMouse/VBoxMouseFilter.h @@ -0,0 +1,87 @@ +/* $Id: VBoxMouseFilter.h $ */ +/** @file + * VBoxMouse; input_server filter - Haiku Guest Additions, header. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GA_INCLUDED_SRC_haiku_VBoxMouse_VBoxMouseFilter_h +#define GA_INCLUDED_SRC_haiku_VBoxMouse_VBoxMouseFilter_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <InputServerFilter.h> + +extern "C" _EXPORT BInputServerFilter* instantiate_input_filter(); + +class VBoxMouseFilter : public BInputServerFilter +{ + public: + VBoxMouseFilter(); + virtual ~VBoxMouseFilter(); + + virtual filter_result Filter(BMessage* message, BList* outList); + + private: + static status_t _ServiceThreadNub(void *_this); + status_t _ServiceThread(); + + int fDriverFD; + thread_id fServiceThreadID; + bool fExiting; + bool fEnabled; + int32 fCurrentButtons; +}; + +#endif /* !GA_INCLUDED_SRC_haiku_VBoxMouse_VBoxMouseFilter_h */ + diff --git a/src/VBox/Additions/haiku/VBoxTray/Makefile.kmk b/src/VBox/Additions/haiku/VBoxTray/Makefile.kmk new file mode 100644 index 00000000..96d6c52e --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxTray/Makefile.kmk @@ -0,0 +1,128 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for VBoxTray, Haiku Guest Additions. +# + +# +# Copyright (C) 2012-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +# +# This code is based on: +# +# VirtualBox Guest Additions for Haiku. +# Copyright (c) 2011 Mike Smith <mike@scgtrp.net> +# François Revol <revol@free.fr> +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +# @todo split the tray code, +# single bin will cause problems loading gcc4 binary from a gcc2-built Deskbar! + +PROGRAMS += VBoxTray +VBoxTray_TEMPLATE = VBoxGuestR3Exe +VBoxTray_DEFS = VBOX_WITH_HGCM LOG_TO_BACKDOOR +VBoxTray_DEFS += LOG_ENABLED +VBoxTray_INCS = ../include +VBoxTray_SOURCES = \ + VBoxClipboard.cpp \ + VBoxDisplay.cpp \ + VBoxGuestApplication.cpp \ + VBoxGuestDeskbarView.cpp + +VBoxTray_SOURCES += \ + $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp + +VBoxTray_LIBS = \ + be translation \ + $(VBOX_LIB_VBGL_R3) \ + $(VBOX_LIB_IPRT_GUEST_R3) \ + $(VBOX_LIB_VBGL_R3) + +VBoxTray_RSRCS += $(VBoxTray_0_OUTDIR)/VBoxTray.rsrc +VBoxTray_DEPS += $(VBoxTray_0_OUTDIR)/VBoxTray.rsrc +VBoxTray_CLEAN += $(VBoxTray_0_OUTDIR)/VBoxTray.rsrc + +# VBoxGuestApplication.cpp uses VBOX_SVN_REV. +VBoxGuestApplication.cpp_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV) +VBoxGuestApplication.cpp_DEPS = $(VBOX_SVN_REV_KMK) +VBoxGuestDeskbarView.cpp_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV) +VBoxGuestDeskbarView.cpp_DEPS = $(VBOX_SVN_REV_KMK) + +## The icon location is configurable. +VBoxTray.rdef_INCS = $(VBoxTray_0_OUTDIR) +VBoxTray.rdef_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV) \ + VBOX_HAIKU_DESKBAR_ICON_PNG=\"$(VBOX_BRAND_GUI_VBOX_16PX_PNG)\" +VBoxTray.rdef_DEPS = $(VBOX_SVN_REV_KMK) + +VBoxTray.rsrc_DEPS = VBoxTray.rdef +VBoxTray.rsrc_CLEAN = VBoxTray.rdef + + + +#XXX: cleanup! +#XXX: handle deps correctly +#XXX: -I / is due to a bug in rc with absolute paths +## Resource file. +$$(VBoxTray_0_OUTDIR)/VBoxTray.rsrc: $$(VBoxTray_DEFPATH)/VBoxTray.rdef $$(VBoxTray_DEFPATH)/Makefile.kmk | $$(dir $$@) + $(call MSG_TOOL,$(VBOX_HAIKU_RCTOOL),HaikuResources,$<,$@) + $(QUIET)cat $< | gcc -E -I $(dir $<) -I $(dir $<)/../include $(foreach name, $(INCS), -I $(name)) $(foreach dname, $(VBoxTray.rdef_DEFS), -D$(dname)) - | grep -v '^#' | $(VBOX_HAIKU_RCTOOL) -I / -I $(dir $<) -I $(dir $<)/../include -o "$@" - + + +# rc -I $(VBoxTray_DEFPATH)/../include -o $@ $< +# $(RM) -f $@ +# $(APPEND) $@ 'IDI_VIRTUALBOX ICON DISCARDABLE "$(subst /,\\,$(VBOX_WINDOWS_ADDITIONS_ICON_FILE))"' + +## The icon location is configurable. +#VBoxTray.rc_INCS = $(VBoxTray_0_OUTDIR) +#VBoxTray.rc_DEPS = $(VBoxTray_0_OUTDIR)/VBoxTray-icon.rc +#VBoxTray.rc_CLEAN = $(VBoxTray_0_OUTDIR)/VBoxTray-icon.rc + +## Icon include file. +#$$(VBoxTray_0_OUTDIR)/VBoxTray-icon.rc: $(VBOX_WINDOWS_ADDITIONS_ICON_FILE) $$(VBoxTray_DEFPATH)/Makefile.kmk | $$(dir $$@) +# $(RM) -f $@ +# $(APPEND) $@ 'IDI_VIRTUALBOX ICON DISCARDABLE "$(subst /,\\,$(VBOX_WINDOWS_ADDITIONS_ICON_FILE))"' + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.cpp b/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.cpp new file mode 100644 index 00000000..b500b95d --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.cpp @@ -0,0 +1,468 @@ +/* $Id: VBoxClipboard.cpp $ */ +/** @file + * VBoxClipboard; Haiku Guest Additions, implementation. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * Fran�ois Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <new> +#include <Bitmap.h> +#include <BitmapStream.h> +#include <Clipboard.h> +#include <DataIO.h> +#include <Message.h> +#include <TranslationUtils.h> +#include <TranslatorFormats.h> +#include <TranslatorRoster.h> +#include <String.h> + +#include "VBoxGuestApplication.h" +#include "VBoxClipboard.h" +#include <VBoxGuestInternal.h> + +#include <iprt/mem.h> +#include <VBox/GuestHost/clipboard-helper.h> +#include <VBox/HostServices/VBoxClipboardSvc.h> +#include <VBox/log.h> + +/** @todo r=ramshankar: this hack should go eventually. */ +#ifdef DEBUG_ramshankar +# undef Log +# define Log(x) printf x +# undef LogRel +# define LogRel(x) printf x +# undef LogRelFlowFunc +# define LogRelFlowFunc(x) printf x +#endif + + +VBoxShClService::VBoxShClService() + : BHandler("VBoxShClService"), + fClientId(-1), + fServiceThreadID(-1), + fExiting(false) +{ +} + + +VBoxShClService::~VBoxShClService() +{ +} + + +status_t VBoxShClService::Connect() +{ + status_t err; + LogFlowFunc(("Connect\n")); + + int rc = VbglR3ClipboardConnect(&fClientId); + if (RT_SUCCESS(rc)) + { + err = fServiceThreadID = spawn_thread(_ServiceThreadNub, "VBoxShClService", B_NORMAL_PRIORITY, this); + if (err >= B_OK) + { + resume_thread(fServiceThreadID); + err = be_clipboard->StartWatching(BMessenger(this)); + LogFlow(("be_clipboard->StartWatching: %ld\n", err)); + if (err == B_OK) + return B_OK; + else + LogRel(("VBoxShClService: Error watching the system clipboard: %ld\n", err)); + } + else + LogRel(("VBoxShClService: Error starting service thread: %ld\n", err)); + + //rc = RTErrConvertFromErrno(err); + VbglR3ClipboardDisconnect(fClientId); + } + else + LogRel(("VBoxShClService: Error starting service thread: %d\n", rc)); + return B_ERROR; +} + + +status_t VBoxShClService::Disconnect() +{ + status_t status; + + be_clipboard->StopWatching(BMessenger(this)); + + fExiting = true; + + VbglR3ClipboardDisconnect(fClientId); + + wait_for_thread(fServiceThreadID, &status); + return B_OK; +} + + +void VBoxShClService::MessageReceived(BMessage *message) +{ + uint32_t formats = 0; + message->PrintToStream(); + switch (message->what) + { + case VBOX_GUEST_CLIPBOARD_HOST_MSG_FORMATS: + { + int rc; + uint32_t cb; + void *pv; + bool commit = false; + + if (message->FindInt32("Formats", (int32 *)&formats) != B_OK) + break; + + if (!formats) + break; + + if (!be_clipboard->Lock()) + break; + + be_clipboard->Clear(); + BMessage *clip = be_clipboard->Data(); + if (!clip) + { + be_clipboard->Unlock(); + break; + } + + if (formats & VBOX_SHCL_FMT_UNICODETEXT) + { + pv = _VBoxReadHostClipboard(VBOX_SHCL_FMT_UNICODETEXT, &cb); + if (pv) + { + char *text; + rc = RTUtf16ToUtf8((PCRTUTF16)pv, &text); + if (RT_SUCCESS(rc)) + { + BString str(text); + /** @todo user vboxClipboardUtf16WinToLin() */ + // convert Windows CRLF to LF + str.ReplaceAll("\r\n", "\n"); + // don't include the \0 + clip->AddData("text/plain", B_MIME_TYPE, str.String(), str.Length()); + RTStrFree(text); + commit = true; + } + free(pv); + } + } + + if (formats & VBOX_SHCL_FMT_BITMAP) + { + pv = _VBoxReadHostClipboard(VBOX_SHCL_FMT_BITMAP, &cb); + if (pv) + { + void *pBmp = NULL; + size_t cbBmp = 0; + rc = ShClDibToBmp(pv, cb, &pBmp, &cbBmp); + if (RT_SUCCESS(rc)) + { + BMemoryIO mio(pBmp, cbBmp); + BBitmap *bitmap = BTranslationUtils::GetBitmap(&mio); + if (bitmap) + { + BMessage bitmapArchive; + + /** @todo r=ramshankar: split this into functions with error checking as + * neccessary. */ + if ( bitmap->IsValid() + && bitmap->Archive(&bitmapArchive) == B_OK + && clip->AddMessage("image/bitmap", &bitmapArchive) == B_OK) + { + commit = true; + } + delete bitmap; + } + RTMemFree(pBmp); + } + free(pv); + } + } + + /* + * Make sure we don't bounce this data back to the host, it's impolite. It can also + * be used as a hint to applications probably. + */ + clip->AddBool("FromVirtualBoxHost", true); + if (commit) + be_clipboard->Commit(); + be_clipboard->Unlock(); + break; + } + + case VBOX_GUEST_CLIPBOARD_HOST_MSG_READ_DATA: + { + int rc; + + if (message->FindInt32("Formats", (int32 *)&formats) != B_OK) + break; + + if (!formats) + break; + if (!be_clipboard->Lock()) + break; + + BMessage *clip = be_clipboard->Data(); + if (!clip) + { + be_clipboard->Unlock(); + break; + } + clip->PrintToStream(); + + if (formats & VBOX_SHCL_FMT_UNICODETEXT) + { + const char *text; + int32 textLen; + if (clip->FindData("text/plain", B_MIME_TYPE, (const void **)&text, &textLen) == B_OK) + { + // usually doesn't include the \0 so be safe + BString str(text, textLen); + // convert from LF to Windows CRLF + str.ReplaceAll("\n", "\r\n"); + PRTUTF16 pwsz; + rc = RTStrToUtf16(str.String(), &pwsz); + if (RT_SUCCESS(rc)) + { + uint32_t cb = (RTUtf16Len(pwsz) + 1) * sizeof(RTUTF16); + + rc = VbglR3ClipboardWriteData(fClientId, VBOX_SHCL_FMT_UNICODETEXT, pwsz, cb); + //printf("VbglR3ClipboardWriteData: %d\n", rc); + RTUtf16Free(pwsz); + } + } + } + else if (formats & VBOX_SHCL_FMT_BITMAP) + { + BMessage archivedBitmap; + if (clip->FindMessage("image/bitmap", &archivedBitmap) == B_OK || + clip->FindMessage("image/x-be-bitmap", &archivedBitmap) == B_OK) + { + BBitmap *bitmap = new(std::nothrow) BBitmap(&archivedBitmap); + if (bitmap) + { + // Don't delete bitmap, BBitmapStream will. + BBitmapStream stream(bitmap); + BTranslatorRoster *roster = BTranslatorRoster::Default(); + if (roster && bitmap->IsValid()) + { + BMallocIO bmpStream; + if (roster->Translate(&stream, NULL, NULL, &bmpStream, B_BMP_FORMAT) == B_OK) + { + const void *pDib; + size_t cbDibSize; + /* Strip out the BM header */ + rc = ShClBmpGetDib(bmpStream.Buffer(), bmpStream.BufferLength(), &pDib, &cbDibSize); + if (RT_SUCCESS(rc)) + { + rc = VbglR3ClipboardWriteData(fClientId, VBOX_SHCL_FMT_BITMAP, (void *)pDib, + cbDibSize); + } + } + } + } + } + } + + be_clipboard->Unlock(); + break; + } + + case B_CLIPBOARD_CHANGED: + { + printf("B_CLIPBOARD_CHANGED\n"); + const void *data; + int32 dataLen; + if (!be_clipboard->Lock()) + break; + + BMessage *clip = be_clipboard->Data(); + if (!clip) + { + be_clipboard->Unlock(); + break; + } + + bool fromVBox; + if (clip->FindBool("FromVirtualBoxHost", &fromVBox) == B_OK && fromVBox) + { + // It already comes from the host, discard. + be_clipboard->Unlock(); + break; + } + + if (clip->FindData("text/plain", B_MIME_TYPE, &data, &dataLen) == B_OK) + formats |= VBOX_SHCL_FMT_UNICODETEXT; + + if ( clip->HasMessage("image/bitmap") + || clip->HasMessage("image/x-be-bitmap")) + { + formats |= VBOX_SHCL_FMT_BITMAP; + } + + be_clipboard->Unlock(); + + VbglR3ClipboardReportFormats(fClientId, formats); + break; + } + + case B_QUIT_REQUESTED: + fExiting = true; + break; + + default: + BHandler::MessageReceived(message); + } +} + + +status_t VBoxShClService::_ServiceThreadNub(void *_this) +{ + VBoxShClService *service = (VBoxShClService *)_this; + return service->_ServiceThread(); +} + + +status_t VBoxShClService::_ServiceThread() +{ + printf("VBoxShClService::%s()\n", __FUNCTION__); + + /* The thread waits for incoming messages from the host. */ + for (;;) + { + uint32_t u32Msg; + uint32_t u32Formats; + int rc = VbglR3ClipboardGetHostMsgOld(fClientId, &u32Msg, &u32Formats); + if (RT_SUCCESS(rc)) + { + switch (u32Msg) + { + case VBOX_SHCL_HOST_MSG_FORMATS_REPORT: + { + /* + * The host has announced available clipboard formats. Forward + * the information to the handler. + */ + LogRelFlowFunc(("VBOX_SHCL_HOST_MSG_REPORT_FORMATS u32Formats=%x\n", u32Formats)); + BMessage msg(VBOX_GUEST_CLIPBOARD_HOST_MSG_FORMATS); + msg.AddInt32("Formats", (uint32)u32Formats); + Looper()->PostMessage(&msg, this); + break; + } + + case VBOX_SHCL_HOST_MSG_READ_DATA: + { + /* The host needs data in the specified format. */ + LogRelFlowFunc(("VBOX_SHCL_HOST_MSG_READ_DATA u32Formats=%x\n", u32Formats)); + BMessage msg(VBOX_GUEST_CLIPBOARD_HOST_MSG_READ_DATA); + msg.AddInt32("Formats", (uint32)u32Formats); + Looper()->PostMessage(&msg, this); + break; + } + + case VBOX_SHCL_HOST_MSG_QUIT: + { + /* The host is terminating. */ + LogRelFlowFunc(("VBOX_SHCL_HOST_MSG_QUIT\n")); + fExiting = true; + return VERR_INTERRUPTED; + } + + default: + Log(("VBoxShClService::%s: Unsupported message from host! Message = %u\n", __FUNCTION__, u32Msg)); + } + } + else + fExiting = true; + + LogRelFlow(("processed host event rc = %d\n", rc)); + + if (fExiting) + break; + } + return 0; +} + + +void* VBoxShClService::_VBoxReadHostClipboard(uint32_t format, uint32_t *pcb) +{ + uint32_t cb = 1024; + void *pv; + int rc; + + pv = malloc(cb); + if (pv == NULL) + return NULL; + + rc = VbglR3ClipboardReadData(fClientId, format, pv, cb, pcb); + if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW)) + return pv; + if (rc == VINF_BUFFER_OVERFLOW) + { + free(pv); + cb = *pcb; + pv = malloc(cb); + if (pv == NULL) + return NULL; + + rc = VbglR3ClipboardReadData(fClientId, format, pv, cb, pcb); + if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW)) + return pv; + + free(pv); + } + return NULL; +} + diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.h b/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.h new file mode 100644 index 00000000..ad4cabbd --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.h @@ -0,0 +1,88 @@ +/* $Id: VBoxClipboard.h $ */ +/** @file + * VBoxClipboard, Haiku Guest Additions, header. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GA_INCLUDED_SRC_haiku_VBoxTray_VBoxClipboard_h +#define GA_INCLUDED_SRC_haiku_VBoxTray_VBoxClipboard_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <Handler.h> + +class VBoxShClService : public BHandler +{ + public: + VBoxShClService(); + virtual ~VBoxShClService(); + + virtual status_t Connect(); + virtual status_t Disconnect(); + + virtual void MessageReceived(BMessage *message); + + private: + static status_t _ServiceThreadNub(void *_this); + status_t _ServiceThread(); + + void* _VBoxReadHostClipboard(uint32_t format, uint32_t *pcb); + + uint32_t fClientId; + thread_id fServiceThreadID; + bool fExiting; +}; + +#endif /* !GA_INCLUDED_SRC_haiku_VBoxTray_VBoxClipboard_h */ + diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.cpp b/src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.cpp new file mode 100644 index 00000000..5eb0a7d5 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.cpp @@ -0,0 +1,177 @@ +/* $Id: VBoxDisplay.cpp $ */ +/** @file + * VBoxDisplayService, Haiku Guest Additions, implementation. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <new> +#include <DataIO.h> +#include <Message.h> +#include <TranslationUtils.h> +#include <TranslatorFormats.h> +#include <TranslatorRoster.h> +#include <String.h> + +#include "VBoxGuestApplication.h" +#include "VBoxDisplay.h" +#include <VBoxGuestInternal.h> +#include "../VBoxVideo/common/VBoxVideo_common.h" + +#include <iprt/mem.h> +#include <VBox/log.h> + +#ifdef DEBUG_ramshankar +# undef Log +# define Log(x) printf x +# undef LogRel +# define LogRel(x) printf x +# undef LogRelFlowFunc +# define LogRelFlowFunc(x) printf x +#endif + +VBoxDisplayService::VBoxDisplayService() + : BHandler("VBoxDisplayService"), + fClientId(-1), + fServiceThreadID(-1), + fExiting(false), + fScreen(B_MAIN_SCREEN_ID) +{ +} + + +VBoxDisplayService::~VBoxDisplayService() +{ +} + + +void VBoxDisplayService::Start() +{ + status_t err; + err = fServiceThreadID = spawn_thread(_ServiceThreadNub, "VBoxDisplayService", B_NORMAL_PRIORITY, this); + if (err >= B_OK) + resume_thread(fServiceThreadID); + else + LogRel(("VBoxDisplayService: Error starting service thread: %s\n", strerror(err))); +} + + +void VBoxDisplayService::MessageReceived(BMessage *message) +{ + if (message->what == B_QUIT_REQUESTED) + fExiting = true; + else + BHandler::MessageReceived(message); +} + + +status_t VBoxDisplayService::_ServiceThreadNub(void *_this) +{ + VBoxDisplayService *service = (VBoxDisplayService *)_this; + return service->_ServiceThread(); +} + + +status_t VBoxDisplayService::_ServiceThread() +{ + LogFlow(("VBoxDisplayService::_ServiceThread")); + + VbglR3CtlFilterMask(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0); + VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0); + for (;;) + { + uint32_t events; + int rc = VbglR3WaitEvent(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 5000, &events); + if ( rc == VERR_TIMEOUT + || rc == VERR_INTERRUPTED) + continue; + + if (RT_SUCCESS(rc)) + { + uint32_t cx, cy, cBits, iDisplay; + int rc2 = VbglR3GetDisplayChangeRequest(&cx, &cy, &cBits, &iDisplay, NULL, NULL, NULL, NULL, true); + LogFlow(("rc2=%d screen %d size changed (%d, %d, %d)\n", rc2, iDisplay, cx, cy, cBits)); + + if (RT_SUCCESS(rc2)) + { + display_mode mode; + fScreen.GetMode(&mode); + if (cBits == 0) + cBits = get_depth_for_color_space(mode.space); + + mode.timing.h_display = cx; + mode.timing.v_display = cy; + mode.space = get_color_space_for_depth(cBits); + mode.virtual_width = cx; + mode.virtual_height = cy; + + /*= { + {0, cx, 0, 0, cBits * cx / 8, cy, 0, 0, cBits * cy / 8, 0}, + get_color_space_for_depth(cBits), + cx, cy, 0, 0, 0 + };*/ + + fScreen.SetMode(&mode, false); + } + } + else + fExiting = true; + + LogFlow(("processed host event rc = %d\n", rc)); + if (fExiting) + break; + } + return 0; +} + diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.h b/src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.h new file mode 100644 index 00000000..434cca51 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxTray/VBoxDisplay.h @@ -0,0 +1,86 @@ +/* $Id: VBoxDisplay.h $ */ +/** @file + * VBoxDisplayService, Haiku Guest Additions, header. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GA_INCLUDED_SRC_haiku_VBoxTray_VBoxDisplay_h +#define GA_INCLUDED_SRC_haiku_VBoxTray_VBoxDisplay_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <Handler.h> +#include <Screen.h> + +class VBoxDisplayService : public BHandler +{ + public: + VBoxDisplayService(); + virtual ~VBoxDisplayService(); + + void Start(); + virtual void MessageReceived(BMessage *message); + + private: + static status_t _ServiceThreadNub(void *_this); + status_t _ServiceThread(); + + uint32_t fClientId; + thread_id fServiceThreadID; + volatile bool fExiting; + BScreen fScreen; +}; + +#endif /* !GA_INCLUDED_SRC_haiku_VBoxTray_VBoxDisplay_h */ + diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.cpp b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.cpp new file mode 100644 index 00000000..c2c26762 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.cpp @@ -0,0 +1,101 @@ +/* $Id: VBoxGuestApplication.cpp $ */ +/** @file + * VBoxGuestApplication, Haiku Guest Additions, implementation. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/log.h> + +#include <errno.h> +#include <Alert.h> +#include <Debug.h> +#include <Invoker.h> +#include <String.h> + +#include "VBoxClipboard.h" +#include "VBoxGuestApplication.h" +#include "VBoxGuestDeskbarView.h" + +VBoxGuestApplication::VBoxGuestApplication() + : BApplication(VBOX_GUEST_APP_SIG) +{ +} + + +VBoxGuestApplication::~VBoxGuestApplication() +{ +} + + +void VBoxGuestApplication::ReadyToRun() +{ + status_t err; + + err = VBoxGuestDeskbarView::AddToDeskbar(); + LogFlow(("VBoxGuestDeskbarView::ReadyToRun: AddToDeskbar returned 0x%08lx\n", err)); + exit(0); +} + + +int main(int argc, const char **argv) +{ + new VBoxGuestApplication(); + be_app->Run(); + delete be_app; + return 0; +} + diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.h b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.h new file mode 100644 index 00000000..d7996740 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestApplication.h @@ -0,0 +1,89 @@ +/* $Id: VBoxGuestApplication.h $ */ +/** @file + * VBoxGuestApplication, Haiku Guest Additions, header. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GA_INCLUDED_SRC_haiku_VBoxTray_VBoxGuestApplication_h +#define GA_INCLUDED_SRC_haiku_VBoxTray_VBoxGuestApplication_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** @todo r=ramshankar; why are we including all the headers here!?? Do it in + * the .cpp please. */ +#include <Application.h> + +#include <iprt/initterm.h> +#include <iprt/string.h> + +#include <VBox/version.h> +#include <VBox/log.h> +#include <VBox/VBoxGuest.h> /** @todo use the VbglR3 interface! */ +#include <VBox/VBoxGuestLib.h> + +#include <VBoxGuestInternal.h> + +class VBoxShClService; + +class VBoxGuestApplication : public BApplication +{ + public: + VBoxGuestApplication(); + virtual ~VBoxGuestApplication(); + + virtual void ReadyToRun(); +}; + +#endif /* !GA_INCLUDED_SRC_haiku_VBoxTray_VBoxGuestApplication_h */ + diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.cpp b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.cpp new file mode 100644 index 00000000..aaba2392 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.cpp @@ -0,0 +1,297 @@ +/* $Id: VBoxGuestDeskbarView.cpp $ */ +/** @file + * VBoxGuestDeskbarView, Haiku Guest Additions, implementation. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <errno.h> +#include <Alert.h> +#include <Roster.h> +#include <Debug.h> +#include <Deskbar.h> +#include <File.h> +#include <MenuItem.h> +#include <Path.h> +#include <PopUpMenu.h> +#include <Resources.h> +#include <String.h> +#include <TranslationUtils.h> + +#include "VBoxGuestDeskbarView.h" +#include "VBoxGuestApplication.h" + +#define VIEWNAME "VBoxGuestDeskbarView" + +static status_t +our_image(image_info& image) +{ + /** @todo r=ramshankar: find a way to do this without annoying the compiler, probably uintptr_t? */ + int32 cookie = 0; + while (get_next_image_info(B_CURRENT_TEAM, &cookie, &image) == B_OK) + { + if ((char *)our_image >= (char *)image.text + && (char *)our_image <= (char *)image.text + image.text_size) + return B_OK; + } + + return B_ERROR; +} + + +VBoxGuestDeskbarView::VBoxGuestDeskbarView() + : BView(BRect(0, 0, 15, 15), VIEWNAME, B_FOLLOW_NONE, + B_WILL_DRAW | B_NAVIGABLE), + fIcon(NULL), fClipboardService(NULL), fDisplayService(NULL) +{ + _Init(); +} + + +VBoxGuestDeskbarView::VBoxGuestDeskbarView(BMessage *archive) + : BView(archive), + fIcon(NULL) +{ + archive->PrintToStream(); + _Init(archive); +} + + +VBoxGuestDeskbarView::~VBoxGuestDeskbarView() +{ + delete fIcon; + if (fClipboardService) + { + fClipboardService->Disconnect(); + delete fClipboardService; + } + VbglR3Term(); +} + + +BArchivable* VBoxGuestDeskbarView::Instantiate(BMessage *data) +{ + if (!validate_instantiation(data, VIEWNAME)) + return NULL; + + return new VBoxGuestDeskbarView(data); +} + + +status_t VBoxGuestDeskbarView::Archive(BMessage *data, bool deep) const +{ + status_t err; + + err = BView::Archive(data, false); + if (err < B_OK) + { + LogRel(("VBoxGuestDeskbarView::Archive failed.rc=%08lx\n", err)); + return err; + } + data->AddString("add_on", VBOX_GUEST_APP_SIG); + data->AddString("class", "VBoxGuestDeskbarView"); + return B_OK; +} + + +void VBoxGuestDeskbarView::Draw(BRect rect) +{ + SetDrawingMode(B_OP_ALPHA); + DrawBitmap(fIcon); +} + + +void VBoxGuestDeskbarView::AttachedToWindow() +{ + BView::AttachedToWindow(); + if (Parent()) + { + SetViewColor(Parent()->ViewColor()); + SetLowColor(Parent()->LowColor()); + } + + if (fClipboardService) /* Don't repeatedly crash deskbar if vboxdev not loaded */ + { + Looper()->AddHandler(fClipboardService); + fClipboardService->Connect(); + } + + if (fDisplayService) + fDisplayService->Start(); +} + + +void VBoxGuestDeskbarView::DetachedFromWindow() +{ + BMessage message(B_QUIT_REQUESTED); + fClipboardService->MessageReceived(&message); + fDisplayService->MessageReceived(&message); +} + + +void VBoxGuestDeskbarView::MouseDown(BPoint point) +{ + int32 buttons = B_PRIMARY_MOUSE_BUTTON; + if (Looper() != NULL && Looper()->CurrentMessage() != NULL) + Looper()->CurrentMessage()->FindInt32("buttons", &buttons); + + BPoint where = ConvertToScreen(point); + + if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) + { + BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false); + menu->SetAsyncAutoDestruct(true); + menu->SetFont(be_plain_font); + + menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED))); + menu->SetTargetForItems(this); + + menu->Go(where, true, true, true); + } +} + + +void VBoxGuestDeskbarView::MessageReceived(BMessage *message) +{ + if (message->what == B_QUIT_REQUESTED) + RemoveFromDeskbar(); + else + BHandler::MessageReceived(message); +} + + +status_t VBoxGuestDeskbarView::AddToDeskbar(bool force) +{ + BDeskbar deskbar; + status_t err; + + if (force) + RemoveFromDeskbar(); + else if (deskbar.HasItem(VIEWNAME)) + return B_OK; + + app_info info; + err = be_app->GetAppInfo(&info); + if (err < B_OK) + return err; + + BPath p(&info.ref); + return deskbar.AddItem(&info.ref); +} + + +status_t VBoxGuestDeskbarView::RemoveFromDeskbar() +{ + BDeskbar deskbar; + return deskbar.RemoveItem(VIEWNAME); +} + + +status_t VBoxGuestDeskbarView::_Init(BMessage *archive) +{ + BString toolTipText; + toolTipText << VBOX_PRODUCT << " Guest Additions "; + toolTipText << VBOX_VERSION_MAJOR << "." << VBOX_VERSION_MINOR << "." << VBOX_VERSION_BUILD; + toolTipText << "r" << VBOX_SVN_REV; + + SetToolTip(toolTipText.String()); + + image_info info; + if (our_image(info) != B_OK) + return B_ERROR; + + BFile file(info.name, B_READ_ONLY); + if (file.InitCheck() < B_OK) + return B_ERROR; + + BResources resources(&file); + if (resources.InitCheck() < B_OK) + return B_ERROR; + + const void *data = NULL; + size_t size; + //data = resources.LoadResource(B_VECTOR_ICON_TYPE, + // kNetworkStatusNoDevice + i, &size); + data = resources.LoadResource('data', 400, &size); + if (data != NULL) + { + BMemoryIO mem(data, size); + fIcon = BTranslationUtils::GetBitmap(&mem); + } + + int rc = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); + if (RT_SUCCESS(rc)) + { + rc = VbglR3Init(); + if (RT_SUCCESS(rc)) + { + fClipboardService = new VBoxShClService(); + fDisplayService = new VBoxDisplayService(); + } + else + LogRel(("VBoxGuestDeskbarView::_init VbglR3Init failed. rc=%d\n", rc)); + } + else + LogRel(("VBoxGuestDeskbarView::_init RTR3InitDll failed. rc=%d\n", rc)); + return RTErrConvertToErrno(rc); +} + + +RTDECL(BView*) instantiate_deskbar_item() +{ + return new VBoxGuestDeskbarView(); +} + diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.h b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.h new file mode 100644 index 00000000..be8cfa54 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxTray/VBoxGuestDeskbarView.h @@ -0,0 +1,109 @@ +/* $Id: VBoxGuestDeskbarView.h $ */ +/** @file + * VBoxGuestDeskbarView, Haiku Guest Additions, header. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GA_INCLUDED_SRC_haiku_VBoxTray_VBoxGuestDeskbarView_h +#define GA_INCLUDED_SRC_haiku_VBoxTray_VBoxGuestDeskbarView_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <Bitmap.h> +#include <View.h> + +#include <iprt/initterm.h> +#include <iprt/string.h> + +#include <VBox/version.h> +#include <VBox/log.h> +#include <VBox/VBoxGuest.h> /** @todo use the VbglR3 interface! */ +#include <VBox/VBoxGuestLib.h> + +#include <VBoxGuestInternal.h> +#include "VBoxClipboard.h" +#include "VBoxDisplay.h" + +#define REMOVE_FROM_DESKBAR_MSG 'vbqr' + +class VBoxGuestDeskbarView : public BView +{ + public: + VBoxGuestDeskbarView(); + VBoxGuestDeskbarView(BMessage *archive); + virtual ~VBoxGuestDeskbarView(); + + static BArchivable* Instantiate(BMessage *data); + virtual status_t Archive(BMessage *data, bool deep = true) const; + + void Draw(BRect rect); + void AttachedToWindow(); + void DetachedFromWindow(); + + virtual void MouseDown(BPoint point); + virtual void MessageReceived(BMessage *message); + + static status_t AddToDeskbar(bool force = true); + static status_t RemoveFromDeskbar(); + + private: + status_t _Init(BMessage *archive = NULL); + BBitmap *fIcon; + + VBoxShClService *fClipboardService; + VBoxDisplayService *fDisplayService; +}; + +#endif /* !GA_INCLUDED_SRC_haiku_VBoxTray_VBoxGuestDeskbarView_h */ + diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxServiceDescriptor.h b/src/VBox/Additions/haiku/VBoxTray/VBoxServiceDescriptor.h new file mode 100644 index 00000000..0a1a0e6e --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxTray/VBoxServiceDescriptor.h @@ -0,0 +1,78 @@ +/* $Id: VBoxServiceDescriptor.h $ */ +/** @file + * VBoxGuestServiceDescriptor, Haiku Guest Additions, header. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GA_INCLUDED_SRC_haiku_VBoxTray_VBoxServiceDescriptor_h +#define GA_INCLUDED_SRC_haiku_VBoxTray_VBoxServiceDescriptor_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <Handler.h> + +class VBoxShClService : public BHandler +{ + public: + VBoxShClService(); + virtual ~VBoxShClService(); +}; + +/* The shared clipboard service prototypes. */ +int VBoxShClInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread); +unsigned __stdcall VBoxShClThread(void *pInstance); +void VBoxShClDestroy(const VBOXSERVICEENV *pEnv, void *pInstance); + +#endif /* !GA_INCLUDED_SRC_haiku_VBoxTray_VBoxServiceDescriptor_h */ + diff --git a/src/VBox/Additions/haiku/VBoxTray/VBoxTray.rdef b/src/VBox/Additions/haiku/VBoxTray/VBoxTray.rdef new file mode 100644 index 00000000..f2bd244c --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxTray/VBoxTray.rdef @@ -0,0 +1,93 @@ +/* $Id: VBoxTray.rdef $ */ +/** @file + * VBoxApp - Resource definition file containing version info and icon, Haiku Guest Additions. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + *----------------------------------------------------------------------------- + * + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "VBoxGuestInternal.h" + +resource(1, "BEOS:APP_SIG") #'MIMS' VBOX_GUEST_APP_SIG; + +resource app_flags B_SINGLE_LAUNCH; + +/* This is done for all binaries with VBOX_HAIKU_XRES_SETVER_CMDS +resource app_version { + major = VBOX_VERSION_MAJOR, + middle = VBOX_VERSION_MINOR, + minor = VBOX_VERSION_BUILD, + + variety = B_APPV_DEVELOPMENT, + internal = VBOX_SVN_REV, + + short_info = VBOX_PRODUCT, + long_info = VBOX_PRODUCT " " VBOX_VERSION_STRING " ©2009-" VBOX_C_YEAR " " VBOX_VENDOR +}; +*/ + +/* Maybe one day ? */ +//resource(1, "BEOS:FILE_TYPES") message { +// "types" = "application/x-vnd.Be.URL.vboxsf" +//}; + +resource vector_icon { + $"6E636966060500020006023B55F13C5CD2BE755C3D78974A454E48FFCB000EB3" + $"B5FF003BFF020006023CD471BA2F923B0FF33DF6F048DA184417BB0000FBFFFF" + $"0000FF020006023C318B3A487CBD09B43EEB2D4B485C48176F0000AAFFFF0537" + $"C704016D05FF070A062231224E3E5C5248522D37260A042231224E3E5C3E3A0A" + $"0422313E3A522D37260A043E5C5248522D3E3A0A043E5E4E5E60485444080835" + $"3A393B3C4442384441493A4B444F460A04352E503750533547060A040104000A" + $"0001001001178400040A010101000A020102000A030103000A05020506123F45" + $"D10000000000003F45D1C70BA246F45D0117820004" +}; + +resource(400, "DeskbarShelfIcon.png") #'data' import VBOX_HAIKU_DESKBAR_ICON_PNG; + diff --git a/src/VBox/Additions/haiku/VBoxVideo/Makefile.kmk b/src/VBox/Additions/haiku/VBoxVideo/Makefile.kmk new file mode 100644 index 00000000..43090fec --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/Makefile.kmk @@ -0,0 +1,64 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for Haiku VBoxVideo. +# + +# +# Copyright (C) 2012-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +# +# This code is based on: +# +# VirtualBox Guest Additions for Haiku. +# Copyright (c) 2011 Mike Smith <mike@scgtrp.net> +# François Revol <revol@free.fr> +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +include $(PATH_SUB_CURRENT)/accelerant/Makefile.kmk +include $(PATH_SUB_CURRENT)/driver/Makefile.kmk + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/haiku/VBoxVideo/accelerant/Makefile.kmk b/src/VBox/Additions/haiku/VBoxVideo/accelerant/Makefile.kmk new file mode 100644 index 00000000..7084e0ed --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/accelerant/Makefile.kmk @@ -0,0 +1,75 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for VBoxVideo accelerant, Haiku Guest Additions. +# + +# +# Copyright (C) 2012-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +# +# This code is based on: +# +# VirtualBox Guest Additions for Haiku. +# Copyright (c) 2011 Mike Smith <mike@scgtrp.net> +# François Revol <revol@free.fr> +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +SUB_DEPTH = ../../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +PROGRAMS += vboxvideo.accelerant +vboxvideo.accelerant_TEMPLATE = VBoxGuestR3Exe +vboxvideo.accelerant_DEFS = VBOX_WITH_HGCM LOG_TO_BACKDOOR +vboxvideo.accelerant_DEFS += LOG_ENABLED +vboxvideo.accelerant_INCS = ../include +vboxvideo.accelerant_SOURCES = \ + accelerant.cpp + +vboxvideo.accelerant_LIBS = \ + be device \ + $(VBOX_LIB_IPRT_GUEST_R3_SHARED) \ + $(VBOX_LIB_VBGL_R3) \ + /system/servers/app_server + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.cpp b/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.cpp new file mode 100644 index 00000000..5352bd82 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.cpp @@ -0,0 +1,473 @@ +/* $Id: accelerant.cpp $ */ +/** @file + * VBoxVideo Accelerant; Haiku Guest Additions, implementation. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <Accelerant.h> +#include "accelerant.h" +#include <stdio.h> +#include <string.h> +#include <errno.h> + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +AccelerantInfo gInfo; +static engine_token sEngineToken = { 1, 0 /*B_2D_ACCELERATION*/, NULL }; + +/** @todo r=ramshankar: get rid of this and replace with IPRT logging. */ +#define TRACE(x...) do { \ + FILE* logfile = fopen("/var/log/vboxvideo.accelerant.log", "a"); \ + fprintf(logfile, x); \ + fflush(logfile); \ + fsync(fileno(logfile)); \ + fclose(logfile); \ + sync(); \ + } while(0) + +class AreaCloner +{ + public: + AreaCloner() + : fArea(-1) + { + } + + ~AreaCloner() + { + if (fArea >= B_OK) + delete_area(fArea); + } + + area_id Clone(const char *name, void **_address, uint32 spec, uint32 protection, area_id sourceArea) + { + fArea = clone_area(name, _address, spec, protection, sourceArea); + return fArea; + } + + status_t InitCheck() + { + return fArea < B_OK ? (status_t)fArea : B_OK; + } + + void Keep() + { + fArea = -1; + } + + private: + area_id fArea; +}; + +extern "C" +void* get_accelerant_hook(uint32 feature, void *data) +{ + TRACE("%s\n", __FUNCTION__); + switch (feature) + { + /* General */ + case B_INIT_ACCELERANT: + return (void *)vboxvideo_init_accelerant; + case B_UNINIT_ACCELERANT: + return (void *)vboxvideo_uninit_accelerant; + case B_CLONE_ACCELERANT: + return (void *)vboxvideo_clone_accelerant; + case B_ACCELERANT_CLONE_INFO_SIZE: + return (void *)vboxvideo_accelerant_clone_info_size; + case B_GET_ACCELERANT_CLONE_INFO: + return (void *)vboxvideo_get_accelerant_clone_info; + case B_GET_ACCELERANT_DEVICE_INFO: + return (void *)vboxvideo_get_accelerant_device_info; + case B_ACCELERANT_RETRACE_SEMAPHORE: + return (void *)vboxvideo_accelerant_retrace_semaphore; + + /* Mode configuration */ + case B_ACCELERANT_MODE_COUNT: + return (void *)vboxvideo_accelerant_mode_count; + case B_GET_MODE_LIST: + return (void *)vboxvideo_get_mode_list; + case B_SET_DISPLAY_MODE: + return (void *)vboxvideo_set_display_mode; + case B_GET_DISPLAY_MODE: + return (void *)vboxvideo_get_display_mode; + case B_GET_EDID_INFO: + return (void *)vboxvideo_get_edid_info; + case B_GET_FRAME_BUFFER_CONFIG: + return (void *)vboxvideo_get_frame_buffer_config; + case B_GET_PIXEL_CLOCK_LIMITS: + return (void *)vboxvideo_get_pixel_clock_limits; + +#if 0 + /* cursor managment */ + case B_SET_CURSOR_SHAPE: + return (void*)vboxvideo_set_cursor_shape; + case B_MOVE_CURSOR: + return (void*)vboxvideo_move_cursor; + case B_SHOW_CURSOR: + return (void*)vboxvideo_show_cursor; +#endif + + /* Engine/synchronization */ + case B_ACCELERANT_ENGINE_COUNT: + return (void *)vboxvideo_accelerant_engine_count; + case B_ACQUIRE_ENGINE: + return (void *)vboxvideo_acquire_engine; + case B_RELEASE_ENGINE: + return (void *)vboxvideo_release_engine; + case B_WAIT_ENGINE_IDLE: + return (void *)vboxvideo_wait_engine_idle; + case B_GET_SYNC_TOKEN: + return (void *)vboxvideo_get_sync_token; + case B_SYNC_TO_TOKEN: + return (void *)vboxvideo_sync_to_token; + } + + return NULL; +} + +status_t vboxvideo_init_common(int fd, bool cloned) +{ + unlink("/var/log/vboxvideo.accelerant.log"); // clear old log - next TRACE() will recreate it + TRACE("%s\n", __FUNCTION__); + + gInfo.deviceFD = fd; + gInfo.isClone = cloned; + gInfo.sharedInfo = NULL; + gInfo.sharedInfoArea = -1; + + area_id sharedArea; + if (ioctl(gInfo.deviceFD, VBOXVIDEO_GET_PRIVATE_DATA, &sharedArea, sizeof(area_id)) != 0) + { + TRACE("ioctl failed\n"); + return B_ERROR; + } + + AreaCloner sharedCloner; + gInfo.sharedInfoArea = sharedCloner.Clone("vboxvideo shared info", (void **)&gInfo.sharedInfo, B_ANY_ADDRESS, + B_READ_AREA | B_WRITE_AREA, sharedArea); + status_t status = sharedCloner.InitCheck(); + if (status < B_OK) + { + TRACE("InitCheck failed (%s)\n", strerror(status)); + return status; + } + sharedCloner.Keep(); + + return B_OK; +} + + +status_t vboxvideo_init_accelerant(int fd) +{ + return vboxvideo_init_common(fd, false); +} + + +ssize_t vboxvideo_accelerant_clone_info_size(void) +{ + TRACE("%s\n", __FUNCTION__); + return B_PATH_NAME_LENGTH; +} + + +void vboxvideo_get_accelerant_clone_info(void *data) +{ + TRACE("%s\n", __FUNCTION__); + ioctl(gInfo.deviceFD, VBOXVIDEO_GET_DEVICE_NAME, data, B_PATH_NAME_LENGTH); +} + + +status_t vboxvideo_clone_accelerant(void *data) +{ + TRACE("%s\n", __FUNCTION__); + + /* Create full device name */ + char path[MAXPATHLEN]; + strcpy(path, "/dev/"); + strcat(path, (const char *)data); + + int fd = open(path, B_READ_WRITE); + if (fd < 0) + return errno; + + return vboxvideo_init_common(fd, true); +} + + +void vboxvideo_uninit_accelerant(void) +{ + delete_area(gInfo.sharedInfoArea); + gInfo.sharedInfo = NULL; + gInfo.sharedInfoArea = -1; + + if (gInfo.isClone) + close(gInfo.deviceFD); + + TRACE("%s\n", __FUNCTION__); +} + + +status_t vboxvideo_get_accelerant_device_info(accelerant_device_info *adi) +{ + TRACE("%s\n", __FUNCTION__); + adi->version = B_ACCELERANT_VERSION; + strcpy(adi->name, "Virtual display"); + strcpy(adi->chipset, "VirtualBox Graphics Adapter"); + strcpy(adi->serial_no, "9001"); + return B_OK; +} + + +sem_id vboxvideo_accelerant_retrace_semaphore(void) +{ + TRACE("%s\n", __FUNCTION__); + return -1; +} + + +// modes & constraints +uint32 vboxvideo_accelerant_mode_count(void) +{ + TRACE("%s\n", __FUNCTION__); + return 1; +} + + +status_t vboxvideo_get_mode_list(display_mode *dm) +{ + /// @todo return some standard modes here + TRACE("%s\n", __FUNCTION__); + return vboxvideo_get_display_mode(dm); +} + + +status_t vboxvideo_set_display_mode(display_mode *modeToSet) +{ + TRACE("%s\n", __FUNCTION__); + TRACE("trying to set mode %dx%d\n", modeToSet->timing.h_display, modeToSet->timing.v_display); + return ioctl(gInfo.deviceFD, VBOXVIDEO_SET_DISPLAY_MODE, modeToSet, sizeof(display_mode)); +} + + +status_t vboxvideo_get_display_mode(display_mode *currentMode) +{ + TRACE("%s\n", __FUNCTION__); + *currentMode = gInfo.sharedInfo->currentMode; + TRACE("current mode is %dx%d\n", currentMode->timing.h_display, currentMode->timing.v_display); + return B_OK; +} + + +status_t vboxvideo_get_edid_info(void *info, size_t size, uint32 *_version) +{ + TRACE("%s\n", __FUNCTION__); + + /* Copied from the X11 implementation: */ + static const uint8 edid_data[128] = { + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, /* header */ + 0x58, 0x58, /* manufacturer (VBX) */ + 0x00, 0x00, /* product code */ + 0x00, 0x00, 0x00, 0x00, /* serial number goes here */ + 0x01, /* week of manufacture */ + 0x00, /* year of manufacture */ + 0x01, 0x03, /* EDID version */ + 0x80, /* capabilities - digital */ + 0x00, /* horiz. res in cm, zero for projectors */ + 0x00, /* vert. res in cm */ + 0x78, /* display gamma (120 == 2.2). Should we ask the host for this? */ + 0xEE, /* features (standby, suspend, off, RGB, standard colour space, + * preferred timing mode) */ + 0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F, 0x50, 0x54, + /* chromaticity for standard colour space - should we ask the host? */ + 0x00, 0x00, 0x00, /* no default timings */ + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, /* no standard timings */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* descriptor block 1 goes here */ + 0x00, 0x00, 0x00, 0xFD, 0x00, /* descriptor block 2, monitor ranges */ + 0x00, 0xC8, 0x00, 0xC8, 0x64, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, /* 0-200Hz vertical, 0-200KHz horizontal, 1000MHz pixel clock */ + 0x00, 0x00, 0x00, 0xFC, 0x00, /* descriptor block 3, monitor name */ + 'V', 'B', 'O', 'X', ' ', 'm', 'o', 'n', 'i', 't', 'o', 'r', '\n', + 0x00, 0x00, 0x00, 0x10, 0x00, /* descriptor block 4: dummy data */ + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, + 0x00, /* number of extensions */ + 0x00 /* checksum goes here */ + }; + + if (size < 128) + return B_BUFFER_OVERFLOW; + + *_version = 1; /* EDID_VERSION_1 */ + memcpy(info, edid_data, 128); + return B_OK; +} + + +status_t vboxvideo_get_frame_buffer_config(frame_buffer_config *config) +{ + TRACE("%s\n", __FUNCTION__); + config->frame_buffer = gInfo.sharedInfo->framebuffer; + config->frame_buffer_dma = NULL; + config->bytes_per_row = get_depth_for_color_space(gInfo.sharedInfo->currentMode.space) + * gInfo.sharedInfo->currentMode.timing.h_display / 8; + return B_OK; +} + + +status_t vboxvideo_get_pixel_clock_limits(display_mode *dm, uint32 *low, uint32 *high) +{ + TRACE("%s\n", __FUNCTION__); + // irrelevant for virtual monitors + *low = 0; + *high = 9001; + return B_OK; +} + + +/* Cursor */ +status_t vboxvideo_set_cursor_shape(uint16 width, uint16 height, uint16 hotX, uint16 hotY, uint8 *andMask, uint8 *xorMask) +{ + TRACE("%s\n", __FUNCTION__); + // VBoxHGSMIUpdatePointerShape + return B_UNSUPPORTED; +} + + +void vboxvideo_move_cursor(uint16 x, uint16 y) +{ + TRACE("%s\n", __FUNCTION__); +} + + +void vboxvideo_show_cursor(bool is_visible) +{ + TRACE("%s\n", __FUNCTION__); +} + + +/* Accelerant engine */ +uint32 vboxvideo_accelerant_engine_count(void) +{ + TRACE("%s\n", __FUNCTION__); + return 1; +} + +status_t vboxvideo_acquire_engine(uint32 capabilities, uint32 maxWait, sync_token *st, engine_token **et) +{ + TRACE("%s\n", __FUNCTION__); + *et = &sEngineToken; + return B_OK; +} + + +status_t vboxvideo_release_engine(engine_token *et, sync_token *st) +{ + TRACE("%s\n", __FUNCTION__); + if (st != NULL) + st->engine_id = et->engine_id; + + return B_OK; +} + + +void vboxvideo_wait_engine_idle(void) +{ + TRACE("%s\n", __FUNCTION__); +} + + +status_t vboxvideo_get_sync_token(engine_token *et, sync_token *st) +{ + TRACE("%s\n", __FUNCTION__); + return B_OK; +} + + +status_t vboxvideo_sync_to_token(sync_token *st) +{ + TRACE("%s\n", __FUNCTION__); + return B_OK; +} + + +/* 2D acceleration */ +void vboxvideo_screen_to_screen_blit(engine_token *et, blit_params *list, uint32 count) +{ + TRACE("%s\n", __FUNCTION__); +} + + +void vboxvideo_fill_rectangle(engine_token *et, uint32 color, fill_rect_params *list, uint32 count) +{ + TRACE("%s\n", __FUNCTION__); +} + + +void vboxvideo_invert_rectangle(engine_token *et, fill_rect_params *list, uint32 count) +{ + TRACE("%s\n", __FUNCTION__); +} + + +void vboxvideo_fill_span(engine_token *et, uint32 color, uint16 *list, uint32 count) +{ + TRACE("%s\n", __FUNCTION__); +} diff --git a/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.h b/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.h new file mode 100644 index 00000000..735f4d2b --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.h @@ -0,0 +1,115 @@ +/* $Id: accelerant.h $ */ +/** @file + * VBoxVideo Accelerant; Haiku Guest Additions, header. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GA_INCLUDED_SRC_haiku_VBoxVideo_accelerant_accelerant_h +#define GA_INCLUDED_SRC_haiku_VBoxVideo_accelerant_accelerant_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <Accelerant.h> +#include "../common/VBoxVideo_common.h" + +struct AccelerantInfo +{ + /** @todo doxygen document these fields */ + int deviceFD; + bool isClone; + + SharedInfo *sharedInfo; + area_id sharedInfoArea; +}; +extern AccelerantInfo gInfo; + +/* General */ +status_t vboxvideo_init_accelerant(int fd); +ssize_t vboxvideo_accelerant_clone_info_size(void); +void vboxvideo_get_accelerant_clone_info(void *data); +status_t vboxvideo_clone_accelerant(void *data); +void vboxvideo_uninit_accelerant(void); +status_t vboxvideo_get_accelerant_device_info(accelerant_device_info *adi); +sem_id vboxvideo_accelerant_retrace_semaphore(void); + +/* Modes & constraints */ +uint32 vboxvideo_accelerant_mode_count(void); +status_t vboxvideo_get_mode_list(display_mode *dm); +status_t vboxvideo_set_display_mode(display_mode *modeToSet); +status_t vboxvideo_get_display_mode(display_mode *currentMode); +status_t vboxvideo_get_edid_info(void *info, size_t size, uint32 *_version); +status_t vboxvideo_get_frame_buffer_config(frame_buffer_config *config); +status_t vboxvideo_get_pixel_clock_limits(display_mode *dm, uint32 *low, uint32 *high); + +/* Cursor */ +status_t vboxvideo_set_cursor_shape(uint16 width, uint16 height, uint16 hotX, uint16 hotY, uint8 *andMask, uint8 *xorMask); +void vboxvideo_move_cursor(uint16 x, uint16 y); +void vboxvideo_show_cursor(bool is_visible); + +/* Accelerant engine */ +uint32 vboxvideo_accelerant_engine_count(void); +status_t vboxvideo_acquire_engine(uint32 capabilities, uint32 maxWait, sync_token *st, engine_token **et); +status_t vboxvideo_release_engine(engine_token *et, sync_token *st); +void vboxvideo_wait_engine_idle(void); +status_t vboxvideo_get_sync_token(engine_token *et, sync_token *st); +status_t vboxvideo_sync_to_token(sync_token *st); + +/* 2D acceleration */ +void vboxvideo_screen_to_screen_blit(engine_token *et, blit_params *list, uint32 count); +void vboxvideo_fill_rectangle(engine_token *et, uint32 color, fill_rect_params *list, uint32 count); +void vboxvideo_invert_rectangle(engine_token *et, fill_rect_params *list, uint32 count); +void vboxvideo_fill_span(engine_token *et, uint32 color, uint16 *list, uint32 count); + +#endif /* !GA_INCLUDED_SRC_haiku_VBoxVideo_accelerant_accelerant_h */ + diff --git a/src/VBox/Additions/haiku/VBoxVideo/common/VBoxVideo_common.h b/src/VBox/Additions/haiku/VBoxVideo/common/VBoxVideo_common.h new file mode 100644 index 00000000..b00bce3f --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/common/VBoxVideo_common.h @@ -0,0 +1,114 @@ +/* $Id: VBoxVideo_common.h $ */ +/** @file + * VBoxVideo, Haiku Guest Additions, common header. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GA_INCLUDED_SRC_haiku_VBoxVideo_common_VBoxVideo_common_h +#define GA_INCLUDED_SRC_haiku_VBoxVideo_common_VBoxVideo_common_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <Drivers.h> +#include <Accelerant.h> +#include <PCI.h> + +struct SharedInfo +{ + display_mode currentMode; + area_id framebufferArea; + void *framebuffer; +}; + +enum +{ + VBOXVIDEO_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1, + VBOXVIDEO_GET_DEVICE_NAME, + VBOXVIDEO_SET_DISPLAY_MODE +}; + +static inline uint32 get_color_space_for_depth(uint32 depth) +{ + switch (depth) + { + case 1: return B_GRAY1; + case 4: return B_GRAY8; + /* The app_server is smart enough to translate this to VGA mode */ + case 8: return B_CMAP8; + case 15: return B_RGB15; + case 16: return B_RGB16; + case 24: return B_RGB24; + case 32: return B_RGB32; + } + + return 0; +} + +static inline uint32 get_depth_for_color_space(uint32 depth) +{ + switch (depth) + { + case B_GRAY1: return 1; + case B_GRAY8: return 4; + case B_CMAP8: return 8; + case B_RGB15: return 15; + case B_RGB16: return 16; + case B_RGB24: return 24; + case B_RGB32: return 32; + } + return 0; +} + +#endif /* !GA_INCLUDED_SRC_haiku_VBoxVideo_common_VBoxVideo_common_h */ + diff --git a/src/VBox/Additions/haiku/VBoxVideo/driver/Makefile.kmk b/src/VBox/Additions/haiku/VBoxVideo/driver/Makefile.kmk new file mode 100644 index 00000000..b32a91b3 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/driver/Makefile.kmk @@ -0,0 +1,95 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for VBoxVideo driver, Haiku Guest Additions. +# + +# +# Copyright (C) 2012-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +# +# This code is based on: +# +# VirtualBox Guest Additions for Haiku. +# Copyright (c) 2011 Mike Smith <mike@scgtrp.net> +# François Revol <revol@free.fr> +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +SUB_DEPTH = ../../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +ifdef VBOX_WITH_ADDITION_DRIVERS + SYSMODS += vboxvideo +endif + +# +# Populate FILES_VBOXSF_NOBIN +# +#include $(PATH_SUB_CURRENT)/files_VBoxVideo + +# +# The module (for syntax checking). +# The DEBUG_HASH* stuff is for CONFIG_DYNAMIC_DEBUG-enabled kernels +# +vboxvideo_TEMPLATE = VBoxGuestR0Drv +vboxvideo_DEFS = \ + MODULE IN_RT_R0 VBOXGUEST VBOX_WITH_HGCM \ + KBUILD_MODNAME=KBUILD_STR\(VBoxVideo\) \ + KBUILD_BASENAME=KBUILD_STR\(VBoxVideo\) +vboxvideo_INCS = \ + $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuestLib \ + $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest \ + $(PATH_ROOT)/src/VBox/Runtime/r0drv/haiku \ + $(VBOX_GRAPHICS_INCS) +vboxvideo_SOURCES = \ + driver.cpp \ + $(PATH_ROOT)/src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp \ + $(PATH_ROOT)/src/VBox/Additions/common/VBoxVideo/HGSMIBuffers.cpp \ + $(PATH_ROOT)/src/VBox/Additions/common/VBoxVideo/Modesetting.cpp \ + $(PATH_ROOT)/src/VBox/Additions/common/VBoxVideo/VBVABase.cpp \ + $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest/VBoxGuest-haiku-stubs.c +vboxvideo_LIBS = \ + $(VBOX_LIB_VBGL_R0) \ + $(VBOX_PATH_ADDITIONS_LIB)/HGSMIGuestR0Lib$(VBOX_SUFF_LIB) + +include $(KBUILD_PATH)/subfooter.kmk + diff --git a/src/VBox/Additions/haiku/VBoxVideo/driver/driver.cpp b/src/VBox/Additions/haiku/VBoxVideo/driver/driver.cpp new file mode 100644 index 00000000..ce04560a --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/driver/driver.cpp @@ -0,0 +1,382 @@ +/* $Id: driver.cpp $ */ +/** @file + * VBoxVideo driver, Haiku Guest Additions, implementation. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <KernelExport.h> +#include <PCI.h> +#include <malloc.h> +#include <stdio.h> +#include <string.h> +#include <graphic_driver.h> +#include <VBoxGuest-haiku.h> +#include <VBoxVideoGuest.h> +#include "../common/VBoxVideo_common.h" + +#define VENDOR_ID 0x80ee +#define DEVICE_ID 0xbeef +#define DRIVER_NAME "VBoxVideoDriver" +#define DEVICE_FORMAT "vd_%04X_%04X_%02X%02X%02X" + +/** @todo r=ramshankar: pretty sure IPRT has something for page rounding, + * replace with IPRT version later. */ +#define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1)) + +#define ENABLE_DEBUG_TRACE + +#undef TRACE +#ifdef ENABLE_DEBUG_TRACE +#define TRACE(x...) dprintf("VBoxVideo: " x) +#else +#define TRACE(x...) ; +#endif + +int32 api_version = B_CUR_DRIVER_API_VERSION; // revision of driver API we support + +extern "C" status_t vm_set_area_memory_type(area_id id, phys_addr_t physicalBase, uint32 type); + +struct Benaphore +{ + sem_id sem; + int32 count; + + status_t Init(const char *name) + { + count = 0; + sem = create_sem(0, name); + return sem < 0 ? sem : B_OK; + } + + status_t Acquire() + { + if (atomic_add(&count, 1) > 0) + return acquire_sem(sem); + return B_OK; + } + + status_t Release() + { + if (atomic_add(&count, -1) > 1) + return release_sem(sem); + return B_OK; + } + + void Delete() + { + delete_sem(sem); + } +}; + +struct DeviceInfo +{ + uint32 openCount; /* Count of how many times device has been opened */ + uint32 flags; /* Device flags */ + area_id sharedArea; /* Area shared between driver and all accelerants */ + SharedInfo *sharedInfo; /* Pointer to shared info area memory */ + pci_info pciInfo; /* Copy of pci info for this device */ + char name[B_OS_NAME_LENGTH]; /* Name of device */ +}; + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +status_t device_open(const char *name, uint32 flags, void **cookie); +status_t device_close(void *dev); +status_t device_free(void *dev); +status_t device_read(void *dev, off_t pos, void *buf, size_t *len); +status_t device_write(void *dev, off_t pos, const void *buf, size_t *len); +status_t device_ioctl(void *dev, uint32 msg, void *buf, size_t len); +static uint32 get_color_space_for_depth(uint32 depth); + + +/********************************************************************************************************************************* +* Globals * +*********************************************************************************************************************************/ +/* At most one virtual video card ever appears, no reason for this to be an array */ +static DeviceInfo gDeviceInfo; +static char *gDeviceNames[2] = { gDeviceInfo.name, NULL }; +static bool gCanHasDevice = false; /* is the device present? */ +static Benaphore gLock; +static pci_module_info *gPCI; + +static device_hooks gDeviceHooks = +{ + device_open, + device_close, + device_free, + device_ioctl, + device_read, + device_write, + NULL, /* select */ + NULL, /* deselect */ + NULL, /* read_pages */ + NULL /* write_pages */ +}; + + +status_t init_hardware() +{ + LogFlowFunc(("init_hardware\n")); + + status_t err = get_module(VBOXGUEST_MODULE_NAME, (module_info **)&g_VBoxGuest); + if (err == B_OK) + { + err = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI); + if (err == B_OK) + return B_OK; + + LogRel((DRIVER_NAME ":_init_hardware() get_module(%s) failed. err=%08lx\n", B_PCI_MODULE_NAME)); + } + else + LogRel((DRIVER_NAME ":_init_hardware() get_module(%s) failed. err=%08lx\n", VBOXGUEST_MODULE_NAME, err)); + return B_ERROR; +} + + +status_t init_driver() +{ + LogFlowFunc(("init_driver\n")); + + gLock.Init("VBoxVideo driver lock"); + + uint32 pciIndex = 0; + + while (gPCI->get_nth_pci_info(pciIndex, &gDeviceInfo.pciInfo) == B_OK) + { + if (gDeviceInfo.pciInfo.vendor_id == VENDOR_ID && gDeviceInfo.pciInfo.device_id == DEVICE_ID) + { + sprintf(gDeviceInfo.name, "graphics/" DEVICE_FORMAT, + gDeviceInfo.pciInfo.vendor_id, gDeviceInfo.pciInfo.device_id, + gDeviceInfo.pciInfo.bus, gDeviceInfo.pciInfo.device, gDeviceInfo.pciInfo.function); + TRACE("found device %s\n", gDeviceInfo.name); + + gCanHasDevice = true; + gDeviceInfo.openCount = 0; + + size_t sharedSize = (sizeof(SharedInfo) + 7) & ~7; + gDeviceInfo.sharedArea = create_area("vboxvideo shared info", + (void **)&gDeviceInfo.sharedInfo, B_ANY_KERNEL_ADDRESS, + ROUND_TO_PAGE_SIZE(sharedSize), B_FULL_LOCK, + B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA); + + uint16_t width, height, vwidth, bpp, flags; + VBoxVideoGetModeRegisters(&width, &height, &vwidth, &bpp, &flags); + + gDeviceInfo.sharedInfo->currentMode.space = get_color_space_for_depth(bpp); + gDeviceInfo.sharedInfo->currentMode.virtual_width = width; + gDeviceInfo.sharedInfo->currentMode.virtual_height = height; + gDeviceInfo.sharedInfo->currentMode.h_display_start = 0; + gDeviceInfo.sharedInfo->currentMode.v_display_start = 0; + gDeviceInfo.sharedInfo->currentMode.flags = 0; + gDeviceInfo.sharedInfo->currentMode.timing.h_display = width; + gDeviceInfo.sharedInfo->currentMode.timing.v_display = height; + /* Not used, but this makes a reasonable-sounding refresh rate show in screen prefs: */ + gDeviceInfo.sharedInfo->currentMode.timing.h_total = 1000; + gDeviceInfo.sharedInfo->currentMode.timing.v_total = 1; + gDeviceInfo.sharedInfo->currentMode.timing.pixel_clock = 850; + + /* Map the PCI memory space */ + uint32 command_reg = gPCI->read_pci_config(gDeviceInfo.pciInfo.bus, + gDeviceInfo.pciInfo.device, gDeviceInfo.pciInfo.function, PCI_command, 2); + command_reg |= PCI_command_io | PCI_command_memory | PCI_command_master; + gPCI->write_pci_config(gDeviceInfo.pciInfo.bus, gDeviceInfo.pciInfo.device, + gDeviceInfo.pciInfo.function, PCI_command, 2, command_reg); + + gDeviceInfo.sharedInfo->framebufferArea = map_physical_memory("vboxvideo framebuffer", + (phys_addr_t)gDeviceInfo.pciInfo.u.h0.base_registers[0], + gDeviceInfo.pciInfo.u.h0.base_register_sizes[0], B_ANY_KERNEL_BLOCK_ADDRESS, + B_READ_AREA | B_WRITE_AREA, &(gDeviceInfo.sharedInfo->framebuffer)); + vm_set_area_memory_type(gDeviceInfo.sharedInfo->framebufferArea, + (phys_addr_t)gDeviceInfo.pciInfo.u.h0.base_registers[0], B_MTR_WC); + break; + } + + pciIndex++; + } + + return B_OK; +} + + +const char** publish_devices() +{ + LogFlowFunc(("publish_devices\n")); + if (gCanHasDevice) + return (const char **)gDeviceNames; + return NULL; +} + + +device_hooks* find_device(const char *name) +{ + LogFlowFunc(("find_device\n")); + if (gCanHasDevice && strcmp(name, gDeviceInfo.name) == 0) + return &gDeviceHooks; + + return NULL; +} + + +void uninit_driver() +{ + LogFlowFunc(("uninit_driver\n")); + gLock.Delete(); + put_module(VBOXGUEST_MODULE_NAME); +} + +status_t device_open(const char *name, uint32 flags, void **cookie) +{ + LogFlowFunc(("device_open\n")); + + if (!gCanHasDevice || strcmp(name, gDeviceInfo.name) != 0) + return B_BAD_VALUE; + + /** @todo init device! */ + + *cookie = (void *)&gDeviceInfo; + return B_OK; +} + + +status_t device_close(void *dev) +{ + LogFlowFunc(("device_close\n")); + return B_ERROR; +} + + +status_t device_free(void *dev) +{ + LogFlowFunc(("device_free\n")); + + DeviceInfo& di = *(DeviceInfo *)dev; + gLock.Acquire(); + + if (di.openCount <= 1) + { + /// @todo deinit device! + delete_area(di.sharedArea); + di.sharedArea = -1; + di.sharedInfo = NULL; + } + + if (di.openCount > 0) + di.openCount--; + + gLock.Release(); + + return B_OK; +} + + +status_t device_read(void *dev, off_t pos, void *buf, size_t *len) +{ + LogFlowFunc(("device_read\n")); + return B_NOT_ALLOWED; +} + + +status_t device_write(void *dev, off_t pos, const void *buf, size_t *len) +{ + LogFlowFunc(("device_write\n")); + return B_NOT_ALLOWED; +} + + +status_t device_ioctl(void *cookie, uint32 msg, void *buf, size_t len) +{ + LogFlowFunc(("device_ioctl\n")); + + DeviceInfo *dev = (DeviceInfo *)cookie; + + switch (msg) + { + case B_GET_ACCELERANT_SIGNATURE: + { + strcpy((char *)buf, "vboxvideo.accelerant"); + return B_OK; + } + + case VBOXVIDEO_GET_PRIVATE_DATA: + { + /** @todo r=ramshankar: implement RTR0MemUserCopyFrom for haiku. */ + return user_memcpy(buf, &dev->sharedArea, sizeof(area_id)); + } + + case VBOXVIDEO_GET_DEVICE_NAME: + { + /** @todo r=ramshankar: implement RTR0MemUserCopyFrom for haiku. */ + if (user_strlcpy((char *)buf, gDeviceInfo.name, len) < B_OK) + return B_BAD_ADDRESS; + return B_OK; + } + + case VBOXVIDEO_SET_DISPLAY_MODE: + { + display_mode *mode = (display_mode *)buf; + VBoxVideoSetModeRegisters(mode->timing.h_display, mode->timing.v_display, + mode->timing.h_display, get_depth_for_color_space(mode->space), 0, 0, 0); + gDeviceInfo.sharedInfo->currentMode = *mode; + return B_OK; + } + default: + return B_BAD_VALUE; + } +} + diff --git a/src/VBox/Additions/haiku/include/VBoxGuestInternal.h b/src/VBox/Additions/haiku/include/VBoxGuestInternal.h new file mode 100644 index 00000000..87adbb92 --- /dev/null +++ b/src/VBox/Additions/haiku/include/VBoxGuestInternal.h @@ -0,0 +1,74 @@ +/* $$ */ +/** @file + * VBoxGuestInternal - Private Haiku additions declarations. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * Copyright (c) 2011 Mike Smith <mike@scgtrp.net> + * François Revol <revol@free.fr> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GA_INCLUDED_HAIKU_VBoxGuestInternal_h +#define GA_INCLUDED_HAIKU_VBoxGuestInternal_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** The MIME signature of the VBoxGuest application. */ +#define VBOX_GUEST_APP_SIG "application/x-vnd.Oracle-VBoxGuest" + +/** The code used for messages sent by and to the system tray. */ +#define VBOX_GUEST_CLIPBOARD_HOST_MSG_READ_DATA 'vbC2' +#define VBOX_GUEST_CLIPBOARD_HOST_MSG_FORMATS 'vbC3' + +/** The code used for messages sent by and to the system tray. */ +#define VBOX_GUEST_APP_ACTION 'vbox' + +#endif /* !GA_INCLUDED_HAIKU_VBoxGuestInternal_h */ + diff --git a/src/VBox/Additions/haiku/include/lock.h b/src/VBox/Additions/haiku/include/lock.h new file mode 100644 index 00000000..13d2f94c --- /dev/null +++ b/src/VBox/Additions/haiku/include/lock.h @@ -0,0 +1,318 @@ +/* $Id: lock.h $ */ +/** @file + * Lock.h - Haiku, private locking internals. + */ + +/* + * Copyright (C) 2012-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * This code is based on: + * + * VirtualBox Guest Additions for Haiku. + * + * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +/** @todo r=ramshankar: Eventually this file should be shipped by Haiku and + * should be removed from the VBox tree. */ + +#ifndef GA_INCLUDED_HAIKU_lock_h +#define GA_INCLUDED_HAIKU_lock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <OS.h> + + +struct mutex_waiter; + +typedef struct mutex { + const char* name; + struct mutex_waiter* waiters; +#if KDEBUG + thread_id holder; +#else + int32 count; + uint16 ignore_unlock_count; +#endif + uint8 flags; +} mutex; + +#define MUTEX_FLAG_CLONE_NAME 0x1 + + +typedef struct recursive_lock { + mutex lock; +#if !KDEBUG + thread_id holder; +#endif + int recursion; +} recursive_lock; + + +struct rw_lock_waiter; + +typedef struct rw_lock { + const char* name; + struct rw_lock_waiter* waiters; + thread_id holder; + vint32 count; + int32 owner_count; + int16 active_readers; + // Only > 0 while a writer is waiting: number + // of active readers when the first waiting + // writer started waiting. + int16 pending_readers; + // Number of readers that have already + // incremented "count", but have not yet started + // to wait at the time the last writer unlocked. + uint32 flags; +} rw_lock; + +#define RW_LOCK_WRITER_COUNT_BASE 0x10000 + +#define RW_LOCK_FLAG_CLONE_NAME 0x1 + + +#if KDEBUG +# define KDEBUG_RW_LOCK_DEBUG 0 + // Define to 1 if you want to use ASSERT_READ_LOCKED_RW_LOCK(). + // The rw_lock will just behave like a recursive locker then. +# define ASSERT_LOCKED_RECURSIVE(r) \ + { ASSERT(find_thread(NULL) == (r)->lock.holder); } +# define ASSERT_LOCKED_MUTEX(m) { ASSERT(find_thread(NULL) == (m)->holder); } +# define ASSERT_WRITE_LOCKED_RW_LOCK(l) \ + { ASSERT(find_thread(NULL) == (l)->holder); } +# if KDEBUG_RW_LOCK_DEBUG +# define ASSERT_READ_LOCKED_RW_LOCK(l) \ + { ASSERT(find_thread(NULL) == (l)->holder); } +# else +# define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false) +# endif +#else +# define ASSERT_LOCKED_RECURSIVE(r) do {} while (false) +# define ASSERT_LOCKED_MUTEX(m) do {} while (false) +# define ASSERT_WRITE_LOCKED_RW_LOCK(m) do {} while (false) +# define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false) +#endif + + +// static initializers +#if KDEBUG +# define MUTEX_INITIALIZER(name) { name, NULL, -1, 0 } +# define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), 0 } +#else +# define MUTEX_INITIALIZER(name) { name, NULL, 0, 0, 0 } +# define RECURSIVE_LOCK_INITIALIZER(name) { MUTEX_INITIALIZER(name), -1, 0 } +#endif + +#define RW_LOCK_INITIALIZER(name) { name, NULL, -1, 0, 0, 0 } + + +#if KDEBUG +# define RECURSIVE_LOCK_HOLDER(recursiveLock) ((recursiveLock)->lock.holder) +#else +# define RECURSIVE_LOCK_HOLDER(recursiveLock) ((recursiveLock)->holder) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +extern void recursive_lock_init(recursive_lock *lock, const char *name); + // name is *not* cloned nor freed in recursive_lock_destroy() +extern void recursive_lock_init_etc(recursive_lock *lock, const char *name, + uint32 flags); +extern void recursive_lock_destroy(recursive_lock *lock); +extern status_t recursive_lock_lock(recursive_lock *lock); +extern status_t recursive_lock_trylock(recursive_lock *lock); +extern void recursive_lock_unlock(recursive_lock *lock); +extern int32 recursive_lock_get_recursion(recursive_lock *lock); + +extern void rw_lock_init(rw_lock* lock, const char* name); + // name is *not* cloned nor freed in rw_lock_destroy() +extern void rw_lock_init_etc(rw_lock* lock, const char* name, uint32 flags); +extern void rw_lock_destroy(rw_lock* lock); +extern status_t rw_lock_write_lock(rw_lock* lock); + +extern void mutex_init(mutex* lock, const char* name); + // name is *not* cloned nor freed in mutex_destroy() +extern void mutex_init_etc(mutex* lock, const char* name, uint32 flags); +extern void mutex_destroy(mutex* lock); +extern status_t mutex_switch_lock(mutex* from, mutex* to); + // Unlocks "from" and locks "to" such that unlocking and starting to wait + // for the lock is atomically. I.e. if "from" guards the object "to" belongs + // to, the operation is safe as long as "from" is held while destroying + // "to". +extern status_t mutex_switch_from_read_lock(rw_lock* from, mutex* to); + // Like mutex_switch_lock(), just for a switching from a read-locked + // rw_lock. + + +// implementation private: + +extern status_t _rw_lock_read_lock(rw_lock* lock); +extern status_t _rw_lock_read_lock_with_timeout(rw_lock* lock, + uint32 timeoutFlags, bigtime_t timeout); +extern void _rw_lock_read_unlock(rw_lock* lock, bool threadsLocked); +extern void _rw_lock_write_unlock(rw_lock* lock, bool threadsLocked); + +extern status_t _mutex_lock(mutex* lock, bool threadsLocked); +extern void _mutex_unlock(mutex* lock, bool threadsLocked); +extern status_t _mutex_trylock(mutex* lock); +extern status_t _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, + bigtime_t timeout); + + +static inline status_t +rw_lock_read_lock(rw_lock* lock) +{ +#if KDEBUG_RW_LOCK_DEBUG + return rw_lock_write_lock(lock); +#else + int32 oldCount = atomic_add(&lock->count, 1); + if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) + return _rw_lock_read_lock(lock); + return B_OK; +#endif +} + + +static inline status_t +rw_lock_read_lock_with_timeout(rw_lock* lock, uint32 timeoutFlags, + bigtime_t timeout) +{ +#if KDEBUG_RW_LOCK_DEBUG + return mutex_lock_with_timeout(lock, timeoutFlags, timeout); +#else + int32 oldCount = atomic_add(&lock->count, 1); + if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) + return _rw_lock_read_lock_with_timeout(lock, timeoutFlags, timeout); + return B_OK; +#endif +} + + +static inline void +rw_lock_read_unlock(rw_lock* lock) +{ +#if KDEBUG_RW_LOCK_DEBUG + rw_lock_write_unlock(lock); +#else + int32 oldCount = atomic_add(&lock->count, -1); + if (oldCount >= RW_LOCK_WRITER_COUNT_BASE) + _rw_lock_read_unlock(lock, false); +#endif +} + + +static inline void +rw_lock_write_unlock(rw_lock* lock) +{ + _rw_lock_write_unlock(lock, false); +} + + +static inline status_t +mutex_lock(mutex* lock) +{ +#if KDEBUG + return _mutex_lock(lock, false); +#else + if (atomic_add(&lock->count, -1) < 0) + return _mutex_lock(lock, false); + return B_OK; +#endif +} + + +static inline status_t +mutex_lock_threads_locked(mutex* lock) +{ +#if KDEBUG + return _mutex_lock(lock, true); +#else + if (atomic_add(&lock->count, -1) < 0) + return _mutex_lock(lock, true); + return B_OK; +#endif +} + + +static inline status_t +mutex_trylock(mutex* lock) +{ +#if KDEBUG + return _mutex_trylock(lock); +#else + if (atomic_test_and_set(&lock->count, -1, 0) != 0) + return B_WOULD_BLOCK; + return B_OK; +#endif +} + + +static inline status_t +mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout) +{ +#if KDEBUG + return _mutex_lock_with_timeout(lock, timeoutFlags, timeout); +#else + if (atomic_add(&lock->count, -1) < 0) + return _mutex_lock_with_timeout(lock, timeoutFlags, timeout); + return B_OK; +#endif +} + + +static inline void +mutex_unlock(mutex* lock) +{ +#if !KDEBUG + if (atomic_add(&lock->count, 1) < -1) +#endif + _mutex_unlock(lock, false); +} + + +static inline void +mutex_transfer_lock(mutex* lock, thread_id thread) +{ +#if KDEBUG + lock->holder = thread; +#endif +} + + +extern void lock_debug_init(); + +#ifdef __cplusplus +} +#endif + +#endif /* !GA_INCLUDED_HAIKU_lock_h */ diff --git a/src/VBox/Additions/haiku/load.sh b/src/VBox/Additions/haiku/load.sh new file mode 100755 index 00000000..209a55ac --- /dev/null +++ b/src/VBox/Additions/haiku/load.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# $Id: load.sh $ +## @file +# Driver load script. +# + +# +# Copyright (C) 2012-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +outdir=out/haiku.x86/debug/bin/additions +instdir=/boot/apps/VBoxAdditions + + +# vboxguest +mkdir -p ~/config/add-ons/kernel/generic/ +cp $outdir/vboxguest ~/config/add-ons/kernel/generic/ + +# vboxdev +mkdir -p ~/config/add-ons/kernel/drivers/dev/misc/ +cp $outdir/vboxdev ~/config/add-ons/kernel/drivers/bin/ +ln -sf ../../bin/vboxdev ~/config/add-ons/kernel/drivers/dev/misc + +# VBoxMouse +cp $outdir/VBoxMouse ~/config/add-ons/input_server/devices/ +cp $outdir/VBoxMouseFilter ~/config/add-ons/input_server/filters/ + +# Services +mkdir -p $instdir +cp $outdir/VBoxService $instdir/ +cp $outdir/VBoxTray $instdir/ +cp $outdir/VBoxControl $instdir/ +ln -sf $instdir/VBoxService ~/config/boot/launch + diff --git a/src/VBox/Additions/haiku/unload.sh b/src/VBox/Additions/haiku/unload.sh new file mode 100755 index 00000000..7ed68eb8 --- /dev/null +++ b/src/VBox/Additions/haiku/unload.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# $Id: unload.sh $ +## @file +# Driver unload script. +# + +# +# Copyright (C) 2012-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +basedir=/boot/home/config/add-ons/ +rm -f $basedir/input_server/devices/VBoxMouse +rm -f $basedir/kernel/drivers/bin/vboxdev +rm -f $basedir/kernel/drivers/dev/misc/vboxdev +rm -f $basedir/kernel/file_systems/vboxsf +rm -f $basedir/kernel/generic/vboxguest +rm -rf /boot/apps/VBoxAdditions + |