win-pvdrivers

changeset 980:ea3c61839ff5

fix usb-detach hang
author James Harper <james.harper@bendigoit.com.au>
date Sun Apr 15 23:41:21 2012 +1000 (2012-04-15)
parents 8f483a2b2991
children b96f14f62b50
files xenusb/xenusb.h xenusb/xenusb_fdo.c xenusb/xenusb_hub.c xenusb/xenusb_huburb.c
line diff
     1.1 --- a/xenusb/xenusb.h	Sun Apr 15 19:47:10 2012 +1000
     1.2 +++ b/xenusb/xenusb.h	Sun Apr 15 23:41:21 2012 +1000
     1.3 @@ -108,8 +108,8 @@ typedef struct _pvurb pvurb_t;
     1.4  typedef struct _partial_pvurb partial_pvurb_t;
     1.5  
     1.6  /* needs to be at least USB_URB_RING_SIZE number of requests available */
     1.7 -#define MAX_ID_COUNT 64
     1.8 -#define ID_COUNT min(MAX_ID_COUNT, USB_URB_RING_SIZE)
     1.9 +#define MAX_REQ_ID_COUNT 64
    1.10 +#define REQ_ID_COUNT min(MAX_REQ_ID_COUNT, USB_URB_RING_SIZE)
    1.11  
    1.12  /*
    1.13  for IOCTL_PVUSB_SUBMIT_URB, the pvusb_urb_t struct is passed as Parameters.Others.Arg1
    1.14 @@ -216,8 +216,8 @@ typedef struct {
    1.15    
    1.16    WDFDEVICE root_hub_device;
    1.17  
    1.18 -  struct stack_state *id_ss;
    1.19 -  partial_pvurb_t *partial_pvurbs[MAX_ID_COUNT];
    1.20 +  struct stack_state *req_id_ss;
    1.21 +  partial_pvurb_t *partial_pvurbs[MAX_REQ_ID_COUNT];
    1.22  
    1.23    PUCHAR config_page;
    1.24  
    1.25 @@ -245,6 +245,8 @@ typedef struct {
    1.26  
    1.27  WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(XENUSB_DEVICE_DATA, GetXudd)
    1.28  
    1.29 +#define DEV_ID_COUNT 64
    1.30 +
    1.31  typedef struct {  
    1.32    WDFDEVICE wdf_device;
    1.33    WDFDEVICE wdf_device_bus_fdo;
    1.34 @@ -252,8 +254,7 @@ typedef struct {
    1.35    WDFQUEUE io_queue;
    1.36    WDFQUEUE urb_queue;
    1.37    ULONG device_number;
    1.38 -  //ULONG port_number;
    1.39 -  //ULONG port_type;
    1.40 +  struct stack_state *dev_id_ss;
    1.41    xenusb_device_t *usb_device;
    1.42    PVOID BusCallbackContext;
    1.43    PRH_INIT_CALLBACK BusCallbackFunction;
    1.44 @@ -281,20 +282,19 @@ typedef struct {
    1.45  
    1.46  
    1.47  static uint16_t
    1.48 -get_id_from_freelist(PXENUSB_DEVICE_DATA xudd) {
    1.49 +get_id_from_freelist(struct stack_state *ss) {
    1.50    ULONG_PTR _id;
    1.51 -  if (!stack_pop(xudd->id_ss, (VOID *)&_id)) {
    1.52 +  if (!stack_pop(ss, (VOID *)&_id)) {
    1.53      KdPrint((__DRIVER_NAME "     No more id's\n"));
    1.54      return (uint16_t)-1;
    1.55    }
    1.56    return (uint16_t)_id;
    1.57  }
    1.58  
    1.59 -/* call with ring lock held */
    1.60  static VOID
    1.61 -put_id_on_freelist(PXENUSB_DEVICE_DATA xudd, uint16_t id) {
    1.62 +put_id_on_freelist(struct stack_state *ss, uint16_t id) {
    1.63    ULONG_PTR _id = id;
    1.64 -  stack_push(xudd->id_ss, (VOID *)_id);
    1.65 +  stack_push(ss, (VOID *)_id);
    1.66  }
    1.67  
    1.68  static
    1.69 @@ -309,21 +309,6 @@ ULONGLONG parse_numeric_string(PCHAR str
    1.70    return val;
    1.71  }
    1.72  
    1.73 -#if 0
    1.74 -static VOID
    1.75 -XenUsb_PutRequest(PXENVBD_DEVICE_DATA xudd, usbif_request_t *req)
    1.76 -{
    1.77 -  *RING_GET_REQUEST(&xudd->ring, xudd->ring.req_prod_pvt) = *req;
    1.78 -  xudd->ring.req_prod_pvt++;
    1.79 -}
    1.80 -
    1.81 -static usbif_request_t *
    1.82 -XenUsb_GetResponse(PXENVBD_DEVICE_DATA xudd, ULONG i)
    1.83 -{
    1.84 -  return RING_GET_RESPONSE(&xvdd->ring, i);
    1.85 -}
    1.86 -#endif
    1.87 -
    1.88  EVT_WDF_DRIVER_DEVICE_ADD XenUsb_EvtDriverDeviceAdd;
    1.89  
    1.90  EVT_WDF_CHILD_LIST_CREATE_DEVICE XenUsb_EvtChildListCreateDevice;
     2.1 --- a/xenusb/xenusb_fdo.c	Sun Apr 15 19:47:10 2012 +1000
     2.2 +++ b/xenusb/xenusb_fdo.c	Sun Apr 15 23:41:21 2012 +1000
     2.3 @@ -105,7 +105,7 @@ PutRequestsOnRing(PXENUSB_DEVICE_DATA xu
     2.4    while ((partial_pvurb = (partial_pvurb_t *)RemoveHeadList((PLIST_ENTRY)&xudd->partial_pvurb_queue)) != (partial_pvurb_t *)&xudd->partial_pvurb_queue) {
     2.5      FUNCTION_MSG("partial_pvurb = %p\n", partial_pvurb);
     2.6      /* if this partial_pvurb is cancelling another we don't need to check if the cancelled partial_pvurb is on the ring - that is taken care of in HandleEvent */
     2.7 -    id = get_id_from_freelist(xudd);
     2.8 +    id = get_id_from_freelist(xudd->req_id_ss);
     2.9      if (id == (uint16_t)-1) {
    2.10        FUNCTION_MSG("no free ring slots\n");
    2.11        InsertHeadList(&xudd->partial_pvurb_queue, &partial_pvurb->entry);
    2.12 @@ -199,7 +199,7 @@ XenUsb_HandleEvent(PVOID context)
    2.13        default:
    2.14          break;
    2.15        }
    2.16 -      put_id_on_freelist(xudd, partial_pvurb->rsp.id);
    2.17 +      put_id_on_freelist(xudd->req_id_ss, partial_pvurb->rsp.id);
    2.18        partial_pvurb->pvurb->next = NULL;
    2.19        if (!partial_pvurb->pvurb->ref) {
    2.20          if (complete_tail) {
    2.21 @@ -242,16 +242,18 @@ XenUsb_HandleEvent(PVOID context)
    2.22      KeMemoryBarrier();
    2.23      for (cons = xudd->conn_ring.rsp_cons; cons != prod; cons++)
    2.24      {
    2.25 +      USHORT old_port_status;
    2.26        conn_rsp = RING_GET_RESPONSE(&xudd->conn_ring, cons);
    2.27        KdPrint((__DRIVER_NAME "     conn_rsp->portnum = %d\n", conn_rsp->portnum));
    2.28        KdPrint((__DRIVER_NAME "     conn_rsp->speed = %d\n", conn_rsp->speed));
    2.29        
    2.30 +      old_port_status = xudd->ports[conn_rsp->portnum - 1].port_status;
    2.31        xudd->ports[conn_rsp->portnum - 1].port_type = conn_rsp->speed;
    2.32        xudd->ports[conn_rsp->portnum - 1].port_status &= ~((1 << PORT_LOW_SPEED) | (1 << PORT_HIGH_SPEED) | (1 << PORT_CONNECTION));
    2.33        switch (conn_rsp->speed)
    2.34        {
    2.35        case USB_PORT_TYPE_NOT_CONNECTED:
    2.36 -        //xudd->ports[conn_rsp->portnum - 1].port_status |= 0;
    2.37 +        xudd->ports[conn_rsp->portnum - 1].port_status &= ~(1 << PORT_ENABLE);
    2.38          break;
    2.39        case USB_PORT_TYPE_LOW_SPEED:
    2.40          xudd->ports[conn_rsp->portnum - 1].port_status |= (1 << PORT_LOW_SPEED) | (1 << PORT_CONNECTION);
    2.41 @@ -263,8 +265,9 @@ XenUsb_HandleEvent(PVOID context)
    2.42          xudd->ports[conn_rsp->portnum - 1].port_status |= (1 << PORT_HIGH_SPEED) | (1 << PORT_CONNECTION);
    2.43          break;
    2.44        }      
    2.45 -      xudd->ports[conn_rsp->portnum - 1].port_change |= (1 << PORT_CONNECTION);
    2.46 -      port_changed = TRUE;    
    2.47 +      xudd->ports[conn_rsp->portnum - 1].port_change |= (xudd->ports[conn_rsp->portnum - 1].port_status ^ old_port_status) & ((1 << PORT_ENABLE) | (1 << PORT_CONNECTION));
    2.48 +      if (xudd->ports[conn_rsp->portnum - 1].port_change)
    2.49 +        port_changed = TRUE;
    2.50        conn_req = RING_GET_REQUEST(&xudd->conn_ring, xudd->conn_ring.req_prod_pvt);
    2.51        conn_req->id = conn_rsp->id;
    2.52        xudd->conn_ring.req_prod_pvt++;
    2.53 @@ -386,9 +389,9 @@ XenUsb_CompleteXenbusInit(PXENUSB_DEVICE
    2.54      return STATUS_BAD_INITIAL_PC;
    2.55    }
    2.56    
    2.57 -  stack_new(&xudd->id_ss, ID_COUNT);
    2.58 -  for (i = 0; i < ID_COUNT; i++)  {
    2.59 -    put_id_on_freelist(xudd, (uint16_t)i);
    2.60 +  stack_new(&xudd->req_id_ss, REQ_ID_COUNT);
    2.61 +  for (i = 0; i < REQ_ID_COUNT; i++)  {
    2.62 +    put_id_on_freelist(xudd->req_id_ss, (uint16_t)i);
    2.63    }
    2.64    
    2.65    return STATUS_SUCCESS;
     3.1 --- a/xenusb/xenusb_hub.c	Sun Apr 15 19:47:10 2012 +1000
     3.2 +++ b/xenusb/xenusb_hub.c	Sun Apr 15 23:41:21 2012 +1000
     3.3 @@ -639,7 +639,7 @@ XenUsbHub_UBIH_InitializeUsbDevice(
     3.4    usb_device->pdo_device = BusContext;
     3.5    
     3.6    // TODO: get address from freelist and assign it to the device...
     3.7 -  usb_device->address = 2;
     3.8 +  usb_device->address = (UCHAR)get_id_from_freelist(xupdd->dev_id_ss);
     3.9    // TODO: get this stuff properly ...
    3.10    xupdd->usb_device->device_speed = UsbHighSpeed;
    3.11    xupdd->usb_device->device_type = Usb20Device;
    3.12 @@ -838,6 +838,7 @@ XenUsbHub_UBIH_InitializeUsbDevice(
    3.13        j++;
    3.14      }
    3.15    }
    3.16 +  ExFreePoolWithTag(buf, XENUSB_POOL_TAG);
    3.17  
    3.18    usb_device->active_config = usb_device->configs[0];
    3.19    usb_device->active_interface = usb_device->configs[0]->interfaces[0];
    3.20 @@ -918,9 +919,10 @@ XenUsbHub_UBIH_RemoveUsbDevice (
    3.21   ULONG Flags)
    3.22  {
    3.23    NTSTATUS status = STATUS_SUCCESS;
    3.24 -
    3.25 -  UNREFERENCED_PARAMETER(BusContext);
    3.26 -  UNREFERENCED_PARAMETER(DeviceHandle);
    3.27 +  WDFDEVICE device = BusContext;
    3.28 +  PXENUSB_PDO_DEVICE_DATA xupdd = GetXupdd(device);
    3.29 +  xenusb_device_t *usb_device = DeviceHandle;
    3.30 +  int i, j, k;
    3.31  
    3.32    FUNCTION_ENTER();
    3.33    
    3.34 @@ -930,6 +932,20 @@ XenUsbHub_UBIH_RemoveUsbDevice (
    3.35    if (Flags & USBD_MARK_DEVICE_BUSY)
    3.36      KdPrint((__DRIVER_NAME "     USBD_MARK_DEVICE_BUSY\n"));
    3.37  
    3.38 +  put_id_on_freelist(xupdd->dev_id_ss, (uint16_t)usb_device->address);
    3.39 +  // check if there are no pending requests
    3.40 +  for (i = 0; i < usb_device->device_descriptor.bNumConfigurations; i++) {
    3.41 +    for (j = 0; j < usb_device->configs[i]->config_descriptor.bNumInterfaces; j++) {
    3.42 +      for (k = 0; k < usb_device->configs[i]->interfaces[j]->interface_descriptor.bNumEndpoints; k++) {
    3.43 +        ExFreePoolWithTag(usb_device->configs[i]->interfaces[j]->endpoints[k], XENUSB_POOL_TAG);
    3.44 +      }
    3.45 +      ExFreePoolWithTag(usb_device->configs[i]->interfaces[j], XENUSB_POOL_TAG);
    3.46 +    }
    3.47 +    ExFreePoolWithTag(usb_device->configs[i]->config_descriptor_all, XENUSB_POOL_TAG);
    3.48 +    ExFreePoolWithTag(usb_device->configs[i], XENUSB_POOL_TAG);
    3.49 +  }
    3.50 +  ExFreePoolWithTag(usb_device->configs, XENUSB_POOL_TAG);
    3.51 +  ExFreePoolWithTag(usb_device, XENUSB_POOL_TAG);
    3.52    FUNCTION_EXIT();
    3.53    return status;
    3.54  }
    3.55 @@ -1999,6 +2015,7 @@ XenUsb_EvtChildListCreateDevice(WDFCHILD
    3.56    PNP_LOCATION_INTERFACE pli;
    3.57  #endif
    3.58    UCHAR pnp_minor_functions[] = { IRP_MN_QUERY_INTERFACE };
    3.59 +  int i;
    3.60  
    3.61    FUNCTION_ENTER();
    3.62  
    3.63 @@ -2057,6 +2074,12 @@ XenUsb_EvtChildListCreateDevice(WDFCHILD
    3.64  
    3.65    xudd->root_hub_device = child_device;
    3.66    
    3.67 +  stack_new(&xupdd->dev_id_ss, DEV_ID_COUNT);
    3.68 +  /* 0 is invalid and 1 is the root hub */
    3.69 +  for (i = 2; i < DEV_ID_COUNT; i++)  {
    3.70 +    put_id_on_freelist(xupdd->dev_id_ss, (uint16_t)i);
    3.71 +  }
    3.72 +  
    3.73    xupdd->wdf_device = child_device;
    3.74    xupdd->wdf_device_bus_fdo = WdfChildListGetDevice(child_list);
    3.75  
     4.1 --- a/xenusb/xenusb_huburb.c	Sun Apr 15 19:47:10 2012 +1000
     4.2 +++ b/xenusb/xenusb_huburb.c	Sun Apr 15 23:41:21 2012 +1000
     4.3 @@ -381,6 +381,11 @@ XenUsb_EvtIoInternalDeviceControl_ROOTHU
     4.4              xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change &= ~(1 << PORT_CONNECTION);
     4.5              urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
     4.6              break;
     4.7 +          case C_PORT_ENABLE:
     4.8 +            KdPrint((__DRIVER_NAME "        C_PORT_ENABLE\n"));
     4.9 +            xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change &= ~(1 << PORT_ENABLE);
    4.10 +            urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
    4.11 +            break;
    4.12            case C_PORT_RESET:
    4.13              KdPrint((__DRIVER_NAME "        C_PORT_RESET\n"));
    4.14              xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change &= ~(1 << PORT_RESET);