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 *********************************************************/