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

bcioctl.c

/*
 * 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 baycomusb Device
 */
#include "bcusb.h"

#include "usbdevio.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

/*
 * Helper structures for synchronous calls to USBD with timeout
 */

#define USBDEVFS_INTERNAL_CONTROL      CTL_CODE(FILE_DEVICE_USBDEVIO,256,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define USBDEVFS_INTERNAL_BULK         CTL_CODE(FILE_DEVICE_USBDEVIO,257,METHOD_BUFFERED,FILE_ANY_ACCESS)

struct internal_ctrlbulk {
        unsigned int timeout; /* in milliseconds */
        PURB urb;
};


/*
 * Synchronous call to usbd; note: no timeout
 */

NTSTATUS call_usbd(PDEVICE_OBJECT fdo, PURB urb)
{
      NTSTATUS ret;
      pdabusb_t s;
      PIRP irp;
      KEVENT event;
      IO_STATUS_BLOCK ioStatus;
      PIO_STACK_LOCATION ns;
        
      s = fdo->DeviceExtension;
        if(s->device_state == _removed || s->CurrentDevicePowerState == PowerDeviceD3)
                return STATUS_DELETE_PENDING;
      KeInitializeEvent(&event, NotificationEvent, FALSE);
      irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB, s->sdo,
                                            NULL, 0, NULL, 0, TRUE, /* INTERNAL */
                                            &event, &ioStatus);
      ns = IoGetNextIrpStackLocation(irp);
      ASSERT(ns != NULL);
      ns->Parameters.Others.Argument1 = urb;
      ret = IoCallDriver(s->sdo, irp);
      if (ret == STATUS_PENDING) {
            KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
            ret = ioStatus.Status;
      }
      if(!NT_SUCCESS(ret) || !USBD_SUCCESS(urb->UrbHeader.Status))
            ELOG(printk(MODSTR"call_usbd: NT-Status: %08X URB-Status: %08X\n", ret, urb->UrbHeader.Status));
      return ret;
}

/*
 * Synchronous call to usbd; with timeout
 */

static NTSTATUS callusbdtimeoutcompletion(PDEVICE_OBJECT devobj, PIRP irp, PKEVENT event)
{
        KeSetEvent(event, 0, FALSE);
        return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS call_usbd_timeout(PDEVICE_OBJECT fdo, PURB urb, unsigned int tmo)
{
      NTSTATUS ret;
      pdabusb_t s;
      PIRP irp;
      KEVENT event;
      IO_STATUS_BLOCK ioStatus;
      PIO_STACK_LOCATION ns;
        LARGE_INTEGER timeout;
        
      s = fdo->DeviceExtension;
        if(s->device_state == _removed || s->CurrentDevicePowerState == PowerDeviceD3)
                return STATUS_DELETE_PENDING;
      KeInitializeEvent(&event, NotificationEvent, FALSE);
        irp = IoAllocateIrp((CCHAR)(s->sdo->StackSize+1), FALSE);
        if (!irp)
                return STATUS_INSUFFICIENT_RESOURCES;
      ns = IoGetNextIrpStackLocation(irp);
        ns->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
        ns->Parameters.DeviceIoControl.OutputBufferLength = 0;
        ns->Parameters.DeviceIoControl.InputBufferLength = 0;
        ns->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
        irp->AssociatedIrp.SystemBuffer = NULL;
      ns->Parameters.Others.Argument1 = urb;
        IoSetCompletionRoutine(irp, callusbdtimeoutcompletion, &event, TRUE, TRUE, TRUE);
      ret = IoCallDriver(s->sdo, irp);
        if (!NT_SUCCESS(ret))
                goto out;
        if (ret != STATUS_PENDING)
                goto out;
        if (tmo)
                timeout.QuadPart = -10000 * (LONGLONG)tmo;
        ret = KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, tmo ? &timeout : NULL);
        if (ret == STATUS_TIMEOUT) {
                IoCancelIrp(irp);
                KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
        }
        ret = irp->IoStatus.Status;
        /* STATUS_TIMEOUT is not an error condition... */
#if 0
        if (ret == STATUS_CANCELLED)
                ret = STATUS_TIMEOUT;
#endif
        
  out:
        IoFreeIrp(irp);
      if(!NT_SUCCESS(ret) || !USBD_SUCCESS(urb->UrbHeader.Status))
            ELOG(printk(MODSTR"call_usbd: NT-Status: %08X URB-Status: %08X\n", ret, urb->UrbHeader.Status));
      return ret;
}

/*
 * create URB's for control and bulk transfers
 */

static NTSTATUS make_control_urb(PURB *rurb, PDEVICE_OBJECT fdo, unsigned int flags, unsigned char requesttype, unsigned char request,
                         unsigned short value, unsigned short index, unsigned short length, void *data, PMDL mdl)
{
      pdabusb_t s = fdo->DeviceExtension;
        USHORT func;
        PURB urb;
      unsigned int flg;

      *rurb = NULL;
        if (request == 6 && requesttype == 0x80 && value >= 1 && value <= 3) {
                if (!(urb = kmalloc(sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST))))
                        return STATUS_NO_MEMORY;
                UsbBuildGetDescriptorRequest(urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
                                             (value == 1) ? USB_DEVICE_DESCRIPTOR_TYPE :
                                             (value == 2) ? USB_CONFIGURATION_DESCRIPTOR_TYPE : USB_STRING_DESCRIPTOR_TYPE,
                                             index, 0, data, mdl, length, NULL);
            *rurb = urb;
            return STATUS_SUCCESS;
      }
        switch (requesttype & 0x60) {
        case 0x20:  /* CLASS */
                switch (requesttype & 0x1f) {
                case 0:
                        func = URB_FUNCTION_CLASS_DEVICE;
                        break;

                case 1:
                        func = URB_FUNCTION_CLASS_INTERFACE;
                        break;

                case 2:
                        func = URB_FUNCTION_CLASS_ENDPOINT;
                        break;

                case 3:
                        func = URB_FUNCTION_CLASS_OTHER;
                        break;

                default:
                        return STATUS_INVALID_PARAMETER;
                }
                break;

        case 0x40: /* VENDOR */
                switch (requesttype & 0x1f) {
                case 0:
                        func = URB_FUNCTION_VENDOR_DEVICE;
                        break;

                case 1:
                        func = URB_FUNCTION_VENDOR_INTERFACE;
                        break;

                case 2:
                        func = URB_FUNCTION_VENDOR_ENDPOINT;
                        break;

                case 3:
                        func = URB_FUNCTION_VENDOR_OTHER;
                        break;

                default:
                        return STATUS_INVALID_PARAMETER;
                }
                break;

        default:
                return STATUS_INVALID_PARAMETER;
        }
        if (!(urb = kmalloc(sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST))))
                return STATUS_NO_MEMORY;
      flg = ((requesttype & 0x80) ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT);
      if (!(flags & USBDEVFS_URB_DISABLE_SPD))
            flg |= USBD_SHORT_TRANSFER_OK;
        UsbBuildVendorRequest(urb, func, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
                              flg, 0, request, value, index, data, mdl, length, NULL);
      *rurb = urb;
      return STATUS_SUCCESS;
}

static NTSTATUS make_bulk_urb(PURB *rurb, PDEVICE_OBJECT fdo, unsigned int flags, unsigned int ep, unsigned int dlen, void *data, PMDL mdl)
{
      pdabusb_t s = fdo->DeviceExtension;
        PURB urb, urb2 = NULL;
        unsigned int maxpktsz = 0, flg;

      *rurb = NULL;
        if (ep & 0x80)
                ep = (ep & 15) | 16;
        else
                ep &= 15;
        if (!s->eptopipeh[ep])
                return STATUS_INVALID_PARAMETER;
#if 0
        /* URB link does not work by design, according to Microsoft */
        if (ep < 16)
                maxpktsz = s->epmaxpkt[ep];
        /* manually append NULL packet to conserve packet boundaries for BULK OUT */
        if ((maxpktsz > 0) && (dlen > 0) && !(dlen % maxpktsz)) {
                VLOG(printk(MODSTR"make_bulk_urb: add zero length URB\n"));
                if (!(urb2 = kmalloc(sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER))))
                        return STATUS_NO_MEMORY;
                UsbBuildInterruptOrBulkTransferRequest(urb2, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                                                       s->eptopipeh[ep], data, mdl, 0, USBD_SHORT_TRANSFER_OK, NULL);
        }
#endif
        if (!(urb = kmalloc(sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER)))) {
                if (urb2)
                        kfree(urb2);
                return STATUS_NO_MEMORY;
        }
      flg = 0;
      if (!(flags & USBDEVFS_URB_DISABLE_SPD))
            flg |= USBD_SHORT_TRANSFER_OK;
        UsbBuildInterruptOrBulkTransferRequest(urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                                               s->eptopipeh[ep], data, mdl, dlen, flg, urb2);
      *rurb = urb;
      return STATUS_SUCCESS;
}

static NTSTATUS make_iso_urb(PURB *rurb, PDEVICE_OBJECT fdo, struct usbdevfs_isotransfer *iso, void *data, PMDL mdl)
{
      pdabusb_t s = fdo->DeviceExtension;
        PURB urb;
        unsigned int ep, sz, i;
        
      *rurb = NULL;
      if (!iso || !data)
            return STATUS_INVALID_PARAMETER;
      ep = iso->ep;
        if (ep & 0x80)
                ep = (ep & 15) | 16;
        else
                ep &= 15;
        if (!s->eptopipeh[ep])
                return STATUS_INVALID_PARAMETER;
      if (iso->number_of_packets < 1 || iso->number_of_packets > 256)
            return STATUS_INVALID_PARAMETER;
      sz = GET_ISO_URB_SIZE(iso->number_of_packets);
        if (!(urb = kmalloc(sz)))
                return STATUS_NO_MEMORY;
      memset(urb, 0, sz);
        urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
      urb->UrbIsochronousTransfer.Hdr.Length = (USHORT)sz;
        urb->UrbIsochronousTransfer.PipeHandle = s->eptopipeh[ep];
        urb->UrbIsochronousTransfer.TransferFlags = (ep & 0x10) ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT;
        urb->UrbIsochronousTransfer.TransferBuffer = data;
        urb->UrbIsochronousTransfer.TransferBufferMDL = mdl;
        urb->UrbIsochronousTransfer.TransferBufferLength = iso->len;
        if (iso->flags & USBDEVFS_URB_ISO_ASAP)
            urb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP;
        urb->UrbIsochronousTransfer.NumberOfPackets = iso->number_of_packets;
        urb->UrbIsochronousTransfer.UrbLink = NULL;
      urb->UrbIsochronousTransfer.StartFrame = iso->start_frame;
 
      for (i = 0; i < iso->number_of_packets; i++) {
            urb->UrbIsochronousTransfer.IsoPacket[i].Offset = iso->iso_frame_desc[i].offset;
            urb->UrbIsochronousTransfer.IsoPacket[i].Length = iso->iso_frame_desc[i].length;
      }
      *rurb = urb;
      return STATUS_SUCCESS;
}

static NTSTATUS make_resetep_urb(PURB *rurb, PDEVICE_OBJECT fdo, USHORT func, unsigned int ep)
{
      pdabusb_t s = fdo->DeviceExtension;
        PURB urb;
        
      *rurb = NULL;
        if (ep & 0x80)
                ep = (ep & 15) | 16;
        else
                ep &= 15;
        if (!s->eptopipeh[ep])
                return STATUS_INVALID_PARAMETER;
        if (!(urb = kmalloc(sizeof(struct _URB_PIPE_REQUEST))))
                return STATUS_NO_MEMORY;
        RtlZeroMemory(urb, sizeof(struct _URB_PIPE_REQUEST));
        urb->UrbHeader.Length = sizeof(struct _URB_PIPE_REQUEST);
        urb->UrbHeader.Function = func;
        urb->UrbPipeRequest.PipeHandle = s->eptopipeh[ep];
      *rurb = urb;
      return STATUS_SUCCESS;
}

/*
 * completion handler
 */

#define COMPL_CONTROL           0
#define COMPL_BULK              1
#define COMPL_ISO               2
#define COMPL_ERRRETURN         3
#define COMPL_INTERNALCTRL      4
#define COMPL_INTERNALBULK      5

struct completionstate {
        PDEVICE_OBJECT fdo;
      unsigned int ctype;
        KDPC timeout_dpc;
      KTIMER timeout_timer;
        PIRP irp;
        PURB urb;
        NTSTATUS status;
      unsigned int cookie;
      struct list_head cancel_list;
};

static void async_timeout(PKDPC dpc, PVOID dc, PVOID SystemArgument1, PVOID SystemArgument2)
{
        struct completionstate *st = (struct completionstate *)dc;
        PDEVICE_OBJECT fdo = st->fdo;
      pdabusb_t s = fdo->DeviceExtension;

        if (!IoCancelIrp(st->irp))
            ELOG(printk(MODSTR"async_timeout: IoCancelIrp failed\n"));
        ELOG(printk(MODSTR"async_timeout: st 0x%08x ctype %d\n", (unsigned int)st, st->ctype));
}

static NTSTATUS async_complete(PDEVICE_OBJECT DevObj, PIRP irp, PVOID dc)
{
        struct completionstate *st = (struct completionstate *)dc;
        PDEVICE_OBJECT fdo = st->fdo;
      pdabusb_t s = fdo->DeviceExtension;
      PURB urb = st->urb;
      NTSTATUS ret = STATUS_SUCCESS;
        struct usbdevfs_ctrltransfer *ctrl;
        struct usbdevfs_bulktransfer *bulk;
      struct usbdevfs_isotransfer *iso;
        unsigned int *uip;
      unsigned int i;
        KIRQL irql;

        KeCancelTimer(&st->timeout_timer);
      /* take out of cookie list */
      KeAcquireSpinLock(&s->cancel_list_lock, &irql);
      list_del(&st->cancel_list);
      INIT_LIST_HEAD(&st->cancel_list);
      KeReleaseSpinLock(&s->cancel_list_lock, irql);
#if 1
        VLOG(printk(MODSTR"async_complete: st 0x%08x ntstat 0x%08x, usbd stat: 0x%08x  len: %u\n",
                    (unsigned int)st, irp->IoStatus.Status, urb->UrbHeader.Status,
                    (st->ctype == COMPL_CONTROL) ? urb->UrbControlVendorClassRequest.TransferBufferLength :
                    (st->ctype == COMPL_BULK) ? urb->UrbBulkOrInterruptTransfer.TransferBufferLength : 0));
#else
        if (!NT_SUCCESS(irp->IoStatus.Status) || !USBD_SUCCESS(urb->UrbHeader.Status))
                ELOG(printk(MODSTR"async_complete: ntstat 0x%08x, usbd stat: 0x%08x\n",
                       irp->IoStatus.Status, urb->UrbHeader.Status));
#endif
        /* If the lower driver returned PENDING, mark our stack location as pending also. */
        if (irp->PendingReturned)
                IoMarkIrpPending(irp);
      /* completion type specific processing */
      irp->IoStatus.Information = 0;
      switch (st->ctype) {
      case COMPL_CONTROL:
                ctrl = (struct usbdevfs_ctrltransfer *)irp->AssociatedIrp.SystemBuffer;
                ctrl->usberr = urb->UrbHeader.Status;
                ctrl->len = urb->UrbControlVendorClassRequest.TransferBufferLength;
                irp->IoStatus.Information = sizeof(struct usbdevfs_ctrltransfer);
            if (NT_SUCCESS(irp->IoStatus.Status) && USBD_SUCCESS(urb->UrbHeader.Status)) {
                        if (ctrl->requesttype & 0x80)
                                irp->IoStatus.Information = sizeof(struct usbdevfs_ctrltransfer) + ctrl->len;
            } else {
                  s->lastusberror = urb->UrbHeader.Status;
                  ret = STATUS_UNSUCCESSFUL;
            }
            break;

      case COMPL_BULK:
                bulk = (struct usbdevfs_bulktransfer *)irp->AssociatedIrp.SystemBuffer;
                bulk->usberr = urb->UrbHeader.Status;
                bulk->len = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
                if (urb->UrbBulkOrInterruptTransfer.UrbLink)
                        kfree(urb->UrbBulkOrInterruptTransfer.UrbLink);
                urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
            if (NT_SUCCESS(irp->IoStatus.Status) && USBD_SUCCESS(urb->UrbHeader.Status)) {
                        if (bulk->ep & 0x80)
                                irp->IoStatus.Information = sizeof(struct usbdevfs_bulktransfer) + bulk->len;
            } else {
                  s->lastusberror = urb->UrbHeader.Status;
                  ret = STATUS_UNSUCCESSFUL;
            }
            break;

      case COMPL_ISO:
                iso = (struct usbdevfs_isotransfer *)irp->AssociatedIrp.SystemBuffer;
                iso->usberr = urb->UrbHeader.Status;
            iso->error_count = urb->UrbIsochronousTransfer.ErrorCount;
            for (i = 0; i < iso->number_of_packets; i++) {
                  iso->iso_frame_desc[i].usberr = urb->UrbIsochronousTransfer.IsoPacket[i].Status;
                  iso->iso_frame_desc[i].length = urb->UrbIsochronousTransfer.IsoPacket[i].Length;
            }
            if (urb->UrbIsochronousTransfer.UrbLink)
                        kfree(urb->UrbIsochronousTransfer.UrbLink);
                urb->UrbIsochronousTransfer.UrbLink = NULL;
            if (NT_SUCCESS(irp->IoStatus.Status) && USBD_SUCCESS(urb->UrbHeader.Status)) {
                        if (iso->ep & 0x80)
                                irp->IoStatus.Information = iso->len;
            } else {
                  s->lastusberror = urb->UrbHeader.Status;
                  ret = STATUS_UNSUCCESSFUL;
            }
            break;

      case COMPL_ERRRETURN:
                uip = (unsigned int *)irp->AssociatedIrp.SystemBuffer;
                *uip = urb->UrbHeader.Status;
                irp->IoStatus.Information = sizeof(unsigned int);
            if (!NT_SUCCESS(irp->IoStatus.Status) || !USBD_SUCCESS(urb->UrbHeader.Status)) {
                  s->lastusberror = urb->UrbHeader.Status;
                  ret = STATUS_UNSUCCESSFUL;
            }
            break;

        case COMPL_INTERNALCTRL:
                irp->IoStatus.Information = urb->UrbControlVendorClassRequest.TransferBufferLength;
            if (!NT_SUCCESS(irp->IoStatus.Status) || !USBD_SUCCESS(urb->UrbHeader.Status))
                        ret = STATUS_UNSUCCESSFUL;
                break;
                
        case COMPL_INTERNALBULK:
                irp->IoStatus.Information = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
            if (!NT_SUCCESS(irp->IoStatus.Status) || !USBD_SUCCESS(urb->UrbHeader.Status))
                        ret = STATUS_UNSUCCESSFUL;
                break;
                
      default:
            ELOG(printk(MODSTR"unknown completion type: %d\n", st->ctype));
            ret = STATUS_UNSUCCESSFUL;
      }
      irp->IoStatus.Status = ret;
      kfree(urb);
      kfree(st);
      dabusb_decrement_io_count(fdo);
        return (ret == STATUS_SUCCESS) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
};

static NTSTATUS async_usbd(PDEVICE_OBJECT fdo, PIRP irp, PURB urb, unsigned int tmo, unsigned int ctype, unsigned int cookie)
{
      pdabusb_t s = fdo->DeviceExtension;
        struct completionstate *st = NULL;
      NTSTATUS ret;
      PIO_STACK_LOCATION ns;
        LARGE_INTEGER timeout;
      KIRQL irql;

        if(s->device_state == _removed || s->CurrentDevicePowerState == PowerDeviceD3) {
                ret = STATUS_DELETE_PENDING;
                goto out;
        }
        if (!urb) {
                ret = STATUS_INVALID_PARAMETER;
                goto out;
        }
        if (!(st = kmalloc(sizeof(struct completionstate)))) {
            ret = STATUS_INSUFFICIENT_RESOURCES;
            goto out;
      }
      dabusb_increment_io_count(fdo);
        /* set up callusbd state structure */
        st->fdo = fdo;
        st->urb = urb;
      st->irp = irp;
        st->ctype = ctype;
        KeInitializeDpc(&st->timeout_dpc, async_timeout, st);
        KeInitializeTimerEx(&st->timeout_timer, NotificationTimer);
      INIT_LIST_HEAD(&st->cancel_list);
      st->cookie = cookie;
      /* setup next IRP location */
      ns = IoGetNextIrpStackLocation(irp);
      ASSERT(ns != NULL);
        ns->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
        ns->Parameters.Others.Argument1 = urb;
        ns->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
        IoSetCompletionRoutine(irp, async_complete, st, TRUE, TRUE, TRUE);
      /* set timer if requested */
        if (tmo) {
                timeout.QuadPart = -10000 * (LONGLONG)tmo;
            VLOG(printk(MODSTR"async_usbd: timeout %ums setting timeout %d\n", tmo, timeout.QuadPart));
                KeSetTimer(&st->timeout_timer, timeout, &st->timeout_dpc);
        }
      /* put into cookie list */
      KeAcquireSpinLock(&s->cancel_list_lock, &irql);
      list_add_tail(&st->cancel_list, &s->cancel_list);
      KeReleaseSpinLock(&s->cancel_list_lock, irql);
      ret = IoCallDriver(s->sdo, irp);
      if (ret == STATUS_PENDING)
            return ret;
      if (NT_SUCCESS(ret))
            VLOG(printk(MODSTR"async_usbd: IoCallDriver successfully returned 0x%08x\n", ret));
      else
            ELOG(printk(MODSTR"async_usbd: IoCallDriver error 0x%08x\n", ret));
      KeCancelTimer(&st->timeout_timer);
      KeAcquireSpinLock(&s->cancel_list_lock, &irql);
      list_del(&st->cancel_list);
      INIT_LIST_HEAD(&st->cancel_list);
      KeReleaseSpinLock(&s->cancel_list_lock, irql);
      kfree(urb);
      kfree(st);
      irp->IoStatus.Status = ret;
      irp->IoStatus.Information = 0;
      IoCompleteRequest(irp, IO_NO_INCREMENT); 
      dabusb_decrement_io_count(fdo);
      return ret;

  out:
        if (urb)
                kfree(urb);
      if (st)
            kfree(st);
      irp->IoStatus.Status = ret;
      irp->IoStatus.Information = 0;
      IoCompleteRequest(irp, IO_NO_INCREMENT);
      return ret;
}

static NTSTATUS async_cancel(PDEVICE_OBJECT fdo, unsigned int cookie)
{
      pdabusb_t s = fdo->DeviceExtension;
        struct completionstate *st;
      struct list_head *list;
      KIRQL irql;
      PIRP irp;
      unsigned int killed = 0, killerr = 0;

      if (!cookie) {
              VLOG(printk(MODSTR"async_cancel: invalid cookie %u\n", cookie));
            return STATUS_INVALID_PARAMETER;
      }
      for (;;) {
              irp = NULL;
            KeAcquireSpinLock(&s->cancel_list_lock, &irql);
            for (list = s->cancel_list.next; list != &s->cancel_list;) {
                  st = list_entry(list, struct completionstate, cancel_list);
                  list = list->next;
                  if (st->cookie == cookie) {
                        irp = st->irp;
                        list_del(&st->cancel_list);
                        INIT_LIST_HEAD(&st->cancel_list);
                        break;
                  }
            }
            KeReleaseSpinLock(&s->cancel_list_lock, irql);
            if (!irp)
                  break;
            /* race with normal/timeout completion?? */
            if (IoCancelIrp(irp))
                  killed++;
            else
                  killerr++;
            VLOG(printk(MODSTR"async_cancel: found killable irp: %p killed: %u killerr: %u\n",
                      irp, killed, killerr));
      }
      if (killerr) {
              VLOG(printk(MODSTR"async_cancel: unsuccessful\n"));
            return STATUS_UNSUCCESSFUL;
      }
      else if (killed) {
              VLOG(printk(MODSTR"async_cancel: success\n"));
            return STATUS_SUCCESS;
      }
      VLOG(printk(MODSTR"async_cancel: no killable irps with cookie %u found\n", cookie));
      return STATUS_INVALID_PARAMETER_1;
}

NTSTATUS async_cancel_all(PDEVICE_OBJECT fdo)
{
      pdabusb_t s = fdo->DeviceExtension;
        struct completionstate *st;
      struct list_head *list;
      KIRQL irql;
      PIRP irp;
      NTSTATUS ret = STATUS_SUCCESS;

      VLOG(printk(MODSTR"async_cancel_all: entering\n"));
      for (;;) {
            irp = NULL;
            KeAcquireSpinLock(&s->cancel_list_lock, &irql);
            list = s->cancel_list.next;
            if (list != &s->cancel_list) {
                  st = list_entry(list, struct completionstate, cancel_list);
                  list_del(&st->cancel_list);
                  INIT_LIST_HEAD(&st->cancel_list);
                  irp = st->irp;
            }
            KeReleaseSpinLock(&s->cancel_list_lock, irql);
            if (!irp)
                  break;
            VLOG(printk(MODSTR"async_cancel_all: cancelling IRP 0x%08x\n", (unsigned long)irp));
            if (!IoCancelIrp(irp)) {
                  ret = STATUS_UNSUCCESSFUL;
                  ELOG(printk(MODSTR"async_cancel_all: IoCancelIrp failed\n"));
            }
      }
      VLOG(printk(MODSTR"async_cancel_all: leaving 0x%08x\n", ret));
      return ret;
}

/*
 * Synchronous calls
 */

int usb_control_msg(PDEVICE_OBJECT fdo, unsigned char requesttype, unsigned char request,
                    unsigned short value, unsigned short index, unsigned short length, void *data, unsigned int timeout)
{
      pdabusb_t s = fdo->DeviceExtension;
        PURB urb;
        NTSTATUS ret;

      ret = make_control_urb(&urb, fdo, 0, requesttype, request, value, index, length, data, NULL);
      if (!NT_SUCCESS(ret))
            return ret;
        //ret = call_usbd(fdo, urb);
        ret = call_usbd_timeout(fdo, urb, timeout);
        if (NT_SUCCESS(ret)) {
                if (USBD_SUCCESS(urb->UrbHeader.Status))
                        ret = urb->UrbControlVendorClassRequest.TransferBufferLength;
                else
                        ret = STATUS_UNSUCCESSFUL;
        }
        kfree(urb);
        return ret;
}

int usb_bulk_msg(PDEVICE_OBJECT fdo, unsigned int ep, unsigned int dlen, void *data, unsigned int timeout)
{
      pdabusb_t s = fdo->DeviceExtension;
        PURB urb;
        NTSTATUS ret;
        
      ret = make_bulk_urb(&urb, fdo, 0, ep, dlen, data, NULL);
      if (!NT_SUCCESS(ret))
            return ret;
        //ret = call_usbd(fdo, urb);
        ret = call_usbd_timeout(fdo, urb, timeout);
        if (NT_SUCCESS(ret)) {
                if (USBD_SUCCESS(urb->UrbHeader.Status))
                        ret = urb->UrbControlVendorClassRequest.TransferBufferLength;
                else
                        ret = STATUS_UNSUCCESSFUL;
        }
        kfree(urb);
        return ret;
}

NTSTATUS abort_pipes(PDEVICE_OBJECT fdo)
{
      pdabusb_t s = fdo->DeviceExtension;
        PURB urb;
      unsigned int i;
      NTSTATUS ret;

      VLOG(printk(MODSTR"abort_pipes: enter\n"));
      if (!(urb = kmalloc(sizeof(struct _URB_PIPE_REQUEST)))) {
            ELOG(printk(MODSTR"abort_pipes: out of memory\n"));
                return STATUS_NO_MEMORY;
      }
      for (i = 0; i < 32; i++) {
            if (!s->eptopipeh[i])
                  continue;
            VLOG(printk(MODSTR"abort_pipes: aborting pipe %u\n", i));
            RtlZeroMemory(urb, sizeof(struct _URB_PIPE_REQUEST));
            urb->UrbHeader.Length = sizeof(struct _URB_PIPE_REQUEST);
            urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
            urb->UrbPipeRequest.PipeHandle = s->eptopipeh[i];
            ret = call_usbd_timeout(fdo, urb, 100);
            if (!NT_SUCCESS(ret) || !USBD_SUCCESS(urb->UrbHeader.Status))
                  ELOG(printk(MODSTR"abort_pipes: pipe %u abort error 0x%08x, 0x%08x\n", 
                            ret, urb->UrbHeader.Status));
            RtlZeroMemory(urb, sizeof(struct _URB_PIPE_REQUEST));
            urb->UrbHeader.Length = sizeof(struct _URB_PIPE_REQUEST);
            urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
            urb->UrbPipeRequest.PipeHandle = s->eptopipeh[i];
            ret = call_usbd_timeout(fdo, urb, 100);
            if (!NT_SUCCESS(ret) || !USBD_SUCCESS(urb->UrbHeader.Status))
                  ELOG(printk(MODSTR"abort_pipes: pipe %u reset error 0x%08x, 0x%08x\n", 
                            ret, urb->UrbHeader.Status));
      }
      kfree(urb);
      VLOG(printk(MODSTR"abort_pipes: exit\n"));
      return STATUS_SUCCESS;
}

int usb_resetep(PDEVICE_OBJECT fdo, unsigned int ep)
{
      pdabusb_t s = fdo->DeviceExtension;
        PURB urb;
        NTSTATUS ret;
        
        ret = make_resetep_urb(&urb, fdo, URB_FUNCTION_RESET_PIPE, ep);
      if (!NT_SUCCESS(ret))
            return ret;
        //ret = call_usbd(fdo, urb);
        ret = call_usbd_timeout(fdo, urb, 100);
        if (NT_SUCCESS(ret)) {
                if (USBD_SUCCESS(urb->UrbHeader.Status))
                        ret = urb->UrbControlVendorClassRequest.TransferBufferLength;
                else
                        ret = STATUS_UNSUCCESSFUL;
        }
        kfree(urb);
        return ret;
}

static PUSB_CONFIGURATION_DESCRIPTOR getcfgdesc(PDEVICE_OBJECT fdo, unsigned int index)
{
      pdabusb_t s = fdo->DeviceExtension;
        PUSB_CONFIGURATION_DESCRIPTOR cfgdesc;
        PURB urb;
        NTSTATUS ret;
        unsigned int sz;

        if (!(urb = kmalloc(sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST))))
                return NULL;
        sz = sizeof(USB_CONFIGURATION_DESCRIPTOR) + 16;
        if (!(cfgdesc = kmalloc(sz))) {
                kfree(urb);
                return NULL;
        }
        UsbBuildGetDescriptorRequest(urb, sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
                                     USB_CONFIGURATION_DESCRIPTOR_TYPE, index, 0,
                                     cfgdesc, NULL,
                                     sizeof(USB_CONFIGURATION_DESCRIPTOR), /* Get only the configuration descriptor */
                                     NULL);
        //ret = call_usbd(fdo, urb);
        ret = call_usbd_timeout(fdo, urb, 100);
        if (!NT_SUCCESS(ret)) {
                kfree(cfgdesc);
                kfree(urb);
                return NULL;
        }
        sz = cfgdesc->wTotalLength + 16;
        kfree(cfgdesc);
        if (!(cfgdesc = kmalloc(sz))) {
                kfree(urb);
                return NULL;
        }
        UsbBuildGetDescriptorRequest(urb, sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
                                     USB_CONFIGURATION_DESCRIPTOR_TYPE, index, 0,
                                     cfgdesc, NULL, sz, NULL);
        //ret = call_usbd(fdo, urb);
        ret = call_usbd_timeout(fdo, urb, 100);
        if (!NT_SUCCESS(ret)) {
                kfree(cfgdesc);
                kfree(urb);
                return NULL;
        }
        kfree(urb);
        return cfgdesc;
}


int usb_setconfiguration(PDEVICE_OBJECT fdo, unsigned int configuration)
{
      pdabusb_t s = fdo->DeviceExtension;
        PUSB_CONFIGURATION_DESCRIPTOR cfgdesc;
        USBD_INTERFACE_LIST_ENTRY iflist;
        PURB urb;
        NTSTATUS ret;
        int ret2;
        unsigned int index;

      for (index = 0; index < 256; index++) {
            cfgdesc = getcfgdesc(fdo, index);
            if (!cfgdesc)
                  break;
            if (cfgdesc->bConfigurationValue == configuration)
                  break;
            kfree(cfgdesc);
            cfgdesc = NULL;
      }
      if (!cfgdesc) {
            ELOG(printk(MODSTR"failure to get configuration descriptor\n"));
            return STATUS_INVALID_PARAMETER;
      }
      abort_pipes(fdo);
        memset(&s->eptopipeh, 0, sizeof(s->eptopipeh));
        memset(&s->epmaxpkt, 0, sizeof(s->epmaxpkt));
        kfree(cfgdesc);
        return STATUS_SUCCESS;
}

int usb_setinterface(PDEVICE_OBJECT fdo, unsigned int intf, unsigned int altsetting)
{
      pdabusb_t s = fdo->DeviceExtension;
        PURB urb;
        PUSB_CONFIGURATION_DESCRIPTOR cfgdesc;
        PUSBD_INTERFACE_INFORMATION ifobj;
        USBD_INTERFACE_LIST_ENTRY iflist[2];
        NTSTATUS ret;
        unsigned int i, j, ep;

      abort_pipes(fdo);
        memset(&s->eptopipeh, 0, sizeof(s->eptopipeh));
        memset(&s->epmaxpkt, 0, sizeof(s->epmaxpkt));
        cfgdesc = getcfgdesc(fdo, s->cfgindex);
        if (!cfgdesc) {
                ELOG(printk(MODSTR"failure to get configuration descriptor\n"));
                return STATUS_INVALID_PARAMETER;
        }
        iflist[0].InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(cfgdesc, cfgdesc, intf, altsetting, -1, -1, -1);
        if (!iflist[0].InterfaceDescriptor) {
                ELOG(printk(MODSTR"invalid interface %u altsetting %u\n", intf, altsetting));
                kfree(cfgdesc);
                return STATUS_INVALID_PARAMETER;
        }
        iflist[1].InterfaceDescriptor = NULL;
        iflist[1].Interface = NULL;
        urb = USBD_CreateConfigurationRequestEx(cfgdesc, &iflist[0]);
        if (!urb) {
                ELOG(printk(MODSTR "USBD_CreateConfigurationRequestEx failed\n"));
                kfree(cfgdesc);
                return STATUS_INVALID_PARAMETER;
        }
        //ret = call_usbd(fdo, urb);
        ret = call_usbd_timeout(fdo, urb, 100);
        if (!NT_SUCCESS(ret) || !USBD_SUCCESS(urb->UrbHeader.Status)) {
                kfree(cfgdesc);
                kfree(urb);
                ELOG(printk(MODSTR"Error in configuration request: ntstatus %d urb status %d\n", ret, urb->UrbHeader.Status));
                return NT_SUCCESS(ret) ? STATUS_UNSUCCESSFUL : ret;
        }
        ifobj = (PUSBD_INTERFACE_INFORMATION)(&(urb->UrbSelectConfiguration.Interface));
        /* save in our EP->pipehandle translation table */
        for (i = 0; i < ifobj->NumberOfPipes; i++) {
                ep = ifobj->Pipes[i].EndpointAddress & 15;
                if (ifobj->Pipes[i].EndpointAddress & 0x80)
                        ep |= 16;
                else
                        s->epmaxpkt[ep] = ifobj->Pipes[i].MaximumPacketSize;
                s->eptopipeh[ep] = ifobj->Pipes[i].PipeHandle;
        }
        kfree(cfgdesc);
        kfree(urb);
        return STATUS_SUCCESS;
}

int usb_claiminterface(PDEVICE_OBJECT fdo, unsigned int intf)
{
        return STATUS_SUCCESS;
}

int usb_releaseinterface(PDEVICE_OBJECT fdo, unsigned int intf)
{
        return STATUS_SUCCESS;
}

NTSTATUS baycomusb_internal_ioctl(IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
      pdabusb_t s = fdo->DeviceExtension;
        NTSTATUS ret = STATUS_INVALID_PARAMETER;
        PIO_STACK_LOCATION irpSp;
        struct internal_ctrlbulk *cb;
        
        irpSp = IoGetCurrentIrpStackLocation(irp);
        VLOG(printk(MODSTR"ioctlinternal>>>> code 0x%08x\n", irpSp->Parameters.DeviceIoControl.IoControlCode));
        switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
        case USBDEVFS_INTERNAL_CONTROL:
                cb = irpSp->Parameters.Others.Argument1;
                ret = async_usbd(fdo, irp, cb->urb, cb->timeout, COMPL_INTERNALCTRL, 0);
                break;
                
        case USBDEVFS_INTERNAL_BULK:
                cb = irpSp->Parameters.Others.Argument1;
                ret = async_usbd(fdo, irp, cb->urb, cb->timeout, COMPL_INTERNALBULK, 0);
                break;
                
        default:
                return baycomusb_ioctl(fdo, irp);
        }
        VLOG(printk(MODSTR"ioctlinternal<<<< async: status 0x%08x retstatus 0x%08x info %d  usberr 0x%08x\n", irp->IoStatus.Status, ret, irp->IoStatus.Information, s->lastusberror));
        return ret;        
}

NTSTATUS baycomusb_ioctl(IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
      pdabusb_t s = fdo->DeviceExtension;
        NTSTATUS ret = STATUS_INVALID_PARAMETER;
        PIO_STACK_LOCATION irpSp;
        struct usbdevfs_ctrltransfer *ctrl;
        struct usbdevfs_bulktransfer *bulk;
      struct usbdevfs_isotransfer *iso;
        struct usbdevfs_setinterface *setif;
        struct usbdevfs_setconfig *setcfg;
        struct usbdevfs_resetep *rstep;
      PURB urb = NULL;
        PULONG ulptr;
      unsigned int i, j, k;

        irpSp = IoGetCurrentIrpStackLocation(irp);
        VLOG(printk(MODSTR"ioctl>>>> code 0x%08x\n", irpSp->Parameters.DeviceIoControl.IoControlCode));
        switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
        case USBDEVFS_CONTROL:
                ctrl = (struct usbdevfs_ctrltransfer *)irp->AssociatedIrp.SystemBuffer;
                if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct usbdevfs_ctrltransfer) ||
                    irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(struct usbdevfs_ctrltransfer) ||
                    ((ctrl->requesttype & 0x80) && irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(struct usbdevfs_ctrltransfer) + ctrl->len) ||
                    (!(ctrl->requesttype & 0x80) && irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct usbdevfs_ctrltransfer) + ctrl->len))
                        goto outseterr;
                VLOG(printk(MODSTR"     >>>> rq 0x%02x rqt 0x%02x val 0x%04x idx 0x%04x len %u tmo %u flg 0x%x\n",
                            ctrl->request, ctrl->requesttype, ctrl->value, ctrl->index, ctrl->len, ctrl->timeout, ctrl->flags));
            /* async version */
            ret = make_control_urb(&urb, fdo, ctrl->flags, ctrl->requesttype, ctrl->request, ctrl->value, ctrl->index, (unsigned short)ctrl->len, (void *)(ctrl + 1), NULL);
            if (!NT_SUCCESS(ret))
                  goto outseterr;
            ret = async_usbd(fdo, irp, urb, ctrl->timeout, COMPL_CONTROL, ctrl->cookie);
            goto outasyncok;

        case USBDEVFS_BULK:
                bulk = (struct usbdevfs_bulktransfer *)irp->AssociatedIrp.SystemBuffer;
                if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct usbdevfs_bulktransfer) ||
                    irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(struct usbdevfs_bulktransfer) ||
                    ((bulk->ep & 0x80) && irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(struct usbdevfs_bulktransfer) + bulk->len) ||
                    (!(bulk->ep & 0x80) && irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct usbdevfs_bulktransfer) + bulk->len))
                        goto outseterr;
                VLOG(printk(MODSTR"     >>>> ep 0x%02x len %u tmo %u flg 0x%x\n",
                      bulk->ep, bulk->len, bulk->timeout, bulk->flags));
            /* async version */
            ret = make_bulk_urb(&urb, fdo, bulk->flags, bulk->ep, bulk->len, (void *)(bulk + 1), NULL);
            if (!NT_SUCCESS(ret))
                  goto outseterr;
            ret = async_usbd(fdo, irp, urb, bulk->timeout, COMPL_BULK, bulk->cookie);
            goto outasyncok;

        case USBDEVFS_ISO:
                iso = (struct usbdevfs_isotransfer *)irp->AssociatedIrp.SystemBuffer;
                if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct usbdevfs_isotransfer) ||
                    irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(struct usbdevfs_isotransfer))
                  goto outseterr;
            i = sizeof(struct usbdevfs_isotransfer) + iso->number_of_packets * sizeof(struct usbdevfs_isopacketdesc);
                if (irpSp->Parameters.DeviceIoControl.InputBufferLength < i ||
                    irpSp->Parameters.DeviceIoControl.OutputBufferLength < i)
                  goto outseterr;
            if (iso->len > irpSp->Parameters.DeviceIoControl.InputBufferLength ||
                iso->len > irpSp->Parameters.DeviceIoControl.OutputBufferLength)
                  goto outseterr;
            for (i = j = 0; j < iso->number_of_packets; j++) {
                  k = iso->iso_frame_desc[j].offset + iso->iso_frame_desc[j].length;
                  if (k < iso->iso_frame_desc[j].offset)
                        goto outseterr;
                  if (i < k)
                        i = k;
            }
            if (i > iso->len)
                  goto outseterr;
                VLOG(printk(MODSTR"     >>>> ep 0x%02x len %u flg 0x%x\n", iso->ep, i, iso->flags));
            /* async version */
            ret = make_iso_urb(&urb, fdo, iso, iso, NULL);
            if (!NT_SUCCESS(ret))
                  goto outseterr;
            ret = async_usbd(fdo, irp, urb, iso->timeout, COMPL_ISO, iso->cookie);
            goto outasyncok;

        case USBDEVFS_RESETEP:
                rstep = (struct usbdevfs_resetep *)irp->AssociatedIrp.SystemBuffer;
                if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct usbdevfs_resetep) ||
                    irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(unsigned int))
                        goto outseterr;
                VLOG(printk(MODSTR"     >>>> ep 0x%02x\n", rstep->ep));
            /* async version */
            ret = make_resetep_urb(&urb, fdo, URB_FUNCTION_RESET_PIPE, rstep->ep);
            if (!NT_SUCCESS(ret))
                  goto outseterr;
            ret = async_usbd(fdo, irp, urb, 1000, COMPL_ERRRETURN, 0);
            goto outasyncok;

        case USBDEVFS_ABORTEP:
                rstep = (struct usbdevfs_resetep *)irp->AssociatedIrp.SystemBuffer;
                if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct usbdevfs_resetep) ||
                    irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(unsigned int))
                        goto outseterr;
                VLOG(printk(MODSTR"     >>>> ep 0x%02x\n", rstep->ep));
            /* async version */
            ret = make_resetep_urb(&urb, fdo, URB_FUNCTION_ABORT_PIPE, rstep->ep);
            if (!NT_SUCCESS(ret))
                  goto outseterr;
            ret = async_usbd(fdo, irp, urb, 1000, COMPL_ERRRETURN, 0);
            goto outasyncok;

        case USBDEVFS_SETINTERFACE:
                setif = (struct usbdevfs_setinterface *)irp->AssociatedIrp.SystemBuffer;
                if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct usbdevfs_setinterface)) {
                        ret = STATUS_INVALID_PARAMETER;
                        break;
                }
                VLOG(printk(MODSTR"     >>>> interface %u altsetting %u\n", setif->interf, setif->altsetting));
                ret = usb_setinterface(fdo, setif->interf, setif->altsetting);
                if (!NT_SUCCESS(ret))
                  goto outseterr;
            irp->IoStatus.Status = STATUS_SUCCESS;
            irp->IoStatus.Information = ret;
            goto outcompl;

        case USBDEVFS_SETCONFIGURATION:
                setcfg = (struct usbdevfs_setconfig *)irp->AssociatedIrp.SystemBuffer;
                if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct usbdevfs_setconfig)) {
                        ret = STATUS_INVALID_PARAMETER;
                        break;
                }
                ret = usb_setconfiguration(fdo, setcfg->config);
                if (!NT_SUCCESS(ret))
                  goto outseterr;
            irp->IoStatus.Status = STATUS_SUCCESS;
            irp->IoStatus.Information = ret;
            goto outcompl;
                
        case USBDEVFS_CLAIMINTERFACE:
                irp->IoStatus.Status = STATUS_SUCCESS;
                irp->IoStatus.Information = 0;
                goto outcompl;

        case USBDEVFS_RELEASEINTERFACE:
                irp->IoStatus.Status = STATUS_SUCCESS;
                irp->IoStatus.Information = 0;
                goto outcompl;

        case USBDEVFS_GETLASTERROR:
                ulptr = (PULONG)irp->AssociatedIrp.SystemBuffer;
                if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*ulptr)) {
                        irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
                        irp->IoStatus.Information = 0;
                        goto outcompl;
                }
                *ulptr = s->lastusberror;
                irp->IoStatus.Status = STATUS_SUCCESS;
                irp->IoStatus.Information = sizeof(*ulptr);
                goto outcompl;

      case USBDEVFS_CANCELTRANSFER:
                ulptr = (PULONG)irp->AssociatedIrp.SystemBuffer;
                if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*ulptr)) {
                        irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
                        irp->IoStatus.Information = 0;
                        goto outcompl;
                }
                irp->IoStatus.Status = async_cancel(fdo, *ulptr);
                irp->IoStatus.Information = 0;
                goto outcompl;

        default:
                ret = STATUS_NOT_IMPLEMENTED;
            goto outseterr;
        }
        goto outseterr;

  outseterr:
      irp->IoStatus.Status = ret;
      irp->IoStatus.Information = 0;
  outcompl:
      IoCompleteRequest(irp, IO_NO_INCREMENT);
      VLOG(printk(MODSTR"ioctl<<<< status 0x%08x info %d  usberr 0x%08x\n", irp->IoStatus.Status, irp->IoStatus.Information, s->lastusberror));
      return irp->IoStatus.Status;

  outasyncok:
      VLOG(printk(MODSTR"ioctl<<<< async: status 0x%08x retstatus 0x%08x info %d  usberr 0x%08x\n", irp->IoStatus.Status, ret, irp->IoStatus.Information, s->lastusberror));
      return ret;
}

Generated by  Doxygen 1.6.0   Back to index