Add USB code

Adds the usb code that we got in ECE 385. It will not work now, and
parts that involve the timer are disabled. It does compile though, with
a few warnings.

The goal will be to add USB MSD support, which is not actually given to
us so I will have to do myself or find some other code to base it off
of.
This commit is contained in:
Byron Lathi
2022-03-10 16:15:08 -06:00
parent aca739338a
commit 5d8c4aab44
15 changed files with 2165 additions and 2 deletions

View File

@@ -15,6 +15,7 @@ LISTS=lists
TESTS=tests
SRCS=$(wildcard *.s) $(wildcard *.c)
SRCS+=$(wildcard usb/*.c)
OBJS+=$(patsubst %.s,%.o,$(filter %s,$(SRCS)))
OBJS+=$(patsubst %.c,%.o,$(filter %c,$(SRCS)))
@@ -45,8 +46,8 @@ $(BIN): $(OBJS)
$(CC) $(CFLAGS) -l $(LISTS)/$<.list -c $< -o $@
$(LISTS):
mkdir $(LISTS)
mkdir $(LISTS)/$(TESTS)
mkdir -p $(addprefix $(LISTS)/,$(sort $(dir $(SRCS))))
mkdir $(LISTS)/$(sort $(dir $(TEST_SRCS)))
.PHONY: clean
clean:

9
sw/gpio.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef _GPIO_H
#define _GPIO_H
#include <stdint.h>
#define USB_GPIO (uint8_t*)0x7ff1
extern uint8_t* usb_gpio;
#endif

9
sw/io.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef _IO_H
#define _IO_H
#include <stdint.h>
#define USB_GPIO 0x7ff1
extern uint8_t* usb_gpio;
#endif

9
sw/usb/GenericMacros.h Normal file
View File

@@ -0,0 +1,9 @@
/* Generic macros */
/* Word <> two chars. Works both ways */
#define LOBYTE(x) ((char*)(&(x)))[0]
#define HIBYTE(x) ((char*)(&(x)))[1]
/* Bit set/clear */
#define bitset(var, bitno) ((var) |= 1 << (bitno))
#define bitclr(var, bitno) ((var) &= ~(1 << (bitno)))

115
sw/usb/GenericTypeDefs.h Normal file
View File

@@ -0,0 +1,115 @@
//Modified version of Generic Types as included by Microchip C18
#ifndef __GENERIC_TYPE_DEFS_H_
#define __GENERIC_TYPE_DEFS_H_
typedef enum _BOOL {
FALSE = 0, TRUE
} BOOL; // Undefined size
#define ON TRUE
#define OFF FALSE
typedef unsigned char BYTE; // 8-bit unsigned
typedef unsigned short int WORD; // 16-bit unsigned
typedef unsigned long DWORD; // 32-bit unsigned
typedef signed char CHAR; // 8-bit signed
typedef signed short int SHORT; // 16-bit signed
typedef signed long LONG; // 32-bit signed
typedef union _BYTE_VAL {
BYTE Val;
struct {
unsigned int b0 :1;
unsigned int b1 :1;
unsigned int b2 :1;
unsigned int b3 :1;
unsigned int b4 :1;
unsigned int b5 :1;
unsigned int b6 :1;
unsigned int b7 :1;
} bits;
} BYTE_VAL;
typedef union _WORD_VAL {
WORD Val;
BYTE v[2];
struct {
BYTE LB;
BYTE HB;
} byte;
struct {
unsigned int b0 :1;
unsigned int b1 :1;
unsigned int b2 :1;
unsigned int b3 :1;
unsigned int b4 :1;
unsigned int b5 :1;
unsigned int b6 :1;
unsigned int b7 :1;
unsigned int b8 :1;
unsigned int b9 :1;
unsigned int b10 :1;
unsigned int b11 :1;
unsigned int b12 :1;
unsigned int b13 :1;
unsigned int b14 :1;
unsigned int b15 :1;
} bits;
} WORD_VAL;
typedef union _DWORD_VAL {
DWORD Val;
WORD w[2];
BYTE v[4];
struct {
WORD LW;
WORD HW;
} word;
struct {
BYTE LB;
BYTE HB;
BYTE UB;
BYTE MB;
} byte;
struct {
unsigned int b0 :1;
unsigned int b1 :1;
unsigned int b2 :1;
unsigned int b3 :1;
unsigned int b4 :1;
unsigned int b5 :1;
unsigned int b6 :1;
unsigned int b7 :1;
unsigned int b8 :1;
unsigned int b9 :1;
unsigned int b10 :1;
unsigned int b11 :1;
unsigned int b12 :1;
unsigned int b13 :1;
unsigned int b14 :1;
unsigned int b15 :1;
unsigned int b16 :1;
unsigned int b17 :1;
unsigned int b18 :1;
unsigned int b19 :1;
unsigned int b20 :1;
unsigned int b21 :1;
unsigned int b22 :1;
unsigned int b23 :1;
unsigned int b24 :1;
unsigned int b25 :1;
unsigned int b26 :1;
unsigned int b27 :1;
unsigned int b28 :1;
unsigned int b29 :1;
unsigned int b30 :1;
unsigned int b31 :1;
} bits;
} DWORD_VAL;
#ifndef NULL
#define NULL 0
#endif
#endif //__GENERIC_TYPE_DEFS_H_

242
sw/usb/HID.c Normal file
View File

@@ -0,0 +1,242 @@
/* HID class support functions */
#include <stdio.h>
#include "project_config.h"
BYTE bigbuf[256]; //256 bytes
extern DEV_RECORD devtable[];
HID_DEVICE hid_device = { { 0 } };
EP_RECORD hid_ep[2] = { { 0 } }; //HID class endpoints, 1 control, 1 interrupt-IN
//the third endpoint is not implemented
/* HID Mouse probe. Called from USB state machine. */
/* assumes configuration length is less than 256 bytes */
/* looks for Class:03, Subclass: 01, Protocol: 02 in interface descriptor */
/* sets mouse in boot protocol */
/* assumes single configuration and interface configuration 0 */
BOOL HIDMProbe(BYTE addr, DWORD flags) {
BYTE tmpbyte;
BYTE rcode;
BYTE confvalue;
WORD total_length;
USB_DESCR* data_ptr = (USB_DESCR *) &bigbuf;
BYTE* byte_ptr = bigbuf;
(void) flags;
rcode = XferGetConfDescr(addr, 0, CONF_DESCR_LEN, 0, bigbuf); //get configuration descriptor
if (rcode) { //error handling
//printf("unable to get configuration descriptor");
return (FALSE);
}
if (data_ptr->descr.config.wTotalLength > 256) {
total_length = 256;
} else {
total_length = data_ptr->descr.config.wTotalLength;
}
rcode = XferGetConfDescr(addr, 0, total_length, 0, bigbuf); //get the whole configuration
if (rcode) { //error handling
//printf("unable to get configuration");
return (FALSE);
}
confvalue = data_ptr->descr.config.bConfigurationValue;
//printf("checking configuration value (length: %d): ",
// data_ptr->descr.config.wTotalLength);
//for (int i = 0; i < data_ptr->descr.config.wTotalLength; i++) {
//printf("%x ", (unsigned char) (bigbuf[i] & 0xff));
//}
while (byte_ptr < bigbuf + total_length) {
if (data_ptr->descr.config.bDescriptorType != USB_DESCRIPTOR_INTERFACE) {
byte_ptr = byte_ptr + data_ptr->descr.config.bLength;
data_ptr = (USB_DESCR*) byte_ptr;
} // if( data_ptr->descr.config.bDescriptorType != USB_DESCRIPTOR_INTERFACE
else {
//printf("starting interface parsing at byte location %d\n",
// data_ptr->descr.config.bLength);
BYTE class = data_ptr->descr.interface.bInterfaceClass;
BYTE subclass = data_ptr->descr.interface.bInterfaceSubClass;
BYTE protocol = data_ptr->descr.interface.bInterfaceProtocol;
//printf("class %x, subclass %x, protocol %x,\n", class, subclass,
// protocol);
//interface descriptor
if (class == HID_INTF && subclass == BOOT_INTF_SUBCLASS
&& protocol == HID_PROTOCOL_MOUSE) {
//detected a mouse
devtable[addr].devclass = HID_M; //device class
tmpbyte = devtable[addr].epinfo->MaxPktSize;
HID_init(); //initialize data structures
devtable[addr].epinfo = hid_ep; //switch endpoint information structure
devtable[addr].epinfo[0].MaxPktSize = tmpbyte;
hid_device.interface =
data_ptr->descr.interface.bInterfaceNumber;
hid_device.addr = addr;
byte_ptr = byte_ptr + data_ptr->descr.config.bLength;
data_ptr = (USB_DESCR*) byte_ptr;
while (byte_ptr < bigbuf + total_length) {
if (data_ptr->descr.config.bDescriptorType
!= USB_DESCRIPTOR_ENDPOINT) { //skip to endpoint descriptor
byte_ptr = byte_ptr + data_ptr->descr.config.bLength;
data_ptr = (USB_DESCR*) byte_ptr;
} else {
/* fill endpoint information structure */
devtable[addr].epinfo[1].epAddr =
data_ptr->descr.endpoint.bEndpointAddress;
devtable[addr].epinfo[1].Attr =
data_ptr->descr.endpoint.bmAttributes;
devtable[addr].epinfo[1].MaxPktSize =
data_ptr->descr.endpoint.wMaxPacketSize;
devtable[addr].epinfo[1].Interval =
data_ptr->descr.endpoint.bInterval;
// devtable[ addr ].epinfo[ 1 ].rcvToggle = bmRCVTOG0;
/* configure device */
rcode = XferSetConf(addr, 0, confvalue); //set configuration
if (rcode) { //error handling
return (FALSE);
}
rcode = XferSetProto(addr, 0, hid_device.interface,
BOOT_PROTOCOL);
if (rcode) { //error handling
return (FALSE);
} else {
return (TRUE);
}
}
} //while( byte_ptr....
} //if (Class matches
else { //if class don't match; die on first interface. Not really correct
return (FALSE);
}
} //else if( data_ptr->
} // while( byte_ptr < &buf + total_length
return (FALSE);
}
/* HID Keyboard probe. Called from USB state machine. */
/* assumes configuration length is less than 256 bytes */
/* looks for Class:03, Subclass: 01, Protocol: 01 in interface descriptor */
/* sets keyboard in boot protocol */
/* assumes single configuration, single endpoint, and interface configuration 0 */
BOOL HIDKProbe(BYTE addr, DWORD flags) {
BYTE tmpbyte;
BYTE rcode;
BYTE confvalue;
WORD total_length;
USB_DESCR* data_ptr = (USB_DESCR *) &bigbuf;
BYTE* byte_ptr = bigbuf;
(void) flags;
rcode = XferGetConfDescr(addr, 0, CONF_DESCR_LEN, 0, bigbuf); //get configuration descriptor
if (rcode) { //error handling
return (FALSE);
}
if (data_ptr->descr.config.wTotalLength > 256) {
total_length = 256;
} else {
total_length = data_ptr->descr.config.wTotalLength;
}
rcode = XferGetConfDescr(addr, 0, total_length, 0, bigbuf); //get the whole configuration
if (rcode) { //error handling
return (FALSE);
}
confvalue = data_ptr->descr.config.bConfigurationValue; //save configuration value to use later
while (byte_ptr < bigbuf + total_length) { //parse configuration
if (data_ptr->descr.config.bDescriptorType != USB_DESCRIPTOR_INTERFACE) { //skip to the next descriptor
byte_ptr = byte_ptr + data_ptr->descr.config.bLength;
data_ptr = (USB_DESCR*) byte_ptr;
} // if( data_ptr->descr.config.bDescriptorType != USB_DESCRIPTOR_INTERFACE
else {
//printf("starting interface parsing at byte location %d\n",
// data_ptr->descr.config.bLength);
BYTE class = data_ptr->descr.interface.bInterfaceClass;
BYTE subclass = data_ptr->descr.interface.bInterfaceSubClass;
BYTE protocol = data_ptr->descr.interface.bInterfaceProtocol;
//printf("class %x, subclass %x, protocol %x,\n", class, subclass,
// protocol);
//interface descriptor
if (class == HID_INTF && subclass == BOOT_INTF_SUBCLASS
&& protocol == HID_PROTOCOL_KEYBOARD) {
//detected a keyboard
devtable[addr].devclass = HID_K; //fill device class
tmpbyte = devtable[addr].epinfo->MaxPktSize; //save max.packet size
HID_init(); //initialize data structures
devtable[addr].epinfo = hid_ep; //switch endpoint information structure
devtable[addr].epinfo[0].MaxPktSize = tmpbyte; //fill in max.packet size
hid_device.interface =
data_ptr->descr.interface.bInterfaceNumber; //fill in interface number to be used in HID requests
hid_device.addr = addr; //fill in address
byte_ptr = byte_ptr + data_ptr->descr.config.bLength; //skip to the next descriptor
data_ptr = (USB_DESCR*) byte_ptr;
while (byte_ptr < bigbuf + total_length) {
if (data_ptr->descr.config.bDescriptorType
!= USB_DESCRIPTOR_ENDPOINT) { //skip to endpoint descriptor
byte_ptr = byte_ptr + data_ptr->descr.config.bLength;
data_ptr = (USB_DESCR*) byte_ptr;
} else {
/* fill endpoint information structure */
devtable[addr].epinfo[1].epAddr =
data_ptr->descr.endpoint.bEndpointAddress;
devtable[addr].epinfo[1].Attr =
data_ptr->descr.endpoint.bmAttributes;
devtable[addr].epinfo[1].MaxPktSize =
data_ptr->descr.endpoint.wMaxPacketSize;
devtable[addr].epinfo[1].Interval =
data_ptr->descr.endpoint.bInterval;
/* configure device */
rcode = XferSetConf(addr, 0, confvalue); //set configuration
if (rcode) { //error handling
return (FALSE);
}
rcode = XferSetProto(addr, 0, hid_device.interface,
BOOT_PROTOCOL);
if (rcode) { //error handling
return (FALSE);
} else {
return (TRUE);
}
}
} //while( byte_ptr....
} //if (Class matches
else { //if class don't match; stop processing after first interface. Not really correct
return (FALSE);
}
} //else if( data_ptr->
} // while( byte_ptr < &buf + total_length
return (FALSE);
}
/* HID data structures initialization */
void HID_init(void) {
hid_ep[1].sndToggle = bmSNDTOG0;
hid_ep[1].rcvToggle = bmRCVTOG0;
}
/* poll boot mouse */
BYTE mousePoll(BOOT_MOUSE_REPORT* buf) {
BYTE rcode;
MAXreg_wr( rPERADDR, hid_device.addr); //set peripheral address
rcode = XferInTransfer(hid_device.addr, 1, 8, (BYTE*) buf,
devtable[hid_device.addr].epinfo[1].MaxPktSize);
return (rcode);
}
/* poll boot keyboard */
BYTE kbdPoll(BOOT_KBD_REPORT* buf) {
BYTE rcode;
MAXreg_wr( rPERADDR, hid_device.addr); //set peripheral address
rcode = XferInTransfer(hid_device.addr, 1, 8, (BYTE*) buf,
devtable[hid_device.addr].epinfo[1].MaxPktSize);
return (rcode);
}
BOOL HIDMEventHandler(BYTE address, BYTE event, void *data, DWORD size) {
(void) address;
(void) event;
(void) size;
(void) data;
return (FALSE);
}
BOOL HIDKEventHandler(BYTE address, BYTE event, void *data, DWORD size) {
(void) address;
(void) event;
(void) size;
(void) data;
return (FALSE);
}

50
sw/usb/HID.h Normal file
View File

@@ -0,0 +1,50 @@
/* HID support header */
#ifndef _HID_h_
#define _HID_h
/* HID device structure */
typedef struct {
BYTE addr;
BYTE interface;
} HID_DEVICE;
/* Boot mouse report 8 bytes */
typedef struct {
// struct {
// unsigned one:1;
// unsigned two:1;
// unsigned three:1;
// unsigned :5;
// } button;
BYTE button;
BYTE Xdispl;
BYTE Ydispl;
BYTE bytes3to7[5]; //optional bytes
} BOOT_MOUSE_REPORT;
/* boot keyboard report 8 bytes */
typedef struct {
BYTE mod;
// struct {
// unsigned LCtrl:1;
// unsigned LShift:1;
// unsigned LAlt:1;
// unsigned LWin:1;
// /**/
// unsigned RCtrl:1;
// unsigned RShift:1;
// unsigned RAlt:1;
// unsigned RWin:1;
// } mod;
BYTE reserved;
BYTE keycode[6];
} BOOT_KBD_REPORT;
/* Function prototypes */
BOOL HIDMProbe(BYTE address, DWORD flags);
BOOL HIDKProbe(BYTE address, DWORD flags);
void HID_init(void);
BYTE mousePoll(BOOT_MOUSE_REPORT* buf);
BYTE kbdPoll(BOOT_KBD_REPORT* buf);
BOOL HIDMEventHandler(BYTE addr, BYTE event, void *data, DWORD size);
BOOL HIDKEventHandler(BYTE addr, BYTE event, void *data, DWORD size);
#endif // _HID_h_

250
sw/usb/MAX3421E.c Normal file
View File

@@ -0,0 +1,250 @@
//Fill in your low-level SPI functions here, as per your host platform
#define _MAX3421E_C_
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "project_config.h"
#include <spi.h>
#include <gpio.h>
#include <unistd.h>
//variables and data structures
//External variables
extern BYTE usb_task_state;
uint8_t* usb_gpio = USB_GPIO;
/* Functions */
void SPI_init(BYTE sync_mode, BYTE bus_mode, BYTE smp_phase) {
//Don't need to initialize SPI port, already ready to go with BSP
(void) sync_mode;
(void) bus_mode;
(void) smp_phase;
}
//writes single byte to MAX3421E via SPI, simultanously reads status register and returns it
BYTE SPI_wr(BYTE data) {
(void) data;
//This function is never used by the code, so you do not need to fill it in
return -1;
}
//writes register to MAX3421E via SPI
void MAXreg_wr(BYTE reg, BYTE val) {
//psuedocode:
//select MAX3421E (may not be necessary if you are using SPI peripheral)
//write reg + 2 via SPI
//write val via SPI
//read return code from SPI peripheral (see Intel documentation)
//if return code < 0 print an error
//deselect MAX3421E (may not be necessary if you are using SPI peripheral)
BYTE regdir = reg + 2; //reg bitshift plus direction bit.
spi_byte(regdir);
spi_byte(val);
spi_deselect();
}
//multiple-byte write
//returns a pointer to a memory position after last written
BYTE* MAXbytes_wr(BYTE reg, BYTE nbytes, BYTE* data) {
//psuedocode:
//select MAX3421E (may not be necessary if you are using SPI peripheral)
//write reg + 2 via SPI
//write data[n] via SPI, where n goes from 0 to nbytes-1
//read return code from SPI peripheral (see Intel documentation)
//if return code < 0 print an error
//deselect MAX3421E (may not be necessary if you are using SPI peripheral)
//return (data + nbytes);
int i;
BYTE regdir = reg + 2;
spi_byte(regdir);
for (i = 0; i < nbytes; i++){
spi_byte(data[i]);
}
spi_deselect();
return data + nbytes;
}
//reads register from MAX3421E via SPI
BYTE MAXreg_rd(BYTE reg) {
//psuedocode:
//select MAX3421E (may not be necessary if you are using SPI peripheral)
//write reg via SPI
//read val via SPI
//read return code from SPI peripheral (see Intel documentation)
//if return code < 0 print an error
//deselect MAX3421E (may not be necessary if you are using SPI peripheral)
//return val
BYTE regdir = reg;
BYTE rxdata;
spi_byte(regdir);
rxdata = spi_byte(0);
spi_deselect();
return rxdata;
}
//multiple-byte write
//returns a pointer to a memory position after last written
BYTE* MAXbytes_rd(BYTE reg, BYTE nbytes, BYTE* data) {
//psuedocode:
//select MAX3421E (may not be necessary if you are using SPI peripheral)
//write reg via SPI
//read data[n] from SPI, where n goes from 0 to nbytes-1
//read return code from SPI peripheral (see Intel documentation)
//if return code < 0 print an error
//deselect MAX3421E (may not be necessary if you are using SPI peripheral)
//return (data + nbytes);
int i;
BYTE regdir = reg;
spi_byte(regdir);
for (i = 0; i < nbytes; i++){
data[i] = spi_byte(0);
}
spi_deselect();
return data + nbytes;
}
/* reset MAX3421E using chip reset bit. SPI configuration is not affected */
void MAX3421E_reset(void) {
//hardware reset, then software reset
BYTE tmp;
*usb_gpio &= ~USB_GPIO_RST;
//TODO
//sleep(1);
*usb_gpio |= USB_GPIO_RST;
tmp = 0;
MAXreg_wr( rUSBCTL, bmCHIPRES); //Chip reset. This stops the oscillator
MAXreg_wr( rUSBCTL, 0x00); //Remove the reset
while (!(MAXreg_rd( rUSBIRQ) & bmOSCOKIRQ)) { //wait until the PLL stabilizes
tmp++; //timeout after 256 attempts
if (tmp == 0) {
//printf("reset timeout!");
}
}
}
/* turn USB power on/off */
/* ON pin of VBUS switch (MAX4793 or similar) is connected to GPOUT7 */
/* OVERLOAD pin of Vbus switch is connected to GPIN7 */
/* OVERLOAD state low. NO OVERLOAD or VBUS OFF state high. */
BOOL Vbus_power(BOOL action) {
// power on/off successful
return (1);
}
/* probe bus to determine device presense and speed */
void MAX_busprobe(void) {
BYTE bus_sample;
// MAXreg_wr(rHCTL,bmSAMPLEBUS);
bus_sample = MAXreg_rd( rHRSL); //Get J,K status
bus_sample &= ( bmJSTATUS | bmKSTATUS); //zero the rest of the byte
switch (bus_sample) { //start full-speed or low-speed host
case ( bmJSTATUS):
/*kludgy*/
if (usb_task_state != USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE) { //bus reset causes connection detect interrupt
if (!(MAXreg_rd( rMODE) & bmLOWSPEED)) {
MAXreg_wr( rMODE, MODE_FS_HOST); //start full-speed host
//printf("Starting in full speed\n");
} else {
MAXreg_wr( rMODE, MODE_LS_HOST); //start low-speed host
//printf("Starting in low speed\n");
}
usb_task_state = ( USB_STATE_ATTACHED); //signal usb state machine to start attachment sequence
}
break;
case ( bmKSTATUS):
if (usb_task_state != USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE) { //bus reset causes connection detect interrupt
if (!(MAXreg_rd( rMODE) & bmLOWSPEED)) {
MAXreg_wr( rMODE, MODE_LS_HOST); //start low-speed host
//printf("Starting in low speed\n");
} else {
MAXreg_wr( rMODE, MODE_FS_HOST); //start full-speed host
//printf("Starting in full speed\n");
}
usb_task_state = ( USB_STATE_ATTACHED); //signal usb state machine to start attachment sequence
}
break;
case ( bmSE1): //illegal state
usb_task_state = ( USB_DETACHED_SUBSTATE_ILLEGAL);
break;
case ( bmSE0): //disconnected state
if (!((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED)) //if we came here from other than detached state
usb_task_state = ( USB_DETACHED_SUBSTATE_INITIALIZE); //clear device data structures
else {
MAXreg_wr( rMODE, MODE_FS_HOST); //start full-speed host
usb_task_state = ( USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE);
}
break;
} //end switch( bus_sample )
}
/* MAX3421E initialization after power-on */
void MAX3421E_init(void) {
/* Configure full-duplex SPI, interrupt pulse */
MAXreg_wr( rPINCTL, (bmFDUPSPI + bmINTLEVEL + bmGPXB)); //Full-duplex SPI, level interrupt, GPX
MAX3421E_reset(); //stop/start the oscillator
/* configure power switch */
Vbus_power( OFF); //turn Vbus power off
MAXreg_wr( rGPINIEN, bmGPINIEN7); //enable interrupt on GPIN7 (power switch overload flag)
Vbus_power( ON);
/* configure host operation */
MAXreg_wr( rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ); // set pull-downs, SOF, Host, Separate GPIN IRQ on GPX
//MAXreg_wr( rHIEN, bmFRAMEIE|bmCONDETIE|bmBUSEVENTIE ); // enable SOF, connection detection, bus event IRQs
MAXreg_wr( rHIEN, bmCONDETIE); //connection detection
/* HXFRDNIRQ is checked in Dispatch packet function */
MAXreg_wr(rHCTL, bmSAMPLEBUS); // update the JSTATUS and KSTATUS bits
MAX_busprobe(); //check if anything is connected
MAXreg_wr( rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
MAXreg_wr( rCPUCTL, 0x01); //enable interrupt pin
}
/* MAX3421 state change task and interrupt handler */
void MAX3421E_Task(void) {
if ((*usb_gpio & USB_GPIO_IRQ) == 0) {
//printf("MAX interrupt\n\r");
MaxIntHandler();
}
if ((*usb_gpio & USB_GPIO_GPX) != 0) {
//printf("GPX interrupt\n\r");
MaxGpxHandler();
}
}
void MaxIntHandler(void) {
BYTE HIRQ;
BYTE HIRQ_sendback = 0x00;
HIRQ = MAXreg_rd( rHIRQ); //determine interrupt source
//printf("IRQ: %x\n", HIRQ);
if (HIRQ & bmFRAMEIRQ) { //->1ms SOF interrupt handler
HIRQ_sendback |= bmFRAMEIRQ;
} //end FRAMEIRQ handling
if (HIRQ & bmCONDETIRQ) {
MAX_busprobe();
HIRQ_sendback |= bmCONDETIRQ; //set sendback to 1 to clear register
}
if (HIRQ & bmSNDBAVIRQ) //if the send buffer is clear (previous transfer completed without issue)
{
MAXreg_wr(rSNDBC, 0x00);//clear the send buffer (not really necessary, but clears interrupt)
}
if (HIRQ & bmBUSEVENTIRQ) { //bus event is either reset or suspend
usb_task_state++; //advance USB task state machine
HIRQ_sendback |= bmBUSEVENTIRQ;
}
/* End HIRQ interrupts handling, clear serviced IRQs */
MAXreg_wr( rHIRQ, HIRQ_sendback); //write '1' to CONDETIRQ to ack bus state change
}
void MaxGpxHandler(void) {
BYTE GPINIRQ;
GPINIRQ = MAXreg_rd( rGPINIRQ); //read both IRQ registers
}

250
sw/usb/MAX3421E.h Normal file
View File

@@ -0,0 +1,250 @@
/* MAX3421E support header */
/* Register names and bit masks for MAX3421 in host mode */
/* Function prototypes in MAX3421E.c */
#ifndef _MAX3421E_H_
#define _MAX3421E_H_
#define USB_GPIO_RST (1 << 0)
#define USB_GPIO_IRQ (1 << 1)
#define USB_GPIO_GPX (1 << 2)
/* SPI interface definitions */
/* SSPSTAT REGISTER */
// Master SPI mode only
#define SMPEND 0x80 // Input data sample at end of data out
#define SMPMID 0x00 // Input data sample at middle of data out
#define MODE_00 0 // Setting for SPI bus Mode 0,0
//CKE 0x40 // SSPSTAT register
//CKP 0x00 // SSPCON1 register
#define MODE_01 1 // Setting for SPI bus Mode 0,1
//CKE 0x00 // SSPSTAT register
//CKP 0x00 // SSPCON1 register
#define MODE_10 2 // Setting for SPI bus Mode 1,0
//CKE 0x40 // SSPSTAT register
//CKP 0x10 // SSPCON1 register
#define MODE_11 3 // Setting for SPI bus Mode 1,1
//CKE 0x00 // SSPSTAT register
//CKP 0x10 // SSPCON1 register
/* SSPCON1 REGISTER */
#define SSPENB 0x20 // Enable serial port and configures SCK, SDO, SDI
#define SPI_FOSC_4 0 // SPI Master mode, clock = Fosc/4
#define SPI_FOSC_16 1 // SPI Master mode, clock = Fosc/16
#define SPI_FOSC_64 2 // SPI Master mode, clock = Fosc/64
#define SPI_FOSC_TMR2 3 // SPI Master mode, clock = TMR2 output/2
#define SLV_SSON 4 // SPI Slave mode, /SS pin control enabled
#define SLV_SSOFF 5 // SPI Slave mode, /SS pin control disabled
/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */
//
// MAX3421E Registers in HOST mode.
//
#define rRCVFIFO 0x08 //1<<3
#define rSNDFIFO 0x10 //2<<3
#define rSUDFIFO 0x20 //4<<3
#define rRCVBC 0x30 //6<<3
#define rSNDBC 0x38 //7<<3
#define rUSBIRQ 0x68 //13<<3
/* USBIRQ Bits */
#define bmVBUSIRQ 0x40 //b6
#define bmNOVBUSIRQ 0x20 //b5
#define bmOSCOKIRQ 0x01 //b0
#define rUSBIEN 0x70 //14<<3
/* USBIEN Bits */
#define bmVBUSIE 0x40 //b6
#define bmNOVBUSIE 0x20 //b5
#define bmOSCOKIE 0x01 //b0
#define rUSBCTL 0x78 //15<<3
/* USBCTL Bits */
#define bmCHIPRES 0x20 //b5
#define bmPWRDOWN 0x10 //b4
#define rCPUCTL 0x80 //16<<3
/* CPUCTL Bits */
#define bmPUSLEWID1 0x80 //b7
#define bmPULSEWID0 0x40 //b6
#define bmIE 0x01 //b0
#define rPINCTL 0x88 //17<<3
/* PINCTL Bits */
#define bmFDUPSPI 0x10 //b4
#define bmINTLEVEL 0x08 //b3
#define bmPOSINT 0x04 //b2
#define bmGPXB 0x02 //b1
#define bmGPXA 0x01 //b0
// GPX pin selections
#define GPX_OPERATE 0x00
#define GPX_VBDET 0x01
#define GPX_BUSACT 0x02
#define GPX_SOF 0x03
#define rREVISION 0x90 //18<<3
#define rIOPINS1 0xa0 //20<<3
/* IOPINS1 Bits */
#define bmGPOUT0 0x01
#define bmGPOUT1 0x02
#define bmGPOUT2 0x04
#define bmGPOUT3 0x08
#define bmGPIN0 0x10
#define bmGPIN1 0x20
#define bmGPIN2 0x40
#define bmGPIN3 0x80
#define rIOPINS2 0xa8 //21<<3
/* IOPINS2 Bits */
#define bmGPOUT4 0x01
#define bmGPOUT5 0x02
#define bmGPOUT6 0x04
#define bmGPOUT7 0x08
#define bmGPIN4 0x10
#define bmGPIN5 0x20
#define bmGPIN6 0x40
#define bmGPIN7 0x80
#define rGPINIRQ 0xb0 //22<<3
/* GPINIRQ Bits */
#define bmGPINIRQ0 0x01
#define bmGPINIRQ1 0x02
#define bmGPINIRQ2 0x04
#define bmGPINIRQ3 0x08
#define bmGPINIRQ4 0x10
#define bmGPINIRQ5 0x20
#define bmGPINIRQ6 0x40
#define bmGPINIRQ7 0x80
#define rGPINIEN 0xb8 //23<<3
/* GPINIEN Bits */
#define bmGPINIEN0 0x01
#define bmGPINIEN1 0x02
#define bmGPINIEN2 0x04
#define bmGPINIEN3 0x08
#define bmGPINIEN4 0x10
#define bmGPINIEN5 0x20
#define bmGPINIEN6 0x40
#define bmGPINIEN7 0x80
#define rGPINPOL 0xc0 //24<<3
/* GPINPOL Bits */
#define bmGPINPOL0 0x01
#define bmGPINPOL1 0x02
#define bmGPINPOL2 0x04
#define bmGPINPOL3 0x08
#define bmGPINPOL4 0x10
#define bmGPINPOL5 0x20
#define bmGPINPOL6 0x40
#define bmGPINPOL7 0x80
#define rHIRQ 0xc8 //25<<3
/* HIRQ Bits */
#define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume
#define bmRWUIRQ 0x02
#define bmRCVDAVIRQ 0x04
#define bmSNDBAVIRQ 0x08
#define bmSUSDNIRQ 0x10
#define bmCONDETIRQ 0x20
#define bmFRAMEIRQ 0x40
#define bmHXFRDNIRQ 0x80
#define rHIEN 0xd0 //26<<3
/* HIEN Bits */
#define bmBUSEVENTIE 0x01
#define bmRWUIE 0x02
#define bmRCVDAVIE 0x04
#define bmSNDBAVIE 0x08
#define bmSUSDNIE 0x10
#define bmCONDETIE 0x20
#define bmFRAMEIE 0x40
#define bmHXFRDNIE 0x80
#define rMODE 0xd8 //27<<3
/* MODE Bits */
#define bmHOST 0x01
#define bmLOWSPEED 0x02
#define bmHUBPRE 0x04
#define bmSOFKAENAB 0x08
#define bmSEPIRQ 0x10
#define bmDELAYISO 0x20
#define bmDMPULLDN 0x40
#define bmDPPULLDN 0x80
#define rPERADDR 0xe0 //28<<3
#define rHCTL 0xe8 //29<<3
/* HCTL Bits */
#define bmBUSRST 0x01
#define bmFRMRST 0x02
#define bmSAMPLEBUS 0x04
#define bmSIGRSM 0x08
#define bmRCVTOG0 0x10
#define bmRCVTOG1 0x20
#define bmSNDTOG0 0x40
#define bmSNDTOG1 0x80
#define rHXFR 0xf0 //30<<3
/* Host transfer token values for writing the HXFR register (R30) */
/* OR this bit field with the endpoint number in bits 3:0 */
#define tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1
#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
#define rHRSL 0xf8 //31<<3
/* HRSL Bits */
#define bmRCVTOGRD 0x10
#define bmSNDTOGRD 0x20
#define bmKSTATUS 0x40
#define bmJSTATUS 0x80
#define bmSE0 0x00 //SE0 - disconnect state
#define bmSE1 0xc0 //SE1 - illegal state
/* Host error result codes, the 4 LSB's in the HRSL register */
#define hrSUCCESS 0x00
#define hrBUSY 0x01
#define hrBADREQ 0x02
#define hrUNDEF 0x03
#define hrNAK 0x04
#define hrSTALL 0x05
#define hrTOGERR 0x06
#define hrWRONGPID 0x07
#define hrBADBC 0x08
#define hrPIDERR 0x09
#define hrPKTERR 0x0A
#define hrCRCERR 0x0B
#define hrKERR 0x0C
#define hrJERR 0x0D
#define hrTIMEOUT 0x0E
#define hrBABBLE 0x0F
#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB)
#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB)
/* MAX3421E.c function prototypes */
void SPI_init(BYTE sync_mode, BYTE bus_mode, BYTE smp_phase);
BYTE SPI_wr(BYTE data);
void MAXreg_wr(BYTE reg, BYTE val);
BYTE* MAXbytes_wr(BYTE reg, BYTE nbytes, BYTE * data);
BYTE MAXreg_rd(BYTE reg);
BYTE* MAXbytes_rd(BYTE reg, BYTE nbytes, BYTE *data);
void MAX3421E_reset(void);
BOOL Vbus_power(BOOL action);
void MAX3421E_init(void);
void MAX_busprobe(void);
void MAX3421E_Task(void);
void MaxIntHandler(void);
void MaxGpxHandler(void);
#endif //_MAX3421E_H_

12
sw/usb/README Normal file
View File

@@ -0,0 +1,12 @@
This is a project directory of Lightweight USB host for Microchip PIC18 and Maxim MAX3421E USB Host controller.
This is a migration from FreeRTOS implementation, which I decided to stop developing because the end product will not fit into PIC18.
Therefore, you will find fragments of strange code every now and then.
The code is compiled using Microchip C18 compiler in MPLAB. MPLAB project file is provided but not guaranteed to work on your system
due to absolute path issue. You can manually edit the .mcp file or make your own. The project uses standard linker script and headers.
In addition, logic analyzer trace is provided in LPF file. Too see the trace you will need to download Logicport software from Intronix,
http://www.pctestinstruments.com/downloads.htm
For hardware implementation information go to http://www.circuitsathome.com

277
sw/usb/USB.h Normal file
View File

@@ -0,0 +1,277 @@
/* USB task support header */
#ifndef _USB_h_
#define _USB_h_
// *****************************************************************************
// Section: State Machine Constants
// *****************************************************************************
/* States are defined by 4 high bits
Substates are defined by 4 low bits */
#define USB_STATE_MASK 0xf0 //
#define USB_SUBSTATE_MASK 0x0f //
#define SUBSUBSTATE_MASK 0x000F //
#define NEXT_STATE 0x0100 //
#define NEXT_SUBSTATE 0x0010 //
#define NEXT_SUBSUBSTATE 0x0001 //
#define SUBSUBSTATE_ERROR 0x000F //
#define NO_STATE 0xFFFF //
/*
*******************************************************************************
DETACHED state machine values
This state machine handles the condition when no device is attached.
*/
#define USB_STATE_DETACHED 0x00
#define USB_DETACHED_SUBSTATE_INITIALIZE 0x01
#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x03
#define USB_DETACHED_SUBSTATE_ILLEGAL 0x04
/*
*******************************************************************************
ATTACHED state machine values
This state machine gets the device descriptor of the remote device. We get the
size of the device descriptor, and use that size to get the entire device
descriptor. Then we check the VID and PID and make sure they appear in the TPL.
*/
#define USB_STATE_ATTACHED 0x10
#define USB_ATTACHED_SUBSTATE_SETTLE 0x11
#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x12
#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x13
#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x14
#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x15
//#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR 0x16
//#define USB_ATTACHED_SUBSTATE_VALIDATE_VID_PID 0x17
//#define USB_ATTACHED_SUBSTATE_VALIDATE_CLSP 0x18
/*
*******************************************************************************
ADDRESSING state machine values
This state machine sets the address of the remote device.
*/
#define USB_STATE_ADDRESSING 0x20
/*
*******************************************************************************
CONFIGURING state machine values
This state machine sets the configuration of the remote device, and sets up
internal variables to support the device.
*/
#define USB_STATE_CONFIGURING 0x30
/*
*******************************************************************************
RUNNING state machine values
*/
#define USB_STATE_RUNNING 0x40
//#define RUNNING_SUBSTATE_NORMAL_RUN 0x0000 //
//#define RUNNING_SUBSTATE_SUSPEND_AND_RESUME 0x0010 //
//#define RUNNING_SUBSUBSTATE_SUSPEND 0x0000 //
//#define RUNNING_SUBSUBSTATE_RESUME 0x0001 //
//#define RUNNING_SUBSUBSTATE_RESUME_WAIT 0x0002 //
//#define RUNNING_SUBSUBSTATE_RESUME_RECOVERY 0x0003 //
//#define RUNNING_SUBSUBSTATE_RESUME_RECOVERY_WAIT 0x0004 //
//#define RUNNING_SUBSUBSTATE_RESUME_COMPLETE 0x0005 //
/*
*******************************************************************************
HOLDING state machine values
*/
#define STATE_HOLDING 0x50 //
#define HOLDING_SUBSTATE_HOLD_INIT 0x0000 //
#define HOLDING_SUBSTATE_HOLD 0x0001 //
/* Error state machine state. Non-recoverable */
#define USB_STATE_ERROR 0xff
// *****************************************************************************
// Section: Token State Machine Constants
// *****************************************************************************
#define TSTATE_MASK 0x00F0 //
#define TSUBSTATE_MASK 0x000F //
#define TSUBSTATE_ERROR 0x000F //
#define TSTATE_IDLE 0x0000 //
#define TSTATE_CONTROL_NO_DATA 0x0010 //
#define TSUBSTATE_CONTROL_NO_DATA_SETUP 0x0000 //
#define TSUBSTATE_CONTROL_NO_DATA_ACK 0x0001 //
#define TSUBSTATE_CONTROL_NO_DATA_COMPLETE 0x0002 //
#define TSTATE_CONTROL_READ 0x0020 //
#define TSUBSTATE_CONTROL_READ_SETUP 0x0000 //
#define TSUBSTATE_CONTROL_READ_DATA 0x0001 //
#define TSUBSTATE_CONTROL_READ_ACK 0x0002 //
#define TSUBSTATE_CONTROL_READ_COMPLETE 0x0003 //
#define TSTATE_CONTROL_WRITE 0x0030 //
#define TSUBSTATE_CONTROL_WRITE_SETUP 0x0000 //
#define TSUBSTATE_CONTROL_WRITE_DATA 0x0001 //
#define TSUBSTATE_CONTROL_WRITE_ACK 0x0002 //
#define TSUBSTATE_CONTROL_WRITE_COMPLETE 0x0003 //
#define TSTATE_INTERRUPT_READ 0x0040 //
#define TSUBSTATE_INTERRUPT_READ_DATA 0x0000 //
#define TSUBSTATE_INTERRUPT_READ_COMPLETE 0x0001 //
#define TSTATE_INTERRUPT_WRITE 0x0050 //
#define TSUBSTATE_INTERRUPT_WRITE_DATA 0x0000 //
#define TSUBSTATE_INTERRUPT_WRITE_COMPLETE 0x0001 //
#define TSTATE_ISOCHRONOUS_READ 0x0060 //
#define TSUBSTATE_ISOCHRONOUS_READ_DATA 0x0000 //
#define TSUBSTATE_ISOCHRONOUS_READ_COMPLETE 0x0001 //
#define TSTATE_ISOCHRONOUS_WRITE 0x0070 //
#define TSUBSTATE_ISOCHRONOUS_WRITE_DATA 0x0000 //
#define TSUBSTATE_ISOCHRONOUS_WRITE_COMPLETE 0x0001 //
#define TSTATE_BULK_READ 0x0080 //
#define TSUBSTATE_BULK_READ_DATA 0x0000 //
#define TSUBSTATE_BULK_READ_COMPLETE 0x0001 //
#define TSTATE_BULK_WRITE 0x0090 //
#define TSUBSTATE_BULK_WRITE_DATA 0x0000 //
#define TSUBSTATE_BULK_WRITE_COMPLETE 0x0001 //
// ************************
// Standard USB Requests
#define SR_GET_STATUS 0x00 // Get Status
#define SR_CLEAR_FEATURE 0x01 // Clear Feature
#define SR_RESERVED 0x02 // Reserved
#define SR_SET_FEATURE 0x03 // Set Feature
#define SR_SET_ADDRESS 0x05 // Set Address
#define SR_GET_DESCRIPTOR 0x06 // Get Descriptor
#define SR_SET_DESCRIPTOR 0x07 // Set Descriptor
#define SR_GET_CONFIGURATION 0x08 // Get Configuration
#define SR_SET_CONFIGURATION 0x09 // Set Configuration
#define SR_GET_INTERFACE 0x0a // Get Interface
#define SR_SET_INTERFACE 0x0b // Set Interface
// Get Descriptor codes
#define GD_DEVICE 0x01 // Get device descriptor: Device
#define GD_CONFIGURATION 0x02 // Get device descriptor: Configuration
#define GD_STRING 0x03 // Get device descriptor: String
#define GD_HID 0x21 // Get descriptor: HID
#define GD_REPORT 0x22 // Get descriptor: Report
// HID bRequest values
#define GET_REPORT 1
#define GET_IDLE 2
#define GET_PROTOCOL 3
#define SET_REPORT 9
#define SET_IDLE 0x0A
#define SET_PROTOCOL 0x0B
#define INPUT_REPORT 1
////******************************************************************************
////******************************************************************************
//// Section: Macros
////
//// These macros are all internal to the host layer.
////******************************************************************************
////******************************************************************************
//
//#define _USB_InitErrorCounters() { numCommandTries = USB_NUM_COMMAND_TRIES; }
//#define _USB_SetDATA01(x) { pCurrentEndpoint->status.bfNextDATA01 = x; }
//#define _USB_SetErrorCode(x) { usbDeviceInfo.errorCode = x; }
//#define _USB_SetHoldState() { usbHostState = STATE_HOLDING; }
//#define _USB_SetNextState() { usbHostState = (usbHostState & STATE_MASK) + NEXT_STATE; }
//#define _host_tasks_SetNextSubState() { host_tasks_state =( host_tasks_state & (STATE_MASK | SUBSTATE_MASK)) + NEXT_SUBSTATE; }
//#define _USB_SetNextSubSubState() { usbHostState = usbHostState + NEXT_SUBSUBSTATE; }
//#define _USB_SetNextTransferState() { pCurrentEndpoint->transferState ++; }
//#define _USB_SetPreviousSubSubState() { usbHostState = usbHostState - NEXT_SUBSUBSTATE; }
//#define _USB_SetTransferErrorState(x) { x->transferState = (x->transferState & TSTATE_MASK) | TSUBSTATE_ERROR; }
//#define freez(x) { free(x); x = NULL; }
/* data structures */
// *****************************************************************************
/* USB Mass Storage Device Information
This structure is used to hold all the information about an attached Mass Storage device.
*/
typedef struct _USB_MSD_DEVICE_INFO {
BYTE blockData[31]; // Data buffer for device communication.
BYTE deviceAddress; // Address of the device on the bus.
BYTE errorCode; // Error code of last error.
BYTE state; // State machine state of the device.
BYTE returnState; // State to return to after performing error handling.
union {
struct {
unsigned int bfDirection :1; // Direction of current transfer (0=OUT, 1=IN).
unsigned int bfReset :1; // Flag indicating to perform Mass Storage Reset.
unsigned int bfClearDataIN :1; // Flag indicating to clear the IN endpoint.
unsigned int bfClearDataOUT :1; // Flag indicating to clear the OUT endpoint.
};
BYTE val;
} flags;
BYTE maxLUN; // The maximum Logical Unit Number of the device.
BYTE interface; // Interface number we are using.
BYTE epin_idx; // Bulk IN endpoint index in devinfo.epinfo_ptr[].
BYTE epout_idx; // Bulk OUT endpoint index in devinfo.epinfo_ptr[].
BYTE endpointDATA; // Endpoint to use for the current transfer.
BYTE *userData; // Pointer to the user's data buffer.
DWORD userDataLength; // Length of the user's data buffer.
DWORD bytesTransferred; // Number of bytes transferred to/from the user's data buffer.
DWORD dCBWTag; // The value of the dCBWTag to verify against the dCSWtag.
BYTE attemptsCSW; // Number of attempts to retrieve the CSW.
} USB_MSD_DEVICE_INFO;
///* class driver event handler */
//typedef BOOL (* rom CLASS_EVENT_HANDLER) ( BYTE address, BYTE event, void *data, DWORD size );
//
///* class driver initialization */
//typedef BOOL (* rom CLASS_INIT) ( BYTE address, DWORD flags );
//
//// *****************************************************************************
///* Client Driver Table Structure
//
// */
//
//typedef struct _CLASS_CALLBACK_TABLE
//{
// CLASS_INIT Initialize; // Initialization routine
// CLASS_EVENT_HANDLER EventHandler; // Event routine
// DWORD flags; // Initialization flags
//
//} CLASS_CALLBACK_TABLE;
//* Functions */
//
//void vUSBtask_init( void );
//void vUSB_task( void *pvParameters );
//void prvUSBdata_init( void );
//char bUSB_Control_Write_ND( BYTE addr, BYTE ep );
//char bUSB_Control_Read( BYTE addr, BYTE ep );
//char bUSB_IN_Transfer( BYTE ep, WORD nbytes, BYTE maxpktsize, BYTE * data );
//char bUSB_Dispatch_Pkt( BYTE token, BYTE ep );
//BOOL prvMSDInit( BYTE address, DWORD flags );
//BOOL prvMSDEventHandler( BYTE address, BYTE event, void *data, DWORD size );
//BOOL prvCDCProbe( BYTE address, DWORD flags );
//BOOL prvCDCEventHandler( BYTE address, BYTE event, void *data, DWORD size );
//BOOL prvDummyProbe( BYTE address , DWORD flags );
//BOOL prvDummyEventHandler( BYTE address, BYTE event, void *data, DWORD size );
//BYTE flush_Q( xQueueHandle QueueH );
#endif //_USB_h_

22
sw/usb/project_config.h Normal file
View File

@@ -0,0 +1,22 @@
/* Project name project configuration file */
#ifndef _project_config_h_
#define _project_config_h_
#include "GenericMacros.h"
#include "GenericTypeDefs.h"
#include "HID.h"
#include "MAX3421E.h"
#include "transfer.h"
#include "usb_ch9.h"
#include "USB.h"
/* USB constants */
/* time in milliseconds */
#define USB_SETTLE_TIME 200 //USB settle after reset
#define USB_XFER_TIMEOUT 5000 //USB transfer timeout
#define USB_NAK_LIMIT 2
#define USB_RETRY_LIMIT 3
#endif // _project_config_h

475
sw/usb/transfer.c Normal file
View File

@@ -0,0 +1,475 @@
/* USB transfers */
#define _transfer_c_
#include "project_config.h"
#include <stdio.h>
EP_RECORD dev0ep = {{ 0 }}; //Endpoint data structure for uninitialized device during enumeration
EP_RECORD msd_ep[ 3 ] = {{ 0 }}; //Mass storage bulk-only transport endpoints: 1 control and 2 bulk, IN and OUT
//ep records for other classes are defined in class-specific modules
/* macros to aid filling in TPL */
#define INIT_VID_PID(v,p) 0x##p##v
#define INIT_CL_SC_P(c,s,p) 0x##00##p##s##c
//const rom USB_TPL_ENTRY TplTable[ USB_NUMTARGETS + 1 ] = {
//// VID & PID or Client
//// Class, Subclass & Protocol Config Numep Eprecord Driver
//{ INIT_VID_PID( 0000, 0000 ), 0, 1, &dev0ep, 0, "Uninitialized" },
//{ INIT_VID_PID( 0781, 5406 ), 0, 3, msd_ep, MSD_DRIVER, "Mass storage" }, //Sandisk U3 Cruzer Micro
////{ INIT_VID_PID( 0CF2, 6220 ), 0, 0 }, //ENE UB6220
//{ INIT_CL_SC_P( 03, 01, 02 ), 0, 3, hid_ep, HIDM_DRIVER, "HID Mouse with Boot protocol" }, //
//{ INIT_VID_PID( aaaa, 5555 ), 0, 1, NULL, 0, NULL }, //
//{ INIT_CL_SC_P( 08, 06, 50 ), 0, 3, msd_ep, MSD_DRIVER, "Mass storage" } //Mass storage bulk only class
//};
/* control transfers function pointers */
const CTRL_XFER ctrl_xfers[ 2 ] = {
XferCtrlND,
XferCtrlData
};
/* device table. Filled during enumeration */
/* index corresponds to device address */
/* each entry contains pointer to endpoint structure */
/* and device class to use in various places */
DEV_RECORD devtable[ USB_NUMDEVICES + 1 ];
/* Client Driver Function Pointer Table */
CLASS_CALLBACK_TABLE ClientDriverTable[ USB_NUMCLASSES ] = {
{
MSDProbe, //Mass storage class device init
MSDEventHandler,
0
},
{
HIDMProbe, //HID class device init
HIDMEventHandler,
0
},
{
HIDKProbe,
HIDKEventHandler,
0
},
{
DummyProbe,
DummyEventHandler,
0
}
};
/* Control transfer stages function pointer table */
/* USB state machine related variables */
BYTE usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
BYTE usb_error;
BYTE last_usb_task_state = 0;
/* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */
/* depending on request. Actual requests are defined as macros */
/* return codes: */
/* 00 = success */
/* 01-0f = non-zero HRSLT */
BYTE XferCtrlReq( BYTE addr, BYTE ep, BYTE bmReqType, BYTE bRequest, BYTE wValLo, BYTE wValHi, WORD wInd, WORD nbytes, BYTE* dataptr )
{
BOOL direction = FALSE; //request direction, IN or OUT
BYTE datastage = 1; //request data stage present or absent
BYTE rcode;
SETUP_PKT setup_pkt;
if( dataptr == NULL ) {
datastage = 0;
}
MAXreg_wr( rPERADDR, addr ); //set peripheral address
/* fill in setup packet */
if( bmReqType & 0x80 ) {
direction = TRUE; //determine request direction
}
/* fill in setup packet */
setup_pkt.ReqType_u.bmRequestType = bmReqType;
setup_pkt.bRequest = bRequest;
setup_pkt.wVal_u.wValueLo = wValLo;
setup_pkt.wVal_u.wValueHi = wValHi;
setup_pkt.wIndex = wInd;
setup_pkt.wLength = nbytes;
MAXbytes_wr( rSUDFIFO, 8, (BYTE *)&setup_pkt ); //transfer to setup packet FIFO
rcode = XferDispatchPkt( tokSETUP, ep ); //dispatch packet
if( rcode ) { //return HRSLT if not zero
return( rcode );
}
rcode = ctrl_xfers[ datastage ]( addr, ep, nbytes, dataptr, direction ); //call data stage or no data stage transfer
return( rcode );
}
/* Control transfer with data stage */
BYTE XferCtrlData( BYTE addr, BYTE ep, WORD nbytes, BYTE* dataptr, BOOL direction )
{
BYTE rcode;
//MAXreg_wr( rHCTL, bmRCVTOG1 ); //set toggle to DATA1
if( direction ) { //IN transfer
devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1;
rcode = XferInTransfer( addr, ep, nbytes, dataptr, devtable[ addr ].epinfo[ ep ].MaxPktSize );
if( rcode ) {
return( rcode );
}
rcode = XferDispatchPkt( tokOUTHS, ep );
return( rcode );
}
else { //OUT not implemented
return( 0xff );
}
}
/* Control transfer with status stage and no data stage */
BYTE XferCtrlND( BYTE addr, BYTE ep, WORD nbytes, BYTE* dataptr, BOOL direction )
{
BYTE rcode;
(void) addr;
(void) nbytes;
(void) dataptr;
if( direction ) { //GET
rcode = XferDispatchPkt( tokOUTHS, ep );
}
else {
rcode = XferDispatchPkt( tokINHS, ep );
}
return( rcode );
}
/* Dispatch a packet. Assumes peripheral address is set and, if necessary, sudFIFO-sendFIFO loaded. */
/* Result code: 0 success, nonzero = error condition */
/* If NAK, tries to re-send up to USB_NAK_LIMIT times */
/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
/* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */
BYTE XferDispatchPkt( BYTE token, BYTE ep )
{
DWORD timeout = 0;//(alt_nticks()*1000)/alt_ticks_per_second() + USB_XFER_TIMEOUT;
BYTE tmpdata;
BYTE rcode;
char retry_count = 0;
BYTE nak_count = 0;
while( 1 ) {
MAXreg_wr( rHXFR, ( token|ep )); //launch the transfer
rcode = 0xff;
/*
while( (alt_nticks()*1000)/alt_ticks_per_second() < timeout ) {
tmpdata = MAXreg_rd( rHIRQ );
if( tmpdata & bmHXFRDNIRQ ) {
MAXreg_wr( rHIRQ, bmHXFRDNIRQ ); //clear the interrupt
rcode = 0x00;
break;
}
}
*/
if( rcode != 0x00 ) { //exit if timeout
return( rcode );
}
rcode = ( MAXreg_rd( rHRSL ) & 0x0f );
if( rcode == hrNAK ) {
nak_count++;
if( nak_count == USB_NAK_LIMIT ) {
break;
}
else {
continue;
}
}
if( rcode == hrTIMEOUT ) {
retry_count++;
if( retry_count == USB_RETRY_LIMIT ) {
break;
}
else {
continue;
}
}
else break;
}//while( 1 )
return( rcode );
}
/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes.
Keep sending INs and writes data to memory area pointed by 'data' */
/* rcode 0 if no errors. rcode 01-0f is relayed from prvXferDispatchPkt(). Rcode f0 means RCVDAVIRQ error,
fe USB xfer timeout */
BYTE XferInTransfer( BYTE addr/* not sure if it's necessary */, BYTE ep, WORD nbytes, BYTE* data, BYTE maxpktsize )
{
BYTE rcode;
//BYTE i;
//BYTE tmpbyte;
BYTE pktsize;
WORD xfrlen = 0;
MAXreg_wr( rHCTL, devtable[ addr ].epinfo[ ep ].rcvToggle ); //set toggle value
while( 1 ) { // use a 'return' to exit this loop
rcode = XferDispatchPkt( tokIN, ep ); //IN packet to EP-'endpoint'. Function takes care of NAKS.
if( rcode ) {
return( rcode ); //should be 0, indicating ACK. Else return error code.
}
/* check for RCVDAVIRQ and generate error if not present */
/* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */
if(( MAXreg_rd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) {
return ( 0xf0 ); //receive error
}
pktsize = MAXreg_rd( rRCVBC ); //number of received bytes
//printf ("pktsize: %d\n", pktsize);
data = MAXbytes_rd( rRCVFIFO, pktsize, data );
MAXreg_wr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer
xfrlen += pktsize; // add this packet's byte count to total transfer length
/* The transfer is complete under two conditions: */
/* 1. The device sent a short packet (L.T. maxPacketSize) */
/* 2. 'nbytes' have been transferred. */
if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) { // have we transferred 'nbytes' bytes?
if( MAXreg_rd( rHRSL ) & bmRCVTOGRD ) { //save toggle value
devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1;
}
else {
devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG0;
}
return( 0 );
}
}//while( 1 )
}
/* initialization of USB data structures */
void USB_init( void )
{
BYTE i;
for( i = 0; i < ( USB_NUMDEVICES + 1 ); i++ ) {
devtable[ i ].epinfo = NULL; //clear device table
devtable[ i ].devclass = 0;
}
devtable[ 0 ].epinfo = &dev0ep; //set single ep for uninitialized device
dev0ep.MaxPktSize = 0;
dev0ep.sndToggle = bmSNDTOG0; //set DATA0/1 toggles to 0
dev0ep.rcvToggle = bmRCVTOG0;
}
USB_DEVICE_DESCRIPTOR buf = {0};
USB_STRING_DESCRIPTOR strDesc = {0};
/* USB state machine. Connect/disconnect, enumeration, initialization */
/* error codes: 01-0f HRSLT */
/* ff - unsupported device */
/* fe - no address available */
/* fd - no client driver available */
void USB_Task( void )
{
static DWORD usb_delay = 0;
static BYTE tmp_addr;
BYTE rcode, tmpdata;
BYTE i;
switch( usb_task_state & USB_STATE_MASK ) {
/* Detached state - when nothing is connected to ( or just disconnected from) USB bus */
case( USB_STATE_DETACHED ):
switch( usb_task_state ) {
case( USB_DETACHED_SUBSTATE_INITIALIZE ):
/* cleanup device data structures */
USB_init();
usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
break;
case( USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE ):
/* Do nothing */
MAXreg_wr(rHCTL,bmSAMPLEBUS);
break;
case( USB_DETACHED_SUBSTATE_ILLEGAL ):
/* don't know what to do yet */
break;
}//switch( usb_task_state )
break;//( USB_STATE_DETACHED ):
/**/
case( USB_STATE_ATTACHED ): //prepare for enumeration
switch( usb_task_state ) {
case( USB_STATE_ATTACHED ):
//TODO
//usb_delay = (alt_nticks()*1000)/alt_ticks_per_second() + 200; //initial settle 200ms
usb_delay = 0;
usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
break;//case( USB_STATE_ATTACHED )
case( USB_ATTACHED_SUBSTATE_SETTLE ): //waiting for settle timer to expire
//TODO
/*
if( (alt_nticks()*1000)/alt_ticks_per_second() > usb_delay ) {
usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
}
*/
break;//case( USB_ATTACHED_SUBSTATE_SETTLE )
case( USB_ATTACHED_SUBSTATE_RESET_DEVICE ):
MAXreg_wr( rHIRQ, bmBUSEVENTIRQ ); //clear bus event IRQ
MAXreg_wr( rHCTL, bmBUSRST ); //issue bus reset
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
break;//case( USB_ATTACHED_SUBSTATE_RESET_DEVICE )
case( USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE ): //wait for bus reset and first SOF
if(( MAXreg_rd( rHCTL ) & bmBUSRST ) == 0 ) {
tmpdata = MAXreg_rd( rMODE ) | bmSOFKAENAB; //start SOF generation
MAXreg_wr( rMODE, tmpdata );
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
}
break;//case( USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE )
case( USB_ATTACHED_SUBSTATE_WAIT_SOF ):
if( MAXreg_rd( rHIRQ ) | bmFRAMEIRQ ) { //when first SOF received we can continue
usb_task_state = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
}
break;//case( USB_ATTACHED_SUBSTATE_WAIT_SOF )
case( USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE ): //send request for first 8 bytes of device descriptor
devtable[ 0 ].epinfo->MaxPktSize = 0x0008; //fill max packet size with minimum allowed
rcode = XferGetDevDescr( 0, 0, 8, (BYTE *)&buf ); //get device descriptor size
if( rcode == 0 ) {
devtable[ 0 ].epinfo->MaxPktSize = buf.bMaxPacketSize0;
rcode = XferGetDevDescr( 0, 0, buf.bLength, (BYTE *)&buf ); //get full descriptor
//pull the string descriptor for the product if it exists
//hackish, store this somewhere
if (buf.iManufacturer != 0)
{
rcode = XferGetStrDescr( 0, 0, 2, buf.iManufacturer, LANG_EN_US, (BYTE *)&strDesc);
rcode = XferGetStrDescr( 0, 0, strDesc.bLength, buf.iManufacturer, LANG_EN_US, (BYTE *)&strDesc);
//printf ("Mfgr string(%i): %s\n", buf.iManufacturer, ConvUTF8ToStr(strDesc.bString, (strDesc.bLength>>1)-1));
}
if (buf.iProduct != 0)
{
rcode = XferGetStrDescr( 0, 0, 2, buf.iProduct, LANG_EN_US, (BYTE *)&strDesc);
rcode = XferGetStrDescr( 0, 0, strDesc.bLength, buf.iProduct, LANG_EN_US, (BYTE *)&strDesc);
//printf ("Product string(%i): %s\n", buf.iProduct, ConvUTF8ToStr(strDesc.bString, (strDesc.bLength>>1)-1));
}
usb_task_state = USB_STATE_ADDRESSING;
}
else {
usb_error = rcode;
last_usb_task_state = usb_task_state;
usb_task_state = USB_STATE_ERROR;
}
break;//case( USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE ):
}//switch( usb_task_state )
break;//case ( USB_STATE_ATTACHED )
case( USB_STATE_ADDRESSING ): //give device an address
for( i = 1; i < USB_NUMDEVICES; i++ ) {
if( devtable[ i ].epinfo == NULL ) {
devtable[ i ].epinfo = devtable[ 0 ].epinfo; //set correct MaxPktSize
//devtable[ i ].epinfo->MaxPktSize = devtable[ 0 ].epinfo->MaxPktSize; //copy uninitialized device record to have correct MaxPktSize
rcode = XferSetAddr( 0, 0, i );
if( rcode == 0 ) {
tmp_addr = i;
usb_task_state = USB_STATE_CONFIGURING;
}
else {
usb_error = rcode; //set address error
last_usb_task_state = usb_task_state;
usb_task_state = USB_STATE_ERROR;
}
break; //break if address assigned or error occurred during address assignment attempt
}
}
if( usb_task_state == USB_STATE_ADDRESSING ) {
usb_error = 0xfe;
last_usb_task_state = usb_task_state;
usb_task_state = USB_STATE_ERROR;
}
break;//case ( USB_STATE_ADDRESSING )
case( USB_STATE_CONFIGURING ): //checking for driver
//run device class probes until one returns TRUE
for( i = 0; i < USB_NUMCLASSES; i++ ) {
rcode = ClientDriverTable[ i ].Initialize( tmp_addr, 0 );
if( rcode == TRUE ) {
usb_task_state = USB_STATE_RUNNING;
break;
}
}
if( usb_task_state == USB_STATE_CONFIGURING ) {
usb_error = 0xfd;
last_usb_task_state = usb_task_state;
usb_task_state = USB_STATE_ERROR;
}
break;//( USB_STATE_CONFIGURING )
case( USB_STATE_RUNNING ):
//vTaskDelay( LED_RATE );
break;//( USB_STATE_RUNNING )
case( USB_STATE_ERROR ):
//vTaskDelay( LED_RATE ); //stay here if error
break;//( USB_STATE_ERROR )
default:
//Should never get here
break;
}//switch( usb_task_state & STATE_MASK )
}
//place-holders for MSD (mass-storage device) drivers, we don't have them ported.
//returns TRUE if device is successfully identified and configured, otherwise returns FALSE
BOOL MSDProbe( BYTE addr, DWORD flags )
{
(void) addr;
(void) flags;
return( FALSE );
}
BOOL MSDEventHandler( BYTE address, BYTE event, void *data, DWORD size )
{
(void) address;
(void) event;
(void) data;
(void) size;
return( FALSE );
}
//CDC (communication device class also not supported)
BOOL CDCProbe( BYTE address, DWORD flags )
{
(void) address;
(void) flags;
return( FALSE );
}
BOOL CDCEventHandler( BYTE address, BYTE event, void *data, DWORD size )
{
(void) address;
(void) event;
(void) data;
(void) size;
return( FALSE );
}
BOOL DummyProbe( BYTE address , DWORD flags )
{
(void) address;
(void) flags;
return( FALSE );
}
BOOL DummyEventHandler( BYTE address, BYTE event, void *data, DWORD size )
{
(void) address;
(void) event;
(void) data;
(void) size;
return( FALSE );
}
/* Function to access usb_task_state variable from outside */
BYTE GetUsbTaskState( void )
{
return( usb_task_state );
}
/* Function to access devtable[] from outside */
DEV_RECORD* GetDevtable( BYTE index )
{
return( &devtable[ index ] );
}
char* ConvUTF8ToStr(BYTE* utf8, BYTE length)
{
BYTE i;
for (i = 0; i < length; i++)
{
utf8[i] = utf8[2*i];
}
utf8[length] = 0x00;
return (char*)utf8;
}

253
sw/usb/transfer.h Normal file
View File

@@ -0,0 +1,253 @@
/* USB transfers support header */
#ifndef _transfer_h_
#define _transfer_h_
/* Targeted peripheral list table */
#define USB_NUMTARGETS 4 //number of targets in TPL, not counting uninitialized device
#define USB_NUMDEVICES 8 //number of supported devices
#define USB_NUMCLASSES 5 //number of device classes in class callback table
#define UNINIT 0 //uninitialized
#define HID_K 1 //HID Keyboard boot driver number in DEV_RECORD
#define HID_M 2 //HID Mouse boot driver number in DEV_RECORD
#define MSD 3 //Mass storage class driver number in DEV_RECORD
#define RAPHNET 4
/* Standard Device Requests */
#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS
#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE
#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE
#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS
#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR
#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR
#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION
#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION
#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE
#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE
#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME
#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up
#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode
/* Setup Data Constants */
#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer
#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer
#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard
#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class
#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor
#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device
#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface
#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint
#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other
/* USB descriptors */
#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor.
#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor.
#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor.
#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor.
#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor.
#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier.
#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration.
#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power.
#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor.
/* OTG SET FEATURE Constants */
#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP
#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP
#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP
/* USB Endpoint Transfer Types */
#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint.
#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint.
#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint.
#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint.
#define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes
/* Standard Feature Selectors for CLEAR_FEATURE Requests */
#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient
#define USB_FEATURE_TEST_MODE 2 // Device recipient
/* MSD class requests. Not part of chapter 9 */
#define USB_MSD_GET_MAX_LUN 0xFE // Device Request code to get the maximum LUN.
#define USB_MSD_RESET 0xFF // Device Request code to reset the device.
/* HID constants. Not part of chapter 9 */
/* Class-Specific Requests */
#define HID_REQUEST_GET_REPORT 0x01
#define HID_REQUEST_GET_IDLE 0x02
#define HID_REQUEST_GET_PROTOCOL 0x03
#define HID_REQUEST_SET_REPORT 0x09
#define HID_REQUEST_SET_IDLE 0x0A
#define HID_REQUEST_SET_PROTOCOL 0x0B
/* Class Descriptor Types */
#define HID_DESCRIPTOR_HID 0x21
#define HID_DESCRIPTOR_REPORT 0x22
#define HID_DESRIPTOR_PHY 0x23
/* Protocol Selection */
#define BOOT_PROTOCOL 0x00
#define RPT_PROTOCOL 0x01
/* HID Interface Class Code */
#define HID_INTF 0x03
/* HID Interface Class SubClass Codes */
#define BOOT_INTF_SUBCLASS 0x01
/* HID Interface Class Protocol Codes */
#define HID_PROTOCOL_NONE 0x00
#define HID_PROTOCOL_KEYBOARD 0x01
#define HID_PROTOCOL_MOUSE 0x02
/* USB Setup Packet Structure */
typedef struct {
union { // offset description
BYTE bmRequestType; // 0 Bit-map of request type
struct {
unsigned int recipient :5; // Recipient of the request
unsigned int type :2; // Type of request
unsigned int direction :1; // Direction of data X-fer
};
} ReqType_u;
BYTE bRequest; // 1 Request
union {
WORD wValue; // 2 Depends on bRequest
struct {
BYTE wValueLo;
BYTE wValueHi;
};
} wVal_u;
WORD wIndex; // 4 Depends on bRequest
WORD wLength; // 6 Depends on bRequest
} SETUP_PKT, *PSETUP_PKT;
/* Endpoint information structure */
/* bToggle of endpoint 0 initialized to 0xff */
/* during enumeration bToggle is set to 00 */
typedef struct {
BYTE epAddr; //copy from endpoint descriptor. Bit 7 indicates direction ( ignored for control endpoints )
BYTE Attr; // Endpoint transfer type.
WORD MaxPktSize; // Maximum packet size.
BYTE Interval; // Polling interval in frames.
BYTE sndToggle; //last toggle value, bitmask for HCTL toggle bits
BYTE rcvToggle; //last toggle value, bitmask for HCTL toggle bits
/* not sure if both are necessary */
} EP_RECORD;
/* device record structure */
typedef struct {
EP_RECORD* epinfo; //device endpoint information
BYTE devclass; //device class
} DEV_RECORD;
//targeted peripheral list element
//NOTE: this is currently not implemented - typically an embedded host will provide a TPL
//to enumerate supported devices.
typedef struct {
union {
DWORD val;
struct {
WORD idVendor;
WORD idProduct;
};
struct {
BYTE bClass;
BYTE bSubClass;
BYTE bProtocol;
};
} dev_u;
BYTE bConfig; //configuration
BYTE numep; //number of endpoints
EP_RECORD* epinfo; //endpoint information structure
BYTE CltDrv; //client driver
const char * desc; //device description
} USB_TPL_ENTRY;
/* control transfer */
typedef BYTE (*CTRL_XFER)(BYTE addr, BYTE ep, WORD nbytes, BYTE* dataptr,
BOOL direction);
/* class driver initialization */
typedef BOOL (*CLASS_INIT)(BYTE address, DWORD flags);
/* class driver event handler */
typedef BOOL (*CLASS_EVENT_HANDLER)(BYTE address, BYTE event, void *data,
DWORD size);
/* Client Driver Table Structure */
typedef struct {
CLASS_INIT Initialize; // Initialization routine
CLASS_EVENT_HANDLER EventHandler; // Event routine
DWORD flags; // Initialization flags
} CLASS_CALLBACK_TABLE;
/* Common setup data constant combinations */
#define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type
#define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface'
#define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type
#define bmREQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define bmREQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
/* Function macros */
//char XferCtrlReq( BYTE addr, BYTE ep, BYTE bmReqType, BYTE bRequest, BYTE wValLo, BYTE wValHi, WORD wInd, WORD nbytes, char* dataptr )
/* Set address request macro. Human-readable form of bXferCtrlReq */
/* won't necessarily work for device in 'Configured' state */
#define XferSetAddr( oldaddr, ep, newaddr ) \
XferCtrlReq( oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL )
/* Set Configuration Request */
#define XferSetConf( addr, ep, conf_value ) \
XferCtrlReq( addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL )
///* Get configuration request */
//#define bXferGetConf( addr, ep, urb_ptr ) bXferCtrlReq( addr, ep, 1, ( bmREQ_GET_DESCR ), USB_REQUEST_GET_CONFIGURATION, 0x00, 0x00, 0x00, urb_ptr );
/* Get device descriptor request macro */
#define XferGetDevDescr( addr, ep, nbytes, dataptr ) \
XferCtrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr )
///* Get configuration descriptor request macro */
#define XferGetConfDescr( addr, ep, nbytes, conf, dataptr ) \
XferCtrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr )
///* Get string descriptor request macro */
#define XferGetStrDescr( addr, ep, nbytes, index, langid, dataptr ) \
XferCtrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nbytes, dataptr )
///* Get MAX LUN MSD class request macro */
//#define bXferGetMaxLUN( addr, intf, urb_ptr ) bXferCtrlReq( addr, 0, 1, ( bmREQ_CL_GET_INTF ), USB_MSD_GET_MAX_LUN, 0, 0, intf, urb_ptr )
#define XferGetHIDDescr(addr, ep, desc, nbytes, dataptr) \
XferCtrlReq(addr, ep, bmREQ_HIDIN, USB_REQUEST_GET_DESCRIPTOR, desc, HID_DESCRIPTOR_REPORT, 0x000, nbytes, dataptr)
/* class requests */
#define XferSetProto( addr, ep, interface, protocol ) \
XferCtrlReq( addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, interface, 0x0000, NULL )
#define XferGetProto( addr, ep, interface, dataptr ) \
XferCtrlReq( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, interface, 0x0001, dataptr )
#define XferGetIdle( addr, ep, interface, reportID, dataptr ) \
XferCtrlReq( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, interface, 0x0001, dataptr )
/* Function prototypes */
BYTE XferCtrlReq(BYTE addr, BYTE ep, BYTE bmReqType, BYTE bRequest, BYTE wValLo,
BYTE wValHi, WORD wInd, WORD nbytes, BYTE* dataptr);
BYTE XferCtrlData(BYTE addr, BYTE ep, WORD nbytes, BYTE* dataptr,
BOOL direction);
BYTE XferCtrlND(BYTE addr, BYTE ep, WORD nbytes, BYTE* dataptr, BOOL direction);
//BYTE startCtrlReq( BYTE addr, BYTE ep, BYTE bmReqType, BYTE bRequest, BYTE wValLo, BYTE wValHi, WORD wInd, WORD nbytes, char* dataptr );
BYTE XferDispatchPkt(BYTE token, BYTE ep);
BYTE XferInTransfer(BYTE addr, BYTE ep, WORD nbytes, BYTE* data,
BYTE maxpktsize);
//BYTE XferInTransfer_mps( BYTE ep, char* data, BYTE maxpktsize );
void USB_init(void);
void USB_Task(void);
BYTE GetUsbTaskState(void);
DEV_RECORD* GetDevtable(BYTE index);
/* Client driver routines */
BOOL MSDProbe(BYTE address, DWORD flags);
BOOL MSDEventHandler(BYTE address, BYTE event, void *data, DWORD size);
BOOL CDCProbe(BYTE address, DWORD flags);
BOOL CDCEventHandler(BYTE address, BYTE event, void *data, DWORD size);
BOOL RaphnetProbe(BYTE address, DWORD flags);
BOOL RaphnetEventHandler(BYTE address, BYTE event, void *data, DWORD size);
BOOL DummyProbe(BYTE address, DWORD flags);
BOOL DummyEventHandler(BYTE address, BYTE event, void *data, DWORD size);
//Function to be able to display string descriptors
char* ConvUTF8ToStr(BYTE* utf8, BYTE length);
#endif //_transfer_h_

189
sw/usb/usb_ch9.h Normal file
View File

@@ -0,0 +1,189 @@
/*
USB Chapter 9 Protocol (Header File)
This file defines data structures, constants, and macros that are used to
to support the USB Device Framework protocol described in Chapter 9 of the
USB 2.0 specification.
In addition to that, class-specific descriptors are typedef'd here as well to keep descriptors together.
They are typedefs anyway and won't take any real code space.
*/
#ifndef _USB_CH9_H_
#define _USB_CH9_H_
/* Misc.USB constants */
#define DEV_DESCR_LEN 18 //device descriptor length
#define CONF_DESCR_LEN 9 //configuration descriptor length
#define INTR_DESCR_LEN 9 //interface descriptor length
#define EP_DESCR_LEN 7 //endpoint descriptor length
/* Device descriptor structure */
typedef struct {
BYTE bLength; // Length of this descriptor.
BYTE bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
WORD bcdUSB; // USB Spec Release Number (BCD).
BYTE bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
BYTE bDeviceSubClass; // Subclass code (assigned by the USB-IF).
BYTE bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
BYTE bMaxPacketSize0; // Maximum packet size for endpoint 0.
WORD idVendor; // Vendor ID (assigned by the USB-IF).
WORD idProduct; // Product ID (assigned by the manufacturer).
WORD bcdDevice; // Device release number (BCD).
BYTE iManufacturer; // Index of String Descriptor describing the manufacturer.
BYTE iProduct; // Index of String Descriptor describing the product.
BYTE iSerialNumber; // Index of String Descriptor with the device's serial number.
BYTE bNumConfigurations; // Number of possible configurations.
} USB_DEVICE_DESCRIPTOR;
/* Configuration Descriptor Structure */
typedef struct {
BYTE bLength; // Length of this descriptor.
BYTE bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
WORD wTotalLength; // Total length of all descriptors for this configuration.
BYTE bNumInterfaces; // Number of interfaces in this configuration.
BYTE bConfigurationValue; // Value of this configuration (1 based).
BYTE iConfiguration; // Index of String Descriptor describing the configuration.
BYTE bmAttributes; // Configuration characteristics.
BYTE bMaxPower; // Maximum power consumed by this configuration.
} USB_CONFIGURATION_DESCRIPTOR;
/* Conf.descriptor attribute bits */
#define USB_CFG_DSC_REQUIRED 0x80 // Required attribute
//#define USB_CFG_DSC_SELF_PWR (0x40|USB_CFG_DSC_REQUIRED) // Device is self powered.
//#define USB_CFG_DSC_REM_WAKE (0x20|USB_CFG_DSC_REQUIRED) // Device can request remote wakup
#define USB_CFG_DSC_SELF_PWR (0x40) // Device is self powered.
#define USB_CFG_DSC_REM_WAKE (0x20) // Device can request remote wakup
/* USB Interface Descriptor Structure */
typedef struct {
BYTE bLength; // Length of this descriptor.
BYTE bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).
BYTE bInterfaceNumber; // Number of this interface (0 based).
BYTE bAlternateSetting; // Value of this alternate interface setting.
BYTE bNumEndpoints; // Number of endpoints in this interface.
BYTE bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
BYTE bInterfaceSubClass; // Subclass code (assigned by the USB-IF).
BYTE bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
BYTE iInterface; // Index of String Descriptor describing the interface.
} USB_INTERFACE_DESCRIPTOR;
/* USB Endpoint Descriptor Structure */
typedef struct {
BYTE bLength; // Length of this descriptor.
BYTE bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
BYTE bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
BYTE bmAttributes; // Endpoint transfer type.
WORD wMaxPacketSize; // Maximum packet size.
BYTE bInterval; // Polling interval in frames.
} USB_ENDPOINT_DESCRIPTOR;
/* Endpoint Direction */
#define EP_DIR_IN 0x80 // Data flows from device to host
#define EP_DIR_OUT 0x00 // Data flows from host to device
/* USB Endpoint Attributes */
// Section: Transfer Types
#define EP_ATTR_CONTROL (0<<0) // Endoint used for control transfers
#define EP_ATTR_ISOCH (1<<0) // Endpoint used for isochronous transfers
#define EP_ATTR_BULK (2<<0) // Endpoint used for bulk transfers
#define EP_ATTR_INTR (3<<0) // Endpoint used for interrupt transfers
// Section: Synchronization Types (for isochronous enpoints)
#define EP_ATTR_NO_SYNC (0<<2) // No Synchronization
#define EP_ATTR_ASYNC (1<<2) // Asynchronous
#define EP_ATTR_ADAPT (2<<2) // Adaptive synchronization
#define EP_ATTR_SYNC (3<<2) // Synchronous
// Section: Usage Types (for isochronous endpoints)
#define EP_ATTR_DATA (0<<4) // Data Endpoint
#define EP_ATTR_FEEDBACK (1<<4) // Feedback endpoint
#define EP_ATTR_IMP_FB (2<<4) // Implicit Feedback data EP
// Section: Max Packet Sizes
#define EP_MAX_PKT_INTR_LS 8 // Max low-speed interrupt packet
#define EP_MAX_PKT_INTR_FS 64 // Max full-speed interrupt packet
#define EP_MAX_PKT_ISOCH_FS 1023 // Max full-speed isochronous packet
#define EP_MAX_PKT_BULK_FS 64 // Max full-speed bulk packet
#define EP_LG_PKT_BULK_FS 32 // Large full-speed bulk packet
#define EP_MED_PKT_BULK_FS 16 // Medium full-speed bulk packet
#define EP_SM_PKT_BULK_FS 8 // Small full-speed bulk packet
/* USB OTG Descriptor Structure */
typedef struct {
BYTE bLength; // Length of this descriptor.
BYTE bDescriptorType; // OTG descriptor type (USB_DESCRIPTOR_OTG).
BYTE bmAttributes; // OTG attributes.
} USB_OTG_DESCRIPTOR;
/* USB String Descriptor Structure */
typedef struct {
BYTE bLength; //size of this descriptor
BYTE bDescriptorType; //type, USB_DSC_STRING
BYTE bString[256 - 2]; //buffer for string
} USB_STRING_DESCRIPTOR;
/* Section: USB Device Qualifier Descriptor Structure */
typedef struct {
BYTE bLength; // Size of this descriptor
BYTE bDescriptorType; // Type, always USB_DESCRIPTOR_DEVICE_QUALIFIER
WORD bcdUSB; // USB spec version, in BCD
BYTE bDeviceClass; // Device class code
BYTE bDeviceSubClass; // Device sub-class code
BYTE bDeviceProtocol; // Device protocol
BYTE bMaxPacketSize0; // EP0, max packet size
BYTE bNumConfigurations; // Number of "other-speed" configurations
BYTE bReserved; // Always zero (0)
} USB_DEVICE_QUALIFIER_DESCRIPTOR;
/* Section: USB Specification Constants */
#define PID_OUT 0x1 // PID for an OUT token
#define PID_ACK 0x2 // PID for an ACK handshake
#define PID_DATA0 0x3 // PID for DATA0 data
#define PID_PING 0x4 // Special PID PING
#define PID_SOF 0x5 // PID for a SOF token
#define PID_NYET 0x6 // PID for a NYET handshake
#define PID_DATA2 0x7 // PID for DATA2 data
#define PID_SPLIT 0x8 // Special PID SPLIT
#define PID_IN 0x9 // PID for a IN token
#define PID_NAK 0xA // PID for a NAK handshake
#define PID_DATA1 0xB // PID for DATA1 data
#define PID_PRE 0xC // Special PID PRE (Same as PID_ERR)
#define PID_ERR 0xC // Special PID ERR (Same as PID_PRE)
#define PID_SETUP 0xD // PID for a SETUP token
#define PID_STALL 0xE // PID for a STALL handshake
#define PID_MDATA 0xF // PID for MDATA data
#define PID_MASK_DATA 0x03 // Data PID mask
#define PID_MASK_DATA_SHIFTED (PID_MASK_DATA << 2) // Data PID shift to proper position
#define LANG_EN_US 0x0409 //US language code, probably the only supported by string descriptors
/* USB Token Types */
/* defined in MAX3421E.h */
/* Section: OTG Descriptor Constants */
#define OTG_HNP_SUPPORT 0x02 // OTG Descriptor bmAttributes - HNP support flag
#define OTG_SRP_SUPPORT 0x01 // OTG Descriptor bmAttributes - SRP support flag
/* Section: USB Class Code Definitions */
#define USB_HUB_CLASSCODE 0x09 // Class code for a hub.
/* HID class-specific defines */
/* USB HID Descriptor header per HID 1.1 spec */
/* section 6.2.1 */
/* the header is variable length. Only first class descriptor fields are defined */
typedef union {
struct {
BYTE bLength;
BYTE bDescriptorType;
WORD bcdHID;
BYTE bCountryCode;
BYTE bNumDescriptors;
BYTE bDescrType;
WORD wDescriptorLength;
};
} USB_HID_DESCRIPTOR;
/* combined descriptor for easy parsing */
typedef struct {
union {
BYTE buf[80];
USB_DEVICE_DESCRIPTOR device;
USB_CONFIGURATION_DESCRIPTOR config;
USB_INTERFACE_DESCRIPTOR interface;
USB_ENDPOINT_DESCRIPTOR endpoint;
USB_STRING_DESCRIPTOR string;
/* class descriptors */
USB_HID_DESCRIPTOR HID;
} descr;
} USB_DESCR;
#endif // _USB_CH9_H_