diff options
-rw-r--r-- | CALLMAP | 22 | ||||
-rw-r--r-- | README | 76 | ||||
-rw-r--r-- | Release.txt | 231 | ||||
-rw-r--r-- | man/siliconmotion.man | 203 | ||||
-rw-r--r-- | src/regsmi.h | 207 | ||||
-rw-r--r-- | src/smi.h | 362 | ||||
-rw-r--r-- | src/smi_accel.c | 1108 | ||||
-rw-r--r-- | src/smi_dac.c | 99 | ||||
-rw-r--r-- | src/smi_dga.c | 301 | ||||
-rw-r--r-- | src/smi_driver.c | 3294 | ||||
-rw-r--r-- | src/smi_hwcurs.c | 375 | ||||
-rw-r--r-- | src/smi_i2c.c | 115 | ||||
-rw-r--r-- | src/smi_shadow.c | 226 | ||||
-rw-r--r-- | src/smi_video.c | 2548 | ||||
-rw-r--r-- | src/smi_video.h | 103 |
15 files changed, 9270 insertions, 0 deletions
@@ -0,0 +1,22 @@ +-- Only Once, calling order -- +ChipIdentify (SMIIdentify) +ChipProbe (SMIProbe) + Passive only, no ram determination, no writing + +-- For each ScrnInfoRec, still calling order -- +ChipPreInit (SMIPreInit) + Allows probing and mapping, hardware must remain unchanged + ChipGetRec + +ChipScreenInit + ChipMapMem + ChipSave + vgaHWSaveMMIO + ChipModeInit + vtSema=TRUE + ChipWriteMode + vgaHWRestoreMMIO + +Header: \\Mercury\Projects\archives\XFree86 4.0\CALLMAP.-arc 1.1 13 Jul 2000 18:16:58 Frido $ + +$XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/CALLMAP,v 1.1 2000/11/28 20:59:18 dawes Exp $ @@ -0,0 +1,76 @@ +What works: +- Supports 8bpp, 16bpp and 24bpp. Heavy testing on SM720. + +XCONFIG options: + +The driver supports quite a few different XConfig options, which can +be used to tune the driver and improve performance. Without any options, +the driver will use conservative settings which should work on most +hardware. Large improvements in performance are possible by selecting +the proper options, which will probably work on most systems. + +Cursor: + +- "hwcursor" "off" behaves exactly like "swcursor". Default: "on" +- "swcursor" will disable the HW Cursor. HW Cursor is used by default and + no option is needed to enable it. + +Display: + +- "ShadowFB" Use shadow framebuffer. Default: off. +- "Rotate" "cw" | "ccw" Rotate the screen CW - clockwise or CCW - counter + clockwise. Uses ShadowFB. Default: no rotation. +- "UseBIOS" Use BIOS to set modes. Default: on. +- "ZoomOnLCD" Allow changing resolution on panel. Default: off. + +Overlays: + +- "VideoKey" Set chroma key for video. Default: Off blue. +- "ByteSwap" Turn on YUV byte swapping. Defaul: off. + +Video memory: + +- "set_mclk" sets the memory clock, format is: + Option "set_mclk" "50000" + in the XF86Config file. Valid values are any + integer <= 100000, where 100000 == 100 MHz. + +Acceleration and graphic engine: + +- "NoAccel" turns off all acceleration +- "fifo_aggressive", "fifo_moderate" and "fifo_conservative" alter the settings + for the threshold at which the pixel FIFO takes over the internal + memory bus to refill itself. The smaller this threshold, the better + the acceleration performance of the card. You may try the fastest + setting ("aggressive") and move down if you encounter pixel corruption. + The optimal setting will probably depend on dot-clock and on color + depth. Note that specifying any of these options will also alter other + memory settings which should increase performance, so you should at + least use "fifo_conservative" (this uses the chip defaults). +- Common XAA acceleration options to disable primitives for test purposes: + "XaaNoScreenToScreenCopy" + "XaaNoSolidFillRect" + "XaaNoColor8x8PatternFillRect" + "XaaNoImageWriteRect" + "XaaNoPixmapCache" + +PCI bus: + +- "pci_burst" will enable PCI burst mode. This should work on all but a + few "broken" PCI chipsets, and will increase performance. Option may + take a parameter "on", "off", "yes", etc... +- "pci_retry" will allow the driver to rely on PCI Retry to program the + ViRGE registers. "pci_burst" must be enabled for this to work. + This will increase performance, especially for small fills/blits, + because the driver does not have to poll the ViRGE before sending it + commands to make sure it is ready. It should work on most + recent PCI chipsets. + +Debug: + +- "ShowCache" Enable or disable viewing offscreen cache memory. A + development debug option. Default: off. + +Header: //Mercury/Projects/archives/XFree86/4.0/README.-arc 1.2 14 Sep 2000 12:28:36 Frido $ + +$XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/README,v 1.3 2001/02/15 18:20:33 dawes Exp $ diff --git a/Release.txt b/Release.txt new file mode 100644 index 0000000..204dba7 --- /dev/null +++ b/Release.txt @@ -0,0 +1,231 @@ +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.1.0 + Alpha Release 1.3.1cz, 11/12/2001 +------------------------------------------------------------------------------- + +Extensions: + +- gamma correction for 24 bit true color mode. + +Known problems: + +- gamma correction does not work for 16 bit true color mode: + LoadPalette gets a gamma correction color table for 5:6:5 RGB, + whereas the SMI RAMDAC wants a 8:8:8 RGB color table. + +- gamma correction only implemented for the Lynx3DM + +- StopVideo don't work. The graphics controller continues to write + into the capture buffer + +Fixed bugs (or new bugs :) ): + +- in SMI_ScreenInit frame buffer size calculation for video changed. + + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.1.0 + Alpha Release 1.3.0cz, 10/26/2001 +------------------------------------------------------------------------------- + +Fixed bugs: + +- XAA: clipping rectangle was clipped to visible screen, so offscreen + pixmaps could not been drawn at with accelerated drawing functions. + +Extensions: + +- smi_video: partly rewritten. + - Support for 7111 + - interlaced video via + - XF86Config Option "Interlaced" or + - attribute XV_INTERLACED + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0.2 + Alpha Release 1.2.2, 02/14/2001 +------------------------------------------------------------------------------- + +Fixed bugs: + +- #920 - Color change/flash at 8bpp when switch back to desktop in rotation + mode. +- #932 - System hangs when enabling rotation in 24-bpp. +- #941 - Overlay disappear in the virtual desktop when move the window. +- #944 - Mouse pointer doesn't work properly in panning modes under rotation. +- #950 - Garbage appears on desktop when click the Basic/Metal for the Theme + Selector. +- #983 - Added ZoomOnLCD option. +- #1058 - Desktop changes color when panning in 24-bpp mode. +- #1069 - CRT is off after exit X on DSTN 800x600. +- #1074 - Screen broken occurs in X when enable Rotation on DSTN 800x600. + +Known problems: + +- When video is playing in panning mode, it is not correctly clipped when you + move the panning window. +- Sound breaks apart in Netscape when moving the window around. + +------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0.2 + Alpha Release 1.2.1, 01/03/2001 +-------------------------------------------------------------------------------- + +Fixed bugs: + +- Severe corruption in 24-bpp across all chips. +- Disable hardware cursor on older BIOSes. + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0.2 + Alpha Release 1.2.0, 12/13/2000 +-------------------------------------------------------------------------------- + +Fixed bugs: + +- When restoring from VESAFB graphics mode, the screen did not update with the + UseBIOS switch on. + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0.1 + Alpha Release 1.1.9, 11/30/2000 +-------------------------------------------------------------------------------- + +Fixed bugs: + +#581 - Need Linux driver to support zooming via ctrl+alt++ & ctrl+alt+-. +#670 - Screen broken occurs when switch back to the Xwindow during in Rotation + mode. +#671 - Very slow to pop up the Exit menu from X windows during in Rotation mode. +#672 - It doesn't redraw properly in X windows during in Rotation mode. +#689 - Screen broken when toggle between terminal and desktop during playing in + MPEG. +#705 - Linux CRT only 800x600 or 1024x768 there is no display. +#864 - Lockup when video is playing and switching to full-screen command shell. + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0.1 + Alpha Release 1.1.8, 11/27/2000 +-------------------------------------------------------------------------------- + +Fixed bugs: + +#640 - X windows shift to the right when start X or apply Rotation. + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0.1 + Alpha Release 1.1.7, 11/17/2000 +-------------------------------------------------------------------------------- + +Fixed bugs: + +#676 - Green color only shown in window when run Xlive in Linux. +#835 - Screen black after DPMS on. + + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0.1 + Alpha Release 1.1.6, 11/03/2000 +-------------------------------------------------------------------------------- + +Fixed bugs: + +#687 - Blue rectangle appears when video is clipped on thr right edge of screen. +#735 - When resume from sleep, X does not wake up. + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0.1 + Alpha Release 1.1.5, 10/06/2000 +-------------------------------------------------------------------------------- + +Fixed bugs: + +#578 - Don't check for CRT-only when validating modes. +#579 - Corrected DPI issue when DDC monitor is not attached. + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0.1 + Alpha Release 1.1.4, 09/20/2000 +-------------------------------------------------------------------------------- + +Fixed bugs: + +#521 - Screen corruption after return from X Server when vesafb is used. + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0.1 + Alpha Release 1.1.3, 09/18/2000 +-------------------------------------------------------------------------------- + +New features: + +- Added live video capture. + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0.1 + Alpha Release 1.1.2, 09/14/2000 +-------------------------------------------------------------------------------- + +Fixed bugs: + +#486 - Video scaling wrong on SM720. + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0.1 + Alpha Release 1.1.1, 08/23/2000 +-------------------------------------------------------------------------------- + +New features: + +- Added support for overlays. + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0.1 + Alpha Release 1.1.0, 08/11/2000 +-------------------------------------------------------------------------------- + +New features: + +- Added support for XFree86 4.0.1 server. This implies that support for the 4.0 + server has gone. Hence the change in the alpha version number from 1.0.x to + 1.1.x. + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0 + Alpha Release 1.0.2, 08/02/2000 +-------------------------------------------------------------------------------- + +Fixed bugs: + +#161, Corruption when moving windows with a wallpaper background. + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0 + Alpha Release 1.0.1, 07/27/2000 +-------------------------------------------------------------------------------- + +Fixed bugs: + +#160, Mouse pointer sometimes in bad location. +#258, Temporary corruption starting X. + +-------------------------------------------------------------------------------- + Silicon Motion Driver for XFree86 4.0 + Alpha Release 1.0.0, 06/05/2000 +-------------------------------------------------------------------------------- + +This is alpha version 1.0.0 of the Silicon Motion drivers for the XFree86 4.0 +server. See the README file for general information. + +This ALPHA version has the following known problems: + +- During mode initialization, the screen shows temporary garbage. +- Image Transfers are disabled in the hardware for now. + +This driver has been tested on the LynxEM+ 712 chip under 16-bit mode. Any other +mode might still show lock-ups and/or garbage. Please report any problems to +frido@siliconmotion.com. + +Header: //Mercury/Projects/archives/XFree86/4.0/Release.txt-arc 1.33 13 Dec 2000 09:52:48 Frido $ + +$XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/Release.txt,v 1.7 2001/12/20 21:35:37 eich Exp $ diff --git a/man/siliconmotion.man b/man/siliconmotion.man new file mode 100644 index 0000000..029b40a --- /dev/null +++ b/man/siliconmotion.man @@ -0,0 +1,203 @@ +.\" Header: //Mercury/Projects/archives/XFree86/4.0/siliconmotion.cpp-arc 1.4 29 Nov 2000 14:12:56 Frido $ +.\" $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/siliconmotion.man,v 1.4 2001/12/20 21:35:38 eich Exp $ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH siliconmotion __drivermansuffix__ __vendorversion__ +.SH NAME +siliconmotion \- Silicon Motion video driver +.SH SYNOPSIS +.B "Section \*qDevice\*q" +.br +.BI " Identifier \*q" devname \*q +.br +.B " Driver \*qsiliconmotion\*q" +.br +\ \ ... +.br +\ \ [ +.B "Option" +"optionname" ["optionvalue"]] +.br +.B EndSection +.SH DESCRIPTION +.B siliconmotion +is an XFree86 driver for Silicon Motion based video cards. The driver is fully +accelerated, and provides support for the following framebuffer depths: +8, 16, and 24. All +visual types are supported for depth 8, and TrueColor +visuals are supported for the other depths. +.SH SUPPORTED HARDWARE +The +.B siliconmotion +driver supports PCI and AGP video cards based on the following Silicon Motion chips: +.TP 12 +.B Lynx +SM910 +.TP 12 +.B LynxE +SM810 +.TP 12 +.B Lynx3D +SM820 +.TP 12 +.B LynxEM +SM710 +.TP 12 +.B LynxEM+ +SM712 +.TP 12 +.B Lynx3DM +SM720 +.SH CONFIGURATION DETAILS +Please refer to XF86Config(__filemansuffix__) for general configuration +details. This section only covers configuration details specific to this +driver. All options names are case and white space insensitive when +parsed by the server, for example, "lynxe" and "LynxE" are equivalent. +.PP +The driver auto-detects the chipset type, but the following +.B ChipSet +names may optionally be specified in the config file +.B \*qDevice\*q +section, and will override the auto-detection: +.PP +.RS 4 +"lynx", "lynxe", "lynx3d", "lynxem", "lynxem+", "lynx3dm". +.RE + +.PP +The following Cursor +.B Options +are supported: +.TP +.BI "Option \*qHWCursor\*q \*q" boolean \*q +Enable or disable the HW cursor. Default: on. +.TP +.BI "Option \*qSWCursor\*q \*q" boolean \*q +Inverse of "HWCursor". Default: off. + +.PP +The following display +.B Options +are supported: +.TP +.BI "Option \*qShadowFB\*q \*q" boolean \*q +Use shadow framebuffer. Default: off. +.TP +.BI "Option \*qRotate\*q \*qCW\*q" +.TP +.BI "Option \*qRotate\*q \*qCCW\*q" +Rotate the screen CW - clockwise or CCW - counter clockwise. +Uses ShadowFB. Default: no rotation. +.TP +.BI "Option \*qVideoKey\*q \*q" integer \*q +Set the video color key. Default: a little off full blue. +.TP +.BI "Option \*qByteSwap\*q \*q" boolean \*q +Turn on byte swapping for capturing using SMI demo board. Default: off. +.TP +.BI "Option \*qInterlaced\*q \*q" boolean \*q +Turn on interlaced video capturing. Default: off. +.TP +.BI "Option \*qUseBIOS\*q \*q" boolean \*q +Use the BIOS to set the modes. This is used for custom panel timings. +Default: on. +.TP +.BI "Option \*qZoomOnLCD\*q \*q" boolean \*q +Allow changing resolution on LCD (Ctrl-Alt-Plus and Ctrl-Alt-Minus). +Default: off. + +.PP +The following video memory +.B Options +are supported: +.TP +.BI "Option \*qset_mclk\*q \*q" integer \*q +sets the memory clock, where +.I integer +is in kHz, and +.I integer +<= 100000. Default: probe the memory clock value, +and use it at server start. + + +.PP +The following acceleration and graphics engine +.B Options +are supported: +.TP +.B "Option \*qNoAccel\*q" +Disable acceleration. Very useful for determining if the +driver has problems with drawing and acceleration routines. This is the first +option to try if your server runs but you see graphic corruption on the screen. +Using it decreases performance, as it uses software emulation for drawing +operations the video driver can accelerate with hardware. +Default: acceleration is enabled. +.TP +.B "Option \*qfifo_aggressive\*q" +.TP +.B "Option \*qfifo_moderate\*q" +.TP +.B "Option \*qfifo_conservative\*q" +alter the settings +for the threshold at which the pixel FIFO takes over the internal +memory bus to refill itself. The smaller this threshold, the better +the acceleration performance of the card. You may try the fastest +setting +.RB ( "fifo_aggressive" ) +and move down if you encounter pixel corruption. +The optimal setting will probably depend on dot-clock and on color +depth. Note that specifying any of these options will also alter other +memory settings which may increase performance, so trying +.B "fifo_conservative" +will in most cases be a slight benefit (this uses the chip defaults). +If pixel corruption or transient streaking is observed during drawing +operations then removing any fifo options is recommended. Default: none. + +.PP +The following PCI bus +.B Options +are supported: +.TP +.BI "Option \*qpci_burst\*q \*q" boolean \*q +will enable PCI burst mode. This should work on all but a +few broken PCI chipsets, and will increase performance. Default: off. +.TP +.BI "Option \*qpci_retry\*q \*q" boolean \*q +will allow the driver to rely on PCI Retry to program the +ViRGE registers. +.B "pci_burst" +must be enabled for this to work. +This will increase performance, especially for small fills/blits, +because the driver does not have to poll the ViRGE before sending it +commands to make sure it is ready. It should work on most +recent PCI chipsets. Default: off. + +.PP +The following additional +.B Options +are supported: +.TP +.BI "Option \*qShowCache\*q \*q" boolean \*q +Enable or disable viewing offscreen cache memory. A +development debug option. Default: off. + +.SH SEE ALSO +XFree86(1), XF86Config(__filemansuffix__), xf86config(1), Xserver(1), X(__miscmansuffix__) + +.SH SUPPORT +For assistance with this driver, or XFree86 in general, check the XFree86 web +site at http://www.xfree86.org. A FAQ is available on the web site at +http://www.xfree86.org/FAQ/. If you find a problem with XFree86 or have a +question not answered in the FAQ please use our bug report form available on +the web site or send mail to XFree86@XFree86.org. When reporting problems +with the driver send as much detail as possible, including chipset type, a +server output log, and operating system specifics. + +.SH AUTHORS +Kevin Brosius, +Matt Grossman, +Harald Koenig, +Sebastien Marineau, +Mark Vojkovich, +Frido Garritsen, +Corvin Zahn. diff --git a/src/regsmi.h b/src/regsmi.h new file mode 100644 index 0000000..c134bed --- /dev/null +++ b/src/regsmi.h @@ -0,0 +1,207 @@ +/* Header: //Mercury/Projects/archives/XFree86/4.0/regsmi.h-arc 1.11 14 Sep 2000 11:17:30 Frido $ */ + +/* +Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. +Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of the XFree86 Project and +Silicon Motion shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without prior written +authorization from the XFree86 Project and SIlicon Motion. +*/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/regsmi.h,v 1.2 2002/01/25 21:56:09 tsi Exp $ */ + +#ifndef _REGSMI_H +#define _REGSMI_H + +#define SMI_LYNX_SERIES(chip) ((chip & 0xF0F0) == 0x0010) +#define SMI_LYNX3D_SERIES(chip) ((chip & 0xF0F0) == 0x0020) +#define SMI_LYNXEM_SERIES(chip) ((chip & 0xFFF0) == 0x0710) +#define SMI_LYNXM_SERIES(chip) ((chip & 0xFF00) == 0x0700) + +/* Chip tags */ +#define PCI_SMI_VENDOR_ID PCI_VENDOR_SMI +#define SMI_UNKNOWN 0 +#define SMI_LYNX PCI_CHIP_SMI910 +#define SMI_LYNXE PCI_CHIP_SMI810 +#define SMI_LYNX3D PCI_CHIP_SMI820 +#define SMI_LYNXEM PCI_CHIP_SMI710 +#define SMI_LYNXEMplus PCI_CHIP_SMI712 +#define SMI_LYNX3DM PCI_CHIP_SMI720 + +/* I/O Functions */ +static __inline__ CARD8 +VGAIN8_INDEX(SMIPtr pSmi, int indexPort, int dataPort, CARD8 index) +{ + if (pSmi->IOBase) + { + MMIO_OUT8(pSmi->IOBase, indexPort, index); + return(MMIO_IN8(pSmi->IOBase, dataPort)); + } + else + { + outb(pSmi->PIOBase + indexPort, index); + return(inb(pSmi->PIOBase + dataPort)); + } +} + +static __inline__ void +VGAOUT8_INDEX(SMIPtr pSmi, int indexPort, int dataPort, CARD8 index, CARD8 data) +{ + if (pSmi->IOBase) + { + MMIO_OUT8(pSmi->IOBase, indexPort, index); + MMIO_OUT8(pSmi->IOBase, dataPort, data); + } + else + { + outb(pSmi->PIOBase + indexPort, index); + outb(pSmi->PIOBase + dataPort, data); + } +} + +static __inline__ CARD8 +VGAIN8(SMIPtr pSmi, int port) +{ + if (pSmi->IOBase) + { + return(MMIO_IN8(pSmi->IOBase, port)); + } + else + { + return(inb(pSmi->PIOBase + port)); + } +} + +static __inline__ void +VGAOUT8(SMIPtr pSmi, int port, CARD8 data) +{ + if (pSmi->IOBase) + { + MMIO_OUT8(pSmi->IOBase, port, data); + } + else + { + outb(pSmi->PIOBase + port, data); + } +} + +#define OUT_SEQ(pSmi, index, data) \ + VGAOUT8_INDEX((pSmi), VGA_SEQ_INDEX, VGA_SEQ_DATA, (index), (data)) +#define IN_SEQ(pSmi, index) \ + VGAIN8_INDEX((pSmi), VGA_SEQ_INDEX, VGA_SEQ_DATA, (index)) + +#define WRITE_DPR(pSmi, dpr, data) MMIO_OUT32(pSmi->DPRBase, dpr, data); DEBUG((VERBLEV, "DPR%02X = %08X\n", dpr, data)) +#define READ_DPR(pSmi, dpr) MMIO_IN32(pSmi->DPRBase, dpr) +#define WRITE_VPR(pSmi, vpr, data) MMIO_OUT32(pSmi->VPRBase, vpr, data); DEBUG((VERBLEV, "VPR%02X = %08X\n", vpr, data)) +#define READ_VPR(pSmi, vpr) MMIO_IN32(pSmi->VPRBase, vpr) +#define WRITE_CPR(pSmi, cpr, data) MMIO_OUT32(pSmi->CPRBase, cpr, data); DEBUG((VERBLEV, "CPR%02X = %08X\n", cpr, data)) +#define READ_CPR(pSmi, cpr) MMIO_IN32(pSmi->CPRBase, cpr) + +/* 2D Engine commands */ +#define SMI_TRANSPARENT_SRC 0x00000100 +#define SMI_TRANSPARENT_DEST 0x00000300 + +#define SMI_OPAQUE_PXL 0x00000000 +#define SMI_TRANSPARENT_PXL 0x00000400 + +#define SMI_MONO_PACK_8 0x00001000 +#define SMI_MONO_PACK_16 0x00002000 +#define SMI_MONO_PACK_32 0x00003000 + +#define SMI_ROP2_SRC 0x00008000 +#define SMI_ROP2_PAT 0x0000C000 +#define SMI_ROP3 0x00000000 + +#define SMI_BITBLT 0x00000000 +#define SMI_RECT_FILL 0x00010000 +#define SMI_TRAPEZOID_FILL 0x00030000 +#define SMI_SHORT_STROKE 0x00060000 +#define SMI_BRESENHAM_LINE 0x00070000 +#define SMI_HOSTBLT_WRITE 0x00080000 +#define SMI_HOSTBLT_READ 0x00090000 +#define SMI_ROTATE_BLT 0x000B0000 + +#define SMI_SRC_COLOR 0x00000000 +#define SMI_SRC_MONOCHROME 0x00400000 + +#define SMI_GRAPHICS_STRETCH 0x00800000 + +#define SMI_ROTATE_CW 0x01000000 +#define SMI_ROTATE_CCW 0x02000000 + +#define SMI_MAJOR_X 0x00000000 +#define SMI_MAJOR_Y 0x04000000 + +#define SMI_LEFT_TO_RIGHT 0x00000000 +#define SMI_RIGHT_TO_LEFT 0x08000000 + +#define SMI_COLOR_PATTERN 0x40000000 +#define SMI_MONO_PATTERN 0x00000000 + +#define SMI_QUICK_START 0x10000000 +#define SMI_START_ENGINE 0x80000000 + +#define MAXLOOP 0x100000 /* timeout value for engine waits */ + +#define ENGINE_IDLE() \ + ((VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x16) & 0x08) == 0) +#define FIFO_EMPTY() \ + ((VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x16) & 0x10) != 0) + +/* Wait until "v" queue entries are free */ +#define WaitQueue(v) \ + do \ + { \ + if (pSmi->NoPCIRetry) \ + { \ + int loop = MAXLOOP; mem_barrier(); \ + while (!FIFO_EMPTY()) \ + if (loop-- == 0) break; \ + if (loop <= 0) SMI_GEReset(pScrn, 1, __LINE__, __FILE__); \ + } \ + } while (0) + +/* Wait until GP is idle */ +#define WaitIdle() \ + do \ + { \ + int loop = MAXLOOP; mem_barrier(); \ + while (!ENGINE_IDLE()) \ + if (loop-- == 0) break; \ + if (loop <= 0) SMI_GEReset(pScrn, 1, __LINE__, __FILE__); \ + } \ + while (0) + +/* Wait until GP is idle and queue is empty */ +#define WaitIdleEmpty() \ + do \ + { \ + WaitQueue(MAXFIFO); \ + WaitIdle(); \ + } \ + while (0) + +#define RGB8_PSEUDO (-1) +#define RGB16_565 0 +#define RGB16_555 1 +#define RGB32_888 2 + +#endif /* _REGSMI_H */ diff --git a/src/smi.h b/src/smi.h new file mode 100644 index 0000000..6fb2ee0 --- /dev/null +++ b/src/smi.h @@ -0,0 +1,362 @@ +/* Header: //Mercury/Projects/archives/XFree86/4.0/smi.h-arc 1.51 29 Nov 2000 17:45:16 Frido $ */ + +/* +Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. +Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of the XFree86 Project and +Silicon Motion shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without prior written +authorization from the XFree86 Project and Silicon Motion. +*/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi.h,v 1.12 2003/01/12 03:55:49 tsi Exp $ */ + +#ifndef _SMI_H +#define _SMI_H + +#define USE_FB + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "xf86Cursor.h" +#include "vgaHW.h" + +#include "compiler.h" + +#include "mipointer.h" +#include "micmap.h" + +#ifdef USE_FB +#include "fb.h" +#else + +#define PSZ 8 +#include "cfb.h" +#undef PSZ +#include "cfb16.h" +#include "cfb24.h" +#endif + +#include "xaa.h" +#include "xf86cmap.h" +#include "xf86i2c.h" + +#include "xf86int10.h" +#include "vbe.h" + +#ifdef XvExtension +# include "xf86xv.h" +# include "Xv.h" +#endif + +/******************************************************************************/ +/* D E F I N I T I O N S */ +/******************************************************************************/ + +#ifndef SMI_DEBUG +# define SMI_DEBUG 0 +#endif + +#define SMI_USE_IMAGE_WRITES 0 +#define SMI_USE_VIDEO 1 +#define SMI_USE_CAPTURE 1 + +/******************************************************************************/ +/* S T R U C T U R E S */ +/******************************************************************************/ + +/* Driver data structure; this should contain all needed info for a mode */ +typedef struct +{ + Bool modeInit; + CARD16 mode; + CARD8 SR17, SR18, SR21, SR31, SR32, SR6A, SR6B, SR81, SRA0; + CARD8 CR33, CR33_2, CR3A; + CARD8 CR40[14], CR40_2[14]; + CARD8 CR90[16], CR9F_2; + CARD8 CRA0[14]; + CARD8 smiDACMask, smiDacRegs[256][3]; + /* CZ 2.11.2001: for gamma correction */ + CARD8 CCR66; + /* end CZ */ + CARD8 smiFont[8192]; + CARD32 DPR10, DPR1C, DPR20, DPR24, DPR28, DPR2C, DPR30, DPR3C, DPR40, + DPR44; + CARD32 VPR00, VPR0C, VPR10; + CARD32 CPR00; + +} SMIRegRec, *SMIRegPtr; + +/* Global PDEV structure. */ +typedef struct +{ + /* accel additions */ + CARD32 AccelCmd; /* Value for DPR0C */ + CARD32 Stride; /* Stride of frame buffer */ + CARD32 ScissorsLeft; /* Left/top of current + scissors */ + CARD32 ScissorsRight; /* Right/bottom of current + scissors */ + Bool ClipTurnedOn; /* Clipping was turned on by + the previous command */ + CARD8 SR18Value; /* PDR#521: original SR18 + value */ + CARD8 SR21Value; /* PDR#521: original SR21 + value */ + SMIRegRec SavedReg; /* console saved mode + registers */ + SMIRegRec ModeReg; /* XServer video state mode + registers */ + xf86CursorInfoPtr CursorInfoRec; /* HW Cursor info */ + + Bool ModeStructInit; /* Flag indicating ModeReg has + been duped from console + state */ + int vgaCRIndex, vgaCRReg; + int width, height; /* Width and height of the + screen */ + int Bpp; /* Bytes per pixel */ + + /* XAA */ + int videoRAMBytes; /* In units as noted, set in + PreInit */ + int videoRAMKBytes; /* In units as noted, set in + PreInit */ + unsigned char * MapBase; /* Base of mapped memory */ + int MapSize; /* Size of mapped memory */ + CARD8 * DPRBase; /* Base of DPR registers */ + CARD8 * VPRBase; /* Base of VPR registers */ + CARD8 * CPRBase; /* Base of CPR registers */ + CARD8 * DataPortBase; /* Base of data port */ + int DataPortSize; /* Size of data port */ + CARD8 * IOBase; /* Base of MMIO VGA ports */ + IOADDRESS PIOBase; /* Base of I/O ports */ + unsigned char * FBBase; /* Base of FB */ + CARD32 FBOffset; /* Current visual FB starting + location */ + CARD32 FBCursorOffset; /* Cursor storage location */ + CARD32 FBReserved; /* Reserved memory in frame + buffer */ + + Bool PrimaryVidMapped; /* Flag indicating if + vgaHWMapMem was used + successfully for + this screen */ + int dacSpeedBpp; /* Clock value */ + int minClock; /* Mimimum clock */ + int maxClock; /* Maximum clock */ + int MCLK; /* Memory Clock */ + int GEResetCnt; /* Limit the number of errors + printed using a counter */ + + Bool pci_burst; /* Enable PCI burst mode for + reads? */ + Bool NoPCIRetry; /* Disable PCI retries */ + Bool fifo_conservative; /* Adjust fifo for + acceleration? */ + Bool fifo_moderate; /* Adjust fifo for + acceleration? */ + Bool fifo_aggressive; /* Adjust fifo for + acceleration? */ + Bool NoAccel; /* Disable Acceleration */ + Bool hwcursor; /* hardware cursor enabled */ + Bool ShowCache; /* Debugging option */ + Bool useBIOS; /* Use BIOS for mode sets */ + Bool zoomOnLCD; /* Zoom on LCD */ + + CloseScreenProcPtr CloseScreen; /* Pointer used to save wrapped + CloseScreen function */ + XAAInfoRecPtr AccelInfoRec; /* XAA info Rec */ + pciVideoPtr PciInfo; /* PCI info vars */ + PCITAG PciTag; + int Chipset; /* Chip info, set using PCI + above */ + int ChipRev; + + /* DGA */ + DGAModePtr DGAModes; /* Pointer to DGA modes */ + int numDGAModes; /* Number of DGA modes */ + Bool DGAactive; /* Flag if DGA is active */ + int DGAViewportStatus; + + /* DPMS */ + int CurrentDPMS; /* Current DPMS state */ + unsigned char DPMS_SR20; /* Saved DPMS SR20 register */ + unsigned char DPMS_SR21; /* Saved DPMS SR21 register */ + unsigned char DPMS_SR31; /* Saved DPMS SR31 register */ + unsigned char DPMS_SR34; /* Saved DPMS SR34 register */ + + /* Panel information */ + Bool lcd; /* LCD active, 1=DSTN, 2=TFT */ + int lcdWidth; /* LCD width */ + int lcdHeight; /* LCD height */ + + I2CBusPtr I2C; /* Pointer into I2C module */ + xf86Int10InfoPtr pInt10; /* Pointer to INT10 module */ + + /* Shadow frame buffer (rotation) */ + Bool shadowFB; /* Flag if shadow buffer is + used */ + int rotate; /* Rotation flags */ + int ShadowPitch; /* Pitch of shadow buffer */ + int ShadowWidthBytes; /* Width of shadow + buffer in bytes */ + int ShadowWidth; /* Width of shadow buffer in + pixels */ + int ShadowHeight; /* Height of shadow buffer in + pixels */ + CARD32 saveBufferSize; /* #670 - FB save buffer size */ + void * pSaveBuffer; /* #670 - FB save buffer */ + CARD32 savedFBOffset; /* #670 - Saved FBOffset value */ + CARD32 savedFBReserved; /* #670 - Saved + FBReserved value */ + CARD8 * paletteBuffer; /* #920 - Palette save buffer */ + + /* Polylines - #671 */ + ValidateGCProcPtr ValidatePolylines; /* Org. + ValidatePolylines + function */ + Bool polyLines; /* Our polylines patch is + active */ + + void (*PointerMoved)(int index, int x, int y); + +#ifdef XvExtension + int videoKey; /* Video chroma key */ + Bool ByteSwap; /* Byte swap for ZV port */ + Bool interlaced; /* True: Interlaced Video */ + /* XvExtension */ + XF86VideoAdaptorPtr ptrAdaptor; /* Pointer to VideoAdapter + structure */ + void (*BlockHandler)(int i, pointer blockData, pointer pTimeout, + pointer pReadMask); + GCPtr videoGC; +#endif + OptionInfoPtr Options; + CARD8 DACmask; +} SMIRec, *SMIPtr; + +#define SMIPTR(p) ((SMIPtr)((p)->driverPrivate)) + +/******************************************************************************/ +/* M A C R O S */ +/******************************************************************************/ + +#if SMI_DEBUG +# define VERBLEV 1 +# define ENTER_PROC(PROCNAME) xf86ErrorFVerb(VERBLEV, "ENTER\t" PROCNAME \ + "(%d)\n", __LINE__); xf86Break1() +# define DEBUG_PROC(PROCNAME) xf86ErrorFVerb(VERBLEV, "DEBUG\t" PROCNAME \ + "(%d)\n", __LINE__); xf86Break2() +# define LEAVE_PROC(PROCNAME) xf86ErrorFVerb(VERBLEV, "LEAVE\t" PROCNAME \ + "(%d)\n", __LINE__); xf86Break1() +# define DEBUG(arg) xf86ErrorFVerb arg +#else +# define VERBLEV 4 +# define ENTER_PROC(PROCNAME) +# define DEBUG_PROC(PROCNAME) +# define LEAVE_PROC(PROCNAME) +# define DEBUG(arg) +#endif + +/* Some Silicon Motion structs & registers */ +#include "regsmi.h" + +#if !defined (MetroLink) && !defined (VertDebug) +#define VerticalRetraceWait() \ +do \ +{ \ + if (VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x17) & 0x80) \ + { \ + while ((VGAIN8(pSmi, vgaIOBase + 0x0A) & 0x08) == 0x00); \ + while ((VGAIN8(pSmi, vgaIOBase + 0x0A) & 0x08) == 0x08); \ + while ((VGAIN8(pSmi, vgaIOBase + 0x0A) & 0x08) == 0x00); \ + } \ +} while (0) +#else +#define SPIN_LIMIT 1000000 +#define VerticalRetraceWait() \ +do \ +{ \ + if (VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x17) & 0x80) \ + { \ + volatile unsigned long _spin_me; \ + for (_spin_me = SPIN_LIMIT; \ + ((VGAIN8(pSmi, vgaIOBase + 0x0A) & 0x08) == 0x00) && \ + _spin_me; \ + _spin_me--); \ + if (!_spin_me) \ + ErrorF("smi: warning: VerticalRetraceWait timed out.\n"); \ + for (_spin_me = SPIN_LIMIT; \ + ((VGAIN8(pSmi, vgaIOBase + 0x0A) & 0x08) == 0x08) && \ + _spin_me; \ + _spin_me--); \ + if (!_spin_me) \ + ErrorF("smi: warning: VerticalRetraceWait timed out.\n"); \ + for (_spin_me = SPIN_LIMIT; \ + ((VGAIN8(pSmi, vgaIOBase + 0x0A) & 0x08) == 0x00) && \ + _spin_me; \ + _spin_me--); \ + if (!_spin_me) \ + ErrorF("smi: warning: VerticalRetraceWait timed out.\n"); \ + } \ +} while (0) +#endif + +/******************************************************************************/ +/* F U N C T I O N P R O T O T Y P E S */ +/******************************************************************************/ + +/* smi_dac.c */ +void SMI_CommonCalcClock(int scrnIndex, long freq, int min_m, int min_n1, + int max_n1, int min_n2, int max_n2, long freq_min, + long freq_max, unsigned char * mdiv, + unsigned char * ndiv); + +/* smi_i2c */ +Bool SMI_I2CInit(ScrnInfoPtr pScrn); + +/* smi_accel.c */ +Bool SMI_AccelInit(ScreenPtr pScrn); +void SMI_AccelSync(ScrnInfoPtr pScrn); +void SMI_GEReset(ScrnInfoPtr pScrn, int from_timeout, int line, char *file); +void SMI_EngineReset(ScrnInfoPtr); + +/* smi_hwcurs.c */ +Bool SMI_HWCursorInit(ScreenPtr pScrn); + +/* smi_driver.c */ +void SMI_AdjustFrame(int scrnIndex, int x, int y, int flags); +Bool SMI_SwitchMode(int scrnIndex, DisplayModePtr mode, int flags); + +/* smi_dga.c */ +Bool SMI_DGAInit(ScreenPtr pScrn); + +/* smi_shadow.c */ +void SMI_PointerMoved(int index, int x, int y); +void SMI_RefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox); + +/* smi_video.c */ +void SMI_InitVideo(ScreenPtr pScreen); + +#endif /*_SMI_H*/ diff --git a/src/smi_accel.c b/src/smi_accel.c new file mode 100644 index 0000000..1c53060 --- /dev/null +++ b/src/smi_accel.c @@ -0,0 +1,1108 @@ +/* Header: //Mercury/Projects/archives/XFree86/4.0/smi_accel.c-arc 1.16 03 Jan 2001 13:29:06 Frido $ */ + +/* +Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. +Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of the XFree86 Project and +Silicon Motion shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without prior written +authorization from the XFree86 Project and silicon Motion. +*/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_accel.c,v 1.7 2003/01/12 03:55:49 tsi Exp $ */ + +#include "smi.h" + +#include "miline.h" +#include "xaalocal.h" +#include "xaarop.h" +#include "servermd.h" + + +static void SMI_SetupForScreenToScreenCopy(ScrnInfoPtr, int, int, int, + unsigned int, int); +static void SMI_SubsequentScreenToScreenCopy(ScrnInfoPtr, int, int, int, int, + int, int); +static void SMI_SetupForSolidFill(ScrnInfoPtr, int, int, unsigned); +static void SMI_SubsequentSolidFillRect(ScrnInfoPtr, int, int, int, int); +static void SMI_SubsequentSolidHorVertLine(ScrnInfoPtr, int, int, int, int); +static void SMI_SetupForCPUToScreenColorExpandFill(ScrnInfoPtr, int, int, int, + unsigned int); +static void SMI_SubsequentCPUToScreenColorExpandFill(ScrnInfoPtr, int, int, int, + int, int); +static void SMI_SetupForMono8x8PatternFill(ScrnInfoPtr, int, int, int, int, int, + unsigned int); +static void SMI_SubsequentMono8x8PatternFillRect(ScrnInfoPtr, int, int, int, + int, int, int); +static void SMI_SetupForColor8x8PatternFill(ScrnInfoPtr, int, int, int, + unsigned int, int); +static void SMI_SubsequentColor8x8PatternFillRect(ScrnInfoPtr, int, int, int, + int, int, int); +#if SMI_USE_IMAGE_WRITES +static void SMI_SetupForImageWrite(ScrnInfoPtr, int, unsigned int, int, int, + int); +static void SMI_SubsequentImageWriteRect(ScrnInfoPtr, int, int, int, int, int); +#endif +static void SMI_SetClippingRectangle(ScrnInfoPtr, int, int, int, int); +static void SMI_DisableClipping(ScrnInfoPtr); +/* #671 */ +static void SMI_ValidatePolylines(GCPtr, unsigned long, DrawablePtr); +static void SMI_Polylines(DrawablePtr, GCPtr, int, int, DDXPointPtr); + +Bool +SMI_AccelInit(ScreenPtr pScreen) +{ + XAAInfoRecPtr infoPtr; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SMIPtr pSmi = SMIPTR(pScrn); + /*BoxRec AvailFBArea;*/ + Bool ret; + /*int numLines, maxLines;*/ + + ENTER_PROC("SMI_AccelInit"); + + pSmi->AccelInfoRec = infoPtr = XAACreateInfoRec(); + if (infoPtr == NULL) + { + LEAVE_PROC("SMI_AccelInit"); + return FALSE; + } + + infoPtr->Flags = PIXMAP_CACHE + | LINEAR_FRAMEBUFFER + | OFFSCREEN_PIXMAPS; + + infoPtr->Sync = SMI_AccelSync; + + /* Screen to screen copies */ + infoPtr->ScreenToScreenCopyFlags = NO_PLANEMASK + | ONLY_TWO_BITBLT_DIRECTIONS; + infoPtr->SetupForScreenToScreenCopy = SMI_SetupForScreenToScreenCopy; + infoPtr->SubsequentScreenToScreenCopy = SMI_SubsequentScreenToScreenCopy; + if (pScrn->bitsPerPixel == 24) + { + infoPtr->ScreenToScreenCopyFlags |= NO_TRANSPARENCY; + } + if ((pSmi->Chipset == SMI_LYNX3D) && (pScrn->bitsPerPixel == 8)) + { + infoPtr->ScreenToScreenCopyFlags |= GXCOPY_ONLY; + } + + /* Solid Fills */ + infoPtr->SolidFillFlags = NO_PLANEMASK; + infoPtr->SetupForSolidFill = SMI_SetupForSolidFill; + infoPtr->SubsequentSolidFillRect = SMI_SubsequentSolidFillRect; + + /* Solid Lines */ + infoPtr->SolidLineFlags = NO_PLANEMASK; + infoPtr->SetupForSolidLine = SMI_SetupForSolidFill; + infoPtr->SubsequentSolidHorVertLine = SMI_SubsequentSolidHorVertLine; + + /* Color Expansion Fills */ + infoPtr->CPUToScreenColorExpandFillFlags = ROP_NEEDS_SOURCE + | NO_PLANEMASK + | BIT_ORDER_IN_BYTE_MSBFIRST + | LEFT_EDGE_CLIPPING + | CPU_TRANSFER_PAD_DWORD + | SCANLINE_PAD_DWORD; + infoPtr->ColorExpandBase = pSmi->DataPortBase; + infoPtr->ColorExpandRange = pSmi->DataPortSize; + infoPtr->SetupForCPUToScreenColorExpandFill = + SMI_SetupForCPUToScreenColorExpandFill; + infoPtr->SubsequentCPUToScreenColorExpandFill = + SMI_SubsequentCPUToScreenColorExpandFill; + + /* 8x8 Mono Pattern Fills */ + infoPtr->Mono8x8PatternFillFlags = NO_PLANEMASK + | HARDWARE_PATTERN_PROGRAMMED_BITS + | HARDWARE_PATTERN_SCREEN_ORIGIN + | BIT_ORDER_IN_BYTE_MSBFIRST; + infoPtr->SetupForMono8x8PatternFill = SMI_SetupForMono8x8PatternFill; + infoPtr->SubsequentMono8x8PatternFillRect = + SMI_SubsequentMono8x8PatternFillRect; + + /* 8x8 Color Pattern Fills */ + if (!SMI_LYNX3D_SERIES(pSmi->Chipset) || (pScrn->bitsPerPixel != 24)) + { + infoPtr->Color8x8PatternFillFlags = NO_PLANEMASK + | HARDWARE_PATTERN_SCREEN_ORIGIN; + infoPtr->SetupForColor8x8PatternFill = + SMI_SetupForColor8x8PatternFill; + infoPtr->SubsequentColor8x8PatternFillRect = + SMI_SubsequentColor8x8PatternFillRect; + } + +#if SMI_USE_IMAGE_WRITES + /* Image Writes */ + infoPtr->ImageWriteFlags = ROP_NEEDS_SOURCE + | NO_PLANEMASK + | CPU_TRANSFER_PAD_DWORD + | SCANLINE_PAD_DWORD; + infoPtr->ImageWriteBase = pSmi->DataPortBase; + infoPtr->ImageWriteRange = pSmi->DataPortSize; + infoPtr->SetupForImageWrite = SMI_SetupForImageWrite; + infoPtr->SubsequentImageWriteRect = SMI_SubsequentImageWriteRect; +#endif + + /* Clipping */ + infoPtr->ClippingFlags = HARDWARE_CLIP_SCREEN_TO_SCREEN_COPY + | HARDWARE_CLIP_MONO_8x8_FILL + | HARDWARE_CLIP_COLOR_8x8_FILL + | HARDWARE_CLIP_SOLID_FILL + | HARDWARE_CLIP_SOLID_LINE + | HARDWARE_CLIP_DASHED_LINE; + infoPtr->SetClippingRectangle = SMI_SetClippingRectangle; + infoPtr->DisableClipping = SMI_DisableClipping; + + /* Pixmap Cache */ + if (pScrn->bitsPerPixel == 24) + { + infoPtr->CachePixelGranularity = 16; + } + else + { + infoPtr->CachePixelGranularity = 128 / pScrn->bitsPerPixel; + } + + /* Offscreen Pixmaps */ + infoPtr->maxOffPixWidth = 4096; + infoPtr->maxOffPixHeight = 4096; + if (pScrn->bitsPerPixel == 24) + { + infoPtr->maxOffPixWidth = 4096 / 3; + + if (pSmi->Chipset == SMI_LYNX) + { + infoPtr->maxOffPixHeight = 4096 / 3; + } + } + + SMI_EngineReset(pScrn); + + + /* CZ 18.06.2001: moved to smi_driver.c before the NoAccel question + to have offscreen framebuffer in NoAccel mode */ +#if 0 + maxLines = pSmi->FBReserved / (pSmi->width * pSmi->Bpp); + if (pSmi->rotate) + { + numLines = maxLines; + } + else + { +#if defined(XvExtension) && SMI_USE_VIDEO + numLines = ((pSmi->FBReserved - pSmi->width * pSmi->Bpp * pSmi->height) + * 25 / 100 + pSmi->width * pSmi->Bpp - 1) + / (pSmi->width * pSmi->Bpp); + numLines += pSmi->height; +#else + numLines = maxLines; +#endif + } + + AvailFBArea.x1 = 0; + AvailFBArea.y1 = 0; + AvailFBArea.x2 = pSmi->width; + AvailFBArea.y2 = numLines; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "FrameBuffer Box: %d,%d - %d,%d\n", + AvailFBArea.x1, AvailFBArea.y1, AvailFBArea.x2, AvailFBArea.y2); + xf86InitFBManager(pScreen, &AvailFBArea); +#endif + + ret = XAAInit(pScreen, infoPtr); + if (ret && pSmi->shadowFB) /* #671 */ + { + pSmi->ValidatePolylines = infoPtr->ValidatePolylines; + infoPtr->ValidatePolylines = SMI_ValidatePolylines; + } + + LEAVE_PROC("SMI_AccelInit"); + return(ret); +} + +void +SMI_GEReset(ScrnInfoPtr pScrn, int from_timeout, int line, char *file) +{ + SMIPtr pSmi = SMIPTR(pScrn); + CARD8 tmp; + + ENTER_PROC("SMI_GEReset"); + + if (from_timeout) + { + if (pSmi->GEResetCnt++ < 10 || xf86GetVerbosity() > 1) + { + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"\tSMI_GEReset called from %s line %d\n", file, line); + } + } + else + { + WaitIdleEmpty(); + } + + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x15); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x15, tmp | 0x30); + + WaitIdleEmpty(); + + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x15, tmp); + SMI_EngineReset(pScrn); + + LEAVE_PROC("SMI_GEReset"); +} + +/* The sync function for the GE */ +void +SMI_AccelSync(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_AccelSync"); + + WaitIdleEmpty(); /* #161 */ + + LEAVE_PROC("SMI_AccelSync"); +} + +void +SMI_EngineReset(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + CARD32 DEDataFormat = 0; + int i; + int xyAddress[] = { 320, 400, 512, 640, 800, 1024, 1280, 1600, 2048 }; + + ENTER_PROC("SMI_EngineReset"); + + pSmi->Stride = (pSmi->width * pSmi->Bpp + 15) & ~15; + + switch (pScrn->bitsPerPixel) + { + case 8: + DEDataFormat = 0x00000000; + break; + + case 16: + pSmi->Stride >>= 1; + DEDataFormat = 0x00100000; + break; + + case 24: + DEDataFormat = 0x00300000; + break; + + case 32: + pSmi->Stride >>= 2; + DEDataFormat = 0x00200000; + break; + } + for (i = 0; i < sizeof(xyAddress) / sizeof(xyAddress[0]); i++) + { + if (pSmi->rotate) + { + if (xyAddress[i] == pSmi->height) + { + DEDataFormat |= i << 16; + break; + } + } + else + { + if (xyAddress[i] == pSmi->width) + { + DEDataFormat |= i << 16; + break; + } + } + } + + WaitIdleEmpty(); + WRITE_DPR(pSmi, 0x10, (pSmi->Stride << 16) | pSmi->Stride); + WRITE_DPR(pSmi, 0x1C, DEDataFormat); + WRITE_DPR(pSmi, 0x24, 0xFFFFFFFF); + WRITE_DPR(pSmi, 0x28, 0xFFFFFFFF); + WRITE_DPR(pSmi, 0x3C, (pSmi->Stride << 16) | pSmi->Stride); + WRITE_DPR(pSmi, 0x40, 0); + WRITE_DPR(pSmi, 0x44, 0); + + SMI_DisableClipping(pScrn); + + LEAVE_PROC("SMI_EngineReset"); +} + +/******************************************************************************/ +/* Screen to Screen Copies */ +/******************************************************************************/ + +static void +SMI_SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, int rop, + unsigned int planemask, int trans) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SetupForScreenToScreenCopy"); + DEBUG((VERBLEV, "xdir=%d ydir=%d rop=%02X trans=%08X\n", xdir, ydir, + rop, trans)); + + pSmi->AccelCmd = XAACopyROP[rop] + | SMI_BITBLT + | SMI_START_ENGINE; + + if ((xdir == -1) || (ydir == -1)) + { + pSmi->AccelCmd |= SMI_RIGHT_TO_LEFT; + } + + if (trans != -1) + { + pSmi->AccelCmd |= SMI_TRANSPARENT_SRC | SMI_TRANSPARENT_PXL; + WaitQueue(1); + WRITE_DPR(pSmi, 0x20, trans); + } + + if (pSmi->ClipTurnedOn) + { + WaitQueue(1); + WRITE_DPR(pSmi, 0x2C, pSmi->ScissorsLeft); + pSmi->ClipTurnedOn = FALSE; + } + + LEAVE_PROC("SMI_SetupForScreenToScreenCopy"); +} + +static void +SMI_SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int x1, int y1, int x2, + int y2, int w, int h) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SubsequentScreenToScreenCopy"); + DEBUG((VERBLEV, "x1=%d y1=%d x2=%d y2=%d w=%d h=%d\n", x1, y1, x2, y2, w, + h)); + + if (pSmi->AccelCmd & SMI_RIGHT_TO_LEFT) + { + x1 += w - 1; + y1 += h - 1; + x2 += w - 1; + y2 += h - 1; + } + + if (pScrn->bitsPerPixel == 24) + { + x1 *= 3; + x2 *= 3; + w *= 3; + + if (pSmi->Chipset == SMI_LYNX) + { + y1 *= 3; + y2 *= 3; + } + + if (pSmi->AccelCmd & SMI_RIGHT_TO_LEFT) + { + x1 += 2; + x2 += 2; + } + } + + WaitQueue(4); + WRITE_DPR(pSmi, 0x00, (x1 << 16) + (y1 & 0xFFFF)); + WRITE_DPR(pSmi, 0x04, (x2 << 16) + (y2 & 0xFFFF)); + WRITE_DPR(pSmi, 0x08, (w << 16) + (h & 0xFFFF)); + WRITE_DPR(pSmi, 0x0C, pSmi->AccelCmd); + + LEAVE_PROC("SMI_SubsequentScreenToScreenCopy"); +} + +/******************************************************************************/ +/* Solid Fills */ +/******************************************************************************/ + +static void +SMI_SetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SetupForSolidFill"); + DEBUG((VERBLEV, "color=%08X rop=%02X\n", color, rop)); + + pSmi->AccelCmd = XAAPatternROP[rop] + | SMI_BITBLT + | SMI_START_ENGINE; + + if (pSmi->ClipTurnedOn) + { + WaitQueue(4); + WRITE_DPR(pSmi, 0x2C, pSmi->ScissorsLeft); + pSmi->ClipTurnedOn = FALSE; + } + else + { + WaitQueue(3); + } + WRITE_DPR(pSmi, 0x14, color); + WRITE_DPR(pSmi, 0x34, 0xFFFFFFFF); + WRITE_DPR(pSmi, 0x38, 0xFFFFFFFF); + + LEAVE_PROC("SMI_SetupForSolidFill"); +} + +void +SMI_SubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SubsequentSolidFillRect"); + DEBUG((VERBLEV, "x=%d y=%d w=%d h=%d\n", x, y, w, h)); + + if (pScrn->bitsPerPixel == 24) + { + x *= 3; + w *= 3; + + if (pSmi->Chipset == SMI_LYNX) + { + y *= 3; + } + } + + WaitQueue(3); + WRITE_DPR(pSmi, 0x04, (x << 16) | (y & 0xFFFF)); + WRITE_DPR(pSmi, 0x08, (w << 16) | (h & 0xFFFF)); + WRITE_DPR(pSmi, 0x0C, pSmi->AccelCmd); + + LEAVE_PROC("SMI_SubsequentSolidFillRect"); +} + +/******************************************************************************/ +/* Solid Lines */ +/******************************************************************************/ + +static void +SMI_SubsequentSolidHorVertLine(ScrnInfoPtr pScrn, int x, int y, int len, + int dir) +{ + SMIPtr pSmi = SMIPTR(pScrn); + int w, h; + + ENTER_PROC("SMI_SubsequentSolidHorVertLine"); + DEBUG((VERBLEV, "x=%d y=%d len=%d dir=%d\n", x, y, len, dir)); + + if (dir == DEGREES_0) + { + w = len; + h = 1; + } + else + { + w = 1; + h = len; + } + + if (pScrn->bitsPerPixel == 24) + { + x *= 3; + w *= 3; + + if (pSmi->Chipset == SMI_LYNX) + { + y *= 3; + } + } + + WaitQueue(3); + WRITE_DPR(pSmi, 0x04, (x << 16) | (y & 0xFFFF)); + WRITE_DPR(pSmi, 0x08, (w << 16) | (h & 0xFFFF)); + WRITE_DPR(pSmi, 0x0C, pSmi->AccelCmd); + + LEAVE_PROC("SMI_SubsequentSolidHorVertLine"); +} + +/******************************************************************************/ +/* Color Expansion Fills */ +/******************************************************************************/ + +static void +SMI_SetupForCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, int fg, int bg, + int rop, unsigned int planemask) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SetupForCPUToScreenColorExpandFill"); + DEBUG((VERBLEV, "fg=%08X bg=%08X rop=%02X\n", fg, bg, rop)); + + pSmi->AccelCmd = XAACopyROP[rop] + | SMI_HOSTBLT_WRITE + | SMI_SRC_MONOCHROME + | SMI_START_ENGINE; + + if (bg == -1) + { + pSmi->AccelCmd |= SMI_TRANSPARENT_SRC; + + WaitQueue(3); + WRITE_DPR(pSmi, 0x14, fg); + WRITE_DPR(pSmi, 0x18, ~fg); + WRITE_DPR(pSmi, 0x20, fg); + } + else + { + WaitQueue(2); + WRITE_DPR(pSmi, 0x14, fg); + WRITE_DPR(pSmi, 0x18, bg); + } + + LEAVE_PROC("SMI_SetupForCPUToScreenColorExpandFill"); +} + +void +SMI_SubsequentCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, int x, int y, int w, + int h, int skipleft) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SubsequentCPUToScreenColorExpandFill"); + DEBUG((VERBLEV, "x=%d y=%d w=%d h=%d skipleft=%d\n", x, y, w, h, skipleft)); + + if (pScrn->bitsPerPixel == 24) + { + x *= 3; + w *= 3; + skipleft *= 3; + + if (pSmi->Chipset == SMI_LYNX) + { + y *= 3; + } + } + + if (skipleft) + { + WaitQueue(5); + WRITE_DPR(pSmi, 0x2C, (pSmi->ScissorsLeft & 0xFFFF0000) + | (x + skipleft) | 0x2000); + pSmi->ClipTurnedOn = TRUE; + } + else + { + if (pSmi->ClipTurnedOn) + { + WaitQueue(5); + WRITE_DPR(pSmi, 0x2C, pSmi->ScissorsLeft); + pSmi->ClipTurnedOn = FALSE; + } + else + { + WaitQueue(4); + } + } + WRITE_DPR(pSmi, 0x00, 0); + WRITE_DPR(pSmi, 0x04, (x << 16) | (y & 0xFFFF)); + WRITE_DPR(pSmi, 0x08, (w << 16) | (h & 0xFFFF)); + WRITE_DPR(pSmi, 0x0C, pSmi->AccelCmd); + + LEAVE_PROC("SMI_SubsequentCPUToScreenColorExpandFill"); +} + +/******************************************************************************/ +/* 8x8 Mono Pattern Fills */ +/******************************************************************************/ + +static void +SMI_SetupForMono8x8PatternFill(ScrnInfoPtr pScrn, int patx, int paty, int fg, + int bg, int rop, unsigned int planemask) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SetupForMono8x8PatternFill"); + DEBUG((VERBLEV, "patx=%08X paty=%08X fg=%08X bg=%08X rop=%02X\n", patx, + paty, fg, bg, rop)); + + pSmi->AccelCmd = XAAPatternROP[rop] + | SMI_BITBLT + | SMI_START_ENGINE; + + if (pSmi->ClipTurnedOn) + { + WaitQueue(1); + WRITE_DPR(pSmi, 0x2C, pSmi->ScissorsLeft); + pSmi->ClipTurnedOn = FALSE; + } + + if (bg == -1) + { + WaitQueue(5); + WRITE_DPR(pSmi, 0x14, fg); + WRITE_DPR(pSmi, 0x18, ~fg); + WRITE_DPR(pSmi, 0x20, fg); + WRITE_DPR(pSmi, 0x34, patx); + WRITE_DPR(pSmi, 0x38, paty); + } + else + { + WaitQueue(4); + WRITE_DPR(pSmi, 0x14, fg); + WRITE_DPR(pSmi, 0x18, bg); + WRITE_DPR(pSmi, 0x34, patx); + WRITE_DPR(pSmi, 0x38, paty); + } + + LEAVE_PROC("SMI_SetupForMono8x8PatternFill"); +} + +static void +SMI_SubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn, int patx, int paty, + int x, int y, int w, int h) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SubsequentMono8x8PatternFillRect"); + DEBUG((VERBLEV, "x=%d y=%d w=%d h=%d\n", x, y, w, h)); + + if (pScrn->bitsPerPixel == 24) + { + x *= 3; + w *= 3; + if (pSmi->Chipset == SMI_LYNX) + { + y *= 3; + } + } + + WaitQueue(3); + WRITE_DPR(pSmi, 0x04, (x << 16) | (y & 0xFFFF)); + WRITE_DPR(pSmi, 0x08, (w << 16) | (h & 0xFFFF)); + WRITE_DPR(pSmi, 0x0C, pSmi->AccelCmd); + + LEAVE_PROC("SMI_SubsequentMono8x8PatternFillRect"); +} + +/******************************************************************************/ +/* 8x8 Color Pattern Fills */ +/******************************************************************************/ + +static void +SMI_SetupForColor8x8PatternFill(ScrnInfoPtr pScrn, int patx, int paty, int rop, + unsigned int planemask, int trans_color) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SetupForColor8x8PatternFill"); + DEBUG((VERBLEV, "patx=%d paty=%d rop=%02X trans_color=%08X\n", patx, paty, + rop, trans_color)); + + pSmi->AccelCmd = XAAPatternROP[rop] + | SMI_BITBLT + | SMI_COLOR_PATTERN + | SMI_START_ENGINE; + + if (pScrn->bitsPerPixel <= 16) + { + /* PDR#950 */ + CARD8* pattern = pSmi->FBBase + + (patx + paty * pSmi->Stride) * pSmi->Bpp; + + WaitIdleEmpty(); + WRITE_DPR(pSmi, 0x0C, SMI_BITBLT | SMI_COLOR_PATTERN); + memcpy(pSmi->DataPortBase, pattern, 8 * pSmi->Bpp * 8); + } + else + { + if (pScrn->bitsPerPixel == 24) + { + patx *= 3; + + if (pSmi->Chipset == SMI_LYNX) + { + paty *= 3; + } + } + + WaitQueue(1); + WRITE_DPR(pSmi, 0x00, (patx << 16) | (paty & 0xFFFF)); + } + + if (trans_color == -1) + { + pSmi->AccelCmd |= SMI_TRANSPARENT_SRC | SMI_TRANSPARENT_PXL; + + WaitQueue(1); + WRITE_DPR(pSmi, 0x20, trans_color); + } + + if (pSmi->ClipTurnedOn) + { + WaitQueue(1); + WRITE_DPR(pSmi, 0x2C, pSmi->ScissorsLeft); + pSmi->ClipTurnedOn = FALSE; + } + + LEAVE_PROC("SMI_SetupForColor8x8PatternFill"); +} + +static void +SMI_SubsequentColor8x8PatternFillRect(ScrnInfoPtr pScrn, int patx, int paty, + int x, int y, int w, int h) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SubsequentColor8x8PatternFillRect"); + DEBUG((VERBLEV, "x=%d y=%d w=%d h=%d\n", x, y, w, h)); + + if (pScrn->bitsPerPixel == 24) + { + x *= 3; + w *= 3; + + if (pSmi->Chipset == SMI_LYNX) + { + y *= 3; + } + } + + WaitQueue(3); + WRITE_DPR(pSmi, 0x04, (x << 16) | (y & 0xFFFF)); + WRITE_DPR(pSmi, 0x08, (w << 16) | (h & 0xFFFF)); /* PDR#950 */ + WRITE_DPR(pSmi, 0x0C, pSmi->AccelCmd); + + LEAVE_PROC("SMI_SubsequentColor8x8PatternFillRect"); +} + +#if SMI_USE_IMAGE_WRITES +/******************************************************************************/ +/* Image Writes */ +/******************************************************************************/ + +static void +SMI_SetupForImageWrite(ScrnInfoPtr pScrn, int rop, unsigned int planemask, + int trans_color, int bpp, int depth) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SetupForImageWrite"); + DEBUG((VERBLEV, "rop=%02X trans_color=%08X bpp=%d depth=%d\n", rop, + trans_color, bpp, depth)); + + pSmi->AccelCmd = XAACopyROP[rop] + | SMI_HOSTBLT_WRITE + | SMI_START_ENGINE; + + if (trans_color != -1) + { + pSmi->AccelCmd |= SMI_TRANSPARENT_SRC | SMI_TRANSPARENT_PXL; + + WaitQueue(1); + WRITE_DPR(pSmi, 0x20, trans_color); + } + + LEAVE_PROC("SMI_SetupForImageWrite"); +} + +static void +SMI_SubsequentImageWriteRect(ScrnInfoPtr pScrn, int x, int y, int w, int h, + int skipleft) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SubsequentImageWriteRect"); + DEBUG((VERBLEV, "x=%d y=%d w=%d h=%d skipleft=%d\n", x, y, w, h, skipleft)); + + if (pScrn->bitsPerPixel == 24) + { + x *= 3; + w *= 3; + skipleft *= 3; + + if (pSmi->Chipset == SMI_LYNX) + { + y *= 3; + } + } + + if (skipleft) + { + WaitQueue(5); + WRITE_DPR(pSmi, 0x2C, (pSmi->ScissorsLeft & 0xFFFF0000) | + (x + skipleft) | 0x2000); + pSmi->ClipTurnedOn = TRUE; + } + else + { + if (pSmi->ClipTurnedOn) + { + WaitQueue(5); + WRITE_DPR(pSmi, 0x2C, pSmi->ScissorsLeft); + pSmi->ClipTurnedOn = FALSE; + } + else + { + WaitQueue(4); + } + } + WRITE_DPR(pSmi, 0x00, 0); + WRITE_DPR(pSmi, 0x04, (x << 16) | (y * 0xFFFF)); + WRITE_DPR(pSmi, 0x08, (w << 16) | (h & 0xFFFF)); + WRITE_DPR(pSmi, 0x0C, pSmi->AccelCmd); + + LEAVE_PROC("SMI_SubsequentImageWriteRect"); +} +#endif + +/******************************************************************************/ +/* Clipping */ +/******************************************************************************/ + +static void +SMI_SetClippingRectangle(ScrnInfoPtr pScrn, int left, int top, int right, + int bottom) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SetClippingRectangle"); + DEBUG((VERBLEV, "left=%d top=%d right=%d bottom=%d\n", left, top, right, + bottom)); + + /* CZ 26.10.2001: this code prevents offscreen pixmaps being drawn ??? + left = max(left, 0); + top = max(top, 0); + right = min(right, pSmi->width); + bottom = min(bottom, pSmi->height); + */ + + if (pScrn->bitsPerPixel == 24) + { + left *= 3; + right *= 3; + + if (pSmi->Chipset == SMI_LYNX) + { + top *= 3; + bottom *= 3; + } + } + + pSmi->ScissorsLeft = (top << 16) | (left & 0xFFFF) | 0x2000; + pSmi->ScissorsRight = (bottom << 16) | (right & 0xFFFF); + + pSmi->ClipTurnedOn = FALSE; + + WaitQueue(2); + WRITE_DPR(pSmi, 0x2C, pSmi->ScissorsLeft); + WRITE_DPR(pSmi, 0x30, pSmi->ScissorsRight); + + LEAVE_PROC("SMI_SetClippingRectangle"); +} + +static void +SMI_DisableClipping(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_DisableClipping"); + + pSmi->ScissorsLeft = 0; + if (pScrn->bitsPerPixel == 24) + { + if (pSmi->Chipset == SMI_LYNX) + { + pSmi->ScissorsRight = ((pSmi->height * 3) << 16) + | (pSmi->width * 3); + } + else + { + pSmi->ScissorsRight = (pSmi->height << 16) | (pSmi->width * 3); + } + } + else + { + pSmi->ScissorsRight = (pSmi->height << 16) | pSmi->width; + } + + pSmi->ClipTurnedOn = FALSE; + + WaitQueue(2); + WRITE_DPR(pSmi, 0x2C, pSmi->ScissorsLeft); + WRITE_DPR(pSmi, 0x30, pSmi->ScissorsRight); + + LEAVE_PROC("SMI_DisableClipping"); +} + +/******************************************************************************/ +/* Polylines #671 */ +/******************************************************************************/ + +/* + +In order to speed up the "logout" screen in rotated modes, we need to intercept +the Polylines function. Normally, the polylines are drawn and the shadowFB is +then sending a request of the bounding rectangle of those poylines. This should +be okay, if it weren't for the fact that the Gnome logout screen is drawing +polylines in rectangles and this asks for a rotation of the entire rectangle. +This is very slow. + +To circumvent this slowness, we intercept the ValidatePolylines function and +override the default "Fallback" Polylines with our own Polylines function. Our +Polylines function first draws the polylines through the original Fallback +function and then rotates the lines, line by line. We then set a flag and +return control to the shadowFB which will try to rotate the bounding rectangle. +However, the flag has been set and the RefreshArea function does nothing but +clear the flag so the next Refresh that comes in shoiuld be handled correctly. + +All this code improves the speed quite a bit. + +*/ + +#define IS_VISIBLE(pWin) \ +( \ + pScrn->vtSema \ + && (((WindowPtr) pWin)->visibility != VisibilityFullyObscured) \ +) + +#define TRIM_BOX(box, pGC) \ +{ \ + BoxPtr extents = &pGC->pCompositeClip->extents; \ + if (box.x1 < extents->x1) box.x1 = extents->x1; \ + if (box.y1 < extents->y1) box.y1 = extents->y1; \ + if (box.x2 > extents->x2) box.x2 = extents->x2; \ + if (box.y2 > extents->y2) box.y2 = extents->y2; \ +} + +#define TRANSLATE_BOX(box, pDraw) \ +{ \ + box.x1 += pDraw->x; \ + box.y1 += pDraw->y; \ + box.x2 += pDraw->x; \ + box.y2 += pDraw->y; \ +} + +#define BOX_NOT_EMPTY(box) \ + ((box.x2 > box.x1) && (box.y2 > box.y1)) + +static void +SMI_ValidatePolylines(GCPtr pGC, unsigned long changes, DrawablePtr pDraw) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + SMIPtr pSmi = SMIPTR(infoRec->pScrn); + + ENTER_PROC("SMI_ValidatePolylines"); + + pSmi->ValidatePolylines(pGC, changes, pDraw); + if (pGC->ops->Polylines == XAAFallbackOps.Polylines) + { + /* Override the Polylines function with our own Polylines function. */ + pGC->ops->Polylines = SMI_Polylines; + } + + LEAVE_PROC("SMI_ValidatePolylines"); +} + +static void +SMI_Polylines(DrawablePtr pDraw, GCPtr pGC, int mode, int npt, + DDXPointPtr pptInit) +{ + XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); + ScrnInfoPtr pScrn = infoRec->pScrn; + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_Polylines"); + + /* Call the original Polylines function. */ + pGC->ops->Polylines = XAAFallbackOps.Polylines; + (*pGC->ops->Polylines)(pDraw, pGC, mode, npt, pptInit); + pGC->ops->Polylines = SMI_Polylines; + + if (IS_VISIBLE(pDraw) && npt) + { + /* Allocate a temporary buffer for all segments of the polyline. */ + BoxPtr pBox = xnfcalloc(sizeof(BoxRec), npt); + int extra = pGC->lineWidth >> 1, box; + + if (npt > 1) + { + /* Adjust the extra space required per polyline segment. */ + if (pGC->joinStyle == JoinMiter) + { + extra = 6 * pGC->lineWidth; + } + else if (pGC->capStyle == CapProjecting) + { + extra = pGC->lineWidth; + } + } + + for (box = 0; --npt;) + { + /* Setup the bounding box for one polyline segment. */ + pBox[box].x1 = pptInit->x; + pBox[box].y1 = pptInit->y; + pptInit++; + pBox[box].x2 = pptInit->x; + pBox[box].y2 = pptInit->y; + if (mode == CoordModePrevious) + { + pBox[box].x2 += pBox[box].x1; + pBox[box].y2 += pBox[box].y1; + } + + /* Sort coordinates. */ + if (pBox[box].x1 > pBox[box].x2) + { + int tmp = pBox[box].x1; + pBox[box].x1 = pBox[box].x2; + pBox[box].x2 = tmp; + } + if (pBox[box].y1 > pBox[box].y2) + { + int tmp = pBox[box].y1; + pBox[box].y1 = pBox[box].y2; + pBox[box].y2 = tmp; + } + + /* Add extra space required for each polyline segment. */ + pBox[box].x1 -= extra; + pBox[box].y1 -= extra; + pBox[box].x2 += extra + 1; + pBox[box].y2 += extra + 1; + + /* See if we need to draw this polyline segment. */ + TRANSLATE_BOX(pBox[box], pDraw); + TRIM_BOX(pBox[box], pGC); + if (BOX_NOT_EMPTY(pBox[box])) + { + box++; + } + } + + if (box) + { + /* Refresh all polyline segments now. */ + SMI_RefreshArea(pScrn, box, pBox); + } + + /* Free the temporary buffer. */ + xfree(pBox); + } + + pSmi->polyLines = TRUE; + LEAVE_PROC("SMI_Polylines"); +} diff --git a/src/smi_dac.c b/src/smi_dac.c new file mode 100644 index 0000000..627b892 --- /dev/null +++ b/src/smi_dac.c @@ -0,0 +1,99 @@ +/* Header: //Mercury/Projects/archives/XFree86/4.0/smi_dac.c-arc 1.8 27 Nov 2000 15:47:08 Frido $ */ + +/* +Copyright (C) 1994-1998 The XFree86 Project, Inc. All Rights Reserved. +Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of the XFree86 Project and +Silicon Motion shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without prior written +authorization from the XFree86 Project and Silicon Motion. +*/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_dac.c,v 1.2 2001/11/30 12:11:59 eich Exp $ */ + +#include "smi.h" + +#define BASE_FREQ 14.31818 /* MHz */ + +void +SMI_CommonCalcClock(int scrnIndex, long freq, int min_m, int min_n1, + int max_n1, int min_n2, int max_n2, long freq_min, + long freq_max, unsigned char *mdiv, unsigned char *ndiv) +{ + double div, diff, best_diff; + unsigned int m; + unsigned char n1, n2; + unsigned char best_n1 = 63, best_n2 = 3, best_m = 255; + + double ffreq = freq / 1000.0 / BASE_FREQ; + double ffreq_min = freq_min / 1000.0 / BASE_FREQ; + double ffreq_max = freq_max / 1000.0 / BASE_FREQ; + + if (ffreq < ffreq_min / (1 << max_n2)) + { + xf86DrvMsg(scrnIndex,X_WARNING,"invalid frequency %1.3f MHz [freq >= %1.3f MHz]\n", + ffreq * BASE_FREQ, ffreq_min * BASE_FREQ / (1 << max_n2)); + ffreq = ffreq_min / (1 << max_n2); + } + if (ffreq > ffreq_max / (1 << min_n2)) + { + xf86DrvMsg(scrnIndex,X_WARNING,"invalid frequency %1.3f MHz [freq <= %1.3f MHz]\n", + ffreq * BASE_FREQ, ffreq_max * BASE_FREQ / (1 << min_n2)); + ffreq = ffreq_max / (1 << min_n2); + } + + /* work out suitable timings */ + best_diff = ffreq; + + for (n2 = min_n2; n2 <= max_n2; n2++) + { + for (n1 = min_n1; n1 <= max_n1; n1++) + { + m = (int)(ffreq * n1 * (1 << n2) + 0.5); + if ( (m < min_m) || (m > 255) ) + { + continue; + } + div = (double)(m) / (double)(n1); + if ( (div >= ffreq_min) && (div <= ffreq_max) ) + { + diff = ffreq - div / (1 << n2); + if (diff < 0.0) + { + diff = -diff; + } + if (diff < best_diff) + { + best_diff = diff; + best_m = m; + best_n1 = n1; + best_n2 = n2; + } + } + } + } + + DEBUG((VERBLEV, "Clock parameters for %1.6f MHz: m=%d, n1=%d, n2=%d\n", + ((double)(best_m) / (double)(best_n1) / (1 << best_n2)) * BASE_FREQ, + best_m, best_n1, best_n2)); + + *ndiv = best_n1 | (best_n2 << 6); + *mdiv = best_m; +} diff --git a/src/smi_dga.c b/src/smi_dga.c new file mode 100644 index 0000000..9f090b9 --- /dev/null +++ b/src/smi_dga.c @@ -0,0 +1,301 @@ +/* Header: //Mercury/Projects/archives/XFree86/4.0/smi_dga.c-arc 1.5 27 Nov 2000 15:47:18 Frido $ */ + +/* +Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. +Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of the XFree86 Project and +Silicon Motion shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without prior written +authorization from the XFree86 Project and Silicon Motion. +*/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_dga.c,v 1.2 2001/02/15 18:20:33 dawes Exp $ */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "xf86Pci.h" +#include "xf86PciInfo.h" +#include "xaa.h" +#include "xaalocal.h" + +#include "smi.h" +#include "dgaproc.h" + +static Bool SMI_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **, int *, + int *, int *); +static Bool SMI_SetMode(ScrnInfoPtr, DGAModePtr); +static int SMI_GetViewport(ScrnInfoPtr); +static void SMI_SetViewport(ScrnInfoPtr, int, int, int); +static void SMI_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long); +static void SMI_BlitRect(ScrnInfoPtr, int, int, int, int, int, int); +static void SMI_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int, + unsigned long); + +static +DGAFunctionRec SMI_DGAFuncs = +{ + SMI_OpenFramebuffer, + NULL, + SMI_SetMode, + SMI_SetViewport, + SMI_GetViewport, + SMI_AccelSync, + SMI_FillRect, + SMI_BlitRect, + SMI_BlitTransRect +}; + +Bool +SMI_DGAInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SMIPtr pSmi = SMIPTR(pScrn); + DGAModePtr modes = NULL, newmodes = NULL, currentMode; + DisplayModePtr pMode, firstMode; + int Bpp = pScrn->bitsPerPixel >> 3; + int num = 0; + Bool ret; + + ENTER_PROC("SMI_DGAInit"); + + pMode = firstMode = pScrn->modes; + + while (pMode) + { + newmodes = xrealloc(modes, (num + 1) * sizeof(DGAModeRec)); + if (newmodes == NULL) + { + xfree(modes); + LEAVE_PROC("SMI_DGAInit"); + return(FALSE); + } + + modes = newmodes; + + currentMode = modes + num; + num++; + + currentMode->mode = pMode; + currentMode->flags = DGA_PIXMAP_AVAILABLE; + if (!pSmi->NoAccel) + { + currentMode->flags |= DGA_FILL_RECT + | DGA_BLIT_RECT + | DGA_BLIT_RECT_TRANS; + } + if (pMode->Flags & V_DBLSCAN) + { + currentMode->flags |= DGA_DOUBLESCAN; + } + if (pMode->Flags & V_INTERLACE) + { + currentMode->flags |= DGA_INTERLACED; + } + + currentMode->byteOrder = pScrn->imageByteOrder; + currentMode->depth = pScrn->depth; + currentMode->bitsPerPixel = pScrn->bitsPerPixel; + currentMode->red_mask = pScrn->mask.red; + currentMode->green_mask = pScrn->mask.green; + currentMode->blue_mask = pScrn->mask.blue; + currentMode->visualClass = (Bpp == 1) ? PseudoColor : TrueColor; + currentMode->viewportWidth = pMode->HDisplay; + currentMode->viewportHeight = pMode->VDisplay; + currentMode->xViewportStep = (Bpp == 3) ? 8 : (8 / Bpp); + currentMode->yViewportStep = 1; + currentMode->viewportFlags = DGA_FLIP_RETRACE; + currentMode->offset = 0; + currentMode->address = pSmi->FBBase; + + xf86ErrorFVerb(VERBLEV, "\tSMI_DGAInit %dx%d @ %d bpp\n", + currentMode->viewportWidth, currentMode->viewportHeight, + currentMode->bitsPerPixel); + + currentMode->bytesPerScanline = ((pScrn->displayWidth * Bpp) + 15) + & ~15L; + currentMode->imageWidth = pScrn->displayWidth; + currentMode->imageHeight = pSmi->FBReserved + / currentMode->bytesPerScanline; + currentMode->pixmapWidth = currentMode->imageWidth; + currentMode->pixmapHeight = currentMode->imageHeight; + currentMode->maxViewportX = currentMode->imageWidth + - currentMode->viewportWidth; + currentMode->maxViewportY = currentMode->imageHeight + - currentMode->viewportHeight; + + pMode = pMode->next; + if (pMode == firstMode) + { + break; + } + } + + pSmi->numDGAModes = num; + pSmi->DGAModes = modes; + + ret = DGAInit(pScreen, &SMI_DGAFuncs, modes, num); + LEAVE_PROC("SMI_DGAInit"); + return(ret); +} + +static Bool +SMI_SetMode(ScrnInfoPtr pScrn, DGAModePtr pMode) +{ + static int OldDisplayWidth[MAXSCREENS]; + int index = pScrn->pScreen->myNum; + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SetMode"); + + if (pMode == NULL) + { /* restore the original mode */ + + /* put the ScreenParameters back */ + pScrn->displayWidth = OldDisplayWidth[index]; + + SMI_SwitchMode(index, pScrn->currentMode, 0); + pSmi->DGAactive = FALSE; + } + else + { + if (!pSmi->DGAactive) + { /* save the old parameters */ + OldDisplayWidth[index] = pScrn->displayWidth; + + pSmi->DGAactive = TRUE; + } + + pScrn->displayWidth = pMode->bytesPerScanline + / (pMode->bitsPerPixel >> 3); + + SMI_SwitchMode(index, pMode->mode, 0); + } + + LEAVE_PROC("SMI_SetMode"); + return(TRUE); +} + + +static int +SMI_GetViewport(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_GetViewport"); + + LEAVE_PROC("SMI_GetViewport"); + + return(pSmi->DGAViewportStatus); +} + +static void +SMI_SetViewport(ScrnInfoPtr pScrn, int x, int y, int flags) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SetViewport"); + + SMI_AdjustFrame(pScrn->pScreen->myNum, x, y, flags); + pSmi->DGAViewportStatus = 0; + + LEAVE_PROC("SMI_SetViewport"); +} + +static void +SMI_FillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h, unsigned long color) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_FillRect"); + + if (pSmi->AccelInfoRec) + { + (*pSmi->AccelInfoRec->SetupForSolidFill)(pScrn, color, GXcopy, ~0); + (*pSmi->AccelInfoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h); + SET_SYNC_FLAG(pSmi->AccelInfoRec); + } + + LEAVE_PROC("SMI_FillRect"); +} + +static void +SMI_BlitRect(ScrnInfoPtr pScrn, int srcx, int srcy, int w, int h, int dstx, + int dsty) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_BlitRect"); + + if (pSmi->AccelInfoRec) + { + int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1; + int ydir = (srcy < dsty) ? -1 : 1; + + (*pSmi->AccelInfoRec->SetupForScreenToScreenCopy)(pScrn, xdir, ydir, + GXcopy, ~0, -1); + (*pSmi->AccelInfoRec->SubsequentScreenToScreenCopy)(pScrn, srcx, srcy, + dstx, dsty, w, h); + SET_SYNC_FLAG(pSmi->AccelInfoRec); + } + + LEAVE_PROC("SMI_BlitRect"); +} + +static void +SMI_BlitTransRect(ScrnInfoPtr pScrn, int srcx, int srcy, int w, int h, int dstx, + int dsty, unsigned long color) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_BlitTraneRect"); + + if (pSmi->AccelInfoRec) + { + int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1; + int ydir = (srcy < dsty) ? -1 : 1; + + (*pSmi->AccelInfoRec->SetupForScreenToScreenCopy)(pScrn, xdir, ydir, + GXcopy, ~0, color); + (*pSmi->AccelInfoRec->SubsequentScreenToScreenCopy)(pScrn, srcx, srcy, + dstx, dsty, w, h); + SET_SYNC_FLAG(pSmi->AccelInfoRec); + } + + LEAVE_PROC("SMI_BlitTraneRect"); +} + +static Bool +SMI_OpenFramebuffer(ScrnInfoPtr pScrn, char **name, unsigned char **mem, + int *size, int *offset, int *flags) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_OpenFrameBuffer"); + + *name = NULL; /* no special device */ + *mem = (unsigned char*)pSmi->FBBase; + *size = pSmi->videoRAMBytes; + *offset = 0; + *flags = DGA_NEED_ROOT; + + LEAVE_PROC("SMI_OpenFrameBuffer"); + return(TRUE); +} diff --git a/src/smi_driver.c b/src/smi_driver.c new file mode 100644 index 0000000..ffd946e --- /dev/null +++ b/src/smi_driver.c @@ -0,0 +1,3294 @@ +/* Header: //Mercury/Projects/archives/XFree86/4.0/smi_driver.c-arc 1.42 03 Jan 2001 13:52:16 Frido $ */ + +/* +Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. +Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of The XFree86 Project and +Silicon Motion shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without prior written +authorization from The XFree86 Project or Silicon Motion. +*/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_driver.c,v 1.28.2.1 2003/05/09 02:22:00 dawes Exp $ */ + +#include "xf86Resources.h" +#include "xf86RAC.h" +#include "xf86DDC.h" +#include "xf86int10.h" +#include "vbe.h" +#include "shadowfb.h" + +#include "smi.h" + +#include "globals.h" +#define DPMS_SERVER +#include "extensions/dpms.h" + +/* + * Internals + */ +static void SMI_EnableMmio(ScrnInfoPtr pScrn); +static void SMI_DisableMmio(ScrnInfoPtr pScrn); + +/* + * Forward definitions for the functions that make up the driver. + */ + +static const OptionInfoRec * SMI_AvailableOptions(int chipid, int busid); +static void SMI_Identify(int flags); +static Bool SMI_Probe(DriverPtr drv, int flags); +static Bool SMI_PreInit(ScrnInfoPtr pScrn, int flags); +static Bool SMI_EnterVT(int scrnIndex, int flags); +static void SMI_LeaveVT(int scrnIndex, int flags); +static void SMI_Save (ScrnInfoPtr pScrn); +static void SMI_WriteMode (ScrnInfoPtr pScrn, vgaRegPtr, SMIRegPtr); +static Bool SMI_ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, + char **argv); +static int SMI_InternalScreenInit(int scrnIndex, ScreenPtr pScreen); +static void SMI_PrintRegs(ScrnInfoPtr); +static ModeStatus SMI_ValidMode(int scrnIndex, DisplayModePtr mode, + Bool verbose, int flags); +static void SMI_DisableVideo(ScrnInfoPtr pScrn); +static void SMI_EnableVideo(ScrnInfoPtr pScrn); +static Bool SMI_MapMem(ScrnInfoPtr pScrn); +static void SMI_UnmapMem(ScrnInfoPtr pScrn); +static Bool SMI_ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode); +static Bool SMI_CloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool SMI_SaveScreen(ScreenPtr pScreen, int mode); +static void SMI_LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies, + LOCO *colors, VisualPtr pVisual); +static void SMI_DisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagementMode, int flags); +static Bool SMI_ddc1(int scrnIndex); +static unsigned int SMI_ddc1Read(ScrnInfoPtr pScrn); +static void SMI_FreeScreen(int ScrnIndex, int flags); +static void SMI_ProbeDDC(ScrnInfoPtr pScrn, int index); + + +#define SILICONMOTION_NAME "Silicon Motion" +#define SILICONMOTION_DRIVER_NAME "siliconmotion" +#define SILICONMOTION_VERSION_NAME "1.3.1" +#define SILICONMOTION_VERSION_MAJOR 1 +#define SILICONMOTION_VERSION_MINOR 3 +#define SILICONMOTION_PATCHLEVEL 1 +#define SILICONMOTION_DRIVER_VERSION ((SILICONMOTION_VERSION_MAJOR << 24) | \ + (SILICONMOTION_VERSION_MINOR << 16) | \ + (SILICONMOTION_PATCHLEVEL)) + +/* + * This contains the functions needed by the server after loading the + * driver module. It must be supplied, and gets added the driver list by + * the Module Setup funtion in the dynamic case. In the static case a + * reference to this is compiled in, and this requires that the name of + * this DriverRec be an upper-case version of the driver name. + */ + +DriverRec SILICONMOTION = +{ + SILICONMOTION_DRIVER_VERSION, + SILICONMOTION_DRIVER_NAME, + SMI_Identify, + SMI_Probe, + SMI_AvailableOptions, + NULL, + 0 +}; + +/* Supported chipsets */ +static SymTabRec SMIChipsets[] = +{ + { PCI_CHIP_SMI910, "Lynx" }, + { PCI_CHIP_SMI810, "LynxE" }, + { PCI_CHIP_SMI820, "Lynx3D" }, + { PCI_CHIP_SMI710, "LynxEM" }, + { PCI_CHIP_SMI712, "LynxEM+" }, + { PCI_CHIP_SMI720, "Lynx3DM" }, + { -1, NULL } +}; + +static PciChipsets SMIPciChipsets[] = +{ + /* numChipset, PciID, Resource */ + { PCI_CHIP_SMI910, PCI_CHIP_SMI910, RES_SHARED_VGA }, + { PCI_CHIP_SMI810, PCI_CHIP_SMI810, RES_SHARED_VGA }, + { PCI_CHIP_SMI820, PCI_CHIP_SMI820, RES_SHARED_VGA }, + { PCI_CHIP_SMI710, PCI_CHIP_SMI710, RES_SHARED_VGA }, + { PCI_CHIP_SMI712, PCI_CHIP_SMI712, RES_SHARED_VGA }, + { PCI_CHIP_SMI720, PCI_CHIP_SMI720, RES_SHARED_VGA }, + { -1, -1, RES_UNDEFINED } +}; + +typedef enum +{ + OPTION_PCI_BURST, + OPTION_FIFO_CONSERV, + OPTION_FIFO_MODERATE, + OPTION_FIFO_AGGRESSIVE, + OPTION_PCI_RETRY, + OPTION_NOACCEL, + OPTION_MCLK, + OPTION_SHOWCACHE, + OPTION_SWCURSOR, + OPTION_HWCURSOR, + OPTION_SHADOW_FB, + OPTION_ROTATE, +#ifdef XvExtension + OPTION_VIDEOKEY, + OPTION_BYTESWAP, + /* CZ 26.10.2001: interlaced video */ + OPTION_INTERLACED, + /* end CZ */ +#endif + OPTION_USEBIOS, + OPTION_ZOOMONLCD, + NUMBER_OF_OPTIONS + +} SMIOpts; + +static const OptionInfoRec SMIOptions[] = +{ + { OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_FIFO_CONSERV, "fifo_conservative", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_FIFO_MODERATE, "fifo_moderate", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_FIFO_AGGRESSIVE, "fifo_aggressive", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_PCI_RETRY, "pci_retry", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_MCLK, "set_mclk", OPTV_FREQ, {0}, FALSE }, + { OPTION_SHOWCACHE, "show_cache", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_HWCURSOR, "HWCursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SWCURSOR, "SWCursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_ROTATE, "Rotate", OPTV_ANYSTR, {0}, FALSE }, +#ifdef XvExtension + { OPTION_VIDEOKEY, "VideoKey", OPTV_INTEGER, {0}, FALSE }, + { OPTION_BYTESWAP, "ByteSwap", OPTV_BOOLEAN, {0}, FALSE }, + /* CZ 26.10.2001: interlaced video */ + { OPTION_INTERLACED, "Interlaced", OPTV_BOOLEAN, {0}, FALSE }, + /* end CZ */ +#endif + { OPTION_USEBIOS, "UseBIOS", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_ZOOMONLCD, "ZoomOnLCD", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + +/* + * Lists of symbols that may/may not be required by this driver. + * This allows the loader to know which ones to issue warnings for. + * + * Note that vgahwSymbols and xaaSymbols are referenced outside the + * XFree86LOADER define in later code, so are defined outside of that + * define here also. + */ + +static const char *vgahwSymbols[] = +{ + "vgaHWCopyReg", + "vgaHWGetHWRec", + "vgaHWGetIOBase", + "vgaHWGetIndex", + "vgaHWInit", + "vgaHWLock", + "vgaHWMapMem", + "vgaHWProtect", + "vgaHWRestore", + "vgaHWSave", + "vgaHWSaveScreen", + "vgaHWSetMmioFuncs", + "vgaHWSetStdFuncs", + "vgaHWUnmapMem", + "vgaHWddc1SetSpeed", + NULL +}; + +static const char *xaaSymbols[] = +{ + "XAACopyROP", + "XAACreateInfoRec", + "XAADestroyInfoRec", + "XAAFallbackOps", + "XAAFillSolidRects", + "XAAInit", + "XAAPatternROP", + "XAAScreenIndex", + NULL +}; + +static const char *ramdacSymbols[] = +{ + "xf86CreateCursorInfoRec", + "xf86DestroyCursorInfoRec", + "xf86InitCursor", + NULL +}; + +static const char *ddcSymbols[] = +{ + "xf86PrintEDID", + "xf86DoEDID_DDC1", + "xf86DoEDID_DDC2", + "xf86SetDDCproperties", + NULL +}; + +static const char *i2cSymbols[] = +{ + "xf86CreateI2CBusRec", + "xf86CreateI2CDevRec", + "xf86DestroyI2CBusRec", + "xf86DestroyI2CDevRec", + "xf86I2CBusInit", + "xf86I2CDevInit", + "xf86I2CReadBytes", + "xf86I2CWriteByte", + NULL +}; + +static const char *shadowSymbols[] = +{ + "ShadowFBInit", + NULL +}; + +static const char *int10Symbols[] = +{ + "xf86ExecX86int10", + "xf86FreeInt10", + "xf86InitInt10", + NULL +}; + +static const char *vbeSymbols[] = +{ + "VBEInit", + "vbeDoEDID", + "vbeFree", + NULL +}; + +static const char *fbSymbols[] = +{ +#ifdef USE_FB + "fbPictureInit", + "fbScreenInit", +#else + "cfbScreenInit", + "cfb16ScreenInit", + "cfb24ScreenInit", + "cfb32ScreenInit", + "cfb16BresS", + "cfb24BresS", +#endif + NULL +}; + +#ifdef XFree86LOADER + +static MODULESETUPPROTO(siliconmotionSetup); + +static XF86ModuleVersionInfo SMIVersRec = +{ + "siliconmotion", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + SILICONMOTION_VERSION_MAJOR, + SILICONMOTION_VERSION_MINOR, + SILICONMOTION_PATCHLEVEL, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0, 0, 0, 0} +}; + +/* + * This is the module init data for XFree86 modules. + * + * Its name has to be the driver name followed by ModuleData. + */ +XF86ModuleData siliconmotionModuleData = +{ + &SMIVersRec, + siliconmotionSetup, + NULL +}; + +static pointer +siliconmotionSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + + if (!setupDone) + { + setupDone = TRUE; + xf86AddDriver(&SILICONMOTION, module, 0); + + /* + * Modules that this driver always requires can be loaded here + * by calling LoadSubModule(). + */ + + /* + * Tell the loader about symbols from other modules that this module + * might refer to. + */ + LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols, ramdacSymbols, + ddcSymbols, i2cSymbols, int10Symbols, vbeSymbols, + shadowSymbols, NULL); + + /* + * The return value must be non-NULL on success even though there + * is no TearDownProc. + */ + return (pointer) 1; + } + else + { + if (errmaj) + { + *errmaj = LDR_ONCEONLY; + } + return(NULL); + } +} + +#endif /* XFree86LOADER */ + +static Bool +SMI_GetRec(ScrnInfoPtr pScrn) +{ + ENTER_PROC("SMI_GetRec"); + + /* + * Allocate an 'Chip'Rec, and hook it into pScrn->driverPrivate. + * pScrn->driverPrivate is initialised to NULL, so we can check if + * the allocation has already been done. + */ + if (pScrn->driverPrivate == NULL) + { + pScrn->driverPrivate = xnfcalloc(sizeof(SMIRec), 1); + } + + LEAVE_PROC("SMI_GetRec"); + return(TRUE); +} + +static void +SMI_FreeRec(ScrnInfoPtr pScrn) +{ + ENTER_PROC("SMI_FreeRec"); + + if (pScrn->driverPrivate != NULL) + { + xfree(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; + } + + LEAVE_PROC("SMI_FreeRec"); +} + +static const OptionInfoRec * +SMI_AvailableOptions(int chipid, int busid) +{ + ENTER_PROC("SMI_AvailableOptions"); + LEAVE_PROC("SMI_AvailableOptions"); + return(SMIOptions); +} + +static void +SMI_Identify(int flags) +{ + ENTER_PROC("SMI_Identify"); + + xf86PrintChipsets(SILICONMOTION_NAME, "driver (version " + SILICONMOTION_VERSION_NAME ") for Silicon Motion Lynx chipsets", + SMIChipsets); + + LEAVE_PROC("SMI_Identify"); +} + +static Bool +SMI_Probe(DriverPtr drv, int flags) +{ + int i; + GDevPtr *devSections; + int *usedChips; + int numDevSections; + int numUsed; + Bool foundScreen = FALSE; + + ENTER_PROC("SMI_Probe"); + + numDevSections = xf86MatchDevice(SILICONMOTION_DRIVER_NAME, &devSections); + if (numDevSections <= 0) + { + /* There's no matching device section in the config file, so quit now. + */ + LEAVE_PROC("SMI_Probe"); + return(FALSE); + } + + if (xf86GetPciVideoInfo() == NULL) + { + LEAVE_PROC("SMI_Probe"); + return(FALSE); + } + + numUsed = xf86MatchPciInstances(SILICONMOTION_NAME, PCI_SMI_VENDOR_ID, + SMIChipsets, SMIPciChipsets, devSections, + numDevSections, drv, &usedChips); + + /* Free it since we don't need that list after this */ + xfree(devSections); + if (numUsed <= 0) + { + LEAVE_PROC("SMI_Probe"); + return(FALSE); + } + + if (flags & PROBE_DETECT) + { + foundScreen = TRUE; + } + else + { + for (i = 0; i < numUsed; i++) + { + /* Allocate a ScrnInfoRec and claim the slot */ + ScrnInfoPtr pScrn = xf86AllocateScreen(drv, 0); + + /* Fill in what we can of the ScrnInfoRec */ + pScrn->driverVersion = SILICONMOTION_DRIVER_VERSION; + pScrn->driverName = SILICONMOTION_DRIVER_NAME; + pScrn->name = SILICONMOTION_NAME; + pScrn->Probe = SMI_Probe; + pScrn->PreInit = SMI_PreInit; + pScrn->ScreenInit = SMI_ScreenInit; + pScrn->SwitchMode = SMI_SwitchMode; + pScrn->AdjustFrame = SMI_AdjustFrame; + pScrn->EnterVT = SMI_EnterVT; + pScrn->LeaveVT = SMI_LeaveVT; + pScrn->FreeScreen = SMI_FreeScreen; + pScrn->ValidMode = SMI_ValidMode; + foundScreen = TRUE; + + xf86ConfigActivePciEntity(pScrn, usedChips[i], SMIPciChipsets, NULL, + NULL, NULL, NULL, NULL); + } + } + xfree(usedChips); + + LEAVE_PROC("SMI_Probe"); + return(foundScreen); +} + +static Bool +SMI_PreInit(ScrnInfoPtr pScrn, int flags) +{ + EntityInfoPtr pEnt; + SMIPtr pSmi; + MessageType from; + int i; + double real; + ClockRangePtr clockRanges; +#ifndef USE_FB + char *mod = NULL; + const char *reqSym = NULL; +#endif + char *s; + unsigned char config, m, n, shift; + int mclk; + vgaHWPtr hwp; + int vgaCRIndex, vgaCRReg, vgaIOBase; + vbeInfoPtr pVbe = NULL; + + ENTER_PROC("SMI_PreInit"); + + if (flags & PROBE_DETECT) + { + SMI_ProbeDDC(pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index); + LEAVE_PROC("SMI_PreInit"); + return(TRUE); + } + + /* Ignoring the Type list for now. It might be needed when multiple cards + * are supported. + */ + if (pScrn->numEntities > 1) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + /* The vgahw module should be loaded here when needed */ + if (!xf86LoadSubModule(pScrn, "vgahw")) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + xf86LoaderReqSymLists(vgahwSymbols, NULL); + + /* + * Allocate a vgaHWRec + */ + if (!vgaHWGetHWRec(pScrn)) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + /* Allocate the SMIRec driverPrivate */ + if (!SMI_GetRec(pScrn)) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + pSmi = SMIPTR(pScrn); + + /* Set pScrn->monitor */ + pScrn->monitor = pScrn->confScreen->monitor; + + /* + * The first thing we should figure out is the depth, bpp, etc. Our + * default depth is 8, so pass it to the helper function. We support + * only 24bpp layouts, so indicate that. + */ + if (!xf86SetDepthBpp(pScrn, 8, 8, 8, Support24bppFb)) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + /* Check that the returned depth is one we support */ + switch (pScrn->depth) + { + case 8: + case 16: + case 24: + /* OK */ + break; + + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given depth (%d) is not supported by this driver\n", + pScrn->depth); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + xf86PrintDepthBpp(pScrn); + + /* + * This must happen after pScrn->display has been set because + * xf86SetWeight references it. + */ + if (pScrn->depth > 8) + { + /* The defaults are OK for us */ + rgb zeros = {0, 0, 0}; + + if (!xf86SetWeight(pScrn, zeros, zeros)) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + } + + if (!xf86SetDefaultVisual(pScrn, -1)) + { + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + /* We don't currently support DirectColor at > 8bpp */ + if ((pScrn->depth > 8) && (pScrn->defaultVisual != TrueColor)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual (%s) " + "is not supported at depth %d\n", + xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + /* We use a programmable clock */ + pScrn->progClock = TRUE; + + /* Collect all of the relevant option flags (fill in pScrn->options) */ + xf86CollectOptions(pScrn, NULL); + + /* Set the bits per RGB for 8bpp mode */ + if (pScrn->depth == 8) + { + pScrn->rgbBits = 6; + } + + /* Process the options */ + if (!(pSmi->Options = xalloc(sizeof(SMIOptions)))) + return FALSE; + memcpy(pSmi->Options, SMIOptions, sizeof(SMIOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pSmi->Options); + + if (xf86ReturnOptValBool(pSmi->Options, OPTION_PCI_BURST, FALSE)) + { + pSmi->pci_burst = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_burst - PCI burst " + "read enabled\n"); + } + else + { + pSmi->pci_burst = FALSE; + } + + pSmi->NoPCIRetry = TRUE; + if (xf86ReturnOptValBool(pSmi->Options, OPTION_PCI_RETRY, FALSE)) + { + if (xf86ReturnOptValBool(pSmi->Options, OPTION_PCI_BURST, FALSE)) + { + pSmi->NoPCIRetry = FALSE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_retry\n"); + } + else + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"pci_retry\" option " + "requires \"pci_burst\".\n"); + } + } + + if (xf86IsOptionSet(pSmi->Options, OPTION_FIFO_CONSERV)) + { + pSmi->fifo_conservative = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_conservative " + "set\n"); + } + else + { + pSmi->fifo_conservative = FALSE; + } + + if (xf86IsOptionSet(pSmi->Options, OPTION_FIFO_MODERATE)) + { + pSmi->fifo_moderate = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_moderate set\n"); + } + else + { + pSmi->fifo_moderate = FALSE; + } + + if (xf86IsOptionSet(pSmi->Options, OPTION_FIFO_AGGRESSIVE)) + { + pSmi->fifo_aggressive = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_aggressive set\n"); + } + else + { + pSmi->fifo_aggressive = FALSE; + } + + if (xf86ReturnOptValBool(pSmi->Options, OPTION_NOACCEL, FALSE)) + { + pSmi->NoAccel = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: NoAccel - Acceleration " + "disabled\n"); + } + else + { + pSmi->NoAccel = FALSE; + } + + if (xf86ReturnOptValBool(pSmi->Options, OPTION_SHOWCACHE, FALSE)) + { + pSmi->ShowCache = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: show_cache set\n"); + } + else + { + pSmi->ShowCache = FALSE; + } + + if (xf86GetOptValFreq(pSmi->Options, OPTION_MCLK, OPTUNITS_MHZ, &real)) + { + pSmi->MCLK = (int)(real * 1000.0); + if (pSmi->MCLK <= 120000) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: set_mclk set to " + "%1.3f MHz\n", pSmi->MCLK / 1000.0); + } + else + { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Memory Clock value of " + "%1.3f MHz is larger than limit of 120 MHz\n", + pSmi->MCLK / 1000.0); + pSmi->MCLK = 0; + } + } + else + { + pSmi->MCLK = 0; + } + + from = X_DEFAULT; + pSmi->hwcursor = TRUE; + if (xf86GetOptValBool(pSmi->Options, OPTION_HWCURSOR, &pSmi->hwcursor)) + { + from = X_CONFIG; + } + if (xf86ReturnOptValBool(pSmi->Options, OPTION_SWCURSOR, FALSE)) + { + pSmi->hwcursor = FALSE; + from = X_CONFIG; + } + xf86DrvMsg(pScrn->scrnIndex, from, "Using %s Cursor\n", + pSmi->hwcursor ? "Hardware" : "Software"); + + if (xf86GetOptValBool(pSmi->Options, OPTION_SHADOW_FB, &pSmi->shadowFB)) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowFB %s.\n", + pSmi->shadowFB ? "enabled" : "disabled"); + } + +#if 1 /* PDR#932 */ + if ((pScrn->depth == 8) || (pScrn->depth == 16)) +#endif /* PDR#932 */ + if ((s = xf86GetOptValString(pSmi->Options, OPTION_ROTATE))) + { + if(!xf86NameCmp(s, "CW")) + { + pSmi->shadowFB = TRUE; + pSmi->rotate = SMI_ROTATE_CCW; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen " + "clockwise\n"); + } + else if (!xf86NameCmp(s, "CCW")) + { + pSmi->shadowFB = TRUE; + pSmi->rotate = SMI_ROTATE_CW; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen counter " + "clockwise\n"); + } + else + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid " + "value for Option \"Rotate\"\n", s); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid options are \"CW\" or " + "\"CCW\"\n"); + } + } + +#ifdef XvExtension + if (xf86GetOptValInteger(pSmi->Options, OPTION_VIDEOKEY, &pSmi->videoKey)) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: Video key set to " + "0x%08X\n", pSmi->videoKey); + } + else + { + pSmi->videoKey = (1 << pScrn->offset.red) | (1 << pScrn->offset.green) + | (((pScrn->mask.blue >> pScrn->offset.blue) - 1) + << pScrn->offset.blue); + } + + if (xf86ReturnOptValBool(pSmi->Options, OPTION_BYTESWAP, FALSE)) + { + pSmi->ByteSwap = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: ByteSwap enabled.\n"); + } + else + { + pSmi->ByteSwap = FALSE; + } + + /* CZ 26.10.2001: interlaced video */ + if (xf86ReturnOptValBool(pSmi->Options, OPTION_INTERLACED, FALSE)) + { + pSmi->interlaced = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: Interlaced enabled.\n"); + } + else + { + pSmi->interlaced = FALSE; + } + /* end CZ */ +#endif + + if (xf86GetOptValBool(pSmi->Options, OPTION_USEBIOS, &pSmi->useBIOS)) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: UseBIOS %s.\n", + pSmi->useBIOS ? "enabled" : "disabled"); + } + else + { + /* Default to UseBIOS enabled. */ + pSmi->useBIOS = TRUE; + } + + if (xf86GetOptValBool(pSmi->Options, OPTION_ZOOMONLCD, &pSmi->zoomOnLCD)) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: ZoomOnLCD %s.\n", + pSmi->zoomOnLCD ? "enabled" : "disabled"); + } + else + { + /* Default to ZoomOnLCD enabled. */ + pSmi->zoomOnLCD = TRUE; + } + + /* Find the PCI slot for this screen */ + pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + if ((pEnt->location.type != BUS_PCI) || (pEnt->resources)) + { + xfree(pEnt); + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + if (xf86LoadSubModule(pScrn,"int10")) { + xf86LoaderReqSymLists(int10Symbols,NULL); + pSmi->pInt10 = xf86InitInt10(pEnt->index); + } + + if (pSmi->pInt10 && xf86LoadSubModule(pScrn, "vbe")) + { + xf86LoaderReqSymLists(vbeSymbols, NULL); + pVbe = VBEInit(pSmi->pInt10, pEnt->index); + } + + pSmi->PciInfo = xf86GetPciInfoForEntity(pEnt->index); + xf86RegisterResources(pEnt->index, NULL, ResExclusive); +/* xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr); */ +/* xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr); */ + + /* + * Set the Chipset and ChipRev, allowing config file entries to + * override. + */ + if (pEnt->device->chipset && *pEnt->device->chipset) + { + pScrn->chipset = pEnt->device->chipset; + pSmi->Chipset = xf86StringToToken(SMIChipsets, pScrn->chipset); + from = X_CONFIG; + } + else if (pEnt->device->chipID >= 0) + { + pSmi->Chipset = pEnt->device->chipID; + pScrn->chipset = (char *) xf86TokenToString(SMIChipsets, pSmi->Chipset); + from = X_CONFIG; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", + pSmi->Chipset); + } + else + { + from = X_PROBED; + pSmi->Chipset = pSmi->PciInfo->chipType; + pScrn->chipset = (char *) xf86TokenToString(SMIChipsets, pSmi->Chipset); + } + + if (pEnt->device->chipRev >= 0) + { + pSmi->ChipRev = pEnt->device->chipRev; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", + pSmi->ChipRev); + } + else + { + pSmi->ChipRev = pSmi->PciInfo->chipRev; + } + xfree(pEnt); + + /* + * This shouldn't happen because such problems should be caught in + * SMI_Probe(), but check it just in case. + */ + if (pScrn->chipset == NULL) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ChipID 0x%04X is not " + "recognised\n", pSmi->Chipset); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + if (pSmi->Chipset < 0) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Chipset \"%s\" is not " + "recognised\n", pScrn->chipset); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset); + + pSmi->PciTag = pciTag(pSmi->PciInfo->bus, pSmi->PciInfo->device, + pSmi->PciInfo->func); + + SMI_MapMem(pScrn); + SMI_DisableVideo(pScrn); + + hwp = VGAHWPTR(pScrn); + vgaIOBase = hwp->IOBase; + vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET; + vgaCRReg = vgaIOBase + VGA_CRTC_DATA_OFFSET; + pSmi->PIOBase = hwp->PIOOffset; + + xf86ErrorFVerb(VERBLEV, "\tSMI_PreInit vgaCRIndex=%x, vgaIOBase=%x, " + "MMIOBase=%x\n", vgaCRIndex, vgaIOBase, hwp->MMIOBase); + + /* Next go on to detect amount of installed ram */ + config = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x71); + + if (xf86LoadSubModule(pScrn, "i2c")) + { + xf86LoaderReqSymLists(i2cSymbols, NULL); + SMI_I2CInit(pScrn); + } + if (xf86LoadSubModule(pScrn, "ddc")) + { + xf86MonPtr pMon = NULL; + + xf86LoaderReqSymLists(ddcSymbols, NULL); +#if 1 /* PDR#579 */ + if (pVbe) + { + pMon = vbeDoEDID(pVbe, NULL); + if (pMon != NULL) + { + if ( (pMon->rawData[0] == 0x00) + && (pMon->rawData[1] == 0xFF) + && (pMon->rawData[2] == 0xFF) + && (pMon->rawData[3] == 0xFF) + && (pMon->rawData[4] == 0xFF) + && (pMon->rawData[5] == 0xFF) + && (pMon->rawData[6] == 0xFF) + && (pMon->rawData[7] == 0x00) + ) + { + pMon = xf86PrintEDID(pMon); + if (pMon != NULL) + { + xf86SetDDCproperties(pScrn, pMon); + } + } + } + } +#else + if ( (pVbe) + && ((pMon = xf86PrintEDID(vbeDoEDID(pVbe, NULL))) != NULL) + ) + { + xf86SetDDCproperties(pScrn, pMon); + } +#endif + else if (!SMI_ddc1(pScrn->scrnIndex)) + { + if (pSmi->I2C) + { + xf86SetDDCproperties(pScrn, + xf86PrintEDID(xf86DoEDID_DDC2(pScrn->scrnIndex, + pSmi->I2C))); + } + } + } + + vbeFree(pVbe); + xf86FreeInt10(pSmi->pInt10); + pSmi->pInt10 = NULL; + + /* + * If the driver can do gamma correction, it should call xf86SetGamma() + * here. (from MGA, no ViRGE gamma support yet, but needed for + * xf86HandleColormaps support.) + */ + { + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrn, zeros)) + { + LEAVE_PROC("SMI_PreInit"); + SMI_EnableVideo(pScrn); + SMI_UnmapMem(pScrn); + return(FALSE); + } + } + + /* And compute the amount of video memory and offscreen memory */ + pSmi->videoRAMKBytes = 0; + + if (!pScrn->videoRam) + { + switch (pSmi->Chipset) + { + default: + { + int mem_table[4] = { 1, 2, 4, 0 }; + pSmi->videoRAMKBytes = mem_table[(config >> 6)] * 1024; + break; + } + + case SMI_LYNX3D: + { + int mem_table[4] = { 0, 2, 4, 6 }; + pSmi->videoRAMKBytes = mem_table[(config >> 6)] * 1024 + 512; + break; + } + + case SMI_LYNX3DM: + { + int mem_table[4] = { 16, 2, 4, 8 }; + pSmi->videoRAMKBytes = mem_table[(config >> 6)] * 1024; + break; + } + } + pSmi->videoRAMBytes = pSmi->videoRAMKBytes * 1024; + pScrn->videoRam = pSmi->videoRAMKBytes; + + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "videoram: %dkB\n", + pSmi->videoRAMKBytes); + } + else + { + pSmi->videoRAMKBytes = pScrn->videoRam; + pSmi->videoRAMBytes = pScrn->videoRam * 1024; + + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "videoram: %dk\n", + pSmi->videoRAMKBytes); + } + + /* Lynx built-in ramdac speeds */ + pScrn->numClocks = 4; + + if ((pScrn->clock[3] <= 0) && (pScrn->clock[2] > 0)) + { + pScrn->clock[3] = pScrn->clock[2]; + } + + if (pSmi->Chipset == SMI_LYNX3DM) + { + if (pScrn->clock[0] <= 0) pScrn->clock[0] = 200000; + if (pScrn->clock[1] <= 0) pScrn->clock[1] = 200000; + if (pScrn->clock[2] <= 0) pScrn->clock[2] = 200000; + if (pScrn->clock[3] <= 0) pScrn->clock[3] = 200000; + } + else + { + if (pScrn->clock[0] <= 0) pScrn->clock[0] = 135000; + if (pScrn->clock[1] <= 0) pScrn->clock[1] = 135000; + if (pScrn->clock[2] <= 0) pScrn->clock[2] = 135000; + if (pScrn->clock[3] <= 0) pScrn->clock[3] = 135000; + } + + /* Now set RAMDAC limits */ + switch (pSmi->Chipset) + { + default: + pSmi->minClock = 20000; + pSmi->maxClock = 135000; + break; + } + xf86ErrorFVerb(VERBLEV, "\tSMI_PreInit minClock=%d, maxClock=%d\n", + pSmi->minClock, pSmi->maxClock); + + /* Detect current MCLK and print it for user */ + m = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A); + n = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B); + switch (n >> 6) + { + default: + shift = 1; + break; + + case 1: + shift = 4; + break; + + case 2: + shift = 2; + break; + } + n &= 0x3F; + mclk = ((1431818 * m) / n / shift + 50) / 100; + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected current MCLK value of " + "%1.3f MHz\n", mclk / 1000.0); + + SMI_EnableVideo(pScrn); + SMI_UnmapMem(pScrn); + + pScrn->virtualX = pScrn->display->virtualX; + + /* + * Setup the ClockRanges, which describe what clock ranges are available, + * and what sort of modes they can be used for. + */ + clockRanges = xnfcalloc(sizeof(ClockRange),1); + clockRanges->next = NULL; + clockRanges->minClock = pSmi->minClock; + clockRanges->maxClock = pSmi->maxClock; + clockRanges->clockIndex = -1; + clockRanges->interlaceAllowed = FALSE; + clockRanges->doubleScanAllowed = FALSE; + + i = xf86ValidateModes( + pScrn, /* Screen pointer */ + pScrn->monitor->Modes, /* Available monitor modes */ + pScrn->display->modes, /* req mode names for screen */ + clockRanges, /* list of clock ranges allowed */ + NULL, /* use min/max below */ + 128, /* min line pitch (width) */ + 4096, /* maximum line pitch (width) */ + 128, /* bits of granularity for line pitch */ + /* (width) above */ + 128, /* min virtual height */ + 4096, /* max virtual height */ + pScrn->display->virtualX, /* force virtual x */ + pScrn->display->virtualY, /* force virtual Y */ + pSmi->videoRAMBytes, /* size of aperture used to access */ + /* video memory */ + LOOKUP_BEST_REFRESH); /* how to pick modes */ + + if (i == -1) + { + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + /* Prune the modes marked as invalid */ + xf86PruneDriverModes(pScrn); + + if ((i == 0) || (pScrn->modes == NULL)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + xf86SetCrtcForModes(pScrn, 0); + + /* Set the current mode to the first in the list */ + pScrn->currentMode = pScrn->modes; + + /* Print the list of modes being used */ + xf86PrintModes(pScrn); + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + +#ifdef USE_FB + if ((xf86LoadSubModule(pScrn, "fb") == NULL)) + { + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + xf86LoaderReqSymLists(fbSymbols, NULL); +#else + /* Load bpp-specific modules */ + switch (pScrn->bitsPerPixel) + { + case 8: + mod = "cfb"; + reqSym = "cfbScreenInit"; + break; + + case 16: + mod = "cfb16"; + reqSym = "cfb16ScreenInit"; + break; + + case 24: + mod = "cfb24"; + reqSym = "cfb24ScreenInit"; + break; + } + + if (mod && (xf86LoadSubModule(pScrn, mod) == NULL)) + { + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + + xf86LoaderReqSymbols(reqSym, NULL); +#endif + /* Load XAA if needed */ + if (!pSmi->NoAccel || pSmi->hwcursor) + { + if (!xf86LoadSubModule(pScrn, "xaa")) + { + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + xf86LoaderReqSymLists(xaaSymbols, NULL); + } + + /* Load ramdac if needed */ + if (pSmi->hwcursor) + { + if (!xf86LoadSubModule(pScrn, "ramdac")) + { + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + xf86LoaderReqSymLists(ramdacSymbols, NULL); + } + + if (pSmi->shadowFB) + { + if (!xf86LoadSubModule(pScrn, "shadowfb")) + { + SMI_FreeRec(pScrn); + LEAVE_PROC("SMI_PreInit"); + return(FALSE); + } + xf86LoaderReqSymLists(shadowSymbols, NULL); + } + + LEAVE_PROC("SMI_PreInit"); + return(TRUE); +} + +/* + * This is called when VT switching back to the X server. Its job is to + * reinitialise the video mode. We may wish to unmap video/MMIO memory too. + */ + +static Bool +SMI_EnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + SMIPtr pSmi = SMIPTR(pScrn); + Bool ret; + + ENTER_PROC("SMI_EnterVT"); + + /* Enable MMIO and map memory */ + SMI_MapMem(pScrn); + SMI_Save(pScrn); + + /* #670 */ + if (pSmi->shadowFB) + { + pSmi->FBOffset = pSmi->savedFBOffset; + pSmi->FBReserved = pSmi->savedFBReserved; + } + + ret = SMI_ModeInit(pScrn, pScrn->currentMode); + + /* #670 */ + if (ret && pSmi->shadowFB) + { + BoxRec box; + + /* #920 */ + if (pSmi->paletteBuffer) + { + int i; + + VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, 0); + for(i = 0; i < 256 * 3; i++) + { + VGAOUT8(pSmi, VGA_DAC_DATA, pSmi->paletteBuffer[i]); + } + xfree(pSmi->paletteBuffer); + pSmi->paletteBuffer = NULL; + } + + if (pSmi->pSaveBuffer) + { + memcpy(pSmi->FBBase, pSmi->pSaveBuffer, pSmi->saveBufferSize); + xfree(pSmi->pSaveBuffer); + pSmi->pSaveBuffer = NULL; + } + + box.x1 = 0; + box.y1 = 0; + box.x2 = pScrn->virtualY; + box.y2 = pScrn->virtualX; + SMI_RefreshArea(pScrn, 1, &box); + } + + /* Reset the grapics engine */ + if (!pSmi->NoAccel) + SMI_EngineReset(pScrn); + + LEAVE_PROC("SMI_EnterVT"); + return(ret); +} + +/* + * This is called when VT switching away from the X server. Its job is to + * restore the previous (text) mode. We may wish to remap video/MMIO memory + * too. + */ + +static void +SMI_LeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + vgaRegPtr vgaSavePtr = &hwp->SavedReg; + SMIRegPtr SMISavePtr = &pSmi->SavedReg; + + ENTER_PROC("SMI_LeaveVT"); + + /* #670 */ + if (pSmi->shadowFB) + { + pSmi->pSaveBuffer = xnfalloc(pSmi->saveBufferSize); + if (pSmi->pSaveBuffer) + { + memcpy(pSmi->pSaveBuffer, pSmi->FBBase, pSmi->saveBufferSize); + } + + pSmi->savedFBOffset = pSmi->FBOffset; + pSmi->savedFBReserved = pSmi->FBReserved; + + /* #920 */ + if (pSmi->Bpp == 1) + { + pSmi->paletteBuffer = xnfalloc(256 * 3); + if (pSmi->paletteBuffer) + { + int i; + + VGAOUT8(pSmi, VGA_DAC_READ_ADDR, 0); + for (i = 0; i < 256 * 3; i++) + { + pSmi->paletteBuffer[i] = VGAIN8(pSmi, VGA_DAC_DATA); + } + } + } + } + + memset(pSmi->FBBase, 0, 256 * 1024); /* #689 */ + SMI_WriteMode(pScrn, vgaSavePtr, SMISavePtr); + SMI_UnmapMem(pScrn); + + LEAVE_PROC("SMI_LeaveVT"); +} + +/* + * This function performs the inverse of the restore function: It saves all the + * standard and extended registers that we are going to modify to set up a video + * mode. + */ + +static void +SMI_Save(ScrnInfoPtr pScrn) +{ + int i; + CARD32 offset; + + vgaHWPtr hwp = VGAHWPTR(pScrn); + vgaRegPtr vgaSavePtr = &hwp->SavedReg; + SMIPtr pSmi = SMIPTR(pScrn); + SMIRegPtr save = &pSmi->SavedReg; + + int vgaIOBase = hwp->IOBase; + int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET; + int vgaCRData = vgaIOBase + VGA_CRTC_DATA_OFFSET; + + ENTER_PROC("SMI_Save"); + + /* Save the standard VGA registers */ + vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL); + save->smiDACMask = VGAIN8(pSmi, VGA_DAC_MASK); + VGAOUT8(pSmi, VGA_DAC_READ_ADDR, 0); + for (i = 0; i < 256; i++) + { + save->smiDacRegs[i][0] = VGAIN8(pSmi, VGA_DAC_DATA); + save->smiDacRegs[i][1] = VGAIN8(pSmi, VGA_DAC_DATA); + save->smiDacRegs[i][2] = VGAIN8(pSmi, VGA_DAC_DATA); + } + for (i = 0, offset = 2; i < 8192; i++, offset += 8) + { + save->smiFont[i] = *(pSmi->FBBase + offset); + } + + /* Now we save all the extended registers we need. */ + save->SR17 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17); + save->SR18 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18); + save->SR21 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21); + save->SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31); + save->SR32 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32); + save->SR6A = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A); + save->SR6B = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B); + save->SR81 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81); + save->SRA0 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0xA0); + + if (SMI_LYNXM_SERIES(pSmi->Chipset)) + { + /* Save primary registers */ + save->CR90[14] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E); + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, + save->CR90[14] & ~0x20); + + for (i = 0; i < 16; i++) + { + save->CR90[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x90 + i); + } + save->CR33 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33); + save->CR3A = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A); + for (i = 0; i < 14; i++) + { + save->CR40[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i); + } + + /* Save secondary registers */ + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14] | 0x20); + save->CR33_2 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33); + for (i = 0; i < 14; i++) + { + save->CR40_2[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, + 0x40 + i); + } + save->CR9F_2 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9F); + + /* Save common registers */ + for (i = 0; i < 14; i++) + { + save->CRA0[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0xA0 + i); + } + + /* PDR#1069 */ + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14]); + } + else + { + save->CR33 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33); + save->CR3A = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A); + for (i = 0; i < 14; i++) + { + save->CR40[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i); + } + } + + /* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */ + if (pSmi->Chipset == SMI_LYNX3DM) { + save->CCR66 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66); + } + /* end CZ */ + + save->DPR10 = READ_DPR(pSmi, 0x10); + save->DPR1C = READ_DPR(pSmi, 0x1C); + save->DPR20 = READ_DPR(pSmi, 0x20); + save->DPR24 = READ_DPR(pSmi, 0x24); + save->DPR28 = READ_DPR(pSmi, 0x28); + save->DPR2C = READ_DPR(pSmi, 0x2C); + save->DPR30 = READ_DPR(pSmi, 0x30); + save->DPR3C = READ_DPR(pSmi, 0x3C); + save->DPR40 = READ_DPR(pSmi, 0x40); + save->DPR44 = READ_DPR(pSmi, 0x44); + + save->VPR00 = READ_VPR(pSmi, 0x00); + save->VPR0C = READ_VPR(pSmi, 0x0C); + save->VPR10 = READ_VPR(pSmi, 0x10); + + save->CPR00 = READ_CPR(pSmi, 0x00); + + if (!pSmi->ModeStructInit) + { + /* XXX Should check the return value of vgaHWCopyReg() */ + vgaHWCopyReg(&hwp->ModeReg, vgaSavePtr); + memcpy(&pSmi->ModeReg, save, sizeof(SMIRegRec)); + pSmi->ModeStructInit = TRUE; + } + + if (pSmi->useBIOS && (pSmi->pInt10 != NULL)) + { + pSmi->pInt10->num = 0x10; + pSmi->pInt10->ax = 0x0F00; + xf86ExecX86int10(pSmi->pInt10); + save->mode = pSmi->pInt10->ax & 0x007F; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Current mode 0x%02X.\n", + save->mode); + } + + if (xf86GetVerbosity() > 1) + { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "Saved current video mode. Register dump:\n"); + SMI_PrintRegs(pScrn); + } + + LEAVE_PROC("SMI_Save"); +} + +/* + * This function is used to restore a video mode. It writes out all of the + * standard VGA and extended registers needed to setup a video mode. + */ + +static void +SMI_WriteMode(ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr, SMIRegPtr restore) +{ + int i; + CARD8 tmp; + CARD32 offset; + + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + int vgaIOBase = hwp->IOBase; + int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET; + int vgaCRData = vgaIOBase + VGA_CRTC_DATA_OFFSET; + + ENTER_PROC("SMI_WriteMode"); + + vgaHWProtect(pScrn, TRUE); + + /* Wait for engine to become idle */ + WaitIdle(); + + if (pSmi->useBIOS && (pSmi->pInt10 != NULL) + && (restore->mode != 0)) + { + pSmi->pInt10->num = 0x10; + pSmi->pInt10->ax = restore->mode | 0x80; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode 0x%02X\n", + restore->mode); + xf86ExecX86int10(pSmi->pInt10); + + /* Enable linear mode. */ + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18); + tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA); + outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp | 0x01); + + /* Enable DPR/VPR registers. */ + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03); + } + else + { + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17, restore->SR17); + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18) & ~0x1F; + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18, tmp | + (restore->SR18 & 0x1F)); + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03); + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31) & ~0xC0; + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, tmp | + (restore->SR31 & 0xC0)); + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32) & ~0x07; + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32, tmp | + (restore->SR32 & 0x07)); + if (restore->SR6B != 0xFF) + { + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A, + restore->SR6A); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B, + restore->SR6B); + } + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, restore->SR81); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0xA0, restore->SRA0); + + /* Restore the standard VGA registers */ + vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL); + if (restore->smiDACMask) + { + VGAOUT8(pSmi, VGA_DAC_MASK, restore->smiDACMask); + } + else + { + VGAOUT8(pSmi, VGA_DAC_MASK, 0xFF); + } + VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, 0); + for (i = 0; i < 256; i++) + { + VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][0]); + VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][1]); + VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][2]); + } + for (i = 0, offset = 2; i < 8192; i++, offset += 8) + { + *(pSmi->FBBase + offset) = restore->smiFont[i]; + } + + if (SMI_LYNXM_SERIES(pSmi->Chipset)) + { + /* Restore secondary registers */ + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, + restore->CR90[14] | 0x20); + + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33_2); + for (i = 0; i < 14; i++) + { + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i, + restore->CR40_2[i]); + } + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9F, restore->CR9F_2); + + /* Restore primary registers */ + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, + restore->CR90[14] & ~0x20); + + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33); + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A, restore->CR3A); + for (i = 0; i < 14; i++) + { + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i, + restore->CR40[i]); + } + for (i = 0; i < 16; i++) + { + if (i != 14) + { + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x90 + i, + restore->CR90[i]); + } + } + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, restore->CR90[14]); + + /* Restore common registers */ + for (i = 0; i < 14; i++) + { + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0xA0 + i, + restore->CRA0[i]); + } + } + + /* Restore the standard VGA registers */ + if (xf86IsPrimaryPci(pSmi->PciInfo)) { + vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_CMAP + | VGA_SR_FONTS); + } + + if (restore->modeInit) + vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL); + + if (!SMI_LYNXM_SERIES(pSmi->Chipset)) + { + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33); + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A, restore->CR3A); + for (i = 0; i < 14; i++) + { + VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i, + restore->CR40[i]); + } + } + } + + /* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */ + if (pSmi->Chipset == SMI_LYNX3DM) { + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66, restore->CCR66); + } + /* end CZ */ + + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, 0x00); + + WRITE_DPR(pSmi, 0x10, restore->DPR10); + WRITE_DPR(pSmi, 0x1C, restore->DPR1C); + WRITE_DPR(pSmi, 0x20, restore->DPR20); + WRITE_DPR(pSmi, 0x24, restore->DPR24); + WRITE_DPR(pSmi, 0x28, restore->DPR28); + WRITE_DPR(pSmi, 0x2C, restore->DPR2C); + WRITE_DPR(pSmi, 0x30, restore->DPR30); + WRITE_DPR(pSmi, 0x3C, restore->DPR3C); + WRITE_DPR(pSmi, 0x40, restore->DPR40); + WRITE_DPR(pSmi, 0x44, restore->DPR44); + + WRITE_VPR(pSmi, 0x00, restore->VPR00); + WRITE_VPR(pSmi, 0x0C, restore->VPR0C); + WRITE_VPR(pSmi, 0x10, restore->VPR10); + + WRITE_CPR(pSmi, 0x00, restore->CPR00); + + if (xf86GetVerbosity() > 1) + { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "Done restoring mode. Register dump:\n"); + SMI_PrintRegs(pScrn); + } + + vgaHWProtect(pScrn, FALSE); + + LEAVE_PROC("SMI_WriteMode"); +} + +static Bool +SMI_MapMem(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + vgaHWPtr hwp; + CARD32 memBase; + + ENTER_PROC("SMI_MapMem"); + + /* Map the Lynx register space */ + switch (pSmi->Chipset) + { + default: + memBase = pSmi->PciInfo->memBase[0] + 0x400000; + pSmi->MapSize = 0x10000; + break; + + case SMI_LYNX3D: + memBase = pSmi->PciInfo->memBase[0] + 0x680000; + pSmi->MapSize = 0x180000; + break; + + case SMI_LYNXEM: + case SMI_LYNXEMplus: + memBase = pSmi->PciInfo->memBase[0] + 0x400000; + pSmi->MapSize = 0x400000; + break; + + case SMI_LYNX3DM: + memBase = pSmi->PciInfo->memBase[0]; + pSmi->MapSize = 0x200000; + break; + } + pSmi->MapBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pSmi->PciTag, + memBase, pSmi->MapSize); + + if (pSmi->MapBase == NULL) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Internal error: could not map " + "MMIO registers.\n"); + LEAVE_PROC("SMI_MapMem"); + return(FALSE); + } + + switch (pSmi->Chipset) + { + default: + pSmi->DPRBase = pSmi->MapBase + 0x8000; + pSmi->VPRBase = pSmi->MapBase + 0xC000; + pSmi->CPRBase = pSmi->MapBase + 0xE000; + pSmi->IOBase = NULL; + pSmi->DataPortBase = pSmi->MapBase; + pSmi->DataPortSize = 0x8000; + break; + + case SMI_LYNX3D: + pSmi->DPRBase = pSmi->MapBase + 0x000000; + pSmi->VPRBase = pSmi->MapBase + 0x000800; + pSmi->CPRBase = pSmi->MapBase + 0x001000; + pSmi->IOBase = pSmi->MapBase + 0x040000; + pSmi->DataPortBase = pSmi->MapBase + 0x080000; + pSmi->DataPortSize = 0x100000; + break; + + case SMI_LYNXEM: + case SMI_LYNXEMplus: + pSmi->DPRBase = pSmi->MapBase + 0x008000; + pSmi->VPRBase = pSmi->MapBase + 0x00C000; + pSmi->CPRBase = pSmi->MapBase + 0x00E000; + pSmi->IOBase = pSmi->MapBase + 0x300000; + pSmi->DataPortBase = pSmi->MapBase /*+ 0x100000*/; + pSmi->DataPortSize = 0x8000 /*0x200000*/; + break; + + case SMI_LYNX3DM: + pSmi->DPRBase = pSmi->MapBase + 0x000000; + pSmi->VPRBase = pSmi->MapBase + 0x000800; + pSmi->CPRBase = pSmi->MapBase + 0x001000; + pSmi->IOBase = pSmi->MapBase + 0x0C0000; + pSmi->DataPortBase = pSmi->MapBase + 0x100000; + pSmi->DataPortSize = 0x100000; + break; + } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "Physical MMIO at 0x%08X\n", memBase); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "Logical MMIO at 0x%08X - 0x%08X\n", pSmi->MapBase, + pSmi->MapBase + pSmi->MapSize - 1); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "DPR=0x%08X, VPR=0x%08X, IOBase=0x%08X\n", pSmi->DPRBase, + pSmi->VPRBase, pSmi->IOBase); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "DataPort=0x%08X - 0x%08X\n", pSmi->DataPortBase, + pSmi->DataPortBase + pSmi->DataPortSize - 1); + + /* Map the frame buffer */ + if (pSmi->Chipset == SMI_LYNX3DM) + { + pScrn->memPhysBase = pSmi->PciInfo->memBase[0] + 0x200000; + } + else + { + pScrn->memPhysBase = pSmi->PciInfo->memBase[0]; + } + if (pSmi->videoRAMBytes) + { + pSmi->FBBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, + pSmi->PciTag, pScrn->memPhysBase, pSmi->videoRAMBytes); + + if (pSmi->FBBase == NULL) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Internal error: could not " + "map framebuffer.\n"); + LEAVE_PROC("SMI_MapMem"); + return(FALSE); + } + } + pSmi->FBOffset = pScrn->fbOffset = 0; + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "Physical frame buffer at 0x%08X\n", pScrn->memPhysBase); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "Logical frame buffer at 0x%08X - 0x%08X\n", pSmi->FBBase, + pSmi->FBBase + pSmi->videoRAMBytes - 1); + + SMI_EnableMmio(pScrn); + + /* Set up offset to hwcursor memory area. It's a 1K chunk at the end of + * the frame buffer. Also set up the reserved memory space. + */ + pSmi->FBCursorOffset = pSmi->videoRAMBytes - 1024; + if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x01)/* #1074 */ + { + CARD32 fifoOffset = 0; + fifoOffset |= VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x46) + << 3; + fifoOffset |= VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x47) + << 11; + fifoOffset |= (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x49) + & 0x1C) << 17; + pSmi->FBReserved = fifoOffset; /* PDR#1074 */ + } + else + { + pSmi->FBReserved = pSmi->videoRAMBytes - 2048; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Cursor Offset: %08X Reserved: %08X\n", + pSmi->FBCursorOffset, pSmi->FBReserved); + + pSmi->lcd = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31) & 0x01; + if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x01) + { + pSmi->lcd <<= 1; + } + switch (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x0C) + { + case 0x00: + pSmi->lcdWidth = 640; + pSmi->lcdHeight = 480; + break; + + case 0x04: + pSmi->lcdWidth = 800; + pSmi->lcdHeight = 600; + break; + + case 0x08: + if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x74) & 0x02) + { + pSmi->lcdWidth = 1024; + pSmi->lcdHeight = 600; + } + else + { + pSmi->lcdWidth = 1024; + pSmi->lcdHeight = 768; + } + break; + + case 0x0C: + pSmi->lcdWidth = 1280; + pSmi->lcdHeight = 1024; + break; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s Panel Size = %dx%d\n", + (pSmi->lcd == 0) ? "OFF" : (pSmi->lcd == 1) ? "TFT" : "DSTN", + pSmi->lcdWidth, pSmi->lcdHeight); + + /* Assign hwp->MemBase & IOBase here */ + hwp = VGAHWPTR(pScrn); + if (pSmi->IOBase != NULL) + { + vgaHWSetMmioFuncs(hwp, pSmi->MapBase, pSmi->IOBase - pSmi->MapBase); + } + vgaHWGetIOBase(hwp); + + /* Map the VGA memory when the primary video */ + if (xf86IsPrimaryPci(pSmi->PciInfo)) + { + hwp->MapSize = 0x10000; + if (!vgaHWMapMem(pScrn)) + { + LEAVE_PROC("SMI_MapMem"); + return(FALSE); + } + pSmi->PrimaryVidMapped = TRUE; + } + + LEAVE_PROC("SMI_MapMem"); + return(TRUE); +} + +/* UnMapMem - contains half of pre-4.0 EnterLeave function. The EnterLeave + * function which en/disable access to IO ports and ext. regs + */ + +static void +SMI_UnmapMem(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_UnmapMem"); + + /* Unmap VGA mem if mapped. */ + if (pSmi->PrimaryVidMapped) + { + vgaHWUnmapMem(pScrn); + pSmi->PrimaryVidMapped = FALSE; + } + + SMI_DisableMmio(pScrn); + + xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pSmi->MapBase, pSmi->MapSize); + if (pSmi->FBBase != NULL) + { + xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pSmi->FBBase, + pSmi->videoRAMBytes); + } + + LEAVE_PROC("SMI_UnmapMem"); +} + +/* This gets called at the start of each server generation. */ + +static Bool +SMI_ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SMIPtr pSmi = SMIPTR(pScrn); + EntityInfoPtr pEnt; + + ENTER_PROC("SMI_ScreenInit"); + + /* Map MMIO regs and framebuffer */ + if (!SMI_MapMem(pScrn)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + + pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + + if (!pSmi->pInt10) { + pSmi->pInt10 = xf86InitInt10(pEnt->index); + } + + /* Save the chip/graphics state */ + SMI_Save(pScrn); + + /* Zero the frame buffer, #258 */ + memset(pSmi->FBBase, 0, pSmi->videoRAMBytes); + + /* Initialize the first mode */ + if (!SMI_ModeInit(pScrn, pScrn->currentMode)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + + /* + * The next step is to setup the screen's visuals, and initialise the + * framebuffer code. In cases where the framebuffer's default choises for + * things like visual layouts and bits per RGB are OK, this may be as simple + * as calling the framebuffer's ScreenInit() function. If not, the visuals + * will need to be setup before calling a fb ScreenInit() function and fixed + * up after. + * + * For most PC hardware at depths >= 8, the defaults that cfb uses are not + * appropriate. In this driver, we fixup the visuals after. + */ + + /* + * Reset the visual list. + */ + miClearVisualTypes(); + + /* Setup the visuals we support. */ + + /* + * For bpp > 8, the default visuals are not acceptable because we only + * support TrueColor and not DirectColor. To deal with this, call + * miSetVisualTypes with the appropriate visual mask. + */ +#ifndef USE_FB + if (pScrn->bitsPerPixel > 8) + { + if (!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits, + pScrn->defaultVisual)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + } + else +#endif + { + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, + pScrn->defaultVisual)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + } +#ifdef USE_FB + if (!miSetPixmapDepths ()) return FALSE; +#endif + + if (!SMI_InternalScreenInit(scrnIndex, pScreen)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + + xf86SetBlackWhitePixels(pScreen); + + if (pScrn->bitsPerPixel > 8) + { + VisualPtr visual; + /* Fixup RGB ordering */ + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) + { + if ((visual->class | DynamicClass) == DirectColor) + { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + +#ifdef USE_FB + /* must be after RGB ordering fixed */ + fbPictureInit(pScreen, 0, 0); +#endif + + /* CZ 18.06.2001: moved here from smi_accel.c to have offscreen + framebuffer in NoAccel mode */ + { + int numLines, maxLines; + BoxRec AvailFBArea; + + maxLines = pSmi->FBReserved / (pSmi->width * pSmi->Bpp); + if (pSmi->rotate) { + numLines = maxLines; + } else { + /* CZ 3.11.2001: What does the following code? see also smi_video.c aaa line 1226 */ +/*#if defined(XvExtension) && SMI_USE_VIDEO */ +#if 0 + numLines = ((pSmi->FBReserved - pSmi->width * pSmi->Bpp + * pSmi->height) * 25 / 100 + pSmi->width + * pSmi->Bpp - 1) / (pSmi->width * pSmi->Bpp); + numLines += pSmi->height; +#else + numLines = maxLines; +#endif + } + + AvailFBArea.x1 = 0; + AvailFBArea.y1 = 0; + AvailFBArea.x2 = pSmi->width; + AvailFBArea.y2 = numLines; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "FrameBuffer Box: %d,%d - %d,%d\n", + AvailFBArea.x1, AvailFBArea.y1, AvailFBArea.x2, + AvailFBArea.y2); + xf86InitFBManager(pScreen, &AvailFBArea); + } + /* end CZ */ + + + /* Initialize acceleration layer */ + if (!pSmi->NoAccel) { + if (!SMI_AccelInit(pScreen)) { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + } + + miInitializeBackingStore(pScreen); + + /* hardware cursor needs to wrap this layer */ + SMI_DGAInit(pScreen); + + /* Initialise cursor functions */ + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + /* Initialize HW cursor layer. Must follow software cursor + * initialization. + */ + if (pSmi->hwcursor) + { + if (!SMI_HWCursorInit(pScreen)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Hardware cursor " + "initialization failed\n"); + } + } + + if (pSmi->shadowFB) + { + RefreshAreaFuncPtr refreshArea = SMI_RefreshArea; + + if (pSmi->rotate) + { + if (pSmi->PointerMoved == NULL) + { + pSmi->PointerMoved = pScrn->PointerMoved; + pScrn->PointerMoved = SMI_PointerMoved; + } + } + + ShadowFBInit(pScreen, refreshArea); + } + + /* Initialise default colormap */ + if (!miCreateDefColormap(pScreen)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + + /* Initialize colormap layer. Must follow initialization of the default + * colormap. And SetGamma call, else it will load palette with solid white. + */ + /* CZ 2.11.2001: CMAP_PALETTED_TRUECOLOR for gamma correction */ + if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits, SMI_LoadPalette, NULL, + CMAP_RELOAD_ON_MODE_SWITCH | CMAP_PALETTED_TRUECOLOR)) + { + LEAVE_PROC("SMI_ScreenInit"); + return(FALSE); + } + + pScreen->SaveScreen = SMI_SaveScreen; + pSmi->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = SMI_CloseScreen; + + if (!xf86DPMSInit(pScreen, SMI_DisplayPowerManagementSet, 0)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed!\n"); + } + + SMI_InitVideo(pScreen); + + /* Report any unused options (only for the first generation) */ + if (serverGeneration == 1) + { + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + } + + LEAVE_PROC("SMI_ScreenInit"); + return(TRUE); +} + +/* Common init routines needed in EnterVT and ScreenInit */ + +static int +SMI_InternalScreenInit(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SMIPtr pSmi = SMIPTR(pScrn); + int width, height, displayWidth; + int bytesPerPixel = pScrn->bitsPerPixel / 8; + int xDpi, yDpi; + int ret; + + ENTER_PROC("SMI_InternalScreenInit"); + + if (pSmi->rotate) + { + width = pScrn->virtualY; + height = pScrn->virtualX; + xDpi = pScrn->yDpi; + yDpi = pScrn->xDpi; + displayWidth = ((width * bytesPerPixel + 15) & ~15) / bytesPerPixel; + } + else + { + width = pScrn->virtualX; + height = pScrn->virtualY; + xDpi = pScrn->xDpi; + yDpi = pScrn->yDpi; + displayWidth = pScrn->displayWidth; + } + + if (pSmi->shadowFB) + { + pSmi->ShadowWidth = width; + pSmi->ShadowHeight = height; + pSmi->ShadowWidthBytes = (width * bytesPerPixel + 15) & ~15; + if (bytesPerPixel == 3) + { + pSmi->ShadowPitch = ((height * 3) << 16) + | pSmi->ShadowWidthBytes; + } + else + { + pSmi->ShadowPitch = (height << 16) + | (pSmi->ShadowWidthBytes / bytesPerPixel); + } + + pSmi->saveBufferSize = pSmi->ShadowWidthBytes * pSmi->ShadowHeight; + pSmi->FBReserved -= pSmi->saveBufferSize; + pSmi->FBReserved &= ~0x15; + WRITE_VPR(pSmi, 0x0C, (pSmi->FBOffset = pSmi->FBReserved) >> 3); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Shadow: width=%d height=%d " + "offset=0x%08X pitch=0x%08X\n", pSmi->ShadowWidth, + pSmi->ShadowHeight, pSmi->FBOffset, pSmi->ShadowPitch); + } + else + { + pSmi->FBOffset = 0; + } + + /* + * Call the framebuffer layer's ScreenInit function, and fill in other + * pScreen fields. + */ + + DEBUG((VERBLEV, "\tInitializing FB @ 0x%08X for %dx%d (%d)\n", + pSmi->FBBase, width, height, displayWidth)); + switch (pScrn->bitsPerPixel) + { +#ifdef USE_FB + case 8: + case 16: + case 24: + ret = fbScreenInit(pScreen, pSmi->FBBase, width, height, xDpi, + yDpi, displayWidth,pScrn->bitsPerPixel); + break; +#else + case 8: + ret = cfbScreenInit(pScreen, pSmi->FBBase, width, height, xDpi, + yDpi, displayWidth); + break; + + case 16: + ret = cfb16ScreenInit(pScreen, pSmi->FBBase, width, height, xDpi, + yDpi, displayWidth); + break; + + case 24: + ret = cfb24ScreenInit(pScreen, pSmi->FBBase, width, height, xDpi, + yDpi, displayWidth); + break; +#endif + default: + xf86DrvMsg(scrnIndex, X_ERROR, "Internal error: invalid bpp (%d) " + "in SMI_InternalScreenInit\n", pScrn->bitsPerPixel); + LEAVE_PROC("SMI_InternalScreenInit"); + return(FALSE); + } + + LEAVE_PROC("SMI_InternalScreenInit"); + return(ret); +} + +/* Checks if a mode is suitable for the selected configuration. */ +static ModeStatus +SMI_ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + SMIPtr pSmi = SMIPTR(pScrn); + float refresh; + + ENTER_PROC("SMI_ValidMode"); + refresh = (mode->VRefresh > 0) ? mode->VRefresh + : mode->Clock * 1000.0 / mode->VTotal / mode->HTotal; + xf86DrvMsg(scrnIndex, X_INFO, "Mode: %dx%d %d-bpp, %fHz\n", mode->HDisplay, + mode->VDisplay, pScrn->bitsPerPixel, refresh); + + if (pSmi->shadowFB) + { + int mem; + + if (pScrn->bitsPerPixel == 24) + { + LEAVE_PROC("SMI_ValidMode"); + return(MODE_BAD); + } + + mem = (pScrn->virtualX * pScrn->bitsPerPixel / 8 + 15) & ~15; + mem *= pScrn->virtualY * 2; + + if (mem > pSmi->FBReserved) /* PDR#1074 */ + { + LEAVE_PROC("SMI_ValidMode"); + return(MODE_MEM); + } + } + + if (!pSmi->useBIOS || pSmi->lcd) + { +#if 1 /* PDR#983 */ + if (pSmi->zoomOnLCD) + { + if ( (mode->HDisplay > pSmi->lcdWidth) + || (mode->VDisplay > pSmi->lcdHeight) + ) + { + LEAVE_PROC("SMI_ValidMode"); + return(MODE_PANEL); + } + } + else +#endif + { + if ( (mode->HDisplay != pSmi->lcdWidth) + || (mode->VDisplay != pSmi->lcdHeight) + ) + { + LEAVE_PROC("SMI_ValidMode"); + return(MODE_PANEL); + } + } + + } + +#if 1 /* PDR#944 */ + if (pSmi->rotate) + { + if ( (mode->HDisplay != pSmi->lcdWidth) + || (mode->VDisplay != pSmi->lcdHeight) + ) + { + LEAVE_PROC("SMI_ValidMode"); + return(MODE_PANEL); + } + } +#endif + + LEAVE_PROC("SMI_ValidMode"); + return(MODE_OK); +} + +static Bool +SMI_ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + unsigned char tmp; + int panelIndex, modeIndex, i; + int xyAddress[] = { 320, 400, 512, 640, 800, 1024, 1280, 1600, 2048 }; + CARD32 DEDataFormat = 0; + + /* Store values to current mode register structs */ + SMIRegPtr new = &pSmi->ModeReg; + vgaRegPtr vganew = &hwp->ModeReg; + + ENTER_PROC("SMI_ModeInit"); + + if(!vgaHWInit(pScrn, mode)) + { + LEAVE_PROC("SMI_ModeInit"); + return(FALSE); + } + + new->modeInit = TRUE; + + if (pSmi->rotate) + { + pSmi->width = pScrn->virtualY; + pSmi->height = pScrn->virtualX; + } + else + { + pSmi->width = pScrn->virtualX; + pSmi->height = pScrn->virtualY; + } + pSmi->Bpp = pScrn->bitsPerPixel / 8; + + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x17); + tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA); + if (pSmi->pci_burst) + { + new->SR17 = tmp | 0x20; + } + else + { + new->SR17 = tmp & ~0x20; + } + + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18); + new->SR18 = inb(pSmi->PIOBase + VGA_SEQ_DATA) | 0x11; + + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21); + new->SR21 = inb(pSmi->PIOBase + VGA_SEQ_DATA) & ~0x03; + + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x31); + new->SR31 = inb(pSmi->PIOBase + VGA_SEQ_DATA) & ~0xC0; + + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x32); + new->SR32 = inb(pSmi->PIOBase + VGA_SEQ_DATA) & ~0x07; + if (SMI_LYNXM_SERIES(pSmi->Chipset)) + { + new->SR32 |= 0x04; + } + + new->SRA0 = new->CR33 = new->CR3A = 0x00; + + if (pSmi->lcdWidth == 640) + { + panelIndex = 0; + } + else if (pSmi->lcdWidth == 800) + { + panelIndex = 1; + } + else + { + panelIndex = 2; + } + + if (mode->HDisplay == 640) + { + modeIndex = 0; + } + else if (mode->HDisplay == 800) + { + modeIndex = 1; + } + else + { + modeIndex = 2; + } + + if (SMI_LYNXM_SERIES(pSmi->Chipset)) + { + static unsigned char PanelTable[3][14] = + { + { 0x5F, 0x4F, 0x00, 0x52, 0x1E, 0x0B, 0xDF, 0x00, 0xE9, 0x0B, 0x2E, + 0x00, 0x4F, 0xDF }, + { 0x7F, 0x63, 0x00, 0x69, 0x19, 0x72, 0x57, 0x00, 0x58, 0x0C, 0xA2, + 0x20, 0x4F, 0xDF }, + { 0xA3, 0x7F, 0x00, 0x83, 0x14, 0x24, 0xFF, 0x00, 0x02, 0x08, 0xA7, + 0xE0, 0x4F, 0xDF }, + }; + + for (i = 0; i < 14; i++) + { + new->CR40[i] = PanelTable[panelIndex][i]; + } + new->CR90[14] = 0x03; + new->CR90[15] = 0x00; + if (mode->VDisplay < pSmi->lcdHeight) + { + new->CRA0[6] = (pSmi->lcdHeight - mode->VDisplay) / 8; + } + else + { + new->CRA0[6] = 0; + } + + if (mode->HDisplay < pSmi->lcdWidth) + { + new->CRA0[7] = (pSmi->lcdWidth - mode->HDisplay) / 16; + } + else + { + new->CRA0[7] = 0; + } + } + else + { + static unsigned char PanelTable[3][3][14] = + { + { /* 640x480 panel */ + { 0x5F, 0x4F, 0x00, 0x53, 0x00, 0x0B, 0xDF, 0x00, 0xEA, 0x0C, + 0x2E, 0x00, 0x4F, 0xDF }, + { 0x5F, 0x4F, 0x00, 0x53, 0x00, 0x0B, 0xDF, 0x00, 0xEA, 0x0C, + 0x2E, 0x00, 0x4F, 0xDF }, + { 0x5F, 0x4F, 0x00, 0x53, 0x00, 0x0B, 0xDF, 0x00, 0xEA, 0x0C, + 0x2E, 0x00, 0x4F, 0xDF }, + }, + { /* 800x600 panel */ + { 0x7F, 0x59, 0x19, 0x5E, 0x8E, 0x72, 0x1C, 0x37, 0x1D, 0x00, + 0xA2, 0x20, 0x4F, 0xDF }, + { 0x7F, 0x63, 0x00, 0x68, 0x18, 0x72, 0x58, 0x00, 0x59, 0x0C, + 0xE0, 0x20, 0x63, 0x57 }, + { 0x7F, 0x63, 0x00, 0x68, 0x18, 0x72, 0x58, 0x00, 0x59, 0x0C, + 0xE0, 0x20, 0x63, 0x57 }, + }, + { /* 1024x768 panel */ + { 0xA3, 0x67, 0x0F, 0x6D, 0x1D, 0x24, 0x70, 0x95, 0x72, 0x07, + 0xA3, 0x20, 0x4F, 0xDF }, + { 0xA3, 0x71, 0x19, 0x77, 0x07, 0x24, 0xAC, 0xD1, 0xAE, 0x03, + 0xE1, 0x20, 0x63, 0x57 }, + { 0xA3, 0x7F, 0x00, 0x85, 0x15, 0x24, 0xFF, 0x00, 0x01, 0x07, + 0xE5, 0x20, 0x7F, 0xFF }, + }, + }; + + for (i = 0; i < 14; i++) + { + new->CR40[i] = PanelTable[panelIndex][modeIndex][i]; + } + } + + /* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */ + new->CCR66 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66); + if (pSmi->Chipset == SMI_LYNX3DM) { + switch (pScrn->bitsPerPixel) { + case 8: + new->CCR66 = (new->CCR66 & 0xF3) | 0x00; /* 6 bits-RAM */ + break; + case 16: + new->CCR66 = (new->CCR66 & 0xF3) | 0x00; /* 6 bits-RAM */ + /* no Gamma correction in 16 Bit mode (s. Release.txt 1.3.1) */ + break; + case 24: + case 32: + new->CCR66 = (new->CCR66 & 0xF3) | 0x04; /* Gamma correct ON */ + break; + default: + LEAVE_PROC("SMI_ModeInit"); + return(FALSE); + } + } + + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x30); + if (inb(pSmi->PIOBase + VGA_SEQ_DATA) & 0x01) + { + new->SR21 = 0x00; + } + + if (pSmi->MCLK > 0) + { + SMI_CommonCalcClock(pScrn->scrnIndex,pSmi->MCLK, + 1, 1, 31, 0, 2, pSmi->minClock, + pSmi->maxClock, &new->SR6A, &new->SR6B); + } + else + { + new->SR6B = 0xFF; + } + + if ((mode->HDisplay == 640) && SMI_LYNXM_SERIES(pSmi->Chipset)) + { + vganew->MiscOutReg &= ~0x0C; + } + else + { + vganew->MiscOutReg |= 0x0C; + } + vganew->MiscOutReg |= 0xE0; + if (mode->HDisplay == 800) + { + vganew->MiscOutReg &= ~0xC0; + } + if ((mode->HDisplay == 1024) && SMI_LYNXM_SERIES(pSmi->Chipset)) + { + vganew->MiscOutReg &= ~0xC0; + } + + /* Set DPR registers */ + pSmi->Stride = (pSmi->width * pSmi->Bpp + 15) & ~15; + switch (pScrn->bitsPerPixel) + { + case 8: + DEDataFormat = 0x00000000; + break; + + case 16: + pSmi->Stride >>= 1; + DEDataFormat = 0x00100000; + break; + + case 24: + DEDataFormat = 0x00300000; + break; + + case 32: + pSmi->Stride >>= 2; + DEDataFormat = 0x00200000; + break; + } + for (i = 0; i < sizeof(xyAddress) / sizeof(xyAddress[0]); i++) + { + if (pSmi->rotate) + { + if (xyAddress[i] == pSmi->height) + { + DEDataFormat |= i << 16; + break; + } + } + else + { + if (xyAddress[i] == pSmi->width) + { + DEDataFormat |= i << 16; + break; + } + } + } + new->DPR10 = (pSmi->Stride << 16) | pSmi->Stride; + new->DPR1C = DEDataFormat; + new->DPR20 = 0; + new->DPR24 = 0xFFFFFFFF; + new->DPR28 = 0xFFFFFFFF; + new->DPR2C = 0; + new->DPR30 = 0; + new->DPR3C = (pSmi->Stride << 16) | pSmi->Stride; + new->DPR40 = 0; + new->DPR44 = 0; + + /* Set VPR registers */ + switch (pScrn->bitsPerPixel) + { + case 8: + new->VPR00 = 0x00000000; + break; + + case 16: + new->VPR00 = 0x00020000; + break; + + case 24: + new->VPR00 = 0x00040000; + break; + + case 32: + new->VPR00 = 0x00030000; + break; + } + new->VPR0C = pSmi->FBOffset >> 3; + if (pSmi->rotate) + { + new->VPR10 = ((((min(pSmi->lcdWidth, pSmi->height) * pSmi->Bpp) >> 3) + + 2) << 16) | ((pSmi->height * pSmi->Bpp) >> 3); + } + else + { + new->VPR10 = ((((min(pSmi->lcdWidth, pSmi->width) * pSmi->Bpp) >> 3) + + 2) << 16) | ((pSmi->width * pSmi->Bpp) >> 3); + } + + /* Set CPR registers */ + new->CPR00 = 0x00000000; + + pScrn->vtSema = TRUE; + + /* Find the INT 10 mode number */ + { + static struct + { + int x, y, bpp; + CARD16 mode; + + } modeTable[] = + { + { 640, 480, 8, 0x50 }, + { 640, 480, 16, 0x52 }, + { 640, 480, 24, 0x53 }, + { 640, 480, 32, 0x54 }, + { 800, 600, 8, 0x55 }, + { 800, 600, 16, 0x57 }, + { 800, 600, 24, 0x58 }, + { 800, 600, 32, 0x59 }, + { 1024, 768, 8, 0x60 }, + { 1024, 768, 16, 0x62 }, + { 1024, 768, 24, 0x63 }, + { 1024, 768, 32, 0x64 }, + { 1280, 1024, 8, 0x65 }, + { 1280, 1024, 16, 0x67 }, + { 1280, 1024, 24, 0x68 }, + { 1280, 1024, 32, 0x69 }, + }; + + new->mode = 0; + for (i = 0; i < sizeof(modeTable) / sizeof(modeTable[0]); i++) + { + if ( (modeTable[i].x == mode->HDisplay) + && (modeTable[i].y == mode->VDisplay) + && (modeTable[i].bpp == pScrn->bitsPerPixel) + ) + { + new->mode = modeTable[i].mode; + break; + } + } + } + + /* Zero the font memory */ + memset(new->smiFont, 0, sizeof(new->smiFont)); + + /* Write the mode registers to hardware */ + SMI_WriteMode(pScrn, vganew, new); + + /* Adjust the viewport */ + SMI_AdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + + LEAVE_PROC("SMI_ModeInit"); + return(TRUE); +} + +/* + * This is called at the end of each server generation. It restores the + * original (text) mode. It should also unmap the video memory, and free any + * per-generation data allocated by the driver. It should finish by unwrapping + * and calling the saved CloseScreen function. + */ + +static Bool +SMI_CloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + vgaRegPtr vgaSavePtr = &hwp->SavedReg; + SMIRegPtr SMISavePtr = &pSmi->SavedReg; + Bool ret; + + ENTER_PROC("SMI_CloseScreen"); + + if (pScrn->vtSema) + { + SMI_WriteMode(pScrn, vgaSavePtr, SMISavePtr); + vgaHWLock(hwp); + SMI_UnmapMem(pScrn); + } + + if (pSmi->AccelInfoRec != NULL) + { + XAADestroyInfoRec(pSmi->AccelInfoRec); + } + if (pSmi->CursorInfoRec != NULL) + { + xf86DestroyCursorInfoRec(pSmi->CursorInfoRec); + } + if (pSmi->DGAModes != NULL) + { + xfree(pSmi->DGAModes); + } + if (pSmi->pInt10 != NULL) + { + xf86FreeInt10(pSmi->pInt10); + pSmi->pInt10 = NULL; + } +#ifdef XvExtension + if (pSmi->ptrAdaptor != NULL) + { + xfree(pSmi->ptrAdaptor); + } + if (pSmi->BlockHandler != NULL) + { + pScreen->BlockHandler = pSmi->BlockHandler; + } +#endif + if (pSmi->I2C != NULL) + { + xf86DestroyI2CBusRec(pSmi->I2C, FALSE, TRUE); + xfree(pSmi->I2C); + pSmi->I2C = NULL; + } + /* #670 */ + if (pSmi->pSaveBuffer) + { + xfree(pSmi->pSaveBuffer); + } + /* #920 */ + if (pSmi->paletteBuffer) + { + xfree(pSmi->paletteBuffer); + } + + pScrn->vtSema = FALSE; + pScreen->CloseScreen = pSmi->CloseScreen; + ret = (*pScreen->CloseScreen)(scrnIndex, pScreen); + + LEAVE_PROC("SMI_CloseScreen"); + return(ret); +} + +static void +SMI_FreeScreen(int scrnIndex, int flags) +{ + SMI_FreeRec(xf86Screens[scrnIndex]); +} + +static Bool +SMI_SaveScreen(ScreenPtr pScreen, int mode) +{ + Bool ret; + + ENTER_PROC("SMI_SaveScreen"); + + ret = vgaHWSaveScreen(pScreen, mode); + + LEAVE_PROC("SMI_SaveScreen"); + return(ret); +} + +void +SMI_AdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + SMIPtr pSmi = SMIPTR(pScrn); + CARD32 Base; + + ENTER_PROC("SMI_AdjustFrame"); + + if (pSmi->ShowCache && y) + { + y += pScrn->virtualY - 1; + } + + Base = pSmi->FBOffset + (x + y * pScrn->virtualX) * pSmi->Bpp; + if (SMI_LYNX3D_SERIES(pSmi->Chipset)) + { + Base = (Base + 15) & ~15; +#if 1 /* PDR#1058 */ + while ((Base % pSmi->Bpp) > 0) + { + Base -= 16; + } +#endif + } + else + { + Base = (Base + 7) & ~7; +#if 1 /* PDR#1058 */ + while ((Base % pSmi->Bpp) > 0) + { + Base -= 8; + } +#endif + } + + WRITE_VPR(pSmi, 0x0C, Base >> 3); + + LEAVE_PROC("SMI_AdjustFrame"); +} + +Bool +SMI_SwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + Bool ret; + + ENTER_PROC("SMI_SwitchMode"); + + ret = SMI_ModeInit(xf86Screens[scrnIndex], mode); + + LEAVE_PROC("SMI_SwitchMode"); + return(ret); +} + +void +SMI_LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies, LOCO *colors, + VisualPtr pVisual) +{ + SMIPtr pSmi = SMIPTR(pScrn); + int i; + + ENTER_PROC("SMI_LoadPalette"); + + for(i = 0; i < numColors; i++) + { + DEBUG((VERBLEV, "pal[%d] = %d %d %d\n", indicies[i], + colors[indicies[i]].red, colors[indicies[i]].green, colors[indicies[i]].blue)); + VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, indicies[i]); + VGAOUT8(pSmi, VGA_DAC_DATA, colors[indicies[i]].red); + VGAOUT8(pSmi, VGA_DAC_DATA, colors[indicies[i]].green); + VGAOUT8(pSmi, VGA_DAC_DATA, colors[indicies[i]].blue); + } + + LEAVE_PROC("SMI_LoadPalette"); +} + +static void +SMI_DisableVideo(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + CARD8 tmp; + + if (!(tmp = VGAIN8(pSmi, VGA_DAC_MASK))) + return; + pSmi->DACmask = tmp; + VGAOUT8(pSmi, VGA_DAC_MASK, 0); +} + +static void +SMI_EnableVideo(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + VGAOUT8(pSmi, VGA_DAC_MASK, pSmi->DACmask); +} + + +void +SMI_EnableMmio(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + CARD8 tmp; + + ENTER_PROC("SMI_EnableMmio"); + + /* + * Enable chipset (seen on uninitialized secondary cards) might not be + * needed once we use the VGA softbooter + */ + vgaHWSetStdFuncs(hwp); + + /* Enable linear mode */ + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18); + tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA); + pSmi->SR18Value = tmp; /* PDR#521 */ + outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp | 0x11); + + /* Enable 2D/3D Engine and Video Processor */ + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21); + tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA); + pSmi->SR21Value = tmp; /* PDR#521 */ + outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp & ~0x03); + + LEAVE_PROC("SMI_EnableMmio"); +} + +void +SMI_DisableMmio(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_DisableMmio"); + + vgaHWSetStdFuncs(hwp); + + /* Disable 2D/3D Engine and Video Processor */ + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21); + outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR21Value); /* PDR#521 */ + + /* Disable linear mode */ + outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18); + outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR18Value); /* PDR#521 */ + + LEAVE_PROC("SMI_DisableMmio"); +} + +/* This function is used to debug, it prints out the contents of Lynx regs */ +static void +SMI_PrintRegs(ScrnInfoPtr pScrn) +{ + unsigned char i, tmp; + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + int vgaCRIndex = hwp->IOBase + VGA_CRTC_INDEX_OFFSET; + int vgaCRReg = hwp->IOBase + VGA_CRTC_DATA_OFFSET; + int vgaStatus = hwp->IOBase + VGA_IN_STAT_1_OFFSET; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "START register dump ------------------\n"); + + xf86ErrorFVerb(VERBLEV, "MISCELLANEOUS OUTPUT\n %02X\n", + VGAIN8(pSmi, VGA_MISC_OUT_R)); + + xf86ErrorFVerb(VERBLEV, "\nSEQUENCER\n" + " x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF"); + for (i = 0x00; i <= 0xAF; i++) + { + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " "); + xf86ErrorFVerb(VERBLEV, "%02X ", + VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, i)); + } + + xf86ErrorFVerb(VERBLEV, "\n\nCRT CONTROLLER\n" + " x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF"); + for (i = 0x00; i <= 0xAD; i++) + { + if (i == 0x20) i = 0x30; + if (i == 0x50) i = 0x90; + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " "); + xf86ErrorFVerb(VERBLEV, "%02X ", + VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRReg, i)); + } + + xf86ErrorFVerb(VERBLEV, "\n\nGRAPHICS CONTROLLER\n" + " x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF"); + for (i = 0x00; i <= 0x08; i++) + { + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " "); + xf86ErrorFVerb(VERBLEV, "%02X ", + VGAIN8_INDEX(pSmi, VGA_GRAPH_INDEX, VGA_GRAPH_DATA, i)); + } + + xf86ErrorFVerb(VERBLEV, "\n\nATTRIBUTE 0CONTROLLER\n" + " x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF"); + for (i = 0x00; i <= 0x14; i++) + { + tmp = VGAIN8(pSmi, vgaStatus); + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " "); + xf86ErrorFVerb(VERBLEV, "%02X ", + VGAIN8_INDEX(pSmi, VGA_ATTR_INDEX, VGA_ATTR_DATA_R, i)); + } + tmp = VGAIN8(pSmi, vgaStatus); + VGAOUT8(pSmi, VGA_ATTR_INDEX, 0x20); + + xf86ErrorFVerb(VERBLEV, "\n\nDPR x0 x4 x8 xC"); + for (i = 0x00; i <= 0x44; i += 4) + { + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + xf86ErrorFVerb(VERBLEV, " %08X", READ_DPR(pSmi, i)); + } + + xf86ErrorFVerb(VERBLEV, "\n\nVPR x0 x4 x8 xC"); + for (i = 0x00; i <= 0x60; i += 4) + { + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + xf86ErrorFVerb(VERBLEV, " %08X", READ_VPR(pSmi, i)); + } + + xf86ErrorFVerb(VERBLEV, "\n\nCPR x0 x4 x8 xC"); + for (i = 0x00; i <= 0x18; i += 4) + { + if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i); + xf86ErrorFVerb(VERBLEV, " %08X", READ_CPR(pSmi, i)); + } + + xf86ErrorFVerb(VERBLEV, "\n\n"); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "END register dump --------------------\n"); +} + +/* + * SMI_DisplayPowerManagementSet -- Sets VESA Display Power Management + * Signaling (DPMS) Mode. + */ +static void +SMI_DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, + int flags) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + CARD8 SR01, SR20, SR21, SR22, SR23, SR24, SR31, SR34; + + ENTER_PROC("SMI_DisplayPowerManagementSet"); + + /* If we already are in the requested DPMS mode, just return */ + if (pSmi->CurrentDPMS == PowerManagementMode) + { + LEAVE_PROC("SMI_DisplayPowerManagementSet"); + return; + } + +#if 1 /* PDR#735 */ + if (pSmi->pInt10 != NULL) + { + pSmi->pInt10->ax = 0x4F10; + switch (PowerManagementMode) + { + case DPMSModeOn: + pSmi->pInt10->bx = 0x0001; + break; + + case DPMSModeStandby: + pSmi->pInt10->bx = 0x0101; + break; + + case DPMSModeSuspend: + pSmi->pInt10->bx = 0x0201; + break; + + case DPMSModeOff: + pSmi->pInt10->bx = 0x0401; + break; + } + pSmi->pInt10->cx = 0x0000; + pSmi->pInt10->num = 0x10; + xf86ExecX86int10(pSmi->pInt10); + if (pSmi->pInt10->ax == 0x004F) + { + pSmi->CurrentDPMS = PowerManagementMode; +#if 1 /* PDR#835 */ + if (PowerManagementMode == DPMSModeOn) + { + SR01 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01, + SR01 & ~0x20); + } +#endif + LEAVE_PROC("SMI_DisplayPowerManagementSet"); + return; + } + } +#endif + + /* Save the current SR registers */ + if (pSmi->CurrentDPMS == DPMSModeOn) + { + pSmi->DPMS_SR20 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20); + pSmi->DPMS_SR21 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21); + pSmi->DPMS_SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31); + pSmi->DPMS_SR34 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34); + } + + /* Read the required SR registers for the DPMS handler */ + SR01 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01); + SR20 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20); + SR21 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21); + SR22 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22); + SR23 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x23); + SR24 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x24); + SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31); + SR34 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34); + + switch (PowerManagementMode) + { + case DPMSModeOn: + /* Screen On: HSync: On, VSync : On */ + SR01 &= ~0x20; + SR20 = pSmi->DPMS_SR20; + SR21 = pSmi->DPMS_SR21; + SR22 &= ~0x30; + SR23 &= ~0xC0; + SR24 |= 0x01; + SR31 = pSmi->DPMS_SR31; + SR34 = pSmi->DPMS_SR34; + break; + + case DPMSModeStandby: + /* Screen: Off; HSync: Off, VSync: On */ + SR01 |= 0x20; + SR20 = (SR20 & ~0xB0) | 0x10; + SR21 |= 0x88; + SR22 = (SR22 & ~0x30) | 0x10; + SR23 = (SR23 & ~0x07) | 0xD8; + SR24 &= ~0x01; + SR31 = (SR31 & ~0x07) | 0x00; + SR34 |= 0x80; + break; + + case DPMSModeSuspend: + /* Screen: Off; HSync: On, VSync: Off */ + SR01 |= 0x20; + SR20 = (SR20 & ~0xB0) | 0x10; + SR21 |= 0x88; + SR22 = (SR22 & ~0x30) | 0x20; + SR23 = (SR23 & ~0x07) | 0xD8; + SR24 &= ~0x01; + SR31 = (SR31 & ~0x07) | 0x00; + SR34 |= 0x80; + break; + + case DPMSModeOff: + /* Screen: Off; HSync: Off, VSync: Off */ + SR01 |= 0x20; + SR20 = (SR20 & ~0xB0) | 0x10; + SR21 |= 0x88; + SR22 = (SR22 & ~0x30) | 0x30; + SR23 = (SR23 & ~0x07) | 0xD8; + SR24 &= ~0x01; + SR31 = (SR31 & ~0x07) | 0x00; + SR34 |= 0x80; + break; + + default: + xf86ErrorFVerb(VERBLEV, "Invalid PowerManagementMode %d passed to " + "SMI_DisplayPowerManagementSet\n", PowerManagementMode); + LEAVE_PROC("SMI_DisplayPowerManagementSet"); + return; + } + + /* Wait for vertical retrace */ + while (hwp->readST01(hwp) & 0x8) ; + while (!(hwp->readST01(hwp) & 0x8)) ; + + /* Write the registers */ + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01, SR01); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34, SR34); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, SR31); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20, SR20); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22, SR22); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x23, SR23); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, SR21); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x24, SR24); + + /* Save the current power state */ + pSmi->CurrentDPMS = PowerManagementMode; + + LEAVE_PROC("SMI_DisplayPowerManagementSet"); +} + +static void +SMI_ProbeDDC(ScrnInfoPtr pScrn, int index) +{ + vbeInfoPtr pVbe; + if (xf86LoadSubModule(pScrn, "vbe")) + { + pVbe = VBEInit(NULL, index); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); + vbeFree(pVbe); + } +} + +static unsigned int +SMI_ddc1Read(ScrnInfoPtr pScrn) +{ + register vgaHWPtr hwp = VGAHWPTR(pScrn); + SMIPtr pSmi = SMIPTR(pScrn); + unsigned int ret; + + ENTER_PROC("SMI_ddc1Read"); + + while (hwp->readST01(hwp) & 0x8) ; + while (!(hwp->readST01(hwp) & 0x8)) ; + + ret = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72) & 0x08; + + LEAVE_PROC("SMI_ddc1Read"); + return(ret); +} + +static Bool +SMI_ddc1(int scrnIndex) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + SMIPtr pSmi = SMIPTR(pScrn); + Bool success = FALSE; + xf86MonPtr pMon; + unsigned char tmp; + + ENTER_PROC("SMI_ddc1"); + + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72, tmp | 0x20); + + pMon = xf86PrintEDID(xf86DoEDID_DDC1(scrnIndex, vgaHWddc1SetSpeed, + SMI_ddc1Read)); + if (pMon != NULL) + { + success = TRUE; + } + xf86SetDDCproperties(pScrn, pMon); + + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72, tmp); + + LEAVE_PROC("SMI_ddc1"); + return(success); +} diff --git a/src/smi_hwcurs.c b/src/smi_hwcurs.c new file mode 100644 index 0000000..b2f8d69 --- /dev/null +++ b/src/smi_hwcurs.c @@ -0,0 +1,375 @@ +/* Header: //Mercury/Projects/archives/XFree86/4.0/smi_hwcurs.c-arc 1.12 27 Nov 2000 15:47:48 Frido $ */ + +/* +Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. +Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of the XFree86 Project and +Silicon Motion shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without prior written +authorization from the XFree86 Project and Silicon Motion. +*/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_hwcurs.c,v 1.2 2001/03/03 22:26:13 tsi Exp $ */ + +#include "cursorstr.h" +#include "smi.h" + +#define MAX_CURSOR 32 + +static unsigned char * +SMI_RealizeCursor(xf86CursorInfoPtr infoPtr, CursorPtr pCurs) +{ + SMIPtr pSmi = SMIPTR(infoPtr->pScrn); + CursorBitsPtr bits = pCurs->bits; + unsigned char * ram; + unsigned char * psource = bits->source; + unsigned char * pmask = bits->mask; + int x, y, srcwidth, i; + + ENTER_PROC("SMI_RealizeCursor"); + + /* Allocate memory */ + ram = (unsigned char *) xcalloc(1, 1024); + if (ram == NULL) + { + LEAVE_PROC("SMI_RealizeCursor"); + return(NULL); + } + + /* Calculate cursor information */ + srcwidth = ((bits->width + 31) / 8) & ~3; + i = 0; + + switch (pSmi->rotate) + { + default: + /* Copy cursor image */ + for (y = 0; y < min(MAX_CURSOR, bits->height); y++) + { + for (x = 0; x < min(MAX_CURSOR / 8, srcwidth); x++) + { + unsigned char mask = byte_reversed[*pmask++]; + unsigned char source = byte_reversed[*psource++] & mask; + + ram[i++] = ~mask; + ram[i++] = source; + if (i & 4) i += 4; + } + + pmask += srcwidth - x; + psource += srcwidth - x; + + /* Fill remaining part of line with no shape */ + for (; x < MAX_CURSOR / 8; x++) + { + ram[i++] = 0xFF; + ram[i++] = 0x00; + if (i & 4) i += 4; + } + } + + /* Fill remaining part of memory with no shape */ + for (; y < MAX_CURSOR; y++) + { + for (x = 0; x < MAX_CURSOR / 8; x++) + { + ram[i++] = 0xFF; + ram[i++] = 0x00; + if (i & 4) i += 4; + } + } + break; + + case SMI_ROTATE_CW: + /* Initialize cursor memory */ + for (i = 0; i < 1024;) + { + ram[i++] = 0xFF; + ram[i++] = 0x00; + if (i & 4) i += 4; + } + + /* Rotate cursor image */ + for (y = 0; y < min(MAX_CURSOR, bits->height); y++) + { + unsigned char bitmask = 0x01 << (y & 7); + int index = ((MAX_CURSOR - y - 1) / 8) * 2; + if (index & 4) index += 4; + + for (x = 0; x < min(MAX_CURSOR / 8, srcwidth); x++) + { + unsigned char mask = *pmask++; + unsigned char source = *psource++ & mask; + + i = index + (x * 8) * 16; + if (mask || (source & mask)) + { + unsigned char bit; + for (bit = 0x01; bit; bit <<= 1) + { + if (mask & bit) + { + ram[i + 0] &= ~bitmask; + } + + if (source & bit) + { + ram[i + 1] |= bitmask; + } + + i += 16; + } + } + } + + pmask += srcwidth - x; + psource += srcwidth - x; + } + break; + + case SMI_ROTATE_CCW: + /* Initialize cursor memory */ + for (i = 0; i < 1024;) + { + ram[i++] = 0xFF; + ram[i++] = 0x00; + if (i & 4) i += 4; + } + + /* Rotate cursor image */ + for (y = 0; y < min(MAX_CURSOR, bits->height); y++) + { + unsigned char bitmask = 0x80 >> (y & 7); + int index = (y >> 3) * 2; + if (index & 4) index += 4; + + for (x = 0; x < min(MAX_CURSOR / 8, srcwidth); x++) + { + unsigned char mask = *pmask++; + unsigned char source = *psource++ & mask; + + i = index + (MAX_CURSOR - x * 8 - 1) * 16; + if (mask || (source & mask)) + { + unsigned char bit; + for (bit = 0x01; bit; bit <<= 1) + { + if (mask & bit) + { + ram[i + 0] &= ~bitmask; + } + + if (source & bit) + { + ram[i + 1] |= bitmask; + } + + i -= 16; + } + } + } + + pmask += srcwidth - x; + psource += srcwidth - x; + } + break; + } + + LEAVE_PROC("SMI_RealizeCursor"); + return(ram); +} + +static void +SMI_LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src) +{ + SMIPtr pSmi = SMIPTR(pScrn); + CARD8 tmp; + + ENTER_PROC("SMI_LoadCursorImage"); + + /* Load storage location. */ + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x80, + pSmi->FBCursorOffset / 2048); + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81) & 0x80; + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, + tmp | ((pSmi->FBCursorOffset / 2048) >> 8)); + + /* Copy cursor image to framebuffer storage */ + memcpy(pSmi->FBBase + pSmi->FBCursorOffset, src, 1024); + + LEAVE_PROC("SMI_LoadCursorImage"); +} + +static void +SMI_ShowCursor(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + char tmp; + + ENTER_PROC("SMI_ShowCursor"); + + /* Show cursor */ + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, tmp | 0x80); + + LEAVE_PROC("SMI_ShowCursor"); +} + +static void +SMI_HideCursor(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + char tmp; + + ENTER_PROC("SMI_HideCursor"); + + /* Hide cursor */ + tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, tmp & ~0x80); + + LEAVE_PROC("SMI_HideCursor"); +} + +static void +SMI_SetCursorPosition(ScrnInfoPtr pScrn, int x, int y) +{ + SMIPtr pSmi = SMIPTR(pScrn); + int xoff, yoff; + + ENTER_PROC("SMI_SetCursorPosition"); + + /* Calculate coordinates for rotation */ + switch (pSmi->rotate) + { + default: + xoff = x; + yoff = y; + break; + + case SMI_ROTATE_CW: + xoff = pSmi->ShadowHeight - y - MAX_CURSOR; + yoff = x; + break; + + case SMI_ROTATE_CCW: + xoff = y; + yoff = pSmi->ShadowWidth - x - MAX_CURSOR; + break; + } + + /* Program coordinates */ + if (xoff >= 0) + { + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x88, xoff & 0xFF); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x89, + (xoff >> 8) & 0x07); + } + else + { + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x88, + (-xoff) & (MAX_CURSOR - 1)); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x89, 0x08); + } + + if (yoff >= 0) + { + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8A, yoff & 0xFF); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8B, + (yoff >> 8) & 0x07); + } + else + { + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8A, + (-yoff) & (MAX_CURSOR - 1)); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8B, 0x08); + } + + LEAVE_PROC("SMI_SetCursorPosition"); +} + +static void +SMI_SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) +{ + SMIPtr pSmi = SMIPTR(pScrn); + unsigned char packedFG, packedBG; + + ENTER_PROC("SMI_SetCursorColors"); + + /* Pack the true color into 8 bit */ + packedFG = (fg & 0xE00000) >> 16 + | (fg & 0x00E000) >> 11 + | (fg & 0x0000C0) >> 6 + ; + packedBG = (bg & 0xE00000) >> 16 + | (bg & 0x00E000) >> 11 + | (bg & 0x0000C0) >> 6 + ; + + /* Program the colors */ + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8C, packedFG); + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8D, packedBG); + + LEAVE_PROC("SMI_SetCursorColors"); +} + +Bool +SMI_HWCursorInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SMIPtr pSmi = SMIPTR(pScrn); + xf86CursorInfoPtr infoPtr; + Bool ret; + + ENTER_PROC("SMI_HWCursorInit"); + + /* Create cursor infor record */ + infoPtr = xf86CreateCursorInfoRec(); + if (infoPtr == NULL) + { + LEAVE_PROC("SMI_HWCursorInit"); + return(FALSE); + } + + pSmi->CursorInfoRec = infoPtr; + + /* Fill in the information */ + infoPtr->MaxWidth = MAX_CURSOR; + infoPtr->MaxHeight = MAX_CURSOR; + infoPtr->Flags = HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8 + | HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK + | HARDWARE_CURSOR_AND_SOURCE_WITH_MASK + | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST + | HARDWARE_CURSOR_TRUECOLOR_AT_8BPP + | HARDWARE_CURSOR_INVERT_MASK; + + infoPtr->SetCursorColors = SMI_SetCursorColors; + infoPtr->SetCursorPosition = SMI_SetCursorPosition; + infoPtr->LoadCursorImage = SMI_LoadCursorImage; + infoPtr->HideCursor = SMI_HideCursor; + infoPtr->ShowCursor = SMI_ShowCursor; + infoPtr->RealizeCursor = SMI_RealizeCursor; + infoPtr->UseHWCursor = NULL; + + /* Proceed with cursor initialization */ + ret = xf86InitCursor(pScreen, infoPtr); + + LEAVE_PROC("SMI_HWCursorInit"); + return(ret); +} diff --git a/src/smi_i2c.c b/src/smi_i2c.c new file mode 100644 index 0000000..3a73ced --- /dev/null +++ b/src/smi_i2c.c @@ -0,0 +1,115 @@ +/* Header: //Mercury/Projects/archives/XFree86/4.0/smi_i2c.c-arc 1.10 27 Nov 2000 15:47:58 Frido $ */ + +/* +Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. +Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of the XFree86 Project and +Silicon Motion shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without prior written +authorization from the XFree86 Project and Silicon Motion. +*/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_i2c.c,v 1.2 2001/12/20 21:35:39 eich Exp $ */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" +#include "xf86Pci.h" +#include "xf86PciInfo.h" +#include "vgaHW.h" + +#include "smi.h" + +#undef VERBLEV +#undef ENTER_PROC +#undef DEBUG_PROC +#undef LEAVE_PROC +#undef DEBUG +#define VERBLEV 2 +#define ENTER_PROC(PROCNAME) +#define DEBUG_PROC(PROCNAME) +#define LEAVE_PROC(PROCNAME) +#define DEBUG(arg) + +static void +SMI_I2CPutBits(I2CBusPtr b, int clock, int data) +{ + SMIPtr pSmi = SMIPTR(xf86Screens[b->scrnIndex]); + unsigned int reg = 0x30; + + ENTER_PROC("SMI_I2CPutBits"); + + if (clock) reg |= 0x01; + if (data) reg |= 0x02; + + VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72, reg); + + LEAVE_PROC("SMI_I2CPutBits"); +} + +static void +SMI_I2CGetBits(I2CBusPtr b, int *clock, int *data) +{ + SMIPtr pSmi = SMIPTR(xf86Screens[b->scrnIndex]); + unsigned int reg = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72); + + ENTER_PROC("SMI_I2CGetBits"); + + *clock = reg & 0x04; + *data = reg & 0x08; + + LEAVE_PROC("SMI_I2CGetBits"); +} + +Bool +SMI_I2CInit(ScrnInfoPtr pScrn) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_I2CInit"); + + if (pSmi->I2C == NULL) + { + I2CBusPtr I2CPtr = xf86CreateI2CBusRec(); + if (I2CPtr == NULL) + { + LEAVE_PROC("SMI_I2CInit"); + return(FALSE); + } + + I2CPtr->BusName = "I2C bus"; + I2CPtr->scrnIndex = pScrn->scrnIndex; + I2CPtr->I2CPutBits = SMI_I2CPutBits; + I2CPtr->I2CGetBits = SMI_I2CGetBits; + + if (!xf86I2CBusInit(I2CPtr)) + { + xf86DestroyI2CBusRec(I2CPtr, TRUE, TRUE); + LEAVE_PROC("SMI_I2CInit"); + return(FALSE); + } + + pSmi->I2C = I2CPtr; + } + + LEAVE_PROC("SMI_I2CInit"); + return(TRUE); +} diff --git a/src/smi_shadow.c b/src/smi_shadow.c new file mode 100644 index 0000000..5ef9ba5 --- /dev/null +++ b/src/smi_shadow.c @@ -0,0 +1,226 @@ +/* Header: //Mercury/Projects/archives/XFree86/4.0/smi_shadow.c-arc 1.10 30 Nov 2000 11:40:38 Frido $ */ + +/* +Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. +Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of the XFree86 Project and +Silicon Motion shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without prior written +authorization from the XFree86 Project and Silicon Motion. +*/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_shadow.c,v 1.2 2000/12/05 21:18:37 dawes Exp $ */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86_ansic.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "shadowfb.h" +#include "servermd.h" + +#include "smi.h" + +/******************************************************************************\ +|* SMI_RefreshArea +|*============================================================================= +|* +|* PARAMETERS: pScrn Pointer to ScrnInfo structure. +|* num Number of boxes to refresh. +|* pbox Pointer to an array of boxes to refresh. +|* +|* DESCRIPTION: Refresh a portion of the shadow buffer to the visual screen +|* buffer. This is mainly used for rotation purposes. +|* y +|* RETURNS: Nothing. +|* +\******************************************************************************/ +void SMI_RefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + SMIPtr pSmi = SMIPTR(pScrn); + int width, height, srcX, srcY, destX, destY; + + ENTER_PROC("SMI_RefreshArea"); + + /* #671 */ + if (pSmi->polyLines) + { + pSmi->polyLines = FALSE; + return; + } + + if (pSmi->rotate) + { + /* IF we need to do rotation, setup the hardware here. */ + WaitIdleEmpty(); + WRITE_DPR(pSmi, 0x10, pSmi->ShadowPitch); + WRITE_DPR(pSmi, 0x3C, pSmi->ShadowPitch); + WRITE_DPR(pSmi, 0x44, pSmi->FBOffset >> 3); + } + + /* #672 */ + if (pSmi->ClipTurnedOn) + { + WaitQueue(1); + WRITE_DPR(pSmi, 0x2C, pSmi->ScissorsLeft); + pSmi->ClipTurnedOn = FALSE; + } + + while (num--) + { + /* Get coordinates of the box to refresh. */ + srcX = pbox->x1; + srcY = pbox->y1; + width = pbox->x2 - srcX; + height = pbox->y2 - srcY; + + DEBUG((VERBLEV, "x=%d y=%d w=%d h=%d\n", srcX, srcY, width, height)); + + if ((width > 0) && (height > 0)) + { + switch (pSmi->rotate) + { + case SMI_ROTATE_CW: + /* 90 degrees CW rotation. Calculate destination + coordinates: + + *---+ + | | +-----* + | | | | destX = shadowHeight - srcY - 1 + | | --> | | destY = srcX + | | | | + | | +-----+ + +---+ + */ + destX = pSmi->ShadowHeight - srcY - 1; + destY = srcX; + + WaitQueue(4); + WRITE_DPR(pSmi, 0x00, (srcX << 16) + srcY); + WRITE_DPR(pSmi, 0x04, (destX << 16) + destY); + WRITE_DPR(pSmi, 0x08, (width << 16) + height); + WRITE_DPR(pSmi, 0x0C, 0xCC | SMI_ROTATE_BLT | + SMI_ROTATE_CW | SMI_START_ENGINE); + break; + + case SMI_ROTATE_CCW: + /* 90 degrees CCW rotatation. Calculate destination + coordinates: + + *---+ + | | +-----+ + | | | | destX = srcY + | | --> | | destY = shadowWidth - srcX - 1 + | | | | + | | *-----+ + +---+ + */ + destX = srcY; + destY = pSmi->ShadowWidth - srcX - 1; + + WaitQueue(4); + WRITE_DPR(pSmi, 0x00, (srcX << 16) + srcY); + WRITE_DPR(pSmi, 0x04, (destX << 16) + destY); + WRITE_DPR(pSmi, 0x08, (width << 16) + height); + WRITE_DPR(pSmi, 0x0C, 0xCC | SMI_ROTATE_BLT | + SMI_ROTATE_CCW | SMI_START_ENGINE); + break; + + default: + /* No rotation, perform a normal copy. */ + if (pScrn->bitsPerPixel == 24) + { + srcX *= 3; + width *= 3; + + if (pSmi->Chipset == SMI_LYNX) + { + srcY *= 3; + } + } + + WaitQueue(4); + WRITE_DPR(pSmi, 0x00, (srcX << 16) + srcY); + WRITE_DPR(pSmi, 0x04, (srcX << 16) + srcY); + WRITE_DPR(pSmi, 0x08, (width << 16) + height); + WRITE_DPR(pSmi, 0x0C, SMI_BITBLT + SMI_START_ENGINE + 0xCC); + break; + } + } + + pbox++; + } + + if (pSmi->rotate) + { + /* If we did a rotation, we need to restore the hardware state here. */ + WaitIdleEmpty(); + WRITE_DPR(pSmi, 0x10, (pSmi->Stride << 16) | pSmi->Stride); + WRITE_DPR(pSmi, 0x3C, (pSmi->Stride << 16) | pSmi->Stride); + WRITE_DPR(pSmi, 0x44, 0); + } + + LEAVE_PROC("SMI_RefreshArea"); +} + +/******************************************************************************\ +|* SMI_PointerMoved +|*============================================================================= +|* +|* PARAMETERS: index Index of current screen. +|* x X location of pointer. +|* y Y location of pointer. +|* +|* DESCRIPTION: Adjust the pointer location if we are in rotation mode. +|* +|* RETURNS: Nothing. +|* +\******************************************************************************/ +void SMI_PointerMoved(int index, int x, int y) +{ + ScrnInfoPtr pScrn = xf86Screens[index]; + SMIPtr pSmi = SMIPTR(pScrn); + int newX, newY; + + switch (pSmi->rotate) + { + case SMI_ROTATE_CW: + /* 90 degrees CW rotation. */ + newX = pScrn->pScreen->height - y - 1; + newY = x; + break; + + case SMI_ROTATE_CCW: + /* 90 degrees CCW rotation. */ + newX = y; + newY = pScrn->pScreen->width - x - 1; + break; + + default: + /* No rotation. */ + newX = x; + newY = y; + break; + } + + /* Pass adjusted pointer coordinates original PointerMoved function. */ + (*pSmi->PointerMoved)(index, newX, newY); +} diff --git a/src/smi_video.c b/src/smi_video.c new file mode 100644 index 0000000..7ec571e --- /dev/null +++ b/src/smi_video.c @@ -0,0 +1,2548 @@ +/* Header: //Mercury/Projects/archives/XFree86/4.0/smi_video.c.-arc 1.14 30 Nov 2000 16:51:40 Frido $ */ +/* +Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. +Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. +Copyright (C) 2001 Corvin Zahn. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of the XFree86 Project and +Silicon Motion shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without prior written +authorization from the XFree86 Project and silicon Motion. +*/ + +/* +this is a heavy modified version of the V1.2.2 original siliconmotion driver. +- SAA7111 support +- supports attributes: XV_ENCODING, XV_BRIGHTNESS, XV_CONTRAST, + XV_SATURATION, XV_HUE, XV_COLORKEY, XV_INTERLACED + XV_CAPTURE_BRIGHTNESS can be used to set brightness in the capture device +- bug fixes +- tries not to use acceleration functions (if USE_XAA = 0) +- interlaced video for double vertical resolution + +Author of changes: Corvin Zahn <zahn@zac.de> +Date: 2.11.2001 +*/ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_video.c,v 1.9.2.1 2003/05/09 02:22:00 dawes Exp $ */ + +#include "smi.h" +#include "smi_video.h" + + +/* + +new attribute: + +XV_INTERLACED = 0: only one field of an interlaced video signal is displayed: + -> half vertical resolution, but no comb like artifacts from + moving vertical edges +XV_INTERLACED = 1: both fields of an interlaced video signal are displayed: + -> full vertical resolution, but comb like artifacts from + moving vertical edges + +The default value can be set with the driver option Interlaced + +*/ + + + + +#undef MIN +#undef ABS +#undef CLAMP +#undef ENTRIES + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define ABS(n) (((n) < 0) ? -(n) : (n)) +#define CLAMP(v, min, max) (((v) < (min)) ? (min) : MIN(v, max)) + +#define ENTRIES(array) (sizeof(array) / sizeof((array)[0])) +#define nElems(x) (sizeof(x) / sizeof(x[0])) + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +#if defined(XvExtension) && SMI_USE_VIDEO + +/* USE_XAA = 1: use XAA functions for color key rectangle fill, + USE_XAA = 0: use xf86XVFillKeyHelper for color key rectangle fill, + needs common/xf86xv.c >= 1.30, + common/xf86xv.h >= 1.22, + loader/xf86sym.c >= 1.194 */ +#define USE_XAA 1 + +#include "dixstruct.h" +#if USE_XAA +#include "xaa.h" +#include "xaalocal.h" +#endif + + +static int SMI_AddEncoding(XF86VideoEncodingPtr enc, int i, + int norm, int input, int channel); +static void SMI_BuildEncodings(SMI_PortPtr p); + +static XF86VideoAdaptorPtr SMI_SetupVideo(ScreenPtr pScreen); +static void SMI_ResetVideo(ScrnInfoPtr pScrn); + +#if SMI_USE_CAPTURE +static int SMI_PutVideo(ScrnInfoPtr pScrn, + short vid_x, short vid_y, short drw_x, short drw_y, + short vid_w, short vid_h, short drw_w, short drw_h, + RegionPtr clipBoxes, pointer data); +#endif +static void SMI_StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown); +static int SMI_SetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, + INT32 value, pointer data); +static int SMI_GetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, + INT32 *value, pointer data); +static void SMI_QueryBestSize(ScrnInfoPtr pScrn, Bool motion, + short vid_w, short vid_h, short drw_w, short drw_h, + unsigned int *p_w, unsigned int *p_h, pointer data); +static int SMI_PutImage(ScrnInfoPtr pScrn, + short src_x, short src_y, short drw_x, short drw_y, + short src_w, short src_h, short drw_w, short drw_h, + int id, unsigned char *buf, short width, short height, Bool sync, + RegionPtr clipBoxes, pointer data); +static int SMI_QueryImageAttributes(ScrnInfoPtr pScrn, + int id, unsigned short *width, unsigned short *height, + int *picthes, int *offsets); + +static Bool RegionsEqual(RegionPtr A, RegionPtr B); +static Bool SMI_ClipVideo(ScrnInfoPtr pScrn, BoxPtr dst, + INT32 *x1, INT32 *y1, INT32 *x2, INT32 *y2, + RegionPtr reg, INT32 width, INT32 height); +static void SMI_DisplayVideo(ScrnInfoPtr pScrn, int id, int offset, + short width, short height, int pitch, int x1, int y1, int x2, int y2, + BoxPtr dstBox, short vid_w, short vid_h, short drw_w, short drw_h); +static void SMI_BlockHandler(int i, pointer blockData, pointer pTimeout, + pointer pReadMask); +#if 0 +static void SMI_WaitForSync(ScrnInfoPtr pScrn); +#endif +/*static int SMI_SendI2C(ScrnInfoPtr pScrn, CARD8 device, char *devName, + SMI_I2CDataPtr i2cData);*/ + +static void SMI_InitOffscreenImages(ScreenPtr pScreen); +static FBAreaPtr SMI_AllocateMemory(ScrnInfoPtr pScrn, FBAreaPtr area, + int numLines); +static void SMI_CopyData(unsigned char *src, unsigned char *dst, int srcPitch, + int dstPitch, int height, int width); +static void SMI_CopyYV12Data(unsigned char *src1, unsigned char *src2, + unsigned char *src3, unsigned char *dst, int srcPitch1, int srcPitch2, + int dstPitch, int height, int width); + +static int SMI_AllocSurface(ScrnInfoPtr pScrn, + int id, unsigned short width, unsigned short height, + XF86SurfacePtr surface); +static int SMI_FreeSurface(XF86SurfacePtr surface); +static int SMI_DisplaySurface(XF86SurfacePtr surface, + short vid_x, short vid_y, short drw_x, short drw_y, + short vid_w, short vid_h, short drw_w, short drw_h, + RegionPtr clipBoxes); +static int SMI_StopSurface(XF86SurfacePtr surface); +static int SMI_GetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 *value); +static int SMI_SetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 value); + +static int SetAttr(ScrnInfoPtr pScrn, int i, int value); +static int SetAttrSAA7110(ScrnInfoPtr pScrn, int i, int value); +static int SetAttrSAA7111(ScrnInfoPtr pScrn, int i, int value); + +/** + * Atoms + */ + +static Atom xvColorKey; +static Atom xvEncoding; +static Atom xvBrightness,xvCapBrightness, xvContrast, xvSaturation, xvHue; +static Atom xvInterlaced; + + +/******************************************************************************\ +** ** +** C A P A B I L I T I E S ** +** ** +\******************************************************************************/ + + +/**************************************************************************/ +/* input channels */ + +#define N_COMPOSITE_CHANNELS 4 +#define N_SVIDEO_CHANNELS 2 + +#define N_VIDEO_INPUTS 2 +typedef enum _VideoInput { COMPOSITE, SVIDEO } VideoInput; + + +/**************************************************************************/ +/* video input formats */ + +typedef struct _VideoInputDataRec { + char* name; +} VideoInputDataRec; + +static VideoInputDataRec VideoInputs[] = { + { "composite" }, + { "svideo" } +}; + + +/**************************************************************************/ +/* video norms */ + +#define N_VIDEO_NORMS 3 +typedef enum _VideoNorm { PAL, NTSC, SECAM } VideoNorm; + +typedef struct _VideoNormDataRec { + char* name; + unsigned long Wt; + unsigned long Wa; + unsigned long Ht; + unsigned long Ha; + unsigned long HStart; + unsigned long VStart; + XvRationalRec rate; +} VideoNormDataRec; + + +static VideoNormDataRec VideoNorms[] = +{ + /* PAL-BDGHI */ + {"pal", 864, 704, 625, 576, 16, 16, { 1, 50 }}, + /* NTSC */ + {"ntsc", 858, 704, 525, 480, 21, 8, { 1001, 60000 }}, + /* SECAM (not tested) */ + {"secam", 864, 7040, 625, 576, 31, 16, { 1, 50 }}, +}; + + +/**************************************************************************/ +/* number of (generated) XV_ENCODING vaulues */ +#define N_ENCODINGS ((N_VIDEO_NORMS) * (N_COMPOSITE_CHANNELS + N_SVIDEO_CHANNELS)) + + +/**************************************************************************/ + +static XF86VideoFormatRec SMI_VideoFormats[] = +{ + { 15, TrueColor }, /* depth, class */ + { 16, TrueColor }, /* depth, class */ + { 24, TrueColor }, /* depth, class */ +}; + + +/**************************************************************************/ + +/** + * Attributes + */ + +#define XV_ENCODING_NAME "XV_ENCODING" +#define XV_BRIGHTNESS_NAME "XV_BRIGHTNESS" +#define XV_CAPTURE_BRIGHTNESS_NAME "XV_CAPTURE_BRIGHTNESS" +#define XV_CONTRAST_NAME "XV_CONTRAST" +#define XV_SATURATION_NAME "XV_SATURATION" +#define XV_HUE_NAME "XV_HUE" +#define XV_COLORKEY_NAME "XV_COLORKEY" +#define XV_INTERLACED_NAME "XV_INTERLACED" + + +/* fixed order! */ +static XF86AttributeRec SMI_VideoAttributesSAA711x[N_ATTRS] = { + {XvSettable | XvGettable, 0, N_ENCODINGS-1, XV_ENCODING_NAME}, + {XvSettable | XvGettable, 0, 255, XV_BRIGHTNESS_NAME}, + {XvSettable | XvGettable, 0, 255, XV_CAPTURE_BRIGHTNESS_NAME}, + {XvSettable | XvGettable, 0, 127, XV_CONTRAST_NAME}, + {XvSettable | XvGettable, 0, 127, XV_SATURATION_NAME}, + {XvSettable | XvGettable, -128, 127, XV_HUE_NAME}, + {XvSettable | XvGettable, 0x000000, 0xFFFFFF, XV_COLORKEY_NAME}, + {XvSettable | XvGettable, 0, 1, XV_INTERLACED_NAME}, +}; + +static XF86AttributeRec SMI_VideoAttributes[2] = { + {XvSettable | XvGettable, 0, 255, XV_BRIGHTNESS_NAME}, + {XvSettable | XvGettable, 0x000000, 0xFFFFFF, XV_COLORKEY_NAME}, +}; + + +/**************************************************************************/ +static XF86ImageRec SMI_VideoImages[] = +{ + XVIMAGE_YUY2, + XVIMAGE_YV12, + XVIMAGE_I420, + { + FOURCC_RV15, /* id */ + XvRGB, /* type */ + LSBFirst, /* byte_order */ + { 'R', 'V' ,'1', '5', + 0x00, '5', 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, /* guid */ + 16, /* bits_per_pixel */ + XvPacked, /* format */ + 1, /* num_planes */ + 15, /* depth */ + 0x001F, 0x03E0, 0x7C00, /* red_mask, green, blue */ + 0, 0, 0, /* y_sample_bits, u, v */ + 0, 0, 0, /* horz_y_period, u, v */ + 0, 0, 0, /* vert_y_period, u, v */ + { 'R', 'V', 'B' }, /* component_order */ + XvTopToBottom /* scaline_order */ + }, + { + FOURCC_RV16, /* id */ + XvRGB, /* type */ + LSBFirst, /* byte_order */ + { 'R', 'V' ,'1', '6', + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, /* guid */ + 16, /* bits_per_pixel */ + XvPacked, /* format */ + 1, /* num_planes */ + 16, /* depth */ + 0x001F, 0x07E0, 0xF800, /* red_mask, green, blue */ + 0, 0, 0, /* y_sample_bits, u, v */ + 0, 0, 0, /* horz_y_period, u, v */ + 0, 0, 0, /* vert_y_period, u, v */ + { 'R', 'V', 'B' }, /* component_order */ + XvTopToBottom /* scaline_order */ + }, + { + FOURCC_RV24, /* id */ + XvRGB, /* type */ + LSBFirst, /* byte_order */ + { 'R', 'V' ,'2', '4', + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, /* guid */ + 24, /* bits_per_pixel */ + XvPacked, /* format */ + 1, /* num_planes */ + 24, /* depth */ + 0x0000FF, 0x00FF00, 0xFF0000, /* red_mask, green, blue */ + 0, 0, 0, /* y_sample_bits, u, v */ + 0, 0, 0, /* horz_y_period, u, v */ + 0, 0, 0, /* vert_y_period, u, v */ + { 'R', 'V', 'B' }, /* component_order */ + XvTopToBottom /* scaline_order */ + }, + { + FOURCC_RV32, /* id */ + XvRGB, /* type */ + LSBFirst, /* byte_order */ + { 'R', 'V' ,'3', '2', + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, /* guid */ + 32, /* bits_per_pixel */ + XvPacked, /* format */ + 1, /* num_planes */ + 24, /* depth */ + 0x0000FF, 0x00FF00, 0xFF0000, /* red_mask, green, blue */ + 0, 0, 0, /* y_sample_bits, u, v */ + 0, 0, 0, /* horz_y_period, u, v */ + 0, 0, 0, /* vert_y_period, u, v */ + { 'R', 'V', 'B' }, /* component_order */ + XvTopToBottom /* scaline_order */ + }, +}; + + +/**************************************************************************/ + +/** + * SAA7111 video decoder register values + */ + + +/** SAA7111 control sequences for selecting one out of four + composite input channels */ +static I2CByte SAA7111CompositeChannelSelect[N_COMPOSITE_CHANNELS][4] = { + { 0x02, 0xC0, 0x09, 0x4A}, /* CVBS AI11 */ + { 0x02, 0xC1, 0x09, 0x4A}, /* CVBS AI12 */ + { 0x02, 0xC2, 0x09, 0x4A}, /* CVBS AI21 */ + { 0x02, 0xC3, 0x09, 0x4A}, /* CVBS AI22 */ +}; + + +/** SAA7111 control sequences for selecting one out of two + s-video input channels */ +static I2CByte SAA7111SVideoChannelSelect[N_SVIDEO_CHANNELS][4] = { + { 0x02, 0xC6, 0x09, 0xCA}, /* Y/C AI11/AI21 */ + { 0x02, 0xC7, 0x09, 0xCA}, /* Y/C AI12/AI22 */ +}; + + +/** SAA7111 control sequences for selecting one out of three + video norms */ +static I2CByte SAA7111VideoStd[3][8] = { + {0x06, 108, 0x07, 108, 0x08, 0x09, 0x0E, 0x01}, /* PAL */ + {0x06, 107, 0x07, 107, 0x08, 0x49, 0x0E, 0x01}, /* NTSC */ + {0x06, 108, 0x07, 108, 0x08, 0x01, 0x0E, 0x51} /* SECAM */ +}; + + +#if 0 +static I2CByte SAA7110InitData[] = +{ + /* Configuration */ + 0x00, 0x4C, 0x01, 0x3C, 0x02, 0x00, 0x03, 0xEF, + 0x04, 0xBD, 0x05, 0xE2, 0x06, 0x00, 0x07, 0x00, + 0x08, 0xF8, 0x09, 0xF8, 0x0A, 0x60, 0x0B, 0x60, + 0x0C, 0x00, 0x0D, 0x80, 0x0E, 0x18, 0x0F, 0xD9, + 0x10, 0x00, 0x11, 0x2B, 0x12, 0x40, 0x13, 0x40, + 0x14, 0x42, 0x15, 0x1A, 0x16, 0xFF, 0x17, 0xDA, + 0x18, 0xE6, 0x19, 0x90, 0x20, 0xD9, 0x21, 0x16, + 0x22, 0x40, 0x23, 0x40, 0x24, 0x80, 0x25, 0x40, + 0x26, 0x80, 0x27, 0x4F, 0x28, 0xFE, 0x29, 0x01, + 0x2A, 0xCF, 0x2B, 0x0F, 0x2C, 0x03, 0x2D, 0x01, + 0x2E, 0x83, 0x2F, 0x03, 0x30, 0x40, 0x31, 0x35, + 0x32, 0x02, 0x33, 0x8C, 0x34, 0x03, + + /* NTSC */ + 0x11, 0x2B, 0x0F, 0xD9, + + /* RCA input connector */ + 0x06, 0x00, 0x0E, 0x18, 0x20, 0xD9, 0x21, 0x16, + 0x22, 0x40, 0x2C, 0x03, + +}; +#endif + +static I2CByte SAA7111InitData[] = +{ + 0x11, 0x1D, /* 0D D0=1: automatic colour killer off + D1=0: DMSD data to YUV output + D2=1: output enable H/V sync on + D3=1: output enable YUV data on */ + 0x02, 0xC0, /* Mode 0 */ + 0x03, 0x23, /* automatic gain */ + 0x04, 0x00, /* */ + 0x05, 0x00, /* */ + 0x06, 108, /* hor sync begin */ + 0x07, 108, /* hor sync stop */ + 0x08, 0x88, /* sync control: + D1-0=00: VNOI = normal mode + D2=0: PLL closed + D3=1: VTR mode + D7=1: automatic field detection */ + 0x09, 0x41, /* 4A luminance control */ + 0x0A, 0x80, /* brightness = 128 (CCIR level) */ + 0x0B, 0x40, /* contrast = 1.0 */ + 0x0C, 0x40, /* crominance = 1.0 (CCIR level) */ + 0x0D, 0x00, /* hue = 0 */ + 0x0E, 0x01, /* chroma bandwidth = nominal + fast colour time constant = nominal + chrom comp filter on + colour standard PAL BGHI, NTSC M */ + 0x10, 0x48, /* luminance delay compensation = 0 + VRLN = 1 + fine pos of hs = 0 + output format = YUV 422 */ + 0x12, 0x00, /* 20 D5=1: VPO in tristate */ + 0x13, 0x00, + 0x15, 0x00, + 0x16, 0x00, + 0x17, 0x00, + +}; + + +/**************************************************************************/ + +/** + * generates XF86VideoEncoding[i] with video norm norm, video input format + * input and video input channel channel + */ +static int +SMI_AddEncoding(XF86VideoEncodingPtr enc, int i, + int norm, int input, int channel) +{ + char* norm_string; + char* input_string; + char channel_string[20]; + + ENTER_PROC("SMI_AddEncoding"); + + norm_string = VideoNorms[norm].name; + input_string = VideoInputs[input].name; + sprintf(channel_string, "%d", channel); + enc[i].id = i; + enc[i].name = xalloc(strlen(norm_string) + + strlen(input_string) + + strlen(channel_string)+3); + if (NULL == enc[i].name) { + LEAVE_PROC("SMI_AddEncoding"); + return -1; + } + enc[i].width = VideoNorms[norm].Wa; + enc[i].height = VideoNorms[norm].Ha; + enc[i].rate = VideoNorms[norm].rate; + sprintf(enc[i].name,"%s-%s-%s", norm_string, input_string, channel_string); + + LEAVE_PROC("SMI_AddEncoding"); + return 0; +} + + +/** + * builds XF86VideoEncodings with all legal combinations of video norm, + * video input format and video input channel + */ +static void +SMI_BuildEncodings(SMI_PortPtr p) +{ + int ch, n; + + ENTER_PROC("SMI_BuildEncodings"); + + /* allocate memory for encoding array */ + p->enc = xalloc(sizeof(XF86VideoEncodingRec) * N_ENCODINGS); + if (NULL == p->enc) + goto fail; + memset(p->enc,0,sizeof(XF86VideoEncodingRec) * N_ENCODINGS); + /* allocate memory for video norm array */ + p->norm = xalloc(sizeof(int) * N_ENCODINGS); + if (NULL == p->norm) + goto fail; + memset(p->norm,0,sizeof(int) * N_ENCODINGS); + /* allocate memory for video input format array */ + p->input = xalloc(sizeof(int) * N_ENCODINGS); + if (NULL == p->input) + goto fail; + memset(p->input,0,sizeof(int) * N_ENCODINGS); + /* allocate memory for video channel number array */ + p->channel = xalloc(sizeof(int) * N_ENCODINGS); + if (NULL == p->channel) + goto fail; + memset(p->channel,0,sizeof(int) * N_ENCODINGS); + + /* fill arrays */ + p->nenc = 0; + for (ch = 0; ch < N_COMPOSITE_CHANNELS; ch++) { + for (n = 0; n < N_VIDEO_NORMS; n++) { + SMI_AddEncoding(p->enc, p->nenc, n, COMPOSITE, ch); + p->norm[p->nenc] = n; + p->input[p->nenc] = COMPOSITE; + p->channel[p->nenc] = ch; + p->nenc++; + } + } + for (ch = 0; ch < N_SVIDEO_CHANNELS; ch++) { + for (n = 0; n < N_VIDEO_NORMS; n++) { + SMI_AddEncoding(p->enc, p->nenc, n, SVIDEO, ch); + p->norm[p->nenc] = n; + p->input[p->nenc] = SVIDEO; + p->channel[p->nenc] = ch; + p->nenc++; + } + } + LEAVE_PROC("SMI_BuildEncodings"); + return; + + fail: + if (p->input) xfree(p->input); + p->input = NULL; + if (p->norm) xfree(p->norm); + p->norm = NULL; + if (p->channel) xfree(p->channel); + p->channel = NULL; + if (p->enc) xfree(p->enc); + p->enc = NULL; + p->nenc = 0; + LEAVE_PROC("SMI_BuildEncodings"); +} + + +/******************************************************************************\ +** ** +** X V E X T E N S I O N I N T E R F A C E ** +** ** +\******************************************************************************/ + +void +SMI_InitVideo(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SMIPtr psmi = SMIPTR(pScrn); + XF86VideoAdaptorPtr *ptrAdaptors, *newAdaptors = NULL; + XF86VideoAdaptorPtr newAdaptor = NULL; + int numAdaptors; + + ENTER_PROC("SMI_InitVideo"); + + numAdaptors = xf86XVListGenericAdaptors(pScrn, &ptrAdaptors); + + DEBUG((VERBLEV, "numAdaptors=%d\n", numAdaptors)); + + if (psmi->rotate == 0) + { + newAdaptor = SMI_SetupVideo(pScreen); + DEBUG((VERBLEV, "newAdaptor=%p\n", newAdaptor)); + SMI_InitOffscreenImages(pScreen); + } + + if (newAdaptor != NULL) + { + if (numAdaptors == 0) + { + numAdaptors = 1; + ptrAdaptors = &newAdaptor; + } + else + { + newAdaptors = xalloc((numAdaptors + 1) * + sizeof(XF86VideoAdaptorPtr*)); + if (newAdaptors != NULL) + { + memcpy(newAdaptors, ptrAdaptors, + numAdaptors * sizeof(XF86VideoAdaptorPtr)); + newAdaptors[numAdaptors++] = newAdaptor; + ptrAdaptors = newAdaptors; + } + } + } + + if (numAdaptors != 0) + { + DEBUG((VERBLEV, "ScreenInit %i\n",numAdaptors)); + xf86XVScreenInit(pScreen, ptrAdaptors, numAdaptors); + } + + if (newAdaptors != NULL) + { + xfree(newAdaptors); + } + + LEAVE_PROC("SMI_InitVideo"); +} + + +/*************************************************************************/ + +/* + * Video codec controls + */ + +#if 0 +/** + * scales value value of attribute i to range min, max + */ +static int +Scale(int i, int value, int min, int max) +{ + return min + (value - SMI_VideoAttributes[i].min_value) * (max - min) / + (SMI_VideoAttributes[i].max_value - SMI_VideoAttributes[i].min_value); +} +#endif +/** + * sets video decoder attributes channel, encoding, brightness, contrast, saturation, hue + */ +static int +SetAttr(ScrnInfoPtr pScrn, int i, int value) +{ + SMIPtr pSmi = SMIPTR(pScrn); + SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr; + + if (i < XV_ENCODING || i > XV_HUE) + return BadMatch; + + /* clamps value to attribute range */ + value = CLAMP(value, SMI_VideoAttributes[i].min_value, + SMI_VideoAttributes[i].max_value); + + if (i == XV_BRIGHTNESS) { + int my_value = (value <= 128? value + 128 : value - 128); + WRITE_VPR(pSmi, 0x5C, 0xEDEDED | (my_value << 24)); + } else if (pPort->I2CDev.SlaveAddr == SAA7110) { + return SetAttrSAA7110(pScrn, i, value); + } + else if (pPort->I2CDev.SlaveAddr == SAA7111) { + return SetAttrSAA7111(pScrn, i, value); + } +#if 0 + else { + return XvBadAlloc; + } +#endif + + return Success; +} + + +/** + * sets SAA7110 video decoder attributes channel, encoding, brightness, contrast, saturation, hue + */ +static int +SetAttrSAA7110(ScrnInfoPtr pScrn, int i, int value) +{ + /* not supported */ + return XvBadAlloc; +} + + +/** + * sets SAA7111 video decoder attributes channel, encoding, + * brightness, contrast, saturation, hue + */ +static int +SetAttrSAA7111(ScrnInfoPtr pScrn, int i, int value) +{ + SMIPtr pSmi = SMIPTR(pScrn); + SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr; + + if (i == XV_ENCODING) { + int norm; + int input; + int channel; + norm = pPort->norm[value]; + input = pPort->input[value]; + channel = pPort->channel[value]; + + DEBUG((VERBLEV, "SetAttribute XV_ENCODING: %d. norm=%d input=%d channel=%d\n", + value, norm, input, channel)); + + /* set video norm */ + if (!xf86I2CWriteVec(&(pPort->I2CDev), SAA7111VideoStd[norm], + ENTRIES(SAA7111VideoStd[norm]) / 2)) { + return XvBadAlloc; + } + /* set video input format and channel */ + if (input == COMPOSITE) { + if (!xf86I2CWriteVec(&(pPort->I2CDev), + SAA7111CompositeChannelSelect[channel], + ENTRIES(SAA7111CompositeChannelSelect[channel]) / 2)) { + return XvBadAlloc; + } + } + else { + if (!xf86I2CWriteVec(&(pPort->I2CDev), + SAA7111SVideoChannelSelect[channel], + ENTRIES(SAA7111SVideoChannelSelect[channel]) / 2)) { + return XvBadAlloc; + } + } + } + else if (i >= XV_CAPTURE_BRIGHTNESS && i <= XV_HUE) { + int slave_adr = 0; + + switch (i) { + + case XV_CAPTURE_BRIGHTNESS: + DEBUG((VERBLEV, "SetAttribute XV_BRIGHTNESS: %d\n", value)); + slave_adr = 0x0a; + break; + + case XV_CONTRAST: + DEBUG((VERBLEV, "SetAttribute XV_CONTRAST: %d\n", value)); + slave_adr = 0x0b; + break; + + case XV_SATURATION: + DEBUG((VERBLEV, "SetAttribute XV_SATURATION: %d\n", value)); + slave_adr = 0x0c; + break; + + case XV_HUE: + DEBUG((VERBLEV, "SetAttribute XV_HUE: %d\n", value)); + slave_adr = 0x0d; + break; + + default: + return XvBadAlloc; + } + if (!xf86I2CWriteByte(&(pPort->I2CDev), slave_adr, (value & 0xff))) + return XvBadAlloc; + } + else { + return BadMatch; + } + + /* debug: show registers */ + { + I2CByte i2c_bytes[32]; + int i; + xf86I2CReadBytes(&(pPort->I2CDev), 0, i2c_bytes, 32); + DEBUG((VERBLEV, "SAA7111 Registers\n")); + for (i=0; i<32; i++) { + DEBUG((VERBLEV, "%02X=%02X ", i, i2c_bytes[i])); + if ((i&7) == 7) DEBUG((VERBLEV, "\n")); + } + } + + return Success; +} + + +/******************************************************************************\ +** ** +** V I D E O M A N A G E M E N T ** +** ** +\******************************************************************************/ + +static XF86VideoAdaptorPtr +SMI_SetupVideo( + ScreenPtr pScreen +) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SMIPtr pSmi = SMIPTR(pScrn); + SMI_PortPtr smiPortPtr; + XF86VideoAdaptorPtr ptrAdaptor; + + ENTER_PROC("SMI_SetupVideo"); + + ptrAdaptor = xcalloc(1, sizeof(XF86VideoAdaptorRec) + + sizeof(DevUnion) + sizeof(SMI_PortRec)); + if (ptrAdaptor == NULL) + { + LEAVE_PROC("SMI_SetupVideo"); + return(NULL); + } + + ptrAdaptor->type = XvInputMask +#if SMI_USE_CAPTURE + | XvOutputMask + | XvVideoMask +#endif + | XvImageMask + | XvWindowMask + ; + + ptrAdaptor->flags = VIDEO_OVERLAID_IMAGES + | VIDEO_CLIP_TO_VIEWPORT + ; + + ptrAdaptor->name = "Silicon Motion Lynx Series Video Engine"; + + ptrAdaptor->nPorts = 1; + ptrAdaptor->pPortPrivates = (DevUnion*) &ptrAdaptor[1]; + ptrAdaptor->pPortPrivates[0].ptr = (pointer) &ptrAdaptor->pPortPrivates[1]; + + smiPortPtr = (SMI_PortPtr) ptrAdaptor->pPortPrivates[0].ptr; + + SMI_BuildEncodings(smiPortPtr); + ptrAdaptor->nEncodings = smiPortPtr->nenc; + ptrAdaptor->pEncodings = smiPortPtr->enc; +#if 0 + /* aaa whats this? */ + for (i = 0; i < nElems(SMI_VideoEncodings); i++) + { + SMI_VideoEncodings[i].width = pSmi->lcdWidth; + SMI_VideoEncodings[i].height = pSmi->lcdHeight; + } +#endif + + ptrAdaptor->nFormats = nElems(SMI_VideoFormats); + ptrAdaptor->pFormats = SMI_VideoFormats; + + ptrAdaptor->nAttributes = nElems(SMI_VideoAttributes); + ptrAdaptor->pAttributes = SMI_VideoAttributes; + + ptrAdaptor->nImages = nElems(SMI_VideoImages); + ptrAdaptor->pImages = SMI_VideoImages; + +#if SMI_USE_CAPTURE + ptrAdaptor->PutVideo = SMI_PutVideo; + ptrAdaptor->PutStill = NULL; + ptrAdaptor->GetVideo = NULL; + ptrAdaptor->GetStill = NULL; +#else + ptrAdaptor->PutVideo = NULL; + ptrAdaptor->PutStill = NULL; + ptrAdaptor->GetVideo = NULL; + ptrAdaptor->GetStill = NULL; +#endif + ptrAdaptor->StopVideo = SMI_StopVideo; + ptrAdaptor->SetPortAttribute = SMI_SetPortAttribute; + ptrAdaptor->GetPortAttribute = SMI_GetPortAttribute; + ptrAdaptor->QueryBestSize = SMI_QueryBestSize; + ptrAdaptor->PutImage = SMI_PutImage; + ptrAdaptor->QueryImageAttributes = SMI_QueryImageAttributes; + + smiPortPtr->Attribute[XV_COLORKEY] = pSmi->videoKey; + smiPortPtr->Attribute[XV_INTERLACED] = pSmi->interlaced; + smiPortPtr->videoStatus = 0; + +#if 0 + /* aaa does not work ? */ + if (xf86I2CProbeAddress(pSmi->I2C, SAA7111)) + { + LEAVE_PROC("SMI_SetupVideo"); + return(NULL); + } + DEBUG((VERBLEV, "SAA7111 detected\n")); +#endif + + smiPortPtr->I2CDev.DevName = "SAA 7111A"; + smiPortPtr->I2CDev.SlaveAddr = SAA7111; + smiPortPtr->I2CDev.pI2CBus = pSmi->I2C; + + + if (xf86I2CDevInit(&(smiPortPtr->I2CDev))) + { + + if (xf86I2CWriteVec(&(smiPortPtr->I2CDev), SAA7111InitData, + ENTRIES(SAA7111InitData) / 2)) { + xvEncoding = MAKE_ATOM(XV_ENCODING_NAME); + xvHue = MAKE_ATOM(XV_HUE_NAME); + xvSaturation = MAKE_ATOM(XV_SATURATION_NAME); + xvContrast = MAKE_ATOM(XV_CONTRAST_NAME); + + xvInterlaced = MAKE_ATOM(XV_INTERLACED_NAME); + DEBUG((VERBLEV, "SAA7111 intialized\n")); + + } else { + xf86DestroyI2CDevRec(&(smiPortPtr->I2CDev),FALSE); + smiPortPtr->I2CDev.SlaveAddr = 0; + } + } else + smiPortPtr->I2CDev.SlaveAddr = 0; + + REGION_INIT(pScreen, &smiPortPtr->clip, NullBox, 0); + + pSmi->ptrAdaptor = ptrAdaptor; + pSmi->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = SMI_BlockHandler; + + xvColorKey = MAKE_ATOM(XV_COLORKEY_NAME); + xvBrightness = MAKE_ATOM(XV_BRIGHTNESS_NAME); + xvCapBrightness = MAKE_ATOM(XV_CAPTURE_BRIGHTNESS_NAME); + + SMI_ResetVideo(pScrn); + LEAVE_PROC("SMI_SetupVideo"); + return(ptrAdaptor); +} + + +static void +SMI_ResetVideo( + ScrnInfoPtr pScrn +) +{ + SMIPtr pSmi = SMIPTR(pScrn); + SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr; + int r, g, b; + + ENTER_PROC("SMI_ResetVideo"); + + SetAttr(pScrn, XV_ENCODING, 0); /* Encoding = pal-composite-0 */ + SetAttr(pScrn, XV_BRIGHTNESS, 128); /* Brightness = 128 (CCIR level) */ + SetAttr(pScrn, XV_CAPTURE_BRIGHTNESS, 128); /* Brightness = 128 (CCIR level) */ + SetAttr(pScrn, XV_CONTRAST, 71); /* Contrast = 71 (CCIR level) */ + SetAttr(pScrn, XV_SATURATION, 64); /* Color saturation = 64 (CCIR level) */ + SetAttr(pScrn, XV_HUE, 0); /* Hue = 0 */ + + switch (pScrn->depth) + { + case 8: + WRITE_VPR(pSmi, 0x04, pPort->Attribute[XV_COLORKEY] & 0x00FF); + WRITE_VPR(pSmi, 0x08, 0); + break; + + case 15: + case 16: + WRITE_VPR(pSmi, 0x04, pPort->Attribute[XV_COLORKEY] & 0xFFFF); + WRITE_VPR(pSmi, 0x08, 0); + break; + + default: + r = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.red) >> pScrn->offset.red; + g = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.green) >> pScrn->offset.green; + b = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.blue) >> pScrn->offset.blue; + WRITE_VPR(pSmi, 0x04, ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)); + WRITE_VPR(pSmi, 0x08, 0); + break; + } + + WRITE_VPR(pSmi, 0x5C, 0xEDEDED | (pPort->Attribute[XV_BRIGHTNESS] << 24)); + + LEAVE_PROC("SMI_ResetVideo"); +} + + +#if SMI_USE_CAPTURE +static int +SMI_PutVideo( + ScrnInfoPtr pScrn, + short vid_x, + short vid_y, + short drw_x, + short drw_y, + short vid_w, + short vid_h, + short drw_w, + short drw_h, + RegionPtr clipBoxes, + pointer data +) +{ + SMI_PortPtr pPort = (SMI_PortPtr) data; + SMIPtr pSmi = SMIPTR(pScrn); + CARD32 vid_pitch, vid_address; + CARD32 vpr00, cpr00; + int xscale, yscale; + BoxRec dstBox; + INT32 x1, y1, x2, y2; + int norm; + int areaHeight, width, height, fbPitch; + int top, left; + + ENTER_PROC("SMI_PutVideo"); + + DEBUG((VERBLEV, "Interlaced Video %d\n", pPort->Attribute[XV_INTERLACED])); + + if (!pPort->Attribute[XV_INTERLACED]) { + /* no interlace: lines will be doubled */ + vid_h /= 2; + } + + /* field start aaa*/ + norm = pPort->norm[pPort->Attribute[XV_ENCODING]]; + vid_x += VideoNorms[norm].HStart; + vid_y += VideoNorms[norm].VStart; + /* only even values allowed (UV-phase) */ + vid_x &= ~1; + + DEBUG((VERBLEV, "vid_x=%d vid_y=%d drw_x=%d drw_y=%d " + "vid_w=%d vid_h=%d drw_w=%d drw_h=%d\n", + vid_x, vid_y, drw_x, drw_y, vid_w, vid_h, drw_w, drw_h)); + + x1 = vid_x; + y1 = vid_y; + x2 = vid_x + vid_w; + y2 = vid_y + vid_h; + + width = vid_w; + height = vid_h; + + dstBox.x1 = drw_x; + dstBox.y1 = drw_y; + dstBox.x2 = drw_x + drw_w; + dstBox.y2 = drw_y + drw_h; + +#if 1 + if (!SMI_ClipVideo(pScrn, &dstBox, &x1, &y1, &x2, &y2, clipBoxes, width, + height)) +#else + if (!xf86XVClipVideoHelper(&dstBox, &x1, &y1, &x2, &y2, clipBoxes, width, + height)) +#endif + { + LEAVE_PROC("SMI_PutVideo"); + return(Success); + } + + DEBUG((VERBLEV, "Clip: x1=%d y1=%d x2=%d y2=%d\n", x1 >> 16, y1 >> 16, x2 >> 16, y2 >> 16)); + + dstBox.x1 -= pScrn->frameX0; + dstBox.y1 -= pScrn->frameY0; + dstBox.x2 -= pScrn->frameX0; + dstBox.y2 -= pScrn->frameY0; + + vid_pitch = (vid_w * 2 + 7) & ~7; + + vpr00 = READ_VPR(pSmi, 0x00) & ~0x0FF000FF; + cpr00 = READ_CPR(pSmi, 0x00) & ~0x000FFF00; + + /* vpr00: + Bit 2..0 = 6: Video Window I Format = YUV4:2:2 + Bit 3 = 1: Video Window I Enable = enabled + Bit 4 = 0: Video Window I YUV Averaging = disabled + Bit 5 = 0: Video Window I Hor. Replication = disabled + Bit 6 = 0: Video Window I data doubling = disabled + Bit 14..8 = 0: Video Window II = disabled + Bit 18..16 = 0: Graphics Data Format = 8-bit index + Bit 19 = 0: Top Video Window Select = window I + Bit 20 = 1: Color Key for Window I = enabled + Bit 21 = 0: Vertical Interpolation = s. below + Bit 22 = 0: Flicker Reduction for TV Modes = disabled + Bit 23 = 0: Fixed Vertical Interpolation = disabled + Bit 24 = 1: Select Video Window I Source Addr = + Bit 25 = 0: Enable V0FIFO to fetch 8-Bit color data = disabled + Bit 26 = 0: + Bit 27 = 1: Color Key for Window II = disabled + Bit 31..28 = reserved + */ + if (pPort->Attribute[XV_INTERLACED]) { + /* + Bit 21 = 0: Vertical Interpolation = disabled + Bit 24 = 0: Select Video Window I Source Addr = 0 + */ + vpr00 |= 0x0010000E; + } + else { + /* + Bit 21 = 10: Vertical Interpolation = enabled + Bit 24 = 1: Select Video Window I Source Addr = 1 + 1= Video window I source addr = capture port buffer ? + */ + vpr00 |= 0x0130000E; + } + + /* cpr00: + Bit 0 = 1: Video Capture Enable = enabled + Bit 8 = 0: Capture Control = continous + Bit 9 = 0: Double Buffer Enable = s. below + Bit 10 = 0: Interlace Data Capture = s. below + Bit 13..11 = 0: Frame Skip Enable = s. below + Bit 15..14 = 0: Video Capture Input Format = YUV4:2:2 + Bit 17..16 = 0: Enable Hor. Reduction = s. below + Bit 19..18 = 0: Enable Vert. Reduction = s. below + Bit 21..20 = 0: Enable Hor. Filtering = s. below + Bit 22 = 0: HREF Polarity = high active + Bit 23 = 0: VREF Polarity = high active + Bit 24 = 1: Field Detection Method VSYNC edge = rising + */ + if (pPort->Attribute[XV_INTERLACED]) { + /* + Bit 9 = 1: Double Buffer Enable = enabled + Bit 10 = 1: Interlace Data Capture = enabled + Bit 13..11 = 0: Frame Skip Enable = no skip + */ + cpr00 |= 0x01000601; + } + else { + /* + Bit 9 = 0: Double Buffer Enable = disabled + Bit 10 = 0: Interlace Data Capture = disabled + Bit 13..11 = 010: Frame Skip Enable = skip every other frame + */ + cpr00 |= 0x01000801; + } + + if (pSmi->ByteSwap) + cpr00 |= 0x00004000; + + fbPitch = pSmi->Stride; + if (pSmi->Bpp != 3) + { + fbPitch *= pSmi->Bpp; + } + + if (vid_w <= drw_w) + { + xscale = (256 * vid_w / drw_w) & 0xFF; + } + else if (vid_w / 2 <= drw_w) + { + xscale = (128 * vid_w / drw_w) & 0xFF; + width /= 2; + vid_pitch /= 2; + cpr00 |= 0x00010000; + } + else if (vid_w / 4 <= drw_w) + { + xscale = (64 * vid_w / drw_w) & 0xFF; + width /= 4; + vid_pitch /= 4; + cpr00 |= 0x00020000; + } + else + { + xscale = 0; + width /= 4; + vid_pitch /= 4; + cpr00 |= 0x00020000; + } + + if (vid_h <= drw_h) + { + yscale = (256 * vid_h / drw_h) & 0xFF; + } + else if (vid_h / 2 <= drw_h) + { + yscale = (128 * vid_h / drw_h) & 0xFF; + height /= 2; + cpr00 |= 0x00040000; + } + else if (vid_h / 4 <= drw_h) + { + yscale = (64 * vid_h / drw_h) & 0xFF; + height /= 4; + cpr00 |= 0x00080000; + } + else + { + yscale = 0; + height /= 4; + cpr00 |= 0x00080000; + } + + do + { + areaHeight = (vid_pitch * height + fbPitch - 1) / fbPitch; + DEBUG((VERBLEV, "SMI_AllocateMemory: vid_pitch=%d height=%d fbPitch=%d areaHeight=%d\n", + vid_pitch, height, fbPitch, areaHeight)); + pPort->area = SMI_AllocateMemory(pScrn, pPort->area, areaHeight); + if (pPort->area == NULL) + { + if ((cpr00 & 0x000C0000) == 0) + { + /* height -> 1/2 height */ + yscale = (128 * vid_h / drw_h) & 0xFF; + height = vid_h / 2; + cpr00 |= 0x00040000; + } + else if (cpr00 & 0x00040000) + { + /* 1/2 height -> 1/4 height */ + yscale = (64 * vid_h / drw_h) & 0xFF; + height = vid_h / 4; + cpr00 ^= 0x000C0000; + } + else + { + /* 1/4 height */ + if ((cpr00 & 0x00030000) == 0) + { + /* width -> 1/2 width */ + xscale = (128 * vid_w / drw_w) & 0xFF; + width = vid_w / 2; + cpr00 |= 0x00010000; + } + else if (cpr00 & 0x00010000) + { + /* 1/2 width -> 1/4 width */ + xscale = (64 * vid_w / drw_w) & 0xFF; + width = vid_w / 4; + cpr00 ^= 0x00030000; + } + else + { + DEBUG((VERBLEV, "allocate error\n")); + LEAVE_PROC("SMI_PutVideo"); + return(BadAlloc); + } + } + } + } + while (pPort->area == NULL); + + DEBUG((VERBLEV, "xscale==%d yscale=%d width=%d height=%d\n", + xscale, yscale, width, height)); + + /* aaa whats this ----------------------v ? + vid_address = (pPort->area->box.y1 * fbPitch) + ((y1 >> 16) * vid_pitch);*/ + vid_address = (pPort->area->box.y1 * fbPitch); + + DEBUG((VERBLEV, "test RegionsEqual\n")); + if (!RegionsEqual(&pPort->clip, clipBoxes)) + { + DEBUG((VERBLEV, "RegionCopy\n")); + REGION_COPY(pScreen, &pPort->clip, clipBoxes); +#if USE_XAA + XAAFillSolidRects(pScrn, pPort->Attribute[XV_COLORKEY], GXcopy, ~0, + REGION_NUM_RECTS(clipBoxes), REGION_RECTS(clipBoxes)); +#else + DEBUG((VERBLEV, "FillKey\n")); + xf86XVFillKeyHelper(pScrn->pScreen, pPort->Attribute[XV_COLORKEY], clipBoxes); +#endif + + } + + left = x1 >> 16; + top = y1 >> 16; + width = (x2 - x1) >> 16; + height = (y2 - y1) >> 16; + + OUT_SEQ(pSmi, 0x21, IN_SEQ(pSmi, 0x21) & ~0x04); + WRITE_VPR(pSmi, 0x54, READ_VPR(pSmi, 0x54) | 0x00200000); +#if 0 + SMI_WaitForSync(pScrn); +#endif + /* Video Window I Left and Top Boundaries */ + WRITE_VPR(pSmi, 0x14, dstBox.x1 + (dstBox.y1 << 16)); + /* Video Window I Right and Bottom Boundaries */ + WRITE_VPR(pSmi, 0x18, dstBox.x2 + (dstBox.y2 << 16)); + /* Video Window I Source Width and Offset */ + WRITE_VPR(pSmi, 0x20, (vid_pitch / 8) + ((vid_pitch / 8) << 16)); + /* Video Window I Stretch Factor */ + WRITE_VPR(pSmi, 0x24, (xscale << 8) + yscale); + + if (pPort->Attribute[XV_INTERLACED]) { + /* Video Window II Left and Top Boundaries */ + WRITE_VPR(pSmi, 0x28, dstBox.x1 + (dstBox.y1 << 16)); + /* Video Window II Right and Bottom Boundaries */ + WRITE_VPR(pSmi, 0x2C, dstBox.x2 + (dstBox.y2 << 16)); + /* Video Window II Source Width and Offset */ + WRITE_VPR(pSmi, 0x34, (vid_pitch / 8) + ((vid_pitch / 8) << 16)); + /* Video Window II Stretch Factor */ + WRITE_VPR(pSmi, 0x38, (xscale << 8) + yscale); + + /* Video Window I Source Start Address */ + WRITE_VPR(pSmi, 0x1C, vid_address / 8); + /* Video Window II Source Start Address */ + WRITE_VPR(pSmi, 0x30, vid_address / 8); + + /* Video Window I Source Start Address */ + WRITE_VPR(pSmi, 0x48, vid_address / 8); + /* Video Window II Source Start Address */ + WRITE_VPR(pSmi, 0x4C, vid_address / 8 + vid_pitch / 8); + + /* Video Source Clipping Control */ + WRITE_CPR(pSmi, 0x04, left + ((top/2) << 16)); + /* Video Source Capture Size Control */ + WRITE_CPR(pSmi, 0x08, width + ((height/2) << 16)); + /* Capture Port Buffer I Source Start Address */ + WRITE_CPR(pSmi, 0x0C, vid_address / 8); + /* Capture Port Buffer II Source Start Address */ + WRITE_CPR(pSmi, 0x10, vid_address / 8 + vid_pitch / 8); + /* Capture Port Source Offset Address */ + WRITE_CPR(pSmi, 0x14, 2*(vid_pitch / 8) + ((2*(vid_pitch / 8)) << 16)); + } + else { + /* Video Source Clipping Control */ + WRITE_CPR(pSmi, 0x04, left + (top << 16)); + /* Video Source Capture Size Control */ + WRITE_CPR(pSmi, 0x08, width + (height << 16)); + /* Capture Port Buffer I Source Start Address */ + WRITE_CPR(pSmi, 0x0C, vid_address / 8); + /* Capture Port Buffer II Source Start Address */ + WRITE_CPR(pSmi, 0x10, vid_address / 8); + /* Capture Port Source Offset Address */ + WRITE_CPR(pSmi, 0x14, (vid_pitch / 8) + ((vid_pitch / 8) << 16)); + } + + WRITE_CPR(pSmi, 0x00, cpr00); + WRITE_VPR(pSmi, 0x00, vpr00); + + pPort->videoStatus = CLIENT_VIDEO_ON; + DEBUG((VERBLEV, "SMI_PutVideo success\n")); + LEAVE_PROC("SMI_PutVideo"); + return(Success); +} +#endif + + +static void +SMI_StopVideo( + ScrnInfoPtr pScrn, + pointer data, + Bool shutdown +) +{ + SMI_PortPtr pPort = (SMI_PortPtr) data; + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_StopVideo"); + + REGION_EMPTY(pScrn->pScreen, &pPort->clip); + + if (shutdown) + { + if (pPort->videoStatus & CLIENT_VIDEO_ON) + { + WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x01000008); +#if SMI_USE_CAPTURE + WRITE_CPR(pSmi, 0x00, READ_CPR(pSmi, 0x00) & ~0x00000001); + WRITE_VPR(pSmi, 0x54, READ_VPR(pSmi, 0x54) & ~0x00F00000); +/* #864 OUT_SEQ(pSmi, 0x21, IN_SEQ(pSmi, 0x21) | 0x04); */ +#endif + } + if (pPort->area != NULL) + { + xf86FreeOffscreenArea(pPort->area); + pPort->area = NULL; + } + pPort->videoStatus = 0; + /* pPort->i2cDevice = 0;aaa*/ + } + else + { + if (pPort->videoStatus & CLIENT_VIDEO_ON) + { + pPort->videoStatus |= OFF_TIMER; + pPort->offTime = currentTime.milliseconds + OFF_DELAY; + } + } + + LEAVE_PROC("SMI_StopVideo"); +} + + +static int +SMI_SetPortAttribute( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 value, + pointer data +) +{ + int res; + SMI_PortPtr pPort = (SMI_PortPtr) data; + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_SetPortAttribute"); + + if (attribute == xvColorKey) { + int r, g, b; + + pPort->Attribute[XV_COLORKEY] = value; + switch (pScrn->depth) + { + case 8: + WRITE_VPR(pSmi, 0x04, value & 0x00FF); + break; + + case 15: + case 16: + WRITE_VPR(pSmi, 0x04, value & 0xFFFF); + break; + + default: + r = (value & pScrn->mask.red) >> pScrn->offset.red; + g = (value & pScrn->mask.green) >> pScrn->offset.green; + b = (value & pScrn->mask.blue) >> pScrn->offset.blue; + WRITE_VPR(pSmi, 0x04, + ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)); + break; + } + res = Success; + } + else if (attribute == xvInterlaced) { + pPort->Attribute[XV_INTERLACED] = (value != 0); + res = Success; + } + else if (attribute == xvEncoding) { + res = SetAttr(pScrn, XV_ENCODING, value); + } + else if (attribute == xvBrightness) { + res = SetAttr(pScrn, XV_BRIGHTNESS, value); + } + else if (attribute == xvCapBrightness) { + res = SetAttr(pScrn, XV_CAPTURE_BRIGHTNESS, value); + } + else if (attribute == xvContrast) { + res = SetAttr(pScrn, XV_CONTRAST, value); + } + else if (attribute == xvSaturation) { + res = SetAttr(pScrn, XV_SATURATION, value); + } + else if (attribute == xvHue) { + res = SetAttr(pScrn, XV_HUE, value); + } + else { + res = BadMatch; + } + + LEAVE_PROC("SMI_SetPortAttribute"); + return(res); +} + + +static int +SMI_GetPortAttribute( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 *value, + pointer data +) +{ + SMI_PortPtr pPort = (SMI_PortPtr) data; + + ENTER_PROC("SMI_GetPortAttribute"); + if (attribute == xvEncoding) + *value = pPort->Attribute[XV_ENCODING]; + else if (attribute == xvBrightness) + *value = pPort->Attribute[XV_BRIGHTNESS]; + else if (attribute == xvCapBrightness) + *value = pPort->Attribute[XV_CAPTURE_BRIGHTNESS]; + else if (attribute == xvContrast) + *value = pPort->Attribute[XV_CONTRAST]; + else if (attribute == xvSaturation) + *value = pPort->Attribute[XV_SATURATION]; + else if (attribute == xvHue) + *value = pPort->Attribute[XV_HUE]; + else if (attribute == xvColorKey) + *value = pPort->Attribute[XV_COLORKEY]; + + else + { + LEAVE_PROC("SMI_GetPortAttribute"); + return(BadMatch); + } + + LEAVE_PROC("SMI_GetPortAttribute"); + return(Success); +} + + +static void +SMI_QueryBestSize( + ScrnInfoPtr pScrn, + Bool motion, + short vid_w, + short vid_h, + short drw_w, + short drw_h, + unsigned int *p_w, + unsigned int *p_h, + pointer data +) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + ENTER_PROC("SMI_QueryBestSize"); + + *p_w = min(drw_w, pSmi->lcdWidth); + *p_h = min(drw_h, pSmi->lcdHeight); + + LEAVE_PROC("SMI_QueryBestSize"); +} + + +static int +SMI_PutImage( + ScrnInfoPtr pScrn, + short src_x, + short src_y, + short drw_x, + short drw_y, + short src_w, + short src_h, + short drw_w, + short drw_h, + int id, + unsigned char *buf, + short width, + short height, + Bool sync, + RegionPtr clipBoxes, + pointer data +) +{ + SMIPtr pSmi = SMIPTR(pScrn); + SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr; + INT32 x1, y1, x2, y2; + int bpp = 0; + int fbPitch, srcPitch, srcPitch2 = 0, dstPitch, areaHeight; + BoxRec dstBox; + CARD32 offset, offset2 = 0, offset3 = 0, tmp; + int left, top, nPixels, nLines; + unsigned char *dstStart; + + ENTER_PROC("SMI_PutImage"); + + x1 = src_x; + y1 = src_y; + x2 = src_x + src_w; + y2 = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.y1 = drw_y; + dstBox.x2 = drw_x + drw_w; + dstBox.y2 = drw_y + drw_h; + + if (!SMI_ClipVideo(pScrn, &dstBox, &x1, &y1, &x2, &y2, clipBoxes, width, + height)) + { + LEAVE_PROC("SMI_PutImage"); + return(Success); + } + + dstBox.x1 -= pScrn->frameX0; + dstBox.y1 -= pScrn->frameY0; + dstBox.x2 -= pScrn->frameX0; + dstBox.y2 -= pScrn->frameY0; + + if (pSmi->Bpp == 3) + { + fbPitch = pSmi->Stride; + } + else + { + fbPitch = pSmi->Stride * pSmi->Bpp; + } + + switch (id) + { + case FOURCC_YV12: + srcPitch = (width + 3) & ~3; + offset2 = srcPitch * height; + srcPitch2 = ((width >> 1) + 3) & ~3; + offset3 = offset2 + (srcPitch2 * (height >> 1)); + dstPitch = ((width << 1) + 15) & ~15; + break; + + case FOURCC_I420: + srcPitch = (width + 3) & ~3; + offset3 = srcPitch * height; + srcPitch2 = ((width >> 1) + 3) & ~3; + offset2 = offset3 + (srcPitch2 * (height >> 1)); + dstPitch = ((width << 1) + 15) & ~15; + break; + + case FOURCC_RV24: + bpp = 3; + srcPitch = width * bpp; + dstPitch = (srcPitch + 15) & ~15; + break; + + case FOURCC_RV32: + bpp = 4; + srcPitch = width * bpp; + dstPitch = (srcPitch + 15) & ~15; + break; + + case FOURCC_YUY2: + case FOURCC_RV15: + case FOURCC_RV16: + default: + bpp = 2; + srcPitch = width * bpp; + dstPitch = (srcPitch + 15) & ~15; + break; + } + + areaHeight = ((dstPitch * height) + fbPitch - 1) / fbPitch; + pPort->area = SMI_AllocateMemory(pScrn, pPort->area, areaHeight); + if (pPort->area == NULL) + { + LEAVE_PROC("SMI_PutImage"); + return(BadAlloc); + } + + top = y1 >> 16; + left = (x1 >> 16) & ~1; + nPixels = ((((x2 + 0xFFFF) >> 16) + 1) & ~1) - left; + left *= bpp; + + offset = (pPort->area->box.y1 * fbPitch) + (top * dstPitch); + dstStart = pSmi->FBBase + offset + left; + + switch (id) + { + case FOURCC_YV12: + case FOURCC_I420: + top &= ~1; + tmp = ((top >> 1) * srcPitch2) + (left >> 2); + offset2 += tmp; + offset3 += tmp; + nLines = ((((y2 + 0xFFFF) >> 16) + 1) & ~1) - top; + SMI_CopyYV12Data(buf + (top * srcPitch) + (left >> 1), + buf + offset2, buf + offset3, dstStart, srcPitch, srcPitch2, + dstPitch, nLines, nPixels); + break; + + default: + buf += (top * srcPitch) + left; + nLines = ((y2 + 0xFFFF) >> 16) - top; + SMI_CopyData(buf, dstStart, srcPitch, dstPitch, nLines, + nPixels * bpp); + break; + } + + if (!RegionsEqual(&pPort->clip, clipBoxes)) + { + REGION_COPY(pScreen, &pPort->clip, clipBoxes); +#if USE_XAA + XAAFillSolidRects(pScrn, pPort->Attribute[XV_COLORKEY], GXcopy, ~0, + REGION_NUM_RECTS(clipBoxes), REGION_RECTS(clipBoxes)); +#else + /*aaa*/ + return(BadAlloc); +#endif + } + + SMI_DisplayVideo(pScrn, id, offset, width, height, dstPitch, x1, y1, x2, y2, + &dstBox, src_w, src_h, drw_w, drw_h); + + pPort->videoStatus = CLIENT_VIDEO_ON; + LEAVE_PROC("SMI_PutImage"); + return(Success); + +} + + +static int +SMI_QueryImageAttributes( + ScrnInfoPtr pScrn, + int id, + unsigned short *width, + unsigned short *height, + int *pitches, + int *offsets +) +{ + SMIPtr pSmi = SMIPTR(pScrn); + int size, tmp; + + ENTER_PROC("SMI_QueryImageAttributes"); + + if (*width > pSmi->lcdWidth) + { + *width = pSmi->lcdWidth; + } + if (*height > pSmi->lcdHeight) + { + *height = pSmi->lcdHeight; + } + + *width = (*width + 1) & ~1; + if (offsets != NULL) + { + offsets[0] = 0; + } + + switch (id) + { + case FOURCC_YV12: + case FOURCC_I420: + *height = (*height + 1) & ~1; + size = (*width + 3) & ~3; + if (pitches != NULL) + { + pitches[0] = size; + } + size *= *height; + if (offsets != NULL) + { + offsets[1] = size; + } + tmp = ((*width >> 1) + 3) & ~3; + if (pitches != NULL) + { + pitches[1] = pitches[2] = tmp; + } + tmp *= (*height >> 1); + size += tmp; + if (offsets != NULL) + { + offsets[2] = size; + } + size += tmp; + break; + + case FOURCC_YUY2: + case FOURCC_RV15: + case FOURCC_RV16: + default: + size = *width * 2; + if (pitches != NULL) + { + pitches[0] = size; + } + size *= *height; + break; + + case FOURCC_RV24: + size = *width * 3; + if (pitches != NULL) + { + pitches[0] = size; + } + size *= *height; + break; + + case FOURCC_RV32: + size = *width * 4; + if (pitches != NULL) + { + pitches[0] = size; + } + size *= *height; + break; + } + + LEAVE_PROC("SMI_QueryImageAttributes"); + return(size); +} + + +/******************************************************************************\ +** ** +** S U P P O R T F U N C T I O N S ** +** ** +\******************************************************************************/ +#if 0 +static void +SMI_WaitForSync( + ScrnInfoPtr pScrn +) +{ + SMIPtr pSmi = SMIPTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + int vgaIOBase = hwp->IOBase; + int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET; + int vgaCRData = vgaIOBase + VGA_CRTC_DATA_OFFSET; + + VerticalRetraceWait(); +} +#endif + +static Bool +RegionsEqual( + RegionPtr A, + RegionPtr B +) +{ + int *dataA, *dataB; + int num; + + ENTER_PROC("RegionsEqual"); + + num = REGION_NUM_RECTS(A); + if (num != REGION_NUM_RECTS(B)) + { + LEAVE_PROC("RegionsEqual"); + return(FALSE); + } + + if ( (A->extents.x1 != B->extents.x1) + || (A->extents.y1 != B->extents.y1) + || (A->extents.x2 != B->extents.x2) + || (A->extents.y2 != B->extents.y2) + ) + { + LEAVE_PROC("RegionsEqual"); + return(FALSE); + } + + dataA = (int*) REGION_RECTS(A); + dataB = (int*) REGION_RECTS(B); + + while (num--) + { + if ((dataA[0] != dataB[0]) || (dataA[1] != dataB[1])) + { + return(FALSE); + } + dataA += 2; + dataB += 2; + } + + LEAVE_PROC("RegionsEqual"); + return(TRUE); +} + +static Bool +SMI_ClipVideo( + ScrnInfoPtr pScrn, + BoxPtr dst, + INT32 *x1, + INT32 *y1, + INT32 *x2, + INT32 *y2, + RegionPtr reg, + INT32 width, + INT32 height +) +{ + INT32 vscale, hscale; + BoxPtr extents = REGION_EXTENTS(pScrn, reg); + int diff; + + ENTER_PROC("SMI_ClipVideo"); + + DEBUG((VERBLEV, "ClipVideo(%d): x1=%d y1=%d x2=%d y2=%d\n", __LINE__, *x1 >> 16, *y1 >> 16, *x2 >> 16, *y2 >> 16)); + /* PDR#941 */ + extents->x1 = max(extents->x1, pScrn->frameX0); + extents->y1 = max(extents->y1, pScrn->frameY0); + + hscale = ((*x2 - *x1) << 16) / (dst->x2 - dst->x1); + vscale = ((*y2 - *y1) << 16) / (dst->y2 - dst->y1); + + *x1 <<= 16; *y1 <<= 16; + *x2 <<= 16; *y2 <<= 16; + + DEBUG((VERBLEV, "ClipVideo(%d): x1=%d y1=%d x2=%d y2=%d\n", __LINE__, *x1 >> 16, *y1 >> 16, *x2 >> 16, *y2 >> 16)); + + diff = extents->x1 - dst->x1; + if (diff > 0) + { + dst->x1 = extents->x1; + *x1 += diff * hscale; + } + + diff = extents->y1 - dst->y1; + if (diff > 0) + { + dst->y1 = extents->y1; + *y1 += diff * vscale; + } + + diff = dst->x2 - extents->x2; + if (diff > 0) + { + dst->x2 = extents->x2; /* PDR#687 */ + *x2 -= diff * hscale; + } + + diff = dst->y2 - extents->y2; + if (diff > 0) + { + dst->y2 = extents->y2; + *y2 -= diff * vscale; + } + + DEBUG((VERBLEV, "ClipVideo(%d): x1=%d y1=%d x2=%d y2=%d\n", __LINE__, *x1 >> 16, *y1 >> 16, *x2 >> 16, *y2 >> 16)); + + if (*x1 < 0) + { + diff = (-*x1 + hscale - 1) / hscale; + dst->x1 += diff; + *x1 += diff * hscale; + } + + if (*y1 < 0) + { + diff = (-*y1 + vscale - 1) / vscale; + dst->y1 += diff; + *y1 += diff * vscale; + } + + DEBUG((VERBLEV, "ClipVideo(%d): x1=%d y1=%d x2=%d y2=%d\n", __LINE__, *x1 >> 16, *y1 >> 16, *x2 >> 16, *y2 >> 16)); + +#if 0 /* aaa was macht dieser code? */ + delta = *x2 - (width << 16); + if (delta > 0) + { + diff = (delta + hscale - 1) / hscale; + dst->x2 -= diff; + *x2 -= diff * hscale; + } + + delta = *y2 - (height << 16); + if (delta > 0) + { + diff = (delta + vscale - 1) / vscale; + dst->y2 -= diff; + *y2 -= diff * vscale; + } +#endif + + DEBUG((VERBLEV, "ClipVideo(%d): x1=%d y1=%d x2=%d y2=%d\n", __LINE__, *x1 >> 16, *y1 >> 16, *x2 >> 16, *y2 >> 16)); + + if ((*x1 >= *x2) || (*y1 >= *y2)) + { + LEAVE_PROC("SMI_ClipVideo"); + return(FALSE); + } + + if ( (dst->x1 != extents->x1) || (dst->y1 != extents->y1) + || (dst->x2 != extents->x2) || (dst->y2 != extents->y2) + ) + { + RegionRec clipReg; + REGION_INIT(pScrn, &clipReg, dst, 1); + REGION_INTERSECT(pScrn, reg, reg, &clipReg); + REGION_UNINIT(pScrn, &clipReg); + } + + DEBUG((VERBLEV, "ClipVideo(%d): x1=%d y1=%d x2=%d y2=%d\n", __LINE__, *x1 >> 16, *y1 >> 16, *x2 >> 16, *y2 >> 16)); + + LEAVE_PROC("SMI_ClipVideo"); + return(TRUE); +} + +static void +SMI_DisplayVideo( + ScrnInfoPtr pScrn, + int id, + int offset, + short width, + short height, + int pitch, + int x1, + int y1, + int x2, + int y2, + BoxPtr dstBox, + short vid_w, + short vid_h, + short drw_w, + short drw_h +) +{ + SMIPtr pSmi = SMIPTR(pScrn); + CARD32 vpr00; + int hstretch, vstretch; + + ENTER_PROC("SMI_DisplayVideo"); + + vpr00 = READ_VPR(pSmi, 0x00) & ~0x0CB800FF; + + switch (id) + { + case FOURCC_YV12: + case FOURCC_I420: + case FOURCC_YUY2: + vpr00 |= 0x6; + break; + + case FOURCC_RV15: + vpr00 |= 0x1; + break; + + case FOURCC_RV16: + vpr00 |= 0x2; + break; + + case FOURCC_RV24: + vpr00 |= 0x4; + break; + + case FOURCC_RV32: + vpr00 |= 0x3; + break; + } + + + if (drw_w > vid_w) + { + hstretch = (2560 * vid_w / drw_w + 5) / 10; + } + else + { + hstretch = 0; + } + + if (drw_h > vid_h) + { + vstretch = (2560 * vid_h / drw_h + 5) / 10; + vpr00 |= 1 << 21; + } + else + { + vstretch = 0; + } +#if 0 + SMI_WaitForSync(pScrn); +#endif + WRITE_VPR(pSmi, 0x00, vpr00 | (1 << 3) | (1 << 20)); + WRITE_VPR(pSmi, 0x14, (dstBox->x1) | (dstBox->y1 << 16)); + WRITE_VPR(pSmi, 0x18, (dstBox->x2) | (dstBox->y2 << 16)); + WRITE_VPR(pSmi, 0x1C, offset >> 3); + WRITE_VPR(pSmi, 0x20, (pitch >> 3) | ((pitch >> 3) << 16)); + WRITE_VPR(pSmi, 0x24, (hstretch << 8) | vstretch); + + LEAVE_PROC("SMI_DisplayVideo"); +} + +static void +SMI_BlockHandler( + int i, + pointer blockData, + pointer pTimeout, + pointer pReadMask +) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + ScrnInfoPtr pScrn = xf86Screens[i]; + SMIPtr pSmi = SMIPTR(pScrn); + SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr; + + pScreen->BlockHandler = pSmi->BlockHandler; + (*pScreen->BlockHandler)(i, blockData, pTimeout, pReadMask); + pScreen->BlockHandler = SMI_BlockHandler; + + if (pPort->videoStatus & TIMER_MASK) + { + UpdateCurrentTime(); + if (pPort->videoStatus & OFF_TIMER) + { + if (pPort->offTime < currentTime.milliseconds) + { + WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x00000008); + pPort->videoStatus = FREE_TIMER; + pPort->freeTime = currentTime.milliseconds + FREE_DELAY; + } + } + else + { + if (pPort->freeTime < currentTime.milliseconds) + { + xf86FreeOffscreenArea(pPort->area); + pPort->area = NULL; + } + pPort->videoStatus = 0; + } + } +} + +#if 0 +static int +SMI_SendI2C( + ScrnInfoPtr pScrn, + CARD8 device, + char *devName, + SMI_I2CDataPtr i2cData +) +{ + SMIPtr pSmi = SMIPTR(pScrn); + I2CDevPtr dev; + int status = Success; + + ENTER_PROC("SMI_SendI2C"); + + if (pSmi->I2C == NULL) + { + LEAVE_PROC("SMI_SendI2C"); + return(BadAlloc); + } + + dev = xf86CreateI2CDevRec(); + if (dev == NULL) + { + LEAVE_PROC("SMI_SendI2C"); + return(BadAlloc); + } + dev->DevName = devName; + dev->SlaveAddr = device; + dev->pI2CBus = pSmi->I2C; + + if (!xf86I2CDevInit(dev)) + { + status = BadAlloc; + } + else + { + while (i2cData->address != 0xFF || i2cData->data != 0xFF) /* PDR#676 */ + { + if (!xf86I2CWriteByte(dev, i2cData->address, i2cData->data)) + { + status = BadAlloc; + break; + } + i2cData++; + } + } + + xf86DestroyI2CDevRec(dev, TRUE); + LEAVE_PROC("SMI_SendI2C"); + return(status); +} +#endif + +/******************************************************************************\ +** ** +** O F F S C R E E N M E M O R Y M A N A G E R ** +** ** +\******************************************************************************/ + +static void +SMI_InitOffscreenImages( + ScreenPtr pScreen +) +{ + XF86OffscreenImagePtr offscreenImages; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + SMIPtr pSmi = SMIPTR(pScrn); + SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr; + + ENTER_PROC("SMI_InitOffscreenImages"); + + offscreenImages = xalloc(sizeof(XF86OffscreenImageRec)); + if (offscreenImages == NULL) + { + LEAVE_PROC("SMI_InitOffscreenImages"); + return; + } + + offscreenImages->image = SMI_VideoImages; + offscreenImages->flags = VIDEO_OVERLAID_IMAGES + | VIDEO_CLIP_TO_VIEWPORT; + offscreenImages->alloc_surface = SMI_AllocSurface; + offscreenImages->free_surface = SMI_FreeSurface; + offscreenImages->display = SMI_DisplaySurface; + offscreenImages->stop = SMI_StopSurface; + offscreenImages->getAttribute = SMI_GetSurfaceAttribute; + offscreenImages->setAttribute = SMI_SetSurfaceAttribute; + offscreenImages->max_width = pSmi->lcdWidth; + offscreenImages->max_height = pSmi->lcdHeight; + if (!pPort->I2CDev.SlaveAddr) { + offscreenImages->num_attributes = nElems(SMI_VideoAttributes); + offscreenImages->attributes = SMI_VideoAttributes; + } else { + offscreenImages->num_attributes = + nElems(SMI_VideoAttributesSAA711x); + offscreenImages->attributes = SMI_VideoAttributesSAA711x; + } + xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1); + + LEAVE_PROC("SMI_InitOffscreenImages"); +} + +static FBAreaPtr +SMI_AllocateMemory( + ScrnInfoPtr pScrn, + FBAreaPtr area, + int numLines +) +{ + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + + ENTER_PROC("SMI_AllocateMemory"); + + if (area != NULL) + { + if ((area->box.y2 - area->box.y1) >= numLines) + { + LEAVE_PROC("SMI_AllocateMemory (area->box.y2 - area->box.y1) >= numLines ok"); + return(area); + } + + if (xf86ResizeOffscreenArea(area, pScrn->displayWidth, numLines)) + { + LEAVE_PROC("SMI_AllocateMemory xf86ResizeOffscreenArea ok"); + return(area); + } + + xf86FreeOffscreenArea(area); + } + + area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth, numLines, 0, + NULL, NULL, NULL); + + if (area == NULL) + { + int maxW, maxH; + + xf86QueryLargestOffscreenArea(pScreen, &maxW, &maxH, 0, + FAVOR_WIDTH_THEN_AREA, PRIORITY_EXTREME); + + DEBUG((VERBLEV, "QueryLargestOffscreenArea maxW=%d maxH=%d displayWidth=%d numlines=%d\n", + maxW, maxH, pScrn->displayWidth, numLines)); + if ((maxW < pScrn->displayWidth) || (maxH < numLines)) + { + LEAVE_PROC("SMI_AllocateMemory (maxW < pScrn->displayWidth) || (maxH < numLines)"); + return(NULL); + } + + xf86PurgeUnlockedOffscreenAreas(pScreen); + area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth, numLines, + 0, NULL, NULL, NULL); + } + + DEBUG((VERBLEV, "area = %p\n", area)); + LEAVE_PROC("SMI_AllocateMemory"); + return(area); +} + +static void +SMI_CopyData( + unsigned char *src, + unsigned char *dst, + int srcPitch, + int dstPitch, + int height, + int width +) +{ + ENTER_PROC("SMI_CopyData"); + + while (height-- > 0) + { + memcpy(dst, src, width); + src += srcPitch; + dst += dstPitch; + } + + LEAVE_PROC("SMI_CopyData"); +} + +static void +SMI_CopyYV12Data( + unsigned char *src1, + unsigned char *src2, + unsigned char *src3, + unsigned char *dst, + int srcPitch1, + int srcPitch2, + int dstPitch, + int height, + int width +) +{ + CARD32 *pDst = (CARD32 *) dst; + int i, j; + + ENTER_PROC("SMI_CopyYV12Data"); + + for (j = 0; j < height; j++) + { + for (i =0; i < width; i++) + { + pDst[i] = src1[i << 1] | (src1[(i << 1) + 1] << 16) | + (src3[i] << 8) | (src2[i] << 24); + } + pDst += dstPitch >> 2; + src1 += srcPitch1; + if (j & 1) + { + src2 += srcPitch2; + src3 += srcPitch2; + } + } + + LEAVE_PROC("SMI_CopyYV12Data"); +} + +static int +SMI_AllocSurface( + ScrnInfoPtr pScrn, + int id, + unsigned short width, + unsigned short height, + XF86SurfacePtr surface +) +{ + SMIPtr pSmi = SMIPTR(pScrn); + int numLines, pitch, fbPitch, bpp; + SMI_OffscreenPtr ptrOffscreen; + FBAreaPtr area; + + ENTER_PROC("SMI_AllocSurface"); + + if ((width > pSmi->lcdWidth) || (height > pSmi->lcdHeight)) + { + LEAVE_PROC("SMI_AllocSurface"); + return(BadAlloc); + } + + if (pSmi->Bpp == 3) + { + fbPitch = pSmi->Stride; + } + else + { + fbPitch = pSmi->Stride * pSmi->Bpp; + } + + width = (width + 1) & ~1; + switch (id) + { + case FOURCC_YV12: + case FOURCC_I420: + case FOURCC_YUY2: + case FOURCC_RV15: + case FOURCC_RV16: + bpp = 2; + break; + + case FOURCC_RV24: + bpp = 3; + break; + + case FOURCC_RV32: + bpp = 4; + break; + + default: + LEAVE_PROC("SMI_AllocSurface"); + return(BadAlloc); + } + pitch = (width * bpp + 15) & ~15; + + numLines = ((height * pitch) + fbPitch - 1) / fbPitch; + + area = SMI_AllocateMemory(pScrn, NULL, numLines); + if (area == NULL) + { + LEAVE_PROC("SMI_AllocSurface"); + return(BadAlloc); + } + + surface->pitches = xalloc(sizeof(int)); + if (surface->pitches == NULL) + { + xf86FreeOffscreenArea(area); + LEAVE_PROC("SMI_AllocSurface"); + return(BadAlloc); + } + surface->offsets = xalloc(sizeof(int)); + if (surface->offsets == NULL) + { + xfree(surface->pitches); + xf86FreeOffscreenArea(area); + LEAVE_PROC("SMI_AllocSurface"); + return(BadAlloc); + } + + ptrOffscreen = xalloc(sizeof(SMI_OffscreenRec)); + if (ptrOffscreen == NULL) + { + xfree(surface->offsets); + xfree(surface->pitches); + xf86FreeOffscreenArea(area); + LEAVE_PROC("SMI_AllocSurface"); + return(BadAlloc); + } + + surface->pScrn = pScrn; + surface->id = id; + surface->width = width; + surface->height = height; + surface->pitches[0] = pitch; + surface->offsets[0] = area->box.y1 * fbPitch; + surface->devPrivate.ptr = (pointer) ptrOffscreen; + + ptrOffscreen->area = area; + ptrOffscreen->isOn = FALSE; + + LEAVE_PROC("SMI_AllocSurface"); + return(Success); +} + +static int +SMI_FreeSurface( + XF86SurfacePtr surface +) +{ + SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr; + + ENTER_PROC("SMI_FreeSurface"); + + if (ptrOffscreen->isOn) + { + SMI_StopSurface(surface); + } + + xf86FreeOffscreenArea(ptrOffscreen->area); + xfree(surface->pitches); + xfree(surface->offsets); + xfree(surface->devPrivate.ptr); + + LEAVE_PROC("SMI_FreeSurface"); + return(Success); +} + +static int +SMI_DisplaySurface( + XF86SurfacePtr surface, + short vid_x, + short vid_y, + short drw_x, + short drw_y, + short vid_w, + short vid_h, + short drw_w, + short drw_h, + RegionPtr clipBoxes +) +{ + SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr; + SMIPtr pSmi = SMIPTR(surface->pScrn); + SMI_PortPtr pPort = pSmi->ptrAdaptor->pPortPrivates[0].ptr; + INT32 x1, y1, x2, y2; + BoxRec dstBox; + + ENTER_PROC("SMI_DisplaySurface"); + + x1 = vid_x; + x2 = vid_x + vid_w; + y1 = vid_y; + y2 = vid_y + vid_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + if (!SMI_ClipVideo(surface->pScrn, &dstBox, &x1, &y1, &x2, &y2, clipBoxes, + surface->width, surface->height)) + { + LEAVE_PROC("SMI_DisplaySurface"); + return(Success); + } + + dstBox.x1 -= surface->pScrn->frameX0; + dstBox.y1 -= surface->pScrn->frameY0; + dstBox.x2 -= surface->pScrn->frameX0; + dstBox.y2 -= surface->pScrn->frameY0; + +#if USE_XAA + XAAFillSolidRects(surface->pScrn, pPort->Attribute[XV_COLORKEY], GXcopy, ~0, + REGION_NUM_RECTS(clipBoxes), REGION_RECTS(clipBoxes)); +#else + /*aaa*/ + return(BadAlloc); +#endif + + SMI_ResetVideo(surface->pScrn); + SMI_DisplayVideo(surface->pScrn, surface->id, surface->offsets[0], + surface->width, surface->height, surface->pitches[0], x1, y1, x2, + y2, &dstBox, vid_w, vid_h, drw_w, drw_h); + + ptrOffscreen->isOn = TRUE; + if (pPort->videoStatus & CLIENT_VIDEO_ON) + { + REGION_EMPTY(pScrn->pScreen, &pPort->clip); + UpdateCurrentTime(); + pPort->videoStatus = FREE_TIMER; + pPort->freeTime = currentTime.milliseconds + FREE_DELAY; + } + + LEAVE_PROC("SMI_DisplaySurface"); + return(Success); +} + +static int +SMI_StopSurface( + XF86SurfacePtr surface +) +{ + SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr; + + ENTER_PROC("SMI_StopSurface"); + + if (ptrOffscreen->isOn) + { + SMIPtr pSmi = SMIPTR(surface->pScrn); + WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x00000008); + ptrOffscreen->isOn = FALSE; + } + + LEAVE_PROC("SMI_StopSurface"); + return(Success); +} + +static int +SMI_GetSurfaceAttribute( + ScrnInfoPtr pScrn, + Atom attr, + INT32 *value +) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + return(SMI_GetPortAttribute(pScrn, attr, value, + (pointer) pSmi->ptrAdaptor->pPortPrivates[0].ptr)); +} + +static int +SMI_SetSurfaceAttribute( + ScrnInfoPtr pScrn, + Atom attr, + INT32 value +) +{ + SMIPtr pSmi = SMIPTR(pScrn); + + return(SMI_SetPortAttribute(pScrn, attr, value, + (pointer) pSmi->ptrAdaptor->pPortPrivates[0].ptr)); +} +#else /* XvExtension */ +void SMI_InitVideo(ScreenPtr pScreen) {} +#endif diff --git a/src/smi_video.h b/src/smi_video.h new file mode 100644 index 0000000..b63e4bc --- /dev/null +++ b/src/smi_video.h @@ -0,0 +1,103 @@ +/* Header: //Mercury/Projects/archives/XFree86/4.0/smi_video.h.-arc 1.8 27 Nov 2000 15:46:06 Frido $ */ + +/* +Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. +Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of the XFree86 Project and +Silicon Motion shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without prior written +authorization from the XFree86 Project and silicon Motion. +*/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_video.h,v 1.4 2002/09/16 18:06:01 eich Exp $ */ + +#ifndef _SMI_VIDEO_H +#define _SMI_VIDEO_H + +#include "fourcc.h" + +#define SMI_VIDEO_VIDEO 0 +#define SMI_VIDEO_IMAGE 1 + +#define FOURCC_RV15 0x35315652 +#define FOURCC_RV16 0x36315652 +#define FOURCC_RV24 0x34325652 +#define FOURCC_RV32 0x32335652 + +#define OFF_DELAY 200 /* milliseconds */ +#define FREE_DELAY 60000 /* milliseconds */ + +#define OFF_TIMER 0x01 +#define FREE_TIMER 0x02 +#define CLIENT_VIDEO_ON 0x04 +#define TIMER_MASK (OFF_TIMER | FREE_TIMER) + +#define SAA7110 0x9C +#define SAA7111 0x48 + +/* + * Attributes + */ + +#define N_ATTRS 8 + +#define XV_ENCODING 0 +#define XV_BRIGHTNESS 1 +#define XV_CAPTURE_BRIGHTNESS 2 +#define XV_CONTRAST 3 +#define XV_SATURATION 4 +#define XV_HUE 5 +#define XV_COLORKEY 6 +#define XV_INTERLACED 7 + +typedef struct +{ + FBAreaPtr area; + RegionRec clip; + /* Attributes */ + CARD32 Attribute[N_ATTRS]; + CARD32 videoStatus; + Time offTime; + Time freeTime; + I2CDevRec I2CDev; + + /* Encodings */ + XF86VideoEncodingPtr enc; + int *input; + int *norm; + int *channel; + int nenc,cenc; +} SMI_PortRec, *SMI_PortPtr; + +typedef struct +{ + FBAreaPtr area; + Bool isOn; + +} SMI_OffscreenRec, *SMI_OffscreenPtr; + +typedef struct +{ + CARD8 address; + CARD8 data; + +} SMI_I2CDataRec, *SMI_I2CDataPtr; + +#endif /* _SMI_VIDEO_H */ |