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

📄 hc_crisv10.c

📁 usb driver for 2.6.17
💻 C
📖 第 1 页 / 共 5 页
字号:
	TxIsocSB_zout.buf = virt_to_phys(&zout_buffer[0]);	TxIsocSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |				 IO_STATE(USB_SB_command, tt, zout) |				 IO_STATE(USB_SB_command, full, yes) |				 IO_STATE(USB_SB_command, eot, yes) |				 IO_STATE(USB_SB_command, eol, yes));	/* The last isochronous EP descriptor is a dummy. */	for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {		CHECK_ALIGN(&TxIsocEPList[i]);		TxIsocEPList[i].hw_len = 0;		TxIsocEPList[i].command = IO_FIELD(USB_EP_command, epid, i);		TxIsocEPList[i].sub = 0;		TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[i + 1]);	}	CHECK_ALIGN(&TxIsocEPList[i]);	TxIsocEPList[i].hw_len = 0;	/* Must enable the last EP descr to get eof interrupt. */	TxIsocEPList[i].command = (IO_STATE(USB_EP_command, enable, yes) |				   IO_STATE(USB_EP_command, eof, yes) |				   IO_STATE(USB_EP_command, eol, yes) |				   IO_FIELD(USB_EP_command, epid, INVALID_EPID));	TxIsocEPList[i].sub = virt_to_phys(&TxIsocSB_zout);	TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[0]);	*R_DMA_CH8_SUB3_EP = virt_to_phys(&TxIsocEPList[0]);	*R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);	DBFEXIT;}static void etrax_usb_unlink_intr_urb(struct urb *urb){	volatile USB_EP_Desc_t *first_ep;  /* First EP in the list. */	volatile USB_EP_Desc_t *curr_ep;   /* Current EP, the iterator. */	volatile USB_EP_Desc_t *next_ep;   /* The EP after current. */	volatile USB_EP_Desc_t *unlink_ep; /* The one we should remove from the list. */	int epid;	/* Read 8.8.4 in Designer's Reference, "Removing an EP Descriptor from the List". */	DBFENTER;	epid = ((etrax_urb_priv_t *)urb->hcpriv)->epid;	first_ep = &TxIntrEPList[0];	curr_ep = first_ep;	/* Note that this loop removes all EP descriptors with this epid. This assumes	   that all EP descriptors belong to the one and only urb for this epid. */	do {		next_ep = (USB_EP_Desc_t *)phys_to_virt(curr_ep->next);		if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {			dbg_intr("Found EP to unlink for epid %d", epid);			/* This is the one we should unlink. */			unlink_ep = next_ep;			/* Actually unlink the EP from the DMA list. */			curr_ep->next = unlink_ep->next;			/* Wait until the DMA is no longer at this descriptor. */			while (*R_DMA_CH8_SUB2_EP == virt_to_phys(unlink_ep));			/* Now we are free to remove it and its SB descriptor.			   Note that it is assumed here that there is only one sb in the			   sb list for this ep. */			kmem_cache_free(usb_desc_cache, phys_to_virt(unlink_ep->sub));			kmem_cache_free(usb_desc_cache, (USB_EP_Desc_t *)unlink_ep);		}		curr_ep = phys_to_virt(curr_ep->next);	} while (curr_ep != first_ep);        urb->hcpriv = NULL;}void etrax_usb_do_intr_recover(int epid){	USB_EP_Desc_t *first_ep, *tmp_ep;	DBFENTER;	first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP);	tmp_ep = first_ep;	/* What this does is simply to walk the list of interrupt	   ep descriptors and enable those that are disabled. */	do {		if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid &&		    !(tmp_ep->command & IO_MASK(USB_EP_command, enable))) {			tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes);		}		tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next);	} while (tmp_ep != first_ep);	DBFEXIT;}static int etrax_rh_unlink_urb (struct urb *urb){	etrax_hc_t *hc;	DBFENTER;	hc = urb->dev->bus->hcpriv;	if (hc->rh.urb == urb) {		hc->rh.send = 0;		del_timer(&hc->rh.rh_int_timer);	}	DBFEXIT;	return 0;}static void etrax_rh_send_irq(struct urb *urb){	__u16 data = 0;	etrax_hc_t *hc = urb->dev->bus->hcpriv;	DBFENTER;/*  dbg_rh("R_USB_FM_NUMBER   : 0x%08X", *R_USB_FM_NUMBER);  dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING);*/	data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0;	data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0;	*((__u16 *)urb->transfer_buffer) = cpu_to_le16(data);	/* FIXME: Why is actual_length set to 1 when data is 2 bytes?	   Since only 1 byte is used, why not declare data as __u8? */	urb->actual_length = 1;	urb->status = 0;	if (hc->rh.send && urb->complete) {		dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1);		dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2);		urb->complete(urb, NULL);	}	DBFEXIT;}static void etrax_rh_init_int_timer(struct urb *urb){	etrax_hc_t *hc;	DBFENTER;	hc = urb->dev->bus->hcpriv;	hc->rh.interval = urb->interval;	init_timer(&hc->rh.rh_int_timer);	hc->rh.rh_int_timer.function = etrax_rh_int_timer_do;	hc->rh.rh_int_timer.data = (unsigned long)urb;	/* FIXME: Is the jiffies resolution enough? All intervals < 10 ms will be mapped	   to 0, and the rest to the nearest lower 10 ms. */	hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000);	add_timer(&hc->rh.rh_int_timer);	DBFEXIT;}static void etrax_rh_int_timer_do(unsigned long ptr){	struct urb *urb;	etrax_hc_t *hc;	DBFENTER;	urb = (struct urb*)ptr;	hc = urb->dev->bus->hcpriv;	if (hc->rh.send) {		etrax_rh_send_irq(urb);	}	DBFEXIT;}static int etrax_usb_setup_epid(struct urb *urb){	int epid;	char devnum, endpoint, out_traffic, slow;	int maxlen;	unsigned long flags;	DBFENTER;	epid = etrax_usb_lookup_epid(urb);	if ((epid != -1)){		/* An epid that fits this urb has been found. */		DBFEXIT;		return epid;	}	/* We must find and initiate a new epid for this urb. */	epid = etrax_usb_allocate_epid();	if (epid == -1) {		/* Failed to allocate a new epid. */		DBFEXIT;		return epid;	}	/* We now have a new epid to use. Initiate it. */	set_bit(epid, (void *)&epid_usage_bitmask);	devnum = usb_pipedevice(urb->pipe);	endpoint = usb_pipeendpoint(urb->pipe);	slow = usb_pipeslow(urb->pipe);	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));	if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {		/* We want both IN and OUT control traffic to be put on the same EP/SB list. */		out_traffic = 1;	} else {		out_traffic = usb_pipeout(urb->pipe);	}	save_flags(flags);	cli();	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);	nop();	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {		*R_USB_EPT_DATA_ISO = IO_STATE(R_USB_EPT_DATA_ISO, valid, yes) |			/* FIXME: Change any to the actual port? */			IO_STATE(R_USB_EPT_DATA_ISO, port, any) |			IO_FIELD(R_USB_EPT_DATA_ISO, max_len, maxlen) |			IO_FIELD(R_USB_EPT_DATA_ISO, ep, endpoint) |			IO_FIELD(R_USB_EPT_DATA_ISO, dev, devnum);	} else {		*R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) |			IO_FIELD(R_USB_EPT_DATA, low_speed, slow) |			/* FIXME: Change any to the actual port? */			IO_STATE(R_USB_EPT_DATA, port, any) |			IO_FIELD(R_USB_EPT_DATA, max_len, maxlen) |			IO_FIELD(R_USB_EPT_DATA, ep, endpoint) |			IO_FIELD(R_USB_EPT_DATA, dev, devnum);	}	restore_flags(flags);	if (out_traffic) {		set_bit(epid, (void *)&epid_out_traffic);	} else {		clear_bit(epid, (void *)&epid_out_traffic);	}	dbg_epid("Setting up epid %d with devnum %d, endpoint %d and max_len %d (%s)",		 epid, devnum, endpoint, maxlen, out_traffic ? "OUT" : "IN");	DBFEXIT;	return epid;}static void etrax_usb_free_epid(int epid){	unsigned long flags;	DBFENTER;	if (!test_bit(epid, (void *)&epid_usage_bitmask)) {		warn("Trying to free unused epid %d", epid);		DBFEXIT;		return;	}	save_flags(flags);	cli();	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);	nop();	while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold));	/* This will, among other things, set the valid field to 0. */	*R_USB_EPT_DATA = 0;	restore_flags(flags);	clear_bit(epid, (void *)&epid_usage_bitmask);	dbg_epid("Freed epid %d", epid);	DBFEXIT;}static int etrax_usb_lookup_epid(struct urb *urb){	int i;	__u32 data;	char devnum, endpoint, slow, out_traffic;	int maxlen;	unsigned long flags;	DBFENTER;	devnum = usb_pipedevice(urb->pipe);	endpoint = usb_pipeendpoint(urb->pipe);	slow = usb_pipeslow(urb->pipe);	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));	if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {		/* We want both IN and OUT control traffic to be put on the same EP/SB list. */		out_traffic = 1;	} else {		out_traffic = usb_pipeout(urb->pipe);	}	/* Step through att epids. */	for (i = 0; i < NBR_OF_EPIDS; i++) {		if (test_bit(i, (void *)&epid_usage_bitmask) &&		    test_bit(i, (void *)&epid_out_traffic) == out_traffic) {			save_flags(flags);			cli();			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i);			nop();			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {				data = *R_USB_EPT_DATA_ISO;				restore_flags(flags);				if ((IO_MASK(R_USB_EPT_DATA_ISO, valid) & data) &&				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, dev, data) == devnum) &&				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, ep, data) == endpoint) &&				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, max_len, data) == maxlen)) {					dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",						 i, devnum, endpoint, out_traffic ? "OUT" : "IN");					DBFEXIT;					return i;				}			} else {				data = *R_USB_EPT_DATA;				restore_flags(flags);				if ((IO_MASK(R_USB_EPT_DATA, valid) & data) &&				    (IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) &&				    (IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) &&				    (IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) &&				    (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxlen)) {					dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",						 i, devnum, endpoint, out_traffic ? "OUT" : "IN");					DBFEXIT;					return i;				}			}		}	}	DBFEXIT;	return -1;}static int etrax_usb_allocate_epid(void){	int i;	DBFENTER;	for (i = 0; i < NBR_OF_EPIDS; i++) {		if (!test_bit(i, (void *)&epid_usage_bitmask)) {			dbg_epid("Found free epid %d", i);			DBFEXIT;			return i;		}	}	dbg_epid("Found no free epids");	DBFEXIT;	return -1;}static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags){	etrax_hc_t *hc;	int ret = -EINVAL;	DBFENTER;	if (!urb->dev || !urb->dev->bus) {		return -ENODEV;	}	if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) <= 0) {		info("Submit urb to pipe with maxpacketlen 0, pipe 0x%X\n", urb->pipe);		return -EMSGSIZE;	}	if (urb->timeout) {		/* FIXME. */		warn("urb->timeout specified, ignoring.");	}	hc = (etrax_hc_t*)urb->dev->bus->hcpriv;	if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {		/* This request is for the Virtual Root Hub. */		ret = etrax_rh_submit_urb(urb);	} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {		ret = etrax_usb_submit_bulk_urb(urb);	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {		ret = etrax_usb_submit_ctrl_urb(urb);	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {		int bustime;		if (urb->bandwidth == 0) {			bustime = usb_check_bandwidth(urb->dev, urb);			if (bustime < 0) {				ret = bustime;			} else {				ret = etrax_usb_submit_intr_urb(urb);				if (ret == 0)					usb_claim_bandwidth(urb->dev, urb, bustime, 0);			}		} else {			/* Bandwidth already set. */			ret = etrax_usb_submit_intr_urb(urb);		}	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {		int bustime;

⌨️ 快捷键说明

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