[PATCH 2/4] ntoskrnl.exe: Implement loading plug and play devices
Sebastian Lackner
sebastian at fds-team.de
Wed Aug 31 02:22:44 CDT 2016
On 29.08.2016 20:49, Aric Stewart wrote:
> Signed-off-by: Aric Stewart <aric at codeweavers.com>
> ---
> dlls/ntoskrnl.exe/pnp_manager.c | 150 ++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 150 insertions(+)
>
>
>
> 0002-ntoskrnl.exe-Implement-loading-plug-and-play-devices.txt
>
>
> diff --git a/dlls/ntoskrnl.exe/pnp_manager.c b/dlls/ntoskrnl.exe/pnp_manager.c
> index 5b42a0a..f1f3109 100644
> --- a/dlls/ntoskrnl.exe/pnp_manager.c
> +++ b/dlls/ntoskrnl.exe/pnp_manager.c
> @@ -17,6 +17,7 @@
> * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> */
>
> +#define NONAMELESSUNION
> #include <stdarg.h>
> #include "ntstatus.h"
> #define WIN32_NO_STATUS
> @@ -27,6 +28,7 @@
> #include "cfgmgr32.h"
> #include "winsvc.h"
> #include "winreg.h"
> +#include "wine/unicode.h"
> #include "wine/debug.h"
> #include "wine/list.h"
>
> @@ -34,6 +36,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
>
> #define MAX_SERVICE_NAME 260
>
> +typedef NTSTATUS WINAPI (*pAddDevice)(DRIVER_OBJECT *DriverObject, DEVICE_OBJECT *PhysicalDeviceObject);
My Win10 header files contain DRIVER_EXTENSION with the appropriate definition, which
would make the casts unnecessary.
> +
> typedef struct _device_driver {
> struct list entry;
>
> @@ -105,6 +109,143 @@ static device_driver* register_device_driver(const WCHAR *drivername, const WCHA
> return ptr;
> }
>
> +static NTSTATUS WINAPI internalComplete(DEVICE_OBJECT *deviceObject, IRP *irp,
> + void *context )
> +{
> + SetEvent(irp->UserEvent);
> + return STATUS_MORE_PROCESSING_REQUIRED;
> +}
> +
> +static NTSTATUS get_device_id(DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WCHAR **id)
> +{
> + NTSTATUS status;
> + IO_STACK_LOCATION *irpsp;
> + IO_STATUS_BLOCK irp_status;
> + IRP *irp;
> + HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
> +
> + irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status);
> + if (irp == NULL)
> + return STATUS_NO_MEMORY;
The return path here will leak the event handle. The same issue was recently fixed in hidclass.sys.
Also I'm wondering a bit, do we need to keep this identical code at both places?
> +
> + irp->UserEvent = event;
> + irpsp = IoGetNextIrpStackLocation(irp);
> + irpsp->MinorFunction = IRP_MN_QUERY_ID;
> + irpsp->Parameters.QueryId.IdType = type;
> + irpsp->CompletionRoutine = internalComplete;
> + irpsp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
> +
> + IoCallDriver(device, irp);
> +
> + if (irp->IoStatus.u.Status == STATUS_PENDING)
> + WaitForSingleObject(event, INFINITE);
> +
> + *id = (WCHAR*)irp->IoStatus.Information;
> + status = irp->IoStatus.u.Status;
> + IoCompleteRequest(irp, IO_NO_INCREMENT );
> + CloseHandle(event);
> +
> + return status;
> +}
> +
> +static void handle_bus_relations(DEVICE_OBJECT *device)
> +{
> + static const WCHAR szDriverW[] = {'\\','D','r','i','v','e','r','\\',0};
> +
> + NTSTATUS status;
> + WCHAR *id, *idptr;
> + device_driver *driver = NULL;
> + WCHAR fullname[MAX_PATH];
> + DRIVER_OBJECT *driver_obj;
> + UNICODE_STRING driverName;
> +
> + TRACE("Device %p\n", device);
> +
> + /* We could(should?) do a full IRP_MN_QUERY_DEVICE_RELATIONS query,
> + * but we dont have to, We have the DEVICE_OBJECT of the new device
> + * so we can simply handle the process here */
> +
> + status = get_device_id(device, BusQueryCompatibleIDs, &id);
> + if (status != ERROR_SUCCESS || !id)
> + {
> + ERR("Failed to get device IDs\n");
> + return;
> + }
> +
> + idptr = id;
> + do {
> + device_driver *ptr;
> +
> + TRACE("Checking for id %s\n",debugstr_w(idptr));
> +
> + /* Check loaded drivers */
> + LIST_FOR_EACH_ENTRY(ptr, &device_drivers, device_driver, entry)
> + {
> + int i;
> + for (i = 0; i < ptr->id_count; i++)
> + {
> + if (lstrcmpW(idptr, ptr->matching_ids[i]) == 0)
> + {
> + driver = ptr;
> + break;
Is it intentional that this does not abort the outer loop?
> + }
> + }
> + }
> + idptr += (lstrlenW(idptr) + 1);
> + } while (!driver && *idptr != 0);
> +
> + HeapFree(GetProcessHeap(), 0, id);
> +
> + if (!driver)
> + {
> + ERR("No matching driver found for device\n");
> + return;
> + }
> +
> + strcpyW(fullname, szDriverW);
> + strcatW(fullname, driver->driver_name);
> + RtlInitUnicodeString(&driverName, fullname);
> +
> + if (!driver->loaded)
> + {
> + static const WCHAR servicesW[] = {'\\','R','e','g','i','s','t','r','y',
> + '\\','M','a','c','h','i','n','e',
> + '\\','S','y','s','t','e','m',
> + '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
> + '\\','S','e','r','v','i','c','e','s',
> + '\\',0};
> + WCHAR driverKey[MAX_PATH];
> + UNICODE_STRING driverPath;
> +
> + strcpyW(driverKey, servicesW);
> + strcatW(driverKey, driver->driver_name);
> + RtlInitUnicodeString(&driverPath, driverKey);
> + if (ZwLoadDriver(&driverPath) != STATUS_SUCCESS)
> + {
> + ERR("Failed to load driver %s\n",debugstr_w(driver->driver_name));
> + return;
> + }
> + driver->loaded = TRUE;
> + }
> +
> + if (ObReferenceObjectByName(&driverName, OBJ_CASE_INSENSITIVE, NULL,
> + 0, NULL, KernelMode, NULL, (void**)&driver_obj) != STATUS_SUCCESS)
> + {
> + ERR("Failed to locate loaded driver\n");
> + return;
> + }
> +
> + status = ((pAddDevice)driver_obj->DriverExtension->AddDevice)(driver_obj, device);
It would be better to handle the lack of a AddDevice routine.
> +
> + ObDereferenceObject(driver_obj);
> +
> + if (status != STATUS_SUCCESS)
> + {
> + ERR("AddDevice failed\n");
> + return;
> + }
> +}
> +
> static void initialize_driver_store(void)
> {
> static const WCHAR criticalW[] =
> @@ -181,5 +322,14 @@ VOID WINAPI IoInvalidateDeviceRelations(DEVICE_OBJECT *DeviceObject, DEVICE_RELA
> initialized = TRUE;
> initialize_driver_store();
> }
> +
> + switch (Type)
> + {
> + case BusRelations:
> + handle_bus_relations(DeviceObject);
> + break;
> + default:
> + FIXME("Unhandled Relation %i\n", Type);
> + }
> LeaveCriticalSection(&pnp_cs);
> }
>
>
>
More information about the wine-devel
mailing list