aboutsummaryrefslogtreecommitdiffstats
path: root/emulators/qemu
diff options
context:
space:
mode:
authorpav <pav@FreeBSD.org>2006-03-19 05:23:42 +0800
committerpav <pav@FreeBSD.org>2006-03-19 05:23:42 +0800
commit602c89f92239cc822d1275a3e54f802718ca9837 (patch)
treeca8fd0bad6bd5a10be516b378394a0a341ad5215 /emulators/qemu
parentbd3676b58d58d592e643e0116ea9c9e4c458c814 (diff)
downloadfreebsd-ports-gnome-602c89f92239cc822d1275a3e54f802718ca9837.tar.gz
freebsd-ports-gnome-602c89f92239cc822d1275a3e54f802718ca9837.tar.zst
freebsd-ports-gnome-602c89f92239cc822d1275a3e54f802718ca9837.zip
- Add Lonnie's usb host support patches and a bunch of other fixes mostly from
cvs, including a workaround for the -nographic crash. PR: ports/94654 Submitted by: Juergen Lock <nox@jelal.kn-bremen.de> (maintainer)
Diffstat (limited to 'emulators/qemu')
-rw-r--r--emulators/qemu/Makefile2
-rw-r--r--emulators/qemu/files/patch-bsdusb.patch741
-rw-r--r--emulators/qemu/files/patch-dyngen.h11
-rw-r--r--emulators/qemu/files/patch-hw-ne2000.c44
-rw-r--r--emulators/qemu/files/patch-hw-usb-uhci.c28
-rw-r--r--emulators/qemu/files/patch-hw-usb.c11
-rw-r--r--emulators/qemu/files/patch-sdl.c29
-rw-r--r--emulators/qemu/files/patch-slirp-socket.c18
-rw-r--r--emulators/qemu/files/patch-target-i386-translate.c29
-rw-r--r--emulators/qemu/files/patch-usb-hchalt10
-rw-r--r--emulators/qemu/files/patch-usb-hubfixups87
-rw-r--r--emulators/qemu/files/patch-vl.c-nographic9
-rw-r--r--emulators/qemu/pkg-message12
13 files changed, 1030 insertions, 1 deletions
diff --git a/emulators/qemu/Makefile b/emulators/qemu/Makefile
index 61087cfb7139..28c88772c7a0 100644
--- a/emulators/qemu/Makefile
+++ b/emulators/qemu/Makefile
@@ -7,7 +7,7 @@
PORTNAME= qemu
PORTVERSION= 0.8.0
-PORTREVISION= 3
+PORTREVISION= 4
CATEGORIES= emulators
MASTER_SITES= http://www.qemu.org/:release \
http://people.fruitsalad.org/nox/qemu/:snapshot \
diff --git a/emulators/qemu/files/patch-bsdusb.patch b/emulators/qemu/files/patch-bsdusb.patch
new file mode 100644
index 000000000000..9a90b930cbea
--- /dev/null
+++ b/emulators/qemu/files/patch-bsdusb.patch
@@ -0,0 +1,741 @@
+Index: qemu/configure
+@@ -122,6 +122,7 @@
+ *)
+ oss="yes"
+ linux="yes"
++usb="linux"
+ if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
+ kqemu="yes"
+ fi
+@@ -131,6 +132,7 @@
+ if [ "$bsd" = "yes" ] ; then
+ if [ ! "$darwin" = "yes" ] ; then
+ make="gmake"
++ usb="bsd"
+ fi
+ fi
+
+@@ -656,6 +675,19 @@
+ echo "#define _BSD 1" >> $config_h
+ fi
+
++# USB host support
++case "$usb" in
++linux)
++ echo "HOST_USB=linux" >> $conig_mak
++;;
++bsd)
++ echo "HOST_USB=bsd" >> $config_mak
++;;
++*)
++ echo "HOST_USB=stub" >> $config_mak
++;;
++esac
++
+ for target in $target_list; do
+
+ target_dir="$target"
+Index: qemu/Makefile.target
+@@ -303,7 +303,7 @@
+ endif
+
+ # USB layer
+-VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o
++VL_OBJS+= usb.o usb-uhci.o usb-$(HOST_USB).o usb-hid.o
+
+ ifeq ($(TARGET_BASE_ARCH), i386)
+ # Hardware support
+Index: qemu/usb-stub.c
+@@ -0,0 +1,11 @@
++#include "vl.h"
++
++void usb_host_info(void)
++{
++ term_printf("USB host devices not supported\n");
++}
++
++USBDevice *usb_host_device_open(const char *devname)
++{
++ return NULL;
++}
+Index: qemu/usb-bsd.c
+@@ -0,0 +1,592 @@
++/*
++ * BSD host USB redirector
++ *
++ * Copyright (c) 2005 Lonnie Mendez
++ * Portions of code and concepts borrowed from
++ * usb-linux.c and libusb's bsd.c and are copyright their respective owners.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
++ * THE SOFTWARE.
++ */
++
++#include "vl.h"
++
++/* usb.h declares these */
++#undef USB_SPEED_HIGH
++#undef USB_SPEED_FULL
++#undef USB_SPEED_LOW
++
++#include <sys/ioctl.h>
++#include <dev/usb/usb.h>
++#include <signal.h>
++
++/* This value has maximum potential at 16.
++ * You should also set hw.usb.debug to gain
++ * more detailed view.
++ */
++//#define DEBUG
++#define UGEN_DEBUG_LEVEL 0
++
++
++typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
++ int vendor_id, int product_id,
++ const char *product_name, int speed);
++static int usb_host_find_device(int *pbus_num, int *paddr,
++ const char *devname);
++
++typedef struct USBHostDevice {
++ USBDevice dev;
++ int ep_fd[USB_MAX_ENDPOINTS];
++ int devfd;
++ char devpath[32];
++} USBHostDevice;
++
++
++static int ensure_ep_open(USBHostDevice *dev, int ep, int mode)
++{
++ char buf[32];
++ int fd;
++
++ /* Get the address for this endpoint */
++ ep = UE_GET_ADDR(ep);
++
++ if (dev->ep_fd[ep] < 0) {
++#if __FreeBSD__
++ snprintf(buf, sizeof(buf) - 1, "%s.%d", dev->devpath, ep);
++#else
++ snprintf(buf, sizeof(buf) - 1, "%s.%02d", dev->devpath, ep);
++#endif
++ /* Try to open it O_RDWR first for those devices which have in and out
++ * endpoints with the same address (eg 0x02 and 0x82)
++ */
++ fd = open(buf, O_RDWR);
++ if (fd < 0 && errno == ENXIO)
++ fd = open(buf, mode);
++ if (fd < 0) {
++#ifdef DEBUG
++ printf("ensure_ep_open: failed to open device endpoint %s: %s\n",
++ buf, strerror(errno));
++#endif
++ }
++ dev->ep_fd[ep] = fd;
++ }
++
++ return dev->ep_fd[ep];
++}
++
++static void ensure_eps_closed(USBHostDevice *dev)
++{
++ int epnum = 1;
++
++ if (!dev)
++ return;
++
++ while (epnum < USB_MAX_ENDPOINTS) {
++ if (dev->ep_fd[epnum] >= 0) {
++ close(dev->ep_fd[epnum]);
++ dev->ep_fd[epnum] = -1;
++ }
++ epnum++;
++ }
++}
++
++static void usb_host_handle_reset(USBDevice *dev)
++{
++#if 0
++ USBHostDevice *s = (USBHostDevice *)dev;
++#endif
++}
++
++/* XXX:
++ * -check device states against transfer requests
++ * and return appropriate response
++ */
++static int usb_host_handle_control(USBDevice *dev,
++ int request,
++ int value,
++ int index,
++ int length,
++ uint8_t *data)
++{
++ USBHostDevice *s = (USBHostDevice *)dev;
++ struct usb_ctl_request req;
++ struct usb_alt_interface aiface;
++ int ret, timeout = 50;
++
++ if ((request >> 8) == UT_WRITE_DEVICE &&
++ (request & 0xff) == UR_SET_ADDRESS) {
++
++ /* specific SET_ADDRESS support */
++ dev->addr = value;
++ return 0;
++ } else if ((request >> 8) == UT_WRITE_DEVICE &&
++ (request & 0xff) == UR_SET_CONFIG) {
++
++ ensure_eps_closed(s); /* can't do this without all eps closed */
++
++ ret = ioctl(s->devfd, USB_SET_CONFIG, &value);
++ if (ret < 0) {
++#ifdef DEBUG
++ printf("handle_control: failed to set configuration - %s\n",
++ strerror(errno));
++#endif
++ return USB_RET_STALL;
++ }
++
++ return 0;
++ } else if ((request >> 8) == UT_WRITE_INTERFACE &&
++ (request & 0xff) == UR_SET_INTERFACE) {
++
++ aiface.uai_interface_index = index;
++ aiface.uai_alt_no = value;
++
++ ensure_eps_closed(s); /* can't do this without all eps closed */
++ ret = ioctl(s->devfd, USB_SET_ALTINTERFACE, &aiface);
++ if (ret < 0) {
++#ifdef DEBUG
++ printf("handle_control: failed to set alternate interface - %s\n",
++ strerror(errno));
++#endif
++ return USB_RET_STALL;
++ }
++
++ return 0;
++ } else {
++ req.ucr_request.bmRequestType = request >> 8;
++ req.ucr_request.bRequest = request & 0xff;
++ USETW(req.ucr_request.wValue, value);
++ USETW(req.ucr_request.wIndex, index);
++ USETW(req.ucr_request.wLength, length);
++ req.ucr_data = data;
++ req.ucr_flags = USBD_SHORT_XFER_OK;
++
++ ret = ioctl(s->devfd, USB_SET_TIMEOUT, &timeout);
++#if (__NetBSD__ || __OpenBSD__)
++ if (ret < 0 && errno != EINVAL) {
++#else
++ if (ret < 0) {
++#endif
++#ifdef DEBUG
++ printf("handle_control: setting timeout failed - %s\n",
++ strerror(errno));
++#endif
++ }
++
++ ret = ioctl(s->devfd, USB_DO_REQUEST, &req);
++ /* ugen returns EIO for usbd_do_request_ no matter what
++ * happens with the transfer */
++ if (ret < 0) {
++#ifdef DEBUG
++ printf("handle_control: error after request - %s\n",
++ strerror(errno));
++#endif
++ return USB_RET_NAK; // STALL
++ } else {
++ return req.ucr_actlen;
++ }
++ }
++}
++
++static int usb_host_handle_data(USBDevice *dev, int pid,
++ uint8_t devep,
++ uint8_t *data, int len)
++{
++ USBHostDevice *s = (USBHostDevice *)dev;
++ int ret, fd, mode;
++ int one = 1, shortpacket = 0, timeout = 50;
++ sigset_t new_mask, old_mask;
++
++ /* protect data transfers from SIGALRM signal */
++ sigemptyset(&new_mask);
++ sigaddset(&new_mask, SIGALRM);
++ sigprocmask(SIG_BLOCK, &new_mask, &old_mask);
++
++ /* XXX: optimize and handle all data types by looking at the
++ config descriptor */
++ if (pid == USB_TOKEN_IN) {
++ devep |= 0x80;
++ mode = O_RDONLY;
++ shortpacket = 1;
++ } else {
++ mode = O_WRONLY;
++ }
++
++ fd = ensure_ep_open(s, devep, mode);
++ if (fd < 0) {
++ sigprocmask(SIG_SETMASK, &old_mask, NULL);
++ return USB_RET_NODEV;
++ }
++
++ if (ioctl(fd, USB_SET_TIMEOUT, &timeout) < 0) {
++#ifdef DEBUG
++ printf("handle_data: failed to set timeout - %s\n",
++ strerror(errno));
++#endif
++ }
++
++ if (shortpacket) {
++ if (ioctl(fd, USB_SET_SHORT_XFER, &one) < 0) {
++#ifdef DEBUG
++ printf("handle_data: failed to set short xfer mode - %s\n",
++ strerror(errno));
++#endif
++ sigprocmask(SIG_SETMASK, &old_mask, NULL);
++ }
++ }
++
++ if (pid == USB_TOKEN_IN)
++ ret = read(fd, data, len);
++ else
++ ret = write(fd, data, len);
++
++ sigprocmask(SIG_SETMASK, &old_mask, NULL);
++
++ if (ret < 0) {
++#ifdef DEBUG
++ printf("handle_data: error after %s data - %s\n",
++ pid == USB_TOKEN_IN ? "reading" : "writing", strerror(errno));
++#endif
++ switch(errno) {
++ case ETIMEDOUT:
++ case EINTR:
++ return USB_RET_NAK;
++ default:
++ return USB_RET_STALL;
++ }
++ } else {
++ return ret;
++ }
++}
++
++USBDevice *usb_host_device_open(const char *devname)
++{
++ struct usb_device_info bus_info, dev_info;
++ USBHostDevice *dev;
++ char ctlpath[PATH_MAX + 1];
++ char buspath[PATH_MAX + 1];
++ int bfd, dfd, bus, address, i;
++ int ugendebug = UGEN_DEBUG_LEVEL;
++
++ if (usb_host_find_device(&bus, &address, devname) < 0)
++ return NULL;
++
++ snprintf(buspath, PATH_MAX, "/dev/usb%d", bus);
++
++ bfd = open(buspath, O_RDWR);
++ if (bfd < 0) {
++#ifdef DEBUG
++ printf("usb_host_device_open: failed to open usb bus - %s\n",
++ strerror(errno));
++#endif
++ return NULL;
++ }
++
++ bus_info.udi_addr = address;
++ if (ioctl(bfd, USB_DEVICEINFO, &bus_info) < 0) {
++#ifdef DEBUG
++ printf("usb_host_device_open: failed to grab bus information - %s\n",
++ strerror(errno));
++#endif
++ return NULL;
++ }
++
++#if __FreeBSD__
++ snprintf(ctlpath, PATH_MAX, "/dev/%s", bus_info.udi_devnames[0]);
++#else
++ snprintf(ctlpath, PATH_MAX, "/dev/%s.00", bus_info.udi_devnames[0]);
++#endif
++
++ dfd = open(ctlpath, O_RDWR);
++ if (dfd < 0) {
++ dfd = open(ctlpath, O_RDONLY);
++ if (dfd < 0) {
++#ifdef DEBUG
++ printf("usb_host_device_open: failed to open usb device %s - %s\n",
++ ctlpath, strerror(errno));
++#endif
++ }
++ }
++
++ if (dfd >= 0) {
++ dev = qemu_mallocz(sizeof(USBHostDevice));
++ if (!dev)
++ goto fail;
++ dev->devfd = dfd;
++
++ if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0) {
++#ifdef DEBUG
++ printf("usb_host_device_open: failed to grab device info - %s\n",
++ strerror(errno));
++#endif
++ goto fail;
++ }
++
++ if (dev_info.udi_speed == 1)
++ dev->dev.speed = USB_SPEED_LOW - 1;
++ else
++ dev->dev.speed = USB_SPEED_FULL - 1;
++
++ dev->dev.handle_packet = usb_generic_handle_packet;
++
++ dev->dev.handle_reset = usb_host_handle_reset;
++ dev->dev.handle_control = usb_host_handle_control;
++ dev->dev.handle_data = usb_host_handle_data;
++
++ strcpy(dev->devpath, "/dev/");
++ strcat(dev->devpath, dev_info.udi_devnames[0]);
++
++ /* Mark the endpoints as not yet open */
++ for (i = 0; i < USB_MAX_ENDPOINTS; i++)
++ dev->ep_fd[i] = -1;
++
++ ioctl(dfd, USB_SETDEBUG, &ugendebug);
++
++ return (USBDevice *)dev;
++ }
++
++fail:
++ return NULL;
++}
++
++void usb_host_device_close(USBDevice *opaque)
++{
++ USBHostDevice *s = (USBHostDevice *)opaque;
++ int i;
++
++ for (i = 0; i < USB_MAX_ENDPOINTS; i++)
++ if (s->ep_fd[i] >= 0)
++ close(s->ep_fd[i]);
++
++ if (s->devfd < 0)
++ return;
++
++ close(s->devfd);
++}
++
++static int usb_host_scan(void *opaque, USBScanFunc *func)
++{
++ struct usb_device_info bus_info;
++ struct usb_device_info dev_info;
++ uint16_t vendor_id, product_id, class_id, speed;
++ int bfd, dfd, bus, address;
++ char busbuf[20], devbuf[20], product_name[256];
++ int ret = 0;
++
++ for (bus = 0; bus < 10; bus++) {
++
++ snprintf(busbuf, sizeof(busbuf) - 1, "/dev/usb%d", bus);
++ bfd = open(busbuf, O_RDWR);
++ if (bfd < 0)
++ continue;
++
++ for (address = 1; address < 127; address++) {
++
++ bus_info.udi_addr = address;
++ if (ioctl(bfd, USB_DEVICEINFO, &bus_info) < 0)
++ continue;
++
++ /* only list devices that can be used by generic layer */
++ if (strncmp(bus_info.udi_devnames[0], "ugen", 4) != 0)
++ continue;
++
++#if __FreeBSD__
++ snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s", bus_info.udi_devnames[0]);
++#else
++ snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s.00", bus_info.udi_devnames[0]);
++#endif
++
++ dfd = open(devbuf, O_RDONLY);
++ if (dfd < 0) {
++#ifdef DEBUG
++ printf("usb_host_scan: couldn't open device %s - %s\n", devbuf,
++ strerror(errno));
++#endif
++ continue;
++ }
++
++ if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0)
++ printf("usb_host_scan: couldn't get device information for %s - %s\n",
++ devbuf, strerror(errno));
++
++ // XXX: might need to fixup endianess of word values before copying over
++
++ vendor_id = dev_info.udi_vendorNo;
++ product_id = dev_info.udi_productNo;
++ class_id = dev_info.udi_class;
++ speed = dev_info.udi_speed;
++
++ if (strncmp(dev_info.udi_product, "product", 7) != 0)
++ strcpy(product_name, dev_info.udi_product);
++ else
++ product_name[0] = '\0';
++
++ ret = func(opaque, bus, address, class_id, vendor_id,
++ product_id, product_name, speed);
++
++ close(dfd);
++
++ if (ret)
++ goto the_end;
++ }
++
++ close(bfd);
++ }
++
++the_end:
++ return ret;
++}
++
++typedef struct FindDeviceState {
++ int vendor_id;
++ int product_id;
++ int bus_num;
++ int addr;
++} FindDeviceState;
++
++static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
++ int class_id,
++ int vendor_id, int product_id,
++ const char *product_name, int speed)
++{
++ FindDeviceState *s = opaque;
++ if (vendor_id == s->vendor_id &&
++ product_id == s->product_id) {
++ s->bus_num = bus_num;
++ s->addr = addr;
++ return 1;
++ } else {
++ return 0;
++ }
++}
++
++
++/* the syntax is :
++ 'bus.addr' (decimal numbers) or
++ 'vendor_id:product_id' (hexa numbers) */
++static int usb_host_find_device(int *pbus_num, int *paddr,
++ const char *devname)
++{
++ const char *p;
++ int ret;
++ FindDeviceState fs;
++
++ p = strchr(devname, '.');
++ if (p) {
++ *pbus_num = strtoul(devname, NULL, 0);
++ *paddr = strtoul(p + 1, NULL, 0);
++ return 0;
++ }
++ p = strchr(devname, ':');
++ if (p) {
++ fs.vendor_id = strtoul(devname, NULL, 16);
++ fs.product_id = strtoul(p + 1, NULL, 16);
++ ret = usb_host_scan(&fs, usb_host_find_device_scan);
++ if (ret) {
++ *pbus_num = fs.bus_num;
++ *paddr = fs.addr;
++ return 0;
++ }
++ }
++ return -1;
++}
++
++/**********************/
++/* USB host device info */
++
++struct usb_class_info {
++ int class;
++ const char *class_name;
++};
++
++static const struct usb_class_info usb_class_info[] = {
++ { USB_CLASS_AUDIO, "Audio"},
++ { USB_CLASS_COMM, "Communication"},
++ { USB_CLASS_HID, "HID"},
++ { USB_CLASS_HUB, "Hub" },
++ { USB_CLASS_PHYSICAL, "Physical" },
++ { USB_CLASS_PRINTER, "Printer" },
++ { USB_CLASS_MASS_STORAGE, "Storage" },
++ { USB_CLASS_CDC_DATA, "Data" },
++ { USB_CLASS_APP_SPEC, "Application Specific" },
++ { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
++ { USB_CLASS_STILL_IMAGE, "Still Image" },
++ { USB_CLASS_CSCID, "Smart Card" },
++ { USB_CLASS_CONTENT_SEC, "Content Security" },
++ { -1, NULL }
++};
++
++static const char *usb_class_str(uint8_t class)
++{
++ const struct usb_class_info *p;
++ for (p = usb_class_info; p->class != -1; p++) {
++ if (p->class == class)
++ break;
++ }
++ return p->class_name;
++}
++
++void usb_info_device(int bus_num, int addr, int class_id,
++ int vendor_id, int product_id,
++ const char *product_name,
++ int speed)
++{
++ const char *class_str, *speed_str;
++
++ switch(speed) {
++ case USB_SPEED_LOW:
++ speed_str = "1.5";
++ break;
++ case USB_SPEED_FULL:
++ speed_str = "12";
++ break;
++ case USB_SPEED_HIGH:
++ speed_str = "480";
++ break;
++ default:
++ speed_str = "?";
++ break;
++ }
++
++ term_printf(" Device %d.%d, speed %s Mb/s\n",
++ bus_num, addr, speed_str);
++ class_str = usb_class_str(class_id);
++ if (class_str)
++ term_printf(" %s:", class_str);
++ else
++ term_printf(" Class %02x:", class_id);
++ term_printf(" USB device %04x:%04x", vendor_id, product_id);
++ if (product_name[0] != '\0')
++ term_printf(", %s", product_name);
++ term_printf("\n");
++}
++
++static int usb_host_info_device(void *opaque, int bus_num, int addr,
++ int class_id,
++ int vendor_id, int product_id,
++ const char *product_name,
++ int speed)
++{
++ usb_info_device(bus_num, addr, class_id, vendor_id, product_id,
++ product_name, speed);
++ return 0;
++}
++
++void usb_host_info(void)
++{
++ usb_host_scan(NULL, usb_host_info_device);
++}
+Index: qemu/vl.c
+@@ -2820,10 +2822,12 @@
+ dev = usb_host_device_open(p);
+ if (!dev)
+ return -1;
++ dev->isproxied = 1;
+ } else if (!strcmp(devname, "mouse")) {
+ dev = usb_mouse_init();
+ if (!dev)
+ return -1;
++ dev->isproxied = 0;
+ } else {
+ return -1;
+ }
+@@ -2852,6 +2856,8 @@
+ if (dev && dev->addr == addr)
+ break;
+ }
++ if (dev && dev->isproxied)
++ usb_host_device_close(dev);
+ if (i == MAX_VM_USB_PORTS)
+ return -1;
+ usb_attach(vm_usb_ports[i], NULL);
+Index: qemu/hw/usb.h
+@@ -135,6 +146,8 @@
+ int setup_state;
+ int setup_len;
+ int setup_index;
++
++ int isproxied;
+ };
+
+ /* USB port on which a device can be connected */
+@@ -157,8 +170,9 @@
+ /* usb-uhci.c */
+ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports);
+
+-/* usb-linux.c */
++/* host proxy functions */
+ USBDevice *usb_host_device_open(const char *devname);
++void usb_host_device_close(USBDevice *dev);
+ void usb_host_info(void);
+
+ /* usb-hid.c */
+Index: qemu/usb-linux.c
+@@ -23,7 +23,6 @@
+ */
+ #include "vl.h"
+
+-#if defined(__linux__)
+ #include <dirent.h>
+ #include <sys/ioctl.h>
+ #include <linux/usbdevice_fs.h>
+@@ -255,6 +254,14 @@
+ return q - buf;
+ }
+
++void usb_host_device_close(USBDevice *opaque)
++{
++ USBHostDevice *s = (USBHostDevice *)opaque;
++
++ if (s->fd >= 0)
++ close(s->fd);
++}
++
+ static int usb_host_scan(void *opaque, USBScanFunc *func)
+ {
+ FILE *f;
+@@ -468,18 +475,3 @@
+ {
+ usb_host_scan(NULL, usb_host_info_device);
+ }
+-
+-#else
+-
+-void usb_host_info(void)
+-{
+- term_printf("USB host devices not supported\n");
+-}
+-
+-/* XXX: modify configure to compile the right host driver */
+-USBDevice *usb_host_device_open(const char *devname)
+-{
+- return NULL;
+-}
+-
+-#endif
diff --git a/emulators/qemu/files/patch-dyngen.h b/emulators/qemu/files/patch-dyngen.h
new file mode 100644
index 000000000000..09ab311dfdf6
--- /dev/null
+++ b/emulators/qemu/files/patch-dyngen.h
@@ -0,0 +1,11 @@
+# 1.9
+Index: qemu/dyngen.h
+@@ -59,7 +59,7 @@
+ {
+ unsigned long p;
+
+- p = start & ~(MIN_CACHE_LINE_SIZE - 1);
++ start &= ~(MIN_CACHE_LINE_SIZE - 1);
+ stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
+
+ for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
diff --git a/emulators/qemu/files/patch-hw-ne2000.c b/emulators/qemu/files/patch-hw-ne2000.c
new file mode 100644
index 000000000000..eec4a3f31ccc
--- /dev/null
+++ b/emulators/qemu/files/patch-hw-ne2000.c
@@ -0,0 +1,44 @@
+# 1.19
+Index: qemu/hw/ne2000.c
+@@ -648,6 +648,8 @@
+ {
+ NE2000State* s=(NE2000State*)opaque;
+
++ qemu_put_8s(f, &s->rxcr);
++
+ qemu_put_8s(f, &s->cmd);
+ qemu_put_be32s(f, &s->start);
+ qemu_put_be32s(f, &s->stop);
+@@ -672,8 +674,13 @@
+ {
+ NE2000State* s=(NE2000State*)opaque;
+
+- if (version_id != 1)
++ if (version_id == 2) {
++ qemu_get_8s(f, &s->rxcr);
++ } else if (version_id == 1) {
++ s->rxcr = 0x0c;
++ } else {
+ return -EINVAL;
++ }
+
+ qemu_get_8s(f, &s->cmd);
+ qemu_get_be32s(f, &s->start);
+@@ -732,7 +739,7 @@
+ s->macaddr[4],
+ s->macaddr[5]);
+
+- register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
++ register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s);
+ }
+
+ /***********************************************************/
+@@ -803,7 +810,7 @@
+ s->macaddr[5]);
+
+ /* XXX: instance number ? */
+- register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
++ register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s);
+ register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load,
+ &d->dev);
+ }
diff --git a/emulators/qemu/files/patch-hw-usb-uhci.c b/emulators/qemu/files/patch-hw-usb-uhci.c
new file mode 100644
index 000000000000..c5f3c36629bb
--- /dev/null
+++ b/emulators/qemu/files/patch-hw-usb-uhci.c
@@ -0,0 +1,28 @@
+# 1.6
+Index: qemu/hw/usb-uhci.c
+@@ -153,6 +153,7 @@
+ switch(addr) {
+ case 0x0c:
+ val = s->sof_timing;
++ break;
+ default:
+ val = 0xff;
+ break;
+@@ -654,6 +655,7 @@
+ pci_conf[0x0b] = 0x0c;
+ pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[0x3d] = 4; // interrupt pin 3
++ pci_conf[0x60] = 0x10; // release number
+
+ for(i = 0; i < NB_PORTS; i++) {
+ port = &s->ports[i];
+@@ -666,6 +668,8 @@
+
+ uhci_reset(s);
+
+- pci_register_io_region(&s->dev, 0, 0x20,
++ /* Use region 4 for consistency with real hardware. BSD guests seem
++ to rely on this. */
++ pci_register_io_region(&s->dev, 4, 0x20,
+ PCI_ADDRESS_SPACE_IO, uhci_map);
+ }
diff --git a/emulators/qemu/files/patch-hw-usb.c b/emulators/qemu/files/patch-hw-usb.c
new file mode 100644
index 000000000000..50f6fc884a7a
--- /dev/null
+++ b/emulators/qemu/files/patch-hw-usb.c
@@ -0,0 +1,11 @@
+# 1.4
+Index: qemu/hw/usb.c
+@@ -183,7 +183,7 @@
+
+ q = buf;
+ len = strlen(str);
+- *q++ = 2 * len + 1;
++ *q++ = 2 * len + 2;
+ *q++ = 3;
+ for(i = 0; i < len; i++) {
+ *q++ = str[i];
diff --git a/emulators/qemu/files/patch-sdl.c b/emulators/qemu/files/patch-sdl.c
new file mode 100644
index 000000000000..2b64583d0a0b
--- /dev/null
+++ b/emulators/qemu/files/patch-sdl.c
@@ -0,0 +1,29 @@
+# 1.24
+Index: qemu/sdl.c
+@@ -404,6 +404,7 @@
+ mod_state = (ev->key.keysym.mod & gui_grab_code);
+ if (!mod_state) {
+ if (gui_key_modifier_pressed) {
++ gui_key_modifier_pressed = 0;
+ if (gui_keysym == 0) {
+ /* exit/enter grab if pressing Ctrl-Alt */
+ if (!gui_grab)
+@@ -415,7 +416,6 @@
+ reset_keys();
+ break;
+ }
+- gui_key_modifier_pressed = 0;
+ gui_keysym = 0;
+ }
+ }
+@@ -456,8 +456,8 @@
+ }
+ break;
+ case SDL_ACTIVEEVENT:
+- if (gui_grab && (ev->active.gain & SDL_ACTIVEEVENTMASK) == 0 &&
+- !gui_fullscreen_initial_grab) {
++ if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
++ !ev->active.gain && !gui_fullscreen_initial_grab) {
+ sdl_grab_end();
+ }
+ break;
diff --git a/emulators/qemu/files/patch-slirp-socket.c b/emulators/qemu/files/patch-slirp-socket.c
new file mode 100644
index 000000000000..91b030ae62c3
--- /dev/null
+++ b/emulators/qemu/files/patch-slirp-socket.c
@@ -0,0 +1,18 @@
+# 1.6
+Index: qemu/slirp/socket.c
+@@ -573,6 +573,7 @@
+ addr.sin_port = port;
+
+ if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) ||
++ (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) ||
+ (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
+ (listen(s,1) < 0)) {
+ int tmperrno = errno; /* Don't clobber the real reason we failed */
+@@ -587,7 +588,6 @@
+ #endif
+ return NULL;
+ }
+- setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
+ setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
+
+ getsockname(s,(struct sockaddr *)&addr,&addrlen);
diff --git a/emulators/qemu/files/patch-target-i386-translate.c b/emulators/qemu/files/patch-target-i386-translate.c
new file mode 100644
index 000000000000..5c9be22401f7
--- /dev/null
+++ b/emulators/qemu/files/patch-target-i386-translate.c
@@ -0,0 +1,29 @@
+# 1.53
+Index: qemu/target-i386/translate.c
+@@ -5803,14 +5803,24 @@
+ op = (modrm >> 3) & 7;
+ switch(op) {
+ case 0: /* fxsave */
+- if (mod == 3 || !(s->cpuid_features & CPUID_FXSR))
++ if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
++ (s->flags & HF_EM_MASK))
+ goto illegal_op;
++ if (s->flags & HF_TS_MASK) {
++ gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
++ break;
++ }
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ gen_op_fxsave_A0((s->dflag == 2));
+ break;
+ case 1: /* fxrstor */
+- if (mod == 3 || !(s->cpuid_features & CPUID_FXSR))
++ if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
++ (s->flags & HF_EM_MASK))
+ goto illegal_op;
++ if (s->flags & HF_TS_MASK) {
++ gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
++ break;
++ }
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ gen_op_fxrstor_A0((s->dflag == 2));
+ break;
diff --git a/emulators/qemu/files/patch-usb-hchalt b/emulators/qemu/files/patch-usb-hchalt
new file mode 100644
index 000000000000..360104d5bb25
--- /dev/null
+++ b/emulators/qemu/files/patch-usb-hchalt
@@ -0,0 +1,10 @@
+Index: qemu/hw/usb-uhci.c
+@@ -527,6 +532,8 @@
+
+ if (!(s->cmd & UHCI_CMD_RS)) {
+ qemu_del_timer(s->frame_timer);
++ /* set hchalted bit in status - UHCI11D 2.1.2 */
++ s->status |= UHCI_STS_HCHALTED;
+ return;
+ }
+ frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);
diff --git a/emulators/qemu/files/patch-usb-hubfixups b/emulators/qemu/files/patch-usb-hubfixups
new file mode 100644
index 000000000000..17db3bd32806
--- /dev/null
+++ b/emulators/qemu/files/patch-usb-hubfixups
@@ -0,0 +1,87 @@
+Index: qemu/hw/usb.c
+@@ -330,9 +330,9 @@
+ 0x0a, /* u16 wHubCharacteristics; */
+ 0x00, /* (per-port OC, no power switching) */
+ 0x01, /* u8 bPwrOn2pwrGood; 2ms */
+- 0x00, /* u8 bHubContrCurrent; 0 mA */
+- 0x00, /* u8 DeviceRemovable; *** 7 Ports max *** */
+- 0xff /* u8 PortPwrCtrlMask; *** 7 ports max *** */
++ 0x00 /* u8 bHubContrCurrent; 0 mA */
++
++ /* DeviceRemovable and PortPwrCtrlMask patched in later */
+ };
+
+ static void usb_hub_attach(USBPort *port1, USBDevice *dev)
+@@ -391,6 +391,12 @@
+ }
+ ret = 0;
+ break;
++ case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
++ if (value == 0 && index != 0x81) { /* clear ep halt */
++ goto fail;
++ }
++ ret = 0;
++ break;
+ case DeviceOutRequest | USB_REQ_SET_FEATURE:
+ if (value == USB_DEVICE_REMOTE_WAKEUP) {
+ dev->remote_wakeup = 1;
+@@ -408,6 +414,11 @@
+ case USB_DT_DEVICE:
+ memcpy(data, qemu_hub_dev_descriptor,
+ sizeof(qemu_hub_dev_descriptor));
++
++ /* status change endpoint size based on number
++ * of ports */
++ data[22] = (s->nb_ports + 1 + 7) / 8;
++
+ ret = sizeof(qemu_hub_dev_descriptor);
+ break;
+ case USB_DT_CONFIG:
+@@ -558,11 +569,29 @@
+ }
+ break;
+ case GetHubDescriptor:
+- memcpy(data, qemu_hub_hub_descriptor,
+- sizeof(qemu_hub_hub_descriptor));
+- data[2] = s->nb_ports;
+- ret = sizeof(qemu_hub_hub_descriptor);
+- break;
++ {
++ unsigned int n, limit, var_hub_size = 0;
++ memcpy(data, qemu_hub_hub_descriptor,
++ sizeof(qemu_hub_hub_descriptor));
++ data[2] = s->nb_ports;
++
++ /* fill DeviceRemovable bits */
++ limit = ((s->nb_ports + 1 + 7) / 8) + 7;
++ for (n = 7; n < limit; n++) {
++ data[n] = 0x00;
++ var_hub_size++;
++ }
++
++ /* fill PortPwrCtrlMask bits */
++ limit = limit + ((s->nb_ports + 7) / 8);
++ for (;n < limit; n++) {
++ data[n] = 0xff;
++ var_hub_size++;
++ }
++
++ ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
++ break;
++ }
+ default:
+ fail:
+ ret = USB_RET_STALL;
+@@ -584,8 +613,11 @@
+ unsigned int status;
+ int i, n;
+ n = (s->nb_ports + 1 + 7) / 8;
+- if (n > len)
++ if (len == 1) { /* FreeBSD workaround */
++ n = 1;
++ } else if (n > len) {
+ return USB_RET_BABBLE;
++ }
+ status = 0;
+ for(i = 0; i < s->nb_ports; i++) {
+ port = &s->ports[i];
diff --git a/emulators/qemu/files/patch-vl.c-nographic b/emulators/qemu/files/patch-vl.c-nographic
new file mode 100644
index 000000000000..be2f002c4920
--- /dev/null
+++ b/emulators/qemu/files/patch-vl.c-nographic
@@ -0,0 +1,9 @@
+Index: qemu/vl.c
+@@ -4668,6 +4668,7 @@
+ case QEMU_OPTION_nographic:
+ pstrcpy(monitor_device, sizeof(monitor_device), "stdio");
+ pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio");
++ pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "null");
+ nographic = 1;
+ break;
+ case QEMU_OPTION_kernel:
diff --git a/emulators/qemu/pkg-message b/emulators/qemu/pkg-message
index 4728b9171ccb..c335f5b3be17 100644
--- a/emulators/qemu/pkg-message
+++ b/emulators/qemu/pkg-message
@@ -33,4 +33,16 @@ in this message: http://docs.freebsd.org/cgi/mid.cgi?200510131428.21211.jkim
(not included in the port since the used VIA VT86C926 PCI ID does not
really match the emulated nic exactly, it just `happens' to work with
6.0-RC1's driver.)
+- if you want to use usb devices connected to the host in the guest
+(usb_add host:... monitor command) you need to make sure the host isn't
+claiming them, e.g. for umass devices (like memory sticks or external
+harddrives) make sure umass isn't in the kernel (you can then still load it
+as a kld when needed), also unless you are running qemu as root you then
+need to fix permissions for /dev/ugen* device nodes: if you are on 5.x or
+later (devfs) put a rule in /etc/devfs.rules, activate it in /etc/rc.conf
+and run /etc/rc.d/devfs restart. example devfs.rules:
+ [ugen_ruleset=20]
+ add path 'ugen*' mode 660 group operator
+corresponding rc.conf line:
+ devfs_system_ruleset="ugen_ruleset"
====