www.pudn.com > isp1161.rar > hc_isp116x.c


/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*
 * isp1161 USB HCD for Linux Version 0.9.5 (10/28/2001)
 * 
 * requires (includes) hc_simple.[hc] simple generic HCD frontend
 *  
 * Roman Weissgaerber weissg@vienna.at (C) 2001
 *
 * Thanks to Benjamin Herrenschmidt for debugging and the removing of
 * some bugs.
 *
 *-------------------------------------------------------------------------*
 * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 *-------------------------------------------------------------------------*/
/*History*/
/* V 0.9.5  10/28/2001 correct toggle on error */
/*         inw, outw macros; ISOC support */ 
/* V 0.9  remove some bugs, ISOC still missing */
/* V 0.8.1 9/5/2001 mv memcpy of in packet to hc */
/* V 0.8 initial release */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#include 

#undef HC_URB_TIMEOUT
#undef HC_SWITCH_INT
#undef HC_ENABLE_ISOC

#include "hc_isp116x.h"
#include "hc_simple.h"

static int hc_verbose = 1;
static int hc_error_verbose = 0;
static int urb_debug = 0;
 
#include "hc_simple.c"
#include "hc_isp116x_rh.c"


#ifndef CONFIG_ARCH_SITSANG
static int irq = 10;
static int hcport = 0x290;
static int hcport2 = 0x292;
static int wuport = 0x240;
#else
static int irq = SITSANG_USB_HC_IRQ;
static int hcport = 0xf4000290;
static int hcport2 = 0xf4000292;
#endif

MODULE_PARM(hc_verbose,"i");
MODULE_PARM_DESC(hc_verbose,"verbose startup messages, default is 1 (yes)");
MODULE_PARM(hc_error_verbose,"i");
MODULE_PARM_DESC(hc_error_verbose,"verbose error/warning messages, default is 0 (no)");
MODULE_PARM(urb_debug,"i");
MODULE_PARM_DESC(urb_debug,"debug urb messages, default is 0 (no)");

MODULE_PARM(irq,"i");
MODULE_PARM_DESC(irq,"IRQ 3, 10 (default)");
MODULE_PARM(hcport,"i");
MODULE_PARM_DESC(hcport,"ISP116x PORT 0x290");
MODULE_PARM(hcport2,"i");
MODULE_PARM_DESC(hcport2,"ISP116x PORT2 0x292");

static inline void ISP116x_OUTW (int val, int addr) 
{
	outw (val, addr);
	
}

static inline int ISP116x_INW (int addr)
{
	return inw (addr);
	
}

static inline int READ_REG32 (hci_t * hci, int regindex)
{
	
	hcipriv_t * hp = &hci->hp; 
	int val16, val;

	ISP116x_OUTW (regindex, hp->hcport2);

	val16 = ISP116x_INW (hp->hcport);
	val = val16;

	val16 = ISP116x_INW (hp->hcport);
	val += val16 << 16;

	return val;
}

static inline int READ_REG16 (hci_t * hci, int regindex) 
{
	hcipriv_t * hp = &hci->hp; 
	int val = 0;

	ISP116x_OUTW (regindex, hp->hcport2);
	val = ISP116x_INW (hp->hcport);
	
	return val;
}

static inline void READ_REGn16 (hci_t * hci, int regindex, int length, __u8 * buffer)
{

	hcipriv_t * hp = &hci->hp; 
	int i;
	int val = 0;

	ISP116x_OUTW (regindex, hp->hcport2);

	for (i = 0; i < length - 1; i += 2) {
	  
		val = ISP116x_INW (hp->hcport);
		buffer [i] = val;
		buffer [i+1] = val >> 8; 
	}
	if (length & 1) {
		val = ISP116x_INW (hp->hcport);
		buffer [length - 1] = val;
	}
#ifdef DEBUG1
	printk (" READ_REGn16: %d :", length);
	for (i = 0; i < length; i++)
		printk (" %2x", buffer [i]);
	printk("\n");
#endif
}

static inline void WRITE_REG32 (hci_t * hci, unsigned int value, int regindex) 
{

	hcipriv_t * hp = &hci->hp; 

	ISP116x_OUTW (regindex | 0x80, hp->hcport2);

	ISP116x_OUTW (value, hp->hcport);
				
	ISP116x_OUTW (value >> 16, hp->hcport);
}

static inline void WRITE_REG16 (hci_t * hci, unsigned int value, int regindex) 
{
	hcipriv_t * hp = &hci->hp; 

	ISP116x_OUTW (regindex | 0x80, hp->hcport2);
	ISP116x_OUTW (value, hp->hcport);
}

static inline void WRITE_REG0 (hci_t * hci, int regindex) 
{	
	hcipriv_t * hp = &hci->hp; 

	ISP116x_OUTW (regindex | 0x80, hp->hcport2);
}

static inline void WRITE_REGn16 (hci_t * hci, int regindex, int length, __u8 * buffer) 
{

	hcipriv_t * hp = &hci->hp; 
	int i;

	ISP116x_OUTW (regindex | 0x80, hp->hcport2);

	for (i = 0; i < length - 1; i += 2) {
	
		ISP116x_OUTW (buffer [i] + (buffer [i+1] << 8), hp->hcport);
	}
	if (length & 1) {
		ISP116x_OUTW (buffer [length - 1], hp->hcport);
	}
#ifdef DEBUG1
	printk (" WRITE_REGn16: %d :", length);
	for (i = 0; i < length; i++)
		printk (" %2x", buffer [i]);
	printk("\n");
#endif
}

/*-------------------------------------------------------------------------*/
/* tl functions */

static inline void hc_mark_last_trans (hci_t * hci) 
{
	hcipriv_t * hp = &hci->hp; 
	__u8 * ptd = hp->tl;
	
	if (hp->tlp > 0)
		*(ptd + hp->tl_last) |= (1 << 3);
}

static inline void hc_flush_data_cache (hci_t * hci, void * data, int len) 
{}

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)
{
	hcipriv_t * hp = &hci->hp; 
	int last = 0;
	__u8 * ptd = hp->tl;
	int parts = 2;

	/* just send 4 packets of each kind at a frame,
	 * other URBs also want some bandwitdh, and a NACK is cheaper
	 * with less packets */
	
	switch (hci->active_urbs) {
		case 1: parts =  8; break;
		case 2: parts =  6; break;
		case 3: parts =  4; break;
		case 4: parts =  3; break;
		case 5: parts =  2; break;
		default: parts = 2;
	}
	
	if (len > maxps * parts)
			len = maxps * parts; 
	
	if (hp->units_left < ((len + 8 + 3) & ~0x3))
		return -1;
	else
		hp->units_left -= (len + 8 + 3) & ~0x3;

	
	ptd += hp->tlp;
	hp->tl_last = hp->tlp + 3;
	ptd [0] = 0;
	ptd [1] = (toggle << 2) | (1 << 3) | (0xf << 4);
	ptd [2] = maxps;
	ptd [3] = ((maxps >> 8) & 0x3) | (slow << 2) | (last << 3) | (endpoint << 4);
	ptd [4] = len;
	ptd [5] = ((len >> 8) & 0x3) | (pid << 2);
	ptd [6] = address | (format << 7);
        ptd [7] = 0;

        if (pid != PID_IN && len)
               memcpy (ptd + 8, data, len);
    
        hp->tlp += ((len + 8 + 3) & ~0x3);
       
	return len;
}

static inline int hc_parse_trans (hci_t * hci, int * actbytes, void * data, 
			int * cc, int * toggle, int length)
{
	hcipriv_t * hp = &hci->hp; 
	int last = 0;
	int totbytes;
	int pid;
	__u8 *ptd = hp->tl + hp->tlp;


	*cc = (ptd [1] >> 4) & 0xf;
	last = (ptd [3] >> 3) & 0x1;
	*actbytes = ((ptd [1] & 0x3) << 8) | ptd [0];
	totbytes = ((ptd [5] & 0x3) << 8) | ptd [4];
	pid = (ptd [5] >> 2) & 0x3;
	if (*actbytes > length)
		*actbytes = length;
	if (pid == PID_IN && *actbytes)
		memcpy (data, ptd + 8, *actbytes);
	
	*toggle = (ptd [1] >> 2 & 1);
	if (*cc > 0 && *cc < 0xE && *cc != 9)
		*toggle = !*toggle;

	hp->tlp += ((totbytes + 8 + 3) & ~0x3);  
	
	return !last;
}


/*-------------------------------------------------------------------------*/

static void hc_start_int (hci_t * hci)
{
#ifdef HC_SWITCH_INT	
	int mask = SOFITLInt | ATLInt | OPR_Reg;
	WRITE_REG16 (hci, mask, HcuPInterrupt); 
	WRITE_REG16 (hci, mask, HcuPInterruptEnable);
#endif
}	

static void hc_stop_int (hci_t * hci)
{
#ifdef HC_SWITCH_INT
	WRITE_REG16 (hci, 0, HcuPInterruptEnable);
#endif
}

/* an interrupt happens */
static void hc_interrupt (int irq, void * __hci, struct pt_regs * r)
{
	hci_t * hci = __hci;
	hcipriv_t * hp = &hci->hp; 
	int ints_uP, ints = 0, bstat = 0;
	int iso_buffer_index = 0;
/*
#ifdef CONFIG_ARCH_SITSANG      
	if (!(SITSANG_BIPR_RW & SITSANG_BIPR_USB_HC_IRQ))
            return ;
        SITSANG_BIMR_RW &= ~SITSANG_BIMR_USB_HC_IRQ; 
	SITSANG_BIPR_RW = SITSANG_BIPR_USB_HC_IRQ;
#endif
*/        	
	if ((ints_uP = (READ_REG16 (hci, HcuPInterrupt) & READ_REG16 (hci, HcuPInterruptEnable))) == 0) {
		return;
	}
	WRITE_REG16 (hci, ints_uP, HcuPInterrupt);
	if ((ints_uP & OPR_Reg) &&
 		(ints = (READ_REG32 (hci, HcInterruptStatus)))) {

		if (ints & OHCI_INTR_SO) {
			dbg("USB Schedule overrun");
			WRITE_REG32 (hci, OHCI_INTR_SO, HcInterruptEnable);
		}

		if (ints & OHCI_INTR_SF) {
			WRITE_REG32 (hci, OHCI_INTR_SF, HcInterruptEnable);
		}

		WRITE_REG32 (hci, ints, HcInterruptStatus);
		WRITE_REG32 (hci, OHCI_INTR_MIE, HcInterruptEnable);
	}
	hci->frame_number = GET_FRAME_NUMBER (hci);

	bstat = READ_REG16 (hci, HcBufferStatus);
	if (ints_uP & SOFITLInt) {			
		hci->frame_number = GET_FRAME_NUMBER (hci);

#ifdef HC_ENABLE_ISOC
	/* read itl1 first. if there is an buffer overflow HC will stop at itl1 
	   There will be a quirks in sh_done_list if this happens !!!!! */

		if ((bstat & ITL1BufferFull) && (bstat & ITL1BufferDone)) {
			hp->itl1_len = READ_REG16 (hci, HcReadBackITL1Length);
			if (hp->itl1_len > 0) {
				WRITE_REG16 (hci, hp->itl1_len, HcTransferCounter);
				READ_REGn16 (hci, HcITLBufferPort, hp->itl1_len, hp->tl);
				hp->tlp = 0;
				hci->td_array = &hci->i_td_array [1];
				sh_done_list (hci);
			}
			iso_buffer_index = 1;
		}
		if ((bstat & ITL0BufferFull) && (bstat & ITL0BufferDone)) {
			hp->itl0_len = READ_REG16 (hci, HcReadBackITL0Length);
			if (hp->itl0_len > 0) {
				WRITE_REG16 (hci, hp->itl0_len, HcTransferCounter);
				READ_REGn16 (hci, HcITLBufferPort, hp->itl0_len, hp->tl);
				hp->tlp = 0;
				hci->td_array = &hci->i_td_array [0];
				sh_done_list (hci);
			}
			iso_buffer_index = 0;
		}
		hp->tlp = 0;
		hci->td_array = &hci->i_td_array [iso_buffer_index];
		sh_scan_iso_urb_list (hci, &hci->iso_list, hci->frame_number + 1);
		if (hp->tlp >0) {
			WRITE_REG16 (hci, hp->tlp, HcTransferCounter);
			WRITE_REGn16 (hci, HcITLBufferPort, hp->tlp, hp->tl);
                       
		}
#endif
	}

	if (ints_uP & ATLInt) {
		if ((bstat & ATLBufferFull) && (bstat & ATLBufferDone)) {
				if (hp->atl_len > 0) {
				WRITE_REG16 (hci, hp->atl_len, HcTransferCounter);
				READ_REGn16 (hci, HcATLBufferPort, hp->atl_len, hp->tl);
				hp->tlp = 0;
				hci->td_array = &hci->a_td_array;
				sh_done_list (hci);
			}
			hp->tlp = 0;
		}
	}
	if (!hci->td_array->len)
		sh_del_list (hci);
	hci->td_array = &hci->a_td_array;
	bstat = READ_REG16 (hci, HcBufferStatus);
	if (hci->td_array->len == 0 && !(bstat & ATLBufferFull)) {
		hp->units_left = hp->atl_buffer_len;
		hp->tlp = 0;
		sh_schedule_trans (hci);
		hc_mark_last_trans (hci);
		hp->atl_len = hp->tlp;
		if (hp->atl_len > 0) {
			WRITE_REG16 (hci, hp->atl_len, HcTransferCounter);
			WRITE_REGn16 (hci, HcATLBufferPort, hp->atl_len, hp->tl);
			
		}
		
	}
/*
#ifdef CONFIG_ARCH_SITSANG
	SITSANG_BIPR_RW = SITSANG_BIPR_USB_HC_IRQ;
        SITSANG_BIMR_RW |= SITSANG_BIMR_USB_HC_IRQ; 
#endif
*/
}



/*-------------------------------------------------------------------------*
 * HC functions
 *-------------------------------------------------------------------------*/

/* reset the HC and BUS */

static int hc_reset (hci_t * hci)
{
	int timeout = 30;
	 	
	/* Disable HC interrupts */
	WRITE_REG32 (hci, OHCI_INTR_MIE, HcInterruptDisable);

	dbg ("USB HC reset_hc usb-: ctrl = 0x%x ;",
		READ_REG32 (hci, HcControl));

  	/* Reset USB (needed by some controllers) */
	WRITE_REG32 (hci, 0, HcControl);
  
	WRITE_REG0 (hci, HcSoftwareReset);
    	
	/* HC Reset requires max 10 us delay */
	WRITE_REG32 (hci, OHCI_HCR, HcCommandStatus);
	while ((READ_REG32 (hci, HcCommandStatus) & OHCI_HCR) != 0) {
		if (--timeout == 0) {
			err ("USB HC reset timed out!");
			return -1;
		}	
		udelay (1);
	}	 
	return 0;
}

/*-------------------------------------------------------------------------*/

/* Start an host controller, set the BUS operational
 * enable interrupts 
 * connect the virtual root hub */

static int hc_alloc_trans_buffer (hci_t * hci)
{
	hcipriv_t * hp = &hci->hp; 
	int maxlen;

	hp->itl0_len = 0;
	hp->itl1_len = 0;
	hp->atl_len = 0;

	hp->itl_buffer_len = 1024;
	hp->atl_buffer_len = 4096 - 2 * hp->itl_buffer_len; /* 2048 */

	WRITE_REG16 (hci, hp->itl_buffer_len, HcITLBufferLength);
	WRITE_REG16 (hci, hp->atl_buffer_len, HcATLBufferLength); 
	WRITE_REG16 (hci, 
		InterruptPinEnable |
		InterruptPinTrigger |
		InterruptOutputPolarity | 
		DataBusWidth16 | 
		AnalogOCEnable, 
		HcHardwareConfiguration);
	WRITE_REG16 (hci, 0, HcDMAConfiguration);

	maxlen = (hp->itl_buffer_len > hp->atl_buffer_len) ? hp->itl_buffer_len : hp->atl_buffer_len;

	hp->tl = kmalloc (maxlen, GFP_KERNEL);
	
	if (!hp->tl)
		return -ENOMEM;

	memset (hp->tl, 0, maxlen);
	return 0;
}
	
static int hc_start (hci_t * hci)
{
       int uData;
	hcipriv_t * hp = &hci->hp; 
  	__u32 mask;
  	unsigned int fminterval;

  	fminterval = 0x2edf;
	fminterval |= ((((fminterval - 210) * 6) / 7) << 16); 
	WRITE_REG32 (hci, fminterval, HcFmInterval);	
	WRITE_REG32 (hci, 0x628, HcLSThreshold);

	/*start the usb as operational*/
	hp->hc_control = OHCI_USB_OPER;
	WRITE_REG32 (hci, hp->hc_control, HcControl);
	
	/* Choose the interrupts we care about now, others later on demand */
	mask = OHCI_INTR_MIE | 
	OHCI_INTR_SO | 
	OHCI_INTR_SF;

	WRITE_REG32 (hci, mask, HcInterruptEnable);
	WRITE_REG32 (hci, mask, HcInterruptStatus);

	mask = SOFITLInt | ATLInt | OPR_Reg;
#ifdef HC_SWITCH_INT
	mask = 0;
#endif
	WRITE_REG16 (hci, mask, HcuPInterrupt); 
	WRITE_REG16 (hci, mask, HcuPInterruptEnable);

        //Use NPS according to Philip ISA-USB driver demo ,11/20/2002
	uData = READ_REG32(hci,HcRhDescriptorA);
	uData &= ~RH_A_POTPGT;
	uData |= RH_A_NPS;
	uData &= ~RH_A_PSM;
	uData |= ((50/2)<<24);
	WRITE_REG32 (hci,uData,HcRhDescriptorA);
	WRITE_REG32 (hci, RH_HS_LPSC, HcRhStatus);

	// POTPGT delay is bits 24-31, in 2 ms units.
	mdelay ((READ_REG32 (hci, HcRhDescriptorA) >> 23) & 0x1fe);
 
	rh_connect_rh (hci);
	
	return 0;
}


/*-------------------------------------------------------------------------*/

/* allocate HCI */

static hci_t * __devinit hc_alloc_hci (void)
{
	hci_t * hci;
	hcipriv_t * hp; 
	
	struct usb_bus * bus;

	hci = (hci_t *) kmalloc (sizeof (hci_t), GFP_KERNEL);
	if (!hci)
		return NULL;

	memset (hci, 0, sizeof (hci_t));

	hp = &hci->hp;
	
	hp->irq = -1;
	hp->hcport = -1;

 	hci->a_td_array.len = 0;
 	hci->i_td_array[0].len = 0;
 	hci->i_td_array[1].len = 0;
 	hci->td_array = &hci->a_td_array;
 	hci->active_urbs = 0;
 
	INIT_LIST_HEAD (&hci->hci_hcd_list);
	list_add (&hci->hci_hcd_list, &hci_hcd_list);
	init_waitqueue_head (&hci->waitq);

	INIT_LIST_HEAD (&hci->ctrl_list);
	INIT_LIST_HEAD (&hci->bulk_list);
	INIT_LIST_HEAD (&hci->iso_list);
	INIT_LIST_HEAD (&hci->intr_list);
	INIT_LIST_HEAD (&hci->del_list);

	bus = usb_alloc_bus (&hci_device_operations);
	if (!bus) {
		kfree (hci);
		return NULL;
	}

	hci->bus = bus;
	bus->hcpriv = (void *) hci;

	return hci;
} 


/*-------------------------------------------------------------------------*/

/* De-allocate all resources.. */

static void hc_release_hci (hci_t * hci)
{	
	hcipriv_t * hp = &hci->hp; 
	dbg ("USB HC release hci %d", hci->regs);

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

	if (hp->hcport > 0) {
		WRITE_REG16 (hci, 0, HcHardwareConfiguration);
		WRITE_REG16 (hci, 0, HcDMAConfiguration);
		WRITE_REG16 (hci, 0, HcuPInterruptEnable);
	}

//	if (!hci->disabled)
		hc_reset (hci);
	
	if (hp->tl)
		kfree (hp->tl);
 
	if (hp->hcport > 0) {
		release_region (hp->hcport, 2);
		hp->hcport = 0;
	}

	if (hp->hcport2 > 0) {
		release_region (hp->hcport2, 2);
		hp->hcport2 = 0;
	}

	if (hp->irq >= 0) {
		free_irq (hp->irq, hci);
		hp->irq = -1;
	}

	if (hci->bus->busnum >= 0)
		usb_deregister_bus (hci->bus);
	usb_free_bus (hci->bus);

	list_del (&hci->hci_hcd_list);
	INIT_LIST_HEAD (&hci->hci_hcd_list);
       
	kfree (hci);
}

/*-------------------------------------------------------------------------*/

/* Increment the module usage count, start the control thread and
 * return success. */

static int __devinit hc_found_hci (int addr, int addr2, int irq, int dma)
{
	int hcfs;
	hci_t * hci;
	hcipriv_t * hp; 
    
	hci = hc_alloc_hci ();
	if (!hci) {
		return -ENOMEM;
	}

	hp = &hci->hp;
	if (!request_region (addr, 2, "ISP116x USB HOST")) {
		err ("request address %d-%d failed", addr, addr+4);
		hc_release_hci (hci);
		return -EBUSY;	
	}

	hp->hcport = addr;
	if (!request_region (addr2, 2, "ISP116x USB HOST")) {
		err ("request address %d-%d failed", addr, addr+4);
		hc_release_hci (hci);
		return -EBUSY;	
	}

	hp->hcport2 = addr2;
	if ((READ_REG16(hci, HcChipID) & 0xff00) != 0x6100) {
		hc_release_hci (hci);
		return -ENODEV;
	}
	if (hc_reset (hci) < 0) {
		hc_release_hci (hci);
		return -ENODEV;
	}
	if (hc_alloc_trans_buffer (hci)) {
		hc_release_hci (hci);
		return -ENOMEM;
	}
	printk(KERN_INFO __FILE__ ": USB ISP116x at %x/%x,IRQ %d Rev. %x ChipID: %x\n",
		                addr, addr2, irq, READ_REG32(hci, HcRevision), READ_REG16(hci, HcChipID));

	
	/* FIXME this is a second HC reset; why?? */
	WRITE_REG32 (hci, hp->hc_control = OHCI_USB_RESET, HcControl);
	wait_ms (1000);
	
        usb_register_bus (hci->bus);
	
	if (request_irq (irq, hc_interrupt,SA_SHIRQ,"ISP116x", hci) != 0) {
		err ("request interrupt %d failed", irq);
		hc_release_hci (hci);
		return -EBUSY;
	}
	hp->irq = irq;

	if (hc_start (hci) < 0) {
		err ("can't start usb-%x", addr);
		hc_release_hci (hci);
		return -EBUSY;
	}

/*        
	//Enable USB_HC irq report
	SITSANG_BIPR_RW = SITSANG_BIPR_USB_HC_IRQ;
	SITSANG_BIMR_RW |= SITSANG_BIMR_USB_HC_IRQ;
*/
	return 0;
}


/*-------------------------------------------------------------------------*/

static int __init hci_hcd_init (void) 
{
	int ret;

#ifdef CONFIG_ARCH_SITSANG
	unsigned int irq_gpio_pin = 0;

        irq_gpio_pin = IRQ_TO_GPIO_2_80(SITSANG_USB_HC_IRQ);
        GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin);
	set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_RISING_EDGE);
/*		
    	SITSANG_PCR_RW |= SITSANG_PCR_USB_HOST_ON | SITSANG_PCR_PER_ON;
						
	SITSANG_BCR_RW |= SITSANG_BCR_BUS_OPEN | SITSANG_BCR_USB_NDP;
	SITSANG_BCR_RW |= SITSANG_BCR_USB_HC_RESET;	
	mdelay(500);
*/				
	/*Reset the CHIP*/
//	SITSANG_BCR_RW &= ~(SITSANG_BCR_USB_HC_RESET);
//	mdelay(500);

        MSC2 &= 0xffff0000;
        MSC2 |= 0x0000fbc9;

#endif	
	ret = hc_found_hci (hcport, hcport2, irq, 0);
	return ret;
}

/*-------------------------------------------------------------------------*/

static void __exit hci_hcd_cleanup (void) 
{
	struct list_head *  hci_l;
	hci_t * hci;
	for (hci_l = hci_hcd_list.next; hci_l != &hci_hcd_list;) {
		hci = list_entry (hci_l, hci_t, hci_hcd_list);
		hci_l = hci_l->next;
		hc_release_hci(hci);
	}
/*
#ifdef CONFIG_ARCH_SITSANG
        SITSANG_BIMR_RW &= ~SITSANG_BIMR_USB_HC_IRQ; 
	SITSANG_PCR_RW &= ~SITSANG_PCR_USB_HOST_ON;
#endif	
*/
}

module_init (hci_hcd_init);
module_exit (hci_hcd_cleanup);


MODULE_AUTHOR ("Roman Weissgaerber ");
MODULE_DESCRIPTION ("USB ISP116x Host Controller Driver");