首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

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

2013-10-13 
自娱自乐8之Linux UDC驱动4(自编udc驱动,基本功能完成)直接上代码,可以和我之前写的模板比较比较/********

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

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

/*********************************** 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_FSstatic 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,此位为1if (ep_num > 4 || crq->wLength > 2)//crq->wLength为2return 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 DEBUGstatic int printDesc = 0;#endifstatic 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 fifoSETB(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 DATASETB(dev, IN_CSR2_REG, 4);//关闭in dma中断,先不用dma        CLRB(dev, IN_CSR2_REG, 5);//out        //SETB(dev, OUT_CSR1_REG, 0);//清楚IN_PKT_RDYSETB(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硬件不支持,没实现,上层调用会得到-EOPNOTSUPPstatic 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_haltif ((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_haltif ((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_SETWEDHEstatic 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);}#endifstatic 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来控制usbstatic 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_NEWSTYLEstatic 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);#endifstatic 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实现的就是它//下面参考net2272static 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 实现它//下面参考s3c2440static 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);#endiferr_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);#endiferr_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_PMstatic 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");


热点排行