397 lines
8.3 KiB
C
397 lines
8.3 KiB
C
/**
|
|
* Copyright (C) 2009 Ubixum, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
**/
|
|
|
|
//#define DEBUG_SETUPDAT
|
|
|
|
#ifdef DEBUG_SETUPDAT
|
|
#include <stdio.h> // NOTE this needs deleted
|
|
#else
|
|
#define printf(...)
|
|
#define NULL (void*)0;
|
|
#endif
|
|
|
|
#include <fx2regs.h>
|
|
#include <fx2macros.h>
|
|
#include <eputils.h>
|
|
#include <setupdat.h>
|
|
|
|
|
|
extern BOOL handle_vendorcommand(BYTE cmd);
|
|
extern BOOL handle_set_configuration(BYTE cfg);
|
|
extern BOOL handle_get_interface(BYTE ifc, BYTE * alt_ifc);
|
|
extern BOOL handle_set_interface(BYTE ifc, BYTE alt_ifc);
|
|
extern BYTE handle_get_configuration();
|
|
extern BOOL handle_set_configuration(BYTE cfg);
|
|
extern void handle_reset_ep(BYTE ep);
|
|
|
|
/**
|
|
* Predefs for handlers
|
|
**/
|
|
|
|
|
|
// GET_STATUS,
|
|
BOOL handle_get_status();
|
|
// CLEAR_FEATURE,
|
|
BOOL handle_clear_feature();
|
|
// 0x02 is reserved
|
|
// SET_FEATURE=0x03,
|
|
BOOL handle_set_feature();
|
|
// 0x04 is reserved
|
|
// SET_ADDRESS=0x05, // this is handled by EZ-USB core unless RENUM=0
|
|
// GET_DESCRIPTOR,
|
|
void handle_get_descriptor();
|
|
// SET_DESCRIPTOR,
|
|
// GET_CONFIGURATION, // handled by callback
|
|
// SET_CONFIGURATION, // handled by callback
|
|
// GET_INTERFACE, // handled by callback
|
|
// SET_INTERFACE, // handled by callback
|
|
// SYNC_FRAME // not yet implemented
|
|
|
|
/*
|
|
TRM 2.2
|
|
Setup Token ->
|
|
data transfer ->
|
|
handshake
|
|
*/
|
|
|
|
void
|
|
handle_setupdata()
|
|
{
|
|
//printf ( "Handle setupdat: %02x\n", SETUPDAT[1] );
|
|
|
|
switch (SETUPDAT[1]) {
|
|
|
|
case GET_STATUS:
|
|
if (!handle_get_status())
|
|
STALLEP0();
|
|
break;
|
|
case CLEAR_FEATURE:
|
|
if (!handle_clear_feature()) {
|
|
STALLEP0();
|
|
}
|
|
break;
|
|
case SET_FEATURE:
|
|
if (!handle_set_feature()) {
|
|
STALLEP0();
|
|
}
|
|
break;
|
|
case GET_DESCRIPTOR:
|
|
handle_get_descriptor();
|
|
break;
|
|
case GET_CONFIGURATION:
|
|
EP0BUF[0] = handle_get_configuration();
|
|
EP0BCH = 0;
|
|
EP0BCL = 1;
|
|
break;
|
|
case SET_CONFIGURATION:
|
|
// user callback
|
|
if (!handle_set_configuration(SETUPDAT[2])) {
|
|
STALLEP0();
|
|
}
|
|
break;
|
|
case GET_INTERFACE:
|
|
{
|
|
BYTE alt_ifc;
|
|
if (!handle_get_interface(SETUPDAT[4], &alt_ifc)) {
|
|
STALLEP0();
|
|
} else {
|
|
EP0BUF[0] = alt_ifc;
|
|
EP0BCH = 0;
|
|
EP0BCL = 1;
|
|
}
|
|
}
|
|
break;
|
|
case SET_INTERFACE:
|
|
// user callback
|
|
if (!handle_set_interface(SETUPDAT[4], SETUPDAT[2])) {
|
|
STALLEP0();
|
|
}
|
|
break;
|
|
default:
|
|
if (!handle_vendorcommand(SETUPDAT[1])) {
|
|
printf("Unhandled Vendor Command: %02x\n", SETUPDAT[1]);
|
|
STALLEP0();
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// do the handshake
|
|
EP0CS |= bmHSNAK;
|
|
|
|
}
|
|
|
|
__xdata BYTE *
|
|
ep_addr(BYTE ep)
|
|
{ // bit 8 of ep_num is the direction
|
|
BYTE ep_num = ep & ~0x80; // mask the direction
|
|
switch (ep_num) {
|
|
case 0:
|
|
return &EP0CS;
|
|
case 1:
|
|
return ep & 0x80 ? &EP1INCS : &EP1OUTCS;
|
|
case 2:
|
|
return &EP2CS;
|
|
case 4:
|
|
return &EP4CS;
|
|
case 6:
|
|
return &EP6CS;
|
|
case 8:
|
|
return &EP8CS;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// Get status has three request types
|
|
#define GS_DEVICE 0x80
|
|
#define GS_INTERFACE 0x81
|
|
#define GS_ENDPOINT 0x82
|
|
|
|
|
|
volatile BOOL self_powered = FALSE;
|
|
volatile BOOL remote_wakeup_allowed = FALSE;
|
|
|
|
BOOL
|
|
handle_get_status()
|
|
{
|
|
|
|
switch (SETUPDAT[0]) {
|
|
|
|
// case 0: // sometimes we get a 0 status too
|
|
case GS_INTERFACE:
|
|
EP0BUF[0] = 0;
|
|
EP0BUF[1] = 0;
|
|
EP0BCH = 0;
|
|
EP0BCL = 2;
|
|
break;
|
|
case GS_DEVICE:
|
|
|
|
// two byte response
|
|
// byte 0 bit 0 = self powered bit 1 = remote wakeup
|
|
EP0BUF[0] = (remote_wakeup_allowed << 1) | self_powered;
|
|
// byte 1 = 0
|
|
EP0BUF[1] = 0;
|
|
EP0BCH = 0;
|
|
EP0BCL = 2;
|
|
break;
|
|
case GS_ENDPOINT:
|
|
{
|
|
__xdata BYTE *pep = ep_addr(SETUPDAT[4]);
|
|
if (!pep)
|
|
return FALSE;
|
|
// byte 0 bit 0 = stall bit
|
|
EP0BUF[0] = *pep & bmEPSTALL ? 1 : 0;
|
|
EP0BUF[1] = 0;
|
|
EP0BCH = 0;
|
|
EP0BCL = 2;
|
|
}
|
|
break;
|
|
default:
|
|
printf("Unexpected Get Status: %02x\n", SETUPDAT[0]);
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#define GF_DEVICE 0
|
|
#define GF_ENDPOINT 2
|
|
|
|
BOOL
|
|
handle_clear_feature()
|
|
{
|
|
//printf ( "Clear Feature\n" );
|
|
switch (SETUPDAT[0]) {
|
|
case GF_DEVICE:
|
|
if (SETUPDAT[2] == 1) {
|
|
remote_wakeup_allowed = FALSE;
|
|
break;
|
|
}
|
|
return FALSE;
|
|
case GF_ENDPOINT:
|
|
if (SETUPDAT[2] == 0) { // ep stall feature
|
|
__xdata BYTE *pep = ep_addr(SETUPDAT[4]);
|
|
printf("unstall endpoint %02X\n", SETUPDAT[4]);
|
|
*pep &= ~bmEPSTALL;
|
|
RESETTOGGLE(SETUPDAT[4]);
|
|
} else {
|
|
printf("unsupported ep feature %02x", SETUPDAT[2]);
|
|
return FALSE;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
return handle_vendorcommand(SETUPDAT[1]);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
handle_set_feature()
|
|
{
|
|
printf("Set Feature %02x\n", SETUPDAT[0]);
|
|
switch (SETUPDAT[0]) {
|
|
case GF_DEVICE:
|
|
if (SETUPDAT[2] == 2)
|
|
break; // this is TEST_MODE and we simply need to return the handshake
|
|
if (SETUPDAT[2] == 1) {
|
|
remote_wakeup_allowed = TRUE;
|
|
break;
|
|
}
|
|
return FALSE;
|
|
case GF_ENDPOINT:
|
|
if (SETUPDAT[2] == 0) { // ep stall feature
|
|
// set TRM 2.3.2
|
|
// stall and endpoint
|
|
__xdata BYTE *pep = ep_addr(SETUPDAT[4]);
|
|
printf("Stall ep %d\n", SETUPDAT[4]);
|
|
if (!pep) {
|
|
return FALSE;
|
|
}
|
|
|
|
*pep |= bmEPSTALL;
|
|
// should now reset data toggles
|
|
// write ep+dir to TOGCTL
|
|
RESETTOGGLE(SETUPDAT[4]);
|
|
// restore stalled ep to default condition
|
|
// NOTE
|
|
//handle_reset_ep(SETUPDAT[4]);
|
|
|
|
} else {
|
|
printf("unsupported ep feature %02x\n", SETUPDAT[2]);
|
|
return FALSE;
|
|
}
|
|
break;
|
|
default:
|
|
return handle_vendorcommand(SETUPDAT[1]);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* these are devined in dscr.asm
|
|
and need to be customized then
|
|
linked in by the firmware manually */
|
|
extern __code WORD dev_dscr;
|
|
extern __code WORD dev_qual_dscr;
|
|
extern __code WORD highspd_dscr;
|
|
extern __code WORD fullspd_dscr;
|
|
extern __code WORD dev_strings;
|
|
|
|
WORD pDevConfig = (WORD) & fullspd_dscr;
|
|
WORD pOtherConfig = (WORD) & highspd_dscr;
|
|
|
|
void
|
|
handle_hispeed(BOOL highspeed)
|
|
{
|
|
__critical {
|
|
printf("Hi Speed or reset Interrupt\n");
|
|
if (highspeed) {
|
|
pDevConfig = (WORD) & highspd_dscr;
|
|
pOtherConfig = (WORD) & fullspd_dscr;
|
|
} else {
|
|
pDevConfig = (WORD) & fullspd_dscr;
|
|
pOtherConfig = (WORD) & highspd_dscr;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle:
|
|
* Device Descriptor
|
|
* Device Qualifier
|
|
* Configuration
|
|
* String
|
|
* Other-Speed
|
|
**/
|
|
void
|
|
handle_get_descriptor()
|
|
{
|
|
//printf ( "Get Descriptor\n" );
|
|
|
|
switch (SETUPDAT[3]) {
|
|
case DSCR_DEVICE_TYPE:
|
|
printf("Get Device Config\n");
|
|
SUDPTRH = MSB((WORD) & dev_dscr);
|
|
SUDPTRL = LSB((WORD) & dev_dscr);
|
|
break;
|
|
case DSCR_CONFIG_TYPE:
|
|
// get the config descriptor
|
|
printf("Get Config Descriptor\n");
|
|
SUDPTRH = MSB(pDevConfig);
|
|
SUDPTRL = LSB(pDevConfig);
|
|
break;
|
|
case DSCR_STRING_TYPE:
|
|
//printf ( "Get String Descriptor idx: %d\n", SETUPDAT[2] );
|
|
{
|
|
STRING_DSCR *pStr = (STRING_DSCR *) & dev_strings;
|
|
// pStr points to string 0
|
|
BYTE idx = SETUPDAT[2];
|
|
BYTE cur = 0; // current check
|
|
do {
|
|
if (idx == cur++)
|
|
break;
|
|
//printf ( "Length of pStr: %d\n", pStr->dsc_len );
|
|
//printf ( "pstr: %04x to ", pStr );
|
|
pStr =
|
|
(STRING_DSCR *) ((BYTE *) pStr +
|
|
pStr->dsc_len);
|
|
//printf ( "%04x\n" , pStr );
|
|
if (pStr->dsc_type != DSCR_STRING_TYPE)
|
|
pStr = NULL;
|
|
} while (pStr && cur <= idx);
|
|
|
|
if (pStr) {
|
|
/* BYTE i;
|
|
//printf ( "found str: '");
|
|
for (i=0;i<pStr->dsc_len-2;++i) {
|
|
printf ( i%2==0?"%c":"%02x", *((BYTE*)(&pStr->pstr)+i));
|
|
} printf ( "\n"); */
|
|
|
|
SUDPTRH = MSB((WORD) pStr);
|
|
SUDPTRL = LSB((WORD) pStr);
|
|
//SUDPTRH = MSB((WORD)&dev_strings);
|
|
//SUDPTRL = LSB((WORD)&dev_strings);
|
|
} else {
|
|
STALLEP0();
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
case DSCR_DEVQUAL_TYPE:
|
|
printf("Get Device Qualifier Descriptor\n");
|
|
// assumes this is a high speed capable device
|
|
SUDPTRH = MSB((WORD) & dev_qual_dscr);
|
|
SUDPTRL = LSB((WORD) & dev_qual_dscr);
|
|
break;
|
|
case DSCR_OTHERSPD_TYPE:
|
|
printf("Other Speed Descriptor\n");
|
|
SUDPTRH = MSB(pOtherConfig);
|
|
SUDPTRL = LSB(pOtherConfig);
|
|
break;
|
|
default:
|
|
printf("Unhandled Get Descriptor: %02x\n", SETUPDAT[3]);
|
|
STALLEP0();
|
|
}
|
|
|
|
}
|