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

📄 fsl_usb2_udc.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (!_ep) {		return;	} else {		ep = container_of(_ep, struct fsl_ep, ep);		if (!ep->desc)			return;	}	ep_num = ep_index(ep);	ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV;	if (ep_num == 0)		bits = (1 << 16) | 1;	else if (ep_dir == USB_SEND)		bits = 1 << (16 + ep_num);	else		bits = 1 << ep_num;	timeout = jiffies + FSL_UDC_FLUSH_TIMEOUT;	do {		fsl_writel(bits, &dr_regs->endptflush);		/* Wait until flush complete */		while (fsl_readl(&dr_regs->endptflush)) {			if (time_after(jiffies, timeout)) {				ERR("ep flush timeout\n");				return;			}			cpu_relax();		}		/* See if we need to flush again */	} while (fsl_readl(&dr_regs->endptstatus) & bits);}static struct usb_ep_ops fsl_ep_ops = {	.enable = fsl_ep_enable,	.disable = fsl_ep_disable,	.alloc_request = fsl_alloc_request,	.free_request = fsl_free_request,	.queue = fsl_ep_queue,	.dequeue = fsl_ep_dequeue,	.set_halt = fsl_ep_set_halt,	.fifo_flush = fsl_ep_fifo_flush,	/* flush fifo */};/*-------------------------------------------------------------------------		Gadget Driver Layer Operations-------------------------------------------------------------------------*//*---------------------------------------------------------------------- * Get the current frame number (from DR frame_index Reg ) *----------------------------------------------------------------------*/static int fsl_get_frame(struct usb_gadget *gadget){	return (int)(fsl_readl(&dr_regs->frindex) & USB_FRINDEX_MASKS);}/*----------------------------------------------------------------------- * Tries to wake up the host connected to this gadget -----------------------------------------------------------------------*/static int fsl_wakeup(struct usb_gadget *gadget){	struct fsl_udc *udc = container_of(gadget, struct fsl_udc, gadget);	u32 portsc;	/* Remote wakeup feature not enabled by host */	if (!udc->remote_wakeup)		return -ENOTSUPP;	portsc = fsl_readl(&dr_regs->portsc1);	/* not suspended? */	if (!(portsc & PORTSCX_PORT_SUSPEND))		return 0;	/* trigger force resume */	portsc |= PORTSCX_PORT_FORCE_RESUME;	fsl_writel(portsc, &dr_regs->portsc1);	return 0;}static int can_pullup(struct fsl_udc *udc){	return udc->driver && udc->softconnect && udc->vbus_active;}/* Notify controller that VBUS is powered, Called by whatever   detects VBUS sessions */static int fsl_vbus_session(struct usb_gadget *gadget, int is_active){	struct fsl_udc	*udc;	unsigned long	flags;	udc = container_of(gadget, struct fsl_udc, gadget);	spin_lock_irqsave(&udc->lock, flags);	VDBG("VBUS %s\n", is_active ? "on" : "off");	udc->vbus_active = (is_active != 0);	if (can_pullup(udc))		fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),				&dr_regs->usbcmd);	else		fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),				&dr_regs->usbcmd);	spin_unlock_irqrestore(&udc->lock, flags);	return 0;}/* constrain controller's VBUS power usage * This call is used by gadget drivers during SET_CONFIGURATION calls, * reporting how much power the device may consume.  For example, this * could affect how quickly batteries are recharged. * * Returns zero on success, else negative errno. */static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA){	struct fsl_udc *udc;	udc = container_of(gadget, struct fsl_udc, gadget);	if (udc->transceiver)		return otg_set_power(udc->transceiver, mA);	return -ENOTSUPP;}/* Change Data+ pullup status * this func is used by usb_gadget_connect/disconnet */static int fsl_pullup(struct usb_gadget *gadget, int is_on){	struct fsl_udc *udc;	udc = container_of(gadget, struct fsl_udc, gadget);	udc->softconnect = (is_on != 0);	if (can_pullup(udc))		fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),				&dr_regs->usbcmd);	else		fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),				&dr_regs->usbcmd);	return 0;}/* defined in gadget.h */static struct usb_gadget_ops fsl_gadget_ops = {	.get_frame = fsl_get_frame,	.wakeup = fsl_wakeup,/*	.set_selfpowered = fsl_set_selfpowered,	*/ /* Always selfpowered */	.vbus_session = fsl_vbus_session,	.vbus_draw = fsl_vbus_draw,	.pullup = fsl_pullup,};/* Set protocol stall on ep0, protocol stall will automatically be cleared   on new transaction */static void ep0stall(struct fsl_udc *udc){	u32 tmp;	/* must set tx and rx to stall at the same time */	tmp = fsl_readl(&dr_regs->endptctrl[0]);	tmp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL;	fsl_writel(tmp, &dr_regs->endptctrl[0]);	udc->ep0_state = WAIT_FOR_SETUP;	udc->ep0_dir = 0;}/* Prime a status phase for ep0 */static int ep0_prime_status(struct fsl_udc *udc, int direction){	struct fsl_req *req = udc->status_req;	struct fsl_ep *ep;	int status = 0;	if (direction == EP_DIR_IN)		udc->ep0_dir = USB_DIR_IN;	else		udc->ep0_dir = USB_DIR_OUT;	ep = &udc->eps[0];	udc->ep0_state = WAIT_FOR_OUT_STATUS;	req->ep = ep;	req->req.length = 0;	req->req.status = -EINPROGRESS;	req->req.actual = 0;	req->req.complete = NULL;	req->dtd_count = 0;	if (fsl_req_to_dtd(req) == 0)		status = fsl_queue_td(ep, req);	else		return -ENOMEM;	if (status)		ERR("Can't queue ep0 status request \n");	list_add_tail(&req->queue, &ep->queue);	return status;}static inline int udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe){	struct fsl_ep *ep = get_ep_by_pipe(udc, pipe);	if (!ep->name)		return 0;	nuke(ep, -ESHUTDOWN);	return 0;}/* * ch9 Set address */static void ch9setaddress(struct fsl_udc *udc, u16 value, u16 index, u16 length){	/* Save the new address to device struct */	udc->device_address = (u8) value;	/* Update usb state */	udc->usb_state = USB_STATE_ADDRESS;	/* Status phase */	if (ep0_prime_status(udc, EP_DIR_IN))		ep0stall(udc);}/* * ch9 Get status */static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,		u16 index, u16 length){	u16 tmp = 0;		/* Status, cpu endian */	struct fsl_req *req;	struct fsl_ep *ep;	int status = 0;	ep = &udc->eps[0];	if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {		/* Get device status */		tmp = 1 << USB_DEVICE_SELF_POWERED;		tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;	} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {		/* Get interface status */		/* We don't have interface information in udc driver */		tmp = 0;	} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {		/* Get endpoint status */		struct fsl_ep *target_ep;		target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index));		/* stall if endpoint doesn't exist */		if (!target_ep->desc)			goto stall;		tmp = dr_ep_get_stall(ep_index(target_ep), ep_is_in(target_ep))				<< USB_ENDPOINT_HALT;	}	udc->ep0_dir = USB_DIR_IN;	/* Borrow the per device status_req */	req = udc->status_req;	/* Fill in the reqest structure */	*((u16 *) req->req.buf) = cpu_to_le16(tmp);	req->ep = ep;	req->req.length = 2;	req->req.status = -EINPROGRESS;	req->req.actual = 0;	req->req.complete = NULL;	req->dtd_count = 0;	/* prime the data phase */	if ((fsl_req_to_dtd(req) == 0))		status = fsl_queue_td(ep, req);	else			/* no mem */		goto stall;	if (status) {		ERR("Can't respond to getstatus request \n");		goto stall;	}	list_add_tail(&req->queue, &ep->queue);	udc->ep0_state = DATA_STATE_XMIT;	return;stall:	ep0stall(udc);}static void setup_received_irq(struct fsl_udc *udc,		struct usb_ctrlrequest *setup){	u16 wValue = le16_to_cpu(setup->wValue);	u16 wIndex = le16_to_cpu(setup->wIndex);	u16 wLength = le16_to_cpu(setup->wLength);	udc_reset_ep_queue(udc, 0);	/* We process some stardard setup requests here */	switch (setup->bRequest) {	case USB_REQ_GET_STATUS:		/* Data+Status phase from udc */		if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))					!= (USB_DIR_IN | USB_TYPE_STANDARD))			break;		ch9getstatus(udc, setup->bRequestType, wValue, wIndex, wLength);		return;	case USB_REQ_SET_ADDRESS:		/* Status phase from udc */		if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD						| USB_RECIP_DEVICE))			break;		ch9setaddress(udc, wValue, wIndex, wLength);		return;	case USB_REQ_CLEAR_FEATURE:	case USB_REQ_SET_FEATURE:		/* Status phase from udc */	{		int rc = -EOPNOTSUPP;		if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))				== (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {			int pipe = get_pipe_by_windex(wIndex);			struct fsl_ep *ep;			if (wValue != 0 || wLength != 0 || pipe > udc->max_ep)				break;			ep = get_ep_by_pipe(udc, pipe);			spin_unlock(&udc->lock);			rc = fsl_ep_set_halt(&ep->ep,					(setup->bRequest == USB_REQ_SET_FEATURE)						? 1 : 0);			spin_lock(&udc->lock);		} else if ((setup->bRequestType & (USB_RECIP_MASK				| USB_TYPE_MASK)) == (USB_RECIP_DEVICE				| USB_TYPE_STANDARD)) {			/* Note: The driver has not include OTG support yet.			 * This will be set when OTG support is added */			if (!gadget_is_otg(&udc->gadget))				break;			else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)				udc->gadget.b_hnp_enable = 1;			else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)				udc->gadget.a_hnp_support = 1;			else if (setup->bRequest ==					USB_DEVICE_A_ALT_HNP_SUPPORT)				udc->gadget.a_alt_hnp_support = 1;			else				break;			rc = 0;		} else			break;		if (rc == 0) {			if (ep0_prime_status(udc, EP_DIR_IN))				ep0stall(udc);		}		return;	}	default:		break;	}	/* Requests handled by gadget */	if (wLength) {		/* Data phase from gadget, status phase from udc */		udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)				?  USB_DIR_IN : USB_DIR_OUT;		spin_unlock(&udc->lock);		if (udc->driver->setup(&udc->gadget,				&udc->local_setup_buff) < 0)			ep0stall(udc);		spin_lock(&udc->lock);		udc->ep0_state = (setup->bRequestType & USB_DIR_IN)				?  DATA_STATE_XMIT : DATA_STATE_RECV;	} else {		/* No data phase, IN status from gadget */		udc->ep0_dir = USB_DIR_IN;		spin_unlock(&udc->lock);		if (udc->driver->setup(&udc->gadget,				&udc->local_setup_buff) < 0)			ep0stall(udc);		spin_lock(&udc->lock);		udc->ep0_state = WAIT_FOR_OUT_STATUS;	}}/* Process request for Data or Status phase of ep0 * prime status phase if needed */static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0,		struct fsl_req *req){	if (udc->usb_state == USB_STATE_ADDRESS) {		/* Set the new address */		u32 new_address = (u32) udc->device_address;		fsl_writel(new_address << USB_DEVICE_ADDRESS_BIT_POS,				&dr_regs->deviceaddr);	}	done(ep0, req, 0);	switch (udc->ep0_state) {	case DATA_STATE_XMIT:		/* receive status phase */		if (ep0_prime_status(udc, EP_DIR_OUT))			ep0stall(udc);		break;	case DATA_STATE_RECV:		/* send status phase */		if (ep0_prime_status(udc, EP_DIR_IN))			ep0stall(udc);		break;	case WAIT_FOR_OUT_STATUS:		udc->ep0_state = WAIT_FOR_SETUP;		break;	case WAIT_FOR_SETUP:		ERR("Unexpect ep0 packets \n");		break;	default:		ep0stall(udc);		break;	}}/* Tripwire mechanism to ensure a setup packet payload is extracted without * being corrupted by another incoming setup packet */static void tripwire_handler(struct fsl_udc *udc, u8 ep_num, u8 *buffer_ptr){	u32 temp;	struct ep_queue_head *qh;	qh = &udc->ep_qh[ep_num * 2 + EP_DIR_OUT];	/* Clear bit in ENDPTSETUPSTAT */	temp = fsl_readl(&dr_regs->endptsetupstat);	fsl_writel(temp | (1 << ep_num), &dr_regs->endptsetupstat);	/* while a hazard exists when setup package arrives */	do {		/* Set Setup Tripwire */		temp = fsl_readl(&dr_regs->usbcmd);		fsl_writel(temp | USB_CMD_SUTW, &dr_regs->usbcmd);		/* Copy the setup packet to local buffer */		memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);	} while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_SUTW));	/* Clear Setup Tripwire */	temp = fsl_readl(&dr_regs->usbcmd);	fsl_writel(temp & ~USB_CMD_SUTW, &dr_regs->usbcmd);}/* process-ep_req(): free the completed Tds for this req */static int process_ep_req(struct fsl_udc *udc, int pipe,		struct fsl_req *curr_req){	struct ep_td_struct *curr_td;	int	td_complete, actual, remaining_length, j, tmp;	int	status = 0;	int	errors = 0;	struct  ep_queue_head *curr_qh = &udc->ep_qh[pipe];	int direction = pipe % 2;	curr_td = curr_req->head;	td_complete = 0;	actual = curr_req->req.length;	for (j = 0; j < curr_req->dtd_count; j++) {		remaining_length = (le32_to_cpu(curr_td->size_ioc_sts)					& DTD_PACKET_SIZE)				>> DTD_LENGTH_BIT_POS;		actual -= remaining_length;		if ((errors = le32_to_cpu(curr_td->size_ioc_sts) &						DTD_ERROR_MASK)) {			if (errors & DTD_STATUS_HALTED) {				ERR("dTD error %08x QH=%d\n", errors, pipe);				/* Clear the errors and Halt condition */				tmp = le32_to_cpu(curr_qh->size_ioc_int_sts);				tmp &= ~errors;				curr_qh->size_ioc_int_sts = cpu_to_le32(tmp);

⌨️ 快捷键说明

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