📄 ata.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.
____________________________________________________________________________
____________________________________________________________________________
<module name> - <module description>
____________________________________________________________________________
comments tbd
____________________________________________________________________________
Revision History
Date Who Comment
________ ___ _____________________________________________________________
04/20/01 cds initial version
09/##/01 tbh optimized for speed
11/16/01 cds - updated code to use lun instance data instead of globals.
- tried global search & replace of thread_clr_sync to
_thread_clr_sync but it turns out the bug is more devious
and is attached to bits_got, not the thread_clr_sync.
11/26/01 cds modified ata_pio_rd to include blk-xfer for 210 instead of
calling pio_wr_pkt. Tests whether high-speed or full-speed
and only sets 512-byte-pkts for blk-xfer in hs connections.
11/28/01 rcc modified ata_pio_rd Tests whether high-speed or full-speed
and only sets 512-byte-pkts for blk-xfer in hs connections also
CLEARS this bit if FS and does this before the blk-xfer bit it set.
12/04/01 tbh tweaked identify_device for newish fmc style _lun_data access.
12/13/01 tbh tweaked data xfers to use fmc_transfer()
02/26/02 tbh added NULL placeholder in _fmc_set_callback() invocations
03/12/02 tbh minor renaming to fit the fmc project's idiom
04/15/02 tbh ensure fmc_options set to 0 before read/write
05/20/02 tbh turn off multiple emulation in ata_read_end_xfer.
added ata_write_end_xfer to ensure multiple emulation turned off
in case of aborted transfer.
06/05/02 cds added trace statement to dump the # of sectors per irq (burst)
of the read/write multiple command from identify device data
06/10/02 tbh performance enhancements using _ata_register_wr() macro to replace
ata_register_wr() function. other minor enhancements.
06/20/02 tbh in ata_initialize_media2 set the CF into pio mode 4 (from default 0)
06/25/02 tbh subtract 1 from lba_max to get correct capacity reported to host
to fix the problem with quick format.
07/09/02 cds replaced _work_buf with common g_sector_buffer, as used in
sm, ms, and nand luns.
07/23/02 cds added obsolete PIO Transfer Cycle Mode field (word 51) to
identify device data. Moved the setting of the cfc_ata_mode_ctl
register into the identify device function so that as soon as
the mode is determined, the register is set, but before then,
PIO mode 0 is used (to obtain the ID data).
08/29/02 tbh added rudimentary profiling of ata drives (to identify the
edata 32mb cf card and drop it to mode 0)
09/10/02 tbh forced reporting as removable media always because some CF
cards seem to say they are fixed disks.
10/17/02 cds - project-wide lun data & vtbl paging to reduce code space.
- removed g_active_media from _lun_data, _lun_() virtual functions
- added _lun_data_rd() and _lun_data_wr() macros to bypass lun paging
- added lun_set_active(log_lun) function to switch luns
============================================================================*/
#define __ata_dot_c__
#include "project.h"
#include "dev.h"
code _vtbl_defn(ata);
#ifdef k_flash_family
#define k_lun_ata k_lun_cf
#else
#define k_lun_ata 0
#endif
// to use this optimization you want fmc_select_cf() to set CKCON = 0x00 also...
#define _ata_clock_slow() CKCON=0x02
#define _ata_clock_fast() CKCON=0x00
//------------------------------------------------------------------------------
// exported globals
xdata uint8 g_dev_max_dma_mode; // represents max DMA mode supported by the device
// ata device characteristics
bit g_use_dma;
bit g_disable_iordy;
xdata uint8 g_dma_mode_current;
// ata device capabilities & properties
// these are all relevant properties from ata identify device data.
xdata uint16 g_ata_dev_cmdset_support_1;
xdata uint16 g_ata_dev_cmdset_support_2;
xdata uint16 g_ata_dev_cmdset_support_3;
xdata uint16 g_ata_dev_cmdset_enabled_1;
xdata uint16 g_ata_dev_cmdset_enabled_2;
xdata uint16 g_ata_dev_cmdset_enabled_3;
xdata uint16 g_ata_dev_num_log_cyl;
xdata uint16 g_ata_dev_num_log_hds;
xdata uint16 g_ata_dev_num_log_sec_per_trk;
xdata uint16 g_ata_dev_caps_1;
xdata uint16 g_ata_dev_caps_2;
//+-----------------------------------------------------------------------------
// Name:
// ata_dump_build_options
//
// Declaration:
// void ata_dump_build_options(void);
//
// Purpose:
// Debugging. Dumps the build options.
//
// Arguments:
// None.
//
// Return:
// None.
//
// Notes:
// None.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void ata_dump_build_options(void) reentrant;
void ata_dump_build_options() reentrant
{
trace0(0, ata, 0, "ata_dump_build_options()");
trace1(0, ata, 0, "dma mode: %02x", k_dma_mode);
trace0(0, ata, 0, "Shadow PIO_COMPLETE: Y");
trace0(0, ata, 0, "ATA Device Support:Y");
}
//+-----------------------------------------------------------------------------
// Name:
// ata_register_wr
//
// Declaration:
// void ata_register_wr(t_ata_register_ref r, uint8 d);
//
// Purpose:
// Write a value to an ata register.
//
// Arguments:
// r - the t_ata_register_ref identifying the register to be written.
// d - the uint8 to be written there.
//
// Return:
// None.
//
// Notes:
// None.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void ata_register_wr(t_ata_register_ref r, uint8 d) reentrant
{
_ata_clock_slow();
trace2(0, ata, 0, "ata_register_wr(%04x=%02x)", (uint16)r, d);
while( !(x_cfc_stat & kbm_cfc_stat_xrdy)); // <-- WARNING! WARNING! DANGER, WILL ROBINSON!
*r = d;
_ata_clock_fast();
}
//------------------------------------------------------------------------------
// performance enhancement is to use a macro in ata_read/write_begin_burst
// while issuing the command
//------------------------------------------------------------------------------
#define _ata_register_wr(__r, __d) \
{ \
_ata_clock_slow(); \
while( !(x_cfc_stat & kbm_cfc_stat_xrdy)); \
*(__r) = (__d); \
_ata_clock_fast(); \
}
//+-----------------------------------------------------------------------------
// Name:
// ata_register_rd
//
// Declaration:
// uint8 ata_register_rd(t_ata_register_ref r);
//
// Purpose:
// Read a value from an ata register.
//
// Arguments:
// r - the t_register_ref identifying the register to be read.
//
// Return:
// The uint8 to read from the ata register.
//
// Notes:
// None.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
uint8 ata_register_rd(t_ata_register_ref r) reentrant
{
uint8 val;
_mcu_begin_critical_section();
_ata_clock_slow();
// start read cycle, then get data from lsb_ata
val = *r;
_nop_(); _nop_(); _nop_();
val = x_lsb_ata;
_ata_clock_fast();
_mcu_end_critical_section();
return val;
}
//+-----------------------------------------------------------------------------
// Name:
// ata_read_status
//
// Declaration:
// uint8 ata_read_status(void);
//
// Purpose:
// Read the ata status register.
//
// Arguments:
// None.
//
// Return:
// The uint8 read from the ata status register.
//
// Notes:
// Reading the ata status register clears the ata interrupt (in the drive).
// This function also clears and unmasks the interrupts k_irq_ata and k_irq_fmc_cfc_intrq.
//
// Since:
// fmc-1.0
//
// History:
// 06/18/02 tbh - modified to leave the ata interrupt masked.
// - modified this wait_irq_with_timeout to break out if ata irq
// bit seen via polling.
// - this cut about 270usec off the begin burst, decreasing cbw time.
//------------------------------------------------------------------------------
uint8 ata_read_status(void) reentrant;
uint8 ata_read_status() reentrant
{
uint8 val;
_mcu_begin_critical_section();
_ata_clock_slow();
val = ata_status;
_nop_(); _nop_(); _nop_();
val = x_lsb_ata;
_ata_clock_fast();
// clear compact flash status as well
// could do this... but its slower...
//irq_control(k_irq_fmc_cfc_intrq, kbm_irqctl_clear |kbm_irqctl_unmask);
x_cfc_stat = kbm_cfc_stat_intrq;
x_cfc_stat_msk &= ~kbm_cfc_stat_intrq;
// could do this... but its slower...
//irq_control(k_irq_ata, kbm_irqctl_clear |kbm_irqctl_unmask);
x_isr0 = kbm_isr0_ata_irq;
// 06/18/02 tbh - ata_wait_irq_with_timeout() now polls this bit to avoid
// the overhead of having the kernel interrupt handler process all of the
// nested interrupts beneath the fmc/ata irq. (it takes so long in the isr0
// handler to check every possible nested source for the ata/fmc irq that
// it is dramatically faster to just poll the register.
//x_imr0 &= ~kbm_isr0_ata_irq;
trace1(0, ata, 99, "status:%02x", val);
_mcu_end_critical_section();
return val;
}
//+-----------------------------------------------------------------------------
// Name:
// ata_reset
//
// Declaration:
// void ata_reset(void);
//
// Purpose:
// Perform a hard reset on the ata drive via the reset pin in the ata cable.
//
// Arguments:
// None.
//
// Return:
// None.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
#define kix_ata_reset_pin 0x05
void ata_reset() reentrant
{
trace0(0, ata, 0, "ata_reset()");
_mcu_register_set_bits(x_cfc_ata_mode_ctl, kbm_cfc_ata_mode_ctl_dev_rst);
thread_set_timer(1);
while(!thread_got_sync(kbm_sync_timer));
_mcu_register_clr_bits(x_cfc_ata_mode_ctl, kbm_cfc_ata_mode_ctl_dev_rst);
// spec requires at least 2msec wait here... make sure other code induces wait...
thread_set_timer(3);
while(!thread_got_sync(kbm_sync_timer));
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_ata_reset_media
//
// Declaration:
// void dfa_ata_reset_media(void);
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -