Commit bb36d4708bc93874af95db54da2a9cee0d30a84d

Authored by bellard
1 parent 1aff381f

initial USB support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1597 c046a42c-6fe2-441c-8c8c-71466251a162
Changelog
... ... @@ -6,6 +6,7 @@ version 0.7.3:
6 6 - ALSA audio driver (malc)
7 7 - new audio options: '-soundhw' and '-audio-help' (malc)
8 8 - ES1370 PCI audio device (malc)
  9 + - Initial USB support
9 10  
10 11 version 0.7.2:
11 12  
... ...
Makefile.target
... ... @@ -294,7 +294,7 @@ ifeq ($(TARGET_BASE_ARCH), i386)
294 294 # Hardware support
295 295 VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
296 296 VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
297   -VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o
  297 +VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o usb.o usb-uhci.o usb-linux.o
298 298 DEFINES += -DHAS_AUDIO
299 299 endif
300 300 ifeq ($(TARGET_BASE_ARCH), ppc)
... ...
... ... @@ -620,6 +620,28 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
620 620  
621 621 cmos_init(ram_size, boot_device, bs_table);
622 622  
  623 + if (pci_enabled && usb_enabled) {
  624 + USBPort *usb_root_ports[2];
  625 + USBDevice *usb_hub;
  626 + usb_uhci_init(pci_bus, usb_root_ports);
  627 +#if 0
  628 + {
  629 + USBPort *usb_hub1_ports[4];
  630 + USBPort *usb_hub2_ports[2];
  631 + /* test: we simulate a USB hub */
  632 + usb_hub = usb_hub_init(usb_hub1_ports, 4);
  633 + usb_attach(usb_root_ports[0], usb_hub);
  634 +
  635 + /* test: we simulate a USB hub */
  636 + usb_hub = usb_hub_init(usb_hub2_ports, 2);
  637 + usb_attach(usb_hub1_ports[0], usb_hub);
  638 + }
  639 +#endif
  640 + /* simulated hub with the host USB devices connected to it */
  641 + usb_hub = usb_host_hub_init();
  642 + usb_attach(usb_root_ports[0], usb_hub);
  643 + }
  644 +
623 645 /* must be done after all PCI devices are instanciated */
624 646 /* XXX: should be done in the Bochs BIOS */
625 647 if (pci_enabled) {
... ...
hw/usb-uhci.c 0 → 100644
  1 +/*
  2 + * USB UHCI controller 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 +//#define DEBUG_PACKET
  28 +
  29 +#define UHCI_CMD_GRESET (1 << 2)
  30 +#define UHCI_CMD_HCRESET (1 << 1)
  31 +#define UHCI_CMD_RS (1 << 0)
  32 +
  33 +#define UHCI_STS_HCHALTED (1 << 5)
  34 +#define UHCI_STS_HCPERR (1 << 4)
  35 +#define UHCI_STS_HSERR (1 << 3)
  36 +#define UHCI_STS_RD (1 << 2)
  37 +#define UHCI_STS_USBERR (1 << 1)
  38 +#define UHCI_STS_USBINT (1 << 0)
  39 +
  40 +#define TD_CTRL_SPD (1 << 29)
  41 +#define TD_CTRL_ERROR_SHIFT 27
  42 +#define TD_CTRL_IOS (1 << 25)
  43 +#define TD_CTRL_IOC (1 << 24)
  44 +#define TD_CTRL_ACTIVE (1 << 23)
  45 +#define TD_CTRL_STALL (1 << 22)
  46 +#define TD_CTRL_BABBLE (1 << 20)
  47 +#define TD_CTRL_NAK (1 << 19)
  48 +#define TD_CTRL_TIMEOUT (1 << 18)
  49 +
  50 +#define UHCI_PORT_RESET (1 << 9)
  51 +#define UHCI_PORT_LSDA (1 << 8)
  52 +#define UHCI_PORT_ENC (1 << 3)
  53 +#define UHCI_PORT_EN (1 << 2)
  54 +#define UHCI_PORT_CSC (1 << 1)
  55 +#define UHCI_PORT_CCS (1 << 0)
  56 +
  57 +#define FRAME_TIMER_FREQ 1000
  58 +
  59 +#define FRAME_MAX_LOOPS 100
  60 +
  61 +#define NB_PORTS 2
  62 +
  63 +typedef struct UHCIPort {
  64 + USBPort port;
  65 + uint16_t ctrl;
  66 + USBDevice *dev; /* connected device */
  67 +} UHCIPort;
  68 +
  69 +typedef struct UHCIState {
  70 + PCIDevice dev;
  71 + uint16_t cmd; /* cmd register */
  72 + uint16_t status;
  73 + uint16_t intr; /* interrupt enable register */
  74 + uint16_t frnum; /* frame number */
  75 + uint32_t fl_base_addr; /* frame list base address */
  76 + uint8_t sof_timing;
  77 + uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */
  78 + QEMUTimer *frame_timer;
  79 + UHCIPort ports[NB_PORTS];
  80 +} UHCIState;
  81 +
  82 +typedef struct UHCI_TD {
  83 + uint32_t link;
  84 + uint32_t ctrl; /* see TD_CTRL_xxx */
  85 + uint32_t token;
  86 + uint32_t buffer;
  87 +} UHCI_TD;
  88 +
  89 +typedef struct UHCI_QH {
  90 + uint32_t link;
  91 + uint32_t el_link;
  92 +} UHCI_QH;
  93 +
  94 +static void uhci_attach(USBPort *port1, USBDevice *dev);
  95 +
  96 +static void uhci_update_irq(UHCIState *s)
  97 +{
  98 + int level;
  99 + if (((s->status2 & 1) && (s->intr & (1 << 2))) ||
  100 + ((s->status2 & 2) && (s->intr & (1 << 3))) ||
  101 + ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) ||
  102 + ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) ||
  103 + (s->status & UHCI_STS_HSERR) ||
  104 + (s->status & UHCI_STS_HCPERR)) {
  105 + level = 1;
  106 + } else {
  107 + level = 0;
  108 + }
  109 + pci_set_irq(&s->dev, 0, level);
  110 +}
  111 +
  112 +static void uhci_reset(UHCIState *s)
  113 +{
  114 + uint8_t *pci_conf;
  115 + int i;
  116 + UHCIPort *port;
  117 +
  118 + pci_conf = s->dev.config;
  119 +
  120 + pci_conf[0x6a] = 0x01; /* usb clock */
  121 + pci_conf[0x6b] = 0x00;
  122 + s->cmd = 0;
  123 + s->status = 0;
  124 + s->status2 = 0;
  125 + s->intr = 0;
  126 + s->fl_base_addr = 0;
  127 + s->sof_timing = 64;
  128 + for(i = 0; i < NB_PORTS; i++) {
  129 + port = &s->ports[i];
  130 + port->ctrl = 0x0080;
  131 + if (port->dev)
  132 + uhci_attach(&port->port, port->dev);
  133 + }
  134 +}
  135 +
  136 +static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
  137 +{
  138 + UHCIState *s = opaque;
  139 +
  140 + addr &= 0x1f;
  141 + switch(addr) {
  142 + case 0x0c:
  143 + s->sof_timing = val;
  144 + break;
  145 + }
  146 +}
  147 +
  148 +static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr)
  149 +{
  150 + UHCIState *s = opaque;
  151 + uint32_t val;
  152 +
  153 + addr &= 0x1f;
  154 + switch(addr) {
  155 + case 0x0c:
  156 + val = s->sof_timing;
  157 + default:
  158 + val = 0xff;
  159 + break;
  160 + }
  161 + return val;
  162 +}
  163 +
  164 +static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
  165 +{
  166 + UHCIState *s = opaque;
  167 +
  168 + addr &= 0x1f;
  169 +#ifdef DEBUG
  170 + printf("uhci writew port=0x%04x val=0x%04x\n", addr, val);
  171 +#endif
  172 + switch(addr) {
  173 + case 0x00:
  174 + if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
  175 + /* start frame processing */
  176 + qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock));
  177 + }
  178 + if (val & UHCI_CMD_GRESET) {
  179 + UHCIPort *port;
  180 + USBDevice *dev;
  181 + int i;
  182 +
  183 + /* send reset on the USB bus */
  184 + for(i = 0; i < NB_PORTS; i++) {
  185 + port = &s->ports[i];
  186 + dev = port->dev;
  187 + if (dev) {
  188 + dev->handle_packet(dev,
  189 + USB_MSG_RESET, 0, 0, NULL, 0);
  190 + }
  191 + }
  192 + uhci_reset(s);
  193 + return;
  194 + }
  195 + if (val & UHCI_CMD_GRESET) {
  196 + uhci_reset(s);
  197 + return;
  198 + }
  199 + s->cmd = val;
  200 + break;
  201 + case 0x02:
  202 + s->status &= ~val;
  203 + /* XXX: the chip spec is not coherent, so we add a hidden
  204 + register to distinguish between IOC and SPD */
  205 + if (val & UHCI_STS_USBINT)
  206 + s->status2 = 0;
  207 + uhci_update_irq(s);
  208 + break;
  209 + case 0x04:
  210 + s->intr = val;
  211 + uhci_update_irq(s);
  212 + break;
  213 + case 0x06:
  214 + if (s->status & UHCI_STS_HCHALTED)
  215 + s->frnum = val & 0x7ff;
  216 + break;
  217 + case 0x10 ... 0x1f:
  218 + {
  219 + UHCIPort *port;
  220 + USBDevice *dev;
  221 + int n;
  222 +
  223 + n = (addr >> 1) & 7;
  224 + if (n >= NB_PORTS)
  225 + return;
  226 + port = &s->ports[n];
  227 + dev = port->dev;
  228 + if (dev) {
  229 + /* port reset */
  230 + if ( (val & UHCI_PORT_RESET) &&
  231 + !(port->ctrl & UHCI_PORT_RESET) ) {
  232 + dev->handle_packet(dev,
  233 + USB_MSG_RESET, 0, 0, NULL, 0);
  234 + }
  235 + }
  236 + port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb);
  237 + /* some bits are reset when a '1' is written to them */
  238 + port->ctrl &= ~(val & 0x000a);
  239 + }
  240 + break;
  241 + }
  242 +}
  243 +
  244 +static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr)
  245 +{
  246 + UHCIState *s = opaque;
  247 + uint32_t val;
  248 +
  249 + addr &= 0x1f;
  250 + switch(addr) {
  251 + case 0x00:
  252 + val = s->cmd;
  253 + break;
  254 + case 0x02:
  255 + val = s->status;
  256 + break;
  257 + case 0x04:
  258 + val = s->intr;
  259 + break;
  260 + case 0x06:
  261 + val = s->frnum;
  262 + break;
  263 + case 0x10 ... 0x1f:
  264 + {
  265 + UHCIPort *port;
  266 + int n;
  267 + n = (addr >> 1) & 7;
  268 + if (n >= NB_PORTS)
  269 + goto read_default;
  270 + port = &s->ports[n];
  271 + val = port->ctrl;
  272 + }
  273 + break;
  274 + default:
  275 + read_default:
  276 + val = 0xff7f; /* disabled port */
  277 + break;
  278 + }
  279 +#ifdef DEBUG
  280 + printf("uhci readw port=0x%04x val=0x%04x\n", addr, val);
  281 +#endif
  282 + return val;
  283 +}
  284 +
  285 +static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
  286 +{
  287 + UHCIState *s = opaque;
  288 +
  289 + addr &= 0x1f;
  290 +#ifdef DEBUG
  291 + printf("uhci writel port=0x%04x val=0x%08x\n", addr, val);
  292 +#endif
  293 + switch(addr) {
  294 + case 0x08:
  295 + s->fl_base_addr = val & ~0xfff;
  296 + break;
  297 + }
  298 +}
  299 +
  300 +static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr)
  301 +{
  302 + UHCIState *s = opaque;
  303 + uint32_t val;
  304 +
  305 + addr &= 0x1f;
  306 + switch(addr) {
  307 + case 0x08:
  308 + val = s->fl_base_addr;
  309 + break;
  310 + default:
  311 + val = 0xffffffff;
  312 + break;
  313 + }
  314 + return val;
  315 +}
  316 +
  317 +static void uhci_attach(USBPort *port1, USBDevice *dev)
  318 +{
  319 + UHCIState *s = port1->opaque;
  320 + UHCIPort *port = &s->ports[port1->index];
  321 +
  322 + if (dev) {
  323 + if (port->dev) {
  324 + usb_attach(port1, NULL);
  325 + }
  326 + /* set connect status */
  327 + if (!(port->ctrl & UHCI_PORT_CCS)) {
  328 + port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
  329 + }
  330 + /* update speed */
  331 + if (dev->speed == USB_SPEED_LOW)
  332 + port->ctrl |= UHCI_PORT_LSDA;
  333 + else
  334 + port->ctrl &= ~UHCI_PORT_LSDA;
  335 + port->dev = dev;
  336 + /* send the attach message */
  337 + dev->handle_packet(dev,
  338 + USB_MSG_ATTACH, 0, 0, NULL, 0);
  339 + } else {
  340 + /* set connect status */
  341 + if (!(port->ctrl & UHCI_PORT_CCS)) {
  342 + port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
  343 + }
  344 + /* disable port */
  345 + if (port->ctrl & UHCI_PORT_EN) {
  346 + port->ctrl &= ~UHCI_PORT_EN;
  347 + port->ctrl |= UHCI_PORT_ENC;
  348 + }
  349 + dev = port->dev;
  350 + if (dev) {
  351 + /* send the detach message */
  352 + dev->handle_packet(dev,
  353 + USB_MSG_DETACH, 0, 0, NULL, 0);
  354 + }
  355 + port->dev = NULL;
  356 + }
  357 +}
  358 +
  359 +static int uhci_broadcast_packet(UHCIState *s, uint8_t pid,
  360 + uint8_t devaddr, uint8_t devep,
  361 + uint8_t *data, int len)
  362 +{
  363 + UHCIPort *port;
  364 + USBDevice *dev;
  365 + int i, ret;
  366 +
  367 +#ifdef DEBUG_PACKET
  368 + {
  369 + const char *pidstr;
  370 + switch(pid) {
  371 + case USB_TOKEN_SETUP: pidstr = "SETUP"; break;
  372 + case USB_TOKEN_IN: pidstr = "IN"; break;
  373 + case USB_TOKEN_OUT: pidstr = "OUT"; break;
  374 + default: pidstr = "?"; break;
  375 + }
  376 + printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n",
  377 + s->frnum, pidstr, devaddr, devep, len);
  378 + if (pid != USB_TOKEN_IN) {
  379 + printf(" data_out=");
  380 + for(i = 0; i < len; i++) {
  381 + printf(" %02x", data[i]);
  382 + }
  383 + printf("\n");
  384 + }
  385 + }
  386 +#endif
  387 + for(i = 0; i < NB_PORTS; i++) {
  388 + port = &s->ports[i];
  389 + dev = port->dev;
  390 + if (dev && (port->ctrl & UHCI_PORT_EN)) {
  391 + ret = dev->handle_packet(dev, pid,
  392 + devaddr, devep,
  393 + data, len);
  394 + if (ret != USB_RET_NODEV) {
  395 +#ifdef DEBUG_PACKET
  396 + {
  397 + printf(" ret=%d ", ret);
  398 + if (pid == USB_TOKEN_IN && ret > 0) {
  399 + printf("data_in=");
  400 + for(i = 0; i < ret; i++) {
  401 + printf(" %02x", data[i]);
  402 + }
  403 + }
  404 + printf("\n");
  405 + }
  406 +#endif
  407 + return ret;
  408 + }
  409 + }
  410 + }
  411 + return USB_RET_NODEV;
  412 +}
  413 +
  414 +/* return -1 if fatal error (frame must be stopped)
  415 + 0 if TD successful
  416 + 1 if TD unsuccessful or inactive
  417 +*/
  418 +static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask)
  419 +{
  420 + uint8_t pid;
  421 + uint8_t buf[1280];
  422 + int len, max_len, err, ret;
  423 +
  424 + if (td->ctrl & TD_CTRL_IOC) {
  425 + *int_mask |= 0x01;
  426 + }
  427 +
  428 + if (!(td->ctrl & TD_CTRL_ACTIVE))
  429 + return 1;
  430 +
  431 + /* TD is active */
  432 + max_len = ((td->token >> 21) + 1) & 0x7ff;
  433 + pid = td->token & 0xff;
  434 + switch(pid) {
  435 + case USB_TOKEN_OUT:
  436 + case USB_TOKEN_SETUP:
  437 + cpu_physical_memory_read(td->buffer, buf, max_len);
  438 + ret = uhci_broadcast_packet(s, pid,
  439 + (td->token >> 8) & 0x7f,
  440 + (td->token >> 15) & 0xf,
  441 + buf, max_len);
  442 + len = max_len;
  443 + break;
  444 + case USB_TOKEN_IN:
  445 + ret = uhci_broadcast_packet(s, pid,
  446 + (td->token >> 8) & 0x7f,
  447 + (td->token >> 15) & 0xf,
  448 + buf, max_len);
  449 + if (ret >= 0) {
  450 + len = ret;
  451 + if (len > max_len) {
  452 + len = max_len;
  453 + ret = USB_RET_BABBLE;
  454 + }
  455 + if (len > 0) {
  456 + /* write the data back */
  457 + cpu_physical_memory_write(td->buffer, buf, len);
  458 + }
  459 + } else {
  460 + len = 0;
  461 + }
  462 + break;
  463 + default:
  464 + /* invalid pid : frame interrupted */
  465 + s->status |= UHCI_STS_HCPERR;
  466 + uhci_update_irq(s);
  467 + return -1;
  468 + }
  469 + if (td->ctrl & TD_CTRL_IOS)
  470 + td->ctrl &= ~TD_CTRL_ACTIVE;
  471 + if (ret >= 0) {
  472 + td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
  473 + td->ctrl &= ~TD_CTRL_ACTIVE;
  474 + if (pid == USB_TOKEN_IN &&
  475 + (td->ctrl & TD_CTRL_SPD) &&
  476 + len < max_len) {
  477 + *int_mask |= 0x02;
  478 + /* short packet: do not update QH */
  479 + return 1;
  480 + } else {
  481 + /* success */
  482 + return 0;
  483 + }
  484 + } else {
  485 + switch(ret) {
  486 + default:
  487 + case USB_RET_NODEV:
  488 + do_timeout:
  489 + td->ctrl |= TD_CTRL_TIMEOUT;
  490 + err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3;
  491 + if (err != 0) {
  492 + err--;
  493 + if (err == 0) {
  494 + td->ctrl &= ~TD_CTRL_ACTIVE;
  495 + s->status |= UHCI_STS_USBERR;
  496 + uhci_update_irq(s);
  497 + }
  498 + }
  499 + td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |
  500 + (err << TD_CTRL_ERROR_SHIFT);
  501 + return 1;
  502 + case USB_RET_NAK:
  503 + td->ctrl |= TD_CTRL_NAK;
  504 + if (pid == USB_TOKEN_SETUP)
  505 + goto do_timeout;
  506 + return 1;
  507 + case USB_RET_STALL:
  508 + td->ctrl |= TD_CTRL_STALL;
  509 + td->ctrl &= ~TD_CTRL_ACTIVE;
  510 + return 1;
  511 + case USB_RET_BABBLE:
  512 + td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
  513 + td->ctrl &= ~TD_CTRL_ACTIVE;
  514 + /* frame interrupted */
  515 + return -1;
  516 + }
  517 + }
  518 +}
  519 +
  520 +static void uhci_frame_timer(void *opaque)
  521 +{
  522 + UHCIState *s = opaque;
  523 + int64_t expire_time;
  524 + uint32_t frame_addr, link, old_td_ctrl, val;
  525 + int int_mask, cnt, ret;
  526 + UHCI_TD td;
  527 + UHCI_QH qh;
  528 +
  529 + if (!(s->cmd & UHCI_CMD_RS)) {
  530 + qemu_del_timer(s->frame_timer);
  531 + return;
  532 + }
  533 + frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);
  534 + cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4);
  535 + le32_to_cpus(&link);
  536 + int_mask = 0;
  537 + cnt = FRAME_MAX_LOOPS;
  538 + while ((link & 1) == 0) {
  539 + if (--cnt == 0)
  540 + break;
  541 + /* valid frame */
  542 + if (link & 2) {
  543 + /* QH */
  544 + cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh));
  545 + le32_to_cpus(&qh.link);
  546 + le32_to_cpus(&qh.el_link);
  547 + depth_first:
  548 + if (qh.el_link & 1) {
  549 + /* no element : go to next entry */
  550 + link = qh.link;
  551 + } else if (qh.el_link & 2) {
  552 + /* QH */
  553 + link = qh.el_link;
  554 + } else {
  555 + /* TD */
  556 + if (--cnt == 0)
  557 + break;
  558 + cpu_physical_memory_read(qh.el_link & ~0xf,
  559 + (uint8_t *)&td, sizeof(td));
  560 + le32_to_cpus(&td.link);
  561 + le32_to_cpus(&td.ctrl);
  562 + le32_to_cpus(&td.token);
  563 + le32_to_cpus(&td.buffer);
  564 + old_td_ctrl = td.ctrl;
  565 + ret = uhci_handle_td(s, &td, &int_mask);
  566 + /* update the status bits of the TD */
  567 + if (old_td_ctrl != td.ctrl) {
  568 + val = cpu_to_le32(td.ctrl);
  569 + cpu_physical_memory_write((qh.el_link & ~0xf) + 4,
  570 + (const uint8_t *)&val,
  571 + sizeof(val));
  572 + }
  573 + if (ret < 0)
  574 + break; /* interrupted frame */
  575 + if (ret == 0) {
  576 + /* update qh element link */
  577 + qh.el_link = td.link;
  578 + val = cpu_to_le32(qh.el_link);
  579 + cpu_physical_memory_write((link & ~0xf) + 4,
  580 + (const uint8_t *)&val,
  581 + sizeof(val));
  582 + if (qh.el_link & 4) {
  583 + /* depth first */
  584 + goto depth_first;
  585 + }
  586 + }
  587 + /* go to next entry */
  588 + link = qh.link;
  589 + }
  590 + } else {
  591 + /* TD */
  592 + cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td));
  593 + le32_to_cpus(&td.link);
  594 + le32_to_cpus(&td.ctrl);
  595 + le32_to_cpus(&td.token);
  596 + le32_to_cpus(&td.buffer);
  597 + old_td_ctrl = td.ctrl;
  598 + ret = uhci_handle_td(s, &td, &int_mask);
  599 + /* update the status bits of the TD */
  600 + if (old_td_ctrl != td.ctrl) {
  601 + val = cpu_to_le32(td.ctrl);
  602 + cpu_physical_memory_write((link & ~0xf) + 4,
  603 + (const uint8_t *)&val,
  604 + sizeof(val));
  605 + }
  606 + if (ret < 0)
  607 + break; /* interrupted frame */
  608 + link = td.link;
  609 + }
  610 + }
  611 + s->frnum = (s->frnum + 1) & 0x7ff;
  612 + if (int_mask) {
  613 + s->status2 |= int_mask;
  614 + s->status |= UHCI_STS_USBINT;
  615 + uhci_update_irq(s);
  616 + }
  617 + /* prepare the timer for the next frame */
  618 + expire_time = qemu_get_clock(vm_clock) +
  619 + (ticks_per_sec / FRAME_TIMER_FREQ);
  620 + qemu_mod_timer(s->frame_timer, expire_time);
  621 +}
  622 +
  623 +static void uhci_map(PCIDevice *pci_dev, int region_num,
  624 + uint32_t addr, uint32_t size, int type)
  625 +{
  626 + UHCIState *s = (UHCIState *)pci_dev;
  627 +
  628 + register_ioport_write(addr, 32, 2, uhci_ioport_writew, s);
  629 + register_ioport_read(addr, 32, 2, uhci_ioport_readw, s);
  630 + register_ioport_write(addr, 32, 4, uhci_ioport_writel, s);
  631 + register_ioport_read(addr, 32, 4, uhci_ioport_readl, s);
  632 + register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s);
  633 + register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
  634 +}
  635 +
  636 +void usb_uhci_init(PCIBus *bus, USBPort **usb_ports)
  637 +{
  638 + UHCIState *s;
  639 + uint8_t *pci_conf;
  640 + UHCIPort *port;
  641 + int i;
  642 +
  643 + s = (UHCIState *)pci_register_device(bus,
  644 + "USB-UHCI", sizeof(UHCIState),
  645 + -1,
  646 + NULL, NULL);
  647 + pci_conf = s->dev.config;
  648 + pci_conf[0x00] = 0x86;
  649 + pci_conf[0x01] = 0x80;
  650 + pci_conf[0x02] = 0x20;
  651 + pci_conf[0x03] = 0x70;
  652 + pci_conf[0x08] = 0x01; // revision number
  653 + pci_conf[0x09] = 0x00;
  654 + pci_conf[0x0a] = 0x03;
  655 + pci_conf[0x0b] = 0x0c;
  656 + pci_conf[0x0e] = 0x00; // header_type
  657 + pci_conf[0x3d] = 1; // interrupt pin 0
  658 +
  659 + for(i = 0; i < NB_PORTS; i++) {
  660 + port = &s->ports[i];
  661 + port->port.opaque = s;
  662 + port->port.index = i;
  663 + port->port.attach = uhci_attach;
  664 + usb_ports[i] = &port->port;
  665 + }
  666 + s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
  667 +
  668 + uhci_reset(s);
  669 +
  670 + pci_register_io_region(&s->dev, 0, 0x20,
  671 + PCI_ADDRESS_SPACE_IO, uhci_map);
  672 +}
... ...
hw/usb.c 0 → 100644
  1 +/*
  2 + * QEMU USB 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 +void usb_attach(USBPort *port, USBDevice *dev)
  27 +{
  28 + port->attach(port, dev);
  29 +}
  30 +
  31 +/**********************/
  32 +/* generic USB device helpers (you are not forced to use them when
  33 + writing your USB device driver, but they help handling the
  34 + protocol)
  35 +*/
  36 +
  37 +#define SETUP_STATE_IDLE 0
  38 +#define SETUP_STATE_DATA 1
  39 +#define SETUP_STATE_ACK 2
  40 +
  41 +int usb_generic_handle_packet(USBDevice *s, int pid,
  42 + uint8_t devaddr, uint8_t devep,
  43 + uint8_t *data, int len)
  44 +{
  45 + int l, ret = 0;
  46 +
  47 + switch(pid) {
  48 + case USB_MSG_ATTACH:
  49 + s->state = USB_STATE_ATTACHED;
  50 + break;
  51 + case USB_MSG_DETACH:
  52 + s->state = USB_STATE_NOTATTACHED;
  53 + break;
  54 + case USB_MSG_RESET:
  55 + s->remote_wakeup = 0;
  56 + s->addr = 0;
  57 + s->state = USB_STATE_DEFAULT;
  58 + s->handle_reset(s);
  59 + break;
  60 + case USB_TOKEN_SETUP:
  61 + if (s->state < USB_STATE_DEFAULT || devaddr != s->addr)
  62 + return USB_RET_NODEV;
  63 + if (len != 8)
  64 + goto fail;
  65 + memcpy(s->setup_buf, data, 8);
  66 + s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
  67 + s->setup_index = 0;
  68 + if (s->setup_buf[0] & USB_DIR_IN) {
  69 + ret = s->handle_control(s,
  70 + (s->setup_buf[0] << 8) | s->setup_buf[1],
  71 + (s->setup_buf[3] << 8) | s->setup_buf[2],
  72 + (s->setup_buf[5] << 8) | s->setup_buf[4],
  73 + s->setup_len,
  74 + s->data_buf);
  75 + if (ret < 0)
  76 + return ret;
  77 + if (ret < s->setup_len)
  78 + s->setup_len = ret;
  79 + s->setup_state = SETUP_STATE_DATA;
  80 + } else {
  81 + if (s->setup_len == 0)
  82 + s->setup_state = SETUP_STATE_ACK;
  83 + else
  84 + s->setup_state = SETUP_STATE_DATA;
  85 + }
  86 + break;
  87 + case USB_TOKEN_IN:
  88 + if (s->state < USB_STATE_DEFAULT || devaddr != s->addr)
  89 + return USB_RET_NODEV;
  90 + switch(devep) {
  91 + case 0:
  92 + switch(s->setup_state) {
  93 + case SETUP_STATE_ACK:
  94 + s->setup_state = SETUP_STATE_IDLE;
  95 + if (!(s->setup_buf[0] & USB_DIR_IN)) {
  96 + ret = s->handle_control(s,
  97 + (s->setup_buf[0] << 8) | s->setup_buf[1],
  98 + (s->setup_buf[3] << 8) | s->setup_buf[2],
  99 + (s->setup_buf[5] << 8) | s->setup_buf[4],
  100 + s->setup_len,
  101 + s->data_buf);
  102 + if (ret > 0)
  103 + ret = 0;
  104 + } else {
  105 + goto fail;
  106 + }
  107 + break;
  108 + case SETUP_STATE_DATA:
  109 + if (s->setup_buf[0] & USB_DIR_IN) {
  110 + l = s->setup_len - s->setup_index;
  111 + if (l > len)
  112 + l = len;
  113 + memcpy(data, s->data_buf + s->setup_index, l);
  114 + s->setup_index += l;
  115 + if (s->setup_index >= s->setup_len)
  116 + s->setup_state = SETUP_STATE_ACK;
  117 + ret = l;
  118 + } else {
  119 + s->setup_state = SETUP_STATE_IDLE;
  120 + goto fail;
  121 + }
  122 + break;
  123 + default:
  124 + goto fail;
  125 + }
  126 + break;
  127 + default:
  128 + ret = s->handle_data(s, pid, devep, data, len);
  129 + break;
  130 + }
  131 + break;
  132 + case USB_TOKEN_OUT:
  133 + if (s->state < USB_STATE_DEFAULT || devaddr != s->addr)
  134 + return USB_RET_NODEV;
  135 + switch(devep) {
  136 + case 0:
  137 + switch(s->setup_state) {
  138 + case SETUP_STATE_ACK:
  139 + s->setup_state = SETUP_STATE_IDLE;
  140 + if (s->setup_buf[0] & USB_DIR_IN) {
  141 + /* transfer OK */
  142 + } else {
  143 + goto fail;
  144 + }
  145 + break;
  146 + case SETUP_STATE_DATA:
  147 + if (!(s->setup_buf[0] & USB_DIR_IN)) {
  148 + l = s->setup_len - s->setup_index;
  149 + if (l > len)
  150 + l = len;
  151 + memcpy(s->data_buf + s->setup_index, data, l);
  152 + s->setup_index += l;
  153 + if (s->setup_index >= s->setup_len)
  154 + s->setup_state = SETUP_STATE_ACK;
  155 + ret = l;
  156 + } else {
  157 + s->setup_state = SETUP_STATE_IDLE;
  158 + goto fail;
  159 + }
  160 + break;
  161 + default:
  162 + goto fail;
  163 + }
  164 + break;
  165 + default:
  166 + ret = s->handle_data(s, pid, devep, data, len);
  167 + break;
  168 + }
  169 + break;
  170 + default:
  171 + fail:
  172 + ret = USB_RET_STALL;
  173 + break;
  174 + }
  175 + return ret;
  176 +}
  177 +
  178 +/* XXX: fix overflow */
  179 +int set_usb_string(uint8_t *buf, const char *str)
  180 +{
  181 + int len, i;
  182 + uint8_t *q;
  183 +
  184 + q = buf;
  185 + len = strlen(str);
  186 + *q++ = 2 * len + 1;
  187 + *q++ = 3;
  188 + for(i = 0; i < len; i++) {
  189 + *q++ = str[i];
  190 + *q++ = 0;
  191 + }
  192 + return q - buf;
  193 +}
  194 +
  195 +/**********************/
  196 +/* USB hub emulation */
  197 +
  198 +//#define DEBUG
  199 +
  200 +#define MAX_PORTS 8
  201 +
  202 +#define DS_IDLE 0
  203 +#define DS_CONTROL_IN 1
  204 +#define DS_CONTROL_OUT 2
  205 +
  206 +typedef struct USBHubPort {
  207 + USBPort port;
  208 + USBDevice *dev;
  209 + uint16_t wPortStatus;
  210 + uint16_t wPortChange;
  211 +} USBHubPort;
  212 +
  213 +typedef struct USBHubState {
  214 + USBDevice dev;
  215 + int nb_ports;
  216 + USBHubPort ports[MAX_PORTS];
  217 +} USBHubState;
  218 +
  219 +#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE)
  220 +#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE)
  221 +#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR)
  222 +#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS)
  223 +#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS)
  224 +#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE)
  225 +#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE)
  226 +
  227 +#define PORT_STAT_CONNECTION 0x0001
  228 +#define PORT_STAT_ENABLE 0x0002
  229 +#define PORT_STAT_SUSPEND 0x0004
  230 +#define PORT_STAT_OVERCURRENT 0x0008
  231 +#define PORT_STAT_RESET 0x0010
  232 +#define PORT_STAT_POWER 0x0100
  233 +#define PORT_STAT_LOW_SPEED 0x0200
  234 +#define PORT_STAT_HIGH_SPEED 0x0400
  235 +#define PORT_STAT_TEST 0x0800
  236 +#define PORT_STAT_INDICATOR 0x1000
  237 +
  238 +#define PORT_STAT_C_CONNECTION 0x0001
  239 +#define PORT_STAT_C_ENABLE 0x0002
  240 +#define PORT_STAT_C_SUSPEND 0x0004
  241 +#define PORT_STAT_C_OVERCURRENT 0x0008
  242 +#define PORT_STAT_C_RESET 0x0010
  243 +
  244 +#define PORT_CONNECTION 0
  245 +#define PORT_ENABLE 1
  246 +#define PORT_SUSPEND 2
  247 +#define PORT_OVERCURRENT 3
  248 +#define PORT_RESET 4
  249 +#define PORT_POWER 8
  250 +#define PORT_LOWSPEED 9
  251 +#define PORT_HIGHSPEED 10
  252 +#define PORT_C_CONNECTION 16
  253 +#define PORT_C_ENABLE 17
  254 +#define PORT_C_SUSPEND 18
  255 +#define PORT_C_OVERCURRENT 19
  256 +#define PORT_C_RESET 20
  257 +#define PORT_TEST 21
  258 +#define PORT_INDICATOR 22
  259 +
  260 +/* same as Linux kernel root hubs */
  261 +
  262 +static const uint8_t qemu_hub_dev_descriptor[] = {
  263 + 0x12, /* __u8 bLength; */
  264 + 0x01, /* __u8 bDescriptorType; Device */
  265 + 0x10, 0x01, /* __u16 bcdUSB; v1.1 */
  266 +
  267 + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
  268 + 0x00, /* __u8 bDeviceSubClass; */
  269 + 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */
  270 + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
  271 +
  272 + 0x00, 0x00, /* __u16 idVendor; */
  273 + 0x00, 0x00, /* __u16 idProduct; */
  274 + 0x01, 0x01, /* __u16 bcdDevice */
  275 +
  276 + 0x03, /* __u8 iManufacturer; */
  277 + 0x02, /* __u8 iProduct; */
  278 + 0x01, /* __u8 iSerialNumber; */
  279 + 0x01 /* __u8 bNumConfigurations; */
  280 +};
  281 +
  282 +/* XXX: patch interrupt size */
  283 +static const uint8_t qemu_hub_config_descriptor[] = {
  284 +
  285 + /* one configuration */
  286 + 0x09, /* __u8 bLength; */
  287 + 0x02, /* __u8 bDescriptorType; Configuration */
  288 + 0x19, 0x00, /* __u16 wTotalLength; */
  289 + 0x01, /* __u8 bNumInterfaces; (1) */
  290 + 0x01, /* __u8 bConfigurationValue; */
  291 + 0x00, /* __u8 iConfiguration; */
  292 + 0xc0, /* __u8 bmAttributes;
  293 + Bit 7: must be set,
  294 + 6: Self-powered,
  295 + 5: Remote wakeup,
  296 + 4..0: resvd */
  297 + 0x00, /* __u8 MaxPower; */
  298 +
  299 + /* USB 1.1:
  300 + * USB 2.0, single TT organization (mandatory):
  301 + * one interface, protocol 0
  302 + *
  303 + * USB 2.0, multiple TT organization (optional):
  304 + * two interfaces, protocols 1 (like single TT)
  305 + * and 2 (multiple TT mode) ... config is
  306 + * sometimes settable
  307 + * NOT IMPLEMENTED
  308 + */
  309 +
  310 + /* one interface */
  311 + 0x09, /* __u8 if_bLength; */
  312 + 0x04, /* __u8 if_bDescriptorType; Interface */
  313 + 0x00, /* __u8 if_bInterfaceNumber; */
  314 + 0x00, /* __u8 if_bAlternateSetting; */
  315 + 0x01, /* __u8 if_bNumEndpoints; */
  316 + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
  317 + 0x00, /* __u8 if_bInterfaceSubClass; */
  318 + 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
  319 + 0x00, /* __u8 if_iInterface; */
  320 +
  321 + /* one endpoint (status change endpoint) */
  322 + 0x07, /* __u8 ep_bLength; */
  323 + 0x05, /* __u8 ep_bDescriptorType; Endpoint */
  324 + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
  325 + 0x03, /* __u8 ep_bmAttributes; Interrupt */
  326 + 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
  327 + 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */
  328 +};
  329 +
  330 +static const uint8_t qemu_hub_hub_descriptor[] =
  331 +{
  332 + 0x09, /* __u8 bLength; */
  333 + 0x29, /* __u8 bDescriptorType; Hub-descriptor */
  334 + 0x00, /* __u8 bNbrPorts; (patched later) */
  335 + 0x0a, /* __u16 wHubCharacteristics; */
  336 + 0x00, /* (per-port OC, no power switching) */
  337 + 0x01, /* __u8 bPwrOn2pwrGood; 2ms */
  338 + 0x00, /* __u8 bHubContrCurrent; 0 mA */
  339 + 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */
  340 + 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
  341 +};
  342 +
  343 +static void usb_hub_attach(USBPort *port1, USBDevice *dev)
  344 +{
  345 + USBHubState *s = port1->opaque;
  346 + USBHubPort *port = &s->ports[port1->index];
  347 +
  348 + if (dev) {
  349 + if (port->dev)
  350 + usb_attach(port1, NULL);
  351 +
  352 + port->wPortStatus |= PORT_STAT_CONNECTION;
  353 + port->wPortChange |= PORT_STAT_C_CONNECTION;
  354 + if (dev->speed == USB_SPEED_LOW)
  355 + port->wPortStatus |= PORT_STAT_LOW_SPEED;
  356 + else
  357 + port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
  358 + port->dev = dev;
  359 + } else {
  360 + dev = port->dev;
  361 + if (dev) {
  362 + port->wPortStatus &= ~PORT_STAT_CONNECTION;
  363 + port->wPortChange |= PORT_STAT_C_CONNECTION;
  364 + if (port->wPortStatus & PORT_STAT_ENABLE) {
  365 + port->wPortStatus &= ~PORT_STAT_ENABLE;
  366 + port->wPortChange |= PORT_STAT_C_ENABLE;
  367 + }
  368 + port->dev = NULL;
  369 + }
  370 + }
  371 +}
  372 +
  373 +static void usb_hub_handle_reset(USBDevice *dev)
  374 +{
  375 + /* XXX: do it */
  376 +}
  377 +
  378 +static int usb_hub_handle_control(USBDevice *dev, int request, int value,
  379 + int index, int length, uint8_t *data)
  380 +{
  381 + USBHubState *s = (USBHubState *)dev;
  382 + int ret;
  383 +
  384 + switch(request) {
  385 + case DeviceRequest | USB_REQ_GET_STATUS:
  386 + data[0] = (1 << USB_DEVICE_SELF_POWERED) |
  387 + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
  388 + data[1] = 0x00;
  389 + ret = 2;
  390 + break;
  391 + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
  392 + if (value == USB_DEVICE_REMOTE_WAKEUP) {
  393 + dev->remote_wakeup = 0;
  394 + } else {
  395 + goto fail;
  396 + }
  397 + ret = 0;
  398 + break;
  399 + case DeviceOutRequest | USB_REQ_SET_FEATURE:
  400 + if (value == USB_DEVICE_REMOTE_WAKEUP) {
  401 + dev->remote_wakeup = 1;
  402 + } else {
  403 + goto fail;
  404 + }
  405 + ret = 0;
  406 + break;
  407 + case DeviceOutRequest | USB_REQ_SET_ADDRESS:
  408 + dev->addr = value;
  409 + ret = 0;
  410 + break;
  411 + case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
  412 + switch(value >> 8) {
  413 + case USB_DT_DEVICE:
  414 + memcpy(data, qemu_hub_dev_descriptor,
  415 + sizeof(qemu_hub_dev_descriptor));
  416 + ret = sizeof(qemu_hub_dev_descriptor);
  417 + break;
  418 + case USB_DT_CONFIG:
  419 + memcpy(data, qemu_hub_config_descriptor,
  420 + sizeof(qemu_hub_config_descriptor));
  421 + ret = sizeof(qemu_hub_config_descriptor);
  422 + break;
  423 + case USB_DT_STRING:
  424 + switch(value & 0xff) {
  425 + case 0:
  426 + /* language ids */
  427 + data[0] = 4;
  428 + data[1] = 3;
  429 + data[2] = 0x09;
  430 + data[3] = 0x04;
  431 + ret = 4;
  432 + break;
  433 + case 1:
  434 + /* serial number */
  435 + ret = set_usb_string(data, "314159");
  436 + break;
  437 + case 2:
  438 + /* product description */
  439 + ret = set_usb_string(data, "QEMU USB Hub");
  440 + break;
  441 + case 3:
  442 + /* vendor description */
  443 + ret = set_usb_string(data, "QEMU " QEMU_VERSION);
  444 + break;
  445 + default:
  446 + goto fail;
  447 + }
  448 + break;
  449 + default:
  450 + goto fail;
  451 + }
  452 + break;
  453 + case DeviceRequest | USB_REQ_GET_CONFIGURATION:
  454 + data[0] = 1;
  455 + ret = 1;
  456 + break;
  457 + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
  458 + ret = 0;
  459 + break;
  460 + case DeviceRequest | USB_REQ_GET_INTERFACE:
  461 + data[0] = 0;
  462 + ret = 1;
  463 + break;
  464 + case DeviceOutRequest | USB_REQ_SET_INTERFACE:
  465 + ret = 0;
  466 + break;
  467 + /* usb specific requests */
  468 + case GetHubStatus:
  469 + data[0] = 0;
  470 + data[1] = 0;
  471 + data[2] = 0;
  472 + data[3] = 0;
  473 + ret = 4;
  474 + break;
  475 + case GetPortStatus:
  476 + {
  477 + unsigned int n = index - 1;
  478 + USBHubPort *port;
  479 + if (n >= s->nb_ports)
  480 + goto fail;
  481 + port = &s->ports[n];
  482 + data[0] = port->wPortStatus;
  483 + data[1] = port->wPortStatus >> 8;
  484 + data[2] = port->wPortChange;
  485 + data[3] = port->wPortChange >> 8;
  486 + ret = 4;
  487 + }
  488 + break;
  489 + case SetHubFeature:
  490 + case ClearHubFeature:
  491 + if (value == 0 || value == 1) {
  492 + } else {
  493 + goto fail;
  494 + }
  495 + ret = 0;
  496 + break;
  497 + case SetPortFeature:
  498 + {
  499 + unsigned int n = index - 1;
  500 + USBHubPort *port;
  501 + USBDevice *dev;
  502 + if (n >= s->nb_ports)
  503 + goto fail;
  504 + port = &s->ports[n];
  505 + dev = port->dev;
  506 + switch(value) {
  507 + case PORT_SUSPEND:
  508 + port->wPortStatus |= PORT_STAT_SUSPEND;
  509 + break;
  510 + case PORT_RESET:
  511 + if (dev) {
  512 + dev->handle_packet(dev,
  513 + USB_MSG_RESET, 0, 0, NULL, 0);
  514 + port->wPortChange |= PORT_STAT_C_RESET;
  515 + /* set enable bit */
  516 + port->wPortChange |= PORT_STAT_C_ENABLE;
  517 + port->wPortStatus |= PORT_STAT_ENABLE;
  518 + }
  519 + break;
  520 + case PORT_POWER:
  521 + break;
  522 + default:
  523 + goto fail;
  524 + }
  525 + ret = 0;
  526 + }
  527 + break;
  528 + case ClearPortFeature:
  529 + {
  530 + unsigned int n = index - 1;
  531 + USBHubPort *port;
  532 + USBDevice *dev;
  533 + if (n >= s->nb_ports)
  534 + goto fail;
  535 + port = &s->ports[n];
  536 + dev = port->dev;
  537 + switch(value) {
  538 + case PORT_ENABLE:
  539 + port->wPortStatus &= ~PORT_STAT_ENABLE;
  540 + break;
  541 + case PORT_C_ENABLE:
  542 + port->wPortChange &= ~PORT_STAT_C_ENABLE;
  543 + break;
  544 + case PORT_SUSPEND:
  545 + port->wPortStatus &= ~PORT_STAT_SUSPEND;
  546 + break;
  547 + case PORT_C_SUSPEND:
  548 + port->wPortChange &= ~PORT_STAT_C_SUSPEND;
  549 + break;
  550 + case PORT_C_CONNECTION:
  551 + port->wPortChange &= ~PORT_STAT_C_CONNECTION;
  552 + break;
  553 + case PORT_C_OVERCURRENT:
  554 + port->wPortChange &= ~PORT_STAT_C_OVERCURRENT;
  555 + break;
  556 + case PORT_C_RESET:
  557 + port->wPortChange &= ~PORT_STAT_C_RESET;
  558 + break;
  559 + default:
  560 + goto fail;
  561 + }
  562 + ret = 0;
  563 + }
  564 + break;
  565 + case GetHubDescriptor:
  566 + memcpy(data, qemu_hub_hub_descriptor,
  567 + sizeof(qemu_hub_hub_descriptor));
  568 + data[2] = s->nb_ports;
  569 + ret = sizeof(qemu_hub_hub_descriptor);
  570 + break;
  571 + default:
  572 + fail:
  573 + ret = USB_RET_STALL;
  574 + }
  575 + return ret;
  576 +}
  577 +
  578 +static int usb_hub_handle_data(USBDevice *dev, int pid,
  579 + uint8_t devep, uint8_t *data, int len)
  580 +{
  581 + USBHubState *s = (USBHubState *)dev;
  582 + int ret;
  583 +
  584 + switch(pid) {
  585 + case USB_TOKEN_IN:
  586 + if (devep == 1) {
  587 + USBHubPort *port;
  588 + unsigned int status;
  589 + int i, n;
  590 + n = (s->nb_ports + 1 + 7) / 8;
  591 + if (n > len)
  592 + return USB_RET_BABBLE;
  593 + status = 0;
  594 + for(i = 0; i < s->nb_ports; i++) {
  595 + port = &s->ports[i];
  596 + if (port->wPortChange)
  597 + status |= (1 << (i + 1));
  598 + }
  599 + if (status != 0) {
  600 + for(i = 0; i < n; i++) {
  601 + data[i] = status >> (8 * i);
  602 + }
  603 + ret = n;
  604 + } else {
  605 + ret = 0;
  606 + }
  607 + } else {
  608 + goto fail;
  609 + }
  610 + break;
  611 + case USB_TOKEN_OUT:
  612 + default:
  613 + fail:
  614 + ret = USB_RET_STALL;
  615 + break;
  616 + }
  617 + return ret;
  618 +}
  619 +
  620 +static int usb_hub_broadcast_packet(USBHubState *s, int pid,
  621 + uint8_t devaddr, uint8_t devep,
  622 + uint8_t *data, int len)
  623 +{
  624 + USBHubPort *port;
  625 + USBDevice *dev;
  626 + int i, ret;
  627 +
  628 + for(i = 0; i < s->nb_ports; i++) {
  629 + port = &s->ports[i];
  630 + dev = port->dev;
  631 + if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
  632 + ret = dev->handle_packet(dev, pid,
  633 + devaddr, devep,
  634 + data, len);
  635 + if (ret != USB_RET_NODEV) {
  636 + return ret;
  637 + }
  638 + }
  639 + }
  640 + return USB_RET_NODEV;
  641 +}
  642 +
  643 +static int usb_hub_handle_packet(USBDevice *dev, int pid,
  644 + uint8_t devaddr, uint8_t devep,
  645 + uint8_t *data, int len)
  646 +{
  647 + USBHubState *s = (USBHubState *)dev;
  648 +
  649 +#if defined(DEBUG) && 0
  650 + printf("usb_hub: pid=0x%x\n", pid);
  651 +#endif
  652 + if (dev->state == USB_STATE_DEFAULT &&
  653 + dev->addr != 0 &&
  654 + devaddr != dev->addr &&
  655 + (pid == USB_TOKEN_SETUP ||
  656 + pid == USB_TOKEN_OUT ||
  657 + pid == USB_TOKEN_IN)) {
  658 + /* broadcast the packet to the devices */
  659 + return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len);
  660 + }
  661 + return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len);
  662 +}
  663 +
  664 +USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports)
  665 +{
  666 + USBHubState *s;
  667 + USBHubPort *port;
  668 + int i;
  669 +
  670 + if (nb_ports > MAX_PORTS)
  671 + return NULL;
  672 + s = qemu_mallocz(sizeof(USBHubState));
  673 + if (!s)
  674 + return NULL;
  675 + s->dev.speed = USB_SPEED_FULL;
  676 + s->dev.handle_packet = usb_hub_handle_packet;
  677 +
  678 + /* generic USB device init */
  679 + s->dev.handle_reset = usb_hub_handle_reset;
  680 + s->dev.handle_control = usb_hub_handle_control;
  681 + s->dev.handle_data = usb_hub_handle_data;
  682 +
  683 + s->nb_ports = nb_ports;
  684 + for(i = 0; i < s->nb_ports; i++) {
  685 + port = &s->ports[i];
  686 + port->wPortStatus = PORT_STAT_POWER;
  687 + port->wPortChange = 0;
  688 + port->port.attach = usb_hub_attach;
  689 + port->port.opaque = s;
  690 + port->port.index = i;
  691 + usb_ports[i] = &port->port;
  692 + }
  693 + return (USBDevice *)s;
  694 +}
... ...
hw/usb.h 0 → 100644
  1 +/*
  2 + * QEMU USB API
  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 +#define USB_TOKEN_SETUP 0x2d
  25 +#define USB_TOKEN_IN 0x69 /* device -> host */
  26 +#define USB_TOKEN_OUT 0xe1 /* host -> device */
  27 +
  28 +/* specific usb messages, also sent in the 'pid' parameter */
  29 +#define USB_MSG_ATTACH 0x100
  30 +#define USB_MSG_DETACH 0x101
  31 +#define USB_MSG_RESET 0x102
  32 +
  33 +#define USB_RET_NODEV (-1)
  34 +#define USB_RET_NAK (-2)
  35 +#define USB_RET_STALL (-3)
  36 +#define USB_RET_BABBLE (-4)
  37 +
  38 +#define USB_SPEED_LOW 0
  39 +#define USB_SPEED_FULL 1
  40 +#define USB_SPEED_HIGH 2
  41 +
  42 +#define USB_STATE_NOTATTACHED 0
  43 +#define USB_STATE_ATTACHED 1
  44 +//#define USB_STATE_POWERED 2
  45 +#define USB_STATE_DEFAULT 3
  46 +//#define USB_STATE_ADDRESS 4
  47 +//#define USB_STATE_CONFIGURED 5
  48 +#define USB_STATE_SUSPENDED 6
  49 +
  50 +#define USB_DIR_OUT 0
  51 +#define USB_DIR_IN 0x80
  52 +
  53 +#define USB_TYPE_MASK (0x03 << 5)
  54 +#define USB_TYPE_STANDARD (0x00 << 5)
  55 +#define USB_TYPE_CLASS (0x01 << 5)
  56 +#define USB_TYPE_VENDOR (0x02 << 5)
  57 +#define USB_TYPE_RESERVED (0x03 << 5)
  58 +
  59 +#define USB_RECIP_MASK 0x1f
  60 +#define USB_RECIP_DEVICE 0x00
  61 +#define USB_RECIP_INTERFACE 0x01
  62 +#define USB_RECIP_ENDPOINT 0x02
  63 +#define USB_RECIP_OTHER 0x03
  64 +
  65 +#define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
  66 +#define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
  67 +
  68 +#define USB_REQ_GET_STATUS 0x00
  69 +#define USB_REQ_CLEAR_FEATURE 0x01
  70 +#define USB_REQ_SET_FEATURE 0x03
  71 +#define USB_REQ_SET_ADDRESS 0x05
  72 +#define USB_REQ_GET_DESCRIPTOR 0x06
  73 +#define USB_REQ_SET_DESCRIPTOR 0x07
  74 +#define USB_REQ_GET_CONFIGURATION 0x08
  75 +#define USB_REQ_SET_CONFIGURATION 0x09
  76 +#define USB_REQ_GET_INTERFACE 0x0A
  77 +#define USB_REQ_SET_INTERFACE 0x0B
  78 +#define USB_REQ_SYNCH_FRAME 0x0C
  79 +
  80 +#define USB_DEVICE_SELF_POWERED 0
  81 +#define USB_DEVICE_REMOTE_WAKEUP 1
  82 +
  83 +#define USB_DT_DEVICE 0x01
  84 +#define USB_DT_CONFIG 0x02
  85 +#define USB_DT_STRING 0x03
  86 +#define USB_DT_INTERFACE 0x04
  87 +#define USB_DT_ENDPOINT 0x05
  88 +
  89 +typedef struct USBPort USBPort;
  90 +typedef struct USBDevice USBDevice;
  91 +
  92 +/* definition of a USB device */
  93 +struct USBDevice {
  94 + void *opaque;
  95 + int (*handle_packet)(USBDevice *dev, int pid,
  96 + uint8_t devaddr, uint8_t devep,
  97 + uint8_t *data, int len);
  98 + int speed;
  99 +
  100 + /* The following fields are used by the generic USB device
  101 + layer. They are here just to avoid creating a new structure for
  102 + them. */
  103 + void (*handle_reset)(USBDevice *dev);
  104 + int (*handle_control)(USBDevice *dev, int request, int value,
  105 + int index, int length, uint8_t *data);
  106 + int (*handle_data)(USBDevice *dev, int pid, uint8_t devep,
  107 + uint8_t *data, int len);
  108 + uint8_t addr;
  109 +
  110 + int state;
  111 + uint8_t setup_buf[8];
  112 + uint8_t data_buf[1024];
  113 + int remote_wakeup;
  114 + int setup_state;
  115 + int setup_len;
  116 + int setup_index;
  117 +};
  118 +
  119 +/* USB port on which a device can be connected */
  120 +struct USBPort {
  121 + void (*attach)(USBPort *port, USBDevice *dev);
  122 + void *opaque;
  123 + int index; /* internal port index, may be used with the opaque */
  124 +};
  125 +
  126 +void usb_attach(USBPort *port, USBDevice *dev);
  127 +int usb_generic_handle_packet(USBDevice *s, int pid,
  128 + uint8_t devaddr, uint8_t devep,
  129 + uint8_t *data, int len);
  130 +int set_usb_string(uint8_t *buf, const char *str);
  131 +
  132 +/* usb hub */
  133 +USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports);
  134 +
  135 +/* usb-uhci.c */
  136 +void usb_uhci_init(PCIBus *bus, USBPort **usb_ports);
  137 +
  138 +/* usb-linux.c */
  139 +USBDevice *usb_host_hub_init(void);
... ...
usb-linux.c 0 → 100644
  1 +/*
  2 + * Linux host USB redirector
  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 +#if defined(__linux__)
  27 +#include <dirent.h>
  28 +#include <sys/ioctl.h>
  29 +#include <linux/usbdevice_fs.h>
  30 +#include <linux/version.h>
  31 +
  32 +/* We redefine it to avoid version problems */
  33 +struct usb_ctrltransfer {
  34 + uint8_t bRequestType;
  35 + uint8_t bRequest;
  36 + uint16_t wValue;
  37 + uint16_t wIndex;
  38 + uint16_t wLength;
  39 + uint32_t timeout;
  40 + void *data;
  41 +};
  42 +
  43 +//#define DEBUG
  44 +
  45 +#define MAX_DEVICES 8
  46 +
  47 +#define USBDEVFS_PATH "/proc/bus/usb"
  48 +
  49 +typedef struct USBHostDevice {
  50 + USBDevice dev;
  51 + int fd;
  52 +} USBHostDevice;
  53 +
  54 +typedef struct USBHostHubState {
  55 + USBDevice *hub_dev;
  56 + USBPort *hub_ports[MAX_DEVICES];
  57 + USBDevice *hub_devices[MAX_DEVICES];
  58 +} USBHostHubState;
  59 +
  60 +static void usb_host_handle_reset(USBDevice *dev)
  61 +{
  62 +#if 0
  63 + USBHostDevice *s = (USBHostDevice *)dev;
  64 + /* USBDEVFS_RESET, but not the first time as it has already be
  65 + done by the host OS */
  66 + ioctl(s->fd, USBDEVFS_RESET);
  67 +#endif
  68 +}
  69 +
  70 +static int usb_host_handle_control(USBDevice *dev,
  71 + int request,
  72 + int value,
  73 + int index,
  74 + int length,
  75 + uint8_t *data)
  76 +{
  77 + USBHostDevice *s = (USBHostDevice *)dev;
  78 + struct usb_ctrltransfer ct;
  79 + int ret;
  80 +
  81 + if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) {
  82 + /* specific SET_ADDRESS support */
  83 + dev->addr = value;
  84 + return 0;
  85 + } else {
  86 + ct.bRequestType = request >> 8;
  87 + ct.bRequest = request;
  88 + ct.wValue = value;
  89 + ct.wIndex = index;
  90 + ct.wLength = length;
  91 + ct.timeout = 50;
  92 + ct.data = data;
  93 + ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
  94 + if (ret < 0) {
  95 + switch(errno) {
  96 + case ETIMEDOUT:
  97 + return USB_RET_NAK;
  98 + default:
  99 + return USB_RET_STALL;
  100 + }
  101 + } else {
  102 + return ret;
  103 + }
  104 + }
  105 +}
  106 +
  107 +static int usb_host_handle_data(USBDevice *dev, int pid,
  108 + uint8_t devep,
  109 + uint8_t *data, int len)
  110 +{
  111 + USBHostDevice *s = (USBHostDevice *)dev;
  112 + struct usbdevfs_bulktransfer bt;
  113 + int ret;
  114 +
  115 + /* XXX: optimize and handle all data types by looking at the
  116 + config descriptor */
  117 + if (pid == USB_TOKEN_IN)
  118 + devep |= 0x80;
  119 + bt.ep = devep;
  120 + bt.len = len;
  121 + bt.timeout = 50;
  122 + bt.data = data;
  123 + ret = ioctl(s->fd, USBDEVFS_BULK, &bt);
  124 + if (ret < 0) {
  125 + switch(errno) {
  126 + case ETIMEDOUT:
  127 + return USB_RET_NAK;
  128 + case EPIPE:
  129 + default:
  130 +#ifdef DEBUG
  131 + printf("handle_data: errno=%d\n", errno);
  132 +#endif
  133 + return USB_RET_STALL;
  134 + }
  135 + } else {
  136 + return ret;
  137 + }
  138 +}
  139 +
  140 +static int usb_host_handle_packet(USBDevice *dev, int pid,
  141 + uint8_t devaddr, uint8_t devep,
  142 + uint8_t *data, int len)
  143 +{
  144 + return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len);
  145 +}
  146 +
  147 +/* XXX: exclude high speed devices or implement EHCI */
  148 +static void scan_host_device(USBHostHubState *s, const char *filename)
  149 +{
  150 + int fd, interface, ret, i;
  151 + USBHostDevice *dev;
  152 + struct usbdevfs_connectinfo ci;
  153 + uint8_t descr[1024];
  154 + int descr_len, dev_descr_len, config_descr_len, nb_interfaces;
  155 +
  156 +#ifdef DEBUG
  157 + printf("scanning %s\n", filename);
  158 +#endif
  159 + fd = open(filename, O_RDWR);
  160 + if (fd < 0) {
  161 + perror(filename);
  162 + return;
  163 + }
  164 +
  165 + /* read the config description */
  166 + descr_len = read(fd, descr, sizeof(descr));
  167 + if (descr_len <= 0) {
  168 + perror("read descr");
  169 + goto fail;
  170 + }
  171 +
  172 + i = 0;
  173 + dev_descr_len = descr[0];
  174 + if (dev_descr_len > descr_len)
  175 + goto fail;
  176 + i += dev_descr_len;
  177 + config_descr_len = descr[i];
  178 + if (i + config_descr_len > descr_len)
  179 + goto fail;
  180 + nb_interfaces = descr[i + 4];
  181 + if (nb_interfaces != 1) {
  182 + /* NOTE: currently we grab only one interface */
  183 + goto fail;
  184 + }
  185 + /* XXX: only grab if all interfaces are free */
  186 + interface = 0;
  187 + ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);
  188 + if (ret < 0) {
  189 + if (errno == EBUSY) {
  190 +#ifdef DEBUG
  191 + printf("%s already grabbed\n", filename);
  192 +#endif
  193 + } else {
  194 + perror("USBDEVFS_CLAIMINTERFACE");
  195 + }
  196 + fail:
  197 + close(fd);
  198 + return;
  199 + }
  200 +
  201 + ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
  202 + if (ret < 0) {
  203 + perror("USBDEVFS_CONNECTINFO");
  204 + goto fail;
  205 + }
  206 +
  207 +#ifdef DEBUG
  208 + printf("%s grabbed\n", filename);
  209 +#endif
  210 +
  211 + /* find a free slot */
  212 + for(i = 0; i < MAX_DEVICES; i++) {
  213 + if (!s->hub_devices[i])
  214 + break;
  215 + }
  216 + if (i == MAX_DEVICES) {
  217 +#ifdef DEBUG
  218 + printf("too many host devices\n");
  219 + goto fail;
  220 +#endif
  221 + }
  222 +
  223 + dev = qemu_mallocz(sizeof(USBHostDevice));
  224 + if (!dev)
  225 + goto fail;
  226 + dev->fd = fd;
  227 + if (ci.slow)
  228 + dev->dev.speed = USB_SPEED_LOW;
  229 + else
  230 + dev->dev.speed = USB_SPEED_HIGH;
  231 + dev->dev.handle_packet = usb_host_handle_packet;
  232 +
  233 + dev->dev.handle_reset = usb_host_handle_reset;
  234 + dev->dev.handle_control = usb_host_handle_control;
  235 + dev->dev.handle_data = usb_host_handle_data;
  236 +
  237 + s->hub_devices[i] = (USBDevice *)dev;
  238 +
  239 + /* activate device on hub */
  240 + usb_attach(s->hub_ports[i], s->hub_devices[i]);
  241 +}
  242 +
  243 +static void scan_host_devices(USBHostHubState *s, const char *bus_path)
  244 +{
  245 + DIR *d;
  246 + struct dirent *de;
  247 + char buf[1024];
  248 +
  249 + d = opendir(bus_path);
  250 + if (!d)
  251 + return;
  252 + for(;;) {
  253 + de = readdir(d);
  254 + if (!de)
  255 + break;
  256 + if (de->d_name[0] != '.') {
  257 + snprintf(buf, sizeof(buf), "%s/%s", bus_path, de->d_name);
  258 + scan_host_device(s, buf);
  259 + }
  260 + }
  261 + closedir(d);
  262 +}
  263 +
  264 +static void scan_host_buses(USBHostHubState *s)
  265 +{
  266 + DIR *d;
  267 + struct dirent *de;
  268 + char buf[1024];
  269 +
  270 + d = opendir(USBDEVFS_PATH);
  271 + if (!d)
  272 + return;
  273 + for(;;) {
  274 + de = readdir(d);
  275 + if (!de)
  276 + break;
  277 + if (isdigit(de->d_name[0])) {
  278 + snprintf(buf, sizeof(buf), "%s/%s", USBDEVFS_PATH, de->d_name);
  279 + scan_host_devices(s, buf);
  280 + }
  281 + }
  282 + closedir(d);
  283 +}
  284 +
  285 +/* virtual hub containing the USB devices of the host */
  286 +USBDevice *usb_host_hub_init(void)
  287 +{
  288 + USBHostHubState *s;
  289 + s = qemu_mallocz(sizeof(USBHostHubState));
  290 + if (!s)
  291 + return NULL;
  292 + s->hub_dev = usb_hub_init(s->hub_ports, MAX_DEVICES);
  293 + if (!s->hub_dev) {
  294 + free(s);
  295 + return NULL;
  296 + }
  297 + scan_host_buses(s);
  298 + return s->hub_dev;
  299 +}
  300 +
  301 +#else
  302 +
  303 +/* XXX: modify configure to compile the right host driver */
  304 +USBDevice *usb_host_hub_init(void)
  305 +{
  306 + return NULL;
  307 +}
  308 +
  309 +#endif
... ...
... ... @@ -153,6 +153,7 @@ CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
153 153 #ifdef TARGET_I386
154 154 int win2k_install_hack = 0;
155 155 #endif
  156 +int usb_enabled = 0;
156 157  
157 158 /***********************************************************/
158 159 /* x86 ISA bus support */
... ... @@ -2986,6 +2987,7 @@ enum {
2986 2987 QEMU_OPTION_pidfile,
2987 2988 QEMU_OPTION_no_kqemu,
2988 2989 QEMU_OPTION_win2k_hack,
  2990 + QEMU_OPTION_usb,
2989 2991 };
2990 2992  
2991 2993 typedef struct QEMUOption {
... ... @@ -3060,6 +3062,7 @@ const QEMUOption qemu_options[] = {
3060 3062 { "full-screen", 0, QEMU_OPTION_full_screen },
3061 3063 { "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
3062 3064 { "win2k-hack", 0, QEMU_OPTION_win2k_hack },
  3065 + { "usb", 0, QEMU_OPTION_usb },
3063 3066  
3064 3067 /* temporary options */
3065 3068 { "pci", 0, QEMU_OPTION_pci },
... ... @@ -3646,6 +3649,9 @@ int main(int argc, char **argv)
3646 3649 kqemu_allowed = 0;
3647 3650 break;
3648 3651 #endif
  3652 + case QEMU_OPTION_usb:
  3653 + usb_enabled = 1;
  3654 + break;
3649 3655 }
3650 3656 }
3651 3657 }
... ...
... ... @@ -135,6 +135,7 @@ extern int graphic_depth;
135 135 extern const char *keyboard_layout;
136 136 extern int kqemu_allowed;
137 137 extern int win2k_install_hack;
  138 +extern int usb_enabled;
138 139  
139 140 /* XXX: make it dynamic */
140 141 #if defined (TARGET_PPC)
... ... @@ -859,6 +860,8 @@ void adb_mouse_init(ADBBusState *bus);
859 860 extern ADBBusState adb_bus;
860 861 int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq);
861 862  
  863 +#include "hw/usb.h"
  864 +
862 865 #endif /* defined(QEMU_TOOL) */
863 866  
864 867 /* monitor.c */
... ...