* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "qemu-common.h"
#include "trace.h"
#include "hw/usb.h"
-#include "hw/usb/desc.h"
+#include "desc.h"
#include "qemu/error-report.h"
#define NUM_PORTS 8
USBHubPort ports[NUM_PORTS];
} USBHubState;
+#define TYPE_USB_HUB "usb-hub"
+#define USB_HUB(obj) OBJECT_CHECK(USBHubState, (obj), TYPE_USB_HUB)
+
#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE)
#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE)
#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR)
{
.bEndpointAddress = USB_DIR_IN | 0x01,
.bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 1 + (NUM_PORTS + 7) / 8,
+ .wMaxPacketSize = 1 + DIV_ROUND_UP(NUM_PORTS, 8),
.bInterval = 0xff,
},
}
static const uint8_t qemu_hub_hub_descriptor[] =
{
- 0x00, /* u8 bLength; patched in later */
- 0x29, /* u8 bDescriptorType; Hub-descriptor */
- 0x00, /* u8 bNbrPorts; (patched later) */
- 0x0a, /* u16 wHubCharacteristics; */
- 0x00, /* (per-port OC, no power switching) */
- 0x01, /* u8 bPwrOn2pwrGood; 2ms */
- 0x00 /* u8 bHubContrCurrent; 0 mA */
+ 0x00, /* u8 bLength; patched in later */
+ 0x29, /* u8 bDescriptorType; Hub-descriptor */
+ 0x00, /* u8 bNbrPorts; (patched later) */
+ 0x0a, /* u16 wHubCharacteristics; */
+ 0x00, /* (per-port OC, no power switching) */
+ 0x01, /* u8 bPwrOn2pwrGood; 2ms */
+ 0x00 /* u8 bHubContrCurrent; 0 mA */
/* DeviceRemovable and PortPwrCtrlMask patched in later */
};
port->wPortStatus &= ~PORT_STAT_ENABLE;
port->wPortChange |= PORT_STAT_C_ENABLE;
}
+ if (port->wPortStatus & PORT_STAT_SUSPEND) {
+ port->wPortStatus &= ~PORT_STAT_SUSPEND;
+ port->wPortChange |= PORT_STAT_C_SUSPEND;
+ }
usb_wakeup(s->intr, 0);
}
USBHubPort *port = &s->ports[port1->index];
if (port->wPortStatus & PORT_STAT_SUSPEND) {
+ port->wPortStatus &= ~PORT_STAT_SUSPEND;
port->wPortChange |= PORT_STAT_C_SUSPEND;
usb_wakeup(s->intr, 0);
}
static USBDevice *usb_hub_find_device(USBDevice *dev, uint8_t addr)
{
- USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
+ USBHubState *s = USB_HUB(dev);
USBHubPort *port;
USBDevice *downstream;
int i;
static void usb_hub_handle_reset(USBDevice *dev)
{
- USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
+ USBHubState *s = USB_HUB(dev);
USBHubPort *port;
int i;
port->wPortChange &= ~PORT_STAT_C_ENABLE;
break;
case PORT_SUSPEND:
- port->wPortStatus &= ~PORT_STAT_SUSPEND;
+ if (port->wPortStatus & PORT_STAT_SUSPEND) {
+ port->wPortStatus &= ~PORT_STAT_SUSPEND;
+
+ /*
+ * USB Spec rev2.0 11.24.2.7.2.3 C_PORT_SUSPEND
+ * "This bit is set on the following transitions:
+ * - On transition from the Resuming state to the
+ * SendEOP [sic] state"
+ *
+ * Note that this includes both remote wake-up and
+ * explicit ClearPortFeature(PORT_SUSPEND).
+ */
+ port->wPortChange |= PORT_STAT_C_SUSPEND;
+ }
break;
case PORT_C_SUSPEND:
port->wPortChange &= ~PORT_STAT_C_SUSPEND;
data[2] = NUM_PORTS;
/* fill DeviceRemovable bits */
- limit = ((NUM_PORTS + 1 + 7) / 8) + 7;
+ limit = DIV_ROUND_UP(NUM_PORTS + 1, 8) + 7;
for (n = 7; n < limit; n++) {
data[n] = 0x00;
var_hub_size++;
}
/* fill PortPwrCtrlMask bits */
- limit = limit + ((NUM_PORTS + 7) / 8);
+ limit = limit + DIV_ROUND_UP(NUM_PORTS, 8);
for (;n < limit; n++) {
data[n] = 0xff;
var_hub_size++;
unsigned int status;
uint8_t buf[4];
int i, n;
- n = (NUM_PORTS + 1 + 7) / 8;
+ n = DIV_ROUND_UP(NUM_PORTS + 1, 8);
if (p->iov.size == 1) { /* FreeBSD workaround */
n = 1;
} else if (n > p->iov.size) {
}
}
-static void usb_hub_handle_destroy(USBDevice *dev)
+static void usb_hub_unrealize(USBDevice *dev, Error **errp)
{
USBHubState *s = (USBHubState *)dev;
int i;
.complete = usb_hub_complete,
};
-static int usb_hub_initfn(USBDevice *dev)
+static void usb_hub_realize(USBDevice *dev, Error **errp)
{
- USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
+ USBHubState *s = USB_HUB(dev);
USBHubPort *port;
int i;
if (dev->port->hubcount == 5) {
- error_report("usb hub chain too deep");
- return -1;
+ error_setg(errp, "usb hub chain too deep");
+ return;
}
usb_desc_create_serial(dev);
usb_port_location(&port->port, dev->port, i+1);
}
usb_hub_handle_reset(dev);
- return 0;
}
static const VMStateDescription vmstate_usb_hub_port = {
.name = "usb-hub-port",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField []) {
+ .fields = (VMStateField[]) {
VMSTATE_UINT16(wPortStatus, USBHubPort),
VMSTATE_UINT16(wPortChange, USBHubPort),
VMSTATE_END_OF_LIST()
.name = "usb-hub",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField []) {
+ .fields = (VMStateField[]) {
VMSTATE_USB_DEVICE(dev, USBHubState),
VMSTATE_STRUCT_ARRAY(ports, USBHubState, NUM_PORTS, 0,
vmstate_usb_hub_port, USBHubPort),
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
- uc->init = usb_hub_initfn;
+ uc->realize = usb_hub_realize;
uc->product_desc = "QEMU USB Hub";
uc->usb_desc = &desc_hub;
uc->find_device = usb_hub_find_device;
uc->handle_reset = usb_hub_handle_reset;
uc->handle_control = usb_hub_handle_control;
uc->handle_data = usb_hub_handle_data;
- uc->handle_destroy = usb_hub_handle_destroy;
+ uc->unrealize = usb_hub_unrealize;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->fw_name = "hub";
dc->vmsd = &vmstate_usb_hub;
}
static const TypeInfo hub_info = {
- .name = "usb-hub",
+ .name = TYPE_USB_HUB,
.parent = TYPE_USB_DEVICE,
.instance_size = sizeof(USBHubState),
.class_init = usb_hub_class_initfn,