自娛自樂7之Linux UDC驅動2(自編udc驅動,現完成枚舉過程,從驅動代碼分析枚舉過程)

花了半個月,才搞定驅動中的枚舉部分,現在說linux的枚舉,windows可能有差別。

代碼我會貼在後面,現在只是實現枚舉,你可能對代碼不感興趣,我就不分析代碼了,你可以看看

在《自娛自樂1》中的模板,比較一下,我做了什麼,這會給你寫udc驅動提供個思路。我直接分析

調試打印,就是枚舉過程,我們從代碼看枚舉。打印位置可以在下面的代碼裏找到。

如果你要弄懂驅動代碼中涉及枚舉的地方,你就仔細看看代碼在那打印的,這個對你完成一個udc驅

動有幫助。

如果你只是想簡單瞭解枚舉你就看看我分析的調試打印就可以了。

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

這個是枚舉過程,對照着上面說的看我的調試打印,提示我的是從機,他說的是主機。

# insmod s3c2440_add_udc.ko

UPLLCON = 38022, wxl add//驅動usb的時鐘源

# insmod s3c2440_udc.ko

# insmod gadget_transfer.ko

s3c2440_start//調用s3c2440_start(),在此會PULL_UP

s3c2440_udc_alloc_request//分配請求結構體內存

gadget_transfer gadget: gadget_transfer ready

# USB reset//pc檢測到PULL_UP 復位設備

USB ep0 irq//ep0中斷

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

//bRequest = 06是請求描述符,bRequestType = 80輸入方向(輸入是對主機而言) 端點0

//請求長度64(微軟的策略,這裏linux學微軟的)。

//wValue = 0x100: 這個前面的1表示設備描述符

 

USB_REQ_GET_DESCRIPTOR//第一次請求主要是獲取最大包長度,此值在設備描述符第8個字節

USB_DT_DEVICE//設備描述符請求

s3c2440_udc_queue//調用了s3c2440_udc_queue()

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

// Vendor = ff0 Product = ff0 Device = 212 這個在上一篇的gadget_transfer驅動中可以看到

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

// bNumConfigurations = 1 你看看我上一篇的gadget_transfar驅動寫的是2,這裏卻是1

/*

bNumConfigurations是配置數,是用count_configs()統計的,和你在gadget驅動中賦值無關

     多配置很少,不過還是有,例如multi.c可以配置爲RNDIS或ECM。

*/

8bytes USB USB reset //一次發出8個字節,我的ep0最大包長度是8,還有下面的xbytes都是已發的字節數。微軟的策略後面沒發完的不要了,直接復位設備。沒有按usb spec來做。Windows要接受16個才復位。

USB ep0 irq

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

//主機的請求又來了,這次是設置地址

// bRequest = 05 就是設置地址請求,

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

//wValue=0x4 設備地址4,在驅動中看不到它的使用,應該是硬件來判斷

USB_REQ_SET_ADDRESS

USB ep0 irq//這個我調試是數據沒準備好

USB ep0 irq

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

//這次是真的獲取設備描述符,長度18

USB_REQ_GET_DESCRIPTOR

USB_DT_DEVICE

s3c2440_udc_queue

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

8bytes USB ep0 irq

 

 16bytes USB ep0irq

 18bytes USB ep0irq

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

/*

wValue = 0x200: 這個前面的2表示配置描述符,後面是引索

*/

 

//獲取配置描述符

USB_REQ_GET_DESCRIPTOR

USB_DT_CONFIG

s3c2440_udc_queue

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

/*

length = 9描述符長度爲9

TotalLength = 32配置信息的長度--包括配置描述符、接口描述符、端點描述符長度的總和

NumInterfaces = 1 接口數

ConfigurationValue = 3用於表示 USB設備的配置值,主機就是根據這個選

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

bMaxPower = 250用於表示 USB設備運行時所需要消耗的總線電流,單位以2mA 爲基準。USB設備可以從USB總線上獲得最大的電流爲500mA,因此 bMaxPower 字段的最大值可以設置爲250

還有個bmAttributes,沒打印

*/

8bytes USB ep0 irq

 9bytes USB ep0irq

USB ep0 irq

USB ep0 irq

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

/*

wValue = 0x300: 這個前面的3表示字符串描述符,後面是引索0

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

/* 0 == report all availablelanguage codes */

可用的語言數,不細說

*/

USB_REQ_GET_DESCRIPTOR

USB_DT_STRING

s3c2440_udc_queue

Slave: length = 4

 4bytes USB ep0irq

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

//3是上面的iSerialNumber = 3

USB_REQ_GET_DESCRIPTOR

USB_DT_STRING

s3c2440_udc_queue

Slave: length = 66

0123456789.0123456789.0123456789

 //可以在上一篇的驅動開的這個,static charserial[] = "0123456789.0123456789.0123456789";

8bytes USB ep0 irq

 16bytes USB ep0irq

 24bytes USB ep0irq

 32bytes USB ep0irq

 40bytes USB ep0irq

 48bytes USB ep0irq

 56bytes USB ep0irq

 64bytes USB ep0irq

 66bytes USB ep0irq

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

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

USB_REQ_GET_DESCRIPTOR

USB_DT_CONFIG

s3c2440_udc_queue

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

 8bytes USB ep0irq

 16bytes USB ep0irq

 24bytes USB ep0irq

 32bytes USB ep0irq

 32bytes USB ep0irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_STRING

s3c2440_udc_queue

Slave: length = 4

 4bytes USB ep0irq

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

// iProduct = 2

USB_REQ_GET_DESCRIPTOR

USB_DT_STRING

s3c2440_udc_queue

Slave: length = 46

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

 8bytes USB ep0irq

 16bytes USB ep0irq

 24bytes USB ep0irq

 32bytes USB ep0irq

 40bytes USB ep0irq

 46bytes USB ep0irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_STRING

s3c2440_udc_queue

Slave: length = 4

 4bytes USB ep0irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_STRING

s3c2440_udc_queue

Slave: length = 46

Gadget gadget_transfer

 8bytes USB ep0irq

 16bytes USB ep0irq

 24bytes USB ep0irq

 32bytes USB ep0irq

 40bytes USB ep0irq

 46bytes USB ep0irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_DEVICE//獲取設備描述符

s3c2440_udc_queue

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

 8bytes USB ep0irq

 16bytes USB ep0irq

 18bytes USB ep0irq

USB ep0 irq

Host: bRequest = 06 bRequestType = 80 wValue = 0x100wIndex=0x0 wLength=0x40//這裏有用64長度請求一次

USB_REQ_GET_DESCRIPTOR

USB_DT_DEVICE

s3c2440_udc_queue

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

 8bytes USB ep0irq

 16bytes USB ep0irq

 18bytes USB ep0irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_DEVICE//又來一次

s3c2440_udc_queue

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

 8bytes USB ep0irq

 16bytes USB ep0irq

 18bytes USB ep0irq

USB ep0 irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_DEVICE_QUALIFIER

//設備限定描述符用於指定另一傳輸速率下該設備的總體信息,如果高速USB設備既需要採用高速傳//輸又需要全速傳輸,則它必須支持設備限定描述符(Device_Qualifier)。全速設備不支持

//我的是全速設備用不倒QUALIFIERcomposite.cgadget_is_dualspeed()這個判斷

USB ep0 irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_DEVICE_QUALIFIER

USB ep0 irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_DEVICE_QUALIFIER

USB ep0 irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_CONFIG//這次你會看到到wValue & 0xff 03

// iManufacturer = 1 iProduct = 2iSerialNumber = 3

s3c2440_udc_queue

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

 8bytes USB ep0irq

 9bytes USB ep0irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_CONFIG

s3c2440_udc_queue

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

 8bytes USB ep0irq

 16bytes USB ep0irq

 24bytes USB ep0irq

 32bytes USB ep0irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_STRING

s3c2440_udc_queue

Slave: length = 4

 4bytes USB ep0irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_STRING

s3c2440_udc_queue

Slave: length = 46

Gadget gadget_transfer

 8bytes USB ep0irq

 16bytes USB ep0irq

 24bytes USB ep0irq

 32bytes USB ep0irq

 40bytes USB ep0irq

 46bytes USB ep0irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_STRING

s3c2440_udc_queue

Slave: length = 58

Linux 3.2.0 with s3c2440_udc

/*

還記得我的gadget驅動開始

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

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

        gadget->name);

*/

 8bytes USB ep0irq

 16bytes USB ep0irq

 24bytes USB ep0irq

 32bytes USB ep0irq

 40bytes USB ep0irq

 48bytes USB ep0irq

 56bytes USB ep0irq

 58bytes USB ep0irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_STRING

s3c2440_udc_queue

Slave: length = 66

0123456789.0123456789.0123456789

 8bytes USB ep0irq

 16bytes USB ep0irq

 24bytes USB ep0irq

 32bytes USB ep0irq

 40bytes USB ep0irq

 48bytes USB ep0irq

 56bytes USB ep0irq

 64bytes USB ep0irq

 66bytes USB ep0irq

USB ep0 irq

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

USB_REQ_SET_CONFIGURATION//設置配置

// wValue = 0x3對應上面的ConfigurationValue = 3程序中是

/*

static struct usb_configurationsourcesink_driver = {

    .label        = "source/sink",

    .strings   = sourcesink_strings,

    .setup        = sourcesink_setup,

    .bConfigurationValue = 3,

    .bmAttributes    = USB_CONFIG_ATT_SELFPOWER,

    /* .iConfiguration = DYNAMIC */

};

*/

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

s3c2440_udc_ep_enable

s3c2440_udc_ep_enable

s3c2440_udc_queue

USB ep0 irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR

USB_DT_STRING

s3c2440_udc_queue

Slave: length = 42

source and sink data9

 8bytes USB ep0irq

 16bytes USB ep0irq

 24bytes USB ep0irq

 32bytes USB ep0irq

 40bytes USB ep0irq

 42bytes USB ep0irq

USB ep0 irq

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

USB_REQ_GET_DESCRIPTOR//這裏引索是4就是iConfiguration = 4

USB_DT_STRING

s3c2440_udc_queue

Slave: length = 42

source and sink data9

/*代碼

static struct usb_stringstrings_sourcesink[] = {

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

    {  }           /* end of list */

};

*/

 8bytes USB ep0irq

 16bytes USB ep0irq

 24bytes USB ep0irq

 32bytes USB ep0irq

 40bytes USB ep0irq

 42bytes USB ep0irq

 

有些重複的請求就是爲了確認。

下面是代碼:(現在只能枚舉),可以把內核自帶的驅動和我的比較一下,我的宗旨是應用我的模板。

s3c2440_udc.h

/***********************************
 Copyright(C), 2013 LDP
 FileName:  s3c2440_udc.h
 Author:    wwxxxxll
 Date:          
 Description:  
 History:       
 Author       Date            Desc
************************************/
#ifndef __S3C2440_UDC_H__
#define __S3C2440_UDC_H__
/*************配置選項**************/
#define S3C2440_DEBUG_FS  //使用debugfs
#define DEBUG
//struct usb_ep_ops
//#define S3C2440_NEWSTYLE  //使用udc_start
#define S3C2440_SETWEDHE  //實現set_weght方法
#define S3C2440_FIFO_STATUS //支持fifo_status方法
#define S3C2440_FIFO_FLUSH //支持fifo_flush方法

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

//s3c2440 有時鐘控制
//寄存器CLKSLOW開啓UPLL
//CLKCON開啓USB device時鐘,我會定義兩個clk,見下面的結構體
//我可以直接操作寄存器,但是那樣太粗魯了,我們還是用平臺提供
//的時鐘機制解決吧
#define S3C2440_HAVE_CLK  //有專用的CLK
#ifdef S3C2440_HAVE_CLK
#define CLK_DELAY_TIME 10 //ms
#endif

#define S3C2440_USE_IRQ

//端口信息
#define S3C2440_ENDPOINTS 5 //端口數
//一個端點的最大數據包
#define EP0_FIFO_SIZE 8
#define EP1_FIFO_SIZE 64
#define EP2_FIFO_SIZE 64
#define EP3_FIFO_SIZE 64
#define EP4_FIFO_SIZE 64

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

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

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

/*************寄存器定義************/
//s3c2440 有個MISCCR控制usb1爲設備還是主機
//芯片默認爲設備,我就不控制了。MISCCR的USB掛起
//主要爲芯片進入睡眠時用的
//如果按字節模式訪問則偏移地址在大端和小端模式中是不同的。
//我是小端的地址
#define FUNC_ADDR_REG 0x140
//func_addr_reg 存儲usb地址,更新地址時,第7位置位
#define PWR_REG       0x144
/*
pwr_reg:
3: USB_RESET R  主機發復位信號,由USB置位
2: MCS_RESUME R/W MCU置位來給MCU重置,在掛起模式時,產生10ms重置信號
1: SUSPEND_MODE R 設備進入掛起模式時由USB置位。
0: SUBSPEND_EN R 掛起使能位,0:禁止 1:使能
*/
//一旦 MCU 發生中斷,MCU 應該讀取中斷相關寄存器的內容並且如果需要寫回清除其內容。
#define EP_INT_REG 0x148
#define USB_INT_REG 0x158

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

//幀號
#define FRAME_NUM1_REG 0x170 //低字節
#define FRAME_NUM2_REG 0x174 //高字節

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

#define MAXP_REG 0x180
/*
推薦:
EP0 MAXP=8
EP1~4 MAXP=64, 64自動使能雙數據包模式 就是data0和data1
*/

#define EP0_CSR 0x184 

#define IN_CSR1_REG 0x184
#define IN_CSR2_REG 0x188

#define OUT_CSR1_REG 0x190
#define OUT_CSR2_REG 0x194

//FIFO
//端點輸出寫計數寄存器
//此寄存器保存着包的字節數,該數由MCU卸載
#define OUT_FIFO_CNT1 0x198
#define OUT_FIFO_CNT2 0x19c

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

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

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

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

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

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

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

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

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


//我的D+控制口爲gpc5,這裏我也偷懶了,沒有mmap gpio,用了平臺的
#define PULL_UP()    do { \
                       writel((readl(S3C2410_GPCCON) | (1 << 10)) & (~(1 << 11)), S3C2410_GPCCON); \
                       writel(readl(S3C2410_GPCUP) & (~(1 << 5)), S3C2410_GPCUP); \
                       writel(readl(S3C2410_GPCDAT) | (1 << 5), S3C2410_GPCDAT); \
                   }while(0);

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

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

/*************簡單操作**************/
//清楚setup_end標誌
#define EP0_CLRSE(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 SETB(_s3c2440_udc, EP0_CSR, 7); \
                                }while(0)

//out數據已讀完標誌
#define EP0_CLROPR(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 SETB(_s3c2440_udc, EP0_CSR, 6); \
                                }while(0)

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

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

//清楚數據異常
#define EP0_CLRDE(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 CLRB(_s3c2440_udc, EP0_CSR, 2); \
                                }while(0)

//in數據已寫完標誌
#define EP0_SETIPR(_s3c2440_udc) do { \
                                 WRITE_REG(_s3c2440_udc, INDEX_REG, 0); \
                                 SETB(_s3c2440_udc, EP0_CSR, 1);  \
                                }while(0) 
/***********************************/


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

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

    u16 fifo_size;
    u8 num;

    unsigned stopped :1;//維護一個端口停止標誌

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

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

struct s3c2440_request 
{
    struct list_head        queue;        /* ep's requests */
    struct usb_request        req;        //對應主機端看到的urb
};

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

//根據實際要求定義,這個不能當做模板,主要是便於軟件管理
//一般有下面幾個,有的驅動不用這些定義去管理
enum ep0state {
    EP0_IDLE,
    EP0_IN, 
    EP0_OUT,    
    EP0_STALL,        
};
    
struct s3c2440_udc 
{
    spinlock_t lock;
    
    void __iomem *virl_addr;
    u32 phy_addr;
    u32 reg_size;

    struct usb_gadget gadget;
    struct usb_gadget_driver *driver;

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

#ifdef S3C2440_DEBUG_FS
    struct dentry *debug_info;
#endif 

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

#ifdef S3C2440_USE_IRQ
    unsigned int irq_num;
#endif

    u16    devstatus;
};

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

#endif//__S3C2440_UDC_H__

s3c2440.c

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

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

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

#include <mach/regs-gpio.h>

#include "s3c2440_udc.h"

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

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

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



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

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

    return 0;
}

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

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

/***********************hardware_handler************************/
//s3c2440沒有控制usb開啓位,就等到start時使能中斷,imx不是這樣
static void s3c2440_usb_reset(struct s3c2440_udc *dev)
{
    //disable intterupt
    WRITE_REG(dev, EP_INT_EN_REG, 0x00);
    WRITE_REG(dev, USB_INT_EN_REG, 0x00);

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

    PULL_DOWN();

    dev->gadget.speed = USB_SPEED_UNKNOWN;
}

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

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

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

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

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

#ifndef S3C2440_NEWSTYLE
    PULL_UP();
#endif
}

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

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

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

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

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

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

    return count;
}

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

/*
返回
1: 讀包結束
0: 還沒讀完
-1: 錯誤
*/
static int s3c2440_read_fifo(struct s3c2440_udc *dev, struct s3c2440_ep *ep, struct s3c2440_request *req)
{
    u32 fifo_reg;
    u8 *buf;
    u32 idx = 0;
    u32 fifo_count, avail, len, bufspace;
    int ret = 0;

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

    idx = ep->bEndpointAddress & 0x7f;

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

    fifo_reg = EP0_FIFO + 4 * idx;

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

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

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

    WRITE_REG(dev, INDEX_REG, idx);

    s3c2440_usb_fifocnt(dev, &fifo_count);

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

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

    //req->req.actual已接收長度,req->req.length要接收的總長度
    printk(  "read: req->req.actual = %d, req->req.length = %d\n", req->req.actual, req->req.length);

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

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

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

        s3c2440_udc_done(ep, req, 0);
    } else 
    {
        if (idx == 0) 
        {
            EP0_CLROPR(dev);
        } 
        else 
        {
        }
    }
    return ret;
}

static int printDesc = 0;

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

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

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

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

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

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

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

        break;
    case USB_DT_STRING:
        string = (struct usb_string_descriptor *)req->req.buf;
        printk(  "Slave: length = %d\n", string->bLength);
        language = cpu_to_le16(0x0409);//這裏偷工減料了,因爲gadget是我自己寫的我知道是什麼語言

        if (string->bLength == 4)//支持語言數量
        {
            break;
        }
        for (tmp = (u8 *)string->wData, n = 0; n < string->bLength; n++, tmp++) 
        {
            if (*tmp == language)
            {
            }
            else
            {
                printk( "%c", *tmp);//沒考慮大小端
            }
        }

        printk("\n");

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

    printDesc = 0;

    idx = ep->bEndpointAddress & 0x7f;

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

    fifo_reg = EP0_FIFO + 4 * idx;

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

    prefetch(buf);//prefetch將這一塊數據讀取到cache之中,以便後繼快速訪問,爲了下面的writesb

    req->req.actual += len;

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

    //req->req.actual已發送長度
    printk(  " %dbytes ", req->req.actual);

    if (len != ep->ep.maxpacket)
        ret = 1;
    else if (req->req.length != req->req.actual || req->req.zero)//zero當要發送的長度小於請求長度是爲1
        ret = 0;
    else
        ret = 2;

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

        }

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

        }
    }

    return ret;
}

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

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

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

    if (!(ep0_csr & 1))//判斷數據是否接收完成
    {
        return;
    }

    s3c2440_dequeue_all(ep, -EPROTO);

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

        return;
    }

    //EP0_CLROPR是數據接收結束,EP0_SETDE是數據傳輸結束
    switch (ctrlq.bRequest)
    {
    case USB_REQ_GET_STATUS: printk(  "USB_REQ_GET_STATUS\n");
        EP0_CLROPR(dev);
        if ((ctrlq.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
        {

        }

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

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

    case USB_REQ_GET_DESCRIPTOR: printk(  "USB_REQ_GET_DESCRIPTOR\n");
        switch (ctrlq.wValue >> 8) 
        {
        case USB_DT_DEVICE: printk(  "USB_DT_DEVICE\n");
            break;
        //設備限定描述符用於指定另一傳輸速率下該設備的總體信息,如果高速 USB設備既需要採用高速傳輸又需
        //要全速傳輸,則它必須支持設備限定描述符(Device_Qualifier)。全速設備不支持
        case USB_DT_DEVICE_QUALIFIER: printk(  "USB_DT_DEVICE_QUALIFIER\n");
            break;
        case USB_DT_OTHER_SPEED_CONFIG: printk(  "USB_DT_OTHER_SPEED_CONFIG\n");
            break;
        case USB_DT_CONFIG: printk(  "USB_DT_CONFIG\n");
            break;
        case USB_DT_STRING: printk(  "USB_DT_STRING\n");
            break;
        //其他速率配置描述符用於指定另一傳輸速率下該設備的配置信息,如果高速USB設備既需要採用高速傳輸
        //又需要全速傳輸,則它必須支持其他速率配置描述符
        case USB_DT_BOS: printk(  "USB_DT_BOS\n");
            break;
        }

        EP0_CLROPR(dev);

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

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

            EP0_CLROPR(dev);
            EP0_SETDE(dev);
        }

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

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

    if (!dev->driver)
        return;

    //爲了queue()中的調試打印設置標誌
    switch (ctrlq.bRequest)
    {
    case USB_REQ_GET_DESCRIPTOR:
        switch (ctrlq.wValue >> 8) 
        {
        case USB_DT_DEVICE:printDesc = USB_DT_DEVICE;
            break;
        case USB_DT_DEVICE_QUALIFIER: printDesc = USB_DT_DEVICE_QUALIFIER;
            break;
        case USB_DT_OTHER_SPEED_CONFIG: printDesc = USB_DT_OTHER_SPEED_CONFIG;
            break;
        case USB_DT_CONFIG: printDesc = USB_DT_CONFIG;
            break;
        case USB_DT_STRING: printDesc = USB_DT_STRING;
            break;
        case USB_DT_BOS: 
            break;
        }
        break;
    }

    if (dev->driver->setup(&dev->gadget, &ctrlq) < 0)
    {
        if (config == 1)//配置錯誤,不要send stall,會重新選配置
        {
            return;
        }

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

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

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

    WRITE_REG(dev, INDEX_REG, 0);

    ep0_csr = READ_REG(dev, EP0_CSR);

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

        EP0_CLRSST(dev);

        dev->ep0state = EP0_IDLE;

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

        EP0_CLRSE(dev);

        dev->ep0state = EP0_IDLE;
    }

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

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

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

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

//udc的這個中斷,真是包羅萬象,各硬件差別比較大
//簡單一點說,就是清楚中斷標緻位,再根據中斷標誌位對應處理
//實際要複雜的多,如果是ep0,還會從fifo中取得usb_ctrlrequest
//進行對應的處理,我們在實現具體的實現時再說吧
static irqreturn_t s3c2440_udc_irq(int dummy, void *_dev)
{
    struct s3c2440_udc *dev = (struct s3c2440_udc *)_dev;
    unsigned long flags;
    int usb_status;
    int ep_status;

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

    spin_lock_irqsave(&dev->lock, flags);

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

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

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

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

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

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

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

        SETB(dev, USB_INT_REG, 2);

        spin_unlock_irqrestore(&dev->lock, flags);

        return IRQ_HANDLED;
    }

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

        SETB(dev, USB_INT_REG, 1);

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

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

        SETB(dev, USB_INT_REG, 0);

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

        dev->ep0state = EP0_IDLE;
    }

    if (ep_status & 1)
    {
        printk(  "USB ep0 irq\n");

        SETB(dev, EP_INT_REG, 0);

        s3c2440_handle_ep0(dev);
    }

    spin_unlock_irqrestore(&dev->lock, flags);

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

/***********************queue***********************************/
//對於usb請求,一般都要維護一個list去管理請求

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

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

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

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

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

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

    list_del_init(&req->queue);

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

    dev = ep->dev;

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

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

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

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


/***************************************************************/
//may not be the endpoint named "ep0".這是gadget.h的源話
/**************************ep_ops*******************************/
//描述端點操作

//當設備配置或接口設置改變時,驅動會enable或disable端口
static int s3c2440_udc_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
{
    struct s3c2440_udc    *dev;
    struct s3c2440_ep    *ep;
    u32 max;
    unsigned long    flags;

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

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

    max = usb_endpoint_maxp(desc) & 0x1fff;

    spin_lock_irqsave(&dev->lock, flags);

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

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

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

        SETB(dev, IN_CSR2_REG, 0);//關閉in dma中斷,先不用dma
        SETB(dev, IN_CSR2_REG, 5);//in
        SETB(dev, IN_CSR2_REG, 6);//批量端點
    }
    else
    {
        CLRB(dev, IN_CSR2_REG, 5);//out

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

        SETB(dev, OUT_CSR2_REG, 5);//批量端點
        SETB(dev, OUT_CSR2_REG, 6);//關閉out dma中斷,先不用dma
    }

    SETB(dev, EP_INT_EN_REG, ep->num);//開中斷

    spin_unlock_irqrestore(&dev->lock, flags);

    return 0;
}

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

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

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

    local_irq_save(flags);

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

    //清除請求list和關閉ep
    s3c2440_dequeue_all(ep, -ESHUTDOWN);//關機後將無法傳輸端點

    CLRB(dev, EP_INT_REG, ep->num);//關對應ep中斷

    local_irq_restore(flags);

    return 0;
}

//動態分配請求
static struct usb_request *s3c2440_udc_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
{
    struct s3c2440_request *req;

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

    if (!_ep)
        return NULL;

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

    INIT_LIST_HEAD (&req->queue);

    return &req->req;
}

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

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

    if (!_ep || !_req)
        return;

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

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

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

    if (unlikely (!_ep || (!ep->desc && ep->num != 0))) //這個邏輯下面會看到很多(_ep爲空或[ep->desc爲空且不是0端點])
    {
        return -EINVAL;
    }

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

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

    if (unlikely(!_req || !_req->complete
            || !_req->buf || !list_empty(&req->queue))) //_req或_req->buf爲空、complete執行錯誤、req->queue不爲空
    {
        local_irq_restore(flags);

        return -EINVAL;
    } 

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

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

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

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

                break;

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

            default:
                local_irq_restore(flags);

                return -EL2HLT;
            }
        }
        else if ((ep->bEndpointAddress & USB_DIR_IN) != 0)
        {
        }
        else
        {
        }
    }

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

    local_irq_restore(flags);

    return 0;
}

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

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

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

    dev = ep->dev;

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

    local_irq_save (flags);

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

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

    local_irq_restore (flags);
    return retval;
}

#ifdef S3C2440_FIFO_STATUS
//fifo狀態,返回fifo中的字節數。
//在上層的調用usb_ep_fifo_statu()如果不用fifo或不支持這個操作返回錯誤-EOPNOTSUPP
//net2272就有寄存器EP_AVAIL記錄fifo中的字節數。
//s3c2440硬件不支持,沒實現,上層調用會得到-EOPNOTSUPP
static int s3c2440_udc_fifo_status(struct usb_ep *_ep)
{
    struct s3c2440_ep *ep;
    u16 retval = 0;

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

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

    //retval = 讀寄存器

    return retval;
}
#endif

#ifdef S3C2440_FIFO_FLUSH
//沖掉fifo的不明確數據,這個決不用除非端點不能用於任何協議傳輸,這是上層調用的事
static void s3c2440_udc_fifo_flush(struct usb_ep *_ep)
{
    struct s3c2440_ep *ep;

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

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

    //寄存器操作
}
#endif

/*
上層調用usb_ep_set_wedge
停止一個端點並忽略CLEAR_FEATURE請求。如果Gadget驅動清除停止狀態,它將自動Unwedge端點
一般用一個位wedge表示
如果沒有實現set_wedge方法。就用set_halt(ep, 1);代替
我們看個例子(在file_storage.c中)
Bulk-only
當出現無效的CBW時
Bulk-only Spec說我們必須停止IN 端點。還說必須保持這個狀態知道下一次的reset,但是沒有辦法
告訴控制器忽略CLEAR_FEATURE請求。所以我們用一個位來記錄,搞定!
下面是參考net2272的代碼,
value=1:set_halt
= 0:clear_halt
*/
static int s3c2440_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
{
    struct s3c2440_ep *ep;
    unsigned long flags;
    int ret = 0;

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

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

    if (!list_empty(&ep->queue))
        ret = -EAGAIN;
#ifdef S3C2440_FIFO_STATUS
    else if ((ep->bEndpointAddress & USB_DIR_IN) && value && s3c2440_udc_fifo_status(_ep) != 0)//fifo_status是上面實現的
        ret = -EAGAIN;
#endif
    else {
        /* set/clear */
        if (value) {
            if (ep->num == 0)
            {
                 ep->dev->ep0state = EP0_STALL;
                 ep->stopped = 1;
                //net2272的端點0在setup時自動復位,沒有什麼操作。s3c2440就不是了
                //ep->dev->protocol_stall = 1;
                //ep0 set_halt
            }
            else
                //epx(x != 0) set_halt
            if (wedged)//維護wedged
                ep->wedged = 1;
        } else {
            //ep clear_halt
            ep->wedged = 0;
        }
    }
    spin_unlock_irqrestore(&ep->dev->lock, flags);

    return ret;
}
//_ep 不能是同步端點,同步端點不支持錯誤重發機制。在上面判斷
static int s3c2440_udc_set_halt(struct usb_ep *_ep, int value)
{
    printk(  "%s\n", __func__);

    return s3c2440_set_halt_and_wedge(_ep, value, 0);
}

#ifdef S3C2440_SETWEDHE

static int s3c2440_udc_set_wedge(struct usb_ep *_ep)
{

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

    if (!_ep || _ep->name == ep0name)//一般都是端點0請求復位
        return -EINVAL;

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

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

    .alloc_request    = s3c2440_udc_alloc_request,
    .free_request    = s3c2440_udc_free_request,

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

#ifdef S3C2440_SETWEDHE
    .set_wedge  = s3c2440_udc_set_wedge,
#endif

#ifdef S3C2440_FIFO_STATUS
    .fifo_status = s3c2440_udc_fifo_status,
#endif

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

/***************************************************************/
//USB 設備的常用操作包括:設備連接、設備移除、設備配置、地址分配、數據傳輸、 
//設備掛起、設備喚醒等。
/**************************usb_gadget_ops***********************/
//硬件操作函數

//獲取幀號,當主機發送USB 數據包時,每個幀的開始(SOF)包包含一個幀號。
//這個幀號一般自動加載到對應寄存器,此函數主要就是讀這些寄存器
//如果設備不支持返回負
static int s3c2440_udc_get_frame(struct usb_gadget *usb_gdt_p)
{
    printk(  "%s\n", __func__);

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

    spin_lock_irqsave(&dev->lock, flags);

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

    spin_unlock_irqrestore(&dev->lock, flags);

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

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

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

    spin_lock_irqsave(&dev->lock, flags);

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

    spin_unlock_irqrestore(&dev->lock, flags);

    return 0;
}
#endif

#ifdef S3C2440_SELFPOWERED
//設置自供電標誌(selfpowered feature),一般就用一個變量位或一個位記錄一下。USB_RECIP_DEVICE時返回狀態
static int s3c2440_udc_set_selfpowered (struct usb_gadget *usb_gdt_p, int is_selfpowered)
{
    struct s3c2440_udc *dev = to_s3c2440_udc(usb_gdt_p);

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

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

    return 0;
}
#endif

#ifdef S3C2440_VBUS_SESSION
//vbus在硬件上就是usb的電源腳,這個函數就是來控制它。一般通過一個gpio拉高拉底
//這個vbus會話,實際的我看了s3c2410和at91的處理,就是讓usb的D+線與一個gpio口連接
//通過置1置0來控制usb
static int s3c2440_udc_vbus_session (struct usb_gadget *usb_gdt_p, int is_active)
{
    struct s3c2440_udc *dev = to_s3c2440_udc(usb_gdt_p);
    unsigned long flags;

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

    spin_lock_irqsave(&dev->lock, flags);

    //寄存器操作

    spin_unlock_irqrestore(&dev->lock, flags);

    return 0;
}
#endif

#ifdef S3C2440_VBBUS_DRAW
//強制vbus電源控制器行爲,在SET_CONFIGRATION時,設置vbus的電流量
//vbus應該是表示總線電壓,在硬件上是一個腳
//主要是對usb電流的設置,看一下gta02平臺,這個函數會操作pcf50633(一種移動設備的電源管理芯片)
static int s3c2440_udc_vbus_draw (struct usb_gadget *usb_gdt_p, unsigned mA)
{
    return 0;
}
#endif

#ifdef S3C2440X_PULLUP
//這個和上面的vbus_session區別是
//vbus_session是控制vbus的連接
//pullup是控制usb模塊的連接
//在udc-core.c中newstyle的驅動probe函數時才調用它,所以你要實現udc_start和udc_stop,
//當然除了註冊,也可以通過sysfs調用它。和newstyle無關。
//composite.c也有一些調用
//這個就是根據is_on來connect或disconnect usb
//net2272就是由USBCTL0的第三位控制的,s3c2440還是通過gpio和vbus_session沒
//區別
static int s3c2440_udc_pullup (struct usb_gadget *usb_gdt_p, int is_on)
{
    struct s3c2440_udc *dev = to_s3c2440_udc(usb_gdt_p);
    unsigned long flags;

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

    spin_lock_irqsave(&dev->lock, flags);

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

    spin_unlock_irqrestore(&dev->lock, flags);

    return 0;
}
#endif

//不好意思,我看了linux-3.2.36的/gadget的目錄沒發現有實現這個的硬件
static int s3c2440_udc_ioctl(struct usb_gadget *usb_gdt_p, unsigned code, unsigned long param)
{
    return 0;
}

//這個也沒看驅動實現它,從名字就是獲取配置參數,就簡單看看struct usb_dcd_config_params
/*
struct usb_dcd_config_params {
        __u8  bU1devExitLat;    // U1 Device exit Latency  u1設備等待時間
#define USB_DEFAULT_U1_DEV_EXIT_LAT     0x01    // Less then 1 microsec 至少1微秒
        __le16 bU2DevExitLat;   // U2 Device exit Latency 
#define USB_DEFAULT_U2_DEV_EXIT_LAT     0x1F4   // Less then 500 microsec 
};
對應struct usb_ss_cap_descriptor 中的成員
每一個I/O請求包延遲時間限制
*/
static void s3c2440_udc_get_config_params(struct usb_dcd_config_params *usb_dc_cfg_pm)
{
}

//在udc-core.c中start和udc_start的解釋一樣,在bind()之前調用,只要實現一個就行了
//我知道start主要有bind回調
//udc_start主要是設備執行了non-control請求後,要重新連接,net2272和r8a66597實現的就是它
#ifdef S3C2440_NEWSTYLE
static int s3c2440_udc_start(struct usb_gadget *usb_gdt_p, struct usb_gadget_driver *driver);
static int s3c2440_udc_stop(struct usb_gadget *usb_gdt_p, struct usb_gadget_driver *driver);
#else
//s3c2410 s3c2440 實現它
static int s3c2440_start(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *));
static int s3c2440_stop(struct usb_gadget_driver *driver);
#endif

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

#ifdef S3C2440_SELFPOWERED
    .set_selfpowered = s3c2440_udc_set_selfpowered,
#endif

#ifdef S3C2440_VBUS_SESSION
    .vbus_session    = s3c2440_udc_vbus_session,
#endif

#ifdef S3C2440_VBBUS_DRAW
    .vbus_draw        = s3c2440_udc_vbus_draw,
#endif

#ifdef S3C2440X_PULLUP
    .pullup            = s3c2440_udc_pullup,
#endif

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

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


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

static struct s3c2440_udc udc_info = {
    .gadget = {
        .ops        = &s3c2440_ops,
        .ep0        = &udc_info.ep[0].ep,
        .name        = gadget_name,
        .dev = {
            .init_name    = "gadget",
        },
/*
根據自己的硬件選擇
unsigned is_dualspeed:1;
unsigned is_otg:1;
unsigned is_a_peripheral:1;
unsigned b_hnp_enable:1; //hnp:主機協商協議 otg特有的
unsigned a_hnp_support:1;
unsigned a_alt_hnp_support:1;
*/
    },

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    s3c2440_udc_enable(dev);

    return 0;
}

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

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

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

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

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

    return 0;
}

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

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

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

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

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

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

    s3c2440_udc_enable(dev);

    return 0;

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

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

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

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

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

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

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

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

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

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

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

    clk_enable(udc->s3c2440_clk_upll);

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

    clk_enable(udc->s3c2440_clk_udc);

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

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

    spin_lock_init (&udc->lock);

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

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

        goto err_clk_udc;
    }

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

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

    platform_set_drvdata(pdev, udc);

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

#ifdef S3C2440_USE_IRQ

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

    udc->irq_num = resirq->start;

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

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

#endif


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

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

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

    return 0;

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

    return retval;
}

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

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

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

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

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

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

    platform_set_drvdata(pdev, NULL);

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

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

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

    return 0;
}

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

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

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

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


static int __init udc_init(void)
{
    int retval;

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

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

    return 0;

err:
    debugfs_remove(s3c2440_udc_debugfs_root);
    return retval;
}

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

module_init(udc_init);
module_exit(udc_exit);

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

下期完善它,並考慮使用DMA。下期見!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章