ia64/xen-unstable

changeset 10359:e2a2b2da92f4

[HVM][DM] Backport the USB support from QEMU 0.8.1 to the current Xen
device model. To support USB there are two new optional config lines
that can be added to the guest config file:

usb=1
This will enable USB without defining a specific USB device.
This option is assumed and not needed if the `usbdevice' option
is given.

usbdevice='device'
This will enable USB and also enable support for the given device.
Currently, the only two devices are `mouse' (a PS/2 mouse) and
`tablet' (an absolute pointing device). The advantage of `tablet'
is that Windows guests will automatically recognize and support this
device so specifying the config line:

usbdevice='tablet'

will create a mouse that works transparently with Windows guests
under VNC. (Linux doesn't recognize the USB tablet yet so Linux
guests under VNC will still need the Summagraphics emulation.)

Signed-off-by: Don Dugger <donald.d.dugger@intel.com>
author kaf24@firebug.cl.cam.ac.uk
date Mon Jun 12 09:06:55 2006 +0100 (2006-06-12)
parents 5b1bd9eab3b9
children 8d5d225e9f34
files tools/ioemu/hw/pc.c tools/ioemu/hw/pckbd.c tools/ioemu/hw/usb-hid.c tools/ioemu/hw/usb-hub.c tools/ioemu/hw/usb-uhci.c tools/ioemu/hw/usb.c tools/ioemu/hw/usb.h tools/ioemu/monitor.c tools/ioemu/sdl.c tools/ioemu/target-i386-dm/Makefile tools/ioemu/usb-linux.c tools/ioemu/vl.c tools/ioemu/vl.h tools/ioemu/vnc.c tools/python/xen/xend/image.py tools/python/xen/xm/create.py
line diff
     1.1 --- a/tools/ioemu/hw/pc.c	Mon Jun 12 08:53:38 2006 +0100
     1.2 +++ b/tools/ioemu/hw/pc.c	Mon Jun 12 09:06:55 2006 +0100
     1.3 @@ -40,6 +40,7 @@ int speaker_data_on;
     1.4  int dummy_refresh_clock;
     1.5  static fdctrl_t *floppy_controller;
     1.6  static RTCState *rtc_state;
     1.7 +static USBPort *usb_root_ports[2];
     1.8  
     1.9  static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
    1.10  {
    1.11 @@ -584,6 +585,11 @@ void pc_init(uint64_t ram_size, int vga_
    1.12      cmos_init(ram_size, boot_device, bs_table, timeoffset);
    1.13      acpi_init(0x8000);
    1.14  
    1.15 +    if (pci_enabled && usb_enabled) {
    1.16 +	usb_uhci_init(pci_bus, usb_root_ports);
    1.17 +	usb_attach(usb_root_ports[0], vm_usb_hub);
    1.18 +    }
    1.19 +
    1.20      /* must be done after all PCI devices are instanciated */
    1.21      /* XXX: should be done in the Bochs BIOS */
    1.22      if (pci_enabled) {
     2.1 --- a/tools/ioemu/hw/pckbd.c	Mon Jun 12 08:53:38 2006 +0100
     2.2 +++ b/tools/ioemu/hw/pckbd.c	Mon Jun 12 09:06:55 2006 +0100
     2.3 @@ -118,6 +118,9 @@
     2.4  #define SUMMA_MAXX	(16000 - 1)
     2.5  #define SUMMA_MAXY	(16000 - 1)
     2.6  
     2.7 +#define MAX_ABSX	0x7fff
     2.8 +#define MAX_ABSY	0x7fff
     2.9 +
    2.10  typedef struct {
    2.11      uint8_t aux[KBD_QUEUE_SIZE];
    2.12      uint8_t data[KBD_QUEUE_SIZE];
    2.13 @@ -149,8 +152,6 @@ typedef struct KBDState {
    2.14      uint8_t mouse_wrap;
    2.15      uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
    2.16      uint8_t mouse_detect_state;
    2.17 -    int mouse_x;  /* absolute coordinates (for mousepad) */
    2.18 -    int mouse_y;
    2.19      int mouse_dx; /* current values, needed for 'poll' mode */
    2.20      int mouse_dy;
    2.21      int mouse_dz;
    2.22 @@ -422,7 +423,7 @@ static void kbd_write_keyboard(KBDState 
    2.23  
    2.24  int mouse_maxx, mouse_maxy;
    2.25  
    2.26 -static int kbd_mouse_send_packet(KBDState *s)
    2.27 +static void kbd_mouse_send_packet(KBDState *s)
    2.28  {
    2.29      unsigned int b;
    2.30      int dx1, dy1, dz1;
    2.31 @@ -430,100 +431,63 @@ static int kbd_mouse_send_packet(KBDStat
    2.32      dx1 = s->mouse_dx;
    2.33      dy1 = s->mouse_dy;
    2.34      dz1 = s->mouse_dz;
    2.35 +    /* XXX: increase range to 8 bits ? */
    2.36 +    if (dx1 > 127)
    2.37 +        dx1 = 127;
    2.38 +    else if (dx1 < -127)
    2.39 +        dx1 = -127;
    2.40 +    if (dy1 > 127)
    2.41 +        dy1 = 127;
    2.42 +    else if (dy1 < -127)
    2.43 +        dy1 = -127;
    2.44 +    b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
    2.45 +    kbd_queue(s, b, 1);
    2.46 +    kbd_queue(s, dx1 & 0xff, 1);
    2.47 +    kbd_queue(s, dy1 & 0xff, 1);
    2.48 +    /* extra byte for IMPS/2 or IMEX */
    2.49      switch(s->mouse_type) {
    2.50 -  
    2.51 -    case TABLET:        /* Summagraphics pen tablet */
    2.52 -	if (SummaState.report_mode == MODE_STREAM) {
    2.53 -	    dx1 = s->mouse_x;
    2.54 -	    dy1 = s->mouse_y;
    2.55 -	    if (SummaState.origin == ORIGIN_LOWER_LEFT)
    2.56 -		dy1 = mouse_maxy - dy1;
    2.57 -	    dx1 = ((dx1 * SUMMA_MAXX) / mouse_maxx) + SUMMA_BORDER;
    2.58 -	    dy1 = ((dy1 * SUMMA_MAXY) / mouse_maxy) + SUMMA_BORDER;
    2.59 -	    ser_queue(s->serial, 0x80 | (s->mouse_buttons & 7));
    2.60 -	    ser_queue(s->serial, dx1 & 0x7f);
    2.61 -	    ser_queue(s->serial, dx1 >> 7);
    2.62 -	    ser_queue(s->serial, dy1 & 0x7f);
    2.63 -	    ser_queue(s->serial, dy1 >> 7);
    2.64 -	}
    2.65 -	s->mouse_dx = 0; 
    2.66 -	s->mouse_dy = 0;
    2.67 -	s->mouse_dz = 0;
    2.68 -	return 0;
    2.69 +    default:
    2.70 +        break;
    2.71 +    case IMPS2:
    2.72 +        if (dz1 > 127)
    2.73 +            dz1 = 127;
    2.74 +        else if (dz1 < -127)
    2.75 +                dz1 = -127;
    2.76 +        kbd_queue(s, dz1 & 0xff, 1);
    2.77 +        break;
    2.78 +    case IMEX:
    2.79 +        if (dz1 > 7)
    2.80 +            dz1 = 7;
    2.81 +        else if (dz1 < -7)
    2.82 +            dz1 = -7;
    2.83 +        b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
    2.84 +        kbd_queue(s, b, 1);
    2.85 +        break;
    2.86 +    }
    2.87  
    2.88 -    default:	/* PS/2 style mice */
    2.89 -	/* XXX: increase range to 8 bits ? */
    2.90 -	if (dx1 > 127)
    2.91 -	    dx1 = 127;
    2.92 -	else if (dx1 < -127)
    2.93 -	    dx1 = -127;
    2.94 -	if (dy1 > 127)
    2.95 -	    dy1 = 127;
    2.96 -	else if (dy1 < -127)
    2.97 -	    dy1 = -127;
    2.98 -	b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
    2.99 -	kbd_queue(s, b, 1);
   2.100 -	kbd_queue(s, dx1 & 0xff, 1);
   2.101 -	kbd_queue(s, dy1 & 0xff, 1);
   2.102 -	/* extra byte for IMPS/2 or IMEX */
   2.103 -	switch(s->mouse_type) {
   2.104 -
   2.105 -	default:
   2.106 -	    break;
   2.107 -
   2.108 -	case IMPS2:
   2.109 -	    if (dz1 > 127)
   2.110 -		dz1 = 127;
   2.111 -	    else if (dz1 < -127)
   2.112 -		dz1 = -127;
   2.113 -	    kbd_queue(s, dz1 & 0xff, 1);
   2.114 -	    break;
   2.115 -
   2.116 -	case IMEX:
   2.117 -	    if (dz1 > 7)
   2.118 -		dz1 = 7;
   2.119 -	    else if (dz1 < -7)
   2.120 -		dz1 = -7;
   2.121 -	    b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
   2.122 -	    kbd_queue(s, b, 1);
   2.123 -	    break;
   2.124 -	}
   2.125 -
   2.126 -	/* update deltas */
   2.127 -	s->mouse_dx -= dx1;
   2.128 -	s->mouse_dy -= dy1;
   2.129 -	s->mouse_dz -= dz1;
   2.130 -	return s->mouse_dx || s->mouse_dy || s->mouse_dz;
   2.131 -
   2.132 -    }
   2.133 +    /* update deltas */
   2.134 +    s->mouse_dx -= dx1;
   2.135 +    s->mouse_dy -= dy1;
   2.136 +    s->mouse_dz -= dz1;
   2.137  }
   2.138  
   2.139 -static void pc_kbd_mouse_event(void *opaque, 
   2.140 -                               int dx, int dy, int dz, int buttons_state,
   2.141 -			       int x, int y)
   2.142 +static void summa_mouse_event(void *opaque, int x, int y, int z, int buttons_state)
   2.143  {
   2.144      KBDState *s = opaque;
   2.145  
   2.146 -    /* check if deltas are recorded when disabled */
   2.147 -    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
   2.148 -        return;
   2.149 -
   2.150 -    s->mouse_x = x;
   2.151 -    s->mouse_y = y;
   2.152 -    s->mouse_dx += dx;
   2.153 -    s->mouse_dy -= dy;
   2.154 -    s->mouse_dz += dz;
   2.155 -    /* XXX: SDL sometimes generates nul events: we delete them */
   2.156 -    if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
   2.157 -        s->mouse_buttons == buttons_state)
   2.158 -	return;
   2.159 -    s->mouse_buttons = buttons_state;
   2.160 -    
   2.161 -    if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
   2.162 -        (s->queue.count < (KBD_QUEUE_SIZE - 16))) {
   2.163 -		while (kbd_mouse_send_packet(s))
   2.164 -		    ;
   2.165 +    if (SummaState.report_mode == MODE_STREAM) {
   2.166 +	if (SummaState.origin == ORIGIN_LOWER_LEFT)
   2.167 +	    y = mouse_maxy - y;
   2.168 +	x = ((x * SUMMA_MAXX) / MAX_ABSX) + SUMMA_BORDER;
   2.169 +	y = ((y * SUMMA_MAXY) / MAX_ABSY) + SUMMA_BORDER;
   2.170 +fprintf(stderr, "summa_mouse_event: x, y - %d, %d\n", x, y);
   2.171 +	ser_queue(s->serial, 0x80 | (buttons_state & 7));
   2.172 +	ser_queue(s->serial, x & 0x7f);
   2.173 +	ser_queue(s->serial, x >> 7);
   2.174 +	ser_queue(s->serial, y & 0x7f);
   2.175 +	ser_queue(s->serial, y >> 7);
   2.176      }
   2.177 +    return;
   2.178  }
   2.179  
   2.180  static void summa(KBDState *s, uint8_t val)
   2.181 @@ -564,6 +528,7 @@ static void summa(KBDState *s, uint8_t v
   2.182  	s->mouse_status |= MOUSE_STATUS_ENABLED;
   2.183  	SummaState.origin = ORIGIN_LOWER_LEFT;
   2.184  	SummaState.report_mode = (val == 'B') ? MODE_POINT : MODE_STREAM_SWITCH;
   2.185 +	qemu_add_mouse_event_handler(summa_mouse_event, s, 1);
   2.186  	break;
   2.187  
   2.188      case 'z':	/* start of 2 byte command */
   2.189 @@ -647,6 +612,36 @@ void summa_init(SerialState *serial, Cha
   2.190      return;
   2.191  }
   2.192  
   2.193 +static void pc_kbd_mouse_event(void *opaque, 
   2.194 +                               int dx, int dy, int dz, int buttons_state)
   2.195 +{
   2.196 +    KBDState *s = opaque;
   2.197 +
   2.198 +    /* check if deltas are recorded when disabled */
   2.199 +    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
   2.200 +        return;
   2.201 +
   2.202 +    s->mouse_dx += dx;
   2.203 +    s->mouse_dy -= dy;
   2.204 +    s->mouse_dz += dz;
   2.205 +    /* XXX: SDL sometimes generates nul events: we delete them */
   2.206 +    if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
   2.207 +        s->mouse_buttons == buttons_state)
   2.208 +	return;
   2.209 +    s->mouse_buttons = buttons_state;
   2.210 +    
   2.211 +    if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
   2.212 +        (s->queue.count < (KBD_QUEUE_SIZE - 16))) {
   2.213 +	for(;;) {
   2.214 +	    /* if not remote, send event. Multiple events are sent if
   2.215 +	       too big deltas */
   2.216 +	    kbd_mouse_send_packet(s);
   2.217 +	    if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
   2.218 +		break;
   2.219 +	}
   2.220 +    }
   2.221 +}
   2.222 +
   2.223  static void kbd_write_mouse(KBDState *s, int val)
   2.224  {
   2.225  #ifdef DEBUG_MOUSE
   2.226 @@ -890,6 +885,6 @@ void kbd_init(void)
   2.227      register_ioport_write(0x64, 1, 1, kbd_write_command, s);
   2.228  
   2.229      qemu_add_kbd_event_handler(pc_kbd_put_keycode, s);
   2.230 -    qemu_add_mouse_event_handler(pc_kbd_mouse_event, s);
   2.231 +    qemu_add_mouse_event_handler(pc_kbd_mouse_event, s, 0);
   2.232      qemu_register_reset(kbd_reset, s);
   2.233  }
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/ioemu/hw/usb-hid.c	Mon Jun 12 09:06:55 2006 +0100
     3.3 @@ -0,0 +1,537 @@
     3.4 +/*
     3.5 + * QEMU USB HID devices
     3.6 + * 
     3.7 + * Copyright (c) 2005 Fabrice Bellard
     3.8 + * 
     3.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    3.10 + * of this software and associated documentation files (the "Software"), to deal
    3.11 + * in the Software without restriction, including without limitation the rights
    3.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    3.13 + * copies of the Software, and to permit persons to whom the Software is
    3.14 + * furnished to do so, subject to the following conditions:
    3.15 + *
    3.16 + * The above copyright notice and this permission notice shall be included in
    3.17 + * all copies or substantial portions of the Software.
    3.18 + *
    3.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    3.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    3.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    3.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    3.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    3.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    3.25 + * THE SOFTWARE.
    3.26 + */
    3.27 +#include "vl.h"
    3.28 +
    3.29 +/* HID interface requests */
    3.30 +#define GET_REPORT   0xa101
    3.31 +#define GET_IDLE     0xa102
    3.32 +#define GET_PROTOCOL 0xa103
    3.33 +#define SET_IDLE     0x210a
    3.34 +#define SET_PROTOCOL 0x210b
    3.35 +
    3.36 +#define USB_MOUSE  1
    3.37 +#define USB_TABLET 2
    3.38 +
    3.39 +typedef struct USBMouseState {
    3.40 +    USBDevice dev;
    3.41 +    int dx, dy, dz, buttons_state;
    3.42 +    int x, y;
    3.43 +    int kind;
    3.44 +    int mouse_grabbed;
    3.45 +} USBMouseState;
    3.46 +
    3.47 +/* mostly the same values as the Bochs USB Mouse device */
    3.48 +static const uint8_t qemu_mouse_dev_descriptor[] = {
    3.49 +	0x12,       /*  u8 bLength; */
    3.50 +	0x01,       /*  u8 bDescriptorType; Device */
    3.51 +	0x10, 0x00, /*  u16 bcdUSB; v1.0 */
    3.52 +
    3.53 +	0x00,	    /*  u8  bDeviceClass; */
    3.54 +	0x00,	    /*  u8  bDeviceSubClass; */
    3.55 +	0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
    3.56 +	0x08,       /*  u8  bMaxPacketSize0; 8 Bytes */
    3.57 +
    3.58 +	0x27, 0x06, /*  u16 idVendor; */
    3.59 + 	0x01, 0x00, /*  u16 idProduct; */
    3.60 +	0x00, 0x00, /*  u16 bcdDevice */
    3.61 +
    3.62 +	0x03,       /*  u8  iManufacturer; */
    3.63 +	0x02,       /*  u8  iProduct; */
    3.64 +	0x01,       /*  u8  iSerialNumber; */
    3.65 +	0x01        /*  u8  bNumConfigurations; */
    3.66 +};
    3.67 +
    3.68 +static const uint8_t qemu_mouse_config_descriptor[] = {
    3.69 +	/* one configuration */
    3.70 +	0x09,       /*  u8  bLength; */
    3.71 +	0x02,       /*  u8  bDescriptorType; Configuration */
    3.72 +	0x22, 0x00, /*  u16 wTotalLength; */
    3.73 +	0x01,       /*  u8  bNumInterfaces; (1) */
    3.74 +	0x01,       /*  u8  bConfigurationValue; */
    3.75 +	0x04,       /*  u8  iConfiguration; */
    3.76 +	0xa0,       /*  u8  bmAttributes; 
    3.77 +				 Bit 7: must be set,
    3.78 +				     6: Self-powered,
    3.79 +				     5: Remote wakeup,
    3.80 +				     4..0: resvd */
    3.81 +	50,         /*  u8  MaxPower; */
    3.82 +      
    3.83 +	/* USB 1.1:
    3.84 +	 * USB 2.0, single TT organization (mandatory):
    3.85 +	 *	one interface, protocol 0
    3.86 +	 *
    3.87 +	 * USB 2.0, multiple TT organization (optional):
    3.88 +	 *	two interfaces, protocols 1 (like single TT)
    3.89 +	 *	and 2 (multiple TT mode) ... config is
    3.90 +	 *	sometimes settable
    3.91 +	 *	NOT IMPLEMENTED
    3.92 +	 */
    3.93 +
    3.94 +	/* one interface */
    3.95 +	0x09,       /*  u8  if_bLength; */
    3.96 +	0x04,       /*  u8  if_bDescriptorType; Interface */
    3.97 +	0x00,       /*  u8  if_bInterfaceNumber; */
    3.98 +	0x00,       /*  u8  if_bAlternateSetting; */
    3.99 +	0x01,       /*  u8  if_bNumEndpoints; */
   3.100 +	0x03,       /*  u8  if_bInterfaceClass; */
   3.101 +	0x01,       /*  u8  if_bInterfaceSubClass; */
   3.102 +	0x02,       /*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
   3.103 +	0x05,       /*  u8  if_iInterface; */
   3.104 +     
   3.105 +        /* HID descriptor */
   3.106 +        0x09,        /*  u8  bLength; */
   3.107 +        0x21,        /*  u8 bDescriptorType; */
   3.108 +        0x01, 0x00,  /*  u16 HID_class */
   3.109 +        0x00,        /*  u8 country_code */
   3.110 +        0x01,        /*  u8 num_descriptors */
   3.111 +        0x22,        /*  u8 type; Report */
   3.112 +        50, 0,       /*  u16 len */
   3.113 +
   3.114 +	/* one endpoint (status change endpoint) */
   3.115 +	0x07,       /*  u8  ep_bLength; */
   3.116 +	0x05,       /*  u8  ep_bDescriptorType; Endpoint */
   3.117 +	0x81,       /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
   3.118 + 	0x03,       /*  u8  ep_bmAttributes; Interrupt */
   3.119 + 	0x03, 0x00, /*  u16 ep_wMaxPacketSize; */
   3.120 +	0x0a,       /*  u8  ep_bInterval; (255ms -- usb 2.0 spec) */
   3.121 +};
   3.122 +
   3.123 +static const uint8_t qemu_tablet_config_descriptor[] = {
   3.124 +	/* one configuration */
   3.125 +	0x09,       /*  u8  bLength; */
   3.126 +	0x02,       /*  u8  bDescriptorType; Configuration */
   3.127 +	0x22, 0x00, /*  u16 wTotalLength; */
   3.128 +	0x01,       /*  u8  bNumInterfaces; (1) */
   3.129 +	0x01,       /*  u8  bConfigurationValue; */
   3.130 +	0x04,       /*  u8  iConfiguration; */
   3.131 +	0xa0,       /*  u8  bmAttributes; 
   3.132 +				 Bit 7: must be set,
   3.133 +				     6: Self-powered,
   3.134 +				     5: Remote wakeup,
   3.135 +				     4..0: resvd */
   3.136 +	50,         /*  u8  MaxPower; */
   3.137 +      
   3.138 +	/* USB 1.1:
   3.139 +	 * USB 2.0, single TT organization (mandatory):
   3.140 +	 *	one interface, protocol 0
   3.141 +	 *
   3.142 +	 * USB 2.0, multiple TT organization (optional):
   3.143 +	 *	two interfaces, protocols 1 (like single TT)
   3.144 +	 *	and 2 (multiple TT mode) ... config is
   3.145 +	 *	sometimes settable
   3.146 +	 *	NOT IMPLEMENTED
   3.147 +	 */
   3.148 +
   3.149 +	/* one interface */
   3.150 +	0x09,       /*  u8  if_bLength; */
   3.151 +	0x04,       /*  u8  if_bDescriptorType; Interface */
   3.152 +	0x00,       /*  u8  if_bInterfaceNumber; */
   3.153 +	0x00,       /*  u8  if_bAlternateSetting; */
   3.154 +	0x01,       /*  u8  if_bNumEndpoints; */
   3.155 +	0x03,       /*  u8  if_bInterfaceClass; */
   3.156 +	0x01,       /*  u8  if_bInterfaceSubClass; */
   3.157 +	0x02,       /*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
   3.158 +	0x05,       /*  u8  if_iInterface; */
   3.159 +
   3.160 +        /* HID descriptor */
   3.161 +        0x09,        /*  u8  bLength; */
   3.162 +        0x21,        /*  u8 bDescriptorType; */
   3.163 +        0x01, 0x00,  /*  u16 HID_class */
   3.164 +        0x00,        /*  u8 country_code */
   3.165 +        0x01,        /*  u8 num_descriptors */
   3.166 +        0x22,        /*  u8 type; Report */
   3.167 +        74, 0,       /*  u16 len */
   3.168 +
   3.169 +	/* one endpoint (status change endpoint) */
   3.170 +	0x07,       /*  u8  ep_bLength; */
   3.171 +	0x05,       /*  u8  ep_bDescriptorType; Endpoint */
   3.172 +	0x81,       /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
   3.173 + 	0x03,       /*  u8  ep_bmAttributes; Interrupt */
   3.174 + 	0x08, 0x00, /*  u16 ep_wMaxPacketSize; */
   3.175 +	0x03,       /*  u8  ep_bInterval; (255ms -- usb 2.0 spec) */
   3.176 +};
   3.177 +
   3.178 +static const uint8_t qemu_mouse_hid_report_descriptor[] = {
   3.179 +    0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 
   3.180 +    0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
   3.181 +    0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 
   3.182 +    0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
   3.183 +    0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81, 
   3.184 +    0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06,
   3.185 +    0xC0, 0xC0,
   3.186 +};
   3.187 +
   3.188 +static const uint8_t qemu_tablet_hid_report_descriptor[] = {
   3.189 +        0x05, 0x01, /* Usage Page Generic Desktop */
   3.190 +        0x09, 0x01, /* Usage Mouse */
   3.191 +        0xA1, 0x01, /* Collection Application */
   3.192 +        0x09, 0x01, /* Usage Pointer */
   3.193 +        0xA1, 0x00, /* Collection Physical */
   3.194 +        0x05, 0x09, /* Usage Page Button */
   3.195 +        0x19, 0x01, /* Usage Minimum Button 1 */
   3.196 +        0x29, 0x03, /* Usage Maximum Button 3 */
   3.197 +        0x15, 0x00, /* Logical Minimum 0 */
   3.198 +        0x25, 0x01, /* Logical Maximum 1 */
   3.199 +        0x95, 0x03, /* Report Count 3 */
   3.200 +        0x75, 0x01, /* Report Size 1 */
   3.201 +        0x81, 0x02, /* Input (Data, Var, Abs) */
   3.202 +        0x95, 0x01, /* Report Count 1 */
   3.203 +        0x75, 0x05, /* Report Size 5 */
   3.204 +        0x81, 0x01, /* Input (Cnst, Var, Abs) */
   3.205 +        0x05, 0x01, /* Usage Page Generic Desktop */
   3.206 +        0x09, 0x30, /* Usage X */
   3.207 +        0x09, 0x31, /* Usage Y */
   3.208 +        0x15, 0x00, /* Logical Minimum 0 */
   3.209 +        0x26, 0xFF, 0x7F, /* Logical Maximum 0x7fff */
   3.210 +        0x35, 0x00, /* Physical Minimum 0 */
   3.211 +        0x46, 0xFE, 0x7F, /* Physical Maximum 0x7fff */
   3.212 +        0x75, 0x10, /* Report Size 16 */
   3.213 +        0x95, 0x02, /* Report Count 2 */
   3.214 +        0x81, 0x02, /* Input (Data, Var, Abs) */
   3.215 +        0x05, 0x01, /* Usage Page Generic Desktop */
   3.216 +        0x09, 0x38, /* Usage Wheel */
   3.217 +        0x15, 0x81, /* Logical Minimum -127 */
   3.218 +        0x25, 0x7F, /* Logical Maximum 127 */
   3.219 +        0x35, 0x00, /* Physical Minimum 0 (same as logical) */
   3.220 +        0x45, 0x00, /* Physical Maximum 0 (same as logical) */
   3.221 +        0x75, 0x08, /* Report Size 8 */
   3.222 +        0x95, 0x01, /* Report Count 1 */
   3.223 +        0x81, 0x02, /* Input (Data, Var, Rel) */
   3.224 +        0xC0,       /* End Collection */
   3.225 +        0xC0,       /* End Collection */
   3.226 +};
   3.227 +
   3.228 +static void usb_mouse_event(void *opaque,
   3.229 +                            int dx1, int dy1, int dz1, int buttons_state)
   3.230 +{
   3.231 +    USBMouseState *s = opaque;
   3.232 +
   3.233 +    s->dx += dx1;
   3.234 +    s->dy += dy1;
   3.235 +    s->dz += dz1;
   3.236 +    s->buttons_state = buttons_state;
   3.237 +}
   3.238 +
   3.239 +static void usb_tablet_event(void *opaque,
   3.240 +			     int x, int y, int dz, int buttons_state)
   3.241 +{
   3.242 +    USBMouseState *s = opaque;
   3.243 +
   3.244 +    s->x = x;
   3.245 +    s->y = y;
   3.246 +    s->dz += dz;
   3.247 +    s->buttons_state = buttons_state;
   3.248 +}
   3.249 +
   3.250 +static inline int int_clamp(int val, int vmin, int vmax)
   3.251 +{
   3.252 +    if (val < vmin)
   3.253 +        return vmin;
   3.254 +    else if (val > vmax)
   3.255 +        return vmax;
   3.256 +    else
   3.257 +        return val;
   3.258 +}
   3.259 +
   3.260 +static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len)
   3.261 +{
   3.262 +    int dx, dy, dz, b, l;
   3.263 +
   3.264 +    if (!s->mouse_grabbed) {
   3.265 +	qemu_add_mouse_event_handler(usb_mouse_event, s, 0);
   3.266 +	s->mouse_grabbed = 1;
   3.267 +    }
   3.268 +    
   3.269 +    dx = int_clamp(s->dx, -128, 127);
   3.270 +    dy = int_clamp(s->dy, -128, 127);
   3.271 +    dz = int_clamp(s->dz, -128, 127);
   3.272 +
   3.273 +    s->dx -= dx;
   3.274 +    s->dy -= dy;
   3.275 +    s->dz -= dz;
   3.276 +    
   3.277 +    b = 0;
   3.278 +    if (s->buttons_state & MOUSE_EVENT_LBUTTON)
   3.279 +        b |= 0x01;
   3.280 +    if (s->buttons_state & MOUSE_EVENT_RBUTTON)
   3.281 +        b |= 0x02;
   3.282 +    if (s->buttons_state & MOUSE_EVENT_MBUTTON)
   3.283 +        b |= 0x04;
   3.284 +    
   3.285 +    buf[0] = b;
   3.286 +    buf[1] = dx;
   3.287 +    buf[2] = dy;
   3.288 +    l = 3;
   3.289 +    if (len >= 4) {
   3.290 +        buf[3] = dz;
   3.291 +        l = 4;
   3.292 +    }
   3.293 +    return l;
   3.294 +}
   3.295 +
   3.296 +static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len)
   3.297 +{
   3.298 +    int dz, b, l;
   3.299 +
   3.300 +    if (!s->mouse_grabbed) {
   3.301 +	qemu_add_mouse_event_handler(usb_tablet_event, s, 1);
   3.302 +	s->mouse_grabbed = 1;
   3.303 +    }
   3.304 +    
   3.305 +    dz = int_clamp(s->dz, -128, 127);
   3.306 +    s->dz -= dz;
   3.307 +
   3.308 +    /* Appears we have to invert the wheel direction */
   3.309 +    dz = 0 - dz;
   3.310 +    b = 0;
   3.311 +    if (s->buttons_state & MOUSE_EVENT_LBUTTON)
   3.312 +        b |= 0x01;
   3.313 +    if (s->buttons_state & MOUSE_EVENT_RBUTTON)
   3.314 +        b |= 0x02;
   3.315 +    if (s->buttons_state & MOUSE_EVENT_MBUTTON)
   3.316 +        b |= 0x04;
   3.317 +
   3.318 +    buf[0] = b;
   3.319 +    buf[1] = s->x & 0xff;
   3.320 +    buf[2] = s->x >> 8;
   3.321 +    buf[3] = s->y & 0xff;
   3.322 +    buf[4] = s->y >> 8;
   3.323 +    buf[5] = dz;
   3.324 +    l = 6;
   3.325 +
   3.326 +    return l;
   3.327 +}
   3.328 +
   3.329 +static void usb_mouse_handle_reset(USBDevice *dev)
   3.330 +{
   3.331 +    USBMouseState *s = (USBMouseState *)dev;
   3.332 +
   3.333 +    s->dx = 0;
   3.334 +    s->dy = 0;
   3.335 +    s->dz = 0;
   3.336 +    s->x = 0;
   3.337 +    s->y = 0;
   3.338 +    s->buttons_state = 0;
   3.339 +}
   3.340 +
   3.341 +static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
   3.342 +                                  int index, int length, uint8_t *data)
   3.343 +{
   3.344 +    USBMouseState *s = (USBMouseState *)dev;
   3.345 +    int ret = 0;
   3.346 +
   3.347 +    switch(request) {
   3.348 +    case DeviceRequest | USB_REQ_GET_STATUS:
   3.349 +        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
   3.350 +            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
   3.351 +        data[1] = 0x00;
   3.352 +        ret = 2;
   3.353 +        break;
   3.354 +    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
   3.355 +        if (value == USB_DEVICE_REMOTE_WAKEUP) {
   3.356 +            dev->remote_wakeup = 0;
   3.357 +        } else {
   3.358 +            goto fail;
   3.359 +        }
   3.360 +        ret = 0;
   3.361 +        break;
   3.362 +    case DeviceOutRequest | USB_REQ_SET_FEATURE:
   3.363 +        if (value == USB_DEVICE_REMOTE_WAKEUP) {
   3.364 +            dev->remote_wakeup = 1;
   3.365 +        } else {
   3.366 +            goto fail;
   3.367 +        }
   3.368 +        ret = 0;
   3.369 +        break;
   3.370 +    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
   3.371 +        dev->addr = value;
   3.372 +        ret = 0;
   3.373 +        break;
   3.374 +    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
   3.375 +        switch(value >> 8) {
   3.376 +        case USB_DT_DEVICE:
   3.377 +            memcpy(data, qemu_mouse_dev_descriptor, 
   3.378 +                   sizeof(qemu_mouse_dev_descriptor));
   3.379 +            ret = sizeof(qemu_mouse_dev_descriptor);
   3.380 +            break;
   3.381 +        case USB_DT_CONFIG:
   3.382 +	    if (s->kind == USB_MOUSE) {
   3.383 +		memcpy(data, qemu_mouse_config_descriptor, 
   3.384 +		       sizeof(qemu_mouse_config_descriptor));
   3.385 +		ret = sizeof(qemu_mouse_config_descriptor);
   3.386 +	    } else if (s->kind == USB_TABLET) {
   3.387 +		memcpy(data, qemu_tablet_config_descriptor, 
   3.388 +		       sizeof(qemu_tablet_config_descriptor));
   3.389 +		ret = sizeof(qemu_tablet_config_descriptor);
   3.390 +	    }		
   3.391 +            break;
   3.392 +        case USB_DT_STRING:
   3.393 +            switch(value & 0xff) {
   3.394 +            case 0:
   3.395 +                /* language ids */
   3.396 +                data[0] = 4;
   3.397 +                data[1] = 3;
   3.398 +                data[2] = 0x09;
   3.399 +                data[3] = 0x04;
   3.400 +                ret = 4;
   3.401 +                break;
   3.402 +            case 1:
   3.403 +                /* serial number */
   3.404 +                ret = set_usb_string(data, "1");
   3.405 +                break;
   3.406 +            case 2:
   3.407 +                /* product description */
   3.408 +		if (s->kind == USB_MOUSE)
   3.409 +		    ret = set_usb_string(data, "QEMU USB Mouse");
   3.410 +		else if (s->kind == USB_TABLET)
   3.411 +		    ret = set_usb_string(data, "QEMU USB Tablet");
   3.412 +                break;
   3.413 +            case 3:
   3.414 +                /* vendor description */
   3.415 +                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
   3.416 +                break;
   3.417 +            case 4:
   3.418 +                ret = set_usb_string(data, "HID Mouse");
   3.419 +                break;
   3.420 +            case 5:
   3.421 +                ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
   3.422 +                break;
   3.423 +            default:
   3.424 +                goto fail;
   3.425 +            }
   3.426 +            break;
   3.427 +        default:
   3.428 +            goto fail;
   3.429 +        }
   3.430 +        break;
   3.431 +    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
   3.432 +        data[0] = 1;
   3.433 +        ret = 1;
   3.434 +        break;
   3.435 +    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
   3.436 +        ret = 0;
   3.437 +        break;
   3.438 +    case DeviceRequest | USB_REQ_GET_INTERFACE:
   3.439 +        data[0] = 0;
   3.440 +        ret = 1;
   3.441 +        break;
   3.442 +    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
   3.443 +        ret = 0;
   3.444 +        break;
   3.445 +        /* hid specific requests */
   3.446 +    case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
   3.447 +        switch(value >> 8) {
   3.448 +        case 0x22:
   3.449 +	    if (s->kind == USB_MOUSE) {
   3.450 +		memcpy(data, qemu_mouse_hid_report_descriptor, 
   3.451 +		       sizeof(qemu_mouse_hid_report_descriptor));
   3.452 +		ret = sizeof(qemu_mouse_hid_report_descriptor);
   3.453 +	    } else if (s->kind == USB_TABLET) {
   3.454 +		memcpy(data, qemu_tablet_hid_report_descriptor, 
   3.455 +		       sizeof(qemu_tablet_hid_report_descriptor));
   3.456 +		ret = sizeof(qemu_tablet_hid_report_descriptor);
   3.457 +	    }
   3.458 +	    break;
   3.459 +        default:
   3.460 +            goto fail;
   3.461 +        }
   3.462 +        break;
   3.463 +    case GET_REPORT:
   3.464 +	if (s->kind == USB_MOUSE)
   3.465 +	    ret = usb_mouse_poll(s, data, length);
   3.466 +	else if (s->kind == USB_TABLET)
   3.467 +	    ret = usb_tablet_poll(s, data, length);
   3.468 +        break;
   3.469 +    case SET_IDLE:
   3.470 +        ret = 0;
   3.471 +        break;
   3.472 +    default:
   3.473 +    fail:
   3.474 +        ret = USB_RET_STALL;
   3.475 +        break;
   3.476 +    }
   3.477 +    return ret;
   3.478 +}
   3.479 +
   3.480 +static int usb_mouse_handle_data(USBDevice *dev, int pid, 
   3.481 +                                 uint8_t devep, uint8_t *data, int len)
   3.482 +{
   3.483 +    USBMouseState *s = (USBMouseState *)dev;
   3.484 +    int ret = 0;
   3.485 +
   3.486 +    switch(pid) {
   3.487 +    case USB_TOKEN_IN:
   3.488 +        if (devep == 1) {
   3.489 +	    if (s->kind == USB_MOUSE)
   3.490 +		ret = usb_mouse_poll(s, data, len);
   3.491 +	    else if (s->kind == USB_TABLET)
   3.492 +		ret = usb_tablet_poll(s, data, len);
   3.493 +        } else {
   3.494 +            goto fail;
   3.495 +        }
   3.496 +        break;
   3.497 +    case USB_TOKEN_OUT:
   3.498 +    default:
   3.499 +    fail:
   3.500 +        ret = USB_RET_STALL;
   3.501 +        break;
   3.502 +    }
   3.503 +    return ret;
   3.504 +}
   3.505 +
   3.506 +USBDevice *usb_tablet_init(void)
   3.507 +{
   3.508 +    USBMouseState *s;
   3.509 +
   3.510 +    s = qemu_mallocz(sizeof(USBMouseState));
   3.511 +    if (!s)
   3.512 +        return NULL;
   3.513 +    s->dev.speed = USB_SPEED_FULL;
   3.514 +    s->dev.handle_packet = usb_generic_handle_packet;
   3.515 +
   3.516 +    s->dev.handle_reset = usb_mouse_handle_reset;
   3.517 +    s->dev.handle_control = usb_mouse_handle_control;
   3.518 +    s->dev.handle_data = usb_mouse_handle_data;
   3.519 +    s->kind = USB_TABLET;
   3.520 +
   3.521 +    return (USBDevice *)s;
   3.522 +}
   3.523 +
   3.524 +USBDevice *usb_mouse_init(void)
   3.525 +{
   3.526 +    USBMouseState *s;
   3.527 +
   3.528 +    s = qemu_mallocz(sizeof(USBMouseState));
   3.529 +    if (!s)
   3.530 +        return NULL;
   3.531 +    s->dev.speed = USB_SPEED_FULL;
   3.532 +    s->dev.handle_packet = usb_generic_handle_packet;
   3.533 +
   3.534 +    s->dev.handle_reset = usb_mouse_handle_reset;
   3.535 +    s->dev.handle_control = usb_mouse_handle_control;
   3.536 +    s->dev.handle_data = usb_mouse_handle_data;
   3.537 +    s->kind = USB_MOUSE;
   3.538 +
   3.539 +    return (USBDevice *)s;
   3.540 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tools/ioemu/hw/usb-hub.c	Mon Jun 12 09:06:55 2006 +0100
     4.3 @@ -0,0 +1,549 @@
     4.4 +/*
     4.5 + * QEMU USB HUB emulation
     4.6 + *
     4.7 + * Copyright (c) 2005 Fabrice Bellard
     4.8 + * 
     4.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    4.10 + * of this software and associated documentation files (the "Software"), to deal
    4.11 + * in the Software without restriction, including without limitation the rights
    4.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    4.13 + * copies of the Software, and to permit persons to whom the Software is
    4.14 + * furnished to do so, subject to the following conditions:
    4.15 + *
    4.16 + * The above copyright notice and this permission notice shall be included in
    4.17 + * all copies or substantial portions of the Software.
    4.18 + *
    4.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    4.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    4.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    4.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    4.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    4.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    4.25 + * THE SOFTWARE.
    4.26 + */
    4.27 +#include "vl.h"
    4.28 +
    4.29 +//#define DEBUG
    4.30 +
    4.31 +#define MAX_PORTS 8
    4.32 +
    4.33 +typedef struct USBHubPort {
    4.34 +    USBPort port;
    4.35 +    uint16_t wPortStatus;
    4.36 +    uint16_t wPortChange;
    4.37 +} USBHubPort;
    4.38 +
    4.39 +typedef struct USBHubState {
    4.40 +    USBDevice dev;
    4.41 +    int nb_ports;
    4.42 +    USBHubPort ports[MAX_PORTS];
    4.43 +} USBHubState;
    4.44 +
    4.45 +#define ClearHubFeature		(0x2000 | USB_REQ_CLEAR_FEATURE)
    4.46 +#define ClearPortFeature	(0x2300 | USB_REQ_CLEAR_FEATURE)
    4.47 +#define GetHubDescriptor	(0xa000 | USB_REQ_GET_DESCRIPTOR)
    4.48 +#define GetHubStatus		(0xa000 | USB_REQ_GET_STATUS)
    4.49 +#define GetPortStatus		(0xa300 | USB_REQ_GET_STATUS)
    4.50 +#define SetHubFeature		(0x2000 | USB_REQ_SET_FEATURE)
    4.51 +#define SetPortFeature		(0x2300 | USB_REQ_SET_FEATURE)
    4.52 +
    4.53 +#define PORT_STAT_CONNECTION	0x0001
    4.54 +#define PORT_STAT_ENABLE	0x0002
    4.55 +#define PORT_STAT_SUSPEND	0x0004
    4.56 +#define PORT_STAT_OVERCURRENT	0x0008
    4.57 +#define PORT_STAT_RESET		0x0010
    4.58 +#define PORT_STAT_POWER		0x0100
    4.59 +#define PORT_STAT_LOW_SPEED	0x0200
    4.60 +#define PORT_STAT_HIGH_SPEED    0x0400
    4.61 +#define PORT_STAT_TEST          0x0800
    4.62 +#define PORT_STAT_INDICATOR     0x1000
    4.63 +
    4.64 +#define PORT_STAT_C_CONNECTION	0x0001
    4.65 +#define PORT_STAT_C_ENABLE	0x0002
    4.66 +#define PORT_STAT_C_SUSPEND	0x0004
    4.67 +#define PORT_STAT_C_OVERCURRENT	0x0008
    4.68 +#define PORT_STAT_C_RESET	0x0010
    4.69 +
    4.70 +#define PORT_CONNECTION	        0
    4.71 +#define PORT_ENABLE		1
    4.72 +#define PORT_SUSPEND		2
    4.73 +#define PORT_OVERCURRENT	3
    4.74 +#define PORT_RESET		4
    4.75 +#define PORT_POWER		8
    4.76 +#define PORT_LOWSPEED		9
    4.77 +#define PORT_HIGHSPEED		10
    4.78 +#define PORT_C_CONNECTION	16
    4.79 +#define PORT_C_ENABLE		17
    4.80 +#define PORT_C_SUSPEND		18
    4.81 +#define PORT_C_OVERCURRENT	19
    4.82 +#define PORT_C_RESET		20
    4.83 +#define PORT_TEST               21
    4.84 +#define PORT_INDICATOR          22
    4.85 +
    4.86 +/* same as Linux kernel root hubs */
    4.87 +
    4.88 +static const uint8_t qemu_hub_dev_descriptor[] = {
    4.89 +	0x12,       /*  u8 bLength; */
    4.90 +	0x01,       /*  u8 bDescriptorType; Device */
    4.91 +	0x10, 0x01, /*  u16 bcdUSB; v1.1 */
    4.92 +
    4.93 +	0x09,	    /*  u8  bDeviceClass; HUB_CLASSCODE */
    4.94 +	0x00,	    /*  u8  bDeviceSubClass; */
    4.95 +	0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
    4.96 +	0x08,       /*  u8  bMaxPacketSize0; 8 Bytes */
    4.97 +
    4.98 +	0x00, 0x00, /*  u16 idVendor; */
    4.99 + 	0x00, 0x00, /*  u16 idProduct; */
   4.100 +	0x01, 0x01, /*  u16 bcdDevice */
   4.101 +
   4.102 +	0x03,       /*  u8  iManufacturer; */
   4.103 +	0x02,       /*  u8  iProduct; */
   4.104 +	0x01,       /*  u8  iSerialNumber; */
   4.105 +	0x01        /*  u8  bNumConfigurations; */
   4.106 +};
   4.107 +
   4.108 +/* XXX: patch interrupt size */
   4.109 +static const uint8_t qemu_hub_config_descriptor[] = {
   4.110 +
   4.111 +	/* one configuration */
   4.112 +	0x09,       /*  u8  bLength; */
   4.113 +	0x02,       /*  u8  bDescriptorType; Configuration */
   4.114 +	0x19, 0x00, /*  u16 wTotalLength; */
   4.115 +	0x01,       /*  u8  bNumInterfaces; (1) */
   4.116 +	0x01,       /*  u8  bConfigurationValue; */
   4.117 +	0x00,       /*  u8  iConfiguration; */
   4.118 +	0xc0,       /*  u8  bmAttributes; 
   4.119 +				 Bit 7: must be set,
   4.120 +				     6: Self-powered,
   4.121 +				     5: Remote wakeup,
   4.122 +				     4..0: resvd */
   4.123 +	0x00,       /*  u8  MaxPower; */
   4.124 +      
   4.125 +	/* USB 1.1:
   4.126 +	 * USB 2.0, single TT organization (mandatory):
   4.127 +	 *	one interface, protocol 0
   4.128 +	 *
   4.129 +	 * USB 2.0, multiple TT organization (optional):
   4.130 +	 *	two interfaces, protocols 1 (like single TT)
   4.131 +	 *	and 2 (multiple TT mode) ... config is
   4.132 +	 *	sometimes settable
   4.133 +	 *	NOT IMPLEMENTED
   4.134 +	 */
   4.135 +
   4.136 +	/* one interface */
   4.137 +	0x09,       /*  u8  if_bLength; */
   4.138 +	0x04,       /*  u8  if_bDescriptorType; Interface */
   4.139 +	0x00,       /*  u8  if_bInterfaceNumber; */
   4.140 +	0x00,       /*  u8  if_bAlternateSetting; */
   4.141 +	0x01,       /*  u8  if_bNumEndpoints; */
   4.142 +	0x09,       /*  u8  if_bInterfaceClass; HUB_CLASSCODE */
   4.143 +	0x00,       /*  u8  if_bInterfaceSubClass; */
   4.144 +	0x00,       /*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
   4.145 +	0x00,       /*  u8  if_iInterface; */
   4.146 +     
   4.147 +	/* one endpoint (status change endpoint) */
   4.148 +	0x07,       /*  u8  ep_bLength; */
   4.149 +	0x05,       /*  u8  ep_bDescriptorType; Endpoint */
   4.150 +	0x81,       /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
   4.151 + 	0x03,       /*  u8  ep_bmAttributes; Interrupt */
   4.152 + 	0x02, 0x00, /*  u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
   4.153 +	0xff        /*  u8  ep_bInterval; (255ms -- usb 2.0 spec) */
   4.154 +};
   4.155 +
   4.156 +static const uint8_t qemu_hub_hub_descriptor[] =
   4.157 +{
   4.158 +	0x09,			/*  u8  bLength; */
   4.159 +	0x29,			/*  u8  bDescriptorType; Hub-descriptor */
   4.160 +	0x00,			/*  u8  bNbrPorts; (patched later) */
   4.161 +	0x0a,			/* u16  wHubCharacteristics; */
   4.162 +	0x00,			/*   (per-port OC, no power switching) */
   4.163 +	0x01,			/*  u8  bPwrOn2pwrGood; 2ms */
   4.164 +	0x00			/*  u8  bHubContrCurrent; 0 mA */
   4.165 +
   4.166 +        /* DeviceRemovable and PortPwrCtrlMask patched in later */
   4.167 +};
   4.168 +
   4.169 +static void usb_hub_attach(USBPort *port1, USBDevice *dev)
   4.170 +{
   4.171 +    USBHubState *s = port1->opaque;
   4.172 +    USBHubPort *port = &s->ports[port1->index];
   4.173 +    
   4.174 +    if (dev) {
   4.175 +        if (port->port.dev)
   4.176 +            usb_attach(port1, NULL);
   4.177 +        
   4.178 +        port->wPortStatus |= PORT_STAT_CONNECTION;
   4.179 +        port->wPortChange |= PORT_STAT_C_CONNECTION;
   4.180 +        if (dev->speed == USB_SPEED_LOW)
   4.181 +            port->wPortStatus |= PORT_STAT_LOW_SPEED;
   4.182 +        else
   4.183 +            port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
   4.184 +        port->port.dev = dev;
   4.185 +    } else {
   4.186 +        dev = port->port.dev;
   4.187 +        if (dev) {
   4.188 +            port->wPortStatus &= ~PORT_STAT_CONNECTION;
   4.189 +            port->wPortChange |= PORT_STAT_C_CONNECTION;
   4.190 +            if (port->wPortStatus & PORT_STAT_ENABLE) {
   4.191 +                port->wPortStatus &= ~PORT_STAT_ENABLE;
   4.192 +                port->wPortChange |= PORT_STAT_C_ENABLE;
   4.193 +            }
   4.194 +            port->port.dev = NULL;
   4.195 +        }
   4.196 +    }
   4.197 +}
   4.198 +
   4.199 +static void usb_hub_handle_reset(USBDevice *dev)
   4.200 +{
   4.201 +    /* XXX: do it */
   4.202 +}
   4.203 +
   4.204 +static int usb_hub_handle_control(USBDevice *dev, int request, int value,
   4.205 +                                  int index, int length, uint8_t *data)
   4.206 +{
   4.207 +    USBHubState *s = (USBHubState *)dev;
   4.208 +    int ret;
   4.209 +
   4.210 +    switch(request) {
   4.211 +    case DeviceRequest | USB_REQ_GET_STATUS:
   4.212 +        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
   4.213 +            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
   4.214 +        data[1] = 0x00;
   4.215 +        ret = 2;
   4.216 +        break;
   4.217 +    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
   4.218 +        if (value == USB_DEVICE_REMOTE_WAKEUP) {
   4.219 +            dev->remote_wakeup = 0;
   4.220 +        } else {
   4.221 +            goto fail;
   4.222 +        }
   4.223 +        ret = 0;
   4.224 +        break;
   4.225 +    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
   4.226 +        if (value == 0 && index != 0x81) { /* clear ep halt */
   4.227 +            goto fail;
   4.228 +        }
   4.229 +        ret = 0;
   4.230 +        break;
   4.231 +    case DeviceOutRequest | USB_REQ_SET_FEATURE:
   4.232 +        if (value == USB_DEVICE_REMOTE_WAKEUP) {
   4.233 +            dev->remote_wakeup = 1;
   4.234 +        } else {
   4.235 +            goto fail;
   4.236 +        }
   4.237 +        ret = 0;
   4.238 +        break;
   4.239 +    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
   4.240 +        dev->addr = value;
   4.241 +        ret = 0;
   4.242 +        break;
   4.243 +    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
   4.244 +        switch(value >> 8) {
   4.245 +        case USB_DT_DEVICE:
   4.246 +            memcpy(data, qemu_hub_dev_descriptor, 
   4.247 +                   sizeof(qemu_hub_dev_descriptor));
   4.248 +            ret = sizeof(qemu_hub_dev_descriptor);
   4.249 +            break;
   4.250 +        case USB_DT_CONFIG:
   4.251 +            memcpy(data, qemu_hub_config_descriptor, 
   4.252 +                   sizeof(qemu_hub_config_descriptor));
   4.253 +
   4.254 +            /* status change endpoint size based on number
   4.255 +             * of ports */
   4.256 +            data[22] = (s->nb_ports + 1 + 7) / 8;
   4.257 +
   4.258 +            ret = sizeof(qemu_hub_config_descriptor);
   4.259 +            break;
   4.260 +        case USB_DT_STRING:
   4.261 +            switch(value & 0xff) {
   4.262 +            case 0:
   4.263 +                /* language ids */
   4.264 +                data[0] = 4;
   4.265 +                data[1] = 3;
   4.266 +                data[2] = 0x09;
   4.267 +                data[3] = 0x04;
   4.268 +                ret = 4;
   4.269 +                break;
   4.270 +            case 1:
   4.271 +                /* serial number */
   4.272 +                ret = set_usb_string(data, "314159");
   4.273 +                break;
   4.274 +            case 2:
   4.275 +                /* product description */
   4.276 +                ret = set_usb_string(data, "QEMU USB Hub");
   4.277 +                break;
   4.278 +            case 3:
   4.279 +                /* vendor description */
   4.280 +                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
   4.281 +                break;
   4.282 +            default:
   4.283 +                goto fail;
   4.284 +            }
   4.285 +            break;
   4.286 +        default:
   4.287 +            goto fail;
   4.288 +        }
   4.289 +        break;
   4.290 +    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
   4.291 +        data[0] = 1;
   4.292 +        ret = 1;
   4.293 +        break;
   4.294 +    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
   4.295 +        ret = 0;
   4.296 +        break;
   4.297 +    case DeviceRequest | USB_REQ_GET_INTERFACE:
   4.298 +        data[0] = 0;
   4.299 +        ret = 1;
   4.300 +        break;
   4.301 +    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
   4.302 +        ret = 0;
   4.303 +        break;
   4.304 +        /* usb specific requests */
   4.305 +    case GetHubStatus:
   4.306 +        data[0] = 0;
   4.307 +        data[1] = 0;
   4.308 +        data[2] = 0;
   4.309 +        data[3] = 0;
   4.310 +        ret = 4;
   4.311 +        break;
   4.312 +    case GetPortStatus:
   4.313 +        {
   4.314 +            unsigned int n = index - 1;
   4.315 +            USBHubPort *port;
   4.316 +            if (n >= s->nb_ports)
   4.317 +                goto fail;
   4.318 +            port = &s->ports[n];
   4.319 +            data[0] = port->wPortStatus;
   4.320 +            data[1] = port->wPortStatus >> 8;
   4.321 +            data[2] = port->wPortChange;
   4.322 +            data[3] = port->wPortChange >> 8;
   4.323 +            ret = 4;
   4.324 +        }
   4.325 +        break;
   4.326 +    case SetHubFeature:
   4.327 +    case ClearHubFeature:
   4.328 +        if (value == 0 || value == 1) {
   4.329 +        } else {
   4.330 +            goto fail;
   4.331 +        }
   4.332 +        ret = 0;
   4.333 +        break;
   4.334 +    case SetPortFeature:
   4.335 +        {
   4.336 +            unsigned int n = index - 1;
   4.337 +            USBHubPort *port;
   4.338 +            USBDevice *dev;
   4.339 +            if (n >= s->nb_ports)
   4.340 +                goto fail;
   4.341 +            port = &s->ports[n];
   4.342 +            dev = port->port.dev;
   4.343 +            switch(value) {
   4.344 +            case PORT_SUSPEND:
   4.345 +                port->wPortStatus |= PORT_STAT_SUSPEND;
   4.346 +                break;
   4.347 +            case PORT_RESET:
   4.348 +                if (dev) {
   4.349 +                    dev->handle_packet(dev, 
   4.350 +                                       USB_MSG_RESET, 0, 0, NULL, 0);
   4.351 +                    port->wPortChange |= PORT_STAT_C_RESET;
   4.352 +                    /* set enable bit */
   4.353 +                    port->wPortStatus |= PORT_STAT_ENABLE;
   4.354 +                }
   4.355 +                break;
   4.356 +            case PORT_POWER:
   4.357 +                break;
   4.358 +            default:
   4.359 +                goto fail;
   4.360 +            }
   4.361 +            ret = 0;
   4.362 +        }
   4.363 +        break;
   4.364 +    case ClearPortFeature:
   4.365 +        {
   4.366 +            unsigned int n = index - 1;
   4.367 +            USBHubPort *port;
   4.368 +            USBDevice *dev;
   4.369 +            if (n >= s->nb_ports)
   4.370 +                goto fail;
   4.371 +            port = &s->ports[n];
   4.372 +            dev = port->port.dev;
   4.373 +            switch(value) {
   4.374 +            case PORT_ENABLE:
   4.375 +                port->wPortStatus &= ~PORT_STAT_ENABLE;
   4.376 +                break;
   4.377 +            case PORT_C_ENABLE:
   4.378 +                port->wPortChange &= ~PORT_STAT_C_ENABLE;
   4.379 +                break;
   4.380 +            case PORT_SUSPEND:
   4.381 +                port->wPortStatus &= ~PORT_STAT_SUSPEND;
   4.382 +                break;
   4.383 +            case PORT_C_SUSPEND:
   4.384 +                port->wPortChange &= ~PORT_STAT_C_SUSPEND;
   4.385 +                break;
   4.386 +            case PORT_C_CONNECTION:
   4.387 +                port->wPortChange &= ~PORT_STAT_C_CONNECTION;
   4.388 +                break;
   4.389 +            case PORT_C_OVERCURRENT:
   4.390 +                port->wPortChange &= ~PORT_STAT_C_OVERCURRENT;
   4.391 +                break;
   4.392 +            case PORT_C_RESET:
   4.393 +                port->wPortChange &= ~PORT_STAT_C_RESET;
   4.394 +                break;
   4.395 +            default:
   4.396 +                goto fail;
   4.397 +            }
   4.398 +            ret = 0;
   4.399 +        }
   4.400 +        break;
   4.401 +    case GetHubDescriptor:
   4.402 +        {
   4.403 +            unsigned int n, limit, var_hub_size = 0;
   4.404 +            memcpy(data, qemu_hub_hub_descriptor, 
   4.405 +                   sizeof(qemu_hub_hub_descriptor));
   4.406 +            data[2] = s->nb_ports;
   4.407 +
   4.408 +            /* fill DeviceRemovable bits */
   4.409 +            limit = ((s->nb_ports + 1 + 7) / 8) + 7;
   4.410 +            for (n = 7; n < limit; n++) {
   4.411 +                data[n] = 0x00;
   4.412 +                var_hub_size++;
   4.413 +            }
   4.414 +
   4.415 +            /* fill PortPwrCtrlMask bits */
   4.416 +            limit = limit + ((s->nb_ports + 7) / 8);
   4.417 +            for (;n < limit; n++) {
   4.418 +                data[n] = 0xff;
   4.419 +                var_hub_size++;
   4.420 +            }
   4.421 +
   4.422 +            ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
   4.423 +            break;
   4.424 +        }
   4.425 +    default:
   4.426 +    fail:
   4.427 +        ret = USB_RET_STALL;
   4.428 +        break;
   4.429 +    }
   4.430 +    return ret;
   4.431 +}
   4.432 +
   4.433 +static int usb_hub_handle_data(USBDevice *dev, int pid, 
   4.434 +                               uint8_t devep, uint8_t *data, int len)
   4.435 +{
   4.436 +    USBHubState *s = (USBHubState *)dev;
   4.437 +    int ret;
   4.438 +
   4.439 +    switch(pid) {
   4.440 +    case USB_TOKEN_IN:
   4.441 +        if (devep == 1) {
   4.442 +            USBHubPort *port;
   4.443 +            unsigned int status;
   4.444 +            int i, n;
   4.445 +            n = (s->nb_ports + 1 + 7) / 8;
   4.446 +            if (len == 1) { /* FreeBSD workaround */
   4.447 +                n = 1;
   4.448 +            } else if (n > len) {
   4.449 +                return USB_RET_BABBLE;
   4.450 +            }
   4.451 +            status = 0;
   4.452 +            for(i = 0; i < s->nb_ports; i++) {
   4.453 +                port = &s->ports[i];
   4.454 +                if (port->wPortChange)
   4.455 +                    status |= (1 << (i + 1));
   4.456 +            }
   4.457 +            if (status != 0) {
   4.458 +                for(i = 0; i < n; i++) {
   4.459 +                    data[i] = status >> (8 * i);
   4.460 +                }
   4.461 +                ret = n;
   4.462 +            } else {
   4.463 +                ret = USB_RET_NAK; /* usb11 11.13.1 */
   4.464 +            }
   4.465 +        } else {
   4.466 +            goto fail;
   4.467 +        }
   4.468 +        break;
   4.469 +    case USB_TOKEN_OUT:
   4.470 +    default:
   4.471 +    fail:
   4.472 +        ret = USB_RET_STALL;
   4.473 +        break;
   4.474 +    }
   4.475 +    return ret;
   4.476 +}
   4.477 +
   4.478 +static int usb_hub_broadcast_packet(USBHubState *s, int pid, 
   4.479 +                                    uint8_t devaddr, uint8_t devep,
   4.480 +                                    uint8_t *data, int len)
   4.481 +{
   4.482 +    USBHubPort *port;
   4.483 +    USBDevice *dev;
   4.484 +    int i, ret;
   4.485 +
   4.486 +    for(i = 0; i < s->nb_ports; i++) {
   4.487 +        port = &s->ports[i];
   4.488 +        dev = port->port.dev;
   4.489 +        if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
   4.490 +            ret = dev->handle_packet(dev, pid, 
   4.491 +                                     devaddr, devep,
   4.492 +                                     data, len);
   4.493 +            if (ret != USB_RET_NODEV) {
   4.494 +                return ret;
   4.495 +            }
   4.496 +        }
   4.497 +    }
   4.498 +    return USB_RET_NODEV;
   4.499 +}
   4.500 +
   4.501 +static int usb_hub_handle_packet(USBDevice *dev, int pid, 
   4.502 +                                 uint8_t devaddr, uint8_t devep,
   4.503 +                                 uint8_t *data, int len)
   4.504 +{
   4.505 +    USBHubState *s = (USBHubState *)dev;
   4.506 +
   4.507 +#if defined(DEBUG) && 0
   4.508 +    printf("usb_hub: pid=0x%x\n", pid);
   4.509 +#endif
   4.510 +    if (dev->state == USB_STATE_DEFAULT &&
   4.511 +        dev->addr != 0 &&
   4.512 +        devaddr != dev->addr &&
   4.513 +        (pid == USB_TOKEN_SETUP || 
   4.514 +         pid == USB_TOKEN_OUT || 
   4.515 +         pid == USB_TOKEN_IN)) {
   4.516 +        /* broadcast the packet to the devices */
   4.517 +        return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len);
   4.518 +    }
   4.519 +    return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len);
   4.520 +}
   4.521 +
   4.522 +USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports)
   4.523 +{
   4.524 +    USBHubState *s;
   4.525 +    USBHubPort *port;
   4.526 +    int i;
   4.527 +
   4.528 +    if (nb_ports > MAX_PORTS)
   4.529 +        return NULL;
   4.530 +    s = qemu_mallocz(sizeof(USBHubState));
   4.531 +    if (!s)
   4.532 +        return NULL;
   4.533 +    s->dev.speed = USB_SPEED_FULL;
   4.534 +    s->dev.handle_packet = usb_hub_handle_packet;
   4.535 +
   4.536 +    /* generic USB device init */
   4.537 +    s->dev.handle_reset = usb_hub_handle_reset;
   4.538 +    s->dev.handle_control = usb_hub_handle_control;
   4.539 +    s->dev.handle_data = usb_hub_handle_data;
   4.540 +
   4.541 +    s->nb_ports = nb_ports;
   4.542 +    for(i = 0; i < s->nb_ports; i++) {
   4.543 +        port = &s->ports[i];
   4.544 +        port->wPortStatus = PORT_STAT_POWER;
   4.545 +        port->wPortChange = 0;
   4.546 +        port->port.attach = usb_hub_attach;
   4.547 +        port->port.opaque = s;
   4.548 +        port->port.index = i;
   4.549 +        usb_ports[i] = &port->port;
   4.550 +    }
   4.551 +    return (USBDevice *)s;
   4.552 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/tools/ioemu/hw/usb-uhci.c	Mon Jun 12 09:06:55 2006 +0100
     5.3 @@ -0,0 +1,680 @@
     5.4 +/*
     5.5 + * USB UHCI controller emulation
     5.6 + * 
     5.7 + * Copyright (c) 2005 Fabrice Bellard
     5.8 + * 
     5.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    5.10 + * of this software and associated documentation files (the "Software"), to deal
    5.11 + * in the Software without restriction, including without limitation the rights
    5.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    5.13 + * copies of the Software, and to permit persons to whom the Software is
    5.14 + * furnished to do so, subject to the following conditions:
    5.15 + *
    5.16 + * The above copyright notice and this permission notice shall be included in
    5.17 + * all copies or substantial portions of the Software.
    5.18 + *
    5.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    5.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    5.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    5.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    5.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    5.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    5.25 + * THE SOFTWARE.
    5.26 + */
    5.27 +#include "vl.h"
    5.28 +
    5.29 +//#define DEBUG
    5.30 +//#define DEBUG_PACKET
    5.31 +
    5.32 +#define UHCI_CMD_GRESET   (1 << 2)
    5.33 +#define UHCI_CMD_HCRESET  (1 << 1)
    5.34 +#define UHCI_CMD_RS       (1 << 0)
    5.35 +
    5.36 +#define UHCI_STS_HCHALTED (1 << 5)
    5.37 +#define UHCI_STS_HCPERR   (1 << 4)
    5.38 +#define UHCI_STS_HSERR    (1 << 3)
    5.39 +#define UHCI_STS_RD       (1 << 2)
    5.40 +#define UHCI_STS_USBERR   (1 << 1)
    5.41 +#define UHCI_STS_USBINT   (1 << 0)
    5.42 +
    5.43 +#define TD_CTRL_SPD     (1 << 29)
    5.44 +#define TD_CTRL_ERROR_SHIFT  27
    5.45 +#define TD_CTRL_IOS     (1 << 25)
    5.46 +#define TD_CTRL_IOC     (1 << 24)
    5.47 +#define TD_CTRL_ACTIVE  (1 << 23)
    5.48 +#define TD_CTRL_STALL   (1 << 22)
    5.49 +#define TD_CTRL_BABBLE  (1 << 20)
    5.50 +#define TD_CTRL_NAK     (1 << 19)
    5.51 +#define TD_CTRL_TIMEOUT (1 << 18)
    5.52 +
    5.53 +#define UHCI_PORT_RESET (1 << 9)
    5.54 +#define UHCI_PORT_LSDA  (1 << 8)
    5.55 +#define UHCI_PORT_ENC   (1 << 3)
    5.56 +#define UHCI_PORT_EN    (1 << 2)
    5.57 +#define UHCI_PORT_CSC   (1 << 1)
    5.58 +#define UHCI_PORT_CCS   (1 << 0)
    5.59 +
    5.60 +#define FRAME_TIMER_FREQ 1000
    5.61 +
    5.62 +#define FRAME_MAX_LOOPS  100
    5.63 +
    5.64 +#define NB_PORTS 2
    5.65 +
    5.66 +typedef struct UHCIPort {
    5.67 +    USBPort port;
    5.68 +    uint16_t ctrl;
    5.69 +} UHCIPort;
    5.70 +
    5.71 +typedef struct UHCIState {
    5.72 +    PCIDevice dev;
    5.73 +    uint16_t cmd; /* cmd register */
    5.74 +    uint16_t status;
    5.75 +    uint16_t intr; /* interrupt enable register */
    5.76 +    uint16_t frnum; /* frame number */
    5.77 +    uint32_t fl_base_addr; /* frame list base address */
    5.78 +    uint8_t sof_timing;
    5.79 +    uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */
    5.80 +    QEMUTimer *frame_timer;
    5.81 +    UHCIPort ports[NB_PORTS];
    5.82 +} UHCIState;
    5.83 +
    5.84 +typedef struct UHCI_TD {
    5.85 +    uint32_t link;
    5.86 +    uint32_t ctrl; /* see TD_CTRL_xxx */
    5.87 +    uint32_t token;
    5.88 +    uint32_t buffer;
    5.89 +} UHCI_TD;
    5.90 +
    5.91 +typedef struct UHCI_QH {
    5.92 +    uint32_t link;
    5.93 +    uint32_t el_link;
    5.94 +} UHCI_QH;
    5.95 +
    5.96 +static void uhci_attach(USBPort *port1, USBDevice *dev);
    5.97 +
    5.98 +static void uhci_update_irq(UHCIState *s)
    5.99 +{
   5.100 +    int level;
   5.101 +    if (((s->status2 & 1) && (s->intr & (1 << 2))) ||
   5.102 +        ((s->status2 & 2) && (s->intr & (1 << 3))) ||
   5.103 +        ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) ||
   5.104 +        ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) ||
   5.105 +        (s->status & UHCI_STS_HSERR) ||
   5.106 +        (s->status & UHCI_STS_HCPERR)) {
   5.107 +        level = 1;
   5.108 +    } else {
   5.109 +        level = 0;
   5.110 +    }
   5.111 +    pci_set_irq(&s->dev, 3, level);
   5.112 +}
   5.113 +
   5.114 +static void uhci_reset(UHCIState *s)
   5.115 +{
   5.116 +    uint8_t *pci_conf;
   5.117 +    int i;
   5.118 +    UHCIPort *port;
   5.119 +
   5.120 +    pci_conf = s->dev.config;
   5.121 +
   5.122 +    pci_conf[0x6a] = 0x01; /* usb clock */
   5.123 +    pci_conf[0x6b] = 0x00;
   5.124 +    s->cmd = 0;
   5.125 +    s->status = 0;
   5.126 +    s->status2 = 0;
   5.127 +    s->intr = 0;
   5.128 +    s->fl_base_addr = 0;
   5.129 +    s->sof_timing = 64;
   5.130 +    for(i = 0; i < NB_PORTS; i++) {
   5.131 +        port = &s->ports[i];
   5.132 +        port->ctrl = 0x0080;
   5.133 +        if (port->port.dev)
   5.134 +            uhci_attach(&port->port, port->port.dev);
   5.135 +    }
   5.136 +}
   5.137 +
   5.138 +static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
   5.139 +{
   5.140 +    UHCIState *s = opaque;
   5.141 +    
   5.142 +    addr &= 0x1f;
   5.143 +    switch(addr) {
   5.144 +    case 0x0c:
   5.145 +        s->sof_timing = val;
   5.146 +        break;
   5.147 +    }
   5.148 +}
   5.149 +
   5.150 +static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr)
   5.151 +{
   5.152 +    UHCIState *s = opaque;
   5.153 +    uint32_t val;
   5.154 +
   5.155 +    addr &= 0x1f;
   5.156 +    switch(addr) {
   5.157 +    case 0x0c:
   5.158 +        val = s->sof_timing;
   5.159 +        break;
   5.160 +    default:
   5.161 +        val = 0xff;
   5.162 +        break;
   5.163 +    }
   5.164 +    return val;
   5.165 +}
   5.166 +
   5.167 +static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
   5.168 +{
   5.169 +    UHCIState *s = opaque;
   5.170 +    
   5.171 +    addr &= 0x1f;
   5.172 +#ifdef DEBUG
   5.173 +    printf("uhci writew port=0x%04x val=0x%04x\n", addr, val);
   5.174 +#endif
   5.175 +    switch(addr) {
   5.176 +    case 0x00:
   5.177 +        if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
   5.178 +            /* start frame processing */
   5.179 +            qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock));
   5.180 +            s->status &= ~UHCI_STS_HCHALTED;
   5.181 +        } else if (!(val & UHCI_CMD_RS)) {
   5.182 +            s->status |= UHCI_STS_HCHALTED;
   5.183 +        }
   5.184 +        if (val & UHCI_CMD_GRESET) {
   5.185 +            UHCIPort *port;
   5.186 +            USBDevice *dev;
   5.187 +            int i;
   5.188 +
   5.189 +            /* send reset on the USB bus */
   5.190 +            for(i = 0; i < NB_PORTS; i++) {
   5.191 +                port = &s->ports[i];
   5.192 +                dev = port->port.dev;
   5.193 +                if (dev) {
   5.194 +                    dev->handle_packet(dev, 
   5.195 +                                       USB_MSG_RESET, 0, 0, NULL, 0);
   5.196 +                }
   5.197 +            }
   5.198 +            uhci_reset(s);
   5.199 +            return;
   5.200 +        }
   5.201 +        if (val & UHCI_CMD_HCRESET) {
   5.202 +            uhci_reset(s);
   5.203 +            return;
   5.204 +        }
   5.205 +        s->cmd = val;
   5.206 +        break;
   5.207 +    case 0x02:
   5.208 +        s->status &= ~val;
   5.209 +        /* XXX: the chip spec is not coherent, so we add a hidden
   5.210 +           register to distinguish between IOC and SPD */
   5.211 +        if (val & UHCI_STS_USBINT)
   5.212 +            s->status2 = 0;
   5.213 +        uhci_update_irq(s);
   5.214 +        break;
   5.215 +    case 0x04:
   5.216 +        s->intr = val;
   5.217 +        uhci_update_irq(s);
   5.218 +        break;
   5.219 +    case 0x06:
   5.220 +        if (s->status & UHCI_STS_HCHALTED)
   5.221 +            s->frnum = val & 0x7ff;
   5.222 +        break;
   5.223 +    case 0x10 ... 0x1f:
   5.224 +        {
   5.225 +            UHCIPort *port;
   5.226 +            USBDevice *dev;
   5.227 +            int n;
   5.228 +
   5.229 +            n = (addr >> 1) & 7;
   5.230 +            if (n >= NB_PORTS)
   5.231 +                return;
   5.232 +            port = &s->ports[n];
   5.233 +            dev = port->port.dev;
   5.234 +            if (dev) {
   5.235 +                /* port reset */
   5.236 +                if ( (val & UHCI_PORT_RESET) && 
   5.237 +                     !(port->ctrl & UHCI_PORT_RESET) ) {
   5.238 +                    dev->handle_packet(dev, 
   5.239 +                                       USB_MSG_RESET, 0, 0, NULL, 0);
   5.240 +                }
   5.241 +            }
   5.242 +            port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb);
   5.243 +            /* some bits are reset when a '1' is written to them */
   5.244 +            port->ctrl &= ~(val & 0x000a);
   5.245 +        }
   5.246 +        break;
   5.247 +    }
   5.248 +}
   5.249 +
   5.250 +static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr)
   5.251 +{
   5.252 +    UHCIState *s = opaque;
   5.253 +    uint32_t val;
   5.254 +
   5.255 +    addr &= 0x1f;
   5.256 +    switch(addr) {
   5.257 +    case 0x00:
   5.258 +        val = s->cmd;
   5.259 +        break;
   5.260 +    case 0x02:
   5.261 +        val = s->status;
   5.262 +        break;
   5.263 +    case 0x04:
   5.264 +        val = s->intr;
   5.265 +        break;
   5.266 +    case 0x06:
   5.267 +        val = s->frnum;
   5.268 +        break;
   5.269 +    case 0x10 ... 0x1f:
   5.270 +        {
   5.271 +            UHCIPort *port;
   5.272 +            int n;
   5.273 +            n = (addr >> 1) & 7;
   5.274 +            if (n >= NB_PORTS) 
   5.275 +                goto read_default;
   5.276 +            port = &s->ports[n];
   5.277 +            val = port->ctrl;
   5.278 +        }
   5.279 +        break;
   5.280 +    default:
   5.281 +    read_default:
   5.282 +        val = 0xff7f; /* disabled port */
   5.283 +        break;
   5.284 +    }
   5.285 +#ifdef DEBUG
   5.286 +    printf("uhci readw port=0x%04x val=0x%04x\n", addr, val);
   5.287 +#endif
   5.288 +    return val;
   5.289 +}
   5.290 +
   5.291 +static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
   5.292 +{
   5.293 +    UHCIState *s = opaque;
   5.294 +
   5.295 +    addr &= 0x1f;
   5.296 +#ifdef DEBUG
   5.297 +    printf("uhci writel port=0x%04x val=0x%08x\n", addr, val);
   5.298 +#endif
   5.299 +    switch(addr) {
   5.300 +    case 0x08:
   5.301 +        s->fl_base_addr = val & ~0xfff;
   5.302 +        break;
   5.303 +    }
   5.304 +}
   5.305 +
   5.306 +static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr)
   5.307 +{
   5.308 +    UHCIState *s = opaque;
   5.309 +    uint32_t val;
   5.310 +
   5.311 +    addr &= 0x1f;
   5.312 +    switch(addr) {
   5.313 +    case 0x08:
   5.314 +        val = s->fl_base_addr;
   5.315 +        break;
   5.316 +    default:
   5.317 +        val = 0xffffffff;
   5.318 +        break;
   5.319 +    }
   5.320 +    return val;
   5.321 +}
   5.322 +
   5.323 +static void uhci_attach(USBPort *port1, USBDevice *dev)
   5.324 +{
   5.325 +    UHCIState *s = port1->opaque;
   5.326 +    UHCIPort *port = &s->ports[port1->index];
   5.327 +
   5.328 +    if (dev) {
   5.329 +        if (port->port.dev) {
   5.330 +            usb_attach(port1, NULL);
   5.331 +        }
   5.332 +        /* set connect status */
   5.333 +        if (!(port->ctrl & UHCI_PORT_CCS)) {
   5.334 +            port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
   5.335 +        }
   5.336 +        /* update speed */
   5.337 +        if (dev->speed == USB_SPEED_LOW)
   5.338 +            port->ctrl |= UHCI_PORT_LSDA;
   5.339 +        else
   5.340 +            port->ctrl &= ~UHCI_PORT_LSDA;
   5.341 +        port->port.dev = dev;
   5.342 +        /* send the attach message */
   5.343 +        dev->handle_packet(dev, 
   5.344 +                           USB_MSG_ATTACH, 0, 0, NULL, 0);
   5.345 +    } else {
   5.346 +        /* set connect status */
   5.347 +        if (!(port->ctrl & UHCI_PORT_CCS)) {
   5.348 +            port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
   5.349 +        }
   5.350 +        /* disable port */
   5.351 +        if (port->ctrl & UHCI_PORT_EN) {
   5.352 +            port->ctrl &= ~UHCI_PORT_EN;
   5.353 +            port->ctrl |= UHCI_PORT_ENC;
   5.354 +        }
   5.355 +        dev = port->port.dev;
   5.356 +        if (dev) {
   5.357 +            /* send the detach message */
   5.358 +            dev->handle_packet(dev, 
   5.359 +                               USB_MSG_DETACH, 0, 0, NULL, 0);
   5.360 +        }
   5.361 +        port->port.dev = NULL;
   5.362 +    }
   5.363 +}
   5.364 +
   5.365 +static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, 
   5.366 +                                 uint8_t devaddr, uint8_t devep,
   5.367 +                                 uint8_t *data, int len)
   5.368 +{
   5.369 +    UHCIPort *port;
   5.370 +    USBDevice *dev;
   5.371 +    int i, ret;
   5.372 +
   5.373 +#ifdef DEBUG_PACKET
   5.374 +    {
   5.375 +        const char *pidstr;
   5.376 +        switch(pid) {
   5.377 +        case USB_TOKEN_SETUP: pidstr = "SETUP"; break;
   5.378 +        case USB_TOKEN_IN: pidstr = "IN"; break;
   5.379 +        case USB_TOKEN_OUT: pidstr = "OUT"; break;
   5.380 +        default: pidstr = "?"; break;
   5.381 +        }
   5.382 +        printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n",
   5.383 +               s->frnum, pidstr, devaddr, devep, len);
   5.384 +        if (pid != USB_TOKEN_IN) {
   5.385 +            printf("     data_out=");
   5.386 +            for(i = 0; i < len; i++) {
   5.387 +                printf(" %02x", data[i]);
   5.388 +            }
   5.389 +            printf("\n");
   5.390 +        }
   5.391 +    }
   5.392 +#endif
   5.393 +    for(i = 0; i < NB_PORTS; i++) {
   5.394 +        port = &s->ports[i];
   5.395 +        dev = port->port.dev;
   5.396 +        if (dev && (port->ctrl & UHCI_PORT_EN)) {
   5.397 +            ret = dev->handle_packet(dev, pid, 
   5.398 +                                     devaddr, devep,
   5.399 +                                     data, len);
   5.400 +            if (ret != USB_RET_NODEV) {
   5.401 +#ifdef DEBUG_PACKET
   5.402 +                {
   5.403 +                    printf("     ret=%d ", ret);
   5.404 +                    if (pid == USB_TOKEN_IN && ret > 0) {
   5.405 +                        printf("data_in=");
   5.406 +                        for(i = 0; i < ret; i++) {
   5.407 +                            printf(" %02x", data[i]);
   5.408 +                        }
   5.409 +                    }
   5.410 +                    printf("\n");
   5.411 +                }
   5.412 +#endif
   5.413 +                return ret;
   5.414 +            }
   5.415 +        }
   5.416 +    }
   5.417 +    return USB_RET_NODEV;
   5.418 +}
   5.419 +
   5.420 +/* return -1 if fatal error (frame must be stopped)
   5.421 +          0 if TD successful
   5.422 +          1 if TD unsuccessful or inactive
   5.423 +*/
   5.424 +static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask)
   5.425 +{
   5.426 +    uint8_t pid;
   5.427 +    uint8_t buf[1280];
   5.428 +    int len, max_len, err, ret;
   5.429 +
   5.430 +    if (td->ctrl & TD_CTRL_IOC) {
   5.431 +        *int_mask |= 0x01;
   5.432 +    }
   5.433 +    
   5.434 +    if (!(td->ctrl & TD_CTRL_ACTIVE))
   5.435 +        return 1;
   5.436 +
   5.437 +    /* TD is active */
   5.438 +    max_len = ((td->token >> 21) + 1) & 0x7ff;
   5.439 +    pid = td->token & 0xff;
   5.440 +    switch(pid) {
   5.441 +    case USB_TOKEN_OUT:
   5.442 +    case USB_TOKEN_SETUP:
   5.443 +        cpu_physical_memory_read(td->buffer, buf, max_len);
   5.444 +        ret = uhci_broadcast_packet(s, pid, 
   5.445 +                                    (td->token >> 8) & 0x7f,
   5.446 +                                    (td->token >> 15) & 0xf,
   5.447 +                                    buf, max_len);
   5.448 +        len = max_len;
   5.449 +        break;
   5.450 +    case USB_TOKEN_IN:
   5.451 +        ret = uhci_broadcast_packet(s, pid, 
   5.452 +                                    (td->token >> 8) & 0x7f,
   5.453 +                                    (td->token >> 15) & 0xf,
   5.454 +                                    buf, max_len);
   5.455 +        if (ret >= 0) {
   5.456 +            len = ret;
   5.457 +            if (len > max_len) {
   5.458 +                len = max_len;
   5.459 +                ret = USB_RET_BABBLE;
   5.460 +            }
   5.461 +            if (len > 0) {
   5.462 +                /* write the data back */
   5.463 +                cpu_physical_memory_write(td->buffer, buf, len);
   5.464 +            }
   5.465 +        } else {
   5.466 +            len = 0;
   5.467 +        }
   5.468 +        break;
   5.469 +    default:
   5.470 +        /* invalid pid : frame interrupted */
   5.471 +        s->status |= UHCI_STS_HCPERR;
   5.472 +        uhci_update_irq(s);
   5.473 +        return -1;
   5.474 +    }
   5.475 +    if (td->ctrl & TD_CTRL_IOS)
   5.476 +        td->ctrl &= ~TD_CTRL_ACTIVE;
   5.477 +    if (ret >= 0) {
   5.478 +        td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
   5.479 +        td->ctrl &= ~TD_CTRL_ACTIVE;
   5.480 +        if (pid == USB_TOKEN_IN && 
   5.481 +            (td->ctrl & TD_CTRL_SPD) &&
   5.482 +            len < max_len) {
   5.483 +            *int_mask |= 0x02;
   5.484 +            /* short packet: do not update QH */
   5.485 +            return 1;
   5.486 +        } else {
   5.487 +            /* success */
   5.488 +            return 0;
   5.489 +        }
   5.490 +    } else {
   5.491 +        switch(ret) {
   5.492 +        default:
   5.493 +        case USB_RET_NODEV:
   5.494 +        do_timeout:
   5.495 +            td->ctrl |= TD_CTRL_TIMEOUT;
   5.496 +            err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3;
   5.497 +            if (err != 0) {
   5.498 +                err--;
   5.499 +                if (err == 0) {
   5.500 +                    td->ctrl &= ~TD_CTRL_ACTIVE;
   5.501 +                    s->status |= UHCI_STS_USBERR;
   5.502 +                    uhci_update_irq(s);
   5.503 +                }
   5.504 +            }
   5.505 +            td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | 
   5.506 +                (err << TD_CTRL_ERROR_SHIFT);
   5.507 +            return 1;
   5.508 +        case USB_RET_NAK:
   5.509 +            td->ctrl |= TD_CTRL_NAK;
   5.510 +            if (pid == USB_TOKEN_SETUP)
   5.511 +                goto do_timeout;
   5.512 +            return 1;
   5.513 +        case USB_RET_STALL:
   5.514 +            td->ctrl |= TD_CTRL_STALL;
   5.515 +            td->ctrl &= ~TD_CTRL_ACTIVE;
   5.516 +            return 1;
   5.517 +        case USB_RET_BABBLE:
   5.518 +            td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
   5.519 +            td->ctrl &= ~TD_CTRL_ACTIVE;
   5.520 +            /* frame interrupted */
   5.521 +            return -1;
   5.522 +        }
   5.523 +    }
   5.524 +}
   5.525 +
   5.526 +static void uhci_frame_timer(void *opaque)
   5.527 +{
   5.528 +    UHCIState *s = opaque;
   5.529 +    int64_t expire_time;
   5.530 +    uint32_t frame_addr, link, old_td_ctrl, val;
   5.531 +    int int_mask, cnt, ret;
   5.532 +    UHCI_TD td;
   5.533 +    UHCI_QH qh;
   5.534 +
   5.535 +    if (!(s->cmd & UHCI_CMD_RS)) {
   5.536 +        qemu_del_timer(s->frame_timer);
   5.537 +        /* set hchalted bit in status - UHCI11D 2.1.2 */
   5.538 +        s->status |= UHCI_STS_HCHALTED;
   5.539 +        return;
   5.540 +    }
   5.541 +    frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);
   5.542 +    cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4);
   5.543 +    le32_to_cpus(&link);
   5.544 +    int_mask = 0;
   5.545 +    cnt = FRAME_MAX_LOOPS;
   5.546 +    while ((link & 1) == 0) {
   5.547 +        if (--cnt == 0)
   5.548 +            break;
   5.549 +        /* valid frame */
   5.550 +        if (link & 2) {
   5.551 +            /* QH */
   5.552 +            cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh));
   5.553 +            le32_to_cpus(&qh.link);
   5.554 +            le32_to_cpus(&qh.el_link);
   5.555 +        depth_first:
   5.556 +            if (qh.el_link & 1) {
   5.557 +                /* no element : go to next entry */
   5.558 +                link = qh.link;
   5.559 +            } else if (qh.el_link & 2) {
   5.560 +                /* QH */
   5.561 +                link = qh.el_link;
   5.562 +            } else {
   5.563 +                /* TD */
   5.564 +                if (--cnt == 0)
   5.565 +                    break;
   5.566 +                cpu_physical_memory_read(qh.el_link & ~0xf, 
   5.567 +                                         (uint8_t *)&td, sizeof(td));
   5.568 +                le32_to_cpus(&td.link);
   5.569 +                le32_to_cpus(&td.ctrl);
   5.570 +                le32_to_cpus(&td.token);
   5.571 +                le32_to_cpus(&td.buffer);
   5.572 +                old_td_ctrl = td.ctrl;
   5.573 +                ret = uhci_handle_td(s, &td, &int_mask);
   5.574 +                /* update the status bits of the TD */
   5.575 +                if (old_td_ctrl != td.ctrl) {
   5.576 +                    val = cpu_to_le32(td.ctrl);
   5.577 +                    cpu_physical_memory_write((qh.el_link & ~0xf) + 4, 
   5.578 +                                              (const uint8_t *)&val, 
   5.579 +                                              sizeof(val));
   5.580 +                }
   5.581 +                if (ret < 0)
   5.582 +                    break; /* interrupted frame */
   5.583 +                if (ret == 0) {
   5.584 +                    /* update qh element link */
   5.585 +                    qh.el_link = td.link;
   5.586 +                    val = cpu_to_le32(qh.el_link);
   5.587 +                    cpu_physical_memory_write((link & ~0xf) + 4, 
   5.588 +                                              (const uint8_t *)&val, 
   5.589 +                                              sizeof(val));
   5.590 +                    if (qh.el_link & 4) {
   5.591 +                        /* depth first */
   5.592 +                        goto depth_first;
   5.593 +                    }
   5.594 +                }
   5.595 +                /* go to next entry */
   5.596 +                link = qh.link;
   5.597 +            }
   5.598 +        } else {
   5.599 +            /* TD */
   5.600 +            cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td));
   5.601 +            le32_to_cpus(&td.link);
   5.602 +            le32_to_cpus(&td.ctrl);
   5.603 +            le32_to_cpus(&td.token);
   5.604 +            le32_to_cpus(&td.buffer);
   5.605 +            old_td_ctrl = td.ctrl;
   5.606 +            ret = uhci_handle_td(s, &td, &int_mask);
   5.607 +            /* update the status bits of the TD */
   5.608 +            if (old_td_ctrl != td.ctrl) {
   5.609 +                val = cpu_to_le32(td.ctrl);
   5.610 +                cpu_physical_memory_write((link & ~0xf) + 4, 
   5.611 +                                          (const uint8_t *)&val, 
   5.612 +                                          sizeof(val));
   5.613 +            }
   5.614 +            if (ret < 0)
   5.615 +                break; /* interrupted frame */
   5.616 +            link = td.link;
   5.617 +        }
   5.618 +    }
   5.619 +    s->frnum = (s->frnum + 1) & 0x7ff;
   5.620 +    if (int_mask) {
   5.621 +        s->status2 |= int_mask;
   5.622 +        s->status |= UHCI_STS_USBINT;
   5.623 +        uhci_update_irq(s);
   5.624 +    }
   5.625 +    /* prepare the timer for the next frame */
   5.626 +    expire_time = qemu_get_clock(vm_clock) + 
   5.627 +        (ticks_per_sec / FRAME_TIMER_FREQ);
   5.628 +    qemu_mod_timer(s->frame_timer, expire_time);
   5.629 +}
   5.630 +
   5.631 +static void uhci_map(PCIDevice *pci_dev, int region_num, 
   5.632 +                    uint32_t addr, uint32_t size, int type)
   5.633 +{
   5.634 +    UHCIState *s = (UHCIState *)pci_dev;
   5.635 +
   5.636 +    register_ioport_write(addr, 32, 2, uhci_ioport_writew, s);
   5.637 +    register_ioport_read(addr, 32, 2, uhci_ioport_readw, s);
   5.638 +    register_ioport_write(addr, 32, 4, uhci_ioport_writel, s);
   5.639 +    register_ioport_read(addr, 32, 4, uhci_ioport_readl, s);
   5.640 +    register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s);
   5.641 +    register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
   5.642 +}
   5.643 +
   5.644 +void usb_uhci_init(PCIBus *bus, USBPort **usb_ports)
   5.645 +{
   5.646 +    UHCIState *s;
   5.647 +    uint8_t *pci_conf;
   5.648 +    UHCIPort *port;
   5.649 +    int i;
   5.650 +
   5.651 +    s = (UHCIState *)pci_register_device(bus,
   5.652 +                                        "USB-UHCI", sizeof(UHCIState),
   5.653 +                                        ((PCIDevice *)piix3_state)->devfn + 2, 
   5.654 +                                        NULL, NULL);
   5.655 +    pci_conf = s->dev.config;
   5.656 +    pci_conf[0x00] = 0x86;
   5.657 +    pci_conf[0x01] = 0x80;
   5.658 +    pci_conf[0x02] = 0x20;
   5.659 +    pci_conf[0x03] = 0x70;
   5.660 +    pci_conf[0x08] = 0x01; // revision number
   5.661 +    pci_conf[0x09] = 0x00;
   5.662 +    pci_conf[0x0a] = 0x03;
   5.663 +    pci_conf[0x0b] = 0x0c;
   5.664 +    pci_conf[0x0e] = 0x00; // header_type
   5.665 +    pci_conf[0x3d] = 4; // interrupt pin 3
   5.666 +    pci_conf[0x60] = 0x10; // release number
   5.667 +    
   5.668 +    for(i = 0; i < NB_PORTS; i++) {
   5.669 +        port = &s->ports[i];
   5.670 +        port->port.opaque = s;
   5.671 +        port->port.index = i;
   5.672 +        port->port.attach = uhci_attach;
   5.673 +        usb_ports[i] = &port->port;
   5.674 +    }
   5.675 +    s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
   5.676 +
   5.677 +    uhci_reset(s);
   5.678 +
   5.679 +    /* Use region 4 for consistency with real hardware.  BSD guests seem
   5.680 +       to rely on this.  */
   5.681 +    pci_register_io_region(&s->dev, 4, 0x20, 
   5.682 +                           PCI_ADDRESS_SPACE_IO, uhci_map);
   5.683 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tools/ioemu/hw/usb.c	Mon Jun 12 09:06:55 2006 +0100
     6.3 @@ -0,0 +1,193 @@
     6.4 +/*
     6.5 + * QEMU USB emulation
     6.6 + *
     6.7 + * Copyright (c) 2005 Fabrice Bellard
     6.8 + * 
     6.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    6.10 + * of this software and associated documentation files (the "Software"), to deal
    6.11 + * in the Software without restriction, including without limitation the rights
    6.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    6.13 + * copies of the Software, and to permit persons to whom the Software is
    6.14 + * furnished to do so, subject to the following conditions:
    6.15 + *
    6.16 + * The above copyright notice and this permission notice shall be included in
    6.17 + * all copies or substantial portions of the Software.
    6.18 + *
    6.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    6.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    6.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    6.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    6.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    6.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    6.25 + * THE SOFTWARE.
    6.26 + */
    6.27 +#include "vl.h"
    6.28 +
    6.29 +void usb_attach(USBPort *port, USBDevice *dev)
    6.30 +{
    6.31 +    port->attach(port, dev);
    6.32 +}
    6.33 +
    6.34 +/**********************/
    6.35 +/* generic USB device helpers (you are not forced to use them when
    6.36 +   writing your USB device driver, but they help handling the
    6.37 +   protocol) 
    6.38 +*/
    6.39 +
    6.40 +#define SETUP_STATE_IDLE 0
    6.41 +#define SETUP_STATE_DATA 1
    6.42 +#define SETUP_STATE_ACK  2
    6.43 +
    6.44 +int usb_generic_handle_packet(USBDevice *s, int pid, 
    6.45 +                              uint8_t devaddr, uint8_t devep,
    6.46 +                              uint8_t *data, int len)
    6.47 +{
    6.48 +    int l, ret = 0;
    6.49 +
    6.50 +    switch(pid) {
    6.51 +    case USB_MSG_ATTACH:
    6.52 +        s->state = USB_STATE_ATTACHED;
    6.53 +        break;
    6.54 +    case USB_MSG_DETACH:
    6.55 +        s->state = USB_STATE_NOTATTACHED;
    6.56 +        break;
    6.57 +    case USB_MSG_RESET:
    6.58 +        s->remote_wakeup = 0;
    6.59 +        s->addr = 0;
    6.60 +        s->state = USB_STATE_DEFAULT;
    6.61 +        s->handle_reset(s);
    6.62 +        break;
    6.63 +    case USB_TOKEN_SETUP:
    6.64 +        if (s->state < USB_STATE_DEFAULT || devaddr != s->addr)
    6.65 +            return USB_RET_NODEV;
    6.66 +        if (len != 8)
    6.67 +            goto fail;
    6.68 +        memcpy(s->setup_buf, data, 8);
    6.69 +        s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
    6.70 +        s->setup_index = 0;
    6.71 +        if (s->setup_buf[0] & USB_DIR_IN) {
    6.72 +            ret = s->handle_control(s, 
    6.73 +                                    (s->setup_buf[0] << 8) | s->setup_buf[1],
    6.74 +                                    (s->setup_buf[3] << 8) | s->setup_buf[2],
    6.75 +                                    (s->setup_buf[5] << 8) | s->setup_buf[4],
    6.76 +                                    s->setup_len,
    6.77 +                                    s->data_buf);
    6.78 +            if (ret < 0)
    6.79 +                return ret;
    6.80 +            if (ret < s->setup_len)
    6.81 +                s->setup_len = ret;
    6.82 +            s->setup_state = SETUP_STATE_DATA;
    6.83 +        } else {
    6.84 +            if (s->setup_len == 0)
    6.85 +                s->setup_state = SETUP_STATE_ACK;
    6.86 +            else
    6.87 +                s->setup_state = SETUP_STATE_DATA;
    6.88 +        }
    6.89 +        break;
    6.90 +    case USB_TOKEN_IN:
    6.91 +        if (s->state < USB_STATE_DEFAULT || devaddr != s->addr)
    6.92 +            return USB_RET_NODEV;
    6.93 +        switch(devep) {
    6.94 +        case 0:
    6.95 +            switch(s->setup_state) {
    6.96 +            case SETUP_STATE_ACK:
    6.97 +                if (!(s->setup_buf[0] & USB_DIR_IN)) {
    6.98 +                    s->setup_state = SETUP_STATE_IDLE;
    6.99 +                    ret = s->handle_control(s, 
   6.100 +                                      (s->setup_buf[0] << 8) | s->setup_buf[1],
   6.101 +                                      (s->setup_buf[3] << 8) | s->setup_buf[2],
   6.102 +                                      (s->setup_buf[5] << 8) | s->setup_buf[4],
   6.103 +                                      s->setup_len,
   6.104 +                                      s->data_buf);
   6.105 +                    if (ret > 0)
   6.106 +                        ret = 0;
   6.107 +                } else {
   6.108 +                    /* return 0 byte */
   6.109 +                }
   6.110 +                break;
   6.111 +            case SETUP_STATE_DATA:
   6.112 +                if (s->setup_buf[0] & USB_DIR_IN) {
   6.113 +                    l = s->setup_len - s->setup_index;
   6.114 +                    if (l > len)
   6.115 +                        l = len;
   6.116 +                    memcpy(data, s->data_buf + s->setup_index, l);
   6.117 +                    s->setup_index += l;
   6.118 +                    if (s->setup_index >= s->setup_len)
   6.119 +                        s->setup_state = SETUP_STATE_ACK;
   6.120 +                    ret = l;
   6.121 +                } else {
   6.122 +                    s->setup_state = SETUP_STATE_IDLE;
   6.123 +                    goto fail;
   6.124 +                }
   6.125 +                break;
   6.126 +            default:
   6.127 +                goto fail;
   6.128 +            }
   6.129 +            break;
   6.130 +        default:
   6.131 +            ret = s->handle_data(s, pid, devep, data, len);
   6.132 +            break;
   6.133 +        }
   6.134 +        break;
   6.135 +    case USB_TOKEN_OUT:
   6.136 +        if (s->state < USB_STATE_DEFAULT || devaddr != s->addr)
   6.137 +            return USB_RET_NODEV;
   6.138 +        switch(devep) {
   6.139 +        case 0:
   6.140 +            switch(s->setup_state) {
   6.141 +            case SETUP_STATE_ACK:
   6.142 +                if (s->setup_buf[0] & USB_DIR_IN) {
   6.143 +                    s->setup_state = SETUP_STATE_IDLE;
   6.144 +                    /* transfer OK */
   6.145 +                } else {
   6.146 +                    /* ignore additionnal output */
   6.147 +                }
   6.148 +                break;
   6.149 +            case SETUP_STATE_DATA:
   6.150 +                if (!(s->setup_buf[0] & USB_DIR_IN)) {
   6.151 +                    l = s->setup_len - s->setup_index;
   6.152 +                    if (l > len)
   6.153 +                        l = len;
   6.154 +                    memcpy(s->data_buf + s->setup_index, data, l);
   6.155 +                    s->setup_index += l;
   6.156 +                    if (s->setup_index >= s->setup_len)
   6.157 +                        s->setup_state = SETUP_STATE_ACK;
   6.158 +                    ret = l;
   6.159 +                } else {
   6.160 +                    s->setup_state = SETUP_STATE_IDLE;
   6.161 +                    goto fail;
   6.162 +                }
   6.163 +                break;
   6.164 +            default:
   6.165 +                goto fail;
   6.166 +            }
   6.167 +            break;
   6.168 +        default:
   6.169 +            ret = s->handle_data(s, pid, devep, data, len);
   6.170 +            break;
   6.171 +        }
   6.172 +        break;
   6.173 +    default:
   6.174 +    fail:
   6.175 +        ret = USB_RET_STALL;
   6.176 +        break;
   6.177 +    }
   6.178 +    return ret;
   6.179 +}
   6.180 +
   6.181 +/* XXX: fix overflow */
   6.182 +int set_usb_string(uint8_t *buf, const char *str)
   6.183 +{
   6.184 +    int len, i;
   6.185 +    uint8_t *q;
   6.186 +
   6.187 +    q = buf;
   6.188 +    len = strlen(str);
   6.189 +    *q++ = 2 * len + 2;
   6.190 +    *q++ = 3;
   6.191 +    for(i = 0; i < len; i++) {
   6.192 +        *q++ = str[i];
   6.193 +        *q++ = 0;
   6.194 +    }
   6.195 +    return q - buf;
   6.196 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/tools/ioemu/hw/usb.h	Mon Jun 12 09:06:55 2006 +0100
     7.3 @@ -0,0 +1,166 @@
     7.4 +/*
     7.5 + * QEMU USB API
     7.6 + * 
     7.7 + * Copyright (c) 2005 Fabrice Bellard
     7.8 + * 
     7.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    7.10 + * of this software and associated documentation files (the "Software"), to deal
    7.11 + * in the Software without restriction, including without limitation the rights
    7.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    7.13 + * copies of the Software, and to permit persons to whom the Software is
    7.14 + * furnished to do so, subject to the following conditions:
    7.15 + *
    7.16 + * The above copyright notice and this permission notice shall be included in
    7.17 + * all copies or substantial portions of the Software.
    7.18 + *
    7.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    7.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    7.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    7.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    7.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    7.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    7.25 + * THE SOFTWARE.
    7.26 + */
    7.27 +#define USB_TOKEN_SETUP 0x2d
    7.28 +#define USB_TOKEN_IN    0x69 /* device -> host */
    7.29 +#define USB_TOKEN_OUT   0xe1 /* host -> device */
    7.30 +
    7.31 +/* specific usb messages, also sent in the 'pid' parameter */
    7.32 +#define USB_MSG_ATTACH   0x100
    7.33 +#define USB_MSG_DETACH   0x101
    7.34 +#define USB_MSG_RESET    0x102
    7.35 +
    7.36 +#define USB_RET_NODEV  (-1) 
    7.37 +#define USB_RET_NAK    (-2)
    7.38 +#define USB_RET_STALL  (-3)
    7.39 +#define USB_RET_BABBLE (-4)
    7.40 +
    7.41 +#define USB_SPEED_LOW   0
    7.42 +#define USB_SPEED_FULL  1
    7.43 +#define USB_SPEED_HIGH  2
    7.44 +
    7.45 +#define USB_STATE_NOTATTACHED 0
    7.46 +#define USB_STATE_ATTACHED    1
    7.47 +//#define USB_STATE_POWERED     2
    7.48 +#define USB_STATE_DEFAULT     3
    7.49 +//#define USB_STATE_ADDRESS     4
    7.50 +//#define	USB_STATE_CONFIGURED  5
    7.51 +#define USB_STATE_SUSPENDED   6
    7.52 +
    7.53 +#define USB_CLASS_AUDIO			1
    7.54 +#define USB_CLASS_COMM			2
    7.55 +#define USB_CLASS_HID			3
    7.56 +#define USB_CLASS_PHYSICAL		5
    7.57 +#define USB_CLASS_STILL_IMAGE		6
    7.58 +#define USB_CLASS_PRINTER		7
    7.59 +#define USB_CLASS_MASS_STORAGE		8
    7.60 +#define USB_CLASS_HUB			9
    7.61 +#define USB_CLASS_CDC_DATA		0x0a
    7.62 +#define USB_CLASS_CSCID			0x0b
    7.63 +#define USB_CLASS_CONTENT_SEC		0x0d
    7.64 +#define USB_CLASS_APP_SPEC		0xfe
    7.65 +#define USB_CLASS_VENDOR_SPEC		0xff
    7.66 +
    7.67 +#define USB_DIR_OUT			0
    7.68 +#define USB_DIR_IN			0x80
    7.69 +
    7.70 +#define USB_TYPE_MASK			(0x03 << 5)
    7.71 +#define USB_TYPE_STANDARD		(0x00 << 5)
    7.72 +#define USB_TYPE_CLASS			(0x01 << 5)
    7.73 +#define USB_TYPE_VENDOR			(0x02 << 5)
    7.74 +#define USB_TYPE_RESERVED		(0x03 << 5)
    7.75 +
    7.76 +#define USB_RECIP_MASK			0x1f
    7.77 +#define USB_RECIP_DEVICE		0x00
    7.78 +#define USB_RECIP_INTERFACE		0x01
    7.79 +#define USB_RECIP_ENDPOINT		0x02
    7.80 +#define USB_RECIP_OTHER			0x03
    7.81 +
    7.82 +#define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
    7.83 +#define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
    7.84 +#define InterfaceRequest \
    7.85 +        ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
    7.86 +#define InterfaceOutRequest \
    7.87 +        ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
    7.88 +#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
    7.89 +#define EndpointOutRequest \
    7.90 +        ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
    7.91 +
    7.92 +#define USB_REQ_GET_STATUS		0x00
    7.93 +#define USB_REQ_CLEAR_FEATURE		0x01
    7.94 +#define USB_REQ_SET_FEATURE		0x03
    7.95 +#define USB_REQ_SET_ADDRESS		0x05
    7.96 +#define USB_REQ_GET_DESCRIPTOR		0x06
    7.97 +#define USB_REQ_SET_DESCRIPTOR		0x07
    7.98 +#define USB_REQ_GET_CONFIGURATION	0x08
    7.99 +#define USB_REQ_SET_CONFIGURATION	0x09
   7.100 +#define USB_REQ_GET_INTERFACE		0x0A
   7.101 +#define USB_REQ_SET_INTERFACE		0x0B
   7.102 +#define USB_REQ_SYNCH_FRAME		0x0C
   7.103 +
   7.104 +#define USB_DEVICE_SELF_POWERED		0
   7.105 +#define USB_DEVICE_REMOTE_WAKEUP	1
   7.106 +
   7.107 +#define USB_DT_DEVICE			0x01
   7.108 +#define USB_DT_CONFIG			0x02
   7.109 +#define USB_DT_STRING			0x03
   7.110 +#define USB_DT_INTERFACE		0x04
   7.111 +#define USB_DT_ENDPOINT			0x05
   7.112 +
   7.113 +typedef struct USBPort USBPort;
   7.114 +typedef struct USBDevice USBDevice;
   7.115 +
   7.116 +/* definition of a USB device */
   7.117 +struct USBDevice {
   7.118 +    void *opaque;
   7.119 +    int (*handle_packet)(USBDevice *dev, int pid, 
   7.120 +                         uint8_t devaddr, uint8_t devep,
   7.121 +                         uint8_t *data, int len);
   7.122 +    int speed;
   7.123 +    
   7.124 +    /* The following fields are used by the generic USB device
   7.125 +       layer. They are here just to avoid creating a new structure for
   7.126 +       them. */
   7.127 +    void (*handle_reset)(USBDevice *dev);
   7.128 +    int (*handle_control)(USBDevice *dev, int request, int value,
   7.129 +                          int index, int length, uint8_t *data);
   7.130 +    int (*handle_data)(USBDevice *dev, int pid, uint8_t devep,
   7.131 +                       uint8_t *data, int len);
   7.132 +    uint8_t addr;
   7.133 +    
   7.134 +    int state;
   7.135 +    uint8_t setup_buf[8];
   7.136 +    uint8_t data_buf[1024];
   7.137 +    int remote_wakeup;
   7.138 +    int setup_state;
   7.139 +    int setup_len;
   7.140 +    int setup_index;
   7.141 +};
   7.142 +
   7.143 +/* USB port on which a device can be connected */
   7.144 +struct USBPort {
   7.145 +    USBDevice *dev;
   7.146 +    void (*attach)(USBPort *port, USBDevice *dev);
   7.147 +    void *opaque;
   7.148 +    int index; /* internal port index, may be used with the opaque */
   7.149 +};
   7.150 +
   7.151 +void usb_attach(USBPort *port, USBDevice *dev);
   7.152 +int usb_generic_handle_packet(USBDevice *s, int pid, 
   7.153 +                              uint8_t devaddr, uint8_t devep,
   7.154 +                              uint8_t *data, int len);
   7.155 +int set_usb_string(uint8_t *buf, const char *str);
   7.156 +
   7.157 +/* usb hub */
   7.158 +USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports);
   7.159 +
   7.160 +/* usb-uhci.c */
   7.161 +void usb_uhci_init(PCIBus *bus, USBPort **usb_ports);
   7.162 +
   7.163 +/* usb-linux.c */
   7.164 +USBDevice *usb_host_device_open(const char *devname);
   7.165 +void usb_host_info(void);
   7.166 +
   7.167 +/* usb-hid.c */
   7.168 +USBDevice *usb_mouse_init(void);
   7.169 +USBDevice *usb_tablet_init(void);
     8.1 --- a/tools/ioemu/monitor.c	Mon Jun 12 08:53:38 2006 +0100
     8.2 +++ b/tools/ioemu/monitor.c	Mon Jun 12 09:06:55 2006 +0100
     8.3 @@ -492,6 +492,10 @@ static term_cmd_t term_cmds[] = {
     8.4        "", "quit the emulator" },
     8.5      { "sendkey", "s", do_send_key, 
     8.6        "keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" },
     8.7 +    { "usb_add", "s", do_usb_add,
     8.8 +      "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" },
     8.9 +    { "usb_del", "s", do_usb_del,
    8.10 +      "device", "remove USB device 'bus.addr'" },
    8.11      { NULL, NULL, }, 
    8.12  };
    8.13  
    8.14 @@ -510,6 +514,10 @@ static term_cmd_t info_cmds[] = {
    8.15        "", "show i8259 (PIC) state", },
    8.16      { "pci", "", pci_info,
    8.17        "", "show PCI info", },
    8.18 +    { "usb", "", usb_info,
    8.19 +      "", "show guest USB devices", },
    8.20 +    { "usbhost", "", usb_host_info,
    8.21 +      "", "show host USB devices", },
    8.22      { "hvmiopage", "", sp_info,
    8.23        "", "show HVM device model shared page info", },
    8.24      { NULL, NULL, },
     9.1 --- a/tools/ioemu/sdl.c	Mon Jun 12 08:53:38 2006 +0100
     9.2 +++ b/tools/ioemu/sdl.c	Mon Jun 12 09:06:55 2006 +0100
     9.3 @@ -49,8 +49,12 @@ static void* kbd_layout=0;
     9.4  static int gui_fullscreen_initial_grab;
     9.5  static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
     9.6  static uint8_t modifiers_state[256];
     9.7 +static int width, height;
     9.8 +static SDL_Cursor *sdl_cursor_normal;
     9.9 +static SDL_Cursor *sdl_cursor_hidden;
    9.10 +static int absolute_enabled = 0;
    9.11  
    9.12 -SDL_PixelFormat* sdl_get_format() {
    9.13 +SDL_PixelFormat* sdl_get_format(void) {
    9.14  	return screen->format;
    9.15  }
    9.16  
    9.17 @@ -69,6 +73,8 @@ static void sdl_resize(DisplayState *ds,
    9.18      flags |= SDL_RESIZABLE;
    9.19      if (gui_fullscreen)
    9.20          flags |= SDL_FULLSCREEN;
    9.21 +    width = w;
    9.22 +    height = h;
    9.23      screen = SDL_SetVideoMode(w, h, 0, flags);
    9.24      if (!screen) {
    9.25          fprintf(stderr, "Could not open SDL display\n");
    9.26 @@ -368,9 +374,21 @@ static void sdl_update_caption(void)
    9.27      SDL_WM_SetCaption(buf, domain_name);
    9.28  }
    9.29  
    9.30 +static void sdl_hide_cursor(void)
    9.31 +{
    9.32 +    SDL_SetCursor(sdl_cursor_hidden);
    9.33 +}
    9.34 +
    9.35 +static void sdl_show_cursor(void)
    9.36 +{
    9.37 +    if (!kbd_mouse_is_absolute()) {
    9.38 +	SDL_SetCursor(sdl_cursor_normal);
    9.39 +    }
    9.40 +}
    9.41 +
    9.42  static void sdl_grab_start(void)
    9.43  {
    9.44 -    SDL_ShowCursor(0);
    9.45 +    sdl_hide_cursor();
    9.46      SDL_WM_GrabInput(SDL_GRAB_ON);
    9.47      /* dummy read to avoid moving the mouse */
    9.48      SDL_GetRelativeMouseState(NULL, NULL);
    9.49 @@ -381,6 +399,7 @@ static void sdl_grab_start(void)
    9.50  static void sdl_grab_end(void)
    9.51  {
    9.52      SDL_WM_GrabInput(SDL_GRAB_OFF);
    9.53 +    sdl_show_cursor();
    9.54      SDL_ShowCursor(1);
    9.55      gui_grab = 0;
    9.56      sdl_update_caption();
    9.57 @@ -397,6 +416,21 @@ static void sdl_send_mouse_event(void)
    9.58          buttons |= MOUSE_EVENT_RBUTTON;
    9.59      if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
    9.60          buttons |= MOUSE_EVENT_MBUTTON;
    9.61 +
    9.62 +    if (kbd_mouse_is_absolute()) {
    9.63 +	if (!absolute_enabled) {
    9.64 +	    sdl_hide_cursor();
    9.65 +	    if (gui_grab) {
    9.66 +		sdl_grab_end();
    9.67 +	    }
    9.68 +	    absolute_enabled = 1;
    9.69 +	}
    9.70 +
    9.71 +	SDL_GetMouseState(&dx, &dy);
    9.72 +	dx = dx * 0x7FFF / width;
    9.73 +	dy = dy * 0x7FFF / height;
    9.74 +    }
    9.75 +
    9.76      /* XXX: test wheel */
    9.77      dz = 0;
    9.78  #ifdef SDL_BUTTON_WHEELUP
    9.79 @@ -405,7 +439,7 @@ static void sdl_send_mouse_event(void)
    9.80      if (state & SDL_BUTTON(SDL_BUTTON_WHEELDOWN))
    9.81          dz++;
    9.82  #endif
    9.83 -    kbd_mouse_event(dx, dy, dz, buttons, 0, 0);
    9.84 +    kbd_mouse_event(dx, dy, dz, buttons);
    9.85  }
    9.86  
    9.87  static void toggle_full_screen(DisplayState *ds)
    9.88 @@ -571,6 +605,7 @@ static void sdl_cleanup(void)
    9.89  void sdl_display_init(DisplayState *ds, int full_screen)
    9.90  {
    9.91      int flags;
    9.92 +    uint8_t data = 0;
    9.93  
    9.94      if(keyboard_layout)
    9.95  	    kbd_layout=init_keyboard_layout(keyboard_layout);
    9.96 @@ -597,6 +632,9 @@ void sdl_display_init(DisplayState *ds, 
    9.97      SDL_EnableUNICODE(1);
    9.98      gui_grab = 0;
    9.99  
   9.100 +    sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
   9.101 +    sdl_cursor_normal = SDL_GetCursor();
   9.102 +
   9.103      atexit(sdl_cleanup);
   9.104      if (full_screen) {
   9.105          gui_fullscreen = 1;
    10.1 --- a/tools/ioemu/target-i386-dm/Makefile	Mon Jun 12 08:53:38 2006 +0100
    10.2 +++ b/tools/ioemu/target-i386-dm/Makefile	Mon Jun 12 09:06:55 2006 +0100
    10.3 @@ -275,6 +275,9 @@ audio.o fmodaudio.o: DEFINES := -I$(CONF
    10.4  LIBS += $(CONFIG_FMOD_LIB)
    10.5  endif
    10.6  
    10.7 +# USB layer
    10.8 +VL_OBJS+= usb.o usb-hub.o usb-uhci.o usb-linux.o usb-hid.o
    10.9 +
   10.10  # Hardware support
   10.11  VL_OBJS+= ide.o ne2000.o pckbd.o vga.o dma.o
   10.12  VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259_stub.o pc.o port-e9.o
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/tools/ioemu/usb-linux.c	Mon Jun 12 09:06:55 2006 +0100
    11.3 @@ -0,0 +1,487 @@
    11.4 +/*
    11.5 + * Linux host USB redirector
    11.6 + *
    11.7 + * Copyright (c) 2005 Fabrice Bellard
    11.8 + * 
    11.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   11.10 + * of this software and associated documentation files (the "Software"), to deal
   11.11 + * in the Software without restriction, including without limitation the rights
   11.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   11.13 + * copies of the Software, and to permit persons to whom the Software is
   11.14 + * furnished to do so, subject to the following conditions:
   11.15 + *
   11.16 + * The above copyright notice and this permission notice shall be included in
   11.17 + * all copies or substantial portions of the Software.
   11.18 + *
   11.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   11.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   11.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   11.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   11.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   11.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   11.25 + * THE SOFTWARE.
   11.26 + */
   11.27 +#include "vl.h"
   11.28 +
   11.29 +#if defined(__linux__)
   11.30 +#include <dirent.h>
   11.31 +#include <sys/ioctl.h>
   11.32 +#include <linux/usbdevice_fs.h>
   11.33 +#include <linux/version.h>
   11.34 +
   11.35 +/* We redefine it to avoid version problems */
   11.36 +struct usb_ctrltransfer {
   11.37 +    uint8_t  bRequestType;
   11.38 +    uint8_t  bRequest;
   11.39 +    uint16_t wValue;
   11.40 +    uint16_t wIndex;
   11.41 +    uint16_t wLength;
   11.42 +    uint32_t timeout;
   11.43 +    void *data;
   11.44 +};
   11.45 +
   11.46 +typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
   11.47 +                        int vendor_id, int product_id, 
   11.48 +                        const char *product_name, int speed);
   11.49 +static int usb_host_find_device(int *pbus_num, int *paddr, 
   11.50 +                                const char *devname);
   11.51 +
   11.52 +//#define DEBUG
   11.53 +
   11.54 +#define USBDEVFS_PATH "/proc/bus/usb"
   11.55 +
   11.56 +typedef struct USBHostDevice {
   11.57 +    USBDevice dev;
   11.58 +    int fd;
   11.59 +} USBHostDevice;
   11.60 +
   11.61 +static void usb_host_handle_reset(USBDevice *dev)
   11.62 +{
   11.63 +#if 0
   11.64 +    USBHostDevice *s = (USBHostDevice *)dev;
   11.65 +    /* USBDEVFS_RESET, but not the first time as it has already be
   11.66 +       done by the host OS */
   11.67 +    ioctl(s->fd, USBDEVFS_RESET);
   11.68 +#endif
   11.69 +} 
   11.70 +
   11.71 +static int usb_host_handle_control(USBDevice *dev,
   11.72 +                                   int request,
   11.73 +                                   int value,
   11.74 +                                   int index,
   11.75 +                                   int length,
   11.76 +                                   uint8_t *data)
   11.77 +{
   11.78 +    USBHostDevice *s = (USBHostDevice *)dev;
   11.79 +    struct usb_ctrltransfer ct;
   11.80 +    int ret;
   11.81 +
   11.82 +    if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) {
   11.83 +        /* specific SET_ADDRESS support */
   11.84 +        dev->addr = value;
   11.85 +        return 0;
   11.86 +    } else {
   11.87 +        ct.bRequestType = request >> 8;
   11.88 +        ct.bRequest = request;
   11.89 +        ct.wValue = value;
   11.90 +        ct.wIndex = index;
   11.91 +        ct.wLength = length;
   11.92 +        ct.timeout = 50;
   11.93 +        ct.data = data;
   11.94 +        ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
   11.95 +        if (ret < 0) {
   11.96 +            switch(errno) {
   11.97 +            case ETIMEDOUT:
   11.98 +                return USB_RET_NAK;
   11.99 +            default:
  11.100 +                return USB_RET_STALL;
  11.101 +            }
  11.102 +        } else {
  11.103 +            return ret;
  11.104 +        }
  11.105 +   }
  11.106 +}
  11.107 +
  11.108 +static int usb_host_handle_data(USBDevice *dev, int pid, 
  11.109 +                                uint8_t devep,
  11.110 +                                uint8_t *data, int len)
  11.111 +{
  11.112 +    USBHostDevice *s = (USBHostDevice *)dev;
  11.113 +    struct usbdevfs_bulktransfer bt;
  11.114 +    int ret;
  11.115 +
  11.116 +    /* XXX: optimize and handle all data types by looking at the
  11.117 +       config descriptor */
  11.118 +    if (pid == USB_TOKEN_IN)
  11.119 +        devep |= 0x80;
  11.120 +    bt.ep = devep;
  11.121 +    bt.len = len;
  11.122 +    bt.timeout = 50;
  11.123 +    bt.data = data;
  11.124 +    ret = ioctl(s->fd, USBDEVFS_BULK, &bt);
  11.125 +    if (ret < 0) {
  11.126 +        switch(errno) {
  11.127 +        case ETIMEDOUT:
  11.128 +            return USB_RET_NAK;
  11.129 +        case EPIPE:
  11.130 +        default:
  11.131 +#ifdef DEBUG
  11.132 +            printf("handle_data: errno=%d\n", errno);
  11.133 +#endif
  11.134 +            return USB_RET_STALL;
  11.135 +        }
  11.136 +    } else {
  11.137 +        return ret;
  11.138 +    }
  11.139 +}
  11.140 +
  11.141 +/* XXX: exclude high speed devices or implement EHCI */
  11.142 +USBDevice *usb_host_device_open(const char *devname)
  11.143 +{
  11.144 +    int fd, interface, ret, i;
  11.145 +    USBHostDevice *dev;
  11.146 +    struct usbdevfs_connectinfo ci;
  11.147 +    uint8_t descr[1024];
  11.148 +    char buf[1024];
  11.149 +    int descr_len, dev_descr_len, config_descr_len, nb_interfaces;
  11.150 +    int bus_num, addr;
  11.151 +
  11.152 +    if (usb_host_find_device(&bus_num, &addr, devname) < 0) 
  11.153 +        return NULL;
  11.154 +    
  11.155 +    snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", 
  11.156 +             bus_num, addr);
  11.157 +    fd = open(buf, O_RDWR);
  11.158 +    if (fd < 0) {
  11.159 +        perror(buf);
  11.160 +        return NULL;
  11.161 +    }
  11.162 +
  11.163 +    /* read the config description */
  11.164 +    descr_len = read(fd, descr, sizeof(descr));
  11.165 +    if (descr_len <= 0) {
  11.166 +        perror("read descr");
  11.167 +        goto fail;
  11.168 +    }
  11.169 +    
  11.170 +    i = 0;
  11.171 +    dev_descr_len = descr[0];
  11.172 +    if (dev_descr_len > descr_len)
  11.173 +        goto fail;
  11.174 +    i += dev_descr_len;
  11.175 +    config_descr_len = descr[i];
  11.176 +    if (i + config_descr_len > descr_len)
  11.177 +        goto fail;
  11.178 +    nb_interfaces = descr[i + 4];
  11.179 +    if (nb_interfaces != 1) {
  11.180 +        /* NOTE: currently we grab only one interface */
  11.181 +        fprintf(stderr, "usb_host: only one interface supported\n");
  11.182 +        goto fail;
  11.183 +    }
  11.184 +
  11.185 +#ifdef USBDEVFS_DISCONNECT
  11.186 +    /* earlier Linux 2.4 do not support that */
  11.187 +    {
  11.188 +        struct usbdevfs_ioctl ctrl;
  11.189 +        ctrl.ioctl_code = USBDEVFS_DISCONNECT;
  11.190 +        ctrl.ifno = 0;
  11.191 +        ret = ioctl(fd, USBDEVFS_IOCTL, &ctrl);
  11.192 +        if (ret < 0 && errno != ENODATA) {
  11.193 +            perror("USBDEVFS_DISCONNECT");
  11.194 +            goto fail;
  11.195 +        }
  11.196 +    }
  11.197 +#endif
  11.198 +
  11.199 +    /* XXX: only grab if all interfaces are free */
  11.200 +    interface = 0;
  11.201 +    ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);
  11.202 +    if (ret < 0) {
  11.203 +        if (errno == EBUSY) {
  11.204 +            fprintf(stderr, "usb_host: device already grabbed\n");
  11.205 +        } else {
  11.206 +            perror("USBDEVFS_CLAIMINTERFACE");
  11.207 +        }
  11.208 +    fail:
  11.209 +        close(fd);
  11.210 +        return NULL;
  11.211 +    }
  11.212 +
  11.213 +    ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
  11.214 +    if (ret < 0) {
  11.215 +        perror("USBDEVFS_CONNECTINFO");
  11.216 +        goto fail;
  11.217 +    }
  11.218 +
  11.219 +#ifdef DEBUG
  11.220 +    printf("host USB device %d.%d grabbed\n", bus_num, addr);
  11.221 +#endif    
  11.222 +
  11.223 +    dev = qemu_mallocz(sizeof(USBHostDevice));
  11.224 +    if (!dev)
  11.225 +        goto fail;
  11.226 +    dev->fd = fd;
  11.227 +    if (ci.slow)
  11.228 +        dev->dev.speed = USB_SPEED_LOW;
  11.229 +    else
  11.230 +        dev->dev.speed = USB_SPEED_HIGH;
  11.231 +    dev->dev.handle_packet = usb_generic_handle_packet;
  11.232 +
  11.233 +    dev->dev.handle_reset = usb_host_handle_reset;
  11.234 +    dev->dev.handle_control = usb_host_handle_control;
  11.235 +    dev->dev.handle_data = usb_host_handle_data;
  11.236 +    return (USBDevice *)dev;
  11.237 +}
  11.238 +
  11.239 +static int get_tag_value(char *buf, int buf_size,
  11.240 +                         const char *str, const char *tag, 
  11.241 +                         const char *stopchars)
  11.242 +{
  11.243 +    const char *p;
  11.244 +    char *q;
  11.245 +    p = strstr(str, tag);
  11.246 +    if (!p)
  11.247 +        return -1;
  11.248 +    p += strlen(tag);
  11.249 +    while (isspace(*p))
  11.250 +        p++;
  11.251 +    q = buf;
  11.252 +    while (*p != '\0' && !strchr(stopchars, *p)) {
  11.253 +        if ((q - buf) < (buf_size - 1))
  11.254 +            *q++ = *p;
  11.255 +        p++;
  11.256 +    }
  11.257 +    *q = '\0';
  11.258 +    return q - buf;
  11.259 +}
  11.260 +
  11.261 +static int usb_host_scan(void *opaque, USBScanFunc *func)
  11.262 +{
  11.263 +    FILE *f;
  11.264 +    char line[1024];
  11.265 +    char buf[1024];
  11.266 +    int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
  11.267 +    int ret;
  11.268 +    char product_name[512];
  11.269 +    
  11.270 +    f = fopen(USBDEVFS_PATH "/devices", "r");
  11.271 +    if (!f) {
  11.272 +        term_printf("Could not open %s\n", USBDEVFS_PATH "/devices");
  11.273 +        return 0;
  11.274 +    }
  11.275 +    device_count = 0;
  11.276 +    bus_num = addr = speed = class_id = product_id = vendor_id = 0;
  11.277 +    ret = 0;
  11.278 +    for(;;) {
  11.279 +        if (fgets(line, sizeof(line), f) == NULL)
  11.280 +            break;
  11.281 +        if (strlen(line) > 0)
  11.282 +            line[strlen(line) - 1] = '\0';
  11.283 +        if (line[0] == 'T' && line[1] == ':') {
  11.284 +            if (device_count && (vendor_id || product_id)) {
  11.285 +                /* New device.  Add the previously discovered device.  */
  11.286 +                ret = func(opaque, bus_num, addr, class_id, vendor_id, 
  11.287 +                           product_id, product_name, speed);
  11.288 +                if (ret)
  11.289 +                    goto the_end;
  11.290 +            }
  11.291 +            if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0)
  11.292 +                goto fail;
  11.293 +            bus_num = atoi(buf);
  11.294 +            if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0)
  11.295 +                goto fail;
  11.296 +            addr = atoi(buf);
  11.297 +            if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0)
  11.298 +                goto fail;
  11.299 +            if (!strcmp(buf, "480"))
  11.300 +                speed = USB_SPEED_HIGH;
  11.301 +            else if (!strcmp(buf, "1.5"))
  11.302 +                speed = USB_SPEED_LOW;
  11.303 +            else
  11.304 +                speed = USB_SPEED_FULL;
  11.305 +            product_name[0] = '\0';
  11.306 +            class_id = 0xff;
  11.307 +            device_count++;
  11.308 +            product_id = 0;
  11.309 +            vendor_id = 0;
  11.310 +        } else if (line[0] == 'P' && line[1] == ':') {
  11.311 +            if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0)
  11.312 +                goto fail;
  11.313 +            vendor_id = strtoul(buf, NULL, 16);
  11.314 +            if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0)
  11.315 +                goto fail;
  11.316 +            product_id = strtoul(buf, NULL, 16);
  11.317 +        } else if (line[0] == 'S' && line[1] == ':') {
  11.318 +            if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0)
  11.319 +                goto fail;
  11.320 +            pstrcpy(product_name, sizeof(product_name), buf);
  11.321 +        } else if (line[0] == 'D' && line[1] == ':') {
  11.322 +            if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0)
  11.323 +                goto fail;
  11.324 +            class_id = strtoul(buf, NULL, 16);
  11.325 +        }
  11.326 +    fail: ;
  11.327 +    }
  11.328 +    if (device_count && (vendor_id || product_id)) {
  11.329 +        /* Add the last device.  */
  11.330 +        ret = func(opaque, bus_num, addr, class_id, vendor_id, 
  11.331 +                   product_id, product_name, speed);
  11.332 +    }
  11.333 + the_end:
  11.334 +    fclose(f);
  11.335 +    return ret;
  11.336 +}
  11.337 +
  11.338 +typedef struct FindDeviceState {
  11.339 +    int vendor_id;
  11.340 +    int product_id;
  11.341 +    int bus_num;
  11.342 +    int addr;
  11.343 +} FindDeviceState;
  11.344 +
  11.345 +static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, 
  11.346 +                                     int class_id,
  11.347 +                                     int vendor_id, int product_id, 
  11.348 +                                     const char *product_name, int speed)
  11.349 +{
  11.350 +    FindDeviceState *s = opaque;
  11.351 +    if (vendor_id == s->vendor_id &&
  11.352 +        product_id == s->product_id) {
  11.353 +        s->bus_num = bus_num;
  11.354 +        s->addr = addr;
  11.355 +        return 1;
  11.356 +    } else {
  11.357 +        return 0;
  11.358 +    }
  11.359 +}
  11.360 +
  11.361 +/* the syntax is : 
  11.362 +   'bus.addr' (decimal numbers) or 
  11.363 +   'vendor_id:product_id' (hexa numbers) */
  11.364 +static int usb_host_find_device(int *pbus_num, int *paddr, 
  11.365 +                                const char *devname)
  11.366 +{
  11.367 +    const char *p;
  11.368 +    int ret;
  11.369 +    FindDeviceState fs;
  11.370 +
  11.371 +    p = strchr(devname, '.');
  11.372 +    if (p) {
  11.373 +        *pbus_num = strtoul(devname, NULL, 0);
  11.374 +        *paddr = strtoul(p + 1, NULL, 0);
  11.375 +        return 0;
  11.376 +    }
  11.377 +    p = strchr(devname, ':');
  11.378 +    if (p) {
  11.379 +        fs.vendor_id = strtoul(devname, NULL, 16);
  11.380 +        fs.product_id = strtoul(p + 1, NULL, 16);
  11.381 +        ret = usb_host_scan(&fs, usb_host_find_device_scan);
  11.382 +        if (ret) {
  11.383 +            *pbus_num = fs.bus_num;
  11.384 +            *paddr = fs.addr;
  11.385 +            return 0;
  11.386 +        }
  11.387 +    }
  11.388 +    return -1;
  11.389 +}
  11.390 +
  11.391 +/**********************/
  11.392 +/* USB host device info */
  11.393 +
  11.394 +struct usb_class_info {
  11.395 +    int class;
  11.396 +    const char *class_name;
  11.397 +};
  11.398 +
  11.399 +static const struct usb_class_info usb_class_info[] = {
  11.400 +    { USB_CLASS_AUDIO, "Audio"},
  11.401 +    { USB_CLASS_COMM, "Communication"},
  11.402 +    { USB_CLASS_HID, "HID"},
  11.403 +    { USB_CLASS_HUB, "Hub" },
  11.404 +    { USB_CLASS_PHYSICAL, "Physical" },
  11.405 +    { USB_CLASS_PRINTER, "Printer" },
  11.406 +    { USB_CLASS_MASS_STORAGE, "Storage" },
  11.407 +    { USB_CLASS_CDC_DATA, "Data" },
  11.408 +    { USB_CLASS_APP_SPEC, "Application Specific" },
  11.409 +    { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
  11.410 +    { USB_CLASS_STILL_IMAGE, "Still Image" },
  11.411 +    { USB_CLASS_CSCID, 	"Smart Card" },
  11.412 +    { USB_CLASS_CONTENT_SEC, "Content Security" },
  11.413 +    { -1, NULL }
  11.414 +};
  11.415 +
  11.416 +static const char *usb_class_str(uint8_t class)
  11.417 +{
  11.418 +    const struct usb_class_info *p;
  11.419 +    for(p = usb_class_info; p->class != -1; p++) {
  11.420 +        if (p->class == class)
  11.421 +            break;
  11.422 +    }
  11.423 +    return p->class_name;
  11.424 +}
  11.425 +
  11.426 +void usb_info_device(int bus_num, int addr, int class_id,
  11.427 +                     int vendor_id, int product_id, 
  11.428 +                     const char *product_name,
  11.429 +                     int speed)
  11.430 +{
  11.431 +    const char *class_str, *speed_str;
  11.432 +
  11.433 +    switch(speed) {
  11.434 +    case USB_SPEED_LOW: 
  11.435 +        speed_str = "1.5"; 
  11.436 +        break;
  11.437 +    case USB_SPEED_FULL: 
  11.438 +        speed_str = "12"; 
  11.439 +        break;
  11.440 +    case USB_SPEED_HIGH: 
  11.441 +        speed_str = "480"; 
  11.442 +        break;
  11.443 +    default:
  11.444 +        speed_str = "?"; 
  11.445 +        break;
  11.446 +    }
  11.447 +
  11.448 +    term_printf("  Device %d.%d, speed %s Mb/s\n", 
  11.449 +                bus_num, addr, speed_str);
  11.450 +    class_str = usb_class_str(class_id);
  11.451 +    if (class_str) 
  11.452 +        term_printf("    %s:", class_str);
  11.453 +    else
  11.454 +        term_printf("    Class %02x:", class_id);
  11.455 +    term_printf(" USB device %04x:%04x", vendor_id, product_id);
  11.456 +    if (product_name[0] != '\0')
  11.457 +        term_printf(", %s", product_name);
  11.458 +    term_printf("\n");
  11.459 +}
  11.460 +
  11.461 +static int usb_host_info_device(void *opaque, int bus_num, int addr, 
  11.462 +                                int class_id,
  11.463 +                                int vendor_id, int product_id, 
  11.464 +                                const char *product_name,
  11.465 +                                int speed)
  11.466 +{
  11.467 +    usb_info_device(bus_num, addr, class_id, vendor_id, product_id,
  11.468 +                    product_name, speed);
  11.469 +    return 0;
  11.470 +}
  11.471 +
  11.472 +void usb_host_info(void)
  11.473 +{
  11.474 +    usb_host_scan(NULL, usb_host_info_device);
  11.475 +}
  11.476 +
  11.477 +#else
  11.478 +
  11.479 +void usb_host_info(void)
  11.480 +{
  11.481 +    term_printf("USB host devices not supported\n");
  11.482 +}
  11.483 +
  11.484 +/* XXX: modify configure to compile the right host driver */
  11.485 +USBDevice *usb_host_device_open(const char *devname)
  11.486 +{
  11.487 +    return NULL;
  11.488 +}
  11.489 +
  11.490 +#endif
    12.1 --- a/tools/ioemu/vl.c	Mon Jun 12 08:53:38 2006 +0100
    12.2 +++ b/tools/ioemu/vl.c	Mon Jun 12 09:06:55 2006 +0100
    12.3 @@ -144,6 +144,9 @@ int graphic_height = 600;
    12.4  int graphic_depth = 15;
    12.5  int full_screen = 0;
    12.6  int repeat_key = 1;
    12.7 +int usb_enabled = 0;
    12.8 +USBPort *vm_usb_ports[MAX_VM_USB_PORTS];
    12.9 +USBDevice *vm_usb_hub;
   12.10  TextConsole *vga_console;
   12.11  CharDriverState *serial_hds[MAX_SERIAL_PORTS];
   12.12  int serial_summa_port = -1;
   12.13 @@ -438,6 +441,7 @@ static QEMUPutKBDEvent *qemu_put_kbd_eve
   12.14  static void *qemu_put_kbd_event_opaque;
   12.15  static QEMUPutMouseEvent *qemu_put_mouse_event;
   12.16  static void *qemu_put_mouse_event_opaque;
   12.17 +static int qemu_put_mouse_event_absolute;
   12.18  
   12.19  void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
   12.20  {
   12.21 @@ -445,10 +449,11 @@ void qemu_add_kbd_event_handler(QEMUPutK
   12.22      qemu_put_kbd_event = func;
   12.23  }
   12.24  
   12.25 -void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque)
   12.26 +void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute)
   12.27  {
   12.28      qemu_put_mouse_event_opaque = opaque;
   12.29      qemu_put_mouse_event = func;
   12.30 +    qemu_put_mouse_event_absolute = absolute;
   12.31  }
   12.32  
   12.33  void kbd_put_keycode(int keycode)
   12.34 @@ -458,14 +463,19 @@ void kbd_put_keycode(int keycode)
   12.35      }
   12.36  }
   12.37  
   12.38 -void kbd_mouse_event(int dx, int dy, int dz, int buttons_state, int x, int y)
   12.39 +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
   12.40  {
   12.41      if (qemu_put_mouse_event) {
   12.42          qemu_put_mouse_event(qemu_put_mouse_event_opaque,
   12.43 -                             dx, dy, dz, buttons_state, x, y);
   12.44 +                             dx, dy, dz, buttons_state);
   12.45      }
   12.46  }
   12.47  
   12.48 +int kbd_mouse_is_absolute(void)
   12.49 +{
   12.50 +    return qemu_put_mouse_event_absolute;
   12.51 +}
   12.52 +
   12.53  /***********************************************************/
   12.54  /* timers */
   12.55  
   12.56 @@ -1644,6 +1654,121 @@ static int net_fd_init(NetDriverState *n
   12.57  }
   12.58  
   12.59  #endif /* !_WIN32 */
   12.60 + 
   12.61 +/***********************************************************/
   12.62 +/* USB devices */
   12.63 +
   12.64 +static int usb_device_add(const char *devname)
   12.65 +{
   12.66 +    const char *p;
   12.67 +    USBDevice *dev;
   12.68 +    int i;
   12.69 +
   12.70 +    if (!vm_usb_hub)
   12.71 +        return -1;
   12.72 +    for(i = 0;i < MAX_VM_USB_PORTS; i++) {
   12.73 +        if (!vm_usb_ports[i]->dev)
   12.74 +            break;
   12.75 +    }
   12.76 +    if (i == MAX_VM_USB_PORTS)
   12.77 +        return -1;
   12.78 +
   12.79 +    if (strstart(devname, "host:", &p)) {
   12.80 +        dev = usb_host_device_open(p);
   12.81 +        if (!dev)
   12.82 +            return -1;
   12.83 +    } else if (!strcmp(devname, "mouse")) {
   12.84 +        dev = usb_mouse_init();
   12.85 +        if (!dev)
   12.86 +            return -1;
   12.87 +    } else if (!strcmp(devname, "tablet")) {
   12.88 +	dev = usb_tablet_init();
   12.89 +	if (!dev)
   12.90 +	    return -1;
   12.91 +    } else {
   12.92 +        return -1;
   12.93 +    }
   12.94 +    usb_attach(vm_usb_ports[i], dev);
   12.95 +    return 0;
   12.96 +}
   12.97 +
   12.98 +static int usb_device_del(const char *devname)
   12.99 +{
  12.100 +    USBDevice *dev;
  12.101 +    int bus_num, addr, i;
  12.102 +    const char *p;
  12.103 +
  12.104 +    if (!vm_usb_hub)
  12.105 +        return -1;
  12.106 +
  12.107 +    p = strchr(devname, '.');
  12.108 +    if (!p) 
  12.109 +        return -1;
  12.110 +    bus_num = strtoul(devname, NULL, 0);
  12.111 +    addr = strtoul(p + 1, NULL, 0);
  12.112 +    if (bus_num != 0)
  12.113 +        return -1;
  12.114 +    for(i = 0;i < MAX_VM_USB_PORTS; i++) {
  12.115 +        dev = vm_usb_ports[i]->dev;
  12.116 +        if (dev && dev->addr == addr)
  12.117 +            break;
  12.118 +    }
  12.119 +    if (i == MAX_VM_USB_PORTS)
  12.120 +        return -1;
  12.121 +    usb_attach(vm_usb_ports[i], NULL);
  12.122 +    return 0;
  12.123 +}
  12.124 +
  12.125 +void do_usb_add(const char *devname)
  12.126 +{
  12.127 +    int ret;
  12.128 +    ret = usb_device_add(devname);
  12.129 +    if (ret < 0) 
  12.130 +        term_printf("Could not add USB device '%s'\n", devname);
  12.131 +}
  12.132 +
  12.133 +void do_usb_del(const char *devname)
  12.134 +{
  12.135 +    int ret;
  12.136 +    ret = usb_device_del(devname);
  12.137 +    if (ret < 0) 
  12.138 +        term_printf("Could not remove USB device '%s'\n", devname);
  12.139 +}
  12.140 +
  12.141 +void usb_info(void)
  12.142 +{
  12.143 +    USBDevice *dev;
  12.144 +    int i;
  12.145 +    const char *speed_str;
  12.146 +
  12.147 +    if (!vm_usb_hub) {
  12.148 +        term_printf("USB support not enabled\n");
  12.149 +        return;
  12.150 +    }
  12.151 +
  12.152 +    for(i = 0; i < MAX_VM_USB_PORTS; i++) {
  12.153 +        dev = vm_usb_ports[i]->dev;
  12.154 +        if (dev) {
  12.155 +            term_printf("Hub port %d:\n", i);
  12.156 +            switch(dev->speed) {
  12.157 +            case USB_SPEED_LOW: 
  12.158 +                speed_str = "1.5"; 
  12.159 +                break;
  12.160 +            case USB_SPEED_FULL: 
  12.161 +                speed_str = "12"; 
  12.162 +                break;
  12.163 +            case USB_SPEED_HIGH: 
  12.164 +                speed_str = "480"; 
  12.165 +                break;
  12.166 +            default:
  12.167 +                speed_str = "?"; 
  12.168 +                break;
  12.169 +            }
  12.170 +            term_printf("  Device %d.%d, speed %s Mb/s\n", 
  12.171 +                        0, dev->addr, speed_str);
  12.172 +        }
  12.173 +    }
  12.174 +}
  12.175  
  12.176  /***********************************************************/
  12.177  /* dumb display */
  12.178 @@ -2214,6 +2339,8 @@ void help(void)
  12.179             "-enable-audio   enable audio support\n"
  12.180             "-localtime      set the real time clock to local time [default=utc]\n"
  12.181             "-full-screen    start in full screen\n"
  12.182 +           "-usb            enable the USB driver (will be the default soon)\n"
  12.183 +           "-usbdevice name add the host or guest USB device 'name'\n"
  12.184  #ifdef TARGET_PPC
  12.185             "-prep           Simulate a PREP system (default is PowerMAC)\n"
  12.186             "-g WxH[xDEPTH]  Set the initial VGA graphic mode\n"
  12.187 @@ -2355,6 +2482,8 @@ enum {
  12.188      QEMU_OPTION_full_screen,
  12.189      QEMU_OPTION_vgaacc,
  12.190      QEMU_OPTION_repeatkey,
  12.191 +    QEMU_OPTION_usb,
  12.192 +    QEMU_OPTION_usbdevice,
  12.193  };
  12.194  
  12.195  typedef struct QEMUOption {
  12.196 @@ -2428,8 +2557,10 @@ const QEMUOption qemu_options[] = {
  12.197      { "serial", 1, QEMU_OPTION_serial },
  12.198      { "loadvm", HAS_ARG, QEMU_OPTION_loadvm },
  12.199      { "full-screen", 0, QEMU_OPTION_full_screen },
  12.200 +    { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice },
  12.201  
  12.202      /* temporary options */
  12.203 +    { "usb", 0, QEMU_OPTION_usb },
  12.204      { "pci", 0, QEMU_OPTION_pci },
  12.205      { "nic-ne2000", 0, QEMU_OPTION_nic_ne2000 },
  12.206      { "cirrusvga", 0, QEMU_OPTION_cirrusvga },
  12.207 @@ -2555,6 +2686,8 @@ int main(int argc, char **argv)
  12.208      char monitor_device[128];
  12.209      char serial_devices[MAX_SERIAL_PORTS][128];
  12.210      int serial_device_index;
  12.211 +    char usb_devices[MAX_VM_USB_PORTS][128];
  12.212 +    int usb_devices_index;
  12.213      char qemu_dm_logfilename[64];
  12.214      const char *loadvm = NULL;
  12.215      unsigned long nr_pages;
  12.216 @@ -2595,6 +2728,7 @@ int main(int argc, char **argv)
  12.217          serial_devices[i][0] = '\0';
  12.218      serial_device_index = 0;
  12.219  
  12.220 +    usb_devices_index = 0;
  12.221      nb_tun_fds = 0;
  12.222      net_if_type = -1;
  12.223      nb_nics = 1;
  12.224 @@ -2939,6 +3073,20 @@ int main(int argc, char **argv)
  12.225              case QEMU_OPTION_full_screen:
  12.226                  full_screen = 1;
  12.227                  break;
  12.228 +            case QEMU_OPTION_usb:
  12.229 +                usb_enabled = 1;
  12.230 +                break;
  12.231 +            case QEMU_OPTION_usbdevice:
  12.232 +                usb_enabled = 1;
  12.233 +                if (usb_devices_index >= MAX_VM_USB_PORTS) {
  12.234 +                    fprintf(stderr, "Too many USB devices\n");
  12.235 +                    exit(1);
  12.236 +                }
  12.237 +                pstrcpy(usb_devices[usb_devices_index],
  12.238 +                        sizeof(usb_devices[usb_devices_index]),
  12.239 +                        optarg);
  12.240 +                usb_devices_index++;
  12.241 +                break;
  12.242              case QEMU_OPTION_domainname:
  12.243                  strncat(domain_name, optarg, sizeof(domain_name) - 20);
  12.244                  break;
  12.245 @@ -3139,6 +3287,17 @@ int main(int argc, char **argv)
  12.246          }
  12.247      }
  12.248  
  12.249 +    /* init USB devices */
  12.250 +    if (usb_enabled) {
  12.251 +        vm_usb_hub = usb_hub_init(vm_usb_ports, MAX_VM_USB_PORTS);
  12.252 +        for(i = 0; i < usb_devices_index; i++) {
  12.253 +            if (usb_device_add(usb_devices[i]) < 0) {
  12.254 +                fprintf(stderr, "Warning: could not add USB device %s\n",
  12.255 +                        usb_devices[i]);
  12.256 +            }
  12.257 +        }
  12.258 +    }
  12.259 +
  12.260      /* init CPU state */
  12.261      env = cpu_init();
  12.262      global_env = env;
    13.1 --- a/tools/ioemu/vl.h	Mon Jun 12 08:53:38 2006 +0100
    13.2 +++ b/tools/ioemu/vl.h	Mon Jun 12 09:06:55 2006 +0100
    13.3 @@ -154,13 +154,14 @@ extern int graphic_depth;
    13.4  #define MOUSE_EVENT_MBUTTON 0x04
    13.5  
    13.6  typedef void QEMUPutKBDEvent(void *opaque, int keycode);
    13.7 -typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state, int x, int y);
    13.8 +typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state);
    13.9  
   13.10  void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
   13.11 -void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque);
   13.12 +void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute);
   13.13  
   13.14  void kbd_put_keycode(int keycode);
   13.15 -void kbd_mouse_event(int dx, int dy, int dz, int buttons_state, int x, int y);
   13.16 +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
   13.17 +int kbd_mouse_is_absolute(void);
   13.18  
   13.19  /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
   13.20     constants) */
   13.21 @@ -633,6 +634,7 @@ void pci_pcnet_init(PCIBus *bus, NetDriv
   13.22  void kbd_init(void);
   13.23  extern const char* keyboard_layout;
   13.24  extern int repeat_key;
   13.25 +extern int usb_enabled;
   13.26  
   13.27  /* mc146818rtc.c */
   13.28  
   13.29 @@ -792,6 +794,19 @@ void adb_mouse_init(ADBBusState *bus);
   13.30  
   13.31  /* cuda.c */
   13.32  
   13.33 +#include "hw/usb.h"
   13.34 +
   13.35 +/* usb ports of the VM */
   13.36 +
   13.37 +#define MAX_VM_USB_PORTS 8
   13.38 +
   13.39 +extern USBPort *vm_usb_ports[MAX_VM_USB_PORTS];
   13.40 +extern USBDevice *vm_usb_hub;
   13.41 +
   13.42 +void do_usb_add(const char *devname);
   13.43 +void do_usb_del(const char *devname);
   13.44 +void usb_info(void);
   13.45 +
   13.46  extern ADBBusState adb_bus;
   13.47  int cuda_init(openpic_t *openpic, int irq);
   13.48  
    14.1 --- a/tools/ioemu/vnc.c	Mon Jun 12 08:53:38 2006 +0100
    14.2 +++ b/tools/ioemu/vnc.c	Mon Jun 12 09:06:55 2006 +0100
    14.3 @@ -138,9 +138,16 @@ static void init_mouse(int max_x,int max
    14.4  }
    14.5  
    14.6  static void mouse_refresh() {
    14.7 +	static int last_x = -1;
    14.8 +	static int last_y = -1;
    14.9 +	static int last_z = -1;
   14.10 +	static int last_b = -1;
   14.11  	int dx=0,dy=0,dz=new_mouse_z;
   14.12  	static int counter=1;
   14.13  
   14.14 +	if (new_mouse_x == last_x && new_mouse_y == last_y &&
   14.15 +	    new_mouse_z == last_z && new_mouse_buttons == last_b)
   14.16 +		return;
   14.17  	/*
   14.18  	 *  Simulate lifting the mouse by pressing left <ctl><alt> together
   14.19  	 *  e.g. don't send mouse events.
   14.20 @@ -148,27 +155,40 @@ static void mouse_refresh() {
   14.21  	if (ctl_keys == 3) {
   14.22  		mouse_x = new_mouse_x;
   14.23  		mouse_y = new_mouse_y;
   14.24 +		last_x = new_mouse_x;
   14.25 +		last_y = new_mouse_y;
   14.26 +		last_z = new_mouse_z;
   14.27 +		last_b = new_mouse_buttons;
   14.28  		return;
   14.29  	}
   14.30  	counter++;
   14.31 -	if(!mouse_magic->calibration && counter>=2) { counter=0; return; }
   14.32 -
   14.33 -	dx=new_mouse_x-mouse_x;
   14.34 -	dy=new_mouse_y-mouse_y;
   14.35 -
   14.36 -	if(mouse_magic->sonic_wall_is_orthogonal) {
   14.37 -		if(abs(dx)>=mouse_magic->sonic_wall_x) { dx/=2; mouse_x+=dx; }
   14.38 -		if(abs(dy)>=mouse_magic->sonic_wall_y) { dy/=2; mouse_y+=dy; }
   14.39 +	//fprintf(stderr,"sending mouse event %d,%d\n",dx,dy);
   14.40 +	if (kbd_mouse_is_absolute()) {
   14.41 +		kbd_mouse_event(new_mouse_x * 0x7FFF / screen->width,
   14.42 +				new_mouse_y * 0x7FFF / screen->height, dz, new_mouse_buttons);
   14.43  	} else {
   14.44 -		if(abs(dx)>=mouse_magic->sonic_wall_x || abs(dy)>=mouse_magic->sonic_wall_y) {
   14.45 -			dx/=2; mouse_x+=dx;
   14.46 -			dy/=2; mouse_y+=dy;
   14.47 +		if(!mouse_magic->calibration && counter>=2) { counter=0; return; }
   14.48 +
   14.49 +		dx=new_mouse_x-last_x;
   14.50 +		dy=new_mouse_y-last_y;
   14.51 +
   14.52 +		if(mouse_magic->sonic_wall_is_orthogonal) {
   14.53 +			if(abs(dx)>=mouse_magic->sonic_wall_x) { dx/=2; mouse_x+=dx; }
   14.54 +			if(abs(dy)>=mouse_magic->sonic_wall_y) { dy/=2; mouse_y+=dy; }
   14.55 +		} else {
   14.56 +			if(abs(dx)>=mouse_magic->sonic_wall_x || abs(dy)>=mouse_magic->sonic_wall_y) {
   14.57 +				dx/=2; mouse_x+=dx;
   14.58 +				dy/=2; mouse_y+=dy;
   14.59 +			}
   14.60  		}
   14.61 +		if (last_x != -1)
   14.62 +			kbd_mouse_event(dx,dy,dz,new_mouse_buttons);
   14.63 +
   14.64  	}
   14.65 -	//fprintf(stderr,"sending mouse event %d,%d\n",dx,dy);
   14.66 -	kbd_mouse_event(dx,dy,dz,new_mouse_buttons,new_mouse_x,new_mouse_y);
   14.67 -	mouse_x+=dx;
   14.68 -	mouse_y+=dy;
   14.69 +	last_x = new_mouse_x;
   14.70 +	last_y = new_mouse_y;
   14.71 +	last_z = new_mouse_z;
   14.72 +	last_b = new_mouse_buttons;
   14.73  		
   14.74  	updates_since_mouse=0;
   14.75  }
   14.76 @@ -250,7 +270,7 @@ static void mouse_calibration_refresh() 
   14.77  	
   14.78  	if(calibration_step==0) {
   14.79  		x=0; y=1;
   14.80 -		kbd_mouse_event(0,-1,0,0,x,y);
   14.81 +		kbd_mouse_event(0,-1,0,0);
   14.82  		calibration_step++;
   14.83  	} else if(calibration_step==1) {
   14.84  		// find out the initial position of the cursor
   14.85 @@ -282,7 +302,7 @@ static void mouse_calibration_refresh() 
   14.86  		} else {
   14.87  			y++;
   14.88  move_calibrate:
   14.89 -			kbd_mouse_event(-x,-y,0,0,x,y);
   14.90 +			kbd_mouse_event(-x,-y,0,0);
   14.91  			before_update=last_update;
   14.92  		}
   14.93  	} else if(calibration_step==3) {
    15.1 --- a/tools/python/xen/xend/image.py	Mon Jun 12 08:53:38 2006 +0100
    15.2 +++ b/tools/python/xen/xend/image.py	Mon Jun 12 09:06:55 2006 +0100
    15.3 @@ -249,7 +249,8 @@ class HVMImageHandler(ImageHandler):
    15.4      # xm config file
    15.5      def parseDeviceModelArgs(self, imageConfig, deviceConfig):
    15.6          dmargs = [ 'cdrom', 'boot', 'fda', 'fdb', 'ne2000', 'audio',
    15.7 -                   'localtime', 'serial', 'stdvga', 'isa', 'vcpus']
    15.8 +                   'localtime', 'serial', 'stdvga', 'isa', 'vcpus',
    15.9 +		   'usb', 'usbdevice']
   15.10          ret = []
   15.11          for a in dmargs:
   15.12              v = sxp.child_value(imageConfig, a)
   15.13 @@ -260,7 +261,7 @@ class HVMImageHandler(ImageHandler):
   15.14              if a == 'audio': a = 'enable-audio'
   15.15  
   15.16              # Handle booleans gracefully
   15.17 -            if a in ['localtime', 'std-vga', 'isa', 'nic-ne2000', 'enable-audio']:
   15.18 +            if a in ['localtime', 'std-vga', 'isa', 'nic-ne2000', 'enable-audio', 'usb']:
   15.19                  if v != None: v = int(v)
   15.20                  if v: ret.append("-%s" % a)
   15.21              else:
    16.1 --- a/tools/python/xen/xm/create.py	Mon Jun 12 08:53:38 2006 +0100
    16.2 +++ b/tools/python/xen/xm/create.py	Mon Jun 12 09:06:55 2006 +0100
    16.3 @@ -264,7 +264,7 @@ gopts.var('irq', val='IRQ',
    16.4           For example 'irq=7'.
    16.5           This option may be repeated to add more than one IRQ.""")
    16.6  
    16.7 -gopts.var('usb', val='PATH',
    16.8 +gopts.var('usbport', val='PATH',
    16.9            fn=append_value, default=[],
   16.10            use="""Add a physical USB port to a domain, as specified by the path
   16.11            to that port.  This option may be repeated to add more than one port.""")
   16.12 @@ -372,6 +372,14 @@ gopts.var('localtime', val='no|yes',
   16.13            fn=set_bool, default=0,
   16.14            use="Is RTC set to localtime?")
   16.15  
   16.16 +gopts.var('usb', val='no|yes',
   16.17 +          fn=set_bool, default=0,
   16.18 +          use="Emulate USB devices?")
   16.19 +
   16.20 +gopts.var('usbdevice', val='NAME',
   16.21 +          fn=set_value, default='',
   16.22 +          use="Name of USB device to add?")
   16.23 +
   16.24  gopts.var('stdvga', val='no|yes',
   16.25            fn=set_bool, default=0,
   16.26            use="Use std vga or cirrhus logic graphics")
   16.27 @@ -508,8 +516,8 @@ def configure_irq(config_devs, vals):
   16.28          config_devs.append(['device', config_irq])
   16.29  
   16.30  def configure_usb(config_devs, vals):
   16.31 -    for path in vals.usb:
   16.32 -        config_usb = ['usb', ['path', path]]
   16.33 +    for path in vals.usbport:
   16.34 +        config_usb = ['usbport', ['path', path]]
   16.35          config_devs.append(['device', config_usb])
   16.36  
   16.37  
   16.38 @@ -614,7 +622,7 @@ def configure_hvm(config_image, vals):
   16.39      args = [ 'device_model', 'pae', 'vcpus', 'cdrom', 'boot', 'fda', 'fdb',
   16.40               'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'audio',
   16.41               'vnc', 'vncviewer', 'sdl', 'display', 'ne2000', 'acpi', 'apic',
   16.42 -             'xauthority' ]
   16.43 +             'xauthority', 'usb', 'usbdevice' ]
   16.44      for a in args:
   16.45          if (vals.__dict__[a]):
   16.46              config_image.append([a, vals.__dict__[a]])