www.pudn.com > SMSC USB2.0.zip > fmcapp.c
/*============================================================================
____________________________________________________________________________
______________________________________________
SSSS M M CCCC Standard Microsystems Corporation
S MM MM SSSS C Austin Design Center
SSS M M M S C 11000 N. Mopac Expressway
S M M SSS C Stonelake Bldg. 6, Suite 500
SSSS M M S CCCC Austin, Texas 78759
SSSS ______________________________________________
____________________________________________________________________________
Copyright(C) 1999, Standard Microsystems Corporation
All Rights Reserved.
This program code listing is proprietary to SMSC and may not be copied,
distributed, or used without a license to do so. Such license may have
Limited or Restricted Rights. Please refer to the license for further
clarification.
____________________________________________________________________________
Notice: The program contained in this listing is a proprietary trade
secret of SMSC, Hauppauge, New York, and is copyrighted
under the United States Copyright Act of 1976 as an unpublished work,
pursuant to Section 104 and Section 408 of Title XVII of the United
States code. Unauthorized copying, adaption, distribution, use, or
display is prohibited by this law.
____________________________________________________________________________
Use, duplication, or disclosure by the Government is subject to
restrictions as set forth in subparagraph(c)(1)(ii) of the Rights
in Technical Data and Computer Software clause at DFARS 52.227-7013.
Contractor/Manufacturer is Standard Microsystems Corporation,
80 Arkay Drive, Hauppauge, New York, 1178-8847.
____________________________________________________________________________
____________________________________________________________________________
fmcapp.c - the application interface manager and main application thread.
____________________________________________________________________________
comments tbd
____________________________________________________________________________
Revision History
Date Who Comment
________ ___ _____________________________________________________________
09/14/01 cds moved from atapi.c to help isolate the stages. this abstraction
could cost some performance, however.
05/31/00 tbh initial version
============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
// USER INTERFACE MODULE
//
// mass storage, bulk only, atapi
//
////////////////////////////////////////////////////////////////////////////////
#include "fmc.h"
// -----------------------------------------------------------------------------
// Begin Source
// -----------------------------------------------------------------------------
//------------------------------------------------------------------------------
// special smsc hardware debug registers
//------------------------------------------------------------------------------
bit g_device_present ;
bit g_poll_for_drq ;
bit g_use_dma ;
bit g_disable_iordy ;
bit g_data_direction ; /* 1 = k_data_in, 0 = k_data_out */
bit g_prevent_reset ; /* 1=k_true, 0=k_false. Don't keep resetting the device during enumeration */
bit g_device_present ; /* 1=k_true, 0=k_false. This doesn't mean the device is an ATAPI device! */
bit g_forced_phase_error;
bit g_tx_missed_ack;
bit g_doing_dma ;
// device type
#define k_device_type_ata 0
#define k_device_type_atapi 1
#define k_device_type_floppy 2
// ata device characteristics
uint8 g_dev_max_dma_mode ; /* represents max DMA mode supported by the device */
//------------------------------------------------------------------------------
// global variables - these can be cleaned up, and probably placed into
// our x_data buffer, freeing up ram for some other optimization
//------------------------------------------------------------------------------
uint8 g_ix_ata_thread;
uint32 g_original_request_length ;
// pio DRQ-block transfer variables
uint32 g_remaining_drq_length ;
uint16 g_available_pkt_length ;
uint16 g_available_pkt ; // offset of next available byte. k_data_in: next free, k_data_out: next valid
uint8 g_available_buffer ; // start sending to host on.... 0 = A , 1 = B
uint8 g_last_packet ;
uint16 g_ata_data_xfer_length ; /* Data Transfer Length for use ONLY with the Ata state machine */
static void fmcapp_cfc_init_done() reentrant ;
//------------------------------------------------------------------------------
// <<< ATA INTERFACE - MANAGER >>>
// Target MCU:
// 200
// Declaration:
// uint8 ata_mngr(t_message *msgp);
// Purpose:
// This is the manager for all things related to the ata interface.
// Arguments:
// None.
// Return:
// k_success
// K-error
// Note:
// Do NOT yield from this routine. It is NOT part of any thread. It does
// not execute in an any thread's context. Yielding from within this function
// will cause your firmware to crash.
//------------------------------------------------------------------------------
uint8 fmcapp_mngr(t_message *msgp) reentrant
{
uint8 i ;
TRACE1(328, fmc, 0, "+fmcapp_mngr() msg_id:%d", message_rd_id(msgp));
switch(message_rd_id(msgp))
{
//--------------------------------------------------------------------------
// always return k_success for these.
//--------------------------------------------------------------------------
case k_msg_initialize:
TRACE0(329, fmcapp, 1, "k_msg_initialize");
#ifdef TRACE
// print out compile-time options
fmcapp_trace_compiled_opts() ;
#endif
// create thread
g_ix_ata_thread = thread_create(fmcapp_create_thread, NULL, k_true);
// register endpoints - do nothing here as only the default control pipe is used
ctl_bind_endpoint(2, g_ix_ata_thread, NULL);
ctl_bind_endpoint(2, g_ix_ata_thread, NULL);
// register interfaces - must jive with the configuration descriptor...
ctl_bind_interface(0, fmcapp_cpex);
// set up the gpio interface
gpio_initialize();
// application initializations
for(i=0;i>>
// Target MCU:
// 200
// Declaration:
// uint8 ata_cpex(t_message *msgp);
// Purpose:
// Handles requests targeted to its interface: standard, class, vendor.
// Arguments:
// None.
// Return:
// k_success - Causes the protocol engine to complete the status stage successfully.
// k_error - Causes the protocol engine to stall the control pipe.
// k_in_progress - For k_msg_source_payload, causes the protocol engine to deliver
// another empty packet buffer to the cpex to be loaded for transmission.
// For k_msg_sink_payload, informs the protocol engine that the cpex expects at
// least one more payload buffer to be delivered to it by the protocol engine.
// k_finished - For k_msg_source_payload and k_msg_sink_payload, informs the
// protocol engine that the data phase is complete and no more data is expected
// in either direction.
// Note:
// Do NOT yield from this routine. It is part of the protocol engine's thread.
// It executes in the context of g_ix_ctl_thread. Yielding from within this
// function will cause the protocol engine's state machine to float belly up.
// And that will cause your firmware to shuffle off this mortal coil, post haste.
//------------------------------------------------------------------------------
uint8 fmcapp_cpex(t_message *msgp) reentrant
{
uint8 pktsz;
uint8 pnr_loc;
t_usb_rqst *rqstp;
rqstp = (t_usb_rqst *)(message_rd_arg(msgp));
switch(message_rd_id(msgp))
{
// standard requests
//--------------------------------------------------------------------------
// Note - the 97C2xx has an SIE that is smart enough to handle most standard
// control requests. therefore, many of these messages won't appear in this cpex
// as they would if this were built for the 100 or 102 mcu's
// class specific requests
//--------------------------------------------------------------------------
case k_cls_mass_storage_reset:
trace0(0, atapi, 0, "got k_hci_msc_reset");
// command block reset
// $$$ cds to do - we MUST find a way to NAK the host until
// the reset has occured by order of the Mass Storage Class Spec
// fmc_soft_reset()...
// for now, just send a usbreset and return success... it'll work, but it's technically
// non compliant for devices that actually send this message
thread_set_sync(g_ix_ata_thread, kbm_sync_usbrst) ;
return k_success;
case k_cls_mass_storage_get_max_lun:
trace0(0, atapi, 0, "got k_dci_msc_get_max_lun");
g_tmp = 0;
// tell the data pump where to find it and how much there is
_payload_source(&g_tmp, k_lun_max);
return k_success;
// os messages
case k_msg_source_payload:
// load some application specific data into a packet buffer
// return k_in_progress if app expects to be supply at least one more packet's worth of data
// return k_finished otherwise
pnr_loc = *(uint8 *)(message_rd_arg(msgp));
pktsz = _min(g_data_len, k_maxpktsz);
g_data_len -= pktsz;
mmu_wr_pkt(0, pnr_loc, g_source_addr, pktsz);
g_source_addr += pktsz;
#ifdef k_mcu_97200
x_ep0tx_bc = pktsz;
#endif
return g_data_len ? k_in_progress : k_finished;
case k_msg_sink_payload:
// unload data from a packet buffer and do something application specific with it
// return k_in_progress if app can process this request
// return k_finished otherwise
pnr_loc = *(uint8 *)(message_rd_arg(msgp));
#ifdef k_mcu_97200
pktsz = x_ep0rx_bc;
#else
pktsz = _min(g_data_len, k_maxpktsz);
#endif
g_data_len -= pktsz;
mmu_rd_pkt(pnr_loc, pktsz, g_sink_addr);
g_sink_addr += pktsz;
return g_data_len ? k_in_progress : k_finished;
default:
return k_error;
}
return k_error;
}
//------------------------------------------------------------------------------
// <<< ATA INTERFACE - POLLER >>>
// Target MCU:
// 200
// Declaration:
// void ctl_poll(void);
// Purpose:
// Poll for non-interrupt events related to this interface and synchronize
// the associated thread(s).
// Arguments:
// None.
// Return:
// None.
// Note:
// Do NOT yield from this routine. It is NOT part of any thread. It does
// not execute in an any thread's context. Yielding from within this function
// will cause your firmware to flounder, panic, flail, and eventually expire.
//------------------------------------------------------------------------------
// i think we may need this...
// implement ata_poll_whatever() here if you end up needing it...
//------------------------------------------------------------------------------
// <<< ATA INTERFACEE - THREAD >>>
// Target MCU:
// 200
// Purpose:
// Handles the application specific peripheral control state machine for this
// interface.
//------------------------------------------------------------------------------
/*****************************************************************************/
/* ATAPI_CreateThread aka wait_until_atapi_thread_gets_created() */
/*****************************************************************************/
void fmcapp_init_2() reentrant ;
void fmcapp_init_3() reentrant ;
void fmcapp_init_4() reentrant ;
void fmcapp_create_thread() reentrant
{
TRACE0(332, fmcapp, 0, "+fmcapp_create_thread()") ;
// initialize fmcapp state variables
g_available_pkt_length = 0x0000;
#if defined(k_mcu_97200) || defined(k_mcu_97201)
// frob the fmc registers to prepare the fmc hardware.
// clr muxen to select ATA interface.
x_ata_ctl |= kbm_ata_ctl_out_control ;
x_ata_ctl &= ~kbm_ata_ctl_muxen ;
#endif
#if defined(k_mcu_97210)
// initialize the compact flash controller & device
thread_run_dfa(fmc_init, NULL, fmcapp_init_2) ;
#endif
}
//------------------------------------------------------------------------------
void fmcapp_trace_compiled_opts() reentrant
{
TRACE0(335, fmcapp, 0, "** SMSC Flash Media Controller Configuration **") ;
TRACE4(336, fmcapp, 0, " -firmware version: %d.%d.%d.%d", kbcd_dev_version_major, kbcd_dev_version_minor, kbcd_dev_version_external_change, kbcd_dev_version_internal_change) ;
TRACE1(337, fmcapp, 0, " -dma support: %c", k_dma_mode > 0 ? 'Y' : 'N' ) ;
if(k_dma_mode > 0)
{
switch(k_dma_mode)
{
case k_dma_mode_multiword_0 :
trace0(0, atapi, 0, "DMA Mode: Multiword Mode 0") ;
break;
case k_dma_mode_multiword_1 :
trace0(0, atapi, 0, "DMA Mode: Multiword Mode 1") ;
break;
case k_dma_mode_multiword_2 :
trace0(0, atapi, 0, "DMA Mode: Multiword Mode 2") ;
break;
case k_dma_mode_ultra_dma_0 :
trace0(0, atapi, 0, "DMA Mode: Ultra DMA Mode 0") ;
break;
case k_dma_mode_ultra_dma_1 :
trace0(0, atapi, 0, "DMA Mode: Ultra DMA Mode 1") ;
break;
case k_dma_mode_ultra_dma_2 :
trace0(0, atapi, 0, "DMA Mode: Ultra DMA Mode 2") ;
break;
case k_dma_mode_ultra_dma_3 :
trace0(0, atapi, 0, "DMA Mode: Ultra DMA Mode 3") ;
break;
case k_dma_mode_ultra_dma_4 :
trace0(0, atapi, 0, "DMA Mode: Ultra DMA Mode 4") ;
break;
case k_dma_mode_ultra_dma_5 :
trace0(0, atapi, 0, "DMA Mode: Ultra DMA Mode 5") ;
break;
default:
trace1(0, atapi, 0, "DMA Mode: Unknown Mode Specifed (%d)", k_dma_mode) ;
break;
}
trace1(0, atapi, 0, "DMA Used for Data In (ATA to SIE): %c", (k_dma_data_in ? 'Y' : 'N') ) ;
trace1(0, atapi, 0, "DMA Used for Data Out (SIE to ATA): %c", (k_dma_data_out ? 'Y' : 'N') ) ;
}
#ifdef SHADOW_PIO_COMPLETE
TRACE0(338, fmcdev, 0, "Shadow PIO_COMPLETE: Y") ;
#else
TRACE0(339, fmcdev, 0, "Shadow PIO_COMPLETE: N") ;
#endif
#ifdef k_support_ata
TRACE0(340, fmcdev, 0, "ATA Device Support:Y") ;
#else
TRACE0(341, fmcdev, 0, "ATA Device Support:N") ;
#endif
}