diff --git a/src/add-ons/accelerants/Jamfile b/src/add-ons/accelerants/Jamfile index 805d6edf95..db7e0a1358 100644 --- a/src/add-ons/accelerants/Jamfile +++ b/src/add-ons/accelerants/Jamfile @@ -4,6 +4,7 @@ SubInclude HAIKU_TOP src add-ons accelerants 3dfx ; SubInclude HAIKU_TOP src add-ons accelerants ati ; SubInclude HAIKU_TOP src add-ons accelerants common ; SubInclude HAIKU_TOP src add-ons accelerants et6x00 ; +SubInclude HAIKU_TOP src add-ons accelerants framebuffer ; SubInclude HAIKU_TOP src add-ons accelerants intel_810 ; SubInclude HAIKU_TOP src add-ons accelerants intel_extreme ; SubInclude HAIKU_TOP src add-ons accelerants matrox ; diff --git a/src/add-ons/accelerants/framebuffer/Jamfile b/src/add-ons/accelerants/framebuffer/Jamfile new file mode 100644 index 0000000000..e60738fa7f --- /dev/null +++ b/src/add-ons/accelerants/framebuffer/Jamfile @@ -0,0 +1,13 @@ +SubDir HAIKU_TOP src add-ons accelerants framebuffer ; + +UsePrivateHeaders graphics ; +UsePrivateHeaders [ FDirName graphics vesa ] ; +UsePrivateHeaders [ FDirName graphics common ] ; + +Addon framebuffer.accelerant : + accelerant.cpp + engine.cpp + hooks.cpp + mode.cpp + : libaccelerantscommon.a +; diff --git a/src/add-ons/accelerants/framebuffer/accelerant.cpp b/src/add-ons/accelerants/framebuffer/accelerant.cpp new file mode 100644 index 0000000000..c90999af87 --- /dev/null +++ b/src/add-ons/accelerants/framebuffer/accelerant.cpp @@ -0,0 +1,249 @@ +/* + * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com. + * Distributed under the terms of the MIT License. + */ + + +#include "accelerant_protos.h" +#include "accelerant.h" + +#include +#include +#include +#include +#include + + +//#define TRACE_ACCELERANT +#ifdef TRACE_ACCELERANT +extern "C" void _sPrintf(const char *format, ...); +# define TRACE(x) _sPrintf x +#else +# define TRACE(x) ; +#endif + + +struct accelerant_info *gInfo; + + +class AreaCloner { + public: + AreaCloner(); + ~AreaCloner(); + + area_id Clone(const char *name, void **_address, uint32 spec, + uint32 protection, area_id sourceArea); + status_t InitCheck() { return fArea < B_OK ? (status_t)fArea : B_OK; } + void Keep(); + + private: + area_id fArea; +}; + + +AreaCloner::AreaCloner() + : + fArea(-1) +{ +} + + +AreaCloner::~AreaCloner() +{ + if (fArea >= B_OK) + delete_area(fArea); +} + + +area_id +AreaCloner::Clone(const char *name, void **_address, uint32 spec, + uint32 protection, area_id sourceArea) +{ + fArea = clone_area(name, _address, spec, protection, sourceArea); + return fArea; +} + + +void +AreaCloner::Keep() +{ + fArea = -1; +} + + +// #pragma mark - + + +/*! This is the common accelerant_info initializer. It is called by + both, the first accelerant and all clones. +*/ +static status_t +init_common(int device, bool isClone) +{ + // initialize global accelerant info structure + + gInfo = (accelerant_info *)malloc(sizeof(accelerant_info)); + if (gInfo == NULL) + return B_NO_MEMORY; + + memset(gInfo, 0, sizeof(accelerant_info)); + + gInfo->is_clone = isClone; + gInfo->device = device; + gInfo->current_mode = UINT16_MAX; + + // get basic info from driver + + area_id sharedArea; + if (ioctl(device, VESA_GET_PRIVATE_DATA, &sharedArea, sizeof(area_id)) + != 0) { + free(gInfo); + return B_ERROR; + } + + AreaCloner sharedCloner; + gInfo->shared_info_area = sharedCloner.Clone("framebuffer shared info", + (void **)&gInfo->shared_info, B_ANY_ADDRESS, + B_READ_AREA | B_WRITE_AREA, sharedArea); + status_t status = sharedCloner.InitCheck(); + if (status < B_OK) { + free(gInfo); + return status; + } + + sharedCloner.Keep(); + return B_OK; +} + + +/*! Cleans up everything done by a successful init_common(). */ +static void +uninit_common(void) +{ + delete_area(gInfo->shared_info_area); + gInfo->shared_info_area = -1; + gInfo->shared_info = NULL; + + // close the file handle ONLY if we're the clone + // (this is what Be tells us ;) + if (gInfo->is_clone) + close(gInfo->device); + + free(gInfo); +} + + +// #pragma mark - public accelerant functions + + +/*! Init primary accelerant */ +status_t +framebuffer_init_accelerant(int device) +{ + TRACE(("framebuffer_init_accelerant()\n")); + + status_t status = init_common(device, false); + if (status != B_OK) + return status; + + status = create_mode_list(); + if (status != B_OK) { + uninit_common(); + return status; + } + + return B_OK; +} + + +ssize_t +framebuffer_accelerant_clone_info_size(void) +{ + // clone info is device name, so return its maximum size + return B_PATH_NAME_LENGTH; +} + + +void +framebuffer_get_accelerant_clone_info(void *info) +{ + ioctl(gInfo->device, VESA_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH); +} + + +status_t +framebuffer_clone_accelerant(void *info) +{ + TRACE(("framebuffer_clone_accelerant()\n")); + + // create full device name + char path[MAXPATHLEN]; + strcpy(path, "/dev/"); + strcat(path, (const char *)info); + + int fd = open(path, B_READ_WRITE); + if (fd < 0) + return errno; + + status_t status = init_common(fd, true); + if (status != B_OK) + goto err1; + + // get read-only clone of supported display modes + status = gInfo->mode_list_area = clone_area( + "framebuffer cloned modes", (void **)&gInfo->mode_list, + B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area); + if (status < B_OK) + goto err2; + + return B_OK; + +err2: + uninit_common(); +err1: + close(fd); + return status; +} + + +/*! This function is called for both, the primary accelerant and all of + its clones. +*/ +void +framebuffer_uninit_accelerant(void) +{ + TRACE(("framebuffer_uninit_accelerant()\n")); + + // delete accelerant instance data + delete_area(gInfo->mode_list_area); + gInfo->mode_list = NULL; + + uninit_common(); +} + + +status_t +framebuffer_get_accelerant_device_info(accelerant_device_info *info) +{ + info->version = B_ACCELERANT_VERSION; + strcpy(info->name, "Framebuffer Driver"); + strcpy(info->chipset, "Framebuffer"); + // ToDo: provide some more insight here... + strcpy(info->serial_no, "None"); + +#if 0 + info->memory = ??? + info->dac_speed = ??? +#endif + + return B_OK; +} + + +sem_id +framebuffer_accelerant_retrace_semaphore() +{ + return -1; +} + diff --git a/src/add-ons/accelerants/framebuffer/accelerant.h b/src/add-ons/accelerants/framebuffer/accelerant.h new file mode 100644 index 0000000000..f49c88a3db --- /dev/null +++ b/src/add-ons/accelerants/framebuffer/accelerant.h @@ -0,0 +1,30 @@ +/* + * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com. + * Distributed under the terms of the MIT License. + */ +#ifndef VESA_ACCELERANT_H +#define VESA_ACCELERANT_H + + +#include "vesa_info.h" + + +typedef struct accelerant_info { + int device; + bool is_clone; + + area_id shared_info_area; + vesa_shared_info *shared_info; + + area_id mode_list_area; + // cloned list of standard display modes + display_mode *mode_list; + uint16 current_mode; +} accelerant_info; + +extern accelerant_info *gInfo; + +extern status_t create_mode_list(void); + +#endif /* VESA_ACCELERANT_H */ diff --git a/src/add-ons/accelerants/framebuffer/accelerant_protos.h b/src/add-ons/accelerants/framebuffer/accelerant_protos.h new file mode 100644 index 0000000000..5382891037 --- /dev/null +++ b/src/add-ons/accelerants/framebuffer/accelerant_protos.h @@ -0,0 +1,49 @@ +/* + * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com. + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef _ACCELERANT_PROTOS_H +#define _ACCELERANT_PROTOS_H + + +#include +#include "video_overlay.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +// general +status_t framebuffer_init_accelerant(int fd); +ssize_t framebuffer_accelerant_clone_info_size(void); +void framebuffer_get_accelerant_clone_info(void *data); +status_t framebuffer_clone_accelerant(void *data); +void framebuffer_uninit_accelerant(void); +status_t framebuffer_get_accelerant_device_info(accelerant_device_info *adi); +sem_id framebuffer_accelerant_retrace_semaphore(void); + +// modes & constraints +uint32 framebuffer_accelerant_mode_count(void); +status_t framebuffer_get_mode_list(display_mode *dm); +status_t framebuffer_set_display_mode(display_mode *modeToSet); +status_t framebuffer_get_display_mode(display_mode *currentMode); +status_t framebuffer_get_frame_buffer_config(frame_buffer_config *config); +status_t framebuffer_get_pixel_clock_limits(display_mode *dm, uint32 *low, + uint32 *high); + +// accelerant engine +uint32 framebuffer_accelerant_engine_count(void); +status_t framebuffer_acquire_engine(uint32 capabilities, uint32 maxWait, + sync_token *st, engine_token **et); +status_t framebuffer_release_engine(engine_token *et, sync_token *st); +void framebuffer_wait_engine_idle(void); +status_t framebuffer_get_sync_token(engine_token *et, sync_token *st); +status_t framebuffer_sync_to_token(sync_token *st); + +#ifdef __cplusplus +} +#endif + +#endif /* _ACCELERANT_PROTOS_H */ diff --git a/src/add-ons/accelerants/framebuffer/engine.cpp b/src/add-ons/accelerants/framebuffer/engine.cpp new file mode 100644 index 0000000000..988640bba4 --- /dev/null +++ b/src/add-ons/accelerants/framebuffer/engine.cpp @@ -0,0 +1,59 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "accelerant_protos.h" +#include "vesa_info.h" + + +static engine_token sEngineToken = {1, 0 /*B_2D_ACCELERATION*/, NULL}; + + +uint32 +framebuffer_accelerant_engine_count(void) +{ + return 1; +} + + +status_t +framebuffer_acquire_engine(uint32 capabilities, uint32 max_wait, sync_token *syncToken, + engine_token **_engineToken) +{ + *_engineToken = &sEngineToken; + + return B_OK; +} + + +status_t +framebuffer_release_engine(engine_token *engineToken, sync_token *syncToken) +{ + if (syncToken != NULL) + syncToken->engine_id = engineToken->engine_id; + + return B_OK; +} + + +void +framebuffer_wait_engine_idle(void) +{ +} + + +status_t +framebuffer_get_sync_token(engine_token *engineToken, sync_token *syncToken) +{ + return B_OK; +} + + +status_t +framebuffer_sync_to_token(sync_token *syncToken) +{ + return B_OK; +} + diff --git a/src/add-ons/accelerants/framebuffer/hooks.cpp b/src/add-ons/accelerants/framebuffer/hooks.cpp new file mode 100644 index 0000000000..65477fc611 --- /dev/null +++ b/src/add-ons/accelerants/framebuffer/hooks.cpp @@ -0,0 +1,65 @@ +/* + * Copyright 2005-2012, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +#include "accelerant_protos.h" +#include "accelerant.h" + +#include + + +extern "C" void* +get_accelerant_hook(uint32 feature, void* data) +{ + switch (feature) { + /* general */ + case B_INIT_ACCELERANT: + return (void*)framebuffer_init_accelerant; + case B_UNINIT_ACCELERANT: + return (void*)framebuffer_uninit_accelerant; + case B_CLONE_ACCELERANT: + return (void*)framebuffer_clone_accelerant; + case B_ACCELERANT_CLONE_INFO_SIZE: + return (void*)framebuffer_accelerant_clone_info_size; + case B_GET_ACCELERANT_CLONE_INFO: + return (void*)framebuffer_get_accelerant_clone_info; + case B_GET_ACCELERANT_DEVICE_INFO: + return (void*)framebuffer_get_accelerant_device_info; + case B_ACCELERANT_RETRACE_SEMAPHORE: + return (void*)framebuffer_accelerant_retrace_semaphore; + + /* mode configuration */ + case B_ACCELERANT_MODE_COUNT: + return (void*)framebuffer_accelerant_mode_count; + case B_GET_MODE_LIST: + return (void*)framebuffer_get_mode_list; + case B_SET_DISPLAY_MODE: + return (void*)framebuffer_set_display_mode; + case B_GET_DISPLAY_MODE: + return (void*)framebuffer_get_display_mode; + case B_GET_FRAME_BUFFER_CONFIG: + return (void*)framebuffer_get_frame_buffer_config; + case B_GET_PIXEL_CLOCK_LIMITS: + return (void*)framebuffer_get_pixel_clock_limits; + + /* engine/synchronization */ + case B_ACCELERANT_ENGINE_COUNT: + return (void*)framebuffer_accelerant_engine_count; + case B_ACQUIRE_ENGINE: + return (void*)framebuffer_acquire_engine; + case B_RELEASE_ENGINE: + return (void*)framebuffer_release_engine; + case B_WAIT_ENGINE_IDLE: + return (void*)framebuffer_wait_engine_idle; + case B_GET_SYNC_TOKEN: + return (void*)framebuffer_get_sync_token; + case B_SYNC_TO_TOKEN: + return (void*)framebuffer_sync_to_token; + } + + return NULL; +} + diff --git a/src/add-ons/accelerants/framebuffer/mode.cpp b/src/add-ons/accelerants/framebuffer/mode.cpp new file mode 100644 index 0000000000..476a2b7754 --- /dev/null +++ b/src/add-ons/accelerants/framebuffer/mode.cpp @@ -0,0 +1,147 @@ +/* + * Copyright 2005-2015, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + +#include +#include + +#include "accelerant_protos.h" +#include "accelerant.h" +#include "utility.h" + + +//#define TRACE_MODE +#ifdef TRACE_MODE +extern "C" void _sPrintf(const char* format, ...); +# define TRACE(x) _sPrintf x +#else +# define TRACE(x) ; +#endif + + +bool +operator==(const display_mode &lhs, const display_mode &rhs) +{ + return lhs.space == rhs.space + && lhs.virtual_width == rhs.virtual_width + && lhs.virtual_height == rhs.virtual_height + && lhs.h_display_start == rhs.h_display_start + && lhs.v_display_start == rhs.v_display_start; +} + + +/*! Checks if the specified \a mode can be set using VESA. */ +static bool +is_mode_supported(display_mode* mode) +{ + return (mode != NULL) && (*mode == gInfo->shared_info->current_mode); +} + + +/*! Creates the initial mode list of the primary accelerant. + It's called from vesa_init_accelerant(). +*/ +status_t +create_mode_list(void) +{ + const color_space colorspace[] = { + (color_space)gInfo->shared_info->current_mode.space + }; + display_mode mode = gInfo->shared_info->current_mode; + + compute_display_timing(mode.virtual_width, mode.virtual_height, 60, false, + &mode.timing); + fill_display_mode(mode.virtual_width, mode.virtual_height, &mode); + + gInfo->mode_list_area = create_display_modes("framebuffer modes", + NULL, &mode, 1, colorspace, 1, is_mode_supported, &gInfo->mode_list, + &gInfo->shared_info->mode_count); + + if (gInfo->mode_list_area < 0) + return gInfo->mode_list_area; + + gInfo->shared_info->mode_list_area = gInfo->mode_list_area; + return B_OK; +} + + +// #pragma mark - + + +uint32 +framebuffer_accelerant_mode_count(void) +{ + TRACE(("framebuffer_accelerant_mode_count() = %d\n", + gInfo->shared_info->mode_count)); + return gInfo->shared_info->mode_count; +} + + +status_t +framebuffer_get_mode_list(display_mode* modeList) +{ + TRACE(("framebuffer_get_mode_info()\n")); + memcpy(modeList, gInfo->mode_list, + gInfo->shared_info->mode_count * sizeof(display_mode)); + return B_OK; +} + + +status_t +framebuffer_set_display_mode(display_mode* _mode) +{ + TRACE(("framebuffer_set_display_mode()\n")); + if (_mode != NULL && *_mode == gInfo->shared_info->current_mode) + return B_OK; + + return B_UNSUPPORTED; +} + + +status_t +framebuffer_get_display_mode(display_mode* _currentMode) +{ + TRACE(("framebuffer_get_display_mode()\n")); + *_currentMode = gInfo->shared_info->current_mode; + return B_OK; +} + + +status_t +framebuffer_get_frame_buffer_config(frame_buffer_config* config) +{ + TRACE(("framebuffer_get_frame_buffer_config()\n")); + + config->frame_buffer = gInfo->shared_info->frame_buffer; + config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer; + config->bytes_per_row = gInfo->shared_info->bytes_per_row; + + return B_OK; +} + + +status_t +framebuffer_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high) +{ + TRACE(("framebuffer_get_pixel_clock_limits()\n")); + + // TODO: do some real stuff here (taken from radeon driver) + uint32 totalPixel = (uint32)mode->timing.h_total + * (uint32)mode->timing.v_total; + uint32 clockLimit = 2000000; + + // lower limit of about 48Hz vertical refresh + *_low = totalPixel * 48L / 1000L; + if (*_low > clockLimit) + return B_ERROR; + + *_high = clockLimit; + return B_OK; +} + diff --git a/src/add-ons/kernel/drivers/graphics/Jamfile b/src/add-ons/kernel/drivers/graphics/Jamfile index e1a282a73f..07d24ace4d 100644 --- a/src/add-ons/kernel/drivers/graphics/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/Jamfile @@ -4,6 +4,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers graphics 3dfx ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics ati ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics common ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics et6x00 ; +SubInclude HAIKU_TOP src add-ons kernel drivers graphics framebuffer ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics intel_810 ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics intel_extreme ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics matrox ; diff --git a/src/add-ons/kernel/drivers/graphics/framebuffer/Jamfile b/src/add-ons/kernel/drivers/graphics/framebuffer/Jamfile new file mode 100644 index 0000000000..8ad432401c --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/framebuffer/Jamfile @@ -0,0 +1,12 @@ +SubDir HAIKU_TOP src add-ons kernel drivers graphics framebuffer ; + +UsePrivateHeaders [ FDirName graphics common ] ; +UsePrivateHeaders [ FDirName graphics vesa ] ; +UsePrivateKernelHeaders ; + +KernelAddon framebuffer : + device.cpp + driver.cpp + framebuffer.cpp + ; + diff --git a/src/add-ons/kernel/drivers/graphics/framebuffer/device.cpp b/src/add-ons/kernel/drivers/graphics/framebuffer/device.cpp new file mode 100644 index 0000000000..914f35c306 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/framebuffer/device.cpp @@ -0,0 +1,166 @@ +/* + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com. + * Distributed under the terms of the MIT License. + */ + + +#include "device.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "driver.h" +#include "utility.h" +#include "vesa_info.h" +#include "framebuffer_private.h" + + +//#define TRACE_DEVICE +#ifdef TRACE_DEVICE +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +static status_t +device_open(const char* name, uint32 flags, void** _cookie) +{ + int id; + + // find accessed device + char* thisName; + + // search for device name + for (id = 0; (thisName = gDeviceNames[id]) != NULL; id++) { + if (!strcmp(name, thisName)) + break; + } + if (thisName == NULL) + return B_BAD_VALUE; + + framebuffer_info* info = gDeviceInfo[id]; + + mutex_lock(&gLock); + + status_t status = B_OK; + + if (info->open_count == 0) { + // this device has been opened for the first time, so + // we allocate needed resources and initialize the structure + if (status == B_OK) + status = framebuffer_init(*info); + if (status == B_OK) + info->id = id; + } + + if (status == B_OK) { + info->open_count++; + *_cookie = info; + } + + mutex_unlock(&gLock); + return status; +} + + +static status_t +device_close(void* cookie) +{ + return B_OK; +} + + +static status_t +device_free(void* cookie) +{ + struct framebuffer_info* info = (framebuffer_info*)cookie; + + mutex_lock(&gLock); + + if (info->open_count-- == 1) { + // release info structure + framebuffer_uninit(*info); + } + + mutex_unlock(&gLock); + return B_OK; +} + + +static status_t +device_ioctl(void* cookie, uint32 msg, void* buffer, size_t bufferLength) +{ + struct framebuffer_info* info = (framebuffer_info*)cookie; + + switch (msg) { + case B_GET_ACCELERANT_SIGNATURE: + dprintf(DEVICE_NAME ": acc: %s\n", ACCELERANT_NAME); + if (user_strlcpy((char*)buffer, ACCELERANT_NAME, + B_FILE_NAME_LENGTH) < B_OK) + return B_BAD_ADDRESS; + + return B_OK; + + // needed to share data between kernel and accelerant + case VESA_GET_PRIVATE_DATA: + return user_memcpy(buffer, &info->shared_area, sizeof(area_id)); + + // needed for cloning + case VESA_GET_DEVICE_NAME: + if (user_strlcpy((char*)buffer, gDeviceNames[info->id], + B_PATH_NAME_LENGTH) < B_OK) + return B_BAD_ADDRESS; + + return B_OK; + + default: + TRACE((DEVICE_NAME ": ioctl() unknown message %ld (length = %lu)\n", + msg, bufferLength)); + break; + } + + return B_DEV_INVALID_IOCTL; +} + + +static status_t +device_read(void* /*cookie*/, off_t /*pos*/, void* /*buffer*/, size_t* _length) +{ + *_length = 0; + return B_NOT_ALLOWED; +} + + +static status_t +device_write(void* /*cookie*/, off_t /*pos*/, const void* /*buffer*/, + size_t* _length) +{ + *_length = 0; + return B_NOT_ALLOWED; +} + + +device_hooks gDeviceHooks = { + device_open, + device_close, + device_free, + device_ioctl, + device_read, + device_write, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/add-ons/kernel/drivers/graphics/framebuffer/device.h b/src/add-ons/kernel/drivers/graphics/framebuffer/device.h new file mode 100644 index 0000000000..9ce0264531 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/framebuffer/device.h @@ -0,0 +1,13 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef DEVICE_H +#define DEVICE_H + +#include + +// The device hooks for the published device +extern device_hooks gDeviceHooks; + +#endif /* DEVICE_H */ diff --git a/src/add-ons/kernel/drivers/graphics/framebuffer/driver.cpp b/src/add-ons/kernel/drivers/graphics/framebuffer/driver.cpp new file mode 100644 index 0000000000..54332d996c --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/framebuffer/driver.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "driver.h" +#include "device.h" + + +#define TRACE_DRIVER +#ifdef TRACE_DRIVER +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + +#define MAX_CARDS 1 + + +int32 api_version = B_CUR_DRIVER_API_VERSION; + +char* gDeviceNames[MAX_CARDS + 1]; +framebuffer_info* gDeviceInfo[MAX_CARDS]; +mutex gLock; + + +extern "C" const char** +publish_devices(void) +{ + TRACE((DEVICE_NAME ": publish_devices()\n")); + return (const char**)gDeviceNames; +} + + +extern "C" status_t +init_hardware(void) +{ + TRACE((DEVICE_NAME ": init_hardware()\n")); + + // If we don't have a VESA mode list, then we are a dumb + // framebuffer, e.g. when there are no drivers available + // on a UEFI system. + return (get_boot_item(VESA_MODES_BOOT_INFO, NULL) == NULL + && get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL) != NULL) + ? B_OK : B_ERROR; +} + + +extern "C" status_t +init_driver(void) +{ + TRACE((DEVICE_NAME ": init_driver()\n")); + + gDeviceInfo[0] = (framebuffer_info*)malloc(sizeof(framebuffer_info)); + if (gDeviceInfo[0] == NULL) + return B_NO_MEMORY; + + memset(gDeviceInfo[0], 0, sizeof(framebuffer_info)); + + gDeviceNames[0] = strdup("graphics/framebuffer"); + if (gDeviceNames[0] == NULL) { + free(gDeviceNames[0]); + return B_NO_MEMORY; + } + + gDeviceNames[1] = NULL; + + mutex_init(&gLock, "framebuffer lock"); + return B_OK; +} + + +extern "C" void +uninit_driver(void) +{ + TRACE((DEVICE_NAME ": uninit_driver()\n")); + + mutex_destroy(&gLock); + + // free device related structures + char* name; + for (int32 index = 0; (name = gDeviceNames[index]) != NULL; index++) { + free(gDeviceInfo[index]); + free(name); + } +} + + +extern "C" device_hooks* +find_device(const char* name) +{ + int index; + + TRACE((DEVICE_NAME ": find_device()\n")); + + for (index = 0; gDeviceNames[index] != NULL; index++) { + if (!strcmp(name, gDeviceNames[index])) + return &gDeviceHooks; + } + + return NULL; +} + diff --git a/src/add-ons/kernel/drivers/graphics/framebuffer/driver.h b/src/add-ons/kernel/drivers/graphics/framebuffer/driver.h new file mode 100644 index 0000000000..c9ac172d64 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/framebuffer/driver.h @@ -0,0 +1,22 @@ +/* + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com. + * Distributed under the terms of the MIT License. + */ +#ifndef DRIVER_H +#define DRIVER_H + + +#include +#include + +#include + +#include "framebuffer_private.h" + + +extern char* gDeviceNames[]; +extern framebuffer_info* gDeviceInfo[]; +extern mutex gLock; + +#endif /* DRIVER_H */ diff --git a/src/add-ons/kernel/drivers/graphics/framebuffer/framebuffer.cpp b/src/add-ons/kernel/drivers/graphics/framebuffer/framebuffer.cpp new file mode 100644 index 0000000000..e732f1c5a8 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/framebuffer/framebuffer.cpp @@ -0,0 +1,202 @@ +/* + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com. + * Distributed under the terms of the MIT License. + */ + + +#include "framebuffer_private.h" +#include "vesa.h" + +#include + +#include + +#include +#include +#include +#include + +#include "driver.h" +#include "utility.h" +#include "vesa_info.h" + + +static status_t +find_graphics_card(addr_t frameBuffer, addr_t& base, size_t& size) +{ + // TODO: when we port this over to the new driver API, this mechanism can be + // used to find the right device_node + pci_module_info* pci; + if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci) != B_OK) + return B_ERROR; + + pci_info info; + for (int32 index = 0; pci->get_nth_pci_info(index, &info) == B_OK; index++) { + if (info.class_base != PCI_display) + continue; + + // check PCI BARs + for (uint32 i = 0; i < 6; i++) { + if (info.u.h0.base_registers[i] <= frameBuffer + && info.u.h0.base_registers[i] + info.u.h0.base_register_sizes[i] + > frameBuffer) { + // found it! + base = info.u.h0.base_registers[i]; + size = info.u.h0.base_register_sizes[i]; + + put_module(B_PCI_MODULE_NAME); + return B_OK; + } + } + } + + put_module(B_PCI_MODULE_NAME); + return B_ENTRY_NOT_FOUND; +} + + +static 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; +} + + +/*! Remaps the frame buffer if necessary; if we've already mapped the complete + frame buffer, there is no need to map it again. +*/ +static status_t +remap_frame_buffer(framebuffer_info& info, addr_t physicalBase, uint32 width, + uint32 height, int8 depth, uint32 bytesPerRow, bool initializing) +{ + vesa_shared_info& sharedInfo = *info.shared_info; + addr_t frameBuffer = info.frame_buffer; + + if (!info.complete_frame_buffer_mapped) { + addr_t base = physicalBase; + size_t size = bytesPerRow * height; + bool remap = !initializing; + + if (info.physical_frame_buffer_size != 0) { + // we can map the complete frame buffer + base = info.physical_frame_buffer; + size = info.physical_frame_buffer_size; + remap = true; + } + + if (remap) { + area_id area = map_physical_memory("framebuffer buffer", base, + size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, + (void**)&frameBuffer); + if (area < 0) + return area; + + if (initializing) { + // We need to manually update the kernel's frame buffer address, + // since this frame buffer remapping has not been issued by the + // app_server (which would otherwise take care of this) + frame_buffer_update(frameBuffer, width, height, depth, + bytesPerRow); + } + + delete_area(info.shared_info->frame_buffer_area); + + info.frame_buffer = frameBuffer; + sharedInfo.frame_buffer_area = area; + + // Turn on write combining for the area + vm_set_area_memory_type(area, base, B_MTR_WC); + + if (info.physical_frame_buffer_size != 0) + info.complete_frame_buffer_mapped = true; + } + } + + if (info.complete_frame_buffer_mapped) + frameBuffer += physicalBase - info.physical_frame_buffer; + + // Update shared frame buffer information + sharedInfo.frame_buffer = (uint8*)frameBuffer; + sharedInfo.physical_frame_buffer = (uint8*)physicalBase; + sharedInfo.bytes_per_row = bytesPerRow; + + return B_OK; +} + + +// #pragma mark - + + +status_t +framebuffer_init(framebuffer_info& info) +{ + frame_buffer_boot_info* bufferInfo + = (frame_buffer_boot_info*)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL); + if (bufferInfo == NULL) + return B_ERROR; + + info.complete_frame_buffer_mapped = false; + + // Find out which PCI device we belong to, so that we know its frame buffer + // size + find_graphics_card(bufferInfo->physical_frame_buffer, + info.physical_frame_buffer, info.physical_frame_buffer_size); + + size_t sharedSize = (sizeof(vesa_shared_info) + 7) & ~7; + + info.shared_area = create_area("framebuffer shared info", + (void**)&info.shared_info, B_ANY_KERNEL_ADDRESS, + ROUND_TO_PAGE_SIZE(sharedSize), B_FULL_LOCK, + B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_USER_CLONEABLE_AREA); + if (info.shared_area < 0) + return info.shared_area; + + vesa_shared_info& sharedInfo = *info.shared_info; + + memset(&sharedInfo, 0, sizeof(vesa_shared_info)); + + sharedInfo.frame_buffer_area = bufferInfo->area; + + remap_frame_buffer(info, bufferInfo->physical_frame_buffer, + bufferInfo->width, bufferInfo->height, bufferInfo->depth, + bufferInfo->bytes_per_row, true); + // Does not matter if this fails - the frame buffer was already mapped + // before. + + sharedInfo.current_mode.virtual_width = bufferInfo->width; + sharedInfo.current_mode.virtual_height = bufferInfo->height; + sharedInfo.current_mode.space = get_color_space_for_depth( + bufferInfo->depth); + + dprintf(DEVICE_NAME ": framebuffer_init() completed successfully!\n"); + return B_OK; +} + + +void +framebuffer_uninit(framebuffer_info& info) +{ + dprintf(DEVICE_NAME": framebuffer_uninit()\n"); + + delete_area(info.shared_info->frame_buffer_area); + delete_area(info.shared_area); +} diff --git a/src/add-ons/kernel/drivers/graphics/framebuffer/framebuffer_private.h b/src/add-ons/kernel/drivers/graphics/framebuffer/framebuffer_private.h new file mode 100644 index 0000000000..4de5bf4bda --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/framebuffer/framebuffer_private.h @@ -0,0 +1,35 @@ +/* + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com. + * Distributed under the terms of the MIT License. + */ +#ifndef VESA_PRIVATE_H +#define VESA_PRIVATE_H + + +#include +#include +#include + + +#define DEVICE_NAME "framebuffer" +#define ACCELERANT_NAME "framebuffer.accelerant" + + +struct framebuffer_info { + uint32 cookie_magic; + int32 open_count; + int32 id; + struct vesa_shared_info* shared_info; + area_id shared_area; + + addr_t frame_buffer; + addr_t physical_frame_buffer; + size_t physical_frame_buffer_size; + bool complete_frame_buffer_mapped; +}; + +extern status_t framebuffer_init(framebuffer_info& info); +extern void framebuffer_uninit(framebuffer_info& info); + +#endif /* VESA_PRIVATE_H */