• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
wdf_device()438   __forceinline WDFDEVICE wdf_device() const {
439     return reinterpret_cast<WDFDEVICE>(wdf_object());
440   }
441 
442   /// Gets target USB device descriptor
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
usb_device_info()448   __forceinline const WDF_USB_DEVICE_INFORMATION* usb_device_info() const {
449     return &usb_device_info_;
450   }
451 
452   /// Gets selected interface descriptor
interface_descriptor()453   __forceinline const USB_INTERFACE_DESCRIPTOR* interface_descriptor() const {
454     return &interface_descriptor_;
455   }
456 
457   /// Gets target (PDO) device handle
wdf_target_device()458   __forceinline WDFUSBDEVICE wdf_target_device() const {
459     return wdf_target_device_;
460   }
461 
462   /// Checks if target device has been created
IsTaretDeviceCreated()463   __forceinline bool IsTaretDeviceCreated() const {
464     return (NULL != wdf_target_device());
465   }
466 
467   /// Gets USB configuration descriptor
configuration_descriptor()468   __forceinline const USB_CONFIGURATION_DESCRIPTOR* configuration_descriptor() const {
469     return configuration_descriptor_;
470   }
471 
472   /// Checks if device has been configured
IsDeviceConfigured()473   __forceinline bool IsDeviceConfigured() const {
474     return (NULL != configuration_descriptor());
475   }
476 
477   /// Gets number of interfaces for this device
GetInterfaceCount()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
IsSingleInterfaceDevice()484   __forceinline bool IsSingleInterfaceDevice() const {
485     return (1 == GetInterfaceCount());
486   }
487 
488   /// Gets USB interface selected on this device
wdf_usb_interface()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
IsInterfaceSelected()494   __forceinline bool IsInterfaceSelected() const {
495     return (NULL != wdf_usb_interface());
496   }
497 
498   /// Gets number of pipes configured on this device
configured_pipes_num()499   __forceinline UCHAR configured_pipes_num() const {
500     return configured_pipes_num_;
501   }
502 
503   /// Gets index of the bulk read pipe
bulk_read_pipe_index()504   __forceinline UCHAR bulk_read_pipe_index() const {
505     return bulk_read_pipe_index_;
506   }
507 
508   /// Gets index of the bulk write pipe
bulk_write_pipe_index()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
IsHighSpeed()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
IsBulkReadPipeKnown()519   __forceinline bool IsBulkReadPipeKnown() const {
520     return (INVALID_UCHAR != bulk_read_pipe_index());
521   }
522 
523   /// Checks if bulk write pipe index is known
IsBulkWritePipeKnown()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.
serial_number()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
serial_number_char_len()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
serial_number_byte_len()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 */
GetAndroidUsbDeviceObjectFromHandle(WDFDEVICE wdf_dev)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