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.

1896 lines
67 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Copyright (c) 1996 Intel Corporation
  4. Module Name:
  5. Sample.c
  6. Abstract:
  7. USB device driver for Sample USB Device
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  12. KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  13. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  14. PURPOSE.
  15. Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  16. Copyright (c) 1996 Intel Corporation All Rights Reserved.
  17. Revision History:
  18. 8-15-96: Version 1.0 Kosar Jaff
  19. Created
  20. 10-20-96: Version 1.1 Kosar Jaff
  21. Added changes to support new PnP IOCTLs
  22. 11-29-96: Version 1.2 Kosar Jaff
  23. Added support for IOCTLs from companion Sample Application
  24. 12-10-96: Version 1.3 Kosar Jaff
  25. Added Bulk Write/Read functions and corresponding IOCTLs
  26. Cleaned up device removal code
  27. 01-08-97: Version 1.4 Kosar Jaff
  28. Changed IoAttachDeviceByPointer (obsolete) to IoAttachDeviceToDeviceStack
  29. Cleaned up comments
  30. --*/
  31. #define DRIVER
  32. /*
  33. // Include files needed for WDM driver support
  34. */
  35. #include <wdm.h>
  36. #include "stdarg.h"
  37. #include "stdio.h"
  38. /*
  39. // Include files needed for USB support
  40. */
  41. #include "usbdi.h"
  42. #include "usbdlib.h"
  43. #include "usb.h"
  44. /*
  45. // Include file for the Sample Device
  46. */
  47. #include "Sample.h"
  48. #define DEADMAN_TIMEOUT 5000 //timeout in ms; we use a 5 second timeout
  49. NTSTATUS
  50. DriverEntry(
  51. IN PDRIVER_OBJECT DriverObject,
  52. IN PUNICODE_STRING RegistryPath
  53. )
  54. /*++
  55. Routine Description:
  56. Installable driver initialization entry point.
  57. This is where the driver is called when the driver is being loaded
  58. by the I/O system. This entry point is called directly by the I/O system.
  59. Arguments:
  60. DriverObject - pointer to the driver object
  61. RegistryPath - pointer to a unicode string representing the path
  62. to driver-specific key in the registry
  63. Return Value:
  64. STATUS_SUCCESS if successful,
  65. STATUS_UNSUCCESSFUL otherwise
  66. --*/
  67. {
  68. NTSTATUS ntStatus = STATUS_SUCCESS;
  69. PDEVICE_OBJECT deviceObject = NULL;
  70. Sample_KdPrint (("entering (Sample) DriverEntry (Build: %s/%s\n",__DATE__,__TIME__));
  71. /*
  72. // Create dispatch points for the various events handled by this
  73. // driver. For example, device I/O control calls (e.g., when a Win32
  74. // application calls the DeviceIoControl function) will be dispatched to
  75. // routine specified below in the IRP_MJ_DEVICE_CONTROL case.
  76. //
  77. // For more information about the IRP_XX_YYYY codes, please consult the
  78. // Windows NT DDK documentation.
  79. //
  80. */
  81. DriverObject->MajorFunction[IRP_MJ_CREATE] = Sample_Create;
  82. DriverObject->MajorFunction[IRP_MJ_CLOSE] = Sample_Create;
  83. DriverObject->DriverUnload = Sample_Unload;
  84. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Sample_ProcessIOCTL;
  85. DriverObject->MajorFunction[IRP_MJ_PNP] = Sample_Dispatch;
  86. DriverObject->MajorFunction[IRP_MJ_POWER] = Sample_Dispatch;
  87. DriverObject->DriverExtension->AddDevice = Sample_PnPAddDevice;
  88. Sample_KdPrint (("exiting (Sample) DriverEntry (%x)\n", ntStatus));
  89. return ntStatus;
  90. }
  91. NTSTATUS
  92. Sample_Dispatch(
  93. IN PDEVICE_OBJECT DeviceObject,
  94. IN PIRP Irp
  95. )
  96. /*++
  97. Routine Description:
  98. Process the IRPs sent to this device.
  99. Arguments:
  100. DeviceObject - pointer to a device object
  101. Irp - pointer to an I/O Request Packet
  102. Return Value:
  103. NTSTATUS
  104. --*/
  105. {
  106. PIO_STACK_LOCATION irpStack, nextStack;
  107. PDEVICE_EXTENSION deviceExtension;
  108. NTSTATUS ntStatus;
  109. Irp->IoStatus.Status = STATUS_SUCCESS;
  110. Irp->IoStatus.Information = 0;
  111. /*
  112. // Get a pointer to the current location in the Irp. This is where
  113. // the function codes and parameters are located.
  114. */
  115. irpStack = IoGetCurrentIrpStackLocation (Irp);
  116. /*
  117. // Get a pointer to the device extension
  118. */
  119. deviceExtension = DeviceObject->DeviceExtension;
  120. switch (irpStack->MajorFunction) {
  121. case IRP_MJ_PNP:
  122. /*
  123. //
  124. // This IRP is for Plug and Play and Power Management messages for your device.
  125. //
  126. // When your device is first installed, the port on the hub to which it
  127. // is attached is powered on and the USB software subsystem does some
  128. // minimal querying of the device. After the USB subsystem is done with that
  129. // basic communication, (the device ID has been determined, and the device
  130. // has been given a unique USB bus address), it is considered "powered" by
  131. // the system. The IRP's minor code gives more information about the power event.
  132. //
  133. // Similarly, when the USB device is being removed from the system, the Plug
  134. // and Play subsystem and the USB software stack interact to notify the
  135. // appropriate driver using this same IRP code, although in this case the
  136. // minor code gives more information about the exact power event.
  137. //
  138. */
  139. Sample_KdPrint (("IRP_MJ_PNP\n"));
  140. switch (irpStack->MinorFunction) {
  141. case IRP_MN_START_DEVICE:
  142. Sample_KdPrint (("IRP_MN_START_DEVICE\n"));
  143. /*
  144. // We pass the Irp down to the underlying PDO first since that driver
  145. // may have some configuration work to do before we can control the device
  146. */
  147. nextStack = IoGetNextIrpStackLocation(Irp);
  148. ASSERT(nextStack != NULL);
  149. RtlCopyMemory(nextStack, irpStack, sizeof(IO_STACK_LOCATION));
  150. Sample_KdPrint (("Passing START_DEVICE Irp down\n"));
  151. ntStatus = IoCallDriver(deviceExtension->StackDeviceObject, Irp);
  152. Sample_KdPrint (("Back from passing START_DEVICE Irp down; status: %#X\n", ntStatus));
  153. // Now we can begin our configuration actions on the device
  154. ntStatus = Sample_StartDevice(DeviceObject);
  155. break; //IRP_MN_START_DEVICE
  156. case IRP_MN_STOP_DEVICE:
  157. Sample_KdPrint (("IRP_MN_STOP_DEVICE\n"));
  158. Sample_Cleanup (DeviceObject);
  159. ntStatus = Sample_StopDevice(DeviceObject);
  160. break; //IRP_MN_STOP_DEVICE
  161. case IRP_MN_REMOVE_DEVICE:
  162. /*
  163. // Note: This IRP handler will change slightly in future revisions of this
  164. // sample driver. Please watch this space for updates.
  165. */
  166. Sample_KdPrint (("IRP_MN_REMOVE_DEVICE\n"))
  167. Sample_Cleanup (DeviceObject);
  168. ntStatus = Sample_RemoveDevice(DeviceObject);
  169. /*
  170. // Delete the link to the Stack Device Object, and delete the
  171. // Functional Device Object we created
  172. */
  173. IoDetachDevice(deviceExtension->StackDeviceObject);
  174. IoDeleteDevice (DeviceObject);
  175. break; //IRP_MN_REMOVE_DEVICE
  176. case IRP_MN_QUERY_STOP_DEVICE:
  177. Sample_KdPrint (("IRP_MN_QUERY_STOP_DEVICE\n"));
  178. break;
  179. case IRP_MN_QUERY_REMOVE_DEVICE:
  180. Sample_KdPrint (("IRP_MN_QUERY_REMOVE_DEVICE\n"));
  181. break;
  182. case IRP_MN_CANCEL_STOP_DEVICE:
  183. Sample_KdPrint (("IRP_MN_CANCEL_STOP_DEVICE\n"));
  184. break;
  185. case IRP_MN_CANCEL_REMOVE_DEVICE:
  186. Sample_KdPrint (("IRP_MN_CANCEL_REMOVE_DEVICE\n"));
  187. break;
  188. default:
  189. // A PnP Minor Function was not handled
  190. Sample_KdPrint (("PnP IOCTL not handled\n"));
  191. } /* switch MinorFunction*/
  192. nextStack = IoGetNextIrpStackLocation(Irp);
  193. ASSERT(nextStack != NULL);
  194. RtlCopyMemory(nextStack, irpStack, sizeof(IO_STACK_LOCATION));
  195. /*
  196. // All PNP_POWER messages get passed to the StackDeviceObject that
  197. // we were given in PnPAddDevice.
  198. //
  199. // This stack device object is managed by the USB software subsystem,
  200. // and so this IRP must be propagated to the owning device driver for
  201. // that stack device object, so that driver in turn can perform any
  202. // device state management (e.g., remove its device object, etc.).
  203. */
  204. Sample_KdPrint (("Passing PnP Irp down, status = %x\n", ntStatus));
  205. ntStatus = IoCallDriver(deviceExtension->StackDeviceObject, Irp);
  206. /*
  207. // If lower layer driver marked the Irp as pending then reflect that by
  208. // calling IoMarkIrpPending.
  209. */
  210. if (ntStatus == STATUS_PENDING) {
  211. IoMarkIrpPending(Irp);
  212. Sample_KdPrint (("PnP Irp came back with STATUS_PENDING (%x)\n", ntStatus));
  213. } else {
  214. Sample_KdPrint (("PnP Irp came back, status = %x\n", ntStatus));
  215. } // if ntStatus is PENDING
  216. goto Sample_Dispatch_Done;
  217. break; //IRP_MJ_PNP_POWER
  218. case IRP_MJ_POWER:
  219. /*
  220. //
  221. // This IRP is for Plug and Play and Power Management messages for your device.
  222. //
  223. // When your device is first installed, the port on the hub to which it
  224. // is attached is powered on and the USB software subsystem does some
  225. // minimal querying of the device. After the USB subsystem is done with that
  226. // basic communication, (the device ID has been determined, and the device
  227. // has been given a unique USB bus address), it is considered "powered" by
  228. // the system. The IRP's minor code gives more information about the power event.
  229. //
  230. // Similarly, when the USB device is being removed from the system, the Plug
  231. // and Play subsystem and the USB software stack interact to notify the
  232. // appropriate driver using this same IRP code, although in this case the
  233. // minor code gives more information about the exact power event.
  234. //
  235. */
  236. Sample_KdPrint (("IRP_MJ_POWER\n"));
  237. switch (irpStack->MinorFunction) {
  238. case IRP_MN_SET_POWER:
  239. switch (irpStack->Parameters.Power.Type) {
  240. case SystemPowerState:
  241. break; //SystemPowerState
  242. case DevicePowerState:
  243. switch (irpStack->Parameters.Power.State.DeviceState) {
  244. case PowerDeviceD3:
  245. Sample_KdPrint (("IRP_MN_SET_D3\n"));
  246. break;
  247. case PowerDeviceD2:
  248. Sample_KdPrint (("IRP_MN_SET_D2\n"));
  249. break;
  250. case PowerDeviceD1:
  251. Sample_KdPrint (("IRP_MN_SET_D1\n"));
  252. break;
  253. case PowerDeviceD0:
  254. Sample_KdPrint (("IRP_MN_SET_D0\n"));
  255. break;
  256. } // switch on Power.State.DeviceState
  257. break; //DevicePowerState
  258. }// switch on Power.Type
  259. break; //IRP_MN_SET_POWER
  260. case IRP_MN_QUERY_POWER:
  261. // Look at what type of power query this is
  262. switch (irpStack->Parameters.Power.Type) {
  263. case SystemPowerState:
  264. break; //SystemPowerState
  265. case DevicePowerState:
  266. switch (irpStack->Parameters.Power.State.DeviceState) {
  267. case PowerDeviceD2:
  268. Sample_KdPrint (("IRP_MN_QUERY_D2\n"));
  269. break;
  270. case PowerDeviceD1:
  271. Sample_KdPrint (("IRP_MN_QUERY_D1\n"));
  272. break;
  273. case PowerDeviceD3:
  274. Sample_KdPrint (("IRP_MN_QUERY_D3\n"));
  275. break;
  276. } //switch on Power.State.DeviceState
  277. break; //DevicePowerState
  278. }//switch on Power.Type
  279. break; //IRP_MN_QUERY_POWER
  280. default:
  281. // A PnP Minor Function was not handled
  282. Sample_KdPrint (("Power IOCTL not handled\n"));
  283. } /* switch MinorFunction*/
  284. nextStack = IoGetNextIrpStackLocation(Irp);
  285. ASSERT(nextStack != NULL);
  286. RtlCopyMemory(nextStack, irpStack, sizeof(IO_STACK_LOCATION));
  287. /*
  288. // All PNP_POWER messages get passed to the StackDeviceObject that
  289. // we were given in PnPAddDevice.
  290. //
  291. // This stack device object is managed by the USB software subsystem,
  292. // and so this IRP must be propagated to the owning device driver for
  293. // that stack device object, so that driver in turn can perform any
  294. // device state management (e.g., remove its device object, etc.).
  295. */
  296. Sample_KdPrint (("Passing Power Irp down, status = %x\n", ntStatus));
  297. ntStatus = IoCallDriver(deviceExtension->StackDeviceObject, Irp);
  298. /*
  299. // If lower layer driver marked the Irp as pending then reflect that by
  300. // calling IoMarkIrpPending.
  301. */
  302. if (ntStatus == STATUS_PENDING) {
  303. IoMarkIrpPending(Irp);
  304. Sample_KdPrint (("Power Irp came back with STATUS_PENDING (%x)\n", ntStatus));
  305. } else {
  306. Sample_KdPrint (("Power Irp came back, status = %x\n", ntStatus));
  307. } // if ntStatus is PENDING
  308. goto Sample_Dispatch_Done;
  309. break; //IRP_MJ_POWER
  310. default:
  311. Sample_KdPrint (("A MAJOR IOCTL Code was not handled: %#X\n",
  312. irpStack->MajorFunction));
  313. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  314. } /* switch MajorFunction */
  315. ntStatus = Irp->IoStatus.Status;
  316. IoCompleteRequest (Irp,
  317. IO_NO_INCREMENT
  318. );
  319. Sample_Dispatch_Done:
  320. Sample_KdPrint (("Exit Sample_Dispatch %x\n", ntStatus));
  321. return ntStatus;
  322. }//Sample_Dispatch
  323. VOID
  324. Sample_Unload(
  325. IN PDRIVER_OBJECT DriverObject
  326. )
  327. /*++
  328. Routine Description:
  329. Free all the allocated resources, etc.
  330. TODO: This is a placeholder for driver writer to add code on unload
  331. Arguments:
  332. DriverObject - pointer to a driver object
  333. Return Value:
  334. None
  335. --*/
  336. {
  337. Sample_KdPrint (("enter Sample_Unload\n"));
  338. /*
  339. // TODO: Free any global resources allocated in DriverEntry
  340. */
  341. Sample_KdPrint (("exit Sample_Unload\n"));
  342. }
  343. NTSTATUS
  344. Sample_StartDevice(
  345. IN PDEVICE_OBJECT DeviceObject
  346. )
  347. /*++
  348. Routine Description:
  349. Initializes a given instance of the Sample Device on the USB.
  350. TODO: Perform any device initialization and querying here. For example,
  351. this routine queries the device's descriptors. Your device can
  352. be queried in a similar fashion with more specific requests that are
  353. tailored to your device's functionality.
  354. Arguments:
  355. DeviceObject - pointer to the device object for this instance of a
  356. Sample Device
  357. Return Value:
  358. NT status code
  359. --*/
  360. {
  361. PDEVICE_EXTENSION deviceExtension;
  362. NTSTATUS ntStatus;
  363. PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
  364. PURB urb;
  365. ULONG siz;
  366. Sample_KdPrint (("enter Sample_StartDevice\n"));
  367. deviceExtension = DeviceObject->DeviceExtension;
  368. deviceExtension->NeedCleanup = TRUE;
  369. /*
  370. // Get some memory from then non paged pool (fixed, locked system memory)
  371. // for use by the USB Request Block (urb) for the specific USB Request we
  372. // will be performing below (a USB device request).
  373. */
  374. urb = ExAllocatePool( NonPagedPool,
  375. sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  376. if (urb) {
  377. siz = sizeof(USB_DEVICE_DESCRIPTOR);
  378. // Get some non paged memory for the device descriptor contents
  379. deviceDescriptor = ExAllocatePool(NonPagedPool,
  380. siz);
  381. if (deviceDescriptor) {
  382. // Use a macro in the standard USB header files to build the URB
  383. UsbBuildGetDescriptorRequest(urb,
  384. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  385. USB_DEVICE_DESCRIPTOR_TYPE,
  386. 0,
  387. 0,
  388. deviceDescriptor,
  389. NULL,
  390. siz,
  391. NULL);
  392. // Get the device descriptor
  393. ntStatus = Sample_CallUSBD(DeviceObject, urb);
  394. // Dump out the descriptor info to the debugger
  395. if (NT_SUCCESS(ntStatus)) {
  396. Sample_KdPrint (("Device Descriptor = %x, len %x\n",
  397. deviceDescriptor,
  398. urb->UrbControlDescriptorRequest.TransferBufferLength));
  399. Sample_KdPrint (("Sample Device Descriptor:\n"));
  400. Sample_KdPrint (("-------------------------\n"));
  401. Sample_KdPrint (("bLength %d\n", deviceDescriptor->bLength));
  402. Sample_KdPrint (("bDescriptorType 0x%x\n", deviceDescriptor->bDescriptorType));
  403. Sample_KdPrint (("bcdUSB 0x%x\n", deviceDescriptor->bcdUSB));
  404. Sample_KdPrint (("bDeviceClass 0x%x\n", deviceDescriptor->bDeviceClass));
  405. Sample_KdPrint (("bDeviceSubClass 0x%x\n", deviceDescriptor->bDeviceSubClass));
  406. Sample_KdPrint (("bDeviceProtocol 0x%x\n", deviceDescriptor->bDeviceProtocol));
  407. Sample_KdPrint (("bMaxPacketSize0 0x%x\n", deviceDescriptor->bMaxPacketSize0));
  408. Sample_KdPrint (("idVendor 0x%x\n", deviceDescriptor->idVendor));
  409. Sample_KdPrint (("idProduct 0x%x\n", deviceDescriptor->idProduct));
  410. Sample_KdPrint (("bcdDevice 0x%x\n", deviceDescriptor->bcdDevice));
  411. Sample_KdPrint (("iManufacturer 0x%x\n", deviceDescriptor->iManufacturer));
  412. Sample_KdPrint (("iProduct 0x%x\n", deviceDescriptor->iProduct));
  413. Sample_KdPrint (("iSerialNumber 0x%x\n", deviceDescriptor->iSerialNumber));
  414. Sample_KdPrint (("bNumConfigurations 0x%x\n", deviceDescriptor->bNumConfigurations));
  415. }
  416. } else {
  417. ntStatus = STATUS_NO_MEMORY;
  418. }
  419. if (NT_SUCCESS(ntStatus)) {
  420. /*
  421. // Put a ptr to the device descriptor in the device extension for easy
  422. // access (like a "cached" copy). We will free this memory when the
  423. // device is removed. See the "Sample_RemoveDevice" code.
  424. */
  425. deviceExtension->DeviceDescriptor = deviceDescriptor;
  426. deviceExtension->Stopped = FALSE;
  427. } else if (deviceDescriptor) {
  428. /*
  429. // If the bus transaction failed, then free up the memory created to hold
  430. // the device descriptor, since the device is probably non-functional
  431. */
  432. ExFreePool(deviceDescriptor);
  433. deviceExtension->DeviceDescriptor = NULL;
  434. }
  435. ExFreePool(urb);
  436. } else {
  437. // Failed getting memory for the Urb
  438. ntStatus = STATUS_NO_MEMORY;
  439. }
  440. // If the Get_Descriptor call was successful, then configure the device.
  441. if (NT_SUCCESS(ntStatus)) {
  442. ntStatus = Sample_ConfigureDevice(DeviceObject);
  443. }
  444. Sample_KdPrint (("exit Sample_StartDevice (%x)\n", ntStatus));
  445. return ntStatus;
  446. }
  447. NTSTATUS
  448. Sample_RemoveDevice(
  449. IN PDEVICE_OBJECT DeviceObject
  450. )
  451. /*++
  452. Routine Description:
  453. Removes a given instance of a Sample Device device on the USB.
  454. Arguments:
  455. DeviceObject - pointer to the device object for this instance of a Sample Device
  456. Return Value:
  457. NT status code
  458. --*/
  459. {
  460. PDEVICE_EXTENSION deviceExtension;
  461. NTSTATUS ntStatus = STATUS_SUCCESS;
  462. Sample_KdPrint (("enter Sample_RemoveDevice\n"));
  463. deviceExtension = DeviceObject->DeviceExtension;
  464. if (deviceExtension->DeviceDescriptor) {
  465. ExFreePool(deviceExtension->DeviceDescriptor);
  466. }
  467. /*
  468. // Free up any interface structures in our device extension
  469. */
  470. if (deviceExtension->Interface != NULL) {
  471. ExFreePool(deviceExtension->Interface);
  472. }//if
  473. Sample_KdPrint (("exit Sample_RemoveDevice (%x)\n", ntStatus));
  474. return ntStatus;
  475. }
  476. NTSTATUS
  477. Sample_StopDevice(
  478. IN PDEVICE_OBJECT DeviceObject
  479. )
  480. /*++
  481. Routine Description:
  482. Stops a given instance of a Sample Device device on USB.
  483. Arguments:
  484. DeviceObject - pointer to the device object for this instance of a Sample Device
  485. Return Value:
  486. NT status code
  487. --*/
  488. {
  489. PDEVICE_EXTENSION deviceExtension;
  490. NTSTATUS ntStatus = STATUS_SUCCESS;
  491. PURB urb;
  492. ULONG siz;
  493. Sample_KdPrint (("enter Sample_StopDevice\n"));
  494. deviceExtension = DeviceObject->DeviceExtension;
  495. /*
  496. // Send the select configuration urb with a NULL pointer for the configuration
  497. // handle, this closes the configuration and puts the device in the 'unconfigured'
  498. // state.
  499. */
  500. siz = sizeof(struct _URB_SELECT_CONFIGURATION);
  501. urb = ExAllocatePool(NonPagedPool,
  502. siz);
  503. if (urb) {
  504. NTSTATUS status;
  505. UsbBuildSelectConfigurationRequest(urb,
  506. (USHORT) siz,
  507. NULL);
  508. status = Sample_CallUSBD(DeviceObject, urb);
  509. Sample_KdPrint (("Device Configuration Closed status = %x usb status = %x.\n",
  510. status, urb->UrbHeader.Status));
  511. ExFreePool(urb);
  512. } else {
  513. ntStatus = STATUS_NO_MEMORY;
  514. }
  515. Sample_KdPrint (("exit Sample_StopDevice (%x)\n", ntStatus));
  516. return ntStatus;
  517. }
  518. NTSTATUS
  519. Sample_PnPAddDevice(
  520. IN PDRIVER_OBJECT DriverObject,
  521. IN PDEVICE_OBJECT PhysicalDeviceObject
  522. )
  523. /*++
  524. Routine Description:
  525. This routine is called to create a new instance of the device
  526. Arguments:
  527. DriverObject - pointer to the driver object for this instance of Sample
  528. PhysicalDeviceObject - pointer to a device object created by the bus
  529. Return Value:
  530. STATUS_SUCCESS if successful,
  531. STATUS_UNSUCCESSFUL otherwise
  532. --*/
  533. {
  534. NTSTATUS ntStatus = STATUS_SUCCESS;
  535. PDEVICE_OBJECT deviceObject = NULL;
  536. PDEVICE_EXTENSION deviceExtension;
  537. Sample_KdPrint(("enter Sample_PnPAddDevice\n"));
  538. // create our functional device object (FDO)
  539. ntStatus = Sample_CreateDeviceObject(DriverObject, &deviceObject, 0);
  540. if (NT_SUCCESS(ntStatus)) {
  541. deviceExtension = deviceObject->DeviceExtension;
  542. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  543. /*
  544. // Add more flags here if your driver supports other specific
  545. // behavior. For example, if your IRP_MJ_READ and IRP_MJ_WRITE
  546. // handlers support DIRECT_IO, you would set that flag here.
  547. //
  548. // Also, store away the Physical device Object
  549. */
  550. deviceExtension->PhysicalDeviceObject=PhysicalDeviceObject;
  551. //
  552. // Attach to the StackDeviceObject. This is the device object that what we
  553. // use to send Irps and Urbs down the USB software stack
  554. //
  555. deviceExtension->StackDeviceObject =
  556. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  557. ASSERT (deviceExtension->StackDeviceObject != NULL);
  558. }
  559. Sample_KdPrint(("exit Sample_PnPAddDevice (%x)\n", ntStatus));
  560. return ntStatus;
  561. }
  562. NTSTATUS
  563. Sample_CreateDeviceObject(
  564. IN PDRIVER_OBJECT DriverObject,
  565. IN PDEVICE_OBJECT *DeviceObject,
  566. LONG Instance
  567. )
  568. /*++
  569. Routine Description:
  570. Creates a Functional DeviceObject
  571. Arguments:
  572. DriverObject - pointer to the driver object for device
  573. DeviceObject - pointer to DeviceObject pointer to return
  574. created device object.
  575. Instance - instnace of the device create.
  576. Return Value:
  577. STATUS_SUCCESS if successful,
  578. STATUS_UNSUCCESSFUL otherwise
  579. --*/
  580. {
  581. NTSTATUS ntStatus;
  582. WCHAR deviceLinkBuffer[] = L"\\DosDevices\\Sample-0";
  583. UNICODE_STRING deviceLinkUnicodeString;
  584. WCHAR deviceNameBuffer[] = L"\\Device\\Sample-0";
  585. UNICODE_STRING deviceNameUnicodeString;
  586. PDEVICE_EXTENSION deviceExtension;
  587. STRING deviceName;
  588. Sample_KdPrint(("enter Sample_CreateDeviceObject instance = %d\n", Instance));
  589. /*
  590. // fix up device names based on Instance
  591. //
  592. // NOTE: Watch this space for potential changes to this approach in future revisions
  593. // of this sample driver.
  594. */
  595. deviceLinkBuffer[19] = (USHORT) ('0' + Instance);
  596. deviceNameBuffer[15] = (USHORT) ('0' + Instance);
  597. Sample_KdPrint(("Create Device name (%ws)\n", deviceNameBuffer));
  598. RtlInitUnicodeString (&deviceNameUnicodeString,
  599. deviceNameBuffer);
  600. /*
  601. //Print out the unicode string
  602. //NOTE: We must first convert the string to Unicode due to a bug in the Debugger that does not allow
  603. // Unicode Strings to be printed to the debug device.
  604. */
  605. deviceName.Buffer = NULL;
  606. ntStatus = RtlUnicodeStringToAnsiString (&deviceName,
  607. &deviceNameUnicodeString,
  608. TRUE);
  609. if (NT_SUCCESS(ntStatus)) {
  610. Sample_KdPrint(("Create Device Name (%s)\n", deviceName.Buffer));
  611. RtlFreeAnsiString (&deviceName);
  612. } else {
  613. Sample_KdPrint(("Unicode to Ansi str failed w/ ntStatus: 0x%x\n",ntStatus));
  614. }
  615. ntStatus = IoCreateDevice (DriverObject,
  616. sizeof (DEVICE_EXTENSION),
  617. &deviceNameUnicodeString,
  618. FILE_DEVICE_UNKNOWN,
  619. 0,
  620. FALSE,
  621. DeviceObject);
  622. if (NT_SUCCESS(ntStatus)) {
  623. RtlInitUnicodeString (&deviceLinkUnicodeString,
  624. deviceLinkBuffer);
  625. Sample_KdPrint(("Create DosDevice name (%ws)\n", deviceLinkBuffer));
  626. ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
  627. &deviceNameUnicodeString);
  628. // Initialize our device extension
  629. deviceExtension = (PDEVICE_EXTENSION) ((*DeviceObject)->DeviceExtension);
  630. RtlCopyMemory(deviceExtension->DeviceLinkNameBuffer,
  631. deviceLinkBuffer,
  632. sizeof(deviceLinkBuffer));
  633. deviceExtension->ConfigurationHandle = NULL;
  634. deviceExtension->DeviceDescriptor = NULL;
  635. deviceExtension->NeedCleanup = FALSE;
  636. // Initialize our interface
  637. deviceExtension->Interface = NULL;
  638. }
  639. Sample_KdPrint(("exit Sample_CreateDeviceObject (%x)\n", ntStatus));
  640. return ntStatus;
  641. }
  642. VOID
  643. Sample_Cleanup(
  644. PDEVICE_OBJECT DeviceObject
  645. )
  646. /*++
  647. Routine Description:
  648. Cleans up certain elements of the device object. This is called when the device
  649. is being removed from the system
  650. Arguments:
  651. DeviceObject - pointer to DeviceObject
  652. Return Value:
  653. None.
  654. --*/
  655. {
  656. PDEVICE_EXTENSION deviceExtension;
  657. UNICODE_STRING deviceLinkUnicodeString;
  658. deviceExtension = DeviceObject->DeviceExtension;
  659. if (deviceExtension->NeedCleanup) {
  660. deviceExtension->NeedCleanup = FALSE;
  661. RtlInitUnicodeString (&deviceLinkUnicodeString,
  662. deviceExtension->DeviceLinkNameBuffer);
  663. IoDeleteSymbolicLink(&deviceLinkUnicodeString);
  664. }
  665. }
  666. NTSTATUS
  667. Sample_CallUSBD(
  668. IN PDEVICE_OBJECT DeviceObject,
  669. IN PURB Urb
  670. )
  671. /*++
  672. Routine Description:
  673. Passes a Usb Request Block (URB) to the USB class driver (USBD)
  674. Note that we create our own IRP here and use it to send the request to
  675. the USB software subsystem. This means that this routine is essentially
  676. independent of the IRP that caused this driver to be called in the first
  677. place. The IRP for this transfer is created, used, and then destroyed
  678. in this routine.
  679. However, note that this routine uses the Usb Request Block (urb) passed
  680. in by the caller as the request block for the USB software stack.
  681. Implementation of this routine may be changed depending on the specific
  682. requirements of your driver. For example, while this routine issues a
  683. synchronous request to the USB stack, you may wish to implement this as an
  684. asynchronous request in which you set an IoCompletionRoutine to be called
  685. when the request is complete.
  686. Arguments:
  687. DeviceObject - pointer to the device object for this instance of an Sample Device
  688. Urb - pointer to Urb request block
  689. Return Value:
  690. STATUS_SUCCESS if successful,
  691. STATUS_UNSUCCESSFUL otherwise
  692. --*/
  693. {
  694. NTSTATUS ntStatus, status = STATUS_SUCCESS;
  695. PDEVICE_EXTENSION deviceExtension;
  696. PIRP irp;
  697. KEVENT event;
  698. IO_STATUS_BLOCK ioStatus;
  699. PIO_STACK_LOCATION nextStack;
  700. Sample_KdPrint (("enter Sample_CallUSBD\n"));
  701. deviceExtension = DeviceObject->DeviceExtension;
  702. // issue a synchronous request (see notes above)
  703. KeInitializeEvent(&event, NotificationEvent, FALSE);
  704. irp = IoBuildDeviceIoControlRequest(
  705. IOCTL_INTERNAL_USB_SUBMIT_URB,
  706. deviceExtension->StackDeviceObject,
  707. NULL,
  708. 0,
  709. NULL,
  710. 0,
  711. TRUE, /* INTERNAL */
  712. &event,
  713. &ioStatus);
  714. // Prepare for calling the USB driver stack
  715. nextStack = IoGetNextIrpStackLocation(irp);
  716. ASSERT(nextStack != NULL);
  717. // Set up the URB ptr to pass to the USB driver stack
  718. nextStack->Parameters.Others.Argument1 = Urb;
  719. Sample_KdPrint (("Calling USB Driver Stack\n"));
  720. /*
  721. // Call the USB class driver to perform the operation. If the returned status
  722. // is PENDING, wait for the request to complete.
  723. */
  724. ntStatus = IoCallDriver(deviceExtension->StackDeviceObject,
  725. irp);
  726. Sample_KdPrint (("return from IoCallDriver USBD %x\n", ntStatus));
  727. if (ntStatus == STATUS_PENDING)
  728. {
  729. LARGE_INTEGER dueTime;
  730. Sample_KdPrint (("Wait for single object\n"));
  731. dueTime.QuadPart = -10000 * DEADMAN_TIMEOUT;
  732. ntStatus = KeWaitForSingleObject(
  733. &event,
  734. Suspended,
  735. KernelMode,
  736. FALSE,
  737. &dueTime);
  738. Sample_KdPrint (("Wait for single object, returned %x\n", status));
  739. if(ntStatus == STATUS_TIMEOUT)
  740. {
  741. ioStatus.Status = ntStatus = STATUS_IO_TIMEOUT;
  742. ioStatus.Information = 0;
  743. // We've waited long enough and we're not going to take
  744. // it anymore...cancel it
  745. IoCancelIrp(irp);
  746. // Wait for the stack to signal the _real_ completion of the cancel
  747. // Note we wait forever here, so we depend on the USB stack to signal this
  748. // event when it completes the cancelled Irp. Gosh, I hope this works. (kjaff 4-16-97)
  749. ntStatus = KeWaitForSingleObject(
  750. &event,
  751. Suspended,
  752. KernelMode,
  753. FALSE,
  754. NULL);
  755. Sample_KdPrint (("Wait for single object, returned %x\n", status));
  756. }
  757. } else
  758. {
  759. ioStatus.Status = ntStatus;
  760. }
  761. Sample_KdPrint (("URB status = %x status = %x irp status %x\n",
  762. Urb->UrbHeader.Status, status, ioStatus.Status));
  763. /*
  764. // USBD maps the error code for us. USBD uses error codes in its URB
  765. // structure that are more insightful into USB behavior. In order to
  766. // match the NT Status codes, USBD maps its error codes into more general NT
  767. // error categories so higher level drivers can decipher the error codes
  768. // based on standard NT error code definitions. To allow more insight into
  769. // the specific USB error that occurred, your driver may wish to examine the
  770. // URB's status code (Urb->UrbHeader.Status) as well.
  771. */
  772. ntStatus = ioStatus.Status;
  773. Sample_KdPrint(("exit Sample_CallUSBD (%x)\n", ntStatus));
  774. return ntStatus;
  775. }
  776. NTSTATUS
  777. Sample_ConfigureDevice(
  778. IN PDEVICE_OBJECT DeviceObject
  779. )
  780. /*++
  781. Routine Description:
  782. Configures the USB device via USB-specific device requests and interaction
  783. with the USB software subsystem.
  784. Arguments:
  785. DeviceObject - pointer to the device object for this instance of the Sample Device
  786. Return Value:
  787. NT status code
  788. --*/
  789. {
  790. PDEVICE_EXTENSION deviceExtension;
  791. NTSTATUS ntStatus;
  792. PURB urb = NULL;
  793. ULONG siz;
  794. PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL;
  795. Sample_KdPrint (("enter Sample_ConfigureDevice\n"));
  796. deviceExtension = DeviceObject->DeviceExtension;
  797. /*
  798. // Get memory for the USB Request Block (urb).
  799. */
  800. urb = ExAllocatePool(NonPagedPool,
  801. sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  802. if (urb != NULL) {
  803. /*
  804. // Set size of the data buffer. Note we add padding to cover hardware faults
  805. // that may cause the device to go past the end of the data buffer
  806. */
  807. siz = sizeof(USB_CONFIGURATION_DESCRIPTOR) + 16;
  808. // Get the nonpaged pool memory for the data buffer
  809. configurationDescriptor = ExAllocatePool(NonPagedPool, siz);
  810. if (configurationDescriptor != NULL) {
  811. UsbBuildGetDescriptorRequest(urb,
  812. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  813. USB_CONFIGURATION_DESCRIPTOR_TYPE,
  814. 0,
  815. 0,
  816. configurationDescriptor,
  817. NULL,
  818. sizeof (USB_CONFIGURATION_DESCRIPTOR),/* Get only the configuration descriptor */
  819. NULL);
  820. ntStatus = Sample_CallUSBD(DeviceObject, urb);
  821. if (NT_SUCCESS(ntStatus)) {
  822. Sample_KdPrint (("Configuration Descriptor is at %x, bytes txferred: %d\n\
  823. Configuration Descriptor Actual Length: %d\n",
  824. configurationDescriptor,
  825. urb->UrbControlDescriptorRequest.TransferBufferLength,
  826. configurationDescriptor->wTotalLength));
  827. }//if
  828. } else {
  829. ntStatus = STATUS_NO_MEMORY;
  830. goto Exit_SampleConfigureDevice;
  831. }//if-else
  832. // Determine how much data is in the entire configuration descriptor
  833. // and add extra room to protect against accidental overrun
  834. siz = configurationDescriptor->wTotalLength + 16;
  835. // Free up the data buffer memory just used
  836. ExFreePool(configurationDescriptor);
  837. configurationDescriptor = NULL;
  838. // Get nonpaged pool memory for the data buffer
  839. configurationDescriptor = ExAllocatePool(NonPagedPool, siz);
  840. // Now get the entire Configuration Descriptor
  841. if (configurationDescriptor != NULL) {
  842. UsbBuildGetDescriptorRequest(urb,
  843. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  844. USB_CONFIGURATION_DESCRIPTOR_TYPE,
  845. 0,
  846. 0,
  847. configurationDescriptor,
  848. NULL,
  849. siz, // Get all the descriptor data
  850. NULL);
  851. ntStatus = Sample_CallUSBD(DeviceObject, urb);
  852. if (NT_SUCCESS(ntStatus)) {
  853. Sample_KdPrint (("Entire Configuration Descriptor is at %x, bytes txferred: %d\n",
  854. configurationDescriptor,
  855. urb->UrbControlDescriptorRequest.TransferBufferLength));
  856. } else {
  857. //Error in getting configuration descriptor
  858. goto Exit_SampleConfigureDevice;
  859. }//else
  860. } else {
  861. // Failed getting data buffer (configurationDescriptor) memory
  862. ntStatus = STATUS_NO_MEMORY;
  863. goto Exit_SampleConfigureDevice;
  864. }//if-else
  865. } else {
  866. // failed getting urb memory
  867. ntStatus = STATUS_NO_MEMORY;
  868. goto Exit_SampleConfigureDevice;
  869. }//if-else
  870. /*
  871. // We have the configuration descriptor for the configuration
  872. // we want.
  873. //
  874. // Now we issue the SelectConfiguration command to get
  875. // the pipes associated with this configuration.
  876. */
  877. if (configurationDescriptor) {
  878. // Get our pipes
  879. ntStatus = Sample_SelectInterfaces(DeviceObject,
  880. configurationDescriptor,
  881. NULL // Device not yet configured
  882. );
  883. } //if
  884. Exit_SampleConfigureDevice:
  885. // Clean up and exit this routine
  886. if (urb != NULL) {
  887. ExFreePool(urb); // Free urb memory
  888. }//if
  889. if (configurationDescriptor != NULL) {
  890. ExFreePool(configurationDescriptor);// Free data buffer
  891. }//if
  892. Sample_KdPrint (("exit Sample_ConfigureDevice (%x)\n", ntStatus));
  893. return ntStatus;
  894. }//Sample_ConfigureDevice
  895. NTSTATUS
  896. Sample_SelectInterfaces(
  897. IN PDEVICE_OBJECT DeviceObject,
  898. IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
  899. IN PUSBD_INTERFACE_INFORMATION Interface
  900. )
  901. /*++
  902. Routine Description:
  903. Initializes an Sample Device with multiple interfaces
  904. Arguments:
  905. DeviceObject - pointer to the device object for this instance of the Sample Device
  906. ConfigurationDescriptor - pointer to the USB configuration descriptor containing the interface and endpoint
  907. descriptors.
  908. Interface - pointer to a USBD Interface Information Object
  909. - If this is NULL, then this driver must choose its interface based on driver-specific
  910. criteria, and the driver must also CONFIGURE the device.
  911. - If it is NOT NULL, then the driver has already been given an interface and
  912. the device has already been configured by the parent of this device driver.
  913. Return Value:
  914. NT status code
  915. --*/
  916. {
  917. PDEVICE_EXTENSION deviceExtension;
  918. NTSTATUS ntStatus;
  919. PURB urb;
  920. ULONG siz, numberOfInterfaces, j;
  921. UCHAR numberOfPipes, alternateSetting, MyInterfaceNumber;
  922. PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
  923. PUSBD_INTERFACE_INFORMATION interfaceObject;
  924. Sample_KdPrint (("enter Sample_SelectInterfaces\n"));
  925. deviceExtension = DeviceObject->DeviceExtension;
  926. MyInterfaceNumber = SAMPLE_INTERFACE_NBR;
  927. if (Interface == NULL) {
  928. /*
  929. // This example driver only supports one interface. This can be extended
  930. // to be a dynamically allocated array by your driver.
  931. */
  932. numberOfInterfaces = ConfigurationDescriptor->bNumInterfaces;
  933. Sample_KdPrint (("Device has %d Interfaces\n",numberOfInterfaces));
  934. numberOfInterfaces =1; // Fixed for this sample driver in this revision
  935. numberOfPipes = 0; // Initialize to zero
  936. /*
  937. // We use alternate interface setting 0 for all interfaces
  938. // NOTE: This is a simplification and is due to change in future releases of this driver. If
  939. // your driver supports alternate settings, you will have to do more work to switch between
  940. // alternate settings.
  941. */
  942. alternateSetting = 0;
  943. /*
  944. // Call a USBD helper function that returns a ptr to a USB Interface Descriptor given
  945. // a USB Configuration Descriptor, an Interface Number, and an Alternate Setting for that Interface
  946. */
  947. interfaceDescriptor =
  948. USBD_ParseConfigurationDescriptor(ConfigurationDescriptor,
  949. MyInterfaceNumber, //interface number (this is bInterfaceNumber from interface descr)
  950. alternateSetting);
  951. ASSERT(interfaceDescriptor != NULL);
  952. if (interfaceDescriptor != NULL) {
  953. Sample_KdPrint (("Device has %d Interface(s) | MyInterface (%d) is at: (%#X)\n",
  954. numberOfInterfaces, MyInterfaceNumber, interfaceDescriptor));
  955. } /* if there was a valid interfacedesc */
  956. /* Add to the tally of pipes in this configuration */
  957. numberOfPipes += interfaceDescriptor->bNumEndpoints;
  958. Sample_KdPrint (("Interface has %d endpoints\n",
  959. interfaceDescriptor->bNumEndpoints));
  960. /*
  961. // Now that we have looked at the interface, we configure the device so that the remainder
  962. // of the USBD objects will come into existence (ie., pipes, etc.) as a result of the configuration,
  963. // thus completing the configuration process for the USB device.
  964. //
  965. // Allocate a URB big enough for this Select Configuration request
  966. // This example driver supports only 1 interface
  967. //
  968. // NOTE: The new service USBD_CreateConfigurationRequest will replace some of the
  969. // code below. Future releases of this driver will demonstrate how to use
  970. // that service.
  971. //
  972. */
  973. siz = GET_SELECT_CONFIGURATION_REQUEST_SIZE(numberOfInterfaces, numberOfPipes);
  974. Sample_KdPrint (("size of config request Urb = %d\n", siz));
  975. urb = ExAllocatePool(NonPagedPool,
  976. siz);
  977. if (urb) {
  978. interfaceObject = (PUSBD_INTERFACE_INFORMATION) (&(urb->UrbSelectConfiguration.Interface));
  979. Sample_KdPrint (("urb.Interface=%#X\n", &(urb->UrbSelectConfiguration.Interface)));
  980. // set up the input parameters in our interface request structure.
  981. interfaceObject->Length = GET_USBD_INTERFACE_SIZE(interfaceDescriptor->bNumEndpoints);
  982. Sample_KdPrint (("size of interface request = %d\n", interfaceObject->Length));
  983. interfaceObject->InterfaceNumber = interfaceDescriptor->bInterfaceNumber;
  984. interfaceObject->AlternateSetting = interfaceDescriptor->bAlternateSetting;
  985. interfaceObject->NumberOfPipes = interfaceDescriptor->bNumEndpoints;
  986. /*
  987. // We set up a default max transfer size for the endpoints. Your driver will
  988. // need to change this to reflect the capabilities of your device's endpoints.
  989. */
  990. for (j=0; j<interfaceDescriptor->bNumEndpoints; j++) {
  991. interfaceObject->Pipes[j].MaximumTransferSize =
  992. USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
  993. } /* for */
  994. Sample_KdPrint (("InterfaceObj Inteface Nbr: %d | InterfaceObj AltSett: %d |NbrPip: %d\n",
  995. interfaceObject->InterfaceNumber,
  996. interfaceObject->AlternateSetting,
  997. interfaceObject->NumberOfPipes));
  998. UsbBuildSelectConfigurationRequest(urb,
  999. (USHORT) siz,
  1000. ConfigurationDescriptor);
  1001. ntStatus = Sample_CallUSBD(DeviceObject, urb);
  1002. if (NT_SUCCESS(ntStatus) && USBD_SUCCESS(urb->UrbSelectConfiguration.Status)) {
  1003. // Save the configuration handle for this device
  1004. deviceExtension->ConfigurationHandle =
  1005. urb->UrbSelectConfiguration.ConfigurationHandle;
  1006. deviceExtension->Interface = ExAllocatePool(NonPagedPool,
  1007. interfaceObject->Length);
  1008. if (deviceExtension->Interface) {
  1009. // save a copy of the interfaceObject information returned
  1010. RtlCopyMemory(deviceExtension->Interface, interfaceObject, interfaceObject->Length);
  1011. // Dump the interfaceObject to the debugger
  1012. Sample_KdPrint (("---------\n"));
  1013. Sample_KdPrint (("NumberOfPipes 0x%x\n", deviceExtension->Interface->NumberOfPipes));
  1014. Sample_KdPrint (("Length 0x%x\n", deviceExtension->Interface->Length));
  1015. Sample_KdPrint (("Alt Setting 0x%x\n", deviceExtension->Interface->AlternateSetting));
  1016. Sample_KdPrint (("Interface Number 0x%x\n", deviceExtension->Interface->InterfaceNumber));
  1017. // Dump the pipe info
  1018. for (j=0; j<interfaceObject->NumberOfPipes; j++) {
  1019. PUSBD_PIPE_INFORMATION pipeInformation;
  1020. pipeInformation = &deviceExtension->Interface->Pipes[j];
  1021. Sample_KdPrint (("---------\n"));
  1022. Sample_KdPrint (("PipeType 0x%x\n", pipeInformation->PipeType));
  1023. Sample_KdPrint (("EndpointAddress 0x%x\n", pipeInformation->EndpointAddress));
  1024. Sample_KdPrint (("MaxPacketSize 0x%x\n", pipeInformation->MaximumPacketSize));
  1025. Sample_KdPrint (("Interval 0x%x\n", pipeInformation->Interval));
  1026. Sample_KdPrint (("Handle 0x%x\n", pipeInformation->PipeHandle));
  1027. Sample_KdPrint (("MaximumTransferSize 0x%x\n", pipeInformation->MaximumTransferSize));
  1028. }/* for all the pipes in this interface */
  1029. Sample_KdPrint (("---------\n"));
  1030. } /*If ExAllocate passed */
  1031. }/* if selectconfiguration request was successful */
  1032. } else {
  1033. ntStatus = STATUS_NO_MEMORY;
  1034. }/* if urb alloc passed */
  1035. }//if Interface was not NULL
  1036. Sample_KdPrint (("exit Sample_SelectInterfaces (%x)\n", ntStatus));
  1037. return ntStatus;
  1038. }/* Sample_SelectInterfaces */
  1039. NTSTATUS
  1040. Sample_Read_Write(
  1041. IN PDEVICE_OBJECT DeviceObject,
  1042. IN PIRP Irp,
  1043. IN BOOLEAN Read
  1044. )
  1045. /*++
  1046. Routine Description:
  1047. This function is called for IOCTLs to Read or Write bulk or interrupt endpoints.
  1048. By agreement between the driver and application, the endpoint on which the READ or WRITE
  1049. is to be performed is supplied by the caller (the User-Mode application that performed
  1050. the IOCTL puts this value in the buffer supplied in the DeviceIoControl call). This
  1051. number is an INDEX into an array of pipes, which are ordered exactly like the order of the
  1052. endpoints as they appear in the device's configuration descriptor.
  1053. The endpoint list is ordered as the endpoint descriptors appear in the device. The list
  1054. is a zero-index based ordered list. That is, when the application specifies:
  1055. Endpoint index 0 = the endpoint described by the FIRST endpoint descriptor
  1056. in the configuration descriptor
  1057. Endpoint index 1 = the endpoint described by the SECOND endpoint descriptor
  1058. in the configuration descriptor
  1059. etc.
  1060. Also by agreement between this driver and the application, this INDEX is specified in
  1061. the first DWORD (32-bits) of the input buffer. Note that more sophisticated structures
  1062. can be passed between the application and the driver to communicate the desired operation.
  1063. For READs, this data received from the device is put into the SystemBuffer. This routine
  1064. sets the "information" field in the Irp to tell the IOS to how many bytes to copy back
  1065. to user space (in the user's lpOutputBuffer). The actual bytes copied back is reflected in
  1066. the lpBytesReturned field in the DeviceIoControl() call, which the application can examine.
  1067. For WRITEs, the data is retrieved from the SystemBuffer and sent to the device.
  1068. Arguments:
  1069. DeviceObject - pointer to the device object for this instance of the Sample device.
  1070. Irp - pointer to IRP
  1071. Read - if TRUE this is a Device-to-Host (Read from device) transfer
  1072. if FALSE this is a Host-to-Device (Write to device) transfer
  1073. Return Value:
  1074. NT status code
  1075. STATUS_SUCCESS: Read was done successfully
  1076. STATUS_INVALID_PARAMETER_3: The Endpoint Index does not specify an IN pipe
  1077. STATUS_NO_MEMORY: Insufficient data memory was supplied to perform the READ
  1078. This routine fills the status code into the Irp
  1079. --*/
  1080. {
  1081. USBD_INTERFACE_INFORMATION * pInterfaceInfo;
  1082. USBD_PIPE_INFORMATION * pPipeInfo;
  1083. PIO_STACK_LOCATION irpStack;
  1084. PDEVICE_EXTENSION deviceExtension;
  1085. NTSTATUS ntStatus;
  1086. PVOID ioBuffer;
  1087. PCHAR pcTempBuffer;
  1088. ULONG length;
  1089. PULONG pPipeNum;
  1090. ULONG inputBufferLength;
  1091. ULONG outputBufferLength;
  1092. ULONG siz;
  1093. PURB urb;
  1094. Sample_KdPrint(("enter READ\n"));
  1095. irpStack = IoGetCurrentIrpStackLocation (Irp);
  1096. ASSERT (irpStack != NULL);
  1097. deviceExtension = DeviceObject->DeviceExtension;
  1098. ASSERT (deviceExtension != NULL);
  1099. ioBuffer = Irp->AssociatedIrp.SystemBuffer;
  1100. inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  1101. outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  1102. //DEBUG ONLY
  1103. if ((ioBuffer == NULL) || (inputBufferLength == 0) || (outputBufferLength==0)) {
  1104. Sample_KdPrint (("ERROR ioBuffer %X | inBufLen: %d | outBufLen %d\n",
  1105. ioBuffer, inputBufferLength, outputBufferLength));
  1106. Irp->IoStatus.Information = 0;
  1107. return (STATUS_NO_MEMORY);
  1108. } //DEBUG ONLY
  1109. pInterfaceInfo = deviceExtension->Interface;
  1110. ASSERT (pInterfaceInfo != NULL);
  1111. pPipeNum = (PULONG) ioBuffer;
  1112. ASSERT (*pPipeNum <= pInterfaceInfo->NumberOfPipes);
  1113. pPipeInfo = &(pInterfaceInfo->Pipes[*pPipeNum]);
  1114. ASSERT (pPipeInfo != NULL);
  1115. ASSERT ((pPipeInfo->PipeHandle) != NULL);
  1116. Sample_KdPrint (("PipeNum: %d | ioBuffer %X | inBufLen: %d | outBufLen %d\n",
  1117. *pPipeNum, ioBuffer, inputBufferLength, outputBufferLength));
  1118. siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
  1119. // allocate urb
  1120. urb = ExAllocatePool(NonPagedPool, siz);
  1121. // By convention, the first dword of the buffer is reserved for the pipe index, so
  1122. // skip over the first dword when specifying the transferbuffer
  1123. pcTempBuffer = (((char*)ioBuffer) + sizeof (ULONG));
  1124. if (Read==TRUE) {
  1125. // A READ operation implies that the data is placed in the User's Output Data Buffer
  1126. length = outputBufferLength - sizeof(ULONG);
  1127. } else {
  1128. // A WRITE operation implies that the data is gotten from the User's Input Data Buffer
  1129. length = inputBufferLength - sizeof(ULONG);
  1130. }/* else */
  1131. // set up urb
  1132. UsbBuildInterruptOrBulkTransferRequest(urb, //ptr to urb
  1133. (USHORT) siz, //siz of urb
  1134. pPipeInfo->PipeHandle, //usbd pipe handle
  1135. pcTempBuffer, //TransferBuffer
  1136. NULL, //mdl (unused)
  1137. length,
  1138. //bufferlength
  1139. USBD_SHORT_TRANSFER_OK, //flags
  1140. NULL); //link
  1141. // call the usb stack
  1142. ntStatus = Sample_CallUSBD(DeviceObject, urb);
  1143. // The Information field tells IOM how much to copy back into the
  1144. // usermode buffer in the BUFFERED method
  1145. if (NT_SUCCESS(ntStatus) && Read==TRUE) {
  1146. Sample_KdPrint (("Sucessfully Transferred %d Bytes\n", urb->UrbBulkOrInterruptTransfer.TransferBufferLength));
  1147. // We fill in the actual length transferred in the first DWORD (this overwrites the pipe number)
  1148. *((PULONG)ioBuffer) = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  1149. // Tell the IOS to copy whatever the device returned, as well as the first DWORD that was skipped over
  1150. Irp->IoStatus.Information = (urb->UrbBulkOrInterruptTransfer.TransferBufferLength + sizeof(ULONG));
  1151. ASSERT (Irp->IoStatus.Information <= outputBufferLength);
  1152. }else if (NT_SUCCESS(ntStatus) && Read==FALSE) {
  1153. // We fill in the actual length transferred in the first DWORD (this overwrites the pipe number)
  1154. *((PULONG)ioBuffer) = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  1155. // Tell the IOS to copy whatever the device returned, as well as the first DWORD that was skipped over
  1156. Irp->IoStatus.Information = sizeof (ULONG);
  1157. ASSERT (Irp->IoStatus.Information <= outputBufferLength);
  1158. }/* else */
  1159. Irp->IoStatus.Status = ntStatus;
  1160. // free allocated urb
  1161. ExFreePool(urb);
  1162. Sample_KdPrint(("exit READ\n"));
  1163. return (ntStatus);
  1164. }
  1165. NTSTATUS
  1166. Sample_Create(
  1167. IN PDEVICE_OBJECT DeviceObject,
  1168. IN PIRP Irp
  1169. )
  1170. /*++
  1171. Routine Description:
  1172. This is the Entry point for CreateFile calls from user mode apps (apps may open "\\.\Sample-x\yyzz"
  1173. where yy is the interface number and zz is the endpoint address).
  1174. Here is where you would add code to create symbolic links between endpoints
  1175. (i.e., pipes in USB software terminology) and User Mode file names. You are
  1176. free to use any convention you wish to create these links, although the above
  1177. convention offers a way to identify resources on a device by familiar file and
  1178. directory structure nomenclature.
  1179. Arguments:
  1180. DeviceObject - pointer to the device object for this instance of the Sample device
  1181. Return Value:
  1182. NT status code
  1183. --*/
  1184. {
  1185. NTSTATUS ntStatus;
  1186. Irp->IoStatus.Status = STATUS_SUCCESS;
  1187. Irp->IoStatus.Information = 0;
  1188. // Create all the symbolic links here
  1189. ntStatus = Irp->IoStatus.Status;
  1190. IoCompleteRequest (Irp,
  1191. IO_NO_INCREMENT
  1192. );
  1193. return ntStatus;
  1194. }//Sample_Create
  1195. NTSTATUS
  1196. Sample_Close(
  1197. IN PDEVICE_OBJECT DeviceObject,
  1198. IN PIRP Irp
  1199. )
  1200. /*++
  1201. Routine Description:
  1202. Entry point for CloseHandle calls from user mode apps to close handles they have opened
  1203. Arguments:
  1204. DeviceObject - pointer to the device object for this instance of the Sample device
  1205. Irp - pointer to an irp
  1206. Return Value:
  1207. NT status code
  1208. --*/
  1209. {
  1210. NTSTATUS ntStatus = STATUS_SUCCESS;
  1211. return ntStatus;
  1212. }//Sample_Close
  1213. NTSTATUS
  1214. Sample_ProcessIOCTL(
  1215. IN PDEVICE_OBJECT DeviceObject,
  1216. IN PIRP Irp
  1217. )
  1218. /*++
  1219. Routine Description:
  1220. This where all the DeviceIoControl codes are handled. You can add more code
  1221. here to handle IOCTL codes that are specific to your device driver.
  1222. Arguments:
  1223. DeviceObject - pointer to the device object for this instance of the Sample device.
  1224. Return Value:
  1225. NT status code
  1226. --*/
  1227. {
  1228. PIO_STACK_LOCATION irpStack;
  1229. PVOID ioBuffer;
  1230. ULONG inputBufferLength;
  1231. ULONG outputBufferLength;
  1232. PDEVICE_EXTENSION deviceExtension;
  1233. ULONG ioControlCode;
  1234. NTSTATUS ntStatus;
  1235. ULONG length;
  1236. PUCHAR pch;
  1237. Sample_KdPrint (("IRP_MJ_DEVICE_CONTROL\n"));
  1238. /*
  1239. // Get a pointer to the current location in the Irp. This is where
  1240. // the function codes and parameters are located.
  1241. */
  1242. irpStack = IoGetCurrentIrpStackLocation (Irp);
  1243. Irp->IoStatus.Status = STATUS_SUCCESS;
  1244. Irp->IoStatus.Information = 0;
  1245. /*
  1246. // Get a pointer to the device extension
  1247. */
  1248. deviceExtension = DeviceObject->DeviceExtension;
  1249. ioBuffer = Irp->AssociatedIrp.SystemBuffer;
  1250. inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  1251. outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  1252. ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
  1253. /*
  1254. // Handle Ioctls from User mode
  1255. */
  1256. switch (ioControlCode) {
  1257. case IOCTL_Sample_GET_PIPE_INFO:
  1258. /*
  1259. // inputs - none
  1260. // outputs - we copy the interface information structure that we have
  1261. // stored in our device extension area to the output buffer which
  1262. // will be reflected to the user mode application by the IOS.
  1263. */
  1264. length = 0;
  1265. pch = (PUCHAR) ioBuffer;
  1266. if (deviceExtension->Interface) {
  1267. RtlCopyMemory(pch+length,
  1268. (PUCHAR) deviceExtension->Interface,
  1269. deviceExtension->Interface->Length);
  1270. length += deviceExtension->Interface->Length;
  1271. } /* if */
  1272. Irp->IoStatus.Information = length;
  1273. Irp->IoStatus.Status = STATUS_SUCCESS;
  1274. break;
  1275. case IOCTL_Sample_GET_DEVICE_DESCRIPTOR:
  1276. /*
  1277. // inputs - pointer to a buffer in which to place descriptor data
  1278. // outputs - we put the device descriptor data, if any is returned by the device
  1279. // in the system buffer and then we set the length inthe Information field
  1280. // in the Irp, which will then cause the system to copy the buffer back
  1281. // to the user's buffer
  1282. */
  1283. length = Sample_GetDeviceDescriptor (DeviceObject, ioBuffer);
  1284. Sample_KdPrint(("Get Device Descriptor returned %d bytes\n", length));
  1285. Irp->IoStatus.Information = length;
  1286. Irp->IoStatus.Status = STATUS_SUCCESS;
  1287. break;
  1288. case IOCTL_Sample_GET_CONFIGURATION_DESCRIPTOR:
  1289. /*
  1290. // inputs - pointer to a buffer in which to place descriptor data
  1291. // outputs - we put the configuration descriptor data, if any is returned by the device
  1292. // in the system buffer and then we set the length in the Information field
  1293. // in the Irp, which will then cause the system to copy the buffer back
  1294. // to the user's buffer
  1295. */
  1296. length = Sample_GetConfigDescriptor (DeviceObject, ioBuffer, outputBufferLength);
  1297. Sample_KdPrint(("Get Config Descriptor returned %d bytes\n", length));
  1298. Irp->IoStatus.Information = length;
  1299. Irp->IoStatus.Status = STATUS_SUCCESS;
  1300. break;
  1301. case IOCTL_Sample_BULK_OR_INTERRUPT_WRITE:
  1302. /*
  1303. // inputs - pointer to the parameter block for this IOCTL.
  1304. //
  1305. // outputs - A status field is filled in the header of the parameter block.
  1306. //
  1307. // assumptions:
  1308. // When we configured the device, we made a list of pipes to represent the endpoints
  1309. // on the device, in the order that the endpoint descriptors appeared in the configuration
  1310. // descriptor. In this IOCTL, the application specifies the offset into that list of
  1311. // pipes (this is an array, so it's zero-based indexing) and that is the pipe we will
  1312. // use for this transfer. So, if the device has an OUTPUT endpoint as the second endpoint
  1313. // descriptor (ie., offset = 1 in the array) the app would specify a "1" in the pipe offset
  1314. // parameter for this IOCTL.
  1315. //
  1316. // NOTE: It is currently ILLEGAL to perform interrupt OUT transfers on USB. This IOCTL is named as it is
  1317. // just for symmetry with its IN counterpart's name.
  1318. */
  1319. if ((ioBuffer) && (inputBufferLength>=0) && (outputBufferLength>=0)) {
  1320. Sample_KdPrint (("IOCTL_Sample_BULK_OR_INTERRUPT_WRITE\n"));
  1321. Sample_Read_Write (DeviceObject, Irp, FALSE);
  1322. }else {
  1323. Sample_KdPrint (("IOCTL_Sample_BULK_OR_INTERRUPT_WRITE got INVALID buffer(s)!\n"));
  1324. Sample_KdPrint (("ioBuffer: %x | inputBufferLength: %d | outputBufferLength: %d\n",
  1325. ioBuffer, inputBufferLength, outputBufferLength));
  1326. }/*else bad pointer(s) received */
  1327. break;
  1328. case IOCTL_Sample_BULK_OR_INTERRUPT_READ:
  1329. /*
  1330. // inputs - pointer to the parameter block for this IOCTL.
  1331. //
  1332. // outputs - A status field is filled in the header of the parameter block. The data
  1333. // returned from the device is copied into the data buffer section of the parameter block.
  1334. //
  1335. // assumptions:
  1336. // When we configured the device, we made a list of pipes to represent the endpoints
  1337. // on the device, in the order that the endpoint descriptors appeared in the configuration
  1338. // descriptor. In this IOCTL, the application specifies the offset into that list of
  1339. // pipes (this is an array, so it's zero-based indexing) and that is the pipe we will
  1340. // use for this transfer. So, if the device has an INPUT endpoint as the first endpoint
  1341. // descriptor (ie., offset = 0 in the array) the app would specify a "0" in the pipe offset
  1342. // parameter for this IOCTL.
  1343. */
  1344. if ((ioBuffer) && (inputBufferLength>=0) && (outputBufferLength>=0)) {
  1345. Sample_KdPrint (("IOCTL_Sample_BULK_OR_INTERRUPT_READ\n"));
  1346. Sample_Read_Write (DeviceObject, Irp, TRUE);
  1347. }else {
  1348. Sample_KdPrint (("IOCTL_Sample_BULK_OR_INTERRUPT_READ got INVALID buffer(s)!\n"));
  1349. Sample_KdPrint (("ioBuffer: %x | inputBufferLength: %d | outputBufferLength: %d\n",
  1350. ioBuffer, inputBufferLength, outputBufferLength));
  1351. }/*else bad pointer(s) received */
  1352. break;
  1353. default:
  1354. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1355. }/* switch on ioControlCode */
  1356. ntStatus = Irp->IoStatus.Status;
  1357. IoCompleteRequest (Irp,
  1358. IO_NO_INCREMENT
  1359. );
  1360. return ntStatus;
  1361. }
  1362. ULONG
  1363. Sample_GetDeviceDescriptor(
  1364. IN PDEVICE_OBJECT DeviceObject,
  1365. PVOID pvOutputBuffer
  1366. )
  1367. /*++
  1368. Routine Description:
  1369. Gets a device descriptor from the given device object
  1370. Arguments:
  1371. DeviceObject - pointer to the sample device object
  1372. Return Value:
  1373. Number of valid bytes in data buffer
  1374. --*/
  1375. {
  1376. PDEVICE_EXTENSION deviceExtension = NULL;
  1377. NTSTATUS ntStatus = STATUS_SUCCESS;
  1378. PURB urb = NULL;
  1379. ULONG length = 0;
  1380. Sample_KdPrint (("Enter Sample_GetDeviceDescriptor\n"));
  1381. deviceExtension = DeviceObject->DeviceExtension;
  1382. urb = ExAllocatePool(NonPagedPool,
  1383. sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  1384. if (urb) {
  1385. if (pvOutputBuffer) {
  1386. UsbBuildGetDescriptorRequest(urb,
  1387. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  1388. USB_DEVICE_DESCRIPTOR_TYPE, //descriptor type
  1389. 0, //index
  1390. 0, //language ID
  1391. pvOutputBuffer, //transfer buffer
  1392. NULL, //MDL
  1393. sizeof(USB_DEVICE_DESCRIPTOR), //buffer length
  1394. NULL); //link
  1395. ntStatus = Sample_CallUSBD(DeviceObject, urb);
  1396. } else {
  1397. ntStatus = STATUS_NO_MEMORY;
  1398. }
  1399. // Get the length from the Urb
  1400. length = urb->UrbControlDescriptorRequest.TransferBufferLength;
  1401. Sample_KdPrint (("%d bytes of dev descriptor received\n",length));
  1402. ExFreePool(urb);
  1403. } else {
  1404. ntStatus = STATUS_NO_MEMORY;
  1405. }
  1406. Sample_KdPrint (("Leaving Sample_GetDeviceDescriptor\n"));
  1407. return length;
  1408. }
  1409. ULONG
  1410. Sample_GetConfigDescriptor(
  1411. IN PDEVICE_OBJECT DeviceObject,
  1412. PVOID pvOutputBuffer,
  1413. ULONG ulLength
  1414. )
  1415. /*++
  1416. Routine Description:
  1417. Gets a configuration descriptor from the given device object
  1418. Arguments:
  1419. DeviceObject - pointer to the sample device object
  1420. pvOutputBuffer - pointer to the buffer where the data is to be placed
  1421. ulLength - length of the buffer
  1422. Return Value:
  1423. Number of valid bytes in data buffer
  1424. --*/
  1425. {
  1426. PDEVICE_EXTENSION deviceExtension = NULL;
  1427. NTSTATUS ntStatus = STATUS_SUCCESS;
  1428. PURB urb = NULL;
  1429. ULONG length = 0;
  1430. Sample_KdPrint (("Enter Sample_GetConfigurationDescriptor\n"));
  1431. deviceExtension = DeviceObject->DeviceExtension;
  1432. urb = ExAllocatePool(NonPagedPool,
  1433. sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  1434. if (urb) {
  1435. if (pvOutputBuffer) {
  1436. UsbBuildGetDescriptorRequest(urb,
  1437. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  1438. USB_CONFIGURATION_DESCRIPTOR_TYPE, //descriptor type
  1439. 0, //index
  1440. 0, //language ID
  1441. pvOutputBuffer, //transfer buffer
  1442. NULL, //MDL
  1443. ulLength, //buffer length
  1444. NULL); //link
  1445. ntStatus = Sample_CallUSBD(DeviceObject, urb);
  1446. } else {
  1447. ntStatus = STATUS_NO_MEMORY;
  1448. }
  1449. // Get the length from the Urb
  1450. length = urb->UrbControlDescriptorRequest.TransferBufferLength;
  1451. Sample_KdPrint (("%d bytes of cfg descriptor received\n",length));
  1452. ExFreePool(urb);
  1453. } else {
  1454. ntStatus = STATUS_NO_MEMORY;
  1455. }
  1456. Sample_KdPrint (("Leaving Sample_GetConfigurationDescriptor\n"));
  1457. return length;
  1458. }
  1459.