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.

4109 lines
146 KiB

  1. /***************************************************************************
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. UTILS.C
  5. Abstract:
  6. Routines that don't fit anywhere else.
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  11. KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  12. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  13. PURPOSE.
  14. Copyright (c) 1998 Microsoft Corporation. All Rights Reserved.
  15. Revision History:
  16. 12/23/97 : created
  17. Authors:
  18. Tom Green
  19. ****************************************************************************/
  20. #include <wdm.h>
  21. #include <ntddser.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <usb.h>
  25. #include <usbdrivr.h>
  26. #include <usbdlib.h>
  27. #include <usbcomm.h>
  28. #ifdef WMI_SUPPORT
  29. #include <wmilib.h>
  30. #include <wmidata.h>
  31. #include <wmistr.h>
  32. #endif
  33. #include "usbser.h"
  34. #include "usbserpw.h"
  35. #include "serioctl.h"
  36. #include "utils.h"
  37. #include "debugwdm.h"
  38. #ifdef ALLOC_PRAGMA
  39. #if DBG
  40. #pragma alloc_text(PAGEUBS0, UsbSerLockPagableCodeSection)
  41. #endif
  42. #pragma alloc_text(PAGEUBS0, UsbSerGetRegistryKeyValue)
  43. #pragma alloc_text(PAGEUBS0, UsbSerUndoExternalNaming)
  44. #pragma alloc_text(PAGEUBS0, UsbSerDoExternalNaming)
  45. #pragma alloc_text(PAGEUBS0, StopDevice)
  46. #pragma alloc_text(PAGEUBS0, StartPerfTimer)
  47. #pragma alloc_text(PAGEUBS0, StopPerfTimer)
  48. #pragma alloc_text(PAGEUBS0, BytesPerSecond)
  49. #pragma alloc_text(PAGEUBS0, CallUSBD)
  50. #pragma alloc_text(PAGEUBS0, ConfigureDevice)
  51. #pragma alloc_text(PAGEUBS0, BuildRequest)
  52. // #pragma alloc_text(PAGEUBS0, BuildReadRequest) -- called from restartnotify
  53. #pragma alloc_text(PAGEUBS0, ClassVendorCommand)
  54. #pragma alloc_text(PAGEUBS0, StartRead)
  55. #pragma alloc_text(PAGEUBS0, StartNotifyRead)
  56. #pragma alloc_text(PAGEUBS0, UsbSerRestoreModemSettings)
  57. #pragma alloc_text(PAGEUBS0, StartDevice)
  58. #pragma alloc_text(PAGEUBS0, DeleteObjectAndLink)
  59. #pragma alloc_text(PAGEUBS0, RemoveDevice)
  60. // #pragma alloc_text(PAGEUSBS, CancelPendingWaitMasks) -- called from STOP
  61. #pragma alloc_text(PAGEUSBS, UsbSerTryToCompleteCurrent)
  62. #pragma alloc_text(PAGEUSBS, UsbSerGetNextIrp)
  63. #pragma alloc_text(PAGEUSBS, UsbSerStartOrQueue)
  64. #pragma alloc_text(PAGEUSBS, UsbSerCancelQueued)
  65. #pragma alloc_text(PAGEUSBS, UsbSerKillAllReadsOrWrites)
  66. #pragma alloc_text(PAGEUSBS, UsbSerKillPendingIrps)
  67. #pragma alloc_text(PAGEUSBS, UsbSerCompletePendingWaitMasks)
  68. #pragma alloc_text(PAGEUSBS, UsbSerProcessEmptyTransmit)
  69. #pragma alloc_text(PAGEUSBS, UsbSerCancelWaitOnMask)
  70. #endif // ALLOC_PRAGMA
  71. // we will support 256 devices, keep track of open slots here
  72. #define NUM_DEVICE_SLOTS 256
  73. LOCAL BOOLEAN Slots[NUM_DEVICE_SLOTS];
  74. LOCAL ULONG NumDevices;
  75. LOCAL PDEVICE_OBJECT GlobDeviceObject;
  76. USHORT RxBuffSize = RX_BUFF_SIZE;
  77. /************************************************************************/
  78. /* UsbSerGetRegistryValues */
  79. /************************************************************************/
  80. /* */
  81. /* Routine Description: */
  82. /* */
  83. /* Gets values from the registry */
  84. /* */
  85. /* Arguments: */
  86. /* */
  87. /* Handle Handle to the opened registry key */
  88. /* */
  89. /* PKeyNameString ANSI string to the desired key */
  90. /* */
  91. /* KeyNameStringLength Length of the KeyNameString */
  92. /* */
  93. /* PData Buffer to place the key value in */
  94. /* */
  95. /* DataLength Length of the data buffer */
  96. /* */
  97. /* PDevExt - pointer to the device extension */
  98. /* */
  99. /* Return Value: */
  100. /* */
  101. /* STATUS_SUCCESS if all works, otherwise status of system call that */
  102. /* went wrong. */
  103. /* */
  104. /************************************************************************/
  105. NTSTATUS
  106. UsbSerGetRegistryKeyValue(IN HANDLE Handle, IN PWCHAR PKeyNameString,
  107. IN ULONG KeyNameStringLength, IN PVOID PData,
  108. IN ULONG DataLength)
  109. {
  110. UNICODE_STRING keyName;
  111. ULONG length;
  112. PKEY_VALUE_FULL_INFORMATION pFullInfo;
  113. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  114. PAGED_CODE();
  115. DEBUG_LOG_PATH("enter UsbSerGetRegistryKeyValue");
  116. UsbSerSerialDump(USBSERTRACEOTH, (">UsbSerGetRegistryKeyValue\n"));
  117. RtlInitUnicodeString(&keyName, PKeyNameString);
  118. length = sizeof(KEY_VALUE_FULL_INFORMATION) + KeyNameStringLength
  119. + DataLength;
  120. pFullInfo = DEBUG_MEMALLOC(PagedPool, length);
  121. if (pFullInfo) {
  122. status = ZwQueryValueKey(Handle, &keyName,
  123. KeyValueFullInformation, pFullInfo,
  124. length, &length);
  125. if (NT_SUCCESS(status)) {
  126. //
  127. // If there is enough room in the data buffer,
  128. // copy the output
  129. //
  130. if (DataLength >= pFullInfo->DataLength) {
  131. RtlCopyMemory(PData, ((PUCHAR)pFullInfo)
  132. + pFullInfo->DataOffset,
  133. pFullInfo->DataLength);
  134. }
  135. }
  136. DEBUG_MEMFREE(pFullInfo);
  137. }
  138. DEBUG_LOG_ERROR(status);
  139. DEBUG_LOG_PATH("exit UsbSerGetRegistryKeyValue");
  140. DEBUG_TRACE3(("status (%08X)\n", status));
  141. UsbSerSerialDump(USBSERTRACEOTH, ("<UsbSerGetRegistryKeyValue %08X\n",
  142. status));
  143. return status;
  144. } // UsbSerGetRegistryKeyValue
  145. /************************************************************************/
  146. /* UsbSerUndoExternalNaming */
  147. /************************************************************************/
  148. /* */
  149. /* Routine Description: */
  150. /* */
  151. /* Remove any and all external namespace interfaces we exposed */
  152. /* */
  153. /* Arguments: */
  154. /* */
  155. /* PDevExt - pointer to the device extension */
  156. /* */
  157. /* Return Value: */
  158. /* */
  159. /* VOID */
  160. /* */
  161. /************************************************************************/
  162. VOID
  163. UsbSerUndoExternalNaming(IN PDEVICE_EXTENSION PDevExt)
  164. {
  165. PAGED_CODE();
  166. DEBUG_LOG_PATH("enter UsbSerUndoExternalNaming");
  167. UsbSerSerialDump(USBSERTRACEOTH, (">UsbSerUndoExternalNaming\n"));
  168. if (PDevExt->SymbolicLinkName.Buffer && PDevExt->CreatedSymbolicLink) {
  169. IoDeleteSymbolicLink(&PDevExt->SymbolicLinkName);
  170. }
  171. if (PDevExt->SymbolicLinkName.Buffer != NULL) {
  172. DEBUG_MEMFREE(PDevExt->SymbolicLinkName.Buffer);
  173. RtlInitUnicodeString(&PDevExt->SymbolicLinkName, NULL);
  174. }
  175. if (PDevExt->DosName.Buffer != NULL) {
  176. DEBUG_MEMFREE(PDevExt->DosName.Buffer);
  177. RtlInitUnicodeString(&PDevExt->DosName, NULL);
  178. }
  179. if (PDevExt->DeviceName.Buffer != NULL) {
  180. RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP,
  181. PDevExt->DeviceName.Buffer);
  182. DEBUG_MEMFREE(PDevExt->DeviceName.Buffer);
  183. RtlInitUnicodeString(&PDevExt->DeviceName, NULL);
  184. }
  185. #ifdef WMI_SUPPORT
  186. if (PDevExt->WmiIdentifier.Buffer)
  187. {
  188. DEBUG_MEMFREE(PDevExt->WmiIdentifier.Buffer);
  189. PDevExt->WmiIdentifier.MaximumLength
  190. = PDevExt->WmiIdentifier.Length = 0;
  191. PDevExt->WmiIdentifier.Buffer = NULL;
  192. }
  193. #endif
  194. DEBUG_LOG_PATH("exit UsbSerUndoExternalNaming");
  195. UsbSerSerialDump(USBSERTRACEOTH, ("<UsbSerUndoExternalNaming\n"));
  196. } // UsbSerUndoExternalNaming
  197. /************************************************************************/
  198. /* UsbSerDoExternalNaming */
  199. /************************************************************************/
  200. /* */
  201. /* Routine Description: */
  202. /* */
  203. /* Exposes interfaces in external namespace */
  204. /* */
  205. /* Arguments: */
  206. /* */
  207. /* PDevExt - pointer to the device extension */
  208. /* */
  209. /* Return Value: */
  210. /* */
  211. /* NTSTATUS */
  212. /* */
  213. /************************************************************************/
  214. NTSTATUS
  215. UsbSerDoExternalNaming(IN PDEVICE_EXTENSION PDevExt)
  216. {
  217. NTSTATUS status;
  218. HANDLE keyHandle;
  219. WCHAR *pRegName = NULL;
  220. UNICODE_STRING linkName;
  221. PAGED_CODE();
  222. DEBUG_LOG_PATH("enter UsbSerDoExternalNaming");
  223. UsbSerSerialDump(USBSERTRACEOTH, (">UsbSerDoExternalNaming\n"));
  224. RtlZeroMemory(&linkName, sizeof(UNICODE_STRING));
  225. linkName.MaximumLength = SYMBOLIC_NAME_LENGTH * sizeof(WCHAR);
  226. linkName.Buffer = DEBUG_MEMALLOC(PagedPool, linkName.MaximumLength
  227. + sizeof(WCHAR));
  228. if (linkName.Buffer == NULL) {
  229. status = STATUS_INSUFFICIENT_RESOURCES;
  230. goto UsbSerDoExternalNamingError;
  231. }
  232. RtlZeroMemory(linkName.Buffer, linkName.MaximumLength + sizeof(WCHAR));
  233. pRegName = DEBUG_MEMALLOC(PagedPool, SYMBOLIC_NAME_LENGTH * sizeof(WCHAR)
  234. + sizeof(WCHAR));
  235. if (pRegName == NULL) {
  236. status = STATUS_INSUFFICIENT_RESOURCES;
  237. goto UsbSerDoExternalNamingError;
  238. }
  239. status = IoOpenDeviceRegistryKey(PDevExt->PhysDeviceObject,
  240. PLUGPLAY_REGKEY_DEVICE,
  241. STANDARD_RIGHTS_READ, &keyHandle);
  242. if (status != STATUS_SUCCESS) {
  243. goto UsbSerDoExternalNamingError;
  244. }
  245. status = UsbSerGetRegistryKeyValue(keyHandle, L"PortName", sizeof(L"PortName"),
  246. pRegName, SYMBOLIC_NAME_LENGTH * sizeof(WCHAR));
  247. if (status != STATUS_SUCCESS) {
  248. status = UsbSerGetRegistryKeyValue(keyHandle, L"Identifier",
  249. sizeof(L"Identifier"), pRegName,
  250. SYMBOLIC_NAME_LENGTH * sizeof(WCHAR));
  251. if (status != STATUS_SUCCESS) {
  252. ZwClose(keyHandle);
  253. goto UsbSerDoExternalNamingError;
  254. }
  255. }
  256. ZwClose(keyHandle);
  257. #ifdef WMI_SUPPORT
  258. {
  259. ULONG bufLen;
  260. bufLen = wcslen(pRegName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
  261. PDevExt->WmiIdentifier.Buffer = DEBUG_MEMALLOC(PagedPool, bufLen);
  262. if (PDevExt->WmiIdentifier.Buffer == NULL)
  263. {
  264. status = STATUS_INSUFFICIENT_RESOURCES;
  265. goto UsbSerDoExternalNamingError;
  266. }
  267. RtlZeroMemory(PDevExt->WmiIdentifier.Buffer, bufLen);
  268. PDevExt->WmiIdentifier.Length = 0;
  269. PDevExt->WmiIdentifier.MaximumLength = (USHORT)bufLen - sizeof(WCHAR);
  270. RtlAppendUnicodeToString(&PDevExt->WmiIdentifier, pRegName);
  271. }
  272. #endif
  273. //
  274. // Create the "\\DosDevices\\<symbolicname>" string
  275. //
  276. RtlAppendUnicodeToString(&linkName, L"\\");
  277. RtlAppendUnicodeToString(&linkName, DEFAULT_DIRECTORY);
  278. RtlAppendUnicodeToString(&linkName, L"\\");
  279. RtlAppendUnicodeToString(&linkName, pRegName);
  280. //
  281. // Allocate pool and save the symbolic link name in the device extension
  282. //
  283. PDevExt->SymbolicLinkName.MaximumLength = linkName.Length + sizeof(WCHAR);
  284. PDevExt->SymbolicLinkName.Buffer
  285. = DEBUG_MEMALLOC(PagedPool, PDevExt->SymbolicLinkName.MaximumLength);
  286. if (PDevExt->SymbolicLinkName.Buffer == NULL) {
  287. status = STATUS_INSUFFICIENT_RESOURCES;
  288. goto UsbSerDoExternalNamingError;
  289. }
  290. RtlZeroMemory(PDevExt->SymbolicLinkName.Buffer,
  291. PDevExt->SymbolicLinkName.MaximumLength);
  292. RtlAppendUnicodeStringToString(&PDevExt->SymbolicLinkName, &linkName);
  293. status = IoCreateSymbolicLink(&PDevExt->SymbolicLinkName,
  294. &PDevExt->DeviceName);
  295. if (status != STATUS_SUCCESS) {
  296. goto UsbSerDoExternalNamingError;
  297. }
  298. PDevExt->CreatedSymbolicLink = TRUE;
  299. PDevExt->DosName.Buffer = DEBUG_MEMALLOC(PagedPool, 64 + sizeof(WCHAR));
  300. if (PDevExt->DosName.Buffer == NULL) {
  301. status = STATUS_INSUFFICIENT_RESOURCES;
  302. goto UsbSerDoExternalNamingError;
  303. }
  304. PDevExt->DosName.MaximumLength = 64 + sizeof(WCHAR);
  305. PDevExt->DosName.Length = 0;
  306. RtlZeroMemory(PDevExt->DosName.Buffer, PDevExt->DosName.MaximumLength);
  307. RtlAppendUnicodeToString(&PDevExt->DosName, pRegName);
  308. RtlZeroMemory(((PUCHAR)(&PDevExt->DosName.Buffer[0]))
  309. + PDevExt->DosName.Length, sizeof(WCHAR));
  310. status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, L"SERIALCOMM",
  311. PDevExt->DeviceName.Buffer, REG_SZ,
  312. PDevExt->DosName.Buffer,
  313. PDevExt->DosName.Length + sizeof(WCHAR));
  314. if (status != STATUS_SUCCESS) {
  315. goto UsbSerDoExternalNamingError;
  316. }
  317. UsbSerDoExternalNamingError:;
  318. //
  319. // Clean up error conditions
  320. //
  321. if (status != STATUS_SUCCESS) {
  322. if (PDevExt->DosName.Buffer != NULL) {
  323. DEBUG_MEMFREE(PDevExt->DosName.Buffer);
  324. PDevExt->DosName.Buffer = NULL;
  325. }
  326. if (PDevExt->CreatedSymbolicLink == TRUE) {
  327. IoDeleteSymbolicLink(&PDevExt->SymbolicLinkName);
  328. PDevExt->CreatedSymbolicLink = FALSE;
  329. }
  330. if (PDevExt->SymbolicLinkName.Buffer != NULL) {
  331. DEBUG_MEMFREE(PDevExt->SymbolicLinkName.Buffer);
  332. PDevExt->SymbolicLinkName.Buffer = NULL;
  333. }
  334. if (PDevExt->DeviceName.Buffer != NULL) {
  335. RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP,
  336. PDevExt->DeviceName.Buffer);
  337. }
  338. }
  339. //
  340. // Always clean up our temp buffers.
  341. //
  342. if (linkName.Buffer != NULL) {
  343. DEBUG_MEMFREE(linkName.Buffer);
  344. }
  345. if (pRegName != NULL) {
  346. DEBUG_MEMFREE(pRegName);
  347. }
  348. DEBUG_LOG_ERROR(status);
  349. DEBUG_LOG_PATH("exit UsbSerDoExternalNaming");
  350. DEBUG_TRACE3(("status (%08X)\n", status));
  351. UsbSerSerialDump(USBSERTRACEOTH, ("<UsbSerDoExternalNaming %08X\n", status));
  352. return status;
  353. } // UsbSerDoExternalNaming
  354. NTSTATUS
  355. UsbSerAbortPipes(IN PDEVICE_OBJECT PDevObj)
  356. /*++
  357. Routine Description:
  358. Called as part of sudden device removal handling.
  359. Cancels any pending transfers for all open pipes.
  360. Arguments:
  361. Ptrs to our FDO
  362. Return Value:
  363. NT status code
  364. --*/
  365. {
  366. NTSTATUS ntStatus = STATUS_SUCCESS;
  367. PURB pUrb;
  368. PDEVICE_EXTENSION pDevExt;
  369. ULONG pendingIrps;
  370. DEBUG_TRACE1(("UsbSerAbortPipes\n"));
  371. UsbSerSerialDump(USBSERTRACEOTH | USBSERTRACERD,
  372. (">UsbSerAbortPipes (%08X)\n", PDevObj));
  373. pDevExt = PDevObj->DeviceExtension;
  374. pUrb = DEBUG_MEMALLOC(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST));
  375. if (pUrb != NULL)
  376. {
  377. pUrb->UrbHeader.Length = (USHORT)sizeof(struct _URB_PIPE_REQUEST);
  378. pUrb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
  379. pUrb->UrbPipeRequest.PipeHandle = pDevExt->DataInPipe;
  380. ntStatus = CallUSBD(PDevObj, pUrb);
  381. if (ntStatus != STATUS_SUCCESS) {
  382. goto UsbSerAbortPipesErr;
  383. }
  384. //
  385. // Wait for all the read IRPS to drain
  386. //
  387. UsbSerSerialDump(USBSERTRACERD, ("DataInCountw %08X @ %08X\n",
  388. pDevExt->PendingDataInCount,
  389. &pDevExt->PendingDataInCount));
  390. //
  391. // Decrement for initial value
  392. //
  393. pendingIrps = InterlockedDecrement(&pDevExt->PendingDataInCount);
  394. if (pendingIrps) {
  395. DEBUG_TRACE1(("Abort DataIn Pipe\n"));
  396. UsbSerSerialDump(USBSERTRACEOTH, ("Waiting for DataIn Pipe\n"));
  397. KeWaitForSingleObject(&pDevExt->PendingDataInEvent, Executive,
  398. KernelMode, FALSE, NULL);
  399. }
  400. //
  401. // Reset counter
  402. //
  403. InterlockedIncrement(&pDevExt->PendingDataInCount);
  404. UsbSerSerialDump(USBSERTRACERD, ("DataInCountx %08X @ %08X\n",
  405. pDevExt->PendingDataInCount,
  406. &pDevExt->PendingDataInCount));
  407. pUrb->UrbHeader.Length = (USHORT)sizeof(struct _URB_PIPE_REQUEST);
  408. pUrb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
  409. pUrb->UrbPipeRequest.PipeHandle = pDevExt->DataOutPipe;
  410. ntStatus = CallUSBD(PDevObj, pUrb);
  411. if (ntStatus != STATUS_SUCCESS) {
  412. goto UsbSerAbortPipesErr;
  413. }
  414. //
  415. // Wait for all the write irps to drain
  416. //
  417. //
  418. // Decrement for initial value
  419. //
  420. pendingIrps = InterlockedDecrement(&pDevExt->PendingDataOutCount);
  421. if (pendingIrps) {
  422. UsbSerSerialDump(USBSERTRACEOTH, ("Waiting for DataOut Pipe\n"));
  423. KeWaitForSingleObject(&pDevExt->PendingDataOutEvent, Executive,
  424. KernelMode, FALSE, NULL);
  425. }
  426. //
  427. // Reset counter
  428. //
  429. InterlockedIncrement(&pDevExt->PendingDataOutCount);
  430. pUrb->UrbHeader.Length = (USHORT)sizeof(struct _URB_PIPE_REQUEST);
  431. pUrb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
  432. pUrb->UrbPipeRequest.PipeHandle = pDevExt->NotificationPipe;
  433. ntStatus = CallUSBD(PDevObj, pUrb);
  434. //
  435. // Wait for all the notify irps to drain
  436. //
  437. //
  438. // Decrement for initial value
  439. //
  440. pendingIrps = InterlockedDecrement(&pDevExt->PendingNotifyCount);
  441. if (pendingIrps) {
  442. UsbSerSerialDump(USBSERTRACEOTH, ("Waiting for Notify Pipe\n"));
  443. KeWaitForSingleObject(&pDevExt->PendingNotifyEvent, Executive,
  444. KernelMode, FALSE, NULL);
  445. }
  446. // //
  447. // Die my darling, die.
  448. //
  449. // IoCancelIrp(pDevExt->NotifyIrp);
  450. // Reset counter
  451. //
  452. InterlockedIncrement(&pDevExt->PendingNotifyCount);
  453. UsbSerAbortPipesErr:;
  454. DEBUG_MEMFREE(pUrb);
  455. } else {
  456. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  457. }
  458. UsbSerSerialDump(USBSERTRACEOTH | USBSERTRACERD,
  459. ("<UsbSerAbortPipes %08X\n", ntStatus));
  460. return ntStatus;
  461. }
  462. /************************************************************************/
  463. /* StartDevice */
  464. /************************************************************************/
  465. /* */
  466. /* Routine Description: */
  467. /* */
  468. /* Take care of processing needed to start device. */
  469. /* */
  470. /* Arguments: */
  471. /* */
  472. /* DeviceObject - pointer to a device object */
  473. /* Irp - pointer to an I/O Request Packet */
  474. /* */
  475. /* Return Value: */
  476. /* */
  477. /* NTSTATUS */
  478. /* */
  479. /************************************************************************/
  480. NTSTATUS
  481. StartDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  482. {
  483. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  484. NTSTATUS NtStatus = STATUS_SUCCESS;
  485. KEVENT Event;
  486. PVOID pPagingHandle;
  487. PAGED_CODE();
  488. DEBUG_LOG_PATH("enter StartDevice");
  489. DEBUG_TRACE1(("StartDevice\n"));
  490. // pass this down to the USB stack first
  491. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  492. //
  493. // Initialize our DPC's
  494. //
  495. KeInitializeDpc(&DeviceExtension->TotalReadTimeoutDpc,
  496. UsbSerReadTimeout, DeviceExtension);
  497. KeInitializeDpc(&DeviceExtension->IntervalReadTimeoutDpc,
  498. UsbSerIntervalReadTimeout, DeviceExtension);
  499. KeInitializeDpc(&DeviceExtension->TotalWriteTimeoutDpc,
  500. UsbSerWriteTimeout, DeviceExtension);
  501. //
  502. // Initialize timers
  503. //
  504. KeInitializeTimer(&DeviceExtension->WriteRequestTotalTimer);
  505. KeInitializeTimer(&DeviceExtension->ReadRequestTotalTimer);
  506. KeInitializeTimer(&DeviceExtension->ReadRequestIntervalTimer);
  507. //
  508. // Store values into the extension for interval timing.
  509. //
  510. //
  511. // If the interval timer is less than a second then come
  512. // in with a short "polling" loop.
  513. //
  514. // For large (> then 2 seconds) use a 1 second poller.
  515. //
  516. DeviceExtension->ShortIntervalAmount.QuadPart = -1;
  517. DeviceExtension->LongIntervalAmount.QuadPart = -10000000;
  518. DeviceExtension->CutOverAmount.QuadPart = 200000000;
  519. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  520. IoCopyCurrentIrpStackLocationToNext(Irp);
  521. IoSetCompletionRoutine(Irp, UsbSerSyncCompletion, &Event, TRUE, TRUE,
  522. TRUE);
  523. NtStatus = IoCallDriver(DeviceExtension->StackDeviceObject, Irp);
  524. // wait for Irp to complete if status is pending
  525. if(NtStatus == STATUS_PENDING)
  526. {
  527. KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE,
  528. NULL);
  529. }
  530. NtStatus = Irp->IoStatus.Status;
  531. if (!NT_SUCCESS(NtStatus)) {
  532. goto ExitStartDevice;
  533. }
  534. NtStatus = GetDeviceDescriptor(DeviceObject);
  535. if (!NT_SUCCESS(NtStatus)) {
  536. goto ExitStartDevice;
  537. }
  538. NtStatus = ConfigureDevice(DeviceObject);
  539. if (!NT_SUCCESS(NtStatus)) {
  540. goto ExitStartDevice;
  541. }
  542. //
  543. // Page in and lock necessary code
  544. //
  545. pPagingHandle = UsbSerLockPagableCodeSection(PAGEUSBSER_Function);
  546. // reset device
  547. ResetDevice(NULL, DeviceObject);
  548. // init stuff in device extension
  549. DeviceExtension->HandFlow.ControlHandShake = 0;
  550. DeviceExtension->HandFlow.FlowReplace = SERIAL_RTS_CONTROL;
  551. DeviceExtension->AcceptingRequests = TRUE;
  552. InitializeListHead(&DeviceExtension->ReadQueue);
  553. InitializeListHead(&DeviceExtension->ImmediateReadQueue);
  554. UsbSerDoExternalNaming(DeviceExtension);
  555. // clear DTR and RTS
  556. SetClrDtr(DeviceObject, FALSE);
  557. ClrRts(NULL, DeviceExtension);
  558. // kick off a read
  559. StartRead(DeviceExtension);
  560. // kick off a notification read
  561. StartNotifyRead(DeviceExtension);
  562. UsbSerUnlockPagableImageSection(pPagingHandle);
  563. ExitStartDevice:;
  564. if(NT_SUCCESS(NtStatus))
  565. {
  566. DeviceExtension->DeviceState = DEVICE_STATE_STARTED;
  567. // try and idle the modem
  568. // UsbSerFdoSubmitIdleRequestIrp(DeviceExtension);
  569. }
  570. Irp->IoStatus.Status = NtStatus;
  571. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  572. DEBUG_LOG_PATH("exit StartDevice");
  573. return NtStatus;
  574. } // StartDevice
  575. /************************************************************************/
  576. /* StopDevice */
  577. /************************************************************************/
  578. /* */
  579. /* Routine Description: */
  580. /* */
  581. /* Take care of processing needed to stop device. */
  582. /* */
  583. /* Arguments: */
  584. /* */
  585. /* DeviceObject - pointer to a device object */
  586. /* Irp - pointer to an I/O Request Packet */
  587. /* */
  588. /* Return Value: */
  589. /* */
  590. /* NTSTATUS */
  591. /* */
  592. /************************************************************************/
  593. NTSTATUS
  594. StopDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  595. {
  596. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  597. NTSTATUS NtStatus = STATUS_SUCCESS;
  598. ULONG Size;
  599. PURB Urb;
  600. PAGED_CODE();
  601. DEBUG_LOG_PATH("enter StopDevice");
  602. DEBUG_TRACE1(("StopDevice\n"));
  603. UsbSerFetchBooleanLocked(&DeviceExtension->AcceptingRequests,
  604. FALSE, &DeviceExtension->ControlLock);
  605. CancelPendingWaitMasks(DeviceExtension);
  606. if(DeviceExtension->DeviceState == DEVICE_STATE_STARTED)
  607. {
  608. DEBUG_TRACE1(("AbortPipes\n"));
  609. UsbSerAbortPipes(DeviceObject);
  610. }
  611. DeviceExtension->DeviceState = DEVICE_STATE_STOPPED;
  612. if(DeviceExtension->PendingIdleIrp)
  613. {
  614. IoCancelIrp(DeviceExtension->PendingIdleIrp);
  615. }
  616. Size = sizeof(struct _URB_SELECT_CONFIGURATION);
  617. Urb = DEBUG_MEMALLOC(NonPagedPool, Size);
  618. if(Urb)
  619. {
  620. UsbBuildSelectConfigurationRequest(Urb, (USHORT) Size, NULL);
  621. NtStatus = CallUSBD(DeviceObject, Urb);
  622. DEBUG_TRACE3(("Device Configuration Closed status = (%08X) "
  623. "USB status = (%08X)\n", NtStatus,
  624. Urb->UrbHeader.Status));
  625. DEBUG_MEMFREE(Urb);
  626. }
  627. else
  628. {
  629. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  630. }
  631. DEBUG_LOG_PATH("exit StopDevice");
  632. return NtStatus;
  633. } // StopDevice
  634. /************************************************************************/
  635. /* RemoveDevice */
  636. /************************************************************************/
  637. /* */
  638. /* Routine Description: */
  639. /* */
  640. /* Take care of processing needed to remove device. */
  641. /* */
  642. /* Arguments: */
  643. /* */
  644. /* DeviceObject - pointer to a device object */
  645. /* Irp - pointer to an I/O Request Packet */
  646. /* */
  647. /* Return Value: */
  648. /* */
  649. /* NTSTATUS */
  650. /* */
  651. /************************************************************************/
  652. NTSTATUS
  653. RemoveDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  654. {
  655. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  656. NTSTATUS NtStatus = STATUS_SUCCESS;
  657. PVOID pPagingHandle;
  658. PAGED_CODE();
  659. DEBUG_LOG_PATH("enter RemoveDevice");
  660. DEBUG_TRACE1(("RemoveDevice\n"));
  661. //
  662. // Page in and lock necessary code
  663. //
  664. pPagingHandle = UsbSerLockPagableCodeSection(PAGEUSBSER_Function);
  665. UsbSerFetchBooleanLocked(&DeviceExtension->AcceptingRequests,
  666. FALSE, &DeviceExtension->ControlLock);
  667. CancelPendingWaitMasks(DeviceExtension);
  668. //
  669. // Cancel all pending USB transactions
  670. //
  671. if(DeviceExtension->DeviceState == DEVICE_STATE_STARTED)
  672. {
  673. DEBUG_TRACE1(("AbortPipes\n"));
  674. UsbSerAbortPipes(DeviceObject);
  675. }
  676. //
  677. // Once we set accepting requests to false, we shouldn't
  678. // have any more contention here -- if we do, we're dead
  679. // because we're freeing memory out from under our feet.
  680. //
  681. DEBUG_TRACE1(("Freeing Allocated Memory\n"));
  682. // free allocated notify URB
  683. if(DeviceExtension->NotifyUrb)
  684. {
  685. DEBUG_MEMFREE(DeviceExtension->NotifyUrb);
  686. DeviceExtension->NotifyUrb = NULL;
  687. }
  688. // free allocated Read URB
  689. if(DeviceExtension->ReadUrb)
  690. {
  691. DEBUG_MEMFREE(DeviceExtension->ReadUrb);
  692. DeviceExtension->ReadUrb = NULL;
  693. }
  694. // free allocated device descriptor
  695. if(DeviceExtension->DeviceDescriptor)
  696. {
  697. DEBUG_MEMFREE(DeviceExtension->DeviceDescriptor);
  698. DeviceExtension->DeviceDescriptor = NULL;
  699. }
  700. // free up read buffer
  701. if(DeviceExtension->ReadBuff)
  702. {
  703. DEBUG_MEMFREE(DeviceExtension->ReadBuff);
  704. DeviceExtension->ReadBuff = NULL;
  705. }
  706. if(DeviceExtension->USBReadBuff)
  707. {
  708. DEBUG_MEMFREE(DeviceExtension->USBReadBuff);
  709. DeviceExtension->USBReadBuff = NULL;
  710. }
  711. // free up notification buffer
  712. if(DeviceExtension->NotificationBuff)
  713. {
  714. DEBUG_MEMFREE(DeviceExtension->NotificationBuff);
  715. DeviceExtension->NotificationBuff = NULL;
  716. }
  717. DEBUG_TRACE1(("Undo Serial Name\n"));
  718. UsbSerUndoExternalNaming(DeviceExtension);
  719. //
  720. // Pass this down to the next driver
  721. IoCopyCurrentIrpStackLocationToNext(Irp);
  722. NtStatus = IoCallDriver(DeviceExtension->StackDeviceObject, Irp);
  723. DEBUG_TRACE1(("Detach Device\n"));
  724. // detach device from stack
  725. IoDetachDevice(DeviceExtension->StackDeviceObject);
  726. DEBUG_TRACE1(("DevExt (%08X) DevExt Size (%08X)\n", DeviceExtension, sizeof(DEVICE_EXTENSION)));
  727. DEBUG_TRACE1(("Delete Object and Link\n"));
  728. // delete device object and symbolic link
  729. DeleteObjectAndLink(DeviceObject);
  730. DEBUG_TRACE1(("Done Removing Device\n"));
  731. DEBUG_LOG_PATH("exit RemoveDevice");
  732. UsbSerUnlockPagableImageSection(pPagingHandle);
  733. DeviceExtension->DeviceState = DEVICE_STATE_STOPPED;
  734. return NtStatus;
  735. } // RemoveDevice
  736. /************************************************************************/
  737. /* CreateDeviceObject */
  738. /************************************************************************/
  739. /* */
  740. /* Routine Description: */
  741. /* */
  742. /* Take care of processing needed to create device obeject for */
  743. /* device. */
  744. /* */
  745. /* Arguments: */
  746. /* */
  747. /* DriverObject - pointer to a driver object */
  748. /* DeviceObject - pointer to a device object pointer */
  749. /* DeviceName - pointer to a base name of device */
  750. /* */
  751. /* Return Value: */
  752. /* */
  753. /* NTSTATUS */
  754. /* */
  755. /************************************************************************/
  756. NTSTATUS
  757. CreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
  758. IN PDEVICE_OBJECT *DeviceObject,
  759. IN PCHAR DeviceName)
  760. {
  761. ANSI_STRING DevName;
  762. ANSI_STRING LinkName;
  763. NTSTATUS NtStatus;
  764. UNICODE_STRING DeviceNameUnicodeString;
  765. UNICODE_STRING LinkNameUnicodeString;
  766. PDEVICE_EXTENSION DeviceExtension;
  767. CHAR DeviceLinkBuffer[NAME_MAX];
  768. CHAR DeviceNameBuffer[NAME_MAX];
  769. ULONG DeviceInstance;
  770. ULONG bufferLen;
  771. KIRQL OldIrql;
  772. DEBUG_LOG_PATH("enter CreateDeviceObject");
  773. DEBUG_TRACE1(("CreateDeviceObject\n"));
  774. KeAcquireSpinLock(&GlobalSpinLock, &OldIrql);
  775. // let's get an instance
  776. for (DeviceInstance = 0; DeviceInstance < NUM_DEVICE_SLOTS;
  777. DeviceInstance++) {
  778. if (Slots[DeviceInstance] == FALSE)
  779. break;
  780. }
  781. KeReleaseSpinLock(&GlobalSpinLock, OldIrql);
  782. // check if we didn't have any empty slots
  783. if (DeviceInstance == NUM_DEVICE_SLOTS)
  784. NtStatus = STATUS_INVALID_DEVICE_REQUEST;
  785. else {
  786. // complete names of links and devices
  787. sprintf(DeviceLinkBuffer, "%s%s%03d", "\\DosDevices\\", DeviceName,
  788. DeviceInstance);
  789. sprintf(DeviceNameBuffer, "%s%s%03d", "\\Device\\", DeviceName,
  790. DeviceInstance);
  791. // init ANSI string with our link and device names
  792. RtlInitAnsiString(&DevName, DeviceNameBuffer);
  793. RtlInitAnsiString(&LinkName, DeviceLinkBuffer);
  794. DeviceNameUnicodeString.Length = 0;
  795. DeviceNameUnicodeString.Buffer = NULL;
  796. LinkNameUnicodeString.Length = 0;
  797. LinkNameUnicodeString.Buffer = NULL;
  798. *DeviceObject = NULL;
  799. // convert to UNICODE string
  800. NtStatus = RtlAnsiStringToUnicodeString(&DeviceNameUnicodeString,
  801. &DevName, TRUE);
  802. if(NT_SUCCESS(NtStatus))
  803. {
  804. NtStatus = RtlAnsiStringToUnicodeString(&LinkNameUnicodeString,
  805. &LinkName, TRUE);
  806. if(NT_SUCCESS(NtStatus))
  807. {
  808. DEBUG_TRACE3(("Create Device (%s)\n", DeviceNameBuffer));
  809. // create the device object
  810. NtStatus = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
  811. &DeviceNameUnicodeString,
  812. FILE_DEVICE_MODEM, 0, TRUE,
  813. DeviceObject);
  814. } else {
  815. goto CreateDeviceObjectError;
  816. }
  817. } else {
  818. goto CreateDeviceObjectError;
  819. }
  820. // created the device object O.K., create symbolic links,
  821. // attach device object, and fill in the device extension
  822. if (NT_SUCCESS(NtStatus)) {
  823. // create symbolic links
  824. DEBUG_TRACE3(("Create SymLink (%s)\n", DeviceLinkBuffer));
  825. NtStatus = IoCreateUnprotectedSymbolicLink(&LinkNameUnicodeString,
  826. &DeviceNameUnicodeString);
  827. if (NtStatus != STATUS_SUCCESS) {
  828. goto CreateDeviceObjectError;
  829. }
  830. // get pointer to device extension
  831. DeviceExtension = (PDEVICE_EXTENSION) (*DeviceObject)->DeviceExtension;
  832. // let's zero out device extension
  833. RtlZeroMemory(DeviceExtension, sizeof(DEVICE_EXTENSION));
  834. // save our strings
  835. // save link name
  836. strcpy(DeviceExtension->LinkName, DeviceLinkBuffer);
  837. bufferLen = RtlAnsiStringToUnicodeSize(&DevName);
  838. DeviceExtension->DeviceName.Length = 0;
  839. DeviceExtension->DeviceName.MaximumLength = (USHORT)bufferLen;
  840. DeviceExtension->DeviceName.Buffer = DEBUG_MEMALLOC(PagedPool,
  841. bufferLen);
  842. if (DeviceExtension->DeviceName.Buffer == NULL) {
  843. //
  844. // Skip out. We have worse problems than missing
  845. // the name.
  846. //
  847. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  848. goto CreateDeviceObjectError;
  849. } else {
  850. RtlAnsiStringToUnicodeString(&DeviceExtension->DeviceName, &DevName,
  851. FALSE);
  852. // save physical device object
  853. DeviceExtension->PhysDeviceObject = *DeviceObject;
  854. DeviceExtension->Instance = DeviceInstance;
  855. // initialize spinlocks
  856. KeInitializeSpinLock(&DeviceExtension->ControlLock);
  857. // mark this device slot as in use and increment number
  858. // of devices
  859. KeAcquireSpinLock(&GlobalSpinLock, &OldIrql);
  860. Slots[DeviceInstance] = TRUE;
  861. NumDevices++;
  862. KeReleaseSpinLock(&GlobalSpinLock, OldIrql);
  863. DeviceExtension->IsDevice = TRUE;
  864. KeInitializeEvent(&DeviceExtension->PendingDataInEvent,
  865. SynchronizationEvent, FALSE);
  866. KeInitializeEvent(&DeviceExtension->PendingDataOutEvent,
  867. SynchronizationEvent, FALSE);
  868. KeInitializeEvent(&DeviceExtension->PendingNotifyEvent,
  869. SynchronizationEvent, FALSE);
  870. KeInitializeEvent(&DeviceExtension->PendingFlushEvent,
  871. SynchronizationEvent, FALSE);
  872. DeviceExtension->PendingDataInCount = 1;
  873. DeviceExtension->PendingDataOutCount = 1;
  874. DeviceExtension->PendingNotifyCount = 1;
  875. DeviceExtension->SanityCheck = SANITY_CHECK;
  876. }
  877. }
  878. CreateDeviceObjectError:;
  879. // free Unicode strings
  880. RtlFreeUnicodeString(&DeviceNameUnicodeString);
  881. RtlFreeUnicodeString(&LinkNameUnicodeString);
  882. //
  883. // Delete the devobj if there was an error
  884. //
  885. if (NtStatus != STATUS_SUCCESS) {
  886. if (*DeviceObject) {
  887. IoDeleteDevice(*DeviceObject);
  888. *DeviceObject = NULL;
  889. }
  890. }
  891. }
  892. // log an error if we got one
  893. DEBUG_LOG_ERROR(NtStatus);
  894. DEBUG_LOG_PATH("exit CreateDeviceObject");
  895. DEBUG_TRACE3(("status (%08X)\n", NtStatus));
  896. return NtStatus;
  897. } // CreateDeviceObject
  898. /************************************************************************/
  899. /* CompleteIO */
  900. /************************************************************************/
  901. /* */
  902. /* Routine Description: */
  903. /* */
  904. /* Complete IO request and log IRP */
  905. /* */
  906. /* Arguments: */
  907. /* */
  908. /* DeviceObject - pointer to device object. */
  909. /* Irp - pointer to IRP. */
  910. /* MajorFunction - major function of IRP. */
  911. /* IoBuffer - buffer for data passed in and out of driver. */
  912. /* BufferLen - length of buffer */
  913. /* */
  914. /* Return Value: */
  915. /* */
  916. /* VOID */
  917. /* */
  918. /************************************************************************/
  919. VOID
  920. CompleteIO(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ULONG MajorFunction,
  921. IN PVOID IoBuffer, IN ULONG_PTR BufferLen)
  922. {
  923. PDEVICE_EXTENSION DeviceExtension;
  924. DEBUG_LOG_PATH("enter CompleteIO");
  925. // get pointer to device extension
  926. DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  927. // log IRP count and bytes processed in device extension
  928. DeviceExtension->IRPCount++;
  929. DeviceExtension->ByteCount
  930. = RtlLargeIntegerAdd(DeviceExtension->ByteCount,
  931. RtlConvertUlongToLargeInteger((ULONG)Irp->IoStatus
  932. .Information));
  933. // make entry in IRP history table
  934. DEBUG_LOG_IRP_HIST(DeviceObject, Irp, MajorFunction, IoBuffer,
  935. (ULONG)BufferLen);
  936. // if we got here, must want to complete request on IRP
  937. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  938. DEBUG_LOG_PATH("exit CompleteIO");
  939. } // CompleteIO
  940. /************************************************************************/
  941. /* DeleteObjectAndLink */
  942. /************************************************************************/
  943. /* */
  944. /* Routine Description: */
  945. /* */
  946. /* Deletes a device object and associated symbolic link */
  947. /* */
  948. /* Arguments: */
  949. /* */
  950. /* DeviceObject - pointer to device object. */
  951. /* */
  952. /* Return Value: */
  953. /* */
  954. /* NTSTATUS */
  955. /* */
  956. /************************************************************************/
  957. NTSTATUS
  958. DeleteObjectAndLink(IN PDEVICE_OBJECT DeviceObject)
  959. {
  960. PDEVICE_EXTENSION DeviceExtension;
  961. UNICODE_STRING DeviceLinkUnicodeString;
  962. ANSI_STRING DeviceLinkAnsiString;
  963. NTSTATUS NtStatus;
  964. PAGED_CODE();
  965. DEBUG_LOG_PATH("enter DeleteObjectAndLink");
  966. DEBUG_TRACE1(("DeleteObjectAndLink\n"));
  967. // get pointer to device extension, we will get the symbolic link name
  968. // here
  969. DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  970. // get rid of the symbolic link
  971. RtlInitAnsiString(&DeviceLinkAnsiString, DeviceExtension->LinkName);
  972. NtStatus = RtlAnsiStringToUnicodeString(&DeviceLinkUnicodeString,
  973. &DeviceLinkAnsiString, TRUE);
  974. DEBUG_TRACE1(("Delete Symbolic Link\n"));
  975. IoDeleteSymbolicLink(&DeviceLinkUnicodeString);
  976. // clear out slot and decrement number of devices
  977. if(DeviceExtension->Instance < NUM_DEVICE_SLOTS)
  978. {
  979. UsbSerFetchBooleanLocked(&Slots[DeviceExtension->Instance],
  980. FALSE, &GlobalSpinLock);
  981. NumDevices--;
  982. if(!NumDevices)
  983. DEBUG_CHECKMEM();
  984. }
  985. DEBUG_TRACE1(("Delete Device Object\n"));
  986. if(DeviceExtension->SanityCheck != SANITY_CHECK)
  987. {
  988. DEBUG_TRACE1(("Device Extension Scrozzled\n"));
  989. }
  990. // wait to do this till here as this triggers unload routine
  991. IoDeleteDevice(DeviceObject);
  992. DEBUG_TRACE1(("Done Deleting Device Object and Link\n"));
  993. DEBUG_LOG_PATH("exit DeleteObjectAndLink");
  994. return NtStatus;
  995. } // DeleteObjectAndLink
  996. /************************************************************************/
  997. /* StartPerfTimer */
  998. /************************************************************************/
  999. /* */
  1000. /* Routine Description: */
  1001. /* */
  1002. /* Start perf timer for measuring bytes/second throughput */
  1003. /* */
  1004. /* Arguments: */
  1005. /* */
  1006. /* DeviceExtension - pointer to device extension for device */
  1007. /* */
  1008. /* Return Value: */
  1009. /* */
  1010. /* VOID */
  1011. /* */
  1012. /************************************************************************/
  1013. VOID
  1014. StartPerfTimer(IN OUT PDEVICE_EXTENSION DeviceExtension)
  1015. {
  1016. PAGED_CODE();
  1017. // set up perf stuff if perf timing enabled
  1018. if(DeviceExtension && DeviceExtension->PerfTimerEnabled)
  1019. {
  1020. // get current perf counter
  1021. DeviceExtension->TimerStart = KeQueryPerformanceCounter(NULL);
  1022. }
  1023. } // StartPerfTimer
  1024. /************************************************************************/
  1025. /* StopPerfTimer */
  1026. /************************************************************************/
  1027. /* */
  1028. /* Routine Description: */
  1029. /* */
  1030. /* Stop perf timer for measuring bytes/second throughput */
  1031. /* */
  1032. /* Arguments: */
  1033. /* */
  1034. /* DeviceExtension - pointer to device extension for device */
  1035. /* BytesXfered - number of bytes tranferred this iteration */
  1036. /* */
  1037. /* Return Value: */
  1038. /* */
  1039. /* VOID */
  1040. /* */
  1041. /************************************************************************/
  1042. VOID
  1043. StopPerfTimer(IN OUT PDEVICE_EXTENSION DeviceExtension,
  1044. IN ULONG BytesXfered)
  1045. {
  1046. LARGE_INTEGER BytesThisTransfer;
  1047. LARGE_INTEGER CurrentTime;
  1048. LARGE_INTEGER TimeThisTransfer;
  1049. PAGED_CODE();
  1050. if(DeviceExtension && DeviceExtension->PerfTimerEnabled)
  1051. {
  1052. // get updated time
  1053. CurrentTime = KeQueryPerformanceCounter(NULL);
  1054. // stop perf timing with system timer
  1055. BytesThisTransfer = RtlConvertUlongToLargeInteger(BytesXfered);
  1056. DeviceExtension->BytesXfered
  1057. = RtlLargeIntegerAdd(DeviceExtension->BytesXfered,
  1058. BytesThisTransfer);
  1059. // now add the time it took to elapsed time
  1060. TimeThisTransfer
  1061. = RtlLargeIntegerSubtract(CurrentTime,
  1062. DeviceExtension->TimerStart);
  1063. DeviceExtension->ElapsedTime
  1064. = RtlLargeIntegerAdd(DeviceExtension->ElapsedTime,
  1065. TimeThisTransfer);
  1066. }
  1067. } // StopPerfTimer
  1068. /************************************************************************/
  1069. /* BytesPerSecond */
  1070. /************************************************************************/
  1071. /* */
  1072. /* Routine Description: */
  1073. /* */
  1074. /* Start perf timer for measuring bytes/second throughput */
  1075. /* */
  1076. /* Arguments: */
  1077. /* */
  1078. /* DeviceExtension - pointer to device extension for device */
  1079. /* */
  1080. /* Return Value: */
  1081. /* */
  1082. /* ULONG - bytes/second for device */
  1083. /* */
  1084. /************************************************************************/
  1085. ULONG
  1086. BytesPerSecond(IN OUT PDEVICE_EXTENSION DeviceExtension)
  1087. {
  1088. ULONG Remainder;
  1089. LARGE_INTEGER Result;
  1090. LARGE_INTEGER TicksPerSecond;
  1091. PAGED_CODE();
  1092. // get ticks per second from perf counter
  1093. KeQueryPerformanceCounter(&TicksPerSecond);
  1094. // scale the bytes xfered
  1095. Result = RtlExtendedIntegerMultiply(DeviceExtension->BytesXfered,
  1096. TicksPerSecond.LowPart);
  1097. // Don't divide by 0
  1098. DeviceExtension->ElapsedTime.LowPart
  1099. = (DeviceExtension->ElapsedTime.LowPart == 0L) ? 1 :
  1100. DeviceExtension->ElapsedTime.LowPart;
  1101. // lets get stats here
  1102. Result
  1103. = RtlExtendedLargeIntegerDivide(Result,
  1104. DeviceExtension->ElapsedTime.LowPart,
  1105. &Remainder);
  1106. return Result.LowPart;
  1107. } // BytesPerSecond
  1108. /************************************************************************/
  1109. /* CallUSBD */
  1110. /************************************************************************/
  1111. /* */
  1112. /* Routine Description: */
  1113. /* */
  1114. /* Call USB bus driver. */
  1115. /* */
  1116. /* Arguments: */
  1117. /* */
  1118. /* DeviceObject - pointer to a device object */
  1119. /* Urb - pointer to URB */
  1120. /* */
  1121. /* Return Value: */
  1122. /* */
  1123. /* NTSTATUS */
  1124. /* */
  1125. /************************************************************************/
  1126. NTSTATUS
  1127. CallUSBD(IN PDEVICE_OBJECT DeviceObject, IN PURB Urb)
  1128. {
  1129. NTSTATUS NtStatus = STATUS_SUCCESS;
  1130. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  1131. PIRP Irp;
  1132. KEVENT Event;
  1133. PIO_STACK_LOCATION NextStack;
  1134. PAGED_CODE();
  1135. DEBUG_LOG_PATH("enter CallUSBD");
  1136. // issue a synchronous request
  1137. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  1138. Irp = IoAllocateIrp(DeviceExtension->StackDeviceObject->StackSize, FALSE);
  1139. if (Irp == NULL)
  1140. {
  1141. return STATUS_INSUFFICIENT_RESOURCES;
  1142. }
  1143. // Set the Irp parameters
  1144. NextStack = IoGetNextIrpStackLocation(Irp);
  1145. NextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1146. NextStack->Parameters.DeviceIoControl.IoControlCode =
  1147. IOCTL_INTERNAL_USB_SUBMIT_URB;
  1148. NextStack->Parameters.Others.Argument1 = Urb;
  1149. // Set the completion routine, which will signal the event
  1150. IoSetCompletionRoutine(Irp,
  1151. CallUSBD_SyncCompletionRoutine,
  1152. &Event,
  1153. TRUE, // InvokeOnSuccess
  1154. TRUE, // InvokeOnError
  1155. TRUE); // InvokeOnCancel
  1156. DEBUG_LOG_PATH("Calling USB driver stack");
  1157. NtStatus = IoCallDriver(DeviceExtension->StackDeviceObject, Irp);
  1158. DEBUG_LOG_PATH("Returned from calling USB driver stack");
  1159. // block on pending request
  1160. if(NtStatus == STATUS_PENDING)
  1161. {
  1162. LARGE_INTEGER timeout;
  1163. // Specify a timeout of 30 seconds to wait for this call to complete.
  1164. //
  1165. timeout.QuadPart = -10000 * 30000;
  1166. NtStatus = KeWaitForSingleObject(&Event,
  1167. Executive,
  1168. KernelMode,
  1169. FALSE,
  1170. &timeout);
  1171. if(NtStatus == STATUS_TIMEOUT)
  1172. {
  1173. NtStatus = STATUS_IO_TIMEOUT;
  1174. // Cancel the Irp we just sent.
  1175. //
  1176. IoCancelIrp(Irp);
  1177. // And wait until the cancel completes
  1178. //
  1179. KeWaitForSingleObject(&Event,
  1180. Executive,
  1181. KernelMode,
  1182. FALSE,
  1183. NULL);
  1184. }
  1185. else
  1186. {
  1187. NtStatus = Irp->IoStatus.Status;
  1188. }
  1189. }
  1190. IoFreeIrp(Irp);
  1191. DEBUG_LOG_PATH("exit CallUSBD");
  1192. return NtStatus;
  1193. } // CallUSBD
  1194. /************************************************************************/
  1195. /* CallUSBD_SyncCompletionRoutine */
  1196. /************************************************************************/
  1197. /* */
  1198. /* Routine Description: */
  1199. /* */
  1200. /* Completion routine for USB sync request. */
  1201. /* */
  1202. /* Return Value: */
  1203. /* */
  1204. /* NTSTATUS */
  1205. /* */
  1206. /************************************************************************/
  1207. NTSTATUS
  1208. CallUSBD_SyncCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
  1209. IN PIRP Irp,
  1210. IN PVOID Context)
  1211. {
  1212. PKEVENT kevent;
  1213. kevent = (PKEVENT) Context;
  1214. KeSetEvent(kevent, IO_NO_INCREMENT, FALSE);
  1215. return STATUS_MORE_PROCESSING_REQUIRED;
  1216. } // CallUSBD_SyncCompletionRoutine
  1217. /************************************************************************/
  1218. /* GetDeviceDescriptor */
  1219. /************************************************************************/
  1220. /* */
  1221. /* Routine Description: */
  1222. /* */
  1223. /* Get device descriptor for USB device. */
  1224. /* */
  1225. /* Arguments: */
  1226. /* */
  1227. /* DeviceObject - pointer to a device object */
  1228. /* */
  1229. /* Return Value: */
  1230. /* */
  1231. /* NTSTATUS */
  1232. /* */
  1233. /************************************************************************/
  1234. NTSTATUS
  1235. GetDeviceDescriptor(IN PDEVICE_OBJECT DeviceObject)
  1236. {
  1237. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  1238. NTSTATUS NtStatus;
  1239. PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
  1240. PURB Urb;
  1241. ULONG Size;
  1242. ULONG UrbCDRSize;
  1243. KIRQL OldIrql;
  1244. DEBUG_LOG_PATH("enter GetDeviceDescriptor");
  1245. UrbCDRSize = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
  1246. Urb = DEBUG_MEMALLOC(NonPagedPool, UrbCDRSize);
  1247. if (Urb) {
  1248. Size = sizeof(USB_DEVICE_DESCRIPTOR);
  1249. DeviceDescriptor = DEBUG_MEMALLOC(NonPagedPool, Size);
  1250. if (DeviceDescriptor) {
  1251. UsbBuildGetDescriptorRequest(Urb, (USHORT)UrbCDRSize,
  1252. USB_DEVICE_DESCRIPTOR_TYPE, 0, 0,
  1253. DeviceDescriptor, NULL, Size, NULL);
  1254. NtStatus = CallUSBD(DeviceObject, Urb);
  1255. if (NT_SUCCESS(NtStatus)) {
  1256. DEBUG_TRACE3(("Device Descriptor (%08X)\n", DeviceDescriptor));
  1257. DEBUG_TRACE3(("Length (%08X)\n",
  1258. Urb->UrbControlDescriptorRequest
  1259. .TransferBufferLength));
  1260. DEBUG_TRACE3(("Device Descriptor:\n"));
  1261. DEBUG_TRACE3(("-------------------------\n"));
  1262. DEBUG_TRACE3(("bLength (%08X)\n",
  1263. DeviceDescriptor->bLength));
  1264. DEBUG_TRACE3(("bDescriptorType (%08X)\n",
  1265. DeviceDescriptor->bDescriptorType));
  1266. DEBUG_TRACE3(("bcdUSB (%08X)\n",
  1267. DeviceDescriptor->bcdUSB));
  1268. DEBUG_TRACE3(("bDeviceClass (%08X)\n",
  1269. DeviceDescriptor->bDeviceClass));
  1270. DEBUG_TRACE3(("bDeviceSubClass (%08X)\n",
  1271. DeviceDescriptor->bDeviceSubClass));
  1272. DEBUG_TRACE3(("bDeviceProtocol (%08X)\n",
  1273. DeviceDescriptor->bDeviceProtocol));
  1274. DEBUG_TRACE3(("bMaxPacketSize0 (%08X)\n",
  1275. DeviceDescriptor->bMaxPacketSize0));
  1276. DEBUG_TRACE3(("idVendor (%08X)\n",
  1277. DeviceDescriptor->idVendor));
  1278. DEBUG_TRACE3(("idProduct (%08X)\n",
  1279. DeviceDescriptor->idProduct));
  1280. DEBUG_TRACE3(("bcdDevice (%08X)\n",
  1281. DeviceDescriptor->bcdDevice));
  1282. DEBUG_TRACE3(("iManufacturer (%08X)\n",
  1283. DeviceDescriptor->iManufacturer));
  1284. DEBUG_TRACE3(("iProduct (%08X)\n",
  1285. DeviceDescriptor->iProduct));
  1286. DEBUG_TRACE3(("iSerialNumber (%08X)\n",
  1287. DeviceDescriptor->iSerialNumber));
  1288. DEBUG_TRACE3(("bNumConfigurations (%08X)\n",
  1289. DeviceDescriptor->bNumConfigurations));
  1290. }
  1291. } else {
  1292. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1293. }
  1294. // save the device descriptor
  1295. if (NT_SUCCESS(NtStatus)) {
  1296. PVOID pOldDesc = NULL;
  1297. ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
  1298. if (DeviceExtension->DeviceDescriptor) {
  1299. pOldDesc = DeviceExtension->DeviceDescriptor;
  1300. }
  1301. DeviceExtension->DeviceDescriptor = DeviceDescriptor;
  1302. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  1303. if (pOldDesc != NULL) {
  1304. DEBUG_MEMFREE(pOldDesc);
  1305. }
  1306. } else if (DeviceDescriptor) {
  1307. DEBUG_MEMFREE(DeviceDescriptor);
  1308. }
  1309. DEBUG_MEMFREE(Urb);
  1310. } else {
  1311. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1312. }
  1313. DEBUG_LOG_PATH("exit GetDeviceDescriptor");
  1314. return NtStatus;
  1315. } // GetDeviceDescriptor
  1316. /************************************************************************/
  1317. /* ConfigureDevice */
  1318. /************************************************************************/
  1319. /* */
  1320. /* Routine Description: */
  1321. /* */
  1322. /* Initializes USB device and selects configuration. */
  1323. /* */
  1324. /* Arguments: */
  1325. /* */
  1326. /* DeviceObject - pointer to a device object */
  1327. /* */
  1328. /* Return Value: */
  1329. /* */
  1330. /* NTSTATUS */
  1331. /* */
  1332. /************************************************************************/
  1333. NTSTATUS
  1334. ConfigureDevice(IN PDEVICE_OBJECT DeviceObject)
  1335. {
  1336. PDEVICE_EXTENSION DeviceExtension
  1337. = DeviceObject->DeviceExtension;
  1338. NTSTATUS NtStatus;
  1339. PURB Urb;
  1340. ULONG Size;
  1341. ULONG UrbCDRSize;
  1342. PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
  1343. ULONG NumConfigs;
  1344. UCHAR Config;
  1345. PAGED_CODE();
  1346. DEBUG_LOG_PATH("enter ConfigureDevice");
  1347. UrbCDRSize = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
  1348. // first configure the device
  1349. Urb = DEBUG_MEMALLOC(NonPagedPool, UrbCDRSize);
  1350. if (Urb) {
  1351. // there may be problems with the 82930 chip, so make this buffer bigger
  1352. // to prevent choking
  1353. Size = sizeof(USB_CONFIGURATION_DESCRIPTOR) + 256;
  1354. // get the number of configurations
  1355. NumConfigs = DeviceExtension->DeviceDescriptor->bNumConfigurations;
  1356. // run through all of the configurations looking for a CDC device
  1357. for (Config = 0; Config < NumConfigs; Config++) {
  1358. // we will probably only do this once, maybe twice
  1359. while (TRUE) {
  1360. ConfigurationDescriptor = DEBUG_MEMALLOC(NonPagedPool, Size);
  1361. if (ConfigurationDescriptor) {
  1362. UsbBuildGetDescriptorRequest(Urb, (USHORT)UrbCDRSize,
  1363. USB_CONFIGURATION_DESCRIPTOR_TYPE,
  1364. Config, 0, ConfigurationDescriptor,
  1365. NULL, Size, NULL);
  1366. NtStatus = CallUSBD(DeviceObject, Urb);
  1367. DEBUG_TRACE3(("Configuration Descriptor (%08X) "
  1368. "Length (%08X)\n", ConfigurationDescriptor,
  1369. Urb->UrbControlDescriptorRequest
  1370. .TransferBufferLength));
  1371. } else {
  1372. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1373. break;
  1374. }
  1375. // see if we got enough data, we may get an error in URB because of
  1376. // buffer overrun
  1377. if (Urb->UrbControlDescriptorRequest.TransferBufferLength>0 &&
  1378. ConfigurationDescriptor->wTotalLength > Size) {
  1379. // size of data exceeds current buffer size, so allocate correct
  1380. // size
  1381. Size = ConfigurationDescriptor->wTotalLength;
  1382. DEBUG_MEMFREE(ConfigurationDescriptor);
  1383. ConfigurationDescriptor = NULL;
  1384. } else {
  1385. break;
  1386. }
  1387. }
  1388. if (NT_SUCCESS(NtStatus)) {
  1389. NtStatus = SelectInterface(DeviceObject, ConfigurationDescriptor);
  1390. DEBUG_MEMFREE(ConfigurationDescriptor);
  1391. ConfigurationDescriptor = NULL;
  1392. }
  1393. else
  1394. {
  1395. DEBUG_MEMFREE(ConfigurationDescriptor);
  1396. ConfigurationDescriptor = NULL;
  1397. }
  1398. // found a config we like
  1399. if (NT_SUCCESS(NtStatus))
  1400. break;
  1401. }
  1402. DEBUG_MEMFREE(Urb);
  1403. } else {
  1404. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1405. }
  1406. DEBUG_LOG_PATH("exit ConfigureDevice");
  1407. return NtStatus;
  1408. } // ConfigureDevice
  1409. /************************************************************************/
  1410. /* SelectInterface */
  1411. /************************************************************************/
  1412. /* */
  1413. /* Routine Description: */
  1414. /* */
  1415. /* Select interface for USB device. */
  1416. /* */
  1417. /* Arguments: */
  1418. /* */
  1419. /* DeviceObject - pointer to a device object */
  1420. /* ConfigurationDescriptor - pointer to config descriptor */
  1421. /* */
  1422. /* Return Value: */
  1423. /* */
  1424. /* NTSTATUS */
  1425. /* */
  1426. /************************************************************************/
  1427. NTSTATUS
  1428. SelectInterface(IN PDEVICE_OBJECT DeviceObject,
  1429. IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
  1430. {
  1431. PDEVICE_EXTENSION DeviceExtension
  1432. = DeviceObject->DeviceExtension;
  1433. NTSTATUS NtStatus;
  1434. PURB Urb;
  1435. USHORT Size;
  1436. ULONG Index;
  1437. PUSBD_INTERFACE_INFORMATION Interfaces[2];
  1438. PUSBD_INTERFACE_INFORMATION Interface;
  1439. PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor[2];
  1440. UCHAR AlternateSetting, InterfaceNumber;
  1441. ULONG Pipe;
  1442. KIRQL OldIrql;
  1443. PUCHAR Temp;
  1444. BOOLEAN FoundCommDevice = FALSE;
  1445. DEBUG_LOG_PATH("enter SelectInterface");
  1446. Urb = USBD_CreateConfigurationRequest(ConfigurationDescriptor, &Size);
  1447. if (Urb) {
  1448. Temp = (PUCHAR) &Urb->UrbSelectConfiguration.Interface;
  1449. for (InterfaceNumber = 0;
  1450. InterfaceNumber < ConfigurationDescriptor->bNumInterfaces;
  1451. InterfaceNumber++) {
  1452. AlternateSetting = 0;
  1453. InterfaceDescriptor[InterfaceNumber] =
  1454. USBD_ParseConfigurationDescriptor(ConfigurationDescriptor,
  1455. InterfaceNumber,
  1456. AlternateSetting);
  1457. Interfaces[InterfaceNumber] = (PUSBD_INTERFACE_INFORMATION) Temp;
  1458. Interfaces[InterfaceNumber]->Length
  1459. = GET_USBD_INTERFACE_SIZE(InterfaceDescriptor[InterfaceNumber]
  1460. ->bNumEndpoints);
  1461. Interfaces[InterfaceNumber]->InterfaceNumber
  1462. = InterfaceDescriptor[InterfaceNumber]->bInterfaceNumber;
  1463. Interfaces[InterfaceNumber]->AlternateSetting
  1464. = InterfaceDescriptor[InterfaceNumber]->bAlternateSetting;
  1465. for (Index = 0; Index < Interfaces[InterfaceNumber]->NumberOfPipes;
  1466. Index++)
  1467. {
  1468. PUSBD_PIPE_INFORMATION PipeInformation;
  1469. PipeInformation = &Interfaces[InterfaceNumber]->Pipes[Index];
  1470. if (USB_ENDPOINT_DIRECTION_IN(PipeInformation->EndpointAddress))
  1471. {
  1472. // check for data in pipe
  1473. if (PipeInformation->PipeType == USB_ENDPOINT_TYPE_BULK)
  1474. {
  1475. // set bulk pipe in max transfer size
  1476. PipeInformation->MaximumTransferSize
  1477. = USB_RX_BUFF_SIZE;
  1478. }
  1479. }
  1480. else if (USB_ENDPOINT_DIRECTION_OUT(PipeInformation->EndpointAddress))
  1481. {
  1482. // check for data out pipe
  1483. if (PipeInformation->PipeType == USB_ENDPOINT_TYPE_BULK)
  1484. {
  1485. // set bulk pipe out max transfer size
  1486. PipeInformation->MaximumTransferSize
  1487. = MAXIMUM_TRANSFER_SIZE;
  1488. }
  1489. }
  1490. }
  1491. Temp += Interfaces[InterfaceNumber]->Length;
  1492. }
  1493. UsbBuildSelectConfigurationRequest(Urb, Size, ConfigurationDescriptor);
  1494. NtStatus = CallUSBD(DeviceObject, Urb);
  1495. if (NtStatus != STATUS_SUCCESS) {
  1496. ExFreePool(Urb);
  1497. goto ExitSelectInterface;
  1498. }
  1499. DEBUG_TRACE3(("Select Config Status (%08X)\n", NtStatus));
  1500. DeviceExtension->ConfigurationHandle
  1501. = Urb->UrbSelectConfiguration.ConfigurationHandle;
  1502. for (InterfaceNumber = 0;
  1503. InterfaceNumber < ConfigurationDescriptor->bNumInterfaces;
  1504. InterfaceNumber++) {
  1505. Interface = Interfaces[InterfaceNumber];
  1506. DEBUG_TRACE3(("---------\n"));
  1507. DEBUG_TRACE3(("NumberOfPipes (%08X)\n", Interface->NumberOfPipes));
  1508. DEBUG_TRACE3(("Length (%08X)\n", Interface->Length));
  1509. DEBUG_TRACE3(("Alt Setting (%08X)\n",
  1510. Interface->AlternateSetting));
  1511. DEBUG_TRACE3(("Interface Number (%08X)\n",
  1512. Interface->InterfaceNumber));
  1513. DEBUG_TRACE3(("Class (%08X) SubClass (%08X) Protocol (%08X)\n",
  1514. Interface->Class,
  1515. Interface->SubClass,
  1516. Interface->Protocol));
  1517. if (Interface->Class == USB_COMM_COMMUNICATION_CLASS_CODE) {
  1518. FoundCommDevice = TRUE;
  1519. DeviceExtension->CommInterface = Interface->InterfaceNumber;
  1520. }
  1521. for (Pipe = 0; Pipe < Interface->NumberOfPipes; Pipe++) {
  1522. PUSBD_PIPE_INFORMATION PipeInformation;
  1523. PipeInformation = &Interface->Pipes[Pipe];
  1524. DEBUG_TRACE3(("---------\n"));
  1525. DEBUG_TRACE3(("PipeType (%08X)\n",
  1526. PipeInformation->PipeType));
  1527. DEBUG_TRACE3(("EndpointAddress (%08X)\n",
  1528. PipeInformation->EndpointAddress));
  1529. DEBUG_TRACE3(("MaxPacketSize (%08X)\n",
  1530. PipeInformation->MaximumPacketSize));
  1531. DEBUG_TRACE3(("Interval (%08X)\n",
  1532. PipeInformation->Interval));
  1533. DEBUG_TRACE3(("Handle (%08X)\n",
  1534. PipeInformation->PipeHandle));
  1535. DEBUG_TRACE3(("MaximumTransferSize (%08X)\n",
  1536. PipeInformation->MaximumTransferSize));
  1537. // now lets save pipe handles in device extension
  1538. if (USB_ENDPOINT_DIRECTION_IN(PipeInformation->EndpointAddress)) {
  1539. // check for data in pipe
  1540. if (PipeInformation->PipeType == USB_ENDPOINT_TYPE_BULK) {
  1541. PVOID pOldNotBuff = NULL;
  1542. PVOID pOldReadBuff = NULL;
  1543. PVOID pOldUSBReadBuff = NULL;
  1544. PVOID pNewNotBuff = NULL;
  1545. PVOID pNewReadBuff = NULL;
  1546. PVOID pNewUSBReadBuff = NULL;
  1547. DeviceExtension->RxMaxPacketSize = RxBuffSize;
  1548. if (DeviceExtension->RxMaxPacketSize != 0) {
  1549. pNewReadBuff = DEBUG_MEMALLOC(NonPagedPool,
  1550. DeviceExtension->RxMaxPacketSize);
  1551. }
  1552. pNewNotBuff = DEBUG_MEMALLOC(NonPagedPool,
  1553. NOTIFICATION_BUFF_SIZE);
  1554. pNewUSBReadBuff = DEBUG_MEMALLOC(NonPagedPool,
  1555. USB_RX_BUFF_SIZE);
  1556. ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
  1557. DeviceExtension->DataInPipe = PipeInformation->PipeHandle;
  1558. if (DeviceExtension->NotificationBuff)
  1559. pOldNotBuff = DeviceExtension->NotificationBuff;
  1560. if (DeviceExtension->ReadBuff)
  1561. pOldReadBuff = DeviceExtension->ReadBuff;
  1562. if (DeviceExtension->USBReadBuff)
  1563. pOldUSBReadBuff = DeviceExtension->USBReadBuff;
  1564. DeviceExtension->RxQueueSize
  1565. = DeviceExtension->RxMaxPacketSize;
  1566. DeviceExtension->CharsInReadBuff = 0;
  1567. DeviceExtension->CurrentReadBuffPtr = 0;
  1568. DeviceExtension->ReadBuff = pNewReadBuff;
  1569. DeviceExtension->USBReadBuff = pNewUSBReadBuff;
  1570. DeviceExtension->NotificationBuff = pNewNotBuff;
  1571. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  1572. if (pOldNotBuff != NULL) {
  1573. DEBUG_MEMFREE(pOldNotBuff);
  1574. }
  1575. if (pOldReadBuff != NULL) {
  1576. DEBUG_MEMFREE(pOldReadBuff);
  1577. }
  1578. if (pOldUSBReadBuff != NULL) {
  1579. DEBUG_MEMFREE(pOldUSBReadBuff);
  1580. }
  1581. }
  1582. // check for notification pipe
  1583. else if (PipeInformation->PipeType
  1584. == USB_ENDPOINT_TYPE_INTERRUPT)
  1585. DeviceExtension->NotificationPipe
  1586. = PipeInformation->PipeHandle;
  1587. } else {
  1588. // check for data out pipe
  1589. if (PipeInformation->PipeType == USB_ENDPOINT_TYPE_BULK)
  1590. DeviceExtension->DataOutPipe = PipeInformation->PipeHandle;
  1591. }
  1592. }
  1593. DEBUG_TRACE3(("Data Out (%08X) Data In (%08X) Notification (%08X)\n",
  1594. DeviceExtension->DataOutPipe,
  1595. DeviceExtension->DataInPipe,
  1596. DeviceExtension->NotificationPipe));
  1597. }
  1598. ExFreePool(Urb);
  1599. } else {
  1600. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1601. }
  1602. if (!FoundCommDevice)
  1603. NtStatus = STATUS_NO_SUCH_DEVICE;
  1604. ExitSelectInterface:;
  1605. DEBUG_LOG_PATH("exit SelectInterface");
  1606. return NtStatus;
  1607. } // SelectInterface
  1608. /************************************************************************/
  1609. /* BuildRequest */
  1610. /************************************************************************/
  1611. /* */
  1612. /* Routine Description: */
  1613. /* */
  1614. /* Build a Urb for a USB request */
  1615. /* */
  1616. /* Arguments: */
  1617. /* */
  1618. /* DeviceObject - pointer to a device object */
  1619. /* Irp - pointer to Irp */
  1620. /* PipeHandle - USB pipe handle */
  1621. /* Read - transfer direction */
  1622. /* */
  1623. /* Return Value: */
  1624. /* */
  1625. /* Pointer to URB */
  1626. /* */
  1627. /************************************************************************/
  1628. PURB
  1629. BuildRequest(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp,
  1630. IN USBD_PIPE_HANDLE PipeHandle, IN BOOLEAN Read)
  1631. {
  1632. ULONG Size;
  1633. ULONG Length;
  1634. PURB Urb;
  1635. PAGED_CODE();
  1636. DEBUG_LOG_PATH("enter BuildRequest");
  1637. // length of buffer
  1638. Length = MmGetMdlByteCount(Irp->MdlAddress);
  1639. // allocate and zero Urb
  1640. Size = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
  1641. Urb = DEBUG_MEMALLOC(NonPagedPool, Size);
  1642. if (Urb) {
  1643. RtlZeroMemory(Urb, Size);
  1644. Urb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT) Size;
  1645. Urb->UrbBulkOrInterruptTransfer.Hdr.Function =
  1646. URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
  1647. Urb->UrbBulkOrInterruptTransfer.PipeHandle = PipeHandle;
  1648. Urb->UrbBulkOrInterruptTransfer.TransferFlags =
  1649. Read ? USBD_TRANSFER_DIRECTION_IN : 0;
  1650. // use an MDL
  1651. Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = Irp->MdlAddress;
  1652. Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = Length;
  1653. // short packet is not treated as an error.
  1654. Urb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
  1655. // no linkage for now
  1656. Urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
  1657. }
  1658. DEBUG_LOG_PATH("exit BuildRequest");
  1659. return Urb;
  1660. } // BuildRequest
  1661. /************************************************************************/
  1662. /* BuildReadRequest */
  1663. /************************************************************************/
  1664. /* */
  1665. /* Routine Description: */
  1666. /* */
  1667. /* Build a Urb for a USB read request */
  1668. /* */
  1669. /* Arguments: */
  1670. /* */
  1671. /* Urb - pointer to URB */
  1672. /* Buffer - pointer to data buffer */
  1673. /* Length - length of data buffer */
  1674. /* PipeHandle - USB pipe handle */
  1675. /* Read - transfer direction */
  1676. /* */
  1677. /* Return Value: */
  1678. /* */
  1679. /* VOID */
  1680. /* */
  1681. /************************************************************************/
  1682. VOID
  1683. BuildReadRequest(PURB Urb, PUCHAR Buffer, ULONG Length,
  1684. IN USBD_PIPE_HANDLE PipeHandle, IN BOOLEAN Read)
  1685. {
  1686. ULONG Size;
  1687. // PAGED_CODE();
  1688. DEBUG_LOG_PATH("enter BuildReadRequest");
  1689. Size = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
  1690. // zero Urb
  1691. RtlZeroMemory(Urb, Size);
  1692. Urb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT) Size;
  1693. Urb->UrbBulkOrInterruptTransfer.Hdr.Function =
  1694. URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
  1695. Urb->UrbBulkOrInterruptTransfer.PipeHandle = PipeHandle;
  1696. Urb->UrbBulkOrInterruptTransfer.TransferFlags =
  1697. Read ? USBD_TRANSFER_DIRECTION_IN : 0;
  1698. // we are using a tranfsfer buffer instead of an MDL
  1699. Urb->UrbBulkOrInterruptTransfer.TransferBuffer = Buffer;
  1700. Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = Length;
  1701. Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
  1702. // short packet is not treated as an error.
  1703. Urb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
  1704. // no linkage for now
  1705. Urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
  1706. DEBUG_LOG_PATH("exit BuildReadRequest");
  1707. } // BuildReadRequest
  1708. /************************************************************************/
  1709. /* ClassVendorCommand */
  1710. /************************************************************************/
  1711. /* */
  1712. /* Routine Description: */
  1713. /* */
  1714. /* Issue class or vendor specific command */
  1715. /* */
  1716. /* Arguments: */
  1717. /* */
  1718. /* DeviceObject - pointer to a device object */
  1719. /* Request - request field of class/vendor specific command */
  1720. /* Value - value field of class/vendor specific command */
  1721. /* Index - index field of class/vendor specific command */
  1722. /* Buffer - pointer to data buffer */
  1723. /* BufferLen - data buffer length */
  1724. /* Read - data direction flag */
  1725. /* Class - True if Class Command, else vendor command */
  1726. /* */
  1727. /* Return Value: */
  1728. /* */
  1729. /* NTSTATUS */
  1730. /* */
  1731. /************************************************************************/
  1732. NTSTATUS
  1733. ClassVendorCommand(IN PDEVICE_OBJECT DeviceObject, IN UCHAR Request,
  1734. IN USHORT Value, IN USHORT Index, IN PVOID Buffer,
  1735. IN OUT PULONG BufferLen, IN BOOLEAN Read, IN ULONG ComType)
  1736. {
  1737. NTSTATUS NtStatus;
  1738. PURB Urb;
  1739. ULONG Size;
  1740. ULONG Length;
  1741. PAGED_CODE();
  1742. DEBUG_LOG_PATH("enter VendorCommand");
  1743. // length of buffer passed in
  1744. Length = BufferLen ? *BufferLen : 0;
  1745. Size = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
  1746. // allocate memory for the Urb
  1747. Urb = DEBUG_MEMALLOC(NonPagedPool, Size);
  1748. if (Urb) {
  1749. UsbBuildVendorRequest(Urb, ComType == USBSER_CLASS_COMMAND
  1750. ? URB_FUNCTION_CLASS_INTERFACE
  1751. : URB_FUNCTION_VENDOR_DEVICE, (USHORT) Size,
  1752. Read ? USBD_TRANSFER_DIRECTION_IN
  1753. : USBD_TRANSFER_DIRECTION_OUT, 0, Request, Value,
  1754. Index, Buffer, NULL, Length, NULL);
  1755. NtStatus = CallUSBD(DeviceObject, Urb);
  1756. // get length of buffer
  1757. if (BufferLen)
  1758. *BufferLen = Urb->UrbControlVendorClassRequest.TransferBufferLength;
  1759. DEBUG_MEMFREE(Urb);
  1760. } else {
  1761. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1762. }
  1763. DEBUG_LOG_PATH("exit VendorCommand");
  1764. return NtStatus;
  1765. } // ClassVendorCommand
  1766. /************************************************************************/
  1767. /* CancelPendingWaitMasks */
  1768. /************************************************************************/
  1769. /* */
  1770. /* Routine Description: */
  1771. /* */
  1772. /* Cancels any wait masks in progress. */
  1773. /* */
  1774. /* Arguments: */
  1775. /* */
  1776. /* DeviceExtension - pointer to a device extension */
  1777. /* */
  1778. /* Return Value: */
  1779. /* */
  1780. /* VOID */
  1781. /* */
  1782. /************************************************************************/
  1783. VOID
  1784. CancelPendingWaitMasks(IN PDEVICE_EXTENSION DeviceExtension)
  1785. {
  1786. KIRQL OldIrql;
  1787. PIRP CurrentMaskIrp;
  1788. DEBUG_LOG_PATH("enter CancelPendingWaitMasks");
  1789. UsbSerSerialDump(USBSERTRACEOTH, (">CancelPendingWaitMasks\n"));
  1790. ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
  1791. CurrentMaskIrp = DeviceExtension->CurrentMaskIrp;
  1792. // mark current pending wait mask as cancelled
  1793. if(CurrentMaskIrp)
  1794. {
  1795. DeviceExtension->CurrentMaskIrp = NULL;
  1796. CurrentMaskIrp->IoStatus.Status = STATUS_CANCELLED;
  1797. CurrentMaskIrp->IoStatus.Information = 0;
  1798. IoSetCancelRoutine(CurrentMaskIrp, NULL);
  1799. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  1800. IoCompleteRequest(CurrentMaskIrp, IO_NO_INCREMENT);
  1801. DEBUG_TRACE1(("CancelPendingWaitMask\n"));
  1802. } else {
  1803. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  1804. }
  1805. DEBUG_LOG_PATH("exit CancelPendingWaitMasks");
  1806. UsbSerSerialDump(USBSERTRACEOTH, ("<CancelPendingWaitMasks\n"));
  1807. } // CancelPendingWaitMasks
  1808. /************************************************************************/
  1809. /* StartRead */
  1810. /************************************************************************/
  1811. /* */
  1812. /* Routine Description: */
  1813. /* */
  1814. /* Kick off a read. */
  1815. /* */
  1816. /* Arguments: */
  1817. /* */
  1818. /* DeviceExtension - pointer to a device extension */
  1819. /* */
  1820. /* Return Value: */
  1821. /* */
  1822. /* VOID */
  1823. /* */
  1824. /************************************************************************/
  1825. VOID
  1826. StartRead(IN PDEVICE_EXTENSION DeviceExtension)
  1827. {
  1828. PIRP ReadIrp;
  1829. PURB ReadUrb;
  1830. CCHAR StackSize;
  1831. ULONG Size;
  1832. PAGED_CODE();
  1833. DEBUG_LOG_PATH("enter StartRead");
  1834. UsbSerSerialDump(USBSERTRACERD, (">StartRead\n"));
  1835. // get stack size for Irp and allocate one that we will use to keep
  1836. // read requests going
  1837. StackSize = (CCHAR)(DeviceExtension->StackDeviceObject->StackSize + 1);
  1838. ReadIrp = IoAllocateIrp(StackSize, FALSE);
  1839. if (ReadIrp) {
  1840. // get size of Urb and allocate
  1841. Size = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
  1842. ReadUrb = DEBUG_MEMALLOC(NonPagedPool, Size);
  1843. if (ReadUrb) {
  1844. KeInitializeEvent(&DeviceExtension->ReadEvent, NotificationEvent,
  1845. FALSE);
  1846. // save these to be freed when not needed
  1847. UsbSerFetchPVoidLocked(&DeviceExtension->ReadIrp, ReadIrp,
  1848. &DeviceExtension->ControlLock);
  1849. UsbSerFetchPVoidLocked(&DeviceExtension->ReadUrb, ReadUrb,
  1850. &DeviceExtension->ControlLock);
  1851. RestartRead(DeviceExtension);
  1852. }
  1853. }
  1854. UsbSerSerialDump(USBSERTRACERD, ("<StartRead\n"));
  1855. DEBUG_LOG_PATH("exit StartRead");
  1856. } // StartRead
  1857. /************************************************************************/
  1858. /* RestartRead */
  1859. /************************************************************************/
  1860. /* */
  1861. /* Routine Description: */
  1862. /* */
  1863. /* Restart read request. */
  1864. /* */
  1865. /* Arguments: */
  1866. /* */
  1867. /* DeviceExtension - pointer to a device extension */
  1868. /* */
  1869. /* Return Value: */
  1870. /* */
  1871. /* VOID */
  1872. /* */
  1873. /************************************************************************/
  1874. VOID
  1875. RestartRead(IN PDEVICE_EXTENSION DeviceExtension)
  1876. {
  1877. PIRP ReadIrp;
  1878. PURB ReadUrb;
  1879. PIO_STACK_LOCATION NextStack;
  1880. BOOLEAN StartAnotherRead;
  1881. KIRQL OldIrql;
  1882. NTSTATUS NtStatus;
  1883. DEBUG_LOG_PATH("enter RestartRead");
  1884. UsbSerSerialDump(USBSERTRACERD, (">RestartRead\n"));
  1885. do
  1886. {
  1887. StartAnotherRead = FALSE;
  1888. ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
  1889. if(!DeviceExtension->ReadInProgress && DeviceExtension->CharsInReadBuff <= LOW_WATER_MARK
  1890. && DeviceExtension->AcceptingRequests)
  1891. {
  1892. StartAnotherRead = TRUE;
  1893. DeviceExtension->ReadInProgress = TRUE;
  1894. DeviceExtension->ReadInterlock = START_READ;
  1895. }
  1896. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  1897. if(StartAnotherRead)
  1898. {
  1899. ReadIrp = DeviceExtension->ReadIrp;
  1900. ReadUrb = DeviceExtension->ReadUrb;
  1901. BuildReadRequest(ReadUrb, DeviceExtension->USBReadBuff,
  1902. USB_RX_BUFF_SIZE,
  1903. DeviceExtension->DataInPipe, TRUE);
  1904. // set Irp up for a submit Urb IOCTL
  1905. NextStack = IoGetNextIrpStackLocation(ReadIrp);
  1906. NextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1907. NextStack->Parameters.Others.Argument1 = ReadUrb;
  1908. NextStack->Parameters.DeviceIoControl.IoControlCode
  1909. = IOCTL_INTERNAL_USB_SUBMIT_URB;
  1910. // completion routine will take care of updating buffers and counters
  1911. IoSetCompletionRoutine(ReadIrp,ReadCompletion, DeviceExtension, TRUE,
  1912. TRUE, TRUE);
  1913. DEBUG_TRACE1(("StartRead\n"));
  1914. InterlockedIncrement(&DeviceExtension->PendingDataInCount);
  1915. UsbSerSerialDump(USBSERTRACERD, ("DataInCounty %08X @ %08X\n",
  1916. DeviceExtension->PendingDataInCount,
  1917. &DeviceExtension->PendingDataInCount));
  1918. NtStatus = IoCallDriver(DeviceExtension->StackDeviceObject, ReadIrp);
  1919. DEBUG_TRACE1(("Read Status (%08X)\n", NtStatus));
  1920. if(!NT_SUCCESS(NtStatus))
  1921. {
  1922. if(InterlockedDecrement(&DeviceExtension->PendingDataInCount) == 0)
  1923. {
  1924. KeSetEvent(&DeviceExtension->PendingDataInEvent, IO_NO_INCREMENT,
  1925. FALSE);
  1926. UsbSerSerialDump(USBSERTRACERD, ("DataInCountz %08X @ %08X\n",
  1927. DeviceExtension->PendingDataInCount,
  1928. &DeviceExtension->PendingDataInCount));
  1929. }
  1930. }
  1931. ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
  1932. if(DeviceExtension->ReadInterlock == IMMEDIATE_READ)
  1933. {
  1934. StartAnotherRead = TRUE;
  1935. }
  1936. else
  1937. {
  1938. StartAnotherRead = FALSE;
  1939. }
  1940. DeviceExtension->ReadInterlock = END_READ;
  1941. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  1942. }
  1943. }while(StartAnotherRead)
  1944. DEBUG_LOG_PATH("exit RestartRead");
  1945. UsbSerSerialDump(USBSERTRACERD, ("<RestartRead\n"));
  1946. } // RestartRead
  1947. /************************************************************************/
  1948. /* StartNotifyRead */
  1949. /************************************************************************/
  1950. /* */
  1951. /* Routine Description: */
  1952. /* */
  1953. /* Kick off a notify read. */
  1954. /* */
  1955. /* Arguments: */
  1956. /* */
  1957. /* DeviceExtension - pointer to a device extension */
  1958. /* */
  1959. /* Return Value: */
  1960. /* */
  1961. /* VOID */
  1962. /* */
  1963. /************************************************************************/
  1964. VOID
  1965. StartNotifyRead(IN PDEVICE_EXTENSION DeviceExtension)
  1966. {
  1967. PIRP NotifyIrp;
  1968. PURB NotifyUrb;
  1969. CCHAR StackSize;
  1970. ULONG Size;
  1971. PAGED_CODE();
  1972. DEBUG_LOG_PATH("enter StartNotifyRead");
  1973. UsbSerSerialDump(USBSERTRACERD, (">StartNotifyRead\n"));
  1974. // get stack size for Irp and allocate one that we will use to keep
  1975. // notification requests going
  1976. StackSize = (CCHAR)(DeviceExtension->StackDeviceObject->StackSize + 1);
  1977. NotifyIrp = IoAllocateIrp(StackSize, FALSE);
  1978. if (NotifyIrp) {
  1979. // get size of Urb and allocate
  1980. Size = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
  1981. NotifyUrb = DEBUG_MEMALLOC(NonPagedPool, Size);
  1982. if (NotifyUrb) {
  1983. // save these to be freed when not needed
  1984. UsbSerFetchPVoidLocked(&DeviceExtension->NotifyIrp, NotifyIrp,
  1985. &DeviceExtension->ControlLock);
  1986. UsbSerFetchPVoidLocked(&DeviceExtension->NotifyUrb, NotifyUrb,
  1987. &DeviceExtension->ControlLock);
  1988. RestartNotifyRead(DeviceExtension);
  1989. }
  1990. }
  1991. DEBUG_LOG_PATH("exit StartNotifyRead");
  1992. UsbSerSerialDump(USBSERTRACERD, ("<StartNotifyRead\n"));
  1993. } // StartNotifyRead
  1994. /************************************************************************/
  1995. /* RestartNotifyRead */
  1996. /************************************************************************/
  1997. /* */
  1998. /* Routine Description: */
  1999. /* */
  2000. /* Kick off a notify read. */
  2001. /* */
  2002. /* Arguments: */
  2003. /* */
  2004. /* DeviceExtension - pointer to a device extension */
  2005. /* */
  2006. /* Return Value: */
  2007. /* */
  2008. /* VOID */
  2009. /* */
  2010. /************************************************************************/
  2011. VOID
  2012. RestartNotifyRead(IN PDEVICE_EXTENSION DeviceExtension)
  2013. {
  2014. PIRP NotifyIrp;
  2015. PURB NotifyUrb;
  2016. PIO_STACK_LOCATION NextStack;
  2017. NTSTATUS NtStatus;
  2018. DEBUG_LOG_PATH("enter RestartNotifyRead");
  2019. UsbSerSerialDump(USBSERTRACERD, (">RestartNotifyRead\n"));
  2020. NotifyUrb = DeviceExtension->NotifyUrb;
  2021. NotifyIrp = DeviceExtension->NotifyIrp;
  2022. if(DeviceExtension->AcceptingRequests)
  2023. {
  2024. BuildReadRequest(NotifyUrb, DeviceExtension->NotificationBuff,
  2025. NOTIFICATION_BUFF_SIZE,
  2026. DeviceExtension->NotificationPipe, TRUE);
  2027. // set Irp up for a submit Urb IOCTL
  2028. NextStack = IoGetNextIrpStackLocation(NotifyIrp);
  2029. NextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  2030. NextStack->Parameters.Others.Argument1 = NotifyUrb;
  2031. NextStack->Parameters.DeviceIoControl.IoControlCode
  2032. = IOCTL_INTERNAL_USB_SUBMIT_URB;
  2033. // completion routine will take care of updating buffers and counters
  2034. IoSetCompletionRoutine(NotifyIrp, NotifyCompletion, DeviceExtension,
  2035. TRUE, TRUE, TRUE);
  2036. DEBUG_TRACE1(("Start NotifyRead\n"));
  2037. InterlockedIncrement(&DeviceExtension->PendingNotifyCount);
  2038. NtStatus = IoCallDriver(DeviceExtension->StackDeviceObject, NotifyIrp);
  2039. if (!NT_SUCCESS(NtStatus))
  2040. {
  2041. if (InterlockedDecrement(&DeviceExtension->PendingNotifyCount) == 0)
  2042. {
  2043. KeSetEvent(&DeviceExtension->PendingNotifyEvent, IO_NO_INCREMENT, FALSE);
  2044. }
  2045. }
  2046. DEBUG_TRACE1(("Status (%08X)\n", NtStatus));
  2047. }
  2048. DEBUG_LOG_PATH("exit RestartNotifyRead");
  2049. UsbSerSerialDump(USBSERTRACERD, ("<RestartNotifyRead\n"));
  2050. } // RestartNotifyRead
  2051. /************************************************************************/
  2052. /* ReadCompletion */
  2053. /************************************************************************/
  2054. /* */
  2055. /* Routine Description: */
  2056. /* */
  2057. /* Read completion routine. */
  2058. /* */
  2059. /* Arguments: */
  2060. /* */
  2061. /* DeviceObject - pointer to a device object */
  2062. /* Irp - pointer to Irp */
  2063. /* Context - pointer to driver defined context */
  2064. /* */
  2065. /* Return Value: */
  2066. /* */
  2067. /* NTSTATUS */
  2068. /* */
  2069. /************************************************************************/
  2070. NTSTATUS
  2071. ReadCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
  2072. {
  2073. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) Context;
  2074. PURB Urb;
  2075. ULONG Count;
  2076. KIRQL OldIrql;
  2077. DEBUG_LOG_PATH("enter ReadCompletion");
  2078. UsbSerSerialDump(USBSERTRACERD, (">ReadCompletion(%08X)\n", Irp));
  2079. ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
  2080. Urb = DeviceExtension->ReadUrb;
  2081. Count = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  2082. if (NT_SUCCESS(Irp->IoStatus.Status)
  2083. && (DeviceExtension->CurrentDevicePowerState == PowerDeviceD0))
  2084. {
  2085. DeviceExtension->HistoryMask |= SERIAL_EV_RXCHAR | SERIAL_EV_RX80FULL;
  2086. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  2087. //
  2088. // Scan for RXFLAG char if needed
  2089. //
  2090. if(DeviceExtension->IsrWaitMask & SERIAL_EV_RXFLAG)
  2091. {
  2092. ULONG i;
  2093. for(i = 0; i < Count; i++)
  2094. {
  2095. if(*((PUCHAR)(DeviceExtension->USBReadBuff + i))
  2096. == DeviceExtension->SpecialChars.EventChar)
  2097. {
  2098. DeviceExtension->HistoryMask |= SERIAL_EV_RXFLAG;
  2099. break;
  2100. }
  2101. }
  2102. }
  2103. PutData(DeviceExtension, Count);
  2104. // got some data, let's see if we can satisfy any queued reads
  2105. CheckForQueuedReads(DeviceExtension);
  2106. DEBUG_TRACE1(("ReadCompletion (%08X)\n", DeviceExtension->CharsInReadBuff));
  2107. ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
  2108. DeviceExtension->ReadInProgress = FALSE;
  2109. if(DeviceExtension->ReadInterlock == END_READ)
  2110. {
  2111. DeviceExtension->ReadInterlock = IMMEDIATE_READ;
  2112. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  2113. RestartRead(DeviceExtension);
  2114. }
  2115. else
  2116. {
  2117. DeviceExtension->ReadInterlock = IMMEDIATE_READ;
  2118. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  2119. }
  2120. }
  2121. else
  2122. {
  2123. //
  2124. // the device is not accepting requests, so signal anyone who
  2125. // cancelled this or is waiting for it to stop
  2126. //
  2127. DeviceExtension->ReadInterlock = IMMEDIATE_READ;
  2128. DeviceExtension->ReadInProgress = FALSE;
  2129. DeviceExtension->AcceptingRequests = FALSE;
  2130. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  2131. KeSetEvent(&DeviceExtension->ReadEvent, 1, FALSE);
  2132. DEBUG_TRACE1(("RC Irp Status (%08X)\n", Irp->IoStatus.Status));
  2133. }
  2134. //
  2135. // Notify everyone if this is the last IRP
  2136. //
  2137. if (InterlockedDecrement(&DeviceExtension->PendingDataInCount) == 0)
  2138. {
  2139. UsbSerSerialDump(USBSERTRACEOTH, ("DataIn pipe is empty\n"));
  2140. KeSetEvent(&DeviceExtension->PendingDataInEvent, IO_NO_INCREMENT, FALSE);
  2141. }
  2142. UsbSerSerialDump(USBSERTRACERD, ("DataInCount %08X @ %08X\n",
  2143. DeviceExtension->PendingDataInCount,
  2144. &DeviceExtension->PendingDataInCount));
  2145. DEBUG_LOG_PATH("exit ReadCompletion");
  2146. UsbSerSerialDump(USBSERTRACERD, ("<ReadCompletion\n"));
  2147. return STATUS_MORE_PROCESSING_REQUIRED;
  2148. } // ReadCompletion
  2149. /************************************************************************/
  2150. /* GetData */
  2151. /************************************************************************/
  2152. /* */
  2153. /* Routine Description: */
  2154. /* */
  2155. /* Get data from circular buffer. */
  2156. /* */
  2157. /* Arguments: */
  2158. /* */
  2159. /* DeviceExtension - pointer to device extension */
  2160. /* Buffer - pointer to buffer */
  2161. /* BufferLen - size of buffer */
  2162. /* */
  2163. /* Return Value: */
  2164. /* */
  2165. /* ULONG */
  2166. /* */
  2167. /************************************************************************/
  2168. ULONG
  2169. GetData(IN PDEVICE_EXTENSION DeviceExtension, IN PCHAR Buffer,
  2170. IN ULONG BufferLen, IN OUT PULONG_PTR NewCount)
  2171. {
  2172. ULONG count;
  2173. KIRQL OldIrql;
  2174. DEBUG_LOG_PATH("enter GetData");
  2175. UsbSerSerialDump(USBSERTRACERD, (">GetData\n"));
  2176. ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
  2177. BufferLen = min(DeviceExtension->CharsInReadBuff, BufferLen);
  2178. if(BufferLen)
  2179. {
  2180. count = min(BufferLen, (DeviceExtension->RxMaxPacketSize - DeviceExtension->CurrentReadBuffPtr));
  2181. memcpy(Buffer,
  2182. &DeviceExtension->ReadBuff[DeviceExtension->CurrentReadBuffPtr],
  2183. count);
  2184. Buffer += count;
  2185. DeviceExtension->CurrentReadBuffPtr += count;
  2186. DeviceExtension->CharsInReadBuff -= count;
  2187. DeviceExtension->NumberNeededForRead -= count;
  2188. BufferLen -= count;
  2189. *NewCount += count;
  2190. // if there is still something left in the buffer, then we wrapped
  2191. if(BufferLen)
  2192. {
  2193. memcpy(Buffer, DeviceExtension->ReadBuff, BufferLen);
  2194. DeviceExtension->CurrentReadBuffPtr = BufferLen;
  2195. DeviceExtension->CharsInReadBuff -= BufferLen;
  2196. DeviceExtension->NumberNeededForRead -= BufferLen;
  2197. *NewCount += BufferLen;
  2198. }
  2199. }
  2200. DEBUG_TRACE2(("Count (%08X) CharsInReadBuff (%08X)\n", count, DeviceExtension->CharsInReadBuff));
  2201. #if DBG
  2202. if (UsbSerSerialDebugLevel & USBSERDUMPRD) {
  2203. ULONG i;
  2204. DbgPrint("RD: ");
  2205. for (i = 0; i < count; i++) {
  2206. DbgPrint("%02x ", Buffer[i] & 0xFF);
  2207. }
  2208. DbgPrint("\n\n");
  2209. }
  2210. #endif
  2211. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  2212. RestartRead(DeviceExtension);
  2213. DEBUG_LOG_PATH("exit GetData");
  2214. UsbSerSerialDump(USBSERTRACERD, ("<GetData\n"));
  2215. return count;
  2216. } // GetData
  2217. /************************************************************************/
  2218. /* PutData */
  2219. /************************************************************************/
  2220. /* */
  2221. /* Routine Description: */
  2222. /* */
  2223. /* Put data in circular buffer. */
  2224. /* */
  2225. /* Arguments: */
  2226. /* */
  2227. /* DeviceExtension - pointer to device extension */
  2228. /* BufferLen - size of buffer */
  2229. /* */
  2230. /* Return Value: */
  2231. /* */
  2232. /* VOID */
  2233. /* */
  2234. /************************************************************************/
  2235. VOID
  2236. PutData(IN PDEVICE_EXTENSION DeviceExtension, IN ULONG BufferLen)
  2237. {
  2238. KIRQL OldIrql;
  2239. ULONG count;
  2240. ULONG BuffPtr;
  2241. if(BufferLen)
  2242. {
  2243. ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
  2244. // get current pointer into circular buffer
  2245. BuffPtr = (DeviceExtension->CharsInReadBuff + DeviceExtension->CurrentReadBuffPtr) %
  2246. DeviceExtension->RxMaxPacketSize;
  2247. // figure out amount to copy into read buffer, in case we would right past end of buffer
  2248. count = min(BufferLen, (DeviceExtension->RxMaxPacketSize - BuffPtr));
  2249. memcpy(&DeviceExtension->ReadBuff[BuffPtr],
  2250. DeviceExtension->USBReadBuff, count);
  2251. // update counters
  2252. BufferLen -= count;
  2253. DeviceExtension->CharsInReadBuff += count;
  2254. DeviceExtension->ReadByIsr += count;
  2255. // if there is still something left in the buffer, then we wrapped
  2256. if(BufferLen)
  2257. {
  2258. // count still holds the amount copied from buffer on first copy
  2259. // and BufferLen holds the amount remaining to copy
  2260. memcpy(DeviceExtension->ReadBuff,
  2261. &DeviceExtension->USBReadBuff[count], BufferLen);
  2262. DeviceExtension->CharsInReadBuff += BufferLen;
  2263. DeviceExtension->ReadByIsr += BufferLen;
  2264. }
  2265. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  2266. }
  2267. } // PutData
  2268. VOID
  2269. UsbSerRundownIrpRefs(IN PIRP *PpCurrentOpIrp, IN PKTIMER IntervalTimer OPTIONAL,
  2270. IN PKTIMER TotalTimer OPTIONAL,
  2271. IN PDEVICE_EXTENSION PDevExt)
  2272. /*++
  2273. Routine Description:
  2274. This routine runs through the various items that *could*
  2275. have a reference to the current read/write. It try's to kill
  2276. the reason. If it does succeed in killing the reason it
  2277. will decrement the reference count on the irp.
  2278. NOTE: This routine assumes that it is called with the cancel
  2279. spin lock held.
  2280. Arguments:
  2281. PpCurrentOpIrp - Pointer to a pointer to current irp for the
  2282. particular operation.
  2283. IntervalTimer - Pointer to the interval timer for the operation.
  2284. NOTE: This could be null.
  2285. TotalTimer - Pointer to the total timer for the operation.
  2286. NOTE: This could be null.
  2287. PDevExt - Pointer to device extension
  2288. Return Value:
  2289. None.
  2290. --*/
  2291. {
  2292. // PAGED_CODE();
  2293. UsbSerSerialDump(USBSERTRACEOTH, (">UsbSerRundownIrpRefs(%08X)\n",
  2294. *PpCurrentOpIrp));
  2295. //
  2296. // This routine is called with the cancel spin lock held
  2297. // so we know only one thread of execution can be in here
  2298. // at one time.
  2299. //
  2300. //
  2301. // First we see if there is still a cancel routine. If
  2302. // so then we can decrement the count by one.
  2303. //
  2304. if ((*PpCurrentOpIrp)->CancelRoutine) {
  2305. USBSER_CLEAR_REFERENCE(*PpCurrentOpIrp, USBSER_REF_CANCEL);
  2306. IoSetCancelRoutine(*PpCurrentOpIrp, NULL);
  2307. }
  2308. if (IntervalTimer) {
  2309. //
  2310. // Try to cancel the operations interval timer. If the operation
  2311. // returns true then the timer did have a reference to the
  2312. // irp. Since we've canceled this timer that reference is
  2313. // no longer valid and we can decrement the reference count.
  2314. //
  2315. // If the cancel returns false then this means either of two things:
  2316. //
  2317. // a) The timer has already fired.
  2318. //
  2319. // b) There never was an interval timer.
  2320. //
  2321. // In the case of "b" there is no need to decrement the reference
  2322. // count since the "timer" never had a reference to it.
  2323. //
  2324. // In the case of "a", then the timer itself will be coming
  2325. // along and decrement it's reference. Note that the caller
  2326. // of this routine might actually be the this timer, but it
  2327. // has already decremented the reference.
  2328. //
  2329. if (KeCancelTimer(IntervalTimer)) {
  2330. USBSER_CLEAR_REFERENCE(*PpCurrentOpIrp, USBSER_REF_INT_TIMER);
  2331. }
  2332. }
  2333. if (TotalTimer) {
  2334. //
  2335. // Try to cancel the operations total timer. If the operation
  2336. // returns true then the timer did have a reference to the
  2337. // irp. Since we've canceled this timer that reference is
  2338. // no longer valid and we can decrement the reference count.
  2339. //
  2340. // If the cancel returns false then this means either of two things:
  2341. //
  2342. // a) The timer has already fired.
  2343. //
  2344. // b) There never was an total timer.
  2345. //
  2346. // In the case of "b" there is no need to decrement the reference
  2347. // count since the "timer" never had a reference to it.
  2348. // //
  2349. // If we have an escape char event pending, we can't overstuff,
  2350. // so subtract one from the length
  2351. //
  2352. // In the case of "a", then the timer itself will be coming
  2353. // along and decrement it's reference. Note that the caller
  2354. // of this routine might actually be the this timer, but it
  2355. // has already decremented the reference.
  2356. //
  2357. if (KeCancelTimer(TotalTimer)) {
  2358. USBSER_CLEAR_REFERENCE(*PpCurrentOpIrp, USBSER_REF_TOTAL_TIMER);
  2359. }
  2360. }
  2361. // USBSER_CLEAR_REFERENCE(*PpCurrentOpIrp, USBSER_REF_RXBUFFER);
  2362. UsbSerSerialDump(USBSERTRACEOTH, ("<UsbSerRundownIrpRefs\n"));
  2363. }
  2364. VOID
  2365. UsbSerTryToCompleteCurrent(IN PDEVICE_EXTENSION PDevExt,
  2366. IN KIRQL IrqlForRelease, IN NTSTATUS StatusToUse,
  2367. IN PIRP *PpCurrentOpIrp,
  2368. IN PLIST_ENTRY PQueue OPTIONAL,
  2369. IN PKTIMER PIntervalTimer OPTIONAL,
  2370. IN PKTIMER PTotalTimer OPTIONAL,
  2371. IN PUSBSER_START_ROUTINE Starter OPTIONAL,
  2372. IN PUSBSER_GET_NEXT_ROUTINE PGetNextIrp OPTIONAL,
  2373. IN LONG RefType,
  2374. IN BOOLEAN Complete)
  2375. /*++
  2376. Routine Description:
  2377. This routine attempts to kill all of the reasons there are
  2378. references on the current read/write. If everything can be killed
  2379. it will complete this read/write and try to start another.
  2380. NOTE: This routine assumes that it is called with the cancel
  2381. spinlock held.
  2382. Arguments:
  2383. Extension - Simply a pointer to the device extension.
  2384. SynchRoutine - A routine that will synchronize with the isr
  2385. and attempt to remove the knowledge of the
  2386. current irp from the isr. NOTE: This pointer
  2387. can be null.
  2388. IrqlForRelease - This routine is called with the cancel spinlock held.
  2389. This is the irql that was current when the cancel
  2390. spinlock was acquired.
  2391. StatusToUse - The irp's status field will be set to this value, if
  2392. this routine can complete the irp.
  2393. Return Value:
  2394. None.
  2395. --*/
  2396. {
  2397. USBSER_ALWAYS_LOCKED_CODE();
  2398. UsbSerSerialDump(USBSERTRACEOTH | USBSERTRACERD | USBSERTRACEWR,
  2399. (">UsbSerTryToCompleteCurrent(%08X)\n", *PpCurrentOpIrp));
  2400. //
  2401. // We can decrement the reference to "remove" the fact
  2402. // that the caller no longer will be accessing this irp.
  2403. //
  2404. USBSER_CLEAR_REFERENCE(*PpCurrentOpIrp, RefType);
  2405. //
  2406. // Try to run down all other references to this irp.
  2407. //
  2408. UsbSerRundownIrpRefs(PpCurrentOpIrp, PIntervalTimer, PTotalTimer, PDevExt);
  2409. //
  2410. // See if the ref count is zero after trying to kill everybody else.
  2411. //
  2412. if (!USBSER_REFERENCE_COUNT(*PpCurrentOpIrp)) {
  2413. PIRP pNewIrp;
  2414. //
  2415. // The ref count was zero so we should complete this
  2416. // request.
  2417. //
  2418. // The following call will also cause the current irp to be
  2419. // completed.
  2420. //
  2421. (*PpCurrentOpIrp)->IoStatus.Status = StatusToUse;
  2422. if (StatusToUse == STATUS_CANCELLED) {
  2423. (*PpCurrentOpIrp)->IoStatus.Information = 0;
  2424. }
  2425. if (PGetNextIrp) {
  2426. RELEASE_CANCEL_SPINLOCK(PDevExt, IrqlForRelease);
  2427. (*PGetNextIrp)(PpCurrentOpIrp, PQueue, &pNewIrp, Complete, PDevExt);
  2428. if (pNewIrp) {
  2429. Starter(PDevExt);
  2430. }
  2431. } else {
  2432. PIRP pOldIrp = *PpCurrentOpIrp;
  2433. //
  2434. // There was no get next routine. We will simply complete
  2435. // the irp. We should make sure that we null out the
  2436. // pointer to the pointer to this irp.
  2437. //
  2438. *PpCurrentOpIrp = NULL;
  2439. RELEASE_CANCEL_SPINLOCK(PDevExt, IrqlForRelease);
  2440. if (Complete) {
  2441. IoCompleteRequest(pOldIrp, IO_SERIAL_INCREMENT);
  2442. }
  2443. }
  2444. } else {
  2445. RELEASE_CANCEL_SPINLOCK(PDevExt, IrqlForRelease);
  2446. UsbSerSerialDump(USBSERTRACEOTH | USBSERTRACERD | USBSERTRACEWR,
  2447. ("Current IRP still has reference of %08X\n",
  2448. ((UINT_PTR)((IoGetCurrentIrpStackLocation((*PpCurrentOpIrp))->
  2449. Parameters.Others.Argument4)))));
  2450. }
  2451. UsbSerSerialDump(USBSERTRACEOTH | USBSERTRACERD | USBSERTRACEWR,
  2452. ("<UsbSerTryToCompleteCurrent\n"));
  2453. }
  2454. /************************************************************************/
  2455. /* CheckForQueuedReads */
  2456. /************************************************************************/
  2457. /* */
  2458. /* Routine Description: */
  2459. /* */
  2460. /* See if we have any queued reads that we can satisfy. */
  2461. /* */
  2462. /* Arguments: */
  2463. /* */
  2464. /* DeviceExtension - pointer to device extension */
  2465. /* */
  2466. /* Return Value: */
  2467. /* */
  2468. /* VOID */
  2469. /* */
  2470. /************************************************************************/
  2471. VOID
  2472. CheckForQueuedReads(IN PDEVICE_EXTENSION DeviceExtension)
  2473. {
  2474. ULONG charsRead = 0;
  2475. PULONG pWaitMask;
  2476. KIRQL oldIrql;
  2477. //
  2478. // May be paged if we do counter
  2479. //
  2480. DEBUG_LOG_PATH("enter CheckForQueuedReads");
  2481. UsbSerSerialDump(USBSERTRACERD, (">CheckForQueuedReads\n"));
  2482. ACQUIRE_CANCEL_SPINLOCK(DeviceExtension, &oldIrql);
  2483. if ((DeviceExtension->CurrentReadIrp != NULL)
  2484. && (USBSER_REFERENCE_COUNT(DeviceExtension->CurrentReadIrp)
  2485. & USBSER_REF_RXBUFFER))
  2486. {
  2487. RELEASE_CANCEL_SPINLOCK(DeviceExtension, oldIrql);
  2488. DEBUG_TRACE3(("Reading 0x%x\n", DeviceExtension->NumberNeededForRead));
  2489. charsRead
  2490. = GetData(DeviceExtension,
  2491. ((PUCHAR)(DeviceExtension->CurrentReadIrp
  2492. ->AssociatedIrp.SystemBuffer))
  2493. + (IoGetCurrentIrpStackLocation(DeviceExtension
  2494. ->CurrentReadIrp))
  2495. ->Parameters.Read.Length
  2496. - DeviceExtension->NumberNeededForRead,
  2497. DeviceExtension->NumberNeededForRead,
  2498. &DeviceExtension->CurrentReadIrp->IoStatus.Information);
  2499. ACQUIRE_CANCEL_SPINLOCK(DeviceExtension, &oldIrql);
  2500. //
  2501. // See if this read is complete
  2502. //
  2503. if (DeviceExtension->NumberNeededForRead == 0) {
  2504. DEBUG_TRACE3(("USBSER: Completing read\n"));
  2505. if(DeviceExtension->CurrentReadIrp)
  2506. {
  2507. DeviceExtension->CurrentReadIrp->IoStatus.Status = STATUS_SUCCESS;
  2508. }
  2509. //
  2510. // Mark the read as completed and try to service the next one
  2511. //
  2512. DeviceExtension->CountOnLastRead = SERIAL_COMPLETE_READ_COMPLETE;
  2513. #if DBG
  2514. if (UsbSerSerialDebugLevel & USBSERDUMPRD) {
  2515. ULONG i;
  2516. ULONG count;
  2517. if (DeviceExtension->CurrentReadIrp->IoStatus.Status == STATUS_SUCCESS) {
  2518. count = (ULONG)DeviceExtension->CurrentReadIrp->IoStatus.Information;
  2519. } else {
  2520. count = 0;
  2521. }
  2522. DbgPrint("RD2: A(%08X) G(%08X) I(%08X)\n",
  2523. IoGetCurrentIrpStackLocation(DeviceExtension->CurrentReadIrp)
  2524. ->Parameters.Read.Length, count, DeviceExtension->CurrentReadIrp);
  2525. for (i = 0; i < count; i++) {
  2526. DbgPrint("%02x ", *(((PUCHAR)DeviceExtension->CurrentReadIrp
  2527. ->AssociatedIrp.SystemBuffer) + i) & 0xFF);
  2528. }
  2529. if (i == 0) {
  2530. DbgPrint("NULL (%08X)\n", DeviceExtension->CurrentReadIrp
  2531. ->IoStatus.Status);
  2532. }
  2533. DbgPrint("\n\n");
  2534. }
  2535. #endif
  2536. UsbSerTryToCompleteCurrent(DeviceExtension, oldIrql, STATUS_SUCCESS,
  2537. &DeviceExtension->CurrentReadIrp,
  2538. &DeviceExtension->ReadQueue,
  2539. &DeviceExtension->ReadRequestIntervalTimer,
  2540. &DeviceExtension->ReadRequestTotalTimer,
  2541. UsbSerStartRead, UsbSerGetNextIrp,
  2542. USBSER_REF_RXBUFFER,
  2543. TRUE);
  2544. ACQUIRE_CANCEL_SPINLOCK(DeviceExtension, &oldIrql);
  2545. }
  2546. }
  2547. if (DeviceExtension->IsrWaitMask & SERIAL_EV_RXCHAR) {
  2548. DeviceExtension->HistoryMask |= SERIAL_EV_RXCHAR;
  2549. }
  2550. if (DeviceExtension->CurrentMaskIrp != NULL) {
  2551. pWaitMask = (PULONG)DeviceExtension->CurrentMaskIrp->
  2552. AssociatedIrp.SystemBuffer;
  2553. //
  2554. // Process events
  2555. //
  2556. if (DeviceExtension->IsrWaitMask & DeviceExtension->HistoryMask) {
  2557. PIRP pMaskIrp;
  2558. DEBUG_TRACE3(("Completing events\n"));
  2559. *pWaitMask = DeviceExtension->HistoryMask;
  2560. DeviceExtension->HistoryMask = 0;
  2561. pMaskIrp = DeviceExtension->CurrentMaskIrp;
  2562. pMaskIrp->IoStatus.Information = sizeof(ULONG);
  2563. pMaskIrp->IoStatus.Status = STATUS_SUCCESS;
  2564. DeviceExtension->CurrentMaskIrp = NULL;
  2565. IoSetCancelRoutine(pMaskIrp, NULL);
  2566. RELEASE_CANCEL_SPINLOCK(DeviceExtension, oldIrql);
  2567. IoCompleteRequest(pMaskIrp, IO_SERIAL_INCREMENT);
  2568. }
  2569. else
  2570. {
  2571. RELEASE_CANCEL_SPINLOCK(DeviceExtension, oldIrql);
  2572. }
  2573. }
  2574. else
  2575. {
  2576. RELEASE_CANCEL_SPINLOCK(DeviceExtension, oldIrql);
  2577. }
  2578. DEBUG_LOG_PATH("exit CheckForQueuedReads");
  2579. UsbSerSerialDump(USBSERTRACERD, ("<CheckForQueuedReads\n"));
  2580. } // CheckForQueuedReads
  2581. VOID
  2582. UsbSerGetNextIrp(IN PIRP *PpCurrentOpIrp, IN PLIST_ENTRY PQueueToProcess,
  2583. OUT PIRP *PpNextIrp, IN BOOLEAN CompleteCurrent,
  2584. IN PDEVICE_EXTENSION PDevExt)
  2585. /*++
  2586. Routine Description:
  2587. This function gets the next IRP off a queue, marks it as current,
  2588. and possibly completes the current IRP.
  2589. Arguments:
  2590. PpCurrentOpIrp - A pointer to the pointer to the current IRP.
  2591. PQueueToProcess - A pointer to the queue to get the next IRP from.
  2592. PpNextIrp - A pointer to the pointer to the next IRP to process.
  2593. CompleteCurrent - TRUE if we should complete the IRP that is current at
  2594. the time we are called.
  2595. PDevExt - A pointer to the device extension.
  2596. Return Value:
  2597. NTSTATUS
  2598. --*/
  2599. {
  2600. KIRQL oldIrql;
  2601. PIRP pOldIrp;
  2602. USBSER_ALWAYS_LOCKED_CODE();
  2603. DEBUG_LOG_PATH("Enter UsbSerGetNextIrp");
  2604. UsbSerSerialDump(USBSERTRACEOTH | USBSERTRACERD | USBSERTRACEWR,
  2605. (">UsbSerGetNextIrp(%08)\n", *PpCurrentOpIrp));
  2606. ACQUIRE_CANCEL_SPINLOCK(PDevExt, &oldIrql);
  2607. pOldIrp = *PpCurrentOpIrp;
  2608. #if DBG
  2609. if (pOldIrp != NULL) {
  2610. if (CompleteCurrent) {
  2611. ASSERT(pOldIrp->CancelRoutine == NULL);
  2612. }
  2613. }
  2614. #endif
  2615. //
  2616. // Check to see if there is a new irp to start up
  2617. //
  2618. if (!IsListEmpty(PQueueToProcess)) {
  2619. PLIST_ENTRY pHeadOfList;
  2620. pHeadOfList = RemoveHeadList(PQueueToProcess);
  2621. *PpCurrentOpIrp = CONTAINING_RECORD(pHeadOfList, IRP,
  2622. Tail.Overlay.ListEntry);
  2623. IoSetCancelRoutine(*PpCurrentOpIrp, NULL);
  2624. } else {
  2625. *PpCurrentOpIrp = NULL;
  2626. }
  2627. *PpNextIrp = *PpCurrentOpIrp;
  2628. RELEASE_CANCEL_SPINLOCK(PDevExt, oldIrql);
  2629. //
  2630. // Complete the current one if so requested
  2631. //
  2632. if (CompleteCurrent) {
  2633. if (pOldIrp != NULL) {
  2634. IoCompleteRequest(pOldIrp, IO_SERIAL_INCREMENT);
  2635. }
  2636. }
  2637. DEBUG_LOG_PATH("Exit UsbSerGetNextIrp");
  2638. UsbSerSerialDump(USBSERTRACEOTH | USBSERTRACERD | USBSERTRACEWR,
  2639. ("<UsbSerGetNextIrp\n"));
  2640. }
  2641. NTSTATUS
  2642. UsbSerStartOrQueue(IN PDEVICE_EXTENSION PDevExt, IN PIRP PIrp,
  2643. IN PLIST_ENTRY PQueue, IN PIRP *PPCurrentIrp,
  2644. IN PUSBSER_START_ROUTINE Starter)
  2645. /*++
  2646. Routine Description:
  2647. This function is used to either start processing an I/O request or to
  2648. queue it on the appropriate queue if a request is already pending or
  2649. requests may not be started.
  2650. Arguments:
  2651. PDevExt - A pointer to the DeviceExtension.
  2652. PIrp - A pointer to the IRP that is being started or queued.
  2653. PQueue - A pointer to the queue to place the IRP on if necessary.
  2654. PPCurrentIrp - A pointer to the pointer to the currently active I/O IRP.
  2655. Starter - Function to call if we decide to start this IRP.
  2656. Return Value:
  2657. NTSTATUS
  2658. --*/
  2659. {
  2660. KIRQL oldIrql;
  2661. NTSTATUS status;
  2662. USBSER_ALWAYS_LOCKED_CODE();
  2663. DEBUG_LOG_PATH("Enter UsbSerStartOrQueue");
  2664. UsbSerSerialDump(USBSERTRACEOTH, (">UsbSerStartOrQueue(%08X)\n", PIrp));
  2665. ACQUIRE_CANCEL_SPINLOCK(PDevExt, &oldIrql);
  2666. if (IsListEmpty(PQueue) && (*PPCurrentIrp == NULL)) {
  2667. //
  2668. // Nothing pending -- start the new irp
  2669. //
  2670. *PPCurrentIrp = PIrp;
  2671. RELEASE_CANCEL_SPINLOCK(PDevExt, oldIrql);
  2672. status = Starter(PDevExt);
  2673. DEBUG_LOG_PATH("Exit UsbSerStartOrQueue(1)");
  2674. UsbSerSerialDump(USBSERTRACEOTH, ("<UsbSerStartOrQueue(1) %08X\n",
  2675. status));
  2676. return status;
  2677. }
  2678. //
  2679. // We're queueing the irp, so we need a cancel routine -- make sure
  2680. // the irp hasn't already been cancelled.
  2681. //
  2682. if (PIrp->Cancel) {
  2683. //
  2684. // The IRP was apparently cancelled. Complete it.
  2685. //
  2686. RELEASE_CANCEL_SPINLOCK(PDevExt, oldIrql);
  2687. PIrp->IoStatus.Status = STATUS_CANCELLED;
  2688. IoCompleteRequest(PIrp, IO_NO_INCREMENT);
  2689. DEBUG_LOG_PATH("Exit UsbSerStartOrQueue(2)");
  2690. UsbSerSerialDump(USBSERTRACEOTH, ("<UsbSerStartOrQueue(2) %08X\n",
  2691. STATUS_CANCELLED));
  2692. return STATUS_CANCELLED;
  2693. }
  2694. //
  2695. // Mark as pending, attach our cancel routine
  2696. //
  2697. PIrp->IoStatus.Status = STATUS_PENDING;
  2698. IoMarkIrpPending(PIrp);
  2699. InsertTailList(PQueue, &PIrp->Tail.Overlay.ListEntry);
  2700. IoSetCancelRoutine(PIrp, UsbSerCancelQueued);
  2701. RELEASE_CANCEL_SPINLOCK(PDevExt, oldIrql);
  2702. DEBUG_LOG_PATH("Exit UsbSerStartOrQueue(3)");
  2703. UsbSerSerialDump(USBSERTRACEOTH, ("<UsbSerStartOrQueue(3) %08X\n",
  2704. STATUS_PENDING));
  2705. return STATUS_PENDING;
  2706. }
  2707. VOID
  2708. UsbSerCancelQueued(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
  2709. /*++
  2710. Routine Description:
  2711. This function is used as a cancel routine for queued irps. Basically
  2712. for us this means read IRPs.
  2713. Arguments:
  2714. PDevObj - A pointer to the serial device object.
  2715. PIrp - A pointer to the IRP that is being cancelled
  2716. Return Value:
  2717. VOID
  2718. --*/
  2719. {
  2720. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  2721. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
  2722. USBSER_ALWAYS_LOCKED_CODE();
  2723. DEBUG_LOG_PATH("Enter UsbSerCancelQueued");
  2724. UsbSerSerialDump(USBSERTRACEOTH, (">UsbSerCancelQueued(%08X)\n", PIrp));
  2725. //
  2726. // The irp was cancelled -- remove it from the queue
  2727. //
  2728. PIrp->IoStatus.Status = STATUS_CANCELLED;
  2729. PIrp->IoStatus.Information = 0;
  2730. RemoveEntryList(&PIrp->Tail.Overlay.ListEntry);
  2731. RELEASE_CANCEL_SPINLOCK(pDevExt, PIrp->CancelIrql);
  2732. IoCompleteRequest(PIrp, IO_SERIAL_INCREMENT);
  2733. DEBUG_LOG_PATH("Exit UsbSerCancelQueued");
  2734. UsbSerSerialDump(USBSERTRACEOTH, ("<UsbSerCancelQueued\n"));
  2735. }
  2736. VOID
  2737. UsbSerKillAllReadsOrWrites(IN PDEVICE_OBJECT PDevObj,
  2738. IN PLIST_ENTRY PQueueToClean,
  2739. IN PIRP *PpCurrentOpIrp)
  2740. /*++
  2741. Routine Description:
  2742. This function is used to cancel all queued and the current irps
  2743. for reads or for writes.
  2744. Arguments:
  2745. PDevObj - A pointer to the serial device object.
  2746. PQueueToClean - A pointer to the queue which we're going to clean out.
  2747. PpCurrentOpIrp - Pointer to a pointer to the current irp.
  2748. Return Value:
  2749. None.
  2750. --*/
  2751. {
  2752. KIRQL cancelIrql;
  2753. PDRIVER_CANCEL cancelRoutine;
  2754. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  2755. USBSER_ALWAYS_LOCKED_CODE();
  2756. UsbSerSerialDump(USBSERTRACERD | USBSERTRACEWR,
  2757. (">UsbSerKillAllReadsOrWrites(%08X)\n", *PpCurrentOpIrp));
  2758. //
  2759. // We acquire the cancel spin lock. This will prevent the
  2760. // irps from moving around.
  2761. //
  2762. ACQUIRE_CANCEL_SPINLOCK(pDevExt, &cancelIrql);
  2763. //
  2764. // Clean the list from back to front.
  2765. //
  2766. while (!IsListEmpty(PQueueToClean)) {
  2767. PIRP pCurrentLastIrp = CONTAINING_RECORD(PQueueToClean->Blink, IRP,
  2768. Tail.Overlay.ListEntry);
  2769. RemoveEntryList(PQueueToClean->Blink);
  2770. cancelRoutine = pCurrentLastIrp->CancelRoutine;
  2771. pCurrentLastIrp->CancelIrql = cancelIrql;
  2772. pCurrentLastIrp->CancelRoutine = NULL;
  2773. pCurrentLastIrp->Cancel = TRUE;
  2774. cancelRoutine(PDevObj, pCurrentLastIrp);
  2775. ACQUIRE_CANCEL_SPINLOCK(pDevExt, &cancelIrql);
  2776. }
  2777. //
  2778. // The queue is clean. Now go after the current if
  2779. // it's there.
  2780. //
  2781. if (*PpCurrentOpIrp) {
  2782. cancelRoutine = (*PpCurrentOpIrp)->CancelRoutine;
  2783. (*PpCurrentOpIrp)->Cancel = TRUE;
  2784. //
  2785. // If the current irp is not in a cancelable state
  2786. // then it *will* try to enter one and the above
  2787. // assignment will kill it. If it already is in
  2788. // a cancelable state then the following will kill it.
  2789. //
  2790. if (cancelRoutine) {
  2791. (*PpCurrentOpIrp)->CancelRoutine = NULL;
  2792. (*PpCurrentOpIrp)->CancelIrql = cancelIrql;
  2793. //
  2794. // This irp is already in a cancelable state. We simply
  2795. // mark it as canceled and call the cancel routine for
  2796. // it.
  2797. //
  2798. cancelRoutine(PDevObj, *PpCurrentOpIrp);
  2799. } else {
  2800. RELEASE_CANCEL_SPINLOCK(pDevExt, cancelIrql);
  2801. }
  2802. } else {
  2803. RELEASE_CANCEL_SPINLOCK(pDevExt, cancelIrql);
  2804. }
  2805. UsbSerSerialDump(USBSERTRACERD | USBSERTRACEWR,
  2806. ("<UsbSerKillAllReadsOrWrites\n"));
  2807. }
  2808. VOID
  2809. UsbSerKillPendingIrps(PDEVICE_OBJECT PDevObj)
  2810. /*++
  2811. Routine Description:
  2812. Kill all IRPs queued in our driver
  2813. Arguments:
  2814. PDevObj - a pointer to the device object
  2815. Return Value:
  2816. VOID
  2817. --*/
  2818. {
  2819. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  2820. KIRQL cancelIrql;
  2821. USBSER_ALWAYS_LOCKED_CODE();
  2822. UsbSerSerialDump(USBSERTRACEOTH, (">UsbSerKillPendingIrps\n"));
  2823. //
  2824. // Kill all reads; we do not queue writes
  2825. //
  2826. UsbSerKillAllReadsOrWrites(PDevObj, &pDevExt->ReadQueue,
  2827. &pDevExt->CurrentReadIrp);
  2828. //
  2829. // Get rid of any pending waitmasks
  2830. //
  2831. ACQUIRE_CANCEL_SPINLOCK(pDevExt, &cancelIrql);
  2832. if (pDevExt->CurrentMaskIrp != NULL) {
  2833. PDRIVER_CANCEL cancelRoutine;
  2834. cancelRoutine = pDevExt->CurrentMaskIrp->CancelRoutine;
  2835. pDevExt->CurrentMaskIrp->Cancel = TRUE;
  2836. ASSERT(cancelRoutine);
  2837. if (cancelRoutine) {
  2838. pDevExt->CurrentMaskIrp->CancelRoutine = NULL;
  2839. pDevExt->CurrentMaskIrp->CancelIrql = cancelIrql;
  2840. cancelRoutine(PDevObj, pDevExt->CurrentMaskIrp);
  2841. } else {
  2842. RELEASE_CANCEL_SPINLOCK(pDevExt, cancelIrql);
  2843. }
  2844. }else {
  2845. RELEASE_CANCEL_SPINLOCK(pDevExt, cancelIrql);
  2846. }
  2847. //
  2848. // Cancel any pending wait-wake irps
  2849. //
  2850. if (pDevExt->PendingWakeIrp != NULL) {
  2851. IoCancelIrp(pDevExt->PendingWakeIrp);
  2852. pDevExt->PendingWakeIrp = NULL;
  2853. }
  2854. UsbSerSerialDump(USBSERTRACEOTH, ("<UsbSerKillPendingIrps\n"));
  2855. }
  2856. /************************************************************************/
  2857. /* CompletePendingWaitMasks */
  2858. /************************************************************************/
  2859. /* */
  2860. /* Routine Description: */
  2861. /* */
  2862. /* Completes any wait masks in progress with no events set. */
  2863. /* */
  2864. /* Arguments: */
  2865. /* */
  2866. /* DeviceExtension - pointer to a device extension */
  2867. /* */
  2868. /* Return Value: */
  2869. /* */
  2870. /* VOID */
  2871. /* */
  2872. /************************************************************************/
  2873. VOID
  2874. UsbSerCompletePendingWaitMasks(IN PDEVICE_EXTENSION DeviceExtension)
  2875. {
  2876. KIRQL OldIrql;
  2877. PIRP CurrentMaskIrp;
  2878. KIRQL cancelIrql;
  2879. USBSER_ALWAYS_LOCKED_CODE();
  2880. DEBUG_LOG_PATH("enter CompletePendingWaitMasks");
  2881. UsbSerSerialDump(USBSERTRACEOTH, (">CompletePendingWaitMasks\n"));
  2882. ACQUIRE_CANCEL_SPINLOCK(DeviceExtension, &cancelIrql);
  2883. ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql);
  2884. CurrentMaskIrp = DeviceExtension->CurrentMaskIrp;
  2885. if (CurrentMaskIrp) {
  2886. CurrentMaskIrp->IoStatus.Status = STATUS_SUCCESS;
  2887. CurrentMaskIrp->IoStatus.Information = sizeof(ULONG);
  2888. *((PULONG)CurrentMaskIrp->AssociatedIrp.SystemBuffer) = 0;
  2889. DeviceExtension->CurrentMaskIrp = NULL;
  2890. IoSetCancelRoutine(CurrentMaskIrp, NULL);
  2891. }
  2892. // complete the queued IRP if needed
  2893. if (CurrentMaskIrp) {
  2894. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  2895. RELEASE_CANCEL_SPINLOCK(DeviceExtension, cancelIrql);
  2896. IoCompleteRequest(CurrentMaskIrp, IO_NO_INCREMENT);
  2897. DEBUG_TRACE1(("CompletePendingWaitMask\n"));
  2898. }
  2899. else
  2900. {
  2901. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql);
  2902. RELEASE_CANCEL_SPINLOCK(DeviceExtension, cancelIrql);
  2903. }
  2904. DEBUG_LOG_PATH("exit CompletePendingWaitMasks");
  2905. UsbSerSerialDump(USBSERTRACEOTH, ("<CompletePendingWaitMasks\n"));
  2906. } // CancelPendingWaitMasks
  2907. VOID
  2908. UsbSerRestoreModemSettings(PDEVICE_OBJECT PDevObj)
  2909. /*++
  2910. Routine Description:
  2911. Restores the modem's settings upon a powerup.
  2912. Arguments:
  2913. PDevExt - a pointer to the device extension
  2914. Return Value:
  2915. VOID
  2916. --*/
  2917. {
  2918. PAGED_CODE();
  2919. (void)SetLineControlAndBaud(PDevObj);
  2920. }
  2921. VOID
  2922. UsbSerProcessEmptyTransmit(IN PDEVICE_EXTENSION PDevExt)
  2923. /*++
  2924. Routine Description:
  2925. This function is called whenever our tx queue is empty in order
  2926. to set the proper events, etc.
  2927. Arguments:
  2928. PDevExt - Pointer to DeviceExtension for the device
  2929. Return Value:
  2930. VOID
  2931. --*/
  2932. {
  2933. KIRQL oldIrql;
  2934. PULONG pWaitMask;
  2935. USBSER_ALWAYS_LOCKED_CODE();
  2936. //
  2937. // Set the event if needed
  2938. //
  2939. PDevExt->HistoryMask |= SERIAL_EV_TXEMPTY;
  2940. if (PDevExt->IsrWaitMask & SERIAL_EV_TXEMPTY) {
  2941. PIRP pMaskIrp;
  2942. DEBUG_TRACE3(("Completing events\n"));
  2943. ACQUIRE_CANCEL_SPINLOCK(PDevExt, &oldIrql);
  2944. if (PDevExt->CurrentMaskIrp != NULL) {
  2945. pWaitMask = (PULONG)PDevExt->CurrentMaskIrp->
  2946. AssociatedIrp.SystemBuffer;
  2947. *pWaitMask = PDevExt->HistoryMask;
  2948. PDevExt->HistoryMask = 0;
  2949. pMaskIrp = PDevExt->CurrentMaskIrp;
  2950. pMaskIrp->IoStatus.Information = sizeof(ULONG);
  2951. pMaskIrp->IoStatus.Status = STATUS_SUCCESS;
  2952. PDevExt->CurrentMaskIrp = NULL;
  2953. IoSetCancelRoutine(pMaskIrp, NULL);
  2954. RELEASE_CANCEL_SPINLOCK(PDevExt, oldIrql);
  2955. IoCompleteRequest(pMaskIrp, IO_SERIAL_INCREMENT);
  2956. } else {
  2957. RELEASE_CANCEL_SPINLOCK(PDevExt, oldIrql);
  2958. }
  2959. }
  2960. }
  2961. VOID
  2962. UsbSerCancelWaitOnMask(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
  2963. /*++
  2964. Routine Description:
  2965. This function is used as a cancel routine for WaitOnMask IRPs.
  2966. Arguments:
  2967. PDevObj - Pointer to Device Object
  2968. PIrp - Pointer to IRP that is being canceled; must be the same as
  2969. the current mask IRP.
  2970. Return Value:
  2971. VOID
  2972. --*/
  2973. {
  2974. PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)PDevObj->DeviceExtension;
  2975. USBSER_ALWAYS_LOCKED_CODE();
  2976. UsbSerSerialDump(USBSERTRACEOTH, (">UsbSerCancelWaitOnMask(%08X)\n", PIrp));
  2977. ASSERT(pDevExt->CurrentMaskIrp == PIrp);
  2978. PIrp->IoStatus.Status = STATUS_CANCELLED;
  2979. PIrp->IoStatus.Information = 0;
  2980. pDevExt->CurrentMaskIrp = NULL;
  2981. RELEASE_CANCEL_SPINLOCK(pDevExt, PIrp->CancelIrql);
  2982. IoCompleteRequest(PIrp, IO_SERIAL_INCREMENT);
  2983. UsbSerSerialDump(USBSERTRACEOTH, ("<UsbSerCancelWaitOnMask(%08X)"));
  2984. }
  2985. NTSTATUS
  2986. UsbSerSyncCompletion(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp,
  2987. IN PKEVENT PUsbSerSyncEvent)
  2988. /*++
  2989. Routine Description:
  2990. This function is used to signal an event. It is used as a completion
  2991. routine.
  2992. Arguments:
  2993. PDevObj - Pointer to Device Object
  2994. PIrp - Pointer to IRP that is being completed
  2995. PUsbSerSyncEvent - Pointer to event that we should set
  2996. Return Value:
  2997. STATUS_MORE_PROCESSING_REQUIRED
  2998. --*/
  2999. {
  3000. KeSetEvent(PUsbSerSyncEvent, IO_NO_INCREMENT, FALSE);
  3001. return STATUS_MORE_PROCESSING_REQUIRED;
  3002. }
  3003. #if DBG
  3004. PVOID
  3005. UsbSerLockPagableCodeSection(PVOID SecFunc)
  3006. /*++
  3007. Routine Description:
  3008. This function is used to lockdown code pages and increment a lock counter
  3009. for debugging.
  3010. Arguments:
  3011. SecFunc - Function in code section to be locked down.
  3012. Return Value:
  3013. PVOID - Handle for locked down section.
  3014. --*/
  3015. { PVOID handle;
  3016. PAGED_CODE();
  3017. handle = MmLockPagableCodeSection(SecFunc);
  3018. // can this be paged?
  3019. InterlockedIncrement(&PAGEUSBSER_Count);
  3020. return handle;
  3021. }
  3022. #endif
  3023. VOID
  3024. UsbSerFetchBooleanLocked(PBOOLEAN PDest, BOOLEAN Src, PKSPIN_LOCK PSpinLock)
  3025. /*++
  3026. Routine Description:
  3027. This function is used to assign a BOOLEAN value with spinlock protection.
  3028. Arguments:
  3029. PDest - A pointer to Lval.
  3030. Src - Rval.
  3031. PSpinLock - Pointer to the spin lock we should hold.
  3032. Return Value:
  3033. None.
  3034. --*/
  3035. {
  3036. KIRQL tmpIrql;
  3037. KeAcquireSpinLock(PSpinLock, &tmpIrql);
  3038. *PDest = Src;
  3039. KeReleaseSpinLock(PSpinLock, tmpIrql);
  3040. }
  3041. VOID
  3042. UsbSerFetchPVoidLocked(PVOID *PDest, PVOID Src, PKSPIN_LOCK PSpinLock)
  3043. /*++
  3044. Routine Description:
  3045. This function is used to assign a PVOID value with spinlock protection.
  3046. Arguments:
  3047. PDest - A pointer to Lval.
  3048. Src - Rval.
  3049. PSpinLock - Pointer to the spin lock we should hold.
  3050. Return Value:
  3051. None.
  3052. --*/
  3053. {
  3054. KIRQL tmpIrql;
  3055. KeAcquireSpinLock(PSpinLock, &tmpIrql);
  3056. *PDest = Src;
  3057. KeReleaseSpinLock(PSpinLock, tmpIrql);
  3058. }
  3059. /*++
  3060. Routine Description:
  3061. Work item to kick off another notify read
  3062. Arguments:
  3063. DeviceObject - pointer to the device object
  3064. DeviceExtension - context for this call
  3065. Return Value:
  3066. None.
  3067. --*/
  3068. VOID
  3069. USBSER_RestartNotifyReadWorkItem(IN PDEVICE_OBJECT DeviceObject, IN PDEVICE_EXTENSION DeviceExtension)
  3070. {
  3071. KIRQL oldIrql;
  3072. PIO_WORKITEM ioWorkItem;
  3073. ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &oldIrql);
  3074. ioWorkItem = DeviceExtension->IoWorkItem;
  3075. DeviceExtension->IoWorkItem = NULL;
  3076. RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, oldIrql);
  3077. IoFreeWorkItem(ioWorkItem);
  3078. RestartNotifyRead(DeviceExtension);
  3079. } // USBER_RestartNotifyReadWorkItem
  3080.