[BACK]Return to sl811.c CVS log [TXT][DIR] Up to [Development] / linux-2.4-xfs / drivers / usb / host

File: [Development] / linux-2.4-xfs / drivers / usb / host / sl811.c (download)

Revision 1.2, Fri Jan 30 00:27:42 2004 UTC (13 years, 8 months ago) by nathans
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +2 -2 lines

Merge up to 2.4.25-pre8

/*
 * SL811 Host Controller Interface driver for USB.
 *
 * Copyright (c) 2003/06, Courage Co., Ltd.
 *
 * Based on:
 *	1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
 * 	  Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
 * 	  Adam Richter, Gregory P. Smith;
 * 	2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
 *	3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
 *
 * It's now support isochornous mode and more effective than hc_sl811.o
 * Support x86 architecture now.
 *
 * 19.09.2003 (05.06.2003) HNE
 * sl811_alloc_hc: Set "bus->bus_name" at init.
 * sl811_reg_test (hc_reset,regTest):
 *   Stop output at first failed pattern.
 * Down-Grade for Kernel 2.4.20 and from 2.4.22
 * Splitt hardware depens into file sl811-x86.h and sl811-arm.h.
 *
 * 22.09.2003 HNE
 * sl811_found_hc: First patterntest, than interrupt enable.
 * Do nothing, if patterntest failed. Release io, if failed.
 * Stop Interrupts first, than remove handle. (Old blocked Shred IRQ)
 * Alternate IO-Base for second Controller (CF/USB1).
 *
 * 24.09.2003 HNE
 * Remove all arm specific source (moved into include/asm/sl811-hw.h).
 *
 * 03.10.2003 HNE
 * Low level only for port io into hardware-include.

 *
 * To do:
 *	1.Modify the timeout part, it's some messy
 *	2.Use usb-a and usb-b set in Ping-Pong mode
 *	o Floppy do not work.
 *	o driver crash, if io region can't register
 * 	o Only as module tested! Compiled in Version not tested!

 * 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.
 *
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/list.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/irq.h>
#include <linux/usb.h>

#include "../hcd.h"
#include "../hub.h"
#include "sl811.h"

#define DRIVER_VERSION "v0.30"
#define MODNAME "SL811"
#define DRIVER_AUTHOR "Yin Aihua <yinah@couragetech.com.cn>, Henry Nestler <hne@ist1.de>"
#define DRIVER_DESC "Sl811 USB Host Controller Alternate Driver"

static LIST_HEAD(sl811_hcd_list);

/*
 * 0, normal prompt and information
 * 1, error should not occur in normal
 * 2, error maybe occur in normal
 * 3, useful and detail debug information
 * 4, function level enter and level inforamtion
 * 5, endless information will output because of timer function or interrupt
 */
static int debug = 0;
MODULE_PARM(debug,"i");
MODULE_PARM_DESC(debug,"debug level");

#include <asm/sl811-hw.h>	/* Include hardware and board depens */

static void sl811_rh_int_timer_do(unsigned long ptr);
static void sl811_transfer_done(struct sl811_hc *hc, int sof);

/*
 * Read	a byte of data from the	SL811H/SL11H
 */
static __u8 inline sl811_read(struct sl811_hc *hc, __u8 offset)
{
	sl811_write_index (hc, offset);
	return (sl811_read_data (hc));
}

/*
 * Write a byte	of data	to the SL811H/SL11H
 */
static void inline sl811_write(struct sl811_hc *hc, __u8 offset, __u8 data)
{
	sl811_write_index_data (hc, offset, data);
}

/*
 * Read	consecutive bytes of data from the SL811H/SL11H	buffer
 */
static void inline sl811_read_buf(struct sl811_hc *hc, __u8 offset, __u8 *buf, __u8 size)
{
	sl811_write_index (hc, offset);
	while (size--) {
		*buf++ = sl811_read_data(hc);
	}
}

/*
 * Write consecutive bytes of data to the SL811H/SL11H buffer
 */
static void inline sl811_write_buf(struct sl811_hc *hc, __u8 offset, __u8 *buf, __u8 size)
{
	sl811_write_index (hc, offset);
	while (size--) {
		sl811_write_data (hc, *buf);
		buf++;
	}
}

/*
 * This	routine	test the Read/Write functionality of SL811HS registers
 */
static int sl811_reg_test(struct sl811_hc *hc)
{
	int i, data, result = 0;
	__u8 buf[256];

	for (i = 0x10; i < 256;	i++) {
		/* save	the original buffer */
		buf[i] = sl811_read(hc,	i);

		/* Write the new data to the buffer */
		sl811_write(hc,	i, i);
	}

	/* compare the written data */
	for (i = 0x10; i < 256;	i++) {
		data = sl811_read(hc, i);
		if (data != i) {
			PDEBUG(1, "Pattern test failed!! value = 0x%x, s/b 0x%x", data, i);
			result = -1;

			/* If no Debug, show only first failed Address */
			if (!debug)
			    break;
		}
	}

	/* restore the data */
	for (i = 0x10; i < 256;	i++)
		sl811_write(hc,	i, buf[i]);

	return result;
}

/*
 * Display all SL811HS register	values
 */
#if 0 /* unused (hne) */
static void sl811_reg_show(struct sl811_hc *hc)
{
	int i;

	for (i = 0; i <	256; i++)
		PDEBUG(4, "offset %d: 0x%x", i, sl811_read(hc, i));
}
#endif

/*
 * This	function enables SL811HS interrupts
 */
static void sl811_enable_interrupt(struct sl811_hc *hc)
{
	PDEBUG(4, "enter");
	sl811_write(hc, SL811_INTR, SL811_INTR_DONE_A | SL811_INTR_SOF | SL811_INTR_INSRMV);
}

/*
 * This	function disables SL811HS interrupts
 */
static void sl811_disable_interrupt(struct sl811_hc *hc)
{
	PDEBUG(4, "enter");
	// Disable all other interrupt except for insert/remove.
	sl811_write(hc,	SL811_INTR, SL811_INTR_INSRMV);
}

/*
 * SL811 Virtual Root Hub
 */

/* Device descriptor */
static __u8 sl811_rh_dev_des[] =
{
	0x12,       /*  __u8  bLength; */
	0x01,       /*  __u8  bDescriptorType; Device */
	0x10,	    /*  __u16 bcdUSB; v1.1 */
	0x01,
	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
	0x00,	    /*  __u8  bDeviceSubClass; */
	0x00,       /*  __u8  bDeviceProtocol; */
	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
	0x00,       /*  __u16 idVendor; */
	0x00,
	0x00,       /*  __u16 idProduct; */
 	0x00,
	0x00,       /*  __u16 bcdDevice; */
 	0x00,
	0x00,       /*  __u8  iManufacturer; */
	0x02,       /*  __u8  iProduct; */
	0x01,       /*  __u8  iSerialNumber; */
	0x01        /*  __u8  bNumConfigurations; */
};

/* Configuration descriptor */
static __u8 sl811_rh_config_des[] =
{
	0x09,       /*  __u8  bLength; */
	0x02,       /*  __u8  bDescriptorType; Configuration */
	0x19,       /*  __u16 wTotalLength; */
	0x00,
	0x01,       /*  __u8  bNumInterfaces; */
	0x01,       /*  __u8  bConfigurationValue; */
	0x00,       /*  __u8  iConfiguration; */
	0x40,       /*  __u8  bmAttributes;
                    Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup,
                    4..0: resvd */
	0x00,       /*  __u8  MaxPower; */

	/* interface */
	0x09,       /*  __u8  if_bLength; */
	0x04,       /*  __u8  if_bDescriptorType; Interface */
	0x00,       /*  __u8  if_bInterfaceNumber; */
	0x00,       /*  __u8  if_bAlternateSetting; */
	0x01,       /*  __u8  if_bNumEndpoints; */
	0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
	0x00,       /*  __u8  if_bInterfaceSubClass; */
	0x00,       /*  __u8  if_bInterfaceProtocol; */
	0x00,       /*  __u8  if_iInterface; */

	/* endpoint */
	0x07,       /*  __u8  ep_bLength; */
	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
 	0x03,       /*  __u8  ep_bmAttributes; Interrupt */
 	0x08,       /*  __u16 ep_wMaxPacketSize; */
 	0x00,
	0xff        /*  __u8  ep_bInterval; 255 ms */
};

/* root hub class descriptor*/
static __u8 sl811_rh_hub_des[] =
{
	0x09,			/*  __u8  bLength; */
	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */
	0x01,			/*  __u8  bNbrPorts; */
	0x00,			/* __u16  wHubCharacteristics; */
	0x00,
	0x50,			/*  __u8  bPwrOn2pwrGood; 2ms */
	0x00,			/*  __u8  bHubContrCurrent; 0 mA */
	0xfc,			/*  __u8  DeviceRemovable; *** 7 Ports max *** */
	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
};

/*
 * This function examine the port change in the virtual root hub. HUB INTERRUPT ENDPOINT.
 */
static int sl811_rh_send_irq(struct sl811_hc *hc, __u8 *rh_change, int rh_len)
{
	__u8 data = 0;
		
	PDEBUG(5, "enter");

	/*
	 * Right now, It is assume the power is good and no changes and only one port.
	 */
	if (hc->rh_status.wPortChange & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) {  
		data = 1<<1;
		*(__u8 *)rh_change = data;
		return 1;
	} else
		return 0;
}

/*
 * This function creates a timer that act as interrupt pipe in the virtual hub.
 *
 * Note:  The virtual root hub's interrupt pipe are polled by the timer
 *        every "interval" ms
 */
static void sl811_rh_init_int_timer(struct urb * urb)
{
	 struct sl811_hc *hc = urb->dev->bus->hcpriv;
	 hc->rh.interval = urb->interval;

	 init_timer(&hc->rh.rh_int_timer);
	 hc->rh.rh_int_timer.function = sl811_rh_int_timer_do;
	 hc->rh.rh_int_timer.data = (unsigned long)urb;
	 hc->rh.rh_int_timer.expires = jiffies +
		(HZ * (urb->interval < 30? 30: urb->interval)) / 1000;
	 add_timer (&hc->rh.rh_int_timer);
}

/*
 * This function is called when the timer expires.  It gets the the port
 * change data and pass along to the upper protocol.
 */
static void sl811_rh_int_timer_do(unsigned long ptr)
{
	int len;
	struct urb *urb = (struct urb *)ptr;
	struct sl811_hc *hc = urb->dev->bus->hcpriv;
	PDEBUG (5, "enter");

	if(hc->rh.send) {
		len = sl811_rh_send_irq(hc, urb->transfer_buffer,
			urb->transfer_buffer_length);
		if (len > 0) {
			urb->actual_length = len;
			if (urb->complete)
				urb->complete(urb);
		}
	}

#ifdef SL811_TIMEOUT
	
{
	struct list_head *head, *tmp;
	struct sl811_urb_priv *urbp;
	struct urb *u;
	int i;
	static int timeout_count = 0;

// check time out every second
	if (++timeout_count > 4) {
		int max_scan = hc->active_urbs;
		timeout_count = 0;
		for (i = 0; i < 6; ++i) {
			head = &hc->urb_list[i];
			tmp = head->next;
			while (tmp != head && max_scan--) {
				u = list_entry(tmp, struct urb, urb_list);
				urbp = (struct sl811_urb_priv *)u->hcpriv;
				tmp = tmp->next;
				// Check if the URB timed out
				if (u->timeout && time_after_eq(jiffies, urbp->inserttime + u->timeout)) {
					PDEBUG(3, "urb = %p time out, we kill it", urb);
					u->transfer_flags |= USB_TIMEOUT_KILLED;
				}
			}
		}
	}
}

#endif
	// re-activate the timer
	sl811_rh_init_int_timer(urb);
}

/* helper macro */
#define OK(x)	len = (x); break

/*
 * This function handles all USB request to the the virtual root hub
 */
static int sl811_rh_submit_urb(struct urb *urb)
{
	struct usb_device *usb_dev = urb->dev;
	struct sl811_hc *hc = usb_dev->bus->hcpriv;
	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet;
	void *data = urb->transfer_buffer;
	int buf_len = urb->transfer_buffer_length;
	unsigned int pipe = urb->pipe;
	__u8 data_buf[16];
	__u8 *bufp = data_buf;
	int len = 0;
	int status = 0;
	
	__u16 bmRType_bReq;
	__u16 wValue;
	__u16 wIndex;
	__u16 wLength;

	if (usb_pipeint(pipe)) {
		hc->rh.urb =  urb;
		hc->rh.send = 1;
		hc->rh.interval = urb->interval;
		sl811_rh_init_int_timer(urb);
		urb->status = 0;

		return 0;
	}

	bmRType_bReq  = cmd->bRequestType | (cmd->bRequest << 8);
	wValue        = le16_to_cpu (cmd->wValue);
	wIndex        = le16_to_cpu (cmd->wIndex);
	wLength       = le16_to_cpu (cmd->wLength);

	PDEBUG(5, "submit rh urb, req = %d(%x) len=%d", bmRType_bReq, bmRType_bReq, wLength);

	/* Request Destination:
		   without flags: Device,
		   USB_RECIP_INTERFACE: interface,
		   USB_RECIP_ENDPOINT: endpoint,
		   USB_TYPE_CLASS means HUB here,
		   USB_RECIP_OTHER | USB_TYPE_CLASS  almost ever means HUB_PORT here
	*/
	switch (bmRType_bReq) {
	case RH_GET_STATUS:
		*(__u16 *)bufp = cpu_to_le16(1);
		OK(2);

	case RH_GET_STATUS | USB_RECIP_INTERFACE:
		*(__u16 *)bufp = cpu_to_le16(0);
		OK(2);

	case RH_GET_STATUS | USB_RECIP_ENDPOINT:
		*(__u16 *)bufp = cpu_to_le16(0);
		OK(2);

	case RH_GET_STATUS | USB_TYPE_CLASS:
		*(__u32 *)bufp = cpu_to_le32(0);
		OK(4);

	case RH_GET_STATUS | USB_RECIP_OTHER | USB_TYPE_CLASS:
		*(__u32 *)bufp = cpu_to_le32(hc->rh_status.wPortChange<<16 | hc->rh_status.wPortStatus);
		OK(4);

	case RH_CLEAR_FEATURE | USB_RECIP_ENDPOINT:
		switch (wValue)	{
		case 1: 
			OK(0);
		}
		break;

	case RH_CLEAR_FEATURE | USB_TYPE_CLASS:
		switch (wValue) {
		case C_HUB_LOCAL_POWER:
			OK(0);

		case C_HUB_OVER_CURRENT:
			OK(0);
		}
		break;

	case RH_CLEAR_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
		switch (wValue) {
		case USB_PORT_FEAT_ENABLE:
			hc->rh_status.wPortStatus &= ~USB_PORT_STAT_ENABLE;
			OK(0);

		case USB_PORT_FEAT_SUSPEND:
			hc->rh_status.wPortStatus &= ~USB_PORT_STAT_SUSPEND;
			OK(0);

		case USB_PORT_FEAT_POWER:
			hc->rh_status.wPortStatus &= ~USB_PORT_STAT_POWER;
			OK(0);

		case USB_PORT_FEAT_C_CONNECTION:
			hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
			OK(0);

		case USB_PORT_FEAT_C_ENABLE:
			hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_ENABLE;
			OK(0);

		case USB_PORT_FEAT_C_SUSPEND:
			hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_SUSPEND;
			OK(0);

		case USB_PORT_FEAT_C_OVER_CURRENT:
			hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_OVERCURRENT;
			OK(0);

		case USB_PORT_FEAT_C_RESET:
			hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_RESET;
			OK(0);
		}
		break;

	case RH_SET_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
		switch (wValue) {
		case USB_PORT_FEAT_SUSPEND:
			hc->rh_status.wPortStatus |= USB_PORT_STAT_SUSPEND;
			OK(0);

		case USB_PORT_FEAT_RESET:
			hc->rh_status.wPortStatus |= USB_PORT_STAT_RESET;
			hc->rh_status.wPortChange = 0;
			hc->rh_status.wPortChange |= USB_PORT_STAT_C_RESET;
			hc->rh_status.wPortStatus &= ~USB_PORT_STAT_RESET;
			hc->rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
			OK(0);

		case USB_PORT_FEAT_POWER:
			hc->rh_status.wPortStatus |= USB_PORT_STAT_POWER;
			OK(0);

		case USB_PORT_FEAT_ENABLE:
			hc->rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
			OK(0);
		}
		break;

	case RH_SET_ADDRESS:
		hc->rh.devnum = wValue;
		OK(0);

	case RH_GET_DESCRIPTOR:
		switch ((wValue & 0xff00) >> 8) {
		case USB_DT_DEVICE:
			len = sizeof(sl811_rh_dev_des);
			bufp = sl811_rh_dev_des;
			OK(len);

		case USB_DT_CONFIG: 
			len = sizeof(sl811_rh_config_des);
			bufp = sl811_rh_config_des;
			OK(len);

		case USB_DT_STRING:
			len = usb_root_hub_string(wValue & 0xff, (int)(long)0,	"SL811HS", data, wLength);
			if (len > 0) {
				bufp = data;
				OK(len);
			}
		
		default:
			status = -EPIPE;
		}
		break;

	case RH_GET_DESCRIPTOR | USB_TYPE_CLASS:
		len = sizeof(sl811_rh_hub_des);
		bufp = sl811_rh_hub_des;
		OK(len);

	case RH_GET_CONFIGURATION:
		bufp[0] = 0x01;
		OK(1);

	case RH_SET_CONFIGURATION:
		OK(0);

	default:
		PDEBUG(1, "unsupported root hub command");
		status = -EPIPE;
	}

	len = min(len, buf_len);
	if (data != bufp)
		memcpy(data, bufp, len);
	urb->actual_length = len;
	urb->status = status;

	PDEBUG(5, "len = %d, status = %d", len, status);
	
	urb->hcpriv = NULL;
	urb->dev = NULL;
	if (urb->complete)
		urb->complete(urb);

	return 0;
}

/*
 * This function unlinks the URB
 */
static int sl811_rh_unlink_urb(struct urb *urb)
{
	struct sl811_hc *hc = urb->dev->bus->hcpriv;

	PDEBUG(5, "enter");
	
	if (hc->rh.urb == urb) {
		hc->rh.send = 0;
		del_timer(&hc->rh.rh_int_timer);
		hc->rh.urb = NULL;
		urb->hcpriv = NULL;
		usb_dec_dev_use(urb->dev);
		urb->dev = NULL;
		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
			urb->status = -ECONNRESET;
			if (urb->complete)
				urb->complete(urb);
		} else
			urb->status = -ENOENT;
	}

	return 0;
}

/*
 * This function connect the virtual root hub to the USB stack
 */
static int sl811_connect_rh(struct sl811_hc * hc)
{
	struct usb_device *usb_dev;

	hc->rh.devnum = 0;
	usb_dev = usb_alloc_dev(NULL, hc->bus);
	if (!usb_dev)
		return -ENOMEM;

	hc->bus->root_hub = usb_dev;
	usb_connect(usb_dev);

	if (usb_new_device(usb_dev)) {
		usb_free_dev(usb_dev);
		return -ENODEV;
	}
	
	PDEBUG(5, "leave success");
	
	return 0;
}

/*
 * This function allocates private data space for the usb device
 */
static int sl811_alloc_dev_priv(struct usb_device *usb_dev)
{
	return 0;
}

/*
 * This function de-allocates private data space for the usb devic
 */
static int sl811_free_dev_priv (struct usb_device *usb_dev)
{
	return 0;
}

/*
 * This function allocates private data space for the urb
 */
static struct sl811_urb_priv* sl811_alloc_urb_priv(struct urb *urb)
{
	struct sl811_urb_priv *urbp;
	
	urbp = kmalloc(sizeof(*urbp), GFP_ATOMIC);
	if (!urbp)
		return NULL;
	
	memset(urbp, 0, sizeof(*urbp));
	
	INIT_LIST_HEAD(&urbp->td_list);
	
	urbp->urb = urb;
	urb->hcpriv = urbp;
	
	return urbp;
}

/*
 * This function free private data space for the urb
 */
static void sl811_free_urb_priv(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td;
	struct list_head *head, *tmp;
	
	if (!urbp)
		return ;
	
	head = &urbp->td_list;
	tmp = head->next;
	
	while (tmp != head) {
		td = list_entry(tmp, struct sl811_td, td_list);
		tmp = tmp->next;
		kfree(td);
	}
	
	kfree(urbp);
	urb->hcpriv = NULL;
	
	return ;
}

/*
 * This	function calculate the bus time need by this td.
 * Fix me! Can this use usb_calc_bus_time()?
 */
static void sl811_calc_td_time(struct sl811_td *td)
{
#if 1
	int time;
	int len = td->len;
	struct sl811_hc *hc = td->urb->dev->bus->hcpriv; 

	if (hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED)
		time = 8*8*len + 1024;
	else {
		if (td->ctrl & SL811_USB_CTRL_PREAMBLE)
			time = 8*8*len + 2048;
		else
			time = 8*len + 256;
	}

	time += 2*10 * len;

	td->bustime = time;
	
#else

	unsigned long tmp;
	int time;
	int low_speed = usb_pipeslow(td->urb->pipe);
	int input_dir = usb_pipein(td->urb->pipe);
	int bytecount = td->len;
	int isoc = usb_pipeisoc(td->urb->pipe); 

	if (low_speed) {	/* no isoc. here */
		if (input_dir) {
			tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;
			time =  (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
		} else {
			tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;
			time =  (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
		}
	} else if (!isoc){	/* for full-speed: */
		tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
		time = (9107L + BW_HOST_DELAY + tmp);
	} else {		/* for isoc: */
		tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
		time =  (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
	}
	
	td->bustime = time / 84;

#endif		 
}

/*
 * This	function calculate the remainder bus time in current frame.
 */
static inline int sl811_calc_bus_remainder(struct sl811_hc *hc)
{
	return (sl811_read(hc, SL811_SOFCNTDIV) * 64);
}

/*
 * This function allocates td for the urb
 */
static struct sl811_td* sl811_alloc_td(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td;
	
	td = kmalloc(sizeof (*td), GFP_ATOMIC);
	if (!td)
		return NULL;
	
	memset(td, 0, sizeof(*td));
	
	INIT_LIST_HEAD(&td->td_list);
	
	td->urb = urb;
	list_add_tail(&td->td_list, &urbp->td_list);
	
	return td;
}

/*
 * Fill the td.
 */
static inline void sl811_fill_td(struct sl811_td *td, __u8 ctrl, __u8 addr, __u8 len, __u8 pidep, __u8 dev, __u8 *buf)
{
	td->ctrl = ctrl;
	td->addr = addr;
	td->len = len;
	td->pidep = pidep;
	td->dev = dev;
	td->buf = buf;
	td->left = len;
	td->errcnt = 3;
}

/*
 * Fill the td.
 */
static inline void sl811_reset_td(struct sl811_td *td)
{
	td->status = 0;
	td->left = td->len;
	td->done = 0;
	td->errcnt = 3;
	td->nakcnt = 0;
	td->td_status = 0;
}

static void sl811_print_td(int level, struct sl811_td *td)
{
	 PDEBUG(level, "td = %p, ctrl = %x, addr = %x, len = %x, pidep = %x\n "
		"dev = %x, status = %x, left = %x, errcnt = %x, done = %x\n "
		"buf = %p, bustime = %d, td_status = %d\n", 
		td, td->ctrl, td->addr, td->len, td->pidep,
		td->dev, td->status, td->left, td->errcnt, td->done,
		td->buf, td->bustime, td->td_status);
}

/*
 * Isochronous transfers
 */
static int sl811_submit_isochronous(struct urb *urb)
{
	__u8 dev = usb_pipedevice(urb->pipe);
	__u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
	__u8 ctrl = 0;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = NULL;
	int i;
	
	PDEBUG(4, "enter, urb = %p, urbp = %p", urb, urbp);
	
	/* Can't have low speed bulk transfers */
	if (usb_pipeslow(urb->pipe)) {
		PDEBUG(1, "error, urb = %p, low speed device", urb);
		return -EINVAL;
	}
	
	if (usb_pipeout(urb->pipe))
		ctrl |= SL811_USB_CTRL_DIR_OUT;
		
	ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE | SL811_USB_CTRL_ISO;
	
	for (i = 0; i < urb->number_of_packets; i++) {
		urb->iso_frame_desc[i].actual_length = 0;
		urb->iso_frame_desc[i].status = -EXDEV;
			
		td = sl811_alloc_td(urb);
		if (!td)
			return -ENOMEM;

		sl811_fill_td(td, ctrl, SL811_DATA_START, 
			urb->iso_frame_desc[i].length,
			pidep, dev,
			urb->transfer_buffer + urb->iso_frame_desc[i].offset);
		sl811_calc_td_time(td);
		if (urbp->cur_td == NULL)
			urbp->cur_td = urbp->first_td = td;	
	}

	urbp->last_td = td;	
	
	PDEBUG(4, "leave success");

/*	
// for debug
	{
		struct list_head *head, *tmp;
		struct sl811_td *td;
		int i = 0;
		head = &urbp->td_list;
		tmp = head->next;
	
		if (list_empty(&urbp->td_list)) {
			PDEBUG(1, "bug!!! td list is empty!");
			return -ENODEV;
		}
		
		while (tmp != head) {
			++i;
			td = list_entry(tmp, struct sl811_td, td_list);
			PDEBUG(2, "td = %p, i = %d", td, i);
			tmp = tmp->next;
		}
	}
*/	
	return 0;
}

/*
 * Reset isochronous transfers
 */
static void sl811_reset_isochronous(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = NULL;
	struct list_head *head, *tmp;
	int i;

	PDEBUG(4, "enter, urb = %p", urb);
	
	for (i = 0; i < urb->number_of_packets; i++) {
		urb->iso_frame_desc[i].actual_length = 0;
		urb->iso_frame_desc[i].status = -EXDEV;
	}

	head = &urbp->td_list;
	tmp = head->next;
	while (tmp != head) {
		td = list_entry(tmp, struct sl811_td, td_list);
		tmp = tmp->next;
		sl811_reset_td(td);
	}
	
	urbp->cur_td = urbp->first_td;
	
	urb->status = -EINPROGRESS;
	urb->actual_length = 0;
	urb->error_count = 0;
}

/*
 * Result the iso urb.
 */
static void sl811_result_isochronous(struct urb *urb)
{
	struct list_head *tmp, *head;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	int status = 0;
	struct sl811_td *td;
	int i;

	PDEBUG(4, "enter, urb = %p", urb);
		
	urb->actual_length = 0;

	i = 0;
	head = &urbp->td_list;
	tmp = head->next;
	while (tmp != head) {
		td = list_entry(tmp, struct sl811_td, td_list);
		tmp = tmp->next;
		
		if (!td->done) {
			if (urbp->unlink)
				urb->status = -ENOENT;
			else {
				PDEBUG(1, "we should not get here!");
				urb->status = -EXDEV;
			}
			return ;	
		}
		if (td->td_status) {
			status = td->td_status;
			urb->error_count++;
			PDEBUG(1, "error: td = %p, td status = %d", td, td->td_status);
		}

		urb->iso_frame_desc[i].actual_length = td->len - td->left;
		urb->actual_length += td->len - td->left;
		urb->iso_frame_desc[i].status = td->td_status;
		++i;
		if (td->left)
			PDEBUG(3, "short packet, td = %p, len = %d, left = %d", td, td->len, td->left);
	}

	urb->status = status;
/*
// for debug
	PDEBUG(2, "iso urb complete, len = %d, status =%d ", urb->actual_length, urb->status);		
*/
	PDEBUG(4, "leave success");
}

/*
 * Interrupt transfers
 */
static int sl811_submit_interrupt(struct urb *urb)
{
	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
	int len = urb->transfer_buffer_length;
	__u8 *data = urb->transfer_buffer;
	__u8 dev = usb_pipedevice(urb->pipe);
	__u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
	__u8 ctrl = 0;
	struct sl811_hc *hc = urb->dev->bus->hcpriv;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = NULL;
	
	PDEBUG(4, "enter, urb = %p", urb);
	
	if (len > maxsze) {
		PDEBUG(1, "length is big than max packet size, len = %d, max packet = %d", len, maxsze);
		return -EINVAL;
	}
	if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED))
		ctrl |= SL811_USB_CTRL_PREAMBLE;
	
	ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
	if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
		ctrl |= SL811_USB_CTRL_TOGGLE_1;
	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));	
	td = sl811_alloc_td(urb);
	if (!td)
		return -ENOMEM;
		
	sl811_fill_td(td, ctrl, SL811_DATA_START, len, pidep, dev, data);
	sl811_calc_td_time(td);
	urbp->cur_td = urbp->first_td = urbp->last_td = td;
	urbp->interval = 0;
	
	PDEBUG(4, "leave success");
	
	return 0;
}

/*
 * Reset interrupt transfers
 */
static void sl811_reset_interrupt(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = urbp->cur_td;
	
	PDEBUG(4, "enter, interval = %d", urb->interval);
	
	td->ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
	if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
		td->ctrl |= SL811_USB_CTRL_TOGGLE_1;
	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));	
	
	sl811_reset_td(td);

	urbp->interval = urb->interval;
	
	urb->status = -EINPROGRESS;
	urb->actual_length = 0;
}

/*
 * Result the interrupt urb.
 */
static void sl811_result_interrupt(struct urb *urb)
{
	struct list_head *tmp;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td;
	int toggle;
	
	PDEBUG(4, "enter, urb = %p", urb);
	
	urb->actual_length = 0;

	tmp = &urbp->td_list;
	tmp = tmp->next;
	td = list_entry(tmp, struct sl811_td, td_list);

	// success.
	if (td->done && td->td_status == 0) {
		urb->actual_length += td->len - td->left;
		urb->status = 0;
		return ;
	}
	// tranfer is done but fail, reset the toggle.
	else if (td->done && td->td_status) {
		urb->status = td->td_status;
reset_toggle:
		toggle = (td->ctrl & SL811_USB_CTRL_TOGGLE_1) ? 1 : 0;
		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle);
		PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status);
		return ;
	}
	// unlink, and not do transfer yet
	else if (td->done == 0 && urbp->unlink && td->td_status == 0) {
		urb->status = -ENOENT;
		PDEBUG(3, "unlink and not transfer!");
		return ;
	}
	// unlink, and transfer not complete yet.
	else if (td->done == 0 && urbp->unlink && td->td_status) {
		urb->status = -ENOENT;
		PDEBUG(3, "unlink and not complete!");
		goto reset_toggle;
	}
	// must be bug!!!
	else {// (td->done == 0 && urbp->unlink == 0)
		PDEBUG(1, "we should not get here!");
		urb->status = -EPIPE;
		return ;
	}
}

/*
 * Control transfers
 */
static int sl811_submit_control(struct urb *urb)
{
	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
	int len = urb->transfer_buffer_length;
	__u8 *data = urb->transfer_buffer;
	__u8 dev = usb_pipedevice(urb->pipe);
	__u8 pidep = 0;
	__u8 ctrl = 0;
	struct sl811_hc *hc = urb->dev->bus->hcpriv;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = NULL;
	
	PDEBUG(4, "enter, urb = %p", urb);
	
	if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED))
		ctrl |= SL811_USB_CTRL_PREAMBLE;
	
	/* Build SETUP TD */
	pidep = PIDEP(USB_PID_SETUP, usb_pipeendpoint(urb->pipe));
	ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE | SL811_USB_CTRL_DIR_OUT;
	td = sl811_alloc_td(urb);
	if (!td)
		return -ENOMEM;
		
	sl811_fill_td(td, ctrl, SL811_DATA_START, 8, pidep, dev, urb->setup_packet);
	sl811_calc_td_time(td);
	
	urbp->cur_td = urbp->first_td = td;
	
	/*
	 * If direction is "send", change the frame from SETUP (0x2D)
	 * to OUT (0xE1). Else change it from SETUP to IN (0x69).
	 */
	pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
	if (usb_pipeout(urb->pipe))
		ctrl |= SL811_USB_CTRL_DIR_OUT;
	else
		ctrl &= ~SL811_USB_CTRL_DIR_OUT;

	/* Build the DATA TD's */
	while (len > 0) {
		int pktsze = len;

		if (pktsze > maxsze)
			pktsze = maxsze;

		/* Alternate Data0/1 (start with Data1) */
		ctrl ^= SL811_USB_CTRL_TOGGLE_1;
	
		td = sl811_alloc_td(urb);
		if (!td)
			return -ENOMEM;

		sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data);	
		sl811_calc_td_time(td);
		
		data += pktsze;
		len -= pktsze;
	}

	/* Build the final TD for control status */
	td = sl811_alloc_td(urb);
	if (!td)
		return -ENOMEM;

	/* It's IN if the pipe is an output pipe or we're not expecting data back */
	if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) {
		pidep = PIDEP(USB_PID_IN, usb_pipeendpoint(urb->pipe));
		ctrl &= ~SL811_USB_CTRL_DIR_OUT;	
	} else {
		pidep = PIDEP(USB_PID_OUT, usb_pipeendpoint(urb->pipe));
		ctrl |= SL811_USB_CTRL_DIR_OUT;
	}
		
	/* End in Data1 */
	ctrl |= SL811_USB_CTRL_TOGGLE_1;

	sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0);
	sl811_calc_td_time(td);
	urbp->last_td = td;
/*	
// for debug
	{
		struct list_head *head, *tmp;
		struct sl811_td *td;
		int i = 0;
		head = &urbp->td_list;
		tmp = head->next;
	
		if (list_empty(&urbp->td_list)) {
			PDEBUG(1, "bug!!! td list is empty!");
			return -ENODEV;
		}
		
		while (tmp != head) {
			++i;
			td = list_entry(tmp, struct sl811_td, td_list);
			PDEBUG(3, "td = %p, i = %d", td, i);
			tmp = tmp->next;
		}
	}
*/	
	PDEBUG(4, "leave success");
	
	return 0;
}

/*
 * Result the control urb.
 */
static void sl811_result_control(struct urb *urb)
{
	struct list_head *tmp, *head;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td;

	PDEBUG(4, "enter, urb = %p", urb);
	
	if (list_empty(&urbp->td_list)) {
		PDEBUG(1, "td list is empty");
		return ;
	}

	head = &urbp->td_list;

	tmp = head->next;
	td = list_entry(tmp, struct sl811_td, td_list);

	/* The first TD is the SETUP phase, check the status, but skip the count */
	if (!td->done) {
		PDEBUG(3, "setup phase error, td = %p, done = %d", td, td->done);
		goto err_done;
	}
	if (td->td_status)  {
		PDEBUG(3, "setup phase error, td = %p, td status = %d", td, td->td_status);
		goto err_status;
	}

	urb->actual_length = 0;

	/* The rest of the TD's (but the last) are data */
	tmp = tmp->next;
	while (tmp != head && tmp->next != head) {
		td = list_entry(tmp, struct sl811_td, td_list);
		tmp = tmp->next;
		if (!td->done) {
			PDEBUG(3, "data phase error, td = %p, done = %d", td, td->done);
			goto err_done;
		}
		if (td->td_status)  {
			PDEBUG(3, "data phase error, td = %p, td status = %d", td, td->td_status);
			goto err_status;
		}

		urb->actual_length += td->len - td->left;
		// short packet.
		if (td->left) {
			PDEBUG(3, "data phase short packet, td = %p, count = %d", td, td->len - td->left);
			break;
		}
	}

	/* The last td is status phase */
	td = urbp->last_td;
	if (!td->done) {
		PDEBUG(3, "status phase error, td = %p, done = %d", td, td->done);
		goto err_done;
	}
	if (td->td_status)  {
		PDEBUG(3, "status phase error, td = %p, td status = %d", td, td->td_status);
		goto err_status;
	}
	
	PDEBUG(4, "leave success");
	
	urb->status = 0;
	return ;

err_done:
	if (urbp->unlink)
		urb->status = -ENOENT;
	else {
		PDEBUG(1, "we should not get here! td = %p", td);
		urb->status = -EPIPE;
	}
	return ;	

err_status:
	urb->status = td->td_status;		
	return ;
}

/*
 * Bulk transfers
 */
static int sl811_submit_bulk(struct urb *urb)
{
	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
	int len = urb->transfer_buffer_length;
	__u8 *data = urb->transfer_buffer;
	__u8 dev = usb_pipedevice(urb->pipe);
	__u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
	__u8 ctrl = 0;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = NULL;

	PDEBUG(4, "enter, urb = %p", urb);
		
	if (len < 0) {
		PDEBUG(1, "error, urb = %p, len = %d", urb, len);
		return -EINVAL;
	}

	/* Can't have low speed bulk transfers */
	if (usb_pipeslow(urb->pipe)) {
		PDEBUG(1, "error, urb = %p, low speed device", urb);
		return -EINVAL;
	}

	if (usb_pipeout(urb->pipe))
		ctrl |= SL811_USB_CTRL_DIR_OUT;
		
	ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
			
	/* Build the DATA TD's */
	do {	/* Allow zero length packets */
		int pktsze = len;

		if (pktsze > maxsze)
			pktsze = maxsze;

		td = sl811_alloc_td(urb);
		if (!td)
			return -ENOMEM;

		/* Alternate Data0/1 (start with Data1) */
		ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
		if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
			ctrl |= SL811_USB_CTRL_TOGGLE_1;
		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));		
		
		sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data);
		sl811_calc_td_time(td);
		
		if (urbp->cur_td == NULL)
			urbp->cur_td = urbp->first_td = td;
			
		data += pktsze;
		len -= maxsze;
	} while (len > 0);

	/*
	 * USB_ZERO_PACKET means adding a 0-length packet, if
	 * direction is OUT and the transfer_length was an
	 * exact multiple of maxsze, hence
	 * (len = transfer_length - N * maxsze) == 0
	 * however, if transfer_length == 0, the zero packet
	 * was already prepared above.
	 */
	if (usb_pipeout(urb->pipe) && (urb->transfer_flags & USB_ZERO_PACKET) &&
	   !len && urb->transfer_buffer_length) {
		
		td = sl811_alloc_td(urb);
		if (!td)
			return -ENOMEM;

		/* Alternate Data0/1 (start with Data1) */
		ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
		if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
			ctrl |= SL811_USB_CTRL_TOGGLE_1;
		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
			
		sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0);
		sl811_calc_td_time(td);
	}
	
	urbp->last_td = td;
	
	PDEBUG(4, "leave success");
	
	return 0;
}

/*
 * Reset bulk transfers
 */
static int sl811_reset_bulk(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td;
	struct list_head *head, *tmp;

	PDEBUG(4, "enter, urb = %p", urb);
	
	
	head = &urbp->td_list;	
	tmp = head->next;
	
	while (tmp != head) {
		td = list_entry(tmp, struct sl811_td, td_list);

		/* Alternate Data0/1 (start with Data1) */
		td->ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
		if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
			td->ctrl |= SL811_USB_CTRL_TOGGLE_1;
		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
		
		sl811_reset_td(td);
	} 

	urb->status = -EINPROGRESS;
	urb->actual_length = 0;
	urbp->cur_td = urbp->first_td;

	PDEBUG(4, "leave success");
	
	return 0;
}

/*
 * Result the bulk urb.
 */
static void sl811_result_bulk(struct urb *urb)
{
	struct list_head *tmp, *head;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = NULL;
	int toggle;

	PDEBUG(4, "enter, urb = %p", urb);
	
	urb->actual_length = 0;

	head = &urbp->td_list;
	tmp = head->next;
	while (tmp != head) {
		td = list_entry(tmp, struct sl811_td, td_list);
		tmp = tmp->next;

		// success.
		if (td->done && td->td_status == 0) {
			urb->actual_length += td->len - td->left;
			
			// short packet
			if (td->left) {
				urb->status = 0;
				PDEBUG(3, "short packet, td = %p, count = %d", td, td->len - td->left);
				goto reset_toggle;
			}
		}
		// tranfer is done but fail, reset the toggle.
		else if (td->done && td->td_status) {
			urb->status = td->td_status;
			PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status);
			goto reset_toggle;
		}
		// unlink, and not do transfer yet
		else if (td->done == 0 && urbp->unlink && td->td_status == 0) {
			urb->status = -ENOENT;
			PDEBUG(3, "unlink and not transfer!");
			return ;
		}
		// unlink, and transfer not complete yet.
		else if (td->done == 0 && urbp->unlink && td->td_status) {
			PDEBUG(3, "unlink and not complete!");
			urb->status = -ENOENT;
			goto reset_toggle;
		}
		// must be bug!!!
		else {// (td->done == 0 && urbp->unlink == 0)
			urb->status = -EPIPE;
			PDEBUG(1, "we should not get here!");
			return ;
		}
	}
	
	PDEBUG(4, "leave success");		
	urb->status = 0;
	return ;

reset_toggle:
	toggle = (td->ctrl & SL811_USB_CTRL_TOGGLE_1) ? 1 : 0;
	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle);
}

/*
 * Find the first urb have the same dev and endpoint.
 */
static inline int sl811_find_same_urb(struct list_head *head, struct urb *urb)
{
	struct list_head *tmp;
	struct urb *u;
	
	if (!head || !urb)
		return 0;
		
	tmp = head->next;
	
	while (tmp != head) {
		u = list_entry(tmp, struct urb, urb_list);
		if (u == urb)
			return 1;
		tmp = tmp->next;	
	}
	
	return 0;
}

/*
 * Find the first urb have the same dev and endpoint.
 */
static inline struct urb* sl811_find_same_devep(struct list_head *head, struct urb *urb)
{
	struct list_head *tmp;
	struct urb *u;
	
	if (!head || !urb)
		return NULL;
		
	tmp = head->next;
	
	while (tmp != head) {
		u = list_entry(tmp, struct urb, urb_list);
		if ((usb_pipe_endpdev(u->pipe)) == (usb_pipe_endpdev(urb->pipe)))
			return u;
		tmp = tmp->next;	
	}
	
	return NULL;
}

/*
 * This function is called by the USB core API when an URB is available to
 * process. 
 */
static int sl811_submit_urb(struct urb *urb)
{
	struct sl811_hc *hc = urb->dev->bus->hcpriv;
	unsigned int pipe = urb->pipe;
	struct list_head *head = NULL;
	unsigned long flags;
	int bustime;
	int ret = 0;
	
	if (!urb) {
		PDEBUG(1, "urb is null");
		return -EINVAL;
	}
	
	if (urb->hcpriv) {
		PDEBUG(1, "urbp is not null, urb = %p, urbp = %p", urb, urb->hcpriv);
		return -EINVAL;
	}
	
	if (!urb->dev || !urb->dev->bus || !hc)  {
		PDEBUG(1, "dev or bus or hc is null");
		return -ENODEV;
	}
	
	if (usb_endpoint_halted(urb->dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
		PDEBUG(2, "sl811_submit_urb: endpoint_halted");
		return -EPIPE;
	}
	
	if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) > SL811_DATA_LIMIT) {
		printk(KERN_ERR "Packet size is big for SL811, should < %d!\n", SL811_DATA_LIMIT);
		return -EINVAL;
	}
	
	/* a request to the virtual root hub */ 
	if (usb_pipedevice(pipe) == hc->rh.devnum)
		return sl811_rh_submit_urb(urb);
	
	spin_lock_irqsave(&hc->hc_lock, flags);
	spin_lock(&urb->lock);
	
	switch (usb_pipetype(urb->pipe)) {
	case PIPE_ISOCHRONOUS:
		head = &hc->iso_list;
		break;
	case PIPE_INTERRUPT:
		head = &hc->intr_list;
		break;
	case PIPE_CONTROL:
		head = &hc->ctrl_list;
		break;
	case PIPE_BULK:
		head = &hc->bulk_list;
		break;
	}
		
	if (sl811_find_same_devep(head, urb)) {
		list_add(&urb->urb_list, &hc->wait_list);
		PDEBUG(4, "add to wait list");
		goto out_unlock;
	}
	
	if (!sl811_alloc_urb_priv(urb)) {
		ret = -ENOMEM;
		goto out_unlock;
	}
	
	switch (usb_pipetype(urb->pipe)) {
	case PIPE_ISOCHRONOUS:
		if (urb->number_of_packets <= 0) {
			ret = -EINVAL;
			break;
		}
		bustime = usb_check_bandwidth(urb->dev, urb);
		if (bustime < 0) {
			ret = bustime;
			break;
		}
		if (!(ret = sl811_submit_isochronous(urb)))
			usb_claim_bandwidth(urb->dev, urb, bustime, 1);
		break;
	case PIPE_INTERRUPT:
		bustime = usb_check_bandwidth(urb->dev, urb);
		if (bustime < 0)
			ret = bustime;
		else if (!(ret = sl811_submit_interrupt(urb)))
			usb_claim_bandwidth(urb->dev, urb, bustime, 0);
		break;
	case PIPE_CONTROL:
		ret = sl811_submit_control(urb);
		break;
	case PIPE_BULK:
		ret = sl811_submit_bulk(urb);
		break;
	}
	
	if (!ret) {
		((struct sl811_urb_priv *)urb->hcpriv)->inserttime = jiffies;
		list_add(&urb->urb_list, head);
		PDEBUG(4, "add to type list");
		urb->status = -EINPROGRESS;
		if (++hc->active_urbs == 1)
			sl811_enable_interrupt(hc);
		goto out_unlock;	
	} else {
		PDEBUG(2, "submit urb fail! error = %d", ret);
		sl811_free_urb_priv(urb);
	}
	
out_unlock:	
	spin_unlock(&urb->lock);
	spin_unlock_irqrestore(&hc->hc_lock, flags);

	return ret;
}

/*
 * Submit the urb the wait list.
 */
static int sl811_submit_urb_with_lock(struct urb *urb)
{
	struct sl811_hc *hc = urb->dev->bus->hcpriv;
	struct list_head *head = NULL;
	int bustime;
	int ret = 0;
	
	spin_lock(&urb->lock);
	
	switch (usb_pipetype(urb->pipe)) {
	case PIPE_ISOCHRONOUS:
		head = &hc->iso_list;
		break;
	case PIPE_INTERRUPT:
		head = &hc->intr_list;
		break;
	case PIPE_CONTROL:
		head = &hc->ctrl_list;
		break;
	case PIPE_BULK:
		head = &hc->bulk_list;
		break;
	}
		
	if (!sl811_alloc_urb_priv(urb)) {
		ret = -ENOMEM;
		goto out_unlock;
	}
	
	switch (usb_pipetype(urb->pipe)) {
	case PIPE_ISOCHRONOUS:
		if (urb->number_of_packets <= 0) {
			ret = -EINVAL;
			break;
		}
		bustime = usb_check_bandwidth(urb->dev, urb);
		if (bustime < 0) {
			ret = bustime;
			break;
		}
		if (!(ret = sl811_submit_isochronous(urb)))
			usb_claim_bandwidth(urb->dev, urb, bustime, 1);
		break;
	case PIPE_INTERRUPT:
		bustime = usb_check_bandwidth(urb->dev, urb);
		if (bustime < 0)
			ret = bustime;
		else if (!(ret = sl811_submit_interrupt(urb)))
			usb_claim_bandwidth(urb->dev, urb, bustime, 0);
		break;
	case PIPE_CONTROL:
		ret = sl811_submit_control(urb);
		break;
	case PIPE_BULK:
		ret = sl811_submit_bulk(urb);
		break;
	}
	
	if (ret == 0) {
		((struct sl811_urb_priv *)urb->hcpriv)->inserttime = jiffies;
		list_add(&urb->urb_list, head);
		PDEBUG(4, "add to type list");
		urb->status = -EINPROGRESS;
		if (++hc->active_urbs == 1)
			sl811_enable_interrupt(hc);
		goto out_unlock;	
	} else {
		PDEBUG(2, "submit urb fail! error = %d", ret);
		sl811_free_urb_priv(urb);
	}
	
out_unlock:	
	spin_unlock(&urb->lock);

	return ret;
}

/*
 * Reset the urb
 */
static void sl811_reset_urb(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;

	switch (usb_pipetype(urb->pipe)) {
	case PIPE_ISOCHRONOUS:
		sl811_reset_isochronous(urb);
		break;
	case PIPE_INTERRUPT:
		sl811_reset_interrupt(urb);
		break;
	case PIPE_CONTROL:
		return;
	case PIPE_BULK:
		sl811_reset_bulk(urb);
		break;
	}
	urbp->inserttime = jiffies;
}

/*
 * Return the result of a transfer
 */
static void sl811_result_urb(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_hc *hc = urb->dev->bus->hcpriv;
	struct list_head *head = NULL;
	struct urb *u = NULL;
	int reset = 0;
	int ring = 0;

	if (urb->status != -EINPROGRESS) {
		PDEBUG(1, "urb status is not EINPROGRESS!");
		return ;
	}
	
	spin_lock(&urb->lock);
	
	switch (usb_pipetype(urb->pipe)) {
	case PIPE_ISOCHRONOUS:
		head = &hc->iso_list;
		sl811_result_isochronous(urb);
		
		// if the urb is not unlink and is in a urb "ring", we reset it
		if (!urbp->unlink && urb->next) 
			ring = 1;
		break;
	case PIPE_INTERRUPT:
		head = &hc->intr_list;
		sl811_result_interrupt(urb);
		
		// if the urb is not unlink and not "once" query, we reset.
		if (!urbp->unlink && urb->interval)
			reset = 1;
		break;
	case PIPE_CONTROL:
		head = &hc->ctrl_list;
		sl811_result_control(urb);
		break;
	case PIPE_BULK:
		head = &hc->bulk_list;
		sl811_result_bulk(urb);
		
		// if the urb is not unlink and is in a urb "ring", we reset it
		if (!urbp->unlink && urb->next)
			ring = 1;
		break;
	}
	
	PDEBUG(4, "result urb status = %d", urb->status);
	
	if (ring && urb->next == urb)
		reset = 1;
	
	if (!reset) {
		switch (usb_pipetype(urb->pipe)) {
		case PIPE_ISOCHRONOUS:
			usb_release_bandwidth(urb->dev, urb, 1);
			break;
		case PIPE_INTERRUPT:
			usb_release_bandwidth(urb->dev, urb, 0);
			break;
		}
		sl811_free_urb_priv(urb);
	}
	
	spin_unlock(&urb->lock);
	
	if (urb->complete)
		urb->complete(urb);
	
	if (reset) {
		spin_lock(&urb->lock);
		sl811_reset_urb(urb);
		if (usb_pipeint(urb->pipe))
			list_add(&urb->urb_list, &hc->idle_intr_list);
		else
			list_add(&urb->urb_list, head);
		spin_unlock(&urb->lock);
	} else {
		if (--hc->active_urbs <= 0) {
			hc->active_urbs = 0;
			sl811_disable_interrupt(hc);
		}
		
		if (ring) 
			u = urb->next;
		else
			u = sl811_find_same_devep(&hc->wait_list, urb);
			
		if (u) {
			if (!list_empty(&u->urb_list))
				list_del(&u->urb_list);
			if (sl811_submit_urb_with_lock(u))
				list_add(&u->urb_list, &hc->wait_list);
		}
	}
}


#ifdef SL811_TIMEOUT

/*
 * Unlink the urb from the urb list
 */
static int sl811_unlink_urb(struct urb *urb)
{
	unsigned long flags;
	struct sl811_hc *hc;
	struct sl811_urb_priv *urbp;
	int call = 0;
	int schedule = 0;
	int count = 0;
	
	if (!urb) {
		PDEBUG(1, "urb is null");
		return -EINVAL;
	}
	
	if (!urb->dev || !urb->dev->bus) {
		PDEBUG(1, "dev or bus is null");
		return -ENODEV;
	}
	
	hc = urb->dev->bus->hcpriv; 
	urbp = urb->hcpriv;
	
	/* a request to the virtual root hub */
	if (usb_pipedevice(urb->pipe) == hc->rh.devnum)
		return sl811_rh_unlink_urb(urb); 
	
	spin_lock_irqsave(&hc->hc_lock, flags);
	spin_lock(&urb->lock);

	// in wait list
	if (sl811_find_same_urb(&hc->wait_list, urb)) {	
		PDEBUG(4, "unlink urb in wait list");
		list_del_init(&urb->urb_list);
		urb->status = -ENOENT;
		call = 1;
		goto out;
	}
	
	// in intr idle list.
	if (sl811_find_same_urb(&hc->idle_intr_list, urb)) {	
		PDEBUG(4, "unlink urb in idle intr list");
		list_del_init(&urb->urb_list);
		urb->status = -ENOENT;
		sl811_free_urb_priv(urb);
		usb_release_bandwidth(urb->dev, urb, 0);
		if (--hc->active_urbs <= 0) {
			hc->active_urbs = 0;
			sl811_disable_interrupt(hc);
		}
		call = 1;
		goto out;
	}

	if (urb->status == -EINPROGRESS) {  
		PDEBUG(3, "urb is still in progress");
		urbp->unlink = 1;

re_unlink:
		// Is it in progress?
		urbp = urb->hcpriv;
		if (urbp && hc->cur_td == urbp->cur_td) {
			++count;
			if (sl811_read(hc, 0) & SL811_USB_CTRL_ARM) {
				PDEBUG(3, "unlink: cur td is still in progress! count = %d", count);
re_schedule:				
				schedule = 1;
				spin_unlock(&urb->lock);
				spin_unlock_irqrestore(&hc->hc_lock, flags);
				schedule_timeout(HZ/50);
				spin_lock_irqsave(&hc->hc_lock, flags);
				spin_lock(&urb->lock);
			} else {
				PDEBUG(3, "unlink: lost of interrupt? do parse! count = %d", count);
				spin_unlock(&urb->lock);
				sl811_transfer_done(hc, 0);
				spin_lock(&urb->lock);
			}
			goto re_unlink;
		}
		
		if (list_empty(&urb->urb_list)) {
			PDEBUG(3, "unlink: list empty!");
			goto out;
		}
			
		if (urb->transfer_flags & USB_TIMEOUT_KILLED) { 
			PDEBUG(3, "unlink: time out killed");
			// it is timeout killed by us 
			goto result;
		} else if (urb->transfer_flags & USB_ASYNC_UNLINK) { 
			// we do nothing, just let it be processing later
			PDEBUG(3, "unlink async, do nothing");
			goto out;
		} else {
			// synchron without callback
			PDEBUG(3, "unlink synchron, we wait the urb complete or timeout");
			if (schedule == 0) {
				PDEBUG(3, "goto re_schedule");
				goto re_schedule;
			} else {
				PDEBUG(3, "already scheduled");
				goto result;
			}
		}
	} else if (!list_empty(&urb->urb_list)) {
		PDEBUG(1, "urb = %p, status = %d is in a list, why?", urb, urb->status);
		//list_del_init(&urb->urb_list);
		//call = 1;
	}

out:
	spin_unlock(&urb->lock);
	spin_unlock_irqrestore(&hc->hc_lock, flags);
	
	if (call && urb->complete)
		urb->complete(urb);
	
	return 0;
	
result:
	spin_unlock(&urb->lock);
	
	list_del_init(&urb->urb_list);
	sl811_result_urb(urb);	
	
	spin_unlock_irqrestore(&hc->hc_lock, flags);
	
	return 0;
}

#else

/*
 * Unlink the urb from the urb list
 */
static int sl811_unlink_urb(struct urb *urb)
{
	unsigned long flags;
	struct sl811_hc *hc;
	struct sl811_urb_priv *urbp;
	int call = 0;
	
	if (!urb) {
		PDEBUG(1, "urb is null");
		return -EINVAL;
	}
	
	if (!urb->dev || !urb->dev->bus) {
		PDEBUG(1, "dev or bus is null");
		return -ENODEV;
	}
	
	hc = urb->dev->bus->hcpriv; 
	urbp = urb->hcpriv;
	
	/* a request to the virtual root hub */
	if (usb_pipedevice(urb->pipe) == hc->rh.devnum)
		return sl811_rh_unlink_urb(urb); 
	
	spin_lock_irqsave(&hc->hc_lock, flags);
	spin_lock(&urb->lock);

	// in wait list
	if (sl811_find_same_urb(&hc->wait_list, urb)) {	
		PDEBUG(2, "unlink urb in wait list");
		list_del_init(&urb->urb_list);
		urb->status = -ENOENT;
		call = 1;
		goto out;
	}
	
	if (urb->status == -EINPROGRESS) {  
		PDEBUG(2, "urb is still in progress");
		urbp->unlink = 1;

		// Is it in progress?
		urbp = urb->hcpriv;
		if (urbp && hc->cur_td == urbp->cur_td) {
			// simple, let it out
			PDEBUG(2, "unlink: cur td is still in progress!");
			hc->cur_td = NULL;
		}
		
		goto result;
	} else if (!list_empty(&urb->urb_list)) {
		PDEBUG(1, "urb = %p, status = %d is in a list, why?", urb, urb->status);
		list_del_init(&urb->urb_list);
		if (urbp)
			goto result;
		else
			call = 1;
	}

out:
	spin_unlock(&urb->lock);
	spin_unlock_irqrestore(&hc->hc_lock, flags);
	
	if (call && urb->complete)
		urb->complete(urb);
			
	return 0;
	
result:
	spin_unlock(&urb->lock);
	
	list_del_init(&urb->urb_list);
	sl811_result_urb(urb);	
	
	spin_unlock_irqrestore(&hc->hc_lock, flags);
	
	return 0;
}

#endif

static int sl811_get_current_frame_number(struct usb_device *usb_dev)
{
	return ((struct sl811_hc *)(usb_dev->bus->hcpriv))->frame_number;
}

static struct usb_operations sl811_device_operations = 
{
	sl811_alloc_dev_priv,
	sl811_free_dev_priv,
	sl811_get_current_frame_number,
	sl811_submit_urb,
	sl811_unlink_urb
};

/*
 * This	functions transmit a td.
 */
static inline void sl811_trans_cur_td(struct sl811_hc *hc, struct sl811_td *td)
{
	sl811_print_td(4, td);
	sl811_write_buf(hc, SL811_ADDR_A,  &td->addr, 4);
	if (td->len && (td->ctrl & SL811_USB_CTRL_DIR_OUT))
		sl811_write_buf(hc, td->addr,  td->buf, td->len);

	sl811_write(hc,	SL811_CTRL_A, td->ctrl);
}

		
/*
 * This	function checks	the status of the transmitted or received packet
 * and copy the	data from the SL811HS register into a buffer.
 */
static void sl811_parse_cur_td(struct sl811_hc *hc, struct sl811_td *td)
{
	struct urb *urb = td->urb;
#ifdef SL811_DEBUG
	int dev = usb_pipedevice(td->urb->pipe);
	int ep = usb_pipeendpoint(td->urb->pipe);
#endif

	sl811_read_buf(hc, SL811_STS_A, &td->status, 2);
	
	if (td->status & SL811_USB_STS_ACK) {
		td->done = 1;
		
/*		if ((td->ctrl & SL811_USB_CTRL_TOGGLE_1) != (td->status & SL811_USB_STS_TOGGLE_1)) {
			PDEBUG(2, "dev %d endpoint %d unexpect data toggle!", dev, ep);
			td->td_status = -EILSEQ;
		}
*/		
		if (!(td->ctrl & SL811_USB_CTRL_DIR_OUT) && td->len > 0)
			sl811_read_buf(hc, td->addr, td->buf, td->len - td->left);
			
		if (td->left && (urb->transfer_flags & USB_DISABLE_SPD)) {
			PDEBUG(2, "dev %d endpoint %d unexpect short packet! td = %p", dev, ep, td);
			td->td_status = -EREMOTEIO;
		} else
			td->td_status = 0;
	} else if (td->status & SL811_USB_STS_STALL) {
		PDEBUG(2, "dev %d endpoint %d halt, td = %p", dev, ep, td);
		td->td_status = -EPIPE;
		if (urb->dev)
			usb_endpoint_halt(td->urb->dev, usb_pipeendpoint(td->urb->pipe), usb_pipeout(td->urb->pipe));
		td->done = 1;
	} else if (td->status & SL811_USB_STS_OVERFLOW) {
		PDEBUG(1, "dev %d endpoint %d overflow, sl811 only support packet less than %d", dev, ep, SL811_DATA_LIMIT);	
		td->td_status = -EOVERFLOW;
		td->done = 1;
	} else if (td->status & SL811_USB_STS_TIMEOUT ) {
		PDEBUG(2, "dev %d endpoint %d timeout, td = %p", dev, ep, td);	
		td->td_status = -ETIMEDOUT;
		if (--td->errcnt == 0)
			td->done = 1;
	} else if (td->status & SL811_USB_STS_ERROR) {
		PDEBUG(2, "dev %d endpoint %d error, td = %p", dev, ep, td);
		td->td_status = -EILSEQ;
		if (--td->errcnt == 0)
			td->done = 1;
	} else if (td->status & SL811_USB_STS_NAK) {
		++td->nakcnt;
		PDEBUG(3, "dev %d endpoint %d nak, td = %p, count = %d", dev, ep, td, td->nakcnt);
		td->td_status = -EINPROGRESS;
		if (!usb_pipeslow(td->urb->pipe) && td->nakcnt > 1024) {
			PDEBUG(2, "too many naks, td = %p, count = %d", td, td->nakcnt);
			td->td_status = -ETIMEDOUT;
			td->done = 1;
		} 
	} 
	
	sl811_print_td(4, td);
}

/*
 * This	function checks	the status of current urb.
 */
static int sl811_parse_cur_urb(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = urbp->cur_td;
	struct list_head *tmp;
	
	sl811_print_td(5, td);
	
	// this td not done yet.
	if (!td->done)
		return 0;
	
	// the last ld, so the urb is done.
	if (td == urbp->last_td) {
		PDEBUG(4, "urb = %p is done success", td->urb);
		if (usb_pipeisoc(td->urb->pipe))
			PDEBUG(4, "ISO URB DONE, td = %p", td);
		return 1;
	}
	
	// iso transfer, we always advance to next td 
	if (usb_pipeisoc(td->urb->pipe)) {
		tmp = &td->td_list;
		tmp = tmp->next;
		urbp->cur_td = list_entry(tmp, struct sl811_td, td_list);
		PDEBUG(4, "ISO NEXT, td = %p", urbp->cur_td);	
		return 0;
	}
		
	// some error occur, so the urb is done.
	if (td->td_status) {
		PDEBUG(3, "urb = %p is done error, td status is = %d", td->urb, td->td_status);
		return 1;
	}
		
	// short packet.
	if (td->left) {
		if (usb_pipecontrol(td->urb->pipe)) {
			// control packet, we advance to the last td
			PDEBUG(3, "ctrl short packet, advance to last td");
			urbp->cur_td = urbp->last_td;
			return 0;
		} else {
			// interrut and bulk packet, urb is over.
			PDEBUG(3, "bulk or intr short packet, urb is over");
			return 1;
		}
	}

	// we advance to next td.	
	tmp = &td->td_list;
	tmp = tmp->next;
	urbp->cur_td = list_entry(tmp, struct sl811_td, td_list);
#ifdef SL811_DEBUG
	PDEBUG(4, "advance to the next td, urb = %p, td = %p", urb, urbp->cur_td);
	sl811_print_td(5, urbp->cur_td);
	if (td == urbp->cur_td)
		PDEBUG(1, "bug!!!");
#endif		
	return 0;
}

/*
 * Find the next td to transfer.
 */
static inline struct sl811_td* sl811_schedule_next_td(struct urb *urb, struct sl811_td *cur_td)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	
	PDEBUG(4, "urb at %p, cur td at %p", urb, cur_td);
	
	// iso don't schedule the td in the same frame.
	if (usb_pipeisoc(cur_td->urb->pipe))
		return NULL;
	
	// cur td is not complete
	if (!cur_td->done)
		return NULL;	
	
	// here, urbp->cur_td is already the next td;
	return urbp->cur_td;
}

/*
 * Scan the list to find a active urb
 */
static inline struct urb* sl811_get_list_next_urb(struct sl811_hc *hc, struct list_head *next)
{
	struct urb *urb;
	int i;
	
	if (list_empty(next))
		return NULL;
	
	if (next == hc->cur_list)
		return NULL;
			
	for (i = 0; i < 4; ++i) 
		if (next == &hc->urb_list[i])
			return NULL;
			
	urb = list_entry(next, struct urb, urb_list);
	PDEBUG(4, "next urb in list is at %p", urb);
		
	return urb;
}

/*
 * Find the next td to transfer.
 */
static struct sl811_td* sl811_schedule_next_urb(struct sl811_hc *hc, struct list_head *next)
{
	struct urb *urb = NULL;
	int back_loop = 1;
	struct list_head *old_list = hc->cur_list;
		
	// try to get next urb in the same list.
	if (next) {
		urb = sl811_get_list_next_urb(hc, next);
		if (!urb)
			++hc->cur_list;
	}

	// try other list.
	if (!urb) {			
re_loop:
		// try all the list.
		while (hc->cur_list < &hc->urb_list[4]) { 
			if ((urb = sl811_get_list_next_urb(hc, hc->cur_list->next)))
				return ((struct sl811_urb_priv *)urb->hcpriv)->cur_td;
			++hc->cur_list;
		}
		// the last list is try 
		if (back_loop && (old_list >= &hc->ctrl_list)) {
			hc->cur_list = &hc->ctrl_list;
			back_loop = 0;
			goto re_loop;
		}
	}
	
	if (hc->cur_list > &hc->urb_list[3])
		hc->cur_list = &hc->ctrl_list;
			
	return NULL;
}

/*
 * This function process the transfer rusult.
 */
static void sl811_transfer_done(struct sl811_hc *hc, int sof) 
{
	struct sl811_td *cur_td = hc->cur_td, *next_td = NULL;
	struct urb *cur_urb = NULL;
       	struct list_head *next = NULL;
       	int done;
	
	PDEBUG(5, "enter");
	
	if (cur_td == NULL) {
		PDEBUG(1, "in done interrupt, but td is null, be already parsed?");
		return ;
	}

	cur_urb = cur_td->urb;
	hc->cur_td = NULL;
	next = &cur_urb->urb_list;
	next = next->next;
	
	spin_lock(&cur_urb->lock);	
	sl811_parse_cur_td(hc, cur_td);
	done = sl811_parse_cur_urb(cur_urb);
	spin_unlock(&cur_urb->lock);
	
	if (done) {
		list_del_init(&cur_urb->urb_list);
		cur_td = NULL;
		sl811_result_urb(cur_urb);	
	}

	if (sof)
		return ;
	
	if (!done) {
		next_td = sl811_schedule_next_td(cur_urb, cur_td);
		if (next_td && next_td != cur_td && (sl811_calc_bus_remainder(hc) > next_td->bustime)) {
			hc->cur_td = next_td;
			PDEBUG(5, "ADD TD");
			sl811_trans_cur_td(hc, next_td);
			return ;
		}
	}
	
	while (1) {
		next_td = sl811_schedule_next_urb(hc, next);
		if (!next_td)
			return;
		if (next_td == cur_td)
			return;
		next = &next_td->urb->urb_list;
		next = next->next;
		if (sl811_calc_bus_remainder(hc) > next_td->bustime) {
			hc->cur_td = next_td;
			PDEBUG(5, "ADD TD");
			sl811_trans_cur_td(hc, next_td);
			return ;
		}
	}
}

/*
 *
 */
static void inline sl811_dec_intr_interval(struct sl811_hc *hc)
{
	struct list_head *head, *tmp;
	struct urb *urb;
	struct sl811_urb_priv *urbp;
	
	if (list_empty(&hc->idle_intr_list))
		return ;
	
	head = &hc->idle_intr_list;
	tmp = head->next;
	
	while (tmp != head) {
		urb = list_entry(tmp, struct urb, urb_list);
		tmp = tmp->next;
		spin_lock(&urb->lock);
		urbp = urb->hcpriv;
		if (--urbp->interval == 0) {
			list_del(&urb->urb_list);
			list_add(&urb->urb_list, &hc->intr_list);
			PDEBUG(4, "intr urb active");
		}
		spin_unlock(&urb->lock);
	}
}

/*
 * The sof interrupt is happen.	
 */
static void sl811_start_sof(struct sl811_hc *hc)
{
	struct sl811_td *next_td;
#ifdef SL811_DEBUG
	static struct sl811_td *repeat_td = NULL;
	static int repeat_cnt = 1;
#endif	
	if (++hc->frame_number > 1024)
		hc->frame_number = 0;
	
	if (hc->active_urbs == 0)
		return ;
	
	sl811_dec_intr_interval(hc);
	
	if (hc->cur_td) {
		if (sl811_read(hc, 0) & SL811_USB_CTRL_ARM) {
#ifdef SL811_DEBUG
			if (repeat_td == hc->cur_td) 
				++repeat_cnt;
			else {
				if (repeat_cnt >= 2)
					PDEBUG(2, "cur td = %p repeat %d", hc->cur_td, repeat_cnt);
				repeat_cnt = 1;
				repeat_td = hc->cur_td;
			}
#endif
			return ;
		} else {
			PDEBUG(2, "lost of interrupt in sof? do parse!");
			sl811_transfer_done(hc, 1);
			
			// let this frame idle	
			return;
		}
	}
	
	hc->cur_list = &hc->iso_list;
	
	if (hc->active_urbs == 0)
		return ;
	
	next_td = sl811_schedule_next_urb(hc, NULL);
	if (!next_td) {
#ifdef SL811_DEBUG
		if (list_empty(&hc->idle_intr_list))
			PDEBUG(2, "not schedule a td, why? urbs = %d", hc->active_urbs);
#endif
		return; 
	}
	if (sl811_calc_bus_remainder(hc) > next_td->bustime) {
		hc->cur_td = next_td;
		sl811_trans_cur_td(hc, next_td);
	} else
		PDEBUG(2, "bus time if not enough, why?");
}

/*
 * This	function resets	SL811HS	controller and detects the speed of
 * the connecting device
 *
 * Return: 0 = no device attached; 1 = USB device attached
 */
static int sl811_hc_reset(struct sl811_hc *hc)
{
	int status ;

	sl811_write(hc,	SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
	sl811_write(hc,	SL811_CTRL1, SL811_CTRL1_RESET);

	mdelay(20);
	
	// Disable hardware SOF generation, clear all irq status.
	sl811_write(hc,	SL811_CTRL1, 0);
	mdelay(2);
	sl811_write(hc, SL811_INTRSTS, 0xff); 
	status = sl811_read(hc, SL811_INTRSTS);

	if (status & SL811_INTR_NOTPRESENT) {
		// Device is not present
		PDEBUG(0, "Device not present");
		hc->rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE);
		hc->rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
		sl811_write(hc,	SL811_INTR, SL811_INTR_INSRMV);
		return 0;
	}

	// Send SOF to address 0, endpoint 0.
	sl811_write(hc, SL811_LEN_B, 0);
	sl811_write(hc, SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0));
	sl811_write(hc, SL811_DEV_B, 0x00);
	sl811_write (hc, SL811_SOFLOW, SL811_12M_HI);

	if (status & SL811_INTR_SPEED_FULL) {
		/* full	speed device connect directly to root hub */
		PDEBUG (0, "Full speed Device attached");
		
		sl811_write(hc, SL811_CTRL1, SL811_CTRL1_RESET);
		mdelay(20);
		sl811_write(hc,	SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
		sl811_write(hc, SL811_CTRL1, SL811_CTRL1_SOF);

		/* start the SOF or EOP	*/
		sl811_write(hc, SL811_CTRL_B, SL811_USB_CTRL_ARM);
		hc->rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION;
		hc->rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
		mdelay(2);
		sl811_write (hc, SL811_INTRSTS, 0xff);
	} else {
		/* slow	speed device connect directly to root-hub */
		PDEBUG(0, "Low speed Device attached");
		
		sl811_write(hc, SL811_CTRL1, SL811_CTRL1_RESET);
		mdelay(20);
		sl811_write(hc,	SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI);
		sl811_write(hc, SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF);

		/* start the SOF or EOP	*/
		sl811_write(hc, SL811_CTRL_B, SL811_USB_CTRL_ARM);
		hc->rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED;
		mdelay(2);
		sl811_write(hc, SL811_INTRSTS, 0xff);
	}

	hc->rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
	sl811_write(hc,	SL811_INTR, SL811_INTR_INSRMV);
	
	return 1;
}

/*
 * Interrupt service routine.
 */
static void sl811_interrupt(int irq, void *__hc, struct pt_regs * r)
{
	__u8 status;
	struct sl811_hc *hc = __hc;

	status = sl811_read(hc, SL811_INTRSTS);
	if (status == 0)
		return ; /* Not me */

	sl811_write(hc,	SL811_INTRSTS, 0xff);

	if (status & SL811_INTR_INSRMV) {
		sl811_write(hc,	SL811_INTR, 0);
		sl811_write(hc,	SL811_CTRL1, 0);
		// wait	for device stable
		mdelay(100);			
		sl811_hc_reset(hc);
		return ;
	}

	spin_lock(&hc->hc_lock);
	
	if (status & SL811_INTR_DONE_A) {
		if (status & SL811_INTR_SOF) {
			sl811_transfer_done(hc, 1);
			PDEBUG(4, "sof in done!");
			sl811_start_sof(hc);
		} else
			sl811_transfer_done(hc, 0);
	} else if (status & SL811_INTR_SOF)
		sl811_start_sof(hc);	

	spin_unlock(&hc->hc_lock);	

	return ;
}

/*
 * This	function allocates all data structure and store	in the
 * private data	structure.
 *
 * Return value	 : data structure for the host controller
 */
static struct sl811_hc* __devinit sl811_alloc_hc(void)
{
	struct sl811_hc *hc;
	struct usb_bus *bus;
	int i;

	PDEBUG(5, "enter");

	hc = (struct sl811_hc *)kmalloc(sizeof(struct sl811_hc), GFP_KERNEL);
	if (!hc)
		return NULL;

	memset(hc, 0, sizeof(struct sl811_hc));

	hc->rh_status.wPortStatus = USB_PORT_STAT_POWER;
	hc->rh_status.wPortChange = 0;

	hc->active_urbs	= 0;
	INIT_LIST_HEAD(&hc->hc_hcd_list);
	list_add(&hc->hc_hcd_list, &sl811_hcd_list);
	
	init_waitqueue_head(&hc->waitq);
	
	for (i = 0; i < 6; ++i)
		INIT_LIST_HEAD(&hc->urb_list[i]);
	
	hc->cur_list = &hc->iso_list;

	bus = usb_alloc_bus(&sl811_device_operations);
	if (!bus) {
		kfree (hc);
		return NULL;
	}

	hc->bus	= bus;
	bus->bus_name = MODNAME;
	bus->hcpriv = hc;

	return hc;
}

/*
 * This	function De-allocate all resources
 */
static void sl811_release_hc(struct sl811_hc *hc)
{
	PDEBUG(5, "enter");

	/* disconnect all devices */
	if (hc->bus->root_hub)
		usb_disconnect(&hc->bus->root_hub);

	// Stop interrupt handle
	if (hc->irq)
		free_irq(hc->irq, hc);
	hc->irq = 0;

	/* Stop interrupt for sharing, but only, if PatternTest ok */
	if (hc->addr_io) {
		/* Disable Interrupts */
		sl811_write(hc,	SL811_INTR, 0);

		/* Remove all Interrupt events */
		mdelay(2);
		sl811_write(hc,	SL811_INTRSTS, 0xff);
	}

	/* free io regions */
	sl811_release_regions(hc);

	usb_deregister_bus(hc->bus);
	usb_free_bus(hc->bus);

	list_del(&hc->hc_hcd_list);
	INIT_LIST_HEAD(&hc->hc_hcd_list);

	kfree (hc);
}

/*
 * This	function request IO memory regions, request IRQ, and
 * allocate all	other resources.
 *
 * Input: addr_io = first IO address
 *	  data_io = second IO address
 *	  irq =	interrupt number
 *
 * Return: 0 = success or error	condition
 */
static int __devinit sl811_found_hc(int addr_io, int data_io, int irq)
{
	struct sl811_hc *hc;

	PDEBUG(5, "enter");

	hc = sl811_alloc_hc();
	if (!hc)
		return -ENOMEM;

	if (sl811_request_regions (hc, addr_io, data_io, MODNAME)) {
		PDEBUG(1, "ioport %X,%X is in use!", addr_io, data_io);
		sl811_release_hc(hc);
		return -EBUSY;
	}

	if (sl811_reg_test(hc)) {
		PDEBUG(1, "SL811 register test failed!");
		sl811_release_hc(hc);
		return -ENODEV;
	}
	
#ifdef SL811_DEBUG_VERBOSE
	{
	    __u8 u = SL811Read (hci, SL11H_HWREVREG);
	    
	    // Show the hardware revision of chip
	    PDEBUG(1, "SL811 HW: %02Xh", u);
	    switch (u & 0xF0) {
	    case 0x00: PDEBUG(1, "SL11H");		break;
	    case 0x10: PDEBUG(1, "SL811HS rev1.2");	break;
	    case 0x20: PDEBUG(1, "SL811HS rev1.5");	break;
	    default:   PDEBUG(1, "Revision unknown!");
	    }
	}
#endif // SL811_DEBUG_VERBOSE

	sl811_init_irq();

	usb_register_bus(hc->bus);

	if (request_irq(irq, sl811_interrupt, SA_SHIRQ, MODNAME, hc)) {
		PDEBUG(1, "request interrupt %d failed", irq);
		sl811_release_hc(hc);
		return -EBUSY;
	}
	hc->irq	= irq;

	printk(KERN_INFO __FILE__ ": USB SL811 at %x,%x, IRQ %d\n",
		addr_io, data_io, irq);

	sl811_hc_reset(hc);
	sl811_connect_rh(hc);
	
	return 0;
}

/*
 * This	is an init function, and it is the first function being	called
 *
 * Return: 0 = success or error	condition
 */
static int __init sl811_hcd_init(void)
{
	int ret = -ENODEV;
        int count;
	
	PDEBUG(5, "enter");

	info(DRIVER_VERSION " : " DRIVER_DESC);

        // registering some instance
	for (count = 0; count < MAX_CONTROLERS; count++) {
		if (io[count]) {
			ret = sl811_found_hc(io[count], io[count]+OFFSET_DATA_REG, irq[count]);
			if (ret)
				return (ret);
		}
	}

	return ret;
}

/*
 * This	is a cleanup function, and it is called	when module is unloaded.
 */
static void __exit sl811_hcd_cleanup(void)
{
	struct list_head *list = sl811_hcd_list.next;
	struct sl811_hc *hc;

	PDEBUG(5, "enter");

	for (; list != &sl811_hcd_list; ) {
		hc = list_entry(list, struct sl811_hc, hc_hcd_list);
		list = list->next;
		sl811_release_hc(hc);
	}
}

module_init(sl811_hcd_init);
module_exit(sl811_hcd_cleanup);

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);