hrev44212 adds 2 changesets to branch 'master' old head: 9c02217342b431de9ca99a3ad6a3febe423a32f1 new head: 0e8316cc908c3f24496bdf57855a6dcde483b82f ---------------------------------------------------------------------------- e0ee3b7: 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 [ Gerald Zajac <zajacg@xxxxxxxxxxxxx> ] 0e8316c: intel_810: Style cleanup. No functional change * I think the FunctionNames need to change to function_name [ Alexander von Gluck IV <kallisti5@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- 16 files changed, 2431 insertions(+) .../private/graphics/intel_810/DriverInterface.h | 108 +++ src/add-ons/accelerants/Jamfile | 1 + src/add-ons/accelerants/intel_810/Jamfile | 19 + src/add-ons/accelerants/intel_810/accelerant.cpp | 235 ++++++ src/add-ons/accelerants/intel_810/accelerant.h | 113 +++ src/add-ons/accelerants/intel_810/engine.cpp | 82 ++ src/add-ons/accelerants/intel_810/hooks.cpp | 86 ++ src/add-ons/accelerants/intel_810/i810_dpms.cpp | 101 +++ src/add-ons/accelerants/intel_810/i810_init.cpp | 69 ++ src/add-ons/accelerants/intel_810/i810_mode.cpp | 288 +++++++ src/add-ons/accelerants/intel_810/i810_regs.h | 173 ++++ .../accelerants/intel_810/i810_watermark.cpp | 143 ++++ src/add-ons/accelerants/intel_810/mode.cpp | 333 ++++++++ src/add-ons/kernel/drivers/graphics/Jamfile | 1 + .../kernel/drivers/graphics/intel_810/Jamfile | 9 + .../kernel/drivers/graphics/intel_810/driver.cpp | 670 ++++++++++++++++ ############################################################################ Commit: e0ee3b7971889f4656b26baae75f6ee96f42c190 URL: http://cgit.haiku-os.org/haiku/commit/?id=e0ee3b7 Author: Gerald Zajac <zajacg@xxxxxxxxxxxxx> Date: Wed May 30 20:21:18 2012 UTC Committer: Alexander von Gluck IV <kallisti5@xxxxxxxxxxx> Commit-Date: Wed May 30 20:21:18 2012 UTC Ticket: https://dev.haiku-os.org/ticket/8615 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 ---------------------------------------------------------------------------- diff --git a/headers/private/graphics/intel_810/DriverInterface.h b/headers/private/graphics/intel_810/DriverInterface.h new file mode 100644 index 0000000..a265aef --- /dev/null +++ b/headers/private/graphics/intel_810/DriverInterface.h @@ -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 diff --git a/src/add-ons/accelerants/Jamfile b/src/add-ons/accelerants/Jamfile index 1b10992..442e4c1 100644 --- a/src/add-ons/accelerants/Jamfile +++ b/src/add-ons/accelerants/Jamfile @@ -4,6 +4,7 @@ SubInclude HAIKU_TOP src add-ons accelerants 3dfx ; SubInclude HAIKU_TOP src add-ons accelerants ati ; SubInclude HAIKU_TOP src add-ons accelerants common ; SubInclude HAIKU_TOP src add-ons accelerants et6x00 ; +SubInclude HAIKU_TOP src add-ons accelerants 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 ; diff --git a/src/add-ons/accelerants/intel_810/Jamfile b/src/add-ons/accelerants/intel_810/Jamfile new file mode 100644 index 0000000..3fcb69e --- /dev/null +++ b/src/add-ons/accelerants/intel_810/Jamfile @@ -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 +; diff --git a/src/add-ons/accelerants/intel_810/accelerant.cpp b/src/add-ons/accelerants/intel_810/accelerant.cpp new file mode 100644 index 0000000..475847c --- /dev/null +++ b/src/add-ons/accelerants/intel_810/accelerant.cpp @@ -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; +} diff --git a/src/add-ons/accelerants/intel_810/accelerant.h b/src/add-ons/accelerants/intel_810/accelerant.h new file mode 100644 index 0000000..9406337 --- /dev/null +++ b/src/add-ons/accelerants/intel_810/accelerant.h @@ -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 diff --git a/src/add-ons/accelerants/intel_810/engine.cpp b/src/add-ons/accelerants/intel_810/engine.cpp new file mode 100644 index 0000000..87e2413 --- /dev/null +++ b/src/add-ons/accelerants/intel_810/engine.cpp @@ -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; +} + diff --git a/src/add-ons/accelerants/intel_810/hooks.cpp b/src/add-ons/accelerants/intel_810/hooks.cpp new file mode 100644 index 0000000..b06a95a --- /dev/null +++ b/src/add-ons/accelerants/intel_810/hooks.cpp @@ -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 +} diff --git a/src/add-ons/accelerants/intel_810/i810_dpms.cpp b/src/add-ons/accelerants/intel_810/i810_dpms.cpp new file mode 100644 index 0000000..f49361d --- /dev/null +++ b/src/add-ons/accelerants/intel_810/i810_dpms.cpp @@ -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; +} diff --git a/src/add-ons/accelerants/intel_810/i810_init.cpp b/src/add-ons/accelerants/intel_810/i810_init.cpp new file mode 100644 index 0000000..3c4f4c0 --- /dev/null +++ b/src/add-ons/accelerants/intel_810/i810_init.cpp @@ -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); +} diff --git a/src/add-ons/accelerants/intel_810/i810_mode.cpp b/src/add-ons/accelerants/intel_810/i810_mode.cpp new file mode 100644 index 0000000..3c95d5f --- /dev/null +++ b/src/add-ons/accelerants/intel_810/i810_mode.cpp @@ -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; + } +} diff --git a/src/add-ons/accelerants/intel_810/i810_regs.h b/src/add-ons/accelerants/intel_810/i810_regs.h new file mode 100644 index 0000000..61ddc91 --- /dev/null +++ b/src/add-ons/accelerants/intel_810/i810_regs.h @@ -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__ diff --git a/src/add-ons/accelerants/intel_810/i810_watermark.cpp b/src/add-ons/accelerants/intel_810/i810_watermark.cpp new file mode 100644 index 0000000..8d0cb1d --- /dev/null +++ b/src/add-ons/accelerants/intel_810/i810_watermark.cpp @@ -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; +} diff --git a/src/add-ons/accelerants/intel_810/mode.cpp b/src/add-ons/accelerants/intel_810/mode.cpp new file mode 100644 index 0000000..9f95ccc --- /dev/null +++ b/src/add-ons/accelerants/intel_810/mode.cpp @@ -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__ diff --git a/src/add-ons/kernel/drivers/graphics/Jamfile b/src/add-ons/kernel/drivers/graphics/Jamfile index 79e0815..83781eb 100644 --- a/src/add-ons/kernel/drivers/graphics/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/Jamfile @@ -4,6 +4,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers graphics 3dfx ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics ati ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics common ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics et6x00 ; +SubInclude HAIKU_TOP src add-ons kernel drivers graphics 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 ; diff --git a/src/add-ons/kernel/drivers/graphics/intel_810/Jamfile b/src/add-ons/kernel/drivers/graphics/intel_810/Jamfile new file mode 100644 index 0000000..b118373 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/intel_810/Jamfile @@ -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 +; diff --git a/src/add-ons/kernel/drivers/graphics/intel_810/driver.cpp b/src/add-ons/kernel/drivers/graphics/intel_810/driver.cpp new file mode 100644 index 0000000..f411ae7 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/intel_810/driver.cpp @@ -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; +} + [ *** diff truncated: 42 lines dropped *** ] ############################################################################ Revision: hrev44212 Commit: 0e8316cc908c3f24496bdf57855a6dcde483b82f URL: http://cgit.haiku-os.org/haiku/commit/?id=0e8316c Author: Alexander von Gluck IV <kallisti5@xxxxxxxxxxx> Date: Wed May 30 21:09:52 2012 UTC intel_810: Style cleanup. No functional change * I think the FunctionNames need to change to function_name ----------------------------------------------------------------------------