Commit 72899afc5d2a33576094a80d1eba797e293c975a

Authored by bellard
1 parent 56bebe70

separate file for usb hub device


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1848 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -302,7 +302,7 @@ SOUND_HW += fmopl.o adlib.o
302 302 endif
303 303  
304 304 # USB layer
305   -VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o
  305 +VL_OBJS+= usb.o usb-hub.o usb-uhci.o usb-linux.o usb-hid.o
306 306  
307 307 # PCI network cards
308 308 VL_OBJS+= ne2000.o rtl8139.o
... ...
hw/usb-hub.c 0 → 100644
  1 +/*
  2 + * QEMU USB HUB emulation
  3 + *
  4 + * Copyright (c) 2005 Fabrice Bellard
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#include "vl.h"
  25 +
  26 +//#define DEBUG
  27 +
  28 +#define MAX_PORTS 8
  29 +
  30 +typedef struct USBHubPort {
  31 + USBPort port;
  32 + uint16_t wPortStatus;
  33 + uint16_t wPortChange;
  34 +} USBHubPort;
  35 +
  36 +typedef struct USBHubState {
  37 + USBDevice dev;
  38 + int nb_ports;
  39 + USBHubPort ports[MAX_PORTS];
  40 +} USBHubState;
  41 +
  42 +#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE)
  43 +#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE)
  44 +#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR)
  45 +#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS)
  46 +#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS)
  47 +#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE)
  48 +#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE)
  49 +
  50 +#define PORT_STAT_CONNECTION 0x0001
  51 +#define PORT_STAT_ENABLE 0x0002
  52 +#define PORT_STAT_SUSPEND 0x0004
  53 +#define PORT_STAT_OVERCURRENT 0x0008
  54 +#define PORT_STAT_RESET 0x0010
  55 +#define PORT_STAT_POWER 0x0100
  56 +#define PORT_STAT_LOW_SPEED 0x0200
  57 +#define PORT_STAT_HIGH_SPEED 0x0400
  58 +#define PORT_STAT_TEST 0x0800
  59 +#define PORT_STAT_INDICATOR 0x1000
  60 +
  61 +#define PORT_STAT_C_CONNECTION 0x0001
  62 +#define PORT_STAT_C_ENABLE 0x0002
  63 +#define PORT_STAT_C_SUSPEND 0x0004
  64 +#define PORT_STAT_C_OVERCURRENT 0x0008
  65 +#define PORT_STAT_C_RESET 0x0010
  66 +
  67 +#define PORT_CONNECTION 0
  68 +#define PORT_ENABLE 1
  69 +#define PORT_SUSPEND 2
  70 +#define PORT_OVERCURRENT 3
  71 +#define PORT_RESET 4
  72 +#define PORT_POWER 8
  73 +#define PORT_LOWSPEED 9
  74 +#define PORT_HIGHSPEED 10
  75 +#define PORT_C_CONNECTION 16
  76 +#define PORT_C_ENABLE 17
  77 +#define PORT_C_SUSPEND 18
  78 +#define PORT_C_OVERCURRENT 19
  79 +#define PORT_C_RESET 20
  80 +#define PORT_TEST 21
  81 +#define PORT_INDICATOR 22
  82 +
  83 +/* same as Linux kernel root hubs */
  84 +
  85 +static const uint8_t qemu_hub_dev_descriptor[] = {
  86 + 0x12, /* u8 bLength; */
  87 + 0x01, /* u8 bDescriptorType; Device */
  88 + 0x10, 0x01, /* u16 bcdUSB; v1.1 */
  89 +
  90 + 0x09, /* u8 bDeviceClass; HUB_CLASSCODE */
  91 + 0x00, /* u8 bDeviceSubClass; */
  92 + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
  93 + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
  94 +
  95 + 0x00, 0x00, /* u16 idVendor; */
  96 + 0x00, 0x00, /* u16 idProduct; */
  97 + 0x01, 0x01, /* u16 bcdDevice */
  98 +
  99 + 0x03, /* u8 iManufacturer; */
  100 + 0x02, /* u8 iProduct; */
  101 + 0x01, /* u8 iSerialNumber; */
  102 + 0x01 /* u8 bNumConfigurations; */
  103 +};
  104 +
  105 +/* XXX: patch interrupt size */
  106 +static const uint8_t qemu_hub_config_descriptor[] = {
  107 +
  108 + /* one configuration */
  109 + 0x09, /* u8 bLength; */
  110 + 0x02, /* u8 bDescriptorType; Configuration */
  111 + 0x19, 0x00, /* u16 wTotalLength; */
  112 + 0x01, /* u8 bNumInterfaces; (1) */
  113 + 0x01, /* u8 bConfigurationValue; */
  114 + 0x00, /* u8 iConfiguration; */
  115 + 0xc0, /* u8 bmAttributes;
  116 + Bit 7: must be set,
  117 + 6: Self-powered,
  118 + 5: Remote wakeup,
  119 + 4..0: resvd */
  120 + 0x00, /* u8 MaxPower; */
  121 +
  122 + /* USB 1.1:
  123 + * USB 2.0, single TT organization (mandatory):
  124 + * one interface, protocol 0
  125 + *
  126 + * USB 2.0, multiple TT organization (optional):
  127 + * two interfaces, protocols 1 (like single TT)
  128 + * and 2 (multiple TT mode) ... config is
  129 + * sometimes settable
  130 + * NOT IMPLEMENTED
  131 + */
  132 +
  133 + /* one interface */
  134 + 0x09, /* u8 if_bLength; */
  135 + 0x04, /* u8 if_bDescriptorType; Interface */
  136 + 0x00, /* u8 if_bInterfaceNumber; */
  137 + 0x00, /* u8 if_bAlternateSetting; */
  138 + 0x01, /* u8 if_bNumEndpoints; */
  139 + 0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */
  140 + 0x00, /* u8 if_bInterfaceSubClass; */
  141 + 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
  142 + 0x00, /* u8 if_iInterface; */
  143 +
  144 + /* one endpoint (status change endpoint) */
  145 + 0x07, /* u8 ep_bLength; */
  146 + 0x05, /* u8 ep_bDescriptorType; Endpoint */
  147 + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
  148 + 0x03, /* u8 ep_bmAttributes; Interrupt */
  149 + 0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
  150 + 0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
  151 +};
  152 +
  153 +static const uint8_t qemu_hub_hub_descriptor[] =
  154 +{
  155 + 0x09, /* u8 bLength; */
  156 + 0x29, /* u8 bDescriptorType; Hub-descriptor */
  157 + 0x00, /* u8 bNbrPorts; (patched later) */
  158 + 0x0a, /* u16 wHubCharacteristics; */
  159 + 0x00, /* (per-port OC, no power switching) */
  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 *** */
  164 +};
  165 +
  166 +static void usb_hub_attach(USBPort *port1, USBDevice *dev)
  167 +{
  168 + USBHubState *s = port1->opaque;
  169 + USBHubPort *port = &s->ports[port1->index];
  170 +
  171 + if (dev) {
  172 + if (port->port.dev)
  173 + usb_attach(port1, NULL);
  174 +
  175 + port->wPortStatus |= PORT_STAT_CONNECTION;
  176 + port->wPortChange |= PORT_STAT_C_CONNECTION;
  177 + if (dev->speed == USB_SPEED_LOW)
  178 + port->wPortStatus |= PORT_STAT_LOW_SPEED;
  179 + else
  180 + port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
  181 + port->port.dev = dev;
  182 + } else {
  183 + dev = port->port.dev;
  184 + if (dev) {
  185 + port->wPortStatus &= ~PORT_STAT_CONNECTION;
  186 + port->wPortChange |= PORT_STAT_C_CONNECTION;
  187 + if (port->wPortStatus & PORT_STAT_ENABLE) {
  188 + port->wPortStatus &= ~PORT_STAT_ENABLE;
  189 + port->wPortChange |= PORT_STAT_C_ENABLE;
  190 + }
  191 + port->port.dev = NULL;
  192 + }
  193 + }
  194 +}
  195 +
  196 +static void usb_hub_handle_reset(USBDevice *dev)
  197 +{
  198 + /* XXX: do it */
  199 +}
  200 +
  201 +static int usb_hub_handle_control(USBDevice *dev, int request, int value,
  202 + int index, int length, uint8_t *data)
  203 +{
  204 + USBHubState *s = (USBHubState *)dev;
  205 + int ret;
  206 +
  207 + switch(request) {
  208 + case DeviceRequest | USB_REQ_GET_STATUS:
  209 + data[0] = (1 << USB_DEVICE_SELF_POWERED) |
  210 + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
  211 + data[1] = 0x00;
  212 + ret = 2;
  213 + break;
  214 + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
  215 + if (value == USB_DEVICE_REMOTE_WAKEUP) {
  216 + dev->remote_wakeup = 0;
  217 + } else {
  218 + goto fail;
  219 + }
  220 + ret = 0;
  221 + break;
  222 + case DeviceOutRequest | USB_REQ_SET_FEATURE:
  223 + if (value == USB_DEVICE_REMOTE_WAKEUP) {
  224 + dev->remote_wakeup = 1;
  225 + } else {
  226 + goto fail;
  227 + }
  228 + ret = 0;
  229 + break;
  230 + case DeviceOutRequest | USB_REQ_SET_ADDRESS:
  231 + dev->addr = value;
  232 + ret = 0;
  233 + break;
  234 + case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
  235 + switch(value >> 8) {
  236 + case USB_DT_DEVICE:
  237 + memcpy(data, qemu_hub_dev_descriptor,
  238 + sizeof(qemu_hub_dev_descriptor));
  239 + ret = sizeof(qemu_hub_dev_descriptor);
  240 + break;
  241 + case USB_DT_CONFIG:
  242 + memcpy(data, qemu_hub_config_descriptor,
  243 + sizeof(qemu_hub_config_descriptor));
  244 + ret = sizeof(qemu_hub_config_descriptor);
  245 + break;
  246 + case USB_DT_STRING:
  247 + switch(value & 0xff) {
  248 + case 0:
  249 + /* language ids */
  250 + data[0] = 4;
  251 + data[1] = 3;
  252 + data[2] = 0x09;
  253 + data[3] = 0x04;
  254 + ret = 4;
  255 + break;
  256 + case 1:
  257 + /* serial number */
  258 + ret = set_usb_string(data, "314159");
  259 + break;
  260 + case 2:
  261 + /* product description */
  262 + ret = set_usb_string(data, "QEMU USB Hub");
  263 + break;
  264 + case 3:
  265 + /* vendor description */
  266 + ret = set_usb_string(data, "QEMU " QEMU_VERSION);
  267 + break;
  268 + default:
  269 + goto fail;
  270 + }
  271 + break;
  272 + default:
  273 + goto fail;
  274 + }
  275 + break;
  276 + case DeviceRequest | USB_REQ_GET_CONFIGURATION:
  277 + data[0] = 1;
  278 + ret = 1;
  279 + break;
  280 + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
  281 + ret = 0;
  282 + break;
  283 + case DeviceRequest | USB_REQ_GET_INTERFACE:
  284 + data[0] = 0;
  285 + ret = 1;
  286 + break;
  287 + case DeviceOutRequest | USB_REQ_SET_INTERFACE:
  288 + ret = 0;
  289 + break;
  290 + /* usb specific requests */
  291 + case GetHubStatus:
  292 + data[0] = 0;
  293 + data[1] = 0;
  294 + data[2] = 0;
  295 + data[3] = 0;
  296 + ret = 4;
  297 + break;
  298 + case GetPortStatus:
  299 + {
  300 + unsigned int n = index - 1;
  301 + USBHubPort *port;
  302 + if (n >= s->nb_ports)
  303 + goto fail;
  304 + port = &s->ports[n];
  305 + data[0] = port->wPortStatus;
  306 + data[1] = port->wPortStatus >> 8;
  307 + data[2] = port->wPortChange;
  308 + data[3] = port->wPortChange >> 8;
  309 + ret = 4;
  310 + }
  311 + break;
  312 + case SetHubFeature:
  313 + case ClearHubFeature:
  314 + if (value == 0 || value == 1) {
  315 + } else {
  316 + goto fail;
  317 + }
  318 + ret = 0;
  319 + break;
  320 + case SetPortFeature:
  321 + {
  322 + unsigned int n = index - 1;
  323 + USBHubPort *port;
  324 + USBDevice *dev;
  325 + if (n >= s->nb_ports)
  326 + goto fail;
  327 + port = &s->ports[n];
  328 + dev = port->port.dev;
  329 + switch(value) {
  330 + case PORT_SUSPEND:
  331 + port->wPortStatus |= PORT_STAT_SUSPEND;
  332 + break;
  333 + case PORT_RESET:
  334 + if (dev) {
  335 + dev->handle_packet(dev,
  336 + USB_MSG_RESET, 0, 0, NULL, 0);
  337 + port->wPortChange |= PORT_STAT_C_RESET;
  338 + /* set enable bit */
  339 + port->wPortChange |= PORT_STAT_C_ENABLE;
  340 + port->wPortStatus |= PORT_STAT_ENABLE;
  341 + }
  342 + break;
  343 + case PORT_POWER:
  344 + break;
  345 + default:
  346 + goto fail;
  347 + }
  348 + ret = 0;
  349 + }
  350 + break;
  351 + case ClearPortFeature:
  352 + {
  353 + unsigned int n = index - 1;
  354 + USBHubPort *port;
  355 + USBDevice *dev;
  356 + if (n >= s->nb_ports)
  357 + goto fail;
  358 + port = &s->ports[n];
  359 + dev = port->port.dev;
  360 + switch(value) {
  361 + case PORT_ENABLE:
  362 + port->wPortStatus &= ~PORT_STAT_ENABLE;
  363 + break;
  364 + case PORT_C_ENABLE:
  365 + port->wPortChange &= ~PORT_STAT_C_ENABLE;
  366 + break;
  367 + case PORT_SUSPEND:
  368 + port->wPortStatus &= ~PORT_STAT_SUSPEND;
  369 + break;
  370 + case PORT_C_SUSPEND:
  371 + port->wPortChange &= ~PORT_STAT_C_SUSPEND;
  372 + break;
  373 + case PORT_C_CONNECTION:
  374 + port->wPortChange &= ~PORT_STAT_C_CONNECTION;
  375 + break;
  376 + case PORT_C_OVERCURRENT:
  377 + port->wPortChange &= ~PORT_STAT_C_OVERCURRENT;
  378 + break;
  379 + case PORT_C_RESET:
  380 + port->wPortChange &= ~PORT_STAT_C_RESET;
  381 + break;
  382 + default:
  383 + goto fail;
  384 + }
  385 + ret = 0;
  386 + }
  387 + break;
  388 + case GetHubDescriptor:
  389 + memcpy(data, qemu_hub_hub_descriptor,
  390 + sizeof(qemu_hub_hub_descriptor));
  391 + data[2] = s->nb_ports;
  392 + ret = sizeof(qemu_hub_hub_descriptor);
  393 + break;
  394 + default:
  395 + fail:
  396 + ret = USB_RET_STALL;
  397 + break;
  398 + }
  399 + return ret;
  400 +}
  401 +
  402 +static int usb_hub_handle_data(USBDevice *dev, int pid,
  403 + uint8_t devep, uint8_t *data, int len)
  404 +{
  405 + USBHubState *s = (USBHubState *)dev;
  406 + int ret;
  407 +
  408 + switch(pid) {
  409 + case USB_TOKEN_IN:
  410 + if (devep == 1) {
  411 + USBHubPort *port;
  412 + unsigned int status;
  413 + int i, n;
  414 + n = (s->nb_ports + 1 + 7) / 8;
  415 + if (n > len)
  416 + return USB_RET_BABBLE;
  417 + status = 0;
  418 + for(i = 0; i < s->nb_ports; i++) {
  419 + port = &s->ports[i];
  420 + if (port->wPortChange)
  421 + status |= (1 << (i + 1));
  422 + }
  423 + if (status != 0) {
  424 + for(i = 0; i < n; i++) {
  425 + data[i] = status >> (8 * i);
  426 + }
  427 + ret = n;
  428 + } else {
  429 + ret = 0;
  430 + }
  431 + } else {
  432 + goto fail;
  433 + }
  434 + break;
  435 + case USB_TOKEN_OUT:
  436 + default:
  437 + fail:
  438 + ret = USB_RET_STALL;
  439 + break;
  440 + }
  441 + return ret;
  442 +}
  443 +
  444 +static int usb_hub_broadcast_packet(USBHubState *s, int pid,
  445 + uint8_t devaddr, uint8_t devep,
  446 + uint8_t *data, int len)
  447 +{
  448 + USBHubPort *port;
  449 + USBDevice *dev;
  450 + int i, ret;
  451 +
  452 + for(i = 0; i < s->nb_ports; i++) {
  453 + port = &s->ports[i];
  454 + dev = port->port.dev;
  455 + if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
  456 + ret = dev->handle_packet(dev, pid,
  457 + devaddr, devep,
  458 + data, len);
  459 + if (ret != USB_RET_NODEV) {
  460 + return ret;
  461 + }
  462 + }
  463 + }
  464 + return USB_RET_NODEV;
  465 +}
  466 +
  467 +static int usb_hub_handle_packet(USBDevice *dev, int pid,
  468 + uint8_t devaddr, uint8_t devep,
  469 + uint8_t *data, int len)
  470 +{
  471 + USBHubState *s = (USBHubState *)dev;
  472 +
  473 +#if defined(DEBUG) && 0
  474 + printf("usb_hub: pid=0x%x\n", pid);
  475 +#endif
  476 + if (dev->state == USB_STATE_DEFAULT &&
  477 + dev->addr != 0 &&
  478 + devaddr != dev->addr &&
  479 + (pid == USB_TOKEN_SETUP ||
  480 + pid == USB_TOKEN_OUT ||
  481 + pid == USB_TOKEN_IN)) {
  482 + /* broadcast the packet to the devices */
  483 + return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len);
  484 + }
  485 + return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len);
  486 +}
  487 +
  488 +USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports)
  489 +{
  490 + USBHubState *s;
  491 + USBHubPort *port;
  492 + int i;
  493 +
  494 + if (nb_ports > MAX_PORTS)
  495 + return NULL;
  496 + s = qemu_mallocz(sizeof(USBHubState));
  497 + if (!s)
  498 + return NULL;
  499 + s->dev.speed = USB_SPEED_FULL;
  500 + s->dev.handle_packet = usb_hub_handle_packet;
  501 +
  502 + /* generic USB device init */
  503 + s->dev.handle_reset = usb_hub_handle_reset;
  504 + s->dev.handle_control = usb_hub_handle_control;
  505 + s->dev.handle_data = usb_hub_handle_data;
  506 +
  507 + s->nb_ports = nb_ports;
  508 + for(i = 0; i < s->nb_ports; i++) {
  509 + port = &s->ports[i];
  510 + port->wPortStatus = PORT_STAT_POWER;
  511 + port->wPortChange = 0;
  512 + port->port.attach = usb_hub_attach;
  513 + port->port.opaque = s;
  514 + port->port.index = i;
  515 + usb_ports[i] = &port->port;
  516 + }
  517 + return (USBDevice *)s;
  518 +}
... ...
hw/usb.c
... ... @@ -191,500 +191,3 @@ int set_usb_string(uint8_t *buf, const char *str)
191 191 }
192 192 return q - buf;
193 193 }
194   -
195   -/**********************/
196   -/* USB hub emulation */
197   -
198   -//#define DEBUG
199   -
200   -#define MAX_PORTS 8
201   -
202   -typedef struct USBHubPort {
203   - USBPort port;
204   - uint16_t wPortStatus;
205   - uint16_t wPortChange;
206   -} USBHubPort;
207   -
208   -typedef struct USBHubState {
209   - USBDevice dev;
210   - int nb_ports;
211   - USBHubPort ports[MAX_PORTS];
212   -} USBHubState;
213   -
214   -#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE)
215   -#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE)
216   -#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR)
217   -#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS)
218   -#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS)
219   -#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE)
220   -#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE)
221   -
222   -#define PORT_STAT_CONNECTION 0x0001
223   -#define PORT_STAT_ENABLE 0x0002
224   -#define PORT_STAT_SUSPEND 0x0004
225   -#define PORT_STAT_OVERCURRENT 0x0008
226   -#define PORT_STAT_RESET 0x0010
227   -#define PORT_STAT_POWER 0x0100
228   -#define PORT_STAT_LOW_SPEED 0x0200
229   -#define PORT_STAT_HIGH_SPEED 0x0400
230   -#define PORT_STAT_TEST 0x0800
231   -#define PORT_STAT_INDICATOR 0x1000
232   -
233   -#define PORT_STAT_C_CONNECTION 0x0001
234   -#define PORT_STAT_C_ENABLE 0x0002
235   -#define PORT_STAT_C_SUSPEND 0x0004
236   -#define PORT_STAT_C_OVERCURRENT 0x0008
237   -#define PORT_STAT_C_RESET 0x0010
238   -
239   -#define PORT_CONNECTION 0
240   -#define PORT_ENABLE 1
241   -#define PORT_SUSPEND 2
242   -#define PORT_OVERCURRENT 3
243   -#define PORT_RESET 4
244   -#define PORT_POWER 8
245   -#define PORT_LOWSPEED 9
246   -#define PORT_HIGHSPEED 10
247   -#define PORT_C_CONNECTION 16
248   -#define PORT_C_ENABLE 17
249   -#define PORT_C_SUSPEND 18
250   -#define PORT_C_OVERCURRENT 19
251   -#define PORT_C_RESET 20
252   -#define PORT_TEST 21
253   -#define PORT_INDICATOR 22
254   -
255   -/* same as Linux kernel root hubs */
256   -
257   -static const uint8_t qemu_hub_dev_descriptor[] = {
258   - 0x12, /* u8 bLength; */
259   - 0x01, /* u8 bDescriptorType; Device */
260   - 0x10, 0x01, /* u16 bcdUSB; v1.1 */
261   -
262   - 0x09, /* u8 bDeviceClass; HUB_CLASSCODE */
263   - 0x00, /* u8 bDeviceSubClass; */
264   - 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
265   - 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
266   -
267   - 0x00, 0x00, /* u16 idVendor; */
268   - 0x00, 0x00, /* u16 idProduct; */
269   - 0x01, 0x01, /* u16 bcdDevice */
270   -
271   - 0x03, /* u8 iManufacturer; */
272   - 0x02, /* u8 iProduct; */
273   - 0x01, /* u8 iSerialNumber; */
274   - 0x01 /* u8 bNumConfigurations; */
275   -};
276   -
277   -/* XXX: patch interrupt size */
278   -static const uint8_t qemu_hub_config_descriptor[] = {
279   -
280   - /* one configuration */
281   - 0x09, /* u8 bLength; */
282   - 0x02, /* u8 bDescriptorType; Configuration */
283   - 0x19, 0x00, /* u16 wTotalLength; */
284   - 0x01, /* u8 bNumInterfaces; (1) */
285   - 0x01, /* u8 bConfigurationValue; */
286   - 0x00, /* u8 iConfiguration; */
287   - 0xc0, /* u8 bmAttributes;
288   - Bit 7: must be set,
289   - 6: Self-powered,
290   - 5: Remote wakeup,
291   - 4..0: resvd */
292   - 0x00, /* u8 MaxPower; */
293   -
294   - /* USB 1.1:
295   - * USB 2.0, single TT organization (mandatory):
296   - * one interface, protocol 0
297   - *
298   - * USB 2.0, multiple TT organization (optional):
299   - * two interfaces, protocols 1 (like single TT)
300   - * and 2 (multiple TT mode) ... config is
301   - * sometimes settable
302   - * NOT IMPLEMENTED
303   - */
304   -
305   - /* one interface */
306   - 0x09, /* u8 if_bLength; */
307   - 0x04, /* u8 if_bDescriptorType; Interface */
308   - 0x00, /* u8 if_bInterfaceNumber; */
309   - 0x00, /* u8 if_bAlternateSetting; */
310   - 0x01, /* u8 if_bNumEndpoints; */
311   - 0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */
312   - 0x00, /* u8 if_bInterfaceSubClass; */
313   - 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
314   - 0x00, /* u8 if_iInterface; */
315   -
316   - /* one endpoint (status change endpoint) */
317   - 0x07, /* u8 ep_bLength; */
318   - 0x05, /* u8 ep_bDescriptorType; Endpoint */
319   - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
320   - 0x03, /* u8 ep_bmAttributes; Interrupt */
321   - 0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
322   - 0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
323   -};
324   -
325   -static const uint8_t qemu_hub_hub_descriptor[] =
326   -{
327   - 0x09, /* u8 bLength; */
328   - 0x29, /* u8 bDescriptorType; Hub-descriptor */
329   - 0x00, /* u8 bNbrPorts; (patched later) */
330   - 0x0a, /* u16 wHubCharacteristics; */
331   - 0x00, /* (per-port OC, no power switching) */
332   - 0x01, /* u8 bPwrOn2pwrGood; 2ms */
333   - 0x00, /* u8 bHubContrCurrent; 0 mA */
334   - 0x00, /* u8 DeviceRemovable; *** 7 Ports max *** */
335   - 0xff /* u8 PortPwrCtrlMask; *** 7 ports max *** */
336   -};
337   -
338   -static void usb_hub_attach(USBPort *port1, USBDevice *dev)
339   -{
340   - USBHubState *s = port1->opaque;
341   - USBHubPort *port = &s->ports[port1->index];
342   -
343   - if (dev) {
344   - if (port->port.dev)
345   - usb_attach(port1, NULL);
346   -
347   - port->wPortStatus |= PORT_STAT_CONNECTION;
348   - port->wPortChange |= PORT_STAT_C_CONNECTION;
349   - if (dev->speed == USB_SPEED_LOW)
350   - port->wPortStatus |= PORT_STAT_LOW_SPEED;
351   - else
352   - port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
353   - port->port.dev = dev;
354   - } else {
355   - dev = port->port.dev;
356   - if (dev) {
357   - port->wPortStatus &= ~PORT_STAT_CONNECTION;
358   - port->wPortChange |= PORT_STAT_C_CONNECTION;
359   - if (port->wPortStatus & PORT_STAT_ENABLE) {
360   - port->wPortStatus &= ~PORT_STAT_ENABLE;
361   - port->wPortChange |= PORT_STAT_C_ENABLE;
362   - }
363   - port->port.dev = NULL;
364   - }
365   - }
366   -}
367   -
368   -static void usb_hub_handle_reset(USBDevice *dev)
369   -{
370   - /* XXX: do it */
371   -}
372   -
373   -static int usb_hub_handle_control(USBDevice *dev, int request, int value,
374   - int index, int length, uint8_t *data)
375   -{
376   - USBHubState *s = (USBHubState *)dev;
377   - int ret;
378   -
379   - switch(request) {
380   - case DeviceRequest | USB_REQ_GET_STATUS:
381   - data[0] = (1 << USB_DEVICE_SELF_POWERED) |
382   - (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
383   - data[1] = 0x00;
384   - ret = 2;
385   - break;
386   - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
387   - if (value == USB_DEVICE_REMOTE_WAKEUP) {
388   - dev->remote_wakeup = 0;
389   - } else {
390   - goto fail;
391   - }
392   - ret = 0;
393   - break;
394   - case DeviceOutRequest | USB_REQ_SET_FEATURE:
395   - if (value == USB_DEVICE_REMOTE_WAKEUP) {
396   - dev->remote_wakeup = 1;
397   - } else {
398   - goto fail;
399   - }
400   - ret = 0;
401   - break;
402   - case DeviceOutRequest | USB_REQ_SET_ADDRESS:
403   - dev->addr = value;
404   - ret = 0;
405   - break;
406   - case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
407   - switch(value >> 8) {
408   - case USB_DT_DEVICE:
409   - memcpy(data, qemu_hub_dev_descriptor,
410   - sizeof(qemu_hub_dev_descriptor));
411   - ret = sizeof(qemu_hub_dev_descriptor);
412   - break;
413   - case USB_DT_CONFIG:
414   - memcpy(data, qemu_hub_config_descriptor,
415   - sizeof(qemu_hub_config_descriptor));
416   - ret = sizeof(qemu_hub_config_descriptor);
417   - break;
418   - case USB_DT_STRING:
419   - switch(value & 0xff) {
420   - case 0:
421   - /* language ids */
422   - data[0] = 4;
423   - data[1] = 3;
424   - data[2] = 0x09;
425   - data[3] = 0x04;
426   - ret = 4;
427   - break;
428   - case 1:
429   - /* serial number */
430   - ret = set_usb_string(data, "314159");
431   - break;
432   - case 2:
433   - /* product description */
434   - ret = set_usb_string(data, "QEMU USB Hub");
435   - break;
436   - case 3:
437   - /* vendor description */
438   - ret = set_usb_string(data, "QEMU " QEMU_VERSION);
439   - break;
440   - default:
441   - goto fail;
442   - }
443   - break;
444   - default:
445   - goto fail;
446   - }
447   - break;
448   - case DeviceRequest | USB_REQ_GET_CONFIGURATION:
449   - data[0] = 1;
450   - ret = 1;
451   - break;
452   - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
453   - ret = 0;
454   - break;
455   - case DeviceRequest | USB_REQ_GET_INTERFACE:
456   - data[0] = 0;
457   - ret = 1;
458   - break;
459   - case DeviceOutRequest | USB_REQ_SET_INTERFACE:
460   - ret = 0;
461   - break;
462   - /* usb specific requests */
463   - case GetHubStatus:
464   - data[0] = 0;
465   - data[1] = 0;
466   - data[2] = 0;
467   - data[3] = 0;
468   - ret = 4;
469   - break;
470   - case GetPortStatus:
471   - {
472   - unsigned int n = index - 1;
473   - USBHubPort *port;
474   - if (n >= s->nb_ports)
475   - goto fail;
476   - port = &s->ports[n];
477   - data[0] = port->wPortStatus;
478   - data[1] = port->wPortStatus >> 8;
479   - data[2] = port->wPortChange;
480   - data[3] = port->wPortChange >> 8;
481   - ret = 4;
482   - }
483   - break;
484   - case SetHubFeature:
485   - case ClearHubFeature:
486   - if (value == 0 || value == 1) {
487   - } else {
488   - goto fail;
489   - }
490   - ret = 0;
491   - break;
492   - case SetPortFeature:
493   - {
494   - unsigned int n = index - 1;
495   - USBHubPort *port;
496   - USBDevice *dev;
497   - if (n >= s->nb_ports)
498   - goto fail;
499   - port = &s->ports[n];
500   - dev = port->port.dev;
501   - switch(value) {
502   - case PORT_SUSPEND:
503   - port->wPortStatus |= PORT_STAT_SUSPEND;
504   - break;
505   - case PORT_RESET:
506   - if (dev) {
507   - dev->handle_packet(dev,
508   - USB_MSG_RESET, 0, 0, NULL, 0);
509   - port->wPortChange |= PORT_STAT_C_RESET;
510   - /* set enable bit */
511   - port->wPortChange |= PORT_STAT_C_ENABLE;
512   - port->wPortStatus |= PORT_STAT_ENABLE;
513   - }
514   - break;
515   - case PORT_POWER:
516   - break;
517   - default:
518   - goto fail;
519   - }
520   - ret = 0;
521   - }
522   - break;
523   - case ClearPortFeature:
524   - {
525   - unsigned int n = index - 1;
526   - USBHubPort *port;
527   - USBDevice *dev;
528   - if (n >= s->nb_ports)
529   - goto fail;
530   - port = &s->ports[n];
531   - dev = port->port.dev;
532   - switch(value) {
533   - case PORT_ENABLE:
534   - port->wPortStatus &= ~PORT_STAT_ENABLE;
535   - break;
536   - case PORT_C_ENABLE:
537   - port->wPortChange &= ~PORT_STAT_C_ENABLE;
538   - break;
539   - case PORT_SUSPEND:
540   - port->wPortStatus &= ~PORT_STAT_SUSPEND;
541   - break;
542   - case PORT_C_SUSPEND:
543   - port->wPortChange &= ~PORT_STAT_C_SUSPEND;
544   - break;
545   - case PORT_C_CONNECTION:
546   - port->wPortChange &= ~PORT_STAT_C_CONNECTION;
547   - break;
548   - case PORT_C_OVERCURRENT:
549   - port->wPortChange &= ~PORT_STAT_C_OVERCURRENT;
550   - break;
551   - case PORT_C_RESET:
552   - port->wPortChange &= ~PORT_STAT_C_RESET;
553   - break;
554   - default:
555   - goto fail;
556   - }
557   - ret = 0;
558   - }
559   - break;
560   - case GetHubDescriptor:
561   - memcpy(data, qemu_hub_hub_descriptor,
562   - sizeof(qemu_hub_hub_descriptor));
563   - data[2] = s->nb_ports;
564   - ret = sizeof(qemu_hub_hub_descriptor);
565   - break;
566   - default:
567   - fail:
568   - ret = USB_RET_STALL;
569   - break;
570   - }
571   - return ret;
572   -}
573   -
574   -static int usb_hub_handle_data(USBDevice *dev, int pid,
575   - uint8_t devep, uint8_t *data, int len)
576   -{
577   - USBHubState *s = (USBHubState *)dev;
578   - int ret;
579   -
580   - switch(pid) {
581   - case USB_TOKEN_IN:
582   - if (devep == 1) {
583   - USBHubPort *port;
584   - unsigned int status;
585   - int i, n;
586   - n = (s->nb_ports + 1 + 7) / 8;
587   - if (n > len)
588   - return USB_RET_BABBLE;
589   - status = 0;
590   - for(i = 0; i < s->nb_ports; i++) {
591   - port = &s->ports[i];
592   - if (port->wPortChange)
593   - status |= (1 << (i + 1));
594   - }
595   - if (status != 0) {
596   - for(i = 0; i < n; i++) {
597   - data[i] = status >> (8 * i);
598   - }
599   - ret = n;
600   - } else {
601   - ret = 0;
602   - }
603   - } else {
604   - goto fail;
605   - }
606   - break;
607   - case USB_TOKEN_OUT:
608   - default:
609   - fail:
610   - ret = USB_RET_STALL;
611   - break;
612   - }
613   - return ret;
614   -}
615   -
616   -static int usb_hub_broadcast_packet(USBHubState *s, int pid,
617   - uint8_t devaddr, uint8_t devep,
618   - uint8_t *data, int len)
619   -{
620   - USBHubPort *port;
621   - USBDevice *dev;
622   - int i, ret;
623   -
624   - for(i = 0; i < s->nb_ports; i++) {
625   - port = &s->ports[i];
626   - dev = port->port.dev;
627   - if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
628   - ret = dev->handle_packet(dev, pid,
629   - devaddr, devep,
630   - data, len);
631   - if (ret != USB_RET_NODEV) {
632   - return ret;
633   - }
634   - }
635   - }
636   - return USB_RET_NODEV;
637   -}
638   -
639   -static int usb_hub_handle_packet(USBDevice *dev, int pid,
640   - uint8_t devaddr, uint8_t devep,
641   - uint8_t *data, int len)
642   -{
643   - USBHubState *s = (USBHubState *)dev;
644   -
645   -#if defined(DEBUG) && 0
646   - printf("usb_hub: pid=0x%x\n", pid);
647   -#endif
648   - if (dev->state == USB_STATE_DEFAULT &&
649   - dev->addr != 0 &&
650   - devaddr != dev->addr &&
651   - (pid == USB_TOKEN_SETUP ||
652   - pid == USB_TOKEN_OUT ||
653   - pid == USB_TOKEN_IN)) {
654   - /* broadcast the packet to the devices */
655   - return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len);
656   - }
657   - return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len);
658   -}
659   -
660   -USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports)
661   -{
662   - USBHubState *s;
663   - USBHubPort *port;
664   - int i;
665   -
666   - if (nb_ports > MAX_PORTS)
667   - return NULL;
668   - s = qemu_mallocz(sizeof(USBHubState));
669   - if (!s)
670   - return NULL;
671   - s->dev.speed = USB_SPEED_FULL;
672   - s->dev.handle_packet = usb_hub_handle_packet;
673   -
674   - /* generic USB device init */
675   - s->dev.handle_reset = usb_hub_handle_reset;
676   - s->dev.handle_control = usb_hub_handle_control;
677   - s->dev.handle_data = usb_hub_handle_data;
678   -
679   - s->nb_ports = nb_ports;
680   - for(i = 0; i < s->nb_ports; i++) {
681   - port = &s->ports[i];
682   - port->wPortStatus = PORT_STAT_POWER;
683   - port->wPortChange = 0;
684   - port->port.attach = usb_hub_attach;
685   - port->port.opaque = s;
686   - port->port.index = i;
687   - usb_ports[i] = &port->port;
688   - }
689   - return (USBDevice *)s;
690   -}
... ...