#ifdef USB_DISK 
/*******************************************************************************
 *
 *
 *	Copyright 2003 Steven James <pyro@linuxlabs.com> and
 *	LinuxLabs http://www.linuxlabs.com
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 *	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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 ******************************************************************************/

#include <etherboot.h>
#include <pci.h>
#include <timer.h>
#include <lib.h>

#define DEBUG_THIS DEBUG_USB
#include <debug.h>

#define DPRINTF debug

#include "usb.h"
#include "uhci.h"
#include "debug_x.h"

//#include <string.h>


void dump_link( link_pointer_t *link, char *prefix)
{
	DPRINTF("%saddr: %08x\n", prefix, MEM_ADDR(link->link) );
	DPRINTF("%s raw addr: %04x\n", prefix, (link->link) <<4 );
	DPRINTF("%sterminate: %x\n", prefix, link->terminate);
	DPRINTF("%squeue: %x\n", prefix, link->queue);
	DPRINTF("%sdepth: %x\n", prefix, link->depth);
}

void dump_frame_list( link_pointer_t *addr, char *prefix)
{
	int i;

	DPRINTF("%sFRAMELIST:\n",prefix);

	for(i=0;i<10; i++) {
		dump_link(addr+i, prefix);
		if(addr[i].queue)
			dump_queue_head( MEM_ADDR(addr[i].link), "");
		else
			dump_td( MEM_ADDR(addr[i].link), "");
	}
}

void dump_hex(uchar *data, int len, char *prefix)
{
	int i=0;

	while(i<len) {
		if(!i%16) {
			DPRINTF("\n%s %04x: ", prefix, i);
		}
		else {
			DPRINTF(": ");
		}

		DPRINTF("%02x", data[i++]);
	}

	DPRINTF("\n");
}

void dump_uhci(uint32_t port)
{
#if 0
	unsigned long value;
#endif

	DPRINTF("HCI at %08x\n", port);
#if 0
	value = inw(port);
	DPRINTF("Command: %04x\n", value);

	value = inw(port+2);
	DPRINTF("USBSTS: %04x\n", value);

	value = inw(port+4);
	DPRINTF("USBINTR: %04x\n", value);

	value = inw(port+6);
	DPRINTF("FRNUM: %04x\n", value);

	value = inl(port+8);
	DPRINTF("FLBASEADD: %08x\n", value);

	value = inb(port+0x0c);
	DPRINTF("SOFMOD: %02x\n", value);

	value = inw(port+0x10);
	DPRINTF("PORTSTS1: %04x\n", value);

	value = inw(port+0x12);
	DPRINTF("PORTSTS2: %04x\n", value);
	
#endif

}

void dump_td( td_t *td, char *prefix)
{
	char newpre[64];

	newpre[0]='\t';
	strcpy(newpre+1, prefix);

	DPRINTF("%sTD(%08x):\n", prefix, td);

	switch(td->packet_type) {
		case SETUP_TOKEN:
			DPRINTF("%stype: SETUP\n", prefix);
			break;
		case OUT_TOKEN:
			DPRINTF("%stype: OUT\n", prefix);
			break;
		case IN_TOKEN:
			DPRINTF("%stype: IN\n", prefix);
			break;
		default:
			DPRINTF("%stype: INVALID (%02x)\n", prefix, td->packet_type);
			break;
	}

	DPRINTF("%sretries: %x\n", prefix, td->retrys);

	if(td->isochronous) {
		DPRINTF("%sisochronous\n", prefix);
	}

	if(td->interrupt) {
		DPRINTF("%sIOC\n", prefix);
	}

	if(td->lowspeed) {
		DPRINTF("%slowspeed\n", prefix);
	}

	if(td->detect_short) {
		DPRINTF("%sDETECT_SHORT\n", prefix);
	}

	DPRINTF("%sactive: %04x\n", prefix, td->active);
	DPRINTF("%sdevice_addr: %02x\n", prefix, td->device_addr);
	DPRINTF("%sendpoint: %1x\n", prefix, td->endpoint);
	DPRINTF("%sdata_toggle: %1x\n", prefix, td->data_toggle);
	DPRINTF("%smax_transfer: %x\n", prefix, td->max_transfer);
	DPRINTF("%sactual: %x\n", prefix, td->actual);
	DPRINTF("%slink:\n", prefix);

	if(td->stall) {
		DPRINTF("%sSTALL\n", prefix);
	}

	if(td->bitstuff) {
		DPRINTF("%sBITSTUFF ERROR\n", prefix);
	}

	if(td->crc) {
		DPRINTF("%sCRC ERROR\n", prefix);
	}

	if(td->nak) {
		DPRINTF("%sNAK ERROR\n", prefix);
	}

	if(td->babble) {
		DPRINTF("%sBABBLE ERROR\n", prefix);
	}

	if(td->buffer_error) {
		DPRINTF("%sBUFFER ERROR\n", prefix);
	}

	if(MEM_ADDR(td->link.link) == td) {
		DPRINTF("link loops back to me!\n");
		return;
	}

	dump_link(&(td->link), newpre);
	if(!td->link.terminate) {
		if(td->link.queue)
			dump_queue_head(MEM_ADDR(td->link.link), prefix );
		else
			dump_td(MEM_ADDR(td->link.link), prefix);
	}
}

void dump_queue_head( queue_head_t *qh, char *prefix)
{
	char newpre[64];

	newpre[0] = '\t';
	strcpy(newpre+1, prefix);

	DPRINTF("%sQUEUE HEAD(%x):\n", prefix, qh);
	DPRINTF("%sdepth:\n", prefix);
	dump_link( &(qh->depth), newpre);

	if(!qh->depth.terminate) {
		if(qh->depth.queue) {
			dump_queue_head(MEM_ADDR(qh->depth.link), newpre);
		}
		else {
			dump_td( MEM_ADDR(qh->depth.link), newpre);
		}
	}
		

	DPRINTF("%sbredth:\n", prefix);
	dump_link( &(qh->bredth), newpre);
	if(!qh->bredth.terminate) {
		if(qh->bredth.queue) {
			dump_queue_head(MEM_ADDR(qh->bredth.link), newpre);
		}
		else {
			dump_td( MEM_ADDR(qh->bredth.link), newpre);
		}
	}
}

void dump_transaction( transaction_t *trans, char *prefix)
{
	char newpre[64];

	newpre[0] = '\t';
	strcpy(newpre+1, prefix);


	DPRINTF("%s TRANSACTION(%x):\n", prefix, trans);
	dump_queue_head( trans->qh, newpre);

	DPRINTF("%s TDs:\n", prefix);
	dump_td( trans->td_list, newpre);

	DPRINTF("\n");
	if(trans->next)
		dump_transaction(trans->next, prefix);
}

void dump_usbdev( usbdev_t *dev, char *prefix)
{
	char newpre[64];
	int i;

	newpre[0] = '\t';
	strcpy(newpre+1, prefix);

	DPRINTF("%saddress: %x\n", prefix, dev->address);
	DPRINTF("%sclass: %x\n", prefix, dev->class);
	DPRINTF("%ssubclass: %x\n", prefix, dev->subclass);
	DPRINTF("%sbulk_in: %x\n", prefix, dev->bulk_in);
	DPRINTF("%sbulk_out: %x\n", prefix, dev->bulk_out);
	DPRINTF("%sinterrupt: %x\n", prefix, dev->interrupt);

	DPRINTF("%sep toggle:\n", prefix);
		for(i=0;i<MAX_EP;i++) {
			DPRINTF("%s%x\n", newpre, dev->toggle[i]);
		}

	DPRINTF("%sep max_packet:\n", prefix);
		for(i=0;i<MAX_EP;i++) {
			DPRINTF("%s%x\n", newpre, dev->max_packet[i]);
		}
}

void dump_all_usbdev(char *prefix)
{
	int i;

	for(i=0;i<MAX_USB_DEV;i++) {
		if(usb_device[i].address) {
			DPRINTF("%sDEVICE: %x\n", prefix, i);
			dump_usbdev( usb_device +i, prefix);
		}
	}
}

void dump_device_descriptor( device_descriptor_t *des, char *prefix)
{
	DPRINTF("%sbLength: %02x\n", prefix, des->bLength);
	DPRINTF("%stype: %02x\n", prefix, des->type);
	DPRINTF("%sbcdVersion: %1x%1x\n", prefix, des->bcdVersion[1], des->bcdVersion[0]);
	DPRINTF("%sClass: %02x\n",prefix, des->Class);
	DPRINTF("%sSubClass: %02x\n",prefix, des->SubClass);
	DPRINTF("%sprotocol: %02x\n",prefix, des->protocol);
	DPRINTF("%smax_packet: %x\n",prefix, des->max_packet);
	DPRINTF("%sidVendor: %04x\n", prefix, des->idVendor);
	DPRINTF("%sidProduct: %04x\n", prefix, des->idProduct);
	DPRINTF("%sbcdDeviceVersion: %1x%1x\n", prefix, des->bcdDevice[1], des->bcdDevice[0]);
	DPRINTF("%siManufacturor: %02x\n", prefix, des->iManufacturor);
	DPRINTF("%siProduct: %02x\n", prefix, des->iProduct);
	DPRINTF("%siSerial: %02x\n", prefix, des->iSerial);
	DPRINTF("%sbNumConfig: %02x\n", prefix, des->bNumConfig);

}

void dump_interface_descriptor( interface_descriptor_t *iface, char *prefix)
{

	DPRINTF("%sbLength: %02x\n", prefix, iface->bLength);
	DPRINTF("%stype: %02x\n", prefix, iface->type);
	DPRINTF("%sbInterfaceNumber: %02x\n", prefix, iface->bInterfaceNumber);
	DPRINTF("%sbAlternateSetting: %02x\n", prefix, iface->bAlternateSetting);
	DPRINTF("%sbNumEndpoints: %02x\n", prefix, iface->bNumEndpoints);
	DPRINTF("%sbInterfaceClass: %02x\n", prefix, iface->bInterfaceClass);
	DPRINTF("%sbInterfaceSubClass: %02x\n", prefix, iface->bInterfaceSubClass);
	DPRINTF("%sbInterfaceProtocol: %02x\n", prefix, iface->bInterfaceProtocol);
	DPRINTF("%siInterface: %02x\n", prefix, iface->iInterface);
}

void dump_endpoint_descriptor( endpoint_descriptor_t *ep, char *prefix)
{

	DPRINTF("%sbLength: %02x\n", prefix, ep->bLength);
	DPRINTF("%stype: %02x\n", prefix, ep->type);
	DPRINTF("%sbEndpointAddress: %02x\n", prefix, ep->bEndpointAddress);
	DPRINTF("%sbmAttributes: %02x\n", prefix, ep->bmAttributes);
	DPRINTF("%swMaxPacketSize: %02x\n", prefix, ep->wMaxPacketSize);
	DPRINTF("%sbInterval: %02x\n", prefix, ep->bInterval);
}

void dump_config_descriptor( uchar *des, char *prefix)	// YES uchar *
{
	config_descriptor_t *config;
	interface_descriptor_t *iface;
	endpoint_descriptor_t *ep;
	char newpre[64];
	int i;

	memset(newpre,0,sizeof(newpre));
	newpre[0] = '\t';
	strcpy(newpre+1, prefix);

	config = (config_descriptor_t *) des;
	iface = (interface_descriptor_t *) (des + config->bLength);
	ep = (endpoint_descriptor_t *) (des + config->bLength + iface->bLength);
	
	// now, the config itself
	DPRINTF("%sbLength: %02x\n", prefix, config->bLength);
	DPRINTF("%stype: %02x\n", prefix, config->type);
	DPRINTF("%swTotalLength: %04x\n", prefix, config->wTotalLength);
	DPRINTF("%sbNumInterfaces: %02x\n", prefix, config->bNumInterfaces);
	DPRINTF("%sbConfigurationValue: %02x\n", prefix, config->bConfigurationValue);
	DPRINTF("%siConfiguration: %02x\n", prefix, config->iConfiguration);
	DPRINTF("%sbmAttributes: %02x\n", prefix, config->bmAttributes);

	DPRINTF("%sbMaxPower: %02x\n", prefix, config->bMaxPower);

	DPRINTF("\n%sInterface(%x):\n", prefix, iface);
	dump_interface_descriptor(iface, newpre);

	newpre[1] = '\t';
	strcpy(newpre+2, prefix);

	for(i=0; i<iface->bNumEndpoints; i++) {
		DPRINTF("\n%sEndpoint (%x):\n", newpre+1, ep+i);
		dump_endpoint_descriptor( ep+i, newpre);
	}
}

// Some control message bmRequestType defines
#define CTRL_DEVICE 0
#define CONTROL_INTERFACE 1
#define CONTROL_ENDPOINT 2
#define CONTROL_OTHER 3
#define CONTROL_RECIPIENT_MASK 0x1f

#define CONTROL_TYPE_STD 0
#define CONTROL_TYPE_CLASS 0x20
#define CONTROL_CLASS_VENDOR 0x40
#define CONTROL_CLASS_MASK 0x60

#define CONTROL_OUT 0
#define CONTROL_IN 0x80
#define CONTROL_DIR_MASK 0x80

// bRequest values
#define GET_STATUS 0
#define CLEAR_FEATURE 1
#define SET_FEATURE 3
#define SET_ADDRESS 5

#define GET_DESCRIPTOR 6
#define SET_DESCRIPTOR 7

#define GET_CONFIGURATION 8
#define SET_CONFIGURATION 9

#define GET_INTERFACE 10
#define SET_INTERFACE 11

#define SYNC_FRAME 12

// descriptor types
#define DEVICE_DESC 1
#define CONFIGURATION_DESC 2
#define STRING_DESC 3
#define INTERFACE_DESC 4
#define ENDPOINT_DESC 5
#define OTHERSPEED_DESC 7
#define POWER_DESC 8

// features
#define FEATURE_HALT 0
void dump_ctrlmsg( ctrl_msg_t *msg, char *prefix)
{
	DPRINTF("%sbmRequestType: %02x\n", prefix, msg->bmRequestType);
	DPRINTF("%sbRequest: %02x\n", prefix, msg->bRequest);
	DPRINTF("%swValue: %04x\n", prefix, msg->wValue);
	DPRINTF("%swIndex: %04x\n", prefix, msg->wIndex);
	DPRINTF("%swLength: %04x\n", prefix, msg->wLength);
}

#endif
