/*--------------------------------------------------------------------------*
 * drivers/usb/mcd/usb_mcd_debug.c
 * 
 * USB controller driver
 * 
 * Copyright 2005,2006 Sony Corporation
 * 
 * This code is based on debug.c,
 * Copyright 2005 Mentor Graphics Corporation
 *
 * This file is part of the Inventra Controller Driver for Linux.
 *
 * The Inventra Controller Driver for Linux is free software; you
 * can redistribute it and/or modify it under the terms of the GNU
 * General Public License version 2 as published by the Free Software
 * Foundation.
 *
 * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
 * write to the Free Software Foundation, Inc., 59 Temple Place,
 * Suite 330, Boston, MA  02111-1307  USA
 *
 * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
 * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
 * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
 * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
 * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
 * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
 * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
 * GRAPHICS SUPPORT CUSTOMER.
 *---------------------------------------------------------------------------*/

#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/completion.h>
#include <linux/interrupt.h>

#include <linux/usb.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/mcd/usb_otg_control.h>
#include <linux/usb/mcd/usb_mcd_ioctl.h>
#include "../core/hub.h"
#include "../core/hcd.h"

#include "usb_mcd_cnf.h"
#include "usb_mcd_debug.h"
#include "usb_mcd_dma.h"
#include "usb_mcd_otg.h"
#include "usb_mcd_gadget.h"
#include "usb_mcd_host.h"
#include "usb_mcd_device.h"
#include "usb_mcd_access.h"
#include "usb_mcd_musbhdrc.h"

#define IPRINTF(_f, _m)	printk(KERN_INFO "%s"_f, indent, _m)
#define isspace(c) 	(c==' ' || c=='\t')
#define LABEL KERN_INFO "dump: "

int mcd_debug_level = MCD_DEBUG;
EXPORT_SYMBOL(mcd_debug_level);

unsigned int mcd_debug_lock_irq_count = 0;
unsigned int mcd_debug_lock_count = 0;
EXPORT_SYMBOL(mcd_debug_lock_irq_count);
EXPORT_SYMBOL(mcd_debug_lock_count);

/*
 */
char *decode_csr0(uint16_t csr0)
{
	static char buf[64];
	snprintf(buf, sizeof(buf), "(%s%s%s%s)",
		 csr0 & MCD_M_CSR0_TXPKTRDY ? "[TXPKTRDY]" : "",
		 csr0 & MCD_M_CSR0_P_SVDRXPKTRDY ? "[SVDRXPKTRDY]" : "",
		 csr0 & MCD_M_CSR0_P_SENDSTALL ? "[stalled]" : "",
		 csr0 & MCD_M_CSR0_P_DATAEND ? "[dataend]" : "");
	return buf;
}

char *decode_bits(uint16_t value)
{
	int i = 0;
	static char buf[64];

	for (; i < 16; i++) {
		buf[15 - i] = (value & (1 << i)) ? '1' : '0';
	}

	return buf;
}

/*
 */
char *decode_txcsr(uint16_t txcsr)
{
	static char buf[256];
	snprintf(buf, sizeof(buf), "%s (%s%s%s%s)",
		 decode_bits(txcsr),
		 txcsr & MCD_M_TXCSR_TXPKTRDY ? "[TXPKTRDY]" : "",
		 txcsr & MCD_M_TXCSR_AUTOSET ? "[MCD_M_TXCSR_AUTOSET]" : "",
		 txcsr & MCD_M_TXCSR_DMAENAB ? "[MCD_M_TXCSR_DMAENAB]" : "",
		 txcsr & MCD_M_TXCSR_DMAMODE ? "[MCD_M_TXCSR_DMAMODE]" : "");
	return buf;
}

extern char *dump_node(struct list_head *node)
{
	static char buf[64];
	snprintf(buf, sizeof(buf), "[n=%p,p=%p]", node->next, node->prev);
	return buf;
}

/*
 */
char *decode_devctl(uint16_t devctl)
{
	return (devctl & MCD_M_DEVCTL_HM) ? "host" : "function";
}

/*
 */
char *decode_ep0stage(uint8_t stage)
{
	static char buff[64];
	uint8_t stallbit = stage & MCD_END0_STAGE_STALL_BIT;

	stage = stage & ~stage & MCD_END0_STAGE_STALL_BIT;
	snprintf(buff, sizeof(buff), "%s%s", (stallbit) ? "stall-" : "",
		 (stage == MCD_END0_STAGE_SETUP)
		 ? "setup" : (stage == MCD_END0_STAGE_TX)
		 ? "tx" : (stage == MCD_END0_STAGE_RX)
		 ? "rx" : (stage == MCD_END0_STAGE_STATUSIN)
		 ? "statusin" : (stage == MCD_END0_STAGE_STATUSOUT)
		 ? "statusout" : "error");
	return buff;
}

/*
 */
void dump_urb(void *pUrb)
{
	struct urb *purb = (struct urb *)pUrb;

	printk(LABEL "urb                   :%p\n", purb);
#ifdef V24
	printk(LABEL "next                  :%p\n", purb->next);
#endif
	printk(LABEL "dev                   :%p\n", purb->dev);
	printk(LABEL "pipe                  :%08X\n", purb->pipe);
	printk(LABEL "status                :%d\n", purb->status);
	printk(LABEL "transfer_flags        :%08X\n", purb->transfer_flags);
	printk(LABEL "transfer_buffer       :%p\n", purb->transfer_buffer);
	printk(LABEL "transfer_buffer_length:%d\n",
	       purb->transfer_buffer_length);
	printk(LABEL "actual_length         :%d\n", purb->actual_length);
	printk(LABEL "setup_packet          :%p\n", purb->setup_packet);
	printk(LABEL "start_frame           :%d\n", purb->start_frame);
	printk(LABEL "number_of_packets     :%d\n", purb->number_of_packets);
	printk(LABEL "interval              :%d\n", purb->interval);
	printk(LABEL "error_count           :%d\n", purb->error_count);
	printk(LABEL "context               :%p\n", purb->context);
	printk(LABEL "complete              :%p\n", purb->complete);
}
