Diff for /qemu/usb-linux.c between versions 1.1.1.13 and 1.1.1.14

version 1.1.1.13, 2018/04/24 18:56:03 version 1.1.1.14, 2018/04/24 19:17:08
Line 34 Line 34
 #include "qemu-timer.h"  #include "qemu-timer.h"
 #include "monitor.h"  #include "monitor.h"
 #include "sysemu.h"  #include "sysemu.h"
   #include "trace.h"
   
 #include <dirent.h>  #include <dirent.h>
 #include <sys/ioctl.h>  #include <sys/ioctl.h>
Line 53  struct usb_ctrltransfer { Line 54  struct usb_ctrltransfer {
     void *data;      void *data;
 };  };
   
 typedef int USBScanFunc(void *opaque, int bus_num, int addr, char *port,  typedef int USBScanFunc(void *opaque, int bus_num, int addr, const char *port,
                         int class_id, int vendor_id, int product_id,                          int class_id, int vendor_id, int product_id,
                         const char *product_name, int speed);                          const char *product_name, int speed);
   
Line 114  struct USBAutoFilter { Line 115  struct USBAutoFilter {
 typedef struct USBHostDevice {  typedef struct USBHostDevice {
     USBDevice dev;      USBDevice dev;
     int       fd;      int       fd;
       int       hub_fd;
       int       hub_port;
   
     uint8_t   descr[8192];      uint8_t   descr[8192];
     int       descr_len;      int       descr_len;
Line 123  typedef struct USBHostDevice { Line 126  typedef struct USBHostDevice {
     uint32_t  iso_urb_count;      uint32_t  iso_urb_count;
     Notifier  exit;      Notifier  exit;
   
     struct endp_data endp_table[MAX_ENDPOINTS];      struct endp_data ep_in[MAX_ENDPOINTS];
       struct endp_data ep_out[MAX_ENDPOINTS];
     QLIST_HEAD(, AsyncURB) aurbs;      QLIST_HEAD(, AsyncURB) aurbs;
   
     /* Host side address */      /* Host side address */
Line 131  typedef struct USBHostDevice { Line 135  typedef struct USBHostDevice {
     int addr;      int addr;
     char port[MAX_PORTLEN];      char port[MAX_PORTLEN];
     struct USBAutoFilter match;      struct USBAutoFilter match;
       int seen, errcount;
   
     QTAILQ_ENTRY(USBHostDevice) next;      QTAILQ_ENTRY(USBHostDevice) next;
 } USBHostDevice;  } USBHostDevice;
Line 142  static int parse_filter(const char *spec Line 147  static int parse_filter(const char *spec
 static void usb_host_auto_check(void *unused);  static void usb_host_auto_check(void *unused);
 static int usb_host_read_file(char *line, size_t line_size,  static int usb_host_read_file(char *line, size_t line_size,
                             const char *device_file, const char *device_name);                              const char *device_file, const char *device_name);
   static int usb_linux_update_endp_table(USBHostDevice *s);
   
   static int usb_host_do_reset(USBHostDevice *dev)
   {
       struct timeval s, e;
       uint32_t usecs;
       int ret;
   
       gettimeofday(&s, NULL);
       ret = ioctl(dev->fd, USBDEVFS_RESET);
       gettimeofday(&e, NULL);
       usecs = (e.tv_sec  - s.tv_sec) * 1000000;
       usecs += e.tv_usec - s.tv_usec;
       if (usecs > 1000000) {
           /* more than a second, something is fishy, broken usb device? */
           fprintf(stderr, "husb: device %d:%d reset took %d.%06d seconds\n",
                   dev->bus_num, dev->addr, usecs / 1000000, usecs % 1000000);
       }
       return ret;
   }
   
 static struct endp_data *get_endp(USBHostDevice *s, int ep)  static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep)
 {  {
     return s->endp_table + ep - 1;      struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out;
       assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
       assert(ep > 0 && ep <= MAX_ENDPOINTS);
       return eps + ep - 1;
 }  }
   
 static int is_isoc(USBHostDevice *s, int ep)  static int is_isoc(USBHostDevice *s, int pid, int ep)
 {  {
     return get_endp(s, ep)->type == USBDEVFS_URB_TYPE_ISO;      return get_endp(s, pid, ep)->type == USBDEVFS_URB_TYPE_ISO;
 }  }
   
 static int is_valid(USBHostDevice *s, int ep)  static int is_valid(USBHostDevice *s, int pid, int ep)
 {  {
     return get_endp(s, ep)->type != INVALID_EP_TYPE;      return get_endp(s, pid, ep)->type != INVALID_EP_TYPE;
 }  }
   
 static int is_halted(USBHostDevice *s, int ep)  static int is_halted(USBHostDevice *s, int pid, int ep)
 {  {
     return get_endp(s, ep)->halted;      return get_endp(s, pid, ep)->halted;
 }  }
   
 static void clear_halt(USBHostDevice *s, int ep)  static void clear_halt(USBHostDevice *s, int pid, int ep)
 {  {
     get_endp(s, ep)->halted = 0;      trace_usb_host_ep_clear_halt(s->bus_num, s->addr, ep);
       get_endp(s, pid, ep)->halted = 0;
 }  }
   
 static void set_halt(USBHostDevice *s, int ep)  static void set_halt(USBHostDevice *s, int pid, int ep)
 {  {
     get_endp(s, ep)->halted = 1;      if (ep != 0) {
           trace_usb_host_ep_set_halt(s->bus_num, s->addr, ep);
           get_endp(s, pid, ep)->halted = 1;
       }
 }  }
   
 static int is_iso_started(USBHostDevice *s, int ep)  static int is_iso_started(USBHostDevice *s, int pid, int ep)
 {  {
     return get_endp(s, ep)->iso_started;      return get_endp(s, pid, ep)->iso_started;
 }  }
   
 static void clear_iso_started(USBHostDevice *s, int ep)  static void clear_iso_started(USBHostDevice *s, int pid, int ep)
 {  {
     get_endp(s, ep)->iso_started = 0;      trace_usb_host_ep_stop_iso(s->bus_num, s->addr, ep);
       get_endp(s, pid, ep)->iso_started = 0;
 }  }
   
 static void set_iso_started(USBHostDevice *s, int ep)  static void set_iso_started(USBHostDevice *s, int pid, int ep)
 {  {
     struct endp_data *e = get_endp(s, ep);      struct endp_data *e = get_endp(s, pid, ep);
   
       trace_usb_host_ep_start_iso(s->bus_num, s->addr, ep);
     if (!e->iso_started) {      if (!e->iso_started) {
         e->iso_started = 1;          e->iso_started = 1;
         e->inflight = 0;          e->inflight = 0;
     }      }
 }  }
   
 static int change_iso_inflight(USBHostDevice *s, int ep, int value)  static int change_iso_inflight(USBHostDevice *s, int pid, int ep, int value)
 {  {
     struct endp_data *e = get_endp(s, ep);      struct endp_data *e = get_endp(s, pid, ep);
   
     e->inflight += value;      e->inflight += value;
     return e->inflight;      return e->inflight;
 }  }
   
 static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb)  static void set_iso_urb(USBHostDevice *s, int pid, int ep, AsyncURB *iso_urb)
 {  {
     get_endp(s, ep)->iso_urb = iso_urb;      get_endp(s, pid, ep)->iso_urb = iso_urb;
 }  }
   
 static AsyncURB *get_iso_urb(USBHostDevice *s, int ep)  static AsyncURB *get_iso_urb(USBHostDevice *s, int pid, int ep)
 {  {
     return get_endp(s, ep)->iso_urb;      return get_endp(s, pid, ep)->iso_urb;
 }  }
   
 static void set_iso_urb_idx(USBHostDevice *s, int ep, int i)  static void set_iso_urb_idx(USBHostDevice *s, int pid, int ep, int i)
 {  {
     get_endp(s, ep)->iso_urb_idx = i;      get_endp(s, pid, ep)->iso_urb_idx = i;
 }  }
   
 static int get_iso_urb_idx(USBHostDevice *s, int ep)  static int get_iso_urb_idx(USBHostDevice *s, int pid, int ep)
 {  {
     return get_endp(s, ep)->iso_urb_idx;      return get_endp(s, pid, ep)->iso_urb_idx;
 }  }
   
 static void set_iso_buffer_used(USBHostDevice *s, int ep, int i)  static void set_iso_buffer_used(USBHostDevice *s, int pid, int ep, int i)
 {  {
     get_endp(s, ep)->iso_buffer_used = i;      get_endp(s, pid, ep)->iso_buffer_used = i;
 }  }
   
 static int get_iso_buffer_used(USBHostDevice *s, int ep)  static int get_iso_buffer_used(USBHostDevice *s, int pid, int ep)
 {  {
     return get_endp(s, ep)->iso_buffer_used;      return get_endp(s, pid, ep)->iso_buffer_used;
 }  }
   
 static void set_max_packet_size(USBHostDevice *s, int ep, uint8_t *descriptor)  static void set_max_packet_size(USBHostDevice *s, int pid, int ep,
                                   uint8_t *descriptor)
 {  {
     int raw = descriptor[4] + (descriptor[5] << 8);      int raw = descriptor[4] + (descriptor[5] << 8);
     int size, microframes;      int size, microframes;
Line 241  static void set_max_packet_size(USBHostD Line 277  static void set_max_packet_size(USBHostD
     case 2:  microframes = 3; break;      case 2:  microframes = 3; break;
     default: microframes = 1; break;      default: microframes = 1; break;
     }      }
     get_endp(s, ep)->max_packet_size = size * microframes;      get_endp(s, pid, ep)->max_packet_size = size * microframes;
 }  }
   
 static int get_max_packet_size(USBHostDevice *s, int ep)  static int get_max_packet_size(USBHostDevice *s, int pid, int ep)
 {  {
     return get_endp(s, ep)->max_packet_size;      return get_endp(s, pid, ep)->max_packet_size;
 }  }
   
 /*  /*
Line 271  struct AsyncURB Line 307  struct AsyncURB
   
 static AsyncURB *async_alloc(USBHostDevice *s)  static AsyncURB *async_alloc(USBHostDevice *s)
 {  {
     AsyncURB *aurb = qemu_mallocz(sizeof(AsyncURB));      AsyncURB *aurb = g_malloc0(sizeof(AsyncURB));
     aurb->hdev = s;      aurb->hdev = s;
     QLIST_INSERT_HEAD(&s->aurbs, aurb, next);      QLIST_INSERT_HEAD(&s->aurbs, aurb, next);
     return aurb;      return aurb;
Line 280  static AsyncURB *async_alloc(USBHostDevi Line 316  static AsyncURB *async_alloc(USBHostDevi
 static void async_free(AsyncURB *aurb)  static void async_free(AsyncURB *aurb)
 {  {
     QLIST_REMOVE(aurb, next);      QLIST_REMOVE(aurb, next);
     qemu_free(aurb);      g_free(aurb);
 }  }
   
 static void do_disconnect(USBHostDevice *s)  static void do_disconnect(USBHostDevice *s)
 {  {
     printf("husb: device %d.%d disconnected\n",  
            s->bus_num, s->addr);  
     usb_host_close(s);      usb_host_close(s);
     usb_host_auto_check(NULL);      usb_host_auto_check(NULL);
 }  }
Line 308  static void async_complete(void *opaque) Line 342  static void async_complete(void *opaque)
                 }                  }
                 return;                  return;
             }              }
             if (errno == ENODEV && !s->closing) {              if (errno == ENODEV) {
                 do_disconnect(s);                  if (!s->closing) {
                       trace_usb_host_disconnect(s->bus_num, s->addr);
                       do_disconnect(s);
                   }
                 return;                  return;
             }              }
   
             DPRINTF("husb: async. reap urb failed errno %d\n", errno);              perror("USBDEVFS_REAPURBNDELAY");
             return;              return;
         }          }
   
Line 324  static void async_complete(void *opaque) Line 361  static void async_complete(void *opaque)
            anything else (it is handled further in usb_host_handle_iso_data) */             anything else (it is handled further in usb_host_handle_iso_data) */
         if (aurb->iso_frame_idx == -1) {          if (aurb->iso_frame_idx == -1) {
             int inflight;              int inflight;
               int pid = (aurb->urb.endpoint & USB_DIR_IN) ?
                   USB_TOKEN_IN : USB_TOKEN_OUT;
               int ep = aurb->urb.endpoint & 0xf;
             if (aurb->urb.status == -EPIPE) {              if (aurb->urb.status == -EPIPE) {
                 set_halt(s, aurb->urb.endpoint & 0xf);                  set_halt(s, pid, ep);
             }              }
             aurb->iso_frame_idx = 0;              aurb->iso_frame_idx = 0;
             urbs++;              urbs++;
             inflight = change_iso_inflight(s, aurb->urb.endpoint & 0xf, -1);              inflight = change_iso_inflight(s, pid, ep, -1);
             if (inflight == 0 && is_iso_started(s, aurb->urb.endpoint & 0xf)) {              if (inflight == 0 && is_iso_started(s, pid, ep)) {
                 fprintf(stderr, "husb: out of buffers for iso stream\n");                  fprintf(stderr, "husb: out of buffers for iso stream\n");
             }              }
             continue;              continue;
         }          }
   
         p = aurb->packet;          p = aurb->packet;
           trace_usb_host_urb_complete(s->bus_num, s->addr, aurb, aurb->urb.status,
                                       aurb->urb.actual_length, aurb->more);
   
         if (p) {          if (p) {
             switch (aurb->urb.status) {              switch (aurb->urb.status) {
             case 0:              case 0:
                 p->len += aurb->urb.actual_length;                  p->result += aurb->urb.actual_length;
                 break;                  break;
   
             case -EPIPE:              case -EPIPE:
                 set_halt(s, p->devep);                  set_halt(s, p->pid, p->devep);
                 p->len = USB_RET_STALL;                  p->result = USB_RET_STALL;
                 break;                  break;
   
             default:              default:
                 p->len = USB_RET_NAK;                  p->result = USB_RET_NAK;
                 break;                  break;
             }              }
   
             if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {              if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
                   trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
                 usb_generic_async_ctrl_complete(&s->dev, p);                  usb_generic_async_ctrl_complete(&s->dev, p);
             } else if (!aurb->more) {              } else if (!aurb->more) {
                   trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
                 usb_packet_complete(&s->dev, p);                  usb_packet_complete(&s->dev, p);
             }              }
         }          }
Line 387  static void usb_host_async_cancel(USBDev Line 431  static void usb_host_async_cancel(USBDev
     }      }
 }  }
   
   static int usb_host_claim_port(USBHostDevice *s)
   {
   #ifdef USBDEVFS_CLAIM_PORT
       char *h, hub_name[64], line[1024];
       int hub_addr, ret;
   
       snprintf(hub_name, sizeof(hub_name), "%d-%s",
                s->match.bus_num, s->match.port);
   
       /* try strip off last ".$portnr" to get hub */
       h = strrchr(hub_name, '.');
       if (h != NULL) {
           s->hub_port = atoi(h+1);
           *h = '\0';
       } else {
           /* no dot in there -> it is the root hub */
           snprintf(hub_name, sizeof(hub_name), "usb%d",
                    s->match.bus_num);
           s->hub_port = atoi(s->match.port);
       }
   
       if (!usb_host_read_file(line, sizeof(line), "devnum",
                               hub_name)) {
           return -1;
       }
       if (sscanf(line, "%d", &hub_addr) != 1) {
           return -1;
       }
   
       if (!usb_host_device_path) {
           return -1;
       }
       snprintf(line, sizeof(line), "%s/%03d/%03d",
                usb_host_device_path, s->match.bus_num, hub_addr);
       s->hub_fd = open(line, O_RDWR | O_NONBLOCK);
       if (s->hub_fd < 0) {
           return -1;
       }
   
       ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &s->hub_port);
       if (ret < 0) {
           close(s->hub_fd);
           s->hub_fd = -1;
           return -1;
       }
   
       trace_usb_host_claim_port(s->match.bus_num, hub_addr, s->hub_port);
       return 0;
   #else
       return -1;
   #endif
   }
   
   static void usb_host_release_port(USBHostDevice *s)
   {
       if (s->hub_fd == -1) {
           return;
       }
   #ifdef USBDEVFS_RELEASE_PORT
       ioctl(s->hub_fd, USBDEVFS_RELEASE_PORT, &s->hub_port);
   #endif
       close(s->hub_fd);
       s->hub_fd = -1;
   }
   
   static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
   {
       /* earlier Linux 2.4 do not support that */
   #ifdef USBDEVFS_DISCONNECT
       struct usbdevfs_ioctl ctrl;
       int ret, interface;
   
       for (interface = 0; interface < nb_interfaces; interface++) {
           ctrl.ioctl_code = USBDEVFS_DISCONNECT;
           ctrl.ifno = interface;
           ctrl.data = 0;
           ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
           if (ret < 0 && errno != ENODATA) {
               perror("USBDEVFS_DISCONNECT");
               return -1;
           }
       }
   #endif
       return 0;
   }
   
   static int usb_linux_get_num_interfaces(USBHostDevice *s)
   {
       char device_name[64], line[1024];
       int num_interfaces = 0;
   
       if (usb_fs_type != USB_FS_SYS) {
           return -1;
       }
   
       sprintf(device_name, "%d-%s", s->bus_num, s->port);
       if (!usb_host_read_file(line, sizeof(line), "bNumInterfaces",
                               device_name)) {
           return -1;
       }
       if (sscanf(line, "%d", &num_interfaces) != 1) {
           return -1;
       }
       return num_interfaces;
   }
   
 static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)  static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
 {  {
     const char *op = NULL;      const char *op = NULL;
Line 394  static int usb_host_claim_interfaces(USB Line 544  static int usb_host_claim_interfaces(USB
     int interface, nb_interfaces;      int interface, nb_interfaces;
     int ret, i;      int ret, i;
   
     if (configuration == 0) /* address state - ignore */      if (configuration == 0) { /* address state - ignore */
           dev->ninterfaces   = 0;
           dev->configuration = 0;
         return 1;          return 1;
       }
   
     DPRINTF("husb: claiming interfaces. config %d\n", configuration);      DPRINTF("husb: claiming interfaces. config %d\n", configuration);
   
Line 418  static int usb_host_claim_interfaces(USB Line 571  static int usb_host_claim_interfaces(USB
         }          }
         config_descr_len = dev->descr[i];          config_descr_len = dev->descr[i];
   
         printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration);          DPRINTF("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
   
         if (configuration < 0 || configuration == dev->descr[i + 5]) {          if (configuration == dev->descr[i + 5]) {
             configuration = dev->descr[i + 5];              configuration = dev->descr[i + 5];
             break;              break;
         }          }
Line 435  static int usb_host_claim_interfaces(USB Line 588  static int usb_host_claim_interfaces(USB
     }      }
     nb_interfaces = dev->descr[i + 4];      nb_interfaces = dev->descr[i + 4];
   
 #ifdef USBDEVFS_DISCONNECT      if (usb_host_disconnect_ifaces(dev, nb_interfaces) < 0) {
     /* earlier Linux 2.4 do not support that */          goto fail;
     {  
         struct usbdevfs_ioctl ctrl;  
         for (interface = 0; interface < nb_interfaces; interface++) {  
             ctrl.ioctl_code = USBDEVFS_DISCONNECT;  
             ctrl.ifno = interface;  
             ctrl.data = 0;  
             op = "USBDEVFS_DISCONNECT";  
             ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);  
             if (ret < 0 && errno != ENODATA) {  
                 goto fail;  
             }  
         }  
     }      }
 #endif  
   
     /* XXX: only grab if all interfaces are free */      /* XXX: only grab if all interfaces are free */
     for (interface = 0; interface < nb_interfaces; interface++) {      for (interface = 0; interface < nb_interfaces; interface++) {
         op = "USBDEVFS_CLAIMINTERFACE";          op = "USBDEVFS_CLAIMINTERFACE";
         ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);          ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
         if (ret < 0) {          if (ret < 0) {
             if (errno == EBUSY) {  
                 printf("husb: update iface. device already grabbed\n");  
             } else {  
                 perror("husb: failed to claim interface");  
             }  
             goto fail;              goto fail;
         }          }
     }      }
   
     printf("husb: %d interfaces claimed for configuration %d\n",      trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
            nb_interfaces, configuration);                                      nb_interfaces, configuration);
   
     dev->ninterfaces   = nb_interfaces;      dev->ninterfaces   = nb_interfaces;
     dev->configuration = configuration;      dev->configuration = configuration;
Line 485  static int usb_host_release_interfaces(U Line 620  static int usb_host_release_interfaces(U
 {  {
     int ret, i;      int ret, i;
   
     DPRINTF("husb: releasing interfaces\n");      trace_usb_host_release_interfaces(s->bus_num, s->addr);
   
     for (i = 0; i < s->ninterfaces; i++) {      for (i = 0; i < s->ninterfaces; i++) {
         ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);          ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
         if (ret < 0) {          if (ret < 0) {
             perror("husb: failed to release interface");              perror("USBDEVFS_RELEASEINTERFACE");
             return 0;              return 0;
         }          }
     }      }
   
     return 1;      return 1;
 }  }
   
Line 502  static void usb_host_handle_reset(USBDev Line 636  static void usb_host_handle_reset(USBDev
 {  {
     USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);      USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
   
     DPRINTF("husb: reset device %u.%u\n", s->bus_num, s->addr);      trace_usb_host_reset(s->bus_num, s->addr);
   
     ioctl(s->fd, USBDEVFS_RESET);      usb_host_do_reset(s);;
   
     usb_host_claim_interfaces(s, s->configuration);      usb_host_claim_interfaces(s, 0);
       usb_linux_update_endp_table(s);
 }  }
   
 static void usb_host_handle_destroy(USBDevice *dev)  static void usb_host_handle_destroy(USBDevice *dev)
 {  {
     USBHostDevice *s = (USBHostDevice *)dev;      USBHostDevice *s = (USBHostDevice *)dev;
   
       usb_host_release_port(s);
     usb_host_close(s);      usb_host_close(s);
     QTAILQ_REMOVE(&hostdevs, s, next);      QTAILQ_REMOVE(&hostdevs, s, next);
     qemu_remove_exit_notifier(&s->exit);      qemu_remove_exit_notifier(&s->exit);
 }  }
   
 static int usb_linux_update_endp_table(USBHostDevice *s);  
   
 /* iso data is special, we need to keep enough urbs in flight to make sure  /* iso data is special, we need to keep enough urbs in flight to make sure
    that the controller never runs out of them, otherwise the device will     that the controller never runs out of them, otherwise the device will
    likely suffer a buffer underrun / overrun. */     likely suffer a buffer underrun / overrun. */
 static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)  static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
 {  {
     AsyncURB *aurb;      AsyncURB *aurb;
     int i, j, len = get_max_packet_size(s, ep);      int i, j, len = get_max_packet_size(s, pid, ep);
   
     aurb = qemu_mallocz(s->iso_urb_count * sizeof(*aurb));      aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
     for (i = 0; i < s->iso_urb_count; i++) {      for (i = 0; i < s->iso_urb_count; i++) {
         aurb[i].urb.endpoint      = ep;          aurb[i].urb.endpoint      = ep;
         aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;          aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
         aurb[i].urb.buffer        = qemu_malloc(aurb[i].urb.buffer_length);          aurb[i].urb.buffer        = g_malloc(aurb[i].urb.buffer_length);
         aurb[i].urb.type          = USBDEVFS_URB_TYPE_ISO;          aurb[i].urb.type          = USBDEVFS_URB_TYPE_ISO;
         aurb[i].urb.flags         = USBDEVFS_URB_ISO_ASAP;          aurb[i].urb.flags         = USBDEVFS_URB_ISO_ASAP;
         aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;          aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
         for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)          for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
             aurb[i].urb.iso_frame_desc[j].length = len;              aurb[i].urb.iso_frame_desc[j].length = len;
         if (in) {          if (pid == USB_TOKEN_IN) {
             aurb[i].urb.endpoint |= 0x80;              aurb[i].urb.endpoint |= 0x80;
             /* Mark as fully consumed (idle) */              /* Mark as fully consumed (idle) */
             aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;              aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
         }          }
     }      }
     set_iso_urb(s, ep, aurb);      set_iso_urb(s, pid, ep, aurb);
   
     return aurb;      return aurb;
 }  }
   
 static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)  static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep)
 {  {
     AsyncURB *aurb;      AsyncURB *aurb;
     int i, ret, killed = 0, free = 1;      int i, ret, killed = 0, free = 1;
   
     aurb = get_iso_urb(s, ep);      aurb = get_iso_urb(s, pid, ep);
     if (!aurb) {      if (!aurb) {
         return;          return;
     }      }
Line 564  static void usb_host_stop_n_free_iso(USB Line 698  static void usb_host_stop_n_free_iso(USB
         if (aurb[i].iso_frame_idx == -1) {          if (aurb[i].iso_frame_idx == -1) {
             ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);              ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
             if (ret < 0) {              if (ret < 0) {
                 printf("husb: discard isoc in urb failed errno %d\n", errno);                  perror("USBDEVFS_DISCARDURB");
                 free = 0;                  free = 0;
                 continue;                  continue;
             }              }
Line 578  static void usb_host_stop_n_free_iso(USB Line 712  static void usb_host_stop_n_free_iso(USB
     }      }
   
     for (i = 0; i < s->iso_urb_count; i++) {      for (i = 0; i < s->iso_urb_count; i++) {
         qemu_free(aurb[i].urb.buffer);          g_free(aurb[i].urb.buffer);
     }      }
   
     if (free)      if (free)
         qemu_free(aurb);          g_free(aurb);
     else      else
         printf("husb: leaking iso urbs because of discard failure\n");          printf("husb: leaking iso urbs because of discard failure\n");
     set_iso_urb(s, ep, NULL);      set_iso_urb(s, pid, ep, NULL);
     set_iso_urb_idx(s, ep, 0);      set_iso_urb_idx(s, pid, ep, 0);
     clear_iso_started(s, ep);      clear_iso_started(s, pid, ep);
 }  }
   
 static int urb_status_to_usb_ret(int status)  static int urb_status_to_usb_ret(int status)
Line 604  static int usb_host_handle_iso_data(USBH Line 738  static int usb_host_handle_iso_data(USBH
 {  {
     AsyncURB *aurb;      AsyncURB *aurb;
     int i, j, ret, max_packet_size, offset, len = 0;      int i, j, ret, max_packet_size, offset, len = 0;
       uint8_t *buf;
   
     max_packet_size = get_max_packet_size(s, p->devep);      max_packet_size = get_max_packet_size(s, p->pid, p->devep);
     if (max_packet_size == 0)      if (max_packet_size == 0)
         return USB_RET_NAK;          return USB_RET_NAK;
   
     aurb = get_iso_urb(s, p->devep);      aurb = get_iso_urb(s, p->pid, p->devep);
     if (!aurb) {      if (!aurb) {
         aurb = usb_host_alloc_iso(s, p->devep, in);          aurb = usb_host_alloc_iso(s, p->pid, p->devep);
     }      }
   
     i = get_iso_urb_idx(s, p->devep);      i = get_iso_urb_idx(s, p->pid, p->devep);
     j = aurb[i].iso_frame_idx;      j = aurb[i].iso_frame_idx;
     if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {      if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
         if (in) {          if (in) {
Line 628  static int usb_host_handle_iso_data(USBH Line 763  static int usb_host_handle_iso_data(USBH
                 len = urb_status_to_usb_ret(                  len = urb_status_to_usb_ret(
                                         aurb[i].urb.iso_frame_desc[j].status);                                          aurb[i].urb.iso_frame_desc[j].status);
             /* Check the frame fits */              /* Check the frame fits */
             } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) {              } else if (aurb[i].urb.iso_frame_desc[j].actual_length
                          > p->iov.size) {
                 printf("husb: received iso data is larger then packet\n");                  printf("husb: received iso data is larger then packet\n");
                 len = USB_RET_NAK;                  len = USB_RET_NAK;
             /* All good copy data over */              /* All good copy data over */
             } else {              } else {
                 len = aurb[i].urb.iso_frame_desc[j].actual_length;                  len = aurb[i].urb.iso_frame_desc[j].actual_length;
                 memcpy(p->data,                  buf  = aurb[i].urb.buffer +
                        aurb[i].urb.buffer +                      j * aurb[i].urb.iso_frame_desc[0].length;
                            j * aurb[i].urb.iso_frame_desc[0].length,                  usb_packet_copy(p, buf, len);
                        len);  
             }              }
         } else {          } else {
             len = p->len;              len = p->iov.size;
             offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->devep);              offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->devep);
   
             /* Check the frame fits */              /* Check the frame fits */
             if (len > max_packet_size) {              if (len > max_packet_size) {
Line 650  static int usb_host_handle_iso_data(USBH Line 785  static int usb_host_handle_iso_data(USBH
             }              }
   
             /* All good copy data over */              /* All good copy data over */
             memcpy(aurb[i].urb.buffer + offset, p->data, len);              usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
             aurb[i].urb.iso_frame_desc[j].length = len;              aurb[i].urb.iso_frame_desc[j].length = len;
             offset += len;              offset += len;
             set_iso_buffer_used(s, p->devep, offset);              set_iso_buffer_used(s, p->pid, p->devep, offset);
   
             /* Start the stream once we have buffered enough data */              /* Start the stream once we have buffered enough data */
             if (!is_iso_started(s, p->devep) && i == 1 && j == 8) {              if (!is_iso_started(s, p->pid, p->devep) && i == 1 && j == 8) {
                 set_iso_started(s, p->devep);                  set_iso_started(s, p->pid, p->devep);
             }              }
         }          }
         aurb[i].iso_frame_idx++;          aurb[i].iso_frame_idx++;
         if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {          if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
             i = (i + 1) % s->iso_urb_count;              i = (i + 1) % s->iso_urb_count;
             set_iso_urb_idx(s, p->devep, i);              set_iso_urb_idx(s, p->pid, p->devep, i);
         }          }
     } else {      } else {
         if (in) {          if (in) {
             set_iso_started(s, p->devep);              set_iso_started(s, p->pid, p->devep);
         } else {          } else {
             DPRINTF("hubs: iso out error no free buffer, dropping packet\n");              DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
         }          }
     }      }
   
     if (is_iso_started(s, p->devep)) {      if (is_iso_started(s, p->pid, p->devep)) {
         /* (Re)-submit all fully consumed / filled urbs */          /* (Re)-submit all fully consumed / filled urbs */
         for (i = 0; i < s->iso_urb_count; i++) {          for (i = 0; i < s->iso_urb_count; i++) {
             if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {              if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
                 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);                  ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
                 if (ret < 0) {                  if (ret < 0) {
                     printf("husb error submitting iso urb %d: %d\n", i, errno);                      perror("USBDEVFS_SUBMITURB");
                     if (!in || len == 0) {                      if (!in || len == 0) {
                         switch(errno) {                          switch(errno) {
                         case ETIMEDOUT:                          case ETIMEDOUT:
Line 693  static int usb_host_handle_iso_data(USBH Line 828  static int usb_host_handle_iso_data(USBH
                     break;                      break;
                 }                  }
                 aurb[i].iso_frame_idx = -1;                  aurb[i].iso_frame_idx = -1;
                 change_iso_inflight(s, p->devep, +1);                  change_iso_inflight(s, p->pid, p->devep, 1);
             }              }
         }          }
     }      }
Line 706  static int usb_host_handle_data(USBDevic Line 841  static int usb_host_handle_data(USBDevic
     USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);      USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
     struct usbdevfs_urb *urb;      struct usbdevfs_urb *urb;
     AsyncURB *aurb;      AsyncURB *aurb;
     int ret, rem;      int ret, rem, prem, v;
     uint8_t *pbuf;      uint8_t *pbuf;
     uint8_t ep;      uint8_t ep;
   
     if (!is_valid(s, p->devep)) {      trace_usb_host_req_data(s->bus_num, s->addr,
                               p->pid == USB_TOKEN_IN,
                               p->devep, p->iov.size);
   
       if (!is_valid(s, p->pid, p->devep)) {
           trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
         return USB_RET_NAK;          return USB_RET_NAK;
     }      }
   
Line 720  static int usb_host_handle_data(USBDevic Line 860  static int usb_host_handle_data(USBDevic
         ep = p->devep;          ep = p->devep;
     }      }
   
     if (is_halted(s, p->devep)) {      if (is_halted(s, p->pid, p->devep)) {
         ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);          unsigned int arg = ep;
           ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
         if (ret < 0) {          if (ret < 0) {
             DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",              perror("USBDEVFS_CLEAR_HALT");
                    ep, errno);              trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
             return USB_RET_NAK;              return USB_RET_NAK;
         }          }
         clear_halt(s, p->devep);          clear_halt(s, p->pid, p->devep);
     }      }
   
     if (is_isoc(s, p->devep)) {      if (is_isoc(s, p->pid, p->devep)) {
         return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);          return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
     }      }
   
     rem = p->len;      v = 0;
     pbuf = p->data;      prem = p->iov.iov[v].iov_len;
     p->len = 0;      pbuf = p->iov.iov[v].iov_base;
       rem = p->iov.size;
     while (rem) {      while (rem) {
           if (prem == 0) {
               v++;
               assert(v < p->iov.niov);
               prem = p->iov.iov[v].iov_len;
               pbuf = p->iov.iov[v].iov_base;
               assert(prem <= rem);
           }
         aurb = async_alloc(s);          aurb = async_alloc(s);
         aurb->packet = p;          aurb->packet = p;
   
Line 746  static int usb_host_handle_data(USBDevic Line 895  static int usb_host_handle_data(USBDevic
         urb->type          = USBDEVFS_URB_TYPE_BULK;          urb->type          = USBDEVFS_URB_TYPE_BULK;
         urb->usercontext   = s;          urb->usercontext   = s;
         urb->buffer        = pbuf;          urb->buffer        = pbuf;
           urb->buffer_length = prem;
   
         if (rem > MAX_USBFS_BUFFER_SIZE) {          if (urb->buffer_length > MAX_USBFS_BUFFER_SIZE) {
             urb->buffer_length = MAX_USBFS_BUFFER_SIZE;              urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
             aurb->more         = 1;  
         } else {  
             urb->buffer_length = rem;  
             aurb->more         = 0;  
         }          }
         pbuf += urb->buffer_length;          pbuf += urb->buffer_length;
           prem -= urb->buffer_length;
         rem  -= urb->buffer_length;          rem  -= urb->buffer_length;
           if (rem) {
               aurb->more         = 1;
           }
   
           trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
                                     urb->buffer_length, aurb->more);
         ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);          ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
   
         DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",          DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
                 urb->endpoint, urb->buffer_length, aurb->more, p, aurb);                  urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
   
         if (ret < 0) {          if (ret < 0) {
             DPRINTF("husb: submit failed. errno %d\n", errno);              perror("USBDEVFS_SUBMITURB");
             async_free(aurb);              async_free(aurb);
   
             switch(errno) {              switch(errno) {
             case ETIMEDOUT:              case ETIMEDOUT:
                   trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
                 return USB_RET_NAK;                  return USB_RET_NAK;
             case EPIPE:              case EPIPE:
             default:              default:
                   trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_STALL);
                 return USB_RET_STALL;                  return USB_RET_STALL;
             }              }
         }          }
Line 790  static int ctrl_error(void) Line 944  static int ctrl_error(void)
   
 static int usb_host_set_address(USBHostDevice *s, int addr)  static int usb_host_set_address(USBHostDevice *s, int addr)
 {  {
     DPRINTF("husb: ctrl set addr %u\n", addr);      trace_usb_host_set_address(s->bus_num, s->addr, addr);
     s->dev.addr = addr;      s->dev.addr = addr;
     return 0;      return 0;
 }  }
   
 static int usb_host_set_config(USBHostDevice *s, int config)  static int usb_host_set_config(USBHostDevice *s, int config)
 {  {
       int ret, first = 1;
   
       trace_usb_host_set_config(s->bus_num, s->addr, config);
   
     usb_host_release_interfaces(s);      usb_host_release_interfaces(s);
   
     int ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);  again:
       ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
   
     DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);      DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
   
       if (ret < 0 && errno == EBUSY && first) {
           /* happens if usb device is in use by host drivers */
           int count = usb_linux_get_num_interfaces(s);
           if (count > 0) {
               DPRINTF("husb: busy -> disconnecting %d interfaces\n", count);
               usb_host_disconnect_ifaces(s, count);
               first = 0;
               goto again;
           }
       }
   
     if (ret < 0) {      if (ret < 0) {
         return ctrl_error();          return ctrl_error();
     }      }
     usb_host_claim_interfaces(s, config);      usb_host_claim_interfaces(s, config);
       usb_linux_update_endp_table(s);
     return 0;      return 0;
 }  }
   
Line 815  static int usb_host_set_interface(USBHos Line 986  static int usb_host_set_interface(USBHos
     struct usbdevfs_setinterface si;      struct usbdevfs_setinterface si;
     int i, ret;      int i, ret;
   
       trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
   
     for (i = 1; i <= MAX_ENDPOINTS; i++) {      for (i = 1; i <= MAX_ENDPOINTS; i++) {
         if (is_isoc(s, i)) {          if (is_isoc(s, USB_TOKEN_IN, i)) {
             usb_host_stop_n_free_iso(s, i);              usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i);
           }
           if (is_isoc(s, USB_TOKEN_OUT, i)) {
               usb_host_stop_n_free_iso(s, USB_TOKEN_OUT, i);
         }          }
     }      }
   
Line 849  static int usb_host_handle_control(USBDe Line 1025  static int usb_host_handle_control(USBDe
      */       */
   
     /* Note request is (bRequestType << 8) | bRequest */      /* Note request is (bRequestType << 8) | bRequest */
     DPRINTF("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n",      trace_usb_host_req_control(s->bus_num, s->addr, request, value, index);
             request >> 8, request & 0xff, value, index, length);  
   
     switch (request) {      switch (request) {
     case DeviceOutRequest | USB_REQ_SET_ADDRESS:      case DeviceOutRequest | USB_REQ_SET_ADDRESS:
Line 890  static int usb_host_handle_control(USBDe Line 1065  static int usb_host_handle_control(USBDe
   
     urb->usercontext = s;      urb->usercontext = s;
   
       trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
                                 urb->buffer_length, aurb->more);
     ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);      ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
   
     DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);      DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
Line 910  static int usb_host_handle_control(USBDe Line 1087  static int usb_host_handle_control(USBDe
     return USB_RET_ASYNC;      return USB_RET_ASYNC;
 }  }
   
 static int usb_linux_get_configuration(USBHostDevice *s)  
 {  
     uint8_t configuration;  
     struct usb_ctrltransfer ct;  
     int ret;  
   
     if (usb_fs_type == USB_FS_SYS) {  
         char device_name[32], line[1024];  
         int configuration;  
   
         sprintf(device_name, "%d-%s", s->bus_num, s->port);  
   
         if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",  
                                 device_name)) {  
             goto usbdevfs;  
         }  
         if (sscanf(line, "%d", &configuration) != 1) {  
             goto usbdevfs;  
         }  
         return configuration;  
     }  
   
 usbdevfs:  
     ct.bRequestType = USB_DIR_IN;  
     ct.bRequest = USB_REQ_GET_CONFIGURATION;  
     ct.wValue = 0;  
     ct.wIndex = 0;  
     ct.wLength = 1;  
     ct.data = &configuration;  
     ct.timeout = 50;  
   
     ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);  
     if (ret < 0) {  
         perror("usb_linux_get_configuration");  
         return -1;  
     }  
   
     /* in address state */  
     if (configuration == 0) {  
         return -1;  
     }  
   
     return configuration;  
 }  
   
 static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,  static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
     uint8_t configuration, uint8_t interface)      uint8_t configuration, uint8_t interface)
 {  {
Line 1000  usbdevfs: Line 1132  usbdevfs:
 static int usb_linux_update_endp_table(USBHostDevice *s)  static int usb_linux_update_endp_table(USBHostDevice *s)
 {  {
     uint8_t *descriptors;      uint8_t *descriptors;
     uint8_t devep, type, configuration, alt_interface;      uint8_t devep, type, alt_interface;
     int interface, length, i;      int interface, length, i, ep, pid;
       struct endp_data *epd;
   
     for (i = 0; i < MAX_ENDPOINTS; i++)      for (i = 0; i < MAX_ENDPOINTS; i++) {
         s->endp_table[i].type = INVALID_EP_TYPE;          s->ep_in[i].type = INVALID_EP_TYPE;
           s->ep_out[i].type = INVALID_EP_TYPE;
       }
   
     i = usb_linux_get_configuration(s);      if (s->configuration == 0) {
     if (i < 0)          /* not configured yet -- leave all endpoints disabled */
         return 1;          return 0;
     configuration = i;      }
   
     /* get the desired configuration, interface, and endpoint descriptors      /* get the desired configuration, interface, and endpoint descriptors
      * from device description */       * from device description */
Line 1017  static int usb_linux_update_endp_table(U Line 1152  static int usb_linux_update_endp_table(U
     length = s->descr_len - 18;      length = s->descr_len - 18;
     i = 0;      i = 0;
   
     if (descriptors[i + 1] != USB_DT_CONFIG ||  
         descriptors[i + 5] != configuration) {  
         DPRINTF("invalid descriptor data - configuration\n");  
         return 1;  
     }  
     i += descriptors[i];  
   
     while (i < length) {      while (i < length) {
           if (descriptors[i + 1] != USB_DT_CONFIG) {
               fprintf(stderr, "invalid descriptor data\n");
               return 1;
           } else if (descriptors[i + 5] != s->configuration) {
               DPRINTF("not requested configuration %d\n", s->configuration);
               i += (descriptors[i + 3] << 8) + descriptors[i + 2];
               continue;
           }
   
           i += descriptors[i];
   
         if (descriptors[i + 1] != USB_DT_INTERFACE ||          if (descriptors[i + 1] != USB_DT_INTERFACE ||
             (descriptors[i + 1] == USB_DT_INTERFACE &&              (descriptors[i + 1] == USB_DT_INTERFACE &&
              descriptors[i + 4] == 0)) {               descriptors[i + 4] == 0)) {
Line 1033  static int usb_linux_update_endp_table(U Line 1172  static int usb_linux_update_endp_table(U
         }          }
   
         interface = descriptors[i + 2];          interface = descriptors[i + 2];
         alt_interface = usb_linux_get_alt_setting(s, configuration, interface);          alt_interface = usb_linux_get_alt_setting(s, s->configuration,
                                                     interface);
   
         /* the current interface descriptor is the active interface          /* the current interface descriptor is the active interface
          * and has endpoints */           * and has endpoints */
Line 1056  static int usb_linux_update_endp_table(U Line 1196  static int usb_linux_update_endp_table(U
             }              }
   
             devep = descriptors[i + 2];              devep = descriptors[i + 2];
             if ((devep & 0x0f) == 0) {              pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
               ep = devep & 0xf;
               if (ep == 0) {
                 fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");                  fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
                 return 1;                  return 1;
             }              }
Line 1067  static int usb_linux_update_endp_table(U Line 1209  static int usb_linux_update_endp_table(U
                 break;                  break;
             case 0x01:              case 0x01:
                 type = USBDEVFS_URB_TYPE_ISO;                  type = USBDEVFS_URB_TYPE_ISO;
                 set_max_packet_size(s, (devep & 0xf), descriptors + i);                  set_max_packet_size(s, pid, ep, descriptors + i);
                 break;                  break;
             case 0x02:              case 0x02:
                 type = USBDEVFS_URB_TYPE_BULK;                  type = USBDEVFS_URB_TYPE_BULK;
Line 1079  static int usb_linux_update_endp_table(U Line 1221  static int usb_linux_update_endp_table(U
                 DPRINTF("usb_host: malformed endpoint type\n");                  DPRINTF("usb_host: malformed endpoint type\n");
                 type = USBDEVFS_URB_TYPE_BULK;                  type = USBDEVFS_URB_TYPE_BULK;
             }              }
             s->endp_table[(devep & 0xf) - 1].type = type;              epd = get_endp(s, pid, ep);
             s->endp_table[(devep & 0xf) - 1].halted = 0;              assert(epd->type == INVALID_EP_TYPE);
               epd->type = type;
               epd->halted = 0;
   
             i += descriptors[i];              i += descriptors[i];
         }          }
Line 1125  static int usb_linux_full_speed_compat(U Line 1269  static int usb_linux_full_speed_compat(U
 }  }
   
 static int usb_host_open(USBHostDevice *dev, int bus_num,  static int usb_host_open(USBHostDevice *dev, int bus_num,
                         int addr, char *port, const char *prod_name, int speed)                           int addr, const char *port,
                            const char *prod_name, int speed)
 {  {
     int fd = -1, ret;      int fd = -1, ret;
     char buf[1024];      char buf[1024];
   
       trace_usb_host_open_started(bus_num, addr);
   
     if (dev->fd != -1) {      if (dev->fd != -1) {
         goto fail;          goto fail;
     }      }
     printf("husb: open device %d.%d\n", bus_num, addr);  
   
     if (!usb_host_device_path) {      if (!usb_host_device_path) {
         perror("husb: USB Host Device Path not set");          perror("husb: USB Host Device Path not set");
Line 1172  static int usb_host_open(USBHostDevice * Line 1318  static int usb_host_open(USBHostDevice *
 #endif  #endif
   
   
     /*      /* start unconfigured -- we'll wait for the guest to set a configuration */
      * Initial configuration is -1 which makes us claim first      if (!usb_host_claim_interfaces(dev, 0)) {
      * available config. We used to start with 1, which does not  
      * always work. I've seen devices where first config starts  
      * with 2.  
      */  
     if (!usb_host_claim_interfaces(dev, -1)) {  
         goto fail;          goto fail;
     }      }
   
Line 1208  static int usb_host_open(USBHostDevice * Line 1349  static int usb_host_open(USBHostDevice *
         dev->dev.speedmask |= USB_SPEED_MASK_FULL;          dev->dev.speedmask |= USB_SPEED_MASK_FULL;
     }      }
   
     printf("husb: grabbed usb device %d.%d\n", bus_num, addr);      trace_usb_host_open_success(bus_num, addr);
   
     if (!prod_name || prod_name[0] == '\0') {      if (!prod_name || prod_name[0] == '\0') {
         snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),          snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
Line 1229  static int usb_host_open(USBHostDevice * Line 1370  static int usb_host_open(USBHostDevice *
     return 0;      return 0;
   
 fail:  fail:
       trace_usb_host_open_failure(bus_num, addr);
     if (dev->fd != -1) {      if (dev->fd != -1) {
         close(dev->fd);          close(dev->fd);
         dev->fd = -1;          dev->fd = -1;
Line 1240  static int usb_host_close(USBHostDevice  Line 1382  static int usb_host_close(USBHostDevice 
 {  {
     int i;      int i;
   
     if (dev->fd == -1 || !dev->dev.attached) {      if (dev->fd == -1) {
         return -1;          return -1;
     }      }
   
       trace_usb_host_close(dev->bus_num, dev->addr);
   
     qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);      qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
     dev->closing = 1;      dev->closing = 1;
     for (i = 1; i <= MAX_ENDPOINTS; i++) {      for (i = 1; i <= MAX_ENDPOINTS; i++) {
         if (is_isoc(dev, i)) {          if (is_isoc(dev, USB_TOKEN_IN, i)) {
             usb_host_stop_n_free_iso(dev, i);              usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i);
           }
           if (is_isoc(dev, USB_TOKEN_OUT, i)) {
               usb_host_stop_n_free_iso(dev, USB_TOKEN_OUT, i);
         }          }
     }      }
     async_complete(dev);      async_complete(dev);
     dev->closing = 0;      dev->closing = 0;
     usb_device_detach(&dev->dev);      if (dev->dev.attached) {
     ioctl(dev->fd, USBDEVFS_RESET);          usb_device_detach(&dev->dev);
       }
       usb_host_do_reset(dev);
     close(dev->fd);      close(dev->fd);
     dev->fd = -1;      dev->fd = -1;
     return 0;      return 0;
Line 1264  static void usb_host_exit_notifier(struc Line 1413  static void usb_host_exit_notifier(struc
 {  {
     USBHostDevice *s = container_of(n, USBHostDevice, exit);      USBHostDevice *s = container_of(n, USBHostDevice, exit);
   
       usb_host_release_port(s);
     if (s->fd != -1) {      if (s->fd != -1) {
         ioctl(s->fd, USBDEVFS_RESET);          usb_host_do_reset(s);;
     }      }
 }  }
   
Line 1275  static int usb_host_initfn(USBDevice *de Line 1425  static int usb_host_initfn(USBDevice *de
   
     dev->auto_attach = 0;      dev->auto_attach = 0;
     s->fd = -1;      s->fd = -1;
       s->hub_fd = -1;
   
     QTAILQ_INSERT_TAIL(&hostdevs, s, next);      QTAILQ_INSERT_TAIL(&hostdevs, s, next);
     s->exit.notify = usb_host_exit_notifier;      s->exit.notify = usb_host_exit_notifier;
     qemu_add_exit_notifier(&s->exit);      qemu_add_exit_notifier(&s->exit);
     usb_host_auto_check(NULL);      usb_host_auto_check(NULL);
   
       if (s->match.bus_num != 0 && s->match.port != NULL) {
           usb_host_claim_port(s);
       }
     return 0;      return 0;
 }  }
   
   static const VMStateDescription vmstate_usb_host = {
       .name = "usb-host",
       .unmigratable = 1,
   };
   
 static struct USBDeviceInfo usb_host_dev_info = {  static struct USBDeviceInfo usb_host_dev_info = {
     .product_desc   = "USB Host Device",      .product_desc   = "USB Host Device",
     .qdev.name      = "usb-host",      .qdev.name      = "usb-host",
     .qdev.size      = sizeof(USBHostDevice),      .qdev.size      = sizeof(USBHostDevice),
       .qdev.vmsd      = &vmstate_usb_host,
     .init           = usb_host_initfn,      .init           = usb_host_initfn,
     .handle_packet  = usb_generic_handle_packet,      .handle_packet  = usb_generic_handle_packet,
     .cancel_packet  = usb_host_async_cancel,      .cancel_packet  = usb_host_async_cancel,
Line 1411  static int usb_host_scan_dev(void *opaqu Line 1573  static int usb_host_scan_dev(void *opaqu
     FILE *f = NULL;      FILE *f = NULL;
     char line[1024];      char line[1024];
     char buf[1024];      char buf[1024];
     int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;      int bus_num, addr, speed, device_count;
       int class_id, product_id, vendor_id, port;
     char product_name[512];      char product_name[512];
     int ret = 0;      int ret = 0;
   
Line 1427  static int usb_host_scan_dev(void *opaqu Line 1590  static int usb_host_scan_dev(void *opaqu
     }      }
   
     device_count = 0;      device_count = 0;
     bus_num = addr = class_id = product_id = vendor_id = 0;      bus_num = addr = class_id = product_id = vendor_id = port = 0;
     speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */      speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
     for(;;) {      for(;;) {
         if (fgets(line, sizeof(line), f) == NULL) {          if (fgets(line, sizeof(line), f) == NULL) {
Line 1439  static int usb_host_scan_dev(void *opaqu Line 1602  static int usb_host_scan_dev(void *opaqu
         if (line[0] == 'T' && line[1] == ':') {          if (line[0] == 'T' && line[1] == ':') {
             if (device_count && (vendor_id || product_id)) {              if (device_count && (vendor_id || product_id)) {
                 /* New device.  Add the previously discovered device.  */                  /* New device.  Add the previously discovered device.  */
                 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,                  if (port > 0) {
                       snprintf(buf, sizeof(buf), "%d", port);
                   } else {
                       snprintf(buf, sizeof(buf), "?");
                   }
                   ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
                            product_id, product_name, speed);                             product_id, product_name, speed);
                 if (ret) {                  if (ret) {
                     goto the_end;                      goto the_end;
Line 1449  static int usb_host_scan_dev(void *opaqu Line 1617  static int usb_host_scan_dev(void *opaqu
                 goto fail;                  goto fail;
             }              }
             bus_num = atoi(buf);              bus_num = atoi(buf);
               if (get_tag_value(buf, sizeof(buf), line, "Port=", " ") < 0) {
                   goto fail;
               }
               port = atoi(buf);
             if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {              if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
                 goto fail;                  goto fail;
             }              }
Line 1494  static int usb_host_scan_dev(void *opaqu Line 1666  static int usb_host_scan_dev(void *opaqu
     }      }
     if (device_count && (vendor_id || product_id)) {      if (device_count && (vendor_id || product_id)) {
         /* Add the last device.  */          /* Add the last device.  */
         ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,          if (port > 0) {
               snprintf(buf, sizeof(buf), "%d", port);
           } else {
               snprintf(buf, sizeof(buf), "?");
           }
           ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
                    product_id, product_name, speed);                     product_id, product_name, speed);
     }      }
  the_end:   the_end:
Line 1678  static int usb_host_scan(void *opaque, U Line 1855  static int usb_host_scan(void *opaque, U
         }          }
   
         /* the module setting (used later for opening devices) */          /* the module setting (used later for opening devices) */
         usb_host_device_path = qemu_mallocz(strlen(devpath)+1);          usb_host_device_path = g_malloc0(strlen(devpath)+1);
         strcpy(usb_host_device_path, devpath);          strcpy(usb_host_device_path, devpath);
         if (mon) {          if (mon) {
             monitor_printf(mon, "husb: using %s file-system with %s\n",              monitor_printf(mon, "husb: using %s file-system with %s\n",
Line 1703  static int usb_host_scan(void *opaque, U Line 1880  static int usb_host_scan(void *opaque, U
   
 static QEMUTimer *usb_auto_timer;  static QEMUTimer *usb_auto_timer;
   
 static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,  static int usb_host_auto_scan(void *opaque, int bus_num,
                                 int addr, const char *port,
                               int class_id, int vendor_id, int product_id,                                int class_id, int vendor_id, int product_id,
                               const char *product_name, int speed)                                const char *product_name, int speed)
 {  {
Line 1735  static int usb_host_auto_scan(void *opaq Line 1913  static int usb_host_auto_scan(void *opaq
             continue;              continue;
         }          }
         /* We got a match */          /* We got a match */
           s->seen++;
           if (s->errcount >= 3) {
               return 0;
           }
   
         /* Already attached ? */          /* Already attached ? */
         if (s->fd != -1) {          if (s->fd != -1) {
Line 1742  static int usb_host_auto_scan(void *opaq Line 1924  static int usb_host_auto_scan(void *opaq
         }          }
         DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);          DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
   
         usb_host_open(s, bus_num, addr, port, product_name, speed);          if (usb_host_open(s, bus_num, addr, port, product_name, speed) < 0) {
               s->errcount++;
           }
         break;          break;
     }      }
   
Line 1760  static void usb_host_auto_check(void *un Line 1944  static void usb_host_auto_check(void *un
         if (s->fd == -1) {          if (s->fd == -1) {
             unconnected++;              unconnected++;
         }          }
           if (s->seen == 0) {
               s->errcount = 0;
           }
           s->seen = 0;
     }      }
   
     if (unconnected == 0) {      if (unconnected == 0) {
         /* nothing to watch */          /* nothing to watch */
         if (usb_auto_timer) {          if (usb_auto_timer) {
             qemu_del_timer(usb_auto_timer);              qemu_del_timer(usb_auto_timer);
               trace_usb_host_auto_scan_disabled();
         }          }
         return;          return;
     }      }
Line 1775  static void usb_host_auto_check(void *un Line 1964  static void usb_host_auto_check(void *un
         if (!usb_auto_timer) {          if (!usb_auto_timer) {
             return;              return;
         }          }
           trace_usb_host_auto_scan_enabled();
     }      }
     qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);      qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
 }  }
Line 1865  static const char *usb_class_str(uint8_t Line 2055  static const char *usb_class_str(uint8_t
     return p->class_name;      return p->class_name;
 }  }
   
 static void usb_info_device(Monitor *mon, int bus_num, int addr, char *port,  static void usb_info_device(Monitor *mon, int bus_num,
                               int addr, const char *port,
                             int class_id, int vendor_id, int product_id,                              int class_id, int vendor_id, int product_id,
                             const char *product_name,                              const char *product_name,
                             int speed)                              int speed)
Line 1906  static void usb_info_device(Monitor *mon Line 2097  static void usb_info_device(Monitor *mon
 }  }
   
 static int usb_host_info_device(void *opaque, int bus_num, int addr,  static int usb_host_info_device(void *opaque, int bus_num, int addr,
                                 char *path, int class_id,                                  const char *path, int class_id,
                                 int vendor_id, int product_id,                                  int vendor_id, int product_id,
                                 const char *product_name,                                  const char *product_name,
                                 int speed)                                  int speed)

Removed from v.1.1.1.13  
changed lines
  Added in v.1.1.1.14


unix.superglobalmegacorp.com