summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--openpcd/firmware/include/openpcd.h3
-rw-r--r--openpcd/firmware/src/os/pio_irq.c82
-rw-r--r--openpcd/firmware/src/os/req_ctx.h2
3 files changed, 67 insertions, 20 deletions
diff --git a/openpcd/firmware/include/openpcd.h b/openpcd/firmware/include/openpcd.h
index 6bd88d3..e6ccebe 100644
--- a/openpcd/firmware/include/openpcd.h
+++ b/openpcd/firmware/include/openpcd.h
@@ -72,6 +72,9 @@ enum openpcd_cmd_class {
#define OPENPCD_CMD_USBTEST_IN (0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_USBTEST))
#define OPENPCD_CMD_USBTEST_OUT (0x2|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_USBTEST))
+/* FIXME */
+#define OPENPCD_CMD_PIO_IRQ (0x3|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_USBTEST))
+
#define OPENPCD_VENDOR_ID 0x2342
#define OPENPCD_PRODUCT_ID 0x0001
diff --git a/openpcd/firmware/src/os/pio_irq.c b/openpcd/firmware/src/os/pio_irq.c
index 266512e..8dae806 100644
--- a/openpcd/firmware/src/os/pio_irq.c
+++ b/openpcd/firmware/src/os/pio_irq.c
@@ -2,33 +2,57 @@
#include <sys/types.h>
#include <lib_AT91SAM7.h>
#include <os/pio_irq.h>
+#include <os/dbgu.h>
+#include <os/req_ctx.h>
+#include <openpcd.h>
-static irq_handler_t *pio_handlers[NR_PIO];
+struct pioirq_state {
+ irq_handler_t *handlers[NR_PIO];
+ u_int32_t usbmask;
+ u_int32_t usb_throttled; /* atomic? */
+};
-#if 0
-static u_int8_t ffs(u_int32_t in)
-{
- int i;
-
- for (i = sizeof(in)*8; i > 0; i++) {
- if (in & (1 << (i-1)))
- return i;
- }
-
- return 0;
-}
-#endif
+static struct pioirq_state pirqs;
static void pio_irq_demux(void)
{
u_int32_t pio = AT91F_PIO_GetInterruptStatus(AT91C_BASE_PIOA);
+ u_int8_t send_usb = 0;
int i;
+ DEBUGPCRF("PIO_ISR_STATUS = 0x%08x", pio);
+
for (i = 0; i < NR_PIO; i++) {
- if (pio & (1 << i) && pio_handlers[i])
- pio_handlers[i](i);
+ if (pio & (1 << i) && pirqs.handlers[i])
+ pirqs.handlers[i](i);
+ if (pirqs.usbmask & (1 << i))
+ send_usb = 1;
+ }
+
+ if (send_usb && !pirqs.usb_throttled) {
+ struct req_ctx *irq_rctx;
+ irq_rctx = req_ctx_find_get(RCTX_STATE_FREE,
+ RCTX_STATE_PIOIRQ_BUSY);
+ if (!irq_rctx) {
+ /* we cannot disable the interrupt, since we have
+ * non-usb listeners */
+ pirqs.usb_throttled = 1;
+ } else {
+ struct openpcd_hdr *opcdh;
+ u_int32_t *regmask;
+ opcdh = (struct openpcd_hdr *) &irq_rctx->tx.data[0];
+ regmask = (u_int32_t *) (&irq_rctx->tx.data[0] + sizeof(*opcdh));
+ opcdh->cmd = OPENPCD_CMD_PIO_IRQ;
+ opcdh->reg = 0x00;
+ opcdh->flags = 0x00;
+ opcdh->val = 0x00;
+
+ irq_rctx->tx.tot_len = sizeof(*opcdh) + sizeof(u_int32_t);
+ req_ctx_set_state(irq_rctx, RCTX_STATE_UDP_EP3_PENDING);
+ }
}
- return;
+
+ AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_PIOA);
}
void pio_irq_enable(u_int32_t pio)
@@ -49,12 +73,12 @@ int pio_irq_register(u_int32_t pio, irq_handler_t *handler)
return -EINVAL;
num--;
- if (pio_handlers[num])
+ if (pirqs.handlers[num])
return -EBUSY;
pio_irq_disable(pio);
AT91F_PIO_CfgInput(AT91C_BASE_PIOA, pio);
- pio_handlers[num] = handler;
+ pirqs.handlers[num] = handler;
return 0;
}
@@ -68,11 +92,29 @@ void pio_irq_unregister(u_int32_t pio)
num--;
pio_irq_disable(pio);
- pio_handlers[num] = NULL;
+ pirqs.handlers[num] = NULL;
+}
+
+static int pio_irq_usb_in(struct req_ctx *rctx)
+{
+ struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->rx.data[0];
+ struct openpcd_hdr *pih = (struct openpcd_hdr *) &rctx->tx.data[0];
+
+ switch (poh->cmd) {
+ case OPENPCD_CMD_PIO_IRQ:
+ pirqs.usbmask = poh->val;
+ break;
+ default:
+ DEBUGP("UNKNOWN ");
+ return -EINVAL;
+ }
+
+ return 0;
}
void pio_irq_init(void)
{
+ AT91F_PIOA_CfgPMC();
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_PIOA,
AT91C_AIC_PRIOR_LOWEST,
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &pio_irq_demux);
diff --git a/openpcd/firmware/src/os/req_ctx.h b/openpcd/firmware/src/os/req_ctx.h
index f57f02f..82a133f 100644
--- a/openpcd/firmware/src/os/req_ctx.h
+++ b/openpcd/firmware/src/os/req_ctx.h
@@ -37,6 +37,8 @@ struct req_ctx {
#define RCTX_STATE_SSC_RX_BUSY 0x20
+#define RCTX_STATE_PIOIRQ_BUSY 0x80
+
#define NUM_REQ_CTX 8
extern struct req_ctx *req_ctx_find_get(unsigned long old_state, unsigned long new_state);
extern struct req_ctx *req_ctx_find_busy(void);
personal git repositories of Harald Welte. Your mileage may vary