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

📄 s3c2410_udc.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
		if (fifo_count != avail)			req->req.status = -EOVERFLOW;	} else {		is_last = (req->req.length <= req->req.actual) ? 1 : 0;	}	udc_write(idx, S3C2410_UDC_INDEX_REG);	fifo_count = s3c2410_udc_fifo_count_out();	/* Only ep0 debug messages are interesting */	if (idx == 0)		dprintk(DEBUG_VERBOSE, "%s fifo count : %d [last %d]\n",			__func__, fifo_count,is_last);	if (is_last) {		if (idx == 0) {			s3c2410_udc_set_ep0_de_out(base_addr);			ep->dev->ep0state = EP0_IDLE;		} else {			udc_write(idx, S3C2410_UDC_INDEX_REG);			ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG);			udc_write(idx, S3C2410_UDC_INDEX_REG);			udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY,					S3C2410_UDC_OUT_CSR1_REG);		}		s3c2410_udc_done(ep, req, 0);	} else {		if (idx == 0) {			s3c2410_udc_clear_ep0_opr(base_addr);		} else {			udc_write(idx, S3C2410_UDC_INDEX_REG);			ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG);			udc_write(idx, S3C2410_UDC_INDEX_REG);			udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY,					S3C2410_UDC_OUT_CSR1_REG);		}	}	return is_last;}static int s3c2410_udc_read_fifo_crq(struct usb_ctrlrequest *crq){	unsigned char *outbuf = (unsigned char*)crq;	int bytes_read = 0;	udc_write(0, S3C2410_UDC_INDEX_REG);	bytes_read = s3c2410_udc_fifo_count_out();	dprintk(DEBUG_NORMAL, "%s: fifo_count=%d\n", __func__, bytes_read);	if (bytes_read > sizeof(struct usb_ctrlrequest))		bytes_read = sizeof(struct usb_ctrlrequest);	readsb(S3C2410_UDC_EP0_FIFO_REG + base_addr, outbuf, bytes_read);	dprintk(DEBUG_VERBOSE, "%s: len=%d %02x:%02x {%x,%x,%x}\n", __func__,		bytes_read, crq->bRequest, crq->bRequestType,		crq->wValue, crq->wIndex, crq->wLength);	return bytes_read;}static int s3c2410_udc_get_status(struct s3c2410_udc *dev,		struct usb_ctrlrequest *crq){	u16 status = 0;	u8 ep_num = crq->wIndex & 0x7F;	u8 is_in = crq->wIndex & USB_DIR_IN;	switch (crq->bRequestType & USB_RECIP_MASK) {	case USB_RECIP_INTERFACE:		break;	case USB_RECIP_DEVICE:		status = dev->devstatus;		break;	case USB_RECIP_ENDPOINT:		if (ep_num > 4 || crq->wLength > 2)			return 1;		if (ep_num == 0) {			udc_write(0, S3C2410_UDC_INDEX_REG);			status = udc_read(S3C2410_UDC_IN_CSR1_REG);			status = status & S3C2410_UDC_EP0_CSR_SENDSTL;		} else {			udc_write(ep_num, S3C2410_UDC_INDEX_REG);			if (is_in) {				status = udc_read(S3C2410_UDC_IN_CSR1_REG);				status = status & S3C2410_UDC_ICSR1_SENDSTL;			} else {				status = udc_read(S3C2410_UDC_OUT_CSR1_REG);				status = status & S3C2410_UDC_OCSR1_SENDSTL;			}		}		status = status ? 1 : 0;		break;	default:		return 1;	}	/* Seems to be needed to get it working. ouch :( */	udelay(5);	udc_write(status & 0xFF, S3C2410_UDC_EP0_FIFO_REG);	udc_write(status >> 8, S3C2410_UDC_EP0_FIFO_REG);	s3c2410_udc_set_ep0_de_in(base_addr);	return 0;}/*------------------------- usb state machine -------------------------------*/static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value);static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev,					struct s3c2410_ep *ep,					struct usb_ctrlrequest *crq,					u32 ep0csr){	int len, ret, tmp;	/* start control request? */	if (!(ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY))		return;	s3c2410_udc_nuke(dev, ep, -EPROTO);	len = s3c2410_udc_read_fifo_crq(crq);	if (len != sizeof(*crq)) {		dprintk(DEBUG_NORMAL, "setup begin: fifo READ ERROR"			" wanted %d bytes got %d. Stalling out...\n",			sizeof(*crq), len);		s3c2410_udc_set_ep0_ss(base_addr);		return;	}	dprintk(DEBUG_NORMAL, "bRequest = %d bRequestType %d wLength = %d\n",		crq->bRequest, crq->bRequestType, crq->wLength);	/* cope with automagic for some standard requests. */	dev->req_std = (crq->bRequestType & USB_TYPE_MASK)		== USB_TYPE_STANDARD;	dev->req_config = 0;	dev->req_pending = 1;	switch (crq->bRequest) {	case USB_REQ_SET_CONFIGURATION:		dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ... \n");		if (crq->bRequestType == USB_RECIP_DEVICE) {			dev->req_config = 1;			s3c2410_udc_set_ep0_de_out(base_addr);		}		break;	case USB_REQ_SET_INTERFACE:		dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ... \n");		if (crq->bRequestType == USB_RECIP_INTERFACE) {			dev->req_config = 1;			s3c2410_udc_set_ep0_de_out(base_addr);		}		break;	case USB_REQ_SET_ADDRESS:		dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ... \n");		if (crq->bRequestType == USB_RECIP_DEVICE) {			tmp = crq->wValue & 0x7F;			dev->address = tmp;			udc_write((tmp | S3C2410_UDC_FUNCADDR_UPDATE),					S3C2410_UDC_FUNC_ADDR_REG);			s3c2410_udc_set_ep0_de_out(base_addr);			return;		}		break;	case USB_REQ_GET_STATUS:		dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ... \n");		s3c2410_udc_clear_ep0_opr(base_addr);		if (dev->req_std) {			if (!s3c2410_udc_get_status(dev, crq)) {				return;			}		}		break;	case USB_REQ_CLEAR_FEATURE:		s3c2410_udc_clear_ep0_opr(base_addr);		if (crq->bRequestType != USB_RECIP_ENDPOINT)			break;		if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0)			break;		s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 0);		s3c2410_udc_set_ep0_de_out(base_addr);		return;	case USB_REQ_SET_FEATURE:		s3c2410_udc_clear_ep0_opr(base_addr);		if (crq->bRequestType != USB_RECIP_ENDPOINT)			break;		if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0)			break;		s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 1);		s3c2410_udc_set_ep0_de_out(base_addr);		return;	default:		s3c2410_udc_clear_ep0_opr(base_addr);		break;	}	if (crq->bRequestType & USB_DIR_IN)		dev->ep0state = EP0_IN_DATA_PHASE;	else		dev->ep0state = EP0_OUT_DATA_PHASE;	ret = dev->driver->setup(&dev->gadget, crq);	if (ret < 0) {		if (dev->req_config) {			dprintk(DEBUG_NORMAL, "config change %02x fail %d?\n",				crq->bRequest, ret);			return;		}		if (ret == -EOPNOTSUPP)			dprintk(DEBUG_NORMAL, "Operation not supported\n");		else			dprintk(DEBUG_NORMAL,				"dev->driver->setup failed. (%d)\n", ret);		udelay(5);		s3c2410_udc_set_ep0_ss(base_addr);		s3c2410_udc_set_ep0_de_out(base_addr);		dev->ep0state = EP0_IDLE;		/* deferred i/o == no response yet */	} else if (dev->req_pending) {		dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?\n");		dev->req_pending=0;	}	dprintk(DEBUG_VERBOSE, "ep0state %s\n", ep0states[dev->ep0state]);}static void s3c2410_udc_handle_ep0(struct s3c2410_udc *dev){	u32			ep0csr;	struct s3c2410_ep	*ep = &dev->ep[0];	struct s3c2410_request	*req;	struct usb_ctrlrequest	crq;	if (list_empty(&ep->queue))		req = NULL;	else		req = list_entry(ep->queue.next, struct s3c2410_request, queue);	/* We make the assumption that S3C2410_UDC_IN_CSR1_REG equal to	 * S3C2410_UDC_EP0_CSR_REG when index is zero */	udc_write(0, S3C2410_UDC_INDEX_REG);	ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG);	dprintk(DEBUG_NORMAL, "ep0csr %x ep0state %s\n",		ep0csr, ep0states[dev->ep0state]);	/* clear stall status */	if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {		s3c2410_udc_nuke(dev, ep, -EPIPE);		dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n");		s3c2410_udc_clear_ep0_sst(base_addr);		dev->ep0state = EP0_IDLE;		return;	}	/* clear setup end */	if (ep0csr & S3C2410_UDC_EP0_CSR_SE) {		dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...\n");		s3c2410_udc_nuke(dev, ep, 0);		s3c2410_udc_clear_ep0_se(base_addr);		dev->ep0state = EP0_IDLE;	}	switch (dev->ep0state) {	case EP0_IDLE:		s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr);		break;	case EP0_IN_DATA_PHASE:			/* GET_DESCRIPTOR etc */		dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n");		if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) {			s3c2410_udc_write_fifo(ep, req);		}		break;	case EP0_OUT_DATA_PHASE:		/* SET_DESCRIPTOR etc */		dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n");		if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req ) {			s3c2410_udc_read_fifo(ep,req);		}		break;	case EP0_END_XFER:		dprintk(DEBUG_NORMAL, "EP0_END_XFER ... what now?\n");		dev->ep0state = EP0_IDLE;		break;	case EP0_STALL:		dprintk(DEBUG_NORMAL, "EP0_STALL ... what now?\n");		dev->ep0state = EP0_IDLE;		break;	}}/* *	handle_ep - Manage I/O endpoints */static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep){	struct s3c2410_request	*req;	int			is_in = ep->bEndpointAddress & USB_DIR_IN;	u32			ep_csr1;	u32			idx;	if (likely (!list_empty(&ep->queue)))		req = list_entry(ep->queue.next,				struct s3c2410_request, queue);	else		req = NULL;	idx = ep->bEndpointAddress & 0x7F;	if (is_in) {		udc_write(idx, S3C2410_UDC_INDEX_REG);		ep_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG);		dprintk(DEBUG_VERBOSE, "ep%01d write csr:%02x %d\n",			idx, ep_csr1, req ? 1 : 0);		if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) {			dprintk(DEBUG_VERBOSE, "st\n");			udc_write(idx, S3C2410_UDC_INDEX_REG);			udc_write(ep_csr1 & ~S3C2410_UDC_ICSR1_SENTSTL,					S3C2410_UDC_IN_CSR1_REG);			return;		}		if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req) {			s3c2410_udc_write_fifo(ep,req);		}	} else {		udc_write(idx, S3C2410_UDC_INDEX_REG);		ep_csr1 = udc_read(S3C2410_UDC_OUT_CSR1_REG);		dprintk(DEBUG_VERBOSE, "ep%01d rd csr:%02x\n", idx, ep_csr1);		if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) {			udc_write(idx, S3C2410_UDC_INDEX_REG);			udc_write(ep_csr1 & ~S3C2410_UDC_OCSR1_SENTSTL,					S3C2410_UDC_OUT_CSR1_REG);			return;		}		if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {			s3c2410_udc_read_fifo(ep,req);		}	}}#include <asm/arch/regs-irq.h>/* *	s3c2410_udc_irq - interrupt handler */static irqreturn_t s3c2410_udc_irq(int irq, void *_dev){	struct s3c2410_udc *dev = _dev;	int usb_status;	int usbd_status;	int pwr_reg;	int ep0csr;	int i;	u32 idx;	unsigned long flags;	spin_lock_irqsave(&dev->lock, flags);	/* Driver connected ? */	if (!dev->driver) {		/* Clear interrupts */		udc_write(udc_read(S3C2410_UDC_USB_INT_REG),				S3C2410_UDC_USB_INT_REG);		udc_write(udc_read(S3C2410_UDC_EP_INT_REG),				S3C2410_UDC_EP_INT_REG);	}	/* Save index */	idx = udc_read(S3C2410_UDC_INDEX_REG);	/* Read status registers */	usb_status = udc_read(S3C2410_UDC_USB_INT_REG);	usbd_status = udc_read(S3C2410_UDC_EP_INT_REG);	pwr_reg = udc_read(S3C2410_UDC_PWR_REG);	udc_writeb(base_addr, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);	ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG);	dprintk(DEBUG_NORMAL, "usbs=%02x, usbds=%02x, pwr=%02x ep0csr=%02x\n",		usb_status, usbd_status, pwr_reg, ep0csr);	/*	 * Now, handle interrupts. There's two types :	 * - Reset, Resume, Suspend coming -> usb_int_reg	 * - EP -> ep_int_reg	 */	/* RESET */	if (usb_status & S3C2410_UDC_USBINT_RESET) {		/* two kind of reset :		 * - reset start -> pwr reg = 8		 * - reset end   -> pwr reg = 0		 **/		dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %x\n",			ep0csr, pwr_reg);		dev->gadget.speed = USB_SPEED_UNKNOWN;		udc_write(0x00, S3C2410_UDC_INDEX_REG);		udc_write((dev->ep[0].ep.maxpacket & 0x7ff) >> 3,				S3C2410_UDC_MAXP_REG);		dev->address = 0;		dev->ep0state = EP0_IDLE;		dev->gadget.speed = USB_SPEED_FULL;		/* clear interrupt */		udc_write(S3C2410_UDC_USBINT_RESET,				S3C2410_UDC_USB_INT_REG);		udc_write(idx, S3C2410_UDC_INDEX_REG);		spin_unlock_irqrestore(&dev->lock, flags);		return IRQ_HANDLED;	}	/* RESUME */	if (usb_status & S3C2410_UDC_USBINT_RESUME) {		dprintk(DEBUG_NORMAL, "USB resume\n");		/* clear interrupt */		udc_write(S3C2410_UDC_USBINT_RESUME,				S3C2410_UDC_USB_INT_REG);		if (dev->gadget.speed != USB_SPEED_UNKNOWN				&& dev->driver				&& dev->driver->resume)			dev->driver->resume(&dev->gadget);	}	/* SUSPEND */	if (usb_status & S3C2410_UDC_USBINT_SUSPEND) {		dprintk(DEBUG_NORMAL, "USB suspend\n");		/* clear interrupt */		udc_write(S3C2410_UDC_USBINT_SUSPEND,				S3C2410_UDC_USB_INT_REG);		if (dev->gadget.speed != USB_SPEED_UNKNOWN				&& dev->driver				&& dev->driver->suspend)			dev->driver->suspend(&dev->gadget);		dev->ep0state = EP0_IDLE;	}	/* EP */	/* control traffic */	/* check on ep0csr != 0 is not a good idea as clearing in_pkt_ready	 * generate an interrupt	 */	if (usbd_status & S3C2410_UDC_INT_EP0) {		dprintk(DEBUG_VERBOSE, "USB ep0 irq\n");		/* Clear the interrupt bit by setting it to 1 */		udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG);		s3c2410_udc_handle_ep0(dev);	}	/* endpoint data transfers */	for (i = 1; i < S3C2410_ENDPOINTS; i++) {		u32 tmp = 1 << i;		if (usbd_status & tmp) {			dprintk(DEBUG_VERBOSE, "USB ep%d irq\n", i);			/* Clear the interrupt bit by setting it to 1 */			udc_write(tmp, S3C2410_UDC_EP_INT_REG);			s3c2410_udc_handle_ep(&dev->ep[i]);		}	}	dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", irq);	/* Restore old index */	udc_write(idx, S3C2410_UDC_INDEX_REG);	spin_unlock_irqrestore(&dev->lock, flags);	return IRQ_HANDLED;

⌨️ 快捷键说明

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