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

📄 sl811.c

📁 在LINUX下驱动USB芯片SL811的程序源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		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");//	ctrl_outb(0x41,0xb80080f8);	/* config CF */	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);	    __u8 u = sl811_read (hc, 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/*// Check io area// CN3	ctrl_outb(0x0e, 0xba008000);	printk("address =0xba008000 ");	printk("data High =%x\n", ctrl_inb(0xba008002));//	ctrl_outb(0x0e, 0xba008000);	printk("address =0xba008000 ");	printk("data Low =%x\n", ctrl_inb(0xba008001));// CN4	ctrl_outb(0x0e, 0xba00a000);	printk("address =0xba00a000 ");	printk("data High =%x\n", ctrl_inb(0xba00a002));//	ctrl_outb(0x0e, 0xba00a000);	printk("address =0xba00a000 ");	printk("data Low =%x\n", ctrl_inb(0xba00a001));////check atribute area ???// CN3	ctrl_outb(0x0e, 0xb8008000);	printk("address =0xb8008000 ");	printk("data High =%x\n", ctrl_inb(0xb8008002));//	ctrl_outb(0x0e, 0xb8008000);	printk("address =0xb8008000 ");	printk("data Low =%x\n", ctrl_inb(0xb8008001));// CN4	ctrl_outb(0x0e, 0xb800a000);	printk("address =0xb800a000 ");	printk("data High =%x\n", ctrl_inb(0xb800a002));//	ctrl_outb(0x0e, 0xb800a000);	printk("address =0xb800a000 ");	printk("data Low =%x\n", ctrl_inb(0xb800a001));//check common area ???// CN3	ctrl_outb(0x0e, 0xb8008800);	printk("address =0xb8008800 ");	printk("data High =%x\n", ctrl_inb(0xb8008802));//	ctrl_outb(0x0e, 0xb8008800);	printk("address =0xb8008800 ");	printk("data Low =%x\n", ctrl_inb(0xb8008801));// CN4	ctrl_outb(0x0e, 0xb800a800);	printk("address =0xb800a800 ");	printk("data High =%x\n", ctrl_inb(0xb800a802));//	ctrl_outb(0x0e, 0xb800a800);	printk("address =0xb800a800 ");	printk("data Low =%x\n", ctrl_inb(0xb800a801));*/	sl811_init_irq();	usb_register_bus(hc->bus);	if (request_irq(irq, sl811_interrupt, SA_SHIRQ, MODNAME, hc)) {	

⌨️ 快捷键说明

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