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.

1618 lines
44 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. changer.c
  5. Abstract:
  6. Authors:
  7. Chuck Park (chuckp)
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. --*/
  12. #include "cdchgr.h"
  13. #include "ntddcdrm.h"
  14. #include "initguid.h"
  15. #include "ntddstor.h"
  16. //
  17. // Function declarations
  18. //
  19. NTSTATUS
  20. DriverEntry(
  21. IN PDRIVER_OBJECT DriverObject,
  22. IN PUNICODE_STRING RegistryPath
  23. );
  24. NTSTATUS
  25. ChangerAddDevice(
  26. IN PDRIVER_OBJECT DriverObject,
  27. IN PDEVICE_OBJECT PhysicalDeviceObject
  28. );
  29. NTSTATUS
  30. ChangerPnp(
  31. IN PDEVICE_OBJECT DeviceObject,
  32. IN PIRP Irp
  33. );
  34. NTSTATUS
  35. ChangerPower(
  36. IN PDEVICE_OBJECT DeviceObject,
  37. IN PIRP Irp
  38. );
  39. NTSTATUS
  40. ChangerStartDevice(
  41. IN PDEVICE_OBJECT DeviceObject,
  42. IN PIRP Irp
  43. );
  44. NTSTATUS
  45. ChangerSendToNextDriver(
  46. IN PDEVICE_OBJECT DeviceObject,
  47. IN PIRP Irp
  48. );
  49. NTSTATUS
  50. ChangerCreate(
  51. IN PDEVICE_OBJECT DeviceObject,
  52. IN PIRP Irp
  53. );
  54. NTSTATUS
  55. ChangerPassThrough(
  56. IN PDEVICE_OBJECT DeviceObject,
  57. IN PIRP Irp
  58. );
  59. NTSTATUS
  60. ChangerDeviceControl(
  61. IN PDEVICE_OBJECT DeviceObject,
  62. IN PIRP Irp
  63. );
  64. VOID
  65. ChangerUnload(
  66. IN PDRIVER_OBJECT DriverObject
  67. );
  68. NTSTATUS
  69. DriverEntry(
  70. IN PDRIVER_OBJECT DriverObject,
  71. IN PUNICODE_STRING RegistryPath
  72. )
  73. /*++
  74. Routine Description:
  75. Installable driver initialization entry point.
  76. Arguments:
  77. DriverObject - Supplies the driver object.
  78. RegistryPath - pointer to a unicode string representing the path,
  79. to driver-specific key in the registry.
  80. Return Value:
  81. STATUS_SUCCESS if successful
  82. --*/
  83. {
  84. ULONG i;
  85. DebugPrint((2,
  86. "Changer: DriverEntry\n"));
  87. //
  88. // Set up the device driver entry points.
  89. //
  90. DriverObject->MajorFunction[IRP_MJ_CREATE] = ChangerPassThrough;
  91. DriverObject->MajorFunction[IRP_MJ_CLOSE] = ChangerPassThrough;
  92. DriverObject->MajorFunction[IRP_MJ_READ] = ChangerPassThrough;
  93. DriverObject->MajorFunction[IRP_MJ_WRITE] = ChangerPassThrough;
  94. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ChangerDeviceControl;
  95. DriverObject->MajorFunction[IRP_MJ_PNP] = ChangerPnp;
  96. DriverObject->MajorFunction[IRP_MJ_POWER] = ChangerPower;
  97. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ChangerPassThrough;
  98. DriverObject->DriverExtension->AddDevice = ChangerAddDevice;
  99. DriverObject->DriverUnload = ChangerUnload;
  100. return STATUS_SUCCESS;
  101. } // end DriverEntry()
  102. NTSTATUS
  103. ChangerCreate(
  104. IN PDEVICE_OBJECT DeviceObject,
  105. IN PIRP Irp
  106. )
  107. /*++
  108. Routine Description:
  109. This routine serves create commands. It does no more than
  110. establish the drivers existence by returning status success.
  111. Arguments:
  112. DeviceObject
  113. IRP
  114. Return Value:
  115. NT Status
  116. --*/
  117. {
  118. Irp->IoStatus.Status = STATUS_SUCCESS;
  119. IoCompleteRequest(Irp, 0);
  120. return STATUS_SUCCESS;
  121. }
  122. NTSTATUS
  123. ChangerAddDevice(
  124. IN PDRIVER_OBJECT DriverObject,
  125. IN PDEVICE_OBJECT PhysicalDeviceObject
  126. )
  127. /*++
  128. Routine Description:
  129. Creates and initializes a new filter device object FDO for the
  130. corresponding PDO. Then it attaches the device object to the device
  131. stack of the drivers for the device.
  132. Arguments:
  133. DriverObject - Changer DriverObject.
  134. PhysicalDeviceObject - Physical Device Object from the underlying driver
  135. Return Value:
  136. NTSTATUS
  137. --*/
  138. {
  139. NTSTATUS status;
  140. IO_STATUS_BLOCK ioStatus;
  141. PDEVICE_OBJECT filterDeviceObject;
  142. PDEVICE_EXTENSION deviceExtension;
  143. UNICODE_STRING additionalString;
  144. DebugPrint((2,
  145. "ChangerAddDevice\n"));
  146. //
  147. // Create a filter device object for the underlying cdrom device.
  148. //
  149. status = IoCreateDevice(DriverObject,
  150. DEVICE_EXTENSION_SIZE,
  151. NULL,
  152. FILE_DEVICE_CD_ROM,
  153. 0,
  154. FALSE,
  155. &filterDeviceObject);
  156. if (!NT_SUCCESS(status)) {
  157. DebugPrint((2,
  158. "ChangerAddDevice: IoCreateDevice failed %lx\n",
  159. status));
  160. return status;
  161. }
  162. filterDeviceObject->Flags |= DO_DIRECT_IO;
  163. if (filterDeviceObject->Flags & DO_POWER_INRUSH) {
  164. DebugPrint((1,
  165. "ChangerAddDevice: Someone set DO_POWER_INRUSH?\n",
  166. status
  167. ));
  168. } else {
  169. filterDeviceObject->Flags |= DO_POWER_PAGABLE;
  170. }
  171. deviceExtension = (PDEVICE_EXTENSION) filterDeviceObject->DeviceExtension;
  172. RtlZeroMemory(deviceExtension, DEVICE_EXTENSION_SIZE);
  173. //
  174. // Attaches the device object to the highest device object in the chain and
  175. // return the previously highest device object, which is passed to IoCallDriver
  176. // when pass IRPs down the device stack
  177. //
  178. deviceExtension->CdromTargetDeviceObject =
  179. IoAttachDeviceToDeviceStack(filterDeviceObject, PhysicalDeviceObject);
  180. if (deviceExtension->CdromTargetDeviceObject == NULL) {
  181. DebugPrint((2,
  182. "ChangerAddDevice: IoAttachDevice failed %lx\n",
  183. STATUS_NO_SUCH_DEVICE));
  184. IoDeleteDevice(filterDeviceObject);
  185. return STATUS_NO_SUCH_DEVICE;
  186. }
  187. //
  188. // Save the filter device object in the device extension
  189. //
  190. deviceExtension->DeviceObject = filterDeviceObject;
  191. //
  192. // Initialize the event for PagingPathNotifications
  193. //
  194. KeInitializeEvent(&deviceExtension->PagingPathCountEvent,
  195. SynchronizationEvent, TRUE);
  196. //
  197. // Register interfaces for this device.
  198. //
  199. RtlInitUnicodeString(&(deviceExtension->InterfaceName), NULL);
  200. RtlInitUnicodeString(&(additionalString), L"CdChanger");
  201. status = IoRegisterDeviceInterface(PhysicalDeviceObject,
  202. (LPGUID) &CdChangerClassGuid,
  203. &additionalString,
  204. &(deviceExtension->InterfaceName));
  205. DebugPrint((1,
  206. "Changer: IoRegisterDeviceInterface - status %lx",
  207. status));
  208. filterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  209. return STATUS_SUCCESS;
  210. } // end ChangerAddDevice()
  211. NTSTATUS
  212. ChgrCompletion(
  213. IN PDEVICE_OBJECT DeviceObject,
  214. IN PIRP Irp,
  215. IN PKEVENT Event
  216. )
  217. /*++
  218. Routine Description:
  219. This completion routine sets the event waited on by the start device.
  220. Arguments:
  221. DeviceObject - a pointer to the device object
  222. Irp - a pointer to the irp
  223. Event - a pointer to the event to signal
  224. Return Value:
  225. STATUS_MORE_PROCESSING_REQUIRED
  226. --*/
  227. {
  228. KeSetEvent(Event,
  229. IO_NO_INCREMENT,
  230. FALSE);
  231. return STATUS_MORE_PROCESSING_REQUIRED;
  232. }
  233. NTSTATUS
  234. ChangerStartDevice(
  235. IN PDEVICE_OBJECT DeviceObject,
  236. IN PIRP Irp
  237. )
  238. {
  239. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  240. CCHAR dosNameBuffer[64];
  241. CCHAR deviceNameBuffer[64];
  242. STRING deviceNameString;
  243. STRING dosString;
  244. UNICODE_STRING dosUnicodeString;
  245. UNICODE_STRING unicodeString;
  246. PIRP irp2;
  247. IO_STATUS_BLOCK ioStatus;
  248. STORAGE_DEVICE_NUMBER deviceNumber;
  249. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  250. KEVENT event;
  251. PPASS_THROUGH_REQUEST passThrough = NULL;
  252. PSCSI_PASS_THROUGH srb;
  253. PCDB cdb;
  254. //
  255. // Get the current changer count.
  256. //
  257. //devicesFound = &IoGetConfigurationInformation()->MediumChangerCount;
  258. //
  259. // Recreate the deviceName of the underlying cdrom.
  260. //
  261. KeInitializeEvent(&event, NotificationEvent, FALSE);
  262. irp2 = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
  263. deviceExtension->CdromTargetDeviceObject,
  264. NULL,
  265. 0,
  266. &deviceNumber,
  267. sizeof(STORAGE_DEVICE_NUMBER),
  268. FALSE,
  269. &event,
  270. &ioStatus);
  271. if (!irp2) {
  272. DebugPrint((1,
  273. "ChangerStartDevice: Insufficient resources for GET_DEVICE_NUMBER request\n"));
  274. status = STATUS_INSUFFICIENT_RESOURCES;
  275. goto StartDeviceExit;
  276. }
  277. status = IoCallDriver(deviceExtension->CdromTargetDeviceObject,irp2);
  278. if (status == STATUS_PENDING) {
  279. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  280. status = ioStatus.Status;
  281. }
  282. if (!NT_SUCCESS(status)) {
  283. DebugPrint((1,
  284. "ChangerStartDevice: GetDeviceNumber failed %lx\n",
  285. status));
  286. goto StartDeviceExit;
  287. }
  288. deviceExtension->CdRomDeviceNumber = deviceNumber.DeviceNumber;
  289. //
  290. // Create the the arcname with the same ordinal as the underlying cdrom device.
  291. //
  292. sprintf(dosNameBuffer,
  293. "\\DosDevices\\CdChanger%d",
  294. deviceExtension->CdRomDeviceNumber);
  295. RtlInitString(&dosString, dosNameBuffer);
  296. status = RtlAnsiStringToUnicodeString(&dosUnicodeString,
  297. &dosString,
  298. TRUE);
  299. if(!NT_SUCCESS(status)) {
  300. status = STATUS_INSUFFICIENT_RESOURCES;
  301. dosUnicodeString.Buffer = NULL;
  302. }
  303. sprintf(deviceNameBuffer,
  304. "\\Device\\CdRom%d",
  305. deviceExtension->CdRomDeviceNumber);
  306. RtlInitString(&deviceNameString,
  307. deviceNameBuffer);
  308. status = RtlAnsiStringToUnicodeString(&unicodeString,
  309. &deviceNameString,
  310. TRUE);
  311. if (!NT_SUCCESS(status)) {
  312. status = STATUS_INSUFFICIENT_RESOURCES;
  313. unicodeString.Buffer = NULL;
  314. }
  315. if (dosUnicodeString.Buffer != NULL && unicodeString.Buffer != NULL) {
  316. //
  317. // Link the ChangerName to the Underlying cdrom name.
  318. //
  319. IoCreateSymbolicLink(&dosUnicodeString, &unicodeString);
  320. }
  321. if (dosUnicodeString.Buffer != NULL) {
  322. RtlFreeUnicodeString(&dosUnicodeString);
  323. }
  324. if (unicodeString.Buffer != NULL ) {
  325. RtlFreeUnicodeString(&unicodeString);
  326. }
  327. if (NT_SUCCESS(status)) {
  328. ULONG length;
  329. ULONG slotCount;
  330. //
  331. // Get the inquiry data for the device.
  332. // The passThrough packet will be re-used throughout.
  333. // Ensure that the buffer is never larger than MAX_INQUIRY_DATA.
  334. //
  335. passThrough = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(PASS_THROUGH_REQUEST) + MAX_INQUIRY_DATA);
  336. if (!passThrough) {
  337. DebugPrint((1,
  338. "ChangerStartDevice: Insufficient resources for Inquiry request\n"));
  339. status = STATUS_INSUFFICIENT_RESOURCES;
  340. goto StartDeviceExit;
  341. }
  342. srb = &passThrough->Srb;
  343. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST) + MAX_INQUIRY_DATA);
  344. cdb = (PCDB)srb->Cdb;
  345. srb->TimeOutValue = 20;
  346. srb->CdbLength = CDB6GENERIC_LENGTH;
  347. srb->DataTransferLength = MAX_INQUIRY_DATA;
  348. //
  349. // Set CDB operation code.
  350. //
  351. cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
  352. //
  353. // Set allocation length to inquiry data buffer size.
  354. //
  355. cdb->CDB6INQUIRY.AllocationLength = MAX_INQUIRY_DATA;
  356. status = SendPassThrough(DeviceObject,
  357. passThrough);
  358. if (status == STATUS_DATA_OVERRUN) {
  359. status = STATUS_SUCCESS;
  360. }
  361. if (NT_SUCCESS(status)) {
  362. PINQUIRYDATA inquiryData;
  363. ULONG inquiryLength;
  364. //
  365. // Determine the actual inquiry data length.
  366. //
  367. inquiryData = (PINQUIRYDATA)passThrough->DataBuffer;
  368. inquiryLength = inquiryData->AdditionalLength + FIELD_OFFSET(INQUIRYDATA, Reserved);
  369. if (inquiryLength > srb->DataTransferLength) {
  370. inquiryLength = srb->DataTransferLength;
  371. }
  372. //
  373. // Copy to deviceExtension buffer.
  374. //
  375. RtlMoveMemory(&deviceExtension->InquiryData,
  376. inquiryData,
  377. inquiryLength);
  378. //
  379. // Assume atapi 2.5, unless it's one of the special drives.
  380. //
  381. deviceExtension->DeviceType = ATAPI_25;
  382. if (RtlCompareMemory(inquiryData->VendorId,"ALPS", 4) == 4) {
  383. //
  384. // Nominally supporting the spec. the discChanged bits are ALWAYS set
  385. // and DiscPresent is set if the cartridge has a tray, not necessarily
  386. // an actual disc in the tray.
  387. //
  388. deviceExtension->DeviceType = ALPS_25;
  389. } else if ((RtlCompareMemory(inquiryData->VendorId, "TORiSAN CD-ROM CDR-C", 20) == 20) ||
  390. (RtlCompareMemory(inquiryData->VendorId, "TORiSAN CD-ROM CDR_C", 20) == 20)) {
  391. deviceExtension->DeviceType = TORISAN;
  392. deviceExtension->NumberOfSlots = 3;
  393. status = STATUS_SUCCESS;
  394. }
  395. }
  396. if (deviceExtension->DeviceType != TORISAN) {
  397. //
  398. // Send an unload to ensure that the drive is empty.
  399. // The spec. specifically states that after HW initialization
  400. // slot0 is loaded. Good for unaware drivers, but the mech. status
  401. // will return that slot 0 has media, and a TUR will return that
  402. // the drive also has media.
  403. //
  404. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST));
  405. /*
  406. cdb = (PCDB)srb->Cdb;
  407. srb->CdbLength = CDB12GENERIC_LENGTH;
  408. srb->TimeOutValue = CDCHGR_TIMEOUT;
  409. srb->DataTransferLength = 0;
  410. cdb->LOAD_UNLOAD.OperationCode = SCSIOP_LOAD_UNLOAD_SLOT;
  411. cdb->LOAD_UNLOAD.Start = 0;
  412. cdb->LOAD_UNLOAD.LoadEject = 1;
  413. //
  414. // Send SCSI command (CDB) to device
  415. //
  416. status = SendPassThrough(DeviceObject,
  417. passThrough);
  418. if (!NT_SUCCESS(status)) {
  419. //
  420. // Ignore this error.
  421. //
  422. DebugPrint((1,
  423. "ChangerPnP - StartDevive: Unload slot0 failed. %lx\n",
  424. status));
  425. status = STATUS_SUCCESS;
  426. }
  427. */
  428. //
  429. // Now send and build a mech. status request to determine the
  430. // number of slots that the devices supports.
  431. //
  432. length = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
  433. length += (10 * sizeof(SLOT_TABLE_INFORMATION));
  434. //
  435. // Build srb and cdb.
  436. //
  437. srb = &passThrough->Srb;
  438. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST) + length);
  439. cdb = (PCDB)srb->Cdb;
  440. srb->CdbLength = CDB12GENERIC_LENGTH;
  441. srb->DataTransferLength = length;
  442. srb->TimeOutValue = 200;
  443. cdb->MECH_STATUS.OperationCode = SCSIOP_MECHANISM_STATUS;
  444. cdb->MECH_STATUS.AllocationLength[0] = (UCHAR)(length >> 8);
  445. cdb->MECH_STATUS.AllocationLength[1] = (UCHAR)(length & 0xFF);
  446. status = SendPassThrough(DeviceObject,
  447. passThrough);
  448. if (status == STATUS_DATA_OVERRUN) {
  449. status = STATUS_SUCCESS;
  450. }
  451. if (NT_SUCCESS(status)) {
  452. PMECHANICAL_STATUS_INFORMATION_HEADER statusHeader;
  453. PSLOT_TABLE_INFORMATION slotInfo;
  454. ULONG currentSlot;
  455. statusHeader = (PMECHANICAL_STATUS_INFORMATION_HEADER)
  456. passThrough->DataBuffer;
  457. slotCount = statusHeader->NumberAvailableSlots;
  458. DebugPrint((1,
  459. "ChangerPnP - StartDevice: Device has %x slots\n",
  460. slotCount));
  461. deviceExtension->NumberOfSlots = slotCount;
  462. }
  463. }
  464. if (NT_SUCCESS(status)) {
  465. KeInitializeEvent(&event,NotificationEvent,FALSE);
  466. //
  467. // Issue GET_ADDRESS Ioctl to determine path, target, and lun information.
  468. //
  469. irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_ADDRESS,
  470. deviceExtension->CdromTargetDeviceObject,
  471. NULL,
  472. 0,
  473. &deviceExtension->ScsiAddress,
  474. sizeof(SCSI_ADDRESS),
  475. FALSE,
  476. &event,
  477. &ioStatus);
  478. if (irp2 != NULL) {
  479. status = IoCallDriver(deviceExtension->CdromTargetDeviceObject, irp2);
  480. if (status == STATUS_PENDING) {
  481. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  482. status = ioStatus.Status;
  483. }
  484. if (NT_SUCCESS(status)) {
  485. DebugPrint((1,
  486. "GetAddress: Port %x, Path %x, Target %x, Lun %x\n",
  487. deviceExtension->ScsiAddress.PortNumber,
  488. deviceExtension->ScsiAddress.PathId,
  489. deviceExtension->ScsiAddress.TargetId,
  490. deviceExtension->ScsiAddress.Lun));
  491. if (deviceExtension->DeviceType != TORISAN) {
  492. //
  493. // Finally send a mode sense capabilities page to find out magazine size, etc.
  494. //
  495. length = sizeof(MODE_PARAMETER_HEADER10) + sizeof(CDVD_CAPABILITIES_PAGE);
  496. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST) + length);
  497. srb = &passThrough->Srb;
  498. cdb = (PCDB)srb->Cdb;
  499. srb->CdbLength = CDB10GENERIC_LENGTH;
  500. srb->DataTransferLength = length;
  501. srb->TimeOutValue = 20;
  502. cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  503. cdb->MODE_SENSE10.PageCode = MODE_PAGE_CAPABILITIES;
  504. cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(length >> 8);
  505. cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(length & 0xFF);
  506. status = SendPassThrough(DeviceObject,
  507. passThrough);
  508. if (status == STATUS_DATA_OVERRUN) {
  509. status = STATUS_SUCCESS;
  510. }
  511. if (NT_SUCCESS(status)) {
  512. PMODE_PARAMETER_HEADER10 modeHeader;
  513. PCDVD_CAPABILITIES_PAGE modePage;
  514. (ULONG_PTR)modeHeader = (ULONG_PTR)passThrough->DataBuffer;
  515. (ULONG_PTR)modePage = (ULONG_PTR)modeHeader;
  516. (ULONG_PTR)modePage += sizeof(MODE_PARAMETER_HEADER10);
  517. //
  518. // Determine whether this device uses a cartridge.
  519. //
  520. if ( modePage->LoadingMechanismType ==
  521. CDVD_LMT_CHANGER_CARTRIDGE ) {
  522. //
  523. // Mode data indicates a cartridge.
  524. //
  525. deviceExtension->MechType = 1;
  526. }
  527. DebugPrint((1,
  528. "ChangerStartDevice: Cartridge? %x\n",
  529. deviceExtension->MechType));
  530. goto StartDeviceExit;
  531. } else {
  532. goto StartDeviceExit;
  533. }
  534. } else {
  535. //
  536. // Torisans have a cartridge, not ind. slots.
  537. //
  538. deviceExtension->MechType = 1;
  539. goto StartDeviceExit;
  540. }
  541. } else {
  542. DebugPrint((1,
  543. "ChangerStartDevice: GetAddress of Cdrom%x failed. Status %lx\n",
  544. deviceExtension->CdRomDeviceNumber,
  545. status));
  546. goto StartDeviceExit;
  547. }
  548. } else {
  549. status = STATUS_INSUFFICIENT_RESOURCES;
  550. }
  551. } else {
  552. DebugPrint((1,
  553. "ChangerPnP - StartDevice: Mechanism status failed %lx.\n",
  554. status));
  555. //
  556. // Fall through.
  557. //
  558. }
  559. }
  560. StartDeviceExit:
  561. if (passThrough) {
  562. ExFreePool(passThrough);
  563. }
  564. if (NT_SUCCESS(status)) {
  565. if (!deviceExtension->InterfaceStateSet) {
  566. status = IoSetDeviceInterfaceState(&(deviceExtension->InterfaceName),
  567. TRUE);
  568. deviceExtension->InterfaceStateSet = TRUE;
  569. }
  570. Irp->IoStatus.Status = STATUS_SUCCESS;
  571. return STATUS_SUCCESS;
  572. } else {
  573. Irp->IoStatus.Status = status;
  574. return status;
  575. }
  576. }
  577. NTSTATUS
  578. ChangerPnp(
  579. IN PDEVICE_OBJECT DeviceObject,
  580. IN PIRP Irp
  581. )
  582. /*++
  583. Routine Description:
  584. Dispatch for PNP
  585. Arguments:
  586. DeviceObject - Supplies the device object.
  587. Irp - Supplies the I/O request packet.
  588. Return Value:
  589. NTSTATUS
  590. --*/
  591. {
  592. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  593. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  594. CCHAR dosNameBuffer[64];
  595. STRING dosString;
  596. UNICODE_STRING dosUnicodeString;
  597. NTSTATUS status;
  598. KEVENT event;
  599. DebugPrint((2,
  600. "ChangerPnP\n"));
  601. switch (irpStack->MinorFunction) {
  602. case IRP_MN_START_DEVICE: {
  603. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  604. IoCopyCurrentIrpStackLocationToNext(Irp);
  605. IoSetCompletionRoutine( Irp,
  606. ChgrCompletion,
  607. &event,
  608. TRUE,
  609. TRUE,
  610. TRUE);
  611. status = IoCallDriver(deviceExtension->CdromTargetDeviceObject, Irp);
  612. KeWaitForSingleObject(&event,
  613. Executive,
  614. KernelMode,
  615. FALSE,
  616. NULL);
  617. if(!NT_SUCCESS(Irp->IoStatus.Status)) {
  618. //
  619. // Cdrom failed to start. Bail now.
  620. //
  621. status = Irp->IoStatus.Status;
  622. } else {
  623. status = ChangerStartDevice(DeviceObject,
  624. Irp);
  625. }
  626. break;
  627. }
  628. case IRP_MN_REMOVE_DEVICE: {
  629. //
  630. // IoDelete fake dev. obj
  631. //
  632. status = IoSetDeviceInterfaceState(&(deviceExtension->InterfaceName),
  633. FALSE);
  634. deviceExtension->InterfaceStateSet = FALSE;
  635. RtlFreeUnicodeString(&(deviceExtension->InterfaceName));
  636. //
  637. // Poison it.
  638. //
  639. RtlInitUnicodeString(&(deviceExtension->InterfaceName), NULL);
  640. //
  641. // Delete the symbolic link "CdChangerN".
  642. //
  643. sprintf(dosNameBuffer,
  644. "\\DosDevices\\CdChanger%d",
  645. deviceExtension->CdRomDeviceNumber);
  646. RtlInitString(&dosString, dosNameBuffer);
  647. status = RtlAnsiStringToUnicodeString(&dosUnicodeString,
  648. &dosString,
  649. TRUE);
  650. ASSERT(NT_SUCCESS(status));
  651. if (dosUnicodeString.Buffer != NULL) {
  652. status = IoDeleteSymbolicLink(&dosUnicodeString);
  653. RtlFreeUnicodeString(&dosUnicodeString);
  654. }
  655. IoDetachDevice(deviceExtension->CdromTargetDeviceObject);
  656. return ChangerSendToNextDriver(DeviceObject, Irp);
  657. break;
  658. }
  659. case IRP_MN_DEVICE_USAGE_NOTIFICATION: {
  660. ULONG count;
  661. BOOLEAN setPagable;
  662. if (irpStack->Parameters.UsageNotification.Type != DeviceUsageTypePaging) {
  663. status = ChangerSendToNextDriver(DeviceObject, Irp);
  664. break; // out of case statement
  665. }
  666. //
  667. // wait on the paging path event
  668. //
  669. status = KeWaitForSingleObject(&deviceExtension->PagingPathCountEvent,
  670. Executive, KernelMode,
  671. FALSE, NULL);
  672. //
  673. // if removing last paging device, need to set DO_POWER_PAGABLE
  674. // bit here, and possible re-set it below on failure.
  675. //
  676. setPagable = FALSE;
  677. if (!irpStack->Parameters.UsageNotification.InPath &&
  678. deviceExtension->PagingPathCount == 1 ) {
  679. //
  680. // removing the last paging file.
  681. // must have DO_POWER_PAGABLE bits set
  682. //
  683. if (DeviceObject->Flags & DO_POWER_INRUSH) {
  684. DebugPrint((2, "ChangerPnp: last paging file removed "
  685. "bug DO_POWER_INRUSH set, so not setting "
  686. "DO_POWER_PAGABLE bit for DO %p\n",
  687. DeviceObject));
  688. } else {
  689. DebugPrint((2, "ChangerPnp: Setting PAGABLE "
  690. "bit for DO %p\n", DeviceObject));
  691. DeviceObject->Flags |= DO_POWER_PAGABLE;
  692. setPagable = TRUE;
  693. }
  694. }
  695. //
  696. // send the irp synchronously
  697. //
  698. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  699. IoCopyCurrentIrpStackLocationToNext(Irp);
  700. IoSetCompletionRoutine( Irp, ChgrCompletion,
  701. &event, TRUE, TRUE, TRUE);
  702. status = IoCallDriver(deviceExtension->CdromTargetDeviceObject, Irp);
  703. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  704. status = Irp->IoStatus.Status;
  705. //
  706. // now deal with the failure and success cases.
  707. // note that we are not allowed to fail the irp
  708. // once it is sent to the lower drivers.
  709. //
  710. if (NT_SUCCESS(status)) {
  711. IoAdjustPagingPathCount(
  712. &deviceExtension->PagingPathCount,
  713. irpStack->Parameters.UsageNotification.InPath);
  714. if (irpStack->Parameters.UsageNotification.InPath) {
  715. if (deviceExtension->PagingPathCount == 1) {
  716. DebugPrint((2, "ChangerPnp: Clearing PAGABLE bit "
  717. "for DO %p\n", DeviceObject));
  718. DeviceObject->Flags &= ~DO_POWER_PAGABLE;
  719. }
  720. }
  721. } else {
  722. if (setPagable == TRUE) {
  723. DeviceObject->Flags &= ~DO_POWER_PAGABLE;
  724. setPagable = FALSE;
  725. }
  726. }
  727. //
  728. // set the event so the next one can occur.
  729. //
  730. KeSetEvent(&deviceExtension->PagingPathCountEvent,
  731. IO_NO_INCREMENT, FALSE);
  732. break;
  733. }
  734. default:
  735. return ChangerSendToNextDriver(DeviceObject, Irp);
  736. }
  737. Irp->IoStatus.Status = status;
  738. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  739. return status;
  740. } // end ChangerPnp()
  741. NTSTATUS
  742. ChangerSendToNextDriver(
  743. IN PDEVICE_OBJECT DeviceObject,
  744. IN PIRP Irp
  745. )
  746. /*++
  747. Routine Description:
  748. This routine sends the Irp to the next driver in line
  749. when the Irp is not processed by this driver.
  750. Arguments:
  751. DeviceObject
  752. Irp
  753. Return Value:
  754. NTSTATUS
  755. --*/
  756. {
  757. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  758. DebugPrint((2,
  759. "ChangerSendToNextDriver\n"));
  760. IoSkipCurrentIrpStackLocation(Irp);
  761. return IoCallDriver(deviceExtension->CdromTargetDeviceObject, Irp);
  762. } // end ChangerSendToNextDriver()
  763. NTSTATUS
  764. ChangerPower(
  765. IN PDEVICE_OBJECT DeviceObject,
  766. IN PIRP Irp
  767. )
  768. {
  769. PDEVICE_EXTENSION deviceExtension;
  770. PoStartNextPowerIrp(Irp);
  771. IoSkipCurrentIrpStackLocation(Irp);
  772. deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  773. return PoCallDriver(deviceExtension->CdromTargetDeviceObject, Irp);
  774. }
  775. NTSTATUS
  776. ChangerDeviceControl(
  777. PDEVICE_OBJECT DeviceObject,
  778. PIRP Irp
  779. )
  780. /*++
  781. Routine Description:
  782. This routine handles the medium changer ioctls, and
  783. passes down most cdrom ioctls to the target device.
  784. Arguments:
  785. DeviceObject
  786. Irp
  787. Return Value:
  788. Status is returned.
  789. --*/
  790. {
  791. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  792. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  793. NTSTATUS status = STATUS_SUCCESS;
  794. DebugPrint((2,
  795. "ChangerDeviceControl\n"));
  796. if (ChgrIoctl(irpStack->Parameters.DeviceIoControl.IoControlCode)) {
  797. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  798. case IOCTL_CHANGER_GET_STATUS:
  799. DebugPrint((2,
  800. "CdChgrDeviceControl: IOCTL_CHANGER_GET_STATUS\n"));
  801. status = ChgrGetStatus(DeviceObject, Irp);
  802. break;
  803. case IOCTL_CHANGER_GET_PARAMETERS:
  804. DebugPrint((2,
  805. "CdChgrDeviceControl: IOCTL_CHANGER_GET_PARAMETERS\n"));
  806. //
  807. // Validate buffer length.
  808. //
  809. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  810. sizeof(GET_CHANGER_PARAMETERS)) {
  811. status = STATUS_INFO_LENGTH_MISMATCH;
  812. } else {
  813. status = ChgrGetParameters(DeviceObject, Irp);
  814. }
  815. break;
  816. case IOCTL_CHANGER_GET_PRODUCT_DATA:
  817. DebugPrint((2,
  818. "CdChgrDeviceControl: IOCTL_CHANGER_GET_PRODUCT_DATA\n"));
  819. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  820. sizeof(CHANGER_PRODUCT_DATA)) {
  821. status = STATUS_INFO_LENGTH_MISMATCH;
  822. } else {
  823. status = ChgrGetProductData(DeviceObject, Irp);
  824. }
  825. break;
  826. case IOCTL_CHANGER_SET_ACCESS:
  827. DebugPrint((2,
  828. "CdChgrDeviceControl: IOCTL_CHANGER_SET_ACCESS\n"));
  829. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  830. sizeof(CHANGER_SET_ACCESS)) {
  831. status = STATUS_INFO_LENGTH_MISMATCH;
  832. } else if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  833. sizeof(CHANGER_SET_ACCESS)) {
  834. status = STATUS_INFO_LENGTH_MISMATCH;
  835. } else {
  836. status = ChgrSetAccess(DeviceObject, Irp);
  837. }
  838. break;
  839. case IOCTL_CHANGER_GET_ELEMENT_STATUS:
  840. DebugPrint((2,
  841. "CdChgrDeviceControl: IOCTL_CHANGER_GET_ELEMENT_STATUS\n"));
  842. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  843. sizeof(CHANGER_READ_ELEMENT_STATUS)) {
  844. status = STATUS_INFO_LENGTH_MISMATCH;
  845. } else {
  846. status = ChgrGetElementStatus(DeviceObject, Irp);
  847. }
  848. break;
  849. case IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS:
  850. DebugPrint((2,
  851. "CdChgrDeviceControl: IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS\n"));
  852. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  853. sizeof(CHANGER_INITIALIZE_ELEMENT_STATUS)) {
  854. status = STATUS_INFO_LENGTH_MISMATCH;
  855. } else {
  856. status = ChgrInitializeElementStatus(DeviceObject, Irp);
  857. }
  858. break;
  859. case IOCTL_CHANGER_SET_POSITION:
  860. DebugPrint((2,
  861. "CdChgrDeviceControl: IOCTL_CHANGER_SET_POSITION\n"));
  862. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  863. sizeof(CHANGER_SET_POSITION)) {
  864. status = STATUS_INFO_LENGTH_MISMATCH;
  865. } else {
  866. status = ChgrSetPosition(DeviceObject, Irp);
  867. }
  868. break;
  869. case IOCTL_CHANGER_EXCHANGE_MEDIUM:
  870. DebugPrint((2,
  871. "CdChgrDeviceControl: IOCTL_CHANGER_EXCHANGE_MEDIUM\n"));
  872. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  873. sizeof(CHANGER_EXCHANGE_MEDIUM)) {
  874. status = STATUS_INFO_LENGTH_MISMATCH;
  875. } else {
  876. status = ChgrExchangeMedium(DeviceObject, Irp);
  877. }
  878. break;
  879. case IOCTL_CHANGER_MOVE_MEDIUM:
  880. DebugPrint((2,
  881. "CdChgrDeviceControl: IOCTL_CHANGER_MOVE_MEDIUM\n"));
  882. //if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  883. // sizeof(CHANGER_MOVE_MEDIUM)) {
  884. // status = STATUS_INFO_LENGTH_MISMATCH;
  885. //} else
  886. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  887. sizeof(CHANGER_MOVE_MEDIUM)) {
  888. status = STATUS_INFO_LENGTH_MISMATCH;
  889. } else {
  890. status = ChgrMoveMedium(DeviceObject, Irp);
  891. }
  892. break;
  893. case IOCTL_CHANGER_REINITIALIZE_TRANSPORT:
  894. DebugPrint((2,
  895. "CdChgrDeviceControl: IOCTL_CHANGER_REINITIALIZE_TRANSPORT\n"));
  896. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  897. sizeof(CHANGER_ELEMENT)) {
  898. status = STATUS_INFO_LENGTH_MISMATCH;
  899. } else {
  900. status = ChgrReinitializeUnit(DeviceObject, Irp);
  901. }
  902. break;
  903. case IOCTL_CHANGER_QUERY_VOLUME_TAGS:
  904. DebugPrint((2,
  905. "CdChgrDeviceControl: IOCTL_CHANGER_QUERY_VOLUME_TAGS\n"));
  906. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  907. sizeof(CHANGER_SEND_VOLUME_TAG_INFORMATION)) {
  908. status = STATUS_INFO_LENGTH_MISMATCH;
  909. } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  910. sizeof(READ_ELEMENT_ADDRESS_INFO)) {
  911. status = STATUS_INFO_LENGTH_MISMATCH;
  912. } else {
  913. status = ChgrQueryVolumeTags(DeviceObject, Irp);
  914. }
  915. break;
  916. default:
  917. DebugPrint((1,
  918. "CdChgrDeviceControl: Unhandled IOCTL\n"));
  919. //
  920. // Set current stack back one.
  921. //
  922. Irp->CurrentLocation++,
  923. Irp->Tail.Overlay.CurrentStackLocation++;
  924. //
  925. // Pass unrecognized device control requests
  926. // down to next driver layer.
  927. //
  928. return IoCallDriver(deviceExtension->CdromTargetDeviceObject, Irp);
  929. }
  930. } else {
  931. if (deviceExtension->DeviceType == TORISAN) {
  932. ULONG ioctlCode;
  933. ULONG baseCode;
  934. ULONG functionCode;
  935. ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
  936. baseCode = ioctlCode >> 16;
  937. functionCode = (ioctlCode & (~0xffffc003)) >> 2;
  938. if((functionCode >= 0x200) && (functionCode <= 0x300)) {
  939. ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE, 0, 0, 0);
  940. }
  941. if ((ioctlCode == IOCTL_CDROM_CHECK_VERIFY) || (ioctlCode == IOCTL_STORAGE_GET_MEDIA_TYPES_EX)) {
  942. if (ioctlCode == IOCTL_CDROM_CHECK_VERIFY) {
  943. //
  944. // The fine torisan drives overload TUR as a method to switch platters. Have to send this down via passthrough with the
  945. // appropriate bits set.
  946. //
  947. status = SendTorisanCheckVerify(DeviceObject, Irp);
  948. } else if (ioctlCode == IOCTL_STORAGE_GET_MEDIA_TYPES_EX) {
  949. PGET_MEDIA_TYPES mediaTypes = Irp->AssociatedIrp.SystemBuffer;
  950. PDEVICE_MEDIA_INFO mediaInfo = &mediaTypes->MediaInfo[0];
  951. DebugPrint((1,
  952. "ChangerDeviceControl: GET_MEDIA_TYPES\n"));
  953. //
  954. // Yet another case of having to workaround this design. Media types requires knowing if
  955. // media is present. As the cdrom driver will send a TUR, this will always switch to the first
  956. // platter. So fake it here.
  957. //
  958. //
  959. // Ensure that buffer is large enough.
  960. //
  961. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  962. sizeof(GET_MEDIA_TYPES)) {
  963. //
  964. // Buffer too small.
  965. //
  966. Irp->IoStatus.Information = 0;
  967. status = STATUS_INFO_LENGTH_MISMATCH;
  968. } else {
  969. //
  970. // Set the type.
  971. //
  972. mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = CD_ROM;
  973. mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
  974. mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_ONLY;
  975. mediaTypes->DeviceType = FILE_DEVICE_CD_ROM;
  976. mediaTypes->MediaInfoCount = 1;
  977. status = SendTorisanCheckVerify(DeviceObject, Irp);
  978. if (NT_SUCCESS(status)) {
  979. mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics |= MEDIA_CURRENTLY_MOUNTED;
  980. }
  981. //todo issue IOCTL_CDROM_GET_DRIVE_GEOMETRY to fill in the geom. information.
  982. mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = 2048;
  983. Irp->IoStatus.Information = sizeof(GET_MEDIA_TYPES);
  984. status = STATUS_SUCCESS;
  985. }
  986. }
  987. } else {
  988. DebugPrint((1,
  989. "CdChgrDeviceControl: Unhandled IOCTL\n"));
  990. //
  991. // Set current stack back one.
  992. //
  993. Irp->CurrentLocation++,
  994. Irp->Tail.Overlay.CurrentStackLocation++;
  995. //
  996. // Pass unrecognized device control requests
  997. // down to next driver layer.
  998. //
  999. return IoCallDriver(deviceExtension->CdromTargetDeviceObject, Irp);
  1000. }
  1001. } else {
  1002. status = STATUS_SUCCESS;
  1003. if (deviceExtension->CdromTargetDeviceObject->Flags & DO_VERIFY_VOLUME) {
  1004. DebugPrint((1,
  1005. "ChangerDeviceControl: Volume needs to be verified\n"));
  1006. if (!(irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
  1007. status = STATUS_VERIFY_REQUIRED;
  1008. }
  1009. }
  1010. if (NT_SUCCESS(status)) {
  1011. //
  1012. // Set current stack back one.
  1013. //
  1014. Irp->CurrentLocation++,
  1015. Irp->Tail.Overlay.CurrentStackLocation++;
  1016. //
  1017. // Pass unrecognized device control requests
  1018. // down to next driver layer.
  1019. //
  1020. return IoCallDriver(deviceExtension->CdromTargetDeviceObject, Irp);
  1021. }
  1022. }
  1023. }
  1024. Irp->IoStatus.Status = status;
  1025. if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
  1026. DebugPrint((1,
  1027. "Mcd.ChangerDeviceControl: IOCTL %x, status %lx\n",
  1028. irpStack->Parameters.DeviceIoControl.IoControlCode,
  1029. status));
  1030. IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
  1031. }
  1032. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1033. return status;
  1034. } // end ChangerDeviceControl()
  1035. NTSTATUS
  1036. ChangerPassThrough(
  1037. IN PDEVICE_OBJECT DeviceObject,
  1038. IN PIRP Irp
  1039. )
  1040. /*++
  1041. Routine Description:
  1042. Arguments:
  1043. DeviceObject - Supplies the device object.
  1044. Irp - Supplies the IO request packet.
  1045. Return Value:
  1046. NTSTATUS
  1047. --*/
  1048. {
  1049. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1050. DebugPrint((2,
  1051. "ChangerPassThrough\n"));
  1052. IoSkipCurrentIrpStackLocation(Irp);
  1053. return IoCallDriver(deviceExtension->CdromTargetDeviceObject, Irp);
  1054. }
  1055. VOID
  1056. ChangerUnload(
  1057. IN PDRIVER_OBJECT DriverObject
  1058. )
  1059. /*++
  1060. Routine Description:
  1061. Free all the allocated resources, etc.
  1062. Arguments:
  1063. DriverObject - pointer to a driver object.
  1064. Return Value:
  1065. VOID.
  1066. --*/
  1067. {
  1068. DebugPrint((1,
  1069. "ChangerUnload\n"));
  1070. return;
  1071. }
  1072. #if DBG
  1073. ULONG ChgrDebugLevel = 0;
  1074. UCHAR DebugBuffer[128];
  1075. #endif
  1076. #if DBG
  1077. VOID
  1078. ChgrDebugPrint(
  1079. ULONG DebugPrintLevel,
  1080. PCCHAR DebugMessage,
  1081. ...
  1082. )
  1083. /*++
  1084. Routine Description:
  1085. Debug print for all medium changer drivers
  1086. Arguments:
  1087. Debug print level between 0 and 3, with 3 being the most verbose.
  1088. Return Value:
  1089. None
  1090. --*/
  1091. {
  1092. va_list ap;
  1093. va_start(ap, DebugMessage);
  1094. if (DebugPrintLevel <= ChgrDebugLevel) {
  1095. vsprintf(DebugBuffer, DebugMessage, ap);
  1096. DbgPrint(DebugBuffer);
  1097. }
  1098. va_end(ap);
  1099. } // end ChgrDebugPrint()
  1100. #else
  1101. //
  1102. // DebugPrint stub
  1103. //
  1104. VOID
  1105. ChgrDebugPrint(
  1106. ULONG DebugPrintLevel,
  1107. PCCHAR DebugMessage,
  1108. ...
  1109. )
  1110. {
  1111. }
  1112. #endif