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

📄 hc_isp116x.c

📁 飞利浦isp1161 arm-linux驱动源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*-------------------------------------------------------------------------*//*-------------------------------------------------------------------------* * 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 <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/malloc.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 <asm/irq.h>#include <linux/usb.h>#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_SITSANGstatic int irq = 10;static int hcport = 0x290;static int hcport2 = 0x292;static int wuport = 0x240;#elsestatic int irq = SITSANG_USB_HC_IRQ;static int hcport = 0xf4000290;static int hcport2 = 0xf4000292;#endifMODULE_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);

⌨️ 快捷键说明

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