vesavbe.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  1. /****************************************************************************
  2. *
  3. * The SuperVGA Kit - UniVBE Software Development Kit
  4. *
  5. * ========================================================================
  6. *
  7. * The contents of this file are subject to the SciTech MGL Public
  8. * License Version 1.0 (the "License"); you may not use this file
  9. * except in compliance with the License. You may obtain a copy of
  10. * the License at http://www.scitechsoft.com/mgl-license.txt
  11. *
  12. * Software distributed under the License is distributed on an
  13. * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  14. * implied. See the License for the specific language governing
  15. * rights and limitations under the License.
  16. *
  17. * The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
  18. *
  19. * The Initial Developer of the Original Code is SciTech Software, Inc.
  20. * All Rights Reserved.
  21. *
  22. * ========================================================================
  23. *
  24. * Language: ANSI C
  25. * Environment: IBM PC Real Mode and 16/32 bit Protected Mode.
  26. *
  27. * Description: Module to implement a C callable interface to the standard
  28. * VESA VBE routines. You should rip out this module and use it
  29. * directly in your own applications, or you can use the
  30. * high level SDK functions.
  31. *
  32. * MUST be compiled in the LARGE or FLAT models.
  33. *
  34. ****************************************************************************/
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include "vesavbe.h"
  39. #include "pmapi.h"
  40. #include "drvlib/os/os.h"
  41. /*---------------------------- Global Variables ---------------------------*/
  42. #define VBE_SUCCESS 0x004F
  43. #define MAX_LIN_PTRS 10
  44. static uint VESABuf_len = 1024;/* Length of the VESABuf buffer */
  45. static ibool haveRiva128; /* True if we have a Riva128 */
  46. static VBE_state defState = {0}; /* Default state buffer */
  47. static VBE_state *state = &defState; /* Pointer to current buffer */
  48. static int VBE_shared = 0;
  49. #ifndef REALMODE
  50. static char localBuf[512]; /* Global PM string translate buf */
  51. #define MAX_LOCAL_BUF &localBuf[511]
  52. #endif
  53. /*----------------------------- Implementation ----------------------------*/
  54. /* static function in WinDirect for passing 32-bit registers to BIOS */
  55. int PMAPI WD_int386(int intno, RMREGS *in, RMREGS *out);
  56. void VBEAPI VBE_init(void)
  57. /****************************************************************************
  58. *
  59. * Function: VBE_init
  60. *
  61. * Description: Initialises the VBE transfer buffer in real mode DC.memory.
  62. * This routine is called by the VESAVBE module every time
  63. * it needs to use the transfer buffer, so we simply allocate
  64. * it once and then return.
  65. *
  66. ****************************************************************************/
  67. {
  68. if (!state->VESABuf_ptr) {
  69. /* Allocate a global buffer for communicating with the VESA VBE */
  70. if ((state->VESABuf_ptr = PM_getVESABuf(&VESABuf_len, &state->VESABuf_rseg, &state->VESABuf_roff)) == NULL)
  71. PM_fatalError("VESAVBE.C: Real mode memory allocation failed!");
  72. }
  73. }
  74. void * VBEAPI VBE_getRMBuf(uint *len,uint *rseg,uint *roff)
  75. /****************************************************************************
  76. *
  77. * Function: VBE_getRMBuf
  78. *
  79. * Description: This function returns the location and length of the real
  80. * mode memory buffer for calling real mode functions.
  81. *
  82. ****************************************************************************/
  83. {
  84. *len = VESABuf_len;
  85. *rseg = state->VESABuf_rseg;
  86. *roff = state->VESABuf_roff;
  87. return state->VESABuf_ptr;
  88. }
  89. void VBEAPI VBE_setStateBuffer(VBE_state *s)
  90. /****************************************************************************
  91. *
  92. * Function: VBE_setStateBuffer
  93. *
  94. * Description: This functions sets the internal state buffer for the
  95. * VBE module to the passed in buffer. By default the internal
  96. * global buffer is used, but you must use separate buffers
  97. * for each device in a multi-controller environment.
  98. *
  99. ****************************************************************************/
  100. {
  101. state = s;
  102. }
  103. void VBEAPI VBE_callESDI(RMREGS *regs, void *buffer, int size)
  104. /****************************************************************************
  105. *
  106. * Function: VBE_callESDI
  107. * Parameters: regs - Registers to load when calling VBE
  108. * buffer - Buffer to copy VBE info block to
  109. * size - Size of buffer to fill
  110. *
  111. * Description: Calls the VESA VBE and passes in a buffer for the VBE to
  112. * store information in, which is then copied into the users
  113. * buffer space. This works in protected mode as the buffer
  114. * passed to the VESA VBE is allocated in conventional
  115. * memory, and is then copied into the users memory block.
  116. *
  117. ****************************************************************************/
  118. {
  119. RMSREGS sregs;
  120. if (!state->VESABuf_ptr)
  121. PM_fatalError("You *MUST* call VBE_init() before you can call the VESAVBE.C module!");
  122. sregs.es = (ushort)state->VESABuf_rseg;
  123. regs->x.di = (ushort)state->VESABuf_roff;
  124. memcpy(state->VESABuf_ptr, buffer, size);
  125. PM_int86x(0x10, regs, regs, &sregs);
  126. memcpy(buffer, state->VESABuf_ptr, size);
  127. }
  128. #ifndef REALMODE
  129. static char *VBE_copyStrToLocal(char *p,char *realPtr,char *max)
  130. /****************************************************************************
  131. *
  132. * Function: VBE_copyStrToLocal
  133. * Parameters: p - Flat model buffer to copy to
  134. * realPtr - Real mode pointer to copy
  135. * Returns: Pointer to the next byte after string
  136. *
  137. * Description: Copies the string from the real mode location pointed to
  138. * by 'realPtr' into the flat model buffer pointed to by
  139. * 'p'. We return a pointer to the next byte past the copied
  140. * string.
  141. *
  142. ****************************************************************************/
  143. {
  144. uchar *v;
  145. v = PM_mapRealPointer((uint)((ulong)realPtr >> 16), (uint)((ulong)realPtr & 0xFFFF));
  146. while (*v != 0 && p < max)
  147. *p++ = *v++;
  148. *p++ = 0;
  149. return p;
  150. }
  151. static void VBE_copyShortToLocal(ushort *p,ushort *realPtr)
  152. /****************************************************************************
  153. *
  154. * Function: VBE_copyShortToLocal
  155. * Parameters: p - Flat model buffer to copy to
  156. * realPtr - Real mode pointer to copy
  157. *
  158. * Description: Copies the mode table from real mode memory to the flat
  159. * model buffer.
  160. *
  161. ****************************************************************************/
  162. {
  163. ushort *v;
  164. v = PM_mapRealPointer((uint)((ulong)realPtr >> 16),(uint)((ulong)realPtr & 0xFFFF));
  165. while (*v != 0xFFFF)
  166. *p++ = *v++;
  167. *p = 0xFFFF;
  168. }
  169. #endif
  170. int VBEAPI VBE_detectEXT(VBE_vgaInfo *vgaInfo,ibool forceUniVBE)
  171. /****************************************************************************
  172. *
  173. * Function: VBE_detect
  174. * Parameters: vgaInfo - Place to store the VGA information block
  175. * Returns: VBE version number, or 0 if not detected.
  176. *
  177. * Description: Detects if a VESA VBE is out there and functioning
  178. * correctly. If we detect a VBE interface we return the
  179. * VGAInfoBlock returned by the VBE and the VBE version number.
  180. *
  181. ****************************************************************************/
  182. {
  183. RMREGS regs;
  184. regs.x.ax = 0x4F00; /* Get SuperVGA information */
  185. if (forceUniVBE) {
  186. regs.x.bx = 0x1234;
  187. regs.x.cx = 0x4321;
  188. }
  189. else {
  190. regs.x.bx = 0;
  191. regs.x.cx = 0;
  192. }
  193. strncpy(vgaInfo->VESASignature,"VBE2",4);
  194. VBE_callESDI(&regs, vgaInfo, sizeof(*vgaInfo));
  195. if (regs.x.ax != VBE_SUCCESS)
  196. return 0;
  197. if (strncmp(vgaInfo->VESASignature,"VESA",4) != 0)
  198. return 0;
  199. /* Check for bogus BIOSes that return a VBE version number that is
  200. * not correct, and fix it up. We also check the OemVendorNamePtr for a
  201. * valid value, and if it is invalid then we also reset to VBE 1.2.
  202. */
  203. if (vgaInfo->VESAVersion >= 0x200 && vgaInfo->OemVendorNamePtr == 0)
  204. vgaInfo->VESAVersion = 0x102;
  205. #ifndef REALMODE
  206. /* Relocate all the indirect information (mode tables, OEM strings
  207. * etc) from the low 1Mb memory region into a static buffer in
  208. * our default data segment. We do this to insulate the application
  209. * from mapping the strings from real mode to protected mode.
  210. */
  211. {
  212. char *p,*p2;
  213. p2 = VBE_copyStrToLocal(localBuf,vgaInfo->OemStringPtr,MAX_LOCAL_BUF);
  214. vgaInfo->OemStringPtr = localBuf;
  215. if (vgaInfo->VESAVersion >= 0x200) {
  216. p = VBE_copyStrToLocal(p2,vgaInfo->OemVendorNamePtr,MAX_LOCAL_BUF);
  217. vgaInfo->OemVendorNamePtr = p2;
  218. p2 = VBE_copyStrToLocal(p,vgaInfo->OemProductNamePtr,MAX_LOCAL_BUF);
  219. vgaInfo->OemProductNamePtr = p;
  220. p = VBE_copyStrToLocal(p2,vgaInfo->OemProductRevPtr,MAX_LOCAL_BUF);
  221. vgaInfo->OemProductRevPtr = p2;
  222. VBE_copyShortToLocal((ushort*)p,vgaInfo->VideoModePtr);
  223. vgaInfo->VideoModePtr = (ushort*)p;
  224. }
  225. else {
  226. VBE_copyShortToLocal((ushort*)p2,vgaInfo->VideoModePtr);
  227. vgaInfo->VideoModePtr = (ushort*)p2;
  228. }
  229. }
  230. #endif
  231. state->VBEMemory = vgaInfo->TotalMemory * 64;
  232. /* Check for Riva128 based cards since they have broken triple buffering
  233. * and stereo support.
  234. */
  235. haveRiva128 = false;
  236. if (vgaInfo->VESAVersion >= 0x300 &&
  237. (strstr(vgaInfo->OemStringPtr,"NVidia") != NULL ||
  238. strstr(vgaInfo->OemStringPtr,"Riva") != NULL)) {
  239. haveRiva128 = true;
  240. }
  241. /* Check for Matrox G400 cards which claim to be VBE 3.0
  242. * compliant yet they don't implement the refresh rate control
  243. * functions.
  244. */
  245. if (vgaInfo->VESAVersion >= 0x300 && (strcmp(vgaInfo->OemProductNamePtr,"Matrox G400") == 0))
  246. vgaInfo->VESAVersion = 0x200;
  247. return (state->VBEVersion = vgaInfo->VESAVersion);
  248. }
  249. int VBEAPI VBE_detect(VBE_vgaInfo *vgaInfo)
  250. /****************************************************************************
  251. *
  252. * Function: VBE_detect
  253. * Parameters: vgaInfo - Place to store the VGA information block
  254. * Returns: VBE version number, or 0 if not detected.
  255. *
  256. * Description: Detects if a VESA VBE is out there and functioning
  257. * correctly. If we detect a VBE interface we return the
  258. * VGAInfoBlock returned by the VBE and the VBE version number.
  259. *
  260. ****************************************************************************/
  261. {
  262. return VBE_detectEXT(vgaInfo,false);
  263. }
  264. ibool VBEAPI VBE_getModeInfo(int mode,VBE_modeInfo *modeInfo)
  265. /****************************************************************************
  266. *
  267. * Function: VBE_getModeInfo
  268. * Parameters: mode - VBE mode to get information for
  269. * modeInfo - Place to store VBE mode information
  270. * Returns: True on success, false if function failed.
  271. *
  272. * Description: Obtains information about a specific video mode from the
  273. * VBE. You should use this function to find the video mode
  274. * you wish to set, as the new VBE 2.0 mode numbers may be
  275. * completely arbitrary.
  276. *
  277. ****************************************************************************/
  278. {
  279. RMREGS regs;
  280. int bits;
  281. regs.x.ax = 0x4F01; /* Get mode information */
  282. regs.x.cx = (ushort)mode;
  283. VBE_callESDI(&regs, modeInfo, sizeof(*modeInfo));
  284. if (regs.x.ax != VBE_SUCCESS)
  285. return false;
  286. if ((modeInfo->ModeAttributes & vbeMdAvailable) == 0)
  287. return false;
  288. /* Map out triple buffer and stereo flags for NVidia Riva128
  289. * chips.
  290. */
  291. if (haveRiva128) {
  292. modeInfo->ModeAttributes &= ~vbeMdTripleBuf;
  293. modeInfo->ModeAttributes &= ~vbeMdStereo;
  294. }
  295. /* Support old style RGB definitions for VBE 1.1 BIOSes */
  296. bits = modeInfo->BitsPerPixel;
  297. if (modeInfo->MemoryModel == vbeMemPK && bits > 8) {
  298. modeInfo->MemoryModel = vbeMemRGB;
  299. switch (bits) {
  300. case 15:
  301. modeInfo->RedMaskSize = 5;
  302. modeInfo->RedFieldPosition = 10;
  303. modeInfo->GreenMaskSize = 5;
  304. modeInfo->GreenFieldPosition = 5;
  305. modeInfo->BlueMaskSize = 5;
  306. modeInfo->BlueFieldPosition = 0;
  307. modeInfo->RsvdMaskSize = 1;
  308. modeInfo->RsvdFieldPosition = 15;
  309. break;
  310. case 16:
  311. modeInfo->RedMaskSize = 5;
  312. modeInfo->RedFieldPosition = 11;
  313. modeInfo->GreenMaskSize = 5;
  314. modeInfo->GreenFieldPosition = 5;
  315. modeInfo->BlueMaskSize = 5;
  316. modeInfo->BlueFieldPosition = 0;
  317. modeInfo->RsvdMaskSize = 0;
  318. modeInfo->RsvdFieldPosition = 0;
  319. break;
  320. case 24:
  321. modeInfo->RedMaskSize = 8;
  322. modeInfo->RedFieldPosition = 16;
  323. modeInfo->GreenMaskSize = 8;
  324. modeInfo->GreenFieldPosition = 8;
  325. modeInfo->BlueMaskSize = 8;
  326. modeInfo->BlueFieldPosition = 0;
  327. modeInfo->RsvdMaskSize = 0;
  328. modeInfo->RsvdFieldPosition = 0;
  329. break;
  330. }
  331. }
  332. /* Convert the 32k direct color modes of VBE 1.2+ BIOSes to
  333. * be recognised as 15 bits per pixel modes.
  334. */
  335. if (bits == 16 && modeInfo->RsvdMaskSize == 1)
  336. modeInfo->BitsPerPixel = 15;
  337. /* Fix up bogus BIOS'es that report incorrect reserved pixel masks
  338. * for 32K color modes. Quite a number of BIOS'es have this problem,
  339. * and this affects our OS/2 drivers in VBE fallback mode.
  340. */
  341. if (bits == 15 && (modeInfo->RsvdMaskSize != 1 || modeInfo->RsvdFieldPosition != 15)) {
  342. modeInfo->RsvdMaskSize = 1;
  343. modeInfo->RsvdFieldPosition = 15;
  344. }
  345. return true;
  346. }
  347. long VBEAPI VBE_getPageSize(VBE_modeInfo *mi)
  348. /****************************************************************************
  349. *
  350. * Function: VBE_getPageSize
  351. * Parameters: mi - Pointer to mode information block
  352. * Returns: Caculated page size in bytes rounded to correct boundary
  353. *
  354. * Description: Computes the page size in bytes for the specified mode
  355. * information block, rounded up to the appropriate boundary
  356. * (8k, 16k, 32k or 64k). Pages >= 64k in size are always
  357. * rounded to the nearest 64k boundary (so the start of a
  358. * page is always bank aligned).
  359. *
  360. ****************************************************************************/
  361. {
  362. long size;
  363. size = (long)mi->BytesPerScanLine * (long)mi->YResolution;
  364. if (mi->BitsPerPixel == 4) {
  365. /* We have a 16 color video mode, so round up the page size to
  366. * 8k, 16k, 32k or 64k boundaries depending on how large it is.
  367. */
  368. size = (size + 0x1FFFL) & 0xFFFFE000L;
  369. if (size != 0x2000) {
  370. size = (size + 0x3FFFL) & 0xFFFFC000L;
  371. if (size != 0x4000) {
  372. size = (size + 0x7FFFL) & 0xFFFF8000L;
  373. if (size != 0x8000)
  374. size = (size + 0xFFFFL) & 0xFFFF0000L;
  375. }
  376. }
  377. }
  378. else size = (size + 0xFFFFL) & 0xFFFF0000L;
  379. return size;
  380. }
  381. ibool VBEAPI VBE_setVideoModeExt(int mode,VBE_CRTCInfo *crtc)
  382. /****************************************************************************
  383. *
  384. * Function: VBE_setVideoModeExt
  385. * Parameters: mode - SuperVGA video mode to set.
  386. * Returns: True if the mode was set, false if not.
  387. *
  388. * Description: Attempts to set the specified video mode. This version
  389. * includes support for the VBE/Core 3.0 refresh rate control
  390. * mechanism.
  391. *
  392. ****************************************************************************/
  393. {
  394. RMREGS regs;
  395. if (state->VBEVersion < 0x200 && mode < 0x100) {
  396. /* Some VBE implementations barf terribly if you try to set non-VBE
  397. * video modes with the VBE set mode call. VBE 2.0 implementations
  398. * must be able to handle this.
  399. */
  400. regs.h.al = (ushort)mode;
  401. regs.h.ah = 0;
  402. PM_int86(0x10,&regs,&regs);
  403. }
  404. else {
  405. if (state->VBEVersion < 0x300 && (mode & vbeRefreshCtrl))
  406. return false;
  407. regs.x.ax = 0x4F02;
  408. regs.x.bx = (ushort)mode;
  409. if ((mode & vbeRefreshCtrl) && crtc)
  410. VBE_callESDI(&regs, crtc, sizeof(*crtc));
  411. else
  412. PM_int86(0x10,&regs,&regs);
  413. if (regs.x.ax != VBE_SUCCESS)
  414. return false;
  415. }
  416. return true;
  417. }
  418. ibool VBEAPI VBE_setVideoMode(int mode)
  419. /****************************************************************************
  420. *
  421. * Function: VBE_setVideoMode
  422. * Parameters: mode - SuperVGA video mode to set.
  423. * Returns: True if the mode was set, false if not.
  424. *
  425. * Description: Attempts to set the specified video mode.
  426. *
  427. ****************************************************************************/
  428. {
  429. return VBE_setVideoModeExt(mode,NULL);
  430. }
  431. int VBEAPI VBE_getVideoMode(void)
  432. /****************************************************************************
  433. *
  434. * Function: VBE_getVideoMode
  435. * Returns: Current video mode
  436. *
  437. ****************************************************************************/
  438. {
  439. RMREGS regs;
  440. regs.x.ax = 0x4F03;
  441. PM_int86(0x10,&regs,&regs);
  442. if (regs.x.ax != VBE_SUCCESS)
  443. return -1;
  444. return regs.x.bx;
  445. }
  446. ibool VBEAPI VBE_setBank(int window,int bank)
  447. /****************************************************************************
  448. *
  449. * Function: VBE_setBank
  450. * Parameters: window - Window to set
  451. * bank - Bank number to set window to
  452. * Returns: True on success, false on failure.
  453. *
  454. ****************************************************************************/
  455. {
  456. RMREGS regs;
  457. regs.x.ax = 0x4F05;
  458. regs.h.bh = 0;
  459. regs.h.bl = window;
  460. regs.x.dx = bank;
  461. PM_int86(0x10,&regs,&regs);
  462. return regs.x.ax == VBE_SUCCESS;
  463. }
  464. int VBEAPI VBE_getBank(int window)
  465. /****************************************************************************
  466. *
  467. * Function: VBE_setBank
  468. * Parameters: window - Window to read
  469. * Returns: Bank number for the window (-1 on failure)
  470. *
  471. ****************************************************************************/
  472. {
  473. RMREGS regs;
  474. regs.x.ax = 0x4F05;
  475. regs.h.bh = 1;
  476. regs.h.bl = window;
  477. PM_int86(0x10,&regs,&regs);
  478. if (regs.x.ax != VBE_SUCCESS)
  479. return -1;
  480. return regs.x.dx;
  481. }
  482. ibool VBEAPI VBE_setPixelsPerLine(int pixelsPerLine,int *newBytes,
  483. int *newPixels,int *maxScanlines)
  484. /****************************************************************************
  485. *
  486. * Function: VBE_setPixelsPerLine
  487. * Parameters: pixelsPerLine - Pixels per scanline
  488. * newBytes - Storage for bytes per line value set
  489. * newPixels - Storage for pixels per line value set
  490. * maxScanLines - Storage for maximum number of scanlines
  491. * Returns: True on success, false on failure
  492. *
  493. * Description: Sets the scanline length for the video mode to the specified
  494. * number of pixels per scanline. If you need more granularity
  495. * in TrueColor modes, use the VBE_setBytesPerLine routine
  496. * (only valid for VBE 2.0).
  497. *
  498. ****************************************************************************/
  499. {
  500. RMREGS regs;
  501. regs.x.ax = 0x4F06;
  502. regs.h.bl = 0;
  503. regs.x.cx = pixelsPerLine;
  504. PM_int86(0x10,&regs,&regs);
  505. *newBytes = regs.x.bx;
  506. *newPixels = regs.x.cx;
  507. *maxScanlines = regs.x.dx;
  508. return regs.x.ax == VBE_SUCCESS;
  509. }
  510. ibool VBEAPI VBE_setBytesPerLine(int bytesPerLine,int *newBytes,
  511. int *newPixels,int *maxScanlines)
  512. /****************************************************************************
  513. *
  514. * Function: VBE_setBytesPerLine
  515. * Parameters: pixelsPerLine - Pixels per scanline
  516. * newBytes - Storage for bytes per line value set
  517. * newPixels - Storage for pixels per line value set
  518. * maxScanLines - Storage for maximum number of scanlines
  519. * Returns: True on success, false on failure
  520. *
  521. * Description: Sets the scanline length for the video mode to the specified
  522. * number of bytes per scanline (valid for VBE 2.0 only).
  523. *
  524. ****************************************************************************/
  525. {
  526. RMREGS regs;
  527. regs.x.ax = 0x4F06;
  528. regs.h.bl = 2;
  529. regs.x.cx = bytesPerLine;
  530. PM_int86(0x10,&regs,&regs);
  531. *newBytes = regs.x.bx;
  532. *newPixels = regs.x.cx;
  533. *maxScanlines = regs.x.dx;
  534. return regs.x.ax == VBE_SUCCESS;
  535. }
  536. ibool VBEAPI VBE_getScanlineLength(int *bytesPerLine,int *pixelsPerLine,
  537. int *maxScanlines)
  538. /****************************************************************************
  539. *
  540. * Function: VBE_getScanlineLength
  541. * Parameters: bytesPerLine - Storage for bytes per scanline
  542. * pixelsPerLine - Storage for pixels per scanline
  543. * maxScanLines - Storage for maximum number of scanlines
  544. * Returns: True on success, false on failure
  545. *
  546. ****************************************************************************/
  547. {
  548. RMREGS regs;
  549. regs.x.ax = 0x4F06;
  550. regs.h.bl = 1;
  551. PM_int86(0x10,&regs,&regs);
  552. *bytesPerLine = regs.x.bx;
  553. *pixelsPerLine = regs.x.cx;
  554. *maxScanlines = regs.x.dx;
  555. return regs.x.ax == VBE_SUCCESS;
  556. }
  557. ibool VBEAPI VBE_getMaxScanlineLength(int *maxBytes,int *maxPixels)
  558. /****************************************************************************
  559. *
  560. * Function: VBE_getMaxScanlineLength
  561. * Parameters: maxBytes - Maximum scanline width in bytes
  562. * maxPixels - Maximum scanline width in pixels
  563. * Returns: True if successful, false if function failed
  564. *
  565. ****************************************************************************/
  566. {
  567. RMREGS regs;
  568. regs.x.ax = 0x4F06;
  569. regs.h.bl = 3;
  570. PM_int86(0x10,&regs,&regs);
  571. *maxBytes = regs.x.bx;
  572. *maxPixels = regs.x.cx;
  573. return regs.x.ax == VBE_SUCCESS;
  574. }
  575. ibool VBEAPI VBE_setDisplayStart(int x,int y,ibool waitVRT)
  576. /****************************************************************************
  577. *
  578. * Function: VBE_setDisplayStart
  579. * Parameters: x,y - Position of the first pixel to display
  580. * waitVRT - True to wait for retrace, false if not
  581. * Returns: True if function was successful.
  582. *
  583. * Description: Sets the new starting display position to implement
  584. * hardware scrolling.
  585. *
  586. ****************************************************************************/
  587. {
  588. RMREGS regs;
  589. regs.x.ax = 0x4F07;
  590. if (waitVRT)
  591. regs.x.bx = 0x80;
  592. else regs.x.bx = 0x00;
  593. regs.x.cx = x;
  594. regs.x.dx = y;
  595. PM_int86(0x10,&regs,&regs);
  596. return regs.x.ax == VBE_SUCCESS;
  597. }
  598. ibool VBEAPI VBE_getDisplayStart(int *x,int *y)
  599. /****************************************************************************
  600. *
  601. * Function: VBE_getDisplayStart
  602. * Parameters: x,y - Place to store starting address value
  603. * Returns: True if function was successful.
  604. *
  605. ****************************************************************************/
  606. {
  607. RMREGS regs;
  608. regs.x.ax = 0x4F07;
  609. regs.x.bx = 0x01;
  610. PM_int86(0x10,&regs,&regs);
  611. *x = regs.x.cx;
  612. *y = regs.x.dx;
  613. return regs.x.ax == VBE_SUCCESS;
  614. }
  615. ibool VBEAPI VBE_setDisplayStartAlt(ulong startAddr,ibool waitVRT)
  616. /****************************************************************************
  617. *
  618. * Function: VBE_setDisplayStartAlt
  619. * Parameters: startAddr - 32-bit starting address in display memory
  620. * waitVRT - True to wait for vertical retrace, false if not
  621. * Returns: True if function was successful, false if not supported.
  622. *
  623. * Description: Sets the new starting display position to the specified
  624. * 32-bit display start address. Note that this function is
  625. * different the the version above, since it takes a 32-bit
  626. * byte offset in video memory as the starting address which
  627. * gives the programmer maximum control over the stat address.
  628. *
  629. * NOTE: Requires VBE/Core 3.0
  630. *
  631. ****************************************************************************/
  632. {
  633. RMREGS regs;
  634. if (state->VBEVersion >= 0x300) {
  635. regs.x.ax = 0x4F07;
  636. regs.x.bx = waitVRT ? 0x82 : 0x02;
  637. regs.e.ecx = startAddr;
  638. PM_int86(0x10,&regs,&regs);
  639. return regs.x.ax == VBE_SUCCESS;
  640. }
  641. return false;
  642. }
  643. int VBEAPI VBE_getDisplayStartStatus(void)
  644. /****************************************************************************
  645. *
  646. * Function: VBE_getDisplayStartStatus
  647. * Returns: 0 if last flip not occurred, 1 if already flipped
  648. * -1 if not supported
  649. *
  650. * Description: Returns the status of the previous display start request.
  651. * If this function is supported the programmer can implement
  652. * hardware triple buffering using this function.
  653. *
  654. * NOTE: Requires VBE/Core 3.0
  655. *
  656. ****************************************************************************/
  657. {
  658. RMREGS regs;
  659. if (state->VBEVersion >= 0x300) {
  660. regs.x.ax = 0x4F07;
  661. regs.x.bx = 0x0004;
  662. PM_int86(0x10,&regs,&regs);
  663. if (regs.x.ax == VBE_SUCCESS)
  664. return (regs.x.cx != 0);
  665. }
  666. return -1;
  667. }
  668. ibool VBEAPI VBE_enableStereoMode(void)
  669. /****************************************************************************
  670. *
  671. * Function: VBE_enableStereoMode
  672. * Returns: True if stereo mode enabled, false if not supported.
  673. *
  674. * Description: Puts the system into hardware stereo mode for LC shutter
  675. * glasses, where the display swaps between two display start
  676. * addresses every vertical retrace.
  677. *
  678. * NOTE: Requires VBE/Core 3.0
  679. *
  680. ****************************************************************************/
  681. {
  682. RMREGS regs;
  683. if (state->VBEVersion >= 0x300) {
  684. regs.x.ax = 0x4F07;
  685. regs.x.bx = 0x0005;
  686. PM_int86(0x10,&regs,&regs);
  687. return regs.x.ax == VBE_SUCCESS;
  688. }
  689. return false;
  690. }
  691. ibool VBEAPI VBE_disableStereoMode(void)
  692. /****************************************************************************
  693. *
  694. * Function: VBE_disableStereoMode
  695. * Returns: True if stereo mode disabled, false if not supported.
  696. *
  697. * Description: Puts the system back into normal, non-stereo display mode
  698. * after having stereo mode enabled.
  699. *
  700. * NOTE: Requires VBE/Core 3.0
  701. *
  702. ****************************************************************************/
  703. {
  704. RMREGS regs;
  705. if (state->VBEVersion >= 0x300) {
  706. regs.x.ax = 0x4F07;
  707. regs.x.bx = 0x0006;
  708. PM_int86(0x10,&regs,&regs);
  709. return regs.x.ax == VBE_SUCCESS;
  710. }
  711. return false;
  712. }
  713. ibool VBEAPI VBE_setStereoDisplayStart(ulong leftAddr,ulong rightAddr,
  714. ibool waitVRT)
  715. /****************************************************************************
  716. *
  717. * Function: VBE_setStereoDisplayStart
  718. * Parameters: leftAddr - 32-bit start address for left image
  719. * rightAddr - 32-bit start address for right image
  720. * waitVRT - True to wait for vertical retrace, false if not
  721. * Returns: True if function was successful, false if not supported.
  722. *
  723. * Description: Sets the new starting display position to the specified
  724. * 32-bit display start address. Note that this function is
  725. * different the the version above, since it takes a 32-bit
  726. * byte offset in video memory as the starting address which
  727. * gives the programmer maximum control over the stat address.
  728. *
  729. * NOTE: Requires VBE/Core 3.0
  730. *
  731. ****************************************************************************/
  732. {
  733. RMREGS regs;
  734. if (state->VBEVersion >= 0x300) {
  735. regs.x.ax = 0x4F07;
  736. regs.x.bx = waitVRT ? 0x83 : 0x03;
  737. regs.e.ecx = leftAddr;
  738. regs.e.edx = rightAddr;
  739. PM_int86(0x10,&regs,&regs);
  740. return regs.x.ax == VBE_SUCCESS;
  741. }
  742. return false;
  743. }
  744. ulong VBEAPI VBE_getClosestClock(ushort mode,ulong pixelClock)
  745. /****************************************************************************
  746. *
  747. * Function: VBE_getClosestClock
  748. * Parameters: mode - VBE mode to be used (include vbeLinearBuffer)
  749. * pixelClock - Desired pixel clock
  750. * Returns: Closest pixel clock to desired clock (-1 if not supported)
  751. *
  752. * Description: Calls the VBE/Core 3.0 interface to determine the closest
  753. * pixel clock to the requested value. The BIOS will always
  754. * search for a pixel clock that is no more than 1% below the
  755. * requested clock or somewhere higher than the clock. If the
  756. * clock is higher note that it may well be many Mhz higher
  757. * that requested and the application will have to check that
  758. * the returned value is suitable for it's needs. This function
  759. * returns the actual pixel clock that will be programmed by
  760. * the hardware.
  761. *
  762. * Note that if the pixel clock will be used with a linear
  763. * framebuffer mode, make sure you pass in the linear
  764. * framebuffer flag to this function.
  765. *
  766. * NOTE: Requires VBE/Core 3.0
  767. *
  768. ****************************************************************************/
  769. {
  770. RMREGS regs;
  771. if (state->VBEVersion >= 0x300) {
  772. regs.x.ax = 0x4F0B;
  773. regs.h.bl = 0x00;
  774. regs.e.ecx = pixelClock;
  775. regs.x.dx = mode;
  776. PM_int86(0x10,&regs,&regs);
  777. if (regs.x.ax == VBE_SUCCESS)
  778. return regs.e.ecx;
  779. }
  780. return -1;
  781. }
  782. ibool VBEAPI VBE_setDACWidth(int width)
  783. /****************************************************************************
  784. *
  785. * Function: VBE_setDACWidth
  786. * Parameters: width - Width to set the DAC to
  787. * Returns: True on success, false on failure
  788. *
  789. ****************************************************************************/
  790. {
  791. RMREGS regs;
  792. regs.x.ax = 0x4F08;
  793. regs.h.bl = 0x00;
  794. regs.h.bh = width;
  795. PM_int86(0x10,&regs,&regs);
  796. return regs.x.ax == VBE_SUCCESS;
  797. }
  798. int VBEAPI VBE_getDACWidth(void)
  799. /****************************************************************************
  800. *
  801. * Function: VBE_getDACWidth
  802. * Returns: Current width of the palette DAC
  803. *
  804. ****************************************************************************/
  805. {
  806. RMREGS regs;
  807. regs.x.ax = 0x4F08;
  808. regs.h.bl = 0x01;
  809. PM_int86(0x10,&regs,&regs);
  810. if (regs.x.ax != VBE_SUCCESS)
  811. return -1;
  812. return regs.h.bh;
  813. }
  814. ibool VBEAPI VBE_setPalette(int start,int num,VBE_palette *pal,ibool waitVRT)
  815. /****************************************************************************
  816. *
  817. * Function: VBE_setPalette
  818. * Parameters: start - Starting palette index to program
  819. * num - Number of palette indexes to program
  820. * pal - Palette buffer containing values
  821. * waitVRT - Wait for vertical retrace flag
  822. * Returns: True on success, false on failure
  823. *
  824. * Description: Sets a block of palette registers by calling the VBE 2.0
  825. * BIOS. This function will fail on VBE 1.2 implementations.
  826. *
  827. ****************************************************************************/
  828. {
  829. RMREGS regs;
  830. regs.x.ax = 0x4F09;
  831. regs.h.bl = waitVRT ? 0x80 : 0x00;
  832. regs.x.cx = num;
  833. regs.x.dx = start;
  834. VBE_callESDI(&regs, pal, sizeof(VBE_palette) * num);
  835. return regs.x.ax == VBE_SUCCESS;
  836. }
  837. void * VBEAPI VBE_getBankedPointer(VBE_modeInfo *modeInfo)
  838. /****************************************************************************
  839. *
  840. * Function: VBE_getBankedPointer
  841. * Parameters: modeInfo - Mode info block for video mode
  842. * Returns: Selector to the linear framebuffer (0 on failure)
  843. *
  844. * Description: Returns a near pointer to the VGA framebuffer area.
  845. *
  846. ****************************************************************************/
  847. {
  848. /* We just map the pointer every time, since the pointer will always
  849. * be in real mode memory, so we wont actually be mapping any real
  850. * memory.
  851. *
  852. * NOTE: We cannot currently map a near pointer to the banked frame
  853. * buffer for Watcom Win386, so we create a 16:16 far pointer to
  854. * the video memory. All the assembler code will render to the
  855. * video memory by loading the selector rather than using a
  856. * near pointer.
  857. */
  858. ulong seg = (ushort)modeInfo->WinASegment;
  859. if (seg != 0) {
  860. if (seg == 0xA000)
  861. return (void*)PM_getA0000Pointer();
  862. else
  863. return (void*)PM_mapPhysicalAddr(seg << 4,0xFFFF,true);
  864. }
  865. return NULL;
  866. }
  867. #ifndef REALMODE
  868. void * VBEAPI VBE_getLinearPointer(VBE_modeInfo *modeInfo)
  869. /****************************************************************************
  870. *
  871. * Function: VBE_getLinearPointer
  872. * Parameters: modeInfo - Mode info block for video mode
  873. * Returns: Selector to the linear framebuffer (0 on failure)
  874. *
  875. * Description: Returns a near pointer to the linear framebuffer for the video
  876. * mode.
  877. *
  878. ****************************************************************************/
  879. {
  880. static ulong physPtr[MAX_LIN_PTRS] = {0};
  881. static void *linPtr[MAX_LIN_PTRS] = {0};
  882. static int numPtrs = 0;
  883. int i;
  884. /* Search for an already mapped pointer */
  885. for (i = 0; i < numPtrs; i++) {
  886. if (physPtr[i] == modeInfo->PhysBasePtr)
  887. return linPtr[i];
  888. }
  889. if (numPtrs < MAX_LIN_PTRS) {
  890. physPtr[numPtrs] = modeInfo->PhysBasePtr;
  891. linPtr[numPtrs] = PM_mapPhysicalAddr(modeInfo->PhysBasePtr,(state->VBEMemory * 1024L)-1,true);
  892. return linPtr[numPtrs++];
  893. }
  894. return NULL;
  895. }
  896. static void InitPMCode(void)
  897. /****************************************************************************
  898. *
  899. * Function: InitPMCode - 32 bit protected mode version
  900. *
  901. * Description: Finds the address of and relocates the protected mode
  902. * code block from the VBE 2.0 into a local memory block. The
  903. * memory block is allocated with malloc() and must be freed
  904. * with VBE_freePMCode() after graphics processing is complete.
  905. *
  906. * Note that this buffer _must_ be recopied after each mode set,
  907. * as the routines will change depending on the underlying
  908. * video mode.
  909. *
  910. ****************************************************************************/
  911. {
  912. RMREGS regs;
  913. RMSREGS sregs;
  914. uchar *code;
  915. int pmLen;
  916. if (!state->pmInfo && state->VBEVersion >= 0x200) {
  917. regs.x.ax = 0x4F0A;
  918. regs.x.bx = 0;
  919. PM_int86x(0x10,&regs,&regs,&sregs);
  920. if (regs.x.ax != VBE_SUCCESS)
  921. return;
  922. if (VBE_shared)
  923. state->pmInfo = PM_mallocShared(regs.x.cx);
  924. else
  925. state->pmInfo = PM_malloc(regs.x.cx);
  926. if (state->pmInfo == NULL)
  927. return;
  928. state->pmInfo32 = state->pmInfo;
  929. pmLen = regs.x.cx;
  930. /* Relocate the block into our local data segment */
  931. code = PM_mapRealPointer(sregs.es,regs.x.di);
  932. memcpy(state->pmInfo,code,pmLen);
  933. /* Now do a sanity check on the information we recieve to ensure
  934. * that is is correct. Some BIOS return totally bogus information
  935. * in here (Matrox is one)! Under DOS this works OK, but under OS/2
  936. * we are screwed.
  937. */
  938. if (state->pmInfo->setWindow >= pmLen ||
  939. state->pmInfo->setDisplayStart >= pmLen ||
  940. state->pmInfo->setPalette >= pmLen ||
  941. state->pmInfo->IOPrivInfo >= pmLen) {
  942. if (VBE_shared)
  943. PM_freeShared(state->pmInfo);
  944. else
  945. PM_free(state->pmInfo);
  946. state->pmInfo32 = state->pmInfo = NULL;
  947. return;
  948. }
  949. /* Read the IO priveledge info and determine if we need to
  950. * pass a selector to MMIO registers to the bank switch code.
  951. * Since we no longer support selector allocation, we no longer
  952. * support this mechanism so we disable the protected mode
  953. * interface in this case.
  954. */
  955. if (state->pmInfo->IOPrivInfo && !state->MMIOSel) {
  956. ushort *p = (ushort*)((uchar*)state->pmInfo + state->pmInfo->IOPrivInfo);
  957. while (*p != 0xFFFF)
  958. p++;
  959. p++;
  960. if (*p != 0xFFFF)
  961. VBE_freePMCode();
  962. }
  963. }
  964. }
  965. void * VBEAPI VBE_getSetBank(void)
  966. /****************************************************************************
  967. *
  968. * Function: VBE_getSetBank
  969. * Returns: Pointer to the 32 VBE 2.0 bit bank switching routine.
  970. *
  971. ****************************************************************************/
  972. {
  973. if (state->VBEVersion >= 0x200) {
  974. InitPMCode();
  975. if (state->pmInfo)
  976. return (uchar*)state->pmInfo + state->pmInfo->setWindow;
  977. }
  978. return NULL;
  979. }
  980. void * VBEAPI VBE_getSetDisplayStart(void)
  981. /****************************************************************************
  982. *
  983. * Function: VBE_getSetDisplayStart
  984. * Returns: Pointer to the 32 VBE 2.0 bit CRT start address routine.
  985. *
  986. ****************************************************************************/
  987. {
  988. if (state->VBEVersion >= 0x200) {
  989. InitPMCode();
  990. if (state->pmInfo)
  991. return (uchar*)state->pmInfo + state->pmInfo->setDisplayStart;
  992. }
  993. return NULL;
  994. }
  995. void * VBEAPI VBE_getSetPalette(void)
  996. /****************************************************************************
  997. *
  998. * Function: VBE_getSetPalette
  999. * Returns: Pointer to the 32 VBE 2.0 bit palette programming routine.
  1000. *
  1001. ****************************************************************************/
  1002. {
  1003. if (state->VBEVersion >= 0x200) {
  1004. InitPMCode();
  1005. if (state->pmInfo)
  1006. return (uchar*)state->pmInfo + state->pmInfo->setPalette;
  1007. }
  1008. return NULL;
  1009. }
  1010. void VBEAPI VBE_freePMCode(void)
  1011. /****************************************************************************
  1012. *
  1013. * Function: VBE_freePMCode
  1014. *
  1015. * Description: This routine frees the protected mode code blocks that
  1016. * we copied from the VBE 2.0 interface. This routine must
  1017. * be after you have finished graphics processing to free up
  1018. * the memory occupied by the routines. This is necessary
  1019. * because the PM info memory block must be re-copied after
  1020. * every video mode set from the VBE 2.0 implementation.
  1021. *
  1022. ****************************************************************************/
  1023. {
  1024. if (state->pmInfo) {
  1025. if (VBE_shared)
  1026. PM_freeShared(state->pmInfo);
  1027. else
  1028. PM_free(state->pmInfo);
  1029. state->pmInfo = NULL;
  1030. state->pmInfo32 = NULL;
  1031. }
  1032. }
  1033. void VBEAPI VBE_sharePMCode(void)
  1034. /****************************************************************************
  1035. *
  1036. * Function: VBE_sharePMCode
  1037. *
  1038. * Description: Enables internal sharing of the PM code buffer for OS/2.
  1039. *
  1040. ****************************************************************************/
  1041. {
  1042. VBE_shared = true;
  1043. }
  1044. /* Set of code stubs used to build the final bank switch code */
  1045. #define VBE20_adjustOffset 7
  1046. static uchar VBE20A_bankFunc32_Start[] = {
  1047. 0x53,0x51, /* push ebx,ecx */
  1048. 0x8B,0xD0, /* mov edx,eax */
  1049. 0x33,0xDB, /* xor ebx,ebx */
  1050. 0xB1,0x00, /* mov cl,0 */
  1051. 0xD2,0xE2, /* shl dl,cl */
  1052. };
  1053. static uchar VBE20_bankFunc32_End[] = {
  1054. 0x59,0x5B, /* pop ecx,ebx */
  1055. };
  1056. static uchar bankFunc32[100];
  1057. #define copy(p,b,a) memcpy(b,a,sizeof(a)); (p) = (b) + sizeof(a)
  1058. ibool VBEAPI VBE_getBankFunc32(int *codeLen,void **bankFunc,int dualBanks,
  1059. int bankAdjust)
  1060. /****************************************************************************
  1061. *
  1062. * Function: VBE_getBankFunc32
  1063. * Parameters: codeLen - Place to store length of code
  1064. * bankFunc - Place to store pointer to bank switch code
  1065. * dualBanks - True if dual banks are in effect
  1066. * bankAdjust - Bank shift adjustment factor
  1067. * Returns: True on success, false if not compatible.
  1068. *
  1069. * Description: Creates a local 32 bit bank switch function from the
  1070. * VBE 2.0 bank switch code that is compatible with the
  1071. * virtual flat framebuffer devices (does not have a return
  1072. * instruction at the end and takes the bank number in EAX
  1073. * not EDX). Note that this 32 bit code cannot include int 10h
  1074. * instructions, so we can only do this if we have VBE 2.0
  1075. * or later.
  1076. *
  1077. * Note that we need to know the length of the 32 bit
  1078. * bank switch function, which the standard VBE 2.0 spec
  1079. * does not provide. In order to support this we have
  1080. * extended the VBE 2.0 state->pmInfo structure in UniVBE 5.2 in a
  1081. * way to support this, and we hope that this will become
  1082. * a VBE 2.0 ammendment.
  1083. *
  1084. * Note also that we cannot run the linear framebuffer
  1085. * emulation code with bank switching routines that require
  1086. * a selector to the memory mapped registers passed in ES.
  1087. *
  1088. ****************************************************************************/
  1089. {
  1090. int len;
  1091. uchar *code;
  1092. uchar *p;
  1093. InitPMCode();
  1094. if (state->VBEVersion >= 0x200 && state->pmInfo32 && !state->MMIOSel) {
  1095. code = (uchar*)state->pmInfo32 + state->pmInfo32->setWindow;
  1096. if (state->pmInfo32->extensionSig == VBE20_EXT_SIG)
  1097. len = state->pmInfo32->setWindowLen-1;
  1098. else {
  1099. /* We are running on a system without the UniVBE 5.2 extension.
  1100. * We do as best we can by scanning through the code for the
  1101. * ret function to determine the length. This is not foolproof,
  1102. * but is the best we can do.
  1103. */
  1104. p = code;
  1105. while (*p != 0xC3)
  1106. p++;
  1107. len = p - code;
  1108. }
  1109. if ((len + sizeof(VBE20A_bankFunc32_Start) + sizeof(VBE20_bankFunc32_End)) > sizeof(bankFunc32))
  1110. PM_fatalError("32-bit bank switch function too long!");
  1111. copy(p,bankFunc32,VBE20A_bankFunc32_Start);
  1112. memcpy(p,code,len);
  1113. p += len;
  1114. copy(p,p,VBE20_bankFunc32_End);
  1115. *codeLen = p - bankFunc32;
  1116. bankFunc32[VBE20_adjustOffset] = (uchar)bankAdjust;
  1117. *bankFunc = bankFunc32;
  1118. return true;
  1119. }
  1120. return false;
  1121. }
  1122. #endif