自己娯楽自楽8のLinux UDC駆動4(自作udc駆動、基本機能完了)


直接コードをつけて、私の前に書いたテンプレートと比較することができます
/***********************************
 Copyright(C), 2013 LDP
 FileName:  s3c2440_udc.h
 Author:    wwxxxxll
 Date:          
 Description:  
 History:       
 Author       Date            Desc
************************************/
#ifndef __S3C2440_UDC_H__
#define __S3C2440_UDC_H__
/*************    **************/
#define S3C2440_DEBUG_FS  //  debugfs
#define DEBUG
#ifdef DEBUG
#define printInfo(ARGs...) printk(ARGs)
#else
#define printInfo(ARGs...)
#endif
//struct usb_ep_ops
//#define S3C2440_NEWSTYLE  //  udc_start
#define S3C2440_SETWEDHE  //  set_weght  
#define S3C2440_FIFO_STATUS //  fifo_status  
#define S3C2440_FIFO_FLUSH //  fifo_flush  

//struct usb_gadget_ops
#define S3C2440_S3C2440_GET_FRAME //  get_frame
#define S3C2440_WAKEUP //  wakeup  
#define S3C2440_SELFPOWERED //selfpowered  
//#define S3C2440_VBUS_SESSION //vbus      
//#define S3C2440_VBBUS_DRAW
#define S3C2440X_PULLUP //usb      

//s3c2440      
//   CLKSLOW  UPLL
//CLKCON  USB device  ,      clk,       
//          ,        ,         
//        
#define S3C2440_HAVE_CLK  //    CLK
#ifdef S3C2440_HAVE_CLK
#define CLK_DELAY_TIME 10 //ms
#endif

#define S3C2440_USE_IRQ

//    
#define S3C2440_ENDPOINTS 5 //   
//          
#define EP0_FIFO_SIZE 8
#define EP1_FIFO_SIZE 64
#define EP2_FIFO_SIZE 64
#define EP3_FIFO_SIZE 64
#define EP4_FIFO_SIZE 64

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

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

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

/*************     ************/
//s3c2440   MISCCR  usb1       
//       ,      。MISCCR USB  
//            
//                           。
//       
#define FUNC_ADDR_REG 0x140
//func_addr_reg   usb  ,     , 7   
#define PWR_REG       0x144
/*
pwr_reg:
3: USB_RESET R         , USB  
2: MCS_RESUME R/W MCU    MCU  ,      ,  10ms    
1: SUSPEND_MODE R           USB  。
0: SUBSPEND_EN R      ,0:   1:  
*/
//   MCU     ,MCU                            。
#define EP_INT_REG 0x148
#define USB_INT_REG 0x158

//    
#define EP_INT_EN_REG 0x15c
#define USB_INT_EN_REG 0x16c

//  
#define FRAME_NUM1_REG 0x170 //   
#define FRAME_NUM2_REG 0x174 //   

//          INDEX   (INDEX_REG)(    :0X178)   。        EP0 
//CSR   ,    IN_CSR1      ‘0x00’ INDEX_REG 
#define INDEX_REG 0x178

#define MAXP_REG 0x180
/*
  :
EP0 MAXP=8
EP1~4 MAXP=64, 64             data0 data1
*/

#define EP0_CSR 0x184 

#define IN_CSR1_REG 0x184
#define IN_CSR2_REG 0x188

#define OUT_CSR1_REG 0x190
#define OUT_CSR2_REG 0x194

//FIFO
//          
//            ,   MCU  
#define OUT_FIFO_CNT1 0x198
#define OUT_FIFO_CNT2 0x19c

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

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

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

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

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

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

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

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

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


//  D+    gpc5,       ,  mmap gpio,     
#define PULL_UP()    do { \
                       writel((readl(S3C2410_GPCCON) | (1 << 10)) & (~(1 << 11)), S3C2410_GPCCON); \
                       writel(readl(S3C2410_GPCUP) & (~(1 << 5)), S3C2410_GPCUP); \
                       writel(readl(S3C2410_GPCDAT) | (1 << 5), S3C2410_GPCDAT); \
                   }while(0);

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

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

/*************    **************/
//  setup_end  
#define EP0_CLRSE(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 SETB(_s3c2440_udc, EP0_CSR, 7); \
                                }while(0)

//out       
#define EP0_CLROPR(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 SETB(_s3c2440_udc, EP0_CSR, 6); \
                                }while(0)

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

//  stall  
#define EP0_CLRSST(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 CLRB(_s3c2440_udc, EP0_CSR, 5); \
                                }while(0)  
//  stall
#define EP0_SETSST(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 SETB(_s3c2440_udc, EP0_CSR, 5); \
                                }while(0)          

//      
#define EP0_CLRDE(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 CLRB(_s3c2440_udc, EP0_CSR, 2); \
                                }while(0)

//in       
#define EP0_SETIPR(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 SETB(_s3c2440_udc, EP0_CSR, 1);  \
                                }while(0) 
/***********************************/


struct s3c2440_ep 
{
    struct usb_ep ep; //      
    struct list_head queue;
    struct s3c2440_udc *dev;
    const struct usb_endpoint_descriptor *desc;

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

    u16 fifo_size;
    u8 num;

    unsigned stopped :1;//          

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

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

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

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

//        ,        ,         
//       ,             
enum ep0state {
    EP0_IDLE,
    EP0_IN, 
    EP0_OUT,    
    EP0_STALL,        
};
    
struct s3c2440_udc 
{
    spinlock_t lock;
    
    void __iomem *virl_addr;
    u32 phy_addr;
    u32 reg_size;

    struct usb_gadget gadget;
    struct usb_gadget_driver *driver;

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

#ifdef S3C2440_DEBUG_FS
    struct dentry *debug_info;
#endif 

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

#ifdef S3C2440_USE_IRQ
    unsigned int irq_num;
#endif

    u16    devstatus;
};

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

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

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

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

#include <mach/regs-gpio.h>

#include "s3c2440_udc.h"

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

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

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



//        
// epautoconf.c   
/* type-restriction:  "-iso", "-bulk", or "-int".
 * direction-restriction:  "in", "out".
 */
//  
static const char ep0name[] = "ep0";
static const char * const ep_name[] = {
    ep0name,
    "ep1-bulk", "ep2-bulk", "ep3-bulk", "ep4-bulk",
};
//  mount -t debugfs none /sys/kernel/debug/
///sys/kernel/debug
#ifdef S3C2440_DEBUG_FS
static struct dentry *s3c2440_udc_debugfs_root;

static int s3c2440_udc_debugfs_seq_show(struct seq_file *m, void *p)
{
    seq_printf(m, "My name is %s
", 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
", _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
", __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
", 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
", __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
", \ 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
", \ 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
", 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("
"); 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
", \ 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
"); 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
", __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
"); 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
"); 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
"); 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
"); 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
"); switch (ctrlq.wValue >> 8) { case USB_DT_DEVICE: printInfo( "USB_DT_DEVICE
"); break; // , USB // , (Device_Qualifier)。 case USB_DT_DEVICE_QUALIFIER: printInfo( "USB_DT_DEVICE_QUALIFIER
"); break; case USB_DT_OTHER_SPEED_CONFIG: printInfo( "USB_DT_OTHER_SPEED_CONFIG
"); break; case USB_DT_CONFIG: printInfo( "USB_DT_CONFIG
"); break; case USB_DT_STRING: printInfo( "USB_DT_STRING
"); break; // , USB // , case USB_DT_BOS: printInfo( "USB_DT_BOS
"); break; } EP0_CLROPR(dev); break; case USB_REQ_SET_DESCRIPTOR: printInfo( "USB_REQ_SET_DESCRIPTOR
"); EP0_CLROPR(dev); break; case USB_REQ_GET_CONFIGURATION: printInfo( "USB_REQ_GET_CONFIGURATION
"); EP0_CLROPR(dev); break; case USB_REQ_SET_CONFIGURATION: if (ctrlq.bRequestType == USB_RECIP_DEVICE) { printInfo( "USB_REQ_SET_CONFIGURATION
"); config = 1; EP0_CLROPR(dev); EP0_SETDE(dev); } break; case USB_REQ_GET_INTERFACE: printInfo( "USB_REQ_GET_INTERFACE
"); EP0_CLROPR(dev); break; case USB_REQ_SET_INTERFACE: if (ctrlq.bRequestType == USB_RECIP_INTERFACE) { printInfo( "SB_REQ_SET_INTERFACE
"); config = 1; EP0_CLROPR(dev); EP0_SETDE(dev); } break; case USB_REQ_SYNCH_FRAME: printInfo( "USB_REQ_SYNCH_FRAME
"); 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
"); 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
", usb_status); //printInfo( "EP_INT_REG = 0x%x
", 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
"); 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
"); 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
"); 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
"); 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); 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
", __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
", __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
", __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
", __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
", __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
", __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
", __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
", __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
", __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
", __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
", __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
", __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
", __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
", __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
", __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
", __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
", __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
", __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
", __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()
", __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
"); 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
"); 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
"); #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
"); 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
", 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
"); 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
", udc->irq_num, retval); retval = -EBUSY; goto err_map; } dev_dbg(dev, "got irq %i
", 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
"); } #endif dev_dbg(dev, "probe ok
"); 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()
", __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
", __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
", 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");