Commit a69fb350 authored by Anthony Liguori's avatar Anthony Liguori
Browse files

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

parents 196a7784 ef0bdf77
......@@ -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)
......
......@@ -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. */
......
......@@ -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
......
......@@ -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,
......
......@@ -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
......
......@@ -78,7 +78,7 @@ typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath,
#define USBPROCBUS_PATH "/proc/bus/usb"
#define PRODUCT_NAME_SZ 32
#define MAX_ENDPOINTS 16
#define MAX_ENDPOINTS 15
#define USBDEVBUS_PATH "/dev/bus/usb"
#define USBSYSBUS_PATH "/sys/bus/usb"
......@@ -92,9 +92,20 @@ static char *usb_host_device_path;
static int usb_fs_type;
/* endpoint association data */
#define ISO_FRAME_DESC_PER_URB 32
#define ISO_URB_COUNT 3
#define INVALID_EP_TYPE 255
typedef struct AsyncURB AsyncURB;
struct endp_data {
uint8_t type;
uint8_t halted;
uint8_t iso_started;
AsyncURB *iso_urb;
int iso_urb_idx;
int iso_buffer_used;
int max_packet_size;
};
enum {
......@@ -160,6 +171,11 @@ static int is_isoc(USBHostDevice *s, int ep)
return s->endp_table[ep - 1].type == USBDEVFS_URB_TYPE_ISO;
}
static int is_valid(USBHostDevice *s, int ep)
{
return s->endp_table[ep - 1].type != INVALID_EP_TYPE;
}
static int is_halted(USBHostDevice *s, int ep)
{
return s->endp_table[ep - 1].halted;
......@@ -175,19 +191,73 @@ static void set_halt(USBHostDevice *s, int ep)
s->endp_table[ep - 1].halted = 1;
}
static int is_iso_started(USBHostDevice *s, int ep)
{
return s->endp_table[ep - 1].iso_started;
}
static void clear_iso_started(USBHostDevice *s, int ep)
{
s->endp_table[ep - 1].iso_started = 0;
}
static void set_iso_started(USBHostDevice *s, int ep)
{
s->endp_table[ep - 1].iso_started = 1;
}
static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb)
{
s->endp_table[ep - 1].iso_urb = iso_urb;
}
static AsyncURB *get_iso_urb(USBHostDevice *s, int ep)
{
return s->endp_table[ep - 1].iso_urb;
}
static void set_iso_urb_idx(USBHostDevice *s, int ep, int i)
{
s->endp_table[ep - 1].iso_urb_idx = i;
}
static int get_iso_urb_idx(USBHostDevice *s, int ep)
{
return s->endp_table[ep - 1].iso_urb_idx;
}
static void set_iso_buffer_used(USBHostDevice *s, int ep, int i)
{
s->endp_table[ep - 1].iso_buffer_used = i;
}
static int get_iso_buffer_used(USBHostDevice *s, int ep)
{
return s->endp_table[ep - 1].iso_buffer_used;
}
static int get_max_packet_size(USBHostDevice *s, int ep)
{
return s->endp_table[ep - 1].max_packet_size;
}
/*
* Async URB state.
* We always allocate one isoc descriptor even for bulk transfers
* We always allocate iso packet descriptors even for bulk transfers