Merge remote-tracking branch 'kraxel/usb.7.pull' into staging

This commit is contained in:
Anthony Liguori
2011-05-05 13:04:57 -05:00
8 changed files with 453 additions and 157 deletions
+14
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+6
View File
@@ -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
+4 -5
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff