Beispiel #1
0
NTSTATUS DDKAPI dispatch(DEVICE_OBJECT *device_object, IRP *irp)
{
    libusb_device_t *dev = device_object->DeviceExtension;
    IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);

    switch (stack_location->MajorFunction)
    {
    case IRP_MJ_PNP:
        return dispatch_pnp(dev, irp);

    case IRP_MJ_POWER:
		// ID: 2960644 (farthen)
		// You can't set the power state if the device is not handled at all
		if(!dev->next_stack_device)
		{
			return complete_irp(irp, STATUS_INVALID_DEVICE_STATE, 0);
		}
        return dispatch_power(dev, irp);
    }

    /* since this driver may run as an upper filter we have to check whether */
    /* the IRP is sent to this device object or to the lower one */
    if (accept_irp(dev, irp))
    {
        switch (stack_location->MajorFunction)
        {
        case IRP_MJ_DEVICE_CONTROL:

            if (dev->is_started)
            {
                return dispatch_ioctl(dev, irp);
            }
            else /* not started yet */
            {
                return complete_irp(irp, STATUS_INVALID_DEVICE_STATE, 0);
            }

        case IRP_MJ_CREATE:

            if (dev->is_started)
            {
				// only one driver can act as power policy owner and 
				// power_set_device_state() can only be issued by the PPO.
				// disallow_power_control is set to true for drivers which 
				// we know cause a BSOD on any attempt to request power irps.
                if (dev->power_state.DeviceState != PowerDeviceD0 && !dev->disallow_power_control)
                {
                    /* power up the device, block until the call */
                    /* completes */
                    power_set_device_state(dev, PowerDeviceD0, TRUE);
                }
                return complete_irp(irp, STATUS_SUCCESS, 0);
            }
            else /* not started yet */
            {
                return complete_irp(irp, STATUS_INVALID_DEVICE_STATE, 0);
            }

        case IRP_MJ_CLOSE:

            /* release all interfaces bound to this file object */
            release_all_interfaces(dev, stack_location->FileObject);
            return complete_irp(irp, STATUS_SUCCESS, 0);

        case IRP_MJ_CLEANUP:

            return complete_irp(irp, STATUS_SUCCESS, 0);

        default:
            return complete_irp(irp, STATUS_NOT_SUPPORTED, 0);
        }
    }
    else /* the IRP is for the lower device object */
    {
        return pass_irp_down(dev, irp, NULL, NULL);
    }
}
NTSTATUS transfer(libusb_device_t *dev, IRP *irp,
                  int direction, int urb_function, int endpoint, 
                  int packet_size, MDL *buffer, int size)
{
  IO_STACK_LOCATION *stack_location = NULL;
  context_t *context;
  NTSTATUS status = STATUS_SUCCESS;
 
  DEBUG_PRINT_NL();

  if(urb_function == URB_FUNCTION_ISOCH_TRANSFER)
    DEBUG_MESSAGE("transfer(): isochronous transfer");
  else
    DEBUG_MESSAGE("transfer(): bulk or interrupt transfer");

  if(direction == USBD_TRANSFER_DIRECTION_IN)
    DEBUG_MESSAGE("transfer(): direction in");
  else
    DEBUG_MESSAGE("transfer(): direction out");

  DEBUG_MESSAGE("transfer(): endpoint 0x%02x", endpoint);

  if(urb_function == URB_FUNCTION_ISOCH_TRANSFER)
    DEBUG_MESSAGE("transfer(): packet_size 0x%x", packet_size);

  DEBUG_MESSAGE("transfer(): size %d", size);
  DEBUG_MESSAGE("transfer(): sequence %d", sequence);
  DEBUG_PRINT_NL();

  if(!dev->config.value)
    {
      DEBUG_ERROR("transfer(): invalid configuration 0");
      remove_lock_release(dev);
      return complete_irp(irp, STATUS_INVALID_DEVICE_STATE, 0);
    }
  
  context = ExAllocatePool(NonPagedPool, sizeof(context_t));

  if(!context)
    {
      remove_lock_release(dev);
      return complete_irp(irp, STATUS_NO_MEMORY, 0);
    }

  status = create_urb(dev, &context->urb, direction, urb_function, 
                      endpoint, packet_size, buffer, size);
    
  if(!NT_SUCCESS(status))
    {
      ExFreePool(context);
      remove_lock_release(dev);
      return complete_irp(irp, status, 0);
    }

  context->sequence = sequence++;

  stack_location = IoGetNextIrpStackLocation(irp);
    
  stack_location->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  stack_location->Parameters.Others.Argument1 = context->urb;
  stack_location->Parameters.DeviceIoControl.IoControlCode 
    = IOCTL_INTERNAL_USB_SUBMIT_URB;
    
  IoSetCompletionRoutine(irp, transfer_complete, context,
                         TRUE, TRUE, TRUE);
    
  return IoCallDriver(dev->target_device, irp);
}
NTSTATUS dispatch_pnp(libusb_device_t *dev, IRP *irp)
{
  NTSTATUS status = STATUS_SUCCESS;
  IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
  UNICODE_STRING symbolic_link_name;
  WCHAR tmp_name[128];

  status = remove_lock_acquire(dev);
  
  if(!NT_SUCCESS(status))
    { 
      return complete_irp(irp, status, 0);
    }

  DEBUG_PRINT_NL();

  switch(stack_location->MinorFunction) 
    {     
    case IRP_MN_REMOVE_DEVICE:

      DEBUG_MESSAGE("dispatch_pnp(): IRP_MN_REMOVE_DEVICE");

      dev->is_started = FALSE;
      
      /* wait until all outstanding requests are finished */
      remove_lock_release_and_wait(dev);

      status = pass_irp_down(dev, irp, NULL, NULL); 

      DEBUG_MESSAGE("dispatch_pnp(): deleting device #%d", dev->id);
      
      _snwprintf(tmp_name, sizeof(tmp_name)/sizeof(WCHAR), L"%s%04d", 
                 LIBUSB_SYMBOLIC_LINK_NAME, dev->id);
      
      /* delete the symbolic link */
      RtlInitUnicodeString(&symbolic_link_name, tmp_name);
      IoDeleteSymbolicLink(&symbolic_link_name);

      /* delete the device object */
      IoDetachDevice(dev->next_stack_device);
      IoDeleteDevice(dev->self);

      return status;

    case IRP_MN_SURPRISE_REMOVAL:

      DEBUG_MESSAGE("dispatch_pnp(): IRP_MN_SURPRISE_REMOVAL");
      dev->is_started = FALSE;
      break;

    case IRP_MN_START_DEVICE:

      DEBUG_MESSAGE("dispatch_pnp(): IRP_MN_START_DEVICE");

/*       if(!NT_SUCCESS(set_configuration(dev, 1, 1000))) */
/*         { */
/*           DEBUG_ERROR("dispatch_pnp(): IRP_MN_START_DEVICE: selecting " */
/*                       "configuration failed"); */
/*         } */

      /* report device state to Power Manager */
      /* power_state.DeviceState has been set to D0 by add_device() */
      PoSetPowerState(dev->self, DevicePowerState, dev->power_state);

      return pass_irp_down(dev, irp, on_start_complete, NULL);

    case IRP_MN_STOP_DEVICE:

      dev->is_started = FALSE;
      DEBUG_MESSAGE("dispatch_pnp(): IRP_MN_STOP_DEVICE");
      break;

    case IRP_MN_DEVICE_USAGE_NOTIFICATION:

      DEBUG_MESSAGE("dispatch_pnp(): IRP_MN_DEVICE_USAGE_NOTIFICATION");

      if(!dev->self->AttachedDevice
         || (dev->self->AttachedDevice->Flags & DO_POWER_PAGABLE))
        {
          dev->self->Flags |= DO_POWER_PAGABLE;
        }

      return pass_irp_down(dev, irp, on_device_usage_notification_complete,
                           NULL);

    case IRP_MN_QUERY_CAPABILITIES: 

      DEBUG_MESSAGE("dispatch_pnp(): IRP_MN_QUERY_CAPABILITIES");

      if(!dev->is_filter)
        {
          /* apply registry setting */
          stack_location->Parameters.DeviceCapabilities.Capabilities
            ->SurpriseRemovalOK = dev->surprise_removal_ok;
        }

      return pass_irp_down(dev, irp, on_query_capabilities_complete,  NULL);

    default:
      ;
    }

  remove_lock_release(dev);
  return pass_irp_down(dev, irp, NULL, NULL);
}
NTSTATUS DDKAPI dispatch(DEVICE_OBJECT *device_object, IRP *irp)
{
  libusb_device_t *dev = device_object->DeviceExtension;

  switch(IoGetCurrentIrpStackLocation(irp)->MajorFunction) 
    {
    case IRP_MJ_PNP:
      return dispatch_pnp(dev, irp);
      
    case IRP_MJ_POWER:
      return dispatch_power(dev, irp);
    }

  /* since this driver may run as an upper filter we have to check whether */
  /* the IRP is sent to this device object or to the lower one */
  if(accept_irp(dev, irp))
    {
      switch(IoGetCurrentIrpStackLocation(irp)->MajorFunction) 
        {
        case IRP_MJ_DEVICE_CONTROL:
          
          if(dev->is_started)
            {
              return dispatch_ioctl(dev, irp);
            }
          else /* not started yet */
            {
              return complete_irp(irp, STATUS_INVALID_DEVICE_STATE, 0);
            }

        case IRP_MJ_CREATE:
          
          if(dev->is_started)
            {
              if(InterlockedIncrement(&dev->ref_count) == 1)
                {
                  if(dev->power_state.DeviceState != PowerDeviceD0)
                    {
                      /* power up the device, block until the call */
                      /* completes */
                      power_set_device_state(dev, PowerDeviceD0, TRUE);
                    }
                }

              return complete_irp(irp, STATUS_SUCCESS, 0);
            }
          else /* not started yet */
            {
              return complete_irp(irp, STATUS_INVALID_DEVICE_STATE, 0);
            }
          
        case IRP_MJ_CLOSE:
          
          if(!InterlockedDecrement(&dev->ref_count))
            {
              /* release all interfaces when the last handle is closed */
              release_all_interfaces(dev);
            }
          return complete_irp(irp, STATUS_SUCCESS, 0);
          
        case IRP_MJ_CLEANUP:

          return complete_irp(irp, STATUS_SUCCESS, 0);
          
        default:
          return complete_irp(irp, STATUS_NOT_SUPPORTED, 0);
        }
    }
  else /* the IRP is for the lower device object */
    {
      return pass_irp_down(dev, irp, NULL, NULL);
    }
}