Commit 985d1742dbf75e2d5b2814d0dfa25b1d578874b2
1 parent
3f423c9c
fixes for more than 8 ports - return NAK if no change - FreeBSD workaround (Lonnie Mendez)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1872 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
42 additions
and
10 deletions
hw/usb-hub.c
| @@ -158,9 +158,9 @@ static const uint8_t qemu_hub_hub_descriptor[] = | @@ -158,9 +158,9 @@ static const uint8_t qemu_hub_hub_descriptor[] = | ||
| 158 | 0x0a, /* u16 wHubCharacteristics; */ | 158 | 0x0a, /* u16 wHubCharacteristics; */ |
| 159 | 0x00, /* (per-port OC, no power switching) */ | 159 | 0x00, /* (per-port OC, no power switching) */ |
| 160 | 0x01, /* u8 bPwrOn2pwrGood; 2ms */ | 160 | 0x01, /* u8 bPwrOn2pwrGood; 2ms */ |
| 161 | - 0x00, /* u8 bHubContrCurrent; 0 mA */ | ||
| 162 | - 0x00, /* u8 DeviceRemovable; *** 7 Ports max *** */ | ||
| 163 | - 0xff /* u8 PortPwrCtrlMask; *** 7 ports max *** */ | 161 | + 0x00 /* u8 bHubContrCurrent; 0 mA */ |
| 162 | + | ||
| 163 | + /* DeviceRemovable and PortPwrCtrlMask patched in later */ | ||
| 164 | }; | 164 | }; |
| 165 | 165 | ||
| 166 | static void usb_hub_attach(USBPort *port1, USBDevice *dev) | 166 | static void usb_hub_attach(USBPort *port1, USBDevice *dev) |
| @@ -219,6 +219,12 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, | @@ -219,6 +219,12 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, | ||
| 219 | } | 219 | } |
| 220 | ret = 0; | 220 | ret = 0; |
| 221 | break; | 221 | break; |
| 222 | + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: | ||
| 223 | + if (value == 0 && index != 0x81) { /* clear ep halt */ | ||
| 224 | + goto fail; | ||
| 225 | + } | ||
| 226 | + ret = 0; | ||
| 227 | + break; | ||
| 222 | case DeviceOutRequest | USB_REQ_SET_FEATURE: | 228 | case DeviceOutRequest | USB_REQ_SET_FEATURE: |
| 223 | if (value == USB_DEVICE_REMOTE_WAKEUP) { | 229 | if (value == USB_DEVICE_REMOTE_WAKEUP) { |
| 224 | dev->remote_wakeup = 1; | 230 | dev->remote_wakeup = 1; |
| @@ -241,6 +247,11 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, | @@ -241,6 +247,11 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, | ||
| 241 | case USB_DT_CONFIG: | 247 | case USB_DT_CONFIG: |
| 242 | memcpy(data, qemu_hub_config_descriptor, | 248 | memcpy(data, qemu_hub_config_descriptor, |
| 243 | sizeof(qemu_hub_config_descriptor)); | 249 | sizeof(qemu_hub_config_descriptor)); |
| 250 | + | ||
| 251 | + /* status change endpoint size based on number | ||
| 252 | + * of ports */ | ||
| 253 | + data[22] = (s->nb_ports + 1 + 7) / 8; | ||
| 254 | + | ||
| 244 | ret = sizeof(qemu_hub_config_descriptor); | 255 | ret = sizeof(qemu_hub_config_descriptor); |
| 245 | break; | 256 | break; |
| 246 | case USB_DT_STRING: | 257 | case USB_DT_STRING: |
| @@ -385,11 +396,29 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, | @@ -385,11 +396,29 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, | ||
| 385 | } | 396 | } |
| 386 | break; | 397 | break; |
| 387 | case GetHubDescriptor: | 398 | case GetHubDescriptor: |
| 388 | - memcpy(data, qemu_hub_hub_descriptor, | ||
| 389 | - sizeof(qemu_hub_hub_descriptor)); | ||
| 390 | - data[2] = s->nb_ports; | ||
| 391 | - ret = sizeof(qemu_hub_hub_descriptor); | ||
| 392 | - break; | 399 | + { |
| 400 | + unsigned int n, limit, var_hub_size = 0; | ||
| 401 | + memcpy(data, qemu_hub_hub_descriptor, | ||
| 402 | + sizeof(qemu_hub_hub_descriptor)); | ||
| 403 | + data[2] = s->nb_ports; | ||
| 404 | + | ||
| 405 | + /* fill DeviceRemovable bits */ | ||
| 406 | + limit = ((s->nb_ports + 1 + 7) / 8) + 7; | ||
| 407 | + for (n = 7; n < limit; n++) { | ||
| 408 | + data[n] = 0x00; | ||
| 409 | + var_hub_size++; | ||
| 410 | + } | ||
| 411 | + | ||
| 412 | + /* fill PortPwrCtrlMask bits */ | ||
| 413 | + limit = limit + ((s->nb_ports + 7) / 8); | ||
| 414 | + for (;n < limit; n++) { | ||
| 415 | + data[n] = 0xff; | ||
| 416 | + var_hub_size++; | ||
| 417 | + } | ||
| 418 | + | ||
| 419 | + ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size; | ||
| 420 | + break; | ||
| 421 | + } | ||
| 393 | default: | 422 | default: |
| 394 | fail: | 423 | fail: |
| 395 | ret = USB_RET_STALL; | 424 | ret = USB_RET_STALL; |
| @@ -411,8 +440,11 @@ static int usb_hub_handle_data(USBDevice *dev, int pid, | @@ -411,8 +440,11 @@ static int usb_hub_handle_data(USBDevice *dev, int pid, | ||
| 411 | unsigned int status; | 440 | unsigned int status; |
| 412 | int i, n; | 441 | int i, n; |
| 413 | n = (s->nb_ports + 1 + 7) / 8; | 442 | n = (s->nb_ports + 1 + 7) / 8; |
| 414 | - if (n > len) | 443 | + if (len == 1) { /* FreeBSD workaround */ |
| 444 | + n = 1; | ||
| 445 | + } else if (n > len) { | ||
| 415 | return USB_RET_BABBLE; | 446 | return USB_RET_BABBLE; |
| 447 | + } | ||
| 416 | status = 0; | 448 | status = 0; |
| 417 | for(i = 0; i < s->nb_ports; i++) { | 449 | for(i = 0; i < s->nb_ports; i++) { |
| 418 | port = &s->ports[i]; | 450 | port = &s->ports[i]; |
| @@ -425,7 +457,7 @@ static int usb_hub_handle_data(USBDevice *dev, int pid, | @@ -425,7 +457,7 @@ static int usb_hub_handle_data(USBDevice *dev, int pid, | ||
| 425 | } | 457 | } |
| 426 | ret = n; | 458 | ret = n; |
| 427 | } else { | 459 | } else { |
| 428 | - ret = 0; | 460 | + ret = USB_RET_NAK; /* usb11 11.13.1 */ |
| 429 | } | 461 | } |
| 430 | } else { | 462 | } else { |
| 431 | goto fail; | 463 | goto fail; |