895 lines
20 KiB
C
895 lines
20 KiB
C
// 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>
|
|
#include "i2c.h"
|
|
|
|
/* Also update external declarations in "include/usb.h" if making changes to
|
|
* these variables!
|
|
*/
|
|
volatile bool ep1_out;
|
|
volatile bool ep1_in;
|
|
volatile bool ep6_out;
|
|
|
|
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 = 0xEF,
|
|
.bdevicesubclass = 0x02,
|
|
.bdeviceprotocol = 0x01,
|
|
.bmaxpacketsize0 = 64,
|
|
.idvendor = 0x584e,
|
|
.idproduct = 0x414f,
|
|
.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) +
|
|
3 * sizeof(struct usb_interface_descriptor) +
|
|
((NUM_ENDPOINTS + 2) * sizeof(struct usb_endpoint_descriptor)),
|
|
.bnuminterfaces = 2,
|
|
.bconfigurationvalue = 1,
|
|
.iconfiguration = 1, /* 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 = 0x00,
|
|
.binterfaceprotocol = 0x00,
|
|
.iinterface = 4
|
|
};
|
|
|
|
__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_interface_descriptor interface_descriptor01 = {
|
|
.blength = sizeof(struct usb_interface_descriptor),
|
|
.bdescriptortype = DESCRIPTOR_TYPE_INTERFACE,
|
|
.binterfacenumber = 1,
|
|
.balternatesetting = 0,
|
|
.bnumendpoints = 2,
|
|
.binterfaceclass = 0x0A,
|
|
.binterfacesubclass = 0x00,
|
|
.binterfaceprotocol = 0x00,
|
|
.iinterface = 0x00
|
|
};
|
|
|
|
__code struct usb_endpoint_descriptor bulk_ep6_out_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_in_endpoint_descriptor = {
|
|
.blength = sizeof(struct usb_endpoint_descriptor),
|
|
.bdescriptortype = 0x05,
|
|
.bendpointaddress = (8 | USB_DIR_IN),
|
|
.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
|
|
{
|
|
}
|
|
void ep4_isr(void)__interrupt EP4_ISR
|
|
{
|
|
}
|
|
void ep6_isr(void)__interrupt EP6_ISR
|
|
{
|
|
ep6_out = true;
|
|
EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */
|
|
EPIRQ = 0x40; /* Clear individual EP6OUT IRQ */
|
|
|
|
}
|
|
void ep8_isr(void)__interrupt EP8_ISR
|
|
{
|
|
EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */
|
|
EPIRQ = 0x80; /* Clear individual EP8IN IRQ */
|
|
}
|
|
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) {
|
|
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 = 0xA2;
|
|
syncdelay(3);
|
|
EP8CFG = 0xE2;
|
|
syncdelay(3);
|
|
|
|
/* arm EP1-OUT */
|
|
EP1OUTBC = 0;
|
|
syncdelay(3);
|
|
EP1OUTBC = 0;
|
|
syncdelay(3);
|
|
|
|
/* arm EP1-IN */
|
|
EP1INBC = 0;
|
|
syncdelay(3);
|
|
EP1INBC = 0;
|
|
syncdelay(3);
|
|
|
|
/* arm EP6-OUT */
|
|
EP6BCL = 0x80;
|
|
syncdelay(3);
|
|
EP6BCL = 0x80;
|
|
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);
|
|
}
|
|
|
|
void i2c_recieve(void)
|
|
{
|
|
PIN_SDA_DIR = 0;
|
|
if (EP6FIFOBUF[0] == 1) {
|
|
uint8_t rdwr = EP6FIFOBUF[0]; //read
|
|
uint8_t data_count = EP6FIFOBUF[1]; //data sent count
|
|
uint8_t count = EP6FIFOBUF[2]; //requested data count
|
|
uint8_t adr = EP6FIFOBUF[3]; //address
|
|
uint8_t address = get_address(adr, rdwr); //address byte (read command)
|
|
uint8_t address_2 = get_address(adr, 0); //address byte 2 (write command)
|
|
|
|
printf("%d\n", address - 1);
|
|
|
|
/* start: */
|
|
start_cd();
|
|
/* address: */
|
|
send_byte(address_2); //write
|
|
/* ack: */
|
|
uint8_t ack = get_ack();
|
|
|
|
/* send data */
|
|
if (data_count) { //if there is a byte reg
|
|
for (uint8_t i = 0; i < data_count; i++) {
|
|
send_byte(EP6FIFOBUF[i + 4]);
|
|
/* ack(): */
|
|
ack = get_ack();
|
|
}
|
|
}
|
|
|
|
/* repeated start: */
|
|
repeated_start();
|
|
/* address: */
|
|
send_byte(address);
|
|
/* get ack: */
|
|
ack = get_ack();
|
|
|
|
/* receive data */
|
|
for (uint8_t i = 0; i < count - 1; i++) {
|
|
EP8FIFOBUF[i] = receive_byte();
|
|
|
|
/* send ack: */
|
|
send_ack();
|
|
}
|
|
|
|
EP8FIFOBUF[count - 1] = receive_byte();
|
|
|
|
/* send Nack: */
|
|
send_nack();
|
|
|
|
/* stop */
|
|
stop_cd();
|
|
|
|
EP8BCH = 0; //EP8
|
|
syncdelay(3);
|
|
EP8BCL = count; //EP8
|
|
|
|
EP6BCL = 0x80; //EP6
|
|
syncdelay(3);
|
|
EP6BCL = 0x80; //EP6
|
|
} else {
|
|
uint8_t rdwr = EP6FIFOBUF[0]; //write
|
|
uint8_t count = EP6FIFOBUF[1]; //data count
|
|
uint8_t adr = EP6FIFOBUF[2]; //address
|
|
uint8_t address = get_address(adr, rdwr); //address byte (read command)
|
|
uint8_t ack_cnt = 0;
|
|
|
|
/* start(): */
|
|
start_cd();
|
|
/* address: */
|
|
send_byte(address); //write
|
|
/* ack(): */
|
|
if (!get_ack())
|
|
ack_cnt++;
|
|
/* send data */
|
|
for (uint8_t i = 0; i < count; i++) {
|
|
send_byte(EP6FIFOBUF[i + 3]);
|
|
|
|
/* get ack: */
|
|
if (!get_ack())
|
|
ack_cnt++;
|
|
}
|
|
|
|
/* stop */
|
|
stop_cd();
|
|
|
|
EP8FIFOBUF[0] = ack_cnt;
|
|
|
|
EP8BCH = 0; //EP8
|
|
syncdelay(3);
|
|
EP8BCL = 1; //EP8
|
|
|
|
EP6BCL = 0x80; //EP6
|
|
syncdelay(3);
|
|
EP6BCL = 0x80; //EP6
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 & EP6&8 interrupts */
|
|
EPIE |= 0xCC;
|
|
|
|
/* Clear individual USB interrupt IRQ */
|
|
EPIRQ = 0xCC;
|
|
|
|
/* 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;
|
|
|
|
/* 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 = 0xFF;
|
|
IOC = 0xFF;
|
|
|
|
/* PORT D */
|
|
OED = 0xFF;
|
|
IOD = 0xFF;
|
|
}
|