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