Windows CE LCD显示驱动简析(2)(基于WinCE5.0 SMDK2410 BSP的LCD显示设备驱动)

现在就来看看我们需要实现的GPE继承类S3C2410DISP.
在ddi_if_cpp(/WINCE500/PUBLIC/COMMON/OAK/DRIVERS/DISPLAY/GPE)实现了一个SafeGetGPE函数,其代码如下:
GPE * SafeGetGPE( HANDLE hDriver ) { GPE * pGPE = NULL; __try { if ((hDriver != (HANDLE)SINGLE_DRIVER_HANDLE) && (pfnGetGPEPerCard != NULL)) { pGPE = (*pfnGetGPEPerCard)((int)hDriver); } else { pGPE = GetGPE(); } } __except (EXCEPTION_EXECUTE_HANDLER) { pGPE = NULL; } return pGPE; }
这个函数考虑了多显示器的情况,而我们只有一个显示器,因此该函数实际上只是调用GetGPE函数,并将后者的返回值作为自己的返回值返回给调用者.
而GetGPE就实现在s3c2410x_lcd.cpp中,代码如下:
GPE *GetGPE(void) { if (!gGPE) { gGPE = new S3C2410DISP(); } return gGPE; }
在GetGPE函数中,获得了一个新生成的S3C2410DISP类实例的指针.在以后使用gGPE所指向的数据或函数时,得到的都是S3C2410DISP类型变量的成员函数和函数,只有在S3C2410DISP未定义的部分,才使用父类或更上级类的数据成员和成员函数.
在CE5.0的SMDK2410 BSP中,S3C2410DISP是GPE的继承类,而在CE 6.0的DEVICEEMULATOR BSP中的S3C2410DISP是DDGPE的继承类.DDGPE是GPE的继承类,支持了DirectDraw,由于2410LCD控制器不支持DirectDraw,实际上DDGPE和GPE继承类没有区别.
获取GPE指针后,在微软已经实现的DDI函数中就会调用GPE类的成员函数来获取和实际显示硬件相关的信息和进行相应的操作.
接下来我们就来看看S3C2410DISP的具体成员:
1.S3C2410DISP的构造函数S3C2410DISP
这个函数首先设置一些显示参数,如LCD尺寸(240*320),缓冲区大小等.然和调用InitializeHardware进行LCD控制器初始化.
然后创建GPESurf类的实例m_pPrimarySurface,该类是GPE类实例的首要显示表面.显示表面的实质是显示屏幕上的所有像素点颜色数据在内存中的镜像.
接着设置光标的属性,如果设置了CLEARTYPE(这里没有定义),则读取注册表Gamma亮度属性(如果有的话,否则使用默认值1500),这里实际用的就是默认值,使用比较低的亮度来增加字体的对比度.最后设置24位颜色掩码(static ulong gBitMasks[] = { 0xF800, 0x07E0, 0x001F };  // 565 MODE)(实际上在SetMode函数中设置)
代码如下:
S3C2410DISP::S3C2410DISP (void) { RETAILMSG(0, (TEXT("++S3C2410DISP::S3C2410DISP/r/n"))); RETAILMSG(1, (TEXT("++S3C2410DISP::S3C2410DISP for GEC2410 LCD/r/n"))); // setup up display mode related constants m_nScreenWidth = 240; m_nScreenHeight = 320; m_colorDepth = 16; m_cbScanLineLength = m_nScreenWidth * 2; m_FrameBufferSize = m_nScreenHeight * m_cbScanLineLength; // memory map register access window, frame buffer, and program LCD controller InitializeHardware(); #ifdef ROTATE m_iRotate = 0; SetRotateParms(); #endif //ROTATE // setup ModeInfo structure m_ModeInfo.modeId = 0; m_ModeInfo.width = m_nScreenWidth; m_ModeInfo.height = m_nScreenHeight; m_ModeInfo.Bpp = m_colorDepth; m_ModeInfo.format = gpe16Bpp; m_ModeInfo.frequency = 60; // ? m_pMode = &m_ModeInfo; // allocate primary display surface #ifdef ROTATE m_pPrimarySurface = new GPESurfRotate(m_nScreenWidthSave, m_nScreenHeightSave, (void*)(m_VirtualFrameBuffer), m_cbScanLineLength, m_ModeInfo.format); #else m_pPrimarySurface = new GPESurf(m_nScreenWidth, m_nScreenHeight, (void*)(m_VirtualFrameBuffer), m_cbScanLineLength, m_ModeInfo.format); #endif //!ROTATE if (m_pPrimarySurface) { memset ((void*)m_pPrimarySurface->Buffer(), 0x0, m_FrameBufferSize); } // init cursor related vars m_CursorVisible = FALSE; m_CursorDisabled = TRUE; m_CursorForcedOff = FALSE; memset (&m_CursorRect, 0x0, sizeof(m_CursorRect)); m_CursorBackingStore = NULL; m_CursorXorShape = NULL; m_CursorAndShape = NULL; #ifdef CLEARTYPE HKEY hKey; DWORD dwValue; ULONG ulGamma = DEFAULT_CT_GAMMA; if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE,szGamma,0, NULL,0,0,0,&hKey,&dwValue)) { if (dwValue == REG_OPENED_EXISTING_KEY) { DWORD dwType = REG_DWORD; DWORD dwSize = sizeof(LONG); if (ERROR_SUCCESS == RegQueryValueEx(hKey,szGammaValue,0,&dwType,(BYTE *)&dwValue,&dwSize)) { ulGamma = dwValue; } } else if (dwValue == REG_CREATED_NEW_KEY ) { RegSetValueEx(hKey,szGammaValue,0,REG_DWORD,(BYTE *)&ulGamma,sizeof(DWORD)); } RegCloseKey(hKey); } SetClearTypeBltGamma(ulGamma); SetClearTypeBltMasks(gBitMasks[0], gBitMasks[1], gBitMasks[2]); #endif //CLEARTYPE RETAILMSG(0, (TEXT("--S3C2410DISP::S3C2410DISP/r/n"))); }
其中调用了InitializeHardware来进行硬件初始化,InitializeHardware首先读取注册表获取物理和虚拟显示内存地址
即注册表中的
 "LCDVirtualFrameBase"=dword:ac100000
 "LCDPhysicalFrameBase"=dword:30100000
然后调用InitializeLCDRegisters初始化LCD控制器,最后分配内存空间给显示区域.
void S3C2410DISP::InitializeHardware (void) { WORD *ptr; DWORD index; HKEY hkDisplay = NULL; DWORD dwLCDPhysicalFrameBase = 0; DWORD dwStatus, dwType, dwSize; RETAILMSG(0, (_T("++S3C2410DISP::InitializeHardware/r/n"))); // open the registry key and read our configuration dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, gszBaseInstance, 0, 0, &hkDisplay); dwType = REG_DWORD; if(dwStatus == ERROR_SUCCESS && dwType == REG_DWORD) { dwSize = sizeof(DWORD); dwStatus = RegQueryValueEx(hkDisplay, _T("LCDVirtualFrameBase"), NULL, &dwType, (LPBYTE) &gdwLCDVirtualFrameBase, &dwSize); } if(dwStatus == ERROR_SUCCESS && dwType == REG_DWORD) { dwSize = sizeof(DWORD); dwStatus = RegQueryValueEx(hkDisplay, _T("LCDPhysicalFrameBase"), NULL, &dwType, (LPBYTE) &dwLCDPhysicalFrameBase, &dwSize); } // close the registry key if(hkDisplay != NULL) { RegCloseKey(hkDisplay); } // did we get everything? if(dwStatus != ERROR_SUCCESS) { RETAILMSG(0, (_T("SALCD2: InitializeHardware: couldn't get registry configuration/r/n"))); return; } // Initialize LCD registers. if (!InitializeLCDRegisters(dwLCDPhysicalFrameBase)) { RETAILMSG(0, (_T("SALCD2: InitializeHardware: failed to initialize LCD registers./r/n"))); return; } // map frame buffer into process space memory m_VirtualFrameBuffer = (DWORD)VirtualAlloc(0, (0x40000), MEM_RESERVE, PAGE_NOACCESS); if (m_VirtualFrameBuffer == NULL) { RETAILMSG(0,(TEXT("m_VirtualFrameBuffer is not allocated/n/r"))); return; } else if (!VirtualCopy((PVOID)m_VirtualFrameBuffer, (PVOID)gdwLCDVirtualFrameBase, (0x40000), PAGE_READWRITE | PAGE_NOCACHE)) { RETAILMSG(0, (TEXT("m_VirtualFrameBuffer is not mapped/n/r"))); VirtualFree((PVOID)m_VirtualFrameBuffer, 0, MEM_RELEASE); return; } RETAILMSG(0, (TEXT("m_VirtualFrameBuffer is mapped at %x(PHY : %x)/n/r"), m_VirtualFrameBuffer, gdwLCDVirtualFrameBase)); RETAILMSG(0, (TEXT("Clearing frame buffer !!!/n/r"))); ptr = (WORD *)m_VirtualFrameBuffer; // clear rest of frame buffer out for (index = 0; index < 320*240; index++) { if(index < 3200) { ptr[index] = 0xf800; } else if(index < 6400) { ptr[index] = 0x07e0; } else if(index < 9600) { ptr[index] = 0x001f; } else { ptr[index] = 0xffff; } } RETAILMSG(0, (_T("--S3C2410DISP::InitializeHardware/r/n"))); }
InitializeLCDRegisters就是初始化了LCD控制寄存器,具体内容和在eboot中的处理基本是一样的.
static BOOL InitializeLCDRegisters(DWORD dwPhysicalFrameBase) { volatile S3C2410X_IOPORT_REG *s2410IOP = NULL; volatile S3C2410X_LCD_REG *s2410LCD = NULL; PHYSICAL_ADDRESS pa; // Map the s3c2410x register pointers. // pa.QuadPart = S3C2410X_BASE_REG_PA_IOPORT; s2410IOP = (S3C2410X_IOPORT_REG *) MmMapIoSpace(pa, sizeof(S3C2410X_IOPORT_REG), FALSE); pa.QuadPart = S3C2410X_BASE_REG_PA_LCD; s2410LCD = (S3C2410X_LCD_REG *) MmMapIoSpace(pa, sizeof(S3C2410X_LCD_REG), FALSE); if (!s2410IOP || !s2410LCD) { RETAILMSG(1, (TEXT("ERROR: s3c2410x_lcd: InitializeLCDRegisters failed./r/n"))); return(FALSE); } // Set up the LCD controller registers to display a power-on bitmap image. // s2410IOP->GPCUP = 0xFFFFFFFF; s2410IOP->GPCCON = 0xAAAA56A9; s2410IOP->GPDUP = 0xFFFFFFFF; s2410IOP->GPDCON = 0xAAAAAAAA; s2410LCD->LCDCON1 = (5 << 8) | /* VCLK = HCLK / ((CLKVAL + 1) * 2) -> About 7 Mhz */ (0 << 7) | /* 0 : Each Frame */ (3 << 5) | /* TFT LCD Pannel */ (12 << 1) | /* 16bpp Mode */ (0 << 0) ; /* Disable LCD Output */ s2410LCD->LCDCON2 = (2 << 24) | /* VBPD : 1 */ (LCD_LINEVAL_TFT << 14) | /* Vertical Size : 320 - 1 */ (2 << 6) | /* VFPD : 2 */ (4 << 0) ; /* VSPW : 1 */ s2410LCD->LCDCON3 = (8 << 19) | /* HBPD : 6 */ (LCD_HOZVAL_TFT << 8) | /* HOZVAL_TFT : 240 - 1 */ (8 << 0) ; /* HFPD : 2 */ s2410LCD->LCDCON4 = (LCD_MVAL << 8) | /* MVAL : 13 */ (6 << 0) ; /* HSPW : 4 */ s2410LCD->LCDCON5 = (0 << 12) | /* BPP24BL : LSB valid */ (1 << 11) | /* FRM565 MODE : 5:6:5 Format */ (0 << 10) | /* INVVCLK : VCLK Falling Edge */ (0 << 9) | /* INVVLINE : Inverted Polarity */ (0 << 8) | /* INVVFRAME : Inverted Polarity */ (0 << 7) | /* INVVD : Normal */ (0 << 6) | /* INVVDEN : Normal */ (0 << 5) | /* INVPWREN : Normal */ (0 << 4) | /* INVENDLINE : Normal */ (0 << 3) | /* PWREN : Disable PWREN */ (0 << 2) | /* ENLEND : Disable LEND signal */ (0 << 1) | /* BSWP : Swap Disable */ (1 << 0) ; /* HWSWP : Swap Enable */ s2410LCD->LCDSADDR1 = ((dwPhysicalFrameBase >> 22) << 21) | ((M5D(dwPhysicalFrameBase >> 1)) << 0); s2410LCD->LCDSADDR2 = M5D((dwPhysicalFrameBase + (LCD_XSIZE_TFT * LCD_YSIZE_TFT * 2)) >> 1); s2410LCD->LCDSADDR3 = (((LCD_XSIZE_TFT - LCD_XSIZE_TFT) / 1) << 11) | (LCD_XSIZE_TFT / 1); s2410LCD->LPCSEL |= ~0x7; s2410LCD->TPAL = 0x0; s2410LCD->LCDCON1 |= 1; // Unmap register buffers. // MmUnmapIoSpace((PVOID)s2410IOP, 0); MmUnmapIoSpace((PVOID)s2410LCD, 0); return(TRUE); }
2.SetMode
SetMode成员函数负责设置一个显示设备及其驱动程序能支持的显示模式.
通过调用EngCreatePalette来设置RGB模式:
static ulong gBitMasks[] = { 0xF800, 0x07E0, 0x001F };  // 565 MODE
modeId是要设置的显示工作模式的索引号,由于只有一个显示设备,该值必须为0.
SCODE S3C2410DISP::SetMode (INT modeId, HPALETTE *palette) { RETAILMSG(0, (TEXT("++S3C2410DISP::SetMode/r/n"))); if (modeId != 0) { RETAILMSG(0, (TEXT("S3C2410DISP::SetMode Want mode %d, only have mode 0/r/n"),modeId)); return E_INVALIDARG; } if (palette) { *palette = EngCreatePalette (PAL_BITFIELDS, 0, NULL, gBitMasks[0], gBitMasks[1], gBitMasks[2]); } RETAILMSG(0, (TEXT("--S3C2410DISP::SetMode/r/n"))); return S_OK; }
3.GetModeInfo
GetModeInfo函数用于供调用者获取显示设备当前正在生效的显示工作模式,在S3C2410DISP类的GetModeInfo函数就是把m_ModeInfo成员所记录的GPEMode数据复制给输出参数mode.函数另一个参数modeNumber指定要获取的模式的索引号,在S3C2410DISP类中,它必须取值为0,因为当前的显示设备只支持一种显示模式.
SCODE S3C2410DISP::GetModeInfo(GPEMode *mode, INT modeNumber) { RETAILMSG(0, (TEXT("++S3C2410DISP::GetModeInfo/r/n"))); if (modeNumber != 0) { return E_INVALIDARG; } *mode = m_ModeInfo; RETAILMSG(0, (TEXT("--S3C2410DISP::GetModeInfo/r/n"))); return S_OK; }
4.NumModes
NumModes返回设备驱动程序所能支持的显示工作模式的数量.这里显然只能为1.函数简单返回1.
int S3C2410DISP::NumModes() { RETAILMSG(0, (TEXT("++S3C2410DISP::NumModes/r/n"))); RETAILMSG(0, (TEXT("--S3C2410DISP::NumModes/r/n"))); return 1; }
5.CursorOn
显示光标.
m_CursorForcedOff:记录当前系统中是否暂时关断鼠标显示.
m_CursorDisabled:记录系统是否禁用光标.
m_CursorVisible:指示屏幕上光标当前在显示屏幕上是否可见.
当这个变量都不为真时,即光标处于显示状态.然和计算光标所处位置,如有有旋转设置,则计算相应的新的坐标.
void S3C2410DISP::CursorOn (void) { UCHAR *ptrScreen = (UCHAR*)m_pPrimarySurface->Buffer(); UCHAR *ptrLine; UCHAR *cbsLine; #ifndef ROTATE UCHAR *xorLine; UCHAR *andLine; #endif //!ROTATE int x, y; if (!m_CursorForcedOff && !m_CursorDisabled && !m_CursorVisible) { #ifdef ROTATE RECTL rSave; int iRotate; #endif //ROTATE if (!m_CursorBackingStore) { RETAILMSG(0, (TEXT("S3C2410DISP::CursorOn - No backing store available/r/n"))); return; } #ifdef ROTATE rSave = m_CursorRect; RotateRectl(&m_CursorRect); #endif //ROTATE for (y = m_CursorRect.top; y < m_CursorRect.bottom; y++) { if (y < 0) { continue; } #ifdef ROTATE if (y >= m_nScreenHeightSave) #else if (y >= m_nScreenHeight) #endif //ROTATE { break; } ptrLine = &ptrScreen[y * m_pPrimarySurface->Stride()]; cbsLine = &m_CursorBackingStore[(y - m_CursorRect.top) * (m_CursorSize.x * (m_colorDepth >> 3))]; #ifndef ROTATE xorLine = &m_CursorXorShape[(y - m_CursorRect.top) * m_CursorSize.x]; andLine = &m_CursorAndShape[(y - m_CursorRect.top) * m_CursorSize.x]; #endif //!ROTATE for (x = m_CursorRect.left; x < m_CursorRect.right; x++) { if (x < 0) { continue; } #ifdef ROTATE if (x >= m_nScreenWidthSave) #else if (x >= m_nScreenWidth) #endif //!ROTATE { break; } #ifdef ROTATE switch (m_iRotate) { case DMDO_0: iRotate = (y - m_CursorRect.top)*m_CursorSize.x + x - m_CursorRect.left; break; case DMDO_90: iRotate = (x - m_CursorRect.left)*m_CursorSize.x + m_CursorSize.y - 1 - (y - m_CursorRect.top); break; case DMDO_180: iRotate = (m_CursorSize.y - 1 - (y - m_CursorRect.top))*m_CursorSize.x + m_CursorSize.x - 1 - (x - m_CursorRect.left); break; case DMDO_270: iRotate = (m_CursorSize.x -1 - (x - m_CursorRect.left))*m_CursorSize.x + y - m_CursorRect.top; break; default: iRotate = (y - m_CursorRect.top)*m_CursorSize.x + x - m_CursorRect.left; break; } #endif //ROTATE cbsLine[(x - m_CursorRect.left) * (m_colorDepth >> 3)] = ptrLine[x * (m_colorDepth >> 3)]; #ifdef ROTATE ptrLine[x * (m_colorDepth >> 3)] &= m_CursorAndShape[iRotate]; ptrLine[x * (m_colorDepth >> 3)] ^= m_CursorXorShape[iRotate]; #else ptrLine[x * (m_colorDepth >> 3)] &= andLine[x - m_CursorRect.left]; ptrLine[x * (m_colorDepth >> 3)] ^= xorLine[x - m_CursorRect.left]; #endif //ROTATE if (m_colorDepth > 8) { cbsLine[(x - m_CursorRect.left) * (m_colorDepth >> 3) + 1] = ptrLine[x * (m_colorDepth >> 3) + 1]; #ifdef ROTATE ptrLine[x * (m_colorDepth >> 3) + 1] &= m_CursorAndShape[iRotate]; ptrLine[x * (m_colorDepth >> 3) + 1] ^= m_CursorXorShape[iRotate]; #else ptrLine[x * (m_colorDepth >> 3) + 1] &= andLine[x - m_CursorRect.left]; ptrLine[x * (m_colorDepth >> 3) + 1] ^= xorLine[x - m_CursorRect.left]; #endif //ROTATE if (m_colorDepth > 16) { cbsLine[(x - m_CursorRect.left) * (m_colorDepth >> 3) + 2] = ptrLine[x * (m_colorDepth >> 3) + 2]; #ifdef ROTATE ptrLine[x * (m_colorDepth >> 3) + 2] &= m_CursorAndShape[iRotate]; ptrLine[x * (m_colorDepth >> 3) + 2] ^= m_CursorXorShape[iRotate]; #else ptrLine[x * (m_colorDepth >> 3) + 2] &= andLine[x - m_CursorRect.left]; ptrLine[x * (m_colorDepth >> 3) + 2] ^= xorLine[x - m_CursorRect.left]; #endif //ROTATE } } } } #ifdef ROTATE m_CursorRect = rSave; #endif m_CursorVisible = TRUE; } }
6.CursorOff
关闭光标.
CursorOff最后设置m_CursorVisible = FALSE;来关闭光标的显示.
void S3C2410DISP::CursorOff (void) { UCHAR *ptrScreen = (UCHAR*)m_pPrimarySurface->Buffer(); UCHAR *ptrLine; UCHAR *cbsLine; int x, y; if (!m_CursorForcedOff && !m_CursorDisabled && m_CursorVisible) { #ifdef ROTATE RECTL rSave; #endif //ROTATE if (!m_CursorBackingStore) { RETAILMSG(0, (TEXT("S3C2410DISP::CursorOff - No backing store available/r/n"))); return; } #ifdef ROTATE rSave = m_CursorRect; RotateRectl(&m_CursorRect); #endif //ROTATE for (y = m_CursorRect.top; y < m_CursorRect.bottom; y++) { // clip to displayable screen area (top/bottom) if (y < 0) { continue; } #ifndef ROTATE if (y >= m_nScreenHeight) #else if (y >= m_nScreenHeightSave) #endif //!ROTATE { break; } ptrLine = &ptrScreen[y * m_pPrimarySurface->Stride()]; cbsLine = &m_CursorBackingStore[(y - m_CursorRect.top) * (m_CursorSize.x * (m_colorDepth >> 3))]; for (x = m_CursorRect.left; x < m_CursorRect.right; x++) { // clip to displayable screen area (left/right) if (x < 0) { continue; } #ifndef ROTATE if (x >= m_nScreenWidth) #else if (x>= m_nScreenWidthSave) #endif //!ROTATE { break; } ptrLine[x * (m_colorDepth >> 3)] = cbsLine[(x - m_CursorRect.left) * (m_colorDepth >> 3)]; if (m_colorDepth > 8) { ptrLine[x * (m_colorDepth >> 3) + 1] = cbsLine[(x - m_CursorRect.left) * (m_colorDepth >> 3) + 1]; if (m_colorDepth > 16) { ptrLine[x * (m_colorDepth >> 3) + 2] = cbsLine[(x - m_CursorRect.left) * (m_colorDepth >> 3) + 2]; } } } } #ifdef ROTATE m_CursorRect = rSave; #endif //ROTATE m_CursorVisible = FALSE; } }
7.SetPointerShape
SetPointerShape用于设置显示屏幕上鼠标光标的形状,图案和位置.
pMask参数所指向的显示表面是构成鼠标光标形状轮廓的与-异掩模位图.pColorSurf是指向显示表面包含鼠标光标的颜色图案的位图,这里没有使用,不支持彩色鼠标光标.xHot和yHot是鼠标光标的热点位置.cX和cY是光标在显示屏幕上的大小.
SCODE S3C2410DISP::SetPointerShape(GPESurf *pMask, GPESurf *pColorSurf, INT xHot, INT yHot, INT cX, INT cY) { UCHAR *andPtr; // input pointer UCHAR *xorPtr; // input pointer UCHAR *andLine; // output pointer UCHAR *xorLine; // output pointer char bAnd; char bXor; int row; int col; int i; int bitMask; RETAILMSG(0, (TEXT("S3C2410DISP::SetPointerShape(0x%X, 0x%X, %d, %d, %d, %d)/r/n"),pMask, pColorSurf, xHot, yHot, cX, cY)); // turn current cursor off CursorOff(); // release memory associated with old cursor if (m_CursorBackingStore) { delete (void*)m_CursorBackingStore; m_CursorBackingStore = NULL; } if (m_CursorXorShape) { delete (void*)m_CursorXorShape; m_CursorXorShape = NULL; } if (m_CursorAndShape) { delete (void*)m_CursorAndShape; m_CursorAndShape = NULL; } if (!pMask) // do we have a new cursor shape { m_CursorDisabled = TRUE; // no, so tag as disabled } else { m_CursorDisabled = FALSE; // yes, so tag as not disabled // allocate memory based on new cursor size m_CursorBackingStore = new UCHAR[(cX * (m_colorDepth >> 3)) * cY]; m_CursorXorShape = new UCHAR[cX * cY]; m_CursorAndShape = new UCHAR[cX * cY]; if (!m_CursorXorShape || !m_CursorAndShape) { return(ERROR_NOT_ENOUGH_MEMORY); } // store size and hotspot for new cursor m_CursorSize.x = cX; m_CursorSize.y = cY; m_CursorHotspot.x = xHot; m_CursorHotspot.y = yHot; andPtr = (UCHAR*)pMask->Buffer(); xorPtr = (UCHAR*)pMask->Buffer() + (cY * pMask->Stride()); // store OR and AND mask for new cursor for (row = 0; row < cY; row++) { andLine = &m_CursorAndShape[cX * row]; xorLine = &m_CursorXorShape[cX * row]; for (col = 0; col < cX / 8; col++) { bAnd = andPtr[row * pMask->Stride() + col]; bXor = xorPtr[row * pMask->Stride() + col]; for (bitMask = 0x0080, i = 0; i < 8; bitMask >>= 1, i++) { andLine[(col * 8) + i] = bAnd & bitMask ? 0xFF : 0x00; xorLine[(col * 8) + i] = bXor & bitMask ? 0xFF : 0x00; } } } } return S_OK; }
8.MovePointer

MovePointer用于将鼠标光标移动到指定的屏幕位置.参数xPosition和yPosition记录着光标到达新位置后的热点的坐标.
SCODE S3C2410DISP::MovePointer(INT xPosition, INT yPosition) { RETAILMSG(0, (TEXT("S3C2410DISP::MovePointer(%d, %d)/r/n"), xPosition, yPosition)); CursorOff(); if (xPosition != -1 || yPosition != -1) { // compute new cursor rect m_CursorRect.left = xPosition - m_CursorHotspot.x; m_CursorRect.right = m_CursorRect.left + m_CursorSize.x; m_CursorRect.top = yPosition - m_CursorHotspot.y; m_CursorRect.bottom = m_CursorRect.top + m_CursorSize.y; CursorOn(); } return S_OK; }
9.WaitForNotBusy
WaitForNotBusy用于等待显示设备空闲下来,直到显示设备可以接收新的操作指令WaitForNotBusy才返回.这个功能通常用于复杂而且功能强大的显示卡.而S3C2410的LCD控制器没有这么强的功能,因此该函数直接返回.
void S3C2410DISP::WaitForNotBusy(void) { RETAILMSG(0, (TEXT("S3C2410DISP::WaitForNotBusy/r/n"))); return; }
10.IsBusy

IsBusy用于查询显示设备是否正忙,如果忙返回非0值,空闲返回0.同WaitForNotBusy一样,用于功能强大的显示控制器,这里直接返回0.
int S3C2410DISP::IsBusy(void) { RETAILMSG(0, (TEXT("S3C2410DISP::IsBusy/r/n"))); return 0; }
11.GetPhysicalVideoMemory
GetPhysicalVideoMemory函数主要供DDHAL使用,用来获取显示内存的基地址和容量大小.
void S3C2410DISP::GetPhysicalVideoMemory(unsigned long *physicalMemoryBase, unsigned long *videoMemorySize) { RETAILMSG(0, (TEXT("S3C2410DISP::GetPhysicalVideoMemory/r/n"))); *physicalMemoryBase = gdwLCDVirtualFrameBase; *videoMemorySize = m_cbScanLineLength * m_nScreenHeight; }
12.AllocSurface
AllocSurface用于为显示设备构造显示表面,这里继承自GPE类.还有一种情况是继承自DDGPE类.这里即用于构造GPESurf类型的显示表面.
surface是输出参数,是构造所得的GPESurf对象指针的指针;width和height是要求显示表面的宽和高;format参数是构造显示表面的像素格式要求;surfaceFlags用于指定在哪里构造显示表面.
SCODE S3C2410DISP::AllocSurface(GPESurf **surface, INT width, INT height, EGPEFormat format, INT surfaceFlags) { RETAILMSG(0, (TEXT("S3C2410DISP::AllocSurface/r/n"))); if (surfaceFlags & GPE_REQUIRE_VIDEO_MEMORY) { return E_OUTOFMEMORY; } // Allocate from system memory *surface = new GPESurf(width, height, format); if (*surface != NULL) { // Check that the bits were allocated succesfully if (((*surface)->Buffer()) == NULL) { delete *surface; // Clean up } else { return S_OK; } } return E_OUTOFMEMORY; }
13.Line,WrappedEmulatedLine
Line函数用于在显示表面上画直线段.由于S3C2410的LCD控制器不具备硬件加速能力,所以Line函数实现在非首要显示表面上画线时使用依靠软件实现的默认画线函数GPE::EmulateLine;而在首要表面画线时,调用的是用户实现的WrappedEmulatedLine函数.封装的目的只是要处理如果所画直线的范围矩形与鼠标光标的范围矩形重叠时,要先暂时消隐光标显示,待画完直线后在回复光标.
Line:
SCODE S3C2410DISP::Line(GPELineParms *lineParameters, EGPEPhase phase) { RETAILMSG(0, (TEXT("S3C2410DISP::Line/r/n"))); if (phase == gpeSingle || phase == gpePrepare) { if ((lineParameters->pDst != m_pPrimarySurface)) { lineParameters->pLine = EmulatedLine; } else { lineParameters->pLine = (SCODE (GPE::*)(struct GPELineParms *)) WrappedEmulatedLine; } } return S_OK; }
WrappedEmulatedLine
SCODE S3C2410DISP::WrappedEmulatedLine (GPELineParms *lineParameters) { SCODE retval; RECT bounds; int N_plus_1; // Minor length of bounding rect + 1 // calculate the bounding-rect to determine overlap with cursor if (lineParameters->dN) // The line has a diagonal component (we'll refresh the bounding rect) { N_plus_1 = 2 + ((lineParameters->cPels * lineParameters->dN) / lineParameters->dM); } else { N_plus_1 = 1; } switch(lineParameters->iDir) { case 0: bounds.left = lineParameters->xStart; bounds.top = lineParameters->yStart; bounds.right = lineParameters->xStart + lineParameters->cPels + 1; bounds.bottom = bounds.top + N_plus_1; break; case 1: bounds.left = lineParameters->xStart; bounds.top = lineParameters->yStart; bounds.bottom = lineParameters->yStart + lineParameters->cPels + 1; bounds.right = bounds.left + N_plus_1; break; case 2: bounds.right = lineParameters->xStart + 1; bounds.top = lineParameters->yStart; bounds.bottom = lineParameters->yStart + lineParameters->cPels + 1; bounds.left = bounds.right - N_plus_1; break; case 3: bounds.right = lineParameters->xStart + 1; bounds.top = lineParameters->yStart; bounds.left = lineParameters->xStart - lineParameters->cPels; bounds.bottom = bounds.top + N_plus_1; break; case 4: bounds.right = lineParameters->xStart + 1; bounds.bottom = lineParameters->yStart + 1; bounds.left = lineParameters->xStart - lineParameters->cPels; bounds.top = bounds.bottom - N_plus_1; break; case 5: bounds.right = lineParameters->xStart + 1; bounds.bottom = lineParameters->yStart + 1; bounds.top = lineParameters->yStart - lineParameters->cPels; bounds.left = bounds.right - N_plus_1; break; case 6: bounds.left = lineParameters->xStart; bounds.bottom = lineParameters->yStart + 1; bounds.top = lineParameters->yStart - lineParameters->cPels; bounds.right = bounds.left + N_plus_1; break; case 7: bounds.left = lineParameters->xStart; bounds.bottom = lineParameters->yStart + 1; bounds.right = lineParameters->xStart + lineParameters->cPels + 1; bounds.top = bounds.bottom - N_plus_1; break; default: RETAILMSG(0, (TEXT("Invalid direction: %d/r/n"), lineParameters->iDir)); return E_INVALIDARG; } // check for line overlap with cursor and turn off cursor if overlaps if (m_CursorVisible && !m_CursorDisabled && m_CursorRect.top < bounds.bottom && m_CursorRect.bottom > bounds.top && m_CursorRect.left < bounds.right && m_CursorRect.right > bounds.left) { CursorOff(); m_CursorForcedOff = TRUE; } // do emulated line retval = EmulatedLine (lineParameters); // se if cursor was forced off because of overlap with line bouneds and turn back on if (m_CursorForcedOff) { m_CursorForcedOff = FALSE; CursorOn(); } return retval; }
14.BltPrepare,BltComplete
BltPrepare和BltComplete都是GPE类的纯虚函数,用户定义的继承类必须实现这两个函数.分别为块传输做准备工作和为块传输"打扫战场".BltPrepare函数负责向GPEBltParms*类型的参数传递一个负责具体块传输操作的函数指针.由于不支持硬件加速,这里无法做任何特殊处理.只是将GPE默认的块传输函数复制给GPEBltParms结构的pBlt成员.GPE的EmulatedBlt函数类似于EmulatedLine函数,是GPE类自带的用软件模拟实现的不具备硬件加速能力的默认块传输函数.BltPrepare的其余代码就是处理如果块传输操作的源或目的显示表面其中有一个是首要显示表面,并且块传输区域的范围矩形与屏幕上鼠标光标的范围矩形发生重叠,则要暂时消隐鼠标光标.暂时消隐掉的鼠标光标在块传输完成后由BltComplete函数负责恢复.
BltPrepare:
ROTATE和CLEARTYPE宏均未定义.
SCODE S3C2410DISP::BltPrepare(GPEBltParms *blitParameters) { RECTL rectl; RETAILMSG(0, (TEXT("S3C2410DISP::BltPrepare/r/n"))); // default to base EmulatedBlt routine blitParameters->pBlt = EmulatedBlt; // see if we need to deal with cursor if (m_CursorVisible && !m_CursorDisabled) { // check for destination overlap with cursor and turn off cursor if overlaps if (blitParameters->pDst == m_pPrimarySurface) // only care if dest is main display surface { if (blitParameters->prclDst != NULL) // make sure there is a valid prclDst { rectl = *blitParameters->prclDst; // if so, use it } else { rectl = m_CursorRect; // if not, use the Cursor rect - this forces the cursor to be turned off in this case } if (m_CursorRect.top < rectl.bottom && m_CursorRect.bottom > rectl.top && m_CursorRect.left < rectl.right && m_CursorRect.right > rectl.left) { CursorOff(); m_CursorForcedOff = TRUE; } } // check for source overlap with cursor and turn off cursor if overlaps if (blitParameters->pSrc == m_pPrimarySurface) // only care if source is main display surface { if (blitParameters->prclSrc != NULL) // make sure there is a valid prclSrc { rectl = *blitParameters->prclSrc; // if so, use it } else { rectl = m_CursorRect; // if not, use the CUrsor rect - this forces the cursor to be turned off in this case } if (m_CursorRect.top < rectl.bottom && m_CursorRect.bottom > rectl.top && m_CursorRect.left < rectl.right && m_CursorRect.right > rectl.left) { CursorOff(); m_CursorForcedOff = TRUE; } } } #ifdef ROTATE if (m_iRotate && (blitParameters->pDst == m_pPrimarySurface || blitParameters->pSrc == m_pPrimarySurface)) { blitParameters->pBlt = (SCODE (GPE::*)(GPEBltParms *))EmulatedBltRotate; } #endif //ROTATE #ifdef CLEARTYPE if (((blitParameters->rop4 & 0xffff) == 0xaaf0 ) && (blitParameters->pMask->Format() == gpe8Bpp)) { switch (m_colorDepth) { case 16: blitParameters->pBlt = (SCODE (GPE::*)(struct GPEBltParms *)) ClearTypeBlt::ClearTypeBltDst16; return S_OK; case 24: blitParameters->pBlt = (SCODE (GPE::*)(struct GPEBltParms *)) ClearTypeBlt::ClearTypeBltDst24; return S_OK; case 32: blitParameters->pBlt = (SCODE (GPE::*)(struct GPEBltParms *)) ClearTypeBlt::ClearTypeBltDst32; return S_OK; default: break; } } #endif //CLEARTYPE // see if there are any optimized software blits available EmulatedBltSelect02(blitParameters); EmulatedBltSelect08(blitParameters); EmulatedBltSelect16(blitParameters); return S_OK; }
BltComplete:
SCODE S3C2410DISP::BltComplete(GPEBltParms *blitParameters) { RETAILMSG(0, (TEXT("S3C2410DISP::BltComplete/r/n"))); // see if cursor was forced off because of overlap with source or destination and turn back on if (m_CursorForcedOff) { m_CursorForcedOff = FALSE; CursorOn(); } return S_OK; }
15.InVBlank
InVBlank用来查询显示设备当前时刻是否处在垂直空白阶段.垂直空白阶段指的是CRT类型的显示设备在显示完一帧后,电子枪从屏幕的右下角返回右上角的时间间隙.对于LCD没有这个特性可以利用,因此该函数直接返回0.
INT S3C2410DISP::InVBlank(void) { RETAILMSG(0, (TEXT("S3C2410DISP::InVBlank/r/n"))); return 0; }
16.SetPalette
SetPalette用于对显示设备设置调色板.由于当前设备使用RGB565模式的颜色方案,因此不需要使用调色板.仅仅检查参数的有效性.
SCODE S3C2410DISP::SetPalette(const PALETTEENTRY *source, USHORT firstEntry, USHORT numEntries) { RETAILMSG(0, (TEXT("S3C2410DISP::SetPalette/r/n"))); if (firstEntry < 0 || firstEntry + numEntries > 256 || source == NULL) { return E_INVALIDARG; } return S_OK; }
17.GetGraphicsCaps
GetGraphicsCaps用于向调用者返回显示设备和驱动程序所能支持的图形处理能力.
这里返回了GCAPS_GRAY16,表示显示设备和驱动程序具备字体反锯齿能力.
返回值可能的取值为以下宏定义或组合.如GCAPS_CLEARTYPE,ClearType技术是更高级的字体反锯齿的软件功能.
#define GCAPS_GRAY16 0x01000000 #define GCAPS_CLEARTYPE 0x00000100 #define GCAPS_CLEARTYPE_HORIZONTALY_STRIPED 0x00000200 #define GCAPS_TEXT_CAPS (GCAPS_GRAY16 | GCAPS_CLEARTYPE | GCAPS_CLEARTYPE_HORIZONTALY_STRIPED)
ULONG S3C2410DISP::GetGraphicsCaps() { #ifdef CLEARTYPE return GCAPS_GRAY16 | GCAPS_CLEARTYPE; #else return GCAPS_GRAY16; #endif }
18.DrvEscape
DrvEscape是DDI的同名函数DrvEscape的延续,用于获取一些特殊的,通过与设备无关的设备驱动程序接口获取不到的信息.DDI的DrvEscape函数完成了部分与具体硬件无关的查询,而将需要依赖特定的显示设备硬件信息的交给设备驱动程序的DrvEscape函数.
这里实际上并未实现该函数(CLEARTYPE和ROTATE并未定义),如果定义了这两个宏,就进行Gamma数值和翻转状态的处理.
#if defined(CLEARTYPE) || defined(ROTATE) extern GetGammaValue(ULONG * pGamma); extern SetGammaValue(ULONG ulGamma, BOOL bUpdateReg); ULONG S3C2410DISP::DrvEscape( SURFOBJ *pso, ULONG iEsc, ULONG cjIn, PVOID pvIn, ULONG cjOut, PVOID pvOut) { if (iEsc == DRVESC_GETGAMMAVALUE) { return GetGammaValue((ULONG *)pvOut); } else if (iEsc == DRVESC_SETGAMMAVALUE) { return SetGammaValue(cjIn, *(BOOL *)pvIn); } #ifdef ROTATE if (iEsc == DRVESC_GETSCREENROTATION) { *(int *)pvOut = ((DMDO_0 | DMDO_90 | DMDO_180 | DMDO_270) << 8) | ((BYTE)m_iRotate); return DISP_CHANGE_SUCCESSFUL; } else if (iEsc == DRVESC_SETSCREENROTATION) { if ((cjIn == DMDO_0) || (cjIn == DMDO_90) || (cjIn == DMDO_180) || (cjIn == DMDO_270) ) { return DynRotate(cjIn); } return DISP_CHANGE_BADMODE; } #endif //ROTATE & ROTATE return 0; } #endif //CLEARTYPE
19.DrvGetMasks
DrvGetMasks是我们唯一一个需要直接实现的DDI函数.该函数用于获取显示设备的当前模式下的颜色掩码.直接返回全局数组的指针gBitMasks,就是之前提到过的565的RGB模式.
static ulong gBitMasks[] = { 0xF800, 0x07E0, 0x001F };  // 565 MODE
ULONG *APIENTRY DrvGetMasks(DHPDEV dhpdev) { return gBitMasks; }
至此,GPE继承类S3C2410DISP需要实现的成员函数简单介绍到这里,还有和ClearType和Rotate相关的函数没有介绍,详情可以参考SMDK2410 BSP的显示驱动文件s3c2410x_lcd.cpp.
WinCE6.0 DEVICEEMULATOR BSP(基于s3c2410)的LCD驱动架构也基本类似,唯一大的区别就是使用了DDGPE继承类而不是直接继承GPE类,DDGPE类是GPE的继承类,支持DirectDraw,由于2410的LCD控制器不支持DirectDraw,因此继承这两个类并无本质的区别.
关于显示驱动还有很多内容并未详细介绍,如DDI函数,GPESurf类,调色板等,需要继续学习.

你可能感兴趣的:(c,windows,struct,null,delete,WinCE)