diff options
-rw-r--r-- | openpcd/firmware/include/openpcd.h | 3 | ||||
-rw-r--r-- | openpcd/firmware/src/os/pio_irq.c | 82 | ||||
-rw-r--r-- | openpcd/firmware/src/os/req_ctx.h | 2 |
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); |