/*
* 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.
*/
/** \file
This file consists of implementation of class AndroidUsbDriverObject that
encapsulates our driver object
*/
#pragma data_seg()
#pragma code_seg()
#include "precomp.h"
#include "android_usb_device_object.h"
#include "android_usb_driver_object.h"
#pragma data_seg()
/** Globally accessible instance of the AndroidUsbDriverObject.
NT OS design allows us using of a global pointer to our driver object
instance since it can't be created or destroyed concurently and its value
is not going to change between creation and destruction.
*/
AndroidUsbDriverObject* global_driver_object = NULL;
#pragma code_seg("INIT")
extern "C" {
/// Main entry point to the driver
NTSTATUS DriverEntry(PDRIVER_OBJECT drv_object, PUNICODE_STRING reg_path) {
// Just pass it down inside the class
return AndroidUsbDriverObject::DriverEntry(drv_object, reg_path);
}
} // extern "C"
NTSTATUS AndroidUsbDriverObject::DriverEntry(PDRIVER_OBJECT drv_object,
PUNICODE_STRING reg_path) {
ASSERT_IRQL_PASSIVE();
ASSERT(NULL != drv_object);
ASSERT((NULL != reg_path) &&
(NULL != reg_path->Buffer) &&
(0 != reg_path->Length));
// Instantiate driver object
global_driver_object = new(NonPagedPool, GANDR_POOL_TAG_DRIVER_OBJECT)
AndroidUsbDriverObject(drv_object, reg_path);
ASSERT(NULL != global_driver_object);
if (NULL == global_driver_object)
return STATUS_INSUFFICIENT_RESOURCES;
// Initialize driver object
NTSTATUS status = global_driver_object->OnDriverEntry(drv_object, reg_path);
if (!NT_SUCCESS(status)) {
// Something went wrong. Delete our driver object and get out of here.
delete global_driver_object;
}
return status;
}
AndroidUsbDriverObject::AndroidUsbDriverObject(PDRIVER_OBJECT drv_object,
PUNICODE_STRING reg_path)
: driver_object_(drv_object),
wdf_driver_(NULL) {
ASSERT_IRQL_PASSIVE();
ASSERT(NULL != driver_object());
}
NTSTATUS AndroidUsbDriverObject::OnDriverEntry(PDRIVER_OBJECT drv_object,
PUNICODE_STRING reg_path) {
ASSERT_IRQL_PASSIVE();
ASSERT(driver_object() == drv_object);
// Initiialize driver config, specifying our unload callback and default
// pool tag for memory allocations that KMDF does on our behalf.
WDF_DRIVER_CONFIG config;
WDF_DRIVER_CONFIG_INIT(&config, EvtDeviceAddEntry);
config.EvtDriverUnload = EvtDriverUnloadEntry;
config.DriverPoolTag = GANDR_POOL_TAG_DEFAULT;
// Create a framework driver object to represent our driver.
NTSTATUS status = WdfDriverCreate(drv_object,
reg_path,
WDF_NO_OBJECT_ATTRIBUTES,
&config,
&wdf_driver_);
ASSERT(NT_SUCCESS(status));
if (!NT_SUCCESS(status))
return status;
GoogleDbgPrint("\n>>>>>>>>>> Android USB driver has started >>>>>>>>>>");
return STATUS_SUCCESS;
}
#pragma code_seg("PAGE")
AndroidUsbDriverObject::~AndroidUsbDriverObject() {
ASSERT_IRQL_PASSIVE();
}
NTSTATUS AndroidUsbDriverObject::OnAddDevice(PWDFDEVICE_INIT device_init) {
ASSERT_IRQL_PASSIVE();
GoogleDbgPrint("\n++++++++++ AndroidUsbDriverObject::OnAddDevice ++++++++++");
// Instantiate our device object extension for this device
AndroidUsbDeviceObject* wdf_device_ext =
new(NonPagedPool, GANDR_POOL_TAG_KMDF_DEVICE) AndroidUsbDeviceObject();
ASSERT(NULL != wdf_device_ext);
if (NULL == wdf_device_ext)
return STATUS_INSUFFICIENT_RESOURCES;
// Create and initialize FDO device
NTSTATUS status = wdf_device_ext->CreateFDODevice(device_init);
ASSERT(NT_SUCCESS(status));
if (!NT_SUCCESS(status))
delete wdf_device_ext;
return status;
}
void AndroidUsbDriverObject::OnDriverUnload() {
ASSERT_IRQL_PASSIVE();
GoogleDbgPrint("\n<<<<<<<<<< Android USB driver is unloaded <<<<<<<<<<");
}
NTSTATUS AndroidUsbDriverObject::EvtDeviceAddEntry(
WDFDRIVER wdf_drv,
PWDFDEVICE_INIT device_init) {
ASSERT_IRQL_PASSIVE();
ASSERT((NULL != global_driver_object) && (global_driver_object->wdf_driver() == wdf_drv));
// Pass it down to our driver object
if ((NULL == global_driver_object) ||
(global_driver_object->wdf_driver() != wdf_drv)) {
return STATUS_INTERNAL_ERROR;
}
return global_driver_object->OnAddDevice(device_init);
}
VOID AndroidUsbDriverObject::EvtDriverUnloadEntry(WDFDRIVER wdf_drv) {
ASSERT_IRQL_PASSIVE();
ASSERT((NULL != global_driver_object) &&
(global_driver_object->wdf_driver() == wdf_drv));
// Pass it down to our driver object
if ((NULL != global_driver_object) &&
(global_driver_object->wdf_driver() == wdf_drv)) {
global_driver_object->OnDriverUnload();
// Now we can (and have to) delete our driver object
delete global_driver_object;
}
}
#if DBG
#pragma code_seg()
ULONG __cdecl GoogleDbgPrint(char* format, ...) {
va_list arg_list;
va_start(arg_list, format);
ULONG ret =
vDbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, arg_list);
va_end(arg_list);
return ret;
}
#endif // DBG
#pragma data_seg()
#pragma code_seg()