summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--openpcd/firmware.txt99
-rw-r--r--openpcd/firmware/src/dfu.c64
-rw-r--r--openpcd/firmware/src/dfu.h31
-rw-r--r--openpcd/firmware/src/openpcd.h30
-rw-r--r--openpcd/firmware/src/pcd_enumerate.c153
-rw-r--r--openpcd/firmware/src/pio_irq.c65
-rw-r--r--openpcd/firmware/src/pio_irq.h9
-rw-r--r--openpcd/firmware/src/rc632.c21
-rw-r--r--openpcd/firmware/src/rc632.h11
-rw-r--r--openpcd/hardware/RFID-READER_Bm114_1.pdfbin0 -> 1271562 bytes
-rw-r--r--openpcd/hardware/RFID-READER_Bm115_1.pdfbin0 -> 1271316 bytes
11 files changed, 326 insertions, 157 deletions
diff --git a/openpcd/firmware.txt b/openpcd/firmware.txt
index f24b48e..b34113c 100644
--- a/openpcd/firmware.txt
+++ b/openpcd/firmware.txt
@@ -27,6 +27,8 @@ provides access to the following primitives:
- Read Register
- Write FIFO
- Read FIFO
+- Write Virtual FIFO
+- Read Virtual FIFO
- Signal Interrupt
Since the FIFO of the RC632 are only 64byte deep, and the USB latency is too
@@ -58,8 +60,105 @@ EP1 bulk in
EP2 bulk out
EP3 interrupt
+
3. USB Protocol
3.1 dumb interface
+TBD
+
+3.2 Intelligent interface
+
+TBD
+
+
+4. Firmware code flow architecture
+
+The general idea is to make the firmware as interrupt-driven as possible.
+Synchronous waiting for I/O (SPI, USB, ...) should be avoided, and restricted
+to slow path operations (such as USB configuration) only.
+
+Another design goal is to avoid using a dynamic memory allocator. Dynamic
+memory allocation can be costly, leads to all sorts of fragmentation problems,
+and will lead to the question of what to do in the case of an OOM situation.
+
+Therefore, all data structures such as buffers will be pre-allocated and
+declared as static variables.
+
+4.x Data structures
+
+Any action of the PCD is host-driven. Therefore, the UDC maintains a set
+(2..32) request context structures. Upon completion of a USB OUT EP DMA,
+the corresponding request context is passed on to other parts of the code.
+Once the reply to that request has been processed, the context structure
+is released.
+
+The context structures are statically allocated, and a single u_int32_t
+represents a bitmask of busy context structures. ffs() or a similar function
+is used to search for a free buffer using which the UDC RX DMA can be refilled.
+
+
+4.1 Examples
+
+4.1.1 Performing SPI Register Read
+
+[ UDC has configured RX dma for reception of usb packets ]
+- UDC issues interrupt that USB endpoint receive has completed (FIFO)
+ - UDC driver defragments multiple packets into one transfer [optional]
+ - UDC driver submits another buffer for DMA reception
+ - UDC driver parses PCD ommand header and calls rc632 API
+ - RC632 driver configures SPI DMA transceive
+ - End of UDC interrupt
+- idle loop
+- SPI DMA completion interrupt happens for TX [do nothing]
+- SPI DMA completion interrupt happens for RX
+ - callback into UDC driver using request state data
+ - UDC driver sends IN packet/transfer back to host
+ - End of SPI DMA interrupt
+
+4.1.2 Performing SPI register read
+
+much like register write, although the deferred completion could be skipped and
+the usb transfer approved immediately after having submitted the SPI write
+request to the RC632
+
+5.1.3 Performing FIFO read
+
+much like register read. Only difference is size and duration of transfer
+
+5.1.4 Performing FIFO write
+
+much like register write. Only difference is size and duration of transfer
+
+5.1.5 Performing virtual FIFO read
+
+much like a FIFO write, but make sure to enable FIFO watermark IRQ in RC632.
+
+5.1.6 Performing virtual FIFO write
+
+much like a FIFO read, but make sure to enable FIFO watermark IRQ in RC632.
+Response to USB host is only sent after the full virtual FIFO has been emptied
+into the physical FIFO.
+
+5.1.6 Reporting RC632 interrupts
+
+Upon reception of a RC632 interrupt, the primary and secondary status registers
+are read from the IRQ handler, and an USB packet on the Interrupt In enddpoint is
+created and submitted for transmission.
+
+Some special handling (filtering) of FIFO over/underrun interrupts has to be
+implemented for transparent handling of the virtual FIFO.
+
+5.1.7 Reporting virtual FIFO interrupts
+
+The virtual FIFO itself can generate over/underrun interrupts on the USB. They
+are signalled pretty much like real RC632 interrupts.
+
+
+6. Interrupt priorities
+
+UDC DMA low priority, since we don't want to overflow with usb packets?
+SPI DMA higher than UDC since it might complete while in UDC code?
+RC632_IRQ high priority, since FIFO refill might be required
+DEBUG_UART do we want it to use IRQ at all? if yes it should have highest prio.
diff --git a/openpcd/firmware/src/dfu.c b/openpcd/firmware/src/dfu.c
new file mode 100644
index 0000000..85f85ee
--- /dev/null
+++ b/openpcd/firmware/src/dfu.c
@@ -0,0 +1,64 @@
+
+/* USB Interface descriptor in Runtime mode */
+struct usb_interface_descriptor desc_if_rt = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0x01,
+ .bAlternateSetting = 0x00,
+ .bNumEndpoints = 0x00,
+ .bInterfaceClass = 0xfe,
+ .bInterfaceSubClass = 0x01,
+ .bInterfaceProtocol = 0x01,
+ .iInterface = FIXME,
+};
+
+/* USB DFU Device descriptor in DFU mode */
+struct usb_device_descriptor desc_dev_dfu = {
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = 0x0100,
+ .bDeviceClass = 0x00,
+ .bDeviceSubClass = 0x00,
+ .bDeviceProtocol = 0x00,
+ .bMaxPacketSize0 = 8,
+ .idVendor = USB_VENDOR,
+ .idProtuct = USB_PRODUCT,
+ .bcdDevice = 0x0000,
+ .iManufacturer = FIXME,
+ .iProduct = FIXME,
+ .iSerialNumber = FIXME,
+ .bNumConfigurations = 0x01,
+};
+
+/* USB DFU Interface descriptor in DFU mode */
+struct usb_interface_descriptor desc_if_dfu = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0x00,
+ .bAlternateSetting = 0x00,
+ .bNumEndpoints = 0x00,
+ .bInterfaceClass = 0xfe,
+ .bInterfaceSubClass = 0x01,
+ .bInterfaceProtocol = 0x02,
+ .iInterface = FIXME,
+};
+
+
+{
+ switch () {
+ case USB_REQ_DFU_DETACH:
+ break;
+ case USB_REQ_DFU_DNLOAD:
+ break;
+ case USB_REQ_DFU_GETSTATUS:
+ break;
+ case USB_REQ_DFU_CLRSTATUS:
+ break;
+ case USB_REQ_DFU_ABORT:
+ break;
+ case USB_REQ_GETSTATE:
+ break;
+ case USB_REQ_DFU_UPLOAD:
+ break;
+ }
+}
diff --git a/openpcd/firmware/src/dfu.h b/openpcd/firmware/src/dfu.h
new file mode 100644
index 0000000..873bc0e
--- /dev/null
+++ b/openpcd/firmware/src/dfu.h
@@ -0,0 +1,31 @@
+#ifndef _USB_DFU_H
+#define _USB_DFU_H
+
+#define USB_DT_DFU 0x21
+
+struct usb_dfu_func_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bmAttributs;
+#define USB_DFU_CAN_DOWNLOAD (1 << 0)
+#define USB_DFU_CAN_UPLOAD (1 << 1)
+#define USB_DFU_MANIFEST_TOL (1 << 2)
+#define USB_DFU_WILL_DETACH (1 << 3)
+ __le16 wDetachTimeOut;
+ __le16 wTransferSize;
+ __le16 bcdDFUVersion;
+} __attribute__ ((packed));
+
+#define USB_DT_DFU_SIZE 9
+
+
+/* DFU class-specific requests (Section 3, DFU Rev 1.1) */
+#define USB_REQ_DFU_DETACH 0x00
+#define USB_REQ_DFU_DNLOAD 0x01
+#define USB_REQ_DFU_UPLOAD 0x02
+#define USB_REQ_DFU_GETSTATUS 0x03
+#define USB_REQ_DFU_CLRSTATUS 0x04
+#define USB_REQ_DFU_GETSTATE 0x05
+#define USB_REQ_DFU_ABORT 0x06
+
+#endif /* _USB_DFU_H
diff --git a/openpcd/firmware/src/openpcd.h b/openpcd/firmware/src/openpcd.h
new file mode 100644
index 0000000..2a293b3
--- /dev/null
+++ b/openpcd/firmware/src/openpcd.h
@@ -0,0 +1,30 @@
+#ifndef _OPENPCD_H
+#define _OPENPCD_H
+
+#define OPENPCD_RC632_IRQ AT91C_PA30_IRQ1
+#define OPENPCD_RC632_RESET AT91C_PIO_PA29
+#define OPENPCD_LED1_GREEN AT91C_PIO_PA25
+#define OPENPCD_LED2_RED AT91C_PIO_PA26
+
+#define MAX_REQSIZE 256
+#define MAX_HDRSIZE 8
+
+#define req_buf_payload(x) (x->data[x->hdr_len])
+#define req_buf_hdr(x) (x->data[0])
+
+struct req_buf {
+ u_int16_t hdr_len;
+ u_int16_t tot_len;
+ u_int8_t data[MAX_REQSIZE+MAX_HDRSIZE];
+};
+
+struct req_ctx {
+ u_int16_t seq; /* request sequence number */
+
+ u_int32_t flags;
+
+ struct req_buf rx;
+ struct req_buf tx;
+};
+
+#endif /* _OPENPCD_H */
diff --git a/openpcd/firmware/src/pcd_enumerate.c b/openpcd/firmware/src/pcd_enumerate.c
index 32bc9bf..f660fda 100644
--- a/openpcd/firmware/src/pcd_enumerate.c
+++ b/openpcd/firmware/src/pcd_enumerate.c
@@ -28,30 +28,6 @@ typedef unsigned int uint;
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#if 0
-const char devDescriptor[] = {
- /* Device descriptor */
- 0x12, // bLength
- 0x01, // bDescriptorType
- 0x10, // bcdUSBL
- 0x01, //
- 0x02, // bDeviceClass: CDC class code
- 0x00, // bDeviceSubclass: CDC class sub code
- 0x00, // bDeviceProtocol: CDC Device protocol
- 0x08, // bMaxPacketSize0
- 0xEB, // idVendorL
- 0x03, //
- 0x24, // idProductL
- 0x61, //
- 0x10, // bcdDeviceL
- 0x01, //
- 0x00, // iManufacturer // 0x01
- 0x00, // iProduct
- 0x00, // SerialNumber
- 0x01 // bNumConfigs
-};
-#endif
-
struct usb_device_descriptor devDescriptor = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
@@ -69,99 +45,6 @@ struct usb_device_descriptor devDescriptor = {
.bNumConfigurations = 0x01,
};
-#if 0
-const char cfgDescriptor[] = {
- /* ============== CONFIGURATION 1 =========== */
- /* Configuration 1 descriptor */
- 0x09, // CbLength
- 0x02, // CbDescriptorType
- 0x43, // CwTotalLength 2 EP + Control
- 0x00,
- 0x02, // CbNumInterfaces
- 0x01, // CbConfigurationValue
- 0x00, // CiConfiguration
- 0xC0, // CbmAttributes 0xA0
- 0x00, // CMaxPower
-
- /* Communication Class Interface Descriptor Requirement */
- 0x09, // bLength
- 0x04, // bDescriptorType
- 0x00, // bInterfaceNumber
- 0x00, // bAlternateSetting
- 0x01, // bNumEndpoints
- 0x02, // bInterfaceClass
- 0x02, // bInterfaceSubclass
- 0x00, // bInterfaceProtocol
- 0x00, // iInterface
-
- /* Header Functional Descriptor */
- 0x05, // bFunction Length
- 0x24, // bDescriptor type: CS_INTERFACE
- 0x00, // bDescriptor subtype: Header Func Desc
- 0x10, // bcdCDC:1.1
- 0x01,
-
- /* ACM Functional Descriptor */
- 0x04, // bFunctionLength
- 0x24, // bDescriptor Type: CS_INTERFACE
- 0x02, // bDescriptor Subtype: ACM Func Desc
- 0x00, // bmCapabilities
-
- /* Union Functional Descriptor */
- 0x05, // bFunctionLength
- 0x24, // bDescriptorType: CS_INTERFACE
- 0x06, // bDescriptor Subtype: Union Func Desc
- 0x00, // bMasterInterface: Communication Class Interface
- 0x01, // bSlaveInterface0: Data Class Interface
-
- /* Call Management Functional Descriptor */
- 0x05, // bFunctionLength
- 0x24, // bDescriptor Type: CS_INTERFACE
- 0x01, // bDescriptor Subtype: Call Management Func Desc
- 0x00, // bmCapabilities: D1 + D0
- 0x01, // bDataInterface: Data Class Interface 1
-
- /* Endpoint 1 descriptor */
- 0x07, // bLength
- 0x05, // bDescriptorType
- 0x83, // bEndpointAddress, Endpoint 03 - IN
- 0x03, // bmAttributes INT
- 0x08, // wMaxPacketSize
- 0x00,
- 0xFF, // bInterval
-
- /* Data Class Interface Descriptor Requirement */
- 0x09, // bLength
- 0x04, // bDescriptorType
- 0x01, // bInterfaceNumber
- 0x00, // bAlternateSetting
- 0x02, // bNumEndpoints
- 0x0A, // bInterfaceClass
- 0x00, // bInterfaceSubclass
- 0x00, // bInterfaceProtocol
- 0x00, // iInterface
-
- /* First alternate setting */
- /* Endpoint 1 descriptor */
- 0x07, // bLength
- 0x05, // bDescriptorType
- 0x01, // bEndpointAddress, Endpoint 01 - OUT
- 0x02, // bmAttributes BULK
- AT91C_EP_OUT_SIZE, // wMaxPacketSize
- 0x00,
- 0x00, // bInterval
-
- /* Endpoint 2 descriptor */
- 0x07, // bLength
- 0x05, // bDescriptorType
- 0x82, // bEndpointAddress, Endpoint 02 - IN
- 0x02, // bmAttributes BULK
- AT91C_EP_IN_SIZE, // wMaxPacketSize
- 0x00,
- 0x00 // bInterval
-};
-#endif
-
struct _desc {
struct usb_config_descriptor ucfg;
struct usb_interface_descriptor uif
@@ -239,25 +122,6 @@ const struct _desc cfgDescriptor = {
#define STD_SET_INTERFACE 0x0B01
#define STD_SYNCH_FRAME 0x0C82
-/* CDC Class Specific Request Code */
-#define GET_LINE_CODING 0x21A1
-#define SET_LINE_CODING 0x2021
-#define SET_CONTROL_LINE_STATE 0x2221
-
-typedef struct {
- unsigned int dwDTERRate;
- char bCharFormat;
- char bParityType;
- char bDataBits;
-} AT91S_CDC_LINE_CODING, *AT91PS_CDC_LINE_CODING;
-
-AT91S_CDC_LINE_CODING line = {
- 115200, // baudrate
- 0, // 1 Stop Bit
- 0, // None Parity
- 8
-}; // 8 Data bits
-
/// mt uint currentReceiveBank = AT91C_UDP_RX_DATA_BK0;
static uchar AT91F_UDP_IsConfigured(AT91PS_CDC pCdc);
@@ -575,23 +439,6 @@ static void AT91F_CDC_Enumerate(AT91PS_CDC pCdc)
} else
AT91F_USB_SendStall(pUDP);
break;
-
-#if 0
- // handle CDC class requests
- case SET_LINE_CODING:
- while (!(pUDP->UDP_CSR[0] & AT91C_UDP_RX_DATA_BK0)) ;
- pUDP->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0);
- AT91F_USB_SendZlp(pUDP);
- break;
- case GET_LINE_CODING:
- AT91F_USB_SendData(pUDP, (char *)&line,
- MIN(sizeof(line), wLength));
- break;
- case SET_CONTROL_LINE_STATE:
- pCdc->currentConnection = wValue;
- AT91F_USB_SendZlp(pUDP);
- break;
-#endif
default:
AT91F_USB_SendStall(pUDP);
break;
diff --git a/openpcd/firmware/src/pio_irq.c b/openpcd/firmware/src/pio_irq.c
new file mode 100644
index 0000000..3f73001
--- /dev/null
+++ b/openpcd/firmware/src/pio_irq.c
@@ -0,0 +1,65 @@
+
+#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
new file mode 100644
index 0000000..a71ed75
--- /dev/null
+++ b/openpcd/firmware/src/pio_irq.h
@@ -0,0 +1,9 @@
+
+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);
diff --git a/openpcd/firmware/src/rc632.c b/openpcd/firmware/src/rc632.c
index 9ff1890..6c83182 100644
--- a/openpcd/firmware/src/rc632.c
+++ b/openpcd/firmware/src/rc632.c
@@ -3,9 +3,15 @@
*
* */
+#include "pio_irq.h"
+
static void spi_irq(void)
{
+ u_int32_t status = pSPI->SPI_SR;
+ if (status & (AT91C_SPI_OVRES|AT91C_SPI_MODF)) {
+ /* FIXME: print error message to debug port */
+ }
}
static u_int8_t spi_outbuf[64+1];
@@ -65,7 +71,7 @@ u_int8_t rc632_read_fifo(u_int8_t max_len, u_int8_t *data)
/* RC632 interrupt handling */
-void rc632_irq(void)
+static void rc632_irq(void)
{
/* CL RC632 has interrupted us */
u_int8_t cause = rc632_read_reg(RC632_REG_INTERRUPT_RQ);
@@ -95,15 +101,22 @@ void rc632_init(void)
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SPI, F,
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);
AT91F_SPI_CfgMode(AT91C_SPI_MSTR|AT91C_SPI_PS_FIXED);
- /* CPOL = 0, NCPHA = 1, CSAAT = 0, BITS = 0000, SCBR = 10,
+ /* CPOL = 0, NCPHA = 1, CSAAT = 0, BITS = 0000, SCBR = 10 (4.8MHz),
* DLYBS = 0, DLYBCT = 0 */
AT91F_SPI_CfgCs(pSPI, 0, AT91C_SPI_BITS8|AT91C_SPI_NCPHA|(10<<8));
-
AT91F_SPI_Reset();
+
+ /* Register rc632_irq */
+ pio_irq_register(OPENPCD_RC632_IRQ, &rc632_irq);
+ pio_irq_enable(OPENPCD_RC632_IRQ);
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_RC632_RESET);
};
void rc632_exit(void)
{
-
+ pio_irq_unregister(OPENPCD_RC632_IRQ);
+ AT91F_AIC_DisableIt(AT91C_BASE_AIC, AT91C_ID_SPI);
+ AT01F_SPI_Disable();
}
diff --git a/openpcd/firmware/src/rc632.h b/openpcd/firmware/src/rc632.h
new file mode 100644
index 0000000..281e757
--- /dev/null
+++ b/openpcd/firmware/src/rc632.h
@@ -0,0 +1,11 @@
+#ifndef _RC623_API_H
+#define _RC632_API_H
+
+extern void rc632_write_reg(u_int8_t addr, u_int8_t data);
+extern void rc632_write_fifo(u_int8_t len, u_int8_t *data);
+extern u_int8_t rc632_read_reg(u_int8_t addr);
+extern u_int8_t rc632_read_fifo(u_int8_t max_len, u_int8_t *data);
+extern void rc632_init(void);
+extern void rc632_exit(void);
+
+#endif
diff --git a/openpcd/hardware/RFID-READER_Bm114_1.pdf b/openpcd/hardware/RFID-READER_Bm114_1.pdf
new file mode 100644
index 0000000..62affe8
--- /dev/null
+++ b/openpcd/hardware/RFID-READER_Bm114_1.pdf
Binary files differ
diff --git a/openpcd/hardware/RFID-READER_Bm115_1.pdf b/openpcd/hardware/RFID-READER_Bm115_1.pdf
new file mode 100644
index 0000000..b2bb3fe
--- /dev/null
+++ b/openpcd/hardware/RFID-READER_Bm115_1.pdf
Binary files differ
personal git repositories of Harald Welte. Your mileage may vary