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