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

📄 dm_usb_isp1362.c

📁 blackfin 的 usb devise 的代码 很基础
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * ISP116x HCD (Host Controller Driver) for USB. * * Derived from the SL811 HCD, rewritten for ISP116x. * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee> * * Portions: * Copyright (C) 2004 Psion Teklogix (for NetBook PRO) * Copyright (C) 2004 David Brownell * * Periodic scheduling is based on Roman's OHCI code * Copyright (C) 1999 Roman Weissgaerber * *//* * The driver basically works. A number of people have used it with a range * of devices. * * The driver passes all usbtests 1-14. * * Suspending/resuming of root hub via sysfs works. Remote wakeup works too. * And suspending/resuming of platform device works too. Suspend/resume * via HCD operations vector is not implemented. * * Iso transfer support is not implemented. Adding this would include * implementing recovery from the failure to service the processed ITL * fifo ram in time, which will involve chip reset. * * TODO: + More testing of suspend/resume.*//*  ISP116x chips require certain delays between accesses to its  registers. The following timing options exist.  1. Configure your memory controller (the best)  2. Implement platform-specific delay function possibly  combined with configuring the memory controller; see  include/linux/usb-isp1362.h for more info. Some broken  memory controllers line LH7A400 SMC need this. Also,  uncomment for that to work the following  USE_PLATFORM_DELAY macro.  3. Use ndelay (easiest, poorest). For that, uncomment  the following USE_NDELAY macro.*/#define USE_PLATFORM_DELAY#include <usb.h>#ifndef DEBUG#	define	STUB_DEBUG_FILE#endif#include "hcd.h"#include "isp1362.h"#define DRIVER_VERSION	"05 Aug 2005"#define DRIVER_DESC	"ISP116x USB Host Controller Driver"static const char hcd_name[] = "isp1362-hcd";/*-----------------------------------------------------------------*//*  Write len bytes to fifo, pad till 32-bit boundary */static void write_ptddata_to_fifo(struct isp1362 *isp1362, void *buf, int len){	u8 *dp = (u8 *) buf;	u16 *dp2 = (u16 *) buf;	u16 w;	int quot = len % 4;	if ((unsigned long)dp2 & 1) {		/* not aligned */		for (; len > 1; len -= 2) {			w = *dp++;			w |= *dp++ << 8;			isp1362_raw_write_data16(isp1362, w);		}		if (len)			isp1362_write_data16(isp1362, (u16) * dp);	} else {		/* aligned */		for (; len > 1; len -= 2)			isp1362_raw_write_data16(isp1362, *dp2++);		if (len)			isp1362_write_data16(isp1362, 0xff & *((u8 *) dp2));	}	if (quot == 1 || quot == 2)		isp1362_raw_write_data16(isp1362, 0);}/*  Read len bytes from fifo and then read till 32-bit boundary. */static void read_ptddata_from_fifo(struct isp1362 *isp1362, void *buf, int len){	u8 *dp = (u8 *) buf;	u16 *dp2 = (u16 *) buf;	u16 w;	int quot = len % 4;	if ((unsigned long)dp2 & 1) {		/* not aligned */		for (; len > 1; len -= 2) {			w = isp1362_raw_read_data16(isp1362);			*dp++ = w & 0xff;			*dp++ = (w >> 8) & 0xff;		}		if (len)			*dp = 0xff & isp1362_read_data16(isp1362);	} else {		/* aligned */		for (; len > 1; len -= 2)			*dp2++ = isp1362_raw_read_data16(isp1362);		if (len)			*(u8 *) dp2 = 0xff & isp1362_read_data16(isp1362);	}	if (quot == 1 || quot == 2)		isp1362_raw_read_data16(isp1362);}/*  Write ptd's and data for scheduled transfers into  the fifo ram. Fifo must be empty and ready.*/static void pack_fifo(struct isp1362 *isp1362){	struct isp1362_ep *ep;	struct ptd *ptd;	int buflen = isp1362->atl_last_dir == PTD_DIR_IN	    ? isp1362->atl_bufshrt : isp1362->atl_buflen;	int ptd_count = 0;	isp1362_write_reg16(isp1362, HCuPINT, HCuPINT_AIIEOT);	isp1362_write_reg16(isp1362, HCXFERCTR, buflen);	isp1362_write_addr(isp1362, HCATLPORT | ISP116x_WRITE_OFFSET);	for (ep = isp1362->atl_active; ep; ep = ep->active) {		++ptd_count;		ptd = &ep->ptd;		dump_ptd(ptd);		dump_ptd_out_data(ptd, ep->data);		isp1362_write_data16(isp1362, ptd->count);		isp1362_write_data16(isp1362, ptd->mps);		isp1362_write_data16(isp1362, ptd->len);		isp1362_write_data16(isp1362, ptd->faddr);		buflen -= sizeof(struct ptd);		/* Skip writing data for last IN PTD */		if (ep->active || (isp1362->atl_last_dir != PTD_DIR_IN)) {			write_ptddata_to_fifo(isp1362, ep->data, ep->length);			buflen -= ALIGN(ep->length, 4);		}	}	BUG_ON(buflen);}/*  Read the processed ptd's and data from fifo ram back to  URBs' buffers. Fifo must be full and done*/static void unpack_fifo(struct isp1362 *isp1362){	struct isp1362_ep *ep;	struct ptd *ptd;	int buflen = isp1362->atl_last_dir == PTD_DIR_IN	    ? isp1362->atl_buflen : isp1362->atl_bufshrt;	isp1362_write_reg16(isp1362, HCuPINT, HCuPINT_AIIEOT);	isp1362_write_reg16(isp1362, HCXFERCTR, buflen);	isp1362_write_addr(isp1362, HCATLPORT);	for (ep = isp1362->atl_active; ep; ep = ep->active) {		ptd = &ep->ptd;		ptd->count = isp1362_read_data16(isp1362);		ptd->mps = isp1362_read_data16(isp1362);		ptd->len = isp1362_read_data16(isp1362);		ptd->faddr = isp1362_read_data16(isp1362);		buflen -= sizeof(struct ptd);		/* Skip reading data for last Setup or Out PTD */		if (ep->active || (isp1362->atl_last_dir == PTD_DIR_IN)) {			read_ptddata_from_fifo(isp1362, ep->data, ep->length);			buflen -= ALIGN(ep->length, 4);		}		dump_ptd(ptd);		dump_ptd_in_data(ptd, ep->data);	}	BUG_ON(buflen);}/*---------------------------------------------------------------*//*  Set up PTD's.*/static void preproc_atl_queue(struct isp1362 *isp1362){	struct isp1362_ep *ep;	struct urb *urb;	struct ptd *ptd;	u16 len;	for (ep = isp1362->atl_active; ep; ep = ep->active) {		u16 toggle = 0, dir = PTD_DIR_SETUP;///		BUG_ON(list_empty(&ep->hep->urb_list));///		urb = container_of(ep->hep->urb_list.next,///				   struct urb, urb_list);		ptd = &ep->ptd;		len = ep->length;///		spin_lock(&urb->lock);///		ep->data = (unsigned char *)urb->transfer_buffer///		    + urb->actual_length;		switch (ep->nextpid) {		case USB_PID_IN:			toggle = usb_gettoggle(urb->dev, ep->epnum, 0);			dir = PTD_DIR_IN;			break;		case USB_PID_OUT:			toggle = usb_gettoggle(urb->dev, ep->epnum, 1);			dir = PTD_DIR_OUT;			break;		case USB_PID_SETUP:			len = sizeof(struct usb_ctrlrequest);			ep->data = urb->setup_packet;			break;		case USB_PID_ACK:			toggle = 1;			len = 0;			dir = (urb->transfer_buffer_length			       && usb_pipein(urb->pipe))			    ? PTD_DIR_OUT : PTD_DIR_IN;			break;		default:			printf("%s %d: ep->nextpid %d\n", __func__, __LINE__,			    ep->nextpid);			BUG();		}		ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK | PTD_TOGGLE(toggle);		ptd->mps = PTD_MPS(ep->maxpacket)		    | PTD_SPD(urb->dev->speed == USB_SPEED_LOW)		    | PTD_EP(ep->epnum);		ptd->len = PTD_LEN(len) | PTD_DIR(dir);		ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe));///		spin_unlock(&urb->lock);		if (!ep->active) {			ptd->mps |= PTD_LAST_MSK;			isp1362->atl_last_dir = dir;		}		isp1362->atl_bufshrt = sizeof(struct ptd) + isp1362->atl_buflen;		isp1362->atl_buflen = isp1362->atl_bufshrt + ALIGN(len, 4);	}}/*  Analyze transfer results, handle partial transfers and errors*/static void postproc_atl_queue(struct isp1362 *isp1362){	struct isp1362_ep *ep;	struct urb *urb;	struct usb_device *udev;	struct ptd *ptd;	int short_not_ok;	u8 cc;	for (ep = isp1362->atl_active; ep; ep = ep->active) {///		BUG_ON(list_empty(&ep->hep->urb_list));///		urb =///		    container_of(ep->hep->urb_list.next, struct urb, urb_list);		udev = urb->dev;		ptd = &ep->ptd;		cc = PTD_GET_CC(ptd);		spin_lock(&urb->lock);		short_not_ok = 1;		/* Data underrun is special. For allowed underrun		   we clear the error and continue as normal. For		   forbidden underrun we finish the DATA stage		   immediately while for control transfer,		   we do a STATUS stage. */		if (cc == TD_DATAUNDERRUN) {			if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) {				DBG("Allowed data underrun\n");				cc = TD_CC_NOERROR;				short_not_ok = 0;			} else {				ep->error_count = 1;				if (usb_pipecontrol(urb->pipe))					ep->nextpid = USB_PID_ACK;				else					usb_settoggle(udev, ep->epnum,						      ep->nextpid ==						      USB_PID_OUT,						      PTD_GET_TOGGLE(ptd));				urb->actual_length += PTD_GET_COUNT(ptd);				urb->status = cc_to_error[TD_DATAUNDERRUN];				spin_unlock(&urb->lock);				continue;			}		}		/* Keep underrun error through the STATUS stage */		if (urb->status == cc_to_error[TD_DATAUNDERRUN])			cc = TD_DATAUNDERRUN;		if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED		    && (++ep->error_count >= 3 || cc == TD_CC_STALL			|| cc == TD_DATAOVERRUN)) {			if (urb->status == -1)				urb->status = cc_to_error[cc];			if (ep->nextpid == USB_PID_ACK)				ep->nextpid = 0;			spin_unlock(&urb->lock);			continue;		}		/* According to usb spec, zero-length Int transfer signals		   finishing of the urb. Hey, does this apply only		   for IN endpoints? */		if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {			if (urb->status == -1)				urb->status = 0;			spin_unlock(&urb->lock);			continue;		}		/* Relax after previously failed, but later succeeded		   or correctly NAK'ed retransmission attempt */		if (ep->error_count		    && (cc == TD_CC_NOERROR || cc == TD_NOTACCESSED))			ep->error_count = 0;		/* Take into account idiosyncracies of the isp1362 chip		   regarding toggle bit for failed transfers */		if (ep->nextpid == USB_PID_OUT)			usb_settoggle(udev, ep->epnum, 1, PTD_GET_TOGGLE(ptd)				      ^ (ep->error_count > 0));		else if (ep->nextpid == USB_PID_IN)			usb_settoggle(udev, ep->epnum, 0, PTD_GET_TOGGLE(ptd)				      ^ (ep->error_count > 0));		switch (ep->nextpid) {		case USB_PID_IN:		case USB_PID_OUT:			urb->actual_length += PTD_GET_COUNT(ptd);			if (PTD_GET_ACTIVE(ptd)			    || (cc != TD_CC_NOERROR && cc < 0x0E))				break;			if (urb->transfer_buffer_length != urb->actual_length) {				if (short_not_ok)					break;			} else {				if (urb->transfer_flags & URB_ZERO_PACKET				    && ep->nextpid == USB_PID_OUT				    && !(PTD_GET_COUNT(ptd) % ep->maxpacket)) {					DBG("Zero packet requested\n");					break;				}			}			/* All data for this URB is transferred, let's finish */			if (usb_pipecontrol(urb->pipe))				ep->nextpid = USB_PID_ACK;			else if (urb->status == -1)				urb->status = 0;			break;		case USB_PID_SETUP:			if (PTD_GET_ACTIVE(ptd)			    || (cc != TD_CC_NOERROR && cc < 0x0E))				break;			if (urb->transfer_buffer_length == urb->actual_length)				ep->nextpid = USB_PID_ACK;			else if (usb_pipeout(urb->pipe)) {				usb_settoggle(udev, 0, 1, 1);				ep->nextpid = USB_PID_OUT;			} else {				usb_settoggle(udev, 0, 0, 1);				ep->nextpid = USB_PID_IN;			}			break;		case USB_PID_ACK:			if (PTD_GET_ACTIVE(ptd)			    || (cc != TD_CC_NOERROR && cc < 0x0E))				break;			if (urb->status == -1)				urb->status = 0;			ep->nextpid = 0;			break;		default:			BUG_ON(1);		}		spin_unlock(&urb->lock);	}}#if 0//motor/*  Take done or failed requests out of schedule. Give back  processed urbs.*/static void finish_request(struct isp1362 *isp1362, struct isp1362_ep *ep,			   struct urb *urb, struct pt_regs *regs)__releases(isp1362->lock) __acquires(isp1362->lock){	unsigned i;	urb->hcpriv = NULL;	ep->error_count = 0;	if (usb_pipecontrol(urb->pipe))		ep->nextpid = USB_PID_SETUP;	urb_dbg(urb, "Finish");	spin_unlock(&isp1362->lock);	usb_hcd_giveback_urb(isp1362_to_hcd(isp1362), urb, regs);	spin_lock(&isp1362->lock);	/* take idle endpoints out of the schedule */	if (!list_empty(&ep->hep->urb_list))		return;	/* async deschedule */	if (!list_empty(&ep->schedule)) {		list_del_init(&ep->schedule);		return;	}	/* periodic deschedule */	DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);	for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {		struct isp1362_ep *temp;		struct isp1362_ep **prev = &isp1362->periodic[i];		while (*prev && ((temp = *prev) != ep))			prev = &temp->next;		if (*prev)			*prev = ep->next;		isp1362->load[i] -= ep->load;	}	ep->branch = PERIODIC_SIZE;	isp1362_to_hcd(isp1362)->self.bandwidth_allocated -=	    ep->load / ep->period;	/* switch irq type? */	if (!--isp1362->periodic_count) {		isp1362->irqenb &= ~HCuPINT_SOF;		isp1362->irqenb |= HCuPINT_ATL;	}}/*  Scan transfer lists, schedule transfers, send data off  to chip. */static void start_atl_transfers(struct isp1362 *isp1362){	struct isp1362_ep *last_ep = NULL, *ep;	struct urb *urb;	u16 load = 0;

⌨️ 快捷键说明

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