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

📄 s3c2410_udc.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
}/*------------------------- s3c2410_ep_ops ----------------------------------*/static inline struct s3c2410_ep *to_s3c2410_ep(struct usb_ep *ep){	return container_of(ep, struct s3c2410_ep, ep);}static inline struct s3c2410_udc *to_s3c2410_udc(struct usb_gadget *gadget){	return container_of(gadget, struct s3c2410_udc, gadget);}static inline struct s3c2410_request *to_s3c2410_req(struct usb_request *req){	return container_of(req, struct s3c2410_request, req);}/* *	s3c2410_udc_ep_enable */static int s3c2410_udc_ep_enable(struct usb_ep *_ep,				 const struct usb_endpoint_descriptor *desc){	struct s3c2410_udc	*dev;	struct s3c2410_ep	*ep;	u32			max, tmp;	unsigned long		flags;	u32			csr1,csr2;	u32			int_en_reg;	ep = to_s3c2410_ep(_ep);	if (!_ep || !desc || ep->desc			|| _ep->name == ep0name			|| desc->bDescriptorType != USB_DT_ENDPOINT)		return -EINVAL;	dev = ep->dev;	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)		return -ESHUTDOWN;	max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff;	local_irq_save (flags);	_ep->maxpacket = max & 0x7ff;	ep->desc = desc;	ep->halted = 0;	ep->bEndpointAddress = desc->bEndpointAddress;	/* set max packet */	udc_write(ep->num, S3C2410_UDC_INDEX_REG);	udc_write(max >> 3, S3C2410_UDC_MAXP_REG);	/* set type, direction, address; reset fifo counters */	if (desc->bEndpointAddress & USB_DIR_IN) {		csr1 = S3C2410_UDC_ICSR1_FFLUSH|S3C2410_UDC_ICSR1_CLRDT;		csr2 = S3C2410_UDC_ICSR2_MODEIN|S3C2410_UDC_ICSR2_DMAIEN;		udc_write(ep->num, S3C2410_UDC_INDEX_REG);		udc_write(csr1, S3C2410_UDC_IN_CSR1_REG);		udc_write(ep->num, S3C2410_UDC_INDEX_REG);		udc_write(csr2, S3C2410_UDC_IN_CSR2_REG);	} else {		/* don't flush in fifo or it will cause endpoint interrupt */		csr1 = S3C2410_UDC_ICSR1_CLRDT;		csr2 = S3C2410_UDC_ICSR2_DMAIEN;		udc_write(ep->num, S3C2410_UDC_INDEX_REG);		udc_write(csr1, S3C2410_UDC_IN_CSR1_REG);		udc_write(ep->num, S3C2410_UDC_INDEX_REG);		udc_write(csr2, S3C2410_UDC_IN_CSR2_REG);		csr1 = S3C2410_UDC_OCSR1_FFLUSH | S3C2410_UDC_OCSR1_CLRDT;		csr2 = S3C2410_UDC_OCSR2_DMAIEN;		udc_write(ep->num, S3C2410_UDC_INDEX_REG);		udc_write(csr1, S3C2410_UDC_OUT_CSR1_REG);		udc_write(ep->num, S3C2410_UDC_INDEX_REG);		udc_write(csr2, S3C2410_UDC_OUT_CSR2_REG);	}	/* enable irqs */	int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG);	udc_write(int_en_reg | (1 << ep->num), S3C2410_UDC_EP_INT_EN_REG);	/* print some debug message */	tmp = desc->bEndpointAddress;	dprintk (DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n",		 _ep->name,ep->num, tmp,		 desc->bEndpointAddress & USB_DIR_IN ? "in" : "out", max);	local_irq_restore (flags);	s3c2410_udc_set_halt(_ep, 0);	return 0;}/* * s3c2410_udc_ep_disable */static int s3c2410_udc_ep_disable(struct usb_ep *_ep){	struct s3c2410_ep *ep = to_s3c2410_ep(_ep);	unsigned long flags;	u32 int_en_reg;	if (!_ep || !ep->desc) {		dprintk(DEBUG_NORMAL, "%s not enabled\n",			_ep ? ep->ep.name : NULL);		return -EINVAL;	}	local_irq_save(flags);	dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name);	ep->desc = NULL;	ep->halted = 1;	s3c2410_udc_nuke (ep->dev, ep, -ESHUTDOWN);	/* disable irqs */	int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG);	udc_write(int_en_reg & ~(1<<ep->num), S3C2410_UDC_EP_INT_EN_REG);	local_irq_restore(flags);	dprintk(DEBUG_NORMAL, "%s disabled\n", _ep->name);	return 0;}/* * s3c2410_udc_alloc_request */static struct usb_request *s3c2410_udc_alloc_request(struct usb_ep *_ep, gfp_t mem_flags){	struct s3c2410_request *req;	dprintk(DEBUG_VERBOSE,"%s(%p,%d)\n", __func__, _ep, mem_flags);	if (!_ep)		return NULL;	req = kzalloc (sizeof(struct s3c2410_request), mem_flags);	if (!req)		return NULL;	INIT_LIST_HEAD (&req->queue);	return &req->req;}/* * s3c2410_udc_free_request */static voids3c2410_udc_free_request(struct usb_ep *_ep, struct usb_request *_req){	struct s3c2410_ep	*ep = to_s3c2410_ep(_ep);	struct s3c2410_request	*req = to_s3c2410_req(_req);	dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req);	if (!ep || !_req || (!ep->desc && _ep->name != ep0name))		return;	WARN_ON (!list_empty (&req->queue));	kfree(req);}/* *	s3c2410_udc_queue */static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req,		gfp_t gfp_flags){	struct s3c2410_request	*req = to_s3c2410_req(_req);	struct s3c2410_ep	*ep = to_s3c2410_ep(_ep);	struct s3c2410_udc	*dev;	u32			ep_csr = 0;	int			fifo_count = 0;	unsigned long		flags;	if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {		dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__);		return -EINVAL;	}	dev = ep->dev;	if (unlikely (!dev->driver			|| dev->gadget.speed == USB_SPEED_UNKNOWN)) {		return -ESHUTDOWN;	}	local_irq_save (flags);	if (unlikely(!_req || !_req->complete			|| !_req->buf || !list_empty(&req->queue))) {		if (!_req)			dprintk(DEBUG_NORMAL, "%s: 1 X X X\n", __func__);		else {			dprintk(DEBUG_NORMAL, "%s: 0 %01d %01d %01d\n",				__func__, !_req->complete,!_req->buf,				!list_empty(&req->queue));		}		local_irq_restore(flags);		return -EINVAL;	}	_req->status = -EINPROGRESS;	_req->actual = 0;	dprintk(DEBUG_VERBOSE, "%s: ep%x len %d\n",		 __func__, ep->bEndpointAddress, _req->length);	if (ep->bEndpointAddress) {		udc_write(ep->bEndpointAddress & 0x7F, S3C2410_UDC_INDEX_REG);		ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN)				? S3C2410_UDC_IN_CSR1_REG				: S3C2410_UDC_OUT_CSR1_REG);		fifo_count = s3c2410_udc_fifo_count_out();	} else {		udc_write(0, S3C2410_UDC_INDEX_REG);		ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);		fifo_count = s3c2410_udc_fifo_count_out();	}	/* kickstart this i/o queue? */	if (list_empty(&ep->queue) && !ep->halted) {		if (ep->bEndpointAddress == 0 /* ep0 */) {			switch (dev->ep0state) {			case EP0_IN_DATA_PHASE:				if (!(ep_csr&S3C2410_UDC_EP0_CSR_IPKRDY)						&& s3c2410_udc_write_fifo(ep,							req)) {					dev->ep0state = EP0_IDLE;					req = NULL;				}				break;			case EP0_OUT_DATA_PHASE:				if ((!_req->length)					|| ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY)						&& s3c2410_udc_read_fifo(ep,							req))) {					dev->ep0state = EP0_IDLE;					req = NULL;				}				break;			default:				local_irq_restore(flags);				return -EL2HLT;			}		} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0				&& (!(ep_csr&S3C2410_UDC_OCSR1_PKTRDY))				&& s3c2410_udc_write_fifo(ep, req)) {			req = NULL;		} else if ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY)				&& fifo_count				&& s3c2410_udc_read_fifo(ep, req)) {			req = NULL;		}	}	/* pio or dma irq handler advances the queue. */	if (likely (req != 0))		list_add_tail(&req->queue, &ep->queue);	local_irq_restore(flags);	dprintk(DEBUG_VERBOSE, "%s ok\n", __func__);	return 0;}/* *	s3c2410_udc_dequeue */static int s3c2410_udc_dequeue(struct usb_ep *_ep, struct usb_request *_req){	struct s3c2410_ep	*ep = to_s3c2410_ep(_ep);	struct s3c2410_udc	*udc;	int			retval = -EINVAL;	unsigned long		flags;	struct s3c2410_request	*req = NULL;	dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req);	if (!the_controller->driver)		return -ESHUTDOWN;	if (!_ep || !_req)		return retval;	udc = to_s3c2410_udc(ep->gadget);	local_irq_save (flags);	list_for_each_entry (req, &ep->queue, queue) {		if (&req->req == _req) {			list_del_init (&req->queue);			_req->status = -ECONNRESET;			retval = 0;			break;		}	}	if (retval == 0) {		dprintk(DEBUG_VERBOSE,			"dequeued req %p from %s, len %d buf %p\n",			req, _ep->name, _req->length, _req->buf);		s3c2410_udc_done(ep, req, -ECONNRESET);	}	local_irq_restore (flags);	return retval;}/* * s3c2410_udc_set_halt */static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value){	struct s3c2410_ep	*ep = to_s3c2410_ep(_ep);	u32			ep_csr = 0;	unsigned long		flags;	u32			idx;	if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {		dprintk(DEBUG_NORMAL, "%s: inval 2\n", __func__);		return -EINVAL;	}	local_irq_save (flags);	idx = ep->bEndpointAddress & 0x7F;	if (idx == 0) {		s3c2410_udc_set_ep0_ss(base_addr);		s3c2410_udc_set_ep0_de_out(base_addr);	} else {		udc_write(idx, S3C2410_UDC_INDEX_REG);		ep_csr = udc_read((ep->bEndpointAddress &USB_DIR_IN)				? S3C2410_UDC_IN_CSR1_REG				: S3C2410_UDC_OUT_CSR1_REG);		if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {			if (value)				udc_write(ep_csr | S3C2410_UDC_ICSR1_SENDSTL,					S3C2410_UDC_IN_CSR1_REG);			else {				ep_csr &= ~S3C2410_UDC_ICSR1_SENDSTL;				udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG);				ep_csr |= S3C2410_UDC_ICSR1_CLRDT;				udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG);			}		} else {			if (value)				udc_write(ep_csr | S3C2410_UDC_OCSR1_SENDSTL,					S3C2410_UDC_OUT_CSR1_REG);			else {				ep_csr &= ~S3C2410_UDC_OCSR1_SENDSTL;				udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG);				ep_csr |= S3C2410_UDC_OCSR1_CLRDT;				udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG);			}		}	}	ep->halted = value ? 1 : 0;	local_irq_restore (flags);	return 0;}static const struct usb_ep_ops s3c2410_ep_ops = {	.enable		= s3c2410_udc_ep_enable,	.disable	= s3c2410_udc_ep_disable,	.alloc_request	= s3c2410_udc_alloc_request,	.free_request	= s3c2410_udc_free_request,	.queue		= s3c2410_udc_queue,	.dequeue	= s3c2410_udc_dequeue,	.set_halt	= s3c2410_udc_set_halt,};/*------------------------- usb_gadget_ops ----------------------------------*//* *	s3c2410_udc_get_frame */static int s3c2410_udc_get_frame(struct usb_gadget *_gadget){	int tmp;	dprintk(DEBUG_VERBOSE, "%s()\n", __func__);	tmp = udc_read(S3C2410_UDC_FRAME_NUM2_REG) << 8;	tmp |= udc_read(S3C2410_UDC_FRAME_NUM1_REG);	return tmp;}/* *	s3c2410_udc_wakeup */static int s3c2410_udc_wakeup(struct usb_gadget *_gadget){	dprintk(DEBUG_NORMAL, "%s()\n", __func__);	return 0;}/* *	s3c2410_udc_set_selfpowered */static int s3c2410_udc_set_selfpowered(struct usb_gadget *gadget, int value){	struct s3c2410_udc *udc = to_s3c2410_udc(gadget);	dprintk(DEBUG_NORMAL, "%s()\n", __func__);	if (value)		udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);	else		udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);	return 0;}static void s3c2410_udc_disable(struct s3c2410_udc *dev);static void s3c2410_udc_enable(struct s3c2410_udc *dev);static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on){	dprintk(DEBUG_NORMAL, "%s()\n", __func__);	if (udc_info && udc_info->udc_command) {		if (is_on)			s3c2410_udc_enable(udc);		else {			if (udc->gadget.speed != USB_SPEED_UNKNOWN) {				if (udc->driver && udc->driver->disconnect)					udc->driver->disconnect(&udc->gadget);			}			s3c2410_udc_disable(udc);		}	}	else		return -EOPNOTSUPP;	return 0;}static int s3c2410_udc_vbus_session(struct usb_gadget *gadget, int is_active){	struct s3c2410_udc *udc = to_s3c2410_udc(gadget);	dprintk(DEBUG_NORMAL, "%s()\n", __func__);	udc->vbus = (is_active != 0);	s3c2410_udc_set_pullup(udc, is_active);	return 0;}static int s3c2410_udc_pullup(struct usb_gadget *gadget, int is_on){	struct s3c2410_udc *udc = to_s3c2410_udc(gadget);	dprintk(DEBUG_NORMAL, "%s()\n", __func__);	s3c2410_udc_set_pullup(udc, is_on ? 0 : 1);	return 0;}static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev){	struct s3c2410_udc	*dev = _dev;	unsigned int		value;	dprintk(DEBUG_NORMAL, "%s()\n", __func__);	/* some cpus cannot read from an line configured to IRQ! */	s3c2410_gpio_cfgpin(udc_info->vbus_pin, S3C2410_GPIO_INPUT);	value = s3c2410_gpio_getpin(udc_info->vbus_pin);	s3c2410_gpio_cfgpin(udc_info->vbus_pin, S3C2410_GPIO_SFN2);	if (udc_info->vbus_pin_inverted)		value = !value;	if (value != dev->vbus)		s3c2410_udc_vbus_session(&dev->gadget, value);	return IRQ_HANDLED;}static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma){	dprintk(DEBUG_NORMAL, "%s()\n", __func__);	if (udc_info && udc_info->vbus_draw) {		udc_info->vbus_draw(ma);		return 0;	}	return -ENOTSUPP;}

⌨️ 快捷键说明

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