gendrv.c
来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· C语言 代码 · 共 1,827 行 · 第 1/4 页
C
1,827 行
RtlAnsiStringToUnicodeString(&symb_link, &string, TRUE);
IoDeleteSymbolicLink(&symb_link);
RtlFreeUnicodeString(&symb_link);
if (pdev_ext->desc_buf)
{
usb_dbg_print(DBGLVL_MAXIMUM, ("gendrv_delete_device(): delete desc_buf\n"));
usb_free_mem(pdev_ext->desc_buf);
pdev_ext->desc_buf = NULL;
}
if (dev_obj->ReferenceCount == 0)
{
ExAcquireFastMutex(&pdrvr_ext->drvr_ext_mutex);
RemoveEntryList(&pdev_ext->dev_obj_link);
pdev_ext->ext_drvr_entry->ref_count--; //the ext_drvr_entry is actually in pdrvr_ext, so lock it.
ExReleaseFastMutex(&pdrvr_ext->drvr_ext_mutex);
IoDeleteDevice(dev_obj);
return TRUE;
}
// borrow from umss's work routine
return umss_schedule_workitem(dev_obj, gendrv_deferred_delete_device, NULL, 0);
}
// must have the drvr_ext_mutex acquired.
PGENDRV_EXT_DRVR_ENTRY
gendrv_alloc_ext_drvr_entry(PGENDRV_DRVR_EXTENSION pdrvr_ext)
{
LONG i;
if (pdrvr_ext == NULL)
return NULL;
if (pdrvr_ext->ext_drvr_count == GENDRV_MAX_EXT_DRVR)
return NULL;
for(i = 0; i < GENDRV_MAX_EXT_DRVR; i++)
{
if (pdrvr_ext->ext_drvr_array[i].drvr_link.Flink == NULL &&
pdrvr_ext->ext_drvr_array[i].drvr_link.Blink == NULL)
{
return &pdrvr_ext->ext_drvr_array[i];
}
}
return NULL;
}
// must have the drvr_ext_mutex acquired.
VOID
gendrv_release_ext_drvr_entry(PGENDRV_DRVR_EXTENSION pdrvr_ext, PGENDRV_EXT_DRVR_ENTRY pentry)
{
if (pdrvr_ext == NULL || pentry == NULL)
return;
RtlZeroMemory(pentry, sizeof(GENDRV_EXT_DRVR_ENTRY));
InitializeListHead(&pentry->dev_list);
return;
}
NTSTATUS
gendrv_open_reg_key(OUT PHANDLE handle,
IN HANDLE base_handle OPTIONAL,
IN PUNICODE_STRING keyname, IN ACCESS_MASK desired_access, IN BOOLEAN create)
/*++
Routine Description:
Opens or creates a VOLATILE registry key using the name passed in based
at the BaseHandle node.
Arguments:
Handle - Pointer to the handle which will contain the registry key that
was opened.
BaseHandle - Handle to the base path from which the key must be opened.
KeyName - Name of the Key that must be opened/created.
DesiredAccess - Specifies the desired access that the caller needs to
the key.
Create - Determines if the key is to be created if it does not exist.
Return Value:
The function value is the final status of the operation.
--*/
{
OBJECT_ATTRIBUTES object_attr;
ULONG disposition;
//
// Initialize the object for the key.
//
InitializeObjectAttributes(&object_attr,
keyname, OBJ_CASE_INSENSITIVE, base_handle, (PSECURITY_DESCRIPTOR) NULL);
//
// Create the key or open it, as appropriate based on the caller's
// wishes.
//
if (create)
{
return ZwCreateKey(handle,
desired_access,
&object_attr, 0, (PUNICODE_STRING) NULL, REG_OPTION_VOLATILE, &disposition);
}
else
{
return ZwOpenKey(handle, desired_access, &object_attr);
}
return STATUS_INVALID_PARAMETER;
}
NTSTATUS
gendrv_get_key_value(IN HANDLE KeyHandle, IN PWSTR ValueName, OUT PKEY_VALUE_FULL_INFORMATION * Information)
/*++
Routine Description:
This routine is invoked to retrieve the data for a registry key's value.
This is done by querying the value of the key with a zero-length buffer
to determine the size of the value, and then allocating a buffer and
actually querying the value into the buffer.
It is the responsibility of the caller to free the buffer.
Arguments:
KeyHandle - Supplies the key handle whose value is to be queried
ValueName - Supplies the null-terminated Unicode name of the value.
Information - Returns a pointer to the allocated data buffer.
Return Value:
The function value is the final status of the query operation.
--*/
{
UNICODE_STRING unicodeString;
NTSTATUS status;
PKEY_VALUE_FULL_INFORMATION infoBuffer;
ULONG keyValueLength;
PAGED_CODE();
RtlInitUnicodeString(&unicodeString, ValueName);
//
// Figure out how big the data value is so that a buffer of the
// appropriate size can be allocated.
//
status = ZwQueryValueKey(KeyHandle,
&unicodeString, KeyValueFullInformation, (PVOID) NULL, 0, &keyValueLength);
if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL)
{
return status;
}
//
// Allocate a buffer large enough to contain the entire key data value.
//
infoBuffer = usb_alloc_mem(NonPagedPool, keyValueLength);
if (!infoBuffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Query the data for the key value.
//
status = ZwQueryValueKey(KeyHandle,
&unicodeString,
KeyValueFullInformation, infoBuffer, keyValueLength, &keyValueLength);
if (!NT_SUCCESS(status))
{
usb_free_mem(infoBuffer);
return status;
}
//
// Everything worked, so simply return the address of the allocated
// buffer to the caller, who is now responsible for freeing it.
//
*Information = infoBuffer;
return STATUS_SUCCESS;
}
VOID
gendrv_startio(IN PDEVICE_OBJECT dev_obj, IN PIRP irp)
{
PIO_STACK_LOCATION irp_stack;
ULONG ctrl_code;
PUSB_DEV_MANAGER dev_mgr;
USE_NON_PENDING_IRQL;
if (dev_obj == NULL || irp == NULL)
return;
// standard process from walter oney
IoAcquireCancelSpinLock(&old_irql);
if (irp != dev_obj->CurrentIrp || irp->Cancel)
{
// already move on to other irp
IoReleaseCancelSpinLock(old_irql);
return;
}
else
{
(void)IoSetCancelRoutine(irp, NULL);
}
IoReleaseCancelSpinLock(old_irql);
irp->IoStatus.Information = 0;
irp_stack = IoGetCurrentIrpStackLocation(irp);
ctrl_code = irp_stack->Parameters.DeviceIoControl.IoControlCode;
dev_mgr = ((PDEVEXT_HEADER) dev_obj->DeviceExtension)->dev_mgr;
if (irp_stack->MajorFunction != IRP_MJ_DEVICE_CONTROL &&
irp_stack->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL)
{
GENDRV_COMPLETE_START_IO(dev_obj, STATUS_INVALID_DEVICE_REQUEST, irp);
}
switch (ctrl_code)
{
case IOCTL_SUBMIT_URB_RD:
case IOCTL_SUBMIT_URB_NOIO:
case IOCTL_SUBMIT_URB_WR:
{
PURB purb;
ULONG endp_idx, if_idx, user_buffer_length = 0;
PUCHAR user_buffer = NULL;
PUSB_DEV pdev;
DEV_HANDLE endp_handle;
PUSB_ENDPOINT pendp;
NTSTATUS status;
if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(URB))
{
GENDRV_COMPLETE_START_IO(dev_obj, STATUS_INVALID_PARAMETER, irp);
}
purb = (PURB) irp->AssociatedIrp.SystemBuffer;
if (ctrl_code == IOCTL_SUBMIT_URB_RD || ctrl_code == IOCTL_SUBMIT_URB_WR)
{
if (irp_stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
{
user_buffer = MmGetSystemAddressForMdl(irp->MdlAddress);
user_buffer_length = irp_stack->Parameters.DeviceIoControl.OutputBufferLength;
if (user_buffer_length == 0)
GENDRV_COMPLETE_START_IO(dev_obj, STATUS_INVALID_PARAMETER, irp);
}
else
{
if (purb->data_buffer == NULL || purb->data_length == 0)
GENDRV_COMPLETE_START_IO(dev_obj, STATUS_INVALID_PARAMETER, irp);
user_buffer = purb->data_buffer;
user_buffer_length = purb->data_length;
}
}
purb->reference = 0;
endp_handle = purb->endp_handle;
if (usb_query_and_lock_dev(dev_mgr, endp_handle & ~0xffff, &pdev) != STATUS_SUCCESS)
{
GENDRV_COMPLETE_START_IO(dev_obj, STATUS_IO_DEVICE_ERROR, irp);
}
lock_dev(pdev, FALSE);
if (dev_state(pdev) == USB_DEV_STATE_ZOMB || (dev_state(pdev) < USB_DEV_STATE_ADDRESSED))
{
status = STATUS_INVALID_DEVICE_STATE;
goto ERROR_OUT1;
}
if (dev_state(pdev) == USB_DEV_STATE_ADDRESSED && !default_endp_handle(endp_handle))
{
status = STATUS_DEVICE_NOT_READY;
goto ERROR_OUT1;
}
if_idx = if_idx_from_handle(endp_handle);
endp_idx = endp_idx_from_handle(endp_handle);
//if_idx exceeds the upper limit
if (pdev->usb_config)
{
if (if_idx >= pdev->usb_config->if_count
|| endp_idx >= pdev->usb_config->interf[if_idx].endp_count)
{
if (!default_endp_handle(endp_handle))
{
status = STATUS_INVALID_DEVICE_STATE;
goto ERROR_OUT1;
}
}
}
endp_from_handle(pdev, endp_handle, pendp);
// FIXME: don't know what evil will let loose
if (endp_type(pendp) != USB_ENDPOINT_XFER_CONTROL)
{
if (user_buffer_length > 16)
{
status = STATUS_INVALID_PARAMETER;
goto ERROR_OUT1;
}
}
purb->pirp = irp;
purb->context = dev_mgr;
purb->reference = ctrl_code;
if (ctrl_code == IOCTL_SUBMIT_URB_RD || ctrl_code == IOCTL_SUBMIT_URB_WR)
{
purb->data_buffer = user_buffer;
purb->data_length = user_buffer_length;
purb->completion = disp_urb_completion;
}
else
{
purb->completion = disp_noio_urb_completion;
}
unlock_dev(pdev, FALSE);
//
// we have to register irp before the urb is scheduled to
// avoid race condition.
//
ASSERT(dev_mgr_register_irp(dev_mgr, irp, purb));
//
// the irp can not be canceled at this point, since it is
// now the current irp and not in any urb queue. dev_mgr_cancel_irp
// can not find it and simply return.
//
// FIXME: there is a time window that the irp is registered and
// the urb is not queued. In the meantime, the cancel
// request may come and cause the irp removed from the irp
// queue while fail to cancel due to urb not in any urb queue .
// Thus from that point on, the irp can not be canceled till it
// is completed or hanging there forever.
//
status = usb_submit_urb(dev_mgr, purb);
if (status != STATUS_PENDING)
{
// unmark the pending bit
IoGetCurrentIrpStackLocation((irp))->Control &= ~SL_PENDING_RETURNED;
dev_mgr_remove_irp(dev_mgr, irp);
}
usb_unlock_dev(pdev);
if (status != STATUS_PENDING)
{
irp->IoStatus.Status = status;
GENDRV_COMPLETE_START_IO(dev_obj, status, irp);
}
return;
ERROR_OUT1:
unlock_dev(pdev, FALSE);
usb_unlock_dev(pdev);
irp->IoStatus.Information = 0;
GENDRV_COMPLETE_START_IO(dev_obj, status, irp);
}
}
GENDRV_COMPLETE_START_IO(dev_obj, STATUS_INVALID_DEVICE_REQUEST, irp);
}
VOID
gendrv_clean_up_queued_irps(PDEVICE_OBJECT dev_obj)
{
// called when device may not function or about to be removed, need cleanup
KIRQL cancelIrql;
PIRP irp, cur_irp;
PKDEVICE_QUEUE_ENTRY packet;
LIST_ENTRY cancel_irps, *pthis;
//
// cancel all the irps in the queue
//
if (dev_obj == NULL)
return;
InitializeListHead(&cancel_irps);
// remove the irps from device queue
IoAcquireCancelSpinLock(&cancelIrql);
cur_irp = dev_obj->CurrentIrp;
while ((packet = KeRemoveDeviceQueue(&dev_obj->DeviceQueue)))
{
irp = struct_ptr(packet, IRP, Tail.Overlay.DeviceQueueEntry);
InsertTailList(&cancel_irps, &irp->Tail.Overlay.DeviceQueueEntry.DeviceListEntry);
}
IoReleaseCancelSpinLock(cancelIrql);
// cancel the irps in process
// we did not cancel the current irp, it will be done by hcd when
// disconnect is detected.
// remove_irp_from_list( &dev_mgr->irp_list, cur_irp, dev_mgr );
while (IsListEmpty(&cancel_irps) == FALSE)
{
pthis = RemoveHeadList(&cancel_irps);
irp = struct_ptr(pthis, IRP, Tail.Overlay.DeviceQueueEntry.DeviceListEntry);
irp->IoStatus.Information = 0;
irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(irp, IO_NO_INCREMENT);
}
return;
}
VOID
NTAPI
gendrv_cancel_queued_irp(PDEVICE_OBJECT dev_obj, PIRP pirp)
{
// cancel routine for irps queued in the device queue
PUSB_DEV_MANAGER dev_mgr;
PDEVEXT_HEADER pdev_ext_hdr;
pdev_ext_hdr = (PDEVEXT_HEADER) dev_obj->DeviceExtension;
dev_mgr = pdev_ext_hdr->dev_mgr;
if (dev_obj->CurrentIrp == pirp)
{
// just before start_io set the cancel routine to null
IoReleaseCancelSpinLock(pirp->CancelIrql);
// we did not IoStartNextPacket, leave it for dev_mgr_cancel_irp, that
// is user have to call CancelIo again.
return;
}
KeRemoveEntryDeviceQueue(&dev_obj->DeviceQueue, &pirp->Tail.Overlay.DeviceQueueEntry);
IoReleaseCancelSpinLock(pirp->CancelIrql);
pirp->IoStatus.Information = 0;
pirp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
// the device queue is moved on, no need to call IoStartNextPacket
return;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?