diff options
author | laforge <laforge@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2006-09-12 17:35:30 +0000 |
---|---|---|
committer | laforge <laforge@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2006-09-12 17:35:30 +0000 |
commit | d256545b2fd62d78910efcc6273c3b70abd3aa13 (patch) | |
tree | a05e17ec752cfbcc0b79fdbfba81fb949545a112 /firmware/src/os/pio_irq.c | |
parent | 04e0441914eeb25e042189679b55c9577fc96d2a (diff) |
move to new directory
git-svn-id: https://svn.openpcd.org:2342/trunk@191 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
Diffstat (limited to 'firmware/src/os/pio_irq.c')
-rw-r--r-- | firmware/src/os/pio_irq.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/firmware/src/os/pio_irq.c b/firmware/src/os/pio_irq.c new file mode 100644 index 0000000..8dae806 --- /dev/null +++ b/firmware/src/os/pio_irq.c @@ -0,0 +1,122 @@ +#include <errno.h> +#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> + +struct pioirq_state { + irq_handler_t *handlers[NR_PIO]; + u_int32_t usbmask; + u_int32_t usb_throttled; /* atomic? */ +}; + +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) && 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); + } + } + + AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_PIOA); +} + +void pio_irq_enable(u_int32_t pio) +{ + AT91F_PIO_InterruptEnable(AT91C_BASE_PIOA, pio); +} + +void pio_irq_disable(u_int32_t pio) +{ + AT91F_PIO_InterruptDisable(AT91C_BASE_PIOA, pio); +} + +int pio_irq_register(u_int32_t pio, irq_handler_t *handler) +{ + u_int8_t num = ffs(pio); + + if (num == 0) + return -EINVAL; + num--; + + if (pirqs.handlers[num]) + return -EBUSY; + + pio_irq_disable(pio); + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, pio); + pirqs.handlers[num] = handler; + + return 0; +} + +void pio_irq_unregister(u_int32_t pio) +{ + u_int8_t num = ffs(pio); + + if (num == 0) + return; + num--; + + pio_irq_disable(pio); + 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); + AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_PIOA); +} |