All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gerd Hoffmann <kraxel@redhat.com>
To: qemu-devel@nongnu.org
Cc: Eduardo Habkost <ehabkost@redhat.com>, Gerd Hoffmann <kraxel@redhat.com>
Subject: [Qemu-devel] [PULL 8/9] usb-hub: emulate per port power switching
Date: Wed, 29 May 2019 08:28:31 +0200	[thread overview]
Message-ID: <20190529062832.26483-9-kraxel@redhat.com> (raw)
In-Reply-To: <20190529062832.26483-1-kraxel@redhat.com>

Add support for per port power switching.
Virtual power of course ;)

Use port-power=on property to enable this.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20190524070310.4952-6-kraxel@redhat.com
---
 hw/usb/dev-hub.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 29f4d6723e26..2b64d6ef0349 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -24,6 +24,7 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "qemu-common.h"
+#include "qemu/timer.h"
 #include "trace.h"
 #include "hw/usb.h"
 #include "desc.h"
@@ -41,6 +42,8 @@ typedef struct USBHubState {
     USBDevice dev;
     USBEndpoint *intr;
     uint32_t num_ports;
+    bool port_power;
+    QEMUTimer *port_timer;
     USBHubPort ports[MAX_PORTS];
 } USBHubState;
 
@@ -203,6 +206,20 @@ static bool usb_hub_port_update(USBHubPort *port)
     return notify;
 }
 
+static void usb_hub_port_update_timer(void *opaque)
+{
+    USBHubState *s = opaque;
+    bool notify = false;
+    int i;
+
+    for (i = 0; i < s->num_ports; i++) {
+        notify |= usb_hub_port_update(&s->ports[i]);
+    }
+    if (notify) {
+        usb_wakeup(s->intr, 0);
+    }
+}
+
 static void usb_hub_attach(USBPort *port1)
 {
     USBHubState *s = port1->opaque;
@@ -405,6 +422,11 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
                 usb_wakeup(s->intr, 0);
                 break;
             case PORT_POWER:
+                if (s->port_power) {
+                    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+                    usb_hub_port_set(port, PORT_STAT_POWER);
+                    timer_mod(s->port_timer, now + 5000000); /* 5 ms */
+                }
                 break;
             default:
                 goto fail;
@@ -445,6 +467,14 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
             case PORT_C_RESET:
                 port->wPortChange &= ~PORT_STAT_C_RESET;
                 break;
+            case PORT_POWER:
+                if (s->port_power) {
+                    usb_hub_port_clear(port, PORT_STAT_POWER);
+                    usb_hub_port_clear(port, PORT_STAT_CONNECTION);
+                    usb_hub_port_clear(port, PORT_STAT_ENABLE);
+                    usb_hub_port_clear(port, PORT_STAT_SUSPEND);
+                    port->wPortChange = 0;
+                }
             default:
                 goto fail;
             }
@@ -457,6 +487,11 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
                    sizeof(qemu_hub_hub_descriptor));
             data[2] = s->num_ports;
 
+            if (s->port_power) {
+                data[3] &= ~0x03;
+                data[3] |= 0x01;
+            }
+
             /* fill DeviceRemovable bits */
             limit = DIV_ROUND_UP(s->num_ports + 1, 8) + 7;
             for (n = 7; n < limit; n++) {
@@ -536,6 +571,9 @@ static void usb_hub_unrealize(USBDevice *dev, Error **errp)
         usb_unregister_port(usb_bus_from_device(dev),
                             &s->ports[i].port);
     }
+
+    timer_del(s->port_timer);
+    timer_free(s->port_timer);
 }
 
 static USBPortOps usb_hub_port_ops = {
@@ -565,6 +603,8 @@ static void usb_hub_realize(USBDevice *dev, Error **errp)
 
     usb_desc_create_serial(dev);
     usb_desc_init(dev);
+    s->port_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                 usb_hub_port_update_timer, s);
     s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
     for (i = 0; i < s->num_ports; i++) {
         port = &s->ports[i];
@@ -587,6 +627,24 @@ static const VMStateDescription vmstate_usb_hub_port = {
     }
 };
 
+static bool usb_hub_port_timer_needed(void *opaque)
+{
+    USBHubState *s = opaque;
+
+    return s->port_power;
+}
+
+static const VMStateDescription vmstate_usb_hub_port_timer = {
+    .name = "usb-hub/port-timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = usb_hub_port_timer_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_TIMER_PTR(port_timer, USBHubState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
 static const VMStateDescription vmstate_usb_hub = {
     .name = "usb-hub",
     .version_id = 1,
@@ -596,11 +654,16 @@ static const VMStateDescription vmstate_usb_hub = {
         VMSTATE_STRUCT_ARRAY(ports, USBHubState, MAX_PORTS, 0,
                              vmstate_usb_hub_port, USBHubPort),
         VMSTATE_END_OF_LIST()
+    },
+    .subsections = (const VMStateDescription * []) {
+        &vmstate_usb_hub_port_timer,
+        NULL
     }
 };
 
 static Property usb_hub_properties[] = {
     DEFINE_PROP_UINT32("ports", USBHubState, num_ports, 8),
+    DEFINE_PROP_BOOL("port-power", USBHubState, port_power, false),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-- 
2.18.1



  parent reply	other threads:[~2019-05-29  6:37 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-29  6:28 [Qemu-devel] [PULL 0/9] Usb 20190529 patches Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 1/9] usb: call reset handler before updating state Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 2/9] usb-host: skip reset for untouched devices Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 3/9] usb-host: avoid libusb_set_configuration calls Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 4/9] usb-hub: tweak feature names Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 5/9] usb-hub: make number of ports runtime-configurable Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 6/9] usb-hub: add helpers to update port state Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 7/9] usb-hub: add usb_hub_port_update() Gerd Hoffmann
2019-05-29  6:28 ` Gerd Hoffmann [this message]
2019-05-29  6:28 ` [Qemu-devel] [PULL 9/9] usb-tablet: fix serial compat property Gerd Hoffmann
2019-05-30 14:07 ` [Qemu-devel] [PULL 0/9] Usb 20190529 patches Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190529062832.26483-9-kraxel@redhat.com \
    --to=kraxel@redhat.com \
    --cc=ehabkost@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.