gdevsvga.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. /* Copyright (C) 1991, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
  2. This software is provided AS-IS with no warranty, either express or
  3. implied.
  4. This software is distributed under license and may not be copied,
  5. modified or distributed except as expressly authorized under the terms
  6. of the license contained in the file LICENSE in this distribution.
  7. For more information about licensing, please refer to
  8. http://www.ghostscript.com/licensing/. For information on
  9. commercial licensing, go to http://www.artifex.com/licensing/ or
  10. contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  11. San Rafael, CA 94903, U.S.A., +1(415)492-9861.
  12. */
  13. /* $Id: gdevsvga.c,v 1.6 2004/04/01 04:51:42 dan Exp $ */
  14. /* SuperVGA display drivers */
  15. #include "memory_.h"
  16. #include "gconfigv.h" /* for USE_ASM */
  17. #include "gx.h"
  18. #include "gserrors.h"
  19. #include "gxarith.h" /* for ...log2 */
  20. #include "gxdevice.h"
  21. #include "gdevpccm.h"
  22. #include "gdevpcfb.h"
  23. #include "gdevsvga.h"
  24. #include "gsparam.h"
  25. /* The color map for dynamically assignable colors. */
  26. #define first_dc_index 64
  27. private int next_dc_index;
  28. #define dc_hash_size 293 /* prime, >num_dc */
  29. typedef struct {
  30. ushort rgb, index;
  31. } dc_entry;
  32. private dc_entry dynamic_colors[dc_hash_size + 1];
  33. #define num_colors 255
  34. /* Macro for casting gx_device argument */
  35. #define fb_dev ((gx_device_svga *)dev)
  36. /* Procedure records */
  37. #define svga_procs(open) {\
  38. open, NULL /*get_initial_matrix*/,\
  39. NULL /*sync_output*/, NULL /*output_page*/, svga_close,\
  40. svga_map_rgb_color, svga_map_color_rgb,\
  41. svga_fill_rectangle, NULL /*tile_rectangle*/,\
  42. svga_copy_mono, svga_copy_color, NULL /*draw_line*/,\
  43. svga_get_bits, NULL /*get_params*/, svga_put_params,\
  44. NULL /*map_cmyk_color*/, NULL /*get_xfont_procs*/,\
  45. NULL /*get_xfont_device*/, NULL /*map_rgb_alpha_color*/,\
  46. gx_page_device_get_page_device, NULL /*get_alpha_bits*/,\
  47. svga_copy_alpha\
  48. }
  49. /* Save the controller mode */
  50. private int svga_save_mode = -1;
  51. /* ------ Internal routines ------ */
  52. #define regen 0xa000
  53. /* Construct a pointer for writing a pixel. */
  54. /* Assume 64K pages, 64K granularity. */
  55. /* We know that y is within bounds. */
  56. #define set_pixel_ptr(ptr, fbdev, x, y, wnum)\
  57. { ulong index = (ulong)(y) * fbdev->raster + (uint)(x);\
  58. if ( (uint)(index >> 16) != fbdev->current_page )\
  59. { (*fbdev->set_page)(fbdev, (fbdev->current_page = index >> 16), wnum);\
  60. }\
  61. ptr = (fb_ptr)MK_PTR(regen, (ushort)index);\
  62. }
  63. #define set_pixel_write_ptr(ptr, fbdev, x, y)\
  64. set_pixel_ptr(ptr, fbdev, x, y, fbdev->wnum_write)
  65. #define set_pixel_read_ptr(ptr, fbdev, x, y)\
  66. set_pixel_ptr(ptr, fbdev, x, y, fbdev->wnum_read)
  67. /* Find the graphics mode for a desired width and height. */
  68. /* Set the mode in the device structure and return 0, */
  69. /* or return an error code. */
  70. int
  71. svga_find_mode(gx_device * dev, const mode_info * mip)
  72. {
  73. for (;; mip++) {
  74. if (mip->width >= fb_dev->width &&
  75. mip->height >= fb_dev->height ||
  76. mip[1].mode < 0
  77. ) {
  78. fb_dev->mode = mip;
  79. gx_device_adjust_resolution(dev, mip->width, mip->height, 1);
  80. fb_dev->raster = fb_dev->width;
  81. return 0;
  82. }
  83. }
  84. return_error(gs_error_rangecheck);
  85. }
  86. /* Set the index for writing into the color DAC. */
  87. #define svga_dac_set_write_index(i) outportb(0x3c8, i)
  88. /* Write 6-bit R,G,B values into the color DAC. */
  89. #define svga_dac_write(r, g, b)\
  90. (outportb(0x3c9, r), outportb(0x3c9, g), outportb(0x3c9, b))
  91. /* ------ Common procedures ------ */
  92. #define cv_bits(v,n) (v >> (gx_color_value_bits - n))
  93. /* Initialize the dynamic color table, if any. */
  94. void
  95. svga_init_colors(gx_device * dev)
  96. {
  97. if (fb_dev->fixed_colors)
  98. next_dc_index = num_colors;
  99. else {
  100. memset(dynamic_colors, 0,
  101. (dc_hash_size + 1) * sizeof(dc_entry));
  102. next_dc_index = first_dc_index;
  103. }
  104. }
  105. /* Load the color DAC with the predefined colors. */
  106. private void
  107. svga_load_colors(gx_device * dev)
  108. {
  109. int ci;
  110. svga_dac_set_write_index(0);
  111. if (fb_dev->fixed_colors)
  112. for (ci = 0; ci < num_colors; ci++) {
  113. gx_color_value rgb[3];
  114. pc_8bit_map_color_rgb(dev, (gx_color_index) ci, rgb);
  115. svga_dac_write(cv_bits(rgb[0], 6), cv_bits(rgb[1], 6),
  116. cv_bits(rgb[2], 6));
  117. } else
  118. for (ci = 0; ci < 64; ci++) {
  119. static const byte c2[10] =
  120. {0, 42, 0, 0, 0, 0, 0, 0, 21, 63};
  121. svga_dac_write(c2[(ci >> 2) & 9], c2[(ci >> 1) & 9],
  122. c2[ci & 9]);
  123. }
  124. }
  125. /* Initialize the device structure and the DACs. */
  126. int
  127. svga_open(gx_device * dev)
  128. {
  129. fb_dev->x_pixels_per_inch =
  130. fb_dev->y_pixels_per_inch =
  131. fb_dev->height / PAGE_HEIGHT_INCHES;
  132. /* Set the display mode. */
  133. if (svga_save_mode < 0)
  134. svga_save_mode = (*fb_dev->get_mode) ();
  135. (*fb_dev->set_mode) (fb_dev->mode->mode);
  136. svga_init_colors(dev);
  137. svga_load_colors(dev);
  138. fb_dev->current_page = -1;
  139. return 0;
  140. }
  141. /* Close the device; reinitialize the display for text mode. */
  142. int
  143. svga_close(gx_device * dev)
  144. {
  145. if (svga_save_mode >= 0)
  146. (*fb_dev->set_mode) (svga_save_mode);
  147. svga_save_mode = -1;
  148. return 0;
  149. }
  150. /* Map a r-g-b color to a palette index. */
  151. /* The first 64 entries of the color map are set */
  152. /* for compatibility with the older display modes: */
  153. /* these are indexed as 0.0.R0.G0.B0.R1.G1.B1. */
  154. gx_color_index
  155. svga_map_rgb_color(gx_device * dev, const gx_color_value cv[])
  156. {
  157. ushort rgb;
  158. gx_color_value r = cv[0], g = cv[1], b = cv[2];
  159. if (fb_dev->fixed_colors) {
  160. gx_color_index ci = pc_8bit_map_rgb_color(dev, cv);
  161. /* Here is where we should permute the index to match */
  162. /* the old color map... but we don't yet. */
  163. return ci;
  164. } {
  165. ushort r5 = cv_bits(r, 5), g5 = cv_bits(g, 5), b5 = cv_bits(b, 5);
  166. static const byte cube_bits[32] =
  167. {0, 128, 128, 128, 128, 128, 128, 128, 128, 128,
  168. 8, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
  169. 1, 128, 128, 128, 128, 128, 128, 128, 128, 128,
  170. 9
  171. };
  172. uint cx = ((uint) cube_bits[r5] << 2) +
  173. ((uint) cube_bits[g5] << 1) +
  174. (uint) cube_bits[b5];
  175. /* Check for a color on the cube. */
  176. if (cx < 64)
  177. return (gx_color_index) cx;
  178. /* Not on the cube, check the dynamic color table. */
  179. rgb = (r5 << 10) + (g5 << 5) + b5;
  180. }
  181. {
  182. register dc_entry *pdc;
  183. for (pdc = &dynamic_colors[rgb % dc_hash_size];
  184. pdc->rgb != 0; pdc++
  185. )
  186. if (pdc->rgb == rgb)
  187. return (gx_color_index) (pdc->index);
  188. if (pdc == &dynamic_colors[dc_hash_size]) { /* Wraparound */
  189. for (pdc = &dynamic_colors[0]; pdc->rgb != 0; pdc++)
  190. if (pdc->rgb == rgb)
  191. return (gx_color_index) (pdc->index);
  192. }
  193. if (next_dc_index == num_colors) { /* No space left, report failure. */
  194. return gx_no_color_index;
  195. }
  196. /* Not on the cube, and not in the dynamic table. */
  197. /* Put in the dynamic table if space available. */
  198. {
  199. int i = next_dc_index++;
  200. pdc->rgb = rgb;
  201. pdc->index = i;
  202. svga_dac_set_write_index(i);
  203. svga_dac_write(cv_bits(r, 6), cv_bits(g, 6),
  204. cv_bits(b, 6));
  205. return (gx_color_index) i;
  206. }
  207. }
  208. }
  209. /* Map a color code to r-g-b. */
  210. /* This routine must invert the transformation of the one above. */
  211. /* Since this is practically never used, we just read the DAC. */
  212. int
  213. svga_map_color_rgb(gx_device * dev, gx_color_index color,
  214. gx_color_value prgb[3])
  215. {
  216. uint cval;
  217. outportb(0x3c7, (byte) color);
  218. #define dacin() (cval = inportb(0x3c9) >> 1,\
  219. ((cval << 11) + (cval << 6) + (cval << 1) + (cval >> 4)) >>\
  220. (16 - gx_color_value_bits))
  221. prgb[0] = dacin();
  222. prgb[1] = dacin();
  223. prgb[2] = dacin();
  224. #undef dacin
  225. return 0;
  226. }
  227. /* Fill a rectangle. */
  228. int
  229. svga_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
  230. gx_color_index color)
  231. {
  232. uint raster = fb_dev->raster;
  233. ushort limit = (ushort) - raster;
  234. int yi;
  235. fb_ptr ptr;
  236. fit_fill(dev, x, y, w, h);
  237. set_pixel_write_ptr(ptr, fb_dev, x, y);
  238. /* Most fills are very small and don't cross a page boundary. */
  239. yi = h;
  240. switch (w) {
  241. case 0:
  242. return 0; /* no-op */
  243. case 1:
  244. while (--yi >= 0 && PTR_OFF(ptr) < limit)
  245. ptr[0] = (byte) color,
  246. ptr += raster;
  247. if (!++yi)
  248. return 0;
  249. break;
  250. case 2:
  251. while (--yi >= 0 && PTR_OFF(ptr) < limit)
  252. ptr[0] = ptr[1] = (byte) color,
  253. ptr += raster;
  254. if (!++yi)
  255. return 0;
  256. break;
  257. case 3:
  258. while (--yi >= 0 && PTR_OFF(ptr) < limit)
  259. ptr[0] = ptr[1] = ptr[2] = (byte) color,
  260. ptr += raster;
  261. if (!++yi)
  262. return 0;
  263. break;
  264. case 4:
  265. while (--yi >= 0 && PTR_OFF(ptr) < limit)
  266. ptr[0] = ptr[1] = ptr[2] = ptr[3] = (byte) color,
  267. ptr += raster;
  268. if (!++yi)
  269. return 0;
  270. break;
  271. default:
  272. if (w < 0)
  273. return 0;
  274. /* Check for erasepage. */
  275. if (w == dev->width && h == dev->height &&
  276. color < first_dc_index
  277. )
  278. svga_init_colors(dev);
  279. }
  280. while (--yi >= 0) {
  281. if (PTR_OFF(ptr) < limit) {
  282. memset(ptr, (byte) color, w);
  283. ptr += raster;
  284. } else if (PTR_OFF(ptr) <= (ushort) (-w)) {
  285. memset(ptr, (byte) color, w);
  286. if (yi > 0)
  287. set_pixel_write_ptr(ptr, fb_dev, x, y + h - yi);
  288. } else {
  289. uint left = (uint) 0x10000 - PTR_OFF(ptr);
  290. memset(ptr, (byte) color, left);
  291. set_pixel_write_ptr(ptr, fb_dev, x + left, y + h - 1 - yi);
  292. memset(ptr, (byte) color, w - left);
  293. ptr += raster - left;
  294. }
  295. }
  296. return 0;
  297. }
  298. /* Copy a monochrome bitmap. The colors are given explicitly. */
  299. /* Color = gx_no_color_index means transparent (no effect on the image). */
  300. int
  301. svga_copy_mono(gx_device * dev,
  302. const byte * base, int sourcex, int sraster, gx_bitmap_id id,
  303. int x, int y, int w, int h, gx_color_index czero, gx_color_index cone)
  304. {
  305. uint raster = fb_dev->raster;
  306. ushort limit;
  307. register int wi;
  308. uint skip;
  309. int yi;
  310. register fb_ptr ptr = (fb_ptr) 0;
  311. const byte *srow;
  312. uint invert;
  313. fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
  314. limit = (ushort) - w;
  315. skip = raster - w + 1;
  316. srow = base + (sourcex >> 3);
  317. #define izero (int)czero
  318. #define ione (int)cone
  319. if (ione == no_color) {
  320. gx_color_index temp;
  321. if (izero == no_color)
  322. return 0; /* no-op */
  323. temp = czero;
  324. czero = cone;
  325. cone = temp;
  326. invert = ~0;
  327. } else
  328. invert = 0;
  329. /* Pre-filling saves us a test in the loop, */
  330. /* and since tiling is uncommon, we come out ahead. */
  331. if (izero != no_color)
  332. svga_fill_rectangle(dev, x, y, w, h, czero);
  333. for (yi = 0; yi < h; yi++) {
  334. const byte *sptr = srow;
  335. uint bits;
  336. int bitno = sourcex & 7;
  337. wi = w;
  338. if (PTR_OFF(ptr) <= skip) {
  339. set_pixel_write_ptr(ptr, fb_dev, x, y + yi);
  340. } else if (PTR_OFF(ptr) > limit) { /* We're crossing a page boundary. */
  341. /* This is extremely rare, so it doesn't matter */
  342. /* how slow it is. */
  343. int xi = (ushort) - PTR_OFF(ptr);
  344. svga_copy_mono(dev, srow, sourcex & 7, sraster,
  345. gx_no_bitmap_id, x, y + yi, xi, 1,
  346. gx_no_color_index, cone);
  347. set_pixel_write_ptr(ptr, fb_dev, x + xi, y + yi);
  348. sptr = srow - (sourcex >> 3) + ((sourcex + xi) >> 3);
  349. bitno = (sourcex + xi) & 7;
  350. wi -= xi;
  351. }
  352. bits = *sptr ^ invert;
  353. switch (bitno) {
  354. #define ifbit(msk)\
  355. if ( bits & msk ) *ptr = (byte)ione;\
  356. if ( !--wi ) break; ptr++
  357. case 0:
  358. bit0:ifbit(0x80);
  359. case 1:
  360. ifbit(0x40);
  361. case 2:
  362. ifbit(0x20);
  363. case 3:
  364. ifbit(0x10);
  365. case 4:
  366. ifbit(0x08);
  367. case 5:
  368. ifbit(0x04);
  369. case 6:
  370. ifbit(0x02);
  371. case 7:
  372. ifbit(0x01);
  373. #undef ifbit
  374. bits = *++sptr ^ invert;
  375. goto bit0;
  376. }
  377. ptr += skip;
  378. srow += sraster;
  379. }
  380. #undef izero
  381. #undef ione
  382. return 0;
  383. }
  384. /* Copy a color pixelmap. This is just like a bitmap, */
  385. /* except that each pixel takes 8 bits instead of 1. */
  386. int
  387. svga_copy_color(gx_device * dev,
  388. const byte * base, int sourcex, int sraster, gx_bitmap_id id,
  389. int x, int y, int w, int h)
  390. {
  391. int xi, yi;
  392. int skip;
  393. const byte *sptr;
  394. fb_ptr ptr;
  395. fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
  396. skip = sraster - w;
  397. sptr = base + sourcex;
  398. for (yi = y; yi - y < h; yi++) {
  399. ptr = 0;
  400. for (xi = x; xi - x < w; xi++) {
  401. if (PTR_OFF(ptr) == 0)
  402. set_pixel_write_ptr(ptr, fb_dev, xi, yi);
  403. *ptr++ = *sptr++;
  404. }
  405. sptr += skip;
  406. }
  407. return 0;
  408. }
  409. /* Put parameters. */
  410. int
  411. svga_put_params(gx_device * dev, gs_param_list * plist)
  412. {
  413. int ecode = 0;
  414. int code;
  415. const char *param_name;
  416. if ((code = ecode) < 0 ||
  417. (code = gx_default_put_params(dev, plist)) < 0
  418. ) {
  419. }
  420. return code;
  421. }
  422. /* Read scan lines back from the frame buffer. */
  423. int
  424. svga_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data)
  425. {
  426. uint bytes_per_row = dev->width;
  427. ushort limit = (ushort) - bytes_per_row;
  428. fb_ptr src;
  429. if (y < 0 || y >= dev->height)
  430. return gs_error_rangecheck;
  431. set_pixel_read_ptr(src, fb_dev, 0, y);
  432. /* The logic here is similar to fill_rectangle. */
  433. if (PTR_OFF(src) <= limit)
  434. memcpy(data, src, bytes_per_row);
  435. else {
  436. uint left = (uint) 0x10000 - PTR_OFF(src);
  437. memcpy(data, src, left);
  438. set_pixel_read_ptr(src, fb_dev, left, y);
  439. memcpy(data + left, src, bytes_per_row - left);
  440. }
  441. if (actual_data != 0)
  442. *actual_data = data;
  443. return 0;
  444. }
  445. /* Copy an alpha-map to the screen. */
  446. /* Depth is 1, 2, or 4. */
  447. private int
  448. svga_copy_alpha(gx_device * dev, const byte * base, int sourcex,
  449. int sraster, gx_bitmap_id id, int x, int y, int w, int h,
  450. gx_color_index color, int depth)
  451. {
  452. int xi, yi;
  453. int skip;
  454. const byte *sptr;
  455. byte mask;
  456. int ishift;
  457. /* We fake alpha by interpreting it as saturation, i.e., */
  458. /* alpha = 0 is white, alpha = 1 is the full color. */
  459. byte shades[16];
  460. gx_color_value rgb[3];
  461. int log2_depth = depth >> 1; /* works for 1,2,4 */
  462. int n1 = (1 << depth) - 1;
  463. fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
  464. shades[0] = (byte) svga_map_rgb_color(dev, gx_max_color_value,
  465. gx_max_color_value,
  466. gx_max_color_value);
  467. shades[n1] = (byte) color;
  468. if (n1 > 1) {
  469. memset(shades + 1, 255, n1 - 1);
  470. svga_map_color_rgb(dev, color, rgb);
  471. }
  472. skip = sraster - ((w * depth) >> 3);
  473. sptr = base + (sourcex >> (3 - log2_depth));
  474. mask = n1;
  475. ishift = (~sourcex & (7 >> log2_depth)) << log2_depth;
  476. for (yi = y; yi - y < h; yi++) {
  477. fb_ptr ptr = 0;
  478. int shift = ishift;
  479. for (xi = x; xi - x < w; xi++, ptr++) {
  480. uint a = (*sptr >> shift) & mask;
  481. if (PTR_OFF(ptr) == 0)
  482. set_pixel_write_ptr(ptr, fb_dev, xi, yi);
  483. map:if (a != 0) {
  484. byte ci = shades[a];
  485. if (ci == 255) { /* Map the color now. */
  486. #define make_shade(v, alpha, n1)\
  487. (gx_max_color_value -\
  488. ((ulong)(gx_max_color_value - (v)) * (alpha) / (n1)))
  489. gx_color_value r =
  490. make_shade(rgb[0], a, n1);
  491. gx_color_value g =
  492. make_shade(rgb[1], a, n1);
  493. gx_color_value b =
  494. make_shade(rgb[2], a, n1);
  495. gx_color_index sci =
  496. svga_map_rgb_color(dev, r, g, b);
  497. if (sci == gx_no_color_index) {
  498. a += (n1 + 1 - a) >> 1;
  499. goto map;
  500. }
  501. shades[a] = ci = (byte) sci;
  502. }
  503. *ptr = ci;
  504. }
  505. if (shift == 0)
  506. shift = 8 - depth, sptr++;
  507. else
  508. shift -= depth;
  509. }
  510. sptr += skip;
  511. }
  512. return 0;
  513. }
  514. /* ------ The VESA device ------ */
  515. private dev_proc_open_device(vesa_open);
  516. private const gx_device_procs vesa_procs = svga_procs(vesa_open);
  517. int vesa_get_mode(void);
  518. void vesa_set_mode(int);
  519. private void vesa_set_page(gx_device_svga *, int, int);
  520. gx_device_svga far_data gs_vesa_device =
  521. svga_device(vesa_procs, "vesa", vesa_get_mode, vesa_set_mode, vesa_set_page);
  522. /* Define the structures for information returned by the BIOS. */
  523. #define bits_include(a, m) !(~(a) & (m))
  524. /* Information about the BIOS capabilities. */
  525. typedef struct {
  526. byte vesa_signature[4]; /* "VESA" */
  527. ushort vesa_version;
  528. char *product_info; /* product name string */
  529. byte capabilities[4]; /* (undefined) */
  530. ushort *mode_list; /* supported video modes, -1 ends */
  531. } vga_bios_info;
  532. /* Information about an individual VESA mode. */
  533. typedef enum {
  534. m_supported = 1,
  535. m_graphics = 0x10
  536. } mode_attribute;
  537. typedef enum {
  538. w_supported = 1,
  539. w_readable = 2,
  540. w_writable = 4
  541. } win_attribute;
  542. typedef struct {
  543. ushort mode_attributes;
  544. byte win_a_attributes;
  545. byte win_b_attributes;
  546. ushort win_granularity;
  547. ushort win_size;
  548. ushort win_a_segment;
  549. ushort win_b_segment;
  550. void (*win_func_ptr) (int, int);
  551. ushort bytes_per_line;
  552. /* Optional information */
  553. ushort x_resolution;
  554. ushort y_resolution;
  555. byte x_char_size;
  556. byte y_char_size;
  557. byte number_of_planes;
  558. byte bits_per_pixel;
  559. byte number_of_banks;
  560. byte memory_model;
  561. byte bank_size;
  562. /* Padding to 256 bytes */
  563. byte _padding[256 - 29];
  564. } vesa_info;
  565. /* Read the device mode */
  566. int
  567. vesa_get_mode(void)
  568. {
  569. registers regs;
  570. regs.h.ah = 0x4f;
  571. regs.h.al = 0x03;
  572. int86(0x10, &regs, &regs);
  573. return regs.rshort.bx;
  574. }
  575. /* Set the device mode */
  576. void
  577. vesa_set_mode(int mode)
  578. {
  579. registers regs;
  580. regs.h.ah = 0x4f;
  581. regs.h.al = 0x02;
  582. regs.rshort.bx = mode;
  583. int86(0x10, &regs, &regs);
  584. }
  585. /* Read information about a device mode */
  586. private int
  587. vesa_get_info(int mode, vesa_info _ss * info)
  588. {
  589. registers regs;
  590. struct SREGS sregs;
  591. regs.h.ah = 0x4f;
  592. regs.h.al = 0x01;
  593. regs.rshort.cx = mode;
  594. segread(&sregs);
  595. sregs.es = sregs.ss;
  596. regs.rshort.di = PTR_OFF(info);
  597. int86x(0x10, &regs, &regs, &sregs);
  598. #ifdef DEBUG
  599. if (regs.h.ah == 0 && regs.h.al == 0x4f)
  600. dlprintf8("vesa_get_info(%x): ma=%x wa=%x/%x wg=%x ws=%x wseg=%x/%x\n",
  601. mode, info->mode_attributes,
  602. info->win_a_attributes, info->win_b_attributes,
  603. info->win_granularity, info->win_size,
  604. info->win_a_segment, info->win_b_segment);
  605. else
  606. dlprintf3("vesa_get_info(%x) failed: ah=%x al=%x\n",
  607. mode, regs.h.ah, regs.h.al);
  608. #endif
  609. return (regs.h.ah == 0 && regs.h.al == 0x4f ? 0 : -1);
  610. }
  611. /* Initialize the graphics mode. */
  612. /* Shared routine to look up a VESA-compatible BIOS mode. */
  613. private int
  614. vesa_find_mode(gx_device * dev, const mode_info * mode_table)
  615. { /* Select the proper video mode */
  616. vesa_info info;
  617. const mode_info *mip;
  618. for (mip = mode_table; mip->mode >= 0; mip++) {
  619. if (mip->width >= fb_dev->width &&
  620. mip->height >= fb_dev->height &&
  621. vesa_get_info(mip->mode, &info) >= 0 &&
  622. bits_include(info.mode_attributes,
  623. m_supported | m_graphics) &&
  624. info.win_granularity <= 64 &&
  625. (info.win_granularity & (info.win_granularity - 1)) == 0 &&
  626. info.win_size == 64 &&
  627. bits_include(info.win_a_attributes,
  628. w_supported) &&
  629. info.win_a_segment == regen
  630. ) { /* Make sure we can both read & write. */
  631. /* Initialize for the default case. */
  632. fb_dev->wnum_read = 0;
  633. fb_dev->wnum_write = 0;
  634. if (bits_include(info.win_a_attributes,
  635. w_readable | w_writable)
  636. )
  637. break;
  638. else if (info.win_b_segment == regen &&
  639. bits_include(info.win_b_attributes,
  640. w_supported) &&
  641. bits_include(info.win_a_attributes |
  642. info.win_b_attributes,
  643. w_readable | w_writable)
  644. ) { /* Two superimposed windows. */
  645. if (!bits_include(info.win_a_attributes,
  646. w_writable)
  647. )
  648. fb_dev->wnum_write = 1;
  649. else
  650. fb_dev->wnum_read = 1;
  651. }
  652. break;
  653. }
  654. }
  655. if (mip->mode < 0)
  656. return_error(gs_error_rangecheck); /* mode not available */
  657. fb_dev->mode = mip;
  658. gx_device_adjust_resolution(dev, mip->width, mip->height, 1);
  659. fb_dev->info.vesa.bios_set_page = info.win_func_ptr;
  660. fb_dev->info.vesa.pn_shift = ilog2(64 / info.win_granularity);
  661. /* Reset the raster per the VESA info. */
  662. fb_dev->raster = info.bytes_per_line;
  663. return 0;
  664. }
  665. private int
  666. vesa_open(gx_device * dev)
  667. {
  668. static const mode_info mode_table[] =
  669. {
  670. {640, 400, 0x100},
  671. {640, 480, 0x101},
  672. {800, 600, 0x103},
  673. {1024, 768, 0x105},
  674. {1280, 1024, 0x107},
  675. {-1, -1, -1}
  676. };
  677. int code = vesa_find_mode(dev, mode_table);
  678. if (code < 0)
  679. return code;
  680. return svga_open(dev);
  681. }
  682. /* Set the current display page. */
  683. private void
  684. vesa_set_page(gx_device_svga * dev, int pn, int wnum)
  685. {
  686. #if USE_ASM
  687. extern void vesa_call_set_page(void (*)(int, int), int, int);
  688. if (dev->info.vesa.bios_set_page != NULL)
  689. vesa_call_set_page(dev->info.vesa.bios_set_page, pn << dev->info.vesa.pn_shift, wnum);
  690. else
  691. #endif
  692. {
  693. registers regs;
  694. regs.rshort.dx = pn << dev->info.vesa.pn_shift;
  695. regs.h.ah = 0x4f;
  696. regs.h.al = 5;
  697. regs.rshort.bx = wnum;
  698. int86(0x10, &regs, &regs);
  699. }
  700. }
  701. /* ------ The ATI Wonder device ------ */
  702. private dev_proc_open_device(atiw_open);
  703. private const gx_device_procs atiw_procs = svga_procs(atiw_open);
  704. private int atiw_get_mode(void);
  705. private void atiw_set_mode(int);
  706. private void atiw_set_page(gx_device_svga *, int, int);
  707. gx_device_svga far_data gs_atiw_device =
  708. svga_device(atiw_procs, "atiw", atiw_get_mode, atiw_set_mode, atiw_set_page);
  709. /* Read the device mode */
  710. private int
  711. atiw_get_mode(void)
  712. {
  713. registers regs;
  714. regs.h.ah = 0xf;
  715. int86(0x10, &regs, &regs);
  716. return regs.h.al;
  717. }
  718. /* Set the device mode */
  719. private void
  720. atiw_set_mode(int mode)
  721. {
  722. registers regs;
  723. regs.h.ah = 0;
  724. regs.h.al = mode;
  725. int86(0x10, &regs, &regs);
  726. }
  727. /* Initialize the graphics mode. */
  728. private int
  729. atiw_open(gx_device * dev)
  730. { /* Select the proper video mode */
  731. {
  732. static const mode_info mode_table[] =
  733. {
  734. {640, 400, 0x61},
  735. {640, 480, 0x62},
  736. {800, 600, 0x63},
  737. {1024, 768, 0x64},
  738. {-1, -1, -1}
  739. };
  740. int code = svga_find_mode(dev, mode_table);
  741. if (code < 0)
  742. return code; /* mode not available */
  743. fb_dev->info.atiw.select_reg = *(int *)MK_PTR(0xc000, 0x10);
  744. return svga_open(dev);
  745. }
  746. }
  747. /* Set the current display page. */
  748. private void
  749. atiw_set_page(gx_device_svga * dev, int pn, int wnum)
  750. {
  751. int select_reg = dev->info.atiw.select_reg;
  752. byte reg;
  753. disable();
  754. outportb(select_reg, 0xb2);
  755. reg = inportb(select_reg + 1);
  756. outportb(select_reg, 0xb2);
  757. outportb(select_reg + 1, (reg & 0xe1) + (pn << 1));
  758. enable();
  759. }
  760. /* ------ The Trident device ------ */
  761. private dev_proc_open_device(tvga_open);
  762. private const gx_device_procs tvga_procs = svga_procs(tvga_open);
  763. /* We can use the atiw_get/set_mode procedures. */
  764. private void tvga_set_page(gx_device_svga *, int, int);
  765. gx_device_svga far_data gs_tvga_device =
  766. svga_device(tvga_procs, "tvga", atiw_get_mode, atiw_set_mode, tvga_set_page);
  767. /* Initialize the graphics mode. */
  768. private int
  769. tvga_open(gx_device * dev)
  770. {
  771. fb_dev->wnum_read = 1;
  772. fb_dev->wnum_write = 0;
  773. /* Select the proper video mode */
  774. {
  775. static const mode_info mode_table[] =
  776. {
  777. {640, 400, 0x5c},
  778. {640, 480, 0x5d},
  779. {800, 600, 0x5e},
  780. {1024, 768, 0x62},
  781. {-1, -1, -1}
  782. };
  783. int code = svga_find_mode(dev, mode_table);
  784. if (code < 0)
  785. return code; /* mode not available */
  786. return svga_open(dev);
  787. }
  788. }
  789. /* Set the current display page. */
  790. private void
  791. tvga_set_page(gx_device_svga * dev, int pn, int wnum)
  792. {
  793. /* new mode */
  794. outportb(0x3c4, 0x0b);
  795. inportb(0x3c4);
  796. outportb(0x3c4, 0x0e);
  797. outportb(0x3c5, pn ^ 2);
  798. }
  799. /* ------ The Tseng Labs ET3000/4000 devices ------ */
  800. private dev_proc_open_device(tseng_open);
  801. private const gx_device_procs tseng_procs =
  802. svga_procs(tseng_open);
  803. /* We can use the atiw_get/set_mode procedures. */
  804. private void tseng_set_page(gx_device_svga *, int, int);
  805. /* The 256-color Tseng device */
  806. gx_device_svga far_data gs_tseng_device =
  807. svga_device(tseng_procs, "tseng", atiw_get_mode, atiw_set_mode, tseng_set_page);
  808. /* Initialize the graphics mode. */
  809. private int
  810. tseng_open(gx_device * dev)
  811. {
  812. fb_dev->wnum_read = 1;
  813. fb_dev->wnum_write = 0;
  814. /* Select the proper video mode */
  815. {
  816. static const mode_info mode_table[] =
  817. {
  818. {640, 350, 0x2d},
  819. {640, 480, 0x2e},
  820. {800, 600, 0x30},
  821. {1024, 768, 0x38},
  822. {-1, -1, -1}
  823. };
  824. int code = svga_find_mode(dev, mode_table);
  825. volatile_fb_ptr p0 = (volatile_fb_ptr) MK_PTR(regen, 0);
  826. if (code < 0)
  827. return code; /* mode not available */
  828. code = svga_open(dev);
  829. if (code < 0)
  830. return 0;
  831. /* Figure out whether we have an ET3000 or an ET4000 */
  832. /* by playing with the segment register. */
  833. outportb(0x3cd, 0x44);
  834. *p0 = 4; /* byte 0, page 4 */
  835. outportb(0x3cd, 0x40);
  836. *p0 = 3; /* byte 0, page 0 */
  837. fb_dev->info.tseng.et_model = *p0;
  838. /* read page 0 if ET3000, */
  839. /* page 4 if ET4000 */
  840. return 0;
  841. }
  842. }
  843. /* Set the current display page. */
  844. private void
  845. tseng_set_page(gx_device_svga * dev, int pn, int wnum)
  846. { /* The ET3000 has read page = 5:3, write page = 2:0; */
  847. /* the ET4000 has read page = 7:4, write page = 3:0. */
  848. int shift = dev->info.tseng.et_model;
  849. int mask = (1 << shift) - 1;
  850. if (wnum)
  851. pn <<= shift, mask <<= shift;
  852. outportb(0x3cd, (inportb(0x3cd) & ~mask) + pn);
  853. }
  854. /* ------ The Cirrus device (CL-GD54XX) ------ */
  855. /* Written by Piotr Strzelczyk, BOP s.c., Gda\'nsk, Poland, */
  856. /* e-mail contact via B.Jackowski@GUST.org.pl */
  857. private dev_proc_open_device(cirr_open);
  858. private gx_device_procs cirr_procs = svga_procs(cirr_open);
  859. /* We can use the atiw_get/set_mode procedures. */
  860. private void cirr_set_page(gx_device_svga *, int, int);
  861. gx_device_svga gs_cirr_device =
  862. svga_device(cirr_procs, "cirr", atiw_get_mode, atiw_set_mode, cirr_set_page);
  863. /* Initialize the graphics mode. */
  864. private int
  865. cirr_open(gx_device * dev)
  866. {
  867. fb_dev->wnum_read = 1;
  868. fb_dev->wnum_write = 0;
  869. /* Select the proper video mode */
  870. {
  871. static const mode_info mode_table[] =
  872. {
  873. {640, 400, 0x5e},
  874. {640, 480, 0x5f},
  875. {800, 600, 0x5c},
  876. {1024, 768, 0x60},
  877. {-1, -1, -1}
  878. };
  879. int code = svga_find_mode(dev, mode_table);
  880. if (code < 0)
  881. return code; /* mode not available */
  882. outportb(0x3c4, 0x06);
  883. outportb(0x3c5, 0x12);
  884. outportb(0x3ce, 0x0b);
  885. outportb(0x3cf, (inportb(0x3cf) & 0xde));
  886. return svga_open(dev);
  887. }
  888. }
  889. /* Set the current display page. */
  890. private void
  891. cirr_set_page(gx_device_svga * dev, int pn, int wnum)
  892. {
  893. outportb(0x3ce, 0x09);
  894. outportb(0x3cf, pn << 4);
  895. }
  896. /* ------ The Avance Logic device (mostly experimental) ------ */
  897. /* For questions about this device, please contact Stefan Freund */
  898. /* <freund@ikp.uni-koeln.de>. */
  899. private dev_proc_open_device(ali_open);
  900. private const gx_device_procs ali_procs = svga_procs(ali_open);
  901. /* We can use the atiw_get/set_mode procedures. */
  902. private void ali_set_page(gx_device_svga *, int, int);
  903. /* The 256-color Avance Logic device */
  904. gx_device_svga gs_ali_device =
  905. svga_device(ali_procs, "ali", atiw_get_mode, atiw_set_mode,
  906. ali_set_page);
  907. /* Initialize the graphics mode. */
  908. private int
  909. ali_open(gx_device * dev)
  910. {
  911. fb_dev->wnum_read = 1;
  912. fb_dev->wnum_write = 0;
  913. /* Select the proper video mode */
  914. {
  915. static const mode_info mode_table[] =
  916. {
  917. {640, 400, 0x29},
  918. {640, 480, 0x2a},
  919. {800, 600, 0x2c},
  920. {1024, 768, 0x31},
  921. {-1, -1, -1}
  922. };
  923. int code = svga_find_mode(dev, mode_table);
  924. if (code < 0)
  925. return code; /* mode not available */
  926. return svga_open(dev);
  927. }
  928. }
  929. /* Set the current display page. */
  930. private void
  931. ali_set_page(gx_device_svga * dev, int pn, int wnum)
  932. {
  933. outportb(0x3d6, pn); /* read */
  934. outportb(0x3d7, pn); /* write */
  935. }