1 /*
2 At3d (at25) driver - Matan Ziv-Av zivav@cs.bgu.ac.il
3 please report problems to me,
4 
5 If you have an alliance promotion 6422, it should
6 be easy to make the driver work on it.
7 
8 This driver is based on the XFREE86 apm driver, developed by
9 Kent Hamilton and by Henrik Harmsen.
10 
11 I used the file cirrus.c in this directory as a skeleton.
12 
13 there are still the following problems:
14   * pageflipping (in threeDKit) does not work.
15   * no acceleration (is there a program that uses it anyway?).
16   * The clocks for 320x200 modes are _not easy_ for the driver.
17     if you have a problem with those modes, please contact me.
18   * 24 bits modes don't work on AT24.
19 
20 */
21 
22 
23 #include <stdlib.h>
24 #include <stdio.h>		/* for printf */
25 #include <string.h>		/* for memset */
26 #include <unistd.h>
27 #include "vga.h"
28 #include "libvga.h"
29 #include "driver.h"
30 
31 
32 /* New style driver interface. */
33 #include "timing.h"
34 #include "vgaregs.h"
35 #include "interface.h"
36 #include "accel.h"
37 
38 #define APMREG_SAVE(i) (VGA_TOTAL_REGS+i)
39 #define APM_TOTAL_REGS (VGA_TOTAL_REGS + 38)
40 
41 
42 static int apm_init(int, int, int);
43 static void apm_unlock(void);
44 
45 void __svgalib_apmaccel_init(AccelSpecs * accelspecs, int bpp, int width_in_pixels);
46 
47 static int apm_memory,apm_chiptype;
48 static int apm_is_linear,apm_xbase;
49 
50 static CardSpecs *cardspecs;
51 
outXR(int index,unsigned char d)52 static void outXR(int index,unsigned char d)
53 {
54     __svgalib_outbSR(0x1d,index>>2);
55     outb(apm_xbase,d);
56 }
57 
outwXR(int index,unsigned short d)58 static void outwXR(int index,unsigned short d)
59 {
60     __svgalib_outbSR(0x1d,index>>2);
61     outw(apm_xbase,d);
62 }
63 
outlXR(int index,unsigned long d)64 static void outlXR(int index,unsigned long d)
65 {
66     __svgalib_outbSR(0x1d,index>>2);
67     outl(apm_xbase,d);
68 }
69 
inXR(int index)70 static unsigned char inXR(int index)
71 {
72     __svgalib_outbSR(0x1d,index>>2);
73     return inb(apm_xbase);
74 }
75 
76 #if 0
77 /* currently not used */
78 static unsigned short inwXR(int index)
79 {
80     __svgalib_outbSR(0x1d,index>>2);
81     return inw(apm_xbase);
82 }
83 #endif
84 
inlXR(int index)85 static unsigned long inlXR(int index)
86 {
87     __svgalib_outbSR(0x1d,index>>2);
88     return inl(apm_xbase);
89 }
90 
91 enum {
92     AT6420 = 0, AT6422, AT24, AT3D
93 };
94 
apm_setpage(int page)95 static void apm_setpage(int page)
96 {
97     /* default 4K granularity */
98 outwXR(0xc0,page << 4);
99 }
100 
__svgalib_apm_inlinearmode(void)101 static int __svgalib_apm_inlinearmode(void)
102 {
103 return apm_is_linear;
104 }
105 
106 /* Fill in chipset specific mode information */
107 
apm_getmodeinfo(int mode,vga_modeinfo * modeinfo)108 static void apm_getmodeinfo(int mode, vga_modeinfo *modeinfo)
109 {
110 
111     if(modeinfo->colors==16)return;
112 
113 	modeinfo->maxpixels = apm_memory*1024/modeinfo->bytesperpixel;
114     modeinfo->maxlogicalwidth = 4088;
115 	modeinfo->startaddressrange = apm_memory * 1024 - 1;
116 	modeinfo->haveblit = 0;
117     modeinfo->flags &= ~HAVE_RWPAGE;
118 
119     if (modeinfo->bytesperpixel >= 1) {
120 	modeinfo->flags |= CAPABLE_LINEAR;
121         if (__svgalib_apm_inlinearmode())
122 	    modeinfo->flags |= IS_LINEAR;
123     }
124 }
125 
126 /* Read and save chipset-specific registers */
127 
apm_saveregs(unsigned char regs[])128 static int apm_saveregs(unsigned char regs[])
129 { unsigned long k;
130 
131     apm_unlock();		/* May be locked again by other programs (e.g. X) */
132     regs[APMREG_SAVE(2)] = __svgalib_inCR(0x19);
133     regs[APMREG_SAVE(3)] = __svgalib_inCR(0x1A);
134     regs[APMREG_SAVE(4)] = __svgalib_inCR(0x1B);
135     regs[APMREG_SAVE(5)] = __svgalib_inCR(0x1C);
136     regs[APMREG_SAVE(6)] = __svgalib_inCR(0x1D);
137     regs[APMREG_SAVE(7)] = __svgalib_inCR(0x1E);
138 
139     regs[APMREG_SAVE(0)] = __svgalib_inSR(0x1B);
140     regs[APMREG_SAVE(1)] = __svgalib_inSR(0x1C);
141 
142    regs[APMREG_SAVE(8)] = inXR(0x80) ;
143    regs[APMREG_SAVE(9)] = inXR(0xc0) ;
144    k = inlXR(0xe8) ;
145    regs[APMREG_SAVE(10)] = k&0xff;
146    regs[APMREG_SAVE(11)] = (k >> 8)&0xff;
147    regs[APMREG_SAVE(12)] = (k >> 16) & 0xff ;
148    regs[APMREG_SAVE(13)] = ( k >> 24 ) & 0xff ;
149    k = inlXR(0xec) ;
150    regs[APMREG_SAVE(14)] = k&0xff;
151    regs[APMREG_SAVE(15)] = (k >> 8)&0xff;
152    regs[APMREG_SAVE(16)] = (k >> 16) & 0xff ;
153    regs[APMREG_SAVE(17)] = ( k >> 24 ) & 0xff ;
154 regs[APMREG_SAVE(18)] = inlXR(0xf0) ;
155 regs[APMREG_SAVE(22)] = inlXR(0xf4) ;
156 regs[APMREG_SAVE(26)] = inlXR(0x140) ;
157 regs[APMREG_SAVE(30)] = inlXR(0x144) ;
158 regs[APMREG_SAVE(32)] = inXR(0x148) ;
159 regs[APMREG_SAVE(36)] = inXR(0x14c) ;
160 
161     return APM_TOTAL_REGS - VGA_TOTAL_REGS;
162 }
163 
164 /* Set chipset-specific registers */
165 
apm_setregs(const unsigned char regs[],int mode)166 static void apm_setregs(const unsigned char regs[], int mode)
167 {  unsigned long k ;
168 
169     apm_unlock();		/* May be locked again by other programs (eg. X) */
170     apm_setpage(0);
171 
172     __svgalib_outSR(0x1b,regs[APMREG_SAVE(0)]);
173     __svgalib_outSR(0x1c,regs[APMREG_SAVE(1)]);
174     __svgalib_outCR(0x19,regs[APMREG_SAVE(2)]);
175     __svgalib_outCR(0x1a,regs[APMREG_SAVE(3)]);
176     __svgalib_outCR(0x1b,regs[APMREG_SAVE(4)]);
177     __svgalib_outCR(0x1c,regs[APMREG_SAVE(5)]);
178     __svgalib_outCR(0x1d,regs[APMREG_SAVE(6)]);
179     __svgalib_outCR(0x1e,regs[APMREG_SAVE(7)]);
180 
181    if(apm_chiptype==AT3D) {
182      k=regs[APMREG_SAVE(10)]+(regs[APMREG_SAVE(11)] << 8)+(regs[APMREG_SAVE(12)] << 16)+(regs[APMREG_SAVE(13)] << 24);
183      outlXR(0xe8,k) ;
184    };
185 
186    k=regs[APMREG_SAVE(14)]+(regs[APMREG_SAVE(15)] << 8)+(regs[APMREG_SAVE(16)] << 16)+(regs[APMREG_SAVE(17)] << 24);
187    outlXR(0xec,k & ~(1 << 7)) ;
188    outlXR(0xec,k | (1 << 7)) ;
189 
190    outXR(0x80,regs[APMREG_SAVE(8)]) ;
191 
192 }
193 
194 
195 /* Return nonzero if mode is available */
196 
apm_modeavailable(int mode)197 static int apm_modeavailable(int mode)
198 {
199     struct info *info;
200     ModeTiming *modetiming;
201     ModeInfo *modeinfo;
202 
203     if ((mode < G640x480x256 )
204 	|| mode == G720x348x2)
205 	return __svgalib_vga_driverspecs.modeavailable(mode);
206 
207     info = &__svgalib_infotable[mode];
208     if (apm_memory * 1024 < info->ydim * info->xbytes)
209 	return 0;
210 
211     modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode);
212 
213     if((modeinfo->bitsPerPixel==24)&&(apm_chiptype==AT24)) {
214 	free(modeinfo);
215         return 0;
216     }
217 
218     modetiming = malloc(sizeof(ModeTiming));
219     if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) {
220 	free(modetiming);
221 	free(modeinfo);
222 	return 0;
223     }
224     free(modetiming);
225     free(modeinfo);
226 
227     return SVGADRV;
228 }
229 
230 
231 static unsigned comp_lmn(unsigned clock) ;
232 /* Set a mode */
233 
234 /* Local, called by apm_setmode(). */
235 
apm_initializemode(unsigned char * moderegs,ModeTiming * modetiming,ModeInfo * modeinfo,int mode)236 static void apm_initializemode(unsigned char *moderegs,
237 			    ModeTiming * modetiming, ModeInfo * modeinfo, int mode)
238 { long k;
239 
240     apm_saveregs(moderegs);
241     __svgalib_setup_VGA_registers(moderegs, modetiming, modeinfo);
242 
243   {
244     int offset;
245     offset = modeinfo->lineWidth >> 3;
246     moderegs[0x13] = offset;
247     /* Bit 8 resides at CR1C bits 7:4. */
248     moderegs[APMREG_SAVE(5)] = (offset & 0xf00) >> 4;
249   }
250 
251   /* Set pixel depth. */
252   switch(modeinfo->bitsPerPixel)
253   {
254     case 8:
255          moderegs[APMREG_SAVE(8)] = 0x42;
256          break;
257     case 16:
258          moderegs[APMREG_SAVE(8)] = modeinfo->greenWeight+7;
259          break;
260     case 24:
261          moderegs[APMREG_SAVE(8)] = 0xe;
262          break;
263     case 32:
264          moderegs[APMREG_SAVE(8)] = 0x0f;
265          break;
266     default:
267          break;
268   }
269 
270   /*
271    * Enable VESA Super VGA memory organisation.
272    * Also enable Linear Addressing.
273    */
274     moderegs[APMREG_SAVE(0)] = 0;
275     moderegs[APMREG_SAVE(1)] = 21;
276   /* Set banking register to zero. */
277   moderegs[APMREG_SAVE(9)] = 0;
278 
279   /* Handle the CRTC overflow bits. */
280   {
281     unsigned char val;
282     /* Vertical Overflow. */
283     val = 0;
284     if ((modetiming->CrtcVTotal - 2) & 0x400)
285       val |= 0x01;
286     if ((modetiming->CrtcVDisplay - 1) & 0x400)
287       val |= 0x02;
288     /* VBlankStart is equal to VSyncStart + 1. */
289     if (modetiming->CrtcVSyncStart & 0x400)
290       val |= 0x04;
291     /* VRetraceStart is equal to VSyncStart + 1. */
292     if (modetiming->CrtcVSyncStart & 0x400)
293       val |= 0x08;
294     moderegs[APMREG_SAVE(3)] = val;
295 
296     /* Horizontal Overflow. */
297     val = 0;
298     if ((modetiming->CrtcHTotal / 8 - 5) & 0x100)
299       val |= 1;
300     if ((modetiming->CrtcHDisplay / 8 - 1) & 0x100)
301       val |= 2;
302     /* HBlankStart is equal to HSyncStart - 1. */
303     if ((modetiming->CrtcHSyncStart / 8 - 1) & 0x100)
304       val |= 4;
305     /* HRetraceStart is equal to HSyncStart. */
306     if ((modetiming->CrtcHSyncStart / 8) & 0x100)
307       val |= 8;
308     moderegs[APMREG_SAVE(4)] = val;
309   }
310   moderegs[APMREG_SAVE(7)]= 1;          /* disable autoreset feature */
311 
312     k = comp_lmn(modetiming->pixelClock);
313     if (k==0){
314        k = comp_lmn(modetiming->pixelClock*2);
315        if(k>0)moderegs[VGA_SR1] |= 8 ; /* Sequencer1 - clock halving */
316     };
317     moderegs[APMREG_SAVE(14)]=k&0xff;
318     moderegs[APMREG_SAVE(15)]=(k >> 8)&0xff;
319     moderegs[APMREG_SAVE(16)]=(k >> 16)&0xff;
320     moderegs[APMREG_SAVE(17)]=(k >> 24)&0xff;
321     moderegs[MIS] |= 0xc;
322 moderegs[MIS]=0xef;
323   /* Set up the RAMDAC registers. */
324 
325   if (modeinfo->bitsPerPixel > 8)
326     /* Get rid of white border. */
327     {moderegs[VGA_AR11] = 0;} else
328 { int p,q,r;
329 
330 moderegs[VGA_AR11]=0xff;
331 p=moderegs[1]+((moderegs[APMREG_SAVE(4)]&2)<<7);
332 moderegs[2]=p&0xff;
333 moderegs[APMREG_SAVE(4)]&=0xfd;
334 moderegs[APMREG_SAVE(4)]|=(p&0x100)>>7;
335 q=moderegs[4]+((moderegs[APMREG_SAVE(4)]&8)<<5);
336 r=moderegs[0]+4;
337 moderegs[3]&=0xe0;
338 moderegs[3]|=(r&0x1f);
339 moderegs[5]&=0x7f;
340 moderegs[5]|=(r&0x20)<<2;
341 
342 p=moderegs[0x12]+((moderegs[0x7]&2)<<7)+((moderegs[7]&0x40)<<3)+((moderegs[APMREG_SAVE(3)]&2)<<9);
343 moderegs[0x15]=p&0xff;
344 moderegs[0x7]&=0xf7;
345 moderegs[0x7]|=(p&0x100)>>5;
346 moderegs[0x9]&=0xdf;
347 moderegs[0x9]|=(p&0x200)>>4;
348 moderegs[APMREG_SAVE(3)]&=0xfb;
349 moderegs[APMREG_SAVE(3)]|=(p&0x400)>>7;
350 moderegs[0x16]=moderegs[6]+1;
351 }
352     moderegs[APMREG_SAVE(10)] = 0xe8;
353     moderegs[APMREG_SAVE(11)] = 0x01;
354     moderegs[APMREG_SAVE(12)] = 0x1f;
355     moderegs[APMREG_SAVE(13)] = 0x07;
356 
357 
358 apm_is_linear=0;
359 
360 return ;
361 
362 }
363 
364 
365 
apm_setmode(int mode,int prv_mode)366 static int apm_setmode(int mode, int prv_mode)
367 {
368     unsigned char *moderegs;
369     ModeTiming *modetiming;
370     ModeInfo *modeinfo;
371 
372     if ((mode < G640x480x256 /*&& mode != G320x200x256*/)
373 	|| mode == G720x348x2) {
374 
375 /*	__svgalib_clear_accelspecs(__svgalib_driverspecs->accelspecs);
376 */
377 	/* Let the standard VGA driver set standard VGA modes */
378 	/* But first reset an Cirrus extended register that */
379 	/* an old XFree86 Trident probe corrupts. */
380 	return __svgalib_vga_driverspecs.setmode(mode, prv_mode);
381     }
382     if (!apm_modeavailable(mode))
383 	return 1;
384 
385     modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode);
386 
387     modetiming = malloc(sizeof(ModeTiming));
388     if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) {
389 	free(modetiming);
390 	free(modeinfo);
391 	return 1;
392     }
393 
394     moderegs = malloc(APM_TOTAL_REGS);
395 
396     apm_initializemode(moderegs, modetiming, modeinfo, mode);
397     free(modetiming);
398 
399     __svgalib_setregs(moderegs);	/* Set standard regs. */
400     apm_setregs(moderegs, mode);	/* Set extended regs. */
401     free(moderegs);
402 
403     __svgalib_InitializeAcceleratorInterface(modeinfo);
404 
405 
406     free(modeinfo);
407     return 0;
408 }
409 
410 
411 /* Unlock chipset-specific registers */
412 
apm_unlock(void)413 static void apm_unlock(void)
414 {
415     int vgaIOBase, temp;
416 
417     vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
418     outb(vgaIOBase + 4, 0x11);
419     temp = inb(vgaIOBase + 5);
420     outb(vgaIOBase + 5, temp & 0x7F);
421 
422     __svgalib_outSR(0x10, 0x12);
423 }
424 
425 
426 /* Relock chipset-specific registers */
427 /* (currently not used) */
428 
apm_lock(void)429 static void apm_lock(void)
430 {
431 }
432 
433 
434 /* Indentify chipset, initialize and return non-zero if detected */
435 
apm_test(void)436 static int apm_test(void)
437 {
438     int     i;
439     int	    oldSEQ10;
440 
441 /* To remove annoying "unused..." warning
442     char    id_ap6420[] = "Pro6420";
443     char    id_ap6422[] = "Pro6422";
444 */
445     char    id_at24[]   = "Pro6424";
446     char    id_at3d[]   = "ProAT3D"; /* Yeah, the manual could have been
447                                         correct... */
448     char    idstring[]  = "       ";
449 
450     if ((getenv("IOPERM") == NULL) && (iopl(3) < 0)) {
451 	printf("svgalib(apm): Cannot get I/O permissions.\n");
452 	exit(-1);
453     }
454 
455     /*
456      * Warning! A fully compliant VGA will most probably interprete this as
457      * __svgalib_outbSR(0x00, 0x02), hence stop the sequencer, to play safe
458      * we keep the old setting.
459      */
460 
461     oldSEQ10 = __svgalib_inSR(0x10);
462     __svgalib_outSR(0x10, 0x12);
463 
464     for (i = 0; i < 7; i++)
465       idstring[i] = __svgalib_inSR(0x11+i);
466 
467     /* reset iopl, apm_init will raise it again */
468     if (getenv("IOPERM") == NULL)
469 	iopl(0);
470 
471     /*
472      * Just in case, restore any old setting & select SEQ00:
473      */
474     __svgalib_outSR(0x10, oldSEQ10);
475     __svgalib_inSR(0);
476 
477     if (!memcmp(id_at3d, idstring, 7) || !memcmp(id_at24,idstring,7))
478       { apm_init(0,0,0) ; return 1; }
479     return 0;
480 }
481 
482 
483 /* No r/w paging */
apm_setrdpage(int page)484 static void apm_setrdpage(int page)
485 {
486 }
apm_setwrpage(int page)487 static void apm_setwrpage(int page)
488 {
489 }
490 
491 
492 /* Set display start address (not for 16 color modes) */
493 /* Cirrus supports any address in video memory (up to 2Mb) */
494 
apm_setdisplaystart(int address)495 static void apm_setdisplaystart(int address)
496 {  int i;
497   outw(0x3d4, (address & 0x00FF00) | 0x0C);
498   outw(0x3d4, ((address & 0x00FF) << 8) | 0x0D);
499 
500   /*
501    * Here the high-order bits are masked and shifted, and put into
502    * the appropriate extended registers.
503    */
504    outb(0x3d4,0x1c);
505    i=(inb(0x3d5)&0xf0)|((address & 0x0f0000) >> 16);
506    __svgalib_outCR(0x1c,i);
507 /*  modinx(vgaIOBase + 4, 0x1c, 0x0f, (address & 0x0f0000) >> 16); */
508 
509 }
510 
511 
512 /* Set logical scanline length (usually multiple of 8) */
513 /* Cirrus supports multiples of 8, up to 4088 */
514 
apm_setlogicalwidth(int width)515 static void apm_setlogicalwidth(int width)
516 {
517 }
518 
apm_linear(int op,int param)519 static int apm_linear(int op, int param)
520 {
521 if (op==LINEAR_ENABLE || op==LINEAR_DISABLE){ apm_is_linear=1-apm_is_linear; return 0;}
522 if (op==LINEAR_QUERY_BASE) {__svgalib_outSR(0x1d,0x193>>2); return inb(apm_xbase+3)<<24 ;}
523 if (op == LINEAR_QUERY_RANGE || op == LINEAR_QUERY_GRANULARITY) return 0;		/* No granularity or range. */
524     else return -1;		/* Unknown function. */
525 }
526 
apm_match_programmable_clock(int clock)527 static int apm_match_programmable_clock(int clock)
528 {
529 return clock ;
530 }
apm_map_clock(int bpp,int clock)531 static int apm_map_clock(int bpp, int clock)
532 {
533 return clock ;
534 }
apm_map_horizontal_crtc(int bpp,int pixelclock,int htiming)535 static int apm_map_horizontal_crtc(int bpp, int pixelclock, int htiming)
536 {
537 return htiming;
538 }
539 /* Function table (exported) */
540 
541 DriverSpecs __svgalib_apm_driverspecs =
542 {
543     apm_saveregs,
544     apm_setregs,
545     apm_unlock,
546     apm_lock,
547     apm_test,
548     apm_init,
549     apm_setpage,
550     apm_setrdpage,
551     apm_setwrpage,
552     apm_setmode,
553     apm_modeavailable,
554     apm_setdisplaystart,
555     apm_setlogicalwidth,
556     apm_getmodeinfo,
557     0,				/* old blit funcs */
558     0,
559     0,
560     0,
561     0,
562     0,				/* ext_set */
563     0,				/* accel */
564     apm_linear,
565     0,				/* accelspecs, filled in during init. */
566     NULL,                       /* Emulation */
567 };
568 
569 /* Initialize chipset (called after detection) */
570 
apm_init(int force,int par1,int par2)571 static int apm_init(int force, int par1, int par2)
572 {
573         char    idstring[]  = "       ";
574 
575     /* Get I/O priviledge */
576     if ((getenv("IOPERM") == NULL) && (iopl(3) < 0)) {
577 	printf("svgalib(apm): Cannot get I/O permissions.\n");
578 	exit(-1);
579     }
580 
581     apm_unlock();
582     if (force) {
583 	apm_memory = par1;
584 	apm_chiptype = par2;
585     } else {
586         int     i;
587         char    id_ap6420[] = "Pro6420";
588         char    id_ap6422[] = "Pro6422";
589         char    id_at24[]   = "Pro6424";
590         char    id_at3d[]   = "ProAT3D"; /* Yeah, the manual could have been
591                                         correct... */
592 
593         __svgalib_outSR(0x10, 0x12);
594 
595         for (i = 0; i < 7; i++)
596                idstring[i] = __svgalib_inSR(0x11+i);
597         if (!memcmp(id_ap6420, idstring, 7))
598            {
599          	apm_chiptype=AT6420;
600                 return 1;
601            }
602         else if (!memcmp(id_ap6422, idstring, 7))
603            {
604          	apm_chiptype=AT6422;
605                 return 1;
606            }
607         else if (!memcmp(id_at24, idstring, 7))
608            {
609          	apm_chiptype=AT24;
610            }
611         else if (!memcmp(id_at3d, idstring, 7))
612            {
613            	apm_chiptype=AT3D;
614            }
615         /*else return 1;*/
616         apm_memory=__svgalib_inSR(0x20)*64-34; /* maybe will support accel some day */
617     };
618     if (__svgalib_driver_report) {
619 	printf("Using Alliance driver, %.7s, %iKB.\n",idstring, apm_memory);
620     }
621 
622     apm_xbase= (__svgalib_inSR(0x1f) << 8 ) + __svgalib_inSR(0x1e);
623 
624     cardspecs = malloc(sizeof(CardSpecs));
625     cardspecs->videoMemory = apm_memory;
626     cardspecs->maxPixelClock4bpp = 75000;
627     cardspecs->maxPixelClock8bpp = 175500;
628     if(apm_chiptype==AT24)cardspecs->maxPixelClock8bpp = 160000;
629     cardspecs->maxPixelClock16bpp = 144000;
630     cardspecs->maxPixelClock24bpp = 75000;
631     cardspecs->maxPixelClock32bpp = 94500;
632     cardspecs->flags = CLOCK_PROGRAMMABLE | INTERLACE_DIVIDE_VERT;
633     cardspecs->maxHorizontalCrtc = 4088;
634     cardspecs->maxPixelClock4bpp = 0;
635     cardspecs->nClocks =0;
636     cardspecs->clocks = NULL;
637     cardspecs->mapClock = apm_map_clock;
638     cardspecs->mapHorizontalCrtc = apm_map_horizontal_crtc;
639     cardspecs->matchProgrammableClock=apm_match_programmable_clock;
640     __svgalib_driverspecs = &__svgalib_apm_driverspecs;
641     __svgalib_banked_mem_base=0xa0000;
642     __svgalib_banked_mem_size=0x10000;
643     __svgalib_outSR(0x1d,0x193>>2);
644     __svgalib_linear_mem_base=inb(apm_xbase+3)<<24 ;
645     __svgalib_linear_mem_size=apm_memory*0x400;
646     return 0;
647 }
648 
649 #define WITHIN(v,c1,c2) (((v) >= (c1)) && ((v) <= (c2)))
650 
651 static unsigned
comp_lmn(unsigned clock)652 comp_lmn(unsigned clock)
653 {
654   int     n, m, l, f;
655   double  fvco;
656   double  fout;
657   double  fmax;
658   double  fref;
659   double  fvco_goal;
660   double  k, c;
661 
662     if(apm_chiptype==AT3D)fmax = 400000.0; else fmax=265000.0;
663 /* The XFree86 driver says the max for AT24 is 250000,
664    but there is a much use clock (65MHZ), that is use 260000 fvco,
665    and the VESA bios on the card uses this clock, upped the max */
666 
667   fref = 14318.0;
668 
669   for (m = 1; m <= 5; m++)
670   {
671     for (l = 3; l >= 0; l--)
672     {
673       for (n = 8; n <= 127; n++)
674       {
675         fout = ((double)(n + 1) * fref)/((double)(m + 1) * (1 << l));
676         fvco_goal = (double)clock * (double)(1 << l);
677         fvco = fout * (double)(1 << l);
678         if (!WITHIN(fvco, 0.995*fvco_goal, 1.005*fvco_goal))
679           continue;
680         if (!WITHIN(fvco, 125000.0, fmax))
681           continue;
682         if (!WITHIN(fvco / (double)(n+1), 300.0, 300000.0))
683           continue;
684         if (!WITHIN(fref / (double)(m+1), 300.0, 300000.0))
685           continue;
686 
687         {
688           k = 7.0 / (175.0 - 380.0);
689           c = -k * 380.0;
690           f = (int)(k * fvco/1000.0 + c + 0.5);
691           if (f > 7) f = 7;
692           if (f < 0) f = 0;
693         }
694 /*printf("clock=%i l=%i f=%i m=%i n=%i\n",clock,l,f,m,n);*/
695         return (n << 16) | (m << 8) | (l << 2) | (f << 4);
696       }
697     }
698   }
699 /*printf("Can't do clock=%i\n",clock);*/
700   return 0;
701 }
702 
703 
704