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

📄 usbdev.c

📁 microwindows移植到S3C44B0的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
static voidendpoint_reset_datatoggle(endpoint_t * ep){	// FIXME: is this possible?}#ifdef USBDEV_PIOstatic intendpoint_fifo_read(endpoint_t * ep){	unsigned long flags;	int read_count = 0;	u8 *bufptr;	pkt_t *pkt = ep->outlist.tail;	if (!pkt)		return -EINVAL;	spin_lock_irqsave(&ep->lock, flags);	bufptr = pkt->bufptr;	while (inl(ep->reg->read_fifo_status) & USBDEV_FSTAT_FCNT_MASK) {		*bufptr++ = inl(ep->reg->read_fifo) & 0xff;		read_count++;		pkt->size++;	}	pkt->bufptr = bufptr;	spin_unlock_irqrestore(&ep->lock, flags);	return read_count;}static intendpoint_fifo_write(endpoint_t * ep){	unsigned long flags;	int write_count = 0;	u8 *bufptr;	pkt_t *pkt = ep->inlist.head;	if (!pkt)		return -EINVAL;	spin_lock_irqsave(&ep->lock, flags);	bufptr = pkt->bufptr;	while ((inl(ep->reg->write_fifo_status) & USBDEV_FSTAT_FCNT_MASK) <	       EP_FIFO_DEPTH) {		if (bufptr < pkt->buf + pkt->size) {			outl_sync(*bufptr++, ep->reg->write_fifo);			write_count++;		} else {			break;		}	}	pkt->bufptr = bufptr;	spin_unlock_irqrestore(&ep->lock, flags);	return write_count;}#endif				// USBDEV_PIO/* * This routine is called to restart transmission of a packet. * The endpoint's TSIZE must be set to the new packet's size, * and DMA to the write FIFO needs to be restarted. */static voidkickstart_send_packet(endpoint_t * ep){	u32 cs;	pkt_t *pkt = ep->inlist.head;	dbg(__FUNCTION__ ": pkt=%p", pkt);	if (!pkt)		return;	/*	 * The write fifo should already be drained if things are	 * working right, but flush it anyway just in case.	 */	flush_write_fifo(ep);	cs = inl(ep->reg->ctrl_stat) & USBDEV_CS_STALL;	cs |= (pkt->size << USBDEV_CS_TSIZE_BIT);	outl_sync(cs, ep->reg->ctrl_stat);#ifdef USBDEV_PIO	endpoint_fifo_write(ep);#else	disable_dma(ep->indma);	if (get_dma_active_buffer(ep->indma)) {		set_dma_count1(ep->indma, pkt->size);		set_dma_addr1(ep->indma, virt_to_phys(pkt->bufptr));		enable_dma_buffer1(ep->indma);	// reenable	} else {		set_dma_count0(ep->indma, pkt->size);		set_dma_addr0(ep->indma, virt_to_phys(pkt->bufptr));		enable_dma_buffer0(ep->indma);	// reenable	}	enable_dma(ep->indma);#endif}/* * This routine is called when a packet in the inlist has been * completed. Frees the completed packet and starts sending the * next. */static voidsend_packet_complete(endpoint_t * ep){	if (ep->inlist.head)		dbg(__FUNCTION__ ": pkt=%p, ab=%d",		    ep->inlist.head, get_dma_active_buffer(ep->indma));	outl_sync(inl(ep->reg->ctrl_stat) & USBDEV_CS_STALL,		  ep->reg->ctrl_stat);	//disable_dma(ep->indma);	free_packet(ep, &ep->inlist);	// begin transmitting next packet in the inlist	if (ep->inlist.count)		kickstart_send_packet(ep);}/* * Unlink and return a packet from the head of the given ep's packet * outlist. It is the responsibility of the caller to free the packet. * The receive complete interrupt adds packets to the tail of this list.  */static pkt_t *receive_packet(endpoint_t * ep){	pkt_t *pkt = unlink_packet(ep, &ep->outlist);	//dma_cache_inv((unsigned long)pkt->buf, pkt->size);	return pkt;}/* * This routine is called to restart reception of a packet. */static voidkickstart_receive_packet(endpoint_t * ep){	pkt_t *pkt;	// get and link a new packet for next reception	if (!(pkt = add_packet(ep, &ep->outlist, ep->max_pkt_size))) {		err(__FUNCTION__ ": could not alloc new packet");		return;	}	/*	 * The read fifo should already be drained if things are	 * working right, but flush it anyway just in case.	 */	flush_read_fifo(ep);#ifndef USBDEV_PIO	if (get_dma_active_buffer(ep->outdma)) {		set_dma_count1(ep->outdma, ep->max_pkt_size);		set_dma_addr1(ep->outdma, virt_to_phys(pkt->bufptr));		enable_dma_buffer1(ep->outdma);	// reenable	} else {		set_dma_count0(ep->outdma, ep->max_pkt_size);		set_dma_addr0(ep->outdma, virt_to_phys(pkt->bufptr));		enable_dma_buffer0(ep->outdma);	// reenable	}	enable_dma(ep->outdma);#endif}/* * 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. */static voidreceive_packet_complete(endpoint_t * ep){	pkt_t *pkt = ep->outlist.tail;	if (!pkt)		return;	disable_dma(ep->outdma);	pkt->size = ep->max_pkt_size - get_dma_residue(ep->outdma);#ifdef USBDEV_PIO	pkt->bufptr = pkt->buf;	// reset bufptr#endif	dbg(__FUNCTION__ ": size=%d", pkt->size);	kickstart_receive_packet(ep);}/* * Add a new packet to the tail of the given ep's packet * inlist. The transmit complete interrupt frees packets from * the head of this list. */static intsend_packet(endpoint_t * ep, u8 * data, int data_len, int from_user){	unsigned long flags;	pkt_list_t *list = &ep->inlist;	pkt_t *pkt;	if (!data || !data_len)		return 0;	if (!(pkt = alloc_packet(data_len))) {		err(__FUNCTION__ ": could not alloc new packet");		return -ENOMEM;	}	if (from_user)		copy_from_user(pkt->bufptr, data, data_len);	else		memcpy(pkt->bufptr, data, data_len);	au_sync();	//dma_cache_wback_inv((unsigned long)pkt->buf, data_len);	link_packet(ep, list, pkt);	spin_lock_irqsave(&ep->lock, flags);	dbg(__FUNCTION__ ": size=%d, list count=%d", 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);	}	spin_unlock_irqrestore(&ep->lock, flags);	return data_len;}// SETUP packet request parserstatic voidprocess_setup (struct usb_serial* serial, devrequest* setup){	int desc_len, strnum;	dbg(__FUNCTION__ ": req %d", setup->request);	switch (setup->request) {	case USB_REQ_SET_ADDRESS:		serial->address = le16_to_cpu(setup->value);		dbg(__FUNCTION__ ": our address=%d", serial->address);		if (serial->address > 127 || serial->state == CONFIGURED) {			// usb spec doesn't tell us what to do, so just go to			// default state			serial->state = DEFAULT;			serial->address = 0;		} else if (serial->address)			serial->state = ADDRESS;		else			serial->state = DEFAULT;		break;	case USB_REQ_GET_DESCRIPTOR:		desc_len = le16_to_cpu(setup->length);		switch (le16_to_cpu(setup->value) >> 8) {		case USB_DT_DEVICE:			// send device descriptor!			desc_len = desc_len > serial->dev_desc->bLength ?			    serial->dev_desc->bLength : desc_len;			dbg("sending device desc, size=%d", desc_len);			send_packet(&serial->ep_ctrl, (u8*)serial->dev_desc,				    desc_len, 0);			break;		case USB_DT_CONFIG:			// If the config descr index in low-byte of			// setup->value	is valid, send config descr,			// otherwise stall ep0.			if ((le16_to_cpu(setup->value) & 0xff) == 0) {				// send config descriptor!				if (desc_len <= USB_DT_CONFIG_SIZE) {					dbg("sending partial config desc, size=%d",					     desc_len);					send_packet(&serial->ep_ctrl,						    (u8*)serial->conf_desc,						    desc_len, 0);				} else {					u8 full_conf_desc[CONFIG_DESC_LEN];					int i, index = 0;					memcpy(&full_conf_desc[index],					       serial->conf_desc,					       USB_DT_CONFIG_SIZE);					index += USB_DT_CONFIG_SIZE;					memcpy(&full_conf_desc[index],					       serial->if_desc,					       USB_DT_INTERFACE_SIZE);					index += USB_DT_INTERFACE_SIZE;					for (i = 0; i < NUM_PORTS; i++) {						memcpy(&full_conf_desc[index],						       serial->port[i].ep_bulkin.desc,						       USB_DT_ENDPOINT_SIZE);						index += USB_DT_ENDPOINT_SIZE;						memcpy(&full_conf_desc[index],						       serial->port[i].ep_bulkout.desc,						       USB_DT_ENDPOINT_SIZE);						index += USB_DT_ENDPOINT_SIZE;					}					dbg("sending whole config desc, size=%d, our size=%d",					     desc_len, CONFIG_DESC_LEN);					desc_len = desc_len > CONFIG_DESC_LEN ?					    CONFIG_DESC_LEN : desc_len;					send_packet(&serial->ep_ctrl,						    full_conf_desc, desc_len, 0);				}			} else				endpoint_stall(&serial->ep_ctrl);			break;		case USB_DT_STRING:			// If the string descr index in low-byte of setup->value			// is valid, send string descr, otherwise stall ep0.			strnum = le16_to_cpu(setup->value) & 0xff;			if (strnum >= 0 && strnum < 6) {				struct usb_string_descriptor *desc =				    serial->str_desc[strnum];				desc_len = desc_len > desc->bLength ?					desc->bLength : desc_len;				dbg("sending string desc %d", strnum);				send_packet(&serial->ep_ctrl, (u8 *) desc,					    desc_len, 0);			} else				endpoint_stall(&serial->ep_ctrl);			break;		default:	// Invalid request			dbg("invalid get desc=%d, stalled",			    le16_to_cpu(setup->value) >> 8);			endpoint_stall(&serial->ep_ctrl);	// Stall endpoint 0			break;		}		break;	case USB_REQ_SET_DESCRIPTOR:		// FIXME: anything to set here?		break;	case USB_REQ_GET_INTERFACE:		// interface must be zero.		if ((le16_to_cpu(setup->index) & 0xff) ||		    serial->state == ADDRESS) {			// FIXME: respond with "request error". how?		} else if (serial->state == CONFIGURED) {			// send serial->alternate_setting			dbg("sending alt setting");			send_packet(&serial->ep_ctrl,				    &serial->alternate_setting, 1, 0);		}		break;	case USB_REQ_SET_INTERFACE:		if (serial->state == ADDRESS) {			// FIXME: respond with "request error". how?		} else if (serial->state == CONFIGURED) {			serial->interface = le16_to_cpu(setup->index) & 0xff;			serial->alternate_setting =			    le16_to_cpu(setup->value) & 0xff;			// interface and alternate_setting must be zero			if (serial->interface || serial->alternate_setting) {				// FIXME: respond with "request error". how?			}		}		break;	case USB_REQ_SET_CONFIGURATION:		// set active config to low-byte of serial.value		serial->configuration = le16_to_cpu(setup->value) & 0xff;		dbg("set config, config=%d", serial->configuration);		if (!serial->configuration && serial->state > DEFAULT)			serial->state = ADDRESS;		else if (serial->configuration == 1)			serial->state = CONFIGURED;		else {			// FIXME: "respond with request error" - how?		}		break;	case USB_REQ_GET_CONFIGURATION:		// send serial->configuration		dbg("sending config");		send_packet(&serial->ep_ctrl, &serial->configuration, 1, 0);		break;	case USB_REQ_GET_STATUS:		// FIXME: looks like the h/w handles this one		switch (setup->requesttype) {		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(&serial->ep_ctrl);	// Stall End Point 0			break;		}		break;	case USB_REQ_CLEAR_FEATURE:		switch (setup->requesttype) {		case 0x00:	// Device			if ((le16_to_cpu(setup->value) & 0xff) == 1)				serial->remote_wakeup_en = 0;			else				endpoint_stall(&serial->ep_ctrl);			break;		case 0x02:	// End Point			if ((le16_to_cpu(setup->value) & 0xff) == 0) {				endpoint_t *ep =				    epnum_to_ep(serial,						    le16_to_cpu(setup->index) & 0xff);				endpoint_unstall(ep);				endpoint_reset_datatoggle(ep);			} else				endpoint_stall(&serial->ep_ctrl);			break;		}		break;	case USB_REQ_SET_FEATURE:		switch (setup->requesttype) {		case 0x00:	// Device			if ((le16_to_cpu(setup->value) & 0xff) == 1)				serial->remote_wakeup_en = 1;			else				endpoint_stall(&serial->ep_ctrl);			break;		case 0x02:	// End Point			if ((le16_to_cpu(setup->value) & 0xff) == 0) {				endpoint_t *ep =				    epnum_to_ep(serial,						    le16_to_cpu(setup->index) & 0xff);				endpoint_stall(ep);			} else				endpoint_stall(&serial->ep_ctrl);			break;		}		break;	default:		endpoint_stall(&serial->ep_ctrl);	// Stall End Point 0		break;	}}/* * A complete packet (SETUP, DATA0, or DATA1) has been received * on the given endpoint's fifo. */static voidprocess_complete (struct usb_serial* serial, int fifo_num){	endpoint_t *ep = fifonum_to_ep(serial, fifo_num);	struct usb_serial_port *port = NULL;	pkt_t *pkt = 0;	u32 cs;	cs = inl(ep->reg->ctrl_stat);	switch (fifo_num) {	case 0:		spin_lock(&ep->lock);		// complete packet and prepare a new packet		receive_packet_complete(ep);		// Get it immediately from endpoint.		if (!(pkt = receive_packet(ep))) {			spin_unlock(&ep->lock);			return;		}			// SETUP packet received ?		//if (cs & USBDEV_CS_SU) { FIXME: uncomment!			if (pkt->size == sizeof(devrequest)) {				devrequest setup;			if ((cs & (USBDEV_CS_NAK | USBDEV_CS_ACK)) ==			    USBDEV_CS_ACK)					dbg("got SETUP");				else					dbg("got NAK SETUP, cs=%08x", cs);			memcpy(&setup, pkt->bufptr, sizeof(devrequest));				process_setup(serial, &setup);			//} else  FIXME: uncomment!			//dbg(__FUNCTION__ ": wrong size SETUP received");		} else {			// DATAx packet received on endpoint 0			// FIXME: will need a state machine for control			// OUT transactions			dbg("got DATAx on EP0, size=%d, cs=%08x",			    pkt->size, cs);		}		spin_unlock(&ep->lock);		// we're done processing the packet, free it		kfree(pkt);		break;	case 4:	case 5:		port = fifonum_to_port(serial, fifo_num);		dbg("got DATAx on port %d, cs=%08x", port->number, cs);		spin_lock(&ep->lock);		receive_packet_complete(ep);		spin_unlock(&ep->lock);		// mark a bh to push this data up to the tty		queue_task(&port->receive_complete_tq, &tq_immediate);		mark_bh(IMMEDIATE_BH);		break;	default:		break;	}}// This ISR needs to ack both the complete and suspend eventsstatic voidreq_sus_intr (int irq, void *dev_id, struct pt_regs *regs){	struct usb_serial *serial = (struct usb_serial *) dev_id;	int i;	u32 status;	status = inl(USB_DEV_INT_STATUS);	outl_sync(status, USB_DEV_INT_STATUS);	// ack'em#ifdef USBDEV_PIO	for (i = 0; i < 6; i++) {		if (status & (1 << (USBDEV_INT_HF_BIT + i))) {			endpoint_t *ep = fifonum_to_ep(serial, i);			if (ep->desc->bEndpointAddress & USB_DIR_IN)				endpoint_fifo_write(ep);			else				endpoint_fifo_read(ep);		}	}#endif	for (i = 0; i < 6; i++) {		if (status & (1 << i))			process_complete(serial, i);	}}static voiddma_done_ctrl(struct usb_serial* serial){	endpoint_t *ep = &serial->ep_ctrl;	u32 cs0, buff_done;	spin_lock(&ep->lock);	cs0 = inl(ep->reg->ctrl_stat);	// first check packet transmit done	if ((buff_done = get_dma_buffer_done(ep->indma)) != 0) {		// transmitted a DATAx packet on control endpoint 0		// clear DMA done bit		if (buff_done == DMA_D0)			clear_dma_done0(ep->indma);		else			clear_dma_done1(ep->indma);		send_packet_complete(ep);	}	/*	 * Now check packet receive done. Shouldn't get these,	 * the receive packet complete intr should happen	 * before the DMA done intr occurs.	 */	if ((buff_done = get_dma_buffer_done(ep->outdma)) != 0) {		// clear DMA done bit		if (buff_done == DMA_D0)			clear_dma_done0(ep->outdma);		else			clear_dma_done1(ep->outdma);	}	spin_unlock(&ep->lock);}static voiddma_done_port(struct usb_serial_port * port){	endpoint_t *ep;	u32 buff_done;	// first check packet transmit done (bulk IN ep)	ep = &port->ep_bulkin;	spin_lock(&ep->lock);	if ((buff_done = get_dma_buffer_done(ep->indma)) != 0) {		// transmitted a DATAx packet on the port's bulk IN endpoint		// clear DMA done bit		if (buff_done == DMA_D0)			clear_dma_done0(ep->indma);		else			clear_dma_done1(ep->indma);

⌨️ 快捷键说明

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