|
Server : Apache/2.2.2 (Fedora) System : Linux App1.pathumtani.go.th 2.6.20-1.2320.fc5smp #1 SMP Tue Jun 12 19:40:16 EDT 2007 i686 User : apache ( 48) PHP Version : 5.2.9 Disable Function : NONE Directory : /usr/local/src/apcupsd-3.14.10/examples/ |
Upload File : |
/*
* snoopdecode.c
*
* Decodes traces captured by 'usbsnoop'
* (http://benoit.papillault.free.fr/usbsnoop/index.php)
*
* See usbsnoop.txt for details.
*/
/*
* Copyright (C) 2004-2005 Adam Kropelin
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General
* Public License as published by the Free Software Foundation.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LINE 1024
char line[MAX_LINE] = "";
FILE* file;
enum
{
DIR_UNKNOWN = 0,
DIR_TO_DEVICE,
DIR_FROM_DEVICE
};
enum
{
FUNC_UNKNOWN = 0,
FUNC_CONTROL_TXFER,
FUNC_CLASS_INTERFACE,
FUNC_GET_DESC,
FUNC_SELECT_CONFIG,
FUNC_GET_DESC_FROM_IFACE,
FUNC_BULK_TXFER,
FUNC_RESET_PIPE,
FUNC_ABORT_PIPE,
};
enum
{
REQ_GET_REPORT = 1,
REQ_GET_IDLE = 2,
REQ_GET_PROTOCOL = 3,
REQ_SET_REPORT = 9,
REQ_SET_IDLE = 10,
REQ_SET_PROTOCOL = 11
};
struct urb
{
int seq;
unsigned long len;
unsigned char* data;
unsigned long flags;
unsigned long index;
unsigned long type;
unsigned long reserved;
unsigned long request;
unsigned long value;
int time;
int dir;
int func;
};
struct rpt
{
struct rpt* next;
unsigned char* data;
int seq;
unsigned short len;
unsigned char id;
unsigned long value;
};
struct rpt* rpts = NULL;
/*
[197 ms] >>> URB 1 going down >>>
-- URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
TransferBufferLength = 00000012
TransferBuffer = 864c9208
TransferBufferMDL = 00000000
Index = 00000000
DescriptorType = 00000001 (USB_DEVICE_DESCRIPTOR_TYPE)
LanguageId = 00000000
[203 ms] UsbSnoop - MyInternalIOCTLCompletion(f7b91db0) : fido=00000000, Irp=863df850, Context=86405d10, IRQL=2
[203 ms] <<< URB 1 coming back <<<
-- URB_FUNCTION_CONTROL_TRANSFER:
PipeHandle = 863e4150
TransferFlags = 0000000b (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000012
TransferBuffer = 864c9208
TransferBufferMDL = 8640f108
00000000: 12 01 10 01 00 00 00 08 1d 05 02 00 06 00 03 01
00000010: 02 01
UrbLink = 00000000
*/
/*
[59563 ms] >>> URB 346 going down >>>
-- URB_FUNCTION_CLASS_INTERFACE:
TransferFlags = 00000001 (USBD_TRANSFER_DIRECTION_IN, ~USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000005
TransferBuffer = f7f12ba0
TransferBufferMDL = 00000000
UrbLink = 00000000
RequestTypeReservedBits = 00000022
Request = 00000001
Value = 0000032f
Index = 00000000
[59567 ms] UsbSnoop - MyInternalIOCTLCompletion(f7b91db0) : fido=86397288, Irp=85ff4b40, Context=85f4b3d8, IRQL=2
[59567 ms] <<< URB 346 coming back <<<
-- URB_FUNCTION_CONTROL_TRANSFER:
PipeHandle = 863e4150
TransferFlags = 0000000b (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000002
TransferBuffer = f7f12ba0
TransferBufferMDL = 85f102f0
00000000: 2f 02
UrbLink = 00000000
SetupPacket =
00000000: a1 01 2f 03 00 00 05 00
*/
int fetch_line()
{
return !!fgets(line, sizeof(line), file);
}
int find_urb()
{
do
{
if (line[0] == '[' && strstr(line, " URB ") &&
(strstr(line, "going down") || strstr(line, "coming back")))
{
return 1;
}
}
while( fetch_line() );
return 0;
}
int init_urb(struct urb* urb)
{
memset(urb, 0, sizeof(*urb));
if (!find_urb())
return 0;
urb->time = atoi(line+1);
if (strstr(line, "going down"))
urb->dir = DIR_TO_DEVICE;
else if(strstr(line, "coming back"))
urb->dir = DIR_FROM_DEVICE;
else
urb->dir = DIR_UNKNOWN;
urb->seq = atoi(strstr(line,"URB ")+4);
return 1;
}
unsigned long get_hex_value()
{
char* ptr = strchr(line, '=');
if (!ptr)
return 0xffff;
return strtoul(ptr+2, NULL, 16);
}
unsigned char* parse_data_dump(int len)
{
int count = 0;
char* ptr= NULL;
unsigned char* data = (unsigned char *)malloc(len);
if (!data)
return NULL;
while(count < len)
{
if ((count % 16) == 0)
{
if (count)
{
if (!fetch_line())
{
free(data);
return NULL;
}
}
ptr = strchr(line, ':');
if (!ptr)
{
free(data);
return NULL;
}
ptr += 2;
}
data[count++] = strtoul(ptr, NULL, 16);
ptr += 3;
}
return data;
}
void parse_urb_body(struct urb* urb)
{
int setup_packet = 0;
while (fetch_line())
{
if (line[0] == '[')
break;
if (strstr(line, "TransferBufferLength"))
{
urb->len = get_hex_value();
}
else if (strstr(line, "TransferFlags"))
{
urb->flags = get_hex_value();
}
else if (strstr(line, "Index"))
{
urb->index = get_hex_value();
}
else if (strstr(line, "DescriptorType"))
{
urb->type = get_hex_value();
}
else if (strstr(line, "RequestTypeReservedBits"))
{
urb->reserved = get_hex_value();
}
else if (strstr(line, "Request"))
{
urb->request = get_hex_value();
}
else if (strstr(line, "Value"))
{
urb->value = get_hex_value();
}
else if (strstr(line, "SetupPacket"))
{
setup_packet = 1;
}
else if (strstr(line, "00000000:"))
{
if (!setup_packet && !urb->data)
urb->data = parse_data_dump(urb->len);
}
else if (strstr(line, "-- URB_FUNCTION_"))
{
if (strstr(line, "URB_FUNCTION_CONTROL_TRANSFER"))
urb->func = FUNC_CONTROL_TXFER;
else if (strstr(line, "URB_FUNCTION_CLASS_INTERFACE"))
urb->func = FUNC_CLASS_INTERFACE;
else if (strstr(line, "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE"))
urb->func = FUNC_GET_DESC;
else if (strstr(line, "URB_FUNCTION_SELECT_CONFIGURATION"))
urb->func = FUNC_SELECT_CONFIG;
else if (strstr(line, "URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE"))
urb->func = FUNC_GET_DESC_FROM_IFACE;
else if (strstr(line, "URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER"))
urb->func = FUNC_BULK_TXFER;
else if (strstr(line, "URB_FUNCTION_RESET_PIPE"))
urb->func = FUNC_RESET_PIPE;
else if (strstr(line, "URB_FUNCTION_ABORT_PIPE"))
urb->func = FUNC_ABORT_PIPE;
else
{
urb->func = FUNC_UNKNOWN;
printf("Unknown FUNC: %s\n", line);
exit(0);
}
}
}
}
void free_urb(struct urb* urb)
{
free(urb->data);
}
void print_urb(struct urb* urb)
{
unsigned int x;
printf("[%08d ms] %05d %c ", urb->time, urb->seq,
(urb->dir == DIR_TO_DEVICE) ? '>' : (urb->dir == DIR_FROM_DEVICE) ? '<' : '?');
printf("req=%04lx value=%04lx", urb->request, urb->value);
if( urb->data )
{
printf(" [");
for(x=0; x<urb->len; x++)
{
printf( "%02x", urb->data[x] );
if (x < urb->len-1)
printf(" ");
}
printf("]");
}
printf("\n");
}
struct rpt* find_report_by_seq(int seq)
{
struct rpt* rpt = rpts;
while( rpt )
{
if (rpt->seq == seq)
break;
rpt = rpt->next;
}
return rpt;
}
struct rpt* find_report_by_id(unsigned char id)
{
struct rpt* rpt = rpts;
while( rpt )
{
if (rpt->id == id)
break;
rpt = rpt->next;
}
return rpt;
}
void del_report(struct urb* urb)
{
unsigned char id = urb->data[0];
struct rpt* rpt = rpts;
struct rpt** prev = &rpts;
while( rpt )
{
if (rpt->id == id)
break;
prev = &(rpt->next);
rpt = rpt->next;
}
if (rpt)
{
*prev = rpt->next;
free(rpt);
}
}
void add_report(struct urb* urb)
{
struct rpt* rpt;
unsigned char id;
if (urb->data)
id = urb->data[0];
else
id = urb->value & 0xff;
if ((rpt = find_report_by_id(id)))
{
rpt->seq = urb->seq;
rpt->value = urb->value;
return;
}
rpt = (struct rpt*)malloc(sizeof(*rpt));
memset(rpt, 0, sizeof(*rpt));
rpt->id = id;
rpt->seq = urb->seq;
rpt->value = urb->value;
rpt->next = rpts;
rpts = rpt;
}
int check_and_update_report(struct urb* urb)
{
struct rpt* rpt;
rpt = find_report_by_seq(urb->seq);
if (!rpt)
return 0;
if (rpt->data && !memcmp(rpt->data, urb->data+1, urb->len-1))
return 0;
free(rpt->data);
rpt->len = urb->len-1;
rpt->data = (unsigned char *)malloc(rpt->len);
memcpy(rpt->data, urb->data+1, rpt->len);
return 1;
}
void display_report(struct urb* urb)
{
unsigned long data = 0;
char buf[9];
unsigned int n;
n = printf( "[%04d s] %05d %c %s 0x%02x (%03u) ",
urb->time/1000, urb->seq, urb->func == FUNC_BULK_TXFER ? '*' : ' ',
urb->dir==DIR_TO_DEVICE ? "WRITE" : " READ", urb->data[0], urb->data[0]);
switch (urb->len)
{
case 5:
data = (data << 8) | urb->data[4];
case 4:
data = (data << 8) | urb->data[3];
case 3:
data = (data << 8) | urb->data[2];
case 2:
data = (data << 8) | urb->data[1];
sprintf(buf, "%0*lx", (int)(urb->len-1)*2, data);
n += printf( "%8s (%lu)", buf, data );
break;
default:
n += printf( "-------- (----------)" );
break;
}
printf( "%*c", 55-n, ' ');
for (n=0; n<urb->len-1; n++)
printf("%02x ", urb->data[n+1]);
printf("\n");
fflush(stdout);
}
void update_reports(struct urb* urb)
{
if (urb->dir == DIR_TO_DEVICE)
{
// Only care about class requests
if (urb->func != FUNC_CLASS_INTERFACE)
return;
if (urb->request == REQ_GET_REPORT)
{
add_report(urb);
}
else if (urb->request == REQ_SET_REPORT)
{
display_report(urb);
del_report(urb);
}
}
else
{
if (urb->func == FUNC_CONTROL_TXFER)
{
if (check_and_update_report(urb))
display_report(urb);
}
else if (urb->data && urb->func == FUNC_BULK_TXFER)
{
add_report(urb);
if (check_and_update_report(urb))
display_report(urb);
}
}
}
int main(int argc, char* argv[])
{
struct urb urb;
file = stdin;
while(init_urb(&urb))
{
parse_urb_body(&urb);
update_reports(&urb);
free_urb(&urb);
}
return 0;
}