diff options
| -rw-r--r-- | openpcd/firmware.txt | 99 | ||||
| -rw-r--r-- | openpcd/firmware/src/dfu.c | 64 | ||||
| -rw-r--r-- | openpcd/firmware/src/dfu.h | 31 | ||||
| -rw-r--r-- | openpcd/firmware/src/openpcd.h | 30 | ||||
| -rw-r--r-- | openpcd/firmware/src/pcd_enumerate.c | 153 | ||||
| -rw-r--r-- | openpcd/firmware/src/pio_irq.c | 65 | ||||
| -rw-r--r-- | openpcd/firmware/src/pio_irq.h | 9 | ||||
| -rw-r--r-- | openpcd/firmware/src/rc632.c | 21 | ||||
| -rw-r--r-- | openpcd/firmware/src/rc632.h | 11 | ||||
| -rw-r--r-- | openpcd/hardware/RFID-READER_Bm114_1.pdf | bin | 0 -> 1271562 bytes | |||
| -rw-r--r-- | openpcd/hardware/RFID-READER_Bm115_1.pdf | bin | 0 -> 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.pdfBinary files differ new file mode 100644 index 0000000..62affe8 --- /dev/null +++ b/openpcd/hardware/RFID-READER_Bm114_1.pdf diff --git a/openpcd/hardware/RFID-READER_Bm115_1.pdf b/openpcd/hardware/RFID-READER_Bm115_1.pdfBinary files differ new file mode 100644 index 0000000..b2bb3fe --- /dev/null +++ b/openpcd/hardware/RFID-READER_Bm115_1.pdf | 
