VOID compdev_set_cfg_completion(PURB purb, PVOID context) { DEV_HANDLE dev_handle; PUSB_DEV_MANAGER dev_mgr; PUSB_DRIVER pdriver; NTSTATUS status; PUSB_DEV pdev; USE_BASIC_NON_PENDING_IRQL; if (purb == NULL || context == NULL) return; dev_handle = purb->endp_handle & ~0xffff; dev_mgr = (PUSB_DEV_MANAGER) context; pdriver = (PUSB_DRIVER) purb->reference; if (purb->status != STATUS_SUCCESS) { usb_free_mem(purb); return; } usb_free_mem(purb); purb = NULL; // set the dev state status = usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev); if (status != STATUS_SUCCESS) { usb_unlock_dev(pdev); return; } // safe to release the pdev ref since we are in urb completion usb_unlock_dev(pdev); lock_dev(pdev, TRUE); if (dev_state(pdev) >= USB_DEV_STATE_BEFORE_ZOMB) { unlock_dev(pdev, TRUE); return; } if (dev_mgr_set_driver(dev_mgr, dev_handle, pdriver, pdev) == FALSE) return; //transit the state to configured pdev->flags &= ~USB_DEV_STATE_MASK; pdev->flags |= USB_DEV_STATE_CONFIGURED; unlock_dev(pdev, TRUE); // // we change to use our thread for driver choosing. it will reduce // the race condition when different pnp event comes simultaneously // usb_dbg_print(DBGLVL_MAXIMUM, ("compdev_set_cfg_completion(): start select driver for the dev\n")); compdev_post_event_select_driver(dev_mgr, dev_handle); return; }
LockFile::~LockFile() { // Don't allow exceptions from destructor try { unlock_dev( dev_.c_str(), lockPid_ ); } catch ( ... ) {} }
BOOLEAN compdev_post_event_select_driver(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle) { PUSB_EVENT pevent; BOOLEAN bret; PUSB_DEV pdev; USE_BASIC_NON_PENDING_IRQL; if (dev_mgr == NULL || dev_handle == 0) return FALSE; if (usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev) != STATUS_SUCCESS) return FALSE; KeAcquireSpinLockAtDpcLevel(&dev_mgr->event_list_lock); lock_dev(pdev, TRUE); if (dev_state(pdev) == USB_DEV_STATE_ZOMB) { bret = FALSE; goto LBL_OUT; } pevent = alloc_event(&dev_mgr->event_pool, 1); if (pevent == NULL) { bret = FALSE; goto LBL_OUT; } pevent->flags = USB_EVENT_FLAG_ACTIVE; pevent->event = USB_EVENT_DEFAULT; pevent->pdev = pdev; pevent->context = 0; pevent->param = 0; pevent->pnext = 0; //vertical queue for serialized operation pevent->process_event = compdev_event_select_if_driver; pevent->process_queue = event_list_default_process_queue; InsertTailList(&dev_mgr->event_list, &pevent->event_link); KeSetEvent(&dev_mgr->wake_up_event, 0, FALSE); // wake up the dev_mgr_thread bret = TRUE; LBL_OUT: unlock_dev(pdev, TRUE); KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock); usb_unlock_dev(pdev); return bret; }
//this function is called by the hcd's //dispatch when they have done their job. NTSTATUS dev_mgr_dispatch(IN PUSB_DEV_MANAGER dev_mgr, IN PIRP irp) { PIO_STACK_LOCATION irp_stack; NTSTATUS status; ULONG ctrl_code; USE_NON_PENDING_IRQL; ASSERT(irp); if (dev_mgr == NULL) { EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp); } status = STATUS_SUCCESS; irp_stack = IoGetCurrentIrpStackLocation(irp); ctrl_code = irp_stack->Parameters.DeviceIoControl.IoControlCode; switch (irp_stack->MajorFunction) { case IRP_MJ_CREATE: { InterlockedIncrement(&dev_mgr->open_count); EXIT_DISPATCH(STATUS_SUCCESS, irp); } case IRP_MJ_CLOSE: { InterlockedDecrement(&dev_mgr->open_count); EXIT_DISPATCH(STATUS_SUCCESS, irp); } case IRP_MJ_INTERNAL_DEVICE_CONTROL: case IRP_MJ_DEVICE_CONTROL: { switch (ctrl_code) { case IOCTL_GET_DEV_COUNT: { LONG dev_count; irp->IoStatus.Information = 0; if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(LONG)) { EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp); } KeAcquireSpinLock(&dev_mgr->dev_list_lock, &old_irql); dev_count = usb_count_list(&dev_mgr->dev_list); KeReleaseSpinLock(&dev_mgr->dev_list_lock, old_irql); *((PLONG) irp->AssociatedIrp.SystemBuffer) = dev_count; irp->IoStatus.Information = sizeof(LONG); EXIT_DISPATCH(STATUS_SUCCESS, irp); } case IOCTL_ENUM_DEVICES: { PLIST_ENTRY pthis, pnext; LONG dev_count, array_size, i, j = 0; PUSB_DEV pdev; PENUM_DEV_ARRAY peda; irp->IoStatus.Information = 0; if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(LONG)) { EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp); } if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ENUM_DEV_ARRAY)) { EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp); } array_size = *((PULONG) irp->AssociatedIrp.SystemBuffer); KeAcquireSpinLock(&dev_mgr->dev_list_lock, &old_irql); dev_count = usb_count_list(&dev_mgr->dev_list); dev_count = dev_count > array_size ? array_size : dev_count; peda = (PENUM_DEV_ARRAY) irp->AssociatedIrp.SystemBuffer; RtlZeroMemory(peda, sizeof(ENUM_DEV_ARRAY) + (dev_count - 1) * sizeof(ENUM_DEV_ELEMENT)); if (dev_count) { ListFirst(&dev_mgr->dev_list, pthis); for(i = 0, j = 0; i < dev_count; i++) { pdev = struct_ptr(pthis, USB_DEV, dev_link); ListNext(&dev_mgr->dev_list, pthis, pnext); pthis = pnext; lock_dev(pdev, FALSE); if (dev_state(pdev) == USB_DEV_STATE_ZOMB) { unlock_dev(pdev, FALSE); continue; } if (dev_state(pdev) < USB_DEV_STATE_ADDRESSED) { unlock_dev(pdev, FALSE); continue; } peda->dev_arr[i].dev_handle = (pdev->dev_id << 16); //may not get the desc yet if (pdev->pusb_dev_desc) { peda->dev_arr[i].product_id = pdev->pusb_dev_desc->idProduct; peda->dev_arr[i].vendor_id = pdev->pusb_dev_desc->idVendor; } else { peda->dev_arr[i].product_id = 0xffff; peda->dev_arr[i].vendor_id = 0xffff; } peda->dev_arr[i].dev_addr = pdev->dev_addr; unlock_dev(pdev, FALSE); j++; } } peda->dev_count = dev_count ? j : 0; KeReleaseSpinLock(&dev_mgr->dev_list_lock, old_irql); irp->IoStatus.Information = sizeof(ENUM_DEV_ARRAY) + (dev_count - 1) * sizeof(ENUM_DEV_ELEMENT); EXIT_DISPATCH(STATUS_SUCCESS, irp); } case IOCTL_GET_DEV_DESC: { GET_DEV_DESC_REQ gddr; PUSB_DESC_HEADER pusb_desc_header; PUSB_DEV pdev; LONG buf_size; if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(GET_DEV_DESC_REQ)) { EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp); } if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < 8) { EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp); } status = STATUS_SUCCESS; buf_size = irp_stack->Parameters.DeviceIoControl.OutputBufferLength; RtlCopyMemory(&gddr, irp->AssociatedIrp.SystemBuffer, sizeof(GET_DEV_DESC_REQ)); pusb_desc_header = irp->AssociatedIrp.SystemBuffer; if (gddr.desc_type != USB_DT_CONFIG && gddr.desc_type != USB_DT_DEVICE) { EXIT_DISPATCH(STATUS_INVALID_DEVICE_REQUEST, irp); } if (usb_query_and_lock_dev(dev_mgr, gddr.dev_handle, &pdev) != STATUS_SUCCESS) { EXIT_DISPATCH(STATUS_IO_DEVICE_ERROR, irp); } lock_dev(pdev, FALSE); if (dev_state(pdev) == USB_DEV_STATE_ZOMB) { status = STATUS_INVALID_DEVICE_STATE; goto ERROR_OUT; } if (dev_state(pdev) != USB_DEV_STATE_ADDRESSED && dev_state(pdev) != USB_DEV_STATE_CONFIGURED) { status = STATUS_DEVICE_NOT_READY; goto ERROR_OUT; } if (pdev->pusb_dev_desc == NULL) { status = STATUS_DEVICE_NOT_READY; goto ERROR_OUT; } if (gddr.desc_type == USB_DT_DEVICE) { RtlCopyMemory(pusb_desc_header, pdev->pusb_dev_desc, buf_size > sizeof(USB_DEVICE_DESC) ? sizeof(USB_DEVICE_DESC) : buf_size); irp->IoStatus.Information = buf_size >= sizeof(USB_DEVICE_DESC) ? sizeof(USB_DEVICE_DESC) : buf_size; } else if (gddr.desc_type == USB_DT_CONFIG) { PUSB_CONFIGURATION_DESC pusb_config_desc; if (pdev->pusb_dev_desc->bNumConfigurations <= gddr.desc_idx) { status = STATUS_INVALID_PARAMETER; goto ERROR_OUT; } pusb_config_desc = usb_find_config_desc_by_idx((PUCHAR) & pdev->pusb_dev_desc[1], gddr.desc_idx, pdev->pusb_dev_desc-> bNumConfigurations); if (pusb_config_desc == NULL) { status = STATUS_DEVICE_NOT_READY; goto ERROR_OUT; } RtlCopyMemory(pusb_desc_header, pusb_config_desc, buf_size >= pusb_config_desc->wTotalLength ? pusb_config_desc->wTotalLength : buf_size); irp->IoStatus.Information = buf_size >= pusb_config_desc->wTotalLength ? pusb_config_desc->wTotalLength : buf_size; } ERROR_OUT: unlock_dev(pdev, FALSE); usb_unlock_dev(pdev); EXIT_DISPATCH(status, irp); } case IOCTL_SUBMIT_URB_RD: case IOCTL_SUBMIT_URB_WR: case IOCTL_SUBMIT_URB_NOIO: { 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; if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(URB)) { EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp); } purb = (PURB) irp->AssociatedIrp.SystemBuffer; endp_handle = purb->endp_handle; if (ctrl_code == IOCTL_SUBMIT_URB_RD || ctrl_code == IOCTL_SUBMIT_URB_WR) { if (irp_stack->MajorFunction == IRP_MJ_DEVICE_CONTROL) { user_buffer_length = irp_stack->Parameters.DeviceIoControl.OutputBufferLength; if (user_buffer_length == 0) EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp); user_buffer = MmGetSystemAddressForMdl(irp->MdlAddress); } else { if (purb->data_buffer == NULL || purb->data_length == 0) EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp); user_buffer_length = purb->data_length; user_buffer = purb->data_buffer; } } if (usb_query_and_lock_dev(dev_mgr, endp_handle & ~0xffff, &pdev) != STATUS_SUCCESS) { EXIT_DISPATCH(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 > 0x100000) { 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) { if (ctrl_code == IOCTL_SUBMIT_URB_RD) KeFlushIoBuffers(irp->MdlAddress, TRUE, TRUE); else KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE); 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 mark irp before the urb is scheduled to // avoid race condition IoMarkIrpPending(irp); ASSERT(dev_mgr_register_irp(dev_mgr, irp, purb)); status = usb_submit_urb(dev_mgr, purb); if (status != STATUS_PENDING) { 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; IoCompleteRequest(irp, IO_NO_INCREMENT); } return status; ERROR_OUT1: unlock_dev(pdev, FALSE); usb_unlock_dev(pdev); irp->IoStatus.Information = 0; EXIT_DISPATCH(status, irp); } default: { irp->IoStatus.Information = 0; EXIT_DISPATCH(STATUS_NOT_IMPLEMENTED, irp); } } } default: { irp->IoStatus.Information = 0; break; } } EXIT_DISPATCH(STATUS_INVALID_DEVICE_REQUEST, irp); }