1 /* 2 * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: USB block storage device driver. 5 * COPYRIGHT: 2005-2006 James Tabor 6 * 2011-2012 Michael Martin (michael.martin@reactos.org) 7 * 2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org) 8 */ 9 10 #include "usbstor.h" 11 12 #define NDEBUG 13 #include <debug.h> 14 15 IO_COMPLETION_ROUTINE SyncForwardIrpCompletionRoutine; 16 17 NTSTATUS 18 NTAPI 19 USBSTOR_SyncForwardIrpCompletionRoutine( 20 PDEVICE_OBJECT DeviceObject, 21 PIRP Irp, 22 PVOID Context) 23 { 24 if (Irp->PendingReturned) 25 { 26 KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE); 27 } 28 return STATUS_MORE_PROCESSING_REQUIRED; 29 } 30 31 NTSTATUS 32 NTAPI 33 USBSTOR_GetBusInterface( 34 IN PDEVICE_OBJECT DeviceObject, 35 OUT PUSB_BUS_INTERFACE_USBDI_V2 BusInterface) 36 { 37 KEVENT Event; 38 NTSTATUS Status; 39 PIRP Irp; 40 IO_STATUS_BLOCK IoStatus; 41 PIO_STACK_LOCATION Stack; 42 43 ASSERT(DeviceObject); 44 ASSERT(BusInterface); 45 46 KeInitializeEvent(&Event, NotificationEvent, FALSE); 47 48 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, 49 DeviceObject, 50 NULL, 51 0, 52 NULL, 53 &Event, 54 &IoStatus); 55 if (Irp == NULL) 56 { 57 return STATUS_INSUFFICIENT_RESOURCES; 58 } 59 60 // initialize request 61 Stack = IoGetNextIrpStackLocation(Irp); 62 Stack->MajorFunction = IRP_MJ_PNP; 63 Stack->MinorFunction = IRP_MN_QUERY_INTERFACE; 64 Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD); 65 Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&USB_BUS_INTERFACE_USBDI_GUID; 66 Stack->Parameters.QueryInterface.Version = 2; 67 Stack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface; 68 Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL; 69 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 70 71 Status = IoCallDriver(DeviceObject, Irp); 72 73 if (Status == STATUS_PENDING) 74 { 75 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 76 Status = IoStatus.Status; 77 } 78 79 return Status; 80 } 81 82 NTSTATUS 83 USBSTOR_SyncUrbRequest( 84 IN PDEVICE_OBJECT DeviceObject, 85 OUT PURB UrbRequest) 86 { 87 PIRP Irp; 88 PIO_STACK_LOCATION IoStack; 89 KEVENT Event; 90 NTSTATUS Status; 91 92 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 93 if (!Irp) 94 { 95 return STATUS_INSUFFICIENT_RESOURCES; 96 } 97 98 KeInitializeEvent(&Event, NotificationEvent, FALSE); 99 100 IoStack = IoGetNextIrpStackLocation(Irp); 101 102 // initialize stack location 103 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 104 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; 105 IoStack->Parameters.Others.Argument1 = (PVOID)UrbRequest; 106 IoStack->Parameters.DeviceIoControl.InputBufferLength = UrbRequest->UrbHeader.Length; 107 Irp->IoStatus.Status = STATUS_SUCCESS; 108 109 IoSetCompletionRoutine(Irp, USBSTOR_SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE); 110 111 Status = IoCallDriver(DeviceObject, Irp); 112 113 if (Status == STATUS_PENDING) 114 { 115 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 116 Status = Irp->IoStatus.Status; 117 } 118 119 IoFreeIrp(Irp); 120 return Status; 121 } 122 123 PVOID 124 AllocateItem( 125 IN POOL_TYPE PoolType, 126 IN ULONG ItemSize) 127 { 128 return ExAllocatePoolZero(PoolType, ItemSize, USB_STOR_TAG); 129 } 130 131 VOID 132 FreeItem( 133 IN PVOID Item) 134 { 135 ExFreePoolWithTag(Item, USB_STOR_TAG); 136 } 137 138 NTSTATUS 139 USBSTOR_ClassRequest( 140 IN PDEVICE_OBJECT DeviceObject, 141 IN PFDO_DEVICE_EXTENSION DeviceExtension, 142 IN UCHAR RequestType, 143 IN USHORT Index, 144 IN ULONG TransferFlags, 145 IN ULONG TransferBufferLength, 146 IN PVOID TransferBuffer) 147 148 { 149 PURB Urb; 150 NTSTATUS Status; 151 152 Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); 153 if (!Urb) 154 { 155 return STATUS_INSUFFICIENT_RESOURCES; 156 } 157 158 Urb->UrbControlVendorClassRequest.Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST); 159 Urb->UrbControlVendorClassRequest.Hdr.Function = URB_FUNCTION_CLASS_INTERFACE; 160 Urb->UrbControlVendorClassRequest.TransferFlags = TransferFlags; 161 Urb->UrbControlVendorClassRequest.TransferBufferLength = TransferBufferLength; 162 Urb->UrbControlVendorClassRequest.TransferBuffer = TransferBuffer; 163 Urb->UrbControlVendorClassRequest.Request = RequestType; 164 Urb->UrbControlVendorClassRequest.Index = Index; 165 166 Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb); 167 168 FreeItem(Urb); 169 return Status; 170 } 171 172 NTSTATUS 173 USBSTOR_GetMaxLUN( 174 IN PDEVICE_OBJECT DeviceObject, 175 IN PFDO_DEVICE_EXTENSION DeviceExtension) 176 { 177 PUCHAR Buffer; 178 NTSTATUS Status; 179 180 Buffer = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, sizeof(UCHAR), USB_STOR_TAG); 181 if (!Buffer) 182 { 183 return STATUS_INSUFFICIENT_RESOURCES; 184 } 185 186 Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_GET_MAX_LUN, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_IN, sizeof(UCHAR), Buffer); 187 188 DPRINT("MaxLUN: %x\n", *Buffer); 189 190 if (NT_SUCCESS(Status)) 191 { 192 if (*Buffer > MAX_LUN) 193 { 194 // invalid response documented in usb mass storage specification 195 Status = STATUS_DEVICE_DATA_ERROR; 196 } 197 else 198 { 199 // store maxlun 200 DeviceExtension->MaxLUN = *Buffer; 201 } 202 } 203 else 204 { 205 // "USB Mass Storage Class. Bulk-Only Transport. Revision 1.0" 206 // 3.2 Get Max LUN (class-specific request) : 207 // Devices that do not support multiple LUNs may STALL this command. 208 USBSTOR_ResetDevice(DeviceExtension->LowerDeviceObject, DeviceExtension); 209 210 DeviceExtension->MaxLUN = 0; 211 Status = STATUS_SUCCESS; 212 } 213 214 ExFreePoolWithTag(Buffer, USB_STOR_TAG); 215 return Status; 216 } 217 218 NTSTATUS 219 USBSTOR_ResetDevice( 220 IN PDEVICE_OBJECT DeviceObject, 221 IN PFDO_DEVICE_EXTENSION DeviceExtension) 222 { 223 NTSTATUS Status; 224 225 Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_RESET_DEVICE, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_OUT, 0, NULL); 226 return Status; 227 } 228 229 // if somebody wants to add UFI support, here is a useful function 230 #if 0 231 BOOLEAN 232 USBSTOR_IsFloppy( 233 IN PUCHAR Buffer, 234 IN ULONG BufferLength, 235 OUT PUCHAR MediumTypeCode) 236 { 237 PUFI_CAPACITY_FORMAT_HEADER FormatHeader; 238 PUFI_CAPACITY_DESCRIPTOR Descriptor; 239 ULONG Length, Index, BlockCount, BlockLength; 240 241 FormatHeader = (PUFI_CAPACITY_FORMAT_HEADER)Buffer; 242 ASSERT(FormatHeader->Reserved1 == 0x00); 243 ASSERT(FormatHeader->Reserved2 == 0x00); 244 ASSERT(FormatHeader->Reserved3 == 0x00); 245 246 // is there capacity data 247 if (!FormatHeader->CapacityLength) 248 { 249 DPRINT1("[USBSTOR] No capacity length\n"); 250 return FALSE; 251 } 252 253 // the format header are always 8 bytes in length 254 ASSERT((FormatHeader->CapacityLength & 0x7) == 0); 255 DPRINT1("CapacityLength %x\n", FormatHeader->CapacityLength); 256 257 // grab length and locate first descriptor 258 Length = FormatHeader->CapacityLength; 259 Descriptor = (PUFI_CAPACITY_DESCRIPTOR)(FormatHeader + 1); 260 for (Index = 0; Index < Length / sizeof(UFI_CAPACITY_DESCRIPTOR); Index++) 261 { 262 // blocks are little endian format 263 BlockCount = NTOHL(Descriptor->BlockCount); 264 BlockLength = NTOHL((Descriptor->BlockLengthByte0 << 24 | Descriptor->BlockLengthByte1 << 16 | Descriptor->BlockLengthByte2 << 8)); 265 266 DPRINT1("BlockCount %x BlockLength %x Code %x\n", BlockCount, BlockLength, Descriptor->Code); 267 268 if (BlockLength == 512 && BlockCount == 1440) 269 { 270 // 720 KB DD 271 *MediumTypeCode = 0x1E; 272 return TRUE; 273 } 274 else if (BlockLength == 1024 && BlockCount == 1232) 275 { 276 // 1,25 MB 277 *MediumTypeCode = 0x93; 278 return TRUE; 279 } 280 else if (BlockLength == 512 && BlockCount == 2880) 281 { 282 // 1,44MB KB DD 283 *MediumTypeCode = 0x94; 284 return TRUE; 285 } 286 287 Descriptor++; 288 } 289 290 return FALSE; 291 } 292 #endif 293