00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #define token x1
00042
00043 overflow:
00044 ldi x2, 1<<USB_INTR_PENDING_BIT
00045 USB_STORE_PENDING(x2) ; clear any pending interrupts
00046 ignorePacket:
00047 clr token
00048 rjmp storeTokenAndReturn
00049
00050 ;----------------------------------------------------------------------------
00051 ; Processing of received packet (numbers in brackets are cycles after center of SE0)
00052 ;----------------------------------------------------------------------------
00053 ;This is the only non-error exit point for the software receiver loop
00054 ;we don't check any CRCs here because there is no time left.
00055 se0:
00056 subi cnt, USB_BUFSIZE ;[5]
00057 neg cnt ;[6]
00058 sub YL, cnt ;[7]
00059 sbci YH, 0 ;[8]
00060 ldi x2, 1<<USB_INTR_PENDING_BIT ;[9]
00061 USB_STORE_PENDING(x2) ;[10] clear pending intr and check flag later. SE0 should be over.
00062 ld token, y ;[11]
00063 cpi token, USBPID_DATA0 ;[13]
00064 breq handleData ;[14]
00065 cpi token, USBPID_DATA1 ;[15]
00066 breq handleData ;[16]
00067 lds shift, usbDeviceAddr;[17]
00068 ldd x2, y+1 ;[19] ADDR and 1 bit endpoint number
00069 lsl x2 ;[21] shift out 1 bit endpoint number
00070 cpse x2, shift ;[22]
00071 rjmp ignorePacket ;[23]
00072 /* only compute endpoint number in x3 if required later */
00073 #if USB_CFG_HAVE_INTRIN_ENDPOINT || USB_CFG_IMPLEMENT_FN_WRITEOUT
00074 ldd x3, y+2 ;[24] endpoint number + crc
00075 rol x3 ;[26] shift in LSB of endpoint
00076 #endif
00077 cpi token, USBPID_IN ;[27]
00078 breq handleIn ;[28]
00079 cpi token, USBPID_SETUP ;[29]
00080 breq handleSetupOrOut ;[30]
00081 cpi token, USBPID_OUT ;[31]
00082 brne ignorePacket ;[32] must be ack, nak or whatever
00083 ; rjmp handleSetupOrOut ; fallthrough
00084
00085 ;Setup and Out are followed by a data packet two bit times (16 cycles) after
00086 ;the end of SE0. The sync code allows up to 40 cycles delay from the start of
00087 ;the sync pattern until the first bit is sampled. That's a total of 56 cycles.
00088 handleSetupOrOut: ;[32]
00089 #if USB_CFG_IMPLEMENT_FN_WRITEOUT
00090 andi x3, 0xf ;[32]
00091 breq storeTokenAndReturn ;[33]
00092 mov token, x3 ;[34] indicate that this is endpoint x OUT
00093 #endif
00094 storeTokenAndReturn:
00095 sts usbCurrentTok, token;[35]
00096 doReturn:
00097 POP_STANDARD ;[37] 12...16 cycles
00098 USB_LOAD_PENDING(YL) ;[49]
00099 sbrc YL, USB_INTR_PENDING_BIT;[50] check whether data is already arriving
00100 rjmp waitForJ ;[51] save the pops and pushes -- a new interrupt is already pending
00101 sofError:
00102 POP_RETI ;macro call
00103 reti
00104
00105 handleData:
00106 lds token, usbCurrentTok;[18]
00107 tst token ;[20]
00108 breq doReturn ;[21]
00109 lds x2, usbRxLen ;[22]
00110 tst x2 ;[24]
00111 brne sendNakAndReti ;[25]
00112 ; 2006-03-11: The following two lines fix a problem where the device was not
00113 ; recognized if usbPoll() was called less frequently than once every 4 ms.
00114 cpi cnt, 4 ;[26] zero sized data packets are status phase only -- ignore and ack
00115 brmi sendAckAndReti ;[27] keep rx buffer clean -- we must not NAK next SETUP
00116 sts usbRxLen, cnt ;[28] store received data, swap buffers
00117 sts usbRxToken, token ;[30]
00118 lds x2, usbInputBufOffset;[32] swap buffers
00119 ldi cnt, USB_BUFSIZE ;[34]
00120 sub cnt, x2 ;[35]
00121 sts usbInputBufOffset, cnt;[36] buffers now swapped
00122 rjmp sendAckAndReti ;[38] 40 + 17 = 57 until SOP
00123
00124 handleIn:
00125 ;We don't send any data as long as the C code has not processed the current
00126 ;input data and potentially updated the output data. That's more efficient
00127 ;in terms of code size than clearing the tx buffers when a packet is received.
00128 lds x1, usbRxLen ;[30]
00129 cpi x1, 1 ;[32] negative values are flow control, 0 means "buffer free"
00130 brge sendNakAndReti ;[33] unprocessed input packet?
00131 ldi x1, USBPID_NAK ;[34] prepare value for usbTxLen
00132 #if USB_CFG_HAVE_INTRIN_ENDPOINT
00133 andi x3, 0xf ;[35] x3 contains endpoint
00134 brne handleIn1 ;[36]
00135 #endif
00136 lds cnt, usbTxLen ;[37]
00137 sbrc cnt, 4 ;[39] all handshake tokens have bit 4 set
00138 rjmp sendCntAndReti ;[40] 42 + 16 = 58 until SOP
00139 sts usbTxLen, x1 ;[41] x1 == USBPID_NAK from above
00140 ldi YL, lo8(usbTxBuf) ;[43]
00141 ldi YH, hi8(usbTxBuf) ;[44]
00142 rjmp usbSendAndReti ;[45] 57 + 12 = 59 until SOP
00143
00144 ; Comment about when to set usbTxLen to USBPID_NAK:
00145 ; We should set it back when we receive the ACK from the host. This would
00146 ; be simple to implement: One static variable which stores whether the last
00147 ; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the
00148 ; ACK. However, we set it back immediately when we send the package,
00149 ; assuming that no error occurs and the host sends an ACK. We save one byte
00150 ; RAM this way and avoid potential problems with endless retries. The rest of
00151 ; the driver assumes error-free transfers anyway.
00152
00153 #if USB_CFG_HAVE_INTRIN_ENDPOINT
00154 handleIn1: ;[38]
00155 #if USB_CFG_HAVE_INTRIN_ENDPOINT3
00156 ; 2006-06-10 as suggested by O.Tamura: support second INTR IN / BULK IN endpoint
00157 cpi x3, USB_CFG_EP3_NUMBER;[38]
00158 breq handleIn3 ;[39]
00159 #endif
00160 lds cnt, usbTxLen1 ;[40]
00161 sbrc cnt, 4 ;[42] all handshake tokens have bit 4 set
00162 rjmp sendCntAndReti ;[43] 47 + 16 = 63 until SOP
00163 sts usbTxLen1, x1 ;[44] x1 == USBPID_NAK from above
00164 ldi YL, lo8(usbTxBuf1) ;[46]
00165 ldi YH, hi8(usbTxBuf1) ;[47]
00166 rjmp usbSendAndReti ;[48] 50 + 12 = 62 until SOP
00167 #endif
00168
00169 #if USB_CFG_HAVE_INTRIN_ENDPOINT && USB_CFG_HAVE_INTRIN_ENDPOINT3
00170 handleIn3:
00171 lds cnt, usbTxLen3 ;[41]
00172 sbrc cnt, 4 ;[43]
00173 rjmp sendCntAndReti ;[44] 49 + 16 = 65 until SOP
00174 sts usbTxLen3, x1 ;[45] x1 == USBPID_NAK from above
00175 ldi YL, lo8(usbTxBuf3) ;[47]
00176 ldi YH, hi8(usbTxBuf3) ;[48]
00177 rjmp usbSendAndReti ;[49] 51 + 12 = 63 until SOP
00178 #endif