提交 36dfe324 编写于 作者: H Hans de Goede 提交者: Gerd Hoffmann

usb: Add USB_RET_ADD_TO_QUEUE packet result code

This can be used by usb-device code which wishes to process an entire endpoint
queue at once, to do this the usb-device code returns USB_RET_ADD_TO_QUEUE
from its handle_data class method and defines a flush_ep_queue class method
to call when the hcd is done queuing up packets.
Signed-off-by: NHans de Goede <hdegoede@redhat.com>
Signed-off-by: NGerd Hoffmann <kraxel@redhat.com>
上级 d0ff81b8
...@@ -38,12 +38,13 @@ ...@@ -38,12 +38,13 @@
#define USB_TOKEN_IN 0x69 /* device -> host */ #define USB_TOKEN_IN 0x69 /* device -> host */
#define USB_TOKEN_OUT 0xe1 /* host -> device */ #define USB_TOKEN_OUT 0xe1 /* host -> device */
#define USB_RET_NODEV (-1) #define USB_RET_NODEV (-1)
#define USB_RET_NAK (-2) #define USB_RET_NAK (-2)
#define USB_RET_STALL (-3) #define USB_RET_STALL (-3)
#define USB_RET_BABBLE (-4) #define USB_RET_BABBLE (-4)
#define USB_RET_IOERROR (-5) #define USB_RET_IOERROR (-5)
#define USB_RET_ASYNC (-6) #define USB_RET_ASYNC (-6)
#define USB_RET_ADD_TO_QUEUE (-7)
#define USB_SPEED_LOW 0 #define USB_SPEED_LOW 0
#define USB_SPEED_FULL 1 #define USB_SPEED_FULL 1
...@@ -293,6 +294,12 @@ typedef struct USBDeviceClass { ...@@ -293,6 +294,12 @@ typedef struct USBDeviceClass {
void (*set_interface)(USBDevice *dev, int interface, void (*set_interface)(USBDevice *dev, int interface,
int alt_old, int alt_new); int alt_old, int alt_new);
/*
* Called when the hcd is done queuing packets for an endpoint, only
* necessary for devices which can return USB_RET_ADD_TO_QUEUE.
*/
void (*flush_ep_queue)(USBDevice *dev, USBEndpoint *ep);
const char *product_desc; const char *product_desc;
const USBDesc *usb_desc; const USBDesc *usb_desc;
} USBDeviceClass; } USBDeviceClass;
...@@ -507,6 +514,8 @@ int usb_device_handle_data(USBDevice *dev, USBPacket *p); ...@@ -507,6 +514,8 @@ int usb_device_handle_data(USBDevice *dev, USBPacket *p);
void usb_device_set_interface(USBDevice *dev, int interface, void usb_device_set_interface(USBDevice *dev, int interface,
int alt_old, int alt_new); int alt_old, int alt_new);
void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep);
const char *usb_device_get_product_desc(USBDevice *dev); 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);
......
...@@ -181,6 +181,14 @@ void usb_device_set_interface(USBDevice *dev, int interface, ...@@ -181,6 +181,14 @@ void usb_device_set_interface(USBDevice *dev, int interface,
} }
} }
void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
{
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
if (klass->flush_ep_queue) {
klass->flush_ep_queue(dev, ep);
}
}
static int usb_qdev_init(DeviceState *qdev) static int usb_qdev_init(DeviceState *qdev)
{ {
USBDevice *dev = USB_DEVICE(qdev); USBDevice *dev = USB_DEVICE(qdev);
......
...@@ -393,6 +393,10 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p) ...@@ -393,6 +393,10 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
if (ret == USB_RET_ASYNC) { if (ret == USB_RET_ASYNC) {
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 (ret == USB_RET_ADD_TO_QUEUE) {
usb_packet_set_state(p, USB_PACKET_QUEUED);
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
ret = USB_RET_ASYNC;
} else { } else {
/* /*
* When pipelining is enabled usb-devices must always return async, * When pipelining is enabled usb-devices must always return async,
......
...@@ -2072,6 +2072,7 @@ static int ehci_state_horizqh(EHCIQueue *q) ...@@ -2072,6 +2072,7 @@ static int ehci_state_horizqh(EHCIQueue *q)
static int ehci_fill_queue(EHCIPacket *p) static int ehci_fill_queue(EHCIPacket *p)
{ {
USBEndpoint *ep = p->packet.ep;
EHCIQueue *q = p->queue; EHCIQueue *q = p->queue;
EHCIqtd qtd = p->qtd; EHCIqtd qtd = p->qtd;
uint32_t qtdaddr, start_addr = p->qtdaddr; uint32_t qtdaddr, start_addr = p->qtdaddr;
...@@ -2107,6 +2108,9 @@ static int ehci_fill_queue(EHCIPacket *p) ...@@ -2107,6 +2108,9 @@ static int ehci_fill_queue(EHCIPacket *p)
assert(p->usb_status == USB_RET_ASYNC); assert(p->usb_status == USB_RET_ASYNC);
p->async = EHCI_ASYNC_INFLIGHT; p->async = EHCI_ASYNC_INFLIGHT;
} }
if (p->usb_status != USB_RET_PROCERR) {
usb_device_flush_ep_queue(ep->dev, ep);
}
return p->usb_status; return p->usb_status;
} }
......
...@@ -635,6 +635,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep, ...@@ -635,6 +635,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
ret = usb_handle_packet(dev, &ep->packey[dir].p); ret = usb_handle_packet(dev, &ep->packey[dir].p);
if (ret == USB_RET_ASYNC) { if (ret == USB_RET_ASYNC) {
usb_device_flush_ep_queue(dev, uep);
ep->status[dir] = len; ep->status[dir] = len;
return; return;
} }
......
...@@ -816,6 +816,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, ...@@ -816,6 +816,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len); usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
ret = usb_handle_packet(dev, &ohci->usb_packet); ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret == USB_RET_ASYNC) { if (ret == USB_RET_ASYNC) {
usb_device_flush_ep_queue(dev, ep);
return 1; return 1;
} }
} }
...@@ -1018,6 +1019,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) ...@@ -1018,6 +1019,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
DPRINTF("ret=%d\n", ret); DPRINTF("ret=%d\n", ret);
#endif #endif
if (ret == USB_RET_ASYNC) { if (ret == USB_RET_ASYNC) {
usb_device_flush_ep_queue(dev, ep);
ohci->async_td = addr; ohci->async_td = addr;
return 1; return 1;
} }
......
...@@ -818,7 +818,8 @@ out: ...@@ -818,7 +818,8 @@ out:
} }
static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
uint32_t *int_mask, bool queuing) uint32_t *int_mask, bool queuing,
struct USBEndpoint **ep_ret)
{ {
UHCIAsync *async; UHCIAsync *async;
int len = 0, max_len; int len = 0, max_len;
...@@ -870,6 +871,9 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, ...@@ -870,6 +871,9 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
dev = uhci_find_device(s, (td->token >> 8) & 0x7f); dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf); ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
if (ep_ret) {
*ep_ret = ep;
}
usb_packet_setup(&async->packet, pid, ep, addr); usb_packet_setup(&async->packet, pid, ep, addr);
qemu_sglist_add(&async->sgl, td->buffer, max_len); qemu_sglist_add(&async->sgl, td->buffer, max_len);
usb_packet_map(&async->packet, &async->sgl); usb_packet_map(&async->packet, &async->sgl);
...@@ -983,7 +987,7 @@ static int qhdb_insert(QhDb *db, uint32_t addr) ...@@ -983,7 +987,7 @@ static int qhdb_insert(QhDb *db, uint32_t addr)
return 0; return 0;
} }
static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) static void uhci_fill_queue(UHCIState *s, UHCI_TD *td, struct USBEndpoint *ep)
{ {
uint32_t int_mask = 0; uint32_t int_mask = 0;
uint32_t plink = td->link; uint32_t plink = td->link;
...@@ -1005,7 +1009,7 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) ...@@ -1005,7 +1009,7 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
break; break;
} }
trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token); trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token);
ret = uhci_handle_td(s, plink, &ptd, &int_mask, true); ret = uhci_handle_td(s, plink, &ptd, &int_mask, true, NULL);
if (ret == TD_RESULT_ASYNC_CONT) { if (ret == TD_RESULT_ASYNC_CONT) {
break; break;
} }
...@@ -1013,12 +1017,14 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) ...@@ -1013,12 +1017,14 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
assert(int_mask == 0); assert(int_mask == 0);
plink = ptd.link; plink = ptd.link;
} }
usb_device_flush_ep_queue(ep->dev, ep);
} }
static void uhci_process_frame(UHCIState *s) static void uhci_process_frame(UHCIState *s)
{ {
uint32_t frame_addr, link, old_td_ctrl, val, int_mask; uint32_t frame_addr, link, old_td_ctrl, val, int_mask;
uint32_t curr_qh, td_count = 0; uint32_t curr_qh, td_count = 0;
struct USBEndpoint *curr_ep;
int cnt, ret; int cnt, ret;
UHCI_TD td; UHCI_TD td;
UHCI_QH qh; UHCI_QH qh;
...@@ -1089,7 +1095,7 @@ static void uhci_process_frame(UHCIState *s) ...@@ -1089,7 +1095,7 @@ static void uhci_process_frame(UHCIState *s)
trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token); trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token);
old_td_ctrl = td.ctrl; old_td_ctrl = td.ctrl;
ret = uhci_handle_td(s, link, &td, &int_mask, false); ret = uhci_handle_td(s, link, &td, &int_mask, false, &curr_ep);
if (old_td_ctrl != td.ctrl) { if (old_td_ctrl != td.ctrl) {
/* update the status bits of the TD */ /* update the status bits of the TD */
val = cpu_to_le32(td.ctrl); val = cpu_to_le32(td.ctrl);
...@@ -1108,7 +1114,7 @@ static void uhci_process_frame(UHCIState *s) ...@@ -1108,7 +1114,7 @@ static void uhci_process_frame(UHCIState *s)
case TD_RESULT_ASYNC_START: case TD_RESULT_ASYNC_START:
trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf); trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf);
uhci_fill_queue(s, &td); uhci_fill_queue(s, &td, curr_ep);
link = curr_qh ? qh.link : td.link; link = curr_qh ? qh.link : td.link;
continue; continue;
......
...@@ -1652,6 +1652,7 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext ...@@ -1652,6 +1652,7 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid) static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid)
{ {
XHCIEPContext *epctx; XHCIEPContext *epctx;
USBEndpoint *ep = NULL;
uint64_t mfindex; uint64_t mfindex;
int length; int length;
int i; int i;
...@@ -1745,12 +1746,14 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid ...@@ -1745,12 +1746,14 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
if (epid == 1) { if (epid == 1) {
if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) { if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) {
epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE; epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
ep = xfer->packet.ep;
} else { } else {
fprintf(stderr, "xhci: error firing CTL transfer\n"); fprintf(stderr, "xhci: error firing CTL transfer\n");
} }
} else { } else {
if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) { if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) {
epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE; epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
ep = xfer->packet.ep;
} else { } else {
if (!xfer->iso_xfer) { if (!xfer->iso_xfer) {
fprintf(stderr, "xhci: error firing data transfer\n"); fprintf(stderr, "xhci: error firing data transfer\n");
...@@ -1767,6 +1770,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid ...@@ -1767,6 +1770,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
break; break;
} }
} }
if (ep) {
usb_device_flush_ep_queue(ep->dev, ep);
}
} }
static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid) static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册