832 lines
22 KiB
ArmAsm
832 lines
22 KiB
ArmAsm
/* This file is the part of the Lightweight USB device Stack for STM32 microcontrollers
|
|
*
|
|
* Copyright ©2016 Dmitry Filimonchuk <dmitrystu[at]gmail[dot]com>
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#if !defined (__ASSEMBLER__)
|
|
#define __ASSEMBLER__
|
|
#endif
|
|
|
|
#include "usb.h"
|
|
#if defined(USBD_STM32L100)
|
|
#include "memmap.inc"
|
|
|
|
#define EP_SETUP 0x0800
|
|
#define EP_TYPE 0x0600
|
|
#define EP_KIND 0x0100
|
|
#define EP_ADDR 0x000F
|
|
|
|
#define EP_RX_CTR 0x8000
|
|
#define EP_RX_DTOG 0x4000
|
|
#define EP_RX_STAT 0x3000
|
|
#define EP_RX_SWBUF 0x0040
|
|
|
|
#define EP_RX_DIS 0x0000
|
|
#define EP_RX_STAL 0x1000
|
|
#define EP_RX_NAK 0x2000
|
|
#define EP_RX_VAL 0x3000
|
|
|
|
#define EP_TX_CTR 0x0080
|
|
#define EP_TX_DTOG 0x0040
|
|
#define EP_TX_STAT 0x0030
|
|
#define EP_TX_SWBUF 0x4000
|
|
|
|
#define EP_TX_DIS 0x0000
|
|
#define EP_TX_STAL 0x0010
|
|
#define EP_TX_NAK 0x0020
|
|
#define EP_TX_VAL 0x0030
|
|
|
|
#define RXADDR0 0x00
|
|
#define RXCOUNT0 0x04
|
|
#define RXADDR1 0x08
|
|
#define RXCOUNT1 0x0C
|
|
|
|
#define TXADDR0 0x00
|
|
#define TXCOUNT0 0x04
|
|
#define TXADDR1 0x08
|
|
#define TXCOUNT1 0x0C
|
|
|
|
#define TXADDR 0x00
|
|
#define TXCOUNT 0x04
|
|
#define RXADDR 0x08
|
|
#define RXCOUNT 0x0C
|
|
|
|
|
|
|
|
#define EP_NOTOG (EP_RX_CTR | EP_TX_CTR | EP_SETUP | EP_TYPE | EP_KIND | EP_ADDR)
|
|
|
|
#define TGL_SET(mask, bits) ((EP_NOTOG | (mask))<<16 | (bits))
|
|
|
|
#define TX_STALL TGL_SET(EP_TX_STAT, EP_TX_STAL)
|
|
#define RX_STALL TGL_SET(EP_RX_STAT, EP_RX_STAL)
|
|
#define TX_USTALL TGL_SET(EP_TX_STAT | EP_TX_DTOG, EP_TX_NAK)
|
|
#define RX_USTALL TGL_SET(EP_RX_STAT | EP_RX_DTOG, EP_RX_VAL)
|
|
#define DTX_USTALL TGL_SET(EP_TX_STAT | EP_TX_DTOG | EP_TX_SWBUF, EP_TX_VAL)
|
|
#define DRX_USTALL TGL_SET(EP_RX_STAT | EP_RX_DTOG | EP_RX_SWBUF, EP_RX_VAL | EP_RX_SWBUF)
|
|
|
|
|
|
.syntax unified
|
|
.cpu cortex-m3
|
|
.thumb
|
|
|
|
.section .rodata.usbd_devfs_asm
|
|
.align 4
|
|
.globl usbd_devfs_asm
|
|
usbd_devfs_asm:
|
|
.long _getinfo
|
|
.long _enable
|
|
.long _connect
|
|
.long _setaddr
|
|
.long _ep_config
|
|
.long _ep_deconfig
|
|
.long _ep_read
|
|
.long _ep_write
|
|
.long _ep_setstall
|
|
.long _ep_isstalled
|
|
.long _evt_poll
|
|
.long _get_frame
|
|
.long _get_serial_desc
|
|
.size usbd_devfs_asm, . - usbd_devfs_asm
|
|
|
|
.text
|
|
.align 2
|
|
.thumb_func
|
|
.type _get_serial_desc, %function
|
|
|
|
/* uint16_t get_serial_desc (void *buffer)
|
|
* R0 <- buffer for the string descriptor
|
|
* descrpitor size -> R0
|
|
*/
|
|
_get_serial_desc:
|
|
push {r4, r5, lr}
|
|
movs r1, #18 //descriptor size 18 bytes
|
|
strb r1, [r0]
|
|
movs r1, #0x03 //DTYPE_STRING
|
|
strb r1, [r0, #0x01]
|
|
ldr r5, .L_uid_base //UID3 this is the serial number
|
|
ldr r4, .L_fnv1a_offset //FNV1A offset
|
|
ldr r2, [r5, 0x00] //UID0
|
|
bl .L_fnv1a
|
|
ldr r2, [r5, 0x04] //UID1
|
|
bl .L_fnv1a
|
|
ldr r2, [r5, 0x14] //UID2
|
|
bl .L_fnv1a
|
|
movs r3, #28
|
|
.L_gsn_loop:
|
|
lsrs r1, r4, r3
|
|
and r1, #0x0F
|
|
cmp r1, #0x09
|
|
ite gt
|
|
addgt r1, #55
|
|
addle r1, #48
|
|
.L_gsn_store:
|
|
adds r0, #0x02
|
|
strb r1, [r0]
|
|
lsrs r1, #0x08
|
|
strb r1, [r0, #0x01]
|
|
subs r3, #0x04
|
|
bpl .L_gsn_loop
|
|
movs r0, #18
|
|
pop {r4, r5, pc}
|
|
|
|
.L_fnv1a:
|
|
movs r3, #0x04
|
|
.L_fnv1a_loop:
|
|
uxtb r1, r2
|
|
eors r4, r1
|
|
ldr r1, .L_fnv1a_prime //FNV1A prime
|
|
muls r4, r1
|
|
lsrs r2, #0x08
|
|
subs r3, #0x01
|
|
bne .L_fnv1a_loop
|
|
bx lr
|
|
|
|
.align 2
|
|
.L_uid_base: .long UID_BASE
|
|
.L_fnv1a_offset: .long 2166136261
|
|
.L_fnv1a_prime: .long 16777619
|
|
|
|
.size _get_serial_desc, . - _get_serial_desc
|
|
|
|
.thumb_func
|
|
.type _connect, %function
|
|
_connect:
|
|
ldr r1, =SYSCFG_BASE
|
|
movs r3, #0x01
|
|
ldr r2, [r1, #SYSCFG_PMC]
|
|
bics r2, r3
|
|
cbz r0, .L_conn_store
|
|
orrs r2, r3
|
|
.L_conn_store:
|
|
str r2, [r1, #SYSCFG_PMC]
|
|
movs r0, #usbd_lane_unk
|
|
bx lr
|
|
.size _connect, . - _connect
|
|
|
|
.thumb_func
|
|
.type _getinfo, %function
|
|
_getinfo:
|
|
movs r0, 0
|
|
ldr r2, =RCC_BASE
|
|
ldr r1, [r2, #RCC_APB1ENR]
|
|
lsrs r1, #24 //USBEN -> CF
|
|
bcc .L_getinfo_end
|
|
adds r0, #USBD_HW_ENABLED
|
|
ldr r2, =SYSCFG_BASE
|
|
ldr r1, [r2, #SYSCFG_PMC]
|
|
lsrs r1, #1 //PU -> CF
|
|
bcc .L_getinfo_end
|
|
adds r0, #USBD_HW_SPEED_FS
|
|
.L_getinfo_end:
|
|
bx lr
|
|
.size _getinfo, . - _getinfo
|
|
|
|
.thumb_func
|
|
.type _setaddr, %function
|
|
_setaddr:
|
|
ldr r1, =USB_REGBASE
|
|
adds r0, #0x80
|
|
strh r0, [r1, #USB_DADDR] //USB->DADDR
|
|
bx lr
|
|
.size _setaddr, . - _setaddr
|
|
|
|
.thumb_func
|
|
.type _get_frame, %function
|
|
_get_frame:
|
|
ldr r0, =USB_REGBASE
|
|
ldrh r0, [r0, #USB_FNR] //FNR
|
|
lsls r0, #21
|
|
lsrs r0, #21
|
|
bx lr
|
|
.size _get_frame, . - _get_frame
|
|
|
|
.thumb_func
|
|
.type _enable, %function
|
|
_enable:
|
|
ldr r2, =RCC_BASE //RCC
|
|
movs r3, #0x01
|
|
lsls r3, #23 //USBEN or USBRST
|
|
cbz r0, .L_disable
|
|
.L_enable:
|
|
/* enabling and resetting USB peripheral */
|
|
ldr r1, =USB_REGBASE
|
|
ldr r0, [r2, #RCC_APB1ENR]
|
|
orrs r0, r3
|
|
str r0, [r2, #RCC_APB1ENR] //RCC->APB1ENR |= USBEN
|
|
ldr r0, [r2, #RCC_APB1RSTR]
|
|
orrs r0, r3
|
|
str r0, [r2, #RCC_APB1RSTR] //RCC->APB1RSTR |= USBRST
|
|
bics r0, r3
|
|
str r0, [r2, #RCC_APB1RSTR] //RCC->APB1RSTR &= ~USBRST
|
|
/* enabling SYSCFG peripheral */
|
|
movs r3, #0x01 //SYSCFGEN
|
|
ldr r0, [r2, #RCC_APB2ENR]
|
|
orrs r0, r3
|
|
str r0, [r2, #RCC_APB2ENR]
|
|
/* setting up USB CNTR */
|
|
#if !defined(USBD_SOF_DISABLED)
|
|
movs r0, #0xBE // CTRM | ERRM | WKUPM | SUSPM | RESETM | SOFM
|
|
#else
|
|
movs r0, #0xBC // CTRM | ERRM | WKUPM | SUSPM | RESETM
|
|
#endif
|
|
lsls r0, #0x08
|
|
strh r0, [r1, #USB_CNTR] //set USB->CNTR
|
|
bx lr
|
|
.L_disable:
|
|
ldr r0, [r2, #RCC_APB1ENR]
|
|
tst r0, r3
|
|
beq .L_enable_end // usb is already disabled
|
|
/* disabling USB peripheral */
|
|
bics r0, r3
|
|
str r0, [r2, #RCC_APB1ENR]
|
|
/* disabling USB_PU in SYSCFG_PMC */
|
|
movs r3, #0x01
|
|
ldr r1, =SYSCFG_BASE
|
|
ldr r0, [r1, #SYSCFG_PMC]
|
|
bics r0, r3
|
|
str r0, [r1, #SYSCFG_PMC]
|
|
bx lr
|
|
.L_enable_end:
|
|
bx lr
|
|
.size _enable, . - _enable
|
|
|
|
.thumb_func
|
|
.type _ep_setstall, %function
|
|
|
|
/*void ep_settall(uint8_t ep, bool stall)
|
|
* in R0 <- endpoint number
|
|
* in R1 <- 0 if unstall, !0 if stall
|
|
*/
|
|
_ep_setstall:
|
|
push {r4, lr}
|
|
lsls r2, r0, #28
|
|
lsrs r2, #26
|
|
ldr r3, =USB_EPBASE
|
|
adds r3, r2 // epr -> r3
|
|
movs r2, 0x30 // TX_STAT_MASK -> r2
|
|
ldrh r4, [r3]
|
|
lsls r4, #21
|
|
lsrs r4, #29 // EP_TYPE | EP_KIND -> R4 LSB
|
|
cmp r4, #0x04 // ISO ?
|
|
beq .L_eps_exit
|
|
cmp r0, #0x80
|
|
blo .L_eps_rx
|
|
.L_eps_tx:
|
|
ldr r0, =TX_STALL //stall TX
|
|
cmp r1, #0x00
|
|
bne .L_eps_reg_set
|
|
.L_eps_tx_unstall:
|
|
ldr r0, =DTX_USTALL //unstall dblbulk or iso TX (VALID and clr DTOG_TX & SWBUF_TX)
|
|
cmp r4, #0x01 // if doublebuffered bulk endpoint
|
|
beq .L_eps_reg_set
|
|
ldr r0, =TX_USTALL // unstall other TX (NAKED + clr DTOG_TX)
|
|
b .L_eps_reg_set
|
|
.L_eps_rx:
|
|
lsls r2, #8 // RX_STAT_MASK -> R2
|
|
ldr r0,=RX_STALL //stall RX
|
|
cmp r1, #0x00
|
|
bne .L_eps_reg_set
|
|
.L_eps_rx_unstall:
|
|
ldr r0, =DRX_USTALL //unstall dblbulk or iso (VALID. clr DTOG_RX set SWBUF_RX)
|
|
cmp r4, #0x01 // if dblbulk
|
|
beq .L_eps_reg_set
|
|
ldr r0, =RX_USTALL // unstall other RX (VALID + clr
|
|
/* R0 - mask and toggle bits
|
|
* R2 - mask for STAT bits
|
|
* R3 - endpoint register pointer
|
|
*/
|
|
.L_eps_reg_set:
|
|
ldrh r1, [r3] // *epr -> r1
|
|
ands r2, r1 // check if endpoint disabled
|
|
beq .L_eps_exit // do nothing
|
|
eors r1, r0
|
|
lsrs r0, #16
|
|
ands r1, r0
|
|
strh r1, [r3]
|
|
.L_eps_exit:
|
|
pop {r4, pc}
|
|
.size _ep_setstall, . - _ep_setstall
|
|
|
|
|
|
.thumb_func
|
|
.type _ep_isstalled, %function
|
|
/* bool ep_isstalled(uint8t ep) */
|
|
_ep_isstalled:
|
|
ldr r1, =USB_EPBASE
|
|
lsls r2, r0, #28
|
|
lsrs r2, #26
|
|
ldr r1, [r1, r2]
|
|
lsls r1, #17
|
|
cmp r0, #0x80
|
|
bhs .L_eis_check
|
|
lsls r1, #8
|
|
.L_eis_check:
|
|
lsrs r1, r1, #28
|
|
subs r1, #0x01
|
|
subs r0, r1, #0x01
|
|
sbcs r1, r1
|
|
rsbs r0, r1, #0
|
|
bx lr
|
|
.size _ep_isstalled, . - _ep_isstalled
|
|
|
|
|
|
.thumb_func
|
|
.type _ep_read, %function
|
|
/* int32_t _ep_read(uint8_t ep, void *buf, uint16_t blen)
|
|
* in R0 <- endpoint
|
|
* in R1 <- *buffer
|
|
* in R2 <- length of the buffer
|
|
* out length of the recieved data -> R0 or 0 on error
|
|
*/
|
|
_ep_read:
|
|
push {r4, r5, lr}
|
|
ldr r3, =USB_EPBASE
|
|
ldr r4, =USB_PMABASE
|
|
lsls r0, #28
|
|
lsrs r0, #26
|
|
adds r3, r0 // *EPR -> R3
|
|
lsls r0, #2
|
|
adds r4, r0 // *EPT -> R4
|
|
ldrh r5, [r3] // reading epr
|
|
/* validating endpoint */
|
|
movs r0, #0x37
|
|
lsls r0, #0x08
|
|
ands r0, r5
|
|
lsrs r0, #0x08
|
|
cmp r0, #0x34 // (OK) RX_VALID + ISO
|
|
beq .L_epr_iso
|
|
cmp r0, #0x31 // (OK) RX_VALID + DBLBULK
|
|
beq .L_epr_dbl
|
|
cmp r0, #0x20 // (OK) RX_NAKED + BULK
|
|
beq .L_epr_sngl
|
|
cmp r0, #0x22 // (OK) RX_NAKED + CTRL
|
|
beq .L_epr_sngl
|
|
cmp r0, #0x26 // (OK) RX_NAKED + INTR
|
|
beq .L_epr_sngl
|
|
movs r0, #0xFF // endpoint contains no valid data
|
|
sxtb r0, r0
|
|
b .L_epr_exit
|
|
/* processing */
|
|
.L_epr_dbl:
|
|
lsrs r0, r5, #8
|
|
eors r0, r5
|
|
lsrs r0, #7 // SW_RX ^ DTOG_RX -> CF
|
|
bcs .L_epr_notog // jmp if SW_RX != DTOG_RX (VALID)
|
|
ldr r0, =EP_NOTOG
|
|
ands r5, r0
|
|
adds r5, #EP_RX_SWBUF
|
|
strh r5, [r3] // toggling SW_RX
|
|
.L_epr_notog:
|
|
ldrh r5, [r3]
|
|
lsls r5, #8 // shift SW_RX to DTOG_RX
|
|
.L_epr_iso:
|
|
lsrs r5, #15 // DTOG_RX -> CF
|
|
bcs .L_epr_sngl
|
|
subs r4, #0x08 // set RXADDR0
|
|
.L_epr_sngl:
|
|
ldrh r0, [r4, #RXCOUNT]
|
|
lsrs r5, r0, #0x0A
|
|
lsls r5, #0x0A // r5 = r5 & ~0x03FF
|
|
strh r5, [r4, #RXCOUNT]
|
|
lsls r0, #22
|
|
lsrs r0, #22 // r0 &= 0x3FF (RX count)
|
|
ldrh r5, [r4, #RXADDR]
|
|
ldr r4, =USB_PMABASE
|
|
lsls r5, #0x01
|
|
adds r5, r4 // R5 now has a physical address
|
|
cmp r2, r0
|
|
blo .L_epr_read
|
|
mov r2, r0 // if buffer is larger
|
|
.L_epr_read:
|
|
cmp r2, #1
|
|
blo .L_epr_read_end
|
|
ldrh r4, [r5]
|
|
strb r4, [r1]
|
|
beq .L_epr_read_end
|
|
lsrs r4, #8
|
|
strb r4, [r1, #1]
|
|
adds r1, #2
|
|
adds r5, #4
|
|
subs r2, #2
|
|
bhi .L_epr_read
|
|
.L_epr_read_end:
|
|
ldrh r5, [r3] // reload EPR
|
|
lsls r1, r5, #21
|
|
lsrs r1, #29
|
|
cmp r1, #0x04
|
|
beq .L_epr_exit // ep is iso. no needs to set it to valid
|
|
cmp r1, #0x01
|
|
beq .L_epr_exit // ep is dblbulk. no needs to set it to valid
|
|
ldr r2, =TGL_SET(EP_RX_STAT , EP_RX_VAL)
|
|
eors r5, r2
|
|
lsrs r2, #16
|
|
ands r5, r2
|
|
strh r5, [r3] // set ep to VALID state
|
|
.L_epr_exit:
|
|
pop {r4, r5, pc}
|
|
.size _ep_read, . - _ep_read
|
|
|
|
|
|
.thumb_func
|
|
.type _ep_write, %function
|
|
/* int32_t ep_write(uint8_t ep, void *buf, uint16_t blen)
|
|
* R0 -> endpoint
|
|
* R1 -> *buffer
|
|
* R2 -> data length
|
|
* result -> R0
|
|
*/
|
|
_ep_write:
|
|
push {r4, r5, r6, lr}
|
|
ldr r3, =USB_EPBASE
|
|
ldr r4, =USB_PMABASE
|
|
lsls r0, #28
|
|
lsrs r0, #26
|
|
adds r3, r0 // *EPR -> R3
|
|
lsls r0, #2
|
|
adds r4, r0 // TXADDR0 -> R4
|
|
ldrh r5, [r3] // reading epr
|
|
movs r0, #0x73
|
|
lsls r0, #4
|
|
ands r0, r5
|
|
lsrs r0, #4
|
|
cmp r0, #0x43 // (OK) TX_VALID + ISO
|
|
beq .L_epw_iso
|
|
cmp r0, #0x12 // (OK) TX_NAK + DBLBULK
|
|
beq .L_epw_dbl
|
|
cmp r0, #0x02 // (OK) TX_NAK + BULK
|
|
beq .L_epw_sngl
|
|
cmp r0, #0x22 // (OK) TX_NAK + CONTROL
|
|
beq .L_epw_sngl
|
|
cmp r0, #0x62 // (OK) TX_NAK + INTERRUPT
|
|
beq .L_epw_sngl
|
|
movs r0, #0xFF
|
|
sxtb r0, r0
|
|
b .L_epw_exit
|
|
.L_epw_dbl:
|
|
mvns r5, r5
|
|
lsrs r5, #8 // ~SWBUF_TX -> DTOG_TX
|
|
.L_epw_iso:
|
|
lsrs r5, #7 // DTOG_TX -> CF
|
|
bcs .L_epw_sngl
|
|
adds r4, #8 // TXADDR1 -> R4
|
|
.L_epw_sngl:
|
|
strh r2, [r4, #TXCOUNT]
|
|
mov r0, r2 // save count for return
|
|
ldrh r5, [r4, #TXADDR]
|
|
ldr r4, =USB_PMABASE
|
|
lsls r5, #1
|
|
adds r5, r4 // PMA BUFFER -> R5
|
|
.L_epw_write:
|
|
cmp r2, #1
|
|
blo .L_epw_write_end
|
|
ldrb r4, [r1]
|
|
beq .L_epw_store
|
|
ldrb r6, [r1, #1]
|
|
lsls r6, #8
|
|
orrs r4, r6
|
|
.L_epw_store:
|
|
strh r4, [r5]
|
|
adds r5, #4
|
|
adds r1, #2
|
|
subs r2, #2
|
|
bhi .L_epw_write
|
|
.L_epw_write_end:
|
|
ldrh r5, [r3] // reload EPR
|
|
lsls r1, r5, #21
|
|
lsrs r1, #29
|
|
cmp r1, #0x04
|
|
beq .L_epw_exit // isochronous ep. do nothing
|
|
ldr r2, =TGL_SET(EP_TX_STAT, EP_TX_VAL)
|
|
cmp r1, #0x01
|
|
bne .L_epw_setstate // NOT a doublebuffered bulk
|
|
ldr r2, =TGL_SET(EP_TX_SWBUF, EP_TX_SWBUF)
|
|
bics r5, r2 // clear TX_SWBUF
|
|
.L_epw_setstate:
|
|
eors r5, r2
|
|
lsrs r2, #16
|
|
ands r5, r2
|
|
strh r5, [r3]
|
|
.L_epw_exit:
|
|
pop {r4, r5, r6, pc}
|
|
.size _ep_write, .- _ep_write
|
|
|
|
|
|
|
|
/* internal function */
|
|
/* requester size passed in R2 */
|
|
/* result returns in R0 CF=1 if OK*/
|
|
|
|
_get_next_pma:
|
|
push {r1, r3, r4, lr}
|
|
movs r1, #16
|
|
movs r3, #1
|
|
lsls r3, #9 //R3 MAX_PMA_SIZE 512b
|
|
ldr r0, =USB_PMABASE
|
|
.L_gnp_chkaddr:
|
|
ldrh r4, [r0, #0] //txaddr
|
|
tst r4, r4
|
|
beq .L_gnp_nxtaddr
|
|
cmp r3, r4
|
|
blo .L_gnp_nxtaddr
|
|
mov r3, r4
|
|
.L_gnp_nxtaddr:
|
|
adds r0, #8
|
|
subs r1, #1
|
|
bne .L_gnp_chkaddr
|
|
subs r0, r3, r2
|
|
blo .L_gnp_exit
|
|
cmp r0, #0x20 //check for the pma table overlap
|
|
.L_gnp_exit:
|
|
pop {r1, r3, r4, pc}
|
|
|
|
|
|
|
|
.size _get_next_pma, . - _get_next_pma
|
|
|
|
.thumb_func
|
|
.type _ep_config, %function
|
|
/* bool ep_config(uint8_t ep, uint8_t eptype, uint16_t epsize)
|
|
* R0 <- ep
|
|
* R1 <- eptype
|
|
* R2 <- epsize
|
|
* result -> R0
|
|
*/
|
|
_ep_config:
|
|
push {r4, r5, lr}
|
|
movs r3, 0x01
|
|
ands r3, r2
|
|
adds r2, r3 //R2 -> halfword aligned epsize
|
|
movs r3, #0x00 //BULK
|
|
cmp r1, #0x02 // is eptype bulk ?
|
|
beq .L_epc_settype
|
|
movs r3, #0x01 //DBLBULK
|
|
cmp r1, #0x06
|
|
beq .L_epc_settype
|
|
movs r3, #0x02 //CONTROL
|
|
cmp r1, #0x00
|
|
beq .L_epc_settype
|
|
movs r3, #0x04 //ISO
|
|
cmp r1, #0x01
|
|
beq .L_epc_settype
|
|
movs r3, #0x06 //INTERRUPT
|
|
.L_epc_settype:
|
|
lsls r3, #8
|
|
lsls r4, r0, #28
|
|
lsrs r4, #28
|
|
orrs r3, r4
|
|
lsls r4, #2
|
|
ldr r5, =USB_EPBASE
|
|
strh r3, [r5, r4] //setup EPTYPE EPKIND EPADDR
|
|
cmp r1, #0x00 // is a control ep ?
|
|
beq .L_epc_setuptx
|
|
cmp r0, #0x80
|
|
blo .L_epc_setuprx
|
|
.L_epc_setuptx:
|
|
ldr r5, =USB_PMABASE
|
|
lsls r4, #2
|
|
adds r5, r4
|
|
bl _get_next_pma
|
|
bcc .L_epc_fail
|
|
strh r0, [r5, #TXADDR] //store txaddr or txaddr0
|
|
movs r0, #0x00
|
|
strh r0, [r5, #TXCOUNT] //store txcnt
|
|
cmp r1, #0x06 // is DBLBULK
|
|
beq .L_epc_txdbl
|
|
ldr r3, =TX_USTALL //set state NAKED , clr DTOG_TX
|
|
cmp r1, #0x01 // is ISO
|
|
bne .L_epc_txsetstate //
|
|
.L_epc_txdbl:
|
|
ldr r3, =DTX_USTALL //set state VALID clr DTOG_TX & SWBUF_TX
|
|
bl _get_next_pma
|
|
bcc .L_epc_fail
|
|
strh r0, [r5, #TXADDR1] //store txaddr1
|
|
movs r0, #0x00
|
|
strh r0, [r5, #TXCOUNT1] //store txcnt
|
|
.L_epc_txsetstate:
|
|
ldr r5, =USB_EPBASE
|
|
lsrs r4, #2
|
|
ldrh r0, [r5, r4]
|
|
eors r0, r3
|
|
lsrs r3, #16
|
|
ands r0, r3
|
|
strh r0, [r5, r4]
|
|
cmp r1, #0x00 //is a control ep ?
|
|
bne .L_epc_exit
|
|
.L_epc_setuprx:
|
|
movs r3, r2
|
|
cmp r2, #62
|
|
bls .L_epc_rxbb
|
|
movs r3, #0x1F
|
|
adds r2, r3
|
|
bics r2, r3
|
|
lsrs r3, r2, #5
|
|
adds r3, #0x3E
|
|
.L_epc_rxbb:
|
|
lsls r3, #9
|
|
ldr r5, =USB_PMABASE
|
|
lsls r4, #2
|
|
adds r5, r4
|
|
/* RX or RX1 */
|
|
bl _get_next_pma
|
|
bcc .L_epc_fail
|
|
strh r0, [r5, #RXADDR]
|
|
strh r3, [r5, #RXCOUNT]
|
|
ldr r0, =RX_USTALL
|
|
/* check if doublebuffered */
|
|
cmp r1, 0x06 //if dblbulk
|
|
beq .L_epc_rxdbl
|
|
cmp r1, 0x01 // iso
|
|
bne .L_epc_rxsetstate
|
|
.L_epc_rxdbl:
|
|
bl _get_next_pma
|
|
bcc .L_epc_fail
|
|
strh r0, [r5, #RXADDR0] //store rxaddr0
|
|
strh r3, [r5, #RXCOUNT0] //store rxcnt0
|
|
ldr r0, =DRX_USTALL
|
|
.L_epc_rxsetstate:
|
|
ldr r5, =USB_EPBASE
|
|
lsrs r4, #2
|
|
ldrh r3, [r5, r4]
|
|
eors r3, r0
|
|
lsrs r0, #16
|
|
ands r3, r0
|
|
strh r3, [r5, r4]
|
|
.L_epc_exit:
|
|
movs r0, #0x01
|
|
pop {r4, r5, pc}
|
|
.L_epc_fail:
|
|
movs r0, #0x00
|
|
pop {r4, r5, pc}
|
|
|
|
.size _ep_config, . - _ep_config
|
|
|
|
.thumb_func
|
|
.type _ep_deconfig, %function
|
|
|
|
|
|
/* void ep_deconfig( uint8_t ep)
|
|
* R0 <- ep
|
|
*/
|
|
_ep_deconfig:
|
|
lsls r1, r0, #28
|
|
lsrs r1, #26
|
|
ldr r2, =USB_EPBASE
|
|
ldr r3, =USB_PMABASE
|
|
adds r2, r1
|
|
lsls r1, #1
|
|
adds r3, r1
|
|
/* clearing endpoint register */
|
|
ldr r1, =EP_NOTOG
|
|
ldrh r0, [r2]
|
|
bics r0, r1
|
|
strh r0, [r2]
|
|
/* clearing PMA data */
|
|
movs r0, #0x00
|
|
strh r0, [r3, #TXADDR]
|
|
strh r0, [r3, #TXCOUNT]
|
|
strh r0, [r3, #RXADDR]
|
|
strh r0, [r3, #RXCOUNT]
|
|
bx lr
|
|
|
|
.size _ep_deconfig, . - _ep_config
|
|
|
|
|
|
|
|
|
|
#define ISTRSHIFT 8
|
|
#define ISTRBIT(bit) ((1 << bit) >> ISTRSHIFT)
|
|
|
|
|
|
.thumb_func
|
|
.type _evt_poll, %function
|
|
/*void evt_poll(usbd_device *dev, usbd_evt_callback callback)*/
|
|
_evt_poll:
|
|
push {r0, r1, r4, r5}
|
|
ldr r3, =USB_REGBASE
|
|
ldrh r0, [r3, #4] //USB->ISTR -> R2
|
|
/* ep_index -> R2 */
|
|
movs r2, 0x07
|
|
ands r2, r0
|
|
/* checking USB->ISTR for events */
|
|
#if !defined(USBD_SOF_DISABLED)
|
|
lsrs r1, r0, #10 //SOFM -> CF
|
|
bcs .L_ep_sofm
|
|
#endif
|
|
lsrs r1, r0, #11 //RESETM -> CF
|
|
bcs .L_ep_resetm
|
|
lsrs r1, r0, #16 //CTRM -> CF
|
|
bcs .L_ep_ctrm
|
|
lsrs r1, r0, #14 //ERRM -> CF
|
|
bcs .L_ep_errm
|
|
lsrs r1, r0, #13 //WKUPM -> CF
|
|
bcs .L_ep_wkupm
|
|
lsrs r1, r0, #12 //SUSPM -> CF
|
|
bcs .L_ep_suspm
|
|
/* exit with no callback */
|
|
pop {r0, r1, r4 , r5}
|
|
bx lr
|
|
|
|
.L_ep_ctrm:
|
|
movs r5, #0x80 // CTR_TX mask to R5
|
|
ldr r0,=USB_EPBASE
|
|
lsrs r0, #2
|
|
adds r0, r2
|
|
lsls r0, #2 // R0 ep register address
|
|
ldrh r4, [r0] // R4 EPR valur
|
|
lsrs r3, r4, #8 // CTR_TX -> CF
|
|
bcc .L_ep_ctr_rx
|
|
/* CTR_TX event */
|
|
movs r1, #usbd_evt_eptx
|
|
orrs r2, r5 // set endpoint tx
|
|
b .L_ep_clr_ctr
|
|
.L_ep_ctr_rx:
|
|
/* CTR_RX RX or SETUP */
|
|
lsls r5, #0x08 // set mask to CRT_RX
|
|
movs r1, #usbd_evt_eprx
|
|
lsls r3, r4, #21 //SETUP -> CF
|
|
bcc .L_ep_clr_ctr
|
|
movs r1, #usbd_evt_epsetup
|
|
.L_ep_clr_ctr:
|
|
bics r4, r5 //clear CTR flag
|
|
ldr r5, =EP_NOTOG
|
|
ands r4, r5
|
|
strh r4, [r0] // store
|
|
b .L_ep_callback
|
|
.L_ep_errm:
|
|
movs r1, #usbd_evt_error
|
|
movs r4, #ISTRBIT(13)
|
|
b .L_ep_clristr
|
|
#if !defined(USBD_SOF_DISABLED)
|
|
.L_ep_sofm:
|
|
movs r1, #usbd_evt_sof
|
|
movs r4, #ISTRBIT(9)
|
|
b .L_ep_clristr
|
|
#endif
|
|
.L_ep_wkupm:
|
|
ldrh r1, [r3, #0] //R1 USB->CNTR
|
|
movs r5, #0x08
|
|
bics r1, r5 //clr FSUSP
|
|
strh r1, [r3, #0] //USB->CNTR R2
|
|
movs r1, #usbd_evt_wkup
|
|
movs r4, #ISTRBIT(12)
|
|
b .L_ep_clristr
|
|
|
|
.L_ep_suspm:
|
|
ldrh r1, [r3, #0] //R1 USB->CNTR
|
|
movs r5, #0x08
|
|
orrs r1, r5 //set FSUSP
|
|
strh r1, [r3, #0] //USB->CNTR R2
|
|
movs r1, #usbd_evt_susp
|
|
movs r4, #ISTRBIT(11)
|
|
b .L_ep_clristr
|
|
|
|
/* do reset routine */
|
|
.L_ep_resetm:
|
|
movs r1, #7
|
|
ldr r2, =USB_EPBASE
|
|
ldr r0, =USB_PMABASE
|
|
ldr r5, =EP_NOTOG
|
|
.L_ep_reset_loop:
|
|
ldrh r4, [r2]
|
|
bics r4, r5
|
|
strh r4, [r2]
|
|
movs r4, #0
|
|
strh r4, [r0, #TXADDR]
|
|
strh r4, [r0, #TXCOUNT]
|
|
strh r4, [r0, #RXADDR]
|
|
strh r4, [r0, #RXCOUNT]
|
|
adds r2, #0x04
|
|
adds r0, #0x10
|
|
subs r1, #1
|
|
bpl .L_ep_reset_loop
|
|
movs r2, #0x00
|
|
strh r2, [r3, #0x10] // 0 -> USB->BTABLE
|
|
movs r1, #usbd_evt_reset
|
|
movs r4, #ISTRBIT(10)
|
|
.L_ep_clristr:
|
|
lsls r4, #ISTRSHIFT
|
|
ldrh r0, [r3, #4]
|
|
bics r0, r4
|
|
strh r0, [r3, #4]
|
|
.L_ep_callback:
|
|
pop {r0, r3, r4, r5 }
|
|
bx r3
|
|
|
|
.size _evt_poll, . - _evt_poll
|
|
|
|
.pool
|
|
|
|
.end
|
|
|
|
#endif //USBD_STM32L100
|