aboutsummaryrefslogtreecommitdiff
path: root/AT91SAM7S256/Source/d_usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'AT91SAM7S256/Source/d_usb.c')
-rw-r--r--AT91SAM7S256/Source/d_usb.c946
1 files changed, 946 insertions, 0 deletions
diff --git a/AT91SAM7S256/Source/d_usb.c b/AT91SAM7S256/Source/d_usb.c
new file mode 100644
index 0000000..0caf317
--- /dev/null
+++ b/AT91SAM7S256/Source/d_usb.c
@@ -0,0 +1,946 @@
+//
+// Programmer
+//
+// Date init 14.12.2004
+//
+// Reviser $Author:: Dkandlun $
+//
+// Revision date $Date:: 14-11-07 12:40 $
+//
+// Filename $Workfile:: d_usb.c $
+//
+// Version $Revision:: 1 $
+//
+// Archive $Archive:: /LMS2006/Sys01/Main_V02/Firmware/Source/d_usb. $
+//
+// Platform C
+//
+
+#include "stdconst.h"
+#include "m_sched.h"
+#include "d_usb.h"
+#include "d_usb.r"
+
+#define ENDPOINT_OUT 1 // HOST write
+#define ENDPOINT_OUT_SIZE 64
+#define ENDPOINT_IN 2 // HOST read
+#define ENDPOINT_IN_SIZE 64
+
+#define AT91C_UDP_ISR ((AT91_REG *) 0xFFFB001C) // (UDP) Interrupt Status Register
+#define AT91C_RSTC_URSTEN ((unsigned int) 0x1 << 0) // (RSTC) User Reset Enable
+
+ // Endpoint Control and Status Registers
+#define AT91C_UDP_CSR0 ((AT91_REG *) 0xFFFB0030) // Endpoint 0 Control and Status Register
+#define AT91C_UDP_CSR1 ((AT91_REG *) 0xFFFB0034) // Endpoint 1 Control and Status Register
+#define AT91C_UDP_CSR2 ((AT91_REG *) 0xFFFB0038) // Endpoint 2 Control and Status Register
+#define AT91C_UDP_CSR3 ((AT91_REG *) 0xFFFB003C) // Endpoint 3 Control and Status Register
+
+ // Endpoint FIFO Data Registers
+#define AT91C_UDP_FDR0 ((AT91_REG *) 0xFFFB0050) // Endpoint 0 FIFO Data Register
+#define AT91C_UDP_FDR1 ((AT91_REG *) 0xFFFB0054) // Endpoint 1 FIFO Data Register
+#define AT91C_UDP_FDR2 ((AT91_REG *) 0xFFFB0058) // Endpoint 2 FIFO Data Register
+#define AT91C_UDP_FDR3 ((AT91_REG *) 0xFFFB005C) // Endpoint 3 FIFO Data Register
+
+const UBYTE DeviceDescriptor[] = {
+ /* Device descriptor */
+ 0x12, // bLength, size of this descriptor = 18 entries
+ 0x01, // bDescriptorType = 1 = DEVICE
+ 0x00, // bcdUSBL, USB spec. vers. 2.0
+ 0x02, // bcdUSBH, -
+ 0x00, // bDeviceClass
+ 0x00, // bDeviceSubclass
+ 0x00, // bDeviceProtocol
+ 0x08, // bMaxPacketSize0, EndPointZero packet size = 8
+ 0x94, // idVendorL, LEGO Group
+ 0x06, // idVendorH, -
+ 0x02, // idProductL, LEGO USB IR Tower = 0x01
+ 0x00, // idProductH, -
+ 0x00, // bcdDeviceL, device is version (zero)
+ 0x00, // bcdDeviceH, -
+ 0x00, // iManufacturer, index of string descriptor describing manufacturer
+ 0x00, // iProduct, index of string descriptor describing product
+ 0x01, // iSerialNumber, index of string descriptor describing the device's
+ // serial no.
+ 0x01 // bNumConfigs, number of possible configurations (only one)
+};
+
+/* USB standard request codes */
+
+#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
+
+/* USB constants, masks etc. */
+
+#define END_OF_BUS_RESET ((unsigned int) 0x1 << 12)
+#define SUSPEND_INT ((unsigned int) 0x1 << 8)
+#define SUSPEND_RESUME ((unsigned int) 0x1 << 9)
+#define WAKEUP ((unsigned int) 0x1 << 13)
+
+//USB spec allows 500ms for control transfers
+#define USB_MAX_TIMEOUT 500
+
+static UBYTE UsbHandleList[MAX_HANDLES];
+static UBYTE UsbHandleCnt;
+static UWORD RequestedData;
+static UBYTE BrickNameKnown;
+enum
+{
+ USB_NOT_CONFIGURED,
+ USB_CONFIGURED,
+ USB_CONFIGURED_BUT_SUSPENDED
+};
+static UBYTE UsbConnectionStates;
+
+
+const UBYTE ConfigurationDescriptor[] = {
+ /* ============== CONFIGURATION 1 =========== */
+ /* Configuration 1 descriptor */
+ 0x09, // bLength, descriptor size in bytes
+ 0x02, // bDescriptorType, The constant Configuration
+ 0x20, // wTotalLengthL for 2 EP + Control
+ 0x00, // wTotalLengthH -
+ 0x01, // bNumInterfaces, Number of interfaces in the configuration
+ 0x01, // bConfigurationValue, Identifier for
+ // Set_Configuration and Get_Configuration requests
+ 0x00, // iConfiguration, Index of string descriptor for the configuration
+ 0xC0, // bmAttributes, Bit 7 shall always be set. See e.g. page 108 in the book:
+ // "USB Complete" by Jan Axelson. June 2001
+ // Self powered only bit 6 = 1 (zero = buspowered USB 1.1 and up)
+ 0x00, // MaxPower, power required (mA./2) We're SELF-POWERED, so ZERO
+
+ /* Interface Descriptor */
+ 0x09, // bLength, descriptor size in bytes
+ 0x04, // bDescriptorType, the constant 0x04 = "INTERFACE"
+ 0x00, // bInterfaceNumber, No. identifying this interface
+ 0x00, // bAlternateSetting, value used to get an alternative interface
+ 0x02, // bNumEndpoints, No. of supported endpoints in addition to endpoint 0
+ 0xFF, // bInterfaceClass, Specifies the class code = VENDOR Specific
+ 0xFF, // bInterfaceSubclass, Specifies the subclass code = VENDOR Specific
+ 0xFF, // bInterfaceProtocol, protocol code = VENDOR Specific
+ 0x00, // iInterface, index of string descriptor for the interface
+
+ /* Endpoint 1 descriptor */
+ 0x07, // bLength, descriptor length incl. this = 7
+ 0x05, // bDescriptorType
+ 0x01, // bEndpointAddress, Endpoint 01 - OUT
+ 0x02, // bmAttributes BULK
+ ENDPOINT_OUT_SIZE, // wMaxPacketSize
+ 0x00, // -
+ 0x00, // bInterval
+
+ /* Endpoint 2 descriptor */
+ 0x07, // bLength, descriptor length incl. this = 7
+ 0x05, // bDescriptorType
+ 0x82, // bEndpointAddress, Endpoint 02 - IN
+ 0x02, // bmAttributes BULK
+ ENDPOINT_IN_SIZE, // wMaxPacketSize
+ 0x00, // -
+ 0x00 // bInterval
+};
+
+UBYTE SerialNumberDescriptor[] =
+{
+ 0x1A, // bLength, descriptor length incl. this = 16 bytes
+ 0x03, // bDescriptorType
+
+ 0x31, 0x00, // MSD of Lap (Lap[2,3]) in UNICode
+ 0x32, 0x00, // Lap[4,5]
+ 0x33, 0x00, // Lap[6,7]
+ 0x34, 0x00, // Lap[8,9]
+ 0x35, 0x00, // Lap[10,11]
+ 0x36, 0x00, // Lap[12,13]
+ 0x37, 0x00, // Lap[14,15]
+ 0x38, 0x00, // LSD of Lap (Lap[16,17]) in UNICode
+
+ 0x30, 0x00, // MSD of Nap (Nap[18,19]) in UNICode
+ 0x30, 0x00, // LSD of Nap (Nap[20,21]) in UNICode
+
+ 0x39, 0x00, // MSD of Uap in UNICode
+ 0x30, 0x00 // LSD of Uap in UNICode
+};
+
+const UBYTE LangIdDescriptor[] =
+{
+ 0x04, // Length
+ 0x03, // Type, 3 = CONSTANT String
+ 0x09, // English
+ 0x04 // subcode = U.S. English
+};
+
+static UCHAR CurrentConfiguration; // Configured or not. We've only 1 conf. so... Boolean
+static ULONG CurrentReceiveBank; // Used for keep track of the PING-PONG buffers
+
+ULONG g_UsbTimeoutCounter;
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+void dUsbDisconnect(void)
+{
+ USBDisconnect;
+}
+
+void dUsbConnect(void)
+{
+ USBConnect;
+}
+
+void dUsbStartTimeoutTimer(void)
+{
+ g_UsbTimeoutCounter = 0;
+
+ USBGetActualTime;
+}
+
+// A longer version of the USB timer.
+// Table 7-14 of the USB 2.0 spec allows up to 500ms for standard request completion.
+UBYTE dUsbTimedOut(void)
+{
+ if(USBTimedOut)
+ {
+ g_UsbTimeoutCounter++;
+
+ USBGetActualTime;
+ }
+
+ return (g_UsbTimeoutCounter >= USB_MAX_TIMEOUT) ? TRUE : FALSE;
+}
+
+
+UBYTE ConvertHighToHex(UBYTE TempChar)
+{
+ TempChar = (TempChar >> 4) & 0x0F;
+ if (TempChar > 0x09)
+ TempChar += 0x37;
+ else
+ TempChar += 0x30;
+ return TempChar;
+}
+
+UBYTE ConvertLowToHex(UBYTE TempChar)
+{
+ TempChar &= 0x0F;
+ if (TempChar > 0x09)
+ TempChar += 0x37;
+ else
+ TempChar += 0x30;
+ return TempChar;
+}
+
+void dUsbStoreBtAddress(UBYTE *pBtAddress)
+{
+ UBYTE NoToConvert;
+
+ // make the Lap human readable (hmmm Hexadecimal)
+ NoToConvert = *pBtAddress++;
+ SerialNumberDescriptor[2] = ConvertHighToHex(NoToConvert);
+ SerialNumberDescriptor[4] = ConvertLowToHex(NoToConvert);
+
+ NoToConvert = *pBtAddress++;
+ SerialNumberDescriptor[6] = ConvertHighToHex(NoToConvert);
+ SerialNumberDescriptor[8] = ConvertLowToHex(NoToConvert);
+
+ NoToConvert = *pBtAddress++;
+ SerialNumberDescriptor[10] = ConvertHighToHex(NoToConvert);
+ SerialNumberDescriptor[12] = ConvertLowToHex(NoToConvert);
+
+ NoToConvert = *pBtAddress++;
+ SerialNumberDescriptor[14] = ConvertHighToHex(NoToConvert);
+ SerialNumberDescriptor[16] = ConvertLowToHex(NoToConvert);
+
+ // make the Uap human readable (hmmm Hexadecimal)
+ NoToConvert = *pBtAddress++;
+ SerialNumberDescriptor[18] = ConvertHighToHex(NoToConvert);
+ SerialNumberDescriptor[20] = ConvertLowToHex(NoToConvert);
+
+ // make the Nap human readable (hmmm Hexadecimal)
+ NoToConvert = *pBtAddress++;
+ SerialNumberDescriptor[22] = ConvertHighToHex(NoToConvert);
+ SerialNumberDescriptor[24] = ConvertLowToHex(NoToConvert);
+
+ USBConnect; // We're ready to participate in the real world
+ BrickNameKnown = TRUE; // OK for referencing :-)
+}
+
+
+ULONG dUsbRead(UBYTE *pData, ULONG Length)
+{
+ ULONG PacketSize, NumberOfBytesReceived;
+
+ NumberOfBytesReceived = 0;
+
+ while (Length) // Wished read size from user (Max length)
+ {
+ if ( !(BrickNameKnown)) // Right Brick???
+ break;
+
+ if ( !(dUsbIsConfigured()) )
+ break; // Not configured - no time to waste
+
+ if ( (*AT91C_UDP_CSR1) & CurrentReceiveBank ) // Data packet rx'ed in Current bank?
+ {
+
+ PacketSize = MIN((*AT91C_UDP_CSR1) >> 16, Length); // Normalize number of bytes available in FIFO
+ Length -= PacketSize; // Rest of data to receive
+
+ if (PacketSize < ENDPOINT_OUT_SIZE) // If data less, we only have one loop
+ Length = 0;
+
+ while(PacketSize--) // While more data in this very packet...
+ pData[NumberOfBytesReceived++] = *AT91C_UDP_FDR1; // Fill in buffer
+
+ *AT91C_UDP_CSR1 &= ~(CurrentReceiveBank); // Reset current bank pointer
+
+ if (CurrentReceiveBank == AT91C_UDP_RX_DATA_BK0) // Current Receive Bank 0?
+ CurrentReceiveBank = AT91C_UDP_RX_DATA_BK1; // We better use Bank 1
+ else
+ CurrentReceiveBank = AT91C_UDP_RX_DATA_BK0; // Okay, go for Bank 0 :-)
+
+ }
+
+ else Length = 0; // Leave and let's use the CPU cycles in a better way
+
+ }
+
+ return NumberOfBytesReceived; // Size of actually received stuff
+
+}
+
+ULONG dUsbWrite( const UBYTE *pData, ULONG Length)
+{
+ ULONG CharsEachTx = 0;
+
+ // Send the very first (or only) packet
+ CharsEachTx = MIN(Length, ENDPOINT_IN_SIZE); // First transmission size
+ Length -= CharsEachTx; // Adjust the rest of transmission size
+
+ while (CharsEachTx--) // While more chars in this chunk
+ *AT91C_UDP_FDR2 = *pData++; // Get rid off it one by one
+ // Pushing the data into the UDP TX-fifo
+ *AT91C_UDP_CSR2 |= AT91C_UDP_TXPKTRDY; // Signal "DO THE TX" the stuff is delivered...
+
+ while (Length) // While more bytes (I.e. packets) ín total transmission
+ { // Start filling the second bank
+
+ CharsEachTx = MIN(Length, ENDPOINT_IN_SIZE);
+ Length -= CharsEachTx; // Adjust total length
+
+ while (CharsEachTx--) // While more chars in this chunk
+ *AT91C_UDP_FDR2 = *pData++;
+
+ dUsbStartTimeoutTimer();
+ while ( !((*AT91C_UDP_CSR2) & AT91C_UDP_TXCOMP) ) // Wait for the the first bank to be sent
+ if (dUsbTimedOut() || !(dUsbIsConfigured()) ) // Communication down..... Bail out
+ return Length; // Invalid function - return job length not done
+
+ (*AT91C_UDP_CSR2) &= ~(AT91C_UDP_TXCOMP); // Reset transmit interrupt flag
+
+ while ((*AT91C_UDP_CSR2) & AT91C_UDP_TXCOMP); // Wait until flag (H/W) is reset
+
+ (*AT91C_UDP_CSR2) |= AT91C_UDP_TXPKTRDY; // We're ready to send next bank
+
+ } // Loop while bytes to tx
+
+ dUsbStartTimeoutTimer(); // Arm the timeout timing
+ while ( !((*AT91C_UDP_CSR2) & AT91C_UDP_TXCOMP) ) // Wait for transmission to complete
+ if ( !(dUsbIsConfigured()) || dUsbTimedOut()) // Communication down..... Bail out
+ return Length; // Invalid function - return job length not done
+
+ (*AT91C_UDP_CSR2) &= ~(AT91C_UDP_TXCOMP); // Reset Interrupt flag
+
+ while ((*AT91C_UDP_CSR2) & AT91C_UDP_TXCOMP); // Wait for H/W to settle.....
+
+ return Length; // Return byte count NOT x-ferred
+
+}
+
+static void dUsbSendStall(void)
+{
+ (*AT91C_UDP_CSR0) |= AT91C_UDP_FORCESTALL; // Set STALL condition
+ while ( !((*AT91C_UDP_CSR0) & AT91C_UDP_ISOERROR) ); // Wait until stall ack'ed
+
+ (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR); // Reset again
+ while ((*AT91C_UDP_CSR0) & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR)); // Wait until H/W really reset
+}
+
+static void dUsbSendZeroLengthPackage(void)
+{
+ // Signal that buffer is ready to send
+ (*AT91C_UDP_CSR0) |= AT91C_UDP_TXPKTRDY;
+
+ dUsbStartTimeoutTimer();
+
+ // Wait for ACK handshake from host
+ while ( !((*AT91C_UDP_CSR0) & AT91C_UDP_TXCOMP) && !dUsbTimedOut());
+ // Clear handshake flag
+ (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_TXCOMP);
+ while ((*AT91C_UDP_CSR0) & AT91C_UDP_TXCOMP);
+}
+
+static void dUsbSendViaControl(const UBYTE *pData, ULONG Length)
+{
+ ULONG BytesToTx = 0;
+ AT91_REG Temp_Csr;
+ UBYTE HaveToTxZeroLength = FALSE;
+ UBYTE ZeroCouldBeNeeded = FALSE;
+
+ // If the amount of data requested is more than what can be sent, a 0-length
+ // packet may be required
+ if (RequestedData > Length)
+ {
+ ZeroCouldBeNeeded = TRUE; // Exact same size would be interpreted as EOP @ host
+ }
+
+ do
+ {
+ // The endpoint size is 8 bytes. Limit each data phase to 8 bytes.
+
+ BytesToTx = MIN(Length, 8);
+ Length -= BytesToTx;
+
+ // If this is the last data phase containing data, but the host requested
+ // more, a 0-byte packet will be needed to terminate the data phase.
+ if(ZeroCouldBeNeeded && (Length == 0) && (BytesToTx == 8))
+ {
+ HaveToTxZeroLength = TRUE;
+ }
+
+ // Copy data to endpoint buffer
+ while (BytesToTx--)
+ {
+ (*AT91C_UDP_FDR0) = *pData++;
+ }
+
+ // Signal that buffer is ready to send
+ (*AT91C_UDP_CSR0) |= AT91C_UDP_TXPKTRDY;
+
+ dUsbStartTimeoutTimer();
+
+ // Wait for ACK handshake from host
+ do
+ {
+ Temp_Csr = (*AT91C_UDP_CSR0);
+
+ // Return if the status phase occurs before the packet is accepted
+ if (Temp_Csr & AT91C_UDP_RX_DATA_BK0)
+ {
+ // Clear the PKTRDY flag
+ (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_TXPKTRDY);
+ // Clear the status phase flag
+ (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_RX_DATA_BK0);
+ return;
+ }
+ }
+ while (!(Temp_Csr & AT91C_UDP_TXCOMP) && !dUsbTimedOut());
+
+ // Clear handshake flag
+ (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_TXCOMP);
+
+ while ((*AT91C_UDP_CSR0) & AT91C_UDP_TXCOMP);
+
+ } while (Length);
+
+ if(HaveToTxZeroLength)
+ {
+ dUsbSendZeroLengthPackage();
+ }
+
+ dUsbStartTimeoutTimer();
+
+ // Wait for Status Phase
+ while(!((*AT91C_UDP_CSR0) & AT91C_UDP_RX_DATA_BK0) && !dUsbTimedOut());
+ // Clear flag
+ (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_RX_DATA_BK0);
+}
+
+static void dUsbEnumerate(void)
+{
+ UBYTE bmRequestType, bRequest;
+ UWORD wValue, wIndex, wLength, wStatus;
+
+ if ( !((*AT91C_UDP_CSR0) & AT91C_UDP_RXSETUP) ) // No setup package available
+ return;
+ // Bytes are popped from the FIFO one by one
+
+ bmRequestType = *AT91C_UDP_FDR0;
+ bRequest = *AT91C_UDP_FDR0;
+ wValue = ((*AT91C_UDP_FDR0) & 0xFF);
+ wValue |= ((*AT91C_UDP_FDR0) << 8);
+ wIndex = ((*AT91C_UDP_FDR0) & 0xFF);
+ wIndex |= ((*AT91C_UDP_FDR0) << 8);
+ wLength = ((*AT91C_UDP_FDR0) & 0xFF);
+ wLength |= ((*AT91C_UDP_FDR0) << 8);
+
+ if (bmRequestType & 0x80) // If a DEVICE-TO-HOST request
+ {
+ *AT91C_UDP_CSR0 |= AT91C_UDP_DIR; // Enables data IN transaction in the control data stage
+ while ( !((*AT91C_UDP_CSR0) & AT91C_UDP_DIR) ); // Repeat until the DIR bit is set
+ }
+
+ *AT91C_UDP_CSR0 &= ~AT91C_UDP_RXSETUP; // Device firmware has read the setup data in FIFO
+ while ( ((*AT91C_UDP_CSR0) & AT91C_UDP_RXSETUP) ); // Wait until bit cleared
+
+ // Handle supported standard device request from Table 9-3 in USB specification Rev 2.0
+
+ switch ((bRequest << 8) | bmRequestType)
+ {
+ case STD_GET_DESCRIPTOR:
+
+ RequestedData = wLength;
+
+ if (wValue == 0x100) // Return Device Descriptor
+ {
+ if (sizeof(DeviceDescriptor) > wLength)
+ {
+ dUsbSendViaControl(DeviceDescriptor, wLength);
+ }
+ else
+ {
+ dUsbSendViaControl(DeviceDescriptor, sizeof(DeviceDescriptor));
+ }
+ }
+ else if (wValue == 0x200) // Return Configuration Descriptor
+ {
+ if (sizeof(ConfigurationDescriptor) > wLength)
+ {
+ dUsbSendViaControl(ConfigurationDescriptor, wLength);
+ }
+ else
+ {
+ dUsbSendViaControl(ConfigurationDescriptor, sizeof(ConfigurationDescriptor));
+ }
+ }
+ else if ((wValue & 0xF00) == 0x300)
+ {
+ switch(wValue & 0xFF)
+ {
+ case 0x00:
+ if ((sizeof(LangIdDescriptor)) > wLength)
+ {
+ dUsbSendViaControl(LangIdDescriptor, wLength);
+ }
+ else
+ {
+ dUsbSendViaControl(LangIdDescriptor, sizeof(LangIdDescriptor));
+ }
+ break;
+
+ case 0x01:
+ if ((sizeof(SerialNumberDescriptor)) > wLength)
+ {
+ dUsbSendViaControl(SerialNumberDescriptor, wLength);
+ }
+ else
+ {
+ dUsbSendViaControl(SerialNumberDescriptor, sizeof(SerialNumberDescriptor));
+ }
+ break;
+
+ default:
+ dUsbSendStall(); // Illegal request :-(
+ break;
+ }
+ }
+ else
+ dUsbSendStall(); // Illegal request :-(
+
+ break;
+
+ case STD_SET_ADDRESS:
+
+ // Status IN transfer
+ (*AT91C_UDP_CSR0) |= AT91C_UDP_TXPKTRDY;
+
+ dUsbStartTimeoutTimer();
+
+ while((*AT91C_UDP_CSR0) & AT91C_UDP_TXPKTRDY && !dUsbTimedOut());
+
+ *AT91C_UDP_FADDR = (AT91C_UDP_FEN | wValue); // Set device address. No check for invalid address.
+ // Function endpoint enabled.
+ *AT91C_UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0; // If Device address != 0 then flag device
+ // in ADDRESS STATE
+ break;
+
+ case STD_SET_CONFIGURATION:
+
+ CurrentConfiguration = wValue; // Low byte of wValue = wanted configuration
+ UsbConnectionStates = USB_CONFIGURED;
+ dUsbSendZeroLengthPackage(); // Signal request processed OK
+
+ *AT91C_UDP_GLBSTATE = (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN; // If wanted configuration != 0
+
+ *AT91C_UDP_CSR1 = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0; // Endpoint 1 enabled and set as BULK OUT
+ *AT91C_UDP_CSR2 = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0; // Endpoint 2 enabled and set as BULK IN
+ *AT91C_UDP_CSR3 = (wValue) ? (AT91C_UDP_EPTYPE_INT_IN) : 0; // Endpoint 3 disabled and set as INTERRUPT IN
+
+ break;
+
+ case STD_GET_CONFIGURATION: // The actual configuration value is sent to HOST
+
+ RequestedData = sizeof(CurrentConfiguration);
+
+ dUsbSendViaControl((UBYTE *) &(CurrentConfiguration), sizeof(CurrentConfiguration));
+
+ break;
+
+ case STD_GET_STATUS_ZERO:
+
+ wStatus = 0x01; // Atmel has a 0x00, but we're not BUS-powered
+ RequestedData = sizeof(wStatus);
+
+ dUsbSendViaControl((UBYTE *) &wStatus, sizeof(wStatus));
+
+ break;
+
+ case STD_GET_STATUS_INTERFACE: // Everything reset to zero (reserved)
+
+ wStatus = 0;
+ RequestedData = sizeof(wStatus);
+
+ dUsbSendViaControl((UBYTE *) &wStatus, sizeof(wStatus));
+
+ break;
+
+ case STD_GET_STATUS_ENDPOINT:
+
+ wStatus = 0;
+ RequestedData = sizeof(wStatus);
+ wIndex &= 0x0F; // Mask the endpoint #
+
+ if (((*AT91C_UDP_GLBSTATE) & AT91C_UDP_CONFG) && (wIndex <= 3)) // If device in CONFIGURED state
+ { // and ENDPOINT selected in valid range
+
+ switch (wIndex)
+ {
+
+ case 1: wStatus = ((*AT91C_UDP_CSR1) & AT91C_UDP_EPEDS) ? 0 : 1; // If an endpoint is halted, the HALT
+ // feature is set to 1, else reset
+ break;
+
+ case 2: wStatus = ((*AT91C_UDP_CSR2) & AT91C_UDP_EPEDS) ? 0 : 1;
+
+ break;
+
+ case 3: wStatus = ((*AT91C_UDP_CSR3) & AT91C_UDP_EPEDS) ? 0 : 1;
+
+ break;
+ default:
+ // We'll never come here, but we'll never say never.......
+ break;
+ }
+
+ dUsbSendViaControl((UBYTE *) &wStatus, sizeof(wStatus));
+
+ }
+
+ else if (((*AT91C_UDP_GLBSTATE) & AT91C_UDP_FADDEN) && (wIndex == 0))
+ {
+ wStatus = ((*AT91C_UDP_CSR0) & AT91C_UDP_EPEDS) ? 0 : 1; // Return 1 if device in ADRESSED state
+
+ dUsbSendViaControl((UBYTE *) &wStatus, sizeof(wStatus));
+ }
+ else
+
+ dUsbSendStall(); // Illegal request :-(
+
+ break;
+
+ case STD_SET_FEATURE_ZERO:
+
+ dUsbSendStall(); // Illegal request :-(
+
+ break;
+
+ case STD_SET_FEATURE_INTERFACE:
+
+ dUsbSendZeroLengthPackage(); // TextBook
+
+ break;
+
+ case STD_SET_FEATURE_ENDPOINT:
+
+ wIndex &= 0x0F;
+
+ if ((wValue == 0) && wIndex && (wIndex <= 3)) // Feature Selector = 0 ENDPOINT HALT and
+ { // endpoint isolated and validated
+
+ switch (wIndex)
+ {
+
+ case 1: (*AT91C_UDP_CSR1) = 0;
+
+ break;
+
+ case 2: (*AT91C_UDP_CSR2) = 0;
+
+ break;
+
+ case 3: (*AT91C_UDP_CSR3) = 0;
+
+ break;
+
+ default:
+ // We'll never come here, but we'll never say never.......
+ break;
+
+ }
+
+ dUsbSendZeroLengthPackage();
+
+ }
+ else
+
+ dUsbSendStall(); // Illegal request :-(
+
+ break;
+
+ case STD_CLEAR_FEATURE_ZERO:
+
+ dUsbSendStall(); // Illegal request :-(
+
+ break;
+
+ case STD_CLEAR_FEATURE_INTERFACE:
+
+ dUsbSendZeroLengthPackage(); // No special
+
+ break;
+
+ case STD_CLEAR_FEATURE_ENDPOINT:
+
+ wIndex &= 0x0F;
+
+ if ((wValue == 0) && wIndex && (wIndex <= 3)) // Feature Selector = 0 => ENABLE A HALTED endpoint
+ { // and endpoint isolated and validated
+
+ if (wIndex == 1)
+ (*AT91C_UDP_CSR1) = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT); // On duty again
+ else if (wIndex == 2)
+ (*AT91C_UDP_CSR2) = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN); // -
+ else if (wIndex == 3)
+ (*AT91C_UDP_CSR3) = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN); // -
+
+ dUsbSendZeroLengthPackage();
+
+ }
+ else
+
+ dUsbSendStall(); // Illegal request :-(
+
+ break;
+
+ default:
+
+ dUsbSendStall(); // Illegal request :-(
+
+ break;
+ }
+}
+
+UBYTE dUsbIsConfigured(void)
+{
+
+ if (*AT91C_UDP_ISR & END_OF_BUS_RESET) // If "End Of Bus Reset Interrupt"
+ { // Somebody fallen in the wire? ;-)
+
+
+ *AT91C_UDP_ICR = END_OF_BUS_RESET; // Reset "End Of Bus Reset Interrupt"
+ *AT91C_UDP_ICR = SUSPEND_RESUME; // State unknown after reset, so we better clear
+ *AT91C_UDP_ICR = WAKEUP; // As above
+
+ CurrentConfiguration = 0; // We're new and ready
+ UsbConnectionStates = USB_NOT_CONFIGURED;
+
+ *AT91C_UDP_RSTEP = 0xFFFFFFFF; // Reset all implemented endpoints "and a few more"
+ *AT91C_UDP_RSTEP = 0x0; // Restored as zeroes
+ // Below our main crash thing, if it is missing ;-)
+ CurrentReceiveBank = AT91C_UDP_RX_DATA_BK0; // Start the PING-PONG buffers at a known state and order
+
+ *AT91C_UDP_FADDR = AT91C_UDP_FEN; // Set FEN in the Function Address Register
+ // USB device is able to receive and transfer data
+
+ *AT91C_UDP_CSR0 = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); // Configure endpoint 0
+ // AT91C_UDP_EPEDS = Endpoint enable
+ // AT91C_UDP_EPTYPE_CTRL = Endpoint type CONTROL
+ }
+
+ else if (*AT91C_UDP_ISR & SUSPEND_INT)
+ {
+ if (UsbConnectionStates == USB_CONFIGURED)
+ {
+ UsbConnectionStates = USB_CONFIGURED_BUT_SUSPENDED;
+ }
+ else
+ {
+ UsbConnectionStates = USB_NOT_CONFIGURED;
+ }
+
+ *AT91C_UDP_ICR = SUSPEND_INT;
+ CurrentReceiveBank = AT91C_UDP_RX_DATA_BK0; // Start the PING-PONG buffers at a known state and order
+ }
+
+ else if (*AT91C_UDP_ISR & SUSPEND_RESUME)
+ {
+ if (UsbConnectionStates == USB_CONFIGURED_BUT_SUSPENDED)
+ {
+ UsbConnectionStates = USB_CONFIGURED;
+ }
+ else
+ {
+ UsbConnectionStates = USB_NOT_CONFIGURED;
+ }
+
+ *AT91C_UDP_ICR = WAKEUP;
+ *AT91C_UDP_ICR = SUSPEND_RESUME;
+ }
+
+ else if (*AT91C_UDP_ISR & AT91C_UDP_EPINT0) // If "Endpoint 0 Interrupt"
+ {
+ *AT91C_UDP_ICR = AT91C_UDP_EPINT0; // Reset "Endpoint 0 Interrupt"
+ if (BrickNameKnown)
+ dUsbEnumerate(); // Let's date & exchange "personal data"
+ }
+
+ if (UsbConnectionStates == USB_CONFIGURED)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+
+}
+
+
+void dUsbInsertHandle(UBYTE Handle)
+{
+ UBYTE Tmp;
+
+ Tmp = 0;
+ while((UsbHandleList[Tmp] != MAX_HANDLES) && (Tmp < MAX_HANDLES))
+ {
+ Tmp++;
+ }
+ UsbHandleList[Tmp] = Handle;
+}
+
+void dUsbRemoveHandle(UBYTE Handle)
+{
+ UBYTE Tmp;
+
+ Tmp = 0;
+ while (Tmp < MAX_HANDLES)
+ {
+ if (Handle == UsbHandleList[Tmp])
+ {
+ UsbHandleList[Tmp] = MAX_HANDLES;
+ }
+ Tmp++;
+ }
+}
+
+UWORD dUsbGetFirstHandle(void)
+{
+ UWORD RtnVal;
+
+ UsbHandleCnt = 0;
+ RtnVal = dUsbGetNextHandle();
+
+ return(RtnVal);
+}
+
+UWORD dUsbGetNextHandle(void)
+{
+ UBYTE Tmp;
+ UWORD RtnVal;
+
+ RtnVal = 0;
+ Tmp = UsbHandleCnt;
+ while((Tmp < MAX_HANDLES) && (MAX_HANDLES == UsbHandleList[Tmp]))
+ {
+ Tmp++;
+ }
+ UsbHandleCnt = Tmp + 1;
+
+ if (Tmp < MAX_HANDLES)
+ {
+ RtnVal |= UsbHandleList[Tmp];
+ }
+ else
+ {
+ RtnVal = 0x8100;
+ }
+
+ return(RtnVal);
+}
+
+UWORD dUsbCheckConnection(void)
+{
+ UWORD ADValue;
+ UWORD Return;
+
+ Return = FALSE;
+ USBReadADCValue(&ADValue);
+
+ if (ADValue > 512)
+ {
+ Return = TRUE;
+ }
+ return(Return);
+}
+
+void dUsbInit(void)
+{
+ UBYTE Tmp;
+
+ // We could come from a SAMBA session and then we need
+ // to "introduce ourself in a polite way for the PNP manager
+ // We will pull the carpet and start a new session by removing
+ // the pull up of the D+ wire
+
+ BrickNameKnown = FALSE;
+ dUsbStartTimeoutTimer(); // Let H/W settle
+ dUsbDisconnect(); // Pull the carpet
+ while(!USBTimedOut); // wait 1 mS.
+
+ USBHwInit; // New session
+
+ CurrentConfiguration = 0; // We're new born
+ UsbConnectionStates = USB_NOT_CONFIGURED;
+ CurrentReceiveBank = AT91C_UDP_RX_DATA_BK0; // Always start from Bank 0
+ RequestedData = 0;
+
+ for(Tmp = 0; Tmp < MAX_HANDLES; Tmp++)
+ {
+ UsbHandleList[Tmp] = MAX_HANDLES;
+ }
+}
+
+void dUsbResetConfig(void)
+{
+ CurrentConfiguration = 0; // We've lost the connection
+ UsbConnectionStates = USB_NOT_CONFIGURED;
+}
+
+void dUsbExit(void)
+{
+// USBExit;
+}