自娱自乐8之Linux UDC驱动4(自编udc驱动,基本功能完成)

直接上代码,可以和我之前写的模板比较比较

/***********************************
 Copyright(C), 2013 LDP
 FileName:  s3c2440_udc.h
 Author:    wwxxxxll
 Date:          
 Description:  
 History:       
 Author       Date            Desc
************************************/
#ifndef __S3C2440_UDC_H__
#define __S3C2440_UDC_H__
/*************配置选项**************/
#define S3C2440_DEBUG_FS  //使用debugfs
#define DEBUG
#ifdef DEBUG
#define printInfo(ARGs...) printk(ARGs)
#else
#define printInfo(ARGs...)
#endif
//struct usb_ep_ops
//#define S3C2440_NEWSTYLE  //使用udc_start
#define S3C2440_SETWEDHE  //实现set_weght方法
#define S3C2440_FIFO_STATUS //支持fifo_status方法
#define S3C2440_FIFO_FLUSH //支持fifo_flush方法

//struct usb_gadget_ops
#define S3C2440_S3C2440_GET_FRAME //支持get_frame
#define S3C2440_WAKEUP //支持wakeup功能
#define S3C2440_SELFPOWERED //selfpowered支持
//#define S3C2440_VBUS_SESSION //vbus连接控制支持
//#define S3C2440_VBBUS_DRAW
#define S3C2440X_PULLUP //usb连接控制支持

//s3c2440 有时钟控制
//寄存器CLKSLOW开启UPLL
//CLKCON开启USB device时钟,我会定义两个clk,见下面的结构体
//我可以直接操作寄存器,但是那样太粗鲁了,我们还是用平台提供
//的时钟机制解决吧
#define S3C2440_HAVE_CLK  //有专用的CLK
#ifdef S3C2440_HAVE_CLK
#define CLK_DELAY_TIME 10 //ms
#endif

#define S3C2440_USE_IRQ

//端口信息
#define S3C2440_ENDPOINTS 5 //端口数
//一个端点的最大数据包
#define EP0_FIFO_SIZE 8
#define EP1_FIFO_SIZE 64
#define EP2_FIFO_SIZE 64
#define EP3_FIFO_SIZE 64
#define EP4_FIFO_SIZE 64

#define EP1_ADDRESS 1
#define EP2_ADDRESS 2
#define EP3_ADDRESS 3
#define EP4_ADDRESS 4

#define EP1_ATTR USB_ENDPOINT_XFER_BULK
#define EP2_ATTR USB_ENDPOINT_XFER_BULK
#define EP3_ATTR USB_ENDPOINT_XFER_BULK
#define EP4_ATTR USB_ENDPOINT_XFER_BULK

//fifo长度
#define S3C2440_EP0_FIFO_SIZE 16
#define S3C2440_EP1_FIFO_SIZE 128
#define S3C2440_EP2_FIFO_SIZE 128
#define S3C2440_EP3_FIFO_SIZE 128
#define S3C2440_EP4_FIFO_SIZE 128
/***********************************/

/*************寄存器定义************/
//s3c2440 有个MISCCR控制usb1为设备还是主机
//芯片默认为设备,我就不控制了。MISCCR的USB挂起
//主要为芯片进入睡眠时用的
//如果按字节模式访问则偏移地址在大端和小端模式中是不同的。
//我是小端的地址
#define FUNC_ADDR_REG 0x140
//func_addr_reg 存储usb地址,更新地址时,第7位置位
#define PWR_REG       0x144
/*
pwr_reg:
3: USB_RESET R  主机发复位信号,由USB置位
2: MCS_RESUME R/W MCU置位来给MCU重置,在挂起模式时,产生10ms重置信号
1: SUSPEND_MODE R 设备进入挂起模式时由USB置位。
0: SUBSPEND_EN R 挂起使能位,0:禁止 1:使能
*/
//一旦 MCU 发生中断,MCU 应该读取中断相关寄存器的内容并且如果需要写回清除其内容。
#define EP_INT_REG 0x148
#define USB_INT_REG 0x158

//中断使能
#define EP_INT_EN_REG 0x15c
#define USB_INT_EN_REG 0x16c

//帧号
#define FRAME_NUM1_REG 0x170 //低字节
#define FRAME_NUM2_REG 0x174 //高字节

//通常被标记的寄存器随INDEX寄存器(INDEX_REG)(偏移地址:0X178)值而定。例如如果希望改写EP0 
//CSR寄存器,必须在写IN_CSR1寄存器前写入‘0x00’到INDEX_REG中
#define INDEX_REG 0x178

#define MAXP_REG 0x180
/*
推荐:
EP0 MAXP=8
EP1~4 MAXP=64, 64自动使能双数据包模式 就是data0和data1
*/

#define EP0_CSR 0x184 

#define IN_CSR1_REG 0x184
#define IN_CSR2_REG 0x188

#define OUT_CSR1_REG 0x190
#define OUT_CSR2_REG 0x194

//FIFO
//端点输出写计数寄存器
//此寄存器保存着包的字节数,该数由MCU卸载
#define OUT_FIFO_CNT1 0x198
#define OUT_FIFO_CNT2 0x19c

//EPn_FIFO_REG使能MCU访问EPn FIFO
#define EP0_FIFO 0x1c0
#define EP1_FIFO 0x1c4
#define EP2_FIFO 0x1c8
#define EP3_FIFO 0x1cc
#define EP4_FIFO 0x1d0

//DMA
#define EP1_DMA_CON 0x200
#define EP2_DMA_CON 0x218
#define EP3_DMA_CON 0x240
#define EP4_DMA_CON 0x258

#define EP1_DMA_UNIT 0x204
#define EP2_DMA_UNIT 0x21c
#define EP3_DMA_UNIT 0x244
#define EP4_DMA_UNIT 0x25c

#define EP1_DMA_FIFO 0x208
#define EP2_DMA_FIFO 0x220
#define EP3_DMA_FIFO 0x248
#define EP4_DMA_FIFO 0x260

#define EP1_DMA_TTC_L 0x20c
#define EP1_DMA_TTC_M 0x210
#define EP1_DMA_TTC_H 0x214
#define EP2_DMA_TTC_L 0x224
#define EP2_DMA_TTC_M 0x228
#define EP2_DMA_TTC_H 0x22c
#define EP3_DMA_TTC_L 0x24c
#define EP3_DMA_TTC_M 0x250 
#define EP3_DMA_TTC_H 0x254
#define EP4_DMA_TTC_L 0x264
#define EP4_DMA_TTC_M 0x268
#define EP4_DMA_TTC_H 0x26c

/***********************************/

/************操作定义***************/
#define WRITE_REG(_s3c2440_udc, reg, data) writel(data, _s3c2440_udc->virl_addr + reg)
#define READ_REG(_s3c2440_udc, reg) readl(_s3c2440_udc->virl_addr + reg)

#define SETB(_s3c2440_udc, reg, n) (writel((readl(_s3c2440_udc->virl_addr + reg) | (1 << n)), _s3c2440_udc->virl_addr + reg))
#define CLRB(_s3c2440_udc, reg, n) (writel((readl(_s3c2440_udc->virl_addr + reg) & (~(1 << n))), _s3c2440_udc->virl_addr + reg))

#define GETB(_s3c2440_udc, reg, n) ((readl(_s3c2440_udc->virl_addr + reg) >> n) & 1)


//我的D+控制口为gpc5,这里我也偷懒了,没有mmap gpio,用了平台的
#define PULL_UP()    do { \
                       writel((readl(S3C2410_GPCCON) | (1 << 10)) & (~(1 << 11)), S3C2410_GPCCON); \
                       writel(readl(S3C2410_GPCUP) & (~(1 << 5)), S3C2410_GPCUP); \
                       writel(readl(S3C2410_GPCDAT) | (1 << 5), S3C2410_GPCDAT); \
                   }while(0);

#define PULL_DOWN() do { \
                       writel((readl(S3C2410_GPCCON) | (1 << 10)) & (~(1 << 11)), S3C2410_GPCCON); \
                       writel(readl(S3C2410_GPCUP) & (~(1 << 5)), S3C2410_GPCUP); \
                       writel(readl(S3C2410_GPCDAT) & (~(1 << 5)), S3C2410_GPCDAT); \
                   }while(0);

/***********************************/

/*************简单操作**************/
//清楚setup_end标志
#define EP0_CLRSE(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 SETB(_s3c2440_udc, EP0_CSR, 7); \
                                }while(0)

//out数据已读完标志
#define EP0_CLROPR(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 SETB(_s3c2440_udc, EP0_CSR, 6); \
                                }while(0)

#define EP0_SETDE(_s3c2440_udc) do {\
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 SETB(_s3c2440_udc, EP0_CSR, 3); \
                                }while(0)                            

//清楚stall标志
#define EP0_CLRSST(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 CLRB(_s3c2440_udc, EP0_CSR, 5); \
                                }while(0)  
//发送stall
#define EP0_SETSST(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 SETB(_s3c2440_udc, EP0_CSR, 5); \
                                }while(0)          

//清楚数据异常
#define EP0_CLRDE(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 CLRB(_s3c2440_udc, EP0_CSR, 2); \
                                }while(0)

//in数据已写完标志
#define EP0_SETIPR(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 SETB(_s3c2440_udc, EP0_CSR, 1);  \
                                }while(0) 
/***********************************/


struct s3c2440_ep 
{
    struct usb_ep ep; //描述一个端点
    struct list_head queue;
    struct s3c2440_udc *dev;
    const struct usb_endpoint_descriptor *desc;

    unsigned char fifosize;
    unsigned char bEndpointAddress;
    unsigned char bmAttributes;

    u16 fifo_size;
    u8 num;

    unsigned stopped :1;//维护一个端口停止标志

#ifdef S3C2440_SETWEDHE
    unsigned wedged :1;
#endif
};

#define to_s3c2440_ep(ep_p) container_of(ep_p, struct s3c2440_ep, ep)

struct s3c2440_request 
{
    struct list_head        queue;        /* ep's requests */
    struct usb_request        req;        //对应主机端看到的urb
};

#define to_s3c2440_req(req_p) container_of(req_p, struct s3c2440_request, req)

//根据实际要求定义,这个不能当做模板,主要是便于软件管理
//一般有下面几个,有的驱动不用这些定义去管理
enum ep0state {
    EP0_IDLE,
    EP0_IN, 
    EP0_OUT,    
    EP0_STALL,        
};
    
struct s3c2440_udc 
{
    spinlock_t lock;
    
    void __iomem *virl_addr;
    u32 phy_addr;
    u32 reg_size;

    struct usb_gadget gadget;
    struct usb_gadget_driver *driver;

    enum ep0state ep0state;
    struct s3c2440_ep ep[S3C2440_ENDPOINTS];
    struct s3c2440_request fifo_req;

#ifdef S3C2440_DEBUG_FS
    struct dentry *debug_info;
#endif 

#ifdef S3C2440_HAVE_CLK
    struct clk *s3c2440_clk_upll;
    struct clk *s3c2440_clk_udc;
#endif

#ifdef S3C2440_USE_IRQ
    unsigned int irq_num;
#endif

    u16    devstatus;
};

#define to_s3c2440_udc(gadget_p) container_of(gadget_p, struct s3c2440_udc, gadget)

#endif//__S3C2440_UDC_H__

/***********************************
 Copyright(C), 2013 LDP
 FileName:  s3c2440_udc.c
 Author:    wwxxxxll
 Date:          
 Description: linux-3.2-36
 History:       
 Author       Date            Desc
************************************/

#include <linux/module.h>//MODULE_*
#include <linux/init.h>//printInfo
#include <linux/slab.h>//kzalloc() kfree()
#include <linux/usb/gadget.h>//struct usb_gadget等
#include <linux/clk.h>//struct clk
#include <linux/platform_device.h>//platform
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/prefetch.h>

#include <asm/irq.h>
#include <asm/io.h>//ioremap

#include <mach/regs-gpio.h>

#include "s3c2440_udc.h"

#ifdef S3C2440_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/seq_file.h>//seq_printf seq_read
#endif

#define DRIVER_DESC    "S3C2440 USB Device Controller Gadget"
#define DRIVER_VERSION    "2013"
#define DRIVER_AUTHOR    "wwxxxxll"

static const char        gadget_name[] = "s3c2440_udc";
static const char        driver_desc[] = DRIVER_DESC;



//根据实际情况修改
//在epautoconf.c会看到
/* type-restriction:  "-iso", "-bulk", or "-int".
 * direction-restriction:  "in", "out".
 */
//我们
static const char ep0name[] = "ep0";
static const char * const ep_name[] = {
    ep0name,
    "ep1-bulk", "ep2-bulk", "ep3-bulk", "ep4-bulk",
};
//需要mount -t debugfs none /sys/kernel/debug/
///sys/kernel/debug
#ifdef S3C2440_DEBUG_FS
static struct dentry *s3c2440_udc_debugfs_root;

static int s3c2440_udc_debugfs_seq_show(struct seq_file *m, void *p)
{
    seq_printf(m, "My name is %s\n", gadget_name);

    return 0;
}

static int s3c2440_udc_debugfs_fops_open(struct inode *inode,
                     struct file *file)
{
    return single_open(file, s3c2440_udc_debugfs_seq_show, NULL);
}

static const struct file_operations s3c2440_udc_debugfs_fops = 
{
    .open        = s3c2440_udc_debugfs_fops_open,
    .read        = seq_read,
    .llseek        = seq_lseek,
    .release    = single_release,
    .owner        = THIS_MODULE,
};
#endif

/***********************hardware_handler************************/
//s3c2440没有控制usb开启位,就等到start时使能中断,imx不是这样
static void s3c2440_usb_reset(struct s3c2440_udc *dev)
{
    //disable intterupt
    WRITE_REG(dev, EP_INT_EN_REG, 0x00);
    WRITE_REG(dev, USB_INT_EN_REG, 0x00);

    //clear intterupt flag
    WRITE_REG(dev, EP_INT_REG, 0x1f);
    WRITE_REG(dev, USB_INT_REG, 0x07);

    PULL_DOWN();

    dev->gadget.speed = USB_SPEED_UNKNOWN;
}

static void s3c2440_udc_enable(struct s3c2440_udc *dev)
{
    int i;

    dev->gadget.speed = USB_SPEED_FULL;//s3c2440只支持1.1

    for (i = 0; i < S3C2440_ENDPOINTS; i++)//最大包设置
    {
        WRITE_REG(dev, INDEX_REG, i);
        WRITE_REG(dev, MAXP_REG, dev->ep[i].ep.maxpacket >> 3);
    }

    //SETB(dev, PWR_REG, 0);//enable suspend模式

    //enable intterupt
    SETB(dev, EP_INT_EN_REG, 0);
    WRITE_REG(dev, USB_INT_EN_REG, 0x07);

#ifndef S3C2440_NEWSTYLE
    PULL_UP();
#endif
}

static void s3c2440_usb_fifocnt(struct s3c2440_udc *dev, u32 *fifo_size)
{
    *fifo_size = READ_REG(dev, OUT_FIFO_CNT1);
    *fifo_size |= READ_REG(dev, OUT_FIFO_CNT2) << 8;
}

static u32 s3c2440_read_ctrlq(struct s3c2440_udc *dev, struct usb_ctrlrequest *_ctrlq)
{
    u32 count;

    WRITE_REG(dev, INDEX_REG, 0);
    s3c2440_usb_fifocnt(dev, &count);

    count = (count > sizeof(struct usb_ctrlrequest)) ? sizeof(struct usb_ctrlrequest) : count;

    readsb(EP0_FIFO + dev->virl_addr, (unsigned char *)_ctrlq, count);

    /*
    _ctrlq->bRequest
    bit7: 方向 10 int 0: out
    bit 6:5: 请求类型
    bit 4:0: 接收者
    */
    printInfo(  "Host: bRequest = %02x bRequestType = %02x \
wValue = 0x%x wIndex=0x%x wLength=0x%x\n", _ctrlq->bRequest, _ctrlq->bRequestType, \
        _ctrlq->wValue, _ctrlq->wIndex, _ctrlq->wLength);

    return count;
}

static int s3c2440_get_status(struct s3c2440_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://2.0为预留
		break;

	case USB_RECIP_DEVICE://设备状态是0位表示供电方式,1位表示是否可以远程唤醒
		status = dev->devstatus;
		break;

	case USB_RECIP_ENDPOINT://0位表示halt,如果当前的ep为halt,此位为1
		if (ep_num > 4 || crq->wLength > 2)//crq->wLength为2
			return 1;

		WRITE_REG(dev, INDEX_REG, ep_num);

		status = 0;

		if (ep_num == 0) 
		{
			status = GETB(dev, EP0_CSR, 5);
		} 
		else 
		{
			if (is_in) 
			{
				status = GETB(dev, IN_CSR1_REG, 4);
			} 
			else 
			{
				status = GETB(dev, OUT_CSR1_REG, 5);
			}
		}

		break;

	default:
		return 1;
	}

	WRITE_REG(dev, EP0_FIFO, status & 0xFF);
	WRITE_REG(dev, EP0_FIFO, status >> 8);

    EP0_SETIPR(dev);
    EP0_SETDE(dev);

	return 0;
}

static void s3c2440_udc_done(struct s3c2440_ep *ep, struct s3c2440_request *req, int status);

/*
返回
1: 读包结束
0: 还没读完
-1: 错误
*/
static int s3c2440_read_fifo(struct s3c2440_udc *dev, struct s3c2440_ep *ep, struct s3c2440_request *req)
{
    u32 fifo_reg;
    u8 *buf;
    u32 idx = 0;
    u32 avail, len, bufspace;
    u32 fifo_count = 0;
    int ret = 0;

    //printInfo(  "%s\n", __func__);

    idx = ep->bEndpointAddress & 0x7f;

    if (idx > 4)
    {
        idx = 0;
    }

	WRITE_REG(dev, INDEX_REG, idx);

	s3c2440_usb_fifocnt(dev, &fifo_count);
	
	if (fifo_count == 0)
	{
		return 0;
	}

    fifo_reg = EP0_FIFO + 4 * idx;

    if (req->req.length == 0)
    {
        return 1;
    }

    if (req->req.length <= req->req.actual)
    {
        return -1;
    }

    bufspace = req->req.length - req->req.actual;
    buf = req->req.buf + req->req.actual;

    avail = (fifo_count > ep->ep.maxpacket) ? ep->ep.maxpacket : fifo_count;//一次最多读ep->ep.maxpacket
    
    len = (bufspace < avail) ? bufspace : avail;
    req->req.actual += len;

    readsb(fifo_reg + dev->virl_addr, buf, len);

    //req->req.actual已接收长度,req->req.length要接收的总长度
    //printInfo("read: fifo_count = %d, req->req.actual = %d, req->req.length = %d len = %d avail = %d\n", fifo_count, req->req.actual, req->req.length, len, avail);

	
    if (fifo_count < ep->ep.maxpacket)
    {
        ret = 1;

        if (len != avail)
        {
            req->req.status = -EOVERFLOW;//溢出
        }
    }

    if (ret)
    { 
        if (idx == 0) 
        {
            EP0_SETDE(dev);
            ep->dev->ep0state = EP0_IDLE;
        } 
        else 
        {
			CLRB(dev, OUT_CSR1_REG, 0);
        }

        s3c2440_udc_done(ep, req, 0);
    } 
	else 
    {
        if (idx == 0) 
        {
            EP0_CLROPR(dev);
        } 
        else 
        {
			//SETB(dev, OUT_CSR1_REG, 4);
			CLRB(dev, OUT_CSR1_REG, 0);
        }
    }
    return ret;
}

#ifdef DEBUG
static int printDesc = 0;
#endif

static int s3c2440_write_fifo(struct s3c2440_udc *dev, struct s3c2440_ep *ep, struct s3c2440_request *req)
{
    u32 fifo_reg;
    u8 *buf;
    u32 idx = 0;
    u32 len;
    int ret = 0;

    struct usb_device_descriptor    *desc;
    struct usb_string_descriptor    *string;
    struct usb_config_descriptor    *config;
    u16                language;
    u32                 n;
    u8                *tmp;

#ifdef DEBUG
    //printInfo(  "%s\n", __func__);

    switch (printDesc) 
    {
    case USB_DT_DEVICE:
        desc = (struct usb_device_descriptor*)req->req.buf;

        printInfo(  "Slave: length = %d Vendor = %x Product = %x Device = %x iManufacturer = %d iProduct = %d iSerialNumber = %d bNumConfigurations = %d\n", \
           desc->bLength, le16_to_cpu(desc->idVendor), le16_to_cpu(desc->idProduct), le16_to_cpu(desc->bcdDevice),\
           desc->iManufacturer,desc->iProduct,desc->iSerialNumber,desc->bNumConfigurations);

        break;
    case USB_DT_DEVICE_QUALIFIER: 
        break;
    case USB_DT_OTHER_SPEED_CONFIG:
        break;
    case USB_DT_CONFIG:
        config = (struct usb_config_descriptor *)req->req.buf;

        printInfo(  "Slave: length = %d TotalLength = %d NumInterfaces = %d ConfigurationValue = %d iConfiguration = %d bMaxPower = %d\n", \
           config->bLength, le16_to_cpu(config->wTotalLength), config->bNumInterfaces, config->bConfigurationValue, config->iConfiguration, config->bMaxPower);

        break;
    case USB_DT_STRING:
        string = (struct usb_string_descriptor *)req->req.buf;
        printInfo(  "Slave: length = %d\n", string->bLength);
        language = cpu_to_le16(0x0409);//这里偷工减料了,因为gadget是我自己写的我知道是什么语言

        if (string->bLength == 4)//支持语言数量
        {
            break;
        }
        for (tmp = (u8 *)string->wData, n = 0; n < string->bLength; n++, tmp++) 
        {
            if (*tmp == language)
            {
            }
            else
            {
                printInfo( "%c", *tmp);//没考虑大小端
            }
        }

        printInfo("\n");

        break;
    case USB_DT_BOS: 
        break;
    default:
        break;
    }

    printDesc = 0;
#endif

    idx = ep->bEndpointAddress & 0x7f;

    if (idx > 4)
    {
        idx = 0;
    }

    fifo_reg = EP0_FIFO + 4 * idx;

    len = ((req->req.length - req->req.actual) < ep->ep.maxpacket) ? (req->req.length - req->req.actual) : ep->ep.maxpacket;
    buf = req->req.buf + req->req.actual;

    prefetch(buf);//prefetch将这一块数据读取到cache之中,以便后继快速访问,为了下面的writesb

    req->req.actual += len;

    writesb(fifo_reg + dev->virl_addr, buf, len);

    //req->req.actual已发送长度
    //printInfo(  " %dbytes ", req->req.actual);

    if (len != ep->ep.maxpacket)
        ret = 1;
    else if (req->req.length != req->req.actual || req->req.zero)//zero当要发送的长度小于请求长度是为1
        ret = 0;
    else
        ret = 2;

    //printInfo(   \
            "Written ep%d %d.%d of %d b [last %d,z %d], max = %d\n", \
            idx, len, req->req.actual, req->req.length, \
             ret, req->req.zero,ep->ep.maxpacket);
    if (ret)
    {
        if (idx == 0)
        {
            if (!GETB(dev, USB_INT_REG, 2))
            {  
                EP0_SETIPR(dev);
                EP0_SETDE(dev);
            }
            ep->dev->ep0state = EP0_IDLE;
        }
        else
        {
            SETB(dev, IN_CSR1_REG, 0);
        }
		printInfo("write done\n");

        s3c2440_udc_done(ep, req, 0);
    }
    else
    {
        if (idx == 0)
        {
            if (!GETB(dev, USB_INT_REG, 2))
            {  
                EP0_SETIPR(dev);
            }
        }
        else
        {
            SETB(dev, IN_CSR1_REG, 0);
        }
    }

    return ret;
}

static void s3c2440_dequeue_all(struct s3c2440_ep *ep, int status);
static int s3c2440_udc_set_halt(struct usb_ep *_ep, int value);

static void s3c2440_udc_handle_ep0_idle(struct s3c2440_udc *dev, struct s3c2440_ep *ep, u32 ep0_csr)
{
    struct usb_ctrlrequest ctrlq;
    int tmp;
    bool config = 0;

    //printInfo(  "%s\n", __func__);

    if (!(ep0_csr & 1))//判断数据是否接收完成
    {
        return;
    }

    s3c2440_dequeue_all(ep, -EPROTO);

    if (s3c2440_read_ctrlq(dev, &ctrlq) < sizeof(struct usb_ctrlrequest))
    {
        EP0_SETSST(dev);

        return;
    }

    //EP0_CLROPR是数据接收结束,EP0_SETDE是数据传输结束
    switch (ctrlq.bRequest)
    {
    case USB_REQ_GET_STATUS: printInfo(  "USB_REQ_GET_STATUS\n");
        EP0_CLROPR(dev);
        if ((ctrlq.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
        {
			if (!s3c2440_get_status(dev, &ctrlq)) 
			{
				return;
			}
        }

        break;
    case USB_REQ_CLEAR_FEATURE: printInfo(  "USB_REQ_CLEAR_FEATURE\n");
        EP0_CLROPR(dev);

		if (ctrlq.bRequestType != USB_RECIP_ENDPOINT)
			break;

		if (ctrlq.wValue != USB_ENDPOINT_HALT || ctrlq.wLength != 0)
			break;

		s3c2440_udc_set_halt(&dev->ep[ctrlq.wIndex & 0x7f].ep, 0);

        EP0_CLROPR(dev);
        EP0_SETDE(dev);

		return;
    case USB_REQ_SET_FEATURE: printInfo(  "USB_REQ_SET_FEATURE\n");
        EP0_CLROPR(dev);

		if (ctrlq.bRequestType != USB_RECIP_ENDPOINT)
			break;

		if (ctrlq.wValue != USB_ENDPOINT_HALT || ctrlq.wLength != 0)
			break;

		s3c2440_udc_set_halt(&dev->ep[ctrlq.wIndex & 0x7f].ep, 1);

        EP0_CLROPR(dev);
        EP0_SETDE(dev);

		return;

    case USB_REQ_SET_ADDRESS: printInfo(  "USB_REQ_SET_ADDRESS\n");
        if (ctrlq.bRequestType == USB_RECIP_DEVICE) 
        {
            tmp = ctrlq.wValue & 0x7F;
            WRITE_REG(dev, FUNC_ADDR_REG, (1 << 7) | tmp); 

            EP0_CLROPR(dev);
            EP0_SETDE(dev);
            dev->ep0state = EP0_IDLE;
            return;
        }
        break;

    case USB_REQ_GET_DESCRIPTOR: printInfo(  "USB_REQ_GET_DESCRIPTOR\n");
        switch (ctrlq.wValue >> 8) 
        {
        case USB_DT_DEVICE: printInfo(  "USB_DT_DEVICE\n");
            break;
        //设备限定描述符用于指定另一传输速率下该设备的总体信息,如果高速 USB设备既需要采用高速传输又需
        //要全速传输,则它必须支持设备限定描述符(Device_Qualifier)。全速设备不支持
        case USB_DT_DEVICE_QUALIFIER: printInfo(  "USB_DT_DEVICE_QUALIFIER\n");
            break;
        case USB_DT_OTHER_SPEED_CONFIG: printInfo(  "USB_DT_OTHER_SPEED_CONFIG\n");
            break;
        case USB_DT_CONFIG: printInfo(  "USB_DT_CONFIG\n");
            break;
        case USB_DT_STRING: printInfo(  "USB_DT_STRING\n");
            break;
        //其他速率配置描述符用于指定另一传输速率下该设备的配置信息,如果高速USB设备既需要采用高速传输
        //又需要全速传输,则它必须支持其他速率配置描述符
        case USB_DT_BOS: printInfo(  "USB_DT_BOS\n");
            break;
        }

        EP0_CLROPR(dev);

        break;
    case USB_REQ_SET_DESCRIPTOR: printInfo(  "USB_REQ_SET_DESCRIPTOR\n");
        EP0_CLROPR(dev);
        break;
    case USB_REQ_GET_CONFIGURATION: printInfo(  "USB_REQ_GET_CONFIGURATION\n");
        EP0_CLROPR(dev);
        break;
    case USB_REQ_SET_CONFIGURATION: 
        if (ctrlq.bRequestType == USB_RECIP_DEVICE) 
        {
            printInfo(  "USB_REQ_SET_CONFIGURATION\n");
            config = 1;

            EP0_CLROPR(dev);
            EP0_SETDE(dev);
        }
        break;
    case USB_REQ_GET_INTERFACE: printInfo(  "USB_REQ_GET_INTERFACE\n");
        EP0_CLROPR(dev);
        break;
    case USB_REQ_SET_INTERFACE: 
        if (ctrlq.bRequestType == USB_RECIP_INTERFACE) 
        {
            printInfo(  "SB_REQ_SET_INTERFACE\n");
            config = 1;

            EP0_CLROPR(dev);
            EP0_SETDE(dev);
        }

        break;
    case USB_REQ_SYNCH_FRAME: printInfo(  "USB_REQ_SYNCH_FRAME\n");  
        EP0_CLROPR(dev);
        break;
    }

    if (config != 1)//设置就一次传输就可以了
    {
        if (ctrlq.bRequestType & USB_DIR_IN)
            dev->ep0state = EP0_IN;
        else
            dev->ep0state = EP0_OUT;
    }

    if (!dev->driver)
        return;

#ifdef DEBUG
    //为了queue()中的调试打印设置标志
    switch (ctrlq.bRequest)
    {
    case USB_REQ_GET_DESCRIPTOR:
        switch (ctrlq.wValue >> 8) 
        {
        case USB_DT_DEVICE:printDesc = USB_DT_DEVICE;
            break;
        case USB_DT_DEVICE_QUALIFIER: printDesc = USB_DT_DEVICE_QUALIFIER;
            break;
        case USB_DT_OTHER_SPEED_CONFIG: printDesc = USB_DT_OTHER_SPEED_CONFIG;
            break;
        case USB_DT_CONFIG: printDesc = USB_DT_CONFIG;
            break;
        case USB_DT_STRING: printDesc = USB_DT_STRING;
            break;
        case USB_DT_BOS: 
            break;
        }
        break;
    }
#endif

    if (dev->driver->setup(&dev->gadget, &ctrlq) < 0)
    {
        if (config == 1)//配置错误,不要send stall,会重新选配置
        {
            return;
        }

        EP0_SETSST(dev);
    
        EP0_SETDE(dev);
        dev->ep0state = EP0_IDLE;
    }
}

void s3c2440_handle_ep0(struct s3c2440_udc *dev)
{
    struct s3c2440_ep    *ep = &dev->ep[0];
    struct s3c2440_request *req;
    u32 ep0_csr = 0;

    if (!list_empty(&ep->queue))
        req = list_entry(ep->queue.next, struct s3c2440_request, queue);
    else
        req = NULL;

    WRITE_REG(dev, INDEX_REG, 0);

    ep0_csr = READ_REG(dev, EP0_CSR);

    if (ep0_csr & (1 << 5))//send_stall
    {
        s3c2440_dequeue_all(ep, -EPIPE);//调用complete函数

        EP0_CLRSST(dev);

        dev->ep0state = EP0_IDLE;

        return;
    }
    
    if (ep0_csr & (1 << 4))//setup_end
    {
        s3c2440_dequeue_all(ep, 0);

        EP0_CLRSE(dev);

        dev->ep0state = EP0_IDLE;
    }

    switch (dev->ep0state) {
    case EP0_IDLE:
        s3c2440_udc_handle_ep0_idle(dev, ep, ep0_csr);
        break;

    case EP0_IN:  
        if ((!(ep0_csr & (1 << 1))) && req) 
        {
            s3c2440_write_fifo(dev, ep, req);
        }
        break;

    case EP0_OUT: 
        if ((ep0_csr & 1) && req) 
        {
            s3c2440_read_fifo(dev, ep, req);
        }
        break;

    case EP0_STALL:
        dev->ep0state = EP0_IDLE;
        break;
    }
}

void s3c2440_handle_ep(struct s3c2440_udc *dev, u8 n)
{
    struct s3c2440_ep    *ep = &dev->ep[n];
    struct s3c2440_request *req;
	u32 ep_csr1;

    if (!list_empty(&ep->queue))
        req = list_entry(ep->queue.next, struct s3c2440_request, queue);
    else
        req = NULL;

    WRITE_REG(dev, INDEX_REG, n);

	if (ep->bEndpointAddress & USB_DIR_IN)
	{
		ep_csr1 = READ_REG(dev, IN_CSR1_REG); 

        if (ep_csr1 & (1 << 5))//SENT_STALL
		{
			CLRB(dev, IN_CSR1_REG, 5);

			return;
		}

		if ((!(ep_csr1 & 1)) && req)
		{
			s3c2440_write_fifo(dev, ep, req);
		}
	}
	else
	{
        ep_csr1 = READ_REG(dev, OUT_CSR1_REG);

		if (ep_csr1 & (1 << 6)) //SENT_STALL
		{
			CLRB(dev, OUT_CSR1_REG, 6);
			return;
		}

		if ((ep_csr1 & 1) && req)
		{
			s3c2440_read_fifo(dev, ep, req);
		}
	}
}

//udc的这个中断,真是包罗万象,各硬件差别比较大
//简单一点说,就是清楚中断标致位,再根据中断标志位对应处理
//实际要复杂的多,如果是ep0,还会从fifo中取得usb_ctrlrequest
//进行对应的处理,我们在实现具体的实现时再说吧
static irqreturn_t s3c2440_udc_irq(int dummy, void *_dev)
{
    struct s3c2440_udc *dev = (struct s3c2440_udc *)_dev;
    unsigned long flags;
    int usb_status;
    int ep_status;	
	int pwr_reg;
	int ep0csr;
    u8 n;

    //printInfo(  "enter irq\n");

    spin_lock_irqsave(&dev->lock, flags);

    usb_status = READ_REG(dev, USB_INT_REG);
    ep_status = READ_REG(dev, EP_INT_REG);

    //printInfo(  "USB_INT_REG = 0x%x\n", usb_status);
    //printInfo(  "EP_INT_REG = 0x%x\n", ep_status);

    /* Driver connected ? */
    if (!dev->driver) 
    {
        /* Clear interrupts */
        WRITE_REG(dev, USB_INT_REG, READ_REG(dev, USB_INT_REG));
        WRITE_REG(dev, EP_INT_REG, READ_REG(dev, EP_INT_REG));
    }

    //reset
    if (usb_status & (1 << 2))
    {
        printInfo(  "USB reset\n");

        WRITE_REG(dev, INDEX_REG, 0);
        WRITE_REG(dev, MAXP_REG, (dev->ep[0].ep.maxpacket & 0x7ff) >> 3);

        dev->ep0state = EP0_IDLE;
        dev->gadget.speed = USB_SPEED_FULL;

        s3c2440_dequeue_all(&dev->ep[0], -EPROTO);

        SETB(dev, USB_INT_REG, 2);

        spin_unlock_irqrestore(&dev->lock, flags);

        return IRQ_HANDLED;
    }

    //resume
    if (usb_status & (1 << 1))
    {
        printInfo(  "USB resume\n");

        SETB(dev, USB_INT_REG, 1);

        if (dev->gadget.speed != USB_SPEED_UNKNOWN
                && dev->driver
                && dev->driver->resume)
            dev->driver->resume(&dev->gadget);
    }

    //suspend
    if (usb_status & 1)
    {
        printInfo(  "USB suspend\n");

        SETB(dev, USB_INT_REG, 0);

        if (dev->gadget.speed != USB_SPEED_UNKNOWN
           && dev->driver
           && dev->driver->suspend)
        dev->driver->suspend(&dev->gadget);

        dev->ep0state = EP0_IDLE;
    }

    if (ep_status & 1)
    {
        //printInfo(  "USB ep0 irq\n");
		SETB(dev, EP_INT_REG, 0);

        s3c2440_handle_ep0(dev);
    }


	for (n = 1; n < S3C2440_ENDPOINTS; n++)
	{
		if (ep_status & (1 << n))
		{
			//printInfo(  "USB ep%d irq\n", n);

			SETB(dev, EP_INT_REG, n);//清除中断

			s3c2440_handle_ep(dev, n);
		}
	}

	pwr_reg = READ_REG(dev, PWR_REG);

	WRITE_REG(dev, INDEX_REG, 0);
	ep0csr = READ_REG(dev, EP0_CSR);

	if (!usb_status && !ep_status && !pwr_reg && !ep0csr) 
	{
		for (n = 1; n < S3C2440_ENDPOINTS; n++) 
		{
			WRITE_REG(dev, INDEX_REG, n);

			if (GETB(dev, OUT_CSR1_REG, 0))
			{
				s3c2440_handle_ep(dev, n);
			}
		}
	}


    spin_unlock_irqrestore(&dev->lock, flags);

    return IRQ_HANDLED;
}
/***************************************************************/

/***********************queue***********************************/
//对于usb请求,一般都要维护一个list去管理请求

//端点list初始化,存入gadget里
static void s3c2440_usb_reinit(struct s3c2440_udc *dev)
{
    u8 i;

    /* device/ep0 records init */
    INIT_LIST_HEAD (&dev->gadget.ep_list);
    dev->gadget.ep0 = &dev->ep[0].ep;//ep0单独存放
    dev->ep0state = EP0_IDLE;
    INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);

    for (i = 0; i < S3C2440_ENDPOINTS; i++) {
        struct s3c2440_ep *ep = &dev->ep[i];

        if (i != 0)
            list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);

        ep->dev = dev;
        ep->desc = NULL;
        ep->stopped = 0;
        INIT_LIST_HEAD (&ep->queue);
    }
}

static void s3c2440_udc_done(struct s3c2440_ep *ep, struct s3c2440_request *req, int status)
{
    struct s3c2440_udc *dev;
    unsigned stopped = ep->stopped;

    list_del_init(&req->queue);

    if (likely (req->req.status == -EINPROGRESS))//正在进行中
        req->req.status = status;
    else
        status = req->req.status;

    dev = ep->dev;

    /* don't modify queue heads during completion callback */
    ep->stopped = 1;
    //先解锁再加锁,加锁是在dequeue_all调用前做的
    spin_unlock(&dev->lock);
    req->req.complete(&ep->ep, &req->req);
    spin_lock(&dev->lock);
    ep->stopped = stopped;
}

static void s3c2440_dequeue_all(struct s3c2440_ep *ep, int status)
{
    struct s3c2440_request *req;

    if (&ep->queue == NULL)
        return;

    while (!list_empty(&ep->queue)) //list_del_init会删除链表中的元素
    {
        req = list_entry(ep->queue.next, struct s3c2440_request, queue);
        s3c2440_udc_done(ep, req, status);
    }
}


/***************************************************************/
//may not be the endpoint named "ep0".这是gadget.h的源话
/**************************ep_ops*******************************/
//描述端点操作

//当设备配置或接口设置改变时,驱动会enable或disable端口
static int s3c2440_udc_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
{
    struct s3c2440_udc    *dev;
    struct s3c2440_ep    *ep;
    u32 max;
    unsigned long    flags;

    printInfo(  "%s\n", __func__);

    ep = to_s3c2440_ep(_ep);
    if (!_ep || !desc || ep->desc
            || (desc->bDescriptorType != USB_DT_ENDPOINT)
            || (_ep->name == ep0name))
        return -EINVAL;
    dev = ep->dev;
    if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
        return -ESHUTDOWN;

    max = usb_endpoint_maxp(desc) & 0x1fff;

    spin_lock_irqsave(&dev->lock, flags);

    _ep->maxpacket = max & 0x7fff;
    ep->desc = desc;
    ep->stopped = 0;
#ifdef S3C2440_SETWEDHE
    ep->wedged = 0;
#endif
    ep->bEndpointAddress = desc->bEndpointAddress;

    WRITE_REG(dev, INDEX_REG, ep->num);
    WRITE_REG(dev, MAXP_REG, max >> 3);

    if (desc->bEndpointAddress & USB_DIR_IN) 
    {
        //SETB(dev, IN_CSR1_REG, 0);//清楚IN_PKT_RDY
        SETB(dev, IN_CSR1_REG, 3);//FLUSH fifo
		SETB(dev, IN_CSR1_REG, 6);//CLR DATA

        SETB(dev, IN_CSR2_REG, 4);//关闭in dma中断,先不用dma
		//CLRB(dev, IN_CSR2_REG, 4);//打开in dma中断
        SETB(dev, IN_CSR2_REG, 5);//in
        CLRB(dev, IN_CSR2_REG, 6);//批量端点
    }
    else
    {
		SETB(dev, IN_CSR1_REG, 6);//CLR DATA
		SETB(dev, IN_CSR2_REG, 4);//关闭in dma中断,先不用dma
        CLRB(dev, IN_CSR2_REG, 5);//out

        //SETB(dev, OUT_CSR1_REG, 0);//清楚IN_PKT_RDY
		SETB(dev, OUT_CSR1_REG, 7);
        SETB(dev, OUT_CSR1_REG, 4);//FLUSH fifo

        CLRB(dev, OUT_CSR2_REG, 6);//批量端点
        SETB(dev, OUT_CSR2_REG, 5);//关闭out dma中断,先不用dma
		//CLRB(dev, OUT_CSR2_REG, 5);//打开out dma中断
    }

    SETB(dev, EP_INT_EN_REG, ep->num);//开中断

    spin_unlock_irqrestore(&dev->lock, flags);

    return 0;
}

static int s3c2440_udc_ep_disable(struct usb_ep *_ep)
{
    struct s3c2440_udc    *dev;
    struct s3c2440_ep *ep = to_s3c2440_ep(_ep);
    unsigned long flags;

    printInfo(  "%s\n", __func__);

    if (!_ep || !ep->desc) {
        return -EINVAL;
    }

    local_irq_save(flags);

    ep->desc = NULL;
    ep->stopped = 1;
    dev = ep->dev;

    //清除请求list和关闭ep
    s3c2440_dequeue_all(ep, -ESHUTDOWN);//关机后将无法传输端点

    CLRB(dev, EP_INT_REG, ep->num);//关对应ep中断

    local_irq_restore(flags);

    return 0;
}

//动态分配请求
static struct usb_request *s3c2440_udc_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
{
    struct s3c2440_request *req;

    printInfo(  "%s\n", __func__);

    if (!_ep)
        return NULL;

    req = kzalloc (sizeof(struct s3c2440_request), gfp_flags);
    if (!req)
        return NULL;

    INIT_LIST_HEAD (&req->queue);

    return &req->req;
}

//释放请求
static void s3c2440_udc_free_request(struct usb_ep *_ep, struct usb_request *_req)
{
    //struct s3c2440_ep    *ep = to_s3c2440_ep(_ep);
    struct s3c2440_request *req = to_s3c2440_req(_req);

    printInfo(  "%s\n", __func__);

    if (!_ep || !_req)
        return;

    WARN_ON (!list_empty (&req->queue));
    kfree(req);

	req = NULL;
}

//下面的queue是插入一个请求
//dequeue删除一个请求
static int s3c2440_udc_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
{
    struct s3c2440_udc    *dev;
    unsigned long        flags;
    struct s3c2440_request    *req = to_s3c2440_req(_req);
    struct s3c2440_ep        *ep = to_s3c2440_ep(_ep);
    u32 ep_csr;

    printInfo(  "%s\n", __func__);

    if (unlikely (!_ep || (!ep->desc && ep->num != 0))) //这个逻辑下面会看到很多(_ep为空或[ep->desc为空且不是0端点])
    {
        return -EINVAL;
    }

    dev = ep->dev;
    if (unlikely (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) 
    {
        return -ESHUTDOWN;
    }

    local_irq_save (flags); //因为中断中有queue操作,所以要放在list_empty前

    if (unlikely(!_req || !_req->complete
            || !_req->buf || !list_empty(&req->queue))) //_req或_req->buf为空、complete执行错误、req->queue不为空
    {
        local_irq_restore(flags);

        return -EINVAL;
    } 

    _req->status = -EINPROGRESS;
    _req->actual = 0;

    WRITE_REG(dev, INDEX_REG, ep->bEndpointAddress & 0x7F);
    //s3c2440_usb_fifocnt(dev, &fifo_count);

    if ((ep->bEndpointAddress & 0x7F) == 0)
    {
        ep_csr = READ_REG(dev, EP0_CSR);
    }
    else
    {
		if (ep->bEndpointAddress & USB_DIR_IN)
		{
            ep_csr = READ_REG(dev, IN_CSR1_REG);
		}
		else
		{
			ep_csr = READ_REG(dev, OUT_CSR1_REG);
		}
		//(ep->bEndpointAddress & USB_DIR_IN) ? IN_CSR1_REG : OUT_CSR1_REG);
    }

    if (list_empty(&ep->queue) && !ep->stopped)
    {
        if (ep->bEndpointAddress == 0)
        {
            switch(dev->ep0state)
            {
            case EP0_IN:
                if (!(ep_csr & (1 << 1)))
                {
                    if (s3c2440_write_fifo(dev, ep, req))
                    {
                        dev->ep0state = EP0_IDLE;
                        req = NULL;
                    }
                }

                break;

            case EP0_OUT:
                if (ep_csr & 1)
                {
                    if (s3c2440_read_fifo(dev, ep, req))
                    {
                        dev->ep0state = EP0_IDLE;
                        req = NULL;
                    }
                }
                break;

            default:
                local_irq_restore(flags);

                return -EL2HLT;
            }
        }
        else if ((ep->bEndpointAddress & USB_DIR_IN) != 0)
        {
		   	if ((!(ep_csr & 1)) && req)
		    {
			    if (s3c2440_write_fifo(dev, ep, req))
				{
					req = NULL;
				}
		    }
        }
        else
        {
		    if ((ep_csr & 1) && req)
		    {
			    if (s3c2440_read_fifo(dev, ep, req))
				{
					req = NULL;
				}
		    }
        }
    }

    if (likely(req != 0))
        list_add_tail(&req->queue, &ep->queue);//请求入list

    local_irq_restore(flags);

    return 0;
}

static int s3c2440_udc_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{
    struct s3c2440_ep        *ep = to_s3c2440_ep(_ep);
    struct s3c2440_udc    *dev;
    int            retval = -EINVAL;
    unsigned long        flags;
    struct s3c2440_request    *req = NULL;

    printInfo(  "%s\n", __func__);

    if (!_ep || !_req)
        return retval;

    dev = ep->dev;

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

    local_irq_save (flags);

    list_for_each_entry (req, &ep->queue, queue) 
    {
        if (&req->req == _req) 
        {
            list_del_init (&req->queue);
            _req->status = -ECONNRESET;//Connection reset by peer
            retval = 0;
            break;
        }
    }

    if (retval == 0) 
    {
        s3c2440_udc_done(ep, req, -ECONNRESET);
    }

    local_irq_restore (flags);
    return retval;
}

#ifdef S3C2440_FIFO_STATUS
//fifo状态,返回fifo中的字节数。
//在上层的调用usb_ep_fifo_statu()如果不用fifo或不支持这个操作返回错误-EOPNOTSUPP
//net2272就有寄存器EP_AVAIL记录fifo中的字节数。
//s3c2440硬件不支持,没实现,上层调用会得到-EOPNOTSUPP
static int s3c2440_udc_fifo_status(struct usb_ep *_ep)
{
    struct s3c2440_ep *ep;
    u16 retval = 0;

    printInfo(  "%s\n", __func__);

    ep = to_s3c2440_ep(_ep);
    if (!_ep || (!ep->desc && ep->num != 0))
        return -ENODEV;
    if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
        return -ESHUTDOWN;

    //retval = 读寄存器

    return retval;
}
#endif

#ifdef S3C2440_FIFO_FLUSH
//冲掉fifo的不明确数据,这个决不用除非端点不能用于任何协议传输,这是上层调用的事
static void s3c2440_udc_fifo_flush(struct usb_ep *_ep)
{
    struct s3c2440_ep *ep;

    printInfo(  "%s\n", __func__);

    ep = to_s3c2440_ep(_ep);
    if (!_ep || (!ep->desc && ep->num != 0))
        return;
    if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
        return;

    //寄存器操作
}
#endif

/*
上层调用usb_ep_set_wedge
停止一个端点并忽略CLEAR_FEATURE请求。如果Gadget驱动清除停止状态,它将自动Unwedge端点
一般用一个位wedge表示
如果没有实现set_wedge方法。就用set_halt(ep, 1);代替
我们看个例子(在file_storage.c中)
Bulk-only
当出现无效的CBW时
Bulk-only Spec说我们必须停止IN 端点。还说必须保持这个状态知道下一次的reset,但是没有办法
告诉控制器忽略CLEAR_FEATURE请求。所以我们用一个位来记录,搞定!
下面是参考net2272的代码,
value=1:set_halt
= 0:clear_halt
*/
static int s3c2440_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
{
    struct s3c2440_ep *ep;
    unsigned long flags;
    int ret = 0;
    struct s3c2440_udc    *dev;

    ep = container_of(_ep, struct s3c2440_ep, ep);
    if (!_ep || (!ep->desc && ep->num != 0))
        return -EINVAL;
    if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
        return -ESHUTDOWN;
    if (ep->desc /* not ep0 */ && usb_endpoint_xfer_isoc(ep->desc))//判断是不是同步端点,见下面
        return -EINVAL;

    dev = ep->dev;

    spin_lock_irqsave(&ep->dev->lock, flags);

    if (!list_empty(&ep->queue))
        ret = -EAGAIN;
#ifdef S3C2440_FIFO_STATUS
    else if ((ep->bEndpointAddress & USB_DIR_IN) && value && s3c2440_udc_fifo_status(_ep) != 0)//fifo_status是上面实现的
        ret = -EAGAIN;
#endif
    else {
		WRITE_REG(dev, INDEX_REG, ep->num);
        /* set/clear */
        if (value) {
            if (ep->num == 0)
            {
                 ep->dev->ep0state = EP0_STALL;
                //net2272的端点0在setup时自动复位,没有什么操作。s3c2440就不是了
                //ep->dev->protocol_stall = 1;
                //ep0 set_halt
                EP0_SETSST(dev);
            }
            else
			{
                //epx(x != 0) set_halt
				if ((ep->bEndpointAddress & USB_DIR_IN) != 0)
				{
					SETB(dev, IN_CSR1_REG, 4);
				}
				else
				{
                    SETB(dev, OUT_CSR1_REG, 5);
				}
			}

            if (wedged)//维护wedged
                ep->wedged = 1;
        } else {
			if (ep->num == 0)
            {
                 ep->dev->ep0state = EP0_IDLE;
				 EP0_CLRSST(dev);
            }
            else
			{
                //epx(x != 0) set_halt
				if ((ep->bEndpointAddress & USB_DIR_IN) != 0)
				{
					CLRB(dev, IN_CSR1_REG, 4);
				}
				else
				{
					CLRB(dev, OUT_CSR1_REG, 5);
				}
			}
            //ep clear_halt
            ep->wedged = 0;
        }
    }

	ep->stopped = value ? 1 : 0;

    spin_unlock_irqrestore(&ep->dev->lock, flags);

    return ret;
}
//_ep 不能是同步端点,同步端点不支持错误重发机制。在上面判断
static int s3c2440_udc_set_halt(struct usb_ep *_ep, int value)
{
    printInfo(  "%s\n", __func__);

    return s3c2440_set_halt_and_wedge(_ep, value, 0);
}

#ifdef S3C2440_SETWEDHE

static int s3c2440_udc_set_wedge(struct usb_ep *_ep)
{

    printInfo(  "%s\n", __func__);

    if (!_ep || _ep->name == ep0name)//一般都是端点0请求复位
        return -EINVAL;

    return s3c2440_set_halt_and_wedge(_ep, 1, 1);
}
#endif

static const struct usb_ep_ops s3c2440_ep_ops = 
{
    .enable        = s3c2440_udc_ep_enable,
    .disable    = s3c2440_udc_ep_disable,

    .alloc_request    = s3c2440_udc_alloc_request,
    .free_request    = s3c2440_udc_free_request,

    .queue        = s3c2440_udc_queue,
    .dequeue    = s3c2440_udc_dequeue,
 
    .set_halt    = s3c2440_udc_set_halt,

#ifdef S3C2440_SETWEDHE
    .set_wedge  = s3c2440_udc_set_wedge,
#endif

#ifdef S3C2440_FIFO_STATUS
    .fifo_status = s3c2440_udc_fifo_status,
#endif

#ifdef S3C2440_FIFO_FLUSH
    .fifo_flush = s3c2440_udc_fifo_flush,
#endif
};

/***************************************************************/
//USB 设备的常用操作包括:设备连接、设备移除、设备配置、地址分配、数据传输、 
//设备挂起、设备唤醒等。
/**************************usb_gadget_ops***********************/
//硬件操作函数

//获取帧号,当主机发送USB 数据包时,每个帧的开始(SOF)包包含一个帧号。
//这个帧号一般自动加载到对应寄存器,此函数主要就是读这些寄存器
//如果设备不支持返回负
static int s3c2440_udc_get_frame(struct usb_gadget *usb_gdt_p)
{
    printInfo(  "%s\n", __func__);

#ifdef S3C2440_GET_FRAME
    struct s3c2440_udc *dev = to_s3c2440_udc(usb_gdt_p);
    int retval = 0;
    unsigned long flags;

    spin_lock_irqsave(&dev->lock, flags);

    retval = READ_REG(dev, S3C2410_UDC_FRAME_NUM2_REG) << 8;
    retval |= READ_REG(dev, S3C2410_UDC_FRAME_NUM1_REG);

    spin_unlock_irqrestore(&dev->lock, flags);

    return retval;
#else
    return -EOPNOTSUPP;
#endif
}

#ifdef S3C2440_WAKEUP
//唤醒,举个例子net2272。它的寄存器usbctl0的第五位控制唤醒功能使能
//寄存器usbctl1的第三位通过写1去resume,s3c2440在PWR_REG也有类似
static int s3c2440_udc_wakeup(struct usb_gadget *usb_gdt_p)
{
    struct s3c2440_udc *dev = to_s3c2440_udc(usb_gdt_p);
    unsigned long flags;

    printInfo(  "%s\n", __func__);

    spin_lock_irqsave(&dev->lock, flags);

    if (GETB(dev, PWR_REG, 0))//如果使能挂起模式
    {
        SETB(dev, PWR_REG, 2);
    }

    spin_unlock_irqrestore(&dev->lock, flags);

    return 0;
}
#endif

#ifdef S3C2440_SELFPOWERED
//设置自供电标志(selfpowered feature),一般就用一个变量位或一个位记录一下。USB_RECIP_DEVICE时返回状态
static int s3c2440_udc_set_selfpowered (struct usb_gadget *usb_gdt_p, int is_selfpowered)
{
    struct s3c2440_udc *dev = to_s3c2440_udc(usb_gdt_p);

    printInfo(  "%s\n", __func__);

    if (is_selfpowered)
        dev->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
    else
        dev->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);

    return 0;
}
#endif

#ifdef S3C2440_VBUS_SESSION
//vbus在硬件上就是usb的电源脚,这个函数就是来控制它。一般通过一个gpio拉高拉底
//这个vbus会话,实际的我看了s3c2410和at91的处理,就是让usb的D+线与一个gpio口连接
//通过置1置0来控制usb
static int s3c2440_udc_vbus_session (struct usb_gadget *usb_gdt_p, int is_active)
{
    struct s3c2440_udc *dev = to_s3c2440_udc(usb_gdt_p);
    unsigned long flags;

    printInfo(  "%s\n", __func__);

    spin_lock_irqsave(&dev->lock, flags);

    //寄存器操作

    spin_unlock_irqrestore(&dev->lock, flags);

    return 0;
}
#endif

#ifdef S3C2440_VBBUS_DRAW
//强制vbus电源控制器行为,在SET_CONFIGRATION时,设置vbus的电流量
//vbus应该是表示总线电压,在硬件上是一个脚
//主要是对usb电流的设置,看一下gta02平台,这个函数会操作pcf50633(一种移动设备的电源管理芯片)
static int s3c2440_udc_vbus_draw (struct usb_gadget *usb_gdt_p, unsigned mA)
{
    return 0;
}
#endif

#ifdef S3C2440X_PULLUP
//这个和上面的vbus_session区别是
//vbus_session是控制vbus的连接
//pullup是控制usb模块的连接
//在udc-core.c中newstyle的驱动probe函数时才调用它,所以你要实现udc_start和udc_stop,
//当然除了注册,也可以通过sysfs调用它。和newstyle无关。
//composite.c也有一些调用
//这个就是根据is_on来connect或disconnect usb
//net2272就是由USBCTL0的第三位控制的,s3c2440还是通过gpio和vbus_session没
//区别
static int s3c2440_udc_pullup (struct usb_gadget *usb_gdt_p, int is_on)
{
    struct s3c2440_udc *dev = to_s3c2440_udc(usb_gdt_p);
    unsigned long flags;

    printInfo(  "%s\n", __func__);

    spin_lock_irqsave(&dev->lock, flags);

    if (is_on)
    {
        PULL_UP();
    }
    else
    {
        PULL_DOWN();
    }

    spin_unlock_irqrestore(&dev->lock, flags);

    return 0;
}
#endif

//不好意思,我看了linux-3.2.36的/gadget的目录没发现有实现这个的硬件
static int s3c2440_udc_ioctl(struct usb_gadget *usb_gdt_p, unsigned code, unsigned long param)
{
    return 0;
}

//这个也没看驱动实现它,从名字就是获取配置参数,就简单看看struct usb_dcd_config_params
/*
struct usb_dcd_config_params {
        __u8  bU1devExitLat;    // U1 Device exit Latency  u1设备等待时间
#define USB_DEFAULT_U1_DEV_EXIT_LAT     0x01    // Less then 1 microsec 至少1微秒
        __le16 bU2DevExitLat;   // U2 Device exit Latency 
#define USB_DEFAULT_U2_DEV_EXIT_LAT     0x1F4   // Less then 500 microsec 
};
对应struct usb_ss_cap_descriptor 中的成员
每一个I/O请求包延迟时间限制
*/
static void s3c2440_udc_get_config_params(struct usb_dcd_config_params *usb_dc_cfg_pm)
{
}

//在udc-core.c中start和udc_start的解释一样,在bind()之前调用,只要实现一个就行了
//我知道start主要有bind回调
//udc_start主要是设备执行了non-control请求后,要重新连接,net2272和r8a66597实现的就是它
#ifdef S3C2440_NEWSTYLE
static int s3c2440_udc_start(struct usb_gadget *usb_gdt_p, struct usb_gadget_driver *driver);
static int s3c2440_udc_stop(struct usb_gadget *usb_gdt_p, struct usb_gadget_driver *driver);
#else
//s3c2410 s3c2440 实现它
static int s3c2440_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *));
static int s3c2440_stop(struct usb_gadget_driver *driver);
#endif

static const struct usb_gadget_ops s3c2440_ops = 
{
    .get_frame        = s3c2440_udc_get_frame,
#ifdef S3C2440_WAKEUP
    .wakeup            = s3c2440_udc_wakeup,
#endif

#ifdef S3C2440_SELFPOWERED
    .set_selfpowered = s3c2440_udc_set_selfpowered,
#endif

#ifdef S3C2440_VBUS_SESSION
    .vbus_session    = s3c2440_udc_vbus_session,
#endif

#ifdef S3C2440_VBBUS_DRAW
    .vbus_draw        = s3c2440_udc_vbus_draw,
#endif

#ifdef S3C2440X_PULLUP
    .pullup            = s3c2440_udc_pullup,
#endif

    .ioctl          = s3c2440_udc_ioctl,
    .get_config_params = s3c2440_udc_get_config_params,
#ifdef S3C2440_NEWSTYLE
    .udc_start         = s3c2440_udc_start,
    .udc_stop       = s3c2440_udc_stop,
#else
    .start            = s3c2440_start,
    .stop            = s3c2440_stop,
#endif
};

/***************************************************************/


/***************************************************************/

static struct s3c2440_udc udc_info = {
    .gadget = {
        .ops        = &s3c2440_ops,
        .ep0        = &udc_info.ep[0].ep,
        .name        = gadget_name,
        .dev = {
            .init_name    = "gadget",
        },
/*
根据自己的硬件选择
unsigned is_dualspeed:1;
unsigned is_otg:1;
unsigned is_a_peripheral:1;
unsigned b_hnp_enable:1; //hnp:主机协商协议 otg特有的
unsigned a_hnp_support:1;
unsigned a_alt_hnp_support:1;
*/
    },

    /* control endpoint */
    .ep[0] = {
        .num = 0,
        .ep =
        {
            .name        = "ep0",
            .ops        = &s3c2440_ep_ops,
            .maxpacket    = EP0_FIFO_SIZE,
        },
        .dev        = &udc_info,
        .fifo_size = S3C2440_EP0_FIFO_SIZE,
    },

    /* first group of endpoints */
    .ep[1] = {
        .num = 1,
        .ep = 
        {
            .name        = "ep1-bulk",
            .ops        = &s3c2440_ep_ops,
            .maxpacket    = EP1_FIFO_SIZE,
        },
        .dev        = &udc_info,
        .fifo_size    = S3C2440_EP1_FIFO_SIZE,
        .bEndpointAddress = EP1_ADDRESS,
        .bmAttributes    = EP1_ATTR,
    },
    .ep[2] = {
        .num = 2,
        .ep = 
        {
            .name        = "ep2-bulk",
            .ops        = &s3c2440_ep_ops,
            .maxpacket    = EP2_FIFO_SIZE,
        },
        .dev        = &udc_info,
        .fifo_size    = S3C2440_EP2_FIFO_SIZE,
        .bEndpointAddress = EP2_ADDRESS,
        .bmAttributes    = EP2_ATTR,
    },
    .ep[3] = {
        .num = 3,
        .ep = 
        {
            .name        = "ep3-bulk",
            .ops        = &s3c2440_ep_ops,
            .maxpacket    = EP3_FIFO_SIZE,
        },
        .dev        = &udc_info,
        .fifo_size    = S3C2440_EP3_FIFO_SIZE,
        .bEndpointAddress = EP3_ADDRESS,
        .bmAttributes    = EP3_ATTR,
    },
    .ep[4] = {
        .num = 4,
        .ep = 
        {
            .name        = "ep4-bulk",
            .ops        = &s3c2440_ep_ops,
            .maxpacket    = EP4_FIFO_SIZE,
        },
        .dev        = &udc_info,
        .fifo_size    = S3C2440_EP4_FIFO_SIZE,
        .bEndpointAddress = EP4_ADDRESS,
        .bmAttributes    = EP4_ATTR,
    },
};

static void stop_activity(struct s3c2440_udc *dev, struct usb_gadget_driver *driver)
{
    unsigned i;

    if (dev->gadget.speed == USB_SPEED_UNKNOWN)
        driver = NULL;

    /* disconnect gadget driver after quiesceing hw and the driver */

    s3c2440_usb_reset(dev);//复位或disable
    for (i = 0; i < S3C2440_ENDPOINTS; i++)
    {
        s3c2440_dequeue_all(&dev->ep[i], -ECONNABORTED);
    }

#ifndef S3C2440_NEWSTYLE
/*
if (udc_is_newstyle(udc)) {
        udc->driver->disconnect(udc->gadget);
        udc->driver->unbind(udc->gadget);
        usb_gadget_udc_stop(udc->gadget, udc->driver);
        usb_gadget_disconnect(udc->gadget);//对应pull_up
} else {
        usb_gadget_stop(udc->gadget, udc->driver);//所以非newstyle要disconnect
}
*/
    if (driver) 
    {
        spin_unlock(&dev->lock);
        driver->disconnect(&dev->gadget);
        spin_lock(&dev->lock);
    }
#endif

    if (dev->driver)
    {
        s3c2440_usb_reinit(dev);//重初始化
    }
}

#ifdef S3C2440_NEWSTYLE
/*
udc 的probe函数
if (udc_is_newstyle(udc)) {//是否实现udc_start and udc_stop
        ret = bind(udc->gadget);
        if (ret)
                goto err1;
        ret = usb_gadget_udc_start(udc->gadget, driver);//已绑定,bind是gadget实现的
        if (ret) {
                driver->unbind(udc->gadget);
                goto err1;
        }
        usb_gadget_connect(udc->gadget);//上面的pullup
} else {

        ret = usb_gadget_start(udc->gadget, driver, bind);
        if (ret)
                goto err1;

}
*/
//net2272和r8a66597实现的就是它
//下面参考net2272
static int s3c2440_udc_start(struct usb_gadget *usb_gdt_p, struct usb_gadget_driver *driver)
{
    struct s3c2440_udc *dev;

    printInfo(  "%s\n", __func__);

    if (!driver || !driver->unbind || !driver->setup ||
        driver->speed != USB_SPEED_HIGH)
        return -EINVAL;

    dev = container_of(usb_gdt_p, struct s3c2440_udc, gadget);

    /* hook up the driver ... */
    driver->driver.bus = NULL;
    dev->driver = driver;
    dev->gadget.dev.driver = &driver->driver;

    s3c2440_udc_enable(dev);

    return 0;
}

static int s3c2440_udc_stop(struct usb_gadget *usb_gdt_p, struct usb_gadget_driver *driver)
{
    struct s3c2440_udc *dev;
    unsigned long flags;

    printInfo(  "%s\n", __func__);

    dev = container_of(usb_gdt_p, struct s3c2440_udc, gadget);

    spin_lock_irqsave(&dev->lock, flags);
    stop_activity(dev, driver);
    spin_unlock_irqrestore(&dev->lock, flags);

    dev->gadget.dev.driver = NULL;
    dev->driver = NULL;

    return 0;
}

#else
//s3c2410 s3c2440 实现它
//下面参考s3c2440
static int s3c2440_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *usb_gdt_p))
{
    struct s3c2440_udc *dev = &udc_info;
    int    retval = 0;

    printInfo(  "%s\n", __func__);

    if (!driver
            || driver->speed < USB_SPEED_FULL
            || !bind
            || !driver->disconnect
            || !driver->setup)
        return -EINVAL;
    if (!dev)
        return -ENODEV;
    if (dev->driver)
        return -EBUSY;

    /* hook up the driver */
    driver->driver.bus = NULL;
    dev->driver = driver;
    dev->gadget.dev.driver = &driver->driver;

    if ((retval = device_add(&dev->gadget.dev)) != 0) 
    {
        goto register_error;
    }

    retval = bind(&dev->gadget);
    if (retval) 
    {
        device_del(&dev->gadget.dev);
        goto register_error;
    }

    s3c2440_udc_enable(dev);

    return 0;

register_error:
    dev->driver = NULL;
    dev->gadget.dev.driver = NULL;
    return retval;
}

static int s3c2440_stop(struct usb_gadget_driver *driver)
{
    struct s3c2440_udc *dev = &udc_info;
    unsigned long    flags;

    printInfo(  "%s\n", __func__);

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

    spin_lock_irqsave(&dev->lock, flags);
    dev->driver = NULL;
    stop_activity(dev, driver);
    spin_unlock_irqrestore(&dev->lock, flags);

    driver->unbind(&dev->gadget);
    dev->gadget.dev.driver = NULL;
    dev->driver = NULL;

    device_del(&dev->gadget.dev);
    
    return 0;
}
#endif

/***************************************************************/
static int s3c2440_udc_probe(struct platform_device *pdev)
{

    struct s3c2440_udc *udc = &udc_info;
    struct device *dev = &pdev->dev;
    int retval;
    struct resource *res;
#ifdef S3C2440_USE_IRQ
    struct resource *resirq;
#endif
    resource_size_t res_size;

    dev_dbg(dev, "%s()\n", __func__);

#ifdef S3C2440_HAVE_CLK
    udc->s3c2440_clk_upll = clk_get(NULL, "usb-bus-gadget");
    if (IS_ERR(udc->s3c2440_clk_upll)) 
    {
        dev_err(dev, "failed to get usb bus clock source\n");
        return PTR_ERR(udc->s3c2440_clk_upll);
    }

    clk_enable(udc->s3c2440_clk_upll);

    udc->s3c2440_clk_udc = clk_get(NULL, "usb-device");
    if (IS_ERR(udc->s3c2440_clk_udc)) {
        dev_err(dev, "failed to get udc clock source\n");
        retval = PTR_ERR(udc->s3c2440_clk_udc);
        goto err_clk_upll;
    }

    clk_enable(udc->s3c2440_clk_udc);

#if (CLK_DELAY_TIME != 0)
    mdelay(CLK_DELAY_TIME);
#endif

    dev_dbg(dev, "got and enabled clocks\n");
#endif //S3C2440_HAVE_CLK

    spin_lock_init (&udc->lock);

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!res) 
    {
        dev_err(&pdev->dev, "can't get device resources\n");
        retval = -ENODEV;
        goto err_clk_udc;
    }

    res_size = resource_size(res);
    if (!request_mem_region(res->start, res_size, res->name)) 
    {
        dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
            res_size, res->start);
        retval = -ENOMEM;

        goto err_clk_udc;
    }

    udc->virl_addr = ioremap(res->start, res_size);
    if (!udc->virl_addr) 
    {
        retval = -ENOMEM;
        goto err_mem;
    }
    udc->phy_addr = res->start;
    udc->reg_size = res_size;

    device_initialize(&udc->gadget.dev);
    udc->gadget.dev.parent = &pdev->dev;
    udc->gadget.dev.dma_mask = pdev->dev.dma_mask;

    platform_set_drvdata(pdev, udc);

    //少不了硬件初始化
    s3c2440_usb_reset(udc);
    s3c2440_usb_reinit(udc);

#ifdef S3C2440_USE_IRQ

    resirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    if (!resirq) 
    {
        dev_err(&pdev->dev, "can't get device irq resources\n");
        retval = -ENODEV;
        goto err_map;
    }

    udc->irq_num = resirq->start;

    retval = request_irq(udc->irq_num, s3c2440_udc_irq, 0, gadget_name, (void*)udc);
    if (retval != 0) 
    {
        dev_err(dev, "cannot get irq %i, err %d\n", udc->irq_num, retval);
        retval = -EBUSY;
        goto err_map;
    }

    dev_dbg(dev, "got irq %i\n", udc->irq_num);

#endif


    retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
    if (retval)
        goto err_int;

#ifdef S3C2440_DEBUG_FS
    if (s3c2440_udc_debugfs_root) 
    {
        udc->debug_info = debugfs_create_file("registers", S_IRUGO, s3c2440_udc_debugfs_root,
                udc, &s3c2440_udc_debugfs_fops);
        if (!udc->debug_info)
            dev_warn(dev, "debugfs file creation failed\n");
    }
#endif

    dev_dbg(dev, "probe ok\n");

    return 0;

err_int:
#ifdef S3C2440_USE_IRQ
    free_irq(udc->irq_num, udc);
#endif
err_map:
    iounmap(udc->virl_addr);
err_mem:
    release_mem_region(res->start, res_size);
err_clk_udc:
#ifdef S3C2440_HAVE_CLK
    clk_put(udc->s3c2440_clk_udc);
    clk_disable(udc->s3c2440_clk_udc);
#endif
err_clk_upll:
#ifdef S3C2440_HAVE_CLK
    clk_put(udc->s3c2440_clk_upll);
    clk_disable(udc->s3c2440_clk_upll);
#endif

    return retval;
}

static int s3c2440_udc_remove(struct platform_device *pdev)
{
    struct s3c2440_udc *udc = platform_get_drvdata(pdev);

    dev_dbg(&pdev->dev, "%s()\n", __func__);

    usb_del_gadget_udc(&udc->gadget);
    if (udc->driver)
        return -EBUSY;

#ifdef S3C2440_DEBUG_FS
    debugfs_remove(udc->debug_info);
#endif

#ifdef S3C2440_USE_IRQ
    free_irq(udc->irq_num, udc);
#endif

    iounmap(udc->virl_addr);
    release_mem_region(udc->phy_addr, udc->reg_size);

    platform_set_drvdata(pdev, NULL);

#ifdef S3C2440_HAVE_CLK
    if (!IS_ERR(udc->s3c2440_clk_udc) && udc->s3c2440_clk_udc != NULL) {
        clk_disable(udc->s3c2440_clk_udc);
        clk_put(udc->s3c2440_clk_udc);
        udc->s3c2440_clk_udc = NULL;
    }

    if (!IS_ERR(udc->s3c2440_clk_upll) && udc->s3c2440_clk_upll != NULL) {
        clk_disable(udc->s3c2440_clk_upll);
        clk_put(udc->s3c2440_clk_upll);
        udc->s3c2440_clk_upll = NULL;
    }
#endif

    dev_dbg(&pdev->dev, "%s: remove ok\n", __func__);

    return 0;
}

#ifdef CONFIG_PM
static int s3c2440_udc_suspend(struct platform_device *pdev, pm_message_t message)
{
    return 0;
}

static int s3c2440_udc_resume(struct platform_device *pdev)
{
    return 0;
}
#else
#define s3c2440_udc_suspend    NULL
#define s3c2440_udc_resume    NULL
#endif

/***************************************************************/

//有些设备可能用struct pci_driver,我就不考虑这么多了。
static struct platform_driver udc_driver_s3c2440 = {
    .driver        = {
        .name    = "s3c2440-usbgadget",
        .owner    = THIS_MODULE,
    },
    .probe        = s3c2440_udc_probe,
    .remove        = __exit_p(s3c2440_udc_remove),
    .suspend    = s3c2440_udc_suspend,
    .resume        = s3c2440_udc_resume,
};


static int __init udc_init(void)
{
    int retval;

    s3c2440_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);
    if (IS_ERR(s3c2440_udc_debugfs_root)) {
        printInfo(  "%s: debugfs dir creation failed %ld\n",
            gadget_name, PTR_ERR(s3c2440_udc_debugfs_root));
        s3c2440_udc_debugfs_root = NULL;
    }

    retval = platform_driver_register(&udc_driver_s3c2440);
    if (retval)
        goto err;

    return 0;

err:
    debugfs_remove(s3c2440_udc_debugfs_root);
    return retval;
}

static void __exit udc_exit(void)
{
    platform_driver_unregister(&udc_driver_s3c2440);
    debugfs_remove(s3c2440_udc_debugfs_root);
}

module_init(udc_init);
module_exit(udc_exit);

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");


你可能感兴趣的:(linux,ARM,移动设备)