2  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
 
   3  * Author: Christian Starkjohann
 
   4  * Creation Date: 2007-11-05
 
   6  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
 
   7  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
 
  11 /* Do not link this file! Link usbdrvasm.S instead, which includes the
 
  12  * appropriate implementation!
 
  17 This file contains assembler code which is shared among the USB driver
 
  18 implementations for different CPU cocks. Since the code must be inserted
 
  19 in the middle of the module, it's split out into this file and #included.
 
  21 Jump destinations called from outside:
 
  22     sofError: Called when no start sequence was found.
 
  23     se0: Called when a package has been successfully received.
 
  24     overflow: Called when receive buffer overflows.
 
  25     doReturn: Called after sending data.
 
  27 Outside jump destinations used by this module:
 
  28     waitForJ: Called to receive an already arriving packet.
 
  34 The following macros must be defined before this file is included:
 
  44     ldi     x2, 1<<USB_INTR_PENDING_BIT
 
  45     USB_STORE_PENDING(x2)       ; clear any pending interrupts
 
  48     rjmp    storeTokenAndReturn
 
  50 ;----------------------------------------------------------------------------
 
  51 ; Processing of received packet (numbers in brackets are cycles after center of SE0)
 
  52 ;----------------------------------------------------------------------------
 
  53 ;This is the only non-error exit point for the software receiver loop
 
  54 ;we don't check any CRCs here because there is no time left.
 
  56     subi    cnt, USB_BUFSIZE    ;[5]
 
  60     ldi     x2, 1<<USB_INTR_PENDING_BIT ;[9]
 
  61     USB_STORE_PENDING(x2)       ;[10] clear pending intr and check flag later. SE0 should be over.
 
  63     cpi     token, USBPID_DATA0 ;[13]
 
  65     cpi     token, USBPID_DATA1 ;[15]
 
  67     lds     shift, usbDeviceAddr;[17]
 
  68     ldd     x2, y+1             ;[19] ADDR and 1 bit endpoint number
 
  69     lsl     x2                  ;[21] shift out 1 bit endpoint number
 
  71     rjmp    ignorePacket        ;[23]
 
  72 /* only compute endpoint number in x3 if required later */
 
  73 #if USB_CFG_HAVE_INTRIN_ENDPOINT || USB_CFG_IMPLEMENT_FN_WRITEOUT
 
  74     ldd     x3, y+2             ;[24] endpoint number + crc
 
  75     rol     x3                  ;[26] shift in LSB of endpoint
 
  77     cpi     token, USBPID_IN    ;[27]
 
  79     cpi     token, USBPID_SETUP ;[29]
 
  80     breq    handleSetupOrOut    ;[30]
 
  81     cpi     token, USBPID_OUT   ;[31]
 
  82     brne    ignorePacket        ;[32] must be ack, nak or whatever
 
  83 ;   rjmp    handleSetupOrOut    ; fallthrough
 
  85 ;Setup and Out are followed by a data packet two bit times (16 cycles) after
 
  86 ;the end of SE0. The sync code allows up to 40 cycles delay from the start of
 
  87 ;the sync pattern until the first bit is sampled. That's a total of 56 cycles.
 
  88 handleSetupOrOut:               ;[32]
 
  89 #if USB_CFG_IMPLEMENT_FN_WRITEOUT   /* if we have data for endpoint != 0, set usbCurrentTok to address */
 
  91     breq    storeTokenAndReturn ;[33]
 
  92     mov     token, x3           ;[34] indicate that this is endpoint x OUT
 
  95     sts     usbCurrentTok, token;[35]
 
  97     POP_STANDARD                ;[37] 12...16 cycles
 
  98     USB_LOAD_PENDING(YL)        ;[49]
 
  99     sbrc    YL, USB_INTR_PENDING_BIT;[50] check whether data is already arriving
 
 100     rjmp    waitForJ            ;[51] save the pops and pushes -- a new interrupt is already pending
 
 106 #if USB_CFG_CHECK_CRC
 
 107     CRC_CLEANUP_AND_CHECK       ; jumps to ignorePacket if CRC error
 
 109     lds     shift, usbCurrentTok;[18]
 
 112     lds     x2, usbRxLen        ;[22]
 
 114     brne    sendNakAndReti      ;[25]
 
 115 ; 2006-03-11: The following two lines fix a problem where the device was not
 
 116 ; recognized if usbPoll() was called less frequently than once every 4 ms.
 
 117     cpi     cnt, 4              ;[26] zero sized data packets are status phase only -- ignore and ack
 
 118     brmi    sendAckAndReti      ;[27] keep rx buffer clean -- we must not NAK next SETUP
 
 119 #if USB_CFG_CHECK_DATA_TOGGLING
 
 120     sts     usbCurrentDataToken, token  ; store for checking by C code
 
 122     sts     usbRxLen, cnt       ;[28] store received data, swap buffers
 
 123     sts     usbRxToken, shift   ;[30]
 
 124     lds     x2, usbInputBufOffset;[32] swap buffers
 
 125     ldi     cnt, USB_BUFSIZE    ;[34]
 
 127     sts     usbInputBufOffset, cnt;[36] buffers now swapped
 
 128     rjmp    sendAckAndReti      ;[38] 40 + 17 = 57 until SOP
 
 131 ;We don't send any data as long as the C code has not processed the current
 
 132 ;input data and potentially updated the output data. That's more efficient
 
 133 ;in terms of code size than clearing the tx buffers when a packet is received.
 
 134     lds     x1, usbRxLen        ;[30]
 
 135     cpi     x1, 1               ;[32] negative values are flow control, 0 means "buffer free"
 
 136     brge    sendNakAndReti      ;[33] unprocessed input packet?
 
 137     ldi     x1, USBPID_NAK      ;[34] prepare value for usbTxLen
 
 138 #if USB_CFG_HAVE_INTRIN_ENDPOINT
 
 139     andi    x3, 0xf             ;[35] x3 contains endpoint
 
 140 #if USB_CFG_SUPPRESS_INTR_CODE
 
 141     brne    sendNakAndReti      ;[36]
 
 146     lds     cnt, usbTxLen       ;[37]
 
 147     sbrc    cnt, 4              ;[39] all handshake tokens have bit 4 set
 
 148     rjmp    sendCntAndReti      ;[40] 42 + 16 = 58 until SOP
 
 149     sts     usbTxLen, x1        ;[41] x1 == USBPID_NAK from above
 
 150     ldi     YL, lo8(usbTxBuf)   ;[43]
 
 151     ldi     YH, hi8(usbTxBuf)   ;[44]
 
 152     rjmp    usbSendAndReti      ;[45] 57 + 12 = 59 until SOP
 
 154 ; Comment about when to set usbTxLen to USBPID_NAK:
 
 155 ; We should set it back when we receive the ACK from the host. This would
 
 156 ; be simple to implement: One static variable which stores whether the last
 
 157 ; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the
 
 158 ; ACK. However, we set it back immediately when we send the package,
 
 159 ; assuming that no error occurs and the host sends an ACK. We save one byte
 
 160 ; RAM this way and avoid potential problems with endless retries. The rest of
 
 161 ; the driver assumes error-free transfers anyway.
 
 163 #if !USB_CFG_SUPPRESS_INTR_CODE && USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */
 
 165 #if USB_CFG_HAVE_INTRIN_ENDPOINT3
 
 166 ; 2006-06-10 as suggested by O.Tamura: support second INTR IN / BULK IN endpoint
 
 167     cpi     x3, USB_CFG_EP3_NUMBER;[38]
 
 170     lds     cnt, usbTxLen1      ;[40]
 
 171     sbrc    cnt, 4              ;[42] all handshake tokens have bit 4 set
 
 172     rjmp    sendCntAndReti      ;[43] 47 + 16 = 63 until SOP
 
 173     sts     usbTxLen1, x1       ;[44] x1 == USBPID_NAK from above
 
 174     ldi     YL, lo8(usbTxBuf1)  ;[46]
 
 175     ldi     YH, hi8(usbTxBuf1)  ;[47]
 
 176     rjmp    usbSendAndReti      ;[48] 50 + 12 = 62 until SOP
 
 178 #if USB_CFG_HAVE_INTRIN_ENDPOINT3
 
 180     lds     cnt, usbTxLen3      ;[41]
 
 182     rjmp    sendCntAndReti      ;[44] 49 + 16 = 65 until SOP
 
 183     sts     usbTxLen3, x1       ;[45] x1 == USBPID_NAK from above
 
 184     ldi     YL, lo8(usbTxBuf3)  ;[47]
 
 185     ldi     YH, hi8(usbTxBuf3)  ;[48]
 
 186     rjmp    usbSendAndReti      ;[49] 51 + 12 = 63 until SOP