/*
CPYR: (c) 2002 Beier & Dauskardt IT (www.beier-dauskardt.com)
FILE: urbmine.cpp
DATE: 04.01.2002
AUTH: S.Dauskardt
CMNT: Read,convert and decode USBSnoop output.
	Attempts to analyse OnSpec LC1 Family protocol.


What we need to cleanup:

 * combin upstream/downstream urb's.
 * Shown Data of bulk transfere's only where needed.
 * Decode Endpoints (PipeHandle)


*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>





// SSFDC Card-attributes derived from device-id.
//
#define SSFDCA_PAGE256				0x0001
#define SSFDCA_PAGE512				0x0002
#define SSFDCA_FLASH				0x0004
#define SSFDCA_ROM				0x0008
#define SSFDCA_MULTIZONE			0x0010

// SSFDC Device-attributes
//
#define SSFDCDA_READ_MULTIPLE_REDUNDANCYS	0x0001
#define SSFDCDA_HAS_COPY_PAGE			0x0002
#define SSFDCDA_HAS_WRITE_AND_ERASE		0x0004


//
//
typedef struct ssfdc_geometry {

	// direct results out of the Device-ID:
	//
	int		attributes;

	unsigned long	capacity;		// Size of card in bytes
	int		pagesize;		// Size of page in bytes
	int		pageshift;		// log2 of pagesize

	int		blocksize;		// Size of block in pages 
	int		blockshift;		// log2 of blocksize 
	int		blockmask;		// 2^blockshift - 1

	int		physblocks;		// 256,512,1024
	int		logblocks;		// 250,500,1000
	int		zones;			// 1,2,4,8

} ssfdc_geometry_t, *pssfdc_geometry;

//
//
//
// A few known geomertrys..
//
const struct ssfdc_geometry ssfdcgeo_1MB_Flash={
	attributes:	SSFDCA_PAGE256|SSFDCA_FLASH, 	
	capacity:	0x0100000,
	pagesize:	256,	pageshift:	8,
	blocksize:	16,	blockshift:	4,	blockmask:	0xF,
	physblocks:	256,	logblocks:	250,	zones:		1
};

const struct ssfdc_geometry ssfdcgeo_2MB_Flash={
	attributes:	SSFDCA_PAGE256|SSFDCA_FLASH, 	
	capacity:	0x0200000,
	pagesize:	256,	pageshift:	8,
	blocksize:	16,	blockshift:	4,	blockmask:	0xF,
	physblocks:	512,	logblocks:	500,	zones:		1
};
const struct ssfdc_geometry ssfdcgeo_2MB_ROM={
	attributes:	SSFDCA_PAGE512|SSFDCA_ROM, 
	capacity:	0x0200000,
	pagesize:	512,	pageshift:	9,
	blocksize:	16,	blockshift:	4,	blockmask:	0xF,
	physblocks:	256,	logblocks:	250,	zones:		1
};

const struct ssfdc_geometry ssfdcgeo_4MB_Flash={
	attributes:	SSFDCA_PAGE512|SSFDCA_FLASH, 
	capacity:	0x0400000,
	pagesize:	512,	pageshift:	9,
	blocksize:	16,	blockshift:	4,	blockmask:	0xF,
	physblocks:	512,	logblocks:	500,	zones:		1
};
const struct ssfdc_geometry ssfdcgeo_4MB_ROM={
	attributes:	SSFDCA_PAGE512|SSFDCA_ROM, 
	capacity:	0x0400000,
	pagesize:	512,	pageshift:	9,
	blocksize:	16,	blockshift:	4,	blockmask:	0xF,
	physblocks:	512,	logblocks:	500,	zones:		1
};

const struct ssfdc_geometry ssfdcgeo_8MB_Flash={
	attributes:	SSFDCA_PAGE512|SSFDCA_FLASH, 
	capacity:	0x0800000,
	pagesize:	512,	pageshift:	9,
	blocksize:	16,	blockshift:	4,	blockmask:	0xF,
	physblocks:	1024,	logblocks:	1000,	zones:		1
};
const struct ssfdc_geometry ssfdcgeo_8MB_ROM={
	attributes:	SSFDCA_PAGE512|SSFDCA_ROM, 
	capacity:	0x0800000,
	pagesize:	512,	pageshift:	9,
	blocksize:	16,	blockshift:	4,	blockmask:	0xF,
	physblocks:	1024,	logblocks:	1000,	zones:		1
};

const struct ssfdc_geometry ssfdcgeo_16MB_Flash={
	attributes:	SSFDCA_PAGE512|SSFDCA_FLASH, 
	capacity:	0x1000000,
	pagesize:	512,	pageshift:	9,
	blocksize:	32,	blockshift:	5,	blockmask:	0x1F,
	physblocks:	1024,	logblocks:	1000,	zones:		1
};
const struct ssfdc_geometry ssfdcgeo_32MB_Flash={
	attributes:	SSFDCA_PAGE512|SSFDCA_FLASH|SSFDCA_MULTIZONE, 
	capacity:	0x2000000,
	pagesize:	512,	pageshift:	9,
	blocksize:	32,	blockshift:	5,	blockmask:	0x1F,
	physblocks:	2048,	logblocks:	2000,	zones:		2
};
const struct ssfdc_geometry ssfdcgeo_64MB_Flash={
	attributes:	SSFDCA_PAGE512|SSFDCA_FLASH|SSFDCA_MULTIZONE, 
	capacity:	0x4000000,
	pagesize:	512,	pageshift:	9,
	blocksize:	32,	blockshift:	5,	blockmask:	0x1F,
	physblocks:	4096,	logblocks:	4000,	zones:		4
};
const struct ssfdc_geometry ssfdcgeo_128MB_Flash={
	attributes:	SSFDCA_PAGE512|SSFDCA_FLASH|SSFDCA_MULTIZONE, 
	capacity:	0x8000000,
	pagesize:	512,	pageshift:	9,
	blocksize:	32,	blockshift:	5,	blockmask:	0x1F,
	physblocks:	8192,	logblocks:	8000,	zones:		8
};


// Get Card geometry 
//
const ssfdc_geometry *ssfdc_get_card_geo(int DeviceID)
{
	switch( DeviceID ){
	case 0x6E:
	case 0xE8:
	case 0xEC:	return &ssfdcgeo_1MB_Flash;	break;

	case 0xEA:
	case 0x64:	return &ssfdcgeo_2MB_Flash;	break;
	case 0x5D:	return &ssfdcgeo_2MB_ROM;		break;

	case 0xE3:
	case 0xE5:
	case 0x6B:	return &ssfdcgeo_4MB_Flash;	break;
	case 0xD5:	return &ssfdcgeo_4MB_ROM;		break;
 
	case 0xE6:	return &ssfdcgeo_8MB_Flash;	break;
	case 0xD6:	return &ssfdcgeo_8MB_ROM;		break;

	case 0x73:	return &ssfdcgeo_16MB_Flash;	break;

	case 0x75:	return &ssfdcgeo_32MB_Flash;	break;

	case 0x76:	return &ssfdcgeo_64MB_Flash;	break;

	case 0x79:	return &ssfdcgeo_128MB_Flash;	break;

	default:
		// Undefined state.
		//
		return 0;
	}
}




/*
00000182	0.04747978	<<<<<<< URB 8 coming back...	
00000183	0.04751917	-- URB_FUNCTION_SELECT_CONFIGURATION:	
00000184	0.04754906	  ConfigurationDescriptor = 0x813ceac8 (configure)	
00000185	0.04757979	  ConfigurationDescriptor : bLength             = 0x09	
00000186	0.04760577	  ConfigurationDescriptor : bDescriptorType     = 0x02	
00000187	0.04763119	  ConfigurationDescriptor : wTotalLength        = 0x0020	
00000188	0.04765606	  ConfigurationDescriptor : bNumInterfaces      = 0x01	
00000189	0.04768511	  ConfigurationDescriptor : bConfigurationValue = 0x01	
00000190	0.04771528	  ConfigurationDescriptor : iConfiguration      = 0x00	
00000191	0.04774126	  ConfigurationDescriptor : bmAttributes        = 0xc0	
00000192	0.04776696	  ConfigurationDescriptor : MaxPower            = 0x32	
00000193	0.04779602	  ConfigurationHandle     = 0xe14580e8	
00000194	0.04782619	  Interface[0]: Length            = 0x00000038	
00000195	0.04785189	  Interface[0]: InterfaceNumber   = 0x00	
00000196	0.04787648	  Interface[0]: AlternateSetting  = 0x00	
00000197	0.04790106	  Interface[0]: Class             = 0xff	
00000198	0.04792536	  Interface[0]: SubClass          = 0x00	
00000199	0.04794967	  Interface[0]: Protocol          = 0x00	
00000200	0.04797593	  Interface[0]: InterfaceHandle   = 0x813e13a8	
00000201	0.04800163	  Interface[0]: NumberOfPipes     = 0x00000002	
00000202	0.04803376	  Interface[0]: Pipes[0] : MaximumPacketSize = 0x0040	
00000203	0.04806114	  Interface[0]: Pipes[0] : EndpointAddress   = 0x01	
00000204	0.04809019	  Interface[0]: Pipes[0] : Interval          = 0x00	
00000205	0.04812176	  Interface[0]: Pipes[0] : PipeType          = 0x02 (UsbdPipeTypeBulk)	
00000206	0.04815612	  Interface[0]: Pipes[0] : PipeHandle        = 0x813e13c0	
00000207	0.04819300	  Interface[0]: Pipes[0] : MaxTransferSize   = 0x00010000	
00000208	0.04821982	  Interface[0]: Pipes[0] : PipeFlags         = 0x00	

00000209	0.04825334	  Interface[0]: Pipes[1] : MaximumPacketSize = 0x0040	
00000210	0.04827988	  Interface[0]: Pipes[1] : EndpointAddress   = 0x82	
00000211	0.04830502	  Interface[0]: Pipes[1] : Interval          = 0x00	
00000212	0.04833994	  Interface[0]: Pipes[1] : PipeType          = 0x02 (UsbdPipeTypeBulk)	
00000213	0.04837403	  Interface[0]: Pipes[1] : PipeHandle        = 0x813e13dc	
00000214	0.04840280	  Interface[0]: Pipes[1] : MaxTransferSize   = 0x00010000	
00000215	0.04842878	  Interface[0]: Pipes[1] : PipeFlags         = 0x00	
00000216	0.04882017	UsbSnoop - IRP_MJ_INTERNAL_DEVICE_CONTROL, IOCTL_INTERNAL_USB_SUBMIT_URB	

EP1-O , EP2-I


i.e. Change 
00000218	0.04886236	>>>>>>> URB 9 going down...	
00000219	0.04888666	-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:	
00000220	0.04891683	  PipeHandle           = 813e13c0	
00000221	0.04895091	  TransferFlags        = 00000000 (USBD_TRANSFER_DIRECTION_OUT, ~USBD_SHORT_TRANSFER_OK)	
00000222	0.04898025	  TransferBufferLength = 00000008	
00000223	0.04900539	  TransferBuffer       = 813c372c	
00000224	0.04902606	  TransferBufferMDL    = 00000000	
00000225	0.04904087	 	
00000226	0.04915597	    0000: 00 01 00 00 00 a0 ec 01 	
00000227	0.04917329	  UrbLink              = 00000000	
00000228	0.05014185	 	
00000229	0.05014995	<<<<<<< URB 9 coming back...	
00000230	0.05018208	-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:	
00000231	0.05021169	  PipeHandle           = 813e13c0	
00000232	0.05024437	  TransferFlags        = 00000000 (USBD_TRANSFER_DIRECTION_OUT, ~USBD_SHORT_TRANSFER_OK)	
00000233	0.05027036	  TransferBufferLength = 00000008	
00000234	0.05029941	  TransferBuffer       = 813c372c	
00000235	0.05032763	  TransferBufferMDL    = 81391b48	
00000236	0.05034634	  UrbLink              = 00000000	





00000239	0.05041926	>>>>>>> URB 10 going down...	
00000240	0.05044328	-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:	
00000241	0.05047066	  PipeHandle           = 813e13dc	
00000242	0.05050083	  TransferFlags        = 00000002 (USBD_TRANSFER_DIRECTION_OUT, USBD_SHORT_TRANSFER_OK)	
00000243	0.05053100	  TransferBufferLength = 00000200	
00000244	0.05055084	  TransferBuffer       = 00000000	
00000245	0.05057626	  TransferBufferMDL    = 81391b48	
00000246	0.05059470	 	
00000247	0.05082741	    0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000248	0.05104811	    0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000249	0.05127356	    0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000250	0.05150487	    0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000251	0.05173814	    0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000252	0.05199180	    0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000253	0.05219378	    0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000254	0.05242258	    0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000255	0.05265418	    0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000256	0.05288773	    0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000257	0.05310424	    00a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000258	0.05333695	    00b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000259	0.05356798	    00c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000260	0.05386746	    00d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000261	0.05419683	    00e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000262	0.05450916	    00f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000263	0.05481283	    0100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000264	0.05508912	    0110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000265	0.05539894	    0120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000266	0.05570540	    0130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000267	0.05601410	    0140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000268	0.05628229	    0150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000269	0.05662926	    0160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000270	0.05694243	    0170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000271	0.05720895	    0180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000272	0.05752072	    0190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000273	0.05783025	    01a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000274	0.05809984	    01b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000275	0.05844961	    01c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000276	0.05875831	    01d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000277	0.05904438	    01e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000278	0.05932989	    01f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	
00000279	0.05935615	  UrbLink              = 00000000	
00000280	0.05956120	 	
00000281	0.05957713	<<<<<<< URB 10 coming back...	
00000282	0.05961260	-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:	
00000283	0.05964361	  PipeHandle           = 813e13dc	
00000284	0.05968189	  TransferFlags        = 00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)	
00000285	0.05971429	  TransferBufferLength = 00000002	
00000286	0.05974111	  TransferBuffer       = 00000000	
00000287	0.05977324	  TransferBufferMDL    = 81391b48	
00000288	0.05979699	 	
00000289	0.05986515	    0000: ff 04 	
00000290	0.05989057	  UrbLink              = 00000000	



00000218	0.04886236	URB 9 --> EP1-O sent 8/8 Bytes
				    0000: 00 01 00 00 00 a0 ec 01 	

00000239	0.05041926	URB 10 <-- EP2-I recieved 2/512 Bytes
				    0000: ff 04 	

*/


// Remember Endpoint <--> PipeHandles here.
//
typedef struct EPInfo {
	int			IFace;
	int			Pipe;

	int			EpAddr;		// 0x80 --> In
	unsigned long int	PipeHandle;

} *PEPInfo;

const int MAX_EPs = 16;
EPInfo	EPInfoTable[MAX_EPs];
int	EPInfoCnt;

PEPInfo GetAllocEPInfo(int IFace,int Pipe)
{
	for(int i=0;i<EPInfoCnt;i++){
		if( EPInfoTable[i].IFace == IFace &&
		    EPInfoTable[i].Pipe == Pipe )
			return &EPInfoTable[i];
	}

	PEPInfo epi;

	if( EPInfoCnt < MAX_EPs ){
		epi = &EPInfoTable[EPInfoCnt++];
	}else{
		epi = &EPInfoTable[EPInfoCnt-1];
	}

	epi->IFace = IFace;
	epi->Pipe = Pipe;

	epi->EpAddr	= 0;
	epi->PipeHandle	= 0;
	return epi;
}

int GetEPAddr(unsigned long int	PipeHandle)
{
	for(int i=0;i<EPInfoCnt;i++){
		if( EPInfoTable[i].PipeHandle == PipeHandle ){
			return EPInfoTable[i].EpAddr;
		}
	}

	return 0xFF;
}



// Rought category of USBSnoop output lines.
//
//
const short LID_UPSTREAM_URB	= ((('<')<<8) | '<');
const short LID_DOWNSTREAM_URB	= ((('>')<<8) | '>');
const short LID_URB_DATA	= (((' ')<<8) | ' ');
const short LID_SNOOP_INFO	= ((('U')<<8) | 's');
const short LID_EMPTY		= (((' ')<<8) | '\t');

int SplitLine(char *Line,int& LineNr,char *TimeStamp,short& LineID,char *LineData)
{
	// "00000281	0.05957713	<<<<<<< URB 10 coming back..."
	//
        //  012345678901234567890123456789
 	// "00000281 0.05957713 <<<<<<< URB 10 coming back..."
	//
	// Tab oder '  '

	if( !Line)
		return 0;

	char *Tab1 = strchr(Line,'\t');
	if(!Tab1){
		Tab1 = strchr(Line,' ');
		if(Tab1)
			Tab1++;
	}
	if(!Tab1)
		return 0;

	char *Tab2 = strchr(Tab1+1,'\t');
	if(!Tab2){
		Tab2 = strchr(Tab1+1,' ');
		if(Tab2)
			Tab2++;
	}
	if(!Tab2)
		return 0;

	char *Tab3 = strchr(Tab2+1,'\t');
	if(!Tab3){
		Tab3 = strchr(Tab2+1,' ');
		if(Tab3)
			Tab3++;
	}
	if(!Tab3)
		return 0;

	*Tab1++ = 0;
	*Tab2++ = 0;

	LineNr = atoi(&Line[0]);

	strcpy(TimeStamp,Tab1);

	LineID = (((short)Tab2[0]) << 8 ) | Tab2[1];

	strcpy(LineData,Tab2);

	return LineID;
}


enum {
	EPDIR_UNKNOWN	= 0,
	EPDIR_UPSTREAM,		// IN	
	EPDIR_DOWNSTREAM	// OUT
};

enum {
	LT_BAD = 0,

	LT_BORING,

	LT_URB_HEADER,

	LT_HEXDATA,
	LT_PIPEHANDLE,
	LT_TXBUFLEN,

	LT_IF_EP_ADDR,
	LT_IF_EP_PIPEHANDLE,

	LT_SNOOPMSG
};

typedef struct DecodedLine {

	int	LineNr;
	short	LineID;
	char	TimeStamp[32];
	char	LineData[128];

	int	LineType;

	union {
		struct {
			int	UrbNr;
			int	UrbDir;
		} UrbHeader;

		struct {
			int	Ofs;
			int	Bytes;
		} HexData;

		struct {
			unsigned long int PipeHandle;
		} PipeHandle;

		struct {
			unsigned long int TxBufLen;
		} TxBufLen;

		struct {
			int	IFace;
			int	Pipe;
			int	IfEpAddr;
		} IfEpAddr;

		struct {
			int	IFace;
			int	Pipe;
			unsigned long int PipeHandle;
		} IfEpPipeHandle;

	} UrbSpecData;

} *PDecodedLine;

/*
   TransferFlags        = 00000000 (USBD_TRANSFER_DIRECTION_OUT, ~USBD_SHORT_TRANSFER_OK)
*/

#define SET_TXT(txt)	{ Txt = (txt); TxtLen = strlen(txt); }

int DecodeLine(char *Line,PDecodedLine Dcdln)
{
	char *Mark;
	char	*Txt;
	int	TxtLen;

	Dcdln->LineType = LT_BORING;

	if(!SplitLine(Line,Dcdln->LineNr,Dcdln->TimeStamp,Dcdln->LineID,Dcdln->LineData))
		return 0;

	Mark = Dcdln->LineData;

// printf("%04x <-- '%s'\n",Dcdln->LineID,Dcdln->LineData);

	switch( Dcdln->LineID){
	case LID_UPSTREAM_URB:
		SET_TXT("<<<<<<< URB ");
		if(!strncmp(Mark,Txt,TxtLen)){
			Mark += TxtLen;

			Dcdln->LineType				= LT_URB_HEADER;
			Dcdln->UrbSpecData.UrbHeader.UrbNr	= atoi(Mark);
			Dcdln->UrbSpecData.UrbHeader.UrbDir	= EPDIR_UPSTREAM;
		}
		break;

	case LID_DOWNSTREAM_URB:

		SET_TXT(">>>>>>> URB ");
		if(!strncmp(Mark,Txt,TxtLen)){
			Mark += TxtLen;

			Dcdln->LineType				= LT_URB_HEADER;
			Dcdln->UrbSpecData.UrbHeader.UrbNr	= atoi(Mark);
			Dcdln->UrbSpecData.UrbHeader.UrbDir	= EPDIR_DOWNSTREAM;
		}
		break;

	case LID_URB_DATA:

		SET_TXT("  PipeHandle           = ");
		if(!strncmp(Mark,Txt,TxtLen)){
			Mark += TxtLen;

			Dcdln->UrbSpecData.PipeHandle.PipeHandle	= strtoul(Mark,0,16);
			Dcdln->LineType					= LT_PIPEHANDLE;
			break;
		}

		SET_TXT("  TransferBufferLength = ");
		if(!strncmp(Mark,Txt,TxtLen)){
			Mark += TxtLen;

			Dcdln->UrbSpecData.TxBufLen.TxBufLen		= strtoul(Mark,0,16);
			Dcdln->LineType					= LT_TXBUFLEN;
			break;
		}

		/*
00000209	0.04825334	  Interface[0]: Pipes[1] : MaximumPacketSize = 0x0040	
00000210	0.04827988	  Interface[0]: Pipes[1] : EndpointAddress   = 0x82	
00000211	0.04830502	  Interface[0]: Pipes[1] : Interval          = 0x00	
00000212	0.04833994	  Interface[0]: Pipes[1] : PipeType          = 0x02 (UsbdPipeTypeBulk)	
00000213	0.04837403	  Interface[0]: Pipes[1] : PipeHandle        = 0x813e13dc	
00000214	0.04840280	  Interface[0]: Pipes[1] : MaxTransferSize   = 0x00010000	
00000215	0.04842878	  Interface[0]: Pipes[1] : PipeFlags         = 0x00	

		*/

		SET_TXT("  Interface[");
		if(!strncmp(Mark,Txt,TxtLen)){
			Mark += TxtLen;

			int iface = (int)strtol(Mark,&Mark,10);

			SET_TXT("]: Pipes[");
			if(!strncmp(Mark,Txt,TxtLen)){
				Mark += TxtLen;

				int pipe = (int)strtol(Mark,&Mark,10);

				SET_TXT("] : EndpointAddress   = ");
				if(!strncmp(Mark,Txt,TxtLen)){
					Mark += TxtLen;
				
					Dcdln->UrbSpecData.IfEpAddr.IFace	= iface;
					Dcdln->UrbSpecData.IfEpAddr.Pipe	= pipe;
					Dcdln->UrbSpecData.IfEpAddr.IfEpAddr	= (int )strtoul(Mark,0,16);
					Dcdln->LineType				= LT_IF_EP_ADDR;
					break;	
				}

				SET_TXT("] : PipeHandle        = ");
				if(!strncmp(Mark,Txt,TxtLen)){
					Mark += TxtLen;
				
					Dcdln->UrbSpecData.IfEpPipeHandle.IFace	= iface;
					Dcdln->UrbSpecData.IfEpPipeHandle.Pipe	= pipe;
					Dcdln->UrbSpecData.IfEpPipeHandle.PipeHandle	= (int )strtoul(Mark,0,16);
					Dcdln->LineType				= LT_IF_EP_PIPEHANDLE;
					break;	
				}


			}
			break;
		}



		//

		SET_TXT("    ");
		if(!strncmp(Mark,Txt,TxtLen)){
			Mark += TxtLen;

			Dcdln->UrbSpecData.HexData.Ofs		= strtoul(Mark,0,16);
			Dcdln->UrbSpecData.HexData.Bytes	= 0;

			Dcdln->LineType					= LT_HEXDATA;
			break;
		}
		break;

	case LID_SNOOP_INFO:
		Dcdln->LineType = LT_SNOOPMSG;
		break;
	}

	return Dcdln->LineType;
}



const int MAX_LINES_PER_URB	= 2*(4096+30);	// Enough for 65536 Databytes.
const int MAX_DATA_BYTES	= 65536;

typedef class UnidirUrbData {
public:
	DecodedLine	Lines[MAX_LINES_PER_URB];
	int		LineCnt;

	unsigned char	DataBuffer[MAX_DATA_BYTES];
	int		DataBytes;

	int			UrbNr;
	int			UrbDir;
	int			FirstLineNr;
	char			FirstTimeStamp[32];

	int			LastLineNr;
	char			LastTimeStamp[32];

	unsigned long int	PipeHandle;
	int			DataDir;
	unsigned long int	TxBufLen;

	int			EndPoint;

public:
	UnidirUrbData()
	{
		LineCnt = 0;


		UrbNr		= -1;
		UrbDir		= EPDIR_UNKNOWN;

		FirstLineNr	= -1;
		FirstTimeStamp[0] = 0;
		LastLineNr	= -1;
		LastTimeStamp[0] = 0;

		PipeHandle	= 0;
		DataDir		= EPDIR_UNKNOWN;
		TxBufLen	= 0;

		EndPoint	= 0;

		DataBytes = 0;
	}

	void	AddLine(PDecodedLine Dcdln)
	{
		if( LineCnt >= MAX_LINES_PER_URB ){
			printf("LineBuffer Overflow !\n");
			return;
		}

		int	Add = 0;

		//

		if( FirstLineNr < 0 ){
			FirstLineNr = Dcdln->LineNr;
			strcpy(FirstTimeStamp,Dcdln->TimeStamp);
		}
		LastLineNr = Dcdln->LineNr;
		strcpy(LastTimeStamp,Dcdln->TimeStamp);


		switch( Dcdln->LineType ){
		case LT_URB_HEADER:
			UrbNr	= Dcdln->UrbSpecData.UrbHeader.UrbNr;
			UrbDir	= Dcdln->UrbSpecData.UrbHeader.UrbDir;
			break;

		case LT_PIPEHANDLE:
			PipeHandle = Dcdln->UrbSpecData.PipeHandle.PipeHandle;

			EndPoint = GetEPAddr(PipeHandle);
			if( EndPoint != 0xFF ){
				if( EndPoint & 0x80 ){
					DataDir = EPDIR_UPSTREAM;
				}else{
					DataDir = EPDIR_DOWNSTREAM;
				}

				EndPoint &= 0x7F;
			}
			break;

		case LT_TXBUFLEN:
			TxBufLen = Dcdln->UrbSpecData.TxBufLen.TxBufLen;
			break;

		case LT_HEXDATA:
			Add = 1;

			{
				// "    xxxx: xx xx xx xx xx xx xx xx"
				//
				int Ofs = Dcdln->UrbSpecData.HexData.Ofs;

				if( Ofs != DataBytes ){
					printf("HexData Decode ofs error: %d != %d\n",Ofs,DataBytes);
				}else{
					char *Mark = &Dcdln->LineData[9];	// Auf'm space
					char *Err;

					for(;DataBytes<MAX_DATA_BYTES;){
						unsigned long int b = strtoul(Mark,&Err,16);

						if( Err != Mark+3 )
							break;

						DataBuffer[DataBytes++] = (unsigned char)b;
						Mark = Err;
					}
				}
			}
			break;
		}

		// Really remember lines ?
		//
		if( Add )
			Lines[ LineCnt++ ]= *Dcdln;
	}

	void	OutputData()
	{
		for(int l=0;l<LineCnt;l++){

			PDecodedLine	Dcdln = &Lines[l];

			switch( Dcdln->LineType ){
			case LT_HEXDATA:
				if( Dcdln->UrbSpecData.HexData.Ofs < 64 )
					printf("%08d       %s\n",Dcdln->LineNr,Dcdln->LineData);
				break;
			}
		}
	}

} *PUnidirUrbData;


/*

    +--+--+-----------------> High,Mid,Low Sector Nr ?
    |  |  |  +--------------> N.Sects ? (512 Byte cnt)
    |  |  |  |  +-----------> Const 0xB0 ??
    |  |  |  |  |  +--------> 256 Byte Cnt.
    |  |  |  |  |  |  +-----> CMD
    |  |  |  |  |  |  |
xx xx xx xx xx xx xx xx

CMD:
0x80 - Get Status				[00 00 00 00 00 b0 00 80]
	Read 4 or 2 Bytes afterwards.
	Get 4 - Good
		--> Then read another 2
	Get 2 - Bad

	Good: Read Back twice:
		0b 20 00 00
		50 00

	Bad: Read Back 
		ff 04

0x84 - Get Card Type ??				[00 00 00 00 00 b0 00 84]

	Read back 4 then 2 bytes:

		98 e6 a5 9a -->  8MB SSFDC
		ec 75 48 bb --> 32MB SSFDC

		Memory Stick Dreck:
		00 04 20 00 --> 16MB MS		00 04 --> 0x400 --> 1024 Blöcke ?
						20 00 --> 0x020 --> 32 Sectors / Block ?
		00 08 20 00 --> 32MB MS

		50 00 	


		98 76 a5 ba	64MB SSFDC (Olympus)
		ec 75 48 bb	32MB SSFDC (Olympus)
		98 73 a5 ba	16MB SSFDC
		ec 73 a5 bb	16MB SSFDC
		98 e6 a5 9a	 8MB SSFDC
		ec e6 43 9a	 8MB SSFDC (Olympus)
		    |
		    +-------------> Card ID !
				   Rest Dreck ??


0x85 - Read Sectors				[00 hh mm ll 00 b0 ss 85]
	- Read Data
	- Then Read Status (2 Bytes 50 00)

0x86 - Write Sectors

0x8a - Read Something ?? Maybe Mapping Table 	[00 00 00 00 00 b0 08 8a]
 



---


a0 ec 01 - Get Slot 1 Status ???			[00 01 00 00 00 a0 ec 01]


	Give 2 or 512 Bytes:
	Good:
		ATA Identify Drive

	Bad:
		ff 04


e0 20 01 - Gead Sectors ?? 				[00 01 00 00 00 e0 20 01]
	lh ll bl bm bh e0 20 01



*/

enum {
	CARDTYPE_UNKNOWN = 0,
	CARDTYPE_CF,
	CARDTYPE_SD,
	CARDTYPE_SSFDC,
	CARDTYPE_MEMSTICK
};

int			CardType = CARDTYPE_UNKNOWN;


// MemStick related.
//
int			memstick_PhysBlock;
int			memstick_SectorsPerBlock;

int			memstick_pageshift;
int			memstick_blockshift;
int			memstick_blockmask;


// SSFDC Related.
//
int			ssfdc_CardID;
const ssfdc_geometry	*ssfdc_CardGeo;


//
//
int			DeviceIDUpstreamUrbNr = 0;






void GrabDeviceIDUrb(PUnidirUrbData DevIDUrb)
{
	if( DevIDUrb->DataBytes != 4 ){
		printf("		DeviceID had wrong size ! %d != %d\n",DevIDUrb->DataBytes,4);
		return;
	}

	if( (DevIDUrb->DataBuffer[0] == 0) && 
	    (DevIDUrb->DataBuffer[1] != 0) && 
	    (DevIDUrb->DataBuffer[2] != 0) && 
	    (DevIDUrb->DataBuffer[3] == 0)    ){

		// Probably MemoryStick...
		//
		memstick_PhysBlock	= ((int)DevIDUrb->DataBuffer[1])*256;
		memstick_SectorsPerBlock = DevIDUrb->DataBuffer[2];


		CardType = CARDTYPE_MEMSTICK;

		printf("		Assuming MemoryStick, with %d Blocks a %d Sectors --> %d\n",
			memstick_PhysBlock,
			memstick_SectorsPerBlock,
			memstick_PhysBlock * memstick_SectorsPerBlock * 512
		);

		memstick_pageshift = 9;

		switch( memstick_SectorsPerBlock ){
		case 16: memstick_blockshift = 4; memstick_blockmask = 0x0F; break;
		case 32: memstick_blockshift = 5; memstick_blockmask = 0x1F; break;
		case 64: memstick_blockshift = 6; memstick_blockmask = 0x3F; break;
		default:
			printf("		BAD SecsPerBlock !!\n");
			CardType = CARDTYPE_UNKNOWN;
			break;
		}

		return;
	}


	ssfdc_CardGeo = ssfdc_get_card_geo(DevIDUrb->DataBuffer[1]);
	if( ssfdc_CardGeo ){
		CardType = CARDTYPE_SSFDC;

		printf("		Assuming SSFDC, with %d Blocks a %d Sectors --> %d\n",
			ssfdc_CardGeo->physblocks,
			ssfdc_CardGeo->blocksize,

			ssfdc_CardGeo->physblocks *
			ssfdc_CardGeo->blocksize * 
			ssfdc_CardGeo->pagesize
		);
		return;
	}


	printf("		Unknown DeviceID: %02x %02x %02x %02x\n",
		DevIDUrb->DataBuffer[0],
		DevIDUrb->DataBuffer[1],
		DevIDUrb->DataBuffer[2],
		DevIDUrb->DataBuffer[3]
	);

	return;
}






// Remember Physical <---> Logical Block mappings here,
//
//
int	MappingTableUpstreamUrbNr = 0;
int	MappingTableSize = 0;

const int MAX_MAP_TBL = 32768;	// 128MB

short	sMapTbl[MAX_MAP_TBL];
int	MapTbl[MAX_MAP_TBL];
int	MapTblEnt = 0;

int MapFindRev(int r)
{
	for(int e=0;e<MapTblEnt;e++){
		if( MapTbl[e] == r)
			return e;
	}

	return -1;
}

int MapFindRevCnt(int r)
{
	int	cnt=0;
	for(int e=0;e<MapTblEnt;e++){
		if( MapTbl[e] == r)
			cnt++;
	}

	return cnt;
}

int MapFind(int r)
{
	if( r < 0 || r >= MapTblEnt )
		return -1;

	return MapTbl[r];
}

void GrabMappingTableUrb(PUnidirUrbData MapUrb)
{
	if( MapUrb->DataBytes != MappingTableSize*2 ){
		printf("		Mapping Data had wrong size ! %d != %d\n",MapUrb->DataBytes,MappingTableSize*2);
		return;
	}

	if( MappingTableSize <= 0 || MappingTableSize > MAX_MAP_TBL){
		printf("		Can't handle Mapping table size %d\n",MappingTableSize);
		return;
	}

	memcpy(sMapTbl,MapUrb->DataBuffer,MappingTableSize*2);
	MapTblEnt = MappingTableSize;

	switch( CardType ){
	case CARDTYPE_SSFDC:

		// Hm, SSFDC Cards with more than 1023 Block (not pages) are divided into
		// zones of 1000/1024 Blocks.
		//
		for(int zc=0;zc<MappingTableSize;zc++){
			MapTbl[zc] = sMapTbl[zc] | (zc&0xFC00);	// Fudge in missing bits.
		}
		break;

	case CARDTYPE_MEMSTICK:

		// MemorsSticks also have zones (called segments here) - these are 512/500 
		// Blocks long, but are transparent to us.
		//
	default:
		for(int zc=0;zc<MappingTableSize;zc++){
			MapTbl[zc] = sMapTbl[zc];
		}
		break;
	}


    if( CardType==CARDTYPE_SSFDC ){

	for(int e=0;e<MapTblEnt;e++){

		printf("		Phys %5d --> Log %5d		",
			e,MapTbl[e]
		);


		int	ZoneBase = (e/1024)*1000;
		int	ZoneOfs = e%1024;

	if( ZoneOfs < 1000 ){
		int	logical = ZoneBase+ZoneOfs;

		int cnt = MapFindRevCnt(e);
		switch( cnt ){
		case 0:
			printf("Zone-Log %5d --> Phys --- not mapped\n",
				logical
			);
			break;
		case 1:
			printf("Zone-Log %5d --> Phys %5d\n",
				logical,MapFindRev(e)
			);
			break;
		default:
			printf("Zone-Log %5d --> mapped %d times.\n",
				logical,cnt
			);
			break;
		}
	}else{
		printf("\n");
	}

		if( e%1024 == 1023 )
			printf("		-- zone boundary --\n");
	}

    }else{

	for(int e=0;e<MapTblEnt;e++){

		printf("		Phys %5d --> Log %5d		",
			e,MapTbl[e]
		);

		int cnt = MapFindRevCnt(e);
		switch( cnt ){
		case 0:
			printf("		"
				"Phys %5d --> Log %5d"
				"		"
				"Log %5d --> Phys --- not mapped\n",
				e,MapTbl[e],e
			);
			break;
		case 1:
			printf("		"
				"Phys %5d --> Log %5d"
				"		"
				"Log %5d --> Phys %5d\n",
				e,MapTbl[e],
				e,MapFindRev(e)
			);
			break;
		default:
			printf("		"
				"Phys %5d --> Log %5d"
				"		"
				"Log %5d --> mapped %d times.\n",
				e,MapTbl[e],
				e,cnt
			);
			break;
		}
	}
    }
}


//
//
void AttemptCmdDecode(PUnidirUrbData CmdUrb)
{
	char	cmd_Slot1Status[] =	{ 0x00,0x01,0x00,0x00,0x00,0xa0,0xec,0x01 };
	char	cmd_Slot2Status[] =	{ 0x00,0x00,0x00,0x00,0x00,0xb0,0x00,0x80 };
	char	cmd_Slot2Identify[] =	{ 0x00,0x00,0x00,0x00,0x00,0xb0,0x00,0x84 };


	if( CmdUrb->DataBytes != 8 ){
		printf("		Bad Length Cmd: %d\n",CmdUrb->DataBytes);
		return;
	}

	if( memcmp( CmdUrb->DataBuffer, cmd_Slot1Status, 8) == 0 ){
		printf("		LC1_Slot1_GetStatus\n");
		return;
	}

	if( memcmp( CmdUrb->DataBuffer, cmd_Slot2Status, 8) == 0 ){
		printf("		LC1_Slot2_GetStatus\n");
		return;
	}

	if( memcmp( CmdUrb->DataBuffer, cmd_Slot2Identify, 8) == 0 ){
		printf("		LC1_Slot2_Identify\n");

		DeviceIDUpstreamUrbNr	= CmdUrb->UrbNr + 1;

		return;
	}


	//

	switch( CmdUrb->DataBuffer[7] ){
	case 0x80:
		printf("		LC1_Slot2_GetStatus - little different version.\n");
		break;

	case 0x84:
		printf("		LC1_Slot2_Identify - little different version.\n");

		DeviceIDUpstreamUrbNr	= CmdUrb->UrbNr + 1;

		break;

	case 0x85:

		switch( CardType ){
		case CARDTYPE_SSFDC:
			{
			int	Sector =((int)CmdUrb->DataBuffer[1] << 16) |
					((int)CmdUrb->DataBuffer[2] <<  8) |
					((int)CmdUrb->DataBuffer[3] <<  0) ;

			int	Bytes =  (int)CmdUrb->DataBuffer[6]*256;

			int	nsec = Bytes/512;

			printf("		LC1_Slot2_ReadSectors %d-%d #%d (%d bytes)\n",
				Sector,
				Sector+nsec-1,
				nsec,
				Bytes
			);

			int	lba  = Sector >> (ssfdc_CardGeo->pageshift-9 + ssfdc_CardGeo->blockshift);
			int	page = (Sector >> ssfdc_CardGeo->pageshift-9) & ssfdc_CardGeo->blockmask;
			int	pba = MapFind(lba);	// Rev
			int	xlated = pba << (ssfdc_CardGeo->pageshift-9 + ssfdc_CardGeo->blockshift) | page;

			printf("		xlate %5d -> %4d:%2d ==> %4d:%2d -> %5d-%-5d\n",
				Sector,
				lba,page,
				pba,page,
				xlated,
				xlated+nsec-1
			);


			if(	CmdUrb->DataBuffer[0] != 0x00 ||
				CmdUrb->DataBuffer[4] != 0x00 ||
				CmdUrb->DataBuffer[5] != 0xb0    )
				printf("		- ABNORMAL at ofs 0,4 or 5 !\n");
			}
			break;

		case CARDTYPE_MEMSTICK:
			{
			int	page = (int)CmdUrb->DataBuffer[2];

			int	lba =	((int)CmdUrb->DataBuffer[3] <<  8) |
					((int)CmdUrb->DataBuffer[4] <<  0) ;

			int	Bytes =  (int)CmdUrb->DataBuffer[6]*256;

			int	nsec = Bytes/512;

			printf("		LC1_Slot2_ReadSectors %d:%d #%d (%d bytes)\n",
				lba,
				page,
				nsec,
				Bytes
			);

			int	pba = MapFind(lba);	// Rev
			int	xlated = pba << (memstick_pageshift-9 + memstick_blockshift) | page;

			printf("		xlate %4d:%2d ==> %4d:%2d -> %5d-%-5d\n",
				lba,page,
				pba,page,
				xlated,
				xlated+nsec-1
			);


			if(	CmdUrb->DataBuffer[0] != 0x00 ||
				CmdUrb->DataBuffer[1] != 0x00 ||
				CmdUrb->DataBuffer[5] != 0xb0    )
				printf("		- ABNORMAL at ofs 0,4 or 5 !\n");
			}

			break;

		default:
			{
			int	Sector =((int)CmdUrb->DataBuffer[1] << 16) |
					((int)CmdUrb->DataBuffer[2] <<  8) |
					((int)CmdUrb->DataBuffer[3] <<  0) ;

			int	Bytes =  (int)CmdUrb->DataBuffer[6]*256;

			int	nsec = Bytes/512;

			printf("		LC1_Slot2_ReadSectors %d-%d #%d (%d bytes)\n",
				Sector,
				Sector+nsec-1,
				nsec,
				Bytes
			);


			if(	CmdUrb->DataBuffer[0] != 0x00 ||
				CmdUrb->DataBuffer[4] != 0x00 ||
				CmdUrb->DataBuffer[5] != 0xb0    )
				printf("		- ABNORMAL at ofs 0,4 or 5 !\n");
			}
			break;
		}
		break;

	case 0x86:
		{
			int	Sector =((int)CmdUrb->DataBuffer[1] << 16) |
					((int)CmdUrb->DataBuffer[2] <<  8) |
					((int)CmdUrb->DataBuffer[3] <<  0) ;

			int	Bytes =  (int)CmdUrb->DataBuffer[4]*512;

			int	nsec = Bytes/512;

			int	Something = (int)CmdUrb->DataBuffer[0];

	
			// Something warscheinlich was zu tun mit der Mapping tabelle !

			printf("		LC1_Slot2_WriteSectors %5d-%5d #%2d Special:%2d (%5d bytes)\n",
				Sector,
				Sector+nsec-1,
				nsec,
				Something,
				Bytes
			);


			if(	CmdUrb->DataBuffer[5] != 0xb0 ||
				CmdUrb->DataBuffer[6] != 0x00    )
				printf("		- ABNORMAL at ofs 5 or 6 !\n");
		}
		break;

	case 0x8a:
		{
			int	Bytes =  (int)CmdUrb->DataBuffer[6]*256;
			int	Entries = Bytes / 2;

			printf("		LC1_Slot2_ReadMapTable #%d (%d bytes)\n",
				Entries,
				Bytes
			);

			if(	CmdUrb->DataBuffer[0] != 0x00 ||
				CmdUrb->DataBuffer[1] != 0x00 ||
				CmdUrb->DataBuffer[2] != 0x00 ||
				CmdUrb->DataBuffer[3] != 0x00 ||
				CmdUrb->DataBuffer[4] != 0x00 ||
				CmdUrb->DataBuffer[5] != 0xb0    )
				printf("		- ABNORMAL at ofs 0-5 !\n");


			// Ugly hook...
			//
			MappingTableUpstreamUrbNr	= CmdUrb->UrbNr + 1;
			MappingTableSize		= Entries;
		}
		break;

	case 0x01:
		// Slot 1 Stuff.
		//
		switch( CmdUrb->DataBuffer[6] ){
		case 0xEC:
			printf("		LC1_Slot1_GetStatus - little differen version.\n");
			break;

		case 0x20:
			{
				int	Sector =((int)CmdUrb->DataBuffer[4] << 16) |
						((int)CmdUrb->DataBuffer[3] <<  8) |
						((int)CmdUrb->DataBuffer[2] <<  0) ;
	
				int	Bytes =  (int)CmdUrb->DataBuffer[1]*512;

				int	nsec = Bytes/512;

				printf("		LC1_Slot1_ReadSectors %d-%d #%d (%d bytes)\n",
					Sector,
					Sector+nsec-1,
					nsec,
					Bytes
				);

				if(	CmdUrb->DataBuffer[0] != 0x00 ||
					CmdUrb->DataBuffer[5] != 0xe0    )
					printf("		- ABNORMAL at ofs 0 or 5 !\n");
			}
			break;
		}
		break;

	default:
		printf("		- UNKNOWN Cmd !\n");
		break;

	}
}

void DumpUrbPair(PUnidirUrbData CurrUrb,PUnidirUrbData LastUrb)
{
	if( CurrUrb->UrbNr != LastUrb->UrbNr ){
		printf("Unpeered Urbs feed to DumpUrbPair\n");
		return;
	}

	if( LastUrb->UrbDir != EPDIR_DOWNSTREAM ||
	    CurrUrb->UrbDir != EPDIR_UPSTREAM      ){

		printf("Funny urb directions for %d: %d,%d\n",
			CurrUrb->UrbNr,
			LastUrb->UrbDir,
			CurrUrb->UrbDir
		);
		return;
	}

	// So, Last goind down and Curr comming back.
	//
	if( LastUrb->DataDir != CurrUrb->DataDir ){
		printf("Data direction changing for urb %d: %d,%d\n",
			CurrUrb->UrbNr,
			LastUrb->DataDir,
			CurrUrb->DataDir
		);
		return;
	}

	if( LastUrb->EndPoint != CurrUrb->EndPoint ){
		printf("		EndPoint changing for urb %d: %d,%d\n",
			CurrUrb->UrbNr,
			LastUrb->EndPoint,
			CurrUrb->EndPoint
		);
//		return;
	}
		


	switch( LastUrb->DataDir ){
	case EPDIR_UPSTREAM:
		printf("%08d	<<<<<< URB %-4d, EP%d-IN   %4ld/%-4ld Bytes		(%s)\n",
			LastUrb->FirstLineNr,
			LastUrb->UrbNr,
			LastUrb->EndPoint,
			CurrUrb->TxBufLen,	// Tatsächlich gelesen
			LastUrb->TxBufLen,	// Max gelesen
			LastUrb->FirstTimeStamp
		);
		CurrUrb->OutputData();

		if( LastUrb->UrbNr == MappingTableUpstreamUrbNr )
			GrabMappingTableUrb(CurrUrb);

		if( LastUrb->UrbNr == DeviceIDUpstreamUrbNr )
			GrabDeviceIDUrb(CurrUrb);

		break;

	case EPDIR_DOWNSTREAM:

		if(	LastUrb->EndPoint == 1 &&
			CurrUrb->TxBufLen == 8 && 
			LastUrb->TxBufLen == 8    ){
			printf("\n\n");
			AttemptCmdDecode(LastUrb);
		}

		printf("%08d	>>>>>> URB %-4d, EP%d-OUT  %4ld/%-4ld Bytes		(%s)\n",
			LastUrb->FirstLineNr,
			LastUrb->UrbNr,
			LastUrb->EndPoint,
			CurrUrb->TxBufLen,	// Tatsächlich geschrieben
			LastUrb->TxBufLen,	// Max schrieben
			LastUrb->FirstTimeStamp
		);
		LastUrb->OutputData();
		break;

	default:
		printf("%08d	<----> URB %-4d, EP???  %ld/%ld Bytes		(%s)\n",
			LastUrb->FirstLineNr,
			LastUrb->UrbNr,
			CurrUrb->TxBufLen,	// Tatsächlich geschrieben
			LastUrb->TxBufLen,	// Max schrieben
			LastUrb->FirstTimeStamp
		);

		LastUrb->OutputData();

		break;
	}


	printf("%08d								(%s)\n",
			CurrUrb->LastLineNr,
			CurrUrb->LastTimeStamp
	);
}


int main(int ac,char **av)
{
	FILE	*Src;
	char	Line[512];
	struct DecodedLine 	dl,*Dcdln=&dl;


	PEPInfo epi;


	Src = fopen(av[1],"rb");

	if(!Src){

		printf("can't open something !\n");
		return 0;
	}

	int	UrbDir = EPDIR_UNKNOWN;
	int	DataDir = EPDIR_UNKNOWN;

	PUnidirUrbData	CurrUrb=0,LastUrb=0;

	int lns = 0;
	for(;;lns++){

		if(!fgets(Line,sizeof(Line),Src))
			break;

		char *x = strchr(Line,'\n');
		if(x)
			*x = 0;

		memset(Dcdln,0,sizeof(*Dcdln));

		int LineType = DecodeLine(Line,Dcdln);

		switch( LineType ){
		case LT_URB_HEADER:

			if( CurrUrb && LastUrb ){
				if( CurrUrb->UrbNr == LastUrb->UrbNr ){
					DumpUrbPair(CurrUrb,LastUrb);
				}

				delete LastUrb;
				LastUrb = CurrUrb;
				CurrUrb = new UnidirUrbData();

			}else if(CurrUrb && !LastUrb){

				LastUrb = CurrUrb;
				CurrUrb = new UnidirUrbData();

			}else if(!CurrUrb && !LastUrb){

				CurrUrb = new UnidirUrbData();
			}else{
				fprintf(stderr,"Urb peer Muck !\n");
				exit(1);
			}
			break;

		case LT_IF_EP_ADDR:
			/*
			printf("%08d    IF-EP-Addr %d:%d %02x\n",
					Dcdln->LineNr,
					Dcdln->UrbSpecData.IfEpAddr.IFace,
					Dcdln->UrbSpecData.IfEpAddr.Pipe,
					Dcdln->UrbSpecData.IfEpAddr.IfEpAddr
			);
			*/
			epi = GetAllocEPInfo(Dcdln->UrbSpecData.IfEpAddr.IFace,Dcdln->UrbSpecData.IfEpAddr.Pipe);
			epi->EpAddr	= Dcdln->UrbSpecData.IfEpAddr.IfEpAddr;
			break;

		case LT_IF_EP_PIPEHANDLE:
			/*
			printf("%08d    IF-EP-PipeHandle %d:%d %08lx\n",
					Dcdln->LineNr,
					Dcdln->UrbSpecData.IfEpPipeHandle.IFace,
					Dcdln->UrbSpecData.IfEpPipeHandle.Pipe,
					Dcdln->UrbSpecData.IfEpPipeHandle.PipeHandle
			);
			*/
			epi = GetAllocEPInfo(Dcdln->UrbSpecData.IfEpPipeHandle.IFace,Dcdln->UrbSpecData.IfEpPipeHandle.Pipe);
			epi->PipeHandle	= Dcdln->UrbSpecData.IfEpPipeHandle.PipeHandle;
			break;

		case LT_SNOOPMSG:

			// Dont want:
			//
			// "UsbSnoop - IRP_MJ_INTERNAL_DEVICE_CONTROL, IOCTL_INTERNAL_USB_SUBMIT_URB"
			//
			if( !strstr(Dcdln->LineData,"IOCTL_INTERNAL_USB_SUBMIT_URB") ){

				printf("%08d    %s\n",
					Dcdln->LineNr,
					Dcdln->LineData
				);
			}
			break;
		}

		if( CurrUrb )
			CurrUrb->AddLine(Dcdln);
	}

	// Cleanoff's.

	if( CurrUrb && LastUrb ){
		if( CurrUrb->UrbNr == LastUrb->UrbNr ){
			DumpUrbPair(CurrUrb,LastUrb);
		}else{
			printf("Ending up with unpeered urbs %d & %d.\n",CurrUrb->UrbNr,LastUrb->UrbNr);
		}

		delete CurrUrb;
		delete LastUrb;

		CurrUrb = 0;
		LastUrb = 0;
	}

	if( CurrUrb ){
		printf("Ending up lonely CurrUrb %d.\n",CurrUrb->UrbNr);
		delete CurrUrb;
		CurrUrb = 0;
	}

	if( LastUrb ){
		printf("Ending up lonely LastUrb %d.\n",LastUrb->UrbNr);
		delete LastUrb;
		LastUrb = 0;
	}

	fclose(Src);

	printf("Processed %d lines.\n",lns);
}













