From 514b0f72f50b50b75ef855f008c888f29989d68e Mon Sep 17 00:00:00 2001 From: laforge Date: Wed, 20 Sep 2006 11:44:10 +0000 Subject: - Add OpenPICC register definition (and USB command handling) - Add automatic generation of include/compile.h with svn revision and compiletime - Add openpcd_compile_version structure to obtain version via USB - Move LED commands into new CMD_CLS_GENERIC family - Update TODO - Add support for large (2048 byte) request contexts in addition to 64byte - Shrink req_ctx size by collapsing rx and tx buffer into one - move definition of DFU_API_LOCATION to header file - Implement large req_ctx aware USB transmit / refill routines - Implement TX refilling for IRQ Endpoint - Print version information at startup time - move some generic req_ctx processing into usb_handler.c - Some further work on DFU (still not finished) - Only use '-Os' for DFU, use '-O2' for application code git-svn-id: https://svn.openpcd.org:2342/trunk@208 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- firmware/Makefile | 8 ++-- firmware/TODO | 9 ++-- firmware/include/openpcd.h | 22 ++++++--- firmware/include/openpicc_regs.h | 46 +++++++++++++++++++ firmware/src/dfu/dfu.c | 38 +++++++++++----- firmware/src/os/dbgu.c | 8 +++- firmware/src/os/led.c | 21 --------- firmware/src/os/main.c | 12 +++++ firmware/src/os/main.h | 1 + firmware/src/os/pcd_enumerate.c | 93 +++++++++++++++++++++++++++------------ firmware/src/os/pcd_enumerate.h | 7 ++- firmware/src/os/pio_irq.c | 11 +++-- firmware/src/os/pwm.c | 7 ++- firmware/src/os/req_ctx.c | 37 +++++++++++++++- firmware/src/os/req_ctx.h | 16 ++----- firmware/src/os/usb_benchmark.c | 11 +++-- firmware/src/os/usb_handler.c | 42 +++++++++++------- firmware/src/os/usb_handler.h | 10 +++++ firmware/src/os/usbcmd_generic.c | 49 +++++++++++++++++++++ firmware/src/os/usbcmd_generic.h | 4 ++ firmware/src/pcd/rc632.c | 81 ++++++++++++++-------------------- firmware/src/picc/adc.c | 10 ++--- firmware/src/picc/decoder.c | 2 - firmware/src/picc/main_openpicc.c | 5 +++ firmware/src/picc/openpicc.c | 82 ++++++++++++++++++++++++++++++++++ firmware/src/picc/opicc_reg.h | 18 ++++++++ firmware/src/picc/pll.c | 1 + firmware/src/picc/ssc_picc.c | 21 +++++---- 28 files changed, 486 insertions(+), 186 deletions(-) create mode 100644 firmware/include/openpicc_regs.h create mode 100644 firmware/src/os/usbcmd_generic.c create mode 100644 firmware/src/os/usbcmd_generic.h create mode 100644 firmware/src/picc/openpicc.c create mode 100644 firmware/src/picc/opicc_reg.h diff --git a/firmware/Makefile b/firmware/Makefile index b5044e4..31e7cc5 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -87,7 +87,7 @@ SRCARM += src/os/pcd_enumerate.c src/os/fifo.c src/os/dbgu.c \ src/os/led.c src/os/req_ctx.c src/os/trigger.c \ src/os/main.c src/os/syscalls.c src/os/usb_handler.c \ src/os/usb_benchmark.c src/os/tc_cdiv.c src/os/pit.c \ - src/os/pwm.c src/os/pio_irq.c + src/os/pwm.c src/os/pio_irq.c src/os/usbcmd_generic.c ifeq ($(BOARD), PCD) # PCD support code @@ -102,7 +102,8 @@ ifeq ($(BOARD), PICC) SRCARM += src/picc/tc_fdt.c src/picc/ssc_picc.c src/picc/adc.c \ src/picc/decoder.c src/picc/decoder_miller.c \ src/picc/load_modulation.c \ - src/picc/decoder_nrzl.c src/picc/poti.c src/picc/pll.c + src/picc/decoder_nrzl.c src/picc/poti.c src/picc/pll.c \ + src/picc/openpicc.c # finally, the actual main application SRCARM += src/picc/$(TARGET).c endif @@ -144,7 +145,7 @@ FORMAT = binary # Optimization level, can be [0, 1, 2, 3, s]. # 0 = turn off optimization. s = optimize for size. # (Note: 3 is not always the best optimization level. See avr-libc FAQ.) -OPT = s +OPT = 2 #OPT = 0 # Debugging format. @@ -562,6 +563,7 @@ clean_list : $(REMOVE) $(CPPSRCARM:.cpp=.s) $(REMOVE) $(CPPSRCARM:.cpp=.d) $(REMOVE) .dep/* + $(REMOVE) include/compile.h .PHONY: include/compile.h include/compile.h: diff --git a/firmware/TODO b/firmware/TODO index c63fb89..1d19223 100644 --- a/firmware/TODO +++ b/firmware/TODO @@ -1,19 +1,18 @@ SPI: - use PDC DMA for SPI transfers -- use real SPI clock divisor (4.8MHz) rather than current 320kHz clock RC632: - Fix locking between 'atomic' ops like set/clear bit and RC632 IRQ - Implement VFIFO handling USB: -- don't busy-wait for EP2/EP3 transfers but rather use TX completion IRQ - Implement VFIFO handling -- Add DFU descriptor to host DFU: -- implement DFU protocol for bootloader flash partition -- add capability to copy and execute DFU from RAM +- fix DFU download (usb control write / zlp at end) +- add capability to flash DFU itself +- add a header to the application program, checksum and size +- checksum application image. If wrong, enter DFU recovery mode - Get rid of lots of constant values and replace them by proper defines Generic: diff --git a/firmware/include/openpcd.h b/firmware/include/openpcd.h index e6ccebe..9e2d45e 100644 --- a/firmware/include/openpcd.h +++ b/firmware/include/openpcd.h @@ -6,19 +6,29 @@ #include struct openpcd_hdr { - u_int8_t cmd; /* command. high nibble: class, low nibble: cmd */ + u_int8_t cmd; /* command. high nibble: class, + * low nibble: cmd */ u_int8_t flags; u_int8_t reg; /* register */ u_int8_t val; /* value (in case of write *) */ u_int8_t data[0]; } __attribute__ ((packed)); -#define OPENPC_FLAG_RESPOND 0x01 /* Response requested */ +#define OPCD_REV_LEN 16 +struct openpcd_compile_version { + char svnrev[OPCD_REV_LEN]; + char by[OPCD_REV_LEN]; + char date[OPCD_REV_LEN]; +} __attribute__ ((packed)); + +#define OPENPCD_FLAG_RESPOND 0x01 /* Response requested */ +#define OPENPCD_FLAG_ERROR 0x80 /* An error occurred */ enum openpcd_cmd_class { + OPENPCD_CMD_CLS_GENERIC = 0x0, /* PCD (reader) side */ OPENPCD_CMD_CLS_RC632 = 0x1, - OPENPCD_CMD_CLS_LED = 0x2, + //OPENPCD_CMD_CLS_LED = 0x2, OPENPCD_CMD_CLS_SSC = 0x3, OPENPCD_CMD_CLS_PWM = 0x4, OPENPCD_CMD_CLS_ADC = 0x5, @@ -35,6 +45,9 @@ enum openpcd_cmd_class { #define OPENPCD_CLS2CMD(x) (x << 4) +#define OPENPCD_CMD_GET_VERSION (0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_GENERIC)) +#define OPENPCD_CMD_SET_LED (0x2|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_GENERIC)) + /* CMD_CLS_RC632 */ #define OPENPCD_CMD_WRITE_REG (0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632)) #define OPENPCD_CMD_WRITE_FIFO (0x2|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632)) @@ -47,9 +60,6 @@ enum openpcd_cmd_class { #define OPENPCD_CMD_DUMP_REGS (0x9|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632)) #define OPENPCD_CMD_IRQ (0xa|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_RC632)) -/* CMD_CLS_LED */ -#define OPENPCD_CMD_SET_LED (0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_LED)) - /* CMD_CLS_SSC */ #define OPENPCD_CMD_SSC_READ (0x1|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_SSC)) #define OPENPCD_CMD_SSC_WRITE (0x2|OPENPCD_CLS2CMD(OPENPCD_CMD_CLS_SSC)) diff --git a/firmware/include/openpicc_regs.h b/firmware/include/openpicc_regs.h new file mode 100644 index 0000000..2df0618 --- /dev/null +++ b/firmware/include/openpicc_regs.h @@ -0,0 +1,46 @@ +#ifndef _OPENPICC_STATE +#define _OPENPICC_STATE + +/* according to ISO 14443-3(2000) 6.2 */ +enum opicc_14443a_state { + ISO14443A_ST_POWEROFF, + ISO14443A_ST_IDLE, + ISO14443A_ST_READY, + ISO14443A_ST_ACTIVE, + ISO14443A_ST_HALT, + ISO14443A_ST_READY2, + ISO14443A_ST_ACTIVE2, +}; + +enum opicc_reg_tx_control { + OPICC_REG_TX_BPSK = 0x01, + OPICC_REG_TX_MANCHESTER = 0x02, + OPICC_REG_TX_INTENSITY0 = 0x00, + OPICC_REG_TX_INTENSITY1 = 0x10, + OPICC_REG_TX_INTENSITY2 = 0x20, + OPICC_REG_TX_INTENSITY3 = 0x30, +}; + +enum opicc_reg { + OPICC_REG_14443A_UIDLEN,/* Length of UID in bytes */ + + OPICC_REG_14443A_FDT0, /* Frame delay time if last bit 0 */ + OPICC_REG_14443A_FDT1, /* Frame delay time if last bit 1 */ + OPICC_REG_14443A_STATE, /* see 'enum opicc_14443a_state' */ + + OPICC_REG_RX_CLK_DIV, /* Clock divider for Rx sample clock */ + OPICC_REG_RX_CLK_PHASE, /* Phase shift of Rx sample clock */ + OPICC_REG_RX_COMP_LEVEL,/* Comparator level of Demodulator */ + OPICC_REG_RX_CONTROL, + + OPICC_REG_TX_CLK_DIV, /* Clock divider for Tx sample clock */ + OPICC_REG_TX_CONTROL, /* see 'enum opicc_reg_tx_Control */ + _OPICC_NUM_REGS, +}; + +enum openpicc_14443a_sregs { + /* string 'registers' */ + OPICC_REG_14443A_UID, /* The UID (4...10 bytes) */ +}; + +#endif diff --git a/firmware/src/dfu/dfu.c b/firmware/src/dfu/dfu.c index 09c8784..c5f706e 100644 --- a/firmware/src/dfu/dfu.c +++ b/firmware/src/dfu/dfu.c @@ -31,6 +31,8 @@ #include #include "../openpcd.h" +#define SAM7DFU_SIZE 0x1000 + /* If debug is enabled, we need to access debug functions from flash * and therefore have to omit flashing */ #define DEBUG_DFU @@ -56,8 +58,8 @@ static void __dfufunc udp_init(void) AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP; AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP); - /* Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO - * Set in PIO mode and Configure in Output */ + /* Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the + * corresponding PIO Set in PIO mode and Configure in Output */ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); } @@ -150,8 +152,8 @@ static void __dfufunc udp_ep0_send_stall(void) static u_int8_t status; -static u_int8_t *ptr = (u_int8_t *)0x00101000; -static __dfudata u_int32_t dfu_state; +static u_int8_t *ptr = AT91C_IFLASH + SAM7DFU_SIZE; +static __dfudata u_int32_t dfu_state = DFU_STATE_appIDLE; static u_int8_t pagebuf[AT91C_IFLASH_PAGE_SIZE]; static u_int16_t page_from_ramaddr(const void *addr) @@ -179,7 +181,8 @@ static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len) DEBUGE("download "); if (len > AT91C_IFLASH_PAGE_SIZE) { - /* Too big */ + /* Too big. Not that we'd really care, but it's a + * DFU protocol violation */ dfu_state = DFU_STATE_dfuERROR; status = DFU_STATUS_errADDRESS; udp_ep0_send_stall(); @@ -196,6 +199,12 @@ static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len) dfu_state = DFU_STATE_dfuMANIFEST_SYNC; return 0; } + if (ptr + len > AT91C_IFLASH + AT91C_IFLASH_SIZE) { + dfu_state = DFU_STATE_dfuERROR; + status = DFU_STATUS_errADDRESS; + udp_ep0_send_stall(); + return -EINVAL; + } udp_ep0_recv_data(pagebuf, sizeof(pagebuf)); @@ -234,8 +243,8 @@ static __dfufunc int handle_upload(u_int16_t val, u_int16_t len) return -EINVAL; } - if (ptr + len > AT91C_IFLASH_SIZE) - len = AT91C_IFLASH_SIZE - (u_int32_t) ptr; + if (ptr + len > AT91C_IFLASH + AT91C_IFLASH_SIZE) + len = AT91C_IFLASH + AT91C_IFLASH_SIZE - (u_int32_t) ptr; udp_ep0_send_data((char *)ptr, len); ptr+= len; @@ -273,6 +282,7 @@ static __dfufunc void handle_getstatus(void) dstat.bStatus = status; dstat.bState = dfu_state; dstat.iString = 0; + /* FIXME: set dstat.bwPollTimeout */ udp_ep0_send_data((char *)&dstat, sizeof(dstat)); } @@ -322,11 +332,12 @@ int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req, dfu_state = DFU_STATE_dfuERROR; goto send_stall; } + ptr = AT91C_IFLASH + SAM7DFU_SIZE; handle_dnload(val, len); dfu_state = DFU_STATE_dfuDNLOAD_SYNC; break; case USB_REQ_DFU_UPLOAD: - ptr = 0x00101000; /* Flash base address for app */ + ptr = AT91C_IFLASH + SAM7DFU_SIZE; dfu_state = DFU_STATE_dfuUPLOAD_IDLE; handle_upload(val, len); break; @@ -697,13 +708,16 @@ static __dfufunc void dfu_udp_ep0_handler(void) udp_ep0_send_stall(); break; default: - DEBUGE("DEFAULT(req=0x%02x, type=0x%02x) ", bRequest, bmRequestType); + DEBUGE("DEFAULT(req=0x%02x, type=0x%02x) ", + bRequest, bmRequestType); if ((bmRequestType & 0x3f) == USB_TYPE_DFU) { - dfu_ep0_handler(bmRequestType, bRequest, wValue, wLength); + dfu_ep0_handler(bmRequestType, bRequest, + wValue, wLength); } else udp_ep0_send_stall(); break; } + DEBUGE("\r\n"); } /* minimal USB IRQ handler in DFU mode */ @@ -747,9 +761,12 @@ static void dfu_switch(void) void __dfufunc dfu_main(void) { AT91F_DBGU_Init(); + DEBUGE("sam7dfu startup\r\n"); udp_init(); + dfu_state = DFU_STATE_dfuIDLE; + /* This implements AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_UDP, OPENPCD_IRQ_PRIO_UDP, @@ -771,6 +788,7 @@ void __dfufunc dfu_main(void) flash_init(); + DEBUGE("sam7dfu entering main loop\r\n"); /* do nothing, since all of DFU is interrupt driven */ while (1) ; } diff --git a/firmware/src/os/dbgu.c b/firmware/src/os/dbgu.c index f7c62e3..eed5546 100644 --- a/firmware/src/os/dbgu.c +++ b/firmware/src/os/dbgu.c @@ -139,7 +139,13 @@ void AT91F_DBGU_Init(void) DBGU_irq_handler); AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SYS); - AT91F_DBGU_Printk + AT91F_DBGU_Printk("\n\r"); + AT91F_DBGU_Printk(opcd_version.svnrev); + AT91F_DBGU_Printk(" "); + AT91F_DBGU_Printk(opcd_version.date); + AT91F_DBGU_Printk(" "); + AT91F_DBGU_Printk(opcd_version.by); + AT91F_DBGU_Printk("\n\r"); ("\n\r-I- OpenPCD test mode\n\r 0) Set Pull-up 1) Clear Pull-up " "2) Toggle LED1 3) Toggle LED2 4) Test RC632\n\r" "5) Read RxWait 6) Write RxWait 7) Dump RC632 Regs\n\r"); diff --git a/firmware/src/os/led.c b/firmware/src/os/led.c index 30353ac..96ffecc 100644 --- a/firmware/src/os/led.c +++ b/firmware/src/os/led.c @@ -73,31 +73,10 @@ int led_toggle(int led) return !on; } -static int led_usb_rx(struct req_ctx *rctx) -{ - struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->rx.data[0]; - int ret = 1; - - switch (poh->cmd) { - case OPENPCD_CMD_SET_LED: - DEBUGP("SET LED(%u,%u) ", poh->reg, poh->val); - led_switch(poh->reg, poh->val); - break; - default: - DEBUGP("UNKNOWN "); - ret = -EINVAL; - break; - } - req_ctx_put(rctx); - return 1; -} - void led_init(void) { AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1); AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2); led_switch(1, 0); led_switch(2, 0); - - usb_hdlr_register(&led_usb_rx, OPENPCD_CMD_CLS_LED); } diff --git a/firmware/src/os/main.c b/firmware/src/os/main.c index 3e05a7d..ce611bc 100644 --- a/firmware/src/os/main.c +++ b/firmware/src/os/main.c @@ -24,9 +24,18 @@ #include #include #include +#include #include #include "../openpcd.h" +#include + +const struct openpcd_compile_version opcd_version = { + .svnrev = COMPILE_SVNREV, + .date = COMPILE_DATE, + .by = COMPILE_BY, +}; + int main(void) { /* initialize LED and debug unit */ @@ -34,10 +43,13 @@ int main(void) AT91F_DBGU_Init(); AT91F_PIOA_CfgPMC(); + /* call application specific init function */ _init_func(); /* initialize USB */ + req_ctx_init(); + usbcmd_gen_init(); udp_open(); // Enable User Reset and set its minimal assertion to 960 us diff --git a/firmware/src/os/main.h b/firmware/src/os/main.h index 1adc8f6..bd42341 100644 --- a/firmware/src/os/main.h +++ b/firmware/src/os/main.h @@ -5,4 +5,5 @@ extern void _init_func(void); extern int _main_dbgu(char key); extern void _main_func(void); +extern const struct openpcd_compile_version opcd_version; #endif diff --git a/firmware/src/os/pcd_enumerate.c b/firmware/src/os/pcd_enumerate.c index 1f35b06..e3443a8 100644 --- a/firmware/src/os/pcd_enumerate.c +++ b/firmware/src/os/pcd_enumerate.c @@ -52,7 +52,6 @@ #define AT91C_EP_INT 3 #ifdef CONFIG_DFU -#define DFU_API_LOCATION ((const struct dfuapi *) 0x00100fd0) static const struct dfuapi *dfu = DFU_API_LOCATION; #define udp_init dfu->udp_init #define udp_ep0_send_data dfu->ep0_send_data @@ -167,32 +166,64 @@ void udp_unthrottle(void) pUDP->UDP_IER = AT91C_UDP_EPINT1; } -int udp_refill_ep(int ep, struct req_ctx *rctx) +int udp_refill_ep(int ep) { u_int16_t i; AT91PS_UDP pUDP = upcd.pUdp; + struct req_ctx *rctx; + unsigned int start, end; + /* If we're not configured by the host yet, there is no point + * in trying to send data to it... */ if (!upcd.cur_config) return -ENXIO; - if (rctx->tx.tot_len > AT91C_EP_IN_SIZE) { - DEBUGPCRF("TOO LARGE!!!!!!!!!!!!!!!!!!!!!!!!!!! (%d > %d)", - rctx->tx.tot_len, AT91C_EP_IN_SIZE); - return -EINVAL; - } - + /* If there are already two packets in transit, the DPR of + * the SAM7 UDC doesn't have space for more data */ if (atomic_read(&upcd.ep[ep].pkts_in_transit) == 2) return -EBUSY; - + + /* If we have an incompletely-transmitted req_ctx (>EP size), + * we need to transmit the rest and finish the transaction */ + if (upcd.ep[ep].incomplete.rctx) { + rctx = upcd.ep[ep].incomplete.rctx; + start = upcd.ep[ep].incomplete.bytes_sent; + } else { + unsigned int state, state_busy; + if (ep == 2) { + state = RCTX_STATE_UDP_EP2_PENDING; + state_busy = RCTX_STATE_UDP_EP2_BUSY; + } else { + state = RCTX_STATE_UDP_EP3_PENDING; + state_busy = RCTX_STATE_UDP_EP3_BUSY; + } + + /* get pending rctx and start transmitting from zero */ + rctx = req_ctx_find_get(0, state, state_busy); + if (!rctx) + return 0; + start = 0; + } + + if (rctx->tot_len - start <= AT91C_EP_IN_SIZE) + end = rctx->tot_len; + else + end = AT91C_EP_IN_SIZE; + /* fill FIFO/DPR */ - for (i = 0; i < rctx->tx.tot_len; i++) - pUDP->UDP_FDR[ep] = rctx->tx.data[i]; + for (i = start; i < end; i++) + pUDP->UDP_FDR[ep] = rctx->data[i]; if (atomic_inc_return(&upcd.ep[ep].pkts_in_transit) == 1) { /* not been transmitting before, start transmit */ pUDP->UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY; } + /* Increment the number of bytes sent in the current large + * context, if any */ + if (start != 0) + upcd.ep[ep].incomplete.bytes_sent += end-start; + /* return rctx to pool of free contexts */ req_ctx_put(rctx); @@ -257,19 +288,21 @@ static void udp_irq(void) if (csr & cur_rcv_bank) { u_int16_t pkt_recv = 0; u_int16_t pkt_size = csr >> 16; - struct req_ctx *rctx = req_ctx_find_get(RCTX_STATE_FREE, - RCTX_STATE_UDP_RCV_BUSY); + struct req_ctx *rctx = + req_ctx_find_get(0, RCTX_STATE_FREE, + RCTX_STATE_UDP_RCV_BUSY); if (rctx) { - rctx->rx.tot_len = pkt_size; + rctx->tot_len = pkt_size; while (pkt_size--) - rctx->rx.data[pkt_recv++] = pUDP->UDP_FDR[1]; + rctx->data[pkt_recv++] = pUDP->UDP_FDR[1]; pUDP->UDP_CSR[1] &= ~cur_rcv_bank; if (cur_rcv_bank == AT91C_UDP_RX_DATA_BK0) cur_rcv_bank = AT91C_UDP_RX_DATA_BK1; else cur_rcv_bank = AT91C_UDP_RX_DATA_BK0; upcd.cur_rcv_bank = cur_rcv_bank; + DEBUGI("rctxdump(%s) ", hexdump(rctx->data, rctx->tot_len)); req_ctx_set_state(rctx, RCTX_STATE_UDP_RCV_DONE); DEBUGI("RCTX=%u ", req_ctx_num(rctx)); } else { @@ -283,8 +316,6 @@ static void udp_irq(void) csr = pUDP->UDP_CSR[2]; DEBUGI("EP2INT(In, CSR=0x%08x) ", csr); if (csr & AT91C_UDP_TXCOMP) { - struct req_ctx *rctx; - DEBUGI("ACK_TX_COMP "); /* acknowledge TX completion */ pUDP->UDP_CSR[2] &= ~AT91C_UDP_TXCOMP; @@ -294,21 +325,24 @@ static void udp_irq(void) if (atomic_dec_return(&upcd.ep[2].pkts_in_transit) == 1) pUDP->UDP_CSR[2] |= AT91C_UDP_TXPKTRDY; - /* try to re-fill from pending rcts for EP2 */ - rctx = req_ctx_find_get(RCTX_STATE_UDP_EP2_PENDING, - RCTX_STATE_UDP_EP2_BUSY); - if (rctx) - udp_refill_ep(2, rctx); - else - DEBUGI("NO_RCTX_pending "); + udp_refill_ep(2); } } if (isr & AT91C_UDP_EPINT3) { csr = pUDP->UDP_CSR[3]; DEBUGI("EP3INT(Interrupt, CSR=0x%08x) ", csr); /* Transmit has completed, re-fill from pending rcts for EP3 */ - } + if (csr & AT91C_UDP_TXCOMP) { + pUDP->UDP_CSR[3] &= ~AT91C_UDP_TXCOMP; + while (pUDP->UDP_CSR[3] & AT91C_UDP_TXCOMP) ; + /* if we already have another packet in DPR, send it */ + if (atomic_dec_return(&upcd.ep[3].pkts_in_transit) == 1) + pUDP->UDP_CSR[3] |= AT91C_UDP_TXPKTRDY; + + udp_refill_ep(3); + } + } if (isr & AT91C_UDP_RXSUSP) { pUDP->UDP_ICR = AT91C_UDP_RXSUSP; DEBUGI("RXSUSP "); @@ -424,6 +458,7 @@ static void udp_ep0_handler(void) pUDP->UDP_CSR[0] &= ~AT91C_UDP_RXSETUP; while ((pUDP->UDP_CSR[0] & AT91C_UDP_RXSETUP)) ; + DEBUGE("dfu_state = %u ", *dfu->dfu_state); /* Handle supported standard device request Cf Table 9-3 in USB * speciication Rev 1.1 */ switch ((bRequest << 8) | bmRequestType) { @@ -465,6 +500,10 @@ static void udp_ep0_handler(void) udp_ep0_send_stall(); break; } + } else if (wValue == 0x2100) { + /* Return Function descriptor */ + udp_ep0_send_data((const char *) &dfu->dfu_cfg_descriptor->func_dfu, + MIN(sizeof(dfu->dfu_cfg_descriptor->func_dfu), wLength)); #if 0 } else if (wValue == 0x400) { /* Return Interface descriptor */ @@ -581,7 +620,7 @@ static void udp_ep0_handler(void) pUDP->UDP_RSTEP &= ~AT91C_UDP_EP2; /* free all currently transmitting contexts */ - while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP2_BUSY, + while (rctx = req_ctx_find_get(0, RCTX_STATE_UDP_EP2_BUSY, RCTX_STATE_FREE)) {} atomic_set(&upcd.ep[wIndex].pkts_in_transit, 0); } @@ -593,7 +632,7 @@ static void udp_ep0_handler(void) pUDP->UDP_RSTEP &= ~AT91C_UDP_EP3; /* free all currently transmitting contexts */ - while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP3_BUSY, + while (rctx = req_ctx_find_get(0, RCTX_STATE_UDP_EP3_BUSY, RCTX_STATE_FREE)) {} atomic_set(&upcd.ep[wIndex].pkts_in_transit, 0); } diff --git a/firmware/src/os/pcd_enumerate.h b/firmware/src/os/pcd_enumerate.h index 813243e..3b95de7 100644 --- a/firmware/src/os/pcd_enumerate.h +++ b/firmware/src/os/pcd_enumerate.h @@ -10,13 +10,16 @@ struct req_ctx; extern void udp_open(void); -extern int udp_refill_ep(int ep, struct req_ctx *rctx); +extern int udp_refill_ep(int ep); extern void udp_unthrottle(void); extern void udp_reset(void); struct ep_ctx { atomic_t pkts_in_transit; - void *ctx; + struct { + struct req_ctx *rctx; + unsigned int bytes_sent; + } incomplete; }; struct udp_pcd { diff --git a/firmware/src/os/pio_irq.c b/firmware/src/os/pio_irq.c index dfe818c..14f51c2 100644 --- a/firmware/src/os/pio_irq.c +++ b/firmware/src/os/pio_irq.c @@ -50,7 +50,7 @@ static void pio_irq_demux(void) if (send_usb && !pirqs.usb_throttled) { struct req_ctx *irq_rctx; - irq_rctx = req_ctx_find_get(RCTX_STATE_FREE, + irq_rctx = req_ctx_find_get(0, RCTX_STATE_FREE, RCTX_STATE_PIOIRQ_BUSY); if (!irq_rctx) { /* we cannot disable the interrupt, since we have @@ -59,14 +59,14 @@ static void pio_irq_demux(void) } 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 = (struct openpcd_hdr *) irq_rctx->data; + regmask = (u_int32_t *) (irq_rctx->data + 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); + irq_rctx->tot_len = sizeof(*opcdh) + sizeof(u_int32_t); req_ctx_set_state(irq_rctx, RCTX_STATE_UDP_EP3_PENDING); } } @@ -116,8 +116,7 @@ void pio_irq_unregister(u_int32_t pio) 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]; + struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data; switch (poh->cmd) { case OPENPCD_CMD_PIO_IRQ: diff --git a/firmware/src/os/pwm.c b/firmware/src/os/pwm.c index 5c52ee6..285f4e7 100644 --- a/firmware/src/os/pwm.c +++ b/firmware/src/os/pwm.c @@ -119,8 +119,7 @@ void pwm_duty_set_percent(int channel, u_int16_t duty) static int pwm_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]; */ + struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data; u_int32_t *freq; switch (poh->cmd) { @@ -137,7 +136,7 @@ static int pwm_usb_in(struct req_ctx *rctx) goto respond; break; case OPENPCD_CMD_PWM_FREQ_SET: - if (rctx->rx.tot_len < sizeof(*poh)+4) + if (rctx->tot_len < sizeof(*poh)+4) break; freq = (unsigned char *) poh + sizeof(*poh); pwm_freq_set(0, *freq); @@ -153,7 +152,7 @@ static int pwm_usb_in(struct req_ctx *rctx) return 0; respond: req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); - udp_refill_ep(2, rctx); + udp_refill_ep(2); return 1; } diff --git a/firmware/src/os/req_ctx.c b/firmware/src/os/req_ctx.c index d118aca..fef7258 100644 --- a/firmware/src/os/req_ctx.c +++ b/firmware/src/os/req_ctx.c @@ -28,14 +28,32 @@ /* FIXME: locking, FIFO order processing */ +#define RCTX_SIZE_LARGE 2048 +#define RCTX_SIZE_SMALL 64 + +#define NUM_RCTX_SMALL 8 +#define NUM_RCTX_LARGE 3 + +#define NUM_REQ_CTX (NUM_RCTX_SMALL+NUM_RCTX_LARGE) + +static u_int8_t rctx_data[NUM_RCTX_SMALL][RCTX_SIZE_SMALL]; +static u_int8_t rctx_data_large[NUM_RCTX_LARGE][RCTX_SIZE_LARGE]; + static struct req_ctx req_ctx[NUM_REQ_CTX]; -struct req_ctx *req_ctx_find_get(unsigned long old_state, unsigned long new_state) +struct req_ctx *req_ctx_find_get(int large, + unsigned long old_state, + unsigned long new_state) { unsigned long flags; u_int8_t i; + + if (large) + i = NUM_RCTX_SMALL; + else + i = 0; - for (i = 0; i < NUM_REQ_CTX; i++) { + for (1; i < NUM_REQ_CTX; i++) { local_irq_save(flags); if (req_ctx[i].state == old_state) { req_ctx[i].state = new_state; @@ -67,3 +85,18 @@ void req_ctx_put(struct req_ctx *ctx) { req_ctx_set_state(ctx, RCTX_STATE_FREE); } + +void req_ctx_init(void) +{ + int i; + + for (i = 0; i < NUM_RCTX_SMALL; i++) { + req_ctx[i].size = RCTX_SIZE_SMALL; + req_ctx[i].data = rctx_data[i]; + } + + for (i = 0; i < NUM_RCTX_LARGE; i++) { + req_ctx[i].size = RCTX_SIZE_LARGE; + req_ctx[NUM_RCTX_SMALL+i].data = rctx_data_large[i]; + } +} diff --git a/firmware/src/os/req_ctx.h b/firmware/src/os/req_ctx.h index 82a133f..b68fb66 100644 --- a/firmware/src/os/req_ctx.h +++ b/firmware/src/os/req_ctx.h @@ -9,18 +9,11 @@ #include -struct req_buf { - u_int16_t hdr_len; - u_int16_t tot_len; - u_int8_t data[64]; -}; - struct req_ctx { - u_int16_t seq; /* request sequence number */ - u_int16_t flags; volatile u_int32_t state; - struct req_buf rx; - struct req_buf tx; + u_int16_t size; + u_int16_t tot_len; + u_int8_t *data; }; #define RCTX_STATE_FREE 0x00 @@ -39,8 +32,7 @@ struct req_ctx { #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_get(int large, unsigned long old_state, unsigned long new_state); extern struct req_ctx *req_ctx_find_busy(void); extern void req_ctx_set_state(struct req_ctx *ctx, unsigned long new_state); extern void req_ctx_put(struct req_ctx *ctx); diff --git a/firmware/src/os/usb_benchmark.c b/firmware/src/os/usb_benchmark.c index 1f890bf..bfc6b37 100644 --- a/firmware/src/os/usb_benchmark.c +++ b/firmware/src/os/usb_benchmark.c @@ -33,6 +33,8 @@ static void usbtest_tx_transfer(unsigned int num_pkts) { unsigned int i; +#if 0 +#warning please reimplement refill userspecified rctx for (i = 0; i < num_pkts; i++) { /* send 16 packets of 64byte */ while (udp_refill_ep(2, &dummy_rctx) < 0) @@ -41,11 +43,12 @@ static void usbtest_tx_transfer(unsigned int num_pkts) /* send one packet of 0 byte */ while (udp_refill_ep(2, &empty_rctx) < 0) ; +#endif } static int usbtest_rx(struct req_ctx *rctx) { - struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->rx.data[0]; + struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data; int i; switch (poh->cmd) { @@ -67,10 +70,10 @@ static int usbtest_rx(struct req_ctx *rctx) void usbtest_init(void) { - dummy_rctx.tx.tot_len = 64; - memset(dummy_rctx.tx.data, 0x23, 64); + dummy_rctx.tot_len = 64; + memset(dummy_rctx.data, 0x23, 64); - empty_rctx.tx.tot_len = 0; + empty_rctx.tot_len = 0; usb_hdlr_register(&usbtest_rx, OPENPCD_CMD_CLS_USBTEST); } diff --git a/firmware/src/os/usb_handler.c b/firmware/src/os/usb_handler.c index 6c45e18..c3d4cfa 100644 --- a/firmware/src/os/usb_handler.c +++ b/firmware/src/os/usb_handler.c @@ -46,23 +46,33 @@ void usb_hdlr_unregister(u_int8_t class) static int 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]; + struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data; usb_cmd_fn *hdlr; + int ret; DEBUGP("usb_in(cls=%d) ", OPENPCD_CMD_CLS(poh->cmd)); - if (rctx->rx.tot_len < sizeof(*poh)) + if (rctx->tot_len < sizeof(*poh)) return -EINVAL; - memcpy(pih, poh, sizeof(*poh)); - rctx->tx.tot_len = sizeof(*poh); - hdlr = cmd_hdlrs[OPENPCD_CMD_CLS(poh->cmd)]; - if (hdlr) - return (hdlr)(rctx); - else - DEBUGPCR("no handler for this class\n"); + if (!hdlr) { + DEBUGPCR("no handler for this class "); + ret = USB_ERR(USB_ERR_CMD_UNKNOWN); + } else + ret = (hdlr)(rctx); + + if (ret & USB_RET_ERR) { + poh->val = ret & 0xff; + poh->flags = OPENPCD_FLAG_ERROR; + } + if (ret & USB_RET_RESPOND) { + req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); + udp_refill_ep(2); + } + + DEBUGPCR(""); + return (ret & USB_RET_ERR) ? 1 : 0; } /* Process all pending request contexts that want to Tx on either @@ -71,17 +81,17 @@ void usb_out_process(void) { struct req_ctx *rctx; - while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP3_PENDING, + while (rctx = req_ctx_find_get(0, RCTX_STATE_UDP_EP3_PENDING, RCTX_STATE_UDP_EP3_BUSY)) { DEBUGPCRF("EP3_BUSY for ctx %u", req_ctx_num(rctx)); - if (udp_refill_ep(3, rctx) < 0) + if (udp_refill_ep(3) < 0) req_ctx_set_state(rctx, RCTX_STATE_UDP_EP3_PENDING); } - while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP2_PENDING, + while (rctx = req_ctx_find_get(0, RCTX_STATE_UDP_EP2_PENDING, RCTX_STATE_UDP_EP2_BUSY)) { DEBUGPCRF("EP2_BUSY for ctx %u", req_ctx_num(rctx)); - if (udp_refill_ep(2, rctx) < 0) + if (udp_refill_ep(2) < 0) req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); } } @@ -92,10 +102,10 @@ void usb_in_process(void) { struct req_ctx *rctx; - while (rctx = req_ctx_find_get(RCTX_STATE_UDP_RCV_DONE, + while (rctx = req_ctx_find_get(0, RCTX_STATE_UDP_RCV_DONE, RCTX_STATE_MAIN_PROCESSING)) { DEBUGPCRF("found used ctx %u: len=%u", - req_ctx_num(rctx), rctx->rx.tot_len); + req_ctx_num(rctx), rctx->tot_len); usb_in(rctx); } udp_unthrottle(); diff --git a/firmware/src/os/usb_handler.h b/firmware/src/os/usb_handler.h index 3efcc1f..9d5ad48 100644 --- a/firmware/src/os/usb_handler.h +++ b/firmware/src/os/usb_handler.h @@ -6,6 +6,16 @@ #define MAX_PAYLOAD_LEN (64 - sizeof(struct openpcd_hdr)) +#define USB_RET_RESPOND (1 << 8) +#define USB_RET_ERR (2 << 8) +#define USB_ERR(x) (USB_RET_RESPOND|USB_RET_ERR|(x & 0xff)) + +enum usbapi_err { + USB_ERR_NONE, + USB_ERR_CMD_UNKNOWN, + USB_ERR_CMD_NOT_IMPL, +}; + typedef int usb_cmd_fn(struct req_ctx *rctx); extern int usb_hdlr_register(usb_cmd_fn *hdlr, u_int8_t class); diff --git a/firmware/src/os/usbcmd_generic.c b/firmware/src/os/usbcmd_generic.c new file mode 100644 index 0000000..9dec14e --- /dev/null +++ b/firmware/src/os/usbcmd_generic.c @@ -0,0 +1,49 @@ +/* Some generel USB API commands, common between OpenPCD and OpenPICC + * (C) 2006 by Harald Welte + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int gen_usb_rx(struct req_ctx *rctx) +{ + struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data; + struct openpcd_compile_version *ver = + (struct openpcd_compile_version *) poh->data; + int ret = 1; + + rctx->tot_len = sizeof(*poh); + + switch (poh->cmd) { + case OPENPCD_CMD_GET_VERSION: + DEBUGP("GET_VERSION "); + memcpy(ver, &opcd_version, sizeof(*ver)); + rctx->tot_len += sizeof(*ver); + poh->flags |= OPENPCD_FLAG_RESPOND; + break; + case OPENPCD_CMD_SET_LED: + DEBUGP("SET LED(%u,%u) ", poh->reg, poh->val); + led_switch(poh->reg, poh->val); + break; + default: + DEBUGP("UNKNOWN "); + return USB_ERR(USB_ERR_CMD_UNKNOWN); + break; + } + + if (poh->flags & OPENPCD_FLAG_RESPOND) + return USB_RET_RESPOND; + return 0; +} + +void usbcmd_gen_init(void) +{ + usb_hdlr_register(&gen_usb_rx, OPENPCD_CMD_CLS_GENERIC); +} + diff --git a/firmware/src/os/usbcmd_generic.h b/firmware/src/os/usbcmd_generic.h new file mode 100644 index 0000000..0a7b8b7 --- /dev/null +++ b/firmware/src/os/usbcmd_generic.h @@ -0,0 +1,4 @@ +#ifndef _USBAPI_GENERIC_H +#define _USBAPI_GENERIC_H +extern void usbcmd_gen_init(void); +#endif diff --git a/firmware/src/pcd/rc632.c b/firmware/src/pcd/rc632.c index f0375c6..3713d94 100644 --- a/firmware/src/pcd/rc632.c +++ b/firmware/src/pcd/rc632.c @@ -340,7 +340,7 @@ static void rc632_irq(void) DEBUGP("TxComplete "); - irq_rctx = req_ctx_find_get(RCTX_STATE_FREE, + irq_rctx = req_ctx_find_get(0, RCTX_STATE_FREE, RCTX_STATE_RC632IRQ_BUSY); if (!irq_rctx) { DEBUGPCRF("NO RCTX!\n"); @@ -349,7 +349,7 @@ static void rc632_irq(void) return; } - irq_opcdh = (struct openpcd_hdr *) &irq_rctx->tx.data[0]; + irq_opcdh = (struct openpcd_hdr *) irq_rctx->data; /* initialize static part of openpcd_hdr for USB IRQ reporting */ irq_opcdh->cmd = OPENPCD_CMD_IRQ; @@ -400,58 +400,56 @@ void rc632_reset(void) static int rc632_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]; - u_int16_t len = rctx->rx.tot_len-sizeof(*poh); + struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data; + u_int16_t len = rctx->tot_len-sizeof(*poh); switch (poh->cmd) { case OPENPCD_CMD_READ_REG: - rc632_reg_read(RAH, poh->reg, &pih->val); - DEBUGP("READ REG(0x%02x)=0x%02x ", poh->reg, pih->val); - goto respond; + rc632_reg_read(RAH, poh->reg, &poh->val); + DEBUGP("READ REG(0x%02x)=0x%02x ", poh->reg, poh->val); + /* register read always has to provoke a response */ + poh->flags &= OPENPCD_FLAG_RESPOND; break; case OPENPCD_CMD_READ_FIFO: + /* FIFO read always has to provoke a response */ + poh->flags &= OPENPCD_FLAG_RESPOND; { u_int16_t req_len = poh->val, remain_len = req_len, pih_len; if (req_len > MAX_PAYLOAD_LEN) { pih_len = MAX_PAYLOAD_LEN; remain_len -= pih_len; - rc632_fifo_read(RAH, pih_len, pih->data); - rctx->tx.tot_len += pih_len; + rc632_fifo_read(RAH, pih_len, poh->data); + rctx->tot_len += pih_len; DEBUGP("READ FIFO(len=%u)=%s ", req_len, - hexdump(pih->data, pih_len)); + hexdump(poh->data, pih_len)); req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); - udp_refill_ep(2, rctx); + udp_refill_ep(2); /* get and initialize second rctx */ - rctx = req_ctx_find_get(RCTX_STATE_FREE, + rctx = req_ctx_find_get(0, RCTX_STATE_FREE, RCTX_STATE_MAIN_PROCESSING); if (!rctx) { DEBUGPCRF("FATAL_NO_RCTX!!!\n"); break; } - poh = (struct openpcd_hdr *) &rctx->rx.data[0]; - pih = (struct openpcd_hdr *) &rctx->tx.data[0]; - memcpy(pih, poh, sizeof(*poh)); - rctx->tx.tot_len = sizeof(*poh); + poh = (struct openpcd_hdr *) rctx->data; + rctx->tot_len = sizeof(*poh); pih_len = remain_len; - rc632_fifo_read(RAH, pih->val, pih->data); - rctx->tx.tot_len += pih_len; + rc632_fifo_read(RAH, pih_len, poh->data); + rctx->tot_len += pih_len; DEBUGP("READ FIFO(len=%u)=%s ", pih_len, - hexdump(pih->data, pih_len)); + hexdump(poh->data, pih_len)); /* don't set state of second rctx, main function * body will do this after switch statement */ } else { - pih->val = poh->val; - rc632_fifo_read(RAH, poh->val, pih->data); - rctx->tx.tot_len += pih_len; + rc632_fifo_read(RAH, req_len, poh->data); + rctx->tot_len += pih_len; DEBUGP("READ FIFO(len=%u)=%s ", poh->val, - hexdump(pih->data, poh->val)); + hexdump(poh->data, poh->val)); } - goto respond; - break; } + break; case OPENPCD_CMD_WRITE_REG: DEBUGP("WRITE_REG(0x%02x, 0x%02x) ", poh->reg, poh->val); rc632_reg_write(RAH, poh->reg, poh->val); @@ -463,46 +461,33 @@ static int rc632_usb_in(struct req_ctx *rctx) break; case OPENPCD_CMD_READ_VFIFO: DEBUGP("READ VFIFO "); - DEBUGP("NOT IMPLEMENTED YET "); - goto respond; + goto not_impl; break; case OPENPCD_CMD_WRITE_VFIFO: DEBUGP("WRITE VFIFO "); - DEBUGP("NOT IMPLEMENTED YET "); + goto not_impl; break; case OPENPCD_CMD_REG_BITS_CLEAR: DEBUGP("CLEAR BITS "); - pih->val = rc632_clear_bits(RAH, poh->reg, poh->val); + poh->val = rc632_clear_bits(RAH, poh->reg, poh->val); break; case OPENPCD_CMD_REG_BITS_SET: DEBUGP("SET BITS "); - pih->val = rc632_set_bits(RAH, poh->reg, poh->val); + poh->val = rc632_set_bits(RAH, poh->reg, poh->val); break; case OPENPCD_CMD_DUMP_REGS: DEBUGP("DUMP REGS "); - DEBUGP("NOT IMPLEMENTED YET "); - goto respond; + goto not_impl; break; default: DEBUGP("UNKNOWN "); return -EINVAL; } -#ifdef ALWAYS_RESPOND - goto respond; -#endif - - req_ctx_put(rctx); - DEBUGPCR(""); - return 0; - -respond: - req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); - /* FIXME: we could try to send this immediately */ - udp_refill_ep(2, rctx); - DEBUGPCR(""); - - return 1; + return (poh->flags & OPENPCD_FLAG_RESPOND) ? USB_RET_RESPOND : 0; +not_impl: + DEBUGP("NOT IMPLEMENTED YET "); + return USB_ERR(USB_ERR_CMD_NOT_IMPL); } void rc632_init(void) diff --git a/firmware/src/picc/adc.c b/firmware/src/picc/adc.c index c78f89d..f350a49 100644 --- a/firmware/src/picc/adc.c +++ b/firmware/src/picc/adc.c @@ -74,7 +74,7 @@ static void adc_irq(void) if (sr & AT91C_ADC_ENDRX) { /* rctx full, get rid of it */ DEBUGADC("sending rctx (val=%s) ", - hexdump(rctx->tx.data[4], 2)); + hexdump(rctx->data[4], 2)); req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); adc_state.state = ADC_NONE; @@ -115,8 +115,7 @@ u_int16_T adc_read_pll_dem(void) static int adc_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]; + struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->data[0]; switch (poh->cmd) { case OPENPCD_CMD_ADC_READ: @@ -129,9 +128,8 @@ static int adc_usb_in(struct req_ctx *rctx) adc_state.state = ADC_READ_CONTINUOUS_USB; adc_state.rctx = rctx; - memcpy(pih, poh, sizeof(*pih)); - rctx->tx.tot_len = sizeof(*pih) + poh->val * 2; - AT91F_PDC_SetRx(AT91C_BASE_PDC_ADC, rctx->rx.data, poh->val); + rctx->tot_len = sizeof(*poh) + poh->val * 2; + AT91F_PDC_SetRx(AT91C_BASE_PDC_ADC, rctx->data, poh->val); AT91F_PDC_EnableRx(AT91C_BASE_PDC_ADC); AT91F_ADC_EnableChannel(AT91C_BASE_ADC, OPENPICC_ADC_CH_FIELDSTR); AT91F_ADC_EnableIt(AT91C_BASE_ADC, AT91C_ADC_ENDRX | diff --git a/firmware/src/picc/decoder.c b/firmware/src/picc/decoder.c index ab77250..bdd910e 100644 --- a/firmware/src/picc/decoder.c +++ b/firmware/src/picc/decoder.c @@ -17,8 +17,6 @@ * */ - - #include #include #include diff --git a/firmware/src/picc/main_openpicc.c b/firmware/src/picc/main_openpicc.c index c8d2fd0..df754de 100644 --- a/firmware/src/picc/main_openpicc.c +++ b/firmware/src/picc/main_openpicc.c @@ -47,6 +47,7 @@ static u_int8_t load_mod = 0; void _init_func(void) { + /* low-level hardware initialization */ pio_irq_init(); pll_init(); poti_init(); @@ -57,6 +58,10 @@ void _init_func(void) adc_init(); ssc_rx_init(); // ssc_tx_init(); + + /* high-level protocol */ + decoder_init(); + opicc_usbapi_init(); AT91F_PIO_CfgInput(AT91C_BASE_PIOA, OPENPICC_PIO_BOOTLDR); } diff --git a/firmware/src/picc/openpicc.c b/firmware/src/picc/openpicc.c new file mode 100644 index 0000000..7b2b5f2 --- /dev/null +++ b/firmware/src/picc/openpicc.c @@ -0,0 +1,82 @@ +/* Main state machine and register implementation for OpenPICC + * (C) 2006 by Harald Welte */ + +#include +#include +#include +#include +#include +#include + +#include "opicc_reg.h" + +/******************************************************************** + * OpenPICC Register set + ********************************************************************/ + +/* Our registers, including their power-up default values */ +static u_int16_t opicc_regs[_OPICC_NUM_REGS] = { + [OPICC_REG_14443A_UIDLEN] = 4, + [OPICC_REG_14443A_FDT0] = 1236, + [OPICC_REG_14443A_FDT1] = 1172, + [OPICC_REG_14443A_STATE] = ISO14443A_ST_POWEROFF, + [OPICC_REG_RX_CLK_DIV] = 32, + [OPICC_REG_RX_CLK_PHASE] = 0, + [OPICC_REG_RX_CONTROL] = 0, + [OPICC_REG_TX_CLK_DIV] = 16, + [OPICC_REG_TX_CONTROL] = 0, + [OPICC_REG_RX_COMP_LEVEL] = 0, +}; + +u_int16_t opicc_reg_read(enum opicc_reg reg) +{ + if (reg < _OPICC_NUM_REGS) + return opicc_regs[reg]; + return 0; +} + +void opicc_reg_write(enum opicc_reg reg, u_int16_t val) +{ + if (reg < _OPICC_NUM_REGS) + opicc_regs[reg] = val; + return; +} + +/******************************************************************** + * OpenPICC USB Commandset (access to register set, ...) + ********************************************************************/ + +static int opicc_reg_usb_in(struct req_ctx *rctx) +{ + struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->data[0]; + u_int16_t *val16 = (u_int16_t *) poh->data; + + poh->val = 0; + rctx->tot_len = sizeof(*poh); + + switch (poh->cmd) { + case OPENPCD_CMD_PICC_REG_READ: + *val16 = opicc_reg_read(poh->reg); + rctx->tot_len += sizeof(u_int16_t); + poh->flags |= OPENPCD_FLAG_RESPOND; + break; + case OPENPCD_CMD_PICC_REG_WRITE: + if (rctx->tot_len < sizeof(*poh) + sizeof(u_int16_t)) { + poh->flags = OPENPCD_FLAG_ERROR; + } + opicc_reg_write(poh->reg, *val16); + break; + default: + return USB_ERR(USB_ERR_CMD_UNKNOWN); + } + + if (poh->flags & OPENPCD_FLAG_RESPOND) + return USB_RET_RESPOND; + + return 0; +} + +void opicc_usbapi_init(void) +{ + usb_hdlr_register(&opicc_reg_usb_in, OPENPCD_CMD_CLS_PICC); +} diff --git a/firmware/src/picc/opicc_reg.h b/firmware/src/picc/opicc_reg.h new file mode 100644 index 0000000..e77d157 --- /dev/null +++ b/firmware/src/picc/opicc_reg.h @@ -0,0 +1,18 @@ +#ifndef _OPCD_REG_H +#define _OPCD_REG_H + +#include +#include + +#ifdef DEBUG +u_int16_t opicc_reg_read(enum opicc_reg reg); +void opicc_reg_write(enum opicc_reg reg, u_int16_t val); +#else +u_int16_t opicc_regs[_OPICC_NUM_REGS]; +#define opicc_reg_read(x) (opicc_regs[x]) +#define opicc_reg_Write(x, y) (opicc_regs[x] = y) +#endif + +void opicc_usbapi_init(void); + +#endif diff --git a/firmware/src/picc/pll.c b/firmware/src/picc/pll.c index f98d171..7eb49a4 100644 --- a/firmware/src/picc/pll.c +++ b/firmware/src/picc/pll.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "../openpcd.h" void pll_inhibit(int inhibit) diff --git a/firmware/src/picc/ssc_picc.c b/firmware/src/picc/ssc_picc.c index ea48de5..d4db71a 100644 --- a/firmware/src/picc/ssc_picc.c +++ b/firmware/src/picc/ssc_picc.c @@ -166,8 +166,8 @@ static struct openpcd_hdr opcd_ssc_hdr = { static inline void init_opcdhdr(struct req_ctx *rctx) { - memcpy(&rctx->tx.data[0], &opcd_ssc_hdr, sizeof(opcd_ssc_hdr)); - rctx->tx.tot_len = MAX_HDRSIZE + MAX_REQSIZE -1; + memcpy(rctx->data, &opcd_ssc_hdr, sizeof(opcd_ssc_hdr)); + rctx->tot_len = MAX_HDRSIZE + MAX_REQSIZE -1; } #ifdef DEBUG_SSC_REFILL @@ -191,7 +191,7 @@ static int8_t ssc_rx_refill(void) #if 1 struct req_ctx *rctx; - rctx = req_ctx_find_get(RCTX_STATE_FREE, RCTX_STATE_SSC_RX_BUSY); + rctx = req_ctx_find_get(1, RCTX_STATE_FREE, RCTX_STATE_SSC_RX_BUSY); if (!rctx) { DEBUGPCRF("no rctx for refill!"); return -1; @@ -200,12 +200,12 @@ static int8_t ssc_rx_refill(void) if (AT91F_PDC_IsRxEmpty(rx_pdc)) { DEBUGR("filling primary SSC RX dma ctx"); - AT91F_PDC_SetRx(rx_pdc, &rctx->rx.data[MAX_HDRSIZE], - (sizeof(rctx->rx.data)-MAX_HDRSIZE)>>2); + AT91F_PDC_SetRx(rx_pdc, &rctx->data[MAX_HDRSIZE], + (rctx->size-MAX_HDRSIZE)>>2); ssc_state.rx_ctx[0] = rctx; /* If primary is empty, secondary must be empty, too */ - rctx = req_ctx_find_get(RCTX_STATE_FREE, + rctx = req_ctx_find_get(1, RCTX_STATE_FREE, RCTX_STATE_SSC_RX_BUSY); if (!rctx) { DEBUGPCRF("no rctx for secondary refill!"); @@ -216,8 +216,8 @@ static int8_t ssc_rx_refill(void) if (AT91F_PDC_IsNextRxEmpty(rx_pdc)) { DEBUGR("filling secondary SSC RX dma ctx"); - AT91F_PDC_SetNextRx(rx_pdc, &rctx->rx.data[MAX_HDRSIZE], - (sizeof(rctx->rx.data)-MAX_HDRSIZE)>2); + AT91F_PDC_SetNextRx(rx_pdc, &rctx->data[MAX_HDRSIZE], + (rctx->size-MAX_HDRSIZE)>2); ssc_state.rx_ctx[1] = rctx; return 2; } else { @@ -331,8 +331,7 @@ void ssc_tx_init(void) static int ssc_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]; + struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data; switch (poh->cmd) { case OPENPCD_CMD_SSC_READ: @@ -366,7 +365,7 @@ void ssc_rx_init(void) /* Reset */ //ssc->SSC_CR = AT91C_SSC_SWRST; - /* don't divide clock */ + /* don't divide clock inside SSC, we do that in tc_cdiv */ ssc->SSC_CMR = 0; ssc->SSC_RCMR = AT91C_SSC_CKS_RK | AT91C_SSC_CKO_NONE | -- cgit v1.2.3