📄 pnp.c
字号:
/* * Copyright (C) 2005 Giridhar Pemmasani * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */#include "usb.h"#include "pnp.h"#include "wrapndis.h"#include "loader.h"extern struct semaphore loader_mutex;static NTSTATUS start_pdo(struct device_object *pdo){ int i, ret, count, resources_size; struct wrap_device *wd; struct pci_dev *pdev; struct cm_partial_resource_descriptor *entry; struct cm_partial_resource_list *partial_resource_list; ENTER1("%p, %p", pdo, pdo->reserved); wd = pdo->reserved; if (ntoskernel_init_device(wd)) EXIT1(return STATUS_FAILURE); if (wrap_is_usb_bus(wd->dev_bus)) {#ifdef CONFIG_USB if (usb_init_device(wd)) { ntoskernel_exit_device(wd); EXIT1(return STATUS_FAILURE); }#endif EXIT1(return STATUS_SUCCESS); } if (!wrap_is_pci_bus(wd->dev_bus)) EXIT1(return STATUS_SUCCESS); pdev = wd->pci.pdev; ret = pci_enable_device(pdev); if (ret) { ERROR("couldn't enable PCI device: %x", ret); return STATUS_FAILURE; } ret = pci_request_regions(pdev, DRIVER_NAME); if (ret) { ERROR("couldn't request PCI regions: %x", ret); goto err_enable; } pci_set_power_state(pdev, PCI_D0);#ifdef CONFIG_X86_64 /* 64-bit broadcom driver doesn't work if DMA is allocated * from over 1GB */ if (wd->vendor == 0x14e4) { if (pci_set_dma_mask(pdev, 0x3fffffff) || pci_set_consistent_dma_mask(pdev, 0x3fffffff)) WARNING("couldn't set DMA mask; this driver " "may not work with more than 1GB RAM"); }#endif /* IRQ resource entry is filled in from pdev, instead of * pci_resource macros */ for (i = count = 0; pci_resource_start(pdev, i); i++) if ((pci_resource_flags(pdev, i) & IORESOURCE_MEM) || (pci_resource_flags(pdev, i) & IORESOURCE_IO)) count++; /* space for entry for IRQ is already in * cm_partial_resource_list */ resources_size = sizeof(struct cm_resource_list) + sizeof(struct cm_partial_resource_descriptor) * count; TRACE2("resources: %d, %d", count, resources_size); wd->resource_list = kmalloc(resources_size, GFP_KERNEL); if (!wd->resource_list) { WARNING("couldn't allocate memory"); goto err_regions; } memset(wd->resource_list, 0, resources_size); wd->resource_list->count = 1; wd->resource_list->list[0].interface_type = PCIBus; /* bus_number is not used by WDM drivers */ wd->resource_list->list[0].bus_number = pdev->bus->number; partial_resource_list = &wd->resource_list->list->partial_resource_list; partial_resource_list->version = 1; partial_resource_list->revision = 1; partial_resource_list->count = count + 1; for (i = count = 0; pci_resource_start(pdev, i); i++) { entry = &partial_resource_list->partial_descriptors[count]; TRACE2("%d", count); if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { entry->type = CmResourceTypeMemory; entry->flags = CM_RESOURCE_MEMORY_READ_WRITE; entry->share = CmResourceShareDeviceExclusive; } else if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { entry->type = CmResourceTypePort; entry->flags = CM_RESOURCE_PORT_IO; entry->share = CmResourceShareDeviceExclusive;#if 0 } else if (pci_resource_flags(pdev, i) & IORESOURCE_DMA) { /* it looks like no driver uses this resource */ typeof(pci_resource_flags(pdev, 0)) flags; entry->type = CmResourceTypeDma; flags = pci_resource_flags(pdev, i); if (flags & IORESOURCE_DMA_TYPEA) entry->flags |= CM_RESOURCE_DMA_TYPE_A; else if (flags & IORESOURCE_DMA_TYPEB) entry->flags |= CM_RESOURCE_DMA_TYPE_B; else if (flags & IORESOURCE_DMA_TYPEF) entry->flags |= CM_RESOURCE_DMA_TYPE_F; if (flags & IORESOURCE_DMA_8BIT) entry->flags |= CM_RESOURCE_DMA_8; else if (flags & IORESOURCE_DMA_16BIT) entry->flags |= CM_RESOURCE_DMA_16; /* what about 32bit DMA? */ else if (flags & IORESOURCE_DMA_8AND16BIT) entry->flags |= CM_RESOURCE_DMA_8_AND_16; if (flags & IORESOURCE_DMA_MASTER) entry->flags |= CM_RESOURCE_DMA_BUS_MASTER; entry->u.dma.channel = pci_resource_start(pdev, i); /* what should this be? */ entry->u.dma.port = 1;#endif } else continue; /* TODO: Add other resource types? */ entry->u.generic.start = (ULONG_PTR)pci_resource_start(pdev, i); entry->u.generic.length = pci_resource_len(pdev, i); count++; } /* put IRQ resource at the end */ entry = &partial_resource_list->partial_descriptors[count++]; entry->type = CmResourceTypeInterrupt; entry->flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; /* we assume all devices use shared IRQ */ entry->share = CmResourceShareShared; /* as per documentation, interrupt level should be DIRQL, but * examples from DDK as well some drivers, such as AR5211, * RT8180L use interrupt level as interrupt vector also in * NdisMRegisterInterrupt */ entry->u.interrupt.level = pdev->irq; entry->u.interrupt.vector = pdev->irq; entry->u.interrupt.affinity = -1; TRACE2("resource list count %d, irq: %d", partial_resource_list->count, pdev->irq); pci_set_drvdata(pdev, wd); EXIT1(return STATUS_SUCCESS);err_regions: pci_release_regions(pdev);err_enable: pci_disable_device(pdev); wd->pci.pdev = NULL; wd->pdo = NULL; EXIT1(return STATUS_FAILURE);}static void remove_pdo(struct device_object *pdo){ struct wrap_device *wd = pdo->reserved; ntoskernel_exit_device(wd); if (wrap_is_pci_bus(wd->dev_bus)) { struct pci_dev *pdev = wd->pci.pdev; pci_release_regions(pdev); pci_disable_device(pdev); wd->pci.pdev = NULL; pci_set_drvdata(pdev, NULL); } else if (wrap_is_usb_bus(wd->dev_bus)) {#ifdef CONFIG_USB usb_exit_device(wd);#endif } if (wd->resource_list) kfree(wd->resource_list); wd->resource_list = NULL; return;}wstdcall NTSTATUS IoSendIrpTopDev(struct device_object *dev_obj, ULONG major_fn, ULONG minor_fn, struct io_stack_location *sl){ NTSTATUS status; struct nt_event event; struct irp *irp; struct io_stack_location *irp_sl; struct device_object *top_dev = IoGetAttachedDeviceReference(dev_obj); KeInitializeEvent(&event, NotificationEvent, FALSE); irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, top_dev, NULL, 0, NULL, &event, NULL); irp->io_status.status = STATUS_NOT_IMPLEMENTED; irp->io_status.info = 0; irp_sl = IoGetNextIrpStackLocation(irp); if (sl) memcpy(irp_sl, sl, sizeof(*irp_sl)); irp_sl->major_fn = major_fn; irp_sl->minor_fn = minor_fn; status = IoCallDriver(top_dev, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); status = irp->io_status.status; } ObDereferenceObject(top_dev); return status;}wstdcall NTSTATUS pdoDispatchDeviceControl(struct device_object *pdo, struct irp *irp){ struct io_stack_location *irp_sl; NTSTATUS status; DUMP_IRP(irp); irp_sl = IoGetCurrentIrpStackLocation(irp);#ifdef CONFIG_USB status = wrap_submit_irp(pdo, irp); IOTRACE("status: %08X", status); if (status != STATUS_PENDING) IoCompleteRequest(irp, IO_NO_INCREMENT);#else status = irp->io_status.status = STATUS_NOT_IMPLEMENTED; IoCompleteRequest(irp, IO_NO_INCREMENT);#endif IOEXIT(return status);}WIN_FUNC_DECL(pdoDispatchDeviceControl,2)wstdcall NTSTATUS pdoDispatchPnp(struct device_object *pdo, struct irp *irp){ struct io_stack_location *irp_sl; struct wrap_device *wd; NTSTATUS status;#ifdef CONFIG_USB struct usbd_bus_interface_usbdi *usb_intf;#endif irp_sl = IoGetCurrentIrpStackLocation(irp); TRACE2("%p %d:%d", pdo, irp_sl->major_fn, irp_sl->minor_fn); wd = pdo->reserved; switch (irp_sl->minor_fn) { case IRP_MN_START_DEVICE: status = start_pdo(pdo); break; case IRP_MN_QUERY_STOP_DEVICE: case IRP_MN_STOP_DEVICE: case IRP_MN_QUERY_REMOVE_DEVICE: status = STATUS_SUCCESS; break; case IRP_MN_REMOVE_DEVICE: remove_pdo(pdo); status = STATUS_SUCCESS; break; case IRP_MN_QUERY_INTERFACE:#ifdef CONFIG_USB if (!wrap_is_usb_bus(wd->dev_bus)) { status = STATUS_NOT_IMPLEMENTED; break; } TRACE2("type: %x, size: %d, version: %d", irp_sl->params.query_intf.type->data1, irp_sl->params.query_intf.size, irp_sl->params.query_intf.version); usb_intf = (struct usbd_bus_interface_usbdi *) irp_sl->params.query_intf.intf; usb_intf->Context = wd; usb_intf->InterfaceReference = USBD_InterfaceReference; usb_intf->InterfaceDereference = USBD_InterfaceDereference; usb_intf->GetUSBDIVersion = USBD_InterfaceGetUSBDIVersion; usb_intf->QueryBusTime = USBD_InterfaceQueryBusTime; usb_intf->SubmitIsoOutUrb = USBD_InterfaceSubmitIsoOutUrb; usb_intf->QueryBusInformation = USBD_InterfaceQueryBusInformation; if (irp_sl->params.query_intf.version >= USB_BUSIF_USBDI_VERSION_1) usb_intf->IsDeviceHighSpeed = USBD_InterfaceIsDeviceHighSpeed; if (irp_sl->params.query_intf.version >= USB_BUSIF_USBDI_VERSION_2) usb_intf->LogEntry = USBD_InterfaceLogEntry; status = STATUS_SUCCESS;#else status = STATUS_NOT_IMPLEMENTED;#endif break; default: TRACE2("fn %d not implemented", irp_sl->minor_fn); status = STATUS_SUCCESS; break; } irp->io_status.status = status; TRACE2("status: %08X", status); IoCompleteRequest(irp, IO_NO_INCREMENT); IOEXIT(return status);}WIN_FUNC_DECL(pdoDispatchPnp,2)wstdcall NTSTATUS pdoDispatchPower(struct device_object *pdo, struct irp *irp){ struct io_stack_location *irp_sl; struct wrap_device *wd; union power_state power_state; struct pci_dev *pdev; NTSTATUS status; irp_sl = IoGetCurrentIrpStackLocation(irp); wd = pdo->reserved; TRACE2("pdo: %p, fn: %d:%d, wd: %p", pdo, irp_sl->major_fn, irp_sl->minor_fn, wd); switch (irp_sl->minor_fn) { case IRP_MN_WAIT_WAKE: /* TODO: this is not complete/correct */ TRACE2("state: %d, completion: %p", irp_sl->params.power.state.system_state, irp_sl->completion_routine); IoMarkIrpPending(irp); status = STATUS_PENDING; break; case IRP_MN_SET_POWER: power_state = irp_sl->params.power.state; if (power_state.device_state == PowerDeviceD0) { TRACE2("resuming device %p", wd); if (wrap_is_pci_bus(wd->dev_bus)) { pdev = wd->pci.pdev;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) pci_restore_state(pdev);#else pci_restore_state(pdev, wd->pci.pci_state);#endif } else { // usb device#ifdef CONFIG_USB wrap_resume_urbs(wd);#endif } } else { TRACE2("suspending device %p", wd); if (wrap_is_pci_bus(wd->dev_bus)) { pdev = wd->pci.pdev;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) pci_save_state(pdev);#else pci_save_state(pdev, wd->pci.pci_state);#endif } else { // usb device#ifdef CONFIG_USB wrap_suspend_urbs(wd);#endif } } status = STATUS_SUCCESS; break; case IRP_MN_QUERY_POWER: status = STATUS_SUCCESS; break; default: TRACE2("fn %d not implemented", irp_sl->minor_fn); status = STATUS_SUCCESS; break; } irp->io_status.status = status; IoCompleteRequest(irp, IO_NO_INCREMENT); return status;}WIN_FUNC_DECL(pdoDispatchPower,2)NTSTATUS pnp_set_device_power_state(struct wrap_device *wd, enum device_power_state state){ NTSTATUS status; struct device_object *pdo; struct io_stack_location irp_sl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -