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