/*-------------------------------------------------------------------------*/
/* list of all controllers using this driver 
 * */

static LIST_HEAD (hci_hcd_list);

/* URB states (urb_state) */
/* isoc, interrupt single state */

/* bulk transfer main state and 0-length packet */
#define US_BULK		0
#define US_BULK0	1
/* three setup states */
#define US_CTRL_SETUP	2
#define US_CTRL_DATA	1
#define US_CTRL_ACK	0

/*-------------------------------------------------------------------------*/
/* HC private part of a device descriptor
 * */

#define NUM_EDS 32

typedef struct epd {
	struct urb *pipe_head;
	struct list_head urb_queue;
//	int urb_state;
	struct timer_list timeout;
	int last_iso;		/* timestamp of last queued ISOC transfer */

} epd_t;

struct hci_device {
	epd_t ed[NUM_EDS];
};

/*-------------------------------------------------------------------------*/
/* Virtual Root HUB 
 */

#define usb_to_hci(usb)	((struct hci_device *)(usb)->hcpriv)

struct virt_root_hub {
	int devnum;		/* Address of Root Hub endpoint */
	void *urb;		/* interrupt URB of root hub */
	int send;		/* active flag */
	int interval;		/* interval of roothub interrupt transfers */
	struct timer_list rh_int_timer;	/* interval timer for rh interrupt EP */
};

#if 1
/* USB HUB CONSTANTS (not OHCI-specific; see hub.h and USB spec) */

/* destination of request */
#define RH_INTERFACE		0x01
#define RH_ENDPOINT		0x02
#define RH_OTHER		0x03

#define RH_CLASS		0x20
#define RH_VENDOR		0x40

/* Requests: bRequest << 8 | bmRequestType */
#define RH_GET_STATUS		0x0080
#define RH_CLEAR_FEATURE	0x0100
#define RH_SET_FEATURE		0x0300
#define RH_SET_ADDRESS		0x0500
#define RH_GET_DESCRIPTOR	0x0680
#define RH_SET_DESCRIPTOR	0x0700
#define RH_GET_CONFIGURATION	0x0880
#define RH_SET_CONFIGURATION	0x0900
#define RH_GET_STATE		0x0280
#define RH_GET_INTERFACE	0x0A80
#define RH_SET_INTERFACE	0x0B00
#define RH_SYNC_FRAME		0x0C80
/* Our Vendor Specific Request */
#define RH_SET_EP		0x2000

/* Hub port features */
#define RH_PORT_CONNECTION	0x00
#define RH_PORT_ENABLE		0x01
#define RH_PORT_SUSPEND		0x02
#define RH_PORT_OVER_CURRENT	0x03
#define RH_PORT_RESET		0x04
#define RH_PORT_POWER		0x08
#define RH_PORT_LOW_SPEED	0x09

#define RH_C_PORT_CONNECTION	0x10
#define RH_C_PORT_ENABLE	0x11
#define RH_C_PORT_SUSPEND	0x12
#define RH_C_PORT_OVER_CURRENT	0x13
#define RH_C_PORT_RESET		0x14

/* Hub features */
#define RH_C_HUB_LOCAL_POWER	0x00
#define RH_C_HUB_OVER_CURRENT	0x01

#define RH_DEVICE_REMOTE_WAKEUP	0x00
#define RH_ENDPOINT_STALL	0x01

#endif

/*-------------------------------------------------------------------------*/
/* struct for each HC 
 */

#define MAX_TRANS	32

typedef struct td {
	struct urb *urb;
	__u16 len;
	__u16 iso_index;
} td_t;

typedef struct td_array {
	int len;
	td_t td[MAX_TRANS];
} td_array_t;

typedef struct hci {
	struct virt_root_hub rh;	/* roothub */
	wait_queue_head_t waitq;	/* deletion of URBs and devices needs a waitqueue */
	int active;			/* HC is operating */

	struct list_head ctrl_list;	/* set of ctrl endpoints */
	struct list_head bulk_list;	/* set of bulk endpoints */
	struct list_head iso_list;	/* set of isoc endpoints */
	struct list_head intr_list;	/* ordered (tree) set of int endpoints */
	struct list_head del_list;	/* set of entpoints to be deleted */

	td_array_t *td_array;
	td_array_t a_td_array;
	td_array_t i_td_array[2];

	struct list_head hci_hcd_list;	/* list of all hci_hcd */
	struct usb_bus *bus;		/* our bus */

//	int trans;			/* number of transactions pending */
	int active_urbs;
	int active_trans;
	int frame_number;		/* frame number */
	hcipriv_t hp;			/* individual part of hc type */
	int nakCnt;
	int last_packet_nak;

} hci_t;

/*-------------------------------------------------------------------------*/
/* condition (error) CC codes and mapping OHCI like
 */

#define TD_CC_NOERROR		0x00
#define TD_CC_CRC		0x01
#define TD_CC_BITSTUFFING	0x02
#define TD_CC_DATATOGGLEM	0x03
#define TD_CC_STALL		0x04
#define TD_DEVNOTRESP		0x05
#define TD_PIDCHECKFAIL		0x06
#define TD_UNEXPECTEDPID	0x07
#define TD_DATAOVERRUN		0x08
#define TD_DATAUNDERRUN		0x09
#define TD_BUFFEROVERRUN	0x0C
#define TD_BUFFERUNDERRUN	0x0D
#define TD_NOTACCESSED		0x0F


/* urb interface functions */
static int hci_get_current_frame_number (struct usb_device *usb_dev);
static int hci_unlink_urb (struct urb * urb);

static int qu_queue_urb (hci_t * hci, struct urb * urb);

/* root hub */
static int rh_init_int_timer (struct urb * urb);
static int rh_submit_urb (struct urb * urb);
static int rh_unlink_urb (struct urb * urb);

/* schedule functions */
static int sh_add_packet (hci_t * hci, struct urb * urb);

/* hc specific functions */
static inline void hc_flush_data_cache (hci_t * hci, void *data, int len);
static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data,
				  int *cc, int *toggle, int length, int pid,
				  int urb_state);
static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle,
				int maxps, int slow, int endpoint, int address,
				int pid, int format, int urb_state);

static void hc_start_int (hci_t * hci);
static void hc_stop_int (hci_t * hci);
static void SL811Write (hci_t * hci, char offset, char data);

/* debug| print the main components of an URB     
 * small: 0) header + data packets 1) just header */

static void urb_print (struct urb * urb, char *str, int small)
{
	unsigned int pipe = urb->pipe;
	int i, len;

	if (!urb->dev || !urb->dev->bus) {
		dbg ("%s URB: no dev", str);
		return;
	}

	printk ("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)\n",
		str, hci_get_current_frame_number (urb->dev),
		usb_pipedevice (pipe), usb_pipeendpoint (pipe),
		usb_pipeout (pipe) ? 'O' : 'I',
		usb_pipetype (pipe) < 2 ? (usb_pipeint (pipe) ? "INTR" : "ISOC")
		: (usb_pipecontrol (pipe) ? "CTRL" : "BULK"), urb->transfer_flags,
		urb->actual_length, urb->transfer_buffer_length, urb->status,
		urb->status);
	if (!small) {
		if (usb_pipecontrol (pipe)) {
			printk (__FILE__ ": cmd(8):");
			for (i = 0; i < 8; i++)
				printk (" %02x", ((__u8 *) urb->setup_packet)[i]);
			printk ("\n");
		}
		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
			printk (__FILE__ ": data(%d/%d):", urb->actual_length,
				urb->transfer_buffer_length);
			len = usb_pipeout (pipe) ? urb-> transfer_buffer_length : urb->actual_length;
			for (i = 0; i < 2096 && i < len; i++)
				printk (" %02x", ((__u8 *) urb->transfer_buffer)[i]);
			printk ("%s stat:%d\n", i < len ? "..." : "",
				urb->status);
		}
	}
}
