* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Only host-mode and non-DMA accesses are currently supported.
*/
#include "qemu-timer.h"
#include "usb.h"
#include "irq.h"
+#include "hw.h"
/* Common USB registers */
#define MUSB_HDRC_FADDR 0x00 /* 8-bit */
#define MGC_M_ULPI_REGCTL_COMPLETE 0x02
#define MGC_M_ULPI_REGCTL_REG 0x01
-static void musb_attach(USBPort *port, USBDevice *dev);
+/* #define MUSB_DEBUG */
-struct musb_s {
+#ifdef MUSB_DEBUG
+#define TRACE(fmt,...) fprintf(stderr, "%s@%d: " fmt "\n", __FUNCTION__, \
+ __LINE__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+
+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 USBPortOps musb_port_ops = {
+ .attach = musb_attach,
+ .detach = musb_detach,
+ .complete = musb_schedule_cb,
+};
+
+static USBBusOps musb_bus_ops = {
+ .device_destroy = musb_device_destroy,
+};
+
+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];
+ uint16_t csr[2];
+ uint16_t maxp[2];
+ uint16_t rxcount;
+ uint8_t type[2];
+ uint8_t interval[2];
+ uint8_t config;
+ uint8_t fifosize;
+ int timeout[2]; /* Always in microframes */
+
+ uint8_t *buf[2];
+ int fifolen[2];
+ int fifostart[2];
+ int fifoaddr[2];
+ MUSBPacket packey[2];
+ int status[2];
+ int ext_size[2];
+
+ /* For callbacks' use */
+ int epnum;
+ int interrupt[2];
+ MUSBState *musb;
+ USBCallback *delayed_cb[2];
+ QEMUTimer *intv_timer[2];
+};
+
+struct MUSBState {
qemu_irq *irqs;
+ USBBus bus;
USBPort port;
int idx;
int setup_len;
int session;
- uint32_t buf[0x2000];
-
- struct musb_ep_s {
- uint16_t faddr[2];
- uint8_t haddr[2];
- uint8_t hport[2];
- uint16_t csr[2];
- uint16_t maxp[2];
- uint16_t rxcount;
- uint8_t type[2];
- uint8_t interval[2];
- uint8_t config;
- uint8_t fifosize;
- int timeout[2]; /* Always in microframes */
-
- uint32_t *buf[2];
- int fifolen[2];
- int fifostart[2];
- int fifoaddr[2];
- USBPacket packey[2];
- int status[2];
- int ext_size[2];
-
- /* For callbacks' use */
- int epnum;
- int interrupt[2];
- struct musb_s *musb;
- USBCallback *delayed_cb[2];
- QEMUTimer *intv_timer[2];
+ uint8_t buf[0x8000];
+
/* Duplicating the world since 2008!... probably we should have 32
* logical, single endpoints instead. */
- } ep[16];
-} *musb_init(qemu_irq *irqs)
+ MUSBEndPoint ep[16];
+};
+
+struct MUSBState *musb_init(qemu_irq *irqs)
{
- struct musb_s *s = qemu_mallocz(sizeof(*s));
+ MUSBState *s = qemu_mallocz(sizeof(*s));
int i;
s->irqs = irqs;
s->ep[i].epnum = i;
}
- qemu_register_usb_port(&s->port, s, 0, musb_attach);
+ usb_bus_new(&s->bus, &musb_bus_ops, NULL /* FIXME */);
+ 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;
}
-static void musb_vbus_set(struct musb_s *s, int level)
+static void musb_vbus_set(MUSBState *s, int level)
{
if (level)
s->devctl |= 3 << MGC_S_DEVCTL_VBUS;
qemu_set_irq(s->irqs[musb_set_vbus], level);
}
-static void musb_intr_set(struct musb_s *s, int line, int level)
+static void musb_intr_set(MUSBState *s, int line, int level)
{
if (!level) {
s->intr &= ~(1 << line);
}
}
-static void musb_tx_intr_set(struct musb_s *s, int line, int level)
+static void musb_tx_intr_set(MUSBState *s, int line, int level)
{
if (!level) {
s->tx_intr &= ~(1 << line);
}
}
-static void musb_rx_intr_set(struct musb_s *s, int line, int level)
+static void musb_rx_intr_set(MUSBState *s, int line, int level)
{
if (line) {
if (!level) {
musb_tx_intr_set(s, line, level);
}
-uint32_t musb_core_intr_get(struct musb_s *s)
+uint32_t musb_core_intr_get(MUSBState *s)
{
return (s->rx_intr << 15) | s->tx_intr;
}
-void musb_core_intr_clear(struct musb_s *s, uint32_t mask)
+void musb_core_intr_clear(MUSBState *s, uint32_t mask)
{
if (s->rx_intr) {
s->rx_intr &= mask >> 15;
}
}
-void musb_set_size(struct musb_s *s, int epnum, int size, int is_tx)
+void musb_set_size(MUSBState *s, int epnum, int size, int is_tx)
{
s->ep[epnum].ext_size[!is_tx] = size;
s->ep[epnum].fifostart[0] = 0;
s->ep[epnum].fifolen[1] = 0;
}
-static void musb_session_update(struct musb_s *s, int prev_dev, int prev_sess)
+static void musb_session_update(MUSBState *s, int prev_dev, int prev_sess)
{
int detect_prev = prev_dev && prev_sess;
int detect = !!s->port.dev && s->session;
}
/* Attach or detach a device on our only port. */
-static void musb_attach(USBPort *port, USBDevice *dev)
+static void musb_attach(USBPort *port)
{
- struct musb_s *s = (struct musb_s *) port->opaque;
- USBDevice *curr;
-
- port = &s->port;
- curr = port->dev;
-
- if (dev) {
- if (curr) {
- usb_attach(port, NULL);
- /* TODO: signal some interrupts */
- }
-
- musb_intr_set(s, musb_irq_vbus_request, 1);
-
- /* Send the attach message to device */
- usb_send_msg(dev, USB_MSG_ATTACH);
- } else if (curr) {
- /* Send the detach message */
- usb_send_msg(curr, USB_MSG_DETACH);
+ MUSBState *s = (MUSBState *) port->opaque;
- musb_intr_set(s, musb_irq_disconnect, 1);
- }
+ musb_intr_set(s, musb_irq_vbus_request, 1);
+ musb_session_update(s, 0, s->session);
+}
- port->dev = dev;
+static void musb_detach(USBPort *port)
+{
+ MUSBState *s = (MUSBState *) port->opaque;
- musb_session_update(s, !!curr, s->session);
+ musb_intr_set(s, musb_irq_disconnect, 1);
+ musb_session_update(s, 1, s->session);
}
-static inline void musb_cb_tick0(void *opaque)
+static void musb_cb_tick0(void *opaque)
{
- struct musb_ep_s *ep = (struct musb_ep_s *) 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)
+static void musb_cb_tick1(void *opaque)
{
- struct musb_ep_s *ep = (struct musb_ep_s *) 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 void musb_schedule_cb(USBDevice *dev, USBPacket *packey)
{
- struct musb_ep_s *ep = (struct musb_ep_s *) 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)
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(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(vm_clock) +
- muldiv64(timeout, 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);
+ qemu_mod_timer(ep->intv_timer[dir], qemu_get_clock_ns(vm_clock) +
+ muldiv64(timeout, get_ticks_per_sec(), 8000));
}
static int musb_timeout(int ttype, int speed, int val)
/* TODO: what with low-speed Bulk and Isochronous? */
}
- cpu_abort(cpu_single_env, "bad interval\n");
+ hw_error("bad interval\n");
}
-static inline void musb_packet(struct musb_s *s, struct musb_ep_s *ep,
+static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
int epnum, int pid, int len, USBCallback cb, int dir)
{
int ret;
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->handle_packet(s->port.dev, &ep->packey[dir]);
+ ret = usb_handle_packet(s->port.dev, &ep->packey[dir].p);
else
ret = USB_RET_NODEV;
}
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)
{
/* Unfortunately we can't use packey->devep because that's the remote
* endpoint number and may be different than our local. */
- struct musb_ep_s *ep = (struct musb_ep_s *) opaque;
+ MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
int epnum = ep->epnum;
- struct musb_s *s = ep->musb;
+ MUSBState *s = ep->musb;
ep->fifostart[0] = 0;
ep->fifolen[0] = 0;
{
/* Unfortunately we can't use packey->devep because that's the remote
* endpoint number and may be different than our local. */
- struct musb_ep_s *ep = (struct musb_ep_s *) opaque;
+ MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
int epnum = ep->epnum;
- struct musb_s *s = ep->musb;
+ MUSBState *s = ep->musb;
ep->fifostart[1] = 0;
ep->fifolen[1] = 0;
musb_rx_intr_set(s, epnum, 1);
}
-static void musb_tx_rdy(struct musb_s *s, int epnum)
+static void musb_device_destroy(USBBus *bus, USBDevice *dev)
+{
+ MUSBState *s = container_of(bus, MUSBState, bus);
+ int ep, dir;
+
+ for (ep = 0; ep < 16; ep++) {
+ for (dir = 0; dir < 2; dir++) {
+ if (s->ep[ep].packey[dir].p.owner != dev) {
+ continue;
+ }
+ usb_cancel_packet(&s->ep[ep].packey[dir].p);
+ /* status updates needed here? */
+ }
+ }
+}
+
+static void musb_tx_rdy(MUSBState *s, int epnum)
{
- struct musb_ep_s *ep = s->ep + epnum;
+ MUSBEndPoint *ep = s->ep + epnum;
int pid;
int total, valid = 0;
-
+ TRACE("start %d, len %d", ep->fifostart[0], ep->fifolen[0] );
ep->fifostart[0] += ep->fifolen[0];
ep->fifolen[0] = 0;
}
/* If the packet is not fully ready yet, wait for a next segment. */
- if (epnum && (ep->fifostart[0] << 2) < total)
+ if (epnum && (ep->fifostart[0]) < total)
return;
if (!valid)
- total = ep->fifostart[0] << 2;
+ total = ep->fifostart[0];
pid = USB_TOKEN_OUT;
if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) {
pid = USB_TOKEN_SETUP;
- if (total != 8)
- printf("%s: illegal SETUPPKT length of %i bytes\n",
- __FUNCTION__, total);
+ if (total != 8) {
+ TRACE("illegal SETUPPKT length of %i bytes", total);
+ }
/* Controller should retry SETUP packets three times on errors
* but it doesn't make sense for us to do that. */
}
total, musb_tx_packet_complete, 0);
}
-static void musb_rx_req(struct musb_s *s, int epnum)
+static void musb_rx_req(MUSBState *s, int epnum)
{
- struct musb_ep_s *ep = s->ep + epnum;
+ MUSBEndPoint *ep = s->ep + epnum;
int total;
/* 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 &&
- (ep->fifostart[1] << 2) + ep->rxcount <
- ep->packey[1].len) {
- ep->fifostart[1] += ep->rxcount >> 2;
+ if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
+ (ep->fifostart[1]) + ep->rxcount <
+ 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] << 2),
+ ep->rxcount = MIN(ep->packey[0].p.len - (ep->fifostart[1]),
ep->maxp[1]);
ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
#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
total, musb_rx_packet_complete, 1);
}
-static void musb_ep_frame_cancel(struct musb_ep_s *ep, int dir)
+static uint8_t musb_read_fifo(MUSBEndPoint *ep)
+{
+ uint8_t value;
+ if (ep->fifolen[1] >= 64) {
+ /* We have a FIFO underrun */
+ TRACE("EP%d FIFO is now empty, stop reading", ep->epnum);
+ return 0x00000000;
+ }
+ /* In DMA mode clear RXPKTRDY and set REQPKT automatically
+ * (if AUTOREQ is set) */
+
+ ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL;
+ value=ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++];
+ TRACE("EP%d 0x%02x, %d", ep->epnum, value, ep->fifolen[1] );
+ return value;
+}
+
+static void musb_write_fifo(MUSBEndPoint *ep, uint8_t value)
+{
+ TRACE("EP%d = %02x", ep->epnum, value);
+ if (ep->fifolen[0] >= 64) {
+ /* We have a FIFO overrun */
+ TRACE("EP%d FIFO exceeded 64 bytes, stop feeding data", ep->epnum);
+ return;
+ }
+
+ ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value;
+ ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY;
+}
+
+static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir)
{
if (ep->intv_timer[dir])
qemu_del_timer(ep->intv_timer[dir]);
/* Bus control */
static uint8_t musb_busctl_readb(void *opaque, int ep, int addr)
{
- struct musb_s *s = (struct musb_s *) opaque;
+ MUSBState *s = (MUSBState *) opaque;
switch (addr) {
/* For USB2.0 HS hubs only */
return s->ep[ep].hport[1];
default:
- printf("%s: unknown register at %02x\n", __FUNCTION__, addr);
+ TRACE("unknown register 0x%02x", addr);
return 0x00;
};
}
static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value)
{
- struct musb_s *s = (struct musb_s *) opaque;
+ MUSBState *s = (MUSBState *) opaque;
switch (addr) {
+ case MUSB_HDRC_TXFUNCADDR:
+ s->ep[ep].faddr[0] = value;
+ break;
+ case MUSB_HDRC_RXFUNCADDR:
+ s->ep[ep].faddr[1] = value;
+ break;
case MUSB_HDRC_TXHUBADDR:
s->ep[ep].haddr[0] = value;
break;
break;
default:
- printf("%s: unknown register at %02x\n", __FUNCTION__, addr);
+ TRACE("unknown register 0x%02x", addr);
+ break;
};
}
static uint16_t musb_busctl_readh(void *opaque, int ep, int addr)
{
- struct musb_s *s = (struct musb_s *) opaque;
+ MUSBState *s = (MUSBState *) opaque;
switch (addr) {
case MUSB_HDRC_TXFUNCADDR:
static void musb_busctl_writeh(void *opaque, int ep, int addr, uint16_t value)
{
- struct musb_s *s = (struct musb_s *) opaque;
+ MUSBState *s = (MUSBState *) opaque;
switch (addr) {
case MUSB_HDRC_TXFUNCADDR:
/* Endpoint control */
static uint8_t musb_ep_readb(void *opaque, int ep, int addr)
{
- struct musb_s *s = (struct musb_s *) opaque;
+ MUSBState *s = (MUSBState *) opaque;
switch (addr) {
case MUSB_HDRC_TXTYPE:
return 0x00;
case MUSB_HDRC_FIFOSIZE:
return ep ? s->ep[ep].fifosize : s->ep[ep].config;
+ case MUSB_HDRC_RXCOUNT:
+ return s->ep[ep].rxcount;
default:
- printf("%s: unknown register at %02x\n", __FUNCTION__, addr);
+ TRACE("unknown register 0x%02x", addr);
return 0x00;
};
}
static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value)
{
- struct musb_s *s = (struct musb_s *) opaque;
+ MUSBState *s = (MUSBState *) opaque;
switch (addr) {
case MUSB_HDRC_TXTYPE:
case (MUSB_HDRC_FIFOSIZE & ~1):
break;
case MUSB_HDRC_FIFOSIZE:
- printf("%s: somebody messes with fifosize (now %i bytes)\n",
- __FUNCTION__, value);
+ TRACE("somebody messes with fifosize (now %i bytes)", value);
s->ep[ep].fifosize = value;
break;
-
default:
- printf("%s: unknown register at %02x\n", __FUNCTION__, addr);
+ TRACE("unknown register 0x%02x", addr);
+ break;
};
}
static uint16_t musb_ep_readh(void *opaque, int ep, int addr)
{
- struct musb_s *s = (struct musb_s *) opaque;
+ MUSBState *s = (MUSBState *) opaque;
uint16_t ret;
switch (addr) {
static void musb_ep_writeh(void *opaque, int ep, int addr, uint16_t value)
{
- struct musb_s *s = (struct musb_s *) opaque;
+ MUSBState *s = (MUSBState *) opaque;
switch (addr) {
case MUSB_HDRC_TXMAXP:
/* Generic control */
static uint32_t musb_readb(void *opaque, target_phys_addr_t addr)
{
- struct musb_s *s = (struct musb_s *) opaque;
+ MUSBState *s = (MUSBState *) opaque;
int ep, i;
uint8_t ret;
ep = (addr >> 4) & 0xf;
return musb_ep_readb(s, ep, addr & 0xf);
+ case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+ ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+ return musb_read_fifo(s->ep + ep);
+
default:
- printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr);
+ TRACE("unknown register 0x%02x", (int) addr);
return 0x00;
};
}
static void musb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
{
- struct musb_s *s = (struct musb_s *) opaque;
+ MUSBState *s = (MUSBState *) opaque;
int ep;
switch (addr) {
musb_ep_writeb(s, ep, addr & 0xf, value);
break;
+ case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+ ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+ musb_write_fifo(s->ep + ep, value & 0xff);
+ break;
+
default:
- printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr);
+ TRACE("unknown register 0x%02x", (int) addr);
+ break;
};
}
static uint32_t musb_readh(void *opaque, target_phys_addr_t addr)
{
- struct musb_s *s = (struct musb_s *) opaque;
+ MUSBState *s = (MUSBState *) opaque;
int ep, i;
uint16_t ret;
ep = (addr >> 4) & 0xf;
return musb_ep_readh(s, ep, addr & 0xf);
+ case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+ ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+ return (musb_read_fifo(s->ep + ep) | musb_read_fifo(s->ep + ep) << 8);
+
default:
return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8);
};
static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value)
{
- struct musb_s *s = (struct musb_s *) opaque;
+ MUSBState *s = (MUSBState *) opaque;
int ep;
switch (addr) {
case MUSB_HDRC_TXFIFOADDR:
s->ep[s->idx].fifoaddr[0] = value;
s->ep[s->idx].buf[0] =
- s->buf + ((value << 1) & (sizeof(s->buf) / 4 - 1));
+ s->buf + ((value << 3) & 0x7ff );
break;
case MUSB_HDRC_RXFIFOADDR:
s->ep[s->idx].fifoaddr[1] = value;
s->ep[s->idx].buf[1] =
- s->buf + ((value << 1) & (sizeof(s->buf) / 4 - 1));
+ s->buf + ((value << 3) & 0x7ff);
break;
case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
musb_ep_writeh(s, ep, addr & 0xf, value);
break;
+ case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+ ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+ musb_write_fifo(s->ep + ep, value & 0xff);
+ musb_write_fifo(s->ep + ep, (value >> 8) & 0xff);
+ break;
+
default:
musb_writeb(s, addr, value & 0xff);
musb_writeb(s, addr | 1, value >> 8);
static uint32_t musb_readw(void *opaque, target_phys_addr_t addr)
{
- struct musb_s *s = (struct musb_s *) opaque;
- struct musb_ep_s *ep;
- int epnum;
+ MUSBState *s = (MUSBState *) opaque;
+ int ep;
switch (addr) {
case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- epnum = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- ep = s->ep + epnum;
-
- if (ep->fifolen[1] >= 16) {
- /* We have a FIFO underrun */
- printf("%s: EP%i FIFO is now empty, stop reading\n",
- __FUNCTION__, epnum);
- return 0x00000000;
- }
- /* In DMA mode clear RXPKTRDY and set REQPKT automatically
- * (if AUTOREQ is set) */
-
- ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL;
- return ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++];
-
+ ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+ return ( musb_read_fifo(s->ep + ep) |
+ musb_read_fifo(s->ep + ep) << 8 |
+ musb_read_fifo(s->ep + ep) << 16 |
+ musb_read_fifo(s->ep + ep) << 24 );
default:
- printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr);
+ TRACE("unknown register 0x%02x", (int) addr);
return 0x00000000;
};
}
static void musb_writew(void *opaque, target_phys_addr_t addr, uint32_t value)
{
- struct musb_s *s = (struct musb_s *) opaque;
- struct musb_ep_s *ep;
- int epnum;
+ MUSBState *s = (MUSBState *) opaque;
+ int ep;
switch (addr) {
case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- epnum = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- ep = s->ep + epnum;
-
- if (ep->fifolen[0] >= 16) {
- /* We have a FIFO overrun */
- printf("%s: EP%i FIFO exceeded 64 bytes, stop feeding data\n",
- __FUNCTION__, epnum);
+ ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+ musb_write_fifo(s->ep + ep, value & 0xff);
+ musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff);
+ musb_write_fifo(s->ep + ep, (value >> 16) & 0xff);
+ musb_write_fifo(s->ep + ep, (value >> 24) & 0xff);
break;
- }
-
- ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value;
- if (epnum)
- ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY;
- break;
-
default:
- printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr);
+ TRACE("unknown register 0x%02x", (int) addr);
+ break;
};
}
-CPUReadMemoryFunc *musb_read[] = {
+CPUReadMemoryFunc * const musb_read[] = {
musb_readb,
musb_readh,
musb_readw,
};
-CPUWriteMemoryFunc *musb_write[] = {
+CPUWriteMemoryFunc * const musb_write[] = {
musb_writeb,
musb_writeh,
musb_writew,