From 520784c7ba6a8325e413a293ab11840d982ba87d Mon Sep 17 00:00:00 2001 From: "(no author)" <(no author)@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> Date: Sat, 9 Sep 2006 01:08:38 +0000 Subject: - major reorganization, split source tree in - os: core "operating system" - pcd: PCD (reader) side - picc: PICC (transponder) side - rewrite linker script almost from scratch (for correct DFU operation) git-svn-id: https://svn.openpcd.org:2342/trunk@142 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- openpcd/firmware/Makefile | 27 +- openpcd/firmware/include/librfid/rfid.h | 2 +- .../link/AT91SAM7S256-ROM-dfu-fullimage.ld | 145 +- openpcd/firmware/src/dbgu.c | 324 ----- openpcd/firmware/src/dbgu.h | 43 - openpcd/firmware/src/dfu.c | 678 --------- openpcd/firmware/src/dfu.h | 80 -- openpcd/firmware/src/fifo.c | 108 -- openpcd/firmware/src/fifo.h | 28 - openpcd/firmware/src/flash.c | 45 - openpcd/firmware/src/led.c | 84 -- openpcd/firmware/src/led.h | 9 - openpcd/firmware/src/main.c | 35 - openpcd/firmware/src/main.h | 8 - openpcd/firmware/src/main_analog.c | 86 -- openpcd/firmware/src/main_dumbreader.c | 33 - openpcd/firmware/src/main_pwm.c | 250 ---- openpcd/firmware/src/main_reqa.c | 255 ---- openpcd/firmware/src/openpcd.h | 43 - openpcd/firmware/src/os/dbgu.c | 325 +++++ openpcd/firmware/src/os/dbgu.h | 43 + openpcd/firmware/src/os/dfu.c | 679 +++++++++ openpcd/firmware/src/os/dfu.h | 80 ++ openpcd/firmware/src/os/fifo.c | 108 ++ openpcd/firmware/src/os/fifo.h | 28 + openpcd/firmware/src/os/flash.c | 45 + openpcd/firmware/src/os/led.c | 85 ++ openpcd/firmware/src/os/led.h | 9 + openpcd/firmware/src/os/main.c | 35 + openpcd/firmware/src/os/main.h | 8 + openpcd/firmware/src/os/pcd_enumerate.c | 610 ++++++++ openpcd/firmware/src/os/pcd_enumerate.h | 56 + openpcd/firmware/src/os/pio_irq.c | 66 + openpcd/firmware/src/os/pio_irq.h | 15 + openpcd/firmware/src/os/req_ctx.c | 50 + openpcd/firmware/src/os/req_ctx.h | 47 + openpcd/firmware/src/os/syscalls.c | 169 +++ openpcd/firmware/src/os/trigger.c | 17 + openpcd/firmware/src/os/trigger.h | 7 + openpcd/firmware/src/os/usb_benchmark.c | 57 + openpcd/firmware/src/os/usb_handler.c | 87 ++ openpcd/firmware/src/os/usb_handler.h | 15 + openpcd/firmware/src/pcd/main_analog.c | 86 ++ openpcd/firmware/src/pcd/main_dumbreader.c | 33 + openpcd/firmware/src/pcd/main_pwm.c | 250 ++++ openpcd/firmware/src/pcd/main_reqa.c | 266 ++++ openpcd/firmware/src/pcd/pwm.c | 165 +++ openpcd/firmware/src/pcd/pwm.h | 11 + openpcd/firmware/src/pcd/rc632.c | 624 +++++++++ openpcd/firmware/src/pcd/rc632.h | 31 + openpcd/firmware/src/pcd/rc632_highlevel.c | 1465 ++++++++++++++++++++ openpcd/firmware/src/pcd/rfid_layer2_iso14443a.c | 319 +++++ openpcd/firmware/src/pcd_enumerate.c | 609 -------- openpcd/firmware/src/pcd_enumerate.h | 56 - openpcd/firmware/src/picc/load_modulation.c | 31 + openpcd/firmware/src/picc/load_modulation.h | 7 + openpcd/firmware/src/picc/piccsim.h | 2 +- openpcd/firmware/src/picc/tc.c | 123 ++ openpcd/firmware/src/picc/tc.h | 28 + openpcd/firmware/src/pio_irq.c | 66 - openpcd/firmware/src/pio_irq.h | 15 - openpcd/firmware/src/pwm.c | 164 --- openpcd/firmware/src/pwm.h | 11 - openpcd/firmware/src/rc632.c | 623 --------- openpcd/firmware/src/rc632.h | 31 - openpcd/firmware/src/rc632_highlevel.c | 1465 -------------------- openpcd/firmware/src/req_ctx.c | 49 - openpcd/firmware/src/rfid_layer2_iso14443a.c | 319 ----- openpcd/firmware/src/start/Cstartup.S | 56 +- openpcd/firmware/src/syscalls.c | 169 --- openpcd/firmware/src/tc.c | 122 -- openpcd/firmware/src/tc.h | 28 - openpcd/firmware/src/trigger.c | 17 - openpcd/firmware/src/trigger.h | 7 - openpcd/firmware/src/usb_benchmark.c | 56 - openpcd/firmware/src/usb_handler.c | 86 -- openpcd/firmware/src/usb_handler.h | 15 - 77 files changed, 6226 insertions(+), 6103 deletions(-) delete mode 100644 openpcd/firmware/src/dbgu.c delete mode 100644 openpcd/firmware/src/dbgu.h delete mode 100644 openpcd/firmware/src/dfu.c delete mode 100644 openpcd/firmware/src/dfu.h delete mode 100644 openpcd/firmware/src/fifo.c delete mode 100644 openpcd/firmware/src/fifo.h delete mode 100644 openpcd/firmware/src/flash.c delete mode 100644 openpcd/firmware/src/led.c delete mode 100644 openpcd/firmware/src/led.h delete mode 100644 openpcd/firmware/src/main.c delete mode 100644 openpcd/firmware/src/main.h delete mode 100644 openpcd/firmware/src/main_analog.c delete mode 100644 openpcd/firmware/src/main_dumbreader.c delete mode 100644 openpcd/firmware/src/main_pwm.c delete mode 100644 openpcd/firmware/src/main_reqa.c create mode 100644 openpcd/firmware/src/os/dbgu.c create mode 100644 openpcd/firmware/src/os/dbgu.h create mode 100644 openpcd/firmware/src/os/dfu.c create mode 100644 openpcd/firmware/src/os/dfu.h create mode 100644 openpcd/firmware/src/os/fifo.c create mode 100644 openpcd/firmware/src/os/fifo.h create mode 100644 openpcd/firmware/src/os/flash.c create mode 100644 openpcd/firmware/src/os/led.c create mode 100644 openpcd/firmware/src/os/led.h create mode 100644 openpcd/firmware/src/os/main.c create mode 100644 openpcd/firmware/src/os/main.h create mode 100644 openpcd/firmware/src/os/pcd_enumerate.c create mode 100644 openpcd/firmware/src/os/pcd_enumerate.h create mode 100644 openpcd/firmware/src/os/pio_irq.c create mode 100644 openpcd/firmware/src/os/pio_irq.h create mode 100644 openpcd/firmware/src/os/req_ctx.c create mode 100644 openpcd/firmware/src/os/req_ctx.h create mode 100644 openpcd/firmware/src/os/syscalls.c create mode 100644 openpcd/firmware/src/os/trigger.c create mode 100644 openpcd/firmware/src/os/trigger.h create mode 100644 openpcd/firmware/src/os/usb_benchmark.c create mode 100644 openpcd/firmware/src/os/usb_handler.c create mode 100644 openpcd/firmware/src/os/usb_handler.h create mode 100644 openpcd/firmware/src/pcd/main_analog.c create mode 100644 openpcd/firmware/src/pcd/main_dumbreader.c create mode 100644 openpcd/firmware/src/pcd/main_pwm.c create mode 100644 openpcd/firmware/src/pcd/main_reqa.c create mode 100644 openpcd/firmware/src/pcd/pwm.c create mode 100644 openpcd/firmware/src/pcd/pwm.h create mode 100644 openpcd/firmware/src/pcd/rc632.c create mode 100644 openpcd/firmware/src/pcd/rc632.h create mode 100644 openpcd/firmware/src/pcd/rc632_highlevel.c create mode 100644 openpcd/firmware/src/pcd/rfid_layer2_iso14443a.c delete mode 100644 openpcd/firmware/src/pcd_enumerate.c delete mode 100644 openpcd/firmware/src/pcd_enumerate.h create mode 100644 openpcd/firmware/src/picc/load_modulation.c create mode 100644 openpcd/firmware/src/picc/load_modulation.h create mode 100644 openpcd/firmware/src/picc/tc.c create mode 100644 openpcd/firmware/src/picc/tc.h delete mode 100644 openpcd/firmware/src/pio_irq.c delete mode 100644 openpcd/firmware/src/pio_irq.h delete mode 100644 openpcd/firmware/src/pwm.c delete mode 100644 openpcd/firmware/src/pwm.h delete mode 100644 openpcd/firmware/src/rc632.c delete mode 100644 openpcd/firmware/src/rc632.h delete mode 100644 openpcd/firmware/src/rc632_highlevel.c delete mode 100644 openpcd/firmware/src/req_ctx.c delete mode 100644 openpcd/firmware/src/rfid_layer2_iso14443a.c delete mode 100644 openpcd/firmware/src/syscalls.c delete mode 100644 openpcd/firmware/src/tc.c delete mode 100644 openpcd/firmware/src/tc.h delete mode 100644 openpcd/firmware/src/trigger.c delete mode 100644 openpcd/firmware/src/trigger.h delete mode 100644 openpcd/firmware/src/usb_benchmark.c delete mode 100644 openpcd/firmware/src/usb_handler.c delete mode 100644 openpcd/firmware/src/usb_handler.h diff --git a/openpcd/firmware/Makefile b/openpcd/firmware/Makefile index 2999093..4d8f2a6 100644 --- a/openpcd/firmware/Makefile +++ b/openpcd/firmware/Makefile @@ -75,17 +75,32 @@ SRC = # List C source files here which must be compiled in ARM-Mode. # use file-extension c for "c-only"-files + +# First, build library ... SRCARM = lib/lib_AT91SAM7.c -SRCARM += src/pcd_enumerate.c src/fifo.c src/dbgu.c \ - src/led.c src/rc632.c src/rc632_highlevel.c src/req_ctx.c \ - src/trigger.c src/main.c src/syscalls.c src/pwm.c src/tc.c \ - src/usb_handler.c src/ssc.c src/usb_benchmark.c src/dfu.c \ - src/$(TARGET).c src/start/Cstartup_SAM7.c ifdef DEBUG SRCARM += lib/vsprintf.c lib/ctype.c lib/string.c endif -SRCARM += src/rfid_layer2_iso14443a.c +# then, OS ... +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/dfu.c src/start/Cstartup_SAM7.c + +ifdef PCD +# PCD support code +SRCARM += src/pcd/rc632.c src/pcd/rc632_highlevel.c \ + src/pcd/pwm.c src/pcd/rfid_layer2_iso14443a.c +# finally, the actual main application +SRCARM += src/pcd/$(TARGET).c +else +# PICC support code +SRCARM += src/picc/tc.c src/picc/ssc.c +# finally, the actual main application +SRCARM += src/picc/$(TARGET).c +endif + # List C++ source files here. # use file-extension cpp for C++-files (use extension .cpp) diff --git a/openpcd/firmware/include/librfid/rfid.h b/openpcd/firmware/include/librfid/rfid.h index eb96378..308f46e 100644 --- a/openpcd/firmware/include/librfid/rfid.h +++ b/openpcd/firmware/include/librfid/rfid.h @@ -1,7 +1,7 @@ #ifndef _RFID_H #define _RFID_H -#include "dbgu.h" +#include #define rfid_hexdump hexdump diff --git a/openpcd/firmware/link/AT91SAM7S256-ROM-dfu-fullimage.ld b/openpcd/firmware/link/AT91SAM7S256-ROM-dfu-fullimage.ld index 9bb5163..3932e64 100644 --- a/openpcd/firmware/link/AT91SAM7S256-ROM-dfu-fullimage.ld +++ b/openpcd/firmware/link/AT91SAM7S256-ROM-dfu-fullimage.ld @@ -41,82 +41,79 @@ MEMORY SECTIONS { - . = 0x00000000; - /* first section is .text which is used for code */ - .text : { - src/start/Cstartup*.o (.text) - *(.dfu.func) - *(.dfu.struct) - } >FLASH - _etext_dfu = . ; - - .data : AT (_etext_dfu) { - _data_dfu = . ; - KEEP(*(.vectram)) - src/dfu.o (.data) + . = 0x00000000; + /* first section is .text which is used for code */ + .dfu.text 0x00100000: AT ( 0x00000000 ) { + src/start/Cstartup*.o (.text) + *(.dfu.func) + *(.dfu.struct) + . = ALIGN(4); + } >FLASH + + _etext_dfu = . ; + + .dfu.data 0x00200000: AT ( ADDR(.dfu.text) + SIZEOF(.dfu.text) - ADDR(.dfu.text) ) { + _data_dfu = . ; + *(.vectram) + src/os/dfu.o (.data) + . = ALIGN(4); + } >DATA + _edata_dfu = . ; - } >DATA - .text : { - . = 0x00002000; - *(.dfu.functab) - - . = 0x00002100; - *(.text) /* remaining code */ - - *(.glue_7t) *(.glue_7) - - } >FLASH - - . = ALIGN(4); - - /* .rodata section which is used for read-only data (constants) */ - - .rodata : - { - *(.rodata) - } >FLASH - - . = ALIGN(4); - - _etext = . ; - PROVIDE (etext = .); - - /* .data section which is used for initialized data */ - - .data : AT (_etext) - { - _data = . ; - *(.data) - SORT(CONSTRUCTORS) - . = ALIGN(4); - *(.fastrun) - } >DATA - . = ALIGN(4); - - _edata = . ; - PROVIDE (edata = .); - - /* .bss section which is used for uninitialized data */ - - .bss : - { - __bss_start = . ; - __bss_start__ = . ; - *(.bss) - *(COMMON) - } - . = ALIGN(4); - __bss_end__ = . ; - __bss_end__ = . ; - _end = .; - . = ALIGN(4); - .int_data : - { - *(.internal_ram_top) - }> STACK - - PROVIDE (end = .); + .dfu.functab 0x00102100: AT ( ADDR(.dfu.functab) - ADDR(.dfu.text) ) { + *(.dfu.functab) + . = ALIGN(4); + } >FLASH + + .text 0x00102200: AT ( ADDR(.text) - ADDR(.dfu.text) ) { + *(.text) /* remaining code */ + *(.glue_7t) *(.glue_7) + . = ALIGN(4); + } >FLASH + + + /* .rodata section which is used for read-only data (constants) */ + .rodata : AT ( ADDR(.text) + SIZEOF(.text) - ADDR(.dfu.text) ) { + *(.rodata*) + . = ALIGN(4); + } >FLASH + + _etext = . ; + PROVIDE (etext = .); + + /* .data section which is used for initialized data */ + .data : AT ( ADDR(.rodata) + SIZEOF(.rodata) - ADDR(.dfu.text) ) { + _data = . ; + *(.data) + SORT(CONSTRUCTORS) + . = ALIGN(4); + *(.fastrun) + . = ALIGN(4); + } >DATA + + _edata = . ; + PROVIDE (edata = .); + + /* .bss section which is used for uninitialized data */ + .bss : { + __bss_start = . ; + __bss_start__ = . ; + *(.bss) + *(COMMON) + } >DATA + + . = ALIGN(4); + __bss_end__ = . ; + __bss_end__ = . ; + _end = . ; + + . = ALIGN(4); + .int_data : { + *(.internal_ram_top) + } >STACK + + PROVIDE (end = .); /* Stabs debugging sections. */ .stab 0 : { *(.stab) } diff --git a/openpcd/firmware/src/dbgu.c b/openpcd/firmware/src/dbgu.c deleted file mode 100644 index 2e8cb8b..0000000 --- a/openpcd/firmware/src/dbgu.c +++ /dev/null @@ -1,324 +0,0 @@ -/*---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - ROUSSET - - *---------------------------------------------------------------------------- - * The software is delivered "AS IS" without warranty or condition of any - * kind, either express, implied or statutory. This includes without - * limitation any warranty or condition with respect to merchantability or - * fitness for any particular purpose, or against the infringements of - * intellectual property rights of others. - *---------------------------------------------------------------------------- - * File Name : Debug.c - * Object : Debug menu - * Creation : JPP 14/Sep/2004 - * 1.1 29/Aug/05 JPP : Update AIC definion - *----------------------------------------------------------------------------*/ - -// Include Standard files -#include -#include "dbgu.h" -#include "rc632.h" -#include "openpcd.h" -#include "led.h" -#include "main.h" -#include - -#define USART_SYS_LEVEL 4 -/*---------------------------- Global Variable ------------------------------*/ -//*--------------------------1-------------------------------------------------- -//* \fn AT91F_DBGU_Printk -//* \brief This function is used to send a string through the DBGU channel -//*---------------------------------------------------------------------------- -void AT91F_DBGU_Ready(void) -{ - while (!(AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXEMPTY)) ; -} - -//*---------------------------------------------------------------------------- -//* Function Name : Send_reset -//* Object : Acknoledeg AIC and send reset -//*---------------------------------------------------------------------------- -static void Send_reset(void) -{ - void (*pfct) (void) = (void (*)(void))0x00000000; - - // Acknoledge the interrupt - // Mark the End of Interrupt on the AIC - AT91C_BASE_AIC->AIC_EOICR = 0; - AT91F_DBGU_Ready(); - // Jump in reset - pfct(); -} - -//*---------------------------------------------------------------------------- -//* Function Name : DBGU_irq_handler -//* Object : C handler interrupt function called by the interrupts -//* assembling routine -//*---------------------------------------------------------------------------- -static void DBGU_irq_handler(void) -{ - static char value; - - AT91F_DBGU_Get(&value); - switch (value) { - case '0': //* info - AT91F_DBGU_Frame("Set Pull up\n\r"); - // Set - AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); - break; - case '1': //* info - AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); - AT91F_DBGU_Printk("Clear Pull up\n\r"); - // Reset Application - Send_reset(); - break; - case '2': - AT91F_DBGU_Printk("Toggling LED 1\n\r"); - led_toggle(1); - break; - case '3': - AT91F_DBGU_Printk("Toggling LED 2\n\r"); - led_toggle(2); - break; - case '4': - AT91F_DBGU_Printk("Testing RC632 : "); - if (rc632_test(RAH) == 0) - AT91F_DBGU_Printk("SUCCESS!\n\r"); - else - AT91F_DBGU_Printk("ERROR!\n\r"); - - break; - case '5': - rc632_reg_read(RAH, RC632_REG_RX_WAIT, &value); - DEBUGPCR("Reading RC632 Reg RxWait: 0x%02xr", value); - - break; - case '6': - DEBUGPCR("Writing RC632 Reg RxWait: 0x55"); - rc632_reg_write(RAH, RC632_REG_RX_WAIT, 0x55); - break; - case '7': - rc632_dump(); - break; - default: - if (_main_dbgu(value) < 0) - AT91F_DBGU_Printk("\n\r"); - break; - } // end switch -} - -void dbgu_rb_init(void); -//*---------------------------------------------------------------------------- -//* \fn AT91F_DBGU_Init -//* \brief This function is used to send a string through the DBGU channel (Very low level debugging) -//*---------------------------------------------------------------------------- -void AT91F_DBGU_Init(void) -{ - dbgu_rb_init(); - - //* Open PIO for DBGU - AT91F_DBGU_CfgPIO(); - //* Enable Transmitter & receivier - ((AT91PS_USART) AT91C_BASE_DBGU)->US_CR = - AT91C_US_RSTTX | AT91C_US_RSTRX; - - //* Configure DBGU - AT91F_US_Configure((AT91PS_USART) AT91C_BASE_DBGU, // DBGU base address - MCK, AT91C_US_ASYNC_MODE, // Mode Register to be programmed - AT91C_DBGU_BAUD, // Baudrate to be programmed - 0); // Timeguard to be programmed - - //* Enable Transmitter & receivier - ((AT91PS_USART) AT91C_BASE_DBGU)->US_CR = AT91C_US_RXEN | AT91C_US_TXEN; - - //* Enable USART IT error and AT91C_US_ENDRX - AT91F_US_EnableIt((AT91PS_USART) AT91C_BASE_DBGU, AT91C_US_RXRDY); - - //* open interrupt - AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS, USART_SYS_LEVEL, - AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, - DBGU_irq_handler); - AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SYS); - - AT91F_DBGU_Printk - ("\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"); -} - -//*---------------------------------------------------------------------------- -//* \fn AT91F_DBGU_Printk -//* \brief This function is used to send a string through the DBGU channel (Very low level debugging) -//*---------------------------------------------------------------------------- -void AT91F_DBGU_Printk(char *buffer) -{ - while (*buffer != '\0') { - while (!AT91F_US_TxReady((AT91PS_USART) AT91C_BASE_DBGU)) ; - AT91F_US_PutChar((AT91PS_USART) AT91C_BASE_DBGU, *buffer++); - } -} - -//*---------------------------------------------------------------------------- -//* \fn AT91F_DBGU_Frame -//* \brief This function is used to send a string through the DBGU channel -//*---------------------------------------------------------------------------- -void AT91F_DBGU_Frame(char *buffer) -{ - unsigned char len; - - for (len = 0; buffer[len] != '\0'; len++) { - } - - AT91F_US_SendFrame((AT91PS_USART) AT91C_BASE_DBGU, - (unsigned char *)buffer, len, 0, 0); - -} - -//*---------------------------------------------------------------------------- -//* \fn AT91F_US_Get -//* \brief Get a Char to USART -//*---------------------------------------------------------------------------- -int AT91F_DBGU_Get(char *val) -{ - if ((AT91F_US_RxReady((AT91PS_USART) AT91C_BASE_DBGU)) == 0) - return (0); - else { - *val = AT91F_US_GetChar((AT91PS_USART) AT91C_BASE_DBGU); - return (-1); - } -} - -// mthomas: function not used in this application. avoid -// linking huge newlib code for sscanf. - -#ifdef DEBUG -#include -#include -#include -const char * -hexdump(const void *data, unsigned int len) -{ - static char string[256]; - unsigned char *d = (unsigned char *) data; - unsigned int i, left; - - string[0] = '\0'; - left = sizeof(string); - for (i = 0; len--; i += 3) { - if (i >= sizeof(string) -4) - break; - snprintf(string+i, 4, " %02x", *d++); - } - return string; -} - -struct dbgu { - char buf[4096]; - char *next_inbyte; - char *next_outbyte; -}; -static struct dbgu dbgu; - -void dbgu_rb_init(void) -{ - memset(dbgu.buf, 0, sizeof(dbgu.buf)); - dbgu.next_inbyte = &dbgu.buf[0]; - dbgu.next_outbyte = &dbgu.buf[0]; -} - -/* pull one char out of debug ring buffer */ -static int dbgu_rb_pull(char *ret) -{ - unsigned long flags; - - local_irq_save(flags); - - if (dbgu.next_outbyte == dbgu.next_inbyte) { - local_irq_restore(flags); - return -1; - } - - *ret = *dbgu.next_outbyte; - - dbgu.next_outbyte++; - if (dbgu.next_outbyte == &dbgu.buf[0]+sizeof(dbgu.buf)) { - //AT91F_DBGU_Printk("WRAP DURING PULL\r\n"); - dbgu.next_outbyte = &dbgu.buf[0]; - } else if (dbgu.next_outbyte > &dbgu.buf[0]+sizeof(dbgu.buf)) { - //AT91F_DBGU_Printk("OUTBYTE > END_OF_BUF!!\r\n"); - dbgu.next_outbyte -= sizeof(dbgu.buf); - } - - local_irq_restore(flags); - - return 0; -} - -static void __rb_flush(void) -{ - char ch; - while (dbgu_rb_pull(&ch) >= 0) { - while (!AT91F_US_TxReady((AT91PS_USART) AT91C_BASE_DBGU)) ; - AT91F_US_PutChar((AT91PS_USART) AT91C_BASE_DBGU, ch); - } -} - -/* flush pending data from debug ring buffer to serial port */ -void dbgu_rb_flush(void) -{ - __rb_flush(); -} - -static void __dbgu_rb_append(char *data, int len) -{ - char *pos = dbgu.next_inbyte; - - dbgu.next_inbyte += len; - if (dbgu.next_inbyte >= &dbgu.buf[0]+sizeof(dbgu.buf)) { - AT91F_DBGU_Printk("WRAP DURING APPEND\r\n"); - dbgu.next_inbyte -= sizeof(dbgu.buf); - } - - memcpy(pos, data, len); -} - -void dbgu_rb_append(char *data, int len) -{ - unsigned long flags; - int bytes_left; - char *data_cur; - - local_irq_save(flags); - - bytes_left = &dbgu.buf[0]+sizeof(dbgu.buf)-dbgu.next_inbyte; - data_cur = data; - - if (len > bytes_left) { - AT91F_DBGU_Printk("LEN > BYTES_LEFT\r\n"); - __rb_flush(); - __dbgu_rb_append(data_cur, bytes_left); - len -= bytes_left; - data_cur += bytes_left; - } - __dbgu_rb_append(data_cur, len); - - local_irq_restore(flags); -} - -static char dbg_buf[256]; -void debugp(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - vsnprintf(dbg_buf, sizeof(dbg_buf)-1, format, ap); - va_end(ap); - - dbg_buf[sizeof(dbg_buf)-1] = '\0'; - //AT91F_DBGU_Frame(dbg_buf); - //AT91F_DBGU_Printk(dbg_buf); - dbgu_rb_append(dbg_buf, strlen(dbg_buf)); -} -#else -void dbgu_rb_flush(void) {} -void dbgu_rb_init(void) {} -#endif diff --git a/openpcd/firmware/src/dbgu.h b/openpcd/firmware/src/dbgu.h deleted file mode 100644 index 8dd34be..0000000 --- a/openpcd/firmware/src/dbgu.h +++ /dev/null @@ -1,43 +0,0 @@ -//*---------------------------------------------------------------------------- -//* ATMEL Microcontroller Software Support - ROUSSET - -//*---------------------------------------------------------------------------- -//* The software is delivered "AS IS" without warranty or condition of any -//* kind, either express, implied or statutory. This includes without -//* limitation any warranty or condition with respect to merchantability or -//* fitness for any particular purpose, or against the infringements of -//* intellectual property rights of others. -//*---------------------------------------------------------------------------- -//* File Name : Debug.h -//* Object : Debug menu -//* Creation : JPP 02/Sep/2004 -//*---------------------------------------------------------------------------- - -#ifndef dbgu_h -#define dbgu_h - -#define AT91C_DBGU_BAUD 115200 - -//#define DEBUGP(x) AT91F_DBGU_Printk(x) - -//* ----------------------- External Function Prototype ----------------------- - -extern const char *hexdump(const void *data, unsigned int len); -void AT91F_DBGU_Init(void); -void AT91F_DBGU_Printk( char *buffer); -void AT91F_DBGU_Frame( char *buffer); -int AT91F_DBGU_Get( char *val); -#ifndef __WinARM__ -void AT91F_DBGU_scanf(char * type,unsigned int * val); -#endif - -#ifdef DEBUG -extern void debugp(const char *format, ...); -#define DEBUGP(x, args ...) debugp(x, ## args) -#else -#define DEBUGP(x, args ...) do {} while(0) -#endif - -#define DEBUGPCR(x, args ...) DEBUGP(x "\r\n", ## args) -#define DEBUGPCRF(x, args ...) DEBUGPCR("%s(%d): " x, __FUNCTION__, __LINE__, ## args) - -#endif /* dbgu_h */ diff --git a/openpcd/firmware/src/dfu.c b/openpcd/firmware/src/dfu.c deleted file mode 100644 index a56e538..0000000 --- a/openpcd/firmware/src/dfu.c +++ /dev/null @@ -1,678 +0,0 @@ -/* USB Device Firmware Update Implementation for OpenPCD - * (C) 2006 by Harald Welte - * - * This ought to be compliant to the USB DFU Spec 1.0 as available from - * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf - * - */ - -#include -#include -#include -#include - -#include "dfu.h" -#include "pcd_enumerate.h" -#include "openpcd.h" - -/* If debug is enabled, we need to access debug functions from flash - * and therefore have to omit flashing */ -#define DEBUG_DFU - -#ifdef DEBUG_DFU -#define DEBUGE DEBUGP -#define DEBUGI DEBUGP -#else -#define DEBUGE(x, args ...) -#define DEBUGI(x, args ...) -#endif - -/* this is only called once before DFU mode, no __dfufunc required */ -void udp_init(void) -{ - /* Set the PLL USB Divider */ - AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1; - - /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock */ - 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 */ - AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); -} - -/* Send Data through the control endpoint */ -static void __dfufunc udp_ep0_send_data(const char *pData, u_int32_t length) -{ - AT91PS_UDP pUdp = AT91C_BASE_UDP; - u_int32_t cpt = 0; - AT91_REG csr; - - DEBUGE("send_data: %u bytes ", length); - - do { - cpt = MIN(length, 8); - length -= cpt; - - while (cpt--) - pUdp->UDP_FDR[0] = *pData++; - - if (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) { - pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP); - while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ; - } - - pUdp->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY; - do { - csr = pUdp->UDP_CSR[0]; - - /* Data IN stage has been stopped by a status OUT */ - if (csr & AT91C_UDP_RX_DATA_BK0) { - pUdp->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0); - DEBUGE("stopped by status out "); - return; - } - } while (!(csr & AT91C_UDP_TXCOMP)); - - } while (length); - - if (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) { - pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP); - while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ; - } -} - -/* Send zero length packet through the control endpoint */ -static void __dfufunc udp_ep0_send_zlp(void) -{ - AT91PS_UDP pUdp = AT91C_BASE_UDP; - pUdp->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY; - while (!(pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP)) ; - pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP); - while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ; -} - -/* Stall the control endpoint */ -static void __dfufunc udp_ep0_send_stall(void) -{ - AT91PS_UDP pUdp = AT91C_BASE_UDP; - pUdp->UDP_CSR[0] |= AT91C_UDP_FORCESTALL; - while (!(pUdp->UDP_CSR[0] & AT91C_UDP_ISOERROR)) ; - pUdp->UDP_CSR[0] &= ~(AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR); - while (pUdp->UDP_CSR[0] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR)) ; -} - - -static u_int8_t status; -static u_int8_t *ptr; -static u_int8_t dfu_state; - -static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len) -{ - volatile u_int32_t *p = (volatile u_int32_t *)ptr; - - DEBUGE("download "); - - if (len > AT91C_IFLASH_PAGE_SIZE) { - /* Too big */ - dfu_state = DFU_STATE_dfuERROR; - status = DFU_STATUS_errADDRESS; - udp_ep0_send_stall(); - return -EINVAL; - } - if (len & 0x3) { - dfu_state = DFU_STATE_dfuERROR; - status = DFU_STATUS_errADDRESS; - udp_ep0_send_stall(); - return -EINVAL; - } - if (len == 0) { - dfu_state = DFU_STATE_dfuMANIFEST_SYNC; - return 0; - } -#if 0 - for (i = 0; i < len/4; i++) - p[i] = -#endif - - /* FIXME: get data packet from FIFO, (erase+)write flash */ -#ifndef DEBUG_DFU - -#endif - - return 0; -} - -static __dfufunc int handle_upload(u_int16_t val, u_int16_t len) -{ - DEBUGE("upload "); - if (len > AT91C_IFLASH_PAGE_SIZE - || ptr > AT91C_IFLASH_SIZE) { - /* Too big */ - dfu_state = DFU_STATE_dfuERROR; - status = DFU_STATUS_errADDRESS; - udp_ep0_send_stall(); - return -EINVAL; - } - - if (ptr + len > AT91C_IFLASH_SIZE) - len = AT91C_IFLASH_SIZE - (u_int32_t) ptr; - - udp_ep0_send_data(ptr, len); - ptr+= len; - - return len; -} - -static __dfufunc void handle_getstatus(void) -{ - struct dfu_status dstat; - - DEBUGE("getstatus "); - - /* send status response */ - dstat.bStatus = status; - dstat.bState = dfu_state; - dstat.iString = 0; - udp_ep0_send_data(&dstat, sizeof(dstat)); -} - -static void __dfufunc handle_getstate(void) -{ - u_int8_t u8 = dfu_state; - DEBUGE("getstate "); - udp_ep0_send_data((char *)&u8, sizeof(u8)); -} - -/* callback function for DFU requests */ -int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req, - u_int16_t val, u_int16_t len) -{ - int rc; - - DEBUGE("old_state = %u ", dfu_state); - - switch (dfu_state) { - case DFU_STATE_appIDLE: - if (req != USB_REQ_DFU_DETACH) - goto send_stall; - dfu_state = DFU_STATE_appDETACH; - goto send_zlp; - break; - case DFU_STATE_appDETACH: - switch (req) { - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(); - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(); - break; - default: - dfu_state = DFU_STATE_appIDLE; - goto send_stall; - break; - } - /* FIXME: implement timer to return to appIDLE */ - break; - case DFU_STATE_dfuIDLE: - switch (req) { - case USB_REQ_DFU_DNLOAD: - if (len == 0) { - dfu_state = DFU_STATE_dfuERROR; - goto send_stall; - } - handle_dnload(val, len); - break; - case USB_REQ_DFU_UPLOAD: - ptr = 0; - dfu_state = DFU_STATE_dfuUPLOAD_IDLE; - handle_upload(val, len); - break; - case USB_REQ_DFU_ABORT: - /* no zlp? */ - goto send_zlp; - break; - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(); - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(); - break; - default: - dfu_state = DFU_STATE_dfuERROR; - goto send_stall; - break; - } - break; - case DFU_STATE_dfuDNLOAD_SYNC: - switch (req) { - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(); - /* FIXME: state transition depending on block completeness */ - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(); - break; - default: - dfu_state = DFU_STATE_dfuERROR; - goto send_stall; - } - break; - case DFU_STATE_dfuDNBUSY: - dfu_state = DFU_STATE_dfuERROR; - goto send_stall; - break; - case DFU_STATE_dfuDNLOAD_IDLE: - switch (req) { - case USB_REQ_DFU_DNLOAD: - if (handle_dnload(val, len)) - /* FIXME: state transition */ - break; - case USB_REQ_DFU_ABORT: - dfu_state = DFU_STATE_dfuIDLE; - goto send_zlp; - break; - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(); - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(); - break; - default: - dfu_state = DFU_STATE_dfuERROR; - goto send_stall; - break; - } - break; - case DFU_STATE_dfuMANIFEST_SYNC: - switch (req) { - case USB_REQ_DFU_GETSTATUS: - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(); - break; - default: - dfu_state = DFU_STATE_dfuERROR; - goto send_stall; - break; - } - break; - case DFU_STATE_dfuMANIFEST: - dfu_state = DFU_STATE_dfuERROR; - goto send_stall; - break; - case DFU_STATE_dfuMANIFEST_WAIT_RST: - /* we should never go here */ - break; - case DFU_STATE_dfuUPLOAD_IDLE: - switch (req) { - case USB_REQ_DFU_UPLOAD: - /* state transition if less data then requested */ - rc = handle_upload(val, len); - if (rc >= 0 && rc < len) - dfu_state = DFU_STATE_dfuIDLE; - break; - case USB_REQ_DFU_ABORT: - dfu_state = DFU_STATE_dfuIDLE; - /* no zlp? */ - goto send_zlp; - break; - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(); - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(); - break; - default: - dfu_state = DFU_STATE_dfuERROR; - goto send_stall; - break; - } - break; - case DFU_STATE_dfuERROR: - switch (req) { - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(); - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(); - break; - case USB_REQ_DFU_CLRSTATUS: - dfu_state = DFU_STATE_dfuIDLE; - /* no zlp? */ - goto send_zlp; - break; - default: - dfu_state = DFU_STATE_dfuERROR; - goto send_stall; - break; - } - break; - } - - DEBUGE("OK new_state = %u\r\n", dfu_state); - return 0; - -send_stall: - udp_ep0_send_stall(); - DEBUGE("STALL new_state = %u\r\n", dfu_state); - return -EINVAL; - -send_zlp: - udp_ep0_send_zlp(); - DEBUGE("ZLP new_state = %u\r\n", dfu_state); - return 0; -} -static u_int8_t cur_config; - -/* USB DFU Device descriptor in DFU mode */ -__dfustruct struct usb_device_descriptor dfu_dev_descriptor = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0100, - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = 8, - .idVendor = OPENPCD_VENDOR_ID, - .idProduct = OPENPCD_PRODUCT_ID, - .bcdDevice = 0x0000, - .iManufacturer = 0x00, - .iProduct = 0x00, - .iSerialNumber = 0x00, - .bNumConfigurations = 0x01, -}; - -/* USB DFU Config descriptor in DFU mode */ -__dfustruct struct _dfu_desc dfu_cfg_descriptor = { - .ucfg = { - .bLength = USB_DT_CONFIG_SIZE, - .bDescriptorType = USB_DT_CONFIG, - .wTotalLength = USB_DT_CONFIG_SIZE + - 2* USB_DT_INTERFACE_SIZE + - USB_DT_DFU_SIZE, - .bNumInterfaces = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = USB_CONFIG_ATT_ONE, - .bMaxPower = 100, - }, - .uif[0] = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0x00, - .bAlternateSetting = 0x00, - .bNumEndpoints = 0x00, - .bInterfaceClass = 0xfe, - .bInterfaceSubClass = 0x01, - .bInterfaceProtocol = 0x02, - .iInterface = 0, - }, - .uif[1] = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0x00, - .bAlternateSetting = 0x01, - .bNumEndpoints = 0x00, - .bInterfaceClass = 0xfe, - .bInterfaceSubClass = 0x01, - .bInterfaceProtocol = 0x02, - .iInterface = 0, - }, - - .func_dfu = DFU_FUNC_DESC, -}; - - -/* minimal USB EP0 handler in DFU mode */ -static __dfufunc void dfu_udp_ep0_handler(void) -{ - AT91PS_UDP pUDP = AT91C_BASE_UDP; - u_int8_t bmRequestType, bRequest; - u_int16_t wValue, wIndex, wLength, wStatus; - u_int32_t csr = pUDP->UDP_CSR[0]; - - DEBUGE("CSR=0x%04x ", csr); - - if (csr & AT91C_UDP_STALLSENT) { - DEBUGE("ACK_STALLSENT "); - pUDP->UDP_CSR[0] = ~AT91C_UDP_STALLSENT; - } - - if (csr & AT91C_UDP_RX_DATA_BK0) { - DEBUGE("ACK_BANK0 "); - pUDP->UDP_CSR[0] &= ~AT91C_UDP_RX_DATA_BK0; - } - - if (!(csr & AT91C_UDP_RXSETUP)) { - DEBUGE("no setup packet "); - return; - } - - DEBUGE("len=%d ", csr >> 16); - if (csr >> 16 == 0) { - DEBUGE("empty packet "); - return; - } - - bmRequestType = pUDP->UDP_FDR[0]; - bRequest = pUDP->UDP_FDR[0]; - wValue = (pUDP->UDP_FDR[0] & 0xFF); - wValue |= (pUDP->UDP_FDR[0] << 8); - wIndex = (pUDP->UDP_FDR[0] & 0xFF); - wIndex |= (pUDP->UDP_FDR[0] << 8); - wLength = (pUDP->UDP_FDR[0] & 0xFF); - wLength |= (pUDP->UDP_FDR[0] << 8); - - DEBUGE("bmRequestType=0x%2x ", bmRequestType); - - if (bmRequestType & 0x80) { - DEBUGE("DATA_IN=1 "); - pUDP->UDP_CSR[0] |= AT91C_UDP_DIR; - while (!(pUDP->UDP_CSR[0] & AT91C_UDP_DIR)) ; - } - pUDP->UDP_CSR[0] &= ~AT91C_UDP_RXSETUP; - while ((pUDP->UDP_CSR[0] & AT91C_UDP_RXSETUP)) ; - - /* Handle supported standard device request Cf Table 9-3 in USB - * speciication Rev 1.1 */ - switch ((bRequest << 8) | bmRequestType) { - case STD_GET_DESCRIPTOR: - DEBUGE("GET_DESCRIPTOR "); - if (wValue == 0x100) { - /* Return Device Descriptor */ - udp_ep0_send_data((const char *) - &dfu_dev_descriptor, - MIN(sizeof(dfu_dev_descriptor), - wLength)); - } else if (wValue == 0x200) { - /* Return Configuration Descriptor */ - udp_ep0_send_data((const char *) - &dfu_cfg_descriptor, - MIN(sizeof(dfu_cfg_descriptor), - wLength)); -#if 0 - } else if (wValue == 0x400) { - /* Return Interface descriptor */ - if (wIndex != 0x01) - udp_ep0_send_stall(); - udp_ep0_send_data((const char *) - &dfu_if_descriptor, - MIN(sizeof(dfu_if_descriptor), - wLength)); -#endif - } else - udp_ep0_send_stall(); - break; - case STD_SET_ADDRESS: - DEBUGE("SET_ADDRESS "); - udp_ep0_send_zlp(); - pUDP->UDP_FADDR = (AT91C_UDP_FEN | wValue); - pUDP->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0; - break; - case STD_SET_CONFIGURATION: - DEBUGE("SET_CONFIG "); - if (wValue) - DEBUGE("VALUE!=0 "); - cur_config = wValue; - udp_ep0_send_zlp(); - pUDP->UDP_GLBSTATE = - (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN; - pUDP->UDP_CSR[1] = - (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : - 0; - pUDP->UDP_CSR[2] = - (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0; - pUDP->UDP_CSR[3] = - (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0; - pUDP->UDP_IER = (AT91C_UDP_EPINT0|AT91C_UDP_EPINT1| - AT91C_UDP_EPINT2|AT91C_UDP_EPINT3); - break; - case STD_GET_CONFIGURATION: - DEBUGE("GET_CONFIG "); - udp_ep0_send_data((char *)&(cur_config), - sizeof(cur_config)); - break; - case STD_GET_STATUS_ZERO: - DEBUGE("GET_STATUS_ZERO "); - wStatus = 0; - udp_ep0_send_data((char *)&wStatus, sizeof(wStatus)); - break; - case STD_GET_STATUS_INTERFACE: - DEBUGE("GET_STATUS_INTERFACE "); - wStatus = 0; - udp_ep0_send_data((char *)&wStatus, sizeof(wStatus)); - break; - case STD_GET_STATUS_ENDPOINT: - DEBUGE("GET_STATUS_ENDPOINT(EPidx=%u) ", wIndex&0x0f); - wStatus = 0; - wIndex &= 0x0F; - if ((pUDP->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex == 0)) { - wStatus = - (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; - udp_ep0_send_data((char *)&wStatus, - sizeof(wStatus)); - } else if ((pUDP->UDP_GLBSTATE & AT91C_UDP_FADDEN) - && (wIndex == 0)) { - wStatus = - (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; - udp_ep0_send_data((char *)&wStatus, - sizeof(wStatus)); - } else - udp_ep0_send_stall(); - break; - case STD_SET_FEATURE_ZERO: - DEBUGE("SET_FEATURE_ZERO "); - udp_ep0_send_stall(); - break; - case STD_SET_FEATURE_INTERFACE: - DEBUGE("SET_FEATURE_INTERFACE "); - udp_ep0_send_zlp(); - break; - case STD_SET_FEATURE_ENDPOINT: - DEBUGE("SET_FEATURE_ENDPOINT "); - udp_ep0_send_stall(); - break; - case STD_CLEAR_FEATURE_ZERO: - DEBUGE("CLEAR_FEATURE_ZERO "); - udp_ep0_send_stall(); - break; - case STD_CLEAR_FEATURE_INTERFACE: - DEBUGE("CLEAR_FEATURE_INTERFACE "); - udp_ep0_send_zlp(); - break; - case STD_CLEAR_FEATURE_ENDPOINT: - DEBUGE("CLEAR_FEATURE_ENDPOINT(EPidx=%u) ", wIndex & 0x0f); - udp_ep0_send_stall(); - break; - case STD_SET_INTERFACE: - DEBUGE("SET INTERFACE "); - udp_ep0_send_stall(); - break; - default: - DEBUGE("DEFAULT(req=0x%02x, type=0x%02x) ", bRequest, bmRequestType); - if ((bmRequestType & 0x3f) == USB_TYPE_DFU) { - dfu_ep0_handler(bmRequestType, bRequest, wValue, wLength); - } else - udp_ep0_send_stall(); - break; - } -} - -/* minimal USB IRQ handler in DFU mode */ -static __dfufunc void dfu_udp_irq(void) -{ - AT91PS_UDP pUDP = AT91C_BASE_UDP; - AT91_REG isr = pUDP->UDP_ISR; - - if (isr & AT91C_UDP_ENDBUSRES) { - pUDP->UDP_IER = AT91C_UDP_EPINT0; - /* reset all endpoints */ - pUDP->UDP_RSTEP = (unsigned int)-1; - pUDP->UDP_RSTEP = 0; - /* Enable the function */ - pUDP->UDP_FADDR = AT91C_UDP_FEN; - /* Configure endpoint 0 */ - pUDP->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); - cur_config = 0; - } - - if (isr & AT91C_UDP_EPINT0) - dfu_udp_ep0_handler(); - - /* clear all interrupts */ - pUDP->UDP_ICR = isr; - - AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_UDP); -} - -/* this is only called once before DFU mode, no __dfufunc required */ -static void dfu_switch(void) -{ - AT91PS_AIC pAic = AT91C_BASE_AIC; - - DEBUGE("Switching to DFU mode "); - - pAic->AIC_SVR[AT91C_ID_UDP] = (unsigned int) &dfu_udp_irq; - dfu_state = DFU_STATE_dfuIDLE; -} - -void __dfufunc dfu_main(void) -{ - /* - AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_UDP, - OPENPCD_IRQ_PRIO_UDP, - AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, dfu_udp_irq); - */ - - AT91PS_AIC pAic = AT91C_BASE_AIC; - pAic->AIC_IDCR = 1 << AT91C_ID_UDP; - pAic->AIC_SVR[AT91C_ID_UDP] = (unsigned int) &dfu_udp_irq; - pAic->AIC_SMR[AT91C_ID_UDP] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | - OPENPCD_IRQ_PRIO_UDP; - pAic->AIC_ICCR = 1 << AT91C_ID_UDP; - - AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_UDP); - - /* End-of-Bus-Reset is always enabled */ - - /* Clear for set the Pull up resistor */ - AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); - - /* do nothing, since all of DFU is interrupt driven */ - while (1) ; -} - -struct dfuapi __dfufunctab dfu_api = { - .ep0_send_data = &udp_ep0_send_data, - .ep0_send_zlp = &udp_ep0_send_zlp, - .ep0_send_stall = &udp_ep0_send_stall, - .dfu_ep0_handler = &dfu_ep0_handler, - .dfu_switch = &dfu_switch, - .dfu_state = &dfu_state, - .dfu_dev_descriptor = &dfu_dev_descriptor, - .dfu_cfg_descriptor = &dfu_cfg_descriptor, -}; - -int foo = 12345; diff --git a/openpcd/firmware/src/dfu.h b/openpcd/firmware/src/dfu.h deleted file mode 100644 index a663688..0000000 --- a/openpcd/firmware/src/dfu.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef _DFU_H -#define _DFU_H - -/* USB Device Firmware Update Implementation for OpenPCD - * (C) 2006 by Harald Welte - * - * This ought to be compliant to the USB DFU Spec 1.0 as available from - * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf - * - */ - -#include -#include -#include - -#include "dbgu.h" - -/* USB DFU functional descriptor */ -#define DFU_FUNC_DESC { \ - .bLength = USB_DT_DFU_SIZE, \ - .bDescriptorType = USB_DT_DFU, \ - .bmAttributes = USB_DFU_CAN_UPLOAD | USB_DFU_CAN_DOWNLOAD, \ - .wDetachTimeOut = 0xff00, \ - .wTransferSize = AT91C_IFLASH_PAGE_SIZE, \ - .bcdDFUVersion = 0x0100, \ -} - -/* USB Interface descriptor in Runtime mode */ -#define DFU_RT_IF_DESC { \ - .bLength = USB_DT_INTERFACE_SIZE, \ - .bDescriptorType = USB_DT_INTERFACE, \ - .bInterfaceNumber = 0x01, \ - .bAlternateSetting = 0x00, \ - .bNumEndpoints = 0x00, \ - .bInterfaceClass = 0xfe, \ - .bInterfaceSubClass = 0x01, \ - .bInterfaceProtocol = 0x01, \ - .iInterface = 1, \ -} - -#define __dfufunc __attribute__ ((long_call, section (".dfu.func"))) -#define __dfustruct __attribute__ ((section (".dfu.struct"))) const -#define __dfufunctab __attribute__ ((section (".dfu.functab"))) - -#if 0 -extern void __dfufunc udp_ep0_send_data(const char *data, u_int32_t length); -extern void __dfufunc udp_ep0_send_zlp(void); -extern void __dfufunc udp_ep0_send_stall(void); -extern __dfustruct struct usb_device_descriptor dfu_dev_descriptor; -extern __dfustruct struct _dfu_desc dfu_cfg_descriptor; -extern void dfu_switch(void); -extern int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req, - u_int16_t val, u_int16_t len); -extern static u_int8_t dfu_state; -struct udp_pcd; -#endif - - -extern void udp_init(void); - -struct _dfu_desc { - struct usb_config_descriptor ucfg; - struct usb_interface_descriptor uif[2]; - struct usb_dfu_func_descriptor func_dfu; -}; - -struct dfuapi { - void (*ep0_send_data)(const char *data, u_int32_t len); - void (*ep0_send_zlp)(void); - void (*ep0_send_stall)(void); - int (*dfu_ep0_handler)(u_int8_t req_type, u_int8_t req, - u_int16_t val, u_int16_t len); - void (*dfu_switch)(void); - u_int8_t *dfu_state; - struct usb_device_descriptor *dfu_dev_descriptor; - struct _dfu_desc *dfu_cfg_descriptor; -}; - - -#endif /* _DFU_H */ diff --git a/openpcd/firmware/src/fifo.c b/openpcd/firmware/src/fifo.c deleted file mode 100644 index b0ec152..0000000 --- a/openpcd/firmware/src/fifo.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Implementation of a virtual FIFO */ - -#include "fifo.h" - -#include -#include - -#define FIFO_IRQ_LO 0x01 -#define FIFO_IRQ_HI 0x02 -#define FIFO_IRQ_OFLOW 0x04 - -/* returns number of data bytes present in the fifo */ -int fifo_available(struct fifo *fifo) -{ - if (fifo->producer > fifo->consumer) - return fifo->producer - fifo->consumer; - else - return (fifo->size - fifo->consumer) + fifo->producer; -} - -void fifo_check_water(struct fifo *fifo) -{ - int avail = fifo_available(fifo); - - if (avail <= fifo->watermark) - fifo->irq |= FIFO_IRQ_LO; - else - fifo->irq &= FIFO_IRQ_LO; - - if (fifo->size - avail >= fifo->watermark) - fifo->irq |= FIFO_IRQ_HI; - else - fifo->irq &= FIFO_IRQ_HI; -} - -void fifo_check_raise_int(struct fifo *fifo) -{ - if (fifo->irq & fifo->irq_en) - fifo->callback(fifo, fifo->irq, fifo->cb_data); -} - - -u_int16_t fifo_data_put(struct fifo *fifo, u_int16_t len, u_int8_t *data) -{ - if (len > fifo_available(fifo)) { - len = fifo_available(fifo); - fifo->irq |= FIFO_IRQ_OFLOW; - } - - if (len + fifo->producer <= fifo->size) { - /* easy case */ - memcpy(&fifo->data[fifo->producer], data, len); - fifo->producer += len; - } else { - /* difficult: wrap around */ - u_int16_t chunk_len; - - chunk_len = fifo->size - fifo->producer; - memcpy(&fifo->data[fifo->producer], data, chunk_len); - - memcpy(&fifo->data[0], data + chunk_len, len - chunk_len); - fifo->producer = len - chunk_len; - } - - fifo_check_water(fifo); - - return len; -} - - -u_int16_t fifo_data_get(struct fifo *fifo, u_int16_t len, u_int8_t *data) -{ - u_int16_t avail = fifo_available(fifo); - - if (avail < len) - len = avail; - - if (fifo->producer > fifo->consumer) { - /* easy case */ - memcpy(data, &fifo->data[fifo->consumer], len); - } else { - /* difficult case: wrap */ - u_int16_t chunk_len = fifo->size - fifo->consumer; - memcpy(data, &fifo->data[fifo->consumer], chunk_len); - memcpy(data+chunk_len, &fifo->data[0], len - chunk_len); - } - - fifo_check_water(fifo); - - return len; -} - -int fifo_init(struct fifo *fifo, u_int16_t size, - void (*cb)(struct fifo *fifo, u_int8_t event, void *data), void *cb_data) -{ - if (size > sizeof(fifo->data)) - return -EINVAL; - - memset(fifo->data, 0, sizeof(fifo->data)); - fifo->size = size; - fifo->producer = fifo->consumer = 0; - fifo->watermark = 0; - fifo->callback = cb; - fifo->cb_data = cb_data; - - return 0; -} - diff --git a/openpcd/firmware/src/fifo.h b/openpcd/firmware/src/fifo.h deleted file mode 100644 index d91c6c2..0000000 --- a/openpcd/firmware/src/fifo.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _FIFO_H -#define _FIFO_H - -#include - -#define FIFO_SIZE 1024 - -struct fifo { - u_int16_t size; /* actual FIFO size, can be smaller than 'data' */ - u_int16_t producer; /* index of producer */ - u_int16_t consumer; /* index of consumer */ - u_int16_t watermark; - u_int8_t irq; - u_int8_t irq_en; - u_int8_t status; - void (*callback)(struct fifo *fifo, u_int8_t event, void *data); - void *cb_data; - u_int8_t data[FIFO_SIZE]; -}; - - -extern int fifo_init(struct fifo *fifo, u_int16_t size, - void (*callback)(struct fifo *fifo, u_int8_t event, void *data), void *cb_data); -extern u_int16_t fifo_data_get(struct fifo *fifo, u_int16_t len, u_int8_t *data); -extern u_int16_t fifo_data_put(struct fifo *fifo, u_int16_t len, u_int8_t *data); -extern int fifo_available(struct fifo *fifo); - -#endif diff --git a/openpcd/firmware/src/flash.c b/openpcd/firmware/src/flash.c deleted file mode 100644 index 2aaf760..0000000 --- a/openpcd/firmware/src/flash.c +++ /dev/null @@ -1,45 +0,0 @@ - - -#define EFCS_CMD_WRITE_PAGE 0x01 -#define EFCS_CMD_SET_LOCK_BIT 0x02 -#define EFCS_CMD_WRITE_PAGE_LOCK 0x03 -#define EFCS_CMD_CLEAR_LOCK 0x04 -#define EFCS_CMD_ERASE_ALL 0x08 -#define EFCS_CMD_SET_NVM_BIT 0x0b -#define EFCS_CMD_CLEAR_NVM_BIT 0x0d -#define EFCS_CMD_SET_SECURITY_BIT 0x0f - - -int unlock_page(u_int16_t page) -{ - AT91C_MC_FCMD_UNLOCK | AT91C_MC_CORRECT_KEY | - -} - -int flash_sector(unsigned int sector, const u_int8_t *data, unsigned int len) -{ - volatile u_int32_t *p = (volatile u_int32_t *)0; - u_int32_t *src32 = (u_int32_t *)data; - int i; - - /* hand-code memcpy because we need to make sure only 32bit accesses - * are used */ - for (i = 0; i < len/4; i++) - p[i] = src32[i]; - - AT91F_MC_EFC_PerformCmd(pmc , AT91C_MC_FCMD_START_PROG| - AT91C_MC_CORRECT_KEY | ); -} - - -void flash_init(void) -{ - unsigned int fmcn = AT91F_MC_EFC_ComputerFMCN(48000000); - - AT91F_MC_EFC_CfgModeReg(ff, fmcn << 16 | AT91C_MC_FWS_3FWS | - AT91C_MC_FRDY | AT91C_MC_LOCKE | - AT91C_MC_PROGE); - - AT91F_AIC_EnableIt(); - -} diff --git a/openpcd/firmware/src/led.c b/openpcd/firmware/src/led.c deleted file mode 100644 index 1620444..0000000 --- a/openpcd/firmware/src/led.c +++ /dev/null @@ -1,84 +0,0 @@ - -#include -#include -#include -#include -#include "openpcd.h" -#include "usb_handler.h" -#include "dbgu.h" - -static int led2port(int led) -{ - if (led == 1) - return OPENPCD_PIO_LED1; - else if (led == 2) - return OPENPCD_PIO_LED2; - else - return 0; -} - -void led_switch(int led, int on) -{ - int port = led2port(led); - - if (port == -1) - return; - - if (on) - AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, port); - else - AT91F_PIO_SetOutput(AT91C_BASE_PIOA, port); -} - -int led_get(int led) -{ - int port = led2port(led); - - if (port == -1) - return -1; - - return !(AT91F_PIO_GetOutputDataStatus(AT91C_BASE_PIOA) & port); -} - -int led_toggle(int led) -{ - int on = led_get(led); - if (on == -1) - return -1; - - if (on) - led_switch(led, 0); - else - led_switch(led, 1); - - 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/openpcd/firmware/src/led.h b/openpcd/firmware/src/led.h deleted file mode 100644 index 394107b..0000000 --- a/openpcd/firmware/src/led.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _LED_H -#define _LED_H - -extern void led_init(void); -extern void led_switch(int led, int on); -extern int led_get(int led); -extern int led_toggle(int led); - -#endif diff --git a/openpcd/firmware/src/main.c b/openpcd/firmware/src/main.c deleted file mode 100644 index def9e57..0000000 --- a/openpcd/firmware/src/main.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include -#include "dbgu.h" -#include "led.h" -#include "openpcd.h" - -int main(void) -{ - /* initialize LED and debug unit */ - led_init(); - AT91F_DBGU_Init(); - - /* call application specific init function */ - _init_func(); - - // Enable User Reset and set its minimal assertion to 960 us - AT91C_BASE_RSTC->RSTC_RMR = - AT91C_RSTC_URSTEN | (0x4 << 8) | (unsigned int)(0xA5 << 24); - -#ifdef DEBUG_CLOCK_PA6 - AT91F_PMC_EnablePCK(AT91C_BASE_PMC, 0, AT91C_PMC_CSS_PLL_CLK); - AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, AT91C_PA6_PCK0); -#endif - - /* switch on first led */ - led_switch(1, 1); - - DEBUGPCRF("entering main (idle) loop"); - while (1) { - /* Call application specific main idle function */ - _main_func(); - dbgu_rb_flush(); - } -} diff --git a/openpcd/firmware/src/main.h b/openpcd/firmware/src/main.h deleted file mode 100644 index 1adc8f6..0000000 --- a/openpcd/firmware/src/main.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _MAIN_H -#define _MAIN_H - -extern void _init_func(void); -extern int _main_dbgu(char key); -extern void _main_func(void); - -#endif diff --git a/openpcd/firmware/src/main_analog.c b/openpcd/firmware/src/main_analog.c deleted file mode 100644 index 92de3a4..0000000 --- a/openpcd/firmware/src/main_analog.c +++ /dev/null @@ -1,86 +0,0 @@ -/* main_reqa - OpenPCD firmware for generating an endless loop of - * ISO 14443-A REQA packets. - * - * If a response is received from the PICC, LED1 (Red) will be switched - * on. If no valid response has been received within the timeout of the - * receiver, LED1 (Red) will be switched off. - * - */ - -#include -#include -#include -#include "rc632.h" -#include "dbgu.h" -#include "led.h" -#include "trigger.h" -#include "pcd_enumerate.h" -#include "main.h" - -void _init_func(void) -{ - //udp_init(); - trigger_init(); - rc632_init(); - DEBUGPCRF("turning on RF"); - rc632_turn_on_rf(RAH); - /* FIXME: do we need this? */ - DEBUGPCRF("initializing 14443A operation"); - rc632_iso14443a_init(RAH); - /* Switch to 848kBps (1subcp / bit) */ - //rc632_clear_bits(RAH, RC632_REG_RX_CONTROL1, RC632_RXCTRL1_SUBCP_MASK); -} - -int _main_dbgu(char key) -{ - static char ana_out_sel; - int ret = -EINVAL; - - switch (key) { - case 'q': - ana_out_sel--; - ret = 1; - break; - case 'w': - ana_out_sel++; - ret = 1; - break; - case 'c': - rc632_turn_on_rf(RAH); - break; - case 'o': - rc632_turn_off_rf(RAH); - break; - } - - if (ana_out_sel >= 0xd) - ana_out_sel = 0; - - if (ret == 1) { - ana_out_sel &= 0x0f; - DEBUGPCR("switching to analog output mode 0x%x\n", ana_out_sel); - rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); - } - - return ret; -} - -void _main_func(void) -{ -#if 1 - struct iso14443a_atqa atqa; - - memset(&atqa, 0, sizeof(atqa)); - - trigger_pulse(); - - if (rc632_iso14443a_transceive_sf(RAH, ISO14443A_SF_CMD_WUPA, &atqa) < 0) { - DEBUGPCRF("error during transceive_sf"); - led_switch(1, 0); - } else { - DEBUGPCRF("received ATQA: %s\n", hexdump((char *)&atqa, sizeof(atqa))); - led_switch(1, 1); - } -#endif - led_toggle(2); -} diff --git a/openpcd/firmware/src/main_dumbreader.c b/openpcd/firmware/src/main_dumbreader.c deleted file mode 100644 index d9172ed..0000000 --- a/openpcd/firmware/src/main_dumbreader.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include -#include "dbgu.h" -#include "rc632.h" -#include "led.h" -#include "pcd_enumerate.h" -#include "usb_handler.h" -#include "openpcd.h" -#include "main.h" - -void _init_func(void) -{ - rc632_init(); - udp_init(); - rc632_test(RAH); -} - -int _main_dbgu(char key) -{ - return -EINVAL; -} - -void _main_func(void) -{ - /* first we try to get rid of pending to-be-sent stuff */ - usb_out_process(); - - /* next we deal with incoming reqyests from USB EP1 (OUT) */ - usb_in_process(); - - rc632_unthrottle(); -} diff --git a/openpcd/firmware/src/main_pwm.c b/openpcd/firmware/src/main_pwm.c deleted file mode 100644 index 51ecf48..0000000 --- a/openpcd/firmware/src/main_pwm.c +++ /dev/null @@ -1,250 +0,0 @@ -/* main_pwm - OpenPCD firmware for generating a PWM-modulated 13.56MHz - * carrier - * - * To use this, you need to connect PIOA P0 with MFIN of the reader. - */ - -#include -#include -#include -#include "openpcd.h" -#include "rc632.h" -#include "dbgu.h" -#include "led.h" -#include "pwm.h" -#include "tc.h" -#include "ssc.h" -#include "pcd_enumerate.h" -#include "usb_handler.h" - -static u_int8_t force_100ask = 1; -static u_int8_t mod_conductance = 0x3f; -static u_int8_t cw_conductance = 0x3f; -static u_int16_t duty_percent = 22; - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -static u_int32_t pwm_freq[] = { 105937, 211875, 423750, 847500 }; -static u_int8_t pwm_freq_idx = 0; - -static void rc632_modulate_mfin() -{ - rc632_reg_write(RAH, RC632_REG_TX_CONTROL, - RC632_TXCTRL_MOD_SRC_MFIN|RC632_TXCTRL_TX2_INV| - RC632_TXCTRL_TX1_RF_EN|RC632_TXCTRL_TX2_RF_EN); -} - -/* (77/40) ^ EXPcsCfgCW */ -/* 1, 1.925, 3.705625, 7.13332812 */ - -#define COND_MANT(x) (x & 0x0f) -#define COND_EXP(x) ((x & 0x30) >> 4) - -static const u_int16_t rsrel_expfact[] = { 1000, 1925, 3706, 7133 }; - -static u_int32_t calc_conduct_rel(u_int8_t inp) -{ - u_int32_t cond_rel; - - cond_rel = COND_MANT(inp) * rsrel_expfact[COND_EXP(inp)]; - cond_rel = cond_rel / 1000; - - return cond_rel; -} - -static const u_int8_t rsrel_table[] = { - 0, 16, 32, 48, 1, 17, 2, 3, 33, 18, 4, 5, 19, 6, 7, 49, 34, 20, - 8, 9, 21, 10, 11, 35, 22, 12, 13, 23, 14, 50, 36, 15, 24, 25, - 37, 26, 27, 51, 38, 28, 29, 39, 30, 52, 31, 40, 41, 53, 42, 43, - 54, 44, 45, 55, 46, 47, 56, 57, 58, 59, 60, 61, 62, 63 }; - - -static const u_int16_t cdivs[] = { 128, 64, 32, 16 }; -static int cdiv_idx = 0; - -static void help(void) -{ - DEBUGPCR("o: decrease duty p: increase duty\r\n" - "k: stop pwm l: start pwn\r\n" - "n: decrease freq m: incresae freq\r\n" - "v: decrease mod_cond b: increase mod_cond\r\n" - "g: decrease cw_cond h: increase cw_cond"); - DEBUGPCR("u: PA23 const 1 y: PA23 const 0\r\n" - "t: PA23 PWM0 f: toggle Force100ASK\r\n" - "{: decrease cdiv_idx }: increse cdiv idx"); -} - -void _init_func(void) -{ - DEBUGPCR("\r\n===> main_pwm <===\r\n"); - help(); - - rc632_init(); - DEBUGPCRF("turning on RF"); - rc632_turn_on_rf(RAH); - - /* switch PA17 (connected to MFIN on board) to input */ - AT91F_PIO_CfgInput(AT91C_BASE_PIOA, AT91C_PIO_PA17); - - DEBUGPCRF("Initializing carrier divider"); - tc_cdiv_init(); - - DEBUGPCRF("Initializing PWM"); - pwm_init(); - pwm_freq_set(0, 105937); - pwm_start(0); - pwm_duty_set_percent(0, 22); /* 22% of 9.43uS = 2.07uS */ - rc632_modulate_mfin(); - - udp_init(); - - DEBUGPCRF("Initializing SSC RX"); - ssc_rx_init(); -} - -int _main_dbgu(char key) -{ - switch (key) { - case 'o': - if (duty_percent >= 1) - duty_percent--; - pwm_duty_set_percent(0, duty_percent); - break; - case 'p': - if (duty_percent <= 99) - duty_percent++; - pwm_duty_set_percent(0, duty_percent); - break; - case 'k': - pwm_stop(0); - break; - case 'l': - pwm_start(0); - break; - case 'n': - if (pwm_freq_idx > 0) { - pwm_freq_idx--; - pwm_stop(0); - pwm_freq_set(0, pwm_freq[pwm_freq_idx]); - pwm_start(0); - pwm_duty_set_percent(0, 22); /* 22% of 9.43uS = 2.07uS */ - } - break; - case 'm': - if (pwm_freq_idx < ARRAY_SIZE(pwm_freq)-1) { - pwm_freq_idx++; - pwm_stop(0); - pwm_freq_set(0, pwm_freq[pwm_freq_idx]); - pwm_start(0); - pwm_duty_set_percent(0, 22); /* 22% of 9.43uS = 2.07uS */ - } - break; - case 'u': - DEBUGPCRF("PA23 output high"); - AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PIO_PA23); - AT91F_PIO_SetOutput(AT91C_BASE_PIOA, AT91C_PIO_PA23); - break; - case 'y': - DEBUGPCRF("PA23 output low"); - AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PIO_PA23); - AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, AT91C_PIO_PA23); - return 0; - break; - case 't': - DEBUGPCRF("PA23 PeriphA (PWM)"); - AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, AT91C_PA23_PWM0); - return 0; - break; - case 'f': - DEBUGPCRF("%sabling Force100ASK", force_100ask ? "Dis":"En"); - if (force_100ask) { - force_100ask = 0; - rc632_clear_bits(RAH, RC632_REG_TX_CONTROL, - RC632_TXCTRL_FORCE_100_ASK); - } else { - force_100ask = 1; - rc632_set_bits(RAH, RC632_REG_TX_CONTROL, - RC632_TXCTRL_FORCE_100_ASK); - } - return 0; - break; - case 'v': - if (mod_conductance > 0) { - mod_conductance--; - rc632_reg_write(RAH, RC632_REG_MOD_CONDUCTANCE, - rsrel_table[mod_conductance]); - } - break; - case 'b': - if (mod_conductance < 0x3f) { - mod_conductance++; - rc632_reg_write(RAH, RC632_REG_MOD_CONDUCTANCE, - rsrel_table[mod_conductance]); - } - break; - case 'g': - if (cw_conductance > 0) { - cw_conductance--; - rc632_reg_write(RAH, RC632_REG_CW_CONDUCTANCE, - rsrel_table[cw_conductance]); - } - break; - case 'h': - if (cw_conductance < 0x3f) { - cw_conductance++; - rc632_reg_write(RAH, RC632_REG_CW_CONDUCTANCE, - rsrel_table[cw_conductance]); - } - break; - case '?': - help(); - return 0; - break; - case '<': - tc_cdiv_phase_inc(); - break; - case '>': - tc_cdiv_phase_dec(); - break; - case '{': - if (cdiv_idx > 0) - cdiv_idx--; - tc_cdiv_set_divider(cdivs[cdiv_idx]); - break; - case '}': - if (cdiv_idx < ARRAY_SIZE(cdivs)-1) - cdiv_idx++; - tc_cdiv_set_divider(cdivs[cdiv_idx]); - break; - case 's': - ssc_rx_start(); - break; - case 'S': - ssc_rx_stop(); - break; - default: - return -EINVAL; - } - - DEBUGPCR("pwm_freq=%u, duty_percent=%u, mod_cond=%u, cw_cond=%u tc_cdiv=%u", - pwm_freq[pwm_freq_idx], duty_percent, mod_conductance, cw_conductance, - cdivs[cdiv_idx]); - - return 0; -} - - -void _main_func(void) -{ - /* first we try to get rid of pending to-be-sent stuff */ - usb_out_process(); - - /* next we deal with incoming reqyests from USB EP1 (OUT) */ - usb_in_process(); - - /* try unthrottling sources since we now are [more] likely to - * have empty request contexts */ - rc632_unthrottle(); - ssc_rx_unthrottle(); - - led_toggle(2); -} diff --git a/openpcd/firmware/src/main_reqa.c b/openpcd/firmware/src/main_reqa.c deleted file mode 100644 index 0e9acea..0000000 --- a/openpcd/firmware/src/main_reqa.c +++ /dev/null @@ -1,255 +0,0 @@ -/* main_reqa - OpenPCD firmware for generating an endless loop of - * ISO 14443-A REQA packets. Alternatively we can send WUPA, or - * perform a full ISO14443A anti-collision loop. - * - * If a response is received from the PICC, LED1 (Red) will be switched - * on. If no valid response has been received within the timeout of the - * receiver, LED1 (Red) will be switched off. - * - */ - -#include -#include -#include -#include -#include "rc632.h" -#include "dbgu.h" -#include "led.h" -#include "pcd_enumerate.h" -#include "trigger.h" -#include "tc.h" - -void _init_func(void) -{ - //udp_init(); - trigger_init(); - DEBUGPCRF("enabling RC632"); - rc632_init(); - DEBUGPCRF("enabling TC"); - tc_cdiv_init(); - DEBUGPCRF("turning on RF"); - rc632_turn_on_rf(RAH); - DEBUGPCRF("initializing 14443A operation"); - rc632_iso14443a_init(RAH); -} - -#define MODE_REQA 0x01 -#define MODE_WUPA 0x02 -#define MODE_ANTICOL 0x03 -#define MODE_14443A 0x04 - -static volatile int mode = MODE_REQA; - -static const char frame_14443a[] = { 0x00, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; - -static void reg_inc(u_int8_t reg) -{ - u_int8_t val; - rc632_reg_read(RAH, reg, &val); - rc632_reg_write(RAH, reg, val++); - DEBUGPCRF("reg 0x%02x = 0x%02x", reg, val); -} - -static void reg_dec(u_int8_t reg) -{ - u_int8_t val; - rc632_reg_read(RAH, reg, &val); - rc632_reg_write(RAH, reg, val--); - DEBUGPCRF("reg 0x%02x = 0x%02x", reg, val); -} - -static u_int8_t ana_out_sel; -static u_int8_t mfout_sel; -static u_int8_t speed_idx; - -static void help(void) -{ - DEBUGPCR("r: REQA w: WUPA a: ANTICOL\r\n" - "A: 14443A +: inc speed -: dec speed\r\n" - "y: inc cw cond x: dec cond c: inc mod cond"); - DEBUGPCR("v: dec mod cond o: dec ana_out p: dec ana_out\r\n" - "h: trigger high l: trigger low u: dec MFOUT mode"); - DEBUGPCR("i: inc MFOUT md <: dec cdiv ph >: inc cdiv phase\r\n" - "{: dev cdiv }: inc cdiv"); -} - -static u_int16_t cdivs[] = { 128, 64, 32, 16 }; - -int _main_dbgu(char key) -{ - int ret = 0; - static int cdiv_idx = 0; - - switch (key) { - case '?': - help(); - break; - case 'r': - mode = MODE_REQA; - break; - case 'w': - mode = MODE_WUPA; - break; - case 'A': - mode = MODE_14443A; - break; - case 'a': - mode = MODE_ANTICOL; - break; - /* Those below don't work as long as - * iso14443a_init() is called before - * every cycle */ - case 'y': - reg_inc(RC632_REG_CW_CONDUCTANCE); - break; - case 'x': - reg_dec(RC632_REG_CW_CONDUCTANCE); - break; - case 'c': - reg_inc(RC632_REG_MOD_CONDUCTANCE); - break; - case 'v': - reg_dec(RC632_REG_MOD_CONDUCTANCE); - break; - case 'o': - if (ana_out_sel > 0) { - ana_out_sel--; - DEBUGPCR("switching to analog output mode 0x%x\n", ana_out_sel); - rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); - } - ret = 1; - break; - case 'p': - if (ana_out_sel < 0xc) { - ana_out_sel++; - DEBUGPCR("switching to analog output mode 0x%x\n", ana_out_sel); - rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); - } - ret = 1; - break; - case 'u': - if (mfout_sel > 0) { - mfout_sel--; - DEBUGPCR("switching to MFOUT mode 0x%x\n", mfout_sel); - rc632_reg_write(RAH, RC632_REG_MFOUT_SELECT, mfout_sel); - } - ret = 1; - break; - case 'i': - if (mfout_sel < 5) { - mfout_sel++; - DEBUGPCR("switching to MFOUT mode 0x%x\n", mfout_sel); - rc632_reg_write(RAH, RC632_REG_MFOUT_SELECT, mfout_sel); - } - ret = 1; - break; - case 'h': - AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); - break; - case 'l': - AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); - break; - case '<': - tc_cdiv_phase_inc(); - break; - case '>': - tc_cdiv_phase_dec(); - break; - case '{': - if (cdiv_idx > 0) - cdiv_idx--; - tc_cdiv_set_divider(cdivs[cdiv_idx]); - break; - case '}': - if (cdiv_idx < ARRAY_SIZE(cdivs)-1) - cdiv_idx++; - tc_cdiv_set_divider(cdivs[cdiv_idx]); - break; - case '-': - if (speed_idx > 0) - speed_idx--; - break; - case '+': - if (speed_idx < 3) - speed_idx++; - break; - default: - return -EINVAL; - } - - return ret; -} - -void _main_func(void) -{ - int status; - struct iso14443a_atqa atqa; - struct rfid_layer2_handle l2h; - volatile int i; - - memset(&atqa, 0, sizeof(atqa)); - - /* fake layer2 handle initialization */ - memset(&l2h, 0, sizeof(l2h)); - l2h.l2 = &rfid_layer2_iso14443a; - l2h.priv.iso14443a.state = ISO14443A_STATE_NONE; - l2h.priv.iso14443a.level = ISO14443A_LEVEL_NONE; - - /* FIXME: why does this only work every second attempt without reset or - * power-cycle? */ - rc632_turn_off_rf(); - //rc632_reset(); - rc632_turn_on_rf(); - - rc632_iso14443a_init(RAH); - rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); - rc632_reg_write(RAH, RC632_REG_MFOUT_SELECT, mfout_sel); - for (i = 0; i < 0x3ffff; i++) {} - //rc632_dump(); - tc_cdiv_print(); - - switch (mode) { - case MODE_REQA: - status = rc632_iso14443a_transceive_sf(RAH, ISO14443A_SF_CMD_REQA, &atqa); - if (status < 0) - DEBUGPCRF("error during transceive_sf REQA"); - else - DEBUGPCRF("received ATQA: %s", hexdump((char *)&atqa, sizeof(atqa))); - break; - case MODE_WUPA: - status = rc632_iso14443a_transceive_sf(RAH, ISO14443A_SF_CMD_WUPA, &atqa); - if (status < 0) - DEBUGPCRF("error during transceive_sf WUPA"); - else - DEBUGPCRF("received WUPA: %s", hexdump((char *)&atqa, sizeof(atqa))); - break; - case MODE_ANTICOL: - status = rfid_layer2_iso14443a.fn.open(&l2h); - if (status < 0) - DEBUGPCR("error during anticol"); - else - DEBUGPCR("Anticol OK"); - break; - case MODE_14443A: - { - char rx_buf[4]; - int rx_len = sizeof(rx_buf); - rfid_layer2_iso14443a.fn.setopt(&l2h, RFID_OPT_14443A_SPEED_RX, - &speed_idx, sizeof(speed_idx)); - rfid_layer2_iso14443a.fn.setopt(&l2h, RFID_OPT_14443A_SPEED_TX, - &speed_idx, sizeof(speed_idx)); - rfid_layer2_iso14443a.fn.transceive(&l2h, RFID_14443A_FRAME_REGULAR, - &frame_14443a, sizeof(frame_14443a), - &rx_buf, &rx_len, 1, 0); - } - break; - } - - if (status < 0) - led_switch(1, 0); - else - led_switch(1, 1); - - led_toggle(2); - -} diff --git a/openpcd/firmware/src/openpcd.h b/openpcd/firmware/src/openpcd.h index ec577d3..aa47fa4 100644 --- a/openpcd/firmware/src/openpcd.h +++ b/openpcd/firmware/src/openpcd.h @@ -49,49 +49,6 @@ #define OPENPCD_IRQ_PRIO_UDP (AT91C_AIC_PRIOR_LOWEST+1) #define OPENPCD_IRQ_PRIO_RC632 AT91C_AIC_PRIOR_LOWEST -#define MAX_HDRSIZE sizeof(struct openpcd_hdr) -#define MAX_REQSIZE (64-MAX_HDRSIZE) - -#define req_buf_payload(x) (x->data[x->hdr_len]) -#define req_buf_hdr(x) (x->data[0]) - -#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; -}; - -#define RCTX_STATE_FREE 0x00 -#define RCTX_STATE_UDP_RCV_BUSY 0x01 -#define RCTX_STATE_UDP_RCV_DONE 0x02 -#define RCTX_STATE_MAIN_PROCESSING 0x03 -#define RCTX_STATE_RC632IRQ_BUSY 0x04 - -#define RCTX_STATE_UDP_EP2_PENDING 0x10 -#define RCTX_STATE_UDP_EP2_BUSY 0x11 - -#define RCTX_STATE_UDP_EP3_PENDING 0x12 -#define RCTX_STATE_UDP_EP3_BUSY 0x13 - -#define RCTX_STATE_SSC_RX_BUSY 0x20 - -#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); -extern void req_ctx_set_state(struct req_ctx *ctx, unsigned long new_state); -extern void req_ctx_put(struct req_ctx *ctx); -extern u_int8_t req_ctx_num(struct req_ctx *ctx); - extern void _init_func(void); extern void _main_func(void); diff --git a/openpcd/firmware/src/os/dbgu.c b/openpcd/firmware/src/os/dbgu.c new file mode 100644 index 0000000..e64d8eb --- /dev/null +++ b/openpcd/firmware/src/os/dbgu.c @@ -0,0 +1,325 @@ +/*---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support - ROUSSET - + *---------------------------------------------------------------------------- + * The software is delivered "AS IS" without warranty or condition of any + * kind, either express, implied or statutory. This includes without + * limitation any warranty or condition with respect to merchantability or + * fitness for any particular purpose, or against the infringements of + * intellectual property rights of others. + *---------------------------------------------------------------------------- + * File Name : Debug.c + * Object : Debug menu + * Creation : JPP 14/Sep/2004 + * 1.1 29/Aug/05 JPP : Update AIC definion + *----------------------------------------------------------------------------*/ + +// Include Standard files +#include +#include +#include "../openpcd.h" +#include +#include +#include + +#define USART_SYS_LEVEL 4 +/*---------------------------- Global Variable ------------------------------*/ +//*--------------------------1-------------------------------------------------- +//* \fn AT91F_DBGU_Printk +//* \brief This function is used to send a string through the DBGU channel +//*---------------------------------------------------------------------------- +void AT91F_DBGU_Ready(void) +{ + while (!(AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXEMPTY)) ; +} + +//*---------------------------------------------------------------------------- +//* Function Name : Send_reset +//* Object : Acknoledeg AIC and send reset +//*---------------------------------------------------------------------------- +static void Send_reset(void) +{ + void (*pfct) (void) = (void (*)(void))0x00000000; + + // Acknoledge the interrupt + // Mark the End of Interrupt on the AIC + AT91C_BASE_AIC->AIC_EOICR = 0; + AT91F_DBGU_Ready(); + // Jump in reset + pfct(); +} + +//*---------------------------------------------------------------------------- +//* Function Name : DBGU_irq_handler +//* Object : C handler interrupt function called by the interrupts +//* assembling routine +//*---------------------------------------------------------------------------- +static void DBGU_irq_handler(void) +{ + static char value; + + AT91F_DBGU_Get(&value); + switch (value) { + case '0': //* info + AT91F_DBGU_Frame("Set Pull up\n\r"); + // Set + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); + break; + case '1': //* info + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); + AT91F_DBGU_Printk("Clear Pull up\n\r"); + // Reset Application + Send_reset(); + break; + case '2': + AT91F_DBGU_Printk("Toggling LED 1\n\r"); + led_toggle(1); + break; + case '3': + AT91F_DBGU_Printk("Toggling LED 2\n\r"); + led_toggle(2); + break; +#if 0 + case '4': + AT91F_DBGU_Printk("Testing RC632 : "); + if (rc632_test(RAH) == 0) + AT91F_DBGU_Printk("SUCCESS!\n\r"); + else + AT91F_DBGU_Printk("ERROR!\n\r"); + + break; + case '5': + rc632_reg_read(RAH, RC632_REG_RX_WAIT, &value); + DEBUGPCR("Reading RC632 Reg RxWait: 0x%02xr", value); + + break; + case '6': + DEBUGPCR("Writing RC632 Reg RxWait: 0x55"); + rc632_reg_write(RAH, RC632_REG_RX_WAIT, 0x55); + break; + case '7': + rc632_dump(); + break; +#endif + default: + if (_main_dbgu(value) < 0) + AT91F_DBGU_Printk("\n\r"); + break; + } // end switch +} + +void dbgu_rb_init(void); +//*---------------------------------------------------------------------------- +//* \fn AT91F_DBGU_Init +//* \brief This function is used to send a string through the DBGU channel (Very low level debugging) +//*---------------------------------------------------------------------------- +void AT91F_DBGU_Init(void) +{ + dbgu_rb_init(); + + //* Open PIO for DBGU + AT91F_DBGU_CfgPIO(); + //* Enable Transmitter & receivier + ((AT91PS_USART) AT91C_BASE_DBGU)->US_CR = + AT91C_US_RSTTX | AT91C_US_RSTRX; + + //* Configure DBGU + AT91F_US_Configure((AT91PS_USART) AT91C_BASE_DBGU, // DBGU base address + MCK, AT91C_US_ASYNC_MODE, // Mode Register to be programmed + AT91C_DBGU_BAUD, // Baudrate to be programmed + 0); // Timeguard to be programmed + + //* Enable Transmitter & receivier + ((AT91PS_USART) AT91C_BASE_DBGU)->US_CR = AT91C_US_RXEN | AT91C_US_TXEN; + + //* Enable USART IT error and AT91C_US_ENDRX + AT91F_US_EnableIt((AT91PS_USART) AT91C_BASE_DBGU, AT91C_US_RXRDY); + + //* open interrupt + AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS, USART_SYS_LEVEL, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, + DBGU_irq_handler); + AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SYS); + + AT91F_DBGU_Printk + ("\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"); +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_DBGU_Printk +//* \brief This function is used to send a string through the DBGU channel (Very low level debugging) +//*---------------------------------------------------------------------------- +void AT91F_DBGU_Printk(char *buffer) +{ + while (*buffer != '\0') { + while (!AT91F_US_TxReady((AT91PS_USART) AT91C_BASE_DBGU)) ; + AT91F_US_PutChar((AT91PS_USART) AT91C_BASE_DBGU, *buffer++); + } +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_DBGU_Frame +//* \brief This function is used to send a string through the DBGU channel +//*---------------------------------------------------------------------------- +void AT91F_DBGU_Frame(char *buffer) +{ + unsigned char len; + + for (len = 0; buffer[len] != '\0'; len++) { + } + + AT91F_US_SendFrame((AT91PS_USART) AT91C_BASE_DBGU, + (unsigned char *)buffer, len, 0, 0); + +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_US_Get +//* \brief Get a Char to USART +//*---------------------------------------------------------------------------- +int AT91F_DBGU_Get(char *val) +{ + if ((AT91F_US_RxReady((AT91PS_USART) AT91C_BASE_DBGU)) == 0) + return (0); + else { + *val = AT91F_US_GetChar((AT91PS_USART) AT91C_BASE_DBGU); + return (-1); + } +} + +// mthomas: function not used in this application. avoid +// linking huge newlib code for sscanf. + +#ifdef DEBUG +#include +#include +#include +const char * +hexdump(const void *data, unsigned int len) +{ + static char string[256]; + unsigned char *d = (unsigned char *) data; + unsigned int i, left; + + string[0] = '\0'; + left = sizeof(string); + for (i = 0; len--; i += 3) { + if (i >= sizeof(string) -4) + break; + snprintf(string+i, 4, " %02x", *d++); + } + return string; +} + +struct dbgu { + char buf[4096]; + char *next_inbyte; + char *next_outbyte; +}; +static struct dbgu dbgu; + +void dbgu_rb_init(void) +{ + memset(dbgu.buf, 0, sizeof(dbgu.buf)); + dbgu.next_inbyte = &dbgu.buf[0]; + dbgu.next_outbyte = &dbgu.buf[0]; +} + +/* pull one char out of debug ring buffer */ +static int dbgu_rb_pull(char *ret) +{ + unsigned long flags; + + local_irq_save(flags); + + if (dbgu.next_outbyte == dbgu.next_inbyte) { + local_irq_restore(flags); + return -1; + } + + *ret = *dbgu.next_outbyte; + + dbgu.next_outbyte++; + if (dbgu.next_outbyte == &dbgu.buf[0]+sizeof(dbgu.buf)) { + //AT91F_DBGU_Printk("WRAP DURING PULL\r\n"); + dbgu.next_outbyte = &dbgu.buf[0]; + } else if (dbgu.next_outbyte > &dbgu.buf[0]+sizeof(dbgu.buf)) { + //AT91F_DBGU_Printk("OUTBYTE > END_OF_BUF!!\r\n"); + dbgu.next_outbyte -= sizeof(dbgu.buf); + } + + local_irq_restore(flags); + + return 0; +} + +static void __rb_flush(void) +{ + char ch; + while (dbgu_rb_pull(&ch) >= 0) { + while (!AT91F_US_TxReady((AT91PS_USART) AT91C_BASE_DBGU)) ; + AT91F_US_PutChar((AT91PS_USART) AT91C_BASE_DBGU, ch); + } +} + +/* flush pending data from debug ring buffer to serial port */ +void dbgu_rb_flush(void) +{ + __rb_flush(); +} + +static void __dbgu_rb_append(char *data, int len) +{ + char *pos = dbgu.next_inbyte; + + dbgu.next_inbyte += len; + if (dbgu.next_inbyte >= &dbgu.buf[0]+sizeof(dbgu.buf)) { + AT91F_DBGU_Printk("WRAP DURING APPEND\r\n"); + dbgu.next_inbyte -= sizeof(dbgu.buf); + } + + memcpy(pos, data, len); +} + +void dbgu_rb_append(char *data, int len) +{ + unsigned long flags; + int bytes_left; + char *data_cur; + + local_irq_save(flags); + + bytes_left = &dbgu.buf[0]+sizeof(dbgu.buf)-dbgu.next_inbyte; + data_cur = data; + + if (len > bytes_left) { + AT91F_DBGU_Printk("LEN > BYTES_LEFT\r\n"); + __rb_flush(); + __dbgu_rb_append(data_cur, bytes_left); + len -= bytes_left; + data_cur += bytes_left; + } + __dbgu_rb_append(data_cur, len); + + local_irq_restore(flags); +} + +static char dbg_buf[256]; +void debugp(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vsnprintf(dbg_buf, sizeof(dbg_buf)-1, format, ap); + va_end(ap); + + dbg_buf[sizeof(dbg_buf)-1] = '\0'; + //AT91F_DBGU_Frame(dbg_buf); + //AT91F_DBGU_Printk(dbg_buf); + dbgu_rb_append(dbg_buf, strlen(dbg_buf)); +} +#else +void dbgu_rb_flush(void) {} +void dbgu_rb_init(void) {} +#endif diff --git a/openpcd/firmware/src/os/dbgu.h b/openpcd/firmware/src/os/dbgu.h new file mode 100644 index 0000000..8dd34be --- /dev/null +++ b/openpcd/firmware/src/os/dbgu.h @@ -0,0 +1,43 @@ +//*---------------------------------------------------------------------------- +//* ATMEL Microcontroller Software Support - ROUSSET - +//*---------------------------------------------------------------------------- +//* The software is delivered "AS IS" without warranty or condition of any +//* kind, either express, implied or statutory. This includes without +//* limitation any warranty or condition with respect to merchantability or +//* fitness for any particular purpose, or against the infringements of +//* intellectual property rights of others. +//*---------------------------------------------------------------------------- +//* File Name : Debug.h +//* Object : Debug menu +//* Creation : JPP 02/Sep/2004 +//*---------------------------------------------------------------------------- + +#ifndef dbgu_h +#define dbgu_h + +#define AT91C_DBGU_BAUD 115200 + +//#define DEBUGP(x) AT91F_DBGU_Printk(x) + +//* ----------------------- External Function Prototype ----------------------- + +extern const char *hexdump(const void *data, unsigned int len); +void AT91F_DBGU_Init(void); +void AT91F_DBGU_Printk( char *buffer); +void AT91F_DBGU_Frame( char *buffer); +int AT91F_DBGU_Get( char *val); +#ifndef __WinARM__ +void AT91F_DBGU_scanf(char * type,unsigned int * val); +#endif + +#ifdef DEBUG +extern void debugp(const char *format, ...); +#define DEBUGP(x, args ...) debugp(x, ## args) +#else +#define DEBUGP(x, args ...) do {} while(0) +#endif + +#define DEBUGPCR(x, args ...) DEBUGP(x "\r\n", ## args) +#define DEBUGPCRF(x, args ...) DEBUGPCR("%s(%d): " x, __FUNCTION__, __LINE__, ## args) + +#endif /* dbgu_h */ diff --git a/openpcd/firmware/src/os/dfu.c b/openpcd/firmware/src/os/dfu.c new file mode 100644 index 0000000..ec99cef --- /dev/null +++ b/openpcd/firmware/src/os/dfu.c @@ -0,0 +1,679 @@ +/* USB Device Firmware Update Implementation for OpenPCD + * (C) 2006 by Harald Welte + * + * This ought to be compliant to the USB DFU Spec 1.0 as available from + * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include "../openpcd.h" + +/* If debug is enabled, we need to access debug functions from flash + * and therefore have to omit flashing */ +//#define DEBUG_DFU + +#ifdef DEBUG_DFU +#define DEBUGE DEBUGP +#define DEBUGI DEBUGP +#else +#define DEBUGE(x, args ...) +#define DEBUGI(x, args ...) +#endif + +/* this is only called once before DFU mode, no __dfufunc required */ +void udp_init(void) +{ + /* Set the PLL USB Divider */ + AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1; + + /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock */ + 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 */ + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); +} + +/* Send Data through the control endpoint */ +static void __dfufunc udp_ep0_send_data(const char *pData, u_int32_t length) +{ + AT91PS_UDP pUdp = AT91C_BASE_UDP; + u_int32_t cpt = 0; + AT91_REG csr; + + DEBUGE("send_data: %u bytes ", length); + + do { + cpt = MIN(length, 8); + length -= cpt; + + while (cpt--) + pUdp->UDP_FDR[0] = *pData++; + + if (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) { + pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ; + } + + pUdp->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY; + do { + csr = pUdp->UDP_CSR[0]; + + /* Data IN stage has been stopped by a status OUT */ + if (csr & AT91C_UDP_RX_DATA_BK0) { + pUdp->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0); + DEBUGE("stopped by status out "); + return; + } + } while (!(csr & AT91C_UDP_TXCOMP)); + + } while (length); + + if (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) { + pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ; + } +} + +/* Send zero length packet through the control endpoint */ +static void __dfufunc udp_ep0_send_zlp(void) +{ + AT91PS_UDP pUdp = AT91C_BASE_UDP; + pUdp->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY; + while (!(pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP)) ; + pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP); + while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ; +} + +/* Stall the control endpoint */ +static void __dfufunc udp_ep0_send_stall(void) +{ + AT91PS_UDP pUdp = AT91C_BASE_UDP; + pUdp->UDP_CSR[0] |= AT91C_UDP_FORCESTALL; + while (!(pUdp->UDP_CSR[0] & AT91C_UDP_ISOERROR)) ; + pUdp->UDP_CSR[0] &= ~(AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR); + while (pUdp->UDP_CSR[0] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR)) ; +} + + +static u_int8_t status; +static u_int8_t *ptr; +static u_int8_t dfu_state; + +static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len) +{ + volatile u_int32_t *p = (volatile u_int32_t *)ptr; + + DEBUGE("download "); + + if (len > AT91C_IFLASH_PAGE_SIZE) { + /* Too big */ + dfu_state = DFU_STATE_dfuERROR; + status = DFU_STATUS_errADDRESS; + udp_ep0_send_stall(); + return -EINVAL; + } + if (len & 0x3) { + dfu_state = DFU_STATE_dfuERROR; + status = DFU_STATUS_errADDRESS; + udp_ep0_send_stall(); + return -EINVAL; + } + if (len == 0) { + dfu_state = DFU_STATE_dfuMANIFEST_SYNC; + return 0; + } +#if 0 + for (i = 0; i < len/4; i++) + p[i] = +#endif + + /* FIXME: get data packet from FIFO, (erase+)write flash */ +#ifndef DEBUG_DFU + +#endif + + return 0; +} + +static __dfufunc int handle_upload(u_int16_t val, u_int16_t len) +{ + DEBUGE("upload "); + if (len > AT91C_IFLASH_PAGE_SIZE + || ptr > AT91C_IFLASH_SIZE) { + /* Too big */ + dfu_state = DFU_STATE_dfuERROR; + status = DFU_STATUS_errADDRESS; + udp_ep0_send_stall(); + return -EINVAL; + } + + if (ptr + len > AT91C_IFLASH_SIZE) + len = AT91C_IFLASH_SIZE - (u_int32_t) ptr; + + udp_ep0_send_data(ptr, len); + ptr+= len; + + return len; +} + +static __dfufunc void handle_getstatus(void) +{ + struct dfu_status dstat; + + DEBUGE("getstatus "); + + /* send status response */ + dstat.bStatus = status; + dstat.bState = dfu_state; + dstat.iString = 0; + udp_ep0_send_data(&dstat, sizeof(dstat)); +} + +static void __dfufunc handle_getstate(void) +{ + u_int8_t u8 = dfu_state; + DEBUGE("getstate "); + udp_ep0_send_data((char *)&u8, sizeof(u8)); +} + +/* callback function for DFU requests */ +int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req, + u_int16_t val, u_int16_t len) +{ + int rc; + + DEBUGE("old_state = %u ", dfu_state); + + switch (dfu_state) { + case DFU_STATE_appIDLE: + if (req != USB_REQ_DFU_DETACH) + goto send_stall; + dfu_state = DFU_STATE_appDETACH; + goto send_zlp; + break; + case DFU_STATE_appDETACH: + switch (req) { + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + default: + dfu_state = DFU_STATE_appIDLE; + goto send_stall; + break; + } + /* FIXME: implement timer to return to appIDLE */ + break; + case DFU_STATE_dfuIDLE: + switch (req) { + case USB_REQ_DFU_DNLOAD: + if (len == 0) { + dfu_state = DFU_STATE_dfuERROR; + goto send_stall; + } + handle_dnload(val, len); + break; + case USB_REQ_DFU_UPLOAD: + ptr = 0; + dfu_state = DFU_STATE_dfuUPLOAD_IDLE; + handle_upload(val, len); + break; + case USB_REQ_DFU_ABORT: + /* no zlp? */ + goto send_zlp; + break; + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + default: + dfu_state = DFU_STATE_dfuERROR; + goto send_stall; + break; + } + break; + case DFU_STATE_dfuDNLOAD_SYNC: + switch (req) { + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + /* FIXME: state transition depending on block completeness */ + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + default: + dfu_state = DFU_STATE_dfuERROR; + goto send_stall; + } + break; + case DFU_STATE_dfuDNBUSY: + dfu_state = DFU_STATE_dfuERROR; + goto send_stall; + break; + case DFU_STATE_dfuDNLOAD_IDLE: + switch (req) { + case USB_REQ_DFU_DNLOAD: + if (handle_dnload(val, len)) + /* FIXME: state transition */ + break; + case USB_REQ_DFU_ABORT: + dfu_state = DFU_STATE_dfuIDLE; + goto send_zlp; + break; + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + default: + dfu_state = DFU_STATE_dfuERROR; + goto send_stall; + break; + } + break; + case DFU_STATE_dfuMANIFEST_SYNC: + switch (req) { + case USB_REQ_DFU_GETSTATUS: + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + default: + dfu_state = DFU_STATE_dfuERROR; + goto send_stall; + break; + } + break; + case DFU_STATE_dfuMANIFEST: + dfu_state = DFU_STATE_dfuERROR; + goto send_stall; + break; + case DFU_STATE_dfuMANIFEST_WAIT_RST: + /* we should never go here */ + break; + case DFU_STATE_dfuUPLOAD_IDLE: + switch (req) { + case USB_REQ_DFU_UPLOAD: + /* state transition if less data then requested */ + rc = handle_upload(val, len); + if (rc >= 0 && rc < len) + dfu_state = DFU_STATE_dfuIDLE; + break; + case USB_REQ_DFU_ABORT: + dfu_state = DFU_STATE_dfuIDLE; + /* no zlp? */ + goto send_zlp; + break; + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + default: + dfu_state = DFU_STATE_dfuERROR; + goto send_stall; + break; + } + break; + case DFU_STATE_dfuERROR: + switch (req) { + case USB_REQ_DFU_GETSTATUS: + handle_getstatus(); + break; + case USB_REQ_DFU_GETSTATE: + handle_getstate(); + break; + case USB_REQ_DFU_CLRSTATUS: + dfu_state = DFU_STATE_dfuIDLE; + /* no zlp? */ + goto send_zlp; + break; + default: + dfu_state = DFU_STATE_dfuERROR; + goto send_stall; + break; + } + break; + } + + DEBUGE("OK new_state = %u\r\n", dfu_state); + return 0; + +send_stall: + udp_ep0_send_stall(); + DEBUGE("STALL new_state = %u\r\n", dfu_state); + return -EINVAL; + +send_zlp: + udp_ep0_send_zlp(); + DEBUGE("ZLP new_state = %u\r\n", dfu_state); + return 0; +} +static u_int8_t cur_config; + +/* USB DFU Device descriptor in DFU mode */ +__dfustruct struct usb_device_descriptor dfu_dev_descriptor = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0100, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = 8, + .idVendor = OPENPCD_VENDOR_ID, + .idProduct = OPENPCD_PRODUCT_ID, + .bcdDevice = 0x0000, + .iManufacturer = 0x00, + .iProduct = 0x00, + .iSerialNumber = 0x00, + .bNumConfigurations = 0x01, +}; + +/* USB DFU Config descriptor in DFU mode */ +__dfustruct struct _dfu_desc dfu_cfg_descriptor = { + .ucfg = { + .bLength = USB_DT_CONFIG_SIZE, + .bDescriptorType = USB_DT_CONFIG, + .wTotalLength = USB_DT_CONFIG_SIZE + + 2* USB_DT_INTERFACE_SIZE + + USB_DT_DFU_SIZE, + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = USB_CONFIG_ATT_ONE, + .bMaxPower = 100, + }, + .uif[0] = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0x00, + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x00, + .bInterfaceClass = 0xfe, + .bInterfaceSubClass = 0x01, + .bInterfaceProtocol = 0x02, + .iInterface = 0, + }, + .uif[1] = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0x00, + .bAlternateSetting = 0x01, + .bNumEndpoints = 0x00, + .bInterfaceClass = 0xfe, + .bInterfaceSubClass = 0x01, + .bInterfaceProtocol = 0x02, + .iInterface = 0, + }, + + .func_dfu = DFU_FUNC_DESC, +}; + + +/* minimal USB EP0 handler in DFU mode */ +static __dfufunc void dfu_udp_ep0_handler(void) +{ + AT91PS_UDP pUDP = AT91C_BASE_UDP; + u_int8_t bmRequestType, bRequest; + u_int16_t wValue, wIndex, wLength, wStatus; + u_int32_t csr = pUDP->UDP_CSR[0]; + + DEBUGE("CSR=0x%04x ", csr); + + if (csr & AT91C_UDP_STALLSENT) { + DEBUGE("ACK_STALLSENT "); + pUDP->UDP_CSR[0] = ~AT91C_UDP_STALLSENT; + } + + if (csr & AT91C_UDP_RX_DATA_BK0) { + DEBUGE("ACK_BANK0 "); + pUDP->UDP_CSR[0] &= ~AT91C_UDP_RX_DATA_BK0; + } + + if (!(csr & AT91C_UDP_RXSETUP)) { + DEBUGE("no setup packet "); + return; + } + + DEBUGE("len=%d ", csr >> 16); + if (csr >> 16 == 0) { + DEBUGE("empty packet "); + return; + } + + bmRequestType = pUDP->UDP_FDR[0]; + bRequest = pUDP->UDP_FDR[0]; + wValue = (pUDP->UDP_FDR[0] & 0xFF); + wValue |= (pUDP->UDP_FDR[0] << 8); + wIndex = (pUDP->UDP_FDR[0] & 0xFF); + wIndex |= (pUDP->UDP_FDR[0] << 8); + wLength = (pUDP->UDP_FDR[0] & 0xFF); + wLength |= (pUDP->UDP_FDR[0] << 8); + + DEBUGE("bmRequestType=0x%2x ", bmRequestType); + + if (bmRequestType & 0x80) { + DEBUGE("DATA_IN=1 "); + pUDP->UDP_CSR[0] |= AT91C_UDP_DIR; + while (!(pUDP->UDP_CSR[0] & AT91C_UDP_DIR)) ; + } + pUDP->UDP_CSR[0] &= ~AT91C_UDP_RXSETUP; + while ((pUDP->UDP_CSR[0] & AT91C_UDP_RXSETUP)) ; + + /* Handle supported standard device request Cf Table 9-3 in USB + * speciication Rev 1.1 */ + switch ((bRequest << 8) | bmRequestType) { + case STD_GET_DESCRIPTOR: + DEBUGE("GET_DESCRIPTOR "); + if (wValue == 0x100) { + /* Return Device Descriptor */ + udp_ep0_send_data((const char *) + &dfu_dev_descriptor, + MIN(sizeof(dfu_dev_descriptor), + wLength)); + } else if (wValue == 0x200) { + /* Return Configuration Descriptor */ + udp_ep0_send_data((const char *) + &dfu_cfg_descriptor, + MIN(sizeof(dfu_cfg_descriptor), + wLength)); +#if 0 + } else if (wValue == 0x400) { + /* Return Interface descriptor */ + if (wIndex != 0x01) + udp_ep0_send_stall(); + udp_ep0_send_data((const char *) + &dfu_if_descriptor, + MIN(sizeof(dfu_if_descriptor), + wLength)); +#endif + } else + udp_ep0_send_stall(); + break; + case STD_SET_ADDRESS: + DEBUGE("SET_ADDRESS "); + udp_ep0_send_zlp(); + pUDP->UDP_FADDR = (AT91C_UDP_FEN | wValue); + pUDP->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0; + break; + case STD_SET_CONFIGURATION: + DEBUGE("SET_CONFIG "); + if (wValue) + DEBUGE("VALUE!=0 "); + cur_config = wValue; + udp_ep0_send_zlp(); + pUDP->UDP_GLBSTATE = + (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN; + pUDP->UDP_CSR[1] = + (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : + 0; + pUDP->UDP_CSR[2] = + (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0; + pUDP->UDP_CSR[3] = + (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0; + pUDP->UDP_IER = (AT91C_UDP_EPINT0|AT91C_UDP_EPINT1| + AT91C_UDP_EPINT2|AT91C_UDP_EPINT3); + break; + case STD_GET_CONFIGURATION: + DEBUGE("GET_CONFIG "); + udp_ep0_send_data((char *)&(cur_config), + sizeof(cur_config)); + break; + case STD_GET_STATUS_ZERO: + DEBUGE("GET_STATUS_ZERO "); + wStatus = 0; + udp_ep0_send_data((char *)&wStatus, sizeof(wStatus)); + break; + case STD_GET_STATUS_INTERFACE: + DEBUGE("GET_STATUS_INTERFACE "); + wStatus = 0; + udp_ep0_send_data((char *)&wStatus, sizeof(wStatus)); + break; + case STD_GET_STATUS_ENDPOINT: + DEBUGE("GET_STATUS_ENDPOINT(EPidx=%u) ", wIndex&0x0f); + wStatus = 0; + wIndex &= 0x0F; + if ((pUDP->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex == 0)) { + wStatus = + (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; + udp_ep0_send_data((char *)&wStatus, + sizeof(wStatus)); + } else if ((pUDP->UDP_GLBSTATE & AT91C_UDP_FADDEN) + && (wIndex == 0)) { + wStatus = + (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; + udp_ep0_send_data((char *)&wStatus, + sizeof(wStatus)); + } else + udp_ep0_send_stall(); + break; + case STD_SET_FEATURE_ZERO: + DEBUGE("SET_FEATURE_ZERO "); + udp_ep0_send_stall(); + break; + case STD_SET_FEATURE_INTERFACE: + DEBUGE("SET_FEATURE_INTERFACE "); + udp_ep0_send_zlp(); + break; + case STD_SET_FEATURE_ENDPOINT: + DEBUGE("SET_FEATURE_ENDPOINT "); + udp_ep0_send_stall(); + break; + case STD_CLEAR_FEATURE_ZERO: + DEBUGE("CLEAR_FEATURE_ZERO "); + udp_ep0_send_stall(); + break; + case STD_CLEAR_FEATURE_INTERFACE: + DEBUGE("CLEAR_FEATURE_INTERFACE "); + udp_ep0_send_zlp(); + break; + case STD_CLEAR_FEATURE_ENDPOINT: + DEBUGE("CLEAR_FEATURE_ENDPOINT(EPidx=%u) ", wIndex & 0x0f); + udp_ep0_send_stall(); + break; + case STD_SET_INTERFACE: + DEBUGE("SET INTERFACE "); + udp_ep0_send_stall(); + break; + default: + DEBUGE("DEFAULT(req=0x%02x, type=0x%02x) ", bRequest, bmRequestType); + if ((bmRequestType & 0x3f) == USB_TYPE_DFU) { + dfu_ep0_handler(bmRequestType, bRequest, wValue, wLength); + } else + udp_ep0_send_stall(); + break; + } +} + +/* minimal USB IRQ handler in DFU mode */ +static __dfufunc void dfu_udp_irq(void) +{ + AT91PS_UDP pUDP = AT91C_BASE_UDP; + AT91_REG isr = pUDP->UDP_ISR; + + if (isr & AT91C_UDP_ENDBUSRES) { + pUDP->UDP_IER = AT91C_UDP_EPINT0; + /* reset all endpoints */ + pUDP->UDP_RSTEP = (unsigned int)-1; + pUDP->UDP_RSTEP = 0; + /* Enable the function */ + pUDP->UDP_FADDR = AT91C_UDP_FEN; + /* Configure endpoint 0 */ + pUDP->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); + cur_config = 0; + } + + if (isr & AT91C_UDP_EPINT0) + dfu_udp_ep0_handler(); + + /* clear all interrupts */ + pUDP->UDP_ICR = isr; + + AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_UDP); +} + +/* this is only called once before DFU mode, no __dfufunc required */ +static void dfu_switch(void) +{ + AT91PS_AIC pAic = AT91C_BASE_AIC; + + DEBUGE("Switching to DFU mode "); + + pAic->AIC_SVR[AT91C_ID_UDP] = (unsigned int) &dfu_udp_irq; + dfu_state = DFU_STATE_dfuIDLE; +} + +void __dfufunc dfu_main(void) +{ + /* + AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_UDP, + OPENPCD_IRQ_PRIO_UDP, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, dfu_udp_irq); + */ + + AT91PS_AIC pAic = AT91C_BASE_AIC; + pAic->AIC_IDCR = 1 << AT91C_ID_UDP; + pAic->AIC_SVR[AT91C_ID_UDP] = (unsigned int) &dfu_udp_irq; + pAic->AIC_SMR[AT91C_ID_UDP] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | + OPENPCD_IRQ_PRIO_UDP; + pAic->AIC_ICCR = 1 << AT91C_ID_UDP; + + AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_UDP); + + /* End-of-Bus-Reset is always enabled */ + + /* Clear for set the Pull up resistor */ + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); + + /* do nothing, since all of DFU is interrupt driven */ + while (1) ; +} + +struct dfuapi __dfufunctab dfu_api = { + .ep0_send_data = &udp_ep0_send_data, + .ep0_send_zlp = &udp_ep0_send_zlp, + .ep0_send_stall = &udp_ep0_send_stall, + .dfu_ep0_handler = &dfu_ep0_handler, + .dfu_switch = &dfu_switch, + .dfu_state = &dfu_state, + .dfu_dev_descriptor = &dfu_dev_descriptor, + .dfu_cfg_descriptor = &dfu_cfg_descriptor, +}; + +int foo = 12345; diff --git a/openpcd/firmware/src/os/dfu.h b/openpcd/firmware/src/os/dfu.h new file mode 100644 index 0000000..a663688 --- /dev/null +++ b/openpcd/firmware/src/os/dfu.h @@ -0,0 +1,80 @@ +#ifndef _DFU_H +#define _DFU_H + +/* USB Device Firmware Update Implementation for OpenPCD + * (C) 2006 by Harald Welte + * + * This ought to be compliant to the USB DFU Spec 1.0 as available from + * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf + * + */ + +#include +#include +#include + +#include "dbgu.h" + +/* USB DFU functional descriptor */ +#define DFU_FUNC_DESC { \ + .bLength = USB_DT_DFU_SIZE, \ + .bDescriptorType = USB_DT_DFU, \ + .bmAttributes = USB_DFU_CAN_UPLOAD | USB_DFU_CAN_DOWNLOAD, \ + .wDetachTimeOut = 0xff00, \ + .wTransferSize = AT91C_IFLASH_PAGE_SIZE, \ + .bcdDFUVersion = 0x0100, \ +} + +/* USB Interface descriptor in Runtime mode */ +#define DFU_RT_IF_DESC { \ + .bLength = USB_DT_INTERFACE_SIZE, \ + .bDescriptorType = USB_DT_INTERFACE, \ + .bInterfaceNumber = 0x01, \ + .bAlternateSetting = 0x00, \ + .bNumEndpoints = 0x00, \ + .bInterfaceClass = 0xfe, \ + .bInterfaceSubClass = 0x01, \ + .bInterfaceProtocol = 0x01, \ + .iInterface = 1, \ +} + +#define __dfufunc __attribute__ ((long_call, section (".dfu.func"))) +#define __dfustruct __attribute__ ((section (".dfu.struct"))) const +#define __dfufunctab __attribute__ ((section (".dfu.functab"))) + +#if 0 +extern void __dfufunc udp_ep0_send_data(const char *data, u_int32_t length); +extern void __dfufunc udp_ep0_send_zlp(void); +extern void __dfufunc udp_ep0_send_stall(void); +extern __dfustruct struct usb_device_descriptor dfu_dev_descriptor; +extern __dfustruct struct _dfu_desc dfu_cfg_descriptor; +extern void dfu_switch(void); +extern int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req, + u_int16_t val, u_int16_t len); +extern static u_int8_t dfu_state; +struct udp_pcd; +#endif + + +extern void udp_init(void); + +struct _dfu_desc { + struct usb_config_descriptor ucfg; + struct usb_interface_descriptor uif[2]; + struct usb_dfu_func_descriptor func_dfu; +}; + +struct dfuapi { + void (*ep0_send_data)(const char *data, u_int32_t len); + void (*ep0_send_zlp)(void); + void (*ep0_send_stall)(void); + int (*dfu_ep0_handler)(u_int8_t req_type, u_int8_t req, + u_int16_t val, u_int16_t len); + void (*dfu_switch)(void); + u_int8_t *dfu_state; + struct usb_device_descriptor *dfu_dev_descriptor; + struct _dfu_desc *dfu_cfg_descriptor; +}; + + +#endif /* _DFU_H */ diff --git a/openpcd/firmware/src/os/fifo.c b/openpcd/firmware/src/os/fifo.c new file mode 100644 index 0000000..b0ec152 --- /dev/null +++ b/openpcd/firmware/src/os/fifo.c @@ -0,0 +1,108 @@ +/* Implementation of a virtual FIFO */ + +#include "fifo.h" + +#include +#include + +#define FIFO_IRQ_LO 0x01 +#define FIFO_IRQ_HI 0x02 +#define FIFO_IRQ_OFLOW 0x04 + +/* returns number of data bytes present in the fifo */ +int fifo_available(struct fifo *fifo) +{ + if (fifo->producer > fifo->consumer) + return fifo->producer - fifo->consumer; + else + return (fifo->size - fifo->consumer) + fifo->producer; +} + +void fifo_check_water(struct fifo *fifo) +{ + int avail = fifo_available(fifo); + + if (avail <= fifo->watermark) + fifo->irq |= FIFO_IRQ_LO; + else + fifo->irq &= FIFO_IRQ_LO; + + if (fifo->size - avail >= fifo->watermark) + fifo->irq |= FIFO_IRQ_HI; + else + fifo->irq &= FIFO_IRQ_HI; +} + +void fifo_check_raise_int(struct fifo *fifo) +{ + if (fifo->irq & fifo->irq_en) + fifo->callback(fifo, fifo->irq, fifo->cb_data); +} + + +u_int16_t fifo_data_put(struct fifo *fifo, u_int16_t len, u_int8_t *data) +{ + if (len > fifo_available(fifo)) { + len = fifo_available(fifo); + fifo->irq |= FIFO_IRQ_OFLOW; + } + + if (len + fifo->producer <= fifo->size) { + /* easy case */ + memcpy(&fifo->data[fifo->producer], data, len); + fifo->producer += len; + } else { + /* difficult: wrap around */ + u_int16_t chunk_len; + + chunk_len = fifo->size - fifo->producer; + memcpy(&fifo->data[fifo->producer], data, chunk_len); + + memcpy(&fifo->data[0], data + chunk_len, len - chunk_len); + fifo->producer = len - chunk_len; + } + + fifo_check_water(fifo); + + return len; +} + + +u_int16_t fifo_data_get(struct fifo *fifo, u_int16_t len, u_int8_t *data) +{ + u_int16_t avail = fifo_available(fifo); + + if (avail < len) + len = avail; + + if (fifo->producer > fifo->consumer) { + /* easy case */ + memcpy(data, &fifo->data[fifo->consumer], len); + } else { + /* difficult case: wrap */ + u_int16_t chunk_len = fifo->size - fifo->consumer; + memcpy(data, &fifo->data[fifo->consumer], chunk_len); + memcpy(data+chunk_len, &fifo->data[0], len - chunk_len); + } + + fifo_check_water(fifo); + + return len; +} + +int fifo_init(struct fifo *fifo, u_int16_t size, + void (*cb)(struct fifo *fifo, u_int8_t event, void *data), void *cb_data) +{ + if (size > sizeof(fifo->data)) + return -EINVAL; + + memset(fifo->data, 0, sizeof(fifo->data)); + fifo->size = size; + fifo->producer = fifo->consumer = 0; + fifo->watermark = 0; + fifo->callback = cb; + fifo->cb_data = cb_data; + + return 0; +} + diff --git a/openpcd/firmware/src/os/fifo.h b/openpcd/firmware/src/os/fifo.h new file mode 100644 index 0000000..d91c6c2 --- /dev/null +++ b/openpcd/firmware/src/os/fifo.h @@ -0,0 +1,28 @@ +#ifndef _FIFO_H +#define _FIFO_H + +#include + +#define FIFO_SIZE 1024 + +struct fifo { + u_int16_t size; /* actual FIFO size, can be smaller than 'data' */ + u_int16_t producer; /* index of producer */ + u_int16_t consumer; /* index of consumer */ + u_int16_t watermark; + u_int8_t irq; + u_int8_t irq_en; + u_int8_t status; + void (*callback)(struct fifo *fifo, u_int8_t event, void *data); + void *cb_data; + u_int8_t data[FIFO_SIZE]; +}; + + +extern int fifo_init(struct fifo *fifo, u_int16_t size, + void (*callback)(struct fifo *fifo, u_int8_t event, void *data), void *cb_data); +extern u_int16_t fifo_data_get(struct fifo *fifo, u_int16_t len, u_int8_t *data); +extern u_int16_t fifo_data_put(struct fifo *fifo, u_int16_t len, u_int8_t *data); +extern int fifo_available(struct fifo *fifo); + +#endif diff --git a/openpcd/firmware/src/os/flash.c b/openpcd/firmware/src/os/flash.c new file mode 100644 index 0000000..2aaf760 --- /dev/null +++ b/openpcd/firmware/src/os/flash.c @@ -0,0 +1,45 @@ + + +#define EFCS_CMD_WRITE_PAGE 0x01 +#define EFCS_CMD_SET_LOCK_BIT 0x02 +#define EFCS_CMD_WRITE_PAGE_LOCK 0x03 +#define EFCS_CMD_CLEAR_LOCK 0x04 +#define EFCS_CMD_ERASE_ALL 0x08 +#define EFCS_CMD_SET_NVM_BIT 0x0b +#define EFCS_CMD_CLEAR_NVM_BIT 0x0d +#define EFCS_CMD_SET_SECURITY_BIT 0x0f + + +int unlock_page(u_int16_t page) +{ + AT91C_MC_FCMD_UNLOCK | AT91C_MC_CORRECT_KEY | + +} + +int flash_sector(unsigned int sector, const u_int8_t *data, unsigned int len) +{ + volatile u_int32_t *p = (volatile u_int32_t *)0; + u_int32_t *src32 = (u_int32_t *)data; + int i; + + /* hand-code memcpy because we need to make sure only 32bit accesses + * are used */ + for (i = 0; i < len/4; i++) + p[i] = src32[i]; + + AT91F_MC_EFC_PerformCmd(pmc , AT91C_MC_FCMD_START_PROG| + AT91C_MC_CORRECT_KEY | ); +} + + +void flash_init(void) +{ + unsigned int fmcn = AT91F_MC_EFC_ComputerFMCN(48000000); + + AT91F_MC_EFC_CfgModeReg(ff, fmcn << 16 | AT91C_MC_FWS_3FWS | + AT91C_MC_FRDY | AT91C_MC_LOCKE | + AT91C_MC_PROGE); + + AT91F_AIC_EnableIt(); + +} diff --git a/openpcd/firmware/src/os/led.c b/openpcd/firmware/src/os/led.c new file mode 100644 index 0000000..8c34c6c --- /dev/null +++ b/openpcd/firmware/src/os/led.c @@ -0,0 +1,85 @@ + +#include +#include +#include +#include +#include "../openpcd.h" +#include +#include +#include + +static int led2port(int led) +{ + if (led == 1) + return OPENPCD_PIO_LED1; + else if (led == 2) + return OPENPCD_PIO_LED2; + else + return 0; +} + +void led_switch(int led, int on) +{ + int port = led2port(led); + + if (port == -1) + return; + + if (on) + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, port); + else + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, port); +} + +int led_get(int led) +{ + int port = led2port(led); + + if (port == -1) + return -1; + + return !(AT91F_PIO_GetOutputDataStatus(AT91C_BASE_PIOA) & port); +} + +int led_toggle(int led) +{ + int on = led_get(led); + if (on == -1) + return -1; + + if (on) + led_switch(led, 0); + else + led_switch(led, 1); + + 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/openpcd/firmware/src/os/led.h b/openpcd/firmware/src/os/led.h new file mode 100644 index 0000000..394107b --- /dev/null +++ b/openpcd/firmware/src/os/led.h @@ -0,0 +1,9 @@ +#ifndef _LED_H +#define _LED_H + +extern void led_init(void); +extern void led_switch(int led, int on); +extern int led_get(int led); +extern int led_toggle(int led); + +#endif diff --git a/openpcd/firmware/src/os/main.c b/openpcd/firmware/src/os/main.c new file mode 100644 index 0000000..c40fd79 --- /dev/null +++ b/openpcd/firmware/src/os/main.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include "../openpcd.h" + +int main(void) +{ + /* initialize LED and debug unit */ + led_init(); + AT91F_DBGU_Init(); + + /* call application specific init function */ + _init_func(); + + // Enable User Reset and set its minimal assertion to 960 us + AT91C_BASE_RSTC->RSTC_RMR = + AT91C_RSTC_URSTEN | (0x4 << 8) | (unsigned int)(0xA5 << 24); + +#ifdef DEBUG_CLOCK_PA6 + AT91F_PMC_EnablePCK(AT91C_BASE_PMC, 0, AT91C_PMC_CSS_PLL_CLK); + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, AT91C_PA6_PCK0); +#endif + + /* switch on first led */ + led_switch(1, 1); + + DEBUGPCRF("entering main (idle) loop"); + while (1) { + /* Call application specific main idle function */ + _main_func(); + dbgu_rb_flush(); + } +} diff --git a/openpcd/firmware/src/os/main.h b/openpcd/firmware/src/os/main.h new file mode 100644 index 0000000..1adc8f6 --- /dev/null +++ b/openpcd/firmware/src/os/main.h @@ -0,0 +1,8 @@ +#ifndef _MAIN_H +#define _MAIN_H + +extern void _init_func(void); +extern int _main_dbgu(char key); +extern void _main_func(void); + +#endif diff --git a/openpcd/firmware/src/os/pcd_enumerate.c b/openpcd/firmware/src/os/pcd_enumerate.c new file mode 100644 index 0000000..ed71a50 --- /dev/null +++ b/openpcd/firmware/src/os/pcd_enumerate.c @@ -0,0 +1,610 @@ +/* AT91SAM7 USB interface code for OpenPCD + * + * (C) 2006 by Harald Welte + * + * based on existing AT91SAM7 UDP CDC ACM example code, licensed as followed: + *---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support - ROUSSET - + *---------------------------------------------------------------------------- + * The software is delivered "AS IS" without warranty or condition of any + * kind, either express, implied or statutory. This includes without + * limitation any warranty or condition with respect to merchantability or + * fitness for any particular purpose, or against the infringements of + * intellectual property rights of others. + *---------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "../openpcd.h" +#include + +#define DEBUG_UDP_IRQ +#define DEBUG_UDP_EP0 + +#define CONFIG_DFU + +#define AT91C_EP_OUT 1 +#define AT91C_EP_OUT_SIZE 0x40 +#define AT91C_EP_IN 2 +#define AT91C_EP_IN_SIZE 0x40 +#define AT91C_EP_INT 3 + +#ifdef CONFIG_DFU +#define DFU_API_LOCATION ((const struct dfuapi *) 0x1f00) +static const struct dfuapi *dfu = DFU_API_LOCATION; +#define udp_ep0_send_data dfu->ep0_send_data +#define udp_ep0_send_zlp dfu->ep0_send_zlp +#define udp_ep0_send_stall dfu->ep0_send_stall +#else +#error non-DFU builds currently not supported (yet) again +#endif + +static struct udp_pcd upcd; + +const struct usb_device_descriptor dev_descriptor = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = USB_CLASS_VENDOR_SPEC, + .bDeviceSubClass = 0xff, + .bDeviceProtocol = 0xff, + .bMaxPacketSize0 = 0x08, + .idVendor = OPENPCD_VENDOR_ID, + .idProduct = OPENPCD_PRODUCT_ID, + .bcdDevice = 0x0000, + .iManufacturer = 0x00, + .iProduct = 0x00, + .iSerialNumber = 0x00, + .bNumConfigurations = 0x01, +}; + +struct _desc { + struct usb_config_descriptor ucfg; + struct usb_interface_descriptor uif; + struct usb_endpoint_descriptor ep[3]; +#ifdef CONFIG_DFU + struct usb_interface_descriptor uif_dfu; + struct usb_dfu_func_descriptor func_dfu; +#endif +}; + +const struct _desc cfg_descriptor = { + .ucfg = { + .bLength = USB_DT_CONFIG_SIZE, + .bDescriptorType = USB_DT_CONFIG, + .wTotalLength = USB_DT_CONFIG_SIZE + +#ifdef CONFIG_DFU + 2 * USB_DT_INTERFACE_SIZE + + 3 * USB_DT_ENDPOINT_SIZE + + USB_DT_DFU_SIZE, + .bNumInterfaces = 2, +#else + 1 * USB_DT_INTERFACE_SIZE + + 3 * USB_DT_ENDPOINT_SIZE, + .bNumInterfaces = 1, +#endif + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = USB_CONFIG_ATT_ONE, + .bMaxPower = 100, /* 200mA */ + }, + .uif = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 3, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0xff, + .iInterface = 0, + }, + .ep= { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = OPENPCD_OUT_EP, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = AT91C_EP_OUT_SIZE, + .bInterval = 0x00, + }, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = OPENPCD_IN_EP, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = AT91C_EP_IN_SIZE, + .bInterval = 0x00, + }, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = OPENPCD_IRQ_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = AT91C_EP_IN_SIZE, + .bInterval = 0xff, /* FIXME */ + }, + }, +#ifdef CONFIG_DFU + .uif_dfu = DFU_RT_IF_DESC, + .func_dfu = DFU_FUNC_DESC, +#endif +}; + +static const struct usb_string_descriptor string0 = { + .bLength = sizeof(string0), + .bDescriptorType = USB_DT_STRING, + .wData[0] = 0x0409, /* English */ +}; + + +static void udp_ep0_handler(void); + +void udp_unthrottle(void) +{ + AT91PS_UDP pUDP = upcd.pUdp; + pUDP->UDP_IER = AT91C_UDP_EPINT1; +} + +int udp_refill_ep(int ep, struct req_ctx *rctx) +{ + u_int16_t i; + AT91PS_UDP pUDP = upcd.pUdp; + + 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 (atomic_read(&upcd.ep[ep].pkts_in_transit) == 2) + return -EBUSY; + + /* fill FIFO/DPR */ + for (i = 0; i < rctx->tx.tot_len; i++) + pUDP->UDP_FDR[ep] = rctx->tx.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; + } + + /* return rctx to pool of free contexts */ + req_ctx_put(rctx); + + return 0; +} + +#ifdef DEBUG_UDP_IRQ +#define DEBUGI(x, args ...) DEBUGP(x, ## args) +#else +#define DEBUGI(x, args ...) do { } while (0) +#endif + +static void udp_irq(void) +{ + u_int32_t csr; + AT91PS_UDP pUDP = upcd.pUdp; + AT91_REG isr = pUDP->UDP_ISR; + + DEBUGI("udp_irq(imr=0x%04x, isr=0x%04x): ", pUDP->UDP_IMR, isr); + + if (isr & AT91C_UDP_ENDBUSRES) { + DEBUGI("ENDBUSRES "); + pUDP->UDP_ICR = AT91C_UDP_ENDBUSRES; + pUDP->UDP_IER = AT91C_UDP_EPINT0; + /* reset all endpoints */ + pUDP->UDP_RSTEP = (unsigned int)-1; + pUDP->UDP_RSTEP = 0; + /* Enable the function */ + pUDP->UDP_FADDR = AT91C_UDP_FEN; + /* Configure endpoint 0 */ + pUDP->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); + upcd.cur_config = 0; + +#ifdef CONFIG_DFU + if (*dfu->dfu_state == DFU_STATE_appDETACH) { + /* now we need to switch to DFU mode */ + dfu->dfu_switch(); + } +#endif + } + + if (isr & AT91C_UDP_EPINT0) { + DEBUGI("EP0INT(Control) "); + udp_ep0_handler(); + } + if (isr & AT91C_UDP_EPINT1) { + u_int32_t cur_rcv_bank = upcd.cur_rcv_bank; + csr = pUDP->UDP_CSR[1]; + DEBUGI("EP1INT(Out, CSR=0x%08x) ", csr); + if (cur_rcv_bank == AT91C_UDP_RX_DATA_BK1) + DEBUGI("cur_bank=1 "); + else if (cur_rcv_bank == AT91C_UDP_RX_DATA_BK0) + DEBUGI("cur_bank=0 "); + else + DEBUGI("cur_bank INVALID "); + + if (csr & AT91C_UDP_RX_DATA_BK1) + DEBUGI("BANK1 "); + if (csr & AT91C_UDP_RX_DATA_BK0) + DEBUGI("BANK0 "); + + 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); + + if (rctx) { + rctx->rx.tot_len = pkt_size; + while (pkt_size--) + rctx->rx.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; + req_ctx_set_state(rctx, RCTX_STATE_UDP_RCV_DONE); + DEBUGI("RCTX=%u ", req_ctx_num(rctx)); + } else { + /* disable interrupts for now */ + pUDP->UDP_IDR = AT91C_UDP_EPINT1; + DEBUGP("NO_RCTX_AVAIL! "); + } + } + } + if (isr & AT91C_UDP_EPINT2) { + 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; + while (pUDP->UDP_CSR[2] & AT91C_UDP_TXCOMP) ; + + /* if we already have another packet in DPR, send it */ + 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 "); + } + } + 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 (isr & AT91C_UDP_RXSUSP) { + pUDP->UDP_ICR = AT91C_UDP_RXSUSP; + DEBUGI("RXSUSP "); + /* FIXME: implement suspend/resume */ + } + if (isr & AT91C_UDP_RXRSM) { + pUDP->UDP_ICR = AT91C_UDP_RXRSM; + DEBUGI("RXRSM "); + /* FIXME: implement suspend/resume */ + } + if (isr & AT91C_UDP_EXTRSM) { + pUDP->UDP_ICR = AT91C_UDP_EXTRSM; + DEBUGI("EXTRSM "); + /* FIXME: implement suspend/resume */ + } + if (isr & AT91C_UDP_SOFINT) { + pUDP->UDP_ICR = AT91C_UDP_SOFINT; + DEBUGI("SOFINT "); + } + if (isr & AT91C_UDP_WAKEUP) { + pUDP->UDP_ICR = AT91C_UDP_WAKEUP; + DEBUGI("WAKEUP "); + /* FIXME: implement suspend/resume */ + } + + DEBUGI("END\r\n"); + AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_UDP); +} + +/* Open USB Device Port */ +void udp_open(void) +{ + DEBUGPCRF("entering"); + upcd.pUdp = AT91C_BASE_UDP; + upcd.cur_config = 0; + upcd.cur_rcv_bank = AT91C_UDP_RX_DATA_BK0; + + AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_UDP, + OPENPCD_IRQ_PRIO_UDP, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, udp_irq); + AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_UDP); + + /* End-of-Bus-Reset is always enabled */ + + /* Clear for set the Pull up resistor */ + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); +} + +void udp_reset(void) +{ + volatile int i; + + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); + for (i = 0; i < 0xffff; i++) + ; + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); +} + +#ifdef DEBUG_UDP_EP0 +#define DEBUGE(x, args ...) DEBUGP(x, ## args) +#else +#define DEBUGE(x, args ...) do { } while (0) +#endif + +/* Handle requests on the USB Control Endpoint */ +static void udp_ep0_handler(void) +{ + AT91PS_UDP pUDP = upcd.pUdp; + u_int8_t bmRequestType, bRequest; + u_int16_t wValue, wIndex, wLength, wStatus; + u_int32_t csr = pUDP->UDP_CSR[0]; + + DEBUGE("CSR=0x%04x ", csr); + + if (csr & AT91C_UDP_STALLSENT) { + DEBUGE("ACK_STALLSENT "); + pUDP->UDP_CSR[0] = ~AT91C_UDP_STALLSENT; + } + + if (csr & AT91C_UDP_RX_DATA_BK0) { + DEBUGE("ACK_BANK0 "); + pUDP->UDP_CSR[0] &= ~AT91C_UDP_RX_DATA_BK0; + } + + if (!(csr & AT91C_UDP_RXSETUP)) { + DEBUGE("no setup packet "); + return; + } + + DEBUGE("len=%d ", csr >> 16); + if (csr >> 16 == 0) { + DEBUGE("empty packet "); + return; + } + + bmRequestType = pUDP->UDP_FDR[0]; + bRequest = pUDP->UDP_FDR[0]; + wValue = (pUDP->UDP_FDR[0] & 0xFF); + wValue |= (pUDP->UDP_FDR[0] << 8); + wIndex = (pUDP->UDP_FDR[0] & 0xFF); + wIndex |= (pUDP->UDP_FDR[0] << 8); + wLength = (pUDP->UDP_FDR[0] & 0xFF); + wLength |= (pUDP->UDP_FDR[0] << 8); + + DEBUGE("bmRequestType=0x%2x ", bmRequestType); + + if (bmRequestType & 0x80) { + DEBUGE("DATA_IN=1 "); + pUDP->UDP_CSR[0] |= AT91C_UDP_DIR; + while (!(pUDP->UDP_CSR[0] & AT91C_UDP_DIR)) ; + } + pUDP->UDP_CSR[0] &= ~AT91C_UDP_RXSETUP; + while ((pUDP->UDP_CSR[0] & AT91C_UDP_RXSETUP)) ; + + /* Handle supported standard device request Cf Table 9-3 in USB + * speciication Rev 1.1 */ + switch ((bRequest << 8) | bmRequestType) { + case STD_GET_DESCRIPTOR: + DEBUGE("GET_DESCRIPTOR "); + if (wValue == 0x100) { + /* Return Device Descriptor */ +#ifdef CONFIG_DFU + if (*dfu->dfu_state != DFU_STATE_appIDLE) + udp_ep0_send_data((const char *) + dfu->dfu_dev_descriptor, + MIN(dfu->dfu_dev_descriptor->bLength, + wLength)); + else +#endif + udp_ep0_send_data((const char *) &dev_descriptor, + MIN(sizeof(dev_descriptor), wLength)); + } else if (wValue == 0x200) { + /* Return Configuration Descriptor */ +#ifdef CONFIG_DFU + if (*dfu->dfu_state != DFU_STATE_appIDLE) + udp_ep0_send_data((const char *) + dfu->dfu_cfg_descriptor, + MIN(dfu->dfu_cfg_descriptor->ucfg.wTotalLength, + wLength)); + else +#endif + udp_ep0_send_data((const char *) &cfg_descriptor, + MIN(sizeof(cfg_descriptor), wLength)); + } else if (wValue == 0x300) { + /* Return String descriptor */ + switch (wIndex) { + case 0: + udp_ep0_send_data((const char *) &string0, + MIN(sizeof(string0), wLength)); + break; + default: + /* FIXME: implement this */ + udp_ep0_send_stall(); + break; + } +#if 0 + } else if (wValue == 0x400) { + /* Return Interface descriptor */ + if (wIndex != 0x01) + udp_ep0_send_stall(); + udp_ep0_send_data((const char *) + &dfu_if_descriptor, + MIN(sizeof(dfu_if_descriptor), + wLength)); +#endif + } else + udp_ep0_send_stall(); + break; + case STD_SET_ADDRESS: + DEBUGE("SET_ADDRESS "); + udp_ep0_send_zlp(); + pUDP->UDP_FADDR = (AT91C_UDP_FEN | wValue); + pUDP->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0; + break; + case STD_SET_CONFIGURATION: + DEBUGE("SET_CONFIG "); + if (wValue) + DEBUGE("VALUE!=0 "); + upcd.cur_config = wValue; + udp_ep0_send_zlp(); + pUDP->UDP_GLBSTATE = + (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN; + pUDP->UDP_CSR[1] = + (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : + 0; + pUDP->UDP_CSR[2] = + (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0; + pUDP->UDP_CSR[3] = + (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0; + pUDP->UDP_IER = (AT91C_UDP_EPINT0|AT91C_UDP_EPINT1| + AT91C_UDP_EPINT2|AT91C_UDP_EPINT3); + break; + case STD_GET_CONFIGURATION: + DEBUGE("GET_CONFIG "); + udp_ep0_send_data((char *)&(upcd.cur_config), + sizeof(upcd.cur_config)); + break; + case STD_GET_STATUS_ZERO: + DEBUGE("GET_STATUS_ZERO "); + wStatus = 0; + udp_ep0_send_data((char *)&wStatus, sizeof(wStatus)); + break; + case STD_GET_STATUS_INTERFACE: + DEBUGE("GET_STATUS_INTERFACE "); + wStatus = 0; + udp_ep0_send_data((char *)&wStatus, sizeof(wStatus)); + break; + case STD_GET_STATUS_ENDPOINT: + DEBUGE("GET_STATUS_ENDPOINT(EPidx=%u) ", wIndex&0x0f); + wStatus = 0; + wIndex &= 0x0F; + if ((pUDP->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= 3)) { + wStatus = + (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; + udp_ep0_send_data((char *)&wStatus, + sizeof(wStatus)); + } else if ((pUDP->UDP_GLBSTATE & AT91C_UDP_FADDEN) + && (wIndex == 0)) { + wStatus = + (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; + udp_ep0_send_data((char *)&wStatus, + sizeof(wStatus)); + } else + udp_ep0_send_stall(); + break; + case STD_SET_FEATURE_ZERO: + DEBUGE("SET_FEATURE_ZERO "); + udp_ep0_send_stall(); + break; + case STD_SET_FEATURE_INTERFACE: + DEBUGE("SET_FEATURE_INTERFACE "); + udp_ep0_send_zlp(); + break; + case STD_SET_FEATURE_ENDPOINT: + DEBUGE("SET_FEATURE_ENDPOINT "); + udp_ep0_send_zlp(); + wIndex &= 0x0F; + if ((wValue == 0) && wIndex && (wIndex <= 3)) { + pUDP->UDP_CSR[wIndex] = 0; + udp_ep0_send_zlp(); + } else + udp_ep0_send_stall(); + break; + case STD_CLEAR_FEATURE_ZERO: + DEBUGE("CLEAR_FEATURE_ZERO "); + udp_ep0_send_stall(); + break; + case STD_CLEAR_FEATURE_INTERFACE: + DEBUGP("CLEAR_FEATURE_INTERFACE "); + udp_ep0_send_zlp(); + break; + case STD_CLEAR_FEATURE_ENDPOINT: + DEBUGE("CLEAR_FEATURE_ENDPOINT(EPidx=%u) ", wIndex & 0x0f); + wIndex &= 0x0F; + if ((wValue == 0) && wIndex && (wIndex <= 3)) { + struct req_ctx *rctx; + if (wIndex == 1) { + pUDP->UDP_CSR[1] = + (AT91C_UDP_EPEDS | + AT91C_UDP_EPTYPE_BULK_OUT); + pUDP->UDP_RSTEP |= AT91C_UDP_EP1; + pUDP->UDP_RSTEP &= ~AT91C_UDP_EP1; + } + else if (wIndex == 2) { + pUDP->UDP_CSR[2] = + (AT91C_UDP_EPEDS | + AT91C_UDP_EPTYPE_BULK_IN); + pUDP->UDP_RSTEP |= AT91C_UDP_EP2; + pUDP->UDP_RSTEP &= ~AT91C_UDP_EP2; + + /* free all currently transmitting contexts */ + while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP2_BUSY, + RCTX_STATE_FREE)) {} + atomic_set(&upcd.ep[wIndex].pkts_in_transit, 0); + } + else if (wIndex == 3) { + pUDP->UDP_CSR[3] = + (AT91C_UDP_EPEDS | + AT91C_UDP_EPTYPE_INT_IN); + pUDP->UDP_RSTEP |= AT91C_UDP_EP3; + pUDP->UDP_RSTEP &= ~AT91C_UDP_EP3; + + /* free all currently transmitting contexts */ + while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP3_BUSY, + RCTX_STATE_FREE)) {} + atomic_set(&upcd.ep[wIndex].pkts_in_transit, 0); + } + udp_ep0_send_zlp(); + } else + udp_ep0_send_stall(); + break; + case STD_SET_INTERFACE: + DEBUGE("SET INTERFACE "); + udp_ep0_send_stall(); + break; +#ifdef CONFIG_DFU + case USB_TYPE_DFU<<8|USB_REQ_DFU_DETACH: + DEBUGE("DFU_DETACH "); + /* if USB reset occurs within wValue milliseconds, switch to DFU */ + break; +#endif + default: + DEBUGE("DEFAULT(req=0x%02x, type=0x%02x) ", bRequest, bmRequestType); +#ifdef CONFIG_DFU + if ((bmRequestType & 0x3f) == USB_TYPE_DFU) { + dfu->dfu_ep0_handler(bmRequestType, bRequest, wValue, wLength); + } else +#endif + udp_ep0_send_stall(); + break; + } +} + diff --git a/openpcd/firmware/src/os/pcd_enumerate.h b/openpcd/firmware/src/os/pcd_enumerate.h new file mode 100644 index 0000000..57ff88c --- /dev/null +++ b/openpcd/firmware/src/os/pcd_enumerate.h @@ -0,0 +1,56 @@ +#ifndef _OPCD_USB_H +#define _OPCD_USB_H + +#include +#include +#include +#include "openpcd.h" +#include "dfu.h" + +struct req_ctx; + +extern void udp_open(void); +extern int udp_refill_ep(int ep, struct req_ctx *rctx); +extern void udp_unthrottle(void); +extern void udp_reset(void); + +struct ep_ctx { + atomic_t pkts_in_transit; + void *ctx; +}; + +struct udp_pcd { + AT91PS_UDP pUdp; + unsigned char cur_config; + unsigned int cur_rcv_bank; + struct ep_ctx ep[4]; +}; + +/* USB standard request code */ + +#define STD_GET_STATUS_ZERO 0x0080 +#define STD_GET_STATUS_INTERFACE 0x0081 +#define STD_GET_STATUS_ENDPOINT 0x0082 + +#define STD_CLEAR_FEATURE_ZERO 0x0100 +#define STD_CLEAR_FEATURE_INTERFACE 0x0101 +#define STD_CLEAR_FEATURE_ENDPOINT 0x0102 + +#define STD_SET_FEATURE_ZERO 0x0300 +#define STD_SET_FEATURE_INTERFACE 0x0301 +#define STD_SET_FEATURE_ENDPOINT 0x0302 + +#define STD_SET_ADDRESS 0x0500 +#define STD_GET_DESCRIPTOR 0x0680 +#define STD_SET_DESCRIPTOR 0x0700 +#define STD_GET_CONFIGURATION 0x0880 +#define STD_SET_CONFIGURATION 0x0900 +#define STD_GET_INTERFACE 0x0A81 +#define STD_SET_INTERFACE 0x0B01 +#define STD_SYNCH_FRAME 0x0C82 + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + + +#endif + diff --git a/openpcd/firmware/src/os/pio_irq.c b/openpcd/firmware/src/os/pio_irq.c new file mode 100644 index 0000000..3e65561 --- /dev/null +++ b/openpcd/firmware/src/os/pio_irq.c @@ -0,0 +1,66 @@ + +#include +#define NR_PIO 32 + +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; +} + +static void pio_irq_demux(void) +{ + u_int32_t pio = AT91F_PIO_GetInterruptStatus(AT91C_BASE_PIOA); + + for (i = 0; i < NR_PIO; i++) { + if (pio & (1 << i) && pio_handlers[i]) + pio_handlers[i](i); + } + return; +} + +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, void (*handler)(void)) +{ + u_int8_t num = ffs(pio); + + if (num == 0) + return -EINVAL; + num--; + + if (pio_handlers[num]) + return -EBUSY; + + pio_irq_disable(pio); + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, pio); + pio_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); + pio_handlers[num] = NULL; +} diff --git a/openpcd/firmware/src/os/pio_irq.h b/openpcd/firmware/src/os/pio_irq.h new file mode 100644 index 0000000..86021df --- /dev/null +++ b/openpcd/firmware/src/os/pio_irq.h @@ -0,0 +1,15 @@ +#ifndef _PIO_IRQ_H +#define _PIO_IRQ_H + +#include + +typedef irq_handler_t (void)(u_int32_t pio); + +static irq_handler_t pio_handlers[NR_PIO]; + +extern void pio_irq_enable(u_int32_t pio); +extern void pio_irq_disable(u_int32_t pio); +extern int pio_irq_register(u_int32_t pio, irq_handler_t func); +extern void pio_irq_unregister(u_int32_t pio); + +#endif diff --git a/openpcd/firmware/src/os/req_ctx.c b/openpcd/firmware/src/os/req_ctx.c new file mode 100644 index 0000000..831d48e --- /dev/null +++ b/openpcd/firmware/src/os/req_ctx.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include + +#include "../openpcd.h" + +/* FIXME: locking, FIFO order processing */ + +static struct req_ctx req_ctx[NUM_REQ_CTX]; + +struct req_ctx *req_ctx_find_get(unsigned long old_state, unsigned long new_state) +{ + unsigned long flags; + u_int8_t i; + + for (i = 0; i < NUM_REQ_CTX; i++) { + local_irq_save(flags); + if (req_ctx[i].state == old_state) { + req_ctx[i].state = new_state; + local_irq_restore(flags); + return &req_ctx[i]; + } + local_irq_restore(flags); + } + + return NULL; +} + +u_int8_t req_ctx_num(struct req_ctx *ctx) +{ + return ((void *)ctx - (void *)&req_ctx[0])/sizeof(*ctx); +} + +void req_ctx_set_state(struct req_ctx *ctx, unsigned long new_state) +{ + unsigned long flags; + + /* FIXME: do we need this kind of locking, we're UP! */ + local_irq_save(flags); + ctx->state = new_state; + local_irq_restore(flags); +} + +void req_ctx_put(struct req_ctx *ctx) +{ + req_ctx_set_state(ctx, RCTX_STATE_FREE); +} diff --git a/openpcd/firmware/src/os/req_ctx.h b/openpcd/firmware/src/os/req_ctx.h new file mode 100644 index 0000000..f57f02f --- /dev/null +++ b/openpcd/firmware/src/os/req_ctx.h @@ -0,0 +1,47 @@ +#ifndef _REQ_CTX_H +#define _REQ_CTX_H + +#define MAX_HDRSIZE sizeof(struct openpcd_hdr) +#define MAX_REQSIZE (64-MAX_HDRSIZE) + +#define req_buf_payload(x) (x->data[x->hdr_len]) +#define req_buf_hdr(x) (x->data[0]) + +#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; +}; + +#define RCTX_STATE_FREE 0x00 +#define RCTX_STATE_UDP_RCV_BUSY 0x01 +#define RCTX_STATE_UDP_RCV_DONE 0x02 +#define RCTX_STATE_MAIN_PROCESSING 0x03 +#define RCTX_STATE_RC632IRQ_BUSY 0x04 + +#define RCTX_STATE_UDP_EP2_PENDING 0x10 +#define RCTX_STATE_UDP_EP2_BUSY 0x11 + +#define RCTX_STATE_UDP_EP3_PENDING 0x12 +#define RCTX_STATE_UDP_EP3_BUSY 0x13 + +#define RCTX_STATE_SSC_RX_BUSY 0x20 + +#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); +extern void req_ctx_set_state(struct req_ctx *ctx, unsigned long new_state); +extern void req_ctx_put(struct req_ctx *ctx); +extern u_int8_t req_ctx_num(struct req_ctx *ctx); + +#endif /* _REQ_CTX_H */ diff --git a/openpcd/firmware/src/os/syscalls.c b/openpcd/firmware/src/os/syscalls.c new file mode 100644 index 0000000..ed989f1 --- /dev/null +++ b/openpcd/firmware/src/os/syscalls.c @@ -0,0 +1,169 @@ +/***********************************************************************/ +/* */ +/* SYSCALLS.C: System Calls */ +/* most of this is from newlib-lpc and a Keil-demo */ +/* */ +/* These are "reentrant functions" as needed by */ +/* the WinARM-newlib-config, see newlib-manual. */ +/* Collected and modified by Martin Thomas */ +/* */ +/***********************************************************************/ + + +#include +#include +#include + +#include + +static void my_putc(char c) +{ + while (!AT91F_US_TxReady((AT91PS_USART)AT91C_BASE_DBGU)); + AT91F_US_PutChar((AT91PS_USART)AT91C_BASE_DBGU, c); +} + +static int my_kbhit( void ) +{ + if ((AT91F_US_RxReady((AT91PS_USART)AT91C_BASE_DBGU)) == 0) return 0; + else return 1; +} + +static char my_getc( void ) +{ + return AT91F_US_GetChar((AT91PS_USART)AT91C_BASE_DBGU); +} + +_ssize_t _read_r( + struct _reent *r, + int file, + void *ptr, + size_t len) +{ + char c; + int i; + unsigned char *p; + + p = (unsigned char*)ptr; + + for (i = 0; i < len; i++) { + // c = uart0Getch(); + // c = uart0GetchW(); + while ( !my_kbhit() ) ; + c = (char) my_getc(); + if (c == 0x0D) { + *p='\0'; + break; + } + *p++ = c; + ////// uart0_putc(c); + } + return len - i; +} + + +_ssize_t _write_r ( + struct _reent *r, + int file, + const void *ptr, + size_t len) +{ + int i; + const unsigned char *p; + + p = (const unsigned char*) ptr; + + for (i = 0; i < len; i++) { + if (*p == '\n' ) my_putc('\r'); + my_putc(*p++); + } + + return len; +} + + +int _close_r( + struct _reent *r, + int file) +{ + return 0; +} + + +_off_t _lseek_r( + struct _reent *r, + int file, + _off_t ptr, + int dir) +{ + return (_off_t)0; /* Always indicate we are at file beginning. */ +} + + +int _fstat_r( + struct _reent *r, + int file, + struct stat *st) +{ + /* Always set as character device. */ + st->st_mode = S_IFCHR; + /* assigned to strong type with implicit */ + /* signed/unsigned conversion. Required by */ + /* newlib. */ + + return 0; +} + + +int isatty(int file); /* avoid warning */ + +int isatty(int file) +{ + return 1; +} + + +#if 0 +static void _exit (int n) { +label: goto label; /* endless loop */ +} +#endif + + +/* "malloc clue function" from newlib-lpc/Keil-Demo/"generic" */ + +/**** Locally used variables. ****/ +// mt: "cleaner": extern char* end; +extern char end[]; /* end is set in the linker command */ + /* file and is the end of statically */ + /* allocated data (thus start of heap). */ + +static char *heap_ptr; /* Points to current end of the heap. */ + +/************************** _sbrk_r ************************************* + * Support function. Adjusts end of heap to provide more memory to + * memory allocator. Simple and dumb with no sanity checks. + + * struct _reent *r -- re-entrancy structure, used by newlib to + * support multiple threads of operation. + * ptrdiff_t nbytes -- number of bytes to add. + * Returns pointer to start of new heap area. + * + * Note: This implementation is not thread safe (despite taking a + * _reent structure as a parameter). + * Since _s_r is not used in the current implementation, + * the following messages must be suppressed. + */ +void * _sbrk_r( + struct _reent *_s_r, + ptrdiff_t nbytes) +{ + char *base; /* errno should be set to ENOMEM on error */ + + if (!heap_ptr) { /* Initialize if first time through. */ + heap_ptr = end; + } + base = heap_ptr; /* Point to end of heap. */ + heap_ptr += nbytes; /* Increase heap. */ + + return base; /* Return pointer to start of new heap area. */ +} diff --git a/openpcd/firmware/src/os/trigger.c b/openpcd/firmware/src/os/trigger.c new file mode 100644 index 0000000..b8cedf3 --- /dev/null +++ b/openpcd/firmware/src/os/trigger.c @@ -0,0 +1,17 @@ +#include +#include +#include "../openpcd.h" + +void trigger_init(void) +{ + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); +} + +void trigger_pulse(void) +{ + volatile int i; + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); + for (i=0; i < 0xff; i++) + { } + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); +} diff --git a/openpcd/firmware/src/os/trigger.h b/openpcd/firmware/src/os/trigger.h new file mode 100644 index 0000000..597704b --- /dev/null +++ b/openpcd/firmware/src/os/trigger.h @@ -0,0 +1,7 @@ +#ifndef _TRIGGER_H +#define _TRIGGER_H + +extern void trigger_init(void); +extern void trigger_pulse(void); + +#endif diff --git a/openpcd/firmware/src/os/usb_benchmark.c b/openpcd/firmware/src/os/usb_benchmark.c new file mode 100644 index 0000000..3637bc3 --- /dev/null +++ b/openpcd/firmware/src/os/usb_benchmark.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include +#include "../openpcd.h" + +static struct req_ctx dummy_rctx; +static struct req_ctx empty_rctx; + +static void usbtest_tx_transfer(unsigned int num_pkts) +{ + unsigned int i; + + for (i = 0; i < num_pkts; i++) { + /* send 16 packets of 64byte */ + while (udp_refill_ep(2, &dummy_rctx) < 0) + ; + } + /* send one packet of 0 byte */ + while (udp_refill_ep(2, &empty_rctx) < 0) + ; +} + +static int usbtest_rx(struct req_ctx *rctx) +{ + struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->rx.data[0]; + int i; + + switch (poh->cmd) { + case OPENPCD_CMD_USBTEST_IN: + /* test bulk in pipe */ + for (i = 0; i < poh->reg; i++) { + usbtest_tx_transfer(poh->val); + led_toggle(2); + } + break; + case OPENPCD_CMD_USBTEST_OUT: + /* test bulk out pipe */ + break; + } + + req_ctx_put(rctx); + return 1; +} + +void usbtest_init(void) +{ + dummy_rctx.tx.tot_len = 64; + memset(dummy_rctx.tx.data, 0x23, 64); + + empty_rctx.tx.tot_len = 0; + + usb_hdlr_register(&usbtest_rx, OPENPCD_CMD_CLS_USBTEST); +} diff --git a/openpcd/firmware/src/os/usb_handler.c b/openpcd/firmware/src/os/usb_handler.c new file mode 100644 index 0000000..82620be --- /dev/null +++ b/openpcd/firmware/src/os/usb_handler.c @@ -0,0 +1,87 @@ +/* OpenPCD USB handler - handle incoming USB requests on OUT pipe + * (C) 2006 by Harald Welte + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "../openpcd.h" + +static usb_cmd_fn *cmd_hdlrs[16]; + +int usb_hdlr_register(usb_cmd_fn *hdlr, u_int8_t class) +{ + cmd_hdlrs[class] = hdlr; +} + +void usb_hdlr_unregister(u_int8_t class) +{ + cmd_hdlrs[class] = NULL; +} + +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]; + usb_cmd_fn *hdlr; + + DEBUGP("usb_in(cls=%d) ", OPENPCD_CMD_CLS(poh->cmd)); + + if (rctx->rx.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"); +} + +/* Process all pending request contexts that want to Tx on either + * IN or INTERRUPT endpoint */ +void usb_out_process(void) +{ + struct req_ctx *rctx; + + while (rctx = req_ctx_find_get(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) + req_ctx_set_state(rctx, RCTX_STATE_UDP_EP3_PENDING); + } + + while (rctx = req_ctx_find_get(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) + req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); + } +} + +/* process incoming USB packets (OUT pipe) that have already been + * put into request contexts by the UDP IRQ handler */ +void usb_in_process(void) +{ + struct req_ctx *rctx; + + while (rctx = req_ctx_find_get(RCTX_STATE_UDP_RCV_DONE, + RCTX_STATE_MAIN_PROCESSING)) { + DEBUGPCRF("found used ctx %u: len=%u", + req_ctx_num(rctx), rctx->rx.tot_len); + usb_in(rctx); + } + udp_unthrottle(); +} + diff --git a/openpcd/firmware/src/os/usb_handler.h b/openpcd/firmware/src/os/usb_handler.h new file mode 100644 index 0000000..a281c66 --- /dev/null +++ b/openpcd/firmware/src/os/usb_handler.h @@ -0,0 +1,15 @@ +#ifndef _USB_HANDLER_H +#define _USB_HANDLER_H + +#include "openpcd.h" + +#define MAX_PAYLOAD_LEN (64 - sizeof(struct openpcd_hdr)) + +typedef int usb_cmd_fn(struct req_ctx *rctx); + +extern int usb_hdlr_register(usb_cmd_fn *hdlr, u_int8_t class); + +extern void usb_in_process(void); +extern void usb_out_process(void); + +#endif diff --git a/openpcd/firmware/src/pcd/main_analog.c b/openpcd/firmware/src/pcd/main_analog.c new file mode 100644 index 0000000..45869e1 --- /dev/null +++ b/openpcd/firmware/src/pcd/main_analog.c @@ -0,0 +1,86 @@ +/* main_reqa - OpenPCD firmware for generating an endless loop of + * ISO 14443-A REQA packets. + * + * If a response is received from the PICC, LED1 (Red) will be switched + * on. If no valid response has been received within the timeout of the + * receiver, LED1 (Red) will be switched off. + * + */ + +#include +#include +#include +#include "rc632.h" +#include +#include +#include +#include +#include + +void _init_func(void) +{ + //udp_init(); + trigger_init(); + rc632_init(); + DEBUGPCRF("turning on RF"); + rc632_turn_on_rf(RAH); + /* FIXME: do we need this? */ + DEBUGPCRF("initializing 14443A operation"); + rc632_iso14443a_init(RAH); + /* Switch to 848kBps (1subcp / bit) */ + //rc632_clear_bits(RAH, RC632_REG_RX_CONTROL1, RC632_RXCTRL1_SUBCP_MASK); +} + +int _main_dbgu(char key) +{ + static char ana_out_sel; + int ret = -EINVAL; + + switch (key) { + case 'q': + ana_out_sel--; + ret = 1; + break; + case 'w': + ana_out_sel++; + ret = 1; + break; + case 'c': + rc632_turn_on_rf(RAH); + break; + case 'o': + rc632_turn_off_rf(RAH); + break; + } + + if (ana_out_sel >= 0xd) + ana_out_sel = 0; + + if (ret == 1) { + ana_out_sel &= 0x0f; + DEBUGPCR("switching to analog output mode 0x%x\n", ana_out_sel); + rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); + } + + return ret; +} + +void _main_func(void) +{ +#if 1 + struct iso14443a_atqa atqa; + + memset(&atqa, 0, sizeof(atqa)); + + trigger_pulse(); + + if (rc632_iso14443a_transceive_sf(RAH, ISO14443A_SF_CMD_WUPA, &atqa) < 0) { + DEBUGPCRF("error during transceive_sf"); + led_switch(1, 0); + } else { + DEBUGPCRF("received ATQA: %s\n", hexdump((char *)&atqa, sizeof(atqa))); + led_switch(1, 1); + } +#endif + led_toggle(2); +} diff --git a/openpcd/firmware/src/pcd/main_dumbreader.c b/openpcd/firmware/src/pcd/main_dumbreader.c new file mode 100644 index 0000000..21c4135 --- /dev/null +++ b/openpcd/firmware/src/pcd/main_dumbreader.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include "rc632.h" +#include +#include +#include +#include "../openpcd.h" +#include + +void _init_func(void) +{ + rc632_init(); + udp_init(); + rc632_test(RAH); +} + +int _main_dbgu(char key) +{ + return -EINVAL; +} + +void _main_func(void) +{ + /* first we try to get rid of pending to-be-sent stuff */ + usb_out_process(); + + /* next we deal with incoming reqyests from USB EP1 (OUT) */ + usb_in_process(); + + rc632_unthrottle(); +} diff --git a/openpcd/firmware/src/pcd/main_pwm.c b/openpcd/firmware/src/pcd/main_pwm.c new file mode 100644 index 0000000..85d304a --- /dev/null +++ b/openpcd/firmware/src/pcd/main_pwm.c @@ -0,0 +1,250 @@ +/* main_pwm - OpenPCD firmware for generating a PWM-modulated 13.56MHz + * carrier + * + * To use this, you need to connect PIOA P0 with MFIN of the reader. + */ + +#include +#include +#include +#include "../openpcd.h" +#include "rc632.h" +#include +#include +#include "pwm.h" +#include "tc.h" +#include "ssc.h" +#include +#include + +static u_int8_t force_100ask = 1; +static u_int8_t mod_conductance = 0x3f; +static u_int8_t cw_conductance = 0x3f; +static u_int16_t duty_percent = 22; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +static u_int32_t pwm_freq[] = { 105937, 211875, 423750, 847500 }; +static u_int8_t pwm_freq_idx = 0; + +static void rc632_modulate_mfin() +{ + rc632_reg_write(RAH, RC632_REG_TX_CONTROL, + RC632_TXCTRL_MOD_SRC_MFIN|RC632_TXCTRL_TX2_INV| + RC632_TXCTRL_TX1_RF_EN|RC632_TXCTRL_TX2_RF_EN); +} + +/* (77/40) ^ EXPcsCfgCW */ +/* 1, 1.925, 3.705625, 7.13332812 */ + +#define COND_MANT(x) (x & 0x0f) +#define COND_EXP(x) ((x & 0x30) >> 4) + +static const u_int16_t rsrel_expfact[] = { 1000, 1925, 3706, 7133 }; + +static u_int32_t calc_conduct_rel(u_int8_t inp) +{ + u_int32_t cond_rel; + + cond_rel = COND_MANT(inp) * rsrel_expfact[COND_EXP(inp)]; + cond_rel = cond_rel / 1000; + + return cond_rel; +} + +static const u_int8_t rsrel_table[] = { + 0, 16, 32, 48, 1, 17, 2, 3, 33, 18, 4, 5, 19, 6, 7, 49, 34, 20, + 8, 9, 21, 10, 11, 35, 22, 12, 13, 23, 14, 50, 36, 15, 24, 25, + 37, 26, 27, 51, 38, 28, 29, 39, 30, 52, 31, 40, 41, 53, 42, 43, + 54, 44, 45, 55, 46, 47, 56, 57, 58, 59, 60, 61, 62, 63 }; + + +static const u_int16_t cdivs[] = { 128, 64, 32, 16 }; +static int cdiv_idx = 0; + +static void help(void) +{ + DEBUGPCR("o: decrease duty p: increase duty\r\n" + "k: stop pwm l: start pwn\r\n" + "n: decrease freq m: incresae freq\r\n" + "v: decrease mod_cond b: increase mod_cond\r\n" + "g: decrease cw_cond h: increase cw_cond"); + DEBUGPCR("u: PA23 const 1 y: PA23 const 0\r\n" + "t: PA23 PWM0 f: toggle Force100ASK\r\n" + "{: decrease cdiv_idx }: increse cdiv idx"); +} + +void _init_func(void) +{ + DEBUGPCR("\r\n===> main_pwm <===\r\n"); + help(); + + rc632_init(); + DEBUGPCRF("turning on RF"); + rc632_turn_on_rf(RAH); + + /* switch PA17 (connected to MFIN on board) to input */ + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, AT91C_PIO_PA17); + + DEBUGPCRF("Initializing carrier divider"); + tc_cdiv_init(); + + DEBUGPCRF("Initializing PWM"); + pwm_init(); + pwm_freq_set(0, 105937); + pwm_start(0); + pwm_duty_set_percent(0, 22); /* 22% of 9.43uS = 2.07uS */ + rc632_modulate_mfin(); + + udp_init(); + + DEBUGPCRF("Initializing SSC RX"); + ssc_rx_init(); +} + +int _main_dbgu(char key) +{ + switch (key) { + case 'o': + if (duty_percent >= 1) + duty_percent--; + pwm_duty_set_percent(0, duty_percent); + break; + case 'p': + if (duty_percent <= 99) + duty_percent++; + pwm_duty_set_percent(0, duty_percent); + break; + case 'k': + pwm_stop(0); + break; + case 'l': + pwm_start(0); + break; + case 'n': + if (pwm_freq_idx > 0) { + pwm_freq_idx--; + pwm_stop(0); + pwm_freq_set(0, pwm_freq[pwm_freq_idx]); + pwm_start(0); + pwm_duty_set_percent(0, 22); /* 22% of 9.43uS = 2.07uS */ + } + break; + case 'm': + if (pwm_freq_idx < ARRAY_SIZE(pwm_freq)-1) { + pwm_freq_idx++; + pwm_stop(0); + pwm_freq_set(0, pwm_freq[pwm_freq_idx]); + pwm_start(0); + pwm_duty_set_percent(0, 22); /* 22% of 9.43uS = 2.07uS */ + } + break; + case 'u': + DEBUGPCRF("PA23 output high"); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PIO_PA23); + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, AT91C_PIO_PA23); + break; + case 'y': + DEBUGPCRF("PA23 output low"); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PIO_PA23); + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, AT91C_PIO_PA23); + return 0; + break; + case 't': + DEBUGPCRF("PA23 PeriphA (PWM)"); + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, AT91C_PA23_PWM0); + return 0; + break; + case 'f': + DEBUGPCRF("%sabling Force100ASK", force_100ask ? "Dis":"En"); + if (force_100ask) { + force_100ask = 0; + rc632_clear_bits(RAH, RC632_REG_TX_CONTROL, + RC632_TXCTRL_FORCE_100_ASK); + } else { + force_100ask = 1; + rc632_set_bits(RAH, RC632_REG_TX_CONTROL, + RC632_TXCTRL_FORCE_100_ASK); + } + return 0; + break; + case 'v': + if (mod_conductance > 0) { + mod_conductance--; + rc632_reg_write(RAH, RC632_REG_MOD_CONDUCTANCE, + rsrel_table[mod_conductance]); + } + break; + case 'b': + if (mod_conductance < 0x3f) { + mod_conductance++; + rc632_reg_write(RAH, RC632_REG_MOD_CONDUCTANCE, + rsrel_table[mod_conductance]); + } + break; + case 'g': + if (cw_conductance > 0) { + cw_conductance--; + rc632_reg_write(RAH, RC632_REG_CW_CONDUCTANCE, + rsrel_table[cw_conductance]); + } + break; + case 'h': + if (cw_conductance < 0x3f) { + cw_conductance++; + rc632_reg_write(RAH, RC632_REG_CW_CONDUCTANCE, + rsrel_table[cw_conductance]); + } + break; + case '?': + help(); + return 0; + break; + case '<': + tc_cdiv_phase_inc(); + break; + case '>': + tc_cdiv_phase_dec(); + break; + case '{': + if (cdiv_idx > 0) + cdiv_idx--; + tc_cdiv_set_divider(cdivs[cdiv_idx]); + break; + case '}': + if (cdiv_idx < ARRAY_SIZE(cdivs)-1) + cdiv_idx++; + tc_cdiv_set_divider(cdivs[cdiv_idx]); + break; + case 's': + ssc_rx_start(); + break; + case 'S': + ssc_rx_stop(); + break; + default: + return -EINVAL; + } + + DEBUGPCR("pwm_freq=%u, duty_percent=%u, mod_cond=%u, cw_cond=%u tc_cdiv=%u", + pwm_freq[pwm_freq_idx], duty_percent, mod_conductance, cw_conductance, + cdivs[cdiv_idx]); + + return 0; +} + + +void _main_func(void) +{ + /* first we try to get rid of pending to-be-sent stuff */ + usb_out_process(); + + /* next we deal with incoming reqyests from USB EP1 (OUT) */ + usb_in_process(); + + /* try unthrottling sources since we now are [more] likely to + * have empty request contexts */ + rc632_unthrottle(); + ssc_rx_unthrottle(); + + led_toggle(2); +} diff --git a/openpcd/firmware/src/pcd/main_reqa.c b/openpcd/firmware/src/pcd/main_reqa.c new file mode 100644 index 0000000..179b423 --- /dev/null +++ b/openpcd/firmware/src/pcd/main_reqa.c @@ -0,0 +1,266 @@ +/* main_reqa - OpenPCD firmware for generating an endless loop of + * ISO 14443-A REQA packets. Alternatively we can send WUPA, or + * perform a full ISO14443A anti-collision loop. + * + * If a response is received from the PICC, LED1 (Red) will be switched + * on. If no valid response has been received within the timeout of the + * receiver, LED1 (Red) will be switched off. + * + */ + +#include +#include +#include +#include +#include "rc632.h" +#include +#include +#include +#include + +#include "../openpcd.h" + +#ifdef WITH_TC +#include "tc.h" +#endif + +void _init_func(void) +{ + //udp_init(); + trigger_init(); + DEBUGPCRF("enabling RC632"); + rc632_init(); +#ifdef WITH_TC + DEBUGPCRF("enabling TC"); + tc_cdiv_init(); +#endif + DEBUGPCRF("turning on RF"); + rc632_turn_on_rf(RAH); + DEBUGPCRF("initializing 14443A operation"); + rc632_iso14443a_init(RAH); +} + +#define MODE_REQA 0x01 +#define MODE_WUPA 0x02 +#define MODE_ANTICOL 0x03 +#define MODE_14443A 0x04 + +static volatile int mode = MODE_REQA; + +static const char frame_14443a[] = { 0x00, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; + +static void reg_inc(u_int8_t reg) +{ + u_int8_t val; + rc632_reg_read(RAH, reg, &val); + rc632_reg_write(RAH, reg, val++); + DEBUGPCRF("reg 0x%02x = 0x%02x", reg, val); +} + +static void reg_dec(u_int8_t reg) +{ + u_int8_t val; + rc632_reg_read(RAH, reg, &val); + rc632_reg_write(RAH, reg, val--); + DEBUGPCRF("reg 0x%02x = 0x%02x", reg, val); +} + +static u_int8_t ana_out_sel; +static u_int8_t mfout_sel; +static u_int8_t speed_idx; + +static void help(void) +{ + DEBUGPCR("r: REQA w: WUPA a: ANTICOL\r\n" + "A: 14443A +: inc speed -: dec speed\r\n" + "y: inc cw cond x: dec cond c: inc mod cond"); + DEBUGPCR("v: dec mod cond o: dec ana_out p: dec ana_out\r\n" + "h: trigger high l: trigger low u: dec MFOUT mode"); + DEBUGPCR("i: inc MFOUT md <: dec cdiv ph >: inc cdiv phase\r\n" + "{: dev cdiv }: inc cdiv"); +} + +static u_int16_t cdivs[] = { 128, 64, 32, 16 }; + +int _main_dbgu(char key) +{ + int ret = 0; + static int cdiv_idx = 0; + + switch (key) { + case '?': + help(); + break; + case 'r': + mode = MODE_REQA; + break; + case 'w': + mode = MODE_WUPA; + break; + case 'A': + mode = MODE_14443A; + break; + case 'a': + mode = MODE_ANTICOL; + break; + /* Those below don't work as long as + * iso14443a_init() is called before + * every cycle */ + case 'y': + reg_inc(RC632_REG_CW_CONDUCTANCE); + break; + case 'x': + reg_dec(RC632_REG_CW_CONDUCTANCE); + break; + case 'c': + reg_inc(RC632_REG_MOD_CONDUCTANCE); + break; + case 'v': + reg_dec(RC632_REG_MOD_CONDUCTANCE); + break; + case 'o': + if (ana_out_sel > 0) { + ana_out_sel--; + DEBUGPCR("switching to analog output mode 0x%x\n", ana_out_sel); + rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); + } + ret = 1; + break; + case 'p': + if (ana_out_sel < 0xc) { + ana_out_sel++; + DEBUGPCR("switching to analog output mode 0x%x\n", ana_out_sel); + rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); + } + ret = 1; + break; + case 'u': + if (mfout_sel > 0) { + mfout_sel--; + DEBUGPCR("switching to MFOUT mode 0x%x\n", mfout_sel); + rc632_reg_write(RAH, RC632_REG_MFOUT_SELECT, mfout_sel); + } + ret = 1; + break; + case 'i': + if (mfout_sel < 5) { + mfout_sel++; + DEBUGPCR("switching to MFOUT mode 0x%x\n", mfout_sel); + rc632_reg_write(RAH, RC632_REG_MFOUT_SELECT, mfout_sel); + } + ret = 1; + break; + case 'h': + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); + break; + case 'l': + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); + break; +#ifdef WITH_TC + case '<': + tc_cdiv_phase_inc(); + break; + case '>': + tc_cdiv_phase_dec(); + break; + case '{': + if (cdiv_idx > 0) + cdiv_idx--; + tc_cdiv_set_divider(cdivs[cdiv_idx]); + break; + case '}': + if (cdiv_idx < ARRAY_SIZE(cdivs)-1) + cdiv_idx++; + tc_cdiv_set_divider(cdivs[cdiv_idx]); + break; +#endif + case '-': + if (speed_idx > 0) + speed_idx--; + break; + case '+': + if (speed_idx < 3) + speed_idx++; + break; + default: + return -EINVAL; + } + + return ret; +} + +void _main_func(void) +{ + int status; + struct iso14443a_atqa atqa; + struct rfid_layer2_handle l2h; + volatile int i; + + memset(&atqa, 0, sizeof(atqa)); + + /* fake layer2 handle initialization */ + memset(&l2h, 0, sizeof(l2h)); + l2h.l2 = &rfid_layer2_iso14443a; + l2h.priv.iso14443a.state = ISO14443A_STATE_NONE; + l2h.priv.iso14443a.level = ISO14443A_LEVEL_NONE; + + /* FIXME: why does this only work every second attempt without reset or + * power-cycle? */ + rc632_turn_off_rf(); + //rc632_reset(); + rc632_turn_on_rf(); + + rc632_iso14443a_init(RAH); + rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); + rc632_reg_write(RAH, RC632_REG_MFOUT_SELECT, mfout_sel); + for (i = 0; i < 0x3ffff; i++) {} + //rc632_dump(); +#ifdef WITH_TC + tc_cdiv_print(); +#endif + + switch (mode) { + case MODE_REQA: + status = rc632_iso14443a_transceive_sf(RAH, ISO14443A_SF_CMD_REQA, &atqa); + if (status < 0) + DEBUGPCRF("error during transceive_sf REQA"); + else + DEBUGPCRF("received ATQA: %s", hexdump((char *)&atqa, sizeof(atqa))); + break; + case MODE_WUPA: + status = rc632_iso14443a_transceive_sf(RAH, ISO14443A_SF_CMD_WUPA, &atqa); + if (status < 0) + DEBUGPCRF("error during transceive_sf WUPA"); + else + DEBUGPCRF("received WUPA: %s", hexdump((char *)&atqa, sizeof(atqa))); + break; + case MODE_ANTICOL: + status = rfid_layer2_iso14443a.fn.open(&l2h); + if (status < 0) + DEBUGPCR("error during anticol"); + else + DEBUGPCR("Anticol OK"); + break; + case MODE_14443A: + { + char rx_buf[4]; + int rx_len = sizeof(rx_buf); + rfid_layer2_iso14443a.fn.setopt(&l2h, RFID_OPT_14443A_SPEED_RX, + &speed_idx, sizeof(speed_idx)); + rfid_layer2_iso14443a.fn.setopt(&l2h, RFID_OPT_14443A_SPEED_TX, + &speed_idx, sizeof(speed_idx)); + rfid_layer2_iso14443a.fn.transceive(&l2h, RFID_14443A_FRAME_REGULAR, + &frame_14443a, sizeof(frame_14443a), + &rx_buf, &rx_len, 1, 0); + } + break; + } + + if (status < 0) + led_switch(1, 0); + else + led_switch(1, 1); + + led_toggle(2); + +} diff --git a/openpcd/firmware/src/pcd/pwm.c b/openpcd/firmware/src/pcd/pwm.c new file mode 100644 index 0000000..ef1ee3f --- /dev/null +++ b/openpcd/firmware/src/pcd/pwm.c @@ -0,0 +1,165 @@ +/* AT91SAM7 PWM routines for OpenPCD / OpenPICC + * + * (C) 2006 by Harald Welte + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../openpcd.h" + +#define Hz +#define kHz *1000 Hz +#define MHz *1000 kHz +#define MCLK (48 MHz) + +#if 1 +#define DEBUGPWM DEBUGPCRF +#else +#define DEBUGPWM(x, args...) +#endif + +static AT91PS_PWMC pwm = AT91C_BASE_PWMC; + +/* find highest bit set. returns bit (32..1) or 0 in case no bit set */ +static int fhs(u_int32_t val) +{ + int i; + + for (i = 32; i > 0; i--) { + if (val & (1 << (i-1))) + return i; + } + + return 0; +} + +/* set frequency of PWM signal to freq */ +int pwm_freq_set(int channel, u_int32_t freq) +{ + /* in order to get maximum resolution, the pre-scaler must be set to + * something like freq << 16. However, the mimimum pre-scaled frequency + * we can get is MCLK (48MHz), the minimum is MCLK/(1024*255) = + * 48MHz/261120 = 183Hz */ + u_int32_t overall_div; + u_int32_t presc_total; + u_int8_t cpre = 0; + u_int16_t cprd; + + if (freq > MCLK) + return -ERANGE; + + overall_div = MCLK / freq; + DEBUGPCRF("mclk=%u, freq=%u, overall_div=%u", MCLK, freq, overall_div); + + if (overall_div > 0x7fff) { + /* divisor is larger than half the maximum CPRD register, we + * have to configure prescalers */ + presc_total = overall_div >> 15; + + /* find highest 2^n fitting in prescaler (highest bit set) */ + cpre = fhs(presc_total); + if (cpre > 0) { + /* subtract one, because of fhs semantics */ + cpre--; + } + cprd = overall_div / (1 << cpre); + } else + cprd = overall_div; + + DEBUGPCRF("cpre=%u, cprd=%u", cpre, cprd); + AT91F_PWMC_CfgChannel(AT91C_BASE_PWMC, channel, + cpre|AT91C_PWMC_CPOL, cprd, 1); + + return 0; +} + +void pwm_start(int channel) +{ + AT91F_PWMC_StartChannel(AT91C_BASE_PWMC, (1 << channel)); +} + +void pwm_stop(int channel) +{ + AT91F_PWMC_StopChannel(AT91C_BASE_PWMC, (1 << channel)); +} + +void pwm_duty_set_percent(int channel, u_int16_t duty) +{ + u_int32_t tmp = pwm->PWMC_CH[channel].PWMC_CPRDR & 0xffff; + + tmp = tmp << 16; /* extend value by 2^16 */ + tmp = tmp / 100; /* tmp = 1 % of extended cprd */ + tmp = duty * tmp; /* tmp = 'duty' % of extended cprd */ + tmp = tmp >> 16; /* un-extend tmp (divide by 2^16) */ + + DEBUGPWM("Writing %u to Update register\n", tmp); + AT91F_PWMC_UpdateChannel(AT91C_BASE_PWMC, channel, tmp); +} + +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]; + u_int32_t *freq; + + switch (poh->cmd) { + case OPENPCD_CMD_PWM_ENABLE: + if (poh->val) + pwm_start(0); + else + pwm_stop(0); + break; + case OPENPCD_CMD_PWM_DUTY_SET: + pwm_duty_set_percent(0, poh->val); + break; + case OPENPCD_CMD_PWM_DUTY_GET: + goto respond; + break; + case OPENPCD_CMD_PWM_FREQ_SET: + if (rctx->rx.tot_len < sizeof(*poh)+4) + break; + freq = (void *) poh + sizeof(*poh); + pwm_freq_set(0, *freq); + break; + case OPENPCD_CMD_PWM_FREQ_GET: + goto respond; + break; + default: + break; + } + + req_ctx_put(rctx); + return 0; +respond: + req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); + udp_refill_ep(2, rctx); + return 1; +} + +void pwm_init(void) +{ + /* IMPORTANT: Disable PA17 (SSC TD) output */ + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, AT91C_PIO_PA17); + + /* Set PA23 to Peripheral A (PWM0) */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, OPENPCD_PIO_MFIN_PWM); + + /* Enable Clock for PWM controller */ + AT91F_PWMC_CfgPMC(); + + usb_hdlr_register(&pwm_usb_in, OPENPCD_CMD_CLS_PWM); +} + +void pwm_fini(void) +{ + usb_hdlr_unregister(OPENPCD_CMD_CLS_PWM); + AT91F_PMC_DisablePeriphClock(AT91C_BASE_PMC, (1 << AT91C_ID_PWMC)); +} diff --git a/openpcd/firmware/src/pcd/pwm.h b/openpcd/firmware/src/pcd/pwm.h new file mode 100644 index 0000000..8836c32 --- /dev/null +++ b/openpcd/firmware/src/pcd/pwm.h @@ -0,0 +1,11 @@ +#ifndef _PWM_H +#define _PWM_H + +extern void pwm_freq_set(int channel, u_int32_t freq); +extern void pwm_start(int channel); +extern void pwm_stop(int channel); +extern void pwm_duty_set_percent(int channel, u_int16_t duty); +extern void pwm_init(void); +extern void pwm_fini(void); + +#endif diff --git a/openpcd/firmware/src/pcd/rc632.c b/openpcd/firmware/src/pcd/rc632.c new file mode 100644 index 0000000..9fc7428 --- /dev/null +++ b/openpcd/firmware/src/pcd/rc632.c @@ -0,0 +1,624 @@ +/* Philips CL RC632 driver (via SPI) for OpenPCD firmware + * (C) 2006 by Harald Welte + * + * This is heavily based on the librfid RC632 driver. All primitive access + * functions such as rc632_{reg,fifo}_{read,write}() are API compatible to + * librfid in order to be able to leverage higher-level code from librfid + * to this OpenPCD firmware. + * + * */ + +#include +#include +#include +#include +#include +#include "../openpcd.h" +#include +#include +#include +#include +#include +#include "rc632.h" + +#define ALWAYS_RESPOND + +#define NOTHING do {} while(0) + +#if 0 +#define DEBUGPSPI DEBUGP +#define DEBUGPSPIIRQ DEBUGP +#else +#define DEBUGPSPI(x, args ...) NOTHING +#define DEBUGPSPIIRQ(x, args...) NOTHING +#endif + +#if 0 +#define DEBUG632 DEBUGPCRF +#else +#define DEBUG632(x, args ...) NOTHING +#endif + + +/* SPI driver */ + +#ifdef OLIMEX +#define SPI_DEBUG_LOOPBACK +#endif + +#define SPI_USES_DMA + +#define SPI_MAX_XFER_LEN 65 + +static AT91PS_SPI pSPI = AT91C_BASE_SPI; + +/* SPI irq handler */ +static void spi_irq(void) +{ + u_int32_t status = pSPI->SPI_SR; + + DEBUGPSPIIRQ("spi_irq: 0x%08x ", status); + + if (status & AT91C_SPI_OVRES) + DEBUGPSPIIRQ("Overrun "); + if (status & AT91C_SPI_MODF) + DEBUGPSPIIRQ("ModeFault "); + if (status & AT91C_SPI_ENDRX) { + pSPI->SPI_IDR = AT91C_SPI_ENDRX; + DEBUGPSPIIRQ("ENDRX "); + } + if (status & AT91C_SPI_ENDTX) { + pSPI->SPI_IDR = AT91C_SPI_ENDTX; + DEBUGPSPIIRQ("ENDTX "); + } + + DEBUGPSPIIRQ("\r\n"); + + AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_SPI); +} + +#ifdef SPI_USES_DMA +static int spi_transceive(const u_int8_t *tx_data, u_int16_t tx_len, + u_int8_t *rx_data, u_int16_t *rx_len) +{ + //tx_len = *rx_len = 65; + DEBUGPSPI("DMA Xfer tx=%s\r\n", hexdump(tx_data, tx_len)); + if (*rx_len < tx_len) { + DEBUGPCRF("rx_len=%u smaller tx_len=%u\n", *rx_len, tx_len); + return -1; + } + //AT91F_SPI_Disable(pSPI); + + AT91F_SPI_ReceiveFrame(pSPI, rx_data, tx_len, NULL, 0); + AT91F_SPI_SendFrame(pSPI, tx_data, tx_len, NULL, 0); + + AT91F_PDC_EnableRx(AT91C_BASE_PDC_SPI); + AT91F_PDC_EnableTx(AT91C_BASE_PDC_SPI); + + pSPI->SPI_IER = AT91C_SPI_ENDTX|AT91C_SPI_ENDRX; + //pSPI->SPI_IDR = AT91C_SPI_ENDTX|AT91C_SPI_ENDRX; + + + while (! (pSPI->SPI_SR & AT91C_SPI_ENDRX)) ; + + DEBUGPSPI("DMA Xfer finished rx=%s\r\n", hexdump(rx_data, tx_len)); + + *rx_len = tx_len; + + return 0; +} +#else +/* stupid polling transceiver routine */ +static int spi_transceive(const u_int8_t *tx_data, u_int16_t tx_len, + u_int8_t *rx_data, u_int16_t *rx_len) +{ + u_int16_t tx_cur = 0; + u_int16_t rx_len_max = 0; + u_int16_t rx_cnt = 0; + + /* disable RC632 interrupt because it wants to do SPI transactions */ + AT91F_AIC_DisableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); + + DEBUGPSPI("spi_transceive: enter(tx_len=%u) ", tx_len); + + if (rx_len) { + rx_len_max = *rx_len; + *rx_len = 0; + } + + //AT91F_SPI_Enable(pSPI); + while (1) { + u_int32_t sr = pSPI->SPI_SR; + u_int8_t tmp; + if (sr & AT91C_SPI_RDRF) { + tmp = pSPI->SPI_RDR; + rx_cnt++; + if (rx_len && *rx_len < rx_len_max) + rx_data[(*rx_len)++] = tmp; + } + if (sr & AT91C_SPI_TDRE) { + if (tx_len > tx_cur) + pSPI->SPI_TDR = tx_data[tx_cur++]; + } + if (tx_cur >= tx_len && rx_cnt >= tx_len) + break; + } + //AT91F_SPI_Disable(pSPI); + if (rx_data) + DEBUGPSPI("leave(%02x %02x)\r\n", rx_data[0], rx_data[1]); + else + DEBUGPSPI("leave()\r\n"); + + /* Re-enable RC632 interrupts */ + AT91F_AIC_EnableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); + + return 0; +} +#endif + +/* RC632 driver */ + +/* static buffers used by RC632 access primitives below. + * Since we only have one */ + +static u_int8_t spi_outbuf[SPI_MAX_XFER_LEN]; +static u_int8_t spi_inbuf[SPI_MAX_XFER_LEN]; + +#define FIFO_ADDR (RC632_REG_FIFO_DATA << 1) + +struct rc632 { + u_int16_t flags; + struct fifo fifo; +}; +#define RC632_F_FIFO_TX 0x0001 +static struct rc632 rc632; + +/* RC632 access primitives */ + +int rc632_reg_write(struct rfid_asic_handle *hdl, + u_int8_t addr, u_int8_t data) +{ + u_int16_t rx_len = 2; + + DEBUG632("[0x%02x] <= 0x%02x", addr, data); + + addr = (addr << 1) & 0x7e; + + spi_outbuf[0] = addr; + spi_outbuf[1] = data; + + //spi_transceive(spi_outbuf, 2, NULL, NULL); + return spi_transceive(spi_outbuf, 2, spi_inbuf, &rx_len); +} + +int rc632_fifo_write(struct rfid_asic_handle *hdl, + u_int8_t len, u_int8_t *data, u_int8_t flags) +{ + if (len > sizeof(spi_outbuf)-1) + len = sizeof(spi_outbuf)-1; + + spi_outbuf[0] = FIFO_ADDR; + memcpy(&spi_outbuf[1], data, len); + + DEBUG632("[FIFO] <= %s", hexdump(data, len)); + + return spi_transceive(spi_outbuf, len+1, NULL, NULL); +} + +int rc632_reg_read(struct rfid_asic_handle *hdl, + u_int8_t addr, u_int8_t *val) +{ + u_int16_t rx_len = 2; + + addr = (addr << 1) & 0x7e; + + spi_outbuf[0] = addr | 0x80; + spi_outbuf[1] = 0x00; + + spi_transceive(spi_outbuf, 2, spi_inbuf, &rx_len); + *val = spi_inbuf[1]; + + DEBUG632("[0x%02x] => 0x%02x", addr>>1, *val); + + return 0; +} + +int rc632_fifo_read(struct rfid_asic_handle *hdl, + u_int8_t max_len, u_int8_t *data) +{ + int ret; + u_int8_t fifo_length; + u_int8_t i; + u_int16_t rx_len; + + ret = rc632_reg_read(hdl, RC632_REG_FIFO_LENGTH, &fifo_length); + if (ret < 0) + return ret; + + rx_len = fifo_length+1; + + if (max_len < fifo_length) + fifo_length = max_len; + + for (i = 0; i < fifo_length; i++) + spi_outbuf[i] = FIFO_ADDR; + + spi_outbuf[0] |= 0x80; + spi_outbuf[fifo_length] = 0x00; + + spi_transceive(spi_outbuf, fifo_length+1, spi_inbuf, &rx_len); + memcpy(data, spi_inbuf+1, rx_len-1); + + DEBUG632("[FIFO] => %s", hexdump(data, rx_len-1)); + + return 0; +} + +int rc632_set_bits(struct rfid_asic_handle *hdl, + u_int8_t reg, u_int8_t bits) +{ + u_int8_t val; + int ret; + + ret = rc632_reg_read(hdl, reg, &val); + if (ret < 0) + return ret; + + val |= bits; + + return rc632_reg_write(hdl, reg, val); +} + +int rc632_clear_bits(struct rfid_asic_handle *hdl, + u_int8_t reg, u_int8_t bits) +{ + u_int8_t val; + int ret; + + ret = rc632_reg_read(hdl, reg, &val); + if (ret < 0) + return ret; + + val &= ~bits; + + return rc632_reg_write(hdl, reg, val); +} + +/* RC632 interrupt handling */ + +static void rc632_irq(void) +{ + struct req_ctx *irq_rctx; + struct openpcd_hdr *irq_opcdh; + u_int8_t cause; + + /* CL RC632 has interrupted us */ + rc632_reg_read(RAH, RC632_REG_INTERRUPT_RQ, &cause); + + /* ACK all interrupts */ + //rc632_reg_write(RAH, RC632_REG_INTERRUPT_RQ, cause); + rc632_reg_write(RAH, RC632_REG_INTERRUPT_RQ, RC632_INT_TIMER); + DEBUGP("rc632_irq: "); + + if (cause & RC632_INT_LOALERT) { + /* FIFO is getting low, refill from virtual FIFO */ + DEBUGP("FIFO_low "); + #if 0 + if (!fifo_available(&rc632.fifo)) + return; + #endif + /* FIXME */ + } + if (cause & RC632_INT_HIALERT) { + /* FIFO is getting full, empty into virtual FIFO */ + DEBUGP("FIFO_high "); + /* FIXME */ + } + /* All interrupts below can be reported directly to the host */ + if (cause & RC632_INT_TIMER) + DEBUGP("Timer "); + if (cause & RC632_INT_IDLE) + DEBUGP("Idle "); + if (cause & RC632_INT_RX) + DEBUGP("RxComplete "); + if (cause & RC632_INT_TX) + DEBUGP("TxComplete "); + + + irq_rctx = req_ctx_find_get(RCTX_STATE_FREE, + RCTX_STATE_RC632IRQ_BUSY); + if (!irq_rctx) { + DEBUGPCRF("NO RCTX!\n"); + /* disable rc632 interrupt until RCTX is free */ + AT91F_AIC_DisableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); + return; + } + + irq_opcdh = (struct openpcd_hdr *) &irq_rctx->tx.data[0]; + + /* initialize static part of openpcd_hdr for USB IRQ reporting */ + irq_opcdh->cmd = OPENPCD_CMD_IRQ; + irq_opcdh->flags = 0x00; + irq_opcdh->reg = 0x07; + irq_opcdh->val = cause; + + req_ctx_set_state(irq_rctx, RCTX_STATE_UDP_EP3_PENDING); + DEBUGPCR(""); +} + +void rc632_unthrottle(void) +{ + AT91F_AIC_EnableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); +} + +void rc632_power(u_int8_t up) +{ + DEBUGPCRF("powering %s RC632", up ? "up" : "down"); + if (up) + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, + OPENPCD_PIO_RC632_RESET); + else + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, + OPENPCD_PIO_RC632_RESET); +} + +void rc632_reset(void) +{ + volatile int i; + + rc632_power(0); + for (i = 0; i < 0xffff; i++) + {} + rc632_power(1); + + /* wait for startup phase to finish */ + while (1) { + u_int8_t val; + rc632_reg_read(RAH, RC632_REG_COMMAND, &val); + if (val == 0x00) + break; + } + + /* turn off register paging */ + rc632_reg_write(RAH, RC632_REG_PAGE0, 0x00); +} + +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); + + 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; + break; + case OPENPCD_CMD_READ_FIFO: + { + u_int16_t req_len = poh->val, remain_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; + DEBUGP("READ FIFO(len=%u)=%s ", req_len, + hexdump(pih->data, pih_len)); + req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); + udp_refill_ep(2, rctx); + + /* get and initialize second rctx */ + rctx = req_ctx_find_get(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); + + pih_len = remain_len; + rc632_fifo_read(RAH, pih->val, pih->data); + rctx->tx.tot_len += pih_len; + DEBUGP("READ FIFO(len=%u)=%s ", pih_len, + hexdump(pih->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; + DEBUGP("READ FIFO(len=%u)=%s ", poh->val, + hexdump(pih->data, poh->val)); + } + goto respond; + 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); + break; + case OPENPCD_CMD_WRITE_FIFO: + DEBUGP("WRITE FIFO(len=%u): %s ", len, + hexdump(poh->data, len)); + rc632_fifo_write(RAH, len, poh->data, 0); + break; + case OPENPCD_CMD_READ_VFIFO: + DEBUGP("READ VFIFO "); + DEBUGP("NOT IMPLEMENTED YET "); + goto respond; + break; + case OPENPCD_CMD_WRITE_VFIFO: + DEBUGP("WRITE VFIFO "); + DEBUGP("NOT IMPLEMENTED YET "); + break; + case OPENPCD_CMD_REG_BITS_CLEAR: + DEBUGP("CLEAR BITS "); + pih->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); + break; + case OPENPCD_CMD_DUMP_REGS: + DEBUGP("DUMP REGS "); + DEBUGP("NOT IMPLEMENTED YET "); + goto respond; + 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; +} + +void rc632_init(void) +{ + //fifo_init(&rc632.fifo, 256, NULL, &rc632); + + DEBUGPCRF("entering"); + + AT91F_SPI_CfgPMC(); + + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, + AT91C_PA11_NPCS0|AT91C_PA12_MISO| + AT91C_PA13_MOSI |AT91C_PA14_SPCK, 0); + + AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SPI, + OPENPCD_IRQ_PRIO_SPI, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &spi_irq); + AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SPI); + + AT91F_SPI_EnableIt(pSPI, AT91C_SPI_MODF|AT91C_SPI_OVRES); +#ifdef SPI_USES_DMA + AT91F_SPI_EnableIt(pSPI, AT91C_SPI_ENDRX|AT91C_SPI_ENDTX); +#endif + +#ifdef SPI_DEBUG_LOOPBACK + AT91F_SPI_CfgMode(pSPI, AT91C_SPI_MSTR|AT91C_SPI_PS_FIXED| + AT91C_SPI_MODFDIS|AT91C_SPI_LLB); +#else + AT91F_SPI_CfgMode(pSPI, AT91C_SPI_MSTR|AT91C_SPI_PS_FIXED| + AT91C_SPI_MODFDIS); +#endif + /* CPOL = 0, NCPHA = 1, CSAAT = 0, BITS = 0000, SCBR = 10 (4.8MHz), + * DLYBS = 0, DLYBCT = 0 */ +#ifdef SPI_USES_DMA + AT91F_SPI_CfgCs(pSPI, 0, AT91C_SPI_BITS_8|AT91C_SPI_NCPHA|(10<<8)); +#else + /* 320 kHz in case of I/O based SPI */ + AT91F_SPI_CfgCs(pSPI, 0, AT91C_SPI_BITS_8|AT91C_SPI_NCPHA|(0x7f<<8)); +#endif + AT91F_SPI_Enable(pSPI); + + /* Register rc632_irq */ + AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632, + OPENPCD_IRQ_PRIO_RC632, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &rc632_irq); + AT91F_AIC_EnableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); + + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_RC632_RESET); + + rc632_reset(); + + /* configure IRQ pin */ + rc632_reg_write(RAH, RC632_REG_IRQ_PIN_CONFIG, + RC632_IRQCFG_CMOS|RC632_IRQCFG_INV); + /* enable interrupts */ + rc632_reg_write(RAH, RC632_REG_INTERRUPT_EN, RC632_INT_TIMER); + + /* configure AUX to test signal four */ + rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, 0x04); + + usb_hdlr_register(&rc632_usb_in, OPENPCD_CMD_CLS_RC632); +}; + +#if 0 +void rc632_exit(void) +{ + usb_hdlr_unregister(OPENPCD_CMD_CLS_RC632); + AT91F_AIC_DisableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); + AT91F_AIC_DisableIt(AT91C_BASE_AIC, AT91C_ID_SPI); + AT91F_SPI_Disable(pSPI); +} +#endif + +#ifdef DEBUG +static int rc632_reg_write_verify(struct rfid_asic_handle *hdl, + u_int8_t reg, u_int8_t val) +{ + u_int8_t tmp; + + rc632_reg_write(hdl, reg, val); + rc632_reg_read(hdl, reg, &tmp); + + DEBUGPCRF("reg=0x%02x, write=0x%02x, read=0x%02x ", reg, val, tmp); + + return (val == tmp); +} + +int rc632_dump(void) +{ + u_int8_t i; + u_int16_t rx_len = sizeof(spi_inbuf); + + for (i = 0; i <= 0x3f; i++) { + u_int8_t reg = i; + if (reg == RC632_REG_FIFO_DATA) + reg = 0x3e; + + spi_outbuf[i] = reg << 1; + spi_inbuf[i] = 0x00; + } + + /* MSB of first byte of read spi transfer is high */ + spi_outbuf[0] |= 0x80; + + /* last byte of read spi transfer is 0x00 */ + spi_outbuf[0x40] = 0x00; + spi_inbuf[0x40] = 0x00; + + spi_transceive(spi_outbuf, 0x41, spi_inbuf, &rx_len); + + for (i = 0; i < 0x3f; i++) { + if (i == RC632_REG_FIFO_DATA) + DEBUGPCR("REG 0x02 = NOT READ"); + else + DEBUGPCR("REG 0x%02x = 0x%02x", i, spi_inbuf[i+1]); + } + + return 0; +} + +int rc632_test(struct rfid_asic_handle *hdl) +{ + if (rc632_reg_write_verify(hdl, RC632_REG_RX_WAIT, 0x55) != 1) + return -1; + + if (rc632_reg_write_verify(hdl, RC632_REG_RX_WAIT, 0xAA) != 1) + return -1; + + return 0; +} +#else /* DEBUG */ +int rc632_test(struct rfid_asic_handle *hdl) {} +int rc632_dump(void) {} +#endif /* DEBUG */ diff --git a/openpcd/firmware/src/pcd/rc632.h b/openpcd/firmware/src/pcd/rc632.h new file mode 100644 index 0000000..1a4dc22 --- /dev/null +++ b/openpcd/firmware/src/pcd/rc632.h @@ -0,0 +1,31 @@ +#ifndef _RC623_API_H +#define _RC632_API_H + +#include +#include +#include + +extern int rc632_reg_write(struct rfid_asic_handle *hdl, + u_int8_t addr, u_int8_t data); +extern int rc632_fifo_write(struct rfid_asic_handle *hdl, + u_int8_t len, u_int8_t *data, u_int8_t flags); +extern int rc632_reg_read(struct rfid_asic_handle *hdl, + u_int8_t addr, u_int8_t *val); +extern int rc632_fifo_read(struct rfid_asic_handle *hdl, + u_int8_t max_len, u_int8_t *data); +extern int rc632_clear_bits(struct rfid_asic_handle *hdl, + u_int8_t reg, u_int8_t bits); +extern int rc632_set_bits(struct rfid_asic_handle *hdl, + u_int8_t reg, u_int8_t bits); + +extern void rc632_init(void); +extern void rc632_exit(void); + +extern void rc632_unthrottle(void); + +#ifdef DEBUG +extern int rc632_test(struct rfid_asic_handle *hdl); +extern int rc632_dump(void); +#endif + +#endif diff --git a/openpcd/firmware/src/pcd/rc632_highlevel.c b/openpcd/firmware/src/pcd/rc632_highlevel.c new file mode 100644 index 0000000..8cb1b86 --- /dev/null +++ b/openpcd/firmware/src/pcd/rc632_highlevel.c @@ -0,0 +1,1465 @@ +/* Generic Philips CL RC632 Routines + * + * (C) Harald Welte + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * 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 + */ + +#include +#include +#include +#include +#include "rc632.h" +#include +#include +#include + +/* initially we use the same values as cm5121 */ +#define OPENPCD_CW_CONDUCTANCE 0x3f +#define OPENPCD_MOD_CONDUCTANCE 0x3f +#define OPENPCD_14443A_BITPHASE 0xa9 +#define OPENPCD_14443A_THRESHOLD 0xff +#define OPENPCD_14443B_BITPHASE 0xad +#define OPENPCD_14443B_THRESHOLD 0xff + +#define RC632_TMO_AUTH1 14000 + +#define RC632_TIMEOUT_FUZZ_FACTOR 10 + +#define USE_IRQ + +#define ENTER() DEBUGPCRF("entering") +struct rfid_asic rc632; + +static int +rc632_set_bit_mask(struct rfid_asic_handle *handle, + u_int8_t reg, u_int8_t mask, u_int8_t val) +{ + int ret; + u_int8_t tmp; + + ret = rc632_reg_read(handle, reg, &tmp); + if (ret < 0) + return ret; + + /* if bits are already like we want them, abort */ + if ((tmp & mask) == val) + return 0; + + return rc632_reg_write(handle, reg, (tmp & ~mask)|(val & mask)); +} + +int +rc632_turn_on_rf(struct rfid_asic_handle *handle) +{ + ENTER(); + return rc632_set_bits(handle, RC632_REG_TX_CONTROL, 0x03); +} + +int +rc632_turn_off_rf(struct rfid_asic_handle *handle) +{ + ENTER(); + return rc632_clear_bits(handle, RC632_REG_TX_CONTROL, 0x03); +} + +static int +rc632_power_up(struct rfid_asic_handle *handle) +{ + ENTER(); + return rc632_clear_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_POWERDOWN); +} + +static int +rc632_power_down(struct rfid_asic_handle *handle) +{ + return rc632_set_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_POWERDOWN); +} + +/* calculate best 8bit prescaler and divisor for given usec timeout */ +static int best_prescaler(u_int64_t timeout, u_int8_t *prescaler, + u_int8_t *divisor) +{ + u_int8_t best_presc, best_divisor, i; + int64_t smallest_diff; + + smallest_diff = 0x7fffffffffffffff; + best_presc = 0; + + for (i = 0; i < 21; i++) { + u_int64_t clk, tmp_div, res; + int64_t diff; + clk = 13560000 / (1 << i); + tmp_div = (clk * timeout) / 1000000; + tmp_div++; + + if (tmp_div > 0xff) + continue; + + res = 1000000 / (clk / tmp_div); + diff = res - timeout; + + if (diff < 0) + continue; + + if (diff < smallest_diff) { + best_presc = i; + best_divisor = tmp_div; + smallest_diff = diff; + } + } + + *prescaler = best_presc; + *divisor = best_divisor; + + DEBUGPCRF("timeout %u usec, prescaler = %u, divisor = %u", timeout, best_presc, best_divisor); + + return 0; +} + +static int +rc632_timer_set(struct rfid_asic_handle *handle, + u_int64_t timeout) +{ + int ret; + u_int8_t prescaler, divisor; + + ret = best_prescaler(timeout*RC632_TIMEOUT_FUZZ_FACTOR, + &prescaler, &divisor); + + ret = rc632_reg_write(handle, RC632_REG_TIMER_CLOCK, + prescaler & 0x1f); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_TIMER_CONTROL, + RC632_TMR_START_TX_END|RC632_TMR_STOP_RX_BEGIN); + + /* clear timer irq bit */ + ret |= rc632_set_bits(handle, RC632_REG_INTERRUPT_RQ, RC632_INT_TIMER); + +#ifdef USE_IRQ_ + /* enable interrupt for expired timer */ + ret |= rc632_reg_write(handle, RC632_REG_INTERRUPT_EN, + RC632_INT_TIMER|RC632_INT_SET); +#endif + + ret |= rc632_reg_write(handle, RC632_REG_TIMER_RELOAD, divisor); + + return ret; +} + +/* Wait until RC632 is idle or TIMER IRQ has happened */ +static int rc632_wait_idle_timer(struct rfid_asic_handle *handle) +{ + int ret; + u_int8_t irq, cmd; + + while (1) { + ret = rc632_reg_read(handle, RC632_REG_INTERRUPT_RQ, &irq); + if (ret < 0) + return ret; + + /* FIXME: currently we're lazy: If we actually received + * something even after the timer expired, we accept it */ + if (irq & RC632_INT_TIMER && !(irq & RC632_INT_RX)) { + u_int8_t foo; + rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &foo); + DEBUGPCRF("TIMER && !INT_RX, PRIM_STATUS=0x%02x", foo); + if (foo & 0x04) { + rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &foo); + DEBUGPCRF("ERROR_FLAG=0x%02x, returning timeout", foo); + } + + return -ETIMEDOUT; + } + + ret = rc632_reg_read(handle, RC632_REG_COMMAND, &cmd); + if (ret < 0) + return ret; + + if (cmd == 0 || irq & RC632_INT_RX) + return 0; + + /* poll every millisecond */ + /* FIXME usleep(1000);*/ + } +} + +/* Stupid RC632 implementations don't evaluate interrupts but poll the + * command register for "status idle" */ +static int +rc632_wait_idle(struct rfid_asic_handle *handle, u_int64_t timeout) +{ + u_int8_t cmd = 0xff; + int ret, cycles = 0; +#define USLEEP_PER_CYCLE 128 + + while (cmd != 0) { + ret = rc632_reg_read(handle, RC632_REG_COMMAND, &cmd); + if (ret < 0) + return ret; + + if (cmd == 0) { + /* FIXME: read second time ?? */ + return 0; + } + + { + u_int8_t foo; + rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &foo); + if (foo & 0x04) + rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &foo); + } + + /* Abort after some timeout */ + if (cycles > timeout*RC632_TIMEOUT_FUZZ_FACTOR/USLEEP_PER_CYCLE) { + return -ETIMEDOUT; + } + + cycles++; + usleep(USLEEP_PER_CYCLE); + } + + return 0; +} + +static int +rc632_transmit(struct rfid_asic_handle *handle, + const u_int8_t *buf, + u_int8_t len, + u_int64_t timeout) +{ + int ret, cur_len; + const u_int8_t *cur_buf = buf; + + if (len > 64) + cur_len = 64; + else + cur_len = len; + + do { + ret = rc632_fifo_write(handle, cur_len, cur_buf, 0x03); + if (ret < 0) + return ret; + + if (cur_buf == buf) { + /* only start transmit first time */ + ret = rc632_reg_write(handle, RC632_REG_COMMAND, + RC632_CMD_TRANSMIT); + if (ret < 0) + return ret; + } + + cur_buf += cur_len; + if (cur_buf < buf + len) { + cur_len = buf - cur_buf; + if (cur_len > 64) + cur_len = 64; + } else + cur_len = 0; + + } while (cur_len); + + return rc632_wait_idle(handle, timeout); +} + +static int +tcl_toggle_pcb(struct rfid_asic_handle *handle) +{ + // FIXME: toggle something between 0x0a and 0x0b + return 0; +} + +static int +rc632_transceive(struct rfid_asic_handle *handle, + const u_int8_t *tx_buf, + u_int8_t tx_len, + u_int8_t *rx_buf, + u_int8_t *rx_len, + u_int64_t timer, + unsigned int toggle) +{ + int ret, cur_tx_len; + const u_int8_t *cur_tx_buf = tx_buf; + + DEBUGPCRF("tx_len=%u, rx_len=%u, timer=%llu", tx_len, *rx_len, timer); + + if (tx_len > 64) + cur_tx_len = 64; + else + cur_tx_len = tx_len; + + ret = rc632_reg_write(handle, RC632_REG_COMMAND, 0x00); + /* clear all interrupts */ + ret = rc632_reg_write(handle, RC632_REG_INTERRUPT_RQ, 0x7f); + if (ret < 0) + return ret; + + ret = rc632_timer_set(handle, timer); + if (ret < 0) + return ret; + + do { + ret = rc632_fifo_write(handle, cur_tx_len, cur_tx_buf, 0x03); + if (ret < 0) + return ret; + + if (cur_tx_buf == tx_buf) { + ret = rc632_reg_write(handle, RC632_REG_COMMAND, + RC632_CMD_TRANSCEIVE); + if (ret < 0) + return ret; + } + + cur_tx_buf += cur_tx_len; + if (cur_tx_buf < tx_buf + tx_len) { + u_int8_t fifo_fill; + ret = rc632_reg_read(handle, RC632_REG_FIFO_LENGTH, + &fifo_fill); + if (ret < 0) + return ret; + + cur_tx_len = 64 - fifo_fill; + DEBUGPCRF("refilling tx fifo with %u bytes", cur_tx_len); + } else + cur_tx_len = 0; + + } while (cur_tx_len); + + if (toggle == 1) + tcl_toggle_pcb(handle); + + ret = rc632_wait_idle_timer(handle); + if (ret < 0) + return ret; + + ret = rc632_reg_read(handle, RC632_REG_FIFO_LENGTH, rx_len); + if (ret < 0) + return ret; + + DEBUGPCRF("rx_len = %u\n", *rx_len); + + if (*rx_len == 0) { + u_int8_t tmp, tmp2; + + rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &tmp); + rc632_reg_read(handle, RC632_REG_CHANNEL_REDUNDANCY, &tmp2); + + DEBUGPCRF("rx_len == 0, error_flag=0x%02x, channel_red=0x%02x", + tmp, tmp2); + + return -1; + } + + return rc632_fifo_read(handle, *rx_len, rx_buf); +} + +static int +rc632_read_eeprom(struct rfid_asic_handle *handle) +{ + u_int8_t recvbuf[60]; + u_int8_t sndbuf[3]; + int ret; + + sndbuf[0] = 0x00; + sndbuf[1] = 0x00; + sndbuf[2] = 0x3c; + + ret = rc632_fifo_write(handle, 3, sndbuf, 0x03); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_READ_E2); + if (ret < 0) + return ret; + + usleep(20000); + + ret = rc632_fifo_read(handle, sizeof(recvbuf), recvbuf); + if (ret < 0) + return ret; + + // FIXME: do something with eeprom contents + return ret; +} + +static int +rc632_calc_crc16_from(struct rfid_asic_handle *handle) +{ + u_int8_t sndbuf[2] = { 0x01, 0x02 }; + u_int8_t crc_lsb = 0x00 , crc_msb = 0x00; + int ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0x12); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0xe0); + if (ret < 0) + return ret; + + ret = rc632_fifo_write(handle, sizeof(sndbuf), sndbuf, 3); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_CALC_CRC); + if (ret < 0) + return ret; + + usleep(10000); // FIXME: no checking for cmd completion? + + ret = rc632_reg_read(handle, RC632_REG_CRC_RESULT_LSB, &crc_lsb); + if (ret < 0) + return ret; + + ret = rc632_reg_read(handle, RC632_REG_CRC_RESULT_MSB, &crc_msb); + if (ret < 0) + return ret; + + // FIXME: what to do with crc result? + return ret; +} + + +int +rc632_register_dump(struct rfid_asic_handle *handle, u_int8_t *buf) +{ + int ret; + u_int8_t i; + + for (i = 0; i <= 0x3f; i++) { + ret = rc632_reg_read(handle, i, &buf[i]); + // do we want error checks? + } + return 0; +} + + +#if 0 +static int +rc632_init(struct rfid_asic_handle *ah) +{ + int ret; + + /* switch off rf (make sure PICCs are reset at init time) */ + ret = rc632_power_down(ah); + if (ret < 0) + return ret; + + usleep(10000); + + /* switch on rf */ + ret = rc632_power_up(ah); + if (ret < 0) + return ret; + + /* disable register paging */ + ret = rc632_reg_write(ah, 0x00, 0x00); + if (ret < 0) + return ret; + + /* set some sane default values */ + ret = rc632_reg_write(ah, 0x11, 0x5b); + if (ret < 0) + return ret; + + /* switch on rf */ + ret = rc632_turn_on_rf(ah); + if (ret < 0) + return ret; + + return 0; +} + +static int +rc632_fini(struct rfid_asic_handle *ah) +{ + int ret; + + /* switch off rf */ + ret = rc632_turn_off_rf(ah); + if (ret < 0) + return ret; + + ret = rc632_power_down(ah); + if (ret < 0) + return ret; + + return 0; +} +#endif + + +/* + * Philips CL RC632 primitives for ISO 14443-A compliant PICC's + * + * (C) 2005 by Harald Welte + * + */ + +int +rc632_iso14443a_init(struct rfid_asic_handle *handle) +{ + int ret; + + // FIXME: some fifo work (drain fifo?) + + /* flush fifo (our way) */ + ret = rc632_reg_write(handle, RC632_REG_CONTROL, 0x01); + + ret = rc632_reg_write(handle, RC632_REG_TX_CONTROL, + (RC632_TXCTRL_TX1_RF_EN | + RC632_TXCTRL_TX2_RF_EN | + RC632_TXCTRL_TX2_INV | + RC632_TXCTRL_FORCE_100_ASK | + RC632_TXCTRL_MOD_SRC_INT)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CW_CONDUCTANCE, + OPENPCD_CW_CONDUCTANCE); + if (ret < 0) + return ret; + + /* Since FORCE_100_ASK is set (cf mc073930.pdf), this line may be left out? */ + ret = rc632_reg_write(handle, RC632_REG_MOD_CONDUCTANCE, + OPENPCD_MOD_CONDUCTANCE); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CODER_CONTROL, + (RC632_CDRCTRL_TXCD_14443A | + RC632_CDRCTRL_RATE_106K)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, 0x13); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH_SOF, 0x3f); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_TYPE_B_FRAMING, 0x00); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL1, + (RC632_RXCTRL1_GAIN_35DB | + RC632_RXCTRL1_ISO14443 | + RC632_RXCTRL1_SUBCP_8)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_DECODER_CONTROL, + (RC632_DECCTRL_MANCHESTER | + RC632_DECCTRL_RXFR_14443A)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BIT_PHASE, + OPENPCD_14443A_BITPHASE); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD, + OPENPCD_14443A_THRESHOLD); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BPSK_DEM_CONTROL, 0x00); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL2, + (RC632_RXCTRL2_DECSRC_INT | + RC632_RXCTRL2_CLK_Q)); + if (ret < 0) + return ret; + + /* Omnikey proprietary driver has 0x03, but 0x06 is the default reset value ?!? */ + ret = rc632_reg_write(handle, RC632_REG_RX_WAIT, 0x06); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0x63); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0x63); + if (ret < 0) + return ret; + + return 0; +} + +static int +rc632_iso14443a_fini(struct iso14443a_handle *handle_14443) +{ + +#if 0 + ret = rc632_turn_off_rf(handle); + if (ret < 0) + return ret; +#endif + + + return 0; +} + + +/* issue a 14443-3 A PCD -> PICC command in a short frame, such as REQA, WUPA */ +int +rc632_iso14443a_transceive_sf(struct rfid_asic_handle *handle, + u_int8_t cmd, + struct iso14443a_atqa *atqa) +{ + int ret; + u_int8_t tx_buf[1]; + u_int8_t rx_len = 2; + + DEBUGPCRF(""); + memset(atqa, 0, sizeof(atqa)); + + tx_buf[0] = cmd; + + /* transfer only 7 bits of last byte in frame */ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x07); + if (ret < 0) + return ret; + + ret = rc632_clear_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_CRYPTO1_ON); + if (ret < 0) + return ret; + +#if 0 + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); +#else + ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); + +#endif + if (ret < 0) + return ret; + + ret = rc632_transceive(handle, tx_buf, sizeof(tx_buf), + (u_int8_t *)atqa, &rx_len, + ISO14443A_FDT_ANTICOL_LAST1, 0); + if (ret < 0) { + DEBUGPCRF("error during rc632_transceive()"); + return ret; + } + + /* switch back to normal 8bit last byte */ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x00); + if (ret < 0) + return ret; + + if (rx_len != 2) { + DEBUGPCRF("rx_len(%d) != 2", rx_len); + return -1; + } + + return 0; +} + +/* transceive regular frame */ +int +rc632_iso14443ab_transceive(struct rfid_asic_handle *handle, + unsigned int frametype, + const u_int8_t *tx_buf, unsigned int tx_len, + u_int8_t *rx_buf, unsigned int *rx_len, + u_int64_t timeout, unsigned int flags) +{ + int ret; + u_int8_t rxl = *rx_len & 0xff; + u_int8_t channel_red; + + DEBUGPCRF("tx_len=%u, rx_len=%u", tx_len, *rx_len); + + memset(rx_buf, 0, *rx_len); + + switch (frametype) { + case RFID_14443A_FRAME_REGULAR: + case RFID_MIFARE_FRAME: + channel_red = RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE + |RC632_CR_PARITY_ENABLE|RC632_CR_PARITY_ODD; + break; + case RFID_14443B_FRAME_REGULAR: + channel_red = RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE + |RC632_CR_CRC3309; + break; +#if 0 + case RFID_MIFARE_FRAME: + channel_red = RC632_CR_PARITY_ENABLE|RC632_CR_PARITY_ODD; + break; +#endif + default: + return -EINVAL; + break; + } + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + channel_red); + if (ret < 0) + return ret; + + ret = rc632_transceive(handle, tx_buf, tx_len, rx_buf, &rxl, timeout, 0); + *rx_len = rxl; + if (ret < 0) + return ret; + + + return 0; +} + +/* transceive anti collission bitframe */ +int +rc632_iso14443a_transceive_acf(struct rfid_asic_handle *handle, + struct iso14443a_anticol_cmd *acf, + unsigned int *bit_of_col) +{ + int ret; + u_int8_t rx_buf[64]; + u_int8_t rx_len = sizeof(rx_buf); + u_int8_t rx_align = 0, tx_last_bits, tx_bytes; + u_int8_t boc; + u_int8_t error_flag; + *bit_of_col = ISO14443A_BITOFCOL_NONE; + memset(rx_buf, 0, sizeof(rx_buf)); + + /* disable mifare cryto */ + ret = rc632_clear_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_CRYPTO1_ON); + if (ret < 0) + return ret; + + /* disable CRC summing */ +#if 0 + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); +#else + ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_TX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); +#endif + if (ret < 0) + return ret; + + tx_last_bits = acf->nvb & 0x0f; /* lower nibble indicates bits */ + tx_bytes = acf->nvb >> 4; + if (tx_last_bits) { + tx_bytes++; + rx_align = (tx_last_bits+1) % 8;/* rx frame complements tx */ + } + + //rx_align = 8 - tx_last_bits;/* rx frame complements tx */ + + /* set RxAlign and TxLastBits*/ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, + (rx_align << 4) | (tx_last_bits)); + if (ret < 0) + return ret; + + ret = rc632_transceive(handle, (u_int8_t *)acf, tx_bytes, + rx_buf, &rx_len, 0x32, 0); + if (ret < 0) + return ret; + + /* bitwise-OR the two halves of the split byte */ + acf->uid_bits[tx_bytes-2] = ( + (acf->uid_bits[tx_bytes-2] & (0xff >> (8-tx_last_bits))) + | rx_buf[0]); + /* copy the rest */ + memcpy(&acf->uid_bits[tx_bytes+1-2], &rx_buf[1], rx_len-1); + + /* determine whether there was a collission */ + ret = rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &error_flag); + if (ret < 0) + return ret; + + if (error_flag & RC632_ERR_FLAG_COL_ERR) { + /* retrieve bit of collission */ + ret = rc632_reg_read(handle, RC632_REG_COLL_POS, &boc); + if (ret < 0) + return ret; + + /* bit of collission relative to start of part 1 of + * anticollision frame (!) */ + *bit_of_col = 2*8 + boc; + } + + return 0; +} + +enum rc632_rate { + RC632_RATE_106 = 0x00, + RC632_RATE_212 = 0x01, + RC632_RATE_424 = 0x02, + RC632_RATE_848 = 0x03, +}; + +struct rx_config { + u_int8_t subc_pulses; + u_int8_t rx_coding; + u_int8_t rx_threshold; + u_int8_t bpsk_dem_ctrl; +}; + +struct tx_config { + u_int8_t rate; + u_int8_t mod_width; +}; + +static const struct rx_config rx_configs[] = { + { + .subc_pulses = RC632_RXCTRL1_SUBCP_8, + .rx_coding = RC632_DECCTRL_MANCHESTER, + .rx_threshold = 0x88, + .bpsk_dem_ctrl = 0x00, + }, + { + .subc_pulses = RC632_RXCTRL1_SUBCP_4, + .rx_coding = RC632_DECCTRL_BPSK, + .rx_threshold = 0x50, + .bpsk_dem_ctrl = 0x0c, + }, + { + .subc_pulses = RC632_RXCTRL1_SUBCP_2, + .rx_coding = RC632_DECCTRL_BPSK, + .rx_threshold = 0x50, + .bpsk_dem_ctrl = 0x0c, + }, + { + .subc_pulses = RC632_RXCTRL1_SUBCP_1, + .rx_coding = RC632_DECCTRL_BPSK, + .rx_threshold = 0x50, + .bpsk_dem_ctrl = 0x0c, + }, +}; + +static const struct tx_config tx_configs[] = { + { + .rate = RC632_CDRCTRL_RATE_106K, + .mod_width = 0x13, + }, + { + .rate = RC632_CDRCTRL_RATE_212K, + .mod_width = 0x07, + }, + { + .rate = RC632_CDRCTRL_RATE_424K, + .mod_width = 0x03, + }, + { + .rate = RC632_CDRCTRL_RATE_848K, + .mod_width = 0x01, + }, +}; + +int rc632_iso14443a_set_speed(struct rfid_asic_handle *handle, + unsigned int tx, + u_int8_t rate) +{ + int rc; + u_int8_t reg; + + + if (!tx) { + /* Rx */ + if (rate > ARRAY_SIZE(rx_configs)) + return -EINVAL; + + rc = rc632_set_bit_mask(handle, RC632_REG_RX_CONTROL1, + RC632_RXCTRL1_SUBCP_MASK, + rx_configs[rate].subc_pulses); + if (rc < 0) + return rc; + + rc = rc632_set_bit_mask(handle, RC632_REG_DECODER_CONTROL, + RC632_DECCTRL_BPSK, + rx_configs[rate].rx_coding); + if (rc < 0) + return rc; + + rc = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD, + rx_configs[rate].rx_threshold); + if (rc < 0) + return rc; + + if (rx_configs[rate].rx_coding == RC632_DECCTRL_BPSK) { + rc = rc632_reg_write(handle, + RC632_REG_BPSK_DEM_CONTROL, + rx_configs[rate].bpsk_dem_ctrl); + if (rc < 0) + return rc; + } + } else { + /* Tx */ + if (rate > ARRAY_SIZE(tx_configs)) + return -EINVAL; + + rc = rc632_set_bit_mask(handle, RC632_REG_CODER_CONTROL, + RC632_CDRCTRL_RATE_MASK, + tx_configs[rate].rate); + if (rc < 0) + return rc; + + rc = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, + tx_configs[rate].mod_width); + if (rc < 0) + return rc; + } + + return 0; +} + +static int rc632_iso14443b_init(struct rfid_asic_handle *handle) +{ + int ret; + + // FIXME: some FIFO work + + /* flush fifo (our way) */ + ret = rc632_reg_write(handle, RC632_REG_CONTROL, 0x01); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_TX_CONTROL, + (RC632_TXCTRL_TX1_RF_EN | + RC632_TXCTRL_TX2_RF_EN | + RC632_TXCTRL_TX2_INV | + RC632_TXCTRL_MOD_SRC_INT)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CW_CONDUCTANCE, 0x3f); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_CONDUCTANCE, 0x04); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CODER_CONTROL, + (RC632_CDRCTRL_TXCD_NRZ | + RC632_CDRCTRL_RATE_14443B)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, 0x13); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH_SOF, 0x3f); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_TYPE_B_FRAMING, + (RC632_TBFRAMING_SOF_11L_3H | + (6 << RC632_TBFRAMING_SPACE_SHIFT) | + RC632_TBFRAMING_EOF_11)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL1, + (RC632_RXCTRL1_GAIN_35DB | + RC632_RXCTRL1_ISO14443 | + RC632_RXCTRL1_SUBCP_8)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_DECODER_CONTROL, + (RC632_DECCTRL_BPSK | + RC632_DECCTRL_RXFR_14443B)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BIT_PHASE, + OPENPCD_14443B_BITPHASE); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD, + OPENPCD_14443B_THRESHOLD); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BPSK_DEM_CONTROL, + ((0x2 & RC632_BPSKD_TAUB_MASK)<> 4; + key12[i * 2 + 1] = (~ln << 4) | ln; + key12[i * 2] = (~hn << 4) | hn; + } + return 0; +} + +static int +rc632_mifare_set_key(struct rfid_asic_handle *h, const u_int8_t *key) +{ + u_int8_t coded_key[RFID_MIFARE_KEY_CODED_LEN]; + u_int8_t reg; + int ret; + + ret = rc632_mifare_transform_key(key, coded_key); + if (ret < 0) + return ret; + + ret = rc632_fifo_write(h, RFID_MIFARE_KEY_CODED_LEN, coded_key, 0x03); + if (ret < 0) + return ret; + + ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_LOAD_KEY); + if (ret < 0) + return ret; + + ret = rc632_wait_idle(h, RC632_TMO_AUTH1); + if (ret < 0) + return ret; + + ret = rc632_reg_read(h, RC632_REG_ERROR_FLAG, ®); + if (ret < 0) + return ret; + + if (reg & RC632_ERR_FLAG_KEY_ERR) + return -EINVAL; + + return 0; +} + +static int +rc632_mifare_auth(struct rfid_asic_handle *h, u_int8_t cmd, u_int32_t serno, + u_int8_t block) +{ + int ret; + struct mifare_authcmd acmd; + u_int8_t reg; + + if (cmd != RFID_CMD_MIFARE_AUTH1A && cmd != RFID_CMD_MIFARE_AUTH1B) + return -EINVAL; + + /* Initialize acmd */ + acmd.block_address = block & 0xff; + acmd.auth_cmd = cmd; + //acmd.serno = htonl(serno); + acmd.serno = serno; + + /* Clear Rx CRC */ + ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_RX_CRC_ENABLE); + if (ret < 0) + return ret; + + /* Send Authent1 Command */ + ret = rc632_fifo_write(h, sizeof(acmd), (unsigned char *)&acmd, 0x03); + if (ret < 0) + return ret; + + ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_AUTHENT1); + if (ret < 0) + return ret; + + /* Wait until transmitter is idle */ + ret = rc632_wait_idle(h, RC632_TMO_AUTH1); + if (ret < 0) + return ret; + + ret = rc632_reg_read(h, RC632_REG_SECONDARY_STATUS, ®); + if (ret < 0) + return ret; + if (reg & 0x07) + return -EIO; + + /* Clear Tx CRC */ + ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_TX_CRC_ENABLE); + if (ret < 0) + return ret; + + /* Send Authent2 Command */ + ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_AUTHENT2); + if (ret < 0) + return ret; + + /* Wait until transmitter is idle */ + ret = rc632_wait_idle(h, RC632_TMO_AUTH1); + if (ret < 0) + return ret; + + /* Check whether authentication was successful */ + ret = rc632_reg_read(h, RC632_REG_CONTROL, ®); + if (ret < 0) + return ret; + + if (!(reg & RC632_CONTROL_CRYPTO1_ON)) + return -EACCES; + + return 0; + +} + +/* transceive regular frame */ +static int +rc632_mifare_transceive(struct rfid_asic_handle *handle, + const u_int8_t *tx_buf, unsigned int tx_len, + u_int8_t *rx_buf, unsigned int *rx_len, + u_int64_t timeout, unsigned int flags) +{ + int ret; + u_int8_t rxl = *rx_len & 0xff; + + DEBUGP("entered\n"); + memset(rx_buf, 0, *rx_len); + +#if 1 + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD | + RC632_CR_TX_CRC_ENABLE | + RC632_CR_RX_CRC_ENABLE)); +#else + ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); +#endif + if (ret < 0) + return ret; + + ret = rc632_transceive(handle, tx_buf, tx_len, rx_buf, &rxl, 0x32, 0); + *rx_len = rxl; + if (ret < 0) + return ret; + + + return 0; +} + diff --git a/openpcd/firmware/src/pcd/rfid_layer2_iso14443a.c b/openpcd/firmware/src/pcd/rfid_layer2_iso14443a.c new file mode 100644 index 0000000..80d9d5f --- /dev/null +++ b/openpcd/firmware/src/pcd/rfid_layer2_iso14443a.c @@ -0,0 +1,319 @@ +/* ISO 14443-3 A anticollision implementation + * + * (C) 2005 by Harald Welte + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * 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 + */ + +#include +#include +#include +#include + +#include +#include +//#include +#include + +#define TIMEOUT 1236 + +/* Transceive a 7-bit short frame */ +static int +iso14443a_transceive_sf(struct rfid_layer2_handle *handle, + unsigned char cmd, + struct iso14443a_atqa *atqa) +{ + //struct rfid_reader *rdr = handle->rh->reader; + DEBUGPCRF(""); + + return rc632_iso14443a_transceive_sf(handle->rh, cmd, atqa); +} + +/* Transmit an anticollission bit frame */ +static int +iso14443a_transceive_acf(struct rfid_layer2_handle *handle, + struct iso14443a_anticol_cmd *acf, + unsigned int *bit_of_col) +{ + //struct rfid_reader *rdr = handle->rh->reader; + DEBUGPCRF(""); + + return rc632_iso14443a_transceive_acf(handle->rh, acf, bit_of_col); +} + +/* Transmit a regular frame */ +static int +iso14443a_transceive(struct rfid_layer2_handle *handle, + enum rfid_frametype frametype, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len, + u_int64_t timeout, unsigned int flags) +{ + DEBUGPCRF("tx_len=%u, rx_len=%u", tx_len, *rx_len); + return rc632_iso14443ab_transceive(handle->rh, frametype, tx_buf, + tx_len, rx_buf, rx_len, timeout, flags); +} + +static int +iso14443a_code_nvb_bits(unsigned char *nvb, unsigned int bits) +{ + unsigned int byte_count = bits / 8; + unsigned int bit_count = bits % 8; + + if (byte_count < 2 || byte_count > 7) + return -1; + + *nvb = ((byte_count & 0xf) << 4) | bit_count; + + return 0; +} + +/* first bit is '1', second bit '2' */ +static void +set_bit_in_field(unsigned char *bitfield, unsigned int bit) +{ + unsigned int byte_count = bit / 8; + unsigned int bit_count = bit % 8; + + DEBUGP("bitfield=%p, byte_count=%u, bit_count=%u\n", + bitfield, byte_count, bit_count); + DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count)); + *(bitfield+byte_count) |= 1 << (bit_count-1); + DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count)); +} + +static int +iso14443a_anticol(struct rfid_layer2_handle *handle) +{ + int ret; + unsigned int uid_size; + struct iso14443a_handle *h = &handle->priv.iso14443a; + struct iso14443a_atqa atqa; + struct iso14443a_anticol_cmd acf; + unsigned int bit_of_col; + unsigned char sak[3]; + unsigned int rx_len = sizeof(sak); + char *aqptr = (char *) &atqa; + + memset(handle->uid, 0, sizeof(handle->uid)); + memset(sak, 0, sizeof(sak)); + memset(&atqa, 0, sizeof(atqa)); + memset(&acf, 0, sizeof(acf)); + + ret = iso14443a_transceive_sf(handle, ISO14443A_SF_CMD_REQA, &atqa); + if (ret < 0) { + h->state = ISO14443A_STATE_REQA_SENT; + DEBUGP("error during transceive_sf: %d\n", ret); + return ret; + } + h->state = ISO14443A_STATE_ATQA_RCVD; + + DEBUGP("ATQA: 0x%02x 0x%02x\n", *aqptr, *(aqptr+1)); + + if (!atqa.bf_anticol) { + h->state = ISO14443A_STATE_NO_BITFRAME_ANTICOL; + DEBUGP("no bitframe anticollission bits set, aborting\n"); + return -1; + } + + if (atqa.uid_size == 2 || atqa.uid_size == 3) + uid_size = 3; + else if (atqa.uid_size == 1) + uid_size = 2; + else + uid_size = 1; + + acf.sel_code = ISO14443A_AC_SEL_CODE_CL1; + + h->state = ISO14443A_STATE_ANTICOL_RUNNING; + h->level = ISO14443A_LEVEL_CL1; + +cascade: + iso14443a_code_nvb_bits(&acf.nvb, 16); + + ret = iso14443a_transceive_acf(handle, &acf, &bit_of_col); + if (ret < 0) + return ret; + DEBUGP("bit_of_col = %d\n", bit_of_col); + + while (bit_of_col != ISO14443A_BITOFCOL_NONE) { + set_bit_in_field(&acf.uid_bits[0], bit_of_col-16); + iso14443a_code_nvb_bits(&acf.nvb, bit_of_col); + ret = iso14443a_transceive_acf(handle, &acf, &bit_of_col); + DEBUGP("bit_of_col = %d\n", bit_of_col); + if (ret < 0) + return ret; + } + + iso14443a_code_nvb_bits(&acf.nvb, 7*8); + ret = iso14443a_transceive(handle, RFID_14443A_FRAME_REGULAR, + (unsigned char *)&acf, 7, + (unsigned char *) &sak, &rx_len, + TIMEOUT, 0); + if (ret < 0) + return ret; + + if (sak[0] & 0x04) { + /* Cascade bit set, UID not complete */ + switch (acf.sel_code) { + case ISO14443A_AC_SEL_CODE_CL1: + /* cascading from CL1 to CL2 */ + if (acf.uid_bits[0] != 0x88) { + DEBUGP("Cascade bit set, but UID0 != 0x88\n"); + return -1; + } + memcpy(&handle->uid[0], &acf.uid_bits[1], 3); + acf.sel_code = ISO14443A_AC_SEL_CODE_CL2; + h->level = ISO14443A_LEVEL_CL2; + break; + case ISO14443A_AC_SEL_CODE_CL2: + /* cascading from CL2 to CL3 */ + memcpy(&handle->uid[3], &acf.uid_bits[1], 3); + acf.sel_code = ISO14443A_AC_SEL_CODE_CL3; + h->level = ISO14443A_LEVEL_CL3; + break; + default: + DEBUGP("cannot cascade any further than CL3\n"); + h->state = ISO14443A_STATE_ERROR; + return -1; + break; + } + goto cascade; + + } else { + switch (acf.sel_code) { + case ISO14443A_AC_SEL_CODE_CL1: + /* single size UID (4 bytes) */ + memcpy(&handle->uid[0], &acf.uid_bits[0], 4); + break; + case ISO14443A_AC_SEL_CODE_CL2: + /* double size UID (7 bytes) */ + memcpy(&handle->uid[3], &acf.uid_bits[0], 4); + break; + case ISO14443A_AC_SEL_CODE_CL3: + /* triple size UID (10 bytes) */ + memcpy(&handle->uid[6], &acf.uid_bits[0], 4); + break; + } + } + + h->level = ISO14443A_LEVEL_NONE; + h->state = ISO14443A_STATE_SELECTED; + + { + if (uid_size == 1) + handle->uid_len = 4; + else if (uid_size == 2) + handle->uid_len = 7; + else + handle->uid_len = 10; + + DEBUGP("UID %s\n", rfid_hexdump(handle->uid, handle->uid_len)); + } + + if (sak[0] & 0x20) { + DEBUGP("we have a T=CL compliant PICC\n"); + h->tcl_capable = 1; + } else { + DEBUGP("we have a T!=CL PICC\n"); + h->tcl_capable = 0; + } + + return 0; +} + +static int +iso14443a_hlta(struct rfid_layer2_handle *handle) +{ + int ret; + unsigned char tx_buf[2] = { 0x50, 0x00 }; + unsigned char rx_buf[10]; + unsigned int rx_len = sizeof(rx_buf); + + ret = iso14443a_transceive(handle, RFID_14443A_FRAME_REGULAR, + tx_buf, sizeof(tx_buf), + rx_buf, &rx_len, 1000 /* 1ms */, 0); + if (ret < 0) { + /* "error" case: we don't get somethng back from the card */ + return 0; + } + return -1; +} + +static int +iso14443a_setopt(struct rfid_layer2_handle *handle, int optname, + const void *optval, unsigned int optlen) +{ + int ret = -EINVAL; + unsigned int speed; + + switch (optname) { + case RFID_OPT_14443A_SPEED_RX: + speed = *(unsigned int *)optval; + ret = rc632_iso14443a_set_speed(handle->rh, 0, speed); + break; + case RFID_OPT_14443A_SPEED_TX: + speed = *(unsigned int *)optval; + ret = rc632_iso14443a_set_speed(handle->rh, 1, speed); + break; + }; + + return ret; +} + + +static struct rfid_layer2_handle * +iso14443a_init(struct rfid_reader_handle *rh) +{ + int ret; + struct rfid_layer2_handle *h = malloc(sizeof(*h)); + if (!h) + return NULL; + + h->l2 = &rfid_layer2_iso14443a; + h->rh = rh; + h->priv.iso14443a.state = ISO14443A_STATE_NONE; + h->priv.iso14443a.level = ISO14443A_LEVEL_NONE; + + ret = rc632_iso14443a_init(h->rh); + if (ret < 0) { + free(h); + return NULL; + } + + return h; +} + +static int +iso14443a_fini(struct rfid_layer2_handle *handle) +{ + free(handle); + return 0; +} + +struct rfid_layer2 rfid_layer2_iso14443a = { + .id = RFID_LAYER2_ISO14443A, + .name = "ISO 14443-3 A", + .fn = { + .init = &iso14443a_init, + .open = &iso14443a_anticol, + .transceive = &iso14443a_transceive, + .close = &iso14443a_hlta, + .fini = &iso14443a_fini, + .setopt = &iso14443a_setopt, + }, +}; diff --git a/openpcd/firmware/src/pcd_enumerate.c b/openpcd/firmware/src/pcd_enumerate.c deleted file mode 100644 index 4d89e87..0000000 --- a/openpcd/firmware/src/pcd_enumerate.c +++ /dev/null @@ -1,609 +0,0 @@ -/* AT91SAM7 USB interface code for OpenPCD - * - * (C) 2006 by Harald Welte - * - * based on existing AT91SAM7 UDP CDC ACM example code, licensed as followed: - *---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - ROUSSET - - *---------------------------------------------------------------------------- - * The software is delivered "AS IS" without warranty or condition of any - * kind, either express, implied or statutory. This includes without - * limitation any warranty or condition with respect to merchantability or - * fitness for any particular purpose, or against the infringements of - * intellectual property rights of others. - *---------------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include - -#include "pcd_enumerate.h" -#include "dfu.h" -#include "openpcd.h" -#include "dbgu.h" - -#define DEBUG_UDP_IRQ -#define DEBUG_UDP_EP0 - -#define CONFIG_DFU - -#define AT91C_EP_OUT 1 -#define AT91C_EP_OUT_SIZE 0x40 -#define AT91C_EP_IN 2 -#define AT91C_EP_IN_SIZE 0x40 -#define AT91C_EP_INT 3 - -#ifdef CONFIG_DFU -#define DFU_API_LOCATION ((const struct dfuapi *) 0x1f00) -static const struct dfuapi *dfu = DFU_API_LOCATION; -#define udp_ep0_send_data dfu->ep0_send_data -#define udp_ep0_send_zlp dfu->ep0_send_zlp -#define udp_ep0_send_stall dfu->ep0_send_stall -#else -#error non-DFU builds currently not supported (yet) again -#endif - -static struct udp_pcd upcd; - -const struct usb_device_descriptor dev_descriptor = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0200, - .bDeviceClass = USB_CLASS_VENDOR_SPEC, - .bDeviceSubClass = 0xff, - .bDeviceProtocol = 0xff, - .bMaxPacketSize0 = 0x08, - .idVendor = OPENPCD_VENDOR_ID, - .idProduct = OPENPCD_PRODUCT_ID, - .bcdDevice = 0x0000, - .iManufacturer = 0x00, - .iProduct = 0x00, - .iSerialNumber = 0x00, - .bNumConfigurations = 0x01, -}; - -struct _desc { - struct usb_config_descriptor ucfg; - struct usb_interface_descriptor uif; - struct usb_endpoint_descriptor ep[3]; -#ifdef CONFIG_DFU - struct usb_interface_descriptor uif_dfu; - struct usb_dfu_func_descriptor func_dfu; -#endif -}; - -const struct _desc cfg_descriptor = { - .ucfg = { - .bLength = USB_DT_CONFIG_SIZE, - .bDescriptorType = USB_DT_CONFIG, - .wTotalLength = USB_DT_CONFIG_SIZE + -#ifdef CONFIG_DFU - 2 * USB_DT_INTERFACE_SIZE + - 3 * USB_DT_ENDPOINT_SIZE + - USB_DT_DFU_SIZE, - .bNumInterfaces = 2, -#else - 1 * USB_DT_INTERFACE_SIZE + - 3 * USB_DT_ENDPOINT_SIZE, - .bNumInterfaces = 1, -#endif - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = USB_CONFIG_ATT_ONE, - .bMaxPower = 100, /* 200mA */ - }, - .uif = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = 3, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0xff, - .iInterface = 0, - }, - .ep= { - { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = OPENPCD_OUT_EP, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = AT91C_EP_OUT_SIZE, - .bInterval = 0x00, - }, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = OPENPCD_IN_EP, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = AT91C_EP_IN_SIZE, - .bInterval = 0x00, - }, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = OPENPCD_IRQ_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = AT91C_EP_IN_SIZE, - .bInterval = 0xff, /* FIXME */ - }, - }, -#ifdef CONFIG_DFU - .uif_dfu = DFU_RT_IF_DESC, - .func_dfu = DFU_FUNC_DESC, -#endif -}; - -static const struct usb_string_descriptor string0 = { - .bLength = sizeof(string0), - .bDescriptorType = USB_DT_STRING, - .wData[0] = 0x0409, /* English */ -}; - - -static void udp_ep0_handler(void); - -void udp_unthrottle(void) -{ - AT91PS_UDP pUDP = upcd.pUdp; - pUDP->UDP_IER = AT91C_UDP_EPINT1; -} - -int udp_refill_ep(int ep, struct req_ctx *rctx) -{ - u_int16_t i; - AT91PS_UDP pUDP = upcd.pUdp; - - 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 (atomic_read(&upcd.ep[ep].pkts_in_transit) == 2) - return -EBUSY; - - /* fill FIFO/DPR */ - for (i = 0; i < rctx->tx.tot_len; i++) - pUDP->UDP_FDR[ep] = rctx->tx.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; - } - - /* return rctx to pool of free contexts */ - req_ctx_put(rctx); - - return 0; -} - -#ifdef DEBUG_UDP_IRQ -#define DEBUGI(x, args ...) DEBUGP(x, ## args) -#else -#define DEBUGI(x, args ...) do { } while (0) -#endif - -static void udp_irq(void) -{ - u_int32_t csr; - AT91PS_UDP pUDP = upcd.pUdp; - AT91_REG isr = pUDP->UDP_ISR; - - DEBUGI("udp_irq(imr=0x%04x, isr=0x%04x): ", pUDP->UDP_IMR, isr); - - if (isr & AT91C_UDP_ENDBUSRES) { - DEBUGI("ENDBUSRES "); - pUDP->UDP_ICR = AT91C_UDP_ENDBUSRES; - pUDP->UDP_IER = AT91C_UDP_EPINT0; - /* reset all endpoints */ - pUDP->UDP_RSTEP = (unsigned int)-1; - pUDP->UDP_RSTEP = 0; - /* Enable the function */ - pUDP->UDP_FADDR = AT91C_UDP_FEN; - /* Configure endpoint 0 */ - pUDP->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); - upcd.cur_config = 0; - -#ifdef CONFIG_DFU - if (*dfu->dfu_state == DFU_STATE_appDETACH) { - /* now we need to switch to DFU mode */ - dfu->dfu_switch(); - } -#endif - } - - if (isr & AT91C_UDP_EPINT0) { - DEBUGI("EP0INT(Control) "); - udp_ep0_handler(); - } - if (isr & AT91C_UDP_EPINT1) { - u_int32_t cur_rcv_bank = upcd.cur_rcv_bank; - csr = pUDP->UDP_CSR[1]; - DEBUGI("EP1INT(Out, CSR=0x%08x) ", csr); - if (cur_rcv_bank == AT91C_UDP_RX_DATA_BK1) - DEBUGI("cur_bank=1 "); - else if (cur_rcv_bank == AT91C_UDP_RX_DATA_BK0) - DEBUGI("cur_bank=0 "); - else - DEBUGI("cur_bank INVALID "); - - if (csr & AT91C_UDP_RX_DATA_BK1) - DEBUGI("BANK1 "); - if (csr & AT91C_UDP_RX_DATA_BK0) - DEBUGI("BANK0 "); - - 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); - - if (rctx) { - rctx->rx.tot_len = pkt_size; - while (pkt_size--) - rctx->rx.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; - req_ctx_set_state(rctx, RCTX_STATE_UDP_RCV_DONE); - DEBUGI("RCTX=%u ", req_ctx_num(rctx)); - } else { - /* disable interrupts for now */ - pUDP->UDP_IDR = AT91C_UDP_EPINT1; - DEBUGP("NO_RCTX_AVAIL! "); - } - } - } - if (isr & AT91C_UDP_EPINT2) { - 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; - while (pUDP->UDP_CSR[2] & AT91C_UDP_TXCOMP) ; - - /* if we already have another packet in DPR, send it */ - 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 "); - } - } - 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 (isr & AT91C_UDP_RXSUSP) { - pUDP->UDP_ICR = AT91C_UDP_RXSUSP; - DEBUGI("RXSUSP "); - /* FIXME: implement suspend/resume */ - } - if (isr & AT91C_UDP_RXRSM) { - pUDP->UDP_ICR = AT91C_UDP_RXRSM; - DEBUGI("RXRSM "); - /* FIXME: implement suspend/resume */ - } - if (isr & AT91C_UDP_EXTRSM) { - pUDP->UDP_ICR = AT91C_UDP_EXTRSM; - DEBUGI("EXTRSM "); - /* FIXME: implement suspend/resume */ - } - if (isr & AT91C_UDP_SOFINT) { - pUDP->UDP_ICR = AT91C_UDP_SOFINT; - DEBUGI("SOFINT "); - } - if (isr & AT91C_UDP_WAKEUP) { - pUDP->UDP_ICR = AT91C_UDP_WAKEUP; - DEBUGI("WAKEUP "); - /* FIXME: implement suspend/resume */ - } - - DEBUGI("END\r\n"); - AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_UDP); -} - -/* Open USB Device Port */ -void udp_open(void) -{ - DEBUGPCRF("entering"); - upcd.pUdp = AT91C_BASE_UDP; - upcd.cur_config = 0; - upcd.cur_rcv_bank = AT91C_UDP_RX_DATA_BK0; - - AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_UDP, - OPENPCD_IRQ_PRIO_UDP, - AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, udp_irq); - AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_UDP); - - /* End-of-Bus-Reset is always enabled */ - - /* Clear for set the Pull up resistor */ - AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); -} - -void udp_reset(void) -{ - volatile int i; - - AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); - for (i = 0; i < 0xffff; i++) - ; - AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP); -} - -#ifdef DEBUG_UDP_EP0 -#define DEBUGE(x, args ...) DEBUGP(x, ## args) -#else -#define DEBUGE(x, args ...) do { } while (0) -#endif - -/* Handle requests on the USB Control Endpoint */ -static void udp_ep0_handler(void) -{ - AT91PS_UDP pUDP = upcd.pUdp; - u_int8_t bmRequestType, bRequest; - u_int16_t wValue, wIndex, wLength, wStatus; - u_int32_t csr = pUDP->UDP_CSR[0]; - - DEBUGE("CSR=0x%04x ", csr); - - if (csr & AT91C_UDP_STALLSENT) { - DEBUGE("ACK_STALLSENT "); - pUDP->UDP_CSR[0] = ~AT91C_UDP_STALLSENT; - } - - if (csr & AT91C_UDP_RX_DATA_BK0) { - DEBUGE("ACK_BANK0 "); - pUDP->UDP_CSR[0] &= ~AT91C_UDP_RX_DATA_BK0; - } - - if (!(csr & AT91C_UDP_RXSETUP)) { - DEBUGE("no setup packet "); - return; - } - - DEBUGE("len=%d ", csr >> 16); - if (csr >> 16 == 0) { - DEBUGE("empty packet "); - return; - } - - bmRequestType = pUDP->UDP_FDR[0]; - bRequest = pUDP->UDP_FDR[0]; - wValue = (pUDP->UDP_FDR[0] & 0xFF); - wValue |= (pUDP->UDP_FDR[0] << 8); - wIndex = (pUDP->UDP_FDR[0] & 0xFF); - wIndex |= (pUDP->UDP_FDR[0] << 8); - wLength = (pUDP->UDP_FDR[0] & 0xFF); - wLength |= (pUDP->UDP_FDR[0] << 8); - - DEBUGE("bmRequestType=0x%2x ", bmRequestType); - - if (bmRequestType & 0x80) { - DEBUGE("DATA_IN=1 "); - pUDP->UDP_CSR[0] |= AT91C_UDP_DIR; - while (!(pUDP->UDP_CSR[0] & AT91C_UDP_DIR)) ; - } - pUDP->UDP_CSR[0] &= ~AT91C_UDP_RXSETUP; - while ((pUDP->UDP_CSR[0] & AT91C_UDP_RXSETUP)) ; - - /* Handle supported standard device request Cf Table 9-3 in USB - * speciication Rev 1.1 */ - switch ((bRequest << 8) | bmRequestType) { - case STD_GET_DESCRIPTOR: - DEBUGE("GET_DESCRIPTOR "); - if (wValue == 0x100) { - /* Return Device Descriptor */ -#ifdef CONFIG_DFU - if (*dfu->dfu_state != DFU_STATE_appIDLE) - udp_ep0_send_data((const char *) - dfu->dfu_dev_descriptor, - MIN(dfu->dfu_dev_descriptor->bLength, - wLength)); - else -#endif - udp_ep0_send_data((const char *) &dev_descriptor, - MIN(sizeof(dev_descriptor), wLength)); - } else if (wValue == 0x200) { - /* Return Configuration Descriptor */ -#ifdef CONFIG_DFU - if (*dfu->dfu_state != DFU_STATE_appIDLE) - udp_ep0_send_data((const char *) - dfu->dfu_cfg_descriptor, - MIN(dfu->dfu_cfg_descriptor->ucfg.wTotalLength, - wLength)); - else -#endif - udp_ep0_send_data((const char *) &cfg_descriptor, - MIN(sizeof(cfg_descriptor), wLength)); - } else if (wValue == 0x300) { - /* Return String descriptor */ - switch (wIndex) { - case 0: - udp_ep0_send_data((const char *) &string0, - MIN(sizeof(string0), wLength)); - break; - default: - /* FIXME: implement this */ - udp_ep0_send_stall(); - break; - } -#if 0 - } else if (wValue == 0x400) { - /* Return Interface descriptor */ - if (wIndex != 0x01) - udp_ep0_send_stall(); - udp_ep0_send_data((const char *) - &dfu_if_descriptor, - MIN(sizeof(dfu_if_descriptor), - wLength)); -#endif - } else - udp_ep0_send_stall(); - break; - case STD_SET_ADDRESS: - DEBUGE("SET_ADDRESS "); - udp_ep0_send_zlp(); - pUDP->UDP_FADDR = (AT91C_UDP_FEN | wValue); - pUDP->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0; - break; - case STD_SET_CONFIGURATION: - DEBUGE("SET_CONFIG "); - if (wValue) - DEBUGE("VALUE!=0 "); - upcd.cur_config = wValue; - udp_ep0_send_zlp(); - pUDP->UDP_GLBSTATE = - (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN; - pUDP->UDP_CSR[1] = - (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : - 0; - pUDP->UDP_CSR[2] = - (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0; - pUDP->UDP_CSR[3] = - (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0; - pUDP->UDP_IER = (AT91C_UDP_EPINT0|AT91C_UDP_EPINT1| - AT91C_UDP_EPINT2|AT91C_UDP_EPINT3); - break; - case STD_GET_CONFIGURATION: - DEBUGE("GET_CONFIG "); - udp_ep0_send_data((char *)&(upcd.cur_config), - sizeof(upcd.cur_config)); - break; - case STD_GET_STATUS_ZERO: - DEBUGE("GET_STATUS_ZERO "); - wStatus = 0; - udp_ep0_send_data((char *)&wStatus, sizeof(wStatus)); - break; - case STD_GET_STATUS_INTERFACE: - DEBUGE("GET_STATUS_INTERFACE "); - wStatus = 0; - udp_ep0_send_data((char *)&wStatus, sizeof(wStatus)); - break; - case STD_GET_STATUS_ENDPOINT: - DEBUGE("GET_STATUS_ENDPOINT(EPidx=%u) ", wIndex&0x0f); - wStatus = 0; - wIndex &= 0x0F; - if ((pUDP->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= 3)) { - wStatus = - (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; - udp_ep0_send_data((char *)&wStatus, - sizeof(wStatus)); - } else if ((pUDP->UDP_GLBSTATE & AT91C_UDP_FADDEN) - && (wIndex == 0)) { - wStatus = - (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; - udp_ep0_send_data((char *)&wStatus, - sizeof(wStatus)); - } else - udp_ep0_send_stall(); - break; - case STD_SET_FEATURE_ZERO: - DEBUGE("SET_FEATURE_ZERO "); - udp_ep0_send_stall(); - break; - case STD_SET_FEATURE_INTERFACE: - DEBUGE("SET_FEATURE_INTERFACE "); - udp_ep0_send_zlp(); - break; - case STD_SET_FEATURE_ENDPOINT: - DEBUGE("SET_FEATURE_ENDPOINT "); - udp_ep0_send_zlp(); - wIndex &= 0x0F; - if ((wValue == 0) && wIndex && (wIndex <= 3)) { - pUDP->UDP_CSR[wIndex] = 0; - udp_ep0_send_zlp(); - } else - udp_ep0_send_stall(); - break; - case STD_CLEAR_FEATURE_ZERO: - DEBUGE("CLEAR_FEATURE_ZERO "); - udp_ep0_send_stall(); - break; - case STD_CLEAR_FEATURE_INTERFACE: - DEBUGP("CLEAR_FEATURE_INTERFACE "); - udp_ep0_send_zlp(); - break; - case STD_CLEAR_FEATURE_ENDPOINT: - DEBUGE("CLEAR_FEATURE_ENDPOINT(EPidx=%u) ", wIndex & 0x0f); - wIndex &= 0x0F; - if ((wValue == 0) && wIndex && (wIndex <= 3)) { - struct req_ctx *rctx; - if (wIndex == 1) { - pUDP->UDP_CSR[1] = - (AT91C_UDP_EPEDS | - AT91C_UDP_EPTYPE_BULK_OUT); - pUDP->UDP_RSTEP |= AT91C_UDP_EP1; - pUDP->UDP_RSTEP &= ~AT91C_UDP_EP1; - } - else if (wIndex == 2) { - pUDP->UDP_CSR[2] = - (AT91C_UDP_EPEDS | - AT91C_UDP_EPTYPE_BULK_IN); - pUDP->UDP_RSTEP |= AT91C_UDP_EP2; - pUDP->UDP_RSTEP &= ~AT91C_UDP_EP2; - - /* free all currently transmitting contexts */ - while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP2_BUSY, - RCTX_STATE_FREE)) {} - atomic_set(&upcd.ep[wIndex].pkts_in_transit, 0); - } - else if (wIndex == 3) { - pUDP->UDP_CSR[3] = - (AT91C_UDP_EPEDS | - AT91C_UDP_EPTYPE_INT_IN); - pUDP->UDP_RSTEP |= AT91C_UDP_EP3; - pUDP->UDP_RSTEP &= ~AT91C_UDP_EP3; - - /* free all currently transmitting contexts */ - while (rctx = req_ctx_find_get(RCTX_STATE_UDP_EP3_BUSY, - RCTX_STATE_FREE)) {} - atomic_set(&upcd.ep[wIndex].pkts_in_transit, 0); - } - udp_ep0_send_zlp(); - } else - udp_ep0_send_stall(); - break; - case STD_SET_INTERFACE: - DEBUGE("SET INTERFACE "); - udp_ep0_send_stall(); - break; -#ifdef CONFIG_DFU - case USB_TYPE_DFU<<8|USB_REQ_DFU_DETACH: - DEBUGE("DFU_DETACH "); - /* if USB reset occurs within wValue milliseconds, switch to DFU */ - break; -#endif - default: - DEBUGE("DEFAULT(req=0x%02x, type=0x%02x) ", bRequest, bmRequestType); -#ifdef CONFIG_DFU - if ((bmRequestType & 0x3f) == USB_TYPE_DFU) { - dfu->dfu_ep0_handler(bmRequestType, bRequest, wValue, wLength); - } else -#endif - udp_ep0_send_stall(); - break; - } -} - diff --git a/openpcd/firmware/src/pcd_enumerate.h b/openpcd/firmware/src/pcd_enumerate.h deleted file mode 100644 index 57ff88c..0000000 --- a/openpcd/firmware/src/pcd_enumerate.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _OPCD_USB_H -#define _OPCD_USB_H - -#include -#include -#include -#include "openpcd.h" -#include "dfu.h" - -struct req_ctx; - -extern void udp_open(void); -extern int udp_refill_ep(int ep, struct req_ctx *rctx); -extern void udp_unthrottle(void); -extern void udp_reset(void); - -struct ep_ctx { - atomic_t pkts_in_transit; - void *ctx; -}; - -struct udp_pcd { - AT91PS_UDP pUdp; - unsigned char cur_config; - unsigned int cur_rcv_bank; - struct ep_ctx ep[4]; -}; - -/* USB standard request code */ - -#define STD_GET_STATUS_ZERO 0x0080 -#define STD_GET_STATUS_INTERFACE 0x0081 -#define STD_GET_STATUS_ENDPOINT 0x0082 - -#define STD_CLEAR_FEATURE_ZERO 0x0100 -#define STD_CLEAR_FEATURE_INTERFACE 0x0101 -#define STD_CLEAR_FEATURE_ENDPOINT 0x0102 - -#define STD_SET_FEATURE_ZERO 0x0300 -#define STD_SET_FEATURE_INTERFACE 0x0301 -#define STD_SET_FEATURE_ENDPOINT 0x0302 - -#define STD_SET_ADDRESS 0x0500 -#define STD_GET_DESCRIPTOR 0x0680 -#define STD_SET_DESCRIPTOR 0x0700 -#define STD_GET_CONFIGURATION 0x0880 -#define STD_SET_CONFIGURATION 0x0900 -#define STD_GET_INTERFACE 0x0A81 -#define STD_SET_INTERFACE 0x0B01 -#define STD_SYNCH_FRAME 0x0C82 - -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) - - -#endif - diff --git a/openpcd/firmware/src/picc/load_modulation.c b/openpcd/firmware/src/picc/load_modulation.c new file mode 100644 index 0000000..d2af070 --- /dev/null +++ b/openpcd/firmware/src/picc/load_modulation.c @@ -0,0 +1,31 @@ + +#ifdef CONFIG_PICCSIM + +#include +#include + +#include "../openpcd.h" + +void load_mod_level(u_int8_t level) +{ + if (level > 3) + level = 3; + + if (level & 0x1) + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LOAD1); + else + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LOAD1); + + if (level & 0x2) + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LOAD2); + else + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LOAD2); +} + +void load_mod_init(void) +{ + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LOAD1); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LOAD2); +} + +#endif /* CONFIG_PICCSIM */ diff --git a/openpcd/firmware/src/picc/load_modulation.h b/openpcd/firmware/src/picc/load_modulation.h new file mode 100644 index 0000000..71f9d6f --- /dev/null +++ b/openpcd/firmware/src/picc/load_modulation.h @@ -0,0 +1,7 @@ +#ifndef _LOAD_MODULATION_H +#define _LOAD_MODULATION_H + +extern void load_mod_level(u_int8_t level); +extern void load_mod_init(void); + +#endif diff --git a/openpcd/firmware/src/picc/piccsim.h b/openpcd/firmware/src/picc/piccsim.h index 34c7bf0..3cf6514 100644 --- a/openpcd/firmware/src/picc/piccsim.h +++ b/openpcd/firmware/src/picc/piccsim.h @@ -1,5 +1,5 @@ -#include +#include struct piccsim_state { enum rfid_layer2_id l2prot; diff --git a/openpcd/firmware/src/picc/tc.c b/openpcd/firmware/src/picc/tc.c new file mode 100644 index 0000000..d23afa2 --- /dev/null +++ b/openpcd/firmware/src/picc/tc.c @@ -0,0 +1,123 @@ +/* OpenPC TC (Timer / Clock) support code + * (C) 2006 by Harald Welte + * + * This idea of this code is to feed the 13.56MHz carrier clock of RC632 + * into TCLK1, which is routed to XC1. Then configure TC0 to divide this + * clock by a configurable divider. + * + * PICC Simulator Side: + * In order to support responding to synchronous frames (REQA/WUPA/ANTICOL), + * we need a second Timer/Counter (TC1). This unit is reset by an external + * event (rising edge of modulation pause PCD->PICC) connected to TIOB2, and + * counts up to a configurable number of carrier clock cycles (RA). Once the + * RA value is reached, TIOA2 will see a rising edge. This rising edge will + * be interconnected to TF (Tx Frame) of the SSC to start transmitting our + * synchronous response. + * + */ + +#include +#include + +#include "../openpcd.h" +#include "tc.h" + +static AT91PS_TCB tcb = AT91C_BASE_TCB; + +/* set carrier divider to a specific */ +void tc_cdiv_set_divider(u_int16_t div) +{ + tcb->TCB_TC0.TC_RC = div; + + /* set to 50% duty cycle */ + tcb->TCB_TC0.TC_RA = 1; + tcb->TCB_TC0.TC_RB = 1 + (div >> 1); +} + +void tc_cdiv_phase_add(int16_t inc) +{ + tcb->TCB_TC0.TC_RA = (tcb->TCB_TC0.TC_RA + inc) % tcb->TCB_TC0.TC_RC; + tcb->TCB_TC0.TC_RB = (tcb->TCB_TC0.TC_RB + inc) % tcb->TCB_TC0.TC_RC; + + /* FIXME: can this be done more elegantly? */ + if (tcb->TCB_TC0.TC_RA == 0) { + tcb->TCB_TC0.TC_RA += 1; + tcb->TCB_TC0.TC_RB += 1; + } +} + +#ifdef CONFIG_PICCSIM +void tc_fdt_set(u_int16_t count) +{ + tcb->TC_TC2.TC_RA = count; +} +#endif + +void tc_cdiv_init(void) +{ + /* Cfg PA28(TCLK1), PA0(TIOA0), PA1(TIOB0), PA20(TCLK2) as Periph B */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, + OPENPCD_PIO_CARRIER_IN | + OPENPCD_PIO_CARRIER_DIV_OUT | + OPENPCD_PIO_CDIV_HELP_OUT | + OPENPCD_PIO_CDIV_HELP_IN); + + AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, + ((unsigned int) 1 << AT91C_ID_TC0)); + + /* Enable Clock for TC0 */ + tcb->TCB_TC0.TC_CCR = AT91C_TC_CLKEN; + + /* Connect TCLK1 to XC1, TCLK2 to XC2 */ + tcb->TCB_BMR &= ~(AT91C_TCB_TC1XC1S | AT91C_TCB_TC2XC2S); + tcb->TCB_BMR |= (AT91C_TCB_TC1XC1S_TCLK1 | AT91C_TCB_TC2XC2S_TCLK2); + + /* Clock XC1, Wave mode, Reset on RC comp + * TIOA0 on RA comp = set, * TIOA0 on RC comp = clear, + * TIOB0 on EEVT = set, TIOB0 on RB comp = clear, + * EEVT = XC2 (TIOA0) */ + tcb->TCB_TC0.TC_CMR = AT91C_TC_CLKS_XC1 | AT91C_TC_WAVE | + AT91C_TC_WAVESEL_UP_AUTO | + AT91C_TC_ACPA_SET | AT91C_TC_ACPC_CLEAR | + AT91C_TC_BEEVT_SET | AT91C_TC_BCPB_CLEAR | + AT91C_TC_EEVT_XC2 | AT91C_TC_ETRGEDG_RISING; + + tc_cdiv_set_divider(128); + +#ifdef CONFIG_PICCSIM + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, AT91C_PA15_TF, + AT91C_PA26_TIOA2, AT91C_PA17_TIOB2); + AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, + ((unsigned int) 1 << AT91C_ID_TC2)); + /* Clock XC1, Wave Mode, No automatic reset on RC comp + * TIOA2 in RA comp = set, TIOA2 on RC comp = clear, + * TIOB2 as input, EEVT = TIOB2, Reset/Trigger on EEVT */ + tcb->TCB_TC2.TC_CMR = AT91C_TC_CLKS_XC1 | AT91C_TC_WAVE | + AT91C_TC_WAVESEL_UP | + AT91C_TC_ACPA_SET | AT91C_ACPC_CLEAR | + AT91C_TC_BEEVT_NONE | AT91C_TC_BCPB_NONE | + AT91C_TC_EEVT_TIOB | AT91C_TC_ETRGEDG_RISING | + AT91C_TC_ENETRG ; +#endif + + /* Reset to start timers */ + tcb->TCB_BCR = 1; +} + +void tc_cdiv_print(void) +{ + DEBUGP("TCB_BMR=0x%08x ", tcb->TCB_BMR); + DEBUGP("TC0_CV=0x%08x ", tcb->TCB_TC0.TC_CV); + DEBUGP("TC0_CMR=0x%08x ", tcb->TCB_TC0.TC_CMR); + DEBUGPCR("TC0_SR=0x%08x", tcb->TCB_TC0.TC_SR); + + DEBUGPCR("TC0_RA=0x%04x, TC0_RB=0x%04x, TC0_RC=0x%04x", + tcb->TCB_TC0.TC_RA, tcb->TCB_TC0.TC_RB, tcb->TCB_TC0.TC_RC); +} + +void tc_cdiv_fini(void) +{ + tcb->TCB_TC0.TC_CCR = AT91C_TC_CLKDIS; + AT91F_PMC_DisablePeriphClock(AT91C_BASE_PMC, + ((unsigned int) 1 << AT91C_ID_TC0)); +} diff --git a/openpcd/firmware/src/picc/tc.h b/openpcd/firmware/src/picc/tc.h new file mode 100644 index 0000000..e7aa7e4 --- /dev/null +++ b/openpcd/firmware/src/picc/tc.h @@ -0,0 +1,28 @@ +#ifndef _TC_H +#define _TC_H + +#include + +extern void tc_cdiv_phase_add(int16_t inc); +extern void tc_cdiv_set_divider(u_int16_t div); + +static inline void tc_cdiv_phase_inc(void) +{ + tc_cdiv_phase_add(1); +} + +static inline void tc_cdiv_phase_dec(void) +{ + tc_cdiv_phase_add(-1); +} + + +extern void tc_cdiv_print(void); +extern void tc_cdiv_init(void); +extern void tc_cdiv_fini(void); + +#ifdef CONFIG_PICCSIM +extern void tc_fdt_set(u_int16_t count); +#endif + +#endif diff --git a/openpcd/firmware/src/pio_irq.c b/openpcd/firmware/src/pio_irq.c deleted file mode 100644 index 3e65561..0000000 --- a/openpcd/firmware/src/pio_irq.c +++ /dev/null @@ -1,66 +0,0 @@ - -#include -#define NR_PIO 32 - -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; -} - -static void pio_irq_demux(void) -{ - u_int32_t pio = AT91F_PIO_GetInterruptStatus(AT91C_BASE_PIOA); - - for (i = 0; i < NR_PIO; i++) { - if (pio & (1 << i) && pio_handlers[i]) - pio_handlers[i](i); - } - return; -} - -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, void (*handler)(void)) -{ - u_int8_t num = ffs(pio); - - if (num == 0) - return -EINVAL; - num--; - - if (pio_handlers[num]) - return -EBUSY; - - pio_irq_disable(pio); - AT91F_PIO_CfgInput(AT91C_BASE_PIOA, pio); - pio_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); - pio_handlers[num] = NULL; -} diff --git a/openpcd/firmware/src/pio_irq.h b/openpcd/firmware/src/pio_irq.h deleted file mode 100644 index 86021df..0000000 --- a/openpcd/firmware/src/pio_irq.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _PIO_IRQ_H -#define _PIO_IRQ_H - -#include - -typedef irq_handler_t (void)(u_int32_t pio); - -static irq_handler_t pio_handlers[NR_PIO]; - -extern void pio_irq_enable(u_int32_t pio); -extern void pio_irq_disable(u_int32_t pio); -extern int pio_irq_register(u_int32_t pio, irq_handler_t func); -extern void pio_irq_unregister(u_int32_t pio); - -#endif diff --git a/openpcd/firmware/src/pwm.c b/openpcd/firmware/src/pwm.c deleted file mode 100644 index 8247921..0000000 --- a/openpcd/firmware/src/pwm.c +++ /dev/null @@ -1,164 +0,0 @@ -/* AT91SAM7 PWM routines for OpenPCD / OpenPICC - * - * (C) 2006 by Harald Welte - * - */ - -#include -#include -#include -#include -#include -#include "usb_handler.h" -#include "pcd_enumerate.h" -#include "dbgu.h" -#include "openpcd.h" - -#define Hz -#define kHz *1000 Hz -#define MHz *1000 kHz -#define MCLK (48 MHz) - -#if 1 -#define DEBUGPWM DEBUGPCRF -#else -#define DEBUGPWM(x, args...) -#endif - -static AT91PS_PWMC pwm = AT91C_BASE_PWMC; - -/* find highest bit set. returns bit (32..1) or 0 in case no bit set */ -static int fhs(u_int32_t val) -{ - int i; - - for (i = 32; i > 0; i--) { - if (val & (1 << (i-1))) - return i; - } - - return 0; -} - -/* set frequency of PWM signal to freq */ -int pwm_freq_set(int channel, u_int32_t freq) -{ - /* in order to get maximum resolution, the pre-scaler must be set to - * something like freq << 16. However, the mimimum pre-scaled frequency - * we can get is MCLK (48MHz), the minimum is MCLK/(1024*255) = - * 48MHz/261120 = 183Hz */ - u_int32_t overall_div; - u_int32_t presc_total; - u_int8_t cpre = 0; - u_int16_t cprd; - - if (freq > MCLK) - return -ERANGE; - - overall_div = MCLK / freq; - DEBUGPCRF("mclk=%u, freq=%u, overall_div=%u", MCLK, freq, overall_div); - - if (overall_div > 0x7fff) { - /* divisor is larger than half the maximum CPRD register, we - * have to configure prescalers */ - presc_total = overall_div >> 15; - - /* find highest 2^n fitting in prescaler (highest bit set) */ - cpre = fhs(presc_total); - if (cpre > 0) { - /* subtract one, because of fhs semantics */ - cpre--; - } - cprd = overall_div / (1 << cpre); - } else - cprd = overall_div; - - DEBUGPCRF("cpre=%u, cprd=%u", cpre, cprd); - AT91F_PWMC_CfgChannel(AT91C_BASE_PWMC, channel, - cpre|AT91C_PWMC_CPOL, cprd, 1); - - return 0; -} - -void pwm_start(int channel) -{ - AT91F_PWMC_StartChannel(AT91C_BASE_PWMC, (1 << channel)); -} - -void pwm_stop(int channel) -{ - AT91F_PWMC_StopChannel(AT91C_BASE_PWMC, (1 << channel)); -} - -void pwm_duty_set_percent(int channel, u_int16_t duty) -{ - u_int32_t tmp = pwm->PWMC_CH[channel].PWMC_CPRDR & 0xffff; - - tmp = tmp << 16; /* extend value by 2^16 */ - tmp = tmp / 100; /* tmp = 1 % of extended cprd */ - tmp = duty * tmp; /* tmp = 'duty' % of extended cprd */ - tmp = tmp >> 16; /* un-extend tmp (divide by 2^16) */ - - DEBUGPWM("Writing %u to Update register\n", tmp); - AT91F_PWMC_UpdateChannel(AT91C_BASE_PWMC, channel, tmp); -} - -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]; - u_int32_t *freq; - - switch (poh->cmd) { - case OPENPCD_CMD_PWM_ENABLE: - if (poh->val) - pwm_start(0); - else - pwm_stop(0); - break; - case OPENPCD_CMD_PWM_DUTY_SET: - pwm_duty_set_percent(0, poh->val); - break; - case OPENPCD_CMD_PWM_DUTY_GET: - goto respond; - break; - case OPENPCD_CMD_PWM_FREQ_SET: - if (rctx->rx.tot_len < sizeof(*poh)+4) - break; - freq = (void *) poh + sizeof(*poh); - pwm_freq_set(0, *freq); - break; - case OPENPCD_CMD_PWM_FREQ_GET: - goto respond; - break; - default: - break; - } - - req_ctx_put(rctx); - return 0; -respond: - req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); - udp_refill_ep(2, rctx); - return 1; -} - -void pwm_init(void) -{ - /* IMPORTANT: Disable PA17 (SSC TD) output */ - AT91F_PIO_CfgInput(AT91C_BASE_PIOA, AT91C_PIO_PA17); - - /* Set PA23 to Peripheral A (PWM0) */ - AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, OPENPCD_PIO_MFIN_PWM); - - /* Enable Clock for PWM controller */ - AT91F_PWMC_CfgPMC(); - - usb_hdlr_register(&pwm_usb_in, OPENPCD_CMD_CLS_PWM); -} - -void pwm_fini(void) -{ - usb_hdlr_unregister(OPENPCD_CMD_CLS_PWM); - AT91F_PMC_DisablePeriphClock(AT91C_BASE_PMC, (1 << AT91C_ID_PWMC)); -} diff --git a/openpcd/firmware/src/pwm.h b/openpcd/firmware/src/pwm.h deleted file mode 100644 index 8836c32..0000000 --- a/openpcd/firmware/src/pwm.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _PWM_H -#define _PWM_H - -extern void pwm_freq_set(int channel, u_int32_t freq); -extern void pwm_start(int channel); -extern void pwm_stop(int channel); -extern void pwm_duty_set_percent(int channel, u_int16_t duty); -extern void pwm_init(void); -extern void pwm_fini(void); - -#endif diff --git a/openpcd/firmware/src/rc632.c b/openpcd/firmware/src/rc632.c deleted file mode 100644 index 54ff58d..0000000 --- a/openpcd/firmware/src/rc632.c +++ /dev/null @@ -1,623 +0,0 @@ -/* Philips CL RC632 driver (via SPI) for OpenPCD firmware - * (C) 2006 by Harald Welte - * - * This is heavily based on the librfid RC632 driver. All primitive access - * functions such as rc632_{reg,fifo}_{read,write}() are API compatible to - * librfid in order to be able to leverage higher-level code from librfid - * to this OpenPCD firmware. - * - * */ - -#include -#include -#include -#include -#include -#include "openpcd.h" -#include "fifo.h" -#include "dbgu.h" -#include "pcd_enumerate.h" -#include "usb_handler.h" -#include "rc632.h" - -#define ALWAYS_RESPOND - -#define NOTHING do {} while(0) - -#if 0 -#define DEBUGPSPI DEBUGP -#define DEBUGPSPIIRQ DEBUGP -#else -#define DEBUGPSPI(x, args ...) NOTHING -#define DEBUGPSPIIRQ(x, args...) NOTHING -#endif - -#if 0 -#define DEBUG632 DEBUGPCRF -#else -#define DEBUG632(x, args ...) NOTHING -#endif - - -/* SPI driver */ - -#ifdef OLIMEX -#define SPI_DEBUG_LOOPBACK -#endif - -#define SPI_USES_DMA - -#define SPI_MAX_XFER_LEN 65 - -static AT91PS_SPI pSPI = AT91C_BASE_SPI; - -/* SPI irq handler */ -static void spi_irq(void) -{ - u_int32_t status = pSPI->SPI_SR; - - DEBUGPSPIIRQ("spi_irq: 0x%08x ", status); - - if (status & AT91C_SPI_OVRES) - DEBUGPSPIIRQ("Overrun "); - if (status & AT91C_SPI_MODF) - DEBUGPSPIIRQ("ModeFault "); - if (status & AT91C_SPI_ENDRX) { - pSPI->SPI_IDR = AT91C_SPI_ENDRX; - DEBUGPSPIIRQ("ENDRX "); - } - if (status & AT91C_SPI_ENDTX) { - pSPI->SPI_IDR = AT91C_SPI_ENDTX; - DEBUGPSPIIRQ("ENDTX "); - } - - DEBUGPSPIIRQ("\r\n"); - - AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_SPI); -} - -#ifdef SPI_USES_DMA -static int spi_transceive(const u_int8_t *tx_data, u_int16_t tx_len, - u_int8_t *rx_data, u_int16_t *rx_len) -{ - //tx_len = *rx_len = 65; - DEBUGPSPI("DMA Xfer tx=%s\r\n", hexdump(tx_data, tx_len)); - if (*rx_len < tx_len) { - DEBUGPCRF("rx_len=%u smaller tx_len=%u\n", *rx_len, tx_len); - return -1; - } - //AT91F_SPI_Disable(pSPI); - - AT91F_SPI_ReceiveFrame(pSPI, rx_data, tx_len, NULL, 0); - AT91F_SPI_SendFrame(pSPI, tx_data, tx_len, NULL, 0); - - AT91F_PDC_EnableRx(AT91C_BASE_PDC_SPI); - AT91F_PDC_EnableTx(AT91C_BASE_PDC_SPI); - - pSPI->SPI_IER = AT91C_SPI_ENDTX|AT91C_SPI_ENDRX; - //pSPI->SPI_IDR = AT91C_SPI_ENDTX|AT91C_SPI_ENDRX; - - - while (! (pSPI->SPI_SR & AT91C_SPI_ENDRX)) ; - - DEBUGPSPI("DMA Xfer finished rx=%s\r\n", hexdump(rx_data, tx_len)); - - *rx_len = tx_len; - - return 0; -} -#else -/* stupid polling transceiver routine */ -static int spi_transceive(const u_int8_t *tx_data, u_int16_t tx_len, - u_int8_t *rx_data, u_int16_t *rx_len) -{ - u_int16_t tx_cur = 0; - u_int16_t rx_len_max = 0; - u_int16_t rx_cnt = 0; - - /* disable RC632 interrupt because it wants to do SPI transactions */ - AT91F_AIC_DisableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); - - DEBUGPSPI("spi_transceive: enter(tx_len=%u) ", tx_len); - - if (rx_len) { - rx_len_max = *rx_len; - *rx_len = 0; - } - - //AT91F_SPI_Enable(pSPI); - while (1) { - u_int32_t sr = pSPI->SPI_SR; - u_int8_t tmp; - if (sr & AT91C_SPI_RDRF) { - tmp = pSPI->SPI_RDR; - rx_cnt++; - if (rx_len && *rx_len < rx_len_max) - rx_data[(*rx_len)++] = tmp; - } - if (sr & AT91C_SPI_TDRE) { - if (tx_len > tx_cur) - pSPI->SPI_TDR = tx_data[tx_cur++]; - } - if (tx_cur >= tx_len && rx_cnt >= tx_len) - break; - } - //AT91F_SPI_Disable(pSPI); - if (rx_data) - DEBUGPSPI("leave(%02x %02x)\r\n", rx_data[0], rx_data[1]); - else - DEBUGPSPI("leave()\r\n"); - - /* Re-enable RC632 interrupts */ - AT91F_AIC_EnableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); - - return 0; -} -#endif - -/* RC632 driver */ - -/* static buffers used by RC632 access primitives below. - * Since we only have one */ - -static u_int8_t spi_outbuf[SPI_MAX_XFER_LEN]; -static u_int8_t spi_inbuf[SPI_MAX_XFER_LEN]; - -#define FIFO_ADDR (RC632_REG_FIFO_DATA << 1) - -struct rc632 { - u_int16_t flags; - struct fifo fifo; -}; -#define RC632_F_FIFO_TX 0x0001 -static struct rc632 rc632; - -/* RC632 access primitives */ - -int rc632_reg_write(struct rfid_asic_handle *hdl, - u_int8_t addr, u_int8_t data) -{ - u_int16_t rx_len = 2; - - DEBUG632("[0x%02x] <= 0x%02x", addr, data); - - addr = (addr << 1) & 0x7e; - - spi_outbuf[0] = addr; - spi_outbuf[1] = data; - - //spi_transceive(spi_outbuf, 2, NULL, NULL); - return spi_transceive(spi_outbuf, 2, spi_inbuf, &rx_len); -} - -int rc632_fifo_write(struct rfid_asic_handle *hdl, - u_int8_t len, u_int8_t *data, u_int8_t flags) -{ - if (len > sizeof(spi_outbuf)-1) - len = sizeof(spi_outbuf)-1; - - spi_outbuf[0] = FIFO_ADDR; - memcpy(&spi_outbuf[1], data, len); - - DEBUG632("[FIFO] <= %s", hexdump(data, len)); - - return spi_transceive(spi_outbuf, len+1, NULL, NULL); -} - -int rc632_reg_read(struct rfid_asic_handle *hdl, - u_int8_t addr, u_int8_t *val) -{ - u_int16_t rx_len = 2; - - addr = (addr << 1) & 0x7e; - - spi_outbuf[0] = addr | 0x80; - spi_outbuf[1] = 0x00; - - spi_transceive(spi_outbuf, 2, spi_inbuf, &rx_len); - *val = spi_inbuf[1]; - - DEBUG632("[0x%02x] => 0x%02x", addr>>1, *val); - - return 0; -} - -int rc632_fifo_read(struct rfid_asic_handle *hdl, - u_int8_t max_len, u_int8_t *data) -{ - int ret; - u_int8_t fifo_length; - u_int8_t i; - u_int16_t rx_len; - - ret = rc632_reg_read(hdl, RC632_REG_FIFO_LENGTH, &fifo_length); - if (ret < 0) - return ret; - - rx_len = fifo_length+1; - - if (max_len < fifo_length) - fifo_length = max_len; - - for (i = 0; i < fifo_length; i++) - spi_outbuf[i] = FIFO_ADDR; - - spi_outbuf[0] |= 0x80; - spi_outbuf[fifo_length] = 0x00; - - spi_transceive(spi_outbuf, fifo_length+1, spi_inbuf, &rx_len); - memcpy(data, spi_inbuf+1, rx_len-1); - - DEBUG632("[FIFO] => %s", hexdump(data, rx_len-1)); - - return 0; -} - -int rc632_set_bits(struct rfid_asic_handle *hdl, - u_int8_t reg, u_int8_t bits) -{ - u_int8_t val; - int ret; - - ret = rc632_reg_read(hdl, reg, &val); - if (ret < 0) - return ret; - - val |= bits; - - return rc632_reg_write(hdl, reg, val); -} - -int rc632_clear_bits(struct rfid_asic_handle *hdl, - u_int8_t reg, u_int8_t bits) -{ - u_int8_t val; - int ret; - - ret = rc632_reg_read(hdl, reg, &val); - if (ret < 0) - return ret; - - val &= ~bits; - - return rc632_reg_write(hdl, reg, val); -} - -/* RC632 interrupt handling */ - -static void rc632_irq(void) -{ - struct req_ctx *irq_rctx; - struct openpcd_hdr *irq_opcdh; - u_int8_t cause; - - /* CL RC632 has interrupted us */ - rc632_reg_read(RAH, RC632_REG_INTERRUPT_RQ, &cause); - - /* ACK all interrupts */ - //rc632_reg_write(RAH, RC632_REG_INTERRUPT_RQ, cause); - rc632_reg_write(RAH, RC632_REG_INTERRUPT_RQ, RC632_INT_TIMER); - DEBUGP("rc632_irq: "); - - if (cause & RC632_INT_LOALERT) { - /* FIFO is getting low, refill from virtual FIFO */ - DEBUGP("FIFO_low "); - #if 0 - if (!fifo_available(&rc632.fifo)) - return; - #endif - /* FIXME */ - } - if (cause & RC632_INT_HIALERT) { - /* FIFO is getting full, empty into virtual FIFO */ - DEBUGP("FIFO_high "); - /* FIXME */ - } - /* All interrupts below can be reported directly to the host */ - if (cause & RC632_INT_TIMER) - DEBUGP("Timer "); - if (cause & RC632_INT_IDLE) - DEBUGP("Idle "); - if (cause & RC632_INT_RX) - DEBUGP("RxComplete "); - if (cause & RC632_INT_TX) - DEBUGP("TxComplete "); - - - irq_rctx = req_ctx_find_get(RCTX_STATE_FREE, - RCTX_STATE_RC632IRQ_BUSY); - if (!irq_rctx) { - DEBUGPCRF("NO RCTX!\n"); - /* disable rc632 interrupt until RCTX is free */ - AT91F_AIC_DisableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); - return; - } - - irq_opcdh = (struct openpcd_hdr *) &irq_rctx->tx.data[0]; - - /* initialize static part of openpcd_hdr for USB IRQ reporting */ - irq_opcdh->cmd = OPENPCD_CMD_IRQ; - irq_opcdh->flags = 0x00; - irq_opcdh->reg = 0x07; - irq_opcdh->val = cause; - - req_ctx_set_state(irq_rctx, RCTX_STATE_UDP_EP3_PENDING); - DEBUGPCR(""); -} - -void rc632_unthrottle(void) -{ - AT91F_AIC_EnableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); -} - -void rc632_power(u_int8_t up) -{ - DEBUGPCRF("powering %s RC632", up ? "up" : "down"); - if (up) - AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, - OPENPCD_PIO_RC632_RESET); - else - AT91F_PIO_SetOutput(AT91C_BASE_PIOA, - OPENPCD_PIO_RC632_RESET); -} - -void rc632_reset(void) -{ - volatile int i; - - rc632_power(0); - for (i = 0; i < 0xffff; i++) - {} - rc632_power(1); - - /* wait for startup phase to finish */ - while (1) { - u_int8_t val; - rc632_reg_read(RAH, RC632_REG_COMMAND, &val); - if (val == 0x00) - break; - } - - /* turn off register paging */ - rc632_reg_write(RAH, RC632_REG_PAGE0, 0x00); -} - -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); - - 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; - break; - case OPENPCD_CMD_READ_FIFO: - { - u_int16_t req_len = poh->val, remain_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; - DEBUGP("READ FIFO(len=%u)=%s ", req_len, - hexdump(pih->data, pih_len)); - req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); - udp_refill_ep(2, rctx); - - /* get and initialize second rctx */ - rctx = req_ctx_find_get(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); - - pih_len = remain_len; - rc632_fifo_read(RAH, pih->val, pih->data); - rctx->tx.tot_len += pih_len; - DEBUGP("READ FIFO(len=%u)=%s ", pih_len, - hexdump(pih->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; - DEBUGP("READ FIFO(len=%u)=%s ", poh->val, - hexdump(pih->data, poh->val)); - } - goto respond; - 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); - break; - case OPENPCD_CMD_WRITE_FIFO: - DEBUGP("WRITE FIFO(len=%u): %s ", len, - hexdump(poh->data, len)); - rc632_fifo_write(RAH, len, poh->data, 0); - break; - case OPENPCD_CMD_READ_VFIFO: - DEBUGP("READ VFIFO "); - DEBUGP("NOT IMPLEMENTED YET "); - goto respond; - break; - case OPENPCD_CMD_WRITE_VFIFO: - DEBUGP("WRITE VFIFO "); - DEBUGP("NOT IMPLEMENTED YET "); - break; - case OPENPCD_CMD_REG_BITS_CLEAR: - DEBUGP("CLEAR BITS "); - pih->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); - break; - case OPENPCD_CMD_DUMP_REGS: - DEBUGP("DUMP REGS "); - DEBUGP("NOT IMPLEMENTED YET "); - goto respond; - 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; -} - -void rc632_init(void) -{ - //fifo_init(&rc632.fifo, 256, NULL, &rc632); - - DEBUGPCRF("entering"); - - AT91F_SPI_CfgPMC(); - - AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, - AT91C_PA11_NPCS0|AT91C_PA12_MISO| - AT91C_PA13_MOSI |AT91C_PA14_SPCK, 0); - - AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SPI, - OPENPCD_IRQ_PRIO_SPI, - AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &spi_irq); - AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SPI); - - AT91F_SPI_EnableIt(pSPI, AT91C_SPI_MODF|AT91C_SPI_OVRES); -#ifdef SPI_USES_DMA - AT91F_SPI_EnableIt(pSPI, AT91C_SPI_ENDRX|AT91C_SPI_ENDTX); -#endif - -#ifdef SPI_DEBUG_LOOPBACK - AT91F_SPI_CfgMode(pSPI, AT91C_SPI_MSTR|AT91C_SPI_PS_FIXED| - AT91C_SPI_MODFDIS|AT91C_SPI_LLB); -#else - AT91F_SPI_CfgMode(pSPI, AT91C_SPI_MSTR|AT91C_SPI_PS_FIXED| - AT91C_SPI_MODFDIS); -#endif - /* CPOL = 0, NCPHA = 1, CSAAT = 0, BITS = 0000, SCBR = 10 (4.8MHz), - * DLYBS = 0, DLYBCT = 0 */ -#ifdef SPI_USES_DMA - AT91F_SPI_CfgCs(pSPI, 0, AT91C_SPI_BITS_8|AT91C_SPI_NCPHA|(10<<8)); -#else - /* 320 kHz in case of I/O based SPI */ - AT91F_SPI_CfgCs(pSPI, 0, AT91C_SPI_BITS_8|AT91C_SPI_NCPHA|(0x7f<<8)); -#endif - AT91F_SPI_Enable(pSPI); - - /* Register rc632_irq */ - AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632, - OPENPCD_IRQ_PRIO_RC632, - AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &rc632_irq); - AT91F_AIC_EnableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); - - AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_RC632_RESET); - - rc632_reset(); - - /* configure IRQ pin */ - rc632_reg_write(RAH, RC632_REG_IRQ_PIN_CONFIG, - RC632_IRQCFG_CMOS|RC632_IRQCFG_INV); - /* enable interrupts */ - rc632_reg_write(RAH, RC632_REG_INTERRUPT_EN, RC632_INT_TIMER); - - /* configure AUX to test signal four */ - rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, 0x04); - - usb_hdlr_register(&rc632_usb_in, OPENPCD_CMD_CLS_RC632); -}; - -#if 0 -void rc632_exit(void) -{ - usb_hdlr_unregister(OPENPCD_CMD_CLS_RC632); - AT91F_AIC_DisableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); - AT91F_AIC_DisableIt(AT91C_BASE_AIC, AT91C_ID_SPI); - AT91F_SPI_Disable(pSPI); -} -#endif - -#ifdef DEBUG -static int rc632_reg_write_verify(struct rfid_asic_handle *hdl, - u_int8_t reg, u_int8_t val) -{ - u_int8_t tmp; - - rc632_reg_write(hdl, reg, val); - rc632_reg_read(hdl, reg, &tmp); - - DEBUGPCRF("reg=0x%02x, write=0x%02x, read=0x%02x ", reg, val, tmp); - - return (val == tmp); -} - -int rc632_dump(void) -{ - u_int8_t i; - u_int16_t rx_len = sizeof(spi_inbuf); - - for (i = 0; i <= 0x3f; i++) { - u_int8_t reg = i; - if (reg == RC632_REG_FIFO_DATA) - reg = 0x3e; - - spi_outbuf[i] = reg << 1; - spi_inbuf[i] = 0x00; - } - - /* MSB of first byte of read spi transfer is high */ - spi_outbuf[0] |= 0x80; - - /* last byte of read spi transfer is 0x00 */ - spi_outbuf[0x40] = 0x00; - spi_inbuf[0x40] = 0x00; - - spi_transceive(spi_outbuf, 0x41, spi_inbuf, &rx_len); - - for (i = 0; i < 0x3f; i++) { - if (i == RC632_REG_FIFO_DATA) - DEBUGPCR("REG 0x02 = NOT READ"); - else - DEBUGPCR("REG 0x%02x = 0x%02x", i, spi_inbuf[i+1]); - } - - return 0; -} - -int rc632_test(struct rfid_asic_handle *hdl) -{ - if (rc632_reg_write_verify(hdl, RC632_REG_RX_WAIT, 0x55) != 1) - return -1; - - if (rc632_reg_write_verify(hdl, RC632_REG_RX_WAIT, 0xAA) != 1) - return -1; - - return 0; -} -#else /* DEBUG */ -int rc632_test(struct rfid_asic_handle *hdl) {} -int rc632_dump(void) {} -#endif /* DEBUG */ diff --git a/openpcd/firmware/src/rc632.h b/openpcd/firmware/src/rc632.h deleted file mode 100644 index 1a4dc22..0000000 --- a/openpcd/firmware/src/rc632.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _RC623_API_H -#define _RC632_API_H - -#include -#include -#include - -extern int rc632_reg_write(struct rfid_asic_handle *hdl, - u_int8_t addr, u_int8_t data); -extern int rc632_fifo_write(struct rfid_asic_handle *hdl, - u_int8_t len, u_int8_t *data, u_int8_t flags); -extern int rc632_reg_read(struct rfid_asic_handle *hdl, - u_int8_t addr, u_int8_t *val); -extern int rc632_fifo_read(struct rfid_asic_handle *hdl, - u_int8_t max_len, u_int8_t *data); -extern int rc632_clear_bits(struct rfid_asic_handle *hdl, - u_int8_t reg, u_int8_t bits); -extern int rc632_set_bits(struct rfid_asic_handle *hdl, - u_int8_t reg, u_int8_t bits); - -extern void rc632_init(void); -extern void rc632_exit(void); - -extern void rc632_unthrottle(void); - -#ifdef DEBUG -extern int rc632_test(struct rfid_asic_handle *hdl); -extern int rc632_dump(void); -#endif - -#endif diff --git a/openpcd/firmware/src/rc632_highlevel.c b/openpcd/firmware/src/rc632_highlevel.c deleted file mode 100644 index 6fa0f70..0000000 --- a/openpcd/firmware/src/rc632_highlevel.c +++ /dev/null @@ -1,1465 +0,0 @@ -/* Generic Philips CL RC632 Routines - * - * (C) Harald Welte - * - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * 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 - */ - -#include -#include -#include -#include -#include "rc632.h" -#include "dbgu.h" -#include -#include - -/* initially we use the same values as cm5121 */ -#define OPENPCD_CW_CONDUCTANCE 0x3f -#define OPENPCD_MOD_CONDUCTANCE 0x3f -#define OPENPCD_14443A_BITPHASE 0xa9 -#define OPENPCD_14443A_THRESHOLD 0xff -#define OPENPCD_14443B_BITPHASE 0xad -#define OPENPCD_14443B_THRESHOLD 0xff - -#define RC632_TMO_AUTH1 14000 - -#define RC632_TIMEOUT_FUZZ_FACTOR 10 - -#define USE_IRQ - -#define ENTER() DEBUGPCRF("entering") -struct rfid_asic rc632; - -static int -rc632_set_bit_mask(struct rfid_asic_handle *handle, - u_int8_t reg, u_int8_t mask, u_int8_t val) -{ - int ret; - u_int8_t tmp; - - ret = rc632_reg_read(handle, reg, &tmp); - if (ret < 0) - return ret; - - /* if bits are already like we want them, abort */ - if ((tmp & mask) == val) - return 0; - - return rc632_reg_write(handle, reg, (tmp & ~mask)|(val & mask)); -} - -int -rc632_turn_on_rf(struct rfid_asic_handle *handle) -{ - ENTER(); - return rc632_set_bits(handle, RC632_REG_TX_CONTROL, 0x03); -} - -int -rc632_turn_off_rf(struct rfid_asic_handle *handle) -{ - ENTER(); - return rc632_clear_bits(handle, RC632_REG_TX_CONTROL, 0x03); -} - -static int -rc632_power_up(struct rfid_asic_handle *handle) -{ - ENTER(); - return rc632_clear_bits(handle, RC632_REG_CONTROL, - RC632_CONTROL_POWERDOWN); -} - -static int -rc632_power_down(struct rfid_asic_handle *handle) -{ - return rc632_set_bits(handle, RC632_REG_CONTROL, - RC632_CONTROL_POWERDOWN); -} - -/* calculate best 8bit prescaler and divisor for given usec timeout */ -static int best_prescaler(u_int64_t timeout, u_int8_t *prescaler, - u_int8_t *divisor) -{ - u_int8_t best_presc, best_divisor, i; - int64_t smallest_diff; - - smallest_diff = 0x7fffffffffffffff; - best_presc = 0; - - for (i = 0; i < 21; i++) { - u_int64_t clk, tmp_div, res; - int64_t diff; - clk = 13560000 / (1 << i); - tmp_div = (clk * timeout) / 1000000; - tmp_div++; - - if (tmp_div > 0xff) - continue; - - res = 1000000 / (clk / tmp_div); - diff = res - timeout; - - if (diff < 0) - continue; - - if (diff < smallest_diff) { - best_presc = i; - best_divisor = tmp_div; - smallest_diff = diff; - } - } - - *prescaler = best_presc; - *divisor = best_divisor; - - DEBUGPCRF("timeout %u usec, prescaler = %u, divisor = %u", timeout, best_presc, best_divisor); - - return 0; -} - -static int -rc632_timer_set(struct rfid_asic_handle *handle, - u_int64_t timeout) -{ - int ret; - u_int8_t prescaler, divisor; - - ret = best_prescaler(timeout*RC632_TIMEOUT_FUZZ_FACTOR, - &prescaler, &divisor); - - ret = rc632_reg_write(handle, RC632_REG_TIMER_CLOCK, - prescaler & 0x1f); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_TIMER_CONTROL, - RC632_TMR_START_TX_END|RC632_TMR_STOP_RX_BEGIN); - - /* clear timer irq bit */ - ret |= rc632_set_bits(handle, RC632_REG_INTERRUPT_RQ, RC632_INT_TIMER); - -#ifdef USE_IRQ_ - /* enable interrupt for expired timer */ - ret |= rc632_reg_write(handle, RC632_REG_INTERRUPT_EN, - RC632_INT_TIMER|RC632_INT_SET); -#endif - - ret |= rc632_reg_write(handle, RC632_REG_TIMER_RELOAD, divisor); - - return ret; -} - -/* Wait until RC632 is idle or TIMER IRQ has happened */ -static int rc632_wait_idle_timer(struct rfid_asic_handle *handle) -{ - int ret; - u_int8_t irq, cmd; - - while (1) { - ret = rc632_reg_read(handle, RC632_REG_INTERRUPT_RQ, &irq); - if (ret < 0) - return ret; - - /* FIXME: currently we're lazy: If we actually received - * something even after the timer expired, we accept it */ - if (irq & RC632_INT_TIMER && !(irq & RC632_INT_RX)) { - u_int8_t foo; - rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &foo); - DEBUGPCRF("TIMER && !INT_RX, PRIM_STATUS=0x%02x", foo); - if (foo & 0x04) { - rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &foo); - DEBUGPCRF("ERROR_FLAG=0x%02x, returning timeout", foo); - } - - return -ETIMEDOUT; - } - - ret = rc632_reg_read(handle, RC632_REG_COMMAND, &cmd); - if (ret < 0) - return ret; - - if (cmd == 0 || irq & RC632_INT_RX) - return 0; - - /* poll every millisecond */ - /* FIXME usleep(1000);*/ - } -} - -/* Stupid RC632 implementations don't evaluate interrupts but poll the - * command register for "status idle" */ -static int -rc632_wait_idle(struct rfid_asic_handle *handle, u_int64_t timeout) -{ - u_int8_t cmd = 0xff; - int ret, cycles = 0; -#define USLEEP_PER_CYCLE 128 - - while (cmd != 0) { - ret = rc632_reg_read(handle, RC632_REG_COMMAND, &cmd); - if (ret < 0) - return ret; - - if (cmd == 0) { - /* FIXME: read second time ?? */ - return 0; - } - - { - u_int8_t foo; - rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &foo); - if (foo & 0x04) - rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &foo); - } - - /* Abort after some timeout */ - if (cycles > timeout*RC632_TIMEOUT_FUZZ_FACTOR/USLEEP_PER_CYCLE) { - return -ETIMEDOUT; - } - - cycles++; - usleep(USLEEP_PER_CYCLE); - } - - return 0; -} - -static int -rc632_transmit(struct rfid_asic_handle *handle, - const u_int8_t *buf, - u_int8_t len, - u_int64_t timeout) -{ - int ret, cur_len; - const u_int8_t *cur_buf = buf; - - if (len > 64) - cur_len = 64; - else - cur_len = len; - - do { - ret = rc632_fifo_write(handle, cur_len, cur_buf, 0x03); - if (ret < 0) - return ret; - - if (cur_buf == buf) { - /* only start transmit first time */ - ret = rc632_reg_write(handle, RC632_REG_COMMAND, - RC632_CMD_TRANSMIT); - if (ret < 0) - return ret; - } - - cur_buf += cur_len; - if (cur_buf < buf + len) { - cur_len = buf - cur_buf; - if (cur_len > 64) - cur_len = 64; - } else - cur_len = 0; - - } while (cur_len); - - return rc632_wait_idle(handle, timeout); -} - -static int -tcl_toggle_pcb(struct rfid_asic_handle *handle) -{ - // FIXME: toggle something between 0x0a and 0x0b - return 0; -} - -static int -rc632_transceive(struct rfid_asic_handle *handle, - const u_int8_t *tx_buf, - u_int8_t tx_len, - u_int8_t *rx_buf, - u_int8_t *rx_len, - u_int64_t timer, - unsigned int toggle) -{ - int ret, cur_tx_len; - const u_int8_t *cur_tx_buf = tx_buf; - - DEBUGPCRF("tx_len=%u, rx_len=%u, timer=%llu", tx_len, *rx_len, timer); - - if (tx_len > 64) - cur_tx_len = 64; - else - cur_tx_len = tx_len; - - ret = rc632_reg_write(handle, RC632_REG_COMMAND, 0x00); - /* clear all interrupts */ - ret = rc632_reg_write(handle, RC632_REG_INTERRUPT_RQ, 0x7f); - if (ret < 0) - return ret; - - ret = rc632_timer_set(handle, timer); - if (ret < 0) - return ret; - - do { - ret = rc632_fifo_write(handle, cur_tx_len, cur_tx_buf, 0x03); - if (ret < 0) - return ret; - - if (cur_tx_buf == tx_buf) { - ret = rc632_reg_write(handle, RC632_REG_COMMAND, - RC632_CMD_TRANSCEIVE); - if (ret < 0) - return ret; - } - - cur_tx_buf += cur_tx_len; - if (cur_tx_buf < tx_buf + tx_len) { - u_int8_t fifo_fill; - ret = rc632_reg_read(handle, RC632_REG_FIFO_LENGTH, - &fifo_fill); - if (ret < 0) - return ret; - - cur_tx_len = 64 - fifo_fill; - DEBUGPCRF("refilling tx fifo with %u bytes", cur_tx_len); - } else - cur_tx_len = 0; - - } while (cur_tx_len); - - if (toggle == 1) - tcl_toggle_pcb(handle); - - ret = rc632_wait_idle_timer(handle); - if (ret < 0) - return ret; - - ret = rc632_reg_read(handle, RC632_REG_FIFO_LENGTH, rx_len); - if (ret < 0) - return ret; - - DEBUGPCRF("rx_len = %u\n", *rx_len); - - if (*rx_len == 0) { - u_int8_t tmp, tmp2; - - rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &tmp); - rc632_reg_read(handle, RC632_REG_CHANNEL_REDUNDANCY, &tmp2); - - DEBUGPCRF("rx_len == 0, error_flag=0x%02x, channel_red=0x%02x", - tmp, tmp2); - - return -1; - } - - return rc632_fifo_read(handle, *rx_len, rx_buf); -} - -static int -rc632_read_eeprom(struct rfid_asic_handle *handle) -{ - u_int8_t recvbuf[60]; - u_int8_t sndbuf[3]; - int ret; - - sndbuf[0] = 0x00; - sndbuf[1] = 0x00; - sndbuf[2] = 0x3c; - - ret = rc632_fifo_write(handle, 3, sndbuf, 0x03); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_READ_E2); - if (ret < 0) - return ret; - - usleep(20000); - - ret = rc632_fifo_read(handle, sizeof(recvbuf), recvbuf); - if (ret < 0) - return ret; - - // FIXME: do something with eeprom contents - return ret; -} - -static int -rc632_calc_crc16_from(struct rfid_asic_handle *handle) -{ - u_int8_t sndbuf[2] = { 0x01, 0x02 }; - u_int8_t crc_lsb = 0x00 , crc_msb = 0x00; - int ret; - - ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0x12); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0xe0); - if (ret < 0) - return ret; - - ret = rc632_fifo_write(handle, sizeof(sndbuf), sndbuf, 3); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_CALC_CRC); - if (ret < 0) - return ret; - - usleep(10000); // FIXME: no checking for cmd completion? - - ret = rc632_reg_read(handle, RC632_REG_CRC_RESULT_LSB, &crc_lsb); - if (ret < 0) - return ret; - - ret = rc632_reg_read(handle, RC632_REG_CRC_RESULT_MSB, &crc_msb); - if (ret < 0) - return ret; - - // FIXME: what to do with crc result? - return ret; -} - - -int -rc632_register_dump(struct rfid_asic_handle *handle, u_int8_t *buf) -{ - int ret; - u_int8_t i; - - for (i = 0; i <= 0x3f; i++) { - ret = rc632_reg_read(handle, i, &buf[i]); - // do we want error checks? - } - return 0; -} - - -#if 0 -static int -rc632_init(struct rfid_asic_handle *ah) -{ - int ret; - - /* switch off rf (make sure PICCs are reset at init time) */ - ret = rc632_power_down(ah); - if (ret < 0) - return ret; - - usleep(10000); - - /* switch on rf */ - ret = rc632_power_up(ah); - if (ret < 0) - return ret; - - /* disable register paging */ - ret = rc632_reg_write(ah, 0x00, 0x00); - if (ret < 0) - return ret; - - /* set some sane default values */ - ret = rc632_reg_write(ah, 0x11, 0x5b); - if (ret < 0) - return ret; - - /* switch on rf */ - ret = rc632_turn_on_rf(ah); - if (ret < 0) - return ret; - - return 0; -} - -static int -rc632_fini(struct rfid_asic_handle *ah) -{ - int ret; - - /* switch off rf */ - ret = rc632_turn_off_rf(ah); - if (ret < 0) - return ret; - - ret = rc632_power_down(ah); - if (ret < 0) - return ret; - - return 0; -} -#endif - - -/* - * Philips CL RC632 primitives for ISO 14443-A compliant PICC's - * - * (C) 2005 by Harald Welte - * - */ - -int -rc632_iso14443a_init(struct rfid_asic_handle *handle) -{ - int ret; - - // FIXME: some fifo work (drain fifo?) - - /* flush fifo (our way) */ - ret = rc632_reg_write(handle, RC632_REG_CONTROL, 0x01); - - ret = rc632_reg_write(handle, RC632_REG_TX_CONTROL, - (RC632_TXCTRL_TX1_RF_EN | - RC632_TXCTRL_TX2_RF_EN | - RC632_TXCTRL_TX2_INV | - RC632_TXCTRL_FORCE_100_ASK | - RC632_TXCTRL_MOD_SRC_INT)); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_CW_CONDUCTANCE, - OPENPCD_CW_CONDUCTANCE); - if (ret < 0) - return ret; - - /* Since FORCE_100_ASK is set (cf mc073930.pdf), this line may be left out? */ - ret = rc632_reg_write(handle, RC632_REG_MOD_CONDUCTANCE, - OPENPCD_MOD_CONDUCTANCE); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_CODER_CONTROL, - (RC632_CDRCTRL_TXCD_14443A | - RC632_CDRCTRL_RATE_106K)); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, 0x13); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH_SOF, 0x3f); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_TYPE_B_FRAMING, 0x00); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL1, - (RC632_RXCTRL1_GAIN_35DB | - RC632_RXCTRL1_ISO14443 | - RC632_RXCTRL1_SUBCP_8)); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_DECODER_CONTROL, - (RC632_DECCTRL_MANCHESTER | - RC632_DECCTRL_RXFR_14443A)); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_BIT_PHASE, - OPENPCD_14443A_BITPHASE); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD, - OPENPCD_14443A_THRESHOLD); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_BPSK_DEM_CONTROL, 0x00); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL2, - (RC632_RXCTRL2_DECSRC_INT | - RC632_RXCTRL2_CLK_Q)); - if (ret < 0) - return ret; - - /* Omnikey proprietary driver has 0x03, but 0x06 is the default reset value ?!? */ - ret = rc632_reg_write(handle, RC632_REG_RX_WAIT, 0x06); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, - (RC632_CR_PARITY_ENABLE | - RC632_CR_PARITY_ODD)); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0x63); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0x63); - if (ret < 0) - return ret; - - return 0; -} - -static int -rc632_iso14443a_fini(struct iso14443a_handle *handle_14443) -{ - -#if 0 - ret = rc632_turn_off_rf(handle); - if (ret < 0) - return ret; -#endif - - - return 0; -} - - -/* issue a 14443-3 A PCD -> PICC command in a short frame, such as REQA, WUPA */ -int -rc632_iso14443a_transceive_sf(struct rfid_asic_handle *handle, - u_int8_t cmd, - struct iso14443a_atqa *atqa) -{ - int ret; - u_int8_t tx_buf[1]; - u_int8_t rx_len = 2; - - DEBUGPCRF(""); - memset(atqa, 0, sizeof(atqa)); - - tx_buf[0] = cmd; - - /* transfer only 7 bits of last byte in frame */ - ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x07); - if (ret < 0) - return ret; - - ret = rc632_clear_bits(handle, RC632_REG_CONTROL, - RC632_CONTROL_CRYPTO1_ON); - if (ret < 0) - return ret; - -#if 0 - ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, - (RC632_CR_PARITY_ENABLE | - RC632_CR_PARITY_ODD)); -#else - ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY, - RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); - -#endif - if (ret < 0) - return ret; - - ret = rc632_transceive(handle, tx_buf, sizeof(tx_buf), - (u_int8_t *)atqa, &rx_len, - ISO14443A_FDT_ANTICOL_LAST1, 0); - if (ret < 0) { - DEBUGPCRF("error during rc632_transceive()"); - return ret; - } - - /* switch back to normal 8bit last byte */ - ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x00); - if (ret < 0) - return ret; - - if (rx_len != 2) { - DEBUGPCRF("rx_len(%d) != 2", rx_len); - return -1; - } - - return 0; -} - -/* transceive regular frame */ -int -rc632_iso14443ab_transceive(struct rfid_asic_handle *handle, - unsigned int frametype, - const u_int8_t *tx_buf, unsigned int tx_len, - u_int8_t *rx_buf, unsigned int *rx_len, - u_int64_t timeout, unsigned int flags) -{ - int ret; - u_int8_t rxl = *rx_len & 0xff; - u_int8_t channel_red; - - DEBUGPCRF("tx_len=%u, rx_len=%u", tx_len, *rx_len); - - memset(rx_buf, 0, *rx_len); - - switch (frametype) { - case RFID_14443A_FRAME_REGULAR: - case RFID_MIFARE_FRAME: - channel_red = RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE - |RC632_CR_PARITY_ENABLE|RC632_CR_PARITY_ODD; - break; - case RFID_14443B_FRAME_REGULAR: - channel_red = RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE - |RC632_CR_CRC3309; - break; -#if 0 - case RFID_MIFARE_FRAME: - channel_red = RC632_CR_PARITY_ENABLE|RC632_CR_PARITY_ODD; - break; -#endif - default: - return -EINVAL; - break; - } - ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, - channel_red); - if (ret < 0) - return ret; - - ret = rc632_transceive(handle, tx_buf, tx_len, rx_buf, &rxl, timeout, 0); - *rx_len = rxl; - if (ret < 0) - return ret; - - - return 0; -} - -/* transceive anti collission bitframe */ -int -rc632_iso14443a_transceive_acf(struct rfid_asic_handle *handle, - struct iso14443a_anticol_cmd *acf, - unsigned int *bit_of_col) -{ - int ret; - u_int8_t rx_buf[64]; - u_int8_t rx_len = sizeof(rx_buf); - u_int8_t rx_align = 0, tx_last_bits, tx_bytes; - u_int8_t boc; - u_int8_t error_flag; - *bit_of_col = ISO14443A_BITOFCOL_NONE; - memset(rx_buf, 0, sizeof(rx_buf)); - - /* disable mifare cryto */ - ret = rc632_clear_bits(handle, RC632_REG_CONTROL, - RC632_CONTROL_CRYPTO1_ON); - if (ret < 0) - return ret; - - /* disable CRC summing */ -#if 0 - ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, - (RC632_CR_PARITY_ENABLE | - RC632_CR_PARITY_ODD)); -#else - ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY, - RC632_CR_TX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); -#endif - if (ret < 0) - return ret; - - tx_last_bits = acf->nvb & 0x0f; /* lower nibble indicates bits */ - tx_bytes = acf->nvb >> 4; - if (tx_last_bits) { - tx_bytes++; - rx_align = (tx_last_bits+1) % 8;/* rx frame complements tx */ - } - - //rx_align = 8 - tx_last_bits;/* rx frame complements tx */ - - /* set RxAlign and TxLastBits*/ - ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, - (rx_align << 4) | (tx_last_bits)); - if (ret < 0) - return ret; - - ret = rc632_transceive(handle, (u_int8_t *)acf, tx_bytes, - rx_buf, &rx_len, 0x32, 0); - if (ret < 0) - return ret; - - /* bitwise-OR the two halves of the split byte */ - acf->uid_bits[tx_bytes-2] = ( - (acf->uid_bits[tx_bytes-2] & (0xff >> (8-tx_last_bits))) - | rx_buf[0]); - /* copy the rest */ - memcpy(&acf->uid_bits[tx_bytes+1-2], &rx_buf[1], rx_len-1); - - /* determine whether there was a collission */ - ret = rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &error_flag); - if (ret < 0) - return ret; - - if (error_flag & RC632_ERR_FLAG_COL_ERR) { - /* retrieve bit of collission */ - ret = rc632_reg_read(handle, RC632_REG_COLL_POS, &boc); - if (ret < 0) - return ret; - - /* bit of collission relative to start of part 1 of - * anticollision frame (!) */ - *bit_of_col = 2*8 + boc; - } - - return 0; -} - -enum rc632_rate { - RC632_RATE_106 = 0x00, - RC632_RATE_212 = 0x01, - RC632_RATE_424 = 0x02, - RC632_RATE_848 = 0x03, -}; - -struct rx_config { - u_int8_t subc_pulses; - u_int8_t rx_coding; - u_int8_t rx_threshold; - u_int8_t bpsk_dem_ctrl; -}; - -struct tx_config { - u_int8_t rate; - u_int8_t mod_width; -}; - -static struct rx_config rx_configs[] = { - { - .subc_pulses = RC632_RXCTRL1_SUBCP_8, - .rx_coding = RC632_DECCTRL_MANCHESTER, - .rx_threshold = 0x88, - .bpsk_dem_ctrl = 0x00, - }, - { - .subc_pulses = RC632_RXCTRL1_SUBCP_4, - .rx_coding = RC632_DECCTRL_BPSK, - .rx_threshold = 0x50, - .bpsk_dem_ctrl = 0x0c, - }, - { - .subc_pulses = RC632_RXCTRL1_SUBCP_2, - .rx_coding = RC632_DECCTRL_BPSK, - .rx_threshold = 0x50, - .bpsk_dem_ctrl = 0x0c, - }, - { - .subc_pulses = RC632_RXCTRL1_SUBCP_1, - .rx_coding = RC632_DECCTRL_BPSK, - .rx_threshold = 0x50, - .bpsk_dem_ctrl = 0x0c, - }, -}; - -static struct tx_config tx_configs[] = { - { - .rate = RC632_CDRCTRL_RATE_106K, - .mod_width = 0x13, - }, - { - .rate = RC632_CDRCTRL_RATE_212K, - .mod_width = 0x07, - }, - { - .rate = RC632_CDRCTRL_RATE_424K, - .mod_width = 0x03, - }, - { - .rate = RC632_CDRCTRL_RATE_848K, - .mod_width = 0x01, - }, -}; - -int rc632_iso14443a_set_speed(struct rfid_asic_handle *handle, - unsigned int tx, - u_int8_t rate) -{ - int rc; - u_int8_t reg; - - - if (!tx) { - /* Rx */ - if (rate > ARRAY_SIZE(rx_configs)) - return -EINVAL; - - rc = rc632_set_bit_mask(handle, RC632_REG_RX_CONTROL1, - RC632_RXCTRL1_SUBCP_MASK, - rx_configs[rate].subc_pulses); - if (rc < 0) - return rc; - - rc = rc632_set_bit_mask(handle, RC632_REG_DECODER_CONTROL, - RC632_DECCTRL_BPSK, - rx_configs[rate].rx_coding); - if (rc < 0) - return rc; - - rc = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD, - rx_configs[rate].rx_threshold); - if (rc < 0) - return rc; - - if (rx_configs[rate].rx_coding == RC632_DECCTRL_BPSK) { - rc = rc632_reg_write(handle, - RC632_REG_BPSK_DEM_CONTROL, - rx_configs[rate].bpsk_dem_ctrl); - if (rc < 0) - return rc; - } - } else { - /* Tx */ - if (rate > ARRAY_SIZE(tx_configs)) - return -EINVAL; - - rc = rc632_set_bit_mask(handle, RC632_REG_CODER_CONTROL, - RC632_CDRCTRL_RATE_MASK, - tx_configs[rate].rate); - if (rc < 0) - return rc; - - rc = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, - tx_configs[rate].mod_width); - if (rc < 0) - return rc; - } - - return 0; -} - -static int rc632_iso14443b_init(struct rfid_asic_handle *handle) -{ - int ret; - - // FIXME: some FIFO work - - /* flush fifo (our way) */ - ret = rc632_reg_write(handle, RC632_REG_CONTROL, 0x01); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_TX_CONTROL, - (RC632_TXCTRL_TX1_RF_EN | - RC632_TXCTRL_TX2_RF_EN | - RC632_TXCTRL_TX2_INV | - RC632_TXCTRL_MOD_SRC_INT)); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_CW_CONDUCTANCE, 0x3f); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_MOD_CONDUCTANCE, 0x04); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_CODER_CONTROL, - (RC632_CDRCTRL_TXCD_NRZ | - RC632_CDRCTRL_RATE_14443B)); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, 0x13); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH_SOF, 0x3f); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_TYPE_B_FRAMING, - (RC632_TBFRAMING_SOF_11L_3H | - (6 << RC632_TBFRAMING_SPACE_SHIFT) | - RC632_TBFRAMING_EOF_11)); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL1, - (RC632_RXCTRL1_GAIN_35DB | - RC632_RXCTRL1_ISO14443 | - RC632_RXCTRL1_SUBCP_8)); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_DECODER_CONTROL, - (RC632_DECCTRL_BPSK | - RC632_DECCTRL_RXFR_14443B)); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_BIT_PHASE, - OPENPCD_14443B_BITPHASE); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD, - OPENPCD_14443B_THRESHOLD); - if (ret < 0) - return ret; - - ret = rc632_reg_write(handle, RC632_REG_BPSK_DEM_CONTROL, - ((0x2 & RC632_BPSKD_TAUB_MASK)<> 4; - key12[i * 2 + 1] = (~ln << 4) | ln; - key12[i * 2] = (~hn << 4) | hn; - } - return 0; -} - -static int -rc632_mifare_set_key(struct rfid_asic_handle *h, const u_int8_t *key) -{ - u_int8_t coded_key[RFID_MIFARE_KEY_CODED_LEN]; - u_int8_t reg; - int ret; - - ret = rc632_mifare_transform_key(key, coded_key); - if (ret < 0) - return ret; - - ret = rc632_fifo_write(h, RFID_MIFARE_KEY_CODED_LEN, coded_key, 0x03); - if (ret < 0) - return ret; - - ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_LOAD_KEY); - if (ret < 0) - return ret; - - ret = rc632_wait_idle(h, RC632_TMO_AUTH1); - if (ret < 0) - return ret; - - ret = rc632_reg_read(h, RC632_REG_ERROR_FLAG, ®); - if (ret < 0) - return ret; - - if (reg & RC632_ERR_FLAG_KEY_ERR) - return -EINVAL; - - return 0; -} - -static int -rc632_mifare_auth(struct rfid_asic_handle *h, u_int8_t cmd, u_int32_t serno, - u_int8_t block) -{ - int ret; - struct mifare_authcmd acmd; - u_int8_t reg; - - if (cmd != RFID_CMD_MIFARE_AUTH1A && cmd != RFID_CMD_MIFARE_AUTH1B) - return -EINVAL; - - /* Initialize acmd */ - acmd.block_address = block & 0xff; - acmd.auth_cmd = cmd; - //acmd.serno = htonl(serno); - acmd.serno = serno; - - /* Clear Rx CRC */ - ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY, - RC632_CR_RX_CRC_ENABLE); - if (ret < 0) - return ret; - - /* Send Authent1 Command */ - ret = rc632_fifo_write(h, sizeof(acmd), (unsigned char *)&acmd, 0x03); - if (ret < 0) - return ret; - - ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_AUTHENT1); - if (ret < 0) - return ret; - - /* Wait until transmitter is idle */ - ret = rc632_wait_idle(h, RC632_TMO_AUTH1); - if (ret < 0) - return ret; - - ret = rc632_reg_read(h, RC632_REG_SECONDARY_STATUS, ®); - if (ret < 0) - return ret; - if (reg & 0x07) - return -EIO; - - /* Clear Tx CRC */ - ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY, - RC632_CR_TX_CRC_ENABLE); - if (ret < 0) - return ret; - - /* Send Authent2 Command */ - ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_AUTHENT2); - if (ret < 0) - return ret; - - /* Wait until transmitter is idle */ - ret = rc632_wait_idle(h, RC632_TMO_AUTH1); - if (ret < 0) - return ret; - - /* Check whether authentication was successful */ - ret = rc632_reg_read(h, RC632_REG_CONTROL, ®); - if (ret < 0) - return ret; - - if (!(reg & RC632_CONTROL_CRYPTO1_ON)) - return -EACCES; - - return 0; - -} - -/* transceive regular frame */ -static int -rc632_mifare_transceive(struct rfid_asic_handle *handle, - const u_int8_t *tx_buf, unsigned int tx_len, - u_int8_t *rx_buf, unsigned int *rx_len, - u_int64_t timeout, unsigned int flags) -{ - int ret; - u_int8_t rxl = *rx_len & 0xff; - - DEBUGP("entered\n"); - memset(rx_buf, 0, *rx_len); - -#if 1 - ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, - (RC632_CR_PARITY_ENABLE | - RC632_CR_PARITY_ODD | - RC632_CR_TX_CRC_ENABLE | - RC632_CR_RX_CRC_ENABLE)); -#else - ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY, - RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); -#endif - if (ret < 0) - return ret; - - ret = rc632_transceive(handle, tx_buf, tx_len, rx_buf, &rxl, 0x32, 0); - *rx_len = rxl; - if (ret < 0) - return ret; - - - return 0; -} - diff --git a/openpcd/firmware/src/req_ctx.c b/openpcd/firmware/src/req_ctx.c deleted file mode 100644 index 984f6b9..0000000 --- a/openpcd/firmware/src/req_ctx.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include - -#include "openpcd.h" -#include "dbgu.h" - -/* FIXME: locking, FIFO order processing */ - -static struct req_ctx req_ctx[NUM_REQ_CTX]; - -struct req_ctx *req_ctx_find_get(unsigned long old_state, unsigned long new_state) -{ - unsigned long flags; - u_int8_t i; - - for (i = 0; i < NUM_REQ_CTX; i++) { - local_irq_save(flags); - if (req_ctx[i].state == old_state) { - req_ctx[i].state = new_state; - local_irq_restore(flags); - return &req_ctx[i]; - } - local_irq_restore(flags); - } - - return NULL; -} - -u_int8_t req_ctx_num(struct req_ctx *ctx) -{ - return ((void *)ctx - (void *)&req_ctx[0])/sizeof(*ctx); -} - -void req_ctx_set_state(struct req_ctx *ctx, unsigned long new_state) -{ - unsigned long flags; - - /* FIXME: do we need this kind of locking, we're UP! */ - local_irq_save(flags); - ctx->state = new_state; - local_irq_restore(flags); -} - -void req_ctx_put(struct req_ctx *ctx) -{ - req_ctx_set_state(ctx, RCTX_STATE_FREE); -} diff --git a/openpcd/firmware/src/rfid_layer2_iso14443a.c b/openpcd/firmware/src/rfid_layer2_iso14443a.c deleted file mode 100644 index 80d9d5f..0000000 --- a/openpcd/firmware/src/rfid_layer2_iso14443a.c +++ /dev/null @@ -1,319 +0,0 @@ -/* ISO 14443-3 A anticollision implementation - * - * (C) 2005 by Harald Welte - * - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * 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 - */ - -#include -#include -#include -#include - -#include -#include -//#include -#include - -#define TIMEOUT 1236 - -/* Transceive a 7-bit short frame */ -static int -iso14443a_transceive_sf(struct rfid_layer2_handle *handle, - unsigned char cmd, - struct iso14443a_atqa *atqa) -{ - //struct rfid_reader *rdr = handle->rh->reader; - DEBUGPCRF(""); - - return rc632_iso14443a_transceive_sf(handle->rh, cmd, atqa); -} - -/* Transmit an anticollission bit frame */ -static int -iso14443a_transceive_acf(struct rfid_layer2_handle *handle, - struct iso14443a_anticol_cmd *acf, - unsigned int *bit_of_col) -{ - //struct rfid_reader *rdr = handle->rh->reader; - DEBUGPCRF(""); - - return rc632_iso14443a_transceive_acf(handle->rh, acf, bit_of_col); -} - -/* Transmit a regular frame */ -static int -iso14443a_transceive(struct rfid_layer2_handle *handle, - enum rfid_frametype frametype, - const unsigned char *tx_buf, unsigned int tx_len, - unsigned char *rx_buf, unsigned int *rx_len, - u_int64_t timeout, unsigned int flags) -{ - DEBUGPCRF("tx_len=%u, rx_len=%u", tx_len, *rx_len); - return rc632_iso14443ab_transceive(handle->rh, frametype, tx_buf, - tx_len, rx_buf, rx_len, timeout, flags); -} - -static int -iso14443a_code_nvb_bits(unsigned char *nvb, unsigned int bits) -{ - unsigned int byte_count = bits / 8; - unsigned int bit_count = bits % 8; - - if (byte_count < 2 || byte_count > 7) - return -1; - - *nvb = ((byte_count & 0xf) << 4) | bit_count; - - return 0; -} - -/* first bit is '1', second bit '2' */ -static void -set_bit_in_field(unsigned char *bitfield, unsigned int bit) -{ - unsigned int byte_count = bit / 8; - unsigned int bit_count = bit % 8; - - DEBUGP("bitfield=%p, byte_count=%u, bit_count=%u\n", - bitfield, byte_count, bit_count); - DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count)); - *(bitfield+byte_count) |= 1 << (bit_count-1); - DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count)); -} - -static int -iso14443a_anticol(struct rfid_layer2_handle *handle) -{ - int ret; - unsigned int uid_size; - struct iso14443a_handle *h = &handle->priv.iso14443a; - struct iso14443a_atqa atqa; - struct iso14443a_anticol_cmd acf; - unsigned int bit_of_col; - unsigned char sak[3]; - unsigned int rx_len = sizeof(sak); - char *aqptr = (char *) &atqa; - - memset(handle->uid, 0, sizeof(handle->uid)); - memset(sak, 0, sizeof(sak)); - memset(&atqa, 0, sizeof(atqa)); - memset(&acf, 0, sizeof(acf)); - - ret = iso14443a_transceive_sf(handle, ISO14443A_SF_CMD_REQA, &atqa); - if (ret < 0) { - h->state = ISO14443A_STATE_REQA_SENT; - DEBUGP("error during transceive_sf: %d\n", ret); - return ret; - } - h->state = ISO14443A_STATE_ATQA_RCVD; - - DEBUGP("ATQA: 0x%02x 0x%02x\n", *aqptr, *(aqptr+1)); - - if (!atqa.bf_anticol) { - h->state = ISO14443A_STATE_NO_BITFRAME_ANTICOL; - DEBUGP("no bitframe anticollission bits set, aborting\n"); - return -1; - } - - if (atqa.uid_size == 2 || atqa.uid_size == 3) - uid_size = 3; - else if (atqa.uid_size == 1) - uid_size = 2; - else - uid_size = 1; - - acf.sel_code = ISO14443A_AC_SEL_CODE_CL1; - - h->state = ISO14443A_STATE_ANTICOL_RUNNING; - h->level = ISO14443A_LEVEL_CL1; - -cascade: - iso14443a_code_nvb_bits(&acf.nvb, 16); - - ret = iso14443a_transceive_acf(handle, &acf, &bit_of_col); - if (ret < 0) - return ret; - DEBUGP("bit_of_col = %d\n", bit_of_col); - - while (bit_of_col != ISO14443A_BITOFCOL_NONE) { - set_bit_in_field(&acf.uid_bits[0], bit_of_col-16); - iso14443a_code_nvb_bits(&acf.nvb, bit_of_col); - ret = iso14443a_transceive_acf(handle, &acf, &bit_of_col); - DEBUGP("bit_of_col = %d\n", bit_of_col); - if (ret < 0) - return ret; - } - - iso14443a_code_nvb_bits(&acf.nvb, 7*8); - ret = iso14443a_transceive(handle, RFID_14443A_FRAME_REGULAR, - (unsigned char *)&acf, 7, - (unsigned char *) &sak, &rx_len, - TIMEOUT, 0); - if (ret < 0) - return ret; - - if (sak[0] & 0x04) { - /* Cascade bit set, UID not complete */ - switch (acf.sel_code) { - case ISO14443A_AC_SEL_CODE_CL1: - /* cascading from CL1 to CL2 */ - if (acf.uid_bits[0] != 0x88) { - DEBUGP("Cascade bit set, but UID0 != 0x88\n"); - return -1; - } - memcpy(&handle->uid[0], &acf.uid_bits[1], 3); - acf.sel_code = ISO14443A_AC_SEL_CODE_CL2; - h->level = ISO14443A_LEVEL_CL2; - break; - case ISO14443A_AC_SEL_CODE_CL2: - /* cascading from CL2 to CL3 */ - memcpy(&handle->uid[3], &acf.uid_bits[1], 3); - acf.sel_code = ISO14443A_AC_SEL_CODE_CL3; - h->level = ISO14443A_LEVEL_CL3; - break; - default: - DEBUGP("cannot cascade any further than CL3\n"); - h->state = ISO14443A_STATE_ERROR; - return -1; - break; - } - goto cascade; - - } else { - switch (acf.sel_code) { - case ISO14443A_AC_SEL_CODE_CL1: - /* single size UID (4 bytes) */ - memcpy(&handle->uid[0], &acf.uid_bits[0], 4); - break; - case ISO14443A_AC_SEL_CODE_CL2: - /* double size UID (7 bytes) */ - memcpy(&handle->uid[3], &acf.uid_bits[0], 4); - break; - case ISO14443A_AC_SEL_CODE_CL3: - /* triple size UID (10 bytes) */ - memcpy(&handle->uid[6], &acf.uid_bits[0], 4); - break; - } - } - - h->level = ISO14443A_LEVEL_NONE; - h->state = ISO14443A_STATE_SELECTED; - - { - if (uid_size == 1) - handle->uid_len = 4; - else if (uid_size == 2) - handle->uid_len = 7; - else - handle->uid_len = 10; - - DEBUGP("UID %s\n", rfid_hexdump(handle->uid, handle->uid_len)); - } - - if (sak[0] & 0x20) { - DEBUGP("we have a T=CL compliant PICC\n"); - h->tcl_capable = 1; - } else { - DEBUGP("we have a T!=CL PICC\n"); - h->tcl_capable = 0; - } - - return 0; -} - -static int -iso14443a_hlta(struct rfid_layer2_handle *handle) -{ - int ret; - unsigned char tx_buf[2] = { 0x50, 0x00 }; - unsigned char rx_buf[10]; - unsigned int rx_len = sizeof(rx_buf); - - ret = iso14443a_transceive(handle, RFID_14443A_FRAME_REGULAR, - tx_buf, sizeof(tx_buf), - rx_buf, &rx_len, 1000 /* 1ms */, 0); - if (ret < 0) { - /* "error" case: we don't get somethng back from the card */ - return 0; - } - return -1; -} - -static int -iso14443a_setopt(struct rfid_layer2_handle *handle, int optname, - const void *optval, unsigned int optlen) -{ - int ret = -EINVAL; - unsigned int speed; - - switch (optname) { - case RFID_OPT_14443A_SPEED_RX: - speed = *(unsigned int *)optval; - ret = rc632_iso14443a_set_speed(handle->rh, 0, speed); - break; - case RFID_OPT_14443A_SPEED_TX: - speed = *(unsigned int *)optval; - ret = rc632_iso14443a_set_speed(handle->rh, 1, speed); - break; - }; - - return ret; -} - - -static struct rfid_layer2_handle * -iso14443a_init(struct rfid_reader_handle *rh) -{ - int ret; - struct rfid_layer2_handle *h = malloc(sizeof(*h)); - if (!h) - return NULL; - - h->l2 = &rfid_layer2_iso14443a; - h->rh = rh; - h->priv.iso14443a.state = ISO14443A_STATE_NONE; - h->priv.iso14443a.level = ISO14443A_LEVEL_NONE; - - ret = rc632_iso14443a_init(h->rh); - if (ret < 0) { - free(h); - return NULL; - } - - return h; -} - -static int -iso14443a_fini(struct rfid_layer2_handle *handle) -{ - free(handle); - return 0; -} - -struct rfid_layer2 rfid_layer2_iso14443a = { - .id = RFID_LAYER2_ISO14443A, - .name = "ISO 14443-3 A", - .fn = { - .init = &iso14443a_init, - .open = &iso14443a_anticol, - .transceive = &iso14443a_transceive, - .close = &iso14443a_hlta, - .fini = &iso14443a_fini, - .setopt = &iso14443a_setopt, - }, -}; diff --git a/openpcd/firmware/src/start/Cstartup.S b/openpcd/firmware/src/start/Cstartup.S index 68e1a07..731d4c3 100644 --- a/openpcd/firmware/src/start/Cstartup.S +++ b/openpcd/firmware/src/start/Cstartup.S @@ -16,6 +16,41 @@ //*- 1.1 01/Apr/05 JPP : save SPSR //*-----------------------------------------------------------------------------*/ +//#define DEBUG_LL + +#ifdef DEBUG_LL +#define PIOA_PER 0xFFFFF400 +#define PIOA_OER 0xFFFFF410 +#define PIOA_SODR 0xFFFFF430 +#define PIOA_CODR 0xFFFFF434 +#define LED1 25 + .macro led1on + ldr r2, =PIOA_CODR + mov r1, #(1 << LED1) + str r1, [r2] + .endm + .macro led1off + ldr r2, =PIOA_SODR + mov r1, #(1 << LED1) + str r1, [r2] + .endm + .macro ledinit + ldr r2, =PIOA_PER + mov r1, #(1 << LED1) + str r1, [r2] + ldr r2, =PIOA_OER + str r1, [r2] + led1off + .endm +#else + .macro ledinit + .endm + .macro led1on + .endm + .macro led1off + .endm +#endif + .equ IRQ_Stack_Size, 0x00000400 .equ AIC_IVR, (256) @@ -128,6 +163,7 @@ IRQ_Handler_EntryR: .global remap .func remap _remap: +# led1on # Remap RAM to 0x00000000 for DFU ldr r1, =AT91C_BASE_AIC mov r2, #0x01 @@ -236,11 +272,12 @@ InitReset: /*- minumum C initialization */ /*- call AT91F_LowLevelInit( void) */ - ldr r13,.RAM_TOP /* temporary stack in internal RAM */ + ldr r13,.RAM_TOP /* temporary stack in internal RAM */ /*--Call Low level init function in ABSOLUTE through the Interworking */ - ldr r0,=AT91F_LowLevelInit - mov lr, pc - bx r0 + ldr r0,=AT91F_LowLevelInit + mov lr, pc + bx r0 + ledinit /*------------------------------------------------------------------------------ //*- Stack Sizes Definition //*------------------------ @@ -287,6 +324,15 @@ InitReset: msr CPSR_c, #ARM_MODE_SVC mov r13, r0 /* Init stack Sup */ +/*- Relocate DFU .data section (Copy from ROM to RAM)*/ + ldr r1, =_etext_dfu + ldr r2, =_data_dfu + ldr r3, =_edata_dfu +LoopRelDFU: cmp r2, r3 + ldrlo r0, [r1], #4 + strlo r0, [r2], #4 + blo LoopRelDFU + # Relocate .data section (Copy from ROM to RAM) LDR R1, =_etext LDR R2, =_data @@ -304,6 +350,8 @@ LoopZI: CMP R1, R2 STRLO R0, [R1], #4 BLO LoopZI + led1on + ldr r0, =_remap bx r0 diff --git a/openpcd/firmware/src/syscalls.c b/openpcd/firmware/src/syscalls.c deleted file mode 100644 index ed989f1..0000000 --- a/openpcd/firmware/src/syscalls.c +++ /dev/null @@ -1,169 +0,0 @@ -/***********************************************************************/ -/* */ -/* SYSCALLS.C: System Calls */ -/* most of this is from newlib-lpc and a Keil-demo */ -/* */ -/* These are "reentrant functions" as needed by */ -/* the WinARM-newlib-config, see newlib-manual. */ -/* Collected and modified by Martin Thomas */ -/* */ -/***********************************************************************/ - - -#include -#include -#include - -#include - -static void my_putc(char c) -{ - while (!AT91F_US_TxReady((AT91PS_USART)AT91C_BASE_DBGU)); - AT91F_US_PutChar((AT91PS_USART)AT91C_BASE_DBGU, c); -} - -static int my_kbhit( void ) -{ - if ((AT91F_US_RxReady((AT91PS_USART)AT91C_BASE_DBGU)) == 0) return 0; - else return 1; -} - -static char my_getc( void ) -{ - return AT91F_US_GetChar((AT91PS_USART)AT91C_BASE_DBGU); -} - -_ssize_t _read_r( - struct _reent *r, - int file, - void *ptr, - size_t len) -{ - char c; - int i; - unsigned char *p; - - p = (unsigned char*)ptr; - - for (i = 0; i < len; i++) { - // c = uart0Getch(); - // c = uart0GetchW(); - while ( !my_kbhit() ) ; - c = (char) my_getc(); - if (c == 0x0D) { - *p='\0'; - break; - } - *p++ = c; - ////// uart0_putc(c); - } - return len - i; -} - - -_ssize_t _write_r ( - struct _reent *r, - int file, - const void *ptr, - size_t len) -{ - int i; - const unsigned char *p; - - p = (const unsigned char*) ptr; - - for (i = 0; i < len; i++) { - if (*p == '\n' ) my_putc('\r'); - my_putc(*p++); - } - - return len; -} - - -int _close_r( - struct _reent *r, - int file) -{ - return 0; -} - - -_off_t _lseek_r( - struct _reent *r, - int file, - _off_t ptr, - int dir) -{ - return (_off_t)0; /* Always indicate we are at file beginning. */ -} - - -int _fstat_r( - struct _reent *r, - int file, - struct stat *st) -{ - /* Always set as character device. */ - st->st_mode = S_IFCHR; - /* assigned to strong type with implicit */ - /* signed/unsigned conversion. Required by */ - /* newlib. */ - - return 0; -} - - -int isatty(int file); /* avoid warning */ - -int isatty(int file) -{ - return 1; -} - - -#if 0 -static void _exit (int n) { -label: goto label; /* endless loop */ -} -#endif - - -/* "malloc clue function" from newlib-lpc/Keil-Demo/"generic" */ - -/**** Locally used variables. ****/ -// mt: "cleaner": extern char* end; -extern char end[]; /* end is set in the linker command */ - /* file and is the end of statically */ - /* allocated data (thus start of heap). */ - -static char *heap_ptr; /* Points to current end of the heap. */ - -/************************** _sbrk_r ************************************* - * Support function. Adjusts end of heap to provide more memory to - * memory allocator. Simple and dumb with no sanity checks. - - * struct _reent *r -- re-entrancy structure, used by newlib to - * support multiple threads of operation. - * ptrdiff_t nbytes -- number of bytes to add. - * Returns pointer to start of new heap area. - * - * Note: This implementation is not thread safe (despite taking a - * _reent structure as a parameter). - * Since _s_r is not used in the current implementation, - * the following messages must be suppressed. - */ -void * _sbrk_r( - struct _reent *_s_r, - ptrdiff_t nbytes) -{ - char *base; /* errno should be set to ENOMEM on error */ - - if (!heap_ptr) { /* Initialize if first time through. */ - heap_ptr = end; - } - base = heap_ptr; /* Point to end of heap. */ - heap_ptr += nbytes; /* Increase heap. */ - - return base; /* Return pointer to start of new heap area. */ -} diff --git a/openpcd/firmware/src/tc.c b/openpcd/firmware/src/tc.c deleted file mode 100644 index 2f4628a..0000000 --- a/openpcd/firmware/src/tc.c +++ /dev/null @@ -1,122 +0,0 @@ -/* OpenPC TC (Timer / Clock) support code - * (C) 2006 by Harald Welte - * - * This idea of this code is to feed the 13.56MHz carrier clock of RC632 - * into TCLK1, which is routed to XC1. Then configure TC0 to divide this - * clock by a configurable divider. - * - * PICC Simulator Side: - * In order to support responding to synchronous frames (REQA/WUPA/ANTICOL), - * we need a second Timer/Counter (TC1). This unit is reset by an external - * event (rising edge of modulation pause PCD->PICC) connected to TIOB2, and - * counts up to a configurable number of carrier clock cycles (RA). Once the - * RA value is reached, TIOA2 will see a rising edge. This rising edge will - * be interconnected to TF (Tx Frame) of the SSC to start transmitting our - * synchronous response. - * - */ - -#include -#include "openpcd.h" -#include "dbgu.h" -#include "tc.h" - -static AT91PS_TCB tcb = AT91C_BASE_TCB; - -/* set carrier divider to a specific */ -void tc_cdiv_set_divider(u_int16_t div) -{ - tcb->TCB_TC0.TC_RC = div; - - /* set to 50% duty cycle */ - tcb->TCB_TC0.TC_RA = 1; - tcb->TCB_TC0.TC_RB = 1 + (div >> 1); -} - -void tc_cdiv_phase_add(int16_t inc) -{ - tcb->TCB_TC0.TC_RA = (tcb->TCB_TC0.TC_RA + inc) % tcb->TCB_TC0.TC_RC; - tcb->TCB_TC0.TC_RB = (tcb->TCB_TC0.TC_RB + inc) % tcb->TCB_TC0.TC_RC; - - /* FIXME: can this be done more elegantly? */ - if (tcb->TCB_TC0.TC_RA == 0) { - tcb->TCB_TC0.TC_RA += 1; - tcb->TCB_TC0.TC_RB += 1; - } -} - -#ifdef CONFIG_PICCSIM -void tc_fdt_set(u_int16_t count) -{ - tcb->TC_TC2.TC_RA = count; -} -#endif - -void tc_cdiv_init(void) -{ - /* Cfg PA28(TCLK1), PA0(TIOA0), PA1(TIOB0), PA20(TCLK2) as Periph B */ - AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, - OPENPCD_PIO_CARRIER_IN | - OPENPCD_PIO_CARRIER_DIV_OUT | - OPENPCD_PIO_CDIV_HELP_OUT | - OPENPCD_PIO_CDIV_HELP_IN); - - AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, - ((unsigned int) 1 << AT91C_ID_TC0)); - - /* Enable Clock for TC0 */ - tcb->TCB_TC0.TC_CCR = AT91C_TC_CLKEN; - - /* Connect TCLK1 to XC1, TCLK2 to XC2 */ - tcb->TCB_BMR &= ~(AT91C_TCB_TC1XC1S | AT91C_TCB_TC2XC2S); - tcb->TCB_BMR |= (AT91C_TCB_TC1XC1S_TCLK1 | AT91C_TCB_TC2XC2S_TCLK2); - - /* Clock XC1, Wave mode, Reset on RC comp - * TIOA0 on RA comp = set, * TIOA0 on RC comp = clear, - * TIOB0 on EEVT = set, TIOB0 on RB comp = clear, - * EEVT = XC2 (TIOA0) */ - tcb->TCB_TC0.TC_CMR = AT91C_TC_CLKS_XC1 | AT91C_TC_WAVE | - AT91C_TC_WAVESEL_UP_AUTO | - AT91C_TC_ACPA_SET | AT91C_TC_ACPC_CLEAR | - AT91C_TC_BEEVT_SET | AT91C_TC_BCPB_CLEAR | - AT91C_TC_EEVT_XC2 | AT91C_TC_ETRGEDG_RISING; - - tc_cdiv_set_divider(128); - -#ifdef CONFIG_PICCSIM - AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, AT91C_PA15_TF, - AT91C_PA26_TIOA2, AT91C_PA17_TIOB2); - AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, - ((unsigned int) 1 << AT91C_ID_TC2)); - /* Clock XC1, Wave Mode, No automatic reset on RC comp - * TIOA2 in RA comp = set, TIOA2 on RC comp = clear, - * TIOB2 as input, EEVT = TIOB2, Reset/Trigger on EEVT */ - tcb->TCB_TC2.TC_CMR = AT91C_TC_CLKS_XC1 | AT91C_TC_WAVE | - AT91C_TC_WAVESEL_UP | - AT91C_TC_ACPA_SET | AT91C_ACPC_CLEAR | - AT91C_TC_BEEVT_NONE | AT91C_TC_BCPB_NONE | - AT91C_TC_EEVT_TIOB | AT91C_TC_ETRGEDG_RISING | - AT91C_TC_ENETRG ; -#endif - - /* Reset to start timers */ - tcb->TCB_BCR = 1; -} - -void tc_cdiv_print(void) -{ - DEBUGP("TCB_BMR=0x%08x ", tcb->TCB_BMR); - DEBUGP("TC0_CV=0x%08x ", tcb->TCB_TC0.TC_CV); - DEBUGP("TC0_CMR=0x%08x ", tcb->TCB_TC0.TC_CMR); - DEBUGPCR("TC0_SR=0x%08x", tcb->TCB_TC0.TC_SR); - - DEBUGPCR("TC0_RA=0x%04x, TC0_RB=0x%04x, TC0_RC=0x%04x", - tcb->TCB_TC0.TC_RA, tcb->TCB_TC0.TC_RB, tcb->TCB_TC0.TC_RC); -} - -void tc_cdiv_fini(void) -{ - tcb->TCB_TC0.TC_CCR = AT91C_TC_CLKDIS; - AT91F_PMC_DisablePeriphClock(AT91C_BASE_PMC, - ((unsigned int) 1 << AT91C_ID_TC0)); -} diff --git a/openpcd/firmware/src/tc.h b/openpcd/firmware/src/tc.h deleted file mode 100644 index e7aa7e4..0000000 --- a/openpcd/firmware/src/tc.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _TC_H -#define _TC_H - -#include - -extern void tc_cdiv_phase_add(int16_t inc); -extern void tc_cdiv_set_divider(u_int16_t div); - -static inline void tc_cdiv_phase_inc(void) -{ - tc_cdiv_phase_add(1); -} - -static inline void tc_cdiv_phase_dec(void) -{ - tc_cdiv_phase_add(-1); -} - - -extern void tc_cdiv_print(void); -extern void tc_cdiv_init(void); -extern void tc_cdiv_fini(void); - -#ifdef CONFIG_PICCSIM -extern void tc_fdt_set(u_int16_t count); -#endif - -#endif diff --git a/openpcd/firmware/src/trigger.c b/openpcd/firmware/src/trigger.c deleted file mode 100644 index 7fc51d1..0000000 --- a/openpcd/firmware/src/trigger.c +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include "openpcd.h" -#include "trigger.h" - -void trigger_init(void) -{ - AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); -} - -void trigger_pulse(void) -{ - volatile int i; - AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); - for (i=0; i < 0xff; i++) - { } - AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); -} diff --git a/openpcd/firmware/src/trigger.h b/openpcd/firmware/src/trigger.h deleted file mode 100644 index 597704b..0000000 --- a/openpcd/firmware/src/trigger.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _TRIGGER_H -#define _TRIGGER_H - -extern void trigger_init(void); -extern void trigger_pulse(void); - -#endif diff --git a/openpcd/firmware/src/usb_benchmark.c b/openpcd/firmware/src/usb_benchmark.c deleted file mode 100644 index 9f593f8..0000000 --- a/openpcd/firmware/src/usb_benchmark.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include -#include "openpcd.h" -#include "led.h" -#include "pcd_enumerate.h" -#include "usb_handler.h" - -static struct req_ctx dummy_rctx; -static struct req_ctx empty_rctx; - -static void usbtest_tx_transfer(unsigned int num_pkts) -{ - unsigned int i; - - for (i = 0; i < num_pkts; i++) { - /* send 16 packets of 64byte */ - while (udp_refill_ep(2, &dummy_rctx) < 0) - ; - } - /* send one packet of 0 byte */ - while (udp_refill_ep(2, &empty_rctx) < 0) - ; -} - -static int usbtest_rx(struct req_ctx *rctx) -{ - struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->rx.data[0]; - int i; - - switch (poh->cmd) { - case OPENPCD_CMD_USBTEST_IN: - /* test bulk in pipe */ - for (i = 0; i < poh->reg; i++) { - usbtest_tx_transfer(poh->val); - led_toggle(2); - } - break; - case OPENPCD_CMD_USBTEST_OUT: - /* test bulk out pipe */ - break; - } - - req_ctx_put(rctx); - return 1; -} - -void usbtest_init(void) -{ - dummy_rctx.tx.tot_len = 64; - memset(dummy_rctx.tx.data, 0x23, 64); - - empty_rctx.tx.tot_len = 0; - - usb_hdlr_register(&usbtest_rx, OPENPCD_CMD_CLS_USBTEST); -} diff --git a/openpcd/firmware/src/usb_handler.c b/openpcd/firmware/src/usb_handler.c deleted file mode 100644 index 7a736e8..0000000 --- a/openpcd/firmware/src/usb_handler.c +++ /dev/null @@ -1,86 +0,0 @@ -/* OpenPCD USB handler - handle incoming USB requests on OUT pipe - * (C) 2006 by Harald Welte - */ - -#include -#include -#include - -#include - -#include "pcd_enumerate.h" -#include "usb_handler.h" -#include "openpcd.h" -#include "rc632.h" -#include "led.h" -#include "dbgu.h" - -static usb_cmd_fn *cmd_hdlrs[16]; - -int usb_hdlr_register(usb_cmd_fn *hdlr, u_int8_t class) -{ - cmd_hdlrs[class] = hdlr; -} - -void usb_hdlr_unregister(u_int8_t class) -{ - cmd_hdlrs[class] = NULL; -} - -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]; - usb_cmd_fn *hdlr; - - DEBUGP("usb_in(cls=%d) ", OPENPCD_CMD_CLS(poh->cmd)); - - if (rctx->rx.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"); -} - -/* Process all pending request contexts that want to Tx on either - * IN or INTERRUPT endpoint */ -void usb_out_process(void) -{ - struct req_ctx *rctx; - - while (rctx = req_ctx_find_get(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) - req_ctx_set_state(rctx, RCTX_STATE_UDP_EP3_PENDING); - } - - while (rctx = req_ctx_find_get(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) - req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); - } -} - -/* process incoming USB packets (OUT pipe) that have already been - * put into request contexts by the UDP IRQ handler */ -void usb_in_process(void) -{ - struct req_ctx *rctx; - - while (rctx = req_ctx_find_get(RCTX_STATE_UDP_RCV_DONE, - RCTX_STATE_MAIN_PROCESSING)) { - DEBUGPCRF("found used ctx %u: len=%u", - req_ctx_num(rctx), rctx->rx.tot_len); - usb_in(rctx); - } - udp_unthrottle(); -} - diff --git a/openpcd/firmware/src/usb_handler.h b/openpcd/firmware/src/usb_handler.h deleted file mode 100644 index a281c66..0000000 --- a/openpcd/firmware/src/usb_handler.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _USB_HANDLER_H -#define _USB_HANDLER_H - -#include "openpcd.h" - -#define MAX_PAYLOAD_LEN (64 - sizeof(struct openpcd_hdr)) - -typedef int usb_cmd_fn(struct req_ctx *rctx); - -extern int usb_hdlr_register(usb_cmd_fn *hdlr, u_int8_t class); - -extern void usb_in_process(void); -extern void usb_out_process(void); - -#endif -- cgit v1.2.3