⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hc_isp116x.c

📁 S3C2440ARM9开发板的USB驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* * --------------------------------------------------------------------------- * ISP116x driver */static inline void REG_DELAY(void){	/* The sepcs of the ISP1611 controller require a 300ns delay	 * between writing the command register and writing another.	 * The following is overkill, but will do until I come up with	 * a better way. */	udelay(1);}static inline u32 READ_REG32 (hci_t * hci, int regindex){	hcipriv_t * hp = &hci->hp; 	u32 val16, val;	writew (regindex, hp->hcvirtual + 2);	REG_DELAY();	val16 = readw (hp->hcvirtual);	val = val16;	val16 = readw (hp->hcvirtual);	val |= val16 << 16;	return val;}static inline u16 READ_REG16 (hci_t * hci, int regindex) {	hcipriv_t * hp = &hci->hp; 	writew (regindex, hp->hcvirtual + 2);	REG_DELAY();	return readw (hp->hcvirtual);}static inline void READ_REGn16 (hci_t * hci, int regindex, int length, __u8 * buffer){	hcipriv_t * hp = &hci->hp; 	int i;	unsigned int val = 0;	writew (regindex, hp->hcvirtual + 2);	REG_DELAY();	for (i = 0; i < length; i += 2) {		val = readw (hp->hcvirtual);		buffer [i] = val;		buffer [i+1] = val >> 8; 	}	if (length & 1) {		val = readw (hp->hcvirtual);		buffer [length - 1] = val;	}}static inline void WRITE_REG32 (hci_t * hci, u32 value, int regindex) {	hcipriv_t * hp = &hci->hp; 	writew (regindex | 0x80, hp->hcvirtual + 2);	REG_DELAY();	writew (value, hp->hcvirtual);	writew (value >> 16, hp->hcvirtual);}static inline void WRITE_REG16 (hci_t * hci, u16 value, int regindex) {	hcipriv_t * hp = &hci->hp; 	writew (regindex | 0x80, hp->hcvirtual + 2);	REG_DELAY();	writew (value, hp->hcvirtual);}static inline void WRITE_REGn16 (hci_t * hci, int regindex, int length, __u8 * buffer) {	hcipriv_t * hp = &hci->hp; 	int i;	writew (regindex | 0x80, hp->hcvirtual + 2);	REG_DELAY();	for (i = 0; i < length; i+=2) {		writew (buffer [i] + (buffer [i+1] << 8), hp->hcvirtual);	}	if (length & 1) {		writew (buffer [length - 1], hp->hcvirtual);	}}/*-------------------------------------------------------------------------*//* 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 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;	/* just send 4 packets of each kind at a frame,	 * other URBs also want some bandwitdh, and a NACK is cheaper	 * with less packets */	if (len > maxps * 1)			len = maxps * 1; 		if (hp->units_left < len + 8)		return 0;	else		hp->units_left -= len + 8;		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;    	memcpy (ptd + 8, data, len);	hp->tlp += ((len + 8 + 3) & ~0x3);	return 1;}static inline int hc_parse_trans (hci_t * hci, int * actbytes, void ** data, 			int * cc, int * toggle){	hcipriv_t * hp = &hci->hp; 	int last = 0;	int totbytes;	__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];	*data = ptd + 8;	*toggle = !(ptd [1] >> 2 & 1);	hp->tlp += ((totbytes + 8 + 3) & ~0x3);  		return !last;}/*-------------------------------------------------------------------------*//*static void hc_start_list (hci_t * hci, ed_t * ed){	hcipriv_t * hp = hci->hcipriv;	int units_left = hp->atl_buffer_len;		switch (usb_pipetype (ed->pipe)) {	case PIPE_CONTROL:	case PIPE_BULK:	case PIPE_INTERRUPT:		if (hp->atl_len == 0) {			hp->tlp = 0;			sh_schedule_trans (hci, TR_INTR | TR_CTRL | TR_BULK, &units_left);			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);			}		}	}}	*//* 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;	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);	}	bstat = READ_REG16 (hci, HcBufferStatus);	if (ints_uP & SOFITLInt) {		}	hci->frame_no = GET_FRAME_NUMBER (hci);#ifdef DEBUG	if (hci->frame_no == 0) 		printk("*** INTERRUPT frame %u intuP %x ints %x bstat %x \n", hci->frame_no, ints_uP, ints, bstat);#endif	if (ints_uP & ATLInt) {		dbg("int2 %x %x bstat %x\n", ints_uP, ints, bstat);		if ((bstat & ATLBufferFull) && (bstat & ATLBufferDone)) {			if (hp->atl_len > 0) {				READ_REGn16 (hci, HcATLBufferPort, hp->atl_len, hp->tl);				hp->tlp = 0;				sh_done_list (hci);			}			hp->tlp = 0;			hci->trans = 0;		}	}	sh_del_list (hci);	if (hci->trans == 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);		}			}}/*-------------------------------------------------------------------------* * 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_REG16 (hci, 0xf6, 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;	if (!hp->tl)		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){	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 controller operations */ 	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;	WRITE_REG16 (hci, mask, HcuPInterrupt); 	WRITE_REG16 (hci, mask, HcuPInterruptEnable);#ifdef	OHCI_USE_NPS	WRITE_REG32 ((READ_REG32 (hci, HcRhDescriptorA) | RH_A_NPS) & ~RH_A_PSM,		HcRhDescriptorA);	WRITE_REG32 (hci, RH_HS_LPSC, HcRhStatus);#endif	/* OHCI_USE_NPS */	// 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 = 0;	hp->hcvirtual = 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->bus_name = "isp116x";	bus->hcpriv = (void *) hci;	return hci;} /*-------------------------------------------------------------------------*//* De-allocate all resources.. */static void hc_release_hci (hci_t * hci){		hcipriv_t * hp = &hci->hp; 	/* 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);	}	hc_reset (hci);		if (hp->tl)		kfree (hp->tl);	if (hp->hcvirtual) {		iounmap(hp->hcvirtual);		hp->hcvirtual = 0;	}			if (hp->hcport > 0) {		release_mem_region (hp->hcport, 4);		hp->hcport = 0;	}	if (hp->irq >= 0) {		free_irq (hp->irq, hci);		hp->irq = -1;	}	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 irq, int dma){	hci_t * hci;	hcipriv_t * hp; 	printk("hc_found_hci: addr=%x\n", addr);	hci = hc_alloc_hci ();	if (!hci) {		return -ENOMEM;	}	hp = &hci->hp;		if (!request_mem_region (addr, 4, "ISP116x USB HOST")) {		err ("request address %d-%d failed", addr, addr+4);		hc_release_hci (hci);		return -EBUSY;		}	hp->hcport = addr;	hp->hcvirtual = ioremap(addr, 4);	if (! hp->hcvirtual) {		err("ioremap() failed");		hc_release_hci(hci);		return -EBUSY;	}	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 IRQ %d Rev. %x ChipID: %x\n",		addr, 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, 0,			"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;	}	pm_hci = hci;	return 0;}/*-------------------------------------------------------------------------*/static int __init hci_hcd_init (void) {	int ret;	ret = hc_found_hci(hcport, irq, 0);   #ifdef CONFIG_ARCTIC2 /* MVL-CEE */        hc_isp_ldm_register();#endif                /* MVL-CEE */	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_ARCTIC2 /* MVL-CEE */       hc_isp_ldm_unregister();#endif                /* MVL-CEE */}module_init (hci_hcd_init);module_exit (hci_hcd_cleanup);MODULE_AUTHOR ("Roman Weissgaerber <weissg@vienna.at>");MODULE_DESCRIPTION ("USB ISP116x Host Controller Driver");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -