firmware/usbctrltrf.c
author root@rika
Thu, 23 Apr 2009 19:10:12 +0200
changeset 30 7fd00015f62f
parent 2 2f55e5dd591d
permissions -rw-r--r--
several changes..
     1 /*********************************************************************
     2  *
     3  *                Microchip USB C18 Firmware Version 1.0
     4  *
     5  *********************************************************************
     6  * FileName:        usbctrltrf.c
     7  * Dependencies:    See INCLUDES section below
     8  * Processor:       PIC18
     9  * Compiler:        C18 2.30.01+
    10  * Company:         Microchip Technology, Inc.
    11  *
    12  * Software License Agreement
    13  *
    14  * The software supplied herewith by Microchip Technology Incorporated
    15  * (the “Company”) for its PICmicro® Microcontroller is intended and
    16  * supplied to you, the Company’s customer, for use solely and
    17  * exclusively on Microchip PICmicro Microcontroller products. The
    18  * software is owned by the Company and/or its supplier, and is
    19  * protected under applicable copyright laws. All rights are reserved.
    20  * Any use in violation of the foregoing restrictions may subject the
    21  * user to criminal sanctions under applicable laws, as well as to
    22  * civil liability for the breach of the terms and conditions of this
    23  * license.
    24  *
    25  * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
    26  * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
    27  * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    28  * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
    29  * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
    30  * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
    31  *
    32  * Author               Date        Comment
    33  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    34  * Rawin Rojvanit       11/19/04    Original.
    35  ********************************************************************/
    36 
    37 /** I N C L U D E S **********************************************************/
    38 #include <p18cxxx.h>
    39 #include "typedefs.h"
    40 #include "usb.h"
    41 
    42 /** V A R I A B L E S ********************************************************/
    43 #pragma udata
    44 byte ctrl_trf_state;                // Control Transfer State
    45 byte ctrl_trf_session_owner;        // Current transfer session owner
    46 
    47 POINTER pSrc;                       // Data source pointer
    48 POINTER pDst;                       // Data destination pointer
    49 WORD wCount;                        // Data counter
    50 
    51 /** P R I V A T E  P R O T O T Y P E S ***************************************/
    52 void USBCtrlTrfSetupHandler(void);
    53 void USBCtrlTrfOutHandler(void);
    54 void USBCtrlTrfInHandler(void);
    55 
    56 /** D E C L A R A T I O N S **************************************************/
    57 #pragma code
    58 /******************************************************************************
    59  * Function:        void USBCtrlEPService(void)
    60  *
    61  * PreCondition:    USTAT is loaded with a valid endpoint address.
    62  *
    63  * Input:           None
    64  *
    65  * Output:          None
    66  *
    67  * Side Effects:    None
    68  *
    69  * Overview:        USBCtrlEPService checks for three transaction types that
    70  *                  it knows how to service and services them:
    71  *                  1. EP0 SETUP
    72  *                  2. EP0 OUT
    73  *                  3. EP0 IN
    74  *                  It ignores all other types (i.e. EP1, EP2, etc.)
    75  *
    76  * Note:            None
    77  *****************************************************************************/
    78 void USBCtrlEPService(void)
    79 {   
    80     if(USTAT == EP00_OUT)
    81     {
    82         if(ep0Bo.Stat.PID == SETUP_TOKEN)           // EP0 SETUP
    83             USBCtrlTrfSetupHandler();
    84         else                                        // EP0 OUT
    85             USBCtrlTrfOutHandler();
    86     }
    87     else if(USTAT == EP00_IN)                       // EP0 IN
    88         USBCtrlTrfInHandler();
    89     
    90 }//end USBCtrlEPService
    91 
    92 /******************************************************************************
    93  * Function:        void USBCtrlTrfSetupHandler(void)
    94  *
    95  * PreCondition:    SetupPkt buffer is loaded with valid USB Setup Data
    96  *
    97  * Input:           None
    98  *
    99  * Output:          None
   100  *
   101  * Side Effects:    None
   102  *
   103  * Overview:        This routine is a task dispatcher and has 3 stages.
   104  *                  1. It initializes the control transfer state machine.
   105  *                  2. It calls on each of the module that may know how to
   106  *                     service the Setup Request from the host.
   107  *                     Module Example: USB9, HID, CDC, MSD, ...
   108  *                     As new classes are added, ClassReqHandler table in
   109  *                     usbdsc.c should be updated to call all available
   110  *                     class handlers.
   111  *                  3. Once each of the modules has had a chance to check if
   112  *                     it is responsible for servicing the request, stage 3
   113  *                     then checks direction of the transfer to determine how
   114  *                     to prepare EP0 for the control transfer.
   115  *                     Refer to USBCtrlEPServiceComplete() for more details.
   116  *
   117  * Note:            Microchip USB Firmware has three different states for
   118  *                  the control transfer state machine:
   119  *                  1. WAIT_SETUP
   120  *                  2. CTRL_TRF_TX
   121  *                  3. CTRL_TRF_RX
   122  *                  Refer to firmware manual to find out how one state
   123  *                  is transitioned to another.
   124  *
   125  *                  A Control Transfer is composed of many USB transactions.
   126  *                  When transferring data over multiple transactions,
   127  *                  it is important to keep track of data source, data
   128  *                  destination, and data count. These three parameters are
   129  *                  stored in pSrc,pDst, and wCount. A flag is used to
   130  *                  note if the data source is from ROM or RAM.
   131  *
   132  *****************************************************************************/
   133 void USBCtrlTrfSetupHandler(void)
   134 {
   135     byte i;
   136     
   137     /* Stage 1 */
   138     ctrl_trf_state = WAIT_SETUP;
   139     ctrl_trf_session_owner = MUID_NULL;     // Set owner to NULL
   140     wCount._word = 0;
   141     
   142     /* Stage 2 */
   143     USBCheckStdRequest();                   // See system\usb9\usb9.c
   144     
   145     for(i=0;i < (sizeof(ClassReqHandler)/sizeof(pFunc));i++)
   146     {
   147         if(ctrl_trf_session_owner != MUID_NULL)break;
   148         ClassReqHandler[i]();               // See autofiles\usbdsc.c
   149     }//end while
   150         
   151     /* Stage 3 */
   152     USBCtrlEPServiceComplete();
   153     
   154 }//end USBCtrlTrfSetupHandler
   155 
   156 /******************************************************************************
   157  * Function:        void USBCtrlTrfOutHandler(void)
   158  *
   159  * PreCondition:    None
   160  *
   161  * Input:           None
   162  *
   163  * Output:          None
   164  *
   165  * Side Effects:    None
   166  *
   167  * Overview:        This routine handles an OUT transaction according to
   168  *                  which control transfer state is currently active.
   169  *
   170  * Note:            Note that if the the control transfer was from
   171  *                  host to device, the session owner should be notified
   172  *                  at the end of each OUT transaction to service the
   173  *                  received data.
   174  *
   175  *****************************************************************************/
   176 void USBCtrlTrfOutHandler(void)
   177 {
   178     if(ctrl_trf_state == CTRL_TRF_RX)
   179     {
   180         USBCtrlTrfRxService();
   181         
   182         /*
   183          * Don't have to worry about overwriting _KEEP bit
   184          * because if _KEEP was set, TRNIF would not have been
   185          * generated in the first place.
   186          */
   187         if(ep0Bo.Stat.DTS == 0)
   188             ep0Bo.Stat._byte = _USIE|_DAT1|_DTSEN;
   189         else
   190             ep0Bo.Stat._byte = _USIE|_DAT0|_DTSEN;
   191     }
   192     else    // CTRL_TRF_TX
   193         USBPrepareForNextSetupTrf();
   194     
   195 }//end USBCtrlTrfOutHandler
   196 
   197 /******************************************************************************
   198  * Function:        void USBCtrlTrfInHandler(void)
   199  *
   200  * PreCondition:    None
   201  *
   202  * Input:           None
   203  *
   204  * Output:          None
   205  *
   206  * Side Effects:    None
   207  *
   208  * Overview:        This routine handles an IN transaction according to
   209  *                  which control transfer state is currently active.
   210  *
   211  *
   212  * Note:            A Set Address Request must not change the acutal address
   213  *                  of the device until the completion of the control
   214  *                  transfer. The end of the control transfer for Set Address
   215  *                  Request is an IN transaction. Therefore it is necessary
   216  *                  to service this unique situation when the condition is
   217  *                  right. Macro mUSBCheckAdrPendingState is defined in
   218  *                  usb9.h and its function is to specifically service this
   219  *                  event.
   220  *****************************************************************************/
   221 void USBCtrlTrfInHandler(void)
   222 {
   223     mUSBCheckAdrPendingState();         // Must check if in ADR_PENDING_STATE
   224     
   225     if(ctrl_trf_state == CTRL_TRF_TX)
   226     {
   227         USBCtrlTrfTxService();
   228         
   229         if(ep0Bi.Stat.DTS == 0)
   230             ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN;
   231         else
   232             ep0Bi.Stat._byte = _USIE|_DAT0|_DTSEN;
   233     }
   234     else // CTRL_TRF_RX
   235         USBPrepareForNextSetupTrf();
   236 
   237 }//end USBCtrlTrfInHandler
   238 
   239 /******************************************************************************
   240  * Function:        void USBCtrlTrfTxService(void)
   241  *
   242  * PreCondition:    pSrc, wCount, and usb_stat.ctrl_trf_mem are setup properly.
   243  *
   244  * Input:           None
   245  *
   246  * Output:          None
   247  *
   248  * Side Effects:    None
   249  *
   250  * Overview:        This routine should be called from only two places.
   251  *                  One from USBCtrlEPServiceComplete() and one from
   252  *                  USBCtrlTrfInHandler(). It takes care of managing a
   253  *                  transfer over multiple USB transactions.
   254  *
   255  * Note:            This routine works with isochronous endpoint larger than
   256  *                  256 bytes and is shown here as an example of how to deal
   257  *                  with BC9 and BC8. In reality, a control endpoint can never
   258  *                  be larger than 64 bytes.
   259  *****************************************************************************/
   260 void USBCtrlTrfTxService(void)
   261 {    
   262     WORD byte_to_send;
   263     
   264     /*
   265      * First, have to figure out how many byte of data to send.
   266      */
   267     if(wCount._word < EP0_BUFF_SIZE)
   268         byte_to_send._word = wCount._word;
   269     else
   270         byte_to_send._word = EP0_BUFF_SIZE;
   271     
   272     /*
   273      * Next, load the number of bytes to send to BC9..0 in buffer descriptor
   274      */
   275     ep0Bi.Stat.BC9 = 0;
   276     ep0Bi.Stat.BC8 = 0;
   277     ep0Bi.Stat._byte |= MSB(byte_to_send);
   278     ep0Bi.Cnt = LSB(byte_to_send);
   279     
   280     /*
   281      * Subtract the number of bytes just about to be sent from the total.
   282      */
   283     wCount._word = wCount._word - byte_to_send._word;
   284     
   285     pDst.bRam = (byte*)&CtrlTrfData;        // Set destination pointer
   286 
   287     if(usb_stat.ctrl_trf_mem == _ROM)       // Determine type of memory source
   288     {
   289         while(byte_to_send._word)
   290         {
   291             *pDst.bRam = *pSrc.bRom;
   292             pDst.bRam++;
   293             pSrc.bRom++;
   294             byte_to_send._word--;
   295         }//end while(byte_to_send._word)
   296     }
   297     else // RAM
   298     {
   299         while(byte_to_send._word)
   300         {
   301             *pDst.bRam = *pSrc.bRam;
   302             pDst.bRam++;
   303             pSrc.bRam++;
   304             byte_to_send._word--;
   305         }//end while(byte_to_send._word)
   306     }//end if(usb_stat.ctrl_trf_mem == _ROM)
   307     
   308 }//end USBCtrlTrfTxService
   309 
   310 /******************************************************************************
   311  * Function:        void USBCtrlTrfRxService(void)
   312  *
   313  * PreCondition:    pDst and wCount are setup properly.
   314  *                  pSrc is always &CtrlTrfData
   315  *                  usb_stat.ctrl_trf_mem is always _RAM.
   316  *                  wCount should be set to 0 at the start of each control
   317  *                  transfer.
   318  *
   319  * Input:           None
   320  *
   321  * Output:          None
   322  *
   323  * Side Effects:    None
   324  *
   325  * Overview:        *** This routine is only partially complete. Check for
   326  *                  new version of the firmware.
   327  *
   328  * Note:            None
   329  *****************************************************************************/
   330 void USBCtrlTrfRxService(void)
   331 {
   332     WORD byte_to_read;
   333 
   334     MSB(byte_to_read) = 0x03 & ep0Bo.Stat._byte;    // Filter out last 2 bits
   335     LSB(byte_to_read) = ep0Bo.Cnt;
   336     
   337     /*
   338      * Accumulate total number of bytes read
   339      */
   340     wCount._word = wCount._word + byte_to_read._word;
   341     
   342     pSrc.bRam = (byte*)&CtrlTrfData;
   343 
   344     while(byte_to_read._word)
   345     {
   346         *pDst.bRam = *pSrc.bRam;
   347         pDst.bRam++;
   348         pSrc.bRam++;
   349         byte_to_read._word--;
   350     }//end while(byte_to_read._word)    
   351     
   352 }//end USBCtrlTrfRxService
   353 
   354 /******************************************************************************
   355  * Function:        void USBCtrlEPServiceComplete(void)
   356  *
   357  * PreCondition:    None
   358  *
   359  * Input:           None
   360  *
   361  * Output:          None
   362  *
   363  * Side Effects:    None
   364  *
   365  * Overview:        This routine wrap up the ramaining tasks in servicing
   366  *                  a Setup Request. Its main task is to set the endpoint
   367  *                  controls appropriately for a given situation. See code
   368  *                  below.
   369  *                  There are three main scenarios:
   370  *                  a) There was no handler for the Request, in this case
   371  *                     a STALL should be sent out.
   372  *                  b) The host has requested a read control transfer,
   373  *                     endpoints are required to be setup in a specific way.
   374  *                  c) The host has requested a write control transfer, or
   375  *                     a control data stage is not required, endpoints are
   376  *                     required to be setup in a specific way.
   377  *
   378  *                  Packet processing is resumed by clearing PKTDIS bit.
   379  *
   380  * Note:            None
   381  *****************************************************************************/
   382 void USBCtrlEPServiceComplete(void)
   383 {
   384     if(ctrl_trf_session_owner == MUID_NULL)
   385     {
   386         /*
   387          * If no one knows how to service this request then stall.
   388          * Must also prepare EP0 to receive the next SETUP transaction.
   389          */
   390         ep0Bo.Cnt = EP0_BUFF_SIZE;
   391         ep0Bo.ADR = (byte*)&SetupPkt;
   392         
   393         ep0Bo.Stat._byte = _USIE|_BSTALL;
   394         ep0Bi.Stat._byte = _USIE|_BSTALL;
   395     }
   396     else    // A module has claimed ownership of the control transfer session.
   397     {
   398         if(SetupPkt.DataDir == DEV_TO_HOST)
   399         {
   400             if(SetupPkt.wLength < wCount._word)
   401                 wCount._word = SetupPkt.wLength;
   402             USBCtrlTrfTxService();
   403             ctrl_trf_state = CTRL_TRF_TX;
   404             /*
   405              * Control Read:
   406              * <SETUP[0]><IN[1]><IN[0]>...<OUT[1]> | <SETUP[0]>
   407              * 1. Prepare OUT EP to respond to early termination
   408              *
   409              * NOTE:
   410              * If something went wrong during the control transfer,
   411              * the last status stage may not be sent by the host.
   412              * When this happens, two different things could happen
   413              * depending on the host.
   414              * a) The host could send out a RESET.
   415              * b) The host could send out a new SETUP transaction
   416              *    without sending a RESET first.
   417              * To properly handle case (b), the OUT EP must be setup
   418              * to receive either a zero length OUT transaction, or a
   419              * new SETUP transaction.
   420              *
   421              * Since the SETUP transaction requires the DTS bit to be
   422              * DAT0 while the zero length OUT status requires the DTS
   423              * bit to be DAT1, the DTS bit check by the hardware should
   424              * be disabled. This way the SIE could accept either of
   425              * the two transactions.
   426              *
   427              * Furthermore, the Cnt byte should be set to prepare for
   428              * the SETUP data (8-byte or more), and the buffer address
   429              * should be pointed to SetupPkt.
   430              */
   431             ep0Bo.Cnt = EP0_BUFF_SIZE;
   432             ep0Bo.ADR = (byte*)&SetupPkt;            
   433             ep0Bo.Stat._byte = _USIE;           // Note: DTSEN is 0!
   434     
   435             /*
   436              * 2. Prepare IN EP to transfer data, Cnt should have
   437              *    been initialized by responsible request owner.
   438              */
   439             ep0Bi.ADR = (byte*)&CtrlTrfData;
   440             ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN;
   441         }
   442         else    // (SetupPkt.DataDir == HOST_TO_DEV)
   443         {
   444             ctrl_trf_state = CTRL_TRF_RX;
   445             /*
   446              * Control Write:
   447              * <SETUP[0]><OUT[1]><OUT[0]>...<IN[1]> | <SETUP[0]>
   448              *
   449              * 1. Prepare IN EP to respond to early termination
   450              *
   451              *    This is the same as a Zero Length Packet Response
   452              *    for control transfer without a data stage
   453              */
   454             ep0Bi.Cnt = 0;
   455             ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN;
   456 
   457             /*
   458              * 2. Prepare OUT EP to receive data.
   459              */
   460             ep0Bo.Cnt = EP0_BUFF_SIZE;
   461             ep0Bo.ADR = (byte*)&CtrlTrfData;
   462             ep0Bo.Stat._byte = _USIE|_DAT1|_DTSEN;
   463         }//end if(SetupPkt.DataDir == DEV_TO_HOST)
   464     }//end if(ctrl_trf_session_owner == MUID_NULL)
   465     
   466     /*
   467      * PKTDIS bit is set when a Setup Transaction is received.
   468      * Clear to resume packet processing.
   469      */
   470     UCONbits.PKTDIS = 0;
   471 
   472 }//end USBCtrlEPServiceComplete
   473 
   474 /******************************************************************************
   475  * Function:        void USBPrepareForNextSetupTrf(void)
   476  *
   477  * PreCondition:    None
   478  *
   479  * Input:           None
   480  *
   481  * Output:          None
   482  *
   483  * Side Effects:    None
   484  *
   485  * Overview:        The routine forces EP0 OUT to be ready for a new Setup
   486  *                  transaction, and forces EP0 IN to be owned by CPU.
   487  *
   488  * Note:            None
   489  *****************************************************************************/
   490 void USBPrepareForNextSetupTrf(void)
   491 {
   492     ctrl_trf_state = WAIT_SETUP;            // See usbctrltrf.h
   493     ep0Bo.Cnt = EP0_BUFF_SIZE;              // Defined in usbcfg.h
   494     ep0Bo.ADR = (byte*)&SetupPkt;
   495     ep0Bo.Stat._byte = _USIE|_DAT0|_DTSEN;  // EP0 buff dsc init, see usbmmap.h
   496     ep0Bi.Stat._byte = _UCPU;               // EP0 IN buffer initialization
   497 }//end USBPrepareForNextSetupTrf
   498 
   499 /** EOF usbctrltrf.c *********************************************************/