home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Examples / DriverKit / QVision / QVision_reloc.tproj / QVisionSetMode.m < prev    next >
Text File  |  1996-03-26  |  16KB  |  639 lines

  1. /* Copyright (c) 1993-1996 by NeXT Software, Inc. as an unpublished work.
  2.  * All rights reserved.
  3.  *
  4.  * QVisionSetMode.m -- Mode support for the QVision.
  5.  *
  6.  * Author:  Derek B Clegg    21 May 1993
  7.  *    Based on work by Joe Pasqua.
  8.  * 16 Aug 1994 James C. Lee
  9.  *    Add 3.3 bus support & 8-bit color support.
  10.  * 09 Oct 1995 Rakesh Dubey
  11.  *    Added support for QV64P10.
  12.  */
  13.  
  14. #import <string.h>
  15. #import <driverkit/generalFuncs.h>
  16. #import <driverkit/i386/ioPorts.h>
  17. #import <driverkit/i386/directDevice.h>
  18. #import <driverkit/i386/IOPCIDeviceDescription.h>
  19. #import <driverkit/i386/IOPCIDirectDevice.h>
  20. #import <string.h>
  21. #import <stdio.h>
  22.  
  23. #import "QVision.h"
  24.  
  25. /* The `SetMode' category of `QVision'. */
  26.  
  27. @implementation QVision (SetMode)
  28.  
  29. - (ConfigBusType) determineConfigBusType
  30. {
  31.     const char *busTypeName;
  32.     IOConfigTable *configTable;
  33.  
  34.     configTable = [[self deviceDescription] configTable];
  35.     busTypeName = [configTable valueForStringKey:"Bus Type"];
  36.     if (strcmp(busTypeName, "PCI") == 0) {
  37.     busType = BusPCI;
  38.     } else if (strcmp(busTypeName, "EISA") == 0) {
  39.     busType = BusEISA;
  40.     } else {
  41.     /* default to ISA or VL */
  42.     busType = BusISAorVL;
  43.     }
  44.     return busType;
  45. }
  46.  
  47. /* assume dac type is determined already. This method is called by
  48.  * determineConfiguration only */
  49. - (QVAdapterType) determineVLCardType
  50. {
  51.     QVAdapterType adapterType;
  52.  
  53.     adapterType = UnknownAdapter;
  54.     switch (dac) {
  55.       case Bt484:
  56.         adapterType = OrionAdapter;
  57.         break;
  58.       case Bt485:
  59.       case Bt485A:
  60.       case ATT20C505:
  61.         adapterType = Orion12Adapter;
  62.         break;
  63.       default:
  64.         break;
  65.     }
  66.  
  67.     return adapterType;
  68. }
  69.  
  70. /* TODO: clean up error handling, i.e. return something meaningful rather
  71.  * than returning [super free]; */
  72. - (QVAdapterType) determinePCICardType
  73. {
  74.     unsigned int physicalAddress;
  75.     int     numRanges;
  76.     IOPCIConfigSpace configSpace;
  77.     unsigned char devNum, funcNum, busNum;
  78.     unsigned long vendorDeviceID;
  79.     unsigned short vendorID, deviceID;
  80.     char    idString[11];
  81.     id      deviceDescription;
  82.     QVAdapterType adapterType;
  83.     IOConfigTable *configTable;
  84.     IORange *oldRange, newRange[3];
  85.  
  86.     adapterType = UnknownAdapter;
  87.     if (![self isPCIPresent]) {
  88.     IOLog("%s: No PCI bus found.\n",[self name]);
  89.     return UnknownAdapter;
  90.     }
  91.     deviceDescription = [self deviceDescription];
  92.     [deviceDescription getPCIdevice:&devNum function:&funcNum bus:&busNum];
  93.     IOLog("%s: PCI Dev: %d Func: %d Bus: %d\n", [self name], devNum,
  94.            funcNum, busNum);
  95.            
  96.     [self getPCIConfigData:&vendorDeviceID atRegister:0x00];
  97.     vendorID = (unsigned short)vendorDeviceID;
  98.     deviceID = (unsigned short)(vendorDeviceID >> 16);
  99.     IOLog_dbg(("%s: vendorID=%04x deviceID=%04x\n",[self name], vendorID,
  100.       deviceID));
  101.  
  102.     /* go through "Auto Detect IDs" and make sure we are okay */
  103.     configTable = [[self deviceDescription] configTable];
  104.     sprintf(idString, "%08lx", vendorDeviceID);
  105.     if (strstr([configTable valueForStringKey:"Auto Detect IDs"], idString)
  106.     == NULL) {
  107.     IOLog("%s: VenderDeviceID %08lx not found in instance table.\n",
  108.           [self name], vendorDeviceID);
  109.     return UnknownAdapter;
  110.     } else {
  111.     /*
  112.      * add more card types here if there are PCI cards other than 1280P
  113.      * actually, if there are more than one PCI cards, we should
  114.      * determine which PCI card here 
  115.      */
  116.     adapterType = QVision1280P;
  117.     }
  118.  
  119.     /* need to do set framebuffer address for PCI */
  120.     [self getPCIConfigSpace:&configSpace];
  121.     physicalAddress = configSpace.BaseAddress[0];
  122.     physicalAddress &= 0xfffffff0;    /* mask out lower 4 bits */
  123.  
  124.     if (physicalAddress) {
  125.     IOLog_dbg(("%s: try to set physical address to 0x%08x\n",
  126.            [self name], physicalAddress));
  127.     /* PCI does report where the frame buffer address is */
  128.     oldRange = [deviceDescription memoryRangeList];
  129.     numRanges = [deviceDescription numMemoryRanges];
  130.     if (numRanges == 3) {
  131.         int     ret;
  132.         int     i;
  133.  
  134.         /* replace the address */
  135.         for (i = 0; i < numRanges; i++) {
  136.         newRange[i] = oldRange[i];
  137.         }
  138.         newRange[0].start = physicalAddress;
  139.         ret = [deviceDescription setMemoryRangeList:newRange num:3];
  140.         if (ret) {
  141.         /* can't set to new memory range */
  142.         IOLog("%s: Can't set memory range, using default.\n",
  143.               [self name]);
  144.         for (i = 0; i < numRanges; i++) {
  145.             newRange[i] = oldRange[i];
  146.         }
  147.         physicalAddress = newRange[0].start;
  148.         ret = [deviceDescription setMemoryRangeList:newRange
  149.                num:3];
  150.         if (ret) {
  151.             /* can't set to old range-->major problem! */
  152.             IOLog("%s: Can't set to default range either!\n",
  153.               [self name]);
  154.             return UnknownAdapter;
  155.         }
  156.         }
  157.     } else {
  158.         IOLog("%s: Incorrect number of address ranges: %d.\n",
  159.           [self name], numRanges);
  160.         return UnknownAdapter;
  161.     }
  162.     } else {
  163.     IOLog_dbg(("%s: PCI doesn't tell us the physical address.\n",
  164.            [self name]));
  165.     physicalAddress = [deviceDescription memoryRangeList]->start;
  166.     configSpace.BaseAddress[0] = physicalAddress;
  167.     [self setPCIConfigSpace:&configSpace];
  168.     }
  169.     return adapterType;
  170. }
  171.  
  172.  
  173. /* helper method to -determineEISACardType */
  174. - (QVAdapterType)adapterTypeFromEISAID:(unsigned int)cardID
  175. {
  176.     QVAdapterType adapterType;
  177.  
  178.     adapterType = UnknownAdapter;
  179.     IOLog_dbg(("%s: adapterTypeFromEISAID cardID=0x%08x\n",[self name],
  180.            cardID));
  181.     switch (cardID) {
  182.       case QVISION_EISA_ID:
  183.     adapterType = QVisionAdapter;
  184.     break;
  185.       case ORION_EISA_ID:
  186.     adapterType = OrionAdapter;
  187.     break;
  188.       case ORION12_EISA_ID:
  189.     adapterType = Orion12Adapter;
  190.     break;
  191.       case QVISION_ISA_ID:
  192.       case ORION_ISA_ID:
  193.       case ORION12_ISA_ID:
  194.     IOLog("%s: Sorry, ISA cards are not supported (id=0x%08x).\n",
  195.           [self name], cardID);
  196.     break;
  197.       default:
  198.     /* We found some other EISA card.  Just ignore it. */
  199.     break;
  200.     }
  201.     return adapterType;
  202. }
  203.  
  204. /* helper method to -determineEISACardType */
  205. - (QVAdapterType)autoScanEISAForCardType
  206. {
  207.     int     slot;
  208.     QVAdapterType adapterType;
  209.     unsigned int cardID;
  210.  
  211.     IOLog_dbg(("%s: doing auto-scan on EISA bus.\n",[self name]));
  212.  
  213.     adapterType = UnknownAdapter;
  214.     for (slot = 1; slot < 16; slot++) {
  215.     if ([self getEISAId:&cardID forSlot:slot]) {
  216.         adapterType = [self adapterTypeFromEISAID:cardID];
  217.     }
  218.     if (adapterType != UnknownAdapter) {
  219.         IOLog_dbg(("%s: found card in slot %d.\n",[self name], slot));
  220.         return adapterType;
  221.     }
  222.     }
  223.     return UnknownAdapter;
  224. }
  225.  
  226. /* can't use atoi() nor sscanf() */
  227. - (int) getFirstNumber:(char *)s
  228. {
  229.     char   *cptr;
  230.     int     n;
  231.  
  232.     cptr = s;
  233.     n = -1;
  234.     while (*cptr && ((*cptr < '0') || (*cptr > '9')))
  235.     cptr++;
  236.     while (*cptr && ((*cptr >= '0') && (*cptr <= '9'))) {
  237.     if (n == -1)
  238.         n = 0;
  239.     n = n * 10 + (*cptr - '0');
  240.     cptr++;
  241.     }
  242.     return n;
  243. }
  244.  
  245. /* TODO: clean up error handling, i.e. return something meaningful rather
  246.  * than returning [super free]; */
  247. - (QVAdapterType) determineEISACardType
  248. {
  249.     QVAdapterType adapterType;
  250.     int     mySlot;
  251.     id      deviceDescription;
  252.     const char *slotValue;
  253.     IOConfigTable *configTable;
  254.     unsigned int cardID;
  255.  
  256.     adapterType = UnknownAdapter;
  257.     if (![self isEISAPresent]) {
  258.     IOLog("%s: Not an EISA system.\n",[self name]);
  259.     return UnknownAdapter;
  260.     }
  261.     deviceDescription = [self deviceDescription];
  262.     configTable = [[self deviceDescription] configTable];
  263.  
  264.     /* see what slot we're supposed be in */
  265.     slotValue = [configTable valueForStringKey:"Location"];
  266.     if (strstr(slotValue, "Slot")) {
  267.     mySlot = [self getFirstNumber:(char *)slotValue];
  268.     IOLog_dbg(("%s: we should be in slot %d\n",[self name], mySlot));
  269.     } else {
  270.     /* instance table doesn't tell us what slot we're in */
  271.     return [self autoScanEISAForCardType];
  272.     }
  273.  
  274.     /* TODO: need to check for auto detect id's */
  275.     if (mySlot > 0) {
  276.     if ([self getEISAId:&cardID forSlot:mySlot]) {
  277.         adapterType = [self adapterTypeFromEISAID:cardID];
  278.     } else {
  279.         /* can't find card in the specified slot, do auto-scan */
  280.         adapterType = [self autoScanEISAForCardType];
  281.     }
  282.     } else {
  283.     /* slot not specified, do auto-scan */
  284.     adapterType = [self autoScanEISAForCardType];
  285.     }
  286.     return adapterType;
  287. }
  288.  
  289. - (void)reportConfiguration
  290. {
  291.     const char *adapterString, *dacString;
  292.     unsigned int biosCapability, memoryPresent;
  293.     const char *capString, *memString;
  294.    
  295.     switch (adapter) {
  296.       case QVisionAdapter:
  297.     adapterString = "QVision";
  298.     break;
  299.       case OrionAdapter:
  300.     adapterString = "Orion";
  301.     break;
  302.       case Orion12Adapter:
  303.     adapterString = "Orion12";
  304.     break;
  305.       case QVision1280P:
  306.     adapterString = "QVision1280P";
  307.     break;
  308.       default:
  309.     adapterString = "Unknown";
  310.     break;
  311.     }
  312.  
  313.     switch (dac) {
  314.       case Bt484:
  315.     dacString = "Brooktree 484";
  316.     break;
  317.       case Bt485:
  318.     dacString = "Brooktree 485";
  319.     break;
  320.       case Bt485A:
  321.     dacString = "Brooktree 485A";
  322.     break;
  323.       case ATT20C505:
  324.     dacString = "AT&T 20C505";
  325.     break;
  326.       default:
  327.     dacString = "Unknown";
  328.     break;
  329.     }
  330.  
  331.     /* Unlock */
  332.     outb(VGA_GRFX_INDEX, 0x0F);
  333.     outb(VGA_GRFX_DATA, 0x05);
  334.     
  335.     outb(VGA_GRFX_INDEX, 0x56);
  336.     biosCapability = inb(VGA_GRFX_DATA);
  337.     outb(VGA_GRFX_INDEX, 0x57);
  338.     biosCapability |= (inb(VGA_GRFX_DATA) << 8);
  339.     
  340.     /* TITAN == Bt484, TITAN-1280 == Bt484, GIANT == Bt485 (64-bit) */
  341.     
  342.     switch (biosCapability) {
  343.       case 0x2F3A:
  344.       case 0x2FBA:
  345.     capString = "QV64P10/GIANT";
  346.     break;
  347.       case 0x2F36:
  348.       case 0x2FB6:
  349.     capString = "QV64P10/TITAN-1280";
  350.     break;
  351.       case 0x2F32:
  352.       case 0x2FB2:
  353.     capString = "QV64P10/TITAN";
  354.     break;
  355.       case 0x0936:
  356.     capString = "QV35P04/TITAN-1280";
  357.     break;
  358.       case 0x0932:
  359.     capString = "QV35P04/TITAN";
  360.     break;
  361.       default:
  362.     capString = "Unknown";
  363.     break;
  364.     }
  365.     
  366.     /* Now find amount of installed memory */
  367.     outb(VGA_GRFX_INDEX, 0x54);
  368.     memoryPresent = inb(VGA_GRFX_DATA);
  369.     installedVRAMBytes = (memoryPresent * 1024 * 1024)/4;
  370.     
  371.     switch (memoryPresent) {
  372.       case 0x02:
  373.     memString = "0.5MB";
  374.     break;
  375.       case 0x04:
  376.     memString = "1MB";
  377.     break;
  378.       case 0x08:
  379.     memString = "2MB";
  380.     break;
  381.       case 0x10:
  382.     memString = "4MB";
  383.     break;
  384.       default:
  385.     memString = "Unknown";
  386.     break;
  387.     }
  388.  
  389.     IOLog("%s: %s: %s/%s/%s\n", [self name], adapterString, capString, dacString, memString);
  390.     
  391.     /* Relock */
  392.     outb(VGA_GRFX_INDEX, 0x0F);
  393.     outb(VGA_GRFX_DATA, 0x0);
  394. }
  395.  
  396.  
  397. - determineConfiguration
  398. {
  399.     adapter = UnknownAdapter;
  400.  
  401.     [self determineConfigBusType];
  402.     [self determineDACType];
  403.     
  404.     switch (busType) {
  405.       case BusISAorVL:
  406.     adapter = [self determineVLCardType];
  407.     break;
  408.       case BusPCI:
  409.     adapter = [self determinePCICardType];
  410.     break;
  411.       case BusEISA:
  412.     adapter = [self determineEISACardType];
  413.     break;
  414.     }
  415.     [self reportConfiguration];
  416.     if (adapter == UnknownAdapter || dac == UnknownDAC)
  417.     return nil;
  418.     return self;
  419. }
  420.  
  421. /*
  422.  * Initialize all fields in the QVision mode table. 
  423.  */
  424. - (void)initModeList
  425. {
  426.     int     i, n;
  427.     QVisionMode *qvMode;
  428.     unsigned int memoryNeeded;
  429.     
  430.     for (i = 0; i < QVisionModeTableCount; i++) {
  431.         QVisionModeTable[i].flags = IO_DISPLAY_HAS_TRANSFER_TABLE;
  432.     QVisionModeTable[i].modeUnavailableFlag = IO_DISPLAY_MODE_VALID;
  433.     }
  434.     
  435.     for (i = 0; i < QVisionModeTableCount; i++) {
  436.     memoryNeeded = QVisionModeTable[i].rowBytes * 
  437.         QVisionModeTable[i].height;
  438.         
  439.         if (installedVRAMBytes < memoryNeeded)
  440.         QVisionModeTable[i].modeUnavailableFlag |= 
  441.             IO_DISPLAY_MODE_NEEDS_MORE_MEMORY;
  442.     }
  443.     
  444.     for (i = 0; i < QVisionModeTableCount; i++) {
  445.     memoryNeeded = QVisionModeTable[i].rowBytes * 
  446.         QVisionModeTable[i].height;
  447.     for (n = 1024; n < memoryNeeded; n *= 2)
  448.         ;
  449.     QVisionModeTable[i].memorySize = n;
  450.     }
  451.     
  452.     for (i = 0; i < QVisionModeTableCount; i++) {
  453.     qvMode = QVisionModeTable[i].parameters;
  454.     if (qvMode->adapter > adapter)
  455.         QVisionModeTable[i].modeUnavailableFlag |= 
  456.             IO_DISPLAY_MODE_WRONG_VERSION;
  457.     }
  458.  
  459.     /*
  460.      * Add code here that fills in other fields as well.
  461.      */
  462. }
  463.  
  464. - selectMode
  465. {
  466.     int     mode;
  467.  
  468.     mode = [self selectMode:QVisionModeTable count:QVisionModeTableCount
  469.         valid:0];
  470.  
  471.     if (mode < 0) {
  472.     mode = DEFAULT_QVISION_MODE;
  473.     }
  474.     *[self displayInfo] = QVisionModeTable[mode];
  475.     
  476.     return self;
  477. }
  478.  
  479. - initializeMode
  480. {
  481.     unsigned int i;
  482.     const QVisionMode *mode;
  483.     const IODisplayInfo *displayInfo;
  484.  
  485.     displayInfo = [self displayInfo];
  486.     mode = displayInfo->parameters;
  487.  
  488.     /* Turn off video while setting all of the registers. */
  489.     inb(VGA_INPUT_STATUS_1);
  490.     outb(VGA_ATTR_INDEX, 0x00);
  491.  
  492.     /* Set the sequencer registers. */
  493.     for (i = 0; i < VGA_SEQ_COUNT; i++) {
  494.     outb(VGA_SEQ_INDEX, i);
  495.     outb(VGA_SEQ_DATA, mode->vgaData.seqx[i]);
  496.     }
  497.     outb(VGA_SEQ_INDEX, 0x00);
  498.     outb(VGA_SEQ_DATA, 0x03);    /* Restart the sequencer. */
  499.  
  500.     /* Unlock extended graphics registers. */
  501.     outw(VGA_GRFX_INDEX, 0x050f);
  502.  
  503.     /* Unlock more extended registers. */
  504.     outb(VGA_GRFX_INDEX, 0x10);
  505.     outb(VGA_GRFX_DATA, 0x08);
  506.  
  507.     /* Set Advanced VGA mode (set bit 0 of Ctrl Reg 0). */
  508.     outb(VGA_GRFX_INDEX, 0x40);
  509.     outb(VGA_GRFX_DATA, 0x01);
  510.  
  511.     /* Fix sequencer pixel mask for 8 bits. */
  512.     outb(VGA_SEQ_INDEX, SEQ_PIXEL_WR_MSK);
  513.     outb(VGA_SEQ_DATA, 0xff);
  514.  
  515.     outb(CTRL_REG_1, mode->ctrlReg1);
  516.     if (mode->adapter >= OrionAdapter) {
  517.     /* Set access level & enable high address map. */
  518.     outb(QVGA_CTL_2, 0x14);
  519.     /* Select 2 Meg mode. */
  520.     outb(QVGA_CTL_3, 0x05);
  521.     }
  522.     /* Set miscellaneous output register. */
  523.     outb(VGA_MISC_OUTPUT, mode->vgaData.miscOutput);
  524.  
  525.     [self programDAC];
  526.  
  527.     /* Load CRTC registers. */
  528.     outb(VGA_CRTC_INDEX, 0x11);    /* Unlock CRTC regs 0-7. */
  529.     outb(VGA_CRTC_DATA, 0x00);
  530.     for (i = 0; i < VGA_CRTC_COUNT; i++) {
  531.     outb(VGA_CRTC_INDEX, i);
  532.     outb(VGA_CRTC_DATA, mode->vgaData.crtc[i]);
  533.     }
  534.  
  535.     /* Load overflow registers. */
  536.     outb(VGA_GRFX_INDEX, 0x42);
  537.     outb(VGA_GRFX_DATA, mode->overflow1);
  538.     outb(VGA_GRFX_INDEX, 0x51);
  539.     outb(VGA_GRFX_DATA, mode->overflow2);
  540.  
  541.     /* Load attribute registers. */
  542.  
  543.     inb(VGA_INPUT_STATUS_1);    /* Reset latch. */
  544.     for (i = 0; i < VGA_ATTR_COUNT; i++) {
  545.     outb(VGA_ATTR_INDEX, i);
  546.     outb(VGA_ATTR_DATA, mode->vgaData.attr[i]);
  547.     }
  548.  
  549.     /* Load graphics registers. */
  550.     for (i = 0; i < VGA_GRFX_COUNT; i++) {
  551.     outb(VGA_GRFX_INDEX, i);
  552.     outb(VGA_GRFX_DATA, mode->vgaData.grfx[i]);
  553.     }
  554.     
  555.     [self setGammaTable];
  556.  
  557.     /* Re-enable video display. */
  558.     inb(VGA_INPUT_STATUS_1);
  559.     outb(VGA_ATTR_INDEX, 0x20);
  560.  
  561.     return self;
  562. }
  563.  
  564. - enableLinearFrameBuffer
  565. {
  566.     const IODisplayInfo *displayInfo;
  567.     unsigned char tmp;
  568.  
  569.     /*
  570.      * Override the high address map disable, thus allowing access to the
  571.      * high address map of the current board, even when the board is
  572.      * disabled. 
  573.      */
  574.  
  575.     outb(VGA_GRFX_INDEX, HI_ADDR_MAP + 1);
  576.     tmp = inb(VGA_GRFX_DATA);
  577.     outb(VGA_GRFX_DATA, tmp | 0x80);
  578.  
  579.     /* Map VRAM.  Tell the adapter where to decode the framebuffer. */
  580.  
  581.     /* Set low 8 bits */
  582.     outb(VGA_GRFX_INDEX, HI_ADDR_MAP);
  583.     outb(VGA_GRFX_DATA, (videoRamAddress >> 20) & 0xFF);
  584.  
  585.     /* Set upper 4 bits */
  586.     outb(VGA_GRFX_INDEX, HI_ADDR_MAP + 1);
  587.     outb(VGA_GRFX_DATA, (videoRamAddress >> 28) & 0x0F);
  588.  
  589.     /* Leave them with a nice clear screen. */
  590.  
  591.     displayInfo = [self displayInfo];
  592.     memset(displayInfo->frameBuffer, 0,
  593.        displayInfo->rowBytes * displayInfo->height);
  594.  
  595.     return self;
  596. }
  597.  
  598. - resetVGA
  599. {
  600.     const IODisplayInfo *displayInfo;
  601.     const QVisionMode *mode;
  602.  
  603.     displayInfo = [self displayInfo];
  604.     mode = displayInfo->parameters;
  605.  
  606.     /* Clear the QVision extended mode bit. This is bit 0 of CTRL_REG_1. */
  607.  
  608.     outb(CTRL_REG_1, inb(CTRL_REG_1) & 0xFE);
  609.  
  610.     if (mode != 0 && mode->adapter >= OrionAdapter) {
  611.     /* Select 1 meg mode. */
  612.     outb(QVGA_CTL_3, 0x00);
  613.     /* Reset access level & disable high address map. */
  614.     outb(QVGA_CTL_2, 0x00);
  615.     }
  616.     /* Clear the extended 256 color bit. This is bit 0 of 3CF.40. */
  617.     outb(VGA_GRFX_INDEX, 0x40);
  618.     outb(VGA_GRFX_DATA, (inb(VGA_GRFX_DATA) & 0xFE));
  619.  
  620.     /* Clear the page registers - 3CF.45 and 3CF.46. */
  621.     outb(VGA_GRFX_INDEX, PAGE_REG_0);
  622.     outb(VGA_GRFX_DATA, 0x00);
  623.     outb(VGA_GRFX_INDEX, PAGE_REG_1);
  624.     outb(VGA_GRFX_DATA, 0x00);
  625.  
  626.     [self resetDAC];
  627.  
  628.     /* Clear the overflow registers. */
  629.     outb(VGA_GRFX_INDEX, 0x42);
  630.     outb(VGA_GRFX_DATA, 0x00);
  631.     outb(VGA_GRFX_INDEX, 0x51);
  632.     outb(VGA_GRFX_DATA, 0x00);
  633.  
  634.     VGASetMode(0x03);
  635.  
  636.     return self;
  637. }
  638. @end
  639.