mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'kraxel/usb.7.pull' into staging
This commit is contained in:
@@ -256,6 +256,19 @@ static void usb_hub_wakeup(USBDevice *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_hub_complete(USBDevice *dev, USBPacket *packet)
|
||||
{
|
||||
USBHubState *s = dev->port->opaque;
|
||||
|
||||
/*
|
||||
* Just pass it along upstream for now.
|
||||
*
|
||||
* If we ever inplement usb 2.0 split transactions this will
|
||||
* become a little more complicated ...
|
||||
*/
|
||||
usb_packet_complete(&s->dev, packet);
|
||||
}
|
||||
|
||||
static void usb_hub_handle_attach(USBDevice *dev)
|
||||
{
|
||||
USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
|
||||
@@ -524,6 +537,7 @@ static USBPortOps usb_hub_port_ops = {
|
||||
.attach = usb_hub_attach,
|
||||
.detach = usb_hub_detach,
|
||||
.wakeup = usb_hub_wakeup,
|
||||
.complete = usb_hub_complete,
|
||||
};
|
||||
|
||||
static int usb_hub_initfn(USBDevice *dev)
|
||||
|
||||
+3
-2
@@ -241,7 +241,7 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag,
|
||||
s->mode = USB_MSDM_CSW;
|
||||
}
|
||||
s->packet = NULL;
|
||||
usb_packet_complete(p);
|
||||
usb_packet_complete(&s->dev, p);
|
||||
} else if (s->data_len == 0) {
|
||||
s->mode = USB_MSDM_CSW;
|
||||
}
|
||||
@@ -257,7 +257,7 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag,
|
||||
usb_packet_complete returns. */
|
||||
DPRINTF("Packet complete %p\n", p);
|
||||
s->packet = NULL;
|
||||
usb_packet_complete(p);
|
||||
usb_packet_complete(&s->dev, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -364,6 +364,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
||||
DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
|
||||
s->tag, cbw.flags, cbw.cmd_len, s->data_len);
|
||||
s->residue = 0;
|
||||
s->scsi_len = 0;
|
||||
s->scsi_dev->info->send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
|
||||
/* ??? Should check that USB and SCSI data transfer
|
||||
directions match. */
|
||||
|
||||
+40
-35
@@ -261,13 +261,24 @@
|
||||
|
||||
static void musb_attach(USBPort *port);
|
||||
static void musb_detach(USBPort *port);
|
||||
static void musb_schedule_cb(USBDevice *dev, USBPacket *p);
|
||||
|
||||
static USBPortOps musb_port_ops = {
|
||||
.attach = musb_attach,
|
||||
.detach = musb_detach,
|
||||
.complete = musb_schedule_cb,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
typedef struct MUSBPacket MUSBPacket;
|
||||
typedef struct MUSBEndPoint MUSBEndPoint;
|
||||
|
||||
struct MUSBPacket {
|
||||
USBPacket p;
|
||||
MUSBEndPoint *ep;
|
||||
int dir;
|
||||
};
|
||||
|
||||
struct MUSBEndPoint {
|
||||
uint16_t faddr[2];
|
||||
uint8_t haddr[2];
|
||||
uint8_t hport[2];
|
||||
@@ -284,7 +295,7 @@ typedef struct {
|
||||
int fifolen[2];
|
||||
int fifostart[2];
|
||||
int fifoaddr[2];
|
||||
USBPacket packey[2];
|
||||
MUSBPacket packey[2];
|
||||
int status[2];
|
||||
int ext_size[2];
|
||||
|
||||
@@ -294,7 +305,7 @@ typedef struct {
|
||||
MUSBState *musb;
|
||||
USBCallback *delayed_cb[2];
|
||||
QEMUTimer *intv_timer[2];
|
||||
} MUSBEndPoint;
|
||||
};
|
||||
|
||||
struct MUSBState {
|
||||
qemu_irq *irqs;
|
||||
@@ -321,7 +332,9 @@ struct MUSBState {
|
||||
/* Duplicating the world since 2008!... probably we should have 32
|
||||
* logical, single endpoints instead. */
|
||||
MUSBEndPoint ep[16];
|
||||
} *musb_init(qemu_irq *irqs)
|
||||
};
|
||||
|
||||
struct MUSBState *musb_init(qemu_irq *irqs)
|
||||
{
|
||||
MUSBState *s = qemu_mallocz(sizeof(*s));
|
||||
int i;
|
||||
@@ -488,21 +501,23 @@ static inline void musb_cb_tick0(void *opaque)
|
||||
{
|
||||
MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
|
||||
|
||||
ep->delayed_cb[0](&ep->packey[0], opaque);
|
||||
ep->delayed_cb[0](&ep->packey[0].p, opaque);
|
||||
}
|
||||
|
||||
static inline void musb_cb_tick1(void *opaque)
|
||||
{
|
||||
MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
|
||||
|
||||
ep->delayed_cb[1](&ep->packey[1], opaque);
|
||||
ep->delayed_cb[1](&ep->packey[1].p, opaque);
|
||||
}
|
||||
|
||||
#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0)
|
||||
|
||||
static inline void musb_schedule_cb(USBPacket *packey, void *opaque, int dir)
|
||||
static inline void musb_schedule_cb(USBDevice *dev, USBPacket *packey)
|
||||
{
|
||||
MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
|
||||
MUSBPacket *p = container_of(packey, MUSBPacket, p);
|
||||
MUSBEndPoint *ep = p->ep;
|
||||
int dir = p->dir;
|
||||
int timeout = 0;
|
||||
|
||||
if (ep->status[dir] == USB_RET_NAK)
|
||||
@@ -510,25 +525,15 @@ static inline void musb_schedule_cb(USBPacket *packey, void *opaque, int dir)
|
||||
else if (ep->interrupt[dir])
|
||||
timeout = 8;
|
||||
else
|
||||
return musb_cb_tick(opaque);
|
||||
return musb_cb_tick(ep);
|
||||
|
||||
if (!ep->intv_timer[dir])
|
||||
ep->intv_timer[dir] = qemu_new_timer_ns(vm_clock, musb_cb_tick, opaque);
|
||||
ep->intv_timer[dir] = qemu_new_timer_ns(vm_clock, musb_cb_tick, ep);
|
||||
|
||||
qemu_mod_timer(ep->intv_timer[dir], qemu_get_clock_ns(vm_clock) +
|
||||
muldiv64(timeout, get_ticks_per_sec(), 8000));
|
||||
}
|
||||
|
||||
static void musb_schedule0_cb(USBPacket *packey, void *opaque)
|
||||
{
|
||||
return musb_schedule_cb(packey, opaque, 0);
|
||||
}
|
||||
|
||||
static void musb_schedule1_cb(USBPacket *packey, void *opaque)
|
||||
{
|
||||
return musb_schedule_cb(packey, opaque, 1);
|
||||
}
|
||||
|
||||
static int musb_timeout(int ttype, int speed, int val)
|
||||
{
|
||||
#if 1
|
||||
@@ -585,19 +590,18 @@ static inline void musb_packet(MUSBState *s, MUSBEndPoint *ep,
|
||||
ep->type[idx] >> 6, ep->interval[idx]);
|
||||
ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
|
||||
ep->delayed_cb[dir] = cb;
|
||||
cb = dir ? musb_schedule1_cb : musb_schedule0_cb;
|
||||
|
||||
ep->packey[dir].pid = pid;
|
||||
ep->packey[dir].p.pid = pid;
|
||||
/* A wild guess on the FADDR semantics... */
|
||||
ep->packey[dir].devaddr = ep->faddr[idx];
|
||||
ep->packey[dir].devep = ep->type[idx] & 0xf;
|
||||
ep->packey[dir].data = (void *) ep->buf[idx];
|
||||
ep->packey[dir].len = len;
|
||||
ep->packey[dir].complete_cb = cb;
|
||||
ep->packey[dir].complete_opaque = ep;
|
||||
ep->packey[dir].p.devaddr = ep->faddr[idx];
|
||||
ep->packey[dir].p.devep = ep->type[idx] & 0xf;
|
||||
ep->packey[dir].p.data = (void *) ep->buf[idx];
|
||||
ep->packey[dir].p.len = len;
|
||||
ep->packey[dir].ep = ep;
|
||||
ep->packey[dir].dir = dir;
|
||||
|
||||
if (s->port.dev)
|
||||
ret = s->port.dev->info->handle_packet(s->port.dev, &ep->packey[dir]);
|
||||
ret = s->port.dev->info->handle_packet(s->port.dev, &ep->packey[dir].p);
|
||||
else
|
||||
ret = USB_RET_NODEV;
|
||||
|
||||
@@ -607,7 +611,7 @@ static inline void musb_packet(MUSBState *s, MUSBEndPoint *ep,
|
||||
}
|
||||
|
||||
ep->status[dir] = ret;
|
||||
usb_packet_complete(&ep->packey[dir]);
|
||||
usb_packet_complete(s->port.dev, &ep->packey[dir].p);
|
||||
}
|
||||
|
||||
static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
|
||||
@@ -821,14 +825,14 @@ static void musb_rx_req(MUSBState *s, int epnum)
|
||||
|
||||
/* If we already have a packet, which didn't fit into the
|
||||
* 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
|
||||
if (ep->packey[1].pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
|
||||
if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
|
||||
(ep->fifostart[1]) + ep->rxcount <
|
||||
ep->packey[1].len) {
|
||||
ep->packey[1].p.len) {
|
||||
TRACE("0x%08x, %d", ep->fifostart[1], ep->rxcount );
|
||||
ep->fifostart[1] += ep->rxcount;
|
||||
ep->fifolen[1] = 0;
|
||||
|
||||
ep->rxcount = MIN(ep->packey[0].len - (ep->fifostart[1]),
|
||||
ep->rxcount = MIN(ep->packey[0].p.len - (ep->fifostart[1]),
|
||||
ep->maxp[1]);
|
||||
|
||||
ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
|
||||
@@ -866,10 +870,11 @@ static void musb_rx_req(MUSBState *s, int epnum)
|
||||
#ifdef SETUPLEN_HACK
|
||||
/* Why should *we* do that instead of Linux? */
|
||||
if (!epnum) {
|
||||
if (ep->packey[0].devaddr == 2)
|
||||
if (ep->packey[0].p.devaddr == 2) {
|
||||
total = MIN(s->setup_len, 8);
|
||||
else
|
||||
} else {
|
||||
total = MIN(s->setup_len, 64);
|
||||
}
|
||||
s->setup_len -= total;
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-6
@@ -575,9 +575,9 @@ static void ohci_copy_iso_td(OHCIState *ohci,
|
||||
|
||||
static void ohci_process_lists(OHCIState *ohci, int completion);
|
||||
|
||||
static void ohci_async_complete_packet(USBPacket *packet, void *opaque)
|
||||
static void ohci_async_complete_packet(USBDevice *dev, USBPacket *packet)
|
||||
{
|
||||
OHCIState *ohci = opaque;
|
||||
OHCIState *ohci = container_of(packet, OHCIState, usb_packet);
|
||||
#ifdef DEBUG_PACKET
|
||||
DPRINTF("Async packet complete\n");
|
||||
#endif
|
||||
@@ -748,8 +748,6 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
||||
ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
|
||||
ohci->usb_packet.data = ohci->usb_buf;
|
||||
ohci->usb_packet.len = len;
|
||||
ohci->usb_packet.complete_cb = ohci_async_complete_packet;
|
||||
ohci->usb_packet.complete_opaque = ohci;
|
||||
ret = dev->info->handle_packet(dev, &ohci->usb_packet);
|
||||
if (ret != USB_RET_NODEV)
|
||||
break;
|
||||
@@ -946,8 +944,6 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
|
||||
ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
|
||||
ohci->usb_packet.data = ohci->usb_buf;
|
||||
ohci->usb_packet.len = len;
|
||||
ohci->usb_packet.complete_cb = ohci_async_complete_packet;
|
||||
ohci->usb_packet.complete_opaque = ohci;
|
||||
ret = dev->info->handle_packet(dev, &ohci->usb_packet);
|
||||
if (ret != USB_RET_NODEV)
|
||||
break;
|
||||
@@ -1665,6 +1661,7 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={
|
||||
static USBPortOps ohci_port_ops = {
|
||||
.attach = ohci_attach,
|
||||
.detach = ohci_detach,
|
||||
.complete = ohci_async_complete_packet,
|
||||
};
|
||||
|
||||
static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
|
||||
|
||||
+26
-56
@@ -106,6 +106,8 @@ static void dump_data(const uint8_t *data, int len)
|
||||
static void dump_data(const uint8_t *data, int len) {}
|
||||
#endif
|
||||
|
||||
typedef struct UHCIState UHCIState;
|
||||
|
||||
/*
|
||||
* Pending async transaction.
|
||||
* 'packet' must be the first field because completion
|
||||
@@ -113,7 +115,8 @@ static void dump_data(const uint8_t *data, int len) {}
|
||||
*/
|
||||
typedef struct UHCIAsync {
|
||||
USBPacket packet;
|
||||
struct UHCIAsync *next;
|
||||
UHCIState *uhci;
|
||||
QTAILQ_ENTRY(UHCIAsync) next;
|
||||
uint32_t td;
|
||||
uint32_t token;
|
||||
int8_t valid;
|
||||
@@ -127,7 +130,7 @@ typedef struct UHCIPort {
|
||||
uint16_t ctrl;
|
||||
} UHCIPort;
|
||||
|
||||
typedef struct UHCIState {
|
||||
struct UHCIState {
|
||||
PCIDevice dev;
|
||||
USBBus bus;
|
||||
uint16_t cmd; /* cmd register */
|
||||
@@ -145,10 +148,9 @@ typedef struct UHCIState {
|
||||
uint32_t pending_int_mask;
|
||||
|
||||
/* Active packets */
|
||||
UHCIAsync *async_pending;
|
||||
UHCIAsync *async_pool;
|
||||
QTAILQ_HEAD(,UHCIAsync) async_pending;
|
||||
uint8_t num_ports_vmstate;
|
||||
} UHCIState;
|
||||
};
|
||||
|
||||
typedef struct UHCI_TD {
|
||||
uint32_t link;
|
||||
@@ -167,12 +169,12 @@ static UHCIAsync *uhci_async_alloc(UHCIState *s)
|
||||
UHCIAsync *async = qemu_malloc(sizeof(UHCIAsync));
|
||||
|
||||
memset(&async->packet, 0, sizeof(async->packet));
|
||||
async->uhci = s;
|
||||
async->valid = 0;
|
||||
async->td = 0;
|
||||
async->token = 0;
|
||||
async->done = 0;
|
||||
async->isoc = 0;
|
||||
async->next = NULL;
|
||||
|
||||
return async;
|
||||
}
|
||||
@@ -184,24 +186,12 @@ static void uhci_async_free(UHCIState *s, UHCIAsync *async)
|
||||
|
||||
static void uhci_async_link(UHCIState *s, UHCIAsync *async)
|
||||
{
|
||||
async->next = s->async_pending;
|
||||
s->async_pending = async;
|
||||
QTAILQ_INSERT_HEAD(&s->async_pending, async, next);
|
||||
}
|
||||
|
||||
static void uhci_async_unlink(UHCIState *s, UHCIAsync *async)
|
||||
{
|
||||
UHCIAsync *curr = s->async_pending;
|
||||
UHCIAsync **prev = &s->async_pending;
|
||||
|
||||
while (curr) {
|
||||
if (curr == async) {
|
||||
*prev = curr->next;
|
||||
return;
|
||||
}
|
||||
|
||||
prev = &curr->next;
|
||||
curr = curr->next;
|
||||
}
|
||||
QTAILQ_REMOVE(&s->async_pending, async, next);
|
||||
}
|
||||
|
||||
static void uhci_async_cancel(UHCIState *s, UHCIAsync *async)
|
||||
@@ -220,11 +210,10 @@ static void uhci_async_cancel(UHCIState *s, UHCIAsync *async)
|
||||
*/
|
||||
static UHCIAsync *uhci_async_validate_begin(UHCIState *s)
|
||||
{
|
||||
UHCIAsync *async = s->async_pending;
|
||||
UHCIAsync *async;
|
||||
|
||||
while (async) {
|
||||
QTAILQ_FOREACH(async, &s->async_pending, next) {
|
||||
async->valid--;
|
||||
async = async->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -234,47 +223,30 @@ static UHCIAsync *uhci_async_validate_begin(UHCIState *s)
|
||||
*/
|
||||
static void uhci_async_validate_end(UHCIState *s)
|
||||
{
|
||||
UHCIAsync *curr = s->async_pending;
|
||||
UHCIAsync **prev = &s->async_pending;
|
||||
UHCIAsync *next;
|
||||
UHCIAsync *curr, *n;
|
||||
|
||||
while (curr) {
|
||||
QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
|
||||
if (curr->valid > 0) {
|
||||
prev = &curr->next;
|
||||
curr = curr->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
next = curr->next;
|
||||
|
||||
/* Unlink */
|
||||
*prev = next;
|
||||
|
||||
uhci_async_unlink(s, curr);
|
||||
uhci_async_cancel(s, curr);
|
||||
|
||||
curr = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void uhci_async_cancel_all(UHCIState *s)
|
||||
{
|
||||
UHCIAsync *curr = s->async_pending;
|
||||
UHCIAsync *next;
|
||||
|
||||
while (curr) {
|
||||
next = curr->next;
|
||||
UHCIAsync *curr, *n;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
|
||||
uhci_async_unlink(s, curr);
|
||||
uhci_async_cancel(s, curr);
|
||||
|
||||
curr = next;
|
||||
}
|
||||
|
||||
s->async_pending = NULL;
|
||||
}
|
||||
|
||||
static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token)
|
||||
{
|
||||
UHCIAsync *async = s->async_pending;
|
||||
UHCIAsync *async;
|
||||
UHCIAsync *match = NULL;
|
||||
int count = 0;
|
||||
|
||||
@@ -291,7 +263,7 @@ static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token
|
||||
* If we ever do we'd want to optimize this algorithm.
|
||||
*/
|
||||
|
||||
while (async) {
|
||||
QTAILQ_FOREACH(async, &s->async_pending, next) {
|
||||
if (async->token == token) {
|
||||
/* Good match */
|
||||
match = async;
|
||||
@@ -301,8 +273,6 @@ static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
async = async->next;
|
||||
count++;
|
||||
}
|
||||
|
||||
@@ -672,7 +642,7 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void uhci_async_complete(USBPacket * packet, void *opaque);
|
||||
static void uhci_async_complete(USBDevice *dev, USBPacket *packet);
|
||||
static void uhci_process_frame(UHCIState *s);
|
||||
|
||||
/* return -1 if fatal error (frame must be stopped)
|
||||
@@ -825,8 +795,6 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
|
||||
async->packet.devep = (td->token >> 15) & 0xf;
|
||||
async->packet.data = async->buffer;
|
||||
async->packet.len = max_len;
|
||||
async->packet.complete_cb = uhci_async_complete;
|
||||
async->packet.complete_opaque = s;
|
||||
|
||||
switch(pid) {
|
||||
case USB_TOKEN_OUT:
|
||||
@@ -862,10 +830,10 @@ done:
|
||||
return len;
|
||||
}
|
||||
|
||||
static void uhci_async_complete(USBPacket *packet, void *opaque)
|
||||
static void uhci_async_complete(USBDevice *dev, USBPacket *packet)
|
||||
{
|
||||
UHCIState *s = opaque;
|
||||
UHCIAsync *async = (UHCIAsync *) packet;
|
||||
UHCIAsync *async = container_of(packet, UHCIAsync, packet);
|
||||
UHCIState *s = async->uhci;
|
||||
|
||||
DPRINTF("uhci: async complete. td 0x%x token 0x%x\n", async->td, async->token);
|
||||
|
||||
@@ -1113,6 +1081,7 @@ static USBPortOps uhci_port_ops = {
|
||||
.attach = uhci_attach,
|
||||
.detach = uhci_detach,
|
||||
.wakeup = uhci_wakeup,
|
||||
.complete = uhci_async_complete,
|
||||
};
|
||||
|
||||
static int usb_uhci_common_initfn(UHCIState *s)
|
||||
@@ -1137,6 +1106,7 @@ static int usb_uhci_common_initfn(UHCIState *s)
|
||||
s->expire_time = qemu_get_clock_ns(vm_clock) +
|
||||
(get_ticks_per_sec() / FRAME_TIMER_FREQ);
|
||||
s->num_ports_vmstate = NB_PORTS;
|
||||
QTAILQ_INIT(&s->async_pending);
|
||||
|
||||
qemu_register_reset(uhci_reset, s);
|
||||
|
||||
|
||||
@@ -93,6 +93,12 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
|
||||
s->setup_len = ret;
|
||||
s->setup_state = SETUP_STATE_DATA;
|
||||
} else {
|
||||
if (s->setup_len > sizeof(s->data_buf)) {
|
||||
fprintf(stderr,
|
||||
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
|
||||
s->setup_len, sizeof(s->data_buf));
|
||||
return USB_RET_STALL;
|
||||
}
|
||||
if (s->setup_len == 0)
|
||||
s->setup_state = SETUP_STATE_ACK;
|
||||
else
|
||||
|
||||
@@ -167,7 +167,7 @@ struct USBDevice {
|
||||
|
||||
int32_t state;
|
||||
uint8_t setup_buf[8];
|
||||
uint8_t data_buf[1024];
|
||||
uint8_t data_buf[4096];
|
||||
int32_t remote_wakeup;
|
||||
int32_t setup_state;
|
||||
int32_t setup_len;
|
||||
@@ -235,6 +235,7 @@ typedef struct USBPortOps {
|
||||
void (*attach)(USBPort *port);
|
||||
void (*detach)(USBPort *port);
|
||||
void (*wakeup)(USBDevice *dev);
|
||||
void (*complete)(USBDevice *dev, USBPacket *p);
|
||||
} USBPortOps;
|
||||
|
||||
/* USB port on which a device can be connected */
|
||||
@@ -259,8 +260,6 @@ struct USBPacket {
|
||||
uint8_t *data;
|
||||
int len;
|
||||
/* Internal use by the USB layer. */
|
||||
USBCallback *complete_cb;
|
||||
void *complete_opaque;
|
||||
USBCallback *cancel_cb;
|
||||
void *cancel_opaque;
|
||||
};
|
||||
@@ -278,9 +277,9 @@ static inline void usb_defer_packet(USBPacket *p, USBCallback *cancel,
|
||||
/* Notify the controller that an async packet is complete. This should only
|
||||
be called for packets previously deferred with usb_defer_packet, and
|
||||
should never be called from within handle_packet. */
|
||||
static inline void usb_packet_complete(USBPacket *p)
|
||||
static inline void usb_packet_complete(USBDevice *dev, USBPacket *p)
|
||||
{
|
||||
p->complete_cb(p, p->complete_opaque);
|
||||
dev->port->ops->complete(dev, p);
|
||||
}
|
||||
|
||||
/* Cancel an active packet. The packed must have been deferred with
|
||||
|
||||
+357
-53
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user