/*++ Module Name: ioctliso.c --*/ #include "wdm.h" #include "stdarg.h" #include "stdio.h" #include "usbdi.h" #include "usbdlib.h" #include "usb100.h" #include "Iso82930.h" #include "IsoUsb.h" #include "usbdlib.h" NTSTATUS IsoUsb_ProcessIOCTL( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Dispatch table handler for IRP_MJ_DEVICE_CONTROL; Handle DeviceIoControl() calls from User mode Return Value: NT status code --*/ { PIO_STACK_LOCATION irpStack; PVOID ioBuffer; ULONG inputBufferLength; ULONG outputBufferLength; PDEVICE_EXTENSION deviceExtension; ULONG ioControlCode; NTSTATUS ntStatus; ULONG length; PUCHAR pch; PURB urb; USHORT temp; USHORT temp2; PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor; IsoUsb_IncrementIoCount(DeviceObject); deviceExtension = DeviceObject->DeviceExtension; if ( !IsoUsb_CanAcceptIoRequests( DeviceObject ) ) { ntStatus = STATUS_DELETE_PENDING; Irp->IoStatus.Status = ntStatus; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_NO_INCREMENT ); IsoUsb_DecrementIoCount(DeviceObject); return ntStatus; } irpStack = IoGetCurrentIrpStackLocation (Irp); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; ioBuffer = Irp->AssociatedIrp.SystemBuffer; inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength; outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; switch (ioControlCode) { case 4: //Implemented for Compatability with Cypress Thermometer Driver. pch = (PUCHAR) ioBuffer; switch(pch[0]) { case 0x0E: // Set LED Brightness temp = pch[1]; // Store Brightness length = VendorCommand(DeviceObject, 0x03, // WriteRAM 0x2C, // gbLEDBrightness (USHORT)pch[1], ioBuffer); length = VendorCommand(DeviceObject, 0x03, // WriteRAM 0x2B, // gbLEDBrightnessUpdate 0x01, // TRUE ioBuffer); pch[0] = 0; //Status pch[1] = temp; //Brightness Irp->IoStatus.Information = 2; Irp->IoStatus.Status = STATUS_SUCCESS; ntStatus = STATUS_SUCCESS; break; case 0x0B: // Read Thermometer length = VendorCommand(DeviceObject, 0x02, // ReadRAM 0x33, // gbThermTempRead 0, ioBuffer); temp = pch[1]; // Store Temperature length = VendorCommand(DeviceObject, 0x02, // ReadRAM 0x34, // gbThermTempRead2 0, ioBuffer); temp2 = pch[1]; // Store Sign length = VendorCommand(DeviceObject, 0x02, // ReadRAM 0x7A, // gbButtonPushed 0, ioBuffer); pch[3] = pch[1]; //Move Button pch[0] = 0; //Status pch[1] = temp; //Temperature pch[2] = temp2; //Sign Irp->IoStatus.Information = 4; Irp->IoStatus.Status = STATUS_SUCCESS; ntStatus = STATUS_SUCCESS; break; case 0x14: // Read Port length = VendorCommand(DeviceObject, 0x04, // ReadPort pch[1], // Address 0, ioBuffer); pch[0] = 0; //Status // pch[1] = pch[2]; //Value // error: data cames back in [1] Irp->IoStatus.Information = 2; Irp->IoStatus.Status = STATUS_SUCCESS; ntStatus = STATUS_SUCCESS; break; case 0x15: // Write Port length = VendorCommand(DeviceObject, 0x05, // WritePort pch[1], // Address pch[2], // Value ioBuffer); Irp->IoStatus.Information = 1; Irp->IoStatus.Status = STATUS_SUCCESS; ntStatus = STATUS_SUCCESS; break; case 0x16: // Read RAM length = VendorCommand(DeviceObject, 0x02, // ReadRAM pch[1], // Address 0, ioBuffer); pch[0] = 0; //Status // pch[1] = pch[2]; //Value // error: data cames back in [1] Irp->IoStatus.Information = 2; Irp->IoStatus.Status = STATUS_SUCCESS; ntStatus = STATUS_SUCCESS; break; case 0x17: // Write RAM length = VendorCommand(DeviceObject, 0x03, // WriteRAM pch[1], // Address pch[2], // Value ioBuffer); Irp->IoStatus.Information = 1; Irp->IoStatus.Status = STATUS_SUCCESS; ntStatus = STATUS_SUCCESS; break; case 0x18: // Read ROM length = VendorCommand(DeviceObject, 0x01, // ReadROM pch[1], // Address 0, ioBuffer); pch[0] = 0; //Status // pch[1] = pch[2]; //Value // error: data cames back in [1] Irp->IoStatus.Information = 2; Irp->IoStatus.Status = STATUS_SUCCESS; ntStatus = STATUS_SUCCESS; break; default : break; ntStatus = STATUS_SUCCESS; } break; case 8: //Reads a Vendor Command pch = (PUCHAR) ioBuffer; length = VendorCommand(DeviceObject, (UCHAR)pch[0], (USHORT)pch[1], (USHORT)pch[2], ioBuffer); Irp->IoStatus.Information = length; Irp->IoStatus.Status = STATUS_SUCCESS; ntStatus = STATUS_SUCCESS; break; case 12: // GetDescriptor(s) pch = (PUCHAR) ioBuffer; length = GetDescriptor(DeviceObject, (UCHAR)pch[0], (UCHAR)pch[1], (USHORT)pch[2], ioBuffer); Irp->IoStatus.Information = length; Irp->IoStatus.Status = STATUS_SUCCESS; ntStatus = STATUS_SUCCESS; break; case 16: // Get Status pch = (PUCHAR) ioBuffer; length = GetStatus(DeviceObject, (USHORT)pch[0], (USHORT)pch[1], ioBuffer); Irp->IoStatus.Information = length; Irp->IoStatus.Status = STATUS_SUCCESS; ntStatus = STATUS_SUCCESS; break; case 20: //IOCTL_ISOUSB_RESET_DEVICE: ntStatus = IsoUsb_ResetDevice(DeviceObject); break; case 24: //Reconfigure Device (Enumerate) ntStatus = IsoUsb_ConfigureDevice(DeviceObject); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS; ntStatus = STATUS_SUCCESS; break; case 28: //UnConfigure Device ntStatus = IsoUsb_StopDevice(DeviceObject); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS; ntStatus = STATUS_SUCCESS; break; default: ntStatus = STATUS_INVALID_PARAMETER; Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; } IoCompleteRequest (Irp, IO_NO_INCREMENT ); IsoUsb_DecrementIoCount(DeviceObject); return ntStatus; } ULONG VendorCommand( IN PDEVICE_OBJECT DeviceObject, IN UCHAR Request, IN USHORT Value, IN USHORT Index, PVOID ioBuffer ) { NTSTATUS ntStatus; PURB urb; urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); if (urb) { UsbBuildVendorRequest(urb, URB_FUNCTION_VENDOR_ENDPOINT, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK), 0, // Reserved Bits Request, // Request Value, // Value Index, // Index ioBuffer, // Transfer Buffer NULL, // TransferBufferMDL OPTIONAL 8, // Transfer Buffer Lenght NULL); // Link OPTIONAL ntStatus = IsoUsb_CallUSBD(DeviceObject, urb); ExFreePool(urb); return(urb->UrbControlVendorClassRequest.TransferBufferLength); } else return(0); } ULONG GetDescriptor( IN PDEVICE_OBJECT DeviceObject, IN UCHAR DescriptorType, IN UCHAR Index, IN USHORT LanguageId, PVOID ioBuffer ) { NTSTATUS ntStatus; PURB urb; PUCHAR pch; ULONG length; pch = (PUCHAR) ioBuffer; urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); if (urb) { // Get Descriptor Length UsbBuildGetDescriptorRequest(urb, (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST), DescriptorType, Index, LanguageId, ioBuffer, NULL, 0x01, // Transmit Lenght. Read First Byte. NULL); // Link ntStatus = IsoUsb_CallUSBD(DeviceObject, urb); ExFreePool(urb); // Check Length of Incomming Data. if (urb->UrbControlDescriptorRequest.TransferBufferLength == 0) return(0); urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); length = pch[0]; if (DescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE) length = 1024; if (urb) { UsbBuildGetDescriptorRequest(urb, (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST), DescriptorType, Index, LanguageId, ioBuffer, NULL, length, // Length of Descriptor String NULL); // Link ntStatus = IsoUsb_CallUSBD(DeviceObject, urb); ExFreePool(urb); return(urb->UrbControlDescriptorRequest.TransferBufferLength); } else return(0); } else return(0); } ULONG GetStatus( IN PDEVICE_OBJECT DeviceObject, IN USHORT Op, IN USHORT Index, PVOID ioBuffer ) { NTSTATUS ntStatus; PURB urb; urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST)); if (urb) { UsbBuildGetStatusRequest(urb, Op, // Operation Index, // Index ioBuffer, // Transfer Buffer NULL, // TransferBufferMDL OPTIONAL NULL); // Link OPTIONAL ntStatus = IsoUsb_CallUSBD(DeviceObject, urb); ExFreePool(urb); return(urb->UrbControlGetStatusRequest.TransferBufferLength); } else return(0); } NTSTATUS IsoUsb_ResetDevice( IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: Checks port status; if OK, return success and do no more; If bad, attempt reset Arguments: DeviceObject - pointer to the device object for this instance of the 82930 device. Return Value: NT status code --*/ { NTSTATUS ntStatus; ULONG portStatus; ISOUSB_KdPrint(DBGLVL_MEDIUM,("Enter IsoUsb_ResetDevice()\n")); // // Check the port state, if it is disabled we will need // to re-enable it // ntStatus = IsoUsb_GetPortStatus(DeviceObject, &portStatus); if (NT_SUCCESS(ntStatus) && !(portStatus & USBD_PORT_ENABLED) && portStatus & USBD_PORT_CONNECTED) { // // port is disabled, attempt reset // ISOUSB_KdPrint( DBGLVL_DEFAULT,("IsoUsb_ResetDevice() will reset\n")); ntStatus = IsoUsb_ResetParentPort(DeviceObject); } return ntStatus; } NTSTATUS IsoUsb_GetPortStatus( IN PDEVICE_OBJECT DeviceObject, IN PULONG PortStatus ) /*++ Routine Description: returns the port status for our device Arguments: Return Value: STATUS_SUCCESS if successful, STATUS_UNSUCCESSFUL otherwise --*/ { NTSTATUS ntStatus, status = STATUS_SUCCESS; PIRP irp; KEVENT event; IO_STATUS_BLOCK ioStatus; PIO_STACK_LOCATION nextStack; PDEVICE_EXTENSION deviceExtension; ISOUSB_KdPrint( DBGLVL_DEFAULT,("enter IsoUsb_GetPortStatus\n")); deviceExtension = DeviceObject->DeviceExtension; *PortStatus = 0; // // issue a synchronous request // KeInitializeEvent(&event, NotificationEvent, FALSE); // IoBuildDeviceIoControlRequest allocates and sets up an IRP for a device control request irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_USB_GET_PORT_STATUS, deviceExtension->TopOfStackDeviceObject, //next-lower driver's device object, representing the target device. NULL, // no input or output buffers 0, NULL, 0, TRUE, // internal ( use IRP_MJ_INTERNAL_DEVICE_CONTROL ) &event, // event to be signalled on completion ( we wait for it below ) &ioStatus); // // Call the class driver to perform the operation. If the returned status // is PENDING, wait for the request to complete. // // IoGetNextIrpStackLocation gives a higher level driver access to the next-lower // driver's I/O stack location in an IRP so the caller can set it up for the lower driver. nextStack = IoGetNextIrpStackLocation(irp); ISOUSB_ASSERT(nextStack != NULL); nextStack->Parameters.Others.Argument1 = PortStatus; ISOUSB_KdPrint( DBGLVL_DEFAULT,("IsoUsb_GetPortStatus() calling USBD port status api\n")); ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp); ISOUSB_KdPrint( DBGLVL_DEFAULT,("IsoUsb_GetPortStatus() return from IoCallDriver USBD %x\n", ntStatus)); if (ntStatus == STATUS_PENDING) { ISOUSB_KdPrint( DBGLVL_DEFAULT,("Wait for single object\n")); status = KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL); ISOUSB_KdPrint( DBGLVL_DEFAULT,("IsoUsb_GetPortStatus() Wait for single object, returned %x\n", status)); } else { ioStatus.Status = ntStatus; } ISOUSB_KdPrint( DBGLVL_DEFAULT,("IsoUsb_GetPortStatus() Port status = %x\n", *PortStatus)); // // USBD maps the error code for us // ntStatus = ioStatus.Status; ISOUSB_KdPrint( DBGLVL_DEFAULT,("Exit IsoUsb_GetPortStatus (%x)\n", ntStatus)); return ntStatus; } NTSTATUS IsoUsb_ResetParentPort( IN IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: Reset the our parent port Arguments: Return Value: STATUS_SUCCESS if successful, STATUS_UNSUCCESSFUL otherwise --*/ { NTSTATUS ntStatus, status = STATUS_SUCCESS; PIRP irp; KEVENT event; IO_STATUS_BLOCK ioStatus; PIO_STACK_LOCATION nextStack; PDEVICE_EXTENSION deviceExtension; ISOUSB_KdPrint( DBGLVL_HIGH,("enter IsoUsb_ResetParentPort\n")); deviceExtension = DeviceObject->DeviceExtension; // // issue a synchronous request // KeInitializeEvent(&event, NotificationEvent, FALSE); irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_USB_RESET_PORT, deviceExtension->TopOfStackDeviceObject, NULL, 0, NULL, 0, TRUE, // internal ( use IRP_MJ_INTERNAL_DEVICE_CONTROL ) &event, &ioStatus); // // Call the class driver to perform the operation. If the returned status // is PENDING, wait for the request to complete. // nextStack = IoGetNextIrpStackLocation(irp); ISOUSB_ASSERT(nextStack != NULL); ISOUSB_KdPrint( DBGLVL_HIGH,("IsoUsb_ResetParentPort() calling USBD enable port api\n")); ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp); ISOUSB_KdPrint( DBGLVL_HIGH,("IsoUsb_ResetParentPort() return from IoCallDriver USBD %x\n", ntStatus)); if (ntStatus == STATUS_PENDING) { ISOUSB_KdPrint( DBGLVL_HIGH,("IsoUsb_ResetParentPort() Wait for single object\n")); status = KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL); ISOUSB_KdPrint( DBGLVL_HIGH,("IsoUsb_ResetParentPort() Wait for single object, returned %x\n", status)); } else { ioStatus.Status = ntStatus; } // // USBD maps the error code for us // ntStatus = ioStatus.Status; ISOUSB_KdPrint( DBGLVL_HIGH,("Exit IsoUsb_ResetPort (%x)\n", ntStatus)); return ntStatus; }