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.

603 lines
12 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. utils.c
  5. Abstract:
  6. This module contains utility functions for the pcmcia driver
  7. Authors:
  8. Bob Rinne (BobRi) 3-Aug-1994
  9. Jeff McLeman 12-Apr-1994
  10. Ravisankar Pudipeddi (ravisp) 1-Nov-96
  11. Neil Sandlin (neilsa) June 1 1999
  12. Environment:
  13. Kernel mode
  14. Revision History :
  15. 6-Apr-95
  16. Modified for databook support - John Keys Databook
  17. 1-Nov-96
  18. Total overhaul to make this a bus enumerator - Ravisankar Pudipeddi (ravisp)
  19. 30-Mar-99
  20. Turn this module into really just utility routines
  21. --*/
  22. #include "pch.h"
  23. #pragma alloc_text(PAGE, PcmciaReportControllerError)
  24. //
  25. // Internal References
  26. //
  27. NTSTATUS
  28. PcmciaAdapterIoCompletion(
  29. IN PDEVICE_OBJECT DeviceObject,
  30. IN PIRP Irp,
  31. IN PKEVENT pdoIoCompletedEvent
  32. );
  33. VOID
  34. PcmciaPlayTone(
  35. IN ULONG Frequency,
  36. IN ULONG Duration
  37. );
  38. //
  39. //
  40. //
  41. NTSTATUS
  42. PcmciaIoCallDriverSynchronous(
  43. PDEVICE_OBJECT deviceObject,
  44. PIRP Irp
  45. )
  46. /*++
  47. Routine Description
  48. Arguments
  49. Return Value
  50. --*/
  51. {
  52. NTSTATUS status;
  53. KEVENT event;
  54. KeInitializeEvent(&event, NotificationEvent, FALSE);
  55. IoCopyCurrentIrpStackLocationToNext(Irp);
  56. IoSetCompletionRoutine(
  57. Irp,
  58. PcmciaAdapterIoCompletion,
  59. &event,
  60. TRUE,
  61. TRUE,
  62. TRUE
  63. );
  64. status = IoCallDriver(deviceObject, Irp);
  65. if (status == STATUS_PENDING) {
  66. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  67. status = Irp->IoStatus.Status;
  68. }
  69. return status;
  70. }
  71. NTSTATUS
  72. PcmciaAdapterIoCompletion(
  73. IN PDEVICE_OBJECT DeviceObject,
  74. IN PIRP Irp,
  75. IN PKEVENT pdoIoCompletedEvent
  76. )
  77. /*++
  78. Routine Description:
  79. Generic completion routine used by the driver
  80. Arguments:
  81. DeviceObject
  82. Irp
  83. pdoIoCompletedEvent - this event will be signalled before return of this routine
  84. Return value:
  85. Status
  86. --*/
  87. {
  88. KeSetEvent(pdoIoCompletedEvent, IO_NO_INCREMENT, FALSE);
  89. return STATUS_MORE_PROCESSING_REQUIRED;
  90. }
  91. VOID
  92. PcmciaWait(
  93. IN ULONG MicroSeconds
  94. )
  95. /*++
  96. Routine Description
  97. Waits for the specified interval before returning,
  98. by yielding execution.
  99. Arguments
  100. MicroSeconds - Amount of time to delay in microseconds
  101. Return Value
  102. None. Must succeed.
  103. --*/
  104. {
  105. LARGE_INTEGER dueTime;
  106. NTSTATUS status;
  107. if ((KeGetCurrentIrql() < DISPATCH_LEVEL) && (MicroSeconds > 50)) {
  108. //
  109. // Convert delay to 100-nanosecond intervals
  110. //
  111. dueTime.QuadPart = -((LONG) MicroSeconds*10);
  112. //
  113. // We wait for an event that'll never be set.
  114. //
  115. status = KeWaitForSingleObject(&PcmciaDelayTimerEvent,
  116. Executive,
  117. KernelMode,
  118. FALSE,
  119. &dueTime);
  120. ASSERT(status == STATUS_TIMEOUT);
  121. } else {
  122. KeStallExecutionProcessor(MicroSeconds);
  123. }
  124. }
  125. ULONG
  126. PcmciaCountOnes(
  127. IN ULONG Data
  128. )
  129. /*++
  130. Routine Description:
  131. Counts the number of 1's in the binary representation of the supplied argument
  132. Arguments:
  133. Data - supplied argument for which 1's need to be counted
  134. Return value:
  135. Number of 1's in binary rep. of Data
  136. --*/
  137. {
  138. ULONG count=0;
  139. while (Data) {
  140. Data &= (Data-1);
  141. count++;
  142. }
  143. return count;
  144. }
  145. VOID
  146. PcmciaLogError(
  147. IN PFDO_EXTENSION DeviceExtension,
  148. IN ULONG ErrorCode,
  149. IN ULONG UniqueId,
  150. IN ULONG Argument
  151. )
  152. /*++
  153. Routine Description:
  154. This function logs an error.
  155. Arguments:
  156. DeviceExtension - Supplies a pointer to the port device extension.
  157. ErrorCode - Supplies the error code for this error.
  158. UniqueId - Supplies the UniqueId for this error.
  159. Return Value:
  160. None.
  161. --*/
  162. {
  163. PIO_ERROR_LOG_PACKET packet;
  164. packet = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(DeviceExtension->DeviceObject,
  165. sizeof(IO_ERROR_LOG_PACKET) + sizeof(ULONG));
  166. if (packet) {
  167. packet->ErrorCode = ErrorCode;
  168. packet->SequenceNumber = DeviceExtension->SequenceNumber++;
  169. packet->MajorFunctionCode = 0;
  170. packet->RetryCount = (UCHAR) 0;
  171. packet->UniqueErrorValue = UniqueId;
  172. packet->FinalStatus = STATUS_SUCCESS;
  173. packet->DumpDataSize = sizeof(ULONG);
  174. packet->DumpData[0] = Argument;
  175. IoWriteErrorLogEntry(packet);
  176. }
  177. }
  178. VOID
  179. PcmciaLogErrorWithStrings(
  180. IN PFDO_EXTENSION DeviceExtension,
  181. IN ULONG ErrorCode,
  182. IN ULONG UniqueId,
  183. IN PUNICODE_STRING String1,
  184. IN PUNICODE_STRING String2
  185. )
  186. /*++
  187. Routine Description
  188. This function logs an error and includes the strings provided.
  189. Arguments:
  190. DeviceExtension - Supplies a pointer to the port device extension.
  191. ErrorCode - Supplies the error code for this error.
  192. UniqueId - Supplies the UniqueId for this error.
  193. String1 - The first string to be inserted.
  194. String2 - The second string to be inserted.
  195. Return Value:
  196. None.
  197. --*/
  198. {
  199. ULONG length;
  200. PCHAR dumpData;
  201. PIO_ERROR_LOG_PACKET packet;
  202. length = String1->Length + sizeof(IO_ERROR_LOG_PACKET) + 4;
  203. if (String2) {
  204. length += String2->Length;
  205. }
  206. if (length > ERROR_LOG_MAXIMUM_SIZE) {
  207. //
  208. // Don't have code to truncate strings so don't log this.
  209. //
  210. return;
  211. }
  212. packet = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(DeviceExtension->DeviceObject,
  213. (UCHAR) length);
  214. if (packet) {
  215. packet->ErrorCode = ErrorCode;
  216. packet->SequenceNumber = DeviceExtension->SequenceNumber++;
  217. packet->MajorFunctionCode = 0;
  218. packet->RetryCount = (UCHAR) 0;
  219. packet->UniqueErrorValue = UniqueId;
  220. packet->FinalStatus = STATUS_SUCCESS;
  221. packet->NumberOfStrings = 1;
  222. packet->StringOffset = (USHORT) ((PUCHAR)&packet->DumpData[0] - (PUCHAR)packet);
  223. packet->DumpDataSize = (USHORT) (length - sizeof(IO_ERROR_LOG_PACKET));
  224. packet->DumpDataSize /= sizeof(ULONG);
  225. dumpData = (PUCHAR) &packet->DumpData[0];
  226. RtlCopyMemory(dumpData, String1->Buffer, String1->Length);
  227. dumpData += String1->Length;
  228. if (String2) {
  229. *dumpData++ = '\\';
  230. *dumpData++ = '\0';
  231. RtlCopyMemory(dumpData, String2->Buffer, String2->Length);
  232. dumpData += String2->Length;
  233. }
  234. *dumpData++ = '\0';
  235. *dumpData++ = '\0';
  236. IoWriteErrorLogEntry(packet);
  237. }
  238. return;
  239. }
  240. BOOLEAN
  241. PcmciaReportControllerError(
  242. IN PFDO_EXTENSION FdoExtension,
  243. NTSTATUS ErrorCode
  244. )
  245. /*++
  246. Routine Description
  247. Causes a pop-up dialog to appear indicating an error that
  248. we should tell the user about. The device description of the
  249. controller is also included in the text of the pop-up.
  250. Arguments
  251. FdoExtension - Pointer to device extension for pcmcia controller
  252. ErrorCode - the ntstatus code for the error
  253. Return Value
  254. TRUE - If a an error was queued
  255. FALSE - If it failed for some reason
  256. --*/
  257. {
  258. UNICODE_STRING unicodeString;
  259. PWSTR deviceDesc = NULL;
  260. NTSTATUS status;
  261. ULONG length = 0;
  262. BOOLEAN retVal;
  263. PAGED_CODE();
  264. //
  265. // Obtain the device description for the PCMCIA controller
  266. // that is used in the error pop-up. If one cannot be obtained,
  267. // still pop-up the error dialog, indicating the controller as unknown
  268. //
  269. // First, find out the length of the buffer required to obtain
  270. // device description for this pcmcia controller
  271. //
  272. status = IoGetDeviceProperty(FdoExtension->Pdo,
  273. DevicePropertyDeviceDescription,
  274. 0,
  275. NULL,
  276. &length
  277. );
  278. ASSERT(!NT_SUCCESS(status));
  279. if (status == STATUS_BUFFER_TOO_SMALL) {
  280. deviceDesc = ExAllocatePool(PagedPool, length);
  281. if (deviceDesc != NULL) {
  282. status = IoGetDeviceProperty(FdoExtension->Pdo,
  283. DevicePropertyDeviceDescription,
  284. length,
  285. deviceDesc,
  286. &length);
  287. if (!NT_SUCCESS(status)) {
  288. ExFreePool(deviceDesc);
  289. }
  290. } else {
  291. status = STATUS_INSUFFICIENT_RESOURCES;
  292. }
  293. }
  294. if (!NT_SUCCESS(status)) {
  295. deviceDesc = L"[unknown]";
  296. }
  297. RtlInitUnicodeString(&unicodeString, deviceDesc);
  298. retVal = IoRaiseInformationalHardError(
  299. ErrorCode,
  300. &unicodeString,
  301. NULL);
  302. //
  303. // Note: successful status here indicates success of
  304. // IoGetDeviceProperty above. This would mean we still have an
  305. // allocated buffer.
  306. //
  307. if (NT_SUCCESS(status)) {
  308. ExFreePool(deviceDesc);
  309. }
  310. return retVal;
  311. }
  312. VOID
  313. PcmciaPlaySound(
  314. IN PCMCIA_SOUND_TYPE SoundType
  315. )
  316. /*++
  317. Routine Description:
  318. Plays the sound corresponding the supplied event,
  319. if sounds are enabled
  320. Arguments:
  321. SoundType - specifies the event the sound denotes
  322. Return Value:
  323. None
  324. --*/
  325. {
  326. if (!(PcmciaGlobalFlags & PCMCIA_GLOBAL_SOUNDS_ENABLED)) {
  327. return;
  328. }
  329. switch (SoundType) {
  330. case CARD_INSERTED_SOUND: {
  331. PcmciaPlayTone(660, 150);
  332. PcmciaPlayTone(880, 150);
  333. break;
  334. }
  335. case CARD_REMOVED_SOUND: {
  336. PcmciaPlayTone(880, 150);
  337. PcmciaPlayTone(660, 150);
  338. break;
  339. }
  340. case ERROR_SOUND: {
  341. PcmciaPlayTone(220, 350);
  342. break;
  343. }
  344. }
  345. }
  346. VOID
  347. PcmciaPlayTone(
  348. IN ULONG Frequency,
  349. IN ULONG Duration
  350. )
  351. /*++
  352. Routine Description:
  353. Plays the note of the specified frequency &
  354. duration on the computer's internal speaker.
  355. Arguments:
  356. Frequency - frequency of the note
  357. Duration - duration, in milliseconds, of the note
  358. Return Value:
  359. None
  360. --*/
  361. {
  362. KIRQL OldIrql;
  363. PPCMCIA_SOUND_EVENT soundEvent = ExAllocatePool(NonPagedPool, sizeof(PCMCIA_SOUND_EVENT));
  364. if (!soundEvent) {
  365. return;
  366. }
  367. soundEvent->NextEvent = NULL;
  368. soundEvent->Frequency = Frequency;
  369. soundEvent->Duration = Duration;
  370. //
  371. // Synchronize access to prevent two beeps from starting at once
  372. //
  373. KeAcquireSpinLock(&PcmciaToneLock, &OldIrql);
  374. if (PcmciaToneList != NULL) {
  375. PPCMCIA_SOUND_EVENT curEvent, prevEvent;
  376. //
  377. // List isn't empty, tack this new event on the end of the list
  378. //
  379. curEvent = PcmciaToneList;
  380. while(curEvent) {
  381. prevEvent = curEvent;
  382. curEvent = curEvent->NextEvent;
  383. }
  384. prevEvent->NextEvent = soundEvent;
  385. } else {
  386. LARGE_INTEGER dueTime;
  387. //
  388. // Nothing playing right now, start it up
  389. //
  390. PcmciaToneList = soundEvent;
  391. #if !defined(_WIN64)
  392. HalMakeBeep(soundEvent->Frequency);
  393. #endif
  394. dueTime.QuadPart = -((LONG) soundEvent->Duration*1000*10);
  395. KeSetTimer(&PcmciaToneTimer, dueTime, &PcmciaToneDpc);
  396. }
  397. KeReleaseSpinLock(&PcmciaToneLock, OldIrql);
  398. }
  399. VOID
  400. PcmciaPlayToneCompletion(
  401. IN PKDPC Dpc,
  402. IN PVOID Context,
  403. IN PVOID SystemArgument1,
  404. IN PVOID SystemArgument2
  405. )
  406. /*++
  407. Routine Description
  408. This routine turns off the beep at the end of the duration, and
  409. starts a new one, if one is queued.
  410. Arguments
  411. Return Value
  412. none
  413. --*/
  414. {
  415. KIRQL OldIrql;
  416. PPCMCIA_SOUND_EVENT oldEvent, soundEvent;
  417. //
  418. // turn off previous sound
  419. //
  420. #if !defined(_WIN64)
  421. HalMakeBeep(0);
  422. #endif
  423. KeAcquireSpinLock(&PcmciaToneLock, &OldIrql);
  424. //
  425. // dequeue the previous sound
  426. //
  427. oldEvent = PcmciaToneList;
  428. ASSERT(oldEvent != NULL);
  429. PcmciaToneList = soundEvent = oldEvent->NextEvent;
  430. KeReleaseSpinLock(&PcmciaToneLock, OldIrql);
  431. ExFreePool(oldEvent);
  432. if (soundEvent) {
  433. LARGE_INTEGER dueTime;
  434. //
  435. // turn on next sound, and reschedule timer
  436. //
  437. #if !defined(_WIN64)
  438. HalMakeBeep(soundEvent->Frequency);
  439. #endif
  440. dueTime.QuadPart = -((LONG) soundEvent->Duration*1000*10);
  441. KeSetTimer(&PcmciaToneTimer, dueTime, &PcmciaToneDpc);
  442. }
  443. }