// =================================================================== // // testusb.c // // rev 1.0 beta // // this module handles USB IOCTL/IRP calls // // USB device driver for USB Device Example // kernel mode driver // // // =================================================================== #define DRIVER // Include files needed for WDM driver support; from NT DDK #include "wdm.h" #include "stdarg.h" #include "stdio.h" // Include files needed for USB support; from USB DDK #include "usbdi.h" #include "usbdlib.h" #include "usb.h" #include "Testdrv.h" // headers specified to this driver #include "test98.h" // =================================================================== NTSTATUS Test_CallUSBD( IN PDEVICE_OBJECT DeviceObject, IN PURB Urb ) /* Passes a Usb Request Block (URB) to the USB class driver (USBD) Note that we create our own IRP here and use it to send the request to the USB software subsystem. This means that this routine is essentially independent of the IRP that caused this driver to be called in the first place. The IRP for this transfer is created, used, and then destroyed in this routine. DiviceObject - pointer to the device object for this instance of a Test Device Urb - pointer to Urb request block Return Value: STATUS_SUCCESS if successful, STATUS_UNSUCCESSFUL otherwise */ { NTSTATUS ntStatus, status = STATUS_SUCCESS; PFDO_DEVICE_DATA deviceData; PIRP irp; KEVENT event; IO_STATUS_BLOCK ioStatus; PIO_STACK_LOCATION nextStack; deviceData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension; // issue a synchronous request (see notes above) KeInitializeEvent(&event, NotificationEvent, FALSE); irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_USB_SUBMIT_URB, deviceData->UnderlyingPDO, NULL, 0, NULL, 0, TRUE, /* INTERNAL */ &event, &ioStatus); // Prepare for calling the USB driver stack nextStack = IoGetNextIrpStackLocation(irp); ASSERT(nextStack != NULL); // Set up the URB ptr to pass to the USB driver stack nextStack->Parameters.Others.Argument1 = Urb; // Call the USB class driver to perform the operation. If the returned status // is PENDING, wait for the request to complete. ntStatus = IoCallDriver(deviceData->UnderlyingPDO, irp); if (ntStatus == STATUS_PENDING) { status = KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL); } else { ioStatus.Status = ntStatus; } // USBD maps the error code for us. USBD uses error codes in its URB // structure that are more insightful into USB behavior. To allow more insight into // the specific USB error that occurred, your driver may wish to examine the // URB's status code (Urb->UrbHeader.Status) as well. ntStatus = ioStatus.Status; return ntStatus; } // =================================================================== NTSTATUS Test_ProcessIOCTL( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /* This where all the DeviceIoControl codes are handled. You can expand and add more code here to handle IOCTL/IRP codes that are specific to your device driver. DeviceObject - pointer to the device object for this instance of the test device. Return Value: NT status */ { PIO_STACK_LOCATION irpStack; PVOID ioBuffer; ULONG inputBufferLength; ULONG outputBufferLength; // PDEVICE_EXTENSION deviceExtension; PFDO_DEVICE_DATA deviceData; ULONG ioControlCode; NTSTATUS ntStatus; ULONG length; PUCHAR pch; // Get a pointer to the current location in the Irp. This is where // the function codes and parameters are located. irpStack = IoGetCurrentIrpStackLocation (Irp); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; // Get a pointer to the device extension deviceData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension; // *** Test98_IncIoCount (deviceData); ioBuffer = Irp->AssociatedIrp.SystemBuffer; inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength; outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; // Handle Ioctls from User mode switch (ioControlCode) { case IRP_Test_GET_PIPE_INFO: // inputs - none // outputs - we copy the interface information structure that we have // stored in our device extension area to the output buffer which // will be reflected to the user mode application by the IOS. length = 0; pch = (PUCHAR) ioBuffer; Irp->IoStatus.Information = length; Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_Test_GET_DEVICE_DESCRIPTOR: // inputs - pointer to a buffer in which to place descriptor data // outputs - we put the device descriptor data, if any is returned by the device // in the system buffer and then we set the length inthe Information field // in the Irp, which will then cause the system to copy the buffer back // to the user's buffer length = Test_GetDeviceDescriptor (DeviceObject, ioBuffer); Irp->IoStatus.Information = length; Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_Test_GET_CONFIGURATION_DESCRIPTOR: // inputs - pointer to a buffer in which to place descriptor data // outputs - we put the configuration descriptor data, if any is returned by the device // in the system buffer and then we set the length in the Information field // in the Irp, which will then cause the system to copy the buffer back // to the user's buffer length = Test_GetConfigDescriptor (DeviceObject, ioBuffer, outputBufferLength); Irp->IoStatus.Information = length; Irp->IoStatus.Status = STATUS_SUCCESS; break; default: Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; }// switch on ioControlCode ntStatus = Irp->IoStatus.Status; IoCompleteRequest (Irp, IO_NO_INCREMENT ); Test98_DecIoCount (deviceData); return ntStatus; } // =================================================================== ULONG Test_GetDeviceDescriptor( IN PDEVICE_OBJECT DeviceObject, PVOID pvOutputBuffer ) /* Gets a device descriptor from the given device object DeviceObject - pointer to the test device object Return Value: Number of valid bytes in data buffer */ { PFDO_DEVICE_DATA deviceData = NULL; NTSTATUS ntStatus = STATUS_SUCCESS; PURB urb = NULL; ULONG length = 0; deviceData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension; urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); if (urb) { if (pvOutputBuffer) { UsbBuildGetDescriptorRequest(urb, (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_DEVICE_DESCRIPTOR_TYPE, //descriptor type 0, //index 0, //language ID pvOutputBuffer, //transfer buffer NULL, //MDL sizeof(USB_DEVICE_DESCRIPTOR), //buffer length NULL); //link ntStatus = Test_CallUSBD(DeviceObject, urb); } else { ntStatus = STATUS_NO_MEMORY; } // Get the length from the Urb length = urb->UrbControlDescriptorRequest.TransferBufferLength; ExFreePool(urb); } else { ntStatus = STATUS_NO_MEMORY; } return length; } // =================================================================== /* not tested it yet NTSTATUS SetOne(IN PDEVICE_OBJECT pDeviceObject, PUSBTESTCTRLDESC pTestCtrlDesc) // perform a "set" setup packet // // Return Value: ntstatus { NTSTATUS ntStatus; PURB pUrb; pTemp=ExAllocatePool(NonPagedPool, sizeof(USBDISPDESC)); pUrb=ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); if (pUrb) { RtlCopyMemory(pTemp, pTestCtrlDesc, sizeof(USBTESTDESC)); UsbBuildVendorRequest(pUrb, URB_FUNCTION_CLASS_DEVICE, //Command sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), !(USBD_TRANSFER_DIRECTION_IN),// Direction Bit: OUT 0, // Reserved Bits ! 0x04, // Request (0xF1) pTestCtrlDesc->usControlCode, // Value (0xF0) 0x0, // Index (0x00) pTemp, // Transfer Buffer NULL, // Transfer Buffer MDL 0x08, // Transfer buffer length: Size of display // descriptor. NULL) ; ntStatus=MakeUSBDCall(pDeviceObject, pUrb); ExFreePool(pUrb); } ExFreePool(pTemp); return ntStatus; } */ // =================================================================== ULONG Test_GetConfigDescriptor( IN PDEVICE_OBJECT DeviceObject, PVOID pvOutputBuffer, ULONG ulLength ) /* Gets configuration descriptors from the given device object DeviceObject - pointer to the test device object pvOutputBuffer - pointer to the buffer where the data is to be placed ulLength - length of the buffer Return Value: Number of valid bytes in data buffer */ { PFDO_DEVICE_DATA deviceData = NULL; NTSTATUS ntStatus = STATUS_SUCCESS; PURB urb = NULL; ULONG length = 0; deviceData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension; urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); if (urb) { if (pvOutputBuffer) { UsbBuildGetDescriptorRequest(urb, (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, //descriptor type 0, //index 0, //language ID pvOutputBuffer, //transfer buffer NULL, //MDL ulLength, //buffer length NULL); //link ntStatus = Test_CallUSBD(DeviceObject, urb); } else { ntStatus = STATUS_NO_MEMORY; } // Get the length from the Urb length = urb->UrbControlDescriptorRequest.TransferBufferLength; ExFreePool(urb); } else { ntStatus = STATUS_NO_MEMORY; } return length; } // =================================================================== NTSTATUS Test_Read( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /* This function is called for a IRP_MJ_READ. TODO: Add functionality here for your device driver if it handles that IRP code. DeviceObject - pointer to the device object for this instance of the Test device. Irp - pointer to IRP Return Value: NT status */ { NTSTATUS ntStatus = STATUS_SUCCESS; UNREFERENCED_PARAMETER (DeviceObject); UNREFERENCED_PARAMETER (Irp); return (ntStatus); } // =================================================================== NTSTATUS Test_Write( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /* This function is called for a IRP_MJ_WRITE. TODO: Add functionality here for your device driver if it handles that IRP code. DeviceObject - pointer to the device object for this instance of the Test device. Irp - pointer to IRP Return Value: NT status */ { NTSTATUS ntStatus = STATUS_SUCCESS; UNREFERENCED_PARAMETER (DeviceObject); UNREFERENCED_PARAMETER (Irp); return (ntStatus); } // =================================================================== NTSTATUS Test_Create( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS ntStatus; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; // Create all the symbolic links here ntStatus = Irp->IoStatus.Status; IoCompleteRequest (Irp,IO_NO_INCREMENT); UNREFERENCED_PARAMETER (DeviceObject); return ntStatus; }