vgamach64xx.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "../port/error.h"
  8. #define Image IMAGE
  9. #include <draw.h>
  10. #include <memdraw.h>
  11. #include <cursor.h>
  12. #include "screen.h"
  13. char Eunsupportedformat[] = "unsupported video format";
  14. char Enotconfigured[] = "device not configured";
  15. #define SCALE_ZERO_EXTEND 0x0
  16. #define SCALE_DYNAMIC 0x1
  17. #define SCALE_RED_TEMP_6500K 0x0
  18. #define SCALE_RED_TEMP_9800K 0x2
  19. #define SCALE_HORZ_BLEND 0x0
  20. #define SCALE_HORZ_REP 0x4
  21. #define SCALE_VERT_BLEND 0x0
  22. #define SCALE_VERT_REP 0x8
  23. #define SCALE_BANDWIDTH_NORMAL 0x0
  24. #define SCALE_BANDWIDTH_EXCEEDED 0x4000000
  25. #define SCALE_BANDWIDTH_RESET 0x4000000
  26. #define SCALE_CLK_ACTIVITY 0x0
  27. #define SCALE_CLK_CONTINUOUS 0x20000000
  28. #define OVERLAY_DISABLE 0x0
  29. #define OVERLAY_ENABLE 0x40000000
  30. #define SCALE_DISABLE 0x0
  31. #define SCALE_ENABLE 0x80000000
  32. #define SCALER_FRAME_READ_MODE_FULL 0x0
  33. #define SCALER_BUF_MODE_SINGLE 0x0
  34. #define SCALER_BUF_MODE_DOUBLE 0x40000
  35. #define SCALER_BUF_NEXT_0 0x0
  36. #define SCALER_BUF_NEXT_1 0x80000
  37. #define SCALER_BUF_STATUS_0 0x0
  38. #define SCALER_BUF_STATUS_1 0x100000
  39. #define OVERLAY_MIX_G_CMP 0x0
  40. #define OVERLAY_MIX_ALWAYS_G 0x100
  41. #define OVERLAY_MIX_ALWAYS_V 0x200
  42. #define OVERLAY_MIX_NOT_G 0x300
  43. #define OVERLAY_MIX_NOT_V 0x400
  44. #define OVERLAY_MIX_G_XOR_V 0x500
  45. #define OVERLAY_MIX_NOT_G_XOR_V 0x600
  46. #define OVERLAY_MIX_V_CMP 0x700
  47. #define OVERLAY_MIX_NOT_G_OR_NOT_V 0x800
  48. #define OVERLAY_MIX_G_OR_NOT_V 0x900
  49. #define OVERLAY_MIX_NOT_G_OR_V 0xA00
  50. #define OVERLAY_MIX_G_OR_V 0xB00
  51. #define OVERLAY_MIX_G_AND_V 0xC00
  52. #define OVERLAY_MIX_NOT_G_AND_V 0xD00
  53. #define OVERLAY_MIX_G_AND_NOT_V 0xE00
  54. #define OVERLAY_MIX_NOT_G_AND_NOT_V 0xF00
  55. #define OVERLAY_EXCLUSIVE_NORMAL 0x0
  56. #define OVERLAY_EXCLUSIVE_V_ONLY 0x80000000
  57. #define VIDEO_IN_8BPP 0x2
  58. #define VIDEO_IN_16BPP 0x4
  59. #define VIDEO_IN_32BPP 0x6
  60. #define VIDEO_IN_VYUY422 0xB /*16 bpp */
  61. #define VIDEO_IN_YVYU422 0xC /* 16 bpp */
  62. #define SCALE_IN_15BPP 0x30000 /* aRGB 1555 */
  63. #define SCALE_IN_16BPP 0x40000 /* RGB 565 */
  64. #define SCALE_IN_32BPP 0x60000 /* aRGB 8888 */
  65. #define SCALE_IN_YUV9 0x90000 /* planar */
  66. #define SCALE_IN_YUV12 0xA0000 /* planar */
  67. #define SCALE_IN_VYUY422 0xB0000 /* 16 bpp */
  68. #define SCALE_IN_YVYU422 0xC0000 /* 16 bpp */
  69. #define HOST_YUV_APERTURE_UPPER 0x0
  70. #define HOST_YUV_APERTURE_LOWER 0x20000000
  71. #define HOST_MEM_MODE_Y 0x40000000
  72. #define HOST_MEM_MODE_U 0x80000000
  73. #define HOST_MEM_MODE_V 0xC0000000
  74. #define HOST_MEM_MODE_NORMAL HOST_YUV_APERTURE_UPPER
  75. static Chan *ovl_chan; /* Channel of controlling process */
  76. static int ovl_width; /* Width of input overlay buffer */
  77. static int ovl_height; /* Height of input overlay buffer */
  78. static int ovl_format; /* Overlay format */
  79. static ulong ovl_fib; /* Frame in bytes */
  80. enum {
  81. VTGTB1S1 = 0x01, /* Asic description for VTB1S1 and GTB1S1. */
  82. VT4GTIIC = 0x3A, /* asic descr for VT4 and RAGE IIC */
  83. GTB1U1 = 0x19, /* Asic description for GTB1U1. */
  84. GTB1S2 = 0x41, /* Asic description for GTB1S2. */
  85. GTB2U1 = 0x1A,
  86. GTB2U2 = 0x5A,
  87. GTB2U3 = 0x9A,
  88. GTIIIC1U1 = 0x1B, /* 3D RAGE PRO asic descrp. */
  89. GTIIIC1U2 = 0x5B, /* 3D RAGE PRO asic descrp. */
  90. GTIIIC2U1 = 0x1C, /* 3D RAGE PRO asic descrp. */
  91. GTIIIC2U2 = 0x5C, /* 3D RAGE PRO asic descrp. */
  92. GTIIIC2U3 = 0x7C, /* 3D RAGE PRO asic descrp. */
  93. GTBC = 0x3A, /* 3D RAGE IIC asic descrp. */
  94. LTPRO = 0x9C, /* 3D RAGE LT PRO */
  95. };
  96. /*
  97. * ATI Mach64(CT|ET|G*|V*|L*).
  98. */
  99. typedef struct Mach64types Mach64types;
  100. struct Mach64types {
  101. ushort m64_id; /* Chip ID */
  102. int m64_vtgt; /* Is this a VT or GT chipset? */
  103. ulong m64_ovlclock; /* Max. overlay clock frequency */
  104. int m64_pro; /* Is this a PRO? */
  105. };
  106. static ulong mach64refclock;
  107. static Mach64types *mach64type;
  108. static int mach64revb; /* Revision B or greater? */
  109. static ulong mach64overlay; /* Overlay buffer */
  110. static Mach64types mach64s[] = {
  111. ('C'<<8)|'T', 0, 1350000, /*?*/ 0, /* 4354: CT */
  112. ('E'<<8)|'T', 0, 1350000, /*?*/ 0, /* 4554: ET */
  113. ('G'<<8)|'B', 1, 1250000, 1, /* 4742: 264GT PRO */
  114. ('G'<<8)|'D', 1, 1250000, 1, /* 4744: 264GT PRO */
  115. ('G'<<8)|'I', 1, 1250000, 1, /* 4749: 264GT PRO */
  116. ('G'<<8)|'M', 0, 1350000, 0, /* 474D: Rage XL */
  117. ('G'<<8)|'P', 1, 1250000, 1, /* 4750: 264GT PRO */
  118. ('G'<<8)|'Q', 1, 1250000, 1, /* 4751: 264GT PRO */
  119. ('G'<<8)|'R', 1, 1250000, 1, /* 4752: */
  120. ('G'<<8)|'T', 1, 800000, 0, /* 4754: 264GT[B] */
  121. ('G'<<8)|'U', 1, 1000000, 0, /* 4755: 264GT DVD */
  122. ('G'<<8)|'V', 1, 1000000, 0, /* 4756: Rage2C */
  123. ('G'<<8)|'Z', 1, 1000000, 0, /* 475A: Rage2C */
  124. ('V'<<8)|'T', 1, 800000, 0, /* 5654: 264VT/GT/VTB */
  125. ('V'<<8)|'U', 1, 800000, 0, /* 5655: 264VT3 */
  126. ('V'<<8)|'V', 1, 1000000, 0, /* 5656: 264VT4 */
  127. ('L'<<8)|'B', 0, 1350000, 1, /* 4C42: Rage LTPro AGP */
  128. ('L'<<8)|'I', 0, 1350000, 0, /* 4C49: Rage LTPro AGP */
  129. ('L'<<8)|'M', 0, 1350000, 0, /* 4C4D: Rage Mobility */
  130. ('L'<<8)|'P', 0, 1350000, 1, /* 4C50: 264LT PRO */
  131. };
  132. static int hwfill(VGAscr*, Rectangle, ulong);
  133. static int hwscroll(VGAscr*, Rectangle, Rectangle);
  134. static void initengine(VGAscr*);
  135. static Pcidev*
  136. mach64xxpci(void)
  137. {
  138. Pcidev *p;
  139. int i;
  140. if((p = pcimatch(nil, 0x1002, 0)) == nil)
  141. return nil;
  142. for (i = 0; i != nelem(mach64s); i++)
  143. if (mach64s[i].m64_id == p->did) {
  144. mach64type = &mach64s[i];
  145. return p;
  146. }
  147. return nil;
  148. }
  149. static void
  150. mach64xxenable(VGAscr* scr)
  151. {
  152. Pcidev *p;
  153. if(scr->io)
  154. return;
  155. if(p = mach64xxpci()){
  156. scr->id = p->did;
  157. scr->pci = p;
  158. /*
  159. * The CT doesn't always have the I/O base address
  160. * in the PCI base registers. There is a way to find
  161. * it via the vendor-specific PCI config space but
  162. * this will do for now.
  163. */
  164. scr->io = p->mem[1].bar & ~0x03;
  165. if(scr->io == 0)
  166. scr->io = 0x2EC;
  167. }
  168. }
  169. static void
  170. mach64xxlinear(VGAscr* scr, int size, int)
  171. {
  172. ulong mmiophys;
  173. vgalinearpci(scr);
  174. if(scr->paddr == 0)
  175. return;
  176. /*
  177. * vgalinearpci sets framebuffer into write combining mode.
  178. * Because mmio register page is inside framebuffer space,
  179. * set it back to uncached.
  180. */
  181. mmiophys = scr->paddr + size - BY2PG;
  182. if(!waserror()){
  183. mtrr(mmiophys, BY2PG, "uc");
  184. poperror();
  185. }
  186. scr->mmio = (ulong*)((uchar*)scr->vaddr+size-1024);
  187. addvgaseg("mach64mmio", mmiophys, BY2PG);
  188. addvgaseg("mach64screen", scr->paddr, scr->apsize);
  189. }
  190. enum {
  191. CrtcOffPitch = 0x05,
  192. CrtcGenCtl = 0x07,
  193. CurClr0 = 0x0B, /* I/O Select */
  194. CurClr1 = 0x0C,
  195. CurOffset = 0x0D,
  196. CurHVposn = 0x0E,
  197. CurHVoff = 0x0F,
  198. BusCntl = 0x13,
  199. GenTestCntl = 0x19,
  200. CrtcHsyncDis = 0x04,
  201. CrtcVsyncDis = 0x08,
  202. ContextMask = 0x100, /* not accessible via I/O */
  203. FifoStat,
  204. GuiStat,
  205. DpFrgdClr,
  206. DpBkgdClr,
  207. DpWriteMask,
  208. DpMix,
  209. DpPixWidth,
  210. DpSrc,
  211. ClrCmpCntl,
  212. GuiTrajCntl,
  213. ScLeftRight,
  214. ScTopBottom,
  215. DstOffPitch,
  216. DstYX,
  217. DstHeightWidth,
  218. DstCntl,
  219. DstHeight,
  220. DstBresErr,
  221. DstBresInc,
  222. DstBresDec,
  223. SrcCntl,
  224. SrcHeight1Width1,
  225. SrcHeight2Width2,
  226. SrcYX,
  227. SrcWidth1,
  228. SrcYXstart,
  229. HostCntl,
  230. PatReg0,
  231. PatReg1,
  232. PatCntl,
  233. ScBottom,
  234. ScLeft,
  235. ScRight,
  236. ScTop,
  237. ClrCmpClr,
  238. ClrCmpMask,
  239. DpChainMask,
  240. SrcOffPitch,
  241. LcdIndex,
  242. LcdData,
  243. ClockCntl,
  244. OverlayScaleCntl,
  245. ConfigChipId,
  246. Buf0Pitch,
  247. ScalerBuf0Pitch,
  248. CaptureConfig,
  249. OverlayKeyCntl,
  250. ScalerColourCntl,
  251. ScalerHCoef0,
  252. ScalerHCoef1,
  253. ScalerHCoef2,
  254. ScalerHCoef3,
  255. ScalerHCoef4,
  256. VideoFormat,
  257. Buf0Offset,
  258. ScalerBuf0Offset,
  259. CrtcGenCntl,
  260. OverlayScaleInc,
  261. OverlayYX,
  262. OverlayYXEnd,
  263. ScalerHeightWidth,
  264. HTotalDisp,
  265. VTotalDisp,
  266. };
  267. enum {
  268. LCD_ConfigPanel = 0,
  269. LCD_GenCtrl,
  270. LCD_DstnCntl,
  271. LCD_HfbPitchAddr,
  272. LCD_HorzStretch,
  273. LCD_VertStretch,
  274. LCD_ExtVertStretch,
  275. LCD_LtGio,
  276. LCD_PowerMngmnt,
  277. LCD_ZvgPio,
  278. Nlcd,
  279. };
  280. #define Bank1 (-0x100) /* 1KB */
  281. static int mmoffset[] = {
  282. [HTotalDisp] 0x00,
  283. [VTotalDisp] 0x02,
  284. [CrtcOffPitch] 0x05,
  285. [CrtcGenCntl] 0x07,
  286. [CurClr0] 0x18,
  287. [CurClr1] 0x19,
  288. [CurOffset] 0x1A,
  289. [CurHVposn] 0x1B,
  290. [CurHVoff] 0x1C,
  291. [ClockCntl] 0x24,
  292. [BusCntl] 0x28,
  293. [LcdIndex] 0x29,
  294. [LcdData] 0x2A,
  295. [GenTestCntl] 0x34,
  296. [ConfigChipId] 0x38,
  297. [DstOffPitch] 0x40,
  298. [DstYX] 0x43,
  299. [DstHeight] 0x45,
  300. [DstHeightWidth] 0x46,
  301. [DstBresErr] 0x49,
  302. [DstBresInc] 0x4A,
  303. [DstBresDec] 0x4B,
  304. [DstCntl] 0x4C,
  305. [SrcOffPitch] 0x60,
  306. [SrcYX] 0x63,
  307. [SrcWidth1] 0x64,
  308. [SrcYXstart] 0x69,
  309. [SrcHeight1Width1] 0x66,
  310. [SrcHeight2Width2] 0x6C,
  311. [SrcCntl] 0x6D,
  312. [HostCntl] 0x90,
  313. [PatReg0] 0xA0,
  314. [PatReg1] 0xA1,
  315. [PatCntl] 0xA2,
  316. [ScLeft] 0xA8,
  317. [ScRight] 0xA9,
  318. [ScLeftRight] 0xAA,
  319. [ScTop] 0xAB,
  320. [ScBottom] 0xAC,
  321. [ScTopBottom] 0xAD,
  322. [DpBkgdClr] 0xB0,
  323. [DpFrgdClr] 0xB1,
  324. [DpWriteMask] 0xB2,
  325. [DpChainMask] 0xB3,
  326. [DpPixWidth] 0xB4,
  327. [DpMix] 0xB5,
  328. [DpSrc] 0xB6,
  329. [ClrCmpClr] 0xC0,
  330. [ClrCmpMask] 0xC1,
  331. [ClrCmpCntl] 0xC2,
  332. [FifoStat] 0xC4,
  333. [ContextMask] 0xC8,
  334. [GuiTrajCntl] 0xCC,
  335. [GuiStat] 0xCE,
  336. /* Bank1 */
  337. [OverlayYX] Bank1 + 0x00,
  338. [OverlayYXEnd] Bank1 + 0x01,
  339. [OverlayKeyCntl] Bank1 + 0x06,
  340. [OverlayScaleInc] Bank1 + 0x08,
  341. [OverlayScaleCntl] Bank1 + 0x09,
  342. [ScalerHeightWidth] Bank1 + 0x0A,
  343. [ScalerBuf0Offset] Bank1 + 0x0D,
  344. [ScalerBuf0Pitch] Bank1 + 0x0F,
  345. [VideoFormat] Bank1 + 0x12,
  346. [CaptureConfig] Bank1 + 0x14,
  347. [Buf0Offset] Bank1 + 0x20,
  348. [Buf0Pitch] Bank1 + 0x23,
  349. [ScalerColourCntl] Bank1 + 0x54,
  350. [ScalerHCoef0] Bank1 + 0x55,
  351. [ScalerHCoef1] Bank1 + 0x56,
  352. [ScalerHCoef2] Bank1 + 0x57,
  353. [ScalerHCoef3] Bank1 + 0x58,
  354. [ScalerHCoef4] Bank1 + 0x59,
  355. };
  356. static ulong
  357. ior32(VGAscr* scr, int r)
  358. {
  359. if(scr->io == 0x2EC || scr->io == 0x1C8)
  360. return inl((r<<10)+scr->io);
  361. if(r >= 0x100 && scr->mmio != nil)
  362. return scr->mmio[mmoffset[r]];
  363. return inl((mmoffset[r]<<2)+scr->io);
  364. }
  365. static void
  366. iow32(VGAscr* scr, int r, ulong l)
  367. {
  368. if(scr->io == 0x2EC || scr->io == 0x1C8)
  369. outl(((r)<<10)+scr->io, l);
  370. else if(r >= 0x100 && scr->mmio != nil)
  371. scr->mmio[mmoffset[r]] = l;
  372. else
  373. outl((mmoffset[r]<<2)+scr->io, l);
  374. }
  375. static ulong
  376. lcdr32(VGAscr *scr, ulong r)
  377. {
  378. ulong or;
  379. or = ior32(scr, LcdIndex);
  380. iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
  381. return ior32(scr, LcdData);
  382. }
  383. static void
  384. lcdw32(VGAscr *scr, ulong r, ulong v)
  385. {
  386. ulong or;
  387. or = ior32(scr, LcdIndex);
  388. iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F));
  389. iow32(scr, LcdData, v);
  390. }
  391. static void
  392. mach64xxcurdisable(VGAscr* scr)
  393. {
  394. ulong r;
  395. r = ior32(scr, GenTestCntl);
  396. iow32(scr, GenTestCntl, r & ~0x80);
  397. }
  398. static void
  399. mach64xxcurload(VGAscr* scr, Cursor* curs)
  400. {
  401. uchar *p;
  402. int i, y;
  403. ulong c, s, m, r;
  404. /*
  405. * Disable the cursor.
  406. */
  407. r = ior32(scr, GenTestCntl);
  408. iow32(scr, GenTestCntl, r & ~0x80);
  409. p = scr->vaddr;
  410. p += scr->storage;
  411. /*
  412. * Initialise the 64x64 cursor RAM array.
  413. * The cursor mode gives the following truth table:
  414. * p1 p0 colour
  415. * 0 0 Cursor Colour 0
  416. * 0 1 Cursor Colour 1
  417. * 1 0 Transparent
  418. * 1 1 Complement
  419. * Put the cursor into the top-right of the 64x64 array.
  420. */
  421. for(y = 0; y < 16; y++){
  422. for(i = 0; i < (64-16)/8; i++){
  423. *p++ = 0xAA;
  424. *p++ = 0xAA;
  425. }
  426. c = (curs->clr[2*y]<<8)|curs->clr[y*2 + 1];
  427. s = (curs->set[2*y]<<8)|curs->set[y*2 + 1];
  428. m = 0x00000000;
  429. for(i = 0; i < 16; i++){
  430. if(s & (1<<(15-i)))
  431. m |= 0x01<<(2*i);
  432. else if(c & (1<<(15-i))){
  433. /* nothing to do */
  434. }
  435. else
  436. m |= 0x02<<(2*i);
  437. }
  438. *p++ = m;
  439. *p++ = m>>8;
  440. *p++ = m>>16;
  441. *p++ = m>>24;
  442. }
  443. memset(p, 0xAA, (64-16)*16);
  444. /*
  445. * Set the cursor hotpoint and enable the cursor.
  446. */
  447. scr->offset = curs->offset;
  448. iow32(scr, GenTestCntl, 0x80|r);
  449. }
  450. static int
  451. ptalmostinrect(Point p, Rectangle r)
  452. {
  453. return p.x>=r.min.x && p.x<=r.max.x &&
  454. p.y>=r.min.y && p.y<=r.max.y;
  455. }
  456. /*
  457. * If necessary, translate the rectangle physr
  458. * some multiple of [dx dy] so that it includes p.
  459. * Return 1 if the rectangle changed.
  460. */
  461. static int
  462. screenpan(Point p, Rectangle *physr, int dx, int dy)
  463. {
  464. int d;
  465. if(ptalmostinrect(p, *physr))
  466. return 0;
  467. if(p.y < physr->min.y){
  468. d = physr->min.y - (p.y&~(dy-1));
  469. physr->min.y -= d;
  470. physr->max.y -= d;
  471. }
  472. if(p.y > physr->max.y){
  473. d = ((p.y+dy-1)&~(dy-1)) - physr->max.y;
  474. physr->min.y += d;
  475. physr->max.y += d;
  476. }
  477. if(p.x < physr->min.x){
  478. d = physr->min.x - (p.x&~(dx-1));
  479. physr->min.x -= d;
  480. physr->max.x -= d;
  481. }
  482. if(p.x > physr->max.x){
  483. d = ((p.x+dx-1)&~(dx-1)) - physr->max.x;
  484. physr->min.x += d;
  485. physr->max.x += d;
  486. }
  487. return 1;
  488. }
  489. static int
  490. mach64xxcurmove(VGAscr* scr, Point p)
  491. {
  492. int x, xo, y, yo;
  493. int dx;
  494. ulong off, pitch;
  495. /*
  496. * If the point we want to display is outside the current
  497. * screen rectangle, pan the screen to display it.
  498. *
  499. * We have to move in 64-bit chunks.
  500. */
  501. if(scr->gscreen->depth == 24)
  502. dx = (64*3)/24;
  503. else
  504. dx = 64 / scr->gscreen->depth;
  505. if(panning && screenpan(p, &physgscreenr, dx, 1)){
  506. off = (physgscreenr.min.y*Dx(scr->gscreen->r)+physgscreenr.min.x)/dx;
  507. pitch = Dx(scr->gscreen->r)/8;
  508. iow32(scr, CrtcOffPitch, (pitch<<22)|off);
  509. }
  510. p.x -= physgscreenr.min.x;
  511. p.y -= physgscreenr.min.y;
  512. /*
  513. * Mustn't position the cursor offscreen even partially,
  514. * or it disappears. Therefore, if x or y is -ve, adjust the
  515. * cursor presets instead. If y is negative also have to
  516. * adjust the starting offset.
  517. */
  518. if((x = p.x+scr->offset.x) < 0){
  519. xo = x;
  520. x = 0;
  521. }
  522. else
  523. xo = 0;
  524. if((y = p.y+scr->offset.y) < 0){
  525. yo = y;
  526. y = 0;
  527. }
  528. else
  529. yo = 0;
  530. iow32(scr, CurHVoff, ((64-16-yo)<<16)|(64-16-xo));
  531. iow32(scr, CurOffset, scr->storage/8 + (-yo*2));
  532. iow32(scr, CurHVposn, (y<<16)|x);
  533. return 0;
  534. }
  535. static void
  536. mach64xxcurenable(VGAscr* scr)
  537. {
  538. ulong r, storage;
  539. mach64xxenable(scr);
  540. if(scr->io == 0)
  541. return;
  542. r = ior32(scr, GenTestCntl);
  543. iow32(scr, GenTestCntl, r & ~0x80);
  544. iow32(scr, CurClr0, (Pwhite<<24)|(Pwhite<<16)|(Pwhite<<8)|Pwhite);
  545. iow32(scr, CurClr1, (Pblack<<24)|(Pblack<<16)|(Pblack<<8)|Pblack);
  546. /*
  547. * Find a place for the cursor data in display memory.
  548. * Must be 64-bit aligned.
  549. */
  550. storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+7)/8;
  551. iow32(scr, CurOffset, storage);
  552. scr->storage = storage*8;
  553. /*
  554. * Cursor goes in the top right corner of the 64x64 array
  555. * so the horizontal and vertical presets are 64-16.
  556. */
  557. iow32(scr, CurHVposn, (0<<16)|0);
  558. iow32(scr, CurHVoff, ((64-16)<<16)|(64-16));
  559. /*
  560. * Load, locate and enable the 64x64 cursor.
  561. */
  562. mach64xxcurload(scr, &arrow);
  563. mach64xxcurmove(scr, ZP);
  564. iow32(scr, GenTestCntl, 0x80|r);
  565. }
  566. static void
  567. waitforfifo(VGAscr *scr, int entries)
  568. {
  569. int x;
  570. x = 0;
  571. while((ior32(scr, FifoStat)&0xFF) > (0x8000>>entries) && x++ < 1000000)
  572. ;
  573. if(x >= 1000000)
  574. iprint("fifo %d stat %#.8lux %#.8lux scrio %#.8lux mmio %#p scr %#p pc %#p\n", entries, ior32(scr, FifoStat), scr->mmio[mmoffset[FifoStat]], scr->io, scr->mmio, scr, getcallerpc(&scr));
  575. }
  576. static void
  577. waitforidle(VGAscr *scr)
  578. {
  579. int x;
  580. waitforfifo(scr, 16);
  581. x = 0;
  582. while((ior32(scr, GuiStat)&1) && x++ < 1000000)
  583. ;
  584. if(x >= 1000000)
  585. iprint("idle stat %#.8lux %#.8lux scrio %#.8lux mmio %#p scr %#p pc %#p\n", ior32(scr, GuiStat), scr->mmio[mmoffset[GuiStat]], scr->io, scr->mmio, scr, getcallerpc(&scr));
  586. }
  587. static void
  588. resetengine(VGAscr *scr)
  589. {
  590. ulong x;
  591. x = ior32(scr, GenTestCntl);
  592. iow32(scr, GenTestCntl, x&~0x100);
  593. iow32(scr, GenTestCntl, x|0x100);
  594. iow32(scr, BusCntl, ior32(scr, BusCntl)|0x00A00000);
  595. }
  596. static void
  597. init_overlayclock(VGAscr *scr)
  598. {
  599. uchar *cc, save, pll_ref_div, pll_vclk_cntl, vclk_post_div,
  600. vclk_fb_div, ecp_div;
  601. int i;
  602. ulong dotclock;
  603. /* Taken from GLX */
  604. /* Get monitor dotclock, check for Overlay Scaler clock limit */
  605. cc = (uchar *)&scr->mmio[mmoffset[ClockCntl]];
  606. save = cc[1]; i = cc[0] & 3;
  607. cc[1] = 2<<2; pll_ref_div = cc[2];
  608. cc[1] = 5<<2; pll_vclk_cntl = cc[2];
  609. cc[1] = 6<<2; vclk_post_div = (cc[2]>>(i+i)) & 3;
  610. cc[1] = (7+i)<<2; vclk_fb_div = cc[2];
  611. dotclock = 2 * mach64refclock * vclk_fb_div /
  612. (pll_ref_div * (1 << vclk_post_div));
  613. /* ecp_div: 0=dotclock, 1=dotclock/2, 2=dotclock/4 */
  614. ecp_div = dotclock / mach64type->m64_ovlclock;
  615. if (ecp_div>2) ecp_div = 2;
  616. /* Force a scaler clock factor of 1 if refclock *
  617. * is unknown (VCLK_SRC not PLLVCLK) */
  618. if ((pll_vclk_cntl & 0x03) != 0x03)
  619. ecp_div = 0;
  620. if ((pll_vclk_cntl & 0x30) != ecp_div<<4) {
  621. cc[1] = (5<<2)|2;
  622. cc[2] = (pll_vclk_cntl&0xCF) | (ecp_div<<4);
  623. }
  624. /* Restore PLL Register Index */
  625. cc[1] = save;
  626. }
  627. static void
  628. initengine(VGAscr *scr)
  629. {
  630. ulong pitch;
  631. uchar *bios;
  632. ushort table;
  633. pitch = Dx(scr->gscreen->r)/8;
  634. if(scr->gscreen->depth == 24)
  635. pitch *= 3;
  636. resetengine(scr);
  637. waitforfifo(scr, 14);
  638. iow32(scr, ContextMask, ~0);
  639. iow32(scr, DstOffPitch, pitch<<22);
  640. iow32(scr, DstYX, 0);
  641. iow32(scr, DstHeight, 0);
  642. iow32(scr, DstBresErr, 0);
  643. iow32(scr, DstBresInc, 0);
  644. iow32(scr, DstBresDec, 0);
  645. iow32(scr, DstCntl, 0x23);
  646. iow32(scr, SrcOffPitch, pitch<<22);
  647. iow32(scr, SrcYX, 0);
  648. iow32(scr, SrcHeight1Width1, 1);
  649. iow32(scr, SrcYXstart, 0);
  650. iow32(scr, SrcHeight2Width2, 1);
  651. iow32(scr, SrcCntl, 0x01);
  652. waitforfifo(scr, 13);
  653. iow32(scr, HostCntl, 0);
  654. iow32(scr, PatReg0, 0);
  655. iow32(scr, PatReg1, 0);
  656. iow32(scr, PatCntl, 0);
  657. iow32(scr, ScLeft, 0);
  658. iow32(scr, ScTop, 0);
  659. iow32(scr, ScBottom, 0xFFFF);
  660. iow32(scr, ScRight, 0xFFFF);
  661. iow32(scr, DpBkgdClr, 0);
  662. iow32(scr, DpFrgdClr, ~0);
  663. iow32(scr, DpWriteMask, ~0);
  664. iow32(scr, DpMix, 0x70003);
  665. iow32(scr, DpSrc, 0x00010100);
  666. waitforfifo(scr, 3);
  667. iow32(scr, ClrCmpClr, 0);
  668. iow32(scr, ClrCmpMask, ~0);
  669. iow32(scr, ClrCmpCntl, 0);
  670. waitforfifo(scr, 2);
  671. switch(scr->gscreen->depth){
  672. case 8:
  673. case 24: /* [sic] */
  674. iow32(scr, DpPixWidth, 0x00020202);
  675. iow32(scr, DpChainMask, 0x8080);
  676. break;
  677. case 16:
  678. iow32(scr, DpPixWidth, 0x00040404);
  679. iow32(scr, DpChainMask, 0x8410);
  680. break;
  681. case 32:
  682. iow32(scr, DpPixWidth, 0x00060606);
  683. iow32(scr, DpChainMask, 0x8080);
  684. break;
  685. }
  686. /* Get the base freq from the BIOS */
  687. bios = kaddr(0xC000);
  688. table = *(ushort *)(bios + 0x48);
  689. table = *(ushort *)(bios + table + 0x10);
  690. switch (*(ushort *)(bios + table + 0x08)) {
  691. case 2700:
  692. mach64refclock = 270000;
  693. break;
  694. case 2863:
  695. case 2864:
  696. mach64refclock = 286363;
  697. break;
  698. case 2950:
  699. mach64refclock = 294989;
  700. break;
  701. case 1432:
  702. default:
  703. mach64refclock = 143181;
  704. break ;
  705. }
  706. /* Figure out which revision this chip is */
  707. switch ((scr->mmio[mmoffset[ConfigChipId]] >> 24) & 0xFF) {
  708. case VTGTB1S1:
  709. case GTB1U1:
  710. case GTB1S2:
  711. case GTB2U1:
  712. case GTB2U2:
  713. case GTB2U3:
  714. case GTBC:
  715. case GTIIIC1U1:
  716. case GTIIIC1U2:
  717. case GTIIIC2U1:
  718. case GTIIIC2U2:
  719. case GTIIIC2U3:
  720. case LTPRO:
  721. mach64revb = 1;
  722. break;
  723. default:
  724. mach64revb = 0;
  725. break;
  726. }
  727. waitforidle(scr);
  728. }
  729. static int
  730. mach64hwfill(VGAscr *scr, Rectangle r, ulong sval)
  731. {
  732. ulong pitch;
  733. ulong ctl;
  734. if(drawdebug)
  735. iprint("hwfill %R val %lux...\n", r, sval);
  736. /* shouldn't happen */
  737. if(scr->io == 0x2EC || scr->io == 0x1C8 || scr->io == 0)
  738. return 0;
  739. pitch = Dx(scr->gscreen->r)/8;
  740. ctl = 1|2; /* left-to-right, top-to-bottom */
  741. if(scr->gscreen->depth == 24){
  742. r.min.x *= 3;
  743. r.max.x *= 3;
  744. pitch *= 3;
  745. ctl |= (1<<7)|(((r.min.x/4)%6)<<8);
  746. }
  747. waitforfifo(scr, 11);
  748. iow32(scr, DpFrgdClr, sval);
  749. iow32(scr, DpWriteMask, 0xFFFFFFFF);
  750. iow32(scr, DpMix, 0x00070003);
  751. iow32(scr, DpSrc, 0x00000111);
  752. iow32(scr, ClrCmpCntl, 0x00000000);
  753. iow32(scr, ScLeftRight, 0x1FFF0000);
  754. iow32(scr, ScTopBottom, 0x1FFF0000);
  755. iow32(scr, DstOffPitch, pitch<<22);
  756. iow32(scr, DstCntl, ctl);
  757. iow32(scr, DstYX, (r.min.x<<16)|r.min.y);
  758. iow32(scr, DstHeightWidth, (Dx(r)<<16)|Dy(r));
  759. waitforidle(scr);
  760. return 1;
  761. }
  762. static int
  763. mach64hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
  764. {
  765. ulong pitch;
  766. Point dp, sp;
  767. ulong ctl;
  768. int dx, dy;
  769. dx = Dx(r);
  770. dy = Dy(r);
  771. pitch = Dx(scr->gscreen->r)/8;
  772. if(scr->gscreen->depth == 24){
  773. dx *= 3;
  774. pitch *= 3;
  775. r.min.x *= 3;
  776. sr.min.x *= 3;
  777. }
  778. ctl = 0;
  779. if(r.min.x <= sr.min.x){
  780. ctl |= 1;
  781. dp.x = r.min.x;
  782. sp.x = sr.min.x;
  783. }else{
  784. dp.x = r.min.x+dx-1;
  785. sp.x = sr.min.x+dx-1;
  786. }
  787. if(r.min.y <= sr.min.y){
  788. ctl |= 2;
  789. dp.y = r.min.y;
  790. sp.y = sr.min.y;
  791. }else{
  792. dp.y = r.min.y+dy-1;
  793. sp.y = sr.min.y+dy-1;
  794. }
  795. if(scr->gscreen->depth == 24)
  796. ctl |= (1<<7)|(((dp.x/4)%6)<<8);
  797. waitforfifo(scr, 6);
  798. iow32(scr, ScLeftRight, 0x1FFF0000);
  799. iow32(scr, ScTopBottom, 0x1FFF0000);
  800. iow32(scr, DpWriteMask, 0xFFFFFFFF);
  801. iow32(scr, DpMix, 0x00070003);
  802. iow32(scr, DpSrc, 0x00000300);
  803. iow32(scr, ClrCmpCntl, 0x00000000);
  804. waitforfifo(scr, 8);
  805. iow32(scr, SrcOffPitch, pitch<<22);
  806. iow32(scr, SrcCntl, 0x00000000);
  807. iow32(scr, SrcYX, (sp.x<<16)|sp.y);
  808. iow32(scr, SrcWidth1, dx);
  809. iow32(scr, DstOffPitch, pitch<<22);
  810. iow32(scr, DstCntl, ctl);
  811. iow32(scr, DstYX, (dp.x<<16)|dp.y);
  812. iow32(scr, DstHeightWidth, (dx<<16)|dy);
  813. waitforidle(scr);
  814. return 1;
  815. }
  816. /*
  817. * This should work, but doesn't.
  818. * It messes up the screen timings for some reason.
  819. */
  820. static void
  821. mach64blank(VGAscr *scr, int blank)
  822. {
  823. ulong ctl;
  824. ctl = ior32(scr, CrtcGenCtl) & ~(CrtcHsyncDis|CrtcVsyncDis);
  825. if(blank)
  826. ctl |= CrtcHsyncDis|CrtcVsyncDis;
  827. iow32(scr, CrtcGenCtl, ctl);
  828. }
  829. /*
  830. * We squirrel away whether the LCD and/or CRT were
  831. * on when we were called to blank the screen, and
  832. * restore the old state. If we are called to blank the
  833. * screen when it is already blank, we don't update the state.
  834. * Such a call sequence should not happen, though.
  835. *
  836. * We could try forcing the chip into power management
  837. * mode instead, but I'm not sure how that would interact
  838. * with screen updates going on while the screen is blanked.
  839. */
  840. static void
  841. mach64lcdblank(VGAscr *scr, int blank)
  842. {
  843. static int crtlcd;
  844. ulong x;
  845. if(blank) {
  846. x = lcdr32(scr, LCD_GenCtrl);
  847. if(x & 3) {
  848. crtlcd = x & 3;
  849. lcdw32(scr, LCD_GenCtrl, x&~3);
  850. }
  851. } else {
  852. if(crtlcd == 0)
  853. crtlcd = 2; /* lcd only */
  854. x = lcdr32(scr, LCD_GenCtrl);
  855. lcdw32(scr, LCD_GenCtrl, x | crtlcd);
  856. }
  857. }
  858. static void
  859. mach64xxdrawinit(VGAscr *scr)
  860. {
  861. if(scr->io > 0x2FF){
  862. initengine(scr);
  863. scr->fill = mach64hwfill;
  864. scr->scroll = mach64hwscroll;
  865. }
  866. /* scr->blank = mach64blank; */
  867. switch(scr->id){
  868. default:
  869. break;
  870. case ('L'<<8)|'B': /* 4C42: Rage 3D LTPro */
  871. case ('L'<<8)|'I': /* 4C49: Rage 3D LTPro */
  872. case ('L'<<8)|'M': /* 4C4D: Rage Mobility */
  873. case ('L'<<8)|'P': /* 4C50: Rage 3D LTPro */
  874. scr->blank = mach64lcdblank;
  875. hwblank = 1;
  876. break;
  877. }
  878. }
  879. static void
  880. ovl_configure(VGAscr *scr, Chan *c, char **field)
  881. {
  882. int w, h;
  883. char *format;
  884. w = (int)strtol(field[1], nil, 0);
  885. h = (int)strtol(field[2], nil, 0);
  886. format = field[3];
  887. if (c != ovl_chan)
  888. error(Einuse);
  889. if (strcmp(format, "YUYV"))
  890. error(Eunsupportedformat);
  891. ovl_width = w;
  892. ovl_height = h;
  893. ovl_fib = w * h * sizeof(ushort);
  894. waitforidle(scr);
  895. scr->mmio[mmoffset[BusCntl]] |= 0x08000000; /* Enable regblock 1 */
  896. scr->mmio[mmoffset[OverlayScaleCntl]] =
  897. SCALE_ZERO_EXTEND|SCALE_RED_TEMP_6500K|
  898. SCALE_HORZ_BLEND|SCALE_VERT_BLEND;
  899. scr->mmio[mmoffset[!mach64revb? Buf0Pitch: ScalerBuf0Pitch]] = w;
  900. scr->mmio[mmoffset[CaptureConfig]] =
  901. SCALER_FRAME_READ_MODE_FULL|
  902. SCALER_BUF_MODE_SINGLE|
  903. SCALER_BUF_NEXT_0;
  904. scr->mmio[mmoffset[OverlayKeyCntl]] = !mach64revb?
  905. OVERLAY_MIX_ALWAYS_V|(OVERLAY_EXCLUSIVE_NORMAL << 28):
  906. 0x011;
  907. if (mach64type->m64_pro) {
  908. waitforfifo(scr, 6);
  909. /* set the scaler co-efficient registers */
  910. scr->mmio[mmoffset[ScalerColourCntl]] =
  911. (0x00) | (0x10 << 8) | (0x10 << 16);
  912. scr->mmio[mmoffset[ScalerHCoef0]] =
  913. (0x00) | (0x20 << 8);
  914. scr->mmio[mmoffset[ScalerHCoef1]] =
  915. (0x0D) | (0x20 << 8) | (0x06 << 16) | (0x0D << 24);
  916. scr->mmio[mmoffset[ScalerHCoef2]] =
  917. (0x0D) | (0x1C << 8) | (0x0A << 16) | (0x0D << 24);
  918. scr->mmio[mmoffset[ScalerHCoef3]] =
  919. (0x0C) | (0x1A << 8) | (0x0E << 16) | (0x0C << 24);
  920. scr->mmio[mmoffset[ScalerHCoef4]] =
  921. (0x0C) | (0x14 << 8) | (0x14 << 16) | (0x0C << 24);
  922. }
  923. waitforfifo(scr, 3);
  924. scr->mmio[mmoffset[VideoFormat]] = SCALE_IN_YVYU422 |
  925. (!mach64revb? 0xC: 0);
  926. if (mach64overlay == 0)
  927. mach64overlay = scr->storage + 64 * 64 * sizeof(uchar);
  928. scr->mmio[mmoffset[!mach64revb? Buf0Offset: ScalerBuf0Offset]] =
  929. mach64overlay;
  930. }
  931. static void
  932. ovl_enable(VGAscr *scr, Chan *c, char **field)
  933. {
  934. int x, y, w, h;
  935. long h_inc, v_inc;
  936. x = (int)strtol(field[1], nil, 0);
  937. y = (int)strtol(field[2], nil, 0);
  938. w = (int)strtol(field[3], nil, 0);
  939. h = (int)strtol(field[4], nil, 0);
  940. if (x < 0 || x + w > physgscreenr.max.x ||
  941. y < 0 || y + h > physgscreenr.max.y)
  942. error(Ebadarg);
  943. if (c != ovl_chan)
  944. error(Einuse);
  945. if (scr->mmio[mmoffset[CrtcGenCntl]] & 1) { /* double scan enable */
  946. y *= 2;
  947. h *= 2;
  948. }
  949. waitforfifo(scr, 2);
  950. scr->mmio[mmoffset[OverlayYX]] =
  951. ((x & 0xFFFF) << 16) | (y & 0xFFFF);
  952. scr->mmio[mmoffset[OverlayYXEnd]] =
  953. (((x + w) & 0xFFFF) << 16) | ((y + h) & 0xFFFF);
  954. h_inc = (ovl_width << 12) / (w >> 1); /* ??? */
  955. v_inc = (ovl_height << 12) / h;
  956. waitforfifo(scr, 2);
  957. scr->mmio[mmoffset[OverlayScaleInc]] =
  958. ((h_inc & 0xFFFF) << 16) | (v_inc & 0xFFFF);
  959. scr->mmio[mmoffset[ScalerHeightWidth]] =
  960. ((ovl_width & 0xFFFF) << 16) | (ovl_height & 0xFFFF);
  961. waitforidle(scr);
  962. scr->mmio[mmoffset[OverlayScaleCntl]] |=
  963. (SCALE_ENABLE|OVERLAY_ENABLE);
  964. }
  965. static void
  966. ovl_status(VGAscr *scr, Chan *, char **field)
  967. {
  968. pprint("%s: %s %.4uX, VT/GT %s, PRO %s, ovlclock %lud, rev B %s, refclock %ld\n",
  969. scr->dev->name, field[0], mach64type->m64_id,
  970. mach64type->m64_vtgt? "yes": "no",
  971. mach64type->m64_pro? "yes": "no",
  972. mach64type->m64_ovlclock,
  973. mach64revb? "yes": "no",
  974. mach64refclock);
  975. pprint("%s: storage @%.8luX, aperture @%8.ulX, ovl buf @%.8ulX\n",
  976. scr->dev->name, scr->storage, scr->paddr,
  977. mach64overlay);
  978. }
  979. static void
  980. ovl_openctl(VGAscr *, Chan *c, char **)
  981. {
  982. if (ovl_chan)
  983. error(Einuse);
  984. ovl_chan = c;
  985. }
  986. static void
  987. ovl_closectl(VGAscr *scr, Chan *c, char **)
  988. {
  989. if (c != ovl_chan) return;
  990. waitforidle(scr);
  991. scr->mmio[mmoffset[OverlayScaleCntl]] &=
  992. ~(SCALE_ENABLE|OVERLAY_ENABLE);
  993. ovl_chan = nil;
  994. ovl_width = ovl_height = ovl_fib = 0;
  995. }
  996. enum
  997. {
  998. CMclosectl,
  999. CMconfigure,
  1000. CMenable,
  1001. CMopenctl,
  1002. CMstatus,
  1003. };
  1004. static void (*ovl_cmds[])(VGAscr *, Chan *, char **) =
  1005. {
  1006. [CMclosectl] ovl_closectl,
  1007. [CMconfigure] ovl_configure,
  1008. [CMenable] ovl_enable,
  1009. [CMopenctl] ovl_openctl,
  1010. [CMstatus] ovl_status,
  1011. };
  1012. static Cmdtab mach64xxcmd[] =
  1013. {
  1014. CMclosectl, "closectl", 1,
  1015. CMconfigure, "configure", 4,
  1016. CMenable, "enable", 5,
  1017. CMopenctl, "openctl", 1,
  1018. CMstatus, "status", 1,
  1019. };
  1020. static void
  1021. mach64xxovlctl(VGAscr *scr, Chan *c, void *a, int n)
  1022. {
  1023. Cmdbuf *cb;
  1024. Cmdtab *ct;
  1025. if(!mach64type->m64_vtgt)
  1026. error(Enodev);
  1027. if(!scr->overlayinit){
  1028. scr->overlayinit = 1;
  1029. init_overlayclock(scr);
  1030. }
  1031. cb = parsecmd(a, n);
  1032. if(waserror()){
  1033. free(cb);
  1034. nexterror();
  1035. }
  1036. ct = lookupcmd(cb, mach64xxcmd, nelem(mach64xxcmd));
  1037. ovl_cmds[ct->index](scr, c, cb->f);
  1038. poperror();
  1039. free(cb);
  1040. }
  1041. static int
  1042. mach64xxovlwrite(VGAscr *scr, void *a, int len, vlong offs)
  1043. {
  1044. uchar *src;
  1045. int _len;
  1046. if (ovl_chan == nil) return len; /* Acts as a /dev/null */
  1047. /* Calculate the destination address */
  1048. _len = len;
  1049. src = (uchar *)a;
  1050. while (len > 0) {
  1051. ulong _offs;
  1052. int nb;
  1053. _offs = (ulong)(offs % ovl_fib);
  1054. nb = (_offs + len > ovl_fib)? ovl_fib - _offs: len;
  1055. memmove((uchar *)scr->vaddr + mach64overlay + _offs,
  1056. src, nb);
  1057. offs += nb;
  1058. src += nb;
  1059. len -= nb;
  1060. }
  1061. return _len;
  1062. }
  1063. VGAdev vgamach64xxdev = {
  1064. "mach64xx",
  1065. mach64xxenable, /* enable */
  1066. 0, /* disable */
  1067. 0, /* page */
  1068. mach64xxlinear, /* linear */
  1069. mach64xxdrawinit, /* drawinit */
  1070. 0,
  1071. mach64xxovlctl, /* overlay control */
  1072. mach64xxovlwrite, /* write the overlay */
  1073. };
  1074. VGAcur vgamach64xxcur = {
  1075. "mach64xxhwgc",
  1076. mach64xxcurenable, /* enable */
  1077. mach64xxcurdisable, /* disable */
  1078. mach64xxcurload, /* load */
  1079. mach64xxcurmove, /* move */
  1080. 1 /* doespanning */
  1081. };