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

📄 usbdev.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	list = &ep->inlist;	if (!async && list->count) {		halt_dma(ep->indma);		flush_pkt_list(list);	}	link_tail(ep, list, pkt);	vdbg("%s: ep%d, pkt=%p, size=%d, list count=%d", __FUNCTION__,	     ep->address, pkt, pkt->size, list->count);	if (list->count == 1) {		/*		 * if the packet count is one, it means the list was empty,		 * and no more data will go out this ep until we kick-start		 * it again.		 */		kickstart_send_packet(ep);	}	return pkt->size;}/* * This routine is called to restart reception of a packet. * EP spinlock must be held when calling. */static voidkickstart_receive_packet(endpoint_t * ep){	usbdev_pkt_t *pkt;	// get and link a new packet for next reception	if (!(pkt = add_packet(ep, &ep->outlist, ep->max_pkt_size))) {		err("%s: could not alloc new packet", __FUNCTION__);		return;	}	if (get_dma_active_buffer(ep->outdma) == 1) {		clear_dma_done1(ep->outdma);		set_dma_count1(ep->outdma, ep->max_pkt_size);		set_dma_count0(ep->outdma, 0);		set_dma_addr1(ep->outdma, virt_to_phys(pkt->payload));		enable_dma_buffer1(ep->outdma);	// reenable	} else {		clear_dma_done0(ep->outdma);		set_dma_count0(ep->outdma, ep->max_pkt_size);		set_dma_count1(ep->outdma, 0);		set_dma_addr0(ep->outdma, virt_to_phys(pkt->payload));		enable_dma_buffer0(ep->outdma);	// reenable	}	if (dma_halted(ep->outdma))		start_dma(ep->outdma);}/* * This routine is called when a packet in the outlist has been * completed (received) and we need to prepare for a new packet * to be received. Halts DMA and computes the packet size from the * remaining DMA counter. Then prepares a new packet for reception * and restarts DMA. FIXME: what if another packet comes in * on top of the completed packet? Counter would be wrong. * EP spinlock must be held when calling. */static usbdev_pkt_t *receive_packet_complete(endpoint_t * ep){	usbdev_pkt_t *pkt = ep->outlist.tail;	u32 cs;	halt_dma(ep->outdma);	cs = au_readl(ep->reg->ctrl_stat);	if (!pkt)		return NULL;	pkt->size = ep->max_pkt_size - get_dma_residue(ep->outdma);	if (pkt->size)		dma_cache_inv((unsigned long)pkt->payload, pkt->size);	/*	 * need to pull out any remaining bytes in the FIFO.	 */	endpoint_fifo_read(ep);	/*	 * should be drained now, but flush anyway just in case.	 */	flush_read_fifo(ep);	pkt->status = (cs & USBDEV_CS_NAK) ? PKT_STATUS_NAK : PKT_STATUS_ACK;	if (ep->address == 0 && (cs & USBDEV_CS_SU))		pkt->status |= PKT_STATUS_SU;	vdbg("%s: ep%d, %s pkt=%p, size=%d", __FUNCTION__,	     ep->address, (pkt->status & PKT_STATUS_NAK) ?	     "NAK" : "ACK", pkt, pkt->size);	kickstart_receive_packet(ep);	return pkt;}/* **************************************************************************** * Here starts the standard device request handlers. They are * all called by do_setup() via a table of function pointers. **************************************************************************** */static ep0_stage_tdo_get_status(struct usb_dev* dev, struct usb_ctrlrequest* setup){	switch (setup->bRequestType) {	case 0x80:	// Device		// FIXME: send device status		break;	case 0x81:	// Interface		// FIXME: send interface status		break;	case 0x82:	// End Point		// FIXME: send endpoint status		break;	default:		// Invalid Command		endpoint_stall(&dev->ep[0]); // Stall End Point 0		break;	}	return STATUS_STAGE;}static ep0_stage_tdo_clear_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup){	switch (setup->bRequestType) {	case 0x00:	// Device		if ((le16_to_cpu(setup->wValue) & 0xff) == 1)			dev->remote_wakeup_en = 0;	else			endpoint_stall(&dev->ep[0]);		break;	case 0x02:	// End Point		if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {			endpoint_t *ep =				epaddr_to_ep(dev,					     le16_to_cpu(setup->wIndex) & 0xff);			endpoint_unstall(ep);			endpoint_reset_datatoggle(ep);		} else			endpoint_stall(&dev->ep[0]);		break;	}	return SETUP_STAGE;}static ep0_stage_tdo_reserved(struct usb_dev* dev, struct usb_ctrlrequest* setup){	// Invalid request, stall End Point 0	endpoint_stall(&dev->ep[0]);	return SETUP_STAGE;}static ep0_stage_tdo_set_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup){	switch (setup->bRequestType) {	case 0x00:	// Device		if ((le16_to_cpu(setup->wValue) & 0xff) == 1)			dev->remote_wakeup_en = 1;		else			endpoint_stall(&dev->ep[0]);		break;	case 0x02:	// End Point		if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {			endpoint_t *ep =				epaddr_to_ep(dev,					     le16_to_cpu(setup->wIndex) & 0xff);			endpoint_stall(ep);		} else			endpoint_stall(&dev->ep[0]);		break;	}	return SETUP_STAGE;}static ep0_stage_tdo_set_address(struct usb_dev* dev, struct usb_ctrlrequest* setup){	int new_state = dev->state;	int new_addr = le16_to_cpu(setup->wValue);	dbg("%s: our address=%d", __FUNCTION__, new_addr);	if (new_addr > 127) {			// usb spec doesn't tell us what to do, so just go to			// default state		new_state = DEFAULT;		dev->address = 0;	} else if (dev->address != new_addr) {		dev->address = new_addr;		new_state = ADDRESS;	}	if (dev->state != new_state) {		dev->state = new_state;		/* inform function layer of usbdev state change */		dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);	}	return SETUP_STAGE;}static ep0_stage_tdo_get_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup){	int strnum, desc_len = le16_to_cpu(setup->wLength);		switch (le16_to_cpu(setup->wValue) >> 8) {		case USB_DT_DEVICE:			// send device descriptor!		desc_len = desc_len > dev->dev_desc->bLength ?			dev->dev_desc->bLength : desc_len;			dbg("sending device desc, size=%d", desc_len);		send_packet(dev, alloc_packet(&dev->ep[0], desc_len,					      dev->dev_desc), 0);			break;		case USB_DT_CONFIG:			// If the config descr index in low-byte of			// setup->wValue	is valid, send config descr,			// otherwise stall ep0.			if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {				// send config descriptor!				if (desc_len <= USB_DT_CONFIG_SIZE) {					dbg("sending partial config desc, size=%d",					     desc_len);				send_packet(dev,					    alloc_packet(&dev->ep[0],							 desc_len,							 dev->conf_desc),					    0);				} else {				int len = le16_to_cpu(dev->conf_desc->wTotalLength);				dbg("sending whole config desc,"				    " size=%d, our size=%d", desc_len, len);				desc_len = desc_len > len ? len : desc_len;				send_packet(dev,					    alloc_packet(&dev->ep[0],							 desc_len,							 dev->full_conf_desc),					    0);				}			} else			endpoint_stall(&dev->ep[0]);			break;		case USB_DT_STRING:			// If the string descr index in low-byte of setup->wValue			// is valid, send string descr, otherwise stall ep0.			strnum = le16_to_cpu(setup->wValue) & 0xff;			if (strnum >= 0 && strnum < 6) {				struct usb_string_descriptor *desc =				dev->str_desc[strnum];				desc_len = desc_len > desc->bLength ?					desc->bLength : desc_len;				dbg("sending string desc %d", strnum);			send_packet(dev,				    alloc_packet(&dev->ep[0], desc_len,						 desc), 0);			} else			endpoint_stall(&dev->ep[0]);			break;	default:		// Invalid request		err("invalid get desc=%d, stalled",			    le16_to_cpu(setup->wValue) >> 8);		endpoint_stall(&dev->ep[0]);	// Stall endpoint 0			break;		}	return STATUS_STAGE;}static ep0_stage_tdo_set_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup){	// TODO: implement	// there will be an OUT data stage (the descriptor to set)	return DATA_STAGE;}static ep0_stage_tdo_get_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup){	// send dev->configuration	dbg("sending config");	send_packet(dev, alloc_packet(&dev->ep[0], 1, &dev->configuration),		    0);	return STATUS_STAGE;}static ep0_stage_tdo_set_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup){	// set active config to low-byte of setup->wValue	dev->configuration = le16_to_cpu(setup->wValue) & 0xff;	dbg("set config, config=%d", dev->configuration);	if (!dev->configuration && dev->state > DEFAULT) {		dev->state = ADDRESS;		/* inform function layer of usbdev state change */		dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);	} else if (dev->configuration == 1) {		dev->state = CONFIGURED;		/* inform function layer of usbdev state change */		dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);	} else {		// FIXME: "respond with request error" - how?	}	return SETUP_STAGE;}static ep0_stage_tdo_get_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup){		// interface must be zero.	if ((le16_to_cpu(setup->wIndex) & 0xff) || dev->state == ADDRESS) {			// FIXME: respond with "request error". how?	} else if (dev->state == CONFIGURED) {		// send dev->alternate_setting			dbg("sending alt setting");		send_packet(dev, alloc_packet(&dev->ep[0], 1,					      &dev->alternate_setting), 0);		}	return STATUS_STAGE;}static ep0_stage_tdo_set_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup){	if (dev->state == ADDRESS) {			// FIXME: respond with "request error". how?	} else if (dev->state == CONFIGURED) {		dev->interface = le16_to_cpu(setup->wIndex) & 0xff;		dev->alternate_setting =			    le16_to_cpu(setup->wValue) & 0xff;			// interface and alternate_setting must be zero		if (dev->interface || dev->alternate_setting) {				// FIXME: respond with "request error". how?			}		}	return SETUP_STAGE;}static ep0_stage_tdo_synch_frame(struct usb_dev* dev, struct usb_ctrlrequest* setup){	// TODO	return SETUP_STAGE;}typedef ep0_stage_t (*req_method_t)(struct usb_dev* dev,				    struct usb_ctrlrequest* setup);/* Table of the standard device request handlers */static const req_method_t req_method[] = {	do_get_status,	do_clear_feature,	do_reserved,	do_set_feature,	do_reserved,	do_set_address,	do_get_descriptor,	do_set_descriptor,	do_get_configuration,	do_set_configuration,	do_get_interface,	do_set_interface,	do_synch_frame};// SETUP packet request dispatcherstatic voiddo_setup (struct usb_dev* dev, struct usb_ctrlrequest* setup){	req_method_t m;	dbg("%s: req %d %s", __FUNCTION__, setup->bRequestType,	    get_std_req_name(setup->bRequestType));	if ((setup->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD ||	    (setup->bRequestType & USB_RECIP_MASK) != USB_RECIP_DEVICE) {		err("%s: invalid requesttype 0x%02x", __FUNCTION__,		    setup->bRequestType);		return;		}	if ((setup->bRequestType & 0x80) == USB_DIR_OUT && setup->wLength)		dbg("%s: OUT phase! length=%d", __FUNCTION__, setup->wLength);	if (setup->bRequestType < sizeof(req_method)/sizeof(req_method_t))		m = req_method[setup->bRequestType];			else		m = do_reserved;	dev->ep0_stage = (*m)(dev, setup);}/* * A SETUP, DATA0, or DATA1 packet has been received * on the default control endpoint's fifo. */static voidprocess_ep0_receive (struct usb_dev* dev){	endpoint_t *ep0 = &dev->ep[0];	usbdev_pkt_t *pkt;	spin_lock(&ep0->lock);		// complete packet and prepare a new packet	pkt = receive_packet_complete(ep0);	if (!pkt) {		// FIXME: should  put a warn/err here.		spin_unlock(&ep0->lock);			return;		}	// unlink immediately from endpoint.	unlink_head(&ep0->outlist);	// override current stage if h/w says it's a setup packet	if (pkt->status & PKT_STATUS_SU)		dev->ep0_stage = SETUP_STAGE;	switch (dev->ep0_stage) {	case SETUP_STAGE:		vdbg("SU bit is %s in setup stage",		     (pkt->status & PKT_STATUS_SU) ? "set" : "not set");			if (pkt->size == sizeof(struct usb_ctrlrequest)) {#ifdef VDEBUG			if (pkt->status & PKT_STATUS_ACK)				vdbg("received SETUP");				else				vdbg("received NAK SETUP");#endif			do_setup(dev, (struct usb_ctrlrequest*)pkt->payload);		} else			err("%s: wrong size SETUP received", __FUNCTION__);		break;	case DATA_STAGE:		/*		 * this setup has an OUT data stage. Of the standard		 * device requests, only set_descriptor has this stage,		 * so this packet is that descriptor. TODO: drop it for		 * now, set_descriptor not implemented.		 *		 * Need to place a byte in the write FIFO here, to prepare		 * to send a zero-length DATA ack packet to the host in the		 * STATUS stage.		 */		au_writel(0, ep0->reg->write_fifo);		dbg("received OUT stage DATAx on EP0, size=%d", pkt->size);		dev->ep0_stage = SETUP_STAGE;		break;	case STATUS_STAGE:		// this setup had an IN data stage, and host is ACK'ing		// the packet we sent during that stage.		if (pkt->size != 0)			warn("received non-zero ACK on EP0??");#ifdef VDEBUG		else			vdbg("received ACK on EP0");#endif		dev->ep0_stage = SETUP_STAGE;		break;	}	spin_unlock(&ep0->lock);	// we're done processing the packet, free it	kfree(pkt);}/* * A DATA0/1 packet has been received on one of the OUT endpoints (4 or 5) */static voidprocess_ep_receive (struct usb_dev* dev, endpoint_t *ep){	usbdev_pkt_t *pkt;		spin_lock(&ep->lock);	pkt = receive_packet_complete(ep);		spin_unlock(&ep->lock);	dev->func_cb(CB_PKT_COMPLETE, (unsigned long)pkt, dev->cb_data);}/* This ISR handles the receive complete and suspend events */static voidreq_sus_intr (int irq, void *dev_id, struct pt_regs *regs){	struct usb_dev *dev = (struct usb_dev *) dev_id;	u32 status;

⌨️ 快捷键说明

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