MYVXD.C
Upload User: linklycbj
Upload Date: 2009-11-12
Package Size: 447k
Code Size: 10k
Category:

Windows Develop

Development Platform:

WINDOWS

  1. /*****************************************************************************/
  2. /*  */
  3. /*   Sample VxD illustrating how to do DMA from a VxD  */
  4. /*  */
  5. /*****************************************************************************/
  6. // To test this sample, you will need to prevent VFBACKUP from loading (because
  7. // it loads VFD.VXD, which virtualizes DMA channel 2). One way to do this
  8. // is to rename the StaticVxD named value in HKLMSystemCurrentControlSet
  9. // ServicesVxDVFBACKUP to something else. You will also need to disable
  10. // the real A-drive in Device Manager. For example, Uncheck the box that
  11. // makes it part of your current configuration. Finally, you will have to
  12. // remove the ForcedConfig from the A-drive's hardware key. You'll usually
  13. // find this in HKLMEnumRoot*PNP0700000. You should rename this value
  14. // so you can restore it later.
  15. #define WANTVXDWRAPS
  16. #include <basedef.h>
  17. #include <vmm.h>
  18. #include <debug.h>
  19. #include <vpicd.h>
  20. #include <vxdwraps.h>
  21. #include <configmg.h>
  22. #include "vdmad.h" // N.B.: Our own header file
  23. #include "crs.h" // ditto
  24. ///////////////////////////////////////////////////////////////////////////////
  25. // Useful general-purpose definitions
  26. #ifdef DEBUG
  27. #define ASSERT(e) if(!(e)){Debug_Printf("Assertion failure in " __FILE__ ", line %d: " #e "rn", __LINE__);
  28. _asm int 1
  29. }
  30. #else
  31. #define ASSERT(e)
  32. #endif
  33. #ifndef MAKELONG
  34. #define MAKELONG(low, high) ((LONG)(((WORD)(low)) | (((DWORD)((WORD)(high))) << 16)))
  35. #endif
  36. #ifndef FIELDOFFSET
  37. #define FIELDOFFSET(type, field)    ((DWORD)(&((type *)0)->field))
  38. #endif
  39. ///////////////////////////////////////////////////////////////////////////////
  40. DMAHANDLE dmahandle; // virtualized DMA channel handle
  41. HIRQ irqhandle; // virtualized IRQ handle
  42. DWORD baseport; // I/O base address (i.e., 3F2)
  43. VMM_SEMAPHORE waitsem; // semaphore to wait on
  44. CONFIGRET CM_HANDLER OnConfigure(CONFIGFUNC cf, SUBCONFIGFUNC scf, DEVNODE devnode, DWORD refdata, ULONG flags);
  45. void Hw_Int_Proc_Thunk();
  46. BOOL Hw_Int_Proc(HIRQ hirq, DWORD refdata);
  47. void FdcWakeup();
  48. void FdcWrite(DWORD baseport, BYTE* data, int length);
  49. void FdcWait(DWORD baseport);
  50. ///////////////////////////////////////////////////////////////////////////////
  51. BOOL OnSysDynamicDeviceInit()
  52. { // OnSysDynamicDeviceInit
  53. waitsem = Create_Semaphore(0);
  54. return waitsem != NULL;
  55. } // OnSysDynamicDeviceInit
  56. ///////////////////////////////////////////////////////////////////////////////
  57. BOOL OnSysDynamicDeviceExit()
  58. { // OnSysDynamicDeviceExit
  59. if (waitsem)
  60. Destroy_Semaphore(waitsem);
  61. return TRUE;
  62. } // OnSysDynamicDeviceExit
  63. ///////////////////////////////////////////////////////////////////////////////
  64. CONFIGRET OnPnpNewDevnode(DEVNODE devnode, DWORD loadtype)
  65. { // OnPnpNewDevnode
  66. return CM_Register_Device_Driver(devnode, OnConfigure, 0, CM_REGISTER_DEVICE_DRIVER_REMOVABLE | CM_REGISTER_DEVICE_DRIVER_DISABLEABLE);
  67. } // OnPnpNewDevnode
  68. ///////////////////////////////////////////////////////////////////////////////
  69. CONFIGRET CM_HANDLER OnConfigure(CONFIGFUNC cf, SUBCONFIGFUNC scf, DEVNODE devnode, DWORD refdata, ULONG flags)
  70. { // OnConfigure
  71. switch (cf)
  72. { // handle configuration function
  73. case CONFIG_START:
  74. { // CONFIG_START
  75. CMCONFIG config;
  76. DWORD channel;
  77. DWORD irq;
  78. VID vid = {0, 0, (DWORD) Hw_Int_Proc_Thunk};
  79. CM_Get_Alloc_Log_Conf(&config, devnode, CM_GET_ALLOC_LOG_CONF_ALLOC);
  80. ASSERT(config.wNumIOPorts == 1);
  81. ASSERT(config.wNumIRQs == 1);
  82. ASSERT(config.wNumDMAs == 1);
  83. baseport = config.wIOPortBase[0];
  84. channel = config.bDMALst[0];
  85. irq = config.bIRQRegisters[0];
  86. ASSERT(baseport == 0x3F2);
  87. ASSERT(channel == 2);
  88. ASSERT(irq == 6);
  89. dmahandle = VDMAD_Virtualize_Channel(channel, NULL);
  90. ASSERT(dmahandle);
  91. vid.VID_IRQ_Number = (USHORT) irq;
  92. irqhandle = VPICD_Virtualize_IRQ(&vid);
  93. ASSERT(irqhandle);
  94. return CR_SUCCESS;
  95. } // CONFIG_START
  96. case CONFIG_STOP:
  97. case CONFIG_REMOVE:
  98. if (dmahandle)
  99. { // unvirtualize DMA channel
  100. VDMAD_Unvirtualize_Channel(dmahandle);
  101. dmahandle = NULL;
  102. } // unvirtualize DMA channel
  103. if (irqhandle)
  104. { // unvirtualize IRQ
  105. VPICD_Force_Default_Behavior(irqhandle);
  106. irqhandle = NULL;
  107. } // unvirtualize IRQ
  108. return CR_SUCCESS;
  109. default:
  110. return CR_DEFAULT;
  111. } // handle configuration function
  112. } // OnConfigure
  113. ///////////////////////////////////////////////////////////////////////////////
  114. void __declspec(naked) Hw_Int_Proc_Thunk()
  115. { // Hw_Int_Proc_Thunk
  116. _asm
  117. { // call hw int proc
  118. push edx ; ref data (if any)
  119. push eax ; IRQ handle
  120. call Hw_Int_Proc ; call C program
  121. add  esp, 8 ; lose args
  122. cmp  eax, 1 ; turn TRUE return into CLC
  123. ret ; return to VPICD
  124. } // call hw int proc
  125. } // Hw_Int_Proc_Thunk
  126. BOOL Hw_Int_Proc(HIRQ hirq, DWORD refdata)
  127. { // Hw_Int_Proc
  128. int i;
  129. BYTE status[7]; // 7 status bytes
  130. for (i = 0; i < 7; ++i)
  131. { // read status from controller
  132. BYTE c;
  133. FdcWait(baseport);
  134. _asm
  135. { // read next status byte
  136. mov edx, baseport ; DX = port to read from
  137. add dx, 3 ;   ..
  138. in al, dx ; read status byte
  139. mov c, al ;   ..
  140. } // read next status byte
  141. status[i] = c;
  142. } // read status from controller
  143. VPICD_Phys_EOI(hirq);
  144. Schedule_Global_Event(FdcWakeup, waitsem);
  145. return TRUE;
  146. } // Hw_Int_Proc
  147. void __declspec(naked) FdcWakeup()
  148. { // FdcWakeup
  149. _asm mov eax, edx ; EDX (ref data) = semaphore handle
  150. VMMCall(Signal_Semaphore_No_Switch); // wakeup waiting thread
  151. _asm ret
  152. } // FdcWakeup
  153. ///////////////////////////////////////////////////////////////////////////////
  154. void ApiEntry(HVM hVM, PTCB tcb, PCRS pRegs)
  155. { // ApiEntry
  156. static BYTE cmd[] = {3, 0xAF, 2, 0xE6, 0, 0, 0, 1, 2, 0x12, 0x1B, 255}; // read sector cmd
  157. DWORD buffer; // flat address of client's buffer
  158. DWORD code;
  159. // Initialize the floppy disk controller
  160. _asm
  161. { // initialize floppy controller
  162. mov edx, baseport ; DX = base port (3F2)
  163. mov al, 1Ch ; 0001 1 1 00 => motor A on, DMA, REST, select A
  164. out dx, al ;   ..
  165. jmp delay1
  166. delay1:
  167. jmp delay2
  168. delay2:
  169. add dx, 5 ; DX = 3F7
  170. xor al, al
  171. out dx, al
  172. } // initialize floppy controller
  173. // Setup DMA channel 2 to transfer 512 bytes to the buffer at client
  174. // DS:BX
  175. buffer = Client_Ptr_Flat(DS, BX);
  176. do { // force address translation on this channel
  177. code = VDMAD_Enable_Translation(dmahandle, hVM);
  178. } // force address translation on this channel
  179. while ((code & ET_WASENABLED) != ET_WASENABLED);
  180. VDMAD_Set_Virt_State(dmahandle, hVM, buffer,
  181. 512, DMA_type_write | DMA_single_mode);
  182. VDMAD_Default_Handler(dmahandle, hVM);
  183. // Program the floppy controller with a read-sector command to read
  184. // sector 0
  185. FdcWrite(baseport, cmd, sizeof(cmd));
  186. // Wait for the operation to complete
  187. Wait_Semaphore(waitsem, BLOCK_SVC_INTS);
  188. _asm
  189. { // turn motor off
  190. mov edx, baseport
  191. mov al, 0Ch
  192. out dx, al
  193. } // turn motor off
  194. } // ApiEntry
  195. void FdcWrite(DWORD baseport, BYTE* data, int length)
  196. { // FdcWrite
  197. while (length-- > 0)
  198. { // for each byte
  199. BYTE c = *data++; // next byte to write
  200. FdcWait(baseport); // wait until it's okay to write
  201. _asm
  202. { // write data byte
  203. mov edx, baseport ; compute port address
  204. add dx, 3 ;   ..
  205. mov al, c ; AL = next data byte
  206. out dx, al ; output data byte
  207. } // write data byte
  208. } // for each byte
  209. } // FdcWrite
  210. void FdcWait(DWORD baseport)
  211. { // FdcWait
  212. _asm
  213. { // wait for floppy controller
  214. mov edx, baseport ; base port address
  215. add dx, 2 ; point to status port
  216. waitloop:
  217. in al, dx ; read status byte
  218. test al, 80h ; wait for ready bit to become one
  219. jz waitloop ;   ..
  220. } // wait for floppy controller
  221. } // FdcWait
  222. ///////////////////////////////////////////////////////////////////////////////
  223. // Untested example of programming a DMA transfer the hard way:
  224. #pragma warning(disable:4035)
  225. VXDINLINE BOOL Time_Slice_Sleep(DWORD timeout)
  226. {
  227. _asm mov eax, timeout
  228. VMMCall(Time_Slice_Sleep)
  229. _asm mov eax, 0
  230. _asm setnz al ; 1 => timeout completed
  231. }
  232. #pragma warning(default:4035)
  233. DWORD foo(DWORD address, DWORD size, WORD mode, BYTE align, VMM_SEMAPHORE sem)
  234. { // foo
  235. DWORD code;
  236. DWORD result;
  237. BYTE id;
  238. code = VDMAD_Lock_DMA_Region(address, size, align, &result);
  239. if (code == 0 && result >= (VDMAD_Get_Max_Phys_Page() << 12))
  240. { // beyond maximum
  241. VDMAD_Unlock_DMA_Region(address, size);
  242. code = DMA_Invalid_Region;
  243. } // beyond maximum
  244. if (code)
  245. { // try to buffer transfer
  246. while ((code = VDMAD_Request_Buffer(address, size, &result, &id)) == DMA_Buffer_In_Use)
  247. Time_Slice_Sleep(100);
  248. if (code)
  249. return code; // must be Buffer_Too_Small
  250. } // try to buffer transfer
  251. VDMAD_Set_Region_Info(dmahandle, id, TRUE, address, size, result);
  252. if (id && (mode & DMA_type_read))
  253. VDMAD_Copy_To_Buffer(id, address, 0, size);
  254. VDMAD_Set_Phys_State(dmahandle, mode);
  255. VDMAD_UnMask_Channel(dmahandle, Get_Sys_VM_Handle());
  256. Wait_Semaphore(sem, BLOCK_SVC_INTS); // time passes...
  257. VDMAD_Mask_Channel(dmahandle);
  258. if (id)
  259. { // buffered xfer
  260. if (mode & DMA_type_write)
  261. VDMAD_Copy_From_Buffer(id, address, 0, size);
  262. VDMAD_Release_Buffer(id);
  263. } // buffered xfer
  264. else
  265. if (mode & DMA_type_write)
  266. VDMAD_Unlock_DMA_Region(address, size);
  267. else
  268. VDMAD_Unlock_DMA_Region_No_Dirty(address, size);
  269. return 0;
  270. } // foo