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 NTSTATUS 17 NTAPI 18 USBSTOR_GetDescriptor( 19 IN PDEVICE_OBJECT DeviceObject, 20 IN UCHAR DescriptorType, 21 IN ULONG DescriptorLength, 22 IN UCHAR DescriptorIndex, 23 IN LANGID LanguageId, 24 OUT PVOID *OutDescriptor) 25 { 26 PURB Urb; 27 NTSTATUS Status; 28 PVOID Descriptor; 29 30 ASSERT(DeviceObject); 31 ASSERT(OutDescriptor); 32 ASSERT(DescriptorLength); 33 34 // first allocate descriptor buffer 35 Descriptor = AllocateItem(NonPagedPool, DescriptorLength); 36 if (!Descriptor) 37 { 38 // no memory 39 return STATUS_INSUFFICIENT_RESOURCES; 40 } 41 42 Urb = (PURB) AllocateItem(NonPagedPool, sizeof(URB)); 43 if (!Urb) 44 { 45 // no memory 46 FreeItem(Descriptor); 47 return STATUS_INSUFFICIENT_RESOURCES; 48 } 49 50 // initialize urb 51 UsbBuildGetDescriptorRequest(Urb, 52 sizeof(Urb->UrbControlDescriptorRequest), 53 DescriptorType, 54 DescriptorIndex, 55 LanguageId, 56 Descriptor, 57 NULL, 58 DescriptorLength, 59 NULL); 60 61 // submit urb 62 Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb); 63 64 FreeItem(Urb); 65 66 if (NT_SUCCESS(Status)) 67 { 68 *OutDescriptor = Descriptor; 69 } 70 71 return Status; 72 } 73 74 NTSTATUS 75 USBSTOR_GetDescriptors( 76 IN PDEVICE_OBJECT DeviceObject) 77 { 78 NTSTATUS Status; 79 PFDO_DEVICE_EXTENSION DeviceExtension; 80 USHORT DescriptorLength; 81 82 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 83 84 // first get device descriptor 85 Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_DEVICE_DESCRIPTOR_TYPE, sizeof(USB_DEVICE_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->DeviceDescriptor); 86 if (!NT_SUCCESS(Status)) 87 { 88 DeviceExtension->DeviceDescriptor = NULL; 89 return Status; 90 } 91 92 // now get basic configuration descriptor 93 Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, sizeof(USB_CONFIGURATION_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor); 94 if (!NT_SUCCESS(Status)) 95 { 96 FreeItem(DeviceExtension->DeviceDescriptor); 97 DeviceExtension->DeviceDescriptor = NULL; 98 return Status; 99 } 100 101 // backup length 102 DescriptorLength = DeviceExtension->ConfigurationDescriptor->wTotalLength; 103 104 // release basic descriptor 105 FreeItem(DeviceExtension->ConfigurationDescriptor); 106 DeviceExtension->ConfigurationDescriptor = NULL; 107 108 // allocate full descriptor 109 Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, DescriptorLength, 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor); 110 if (!NT_SUCCESS(Status)) 111 { 112 FreeItem(DeviceExtension->DeviceDescriptor); 113 DeviceExtension->DeviceDescriptor = NULL; 114 return Status; 115 } 116 117 // check if there is a serial number provided 118 if (DeviceExtension->DeviceDescriptor->iSerialNumber) 119 { 120 // get serial number 121 Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_STRING_DESCRIPTOR_TYPE, MAXIMUM_USB_STRING_LENGTH, DeviceExtension->DeviceDescriptor->iSerialNumber, 0x0409, (PVOID*)&DeviceExtension->SerialNumber); 122 if (!NT_SUCCESS(Status)) 123 { 124 FreeItem(DeviceExtension->DeviceDescriptor); 125 DeviceExtension->DeviceDescriptor = NULL; 126 127 FreeItem(DeviceExtension->ConfigurationDescriptor); 128 DeviceExtension->ConfigurationDescriptor = NULL; 129 130 DeviceExtension->SerialNumber = NULL; 131 return Status; 132 } 133 } 134 135 return Status; 136 } 137 138 NTSTATUS 139 NTAPI 140 USBSTOR_ScanConfigurationDescriptor( 141 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, 142 OUT PUSB_INTERFACE_DESCRIPTOR *OutInterfaceDescriptor, 143 OUT PUSB_ENDPOINT_DESCRIPTOR *InEndpointDescriptor, 144 OUT PUSB_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor) 145 { 146 PUSB_CONFIGURATION_DESCRIPTOR CurrentDescriptor; 147 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor; 148 149 ASSERT(ConfigurationDescriptor); 150 ASSERT(OutInterfaceDescriptor); 151 ASSERT(InEndpointDescriptor); 152 ASSERT(OutEndpointDescriptor); 153 154 *OutInterfaceDescriptor = NULL; 155 *InEndpointDescriptor = NULL; 156 *OutEndpointDescriptor = NULL; 157 158 // start scanning 159 CurrentDescriptor = ConfigurationDescriptor; 160 161 do 162 { 163 if (CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) 164 { 165 if (*OutInterfaceDescriptor) 166 { 167 // we only process the first interface descriptor as ms does -> see documentation 168 break; 169 } 170 171 // store interface descriptor 172 *OutInterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)CurrentDescriptor; 173 } 174 else if (CurrentDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE) 175 { 176 EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)CurrentDescriptor; 177 178 ASSERT(*OutInterfaceDescriptor); 179 180 // get endpoint type 181 if ((EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) 182 { 183 if (USB_ENDPOINT_DIRECTION_IN(EndpointDescriptor->bEndpointAddress)) 184 { 185 *InEndpointDescriptor = EndpointDescriptor; 186 } 187 else 188 { 189 *OutEndpointDescriptor = EndpointDescriptor; 190 } 191 } 192 else if ((EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT) 193 { 194 UNIMPLEMENTED; 195 } 196 } 197 198 // move to next descriptor 199 CurrentDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)((ULONG_PTR)CurrentDescriptor + CurrentDescriptor->bLength); 200 201 // was it the last descriptor 202 if ((ULONG_PTR)CurrentDescriptor >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength)) 203 { 204 break; 205 } 206 207 } while(TRUE); 208 209 // check if everything has been found 210 if (*OutInterfaceDescriptor == NULL || *InEndpointDescriptor == NULL || *OutEndpointDescriptor == NULL) 211 { 212 DPRINT1("USBSTOR_ScanConfigurationDescriptor: Failed to find InterfaceDescriptor %p InEndpointDescriptor %p OutEndpointDescriptor %p\n", *OutInterfaceDescriptor, *InEndpointDescriptor, *OutEndpointDescriptor); 213 return STATUS_UNSUCCESSFUL; 214 } 215 216 return STATUS_SUCCESS; 217 } 218 219 VOID 220 DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor) 221 { 222 DPRINT1("Dumping ConfigurationDescriptor %p\n", ConfigurationDescriptor); 223 DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength); 224 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType); 225 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength); 226 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces); 227 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue); 228 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration); 229 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes); 230 DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower); 231 } 232 233 NTSTATUS 234 USBSTOR_SelectConfigurationAndInterface( 235 IN PDEVICE_OBJECT DeviceObject, 236 IN PFDO_DEVICE_EXTENSION DeviceExtension) 237 { 238 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; 239 PUSB_ENDPOINT_DESCRIPTOR InEndpointDescriptor, OutEndpointDescriptor; 240 NTSTATUS Status; 241 PURB Urb; 242 PUSBD_INTERFACE_LIST_ENTRY InterfaceList; 243 244 Status = USBSTOR_ScanConfigurationDescriptor(DeviceExtension->ConfigurationDescriptor, &InterfaceDescriptor, &InEndpointDescriptor, &OutEndpointDescriptor); 245 if (!NT_SUCCESS(Status)) 246 { 247 return Status; 248 } 249 250 // now allocate one interface entry and terminating null entry 251 InterfaceList = (PUSBD_INTERFACE_LIST_ENTRY)AllocateItem(PagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * 2); 252 if (!InterfaceList) 253 { 254 return STATUS_INSUFFICIENT_RESOURCES; 255 } 256 257 // initialize interface list entry 258 InterfaceList[0].InterfaceDescriptor = InterfaceDescriptor; 259 260 // now allocate the urb 261 Urb = USBD_CreateConfigurationRequestEx(DeviceExtension->ConfigurationDescriptor, InterfaceList); 262 if (!Urb) 263 { 264 FreeItem(InterfaceList); 265 return STATUS_INSUFFICIENT_RESOURCES; 266 } 267 268 269 ASSERT(InterfaceList[0].Interface); 270 271 // submit urb 272 Status = USBSTOR_SyncUrbRequest(DeviceExtension->LowerDeviceObject, Urb); 273 if (!NT_SUCCESS(Status)) 274 { 275 // failed to set configuration 276 DPRINT1("USBSTOR_SelectConfiguration failed to set interface %x\n", Status); 277 FreeItem(InterfaceList); 278 ExFreePoolWithTag(Urb, 0); 279 return Status; 280 } 281 282 // backup interface information 283 DeviceExtension->InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)AllocateItem(NonPagedPool, Urb->UrbSelectConfiguration.Interface.Length); 284 if (!DeviceExtension->InterfaceInformation) 285 { 286 FreeItem(InterfaceList); 287 ExFreePoolWithTag(Urb, 0); 288 return STATUS_INSUFFICIENT_RESOURCES; 289 } 290 291 // copy interface information 292 RtlCopyMemory(DeviceExtension->InterfaceInformation, &Urb->UrbSelectConfiguration.Interface, Urb->UrbSelectConfiguration.Interface.Length); 293 294 // store pipe handle 295 DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle; 296 297 // now prepare interface urb 298 UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting); 299 300 // copy interface information structure back - as offset for SelectConfiguration / SelectInterface request do differ 301 RtlCopyMemory(&Urb->UrbSelectInterface.Interface, DeviceExtension->InterfaceInformation, DeviceExtension->InterfaceInformation->Length); 302 303 // now select the interface 304 Status = USBSTOR_SyncUrbRequest(DeviceExtension->LowerDeviceObject, Urb); 305 if (NT_SUCCESS(Status)) 306 { 307 // update configuration info 308 ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceInformation->Length); 309 RtlCopyMemory(DeviceExtension->InterfaceInformation, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length); 310 } 311 312 FreeItem(InterfaceList); 313 ExFreePoolWithTag(Urb, 0); 314 315 return Status; 316 } 317 318 NTSTATUS 319 USBSTOR_GetPipeHandles( 320 IN PFDO_DEVICE_EXTENSION DeviceExtension) 321 { 322 ULONG Index; 323 BOOLEAN BulkInFound = FALSE, BulkOutFound = FALSE; 324 325 // enumerate all pipes and extract bulk-in / bulk-out pipe handle 326 for (Index = 0; Index < DeviceExtension->InterfaceInformation->NumberOfPipes; Index++) 327 { 328 if (DeviceExtension->InterfaceInformation->Pipes[Index].PipeType == UsbdPipeTypeBulk) 329 { 330 if (USB_ENDPOINT_DIRECTION_IN(DeviceExtension->InterfaceInformation->Pipes[Index].EndpointAddress)) 331 { 332 DeviceExtension->BulkInPipeIndex = Index; 333 334 // there should not be another bulk in pipe 335 ASSERT(BulkInFound == FALSE); 336 BulkInFound = TRUE; 337 } 338 else 339 { 340 DeviceExtension->BulkOutPipeIndex = Index; 341 342 // there should not be another bulk out pipe 343 ASSERT(BulkOutFound == FALSE); 344 BulkOutFound = TRUE; 345 } 346 } 347 } 348 349 if (!BulkInFound || !BulkOutFound) 350 { 351 // WTF? usb port driver does not give us bulk pipe access 352 DPRINT1("USBSTOR_GetPipeHandles> BulkInFound %c BulkOutFound %c missing!!!\n", BulkInFound, BulkOutFound); 353 return STATUS_DEVICE_CONFIGURATION_ERROR; 354 } 355 356 return STATUS_SUCCESS; 357 } 358