static void musb_attach(USBPort *port);
static void musb_detach(USBPort *port);
-static void musb_schedule_cb(USBDevice *dev, USBPacket *p);
-static void musb_device_destroy(USBBus *bus, USBDevice *dev);
+static void musb_child_detach(USBPort *port, USBDevice *child);
+static void musb_schedule_cb(USBPort *port, USBPacket *p);
+static void musb_async_cancel_device(MUSBState *s, USBDevice *dev);
static USBPortOps musb_port_ops = {
.attach = musb_attach,
.detach = musb_detach,
+ .child_detach = musb_child_detach,
.complete = musb_schedule_cb,
};
static USBBusOps musb_bus_ops = {
- .device_destroy = musb_device_destroy,
};
typedef struct MUSBPacket MUSBPacket;
};
struct MUSBState {
- qemu_irq *irqs;
+ qemu_irq irqs[musb_irq_max];
USBBus bus;
USBPort port;
MUSBEndPoint ep[16];
};
-struct MUSBState *musb_init(qemu_irq *irqs)
+void musb_reset(MUSBState *s)
{
- MUSBState *s = qemu_mallocz(sizeof(*s));
int i;
- s->irqs = irqs;
-
s->faddr = 0x00;
+ s->devctl = 0;
s->power = MGC_M_POWER_HSENAB;
s->tx_intr = 0x0000;
s->rx_intr = 0x0000;
s->mask = 0x06;
s->idx = 0;
+ s->setup_len = 0;
+ s->session = 0;
+ memset(s->buf, 0, sizeof(s->buf));
+
/* TODO: _DW */
s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO;
for (i = 0; i < 16; i ++) {
s->ep[i].maxp[1] = 0x40;
s->ep[i].musb = s;
s->ep[i].epnum = i;
+ usb_packet_init(&s->ep[i].packey[0].p);
+ usb_packet_init(&s->ep[i].packey[1].p);
+ }
+}
+
+struct MUSBState *musb_init(DeviceState *parent_device, int gpio_base)
+{
+ MUSBState *s = g_malloc0(sizeof(*s));
+ int i;
+
+ for (i = 0; i < musb_irq_max; i++) {
+ s->irqs[i] = qdev_get_gpio_in(parent_device, gpio_base + i);
}
- usb_bus_new(&s->bus, &musb_bus_ops, NULL /* FIXME */);
+ musb_reset(s);
+
+ usb_bus_new(&s->bus, &musb_bus_ops, parent_device);
usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
- usb_port_location(&s->port, NULL, 1);
return s;
}
{
MUSBState *s = (MUSBState *) port->opaque;
+ musb_async_cancel_device(s, port->dev);
+
musb_intr_set(s, musb_irq_disconnect, 1);
musb_session_update(s, 1, s->session);
}
+static void musb_child_detach(USBPort *port, USBDevice *child)
+{
+ MUSBState *s = (MUSBState *) port->opaque;
+
+ musb_async_cancel_device(s, child);
+}
+
static void musb_cb_tick0(void *opaque)
{
MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0)
-static void musb_schedule_cb(USBDevice *dev, USBPacket *packey)
+static void musb_schedule_cb(USBPort *port, USBPacket *packey)
{
MUSBPacket *p = container_of(packey, MUSBPacket, p);
MUSBEndPoint *ep = p->ep;
ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
ep->delayed_cb[dir] = cb;
- ep->packey[dir].p.pid = pid;
/* A wild guess on the FADDR semantics... */
- 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;
+ usb_packet_setup(&ep->packey[dir].p, pid, ep->faddr[idx],
+ ep->type[idx] & 0xf);
+ usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
ep->packey[dir].ep = ep;
ep->packey[dir].dir = dir;
}
ep->status[dir] = ret;
- usb_packet_complete(s->port.dev, &ep->packey[dir].p);
+ musb_schedule_cb(&s->port, &ep->packey[dir].p);
}
static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
if (ep->status[1] == USB_RET_STALL) {
ep->status[1] = 0;
- packey->len = 0;
+ packey->result = 0;
ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
if (!epnum)
* Data-errors in Isochronous. */
if (ep->interrupt[1])
return musb_packet(s, ep, epnum, USB_TOKEN_IN,
- packey->len, musb_rx_packet_complete, 1);
+ packey->iov.size, musb_rx_packet_complete, 1);
ep->csr[1] |= MGC_M_RXCSR_DATAERROR;
if (!epnum)
/* TODO: check len for over/underruns of an OUT packet? */
/* TODO: perhaps make use of e->ext_size[1] here. */
- packey->len = ep->status[1];
+ packey->result = ep->status[1];
if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
if (!epnum)
ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
- ep->rxcount = packey->len; /* XXX: MIN(packey->len, ep->maxp[1]); */
+ ep->rxcount = packey->result; /* XXX: MIN(packey->len, ep->maxp[1]); */
/* In DMA mode: assert DMA request for this EP */
}
musb_rx_intr_set(s, epnum, 1);
}
-static void musb_device_destroy(USBBus *bus, USBDevice *dev)
+static void musb_async_cancel_device(MUSBState *s, USBDevice *dev)
{
- MUSBState *s = container_of(bus, MUSBState, bus);
int ep, dir;
for (ep = 0; ep < 16; ep++) {
* 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
(ep->fifostart[1]) + ep->rxcount <
- ep->packey[1].p.len) {
+ ep->packey[1].p.iov.size) {
TRACE("0x%08x, %d", ep->fifostart[1], ep->rxcount );
ep->fifostart[1] += ep->rxcount;
ep->fifolen[1] = 0;
- ep->rxcount = MIN(ep->packey[0].p.len - (ep->fifostart[1]),
+ ep->rxcount = MIN(ep->packey[0].p.iov.size - (ep->fifostart[1]),
ep->maxp[1]);
ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;