mirror of https://github.com/xemu-project/xemu.git
Merge remote-tracking branch 'kraxel/usb.74' into staging
* kraxel/usb.74: usb-tablet: Allow connecting to ehci ehci: Lower timer freq when the periodic schedule is idle usb: Allow overriding of usb_desc at the device level usb: Don't allow USB_RET_ASYNC for interrupt packets usb: Call wakeup when data becomes available for all devices with int eps add pc-1.4 Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
commit
c62adbee15
24
hw/pc_piix.c
24
hw/pc_piix.c
|
@ -281,8 +281,8 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static QEMUMachine pc_machine_v1_3 = {
|
static QEMUMachine pc_machine_v1_4 = {
|
||||||
.name = "pc-1.3",
|
.name = "pc-1.4",
|
||||||
.alias = "pc",
|
.alias = "pc",
|
||||||
.desc = "Standard PC",
|
.desc = "Standard PC",
|
||||||
.init = pc_init_pci_1_3,
|
.init = pc_init_pci_1_3,
|
||||||
|
@ -290,7 +290,26 @@ static QEMUMachine pc_machine_v1_3 = {
|
||||||
.is_default = 1,
|
.is_default = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define PC_COMPAT_1_3 \
|
||||||
|
{\
|
||||||
|
.driver = "usb-tablet",\
|
||||||
|
.property = "usb_version",\
|
||||||
|
.value = stringify(1),\
|
||||||
|
}
|
||||||
|
|
||||||
|
static QEMUMachine pc_machine_v1_3 = {
|
||||||
|
.name = "pc-1.3",
|
||||||
|
.desc = "Standard PC",
|
||||||
|
.init = pc_init_pci_1_3,
|
||||||
|
.max_cpus = 255,
|
||||||
|
.compat_props = (GlobalProperty[]) {
|
||||||
|
PC_COMPAT_1_3,
|
||||||
|
{ /* end of list */ }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
#define PC_COMPAT_1_2 \
|
#define PC_COMPAT_1_2 \
|
||||||
|
PC_COMPAT_1_3,\
|
||||||
{\
|
{\
|
||||||
.driver = "nec-usb-xhci",\
|
.driver = "nec-usb-xhci",\
|
||||||
.property = "msi",\
|
.property = "msi",\
|
||||||
|
@ -626,6 +645,7 @@ static QEMUMachine xenfv_machine = {
|
||||||
|
|
||||||
static void pc_machine_init(void)
|
static void pc_machine_init(void)
|
||||||
{
|
{
|
||||||
|
qemu_register_machine(&pc_machine_v1_4);
|
||||||
qemu_register_machine(&pc_machine_v1_3);
|
qemu_register_machine(&pc_machine_v1_3);
|
||||||
qemu_register_machine(&pc_machine_v1_2);
|
qemu_register_machine(&pc_machine_v1_2);
|
||||||
qemu_register_machine(&pc_machine_v1_1);
|
qemu_register_machine(&pc_machine_v1_1);
|
||||||
|
|
2
hw/usb.h
2
hw/usb.h
|
@ -197,6 +197,7 @@ struct USBEndpoint {
|
||||||
|
|
||||||
enum USBDeviceFlags {
|
enum USBDeviceFlags {
|
||||||
USB_DEV_FLAG_FULL_PATH,
|
USB_DEV_FLAG_FULL_PATH,
|
||||||
|
USB_DEV_FLAG_IS_HOST,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* definition of a USB device */
|
/* definition of a USB device */
|
||||||
|
@ -229,6 +230,7 @@ struct USBDevice {
|
||||||
USBEndpoint ep_out[USB_MAX_ENDPOINTS];
|
USBEndpoint ep_out[USB_MAX_ENDPOINTS];
|
||||||
|
|
||||||
QLIST_HEAD(, USBDescString) strings;
|
QLIST_HEAD(, USBDescString) strings;
|
||||||
|
const USBDesc *usb_desc; /* Overrides class usb_desc if not NULL */
|
||||||
const USBDescDevice *device;
|
const USBDescDevice *device;
|
||||||
|
|
||||||
int configuration;
|
int configuration;
|
||||||
|
|
|
@ -166,6 +166,9 @@ const char *usb_device_get_product_desc(USBDevice *dev)
|
||||||
const USBDesc *usb_device_get_usb_desc(USBDevice *dev)
|
const USBDesc *usb_device_get_usb_desc(USBDevice *dev)
|
||||||
{
|
{
|
||||||
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
|
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
|
||||||
|
if (dev->usb_desc) {
|
||||||
|
return dev->usb_desc;
|
||||||
|
}
|
||||||
return klass->usb_desc;
|
return klass->usb_desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -406,7 +406,11 @@ void usb_handle_packet(USBDevice *dev, USBPacket *p)
|
||||||
if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) {
|
if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) {
|
||||||
usb_process_one(p);
|
usb_process_one(p);
|
||||||
if (p->status == USB_RET_ASYNC) {
|
if (p->status == USB_RET_ASYNC) {
|
||||||
|
/* hcd drivers cannot handle async for isoc */
|
||||||
assert(p->ep->type != USB_ENDPOINT_XFER_ISOC);
|
assert(p->ep->type != USB_ENDPOINT_XFER_ISOC);
|
||||||
|
/* using async for interrupt packets breaks migration */
|
||||||
|
assert(p->ep->type != USB_ENDPOINT_XFER_INT ||
|
||||||
|
(dev->flags & USB_DEV_FLAG_IS_HOST));
|
||||||
usb_packet_set_state(p, USB_PACKET_ASYNC);
|
usb_packet_set_state(p, USB_PACKET_ASYNC);
|
||||||
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
|
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
|
||||||
} else if (p->status == USB_RET_ADD_TO_QUEUE) {
|
} else if (p->status == USB_RET_ADD_TO_QUEUE) {
|
||||||
|
|
|
@ -46,6 +46,7 @@ typedef struct USBHIDState {
|
||||||
USBDevice dev;
|
USBDevice dev;
|
||||||
USBEndpoint *intr;
|
USBEndpoint *intr;
|
||||||
HIDState hid;
|
HIDState hid;
|
||||||
|
uint32_t usb_version;
|
||||||
} USBHIDState;
|
} USBHIDState;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -131,6 +132,36 @@ static const USBDescIface desc_iface_tablet = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const USBDescIface desc_iface_tablet2 = {
|
||||||
|
.bInterfaceNumber = 0,
|
||||||
|
.bNumEndpoints = 1,
|
||||||
|
.bInterfaceClass = USB_CLASS_HID,
|
||||||
|
.bInterfaceProtocol = 0x02,
|
||||||
|
.ndesc = 1,
|
||||||
|
.descs = (USBDescOther[]) {
|
||||||
|
{
|
||||||
|
/* HID descriptor */
|
||||||
|
.data = (uint8_t[]) {
|
||||||
|
0x09, /* u8 bLength */
|
||||||
|
USB_DT_HID, /* u8 bDescriptorType */
|
||||||
|
0x01, 0x00, /* u16 HID_class */
|
||||||
|
0x00, /* u8 country_code */
|
||||||
|
0x01, /* u8 num_descriptors */
|
||||||
|
USB_DT_REPORT, /* u8 type: Report */
|
||||||
|
74, 0, /* u16 len */
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.eps = (USBDescEndpoint[]) {
|
||||||
|
{
|
||||||
|
.bEndpointAddress = USB_DIR_IN | 0x01,
|
||||||
|
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||||
|
.wMaxPacketSize = 8,
|
||||||
|
.bInterval = 4, /* 2 ^ (4-1) * 125 usecs = 1 ms */
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static const USBDescIface desc_iface_keyboard = {
|
static const USBDescIface desc_iface_keyboard = {
|
||||||
.bInterfaceNumber = 0,
|
.bInterfaceNumber = 0,
|
||||||
.bNumEndpoints = 1,
|
.bNumEndpoints = 1,
|
||||||
|
@ -196,6 +227,23 @@ static const USBDescDevice desc_device_tablet = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const USBDescDevice desc_device_tablet2 = {
|
||||||
|
.bcdUSB = 0x0200,
|
||||||
|
.bMaxPacketSize0 = 64,
|
||||||
|
.bNumConfigurations = 1,
|
||||||
|
.confs = (USBDescConfig[]) {
|
||||||
|
{
|
||||||
|
.bNumInterfaces = 1,
|
||||||
|
.bConfigurationValue = 1,
|
||||||
|
.iConfiguration = STR_CONFIG_TABLET,
|
||||||
|
.bmAttributes = 0xa0,
|
||||||
|
.bMaxPower = 50,
|
||||||
|
.nif = 1,
|
||||||
|
.ifs = &desc_iface_tablet2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static const USBDescDevice desc_device_keyboard = {
|
static const USBDescDevice desc_device_keyboard = {
|
||||||
.bcdUSB = 0x0100,
|
.bcdUSB = 0x0100,
|
||||||
.bMaxPacketSize0 = 8,
|
.bMaxPacketSize0 = 8,
|
||||||
|
@ -239,6 +287,20 @@ static const USBDesc desc_tablet = {
|
||||||
.str = desc_strings,
|
.str = desc_strings,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const USBDesc desc_tablet2 = {
|
||||||
|
.id = {
|
||||||
|
.idVendor = 0x0627,
|
||||||
|
.idProduct = 0x0001,
|
||||||
|
.bcdDevice = 0,
|
||||||
|
.iManufacturer = STR_MANUFACTURER,
|
||||||
|
.iProduct = STR_PRODUCT_TABLET,
|
||||||
|
.iSerialNumber = STR_SERIALNUMBER,
|
||||||
|
},
|
||||||
|
.full = &desc_device_tablet,
|
||||||
|
.high = &desc_device_tablet2,
|
||||||
|
.str = desc_strings,
|
||||||
|
};
|
||||||
|
|
||||||
static const USBDesc desc_keyboard = {
|
static const USBDesc desc_keyboard = {
|
||||||
.id = {
|
.id = {
|
||||||
.idVendor = 0x0627,
|
.idVendor = 0x0627,
|
||||||
|
@ -508,6 +570,21 @@ static int usb_hid_initfn(USBDevice *dev, int kind)
|
||||||
|
|
||||||
static int usb_tablet_initfn(USBDevice *dev)
|
static int usb_tablet_initfn(USBDevice *dev)
|
||||||
{
|
{
|
||||||
|
USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
|
||||||
|
|
||||||
|
switch (us->usb_version) {
|
||||||
|
case 1:
|
||||||
|
dev->usb_desc = &desc_tablet;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
dev->usb_desc = &desc_tablet2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_report("Invalid usb version %d for usb-tabler (must be 1 or 2)",
|
||||||
|
us->usb_version);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return usb_hid_initfn(dev, HID_TABLET);
|
return usb_hid_initfn(dev, HID_TABLET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,8 +639,14 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data)
|
||||||
uc->handle_control = usb_hid_handle_control;
|
uc->handle_control = usb_hid_handle_control;
|
||||||
uc->handle_data = usb_hid_handle_data;
|
uc->handle_data = usb_hid_handle_data;
|
||||||
uc->handle_destroy = usb_hid_handle_destroy;
|
uc->handle_destroy = usb_hid_handle_destroy;
|
||||||
|
uc->handle_attach = usb_desc_attach;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Property usb_tablet_properties[] = {
|
||||||
|
DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
|
static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
@ -572,8 +655,8 @@ static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
|
||||||
usb_hid_class_initfn(klass, data);
|
usb_hid_class_initfn(klass, data);
|
||||||
uc->init = usb_tablet_initfn;
|
uc->init = usb_tablet_initfn;
|
||||||
uc->product_desc = "QEMU USB Tablet";
|
uc->product_desc = "QEMU USB Tablet";
|
||||||
uc->usb_desc = &desc_tablet;
|
|
||||||
dc->vmsd = &vmstate_usb_ptr;
|
dc->vmsd = &vmstate_usb_ptr;
|
||||||
|
dc->props = usb_tablet_properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypeInfo usb_tablet_info = {
|
static TypeInfo usb_tablet_info = {
|
||||||
|
|
|
@ -184,6 +184,7 @@ static void usb_hub_detach(USBPort *port1)
|
||||||
port->wPortStatus &= ~PORT_STAT_ENABLE;
|
port->wPortStatus &= ~PORT_STAT_ENABLE;
|
||||||
port->wPortChange |= PORT_STAT_C_ENABLE;
|
port->wPortChange |= PORT_STAT_C_ENABLE;
|
||||||
}
|
}
|
||||||
|
usb_wakeup(s->intr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
|
static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
|
||||||
|
@ -363,6 +364,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
|
||||||
port->wPortChange |= PORT_STAT_C_RESET;
|
port->wPortChange |= PORT_STAT_C_RESET;
|
||||||
/* set enable bit */
|
/* set enable bit */
|
||||||
port->wPortStatus |= PORT_STAT_ENABLE;
|
port->wPortStatus |= PORT_STAT_ENABLE;
|
||||||
|
usb_wakeup(s->intr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PORT_POWER:
|
case PORT_POWER:
|
||||||
|
|
|
@ -639,6 +639,8 @@ typedef struct USBNetState {
|
||||||
unsigned int in_ptr, in_len;
|
unsigned int in_ptr, in_len;
|
||||||
uint8_t in_buf[2048];
|
uint8_t in_buf[2048];
|
||||||
|
|
||||||
|
USBEndpoint *intr;
|
||||||
|
|
||||||
char usbstring_mac[13];
|
char usbstring_mac[13];
|
||||||
NICState *nic;
|
NICState *nic;
|
||||||
NICConf conf;
|
NICConf conf;
|
||||||
|
@ -851,6 +853,10 @@ static void *rndis_queue_response(USBNetState *s, unsigned int length)
|
||||||
struct rndis_response *r =
|
struct rndis_response *r =
|
||||||
g_malloc0(sizeof(struct rndis_response) + length);
|
g_malloc0(sizeof(struct rndis_response) + length);
|
||||||
|
|
||||||
|
if (QTAILQ_EMPTY(&s->rndis_resp)) {
|
||||||
|
usb_wakeup(s->intr);
|
||||||
|
}
|
||||||
|
|
||||||
QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries);
|
QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries);
|
||||||
r->length = length;
|
r->length = length;
|
||||||
|
|
||||||
|
@ -1349,6 +1355,7 @@ static int usb_net_initfn(USBDevice *dev)
|
||||||
s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */;
|
s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */;
|
||||||
s->filter = 0;
|
s->filter = 0;
|
||||||
s->vendorid = 0x1234;
|
s->vendorid = 0x1234;
|
||||||
|
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
|
||||||
|
|
||||||
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
||||||
s->nic = qemu_new_nic(&net_usbnet_info, &s->conf,
|
s->nic = qemu_new_nic(&net_usbnet_info, &s->conf,
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
|
|
||||||
typedef struct USBWacomState {
|
typedef struct USBWacomState {
|
||||||
USBDevice dev;
|
USBDevice dev;
|
||||||
|
USBEndpoint *intr;
|
||||||
QEMUPutMouseEntry *eh_entry;
|
QEMUPutMouseEntry *eh_entry;
|
||||||
int dx, dy, dz, buttons_state;
|
int dx, dy, dz, buttons_state;
|
||||||
int x, y;
|
int x, y;
|
||||||
|
@ -137,6 +138,7 @@ static void usb_mouse_event(void *opaque,
|
||||||
s->dz += dz1;
|
s->dz += dz1;
|
||||||
s->buttons_state = buttons_state;
|
s->buttons_state = buttons_state;
|
||||||
s->changed = 1;
|
s->changed = 1;
|
||||||
|
usb_wakeup(s->intr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_wacom_event(void *opaque,
|
static void usb_wacom_event(void *opaque,
|
||||||
|
@ -150,6 +152,7 @@ static void usb_wacom_event(void *opaque,
|
||||||
s->dz += dz;
|
s->dz += dz;
|
||||||
s->buttons_state = buttons_state;
|
s->buttons_state = buttons_state;
|
||||||
s->changed = 1;
|
s->changed = 1;
|
||||||
|
usb_wakeup(s->intr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int int_clamp(int val, int vmin, int vmax)
|
static inline int int_clamp(int val, int vmin, int vmax)
|
||||||
|
@ -337,6 +340,7 @@ static int usb_wacom_initfn(USBDevice *dev)
|
||||||
USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
|
USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
|
||||||
usb_desc_create_serial(dev);
|
usb_desc_create_serial(dev);
|
||||||
usb_desc_init(dev);
|
usb_desc_init(dev);
|
||||||
|
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
|
||||||
s->changed = 1;
|
s->changed = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@
|
||||||
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
|
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
|
||||||
#define MAX_QH 100 // Max allowable queue heads in a chain
|
#define MAX_QH 100 // Max allowable queue heads in a chain
|
||||||
#define MIN_FR_PER_TICK 3 // Min frames to process when catching up
|
#define MIN_FR_PER_TICK 3 // Min frames to process when catching up
|
||||||
|
#define PERIODIC_ACTIVE 64
|
||||||
|
|
||||||
/* Internal periodic / asynchronous schedule state machine states
|
/* Internal periodic / asynchronous schedule state machine states
|
||||||
*/
|
*/
|
||||||
|
@ -738,6 +739,19 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[],
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep)
|
||||||
|
{
|
||||||
|
EHCIState *s = container_of(bus, EHCIState, bus);
|
||||||
|
uint32_t portsc = s->portsc[ep->dev->port->index];
|
||||||
|
|
||||||
|
if (portsc & PORTSC_POWNER) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->periodic_sched_active = PERIODIC_ACTIVE;
|
||||||
|
qemu_bh_schedule(s->async_bh);
|
||||||
|
}
|
||||||
|
|
||||||
static USBDevice *ehci_find_device(EHCIState *ehci, uint8_t addr)
|
static USBDevice *ehci_find_device(EHCIState *ehci, uint8_t addr)
|
||||||
{
|
{
|
||||||
USBDevice *dev;
|
USBDevice *dev;
|
||||||
|
@ -1188,9 +1202,10 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
|
||||||
trace_usb_ehci_packet_action(p->queue, p, "wakeup");
|
trace_usb_ehci_packet_action(p->queue, p, "wakeup");
|
||||||
p->async = EHCI_ASYNC_FINISHED;
|
p->async = EHCI_ASYNC_FINISHED;
|
||||||
|
|
||||||
if (p->queue->async) {
|
if (!p->queue->async) {
|
||||||
qemu_bh_schedule(p->queue->ehci->async_bh);
|
s->periodic_sched_active = PERIODIC_ACTIVE;
|
||||||
}
|
}
|
||||||
|
qemu_bh_schedule(s->async_bh);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ehci_execute_complete(EHCIQueue *q)
|
static void ehci_execute_complete(EHCIQueue *q)
|
||||||
|
@ -1344,6 +1359,8 @@ static int ehci_process_itd(EHCIState *ehci,
|
||||||
uint32_t i, len, pid, dir, devaddr, endp;
|
uint32_t i, len, pid, dir, devaddr, endp;
|
||||||
uint32_t pg, off, ptr1, ptr2, max, mult;
|
uint32_t pg, off, ptr1, ptr2, max, mult;
|
||||||
|
|
||||||
|
ehci->periodic_sched_active = PERIODIC_ACTIVE;
|
||||||
|
|
||||||
dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
|
dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
|
||||||
devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
|
devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
|
||||||
endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
|
endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
|
||||||
|
@ -2033,6 +2050,9 @@ static void ehci_advance_state(EHCIState *ehci, int async)
|
||||||
case EST_WRITEBACK:
|
case EST_WRITEBACK:
|
||||||
assert(q != NULL);
|
assert(q != NULL);
|
||||||
again = ehci_state_writeback(q);
|
again = ehci_state_writeback(q);
|
||||||
|
if (!async) {
|
||||||
|
ehci->periodic_sched_active = PERIODIC_ACTIVE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2198,7 +2218,6 @@ static void ehci_frame_timer(void *opaque)
|
||||||
|
|
||||||
if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) {
|
if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) {
|
||||||
need_timer++;
|
need_timer++;
|
||||||
ehci->async_stepdown = 0;
|
|
||||||
|
|
||||||
if (frames > ehci->maxframes) {
|
if (frames > ehci->maxframes) {
|
||||||
skipped_frames = frames - ehci->maxframes;
|
skipped_frames = frames - ehci->maxframes;
|
||||||
|
@ -2222,18 +2241,25 @@ static void ehci_frame_timer(void *opaque)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ehci->periodic_sched_active) {
|
||||||
|
ehci->periodic_sched_active--;
|
||||||
|
}
|
||||||
ehci_update_frindex(ehci, 1);
|
ehci_update_frindex(ehci, 1);
|
||||||
ehci_advance_periodic_state(ehci);
|
ehci_advance_periodic_state(ehci);
|
||||||
ehci->last_run_ns += FRAME_TIMER_NS;
|
ehci->last_run_ns += FRAME_TIMER_NS;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ehci->async_stepdown < ehci->maxframes / 2) {
|
ehci->periodic_sched_active = 0;
|
||||||
ehci->async_stepdown++;
|
|
||||||
}
|
|
||||||
ehci_update_frindex(ehci, frames);
|
ehci_update_frindex(ehci, frames);
|
||||||
ehci->last_run_ns += FRAME_TIMER_NS * frames;
|
ehci->last_run_ns += FRAME_TIMER_NS * frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ehci->periodic_sched_active) {
|
||||||
|
ehci->async_stepdown = 0;
|
||||||
|
} else if (ehci->async_stepdown < ehci->maxframes / 2) {
|
||||||
|
ehci->async_stepdown++;
|
||||||
|
}
|
||||||
|
|
||||||
/* Async is not inside loop since it executes everything it can once
|
/* Async is not inside loop since it executes everything it can once
|
||||||
* called
|
* called
|
||||||
*/
|
*/
|
||||||
|
@ -2301,6 +2327,7 @@ static USBPortOps ehci_port_ops = {
|
||||||
|
|
||||||
static USBBusOps ehci_bus_ops = {
|
static USBBusOps ehci_bus_ops = {
|
||||||
.register_companion = ehci_register_companion,
|
.register_companion = ehci_register_companion,
|
||||||
|
.wakeup_endpoint = ehci_wakeup_endpoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int usb_ehci_post_load(void *opaque, int version_id)
|
static int usb_ehci_post_load(void *opaque, int version_id)
|
||||||
|
|
|
@ -311,6 +311,7 @@ struct EHCIState {
|
||||||
|
|
||||||
uint64_t last_run_ns;
|
uint64_t last_run_ns;
|
||||||
uint32_t async_stepdown;
|
uint32_t async_stepdown;
|
||||||
|
uint32_t periodic_sched_active;
|
||||||
bool int_req_by_async;
|
bool int_req_by_async;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -292,6 +292,7 @@ static void usb_host_handle_destroy(USBDevice *opaque)
|
||||||
|
|
||||||
static int usb_host_initfn(USBDevice *dev)
|
static int usb_host_initfn(USBDevice *dev)
|
||||||
{
|
{
|
||||||
|
dev->flags |= (1 << USB_DEV_FLAG_IS_HOST);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1476,6 +1476,7 @@ static int usb_host_initfn(USBDevice *dev)
|
||||||
{
|
{
|
||||||
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
|
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
|
||||||
|
|
||||||
|
dev->flags |= (1 << USB_DEV_FLAG_IS_HOST);
|
||||||
dev->auto_attach = 0;
|
dev->auto_attach = 0;
|
||||||
s->fd = -1;
|
s->fd = -1;
|
||||||
s->hub_fd = -1;
|
s->hub_fd = -1;
|
||||||
|
|
|
@ -1644,6 +1644,10 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) {
|
||||||
|
usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f));
|
||||||
|
}
|
||||||
|
|
||||||
/* bufp_alloc also adds the packet to the ep queue */
|
/* bufp_alloc also adds the packet to the ep queue */
|
||||||
bufp_alloc(dev, data, data_len, interrupt_packet->status, ep);
|
bufp_alloc(dev, data, data_len, interrupt_packet->status, ep);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue