home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer)…68k, x86, SPARC, PA-RISC] / NeXTSTEP 3.3 Dev Intel.iso / NextDeveloper / Examples / DriverKit / QVision / QVision_reloc.tproj / QVisionSetMode.m < prev    next >
Encoding:
Text File  |  1994-09-26  |  13.7 KB  |  536 lines

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