1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxUsbDeviceAPI.cpp
8 
9 Abstract:
10 
11 
12 Author:
13 
14 Environment:
15 
16     kernel mode only
17 
18 Revision History:
19 
20 --*/
21 
22 #include "fxusbpch.hpp"
23 
24 extern "C" {
25 #include "FxUsbDeviceApiKm.tmh"
26 }
27 
28 //
29 // Extern "C" all APIs
30 //
31 extern "C" {
32 
33 _Must_inspect_result_
34 __drv_maxIRQL(DISPATCH_LEVEL)
35 NTSTATUS
36 WDFAPI
37 WDFEXPORT(WdfUsbTargetDeviceRetrieveCurrentFrameNumber)(
38     __in
39     PWDF_DRIVER_GLOBALS DriverGlobals,
40     __in
41     WDFUSBDEVICE UsbDevice,
42     __out
43     PULONG CurrentFrameNumber
44     )
45 {
46     DDI_ENTRY();
47 
48     PFX_DRIVER_GLOBALS pFxDriverGlobals;
49     FxUsbDevice* pUsbDevice;
50 
51     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
52                                    UsbDevice,
53                                    FX_TYPE_IO_TARGET_USB_DEVICE,
54                                    (PVOID*) &pUsbDevice,
55                                    &pFxDriverGlobals);
56 
57     FxPointerNotNull(pFxDriverGlobals, CurrentFrameNumber);
58 
59     return pUsbDevice->GetCurrentFrameNumber(CurrentFrameNumber);
60 }
61 
62 _Must_inspect_result_
63 __drv_maxIRQL(PASSIVE_LEVEL)
64 NTSTATUS
65 WDFAPI
66 WDFEXPORT(WdfUsbTargetDeviceSendUrbSynchronously)(
67     __in
68     PWDF_DRIVER_GLOBALS DriverGlobals,
69     __in
70     WDFUSBDEVICE UsbDevice,
71     __in_opt
72     WDFREQUEST Request,
73     __in_opt
74     PWDF_REQUEST_SEND_OPTIONS RequestOptions,
75     __in_xcount("union bug in SAL")
76     PURB Urb
77     )
78 {
79     PFX_DRIVER_GLOBALS pFxDriverGlobals;
80     FxRequestBuffer buf;
81     NTSTATUS status;
82     FxUsbDevice* pUsbDevice;
83 
84     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
85                                    UsbDevice,
86                                    FX_TYPE_IO_TARGET_USB_DEVICE,
87                                    (PVOID*) &pUsbDevice,
88                                    &pFxDriverGlobals);
89 
90     FxUsbUrbContext context;
91     FxSyncRequest request(pFxDriverGlobals, &context, Request);
92 
93     //
94     // FxSyncRequest always succeesds for KM but can fail for UM.
95     //
96     status = request.Initialize();
97     if (!NT_SUCCESS(status)) {
98         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
99                             "Failed to initialize FxSyncRequest");
100         return status;
101     }
102 
103     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
104                         "WDFUSBDEVICE %p, Urb %p", UsbDevice, Urb);
105 
106     FxPointerNotNull(pFxDriverGlobals, Urb);
107 
108     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
109     if (!NT_SUCCESS(status)) {
110         return status;
111     }
112 
113     status = FxValidateRequestOptions(pFxDriverGlobals, RequestOptions);
114     if (!NT_SUCCESS(status)) {
115         return status;
116     }
117 
118     buf.SetBuffer(Urb, 0);
119 
120     status = FxFormatUrbRequest(pFxDriverGlobals,
121                                 pUsbDevice,
122                                 request.m_TrueRequest,
123                                 &buf,
124                                 pUsbDevice->GetUrbType(),
125                                 pUsbDevice->GetUSBDHandle());
126 
127     if (NT_SUCCESS(status)) {
128         DoTraceLevelMessage(
129             pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
130             "WDFUSBDEVICE %p, WDFREQUEST %p being submitted",
131             UsbDevice, request.m_TrueRequest->GetTraceObjectHandle());
132 
133         status = pUsbDevice->SubmitSync(request.m_TrueRequest, RequestOptions);
134     }
135 
136     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
137                         "Device %p, Urb %p, %!STATUS!",
138                         UsbDevice, Urb, status);
139 
140     return status;
141 }
142 
143 _Must_inspect_result_
144 __drv_maxIRQL(DISPATCH_LEVEL)
145 NTSTATUS
146 WDFAPI
147 WDFEXPORT(WdfUsbTargetDeviceFormatRequestForUrb)(
148     __in
149     PWDF_DRIVER_GLOBALS DriverGlobals,
150     __in
151     WDFUSBDEVICE UsbDevice,
152     __in
153     WDFREQUEST Request,
154     __in
155     WDFMEMORY UrbMemory,
156     __in_opt
157     PWDFMEMORY_OFFSET UrbOffsets
158     )
159 {
160     DDI_ENTRY();
161 
162     PFX_DRIVER_GLOBALS pFxDriverGlobals;
163     IFxMemory* pMemory;
164     FxUsbDevice* pUsbDevice;
165     FxRequestBuffer buf;
166     FxRequest* pRequest;
167     NTSTATUS status;
168     size_t bufferSize;
169 
170     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
171                                    UsbDevice,
172                                    FX_TYPE_IO_TARGET_USB_DEVICE,
173                                    (PVOID*) &pUsbDevice,
174                                    &pFxDriverGlobals);
175 
176     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
177                         "WDFUSBDEVICE %p, Request %p, Memory %p",
178                         UsbDevice, Request, UrbMemory);
179 
180     FxPointerNotNull(pFxDriverGlobals, UrbMemory);
181 
182     FxObjectHandleGetPtr(pFxDriverGlobals,
183                          UrbMemory,
184                          IFX_TYPE_MEMORY,
185                          (PVOID*) &pMemory);
186 
187     FxObjectHandleGetPtr(pFxDriverGlobals,
188                          Request,
189                          FX_TYPE_REQUEST,
190                          (PVOID*) &pRequest);
191 
192     status = pMemory->ValidateMemoryOffsets(UrbOffsets);
193     if (!NT_SUCCESS(status)) {
194         return status;
195     }
196 
197     bufferSize = pMemory->GetBufferSize();
198     if (UrbOffsets != NULL && UrbOffsets->BufferOffset > 0) {
199         bufferSize -= UrbOffsets->BufferOffset;
200     }
201 
202     if (bufferSize < sizeof(_URB_HEADER)) {
203         status = STATUS_INVALID_PARAMETER;
204         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
205                             "UrbMemory %p buffer size, %I64d, smaller then"
206                             "_URB_HEADER, %!STATUS!",
207                              UrbMemory, pMemory->GetBufferSize(), status);
208         return status;
209     }
210 
211     buf.SetMemory(pMemory, UrbOffsets);
212 
213     status = FxFormatUrbRequest(pFxDriverGlobals,
214                                 pUsbDevice,
215                                 pRequest,
216                                 &buf,
217                                 pUsbDevice->GetUrbType(),
218                                 pUsbDevice->GetUSBDHandle());
219 
220     if (NT_SUCCESS(status)) {
221         FxUsbUrbContext* pContext;
222         pContext = (FxUsbUrbContext*) pRequest->GetContext();
223 
224         pContext->SetUsbType(WdfUsbRequestTypeDeviceUrb);
225         pContext->m_UsbParameters.Parameters.DeviceUrb.Buffer = UrbMemory;
226     }
227 
228     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
229                         "WDFUSBDEVICE %p, Request %p, Memory %p, %!STATUS!",
230                         UsbDevice, Request, UrbMemory, status);
231 
232     return status;
233 }
234 
235 _Must_inspect_result_
236 __drv_maxIRQL(PASSIVE_LEVEL)
237 NTSTATUS
238 WDFAPI
239 WDFEXPORT(WdfUsbTargetDeviceIsConnectedSynchronous)(
240     __in
241     PWDF_DRIVER_GLOBALS DriverGlobals,
242     __in
243     WDFUSBDEVICE UsbDevice
244     )
245 {
246     DDI_ENTRY();
247 
248     PFX_DRIVER_GLOBALS pFxDriverGlobals;
249     FxUsbDevice* pUsbDevice;
250     NTSTATUS status;
251 
252     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
253                                    UsbDevice,
254                                    FX_TYPE_IO_TARGET_USB_DEVICE,
255                                    (PVOID*) &pUsbDevice,
256                                    &pFxDriverGlobals);
257 
258     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
259     if (!NT_SUCCESS(status)) {
260         return status;
261     }
262 
263     status = pUsbDevice->IsConnected();
264 
265     return status;
266 }
267 
268 _Must_inspect_result_
269 __drv_maxIRQL(PASSIVE_LEVEL)
270 NTSTATUS
271 WDFEXPORT(WdfUsbTargetDeviceCyclePortSynchronously)(
272     __in
273     PWDF_DRIVER_GLOBALS DriverGlobals,
274     __in
275     WDFUSBDEVICE UsbDevice
276     )
277 /*++
278 
279 Routine Description:
280     Synchronously cycles a device on a USB port.  This will cause the device
281     to be surprise removed and reenumerated.  Very similar to the reenumerate
282     interface we use in the pnp state machine.  Usually a driver will do this
283     after it has downloaded firmware and wants to be reenumerated as a new
284     device.
285 
286 
287 
288 
289 Arguments:
290     UsbDevice - the IOTARGET representing the device
291 
292 Return Value:
293     NTSTATUS
294 
295   --*/
296 {
297     DDI_ENTRY();
298 
299     PFX_DRIVER_GLOBALS pFxDriverGlobals;
300     FxUsbDevice* pUsbDevice;
301     NTSTATUS status;
302 
303     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
304                                    UsbDevice,
305                                    FX_TYPE_IO_TARGET_USB_DEVICE,
306                                    (PVOID*) &pUsbDevice,
307                                    &pFxDriverGlobals);
308 
309     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
310     if (!NT_SUCCESS(status)) {
311         return status;
312     }
313 
314     status = pUsbDevice->CyclePort();
315 
316     return status;
317 }
318 
319 _Must_inspect_result_
320 __drv_maxIRQL(DISPATCH_LEVEL)
321 NTSTATUS
322 WDFEXPORT(WdfUsbTargetDeviceFormatRequestForCyclePort)(
323     __in
324     PWDF_DRIVER_GLOBALS DriverGlobals,
325     __in
326     WDFUSBDEVICE UsbDevice,
327     __in
328     WDFREQUEST Request
329     )
330 /*++
331 
332 Routine Description:
333     Formats a WDFREQUEST so that it will cycle the port and reenumerate the
334     device when sent.
335 
336 Arguments:
337     UsbDevice - the IOTARGET representing the device that will be reenumerated
338 
339     Request - the request which will be formatted
340 
341 Return Value:
342     NTSTATUS
343 
344   --*/
345 {
346     DDI_ENTRY();
347 
348     PFX_DRIVER_GLOBALS pFxDriverGlobals;
349     FxUsbDevice* pUsbDevice;
350     FxRequest* pRequest;
351     NTSTATUS status;
352 
353     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
354                                    UsbDevice,
355                                    FX_TYPE_IO_TARGET_USB_DEVICE,
356                                    (PVOID*) &pUsbDevice,
357                                    &pFxDriverGlobals);
358 
359     FxObjectHandleGetPtr(pFxDriverGlobals,
360                          Request,
361                          FX_TYPE_REQUEST,
362                          (PVOID*) &pRequest);
363 
364     status = pUsbDevice->FormatCycleRequest(pRequest);
365 
366     return status;
367 }
368 
369 __checkReturn
370 __drv_maxIRQL(DISPATCH_LEVEL)
371 NTSTATUS
372 WDFAPI
373 WDFEXPORT(WdfUsbTargetDeviceCreateUrb)(
374     __in
375     PWDF_DRIVER_GLOBALS DriverGlobals,
376     __in
377     WDFUSBDEVICE UsbDevice,
378     __in_opt
379     PWDF_OBJECT_ATTRIBUTES Attributes,
380     __out
381     WDFMEMORY* UrbMemory,
382     __deref_opt_out_bcount(sizeof(URB))
383     PURB* Urb
384     )
385 /*++
386 
387 Routine Description:
388     Creates a WDFUSBDEVICE handle for the client.
389 
390 Arguments:
391     Attributes - Attributes associated with this object
392 
393     UrbMemory - The returned handle to the caller for the allocated Urb
394 
395     Urb - (opt) Pointer to the associated urb buffer.
396 
397 Return Value:
398     STATUS_INVALID_PARAMETER - any required parameters are not present/invalid
399 
400     STATUS_INVALID_DEVICE_STATE - If the client did not specify a client contract verion while
401         creating the WDFUSBDEVICE
402 
403     STATUS_INSUFFICIENT_RESOURCES - could not allocated the object that backs
404         the handle
405 
406     STATUS_SUCCESS - success
407 
408     ...
409 
410   --*/
411 {
412     DDI_ENTRY();
413 
414     PFX_DRIVER_GLOBALS pFxDriverGlobals;
415     FxUsbDevice* pUsbDevice;
416     NTSTATUS status;
417 
418     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
419                                    UsbDevice,
420                                    FX_TYPE_IO_TARGET_USB_DEVICE,
421                                    (PVOID*) &pUsbDevice,
422                                    &pFxDriverGlobals);
423 
424     //
425     // Basic parameter validation
426     //
427     FxPointerNotNull(pFxDriverGlobals, UrbMemory);
428 
429     if (pUsbDevice->GetUSBDHandle() == NULL) {
430         status = STATUS_INVALID_DEVICE_STATE;
431 
432         DoTraceLevelMessage(
433             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
434             "USBDEVICE Must have been created with Client Contract Verion Info, %!STATUS!",
435             status);
436 
437         return status;
438     }
439 
440     status = pUsbDevice->CreateUrb(Attributes, UrbMemory, Urb);
441 
442     return status;
443 }
444 
445 } // extern "C"
446