Commit 985d1742dbf75e2d5b2814d0dfa25b1d578874b2

Authored by bellard
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 158 0x0a, /* u16 wHubCharacteristics; */
159 159 0x00, /* (per-port OC, no power switching) */
160 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 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 219 }
220 220 ret = 0;
221 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 228 case DeviceOutRequest | USB_REQ_SET_FEATURE:
223 229 if (value == USB_DEVICE_REMOTE_WAKEUP) {
224 230 dev->remote_wakeup = 1;
... ... @@ -241,6 +247,11 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
241 247 case USB_DT_CONFIG:
242 248 memcpy(data, qemu_hub_config_descriptor,
243 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 255 ret = sizeof(qemu_hub_config_descriptor);
245 256 break;
246 257 case USB_DT_STRING:
... ... @@ -385,11 +396,29 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
385 396 }
386 397 break;
387 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 422 default:
394 423 fail:
395 424 ret = USB_RET_STALL;
... ... @@ -411,8 +440,11 @@ static int usb_hub_handle_data(USBDevice *dev, int pid,
411 440 unsigned int status;
412 441 int i, n;
413 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 446 return USB_RET_BABBLE;
  447 + }
416 448 status = 0;
417 449 for(i = 0; i < s->nb_ports; i++) {
418 450 port = &s->ports[i];
... ... @@ -425,7 +457,7 @@ static int usb_hub_handle_data(USBDevice *dev, int pid,
425 457 }
426 458 ret = n;
427 459 } else {
428   - ret = 0;
  460 + ret = USB_RET_NAK; /* usb11 11.13.1 */
429 461 }
430 462 } else {
431 463 goto fail;
... ...