Main Page | Data Structures | Directories | File List | Data Fields | Globals

usbctrltrf.c

Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  *                Microchip USB C18 Firmware Version 1.0
00004  *
00005  *********************************************************************
00006  * FileName:        usbctrltrf.c
00007  * Dependencies:    See INCLUDES section below
00008  * Processor:       PIC18
00009  * Compiler:        C18 2.30.01+
00010  * Company:         Microchip Technology, Inc.
00011  *
00012  * Software License Agreement
00013  *
00014  * The software supplied herewith by Microchip Technology Incorporated
00015  * (the “Company”) for its PICmicro® Microcontroller is intended and
00016  * supplied to you, the Company’s customer, for use solely and
00017  * exclusively on Microchip PICmicro Microcontroller products. The
00018  * software is owned by the Company and/or its supplier, and is
00019  * protected under applicable copyright laws. All rights are reserved.
00020  * Any use in violation of the foregoing restrictions may subject the
00021  * user to criminal sanctions under applicable laws, as well as to
00022  * civil liability for the breach of the terms and conditions of this
00023  * license.
00024  *
00025  * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
00026  * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
00027  * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00028  * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
00029  * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
00030  * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
00031  *
00032  * Author               Date        Comment
00033  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00034  * Rawin Rojvanit       11/19/04    Original.
00035  ********************************************************************/
00036 
00037 /** I N C L U D E S **********************************************************/
00038 #include <p18cxxx.h>
00039 #include "system\typedefs.h"
00040 #include "system\usb\usb.h"
00041 
00042 /** V A R I A B L E S ********************************************************/
00043 #pragma udata
00044 byte ctrl_trf_state;                // Control Transfer State
00045 byte ctrl_trf_session_owner;        // Current transfer session owner
00046 
00047 POINTER pSrc;                       // Data source pointer
00048 POINTER pDst;                       // Data destination pointer
00049 WORD wCount;                        // Data counter
00050 
00051 /** P R I V A T E  P R O T O T Y P E S ***************************************/
00052 void USBCtrlTrfSetupHandler(void);
00053 void USBCtrlTrfOutHandler(void);
00054 void USBCtrlTrfInHandler(void);
00055 
00056 /** D E C L A R A T I O N S **************************************************/
00057 #pragma code
00058 /******************************************************************************
00059  * Function:        void USBCtrlEPService(void)
00060  *
00061  * PreCondition:    USTAT is loaded with a valid endpoint address.
00062  *
00063  * Input:           None
00064  *
00065  * Output:          None
00066  *
00067  * Side Effects:    None
00068  *
00069  * Overview:        USBCtrlEPService checks for three transaction types that
00070  *                  it knows how to service and services them:
00071  *                  1. EP0 SETUP
00072  *                  2. EP0 OUT
00073  *                  3. EP0 IN
00074  *                  It ignores all other types (i.e. EP1, EP2, etc.)
00075  *
00076  * Note:            None
00077  *****************************************************************************/
00078 void USBCtrlEPService(void)
00079 {   
00080     if(USTAT == EP00_OUT)
00081     {
00082         if(ep0Bo.Stat.PID == SETUP_TOKEN)           // EP0 SETUP
00083             USBCtrlTrfSetupHandler();
00084         else                                        // EP0 OUT
00085             USBCtrlTrfOutHandler();
00086     }
00087     else if(USTAT == EP00_IN)                       // EP0 IN
00088         USBCtrlTrfInHandler();
00089     
00090 }//end USBCtrlEPService
00091 
00092 /******************************************************************************
00093  * Function:        void USBCtrlTrfSetupHandler(void)
00094  *
00095  * PreCondition:    SetupPkt buffer is loaded with valid USB Setup Data
00096  *
00097  * Input:           None
00098  *
00099  * Output:          None
00100  *
00101  * Side Effects:    None
00102  *
00103  * Overview:        This routine is a task dispatcher and has 3 stages.
00104  *                  1. It initializes the control transfer state machine.
00105  *                  2. It calls on each of the module that may know how to
00106  *                     service the Setup Request from the host.
00107  *                     Module Example: USB9, HID, CDC, MSD, ...
00108  *                     As new classes are added, ClassReqHandler table in
00109  *                     usbdsc.c should be updated to call all available
00110  *                     class handlers.
00111  *                  3. Once each of the modules has had a chance to check if
00112  *                     it is responsible for servicing the request, stage 3
00113  *                     then checks direction of the transfer to determine how
00114  *                     to prepare EP0 for the control transfer.
00115  *                     Refer to USBCtrlEPServiceComplete() for more details.
00116  *
00117  * Note:            Microchip USB Firmware has three different states for
00118  *                  the control transfer state machine:
00119  *                  1. WAIT_SETUP
00120  *                  2. CTRL_TRF_TX
00121  *                  3. CTRL_TRF_RX
00122  *                  Refer to firmware manual to find out how one state
00123  *                  is transitioned to another.
00124  *
00125  *                  A Control Transfer is composed of many USB transactions.
00126  *                  When transferring data over multiple transactions,
00127  *                  it is important to keep track of data source, data
00128  *                  destination, and data count. These three parameters are
00129  *                  stored in pSrc,pDst, and wCount. A flag is used to
00130  *                  note if the data source is from ROM or RAM.
00131  *
00132  *****************************************************************************/
00133 void USBCtrlTrfSetupHandler(void)
00134 {
00135     byte i;
00136     
00137     /* Stage 1 */
00138     ctrl_trf_state = WAIT_SETUP;
00139     ctrl_trf_session_owner = MUID_NULL;     // Set owner to NULL
00140     wCount._word = 0;
00141     
00142     /* Stage 2 */
00143     USBCheckStdRequest();                   // See system\usb9\usb9.c
00144     
00145     for(i=0;i < (sizeof(ClassReqHandler)/sizeof(pFunc));i++)
00146     {
00147         if(ctrl_trf_session_owner != MUID_NULL)break;
00148         ClassReqHandler[i]();               // See autofiles\usbdsc.c
00149     }//end while
00150         
00151     /* Stage 3 */
00152     USBCtrlEPServiceComplete();
00153     
00154 }//end USBCtrlTrfSetupHandler
00155 
00156 /******************************************************************************
00157  * Function:        void USBCtrlTrfOutHandler(void)
00158  *
00159  * PreCondition:    None
00160  *
00161  * Input:           None
00162  *
00163  * Output:          None
00164  *
00165  * Side Effects:    None
00166  *
00167  * Overview:        This routine handles an OUT transaction according to
00168  *                  which control transfer state is currently active.
00169  *
00170  * Note:            Note that if the the control transfer was from
00171  *                  host to device, the session owner should be notified
00172  *                  at the end of each OUT transaction to service the
00173  *                  received data.
00174  *
00175  *****************************************************************************/
00176 void USBCtrlTrfOutHandler(void)
00177 {
00178     if(ctrl_trf_state == CTRL_TRF_RX)
00179     {
00180         USBCtrlTrfRxService();
00181         
00182         /*
00183          * Don't have to worry about overwriting _KEEP bit
00184          * because if _KEEP was set, TRNIF would not have been
00185          * generated in the first place.
00186          */
00187         if(ep0Bo.Stat.DTS == 0)
00188             ep0Bo.Stat._byte = _USIE|_DAT1|_DTSEN;
00189         else
00190             ep0Bo.Stat._byte = _USIE|_DAT0|_DTSEN;
00191     }
00192     else    // CTRL_TRF_TX
00193         USBPrepareForNextSetupTrf();
00194     
00195 }//end USBCtrlTrfOutHandler
00196 
00197 /******************************************************************************
00198  * Function:        void USBCtrlTrfInHandler(void)
00199  *
00200  * PreCondition:    None
00201  *
00202  * Input:           None
00203  *
00204  * Output:          None
00205  *
00206  * Side Effects:    None
00207  *
00208  * Overview:        This routine handles an IN transaction according to
00209  *                  which control transfer state is currently active.
00210  *
00211  *
00212  * Note:            A Set Address Request must not change the acutal address
00213  *                  of the device until the completion of the control
00214  *                  transfer. The end of the control transfer for Set Address
00215  *                  Request is an IN transaction. Therefore it is necessary
00216  *                  to service this unique situation when the condition is
00217  *                  right. Macro mUSBCheckAdrPendingState is defined in
00218  *                  usb9.h and its function is to specifically service this
00219  *                  event.
00220  *****************************************************************************/
00221 void USBCtrlTrfInHandler(void)
00222 {
00223     mUSBCheckAdrPendingState();         // Must check if in ADR_PENDING_STATE
00224     
00225     if(ctrl_trf_state == CTRL_TRF_TX)
00226     {
00227         USBCtrlTrfTxService();
00228         
00229         if(ep0Bi.Stat.DTS == 0)
00230             ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN;
00231         else
00232             ep0Bi.Stat._byte = _USIE|_DAT0|_DTSEN;
00233     }
00234     else // CTRL_TRF_RX
00235         USBPrepareForNextSetupTrf();
00236 
00237 }//end USBCtrlTrfInHandler
00238 
00239 /******************************************************************************
00240  * Function:        void USBCtrlTrfTxService(void)
00241  *
00242  * PreCondition:    pSrc, wCount, and usb_stat.ctrl_trf_mem are setup properly.
00243  *
00244  * Input:           None
00245  *
00246  * Output:          None
00247  *
00248  * Side Effects:    None
00249  *
00250  * Overview:        This routine should be called from only two places.
00251  *                  One from USBCtrlEPServiceComplete() and one from
00252  *                  USBCtrlTrfInHandler(). It takes care of managing a
00253  *                  transfer over multiple USB transactions.
00254  *
00255  * Note:            This routine works with isochronous endpoint larger than
00256  *                  256 bytes and is shown here as an example of how to deal
00257  *                  with BC9 and BC8. In reality, a control endpoint can never
00258  *                  be larger than 64 bytes.
00259  *****************************************************************************/
00260 void USBCtrlTrfTxService(void)
00261 {    
00262     WORD byte_to_send;
00263     
00264     /*
00265      * First, have to figure out how many byte of data to send.
00266      */
00267     if(wCount._word < EP0_BUFF_SIZE)
00268         byte_to_send._word = wCount._word;
00269     else
00270         byte_to_send._word = EP0_BUFF_SIZE;
00271     
00272     /*
00273      * Next, load the number of bytes to send to BC9..0 in buffer descriptor
00274      */
00275     ep0Bi.Stat.BC9 = 0;
00276     ep0Bi.Stat.BC8 = 0;
00277     ep0Bi.Stat._byte |= MSB(byte_to_send);
00278     ep0Bi.Cnt = LSB(byte_to_send);
00279     
00280     /*
00281      * Subtract the number of bytes just about to be sent from the total.
00282      */
00283     wCount._word = wCount._word - byte_to_send._word;
00284     
00285     pDst.bRam = (byte*)&CtrlTrfData;        // Set destination pointer
00286 
00287     if(usb_stat.ctrl_trf_mem == _ROM)       // Determine type of memory source
00288     {
00289         while(byte_to_send._word)
00290         {
00291             *pDst.bRam = *pSrc.bRom;
00292             pDst.bRam++;
00293             pSrc.bRom++;
00294             byte_to_send._word--;
00295         }//end while(byte_to_send._word)
00296     }
00297     else // RAM
00298     {
00299         while(byte_to_send._word)
00300         {
00301             *pDst.bRam = *pSrc.bRam;
00302             pDst.bRam++;
00303             pSrc.bRam++;
00304             byte_to_send._word--;
00305         }//end while(byte_to_send._word)
00306     }//end if(usb_stat.ctrl_trf_mem == _ROM)
00307     
00308 }//end USBCtrlTrfTxService
00309 
00310 /******************************************************************************
00311  * Function:        void USBCtrlTrfRxService(void)
00312  *
00313  * PreCondition:    pDst and wCount are setup properly.
00314  *                  pSrc is always &CtrlTrfData
00315  *                  usb_stat.ctrl_trf_mem is always _RAM.
00316  *                  wCount should be set to 0 at the start of each control
00317  *                  transfer.
00318  *
00319  * Input:           None
00320  *
00321  * Output:          None
00322  *
00323  * Side Effects:    None
00324  *
00325  * Overview:        *** This routine is only partially complete. Check for
00326  *                  new version of the firmware.
00327  *
00328  * Note:            None
00329  *****************************************************************************/
00330 void USBCtrlTrfRxService(void)
00331 {
00332     WORD byte_to_read;
00333 
00334     MSB(byte_to_read) = 0x03 & ep0Bo.Stat._byte;    // Filter out last 2 bits
00335     LSB(byte_to_read) = ep0Bo.Cnt;
00336     
00337     /*
00338      * Accumulate total number of bytes read
00339      */
00340     wCount._word = wCount._word + byte_to_read._word;
00341     
00342     pSrc.bRam = (byte*)&CtrlTrfData;
00343 
00344     while(byte_to_read._word)
00345     {
00346         *pDst.bRam = *pSrc.bRam;
00347         pDst.bRam++;
00348         pSrc.bRam++;
00349         byte_to_read._word--;
00350     }//end while(byte_to_read._word)    
00351     
00352 }//end USBCtrlTrfRxService
00353 
00354 /******************************************************************************
00355  * Function:        void USBCtrlEPServiceComplete(void)
00356  *
00357  * PreCondition:    None
00358  *
00359  * Input:           None
00360  *
00361  * Output:          None
00362  *
00363  * Side Effects:    None
00364  *
00365  * Overview:        This routine wrap up the ramaining tasks in servicing
00366  *                  a Setup Request. Its main task is to set the endpoint
00367  *                  controls appropriately for a given situation. See code
00368  *                  below.
00369  *                  There are three main scenarios:
00370  *                  a) There was no handler for the Request, in this case
00371  *                     a STALL should be sent out.
00372  *                  b) The host has requested a read control transfer,
00373  *                     endpoints are required to be setup in a specific way.
00374  *                  c) The host has requested a write control transfer, or
00375  *                     a control data stage is not required, endpoints are
00376  *                     required to be setup in a specific way.
00377  *
00378  *                  Packet processing is resumed by clearing PKTDIS bit.
00379  *
00380  * Note:            None
00381  *****************************************************************************/
00382 void USBCtrlEPServiceComplete(void)
00383 {
00384     if(ctrl_trf_session_owner == MUID_NULL)
00385     {
00386         /*
00387          * If no one knows how to service this request then stall.
00388          * Must also prepare EP0 to receive the next SETUP transaction.
00389          */
00390         ep0Bo.Cnt = EP0_BUFF_SIZE;
00391         ep0Bo.ADR = (byte*)&SetupPkt;
00392         
00393         ep0Bo.Stat._byte = _USIE|_BSTALL;
00394         ep0Bi.Stat._byte = _USIE|_BSTALL;
00395     }
00396     else    // A module has claimed ownership of the control transfer session.
00397     {
00398         if(SetupPkt.DataDir == DEV_TO_HOST)
00399         {
00400             if(SetupPkt.wLength < wCount._word)
00401                 wCount._word = SetupPkt.wLength;
00402             USBCtrlTrfTxService();
00403             ctrl_trf_state = CTRL_TRF_TX;
00404             /*
00405              * Control Read:
00406              * <SETUP[0]><IN[1]><IN[0]>...<OUT[1]> | <SETUP[0]>
00407              * 1. Prepare OUT EP to respond to early termination
00408              *
00409              * NOTE:
00410              * If something went wrong during the control transfer,
00411              * the last status stage may not be sent by the host.
00412              * When this happens, two different things could happen
00413              * depending on the host.
00414              * a) The host could send out a RESET.
00415              * b) The host could send out a new SETUP transaction
00416              *    without sending a RESET first.
00417              * To properly handle case (b), the OUT EP must be setup
00418              * to receive either a zero length OUT transaction, or a
00419              * new SETUP transaction.
00420              *
00421              * Since the SETUP transaction requires the DTS bit to be
00422              * DAT0 while the zero length OUT status requires the DTS
00423              * bit to be DAT1, the DTS bit check by the hardware should
00424              * be disabled. This way the SIE could accept either of
00425              * the two transactions.
00426              *
00427              * Furthermore, the Cnt byte should be set to prepare for
00428              * the SETUP data (8-byte or more), and the buffer address
00429              * should be pointed to SetupPkt.
00430              */
00431             ep0Bo.Cnt = EP0_BUFF_SIZE;
00432             ep0Bo.ADR = (byte*)&SetupPkt;            
00433             ep0Bo.Stat._byte = _USIE;           // Note: DTSEN is 0!
00434     
00435             /*
00436              * 2. Prepare IN EP to transfer data, Cnt should have
00437              *    been initialized by responsible request owner.
00438              */
00439             ep0Bi.ADR = (byte*)&CtrlTrfData;
00440             ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN;
00441         }
00442         else    // (SetupPkt.DataDir == HOST_TO_DEV)
00443         {
00444             ctrl_trf_state = CTRL_TRF_RX;
00445             /*
00446              * Control Write:
00447              * <SETUP[0]><OUT[1]><OUT[0]>...<IN[1]> | <SETUP[0]>
00448              *
00449              * 1. Prepare IN EP to respond to early termination
00450              *
00451              *    This is the same as a Zero Length Packet Response
00452              *    for control transfer without a data stage
00453              */
00454             ep0Bi.Cnt = 0;
00455             ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN;
00456 
00457             /*
00458              * 2. Prepare OUT EP to receive data.
00459              */
00460             ep0Bo.Cnt = EP0_BUFF_SIZE;
00461             ep0Bo.ADR = (byte*)&CtrlTrfData;
00462             ep0Bo.Stat._byte = _USIE|_DAT1|_DTSEN;
00463         }//end if(SetupPkt.DataDir == DEV_TO_HOST)
00464     }//end if(ctrl_trf_session_owner == MUID_NULL)
00465     
00466     /*
00467      * PKTDIS bit is set when a Setup Transaction is received.
00468      * Clear to resume packet processing.
00469      */
00470     UCONbits.PKTDIS = 0;
00471 
00472 }//end USBCtrlEPServiceComplete
00473 
00474 /******************************************************************************
00475  * Function:        void USBPrepareForNextSetupTrf(void)
00476  *
00477  * PreCondition:    None
00478  *
00479  * Input:           None
00480  *
00481  * Output:          None
00482  *
00483  * Side Effects:    None
00484  *
00485  * Overview:        The routine forces EP0 OUT to be ready for a new Setup
00486  *                  transaction, and forces EP0 IN to be owned by CPU.
00487  *
00488  * Note:            None
00489  *****************************************************************************/
00490 void USBPrepareForNextSetupTrf(void)
00491 {
00492     ctrl_trf_state = WAIT_SETUP;            // See usbctrltrf.h
00493     ep0Bo.Cnt = EP0_BUFF_SIZE;              // Defined in usbcfg.h
00494     ep0Bo.ADR = (byte*)&SetupPkt;
00495     ep0Bo.Stat._byte = _USIE|_DAT0|_DTSEN;  // EP0 buff dsc init, see usbmmap.h
00496     ep0Bi.Stat._byte = _UCPU;               // EP0 IN buffer initialization
00497 }//end USBPrepareForNextSetupTrf
00498 
00499 /** EOF usbctrltrf.c *********************************************************/

Generated on Wed Jun 8 03:49:39 2005 for cdc by  doxygen 1.4.2