driver: New intel 810 video driver
* Introduced by Gerald Zajac in #8615 * Will need reviewed, tested, and some style cleanup * Not in images until steps above complete
This commit is contained in:
parent
9c02217342
commit
e0ee3b7971
110
headers/private/graphics/intel_810/DriverInterface.h
Normal file
110
headers/private/graphics/intel_810/DriverInterface.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2007-2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#ifndef DRIVERINTERFACE_H
|
||||
#define DRIVERINTERFACE_H
|
||||
|
||||
|
||||
#include <Accelerant.h>
|
||||
#include <GraphicsDefs.h>
|
||||
#include <Drivers.h>
|
||||
#include <edid.h>
|
||||
|
||||
|
||||
// This file contains info that is shared between the kernel driver and the
|
||||
// accelerant, and info that is shared among the source files of the
|
||||
// accelerant.
|
||||
|
||||
|
||||
#define ENABLE_DEBUG_TRACE // if defined, turns on debug output to syslog
|
||||
|
||||
|
||||
#define ARRAY_SIZE(a) (int(sizeof(a) / sizeof(a[0]))) // get number of elements in an array
|
||||
|
||||
|
||||
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); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum {
|
||||
INTEL_GET_SHARED_DATA = B_DEVICE_OP_CODES_END + 234,
|
||||
INTEL_DEVICE_NAME,
|
||||
INTEL_GET_EDID,
|
||||
};
|
||||
|
||||
|
||||
struct DisplayModeEx : display_mode {
|
||||
uint8 bitsPerPixel;
|
||||
uint8 bytesPerPixel;
|
||||
uint16 bytesPerRow; // number of bytes in one line/row
|
||||
};
|
||||
|
||||
|
||||
struct SharedInfo {
|
||||
// Device ID info.
|
||||
uint16 vendorID; // PCI vendor ID, from pci_info
|
||||
uint16 deviceID; // PCI device ID, from pci_info
|
||||
uint8 revision; // PCI device revsion, from pci_info
|
||||
char chipName[32]; // user recognizable name of chip
|
||||
|
||||
bool bAccelerantInUse; // true = accelerant has been initialized
|
||||
|
||||
// Memory mappings.
|
||||
area_id regsArea; // area_id for the memory mapped registers. It will
|
||||
// be cloned into accelerant's address space.
|
||||
area_id videoMemArea; // video memory area_id. Addr's shared with all teams.
|
||||
addr_t videoMemAddr; // virtual video memory addr
|
||||
phys_addr_t videoMemPCI; // physical video memory addr
|
||||
uint32 videoMemSize; // video memory size in bytes (for frame buffer).
|
||||
|
||||
uint32 maxFrameBufferSize; // max available video memory for frame buffer
|
||||
|
||||
// Color spaces supported by current video chip/driver.
|
||||
color_space colorSpaces[6];
|
||||
uint32 colorSpaceCount; // number of color spaces in array colorSpaces
|
||||
|
||||
// List of screen modes.
|
||||
area_id modeArea; // area containing list of display modes the driver supports
|
||||
uint32 modeCount; // number of display modes in the list
|
||||
|
||||
DisplayModeEx displayMode; // current display mode configuration
|
||||
|
||||
edid1_info edidInfo;
|
||||
bool bHaveEDID; // true = EDID info from device is in edidInfo
|
||||
|
||||
Benaphore engineLock; // for serializing access to the acceleration engine
|
||||
};
|
||||
|
||||
|
||||
#endif // DRIVERINTERFACE_H
|
@ -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 intel_810 ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants intel_extreme ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants matrox ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants neomagic ;
|
||||
|
19
src/add-ons/accelerants/intel_810/Jamfile
Normal file
19
src/add-ons/accelerants/intel_810/Jamfile
Normal file
@ -0,0 +1,19 @@
|
||||
SubDir HAIKU_TOP src add-ons accelerants intel_810 ;
|
||||
|
||||
UsePrivateHeaders graphics ;
|
||||
UsePrivateHeaders [ FDirName graphics intel_810 ] ;
|
||||
UsePrivateHeaders [ FDirName graphics common ] ;
|
||||
|
||||
Addon intel_810.accelerant :
|
||||
accelerant.cpp
|
||||
engine.cpp
|
||||
hooks.cpp
|
||||
mode.cpp
|
||||
|
||||
i810_dpms.cpp
|
||||
i810_init.cpp
|
||||
i810_mode.cpp
|
||||
i810_watermark.cpp
|
||||
|
||||
: be libaccelerantscommon.a
|
||||
;
|
236
src/add-ons/accelerants/intel_810/accelerant.cpp
Normal file
236
src/add-ons/accelerants/intel_810/accelerant.cpp
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright 2007-2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
AccelerantInfo gInfo; // global data used by source files of accelerant
|
||||
|
||||
static uint32 videoValue;
|
||||
|
||||
|
||||
static int32
|
||||
SuppressArtifacts(void* dataPtr)
|
||||
{
|
||||
// The Intel 810 & 815 video chips create annoying artifacts which are
|
||||
// most noticeable when the cursor is moved by itself or the user goes up
|
||||
// and down through a menu. However, if a large number of video memory
|
||||
// locations are accessed frequently like when the GLTeapot demo is
|
||||
// running, the artifacts are greatly suppressed. Thus, that is the reason
|
||||
// why this function accesses a large number of video memory locations
|
||||
// frequently. Note that the accessed memory locations are at the end of
|
||||
// the video memory. This is because some artifacts still occur at the
|
||||
// top of the screen if the accessed memory is at the beginning of the
|
||||
// video memory.
|
||||
|
||||
// Note that this function will reduce the general performance of a
|
||||
// computer somewhat, but it is much less of a hit than if double
|
||||
// buffering was used for the video. Base on the frame rate of the
|
||||
// the GLTeapot demo, it is less than a 10% reduction.
|
||||
|
||||
SharedInfo& si = *((SharedInfo*)dataPtr);
|
||||
|
||||
while (true)
|
||||
{
|
||||
uint32* src = ((uint32*)(si.videoMemAddr)) + si.videoMemSize / 4 - 1;
|
||||
uint32 count = 65000;
|
||||
|
||||
while (count-- > 0)
|
||||
videoValue = *src--;
|
||||
|
||||
snooze(30000); // sleep for 30 msec
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
InitCommon(int fileDesc)
|
||||
{
|
||||
// Initialization function used by primary and cloned accelerants.
|
||||
|
||||
gInfo.deviceFileDesc = fileDesc;
|
||||
|
||||
// Get area ID of shared data from driver.
|
||||
|
||||
area_id sharedArea;
|
||||
status_t result = ioctl(gInfo.deviceFileDesc, INTEL_GET_SHARED_DATA,
|
||||
&sharedArea, sizeof(sharedArea));
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
gInfo.sharedInfoArea = clone_area("i810 shared info",
|
||||
(void**)&(gInfo.sharedInfo), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
|
||||
sharedArea);
|
||||
if (gInfo.sharedInfoArea < 0)
|
||||
return gInfo.sharedInfoArea; // sharedInfoArea has error code
|
||||
|
||||
gInfo.regsArea = clone_area("i810 regs area", (void**)&(gInfo.regs),
|
||||
B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, gInfo.sharedInfo->regsArea);
|
||||
if (gInfo.regsArea < 0) {
|
||||
delete_area(gInfo.sharedInfoArea);
|
||||
return gInfo.regsArea; // regsArea has error code
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
UninitCommon(void)
|
||||
{
|
||||
// This function is used by both primary and cloned accelerants.
|
||||
|
||||
delete_area(gInfo.regsArea);
|
||||
gInfo.regs = 0;
|
||||
|
||||
delete_area(gInfo.sharedInfoArea);
|
||||
gInfo.sharedInfo = 0;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
InitAccelerant(int fileDesc)
|
||||
{
|
||||
// Initialize the accelerant. fileDesc is the file handle of the device
|
||||
// (in /dev/graphics) that has been opened by the app_server.
|
||||
|
||||
TRACE("Enter InitAccelerant()\n");
|
||||
|
||||
gInfo.bAccelerantIsClone = false; // indicate this is primary accelerant
|
||||
|
||||
status_t result = InitCommon(fileDesc);
|
||||
if (result == B_OK) {
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
TRACE("Vendor ID: 0x%X, Device ID: 0x%X\n", si.vendorID, si.deviceID);
|
||||
|
||||
// Ensure that InitAccelerant is executed just once (copies should be
|
||||
// clones)
|
||||
|
||||
if (si.bAccelerantInUse) {
|
||||
result = B_NOT_ALLOWED;
|
||||
} else {
|
||||
result = I810_Init(); // perform init related to current chip
|
||||
if (result == B_OK) {
|
||||
result = si.engineLock.Init("i810 engine lock");
|
||||
if (result == B_OK) {
|
||||
// Ensure that this function won't be executed again
|
||||
// (copies should be clones)
|
||||
si.bAccelerantInUse = true;
|
||||
|
||||
thread_id threadID = spawn_thread(SuppressArtifacts,
|
||||
"SuppressArtifacts_Thread", B_DISPLAY_PRIORITY,
|
||||
gInfo.sharedInfo);
|
||||
result = resume_thread(threadID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result != B_OK)
|
||||
UninitCommon();
|
||||
}
|
||||
|
||||
TRACE("Leave InitAccelerant(), result: 0x%X\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
AccelerantCloneInfoSize(void)
|
||||
{
|
||||
// Return the number of bytes required to hold the information required
|
||||
// to clone the device. The information is merely the name of the device;
|
||||
// thus, return the size of the name buffer.
|
||||
|
||||
return B_OS_NAME_LENGTH;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GetAccelerantCloneInfo(void* data)
|
||||
{
|
||||
// Return the info required to clone the device. Argument data points to
|
||||
// a buffer which is the size returned by AccelerantCloneInfoSize().
|
||||
|
||||
ioctl(gInfo.deviceFileDesc, INTEL_DEVICE_NAME, data, B_OS_NAME_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CloneAccelerant(void* data)
|
||||
{
|
||||
// Initialize a copy of the accelerant as a clone. Argument data points to
|
||||
// a copy of the data which was returned by GetAccelerantCloneInfo().
|
||||
|
||||
TRACE("Enter CloneAccelerant()\n");
|
||||
|
||||
char path[MAXPATHLEN] = "/dev/";
|
||||
strcat(path, (const char*)data);
|
||||
|
||||
gInfo.deviceFileDesc = open(path, B_READ_WRITE); // open the device
|
||||
if (gInfo.deviceFileDesc < 0)
|
||||
return errno;
|
||||
|
||||
gInfo.bAccelerantIsClone = true;
|
||||
|
||||
status_t result = InitCommon(gInfo.deviceFileDesc);
|
||||
if (result != B_OK) {
|
||||
close(gInfo.deviceFileDesc);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = gInfo.modeListArea = clone_area("i810 cloned display_modes",
|
||||
(void**) &gInfo.modeList, B_ANY_ADDRESS, B_READ_AREA,
|
||||
gInfo.sharedInfo->modeArea);
|
||||
if (result < 0) {
|
||||
UninitCommon();
|
||||
close(gInfo.deviceFileDesc);
|
||||
return result;
|
||||
}
|
||||
|
||||
TRACE("Leave CloneAccelerant()\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UninitAccelerant(void)
|
||||
{
|
||||
delete_area(gInfo.modeListArea);
|
||||
gInfo.modeList = NULL;
|
||||
|
||||
UninitCommon();
|
||||
|
||||
if (gInfo.bAccelerantIsClone)
|
||||
close(gInfo.deviceFileDesc);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetAccelerantDeviceInfo(accelerant_device_info* adi)
|
||||
{
|
||||
// Get info about the device.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
adi->version = 1;
|
||||
strcpy(adi->name, "Intel 810/815 chipset");
|
||||
strcpy(adi->chipset, si.chipName);
|
||||
strcpy(adi->serial_no, "unknown");
|
||||
adi->memory = si.maxFrameBufferSize;
|
||||
adi->dac_speed = 270;
|
||||
|
||||
return B_OK;
|
||||
}
|
117
src/add-ons/accelerants/intel_810/accelerant.h
Normal file
117
src/add-ons/accelerants/intel_810/accelerant.h
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2007-2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#ifndef _ACCELERANT_H
|
||||
#define _ACCELERANT_H
|
||||
|
||||
#include "DriverInterface.h"
|
||||
|
||||
|
||||
|
||||
#undef TRACE
|
||||
|
||||
#ifdef ENABLE_DEBUG_TRACE
|
||||
extern "C" void _sPrintf(const char* format, ...);
|
||||
# define TRACE(x...) _sPrintf("i810: " x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
|
||||
|
||||
// Global data used by various source files of the accelerant.
|
||||
|
||||
struct AccelerantInfo {
|
||||
int deviceFileDesc; // file descriptor of kernel driver
|
||||
|
||||
SharedInfo* sharedInfo; // address of info shared between
|
||||
// accelerants & driver
|
||||
area_id sharedInfoArea; // shared info area ID
|
||||
|
||||
uint8* regs; // base address of MMIO register area
|
||||
area_id regsArea; // MMIO register area ID
|
||||
|
||||
display_mode* modeList; // list of standard display modes
|
||||
area_id modeListArea; // mode list area ID
|
||||
|
||||
bool bAccelerantIsClone; // true if this is a cloned accelerant
|
||||
};
|
||||
|
||||
extern AccelerantInfo gInfo;
|
||||
|
||||
|
||||
// Prototypes of the interface functions called by the app_server. Note that
|
||||
// the functions that are unique to a particular chip family, will be prefixed
|
||||
// with the name of the family, and the functions that are applicable to all
|
||||
// chips will have no prefix.
|
||||
//================================================================
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// General
|
||||
status_t InitAccelerant(int fd);
|
||||
ssize_t AccelerantCloneInfoSize(void);
|
||||
void GetAccelerantCloneInfo(void* data);
|
||||
status_t CloneAccelerant(void* data);
|
||||
void UninitAccelerant(void);
|
||||
status_t GetAccelerantDeviceInfo(accelerant_device_info* adi);
|
||||
|
||||
// Mode Configuration
|
||||
uint32 AccelerantModeCount(void);
|
||||
status_t GetModeList(display_mode* dm);
|
||||
status_t ProposeDisplayMode(display_mode* target, const display_mode* low,
|
||||
const display_mode* high);
|
||||
status_t SetDisplayMode(display_mode* mode_to_set);
|
||||
status_t GetDisplayMode(display_mode* current_mode);
|
||||
status_t GetFrameBufferConfig(frame_buffer_config* a_frame_buffer);
|
||||
status_t GetPixelClockLimits(display_mode* dm, uint32* low, uint32* high);
|
||||
status_t MoveDisplay(uint16 h_display_start, uint16 v_display_start);
|
||||
void I810_SetIndexedColors(uint count, uint8 first, uint8* color_data,
|
||||
uint32 flags);
|
||||
status_t GetEdidInfo(void* info, size_t size, uint32* _version);
|
||||
|
||||
// DPMS
|
||||
uint32 I810_DPMSCapabilities(void);
|
||||
uint32 I810_GetDPMSMode(void);
|
||||
status_t I810_SetDPMSMode(uint32 dpms_flags);
|
||||
|
||||
// Engine Management
|
||||
uint32 AccelerantEngineCount(void);
|
||||
status_t AcquireEngine(uint32 capabilities, uint32 max_wait, sync_token* st,
|
||||
engine_token** et);
|
||||
status_t ReleaseEngine(engine_token* et, sync_token* st);
|
||||
void WaitEngineIdle(void);
|
||||
status_t GetSyncToken(engine_token* et, sync_token* st);
|
||||
status_t SyncToToken(sync_token* st);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Prototypes for other functions that are called from source files other than
|
||||
// where they are defined.
|
||||
//============================================================================
|
||||
|
||||
status_t CreateModeList(bool (*checkMode)(const display_mode* mode));
|
||||
bool IsModeUsable(const display_mode* mode);
|
||||
|
||||
// Intel 810 functions.
|
||||
|
||||
status_t I810_Init(void);
|
||||
bool I810_GetColorSpaceParams(int colorSpace, uint8& bpp,
|
||||
uint32& maxPixelClk);
|
||||
uint32 I810_GetWatermark(const DisplayModeEx& mode);
|
||||
|
||||
void I810_AdjustFrame(const DisplayModeEx& mode);
|
||||
status_t I810_SetDisplayMode(const DisplayModeEx& mode);
|
||||
|
||||
|
||||
#endif // _ACCELERANT_H
|
81
src/add-ons/accelerants/intel_810/engine.cpp
Normal file
81
src/add-ons/accelerants/intel_810/engine.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2007-2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "i810_regs.h"
|
||||
|
||||
|
||||
static engine_token sEngineToken = { 1, B_2D_ACCELERATION, NULL };
|
||||
|
||||
|
||||
uint32
|
||||
AccelerantEngineCount(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AcquireEngine(uint32 capabilities, uint32 maxWait,
|
||||
sync_token* syncToken, engine_token** engineToken)
|
||||
{
|
||||
(void)capabilities; // avoid compiler warning for unused arg
|
||||
(void)maxWait; // avoid compiler warning for unused arg
|
||||
|
||||
if (gInfo.sharedInfo->engineLock.Acquire() != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
if (syncToken)
|
||||
SyncToToken(syncToken);
|
||||
|
||||
*engineToken = &sEngineToken;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ReleaseEngine(engine_token* engineToken, sync_token* syncToken)
|
||||
{
|
||||
if (syncToken)
|
||||
GetSyncToken(engineToken, syncToken);
|
||||
|
||||
gInfo.sharedInfo->engineLock.Release();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WaitEngineIdle(void)
|
||||
{
|
||||
// Wait until engine is idle.
|
||||
|
||||
int k = 10000000;
|
||||
|
||||
while ((INREG16(INST_DONE) & 0x7B) != 0x7B && k > 0)
|
||||
k--;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetSyncToken(engine_token* engineToken, sync_token* syncToken)
|
||||
{
|
||||
syncToken->engine_id = engineToken->engine_id;
|
||||
syncToken->counter = 0;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SyncToToken(sync_token* syncToken)
|
||||
{
|
||||
(void)syncToken; // avoid compiler warning for unused arg
|
||||
|
||||
WaitEngineIdle();
|
||||
return B_OK;
|
||||
}
|
||||
|
84
src/add-ons/accelerants/intel_810/hooks.cpp
Normal file
84
src/add-ons/accelerants/intel_810/hooks.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2008-2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
|
||||
extern "C" void*
|
||||
get_accelerant_hook(uint32 feature, void* data)
|
||||
{
|
||||
(void)data; // avoid compiler warning for unused arg
|
||||
|
||||
switch (feature) {
|
||||
// General
|
||||
case B_INIT_ACCELERANT:
|
||||
return (void*)InitAccelerant;
|
||||
case B_UNINIT_ACCELERANT:
|
||||
return (void*)UninitAccelerant;
|
||||
case B_CLONE_ACCELERANT:
|
||||
return (void*)CloneAccelerant;
|
||||
case B_ACCELERANT_CLONE_INFO_SIZE:
|
||||
return (void*)AccelerantCloneInfoSize;
|
||||
case B_GET_ACCELERANT_CLONE_INFO:
|
||||
return (void*)GetAccelerantCloneInfo;
|
||||
case B_GET_ACCELERANT_DEVICE_INFO:
|
||||
return (void*)GetAccelerantDeviceInfo;
|
||||
case B_ACCELERANT_RETRACE_SEMAPHORE:
|
||||
return NULL;
|
||||
|
||||
// Mode Configuration
|
||||
case B_ACCELERANT_MODE_COUNT:
|
||||
return (void*)AccelerantModeCount;
|
||||
case B_GET_MODE_LIST:
|
||||
return (void*)GetModeList;
|
||||
case B_PROPOSE_DISPLAY_MODE:
|
||||
return (void*)ProposeDisplayMode;
|
||||
case B_SET_DISPLAY_MODE:
|
||||
return (void*)SetDisplayMode;
|
||||
case B_GET_DISPLAY_MODE:
|
||||
return (void*)GetDisplayMode;
|
||||
#ifdef __HAIKU__
|
||||
case B_GET_EDID_INFO:
|
||||
return (void*)GetEdidInfo;
|
||||
#endif
|
||||
case B_GET_FRAME_BUFFER_CONFIG:
|
||||
return (void*)GetFrameBufferConfig;
|
||||
case B_GET_PIXEL_CLOCK_LIMITS:
|
||||
return (void*)GetPixelClockLimits;
|
||||
case B_MOVE_DISPLAY:
|
||||
return (void*)MoveDisplay;
|
||||
case B_SET_INDEXED_COLORS:
|
||||
return (void*)(I810_SetIndexedColors);
|
||||
case B_GET_TIMING_CONSTRAINTS:
|
||||
return NULL;
|
||||
|
||||
// DPMS
|
||||
case B_DPMS_CAPABILITIES:
|
||||
return (void*)(I810_DPMSCapabilities);
|
||||
case B_DPMS_MODE:
|
||||
return (void*)(I810_GetDPMSMode);
|
||||
case B_SET_DPMS_MODE:
|
||||
return (void*)(I810_SetDPMSMode);
|
||||
|
||||
// Engine Management
|
||||
case B_ACCELERANT_ENGINE_COUNT:
|
||||
return (void*)AccelerantEngineCount;
|
||||
case B_ACQUIRE_ENGINE:
|
||||
return (void*)AcquireEngine;
|
||||
case B_RELEASE_ENGINE:
|
||||
return (void*)ReleaseEngine;
|
||||
case B_WAIT_ENGINE_IDLE:
|
||||
return (void*)WaitEngineIdle;
|
||||
case B_GET_SYNC_TOKEN:
|
||||
return (void*)GetSyncToken;
|
||||
case B_SYNC_TO_TOKEN:
|
||||
return (void*)SyncToToken;
|
||||
}
|
||||
|
||||
return NULL; // Return null pointer for any feature not handled above
|
||||
}
|
101
src/add-ons/accelerants/intel_810/i810_dpms.cpp
Normal file
101
src/add-ons/accelerants/intel_810/i810_dpms.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
/*!
|
||||
Haiku Intel-810 video driver was adapted from the X.org intel driver which
|
||||
has the following copyright.
|
||||
|
||||
Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
All Rights Reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "i810_regs.h"
|
||||
|
||||
|
||||
#define DPMS_SYNC_SELECT 0x5002
|
||||
#define H_SYNC_OFF 0x02
|
||||
#define V_SYNC_OFF 0x08
|
||||
|
||||
|
||||
uint32
|
||||
I810_DPMSCapabilities(void)
|
||||
{
|
||||
// Return DPMS modes supported by this device.
|
||||
|
||||
return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
I810_GetDPMSMode(void)
|
||||
{
|
||||
// Return the current DPMS mode.
|
||||
|
||||
uint32 tmp = INREG8(DPMS_SYNC_SELECT) & (H_SYNC_OFF | V_SYNC_OFF);
|
||||
uint32 mode;
|
||||
|
||||
if (tmp == 0 )
|
||||
mode = B_DPMS_ON;
|
||||
else if (tmp == H_SYNC_OFF)
|
||||
mode = B_DPMS_STAND_BY;
|
||||
else if (tmp == V_SYNC_OFF)
|
||||
mode = B_DPMS_SUSPEND;
|
||||
else
|
||||
mode = B_DPMS_OFF;
|
||||
|
||||
TRACE("I810_DPMSMode() mode: %d\n", mode);
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
I810_SetDPMSMode(uint32 dpmsMode)
|
||||
{
|
||||
// Set the display into one of the Display Power Management modes,
|
||||
// and return B_OK if successful, else return B_ERROR.
|
||||
|
||||
TRACE("I810_SetDPMSMode() mode: %d\n", dpmsMode);
|
||||
|
||||
uint8 seq01 = ReadSeqReg(1) & ~0x20;
|
||||
uint8 dpmsSyncSelect = 0;
|
||||
|
||||
switch (dpmsMode) {
|
||||
case B_DPMS_ON:
|
||||
// Screen: On; HSync: On, VSync: On.
|
||||
break;
|
||||
|
||||
case B_DPMS_STAND_BY:
|
||||
// Screen: Off; HSync: Off, VSync: On.
|
||||
seq01 |= 0x20;
|
||||
dpmsSyncSelect = H_SYNC_OFF;
|
||||
break;
|
||||
|
||||
case B_DPMS_SUSPEND:
|
||||
// Screen: Off; HSync: On, VSync: Off.
|
||||
seq01 |= 0x20;
|
||||
dpmsSyncSelect = V_SYNC_OFF;
|
||||
break;
|
||||
|
||||
case B_DPMS_OFF:
|
||||
// Screen: Off; HSync: Off, VSync: Off.
|
||||
seq01 |= 0x20;
|
||||
dpmsSyncSelect = H_SYNC_OFF | V_SYNC_OFF;
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE("Invalid DPMS mode %d\n", dpmsMode);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
WriteSeqReg(1, seq01); // turn the screen on/off
|
||||
OUTREG8(DPMS_SYNC_SELECT, dpmsSyncSelect); // set DPMS mode
|
||||
|
||||
return B_OK;
|
||||
}
|
70
src/add-ons/accelerants/intel_810/i810_init.cpp
Normal file
70
src/add-ons/accelerants/intel_810/i810_init.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
/*!
|
||||
Haiku Intel-810 video driver was adapted from the X.org intel driver which
|
||||
has the following copyright.
|
||||
|
||||
Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
All Rights Reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "i810_regs.h"
|
||||
|
||||
|
||||
|
||||
bool
|
||||
I810_GetColorSpaceParams(int colorSpace, uint8& bitsPerPixel,
|
||||
uint32& maxPixelClock)
|
||||
{
|
||||
// Get parameters for a color space which is supported by the i810 chips.
|
||||
// Argument maxPixelClock is in KHz.
|
||||
// Return true if the color space is supported; else return false.
|
||||
|
||||
switch (colorSpace) {
|
||||
case B_RGB16:
|
||||
bitsPerPixel = 16;
|
||||
maxPixelClock = 163000;
|
||||
break;
|
||||
break;
|
||||
case B_CMAP8:
|
||||
bitsPerPixel = 8;
|
||||
maxPixelClock = 203000;
|
||||
break;
|
||||
default:
|
||||
TRACE("Unsupported color space: 0x%X\n", colorSpace);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
I810_Init(void)
|
||||
{
|
||||
TRACE("I810_Init()\n");
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
// Use all of video memory for the frame buffer.
|
||||
|
||||
si.maxFrameBufferSize = si.videoMemSize;
|
||||
|
||||
// Set up the array of the supported color spaces.
|
||||
|
||||
si.colorSpaces[0] = B_CMAP8;
|
||||
si.colorSpaces[1] = B_RGB16;
|
||||
si.colorSpaceCount = 2;
|
||||
|
||||
// Setup the mode list.
|
||||
|
||||
return CreateModeList(IsModeUsable);
|
||||
}
|
288
src/add-ons/accelerants/intel_810/i810_mode.cpp
Normal file
288
src/add-ons/accelerants/intel_810/i810_mode.cpp
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright 2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
/*!
|
||||
Haiku Intel-810 video driver was adapted from the X.org intel driver which
|
||||
has the following copyright.
|
||||
|
||||
Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "i810_regs.h"
|
||||
|
||||
#include <create_display_modes.h> // common accelerant header file
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
// I810_CalcVCLK -- Determine closest clock frequency to the one requested.
|
||||
|
||||
#define MAX_VCO_FREQ 600.0
|
||||
#define TARGET_MAX_N 30
|
||||
#define REF_FREQ 24.0
|
||||
|
||||
#define CALC_VCLK(m,n,p) (double)m / ((double)n * (1 << p)) * 4 * REF_FREQ
|
||||
|
||||
static void
|
||||
CalcVCLK(double freq, uint16& clkM, uint16& clkN, uint16& clkP) {
|
||||
int m, n, p;
|
||||
double f_out, f_best;
|
||||
double f_err;
|
||||
double f_vco;
|
||||
int m_best = 0, n_best = 0, p_best = 0;
|
||||
double f_target = freq;
|
||||
double errMax = 0.005;
|
||||
double errTarget = 0.001;
|
||||
double errBest = 999999.0;
|
||||
|
||||
p_best = p = int(log(MAX_VCO_FREQ / f_target) / log((double)2));
|
||||
// Make sure p is within range.
|
||||
if (p_best > 5) {
|
||||
p_best = p = 5;
|
||||
}
|
||||
|
||||
f_vco = f_target * (1 << p);
|
||||
|
||||
n = 2;
|
||||
do {
|
||||
n++;
|
||||
m = int(f_vco / (REF_FREQ / (double)n) / (double)4.0 + 0.5);
|
||||
if (m < 3)
|
||||
m = 3;
|
||||
f_out = CALC_VCLK(m, n, p);
|
||||
f_err = 1.0 - (f_target / f_out);
|
||||
if (fabs(f_err) < errMax) {
|
||||
m_best = m;
|
||||
n_best = n;
|
||||
f_best = f_out;
|
||||
errBest = f_err;
|
||||
}
|
||||
} while ((fabs(f_err) >= errTarget) &&
|
||||
((n <= TARGET_MAX_N) || (fabs(errBest) > errMax)));
|
||||
|
||||
if (fabs(f_err) < errTarget) {
|
||||
m_best = m;
|
||||
n_best = n;
|
||||
}
|
||||
|
||||
clkM = (m_best - 2) & 0x3FF;
|
||||
clkN = (n_best - 2) & 0x3FF;
|
||||
clkP = (p_best << 4);
|
||||
|
||||
TRACE("Setting dot clock to %.1f MHz [ 0x%x 0x%x 0x%x ] [ %d %d %d ]\n",
|
||||
CALC_VCLK(m_best, n_best, p_best),
|
||||
clkM, clkN, clkP, m_best, n_best, p_best);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
SetCrtcTimingValues(const DisplayModeEx& mode)
|
||||
{
|
||||
// Set the timing values for CRTC registers cr00 to cr18, and some extended
|
||||
// CRTC registers.
|
||||
|
||||
int hTotal = mode.timing.h_total / 8 - 5;
|
||||
int hDisp_e = mode.timing.h_display / 8 - 1;
|
||||
int hSync_s = mode.timing.h_sync_start / 8;
|
||||
int hSync_e = mode.timing.h_sync_end / 8;
|
||||
int hBlank_s = hDisp_e + 1; // start of horizontal blanking
|
||||
int hBlank_e = hTotal; // end of horizontal blanking
|
||||
|
||||
int vTotal = mode.timing.v_total - 2;
|
||||
int vDisp_e = mode.timing.v_display - 1;
|
||||
int vSync_s = mode.timing.v_sync_start;
|
||||
int vSync_e = mode.timing.v_sync_end;
|
||||
int vBlank_s = vDisp_e; // start of vertical blanking
|
||||
int vBlank_e = vTotal; // end of vertical blanking
|
||||
|
||||
uint16 offset = mode.bytesPerRow / 8;
|
||||
|
||||
// CRTC Controller values
|
||||
|
||||
uint8 crtc[25];
|
||||
crtc[0x00] = hTotal;
|
||||
crtc[0x01] = hDisp_e;
|
||||
crtc[0x02] = hBlank_s;
|
||||
crtc[0x03] = (hBlank_e & 0x1f) | 0x80;
|
||||
crtc[0x04] = hSync_s;
|
||||
crtc[0x05] = ((hSync_e & 0x1f) | ((hBlank_e & 0x20) << 2));
|
||||
crtc[0x06] = vTotal;
|
||||
crtc[0x07] = (((vTotal & 0x100) >> 8)
|
||||
| ((vDisp_e & 0x100) >> 7)
|
||||
| ((vSync_s & 0x100) >> 6)
|
||||
| ((vBlank_s & 0x100) >> 5)
|
||||
| 0x10
|
||||
| ((vTotal & 0x200) >> 4)
|
||||
| ((vDisp_e & 0x200) >> 3)
|
||||
| ((vSync_s & 0x200) >> 2));
|
||||
|
||||
crtc[0x08] = 0x00;
|
||||
crtc[0x09] = ((vBlank_s & 0x200) >> 4) | 0x40;
|
||||
crtc[0x0a] = 0x00;
|
||||
crtc[0x0b] = 0x00;
|
||||
crtc[0x0c] = 0x00;
|
||||
crtc[0x0d] = 0x00;
|
||||
crtc[0x0e] = 0x00;
|
||||
crtc[0x0f] = 0x00;
|
||||
crtc[0x10] = vSync_s;
|
||||
crtc[0x11] = (vSync_e & 0x0f) | 0x20;
|
||||
crtc[0x12] = vDisp_e;
|
||||
crtc[0x13] = offset;
|
||||
crtc[0x14] = 0x00;
|
||||
crtc[0x15] = vBlank_s;
|
||||
crtc[0x16] = vBlank_e;
|
||||
crtc[0x17] = 0xc3;
|
||||
crtc[0x18] = 0xff;
|
||||
|
||||
// Set the standard CRTC vga regs; however, before setting them, unlock
|
||||
// CRTC reg's 0-7 by clearing bit 7 of cr11
|
||||
|
||||
WriteCrtcReg(0x11, crtc[0x11] & ~0x80);
|
||||
|
||||
for (uint8 j = 0; j <= 0x18; j++)
|
||||
WriteCrtcReg(j, crtc[j]);
|
||||
|
||||
// Set the extended CRTC reg's.
|
||||
|
||||
WriteCrtcReg(EXT_VERT_TOTAL, vTotal >> 8);
|
||||
WriteCrtcReg(EXT_VERT_DISPLAY, vDisp_e >> 8);
|
||||
WriteCrtcReg(EXT_VERT_SYNC_START, vSync_s >> 8);
|
||||
WriteCrtcReg(EXT_VERT_BLANK_START, vBlank_s >> 8);
|
||||
WriteCrtcReg(EXT_HORIZ_TOTAL, hTotal >> 8);
|
||||
WriteCrtcReg(EXT_HORIZ_BLANK, (hBlank_e & 0x40) >> 6);
|
||||
WriteCrtcReg(EXT_OFFSET, offset >> 8);
|
||||
|
||||
WriteCrtcReg(INTERLACE_CNTL, INTERLACE_DISABLE); // turn off interlace
|
||||
|
||||
// Enable high resolution mode.
|
||||
WriteCrtcReg(IO_CTNL, ReadCrtcReg(IO_CTNL) | EXTENDED_CRTC_CNTL);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
I810_SetDisplayMode(const DisplayModeEx& mode)
|
||||
{
|
||||
if (mode.bitsPerPixel != 8 && mode.bitsPerPixel != 16) {
|
||||
// Only 8 & 16 bits/pixel are suppoted.
|
||||
TRACE("Unsupported color depth: %d bpp\n", mode.bitsPerPixel);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
snooze(50000);
|
||||
|
||||
// Turn off DRAM refresh.
|
||||
uint8 temp = INREG8(DRAM_ROW_CNTL_HI) & ~DRAM_REFRESH_RATE;
|
||||
OUTREG8(DRAM_ROW_CNTL_HI, temp | DRAM_REFRESH_DISABLE);
|
||||
|
||||
snooze(1000); // wait 1 ms
|
||||
|
||||
// Calculate the VCLK that most closely matches the requested pixel clock,
|
||||
// and then set the M, N, and P values.
|
||||
|
||||
uint16 m, n, p;
|
||||
CalcVCLK(mode.timing.pixel_clock / 1000.0, m, n, p);
|
||||
|
||||
OUTREG16(VCLK2_VCO_M, m);
|
||||
OUTREG16(VCLK2_VCO_N, n);
|
||||
OUTREG8(VCLK2_VCO_DIV_SEL, p);
|
||||
|
||||
// Setup HSYNC & VSYNC polarity and select clock source 2 (0x08) for
|
||||
// programmable PLL.
|
||||
|
||||
uint8 miscOutReg = 0x08 | 0x01;
|
||||
if (!(mode.timing.flags & B_POSITIVE_HSYNC))
|
||||
miscOutReg |= 0x40;
|
||||
if (!(mode.timing.flags & B_POSITIVE_VSYNC))
|
||||
miscOutReg |= 0x80;
|
||||
|
||||
OUTREG8(MISC_OUT_W, miscOutReg);
|
||||
|
||||
SetCrtcTimingValues(mode);
|
||||
|
||||
OUTREG32(MEM_MODE, INREG32(MEM_MODE) | 4);
|
||||
|
||||
// Set the address mapping to use the frame buffer memory mapped via the
|
||||
// GTT table instead of the VGA buffer.
|
||||
|
||||
uint8 addrMapping = ReadGraphReg(ADDRESS_MAPPING);
|
||||
addrMapping &= 0xE0; // preserve reserved bits 7:5
|
||||
addrMapping |= (GTT_MEM_MAP_ENABLE | LINEAR_MODE_ENABLE);
|
||||
WriteGraphReg(ADDRESS_MAPPING, addrMapping);
|
||||
|
||||
// Turn on DRAM refresh.
|
||||
temp = INREG8(DRAM_ROW_CNTL_HI) & ~DRAM_REFRESH_RATE;
|
||||
OUTREG8(DRAM_ROW_CNTL_HI, temp | DRAM_REFRESH_60HZ);
|
||||
|
||||
temp = INREG8(BITBLT_CNTL) & ~COLEXP_MODE;
|
||||
temp |= (mode.bitsPerPixel == 8 ? COLEXP_8BPP : COLEXP_16BPP);
|
||||
OUTREG8(BITBLT_CNTL, temp);
|
||||
|
||||
// Turn on 8 bit dac mode so that the indexed colors are displayed properly,
|
||||
// and put display in high resolution mode.
|
||||
|
||||
uint32 temp32 = INREG32(PIXPIPE_CONFIG) & 0xF3E062FC;
|
||||
temp32 |= (DAC_8_BIT | HIRES_MODE | NO_BLANK_DELAY |
|
||||
(mode.bitsPerPixel == 8 ? DISPLAY_8BPP_MODE : DISPLAY_16BPP_MODE));
|
||||
OUTREG32(PIXPIPE_CONFIG, temp32);
|
||||
|
||||
OUTREG16(EIR, 0);
|
||||
|
||||
temp32 = INREG32(FWATER_BLC);
|
||||
temp32 &= ~(LM_BURST_LENGTH | LM_FIFO_WATERMARK |
|
||||
MM_BURST_LENGTH | MM_FIFO_WATERMARK);
|
||||
temp32 |= I810_GetWatermark(mode);
|
||||
OUTREG32(FWATER_BLC, temp32);
|
||||
|
||||
// Enable high resolution mode.
|
||||
WriteCrtcReg(IO_CTNL, ReadCrtcReg(IO_CTNL) | EXTENDED_CRTC_CNTL);
|
||||
|
||||
I810_AdjustFrame(mode);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
I810_AdjustFrame(const DisplayModeEx& mode)
|
||||
{
|
||||
// Adjust start address in frame buffer.
|
||||
|
||||
uint32 address = ((mode.v_display_start * mode.virtual_width
|
||||
+ mode.h_display_start) * mode.bytesPerPixel) >> 2;
|
||||
|
||||
WriteCrtcReg(START_ADDR_LO, address & 0xff);
|
||||
WriteCrtcReg(START_ADDR_HI, (address >> 8) & 0xff);
|
||||
WriteCrtcReg(EXT_START_ADDR_HI, (address >> 22) & 0xff);
|
||||
WriteCrtcReg(EXT_START_ADDR,
|
||||
((address >> 16) & 0x3f) | EXT_START_ADDR_ENABLE);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
I810_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags)
|
||||
{
|
||||
// Set the indexed color palette for 8-bit color depth mode.
|
||||
|
||||
(void)flags; // avoid compiler warning for unused arg
|
||||
|
||||
if (gInfo.sharedInfo->displayMode.space != B_CMAP8)
|
||||
return ;
|
||||
|
||||
OUTREG8(DAC_MASK, 0xff);
|
||||
OUTREG8(DAC_W_INDEX, first); // initial color index
|
||||
|
||||
while (count--) {
|
||||
OUTREG8(DAC_DATA, colorData[0]); // red
|
||||
OUTREG8(DAC_DATA, colorData[1]); // green
|
||||
OUTREG8(DAC_DATA, colorData[2]); // blue
|
||||
|
||||
colorData += 3;
|
||||
}
|
||||
}
|
163
src/add-ons/accelerants/intel_810/i810_regs.h
Normal file
163
src/add-ons/accelerants/intel_810/i810_regs.h
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
/*!
|
||||
Haiku Intel-810 video driver was adapted from the X.org intel driver which
|
||||
has the following copyright.
|
||||
|
||||
Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef __I810_REGS_H__
|
||||
#define __I810_REGS_H__
|
||||
|
||||
|
||||
// CRT Controller Registers.
|
||||
#define START_ADDR_HI 0x0C
|
||||
#define START_ADDR_LO 0x0D
|
||||
#define VERT_SYNC_END 0x11
|
||||
#define EXT_VERT_TOTAL 0x30
|
||||
#define EXT_VERT_DISPLAY 0x31
|
||||
#define EXT_VERT_SYNC_START 0x32
|
||||
#define EXT_VERT_BLANK_START 0x33
|
||||
#define EXT_HORIZ_TOTAL 0x35
|
||||
#define EXT_HORIZ_BLANK 0x39
|
||||
#define EXT_START_ADDR 0x40
|
||||
#define EXT_START_ADDR_ENABLE 0x80
|
||||
#define EXT_OFFSET 0x41
|
||||
#define EXT_START_ADDR_HI 0x42
|
||||
#define INTERLACE_CNTL 0x70
|
||||
#define INTERLACE_ENABLE 0x80
|
||||
#define INTERLACE_DISABLE 0x00
|
||||
|
||||
// CR80 - IO Control
|
||||
#define IO_CTNL 0x80
|
||||
#define EXTENDED_ATTR_CNTL 0x02
|
||||
#define EXTENDED_CRTC_CNTL 0x01
|
||||
|
||||
// GR10 - Address mapping
|
||||
#define ADDRESS_MAPPING 0x10
|
||||
#define PAGE_TO_LOCAL_MEM_ENABLE 0x10
|
||||
#define GTT_MEM_MAP_ENABLE 0x08
|
||||
#define PACKED_MODE_ENABLE 0x04
|
||||
#define LINEAR_MODE_ENABLE 0x02
|
||||
#define PAGE_MAPPING_ENABLE 0x01
|
||||
|
||||
#define FENCE 0x2000
|
||||
|
||||
#define INST_DONE 0x2090
|
||||
|
||||
// General error reporting regs.
|
||||
#define EIR 0x20B0
|
||||
#define EMR 0x20B4
|
||||
#define ESR 0x20B8
|
||||
|
||||
// FIFO Watermark and Burst Length Control Register.
|
||||
#define FWATER_BLC 0x20d8
|
||||
#define MM_BURST_LENGTH 0x00700000
|
||||
#define MM_FIFO_WATERMARK 0x0001F000
|
||||
#define LM_BURST_LENGTH 0x00000700
|
||||
#define LM_FIFO_WATERMARK 0x0000001F
|
||||
|
||||
#define MEM_MODE 0x020DC
|
||||
|
||||
#define DRAM_ROW_CNTL_HI 0x3002
|
||||
#define DRAM_REFRESH_RATE 0x18
|
||||
#define DRAM_REFRESH_DISABLE 0x00
|
||||
#define DRAM_REFRESH_60HZ 0x08
|
||||
|
||||
#define VCLK2_VCO_M 0x6008
|
||||
#define VCLK2_VCO_N 0x600a
|
||||
#define VCLK2_VCO_DIV_SEL 0x6012
|
||||
|
||||
#define PIXPIPE_CONFIG 0x70008
|
||||
#define NO_BLANK_DELAY 0x100000
|
||||
#define DISPLAY_8BPP_MODE 0x020000
|
||||
#define DISPLAY_15BPP_MODE 0x040000
|
||||
#define DISPLAY_16BPP_MODE 0x050000
|
||||
#define DAC_8_BIT 0x008000
|
||||
#define HIRES_MODE 0x000001
|
||||
|
||||
// Blitter control.
|
||||
#define BITBLT_CNTL 0x7000c
|
||||
#define COLEXP_MODE 0x30
|
||||
#define COLEXP_8BPP 0x00
|
||||
#define COLEXP_16BPP 0x10
|
||||
|
||||
// Color Palette Registers.
|
||||
#define DAC_MASK 0x3C6
|
||||
#define DAC_W_INDEX 0x3C8
|
||||
#define DAC_DATA 0x3C9
|
||||
|
||||
|
||||
#define MISC_OUT_R 0x3CC // read
|
||||
#define MISC_OUT_W 0x3C2 // write
|
||||
#define SEQ_INDEX 0x3C4
|
||||
#define SEQ_DATA 0x3C5
|
||||
#define GRAPH_INDEX 0x3CE
|
||||
#define GRAPH_DATA 0x3CF
|
||||
#define CRTC_INDEX 0x3D4
|
||||
#define CRTC_DATA 0x3D5
|
||||
|
||||
|
||||
// Macros for memory mapped I/O.
|
||||
//==============================
|
||||
|
||||
#define INREG8(addr) (*((vuint8*)(gInfo.regs + (addr))))
|
||||
#define INREG16(addr) (*((vuint16*)(gInfo.regs + (addr))))
|
||||
#define INREG32(addr) (*((vuint32*)(gInfo.regs + (addr))))
|
||||
|
||||
#define OUTREG8(addr, val) (*((vuint8*)(gInfo.regs + (addr))) = (val))
|
||||
#define OUTREG16(addr, val) (*((vuint16*)(gInfo.regs + (addr))) = (val))
|
||||
#define OUTREG32(addr, val) (*((vuint32*)(gInfo.regs + (addr))) = (val))
|
||||
|
||||
// Write a value to an 32-bit reg using a mask. The mask selects the
|
||||
// bits to be modified.
|
||||
#define OUTREGM(addr, value, mask) \
|
||||
(OUTREG(addr, (INREG(addr) & ~mask) | (value & mask)))
|
||||
|
||||
|
||||
static inline uint8 ReadCrtcReg(uint8 index)
|
||||
{
|
||||
OUTREG8(CRTC_INDEX, index);
|
||||
return INREG8(CRTC_DATA);
|
||||
}
|
||||
|
||||
static inline void WriteCrtcReg(uint8 index, uint8 value)
|
||||
{
|
||||
OUTREG8(CRTC_INDEX, index);
|
||||
OUTREG8(CRTC_DATA, value);
|
||||
}
|
||||
|
||||
static inline uint8 ReadGraphReg(uint8 index)
|
||||
{
|
||||
OUTREG8(GRAPH_INDEX, index);
|
||||
return INREG8(GRAPH_DATA);
|
||||
}
|
||||
|
||||
static inline void WriteGraphReg(uint8 index, uint8 value)
|
||||
{
|
||||
OUTREG8(GRAPH_INDEX, index);
|
||||
OUTREG8(GRAPH_DATA, value);
|
||||
}
|
||||
|
||||
static inline uint8 ReadSeqReg(uint8 index)
|
||||
{
|
||||
OUTREG8(SEQ_INDEX, index);
|
||||
return INREG8(SEQ_DATA);
|
||||
}
|
||||
|
||||
static inline void WriteSeqReg(uint8 index, uint8 value)
|
||||
{
|
||||
OUTREG8(SEQ_INDEX, index);
|
||||
OUTREG8(SEQ_DATA, value);
|
||||
}
|
||||
|
||||
|
||||
#endif // __I810_REGS_H__
|
143
src/add-ons/accelerants/intel_810/i810_watermark.cpp
Normal file
143
src/add-ons/accelerants/intel_810/i810_watermark.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
// The code in this file was adapted from the X.org intel driver which had
|
||||
// the following copyright and license.
|
||||
|
||||
/**************************************************************************
|
||||
Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
All Rights Reserved.
|
||||
|
||||
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, sub license, 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 (including the
|
||||
next paragraph) 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 NON-INFRINGEMENT.
|
||||
IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
|
||||
struct WatermarkInfo {
|
||||
double freq;
|
||||
uint32 watermark;
|
||||
};
|
||||
|
||||
static WatermarkInfo watermarks_8[] = {
|
||||
{ 0, 0x22003000},
|
||||
{25.2, 0x22003000},
|
||||
{28.0, 0x22003000},
|
||||
{31.5, 0x22003000},
|
||||
{36.0, 0x22007000},
|
||||
{40.0, 0x22007000},
|
||||
{45.0, 0x22007000},
|
||||
{49.5, 0x22008000},
|
||||
{50.0, 0x22008000},
|
||||
{56.3, 0x22008000},
|
||||
{65.0, 0x22008000},
|
||||
{75.0, 0x22008000},
|
||||
{78.8, 0x22008000},
|
||||
{80.0, 0x22008000},
|
||||
{94.0, 0x22008000},
|
||||
{96.0, 0x22107000},
|
||||
{99.0, 0x22107000},
|
||||
{108.0, 0x22107000},
|
||||
{121.0, 0x22107000},
|
||||
{128.9, 0x22107000},
|
||||
{132.0, 0x22109000},
|
||||
{135.0, 0x22109000},
|
||||
{157.5, 0x2210b000},
|
||||
{162.0, 0x2210b000},
|
||||
{175.5, 0x2210b000},
|
||||
{189.0, 0x2220e000},
|
||||
{202.5, 0x2220e000}
|
||||
};
|
||||
|
||||
static WatermarkInfo watermarks_16[] = {
|
||||
{ 0, 0x22004000},
|
||||
{25.2, 0x22006000},
|
||||
{28.0, 0x22006000},
|
||||
{31.5, 0x22007000},
|
||||
{36.0, 0x22007000},
|
||||
{40.0, 0x22007000},
|
||||
{45.0, 0x22007000},
|
||||
{49.5, 0x22009000},
|
||||
{50.0, 0x22009000},
|
||||
{56.3, 0x22108000},
|
||||
{65.0, 0x2210e000},
|
||||
{75.0, 0x2210e000},
|
||||
{78.8, 0x2210e000},
|
||||
{80.0, 0x22210000},
|
||||
{94.5, 0x22210000},
|
||||
{96.0, 0x22210000},
|
||||
{99.0, 0x22210000},
|
||||
{108.0, 0x22210000},
|
||||
{121.0, 0x22210000},
|
||||
{128.9, 0x22210000},
|
||||
{132.0, 0x22314000},
|
||||
{135.0, 0x22314000},
|
||||
{157.5, 0x22415000},
|
||||
{162.0, 0x22416000},
|
||||
{175.5, 0x22416000},
|
||||
{189.0, 0x22416000},
|
||||
{195.0, 0x22416000},
|
||||
{202.5, 0x22416000}
|
||||
};
|
||||
|
||||
|
||||
|
||||
uint32
|
||||
I810_GetWatermark(const DisplayModeEx& mode)
|
||||
{
|
||||
WatermarkInfo *table;
|
||||
uint32 tableLen;
|
||||
|
||||
// Get burst length and FIFO watermark based upon the bus frequency and
|
||||
// pixel clock.
|
||||
|
||||
switch (mode.bitsPerPixel) {
|
||||
case 8:
|
||||
table = watermarks_8;
|
||||
tableLen = ARRAY_SIZE(watermarks_8);
|
||||
break;
|
||||
case 16:
|
||||
table = watermarks_16;
|
||||
tableLen = ARRAY_SIZE(watermarks_16);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 i;
|
||||
double clockFreq = mode.timing.pixel_clock / 1000.0;
|
||||
|
||||
for (i = 0; i < tableLen && table[i].freq < clockFreq; i++)
|
||||
;
|
||||
|
||||
if (i == tableLen)
|
||||
i--;
|
||||
|
||||
TRACE("chosen watermark 0x%lx (freq %f)\n", table[i].watermark,
|
||||
table[i].freq);
|
||||
|
||||
return table[i].watermark;
|
||||
}
|
339
src/add-ons/accelerants/intel_810/mode.cpp
Normal file
339
src/add-ons/accelerants/intel_810/mode.cpp
Normal file
@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Copyright 2007-2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
#include <create_display_modes.h> // common accelerant header file
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
static bool
|
||||
IsThereEnoughFBMemory(const display_mode* mode, uint32 bitsPerPixel)
|
||||
{
|
||||
// Test if there is enough Frame Buffer memory for the mode and color depth
|
||||
// specified by the caller, and return true if there is sufficient memory.
|
||||
|
||||
uint32 maxWidth = mode->virtual_width;
|
||||
if (mode->timing.h_display > maxWidth)
|
||||
maxWidth = mode->timing.h_display;
|
||||
|
||||
uint32 maxHeight = mode->virtual_height;
|
||||
if (mode->timing.v_display > maxHeight)
|
||||
maxHeight = mode->timing.v_display;
|
||||
|
||||
uint32 bytesPerPixel = (bitsPerPixel + 7) / 8;
|
||||
|
||||
return (maxWidth * maxHeight * bytesPerPixel
|
||||
<= gInfo.sharedInfo->maxFrameBufferSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
IsModeUsable(const display_mode* mode)
|
||||
{
|
||||
// Test if the display mode is usable by the current video chip. That is,
|
||||
// does the chip have enough memory for the mode and is the pixel clock
|
||||
// within the chips allowable range, etc.
|
||||
//
|
||||
// Return true if the mode is usable.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
uint8 bitsPerPixel;
|
||||
uint32 maxPixelClock;
|
||||
|
||||
if (!I810_GetColorSpaceParams(mode->space, bitsPerPixel, maxPixelClock))
|
||||
return false;
|
||||
|
||||
// Is there enough frame buffer memory to handle the mode?
|
||||
|
||||
if (!IsThereEnoughFBMemory(mode, bitsPerPixel))
|
||||
return false;
|
||||
|
||||
if (mode->timing.pixel_clock > maxPixelClock)
|
||||
return false;
|
||||
|
||||
// Is the color space supported?
|
||||
|
||||
bool colorSpaceSupported = false;
|
||||
for (uint32 j = 0; j < si.colorSpaceCount; j++) {
|
||||
if (mode->space == uint32(si.colorSpaces[j])) {
|
||||
colorSpaceSupported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!colorSpaceSupported)
|
||||
return false;
|
||||
|
||||
// Reject modes with a width of 640 and a height < 480 since they do not
|
||||
// work properly with the i810 chipsets.
|
||||
|
||||
if (mode->timing.h_display == 640 && mode->timing.v_display < 480)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CreateModeList(bool (*checkMode)(const display_mode* mode))
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
// Obtain EDID info which is needed for for building the mode list.
|
||||
|
||||
si.bHaveEDID = false;
|
||||
|
||||
if (!si.bHaveEDID) {
|
||||
edid1_raw rawEdid; // raw EDID info to obtain
|
||||
|
||||
if (ioctl(gInfo.deviceFileDesc, INTEL_GET_EDID, &rawEdid,
|
||||
sizeof(rawEdid)) == B_OK) {
|
||||
if (rawEdid.version.version != 1 || rawEdid.version.revision > 4) {
|
||||
TRACE("CreateModeList(); EDID version %d.%d out of range\n",
|
||||
rawEdid.version.version, rawEdid.version.revision);
|
||||
} else {
|
||||
edid_decode(&si.edidInfo, &rawEdid); // decode & save EDID info
|
||||
si.bHaveEDID = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (si.bHaveEDID) {
|
||||
#ifdef ENABLE_DEBUG_TRACE
|
||||
edid_dump(&(si.edidInfo));
|
||||
#endif
|
||||
} else {
|
||||
TRACE("CreateModeList(); Unable to get EDID info\n");
|
||||
}
|
||||
}
|
||||
|
||||
display_mode* list;
|
||||
uint32 count = 0;
|
||||
area_id listArea;
|
||||
|
||||
listArea = create_display_modes("i810 modes",
|
||||
si.bHaveEDID ? &si.edidInfo : NULL,
|
||||
NULL, 0, si.colorSpaces, si.colorSpaceCount,
|
||||
(check_display_mode_hook)checkMode, &list, &count);
|
||||
|
||||
if (listArea < 0)
|
||||
return listArea; // listArea has error code
|
||||
|
||||
si.modeArea = gInfo.modeListArea = listArea;
|
||||
si.modeCount = count;
|
||||
gInfo.modeList = list;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
status_t
|
||||
ProposeDisplayMode(display_mode* target, const display_mode* low,
|
||||
const display_mode* high)
|
||||
{
|
||||
(void)low; // avoid compiler warning for unused arg
|
||||
(void)high; // avoid compiler warning for unused arg
|
||||
|
||||
TRACE("ProposeDisplayMode() %dx%d, pixel clock: %d kHz, space: 0x%X\n",
|
||||
target->timing.h_display, target->timing.v_display,
|
||||
target->timing.pixel_clock, target->space);
|
||||
|
||||
// Search the mode list for the specified mode.
|
||||
|
||||
uint32 modeCount = gInfo.sharedInfo->modeCount;
|
||||
|
||||
for (uint32 j = 0; j < modeCount; j++) {
|
||||
display_mode& mode = gInfo.modeList[j];
|
||||
|
||||
if (target->timing.h_display == mode.timing.h_display
|
||||
&& target->timing.v_display == mode.timing.v_display
|
||||
&& target->space == mode.space)
|
||||
return B_OK; // mode found in list
|
||||
}
|
||||
|
||||
return B_BAD_VALUE; // mode not found in list
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SetDisplayMode(display_mode* pMode)
|
||||
{
|
||||
// First validate the mode, then call a function to set the registers.
|
||||
|
||||
TRACE("SetDisplayMode() begin\n");
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
DisplayModeEx mode;
|
||||
(display_mode&)mode = *pMode;
|
||||
|
||||
uint32 maxPixelClock;
|
||||
if (!I810_GetColorSpaceParams(mode.space, mode.bitsPerPixel, maxPixelClock))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (ProposeDisplayMode(&mode, pMode, pMode) != B_OK)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
mode.bytesPerPixel = (mode.bitsPerPixel + 7) / 8;
|
||||
mode.bytesPerRow = mode.timing.h_display * mode.bytesPerPixel;
|
||||
|
||||
// Is there enough frame buffer memory for this mode?
|
||||
|
||||
if ( ! IsThereEnoughFBMemory(&mode, mode.bitsPerPixel))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
TRACE("Set display mode: %dx%d virtual size: %dx%d "
|
||||
"color depth: %d bits/pixel\n",
|
||||
mode.timing.h_display, mode.timing.v_display,
|
||||
mode.virtual_width, mode.virtual_height, mode.bitsPerPixel);
|
||||
|
||||
TRACE(" mode timing: %d %d %d %d %d %d %d %d %d\n",
|
||||
mode.timing.pixel_clock,
|
||||
mode.timing.h_display,
|
||||
mode.timing.h_sync_start, mode.timing.h_sync_end,
|
||||
mode.timing.h_total,
|
||||
mode.timing.v_display,
|
||||
mode.timing.v_sync_start, mode.timing.v_sync_end,
|
||||
mode.timing.v_total);
|
||||
|
||||
TRACE(" mode hFreq: %.1f kHz vFreq: %.1f Hz %chSync %cvSync\n",
|
||||
double(mode.timing.pixel_clock) / mode.timing.h_total,
|
||||
((double(mode.timing.pixel_clock) / mode.timing.h_total) * 1000.0)
|
||||
/ mode.timing.v_total,
|
||||
(mode.timing.flags & B_POSITIVE_HSYNC) ? '+' : '-',
|
||||
(mode.timing.flags & B_POSITIVE_VSYNC) ? '+' : '-');
|
||||
|
||||
status_t status = I810_SetDisplayMode(mode);
|
||||
if (status != B_OK) {
|
||||
TRACE("SetDisplayMode() failed; status 0x%x\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
si.displayMode = mode;
|
||||
|
||||
TRACE("SetDisplayMode() done\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
status_t
|
||||
MoveDisplay(uint16 horizontalStart, uint16 verticalStart)
|
||||
{
|
||||
// Set which pixel of the virtual frame buffer will show up in the
|
||||
// top left corner of the display device. Used for page-flipping
|
||||
// games and virtual desktops.
|
||||
|
||||
DisplayModeEx& mode = gInfo.sharedInfo->displayMode;
|
||||
|
||||
if (mode.timing.h_display + horizontalStart > mode.virtual_width
|
||||
|| mode.timing.v_display + verticalStart > mode.virtual_height)
|
||||
return B_ERROR;
|
||||
|
||||
mode.h_display_start = horizontalStart;
|
||||
mode.v_display_start = verticalStart;
|
||||
|
||||
I810_AdjustFrame(mode);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
AccelerantModeCount(void)
|
||||
{
|
||||
// Return the number of display modes in the mode list.
|
||||
|
||||
return gInfo.sharedInfo->modeCount;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetModeList(display_mode* dmList)
|
||||
{
|
||||
// Copy the list of supported video modes to the location pointed at
|
||||
// by dmList.
|
||||
|
||||
memcpy(dmList, gInfo.modeList,
|
||||
gInfo.sharedInfo->modeCount * sizeof(display_mode));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetDisplayMode(display_mode* current_mode)
|
||||
{
|
||||
*current_mode = gInfo.sharedInfo->displayMode; // return current display mode
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetFrameBufferConfig(frame_buffer_config* pFBC)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
pFBC->frame_buffer = (void*)((addr_t)(si.videoMemAddr));
|
||||
pFBC->frame_buffer_dma = (void*)((addr_t)(si.videoMemPCI));
|
||||
pFBC->bytes_per_row = si.displayMode.virtual_width
|
||||
* si.displayMode.bytesPerPixel;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetPixelClockLimits(display_mode* mode, uint32* low, uint32* high)
|
||||
{
|
||||
// Return the maximum and minium pixel clock limits for the specified mode.
|
||||
|
||||
uint8 bitsPerPixel;
|
||||
uint32 maxPixelClock;
|
||||
|
||||
if (!I810_GetColorSpaceParams(mode->space, bitsPerPixel, maxPixelClock))
|
||||
return B_ERROR;
|
||||
|
||||
if (low != NULL) {
|
||||
// lower limit of about 48Hz vertical refresh
|
||||
uint32 totalClocks = (uint32)mode->timing.h_total
|
||||
* (uint32)mode->timing.v_total;
|
||||
uint32 lowClock = (totalClocks * 48L) / 1000L;
|
||||
if (lowClock > maxPixelClock)
|
||||
return B_ERROR;
|
||||
|
||||
*low = lowClock;
|
||||
}
|
||||
|
||||
if (high != NULL)
|
||||
*high = maxPixelClock;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef __HAIKU__
|
||||
|
||||
status_t
|
||||
GetEdidInfo(void* info, size_t size, uint32* _version)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
if ( ! si.bHaveEDID)
|
||||
return B_ERROR;
|
||||
|
||||
if (size < sizeof(struct edid1_info))
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
memcpy(info, &si.edidInfo, sizeof(struct edid1_info));
|
||||
*_version = EDID_VERSION_1;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
#endif // __HAIKU__
|
@ -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 intel_810 ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics intel_extreme ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics matrox ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics neomagic ;
|
||||
|
9
src/add-ons/kernel/drivers/graphics/intel_810/Jamfile
Normal file
9
src/add-ons/kernel/drivers/graphics/intel_810/Jamfile
Normal file
@ -0,0 +1,9 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel drivers graphics intel_810 ;
|
||||
|
||||
UsePrivateHeaders [ FDirName graphics intel_810 ] ;
|
||||
UsePrivateHeaders [ FDirName graphics common ] ;
|
||||
UsePrivateHeaders graphics kernel ;
|
||||
|
||||
KernelAddon intel_810 :
|
||||
driver.cpp
|
||||
;
|
674
src/add-ons/kernel/drivers/graphics/intel_810/driver.cpp
Normal file
674
src/add-ons/kernel/drivers/graphics/intel_810/driver.cpp
Normal file
@ -0,0 +1,674 @@
|
||||
/*
|
||||
* Copyright 2007-2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Authors:
|
||||
* Gerald Zajac
|
||||
*/
|
||||
|
||||
#include <AGP.h>
|
||||
#include <KernelExport.h>
|
||||
#include <PCI.h>
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <graphic_driver.h>
|
||||
#include <boot_item.h>
|
||||
#include <arch/x86/vm86.h>
|
||||
|
||||
#include "DriverInterface.h"
|
||||
|
||||
|
||||
#undef TRACE
|
||||
|
||||
#ifdef ENABLE_DEBUG_TRACE
|
||||
# define TRACE(x...) dprintf("i810: " x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
|
||||
|
||||
#define ACCELERANT_NAME "intel_810.accelerant"
|
||||
|
||||
#define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1))
|
||||
|
||||
#define MAX_DEVICES 4
|
||||
#define DEVICE_FORMAT "%04X_%04X_%02X%02X%02X"
|
||||
|
||||
#define VENDOR_ID 0x8086 // Intel vendor ID
|
||||
|
||||
|
||||
struct ChipInfo {
|
||||
uint16 chipID; // PCI device id of the chip
|
||||
const char* chipName; // user recognizable name (must be < 32 chars)
|
||||
};
|
||||
|
||||
|
||||
// This table maps a PCI device ID to a chip type identifier and the chip name.
|
||||
|
||||
static const ChipInfo chipTable[] = {
|
||||
{ 0x7121, "i810" },
|
||||
{ 0x7123, "i810-dc100" },
|
||||
{ 0x7125, "i810e" },
|
||||
{ 0x1132, "i815" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
struct DeviceInfo {
|
||||
uint32 openCount; // count of how many times device has been opened
|
||||
int32 flags;
|
||||
area_id sharedArea; // area shared between driver and accelerants
|
||||
SharedInfo* sharedInfo; // pointer to shared info area memory
|
||||
vuint8* regs; // pointer to memory mapped registers
|
||||
const ChipInfo* pChipInfo; // info about the selected chip
|
||||
pci_info pciInfo; // copy of pci info for this device
|
||||
area_id gttArea; // area used for GTT
|
||||
addr_t gttAddr; // virtual address of GTT
|
||||
char name[B_OS_NAME_LENGTH]; // name of device
|
||||
};
|
||||
|
||||
|
||||
static Benaphore gLock;
|
||||
static DeviceInfo gDeviceInfo[MAX_DEVICES];
|
||||
static char* gDeviceNames[MAX_DEVICES + 1];
|
||||
static pci_module_info* gPCI;
|
||||
|
||||
|
||||
// Prototypes for device hook functions.
|
||||
|
||||
static status_t device_open(const char* name, uint32 flags, void** cookie);
|
||||
static status_t device_close(void* dev);
|
||||
static status_t device_free(void* dev);
|
||||
static status_t device_read(void* dev, off_t pos, void* buf, size_t* len);
|
||||
static status_t device_write(void* dev, off_t pos, const void* buf,
|
||||
size_t* len);
|
||||
static status_t device_ioctl(void* dev, uint32 msg, void* buf, size_t len);
|
||||
|
||||
static device_hooks gDeviceHooks =
|
||||
{
|
||||
device_open,
|
||||
device_close,
|
||||
device_free,
|
||||
device_ioctl,
|
||||
device_read,
|
||||
device_write,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Video chip register definitions.
|
||||
//=================================
|
||||
|
||||
#define INTERRUPT_ENABLED 0x020a0
|
||||
#define INTERRUPT_MASK 0x020a8
|
||||
|
||||
// Graphics address translation table.
|
||||
#define PAGE_TABLE_CONTROL 0x02020
|
||||
#define PAGE_TABLE_ENABLED 0x01
|
||||
|
||||
#define PTE_BASE 0x10000
|
||||
#define PTE_VALID 0x01
|
||||
|
||||
|
||||
// Macros for memory mapped I/O.
|
||||
//==============================
|
||||
|
||||
#define INREG16(addr) (*((vuint16*)(di.regs + (addr))))
|
||||
#define INREG32(addr) (*((vuint32*)(di.regs + (addr))))
|
||||
|
||||
#define OUTREG16(addr, val) (*((vuint16*)(di.regs + (addr))) = (val))
|
||||
#define OUTREG32(addr, val) (*((vuint32*)(di.regs + (addr))) = (val))
|
||||
|
||||
|
||||
|
||||
static inline uint32
|
||||
GetPCI(pci_info& info, uint8 offset, uint8 size)
|
||||
{
|
||||
return gPCI->read_pci_config(info.bus, info.device, info.function, offset,
|
||||
size);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
SetPCI(pci_info& info, uint8 offset, uint8 size, uint32 value)
|
||||
{
|
||||
gPCI->write_pci_config(info.bus, info.device, info.function, offset, size,
|
||||
value);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
GetEdidFromBIOS(edid1_raw& edidRaw)
|
||||
{
|
||||
// Get the EDID info from the video BIOS, and return B_OK if successful.
|
||||
|
||||
#define ADDRESS_SEGMENT(address) ((addr_t)(address) >> 4)
|
||||
#define ADDRESS_OFFSET(address) ((addr_t)(address) & 0xf)
|
||||
|
||||
vm86_state vmState;
|
||||
|
||||
status_t status = vm86_prepare(&vmState, 0x2000);
|
||||
if (status != B_OK) {
|
||||
TRACE("GetEdidFromBIOS(); vm86_prepare() failed, status: 0x%lx\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
vmState.regs.eax = 0x4f15;
|
||||
vmState.regs.ebx = 0; // 0 = report DDC service
|
||||
vmState.regs.ecx = 0;
|
||||
vmState.regs.es = 0;
|
||||
vmState.regs.edi = 0;
|
||||
|
||||
status = vm86_do_int(&vmState, 0x10);
|
||||
if (status == B_OK) {
|
||||
// AH contains the error code, and AL determines wether or not the
|
||||
// function is supported.
|
||||
if (vmState.regs.eax != 0x4f)
|
||||
status = B_NOT_SUPPORTED;
|
||||
|
||||
// Test if DDC is supported by the monitor.
|
||||
if ((vmState.regs.ebx & 3) == 0)
|
||||
status = B_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (status == B_OK) {
|
||||
// According to the author of the vm86 functions, the address of any
|
||||
// object to receive data must be >= 0x1000 and within the ram size
|
||||
// specified in the second argument of the vm86_prepare() call above.
|
||||
// Thus, the address of the struct to receive the EDID info is set to
|
||||
// 0x1000.
|
||||
|
||||
edid1_raw* edid = (edid1_raw*)0x1000;
|
||||
|
||||
vmState.regs.eax = 0x4f15;
|
||||
vmState.regs.ebx = 1; // 1 = read EDID
|
||||
vmState.regs.ecx = 0;
|
||||
vmState.regs.edx = 0;
|
||||
vmState.regs.es = ADDRESS_SEGMENT(edid);
|
||||
vmState.regs.edi = ADDRESS_OFFSET(edid);
|
||||
|
||||
status = vm86_do_int(&vmState, 0x10);
|
||||
if (status == B_OK) {
|
||||
if (vmState.regs.eax != 0x4f) {
|
||||
status = B_NOT_SUPPORTED;
|
||||
} else {
|
||||
// Copy the EDID info to the caller's location, and compute the
|
||||
// checksum of the EDID info while copying.
|
||||
|
||||
uint8 sum = 0;
|
||||
uint8 allOr = 0;
|
||||
uint8* dest = (uint8*)&edidRaw;
|
||||
uint8* src = (uint8*)edid;
|
||||
|
||||
for (uint32 j = 0; j < sizeof(edidRaw); j++) {
|
||||
sum += *src;
|
||||
allOr |= *src;
|
||||
*dest++ = *src++;
|
||||
}
|
||||
|
||||
if (allOr == 0) {
|
||||
TRACE("GetEdidFromBIOS(); EDID info contains only zeros\n");
|
||||
status = B_ERROR;
|
||||
} else if (sum != 0) {
|
||||
TRACE("GetEdidFromBIOS(); Checksum error in EDID info\n");
|
||||
status = B_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vm86_cleanup(&vmState);
|
||||
|
||||
TRACE("GetEdidFromBIOS() status: 0x%lx\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
InitDevice(DeviceInfo& di)
|
||||
{
|
||||
// Perform initialization and mapping of the device, and return B_OK if
|
||||
// sucessful; else, return error code.
|
||||
|
||||
TRACE("enter InitDevice()\n");
|
||||
|
||||
// Create the area for shared info with NO user-space read or write
|
||||
// permissions, to prevent accidental damage.
|
||||
|
||||
size_t sharedSize = (sizeof(SharedInfo) + 7) & ~7;
|
||||
|
||||
di.sharedArea = create_area("i810 shared info",
|
||||
(void**) &(di.sharedInfo),
|
||||
B_ANY_KERNEL_ADDRESS,
|
||||
ROUND_TO_PAGE_SIZE(sharedSize),
|
||||
B_FULL_LOCK, 0);
|
||||
if (di.sharedArea < 0)
|
||||
return di.sharedArea; // return error code
|
||||
|
||||
SharedInfo& si = *(di.sharedInfo);
|
||||
memset(&si, 0, sharedSize);
|
||||
si.regsArea = -1; // indicate area has not yet been created
|
||||
si.videoMemArea = -1;
|
||||
|
||||
pci_info& pciInfo = di.pciInfo;
|
||||
|
||||
si.vendorID = pciInfo.vendor_id;
|
||||
si.deviceID = pciInfo.device_id;
|
||||
si.revision = pciInfo.revision;
|
||||
strcpy(si.chipName, di.pChipInfo->chipName);
|
||||
|
||||
// Enable memory mapped IO and bus master.
|
||||
|
||||
SetPCI(pciInfo, PCI_command, 2, GetPCI(pciInfo, PCI_command, 2)
|
||||
| PCI_command_io | PCI_command_memory | PCI_command_master);
|
||||
|
||||
// Map the MMIO register area.
|
||||
|
||||
phys_addr_t regsBase = pciInfo.u.h0.base_registers[1];
|
||||
uint32 regAreaSize = pciInfo.u.h0.base_register_sizes[1];
|
||||
|
||||
si.regsArea = map_physical_memory("i810 mmio registers",
|
||||
regsBase,
|
||||
regAreaSize,
|
||||
B_ANY_KERNEL_ADDRESS,
|
||||
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
|
||||
(void**)&di.regs);
|
||||
|
||||
if (si.regsArea < 0) {
|
||||
TRACE("Unable to map MMIO, error: 0x%lx\n", si.regsArea);
|
||||
return si.regsArea;
|
||||
}
|
||||
|
||||
// Allocate memory for the GTT which must be 64K for the 810/815 chips.
|
||||
|
||||
uint32 gttSize = 64 * 1024;
|
||||
di.gttArea = create_area("GTT memory", (void**) &(di.gttAddr),
|
||||
B_ANY_KERNEL_ADDRESS, gttSize, B_FULL_LOCK | B_CONTIGUOUS,
|
||||
B_READ_AREA | B_WRITE_AREA);
|
||||
|
||||
if (di.gttArea < B_OK) {
|
||||
TRACE("Unable to create GTT, error: 0x%lx\n", di.gttArea);
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
memset((void*)(di.gttAddr), 0, gttSize);
|
||||
|
||||
// Get the physical address of the GTT, and set GTT address in the chip.
|
||||
|
||||
physical_entry entry;
|
||||
status_t status = get_memory_map((void *)(di.gttAddr),
|
||||
B_PAGE_SIZE, &entry, 1);
|
||||
if (status < B_OK) {
|
||||
TRACE("Unable to get physical address of GTT, error: 0x%lx\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
OUTREG32(PAGE_TABLE_CONTROL, entry.address | PAGE_TABLE_ENABLED);
|
||||
INREG32(PAGE_TABLE_CONTROL);
|
||||
|
||||
// Allocate video memory to be used for the frame buffer.
|
||||
|
||||
si.videoMemSize = 4 * 1024 * 1024;
|
||||
si.videoMemArea = create_area("video memory", (void**)&(si.videoMemAddr),
|
||||
B_ANY_ADDRESS, si.videoMemSize, B_FULL_LOCK,
|
||||
B_READ_AREA | B_WRITE_AREA);
|
||||
if (si.videoMemArea < B_OK) {
|
||||
TRACE("Unable to create video memory, error: 0x%lx\n", si.videoMemArea);
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
// Get the physical address of each page of the video memory, and put
|
||||
// the physical address of each page into the GTT table.
|
||||
|
||||
for (uint32 offset = 0; offset < si.videoMemSize; offset += B_PAGE_SIZE) {
|
||||
status = get_memory_map((void *)(si.videoMemAddr + offset),
|
||||
B_PAGE_SIZE, &entry, 1);
|
||||
if (status < B_OK) {
|
||||
TRACE("Unable to get physical address of video memory page, error:"
|
||||
" 0x%lx offset: %ld\n", status, offset);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (offset == 0)
|
||||
si.videoMemPCI = entry.address;
|
||||
|
||||
OUTREG32(PTE_BASE + ((offset / B_PAGE_SIZE) * 4),
|
||||
entry.address | PTE_VALID);
|
||||
}
|
||||
|
||||
TRACE("InitDevice() exit OK\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
DeleteAreas(DeviceInfo& di)
|
||||
{
|
||||
// Delete all areas that were created.
|
||||
|
||||
if (di.sharedArea >= 0 && di.sharedInfo != NULL) {
|
||||
SharedInfo& si = *(di.sharedInfo);
|
||||
if (si.regsArea >= 0)
|
||||
delete_area(si.regsArea);
|
||||
if (si.videoMemArea >= 0)
|
||||
delete_area(si.videoMemArea);
|
||||
}
|
||||
|
||||
if (di.gttArea >= 0)
|
||||
delete_area(di.gttArea);
|
||||
di.gttArea = -1;
|
||||
di.gttAddr = (addr_t)NULL;
|
||||
|
||||
if (di.sharedArea >= 0)
|
||||
delete_area(di.sharedArea);
|
||||
di.sharedArea = -1;
|
||||
di.sharedInfo = NULL;
|
||||
}
|
||||
|
||||
|
||||
static const ChipInfo*
|
||||
GetNextSupportedDevice(uint32& pciIndex, pci_info& pciInfo)
|
||||
{
|
||||
// Search the PCI devices for a device that is supported by this driver.
|
||||
// The search starts at the device specified by argument pciIndex, and
|
||||
// continues until a supported device is found or there are no more devices
|
||||
// to examine. Argument pciIndex is incremented after each device is
|
||||
// examined.
|
||||
|
||||
// If a supported device is found, return a pointer to the struct containing
|
||||
// the chip info; else return NULL.
|
||||
|
||||
while (gPCI->get_nth_pci_info(pciIndex, &pciInfo) == B_OK) {
|
||||
|
||||
if (pciInfo.vendor_id == VENDOR_ID) {
|
||||
|
||||
// Search the table of supported devices to find a chip/device that
|
||||
// matches device ID of the current PCI device.
|
||||
|
||||
const ChipInfo* pDevice = chipTable;
|
||||
|
||||
while (pDevice->chipID != 0) { // end of table?
|
||||
if (pDevice->chipID == pciInfo.device_id)
|
||||
return pDevice; // matching device/chip found
|
||||
|
||||
pDevice++;
|
||||
}
|
||||
}
|
||||
|
||||
pciIndex++;
|
||||
}
|
||||
|
||||
return NULL; // no supported device found
|
||||
}
|
||||
|
||||
|
||||
|
||||
// #pragma mark - Kernel Interface
|
||||
|
||||
|
||||
status_t
|
||||
init_hardware(void)
|
||||
{
|
||||
// Return B_OK if a device supported by this driver is found; otherwise,
|
||||
// return B_ERROR so the driver will be unloaded.
|
||||
|
||||
status_t status = get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI);
|
||||
if (status != B_OK) {
|
||||
TRACE("PCI module unavailable, error 0x%lx\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Check pci devices for a device supported by this driver.
|
||||
|
||||
uint32 pciIndex = 0;
|
||||
pci_info pciInfo;
|
||||
const ChipInfo* pDevice = GetNextSupportedDevice(pciIndex, pciInfo);
|
||||
|
||||
TRACE("init_hardware() - %s\n",
|
||||
pDevice == NULL ? "no supported devices" : "device supported");
|
||||
|
||||
put_module(B_PCI_MODULE_NAME); // put away the module manager
|
||||
|
||||
return (pDevice == NULL ? B_ERROR : B_OK);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
init_driver(void)
|
||||
{
|
||||
// Get handle for the pci bus.
|
||||
|
||||
status_t status = get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI);
|
||||
if (status != B_OK) {
|
||||
TRACE("PCI module unavailable, error 0x%lx\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = gLock.Init("i810 driver lock");
|
||||
if (status < B_OK) {
|
||||
put_module(B_AGP_GART_MODULE_NAME);
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Get info about all the devices supported by this driver.
|
||||
|
||||
uint32 pciIndex = 0;
|
||||
uint32 count = 0;
|
||||
|
||||
while (count < MAX_DEVICES) {
|
||||
DeviceInfo& di = gDeviceInfo[count];
|
||||
|
||||
const ChipInfo* pDevice = GetNextSupportedDevice(pciIndex, di.pciInfo);
|
||||
if (pDevice == NULL)
|
||||
break; // all supported devices have been obtained
|
||||
|
||||
// Compose device name.
|
||||
sprintf(di.name, "graphics/" DEVICE_FORMAT,
|
||||
di.pciInfo.vendor_id, di.pciInfo.device_id,
|
||||
di.pciInfo.bus, di.pciInfo.device, di.pciInfo.function);
|
||||
TRACE("init_driver() match found; name: %s\n", di.name);
|
||||
|
||||
gDeviceNames[count] = di.name;
|
||||
di.openCount = 0; // mark driver as available for R/W open
|
||||
di.sharedArea = -1; // indicate shared area not yet created
|
||||
di.sharedInfo = NULL;
|
||||
di.gttArea = -1; // indicate GTT area not yet created
|
||||
di.gttAddr = (addr_t)NULL;
|
||||
di.pChipInfo = pDevice;
|
||||
count++;
|
||||
pciIndex++;
|
||||
}
|
||||
|
||||
gDeviceNames[count] = NULL; // terminate list with null pointer
|
||||
|
||||
TRACE("init_driver() %ld supported devices\n", count);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
uninit_driver(void)
|
||||
{
|
||||
// Free the driver data.
|
||||
|
||||
gLock.Delete();
|
||||
put_module(B_AGP_GART_MODULE_NAME);
|
||||
put_module(B_PCI_MODULE_NAME); // put the pci module away
|
||||
}
|
||||
|
||||
|
||||
const char**
|
||||
publish_devices(void)
|
||||
{
|
||||
return (const char**)gDeviceNames; // return list of supported devices
|
||||
}
|
||||
|
||||
|
||||
device_hooks*
|
||||
find_device(const char* name)
|
||||
{
|
||||
int i = 0;
|
||||
while (gDeviceNames[i] != NULL) {
|
||||
if (strcmp(name, gDeviceNames[i]) == 0)
|
||||
return &gDeviceHooks;
|
||||
i++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// #pragma mark - Device Hooks
|
||||
|
||||
|
||||
static status_t
|
||||
device_open(const char* name, uint32 /*flags*/, void** cookie)
|
||||
{
|
||||
status_t status = B_OK;
|
||||
|
||||
TRACE("device_open() - name: %s, cookie: 0x%08lx)\n", name, (uint32)cookie);
|
||||
|
||||
// Find the device name in the list of devices.
|
||||
|
||||
int32 i = 0;
|
||||
while (gDeviceNames[i] != NULL && (strcmp(name, gDeviceNames[i]) != 0))
|
||||
i++;
|
||||
|
||||
if (gDeviceNames[i] == NULL)
|
||||
return B_BAD_VALUE; // device name not found in list of devices
|
||||
|
||||
DeviceInfo& di = gDeviceInfo[i];
|
||||
|
||||
gLock.Acquire(); // make sure no one else has write access to common data
|
||||
|
||||
if (di.openCount == 0) {
|
||||
status = InitDevice(di);
|
||||
if (status < B_OK)
|
||||
DeleteAreas(di); // error occurred; delete any areas created
|
||||
}
|
||||
|
||||
gLock.Release();
|
||||
|
||||
if (status == B_OK) {
|
||||
di.openCount++; // mark device open
|
||||
*cookie = &di; // send cookie to opener
|
||||
}
|
||||
|
||||
TRACE("device_open() returning 0x%lx, open count: %ld\n", status,
|
||||
di.openCount);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
device_read(void* dev, off_t pos, void* buf, size_t* len)
|
||||
{
|
||||
// Following 3 lines of code are here to eliminate "unused parameter"
|
||||
// warnings.
|
||||
(void)dev;
|
||||
(void)pos;
|
||||
(void)buf;
|
||||
|
||||
*len = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
device_write(void* dev, off_t pos, const void* buf, size_t* len)
|
||||
{
|
||||
// Following 3 lines of code are here to eliminate "unused parameter"
|
||||
// warnings.
|
||||
(void)dev;
|
||||
(void)pos;
|
||||
(void)buf;
|
||||
|
||||
*len = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
device_close(void* dev)
|
||||
{
|
||||
(void)dev; // avoid compiler warning for unused arg
|
||||
|
||||
TRACE("device_close()\n");
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
device_free(void* dev)
|
||||
{
|
||||
DeviceInfo& di = *((DeviceInfo*)dev);
|
||||
|
||||
TRACE("enter device_free()\n");
|
||||
|
||||
gLock.Acquire(); // lock driver
|
||||
|
||||
// If opened multiple times, merely decrement the open count and exit.
|
||||
|
||||
if (di.openCount <= 1)
|
||||
DeleteAreas(di);
|
||||
|
||||
if (di.openCount > 0)
|
||||
di.openCount--; // mark device available
|
||||
|
||||
gLock.Release(); // unlock driver
|
||||
|
||||
TRACE("exit device_free() openCount: %ld\n", di.openCount);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
device_ioctl(void* dev, uint32 msg, void* buffer, size_t bufferLength)
|
||||
{
|
||||
DeviceInfo& di = *((DeviceInfo*)dev);
|
||||
|
||||
TRACE("device_ioctl(); ioctl: %lu, buffer: 0x%08lx, bufLen: %lu\n", msg,
|
||||
(uint32)buffer, bufferLength);
|
||||
|
||||
switch (msg) {
|
||||
case B_GET_ACCELERANT_SIGNATURE:
|
||||
strcpy((char*)buffer, ACCELERANT_NAME);
|
||||
TRACE("Intel 810 accelerant: %s\n", ACCELERANT_NAME);
|
||||
return B_OK;
|
||||
|
||||
case INTEL_DEVICE_NAME:
|
||||
strncpy((char*)buffer, di.name, B_OS_NAME_LENGTH);
|
||||
((char*)buffer)[B_OS_NAME_LENGTH -1] = '\0';
|
||||
return B_OK;
|
||||
|
||||
case INTEL_GET_SHARED_DATA:
|
||||
if (bufferLength != sizeof(area_id))
|
||||
return B_BAD_DATA;
|
||||
|
||||
*((area_id*)buffer) = di.sharedArea;
|
||||
return B_OK;
|
||||
|
||||
case INTEL_GET_EDID:
|
||||
{
|
||||
if (bufferLength != sizeof(edid1_raw))
|
||||
return B_BAD_DATA;
|
||||
|
||||
edid1_raw rawEdid;
|
||||
status_t status = GetEdidFromBIOS(rawEdid);
|
||||
if (status == B_OK)
|
||||
user_memcpy((edid1_raw*)buffer, &rawEdid, sizeof(rawEdid));
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return B_DEV_INVALID_IOCTL;
|
||||
}
|
Loading…
Reference in New Issue
Block a user