Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

373 lines
10 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: device.c
  4. //
  5. // Description:
  6. //
  7. //
  8. //@@BEGIN_MSINTERNAL
  9. // Development Team:
  10. // S.Mohanraj
  11. // M.McLaughlin
  12. //
  13. // History: Date Author Comment
  14. //
  15. //@@END_MSINTERNAL
  16. //---------------------------------------------------------------------------
  17. //
  18. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  19. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  20. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  21. // PURPOSE.
  22. //
  23. // Copyright (c) 1995 Microsoft Corporation. All Rights Reserved.
  24. //
  25. //---------------------------------------------------------------------------
  26. #define IRPMJFUNCDESC
  27. //#define MAX_DEBUG 1
  28. #include "common.h"
  29. #ifndef UNDER_NT
  30. #include <ntddk.h>
  31. #include <windef.h>
  32. #pragma warning( disable : 4273 )
  33. #include "..\..\..\..\dos\dos386\vxd\ntkern\inc\rtl.h"
  34. #pragma warning( default : 4273 )
  35. #include "..\..\..\..\dos\dos386\vxd\ntkern\hal\ixisa.h"
  36. #else
  37. #include <nthal.h>
  38. // NOTE! In order to remove cross depot include file dependencies.
  39. // Which break peoples builds if they try to build drivers when they are
  40. // not enlisted in base, I have made a local copy of the file
  41. // base\hals\halx86\i386\ixisa.h. That is the file that defines the
  42. // real ADAPTER_OBJECT structure. This local copy should be kept in sync
  43. // with the original.
  44. #include "ixisa.h"
  45. #endif
  46. #include <rt.h>
  47. #include "glitch.h"
  48. // Maximum number of times we will retry allocating memory for aliasing
  49. // DMA buffers.
  50. #define MAX_RESERVE_RETRIES 128
  51. #ifndef UNDER_NT
  52. #include <vmm.h>
  53. ULONG __stdcall GLITCH_Init_VxD(VOID);
  54. #else
  55. PDEVICE_OBJECT pDO;
  56. #endif
  57. PVOID MapPhysicalToLinear(VOID *physicaladdress, ULONG numbytes, ULONG flags);
  58. ULONG GetCR3(VOID);
  59. VOID DriverUnload(
  60. IN PDRIVER_OBJECT DriverObject
  61. )
  62. {
  63. //dprintf((" DriverUnload Enter (DriverObject = %x)", DriverObject));
  64. Break();
  65. }
  66. NTSTATUS DriverEntry
  67. (
  68. IN PDRIVER_OBJECT DriverObject,
  69. IN PUNICODE_STRING usRegistryPathName
  70. )
  71. {
  72. #ifdef UNDER_NT
  73. UNICODE_STRING usDeviceName;
  74. UNICODE_STRING usLinkName;
  75. PHYSICAL_ADDRESS Physical;
  76. #endif
  77. ADAPTER_OBJECT *DmaControllerObject, *MasterAdapter;
  78. DEVICE_DESCRIPTION DmaDevice={0};
  79. ULONG MapRegisterCount;
  80. ULONG i;
  81. PVOID BadReserve[MAX_RESERVE_RETRIES];
  82. ULONG BadReserveCount=0;
  83. NTSTATUS Status = STATUS_SUCCESS;
  84. #ifdef UNDER_NT
  85. DriverObject->MajorFunction[IRP_MJ_CREATE] = DeviceIoCreate;
  86. DriverObject->MajorFunction[IRP_MJ_CLOSE] = DeviceIoClose;
  87. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIoControl;
  88. #endif
  89. DriverObject->DriverUnload = DriverUnload;
  90. // For now, keep the driver loaded always.
  91. ObReferenceObject(DriverObject);
  92. #ifndef UNDER_NT
  93. GLITCH_Init_VxD();
  94. #else
  95. RtlInitUnicodeString( &usDeviceName, STR_DEVICENAME );
  96. Status = IoCreateDevice( DriverObject, 0, &usDeviceName, FILE_DEVICE_SOUND, 0, FALSE, &pDO );
  97. if (!NT_SUCCESS(Status)) {
  98. return Status;
  99. }
  100. RtlInitUnicodeString( &usLinkName, STR_LINKNAME );
  101. Status = IoCreateSymbolicLink( &usLinkName, &usDeviceName );
  102. if(!NT_SUCCESS(Status)) {
  103. IoDeleteDevice( pDO );
  104. return Status;
  105. }
  106. #endif
  107. // Now allocate the buffer for writing glitch information.
  108. // Note that we actually allocate space for the GlitchInfo structure here
  109. // as well. We allocate space for the output buffer plus 1 page for
  110. // the GlitchInfo structure. This is so that they are tied together
  111. // and we can map both back to user mode at the same time. It is
  112. // also because it makes it easy for the user mode code to build its
  113. // own pointer to the actual output buffer from the pointer it
  114. // gets to the GlitchInfo structure. It is important that the
  115. // user mode code be able to do that easily because the pointer
  116. // that we put in the GlitchInfo structure is for our own kernel mode
  117. // use only. It cannot be used by the user mode code - since the
  118. // buffer will be mapped to a completely different virtual address
  119. // for the user mode code anyway.
  120. #ifdef UNDER_NT
  121. Physical.QuadPart=-1I64;
  122. GlitchInfo=(PGLITCHDATA)MmAllocateContiguousMemory(PROCPAGESIZE*(4+1), Physical);
  123. #else
  124. GlitchInfo=(PGLITCHDATA)ExAllocatePool(NonPagedPool, PROCPAGESIZE*(4+1));
  125. #endif
  126. if (GlitchInfo==NULL) {
  127. Status=STATUS_NO_MEMORY;
  128. #ifdef UNDER_NT
  129. IoDeleteSymbolicLink( &usLinkName );
  130. IoDeleteDevice( pDO );
  131. #endif
  132. return Status;
  133. }
  134. GlitchInfo->WriteLocation=0;
  135. GlitchInfo->ReadLocation=0;
  136. // The output or print buffersize MUST be a power of 2. This is because the read and write
  137. // locations increment constantly and DO NOT WRAP with the buffer size. That is intentional
  138. // because it makes checking whether there is data in the buffer or not very simple and atomic.
  139. // However, the read and write locations will wrap on 32 bit boundaries. This is OK as long as
  140. // our buffersize divides into 2^32 evenly, which it always will if it is a power of 2.
  141. GlitchInfo->BufferSize=PROCPAGESIZE*4;
  142. GlitchInfo->pBuffer=(PCHAR)GlitchInfo+PROCPAGESIZE;
  143. // Mark every slot in the output buffer empty.
  144. for (i=0; i<GlitchInfo->BufferSize; i+=PACKETSIZE) {
  145. ((ULONG *)GlitchInfo->pBuffer)[i/sizeof(ULONG)]=NODATA;
  146. }
  147. DmaDevice.Version=DEVICE_DESCRIPTION_VERSION1;
  148. DmaDevice.Master=FALSE;
  149. DmaDevice.ScatterGather=FALSE;
  150. DmaDevice.DemandMode=FALSE;
  151. DmaDevice.AutoInitialize=TRUE;
  152. DmaDevice.Dma32BitAddresses=TRUE;
  153. DmaDevice.IgnoreCount=FALSE;
  154. DmaDevice.Reserved1=FALSE;
  155. DmaDevice.DmaChannel=0;
  156. DmaDevice.InterfaceType=Internal; // Internal, ISA, EISA
  157. DmaDevice.DmaWidth=Width8Bits; // Width8Bits, Width16Bits, or Width32Bits
  158. DmaDevice.DmaSpeed=Compatible; // Compatible, TypeA, TypeB, or TypeC
  159. DmaDevice.MaximumLength=1<<12;
  160. DmaDevice.DmaPort=0;
  161. MapRegisterCount=1;
  162. DmaControllerObject=(ADAPTER_OBJECT *)HalGetAdapter(&DmaDevice, &MapRegisterCount);
  163. MasterAdapter=DmaControllerObject->MasterAdapter;
  164. for (i=0; i<8; i++) {
  165. if (i==2 || i==4) {
  166. continue;
  167. }
  168. if (MasterAdapter->AdapterBaseVa==(PVOID)(-1I64)) {
  169. PDMAINFO ChannelInfo;
  170. // First allocate space for tracking this channel.
  171. ChannelInfo=(PDMAINFO)ExAllocatePool(NonPagedPool, sizeof(DMAINFO));
  172. if (ChannelInfo==NULL) {
  173. Status=STATUS_NO_MEMORY;
  174. break;
  175. }
  176. // Fill in information about this channel.
  177. ChannelInfo->Channel=i;
  178. ChannelInfo->pMasterAdapterSpinLock=&MasterAdapter->SpinLock;
  179. ChannelInfo->Read32BitPhysicalAddresses=MasterAdapter->Dma32BitAddresses;
  180. // Now get CR3 and map the page directory. This enables us to remap
  181. // the physical pages inside our RT thread. So, we can map our pDmaBuffer
  182. // to whatever physical addresses the hardware DMA buffer is mapped to.
  183. ChannelInfo->CR3=GetCR3();
  184. ChannelInfo->PageDirectory=(PULONG)MapPhysicalToLinear((PVOID)ChannelInfo->CR3, PROCPAGESIZE, 0);
  185. // Now get a set of linear pages that we can remap to whereever we need.
  186. // Make SURE that this set of linear pages all share a single page directory entry.
  187. // To do this we use a very simple algorithm. If any of the allocations we
  188. // make happens to cross a page directory entry (4MB boundary) then simply
  189. // save the location of the bad allocation, and make another allocation.
  190. // We will free all of the bad allocations after we have processed all of the
  191. // channels. That way we hold onto all the bad allocations until after we have
  192. // finish getting a full set of acceptable allocations.
  193. #ifdef UNDER_NT
  194. #define PR_SYSTEM 0
  195. #define PR_FIXED 0
  196. #endif
  197. ChannelInfo->pDmaBuffer=NULL;
  198. while (ChannelInfo->pDmaBuffer==NULL && BadReserveCount<MAX_RESERVE_RETRIES) {
  199. ChannelInfo->pDmaBuffer=ReservePages(PR_SYSTEM, PAGECOUNT, PR_FIXED);
  200. // Does this set of pages cross a 4MB boundary?
  201. if (((ULONG_PTR)ChannelInfo->pDmaBuffer^((ULONG_PTR)ChannelInfo->pDmaBuffer+PAGECOUNT*PROCPAGESIZE))&(4*1024*1024)) {
  202. // This set of pages crosses page directory entries. Dump it and retry.
  203. BadReserve[BadReserveCount++]=ChannelInfo->pDmaBuffer;
  204. ChannelInfo->pDmaBuffer=NULL;
  205. }
  206. }
  207. if (ChannelInfo->pDmaBuffer==NULL) {
  208. Status=STATUS_NO_MEMORY;
  209. break;
  210. }
  211. // Now get a linear address for the page table containing this set of reserved pages.
  212. // I need that so I can change the page table entries and map the pages directly.
  213. ChannelInfo->PageTable=MapPhysicalToLinear((PVOID)((ChannelInfo->PageDirectory[(ULONG)(ChannelInfo->pDmaBuffer)>>22])&(~(PROCPAGESIZE-1))), PROCPAGESIZE, 0);
  214. // Now lock down my linear address alias of my page.
  215. //LockPages((ULONG)ChannelInfo->PageTable, 1, 0, 0);
  216. // This fails. The function returns zero, it has to be non zero for success.
  217. ChannelInfo->DmaBufferSize=0;
  218. ChannelInfo->PhysicalDmaBufferStart=0;
  219. ChannelInfo->pPrintBuffer=GlitchInfo->pBuffer;
  220. ChannelInfo->PrintBufferSize=GlitchInfo->BufferSize;
  221. ChannelInfo->pPrintLoad=&GlitchInfo->WriteLocation;
  222. ChannelInfo->pPrintEmpty=&GlitchInfo->ReadLocation;
  223. // Create the realtime glitch detection thread.
  224. Status=RtCreateThread(1*MSEC, 50*USEC, 0, 2, GlitchDetect, (PVOID)ChannelInfo, NULL);
  225. if (!NT_SUCCESS(Status)) {
  226. // Free the ChannelInfo we allocated for this realtime thread.
  227. ExFreePool(ChannelInfo);
  228. // Stop trying to create additional realtime threads.
  229. break;
  230. }
  231. }
  232. else {
  233. Trap();
  234. Status=STATUS_UNSUCCESSFUL;
  235. break;
  236. }
  237. }
  238. // Now clean up properly if we failed during creation of the glitch monitor
  239. // realtime threads.
  240. // Note that we only free up allocated resources if NO realtime threads were
  241. // successfully created. If we successfully created ANY realtime threads,
  242. // then do not shut them down, and return STATUS_SUCCESS.
  243. if (!NT_SUCCESS(Status) && i==0) {
  244. #ifdef UNDER_NT
  245. MmFreeContiguousMemory(GlitchInfo);
  246. IoDeleteSymbolicLink( &usLinkName );
  247. IoDeleteDevice( pDO );
  248. #else
  249. ExFreePool(GlitchInfo);
  250. #endif
  251. }
  252. else {
  253. #ifdef UNDER_NT
  254. pDO->Flags |= DO_DIRECT_IO ;
  255. pDO->Flags &= ~DO_DEVICE_INITIALIZING;
  256. #endif
  257. Status=STATUS_SUCCESS; // We MUST do this in case Status is an error, but i!=0.
  258. }
  259. // Now clean up any bad reserves before we leave.
  260. // Note that we do this here instead of before the above if statement, so that
  261. // we can reuse i without screwing up the i=0 check in the if statement.
  262. for (i=0; i<BadReserveCount; i++) {
  263. FreePages(BadReserve[i], 0);
  264. }
  265. DbgPrint("Glitch.sys allocated %d DMA alias buffers that crossed 4MB boundaries.\n", BadReserveCount);
  266. return Status;
  267. }