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.

339 lines
9.6 KiB

  1. /****************************************************************************
  2. *
  3. * device.c
  4. *
  5. * Kernel mode entry point for WDM drivers
  6. *
  7. * Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
  8. *
  9. * History
  10. * S.Mohanraj (MohanS)
  11. * M.McLaughlin (MikeM)
  12. * 5-19-97 - Noel Cross (NoelC)
  13. *
  14. ***************************************************************************/
  15. #define IRPMJFUNCDESC
  16. #include "wdmsys.h"
  17. KMUTEX wdmaMutex;
  18. KMUTEX mtxNote;
  19. LIST_ENTRY WdmaContextListHead;
  20. KMUTEX WdmaContextListMutex;
  21. //
  22. // For hardware notifications, we need to init these two values.
  23. //
  24. extern KSPIN_LOCK HardwareCallbackSpinLock;
  25. extern LIST_ENTRY HardwareCallbackListHead;
  26. extern PKSWORKER HardwareCallbackWorkerObject;
  27. extern WORK_QUEUE_ITEM HardwareCallbackWorkItem;
  28. //VOID kmxlPersistHWControlWorker(VOID);
  29. //---------------------------------------------------------------------------
  30. //---------------------------------------------------------------------------
  31. NTSTATUS AddFsContextToList(PWDMACONTEXT pWdmaContext)
  32. {
  33. NTSTATUS Status;
  34. PAGED_CODE();
  35. KeEnterCriticalRegion();
  36. Status = KeWaitForMutexObject(&WdmaContextListMutex, Executive, KernelMode,
  37. FALSE, NULL);
  38. if (NT_SUCCESS(Status))
  39. {
  40. InsertTailList(&WdmaContextListHead, &pWdmaContext->Next);
  41. KeReleaseMutex(&WdmaContextListMutex, FALSE);
  42. }
  43. pWdmaContext->fInList = NT_SUCCESS(Status);
  44. KeLeaveCriticalRegion();
  45. RETURN( Status );
  46. }
  47. NTSTATUS RemoveFsContextFromList(PWDMACONTEXT pWdmaContext)
  48. {
  49. NTSTATUS Status;
  50. PAGED_CODE();
  51. if (pWdmaContext->fInList) {
  52. KeEnterCriticalRegion();
  53. Status = KeWaitForMutexObject(&WdmaContextListMutex, Executive,
  54. KernelMode, FALSE, NULL);
  55. if (NT_SUCCESS(Status)) {
  56. RemoveEntryList(&pWdmaContext->Next);
  57. KeReleaseMutex(&WdmaContextListMutex, FALSE);
  58. }
  59. KeLeaveCriticalRegion();
  60. } else {
  61. Status = STATUS_SUCCESS;
  62. }
  63. RETURN( Status );
  64. }
  65. //
  66. // This routine walks the list of global context structures and calls the callback
  67. // routine with the structure. If the callback routine returns STATUS_MORE_DATA
  68. // the routine will keep on searching the list. If it returns an error or success
  69. // the search will end.
  70. //
  71. NTSTATUS
  72. EnumFsContext(
  73. FNCONTEXTCALLBACK fnCallback,
  74. PVOID pvoidRefData,
  75. PVOID pvoidRefData2
  76. )
  77. {
  78. NTSTATUS Status;
  79. PLIST_ENTRY ple;
  80. PWDMACONTEXT pContext;
  81. PAGED_CODE();
  82. //
  83. // Make sure that we can walk are list without being interrupted.
  84. //
  85. KeEnterCriticalRegion();
  86. Status = KeWaitForMutexObject(&WdmaContextListMutex, Executive,
  87. KernelMode, FALSE, NULL);
  88. if (NT_SUCCESS(Status))
  89. {
  90. //
  91. // Walk the list here and call the callback routine.
  92. //
  93. for(ple = WdmaContextListHead.Flink;
  94. ple != &WdmaContextListHead;
  95. ple = ple->Flink)
  96. {
  97. pContext = CONTAINING_RECORD(ple, WDMACONTEXT, Next);
  98. //
  99. // The callback routine will return STATUS_MORE_ENTRIES
  100. // if it's not done.
  101. //
  102. DPF(DL_TRACE|FA_USER,( "Calling fnCallback: %x %x",pvoidRefData,pvoidRefData2 ) );
  103. Status = fnCallback(pContext,pvoidRefData,pvoidRefData2);
  104. if( STATUS_MORE_ENTRIES != Status )
  105. {
  106. break;
  107. }
  108. }
  109. //
  110. // "break;" should bring us here to release our locks.
  111. //
  112. KeReleaseMutex(&WdmaContextListMutex, FALSE);
  113. } else {
  114. DPF(DL_WARNING|FA_USER,( "Failed to get Mutex: %x %x",pvoidRefData,pvoidRefData2 ) );
  115. }
  116. KeLeaveCriticalRegion();
  117. //
  118. // If the callback routine doesn't return a NTSTATUS, it didn't find
  119. // what it was looking for, thus, EnumFsContext returns as error.
  120. //
  121. if( STATUS_MORE_ENTRIES == Status )
  122. {
  123. Status = STATUS_UNSUCCESSFUL;
  124. }
  125. DPF(DL_TRACE|FA_USER,( "Returning Status: %x",Status ) );
  126. return Status;
  127. }
  128. NTSTATUS DriverEntry
  129. (
  130. IN PDRIVER_OBJECT DriverObject,
  131. IN PUNICODE_STRING usRegistryPathName
  132. )
  133. {
  134. NTSTATUS Status;
  135. PAGED_CODE();
  136. #ifdef DEBUG
  137. GetuiDebugLevel();
  138. #endif
  139. DPF(DL_TRACE|FA_ALL, ("************************************************************") );
  140. DPF(DL_TRACE|FA_ALL, ("* uiDebugLevel=%08X controls the debug output. To change",uiDebugLevel) );
  141. DPF(DL_TRACE|FA_ALL, ("* edit uiDebugLevel like: e uidebuglevel and set to ") );
  142. DPF(DL_TRACE|FA_ALL, ("* 0 - show only fatal error messages and asserts ") );
  143. DPF(DL_TRACE|FA_ALL, ("* 1 (Default) - Also show non-fatal errors and return codes ") );
  144. DPF(DL_TRACE|FA_ALL, ("* 2 - Also show trace messages ") );
  145. DPF(DL_TRACE|FA_ALL, ("* 4 - Show Every message ") );
  146. DPF(DL_TRACE|FA_ALL, ("************************************************************") );
  147. DriverObject->DriverExtension->AddDevice = PnpAddDevice;
  148. DriverObject->DriverUnload = PnpDriverUnload; // KsNullDriverUnload;
  149. DriverObject->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower;
  150. DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
  151. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp;
  152. DriverObject->MajorFunction[IRP_MJ_CREATE] = SoundDispatchCreate;
  153. DriverObject->MajorFunction[IRP_MJ_CLOSE] = SoundDispatchClose;
  154. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SoundDispatch;
  155. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SoundDispatchCleanup;
  156. KeInitializeMutex(&wdmaMutex, 0);
  157. KeInitializeMutex(&mtxNote, 0);
  158. //
  159. // Initialize the hardware event items
  160. //
  161. InitializeListHead(&HardwareCallbackListHead);
  162. KeInitializeSpinLock(&HardwareCallbackSpinLock);
  163. ExInitializeWorkItem(&HardwareCallbackWorkItem,
  164. (PWORKER_THREAD_ROUTINE)kmxlPersistHWControlWorker,
  165. (PVOID)NULL); //pnnode
  166. Status = KsRegisterWorker( DelayedWorkQueue, &HardwareCallbackWorkerObject );
  167. if (!NT_SUCCESS(Status))
  168. {
  169. DPFBTRAP();
  170. HardwareCallbackWorkerObject = NULL;
  171. }
  172. return STATUS_SUCCESS;
  173. }
  174. NTSTATUS
  175. DispatchPnp(
  176. IN PDEVICE_OBJECT pDeviceObject,
  177. IN PIRP pIrp
  178. )
  179. {
  180. PIO_STACK_LOCATION pIrpStack;
  181. PAGED_CODE();
  182. pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
  183. switch(pIrpStack->MinorFunction) {
  184. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  185. //
  186. // Mark the device as not disableable.
  187. //
  188. pIrp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
  189. break;
  190. }
  191. return(KsDefaultDispatchPnp(pDeviceObject, pIrp));
  192. }
  193. NTSTATUS
  194. PnpAddDevice(
  195. IN PDRIVER_OBJECT DriverObject,
  196. IN PDEVICE_OBJECT PhysicalDeviceObject
  197. )
  198. /*++
  199. Routine Description:
  200. When a new device is detected, PnP calls this entry point with the
  201. new PhysicalDeviceObject (PDO). The driver creates an associated
  202. FunctionalDeviceObject (FDO).
  203. Arguments:
  204. DriverObject -
  205. Pointer to the driver object.
  206. PhysicalDeviceObject -
  207. Pointer to the new physical device object.
  208. Return Values:
  209. STATUS_SUCCESS or an appropriate error condition.
  210. --*/
  211. {
  212. NTSTATUS Status;
  213. PDEVICE_OBJECT FunctionalDeviceObject;
  214. PDEVICE_INSTANCE pDeviceInstance;
  215. PAGED_CODE();
  216. DPF(DL_TRACE|FA_ALL, ("Entering"));
  217. //
  218. // The Software Bus Enumerator expects to establish links
  219. // using this device name.
  220. //
  221. Status = IoCreateDevice(
  222. DriverObject,
  223. sizeof( DEVICE_INSTANCE ),
  224. NULL, // FDOs are unnamed
  225. FILE_DEVICE_KS,
  226. 0,
  227. FALSE,
  228. &FunctionalDeviceObject );
  229. if (!NT_SUCCESS(Status)) {
  230. RETURN( Status );
  231. }
  232. pDeviceInstance = (PDEVICE_INSTANCE)FunctionalDeviceObject->DeviceExtension;
  233. Status = KsAllocateDeviceHeader(
  234. &pDeviceInstance->pDeviceHeader,
  235. 0,
  236. NULL );
  237. if (NT_SUCCESS(Status))
  238. {
  239. KsSetDevicePnpAndBaseObject(
  240. pDeviceInstance->pDeviceHeader,
  241. IoAttachDeviceToDeviceStack(
  242. FunctionalDeviceObject,
  243. PhysicalDeviceObject ),
  244. FunctionalDeviceObject );
  245. FunctionalDeviceObject->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE);
  246. FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  247. }
  248. else
  249. {
  250. IoDeleteDevice( FunctionalDeviceObject );
  251. }
  252. #ifdef PROFILE
  253. WdmaInitProfile();
  254. #endif
  255. InitializeListHead(&WdmaContextListHead);
  256. KeInitializeMutex(&WdmaContextListMutex, 0);
  257. InitializeListHead(&wdmaPendingIrpQueue.WdmaPendingIrpListHead);
  258. KeInitializeSpinLock(&wdmaPendingIrpQueue.WdmaPendingIrpListSpinLock);
  259. IoCsqInitialize( &wdmaPendingIrpQueue.Csq,
  260. WdmaCsqInsertIrp,
  261. WdmaCsqRemoveIrp,
  262. WdmaCsqPeekNextIrp,
  263. WdmaCsqAcquireLock,
  264. WdmaCsqReleaseLock,
  265. WdmaCsqCompleteCanceledIrp );
  266. RETURN( Status );
  267. }
  268. VOID
  269. PnpDriverUnload(
  270. IN PDRIVER_OBJECT DriverObject
  271. )
  272. {
  273. PAGED_CODE();
  274. DPF(DL_TRACE|FA_ALL,("Entering"));
  275. //
  276. // Wait for all or our scheduled work items to complete.
  277. //
  278. if( HardwareCallbackWorkerObject )
  279. {
  280. KsUnregisterWorker( HardwareCallbackWorkerObject );
  281. HardwareCallbackWorkerObject = NULL;
  282. }
  283. kmxlCleanupNoteList();
  284. }