//------------------------------------------------------------------- // ajayseek.cpp // // This program discovers the current device-address that Linux // has assigned to our Debug Peripheral, assuming it is plugged // in to the proper USB port and has been successfully detected // by system software. Its algorithm consists of executing the // 'Get Descriptor' control-transfer transaction for successive // device-addresses in the range from 0 up through 127, until a // Debug device-descriptor is successfully returned or else the // range of legal USB device-addresses has been exhausted. For // learning purposes, our screen-output shows EHCI diagnostics. // // to compile: $ g++ ajayseek.cpp -o ajayseek // to execute: $ ./ajayseek // // NOTE: Our 'ajay.c' kernel module is needed for this program. // // programmer: ALLAN CRUSE // written on: 22 FEB 2010 //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for lseek(), usleep() #include // for strcmp() #include // for signal() #include // for mmap() #define AJAYBASE 0x80000 // suitable address for io-mapping #define BULKSIZE 512 // maximum size of 'bulk' transfer unsigned int *lp = (unsigned int*)AJAYBASE; // registers array char devname[] = "/dev/ajay"; // name for our driver device-node void my_sigint_handler( int signo ) { exit(1); } int initiate_debug_port_transaction( unsigned int *lp ) { lp[ 0xA0 >> 2 ] = lp[ 0xA0 >> 2 ] | (1 << 5); // set the GO bit while ( ( lp[ 0xA0 >> 2 ] & (1 << 16)) == 0 ); // await DONE bit return ( ( lp[ 0xA0 >> 2 ] >> 6 )&0xF ); // GOOD or ERROR } void display_controller_registers( unsigned int *lp ) { printf( " USB2CMD=%08X ", lp[ 0x20 >> 2 ] ); printf( " USB2STS=%08X ", lp[ 0x24 >> 2 ] ); printf( " PORT0SC=%08X ", lp[ 0x64 >> 2 ] ); printf( " CNTL_STS=%08X ", lp[ 0xA0 >> 2 ] ); printf( "\n" ); } void release_debug_port_ownership( void ) { printf( "\n\n Quitting... \n" ); lp[ 0xA0 >> 2 ] = 0x00010000; // OWNER_CTL=0, ENABLE_CTL=0 display_controller_registers( lp ); } void exhibit_debug_port_registers( unsigned int *lp ) { unsigned int token_pid = (lp[ 0xA4 >> 2 ] >> 0)&0xFF; unsigned int recv_pid = (lp[ 0xA4 >> 2 ] >> 16)&0xFF; switch( token_pid ) { case 0x2D: printf( "\r SETUP: " ); break; case 0x69: printf( "\r IN: " ); break; case 0xE1: printf( "\r OUT: " ); break; default: printf( "\r " ); break; } printf( " CNTL_STS=%08X ", lp[ 0xA0 >> 2 ] ); printf( " USBPID=%06X ", lp[ 0xA4 >> 2 ] ); printf( " DATABUF=%08X-%08X ", lp[ 0xA8 >> 2 ], lp[ 0xAC >> 2 ] ); switch ( recv_pid ) { case 0x00: printf( " " ); break; case 0xD2: printf( "(ACK) " ); break; case 0x5A: printf( "(NAK) " ); break; case 0x96: printf( "(NYET) " ); break; case 0x1E: printf( "(STALL)" ); break; case 0xC3: printf( "(DATA0)" ); break; case 0x4B: printf( "(DATA1)" ); break; default: printf( "(--?--)" ); break; } } int main( int argc, char **argv ) { // open the device-file for reading and writing int fd = open( devname, O_RDWR ); if ( fd < 0 ) { perror( devname ); exit(1); } // map the EHCI registers to user-space int size = lseek( fd, 0, SEEK_END ); int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; void *mm = (void*)AJAYBASE; if ( mmap( mm, size, prot, flag, fd, 0 ) == MAP_FAILED ) { perror( "mmap" ); exit(1); } // insure that debug port 'ownership' will get released atexit( release_debug_port_ownership ); signal( SIGINT, my_sigint_handler ); // show state of the relevant EHCI controller registers printf( "\n Detecting... \n" ); printf( " CONFIGFLAG=%X ", lp[ 0x60 >> 2 ] ); printf( " USB2INTR=%08X ", lp[ 0x28 >> 2 ] ); printf( "\n" ); display_controller_registers( lp ); printf( "\n" ); // interpret readiness of the EHCI for Debug Port usage unsigned int port0sc = lp[ 0x64 >> 2 ]; unsigned int cfgflag = lp[ 0x60 >> 2 ]; unsigned int dbgcmd = lp[ 0xA0 >> 2 ]; unsigned int usbpid = lp[ 0xA4 >> 2 ]; unsigned int config = lp[ 0xB0 >> 2 ]; if ( cfgflag == 1 ) printf( " EHCI initialized" ); else { printf( "\n EHCI controller is uninitialized " ); exit(1); } if ( (port0sc & 1)==1 ) printf( ", Port 0 connected" ); else { printf( "\n Port 0 is not connected " ); exit(1); } if ( ( (port0sc >> 13)&1 )==0 ) printf( ", but not owned" ); else { printf( "\n Port 0 is already owned " ); exit(1); } if ( ( (dbgcmd >> 30)&1 )==0 ) printf( ", Debug Port available" ); else { printf( "\n Debug Port is already owned " ); exit(1); } printf( "\n\n" ); printf( "\n Now seeking the Debug Peripheral's device-address...\n\n" ); unsigned int dev = 0; do { lp[ 0xB0 >> 2 ] = (dev << 8); printf( " Executing a 'Get Descriptor' control-transfer" ); printf( " with register CONFIG=%04X \n", lp[ 0xB0 >> 2 ] ); // Step 1: the SETUP stage (for 'Get Descriptor') lp[ 0xA8 >> 2 ] = 0x0A000680; // DATABUF_31: lp[ 0xAC >> 2 ] = 0x00080000; // BATABUF_74: lp[ 0xA4 >> 2 ] = 0x0000C32D; // USBPID: SETUP, DATA0 lp[ 0xA0 >> 2 ] = 0x50010018; // CNTL_STS: send 8 bytes initiate_debug_port_transaction( lp ); exhibit_debug_port_registers( lp ); printf( "\n"); // Step 2: the DATA stage (for 'Get_Descriptor') lp[ 0xA8 >> 2 ] = 0xFFFFFFFF; // DATABUF_31: all ones lp[ 0xAC >> 2 ] = 0xFFFFFFFF; // DATABUF_74: all ones lp[ 0xA4 >> 2 ] = 0x0000C369; // USBPID: IN, DATA0 lp[ 0xA0 >> 2 ] = 0x50010008; // CNTL_STS: recv 4 bytes initiate_debug_port_transaction( lp ); exhibit_debug_port_registers( lp ); printf( "\n"); unsigned nbytes = (lp[ 0xA0 >> 2 ] & 0x0F); // Step 3: the HANDSHAKE stage (for 'Get_Descriptor') lp[ 0xA4 >> 2 ] = 0x0000C3E1; // USBPID: OUT, DATA0 lp[ 0xA0 >> 2 ] = 0x50010010; // CNTL_STS: transmit 0 bytes initiate_debug_port_transaction( lp ); exhibit_debug_port_registers( lp ); printf( "\n"); if ( nbytes > 0 ) break; } while ( ++dev < 128 ); if ( dev == 128 ) printf( "\n No Debug Peripheral was detected. \n " ); else printf( "\n Debug Peripheral's device-address = %d \n", dev ); }