Leaked source code of windows server 2003
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.

568 lines
13 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. utils.c
  5. Abstract:
  6. This module contains utility functions for the sd bus driver
  7. Author:
  8. Neil Sandlin (neilsa) Jan 1 2002
  9. Environment:
  10. Kernel mode
  11. Revision History :
  12. --*/
  13. #include "pch.h"
  14. //
  15. // Internal References
  16. //
  17. NTSTATUS
  18. SdbusAdapterIoCompletion(
  19. IN PDEVICE_OBJECT DeviceObject,
  20. IN PIRP Irp,
  21. IN PKEVENT pdoIoCompletedEvent
  22. );
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(PAGE, SdbusGetInterface)
  25. #pragma alloc_text(PAGE, SdbusReportControllerError)
  26. #pragma alloc_text(PAGE, SdbusStringsToMultiString)
  27. #endif
  28. //
  29. //
  30. //
  31. NTSTATUS
  32. SdbusIoCallDriverSynchronous(
  33. PDEVICE_OBJECT deviceObject,
  34. PIRP Irp
  35. )
  36. /*++
  37. Routine Description
  38. Arguments
  39. Return Value
  40. --*/
  41. {
  42. NTSTATUS status;
  43. KEVENT event;
  44. KeInitializeEvent(&event, NotificationEvent, FALSE);
  45. IoCopyCurrentIrpStackLocationToNext(Irp);
  46. IoSetCompletionRoutine(
  47. Irp,
  48. SdbusAdapterIoCompletion,
  49. &event,
  50. TRUE,
  51. TRUE,
  52. TRUE
  53. );
  54. status = IoCallDriver(deviceObject, Irp);
  55. if (status == STATUS_PENDING) {
  56. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  57. status = Irp->IoStatus.Status;
  58. }
  59. return status;
  60. }
  61. NTSTATUS
  62. SdbusAdapterIoCompletion(
  63. IN PDEVICE_OBJECT DeviceObject,
  64. IN PIRP Irp,
  65. IN PKEVENT pdoIoCompletedEvent
  66. )
  67. /*++
  68. Routine Description:
  69. Generic completion routine used by the driver
  70. Arguments:
  71. DeviceObject
  72. Irp
  73. pdoIoCompletedEvent - this event will be signalled before return of this routine
  74. Return value:
  75. Status
  76. --*/
  77. {
  78. KeSetEvent(pdoIoCompletedEvent, IO_NO_INCREMENT, FALSE);
  79. return STATUS_MORE_PROCESSING_REQUIRED;
  80. }
  81. NTSTATUS
  82. SdbusGetInterface(
  83. IN PDEVICE_OBJECT DeviceObject,
  84. IN CONST GUID *pGuid,
  85. IN USHORT sizeofInterface,
  86. OUT PINTERFACE pInterface
  87. )
  88. /*
  89. Routine Description
  90. Gets the interface exported by a lower driver, typically the bus driver
  91. Arguments
  92. Pdo - Pointer to physical device object for the device stack
  93. Return Value
  94. Status
  95. */
  96. {
  97. KEVENT event;
  98. PIRP irp;
  99. NTSTATUS status;
  100. IO_STATUS_BLOCK statusBlock;
  101. PIO_STACK_LOCATION irpSp;
  102. PAGED_CODE();
  103. KeInitializeEvent (&event, NotificationEvent, FALSE);
  104. irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
  105. DeviceObject,
  106. NULL,
  107. 0,
  108. 0,
  109. &event,
  110. &statusBlock
  111. );
  112. irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
  113. irp->IoStatus.Information = 0;
  114. irpSp = IoGetNextIrpStackLocation(irp);
  115. irpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
  116. irpSp->Parameters.QueryInterface.InterfaceType= pGuid;
  117. irpSp->Parameters.QueryInterface.Size = sizeofInterface;
  118. irpSp->Parameters.QueryInterface.Version = 1;
  119. irpSp->Parameters.QueryInterface.Interface = pInterface;
  120. status = IoCallDriver(DeviceObject, irp);
  121. if (status == STATUS_PENDING) {
  122. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  123. status = statusBlock.Status;
  124. }
  125. if (!NT_SUCCESS(status)) {
  126. DebugPrint((SDBUS_DEBUG_INFO, "GetInterface failed with status %x\n", status));
  127. }
  128. return status;
  129. }
  130. VOID
  131. SdbusWait(
  132. IN ULONG MicroSeconds
  133. )
  134. /*++
  135. Routine Description
  136. Waits for the specified interval before returning,
  137. by yielding execution.
  138. Arguments
  139. MicroSeconds - Amount of time to delay in microseconds
  140. Return Value
  141. None. Must succeed.
  142. --*/
  143. {
  144. LARGE_INTEGER dueTime;
  145. NTSTATUS status;
  146. if ((KeGetCurrentIrql() < DISPATCH_LEVEL) && (MicroSeconds > 50)) {
  147. DebugPrint((SDBUS_DEBUG_INFO, "SdbusWait: wait %d\n", MicroSeconds));
  148. //
  149. // Convert delay to 100-nanosecond intervals
  150. //
  151. dueTime.QuadPart = -((LONG) MicroSeconds*10);
  152. //
  153. // We wait for an event that'll never be set.
  154. //
  155. status = KeWaitForSingleObject(&SdbusDelayTimerEvent,
  156. Executive,
  157. KernelMode,
  158. FALSE,
  159. &dueTime);
  160. ASSERT(status == STATUS_TIMEOUT);
  161. } else {
  162. if (MicroSeconds > 50) {
  163. DebugPrint((SDBUS_DEBUG_INFO, "SdbusWait: STALL %d\n", MicroSeconds));
  164. }
  165. KeStallExecutionProcessor(MicroSeconds);
  166. }
  167. }
  168. ULONG
  169. SdbusCountOnes(
  170. IN ULONG Data
  171. )
  172. /*++
  173. Routine Description:
  174. Counts the number of 1's in the binary representation of the supplied argument
  175. Arguments:
  176. Data - supplied argument for which 1's need to be counted
  177. Return value:
  178. Number of 1's in binary rep. of Data
  179. --*/
  180. {
  181. ULONG count=0;
  182. while (Data) {
  183. Data &= (Data-1);
  184. count++;
  185. }
  186. return count;
  187. }
  188. VOID
  189. SdbusLogError(
  190. IN PFDO_EXTENSION DeviceExtension,
  191. IN ULONG ErrorCode,
  192. IN ULONG UniqueId,
  193. IN ULONG Argument
  194. )
  195. /*++
  196. Routine Description:
  197. This function logs an error.
  198. Arguments:
  199. DeviceExtension - Supplies a pointer to the port device extension.
  200. ErrorCode - Supplies the error code for this error.
  201. UniqueId - Supplies the UniqueId for this error.
  202. Return Value:
  203. None.
  204. --*/
  205. {
  206. PIO_ERROR_LOG_PACKET packet;
  207. packet = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(DeviceExtension->DeviceObject,
  208. sizeof(IO_ERROR_LOG_PACKET) + sizeof(ULONG));
  209. if (packet) {
  210. packet->ErrorCode = ErrorCode;
  211. packet->SequenceNumber = DeviceExtension->SequenceNumber++;
  212. packet->MajorFunctionCode = 0;
  213. packet->RetryCount = (UCHAR) 0;
  214. packet->UniqueErrorValue = UniqueId;
  215. packet->FinalStatus = STATUS_SUCCESS;
  216. packet->DumpDataSize = sizeof(ULONG);
  217. packet->DumpData[0] = Argument;
  218. IoWriteErrorLogEntry(packet);
  219. }
  220. }
  221. VOID
  222. SdbusLogErrorWithStrings(
  223. IN PFDO_EXTENSION DeviceExtension,
  224. IN ULONG ErrorCode,
  225. IN ULONG UniqueId,
  226. IN PUNICODE_STRING String1,
  227. IN PUNICODE_STRING String2
  228. )
  229. /*++
  230. Routine Description
  231. This function logs an error and includes the strings provided.
  232. Arguments:
  233. DeviceExtension - Supplies a pointer to the port device extension.
  234. ErrorCode - Supplies the error code for this error.
  235. UniqueId - Supplies the UniqueId for this error.
  236. String1 - The first string to be inserted.
  237. String2 - The second string to be inserted.
  238. Return Value:
  239. None.
  240. --*/
  241. {
  242. ULONG length;
  243. PCHAR dumpData;
  244. PIO_ERROR_LOG_PACKET packet;
  245. length = String1->Length + sizeof(IO_ERROR_LOG_PACKET) + 4;
  246. if (String2) {
  247. length += String2->Length;
  248. }
  249. if (length > ERROR_LOG_MAXIMUM_SIZE) {
  250. //
  251. // Don't have code to truncate strings so don't log this.
  252. //
  253. return;
  254. }
  255. packet = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(DeviceExtension->DeviceObject,
  256. (UCHAR) length);
  257. if (packet) {
  258. packet->ErrorCode = ErrorCode;
  259. packet->SequenceNumber = DeviceExtension->SequenceNumber++;
  260. packet->MajorFunctionCode = 0;
  261. packet->RetryCount = (UCHAR) 0;
  262. packet->UniqueErrorValue = UniqueId;
  263. packet->FinalStatus = STATUS_SUCCESS;
  264. packet->NumberOfStrings = 1;
  265. packet->StringOffset = (USHORT) ((PUCHAR)&packet->DumpData[0] - (PUCHAR)packet);
  266. packet->DumpDataSize = (USHORT) (length - sizeof(IO_ERROR_LOG_PACKET));
  267. packet->DumpDataSize /= sizeof(ULONG);
  268. dumpData = (PUCHAR) &packet->DumpData[0];
  269. RtlCopyMemory(dumpData, String1->Buffer, String1->Length);
  270. dumpData += String1->Length;
  271. if (String2) {
  272. *dumpData++ = '\\';
  273. *dumpData++ = '\0';
  274. RtlCopyMemory(dumpData, String2->Buffer, String2->Length);
  275. dumpData += String2->Length;
  276. }
  277. *dumpData++ = '\0';
  278. *dumpData++ = '\0';
  279. IoWriteErrorLogEntry(packet);
  280. }
  281. return;
  282. }
  283. BOOLEAN
  284. SdbusReportControllerError(
  285. IN PFDO_EXTENSION FdoExtension,
  286. NTSTATUS ErrorCode
  287. )
  288. /*++
  289. Routine Description
  290. Causes a pop-up dialog to appear indicating an error that
  291. we should tell the user about. The device description of the
  292. controller is also included in the text of the pop-up.
  293. Arguments
  294. FdoExtension - Pointer to device extension for sd controller
  295. ErrorCode - the ntstatus code for the error
  296. Return Value
  297. TRUE - If a an error was queued
  298. FALSE - If it failed for some reason
  299. --*/
  300. {
  301. UNICODE_STRING unicodeString;
  302. PWSTR deviceDesc = NULL;
  303. NTSTATUS status;
  304. ULONG length = 0;
  305. BOOLEAN retVal;
  306. PAGED_CODE();
  307. //
  308. // Obtain the device description for the SD controller
  309. // that is used in the error pop-up. If one cannot be obtained,
  310. // still pop-up the error dialog, indicating the controller as unknown
  311. //
  312. // First, find out the length of the buffer required to obtain
  313. // device description for this SD controller
  314. //
  315. status = IoGetDeviceProperty(FdoExtension->Pdo,
  316. DevicePropertyDeviceDescription,
  317. 0,
  318. NULL,
  319. &length
  320. );
  321. ASSERT(!NT_SUCCESS(status));
  322. if (status == STATUS_BUFFER_TOO_SMALL) {
  323. deviceDesc = ExAllocatePool(PagedPool, length);
  324. if (deviceDesc != NULL) {
  325. status = IoGetDeviceProperty(FdoExtension->Pdo,
  326. DevicePropertyDeviceDescription,
  327. length,
  328. deviceDesc,
  329. &length);
  330. if (!NT_SUCCESS(status)) {
  331. ExFreePool(deviceDesc);
  332. }
  333. } else {
  334. status = STATUS_INSUFFICIENT_RESOURCES;
  335. }
  336. }
  337. if (!NT_SUCCESS(status)) {
  338. deviceDesc = L"[unknown]";
  339. }
  340. RtlInitUnicodeString(&unicodeString, deviceDesc);
  341. retVal = IoRaiseInformationalHardError(
  342. ErrorCode,
  343. &unicodeString,
  344. NULL);
  345. //
  346. // Note: successful status here indicates success of
  347. // IoGetDeviceProperty above. This would mean we still have an
  348. // allocated buffer.
  349. //
  350. if (NT_SUCCESS(status)) {
  351. ExFreePool(deviceDesc);
  352. }
  353. return retVal;
  354. }
  355. NTSTATUS
  356. SdbusStringsToMultiString(
  357. IN PCSTR * Strings,
  358. IN ULONG Count,
  359. IN PUNICODE_STRING MultiString
  360. )
  361. /*++
  362. Routine Description:
  363. This routine formats a set of supplied strings into a multi string format, terminating
  364. it with a double '\0' character
  365. Arguments:
  366. Strings - Pointer to an array of strings
  367. Count - Number of strings in the supplied array which are packed into the multi-string
  368. MultiString - Pointer to the Unicode string which packs the supplied string as a multi-string
  369. terminated by double NULL
  370. Return value:
  371. STATUS_SUCCESS
  372. STATUS_INSUFFICIENT_RESOURCES - Could not allocate memory for the multi-string
  373. --*/
  374. {
  375. ULONG i, multiStringLength=0;
  376. UNICODE_STRING tempMultiString;
  377. PCSTR * currentString;
  378. ANSI_STRING ansiString;
  379. NTSTATUS status;
  380. ASSERT (MultiString->Buffer == NULL);
  381. for (i = Count, currentString = Strings; i > 0;i--, currentString++) {
  382. RtlInitAnsiString(&ansiString, *currentString);
  383. multiStringLength += RtlAnsiStringToUnicodeSize(&ansiString);
  384. }
  385. ASSERT(multiStringLength != 0);
  386. multiStringLength += sizeof(WCHAR);
  387. MultiString->Buffer = ExAllocatePool(PagedPool, multiStringLength);
  388. if (MultiString->Buffer == NULL) {
  389. return STATUS_INSUFFICIENT_RESOURCES;
  390. }
  391. MultiString->MaximumLength = (USHORT) multiStringLength;
  392. MultiString->Length = (USHORT) multiStringLength;
  393. tempMultiString = *MultiString;
  394. for (i = Count, currentString = Strings; i > 0;i--, currentString++) {
  395. RtlInitAnsiString(&ansiString, *currentString);
  396. status = RtlAnsiStringToUnicodeString(&tempMultiString,
  397. &ansiString,
  398. FALSE);
  399. ASSERT(NT_SUCCESS(status));
  400. ((PSTR) tempMultiString.Buffer) += tempMultiString.Length + sizeof(WCHAR);
  401. };
  402. //
  403. // Add one more NULL to terminate the multi string
  404. //
  405. RtlZeroMemory(tempMultiString.Buffer, sizeof(WCHAR));
  406. return STATUS_SUCCESS;
  407. }