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

📄 s3c2410_udc22222222.c

📁 2.4核linux的s3c2410-udc驱动代码!经过调试了!
💻 C
📖 第 1 页 / 共 3 页
字号:

	spin_lock_irqsave (&udc->lock, flags);
	list_for_each_entry (req, &ep->queue, queue) {
		if (&req->req == _req) {
			list_del_init (&req->queue);
			_req->status = -ECONNRESET;
			retval = 0;
			break;
		}
	}
	spin_unlock_irqrestore (&udc->lock, flags);

	if (retval == 0) {
		dprintk( "dequeued req %p from %s, len %d buf %p\n",
				req, _ep->name, _req->length, _req->buf);

		_req->complete (_ep, _req);
	}
	return retval;
}

static int
s3c2410_set_halt (struct usb_ep *_ep, int value)
{
	struct s3c2410_ep	*ep;

    	printk("s3c2410_set_halt(ep=%p)\n", _ep);

	if (!_ep)
		return -EINVAL;
	if (!the_controller->driver)
		return -ESHUTDOWN;
	ep = container_of (_ep, struct s3c2410_ep, ep);
	if (!value)
		ep->halted = 0;
	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
			!list_empty (&ep->queue))
		return -EAGAIN;
	else
		ep->halted = 1;
	/* FIXME clear emulated data toggle too */
	return 0;
}



static const struct usb_ep_ops s3c2410_ep_ops = {
	.enable		= s3c2410_enable,
	.disable	= s3c2410_disable,

	.alloc_request	= s3c2410_alloc_request,
	.free_request	= s3c2410_free_request,

	.alloc_buffer	= s3c2410_alloc_buffer,
	.free_buffer	= s3c2410_free_buffer,
	/* map, unmap, ... eventually hook the "generic" dma calls */

	.queue		= s3c2410_queue,
	.dequeue	= s3c2410_dequeue,

	.set_halt	= s3c2410_set_halt,
};




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

/* there are both host and device side versions of this call ... */
static int s3c2410_g_get_frame (struct usb_gadget *_gadget)
{
	struct timeval	tv;

    	printk("s3c2410_g_get_frame()\n");

	do_gettimeofday (&tv);
	return tv.tv_usec / 1000;
}

static int s3c2410_wakeup (struct usb_gadget *_gadget)
{
	struct s3c2410_udc  *udc;

    	printk("s3c2410_wakeup()\n");
	
	udc = container_of (_gadget, struct s3c2410_udc, gadget);

	// udc->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
	return 0;
}

static int s3c2410_set_selfpowered (struct usb_gadget *_gadget, int value)
{
	struct s3c2410_udc  *udc;

    	printk("s3c2410_set_selfpowered()\n");

	udc = container_of (_gadget, struct s3c2410_udc, gadget);
	if (value)
		udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
	else
		udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
	return 0;
}

static void nop_release (struct device *dev)
{
	dprintk("%s %s\n", __FUNCTION__, dev->bus_id);
}

static const struct usb_gadget_ops s3c2410_ops = {
	.get_frame	    = s3c2410_g_get_frame,
	.wakeup		    = s3c2410_wakeup,
	.set_selfpowered    = s3c2410_set_selfpowered,
};


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

/* "function" sysfs attribute */
static ssize_t
show_function (struct device *_dev, char *buf)
{
	struct s3c2410_udc *udc = the_controller;

    	printk("s3c2410_show_function(dev=%p)\n", _dev);

	if (!udc->driver->function
		|| strlen (udc->driver->function) > PAGE_SIZE)
		return 0;
	return snprintf (buf, PAGE_SIZE, "%s\n", udc->driver->function);
}

DEVICE_ATTR (function, S_IRUGO, show_function, NULL);



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

/*
 * Driver registration/unregistration.
 *
 * This is basically hardware-specific; there's usually only one real USB
 * device (not host) controller since that's how USB devices are intended
 * to work.  So most implementations of these api calls will rely on the
 * fact that only one driver will ever bind to the hardware.  But curious
 * hardware can be built with discrete components, so the gadget API doesn't
 * require that assumption.
 */


/* caller must hold lock */
static void
stop_activity (struct s3c2410_udc *udc, struct usb_gadget_driver *driver)
{
	struct s3c2410_ep *ep;

    	printk("stop_activity()\n");

	/* prevent any more requests */
	udc->address = 0;

	/* The timer is left running so that outstanding URBs can fail */

	/* nuke any pending requests first, so driver i/o is quiesced */
	list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list)
		nuke (udc, ep);

	/* driver now does any non-usb quiescing necessary */
	if (driver) {
		spin_unlock (&udc->lock);
		driver->disconnect (&udc->gadget);
		spin_lock (&udc->lock);
	}
}


int
usb_gadget_register_driver (struct usb_gadget_driver *driver)
{
	struct s3c2410_udc *udc = the_controller;
	int		retval, i;

    	printk("usb_gadget_register_driver() '%s'\n",
		driver->driver.name);

	if (!udc)
		return -EINVAL;
	if (udc->driver)
		return -EBUSY;
	if (!driver->bind || !driver->unbind || !driver->setup
			|| driver->speed == USB_SPEED_UNKNOWN)
		return -EINVAL;


	udc->gadget.name = gadget_name;
	udc->gadget.ops = &s3c2410_ops;
	udc->gadget.is_dualspeed = 1;

	udc->gadget.dev.release = nop_release;
	udc->devstatus = 0;

	INIT_LIST_HEAD (&udc->gadget.ep_list);
	for (i = 0; i < S3C2410_ENDPOINTS; i++) {
		struct s3c2410_ep *ep = &udc->ep[i];

		if (!ep_name[i])
			break;
		ep->ep.name = ep_name[i];
		ep->ep.ops = &s3c2410_ep_ops;
		list_add_tail (&ep->ep.ep_list, &udc->gadget.ep_list);
		ep->halted = ep->already_seen = ep->setup_stage = 0;
		ep->ep.maxpacket = ~0;
		ep->last_io = jiffies;
		ep->gadget = &udc->gadget;
		ep->dev = udc;
		ep->desc = 0;
		INIT_LIST_HEAD (&ep->queue);
	}

	udc->gadget.ep0 = &udc->ep[0].ep;
	udc->ep[0].ep.maxpacket = 16;
	list_del_init (&udc->ep[0].ep.ep_list);
	INIT_LIST_HEAD(&udc->fifo_req.queue);

	udc->driver = driver;
	udc->gadget.dev.driver = &driver->driver;
	dprintk( "binding gadget driver '%s'\n", driver->driver.name);
	if ((retval = driver->bind (&udc->gadget)) != 0) {
		udc->driver = 0;
		udc->gadget.dev.driver = 0;
		return retval;
	}

        driver->driver.bus = 0;
        udc->driver = driver;
        udc->gadget.dev.driver = &driver->driver;

/*	driver_register (&driver->driver);
	device_bind_driver (&udc->gadget.dev);
*/
        retval = driver->bind(&udc->gadget);
        if (retval) {
                dprintk("bind to driver %s --> error %d\n",
			driver->driver.name, retval);
                udc->driver = 0;
                udc->gadget.dev.driver = 0;
                return retval;
        }

#if 0
	/* khubd will enumerate this in a while */
	udc->port_status |= USB_PORT_STAT_CONNECTION
		| (1 << USB_PORT_FEAT_C_CONNECTION);
#endif
	return 0;
}

EXPORT_SYMBOL (usb_gadget_register_driver);


int
usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
{
	struct s3c2410_udc *udc = the_controller;
	unsigned long	flags;

	if (!udc)
		return -ENODEV;
	if (!driver || driver != udc->driver)
		return -EINVAL;

    	printk("usb_gadget_register_driver() '%s'\n",
		driver->driver.name);

	spin_lock_irqsave (&udc->lock, flags);
	stop_activity (udc, driver);
/*
	udc->port_status &= ~USB_PORT_STAT_CONNECTION;
	udc->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
*/
	spin_unlock_irqrestore (&udc->lock, flags);

	driver->unbind (&udc->gadget);
	udc->driver = 0;

	device_release_driver (&udc->gadget.dev);

	driver_unregister (&driver->driver);

	return 0;
}

EXPORT_SYMBOL (usb_gadget_unregister_driver);

#undef is_enabled



int s3c2410_set_fifo_mode (struct usb_gadget *gadget, int mode)
{
	return -ENOSYS;
}

EXPORT_SYMBOL (s3c2410_set_fifo_mode);




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

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



#define EP0_FIFO_SIZE	16
#define BULK_FIFO_SIZE	64

static struct s3c2410_udc memory;



static inline void clear_ep_state (struct s3c2410_udc *dev)
{
	unsigned i;

	/* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
	 * fifos, and pending transactions mustn't be continued in any case.
	 */
	for (i = 1; i < 5; i++)
		nuke(dev, &dev->ep[i]);

}


enum ep0_state { 
        EP0_IDLE,
        EP0_IN_DATA_PHASE,
        EP0_OUT_DATA_PHASE,
        EP0_END_XFER,
        EP0_STALL,
};

static inline void ep0_idle (struct s3c2410_udc *dev)
{
	dev->ep0state = EP0_IDLE;
}

static inline int windex_to_ep_num( __u16 w ) 
{ 
    	return (int) ( w & 0x000F); 
}


static inline void udc_change_index(int index, int *backup)
{
    	if (backup)
	    	*backup = __raw_readl(S3C2410_UDC_INDEX_REG);
	if ((index >= 0) && (index <= 5))
	    	__raw_writel(index, S3C2410_UDC_INDEX_REG);
}

static inline int fifo_count_out(void)
{
	int tmp;

      	tmp = __raw_readl(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8;
      	tmp |= __raw_readl(S3C2410_UDC_OUT_FIFO_CNT1_REG);

	return tmp & 0xffff;
}

static inline void out_pkt_ack(int last)
{
      	__raw_writel(S3C2410_UDC_EP0_CSR_SOPKTRDY |
	    	(last)?S3C2410_UDC_EP0_CSR_DE:0, 
		S3C2410_UDC_EP0_CSR_REG);
}


/*
 * read_fifo_crq()
 * Read 1-8 bytes out of EP0 FIFO and put in request.
 * Called to do the initial read of setup requests
 * from the host. Return number of bytes read.
 *
 * Like write fifo above, this driver uses multiple
 * reads checked agains the count register with an
 * overall timeout.
 *
 */
static int
read_fifo_crq(struct usb_ctrlrequest *crq)
{
	int bytes_read = 0;
	int fifo_count = 0;
	int i; // , ep;
	unsigned char *pOut = (unsigned char*)crq;
       
    	udc_change_index(0, NULL);
	
	fifo_count = fifo_count_out();

	BUG_ON( fifo_count > 8 );
	dprintk("read_fifo_crq(): fifo_count=%d\n", fifo_count );

	while( fifo_count-- ) {
		i = 0;
		do {
			*pOut = (unsigned char) 
				__raw_readl(S3C2410_UDC_EP0_FIFO_REG); 
		  	udelay( 10 );
  			i++;
			
		} while((fifo_count_out() != fifo_count) && (i < 10));
		if ( i == 10 ) {
			printk("read_fifo(): read failure\n");
			// usbd_info.stats.ep0_fifo_read_failures++;
		}
		pOut++;
		bytes_read++;
	}

	dprintk("read_fifo_crq(): len=%d %02x:%02x {%x,%x,%x}\n", 
	    	bytes_read, crq->bRequest, crq->bRequestType, 
		crq->wValue, crq->wIndex, crq->wLength);
	// usbd_info.stats.ep0_bytes_read++;
	return bytes_read;
}




static void 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 = 0;
	else
		req = list_entry(ep->queue.next, struct s3c2410_request, queue);

  	S3C2410_UDC_SETIX(EP0);
	ep0csr = __raw_readl(S3C2410_UDC_IN_CSR1_REG);

	/* clear stall status */
	if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {
		nuke(dev, ep);
	    	clear_ep0_sst;
/*		del_timer(&dev->timer);*/
		ep0_idle(dev);
	}

	if (ep0csr & S3C2410_UDC_EP0_CSR_SE
	    	&& dev->ep0state != EP0_IDLE) {
	    	clear_ep0_se;
/*		del_timer(&dev->timer);*/
		ep0_idle(dev);
	}


	switch (dev->ep0state) {
	case EP0_IDLE:
		/* start control request? */
		if (ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) {
			int len, ret, tmp;

⌨️ 快捷键说明

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