diff options
Diffstat (limited to 'src/VBox/Additions/haiku/VBoxVideo')
7 files changed, 1248 insertions, 0 deletions
diff --git a/src/VBox/Additions/haiku/VBoxVideo/Makefile.kmk b/src/VBox/Additions/haiku/VBoxVideo/Makefile.kmk new file mode 100644 index 00000000..b806095a --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/Makefile.kmk @@ -0,0 +1,54 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for Haiku VBoxVideo. +# + +# +# Copyright (C) 2012-2019 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# + +# +# 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..04949103 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/accelerant/Makefile.kmk @@ -0,0 +1,65 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for VBoxVideo accelerant, Haiku Guest Additions. +# + +# +# Copyright (C) 2012-2019 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# + +# +# 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..29c46439 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.cpp @@ -0,0 +1,463 @@ +/* $Id: accelerant.cpp $ */ +/** @file + * VBoxVideo Accelerant; Haiku Guest Additions, implementation. + */ + +/* + * Copyright (C) 2012-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/* + * 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..7c3f2185 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/accelerant/accelerant.h @@ -0,0 +1,105 @@ +/* $Id: accelerant.h $ */ +/** @file + * VBoxVideo Accelerant; Haiku Guest Additions, header. + */ + +/* + * Copyright (C) 2012-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/* + * 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..04811181 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/common/VBoxVideo_common.h @@ -0,0 +1,104 @@ +/* $Id: VBoxVideo_common.h $ */ +/** @file + * VBoxVideo, Haiku Guest Additions, common header. + */ + +/* + * Copyright (C) 2012-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/* + * 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..c37a31fc --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/driver/Makefile.kmk @@ -0,0 +1,85 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for VBoxVideo driver, Haiku Guest Additions. +# + +# +# Copyright (C) 2012-2019 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# + +# +# 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 = VBOXGUESTR0 +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..981ea727 --- /dev/null +++ b/src/VBox/Additions/haiku/VBoxVideo/driver/driver.cpp @@ -0,0 +1,372 @@ +/* $Id: driver.cpp $ */ +/** @file + * VBoxVideo driver, Haiku Guest Additions, implementation. + */ + +/* + * Copyright (C) 2012-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/* + * 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; + } +} + |