firmware/usbdrv.c
author root@rika
Thu, 23 Apr 2009 20:55:41 +0200
changeset 33 7a0c4b0354ba
parent 2 2f55e5dd591d
permissions -rw-r--r--
updated documentation
slime@2
     1
/*********************************************************************
slime@2
     2
 *
slime@2
     3
 *                Microchip USB C18 Firmware Version 1.0
slime@2
     4
 *
slime@2
     5
 *********************************************************************
slime@2
     6
 * FileName:        usbdrv.c
slime@2
     7
 * Dependencies:    See INCLUDES section below
slime@2
     8
 * Processor:       PIC18
slime@2
     9
 * Compiler:        C18 2.30.01+
slime@2
    10
 * Company:         Microchip Technology, Inc.
slime@2
    11
 *
slime@2
    12
 * Software License Agreement
slime@2
    13
 *
slime@2
    14
 * The software supplied herewith by Microchip Technology Incorporated
slime@2
    15
 * (the “Company”) for its PICmicro® Microcontroller is intended and
slime@2
    16
 * supplied to you, the Company’s customer, for use solely and
slime@2
    17
 * exclusively on Microchip PICmicro Microcontroller products. The
slime@2
    18
 * software is owned by the Company and/or its supplier, and is
slime@2
    19
 * protected under applicable copyright laws. All rights are reserved.
slime@2
    20
 * Any use in violation of the foregoing restrictions may subject the
slime@2
    21
 * user to criminal sanctions under applicable laws, as well as to
slime@2
    22
 * civil liability for the breach of the terms and conditions of this
slime@2
    23
 * license.
slime@2
    24
 *
slime@2
    25
 * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
slime@2
    26
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
slime@2
    27
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
slime@2
    28
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
slime@2
    29
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
slime@2
    30
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
slime@2
    31
 *
slime@2
    32
 * Author               Date        Comment
slime@2
    33
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
slime@2
    34
 * Rawin Rojvanit       11/19/04    Original.
slime@2
    35
 ********************************************************************/
slime@2
    36
slime@2
    37
/** I N C L U D E S **********************************************************/
slime@2
    38
#include <p18cxxx.h>
slime@2
    39
#include "typedefs.h"
slime@2
    40
#include "usb.h"
slime@2
    41
#include "io_cfg.h"             // Required for USBCheckBusStatus()
slime@2
    42
slime@2
    43
/** V A R I A B L E S ********************************************************/
slime@2
    44
#pragma udata
slime@2
    45
slime@2
    46
/** P R I V A T E  P R O T O T Y P E S ***************************************/
slime@2
    47
void USBModuleEnable(void);
slime@2
    48
void USBModuleDisable(void);
slime@2
    49
slime@2
    50
void USBSuspend(void);
slime@2
    51
void USBWakeFromSuspend(void);
slime@2
    52
slime@2
    53
void USBProtocolResetHandler(void);
slime@2
    54
void USB_SOF_Handler(void);
slime@2
    55
void USBStallHandler(void);
slime@2
    56
void USBErrorHandler(void);
slime@2
    57
slime@2
    58
/** D E C L A R A T I O N S **************************************************/
slime@2
    59
#pragma code
slime@2
    60
/******************************************************************************
slime@2
    61
 * Function:        void USBCheckBusStatus(void)
slime@2
    62
 *
slime@2
    63
 * PreCondition:    None
slime@2
    64
 *
slime@2
    65
 * Input:           None
slime@2
    66
 *
slime@2
    67
 * Output:          None
slime@2
    68
 *
slime@2
    69
 * Side Effects:    None
slime@2
    70
 *
slime@2
    71
 * Overview:        This routine enables/disables the USB module by monitoring
slime@2
    72
 *                  the USB power signal.
slime@2
    73
 *
slime@2
    74
 * Note:            None
slime@2
    75
 *****************************************************************************/
slime@2
    76
void USBCheckBusStatus(void)
slime@2
    77
{
slime@2
    78
    /**************************************************************************
slime@2
    79
     * Bus Attachment & Detachment Detection
slime@2
    80
     * usb_bus_sense is an i/o pin defined in io_cfg.h
slime@2
    81
     *************************************************************************/
slime@2
    82
    #define USB_BUS_ATTACHED    1
slime@2
    83
    #define USB_BUS_DETACHED    0
slime@2
    84
slime@2
    85
    if(usb_bus_sense == USB_BUS_ATTACHED)       // Is USB bus attached?
slime@2
    86
    {
slime@2
    87
        if(UCONbits.USBEN == 0)                 // Is the module off?
slime@2
    88
            USBModuleEnable();                  // Is off, enable it
slime@2
    89
    }
slime@2
    90
    else
slime@2
    91
    {
slime@2
    92
        if(UCONbits.USBEN == 1)                 // Is the module on?
slime@2
    93
            USBModuleDisable();                 // Is on, disable it
slime@2
    94
    }//end if(usb_bus_sense...)
slime@2
    95
    
slime@2
    96
    /*
slime@2
    97
     * After enabling the USB module, it takes some time for the voltage
slime@2
    98
     * on the D+ or D- line to rise high enough to get out of the SE0 condition.
slime@2
    99
     * The USB Reset interrupt should not be unmasked until the SE0 condition is
slime@2
   100
     * cleared. This helps preventing the firmware from misinterpreting this
slime@2
   101
     * unique event as a USB bus reset from the USB host.
slime@2
   102
     */
slime@2
   103
    if(usb_device_state == ATTACHED_STATE)
slime@2
   104
    {
slime@2
   105
        if(!UCONbits.SE0)
slime@2
   106
        {
slime@2
   107
            UIR = 0;                        // Clear all USB interrupts
slime@2
   108
            UIE = 0;                        // Mask all USB interrupts
slime@2
   109
            UIEbits.URSTIE = 1;             // Unmask RESET interrupt
slime@2
   110
            UIEbits.IDLEIE = 1;             // Unmask IDLE interrupt
slime@2
   111
            usb_device_state = POWERED_STATE;
slime@2
   112
        }//end if                           // else wait until SE0 is cleared
slime@2
   113
    }//end if(usb_device_state == ATTACHED_STATE)
slime@2
   114
slime@2
   115
}//end USBCheckBusStatus
slime@2
   116
slime@2
   117
/******************************************************************************
slime@2
   118
 * Function:        void USBModuleEnable(void)
slime@2
   119
 *
slime@2
   120
 * PreCondition:    None
slime@2
   121
 *
slime@2
   122
 * Input:           None
slime@2
   123
 *
slime@2
   124
 * Output:          None
slime@2
   125
 *
slime@2
   126
 * Side Effects:    None
slime@2
   127
 *
slime@2
   128
 * Overview:        This routine enables the USB module.
slime@2
   129
 *                  An end designer should never have to call this routine
slime@2
   130
 *                  manually. This routine should only be called from
slime@2
   131
 *                  USBCheckBusStatus().
slime@2
   132
 *
slime@2
   133
 * Note:            See USBCheckBusStatus() for more information.
slime@2
   134
 *****************************************************************************/
slime@2
   135
void USBModuleEnable(void)
slime@2
   136
{
slime@2
   137
    UCON = 0;
slime@2
   138
    UIE = 0;                                // Mask all USB interrupts
slime@2
   139
    UCONbits.USBEN = 1;                     // Enable module & attach to bus
slime@2
   140
    usb_device_state = ATTACHED_STATE;      // Defined in usbmmap.c & .h
slime@2
   141
}//end USBModuleEnable
slime@2
   142
slime@2
   143
/******************************************************************************
slime@2
   144
 * Function:        void USBModuleDisable(void)
slime@2
   145
 *
slime@2
   146
 * PreCondition:    None
slime@2
   147
 *
slime@2
   148
 * Input:           None
slime@2
   149
 *
slime@2
   150
 * Output:          None
slime@2
   151
 *
slime@2
   152
 * Side Effects:    None
slime@2
   153
 *
slime@2
   154
 * Overview:        This routine disables the USB module.
slime@2
   155
 *                  An end designer should never have to call this routine
slime@2
   156
 *                  manually. This routine should only be called from
slime@2
   157
 *                  USBCheckBusStatus().
slime@2
   158
 *
slime@2
   159
 * Note:            See USBCheckBusStatus() for more information.
slime@2
   160
 *****************************************************************************/
slime@2
   161
void USBModuleDisable(void)
slime@2
   162
{
slime@2
   163
    UCON = 0;                               // Disable module & detach from bus
slime@2
   164
    UIE = 0;                                // Mask all USB interrupts
slime@2
   165
    usb_device_state = DETACHED_STATE;      // Defined in usbmmap.c & .h
slime@2
   166
}//end USBModuleDisable
slime@2
   167
slime@2
   168
/******************************************************************************
slime@2
   169
 * Function:        void USBSoftDetach(void)
slime@2
   170
 *
slime@2
   171
 * PreCondition:    None
slime@2
   172
 *
slime@2
   173
 * Input:           None
slime@2
   174
 *
slime@2
   175
 * Output:          None
slime@2
   176
 *
slime@2
   177
 * Side Effects:    The device will have to be re-enumerated to function again.
slime@2
   178
 *
slime@2
   179
 * Overview:        USBSoftDetach electrically disconnects the device from
slime@2
   180
 *                  the bus. This is done by stop supplying Vusb voltage to
slime@2
   181
 *                  pull-up resistor. The pull-down resistors on the host
slime@2
   182
 *                  side will pull both differential signal lines low and
slime@2
   183
 *                  the host registers the event as a disconnect.
slime@2
   184
 *
slime@2
   185
 *                  Since the USB cable is not physically disconnected, the
slime@2
   186
 *                  power supply through the cable can still be sensed by
slime@2
   187
 *                  the device. The next time USBCheckBusStatus() function
slime@2
   188
 *                  is called, it will reconnect the device back to the bus.
slime@2
   189
 *
slime@2
   190
 * Note:            None
slime@2
   191
 *****************************************************************************/
slime@2
   192
void USBSoftDetach(void)
slime@2
   193
{
slime@2
   194
    USBModuleDisable();
slime@2
   195
}//end USBSoftDetach
slime@2
   196
slime@2
   197
/******************************************************************************
slime@2
   198
 * Function:        void USBDriverService(void)
slime@2
   199
 *
slime@2
   200
 * PreCondition:    None
slime@2
   201
 *
slime@2
   202
 * Input:           None
slime@2
   203
 *
slime@2
   204
 * Output:          None
slime@2
   205
 *
slime@2
   206
 * Side Effects:    None
slime@2
   207
 *
slime@2
   208
 * Overview:        This routine is the heart of this firmware. It manages
slime@2
   209
 *                  all USB interrupts.
slime@2
   210
 *
slime@2
   211
 * Note:            Device state transitions through the following stages:
slime@2
   212
 *                  DETACHED -> ATTACHED -> POWERED -> DEFAULT ->
slime@2
   213
 *                  ADDRESS_PENDING -> ADDRESSED -> CONFIGURED -> READY
slime@2
   214
 *****************************************************************************/
slime@2
   215
void USBDriverService(void)
slime@2
   216
{   
slime@2
   217
    /*
slime@2
   218
     * Pointless to continue servicing if USB cable is not even attached.
slime@2
   219
     */
slime@2
   220
    if(usb_device_state == DETACHED_STATE) return;
slime@2
   221
    
slime@2
   222
    /*
slime@2
   223
     * Task A: Service USB Activity Interrupt
slime@2
   224
     */
slime@2
   225
slime@2
   226
    if(UIRbits.ACTVIF && UIEbits.ACTVIE)    USBWakeFromSuspend();
slime@2
   227
slime@2
   228
    /*
slime@2
   229
     * Pointless to continue servicing if the device is in suspend mode.
slime@2
   230
     */    
slime@2
   231
    if(UCONbits.SUSPND==1) return;
slime@2
   232
            
slime@2
   233
    /*
slime@2
   234
     * Task B: Service USB Bus Reset Interrupt.
slime@2
   235
     * When bus reset is received during suspend, ACTVIF will be set first,
slime@2
   236
     * once the UCONbits.SUSPND is clear, then the URSTIF bit will be asserted.
slime@2
   237
     * This is why URSTIF is checked after ACTVIF.
slime@2
   238
     */
slime@2
   239
    if(UIRbits.URSTIF && UIEbits.URSTIE)    USBProtocolResetHandler();
slime@2
   240
    
slime@2
   241
    /*
slime@2
   242
     * Task C: Service other USB interrupts
slime@2
   243
     */
slime@2
   244
    if(UIRbits.IDLEIF && UIEbits.IDLEIE)    USBSuspend();
slime@2
   245
    if(UIRbits.SOFIF && UIEbits.SOFIE)      USB_SOF_Handler();
slime@2
   246
    if(UIRbits.STALLIF && UIEbits.STALLIE)  USBStallHandler();
slime@2
   247
    if(UIRbits.UERRIF && UIEbits.UERRIE)    USBErrorHandler();
slime@2
   248
slime@2
   249
    /*
slime@2
   250
     * Pointless to continue servicing if the host has not sent a bus reset.
slime@2
   251
     * Once bus reset is received, the device transitions into the DEFAULT
slime@2
   252
     * state and is ready for communication.
slime@2
   253
     */
slime@2
   254
    if(usb_device_state < DEFAULT_STATE) return;
slime@2
   255
slime@2
   256
    /*
slime@2
   257
     * Task D: Servicing USB Transaction Complete Interrupt
slime@2
   258
     */
slime@2
   259
    if(UIRbits.TRNIF && UIEbits.TRNIE)
slime@2
   260
    {
slime@2
   261
        /*
slime@2
   262
         * USBCtrlEPService only services transactions over EP0.
slime@2
   263
         * It ignores all other EP transactions.
slime@2
   264
         */
slime@2
   265
        USBCtrlEPService();
slime@2
   266
        
slime@2
   267
        /*
slime@2
   268
         * Other EP can be serviced later by responsible device class firmware.
slime@2
   269
         * Each device driver knows when an OUT or IN transaction is ready by
slime@2
   270
         * checking the buffer ownership bit.
slime@2
   271
         * An OUT EP should always be owned by SIE until the data is ready.
slime@2
   272
         * An IN EP should always be owned by CPU until the data is ready.
slime@2
   273
         *
slime@2
   274
         * Because of this logic, it is not necessary to save the USTAT value
slime@2
   275
         * of non-EP0 transactions.
slime@2
   276
         */
slime@2
   277
        UIRbits.TRNIF = 0;
slime@2
   278
    }//end if(UIRbits.TRNIF && UIEbits.TRNIE)
slime@2
   279
    
slime@2
   280
}//end USBDriverService
slime@2
   281
slime@2
   282
/******************************************************************************
slime@2
   283
 * Function:        void USBSuspend(void)
slime@2
   284
 *
slime@2
   285
 * PreCondition:    None
slime@2
   286
 *
slime@2
   287
 * Input:           None
slime@2
   288
 *
slime@2
   289
 * Output:          None
slime@2
   290
 *
slime@2
   291
 * Side Effects:    None
slime@2
   292
 *
slime@2
   293
 * Overview:        
slime@2
   294
 *
slime@2
   295
 * Note:            None
slime@2
   296
 *****************************************************************************/
slime@2
   297
void USBSuspend(void)
slime@2
   298
{
slime@2
   299
    /*
slime@2
   300
     * NOTE: Do not clear UIRbits.ACTVIF here!
slime@2
   301
     * Reason:
slime@2
   302
     * ACTVIF is only generated once an IDLEIF has been generated.
slime@2
   303
     * This is a 1:1 ratio interrupt generation.
slime@2
   304
     * For every IDLEIF, there will be only one ACTVIF regardless of
slime@2
   305
     * the number of subsequent bus transitions.
slime@2
   306
     *
slime@2
   307
     * If the ACTIF is cleared here, a problem could occur when:
slime@2
   308
     * [       IDLE       ][bus activity ->
slime@2
   309
     * <--- 3 ms ----->     ^
slime@2
   310
     *                ^     ACTVIF=1
slime@2
   311
     *                IDLEIF=1
slime@2
   312
     *  #           #           #           #   (#=Program polling flags)
slime@2
   313
     *                          ^
slime@2
   314
     *                          This polling loop will see both
slime@2
   315
     *                          IDLEIF=1 and ACTVIF=1.
slime@2
   316
     *                          However, the program services IDLEIF first
slime@2
   317
     *                          because ACTIVIE=0.
slime@2
   318
     *                          If this routine clears the only ACTIVIF,
slime@2
   319
     *                          then it can never get out of the suspend
slime@2
   320
     *                          mode.             
slime@2
   321
     */
slime@2
   322
    UIEbits.ACTVIE = 1;                     // Enable bus activity interrupt
slime@2
   323
    UIRbits.IDLEIF = 0;
slime@2
   324
    UCONbits.SUSPND = 1;                    // Put USB module in power conserve
slime@2
   325
                                            // mode, SIE clock inactive
slime@2
   326
    /*
slime@2
   327
     * At this point the PIC can go into sleep,idle, or
slime@2
   328
     * switch to a slower clock, etc.
slime@2
   329
     */
slime@2
   330
    
slime@2
   331
    /* Modifiable Section */
slime@2
   332
    PIR2bits.USBIF = 0;
slime@2
   333
    PIE2bits.USBIE = 1;                     // Set USB wakeup source
slime@2
   334
    Sleep();                                // Goto sleep
slime@2
   335
    PIE2bits.USBIE = 0;
slime@2
   336
    /* End Modifiable Section */
slime@2
   337
slime@2
   338
}//end USBSuspend
slime@2
   339
slime@2
   340
/******************************************************************************
slime@2
   341
 * Function:        void USBWakeFromSuspend(void)
slime@2
   342
 *
slime@2
   343
 * PreCondition:    None
slime@2
   344
 *
slime@2
   345
 * Input:           None
slime@2
   346
 *
slime@2
   347
 * Output:          None
slime@2
   348
 *
slime@2
   349
 * Side Effects:    None
slime@2
   350
 *
slime@2
   351
 * Overview:        
slime@2
   352
 *
slime@2
   353
 * Note:            None
slime@2
   354
 *****************************************************************************/
slime@2
   355
void USBWakeFromSuspend(void)
slime@2
   356
{
slime@2
   357
    /* 
slime@2
   358
     * If using clock switching, this is the place to restore the
slime@2
   359
     * original clock frequency.
slime@2
   360
     */
slime@2
   361
    UCONbits.SUSPND = 0;
slime@2
   362
    UIEbits.ACTVIE = 0;
slime@2
   363
    UIRbits.ACTVIF = 0;
slime@2
   364
}//end USBWakeFromSuspend
slime@2
   365
slime@2
   366
/******************************************************************************
slime@2
   367
 * Function:        void USBRemoteWakeup(void)
slime@2
   368
 *
slime@2
   369
 * PreCondition:    None
slime@2
   370
 *
slime@2
   371
 * Input:           None
slime@2
   372
 *
slime@2
   373
 * Output:          None
slime@2
   374
 *
slime@2
   375
 * Side Effects:    None
slime@2
   376
 *
slime@2
   377
 * Overview:        This function should be called by user when the device
slime@2
   378
 *                  is waken up by an external stimulus other than ACTIVIF.
slime@2
   379
 *                  Please read the note below to understand the limitations.
slime@2
   380
 *
slime@2
   381
 * Note:            The modifiable section in this routine should be changed
slime@2
   382
 *                  to meet the application needs. Current implementation
slime@2
   383
 *                  temporary blocks other functions from executing for a
slime@2
   384
 *                  period of 1-13 ms depending on the core frequency.
slime@2
   385
 *
slime@2
   386
 *                  According to USB 2.0 specification section 7.1.7.7,
slime@2
   387
 *                  "The remote wakeup device must hold the resume signaling
slime@2
   388
 *                  for at lest 1 ms but for no more than 15 ms."
slime@2
   389
 *                  The idea here is to use a delay counter loop, using a
slime@2
   390
 *                  common value that would work over a wide range of core
slime@2
   391
 *                  frequencies.
slime@2
   392
 *                  That value selected is 1800. See table below:
slime@2
   393
 *                  ==========================================================
slime@2
   394
 *                  Core Freq(MHz)      MIP         RESUME Signal Period (ms)
slime@2
   395
 *                  ==========================================================
slime@2
   396
 *                      48              12          1.05
slime@2
   397
 *                       4              1           12.6
slime@2
   398
 *                  ==========================================================
slime@2
   399
 *                  * These timing could be incorrect when using code
slime@2
   400
 *                    optimization or extended instruction mode,
slime@2
   401
 *                    or when having other interrupts enabled.
slime@2
   402
 *                    Make sure to verify using the MPLAB SIM's Stopwatch
slime@2
   403
 *****************************************************************************/
slime@2
   404
void USBRemoteWakeup(void)
slime@2
   405
{
slime@2
   406
    static word delay_count;
slime@2
   407
    
slime@2
   408
    if(usb_stat.RemoteWakeup == 1)          // Check if RemoteWakeup function
slime@2
   409
    {                                       // has been enabled by the host.
slime@2
   410
        USBWakeFromSuspend();               // Unsuspend USB modue
slime@2
   411
        UCONbits.RESUME = 1;                // Start RESUME signaling
slime@2
   412
slime@2
   413
        /* Modifiable Section */
slime@2
   414
        
slime@2
   415
        delay_count = 1800U;                // Set RESUME line for 1-13 ms
slime@2
   416
        do
slime@2
   417
        {
slime@2
   418
            delay_count--;
slime@2
   419
        }while(delay_count);        
slime@2
   420
        
slime@2
   421
        /* End Modifiable Section */
slime@2
   422
        
slime@2
   423
        UCONbits.RESUME = 0;
slime@2
   424
    }//endif 
slime@2
   425
}//end USBRemoteWakeup
slime@2
   426
slime@2
   427
/******************************************************************************
slime@2
   428
 * Function:        void USB_SOF_Handler(void)
slime@2
   429
 *
slime@2
   430
 * PreCondition:    None
slime@2
   431
 *
slime@2
   432
 * Input:           None
slime@2
   433
 *
slime@2
   434
 * Output:          None
slime@2
   435
 *
slime@2
   436
 * Side Effects:    None
slime@2
   437
 *
slime@2
   438
 * Overview:        The USB host sends out a SOF packet to full-speed devices
slime@2
   439
 *                  every 1 ms. This interrupt may be useful for isochronous
slime@2
   440
 *                  pipes. End designers should implement callback routine
slime@2
   441
 *                  as necessary.
slime@2
   442
 *
slime@2
   443
 * Note:            None
slime@2
   444
 *****************************************************************************/
slime@2
   445
void USB_SOF_Handler(void)
slime@2
   446
{
slime@2
   447
    /* Callback routine here */
slime@2
   448
    
slime@2
   449
    UIRbits.SOFIF = 0;
slime@2
   450
}//end USB_SOF_Handler
slime@2
   451
slime@2
   452
/******************************************************************************
slime@2
   453
 * Function:        void USBStallHandler(void)
slime@2
   454
 *
slime@2
   455
 * PreCondition:    A STALL packet is sent to the host by the SIE.
slime@2
   456
 *
slime@2
   457
 * Input:           None
slime@2
   458
 *
slime@2
   459
 * Output:          None
slime@2
   460
 *
slime@2
   461
 * Side Effects:    None
slime@2
   462
 *
slime@2
   463
 * Overview:        The STALLIF is set anytime the SIE sends out a STALL
slime@2
   464
 *                  packet regardless of which endpoint causes it.
slime@2
   465
 *                  A Setup transaction overrides the STALL function. A stalled
slime@2
   466
 *                  endpoint stops stalling once it receives a setup packet.
slime@2
   467
 *                  In this case, the SIE will accepts the Setup packet and
slime@2
   468
 *                  set the TRNIF flag to notify the firmware. STALL function
slime@2
   469
 *                  for that particular endpoint pipe will be automatically
slime@2
   470
 *                  disabled (direction specific).
slime@2
   471
 *
slime@2
   472
 *                  There are a few reasons for an endpoint to be stalled.
slime@2
   473
 *                  1. When a non-supported USB request is received.
slime@2
   474
 *                     Example: GET_DESCRIPTOR(DEVICE_QUALIFIER)
slime@2
   475
 *                  2. When an endpoint is currently halted.
slime@2
   476
 *                  3. When the device class specifies that an endpoint must
slime@2
   477
 *                     stall in response to a specific event.
slime@2
   478
 *                     Example: Mass Storage Device Class
slime@2
   479
 *                              If the CBW is not valid, the device shall
slime@2
   480
 *                              STALL the Bulk-In pipe.
slime@2
   481
 *                              See USB Mass Storage Class Bulk-only Transport
slime@2
   482
 *                              Specification for more details.
slime@2
   483
 *
slime@2
   484
 * Note:            UEPn.EPSTALL can be scanned to see which endpoint causes
slime@2
   485
 *                  the stall event.
slime@2
   486
 *                  If
slime@2
   487
 *****************************************************************************/
slime@2
   488
void USBStallHandler(void)
slime@2
   489
{
slime@2
   490
    /*
slime@2
   491
     * Does not really have to do anything here,
slime@2
   492
     * even for the control endpoint.
slime@2
   493
     * All BDs of Endpoint 0 are owned by SIE right now,
slime@2
   494
     * but once a Setup Transaction is received, the ownership
slime@2
   495
     * for EP0_OUT will be returned to CPU.
slime@2
   496
     * When the Setup Transaction is serviced, the ownership
slime@2
   497
     * for EP0_IN will then be forced back to CPU by firmware.
slime@2
   498
     */
slime@2
   499
    if(UEP0bits.EPSTALL == 1)
slime@2
   500
    {
slime@2
   501
        USBPrepareForNextSetupTrf();        // Firmware work-around
slime@2
   502
        UEP0bits.EPSTALL = 0;
slime@2
   503
    }
slime@2
   504
    UIRbits.STALLIF = 0;
slime@2
   505
}//end USBStallHandler
slime@2
   506
slime@2
   507
/******************************************************************************
slime@2
   508
 * Function:        void USBErrorHandler(void)
slime@2
   509
 *
slime@2
   510
 * PreCondition:    None
slime@2
   511
 *
slime@2
   512
 * Input:           None
slime@2
   513
 *
slime@2
   514
 * Output:          None
slime@2
   515
 *
slime@2
   516
 * Side Effects:    None
slime@2
   517
 *
slime@2
   518
 * Overview:        The purpose of this interrupt is mainly for debugging
slime@2
   519
 *                  during development. Check UEIR to see which error causes
slime@2
   520
 *                  the interrupt.
slime@2
   521
 *
slime@2
   522
 * Note:            None
slime@2
   523
 *****************************************************************************/
slime@2
   524
void USBErrorHandler(void)
slime@2
   525
{
slime@2
   526
    UIRbits.UERRIF = 0;
slime@2
   527
}//end USBErrorHandler
slime@2
   528
slime@2
   529
/******************************************************************************
slime@2
   530
 * Function:        void USBProtocolResetHandler(void)
slime@2
   531
 *
slime@2
   532
 * PreCondition:    A USB bus reset is received from the host.
slime@2
   533
 *
slime@2
   534
 * Input:           None
slime@2
   535
 *
slime@2
   536
 * Output:          None
slime@2
   537
 *
slime@2
   538
 * Side Effects:    Currently, this routine flushes any pending USB
slime@2
   539
 *                  transactions. It empties out the USTAT FIFO. This action
slime@2
   540
 *                  might not be desirable in some applications.
slime@2
   541
 *
slime@2
   542
 * Overview:        Once a USB bus reset is received from the host, this
slime@2
   543
 *                  routine should be called. It resets the device address to
slime@2
   544
 *                  zero, disables all non-EP0 endpoints, initializes EP0 to
slime@2
   545
 *                  be ready for default communication, clears all USB
slime@2
   546
 *                  interrupt flags, unmasks applicable USB interrupts, and
slime@2
   547
 *                  reinitializes internal state-machine variables.
slime@2
   548
 *
slime@2
   549
 * Note:            None
slime@2
   550
 *****************************************************************************/
slime@2
   551
void USBProtocolResetHandler(void)
slime@2
   552
{
slime@2
   553
    UEIR = 0;                       // Clear all USB error flags
slime@2
   554
    UIR = 0;                        // Clears all USB interrupts
slime@2
   555
    UEIE = 0b10011111;              // Unmask all USB error interrupts
slime@2
   556
    UIE = 0b01111011;               // Enable all interrupts except ACTVIE
slime@2
   557
    
slime@2
   558
    UADDR = 0x00;                   // Reset to default address
slime@2
   559
    mDisableEP1to15();              // Reset all non-EP0 UEPn registers
slime@2
   560
    UEP0 = EP_CTRL|HSHK_EN;         // Init EP0 as a Ctrl EP, see usbdrv.h
slime@2
   561
slime@2
   562
    while(UIRbits.TRNIF == 1)       // Flush any pending transactions
slime@2
   563
        UIRbits.TRNIF = 0;
slime@2
   564
slime@2
   565
    UCONbits.PKTDIS = 0;            // Make sure packet processing is enabled
slime@2
   566
    USBPrepareForNextSetupTrf();    // Declared in usbctrltrf.c
slime@2
   567
    
slime@2
   568
    usb_stat.RemoteWakeup = 0;      // Default status flag to disable
slime@2
   569
    usb_active_cfg = 0;             // Clear active configuration
slime@2
   570
    usb_device_state = DEFAULT_STATE;
slime@2
   571
}//end USBProtocolResetHandler
slime@2
   572
slime@2
   573
slime@2
   574
/* Auxiliary Function */
slime@2
   575
void ClearArray(byte* startAdr,byte count)
slime@2
   576
{
slime@2
   577
    *startAdr;
slime@2
   578
    while(count)
slime@2
   579
    {
slime@2
   580
        _asm
slime@2
   581
        clrf POSTINC0,0
slime@2
   582
        _endasm
slime@2
   583
        count--;
slime@2
   584
    }//end while
slime@2
   585
}//end ClearArray
slime@2
   586
slime@2
   587
/** EOF usbdrv.c *************************************************************/