精华内容
下载资源
问答
  • 直接上代码,可以和我之前写的模板比较比较 /*********************************** Copyright(C), 2013 LDP FileName: s3c2440_udc.h Author: wwxxxxll Date: Description: History: Author Date

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

    /***********************************
     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");


    展开全文
  • 在《自娱自乐1》中的模板,比较一下,我做了什么,这会给你写udc驱动提供个思路。我直接分析 调试打印,就是枚举过程,我们从代码看枚举。打印位置可以在下面的代码里找到。 如果你要弄懂驱动代码中涉及枚举的地方...

    花了半个月,才搞定驱动中的枚举部分,现在说linux的枚举,windows可能有差别。

    代码我会贴在后面,现在只是实现枚举,你可能对代码不感兴趣,我就不分析代码了,你可以看看

    在《自娱自乐1》中的模板,比较一下,我做了什么,这会给你写udc驱动提供个思路。我直接分析

    调试打印,就是枚举过程,我们从代码看枚举。打印位置可以在下面的代码里找到。

    如果你要弄懂驱动代码中涉及枚举的地方,你就仔细看看代码在那打印的,这个对你完成一个udc驱

    动有帮助。

    如果你只是想简单了解枚举你就看看我分析的调试打印就可以了。

    http://wenku.baidu.com/view/87064d244b35eefdc8d333dc.html

    这个是枚举过程,对照着上面说的看我的调试打印,提示我的是从机,他说的是主机。

    # insmod s3c2440_add_udc.ko

    UPLLCON = 38022, wxl add//驱动usb的时钟源

    # insmod s3c2440_udc.ko

    # insmod gadget_transfer.ko

    s3c2440_start//调用s3c2440_start(),在此会PULL_UP

    s3c2440_udc_alloc_request//分配请求结构体内存

    gadget_transfer gadget: gadget_transfer ready

    # USB reset//pc检测到PULL_UP 复位设备

    USB ep0 irq//ep0中断

    Host: bRequest = 06 bRequestType = 80 wValue = 0x100wIndex=0x0 wLength=0x40//请求信息

    //bRequest = 06是请求描述符,bRequestType = 80输入方向(输入是对主机而言) 端点0

    //请求长度64(微软的策略,这里linux学微软的)。

    //wValue = 0x100: 这个前面的1表示设备描述符

     

    USB_REQ_GET_DESCRIPTOR//第一次请求主要是获取最大包长度,此值在设备描述符第8个字节

    USB_DT_DEVICE//设备描述符请求

    s3c2440_udc_queue//调用了s3c2440_udc_queue()

    Slave: length = 18 Vendor = ff0 Product = ff0 Device =212 iManufacturer = 1 iProduct = 2 iSerialNumber = 3 bNumConfigurations = 1

    // Vendor = ff0 Product = ff0 Device = 212 这个在上一篇的gadget_transfer驱动中可以看到

    // iManufacturer = 1 iProduct = 2iSerialNumber = 3 这个是字符串描述符引索

    // bNumConfigurations = 1 你看看我上一篇的gadget_transfar驱动写的是2,这里却是1

    /*

    bNumConfigurations是配置数,是用count_configs()统计的,和你在gadget驱动中赋值无关

         多配置很少,不过还是有,例如multi.c可以配置为RNDIS或ECM。

    */

    8bytes USB USB reset //一次发出8个字节,我的ep0最大包长度是8,还有下面的xbytes都是已发的字节数。微软的策略后面没发完的不要了,直接复位设备。没有按usb spec来做。Windows要接受16个才复位。

    USB ep0 irq

    Host: bRequest = 05 bRequestType = 00 wValue = 0x4wIndex=0x0 wLength=0x0

    //主机的请求又来了,这次是设置地址

    // bRequest = 05 就是设置地址请求,

    // bRequestType = 00 方向out,地址0

    //wValue=0x4 设备地址4,在驱动中看不到它的使用,应该是硬件来判断

    USB_REQ_SET_ADDRESS

    USB ep0 irq//这个我调试是数据没准备好

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x100wIndex=0x0 wLength=0x12

    //这次是真的获取设备描述符,长度18

    USB_REQ_GET_DESCRIPTOR

    USB_DT_DEVICE

    s3c2440_udc_queue

    Slave: length = 18 Vendor = ff0 Product = ff0 Device =212 iManufacturer = 1 iProduct = 2 iSerialNumber = 3 bNumConfigurations = 1//上面已解释

    8bytes USB ep0 irq

     

     16bytes USB ep0irq

     18bytes USB ep0irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x200wIndex=0x0 wLength=0x9

    /*

    wValue = 0x200: 这个前面的2表示配置描述符,后面是引索

    */

     

    //获取配置描述符

    USB_REQ_GET_DESCRIPTOR

    USB_DT_CONFIG

    s3c2440_udc_queue

    Slave: length = 9 TotalLength = 32 NumInterfaces = 1ConfigurationValue = 3 iConfiguration = 4 bMaxPower = 250

    /*

    length = 9描述符长度为9

    TotalLength = 32配置信息的长度--包括配置描述符、接口描述符、端点描述符长度的总和

    NumInterfaces = 1 接口数

    ConfigurationValue = 3用于表示 USB设备的配置值,主机就是根据这个选

    iConfiguration = 4字符串描述符的索引值

    bMaxPower = 250用于表示 USB设备运行时所需要消耗的总线电流,单位以2mA 为基准。USB设备可以从USB总线上获得最大的电流为500mA,因此 bMaxPower 字段的最大值可以设置为250

    还有个bmAttributes,没打印

    */

    8bytes USB ep0 irq

     9bytes USB ep0irq

    USB ep0 irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x300wIndex=0x0 wLength=0xff

    /*

    wValue = 0x300: 这个前面的3表示字符串描述符,后面是引索0

    之前并没有看到0引索的字符串描述符,不过看一下composite.c就知道了

    /* 0 == report all availablelanguage codes */

    可用的语言数,不细说

    */

    USB_REQ_GET_DESCRIPTOR

    USB_DT_STRING

    s3c2440_udc_queue

    Slave: length = 4

     4bytes USB ep0irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x303wIndex=0x409 wLength=0xff

    //3是上面的iSerialNumber = 3

    USB_REQ_GET_DESCRIPTOR

    USB_DT_STRING

    s3c2440_udc_queue

    Slave: length = 66

    0123456789.0123456789.0123456789

     //可以在上一篇的驱动开的这个,static charserial[] = "0123456789.0123456789.0123456789";

    8bytes USB ep0 irq

     16bytes USB ep0irq

     24bytes USB ep0irq

     32bytes USB ep0irq

     40bytes USB ep0irq

     48bytes USB ep0irq

     56bytes USB ep0irq

     64bytes USB ep0irq

     66bytes USB ep0irq

    //下面又来一次,就是获得的字符串描述不同而已

    Host: bRequest = 06 bRequestType = 80 wValue = 0x200wIndex=0x0 wLength=0xff

    USB_REQ_GET_DESCRIPTOR

    USB_DT_CONFIG

    s3c2440_udc_queue

    Slave: length = 9 TotalLength = 32 NumInterfaces = 1ConfigurationValue = 3 iConfiguration = 4 bMaxPower = 250

     8bytes USB ep0irq

     16bytes USB ep0irq

     24bytes USB ep0irq

     32bytes USB ep0irq

     32bytes USB ep0irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x300wIndex=0x0 wLength=0xff

    USB_REQ_GET_DESCRIPTOR

    USB_DT_STRING

    s3c2440_udc_queue

    Slave: length = 4

     4bytes USB ep0irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x302wIndex=0x409 wLength=0xff

    // iProduct = 2

    USB_REQ_GET_DESCRIPTOR

    USB_DT_STRING

    s3c2440_udc_queue

    Slave: length = 46

    Gadget gadget_transfer// static const char longname[]= "Gadget gadget_transfer";

     8bytes USB ep0irq

     16bytes USB ep0irq

     24bytes USB ep0irq

     32bytes USB ep0irq

     40bytes USB ep0irq

     46bytes USB ep0irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x300wIndex=0x0 wLength=0xff//再一次,不清楚为什么

    USB_REQ_GET_DESCRIPTOR

    USB_DT_STRING

    s3c2440_udc_queue

    Slave: length = 4

     4bytes USB ep0irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x302wIndex=0x409 wLength=0xff

    USB_REQ_GET_DESCRIPTOR

    USB_DT_STRING

    s3c2440_udc_queue

    Slave: length = 46

    Gadget gadget_transfer

     8bytes USB ep0irq

     16bytes USB ep0irq

     24bytes USB ep0irq

     32bytes USB ep0irq

     40bytes USB ep0irq

     46bytes USB ep0irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x100wIndex=0x0 wLength=0x12

    USB_REQ_GET_DESCRIPTOR

    USB_DT_DEVICE//获取设备描述符

    s3c2440_udc_queue

    Slave: length = 18 Vendor = ff0 Product = ff0 Device =212 iManufacturer = 1 iProduct = 2 iSerialNumber = 3 bNumConfigurations = 1

     8bytes USB ep0irq

     16bytes USB ep0irq

     18bytes USB ep0irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x100wIndex=0x0 wLength=0x40//这里有用64长度请求一次

    USB_REQ_GET_DESCRIPTOR

    USB_DT_DEVICE

    s3c2440_udc_queue

    Slave: length = 18 Vendor = ff0 Product = ff0 Device =212 iManufacturer = 1 iProduct = 2 iSerialNumber = 3 bNumConfigurations = 1

     8bytes USB ep0irq

     16bytes USB ep0irq

     18bytes USB ep0irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x100wIndex=0x0 wLength=0x12

    USB_REQ_GET_DESCRIPTOR

    USB_DT_DEVICE//又来一次

    s3c2440_udc_queue

    Slave: length = 18 Vendor = ff0 Product = ff0 Device =212 iManufacturer = 1 iProduct = 2 iSerialNumber = 3 bNumConfigurations = 1

     8bytes USB ep0irq

     16bytes USB ep0irq

     18bytes USB ep0irq

    USB ep0 irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x600wIndex=0x0 wLength=0xa

    USB_REQ_GET_DESCRIPTOR

    USB_DT_DEVICE_QUALIFIER

    //设备限定描述符用于指定另一传输速率下该设备的总体信息,如果高速USB设备既需要采用高速传//输又需要全速传输,则它必须支持设备限定描述符(Device_Qualifier)。全速设备不支持

    //我的是全速设备用不倒QUALIFIERcomposite.cgadget_is_dualspeed()这个判断

    USB ep0 irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x600wIndex=0x0 wLength=0xa

    USB_REQ_GET_DESCRIPTOR

    USB_DT_DEVICE_QUALIFIER

    USB ep0 irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x600wIndex=0x0 wLength=0xa

    USB_REQ_GET_DESCRIPTOR

    USB_DT_DEVICE_QUALIFIER

    USB ep0 irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x200wIndex=0x0 wLength=0x9

    USB_REQ_GET_DESCRIPTOR

    USB_DT_CONFIG//这次你会看到到wValue & 0xff 03

    // iManufacturer = 1 iProduct = 2iSerialNumber = 3

    s3c2440_udc_queue

    Slave: length = 9 TotalLength = 32 NumInterfaces = 1ConfigurationValue = 3 iConfiguration = 4 bMaxPower = 250

     8bytes USB ep0irq

     9bytes USB ep0irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x200wIndex=0x0 wLength=0x20

    USB_REQ_GET_DESCRIPTOR

    USB_DT_CONFIG

    s3c2440_udc_queue

    Slave: length = 9 TotalLength = 32 NumInterfaces = 1ConfigurationValue = 3 iConfiguration = 4 bMaxPower = 250

     8bytes USB ep0irq

     16bytes USB ep0irq

     24bytes USB ep0irq

     32bytes USB ep0irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x300wIndex=0x0 wLength=0xff

    USB_REQ_GET_DESCRIPTOR

    USB_DT_STRING

    s3c2440_udc_queue

    Slave: length = 4

     4bytes USB ep0irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x302wIndex=0x409 wLength=0xff

    USB_REQ_GET_DESCRIPTOR

    USB_DT_STRING

    s3c2440_udc_queue

    Slave: length = 46

    Gadget gadget_transfer

     8bytes USB ep0irq

     16bytes USB ep0irq

     24bytes USB ep0irq

     32bytes USB ep0irq

     40bytes USB ep0irq

     46bytes USB ep0irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x301wIndex=0x409 wLength=0xff

    USB_REQ_GET_DESCRIPTOR

    USB_DT_STRING

    s3c2440_udc_queue

    Slave: length = 58

    Linux 3.2.0 with s3c2440_udc

    /*

    还记得我的gadget驱动开始

       snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",

           init_utsname()->sysname, init_utsname()->release,

            gadget->name);

    */

     8bytes USB ep0irq

     16bytes USB ep0irq

     24bytes USB ep0irq

     32bytes USB ep0irq

     40bytes USB ep0irq

     48bytes USB ep0irq

     56bytes USB ep0irq

     58bytes USB ep0irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x303wIndex=0x409 wLength=0xff

    USB_REQ_GET_DESCRIPTOR

    USB_DT_STRING

    s3c2440_udc_queue

    Slave: length = 66

    0123456789.0123456789.0123456789

     8bytes USB ep0irq

     16bytes USB ep0irq

     24bytes USB ep0irq

     32bytes USB ep0irq

     40bytes USB ep0irq

     48bytes USB ep0irq

     56bytes USB ep0irq

     64bytes USB ep0irq

     66bytes USB ep0irq

    USB ep0 irq

    Host: bRequest = 09 bRequestType = 00 wValue = 0x3wIndex=0x0 wLength=0x0

    USB_REQ_SET_CONFIGURATION//设置配置

    // wValue = 0x3对应上面的ConfigurationValue = 3程序中是

    /*

    static struct usb_configurationsourcesink_driver = {

        .label        = "source/sink",

        .strings   = sourcesink_strings,

        .setup        = sourcesink_setup,

        .bConfigurationValue = 3,

        .bmAttributes    = USB_CONFIG_ATT_SELFPOWER,

        /* .iConfiguration = DYNAMIC */

    };

    */

    gadget_transfer gadget: full-speed config#3: source/sink//上面的.label        ="source/sink",

    s3c2440_udc_ep_enable

    s3c2440_udc_ep_enable

    s3c2440_udc_queue

    USB ep0 irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x304wIndex=0x409 wLength=0xff

    USB_REQ_GET_DESCRIPTOR

    USB_DT_STRING

    s3c2440_udc_queue

    Slave: length = 42

    source and sink data9

     8bytes USB ep0irq

     16bytes USB ep0irq

     24bytes USB ep0irq

     32bytes USB ep0irq

     40bytes USB ep0irq

     42bytes USB ep0irq

    USB ep0 irq

    Host: bRequest = 06 bRequestType = 80 wValue = 0x304wIndex=0x409 wLength=0xff

    USB_REQ_GET_DESCRIPTOR//这里引索是4就是iConfiguration = 4

    USB_DT_STRING

    s3c2440_udc_queue

    Slave: length = 42

    source and sink data9

    /*代码

    static struct usb_stringstrings_sourcesink[] = {

        [0].s ="source and sink data",

        {  }           /* end of list */

    };

    */

     8bytes USB ep0irq

     16bytes USB ep0irq

     24bytes USB ep0irq

     32bytes USB ep0irq

     40bytes USB ep0irq

     42bytes USB ep0irq

     

    有些重复的请求就是为了确认。

    下面是代码:(现在只能枚举),可以把内核自带的驱动和我的比较一下,我的宗旨是应用我的模板。

    s3c2440_udc.h

    /***********************************
     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
    //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__

    s3c2440.c

    /***********************************
     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>//printk
    #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: 接收者
        */
        printk(  "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 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 fifo_count, avail, len, bufspace;
        int ret = 0;
    
        printk(  "%s\n", __func__);
    
        idx = ep->bEndpointAddress & 0x7f;
    
        if (idx > 4)
        {
            idx = 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;
    
        WRITE_REG(dev, INDEX_REG, idx);
    
        s3c2440_usb_fifocnt(dev, &fifo_count);
    
        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要接收的总长度
        printk(  "read: req->req.actual = %d, req->req.length = %d\n", req->req.actual, req->req.length);
    
        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 
           {
           }
    
            s3c2440_udc_done(ep, req, 0);
        } else 
        {
            if (idx == 0) 
            {
                EP0_CLROPR(dev);
            } 
            else 
            {
            }
        }
        return ret;
    }
    
    static int printDesc = 0;
    
    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;
    
        //printk(  "%s\n", __func__);
    
        struct usb_device_descriptor    *desc;
        struct usb_string_descriptor    *string;
        struct usb_config_descriptor    *config;
        u16                language;
        u32                 n;
        u8                *tmp;
    
        switch (printDesc) 
        {
        case USB_DT_DEVICE:
            desc = (struct usb_device_descriptor*)req->req.buf;
    
            printk(  "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;
    
            printk(  "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;
            printk(  "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
                {
                    printk( "%c", *tmp);//没考虑大小端
                }
            }
    
            printk("\n");
    
            break;
        case USB_DT_BOS: 
            break;
        default:
            break;
        }
    
        printDesc = 0;
    
        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已发送长度
        printk(  " %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;
    
        //printk(   \
                "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
            {
    
            }
    
            s3c2440_udc_done(ep, req, 0);
        }
        else
        {
            if (idx == 0)
            {
                if (!GETB(dev, USB_INT_REG, 2))
                {  
                    EP0_SETIPR(dev);
                }
            }
            else
            {
    
            }
        }
    
        return ret;
    }
    
    static void s3c2440_dequeue_all(struct s3c2440_ep *ep, int status);
    
    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;
    
        //printk(  "%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: printk(  "USB_REQ_GET_STATUS\n");
            EP0_CLROPR(dev);
            if ((ctrlq.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
            {
    
            }
    
            break;
        case USB_REQ_CLEAR_FEATURE: printk(  "USB_REQ_CLEAR_FEATURE\n");
            EP0_CLROPR(dev);
            break;
        case USB_REQ_SET_FEATURE: printk(  "USB_REQ_SET_FEATURE\n");
            EP0_CLROPR(dev);
            break;
        case USB_REQ_SET_ADDRESS: printk(  "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: printk(  "USB_REQ_GET_DESCRIPTOR\n");
            switch (ctrlq.wValue >> 8) 
            {
            case USB_DT_DEVICE: printk(  "USB_DT_DEVICE\n");
                break;
            //设备限定描述符用于指定另一传输速率下该设备的总体信息,如果高速 USB设备既需要采用高速传输又需
            //要全速传输,则它必须支持设备限定描述符(Device_Qualifier)。全速设备不支持
            case USB_DT_DEVICE_QUALIFIER: printk(  "USB_DT_DEVICE_QUALIFIER\n");
                break;
            case USB_DT_OTHER_SPEED_CONFIG: printk(  "USB_DT_OTHER_SPEED_CONFIG\n");
                break;
            case USB_DT_CONFIG: printk(  "USB_DT_CONFIG\n");
                break;
            case USB_DT_STRING: printk(  "USB_DT_STRING\n");
                break;
            //其他速率配置描述符用于指定另一传输速率下该设备的配置信息,如果高速USB设备既需要采用高速传输
            //又需要全速传输,则它必须支持其他速率配置描述符
            case USB_DT_BOS: printk(  "USB_DT_BOS\n");
                break;
            }
    
            EP0_CLROPR(dev);
    
            break;
        case USB_REQ_SET_DESCRIPTOR: printk(  "USB_REQ_SET_DESCRIPTOR\n");
            EP0_CLROPR(dev);
            break;
        case USB_REQ_GET_CONFIGURATION: printk(  "USB_REQ_GET_CONFIGURATION\n");
            EP0_CLROPR(dev);
            break;
        case USB_REQ_SET_CONFIGURATION: 
            if (ctrlq.bRequestType == USB_RECIP_DEVICE) 
            {
                printk(  "USB_REQ_SET_CONFIGURATION\n");
                config = 1;
    
                EP0_CLROPR(dev);
                EP0_SETDE(dev);
            }
            break;
        case USB_REQ_GET_INTERFACE: printk(  "USB_REQ_GET_INTERFACE\n");
            EP0_CLROPR(dev);
            break;
        case USB_REQ_SET_INTERFACE: 
            if (ctrlq.bRequestType == USB_RECIP_INTERFACE) 
            {
                printk(  "SB_REQ_SET_INTERFACE\n");
                config = 1;
    
                EP0_CLROPR(dev);
                EP0_SETDE(dev);
            }
    
            break;
        case USB_REQ_SYNCH_FRAME: printk(  "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;
    
        //为了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;
        }
    
        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;
        }
    }
    
    //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;
    
        //printk(  "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);
    
        //printk(  "USB_INT_REG = 0x%x\n", usb_status);
        //printk(  "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))
        {
            printk(  "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))
        {
            printk(  "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)
        {
            printk(  "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)
        {
            printk(  "USB ep0 irq\n");
    
            SETB(dev, EP_INT_REG, 0);
    
            s3c2440_handle_ep0(dev);
        }
    
        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;
    
        printk(  "%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_CSR2_REG, 0);//关闭in dma中断,先不用dma
            SETB(dev, IN_CSR2_REG, 5);//in
            SETB(dev, IN_CSR2_REG, 6);//批量端点
        }
        else
        {
            CLRB(dev, IN_CSR2_REG, 5);//out
    
            SETB(dev, OUT_CSR1_REG, 0);//清楚IN_PKT_RDY
            SETB(dev, OUT_CSR1_REG, 4);//FLUSH fifo
    
            SETB(dev, OUT_CSR2_REG, 5);//批量端点
            SETB(dev, OUT_CSR2_REG, 6);//关闭out dma中断,先不用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;
    
        printk(  "%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;
    
        printk(  "%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);
    
        printk(  "%s\n", __func__);
    
        if (!_ep || !_req)
            return;
    
        WARN_ON (!list_empty (&req->queue));
        kfree(req);
    }
    
    //下面的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 fifo_count, ep_csr;
    
        printk(  "%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 == 0)
        {
            ep_csr = READ_REG(dev, EP0_CSR);
        }
        else
        {
            ep_csr = READ_REG(dev, (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) == 1)
                        {
                            dev->ep0state = EP0_IDLE;
                            req = NULL;
                        }
                    }
                    break;
    
                default:
                    local_irq_restore(flags);
    
                    return -EL2HLT;
                }
            }
            else if ((ep->bEndpointAddress & USB_DIR_IN) != 0)
            {
            }
            else
            {
            }
        }
    
        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;
    
        printk(  "%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;
    
        printk(  "%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;
    
        printk(  "%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;
    
        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;
    
        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 {
            /* set/clear */
            if (value) {
                if (ep->num == 0)
                {
                     ep->dev->ep0state = EP0_STALL;
                     ep->stopped = 1;
                    //net2272的端点0在setup时自动复位,没有什么操作。s3c2440就不是了
                    //ep->dev->protocol_stall = 1;
                    //ep0 set_halt
                }
                else
                    //epx(x != 0) set_halt
                if (wedged)//维护wedged
                    ep->wedged = 1;
            } else {
                //ep clear_halt
                ep->wedged = 0;
            }
        }
        spin_unlock_irqrestore(&ep->dev->lock, flags);
    
        return ret;
    }
    //_ep 不能是同步端点,同步端点不支持错误重发机制。在上面判断
    static int s3c2440_udc_set_halt(struct usb_ep *_ep, int value)
    {
        printk(  "%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)
    {
    
        printk(  "%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)
    {
        printk(  "%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;
    
        printk(  "%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);
    
        printk(  "%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;
    
        printk(  "%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;
    
        printk(  "%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;
    
        printk(  "%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;
    
        printk(  "%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;
    
        printk(  "%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;
    
        printk(  "%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)) {
            printk(  "%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");

    下期完善它,并考虑使用DMA。下期见!

     

    展开全文
  • 我不知道udc和gadget驱动是不是冷门的驱动,资料真是不多。我之前买了一本书,上面说到这些,就教你如何调试已写好的驱动。这样也可以写书,太坑了吧!我随便从网上搜搜都能写的比他好。难道现在的育人机构为了钱都...


    首先,我不是做驱动的开发人员。所以只能用自娱自乐来表示我的行为。

    我不知道udc和gadget驱动是不是冷门的驱动,资料真是不多。我之前买了一本书,上面说到这些,就教你如何调试已写好的驱动。这样也可以写书,太坑了吧!我随便从网上搜搜都能写的比他好。难道现在的育人机构为了钱都变成了坑人机构。

    我以前就希望把自己写过的驱动总结成一个模板,让人能直观的看出linux提供的接口要我们做什么甚至怎么做。虽然做这个比较难,但我还是成功的欺骗了自己,可以做到。

    这是自娱自乐第一期,可能废话多了一点,请大家原谅。现在说这个模板。这个是一个未做实际应用的模板,只是编译通过,除了没实践,还缺少DMA和USB的请求类型处理样例。后期我会用它做一个驱动,不断的完善。现在这个应该在理论和实践之间的东西。

    常用结构体(别人写的,不是linux-3.2.36,不过差不多)

    ========================================================USB UDC与gadget驱动=========================================================
    /*
     *linux内核中usb设备侧驱动程序分为3个层次:UDC驱动、Gadget API和Gadget驱动程序,UDC驱动程序直接访问硬件usb控制器OHCI/EHCI/UHCI,作为usb设备和主机间的底层通信,向上层
     *提供与硬件相关操作的回调函数。当前Gadget API是对UDC驱动程序回调函数的简单包装。Gadget驱动程序具体控制系统作为usb设备时的相关功能的实现,使设备表现出“网络连接”、“打印机”
     *或“USB Mass Storage”等特性。
     *
     *    这里的USB设备控制器(UDC)驱动指作为其他USB主机控制器外设的USB硬件设备上底层硬件控制器的驱动,该硬件和驱动负责将USB设备依附于一个USB主机控制器上:比如当某运行linux的手机作为PC
     *的U盘时,手机的底层USB控制器行使USB设备控制器的功能,这时候运行在底层的是UDC驱动,而手机成为U盘,在UDC驱动之上仍然需要另一个驱动,对于USB大容量存储器为file storage驱动,这一
     *驱动称为gadget驱动(总之是一个运行linux的系统的usb接口作为另一个linux系统的设备)。usb设备驱动调用usb核心提供的API,因此具体驱动与SOC无关。同样,usb gadget驱动调用通用的gadget API
     *因此具体gadget驱动也变得与SOC无关。
     *UDC驱动和gadget驱动都位于内核的drivers/usb/gadget目录下,S3C2410对应的UDC驱动为s3c2410_udc.c。ether.c、f_serial.c、file_storage.c等文件实现了一些gadget驱动
     */
    #include <linux/gadget.h>
    
    -----------------------------------------------------------struct usb_gadget------------------------------------------------------
    struct usb_gadget {   //描述USB设备控制器
    	/* readonly to gadget driver */                  //针对gadget驱动只读
    	const struct usb_gadget_ops	*ops;                //访问硬件函数
    	struct usb_ep			*ep0;                          //端点0,setup使用
    	struct list_head		ep_list;	/* of usb_ep */    //其他端点列表
    	enum usb_device_speed		speed;                   
    	unsigned			is_dualspeed:1;
    	unsigned			is_otg:1;
    	unsigned			is_a_peripheral:1;
    	unsigned			b_hnp_enable:1;                    //A-HOST使能了HNP支持
    	unsigned			a_hnp_support:1;                   //A-HOST支持HNP
    	unsigned			a_alt_hnp_support:1;
    	const char			*name;
    	struct device			dev;
    };
    
    ------------------------------------------------------struct usb_gadget_ops-------------------------------------------------------
    struct usb_gadget_ops {  //硬件操作函数
    	int	(*get_frame)(struct usb_gadget *);
    	int	(*wakeup)(struct usb_gadget *);
    	int	(*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
    	int	(*vbus_session) (struct usb_gadget *, int is_active);
    	int	(*vbus_draw) (struct usb_gadget *, unsigned mA);
    	int	(*pullup) (struct usb_gadget *, int is_on);
    	int	(*ioctl)(struct usb_gadget *,
    				unsigned code, unsigned long param);
    };
    
    -----------------------------------------------------struct usb_gadget_driver----------------------------------------------------
    struct usb_gadget_driver {  //描述gadget驱动
    	char			*function;                          //描述gadget功能的字符串
    	enum usb_device_speed	speed;
    	int			(*bind)(struct usb_gadget *);         //当驱动和gadget绑定时调用
    	void			(*unbind)(struct usb_gadget *);
    	int			(*setup)(struct usb_gadget *,         //处理硬件驱动未处理的端点0请求
    					const struct usb_ctrlrequest *);
    	void			(*disconnect)(struct usb_gadget *);
    	void			(*suspend)(struct usb_gadget *);
    	void			(*resume)(struct usb_gadget *);
    
    	/* FIXME support safe rmmod */
    	struct device_driver	driver;
    };
    
    -----------------------------------------------------struct usb_request----------------------------------------------------------
    struct usb_request {  //表示一个传输请求的usb_request(与从机端看到的urb相似)
    	void			*buf;
    	unsigned		length;
    	dma_addr_t		dma;
    
    	unsigned		no_interrupt:1;
    	unsigned		zero:1;
    	unsigned		short_not_ok:1;
    
    	void			(*complete)(struct usb_ep *ep,
    					struct usb_request *req);
    	void			*context;
    	struct list_head	list;
    
    	int			status;
    	unsigned		actual;
    };
    
    ----------------------------------------------------------struct usb_ep---------------------------------------------------------
    struct usb_ep {   //描述一个端点
    	void			*driver_data;
    
    	const char		*name;
    	const struct usb_ep_ops	*ops;
    	struct list_head	ep_list;
    	unsigned		maxpacket:16;
    };
    
    ------------------------------------------------------struct usb_ep_ops---------------------------------------------------------
    struct usb_ep_ops {   //描述端点操作
    	int (*enable) (struct usb_ep *ep,
    		const struct usb_endpoint_descriptor *desc);
    	int (*disable) (struct usb_ep *ep);
    
    	struct usb_request *(*alloc_request) (struct usb_ep *ep,
    		gfp_t gfp_flags);
    	void (*free_request) (struct usb_ep *ep, struct usb_request *req);
    
    	int (*queue) (struct usb_ep *ep, struct usb_request *req,
    		gfp_t gfp_flags);
    	int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
    
    	int (*set_halt) (struct usb_ep *ep, int value);
    	int (*set_wedge) (struct usb_ep *ep);
    
    	int (*fifo_status) (struct usb_ep *ep);
    	void (*fifo_flush) (struct usb_ep *ep);
    };
    --------------------------------------------------------------------------------------------------------------------------------
    /*
     *UDC和gadget驱动围绕上述数据结构及其成员函数而展开。 
     *在具体的UDC驱动中,需要封装usb_gadget和每个端点usb_ep,实现端点usb_ep_ops,完成usb_request。另外usb_gadget_register_driver和usb_gadget_unregister_driver这两个API需要由UDC
     *驱动提供,gadget驱动会调用它们。
     */
    int usb_gadget_register_driver(struct usb_gadget_driver *driver); //注册,在加载模块中调用,该函数中会调用driver->bind()函数,将usb_gadget_driver与具体的gadget绑定
    int usb_gadget_unregister_driver(struct usb_gadget_driver *driver); //注销,在卸载模块中调用,告诉UDC驱动不再投入工作,如果UDC正在和USB主机连接,会先调用driver->disconnect()
                                                                        //函数,而后会调用unbind()函数
    //在linux/usb/gadget.h中,封装了一些常用的API:                                                                    
    int usb_ep_enable(struct usb_ep *ep,const struct usb_endpoint_descriptor *desc);  //使能端点 ,该函数会调用struct usb_ep_ops->enable()
    int usb_ep_disable(struct usb_ep *ep);  //禁止端点,该函数会调用struct usb_ep_ops->disable()
    
    struct usb_request *usb_ep_alloc_request(struct usb_ep *ep,gfp_t gfp_flags);    //分配一个依附于某端点的 usb_request,该函数会调用struct usb_ep_ops->usb_request()
    void usb_ep_free_request(struct usb_ep *ep,struct usb_request *req);            //释放一个依附于某端点的 usb_request,该函数会调用struct usb_ep_ops->free_request()
    
    int usb_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags);//提交usb_request,该函数告诉UDC完成usb_request(读写buffer),当请求被完成后,该请求对应的completion函数会被调用,
                                                                                  //该函数会调用struct usb_ep_ops->queue(),该函数告诉UDC完成usb_request(读写buffer),当请求完成后,该请求对应的completion函数会被调用
    int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req);  //取消usb_request,该函数会调用struct usb_ep_ops->dequeue()
    
    端点FIFO管理:
    int usb_ep_fifo_status(struct usb_ep *ep);  //该函数会调用truct usb_ep_ops->fifo_status返回目前FIFO中的字节数
    void usb_ep_fifo_flush(struct usb_ep *ep);  //该函数会调用truct usb_ep_ops->fifo_flush,以flush(冲洗)掉FIFO中的数据
    
    int usb_gadget_frame_number(struct usb_gadget *gadget); //它调用gadget->ops->get_frame(gadget)返回目前的帧号
    
    /*
     *S3C2410的UDC驱动在 /driver/usb/gadget/s3c2410_udc.c
     */
    /-----------------------------------------------------------------------------------------------------------------------------/
    

    看请求队列的处理

    struct xxxxx_request

    {

        structlist_head        queue;       /* ep'srequests */

        structusb_request        req;       //对应主机端看到的urb

    };

    struct xxxxx_ep

    {

        struct usb_ep ep; //描述一个端点

       struct list_head queue;

       …

    }

     

        /*device/ep0 records init */

        INIT_LIST_HEAD(&dev->gadget.ep_list);

        INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);

       

    /* basic endpoint recordsinit */

        for(i = 0; i < XXXXX_ENDPOINTS; i++) {

            structxxxxx_ep *ep = &dev->ep[i];

     

            if(i != 0)//除了ep0

                list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);

            …

            INIT_LIST_HEAD(&ep->queue);

     }

    ep0就用gadget里面的,这个在上层的gadget驱动才能看到。Udc只要这样做就可以了

     

    gadget驱动会调用xxxxx_udc_queue把请求插入ep->queue

    udc在端点中断时会从对应的queue取出处理,我的模板没体现这点。


    下面说udc驱动大概包涵哪些。

    1.       struct usb_ep_ops

    2.       struct usb_gadget_ops xxxxx_ops

    3.       有一个中断来处理对应的事件,请求一般包涵在次。(目前的模板没有体现)。

    事实上现在的模板就是告诉你上面两个要实现什么,及怎么实现。代码中有详细解释。我不多说了。

    .H

    /***********************************
     Copyright(C), 2013 LDP
     FileName:  xxxxx_udc.h
     Author:    wwxxxxll
     Date:          
     Description:  
     History:       
     Author       Date            Desc
    ************************************/
    #ifndef __XXXXX_UDC_H__
    #define __XXXXX_UDC_H__
    /*************配置选项**************/
    #define XXXXX_DEBUG_FS  //使用debugfs
    
    //struct usb_ep_ops
    #define XXXXX_NEWSTYLE  //使用udc_start
    #define XXXXX_SETWEDHE  //实现set_weght方法
    #define XXXXX_FIFO_STATUS //支持fifo_status方法
    #define XXXXX_FIFO_FLUSH //支持fifo_flush方法
    
    //struct usb_gadget_ops
    #define XXXXX_XXXXX_GET_FRAME //支持get_frame
    #define XXXXX_WAKEUP //支持wakeup功能
    #define XXXXX_SELFPOWERED //selfpowered支持
    #define XXXXX_VBUS_SESSION //vbus连接控制支持
    #define XXXXXX_PULLUP //usb连接控制支持
    
    #define XXXXX_HAVE_CLK  //有专用的CLK
    #ifdef XXXXX_HAVE_CLK
    #define CLK_DELAY_TIME 10 //ms
    #endif
    
    #define XXXXX_USE_IRQ
    
    //端口信息
    #define XXXXX_ENDPOINTS 2 //端口数
    #define EP0_FIFO_SIZE 8
    #define EP1_FIFO_SIZE 64
    #define EP1_ADDRESS 1
    #define EP1_ATTR USB_ENDPOINT_XFER_BULK
    #define XXXXX_EP_FILO_SIZE 128
    /***********************************/
    
    /*************寄存器定义************/
    
    /***********************************/
    
    
    struct xxxxx_ep 
    {
        struct usb_ep ep; //描述一个端点
        struct list_head queue;
        struct xxxxx_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 XXXXX_SETWEDHE
        unsigned wedged :1;
    #endif
    };
    
    #define to_xxxxx_ep(ep_p) container_of(ep_p, struct xxxxx_ep, ep)
    
    struct xxxxx_request 
    {
        struct list_head        queue;        /* ep's requests */
        struct usb_request        req;        //对应主机端看到的urb
    };
    
    #define to_xxxxx_req(req_p) container_of(req_p, struct xxxxx_request, req)
    
    //根据实际要求定义,这个不能当做模板,主要是便于软件管理
    //一般有下面几个,有的驱动不用这些定义去管理
    enum ep0state {
        EP0_IDLE,
        EP0_IN, 
        EP0_OUT,    
        EP0_STALL,        
    };
        
    struct xxxxx_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 xxxxx_ep ep[XXXXX_ENDPOINTS];
        struct xxxxx_request fifo_req;
    
    #ifdef XXXXX_DEBUG_FS
        struct dentry *debug_info;
    #endif 
    
    #ifdef XXXXX_HAVE_CLK
        struct clk *xxxxx_clk;
    #endif
    
    #ifdef XXXXX_USE_IRQ
        unsigned int irq_num;
    #endif
    
        u16    devstatus;
    };
    
    #define to_xxxxx_udc(gadget_p) container_of(gadget_p, struct xxxxx_udc, gadget)
    
    #endif//__XXXXX_UDC_H__

    .c

    /***********************************
     Copyright(C), 2013 LDP
     FileName:  xxxxx_udc.c
     Author:    wwxxxxll
     Date:          
     Description: linux-3.2-36
     History:       
     Author       Date            Desc
    ************************************/
    
    #include <linux/module.h>//MODULE_*
    #include <linux/init.h>//printk
    #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 <asm/irq.h>
    #include <asm/io.h>//ioremap
    
    #include "xxxxx_udc.h"
    
    #ifdef XXXXX_DEBUG_FS
    #include <linux/debugfs.h>
    #include <linux/seq_file.h>//seq_printf seq_read
    #endif
    
    #define DRIVER_DESC    "XXXXX USB Device Controller Gadget"
    #define DRIVER_VERSION    "2013"
    #define DRIVER_AUTHOR    "wwxxxxll"
    
    static const char        gadget_name[] = "xxxxx_udc";
    static const char        driver_desc[] = DRIVER_DESC;
    
    
    
    //根据实际情况修改
    static const char ep0name[] = "ep0";
    static const char * const ep_name[] = {
        ep0name,
        "ep1",
    };
    
    #ifdef XXXXX_DEBUG_FS
    static struct dentry *xxxxx_udc_debugfs_root;
    
    static int xxxxx_udc_debugfs_seq_show(struct seq_file *m, void *p)
    {
        seq_printf(m, "My name is %s\n", gadget_name);
    
        return 0;
    }
    
    static int xxxxx_udc_debugfs_fops_open(struct inode *inode,
                         struct file *file)
    {
        return single_open(file, xxxxx_udc_debugfs_seq_show, NULL);
    }
    
    static const struct file_operations xxxxx_udc_debugfs_fops = 
    {
        .open        = xxxxx_udc_debugfs_fops_open,
        .read        = seq_read,
        .llseek        = seq_lseek,
        .release    = single_release,
        .owner        = THIS_MODULE,
    };
    #endif
    
    /***********************hardware_handler************************/
    static void xxxxx_usb_reset(struct xxxxx_udc *dev)
    {
        //硬件操作
    }
    
    //udc的这个中断,真是包罗万象,各硬件差别比较大
    //简单一点说,就是清楚中断标致位,再根据中断标志位对应处理
    //实际要复杂的多,如果是ep0,还会从fifo中取得usb_ctrlrequest
    //进行对应的处理,我们在实现具体的实现时再说吧
    static irqreturn_t xxxxx_udc_irq(int dummy, void *_dev)
    {
        return IRQ_HANDLED;
    }
    /***************************************************************/
    
    /***********************queue***********************************/
    //对于usb请求,一般都要维护一个list去管理请求
    
    //端点list初始化,存入gadget里
    static void xxxxx_usb_reinit(struct xxxxx_udc *dev)
    {
        u32 i;
    
        /* device/ep0 records init */
        INIT_LIST_HEAD (&dev->gadget.ep_list);
        dev->gadget.ep0 = &dev->ep[0].ep;//ep0单独存放
        dev->gadget.speed = USB_SPEED_UNKNOWN;
        dev->ep0state = EP0_IDLE;
        INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
    
        for (i = 0; i < XXXXX_ENDPOINTS; i++) {
            struct xxxxx_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 xxxxx_udc_done(struct xxxxx_ep *ep, struct xxxxx_request *req, int status)
    {
        struct xxxxx_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 xxxxx_dequeue_all(struct xxxxx_ep *ep, int status)
    {
        struct xxxxx_request *req;
    
        if (&ep->queue == NULL)
            return;
    
        while (!list_empty(&ep->queue)) //list_del_init会删除链表中的元素
        {
            req = list_entry(ep->queue.next, struct xxxxx_request, queue);
            xxxxx_udc_done(ep, req, status);
        }
    }
    
    
    /***************************************************************/
    //may not be the endpoint named "ep0".这是gadget.h的源话
    /**************************ep_ops*******************************/
    //描述端点操作
    
    //当设备配置或接口设置改变时,驱动会enable或disable端口
    static int xxxxx_udc_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
    {
        struct xxxxx_udc    *dev;
        struct xxxxx_ep    *ep;
        u32 max;
        unsigned long    flags;
    
        ep = to_xxxxx_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 XXXXX_SETWEDHE
        ep->wedged = 0;
    #endif
        ep->bEndpointAddress = desc->bEndpointAddress;
    
        //寄存器操作
        spin_unlock_irqrestore(&dev->lock, flags);
    
        return 0;
    }
    
    static int xxxxx_udc_ep_disable(struct usb_ep *_ep)
    {
        struct xxxxx_ep *ep = to_xxxxx_ep(_ep);
        unsigned long flags;
    
        if (!_ep || !ep->desc) {
            return -EINVAL;
        }
    
        local_irq_save(flags);
    
        ep->desc = NULL;
        ep->stopped = 1;
    
        //清除请求list和关闭ep
        xxxxx_dequeue_all(ep, -ESHUTDOWN);//关机后将无法传输端点
    
        local_irq_restore(flags);
    
        return 0;
    }
    
    //动态分配请求
    static struct usb_request *xxxxx_udc_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
    {
        struct xxxxx_request *req;
    
        if (!_ep)
            return NULL;
    
        req = kzalloc (sizeof(struct xxxxx_request), gfp_flags);
        if (!req)
            return NULL;
    
        INIT_LIST_HEAD (&req->queue);
    
        return &req->req;
    }
    
    //释放请求
    static void xxxxx_udc_free_request(struct usb_ep *_ep, struct usb_request *_req)
    {
        //struct xxxxx_ep    *ep = to_xxxxx_ep(_ep);
        struct xxxxx_request *req = to_xxxxx_req(_req);
    
        if (!_ep || !_req)
            return;
    
        WARN_ON (!list_empty (&req->queue));
        kfree(req);
    }
    
    //下面的queue是插入一个请求
    //dequeue删除一个请求
    static int xxxxx_udc_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
    {
        struct xxxxx_udc    *dev;
        unsigned long        flags;
        struct xxxxx_request    *req = to_xxxxx_req(_req);
        struct xxxxx_ep        *ep = to_xxxxx_ep(_ep);
    
        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;
        }
    
        if (unlikely(!_req || !_req->complete
                || !_req->buf || !list_empty(&req->queue))) //_req或_req->buf为空、complete执行错误、req->queue不为空
        {
            return -EINVAL;
        }
    
        local_irq_save (flags);
    
        //硬件操作
    
        if (likely(req != 0))
            list_add_tail(&req->queue, &ep->queue);//请求入list
    
        local_irq_restore(flags);
    
        return 0;
    }
    
    static int xxxxx_udc_dequeue(struct usb_ep *_ep, struct usb_request *_req)
    {
        struct xxxxx_ep        *ep = to_xxxxx_ep(_ep);
        struct xxxxx_udc    *dev;
        int            retval = -EINVAL;
        unsigned long        flags;
        struct xxxxx_request    *req = NULL;
    
    
        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) 
        {
            xxxxx_udc_done(ep, req, -ECONNRESET);
        }
    
        local_irq_restore (flags);
        return retval;
    }
    
    #ifdef XXXXX_FIFO_STATUS
    //fifo状态,返回fifo中的字节数。
    //在上层的调用usb_ep_fifo_statu()如果不用fifo或不支持这个操作返回错误-EOPNOTSUPP
    //net2272就有寄存器EP_AVAIL记录fifo中的字节数。
    //s3c2440硬件不支持,没实现,上层调用会得到-EOPNOTSUPP
    static int xxxxx_udc_fifo_status(struct usb_ep *_ep)
    {
        struct xxxxx_ep *ep;
        u16 retval = 0;
    
        ep = to_xxxxx_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 XXXXX_FIFO_FLUSH
    //冲掉fifo的不明确数据,这个决不用除非端点不能用于任何协议传输,这是上层调用的事
    static void xxxxx_udc_fifo_flush(struct usb_ep *_ep)
    {
        struct xxxxx_ep *ep;
    
        ep = to_xxxxx_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 xxxxx_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
    {
        struct xxxxx_ep *ep;
        unsigned long flags;
        int ret = 0;
    
        ep = container_of(_ep, struct xxxxx_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;
    
        spin_lock_irqsave(&ep->dev->lock, flags);
    
    
    
        if (!list_empty(&ep->queue))
            ret = -EAGAIN;
    #ifdef XXXXX_FIFO_STATUS
        else if ((ep->bEndpointAddress & USB_DIR_IN) && value && xxxxx_udc_fifo_status(_ep) != 0)//fifo_status是上面实现的
            ret = -EAGAIN;
    #endif
        else {
            /* set/clear */
            if (value) {
                if (ep->num == 0)
                {
                     ep->dev->ep0state = EP0_STALL;
                     ep->stopped = 1;
                    //net2272的端点0在setup时自动复位,没有什么操作。s3c2440就不是了
                    //ep->dev->protocol_stall = 1;
                    //ep0 set_halt
                }
                else
                    //epx(x != 0) set_halt
                if (wedged)//维护wedged
                    ep->wedged = 1;
            } else {
                //ep clear_halt
                ep->wedged = 0;
            }
        }
        spin_unlock_irqrestore(&ep->dev->lock, flags);
    
        return ret;
    }
    //_ep 不能是同步端点,同步端点不支持错误重发机制。在上面判断
    static int xxxxx_udc_set_halt(struct usb_ep *_ep, int value)
    {
        return xxxxx_set_halt_and_wedge(_ep, value, 0);
    }
    
    #ifdef XXXXX_SETWEDHE
    
    static int xxxxx_udc_set_wedge(struct usb_ep *_ep)
    {
        if (!_ep || _ep->name == ep0name)//一般都是端点0请求复位
            return -EINVAL;
    
        return xxxxx_set_halt_and_wedge(_ep, 1, 1);
    }
    #endif
    
    static const struct usb_ep_ops xxxxx_ep_ops = 
    {
        .enable        = xxxxx_udc_ep_enable,
        .disable    = xxxxx_udc_ep_disable,
    
        .alloc_request    = xxxxx_udc_alloc_request,
        .free_request    = xxxxx_udc_free_request,
    
        .queue        = xxxxx_udc_queue,
        .dequeue    = xxxxx_udc_dequeue,
     
        .set_halt    = xxxxx_udc_set_halt,
    
    #ifdef XXXXX_SETWEDHE
        .set_wedge  = xxxxx_udc_set_wedge,
    #endif
    
    #ifdef XXXXX_FIFO_STATUS
        .fifo_status = xxxxx_udc_fifo_status,
    #endif
    
    #ifdef XXXXX_FIFO_FLUSH
        .fifo_flush = xxxxx_udc_fifo_flush,
    #endif
    };
    
    /***************************************************************/
    //USB 设备的常用操作包括:设备连接、设备移除、设备配置、地址分配、数据传输、 
    //设备挂起、设备唤醒等。
    /**************************usb_gadget_ops***********************/
    //硬件操作函数
    
    //获取帧号,当主机发送USB 数据包时,每个帧的开始(SOF)包包含一个帧号。
    //这个帧号一般自动加载到对应寄存器,此函数主要就是读这些寄存器
    //如果设备不支持返回负
    static int xxxxx_udc_get_frame(struct usb_gadget *usb_gdt_p)
    {
    #ifdef XXXXX_GET_FRAME
        struct xxxxx_udc *dev = to_xxxxx_udc(usb_gdt_p);
        int retval = 0;
        unsigned long flags;
    
        spin_lock_irqsave(&dev->lock, flags);
    
        //retval = 读寄存器
    
        spin_unlock_irqrestore(&dev->lock, flags);
    
        return retval;
    #else
        return -EOPNOTSUPP;
    #endif
    }
    
    #ifdef XXXXX_WAKEUP
    //唤醒,举个例子net2272。它的寄存器usbctl0的第五位控制唤醒功能使能
    //寄存器usbctl1的第三位通过写1去resume,s3c2440在PWR_REG也有类似
    static int xxxxx_udc_wakeup(struct usb_gadget *usb_gdt_p)
    {
        struct xxxxx_udc *dev = to_xxxxx_udc(usb_gdt_p);
        unsigned long flags;
    
        spin_lock_irqsave(&dev->lock, flags);
    
        //寄存器操作
    
        spin_unlock_irqrestore(&dev->lock, flags);
    
        return 0;
    }
    #endif
    
    #ifdef XXXXX_SELFPOWERED
    //设置自供电标志(selfpowered feature),一般就用一个变量位或一个位记录一下。USB_RECIP_DEVICE时返回状态
    static int xxxxx_udc_set_selfpowered (struct usb_gadget *usb_gdt_p, int is_selfpowered)
    {
        struct xxxxx_udc *dev = to_xxxxx_udc(usb_gdt_p);
    
        if (is_selfpowered)
            dev->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
        else
            dev->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
    
        return 0;
    }
    #endif
    
    #ifdef XXXXX_VBUS_SESSION
    //vbus在硬件上就是usb的电源脚,这个函数就是来控制它。一般通过一个gpio拉高拉底
    //这个vbus会话,实际的我看了s3c2410和at91的处理,就是让usb的D+线与一个gpio口连接
    //通过置1置0来控制usb
    static int xxxxx_udc_vbus_session (struct usb_gadget *usb_gdt_p, int is_active)
    {
        struct xxxxx_udc *dev = to_xxxxx_udc(usb_gdt_p);
        unsigned long flags;
    
        spin_lock_irqsave(&dev->lock, flags);
    
        //寄存器操作
    
        spin_unlock_irqrestore(&dev->lock, flags);
    
        return 0;
    }
    #endif
    
    #ifdef XXXXX_VBBUS_DRAW
    //强制vbus电源控制器行为,在SET_CONFIGRATION时,设置vbus的电流量
    //vbus应该是表示总线电压,在硬件上是一个脚
    //主要是对usb电流的设置,看一下gta02平台,这个函数会操作pcf50633(一种移动设备的电源管理芯片)
    static int xxxxx_udc_vbus_draw (struct usb_gadget *usb_gdt_p, unsigned mA)
    {
        return 0;
    }
    #endif
    
    #ifdef XXXXXX_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 xxxxx_udc_pullup (struct usb_gadget *usb_gdt_p, int is_on)
    {
        struct xxxxx_udc *dev = to_xxxxx_udc(usb_gdt_p);
        unsigned long flags;
    
        spin_lock_irqsave(&dev->lock, flags);
    
        if (is_on)
        {
            //enable
        }
        else
        {
            //disable
        }
    
        spin_unlock_irqrestore(&dev->lock, flags);
    
        return 0;
    }
    #endif
    
    //不好意思,我看了linux-3.2.36的/gadget的目录没发现有实现这个的硬件
    static int xxxxx_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 xxxxx_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 XXXXX_NEWSTYLE
    static int xxxxx_udc_start(struct usb_gadget *usb_gdt_p, struct usb_gadget_driver *driver);
    static int xxxxx_udc_stop(struct usb_gadget *usb_gdt_p, struct usb_gadget_driver *driver);
    #else
    //s3c2410 xxxxx 实现它
    static int xxxxx_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *));
    static int xxxxx_stop(struct usb_gadget_driver *driver);
    #endif
    
    static const struct usb_gadget_ops xxxxx_ops = 
    {
        .get_frame        = xxxxx_udc_get_frame,
    #ifdef XXXXX_WAKEUP
        .wakeup            = xxxxx_udc_wakeup,
    #endif
    
    #ifdef XXXXX_SELFPOWERED
        .set_selfpowered = xxxxx_udc_set_selfpowered,
    #endif
    
    #ifdef XXXXX_VBUS_SESSION
        .vbus_session    = xxxxx_udc_vbus_session,
    #endif
    
    #ifdef XXXXX_VBBUS_DRAW
        .vbus_draw        = xxxxx_udc_vbus_draw,
    #endif
    
    #ifdef XXXXXX_PULLUP
        .pullup            = xxxxx_udc_pullup,
    #endif
    
        .ioctl          = xxxxx_udc_ioctl,
        .get_config_params = xxxxx_udc_get_config_params,
    #ifdef XXXXX_NEWSTYLE
        .udc_start         = xxxxx_udc_start,
        .udc_stop       = xxxxx_udc_stop,
    #else
        .start            = xxxxx_start,
        .stop            = xxxxx_stop,
    #endif
    };
    
    /***************************************************************/
    
    
    /***************************************************************/
    
    static struct xxxxx_udc udc_info = {
        .gadget = {
            .ops        = &xxxxx_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        = &xxxxx_ep_ops,
                .maxpacket    = EP0_FIFO_SIZE,
            },
            .dev        = &udc_info,
        },
    
        /* first group of endpoints */
        .ep[1] = {
            .num = 1,
            .ep = 
            {
                .name        = "ep1",
                .ops        = &xxxxx_ep_ops,
                .maxpacket    = EP1_FIFO_SIZE,
            },
            .dev        = &udc_info,
            .fifo_size    = EP1_FIFO_SIZE,
            .bEndpointAddress = EP1_ADDRESS,
            .bmAttributes    = EP1_ATTR,
        },
    };
    
    static void stop_activity(struct xxxxx_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 */
    
        xxxxx_usb_reset(dev);//复位或disable
        for (i = 0; i < XXXXX_ENDPOINTS; i++)
        {
            xxxxx_dequeue_all(&dev->ep[i], -ECONNABORTED);
        }
    
    #ifndef XXXXX_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)
        {
            xxxxx_usb_reinit(dev);//重初始化
        }
    }
    
    #ifdef XXXXX_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 xxxxx_udc_start(struct usb_gadget *usb_gdt_p, struct usb_gadget_driver *driver)
    {
        struct xxxxx_udc *dev;
    
        if (!driver || !driver->unbind || !driver->setup ||
            driver->speed != USB_SPEED_HIGH)
            return -EINVAL;
    
        dev = container_of(usb_gdt_p, struct xxxxx_udc, gadget);
    
        /* hook up the driver ... */
        driver->driver.bus = NULL;
        dev->driver = driver;
        dev->gadget.dev.driver = &driver->driver;
    
        //使能udc,硬件操作
    
        return 0;
    }
    
    static int xxxxx_udc_stop(struct usb_gadget *usb_gdt_p, struct usb_gadget_driver *driver)
    {
        struct xxxxx_udc *dev;
        unsigned long flags;
    
        dev = container_of(usb_gdt_p, struct xxxxx_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 goku实现它,参考goku
    static int xxxxx_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *usb_gdt_p))
    {
        struct xxxxx_udc *dev = &udc_info;
        int    retval = 0;
    
        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;
        }
    
        //使能udc,硬件操作
    
    register_error:
        dev->driver = NULL;
        dev->gadget.dev.driver = NULL;
        return retval;
    }
    
    static int xxxxx_stop(struct usb_gadget_driver *driver)
    {
        struct xxxxx_udc *dev = &udc_info;
        unsigned long    flags;
    
        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 xxxxx_udc_probe(struct platform_device *pdev)
    {
    
        struct xxxxx_udc *udc = &udc_info;
        struct device *dev = &pdev->dev;
        int retval;
        struct resource *res;
    #ifdef XXXXX_USE_IRQ
        struct resource *resirq;
    #endif
        resource_size_t res_size;
    
        dev_dbg(dev, "%s()\n", __func__);
    
    #ifdef XXXXX_HAVE_CLK
        udc->xxxxx_clk = clk_get(NULL, "xxxxx");
        if (IS_ERR(udc->xxxxx_clk)) 
        {
            dev_err(dev, "failed to get usb bus clock source\n");
            return PTR_ERR(udc->xxxxx_clk);
        }
    
        clk_enable(udc->xxxxx_clk);
    
    #if (CLK_DELAY_TIME != 0)
        mdelay(CLK_DELAY_TIME);
    #endif
    
        dev_dbg(dev, "got and enabled clocks\n");
    #endif //XXXXX_HAVE_CLK
    
        if (strncmp(pdev->name, "xxxxx", 7) == 0) {
            dev_info(dev, "xxxxx: increasing FIFO to %d bytes\n", XXXXX_EP_FILO_SIZE);
            udc_info.ep[1].fifo_size = XXXXX_EP_FILO_SIZE;
        }
    
        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;
        }
    /*
        pdata = pdev->dev.platform_data;
        if (!pdata) {
            dev_err(&pdev->dev, "driver needs platform data\n");
            return -ENODEV;
        }
    */
        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->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);
    
        //少不了硬件初始化
        xxxxx_usb_reset(udc);
        xxxxx_usb_reinit(udc);
    
    #ifdef XXXXX_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;
    
        /* irq setup after old hardware state is cleaned up */
        retval = request_irq(udc->irq_num, xxxxx_udc_irq, 0, gadget_name, 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 XXXXX_DEBUG_FS
        if (xxxxx_udc_debugfs_root) 
        {
            udc->debug_info = debugfs_create_file("registers", S_IRUGO, xxxxx_udc_debugfs_root,
                    udc, &xxxxx_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 XXXXX_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:
    #ifdef XXXXX_HAVE_CLK
        clk_put(udc->xxxxx_clk);
        clk_disable(udc->xxxxx_clk);
    #endif
    
        return retval;
    }
    
    static int xxxxx_udc_remove(struct platform_device *pdev)
    {
        struct xxxxx_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 XXXXX_DEBUG_FS
        debugfs_remove(udc->debug_info);
    #endif
    
    #ifdef XXXXX_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 XXXXX_HAVE_CLK
        if (!IS_ERR(udc->xxxxx_clk) && udc->xxxxx_clk != NULL) {
            clk_disable(udc->xxxxx_clk);
            clk_put(udc->xxxxx_clk);
            udc->xxxxx_clk = NULL;
        }
    #endif
    
        dev_dbg(&pdev->dev, "%s: remove ok\n", __func__);
    
        return 0;
    }
    
    #ifdef CONFIG_PM
    static int xxxxx_udc_suspend(struct platform_device *pdev, pm_message_t message)
    {
        return 0;
    }
    
    static int xxxxx_udc_resume(struct platform_device *pdev)
    {
        return 0;
    }
    #else
    #define xxxxx_udc_suspend    NULL
    #define xxxxx_udc_resume    NULL
    #endif
    
    /***************************************************************/
    
    static const struct platform_device_id xxxxx_udc_ids[] = {
        { "xxxxx-usbgadget", },
        { }
    };
    
    MODULE_DEVICE_TABLE(platform, xxxxx_udc_ids);
    
    //有些设备可能用struct pci_driver,我就不考虑这么多了。
    static struct platform_driver udc_driver_xxxxx = {
        .driver        = {
            .name    = "xxxxx-usbgadget",
            .owner    = THIS_MODULE,
        },
        .probe        = xxxxx_udc_probe,
        .remove        = __exit_p(xxxxx_udc_remove),
        .suspend    = xxxxx_udc_suspend,
        .resume        = xxxxx_udc_resume,
        .id_table    = xxxxx_udc_ids,
    };
    
    
    static int __init udc_init(void)
    {
        int retval;
    
        xxxxx_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);
        if (IS_ERR(xxxxx_udc_debugfs_root)) {
            printk(KERN_ERR "%s: debugfs dir creation failed %ld\n",
                gadget_name, PTR_ERR(xxxxx_udc_debugfs_root));
            xxxxx_udc_debugfs_root = NULL;
        }
    
        retval = platform_driver_register(&udc_driver_xxxxx);
        if (retval)
            goto err;
    
        return 0;
    
    err:
        debugfs_remove(xxxxx_udc_debugfs_root);
        return retval;
    }
    
    static void __exit udc_exit(void)
    {
        platform_driver_unregister(&udc_driver_xxxxx);
        debugfs_remove(xxxxx_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");

    下期预告:

    基于模板实现一个实际的udc驱动。



    展开全文
  • USB UDC驱动 gadget驱动

    2019-07-13 16:35:36
    例如,当某运行Linux系统的手机作为PC的U盘时,手机中的底层USB控制器行使USB设备控制器的功能,这时运行在底层的是UDC驱动,手机要成为U盘,在UDC驱动之上需要另外一个驱动,对于USB大容量存储...

    UDC(USB设备控制器)

    USB设备控制器(UDC)驱动指的是作为其他USB主机控制器外设的USB硬件设备上底层硬件控制器的驱动该硬件和驱动负责将一个USB设备依附于一个USB主机控制器上。例如,当某运行Linux系统的手机作为PC的U盘时,手机中的底层USB控制器行使USB设备控制器的功能,这时运行在底层的是UDC驱动,手机要成为U盘,在UDC驱动之上需要另外一个驱动,对于USB大容量存储器而言,这个驱动为File Storage驱动,称为Function驱动。
     

    Gadget(小配件)

    USB设备枚举的过程(参考抓包数据)为什么叫枚举

     

    1 设备插入主机,主机检测到设备,复位设备(USB_DEV_RESET)

    2 主机向设备控制端点发送Get_Descriptor来了解设备默认管道的大小

    3 主机指定一个地址,发送Set_Address标准请求设置设备的地址

    4 主机使用新的地址,再次发送Get_Descriptor获得各种描述符

    4 主机加载一个USB设备驱动

    6 USB设备驱动再发送Set_Confuration表示设备请求配置设备
     

    展开全文
  • Linux-USB Gadget : Part 5: 测试 PXA UDC 驱动作者: zjujoe 转载请注明出处Email:zjujoe@yahoo.comBLOG:http://blog.csdn.net/zjujoe 前言 USB协议的特性之一就是把复杂性留给软件。USB 驱动纷繁复杂,不管...
  • Linux gadget 驱动1

    2013-10-18 15:50:16
    gadget是在UDC驱动上面的一层,如果要编写gadget驱动只需调用linux 的gadget API,不需设计底层的UDC驱动. 但要是分析驱动BUG,就需要了同时了解一下UDC.  下面以简单的gadget zero驱动分析驱
  • 实例:Chipidea USB UDC驱动 drivers/usb/chipidea/udc.c是Chipidea USB UDC驱动的主体代码,代码清单16.33列出了它的初始化流程部分。它定义了usb_ep_ops、usb_gadget_ops,在最终进行usb_add_gadget_udc()之前...
  • Linux gadget驱动应用

    千次阅读 2014-05-20 23:40:17
    Linux内核中usb设备侧驱动程序分成3个层次:UDC驱动程序、Gadget API和Gadget驱动程序。UDC驱动程序(USB控制器)直接访问硬件,控制USB设备和主机间的底层通信,向上层提供与硬件相关操作的回调函数。Gadget ...
  • 删除了大量过时的内容,如redhat Linux 2.4内核更新到2.6、传统的按键驱动、SAA7113H启动、传统的IDE驱动等,同时新增了大量内容,包括Linux内核的编码风格、Linux内核的移植、Android驱动、USB UDC和gadget驱动、...
  • Linux USB驱动-鼠标驱动

    2021-03-18 21:28:36
    UDC驱动程序直接访问硬件,控制USB设备控制器与USB主机控制器通信,向上提供与硬件交互的接口。Gadget Function API封装了UDC驱动程序向上提供的接口。Gadget Function驱动程序实现具体的USB设备功能。Linux内核支持...
  • gadget是在UDC驱动上面的一层,如果要编写gadget驱动只需调用linux 的gadget API,不需设计底层的UDC驱动. 但要是分析驱动BUG,就需要了同时了解一下UDC.  下面以简单的gadget zero驱动分析驱动的...
  • linux usb驱动——USB OTG驱动

    千次阅读 2018-03-01 16:45:00
    摘自 linux usb驱动——USB协议架构及驱动架构 OTG驱动 OS_FS: 文件系统 USBD: USB核心 HCD: 主机控制器驱动 UDC: 设备端控制器驱动 OTG设备支持HNP和SRP协议。OTG设备通过USB OTG电缆连接到一起,其中接...
  • 例如,当某运行Linux系统的手机作为PC的U盘时,手机中的底层USB控制器行使USB设备控制器的功能,这时候运行在底层的是UDC驱动,而手机要成为U盘,在UDC驱动之上仍然需要另外一个驱动,对于USB大容量存储器而言,这个...
  • 图16.1 Linux USB驱动总体结构 如图16.1的右侧所示,Linux内核中USB设备侧驱动程序分为3个层次:UDC驱动程序、Gadget Function API和Gadget Function驱动程序。UDC驱动程序直接访问硬件,控制USB设备和主机间的...
  • linux gadget 驱动应用

    千次阅读 2014-01-04 11:30:49
    Linux内核中usb设备侧驱动程序分成3个层次:UDC驱动程序、Gadget API和Gadget驱动程序。UDC驱动程序(USB控制器)直接访问硬件,控制USB设备和主机间的底层通信,向上层提供与硬件相关操作的回调函数。Gadget ...
  • 上期说要用之前的模板写udc驱动。事实我已经做了,等待测试。当我要测试时,我发现还是要用gadget驱动去时udc驱动。虽然有现成的,但是你如果搞不懂的话,出问题你根本不知道在哪。所以调试udc驱动之前我们要看...
  • Linux USB驱动工作流程

    千次阅读 2014-09-13 20:40:39
    Linux驱动中,USB驱动处于最底层的是USB主机控制器硬件,在其之上运行的是USB主机控制器驱动,主机控制器之上为USB核心层,再上层为USB设备驱动层(插入主机上的U盘、鼠标、USB转串口等设备驱动)。 因此,在...
  • linux usb驱动详解

    2019-10-21 10:25:42
    如上图所示,从主机侧视角去看,在linux驱动中,usb驱动处于最上层,主要表现为usb主机侧的功能具体实现(比如U盘,鼠标,usb camer等),其下为usb核心层,主要完成usb驱动管理以及协议处理,再下为usb...
  • 16.4.1 UDC(USB设备控制器)和Gadget(小配件)驱动的关键数据结构与API USB设备...例如,当某运行Linux系统的手机作为PC的U盘时,手机中的底层USB控制器行使USB设备控制器的功能,这时运行在底层的是UDC驱动,手...
  • USB UDC与gadget驱动

    千次阅读 2011-10-09 23:34:42
    这里的USB设备控制器(UDC驱动指作为其他usb主机控制器外设的usb硬件设备上底层硬件控制器的驱动,该硬件和驱动负责将一个usb设备依附于一个usb主机控制器上。 在usb设备控制器于gadget驱动中,我们主要关心几个...
  • linux USB驱动层次

    2016-11-22 18:00:52
    USB 采用树形拓扑结构,主机侧和设备侧的USB 控制器分别称为主机...如图20.1 所示,在Linux 系统中,USB 驱动可以从两个角度去观察,一个角度是主机侧,一个角度是设备侧。     如图20.1 的左侧所示,从主机侧的观
  • Linux系统中,提供主机侧和设备侧视角的USB驱动框架,从主机侧看到的USB主机控制器和设备驱动,以及从设备侧看到的设备控制器和Gadget驱动Linux系统中USB驱动的整体视图 图1 (1) Mass storage USB Mass ...
  • linux设备驱动层次

    2016-03-10 10:42:00
    USB 采用树形拓扑结构,主机侧和设备侧的USB 控制器分别称为...如图20.1 所示,在Linux 系统中,USB 驱动可以从两个角度去观察,一个角度是主机侧,一个角度是设备侧。 如图20.1 的左侧所示,从主机侧的观...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,303
精华内容 521
关键字:

linuxudc驱动

linux 订阅