| /* |
| * Copyright (C) 2006 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef ANDROID_USB_DEVICE_OBJECT_H__ |
| #define ANDROID_USB_DEVICE_OBJECT_H__ |
| /** \file |
| This file consists of declaration of class AndroidUsbDeviceObject that |
| encapsulates an extension for KMDF device (FDO) object. |
| */ |
| |
| #include "android_usb_wdf_object.h" |
| |
| // Forward declaration for file object extension |
| class AndroidUsbFileObject; |
| |
| /** AndroidUsbDeviceObject class encapsulates an extension for KMDF FDO device |
| object. Instances of this class must be allocated from NonPagedPool. |
| */ |
| class AndroidUsbDeviceObject : public AndroidUsbWdfObject { |
| public: |
| /** \brief Constructs the object. |
| |
| This method must be called at low IRQL. |
| */ |
| AndroidUsbDeviceObject(); |
| |
| /** \brief Destructs the object. |
| |
| This method can be called at any IRQL. |
| */ |
| ~AndroidUsbDeviceObject(); |
| |
| public: |
| /** \brief Creates and initializes FDO device object extension |
| |
| This method is called from driver's OnAddDevice method in response to |
| AddDevice call from the PnP manager |
| @param device_init[in] A pointer to a framework-allocated WDFDEVICE_INIT |
| structure. |
| @return If the routine succeeds, it returns STATUS_SUCCESS. Otherwise, |
| it returns one of the error status values defined in ntstatus.h. |
| */ |
| NTSTATUS CreateFDODevice(PWDFDEVICE_INIT device_init); |
| |
| /** \brief Resets target device |
| |
| When executing this method instance of this class may be deleted! |
| This method must be called at PASSIVE IRQL. |
| @return STATUS_SUCCESS or an appropriate error code |
| */ |
| NTSTATUS ResetDevice(); |
| |
| private: |
| /** \name Device event handlers and callbacks |
| */ |
| ///@{ |
| |
| /** \brief Handler for PnP prepare hardware event |
| |
| This method performs any operations that are needed to make a device |
| accessible to the driver. The framework calls this callback after the PnP |
| manager has assigned hardware resources to the device and after the device |
| has entered its uninitialized D0 state. This callback is called before |
| calling the driver's EvtDeviceD0Entry callback function. |
| This method is called at PASSIVE IRQL. |
| @param resources_raw[in] A handle to a framework resource-list object that |
| identifies the raw hardware resources that the PnP manager has |
| assigned to the device. |
| @param resources_translated[in] A handle to a framework resource-list |
| object that identifies the translated hardware resources that the |
| PnP manager has assigned to the device. |
| @return Successful status or an appropriate error code |
| */ |
| NTSTATUS OnEvtDevicePrepareHardware(WDFCMRESLIST resources_raw, |
| WDFCMRESLIST resources_translated); |
| |
| /** \brief Handler for PnP release hardware event |
| |
| This method performs operations that that are needed when a device is no |
| longer accessible. Framework calls the callback function if the device is |
| being removed, or if the PnP manager is attempting to redistribute hardware |
| resources. The framework calls the EvtDeviceReleaseHardware callback |
| function after the driver's device has been shut off, the PnP manager has |
| reclaimed the hardware resources that it assigned to the device, and the |
| device is no longer accessible. (The PCI configuration state is still |
| accessible.) Typically, a EvtDeviceReleaseHardware callback function unmaps |
| memory that the driver's EvtDevicePrepareHardware callback function mapped. |
| Usually, all other hardware shutdown operations should take place in the |
| driver's EvtDeviceD0Exit callback function. |
| This method is called at PASSIVE IRQL. |
| @param wdf_device[in] A handle to a framework device object. |
| @param resources_translated[in] A handle to a framework resource-list |
| object that identifies the translated hardware resources that the |
| PnP manager has assigned to the device. |
| @return Successful status or an appropriate error code |
| */ |
| NTSTATUS OnEvtDeviceReleaseHardware(WDFCMRESLIST resources_translated); |
| |
| /** \brief Handler for create file event (request) |
| |
| This method performs operations that are needed when an application |
| requests access to an item within this device path (including device |
| itself). This method is called synchronously, in the context of the |
| user thread that opens the item. |
| This method is called at PASSIVE IRQL. |
| @param request[in] A handle to a framework request object that represents |
| a file creation request. |
| @param wdf_fo[in] A handle to a framework file object that describes a |
| file that is being created with this request. |
| @return Successful status or an appropriate error code |
| */ |
| void OnEvtDeviceFileCreate(WDFREQUEST request, WDFFILEOBJECT wdf_fo); |
| |
| /** \brief Entry point for PnP prepare hardware event |
| |
| This callback performs any operations that are needed to make a device |
| accessible to the driver. The framework calls this callback after the PnP |
| manager has assigned hardware resources to the device and after the device |
| has entered its uninitialized D0 state. This callback is called before |
| calling the driver's EvtDeviceD0Entry callback function. |
| This callback is called at PASSIVE IRQL. |
| @param wdf_dev[in] A handle to a framework device object. |
| @param resources_raw[in] A handle to a framework resource-list object that |
| identifies the raw hardware resources that the PnP manager has |
| assigned to the device. |
| @param resources_translated[in] A handle to a framework resource-list |
| object that identifies the translated hardware resources that the |
| PnP manager has assigned to the device. |
| @return Successful status or an appropriate error code |
| */ |
| static NTSTATUS EvtDevicePrepareHardwareEntry(WDFDEVICE wdf_dev, |
| WDFCMRESLIST resources_raw, |
| WDFCMRESLIST resources_translated); |
| |
| /** \brief Entry point for PnP release hardware event |
| |
| This callback performs operations that that are needed when a device is no |
| longer accessible. Framework calls the callback function if the device is |
| being removed, or if the PnP manager is attempting to redistribute hardware |
| resources. The framework calls the EvtDeviceReleaseHardware callback |
| function after the driver's device has been shut off, the PnP manager has |
| reclaimed the hardware resources that it assigned to the device, and the |
| device is no longer accessible. (The PCI configuration state is still |
| accessible.) Typically, a EvtDeviceReleaseHardware callback function unmaps |
| memory that the driver's EvtDevicePrepareHardware callback function mapped. |
| Usually, all other hardware shutdown operations should take place in the |
| driver's EvtDeviceD0Exit callback function. |
| This callback is called at PASSIVE IRQL. |
| @param wdf_dev[in] A handle to a framework device object. |
| @param resources_translated[in] A handle to a framework resource-list |
| object that identifies the translated hardware resources that the |
| PnP manager has assigned to the device. |
| @return Successful status or an appropriate error code |
| */ |
| static NTSTATUS EvtDeviceReleaseHardwareEntry(WDFDEVICE wdf_dev, |
| WDFCMRESLIST resources_translated); |
| |
| /** \brief Entry point for create file event (request) |
| |
| This callback performs operations that that are needed when an application |
| requests access to a device. The framework calls a driver's |
| EvtDeviceFileCreate callback function when a user application or another |
| driver opens the device (or file on this device) to perform an I/O |
| operation, such as reading or writing a file. This callback function is |
| called synchronously, in the context of the user thread that opens the |
| device. |
| This callback is called at PASSIVE IRQL. |
| @param wdf_dev[in] A handle to a framework device object. |
| @param request[in] A handle to a framework request object that represents |
| a file creation request. |
| @param wdf_fo[in] A handle to a framework file object that describes a |
| file that is being created with this request. |
| @return Successful status or an appropriate error code |
| */ |
| static void EvtDeviceFileCreateEntry(WDFDEVICE wdf_dev, |
| WDFREQUEST request, |
| WDFFILEOBJECT wdf_fo); |
| |
| ///@} |
| |
| private: |
| /** \name I/O request event handlers and callbacks |
| */ |
| ///@{ |
| |
| /** \brief Read event handler |
| |
| This method is called when a read request comes to a file object opened |
| on this device. |
| This method can be called IRQL <= DISPATCH_LEVEL. |
| @param request[in] A handle to a framework request object. |
| @param length[in] The number of bytes to be read. |
| */ |
| void OnEvtIoRead(WDFREQUEST request, size_t length); |
| |
| /** \brief Write event handler |
| |
| This method is called when a write request comes to a file object opened |
| on this device. |
| This method can be called IRQL <= DISPATCH_LEVEL. |
| @param request[in] A handle to a framework request object. |
| @param length[in] The number of bytes to be written. |
| */ |
| void OnEvtIoWrite(WDFREQUEST request, size_t length); |
| |
| /** \brief IOCTL event handler |
| |
| This method is called when a device control request comes to a file object |
| opened on this device. |
| This method can be called IRQL <= DISPATCH_LEVEL. |
| @param request[in] A handle to a framework request object. |
| @param output_buf_len[in] The length, in bytes, of the request's output |
| buffer, if an output buffer is available. |
| @param input_buf_len[in] The length, in bytes, of the request's input |
| buffer, if an input buffer is available. |
| @param ioctl_code[in] The driver-defined or system-defined I/O control code |
| that is associated with the request. |
| */ |
| void OnEvtIoDeviceControl(WDFREQUEST request, |
| size_t output_buf_len, |
| size_t input_buf_len, |
| ULONG ioctl_code); |
| |
| /** \brief Entry point for read event |
| |
| This callback is called when a read request comes to a file object opened |
| on this device. |
| This callback can be called IRQL <= DISPATCH_LEVEL. |
| @param queue[in] A handle to the framework queue object that is associated |
| with the I/O request. |
| @param request[in] A handle to a framework request object. |
| @param length[in] The number of bytes to be read. |
| */ |
| static void EvtIoReadEntry(WDFQUEUE queue, |
| WDFREQUEST request, |
| size_t length); |
| |
| /** \brief Entry point for write event |
| |
| This callback is called when a write request comes to a file object opened |
| on this device. |
| This callback can be called IRQL <= DISPATCH_LEVEL. |
| @param queue[in] A handle to the framework queue object that is associated |
| with the I/O request. |
| @param request[in] A handle to a framework request object. |
| @param length[in] The number of bytes to be written. |
| */ |
| static void EvtIoWriteEntry(WDFQUEUE queue, |
| WDFREQUEST request, |
| size_t length); |
| |
| /** \brief Entry point for device IOCTL event |
| |
| This callback is called when a device control request comes to a file |
| object opened on this device. |
| This callback can be called IRQL <= DISPATCH_LEVEL. |
| @param queue[in] A handle to the framework queue object that is associated |
| with the I/O request. |
| @param request[in] A handle to a framework request object. |
| @param output_buf_len[in] The length, in bytes, of the request's output |
| buffer, if an output buffer is available. |
| @param input_buf_len[in] The length, in bytes, of the request's input |
| buffer, if an input buffer is available. |
| @param ioctl_code[in] The driver-defined or system-defined I/O control code |
| that is associated with the request. |
| */ |
| static void EvtIoDeviceControlEntry(WDFQUEUE queue, |
| WDFREQUEST request, |
| size_t output_buf_len, |
| size_t input_buf_len, |
| ULONG ioctl_code); |
| |
| ///@} |
| |
| public: |
| /** \name Device level I/O request handlers |
| */ |
| ///@{ |
| |
| /** \brief Gets USB device descriptor |
| |
| This method can be called at IRQL <= DISPATCH_LEVEL |
| @param request[in] A handle to a framework request object for this IOCTL. |
| @param output_buf_len[in] The length, in bytes, of the request's output |
| buffer, if an output buffer is available. |
| */ |
| void OnGetUsbDeviceDescriptorCtl(WDFREQUEST request, size_t output_buf_len); |
| |
| /** \brief Gets USB configuration descriptor for the selected configuration. |
| |
| This method can be called at IRQL <= DISPATCH_LEVEL |
| @param request[in] A handle to a framework request object for this IOCTL. |
| @param output_buf_len[in] The length, in bytes, of the request's output |
| buffer, if an output buffer is available. |
| */ |
| void OnGetUsbConfigDescriptorCtl(WDFREQUEST request, size_t output_buf_len); |
| |
| /** \brief Gets USB configuration descriptor for the selected interface. |
| |
| This method can be called at IRQL <= DISPATCH_LEVEL |
| @param request[in] A handle to a framework request object for this IOCTL. |
| @param output_buf_len[in] The length, in bytes, of the request's output |
| buffer, if an output buffer is available. |
| */ |
| void OnGetUsbInterfaceDescriptorCtl(WDFREQUEST request, size_t output_buf_len); |
| |
| /** \brief Gets information about an endpoint. |
| |
| This method can be called at IRQL <= DISPATCH_LEVEL |
| @param request[in] A handle to a framework request object for this IOCTL. |
| @param input_buf_len[in] The length, in bytes, of the request's input |
| buffer, if an input buffer is available. |
| @param output_buf_len[in] The length, in bytes, of the request's output |
| buffer, if an output buffer is available. |
| */ |
| void OnGetEndpointInformationCtl(WDFREQUEST request, |
| size_t input_buf_len, |
| size_t output_buf_len); |
| |
| /** \brief Gets device serial number. |
| |
| Serial number is returned in form of zero-terminated string that in the |
| output buffer. This method must be called at low IRQL. |
| @param request[in] A handle to a framework request object for this IOCTL. |
| @param output_buf_len[in] The length, in bytes, of the request's output |
| buffer, if an output buffer is available. |
| */ |
| void OnGetSerialNumberCtl(WDFREQUEST request, size_t output_buf_len); |
| |
| ///@} |
| |
| private: |
| /** \name Internal methods |
| */ |
| ///@{ |
| |
| /** \brief Creates default request queue for this device. |
| |
| In KMDF all I/O requests are coming through the queue object. So, in order |
| to enable our device to receive I/O requests we must create a queue for it. |
| This method is called at PASSIVE IRQL. |
| @return STATUS_SUCCESS or an appropriate error code. |
| */ |
| NTSTATUS CreateDefaultQueue(); |
| |
| /** \brief Configures our device. |
| |
| This method is called from the prepare hardware handler after underlying |
| FDO device has been created. |
| This method is called at PASSSIVE IRQL. |
| @return STATUS_SUCCESS or an appropriate error code. |
| */ |
| NTSTATUS ConfigureDevice(); |
| |
| /** \brief Selects interfaces on our device. |
| |
| This method is called from the prepare hardware handler after underlying |
| FDO device has been created and configured. |
| This method is called at PASSSIVE IRQL. |
| @return STATUS_SUCCESS or an appropriate error code. |
| */ |
| NTSTATUS SelectInterfaces(); |
| |
| /** \brief Gets pipe index from a file name |
| |
| This method is called from OnEvtDeviceFileCreate to determine index of |
| the pipe this file is addressing. |
| This method is called at PASSIVE IRQL. |
| @param file_path[in] Path to the file that being opened. |
| @return Pipe index or INVALID_UCHAR if index cannot be calculated. |
| */ |
| UCHAR GetPipeIndexFromFileName(PUNICODE_STRING file_path); |
| |
| /** \brief Creates file object extension for a pipe |
| |
| This method is called from OnEvtDeviceFileCreate to create an appropriate |
| file object extension for a particular pipe type. |
| This method is called at PASSIVE IRQL. |
| @param wdf_fo[in] KMDF file to extend. |
| @param wdf_pipe_obj[in] KMDF pipe for this extension |
| @param pipe_info[in] Pipe information |
| @param wdf_file_ext[out] Upon successfull completion will receive instance |
| of the extension. |
| @return STATUS_SUCCESS or an appropriate error code |
| */ |
| NTSTATUS CreatePipeFileObjectExt(WDFFILEOBJECT wdf_fo, |
| WDFUSBPIPE wdf_pipe_obj, |
| const WDF_USB_PIPE_INFORMATION* pipe_info, |
| AndroidUsbFileObject** wdf_file_ext); |
| |
| ///@} |
| |
| private: |
| /** \name Debugging support |
| */ |
| ///@{ |
| |
| #if DBG |
| /// Prints USB_DEVICE_DESCRIPTOR to debug output |
| void PrintUsbDeviceDescriptor(const USB_DEVICE_DESCRIPTOR* desc); |
| |
| /// Prints WDF_USB_DEVICE_INFORMATION to debug output |
| void PrintUsbTargedDeviceInformation(const WDF_USB_DEVICE_INFORMATION* info); |
| |
| /// Prints USB_CONFIGURATION_DESCRIPTOR to debug output |
| void PrintConfigDescriptor(const USB_CONFIGURATION_DESCRIPTOR* desc, |
| ULONG size); |
| |
| /// Prints WDF_USB_DEVICE_SELECT_CONFIG_PARAMS to debug output |
| void PrintSelectedConfig(const WDF_USB_DEVICE_SELECT_CONFIG_PARAMS* config); |
| |
| /// Prints USB_INTERFACE_DESCRIPTOR to debug output |
| void PrintInterfaceDescriptor(const USB_INTERFACE_DESCRIPTOR* desc); |
| |
| /// Prints WDF_USB_PIPE_INFORMATION to debug output |
| void PrintPipeInformation(const WDF_USB_PIPE_INFORMATION* info, |
| UCHAR pipe_index); |
| |
| #endif // DBG |
| |
| ///@} |
| |
| public: |
| /// Gets WDF device handle for this device |
| __forceinline WDFDEVICE wdf_device() const { |
| return reinterpret_cast<WDFDEVICE>(wdf_object()); |
| } |
| |
| /// Gets target USB device descriptor |
| __forceinline const USB_DEVICE_DESCRIPTOR* usb_device_descriptor() const { |
| return &usb_device_descriptor_; |
| } |
| |
| /// Gets target USB device information |
| __forceinline const WDF_USB_DEVICE_INFORMATION* usb_device_info() const { |
| return &usb_device_info_; |
| } |
| |
| /// Gets selected interface descriptor |
| __forceinline const USB_INTERFACE_DESCRIPTOR* interface_descriptor() const { |
| return &interface_descriptor_; |
| } |
| |
| /// Gets target (PDO) device handle |
| __forceinline WDFUSBDEVICE wdf_target_device() const { |
| return wdf_target_device_; |
| } |
| |
| /// Checks if target device has been created |
| __forceinline bool IsTaretDeviceCreated() const { |
| return (NULL != wdf_target_device()); |
| } |
| |
| /// Gets USB configuration descriptor |
| __forceinline const USB_CONFIGURATION_DESCRIPTOR* configuration_descriptor() const { |
| return configuration_descriptor_; |
| } |
| |
| /// Checks if device has been configured |
| __forceinline bool IsDeviceConfigured() const { |
| return (NULL != configuration_descriptor()); |
| } |
| |
| /// Gets number of interfaces for this device |
| __forceinline UCHAR GetInterfaceCount() const { |
| ASSERT(IsDeviceConfigured()); |
| return IsDeviceConfigured() ? configuration_descriptor()->bNumInterfaces : 0; |
| } |
| |
| /// Checks if this is "single interface" device |
| __forceinline bool IsSingleInterfaceDevice() const { |
| return (1 == GetInterfaceCount()); |
| } |
| |
| /// Gets USB interface selected on this device |
| __forceinline WDFUSBINTERFACE wdf_usb_interface() const { |
| return wdf_usb_interface_; |
| } |
| |
| /// Checks if an interface has been selected on this device |
| __forceinline bool IsInterfaceSelected() const { |
| return (NULL != wdf_usb_interface()); |
| } |
| |
| /// Gets number of pipes configured on this device |
| __forceinline UCHAR configured_pipes_num() const { |
| return configured_pipes_num_; |
| } |
| |
| /// Gets index of the bulk read pipe |
| __forceinline UCHAR bulk_read_pipe_index() const { |
| return bulk_read_pipe_index_; |
| } |
| |
| /// Gets index of the bulk write pipe |
| __forceinline UCHAR bulk_write_pipe_index() const { |
| return bulk_write_pipe_index_; |
| } |
| |
| /// Checks if this is a high speed device |
| __forceinline bool IsHighSpeed() const { |
| return (0 != (usb_device_info()->Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED)); |
| } |
| |
| /// Checks if bulk read pipe index is known |
| __forceinline bool IsBulkReadPipeKnown() const { |
| return (INVALID_UCHAR != bulk_read_pipe_index()); |
| } |
| |
| /// Checks if bulk write pipe index is known |
| __forceinline bool IsBulkWritePipeKnown() const { |
| return (INVALID_UCHAR != bulk_write_pipe_index()); |
| } |
| |
| /// Gets device serial number string. Note that string may be |
| /// not zero-terminated. Use serial_number_len() to get actual |
| /// length of this string. |
| __forceinline const WCHAR* serial_number() const { |
| ASSERT(NULL != serial_number_handle_); |
| return (NULL != serial_number_handle_) ? |
| reinterpret_cast<const WCHAR*> |
| (WdfMemoryGetBuffer(serial_number_handle_, NULL)) : |
| NULL; |
| } |
| |
| /// Gets length (in bytes) of device serial number string |
| __forceinline USHORT serial_number_char_len() const { |
| return serial_number_char_len_; |
| } |
| |
| /// Gets length (in bytes) of device serial number string |
| __forceinline USHORT serial_number_byte_len() const { |
| return serial_number_char_len() * sizeof(WCHAR); |
| } |
| |
| protected: |
| /// Target USB device descriptor |
| USB_DEVICE_DESCRIPTOR usb_device_descriptor_; |
| |
| /// Target USB device information |
| WDF_USB_DEVICE_INFORMATION usb_device_info_; |
| |
| /// Selected interface descriptor |
| USB_INTERFACE_DESCRIPTOR interface_descriptor_; |
| |
| /// USB configuration descriptor |
| PUSB_CONFIGURATION_DESCRIPTOR configuration_descriptor_; |
| |
| /// Target (PDO?) device handle |
| WDFUSBDEVICE wdf_target_device_; |
| |
| /// USB interface selected on this device |
| WDFUSBINTERFACE wdf_usb_interface_; |
| |
| /// Device serial number |
| WDFMEMORY serial_number_handle_; |
| |
| /// Device serial number string length |
| USHORT serial_number_char_len_; |
| |
| /// Number of pipes configured on this device |
| UCHAR configured_pipes_num_; |
| |
| /// Index of the bulk read pipe |
| UCHAR bulk_read_pipe_index_; |
| |
| /// Index of the bulk write pipe |
| UCHAR bulk_write_pipe_index_; |
| }; |
| |
| /** \brief Gets device KMDF object extension for the given KMDF object |
| |
| @param wdf_dev[in] KMDF handle describing device object |
| @return Instance of AndroidUsbDeviceObject associated with KMDF object or |
| NULL if association is not found. |
| */ |
| __forceinline AndroidUsbDeviceObject* GetAndroidUsbDeviceObjectFromHandle( |
| WDFDEVICE wdf_dev) { |
| AndroidUsbWdfObject* wdf_object_ext = |
| GetAndroidUsbWdfObjectFromHandle(wdf_dev); |
| ASSERT((NULL != wdf_object_ext) && |
| wdf_object_ext->Is(AndroidUsbWdfObjectTypeDevice)); |
| if ((NULL != wdf_object_ext) && |
| wdf_object_ext->Is(AndroidUsbWdfObjectTypeDevice)) { |
| return reinterpret_cast<AndroidUsbDeviceObject*>(wdf_object_ext); |
| } |
| return NULL; |
| } |
| |
| #endif // ANDROID_USB_DEVICE_OBJECT_H__ |