Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 18 Mar 2006 20:47:56 +0100 (CET)
From:      Juergen Lock <nox@jelal.kn-bremen.de>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   ports/94654: add usb host support and a few other fixes to emulators/qemu
Message-ID:  <200603181947.k2IJluBT033946@saturn.kn-bremen.de>
Resent-Message-ID: <200603182000.k2IK0Ved002321@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         94654
>Category:       ports
>Synopsis:       add usb host support and a few other fixes to emulators/qemu
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          maintainer-update
>Submitter-Id:   current-users
>Arrival-Date:   Sat Mar 18 20:00:30 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Juergen Lock
>Release:        FreeBSD 5.5-PRERELEASE i386
>Organization:
me?  organized??
>Environment:
System: FreeBSD saturn 5.5-PRERELEASE FreeBSD 5.5-PRERELEASE #0: Fri Mar 17 04:37:54 CET 2006 nox@saturn:/usr/obj/usr/home/nox/src-r5/src/sys/NEPTUNu i386


>Description:
	this adds Lonnie's usb host support patches and a bunch of
	other fixes mostly from cvs, including a workaround for the
	-nographic crash.  (not updating to cvs fully because that
	requires a new kqemu which afaik doesn't work on amd64 hosts yet.)

>How-To-Repeat:
	n/a
>Fix:

New files:
files/patch-bsdusb.patch files/patch-dyngen.h files/patch-hw-ne2000.c
files/patch-hw-usb-uhci.c files/patch-hw-usb.c
files/patch-sdl.c files/patch-slirp-socket.c
files/patch-target-i386-translate.c files/patch-usb-hchalt
files/patch-usb-hubfixups files/patch-vl.c-nographic

Index: Makefile
===================================================================
RCS file: /home/ncvs/ports/emulators/qemu/Makefile,v
retrieving revision 1.45
diff -u -r1.45 Makefile
--- Makefile	21 Jan 2006 23:41:48 -0000	1.45
+++ Makefile	15 Mar 2006 20:34:33 -0000
@@ -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 \
Index: pkg-message
===================================================================
RCS file: /home/ncvs/ports/emulators/qemu/pkg-message,v
retrieving revision 1.11
diff -u -r1.11 pkg-message
--- pkg-message	3 Dec 2005 03:18:40 -0000	1.11
+++ pkg-message	18 Mar 2006 19:23:00 -0000
@@ -33,4 +33,16 @@
 (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"
 ====
Index: 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
Index: 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) {
Index: 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);
+ }
Index: 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);
+ }
Index: 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];
Index: 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;
Index: 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);
Index: 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;
Index: 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);
Index: 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];
Index: 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:
>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200603181947.k2IJluBT033946>