This shows you the differences between two versions of the page.
— |
project:usb:code:enumerated [2007/04/27 00:21] (current) |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Enumerated ====== | ||
+ | Here is the code as it stood when I first got the firmware to enumerate as an HID Device on Windows XP Pro SP2 without errors. Note that this code only seems to work at debugging level 5, or when debugging is disabled (via commenting '' | ||
+ | |||
+ | {{project: | ||
+ | |||
+ | <code cpp> | ||
+ | #include < | ||
+ | |||
+ | // | ||
+ | // Setup PIC and CCS compiler | ||
+ | #fuses XT, PUT, NOWDT, NOPROTECT | ||
+ | #use delay(clock = 4000000) | ||
+ | |||
+ | #use rs232(baud = 19200, xmit = PIN_C6, rcv = PIN_C7, disable_ints) | ||
+ | // By using C6 and C7, we will make use of the 877's hardware USART abilities | ||
+ | |||
+ | #use fast_io(a) | ||
+ | #use standard_io(c) | ||
+ | #byte port_a = 5 | ||
+ | set_tris_a(0xFF); | ||
+ | |||
+ | #use standard_io(b) | ||
+ | #byte port_d = 8 | ||
+ | |||
+ | // | ||
+ | // Debug options | ||
+ | // 0 is most verbose, 1 less so etc | ||
+ | |||
+ | // Comment out the following line to bulid without debugging | ||
+ | // NB: This creates a LOT of warnings during compilation: | ||
+ | // a "Code has no effect" | ||
+ | |||
+ | #define __DEBUGGING_ENABLED | ||
+ | |||
+ | #ifdef __DEBUGGING_ENABLED | ||
+ | #define DEBUG0 | ||
+ | #define DEBUG1 | ||
+ | #define DEBUG2 | ||
+ | #define DEBUG3 | ||
+ | #define DEBUG4 | ||
+ | #define DEBUG5 | ||
+ | #define DEBUG6 | ||
+ | #define DEBUG7 | ||
+ | #else | ||
+ | #define DEBUG0 | ||
+ | #define DEBUG1 | ||
+ | #define DEBUG2 | ||
+ | #define DEBUG3 | ||
+ | #define DEBUG4 | ||
+ | #define DEBUG5 | ||
+ | #define DEBUG6 | ||
+ | #define DEBUG7 | ||
+ | #endif | ||
+ | |||
+ | // | ||
+ | // Definitions | ||
+ | |||
+ | // Yellow LED | ||
+ | #define LED_N | ||
+ | |||
+ | // Constants | ||
+ | #define ON 1 | ||
+ | #define OFF 0 | ||
+ | |||
+ | #define D12_DATA | ||
+ | #define D12_COMMAND | ||
+ | |||
+ | // D12 pins | ||
+ | #define D12_A0 | ||
+ | #define D12_WR_N | ||
+ | #define D12_RD_N | ||
+ | #define D12_SUSPEND | ||
+ | #define D12_INT_N | ||
+ | |||
+ | // D12 Constants | ||
+ | #define D12_CTRL_BUFFER_SIZE | ||
+ | |||
+ | // D12 Endpoint indexes (for bitwise OR'ing with base commands) | ||
+ | #define CTRL_OUT | ||
+ | #define CTRL_IN | ||
+ | #define ENDPT1_OUT | ||
+ | #define ENDPT1_IN | ||
+ | #define ENDPT2_OUT | ||
+ | #define ENDPT2_IN | ||
+ | |||
+ | // D12 Commands | ||
+ | #define SET_ADDRESS | ||
+ | #define SET_ENDPT_ENABLE | ||
+ | #define SET_MODE | ||
+ | #define SET_DMA | ||
+ | #define READ_INT | ||
+ | #define SELECT_ENDPT | ||
+ | #define READ_ENDPT_STATUS | ||
+ | #define READ_BUFFER | ||
+ | #define WRITE_BUFFER | ||
+ | #define SET_ENDPT_STATUS | ||
+ | #define ACK_SETUP | ||
+ | #define CLEAR_BUFFER | ||
+ | #define VALIDATE_BUFFER | ||
+ | #define SEND_RESUME | ||
+ | #define READ_FRAME_NUM | ||
+ | |||
+ | // D12 Interrupt byte 1 | ||
+ | #define INT_CTRL_OUT | ||
+ | #define INT_CTRL_IN | ||
+ | #define INT_ENDPT1_OUT | ||
+ | #define INT_ENDPT1_IN | ||
+ | #define INT_ENDPT2_OUT | ||
+ | #define INT_ENDPT2_IN | ||
+ | #define INT_BUS_RESET | ||
+ | #define INT_SUSPEND_CHANGE | ||
+ | |||
+ | // D12 Interrupt byte 2 | ||
+ | #define DMA_EOT_INT | ||
+ | |||
+ | // D12 Last transaction status | ||
+ | #define STAT_XFER_SUCCESS | ||
+ | #define STAT_ERROR | ||
+ | #define STAT_SETUP | ||
+ | #define STAT_DATA | ||
+ | #define STAT_NOT_READ | ||
+ | |||
+ | // USB bmRequestTypes | ||
+ | #define REQTYPE_XFER_DIRECTION | ||
+ | #define REQTYPE_CMD_TYPE | ||
+ | #define REQTYPE_RECIPIENT | ||
+ | |||
+ | // USB Standard request types | ||
+ | #define GET_STATUS_REQ | ||
+ | #define CLEAR_FEATURE_REQ | ||
+ | #define SET_FEATURE_REQ | ||
+ | #define SET_ADDRESS_REQ | ||
+ | #define GET_DESCRIPTOR_REQ | ||
+ | #define SET_DESCRIPTOR_REQ | ||
+ | #define GET_CONFIGURATION_REQ | ||
+ | #define SET_CONFIGURATION_REQ | ||
+ | #define GET_INTERFACE_REQ | ||
+ | #define SET_INTERFACE_REQ | ||
+ | #define SYNCH_FRAME_REQ | ||
+ | |||
+ | // | ||
+ | // Global Variable Declarations | ||
+ | unsigned char DEBUG_LEVEL; | ||
+ | unsigned char *pLOAD; | ||
+ | unsigned char *pLOAD_TERMINATOR; | ||
+ | unsigned char SET_ADDRESS_PENDING; | ||
+ | unsigned int8 DEBUGGED; | ||
+ | unsigned char SEND_NULL_PACKET; | ||
+ | |||
+ | // | ||
+ | // Structures | ||
+ | struct REQUEST { | ||
+ | int8 bmRequestType; | ||
+ | int8 bRequest; | ||
+ | int16 | ||
+ | int16 | ||
+ | int16 | ||
+ | }; | ||
+ | |||
+ | struct DEVICE { | ||
+ | int8 bLength; | ||
+ | int8 bDescriptorType; | ||
+ | int16 | ||
+ | int8 bDeviceClass; | ||
+ | int8 bDeviceSubClass; | ||
+ | int8 bDeviceProtocol; | ||
+ | int8 bMaxPacketSize; | ||
+ | int16 | ||
+ | int16 | ||
+ | int16 | ||
+ | int8 iManufacturer; | ||
+ | int8 iProduct; | ||
+ | int8 iSerialNumber; | ||
+ | int8 bNumConfigurations; | ||
+ | }; | ||
+ | |||
+ | struct CONFIGURATION { | ||
+ | int8 bLength; | ||
+ | int8 bDescriptorType; | ||
+ | int8 wTotalLength; | ||
+ | int8 wZero; | ||
+ | int8 bNumInterfaces; | ||
+ | int8 bConfigurationValue; | ||
+ | int8 iConfiguration; | ||
+ | int8 bmAttributes; | ||
+ | int8 MaxPower; | ||
+ | }; | ||
+ | |||
+ | struct INTERFACE { | ||
+ | int8 bLength; | ||
+ | int8 bDescriptionType; | ||
+ | int8 bInterfaceNumber; | ||
+ | int8 bAlternateSetting; | ||
+ | int8 bNumEndpoints; | ||
+ | int8 bInterfaceClass; | ||
+ | int8 bInterfaceSubClass; | ||
+ | int8 bInterfaceProtocol; | ||
+ | int8 iInterface; | ||
+ | }; | ||
+ | |||
+ | struct HIDDESC { | ||
+ | int8 bLength; | ||
+ | int8 bDescriptorType; | ||
+ | int16 | ||
+ | int8 bCountryCode; | ||
+ | int8 bNumDescriptors; | ||
+ | int8 bReportDescriptorType; | ||
+ | int16 | ||
+ | }; | ||
+ | |||
+ | struct ENDPOINT { | ||
+ | int8 bLength; | ||
+ | int8 bDescriptorType; | ||
+ | int8 bEndpointAddress; | ||
+ | int8 bmAttributes; | ||
+ | int16 | ||
+ | int8 bInterval; | ||
+ | }; | ||
+ | |||
+ | struct CONFIG { | ||
+ | struct CONFIGURATION sConfig; | ||
+ | struct INTERFACE sInterface; | ||
+ | struct HIDDESC sHIDDesc; | ||
+ | struct ENDPOINT sEndpoint1; | ||
+ | }; | ||
+ | |||
+ | |||
+ | |||
+ | // | ||
+ | // USB Descriptors | ||
+ | /* | ||
+ | struct DEVICE sDevice = { | ||
+ | sizeof( struct DEVICE), //BYTE bLength | ||
+ | 0x01, // | ||
+ | 0x0110, | ||
+ | 0x00, // | ||
+ | 0x00, // | ||
+ | 0x00, // | ||
+ | D12_CTRL_BUFFER_SIZE, | ||
+ | 0x05C7, | ||
+ | 0x0113, | ||
+ | 0x0001, | ||
+ | 0x01, // | ||
+ | 0x02, // | ||
+ | 0x01, // | ||
+ | 0x01 //BYTE bNumConfigurations | ||
+ | }; | ||
+ | */ | ||
+ | |||
+ | struct DEVICE sDevice = { | ||
+ | sizeof( struct DEVICE), //BYTE bLength | ||
+ | 0x01, // | ||
+ | 0x0110, | ||
+ | 0xff, // | ||
+ | 0xff, // | ||
+ | 0xff, // | ||
+ | D12_CTRL_BUFFER_SIZE, | ||
+ | 0x7104, | ||
+ | 0x0211, | ||
+ | 0x0000, | ||
+ | 0x01, // | ||
+ | 0x02, // | ||
+ | 0x00, // | ||
+ | 0x01 //BYTE bNumConfigurations | ||
+ | }; | ||
+ | struct CONFIG sConfiguration = { | ||
+ | sizeof(struct CONFIGURATION), | ||
+ | 0x02, // | ||
+ | sizeof( struct CONFIG), | ||
+ | 0x00, // | ||
+ | 0x01, // | ||
+ | 0x01, // | ||
+ | 0x00, // | ||
+ | 0xa0, // | ||
+ | 0x05, // | ||
+ | sizeof(struct INTERFACE), | ||
+ | 0x04, // | ||
+ | 0x00, // | ||
+ | 0x00, // | ||
+ | 0x01, // | ||
+ | 0x03, // | ||
+ | 0x01, // | ||
+ | 0x01, // | ||
+ | 0x00 //BYTE iInterface | ||
+ | sizeof(struct HIDDESC), | ||
+ | 0x21, // | ||
+ | 0x0001, | ||
+ | 0x00, // | ||
+ | 0x01, // | ||
+ | 0x22, // | ||
+ | 0x3200, | ||
+ | sizeof(struct ENDPOINT), | ||
+ | 0x05, // | ||
+ | 0x81, // | ||
+ | 0x03, // | ||
+ | 0x0800, | ||
+ | 0x0A, // | ||
+ | }; //Interval | ||
+ | |||
+ | unsigned char LANG_ID[4] = { | ||
+ | sizeof(LANG_ID), | ||
+ | 0x03, // bDescriptorType = String Desc | ||
+ | 0x09, // wLangID (Lo) (Lang ID for English = 0x0409) | ||
+ | 0x04, // wLangID (Hi) (Lang ID for English = 0x0409) | ||
+ | }; | ||
+ | |||
+ | // | ||
+ | // Function prototypes | ||
+ | void Init_PIC(); | ||
+ | void Init_D12(); | ||
+ | void D12_Write(short, | ||
+ | void D12_Read(unsigned char, int); | ||
+ | void D12_Interrupt_Handler(); | ||
+ | void D12_Handle_Ctrl_Out_EP(); | ||
+ | void D12_Stall_Endpt(int8); | ||
+ | void D12_Standard_Request(struct REQUEST *pReq); | ||
+ | void D12_Get_Descriptor(struct REQUEST *pReq); | ||
+ | void D12_Send_Null_Packet(int8); | ||
+ | void D12_Set_Address(struct REQUEST *pReq); | ||
+ | #SEPARATE void D12_Transaction_Error(int8); | ||
+ | #SEPARATE void Debug_D12_Request(struct REQUEST *pReq); | ||
+ | |||
+ | // | ||
+ | // Entry point | ||
+ | void main(void){ | ||
+ | |||
+ | DEBUGGED = 0; | ||
+ | Init_PIC(); | ||
+ | |||
+ | delay_ms(1); | ||
+ | |||
+ | // No need to init the D12, as it will trigger a bus reset interrupt as soon | ||
+ | // as it is powered / connects to the USB bus (not too sure which though) | ||
+ | |||
+ | if(! input(D12_INT_N)) | ||
+ | D12_Interrupt_Handler(); | ||
+ | while(TRUE); | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // Used for passing commands or data to the PDIUSBD12 | ||
+ | void D12_Write(short type, int data) | ||
+ | { | ||
+ | int8 i; | ||
+ | switch(type) | ||
+ | { | ||
+ | case D12_DATA: | ||
+ | case D12_COMMAND: | ||
+ | set_tris_d(0x00); | ||
+ | output_high(D12_RD_N); | ||
+ | |||
+ | if(type == D12_COMMAND) | ||
+ | output_high(D12_A0); | ||
+ | else | ||
+ | output_low(D12_A0); | ||
+ | |||
+ | port_d = data; // Setup bus | ||
+ | // | ||
+ | i = 8; | ||
+ | while(i--); | ||
+ | output_low(D12_WR_N); | ||
+ | output_high(D12_WR_N); | ||
+ | |||
+ | if(type == D12_COMMAND) | ||
+ | output_low(D12_A0); | ||
+ | break; | ||
+ | default: | ||
+ | DEBUG7(" | ||
+ | DEBUG7(" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // Used for reading data from the PDIUSBD12 | ||
+ | void D12_Read(unsigned char* buffer, int reads) | ||
+ | { | ||
+ | int i; | ||
+ | |||
+ | set_tris_d(0xFF); | ||
+ | for(i = 0; i<reads; i++) | ||
+ | { | ||
+ | output_low(D12_RD_N); | ||
+ | buffer[i] = port_d; | ||
+ | output_high(D12_RD_N); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // FIXME: Probably want to save some registers when handling | ||
+ | // this interrupt, as it takes quite a long time. | ||
+ | #INT_EXT | ||
+ | void D12_Interrupt_Handler() | ||
+ | { | ||
+ | unsigned char buffer[2], endpt_int, other_int; | ||
+ | |||
+ | // Loop in case another interrupt is triggered while we handle this one | ||
+ | while(! input(D12_INT_N)){ | ||
+ | // Don't add newlines if we've not sent any data to the terminal | ||
+ | if(DEBUGGED > 0)printf(" | ||
+ | DEBUGGED = 0; | ||
+ | |||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Read(buffer, | ||
+ | endpt_int = buffer[0]; | ||
+ | other_int = buffer[1]; | ||
+ | |||
+ | DEBUG0(" | ||
+ | |||
+ | if (endpt_int & INT_BUS_RESET) { | ||
+ | DEBUG7(" | ||
+ | // D12 Firmware programming guide recommends using a flag for this... ahh well | ||
+ | Init_D12(); // Reset D12 settings (not a chip reset) | ||
+ | } else | ||
+ | if (endpt_int & INT_SUSPEND_CHANGE) { | ||
+ | DEBUG1(" | ||
+ | } else | ||
+ | if(endpt_int & INT_CTRL_OUT) { | ||
+ | // Control Out Endpoint interrupt | ||
+ | DEBUG3(" | ||
+ | D12_Handle_Ctrl_Out_EP(); | ||
+ | } else | ||
+ | if (endpt_int & INT_CTRL_IN) { | ||
+ | DEBUG2(" | ||
+ | |||
+ | // Clear interrupt | ||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Read(buffer, | ||
+ | DEBUG1(" | ||
+ | |||
+ | if(SET_ADDRESS_PENDING){ | ||
+ | // Acknowledge token by replying with a null data packet | ||
+ | D12_Send_Null_Packet(CTRL_IN); | ||
+ | |||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Write(D12_DATA, | ||
+ | |||
+ | SET_ADDRESS_PENDING = 0; | ||
+ | DEBUG2(" | ||
+ | } else if (pLOAD_TERMINATOR - pLOAD > 0) { | ||
+ | unsigned char DataLen; | ||
+ | |||
+ | // Smaller of " | ||
+ | DataLen = ((pLOAD_TERMINATOR - pLOAD) > D12_CTRL_BUFFER_SIZE) ? D12_CTRL_BUFFER_SIZE : (pLOAD_TERMINATOR - pLOAD); | ||
+ | DEBUG0(" | ||
+ | |||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Write(D12_DATA, | ||
+ | D12_Write(D12_DATA, | ||
+ | |||
+ | DataLen += pLOAD; | ||
+ | for(; pLOAD< | ||
+ | { | ||
+ | D12_Write(D12_DATA, | ||
+ | } | ||
+ | D12_Write(D12_COMMAND, | ||
+ | |||
+ | DEBUG4(" | ||
+ | } else if (SEND_NULL_PACKET) { | ||
+ | D12_Send_Null_Packet(CTRL_IN); | ||
+ | } else { | ||
+ | // Stall this endpoint (indicating we cannot handle the request) | ||
+ | | ||
+ | } | ||
+ | } else | ||
+ | // INT_ENDPT1_OUT | ||
+ | if (endpt_int & INT_ENDPT1_IN) { | ||
+ | DEBUG2(" | ||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Read(buffer, | ||
+ | DEBUG2(" | ||
+ | } | ||
+ | // INT_ENDPT2_OUT (Main OUT) | ||
+ | // INT_ENDPT2_IN (Main IN) | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // Setups the hardware at its most basic level | ||
+ | void Init_PIC(){ | ||
+ | output_low(LED_N); | ||
+ | |||
+ | set_tris_b(0x01); | ||
+ | set_tris_d(0x00); | ||
+ | port_d = 0xFF; //Set bus high, useful for checking the ribbon has not come loose | ||
+ | |||
+ | output_high(D12_RD_N); | ||
+ | output_high(D12_WR_N); | ||
+ | |||
+ | output_low(D12_A0); | ||
+ | output_low(D12_SUSPEND); | ||
+ | |||
+ | disable_interrupts(GLOBAL); | ||
+ | |||
+ | ext_int_edge(H_TO_L); | ||
+ | enable_interrupts(INT_EXT); | ||
+ | clear_interrupt(INT_EXT); | ||
+ | enable_interrupts(GLOBAL); | ||
+ | |||
+ | DEBUG_LEVEL = port_a & 0x07;// Read DIP switches (3 lower digits only) | ||
+ | DEBUG7(" | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // Takes the D12 out of reset and connects it to the USB bus | ||
+ | void Init_D12(){ | ||
+ | SET_ADDRESS_PENDING = 0; | ||
+ | pLOAD = pLOAD_TERMINATOR = 0; | ||
+ | SEND_NULL_PACKET = 0; | ||
+ | |||
+ | DEBUG0(" | ||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Write(D12_DATA, | ||
+ | |||
+ | DEBUG0(" | ||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Write(D12_DATA, | ||
+ | |||
+ | DEBUG0(" | ||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Write(D12_DATA, | ||
+ | D12_Write(D12_DATA, | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // Check for a SETUP token, and act upon it | ||
+ | void D12_Handle_Ctrl_Out_EP() { | ||
+ | |||
+ | unsigned char buffer[2]; | ||
+ | unsigned char data[D12_CTRL_BUFFER_SIZE]; | ||
+ | struct REQUEST *pReq; | ||
+ | int i; | ||
+ | |||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Read(buffer, | ||
+ | DEBUG2(" | ||
+ | |||
+ | if(buffer[0] & STAT_NOT_READ){ | ||
+ | // Nothing yet ;) | ||
+ | } | ||
+ | |||
+ | if(buffer[0] & STAT_XFER_SUCCESS){ | ||
+ | if(buffer[0] & STAT_SETUP){ // Setup token | ||
+ | |||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Read(data, | ||
+ | DEBUG2(" | ||
+ | |||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Read(data, | ||
+ | DEBUG2(" | ||
+ | |||
+ | // Acknowledge that we like this (NB CTRL_OUT is already selected) | ||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Write(D12_COMMAND, | ||
+ | |||
+ | // Prevent previous data from being sent (need to ack_setup to re-enable clear buffer) | ||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Write(D12_COMMAND, | ||
+ | |||
+ | if(data[1] == 0x08){ | ||
+ | for(i=2; i<10; i++){ | ||
+ | DEBUG1(" | ||
+ | } | ||
+ | pReq = (struct REQUEST *) & | ||
+ | |||
+ | // Output some debugging info | ||
+ | Debug_D12_Request(pReq); | ||
+ | |||
+ | switch((pReq-> | ||
+ | // Standard request | ||
+ | case 0x00: | ||
+ | DEBUG2(" | ||
+ | D12_Standard_Request(pReq); | ||
+ | break; | ||
+ | |||
+ | // Class request | ||
+ | case 0x01: | ||
+ | DEBUG2(" | ||
+ | break; | ||
+ | |||
+ | // Endpoint request | ||
+ | case 0x02: | ||
+ | DEBUG2(" | ||
+ | break; | ||
+ | |||
+ | // Unsupported | ||
+ | default: | ||
+ | DEBUG4(" | ||
+ | DEBUG2("? | ||
+ | // Stall this endpoint (indicating we cannot handle the request) | ||
+ | D12_Stall_Endpt(CTRL_OUT); | ||
+ | break; | ||
+ | } | ||
+ | } else { | ||
+ | // Setup token is an invalid length | ||
+ | D12_Stall_Endpt(CTRL_OUT); | ||
+ | } | ||
+ | } | ||
+ | } else | ||
+ | if (buffer[0] & STAT_ERROR) | ||
+ | { | ||
+ | D12_Transaction_Error(buffer[0] & STAT_ERROR); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // Stalls an enpoint, so the D12 will return STALL to the host, | ||
+ | // which usually indicates we don't understand / support the host's | ||
+ | // request | ||
+ | void D12_Stall_Endpt(int8 ENDPT) | ||
+ | { | ||
+ | DEBUG4(" | ||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Write(D12_DATA, | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // Handle standard USB requests, such as those encountered in | ||
+ | // SETUP tokens | ||
+ | void D12_Standard_Request(struct REQUEST *pReq) | ||
+ | { | ||
+ | switch(pReq-> | ||
+ | case GET_STATUS_REQ: | ||
+ | DEBUG5(" | ||
+ | break; | ||
+ | |||
+ | case CLEAR_FEATURE_REQ: | ||
+ | DEBUG5(" | ||
+ | break; | ||
+ | |||
+ | case SET_FEATURE_REQ: | ||
+ | DEBUG5(" | ||
+ | break; | ||
+ | |||
+ | case SET_ADDRESS_REQ: | ||
+ | DEBUG5(" | ||
+ | D12_Set_Address(pReq); | ||
+ | break; | ||
+ | |||
+ | case GET_DESCRIPTOR_REQ: | ||
+ | DEBUG5(" | ||
+ | D12_Get_Descriptor(pReq); | ||
+ | break; | ||
+ | |||
+ | case SET_DESCRIPTOR_REQ: | ||
+ | DEBUG5(" | ||
+ | break; | ||
+ | |||
+ | case GET_CONFIGURATION_REQ: | ||
+ | DEBUG5(" | ||
+ | break; | ||
+ | |||
+ | case SET_CONFIGURATION_REQ: | ||
+ | DEBUG5(" | ||
+ | break; | ||
+ | |||
+ | case GET_INTERFACE_REQ: | ||
+ | DEBUG5(" | ||
+ | break; | ||
+ | |||
+ | case SET_INTERFACE_REQ: | ||
+ | DEBUG5(" | ||
+ | break; | ||
+ | |||
+ | case SYNCH_FRAME_REQ: | ||
+ | DEBUG5(" | ||
+ | break; | ||
+ | |||
+ | default: | ||
+ | DEBUG7(" | ||
+ | DEBUG5("? | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // Service the host's request for a descriptor | ||
+ | void D12_Get_Descriptor(struct REQUEST *pReq){ | ||
+ | |||
+ | unsigned int16 ReqDataLen; | ||
+ | short supported = 1; | ||
+ | ReqDataLen = pReq-> | ||
+ | |||
+ | switch (pReq-> | ||
+ | // Device Descriptor | ||
+ | case 0x0001: | ||
+ | DEBUG3(" | ||
+ | // Don't transmit more than we need to | ||
+ | if ( ReqDataLen > (unsigned int16) sizeof(struct DEVICE) ){ | ||
+ | ReqDataLen = sizeof(struct DEVICE); | ||
+ | } | ||
+ | pLOAD = (unsigned char *) & | ||
+ | break; | ||
+ | |||
+ | // Configuration Descriptor | ||
+ | case 0x0002: | ||
+ | DEBUG3(" | ||
+ | // Don't transmit more than we need to | ||
+ | if ( ReqDataLen > (unsigned int16) sizeof(struct CONFIG) ){ | ||
+ | ReqDataLen = sizeof(struct CONFIG); | ||
+ | } | ||
+ | pLOAD = (unsigned char *) & | ||
+ | break; | ||
+ | |||
+ | // String descriptor | ||
+ | case 0x0003: | ||
+ | DEBUG3(" | ||
+ | // Now we need to check which string was requested (low byte) | ||
+ | switch(pReq-> | ||
+ | // LANG_ID string descriptor (what language strings we can return) | ||
+ | case 0: | ||
+ | pLOAD = & | ||
+ | break; | ||
+ | |||
+ | // Unknown string descriptor | ||
+ | default: | ||
+ | DEBUG4(" | ||
+ | DEBUG4("? | ||
+ | supported = 0; | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | // Don't transmit more than we need to | ||
+ | if ( ReqDataLen > (unsigned int16) sizeof(*pLOAD) ){ // All string descriptors are kept in arrays | ||
+ | ReqDataLen = sizeof(*pLOAD); | ||
+ | } | ||
+ | break; | ||
+ | |||
+ | // Unsupported | ||
+ | default: | ||
+ | supported = 0; | ||
+ | DEBUG4(" | ||
+ | DEBUG5("? | ||
+ | // Not sure which endpoint would need to be stalled.. | ||
+ | // presumably the one the request came from (CTRL_OUT) | ||
+ | D12_Stall_Endpt(CTRL_OUT); | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | | ||
+ | // Note that if our descriptor is larger then what the host requested, | ||
+ | // | ||
+ | // | ||
+ | // However, if our descriptor is larger than the D12's CTRL_OUT buffer, then | ||
+ | // | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // When an error code is encountered from a 'Read Last Transaction Command' | ||
+ | // this function is called to clean up the mess | ||
+ | |||
+ | #SEPARATE void D12_Transaction_Error(int8 error){ | ||
+ | DEBUG5(" | ||
+ | switch (error) | ||
+ | { | ||
+ | case 0x02 : //0001 PID Encoding Error | ||
+ | break; | ||
+ | case 0x04 : //0010 PID Unknown | ||
+ | break; | ||
+ | case 0x06 : //0011 Unexpected packet | ||
+ | break; | ||
+ | case 0x08 : //0100 Token CRC Error | ||
+ | break; | ||
+ | case 0x0A : //0101 Data CRC Error | ||
+ | break; | ||
+ | case 0x0C : //0110 Time out Error | ||
+ | break; | ||
+ | case 0x0E : //0111 Never happens | ||
+ | break; | ||
+ | case 0x10 : //1000 Unexpected End of Packet | ||
+ | break; | ||
+ | case 0x12 : //1001 Sent or received NAK | ||
+ | break; | ||
+ | case 0x14 : //1010 Sent Stall, token received Endpt Stalled | ||
+ | break; | ||
+ | case 0x16 : //1011 Overflow Error | ||
+ | break; | ||
+ | case 0x1A : //1101 BitStuff Error | ||
+ | break; | ||
+ | case 0x1E : //1111 Wrong DATA PID | ||
+ | break; | ||
+ | default : | ||
+ | DEBUG7(" | ||
+ | DEBUG5("? | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // Output debugging info about a USB request | ||
+ | |||
+ | #SEPARATE void Debug_D12_Request(struct REQUEST *pReq){ | ||
+ | |||
+ | DEBUG4(" | ||
+ | if(pReq-> | ||
+ | DEBUG4(" | ||
+ | } else { | ||
+ | DEBUG4(" | ||
+ | } | ||
+ | |||
+ | DEBUG4(" | ||
+ | switch(pReq-> | ||
+ | // Device | ||
+ | case 0x00: | ||
+ | DEBUG4(" | ||
+ | break; | ||
+ | |||
+ | // Interface | ||
+ | case 0x01: | ||
+ | DEBUG4(" | ||
+ | break; | ||
+ | |||
+ | // Endpoint | ||
+ | case 0x02: | ||
+ | DEBUG4(" | ||
+ | break; | ||
+ | |||
+ | // Other | ||
+ | case 0x03: | ||
+ | DEBUG4("? | ||
+ | break; | ||
+ | |||
+ | // Unsupported | ||
+ | default: | ||
+ | DEBUG7(" | ||
+ | // Stall this endpoint (indicating we cannot handle the request) | ||
+ | D12_Stall_Endpt(CTRL_OUT); | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | DEBUG4(" | ||
+ | DEBUG4(" | ||
+ | DEBUG4(" | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // Responds to the Set_Address request of the host, and then | ||
+ | // sets the D12 address (NB: The address is changed AFTER the | ||
+ | // we respond to the host) | ||
+ | void D12_Set_Address(struct REQUEST *pReq){ | ||
+ | SET_ADDRESS_PENDING = (pReq-> | ||
+ | DEBUG3(" | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // Send a zero-length packet to the selected endpoint | ||
+ | // Useful for empty data stages in setup transactions, | ||
+ | // as signalling the end of a stream when the last packet was | ||
+ | // full (i.e. don't let the host assume there is no more data, | ||
+ | // tell it!) | ||
+ | void D12_Send_Null_Packet(int8 ENDPT) { | ||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Write(D12_COMMAND, | ||
+ | D12_Write(D12_DATA, | ||
+ | D12_Write(D12_DATA, | ||
+ | D12_Write(D12_COMMAND, | ||
+ | |||
+ | DEBUG2(" | ||
+ | } | ||
+ | </ |