2014년 5월 12일 월요일

Pascal USB Bluk Stack for Stellaris / Cortex-M3

USB 2.0 Stack을 Pascal로 구현해 보았습니다. 예전에 열정을 갖고 작성했었는데, 초보자분들께 도움이 되실까 해서, 공개합니다.
USB 2.0 Stack for Bulk Transfer written pascal. Two years ago, I wrote the USB Driver for Stellaris. Stack is now open source. :)


 
 
//------------------------------------------------------------------------------
//
//  USB Bulk Library for LM3S9B95,LMS9B96
//
//  #1. Environment
//  -------------------------------------------------------------------------
//      Eval Board : MikroMedia for Stellaris (LM3S9B95)
//      Compiler   : MikroPascal PRO for ARM v.2.0.0
//
//  #2. Author
//  -------------------------------------------------------------------------
//      simon,choi / south korea (최원식옹의 스텔라리스 USB 라이브러리)
//      Blog       :
http://blog.naver.com/simonsayz
//      E-Mail     :  simonsayz@naver.com
//
//  #3. History
//  ---------------------------------------------------------------------------
//      2012.03.01 : Start
//      2012.03.02 : Convert USBLib in StellarisWare
//      2012.03.05 : RX FIFO Read
//      2012.03.10 : PLL Setting Bug Fixed
//      2012.03.11 : Rewrite Lib
//      2012.03.12 : Enumeration (EP0)
//      2012.03.14 : Data Xfer   (EP1)
//
//  #4. Maximum Speed Test (Full Speed : 12Mhz)
//  ---------------------------------------------------------------------------
//      19 x 64 x 1000     1216000 [Bytes/s]
//      Example.  /wo Rcv  1066667 [Bytes/s]  88% [64000KB Block]
//                /w  Rcv   565771 [Bytes/s]  47%
//                /w  Rcv  1064007 [Bytes/s]
//                /w  Rcv  1066667 [Bytes/s]
//
//                    Snd   941592 [Bytes/s]
//
//  #5. Enumeration List
//      Env. C:\StellarisWare\boards\dk-lm3s9b96\usb_dev_bulk & XP
//  ---------------------------------------------------------------------------
//                                    Ty Rq Value Index Length
//      PC->Dev (GetDesc, Devic    )  80 06 00 01 00 00 40 00
//      Dev->PC (Answer            )  12 01 10 01 FF 00 00 40 BE 1C 03 00 00 01 01 02 03 01
//      PC->Dev (Set Addr          )  00 05 01 00 00 00 00 00    // ZL Ack by Client
//      PC->Dev (GetDesc, Device   )  80 06 00 01 00 00 12 00    // Dev Desc (Ver,PktSize...)
//      Dev->PC (Answser           )  12 01 10 01 FF 00 00 40 BE 1C 03 00 00 01 01 02 03 01
//      PC->Dev (GetDesc, Config   )  80 06 00 02 00 00 09 00
//      Dev->PC (Config Answer     )  09 02 20 00 01 01 05 C0 FA // Cfg.Desc
//      PC->Dev (GetDesc, String   )  80 06 00 03 00 00 FF 00
//      Dev->PC (Lang: EN          )  04 03 09 04                // Lang Desc.
//      PC->Dev (GetDesc,Str Inx3  )  80 06 03 03 09 04 FF 00    // "12345678"
//      Dev->PC (        Str Inx3  )  12 03 31 00 32 00 33 00 34 00 35 00 36 00 37 00 38 00
//      PC->Dev (GetDesc. Cfg Full )  80 06 00 02 00 00 FF 00    // Cfg. All
//      Dev->PC (Config Answer     )  09 02 20 00 01 01 05 C0 FA // Cfg Desc(Self Pwr,500mA)
//                                    09 04 00 00 02 FF 00 00 04 // I/F Desc (Ep#:2,IF:4)
//                                          07 05 81 02 40 00 00 // Ep  Desc (Ep,81,I,Bulk,64,0)
//                                          07 05 01 02 40 00 00 // Ep  Desc (Ep,01,O,Bulk,64,0)
//      PC->Dev (GetDesc,String    )  80 06 00 03 00 00 FF 00
//      Dev->PC (Lang: EN          )  04 03 09 04
//      PC->Dev (GetDesc,Str Inx2  )  80 06 02 03 09 04 FF 00    // "Genera..."
//      Dev->PC (        Str Inx2  )  28 03 47 00 65 00 6E 00 65 00 72 00 69 00
//      PC->Dev (GetDesc,String    )  80 06 00 03 00 00 FF 00
//      Dev->PC (Lang: EN          )  04 03 09 04
//      PC->Dev (GetDesc,Str Inx2  )  80 06 02 03 09 04 FF 00   // "General..."
//      Dev->PC (        Str Inx2  )  28 03 47 00 65 00 6E 00 65 00 72 00 69 00
//      PC->Dev (GetDesc, Device   )  80 06 00 01 00 00 12 00   //
//      Dev->PC (         Device   )  12 01 10 01 FF 00 00 40 BE 1C 03 00 00 01
//      PC->Dev (GetDesc, Config   )  80 06 00 02 00 00 09 00
//      Dev->PC (         Config   )  09 02 20 00 01 01 05 C0 FA
//      PC->Dev (GetDesc,          )  80 06 00 02 00 00 20 00
//                                    09 02 20 00 01 01 05 C0 FA
//      Dev->PC (Config Answer     )  09 04 00 00 02 FF 00 00 04
//                                          07 05 81 02 40 00 00
//                                          07 05 01 00 40 00 00
//      PC->Dev (Get.Status        )  80 00 00 00 00 00 02 00
//      Dev->PC (Self Power OK     )  01 00
//      PC->Dev (SetConfig         )  00 09 01 00 00 00 00 00 // All Enum Done.
//
//
//  bmRequestType               bRequest
//  ---------------------------------------------------
//  Std    Std       Std
//  Device Interface EndPoint
//  ---------------------------------------------------
//  0x80   0x81      0x82       0 #USBDGetStatus
//  0x00   0x01      0x02       1  USBDClearFeature,
//                              -
//  0x00   0x01      0x02       3  USBDSetFeature,
//                              -
//  0x00                        5 #USBDSetAddress,
//  0x80                        6 #USBDGetDescriptor,
//  0x00                        7  USBDSetDescriptor,
//  0x80                        8  USBDGetConfiguration,
//  0x00                        9 #USBDSetConfiguration,
//         0x81                 A  USBDGetInterface,
//         0x01                 B  USBDSetInterface,
//                   0x82       C  USBDSyncFrame
//
//  bmRequest
//  0 00 0:0000
//  x            : 0 : Host To Device
//                 1 : Device to Host
//    xx         : 00 : Standard
//                 01 : Class
//                 10 : Vendor
//                 11 : Reserved
//  1 01 0:0000
//
//
//
//  Command List
//  ---------------------------------------------------------------------------
//  Cmd_SetMode(    Mode,Address : DWord)    ReadMode    Address
//                                           WriteMode   Addesss
//                                           DialogMode  Address
//                                           Execute -
//              PC->Dev : SetUpPkt : $60 $D8 $0000 $0000 $0040
//              PC->Dev : Data[64] ( Mode4, Address4 )
//
//  Cmd_GetMode(Var Mode,Address : DWord);
//              PC->Dev : SetupPkt : $E0 $D8 $0000 $0000 $0040
//              Dev->PC : Data[64]
//
//  Pin Layout
//      USBDM       : USB0DM       p70
//      USBDP       : USB0DP       p71
//      USB-DET     : USB0VBUS PB1 p67
//      USB-ID      : USB0ID   PB0 p66
//
unit Drv_USB;
Uses
 Drv_PasBase,Drv_LM3S9B95,Drv_TFT,Drv_SD;
Const
 //
 _cUSB_Polling   = $1234;
 _cUSB_Interrupt = $2345;
 // TUSBStatus
 _tusNone        = $0000;
 _tusReset       = $0001;
 _tusSuspend     = $0002;
 _tusResume      = $0003;
 _tusDisconnect  = $0004;
 _tusSOF         = $0005;
 _tusReady       = $0006;
 // TUSBPktPhase
 _pSetup         = $0001;
 _pData          = $0002;
 // TUSBModeState
 _tmsNone        = $00;
 _tmsXferStart   = $01;
 _tmsStop        = $02;
 _tmsPictShow    = $03;
 _tmsMovShow     = $04;
 _tmsSDTest      = $05;
 //
 _CmdReqGet      = $80 or $60; // bmRequestType  Get+UserFunc
 _CmdReqSet      = $00 or $60; // bmRequestType  Set+UserFunc
 _CmdReqFunc     = $D8; //        bRequest
 _DirIn          = $01; // PC <- dev="" nbsp="" span="">
 _DirOut         = $02; // PC  -> Dev
 _DirInOut       = $03; // PC <-> Dev
                       //             RT Req Val  Inx  Len   Data
 _CmdNone        = $00;
 _CmdSetStatus   = $01; // PC  -> Dev  60 D8 0001 0000 0040 : dir addr cnt
 _CmdGetStatus   = $02; // PC <- 0000="" 0002="" :="" addr="" cnt="" d8="" dev="" dir="" e0="" nbsp="" span="">
 _CmdSetAction   = $03; // PC  -> Dev  80 D8 0003 0000 0040 : modeState
//
Type
 TUSBOperation  = DWord;
 Pointer        = ^Byte;
 TUSBBufDW      = Array[16] of DWord;
 pUSBBufDW      = ^TUSBBufDW;
 TUSBBuf        = Array[64] of Char;
 TUSBStatus     = DWord;
 TUSBPktPhase   = DWord;
 TUSBState      = DWord;
 TUSBModeState  = DWord;
 TUSB           = Record
                   Operation  : TUSBOperation;
                   Ready      : Boolean;
                   Status     : TUSBStatus;
                   PktPhase   : TUSBPktPhase;
                   CtlReqType : DWord;
                   CtlReq     : DWord;
                   CtlValue   : DWord;
                   CtlLength  : DWord;
                   ModeDir    : DWord;         // Internal Operation
                   ModeAddr   : DWord;
                   ModeCnt    : DWord;
                   ModeState  : TUSBModeState;
                   Addr       : Dword;
                   AddrSet    : Boolean;
                   BufR       : TUSBBuf;
                   BufW       : TUSBBuf;
                  End;
             
 Var
  _gUSB : TUSB;
              
//
Procedure USB_Init(Operation : TUSBOperation);
Procedure USB_Handler;
//
Function  USB_PutSD (Var USB : TUSB) : Boolean;
Function  USB_GetSD (Var USB : TUSB) : Boolean;
Implementation
Const
  //
  cDescDev = 1;   // Device    Descriptor
  cDescCfg = 2;   // Config    Descriptor
  cDescStr = 3;   // String    Descriptor
  cDescIF  = 4;   // Interface Descriptor
  cDescEP  = 5;   // EndPoint  Descriptor
  //
  cEpBulk  = 1;   // Ref. EndPoint Descriptor [In,Out];
  // Device Description -------------------------------------------------------
  cDevDesc : Array[18] of Byte =
              ($12,      // bLength             [Always]
               $01,      // bDescriptorType     [Device Description:$01]
               $10,$01,  // bcdUSB              [USB Version] // $10,$01  $00,$02
               $FF,      // DeviceClass         [Vendor Specific]
               $00,      // bDeviceSubClass     [User Defined]
               $00,      // bDeviceProtocol     [User Defined]
                64,      // bMaxPacketSize      [8,16,32,64]
               $BE,$1C,  // idVendor            [*Stellaris]
               $03,$00,  // idProduct           [*User Define]
               $00,$01,  // bcdDevice           [*Prod Version]
               $01,      // iManufacturer       [Manufacturer Str Inx]
               $02,      // iProduct            [Product Str Inx]
               $03,      // iSerialNumber       [Serial Number Inx]
               $01);     // bNumConfigurations  [# of Config]
  // Config Description -------------------------------------------------------
  cCfgDesc : Array[32] of Byte = (
               // Configuration Descriptor ------------------------------------
               $09,           // bLength             [Always $09]
               $02,           // bDescriptorType     [Configuration Description:$02]
               $20,$00,       // wTotalLength        [Total Size = Cfg + Sub ...]
               $01,           // bNumInterfaces      [Interface #]
               $01,           // bConfigurationValue [1]
               $05,           // iConfiguration      [Config Str Inx]
               $C0,           // bmAttributes        [11.. = Reserved, Self Powered]
               $FA,           // bMaxPower           [$FA x 2mA = 500 mA ]
               // Inteface Descriptor -----------------------------------------
               $09,           // bLength             [Always $09]
               $04,           // bDescriptorType     [Interface Description:$04]
               $00,           // bInterfaceNumber    [Interface ID]
               $00,           // bAlternateSetting   [Alternated Service #]
               $02,           // bNumEndpoint        [2 EP Point(1,81)]
               $FF,           // bInterfaceClass     [*User Define]
               $00,           // bInterfaceSubclass  [Subclass code]
               $00,           // bInterfaceProtocol  [Protocol code]
               $04,           // iInterface          [Interface Str Inx]
               // EndPoint Descriptor (IN) ------------------------------------
               $07,           // bLength             [Always $07]
               $05,           // bDescriptorType     [EndPoint : $05]
               $80 or cEpBulk,// bEndpointAddress    [Addr : 81] <------------------ span="">
               $02,           // bmAttributes        [Bulk]
               $40,$00,       // wMaxPacketSize      [Pkt 64bytes, Ref. Device Desc]
               $00,           // bInterval           [Svc Interval , NAK rate]
               // EndPoint Descriptor (OUT) -----------------------------------
               $07,           // bLength             [Always $07]
               $05,           // bDescriptorType     [EndPoint : $05]
               $00 or cEpBulk,// bEndpointAddress    [Addr : 01] <------------------ span="">
               $02,           // bmAttributes        [Bulk]
               $40,$00,       // wMaxPacketSize      [Pkt 64bytes, Ref. Device Desc]
               $00);          // bInterval           [Svc Interval , NAK rate]
  // String Description -------------------------------------------------------
  cStrLang   : Array[2] of byte = ($09,$04); // $0409 US
  cStrDescs  : Array[5] of String[64] =
               ('Texas Instruments',         // Str Inx 1, Manu   Dev Desc
                'Generic Bulk Device',       // Str Inx 2, Prod   Dev Desc
                '12345678',                  // Str Inx 3, Serial Dev Desc
                'Bulk Data Interface',       // Str Inx 4, I/F    I/F Desc
                'Bulk Data Configuration');  // Str Inx 5, Cfg    Cfg Desc
//------------------------------------------------------------------------------
//
// H/W Driver Function
//
//------------------------------------------------------------------------------
Const
  _EP0_MAX_PACKET_SIZE           = 64;
  _USB_DEV_EP0_IN_PKTPEND        = $00000002; // Transmit data packet pending
  _USB_DEV_EP0_OUT_PKTRDY        = $00000001; // Receive data packet ready
  _USB_DEV_EP0_SENT_STALL        = $00000004; // Stall was sent on this endpoint
  _USB_DEV_EP0_SETUP_END         = $00000010; // Control transaction ended before
  _USB_DEV_RX_DATA_ERROR         = $00080000; // CRC error on the data
  _USB_DEV_RX_FIFO_FULL          = $00020000; // RX FIFO full
  _USB_DEV_RX_OVERRUN            = $00040000; // OUT packet was not loaded due to
  _USB_DEV_RX_PKT_RDY            = $00010000; // Data packet ready
  _USB_DEV_RX_SENT_STALL         = $00400000; // Stall was sent on this endpoint
  _USB_DEV_TX_SENT_STALL         = $00000020; // Stall was sent on this endpoint
  _USB_DEV_TX_UNDERRUN           = $00000004; // IN received with no data ready
  _USB_EP_0                      = $00000000; // Endpoint 0
  _USB_EP_1                      = $00000010; // Endpoint 1
  _USB_EP_AUTO_CLEAR             = $00000004; // Auto clear feature enabled
  _USB_EP_AUTO_SET               = $00000001; // Auto set feature enabled
  _USB_EP_DEV_IN                 = $00002000; // Device IN endpoint
  _USB_EP_DEV_OUT                = $00000000; // Device OUT endpoint
  _USB_EP_DMA_MODE_0             = $00000008; // Enable DMA access using mode 0
  _USB_EP_DMA_MODE_1             = $00000010; // Enable DMA access using mode 1
  _USB_EP_HOST_OUT               = $00002000; // Host OUT endpoint
  _USB_EP_MODE_BULK              = $00000100; // Bulk endpoint
  _USB_EP_MODE_INT               = $00000200; // Interrupt endpoint
  _USB_EP_MODE_ISOC              = $00000000; // Isochronous endpoint
  _USB_EP_MODE_MASK              = $00000300; // Mode Mask
  _USB_FIFO_SZ_64                = $00000003; // 64 byte FIFO
  _USB_INTCTRL_ALL               = $000003FF; // All control interrupt sources
  _USB_INTCTRL_DISCONNECT        = $00000020; // Disconnect Detected
  _USB_INTCTRL_MODE_DETECT       = $00000200; // Mode value valid
  _USB_INTCTRL_POWER_FAULT       = $00000100; // Power Fault detected
  _USB_INTCTRL_RESET             = $00000004; // Reset signaled
  _USB_INTCTRL_RESUME            = $00000002; // Resume detected
  _USB_INTCTRL_SOF               = $00000008; // Start of Frame Detected
  _USB_INTCTRL_STATUS            = $000000FF; // Status Interrupts
  _USB_INTCTRL_SUSPEND           = $00000001; // Suspend detected
  _USB_INTEP_0                   = $00000001; // Endpoint 0 Interrupt
  _USB_INTEP_ALL                 = $FFFFFFFF; // Host IN Interrupts
  _USB_INTEP_DEV_IN              = $0000FFFE; // Device IN Interrupts
  _USB_INTEP_DEV_OUT             = $FFFE0000; // Device OUT Interrupts
  _USB_INTEP_HOST_IN             = $FFFE0000; // Host IN Interrupts
  _USB_INTEP_HOST_OUT            = $0000FFFE; // Host OUT Interrupts
  _USB_INTEP_RX_SHIFT            = 16; // usb.c
  _USB_O_FADDR                   = $00000000; // USB Device Functional Address
  _USB_RX_EPSTATUS_SHIFT         = 16;
  _USB_STATE_IDLE                =  0;        // usbdevicepriv.h   TEP0State
  _USB_STATE_RX                  =  3;
  _USB_STATE_STALL               =  5;
  _USB_STATE_STATUS              =  4;
  _USB_STATE_TX                  =  1;
  _USB_STATE_TX_CONFIG           =  2;
  _USB_TRANS_IN                  = $00000102; // Normal IN transaction
  _USB_TRANS_IN_LAST             = $0000010a; // Final IN transaction (for endpoint 0 in device mode)
  _USB_TXCSRH1_DMAEN             = $00000010; // DMA Request Enable
  _USB_TXCSRH1_DMAMOD            = $00000004; // DMA Request Mode
  _USB_RTYPE_TYPE_M              = $60;
  // Direct Access [Fast Act]
  _USB0_BASE_TXIS                = $40050002;
  _USB0_BASE_FIFO0               = $40050020;  // USB FIFO Endpoint 0
  _USB0_BASE_CSRL0               = $40050102;  // USB Control and Status Endpoint 0 Low
  _USB0_BASE_COUNT0              = $40050108;  // USB Receive Byte Count Endpoint
  _USB0_BASE_TXCSRL1             = $40050112;
  _USB0_BASE_RXCSRL1             = $40050116;
  //
  _urGetStat                     =   0;
  _urSetAddr                     =   5;
  _urGetDesc                     =   6;
  _urSetConf                     =   9;
  //
  _cStrDesc                      =   3;
  _udHost2Dev                    = $00;
  _udDev2Host                    = $80;
 
Type
  TUSBRequest        = Record // usblib.h
                        bmRequestType : Byte; // 80
                        bRequest      : Byte; // 00
                        wValue        : Word; // 80
                        wIndex        : Word; // 80
                        wLength       : Word; // 80
                       End;
  pUSBRequest        = ^TUSBRequest;
  TStrDesc           = Record
                        Len           : Byte;
                        StrDesc       : Byte;
                        Dat           : Array[64] of Byte;
                       End;
  pStrDesc           = ^TStrDesc;
Var
 _lStrDesc : TStrDesc;
//-----------------------------------------------------------------------------
//
//  Original Code : C:\StellarisWare\driverlib\usb.c
//
//   Function  USB_EP_TO_Index(x : DWord) : DWord;//
//   Function  EP_OFFSET(Endpoint : DWord) : DWord;
//   Procedure USBIndexWrite(ulBase, ulEndpoint,ulIndexedReg,ulValue,ulSize : DWord);
//   Procedure USBIntEnableControl(ulBase,ulFlags : DWord);
//   Function  USBIntStatusControl(ulBase : DWord) : DWord;
//   Procedure USBIntEnableEndpoint(ulBase,ulFlags : DWord);
//   Function  USBIntStatusEndpoint(ulBase : DWord) : DWord;
//   Function  USBEndpointStatus(ulBase, ulEndpoint : DWord) : DWord;
//   Procedure USBDevEndpointStatusClear(ulBase,ulEndpoint,ulFlags : DWord);
//   Procedure USBDevConnect( ulBase : DWord);
//   Procedure USBDevDisconnect(ulBase : DWord);
//   Procedure USBDevAddrSet(ulBase, ulAddress : DWord);
//   Procedure USBDevEndpointConfigSet(ulBase,ulEndpoint,ulMaxPacketSize,ulFlags : DWord);
//   Procedure USBFIFOConfigSet(ulBase,ulEndpoint,ulFIFOAddress,ulFIFOSize,ulFlags : DWord);
//   Function  USBEndpointDataAvail(ulBase,ulEndpoint : DWord) : DWord;
//   Function  USBEndpointDataGet(ulBase, ulEndpoint : DWord; pucData : Pointer; Var pulSize : DWord) : LongInt;
//   Procedure USBDevEndpointDataAck(ulBase, ulEndpoint : DWord; bIsLastPacket : Boolean);
//   Function  USBEndpointDataPut(ulBase, ulEndpoint : DWord; pucData  : Pointer; ulSize : DWord) : LongInt;
//   Function  USBEndpointDataSend(ulBase, ulEndpoint,ulTransType : DWord) : LongInt;
//   Procedure USBOTGMode(ulBase : DWord);
//
//-----------------------------------------------------------------------------
// Utility 함수
// usb.c
// Function EP_OFFSET(Endpoint : DWord) : DWord;
//
Procedure USBIndexWrite(ulBase, ulEndpoint,ulIndexedReg,ulValue,ulSize : DWord);
 Var
  ulIndex : DWord;
 Begin
  // Save the old index in case it was in use.
  HWRegBR(ulBase + _USB_O_EPIDX,ulIndex);
  // Set the index.
  HWRegBW(ulBase + _USB_O_EPIDX,ulEndpoint);
  // Determine the size of the register value.
  Case (ulSize = 1) of
   True  : HWRegBW(ulBase + ulIndexedReg,ulValue);
   False : HWRegHW(ulBase + ulIndexedReg,ulValue);
  End;
  // Restore the old index in case it was in use.
  HWRegBW(ulBase + _USB_O_EPIDX, ulIndex);
 End;
// usb.c
Procedure USBIntEnableControl(ulBase,ulFlags : DWord);
 Var
  ulVal : DWord;
 begin
  If(ulFlags and _USB_INTCTRL_STATUS) then
   begin
    HWRegBR(ulBase + _USB_O_IE,ulVal);
    HWRegBW(ulBase + _USB_O_IE,ulVal or ulFlags);
   end;
  // Enable the power fault interrupt.
  If(ulFlags and _USB_INTCTRL_POWER_FAULT) then
   HWRegW(ulBase + _USB_O_EPCIM,USB_EPCIM_PF);
  // Enable the ID pin detect interrupt.
  If(ulFlags and _USB_INTCTRL_MODE_DETECT) then
   HWRegW(_USB0_BASE + _USB_O_IDVIM,USB_IDVIM_ID);
 end;
// usb.c
Function USBIntStatusControl(ulBase : DWord) : DWord;
 Var
  ulStatus      : DWord;
  _USB0_IS      : Byte ; absolute 0x4005000A; volatile; sfr;
  _USB0_EPCISC  : Dword; absolute 0x4005040C; volatile; sfr;
  _USB0_IDVISC  : Dword; absolute 0x4005044C; volatile; sfr;
 begin
  ulStatus := _USB0_IS;
  If(_USB0_EPCISC and _USB_EPCISC_PF) then
   begin
    ulStatus := ulStatus or _USB_INTCTRL_POWER_FAULT;
    _USB0_EPCISC := _USB0_EPCISC or _USB_EPCISC_PF; // Clear power fault int
   end;
  If(_USB0_IDVISC and _USB_IDVRIS_ID) then
   begin
    ulStatus := ulStatus or _USB_INTCTRL_MODE_DETECT;
    _USB0_IDVISC := _USB0_IDVISC or _USB_IDVRIS_ID; // Clear id detection int
   end;
  Result := ulStatus;
 end;
// usb.
Procedure USBIntEnableEndpoint(ulBase,ulFlags : DWord);
 begin
  // Enable any transmit endpoint interrupts.
  HWRegHW(ulBase + _USB_O_TXIE, HWRegHR(ulBase + _USB_O_TXIE) or
          ulFlags and ( _USB_INTEP_HOST_OUT or _USB_INTEP_DEV_IN or _USB_INTEP_0));
  // Enable any receive endpoint interrupts.
  HWRegHW(ulBase + _USB_O_RXIE, HWRegHR(ulBase + _USB_O_RXIE) or
        ((ulFlags and (_USB_INTEP_HOST_IN or _USB_INTEP_DEV_OUT)) shr
         _USB_INTEP_RX_SHIFT));
 end;
 
// usb.c , Pascal Compiler Bug -> hand coding SIMON
Function USBIntStatusEndpoint(ulBase : DWord) : DWord;
 Var
  TXIS : ^DWord;
 begin
  TXIS   := _USB0_BASE_TXIS;
  Result := TXIS^;  // TXIS[16] + RXIS[16]
 end;
// usb.c/ Device Mode Result
Function USBEndpointStatus(ulBase, ulEndpoint : DWord) : DWord;
 Var
  TXCSRL : ^DWord;
  RXCSRL : ^DWord;
 begin
  //
  TXCSRL := _USB0_BASE_TXCSRL1 + (ulEndPoint-$10);
  RXCSRL := _USB0_BASE_RXCSRL1 + (ulEndPoint-$10);
  //
  Result := (TXCSRL^ and $0000FFFF) or
            (RXCSRL^ shl 16)
 end;
 
// usb.c
Procedure USBDevEndpointStatusClear(ulBase,ulEndpoint,ulFlags : DWord);
 Var
  ulVal : DWord;
 begin
  // If this is endpoint 0, then the bits have different meaning and map
  // into the TX memory location.
  Case (ulEndpoint = _USB_EP_0) of
   True : begin // EP0
           HWRegBR( _USB0_Base_CSRL0, ulVal);
           // Set the Serviced RxPktRdy bit to clear the RxPktRdy.
           if(ulFlags and _USB_DEV_EP0_OUT_PKTRDY) then
            HWRegBW(_USB0_Base_CSRL0, ulVal or _USB_CSRL0_RXRDYC);
           // Set the serviced Setup End bit to clear the SetupEnd status.
           if(ulFlags and _USB_DEV_EP0_SETUP_END) then
            HWRegBW(_USB0_Base_CSRL0, ulVal or _USB_CSRL0_SETENDC);
           // Clear the Sent Stall status flag.
           if(ulFlags and _USB_DEV_EP0_SENT_STALL) then
            HWRegBW(_USB0_Base_CSRL0, ulVal and Not(_USB_DEV_EP0_SENT_STALL));
          end;
  False : begin // EP1 ~
           ulEndpoint := ulEndpoint - $10;
           HWRegBR(_USB0_Base_TXCSRL1 + ulEndpoint,ulVal);
           HWRegBW(_USB0_Base_TXCSRL1 + ulEndpoint,
                   ulVal and Not(ulFlags and $00000020)); // _USB_DEV_TX_SENT_STALL or _USB_DEV_TX_UNDERRUN
           HWRegBR(_USB0_Base_RXCSRL1 + ulEndpoint,ulVal);
           HWRegBW(_USB0_Base_RXCSRL1 + ulEndpoint,
                   ulVal and Not((ulFlags and $004C0000) shr 16));
          //  Not((ulFlags and (_USB_DEV_RX_SENT_STALL or _USB_DEV_RX_DATA_ERROR or
          //                      _USB_DEV_RX_OVERRUN)) shr _USB_RX_EPSTATUS_SHIFT));
          end;
  end;
 end;
// usb.c
Procedure USBDevConnect( ulBase : DWord);
 Var
  ulVal : DWord;
 begin
  // Enable connection to the USB bus.
  HWRegBR(ulBase + _USB_O_POWER,ulVal);
  HWRegBW(ulBase + _USB_O_POWER,ulVal or _USB_POWER_SOFTCONN);
 end;
// usb.c
Procedure USBDevDisconnect(ulBase : DWord);
 Var
  ulVal : DWord;
 begin
  // Disable connection to the USB bus.
  HWRegBR(ulBase + _USB_O_POWER,ulVal);
  HWRegBW(ulBase + _USB_O_POWER,ulVal and Not(_USB_POWER_SOFTCONN));
 end;
// usb.c
Procedure USBDevAddrSet(ulBase, ulAddress : DWord);
 begin
  // Set the function address in the correct location.
  HWRegBW(ulBase + _USB_O_FADDR, byte(ulAddress));
 end;
// usb.c
Procedure USBDevEndpointConfigSet(ulBase,ulEndpoint,ulMaxPacketSize,ulFlags : DWord);
 Var
  ulRegister : DWord;
 begin
  Case (ulFlags and _USB_EP_DEV_IN) of
   True : begin
           // Set the maximum packet size.
           HWRegHW(ulBase + (ulEndpoint- $10) + _USB_O_TXMAXP1, ulMaxPacketSize);
           ulRegister := 0;
           If (ulFlags and _USB_EP_AUTO_SET) then
            ulRegister := ulRegister or _USB_TXCSRH1_AUTOSET;
           // Configure the DMA mode.
           Case (ulFlags and _USB_EP_DMA_MODE_1) of
            True : ulRegister := ulRegister or _USB_TXCSRH1_DMAEN or _USB_TXCSRH1_DMAMOD;
            False: If(ulFlags and _USB_EP_DMA_MODE_0) then
                    ulRegister := ulRegister or USB_TXCSRH1_DMAEN;
           End;
          // Enable isochronous mode if requested.
          if((ulFlags and _USB_EP_MODE_MASK) = _USB_EP_MODE_ISOC) then
           ulRegister := ulRegister or USB_TXCSRH1_ISO;
          // Write the transmit control value.
          HWRegBW(ulBase + (ulEndpoint-$10) + _USB_O_TXCSRH1,ulRegister);
          // Reset the Data toggle to zero.
          HWRegBW(ulBase + (ulEndpoint-$10) + _USB_O_TXCSRL1,_USB_TXCSRL1_CLRDT);
         end;
   False:begin
          // Set the MaxPacketSize.
          HWRegHW(ulBase + (ulEndpoint-$10) + _USB_O_RXMAXP1,ulMaxPacketSize);
          ulRegister := 0;
          if(ulFlags and _USB_EP_AUTO_CLEAR) then
            ulRegister := _USB_RXCSRH1_AUTOCL;
          // Configure the DMA mode.
          Case (ulFlags and _USB_EP_DMA_MODE_1) of
           True : ulRegister := ulRegister or _USB_RXCSRH1_DMAEN or _USB_RXCSRH1_DMAMOD;
           False: If (ulFlags and _USB_EP_DMA_MODE_0) then
                   ulRegister := ulRegister or _USB_RXCSRH1_DMAEN;
          End;
          // Enable isochronous mode if requested.
          if((ulFlags and _USB_EP_MODE_MASK) = _USB_EP_MODE_ISOC) then
           ulRegister := ulRegister or _USB_RXCSRH1_ISO;
          // Write the receive control value.
          HWRegBW(ulBase + (ulEndpoint-$10) + _USB_O_RXCSRH1,ulRegister);
          // Reset the Data toggle to zero.
          HWRegBW(ulBase + (ulEndpoint-$10) + _USB_O_RXCSRL1,_USB_RXCSRL1_CLRDT);
         end;
  end;
 end;
// usb.c
Procedure USBFIFOConfigSet(ulBase,ulEndpoint,ulFIFOAddress,ulFIFOSize,ulFlags : DWord);
 begin
  // See if the transmit or receive FIFO is being configured.
  Case (ulFlags and (_USB_EP_HOST_OUT or _USB_EP_DEV_IN)) of
   True : // Set the transmit FIFO location and size for this endpoint.
          begin
           USBIndexWrite(ulBase, ulEndpoint shr 4, _USB_O_TXFIFOSZ, ulFIFOSize, 1);
           USBIndexWrite(ulBase, ulEndpoint shr 4, _USB_O_TXFIFOADD,ulFIFOAddress shr 3, 2);
          end;
   False: // Set the receive FIFO location and size for this endpoint.
          begin
           USBIndexWrite(ulBase, ulEndpoint shr 4, _USB_O_RXFIFOSZ, ulFIFOSize, 1);
           USBIndexWrite(ulBase, ulEndpoint shr 4, _USB_O_RXFIFOADD,ulFIFOAddress shr 3, 2);
          end;
  end;
 end;
// usb.c
Function USBEndpointDataAvail(ulBase,ulEndpoint : DWord) : DWord;
 Var
  ulRegister : DWord;
  ulFIFO     : ^DWord;
 begin
  // Get the address of the receive status register to use, based on the endpoint.
  Case (ulEndpoint = _USB_EP_0) of
   True  : ulRegister := _USB0_BASE_CSRL0;
   False : ulRegister := _USB0_BASE_RXCSRL1 + (ulEndpoint-$10);
  End;
  // Is there a packet ready in the FIFO?
  ulFIFO := ulRegister;
  If (ulFIFO^ and _USB_CSRL0_RXRDY) = 0 then
   begin
    Result := 0;
    Exit;
   end;
  // Return the byte count in the FIFO.
  ulFIFO := _USB0_BASE_COUNT0 + ulEndpoint;
  Result := ulFIFO^;
 end;
//
Procedure USBDevEndpointDataAck(ulBase, ulEndpoint : DWord; bIsLastPacket : Boolean);
 Var
  ulVal : DWord;
 begin
  // Determine which endpoint is being acked.
  Case (ulEndpoint = _USB_EP_0) of
   True : // Clear RxPktRdy, and optionally DataEnd, on endpoint zero.
          Case bIsLastPacket of
           True : HWRegBW(ulBase + _USB_O_CSRL0,_USB_CSRL0_RXRDYC or _USB_CSRL0_DataEnd);
           False: HWRegBW(ulBase + _USB_O_CSRL0,_USB_CSRL0_RXRDYC                      );
          End;
   False: // Clear RxPktRdy on all other endpoints.
          Begin
           HWRegBR(ulBase + _USB_O_RXCSRL1 + (ulEndpoint-$10),ulVal);
           HWRegBW(ulBase + _USB_O_RXCSRL1 + (ulEndpoint-$10),
                   ulVal and Not(Dword(_USB_RXCSRL1_RXRDY)));
          End;
  End;
 End;
 
//                   R0             R1                          R2
Procedure USBGetData(ulFIFO :DWord; Var Buf : Array[1] of Byte; Lp : DWord);
 begin
  asm
   Loop:
   LDR  R3,[R0,#0];  // Load Data
   STR  R3,[R1,#0];  // Save Data to Buf
   SUBS R2, R2, #4;  // Dec Lp
   ADD  R1, R1, #4;  // Pointer Move +1
   BNE  Loop;        //
  end;
 end;
// 추후 Word단위 수정 요망
//                   R0             R1                          R2
Procedure USBPutData(ulFIFO :DWord; Var Buf : Array[1] of Byte; Lp : DWord);
 begin
  asm
   Loop:
   LDRB  R3,[R1,#0];  // Save Data to Buf
   STRB  R3,[R0,#0];  // Load Data
   SUBS R2, R2, #1;  // Dec Lp
   ADD  R1, R1, #1;  // Pointer Move +1
   BNE  Loop;        //
  end;
 end;
 
// usb.c
Function USBEndpointDataGet (ulBase, ulEndpoint : DWord;
                             pucData : Pointer; Var pulSize : DWord) : LongInt;
 Var
  ulRegister  : DWord;
  ulByteCount : DWord;
  ulFIFO      : DWord;
  ulVal       : ^DWord;
  Bv          : Byte;
  Lp          : Byte;
 begin
  // Get the address of the receive status register to use, based on the endpoint.
  Case (ulEndpoint = _USB_EP_0) of
   True  : ulRegister := _USB0_BASE_CSRL0;
   False : ulRegister := _USB0_BASE_RXCSRL1 + (ulEndpoint-$10);
  End;
  // Don't allow reading of data if the RxPktRdy bit is not set.
  ulVal := ulRegister;
  If (ulVal^ and _USB_CSRL0_RXRDY) = 0 then
   begin
    pulSize :=  0;
    Result  := -1;
    Exit;
   end;
  // Get the byte count in the FIFO.
  ulVal := _USB0_BASE_COUNT0 + ulEndPoint;
  ulByteCount := ulVal^;
  If  (ulByteCount >= pulSize) then
   ulByteCount := pulSize;
  // Return the number of bytes we are going to read.
  pulSize := ulByteCount;
  // Calculate the FIFO address.
  ulFIFO := _USB0_BASE_FIFO0 + (ulEndpoint shr 2);
  //
 {
  Lp := 0;
  While (ulByteCount > 0) do
   begin
    HWRegBR(ulFIFO,Bv);
    _gUSB.BufR[lp] := Bv;
    Inc(lp);
    Dec(ulByteCount);
   end;
  }
  //USBGetData(ulFIFO,_gUSB.BufR,ulByteCount);
  USBGetData(ulFIFO,pucData,ulByteCount);
  // Success.
  Result := 0;
 end;
// usb.c
Function USBEndpointDataPut( ulBase, ulEndpoint : DWord;
                             pucData  : Pointer; ulSize : DWord) : LongInt;
 Var
  ulFIFO     : DWord;
  ucTxPktRdy : Byte;
  ulVal      : DWord;
 begin
  // Get the bit position of TxPktRdy based on the endpoint.
  Case (ulEndpoint = _USB_EP_0) of
   True  : ucTxPktRdy := _USB_CSRL0_TXRDY;
   False : ucTxPktRdy := _USB_TXCSRL1_TXRDY;
  End;
  // Don't allow transmit of data if the TxPktRdy bit is already set.
  HWRegBR(ulBase + _USB_O_CSRL0 + ulEndpoint,ulVal);
  If (ulVal and ucTxPktRdy) then
   begin
    Result := -1;
    Exit;
   end;
  // Calculate the FIFO address.
  ulFIFO := ulBase + _USB_O_FIFO0 + (ulEndpoint shr 2);
  // Write the data to the FIFO.
{
  While (ulSize > 0) do
   begin
    HWRegBW(ulFIFO,pucData^); // SIMON / 최적화 필요
    Inc(pucData);
    Dec(ulSize);
   end;
}
  USBPutData(ulFIFO,pucData,ulSize);
  
  // Success.
  Result := 0;
 end;
//
Function USBEndpointDataSend(ulBase, ulEndpoint,ulTransType : DWord) : LongInt;
 Var
  ulTxPktRdy : DWord;
  ulVal      : DWord;
 begin
  // Get the bit position of TxPktRdy based on the endpoint.
  if(ulEndpoint = _USB_EP_0) then
   ulTxPktRdy := ulTransType and $ff
  else
   ulTxPktRdy := (ulTransType shr 8) and $ff;
  // Don't allow transmit of data if the TxPktRdy bit is already set.
  HWRegBR(ulBase + _USB_O_CSRL0 + ulEndpoint,ulVal);
  If (ulVal and _USB_CSRL0_TXRDY) then
   begin
    Result := -1;
    Exit;
   end;
  // Set TxPktRdy in order to send the data.
  HWRegBW(ulBase + _USB_O_CSRL0 + ulEndpoint, ulTxPktRdy);
  // Success.
  Result := 0;
 end;
// usb.c
Procedure USBOTGMode(ulBase : DWord);
 begin
  // Disable the override of the USB controller mode when running on an OTG device.
  HWRegBW(ulBase + _USB_O_GPCS,0);
 end;
//------------------------------------------------------------------------------
// Utility Function
//------------------------------------------------------------------------------
//
Procedure utGetStrDesc(inx : DWord; Var ugDesc : TStrDesc);
 Var
  uLp  : DWord;
  uLen : DWord;
 Begin
  //
  If Inx > 5 then Inx := 2; // Str Product
  //
  ugDesc.StrDesc := _cStrDesc;
  //
  Case inx of
   0    : Begin
           ugDesc.Len := 4;
           ugDesc.Dat[0] := cStrlang[0];
           ugDesc.Dat[1] := cStrlang[1];
          End
   else   Begin
           Dec(inx); // Set Inx
           uLen := Length(cStrDescs[inx]);
           ugDesc.Len := uLen*2 + 2; // Size + StrDesc + Str
           For uLp := 0 to uLen-1 do
            begin
             ugDesc.Dat[uLp*2+0] := cStrDescs[inx][uLp];
             ugDesc.Dat[uLp*2+1] := 0;
            end;
          End;
  End;
 End;
//------------------------------------------------------------------------------
//
// S/W Driver Function
//
//------------------------------------------------------------------------------
//
Procedure User_Reply(Var USB : TUSB);
 Var
  lRetCode : Integer;
 begin
  USB.BufW[0] := $10;
  USB.BufW[1] := $20;
  lRetcode := USBEndpointDataPut(_USB0_BASE,$10,@USB.BufR,64);
  If lRetcode = -1 then Exit;
  USBEndpointDataSend(_USB0_BASE,$10,_USB_TRANS_In_Last);
 end;
// 단 USB.ModeCnt > 0 이상
Procedure Bulk_DevToPc_Start(Var USB : TUSB);
 Var
  lRetCode : Integer;
 begin
  // 첫 번째 패킷 전송
  lRetcode := USBEndpointDataPut(_USB0_BASE,$10,@USB.BufW,64);
  If lRetcode = -1 then Exit;
  //
  Case (USB.ModeCnt = 1) of
   True  : USBEndpointDataSend(_USB0_BASE,$10,_USB_TRANS_In_Last);
   False : USBEndpointDataSend(_USB0_BASE,$10,_USB_TRANS_In     );
  End;
 end;
//
Procedure Bulk_DevToPC_Send(Var USB : TUSB; ulEPStatus : DWord);
 Var
  lRetCode : Integer;
  ulLength : DWord;
 begin
  USBDevEndpointStatusClear(_USB0_BASE,$10 {cEpBulk},ulEPStatus);
  //If _gUSB.UserCmd <>
  Dec(USB.ModeCnt);
  //
  Case (USB.ModeCnt = 0) of
   True : // 종료
          begin
           LCD_Log(clWhite,'Bulk End');
           Exit;
          end;
   False: // 다음 블럭
          begin
           ulLength := 64;
           lRetcode := USBEndpointDataPut(_USB0_BASE,$10,@USB.BufW,ulLength);
           If lRetcode = -1 then Exit;
           Case (USB.ModeCnt = 1) of
            True  : USBEndpointDataSend(_USB0_BASE,$10,_USB_TRANS_In_Last);
            False : USBEndpointDataSend(_USB0_BASE,$10,_USB_TRANS_In     );
           End;
          end;
  End;
 end;

// HandleEndpoints           ( usbdbulk.c )
//       ProcessDataFromHost ( usbdbulk.c )
//             USBDBulkPacketRead
//       ProcessDataToHost   ( usbdbulk.c )
//             USBDBulkPacketWrite
Procedure Process_EP1(Var USB :TUSB; ulStatus :DWord); // Ep[1~x]
 Var
  ulEPStatus : DWord;
  ulSize     : DWord;
  lRetCode   : Integer;
 begin
  // Host -> Dev : Bulk Out // Process_DataFromHost, USBDBulkPacketRead -------
  If (ulStatus and $00020000) then   // Hard Coding , Simon 추후 변경
   begin
    ulEPStatus := USBEndpointStatus  (_USB0_BASE, $10 {cEpBulk} );
    // $0003:0000 ->  RX_FIFO_FULL & RX_PKT_RDY
    If (ulEPStatus and _USB_DEV_RX_PKT_RDY) then
     begin
      ulSize := USBEndpointDataAvail (_USB0_Base, $10 {cEpBulk} );
      USBEndPointDataGet             (_USB0_Base, $10,@_gUSB.BufR,ulSize    );
      //
      USBDevEndpointStatusClear      (_USB0_BASE, $10 {cEpBulk} , ulEPStatus);
      USBDevEndpointDataAck          (_USB0_Base, $10 {cEpBulk} , True);
      If USB.ModeDir = _DirInOut then
       User_Reply(USB);
     end;
   end;
  // Dev -> Host  : Bulk In ( Process_DataToHost(ulStatus) )-------------------
  If (ulStatus and $00000002) then   // Hard Coding, Simon 추후 변경
   begin
    If USB.ModeDir <> _DirIn then Exit; // DirIn [PC<-dev span="">
    ulEPStatus := USBEndpointStatus  (_USB0_BASE, $10 {cEpBulk} );
    Bulk_DevToPC_Send(USB,ulEPStatus);
   end;
 end;
// Process User Command :
Procedure Process_EP0_User(Var USB : TUSB);
 Var
  pUSBBuf   : pUSBBufDW;
 begin
 //
  Case USB.PktPhase of
   _pSetup : // Check Get Set Request
             If USB.CtlReq = _CmdReqFunc then
             Case (USB.CtlReqType and _udDev2Host) > 0 of
              True : // Get Request  ( No Data Phase )
                     begin
                      USBDevEndpointDataAck(_USB0_BASE,_USB_EP_0,false);
                      Case USB.CtlValue of
                       _CmdGetStatus : // 적당한 응답 (Dir + Addr + Cnt)
                                       begin
                                        USBEndpointDataPut (_USB0_BASE,_USB_EP_0,@USB.ModeDir,12);
                                        USBEndpointDataSend(_USB0_BASE,_USB_EP_0,_USB_TRANS_IN_LAST);
                                       end;
                      End;
                     end;
              False: // Set Request -> Read Data
                     Case USB.CtlLength = 0 of
                      True : USBDevEndpointDataAck(_USB0_BASE,_USB_EP_0,True);
                      False: Begin
                              USBDevEndpointDataAck(_USB0_BASE,_USB_EP_0,false);
                              USB.PktPhase   := _pData;
                             End;
                     end;
             end;
   _pData  : // Data Phase for User Command
            begin
             USBDevEndpointDataAck(_USB0_BASE,_USB_EP_0,True);
             If (USB.CtlReq = _CmdReqFunc) then
              Case USB.CtlValue of
               _CmdSetStatus : begin
                                pUSBBuf       := Pointer(@USB.BufR);
                                USB.ModeDir   := pUSBBuf^[0];
                                USB.ModeAddr  := pUSBBuf^[1];
                                USB.ModeCnt   := pUSBBuf^[2];
                               end;
               _CmdSetAction : begin
                                pUSBBuf       := Pointer(@USB.BufR);
                                USB.ModeState := pUSBBuf^[0];
                                // Simon : Future Works...
                                If USB.ModeState = _tmsStop then
                                 SD_MovStop := True;
                                // Bulk_DevToPc_Start(USB);
                               end;
              end;
            end;
  End;
 end;
// Ref. USBDeviceEnumHandler (usbdenum.c)
Procedure Process_EP0(Var USB : TUSB);
 Var
  EP0Stat   : DWord;
  pDat      : Pointer;
  dSize     : DWord;
  wData     : Word;
  pRequest  : pUSBRequest;
  pUSBBuf   : pUSBBufDW;
 begin
  Ep0Stat := USBEndpointStatus(_USB0_BASE, _USB_EP_0); // -값  발생 (Simon)
  If USB.AddrSet then
   begin
    USBDevAddrSet(_USB0_Base,USB.Addr);
    USB.AddrSet := False;
   end;
  If (Ep0Stat and _USB_DEV_EP0_SENT_STALL) then
   USBDevEndpointStatusClear(_USB0_BASE, _USB_EP_0,_USB_DEV_EP0_SENT_STALL);
  If (Ep0Stat and _USB_DEV_EP0_OUT_PKTRDY) = 0 then Exit;
  // Receive Data & Process ---------------------------------------------------
  dSize   := _EP0_MAX_PACKET_SIZE;
  USBEndpointDataGet(_USB0_BASE,_USB_EP_0,@USB.BufR,dSize);
  If dSize = 0 then Exit;
  //
  Case USB.PktPhase of
   _pSetup : begin
              pRequest       := Pointer(@USB.BufR);
              USB.CtlReqType := pRequest^.bmRequestType;
              USB.CtlReq     := pRequest^.bRequest;
              USB.CtlValue   := pRequest^.wValue;
              USB.CtlLength  := pRequest^.wLength;
              Case (pRequest^.bmRequestType and _USB_RTYPE_TYPE_M) = 0 of
               True : // Standard
                      Case pRequest^.bRequest of
                       _urGetStat  : // 0
                                     begin
                                      wData := $0001;
                                      USBDevEndpointDataAck(_USB0_BASE,_USB_EP_0,false);
                                      USBEndpointDataPut   (_USB0_BASE,_USB_EP_0,@wData,SizeOf(wData));
                                      USBEndpointDataSend  (_USB0_BASE,_USB_EP_0,_USB_TRANS_IN_LAST);
                                      //LCD_Log(clLime,'GetStat');
                                     end;
                       _urSetConf  : // 9
                                     begin
                                      USBDevEndpointDataAck(_USB0_BASE, _USB_EP_0,True);
                                      USB.Status := _tusReady;
                                      // LCD_Log(clLime,'SetConf');
                                      USB.Ready  := True;
                                      //
                                      USBDevEndpointConfigSet(_USB0_BASE,_USB_EP_1, 64,_USB_EP_DEV_IN  or _USB_EP_MODE_BULK);
                                      USBDevEndpointConfigSet(_USB0_BASE,_USB_EP_1, 64,_USB_EP_DEV_OUT or _USB_EP_MODE_BULK);
                                      USBFIFOConfigSet       (_USB0_BASE,_USB_EP_1, 64,_USB_FIFO_SZ_64, _USB_EP_DEV_IN );
                                      USBFIFOConfigSet       (_USB0_BASE,_USB_EP_1,128,_USB_FIFO_SZ_64, _USB_EP_DEV_OUT);
                                     end;
                       _urSetAddr  : // 5
                                     begin
                                      USBDevEndpointDataAck(_USB0_BASE, _USB_EP_0,True);
                                      USB.Addr    := pRequest^.wValue;
                                      USB.AddrSet := True;
                                      //LCD_Log(clLime,'SetAddr');
                                     end;
                       _urGetDesc  : // 6
                                     Begin
                                      Case Hi(pRequest^.wValue) of
                                       $01 : // Device
                                             begin
                                              pDat  := @cDevDesc;
                                              dSize := SizeOf(cDevDesc);
                                              //LCD_Log(clLime,'gd Device');
                                             end;
                                       $02 : // Configuration
                                             begin
                                              pDat  := @cCfgDesc;
                                              Case pRequest^.wLength of
                                               $09  : dSize := $09               // Cfg Desc Only
                                               else   dSize := SizeOf(cCfgDesc); // Cfg + Device + EP (Full)
                                              end;
                                              //Case pRequest^.wLength of
                                              // $09  : LCD_Log(clLime,'Cfg mini')
                                              // else   LCD_Log(clLime,'Cfg full');
                                              //End;
                                             end;
                                       $03 : // String
                                             begin
                                              utGetStrDesc(Lo(pRequest^.wValue),_lStrDesc);
                                              pDat  := @_lStrDesc;
                                              dSize := _lStrDesc.Len;
                                              IntToStr(Lo(pRequest^.wValue),Str);
                                              //LCD_Log(clLime,'sd'+Str);
                                             end
                                       else  begin
                                              //LCD_Log(clLime,'Exit');
                                              Exit;
                                             end;
                                      End;
                                      // Send Ack + Data (Asumption : Always DataLen < 64 )
                                      USBDevEndpointDataAck(_USB0_BASE,_USB_EP_0,false);
                                      USBEndpointDataPut   (_USB0_BASE,_USB_EP_0,pDat,dSize);
                                      USBEndpointDataSend  (_USB0_BASE,_USB_EP_0,_USB_TRANS_IN_LAST);
                                     End;
                      end;
               False: // Non-Standard
                      Process_EP0_User(USB);
              end;
             End;
   _pData  : begin
              Case (USB.CtlReqType and _USB_RTYPE_TYPE_M) = 0 of
               True : // Standard
                      USBDevEndpointDataAck(_USB0_BASE, _USB_EP_0,True);
               False: // Non Standard
                      Case USB.CtlReq = _CmdReqFunc of
                       True  : Process_EP0_User(USB);
                       False : USBDevEndpointDataAck(_USB0_BASE, _USB_EP_0,True);
                      End;
              End;
              USB.PktPhase := _pSetup;
             end;
  end;
 end;
//
Procedure USB_Handler;
 Var
  ulStatus   : DWord;
 begin
  // System Event
  ulStatus := USBIntStatusControl(_USB0_Base);
  If (ulStatus and $2F) then
   begin
    If (ulStatus and _USB_INTCTRL_RESET     ) then _gUSB.Status := _tusReset;
    If (ulStatus and _USB_INTCTRL_SUSPEND   ) then _gUSB.Status := _tusSuspend;
    If (ulStatus and _USB_INTCTRL_RESUME    ) then _gUSB.Status := _tusResume;
    If (ulStatus and _USB_INTCTRL_DISCONNECT) then _gUSB.Status := _tusDisconnect;
    If (ulStatus and _USB_INTCTRL_SOF       ) then _gUSB.Status := _tusSOF;
   end;
  // Ep0 Event
  ulStatus := USBIntStatusEndpoint(_USB0_Base);
  If (ulStatus and _USB_INTEP_0 ) then Process_EP0(_gUSB);
  // Ep1~15 Event
  If _gUSB.Ready                  then Process_EP1(_gUSB,ulStatus);
 end;
// USBDeviceIntHandlerInternal (usbdenum.c)
Procedure USB0Int(); iv IVT_INT_USB0;  ics ICS_AUTO; //ics ICS_OFF;  // ics ICS_AUTO;
 begin
  USB_Handler;
 end;
//
Procedure USB_Init(Operation : TUSBOperation);
 Var
  Lp : DWord;
 begin
   // S/W Init ----------------------------------------------------------------
   _gUSB.Operation  := Operation;
   _gUSB.Ready      := False;
   _gUSB.Status     := _tusNone;
   _gUSB.PktPhase   := _pSetup;
   _gUSB.CtlReqType := 0;
   _gUSB.CtlReq     := 0;
   _gUSB.CtlValue   := 0;
   _gUSB.CtlLength  := 0;
   _gUSB.ModeDir    := _DirInOut;
   _gUSB.ModeAddr   := 0;
   _gUSB.ModeCnt    := 0;
   _gUSB.ModeState  := _tmsNone;
   _gUSB.Addr       := 0;
   _gUSB.AddrSet    := False;
   // H/W Init ----------------------------------------------------------------
   SysCtlPeripheralReset (_SYSCTL_PERIPH_USB0); // Reset the USB controller.
   SysCtlPeripheralEnable(_SYSCTL_PERIPH_USB0); // Enable Clocking to the USB controller.
   SysCtlUSBPLLEnable();                        // Turn on USB Phy clock.
   USBOTGMode(_USB0_BASE);
   //--------------------------------------------------------------------------
   USBIntStatusControl  (_USB0_BASE); // 모든 상태 초기화
   USBIntStatusEndpoint (_USB0_BASE);
   // Enable USB Interrupts.
   USBIntEnableControl  (_USB0_BASE,
                         _USB_INTCTRL_SUSPEND    or //$01
                         _USB_INTCTRL_RESUME     or //$02
                         _USB_INTCTRL_RESET      or //$04
                         _USB_INTCTRL_SOF        or //$08
                         _USB_INTCTRL_DISCONNECT);  //$20
   USBIntEnableEndpoint(_USB0_BASE, _USB_INTEP_ALL);
   USBDevDisconnect(_USB0_BASE);
   Delay_ms(100);
   USBDevConnect   (_USB0_BASE); // Attach the device using the soft connect.
   //
   Case Operation = _cUSB_Interrupt of
    True  : IntEnable       (_INT_USB0 ); // Enable the USB interrupt.
    False : For Lp := 0 to 2000 do
             begin
              Delay_ms(1);
              USB_Handler;
              If _gUSB.Ready then Exit;
             end;
   End;
  end;
//------------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------------
// Result : USB.ModeState
Procedure USB_ReadBuf(Var USB : TUSB; Var Buf : Array[1] of Byte; MaxCnt : DWord);
 Var
  ulStatus   : DWord;
  ulEPStatus : DWord;
  ulSize     : DWord;
  ulLp       : Integer;
 begin
  USB.ModeState := _tmsNone;
  ulLp := 0; // 64 x 8 = 512
  Repeat
   // Ep0 Event
   ulStatus := USBIntStatusEndpoint(_USB0_Base);
   If (ulStatus and _USB_INTEP_0 ) then Process_EP0(_gUSB);
   If Not(_gUSB.Ready)             then Exit;
   If USB.ModeState = _tmsStop then Exit;
   // Host -> Dev : Bulk Out // Process_DataFromHost, USBDBulkPacketRead -------
   If (ulStatus and $00020000) then   // Hard Coding , Simon 추후 변경
    begin
     ulEPStatus := USBEndpointStatus  (_USB0_BASE, $10 {cEpBulk} );
     // $0003:0000 ->  RX_FIFO_FULL & RX_PKT_RDY
     If (ulEPStatus and _USB_DEV_RX_PKT_RDY) then
      begin
       ulSize := USBEndpointDataAvail (_USB0_Base, $10 {cEpBulk} );
       USBEndPointDataGet             (_USB0_Base, $10, @Buf[ulLp*64],ulSize);
       USBDevEndpointStatusClear      (_USB0_BASE, $10 {cEpBulk} , ulEPStatus);
       USBDevEndpointDataAck          (_USB0_Base, $10 {cEpBulk} , True);
       Inc(ulLp);
      end
    end;
   //
  Until ( ulLp >= MaxCnt );
 end;
// Result : USB.ModeState
Procedure USB_WriteBuf(Var USB : TUSB; Var Buf : Array[1] of Byte; MaxCnt : DWord);
 Var
  ulStatus   : DWord;
  ulEPStatus : DWord;
  ulSize     : DWord;
  ulLp       : Integer;
 begin
  USB.ModeState := _tmsNone;
  ulLp := 0; // 64 x 8 = 512
  //
  USBEndpointDataPut (_USB0_BASE,$10,@Buf[ulLp*64],64);
  USBEndpointDataSend(_USB0_BASE,$10,_USB_TRANS_In   );
  Inc(ulLp);
  //
  Repeat
   // Ep0 Event
   ulStatus := USBIntStatusEndpoint(_USB0_Base);
   If (ulStatus and _USB_INTEP_0 ) then Process_EP0(_gUSB);
   If Not(_gUSB.Ready)             then Exit;
   If USB.ModeState = _tmsStop     then Exit;
   // Host -> Dev : Bulk Out // Process_DataFromHost, USBDBulkPacketRead -------
   If (ulStatus and $00000002) then   // Hard Coding , Simon 추후 변경
    begin
     ulEPStatus := USBEndpointStatus  (_USB0_BASE, $10 {cEpBulk} );
     //
     USBDevEndpointStatusClear(_USB0_BASE,$10 {cEpBulk},ulEPStatus);
     USBEndpointDataPut       (_USB0_BASE,$10,@Buf[ulLp*64],64);
     // SIMON
     Case (ulLp = (MaxCnt-1))of
      True  : USBEndpointDataSend (_USB0_BASE,$10,_USB_TRANS_In_Last);
      False : USBEndpointDataSend (_USB0_BASE,$10,_USB_TRANS_In     );
     End;
     Inc(ulLp);
    end;
  Until ( ulLp >= MaxCnt );
  //
  While (true) do
   begin
    // Ep0 Event
    ulStatus := USBIntStatusEndpoint(_USB0_Base);
    //If _gUSB.Ready                  then Process_EP1(_gUSB,ulStatus);
    If Not(_gUSB.Ready)             then Exit;
    If USB.ModeState = _tmsStop     then Exit;
    // Host -> Dev : Bulk Out // Process_DataFromHost, USBDBulkPacketRead -------
    If (ulStatus and $00000002) then   // Hard Coding , Simon 추후 변경
     begin
      ulEPStatus := USBEndpointStatus  (_USB0_BASE, $10 {cEpBulk} );
      USBDevEndpointStatusClear(_USB0_BASE,$10 {cEpBulk},ulEPStatus);
      Exit;
     end;
   end;
 end;
//  PC -> Read USB Read ->  Write
Function  USB_PutSD(Var USB : TUSB) : Boolean;
 Var
  Lp  : DWord;
  Inx : DWord;
  Rst : Boolean;
 Label
  JumpEnd;
 begin
  //
  Result := True;
  //
  Rst := SD_Write_MultiBlock_Start (USB.ModeAddr);
  If Not(Rst) then Result := False;
  For Lp := 0 to USB.ModeCnt-1 do
   begin
    USB_ReadBuf(_gUSB,Buf512,8);
    If _gUSB.ModeState = _tmsStop then
     begin
      LCD_log(clRed,'Stop');
      Goto JumpEnd;
     end;
    Rst := SD_Write_MultiBlock(Buf512);
    If Not(Rst) then Result := False;
   end;
  //
  JumpEnd:
  _gUSB.ModeState := _tmsNone;
  SD_Write_MultiBlock_Stop;
 end;
 
//
Function  USB_GetSD (Var USB : TUSB) : Boolean;
 Var
  Lp  : DWord;
  Inx : DWord;
  Rst : Boolean;
 Label
  JumpEnd;
 begin
  //
  Result := True;
  //
  Rst := SD_Read_MultiBlock_Start (USB.ModeAddr);
  If Not(Rst) then Result := False;
  //
  For Lp := 0 to USB.ModeCnt-1 do
   begin
    Rst := SD_Read_MultiBlock(Buf512);
    If Not(Rst) then Result := False;
    USB_WriteBuf(_gUSB,Buf512,8);
    If _gUSB.ModeState = _tmsStop then
     begin
      LCD_log(clRed,'Stop');
      Goto JumpEnd;
     end;
   end;
  //
  JumpEnd:
  _gUSB.ModeState := _tmsNone;
  SD_Read_MultiBlock_Stop;
 end;
end.
 

댓글 없음: