Logo Search packages:      
Sourcecode: baycomusb version File versions  Download package

dabusb.c

// $Id: dabusb.c,v 1.40 2000/01/08 09:00:11 fliegl Exp $
//
// Include files needed for WDM driver support
//
#include <wdm.h>
#include "stdarg.h"
#include "stdio.h"

//
// Include files needed for USB support
//
#include "usbdi.h"
#include "usbdlib.h"

//
// Include file for the dabusb Device
//
#include "bcusb.h"

#if 0
#define VLOG(x)  do { x; } while (0)
#else
#define VLOG(x)  do {  } while (0)
#endif

#if 1
#define ELOG(x)  do { x; } while (0)
#else
#define ELOG(x)  do {  } while (0)
#endif

/* --------------------------------------------------------------------- */

#ifdef CONNECTEVENT
/* IoCreateSynchronizationObject does not exist in W98 WDM */
static PKEVENT sync_event;
static HANDLE sync_event_handle;
#endif

/* --------------------------------------------------------------------- */

LONG dabusb_decrement_io_count(PDEVICE_OBJECT fdo)
{
      pdabusb_t s = fdo->DeviceExtension;
      LONG ioCount;
      
      ioCount = InterlockedDecrement(&s->pending_io_count);
      if (ioCount <= 1) {
            /* trigger no pending io */
            KeSetEvent(&s->NoPendingIoEvent, 1, FALSE);
      }
      if (ioCount == 0) {
            /* trigger remove-device event */
            KeSetEvent(&s->RemoveEvent, 1, FALSE);
      }
      return ioCount;
}

VOID dabusb_increment_io_count(PDEVICE_OBJECT fdo)
{
      pdabusb_t s = fdo->DeviceExtension;
        LONG ioCount;

      KeClearEvent(&s->RemoveEvent);
      KeClearEvent(&s->NoPendingIoEvent);
      ioCount = InterlockedIncrement(&s->pending_io_count);
      if (ioCount <= 1) {
            /* trigger no pending io */
            KeSetEvent(&s->NoPendingIoEvent, 1, FALSE);
      }
}

/* --------------------------------------------------------------------- */

NTSTATUS OnRequestComplete(IN PDEVICE_OBJECT fdo, IN PIRP irp, IN PKEVENT pev )
{
      KeSetEvent(pev, 0, FALSE);
      return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS ForwardAndWait(IN PDEVICE_OBJECT fdo, IN PIRP irp )
{
      KEVENT event;
      pdabusb_t s = (pdabusb_t) fdo->DeviceExtension;
      NTSTATUS ret;

        ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

      //
      // Initialize a kernel event object to use in waiting for the lower-level
      // driver to finish processing the object. 
      //
      KeInitializeEvent(&event, NotificationEvent, FALSE);

      IoCopyCurrentIrpStackLocationToNext(irp);
      IoSetCompletionRoutine(irp, (PIO_COMPLETION_ROUTINE) OnRequestComplete, (PVOID) &event, TRUE, TRUE, TRUE);

      ret = IoCallDriver(s->sdo, irp);

      if (ret == STATUS_PENDING) {
            KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
            ret = irp->IoStatus.Status;
      }

      return ret;
}

// -----------------------------------------------------------

static NTSTATUS dabusb_StartDevice(PDEVICE_OBJECT fdo)
{
      NTSTATUS ret = STATUS_SUCCESS;
        unsigned char mode;
        
      VLOG(printk(MODSTR "enter dabusb_StartDevice\n"));

        //usb_control_msg(fdo, 0xc0, 0xc8, 0, 0, 1, &mode, 500);

      VLOG(printk(MODSTR "exit dabusb_StartDevice (%x)\n", ret));

      return ret;
}

NTSTATUS dabusb_RemoveDevice( IN  PDEVICE_OBJECT fdo)
{
      pdabusb_t s = fdo->DeviceExtension;
      NTSTATUS ret = STATUS_SUCCESS;

      VLOG(printk(MODSTR "enter dabusb_RemoveDevice\n"));

      async_cancel_all(fdo);
      abort_pipes(fdo);

      IoDeleteSymbolicLink(&s->deviceLinkUnicodeString);
      RtlFreeUnicodeString(&s->deviceLinkUnicodeString);

      IoDetachDevice(s->sdo);
      IoDeleteDevice (fdo);

      VLOG(printk(MODSTR "exit dabusb_RemoveDevice (%x)\n", ret));

      return ret;
}

NTSTATUS dabusb_HandleStartDevice( IN PDEVICE_OBJECT fdo, IN PIRP irp )
{
      NTSTATUS ret;
      PIO_STACK_LOCATION stack;

      //
      // First let all lower-level drivers handle this request.
      //
      ret = ForwardAndWait(fdo, irp);
      if (!NT_SUCCESS(ret))
      {
            irp->IoStatus.Status = ret;
            IoCompleteRequest(irp, IO_NO_INCREMENT);
            return ret;
      }
      //
      // now do whatever we need to do to start the device
      //
      ret = dabusb_StartDevice(fdo);

      irp->IoStatus.Status = ret;
      irp->IoStatus.Information = 0;
      IoCompleteRequest(irp, IO_NO_INCREMENT);
      return ret;
}

NTSTATUS dabusb_dispatch_pnp( IN PDEVICE_OBJECT fdo, IN PIRP irp )
{
      PIO_STACK_LOCATION irpStack;
      pdabusb_t s = fdo->DeviceExtension;
      ULONG fcn;
      NTSTATUS ret = STATUS_SUCCESS;
      PDEVICE_CAPABILITIES DeviceCapabilities;

      irpStack = IoGetCurrentIrpStackLocation (irp);
        ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
      fcn = irpStack->MinorFunction;
      VLOG(printk(MODSTR "dabusb_dispatch_pnp enter: fcn %lu\n", fcn));
      dabusb_increment_io_count(fdo);
      switch (fcn) {
        case IRP_MN_QUERY_CAPABILITIES:
                VLOG(printk(MODSTR "IRP_MN_QUERY_CAPABILITIES\n"));
                ret = ForwardAndWait(fdo, irp);
                DeviceCapabilities = irpStack->Parameters.DeviceCapabilities.Capabilities;
                DeviceCapabilities->SurpriseRemovalOK = TRUE;
                IoCompleteRequest(irp, IO_NO_INCREMENT);
            dabusb_decrement_io_count(fdo);
            VLOG(printk(MODSTR "dabusb_dispatch_pnp exit: 0x%x\n", ret));
            return ret;

        case IRP_MN_QUERY_PNP_DEVICE_STATE: 
                VLOG(printk(MODSTR"IRP_MN_QUERY_PNP_DEVICE_STATE\n"));
                break;

        case IRP_MN_QUERY_DEVICE_RELATIONS:
                VLOG(printk(MODSTR"IRP_MN_QUERY_DEVICE_RELATIONS\n"));
                break;

        case IRP_MN_START_DEVICE:
                VLOG(printk(MODSTR "IRP_MN_START_DEVICE\n"));
                s->device_state = _started;
            VLOG(printk(MODSTR "device state: started\n"));
                ret = dabusb_HandleStartDevice(fdo,irp);
            dabusb_decrement_io_count(fdo);
            VLOG(printk(MODSTR "dabusb_dispatch_pnp exit: 0x%x\n", ret));
                return ret;

        case IRP_MN_STOP_DEVICE:
                VLOG(printk(MODSTR "IRP_MN_STOP_DEVICE\n"));
                s->device_state = _stopped;
            VLOG(printk(MODSTR "device state: stopped\n"));
            async_cancel_all(fdo);
            abort_pipes(fdo);
                break;

        case IRP_MN_SURPRISE_REMOVAL:
                VLOG(printk(MODSTR "IRP_MN_SURPRISE_REMOVAL\n"));
                goto queryrm_or_surpriserm;

        case IRP_MN_QUERY_REMOVE_DEVICE:
                VLOG(printk(MODSTR "IRP_MN_QUERY_REMOVE_DEVICE\n"));
      queryrm_or_surpriserm:
            if (s->device_state < _started) {
                  IoSkipCurrentIrpStackLocation (irp);
                  ret = IoCallDriver (s->sdo, irp);
                  dabusb_decrement_io_count(fdo);
                  VLOG(printk(MODSTR "dabusb_dispatch_pnp exit: 0x%x\n", ret));
                  return ret;
            }
            s->device_state = _remove_pending;
            VLOG(printk(MODSTR "device state: remove_pending\n"));
            dabusb_decrement_io_count(fdo);
            async_cancel_all(fdo);
            abort_pipes(fdo);
                KeWaitForSingleObject(&s->NoPendingIoEvent, Suspended, KernelMode, FALSE, NULL);
            IoCopyCurrentIrpStackLocationToNext(irp);
            ret = IoCallDriver(s->sdo, irp);
            VLOG(printk(MODSTR "dabusb_dispatch_pnp exit: 0x%x\n", ret));
            return ret;

        case IRP_MN_REMOVE_DEVICE:
                printk( MODSTR "IRP_MN_REMOVE_DEVICE\n");
            dabusb_decrement_io_count(fdo);
            s->device_state = _removed;
            VLOG(printk(MODSTR "device state: removed\n"));
            async_cancel_all(fdo);
            abort_pipes(fdo);
                IoCopyCurrentIrpStackLocationToNext(irp);
            ret = IoCallDriver(s->sdo, irp);
            dabusb_decrement_io_count(fdo);
            KeWaitForSingleObject(&s->RemoveEvent, Suspended, KernelMode, FALSE, NULL);
            VLOG(printk(MODSTR "IRP_MN_REMOVE_DEVICE: KeWaitForSingleObject succeeded\n"));
            dabusb_RemoveDevice(fdo);
            VLOG(printk(MODSTR "dabusb_dispatch_pnp exit: 0x%x\n", ret));
            return ret;
                
                /* All other PNP IRP's are just passed down the stack by the default handler */
        default:
                VLOG(printk(MODSTR "Passing down unhandled PnP IOCTL MJ=0x%x MN=0x%x\n",
                      irpStack->MajorFunction, irpStack->MinorFunction));
            break;
      }
      if (!NT_SUCCESS(ret)) {
                // if anything went wrong, return failure  without passing Irp down
            irp->IoStatus.Status = ret;
                IoCompleteRequest(irp, IO_NO_INCREMENT);
            dabusb_decrement_io_count(fdo);
            VLOG(printk(MODSTR "dabusb_dispatch_pnp exit: 0x%x\n", ret));
                return ret;
      }
      IoCopyCurrentIrpStackLocationToNext(irp);
      //
      // All PNP_POWER messages get passed to the TopOfStackDeviceObject
      // we were given in PnPAddDevice
      //
      ret = IoCallDriver(s->sdo, irp);
      dabusb_decrement_io_count(fdo);
      VLOG(printk(MODSTR "dabusb_dispatch_pnp exit: 0x%x\n", ret));
        return ret;
}


VOID dabusb_unload(IN PDRIVER_OBJECT drvobj)
{
      VLOG(printk(MODSTR "dabusb_unload enter\n"));
#ifdef CONNECTEVENT
      /* release userspace synchronisation object */
      if (sync_event)
            if (!NT_SUCCESS(ZwClose(sync_event_handle)))
                  printk(MODSTR "ZwClose of SynchronisationEvent failed\n");
      sync_event = NULL;
      sync_event_handle = NULL;
#endif
      VLOG(printk(MODSTR "dabusb_unload exit\n"));
}

NTSTATUS dabusb_pnp_add_device(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT pdo)
{
      NTSTATUS ret = STATUS_SUCCESS;
      PDEVICE_OBJECT fdo = NULL;
      UNICODE_STRING deviceNameUnicodeString;
      ANSI_STRING ansibuf;
      pdabusb_t s;
      PCHAR buf = kmalloc(80);
      int instance = 0;
        unsigned int i;
        
      if(!buf) {
            printk(MODSTR"dabusb_pnp_add_device: can't kmalloc buf");
            return STATUS_NO_MEMORY;
      }

      VLOG(printk(MODSTR"enter dabusb_PnPAddDevice (%x)\n", ret));

      do {
            sprintf(buf,"\\Device\\"MODNAME"%d",instance);
            RtlInitAnsiString(&ansibuf, buf);
            RtlAnsiStringToUnicodeString(&deviceNameUnicodeString, &ansibuf, TRUE);
            ret = IoCreateDevice(DriverObject, sizeof(dabusb_t), &deviceNameUnicodeString, FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo);
            if (NT_SUCCESS(ret))
                  break;
            RtlFreeUnicodeString(&deviceNameUnicodeString);
            instance++;
      } while (instance < 10);

      VLOG(printk(MODSTR "dabusb_pnp_add_device instance: %s\n", buf));

      if (NT_SUCCESS(ret)) {
            s = fdo->DeviceExtension;
            fdo->Flags &= ~DO_DEVICE_INITIALIZING;
            fdo->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
            memset(s, 0, sizeof(dabusb_t));
            s->pdo = pdo;
            s->sdo = IoAttachDeviceToDeviceStack(fdo, pdo);
            // Get a copy of the physical device's capabilities into a
            // DEVICE_CAPABILITIES struct in our device extension;
            // We are most interested in learning which system power states
            // are to be mapped to which device power states for handling
            // IRP_MJ_SET_POWER Irps.
            dabusb_QueryCapabilities(pdo, &s->DeviceCapabilities);
 
                // We want to determine what level to auto-powerdown to; This is the lowest
                //  sleeping level that is LESS than D3;
                // If all are set to D3, auto powerdown/powerup will be disabled.
            s->PowerDownLevel = PowerDeviceUnspecified; // init to disabled
            for (i = PowerSystemSleeping1; i <= PowerSystemSleeping3; i++) {
                        if (s->DeviceCapabilities.DeviceState[i] < PowerDeviceD3)
                                s->PowerDownLevel = s->DeviceCapabilities.DeviceState[i];
            }
                VLOG(printk(MODSTR "s->PowerDownLevel: %x\n",s->PowerDownLevel));

            /* this event is triggered when there is no pending io of any kind and device is removed */
            KeInitializeEvent(&s->RemoveEvent, SynchronizationEvent, FALSE);
            
            /* this event is triggered when there is no pending io  (pending io count == 1) */
            KeInitializeEvent(&s->NoPendingIoEvent, SynchronizationEvent, FALSE);
            /* this event is triggered when self-requested power irps complete */
            KeInitializeEvent(&s->SelfRequestedPowerIrpEvent, NotificationEvent, FALSE);

            KeInitializeEvent(&s->release_ok, SynchronizationEvent, FALSE);

            KeInitializeSemaphore(&s->open_sem, 1, 1);

            KeInitializeSpinLock(&s->cancel_list_lock);
            INIT_LIST_HEAD(&s->cancel_list);

            sprintf(buf, "\\DosDevices\\"MODNAME"%d", instance);
            RtlInitAnsiString(&ansibuf, buf);
            RtlAnsiStringToUnicodeString(&s->deviceLinkUnicodeString, &ansibuf, TRUE);
            ret = IoCreateSymbolicLink(&s->deviceLinkUnicodeString, &deviceNameUnicodeString);
            RtlFreeUnicodeString(&deviceNameUnicodeString);
            ASSERT(s->sdo != NULL);
            dabusb_increment_io_count(fdo);
            // try to power down device until IO actually requested
            dabusb_SelfSuspendOrActivate(fdo, TRUE);
#ifdef CONNECTEVENT
            /* signal user space */
            KeSetEvent(sync_event, 0, FALSE);
#endif
      }
      kfree(buf);

      VLOG(printk(MODSTR "exit dabusb_PnPAddDevice (%x)\n", ret));

      return ret;
}

NTSTATUS dabusb_release(IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
      pdabusb_t s = fdo->DeviceExtension;

      VLOG(printk(MODSTR"dabusb_release enter\n"));
        async_cancel_all(fdo);
      abort_pipes(fdo);
      irp->IoStatus.Status = STATUS_SUCCESS;        
      irp->IoStatus.Information = 0;
      IoCompleteRequest(irp, IO_NO_INCREMENT);
      //KeReleaseSemaphore(&s->open_sem, LOW_REALTIME_PRIORITY, 1, FALSE);
        InterlockedDecrement(&s->opened);
        // try to power down device if this is the last pipe
        dabusb_SelfSuspendOrActivate(fdo, TRUE);
      VLOG(printk(MODSTR"dabusb_release exit\n"));
      return irp->IoStatus.Status;
}

NTSTATUS dabusb_open(IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
      pdabusb_t s = fdo->DeviceExtension;

      VLOG(printk(MODSTR"dabusb_open enter\n"));
        if (InterlockedIncrement(&s->opened) > 1) {
                irp->IoStatus.Status = STATUS_DEVICE_BUSY;
            VLOG(printk(MODSTR"dabusb_open exit: device busy\n"));
                goto done;
        }
        if (s->device_state <= _stop_pending) {
                irp->IoStatus.Status = STATUS_DELETE_PENDING;
                ELOG(printk(MODSTR"dabusb_open exit: stop pending\n"));
                goto done;
        }
        /* try to power up device if its not in D0 */
        dabusb_SelfSuspendOrActivate(fdo, FALSE);

  done:;
        if (irp->IoStatus.Status != STATUS_SUCCESS)
                InterlockedDecrement(&s->opened);
        irp->IoStatus.Information = 0;
        IoCompleteRequest(irp, IO_NO_INCREMENT);
      VLOG(printk(MODSTR "dabusb_open: exit 0x%x\n", irp->IoStatus.Status));
        return irp->IoStatus.Status;
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
{
      NTSTATUS ret = STATUS_SUCCESS;
      PDEVICE_OBJECT deviceObject = NULL;
      UNICODE_STRING eventname;

      printk(MODSTR "BaycomUSB Driver V"VERSTR" (c) DF&TS compiled "__DATE__" "__TIME__"\n");

#ifdef CONNECTEVENT
      /* create userspace synchronisation object */
      RtlInitUnicodeString(&eventname, EVENTNAME);
      sync_event = IoCreateNotificationEvent(&eventname, &sync_event_handle);
      if (!sync_event)
            printk(MODSTR "cannot create SynchronizationEvent\n");
#endif

      DriverObject->MajorFunction[IRP_MJ_CREATE] =          dabusb_open;
      DriverObject->MajorFunction[IRP_MJ_CLOSE] =           dabusb_release;
      //DriverObject->MajorFunction[IRP_MJ_READ] =          dabusb_read;
      DriverObject->DriverUnload =                    dabusb_unload;
      DriverObject->MajorFunction[IRP_MJ_PNP] =       dabusb_dispatch_pnp;
      DriverObject->MajorFunction[IRP_MJ_POWER] =           dabusb_dispatch_power;
      DriverObject->DriverExtension->AddDevice =            dabusb_pnp_add_device;
      DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =    baycomusb_ioctl;
      DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = baycomusb_internal_ioctl;

      return ret;
}

Generated by  Doxygen 1.6.0   Back to index