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

760 lines
22 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. pnp.c
  5. Abstract: ESC/POS (serial) interface for USB Point-of-Sale devices
  6. Author:
  7. ervinp
  8. Environment:
  9. Kernel mode
  10. Revision History:
  11. --*/
  12. #include <WDM.H>
  13. #include <usbdi.h>
  14. #include <usbdlib.h>
  15. #include <usbioctl.h>
  16. #include "escpos.h"
  17. #include "debug.h"
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE, FDO_PnP)
  20. #pragma alloc_text(PAGE, GetDeviceCapabilities)
  21. #endif
  22. NTSTATUS FDO_PnP(PARENTFDOEXT *parentFdoExt, PIRP irp)
  23. /*++
  24. Routine Description:
  25. Dispatch routine for PnP IRPs (MajorFunction == IRP_MJ_PNP)
  26. Arguments:
  27. parentFdoExt - device extension for the targetted device object
  28. irp - IO Request Packet
  29. Return Value:
  30. NT status code
  31. --*/
  32. {
  33. PIO_STACK_LOCATION irpSp;
  34. NTSTATUS status = STATUS_SUCCESS;
  35. BOOLEAN completeIrpHere = FALSE;
  36. BOOLEAN justReturnStatus = FALSE;
  37. ULONG minorFunction;
  38. enum deviceState prevState;
  39. PAGED_CODE();
  40. irpSp = IoGetCurrentIrpStackLocation(irp);
  41. /*
  42. * Get this field into a stack var so we can touch it after the IRP's completed.
  43. */
  44. minorFunction = (ULONG)(irpSp->MinorFunction);
  45. DBG_LOG_PNP_IRP(irp, minorFunction, FALSE, FALSE, -1);
  46. switch (minorFunction){
  47. case IRP_MN_START_DEVICE:
  48. prevState = parentFdoExt->state;
  49. parentFdoExt->state = STATE_STARTING;
  50. /*
  51. * First, send the START_DEVICE irp down the stack
  52. * synchronously to start the lower stack.
  53. * We cannot do anything with our device object
  54. * before propagating the START_DEVICE this way.
  55. */
  56. IoCopyCurrentIrpStackLocationToNext(irp);
  57. status = CallNextDriverSync(parentFdoExt, irp);
  58. if (NT_SUCCESS(status) && (prevState != STATE_STOPPED)){
  59. /*
  60. * Now that the lower stack is started,
  61. * do any initialization required by this device object.
  62. */
  63. status = GetDeviceCapabilities(parentFdoExt);
  64. if (NT_SUCCESS(status)){
  65. status = InitUSB(parentFdoExt);
  66. if (NT_SUCCESS(status)){
  67. /*
  68. * Check whether any special feature needs to be implemented.
  69. */
  70. DBGVERBOSE(("FDO_PnP: Poking registry for posFlag..."));
  71. status = QuerySpecialFeature(parentFdoExt);
  72. if (NT_SUCCESS(status)){
  73. status = CreatePdoForEachEndpointPair(parentFdoExt);
  74. if (NT_SUCCESS(status)){
  75. IoInvalidateDeviceRelations(parentFdoExt->physicalDevObj, BusRelations);
  76. }
  77. }
  78. }
  79. }
  80. }
  81. if (NT_SUCCESS(status)){
  82. parentFdoExt->state = STATE_STARTED;
  83. }
  84. else {
  85. parentFdoExt->state = STATE_START_FAILED;
  86. }
  87. completeIrpHere = TRUE;
  88. break;
  89. case IRP_MN_QUERY_STOP_DEVICE:
  90. break;
  91. case IRP_MN_STOP_DEVICE:
  92. if (parentFdoExt->state == STATE_SUSPENDED){
  93. status = STATUS_DEVICE_POWER_FAILURE;
  94. completeIrpHere = TRUE;
  95. }
  96. else {
  97. /*
  98. * Only set state to STOPPED if the device was
  99. * previously started successfully.
  100. */
  101. if (parentFdoExt->state == STATE_STARTED){
  102. parentFdoExt->state = STATE_STOPPED;
  103. }
  104. }
  105. break;
  106. case IRP_MN_QUERY_REMOVE_DEVICE:
  107. /*
  108. * We will pass this IRP down the driver stack.
  109. * However, we need to change the default status
  110. * from STATUS_NOT_SUPPORTED to STATUS_SUCCESS.
  111. */
  112. irp->IoStatus.Status = STATUS_SUCCESS;
  113. break;
  114. case IRP_MN_SURPRISE_REMOVAL:
  115. /*
  116. * We will pass this IRP down the driver stack.
  117. * However, we need to change the default status
  118. * from STATUS_NOT_SUPPORTED to STATUS_SUCCESS.
  119. */
  120. irp->IoStatus.Status = STATUS_SUCCESS;
  121. /*
  122. * For now just set the STATE_REMOVING state so that
  123. * we don't do any more IO. We are guaranteed to get
  124. * IRP_MN_REMOVE_DEVICE soon; we'll do the rest of
  125. * the remove processing there.
  126. */
  127. parentFdoExt->state = STATE_REMOVING;
  128. break;
  129. case IRP_MN_REMOVE_DEVICE:
  130. /*
  131. * Check the current state to guard against multiple
  132. * REMOVE_DEVICE IRPs.
  133. */
  134. parentFdoExt->state = STATE_REMOVED;
  135. /*
  136. * Send the REMOVE IRP down the stack asynchronously.
  137. * Do not synchronize sending down the REMOVE_DEVICE
  138. * IRP, because the REMOVE_DEVICE IRP must be sent
  139. * down and completed all the way back up to the sender
  140. * before we continue.
  141. */
  142. IoCopyCurrentIrpStackLocationToNext(irp);
  143. status = IoCallDriver(parentFdoExt->physicalDevObj, irp);
  144. justReturnStatus = TRUE;
  145. DBGVERBOSE(("REMOVE_DEVICE - waiting for %d irps to complete...", parentFdoExt->pendingActionCount));
  146. /*
  147. * We must for all outstanding IO to complete before
  148. * completing the REMOVE_DEVICE IRP.
  149. *
  150. * First do an extra decrement on the pendingActionCount.
  151. * This will cause pendingActionCount to eventually
  152. * go to -1 once all asynchronous actions on this
  153. * device object are complete.
  154. * Then wait on the event that gets set when the
  155. * pendingActionCount actually reaches -1.
  156. */
  157. DecrementPendingActionCount(parentFdoExt);
  158. KeWaitForSingleObject( &parentFdoExt->removeEvent,
  159. Executive, // wait reason
  160. KernelMode,
  161. FALSE, // not alertable
  162. NULL ); // no timeout
  163. DBGVERBOSE(("REMOVE_DEVICE - ... DONE waiting. "));
  164. /*
  165. * Detach our device object from the lower device object stack.
  166. */
  167. IoDetachDevice(parentFdoExt->topDevObj);
  168. /*
  169. * Delete all child PDOs.
  170. */
  171. if (ISPTR(parentFdoExt->deviceRelations)){
  172. ULONG i;
  173. DBGVERBOSE(("Parent deleting %xh child PDOs on REMOVE_DEVICE", parentFdoExt->deviceRelations->Count));
  174. for (i = 0; i < parentFdoExt->deviceRelations->Count; i++){
  175. PDEVICE_OBJECT childPdo = parentFdoExt->deviceRelations->Objects[i];
  176. DEVEXT *devExt = childPdo->DeviceExtension;
  177. POSPDOEXT *pdoExt;
  178. ASSERT(devExt->signature == DEVICE_EXTENSION_SIGNATURE);
  179. ASSERT(devExt->isPdo);
  180. pdoExt = &devExt->pdoExt;
  181. DeleteChildPdo(pdoExt);
  182. }
  183. FREEPOOL(parentFdoExt->deviceRelations);
  184. parentFdoExt->deviceRelations = BAD_POINTER;
  185. }
  186. if (ISPTR(parentFdoExt->interfaceInfo)){
  187. FREEPOOL(parentFdoExt->interfaceInfo);
  188. }
  189. if (ISPTR(parentFdoExt->configDesc)){
  190. FREEPOOL(parentFdoExt->configDesc);
  191. }
  192. /*
  193. * Delete our device object.
  194. * This will also delete the associated device extension.
  195. */
  196. IoDeleteDevice(parentFdoExt->functionDevObj);
  197. break;
  198. case IRP_MN_QUERY_DEVICE_RELATIONS:
  199. if (irpSp->Parameters.QueryDeviceRelations.Type == BusRelations){
  200. status = QueryDeviceRelations(parentFdoExt, irp);
  201. if (NT_SUCCESS(status)){
  202. /*
  203. * Although we may have satisfied this IRP,
  204. * we still pass it down the stack.
  205. * But change the default status to success.
  206. */
  207. irp->IoStatus.Status = status;
  208. }
  209. else {
  210. completeIrpHere = TRUE;
  211. }
  212. }
  213. break;
  214. case IRP_MN_QUERY_CAPABILITIES:
  215. /*
  216. * Return the USB PDO's capabilities, but add the SurpriseRemovalOK bit.
  217. */
  218. ASSERT(irpSp->Parameters.DeviceCapabilities.Capabilities);
  219. IoCopyCurrentIrpStackLocationToNext(irp);
  220. status = CallNextDriverSync(parentFdoExt, irp);
  221. if (NT_SUCCESS(status)){
  222. irpSp->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
  223. }
  224. completeIrpHere = TRUE;
  225. break;
  226. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  227. break;
  228. default:
  229. break;
  230. }
  231. if (justReturnStatus){
  232. /*
  233. * We've already sent this IRP down the stack asynchronously.
  234. */
  235. }
  236. else if (completeIrpHere){
  237. ASSERT(status != NO_STATUS);
  238. irp->IoStatus.Status = status;
  239. IoCompleteRequest(irp, IO_NO_INCREMENT);
  240. }
  241. else {
  242. IoCopyCurrentIrpStackLocationToNext(irp);
  243. status = IoCallDriver(parentFdoExt->physicalDevObj, irp);
  244. }
  245. DBG_LOG_PNP_IRP(irp, minorFunction, FALSE, TRUE, status);
  246. return status;
  247. }
  248. NTSTATUS GetDeviceCapabilities(PARENTFDOEXT *parentFdoExt)
  249. /*++
  250. Routine Description:
  251. Function retrieves the DEVICE_CAPABILITIES descriptor from the device
  252. Arguments:
  253. parentFdoExt - device extension for targetted device object
  254. Return Value:
  255. NT status code
  256. --*/
  257. {
  258. NTSTATUS status;
  259. PIRP irp;
  260. PAGED_CODE();
  261. irp = IoAllocateIrp(parentFdoExt->physicalDevObj->StackSize, FALSE);
  262. if (irp){
  263. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  264. nextSp->MajorFunction = IRP_MJ_PNP;
  265. nextSp->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  266. RtlZeroMemory( &parentFdoExt->deviceCapabilities,
  267. sizeof(DEVICE_CAPABILITIES));
  268. nextSp->Parameters.DeviceCapabilities.Capabilities =
  269. &parentFdoExt->deviceCapabilities;
  270. /*
  271. * For any IRP you create, you must set the default status
  272. * to STATUS_NOT_SUPPORTED before sending it.
  273. */
  274. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  275. status = CallNextDriverSync(parentFdoExt, irp);
  276. IoFreeIrp(irp);
  277. }
  278. else {
  279. status = STATUS_INSUFFICIENT_RESOURCES;
  280. }
  281. ASSERT(NT_SUCCESS(status));
  282. return status;
  283. }
  284. NTSTATUS QueryDeviceRelations(PARENTFDOEXT *parentFdoExt, PIRP irp)
  285. {
  286. PIO_STACK_LOCATION irpSp;
  287. NTSTATUS status;
  288. PAGED_CODE();
  289. irpSp = IoGetCurrentIrpStackLocation(irp);
  290. if (irpSp->Parameters.QueryDeviceRelations.Type == BusRelations){
  291. DBGVERBOSE(("QueryDeviceRelations(BusRelations) for parent"));
  292. /*
  293. * NTKERN expects a new pointer each time it calls QUERY_DEVICE_RELATIONS;
  294. * it then FREES THE POINTER.
  295. * So we have to return a new pointer each time, whether or not we actually
  296. * created our copy of the device relations for this call.
  297. */
  298. irp->IoStatus.Information = (ULONG)CopyDeviceRelations(parentFdoExt->deviceRelations);
  299. if (irp->IoStatus.Information){
  300. ULONG i;
  301. /*
  302. * The kernel dereferences each device object
  303. * in the device relations list after each call.
  304. * So for each call, add an extra reference.
  305. */
  306. for (i = 0; i < parentFdoExt->deviceRelations->Count; i++){
  307. ObReferenceObject(parentFdoExt->deviceRelations->Objects[i]);
  308. parentFdoExt->deviceRelations->Objects[i]->Flags &= ~DO_DEVICE_INITIALIZING;
  309. }
  310. DBGVERBOSE(("Returned %d child PDOs", parentFdoExt->deviceRelations->Count));
  311. status = STATUS_SUCCESS;
  312. }
  313. else {
  314. status = STATUS_INSUFFICIENT_RESOURCES;
  315. }
  316. ASSERT(NT_SUCCESS(status));
  317. }
  318. else {
  319. ASSERT(irpSp->Parameters.QueryDeviceRelations.Type == BusRelations);
  320. status = irp->IoStatus.Status;
  321. }
  322. return status;
  323. }
  324. NTSTATUS PDO_PnP(POSPDOEXT *pdoExt, PIRP irp)
  325. {
  326. NTSTATUS status;
  327. PIO_STACK_LOCATION irpSp;
  328. irpSp = IoGetCurrentIrpStackLocation(irp);
  329. DBG_LOG_PNP_IRP(irp, irpSp->MinorFunction, TRUE, FALSE, -1);
  330. switch (irpSp->MinorFunction){
  331. case IRP_MN_START_DEVICE:
  332. status = CreateSymbolicLink(pdoExt);
  333. if (NT_SUCCESS(status)){
  334. pdoExt->state = STATE_STARTED;
  335. /*
  336. * Initializing URB to read the status endpoint for Serial Emulation.
  337. */
  338. if(pdoExt->parentFdoExt->posFlag & SERIAL_EMULATION) {
  339. StatusPipe(pdoExt, pdoExt->statusEndpointInfo.pipeHandle);
  340. DBGVERBOSE(("PDO_PnP: URB to read Status Endpoint initialized"));
  341. }
  342. }
  343. else {
  344. pdoExt->state = STATE_START_FAILED;
  345. }
  346. break;
  347. case IRP_MN_QUERY_STOP_DEVICE:
  348. status = STATUS_SUCCESS;
  349. break;
  350. case IRP_MN_STOP_DEVICE:
  351. pdoExt->state = STATE_STOPPED;
  352. status = STATUS_SUCCESS;
  353. break;
  354. case IRP_MN_SURPRISE_REMOVAL:
  355. status = FlushBuffers(pdoExt);
  356. break;
  357. case IRP_MN_REMOVE_DEVICE:
  358. {
  359. ULONG oldState = pdoExt->state;
  360. KIRQL oldIrql;
  361. BOOLEAN foundPdo = FALSE;
  362. ULONG i;
  363. pdoExt->state = STATE_REMOVED;
  364. if ((oldState == STATE_STARTED) || (oldState == STATE_STOPPED)){
  365. DestroySymbolicLink(pdoExt);
  366. }
  367. else {
  368. DBGWARN(("previous state is %xh during pdo REMOVE_DEVICE", oldState));
  369. }
  370. /*
  371. * See if this child PDO is still in the parent's device relations array.
  372. */
  373. KeAcquireSpinLock(&pdoExt->parentFdoExt->devExtSpinLock, &oldIrql);
  374. for (i = 0; i < pdoExt->parentFdoExt->deviceRelations->Count; i++){
  375. if (pdoExt->parentFdoExt->deviceRelations->Objects[i] == pdoExt->pdo){
  376. foundPdo = TRUE;
  377. }
  378. }
  379. KeReleaseSpinLock(&pdoExt->parentFdoExt->devExtSpinLock, oldIrql);
  380. FlushBuffers(pdoExt);
  381. if (foundPdo){
  382. /*
  383. * If we are still in the parent's deviceRelations, then don't
  384. * free the pdo or pdoName.Buffer . We may get another START
  385. * on this same PDO.
  386. */
  387. }
  388. else {
  389. /*
  390. * This shouldn't happen.
  391. */
  392. ASSERT(foundPdo);
  393. /*
  394. * We've recorded this COM port statically in our software key,
  395. * so don't free it in the COM name arbiter.
  396. */
  397. // ReleaseCOMPort(pdoExt->comPortNumber);
  398. DeleteChildPdo(pdoExt);
  399. }
  400. status = STATUS_SUCCESS;
  401. }
  402. break;
  403. case IRP_MN_QUERY_ID:
  404. status = QueryPdoID(pdoExt, irp);
  405. break;
  406. case IRP_MN_QUERY_CAPABILITIES:
  407. ASSERT(irpSp->Parameters.DeviceCapabilities.Capabilities);
  408. RtlCopyMemory( irpSp->Parameters.DeviceCapabilities.Capabilities,
  409. &pdoExt->parentFdoExt->deviceCapabilities,
  410. sizeof(DEVICE_CAPABILITIES));
  411. /*
  412. * Set the 'Raw' capability so that the child PDO gets started immediately,
  413. * without anyone having to do an open on it first.
  414. */
  415. irpSp->Parameters.DeviceCapabilities.Capabilities->RawDeviceOK = TRUE;
  416. irpSp->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
  417. status = STATUS_SUCCESS;
  418. break;
  419. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  420. status = CallNextDriverSync(pdoExt->parentFdoExt, irp);
  421. break;
  422. case IRP_MN_QUERY_DEVICE_RELATIONS:
  423. if (irpSp->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation){
  424. /*
  425. * Return a reference to this PDO
  426. */
  427. PDEVICE_RELATIONS devRel = ALLOCPOOL(PagedPool, sizeof(DEVICE_RELATIONS));
  428. if (devRel){
  429. /*
  430. * Add a reference to the PDO, since CONFIGMG will free it.
  431. */
  432. ObReferenceObject(pdoExt->pdo);
  433. devRel->Objects[0] = pdoExt->pdo;
  434. devRel->Count = 1;
  435. irp->IoStatus.Information = (ULONG_PTR)devRel;
  436. status = STATUS_SUCCESS;
  437. }
  438. else {
  439. status = STATUS_INSUFFICIENT_RESOURCES;
  440. }
  441. }
  442. else {
  443. /*
  444. * Fail this Irp by returning the default
  445. * status (typically STATUS_NOT_SUPPORTED).
  446. */
  447. DBGVERBOSE(("PDO_PnP: not handling QueryDeviceRelations type %xh.", (ULONG)irpSp->Parameters.QueryDeviceRelations.Type));
  448. status = irp->IoStatus.Status;
  449. }
  450. break;
  451. default:
  452. /*
  453. * Fail the IRP with the default status
  454. */
  455. status = irp->IoStatus.Status;
  456. break;
  457. }
  458. DBG_LOG_PNP_IRP(irp, irpSp->MinorFunction, TRUE, TRUE, status);
  459. return status;
  460. }
  461. NTSTATUS SubstituteOneBusName(PWCHAR hwId)
  462. {
  463. NTSTATUS status;
  464. ULONG len = WStrLen(hwId);
  465. if ((len > 4) && !WStrNCmpI(hwId, L"USB\\", 4)){
  466. hwId[0] = L'P';
  467. hwId[1] = L'O';
  468. hwId[2] = L'S';
  469. status = STATUS_SUCCESS;
  470. }
  471. else {
  472. DBGERR(("SubstituteOneBusName: badly formed name at %ph.", hwId));
  473. status = STATUS_UNSUCCESSFUL;
  474. }
  475. return status;
  476. }
  477. /*
  478. * SubstituteBusNames
  479. *
  480. * busNames is a multi-string of PnP ids.
  481. * Subsitute 'POS\' for 'USB\' in each one.
  482. */
  483. NTSTATUS SubstituteBusNames(PWCHAR busNames)
  484. {
  485. NTSTATUS status = STATUS_SUCCESS;
  486. while (*busNames && (status == STATUS_SUCCESS)){
  487. ULONG len = WStrLen(busNames);
  488. status = SubstituteOneBusName(busNames);
  489. busNames += (len+1);
  490. }
  491. ASSERT(NT_SUCCESS(status));
  492. return status;
  493. }
  494. NTSTATUS QueryPdoID(POSPDOEXT *pdoExt, PIRP irp)
  495. {
  496. PIO_STACK_LOCATION irpSp;
  497. NTSTATUS status;
  498. PAGED_CODE();
  499. irpSp = IoGetCurrentIrpStackLocation(irp);
  500. DBGVERBOSE((" QueryPdoId: idType = %xh ", irpSp->Parameters.QueryId.IdType));
  501. switch (irpSp->Parameters.QueryId.IdType){
  502. case BusQueryHardwareIDs:
  503. /*
  504. * Return a multi-string containing the PnP ID for the POS serial interface.
  505. * Must terminate multi-string with a double unicode null.
  506. */
  507. (PWCHAR)irp->IoStatus.Information =
  508. MemDup(L"POS\\POS_SERIAL_INTERFACE\0", sizeof(L"POS\\POS_SERIAL_INTERFACE\0"));
  509. if (irp->IoStatus.Information){
  510. status = STATUS_SUCCESS;
  511. }
  512. else {
  513. ASSERT(irp->IoStatus.Information);
  514. status = STATUS_INSUFFICIENT_RESOURCES;
  515. }
  516. break;
  517. case BusQueryDeviceID:
  518. /*
  519. * Return the PnP ID for the POS serial interface.
  520. */
  521. (PWCHAR)irp->IoStatus.Information =
  522. MemDup(L"POS\\POS_SERIAL_INTERFACE", sizeof(L"POS\\POS_SERIAL_INTERFACE"));
  523. if (irp->IoStatus.Information){
  524. status = STATUS_SUCCESS;
  525. }
  526. else {
  527. ASSERT(irp->IoStatus.Information);
  528. status = STATUS_INSUFFICIENT_RESOURCES;
  529. }
  530. break;
  531. case BusQueryInstanceID:
  532. /*
  533. * Produce an instance-id for this function-PDO.
  534. *
  535. * Note: NTKERN frees the returned pointer, so we must provide a fresh pointer.
  536. */
  537. {
  538. PWSTR instanceId = MemDup(L"0000", sizeof(L"0000"));
  539. if (instanceId){
  540. KIRQL oldIrql;
  541. ULONG i;
  542. /*
  543. * Find this collection-PDO in the device-relations array
  544. * and make the id be the PDO's index within that array.
  545. */
  546. KeAcquireSpinLock(&pdoExt->parentFdoExt->devExtSpinLock, &oldIrql);
  547. for (i = 0; i < pdoExt->parentFdoExt->deviceRelations->Count; i++){
  548. if (pdoExt->parentFdoExt->deviceRelations->Objects[i] == pdoExt->pdo){
  549. break;
  550. }
  551. }
  552. if (i < pdoExt->parentFdoExt->deviceRelations->Count){
  553. NumToDecString(instanceId, (USHORT)i, 4);
  554. irp->IoStatus.Information = (ULONG)instanceId;
  555. status = STATUS_SUCCESS;
  556. }
  557. else {
  558. ASSERT(i < pdoExt->parentFdoExt->deviceRelations->Count);
  559. status = STATUS_DEVICE_DATA_ERROR;
  560. }
  561. KeReleaseSpinLock(&pdoExt->parentFdoExt->devExtSpinLock, oldIrql);
  562. if (!NT_SUCCESS(status)){
  563. FREEPOOL(instanceId);
  564. }
  565. }
  566. else {
  567. status = STATUS_INSUFFICIENT_RESOURCES;
  568. }
  569. }
  570. ASSERT(NT_SUCCESS(status));
  571. break;
  572. case BusQueryCompatibleIDs:
  573. /*
  574. * Return multi-string of compatible IDs.
  575. */
  576. (PWCHAR)irp->IoStatus.Information = MemDup(L"\0\0", sizeof(L"\0\0"));
  577. if (irp->IoStatus.Information) {
  578. status = STATUS_SUCCESS;
  579. }
  580. else {
  581. ASSERT(irp->IoStatus.Information);
  582. status = STATUS_INSUFFICIENT_RESOURCES;
  583. }
  584. break;
  585. default:
  586. /*
  587. * Do not return STATUS_NOT_SUPPORTED;
  588. * keep the default status
  589. * (this allows filter drivers to work).
  590. */
  591. status = irp->IoStatus.Status;
  592. break;
  593. }
  594. return status;
  595. }
  596. VOID DeleteChildPdo(POSPDOEXT *pdoExt)
  597. {
  598. ASSERT(pdoExt->pdoName.Buffer);
  599. FREEPOOL(pdoExt->pdoName.Buffer);
  600. IoDeleteDevice(pdoExt->pdo);
  601. }