|
|
1.1 root 1: /* Copyright (c) 1992, 1993, 1994 NeXT Computer, Inc. All rights reserved.
2: *
3: * ATI.m - ATI display driver.
4: *
5: * HISTORY
6: * 07 Oct 92 Joe Pasqua
7: * Created.
8: * 01 June 93 Mike Paquette
9: * Rewrite: Convert from Corsair device driver to general MACH32 chipset
10: * driver. Add support for multiple DACs and CRT setups.
11: * Add 8 bit monochrome support. Add support for non-Cosair
12: * implementations.
13: * 7 July 1993 Derek B Clegg
14: * Cleaned up for external release.
15: * Mon Aug 15 17:18:12 PDT 1994 James C. Lee
16: * add 8-bit color support by integrating Peter Graffagnino's mods
17: */
18:
19: #import <driverkit/generalFuncs.h>
20: #import <driverkit/i386/ioPorts.h>
21: #import <driverkit/i386/directDevice.h>
22: #import <driverkit/i386/IOEISADeviceDescription.h>
23: #import <ansi/string.h>
24: #import "ATI.h"
25:
26: #define ONE_MEG (1024 * 1024)
27:
28: @implementation ATI
29:
30: static void
31: UnlockShadowSet(int set)
32: {
33: outb(SHADOW_SET, 2);
34: outb(SHADOW_CNTL, 0);
35: outb(SHADOW_SET, 1);
36: outb(SHADOW_CNTL, 0);
37: outb(SHADOW_SET, set);
38: }
39:
40: static void
41: LockShadowSet(void)
42: {
43: outb(SHADOW_SET, 1);
44: outb(SHADOW_CNTL, 0x3F);
45: outb(SHADOW_SET, 2);
46: outb(SHADOW_CNTL, 0x3F);
47: outb(SHADOW_SET, 0);
48: }
49:
50: static void
51: ProgramShadowSet(int set, const ATI_CRTCSetup *setup)
52: {
53: UnlockShadowSet(set);
54:
55: outb(DISP_CNTL, 0x53); /* Reset, blanking display. */
56: outb(H_TOTAL, setup->h_total);
57: outb(H_DISP, setup->h_disp);
58: outb(H_SYNC_START, setup->h_sync_start);
59: outb(H_SYNC_WIDTH, setup->h_sync_wid);
60: outw(V_TOTAL, setup->v_total);
61: outw(V_DISP, setup->v_disp);
62: outw(V_SYNC_START, setup->v_sync_start);
63: outb(V_SYNC_WID, setup->v_sync_wid);
64: outb(DISP_CNTL, setup->disp_cntl);
65: outw(CLOCK_SELECT, setup->clock_select);
66:
67: /* Zero overscan registers to avoid weird borders. */
68: outw(HORIZONTAL_OVERSCAN, 0);
69: outw(VERTICAL_OVERSCAN, 0);
70: outb(OVERSCAN_COLOR_BLUE, 0);
71: outb(OVERSCAN_COLOR_GREEN, 0);
72: outb(OVERSCAN_COLOR_RED, 0);
73:
74: LockShadowSet();
75: }
76:
77: static void
78: SelectShadowSet(int set)
79: {
80: unsigned char v;
81:
82: switch (set) {
83: case 0:
84: v = 2;
85: break;
86: case 1:
87: v = 3;
88: break;
89: case 2:
90: v = 7;
91: break;
92: default:
93: return;
94: }
95: outb(ADVFUNC_CNTL, v);
96: }
97:
98: static void
99: SetMemOffset(void)
100: {
101: unsigned int vga_boundary;
102:
103: /* Get the video memory boundary, in 256K pages. The 8514 controller
104: * cannot access memory below this, and the VGA controller cannot
105: * access memory above this. */
106: vga_boundary = inb(MEM_BNDRY) & 0x0f;
107:
108: /* Set the start of the CRT buffer to match the start of the
109: * 8514 controller VRAM address. We also set up the graphics engine... */
110: outb(GE_OFFSET_HI, vga_boundary);
111: outb(CRT_OFFSET_HI, vga_boundary);
112: outb(GE_OFFSET_LO, 0);
113: outb(CRT_OFFSET_LO, 0);
114: }
115:
116: /*
117: * Returns the physical base address of the memory aperature. The method
118: * used to decode this varies based on the BIOS and Mach32 chip type.
119: */
120: static unsigned int
121: MemoryAperatureBaseAddress(void)
122: {
123: unsigned char *ip;
124: unsigned int location; /* Base address in Mbytes */
125:
126: /*
127: * The PC BIOS is broken into 2 Kb slices. On startup, the ATI BIOS
128: * stashes away which 2 Kb slice it live in in scratch reg 0.
129: */
130: ip = (unsigned char *)
131: (((inb(ROM_SCRATCH_PAD_0) & 0x7F) * 0x800) + ATI_BIOS_BASEADDR);
132:
133: /* Look up the BIOS flag to see if it uses extended or simple format */
134: if ( (ip[0x62] & 1) != 0 ) /* Corsair/Nova style BIOS */
135: {
136: /*
137: * MEM_CFG+1 specifies an address from 0-127 Mb
138: * (MSB is always 0), and the scratch register specifies
139: * what the external hardware decodes, up to 4 Gb.
140: */
141: location = ((inb(ROM_SCRATCH_PAD_0 + 1) & 0x1F) << 7)
142: | (inb(MEM_CFG + 1));
143: }
144: else /* No external address decode. Just use MEM_CFG register */
145: {
146: if ((inb(CONFIG_STATUS_2 + 1) & MEM_APERATURE_4GB_RANGE) != 0)
147: location = inw( MEM_CFG ) >> 4;
148: else
149: location = inb( MEM_CFG + 1 );
150: }
151: #if DEBUG
152: IOLog("MemoryAperatureBaseAddress() == 0x%x\n", location * ONE_MEG);
153: #endif
154: return (location * ONE_MEG); /* Return phys address in bytes, not Mb */
155: }
156:
157: /*
158: * Returns the physical base address of the memory aperature. The method
159: * used to decode this varies based on the BIOS and Mach32 chip type.
160: */
161: static BOOL
162: SetMemoryAperatureBaseAddress(unsigned int newLocation)
163: {
164: unsigned char *ip;
165: unsigned int location;
166: #if DEBUG
167: IOLog("SetMemoryAperatureBaseAddress(0x%x)\n", newLocation );
168: #endif
169: /* Convert location to Mbytes. Make sure it's on a 1 Mb boundry */
170: if ( (newLocation & (ONE_MEG - 1)) != 0 )
171: return NO;
172: location = newLocation / ONE_MEG;
173:
174: /*
175: * The PC BIOS is broken into 2 Kb slices. On startup, the ATI BIOS
176: * stashes away which 2 Kb slice it live in in scratch reg 0.
177: */
178: ip = (unsigned char *)
179: (((inb(ROM_SCRATCH_PAD_0) & 0x7F) * 0x800) + ATI_BIOS_BASEADDR);
180:
181: /* Look up the BIOS flag to see if it uses extended or simple format */
182: if ( (ip[0x62] & 1) != 0 ) /* Corsair/Nova style BIOS */
183: {
184: /*
185: * It's never safe to reprogram these, as we don't know
186: * how to set the off-chip decoding logic.
187: */
188: return NO;
189: }
190: else /* No external address decode. Just use MEM_CFG register */
191: {
192: if ((inb(CONFIG_STATUS_2 + 1) & MEM_APERATURE_4GB_RANGE) != 0)
193: {
194: outw(MEM_CFG, (location << 4)|(inw( MEM_CFG ) & 0xF));
195: }
196: else
197: {
198: if ( newLocation > ATI_LOCALBUS_VRAM_ADDRESS )
199: return NO; /* Invalid addr for this config */
200: outb( MEM_CFG + 1, location );
201: }
202: }
203: #if DEBUG
204: IOLog("SetMemoryAperatureBaseAddress(0x%x) succeeds\n", newLocation );
205: #endif
206: return YES;
207: }
208:
209: /* Undo our munging of the DAC. Put DAC back in a state usable by VGA mode.
210: */
211: static void
212: reset_DAC(void)
213: {
214: ATI_DAC dac_type;
215:
216: /* Disable VGA passthrough mode so the DAC may be programmed. */
217: outw(CLOCK_SELECT, inw(CLOCK_SELECT) | 1);
218:
219: dac_type = (inb(CONFIG_STATUS_1 + 1) >> 1) & 7;
220: switch(dac_type) {
221: case ATI_DAC_ATT20C491: /* ATT 20C491 */
222: case ATI_DAC_Bt481: /* Brooktree Bt481, Bt482 */
223: /* TO DO: Not tested yet */
224: outw(EXT_GE_CONFIG, 0x101A); /* DAC reg 1. */
225: outb(DAC_MASK, 0); /* VGA mode. */
226: break;
227:
228: case ATI_DAC_68875: /* ATI or TI 34075. */
229: outw(EXT_GE_CONFIG, 0x201A); /* DAC reg 1. */
230: outb(INPUT_CLK_SEL, 0); /* clock 0. */
231: outb(OUTPUT_CLK_SEL, 0); /* SCLK & VCLK 1. */
232: outb(MUX_CNTL, 0x2D); /* MUX CNTL to 8/16. */
233:
234: /* Set default 8 BPP delay and blank adjust. */
235: outw(LOCAL_CNTL, (inw(LOCAL_CNTL) | 0x8));
236: /* Set PIXEL DELAY = 3, BLANK ADJ = 0 (0xC). */
237: outb(MISC_CNTL + 1, (inb(R_MISC_CNTL + 1) & 0xF0) | 0xC);
238: /* Set horizontal skew. */
239: outw(HORIZONTAL_OVERSCAN, 1);
240: break;
241:
242: case ATI_DAC_68830: /* ATI 68830*/
243: default:
244: /* Set PIXEL DELAY = 0, BLANK ADJ = 0. */
245: outb(MISC_CNTL + 1, (inb(R_MISC_CNTL + 1) & 0xF0) | 0);
246: /* Set horizontal skew. */
247: outw(HORIZONTAL_OVERSCAN, 0);
248: break;
249: }
250:
251: /* Put DAC in 6 bit mode, engine in 8 bit mode. */
252: outw(EXT_GE_CONFIG, 0x001A); /* reset EXT_DAC_ADDR */
253: /* Enable VGA passthrough mode. */
254: outw(CLOCK_SELECT, inw(CLOCK_SELECT) & ~1);
255: }
256:
257: static void
258: program_TI34075(const ATI_DACSetup *parm, const IODisplayInfo *displayMode)
259: {
260: ATI_CRTCSetup *setup;
261:
262: /* DAC RS 3 active, 8 bit pixel width. */
263: outw(EXT_GE_CONFIG, 0x201A);
264: outb(OUTPUT_CLK_SEL, parm->out_clk);
265: outb(MUX_CNTL, parm->mux);
266: outb(INPUT_CLK_SEL, parm->in_clk);
267: outw(EXT_GE_CONFIG, parm->GE_config);
268: outb(DAC_MASK, parm->mask);
269:
270: /* Set blank adjust and pixel delay values per parm->delay_timing. */
271: outb(MISC_CNTL + 1, (inb(R_MISC_CNTL + 1) & 0xf0) | parm->delay_timing);
272:
273: setup = (ATI_CRTCSetup *)displayMode->parameters;
274: if (setup->mux_flag == 0)
275: return;
276:
277: /* Set PIXEL DELAY = 0, BLANK ADJ = 1. */
278: outb(MISC_CNTL + 1, (inb(R_MISC_CNTL + 1) & 0xF0) | 1);
279:
280: UnlockShadowSet(2);
281: outw(CLOCK_SELECT, setup->clock_select);
282: LockShadowSet();
283: SelectShadowSet(2);
284: }
285:
286: static void
287: program_ATI68830(const ATI_DACSetup *parm, const IODisplayInfo *displayMode)
288: {
289: /* Set pixel depth, packing, aliased monitor ID of 2. */
290: outw(EXT_GE_CONFIG, parm->GE_config & 0x0fff);
291: }
292:
293: /* Brooktree Bt481, Bt482 or ATT 20C491 RAMDAC setup code.
294: * On entry, the CRT controller is programmed, and VGA passthru is disabled.
295: * TO DO: Test with ATT 20C491.
296: */
297: static void
298: program_Bt481(const ATI_DACSetup *parm, const IODisplayInfo *displayMode)
299: {
300: /* The clock should already be set appropriately for a 'slow', or
301: * double-clocked DAC on entry. */
302:
303: /* Activate the TrueColor mode in the DAC. */
304:
305: /* DAC RS 2 active, 8 bit pixel width. */
306: outw(EXT_GE_CONFIG, 0x101A);
307:
308: /* Set reg 6 to correct mode. */
309: outb(DAC_MASK, parm->mode);
310:
311: /* Set blank adjust and pixel delay values. */
312: outb(MISC_CNTL + 1, (inb(R_MISC_CNTL + 1) & 0xf0) | parm->delay_timing);
313:
314: /* Set pixel depth, packing, aliased monitor ID of 2. */
315: outw(EXT_GE_CONFIG, parm->GE_config & 0x0fff);
316:
317: /* Set the appropriate DAC pixel mask. */
318: outb(DAC_MASK, parm->mask);
319: }
320:
321: /* Set up a simple gamma corrected grayscale. We rely on the Window Server
322: * invoking this function once via IO_SET_TRANSFER_TABLE during startup.
323: */
324: static void
325: ATISetTransferTable(const unsigned int *table, const IODisplayInfo *display,
326: int brightness)
327: {
328: ATI_DAC dac_type;
329: int g, val;
330: unsigned int scale;
331:
332: /*
333: * can only adjust ramdac for 8bit gray and 8bit color
334: */
335: if (display == 0 || display->bitsPerPixel != IO_8BitsPerPixel ||
336: table == 0)
337: return;
338: dac_type = (inb(CONFIG_STATUS_1 + 1) >> 1) & 7;
339:
340: switch (dac_type) {
341: case ATI_DAC_68875: /* ATI or TI 34075 */
342: case ATI_DAC_68830: /* ATI 68830*/
343: case ATI_DAC_Bt476:
344: scale = 0;
345: break;
346: case ATI_DAC_ATT20C491: /* ATT 20C491 */
347: case ATI_DAC_Bt481: /* Brooktree Bt481, Bt482 */
348: default:
349: scale = 2;
350: break;
351: }
352:
353: outb(DAC_W_INDEX, 0);
354:
355: if (display->colorSpace == IO_RGBColorSpace ) {
356: for (g = 0; g < IO_8BPP_TRANSFER_TABLE_SIZE; g++) {
357: val = (table[g] >> 24);
358: if (scale)
359: val >>= scale;
360: outb(DAC_DATA, EV_SCALE_BRIGHTNESS(brightness, val));
361: val = ((table[g] & 0xFF0000) >> 16);
362: if (scale)
363: val >>= scale;
364: outb(DAC_DATA, EV_SCALE_BRIGHTNESS(brightness, val));
365: val = ((table[g] & 0xFF00) >> 8);
366: if (scale)
367: val >>= scale;
368: outb(DAC_DATA, EV_SCALE_BRIGHTNESS(brightness, val));
369: }
370: } else {
371: for (g = 0; g < IO_8BPP_TRANSFER_TABLE_SIZE; g++) {
372: val = (table[g] & 0x000000FF);
373: if (scale)
374: val >>= scale;
375: outb(DAC_DATA, EV_SCALE_BRIGHTNESS(brightness, val));
376: outb(DAC_DATA, EV_SCALE_BRIGHTNESS(brightness, val));
377: outb(DAC_DATA, EV_SCALE_BRIGHTNESS(brightness, val));
378: }
379: }
380: }
381:
382: - (void)setupHardware
383: {
384: ATI_DAC dac_type;
385: const ATI_DACSetup *parm;
386:
387: SetMemOffset(); /* Set VGA VRAM memory offset. */
388:
389: dac_type = (inb(CONFIG_STATUS_1 + 1) >> 1) & 7;
390:
391: /* Load a register shadow set with our desired setup. */
392:
393: /* Load CRT regs, and enable controller in appropriate mode, unblanking
394: * the display in the process. */
395: ProgramShadowSet(2, CRTControllerSetup);
396:
397: /* Select our setup, re-enabling the CRT controller. */
398: SelectShadowSet(2);
399:
400: /* At this point, the CRT timing is set, VGA passthrough is disabled,
401: * and the pixel clock is set. We need to place the DAC in the correct
402: * mode of operation. */
403:
404: if (displayMode->bitsPerPixel == IO_15BitsPerPixel)
405: parm = &ATI_DAC_Setup_15BPP;
406: else
407: parm = &ATI_DAC_Setup_8BPP;
408:
409: switch (dac_type) {
410: case ATI_DAC_68830: /* ATI 68830*/
411: program_ATI68830(parm, displayMode);
412: outw(HORZ_OVERSCAN, 1);
413: break;
414:
415: case ATI_DAC_ATT20C491: /* ATT 20C491 */
416: case ATI_DAC_Bt481: /* Brooktree Bt481, Bt482 */
417: program_Bt481(parm, displayMode);
418: break;
419:
420: case ATI_DAC_68875: /* ATI or TI 34075 */
421: program_TI34075(parm, displayMode);
422: break;
423:
424: default:
425: /* Bt476 or some other unusable part. */
426: IOLog("%s: Unknown DAC on ATI board - ID:%d\n", [self name], dac_type);
427: break;
428: }
429:
430: /* Set the CRT pitch, in units of (pixels_per_line/8).
431: * CAUTION: Writing ADVFUNC_CNTL or MEM_CNTL (0xbee8) resets
432: * this to 1024 pixels/line. */
433: outb(CRT_LINE_PITCH, CRTControllerSetup->xres >> 3);
434:
435: /* Also set the graphics engine... */
436: outb(GE_PITCH, CRTControllerSetup->xres >> 3);
437: }
438:
439: - (vm_offset_t)prepareMemoryAperture
440: {
441: unsigned int physLoc;
442: vm_offset_t virtLoc;
443: vm_size_t length, needed_length;
444: ATI_DAC dac_type;
445: int mode, k;
446: BOOL valid[ATIModeCount];
447: BOOL slowDAC = NO;
448: IORange *range;
449: const IODisplayInfo *displayTable;
450: int numTableEntries;
451: const IODisplayInfo *displayDefault;
452:
453: /* Set memory boundary to share. */
454: outb(MEM_BNDRY, 0);
455: /* Enable memory aperture with a 4 Mb width, page sel for page 0. */
456: outb(MEM_CFG, (inb(MEM_CFG) & 0xf0) | 0x02);
457:
458: /* Get memory aperture location (units in Mbyte). This is hardware
459: * and version dependent. The high 8 bits of MEM_CFG specify the
460: * memory aperature location between 0 and 127Mb, in 1 Mb units.
461: */
462: range = [[self deviceDescription] memoryRangeList];
463: if (range == NULL) {
464: IOLog("%s: No memory range set.\n", [self name]);
465: return 0;
466: }
467:
468: physLoc = 0; /* Default to Configure app settings. */
469:
470: /* Use the Misc Options register (36EE) bits 2&3 to determine
471: * the amount of installed memory. 0 = 512, 1 = 1M, 2 = 2M, 3 = 4M.
472: * Select a timing setup based on available memory and DACs.
473: * We do this here instead of in goLinear so we can report the
474: * potential frame buffer size early in the startup sequence.
475: */
476: dac_type = (inb(CONFIG_STATUS_1 + 1) >> 1) & 7;
477:
478: switch (dac_type) {
479: case ATI_DAC_68830: /* ATI 68830*/
480: case ATI_DAC_68875: /* ATI or TI 34075 */
481: slowDAC = NO;
482: break;
483: case ATI_DAC_ATT20C491: /* ATT 20C491 */
484: case ATI_DAC_Bt476: /* Brooktree Bt476, Bt478 */
485: case ATI_DAC_Bt481: /* Brooktree Bt481, Bt482 */
486: default:
487: /* These DACs can't handle the clock rates at 1024x768. */
488: slowDAC = YES;
489: break;
490: }
491:
492: switch ((inb(MISC_OPTIONS) & 0x0c) >> 2) {
493: default:
494: case 0: /* 512 Kb VRAM. */
495: return (vm_offset_t)0;
496: case 1: /* 1 Mb VRAM. */
497: length = ONE_MEG;
498: break;
499: case 2: /* 2 Mb VRAM. */
500: case 3: /* 4 Mb VRAM. */
501: length = 2 * ONE_MEG; /* The most we currently need. */
502: break;
503: }
504:
505: switch (ati_flavor) {
506: case ATI_EISA_Card: /* Definitely programmable address. */
507: case ATILocalBusCard: /* Usually a programmable address. */
508: /* Read out the full address using the mechanism endorsed by
509: * ATI. This mechanism is supported by ATI in their Windows
510: * driver, and every vendor we've tested follows it rather than
511: * rolling their own drivers.
512: */
513: physLoc = MemoryAperatureBaseAddress();
514:
515: /* If the address is in a range supported by the Mach32
516: * chipset (below 128 Mb), try to program it. Otherwise,
517: * we'll assume the address is hardwired, and pick it up
518: * using the ATI endorsed addressing mechanism. */
519: if ( physLoc != range->start )
520: SetMemoryAperatureBaseAddress( range->start );
521: /* FALL THRU */
522:
523: default: /* Unknown device. */
524: case ATI_NovaCard: /* Not programmable in prototypes tested. */
525: case ATICorsair: /* Not programmable. */
526: /* Read out the full address using the mechanism endorsed by
527: * ATI. This mechanism is supported by ATI in their Windows
528: * driver, and every vendor we've tested follows it rather than
529: * rolling their own drivers.
530: */
531: physLoc = MemoryAperatureBaseAddress();
532:
533: /* If the address doesn't match the one set in Configure, complain.
534: * We then override the Configure address with the address reported
535: * by the hardware. This gives the driver a fighting chance of
536: * working correctly, and works around a bug in 3.1 Configure and
537: * DriverKit which prevents setting addresses in the high 2 Gb of
538: * address space.
539: */
540: if (range->start != physLoc || range->size < length) {
541: IOLog("%s: FB addr decodes as 0x%x, overriding configured "
542: "addr 0x%x.\n", [self name], physLoc, range->start);
543:
544: /* Force the range to match the hardware config,
545: * so the Window Server will work correctly. */
546: range->start = physLoc;
547: range->size = length;
548: /* Reprogram the device description with usable values. */
549: [[self deviceDescription] setMemoryRangeList:range
550: num:[[self deviceDescription] numMemoryRanges]];
551: }
552: break;
553: }
554:
555: /* Enable kernel access with the appropriate mapping. */
556:
557: virtLoc = [self mapFrameBufferAtPhysicalAddress:physLoc length:length];
558: if (virtLoc == 0)
559: return virtLoc;
560:
561: /* If the DAC is a slow double-clocked part (ATT20C491, Bt481) use
562: * the special setup for the part. */
563:
564: if (slowDAC == YES) {
565: displayTable = ATISlowDACMode;
566: numTableEntries = ATISlowDACModeCount;
567: displayDefault = &ATISlowDACMode[ATI_DEFAULT_SlowDAC_MODE];
568: } else {
569: displayTable = ATIMode;
570: numTableEntries = ATIModeCount;
571: displayDefault = (length > ONE_MEG) ? &ATIMode[ATI_DEFAULT_2MEG_MODE]
572: : &ATIMode[ATI_DEFAULT_1MEG_MODE];
573: }
574:
575: /* Determine which entries are valid for the amount of memory in the
576: * system. */
577:
578: for (k = 0; k < numTableEntries; k++) {
579: needed_length = displayTable[k].width * displayTable[k].height;
580: if (displayTable[k].bitsPerPixel != IO_8BitsPerPixel)
581: needed_length *= sizeof(short);
582: valid[k] = (needed_length <= length);
583: /* The 68830 DAC can't handle higher res than 1024x768. */
584: if ( dac_type == ATI_DAC_68830 && displayTable[k].width > 1024 )
585: valid[k] = NO;
586: }
587:
588: /* Look up the correct entry to use. */
589: mode = [self selectMode:displayTable count:numTableEntries valid:valid];
590: if (mode < 0)
591: displayMode = displayDefault;
592: else
593: displayMode = &displayTable[mode];
594: CRTControllerSetup = (ATI_CRTCSetup *)displayMode->parameters;
595: return virtLoc;
596: }
597:
598: - (void)establishLinearFB
599: {
600: /* Local Bus timing magic */
601: if ( inw( MACH32_STEP6_ID_REG ) != MACH32_STEP6_ID_VALUE )
602: {
603: asm volatile(
604: "pushl %eax; \n"
605: "pushl %edx; \n"
606: "; \n"
607: "movl 0x01CE, %edx; \n"
608: "movl 0xAE, %eax; \n"
609: "outb %al, %dx; \n"
610: "incl %edx; \n"
611: "inb %dx, %al; \n"
612: "andb $ ~0x10, %al; \n"
613: "movb %al, %ah; \n"
614: "movb $0xAE, %al; \n"
615: "decl %edx; \n"
616: "outw %ax, %dx; \n"
617: "; \n"
618: "movl $0x2185,%eax; \n"
619: "outw %ax,%dx; \n"
620: "; \n"
621: "movl $0x01CE, %edx; \n"
622: "movl $0xAE, %eax; \n"
623: "outb %al, %dx; \n"
624: "incl %edx; \n"
625: "inb %dx, %al; \n"
626: "orb $ 0x10, %al; \n"
627: "movb %al, %ah; \n"
628: "movl $0xAE, %al; \n"
629: "decl %edx; \n"
630: "outw %ax, %dx; \n"
631: "; \n"
632: "popl %edx; \n"
633: "popl %eax; \n");
634: };
635:
636: /* Program controller to 16bpp or 8bpp mode. */
637: [self setupHardware];
638: }
639:
640: /* Determine whether there is an ATi chipset present.
641: * 1) Check for an EISA card. If found, we're done.
642: * 2) Check for EISA CPU board ID. If it's a Corsair, we're done.
643: * 3) Fallback: assume a localbus+ISA card. (No ID mechanism!)
644: */
645: - (boolean_t)ATIPresent
646: {
647: int slot;
648: unsigned int product_id;
649:
650: /* First, scan for a board in an EISA slot. */
651: if ([self isEISAPresent] == TRUE) {
652: for (slot = 1; slot < 16; slot++) {
653: if ([self getEISAId:&product_id forSlot:slot] == TRUE) {
654: switch (product_id & ~0x0f) {
655: case ATI_EISA_ID:
656: ati_flavor = ATI_EISA_Card;
657: return TRUE;
658: case ATI_NOVA_PBUS_EISA_ID:
659: ati_flavor = ATI_NovaCard;
660: return TRUE;
661: }
662: }
663: }
664:
665: /* Examine the EISA ID for the motherboard, found in 'slot 0'.
666: * Do this AFTER the slot scan, so we preferentially use boards
667: * in the EISA slots.
668: */
669: if ([self getEISAId:&product_id forSlot:0] == TRUE
670: && (product_id & ~0x0f) == INTEL_CORSAIR_ID) {
671: ati_flavor = ATICorsair;
672: return TRUE;
673: }
674: }
675:
676: IOLog("%s: Assuming a local bus ATI card.\n", [self name]);
677: ati_flavor = ATILocalBusCard;
678: return TRUE;
679: }
680:
681: - (void)enterLinearMode
682: {
683: [self establishLinearFB];
684: }
685:
686: - initFromDeviceDescription:deviceDescription
687: {
688: void *frameBuffer;
689: IODisplayInfo *display;
690:
691: if ([super initFromDeviceDescription:deviceDescription] == nil)
692: return [super free];
693:
694: if (![self ATIPresent])
695: return [super free];
696:
697: display = [self displayInfo];
698: frameBuffer = (void *)[self prepareMemoryAperture];
699: if (frameBuffer == 0)
700: return nil;
701: *display = *displayMode;
702: display->frameBuffer = frameBuffer;
703: display->flags = IO_DISPLAY_CACHE_WRITETHROUGH;
704: if (displayMode->bitsPerPixel == IO_15BitsPerPixel) {
705: display->flags |= IO_DISPLAY_NEEDS_SOFTWARE_GAMMA_CORRECTION;
706: } else if (displayMode->bitsPerPixel == IO_8BitsPerPixel) {
707: display->flags |= IO_DISPLAY_HAS_TRANSFER_TABLE;
708: }
709: return self;
710: }
711:
712: - free
713: {
714: return [super free];
715: }
716:
717: - (void)revertToVGAMode
718: {
719: /* Select VGA setup, re-enabling the VGA CRT controller. */
720: SelectShadowSet(0); /* Select VGA CRT configuration. */
721: reset_DAC(); /* Restore DAC for VGA operation. */
722: [super revertToVGAMode]; /* Let superclass do generic VGA stuff. */
723: }
724:
725:
726: /* Set the transfer tables.
727: */
728: - setTransferTable:(const unsigned int *)table count:(int)numEntries
729: {
730: if (transferTable != 0)
731: IOFree(transferTable, sizeof(unsigned int)* transferTableCount);
732:
733: transferTableCount = numEntries;
734:
735: transferTable = IOMalloc(sizeof(unsigned int) * numEntries);
736: bcopy(table, transferTable, sizeof(unsigned int) * numEntries);
737: ATISetTransferTable(table, [self displayInfo], EV_SCREEN_MAX_BRIGHTNESS);
738: return self;
739: }
740:
741: /* Set the brightness to `level'.
742: */
743: - setBrightness:(int)level token:(int)t
744: {
745: if (level < EV_SCREEN_MIN_BRIGHTNESS || level > EV_SCREEN_MAX_BRIGHTNESS) {
746: IOLog("%s Invalid brightness level `%d'.\n", [[self class] name],
747: level);
748: return nil;
749: }
750: brightnessLevel = level;
751: ATISetTransferTable(transferTable, [self displayInfo], brightnessLevel);
752: return self;
753: }
754:
755: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.