;                            Software License Agreement
;
; The software supplied herewith by Microchip Technology Incorporated (the "Company")
; for its PICmicro(r) Microcontroller is intended and supplied to you, the Company's
; customer, for use solely and exclusively on Microchip PICmicro Microcontroller
; products.
;
; The software is owned by the Company and/or its supplier, and is protected under
; applicable copyright laws. All rights are reserved. Any use in violation of the
; foregoing restrictions may subject the user to criminal sanctions under applicable
; laws, as well as to civil liability for the breach of the terms and conditions of
; this license.
;
; THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, WHETHER EXPRESS,
; IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE
; COMPANY SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
; CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
;
; ###############################################################################
;   filename:           HIDCLASS.ASM
;
;   Implements USB Human Interface Device (HID) class specific commands.
;
; ###############################################################################
;
;   Author(s):          Dan Butler and Reston Condit
;   Company:            Microchip Technology Inc
;
;   Revision:           1.21
;   Date:               08 August 2001
;   Assembled using     MPASM 2.61
;   Revision History:
;   23 August 2000      DZB Changed descriptor pointers to 16 bits.
;   24 August 2000      DZB Moved EP1 & 2 configuration from USBReset
;                           to Set_Configuration to implement requirement in
;                           USB V1.1 spec paragraph 5.3.1.2
;   28 August 2000      DZB Force data toggle on OUT packets in PutUSB
;   20 March 2001       DZB Reduced use of common RAM
;   20 March 2001       DZB Put and Get use their own temp variable (GPtemp) to
;                           avoid collisions with the ISR's use of temp.
;   29 March 2001       DZB Fixed saving of bank bits in GetUSB
;   02 May 2001         DZB Implemented SHOW_ENUM_STATUS to show enumeration
;                           status on the PORTB LEDs: 0- Powered, 1- Default,
;                           2- addressed, 3- configured, 4- sleep, 
;                           5- EP0 Activity, 6- EP1 Activity, 7- EP2 Activity
;   03 August 2001      RAC Made distinct GetEP and PutEP macros for endpoints 1 
;                           and 2.  These functions are GetEP1, GetEP2, PutEP1, and 
;                           PutEP2.  Instances of the these macros are created in
;                           usb_ch9.asm.
;   08 August 2001      RAC Corrected various banking and paging issues.
;   15 August           RAC Added Report_desc_index function in descript.asm.
;                           This function allows more than one report descriptor
;                           to be used. 
;   06 September 2001	JMS Changed to work with PBP compiler.
;
;################################################################################
;
;   include files:
;       P16C7x5.inc     Rev 1.00
;       usb_defs.inc    Rev 1.21
;
;################################################################################

; ******************************************************************
; Get Class Specific Descriptor
; ******************************************************************

ClassSpecificRequest
    pagesel Dev2HostHIDRequest
    movf    BufferData+bmRequestType,w
    xorlw   0x21
    btfsc   STATUS,Z
    goto    Host2DevHIDRequest

    movf    BufferData+bmRequestType,w
    xorlw   0x22
    btfsc   STATUS,Z
    goto    Host2DevReportRequest

    movf    BufferData+bmRequestType,w
    xorlw   0x23
    btfsc   STATUS,Z
    goto    Host2DevPhysicalRequest

    movf    BufferData+bmRequestType,w
    xorlw   0xA1
    btfsc   STATUS,Z
    goto    Dev2HostHIDRequest

    movf    BufferData+bmRequestType,w
    xorlw   0xA2
    btfsc   STATUS,Z
    goto    Dev2HostReportRequest

    movf    BufferData+bmRequestType,w
    xorlw   0xA3
    btfsc   STATUS,Z
    goto    Dev2HostPhysicalRequest

    pagesel wrongstate
    goto    wrongstate    

    ; Need to add code if you need to handle optional functions
    ; such as get/set_idle. Otherwise, send STALL buy calling
    ; to signal the host that the feature is not implemented.

Host2DevHIDRequest
    movf    BufferData+bRequest,w
    xorlw   0x01
    btfsc   STATUS,Z
    goto    GetHIDReport

    movf    BufferData+bRequest,w
    xorlw   0x02
    btfsc   STATUS,Z
    goto    GetIdle

    movf    BufferData+bRequest,w
    xorlw   0x03
    btfsc   STATUS,Z
    goto    GetPhysical

    movf    BufferData+bRequest,w
    xorlw   0x06
    btfsc   STATUS,Z
    goto    Get_Report_Descriptor

    movf    BufferData+bRequest,w
    xorlw   0x09
    btfsc   STATUS,Z
    goto    SetHIDReport

    movf    BufferData+bRequest,w
    xorlw   0x0A
    btfsc   STATUS,Z
    goto    SetIdle

    movf    BufferData+bRequest,w
    xorlw   0x0B
    btfsc   STATUS,Z
    goto    SetProtocol

    pagesel wrongstate
    goto    wrongstate
    
; ******************************************************************
; Get Report Descriptor
; Returns the Mouse Report descriptor
; Checks for the report type (input, output or Feature).
; ******************************************************************
Get_Report_Descriptor
    banksel EP0_start
    movlw   GET_DESCRIPTOR
    movwf   USB_dev_req     ; currently processing a get descriptor request

    movlw   8
    movwf   EP0_maxLength

    movf    BufferData+(wValue+1),w ; check report ID
    xorlw   0x01                    ; was it an Input Report?
    btfsc   STATUS,Z
    goto    TryOutputReport

    pagesel Descriptions
    bcf     STATUS,C
    rlf     BufferData+wIndex,w
    call    Report_desc_index   ; translate index to offset into descriptor table
    movwf   EP0_start
    bcf     STATUS,C
    rlf     BufferData+wIndex,w
    addlw   1                   ; point to high order byte
    call    Report_desc_index   ; translate index to offset into descriptor table
    movwf   EP0_start+1
    call    Descriptions
    movwf   EP0_end
    pagesel CheckReportLength
    incf    EP0_start,f
    goto    CheckReportLength

TryOutputReport
    movf    BufferData+(wValue+1),w ; check report ID
    xorlw   0x02                    ; was it an Output Report?
    btfsc   STATUS,Z
    goto    TryFeatureReport

    pagesel Descriptions
    bcf     STATUS,C
    rlf     BufferData+wIndex,w
    call    Report_desc_index   ; translate index to offset into descriptor table
    movwf   EP0_start
    bcf     STATUS,C
    rlf     BufferData+wIndex,w
    addlw   1                   ; point to high order byte
    call    Report_desc_index   ; translate index to offset into descriptor table
    movwf   EP0_start+1
    call    Descriptions
    movwf   EP0_end
    pagesel CheckReportLength
    incf    EP0_start,f
    goto    CheckReportLength

TryFeatureReport
    movf    BufferData+(wValue+1),w ; check report ID
    xorlw   0x03            ; was it an Output Report?
    pagesel wrongstate
    btfsc   STATUS,Z
    goto    wrongstate

; Fill EP0IN buffer here...
    return
    
CheckReportLength
    movf    BufferData+(wLength+1),w ; Is the host requesting more than 255 bytes?
    btfss   STATUS,Z        ; If so, the host is requesting more than we have
    goto    nolimit_rpt

check_low_bytes
    movf    BufferData+wLength,w
    subwf   EP0_end,w       ; if not, compare the amount the host is request
    movf    BufferData+wLength,w ; with the length of the descriptor
    btfsc   STATUS,C        ; if the host is request less than the descriptor
    movwf   EP0_end         ; length, send only as much as what the host wants

nolimit_rpt
    incf    EP0_end,f
    pagesel copy_descriptor_to_EP0        
    call    copy_descriptor_to_EP0
    return

Get_HID_Descriptor
    movlw   GET_DESCRIPTOR
    movwf   USB_dev_req     ; currently processing a get descriptor request

    movlw   8
    movwf   EP0_maxLength

    movlw   low HID_Descriptor
    movwf   EP0_start
    movlw   high HID_Descriptor
    movwf   EP0_start + 1
    pagesel Descriptions
    call    Descriptions    ; get the HID descriptor length
    movwf   EP0_end
    pagesel Get_HID_Descriptor

    movf    BufferData+(wLength+1),f
    btfss   STATUS,Z
    goto    nolimit_hid

    subwf   BufferData+wLength,w
    movf    BufferData+wLength,w
    btfss   STATUS,C
    movwf   EP0_end

nolimit_hid
    incf    EP0_end,f
    pagesel copy_descriptor_to_EP0
    call    copy_descriptor_to_EP0
    return

Get_Physical_Descriptor
    return

Check_Class_Specific_IN
    pagesel copy_descriptor_to_EP0
    movf    USB_dev_req,w
    xorlw   GET_DESCRIPTOR
    btfsc   STATUS,Z
    call    copy_descriptor_to_EP0
    return

; ******************************************************************
; These requests are parsed out, but nothing is actually done with them
; currently they simply stall EP0 to show that the request is not
; supported.  If you need to support them, fill in the code.
; ******************************************************************
Host2DevReportRequest
Host2DevPhysicalRequest
Dev2HostHIDRequest
Dev2HostReportRequest
Dev2HostPhysicalRequest
GetHIDReport
GetIdle
GetPhysical
SetIdle
    pagesel wrongstate
    goto    wrongstate

SetHIDReport
    movlw   HID_SET_REPORT
    movwf   USB_dev_req     ; store status
    banksel BD0OST
    movlw   0xc8            ; reset buffer
    movwf   BD0OST           
    return

; ******************************************************************
; As written, Set Protocol merely returns a zero length packet to keep the OS happy.
; If your application actually needs to do something with the protocol value specified
; here's where to add the code.
; ******************************************************************
SetProtocol
    banksel BD0IBC          ; select bank 3
    movlw   0x00
    movwf   BD0IBC          ; set the byte count field to zero
    movlw   0xc8    
    movwf   BD0IST          ; Set the OWNs bit

; Add code here to actually do something with the protocol value specified.
    return

