Merge remote-tracking branch 'kraxel/usb.33' into staging

* kraxel/usb.33:
  usb-ohci: td.cbp incorrectly updated near page end
  usb-host: properly release port on unplug & exit
  usb-storage: cancel I/O on reset
  Fix parse of usb device description with multiple configurations
This commit is contained in:
Anthony Liguori 2012-01-06 08:11:41 -06:00
commit f3e8275f49
3 changed files with 46 additions and 19 deletions

View File

@ -278,6 +278,18 @@ static void usb_msd_handle_reset(USBDevice *dev)
MSDState *s = (MSDState *)dev; MSDState *s = (MSDState *)dev;
DPRINTF("Reset\n"); DPRINTF("Reset\n");
if (s->req) {
scsi_req_cancel(s->req);
}
assert(s->req == NULL);
if (s->packet) {
USBPacket *p = s->packet;
s->packet = NULL;
p->result = USB_RET_STALL;
usb_packet_complete(dev, p);
}
s->mode = USB_MSDM_CBW; s->mode = USB_MSDM_CBW;
} }

View File

@ -1025,10 +1025,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
if (ret == len) { if (ret == len) {
td.cbp = 0; td.cbp = 0;
} else { } else {
td.cbp += ret;
if ((td.cbp & 0xfff) + ret > 0xfff) { if ((td.cbp & 0xfff) + ret > 0xfff) {
td.cbp &= 0xfff; td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff);
td.cbp |= td.be & ~0xfff; } else {
td.cbp += ret;
} }
} }
td.flags |= OHCI_TD_T1; td.flags |= OHCI_TD_T1;

View File

@ -116,6 +116,7 @@ typedef struct USBHostDevice {
USBDevice dev; USBDevice dev;
int fd; int fd;
int hub_fd; int hub_fd;
int hub_port;
uint8_t descr[8192]; uint8_t descr[8192];
int descr_len; int descr_len;
@ -434,7 +435,7 @@ static int usb_host_claim_port(USBHostDevice *s)
{ {
#ifdef USBDEVFS_CLAIM_PORT #ifdef USBDEVFS_CLAIM_PORT
char *h, hub_name[64], line[1024]; char *h, hub_name[64], line[1024];
int hub_addr, portnr, ret; int hub_addr, ret;
snprintf(hub_name, sizeof(hub_name), "%d-%s", snprintf(hub_name, sizeof(hub_name), "%d-%s",
s->match.bus_num, s->match.port); s->match.bus_num, s->match.port);
@ -442,13 +443,13 @@ static int usb_host_claim_port(USBHostDevice *s)
/* try strip off last ".$portnr" to get hub */ /* try strip off last ".$portnr" to get hub */
h = strrchr(hub_name, '.'); h = strrchr(hub_name, '.');
if (h != NULL) { if (h != NULL) {
portnr = atoi(h+1); s->hub_port = atoi(h+1);
*h = '\0'; *h = '\0';
} else { } else {
/* no dot in there -> it is the root hub */ /* no dot in there -> it is the root hub */
snprintf(hub_name, sizeof(hub_name), "usb%d", snprintf(hub_name, sizeof(hub_name), "usb%d",
s->match.bus_num); s->match.bus_num);
portnr = atoi(s->match.port); s->hub_port = atoi(s->match.port);
} }
if (!usb_host_read_file(line, sizeof(line), "devnum", if (!usb_host_read_file(line, sizeof(line), "devnum",
@ -469,20 +470,32 @@ static int usb_host_claim_port(USBHostDevice *s)
return -1; return -1;
} }
ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &portnr); ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &s->hub_port);
if (ret < 0) { if (ret < 0) {
close(s->hub_fd); close(s->hub_fd);
s->hub_fd = -1; s->hub_fd = -1;
return -1; return -1;
} }
trace_usb_host_claim_port(s->match.bus_num, hub_addr, portnr); trace_usb_host_claim_port(s->match.bus_num, hub_addr, s->hub_port);
return 0; return 0;
#else #else
return -1; return -1;
#endif #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) static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
{ {
/* earlier Linux 2.4 do not support that */ /* earlier Linux 2.4 do not support that */
@ -635,10 +648,8 @@ 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);
if (s->hub_fd != -1) {
close(s->hub_fd);
}
QTAILQ_REMOVE(&hostdevs, s, next); QTAILQ_REMOVE(&hostdevs, s, next);
qemu_remove_exit_notifier(&s->exit); qemu_remove_exit_notifier(&s->exit);
} }
@ -1141,15 +1152,18 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
length = s->descr_len - 18; length = s->descr_len - 18;
i = 0; i = 0;
if (descriptors[i + 1] != USB_DT_CONFIG ||
descriptors[i + 5] != s->configuration) {
fprintf(stderr, "invalid descriptor data - configuration %d\n",
s->configuration);
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)) {
@ -1399,6 +1413,7 @@ static void usb_host_exit_notifier(struct Notifier *n, void *data)
{ {
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) {
usb_host_do_reset(s);; usb_host_do_reset(s);;
} }