提交 c62adbee 编写于 作者: A Anthony Liguori

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: NAnthony Liguori <aliguori@us.ibm.com>
......@@ -281,8 +281,8 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
}
#endif
static QEMUMachine pc_machine_v1_3 = {
.name = "pc-1.3",
static QEMUMachine pc_machine_v1_4 = {
.name = "pc-1.4",
.alias = "pc",
.desc = "Standard PC",
.init = pc_init_pci_1_3,
......@@ -290,7 +290,26 @@ static QEMUMachine pc_machine_v1_3 = {
.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 \
PC_COMPAT_1_3,\
{\
.driver = "nec-usb-xhci",\
.property = "msi",\
......@@ -626,6 +645,7 @@ static QEMUMachine xenfv_machine = {
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_2);
qemu_register_machine(&pc_machine_v1_1);
......
......@@ -197,6 +197,7 @@ struct USBEndpoint {
enum USBDeviceFlags {
USB_DEV_FLAG_FULL_PATH,
USB_DEV_FLAG_IS_HOST,
};
/* definition of a USB device */
......@@ -229,6 +230,7 @@ struct USBDevice {
USBEndpoint ep_out[USB_MAX_ENDPOINTS];
QLIST_HEAD(, USBDescString) strings;
const USBDesc *usb_desc; /* Overrides class usb_desc if not NULL */
const USBDescDevice *device;
int configuration;
......
......@@ -166,6 +166,9 @@ const char *usb_device_get_product_desc(USBDevice *dev)
const USBDesc *usb_device_get_usb_desc(USBDevice *dev)
{
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
if (dev->usb_desc) {
return dev->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) {
usb_process_one(p);
if (p->status == USB_RET_ASYNC) {
/* hcd drivers cannot handle async for 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);
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
} else if (p->status == USB_RET_ADD_TO_QUEUE) {
......
......@@ -46,6 +46,7 @@ typedef struct USBHIDState {
USBDevice dev;
USBEndpoint *intr;
HIDState hid;
uint32_t usb_version;
} USBHIDState;
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 = {
.bInterfaceNumber = 0,
.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 = {
.bcdUSB = 0x0100,
.bMaxPacketSize0 = 8,
......@@ -239,6 +287,20 @@ static const USBDesc desc_tablet = {
.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 = {
.id = {
.idVendor = 0x0627,
......@@ -508,6 +570,21 @@ static int usb_hid_initfn(USBDevice *dev, int kind)
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);
}
......@@ -562,8 +639,14 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data)
uc->handle_control = usb_hid_handle_control;
uc->handle_data = usb_hid_handle_data;
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)
{
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);
uc->init = usb_tablet_initfn;
uc->product_desc = "QEMU USB Tablet";
uc->usb_desc = &desc_tablet;
dc->vmsd = &vmstate_usb_ptr;
dc->props = usb_tablet_properties;
}
static TypeInfo usb_tablet_info = {
......
......@@ -184,6 +184,7 @@ static void usb_hub_detach(USBPort *port1)
port->wPortStatus &= ~PORT_STAT_ENABLE;
port->wPortChange |= PORT_STAT_C_ENABLE;
}
usb_wakeup(s->intr);
}
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;
/* set enable bit */
port->wPortStatus |= PORT_STAT_ENABLE;
usb_wakeup(s->intr);
}
break;
case PORT_POWER:
......
......@@ -639,6 +639,8 @@ typedef struct USBNetState {
unsigned int in_ptr, in_len;
uint8_t in_buf[2048];
USBEndpoint *intr;
char usbstring_mac[13];
NICState *nic;
NICConf conf;
......@@ -851,6 +853,10 @@ static void *rndis_queue_response(USBNetState *s, unsigned int length)
struct rndis_response *r =
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);
r->length = length;
......@@ -1349,6 +1355,7 @@ static int usb_net_initfn(USBDevice *dev)
s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */;
s->filter = 0;
s->vendorid = 0x1234;
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_usbnet_info, &s->conf,
......
......@@ -43,6 +43,7 @@
typedef struct USBWacomState {
USBDevice dev;
USBEndpoint *intr;
QEMUPutMouseEntry *eh_entry;
int dx, dy, dz, buttons_state;
int x, y;
......@@ -137,6 +138,7 @@ static void usb_mouse_event(void *opaque,
s->dz += dz1;
s->buttons_state = buttons_state;
s->changed = 1;
usb_wakeup(s->intr);
}
static void usb_wacom_event(void *opaque,
......@@ -150,6 +152,7 @@ static void usb_wacom_event(void *opaque,
s->dz += dz;
s->buttons_state = buttons_state;
s->changed = 1;
usb_wakeup(s->intr);
}
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);
usb_desc_create_serial(dev);
usb_desc_init(dev);
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
s->changed = 1;
return 0;
}
......
......@@ -114,6 +114,7 @@
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
#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 PERIODIC_ACTIVE 64
/* Internal periodic / asynchronous schedule state machine states
*/
......@@ -738,6 +739,19 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[],
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)
{
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");
p->async = EHCI_ASYNC_FINISHED;
if (p->queue->async) {
qemu_bh_schedule(p->queue->ehci->async_bh);
if (!p->queue->async) {
s->periodic_sched_active = PERIODIC_ACTIVE;
}
qemu_bh_schedule(s->async_bh);
}
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 pg, off, ptr1, ptr2, max, mult;
ehci->periodic_sched_active = PERIODIC_ACTIVE;
dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
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:
assert(q != NULL);
again = ehci_state_writeback(q);
if (!async) {
ehci->periodic_sched_active = PERIODIC_ACTIVE;
}
break;
default:
......@@ -2198,7 +2218,6 @@ static void ehci_frame_timer(void *opaque)
if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) {
need_timer++;
ehci->async_stepdown = 0;
if (frames > ehci->maxframes) {
skipped_frames = frames - ehci->maxframes;
......@@ -2222,18 +2241,25 @@ static void ehci_frame_timer(void *opaque)
break;
}
}
if (ehci->periodic_sched_active) {
ehci->periodic_sched_active--;
}
ehci_update_frindex(ehci, 1);
ehci_advance_periodic_state(ehci);
ehci->last_run_ns += FRAME_TIMER_NS;
}
} else {
if (ehci->async_stepdown < ehci->maxframes / 2) {
ehci->async_stepdown++;
}
ehci->periodic_sched_active = 0;
ehci_update_frindex(ehci, 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
* called
*/
......@@ -2301,6 +2327,7 @@ static USBPortOps ehci_port_ops = {
static USBBusOps ehci_bus_ops = {
.register_companion = ehci_register_companion,
.wakeup_endpoint = ehci_wakeup_endpoint,
};
static int usb_ehci_post_load(void *opaque, int version_id)
......
......@@ -311,6 +311,7 @@ struct EHCIState {
uint64_t last_run_ns;
uint32_t async_stepdown;
uint32_t periodic_sched_active;
bool int_req_by_async;
};
......
......@@ -292,6 +292,7 @@ static void usb_host_handle_destroy(USBDevice *opaque)
static int usb_host_initfn(USBDevice *dev)
{
dev->flags |= (1 << USB_DEV_FLAG_IS_HOST);
return 0;
}
......
......@@ -1476,6 +1476,7 @@ static int usb_host_initfn(USBDevice *dev)
{
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
dev->flags |= (1 << USB_DEV_FLAG_IS_HOST);
dev->auto_attach = 0;
s->fd = -1;
s->hub_fd = -1;
......
......@@ -1644,6 +1644,10 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
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(dev, data, data_len, interrupt_packet->status, ep);
} else {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册