; USB18.ASM ; Put Address into source pointer mSetSourcePointer macro Address movlw low (Address) movwf pSrc movlw high (Address) movwf pSrc + 1 endm ; Put Address into destination pointer mSetDestinationPointer macro Address movlw low (Address) movwf pDst movlw high (Address) movwf pDst + 1 endm ; Get count from first location of ROM table pointed to by pSrc mGetRomTableCount macro movff pSrc, TBLPTRL ; Set source address movff pSrc + 1, TBLPTRH clrf TBLPTRU tblrd * ; Read count movff TABLAT, wCount clrf wCount + 1 endm ; From usb9.c line 70 ;/****************************************************************************** ; * Function: void USBCheckStdRequest(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine checks the setup data packet to see if it ; * knows how to handle it ; * ; * Note: None ; *****************************************************************************/ USBCheckStdRequest movlb high 0x400 ; Point to proper bank movf SetupPkt, W ; RequestType = STANDARD? andlw 0x60 ; Mask to proper bits sublw (STANDARD) << 5 bnz USBCheckStdRequestExit ; No movlw SET_ADR ; Handle request cpfseq SetupPkt + bRequest bra USBCheckStdRequest1 movlw ADR_PENDING_STATE movwf usb_device_state bra USBStdSetSessionOwnerUSB9 ; GET_DESCRIPTOR request? USBCheckStdRequest1 movlw GET_DSC cpfseq SetupPkt + bRequest bra USBCheckStdRequest2 bra USBStdGetDscHandler ; GET_CONFIGURATION request? USBCheckStdRequest2 movlw GET_CFG cpfseq SetupPkt + bRequest bra USBCheckStdRequest3 mSetSourcePointer usb_active_cfg movlw 1 movwf wCount clrf wCount + 1 bcf usb_stat, ctrl_trf_mem ; Indicate RAM bra USBStdSetSessionOwnerUSB9 ; SET_CONFIGURATION request? USBCheckStdRequest3 movlw SET_CFG cpfseq SetupPkt + bRequest bra USBCheckStdRequest4 bra USBStdSetCfgHandler ; GET_STATUS request? USBCheckStdRequest4 movlw GET_STATUS cpfseq SetupPkt + bRequest bra USBCheckStdRequest5 bra USBStdGetStatusHandler ; CLEAR_FEATURE request? USBCheckStdRequest5 movlw CLR_FEATURE cpfseq SetupPkt + bRequest bra USBCheckStdRequest6 bra USBStdFeatureReqHandler ; SET_FEATURE request? USBCheckStdRequest6 movlw SET_FEATURE cpfseq SetupPkt + bRequest bra USBCheckStdRequest7 bra USBStdFeatureReqHandler ; GET_INTERFACE request? USBCheckStdRequest7 movlw GET_INTF cpfseq SetupPkt + bRequest bra USBCheckStdRequest8 mSetSourcePointer usb_alt_intf movf SetupPkt + bIntfID, W addwf pSrc, F movlw 1 movwf wCount clrf wCount + 1 bcf usb_stat, ctrl_trf_mem ; Indicate RAM bra USBStdSetSessionOwnerUSB9 ; SET_INTERFACE request? USBCheckStdRequest8 movlw SET_INTF cpfseq SetupPkt + bRequest return lfsr 2, usb_alt_intf movf SetupPkt + bIntfID, W movff SetupPkt + bAltID, PLUSW2 ; Branch here after decoding one of the above USB standard requests. ; Assign a value to ctrl_trf_session_owner, to prevent stalling USBStdSetSessionOwnerUSB9 movlw MUID_USB9 movwf ctrl_trf_session_owner USBCheckStdRequestExit return ; From usb9.c line 136 ;/****************************************************************************** ; * Function: void USBStdGetDscHandler(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine handles the standard GET_DESCRIPTOR request. ; * It utilizes tables dynamically looks up descriptor size. ; * This routine should never have to be modified if the tables ; * in usbdsc.c are declared correctly. ; * ; * Note: None ; *****************************************************************************/ USBStdGetDscHandler ; movlb high 0x400 ; Point to proper bank movlw 0x80 cpfseq SetupPkt + bmRequestType return movlw DSC_DEV cpfseq SetupPkt + bDscType bra USBStdGetDscHandler1 mSetSourcePointer DeviceDescriptor mGetRomTableCount ; Set wCount bsf usb_stat, ctrl_trf_mem ; Indicate ROM bra USBStdSetSessionOwnerUSB9 USBStdGetDscHandler1 movlw DSC_CFG cpfseq SetupPkt + bDscType bra USBStdGetDscHandler2 mSetSourcePointer Config1 movlw low Config1Len ; Set wCount to total length movwf TBLPTRL movlw high Config1Len movwf TBLPTRH clrf TBLPTRU tblrd *+ ; Read count low movff TABLAT, wCount tblrd *+ ; Ignore RETLW opcode tblrd *+ ; Read count high movff TABLAT, wCount + 1 bsf usb_stat, ctrl_trf_mem ; Indicate ROM bra USBStdSetSessionOwnerUSB9 USBStdGetDscHandler2 movlw DSC_STR cpfseq SetupPkt + bDscType return clrf TBLPTRU clrf TBLPTRH rlncf SetupPkt + bDscIndex, W ; Index * 2 addlw low (USB_SD_Ptr) ; Add element offset to low address movwf TBLPTRL movlw high (USB_SD_Ptr) addwfc TBLPTRH, F tblrd *+ ; Get the data to TABLAT and move pointer forward movff TABLAT, pSrc ; Get low source address tblrd * movff TABLAT, pSrc + 1 ; Get high source address mGetRomTableCount ; Set wCount bsf usb_stat, ctrl_trf_mem ; Indicate ROM bra USBStdSetSessionOwnerUSB9 ; From usb9.c line 180 ;/****************************************************************************** ; * Function: void USBStdSetCfgHandler(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine first disables all endpoints by clearing ; * UEP registers. It then configures (initializes) endpoints ; * specified in the modifiable section. ; * ; * Note: None ; *****************************************************************************/ USBStdSetCfgHandler ; movlb high 0x400 ; Point to proper bank movlw MUID_USB9 movwf ctrl_trf_session_owner lfsr 2, UEP1 ; Reset all non-EP0 UEPn registers movlw 15 USBStdSetCfgHandlerClearEPLoop clrf POSTINC2 decfsz WREG, F bra USBStdSetCfgHandlerClearEPLoop lfsr 2, usb_alt_intf ; Clear usb_alt_intf array movlw MAX_NUM_INT USBStdSetCfgHandlerClearAltLoop clrf POSTINC2 decfsz WREG, F bra USBStdSetCfgHandlerClearAltLoop movf SetupPkt + bCfgValue, W movwf usb_active_cfg bnz USBStdSetCfgHandler1 movlw ADDRESS_STATE ; SetupPkt + bCfgValue = 0 movwf usb_device_state return USBStdSetCfgHandler1 movlw CONFIGURED_STATE movwf usb_device_state #ifdef USB_USE_HID rcall HIDInitEP #endif #ifdef USB_USE_CDC rcall CDCInitEP #endif return ; From usb9.c line 224 ;/****************************************************************************** ; * Function: void USBStdGetStatusHandler(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine handles the standard GET_STATUS request ; * ; * Note: None ; *****************************************************************************/ USBStdGetStatusHandler ; movlb high 0x400 ; Point to proper bank clrf CtrlTrfData ; Initialize content clrf CtrlTrfData + 1 movf SetupPkt, W ; Recipient = RCPT_DEV? andlw 0x1f ; Mask to lower 5 bits sublw RCPT_DEV bnz USBStdGetStatusHandler1 ; No ; ; Recipient of this Setup packet was "Device": set bits to indicate power & remote wakeup ; Decoding of "Self-powered" & "Remote Wakeup" ; _byte0: bit0: Self-Powered Status [0] Bus-Powered [1] Self-Powered ; bit1: RemoteWakeup [0] Disabled [1] Enabled ; #ifdef USB_SELF_POWER bsf CtrlTrfData, 0 #endif btfsc usb_stat, RemoteWakeup bsf CtrlTrfData, 1 bra USBStdGetStatusSetSessionOwner ; USBStdGetStatusHandler1 movf SetupPkt, W ; Recipient = RCPT_INTF? andlw 0x1f ; Mask to lower 5 bits sublw RCPT_INTF bnz USBStdGetStatusHandler2 ; No ; ; Recipient of this Setup packet was "Interface": No data to update bra USBStdGetStatusSetSessionOwner ; USBStdGetStatusHandler2 movf SetupPkt, W ; Recipient = RCPT_EP? andlw 0x1f ; Mask to lower 5 bits sublw RCPT_EP bnz USBStdGetStatusHandler3 ; No ; ; Recipient of this Setup packet was "Endpoint" rcall USBCalcEPAddress ; Put endpoint buffer address in FSR2 movf INDF2, W andlw _BSTALL bz USBStdGetStatusSetSessionOwner bsf CtrlTrfData, 0 USBStdGetStatusSetSessionOwner movlw MUID_USB9 movwf ctrl_trf_session_owner USBStdGetStatusHandler3 movlw MUID_USB9 cpfseq ctrl_trf_session_owner return mSetSourcePointer CtrlTrfData movlw 2 ; Set count movwf wCount clrf wCount + 1 bcf usb_stat, ctrl_trf_mem ; Indicate RAM return ; From usb9.c line 281 ;/****************************************************************************** ; * Function: void USBStdFeatureReqHandler(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine handles the standard SET & CLEAR FEATURES ; * requests ; * ; * Note: None ; *****************************************************************************/ USBStdFeatureReqHandler ; movlb high 0x400 ; Point to proper bank movlw DEVICE_REMOTE_WAKEUP ; If Feature = DEVICE_REMOTE_WAKEUP & cpfseq SetupPkt + bFeature bra USBStdFeatureReqHandler1 movf SetupPkt, W ; Recipient = RCPT_DEV? andlw 0x1f ; Mask to lower 5 bits sublw RCPT_DEV bnz USBStdFeatureReqHandler1 ; No bsf usb_stat, RemoteWakeup ; Preset RemoteWakeup to 1 movlw SET_FEATURE ; Request = SET_FEATURE? cpfseq SetupPkt + bRequest bcf usb_stat, RemoteWakeup ; No, RemoteWakeup = 0 bra USBStdSetSessionOwnerUSB9 USBStdFeatureReqHandler1 movlw ENDPOINT_HALT ; If Feature = ENDPOINT_HALT & cpfseq SetupPkt + bFeature USBStdFeatureReqHandlerExit return movf SetupPkt, W ; Recepient = RCPT_EP & andlw 0x1f ; Mask to lower 5 bits sublw RCPT_EP bnz USBStdFeatureReqHandlerExit movf SetupPkt + bEPID, W ; EPNum != 0 andlw 0x0f ; Mask to EPNum bz USBStdFeatureReqHandlerExit rcall USBCalcEPAddress ; Put endpoint buffer address in FSR2 movlw SET_FEATURE ; Request = SET_FEATURE? cpfseq SetupPkt + bRequest bra USBStdFeatureReqHandler2 ; No movlw _USIE|_BSTALL movwf INDF2 ; Put in endpoint buffer bra USBStdSetSessionOwnerUSB9 USBStdFeatureReqHandler2 movlw _UCPU ; IN btfss SetupPkt + bEPID, EPDir ; EPDir = 1 (IN)? movlw _USIE|_DAT0|_DTSEN ; No - OUT movwf INDF2 ; Put in endpoint buffer bra USBStdSetSessionOwnerUSB9 ; Put endpoint buffer address in FSR2 (ep0Bo+(EPNum*8)+(EPDir*4)) USBCalcEPAddress lfsr 2, ep0Bo ; Point FSR2 to beginning of buffer area rlncf SetupPkt + bEPID, W ; Move endpoint direction to C rlcf SetupPkt + bEPID, W ; Endpoint number * 8 (roll in ep direction) rlncf WREG, F rlncf WREG, F addwf FSR2L, F ; Add to FSR2 (can't overflow to FSR2H) return ; From usbctrltrf.c line 78 ;/****************************************************************************** ; * Function: void USBCtrlEPService(void) ; * ; * PreCondition: USTAT is loaded with a valid endpoint address. ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: USBCtrlEPService checks for three transaction types that ; * it knows how to service and services them: ; * 1. EP0 SETUP ; * 2. EP0 OUT ; * 3. EP0 IN ; * It ignores all other types (i.e. EP1, EP2, etc.) ; * ; * Note: None ; *****************************************************************************/ USBCtrlEPService ; movlb high 0x400 ; Point to proper bank movlw EP00_OUT cpfseq USTAT bra USBCtrlEPService1 movf ep0Bo + Stat, W andlw 0x3c ; Mask to PID sublw (SETUP_TOKEN) << 2 bz USBCtrlTrfSetupHandler bra USBCtrlTrfOutHandler USBCtrlEPService1 movlw EP00_IN cpfseq USTAT return bra USBCtrlTrfInHandler ; From usbctrltrf.c line 133 ;/****************************************************************************** ; * Function: void USBCtrlTrfSetupHandler(void) ; * ; * PreCondition: SetupPkt buffer is loaded with valid USB Setup Data ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine is a task dispatcher and has 3 stages. ; * 1. It initializes the control transfer state machine. ; * 2. It calls on each of the module that may know how to ; * service the Setup Request from the host. ; * Module Example: USB9, HID, CDC, MSD, ... ; * As new classes are added, ClassReqHandler table in ; * usbdsc.c should be updated to call all available ; * class handlers. ; * 3. Once each of the modules has had a chance to check if ; * it is responsible for servicing the request, stage 3 ; * then checks direction of the transfer to determine how ; * to prepare EP0 for the control transfer. ; * Refer to USBCtrlEPServiceComplete() for more details. ; * ; * Note: Microchip USB Firmware has three different states for ; * the control transfer state machine: ; * 1. WAIT_SETUP ; * 2. CTRL_TRF_TX ; * 3. CTRL_TRF_RX ; * Refer to firmware manual to find out how one state ; * is transitioned to another. ; * ; * A Control Transfer is composed of many USB transactions. ; * When transferring data over multiple transactions, ; * it is important to keep track of data source, data ; * destination, and data count. These three parameters are ; * stored in pSrc,pDst, and wCount. A flag is used to ; * note if the data source is from ROM or RAM. ; * ; *****************************************************************************/ USBCtrlTrfSetupHandler ; movlb high 0x400 ; Point to proper bank movlw WAIT_SETUP movwf ctrl_trf_state movlw MUID_NULL ; Set owner to NULL movwf ctrl_trf_session_owner clrf wCount clrf wCount + 1 rcall USBCheckStdRequest movlw MUID_NULL cpfseq ctrl_trf_session_owner bra USBCtrlEPServiceComplete #ifdef USB_USE_HID rcall USBCheckHIDRequest #endif ; USB_USE_HID #ifdef USB_USE_CDC rcall USBCheckCDCRequest #endif ; USB_USE_CDC bra USBCtrlEPServiceComplete ; From usbctrltrf.c line 176 ;/****************************************************************************** ; * Function: void USBCtrlTrfOutHandler(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine handles an OUT transaction according to ; * which control transfer state is currently active. ; * ; * Note: Note that if the the control transfer was from ; * host to device, the session owner should be notified ; * at the end of each OUT transaction to service the ; * received data. ; * ; *****************************************************************************/ USBCtrlTrfOutHandler ; movlb high 0x400 ; Point to proper bank movlw CTRL_TRF_RX cpfseq ctrl_trf_state bra USBPrepareForNextSetupTrf rcall USBCtrlTrfRxService movlw _USIE|_DAT1|_DTSEN btfsc ep0Bo + Stat, DTS movlw _USIE|_DAT0|_DTSEN movwf ep0Bo + Stat return ; From usbctrltrf.c line 221 ;/****************************************************************************** ; * Function: void USBCtrlTrfInHandler(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine handles an IN transaction according to ; * which control transfer state is currently active. ; * ; * ; * Note: A Set Address Request must not change the acutal address ; * of the device until the completion of the control ; * transfer. The end of the control transfer for Set Address ; * Request is an IN transaction. Therefore it is necessary ; * to service this unique situation when the condition is ; * right. Macro mUSBCheckAdrPendingState is defined in ; * usb9.h and its function is to specifically service this ; * event. ; *****************************************************************************/ USBCtrlTrfInHandler ; movlb high 0x400 ; Point to proper bank movlw ADR_PENDING_STATE ; Must check if in ADR_PENDING_STATE cpfseq usb_device_state bra USBCtrlTrfInHandler1 movf SetupPkt + bDevADR, W movwf UADDR movlw ADDRESS_STATE ; If UADDR > 0 btfsc STATUS, Z movlw DEFAULT_STATE movwf usb_device_state USBCtrlTrfInHandler1 movlw CTRL_TRF_TX cpfseq ctrl_trf_state bra USBPrepareForNextSetupTrf rcall USBCtrlTrfTxService movlw _USIE|_DAT1|_DTSEN btfsc ep0Bi + Stat, DTS movlw _USIE|_DAT0|_DTSEN movwf ep0Bi + Stat return ; From usbctrltrf.c line 260 ;/****************************************************************************** ; * Function: void USBCtrlTrfTxService(void) ; * ; * PreCondition: pSrc, wCount, and usb_stat.ctrl_trf_mem are setup properly. ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine should be called from only two places. ; * One from USBCtrlEPServiceComplete() and one from ; * USBCtrlTrfInHandler(). It takes care of managing a ; * transfer over multiple USB transactions. ; * ; * Note: Copies one packet-ful of data pSrc (either ROM or RAM) to ; * EP0 IN buffer. It then updates pSrc to be ready for next ; * piece. ; * This routine works with isochronous endpoint larger than ; * 256 bytes and is shown here as an example of how to deal ; * with BC9 and BC8. In reality, a control endpoint can never ; * be larger than 64 bytes. ; *****************************************************************************/ USBCtrlTrfTxService ; movlb high 0x400 ; Point to proper bank movf wCount, W ; Preset wCount bytes to send movwf usb_temp movf wCount + 1, W movwf usb_temp + 1 sublw high EP0_BUFF_SIZE ; Make sure count does not exceed maximium length bnc USBCtrlTrfTxServiceCopy bnz USBCtrlTrfTxServiceSub movf wCount, W sublw low EP0_BUFF_SIZE bc USBCtrlTrfTxServiceSub USBCtrlTrfTxServiceCopy movlw low EP0_BUFF_SIZE ; Send buffer full of bytes movwf usb_temp movlw high EP0_BUFF_SIZE movwf usb_temp + 1 USBCtrlTrfTxServiceSub movf usb_temp, W ; Subtract actual bytes to be sent from the buffer movwf ep0Bi + Cnt ; Save low number of bytes to send while we're here subwf wCount, F movf usb_temp + 1, W subwfb wCount + 1, F movf ep0Bi + Stat, W ; Get full Stat byte andlw 0xfc ; Clear bottom bits iorwf usb_temp + 1, W ; Put in high bits of bytes to send movwf ep0Bi + Stat ; Save it out lfsr 2, CtrlTrfData ; Set destination pointer movf usb_temp + 1, W ; Check high byte for 0 bnz USBCtrlTrfTxServiceRomRam ; High byte not 0, must have something to do movf usb_temp, W ; Check low byte for 0 bz USBCtrlTrfTxServiceExit ; If both 0 then nothing to send this time USBCtrlTrfTxServiceRomRam btfss usb_stat, ctrl_trf_mem ; ROM or RAM? bra USBCtrlTrfTxServiceRam ; RAM movff pSrc, TBLPTRL ; Move source pointer to TBLPTR movff pSrc + 1, TBLPTRH clrf TBLPTRU USBCtrlTrfTxServiceRomLoop tblrd *+ movff TABLAT, POSTINC2 ; Copy one buffer to the other tblrd *+ ; Skip high location decf usb_temp, F ; Count down number of bytes bnz USBCtrlTrfTxServiceRomLoop decf usb_temp + 1, F bc USBCtrlTrfTxServiceRomLoop movff TBLPTRL, pSrc ; Update source pointer movff TBLPTRH, pSrc + 1 return USBCtrlTrfTxServiceRam movff pSrc, FSR1L ; Move source pointer to FSR1 movff pSrc + 1, FSR1H USBCtrlTrfTxServiceRamLoop movff POSTINC1, POSTINC2 ; Copy one buffer to the other decf usb_temp, F ; Count down number of bytes bnz USBCtrlTrfTxServiceRamLoop decf usb_temp + 1, F bc USBCtrlTrfTxServiceRamLoop movff FSR1L, pSrc ; Update source pointer movff FSR1H, pSrc + 1 USBCtrlTrfTxServiceExit return ; From usbctrltrf.c line 330 ;/****************************************************************************** ; * Function: void USBCtrlTrfRxService(void) ; * ; * PreCondition: pDst and wCount are setup properly. ; * pSrc is always &CtrlTrfData ; * usb_stat.ctrl_trf_mem is always _RAM. ; * wCount should be set to 0 at the start of each control ; * transfer. ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: Transfers bytes received, at EP0 OUT buffer CtrlTrfData, ; * to user's buffer pointed by pDst. ; * This routine only knows how to handle raw byte data. ; * HIDmaker handles transferring and unpacking by a callback ; * function in the generated main program, called from here. ; * ; * Note: None ; *****************************************************************************/ USBCtrlTrfRxService ; movlb high 0x400 ; Point to proper bank movf ep0Bo + Cnt, W ; Get low number of bytes to read movwf usb_temp ; usb_temp & usb_temp + 1 are bytes to read addwf wCount, F ; Accumulate total number of bytes read movf ep0Bo + Stat, W ; Get high bits to read andlw 0x03 ; Mask to the count movwf usb_temp + 1 ; Save to high byte of bytes to read addwfc wCount + 1, F ; Add overflow from low byte (C) and high byte to total number lfsr 1, CtrlTrfData ; Point FSR1 to source movff pDst, FSR2L ; Move destination pointer to FSR2 movff pDst + 1, FSR2H movf usb_temp + 1, W ; Check high byte for 0 bnz USBCtrlTrfRxServiceLoop ; High byte not 0, must have something to do movf usb_temp, W ; Check low byte for 0 bz USBCtrlTrfRxServiceExit ; If both 0 then nothing to send this time USBCtrlTrfRxServiceLoop movff POSTINC1, POSTINC2 ; Copy one buffer to the other decf usb_temp, F ; Count down number of bytes bnz USBCtrlTrfRxServiceLoop decf usb_temp + 1, F bc USBCtrlTrfRxServiceLoop movff FSR2L, pDst ; Update destination pointer movff FSR2H, pDst + 1 USBCtrlTrfRxServiceExit return ; From usbctrltrf.c line 382 ;/****************************************************************************** ; * Function: void USBCtrlEPServiceComplete(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine wrap up the ramaining tasks in servicing ; * a Setup Request. Its main task is to set the endpoint ; * controls appropriately for a given situation. See code ; * below. ; * There are three main scenarios: ; * a) There was no handler for the Request, in this case ; * a STALL should be sent out. ; * b) The host has requested a read control transfer, ; * endpoints are required to be setup in a specific way. ; * c) The host has requested a write control transfer, or ; * a control data stage is not required, endpoints are ; * required to be setup in a specific way. ; * ; * Packet processing is resumed by clearing PKTDIS bit. ; * ; * Note: None ; *****************************************************************************/ USBCtrlEPServiceComplete ; movlb high 0x400 ; Point to proper bank movlw MUID_NULL cpfseq ctrl_trf_session_owner bra USBCtrlEPServiceComplete1 ; ; No handlers claimed ownership of this Setup packet. ; If no one knows how to service this request then stall. ; Must also prepare EP0 to receive the next SETUP transaction. movlw EP0_BUFF_SIZE movwf ep0Bo + Cnt movlw low SetupPkt movwf ep0Bo + ADRL movlw high SetupPkt movwf ep0Bo + ADRH movlw _USIE|_BSTALL movwf ep0Bo + Stat ; movlw _USIE|_BSTALL movwf ep0Bi + Stat bra USBCtrlEPServiceCompleteExit ; ; A module has claimed ownership of the control transfer session. USBCtrlEPServiceComplete1 btfss SetupPkt, DataDir bra USBCtrlEPServiceComplete2 movf wCount + 1, W ; Make sure count does not exceed max length requested by Host subwf SetupPkt + wLength + 1, W bnc USBCtrlEPServiceCompleteCopy bnz USBCtrlEPServiceComplete11 movf wCount, W subwf SetupPkt + wLength, W bc USBCtrlEPServiceComplete11 USBCtrlEPServiceCompleteCopy movff SetupPkt + wLength, wCount ; Set count to maximum movff SetupPkt + wLength + 1, wCount + 1 ; ; Setup packet's data direction is "Device to Host" USBCtrlEPServiceComplete11 rcall USBCtrlTrfTxService ; Actually copy the data to EP0 IN buffer movlw CTRL_TRF_TX movwf ctrl_trf_state ; Control Read: ; ... | ; 1. Prepare OUT EP to respond to early termination ; ; NOTE: ; If something went wrong during the control transfer, ; the last status stage may not be sent by the host. ; When this happens, two different things could happen ; depending on the host. ; a) The host could send out a RESET. ; b) The host could send out a new SETUP transaction ; without sending a RESET first. ; To properly handle case (b), the OUT EP must be setup ; to receive either a zero length OUT transaction, or a ; new SETUP transaction. ; ; Since the SETUP transaction requires the DTS bit to be ; DAT0 while the zero length OUT status requires the DTS ; bit to be DAT1, the DTS bit check by the hardware should ; be disabled. This way the SIE could accept either of ; the two transactions. ; ; Furthermore, the Cnt byte should be set to prepare for ; the SETUP data (8-byte or more), and the buffer address ; should be pointed to SetupPkt. movlw EP0_BUFF_SIZE movwf ep0Bo + Cnt movlw low SetupPkt movwf ep0Bo + ADRL movlw high SetupPkt movwf ep0Bo + ADRH movlw _USIE ; Note: DTSEN is 0! movwf ep0Bo + Stat ; 2. Prepare IN EP to transfer data, Cnt should have ; been initialized by responsible request owner. movlw low CtrlTrfData movwf ep0Bi + ADRL movlw high CtrlTrfData movwf ep0Bi + ADRH movlw _USIE|_DAT1|_DTSEN movwf ep0Bi + Stat bra USBCtrlEPServiceCompleteExit ; ; Setup packet's data direction is "Host to Device" USBCtrlEPServiceComplete2 movlw CTRL_TRF_RX movwf ctrl_trf_state ; Control Write: ; ... | ; ; 1. Prepare IN EP to respond to early termination ; ; This is the same as a Zero Length Packet Response ; for control transfer without a data stage clrf ep0Bi + Cnt movlw _USIE|_DAT1|_DTSEN movwf ep0Bi + Stat ; 2. Prepare OUT EP to receive data. movlw EP0_BUFF_SIZE movwf ep0Bo + Cnt movlw low CtrlTrfData movwf ep0Bo + ADRL movlw high CtrlTrfData movwf ep0Bo + ADRH movlw _USIE|_DAT1|_DTSEN movwf ep0Bo + Stat ; USBCtrlEPServiceCompleteExit ; PKTDIS bit is set when a Setup Transaction is received. ; Clear to resume packet processing. bcf UCON, PKTDIS return ; From usbctrltrf.c line 490 ;/****************************************************************************** ; * Function: void USBPrepareForNextSetupTrf(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: The routine forces EP0 OUT to be ready for a new Setup ; * transaction, and forces EP0 IN to be owned by CPU. ; * ; * Note: None ; *****************************************************************************/ USBPrepareForNextSetupTrf ; movlb high 0x400 ; Point to proper bank movlw WAIT_SETUP movwf ctrl_trf_state movlw EP0_BUFF_SIZE movwf ep0Bo + Cnt movlw low SetupPkt movwf ep0Bo + ADRL movlw high SetupPkt movwf ep0Bo + ADRH movlw _USIE|_DAT0|_DTSEN ; EP0 buff dsc init movwf ep0Bo + Stat movlw _UCPU ; EP0 IN buffer initialization movwf ep0Bi + Stat return ; From usbdrv.c line ??? ;/****************************************************************************** ; * Function: void InitializeUSBDriver(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine initializes variables used by the USB library ; * routines. ; * ; * Note: None ; *****************************************************************************/ InitializeUSBDriver movlb high 0x400 ; Point to proper bank movlw UCFG_VAL movwf UCFG movlw DETACHED_STATE movwf usb_device_state clrf usb_stat clrf usb_active_cfg #ifdef USB_USE_HID rcall HIDInitEP #endif #ifdef USB_USE_CDC rcall CDCInitEP #endif return ; From usbdrv.c line 76 ;/****************************************************************************** ; * Function: void USBCheckBusStatus(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine enables/disables the USB module by monitoring ; * the USB power signal. ; * ; * Note: None ; *****************************************************************************/ USBCheckBusStatus movlb high 0x400 ; Point to proper bank ; Bus Attachment & Detachment Detection ; usb_bus_sense is an i/o pin defined in io_cfg.h #ifdef USE_USB_BUS_SENSE_IO btfss usb_bus_sense ; Is USB bus attached? bra USBCheckBusStatusDetached ; No #endif btfss UCON, USBEN ; Is the module off? rcall USBModuleEnable ; Is off, enable it #ifdef USE_USB_BUS_SENSE_IO bra USBCheckBusStatus1 USBCheckBusStatusDetached btfsc UCON, USBEN ; Is the module on? rcall USBModuleDisable ; Is on, disable it #endif ; ; After enabling the USB module, it takes some time for the voltage ; on the D+ or D- line to rise high enough to get out of the SE0 condition. ; The USB Reset interrupt should not be unmasked until the SE0 condition is ; cleared. This helps preventing the firmware from misinterpreting this ; unique event as a USB bus reset from the USB host. USBCheckBusStatus1 movlw ATTACHED_STATE cpfseq usb_device_state return btfsc UCON, SE0 return clrf UIR ; Clear all USB interrupts clrf UIE ; Mask all USB interrupts bsf UIE, URSTIE ; Unmask RESET interrupt bsf UIE, IDLEIE ; Unmask IDLE interrupt movlw POWERED_STATE movwf usb_device_state return ; From usbdrv.c line 135 USBModuleEnable ; movlb high 0x400 ; Point to proper bank clrf UCON clrf UIE ; Mask all USB interrupts bsf UCON, USBEN ; Enable module & attach to bus movlw ATTACHED_STATE movwf usb_device_state return ; From usbdrv.c line 192 USBSoftDetach ; From usbdrv.c line 161 USBModuleDisable movlb high 0x400 ; Point to proper bank clrf UCON ; Disable module & detach from bus clrf UIE ; Mask all USB interrupts movlw DETACHED_STATE movwf usb_device_state return ; From usbdrv.c line 215 ;/****************************************************************************** ; * Function: void USBDriverService(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine is the heart of this firmware. It manages ; * all USB interrupts. ; * ; * Note: Device state transitions through the following stages: ; * DETACHED -> ATTACHED -> POWERED -> DEFAULT -> ; * ADDRESS_PENDING -> ADDRESSED -> CONFIGURED -> READY ; *****************************************************************************/ USBDriverService movlb high 0x400 ; Point to proper bank movlw DETACHED_STATE subwf usb_device_state, W bz USBDriverServiceExit ; Pointless to continue servicing ; if USB cable is not even attached. ; ; Task A: Service USB Activity Interrupt btfss UIR, ACTVIF bra USBDriverService1 btfsc UIE, ACTVIE rcall USBWakeFromSuspend ; USBDriverService1 btfsc UCON, SUSPND ; Are we suspended? return ; Pointless to continue servicing if the device is in suspend mode. ; ; Task B: Service USB Bus Reset Interrupt. ; When bus reset is received during suspend, ACTVIF will be set first, ; once the UCONbits.SUSPND is clear, then the URSTIF bit will be asserted. ; This is why URSTIF is checked after ACTVIF. ; ; The USB reset flag is masked when the USB state is in ; DETACHED_STATE or ATTACHED_STATE, and therefore cannot ; cause a USB reset event during these two states. btfss UIR, URSTIF ; USB Bus Reset Interrupt? bra USBDriverService2 btfsc UIE, URSTIE rcall USBProtocolResetHandler ; ; Task C: Check & service other USB interrupts USBDriverService2 btfss UIR, IDLEIF bra USBDriverService3 btfsc UIE, IDLEIE rcall USBSuspend USBDriverService3 btfss UIR, SOFIF bra USBDriverService4 btfsc UIE, SOFIE rcall USB_SOF_Handler USBDriverService4 btfss UIR, STALLIF bra USBDriverService5 btfsc UIE, STALLIE rcall USBStallHandler USBDriverService5 btfss UIR, UERRIF bra USBDriverService6 btfsc UIE, UERRIE rcall USBErrorHandler ; ; Pointless to continue servicing if the host has not sent a bus reset. ; Once bus reset is received, the device transitions into the DEFAULT ; * state and is ready for communication. USBDriverService6 movlw DEFAULT_STATE subwf usb_device_state, W bnc USBDriverServiceExit ; ; Task D: Servicing USB Transaction Complete Interrupt btfss UIR, TRNIF bra USBDriverServiceExit btfss UIE, TRNIE bra USBDriverServiceExit ; ; USBCtrlEPService only services transactions over EP0. ; It ignores all other EP transactions. rcall USBCtrlEPService ; Other EPs can be serviced later by responsible device class firmware. ; Each device driver knows when an OUT or IN transaction is ready by ; checking the buffer ownership bit. ; An OUT EP should always be owned by SIE until the data is ready. ; An IN EP should always be owned by CPU until the data is ready. ; ; Because of this logic, it is not necessary to save the USTAT value ; of non-EP0 transactions. bcf UIR, TRNIF USBDriverServiceExit return ; From usbdrv.c line 301 ;/****************************************************************************** ; * Function: void USBSuspend(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: ; * ; * Note: None ; *****************************************************************************/ USBSuspend ; NOTE: Do not clear UIRbits.ACTVIF here! ; Reason: ; ACTVIF is only generated once an IDLEIF has been generated. ; This is a 1:1 ratio interrupt generation. ; For every IDLEIF, there will be only one ACTVIF regardless of ; the number of subsequent bus transitions. ; ; If the ACTIF is cleared here, a problem could occur when: ; [ IDLE ][bus activity -> ; <--- 3 ms -----> ^ ; ^ ACTVIF=1 ; IDLEIF=1 ; # # # # (#=Program polling flags) ; ^ ; This polling loop will see both ; IDLEIF=1 and ACTVIF=1. ; However, the program services IDLEIF first ; because ACTIVIE=0. ; If this routine clears the only ACTIVIF, ; then it can never get out of the suspend ; mode. bsf UIE, ACTVIE ; Enable bus activity interrupt bcf UIR, IDLEIF bsf UCON, SUSPND ; Put USB module in power conserve ; At this point the PIC can go into sleep,idle, or ; switch to a slower clock, etc. return ; From usbdrv.c line 353 ;/****************************************************************************** ; * Function: void USBWakeFromSuspend(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: ; * ; * Note: None ; *****************************************************************************/ USBWakeFromSuspend ; If using clock switching, this is the place to restore the ; original clock frequency. bcf UCON, SUSPND bcf UIE, ACTVIE bcf UIR, ACTVIF return ; From usbdrv.c line 402 ;/****************************************************************************** ; * Function: void USBRemoteWakeup(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This function should be called by user when the device ; * is waken up by an external stimulus other than ACTIVIF. ; * Please read the note below to understand the limitations. ; * ; * Note: The modifiable section in this routine should be changed ; * to meet the application needs. Current implementation ; * temporary blocks other functions from executing for a ; * period of 1-13 ms depending on the core frequency. ; * ; * According to USB 2.0 specification section 7.1.7.7, ; * "The remote wakeup device must hold the resume signaling ; * for at lest 1 ms but for no more than 15 ms." ; * The idea here is to use a delay counter loop, using a ; * common value that would work over a wide range of core ; * frequencies. ; * That value selected is 1800. See table below: ; * ========================================================== ; * Core Freq(MHz) MIP RESUME Signal Period (ms) ; * ========================================================== ; * 48 12 1.05 ; * 4 1 12.6 ; * ========================================================== ; * * These timing could be incorrect when using code ; * optimization or extended instruction mode, ; * or when having other interrupts enabled. ; * Make sure to verify using the MPLAB SIM's Stopwatch ; *****************************************************************************/ USBRemoteWakeup movlb high 0x400 ; Point to proper bank btfss usb_stat, RemoteWakeup ; Check if RemoteWakeup function has been enabled by the host. return ; No rcall USBWakeFromSuspend ; Unsuspend USB modue bsf UCON, RESUME ; Start RESUME signaling movlw 0x10 ; Set RESUME line for 1-13 ms movwf FSR2H ; Using FSR2 as temp clrf FSR2L USBRemoteWakeupLoop decfsz FSR2L, F bra USBRemoteWakeupLoop decfsz FSR2H, F bra USBRemoteWakeupLoop bcf UCON, RESUME return ; From usbdrv.c line 443 ;/****************************************************************************** ; * Function: void USB_SOF_Handler(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: The USB host sends out a SOF packet to full-speed devices ; * every 1 ms. This interrupt may be useful for isochronous ; * pipes. End designers should implement callback routine ; * as necessary. ; * ; * Note: None ; *****************************************************************************/ USB_SOF_Handler ; Callback routine here bcf UIR, SOFIF return ; From usbdrv.c line 486 ;/****************************************************************************** ; * Function: void USBStallHandler(void) ; * ; * PreCondition: A STALL packet is sent to the host by the SIE. ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: The STALLIF is set anytime the SIE sends out a STALL ; * packet regardless of which endpoint causes it. ; * A Setup transaction overrides the STALL function. A stalled ; * endpoint stops stalling once it receives a setup packet. ; * In this case, the SIE will accepts the Setup packet and ; * set the TRNIF flag to notify the firmware. STALL function ; * for that particular endpoint pipe will be automatically ; * disabled (direction specific). ; * ; * There are a few reasons for an endpoint to be stalled. ; * 1. When a non-supported USB request is received. ; * Example: GET_DESCRIPTOR(DEVICE_QUALIFIER) ; * 2. When an endpoint is currently halted. ; * 3. When the device class specifies that an endpoint must ; * stall in response to a specific event. ; * Example: Mass Storage Device Class ; * If the CBW is not valid, the device shall ; * STALL the Bulk-In pipe. ; * See USB Mass Storage Class Bulk-only Transport ; * Specification for more details. ; * ; * Note: UEPn.EPSTALL can be scanned to see which endpoint causes ; * the stall event. ; * If ; *****************************************************************************/ USBStallHandler ; Does not really have to do anything here, ; even for the control endpoint. ; All BDs of Endpoint 0 are owned by SIE right now, ; but once a Setup Transaction is received, the ownership ; for EP0_OUT will be returned to CPU. ; When the Setup Transaction is serviced, the ownership ; for EP0_IN will then be forced back to CPU by firmware. ; ; NOTE: Above description is not quite true at this point. ; It seems the SIE never returns the UOWN bit to CPU, ; and a TRNIF is never generated upon successful ; reception of a SETUP transaction. ; Firmware work-around is implemented below. ; btfsc UEP0, EPSTALL rcall USBPrepareForNextSetupTrf ; Firmware Work-Around bcf UEP0, EPSTALL bcf UIR, STALLIF return ; From usbdrv.c line 528 ;/****************************************************************************** ; * Function: void USBErrorHandler(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: The purpose of this interrupt is mainly for debugging ; * during development. Check UEIR to see which error causes ; * the interrupt. ; * ; * Note: None ; *****************************************************************************/ USBErrorHandler bcf UIR, UERRIF return ; From usbdrv.c line 555 ;/****************************************************************************** ; * Function: void USBProtocolResetHandler(void) ; * ; * PreCondition: A USB bus reset is received from the host. ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: Currently, this routine flushes any pending USB ; * transactions. It empties out the USTAT FIFO. This action ; * might not be desirable in some applications. ; * ; * Overview: Once a USB bus reset is received from the host, this ; * routine should be called. It resets the device address to ; * zero, disables all non-EP0 endpoints, initializes EP0 to ; * be ready for default communication, clears all USB ; * interrupt flags, unmasks applicable USB interrupts, and ; * reinitializes internal state-machine variables. ; * ; * Note: None ; *****************************************************************************/ USBProtocolResetHandler ; movlb high 0x400 ; Point to proper bank clrf UEIR ; Clear all USB error flags clrf UIR ; Clears all USB interrupts movlw 0x9f ; Unmask all USB error interrupts movwf UEIE movlw 0x7b ; Enable all interrupts except ACTVIE movwf UIE clrf UADDR ; Reset to default address lfsr 2, UEP1 ; Reset all non-EP0 UEPn registers movlw 15 USBProtocolResetHandlerClearLoop clrf POSTINC2 decfsz WREG, F bra USBProtocolResetHandlerClearLoop movlw EP_CTRL|HSHK_EN ; Init EP0 as a Ctrl EP movwf UEP0 btfsc UIR, TRNIF ; Flush any pending transactions USBProtocolResetHandlerFlushLoop bcf UIR, TRNIF btfsc UIR, TRNIF bra USBProtocolResetHandlerFlushLoop bcf UCON, PKTDIS ; Make sure packet processing is enabled rcall USBPrepareForNextSetupTrf bcf usb_stat, RemoteWakeup ; Default status flag to disable clrf usb_active_cfg ; Clear active configuration movlw DEFAULT_STATE movwf usb_device_state return #ifdef USB_USE_HID ; From hid.c line 72 ;/****************************************************************************** ; * Function: void USBCheckHIDRequest(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine checks the setup data packet to see if it ; * knows how to handle it ; * ; * Note: None ; *****************************************************************************/ USBCheckHIDRequest movlb high 0x400 ; Point to proper bank movf SetupPkt, W ; Recipient = RCPT_INTF? andlw 0x1f ; Mask to lower 5 bits sublw RCPT_INTF bnz USBCheckHIDRequestExit ; No movlw HID_INTF_ID ; IntfID = HID_INTF_ID? cpfseq SetupPkt + bIntfID USBCheckHIDRequestExit return ; No ; ; There are two standard requests that hid.c may support. ; 1. GET_DSC(DSC_HID,DSC_RPT,DSC_PHY); ; 2. SET_DSC(DSC_HID,DSC_RPT,DSC_PHY); ; movlw GET_DSC ; Request = GET_DSC? cpfseq SetupPkt + bRequest bra USBCheckHIDRequestClass ; No movlw DSC_HID ; DscType = DSC_HID? cpfseq SetupPkt + bDscType bra USBCheckHIDRequest1 ; No mSetSourcePointer HIDDescriptor1 mGetRomTableCount ; Set wCount bsf usb_stat, ctrl_trf_mem ; Indicate ROM bra USBHIDSetSessionOwner USBCheckHIDRequest1 movlw DSC_RPT ; DscType = DSC_RPT? cpfseq SetupPkt + bDscType bra USBCheckHIDRequest2 ; No mSetSourcePointer ReportDescriptor1 movlw low (ReportDescriptor1Len) ; Set wCount movwf TBLPTRL movlw high (ReportDescriptor1Len) movwf TBLPTRH clrf TBLPTRU tblrd *+ ; Read count low movff TABLAT, wCount tblrd *+ ; Skip next tblrd * ; Read count high movff TABLAT, wCount + 1 bsf usb_stat, ctrl_trf_mem ; Indicate ROM bra USBHIDSetSessionOwner USBCheckHIDRequest2 ; movlw DSC_PHY ; DscType = DSC_PHY? ; cpfseq SetupPkt + bDscType ; return ; No USBCheckHIDRequestClass movf SetupPkt, W ; RequestType = CLASS? andlw 0x60 ; Mask to proper bits sublw (CLASS) << 5 bnz USBCheckHIDRequestExit ; No ; movlw GET_REPORT ; Request = GET_REPORT? ; subwf SetupPkt + bRequest, W ; bz HIDGetReportHandler ; Yes ; movlw SET_REPORT ; Request = SET_REPORT? ; subwf SetupPkt + bRequest, W ; bz HIDSetReportHandler ; Yes movlw GET_IDLE ; Request = GET_IDLE? cpfseq SetupPkt + bRequest bra USBCheckHIDRequestClass1 ; No mSetSourcePointer idle_rate movlw 1 movwf wCount clrf wCount + 1 bcf usb_stat, ctrl_trf_mem ; Indicate RAM bra USBHIDSetSessionOwner USBCheckHIDRequestClass1 movlw SET_IDLE ; Request = SET_IDLE? cpfseq SetupPkt + bRequest bra USBCheckHIDRequestClass2 ; No movff SetupPkt + wValue + 1, idle_rate bra USBHIDSetSessionOwner USBCheckHIDRequestClass2 movlw GET_PROTOCOL ; Request = GET_PROTOCOL? cpfseq SetupPkt + bRequest bra USBCheckHIDRequestClass3 ; No mSetSourcePointer active_protocol movlw 1 movwf wCount clrf wCount + 1 bcf usb_stat, ctrl_trf_mem ; Indicate RAM bra USBHIDSetSessionOwner USBCheckHIDRequestClass3 movlw SET_PROTOCOL ; Request = SET_PROTOCOL? cpfseq SetupPkt + bRequest return ; No movff SetupPkt + wValue, active_protocol USBHIDSetSessionOwner movlw MUID_HID movwf ctrl_trf_session_owner return ; From hid.c line 158 ;/****************************************************************************** ; * Function: void HIDInitEP(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: HIDInitEP initializes HID endpoints, buffer descriptors, ; * internal state-machine, and variables. ; * It should be called after the USB host has sent out a ; * SET_CONFIGURATION request. ; * See USBStdSetCfgHandler() in usb9.c for examples. ; * ; * Note: None ; *****************************************************************************/ HIDInitEP movlw 1 ; Endpoint 1 Out movwf FSR0L lfsr 1, hid_report_out ; FSR1 = endpoint buffer address movlw HID_INT_OUT_EP_SIZE ; W = endpoint size rcall InitEPOut ; Inititalize the endpoint movlw 1 ; Endpoint 1 In movwf FSR0L lfsr 1, hid_report_in ; FSR1 = endpoint buffer address movlw HID_INT_IN_EP_SIZE ; W = endpoint size bra InitEPIn ; Inititalize the endpoint #endif ; USB_USE_HID #ifdef USB_USE_CDC ;/****************************************************************************** ; * Function: void USBCheckCDCRequest(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: This routine checks the setup data packet to see if it ; * knows how to handle it ; * ; * Note: None ; *****************************************************************************/ USBCheckCDCRequest ; /* ; * If request recipient is not an interface then return ; */ movlb high 0x400 ; Point to proper bank movf SetupPkt, W ; Recipient = RCPT_INTF? andlw 0x1f ; Mask to lower 5 bits sublw RCPT_INTF bnz USBCheckCDCRequestExit ; No ; /* ; * If request type is not class-specific then return ; */ movf SetupPkt, W ; RequestType = CLASS? andlw 0x60 ; Mask to proper bits sublw (CLASS) << 5 bnz USBCheckCDCRequestExit ; No ; /* ; * Interface ID must match interface numbers associated with ; * CDC class, else return ; */ movlw CDC_COMM_INTF_ID ; IntfID = CDC_COMM_INTF_ID? subwf SetupPkt + bIntfID, W bz USBCheckCDCRequest1 ; Yes movlw CDC_DATA_INTF_ID ; IntfID = CDC_DATA_INTF_ID? cpfseq SetupPkt + bIntfID USBCheckCDCRequestExit return ; No USBCheckCDCRequest1 movlw SEND_ENCAPSULATED_COMMAND ; Request = SEND_ENCAPSULATED_COMMAND? cpfseq SetupPkt + bRequest bra USBCheckCDCRequest2 ; No mSetSourcePointer dummy_encapsulated_cmd_response bcf usb_stat, ctrl_trf_mem ; Indicate RAM movlw dummy_length movwf wCount clrf wCount + 1 bra USBCDCSetSessionOwner USBCheckCDCRequest2 movlw GET_ENCAPSULATED_RESPONSE ; Request = GET_ENCAPSULATED_RESPONSE? cpfseq SetupPkt + bRequest bra USBCheckCDCRequest3 ; No ; // Populate dummy_encapsulated_cmd_response first. mSetDestinationPointer dummy_encapsulated_cmd_response bra USBCDCSetSessionOwner USBCheckCDCRequest3 movlw SET_COMM_FEATURE ; Request = SET_COMM_FEATURE? cpfseq SetupPkt + bRequest bra USBCheckCDCRequest4 ; No return ; Optional USBCheckCDCRequest4 movlw GET_COMM_FEATURE ; Request = GET_COMM_FEATURE? cpfseq SetupPkt + bRequest bra USBCheckCDCRequest5 ; No return ; Optional USBCheckCDCRequest5 movlw CLEAR_COMM_FEATURE ; Request = CLEAR_COMM_FEATURE? cpfseq SetupPkt + bRequest bra USBCheckCDCRequest6 ; No return ; Optional USBCheckCDCRequest6 movlw SET_LINE_CODING ; Request = SET_LINE_CODING? cpfseq SetupPkt + bRequest bra USBCheckCDCRequest7 ; No mSetDestinationPointer line_coding bra USBCDCSetSessionOwner USBCheckCDCRequest7 movlw GET_LINE_CODING ; Request = GET_LINE_CODING? cpfseq SetupPkt + bRequest bra USBCheckCDCRequest8 ; No ; Abstract line coding information movlw low 115200 ; baud rate movwf line_coding + dwDTERate movlw high 115200 movwf line_coding + dwDTERate + 1 movlw upper 115200 movwf line_coding + dwDTERate + 2 clrf line_coding + dwDTERate + 3 clrf line_coding + bCharFormat ; 1 stop bit clrf line_coding + bParityType ; None movlw 8 movwf line_coding + bDataBits ; 5,6,7,8, or 16 mSetSourcePointer line_coding bcf usb_stat, ctrl_trf_mem ; Indicate RAM movlw LINE_CODING_LENGTH movwf wCount clrf wCount + 1 bra USBCDCSetSessionOwner USBCheckCDCRequest8 movlw SET_CONTROL_LINE_STATE ; Request = SET_CONTROL_LINE_STATE? cpfseq SetupPkt + bRequest bra USBCheckCDCRequest9 ; No movff SetupPkt + wValue, control_signal_bitmap bra USBCDCSetSessionOwner USBCheckCDCRequest9 movlw SEND_BREAK ; Request = SEND_BREAK? cpfseq SetupPkt + bRequest bra USBCheckCDCRequest10 ; No return ; Optional USBCheckCDCRequest10 return ; Default USBCDCSetSessionOwner movlw MUID_CDC movwf ctrl_trf_session_owner return ;/****************************************************************************** ; * Function: void CDCInitEP(void) ; * ; * PreCondition: None ; * ; * Input: None ; * ; * Output: None ; * ; * Side Effects: None ; * ; * Overview: CDCInitEP initializes CDC endpoints, buffer descriptors, ; * internal state-machine, and variables. ; * It should be called after the USB host has sent out a ; * SET_CONFIGURATION request. ; * See USBStdSetCfgHandler() in usb9.c for examples. ; * ; * Note: None ; *****************************************************************************/ CDCInitEP movlw 2 ; Endpoint 2 In movwf FSR0L lfsr 1, cdc_notice ; FSR1 = endpoint buffer address movlw CDC_INT_EP_SIZE ; W = endpoint size rcall InitEPIn ; Inititalize the endpoint movlw 3 ; Endpoint 3 movwf FSR0L lfsr 1, cdc_data_rx ; FSR1 = endpoint buffer address movlw CDC_BULK_OUT_EP_SIZE ; W = endpoint size rcall InitEPOut ; Inititalize the endpoint movlw 3 ; Endpoint 3 In movwf FSR0L lfsr 1, cdc_data_tx ; FSR1 = endpoint buffer address movlw CDC_BULK_IN_EP_SIZE ; W = endpoint size bra InitEPIn ; Inititalize the endpoint #endif ; USB_USE_CDC ; Generic code for use by all the classes ; InitEPIn ; Generic initialize In endpoint ; Input: ; FSR0L is endpoint number ; FSR1 is endpoint buffer address ; W is endpoint buffer size ; Returns: ; Nada ; Uses ; FSR0 is BDT pointer ; FSR1 is endpoint buffer pointer ; FSR2 is endpoint table pointer InitEPIn ; Save maximum count at front of endpoint buffer and move buffer pointer up (no need to put in Cnt for In) movwf POSTINC1 ; Store maximum count at front of endpoint buffer and move up pointer ; Point FSR2 to endpoint table lfsr 2, UEP0 movf FSR0L, W ; Add in endpoint number addwf FSR2L, F ; Enable In endpoint movlw EP_IN|HSHK_EN ; Enable In pipe iorwf INDF2, F ; Point FSR0 to endpoint BDT rlncf FSR0L, W ; Endpoint number * 8 rlncf WREG, F rlncf WREG, F lfsr 0, ep0Bi ; Point FSR0 to beginning of BDT area addwf FSR0L, F ; Add endpoint offset to FSR0 (can't overflow to FSR0H) ; Set endpoint buffer address from FSR1 movlw ADRL ; Point to ADRL movff FSR1L, PLUSW0 movlw ADRH ; Point to ADRH movff FSR1H, PLUSW0 ; Set endpoint status movlw _UCPU|_DAT1 ; Set transmit status movwf INDF0 ; Set Stat return ; InitEPOut ; Generic initialize Out endpoint ; Input: ; FSR0L is endpoint number ; FSR1 is endpoint buffer address ; W is endpoint buffer size ; Returns: ; Nada ; Uses ; FSR0 is BDT pointer ; FSR1 is endpoint buffer pointer ; FSR2 is endpoint table pointer InitEPOut ; Save maximum count at front of endpoint buffer and move buffer pointer up movwf POSTINC1 ; Store maximum count at front of endpoint buffer and move up pointer ; Point FSR2 to endpoint table lfsr 2, UEP0 movf FSR0L, W ; Add in endpoint number addwf FSR2L, F ; Enable Out endpoint movlw EP_OUT|HSHK_EN ; Enable Out pipe iorwf INDF2, F ; Point FSR0 to endpoint BDT rlncf FSR0L, W ; Endpoint number * 8 rlncf WREG, F rlncf WREG, F lfsr 0, ep0Bo ; Point FSR0 to beginning of BDT area addwf FSR0L, F ; Add endpoint offset to FSR0 (can't overflow to FSR0H) ; Set endpoint buffer address from FSR1 + 1 movlw ADRL ; Point to ADRL movff FSR1L, PLUSW0 movlw ADRH ; Point to ADRH movff FSR1H, PLUSW0 ; Set Cnt to maximum count movf POSTDEC1, W ; Back up endpoint buffer pointer (no PREDEC1!) incf FSR0L, F ; Point to Cnt movff INDF1, POSTDEC0 ; Set maximum count and point back to Stat ; Set endpoint status movlw _USIE|_DAT0|_DTSEN ; Set receive status movwf INDF0 ; Set Stat return ; PutUSB ; Generic fill In endpoint for TX ; Input: ; FSR0L is endpoint number ; FSR1 is source buffer pointer ; W is count ; Returns: ; FSR1 is updated source buffer pointer ; W returns number sent ; Carry is clear for buffer not available ; Uses: ; FSR0 is BDT pointer ; FSR1 is source buffer pointer ; FSR2 is endpoint buffer pointer ; R0 in BANKA is temporary length storage PutUSB movwf R0 ; Save count ; Check to see if we're configured movlb high 0x400 ; Point to proper bank movlw CONFIGURED_STATE ; We might not be configured yet subwf usb_device_state, W movlw 0 ; 0 characters sent, so far bcf STATUS, C ; Clear Carry for possible error return bnz PutUSBNotReady ; We're not configured ; Point FSR0 to requested endpoint In BDT rlncf FSR0L, W ; Endpoint number * 8 rlncf WREG, F rlncf WREG, F lfsr 0, ep0Bi ; Point FSR0 to beginning of BDT area addwf FSR0L, F ; Add endpoint offset to FSR0 (can't overflow to FSR0H) movlw 0 ; 0 characters sent, so far bcf STATUS, C ; Clear Carry for possible error return btfsc INDF0, UOWN ; Who owns the buffer (Stat, UOWN)? PutUSBNotReady return ; Busy (we don't) ; Get endpoint buffer address to FSR2 movlw ADRL ; Point to ADRL movff PLUSW0, FSR2L movlw ADRH ; Point to ADRH movff PLUSW0, FSR2H movlw -1 movf PLUSW2, W ; Get maximum length from in front of endpoint buffer cpfslt R0 ; Find number of bytes to send this time movwf R0 ; Too big - send maximum allowed length incf FSR0L, F ; Point to Cnt movf R0, W ; Get number to send movwf POSTDEC0 ; Put length into Cnt and point back to Stat bz PutUSBZero ; Zero to send PutUSBRamLoop movff POSTINC1, POSTINC2 ; Copy source buffer to endpoint buffer decfsz WREG, F ; Count down number of bytes to transfer bra PutUSBRamLoop PutUSBZero movlw _DTSMASK ; Save only DTS bit andwf INDF0, F btg INDF0, DTS ; Toggle DTS bit movlw _USIE|_DTSEN ; Turn ownership to SIE iorwf INDF0, F movf R0, W ; Return number of bytes sent bsf STATUS, C ; Set Carry for non-error return return ; GetUSB ; Generic get from Out endpoint for RX ; Input: ; FSR0L is endpoint number ; FSR1 is destination buffer pointer ; W is max buffer length ; Returns: ; FSR1 is updated destination buffer pointer ; W returns number received ; Carry is clear for buffer not available ; Uses ; FSR0 is BDT pointer ; FSR1 is destination buffer pointer ; FSR2 is endpoint buffer pointer ; R0 in BANKA is temporary length storage GetUSB movwf R0 ; Save max buffer length ; Check to see if we're configured movlb high 0x400 ; Point to proper bank movlw CONFIGURED_STATE ; We might not be configured yet subwf usb_device_state, W movlw 0 ; 0 characters received, so far bcf STATUS, C ; Clear Carry for possible error return bnz GetUSBNotReady ; We're not configured ; Point FSR0 to requested endpoint Out BDT rlncf FSR0L, W ; Endpoint number * 8 rlncf WREG, F rlncf WREG, F lfsr 0, ep0Bo ; Point FSR0 to beginning of BDT area addwf FSR0L, F ; Add endpoint offset to FSR0 (can't overflow to FSR0H) movlw 0 ; 0 characters received, so far bcf STATUS, C ; Clear Carry for possible error return btfsc INDF0, UOWN ; Who owns the buffer (Stat, UOWN)? GetUSBNotReady return ; Busy (we don't) ; Get endpoint buffer address to FSR2 movlw ADRL ; Point to ADRL movff PLUSW0, FSR2L movlw ADRH ; Point to ADRH movff PLUSW0, FSR2H movf PREINC0, W ; Get Cnt cpfslt R0 ; Make sure it's not longer than the buffer movwf R0 ; It's OK, save returned length movlw -1 movf PLUSW2, W ; Get maximum length from in front of endpoint buffer movwf POSTDEC0 ; Reset max length and point back to Stat movf R0, W ; Get count to W bz GetUSBZero ; Nothing received GetUSBRamLoop movff POSTINC2, POSTINC1 ; Copy endpoint buffer to destination buffer decfsz WREG, F ; Count down number of bytes bra GetUSBRamLoop GetUSBZero movlw _DTSMASK ; Save only DTS bit andwf INDF0, F btg INDF0, DTS ; Toggle DTS bit movlw _USIE|_DTSEN ; Turn ownership to SIE iorwf INDF0, F movf R0, W ; Return number of bytes received bsf STATUS, C ; Set Carry for non-error return return