1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ANDROID_USB_DEVICE_OBJECT_H__ 18 #define ANDROID_USB_DEVICE_OBJECT_H__ 19 /** \file 20 This file consists of declaration of class AndroidUsbDeviceObject that 21 encapsulates an extension for KMDF device (FDO) object. 22 */ 23 24 #include "android_usb_wdf_object.h" 25 26 // Forward declaration for file object extension 27 class AndroidUsbFileObject; 28 29 /** AndroidUsbDeviceObject class encapsulates an extension for KMDF FDO device 30 object. Instances of this class must be allocated from NonPagedPool. 31 */ 32 class AndroidUsbDeviceObject : public AndroidUsbWdfObject { 33 public: 34 /** \brief Constructs the object. 35 36 This method must be called at low IRQL. 37 */ 38 AndroidUsbDeviceObject(); 39 40 /** \brief Destructs the object. 41 42 This method can be called at any IRQL. 43 */ 44 ~AndroidUsbDeviceObject(); 45 46 public: 47 /** \brief Creates and initializes FDO device object extension 48 49 This method is called from driver's OnAddDevice method in response to 50 AddDevice call from the PnP manager 51 @param device_init[in] A pointer to a framework-allocated WDFDEVICE_INIT 52 structure. 53 @return If the routine succeeds, it returns STATUS_SUCCESS. Otherwise, 54 it returns one of the error status values defined in ntstatus.h. 55 */ 56 NTSTATUS CreateFDODevice(PWDFDEVICE_INIT device_init); 57 58 /** \brief Resets target device 59 60 When executing this method instance of this class may be deleted! 61 This method must be called at PASSIVE IRQL. 62 @return STATUS_SUCCESS or an appropriate error code 63 */ 64 NTSTATUS ResetDevice(); 65 66 private: 67 /** \name Device event handlers and callbacks 68 */ 69 ///@{ 70 71 /** \brief Handler for PnP prepare hardware event 72 73 This method performs any operations that are needed to make a device 74 accessible to the driver. The framework calls this callback after the PnP 75 manager has assigned hardware resources to the device and after the device 76 has entered its uninitialized D0 state. This callback is called before 77 calling the driver's EvtDeviceD0Entry callback function. 78 This method is called at PASSIVE IRQL. 79 @param resources_raw[in] A handle to a framework resource-list object that 80 identifies the raw hardware resources that the PnP manager has 81 assigned to the device. 82 @param resources_translated[in] A handle to a framework resource-list 83 object that identifies the translated hardware resources that the 84 PnP manager has assigned to the device. 85 @return Successful status or an appropriate error code 86 */ 87 NTSTATUS OnEvtDevicePrepareHardware(WDFCMRESLIST resources_raw, 88 WDFCMRESLIST resources_translated); 89 90 /** \brief Handler for PnP release hardware event 91 92 This method performs operations that that are needed when a device is no 93 longer accessible. Framework calls the callback function if the device is 94 being removed, or if the PnP manager is attempting to redistribute hardware 95 resources. The framework calls the EvtDeviceReleaseHardware callback 96 function after the driver's device has been shut off, the PnP manager has 97 reclaimed the hardware resources that it assigned to the device, and the 98 device is no longer accessible. (The PCI configuration state is still 99 accessible.) Typically, a EvtDeviceReleaseHardware callback function unmaps 100 memory that the driver's EvtDevicePrepareHardware callback function mapped. 101 Usually, all other hardware shutdown operations should take place in the 102 driver's EvtDeviceD0Exit callback function. 103 This method is called at PASSIVE IRQL. 104 @param wdf_device[in] A handle to a framework device object. 105 @param resources_translated[in] A handle to a framework resource-list 106 object that identifies the translated hardware resources that the 107 PnP manager has assigned to the device. 108 @return Successful status or an appropriate error code 109 */ 110 NTSTATUS OnEvtDeviceReleaseHardware(WDFCMRESLIST resources_translated); 111 112 /** \brief Handler for create file event (request) 113 114 This method performs operations that are needed when an application 115 requests access to an item within this device path (including device 116 itself). This method is called synchronously, in the context of the 117 user thread that opens the item. 118 This method is called at PASSIVE IRQL. 119 @param request[in] A handle to a framework request object that represents 120 a file creation request. 121 @param wdf_fo[in] A handle to a framework file object that describes a 122 file that is being created with this request. 123 @return Successful status or an appropriate error code 124 */ 125 void OnEvtDeviceFileCreate(WDFREQUEST request, WDFFILEOBJECT wdf_fo); 126 127 /** \brief Entry point for PnP prepare hardware event 128 129 This callback performs any operations that are needed to make a device 130 accessible to the driver. The framework calls this callback after the PnP 131 manager has assigned hardware resources to the device and after the device 132 has entered its uninitialized D0 state. This callback is called before 133 calling the driver's EvtDeviceD0Entry callback function. 134 This callback is called at PASSIVE IRQL. 135 @param wdf_dev[in] A handle to a framework device object. 136 @param resources_raw[in] A handle to a framework resource-list object that 137 identifies the raw hardware resources that the PnP manager has 138 assigned to the device. 139 @param resources_translated[in] A handle to a framework resource-list 140 object that identifies the translated hardware resources that the 141 PnP manager has assigned to the device. 142 @return Successful status or an appropriate error code 143 */ 144 static NTSTATUS EvtDevicePrepareHardwareEntry(WDFDEVICE wdf_dev, 145 WDFCMRESLIST resources_raw, 146 WDFCMRESLIST resources_translated); 147 148 /** \brief Entry point for PnP release hardware event 149 150 This callback performs operations that that are needed when a device is no 151 longer accessible. Framework calls the callback function if the device is 152 being removed, or if the PnP manager is attempting to redistribute hardware 153 resources. The framework calls the EvtDeviceReleaseHardware callback 154 function after the driver's device has been shut off, the PnP manager has 155 reclaimed the hardware resources that it assigned to the device, and the 156 device is no longer accessible. (The PCI configuration state is still 157 accessible.) Typically, a EvtDeviceReleaseHardware callback function unmaps 158 memory that the driver's EvtDevicePrepareHardware callback function mapped. 159 Usually, all other hardware shutdown operations should take place in the 160 driver's EvtDeviceD0Exit callback function. 161 This callback is called at PASSIVE IRQL. 162 @param wdf_dev[in] A handle to a framework device object. 163 @param resources_translated[in] A handle to a framework resource-list 164 object that identifies the translated hardware resources that the 165 PnP manager has assigned to the device. 166 @return Successful status or an appropriate error code 167 */ 168 static NTSTATUS EvtDeviceReleaseHardwareEntry(WDFDEVICE wdf_dev, 169 WDFCMRESLIST resources_translated); 170 171 /** \brief Entry point for create file event (request) 172 173 This callback performs operations that that are needed when an application 174 requests access to a device. The framework calls a driver's 175 EvtDeviceFileCreate callback function when a user application or another 176 driver opens the device (or file on this device) to perform an I/O 177 operation, such as reading or writing a file. This callback function is 178 called synchronously, in the context of the user thread that opens the 179 device. 180 This callback is called at PASSIVE IRQL. 181 @param wdf_dev[in] A handle to a framework device object. 182 @param request[in] A handle to a framework request object that represents 183 a file creation request. 184 @param wdf_fo[in] A handle to a framework file object that describes a 185 file that is being created with this request. 186 @return Successful status or an appropriate error code 187 */ 188 static void EvtDeviceFileCreateEntry(WDFDEVICE wdf_dev, 189 WDFREQUEST request, 190 WDFFILEOBJECT wdf_fo); 191 192 ///@} 193 194 private: 195 /** \name I/O request event handlers and callbacks 196 */ 197 ///@{ 198 199 /** \brief Read event handler 200 201 This method is called when a read request comes to a file object opened 202 on this device. 203 This method can be called IRQL <= DISPATCH_LEVEL. 204 @param request[in] A handle to a framework request object. 205 @param length[in] The number of bytes to be read. 206 */ 207 void OnEvtIoRead(WDFREQUEST request, size_t length); 208 209 /** \brief Write event handler 210 211 This method is called when a write request comes to a file object opened 212 on this device. 213 This method can be called IRQL <= DISPATCH_LEVEL. 214 @param request[in] A handle to a framework request object. 215 @param length[in] The number of bytes to be written. 216 */ 217 void OnEvtIoWrite(WDFREQUEST request, size_t length); 218 219 /** \brief IOCTL event handler 220 221 This method is called when a device control request comes to a file object 222 opened on this device. 223 This method can be called IRQL <= DISPATCH_LEVEL. 224 @param request[in] A handle to a framework request object. 225 @param output_buf_len[in] The length, in bytes, of the request's output 226 buffer, if an output buffer is available. 227 @param input_buf_len[in] The length, in bytes, of the request's input 228 buffer, if an input buffer is available. 229 @param ioctl_code[in] The driver-defined or system-defined I/O control code 230 that is associated with the request. 231 */ 232 void OnEvtIoDeviceControl(WDFREQUEST request, 233 size_t output_buf_len, 234 size_t input_buf_len, 235 ULONG ioctl_code); 236 237 /** \brief Entry point for read event 238 239 This callback is called when a read request comes to a file object opened 240 on this device. 241 This callback can be called IRQL <= DISPATCH_LEVEL. 242 @param queue[in] A handle to the framework queue object that is associated 243 with the I/O request. 244 @param request[in] A handle to a framework request object. 245 @param length[in] The number of bytes to be read. 246 */ 247 static void EvtIoReadEntry(WDFQUEUE queue, 248 WDFREQUEST request, 249 size_t length); 250 251 /** \brief Entry point for write event 252 253 This callback is called when a write request comes to a file object opened 254 on this device. 255 This callback can be called IRQL <= DISPATCH_LEVEL. 256 @param queue[in] A handle to the framework queue object that is associated 257 with the I/O request. 258 @param request[in] A handle to a framework request object. 259 @param length[in] The number of bytes to be written. 260 */ 261 static void EvtIoWriteEntry(WDFQUEUE queue, 262 WDFREQUEST request, 263 size_t length); 264 265 /** \brief Entry point for device IOCTL event 266 267 This callback is called when a device control request comes to a file 268 object opened on this device. 269 This callback can be called IRQL <= DISPATCH_LEVEL. 270 @param queue[in] A handle to the framework queue object that is associated 271 with the I/O request. 272 @param request[in] A handle to a framework request object. 273 @param output_buf_len[in] The length, in bytes, of the request's output 274 buffer, if an output buffer is available. 275 @param input_buf_len[in] The length, in bytes, of the request's input 276 buffer, if an input buffer is available. 277 @param ioctl_code[in] The driver-defined or system-defined I/O control code 278 that is associated with the request. 279 */ 280 static void EvtIoDeviceControlEntry(WDFQUEUE queue, 281 WDFREQUEST request, 282 size_t output_buf_len, 283 size_t input_buf_len, 284 ULONG ioctl_code); 285 286 ///@} 287 288 public: 289 /** \name Device level I/O request handlers 290 */ 291 ///@{ 292 293 /** \brief Gets USB device descriptor 294 295 This method can be called at IRQL <= DISPATCH_LEVEL 296 @param request[in] A handle to a framework request object for this IOCTL. 297 @param output_buf_len[in] The length, in bytes, of the request's output 298 buffer, if an output buffer is available. 299 */ 300 void OnGetUsbDeviceDescriptorCtl(WDFREQUEST request, size_t output_buf_len); 301 302 /** \brief Gets USB configuration descriptor for the selected configuration. 303 304 This method can be called at IRQL <= DISPATCH_LEVEL 305 @param request[in] A handle to a framework request object for this IOCTL. 306 @param output_buf_len[in] The length, in bytes, of the request's output 307 buffer, if an output buffer is available. 308 */ 309 void OnGetUsbConfigDescriptorCtl(WDFREQUEST request, size_t output_buf_len); 310 311 /** \brief Gets USB configuration descriptor for the selected interface. 312 313 This method can be called at IRQL <= DISPATCH_LEVEL 314 @param request[in] A handle to a framework request object for this IOCTL. 315 @param output_buf_len[in] The length, in bytes, of the request's output 316 buffer, if an output buffer is available. 317 */ 318 void OnGetUsbInterfaceDescriptorCtl(WDFREQUEST request, size_t output_buf_len); 319 320 /** \brief Gets information about an endpoint. 321 322 This method can be called at IRQL <= DISPATCH_LEVEL 323 @param request[in] A handle to a framework request object for this IOCTL. 324 @param input_buf_len[in] The length, in bytes, of the request's input 325 buffer, if an input buffer is available. 326 @param output_buf_len[in] The length, in bytes, of the request's output 327 buffer, if an output buffer is available. 328 */ 329 void OnGetEndpointInformationCtl(WDFREQUEST request, 330 size_t input_buf_len, 331 size_t output_buf_len); 332 333 /** \brief Gets device serial number. 334 335 Serial number is returned in form of zero-terminated string that in the 336 output buffer. This method must be called at low IRQL. 337 @param request[in] A handle to a framework request object for this IOCTL. 338 @param output_buf_len[in] The length, in bytes, of the request's output 339 buffer, if an output buffer is available. 340 */ 341 void OnGetSerialNumberCtl(WDFREQUEST request, size_t output_buf_len); 342 343 ///@} 344 345 private: 346 /** \name Internal methods 347 */ 348 ///@{ 349 350 /** \brief Creates default request queue for this device. 351 352 In KMDF all I/O requests are coming through the queue object. So, in order 353 to enable our device to receive I/O requests we must create a queue for it. 354 This method is called at PASSIVE IRQL. 355 @return STATUS_SUCCESS or an appropriate error code. 356 */ 357 NTSTATUS CreateDefaultQueue(); 358 359 /** \brief Configures our device. 360 361 This method is called from the prepare hardware handler after underlying 362 FDO device has been created. 363 This method is called at PASSSIVE IRQL. 364 @return STATUS_SUCCESS or an appropriate error code. 365 */ 366 NTSTATUS ConfigureDevice(); 367 368 /** \brief Selects interfaces on our device. 369 370 This method is called from the prepare hardware handler after underlying 371 FDO device has been created and configured. 372 This method is called at PASSSIVE IRQL. 373 @return STATUS_SUCCESS or an appropriate error code. 374 */ 375 NTSTATUS SelectInterfaces(); 376 377 /** \brief Gets pipe index from a file name 378 379 This method is called from OnEvtDeviceFileCreate to determine index of 380 the pipe this file is addressing. 381 This method is called at PASSIVE IRQL. 382 @param file_path[in] Path to the file that being opened. 383 @return Pipe index or INVALID_UCHAR if index cannot be calculated. 384 */ 385 UCHAR GetPipeIndexFromFileName(PUNICODE_STRING file_path); 386 387 /** \brief Creates file object extension for a pipe 388 389 This method is called from OnEvtDeviceFileCreate to create an appropriate 390 file object extension for a particular pipe type. 391 This method is called at PASSIVE IRQL. 392 @param wdf_fo[in] KMDF file to extend. 393 @param wdf_pipe_obj[in] KMDF pipe for this extension 394 @param pipe_info[in] Pipe information 395 @param wdf_file_ext[out] Upon successfull completion will receive instance 396 of the extension. 397 @return STATUS_SUCCESS or an appropriate error code 398 */ 399 NTSTATUS CreatePipeFileObjectExt(WDFFILEOBJECT wdf_fo, 400 WDFUSBPIPE wdf_pipe_obj, 401 const WDF_USB_PIPE_INFORMATION* pipe_info, 402 AndroidUsbFileObject** wdf_file_ext); 403 404 ///@} 405 406 private: 407 /** \name Debugging support 408 */ 409 ///@{ 410 411 #if DBG 412 /// Prints USB_DEVICE_DESCRIPTOR to debug output 413 void PrintUsbDeviceDescriptor(const USB_DEVICE_DESCRIPTOR* desc); 414 415 /// Prints WDF_USB_DEVICE_INFORMATION to debug output 416 void PrintUsbTargedDeviceInformation(const WDF_USB_DEVICE_INFORMATION* info); 417 418 /// Prints USB_CONFIGURATION_DESCRIPTOR to debug output 419 void PrintConfigDescriptor(const USB_CONFIGURATION_DESCRIPTOR* desc, 420 ULONG size); 421 422 /// Prints WDF_USB_DEVICE_SELECT_CONFIG_PARAMS to debug output 423 void PrintSelectedConfig(const WDF_USB_DEVICE_SELECT_CONFIG_PARAMS* config); 424 425 /// Prints USB_INTERFACE_DESCRIPTOR to debug output 426 void PrintInterfaceDescriptor(const USB_INTERFACE_DESCRIPTOR* desc); 427 428 /// Prints WDF_USB_PIPE_INFORMATION to debug output 429 void PrintPipeInformation(const WDF_USB_PIPE_INFORMATION* info, 430 UCHAR pipe_index); 431 432 #endif // DBG 433 434 ///@} 435 436 public: 437 /// Gets WDF device handle for this device 438 __forceinline WDFDEVICE wdf_device() const { 439 return reinterpret_cast<WDFDEVICE>(wdf_object()); 440 } 441 442 /// Gets target USB device descriptor 443 __forceinline const USB_DEVICE_DESCRIPTOR* usb_device_descriptor() const { 444 return &usb_device_descriptor_; 445 } 446 447 /// Gets target USB device information 448 __forceinline const WDF_USB_DEVICE_INFORMATION* usb_device_info() const { 449 return &usb_device_info_; 450 } 451 452 /// Gets selected interface descriptor 453 __forceinline const USB_INTERFACE_DESCRIPTOR* interface_descriptor() const { 454 return &interface_descriptor_; 455 } 456 457 /// Gets target (PDO) device handle 458 __forceinline WDFUSBDEVICE wdf_target_device() const { 459 return wdf_target_device_; 460 } 461 462 /// Checks if target device has been created 463 __forceinline bool IsTaretDeviceCreated() const { 464 return (NULL != wdf_target_device()); 465 } 466 467 /// Gets USB configuration descriptor 468 __forceinline const USB_CONFIGURATION_DESCRIPTOR* configuration_descriptor() const { 469 return configuration_descriptor_; 470 } 471 472 /// Checks if device has been configured 473 __forceinline bool IsDeviceConfigured() const { 474 return (NULL != configuration_descriptor()); 475 } 476 477 /// Gets number of interfaces for this device 478 __forceinline UCHAR GetInterfaceCount() const { 479 ASSERT(IsDeviceConfigured()); 480 return IsDeviceConfigured() ? configuration_descriptor()->bNumInterfaces : 0; 481 } 482 483 /// Checks if this is "single interface" device 484 __forceinline bool IsSingleInterfaceDevice() const { 485 return (1 == GetInterfaceCount()); 486 } 487 488 /// Gets USB interface selected on this device 489 __forceinline WDFUSBINTERFACE wdf_usb_interface() const { 490 return wdf_usb_interface_; 491 } 492 493 /// Checks if an interface has been selected on this device 494 __forceinline bool IsInterfaceSelected() const { 495 return (NULL != wdf_usb_interface()); 496 } 497 498 /// Gets number of pipes configured on this device 499 __forceinline UCHAR configured_pipes_num() const { 500 return configured_pipes_num_; 501 } 502 503 /// Gets index of the bulk read pipe 504 __forceinline UCHAR bulk_read_pipe_index() const { 505 return bulk_read_pipe_index_; 506 } 507 508 /// Gets index of the bulk write pipe 509 __forceinline UCHAR bulk_write_pipe_index() const { 510 return bulk_write_pipe_index_; 511 } 512 513 /// Checks if this is a high speed device 514 __forceinline bool IsHighSpeed() const { 515 return (0 != (usb_device_info()->Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED)); 516 } 517 518 /// Checks if bulk read pipe index is known 519 __forceinline bool IsBulkReadPipeKnown() const { 520 return (INVALID_UCHAR != bulk_read_pipe_index()); 521 } 522 523 /// Checks if bulk write pipe index is known 524 __forceinline bool IsBulkWritePipeKnown() const { 525 return (INVALID_UCHAR != bulk_write_pipe_index()); 526 } 527 528 /// Gets device serial number string. Note that string may be 529 /// not zero-terminated. Use serial_number_len() to get actual 530 /// length of this string. 531 __forceinline const WCHAR* serial_number() const { 532 ASSERT(NULL != serial_number_handle_); 533 return (NULL != serial_number_handle_) ? 534 reinterpret_cast<const WCHAR*> 535 (WdfMemoryGetBuffer(serial_number_handle_, NULL)) : 536 NULL; 537 } 538 539 /// Gets length (in bytes) of device serial number string 540 __forceinline USHORT serial_number_char_len() const { 541 return serial_number_char_len_; 542 } 543 544 /// Gets length (in bytes) of device serial number string 545 __forceinline USHORT serial_number_byte_len() const { 546 return serial_number_char_len() * sizeof(WCHAR); 547 } 548 549 protected: 550 /// Target USB device descriptor 551 USB_DEVICE_DESCRIPTOR usb_device_descriptor_; 552 553 /// Target USB device information 554 WDF_USB_DEVICE_INFORMATION usb_device_info_; 555 556 /// Selected interface descriptor 557 USB_INTERFACE_DESCRIPTOR interface_descriptor_; 558 559 /// USB configuration descriptor 560 PUSB_CONFIGURATION_DESCRIPTOR configuration_descriptor_; 561 562 /// Target (PDO?) device handle 563 WDFUSBDEVICE wdf_target_device_; 564 565 /// USB interface selected on this device 566 WDFUSBINTERFACE wdf_usb_interface_; 567 568 /// Device serial number 569 WDFMEMORY serial_number_handle_; 570 571 /// Device serial number string length 572 USHORT serial_number_char_len_; 573 574 /// Number of pipes configured on this device 575 UCHAR configured_pipes_num_; 576 577 /// Index of the bulk read pipe 578 UCHAR bulk_read_pipe_index_; 579 580 /// Index of the bulk write pipe 581 UCHAR bulk_write_pipe_index_; 582 }; 583 584 /** \brief Gets device KMDF object extension for the given KMDF object 585 586 @param wdf_dev[in] KMDF handle describing device object 587 @return Instance of AndroidUsbDeviceObject associated with KMDF object or 588 NULL if association is not found. 589 */ 590 __forceinline AndroidUsbDeviceObject* GetAndroidUsbDeviceObjectFromHandle( 591 WDFDEVICE wdf_dev) { 592 AndroidUsbWdfObject* wdf_object_ext = 593 GetAndroidUsbWdfObjectFromHandle(wdf_dev); 594 ASSERT((NULL != wdf_object_ext) && 595 wdf_object_ext->Is(AndroidUsbWdfObjectTypeDevice)); 596 if ((NULL != wdf_object_ext) && 597 wdf_object_ext->Is(AndroidUsbWdfObjectTypeDevice)) { 598 return reinterpret_cast<AndroidUsbDeviceObject*>(wdf_object_ext); 599 } 600 return NULL; 601 } 602 603 #endif // ANDROID_USB_DEVICE_OBJECT_H__ 604