www.pudn.com > SMSC USB2.0.zip > device_new.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. 
  ____________________________________________________________________________ 
  ____________________________________________________________________________ 
 
  device.c - the device manager implementarion 
  ____________________________________________________________________________ 
 
  comments tbd 
  ____________________________________________________________________________ 
 
  Revision History 
  Date      Who  Comment 
  ________  ___  _____________________________________________________________ 
  05/31/00  tbh  initial version 
  09/04/01  tbh  auto version the product string. 
                 add reserved space to work with dfu on the 201 
  09/05/01  tbh  changed set_config arg to value instead of reference since cannot 
                 use address of sfr.  (building with registers as sfr instead 
                 of xdata reveled this compilation issue) 
  09/##/01  tbh  optimized for speed 
  11/07/01  rcc  added phy #define below to choose your klsi phy rev see dev_intitilize 
  11/26/01  cds  fixed dev_source_eeprom to return correct string length in 
                 response to a 2-byte get_descriptor (string) request. 
  11/28/01  tbh  modified eeprom source/sink to work with writeee.exe. 
  12/01/01  tbh  added all 210 interrupts.  added code to probe cards. 
  01/15/02  cds  fixed version string generation to use two digits when the 
                 version constant is >= 0x10, not > 0x10. 
  02/26/02  tbh  added logical to physical lun mapping 
                 changed strcpy to strncpy for safety 
  03/11/02  tbh  added usage of in dev_intr bit g_force_media_changed.  then removed it. 
  03/12/02  tbh  changed card establish to media change handler. 
  03/28/02  tbh  make sure phy lun for mmc is init'd on power up. 
  04/01/02  ds   Enabled proper handling of the k_irq_fmc_err_sd_blk_ovrun intr, instead of handling it in 
                 case k_irq_fmc_err 
  04/01/02  tbh  only init logical luns < k_max_log_lun 
  04/15/02  tbh  remembed previous configuration so on usb reset can check to 
                 see if had been configured 
  04/18/02  cds  added thread_set_sync(g_ix_dev_thread, kbm_sync_fmc_blk) to the 
                 dev_intr handlers which intercept the smart media ecc detection bits so that 
                 it can stop the fmc_xfer and allow a resume. 
  04/24/02  tbh  added k_dvd_inq_devid, upgraded eeprom support to use new 201 scheme 
  04/25/02  tbh  top level device thread now does not attempt to scan card slots 
                 for media change until after the device has fully enumerated 
                 through set-config(1) (which results in a dev_pwr_up()) so that 
                 the dev_pwr_up() does not cause re-initialization of all of the 
                 cards.  this fixes the bug with wp-sd card on pwr on, and speeds 
                 up enumeration. 
  06/19/02  tbh  the mscbot dfa has been replaced with a high priority thread. 
                 so the device thread had to be rewritten essentially from the 
                 ground up to accomodate it. 
                 added handler for k_irq_fmc_sdc_flash_prg_err, 
                 enhanced handler for k_irq_fmc_sdc_crc_err 
  06/20/02  cds  added nand hd lun initialization, if it is included in the build options. 
  06/20/02  tbh  fixed a problem of powering on with no media and havinf the host 
                 try to do a read even avter seeing a no-media sense code. 
  06/21/02  tbh  don't probe cards on an inquiry command, to make working 
                 when plugin with 4 cards laded on MacOS X 10.1.5 
============================================================================*/ 
#define __device_dot_c__ 
#include "project.h" 
#include "dev.h" 
 
//------------------------------------------------------------------------------ 
// required global constant to communicate desired settings to minimos 
#ifdef k_pfm_6126 
code t_dev_attribute_mask k_dev_attributes = kbm_hub_enabled; 
#else 
code t_dev_attribute_mask k_dev_attributes = kbm_none; 
#endif 
 
//------------------------------------------------------------------------------ 
// device id to avoid use of driver with roque devices 
static code uint8 _devid[] = {'C','o','p','y','r','i','g','h','t',' ','(','C',')',' ','2','0','0','2',' ','S','M','S','C',0}; 
 
//------------------------------------------------------------------------------ 
// offset into the device descriptor for sundry items 
#define k_ix_dev_vid_lo  8 
#define k_ix_dev_vid_hi  9 
#define k_ix_dev_pid_lo  10 
#define k_ix_dev_pid_hi  11 
#define k_ix_dev_ver_lo  12 
#define k_ix_dev_ver_hi  13 
 
//------------------------------------------------------------------------------ 
// vendor id and product id (SMSC -> 0106 dec = 0424 hex) 
#define k_vendorhi         0x04  // vendor id hi 
#define k_vendorlo         0x24  // vendor id lo 
#define k_dev_producthi    0x20  // product id hi 
// #define k_dev_productlo    0xFC  // product id lo 
#define k_dev_productlo    0xCD  // product id lo 
 
//------------------------------------------------------------------------------ 
// version descriptor (not a usb thing, its used by the smsc romset utility) 
// $$$ note that romset as is wont work on this because there are now multiple 
// device and configuration descriptors.  romset needs to be updated. 
uint8 code g_version[] = {k_vendorhi, k_vendorlo, k_dev_producthi, k_dev_productlo, kbcd_dev_version_major, kbcd_dev_version_minor}; 
 
//------------------------------------------------------------------------------ 
// this app is downloadable via dfu, so we must reserve a hole in code space 
// to make dfu work properly on the 201... 
#if !defined(k_ram_isr) && !defined(k_support_otprom) 
uint8 code reserved[768] _at_ 0x0400; 
#endif 
 
//------------------------------------------------------------------------------ 
// string descriptors (in a form that the smsc romset utility can use) 
#define _hi_digit(b) ((uint8) (((uint8)(b>>4)&0x0F) + (uint8)'0')),0 
#define _lo_digit(b) ((uint8) (((uint8)(b   )&0x0F) + (uint8)'0')),0 
uint8 code g_str_lng[4] = {4, 3, 0x09, 0x04};  // (English lo 0x09, hi 0x04) 
uint8 code g_str_mfg[17][2] = {10, 3, "S", "M", "S", "C"}; 
uint8 code g_str_prd[63][2] = 
{ 
  62, 3, 
  "F", "l", "a", "s", "h", 
  " ", "M", "e", "d", "i", 
  "a", " ", "C", "o", "n", 
  "t", "r", "o", "l", "l", 
  "e", "r", " ", 
#if (kbcd_dev_version_major>=0x10) 
  _hi_digit(kbcd_dev_version_major), 
#endif 
  _lo_digit(kbcd_dev_version_major), ".", 
 
#if (kbcd_dev_version_minor>=0x10) 
  _hi_digit(kbcd_dev_version_minor), 
#endif 
  _lo_digit(kbcd_dev_version_minor), ".", 
 
#if (kbcd_dev_version_external_change>=0x10) 
  _hi_digit(kbcd_dev_version_external_change), 
#endif 
  _lo_digit(kbcd_dev_version_external_change), ".", 
 
#if (kbcd_dev_version_internal_change>=0x10) 
  _hi_digit(kbcd_dev_version_internal_change), 
#endif 
  _lo_digit(kbcd_dev_version_internal_change) 
}; 
uint8 code g_str_ser[41][2] = {64, 3, " "}; 
uint8 code *code g_str_dscr[k_dev_max_string] = {g_str_lng, g_str_mfg, g_str_prd, g_str_ser}; 
 
//------------------------------------------------------------------------------ 
// string descriptor indicies 
#define k_dev_idx_str_dscr_lng 0 
#define k_dev_idx_str_dscr_mfg 1 
#define k_dev_idx_str_dscr_prd 2 
#define k_dev_idx_str_dscr_ser 3 
 
//------------------------------------------------------------------------------ 
// device descriptor 
//------------------------------------------------------------------------------ 
// full speed device descriptor 
uint8 code g_fs_dev_dscr[] = 
{ 
  k_usb_devdscrsz,                // length of descriptor in bytes 
  k_usb_dscr_typ_device,          // descriptor type: device 
  0x10,                           // usb version lo 
  0x01,                           // usb version hi 
  0x00,                           // device class: see interfaces 
  0x00,                           // subclass:  see interfaces 
  0x00,                           // protocol:  see interfaces 
  k_maxpktsz,                     // ndp 0 max packet size (8,16,32,64) 
  k_vendorlo,                     // vendor lo 
  k_vendorhi,                     // vendor hi 
  k_dev_productlo,                // product lo 
  k_dev_producthi,                // product hi 
  kbcd_dev_version_minor,         // device release lo 
  kbcd_dev_version_major,         // device release hi 
  k_dev_idx_str_dscr_mfg,         // manufacturer string index 
  k_dev_idx_str_dscr_prd,         // product string index 
  0,                              // serial string index 
  k_dev_max_configuration         // number of configurations 
}; 
// full speed device descriptor with serial number - cds 
uint8 code g_fs_dev_dscr_w_ser[] = 
{ 
  k_usb_devdscrsz,                // length of descriptor in bytes 
  k_usb_dscr_typ_device,          // descriptor type: device 
  0x10,                           // usb version lo 
  0x01,                           // usb version hi 
  0x00,                           // device class: see interfaces 
  0x00,                           // subclass:  see interfaces 
  0x00,                           // protocol:  see interfaces 
  k_maxpktsz,                     // ndp 0 max packet size (8,16,32,64) 
  k_vendorlo,                     // vendor lo 
  k_vendorhi,                     // vendor hi 
  k_dev_productlo,                // product lo 
  k_dev_producthi,                // product hi 
  kbcd_dev_version_minor,         // device release lo 
  kbcd_dev_version_major,         // device release hi 
  k_dev_idx_str_dscr_mfg,         // manufacturer string index 
  k_dev_idx_str_dscr_prd,         // product string index 
  k_dev_idx_str_dscr_ser,         // cds - serial string index 
  k_dev_max_configuration         // number of configurations 
}; 
 
//------------------------------------------------------------------------------ 
// high speed device descriptor 
uint8 code g_hs_dev_dscr[] = 
{ 
  k_usb_devdscrsz,                // length of descriptor in bytes 
  k_usb_dscr_typ_device,          // descriptor type: device 
  0x00,                           // usb version lo 
  0x02,                           // usb version hi 
  0x00,                           // device class: see interfaces 
  0x00,                           // subclass:  see interfaces 
  0x00,                           // protocol:  see interfaces 
  k_maxpktsz,                     // ndp 0 max packet size (8,16,32,64) 
  k_vendorlo,                     // vendor lo 
  k_vendorhi,                     // vendor hi 
  k_dev_productlo,                // product lo 
  k_dev_producthi,                // product hi 
  kbcd_dev_version_minor,         // device release lo 
  kbcd_dev_version_major,         // device release hi 
  k_dev_idx_str_dscr_mfg,         // manufacturer string index 
  k_dev_idx_str_dscr_prd,         // product string index 
  0,                              // serial string index 
  k_dev_max_configuration         // number of configurations 
}; 
// high speed device descriptor with serial number - cds 
uint8 code g_hs_dev_dscr_w_ser[] = 
{ 
  k_usb_devdscrsz,                // length of descriptor in bytes 
  k_usb_dscr_typ_device,          // descriptor type: device 
  0x00,                           // usb version lo 
  0x02,                           // usb version hi 
  0x00,                           // device class: see interfaces 
  0x00,                           // subclass:  see interfaces 
  0x00,                           // protocol:  see interfaces 
  k_maxpktsz,                     // ndp 0 max packet size (8,16,32,64) 
  k_vendorlo,                     // vendor lo 
  k_vendorhi,                     // vendor hi 
  k_dev_productlo,                // product lo 
  k_dev_producthi,                // product hi 
  kbcd_dev_version_minor,         // device release lo 
  kbcd_dev_version_major,         // device release hi 
  k_dev_idx_str_dscr_mfg,         // manufacturer string index 
  k_dev_idx_str_dscr_prd,         // product string index 
  k_dev_idx_str_dscr_ser,         // cds - serial string index 
  k_dev_max_configuration         // number of configurations 
}; 
 
//------------------------------------------------------------------------------ 
// device qualifier descriptor 
//------------------------------------------------------------------------------ 
// full speed device qualifier descriptor 
uint8 code g_fs_devqual_dscr[] = 
{ 
  k_usb_devqualdscrsz,            // length of descriptor in bytes 
  k_usb_dscr_typ_devqual,         // descriptor type: device qualifier 
  0x00,                           // usb version lo 
  0x02,                           // usb version hi 
  0x00,                           // device class: see interfaces 
  0x00,                           // subclass:  see interfaces 
  0x00,                           // protocol:  see interfaces 
  k_maxpktsz,                     // ndp 0 max packet size, other speed 
  k_dev_max_configuration,        // number of other speed configurations 
  0                               // reserved 
}; 
 
//------------------------------------------------------------------------------ 
// high speed device qualifier descriptor 
uint8 code g_hs_devqual_dscr[] = 
{ 
  k_usb_devqualdscrsz,            // length of descriptor in bytes 
  k_usb_dscr_typ_devqual,         // descriptor type: device qualifier 
  0x00,                           // usb version lo 
  0x02,                           // usb version hi 
  0x00,                           // device class: see interfaces 
  0x00,                           // subclass:  see interfaces 
  0x00,                           // protocol:  see interfaces 
  k_maxpktsz,                     // ndp 0 max packet size, other speed 
  k_dev_max_configuration,        // number of other speed configurations 
  0                               // reserved 
}; 
 
//------------------------------------------------------------------------------ 
// configuration descriptor 
//------------------------------------------------------------------------------ 
// full speed configuration descriptor 
uint8 code g_fs_cfg_dscr[] = 
{ 
  k_usb_cfgdscrsz,                // length of descriptor in bytes 
  k_usb_dscr_typ_config,          // descriptor type: configuration 
  k_usb_cfgdscrsz + 
  k_usb_ifcdscrsz + 
  k_usb_ndpdscrsz + 
  k_usb_ndpdscrsz,                // total length lo 
  0,                              // total length hi 
  1,                              // number of interfaces   2 to accomodate the DFU 
  0x01,                           // configuration value 
  0x00,                           // index of string descriptor 
  0xC0,                           // attributes: self powered, no remote wakeup 
  0x01,                           // _max power: 2ma 
  // interface descriptor: BOT mass storage 
  k_usb_ifcdscrsz,                // length of descriptor in bytes 
  k_usb_dscr_typ_interface,       // descriptor type: interface 
  0,                              // interface number 
  0,                              // alternate interface 
  2,                              // number of endpoints 
  0x08,                           // usb interface class: mass storage 
  0x06,                           // usb interface subclass: scsi 
  0x50,                           // interface protocol: BOT (bulk only transport) 
  0x00,                           // interface string index 
  // endpoint descriptor: bulk out 
  k_usb_ndpdscrsz,                // length of descriptor in bytes 
  0x05,                           // descriptor type: endpoint 
  0x02,                           // endpoint 2, out 
  0x02,                           // bulk 
  k_fs_maxpktsz,                  // max packet size lo 
  0x00,                           // max packet size hi 
  0x01,                           // polling interval 
  // endpoint descriptor: bulk in 
  k_usb_ndpdscrsz,                // length of descriptor in bytes 
  0x05,                           // descriptor type: endpoint 
  0x82,                           // endpoint 2, in 
  0x02,                           // bulk 
  k_fs_maxpktsz,                  // max packet size lo 
  0x00,                           // max packet size hi 
  0x00                            // polling interval 
}; 
 
//------------------------------------------------------------------------------ 
// high speed configuration descriptor 
uint8 code g_hs_cfg_dscr[] = 
{ 
  k_usb_cfgdscrsz,                // length of descriptor in bytes 
  k_usb_dscr_typ_config,          // descriptor type: configuration 
  k_usb_cfgdscrsz + 
  k_usb_ifcdscrsz + 
  k_usb_ndpdscrsz + 
  k_usb_ndpdscrsz,                // total length lo 
  0,                              // total length hi 
  1,                              // number of interfaces 
  0x01,                           // configuration value 
  0x00,                           // index of string descriptor 
  0xC0,                           // attributes: self powered, no remote wakeup 
  0x01,                           // _max power: 2ma 
  // interface descriptor: BOT mass storage 
  k_usb_ifcdscrsz,                // length of descriptor in bytes 
  k_usb_dscr_typ_interface,       // descriptor type: interface 
  0,                              // interface number 
  0,                              // alternate interface 
  2,                              // number of endpoints 
  0x08,                           // usb interface class: mass storage 
  0x06,                           // usb interface subclass: scsi 
  0x50,                           // interface protocol: BOT (bulk only transport) 
  0x00,                           // interface string index 
  // endpoint descriptor: bulk out 
  k_usb_ndpdscrsz,                // length of descriptor in bytes 
  0x05,                           // descriptor type: endpoint 
  0x02,                           // endpoint 2, out 
  0x02,                           // bulk 
  _l(k_hs_maxpktsz),              // max packet size lo 
  _h(k_hs_maxpktsz),              // max packet size hi 
  0x01,                           // polling interval 
  // endpoint descriptor: bulk in 
  k_usb_ndpdscrsz,                // length of descriptor in bytes 
  0x05,                           // descriptor type: endpoint 
  0x82,                           // endpoint 2, in 
  0x02,                           // bulk 
  _l(k_hs_maxpktsz),              // max packet size lo 
  _h(k_hs_maxpktsz),              // max packet size hi 
  0x00,                           // polling interval 
}; 
 
//------------------------------------------------------------------------------ 
// other speed configuration descriptor 
//------------------------------------------------------------------------------ 
// full speed other speed configuration descriptor 
uint8 code g_fs_oscfg_dscr[] = 
{ 
  k_usb_cfgdscrsz,                // length of descriptor in bytes 
  k_usb_dscr_typ_osconfig,        // descriptor type: other speed configuration 
  k_usb_cfgdscrsz + 
  k_usb_ifcdscrsz + 
  k_usb_ndpdscrsz + 
  k_usb_ndpdscrsz,                // total length lo 
  0,                              // total length hi 
  1,                              // number of interfaces 
  0x01,                           // configuration value 
  0x00,                           // index of string descriptor 
  0xC0,                           // attributes: self powered, no remote wakeup 
  0x01,                           // _max power: 2ma 
  // interface descriptor: BOT mass storage 
  k_usb_ifcdscrsz,                // length of descriptor in bytes 
  k_usb_dscr_typ_interface,       // descriptor type: interface 
  0,                              // interface number 
  0,                              // alternate interface 
  2,                              // number of endpoints 
  0x08,                           // usb interface class: mass storage 
  0x06,                           // usb interface subclass: scsi 
  0x50,                           // interface protocol: BOT (bulk only transport) 
  0x00,                           // interface string index 
  // endpoint descriptor: bulk out 
  k_usb_ndpdscrsz,                // length of descriptor in bytes 
  0x05,                           // descriptor type: endpoint 
  0x02,                           // endpoint 2, out 
  0x02,                           // bulk 
  k_fs_maxpktsz,                  // max packet size lo 
  0x00,                           // max packet size hi 
  0x01,                           // polling interval 
  // endpoint descriptor: bulk in 
  k_usb_ndpdscrsz,                // length of descriptor in bytes 
  0x05,                           // descriptor type: endpoint 
  0x82,                           // endpoint 2, in 
  0x02,                           // bulk 
  k_fs_maxpktsz,                  // max packet size lo 
  0x00,                           // max packet size hi 
  0x00,                           // polling interval 
}; 
 
//------------------------------------------------------------------------------ 
// high speed other speed configuration descriptor 
uint8 code g_hs_oscfg_dscr[] = 
{ 
  k_usb_cfgdscrsz,                // length of descriptor in bytes 
  k_usb_dscr_typ_osconfig,        // descriptor type: other speed configuration 
  k_usb_cfgdscrsz + 
  k_usb_ifcdscrsz + 
  k_usb_ndpdscrsz + 
  k_usb_ndpdscrsz,                // total length lo 
  0,                              // total length hi 
  1,                              // number of interfaces 
  0x01,                           // configuration value 
  0x00,                           // index of string descriptor 
  0xC0,                           // attributes: self powered, no remote wakeup 
  0x01,                           // _max power: 2ma 
  // interface descriptor: BOT mass storage 
  k_usb_ifcdscrsz,                // length of descriptor in bytes 
  k_usb_dscr_typ_interface,       // descriptor type: interface 
  0,                              // interface number 
  0,                              // alternate interface 
  2,                              // number of endpoints 
  0x08,                           // usb interface class: mass storage 
  0x06,                           // usb interface subclass: scsi 
  0x50,                           // interface protocol: BOT (bulk only transport) 
  0x00,                           // interface string index 
  // endpoint descriptor: bulk out 
  k_usb_ndpdscrsz,                // length of descriptor in bytes 
  0x05,                           // descriptor type: endpoint 
  0x02,                           // endpoint 2, out 
  0x02,                           // bulk 
  _l(k_hs_maxpktsz),              // max packet size lo 
  _h(k_hs_maxpktsz),              // max packet size hi 
  0x01,                           // polling interval 
  // endpoint descriptor: bulk in 
  k_usb_ndpdscrsz,                // length of descriptor in bytes 
  0x05,                           // descriptor type: endpoint 
  0x82,                           // endpoint 2, in 
  0x02,                           // bulk 
  _l(k_hs_maxpktsz),              // max packet size lo 
  _h(k_hs_maxpktsz),              // max packet size hi 
  0x00,                           // polling interval 
}; 
 
//------------------------------------------------------------------------------ 
// globals 
uint8 g_ix_dev_thread; 
#define g_ix_mscbot_thread g_ix_dev_thread 
 
#define k_ix_ser      0 
#define k_sz_ser      26 
#define k_ix_vid_lo   26 
#define k_ix_vid_hi   27 
#define k_ix_pid_lo   28 
#define k_ix_pid_hi   29 
#define k_ix_lng      30 
#define k_sz_lng      4 
#define k_ix_mfr      34 
#define k_sz_mfr      60 
#define k_ix_prd      94 
#define k_sz_prd      60 
#define k_ix_attr_hi  154 
#define k_ix_attr_lh  155 
#define k_ix_attr_hl  156 
#define k_ix_attr_lo  157 
 
 
// 158<->251 reserved 
 
// ata0 format signature 
#define k_ix_ata0_sig_hi  252 
#define k_ix_ata0_sig_lh  253 
#define k_ix_ata0_sig_hl  254 
#define k_ix_ata0_sig_lo  255 
#define k_ata0_sig_hi     0x61 // 'a' 
#define k_ata0_sig_lh     0x74 // 't' 
#define k_ata0_sig_hl     0x61 // 'a' 
#define k_ata0_sig_lo     0x30 // '0' 
 
 
 
// locals 
// static bit _source_eeprom_raw;    // true to source as serial num, false to source as string dscr 
static bit _nvram_data_valid; 
static bit _nvram_insert_vidpid; 
static xdata uint8 _nvram_ix; 
static xdata uint16 _nvram_sz; 
static bit _serial_number_valid; 
 
//------------------------------------------------------------------------------ 
// must store a copy of config so it can be checked after the usbrst arrives 
// since on the 20x family the configuration is cleared by hardware. 
static uint8 _most_recent_config = 0; 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   dev_exception 
// 
// Declaration: 
//   void dev_exception(void); 
// 
// Purpose: 
//   Hard error.  Log message to trace fifo and halt. 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   Does not return.No return value. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
void dev_exception(uint16 ec) reentrant 
{ 
  ec=ec;                          // keep compiler happy for release builds 
  trace0(0, stk, 0, "** fatal exception **"); 
  trace1(0, stk, 0, "  code:  %04x", ec); 
  trace1(0, stk, 0, "  thd:   %d", g_tid); 
  thread_halt(); 
} 
 
//------------------------------------------------------------------------------ 
// Declaration: 
//   uint8 dev_rd_most_recent_config(void); 
// 
// Purpose: 
//   Report the most recent value set by a "set_configuration" request. 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   A uint8 representing the most recent usb configuration value. 
//------------------------------------------------------------------------------ 
uint8 dev_rd_most_recent_config() reentrant 
{ 
  return _most_recent_config; 
} 
 
//------------------------------------------------------------------------------ 
// Declaration: 
//   void dev_wr_most_recent_config(uint8 cfg); 
// 
// Purpose: 
//   Allow interface managers to clear it before rebooting. 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   A uint8 representing the most recent usb configuration value. 
//------------------------------------------------------------------------------ 
void dev_wr_most_recent_config(uint8 cfg) reentrant 
{ 
  _most_recent_config = cfg; 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   dev_initialize 
// 
// Declaration: 
//   void dev_initialize(void); 
// 
// Purpose: 
//   Called once on POR.  initialize device hardware. 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   None. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
static void dev_initialize(void) reentrant; 
static void dev_initialize() reentrant 
{ 
  TRACE0(1, dev, 1, "dev_initialize()" ); 
 
#ifdef k_mcu_97201 
 
 
  // setup ATA control register.  clr muxen to select ATA interface. 
  _mcu_register_set_bits(x_ata_ctl, kbm_ata_ctl_out_control); 
  _mcu_register_clr_bits(x_ata_ctl, kbm_ata_ctl_muxen); 
  // initialize test register so proper phy will be controlled 
  #ifdef k_rev_c_klsi_phy 
  XBYTE[0x3F10] = 0x01;           // rev C klsi phy 
  #else 
  XBYTE[0x3F10] = 0x00;           // rev A klsi phy 
  #endif 
#endif 
#ifdef k_mcu_97210 
  #ifdef k_pkg_100 
  TRACE0(2, dev, 0, "package: 100 pin"); 
  _mcu_register_set_bits( x_fmc_mode_ctl, kbm_fmc_mode_ctl_mux_en ); 
  #endif 
  #ifdef k_pkg_128 
  TRACE0(3, dev, 0, "package: 128 pin"); 
  _mcu_register_clr_bits( x_fmc_mode_ctl, kbm_fmc_mode_ctl_mux_en ); 
  #endif 
#endif 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   dev_power_up 
// 
// Declaration: 
//   void dev_power_up(void); 
// 
// Purpose: 
//   Called on set-config(1), and resume if configuration is non-zero. 
//   Power on the flash media sockets as appropriate. 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   None. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
static void dev_power_up(void) reentrant; 
static void dev_power_up() reentrant 
{ 
  uint8 ps; 
 
  TRACE0(4, dev, 1, "dev_power_up()" ); 
 
  // temporary - disable card status change irq's on power down, enable on power up 
  irq_control(k_irq_crd_sts_chg, kbm_irqctl_clear |kbm_irqctl_unmask); 
 
  ps = _mcu_register_rd(x_crd_ps); 
  // compact flash 
#if (k_log_lun_cf < k_max_log_lun) 
  if (ps & kbm_crd_ps_cf) 
  { 
    TRACE0(5, dev, 0, "_cf_pwr_on()") ; 
    _cf_pwr_on(); 
    _inserted(k_lun_cf); 
  #ifdef k_pfm_led 
    _mcu_register_clr_bits(x_gpiob_out,  kbm_gpio13); 
  #endif 
  } 
#endif 
  // memory stick 
#if (k_log_lun_ms < k_max_log_lun) 
  if (ps & kbm_crd_ps_ms) 
  { 
    _ms_pwr_on(); 
    _inserted(k_lun_ms); 
  #ifdef k_pfm_led 
    _mcu_register_clr_bits(x_gpiob_out,  kbm_gpio12); 
  #endif 
  } 
#endif 
  // smart media 
#if (k_log_lun_sm < k_max_log_lun) 
  if (ps & kbm_crd_ps_sm) 
  { 
    _sm_pwr_on(); 
    _inserted(k_lun_sm); 
  #ifdef k_pfm_led 
    _mcu_register_clr_bits(x_gpiob_out,  kbm_gpio14); 
  #endif 
 
  } 
#endif 
  // secure digital / multi media card 
#if (k_log_lun_sd < k_max_log_lun) 
  _sd_pwr_off(); 
  #ifdef k_pfm_led 
  _mcu_register_clr_bits(x_gpiob_out,  kbm_gpio15); 
  #endif 
  _sd_inserted_ejected(); 
  _lun_map_log2phy(k_log_lun_sd, k_lun_sd); 
#endif 
 
  // nand drive 
#if (k_log_lun_nand < k_max_log_lun) 
  _nand_pwr_on(); 
  // $$$ cds - this doesn't really make sense for a fixed drive. 
  // Will have to figure something out... like moving this to a lun-specific 
  // location 
  _inserted(k_lun_nand); 
  #ifdef k_pfm_led 
    _mcu_register_clr_bits(x_gpiob_out,  kbm_gpio14); 
  #endif 
#endif 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   dev_power_dn 
// 
// Declaration: 
//   void dev_power_dn(void); 
// 
// Purpose: 
//   Called on set-config(0), and suspend if configuration is non-zero. 
//   Power off the flash media sockets and mark the media as ejected. 
// 
// Arguments: 
//   None. 
// 
// Return: 
//   None. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
static void dev_power_dn(void) reentrant; 
static void dev_power_dn() reentrant 
{ 
  TRACE0(6, dev, 1, "dev_power_dn()" ); 
 
  // temporary - disable card status change irq's on power down, enable on power up 
  irq_control(k_irq_crd_sts_chg, kbm_irqctl_mask); 
 
  // simulate eject on all cards 
  _ejected(k_lun_cf); 
  _ejected(k_lun_ms); 
  _ejected(k_lun_sm); 
  //_sd_inserted_ejected(); 
  // turn off all power to cards, indicator leds, etc 
  gpio_clrbit(0); 
  _mcu_register_set_bits(x_gpiob_out, kbm_gpio8 |kbm_gpio9 |kbm_gpio10 |kbm_gpio11 |kbm_gpio12 |kbm_gpio13 |kbm_gpio14 |kbm_gpio15); 
 
#ifdef k_pfm_led 
 
 
  // turn off the activity/inserted LEDs 
  _mcu_register_clr_bits(x_gpiob_out, kbm_gpio12 |kbm_gpio13 |kbm_gpio14 |kbm_gpio15); 
#endif 
 
} 
 
 
//------------------------------------------------------------------------------ 
// prototypes 
// top level state machine for built only transport 
static void dev_thread_wait_csw(void) reentrant; 
static void dev_thread_wait_cbw(void) reentrant; 
static void dev_thread_wait_create1(void) reentrant; 
static void dev_thread_wait_create(void) reentrant; 
 
//------------------------------------------------------------------------------ 
// Declaration: 
//   t_result dev_mngr(t_message *msgp); 
// 
// Purpose: 
//   This is the manager for all things related to the whole device. 
// 
// 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. 
// 
// Since: 
//   u2dp-1.0 
//------------------------------------------------------------------------------ 
t_result dev_mngr(t_message_ref msgp) reentrant 
{ 
  uint8 lun; 
 
  TRACE0(31, dev, 0, "dev_mngr()"); 
  switch (message_rd_id(msgp)) 
  { 
    case k_msg_initialize: 
      TRACE0(32, dev, 0, "k_msg_initialize"); 
      //fmc_dump_registers(); 
      // create threads 
      g_ix_dev_thread = thread_create(dev_thread_wait_create, NULL, k_yes); 
      // set up the gpio interface 
      gpio_initialize(); 
      // initialize the application 
      dev_initialize(); 
      // set the output bits, turn them all off 
      gpio_bit_is_output(0); 
      gpio_bit_is_output(5); 
      _mcu_register_set_bits(x_gpiob_dir, kbm_gpio8 |kbm_gpio9 |kbm_gpio10 |kbm_gpio11 |kbm_gpio12 |kbm_gpio13 |kbm_gpio14 |kbm_gpio15); 
      _mcu_register_set_bits(x_gpiob_out, kbm_gpio8 |kbm_gpio9 |kbm_gpio10 |kbm_gpio11 |kbm_gpio12 |kbm_gpio13 |kbm_gpio14 |kbm_gpio15); 
      // data access led off 
      gpio_clrbit(0);             // 0 is off 
      gpio_setbit(5);             // 1 is off 
      // card power 
      #if (k_log_lun_cf < k_max_log_lun) 
      TRACE0(33, dev, 0, "_cf_pwr_off()") ; 
      _cf_pwr_off(); 
      #endif 
      #if (k_log_lun_ms < k_max_log_lun) 
      _ms_pwr_off(); 
      #endif 
      #if (k_log_lun_sm < k_max_log_lun) 
      _sm_pwr_on();               // must be on at power up to initialize inserted card, if present 
      #endif 
      #if (k_log_lun_sd < k_max_log_lun) 
      _sd_pwr_off(); 
      #endif 
      #if (k_log_lun_nand < k_max_log_lun) 
      _nand_pwr_on();               // must be on at power up to initialize chips & retrieve boot block 
      #endif 
 
       #ifdef k_pfm_demo 
      // turn off the debug lights of science 
      _mcu_register_set_bits(x_gpiob_out, kbm_gpio12 |kbm_gpio13 |kbm_gpio14 |kbm_gpio15); 
      #endif 
 
      #ifdef k_pfm_led 
      // turn off the activity/inserted LEDs 
      _mcu_register_clr_bits(x_gpiob_out, kbm_gpio12 |kbm_gpio13 |kbm_gpio14 |kbm_gpio15); 
      #endif 
 
      #ifdef k_pfm_profile 
      _profile_initialize(); 
      #endif 
 
      // initialize the application specific interface managers 
      mscbot_mngr(msgp); 
      // setup the default logical to physical lun mapping 
      if (k_log_lun_cf < k_max_log_lun) 
      { 
        _lun_map_log2phy(k_log_lun_cf, k_lun_cf); 
      } 
      if (k_log_lun_ms < k_max_log_lun) 
      { 
        _lun_map_log2phy(k_log_lun_ms, k_lun_ms); 
      } 
      if (k_log_lun_sm < k_max_log_lun) 
      { 
        _lun_map_log2phy(k_log_lun_sm, k_lun_sm); 
      } 
      if (k_log_lun_sd < k_max_log_lun) 
      { 
        _lun_map_log2phy(k_log_lun_sd, k_lun_sd); 
      } 
      if (k_log_lun_nand < k_max_log_lun) 
      { 
        _lun_map_log2phy(k_log_lun_nand, k_lun_nand); 
      } 
 
      // initialize the physical luns 
      for (lun=0; lunwLengthHi; 
  g_wtmp *= 256; 
  g_wtmp += (uint16)rqstp->wLengthLo; 
  switch (message_rd_id(msgp)) 
  { 
    case k_dsd_usb_get_descriptor: 
      _nvram_insert_vidpid = k_false; 
      _nvram_ix = 0; 
      _nvram_sz = 0; 
      TRACE3(39, dev, 0, "wLengthHi:%02X wLengthLo:%02X wtmp:%d", rqstp->wLengthHi, rqstp->wLengthLo, g_wtmp); 
      switch (rqstp->wValueHi) 
      { 
        case k_usb_dscr_typ_device: 
          TRACE0(40, dev, 0, "RQ_GET_DESCRIPTOR: device"); 
          // tell the data pump where to find it and how much there is 
          if (sie_is_high_speed()) 
          { 
            // eeprom vid/pid => if eeprom is valid, insert vidpid 
            _nvram_insert_vidpid = _nvram_data_valid; 
            _payload_source((_serial_number_valid?(&g_hs_dev_dscr_w_ser):(&g_hs_dev_dscr)), _min(g_hs_dev_dscr[0], g_wtmp)); 
          } 
          else 
          { 
            // eeprom vid/pid => if eeprom is valid, insert vidpid 
            _nvram_insert_vidpid = _nvram_data_valid; 
            _payload_source((_serial_number_valid?(&g_fs_dev_dscr_w_ser):(&g_fs_dev_dscr)), _min(g_fs_dev_dscr[0], g_wtmp)); 
          } 
          break; 
 
        case k_usb_dscr_typ_devqual: 
          TRACE0(41, dev, 0, "RQ_GET_DESCRIPTOR: devqual"); 
          // tell the data pump where to find it and how much there is 
          if (sie_is_high_speed()) 
          { 
            _payload_source(&g_fs_devqual_dscr, _min(g_fs_devqual_dscr[0], g_wtmp)); 
          } 
          else 
          { 
            _payload_source(&g_hs_devqual_dscr, _min(g_hs_devqual_dscr[0], g_wtmp)); 
          } 
          break; 
 
        case k_usb_dscr_typ_config: 
          TRACE0(42, dev, 0, "RQ_GET_DESCRIPTOR: configuration"); 
          // make sure it is in the supported range 
          if (rqstp->wValueLo > k_dev_max_configuration) 
            return k_error; 
          // tell the data pump where to find it and how much there is 
          if (sie_is_high_speed()) 
          { 
            _payload_source(&g_hs_cfg_dscr, _min(g_hs_cfg_dscr[2], g_wtmp)); 
          } 
          else 
          { 
            _payload_source(&g_fs_cfg_dscr, _min(g_fs_cfg_dscr[2], g_wtmp)); 
          } 
          break; 
 
        case k_usb_dscr_typ_osconfig: 
          TRACE0(43, dev, 0, "RQ_GET_DESCRIPTOR: other speed configuration"); 
          // make sure it is in the supported range 
          if (rqstp->wValueLo > k_dev_max_configuration) 
            return k_error; 
          // tell the data pump where to find it and how much there is 
          if (sie_is_high_speed()) 
          { 
            _payload_source( &g_fs_oscfg_dscr, _min(g_fs_oscfg_dscr[2], g_wtmp)); 
          } 
          else 
          { 
            _payload_source(&g_hs_oscfg_dscr, _min(g_hs_oscfg_dscr[2], g_wtmp)); 
          } 
          break; 
 
        case k_usb_dscr_typ_string: 
          TRACE0(44, dev, 0, "RQ_GET_DESCRIPTOR: string"); 
          // make sure it is in the supported range 
          if (rqstp->wValueLo >= k_dev_max_string) 
            return k_error; 
          #ifdef k_support_nvram 
          // tell the data pump where to find it and how much there is 
          // grab string from rom, unless its asking for the serial number... 
          if (_nvram_data_valid) 
          { 
            switch (rqstp->wValueLo) 
            { 
              case k_dev_idx_str_dscr_lng: 
                TRACE0(45, dev, 0, "source: eeprom Language ID String descriptor"); 
                _nvram_ix  = k_ix_lng;  // data only (same semantics as _source_eeprom_raw=k_false) 
                _nvram_sz  = nvram_read(k_ix_lng); 
                break; 
 
              case k_dev_idx_str_dscr_mfg: 
                TRACE0(46, dev, 0, "source: eeprom Manufacturer ID String descriptor"); 
                _nvram_ix  = k_ix_mfr;  // data only (same semantics as _source_eeprom_raw=k_false) 
                _nvram_sz  = nvram_read(k_ix_mfr); 
                break; 
 
              case k_dev_idx_str_dscr_prd: 
                TRACE0(47, dev, 0, "source: eeprom Product ID String descriptor"); 
                _nvram_ix  = k_ix_prd;  // data only (same semantics as _source_eeprom_raw=k_false) 
                _nvram_sz  = nvram_read(k_ix_prd); 
                break; 
 
              case k_dev_idx_str_dscr_ser: 
                // ... in which case, extract it from the eeprom 
                if (_serial_number_valid) 
                { 
                  TRACE0(48, dev, 0, "source: eeprom Serial Number String descriptor"); 
                  _nvram_ix  = k_ix_ser;  // data only (same semantics as _source_eeprom_raw=k_false) 
                  _nvram_sz  = nvram_read(k_ix_ser); 
                } 
                else 
                { 
                  TRACE0(49, dev, 0, "warning:  source, eeprom Serial Number String, not valid.  no serial # reported"); 
                  return k_error; 
                } 
                break; 
              default: 
                TRACE1(50, dev, 0, "warning:  no string descriptor at index %d", rqstp->wValueLo); 
                return k_error; 
            } 
            // send it along 
            // _payload_source(NULL, _min(eeprom_read(_nvram_ix), g_wtmp)); 
            _payload_source(NULL, _min(_nvram_sz, g_wtmp)); 
          } 
          else 
          { 
            if (rqstp->wValueLo != k_dev_idx_str_dscr_ser) 
            { 
              TRACE0(51, dev, 0, "source:  default string descriptor"); 
              _payload_source(g_str_dscr[rqstp->wValueLo], _min(*((uint8 *)g_str_dscr[rqstp->wValueLo]), g_wtmp)); 
            } 
            else 
            { 
              // cannot happen 
              TRACE1(52, dev, 0, "warning:  no string descriptor at index %d", rqstp->wValueLo); 
              return k_error; 
            } 
          } 
          #else 
          TRACE0(53, dev, 0, "source:  default string descriptor (eeprom support disabled)"); 
          _payload_source(g_str_dscr[rqstp->wValueLo], _min(*((uint8 *)g_str_dscr[rqstp->wValueLo]), g_wtmp)); 
          #endif 
          break; 
 
        default: 
          return k_error; 
      } 
      return k_success; 
 
    case k_hsd_usb_set_configuration: 
      TRACE0(54, dev, 0, "RQ_SET_CONFIGURATION"); 
      if ((uint8)message_rd_arg(msgp))  // unconfigured -> configured 
        dev_power_up(); 
      else 
        dev_power_dn(); 
      dev_wr_most_recent_config(sie_rd_configuration()); 
      return k_success; 
 
      // vendor specific requests 
    case k_hci_dfu_detach: 
      trace0(0, dfu, 0, "k_hci_dfu_detach"); 
      return dfu_cpex(msgp); 
 
    case k_hvd_wr_eerom: 
      TRACE1(55, dev, 0, "k_hvd_wr_eerom - length:%d", g_wtmp); 
      _nvram_ix = 0; 
      _nvram_sz = 256; 
      _payload_sink(NULL, _min(256, g_wtmp)); 
      return k_success; 
 
    case k_dvd_rd_eerom: 
      TRACE1(56, dev, 0, "k_hvd_rd_eerom - length:%d", g_wtmp); 
      _nvram_ix = 0; 
      _nvram_sz = 256; 
      _payload_source(NULL, _min(256, g_wtmp)); 
      return k_success; 
 
    case k_dvd_inq_devid: 
      TRACE0(57, dev, 0, "k_dvd_inq_devid"); 
      _payload_source(_devid, sizeof(_devid)); 
      return k_success; 
 
      // requests from the usb protocol engine 
    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 = *(uint8 *)message_rd_arg(msgp); 
      pktsz = _min(g_data_len, k_maxpktsz); 
      g_data_len -= pktsz; 
      TRACE2(58, dev, 0, "k_msg_source_payload - pnr:%d pktsz:%d", pnr, pktsz); 
      // NULL addr means read non-volitile memory location like eeprom, flashed config info or hard-coded bytes 
      #ifdef k_support_nvram 
      if (NULL == g_source_addr) 
      { 
        nvram_source_payload(pnr, pktsz) ; 
      } 
      else 
      #endif 
      { 
        // write the default data 
        mmu_wr_pkt(0, pnr, g_source_addr, pktsz); 
 
        #ifdef k_support_nvram 
        if ( _nvram_insert_vidpid ) 
        { 
          // overwrite the default data with eeprom vid-pid 
          mcu_begin_critical_section(); 
          _mcu_register_wr(x_sram_addr_lo, (k_pkt_addrlo[pnr]+k_ix_dev_vid_lo) ); 
          _mcu_register_wr(x_sram_addr_hi, k_pkt_addrhi[pnr]); 
 
          _mcu_register_wr(x_sram_data, nvram_read(k_ix_vid_lo)); 
          _mcu_register_wr(x_sram_data, nvram_read(k_ix_vid_hi)); 
          _mcu_register_wr(x_sram_data, nvram_read(k_ix_pid_lo)); 
          _mcu_register_wr(x_sram_data, nvram_read(k_ix_pid_hi)); 
 
          _nvram_insert_vidpid = k_false; 
          mcu_end_critical_section(); 
        } 
        #endif 
        g_source_addr += pktsz; 
      } 
      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 = *(uint8 *)message_rd_arg(msgp); 
      TRACE1(59, dev, 0, "and the packet number is:%d", pnr); 
      pktsz = _min(g_data_len, k_maxpktsz); 
      g_data_len -= pktsz; 
      #ifdef k_support_nvram 
 
      // NULL means write the eeprom 
      if (NULL == g_sink_addr) 
      { 
        nvram_sink_payload(pnr, pktsz) ; 
      } 
      else 
      #endif 
      { 
        mmu_rd_pkt(pnr, pktsz, g_sink_addr); 
        g_sink_addr += pktsz; 
      } 
      return g_data_len ? k_in_progress : k_finished; 
 
    default: 
      return k_error; 
  } 
  return k_error; 
} 
 
//------------------------------------------------------------------------------ 
// Declaration: 
//   t_result dev_intr(uint8 intr); 
// 
// Purpose: 
//   Handle interrupts. 
// 
// Arguments: 
//   intr - the interrupt that occurred. It is a number, not a bitmask. 
// 
// Return: 
//   k_ignored - causes default processing within the kernel isr 
//   k_success - prevents default processing within the kernel isr 
// 
// Note: 
//   This function is called from the kernel isrs.  Therefore it executes at 
//   interrupt level, not foreground level. 
// 
//   This function uses register bank 1 (as do the kernel's isrs) so you cannot 
//   call any function that is not wrapped by the #pragma NOAREGS. 
//   Only functions wrapped by this #pragma are callable from the isrs 
//   (except this one, of course, because it explicitly uses register bank 1...) 
// 
//   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. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
extern t_isr_fragment _hpbot_thread_entry; 
t_result dev_intr(uint8 intr) reentrant using 1 
{ 
  t_result rslt; 
 
  TRACE1(60, dev, 1, "-(dev_intr(%d))", intr); 
  _stack_check(); 
 
  // give first crack at it to the high priority interrupt chain 
  rslt = k_ignored; 
  if (_hpbot_thread_entry) 
    rslt = (*_hpbot_thread_entry)(intr); 
  if (rslt != k_ignored) 
    return rslt; 
 
  // high priority interupt chain didn't process it, so synchronize the foreground 
  switch (intr) 
  { 
    case k_irq_ramwr_a:           // external0 
      // current xfer TO sram buffer A has completed 
      TRACE0(61, dev, 1, "--(k_irq_ramwr_a)"); 
      thread_set_sync(g_ix_dev_thread, kbm_sync_usbrx); 
      return k_ignored; 
 
    case k_irq_ramwr_b:           // external0 
      // current xfer TO sram buffer B has completed 
      TRACE0(62, dev, 1, "--(k_irq_ramwr_b)"); 
      thread_set_sync(g_ix_dev_thread, kbm_sync_usbrx); 
      return k_ignored; 
 
    case k_irq_ramrd_a:           // external0 
      // current xfer FROM sram buffer A has completed 
      TRACE0(63, dev, 1, "--(k_irq_ramrd_a)"); 
      thread_set_sync(g_ix_dev_thread, kbm_sync_usbtx); 
      return k_ignored; 
 
    case k_irq_ramrd_b:           // external0 
      // current xfer FROM sram buffer B has completed 
      TRACE0(64, dev, 1, "--(k_irq_ramrd_b)"); 
      thread_set_sync(g_ix_dev_thread, kbm_sync_usbtx); 
      return k_ignored; 
 
    case k_irq_nak2rx:            // external5 
      TRACE0(65, dev, 1, "--(k_irq_nak2rx)"); 
      // set our usr synchronizer, knl isr auto-masked the nak irq 
      thread_set_sync(g_ix_dev_thread, kbm_sync_outnak); 
      return k_ignored; 
 
    case k_irq_nak2tx:            // external5 
      TRACE0(66, dev, 1, "--(k_irq_nak2tx)"); 
      // set our usr synchronizer, knl isr auto-masked the nak irq 
      thread_set_sync(g_ix_dev_thread, kbm_sync_innak); 
      return k_ignored; 
 
    case k_irq_usb_reset: 
      TRACE0(67, dev, 1, "--(k_irq_usb_reset)"); 
    case k_irq_usb_stat_reset:    // external0/x_usb_stat 
      // indicates that a usb reset has been detected 
      //TRACE0(95, dev, 1, "--(k_irq_usb_stat_reset)"); 
      // don't disturb the mscbot thread if we aren't even enumerated yet 
      // because its probably initializing the drive still 
      if (dev_rd_most_recent_config()) 
      { 
        // make sure to clear it so next reset during re-enum 
        // will not keep continually resetting the mcu. 
        dev_wr_most_recent_config(0); 
        TRACE0(68, dev, 1, "setting reset synch because configuration is set"); 
        thread_set_sync(g_ix_dev_thread, kbm_sync_usbrst); 
      } 
      return k_ignored; 
 
    case k_irq_blk_xfer_complete: // external 0 
      TRACE0(69, dev, 1, "--(k_irq_blk_xfer_complete)"); 
      thread_set_sync(g_ix_dev_thread, kbm_sync_fmc_blk); 
      x_imr0 |= kbm_isr0_blk_xfer_complete;  //!!! persistent??? 
      return k_success; 
 
    case k_irq_fmc:               // external0 
      TRACE0(70, dev, 1, "--(k_irq_fmc)"); 
      // may have to expand this function to decide _who_ interrupted us at this point 
      // by checking on who is currently in control of the mux 
      thread_set_sync(g_ix_dev_thread, kbm_sync_fmc_irq); 
      x_imr0 |= kbm_isr0_fmc_irq; 
      return k_success; 
 
    case k_irq_fmc_cfc_dev_err:   // cfc_stat 
      TRACE0(71, dev, 1, "--(k_irq_fmc_cfc_dev_err)"); 
      return k_success; 
 
    case k_irq_fmc_iordy_err:     // cfc_stat 
      TRACE0(72, dev, 1, "--(k_irq_fmc_iordy_err)"); 
      return k_success; 
 
    case k_irq_fmc_cfc_intrq:     // cfc_stat 
      TRACE0(73, dev, 1, "--(k_irq_fmc_cfc_intrq)"); 
      return k_success; 
 
    case k_irq_fmc_cfc_xrdy:      // cfc_stat 
      TRACE0(74, dev, 1, "--(k_irq_fmc_cfc_xrdy)"); 
      return k_success; 
 
    case k_irq_fmc_cfc_rrdy:      // cfc_stat 
      TRACE0(75, dev, 1, "--(k_irq_fmc_cfc_rrdy)"); 
      return k_success; 
 
    case k_irq_fmc_sm_ecc_err_d_a:  // smc_stat 
      TRACE0(76, dev, 1, "--(k_irq_fmc_sm_ecc_err_d_a)"); 
      thread_set_sync(g_ix_dev_thread, kbm_sync_fmc_blk); 
      return k_success; 
 
    case k_irq_fmc_sm_ecc_err_d_b:  // smc_stat 
      TRACE0(77, dev, 1, "--(k_irq_fmc_sm_ecc_err_d_b)"); 
      thread_set_sync(g_ix_dev_thread, kbm_sync_fmc_blk); 
      return k_success; 
 
    case k_irq_fmc_sm_ecc_err_c_a:  // smc_stat 
      TRACE0(78, dev, 1, "--(k_irq_fmc_sm_ecc_err_c_a)"); 
      thread_set_sync(g_ix_dev_thread, kbm_sync_fmc_blk); 
      return k_success; 
 
    case k_irq_fmc_sm_ecc_err_c_b:  // smc_stat 
      TRACE0(79, dev, 1, "--(k_irq_fmc_sm_ecc_err_c_b)"); 
      thread_set_sync(g_ix_dev_thread, kbm_sync_fmc_blk); 
      return k_success; 
 
    case k_irq_fmc_sm_rdy:        // smc_stat 
      TRACE0(80, dev, 1, "--(k_irq_fmc_sm_rdy)"); 
      return k_success; 
 
    case k_irq_fmc_msc_rdy:       // msc_stat 
      TRACE0(81, dev, 1, "--(k_irq_fmc_msc_rdy)"); 
      return k_success; 
 
    case k_irq_fmc_msc_sif_int:   // msc_stat 
      TRACE0(82, dev, 1, "--(k_irq_fmc_msc_sif_int)"); 
      return k_success; 
 
    case k_irq_fmc_msc_drq:       // msc_stat 
      TRACE0(83, dev, 1, "--(k_irq_fmc_msc_drq)"); 
      return k_success; 
 
    case k_irq_fmc_msc_crc_err:   // msc_stat 
      TRACE0(84, dev, 1, "--(k_irq_fmc_msc_crc_err)"); 
      return k_success; 
 
    case k_irq_fmc_msc_timeout_err:  // msc_stat 
      TRACE0(85, dev, 1, "--(k_irq_fmc_msc_timeout_err)"); 
      return k_success; 
 
    case k_irq_fmc_sdc_crc_err:   // sdc_stat 
      TRACE0(86, dev, 1, "--(k_irq_fmc_sdc_crc_err)"); 
      //set the abort sync, so that we can exit immediately from wait_xxx_timeout functions 
      thread_set_sync(g_ix_dev_thread, kbm_sync_abort); 
      // mask the intrrupt so it doesn't disturb us 
      irq_control(k_irq_fmc_sdc_crc_err, kbm_irqctl_clear |kbm_irqctl_mask); 
      return k_success; 
 
    case k_irq_fmc_sdc_crd_rdy:   // sdc_stat 
      TRACE0(87, dev, 1, "--(k_irq_fmc_sdc_crd_rdy)"); 
      return k_success; 
 
    case k_irq_fmc_sdc_rsp_rdy:   // sdc_stat 
      TRACE0(88, dev, 1, "--(k_irq_fmc_sdc_rsp_rdy)"); 
      return k_success; 
 
    case k_irq_fmc_sdc_cmd_rdy:   // sdc_stat 
      TRACE0(89, dev, 1, "--(k_irq_fmc_sdc_cmd_rdy)"); 
      return k_success; 
 
    case k_irq_fmc_sdc_flash_prg_err:  // external0 
      TRACE0(90, dev, 1, "--(k_irq_fmc_sdc_flash_prg_err)"); 
      //set the abort sync, so that we can exit immediately from wait_xxx_timeout functions 
      thread_set_sync(g_ix_dev_thread, kbm_sync_abort); 
      // mask the intrrupt so it doesn't disturb us 
      irq_control(k_irq_fmc_sdc_flash_prg_err, kbm_irqctl_clear |kbm_irqctl_mask); 
      return k_success; 
 
    case k_irq_cf_insert:         // external2 
      TRACE0(91, dev, 1, "--(k_irq_cf_insert, media present, media unknown, media_changed)"); 
      TRACE0(92, dev, 0, "_cf_pwr_on()") ; 
      _cf_pwr_on(); 
      _inserted(k_lun_cf); 
      #ifdef k_pfm_led 
      _mcu_register_set_bits(x_gpiob_out,  kbm_gpio13); 
      #endif 
      return k_ignored; 
 
    case k_irq_ms_insert:         // external2 
      TRACE0(93, dev, 1, "--(k_irq_ms_insert, media present, media unknown, media_changed)"); 
      _ms_pwr_on(); 
      _inserted(k_lun_ms); 
      #ifdef k_pfm_led 
      _mcu_register_set_bits(x_gpiob_out,  kbm_gpio12); 
      #endif 
      return k_ignored; 
 
    case k_irq_sm_insert:         // external2 
      TRACE0(94, dev, 1, "--(k_irq_sm_insert, media present, media unknown, media_changed)"); 
      _sm_pwr_on(); 
      _inserted(k_lun_sm); 
      #ifdef k_pfm_led 
      _mcu_register_set_bits(x_gpiob_out,  kbm_gpio14); 
      #endif 
      return k_ignored; 
 
    case k_irq_cf_eject:          // external2 
      TRACE0(95, dev, 1, "--(k_irq_cf_eject, no media)"); 
      TRACE0(96, dev, 0, "_cf_pwr_off()") ; 
      _cf_pwr_off(); 
      _ejected(k_lun_cf); 
      #ifdef k_pfm_led 
      _mcu_register_clr_bits(x_gpiob_out,  kbm_gpio13); 
      #endif 
      return k_ignored; 
 
    case k_irq_ms_eject:          // external2 
      TRACE0(97, dev, 1, "--(k_irq_ms_eject, no media)"); 
      _ms_pwr_off(); 
      _ejected(k_lun_ms); 
      #ifdef k_pfm_led 
      _mcu_register_clr_bits(x_gpiob_out,  kbm_gpio12); 
      #endif 
      return k_ignored; 
 
    case k_irq_sm_eject:          // external2 
      TRACE0(98, dev, 1, "--(k_irq_sm_eject, no media)"); 
      _sm_pwr_off(); 
      _ejected(k_lun_sm); 
      #ifdef k_pfm_led 
      _mcu_register_clr_bits(x_gpiob_out,  kbm_gpio14); 
      #endif 
      return k_ignored; 
 
    case k_irq_sd_insert_eject:   // external2 
      _lun_map_log2phy(k_log_lun_sd, k_lun_sd); 
      // don't mask the interrupt back in here, dfa_sd_initialize() does it when its done. 
      TRACE0(99, dev, 1, "--(k_irq_sd_insert_eject)"); 
      _lun_map_log2phy(k_log_lun_sd, k_lun_sd); 
      _mcu_register_clr_bits(x_crd_ps, kbm_crd_ps_sd |kbm_crd_ps_mmc); 
      #ifdef k_pfm_led 
      _mcu_register_clr_bits(x_gpiob_out,  kbm_gpio15); 
      #endif 
      _inserted(k_lun_sd); 
      _inserted(k_lun_mmc); 
      return k_ignored; 
 
    case k_irq_fmc_err_sd_blk_ovrun:  // external2 
      TRACE0(100, dev, 1, "--(k_irq_fmc_err_sd_blk_ovrun)"); 
      //set the abort sync, so that we can exit immediately from wait_xxx_timeout functions 
      thread_set_sync(g_ix_dev_thread, kbm_sync_abort); 
      // mask the intrrupt so it doesn't disturb us 
      irq_control(k_irq_fmc_err_sd_blk_ovrun, kbm_irqctl_clear |kbm_irqctl_mask); 
      return k_ignored; 
 
    default: 
      return k_ignored; 
  } 
  // how'd we get here? 
  return k_error; 
} 
 
//------------------------------------------------------------------------------ 
// holds return values from dfa's, accessed via argp. 
static t_result _result; 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   media_changed1 
// 
// Declaration: 
//   void media_changed1(void); 
// 
// Purpose: 
//   Called once per lun per media change. 
//   Runs _dfa_lun_initialize_media 
// 
// Arguments: 
//   None. 
//   However, relies on g_active_lun. 
//   Activates on kbm_sync_create. 
// 
// Return: 
//   No return value. 
//   However, the DFA's argument pointer is written with a t_result indicating: 
//     k_success - command completed. 
//     k_usbrst  - usb reset signalling was detected while executing the command. 
//     k_aborted - traffic occurred on the control pipe while wexecuting the command (probably a mass storage reset). 
//     k_timeout - a timeout limit exceeded while executing the command. 
//   (This allows the caller to see the return value, via the argp, after the DFA terminates). 
// 
// Notes: 
//   This is a STATE in a DFA, not a FUNCTION. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
static void media_changed1(void) reentrant; 
static void media_changed1() reentrant 
{ 
  TRACE0(101, dev, 0, "media_changed1()"); 
  // check the results of _dfa_lun_reset_media... 
  if ((k_success == _result) && _lun_is_media_changed(g_active_lun)) 
  { 
    // init media and return to dev_thread_wait_cbw 
    thread_run_dfa(_dfa_lun_initialize_media(g_active_lun), (void*) &_result, thread_end_dfa); 
  } 
  // reset failed, skip init, return to dev_thread_wait_cbw 
  thread_end_dfa(); 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   dfa_media_changed 
// 
// Declaration: 
//   void dfa_media_changed(void); 
// 
// Purpose: 
//   Run once per lun per media change. 
//   Runs _dfa_lun_reset_media 
// 
// Arguments: 
//   None. 
//   However, the physical lun number must be passed in the thread's argp field. 
//   Activates on kbm_sync_create. 
// 
// Return: 
//   No return value. 
//   However, the DFA's argument pointer is written with a t_result indicating: 
//     k_success - command completed. 
//     k_usbrst  - usb reset signalling was detected while executing the command. 
//     k_aborted - traffic occurred on the control pipe while wexecuting the command (probably a mass storage reset). 
//     k_timeout - a timeout limit exceeded while executing the command. 
//   (This allows the caller to see the return value, via the argp, after the DFA terminates). 
//   g_active_lun is modified here. 
// 
// Notes: 
//   This is a DFA, not a FUNCTION. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
static void dfa_media_changed(void) reentrant; 
static void dfa_media_changed() reentrant 
{ 
  TRACE0(102, dev, 0, "dfa_media_changed()"); 
  thread_clr_sync(kbm_sync_create); 
  TRACE1(103, dev, 0, "establish lun %d", g_active_lun); 
  thread_run_dfa(_dfa_lun_reset_media(g_active_lun), (void*) &_result, media_changed1); 
} 
 
//------------------------------------------------------------------------------ 
// Activates on kbm_sync_create. 
//------------------------------------------------------------------------------ 
static void dev_thread_wait_csw() reentrant 
{ 
  TRACE0(104, dev, 0, "dev_thread_wait_csw()"); 
  fgnd_hpbot_wait_status_start(_result); 
  thread_yield_ex2(kbm_sync_cbw, dev_thread_wait_cbw); 
} 
 
//------------------------------------------------------------------------------ 
// Activates on kbm_sync_cbw. 
//------------------------------------------------------------------------------ 
static void dev_thread_wait_cbw() reentrant 
{ 
  uint8 media; 
 
  TRACE0(105, dev, 0, "dev_thread_wait_cbw()"); 
  _lun_enable_mux(g_active_lun)(); 
  // don't probe the cards on an inquiry 
  if (k_protocol_inquiry != g_bot_cbw.cdb[0]) 
  { 
    if (_lun_is_media_changed(g_active_lun)) 
    { 
      TRACE1(106, dev, 0, "media changed on phylun: %d", g_active_lun); 
      thread_run_dfa(dfa_media_changed, NULL, dev_thread_wait_cbw); 
    } 
  } 
  _thread_clr_sync(kbm_sync_cbw); 
  // BBB: the first optimization to this was to call these directly from dfa_lun_process_cb. 
  // that eliminated a dfa layer (55usec push, 66usec pop) and required no changes here. 
  // the second optimization was to call it directly from here on rd/wr. 
  // that eliminated another dfa layer cutting out 240 to 270 usec in toto (as measured). 
  thread_wr_dfa_argp(&_result); 
  media = _lun_data(g_active_lun, media); 
  #if 1 
  // this snippet fixes a problem of powering on with no media and havinf the host 
  // try to do a read even avter seeing a no-media sense code. 
  if (!(media & kbm_lun_media_present)) 
    thread_run_dfa(_dfa_lun_process_cb(g_active_lun), &_result, dev_thread_wait_csw); 
  if (media & kbm_lun_media_changed) 
    thread_run_dfa(_dfa_lun_process_cb(g_active_lun), &_result, dev_thread_wait_csw); 
  if (media & kbm_lun_media_unknown) 
    thread_run_dfa(_dfa_lun_process_cb(g_active_lun), &_result, dev_thread_wait_csw); 
  #endif 
  switch (g_bot_cbw.cdb[0]) 
  { 
    case k_protocol_read_10: 
    case k_protocol_read_12: 
      trace0(0, lun, 0, "cb-read (fast)"); 
      //thread_run_dfa(_dfa_lun_read(g_active_lun), &_result, dev_thread_wait_csw); 
      (*_dfa_lun_read(g_active_lun))(); 
      dev_thread_wait_csw(); 
 
    case k_protocol_write_10: 
    case k_protocol_write_12: 
      trace0(0, lun, 0, "cb-write (fast)"); 
      //thread_run_dfa(_dfa_lun_write(g_active_lun), &_result, dev_thread_wait_csw); 
      (*_dfa_lun_write(g_active_lun))(); 
      dev_thread_wait_csw(); 
 
    default: 
      thread_run_dfa(_dfa_lun_process_cb(g_active_lun), &_result, dev_thread_wait_csw); 
  } 
} 
 
//+----------------------------------------------------------------------------- 
// Name: 
//   dev_thread_wait_create 
// 
// Declaration: 
//   void dev_thread_wait_create(void); 
// 
// Purpose: 
//   Called at POR. 
// 
// Arguments: 
//   None. 
//   Activates on kbm_sync_create. 
// 
// Return: 
//   No return value. 
//   This is the top level device thread.  It never returns. 
// 
// Notes: 
//   This is a STATE in the top level device thread, not a FUNCTION. 
// 
// Since: 
//   fmc-1.0 
//------------------------------------------------------------------------------ 
static void dev_thread_wait_create() reentrant 
{ 
  TRACE0(107, dev, 0, "dev_thread_wait_create()"); 
  thread_clr_sync(kbm_sync_create); 
  TRACE0(108, dev, 0, "fire off the high prority bot interrupt chain"); 
  fgnd_hpbot_wait_create(); 
  // wait until a cbw arrives 
  thread_yield_ex2(kbm_sync_cbw, dev_thread_wait_cbw); 
} 
 
//---eof------------------------------------------------------------------------