aboutsummaryrefslogtreecommitdiff
path: root/contrib/firmware/angie/c/src/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/firmware/angie/c/src/usb.c')
-rw-r--r--contrib/firmware/angie/c/src/usb.c784
1 files changed, 784 insertions, 0 deletions
diff --git a/contrib/firmware/angie/c/src/usb.c b/contrib/firmware/angie/c/src/usb.c
new file mode 100644
index 0000000..8fd4de6
--- /dev/null
+++ b/contrib/firmware/angie/c/src/usb.c
@@ -0,0 +1,784 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/****************************************************************************
+ File : usb.c *
+ Contents : usb communication handling code for NanoXplore USB-JTAG *
+ ANGIE adapter hardware. *
+ Based on openULINK project code by: Martin Schmoelzer. *
+ Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. *
+ <aboudjelida@nanoxplore.com> *
+ <ahmederrachedbjld@gmail.com> *
+*****************************************************************************/
+
+#include "usb.h"
+#include "stdint.h"
+#include "delay.h"
+#include "io.h"
+#include "reg_ezusb.h"
+#include <fx2macros.h>
+#include <serial.h>
+#include <stdio.h>
+
+/* Also update external declarations in "include/usb.h" if making changes to
+ * these variables!
+ */
+volatile bool ep1_out;
+volatile bool ep1_in;
+
+volatile __xdata __at 0xE6B8 struct setup_data setup_data;
+
+/* Define number of endpoints (except Control Endpoint 0) in a central place.
+ * Be sure to include the necessary endpoint descriptors!
+ */
+#define NUM_ENDPOINTS 3
+
+__code struct usb_device_descriptor device_descriptor = {
+ .blength = sizeof(struct usb_device_descriptor),
+ .bdescriptortype = DESCRIPTOR_TYPE_DEVICE,
+ .bcdusb = 0x0200, /* BCD: 02.00 (Version 2.0 USB spec) */
+ .bdeviceclass = 0xFF, /* 0xFF = vendor-specific */
+ .bdevicesubclass = 0xFF,
+ .bdeviceprotocol = 0xFF,
+ .bmaxpacketsize0 = 64,
+ .idvendor = 0x584e,
+ .idproduct = 0x424e,
+ .bcddevice = 0x0000,
+ .imanufacturer = 1,
+ .iproduct = 2,
+ .iserialnumber = 3,
+ .bnumconfigurations = 1
+};
+
+/* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */
+
+__code struct usb_config_descriptor config_descriptor = {
+ .blength = sizeof(struct usb_config_descriptor),
+ .bdescriptortype = DESCRIPTOR_TYPE_CONFIGURATION,
+ .wtotallength = sizeof(struct usb_config_descriptor) +
+ sizeof(struct usb_interface_descriptor) +
+ (NUM_ENDPOINTS * sizeof(struct usb_endpoint_descriptor)),
+ .bnuminterfaces = 1,
+ .bconfigurationvalue = 1,
+ .iconfiguration = 4, /* String describing this configuration */
+ .bmattributes = 0x80, /* Only MSB set according to USB spec */
+ .maxpower = 50 /* 100 mA */
+};
+
+__code struct usb_interface_descriptor interface_descriptor00 = {
+ .blength = sizeof(struct usb_interface_descriptor),
+ .bdescriptortype = DESCRIPTOR_TYPE_INTERFACE,
+ .binterfacenumber = 0,
+ .balternatesetting = 0,
+ .bnumendpoints = NUM_ENDPOINTS,
+ .binterfaceclass = 0xFF,
+ .binterfacesubclass = 0xFF,
+ .binterfaceprotocol = 0xFF,
+ .iinterface = 0
+};
+
+__code struct usb_endpoint_descriptor bulk_ep1_out_endpoint_descriptor = {
+ .blength = sizeof(struct usb_endpoint_descriptor),
+ .bdescriptortype = 0x05,
+ .bendpointaddress = (1 | USB_DIR_OUT),
+ .bmattributes = 0x02,
+ .wmaxpacketsize = 64,
+ .binterval = 0
+};
+
+__code struct usb_endpoint_descriptor bulk_ep1_in_endpoint_descriptor = {
+ .blength = sizeof(struct usb_endpoint_descriptor),
+ .bdescriptortype = 0x05,
+ .bendpointaddress = (1 | USB_DIR_IN),
+ .bmattributes = 0x02,
+ .wmaxpacketsize = 64,
+ .binterval = 0
+};
+
+__code struct usb_endpoint_descriptor bulk_ep2_endpoint_descriptor = {
+ .blength = sizeof(struct usb_endpoint_descriptor),
+ .bdescriptortype = 0x05,
+ .bendpointaddress = (2 | USB_DIR_OUT),
+ .bmattributes = 0x02,
+ .wmaxpacketsize = 512,
+ .binterval = 0
+};
+
+__code struct usb_endpoint_descriptor bulk_ep4_endpoint_descriptor = {
+ .blength = sizeof(struct usb_endpoint_descriptor),
+ .bdescriptortype = 0x05,
+ .bendpointaddress = (4 | USB_DIR_IN),
+ .bmattributes = 0x02,
+ .wmaxpacketsize = 512,
+ .binterval = 0
+};
+
+__code struct usb_endpoint_descriptor bulk_ep6_endpoint_descriptor = {
+ .blength = sizeof(struct usb_endpoint_descriptor),
+ .bdescriptortype = 0x05,
+ .bendpointaddress = (6 | USB_DIR_OUT),
+ .bmattributes = 0x02,
+ .wmaxpacketsize = 512,
+ .binterval = 0
+};
+
+__code struct usb_endpoint_descriptor bulk_ep8_endpoint_descriptor = {
+ .blength = sizeof(struct usb_endpoint_descriptor),
+ .bdescriptortype = 0x05,
+ .bendpointaddress = (8 | USB_DIR_OUT),
+ .bmattributes = 0x02,
+ .wmaxpacketsize = 512,
+ .binterval = 0
+};
+
+__code struct usb_language_descriptor language_descriptor = {
+ .blength = 4,
+ .bdescriptortype = DESCRIPTOR_TYPE_STRING,
+ .wlangid = {0x0409 /* US English */}
+};
+
+__code struct usb_string_descriptor strmanufacturer =
+ STR_DESCR(16, 'N', 'a', 'n', 'o', 'X', 'p', 'l', 'o', 'r', 'e', ',', ' ', 'S', 'A', 'S', '.');
+
+__code struct usb_string_descriptor strproduct =
+ STR_DESCR(13, 'A', 'N', 'G', 'I', 'E', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r');
+
+__code struct usb_string_descriptor strserialnumber =
+ STR_DESCR(6, '0', '0', '0', '0', '0', '1');
+
+__code struct usb_string_descriptor strconfigdescr =
+ STR_DESCR(12, 'J', 'T', 'A', 'G', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r');
+
+/* Table containing pointers to string descriptors */
+__code struct usb_string_descriptor *__code en_string_descriptors[4] = {
+ &strmanufacturer,
+ &strproduct,
+ &strserialnumber,
+ &strconfigdescr
+};
+void sudav_isr(void)__interrupt SUDAV_ISR
+{
+ EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */
+ USBIRQ = SUDAVI;
+ EP0CS |= HSNAK;
+ usb_handle_setup_data();
+}
+void sof_isr(void)__interrupt SOF_ISR
+{
+}
+void sutok_isr(void)__interrupt SUTOK_ISR
+{
+}
+void suspend_isr(void)__interrupt SUSPEND_ISR
+{
+}
+void usbreset_isr(void)__interrupt USBRESET_ISR
+{
+}
+void highspeed_isr(void)__interrupt HIGHSPEED_ISR
+{
+}
+void ep0ack_isr(void)__interrupt EP0ACK_ISR
+{
+}
+void stub_isr(void)__interrupt STUB_ISR
+{
+}
+void ep0in_isr(void)__interrupt EP0IN_ISR
+{
+}
+void ep0out_isr(void)__interrupt EP0OUT_ISR
+{
+}
+void ep1in_isr(void)__interrupt EP1IN_ISR
+{
+ ep1_in = true;
+
+ EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */
+ EPIRQ = 0x04; /* Clear individual EP1IN IRQ */
+}
+void ep1out_isr(void)__interrupt EP1OUT_ISR
+{
+ ep1_out = true;
+
+ EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */
+ EPIRQ = 0x08; /* Clear individual EP1OUT IRQ */
+}
+void ep2_isr(void)__interrupt EP2_ISR
+{
+ ep1_out = false; /* Does nothing but required by the compiler */
+}
+void ep4_isr(void)__interrupt EP4_ISR
+{
+}
+void ep6_isr(void)__interrupt EP6_ISR
+{
+}
+void ep8_isr(void)__interrupt EP8_ISR
+{
+}
+void ibn_isr(void)__interrupt IBN_ISR
+{
+}
+void ep0pingnak_isr(void)__interrupt EP0PINGNAK_ISR
+{
+}
+void ep1pingnak_isr(void)__interrupt EP1PINGNAK_ISR
+{
+}
+void ep2pingnak_isr(void)__interrupt EP2PINGNAK_ISR
+{
+}
+void ep4pingnak_isr(void)__interrupt EP4PINGNAK_ISR
+{
+}
+void ep6pingnak_isr(void)__interrupt EP6PINGNAK_ISR
+{
+}
+void ep8pingnak_isr(void)__interrupt EP8PINGNAK_ISR
+{
+}
+void errorlimit_isr(void)__interrupt ERRORLIMIT_ISR
+{
+}
+void ep2piderror_isr(void)__interrupt EP2PIDERROR_ISR
+{
+}
+void ep4piderror_isr(void)__interrupt EP4PIDERROR_ISR
+{
+}
+void ep6piderror_isr(void)__interrupt EP6PIDERROR_ISR
+{
+}
+void ep8piderror_isr(void)__interrupt EP8PIDERROR_ISR
+{
+}
+void ep2pflag_isr(void)__interrupt EP2PFLAG_ISR
+{
+}
+void ep4pflag_isr(void)__interrupt EP4PFLAG_ISR
+{
+}
+void ep6pflag_isr(void)__interrupt EP6PFLAG_ISR
+{
+}
+void ep8pflag_isr(void)__interrupt EP8PFLAG_ISR
+{
+}
+void ep2eflag_isr(void)__interrupt EP2EFLAG_ISR
+{
+}
+void ep4eflag_isr(void)__interrupt EP4EFLAG_ISR
+{
+}
+void ep6eflag_isr(void)__interrupt EP6EFLAG_ISR
+{
+}
+void ep8eflag_isr(void)__interrupt EP8EFLAG_ISR
+{
+}
+void ep2fflag_isr(void)__interrupt EP2FFLAG_ISR
+{
+}
+void ep4fflag_isr(void)__interrupt EP4FFLAG_ISR
+{
+}
+void ep6fflag_isr(void)__interrupt EP6FFLAG_ISR
+{
+}
+void ep8fflag_isr(void)__interrupt EP8FFLAG_ISR
+{
+}
+void gpifcomplete_isr(void)__interrupt GPIFCOMPLETE_ISR
+{
+}
+void gpifwaveform_isr(void)__interrupt GPIFWAVEFORM_ISR
+{
+}
+
+/**
+ * Return the control/status register for an endpoint
+ *
+ * @param ep endpoint address
+ * @return on success: pointer to Control & Status register for endpoint
+ * specified in \a ep
+ * @return on failure: NULL
+ */
+__xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep)
+{
+ /* Mask direction bit */
+ uint8_t ep_num = ep & ~0x80;
+
+ switch (ep_num) {
+ case 0:
+ return &EP0CS;
+ case 1:
+ return ep & 0x80 ? &EP1INCS : &EP1OUTCS;
+ case 2:
+ return &EP2CS;
+ case 4:
+ return &EP4CS;
+ case 6:
+ return &EP6CS;
+ case 8:
+ return &EP8CS;
+ default:
+ return NULL;
+ }
+}
+
+void usb_reset_data_toggle(uint8_t ep)
+{
+ /* TOGCTL register:
+ +----+-----+-----+------+-----+-------+-------+-------+
+ | Q | S | R | IO | EP3 | EP2 | EP1 | EP0 |
+ +----+-----+-----+------+-----+-------+-------+-------+
+
+ To reset data toggle bits, we have to write the endpoint direction (IN/OUT)
+ to the IO bit and the endpoint number to the EP2..EP0 bits. Then, in a
+ separate write cycle, the R bit needs to be set.
+ */
+ TOGCTL = (((ep & 0x80) >> 3) + (ep & 0x0F));
+ TOGCTL |= BMRESETTOGGLE;
+}
+
+/**
+ * Handle GET_STATUS request.
+ *
+ * @return on success: true
+ * @return on failure: false
+ */
+bool usb_handle_get_status(void)
+{
+ uint8_t *ep_cs;
+ switch (setup_data.bmrequesttype) {
+ case GS_DEVICE:
+ /* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup.
+ * Byte 1: reserved, reset to zero */
+ EP0BUF[0] = 0;
+ EP0BUF[1] = 0;
+
+ /* Send response */
+ EP0BCH = 0;
+ syncdelay(3);
+ EP0BCL = 2;
+ syncdelay(3);
+ break;
+ case GS_INTERFACE:
+ /* Always return two zero bytes according to USB 1.1 spec, p. 191 */
+ EP0BUF[0] = 0;
+ EP0BUF[1] = 0;
+
+ /* Send response */
+ EP0BCH = 0;
+ syncdelay(3);
+ EP0BCL = 2;
+ syncdelay(3);
+ break;
+ case GS_ENDPOINT:
+ /* Get stall bit for endpoint specified in low byte of wIndex */
+ ep_cs = usb_get_endpoint_cs_reg(setup_data.windex & 0xff);
+
+ if (*ep_cs & EPSTALL)
+ EP0BUF[0] = 0x01;
+ else
+ EP0BUF[0] = 0x00;
+
+ /* Second byte sent has to be always zero */
+ EP0BUF[1] = 0;
+
+ /* Send response */
+ EP0BCH = 0;
+ syncdelay(3);
+ EP0BCL = 2;
+ syncdelay(3);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Handle CLEAR_FEATURE request.
+ *
+ * @return on success: true
+ * @return on failure: false
+ */
+bool usb_handle_clear_feature(void)
+{
+ __xdata uint8_t *ep_cs;
+
+ switch (setup_data.bmrequesttype) {
+ case CF_DEVICE:
+ /* Clear remote wakeup not supported: stall EP0 */
+ STALL_EP0();
+ break;
+ case CF_ENDPOINT:
+ if (setup_data.wvalue == 0) {
+ /* Unstall the endpoint specified in wIndex */
+ ep_cs = usb_get_endpoint_cs_reg(setup_data.windex);
+ if (!ep_cs)
+ return false;
+ *ep_cs &= ~EPSTALL;
+ } else {
+ /* Unsupported feature, stall EP0 */
+ STALL_EP0();
+ }
+ break;
+ default:
+ /* Vendor commands... */
+ break;
+ }
+ return true;
+}
+
+/**
+ * Handle SET_FEATURE request.
+ *
+ * @return on success: true
+ * @return on failure: false
+ */
+bool usb_handle_set_feature(void)
+{
+ __xdata uint8_t *ep_cs;
+
+ switch (setup_data.bmrequesttype) {
+ case SF_DEVICE:
+ if (setup_data.wvalue == 2)
+ return true;
+ break;
+ case SF_ENDPOINT:
+ if (setup_data.wvalue == 0) {
+ /* Stall the endpoint specified in wIndex */
+ ep_cs = usb_get_endpoint_cs_reg(setup_data.windex);
+ if (!ep_cs)
+ return false;
+ *ep_cs |= EPSTALL;
+ } else {
+ /* Unsupported endpoint feature */
+ return false;
+ }
+ break;
+ default:
+ /* Vendor commands... */
+ break;
+ }
+
+ return true;
+}
+
+/**
+ * Handle GET_DESCRIPTOR request.
+ *
+ * @return on success: true
+ * @return on failure: false
+ */
+bool usb_handle_get_descriptor(void)
+{
+ __xdata uint8_t descriptor_type;
+ __xdata uint8_t descriptor_index;
+
+ descriptor_type = (setup_data.wvalue & 0xff00) >> 8;
+ descriptor_index = setup_data.wvalue & 0x00ff;
+
+ switch (descriptor_type) {
+ case DESCRIPTOR_TYPE_DEVICE:
+ SUDPTRH = HI8(&device_descriptor);
+ SUDPTRL = LO8(&device_descriptor);
+ break;
+ case DESCRIPTOR_TYPE_CONFIGURATION:
+ SUDPTRH = HI8(&config_descriptor);
+ SUDPTRL = LO8(&config_descriptor);
+ break;
+ case DESCRIPTOR_TYPE_STRING:
+ if (setup_data.windex == 0) {
+ /* Supply language descriptor */
+ SUDPTRH = HI8(&language_descriptor);
+ SUDPTRL = LO8(&language_descriptor);
+ } else if (setup_data.windex == 0x0409 /* US English */) {
+ /* Supply string descriptor */
+ SUDPTRH = HI8(en_string_descriptors[descriptor_index - 1]);
+ SUDPTRL = LO8(en_string_descriptors[descriptor_index - 1]);
+ } else {
+ return false;
+ }
+ break;
+ default:
+ /* Unsupported descriptor type */
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Handle SET_INTERFACE request.
+ */
+void usb_handle_set_interface(void)
+{
+ /* Reset Data Toggle */
+ usb_reset_data_toggle(USB_DIR_IN | 4);
+ usb_reset_data_toggle(USB_DIR_OUT | 2);
+
+ /* Unstall & clear busy flag of all valid IN endpoints */
+ EP1INCS = 0 | EPBSY;
+
+ /* Unstall all valid OUT endpoints, reset bytecounts */
+ EP1OUTCS = 0;
+ EP1OUTBC = 0;
+ syncdelay(3);
+}
+
+/* Initialize GPIF interface transfer count */
+void set_gpif_cnt(uint32_t count)
+{
+ GPIFTCB3 = (uint8_t)(((uint32_t)(count) >> 24) & 0x000000ff);
+ syncdelay(3);
+ GPIFTCB2 = (uint8_t)(((uint32_t)(count) >> 16) & 0x000000ff);
+ syncdelay(3);
+ GPIFTCB1 = (uint8_t)(((uint32_t)(count) >> 8) & 0x000000ff);
+ syncdelay(3);
+ GPIFTCB0 = (uint8_t)((uint32_t)(count) & 0x000000ff);
+}
+
+/*
+ * Vendor commands handling:
+*/
+#define VR_CFGOPEN 0xB0
+#define VR_CFGCLOSE 0xB1
+
+uint8_t ix;
+uint8_t bcnt;
+uint8_t __xdata *eptr;
+uint16_t wcnt;
+uint32_t __xdata gcnt;
+bool usb_handle_send_bitstream(void)
+{
+ eptr = EP0BUF; /* points to EP0BUF 64-byte register */
+ wcnt = setup_data.wlength; /* total transfer count */
+
+ /* Clear EP0BUF for OUT requests */
+ if (setup_data.bmrequesttype & 0x80) {
+ bcnt = ((wcnt > 64) ? 64 : wcnt);
+ for (ix = 0; ix < bcnt; ix++)
+ eptr[ix] = 0;
+ }
+
+ switch (setup_data.brequest) {
+ case VR_CFGOPEN:
+ /* Clear bytecount / to allow new data in / to stops NAKing */
+ EP0BCH = 0;
+ EP0BCL = 0;
+ while (EP0CS & EPBSY)
+ ; /* wait to finish transferring in EP0BUF, until not busy */
+ gcnt = ((uint32_t)(eptr[0]) << 24) | ((uint32_t)(eptr[1]) << 16)
+ | ((uint32_t)(eptr[2]) << 8) | (uint32_t)(eptr[3]);
+ /* Angie board FPGA bitstream download */
+ switch ((setup_data.wvalue) & 0x00C0) {
+ case 0x00:
+ PIN_PROGRAM_B = 0; /* Apply RPGM- pulse */
+ GPIFWFSELECT = 0xF2; /* Restore Config mode waveforms select */
+ syncdelay(3);
+ EP2FIFOCFG = BMAUTOOUT; /* and Automatic 8-bit GPIF OUT mode */
+ syncdelay(3);
+ PIN_PROGRAM_B = 1; /* Negate RPGM- pulse */
+ delay_ms(10); /* FPGA init time < 10mS */
+ set_gpif_cnt(gcnt); /* Initialize GPIF interface transfer count */
+ PIN_RDWR_B = 0;
+ PIN_CSI_B = 0;
+ GPIFTRIG = GPIF_EP2; /* Trigger GPIF OUT transfer on EP2 */
+ syncdelay(3);
+ break;
+ default:
+ break;
+ }
+ break;
+ case VR_CFGCLOSE:
+ ix = 10;
+ /* wait until GPIF transaction has been completed */
+ while ((GPIFTRIG & BMGPIFDONE) == 0) {
+ if (ix-- == 0) {
+ printf("GPIF done time out\n");
+ break;
+ }
+ delay_ms(1);
+ }
+ switch ((setup_data.wvalue) & 0x00C0) {
+ case 0x00:
+ PIN_CSI_B = 1;
+ PIN_RDWR_B = 1;
+ IFCONFIG &= 0xFC; /* Exit gpif mode */
+ break;
+ default:
+ break;
+ }
+ EP0BCH = 0;
+ EP0BCL = (uint8_t)(setup_data.wlength); /* Signal buffer is filled */
+ break;
+ default:
+ return true; /* Error: unknown VR command */
+ }
+ return false; /* no error; command handled OK */
+}
+
+/**
+ * Handle the arrival of a USB Control Setup Packet.
+ */
+void usb_handle_setup_data(void)
+{
+ switch (setup_data.brequest) {
+ case GET_STATUS:
+ if (!usb_handle_get_status())
+ STALL_EP0();
+ break;
+ case CLEAR_FEATURE:
+ if (!usb_handle_clear_feature())
+ STALL_EP0();
+ break;
+ case 2: case 4:
+ /* Reserved values */
+ STALL_EP0();
+ break;
+ case SET_FEATURE:
+ if (!usb_handle_set_feature())
+ STALL_EP0();
+ break;
+ case SET_ADDRESS:
+ /* Handled by USB core */
+ break;
+ case SET_DESCRIPTOR:
+ /* Set Descriptor not supported. */
+ STALL_EP0();
+ break;
+ case GET_DESCRIPTOR:
+ if (!usb_handle_get_descriptor())
+ STALL_EP0();
+ break;
+ case GET_CONFIGURATION:
+ /* ANGIE has only one configuration, return its index */
+ EP0BUF[0] = config_descriptor.bconfigurationvalue;
+ EP0BCH = 0;
+ EP0BCL = 1;
+ syncdelay(3);
+ break;
+ case SET_CONFIGURATION:
+ /* ANGIE has only one configuration -> nothing to do */
+ break;
+ case GET_INTERFACE:
+ /* ANGIE only has one interface, return its number */
+ EP0BUF[0] = interface_descriptor00.binterfacenumber;
+ EP0BCH = 0;
+ EP0BCL = 1;
+ syncdelay(3);
+ break;
+ case SET_INTERFACE:
+ usb_handle_set_interface();
+ break;
+ case SYNCH_FRAME:
+ /* Isochronous endpoints not used -> nothing to do */
+ break;
+ default:
+ /* if not Vendor command, Stall EndPoint 0 */
+ if (usb_handle_send_bitstream())
+ STALL_EP0();
+ break;
+ }
+}
+
+/**
+ * Handle the initialization of endpoints.
+ */
+void ep_init(void)
+{
+ EP1INCFG = 0xA0;
+ syncdelay(3);
+ EP1OUTCFG = 0xA0;
+ syncdelay(3);
+ EP2CFG = 0xA0;
+ syncdelay(3);
+ EP4CFG = 0x00;
+ syncdelay(3);
+ EP6CFG = 0x00;
+ syncdelay(3);
+ EP8CFG = 0x00;
+ syncdelay(3);
+
+ /* arm EP1-OUT */
+ EP1OUTBC = 0;
+ syncdelay(3);
+ EP1OUTBC = 0;
+ syncdelay(3);
+
+ /* arm EP1-IN */
+ EP1INBC = 0;
+ syncdelay(3);
+ EP1INBC = 0;
+ syncdelay(3);
+
+ /* Standard procedure to reset FIFOs */
+ FIFORESET = BMNAKALL; /* NAK all transfers during the reset */
+ syncdelay(3);
+ FIFORESET = 0x02; /* reset EP2 FIFO */
+ syncdelay(3);
+ FIFORESET = 0x00; /* deactivate the NAK all */
+ syncdelay(3);
+ EP2FIFOCFG = 0x00;
+ syncdelay(3);
+ EP2FIFOCFG = BMAUTOOUT; /* Automatic 8-bit GPIF OUT mode */
+ syncdelay(3);
+}
+
+/**
+ * Interrupt initialization. Configures USB interrupts.
+ */
+void interrupt_init(void)
+{
+ /* Enable Interrupts */
+ EA = 1;
+
+ /* Enable USB interrupt (EIE register) */
+ EUSB = 1;
+ EICON |= 0x20;
+
+ /* Enable INT 2 & 4 Autovectoring */
+ INTSETUP |= (AV2EN | AV4EN);
+
+ /* Enable individual EP1OUT&IN interrupts */
+ EPIE |= 0x0C;
+
+ /* Clear individual USB interrupt IRQ */
+ EPIRQ = 0x0C;
+
+ /* Enable SUDAV interrupt */
+ USBIEN |= SUDAVI;
+
+ /* Clear SUDAV interrupt */
+ USBIRQ = SUDAVI;
+}
+
+/**
+ * Handle the initialization of io ports.
+ */
+void io_init(void)
+{
+ /* PORT A */
+ PORTACFG = 0x01; /* 0: normal ou 1: alternate function (each bit) */
+ OEA = 0xEF; /* all OUT exept INIT_B IN */
+ IOA = 0xFF;
+ PIN_RDWR_B = 1;
+ PIN_CSI_B = 1;
+ PIN_PROGRAM_B = 1;
+
+ /* PORT B */
+ OEB = 0xEF; /* all OUT exept TDO */
+ IOB = 0xFF;
+ PIN_TRST = 1;
+ PIN_TMS = 0;
+ PIN_TCK = 0;
+ PIN_TDI = 0;
+ PIN_SRST = 1;
+
+ /* PORT C */
+ PORTCCFG = 0x00; /* 0: normal ou 1: alternate function (each bit) */
+ OEC = 0xEF;
+ IOC = 0xFF;
+}