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

📄 s3c2410_udc22222222.c

📁 2.4核linux的s3c2410-udc驱动代码!经过调试了!
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * linux/drivers/usb/gadget/s3c2410_udc.c
 * Samsung on-chip full speed USB device controllers
 *
 * Copyright (C) 2004 Herbert P鰐zl
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */


#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/version.h>

#include <linux/usb.h>
#include <linux/usb_gadget.h>

/* remove this ASAP!!! */
// #include "../core/hub.h"

#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/arch/irqs.h>

#include <asm/arch/h1940.h>
#include <asm/arch/hardware.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-usb.h>

#include "s3c2410_udc.h"


#define dprintk(x...)	printk("USB: " x)


#define DRIVER_DESC     "S3C2410 USB Device Controller Gadget"
#define DRIVER_VERSION  "14 Mar 2004"

static const char	gadget_name [] = "s3c2410_udc";


/*-------------------------------------------------------------------------*/

struct s3c2410_udc;

struct s3c2410_ep {
	struct list_head		queue;
	unsigned long			last_io;	/* jiffies timestamp */
	struct usb_gadget		*gadget;
	struct s3c2410_udc		*dev;
	const struct usb_endpoint_descriptor *desc;
	struct usb_ep			ep;

	unsigned short			fifo_size;
	u8				bEndpointAddress;
	u8				bmAttributes;

	unsigned			halted : 1;
	unsigned			already_seen : 1;
	unsigned			setup_stage : 1;
};

struct s3c2410_request {
	struct list_head		queue;		/* ep's requests */
	struct usb_request		req;
};


/*-------------------------------------------------------------------------*/

/*
 * Every device has ep0 for control requests, plus up to 30 more endpoints.
 *
 * Gadget drivers are responsible for not setting up conflicting endpoint
 * configurations, illegal or unsupported packet lengths, and so on.
 */

static const char ep0name [] = "ep0";

static const char *const ep_name[] = {
	ep0name,				/* everyone has ep0 */

	/* s3c2410 four bidirectional bulk endpoints */
	"ep1", "ep2", "ep3", "ep4",
};

#define S3C2410_ENDPOINTS	ARRAY_SIZE(ep_name)

#define FIFO_SIZE		64


struct s3c2410_udc {
	spinlock_t			lock;

	struct s3c2410_ep		ep[S3C2410_ENDPOINTS];
	int				address;
	struct usb_gadget		gadget;
	struct usb_gadget_driver	*driver;
	struct s3c2410_request		fifo_req;
	u8				fifo_buf[FIFO_SIZE];
	u16				devstatus;
	
	u32				port_status;
    	int 	    	    	    	ep0state;

	unsigned			got_irq : 1;
	
	unsigned			req_std : 1;
	unsigned			req_config : 1;
	unsigned			req_pending : 1;
};

static struct s3c2410_udc *the_controller;




/*-------------------------------------------------------------------------*/

/*
 *  	Gadget Helpers
 */

static inline
struct s3c2410_udc *ep_to_udc (struct s3c2410_ep *ep)
{
	return container_of (ep->gadget, struct s3c2410_udc, gadget);
}

static inline
struct s3c2410_udc *gadget_dev_to_udc (struct device *dev)
{
	return container_of (dev, struct s3c2410_udc, gadget.dev);
}

/* called with spinlock held */
static void nuke (struct s3c2410_udc *udc, struct s3c2410_ep *ep)
{
	while (!list_empty (&ep->queue)) {
		struct s3c2410_request	*req;

		req = list_entry (ep->queue.next, struct s3c2410_request, queue);
		list_del_init (&req->queue);
		req->req.status = -ESHUTDOWN;

		spin_unlock (&udc->lock);
		req->req.complete (&ep->ep, &req->req);
		spin_lock (&udc->lock);
	}
}

static void
fifo_complete (struct usb_ep *ep, struct usb_request *req)
{

	dprintk( "fifo_complete: %d\n", req->status);

}


/*-------------------------------------------------------------------------*/

/*
 *  	Gadget Operations
 */


static int
s3c2410_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
{
	struct s3c2410_udc	*udc;
	struct s3c2410_ep	*ep;
	unsigned		max;
	int			retval;


    	printk("s3c2410_enable():\n");

	ep = container_of (_ep, struct s3c2410_ep, ep);
/*		
	if (!the_controller->driver || !is_enabled ())
		return -ESHUTDOWN;
*/
	max = desc->wMaxPacketSize & 0x3ff;

	/* drivers must not request bad settings, since lower levels
	 * (hardware or its drivers) may not check.  some endpoints
	 * can't do iso, many have maxpacket limitations, etc.
	 */
	udc = container_of (ep->gadget, struct s3c2410_udc, gadget);
	retval = -EINVAL;
	switch (desc->bmAttributes & 0x03) {
	case USB_ENDPOINT_XFER_BULK:
		switch (udc->gadget.speed) {
		case USB_SPEED_HIGH:
			if (max == 512)
				break;
			/* conserve return statements */
		default:
			switch (max) {
			case 8: case 16: case 32: case 64:
				/* we'll fake any legal size */
				break;
			default:
		case USB_SPEED_LOW:
				goto done;
			}
		}
		break;
	case USB_ENDPOINT_XFER_INT:
		switch (udc->gadget.speed) {
		case USB_SPEED_HIGH:
			if (max <= 1024)
				break;
			/* save a return statement */
		case USB_SPEED_FULL:
			if (max <= 64)
				break;
			/* save a return statement */
		default:
			if (max <= 8)
				break;
			goto done;
		}
		break;
	case USB_ENDPOINT_XFER_ISOC:
		/* real hardware might not handle all packet sizes */
		switch (udc->gadget.speed) {
		case USB_SPEED_HIGH:
			if (max <= 1024)
				break;
			/* save a return statement */
		case USB_SPEED_FULL:
			if (max <= 1023)
				break;
			/* save a return statement */
		default:
			goto done;
		}
		break;
	default:
		/* few chips support control except on ep0 */
		goto done;
	}

	_ep->maxpacket = max;
	ep->desc = desc;

	dprintk( "enabled %s (ep%d%s-%s) maxpacket %d\n",
		_ep->name,
		desc->bEndpointAddress & 0x0f,
		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
		({ char *val;
		 switch (desc->bmAttributes & 0x03) {
		 case USB_ENDPOINT_XFER_BULK: val = "bulk"; break;
		 case USB_ENDPOINT_XFER_ISOC: val = "iso"; break;
		 case USB_ENDPOINT_XFER_INT: val = "intr"; break;
		 default: val = "ctrl"; break;
		 }; val; }),
		max);

	/* at this point real hardware should be NAKing transfers
	 * to that endpoint, until a buffer is queued to it.
	 */
	retval = 0;
done:
	return retval;
}


static int s3c2410_disable (struct usb_ep *_ep)
{
	struct s3c2410_ep	*ep;
	struct s3c2410_udc	*udc;
	unsigned long		flags;
	int			retval;

    	printk("s3c2410_disable()\n");
	
	ep = container_of (_ep, struct s3c2410_ep, ep);
	if (!_ep || !ep->desc || _ep->name == ep0name)
		return -EINVAL;
	udc = ep_to_udc (ep);

	spin_lock_irqsave (&udc->lock, flags);
	ep->desc = 0;
	retval = 0;
	nuke (udc, ep);
	spin_unlock_irqrestore (&udc->lock, flags);

	dprintk( "disabled %s\n", _ep->name);
	return retval;
}


static struct usb_request *
s3c2410_alloc_request (struct usb_ep *_ep, int mem_flags)
{
	struct s3c2410_ep	*ep;
	struct s3c2410_request	*req;

    	printk("s3c2410_alloc_request(ep=%p,flags=%d)\n", _ep, mem_flags);

	ep = container_of (_ep, struct s3c2410_ep, ep);
	if (!_ep)
		return 0;

	req = kmalloc (sizeof *req, mem_flags);
	if (!req)
		return 0;
	memset (req, 0, sizeof *req);
	INIT_LIST_HEAD (&req->queue);
	return &req->req;
}

static void
s3c2410_free_request (struct usb_ep *_ep, struct usb_request *_req)
{
	struct s3c2410_ep	*ep;
	struct s3c2410_request	*req;

    	printk("s3c2410_free_request(ep=%p,req=%p)\n", _ep, _req);

	ep = container_of (_ep, struct s3c2410_ep, ep);
	if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
		return;

	req = container_of (_req, struct s3c2410_request, req);
	WARN_ON (!list_empty (&req->queue));
	kfree (req);
}


static void *
s3c2410_alloc_buffer (
	struct usb_ep *_ep,
	unsigned bytes,
	dma_addr_t *dma,
	int mem_flags)
{
	char *retval;

    	printk("s3c2410_alloc_buffer()\n");

	if (!the_controller->driver)
		return 0;
	retval = kmalloc (bytes, mem_flags);
	*dma = (dma_addr_t) retval;
	return retval;
}

static void
s3c2410_free_buffer (
	struct usb_ep *_ep,
	void *buf,
	dma_addr_t dma,
	unsigned bytes)
{
    	printk("s3c2410_free_buffer()\n");

	if (bytes)
		kfree (buf);
}


static int
s3c2410_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags)
{
	struct s3c2410_ep	*ep;
	struct s3c2410_request	*req;
	struct s3c2410_udc	*udc;
	unsigned long		flags;

    	printk("s3c2410_queue(ep=%p,req=%p,mem=%d)\n",
	    	_ep, _req, mem_flags);

	req = container_of (_req, struct s3c2410_request, req);
	if (!_req || !list_empty (&req->queue) || !_req->complete)
		return -EINVAL;

	ep = container_of (_ep, struct s3c2410_ep, ep);
	if (!_ep || (!ep->desc && _ep->name != ep0name))
		return -EINVAL;

/*
	if (!the_controller->driver || !is_enabled ())
		return -ESHUTDOWN;
*/
	udc = container_of (ep->gadget, struct s3c2410_udc, gadget);

	dprintk( "ep %p queue req %p to %s, len %d buf %p\n",
		ep, _req, _ep->name, _req->length, _req->buf);

	_req->status = -EINPROGRESS;
	_req->actual = 0;
	spin_lock_irqsave (&udc->lock, flags);

	/* implement an emulated single-request FIFO */
	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
			list_empty (&udc->fifo_req.queue) &&
			list_empty (&ep->queue) &&
			_req->length <= FIFO_SIZE) {
		req = &udc->fifo_req;
		req->req = *_req;
		req->req.buf = udc->fifo_buf;
		memcpy (udc->fifo_buf, _req->buf, _req->length);
		req->req.context = udc;
		req->req.complete = fifo_complete;

		spin_unlock (&udc->lock);
		_req->actual = _req->length;
		_req->status = 0;
		_req->complete (_ep, _req);
		spin_lock (&udc->lock);
	}
	list_add_tail (&req->queue, &ep->queue);
	spin_unlock_irqrestore (&udc->lock, flags);

	/* real hardware would likely enable transfers here, in case
	 * it'd been left NAKing.
	 */
	return 0;
}

static int s3c2410_dequeue (struct usb_ep *_ep, struct usb_request *_req)
{
	struct s3c2410_ep	*ep;
	struct s3c2410_udc	*udc;
	int			retval = -EINVAL;
	unsigned long		flags;
	struct s3c2410_request	*req = 0;

    	printk("s3c2410_dequeue(ep=%p,req=%p)\n", _ep, _req);

	if (!the_controller->driver)
		return -ESHUTDOWN;

	if (!_ep || !_req)
		return retval;
	ep = container_of (_ep, struct s3c2410_ep, ep);
	udc = container_of (ep->gadget, struct s3c2410_udc, gadget);

⌨️ 快捷键说明

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