diff --git a/headers/private/graphics/s3/DriverInterface.h b/headers/private/graphics/s3/DriverInterface.h index b64bd75d36..a5c3fa6c01 100644 --- a/headers/private/graphics/s3/DriverInterface.h +++ b/headers/private/graphics/s3/DriverInterface.h @@ -2,7 +2,7 @@ Copyright 2007-2008 Haiku, Inc. All rights reserved. Distributed under the terms of the MIT license. - Other authors: + Authors: Gerald Zajac 2007-2008 */ @@ -16,27 +16,42 @@ #include -// This is the info that needs to be shared between the kernel driver and -// the accelerant for the sample driver. +// 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. -#if defined(__cplusplus) -extern "C" { -#endif #define ENABLE_DEBUG_TRACE // if defined, turns on debug output to syslog #define NUM_ELEMENTS(a) ((int)(sizeof(a) / sizeof(a[0]))) // for computing number of elements in an array -struct benaphore { +struct Benaphore { sem_id sem; - int32 ben; -}; + int32 count; -#define INIT_BEN(x) x.sem = create_sem(0, "S3 "#x" benaphore"); x.ben = 0; -#define AQUIRE_BEN(x) if((atomic_add(&(x.ben), 1)) >= 1) acquire_sem(x.sem); -#define RELEASE_BEN(x) if((atomic_add(&(x.ben), -1)) > 1) release_sem(x.sem); -#define DELETE_BEN(x) delete_sem(x.sem); + 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); } +}; #define S3_PRIVATE_DATA_MAGIC 0x4521 // a private driver rev, of sorts @@ -45,6 +60,7 @@ struct benaphore { enum { S3_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1, S3_DEVICE_NAME, + S3_GET_EDID, S3_GET_PIO, S3_SET_PIO, S3_RUN_INTERRUPTS, @@ -54,7 +70,7 @@ enum { // Chip type numbers. These are used to group the chips into related // groups. See table S3_ChipTable in driver.c -enum S3_ChipType { +enum ChipType { S3_TRIO64 = 1, S3_TRIO64_VP, // Trio64V+ has same ID as Trio64 but different revision number S3_TRIO64_UVP, @@ -106,33 +122,10 @@ enum MonitorType { }; -// Bitmap descriptor structures for BCI (for Savage chips) -struct HIGH { - unsigned short Stride; - unsigned char Bpp; - unsigned char ResBWTile; -}; - -struct BMPDESC1 { - unsigned long Offset; - HIGH HighPart; -}; - -struct BMPDESC2 { - unsigned long LoPart; - unsigned long HiPart; -}; - -union BMPDESC { - BMPDESC1 bd1; - BMPDESC2 bd2; -}; - - struct DisplayModeEx : display_mode { - uint32 bpp; // bits/pixel - uint32 bytesPerRow; // number of bytes in one line/row + uint32 bpp; // bits/pixel + uint32 bytesPerRow; // actual number of bytes in one line/row }; @@ -147,6 +140,9 @@ struct SharedInfo { bool bAccelerantInUse; // true = accelerant has been initialized bool bInterruptAssigned; // card has a useable interrupt assigned to it + bool bDisableHdwCursor; // true = disable hardware cursor & use software cursor + bool bDisableAccelDraw; // true = disable accelerated drawing + sem_id vertBlankSem; // vertical blank semaphore; if < 0, there is no semaphore // Memory mappings. @@ -169,11 +165,8 @@ struct SharedInfo { area_id modeArea; // area containing list of display modes the driver supports uint32 modeCount; // number of display modes in the list - // Cursor info. - struct { - uint16 hot_x; // Cursor hot spot. Top left corner of the cursor - uint16 hot_y; // is 0,0 - } cursor; + uint16 cursorHotX; // Cursor hot spot. Top left corner of the cursor + uint16 cursorHotY; // is 0,0 // Current display mode configuration, and other parameters related to // current display mode. @@ -183,12 +176,7 @@ struct SharedInfo { edid1_info edidInfo; bool bHaveEDID; // true = EDID info from device is in edidInfo - // Acceleration engine. - struct { - uint64 count; // last fifo slot used - uint64 lastIdle; // last fifo slot we *know* the engine was idle after - benaphore lock; // for serializing access to the acceleration engine - } engine; + Benaphore engineLock; // for serializing access to the acceleration engine int mclk; @@ -198,41 +186,39 @@ struct SharedInfo { uint16 panelY; // laptop LCD height // Command Overflow Buffer (COB) parameters for Savage chips. - bool bDisableCOB; // enable/disable COB for Savage 4 & ProSavage - uint32 cobIndex; // size index - uint32 cobSize; // size in bytes + uint32 cobSizeIndex; // size index uint32 cobOffset; // offset in video memory - uint32 bciThresholdLo; // low and high thresholds for - uint32 bciThresholdHi; // shadow status update (32bit words) - BMPDESC GlobalBD; // Bitmap Descriptor for BCI + uint32 globalBitmapDesc; // Global Bitmap Descriptor for BCI }; // Set some boolean condition (like enabling or disabling interrupts) struct S3SetBoolState { - uint32 magic; // magic number to make sure the caller groks us + uint32 magic; // magic number bool bEnable; // state to set }; // Retrieve the area_id of the kernel/accelerant shared info struct S3GetPrivateData { - uint32 magic; // magic number to make sure the caller groks us + uint32 magic; // magic number area_id sharedInfoArea; // ID of area containing shared information }; -struct S3GetSetPIO { - uint32 magic; // magic number to make sure the caller groks us - uint32 offset; // offset of PIO register to read/write - uint32 size; // number of bytes to transfer - uint32 value; // value to write or value that was read +struct S3GetEDID { + uint32 magic; // magic number + edid1_raw rawEdid; // raw EDID info to obtain }; -#if defined(__cplusplus) -} -#endif +struct S3GetSetPIO { + uint32 magic; // magic number + uint32 offset; // offset of PIO register to read/write + uint32 size; // number of bytes to transfer + uint32 value; // value to write or value that was read +}; + #endif // DRIVERINTERFACE_H diff --git a/src/add-ons/accelerants/s3/accel.cpp b/src/add-ons/accelerants/s3/accel.cpp index 1662e9c6a0..75d19ecf57 100644 --- a/src/add-ons/accelerants/s3/accel.cpp +++ b/src/add-ons/accelerants/s3/accel.cpp @@ -97,15 +97,15 @@ InitAccelerant(int fileDesc) } else { result = gInfo.ChipInit(); // perform init related to current chip if (result == B_OK) { + result = si.engineLock.Init("ATI engine lock"); + if (result == B_OK) { + if (gInfo.ShowCursor != NULL) + gInfo.ShowCursor(false); - INIT_BEN(si.engine.lock); - si.engine.lastIdle = 0; - si.engine.count = 0; - - gInfo.ShowCursor(false); - - // ensure that this function won't be executed again (copies should be clones) - si.bAccelerantInUse = true; + // ensure that this function won't be executed again + // (copies should be clones) + si.bAccelerantInUse = true; + } } } diff --git a/src/add-ons/accelerants/s3/accel.h b/src/add-ons/accelerants/s3/accel.h index b8245bb2f2..7376da0673 100644 --- a/src/add-ons/accelerants/s3/accel.h +++ b/src/add-ons/accelerants/s3/accel.h @@ -13,11 +13,6 @@ #include "register_io.h" -#if defined(__cplusplus) -extern "C" { -#endif - - #undef TRACE @@ -43,7 +38,7 @@ struct AccelerantInfo { display_mode* modeList; // list of standard display modes area_id modeListArea; // mode list area ID - bool bAccelerantIsClone;// true if this is a cloned accelerant + bool bAccelerantIsClone; // true if this is a cloned accelerant // Pointers to wait handlers. void (*WaitQueue)(uint32); @@ -51,7 +46,7 @@ struct AccelerantInfo { // Pointers to DPMS functions. uint32 (*DPMSCapabilities)(void); - uint32 (*DPMSMode)(void); + uint32 (*GetDPMSMode)(void); status_t (*SetDPMSMode)(uint32 dpms_flags); // Pointers to cursor functions. @@ -82,6 +77,10 @@ extern AccelerantInfo gInfo; // chips will have no prefix. //================================================================ +#if defined(__cplusplus) +extern "C" { +#endif + // General status_t InitAccelerant(int fd); ssize_t AccelerantCloneInfoSize(void); @@ -109,15 +108,15 @@ status_t GetEdidInfo(void* info, size_t size, uint32* _version); // DPMS uint32 Savage_DPMSCapabilities(void); -uint32 Savage_DPMSMode(void); +uint32 Savage_GetDPMSMode(void); status_t Savage_SetDPMSMode(uint32 dpms_flags); uint32 Trio64_DPMSCapabilities(void); -uint32 Trio64_DPMSMode(void); +uint32 Trio64_GetDPMSMode(void); status_t Trio64_SetDPMSMode(uint32 dpms_flags); uint32 Virge_DPMSCapabilities(void); -uint32 Virge_DPMSMode(void); +uint32 Virge_GetDPMSMode(void); status_t Virge_SetDPMSMode(uint32 dpms_flags); // Cursor @@ -152,20 +151,25 @@ void Virge_FillSpan(engine_token* et, uint32 color, uint16* list, uint32 count) void Virge_InvertRectangle(engine_token* et, fill_rect_params* list, uint32 count); void Virge_ScreenToScreenBlit(engine_token* et, blit_params* list, uint32 count); +#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)); +status_t CreateModeList(bool (*checkMode)(const display_mode* mode), + bool (*getEdid)(edid1_info& edidInfo)); void InitCrtcTimingValues(const DisplayModeEx& mode, int horzScaleFactor, uint8 crtc[], uint8& cr3b, uint8& cr3c, uint8& cr5d, uint8& cr5e); bool IsModeUsable(const display_mode* mode); // Savage functions. -bool Savage_GetEdidInfo(void); +bool Savage_GetEdidInfo(edid1_info& edidInfo); bool Savage_LoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask); void Savage_SetCursorPosition(int x, int y); @@ -185,7 +189,7 @@ void Trio64_SetFunctionPointers(void); // Virge functions. -bool Virge_GetEdidInfo(void); +bool Virge_GetEdidInfo(edid1_info& edidInfo); bool Virge_LoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask); void Virge_SetCursorPosition(int x, int y); @@ -195,8 +199,4 @@ bool Virge_SetDisplayMode(const DisplayModeEx& mode); void Virge_SetFunctionPointers(void); -#if defined(__cplusplus) -} -#endif - #endif // _ACCEL_H diff --git a/src/add-ons/accelerants/s3/cursor.cpp b/src/add-ons/accelerants/s3/cursor.cpp index e516d01110..9bf1649e90 100644 --- a/src/add-ons/accelerants/s3/cursor.cpp +++ b/src/add-ons/accelerants/s3/cursor.cpp @@ -9,7 +9,7 @@ #include "accel.h" -status_t +status_t SetCursorShape(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8* andMask, uint8* xorMask) { @@ -23,8 +23,8 @@ SetCursorShape(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, // Update cursor variables appropriately. SharedInfo& si = *gInfo.sharedInfo; - si.cursor.hot_x = hot_x; - si.cursor.hot_y = hot_y; + si.cursorHotX = hot_x; + si.cursorHotY = hot_y; if ( ! gInfo.LoadCursorImage(width, height, andMask, xorMask)) return B_ERROR; @@ -34,7 +34,7 @@ SetCursorShape(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, } -void +void MoveCursor(uint16 xPos, uint16 yPos) { // Move the cursor to the specified position on the desktop. If we're @@ -72,8 +72,8 @@ MoveCursor(uint16 xPos, uint16 yPos) MoveDisplay(hds, vds); // Put cursor in correct physical position. - x -= (hds + si.cursor.hot_x); - y -= (vds + si.cursor.hot_y); + x -= (hds + si.cursorHotX); + y -= (vds + si.cursorHotY); // Position the cursor on the display. gInfo.SetCursorPosition(x, y); diff --git a/src/add-ons/accelerants/s3/engine.cpp b/src/add-ons/accelerants/s3/engine.cpp index d9834ea8ef..b1b03fefa0 100644 --- a/src/add-ons/accelerants/s3/engine.cpp +++ b/src/add-ons/accelerants/s3/engine.cpp @@ -3,7 +3,7 @@ This file may be used under the terms of the Be Sample Code License. Other authors: - Gerald Zajac 2007 + Gerald Zajac 2007-2008 */ #include "accel.h" @@ -12,22 +12,23 @@ static engine_token engineToken = { 1, B_2D_ACCELERATION, NULL }; -uint32 +uint32 AccelerantEngineCount(void) { return 1; } -status_t +status_t AcquireEngine(uint32 capabilities, uint32 max_wait, sync_token* st, engine_token** et) { (void)capabilities; // avoid compiler warning for unused arg (void)max_wait; // avoid compiler warning for unused arg - // Acquire the shared benaphore. - AQUIRE_BEN(gInfo.sharedInfo->engine.lock) + if (gInfo.sharedInfo->engineLock.Acquire() != B_OK) + return B_ERROR; + // Sync if required. if (st) SyncToToken(st); @@ -38,37 +39,35 @@ AcquireEngine(uint32 capabilities, uint32 max_wait, } -status_t +status_t ReleaseEngine(engine_token* et, sync_token* st) { // Update the sync token, if any. if (st) GetSyncToken(et, st); - // Release the shared benaphore. - RELEASE_BEN(gInfo.sharedInfo->engine.lock) + gInfo.sharedInfo->engineLock.Release(); return B_OK; } -void +void WaitEngineIdle(void) { gInfo.WaitIdleEmpty(); // wait until engine is completely idle } -status_t +status_t GetSyncToken(engine_token* et, sync_token* st) { - // Engine count will always be zero: we don't support syncing to token (yet). st->engine_id = et->engine_id; - st->counter = gInfo.sharedInfo->engine.count; + st->counter = 0; return B_OK; } -status_t +status_t SyncToToken(sync_token* st) { (void)st; // avoid compiler warning for unused arg diff --git a/src/add-ons/accelerants/s3/hooks.cpp b/src/add-ons/accelerants/s3/hooks.cpp index 8beed5ddfb..26e259a627 100644 --- a/src/add-ons/accelerants/s3/hooks.cpp +++ b/src/add-ons/accelerants/s3/hooks.cpp @@ -14,6 +14,8 @@ get_accelerant_hook(uint32 feature, void* data) { (void)data; // avoid compiler warning for unused arg + SharedInfo& si = *gInfo.sharedInfo; + switch (feature) { // General case B_INIT_ACCELERANT: return (void*)InitAccelerant; @@ -42,13 +44,16 @@ get_accelerant_hook(uint32 feature, void* data) // DPMS case B_DPMS_CAPABILITIES: return (void*)(gInfo.DPMSCapabilities); - case B_DPMS_MODE: return (void*)(gInfo.DPMSMode); + case B_DPMS_MODE: return (void*)(gInfo.GetDPMSMode); case B_SET_DPMS_MODE: return (void*)(gInfo.SetDPMSMode); // Cursor - case B_SET_CURSOR_SHAPE: return (void*)SetCursorShape; - case B_MOVE_CURSOR: return (void*)MoveCursor; - case B_SHOW_CURSOR: return (void*)(gInfo.ShowCursor); + case B_SET_CURSOR_SHAPE: + return (void*)(si.bDisableHdwCursor ? NULL : SetCursorShape); + case B_MOVE_CURSOR: + return (void*)(si.bDisableHdwCursor ? NULL : MoveCursor); + case B_SHOW_CURSOR: + return (void*)(si.bDisableHdwCursor ? NULL : gInfo.ShowCursor); // Engine Management case B_ACCELERANT_ENGINE_COUNT: return (void*)AccelerantEngineCount; @@ -59,10 +64,14 @@ get_accelerant_hook(uint32 feature, void* data) case B_SYNC_TO_TOKEN: return (void*)SyncToToken; // 2D acceleration - case B_SCREEN_TO_SCREEN_BLIT: return (void*)(gInfo.ScreenToScreenBlit); - case B_FILL_RECTANGLE: return (void*)(gInfo.FillRectangle); - case B_INVERT_RECTANGLE: return (void*)(gInfo.InvertRectangle); - case B_FILL_SPAN: return (void*)(gInfo.FillSpan); + case B_SCREEN_TO_SCREEN_BLIT: + return (void*)(si.bDisableAccelDraw ? NULL : gInfo.ScreenToScreenBlit); + case B_FILL_RECTANGLE: + return (void*)(si.bDisableAccelDraw ? NULL : gInfo.FillRectangle); + case B_INVERT_RECTANGLE: + return (void*)(si.bDisableAccelDraw ? NULL : gInfo.InvertRectangle); + case B_FILL_SPAN: + return (void*)(si.bDisableAccelDraw ? NULL : gInfo.FillSpan); } return NULL; // Return null pointer for any feature not handled above diff --git a/src/add-ons/accelerants/s3/mode.cpp b/src/add-ons/accelerants/s3/mode.cpp index d0d68d9a85..669d44028f 100644 --- a/src/add-ons/accelerants/s3/mode.cpp +++ b/src/add-ons/accelerants/s3/mode.cpp @@ -8,8 +8,9 @@ #include "accel.h" -#include +#include // common accelerant header file #include +#include void @@ -29,7 +30,7 @@ InitCrtcTimingValues(const DisplayModeEx& mode, int horzScaleFactor, uint8 crtc[ int hDisp_e = (mode.timing.h_display * horzScaleFactor) / 8 - 1; int hSync_s = (mode.timing.h_sync_start * horzScaleFactor) / 8; int hSync_e = (mode.timing.h_sync_end * horzScaleFactor) / 8; - int hBlank_s = hDisp_e; // start of horizontal blanking + 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; @@ -39,8 +40,6 @@ InitCrtcTimingValues(const DisplayModeEx& mode, int horzScaleFactor, uint8 crtc[ int vBlank_s = vDisp_e; // start of vertical blanking int vBlank_e = vTotal; // end of vertical blanking - TRACE("InitCrtcTimingValues()\n"); - // CRTC Controller values crtc[0x00] = hTotal; @@ -146,6 +145,28 @@ FindDisplayMode(int width, int height, int refreshRate, uint32 colorDepth) } + +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) { @@ -162,10 +183,9 @@ IsModeUsable(const display_mode* mode) if ( ! gInfo.GetColorSpaceParams(mode->space, bitsPerPixel, maxPixelClock)) return false; - // Is there enough memory to handle the mode? + // Is there enough frame buffer memory to handle the mode? - if (mode->virtual_width * mode->virtual_height * ((bitsPerPixel + 7) / 8) - > si.maxFrameBufferSize) + if ( ! IsThereEnoughFBMemory(mode, bitsPerPixel)) return false; if (mode->timing.pixel_clock > maxPixelClock) @@ -190,42 +210,65 @@ IsModeUsable(const display_mode* mode) if (mode->timing.h_display == 640 && mode->timing.v_display < 480) return false; - // In most mode lists, there are three entries for 640 x 480 which have a - // refresh rate of 60 Hz. The one with a pixel clock of 25175 works fine - // with the S3 chips; however, the other two with higher clock rates - // cause the display to be offset down and to the right; thus, reject them. - - if (mode->timing.h_display == 640 && mode->timing.v_display == 480) { - int modeRefreshRate = int(((mode->timing.pixel_clock * 1000.0 / - mode->timing.h_total) / mode->timing.v_total) + 0.5); - if (modeRefreshRate == 60 && mode->timing.pixel_clock > 26000) - return false; - } - - // If the video is connected directly to an LCD display (ie, laptop + // If the video chip is connected directly to an LCD display (ie, laptop // computer), restrict the display mode to resolutions where the width and // height of the mode are less than or equal to the width and height of the - // LCD display. Note that this code is not needed under Haiku since it can - // get the preferred mode which should be the resolution of the LCD display. + // LCD display. -#ifndef __HAIKU__ - - if (si.displayType == MT_LCD && si.panelX > 0 && si.panelY > 0 && - (mode->timing.h_display > si.panelX + if (si.displayType == MT_LCD && si.panelX > 0 && si.panelY > 0 + && (mode->timing.h_display > si.panelX || mode->timing.v_display > si.panelY)) { return false; } -#endif // __HAIKU__ - return true; } status_t -CreateModeList(bool (*checkMode)(const display_mode* mode)) +CreateModeList( bool (*checkMode)(const display_mode* mode), + bool (*getEdid)(edid1_info& edidInfo)) { SharedInfo& si = *gInfo.sharedInfo; + + // Obtain EDID info which is needed for for building the mode list. + // However, if a laptop's LCD display is active, bypass getting the EDID + // info since it is not needed, and if the external display supports only + // resolutions smaller than the size of the laptop LCD display, it would + // unnecessarily restrict size of the resolutions that could be set for + // laptop LCD display. + + si.bHaveEDID = false; + + if (si.displayType != MT_LCD) { + if (getEdid != NULL) + si.bHaveEDID = getEdid(si.edidInfo); + + if ( ! si.bHaveEDID) { + S3GetEDID ged; + ged.magic = S3_PRIVATE_DATA_MAGIC; + + if (ioctl(gInfo.deviceFileDesc, S3_GET_EDID, &ged, sizeof(ged)) == B_OK) { + if (ged.rawEdid.version.version != 1 + || ged.rawEdid.version.revision > 4) { + TRACE("CreateModeList(); EDID version %d.%d out of range\n", + ged.rawEdid.version.version, ged.rawEdid.version.revision); + } else { + edid_decode(&si.edidInfo, &ged.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; @@ -254,9 +297,9 @@ ProposeDisplayMode(display_mode *target, const display_mode *low, (void)low; // avoid compiler warning for unused arg (void)high; // avoid compiler warning for unused arg - TRACE("ProposeDisplayMode() clock: %d, width: %d, height: %d, space: 0x%X\n", - target->timing.pixel_clock, target->virtual_width, target->virtual_height, - target->space); + 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. @@ -275,6 +318,7 @@ ProposeDisplayMode(display_mode *target, const display_mode *low, } + status_t SetDisplayMode(display_mode* pMode) { @@ -290,27 +334,50 @@ SetDisplayMode(display_mode* pMode) if ( ! gInfo.GetColorSpaceParams(mode.space, mode.bpp, maxPixelClock)) return B_ERROR; - mode.bytesPerRow = mode.virtual_width * ((mode.bpp + 7) / 8); // use virtual width - if (ProposeDisplayMode(&mode, pMode, pMode) != B_OK) return B_ERROR; - // Test if there is sufficient memory for this mode. Use the virtual width - // and height for this calculation since one or both might be greater than - // the actual dimensions of the mode. + // Note that for some Savage chips, accelerated drawing is badly messed up + // when the display width is 1400 because 1400 is not evenly divisible by 32. + // For those chips, set the width to 1408 so that accelerated drawing will + // draw properly. - if (mode.bytesPerRow * mode.virtual_height > si.maxFrameBufferSize) + if (mode.timing.h_display == 1400 && (si.chipType == S3_PROSAVAGE + || si.chipType == S3_PROSAVAGE_DDR + || si.chipType == S3_TWISTER + || si.chipType == S3_SUPERSAVAGE + || si.chipType == S3_SAVAGE2000)) { + mode.timing.h_display = 1408; + mode.virtual_width = 1408; + } + + int bytesPerPixel = (mode.bpp + 7) / 8; + mode.bytesPerRow = mode.timing.h_display * bytesPerPixel; + + // Is there enough frame buffer memory for this mode? + + if ( ! IsThereEnoughFBMemory(&mode, mode.bpp)) return B_ERROR; - TRACE("Display Mode: width = %d, height = %d, depth = %d\n", + TRACE("Set display mode: %dx%d virtual size: %dx%d color depth: %d bpp\n", + mode.timing.h_display, mode.timing.v_display, mode.virtual_width, mode.virtual_height, mode.bpp); - TRACE("Mode Timing = { %d %d %d %d %d %d %d %d %d 0x%x }\n", + 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_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, mode.timing.flags); + 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) ? '+' : '-'); if ( ! gInfo.SetDisplayMode(mode)) return B_ERROR; @@ -379,7 +446,8 @@ GetFrameBufferConfig(frame_buffer_config* pFBC) pFBC->frame_buffer = (void*)((addr_t)si.videoMemAddr + si.frameBufferOffset); pFBC->frame_buffer_dma = (void*)((addr_t)si.videoMemPCI + si.frameBufferOffset); - pFBC->bytes_per_row = si.displayMode.bytesPerRow; + uint32 bytesPerPixel = (si.displayMode.bpp + 7) / 8; + pFBC->bytes_per_row = si.displayMode.virtual_width * bytesPerPixel; return B_OK; } @@ -418,7 +486,6 @@ GetTimingConstraints(display_timing_constraints *constraints) { (void)constraints; // avoid compiler warning for unused arg - TRACE("GetTimingConstraints() called\n"); return B_ERROR; } @@ -429,8 +496,6 @@ GetPreferredDisplayMode(display_mode* preferredMode) // If the chip is connected to a laptop LCD panel, find the mode with // matching width and height, 60 Hz refresh rate, and greatest color depth. - TRACE("GetPreferredDisplayMode()\n"); - SharedInfo& si = *gInfo.sharedInfo; if (si.displayType == MT_LCD) { @@ -452,8 +517,6 @@ GetPreferredDisplayMode(display_mode* preferredMode) status_t GetEdidInfo(void* info, size_t size, uint32* _version) { - TRACE("GetEdidInfo()\n"); - SharedInfo& si = *gInfo.sharedInfo; if ( ! si.bHaveEDID) diff --git a/src/add-ons/accelerants/s3/savage.h b/src/add-ons/accelerants/s3/savage.h index b03e6482ca..491bd58312 100644 --- a/src/add-ons/accelerants/s3/savage.h +++ b/src/add-ons/accelerants/s3/savage.h @@ -40,17 +40,9 @@ // Primary Stream 2 Stride. #define PRI_STREAM2_STRIDE 0x81b8 +#define S3_GLOBAL_GBD_REG 0x816C // global bitmap descriptor register + #define MEMORY_CTRL0_REG 0xCA -#define MEMORY_CONFIG_REG 0x31 - -// Bitmap descriptor register. -#define S3_GLB_BD_LOW 0x8168 -#define S3_GLB_BD_HIGH 0x816C -#define S3_PRI_BD_LOW 0x8170 -#define S3_PRI_BD_HIGH 0x8174 -#define S3_SEC_BD_LOW 0x8178 -#define S3_SEC_BD_HIGH 0x817c - #define MEM_PS1 0x10 // CRCA_4 :Primary stream 1 #define MEM_PS2 0x20 // CRCA_5 :Primary stream 2 @@ -73,7 +65,6 @@ #define TILE_FORMAT_LINEAR 0 -// BD - BCI enable. #define BCI_ENABLE 8 // savage4, MX, IX, 3D #define BCI_ENABLE_TWISTER 0 // twister, prosavage, DDR, supersavage, 2000 @@ -81,6 +72,7 @@ #define S3_LITTLE_ENDIAN 0 #define S3_BD64 1 +#define BCI_BD_BW_DISABLE 0x10000000 #define BCI_BUFFER_OFFSET 0x10000 #define BCI_GET_PTR vuint32* bci_ptr = ((uint32*)(gInfo.regs + BCI_BUFFER_OFFSET)) diff --git a/src/add-ons/accelerants/s3/savage_dpms.cpp b/src/add-ons/accelerants/s3/savage_dpms.cpp index 10f737317f..3670e89fe5 100644 --- a/src/add-ons/accelerants/s3/savage_dpms.cpp +++ b/src/add-ons/accelerants/s3/savage_dpms.cpp @@ -27,7 +27,7 @@ Savage_DPMSCapabilities(void) uint32 -Savage_DPMSMode(void) +Savage_GetDPMSMode(void) { // Return the current DPMS mode. @@ -59,7 +59,7 @@ Savage_DPMSMode(void) mode = ((ReadSeqReg(0x31) & 0x10) ? B_DPMS_ON : B_DPMS_OFF); } - TRACE("Savage_DPMSMode() mode: %d\n", mode); + TRACE("Savage_GetDPMSMode() mode: %d\n", mode); return mode; } diff --git a/src/add-ons/accelerants/s3/savage_draw.cpp b/src/add-ons/accelerants/s3/savage_draw.cpp index 30161a7565..e5d0fcb317 100644 --- a/src/add-ons/accelerants/s3/savage_draw.cpp +++ b/src/add-ons/accelerants/s3/savage_draw.cpp @@ -25,7 +25,7 @@ Savage_FillRectangle(engine_token *et, uint32 color, fill_rect_params *pList, ui (void)et; // avoid compiler warning for unused arg - BCI_CMD_SET_ROP(cmd, 0xCC); // use GXcopy for rop + BCI_CMD_SET_ROP(cmd, 0xF0); // use GXcopy for rop while (count--) { int x = pList->left; @@ -38,8 +38,8 @@ Savage_FillRectangle(engine_token *et, uint32 color, fill_rect_params *pList, ui gInfo.WaitQueue(7); BCI_SEND(cmd); - BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart); - BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart); + BCI_SEND(gInfo.sharedInfo->frameBufferOffset); + BCI_SEND(gInfo.sharedInfo->globalBitmapDesc); BCI_SEND(color); BCI_SEND(BCI_X_Y(x, y)); @@ -58,7 +58,7 @@ Savage_FillSpan(engine_token *et, uint32 color, uint16 *pList, uint32 count) (void)et; // avoid compiler warning for unused arg - BCI_CMD_SET_ROP(cmd, 0xCC); // use GXcopy for rop + BCI_CMD_SET_ROP(cmd, 0xF0); // use GXcopy for rop while (count--) { int y = *pList++; @@ -78,8 +78,8 @@ Savage_FillSpan(engine_token *et, uint32 color, uint16 *pList, uint32 count) gInfo.WaitQueue(7); BCI_SEND(cmd); - BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart); - BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart); + BCI_SEND(gInfo.sharedInfo->frameBufferOffset); + BCI_SEND(gInfo.sharedInfo->globalBitmapDesc); BCI_SEND(color); BCI_SEND(BCI_X_Y(x, y)); @@ -109,8 +109,8 @@ Savage_InvertRectangle(engine_token *et, fill_rect_params *pList, uint32 count) gInfo.WaitQueue(7); BCI_SEND(cmd); - BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart); - BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart); + BCI_SEND(gInfo.sharedInfo->frameBufferOffset); + BCI_SEND(gInfo.sharedInfo->globalBitmapDesc); BCI_SEND(BCI_X_Y(x, y)); BCI_SEND(BCI_W_H(w, h)); @@ -157,17 +157,17 @@ Savage_ScreenToScreenBlit(engine_token *et, blit_params *pList, uint32 count) BCI_SEND(cmd); - BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart); - BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart); + BCI_SEND(gInfo.sharedInfo->frameBufferOffset); + BCI_SEND(gInfo.sharedInfo->globalBitmapDesc); - BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.LoPart); - BCI_SEND(gInfo.sharedInfo->GlobalBD.bd2.HiPart); + BCI_SEND(gInfo.sharedInfo->frameBufferOffset); + BCI_SEND(gInfo.sharedInfo->globalBitmapDesc); BCI_SEND(BCI_X_Y(src_x, src_y)); BCI_SEND(BCI_X_Y(dest_x, dest_y)); BCI_SEND(BCI_W_H(width + 1, height + 1)); - pList ++; + pList++; } } diff --git a/src/add-ons/accelerants/s3/savage_edid.cpp b/src/add-ons/accelerants/s3/savage_edid.cpp index 64c0a63ba7..9bea23ab8c 100644 --- a/src/add-ons/accelerants/s3/savage_edid.cpp +++ b/src/add-ons/accelerants/s3/savage_edid.cpp @@ -50,7 +50,7 @@ SetI2CSignals(void* cookie, int _clock, int data) bool -Savage_GetEdidInfo(void) +Savage_GetEdidInfo(edid1_info& edidInfo) { // Get the EDID info and return true if successful. @@ -83,17 +83,8 @@ Savage_GetEdidInfo(void) uint8 tmp = ReadCrtcReg(DDCPort); WriteCrtcReg(DDCPort, tmp | 0x13); - si.bHaveEDID = (ddc2_read_edid1(&bus, &(si.edidInfo), NULL, NULL) == B_OK); - + bool bResult = (ddc2_read_edid1(&bus, &edidInfo, NULL, NULL) == B_OK); WriteCrtcReg(DDCPort, tmp); - if (si.bHaveEDID) { -#ifdef ENABLE_DEBUG_TRACE - edid_dump(&(si.edidInfo)); -#endif - } else { - TRACE("Savage_GetEdidInfo() failed!\n"); - } - - return si.bHaveEDID; + return bResult; } diff --git a/src/add-ons/accelerants/s3/savage_init.cpp b/src/add-ons/accelerants/s3/savage_init.cpp index 9782568c67..55983918b0 100644 --- a/src/add-ons/accelerants/s3/savage_init.cpp +++ b/src/add-ons/accelerants/s3/savage_init.cpp @@ -95,23 +95,6 @@ WaitIdleEmpty2K() } -static bool -IsLCDWidthValid(int width) -{ - // Search the array of valid LCD widths to find a width that matches the - // width by the caller, and return true if a match is found. - - const int lcdWidths[] = { 640, 800, 1024, 1152, 1280, 1400, 1440, 1600, 1680 }; - - for (int i = 0; i < NUM_ELEMENTS(lcdWidths); i++) { - if (lcdWidths[i] == width) - return true; - } - - return false; // match not found -} - - static void Savage_GetPanelInfo() { @@ -132,20 +115,12 @@ Savage_GetPanelInfo() int panelX = (ReadSeqReg(0x61) + ((ReadSeqReg(0x66) & 0x02) << 7) + 1) * 8; int panelY = ReadSeqReg(0x69) + ((ReadSeqReg(0x6e) & 0x70) << 4) + 1; - if ( ! IsLCDWidthValid(panelX)) { + // A Savage IX/MV in a Thinkpad T22 or SuperSavage in a Thinkpad T23 with + // a 1400x1050 display will return a width of 1408; thus, in this case, + // set the width to the correct value of 1400. - // Some chips such as the Savage IX/MV in a Thinkpad T-22 will return - // a width that is 8 pixels too wide probably because reg SR61 is set - // to a value +1 higher than it should be. Subtract 8 from the width, - // and check if that is a valid width. - - panelX -= 8; - if ( ! IsLCDWidthValid(panelX)) { - TRACE("%dx%d LCD panel width invalid.\n", panelX + 8, panelY); - si.displayType = MT_CRT; - return; - } - } + if (panelX == 1408) + panelX = 1400; char* sTechnology; @@ -199,7 +174,7 @@ Savage_Init(void) static uint8 RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 }; static const uint8 RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 }; static const uint8 RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 }; - int ramSizeMB = 0; // memory size in megabytes + uint32 ramSizeMB = 0; // memory size in megabytes uint8 cr36 = ReadCrtcReg(0x36); // get amount of video ram @@ -239,57 +214,37 @@ Savage_Init(void) break; } - TRACE("Savage_Init() memory size: %d MB\n", ramSizeMB); + uint32 usableMB = ramSizeMB; - if (ramSizeMB <= 0) + + // If a Savage MX chip has > 8 MB, clamp it at 8 MB since memory for the + // hardware cursor above 8 MB is unusable. + + if (si.chipType == S3_SAVAGE_MX && ramSizeMB > 8) + usableMB = 8; + + TRACE("Savage_Init() memory size: %d MB, usable memory: %d MB\n", ramSizeMB, usableMB); + + if (usableMB <= 0) return B_ERROR; - si.videoMemSize = ramSizeMB * 1024 * 1024; - - - // Certain Savage4 and ProSavage chips can have coherency problems - // with respect to the Command Overflow Buffer (COB); thus, to avoid - // problems with these chips, set bDisableCOB to true. - - si.bDisableCOB = false; + si.videoMemSize = usableMB * 1024 * 1024; // Compute the Command Overflow Buffer (COB) location. - if ((S3_SAVAGE4_SERIES(si.chipType) || S3_SUPERSAVAGE == si.chipType) - && si.bDisableCOB) { - - // The Savage4 and ProSavage have COB coherency bugs which render - // the buffer useless. - - si.cobIndex = 0; - si.cobSize = 0; - si.bciThresholdHi = 32; - si.bciThresholdLo = 0; - } else { - // We use 128kB for the COB on all other chips. - si.cobSize = 0x20000; - if (S3_SAVAGE_3D_SERIES(si.chipType) || si.chipType == S3_SAVAGE2000) - si.cobIndex = 7; // rev.A savage4 apparently also uses 7 - else - si.cobIndex = 2; - - // Max command size: 2560 entries. - si.bciThresholdHi = si.cobSize / 4 + 32 - 2560; - si.bciThresholdLo = si.bciThresholdHi - 2560; - } + uint32 cobSize = 0x20000; // use 128kB for the COB + si.cobSizeIndex = 7; // Note that the X.org developers stated that the command overflow buffer // (COB) must END at a 4MB boundary which for all practical purposes means - // the very end of the video memory. The cursor must be at the beginning - // of the video memory. It had been tried immediately preceding the COB, - // but the Savage MX chip screws up the cursor in that case. + // the very end of the video memory. - si.cobOffset = (si.videoMemSize - si.cobSize) & ~0x1ffff; // align cob to 128k - si.cursorOffset = 0; - si.frameBufferOffset = si.cursorOffset + CURSOR_BYTES; - si.maxFrameBufferSize = si.cobOffset - si.frameBufferOffset; + si.cobOffset = (si.videoMemSize - cobSize) & ~0x1ffff; // align cob to 128k + si.cursorOffset = (si.cobOffset - CURSOR_BYTES) & ~0xfff; // align to 4k boundary + si.frameBufferOffset = 0; + si.maxFrameBufferSize = si.cursorOffset - si.frameBufferOffset; - TRACE("cobIndex: %d cobSize: %d cobOffset: 0x%x\n", si.cobIndex, si.cobSize, si.cobOffset); + TRACE("cobSizeIndex: %d cobSize: %d cobOffset: 0x%x\n", si.cobSizeIndex, cobSize, si.cobOffset); TRACE("cursorOffset: 0x%x frameBufferOffset: 0x%x\n", si.cursorOffset, si.frameBufferOffset); // Reset graphics engine to avoid memory corruption. @@ -340,13 +295,12 @@ Savage_Init(void) si.colorSpaces[2] = B_RGB32; si.colorSpaceCount = 3; - // Get info about the display capabilities (EDID). - - Savage_GetEdidInfo(); + si.bDisableHdwCursor = false; // allow use of hardware cursor + si.bDisableAccelDraw = false; // allow use of accelerated drawing functions // Setup the mode list. - return CreateModeList(IsModeUsable); + return CreateModeList(IsModeUsable, Savage_GetEdidInfo); } @@ -379,7 +333,7 @@ Savage_SetFunctionPointers(void) } gInfo.DPMSCapabilities = Savage_DPMSCapabilities; - gInfo.DPMSMode = Savage_DPMSMode; + gInfo.GetDPMSMode = Savage_GetDPMSMode; gInfo.SetDPMSMode = Savage_SetDPMSMode; gInfo.LoadCursorImage = Savage_LoadCursorImage; diff --git a/src/add-ons/accelerants/s3/savage_mode.cpp b/src/add-ons/accelerants/s3/savage_mode.cpp index 4a36d47ca9..af95e9917b 100644 --- a/src/add-ons/accelerants/s3/savage_mode.cpp +++ b/src/add-ons/accelerants/s3/savage_mode.cpp @@ -1,7 +1,8 @@ /* Haiku S3 Savage driver adapted from the X.org Savage driver. - Copyright 1995-1997 The XFree86 Project, Inc. + Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + Copyright (c) 2003-2006, X.Org Foundation Copyright 2007-2008 Haiku, Inc. All rights reserved. Distributed under the terms of the MIT license. @@ -21,9 +22,9 @@ struct SavageRegRec { uint8 CRTC[25]; // Crtc Controller reg's - uint8 SR12, SR13, SR15, SR18, SR1B, SR29; - uint8 CR31, CR33, CR34, CR3A, CR3B, CR3C; - uint8 CR40, CR42, CR43, CR45; + uint8 SR12, SR13, SR1B, SR29; + uint8 CR33, CR34, CR3A, CR3B, CR3C; + uint8 CR42, CR43, CR45; uint8 CR50, CR51, CR53, CR58, CR5D, CR5E; uint8 CR65, CR66, CR67, CR69; uint8 CR86, CR88; @@ -32,15 +33,12 @@ struct SavageRegRec { - static void Savage_SetGBD_Twister(const DisplayModeEx& mode) { SharedInfo& si = *gInfo.sharedInfo; int bci_enable; - TRACE("Savage_SetGBD_Twister()\n"); - if (si.chipType == S3_SAVAGE4) bci_enable = BCI_ENABLE; else @@ -68,12 +66,7 @@ Savage_SetGBD_Twister(const DisplayModeEx& mode) WriteCrtcReg(0x69, 0x80, 0x80); - WriteReg32(0x8128, 0xFFFFFFFFL); - WriteReg32(0x812C, 0xFFFFFFFFL); - - WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64); - - WriteCrtcReg(0x50, 0xc1, 0xc1); // CR50, bit 7,6,0 = 111, Use GBD + WriteReg32(S3_GLOBAL_GBD_REG, bci_enable | S3_LITTLE_ENDIAN | S3_BD64); // If MS1NB style linear tiling mode. // bit MM850C[15] = 0 select NB linear tile mode. @@ -82,45 +75,6 @@ Savage_SetGBD_Twister(const DisplayModeEx& mode) uint32 ulTmp = ReadReg32(ADVANCED_FUNC_CTRL) | 0x8000; // use MS-s style tile mode WriteReg32(ADVANCED_FUNC_CTRL, ulTmp); - // Set up Tiled Surface Registers - // Bit 25:20 - Surface width in tiles. - // Bit 29 - Y Range Flag. - // Bit 31:30 = 00, 4 bpp. - // = 01, 8 bpp. - // = 10, 16 bpp. - // = 11, 32 bpp. - - // Global Bitmap Descriptor Register MM816C - twister/prosavage - // bit 24~25: tile format - // 00: linear - // 01: destination tiling format - // 10: texture tiling format - // 11: reserved - // bit 28: block write disble/enable - // 0: disable - // 1: enable - - // Global Bitmap Descriptor Register MM816C - savage4 - // bit 24~25: tile format - // 00: linear - // 01: reserved - // 10: 16 bpp tiles - // 11: 32 bpp tiles - // bit 28: block write disable/enable - // 0: enable - // 1: disable - - // Do not enable block_write even for non-tiling modes, because - // the driver cannot determine if the memory type is the certain - // type of SGRAM for which block_write can be used. - - si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; // linear - si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10; // disable block write - // HW uses width. - si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display); // number of pixels per line - si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp); - si.GlobalBD.bd1.Offset = si.frameBufferOffset; - // CR88, bit 4 - Block write enabled/disabled. // // Note: Block write must be disabled when writing to tiled @@ -128,28 +82,12 @@ Savage_SetGBD_Twister(const DisplayModeEx& mode) // write should only be enabled for certain types of SGRAM. WriteCrtcReg(0x88, DISABLE_BLOCK_WRITE_2D, DISABLE_BLOCK_WRITE_2D); - - // CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). - // bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window - // at A000:0. - - WriteCrtcReg(MEMORY_CONFIG_REG, 0x00, 0x01); - - // Program the GBD and SBD's. - - WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart); - WriteReg32(S3_GLB_BD_HIGH, si.GlobalBD.bd2.HiPart | bci_enable | S3_LITTLE_ENDIAN | S3_BD64); - WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart); - WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart); } static void Savage_SetGBD_3D(const DisplayModeEx& mode) { - TRACE("Savage_SetGBD_3D()\n"); - - SharedInfo& si = *gInfo.sharedInfo; int bci_enable = BCI_ENABLE; // MM81C0 and 81C4 are used to control primary stream. @@ -174,12 +112,7 @@ Savage_SetGBD_3D(const DisplayModeEx& mode) WriteCrtcReg(0x69, 0x80, 0x80); - WriteReg32(0x8128, 0xFFFFFFFFL); - WriteReg32(0x812C, 0xFFFFFFFFL); - - WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64); - - WriteCrtcReg(0x50, 0xc1, 0xc1); // CR50, bit 7,6,0 = 111, Use GBD + WriteReg32(S3_GLOBAL_GBD_REG, bci_enable | S3_LITTLE_ENDIAN | S3_BD64); // If MS1NB style linear tiling mode. // bit MM850C[15] = 0 select NB linear tile mode. @@ -188,36 +121,6 @@ Savage_SetGBD_3D(const DisplayModeEx& mode) uint32 ulTmp = ReadReg32(ADVANCED_FUNC_CTRL) | 0x8000; // use MS-s style tile mode WriteReg32(ADVANCED_FUNC_CTRL, ulTmp); - // Tiled Surface 0 Registers MM48C40: - // bit 0~23: tile surface 0 frame buffer offset - // bit 24~29:tile surface 0 width - // bit 30~31:tile surface 0 bits/pixel - // 00: reserved - // 01, 8 bits - // 10, 16 Bits. - // 11, 32 Bits. - - // Global Bitmap Descriptor Register MM816C - // bit 24~25: tile format - // 00: linear - // 01: reserved - // 10: 16 bpp tiles - // 11: 32 bpp tiles - // bit 28: block write disable/enable - // 0: enable - // 1: disable - - // Do not enable block_write even for non-tiling modes, because - // the driver cannot determine if the memory type is the certain - // type of SGRAM for which block_write can be used. - - si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; // linear - si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10; // disable block write - // HW uses width. - si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display); // number of pixels per line - si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp); - si.GlobalBD.bd1.Offset = si.frameBufferOffset; - // CR88, bit 4 - Block write enabled/disabled. // // Note: Block write must be disabled when writing to tiled @@ -225,26 +128,12 @@ Savage_SetGBD_3D(const DisplayModeEx& mode) // write should only be enabled for certain types of SGRAM. WriteCrtcReg(0x88, DISABLE_BLOCK_WRITE_2D, DISABLE_BLOCK_WRITE_2D); - - // CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). - // bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window - // at A000:0. - - WriteCrtcReg(MEMORY_CONFIG_REG, 0x00, 0x01); - - // Program the GBD and SBD's. - WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart); - WriteReg32(S3_GLB_BD_HIGH, si.GlobalBD.bd2.HiPart | bci_enable | S3_LITTLE_ENDIAN | S3_BD64); - WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart); - WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart); } static void Savage_SetGBD_MX(const DisplayModeEx& mode) { - TRACE("Savage_SetGBD_MX()\n"); - SharedInfo& si = *gInfo.sharedInfo; int bci_enable = BCI_ENABLE; @@ -285,12 +174,7 @@ Savage_SetGBD_MX(const DisplayModeEx& mode) (((mode.bytesPerRow * 2) << 16) & 0x3FFF0000) | (mode.bytesPerRow & 0x00003fff)); - WriteReg32(0x8128, 0xFFFFFFFFL); - WriteReg32(0x812C, 0xFFFFFFFFL); - - WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64); - - WriteCrtcReg(0x50, 0xc1, 0xc1); // CR50, bit 7,6,0 = 111, Use GBD + WriteReg32(S3_GLOBAL_GBD_REG, bci_enable | S3_LITTLE_ENDIAN | S3_BD64); // CR78, bit 3 - Block write enabled(1)/disabled(0). // bit 2 - Block write cycle time(0:2 cycles,1: 1 cycle) @@ -299,60 +183,12 @@ Savage_SetGBD_MX(const DisplayModeEx& mode) // write should only be enabled for certain types of SGRAM. WriteCrtcReg(0x78, 0xfb, 0xfb); - - // Tiled Surface 0 Registers MM48C40: - // bit 0~23: tile surface 0 frame buffer offset - // bit 24~29:tile surface 0 width - // bit 30~31:tile surface 0 bits/pixel - // 00: reserved - // 01, 8 bits - // 10, 16 Bits. - // 11, 32 Bits. - - // Global Bitmap Descriptor Register MM816C - // bit 24~25: tile format - // 00: linear - // 01: reserved - // 10: 16 bit - // 11: 32 bit - // bit 28: block write disble/enable - // 0: enable - // 1: disable - - // Do not enable block_write even for non-tiling modes, because - // the driver cannot determine if the memory type is the certain - // type of SGRAM for which block_write can be used. - - si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; // linear - si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10; // disable block write - // HW uses width. - si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display); // number of pixels per line - si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp); - si.GlobalBD.bd1.Offset = si.frameBufferOffset; - - // CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). - // bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window - // at A000:0. - - WriteCrtcReg(MEMORY_CONFIG_REG, 0x04, 0x05); // CR31 - - // Program the GBD and SBD's. - WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart ); - // 8: bci enable. - WriteReg32(S3_GLB_BD_HIGH, (si.GlobalBD.bd2.HiPart - | bci_enable | S3_LITTLE_ENDIAN | S3_BD64)); - WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart); - WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart); - WriteReg32(S3_SEC_BD_LOW, si.GlobalBD.bd2.LoPart); - WriteReg32(S3_SEC_BD_HIGH, si.GlobalBD.bd2.HiPart); } static void Savage_SetGBD_Super(const DisplayModeEx& mode) { - TRACE("Savage_SetGBD_Super()\n"); - SharedInfo& si = *gInfo.sharedInfo; int bci_enable = BCI_ENABLE_TWISTER; @@ -395,47 +231,14 @@ Savage_SetGBD_Super(const DisplayModeEx& mode) WriteReg32(PRI_STREAM2_FBUF_ADDR0, (si.frameBufferOffset & 0xfffffffc) | 0x80000000); WriteReg32(PRI_STREAM2_FBUF_ADDR1, si.frameBufferOffset & 0xfffffffc); - WriteReg32(0x8128, 0xFFFFFFFFL); - WriteReg32(0x812C, 0xFFFFFFFFL); - // Bit 28:block write disable. - WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_BD64 | 0x10000000); - - WriteCrtcReg(0x50, 0xc1, 0xc1); // CR50, bit 7,6,0 = 111, Use GBD - - // Do not enable block_write even for non-tiling modes, because - // the driver cannot determine if the memory type is the certain - // type of SGRAM for which block_write can be used. - - si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; // linear - si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10; // disable block write - // HW uses width. - si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display); // number of pixels per line - si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp); - si.GlobalBD.bd1.Offset = si.frameBufferOffset; - - // CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). - // bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window - // at A000:0. - - WriteCrtcReg(MEMORY_CONFIG_REG, 0x00, 0x01); - - // Program the GBD and SBDs. - WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart ); - WriteReg32(S3_GLB_BD_HIGH, (si.GlobalBD.bd2.HiPart - | bci_enable | S3_LITTLE_ENDIAN | S3_BD64)); - WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart); - WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart); - WriteReg32(S3_SEC_BD_LOW, si.GlobalBD.bd2.LoPart); - WriteReg32(S3_SEC_BD_HIGH, si.GlobalBD.bd2.HiPart); + WriteReg32(S3_GLOBAL_GBD_REG, bci_enable | S3_BD64 | 0x10000000); } static void Savage_SetGBD_2000(const DisplayModeEx& mode) { - TRACE("Savage_SetGBD_2000()\n"); - SharedInfo& si = *gInfo.sharedInfo; int bci_enable = BCI_ENABLE_TWISTER; @@ -463,47 +266,18 @@ Savage_SetGBD_2000(const DisplayModeEx& mode) WriteCrtcReg(0x67, 0x08, 0x08); - WriteReg32(0x8128, 0xFFFFFFFFL); - WriteReg32(0x812C, 0xFFFFFFFFL); - // Bit 28:block write disable. - WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_BD64 | 0x10000000); + WriteReg32(S3_GLOBAL_GBD_REG, bci_enable | S3_BD64 | 0x10000000); - WriteCrtcReg(0x50, 0xc1, 0xc1); // CR50, bit 7,6,0 = 111, Use GBD WriteCrtcReg(0x73, 0x00, 0x20); // CR73 bit 5 = 0 block write disable - - // Do not enable block_write even for non-tiling modes, because - // the driver cannot determine if the memory type is the certain - // type of SGRAM for which block_write can be used. - - si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR; // linear - si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10; // disable block write - // HW uses width. - si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display); // number of pixels per line - si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp); - si.GlobalBD.bd1.Offset = si.frameBufferOffset; - - // CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0). - // bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window - // at A000:0. - - WriteCrtcReg(MEMORY_CONFIG_REG, 0x00, 0x01); - - // Program the GBD and SBDs. - WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart ); - WriteReg32(S3_GLB_BD_HIGH, (si.GlobalBD.bd2.HiPart - | bci_enable | S3_LITTLE_ENDIAN | S3_BD64)); - WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart); - WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart); - WriteReg32(S3_SEC_BD_LOW, si.GlobalBD.bd2.LoPart); - WriteReg32(S3_SEC_BD_HIGH, si.GlobalBD.bd2.HiPart); } + static void Savage_SetGBD(const DisplayModeEx& mode) { - TRACE("Savage_SetGBD()\n"); + SharedInfo& si = *gInfo.sharedInfo; VerticalRetraceWait(); @@ -531,19 +305,27 @@ Savage_SetGBD(const DisplayModeEx& mode) Savage_SetGBD_2000(mode); break; } + + WriteCrtcReg(0x50, 0xc1, 0xc1); // CR50, bit 7,6,0 = 111, Use GBD + + // Set up the Global Bitmap Descriptor used for BCI. + // Do not enable block_write because we can't determine if the memory + // type is a certain type of SGRAM for which block write can be used. + // bit 24~25: tile format, 00 = linear + // bit 28: block write disble/enable, 0 = disable, 1 = enable + + si.globalBitmapDesc = mode.timing.h_display | (mode.bpp << 16) + | TILE_FORMAT_LINEAR | BCI_BD_BW_DISABLE | S3_BD64; // disable block write } static void Savage_Initialize2DEngine(const DisplayModeEx& mode) { - TRACE("Savage_Initialize2DEngine()\n"); - SharedInfo& si = *gInfo.sharedInfo; - uint32 thresholds; - WriteCrtcReg(0x40, 0x01); - WriteCrtcReg(0x31, 0x0c); + WriteCrtcReg(0x40, 0x01); // enable graphics engine + WriteCrtcReg(0x31, 0x0c); // turn on 16-bit register access // Setup plane masks. WriteReg32(0x8128, ~0); // enable all write planes @@ -555,14 +337,16 @@ Savage_Initialize2DEngine(const DisplayModeEx& mode) case S3_SAVAGE_3D: case S3_SAVAGE_MX: - // Disable BCI. - WriteReg32(0x48C18, ReadReg32(0x48C18) & 0x3FF0); - // Setup BCI command overflow buffer. - WriteReg32(0x48C14, (si.cobOffset >> 11) | (si.cobIndex << 29)); // tim + WriteReg32(0x48C18, ReadReg32(0x48C18) & 0x3FF0); // Disable BCI + + // Setup BCI command overflow buffer. 0x48c14 + // Bits 0-11 = Bits 22-11 of the Command Buffer Offset. + // Bits 12-28 = Total number of entries in the command buffer(Read only). + // Bits 29-31 = COB size index, 111 = 32K entries or 128K bytes + WriteReg32(0x48C14, (si.cobOffset >> 11) | (si.cobSizeIndex << 29)); + // Program shadow status update. - thresholds = ((si.bciThresholdLo & 0xffff) << 16) | - (si.bciThresholdHi & 0xffff); - WriteReg32(0x48C10, thresholds); + WriteReg32(0x48C10, 0x78207220); WriteReg32(0x48C0C, 0); // Enable BCI and command overflow buffer. @@ -575,23 +359,14 @@ Savage_Initialize2DEngine(const DisplayModeEx& mode) case S3_PROSAVAGE_DDR: case S3_SUPERSAVAGE: - // Disable BCI. - WriteReg32(0x48C18, ReadReg32(0x48C18) & 0x3FF0); - - if ( ! si.bDisableCOB) { - // Setup BCI command overflow buffer. - WriteReg32(0x48C14, (si.cobOffset >> 11) | (si.cobIndex << 29)); - } - // Program shadow status update; AGD: what should this be? - thresholds = ((si.bciThresholdLo & 0x1fffe0) << 11) - | ((si.bciThresholdHi & 0x1fffe0) >> 5); - WriteReg32(0x48C10, thresholds); + // Some Savage4 and ProSavage chips have coherency problems with + // respect to the Command Overflow Buffer (COB); thus, do not + // enable the COB. + WriteReg32(0x48C18, ReadReg32(0x48C18) & 0x3FF0); // Disable BCI + WriteReg32(0x48C10, 0x00700040); WriteReg32(0x48C0C, 0); - if (si.bDisableCOB) - WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x08); // enable BCI without COB - else - WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x0C); // enable BCI with COB + WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x08); // enable BCI without COB break; @@ -600,23 +375,17 @@ Savage_Initialize2DEngine(const DisplayModeEx& mode) // Disable BCI. WriteReg32(0x48C18, 0); // Setup BCI command overflow buffer. - WriteReg32(0x48C18, (si.cobOffset >> 7) | (si.cobIndex)); + WriteReg32(0x48C18, (si.cobOffset >> 7) | (si.cobSizeIndex)); // Disable shadow status update. WriteReg32(0x48A30, 0); // Enable BCI and command overflow buffer. - WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x00280000 ); + WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x00280000); break; } // Use and set global bitmap descriptor. - // For reasons I do not fully understand yet, on the Savage4, the - // write to the GBD register, MM816C, does not "take" at this time. - // Only the low-order byte is acknowledged, resulting in an incorrect - // stride. Writing the register later, after the mode switch, works - // correctly. This needs to get resolved. - Savage_SetGBD(mode); } @@ -624,8 +393,6 @@ Savage_Initialize2DEngine(const DisplayModeEx& mode) static void Savage_GEReset(const DisplayModeEx& mode) { - TRACE("Savage_GEReset() begin\n"); - gInfo.WaitIdleEmpty(); snooze(10000); @@ -665,7 +432,7 @@ Savage_GEReset(const DisplayModeEx& mode) break; snooze(10000); - TRACE("Restarting S3 graphics engine reset %2d ...\n", r); + TRACE("Savage_GEReset(), restarting S3 graphics engine reset %2d ...\n", r); } // At this point, the FIFO is empty and the engine is idle. @@ -678,8 +445,6 @@ Savage_GEReset(const DisplayModeEx& mode) WriteReg32(MONO_PAT_1, ~0); Savage_SetGBD(mode); - - TRACE("Savage_GEReset() end\n"); } @@ -739,7 +504,7 @@ Savage_CalcClock(long freq, int min_m, static void Savage_WriteMode(const DisplayModeEx& mode, const SavageRegRec& regRec) { - TRACE("Savage_WriteMode() enter\n"); + TRACE("Savage_WriteMode() begin\n"); SharedInfo& si = *gInfo.sharedInfo; @@ -756,7 +521,7 @@ Savage_WriteMode(const DisplayModeEx& mode, const SavageRegRec& regRec) if (ReadCrtcReg(0x66) & 0x01) { Savage_GEReset(mode); // reset GE to make sure nothing is going on } - + WriteCrtcReg(0x67, regRec.CR67 & ~0x0e); // no STREAMS yet old and new // Set register SR19 to zero so that the ProSavage chips will start up @@ -769,7 +534,7 @@ Savage_WriteMode(const DisplayModeEx& mode, const SavageRegRec& regRec) // not cleared, it will startup only if booting under BeOS using the // default boot screen or the boot screen resolution matches the resolution // of the mode currently being set. - + if (si.chipType == S3_SAVAGE_MX) WriteSeqReg(0x30, 0x00, 0x08); @@ -777,14 +542,20 @@ Savage_WriteMode(const DisplayModeEx& mode, const SavageRegRec& regRec) WriteCrtcReg(0x66, regRec.CR66); WriteCrtcReg(0x3a, regRec.CR3A); - WriteCrtcReg(0x31, regRec.CR31); WriteCrtcReg(0x58, regRec.CR58); WriteCrtcReg(0x53, regRec.CR53 & 0x7f); - // Set DCLK registers. + // If Savage IX/MX or SuperSavage, set SR54 & SR56 to 0x10 so that when + // resolutions are set where the width and/or height is less than the + // native resolution of the attached LCD display, the chip will not expand + // the display to fill the screen. That is, if a resolution is set to + // 640x480, it will use only 640x480 pixels for the display. When the chip + // expands the display, text is much less readable. - WriteSeqReg(0x29, regRec.SR29); - WriteSeqReg(0x15, regRec.SR15); + if (S3_SAVAGE_MOBILE_SERIES(si.chipType)) { + WriteSeqReg(0x54, 0x10); + WriteSeqReg(0x56, 0x10); + } // Set the standard CRTC vga regs. @@ -818,7 +589,6 @@ Savage_WriteMode(const DisplayModeEx& mode, const SavageRegRec& regRec) // Other mode timing and extended regs. WriteCrtcReg(0x34, regRec.CR34); - WriteCrtcReg(0x40, regRec.CR40); WriteCrtcReg(0x42, regRec.CR42); WriteCrtcReg(0x45, regRec.CR45); WriteCrtcReg(0x50, regRec.CR50); @@ -837,22 +607,21 @@ Savage_WriteMode(const DisplayModeEx& mode, const SavageRegRec& regRec) if (si.chipType == S3_SAVAGE4) WriteCrtcReg(0xb0, regRec.CRB0); - // Set extended seq regs for dclk. - WriteSeqReg(0x12, regRec.SR12); - WriteSeqReg(0x13, regRec.SR13); - WriteSeqReg(0x29, regRec.SR29); - - WriteSeqReg(0x18, regRec.SR18); WriteSeqReg(0x1b, regRec.SR1B); - // Load new m, n pll values for dclk & mclk. - temp = ReadSeqReg(0x15) & ~0x21; + if ( ! (S3_SAVAGE_MOBILE_SERIES(si.chipType) && si.displayType == MT_LCD)) { + // Set extended seq regs for dclk. + WriteSeqReg(0x12, regRec.SR12); + WriteSeqReg(0x13, regRec.SR13); + WriteSeqReg(0x29, regRec.SR29); - WriteSeqReg(0x15, temp | 0x03); - WriteSeqReg(0x15, temp | 0x23); - WriteSeqReg(0x15, temp | 0x03); - WriteSeqReg(0x15, regRec.SR15); - snooze( 100 ); + // Load new m, n pll values for dclk & mclk. + temp = ReadSeqReg(0x15) & ~0x20; + WriteSeqReg(0x15, temp); + WriteSeqReg(0x15, temp | 0x20); + WriteSeqReg(0x15, temp); + snooze(100); + } // Now write out cr67 in full, possibly starting STREAMS. VerticalRetraceWait(); @@ -874,7 +643,7 @@ Savage_WriteMode(const DisplayModeEx& mode, const SavageRegRec& regRec) Savage_SetGBD(mode); - TRACE("Savage_WriteMode() end\n"); + TRACE("Savage_WriteMode() done\n"); return; } @@ -883,7 +652,7 @@ Savage_WriteMode(const DisplayModeEx& mode, const SavageRegRec& regRec) static bool Savage_ModeInit(const DisplayModeEx& mode) { - TRACE("Savage_ModeInit(%dx%d, %dHz)\n", + TRACE("Savage_ModeInit(%dx%d, %d kHz)\n", mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock); SharedInfo& si = *gInfo.sharedInfo; @@ -896,7 +665,7 @@ Savage_ModeInit(const DisplayModeEx& mode) InitCrtcTimingValues(mode, horizScaleFactor, regRec.CRTC, regRec.CR3B, regRec.CR3C, regRec.CR5D, regRec.CR5E); - regRec.CRTC[23] = 0xEB; + regRec.CRTC[0x17] = 0xEB; int dclk = mode.timing.pixel_clock; regRec.CR67 = 0x00; @@ -930,25 +699,14 @@ Savage_ModeInit(const DisplayModeEx& mode) break; } - - // Use traditional register-crunching to set mode. - regRec.CR3A = (ReadCrtcReg(0x3a) & 0x7f) | 0x15; regRec.CR53 = 0x00; - regRec.CR31 = 0x8c; regRec.CR66 = 0x89; regRec.CR58 = (ReadCrtcReg(0x58) & 0x80) | 0x13; - if (si.chipType == S3_SAVAGE2000) - regRec.SR15 = 0x02; - else - regRec.SR15 = 0x83; - - regRec.SR18 = 0x00; regRec.SR1B = ReadSeqReg(0x1b) | 0x10; // enable 8-bit Color Lookup Table regRec.CR43 = regRec.CR45 = regRec.CR65 = 0x00; - regRec.CR40 = ReadCrtcReg(0x40) & ~0x01; unsigned int m, n, r; Savage_CalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r); @@ -997,7 +755,6 @@ Savage_ModeInit(const DisplayModeEx& mode) else regRec.CR33 = 0x08; - regRec.CR67 |= 1; regRec.CR69 = 0; regRec.CR86 = ReadCrtcReg(0x86) | 0x08; regRec.CR88 = ReadCrtcReg(0x88) | DISABLE_BLOCK_WRITE_2D; @@ -1027,6 +784,7 @@ Savage_SetDisplayMode(const DisplayModeEx& mode) Savage_AdjustFrame(mode); WriteSeqReg(0x01, 0x00, 0x20); // unblank the screen + return true; } diff --git a/src/add-ons/accelerants/s3/trio64_dpms.cpp b/src/add-ons/accelerants/s3/trio64_dpms.cpp index 112d98dcc2..ea7fe156b9 100644 --- a/src/add-ons/accelerants/s3/trio64_dpms.cpp +++ b/src/add-ons/accelerants/s3/trio64_dpms.cpp @@ -26,7 +26,7 @@ Trio64_DPMSCapabilities(void) uint32 -Trio64_DPMSMode(void) +Trio64_GetDPMSMode(void) { // Return the current DPMS mode. @@ -53,7 +53,7 @@ Trio64_DPMSMode(void) TRACE("Unknown DPMS mode, reg sr0D: 0x%X\n", ReadSeqReg(0x0d)); } - TRACE("Trio64_DPMSMode() mode: %d\n", mode); + TRACE("Trio64_GetDPMSMode() mode: %d\n", mode); return mode; } diff --git a/src/add-ons/accelerants/s3/trio64_init.cpp b/src/add-ons/accelerants/s3/trio64_init.cpp index 2566ce87fa..0b5d2703c8 100644 --- a/src/add-ons/accelerants/s3/trio64_init.cpp +++ b/src/add-ons/accelerants/s3/trio64_init.cpp @@ -136,9 +136,12 @@ Trio64_Init(void) si.colorSpaces[1] = B_RGB16; si.colorSpaceCount = 2; + si.bDisableHdwCursor = false; // allow use of hardware cursor + si.bDisableAccelDraw = false; // allow use of accelerated drawing functions + // Setup the mode list. - return CreateModeList(Trio64_IsModeUsable); + return CreateModeList(Trio64_IsModeUsable, NULL); } @@ -152,7 +155,7 @@ Trio64_SetFunctionPointers(void) gInfo.WaitIdleEmpty = WaitIdle; gInfo.DPMSCapabilities = Trio64_DPMSCapabilities; - gInfo.DPMSMode = Trio64_DPMSMode; + gInfo.GetDPMSMode = Trio64_GetDPMSMode; gInfo.SetDPMSMode = Trio64_SetDPMSMode; gInfo.LoadCursorImage = Trio64_LoadCursorImage; diff --git a/src/add-ons/accelerants/s3/trio64_mode.cpp b/src/add-ons/accelerants/s3/trio64_mode.cpp index fc212e2d74..d750ee4818 100644 --- a/src/add-ons/accelerants/s3/trio64_mode.cpp +++ b/src/add-ons/accelerants/s3/trio64_mode.cpp @@ -130,7 +130,7 @@ Trio64_ModeInit(const DisplayModeEx& mode) break; } - bool bEnableAccelFuncs = true; + bool bDisableAccelFuncs = false; switch (mode.timing.h_display) { case 640: @@ -152,7 +152,7 @@ Trio64_ModeInit(const DisplayModeEx& mode) cr50 |= 0x81; break; default: - bEnableAccelFuncs = false; // use app_server default accel functions + bDisableAccelFuncs = true; // use app_server default accel functions break; } @@ -167,20 +167,7 @@ Trio64_ModeInit(const DisplayModeEx& mode) // only with the display widths defined in the above switch statement. For // the other widths, the default functions in the app_server will be used. - if (bEnableAccelFuncs) - { - gInfo.FillRectangle = Trio64_FillRectangle; - gInfo.FillSpan = Trio64_FillSpan; - gInfo.InvertRectangle = Trio64_InvertRectangle; - gInfo.ScreenToScreenBlit = Trio64_ScreenToScreenBlit; - } - else - { - gInfo.FillRectangle = NULL; - gInfo.FillSpan = NULL; - gInfo.InvertRectangle = NULL; - gInfo.ScreenToScreenBlit = NULL; - } + si.bDisableAccelDraw = bDisableAccelFuncs; // Set the standard CRTC vga regs. diff --git a/src/add-ons/accelerants/s3/virge_dpms.cpp b/src/add-ons/accelerants/s3/virge_dpms.cpp index 55eb108ae8..ec5b89c16a 100644 --- a/src/add-ons/accelerants/s3/virge_dpms.cpp +++ b/src/add-ons/accelerants/s3/virge_dpms.cpp @@ -26,7 +26,7 @@ Virge_DPMSCapabilities(void) uint32 -Virge_DPMSMode(void) +Virge_GetDPMSMode(void) { // Return the current DPMS mode. @@ -53,7 +53,7 @@ Virge_DPMSMode(void) TRACE("Unknown DPMS mode, reg sr0D: 0x%X\n", ReadSeqReg(0x0d)); } - TRACE("Virge_DPMSMode() mode: %d\n", mode); + TRACE("Virge_GetDPMSMode() mode: %d\n", mode); return mode; } diff --git a/src/add-ons/accelerants/s3/virge_edid.cpp b/src/add-ons/accelerants/s3/virge_edid.cpp index 57d7e6c932..abad312c43 100644 --- a/src/add-ons/accelerants/s3/virge_edid.cpp +++ b/src/add-ons/accelerants/s3/virge_edid.cpp @@ -80,13 +80,13 @@ SetI2CSignals(void* cookie, int _clock, int data) bool -Virge_GetEdidInfo(void) +Virge_GetEdidInfo(edid1_info& edidInfo) { // Get the EDID info and return true if successful. SharedInfo& si = *gInfo.sharedInfo; - si.bHaveEDID = false; + bool bResult = false; if (si.chipType == S3_TRIO_3D_2X) { uint32 DDCPort = 0xAA; @@ -100,7 +100,7 @@ Virge_GetEdidInfo(void) uint8 tmp = ReadCrtcReg(DDCPort); WriteCrtcReg(DDCPort, tmp | 0x13); - si.bHaveEDID = (ddc2_read_edid1(&bus, &(si.edidInfo), NULL, NULL) == B_OK); + bResult = (ddc2_read_edid1(&bus, &edidInfo, NULL, NULL) == B_OK); WriteCrtcReg(DDCPort, tmp); } else { @@ -113,18 +113,10 @@ Virge_GetEdidInfo(void) uint8 tmp = ReadReg8(DDC_REG); WriteReg8(DDC_REG, tmp | 0x13); - si.bHaveEDID = (ddc2_read_edid1(&bus, &(si.edidInfo), NULL, NULL) == B_OK); + bResult = (ddc2_read_edid1(&bus, &edidInfo, NULL, NULL) == B_OK); WriteReg8(DDC_REG, tmp); } - if (si.bHaveEDID) { -#ifdef ENABLE_DEBUG_TRACE - edid_dump(&(si.edidInfo)); -#endif - } else { - TRACE("Virge_GetEdidInfo() failed!\n"); - } - - return si.bHaveEDID; + return bResult; } diff --git a/src/add-ons/accelerants/s3/virge_init.cpp b/src/add-ons/accelerants/s3/virge_init.cpp index 5fa89bb401..b726cc49db 100644 --- a/src/add-ons/accelerants/s3/virge_init.cpp +++ b/src/add-ons/accelerants/s3/virge_init.cpp @@ -226,13 +226,12 @@ Virge_Init(void) si.colorSpaces[1] = B_RGB16; si.colorSpaceCount = 2; - // Get info about the display capabilities (EDID). - - Virge_GetEdidInfo(); + si.bDisableHdwCursor = false; // allow use of hardware cursor + si.bDisableAccelDraw = false; // allow use of accelerated drawing functions // Setup the mode list. - return CreateModeList(IsModeUsable); + return CreateModeList(IsModeUsable, Virge_GetEdidInfo); } @@ -251,7 +250,7 @@ Virge_SetFunctionPointers(void) gInfo.WaitIdleEmpty = VirgeWaitIdleEmpty; gInfo.DPMSCapabilities = Virge_DPMSCapabilities; - gInfo.DPMSMode = Virge_DPMSMode; + gInfo.GetDPMSMode = Virge_GetDPMSMode; gInfo.SetDPMSMode = Virge_SetDPMSMode; gInfo.LoadCursorImage = Virge_LoadCursorImage; diff --git a/src/add-ons/accelerants/s3/virge_mode.cpp b/src/add-ons/accelerants/s3/virge_mode.cpp index 87bfcf39d1..09e4643138 100644 --- a/src/add-ons/accelerants/s3/virge_mode.cpp +++ b/src/add-ons/accelerants/s3/virge_mode.cpp @@ -623,7 +623,7 @@ Virge_ModeInit(const DisplayModeEx& mode) } int width = mode.bytesPerRow >> 3; - regRec.CRTC[19] = 0xFF & width; + regRec.CRTC[0x13] = 0xFF & width; regRec.CR51 = (0x300 & width) >> 4; // Extension bits regRec.CR33 = 0x20; @@ -694,6 +694,13 @@ Virge_ModeInit(const DisplayModeEx& mode) Virge_WriteMode(mode, regRec); // write mode registers to hardware + // Note that the Virge VX chip does not display the hardware cursor when the + // mode is set to 640x480; thus, in this case the hardware cursor functions + // will be disabled so that a software cursor will be used. + + si.bDisableHdwCursor = (si.chipType == S3_VIRGE_VX + && mode.timing.h_display == 640 && mode.timing.v_display == 480); + return true; } diff --git a/src/add-ons/kernel/drivers/graphics/s3/driver.cpp b/src/add-ons/kernel/drivers/graphics/s3/driver.cpp index 3c890bc060..b3de5bb708 100644 --- a/src/add-ons/kernel/drivers/graphics/s3/driver.cpp +++ b/src/add-ons/kernel/drivers/graphics/s3/driver.cpp @@ -1,8 +1,8 @@ /* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. + Copyright 2007-2008 Haiku, Inc. All rights reserved. + Distributed under the terms of the MIT license. - Other authors: + Authors: Gerald Zajac 2007-2008 */ @@ -12,6 +12,9 @@ #include #include #include +#ifdef __HAIKU__ +#include +#endif // __HAIKU__ #include "DriverInterface.h" @@ -25,15 +28,15 @@ #endif -#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s)) -#define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v)) #define SKD_HANDLER_INSTALLED 0x80000000 -#define MAX_DEVICES 8 +#define MAX_DEVICES 4 #define DEVICE_FORMAT "%04X_%04X_%02X%02X%02X" int32 api_version = B_CUR_DRIVER_API_VERSION; // revision of driver API we support +#define VENDOR_ID 0x5333 // S3 vendor ID + struct ChipInfo { uint16 chipID; // PCI device id of the chip @@ -46,7 +49,7 @@ struct ChipInfo { // revision number. After the revision number is examined, the Trio64V+ will // have a different chip type code and name assigned. -static const ChipInfo S3_ChipTable[] = { +static const ChipInfo chipTable[] = { { 0x8811, S3_TRIO64, "Trio64" }, // see comment above { 0x8814, S3_TRIO64_UVP, "Trio64 UV+" }, { 0x8901, S3_TRIO64_V2, "Trio64 V2/DX/GX" }, @@ -87,60 +90,41 @@ static const ChipInfo S3_ChipTable[] = { }; -#define VENDOR_ID 0x5333 // S3 vendor ID - -static struct { - uint16 vendorID; - const ChipInfo* devices; -} SupportedDevices[] = { - { VENDOR_ID, S3_ChipTable }, - { 0x0000, NULL } -}; - - struct DeviceInfo { uint32 openCount; // count of how many times device has been opened int32 flags; area_id sharedArea; // area shared between driver and all accelerants - SharedInfo* si; // pointer to the shared area - vuint8* regs; // kernel's pointer to memory mapped registers + 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 pcii; // copy of pci info for this device + pci_info pciInfo; // copy of pci info for this device char name[B_OS_NAME_LENGTH]; // name of device }; -struct DeviceData { - uint32 count; // number of devices actually found - benaphore kernel; // for serializing opens/closes - char* deviceNames[MAX_DEVICES + 1]; // device name pointer storage - DeviceInfo di[MAX_DEVICES]; // device specific stuff -}; +static Benaphore gLock; +static DeviceInfo gDeviceInfo[MAX_DEVICES]; +static char* gDeviceNames[MAX_DEVICES + 1]; +static pci_module_info* gPCI; -// Prototypes for our private functions. +// Prototypes for device hook functions. -static status_t open_hook (const char* name, uint32 flags, void** cookie); -static status_t close_hook (void* dev); -static status_t free_hook (void* dev); -static status_t read_hook (void* dev, off_t pos, void* buf, size_t* len); -static status_t write_hook (void* dev, off_t pos, const void* buf, size_t* len); -static status_t control_hook (void* dev, uint32 msg, void* buf, size_t len); -static status_t map_device(DeviceInfo* di); -static void unmap_device(DeviceInfo* di); -static void probe_devices(void); -static int32 s3_interrupt(void* data); +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 DeviceData* pd; -static pci_module_info* pci_bus; -static device_hooks graphics_device_hooks = +static device_hooks gDeviceHooks = { - open_hook, - close_hook, - free_hook, - control_hook, - read_hook, - write_hook, + device_open, + device_close, + device_free, + device_ioctl, + device_read, + device_write, NULL, NULL, NULL, @@ -149,11 +133,25 @@ static device_hooks graphics_device_hooks = +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); +} + + // Functions for dealing with Vertical Blanking Interrupts. Currently, I do // not know the commands to handle these operations; thus, these functions // currently do nothing. -static bool +static bool InterruptIsVBI() { // return true only if a vertical blanking interrupt has occured @@ -161,148 +159,35 @@ InterruptIsVBI() } -static void +static void ClearVBI() { } -static void +static void EnableVBI() { } -static void +static void DisableVBI() { } - -static const ChipInfo* -FindDeviceMatch(uint16 vendorID, uint16 deviceID) -{ - // Search the table of supported devices to find a chip/device that - // matches the vendor ID and device ID passed by the caller. - // Return pointer to the struct containing the chip info if match - // is found; else return NULL. - - int vendor = 0; - - while (SupportedDevices[vendor].vendorID != 0) { // end of table? - if (SupportedDevices[vendor].vendorID == vendorID) { - const ChipInfo* pDevice = SupportedDevices[vendor].devices; - - while (pDevice->chipID != 0) { // end of table? - if (pDevice->chipID == deviceID) - return pDevice; // matching device/chip found - - pDevice++; - } - } - vendor++; - } - - return NULL; // no match found -} - - -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. - - long pci_index = 0; - pci_info pcii; - const ChipInfo* pDevice = NULL; - - if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci_bus) != B_OK) - return B_ERROR; // unable to access PCI bus - - // Check all pci devices for a device supported by this driver. - - while ((*pci_bus->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) { - pDevice = FindDeviceMatch(pcii.vendor_id, pcii.device_id); - if (pDevice != NULL) - break; - - pci_index++; - } - - 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. - - if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci_bus) != B_OK) - return B_ERROR; - - pd = (DeviceData*)calloc(1, sizeof(DeviceData)); - if (NULL == pd) { - put_module(B_PCI_MODULE_NAME); - return B_ERROR; - } - - INIT_BEN(pd->kernel); // initialize the benaphore - probe_devices(); // find all devices supported by this driver - - return B_OK; -} - - -const char** -publish_devices(void) -{ - return (const char**)pd->deviceNames; // return list of supported devices -} - - -device_hooks* -find_device(const char* name) -{ - int index = 0; - while (pd->deviceNames[index]) { - if (strcmp(name, pd->deviceNames[index]) == 0) - return &graphics_device_hooks; - index++; - } - return NULL; -} - - -void - uninit_driver(void) -{ - // Free the driver data. - - DELETE_BEN(pd->kernel); - free(pd); - pd = NULL; - - put_module(B_PCI_MODULE_NAME); // put the pci module away -} - - -static status_t -map_device(DeviceInfo* di) +static status_t +MapDevice(DeviceInfo& di) { char areaName[B_OS_NAME_LENGTH]; - SharedInfo* si = di->si; - pci_info* pcii = &(di->pcii); + SharedInfo& si = *(di.sharedInfo); + pci_info& pciInfo = di.pciInfo; - TRACE("enter map_device()\n"); + TRACE("enter MapDevice()\n"); - // enable memory mapped IO and VGA I/O + // Enable memory mapped IO and bus master. - uint32 tmpUlong = get_pci(PCI_command, 2); - tmpUlong |= PCI_command_io | PCI_command_memory | PCI_command_master; - set_pci(PCI_command, 2, tmpUlong); + SetPCI(pciInfo, PCI_command, 2, GetPCI(pciInfo, PCI_command, 2) + | PCI_command_io | PCI_command_memory | PCI_command_master); const uint32 SavageMmioRegBaseOld = 0x1000000; // 16 MB const uint32 SavageMmioRegBaseNew = 0x0000000; @@ -320,178 +205,115 @@ map_device(DeviceInfo* di) // memory, set it to the largest value that the respective chipset // family can have. - if (S3_SAVAGE_FAMILY(di->pChipInfo->chipType)) { - if (S3_SAVAGE_3D_SERIES(di->pChipInfo->chipType)) { + if (S3_SAVAGE_FAMILY(di.pChipInfo->chipType)) { + if (S3_SAVAGE_3D_SERIES(di.pChipInfo->chipType)) { // Savage 3D & Savage MX chips. - regsBase = di->pcii.u.h0.base_registers[0] + SavageMmioRegBaseOld; + regsBase = pciInfo.u.h0.base_registers[0] + SavageMmioRegBaseOld; regAreaSize = SavageMmioRegSize; - videoRamAddr = di->pcii.u.h0.base_registers[0]; + videoRamAddr = pciInfo.u.h0.base_registers[0]; videoRamSize = 16 * 1024 * 1024; // 16 MB is max for 3D series - si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[0]); + si.videoMemPCI = (void *)(pciInfo.u.h0.base_registers_pci[0]); } else { // All other Savage chips. - regsBase = di->pcii.u.h0.base_registers[0] + SavageMmioRegBaseNew; + regsBase = pciInfo.u.h0.base_registers[0] + SavageMmioRegBaseNew; regAreaSize = SavageMmioRegSize; - videoRamAddr = di->pcii.u.h0.base_registers[1]; - videoRamSize = di->pcii.u.h0.base_register_sizes[1]; - si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[1]); + videoRamAddr = pciInfo.u.h0.base_registers[1]; + videoRamSize = pciInfo.u.h0.base_register_sizes[1]; + si.videoMemPCI = (void *)(pciInfo.u.h0.base_registers_pci[1]); } } else { // Trio/Virge chips. - regsBase = di->pcii.u.h0.base_registers[0] + VirgeMmioRegBase; + regsBase = pciInfo.u.h0.base_registers[0] + VirgeMmioRegBase; regAreaSize = VirgeMmioRegSize; - videoRamAddr = di->pcii.u.h0.base_registers[0]; + videoRamAddr = pciInfo.u.h0.base_registers[0]; videoRamSize = 8 * 1024 * 1024; // 8 MB is max for Trio/Virge chips - si->videoMemPCI = (void *)(di->pcii.u.h0.base_registers_pci[0]); + si.videoMemPCI = (void *)(pciInfo.u.h0.base_registers_pci[0]); } // Map the MMIO register area. sprintf(areaName, DEVICE_FORMAT " regs", - di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function); + pciInfo.vendor_id, pciInfo.device_id, + pciInfo.bus, pciInfo.device, pciInfo.function); - si->regsArea = map_physical_memory(areaName, (void*)regsBase, regAreaSize, + si.regsArea = map_physical_memory(areaName, (void*)regsBase, regAreaSize, B_ANY_KERNEL_ADDRESS, 0, // neither read nor write, to hide it from user space apps - (void**)(&(di->regs))); + (void**)(&(di.regs))); - if (si->regsArea < 0) - return si->regsArea; // return error code + if (si.regsArea < 0) + return si.regsArea; // return error code // Map the video memory. sprintf(areaName, DEVICE_FORMAT " framebuffer", - di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function); + pciInfo.vendor_id, pciInfo.device_id, + pciInfo.bus, pciInfo.device, pciInfo.function); - si->videoMemArea = map_physical_memory( + si.videoMemArea = map_physical_memory( areaName, (void*)videoRamAddr, videoRamSize, B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC, B_READ_AREA + B_WRITE_AREA, - &(si->videoMemAddr)); + &(si.videoMemAddr)); - if (si->videoMemArea < 0) { + if (si.videoMemArea < 0) { // Try to map this time without write combining. - si->videoMemArea = map_physical_memory( + si.videoMemArea = map_physical_memory( areaName, (void*)videoRamAddr, videoRamSize, B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA + B_WRITE_AREA, - &(si->videoMemAddr)); + &(si.videoMemAddr)); } - TRACE("Video memory, area: %ld, addr: 0x%lX, size: %ld\n", si->videoMemArea, - (uint32)(si->videoMemAddr), videoRamSize); + TRACE("Video memory, area: %ld, addr: 0x%lX\n", si.videoMemArea, (uint32)(si.videoMemAddr)); // If there was an error, delete other areas. - if (si->videoMemArea < 0) { - delete_area(si->regsArea); - si->regsArea = -1; + if (si.videoMemArea < 0) { + delete_area(si.regsArea); + si.regsArea = -1; } - TRACE("leave map_device(); result: %ld\n", si->videoMemArea); - return si->videoMemArea; + TRACE("leave MapDevice(); result: %ld\n", si.videoMemArea); + return si.videoMemArea; } -static void -unmap_device(DeviceInfo* di) +static void +UnmapDevice(DeviceInfo& di) { - SharedInfo* si = di->si; - pci_info* pcii = &(di->pcii); + SharedInfo& si = *(di.sharedInfo); - TRACE("enter unmap_device()\n"); + TRACE("enter UnmapDevice()\n"); - // Disable memory mapped IO. - uint32 tmpUlong = get_pci(PCI_command, 2); - tmpUlong &= ~(PCI_command_io | PCI_command_memory); - set_pci(PCI_command, 2, tmpUlong); + if (si.regsArea >= 0) + delete_area(si.regsArea); + if (si.videoMemArea >= 0) + delete_area(si.videoMemArea); - if (si->regsArea >= 0) - delete_area(si->regsArea); - if (si->videoMemArea >= 0) - delete_area(si->videoMemArea); + si.regsArea = si.videoMemArea = -1; + si.videoMemAddr = NULL; + di.regs = NULL; - si->regsArea = si->videoMemArea = -1; - si->videoMemAddr = NULL; - di->regs = NULL; - - TRACE("exit unmap_device()\n"); + TRACE("exit UnmapDevice()\n"); } -static void -probe_devices(void) -{ - uint32 pci_index = 0; - uint32 count = 0; - DeviceInfo* di = pd->di; - const ChipInfo* pDevice; - - while ((count < MAX_DEVICES) - && ((*pci_bus->get_nth_pci_info)(pci_index, &(di->pcii)) == B_NO_ERROR)) { - - pDevice = FindDeviceMatch(di->pcii.vendor_id, di->pcii.device_id); - if (pDevice != NULL) { - // Compose device name. - sprintf(di->name, "graphics/" DEVICE_FORMAT, - di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function); - TRACE("probe_devices() match found; name: %s\n", di->name); - - pd->deviceNames[count] = di->name; - di->openCount = 0; // mark driver as available for R/W open - di->sharedArea = -1; // indicate shared area not yet created - di->si = NULL; - di->pChipInfo = pDevice; - di++; - count++; - } - - pci_index++; - } - - pd->count = count; - pd->deviceNames[pd->count] = NULL; // terminate list with null pointer - - TRACE("probe_devices() %ld supported devices\n", pd->count); -} - - -static uint32 -thread_interrupt_work(DeviceInfo* di) -{ - SharedInfo* si = di->si; - uint32 handled = B_HANDLED_INTERRUPT; - - // Release vertical blanking semaphore. - if (si->vertBlankSem >= 0) { - int32 blocked; - if ((get_sem_count(si->vertBlankSem, &blocked) == B_OK) && (blocked < 0)) { - release_sem_etc(si->vertBlankSem, -blocked, B_DO_NOT_RESCHEDULE); - handled = B_INVOKE_SCHEDULER; - } - } - return handled; -} - - -static int32 -s3_interrupt(void* data) +static int32 +InterruptHandler(void* data) { int32 handled = B_UNHANDLED_INTERRUPT; - DeviceInfo* di = (DeviceInfo*)data; - int32* flags = &(di->flags); + DeviceInfo& di = *((DeviceInfo*)data); + int32* flags = &(di.flags); // Is someone already handling an interrupt for this device? if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED) @@ -500,7 +322,18 @@ s3_interrupt(void* data) if (InterruptIsVBI()) { // was interrupt a VBI? ClearVBI(); // clear interrupt - handled = thread_interrupt_work(di); // release semaphore + handled = B_HANDLED_INTERRUPT; + + // Release vertical blanking semaphore. + sem_id& sem = di.sharedInfo->vertBlankSem; + + if (sem >= 0) { + int32 blocked; + if ((get_sem_count(sem, &blocked) == B_OK) && (blocked < 0)) { + release_sem_etc(sem, -blocked, B_DO_NOT_RESCHEDULE); + handled = B_INVOKE_SCHEDULER; + } + } } atomic_and(flags, ~SKD_HANDLER_INSTALLED); // note we're not in handler anymore @@ -509,219 +342,473 @@ s3_interrupt(void* data) } -// #pragma mark - Device Hooks - - -static status_t -open_hook(const char* name, uint32 flags, void** cookie) +static void +InitInterruptHandler(DeviceInfo& di) { - int32 index = 0; - SharedInfo* si; - thread_id thid; - thread_info thinfo; - status_t result = B_OK; - char sharedName[B_OS_NAME_LENGTH]; + SharedInfo& si = *(di.sharedInfo); - (void)flags; // avoid compiler warning for unused arg + TRACE("enter InitInterruptHandler()\n"); - TRACE("open_hook() - name: %s, cookie: 0x%08lx)\n", name, (uint32)cookie); + DisableVBI(); // disable & clear any pending interrupts + si.bInterruptAssigned = false; // indicate interrupt not assigned yet - // Find the device name in the list of devices. - while (pd->deviceNames[index] && (strcmp(name, pd->deviceNames[index]) != 0)) - index++; + // Create a semaphore for vertical blank management. + si.vertBlankSem = create_sem(0, di.name); + if (si.vertBlankSem < 0) + return; - DeviceInfo* di = &(pd->di[index]); + // Change the owner of the semaphores to the calling team (usually the + // app_server). This is required because apps can't aquire kernel + // semaphores. - // Make sure no one else has write access to the common data. - AQUIRE_BEN(pd->kernel); + thread_id threadID = find_thread(NULL); + thread_info threadInfo; + status_t status = get_thread_info(threadID, &threadInfo); + if (status == B_OK) + status = set_sem_owner(si.vertBlankSem, threadInfo.team); - if (di->openCount > 0) - goto mark_as_open; + // If there is a valid interrupt assigned, set up interrupts. - // Create the area for shared info with NO user-space read or write permissions, - // to prevent accidental damage. + if (status == B_OK && di.pciInfo.u.h0.interrupt_pin != 0x00 + && di.pciInfo.u.h0.interrupt_line != 0xff) { + // We have a interrupt line to use. - sprintf(sharedName, DEVICE_FORMAT " shared", - di->pcii.vendor_id, di->pcii.device_id, - di->pcii.bus, di->pcii.device, di->pcii.function); + status = install_io_interrupt_handler(di.pciInfo.u.h0.interrupt_line, + InterruptHandler, (void*)(&di), 0); - di->sharedArea = create_area(sharedName, (void**) &(di->si), B_ANY_KERNEL_ADDRESS, - ((sizeof(SharedInfo) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), - B_FULL_LOCK, 0); - if (di->sharedArea < 0) { - result = di->sharedArea; // return error - goto done; + if (status == B_OK) + si.bInterruptAssigned = true; // we can use interrupt related functions } - si = di->si; + if (status != B_OK) { + // Interrupt does not exist; thus delete semaphore as it won't be used. + delete_sem(si.vertBlankSem); + si.vertBlankSem = -1; + } +} - si->vendorID = di->pcii.vendor_id; - si->deviceID = di->pcii.device_id; - si->revision = di->pcii.revision; - si->chipType = di->pChipInfo->chipType; - strcpy(si->chipName, di->pChipInfo->chipName); + +static status_t +InitDevice(DeviceInfo& di) +{ + // Perform initialization and mapping of the device, and return B_OK if + // sucessful; else, return error code. + + // Create the area for shared info with NO user-space read or write + // permissions, to prevent accidental damage. + + TRACE("enter InitDevice()\n"); + + pci_info& pciInfo = di.pciInfo; + char sharedName[B_OS_NAME_LENGTH]; + + sprintf(sharedName, DEVICE_FORMAT " shared", + pciInfo.vendor_id, pciInfo.device_id, + pciInfo.bus, pciInfo.device, pciInfo.function); + + di.sharedArea = create_area(sharedName, (void**) &(di.sharedInfo), + B_ANY_KERNEL_ADDRESS, + ((sizeof(SharedInfo) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), + B_FULL_LOCK, 0); + if (di.sharedArea < 0) + return di.sharedArea; // return error code + + SharedInfo& si = *(di.sharedInfo); + + si.vendorID = pciInfo.vendor_id; + si.deviceID = pciInfo.device_id; + si.revision = pciInfo.revision; + si.chipType = di.pChipInfo->chipType; + strcpy(si.chipName, di.pChipInfo->chipName); // Trio64 and Trio64V+ chips have the same ID but different revision numbers. // Since the Trio64V+ supports MMIO, better performance can be obtained // from it if it is distinguished from the Trio64. - if (si->chipType == S3_TRIO64 && si->revision & 0x40) { - si->chipType = S3_TRIO64_VP; - strcpy(si->chipName, "Trio64 V+"); + if (si.chipType == S3_TRIO64 && si.revision & 0x40) { + si.chipType = S3_TRIO64_VP; + strcpy(si.chipName, "Trio64 V+"); } - - result = map_device(di); - if (result < 0) - goto free_shared; - - result = B_OK; - - DisableVBI(); // disable & clear any pending interrupts - si->bInterruptAssigned = false; // indicate interrupt not assigned yet - - // Create a semaphore for vertical blank management. - si->vertBlankSem = create_sem(0, di->name); - if (si->vertBlankSem < 0) - goto mark_as_open; - - // Change the owner of the semaphores to the opener's team. - // This is required because apps can't aquire kernel semaphores. - thid = find_thread(NULL); - get_thread_info(thid, &thinfo); - set_sem_owner(si->vertBlankSem, thinfo.team); - - // If there is a valid interrupt assigned, set up interrupts. - - if ((di->pcii.u.h0.interrupt_pin == 0x00) || - (di->pcii.u.h0.interrupt_line == 0xff) || // no IRQ assigned - (di->pcii.u.h0.interrupt_line <= 0x02)) { // system IRQ assigned - // Interrupt does not exist; thus delete semaphore as it won't be used. - delete_sem(si->vertBlankSem); - si->vertBlankSem = -1; - } else { - result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, s3_interrupt, (void*)di, 0); - if (result != B_OK) { - // Delete semaphore as it won't be used. - delete_sem(si->vertBlankSem); - si->vertBlankSem = -1; - } else { - // Inform accelerant(s) we can use interrupt related functions. - si->bInterruptAssigned = true; - } + status_t status = MapDevice(di); + if (status < 0) { + delete_area(di.sharedArea); + di.sharedArea = -1; + di.sharedInfo = NULL; + return status; // return error code } -mark_as_open: - di->openCount++; // mark device open - *cookie = di; // send cookie to opener - goto done; + InitInterruptHandler(di); -free_shared: - delete_area(di->sharedArea); - di->sharedArea = -1; - di->si = NULL; - -done: - // End of critical section. - RELEASE_BEN(pd->kernel); - - TRACE("open_hook() returning 0x%08lx\n", result); - return result; -} - - -static status_t -read_hook(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 -write_hook(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 -close_hook(void* dev) -{ - (void)dev; // avoid compiler warning for unused arg - - TRACE("close_hook()\n"); - return B_NO_ERROR; -} - - -static status_t -free_hook(void* dev) -{ - DeviceInfo* di = (DeviceInfo*)dev; - SharedInfo* si = di->si; - - TRACE("enter free_hook()\n"); - - AQUIRE_BEN(pd->kernel); // lock driver - - // If opened multiple times, decrement the open count and exit. - if (di->openCount > 1) - goto unlock_and_exit; - - DisableVBI(); // disable & clear any pending interrupts - - if (si->bInterruptAssigned) { - remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, s3_interrupt, di); - } - - // Delete the semaphores, ignoring any errors because the owning team may have died. - if (si->vertBlankSem >= 0) - delete_sem(si->vertBlankSem); - si->vertBlankSem = -1; - - unmap_device(di); // free regs and frame buffer areas - - delete_area(di->sharedArea); - di->sharedArea = -1; - di->si = NULL; - -unlock_and_exit: - if (di->openCount > 0) - di->openCount--; // mark device available - - RELEASE_BEN(pd->kernel); // unlock driver - - TRACE("exit free_hook()\n"); + TRACE("Interrupt assigned: %s\n", si.bInterruptAssigned ? "yes" : "no"); return B_OK; } -static status_t -control_hook(void* dev, uint32 msg, void* buf, size_t len) +static const ChipInfo* +GetNextSupportedDevice(uint32& pciIndex, pci_info& pciInfo) { - DeviceInfo* di = (DeviceInfo*)dev; + // 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) { + pciIndex++; + return pDevice; // matching device/chip found + } + + pDevice++; + } + } + + pciIndex++; + } + + return NULL; // no supported device found found +} + + + +#ifdef __HAIKU__ + +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: %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; +} + +#endif // __HAIKU__ + + + +// #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. + + if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI) != B_OK) + return B_ERROR; // unable to access PCI bus + + // 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. + + if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI) != B_OK) + return B_ERROR; + + status_t status = gLock.Init("S3 driver lock"); + if (status < B_OK) + 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.pChipInfo = pDevice; + count++; + } + + 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_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 index = 0; + while (gDeviceNames[index] != NULL) { + if (strcmp(name, gDeviceNames[index]) == 0) + return &gDeviceHooks; + index++; + } + + 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 index = 0; + while (gDeviceNames[index] != NULL && (strcmp(name, gDeviceNames[index]) != 0)) + index++; + + if (gDeviceNames[index] == NULL) + return B_BAD_VALUE; // device name not found in list of devices + + DeviceInfo& di = gDeviceInfo[index]; + + gLock.Acquire(); // make sure no one else has write access to common data + + if (di.openCount == 0) + status = InitDevice(di); + + 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); + SharedInfo& si = *(di.sharedInfo); + pci_info& pciInfo = di.pciInfo; + + TRACE("enter device_free()\n"); + + gLock.Acquire(); // lock driver + + // If opened multiple times, merely decrement the open count and exit. + + if (di.openCount <= 1) { + DisableVBI(); // disable & clear any pending interrupts + + if (si.bInterruptAssigned) { + remove_io_interrupt_handler(pciInfo.u.h0.interrupt_line, InterruptHandler, &di); + } + + // Delete the semaphores, ignoring any errors because the owning team may have died. + if (si.vertBlankSem >= 0) + delete_sem(si.vertBlankSem); + si.vertBlankSem = -1; + + UnmapDevice(di); // free regs and frame buffer areas + + delete_area(di.sharedArea); + di.sharedArea = -1; + di.sharedInfo = NULL; + } + + 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* buf, size_t len) +{ + DeviceInfo& di = *((DeviceInfo*)dev); (void)len; // avoid compiler warning for unused arg +// TRACE("device_ioctl(); ioctl: %lu, buf: 0x%08lx, len: %lu\n", msg, (uint32)buf, len); + switch (msg) { case B_GET_ACCELERANT_SIGNATURE: strcpy((char*)buf, "s3.accelerant"); return B_OK; case S3_DEVICE_NAME: - strncpy((char*)buf, di->name, B_OS_NAME_LENGTH); + strncpy((char*)buf, di.name, B_OS_NAME_LENGTH); ((char*)buf)[B_OS_NAME_LENGTH -1] = '\0'; return B_OK; @@ -729,7 +816,70 @@ control_hook(void* dev, uint32 msg, void* buf, size_t len) { S3GetPrivateData* gpd = (S3GetPrivateData*)buf; if (gpd->magic == S3_PRIVATE_DATA_MAGIC) { - gpd->sharedInfoArea = di->sharedArea; + gpd->sharedInfoArea = di.sharedArea; + return B_OK; + } + break; + } + + case S3_GET_EDID: + { +#ifdef __HAIKU__ + S3GetEDID* ged = (S3GetEDID*)buf; + if (ged->magic == S3_PRIVATE_DATA_MAGIC) { + edid1_raw rawEdid; + status_t status = GetEdidFromBIOS(rawEdid); + if (status == B_OK) + user_memcpy(&ged->rawEdid, &rawEdid, sizeof(rawEdid)); + return status; + } +#else + return B_UNSUPPORTED; +#endif + break; + } + + case S3_GET_PIO: + { + S3GetSetPIO* gsp = (S3GetSetPIO*)buf; + if (gsp->magic == S3_PRIVATE_DATA_MAGIC) { + switch (gsp->size) { + case 1: + gsp->value = gPCI->read_io_8(gsp->offset); + break; + case 2: + gsp->value = gPCI->read_io_16(gsp->offset); + break; + case 4: + gsp->value = gPCI->read_io_32(gsp->offset); + break; + default: + TRACE("device_ioctl() S3_GET_PIO invalid size: %ld\n", gsp->size); + return B_ERROR; + } + return B_OK; + } + break; + } + + case S3_SET_PIO: + { + S3GetSetPIO* gsp = (S3GetSetPIO*)buf; + if (gsp->magic == S3_PRIVATE_DATA_MAGIC) { + switch (gsp->size) { + case 1: + gPCI->write_io_8(gsp->offset, gsp->value); + break; + case 2: + gPCI->write_io_16(gsp->offset, gsp->value); + break; + case 4: + gPCI->write_io_32(gsp->offset, gsp->value); + break; + default: + TRACE("device_ioctl() S3_SET_PIO invalid size: %ld\n", gsp->size); + return B_ERROR; + } return B_OK; } break; @@ -746,54 +896,7 @@ control_hook(void* dev, uint32 msg, void* buf, size_t len) } return B_OK; } - - case S3_GET_PIO: - { - S3GetSetPIO* gsp = (S3GetSetPIO*)buf; - if (gsp->magic == S3_PRIVATE_DATA_MAGIC) { - switch (gsp->size) { - case 1: - gsp->value = pci_bus->read_io_8(gsp->offset); - break; - case 2: - gsp->value = pci_bus->read_io_16(gsp->offset); - break; - case 4: - gsp->value = pci_bus->read_io_32(gsp->offset); - break; - default: - TRACE("control_hook() S3_GET_PIO invalid size: %ld\n", gsp->size); - return B_ERROR; - } - return B_OK; - } - break; - } - - case S3_SET_PIO: - { - S3GetSetPIO* gsp = (S3GetSetPIO*)buf; - if (gsp->magic == S3_PRIVATE_DATA_MAGIC) { - switch (gsp->size) { - case 1: - pci_bus->write_io_8(gsp->offset, gsp->value); - break; - case 2: - pci_bus->write_io_16(gsp->offset, gsp->value); - break; - case 4: - pci_bus->write_io_32(gsp->offset, gsp->value); - break; - default: - TRACE("control_hook() S3_SET_PIO invalid size: %ld\n", gsp->size); - return B_ERROR; - } - return B_OK; - } - break; - } } return B_DEV_INVALID_IOCTL; } -