Bring back the framebuffer driver and accelerant.

This reverts commit 72fc5e6a71.

They were removed because app_server often picked them instead of
a better graphics driver, and fallbacks merged into VESA instead.
That seems to have created more problems than it solved, in the long run,
and so the intent now is to change app_server to understand the
framebuffer driver as a fallback one instead.

Change-Id: I6edd97fb29ed2b9c13c6c540569695c8426ecfd7
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4614
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Augustin Cavalier 2021-10-19 18:43:48 -04:00 committed by waddlesplash
parent b7a1261eef
commit f7bd3509e3
16 changed files with 1182 additions and 0 deletions

View File

@ -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 ;

View File

@ -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
;

View File

@ -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 <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <syslog.h>
//#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;
}

View File

@ -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 */

View File

@ -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 <Accelerant.h>
#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 */

View File

@ -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;
}

View File

@ -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 <new>
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;
}

View File

@ -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 <stdlib.h>
#include <string.h>
#include <compute_display_timing.h>
#include <create_display_modes.h>
#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;
}

View File

@ -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 ;

View File

@ -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
;

View File

@ -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 <stdlib.h>
#include <string.h>
#include <Drivers.h>
#include <graphic_driver.h>
#include <image.h>
#include <KernelExport.h>
#include <OS.h>
#include <PCI.h>
#include <SupportDefs.h>
#include <vesa.h>
#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
};

View File

@ -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 <Drivers.h>
// The device hooks for the published device
extern device_hooks gDeviceHooks;
#endif /* DEVICE_H */

View File

@ -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 <OS.h>
#include <KernelExport.h>
#include <SupportDefs.h>
#include <PCI.h>
#include <frame_buffer_console.h>
#include <boot_item.h>
#include <vesa_info.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#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;
}

View File

@ -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 <ISA.h>
#include <KernelExport.h>
#include <lock.h>
#include "framebuffer_private.h"
extern char* gDeviceNames[];
extern framebuffer_info* gDeviceInfo[];
extern mutex gLock;
#endif /* DRIVER_H */

View File

@ -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 <string.h>
#include <drivers/bios.h>
#include <boot_item.h>
#include <frame_buffer_console.h>
#include <util/kernel_cpp.h>
#include <vm/vm.h>
#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);
}

View File

@ -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 <Drivers.h>
#include <Accelerant.h>
#include <PCI.h>
#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 */