* 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 "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)
{
.bNumInterfaces = 1,
.bConfigurationValue = 1,
- .bmAttributes = 0xe0,
+ .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER |
+ USB_CFG_ATT_WAKEUP,
.nif = 1,
.ifs = &desc_iface_hub,
},
} else {
port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
}
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
}
static void usb_hub_detach(USBPort *port1)
USBHubPort *port = &s->ports[port1->index];
trace_usb_hub_detach(s->dev.addr, port1->index + 1);
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
/* Let upstream know the device on this port is gone */
s->dev.port->ops->child_detach(s->dev.port, port1->dev);
port->wPortStatus &= ~PORT_STAT_ENABLE;
port->wPortChange |= PORT_STAT_C_ENABLE;
}
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
}
static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
if (port->wPortStatus & PORT_STAT_SUSPEND) {
port->wPortChange |= PORT_STAT_C_SUSPEND;
- usb_wakeup(s->intr);
+ 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_RESET;
/* set enable bit */
port->wPortStatus |= PORT_STAT_ENABLE;
- usb_wakeup(s->intr);
+ usb_wakeup(s->intr, 0);
}
break;
case PORT_POWER:
status |= (1 << (i + 1));
}
if (status != 0) {
+ trace_usb_hub_status_report(s->dev.addr, status);
for(i = 0; i < n; i++) {
buf[i] = status >> (8 * 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_setg(errp, "usb hub chain too deep");
+ return;
+ }
+
usb_desc_create_serial(dev);
usb_desc_init(dev);
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
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_control = usb_hub_handle_control;
uc->handle_data = usb_hub_handle_data;
uc->handle_destroy = usb_hub_handle_destroy;
+ 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,