📄 ata.c
字号:
// 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 DFA, not a FUNCTION.
// It overrides dfa_lun_reset.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_ata_reset_media() reentrant
{
trace0(0, ata, 0, "dfa_ata_reset_media()");
ata_reset();
_thread_return_dfa(k_success);
}
//+-----------------------------------------------------------------------------
// Name:
// ata_poll_status_not_busy
//
// Declaration:
// void ata_poll_status_not_busy(void);
//
// Purpose:
// Poll the ata status register to watch for BSY going inactive.
// When it does deliver kbm_sync_ata_rdy to the active thread.
//
// Arguments:
// None.
//
// Return:
// None.
//
// Notes:
// MinimOS installable thread poller.
// Watches for synchronizing events that don't have associated interrupts
// in situations where the thread must yield to avoid blocking other threads.
// Uninstalls itself when sync delivered to its thread.
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void ata_poll_status_not_busy(void) reentrant;
void ata_poll_status_not_busy() reentrant
{
trace0(0, ata, 90, "ata_poll_status_not_busy()");
if (!(ata_read_status() & kbm_ata_status_bsy))
{
thread_set_sync(g_tid, kbm_sync_ata_rdy);
thread_set_poller((t_thd_entry)NULL);
}
}
//+-----------------------------------------------------------------------------
// Name:
// ata_wait_status_with_timeout
//
// Declaration:
// t_result ata_wait_status_with_timeout(uint8 mask, uint8 val, uint16 ticks, uint8 *statusp);
//
// Purpose:
// Poll the ata status register to watch for specific bits matching specific values.
//
// Arguments:
// mask - a uint8 with 1's in the bits to be compared
// val - a uint8 representing the desired value
// ticks - a uint16 representing the timeout limit
// statusp - a pointer to a uint8, where the value of the status register is returned.
// statusp can be NULL, in which case no value is returned.
//
// Return:
// A t_result indicating:
// k_success - the ata status register logically anded with the mask equals the value.
// k_usbrst - usb reset signalling was detected while waiting.
// k_aborted - traffic occurred on the control pipe while waiting (probably a mass storage reset).
// k_timeout - timeout limit exceeded.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ata_wait_status_with_timeout(uint8 mask, uint8 val, uint16 ticks, uint8 *statusp) reentrant;
t_result ata_wait_status_with_timeout(uint8 mask, uint8 val, uint16 ticks, uint8 *statusp) reentrant
{
uint8 status;
t_sync sync;
trace2(0, ata, 1, "ata_wait_status_with_timeout(mask:0x%02X ticks:%d)", mask, ticks);
_stack_check();
// do this to get kbm_sync_abort delivered of there is traffic on the control pipe
_isr_bind_dma_owner(g_tid, kbm_sync_none);
// wait until the device is no longer busy
thread_set_timer(ticks+1);
status = ata_read_status();
do
{
sync = thread_got_sync(kbm_sync_abort |kbm_sync_usbrst |kbm_sync_timer);
_thread_clr_sync(sync);
if (sync & kbm_sync_usbrst)
{
trace0(0, ata, 1, "ata_wait_status_with_timeout() - error: kbm_sync_usbrst");
return k_usbreset;
}
if (sync & kbm_sync_abort)
{
trace0(0, ata, 1, "ata_wait_status_with_timeout() - error: kbm_sync_abort");
return k_aborted;
}
if (sync & kbm_sync_timer)
{
trace0(0, ata, 1, "ata_wait_status_with_timeout() - error: hung busy");
return k_timeout;
}
status = ata_read_status();
if (status & kbm_ata_status_err)
{
status = ata_register_rd(&ata_error);
trace1(0, ata, 1, "ata_wait_status_with_timeout() - error: 0x%02X", status);
return k_error;
}
} while ((status & mask) != val);
if (statusp)
*statusp = status;
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// ata_wait_irq_with_timeout
//
// Declaration:
// t_result ata_wait_irq_with_timeout(uint16 ticks);
//
// Purpose:
// Poll for the ata interrupt.
//
// Arguments:
// ticks - a uint16 representing the timeout limit
//
// Return:
// A t_result indicating:
// k_success - the ata interrupt occurred.
// k_usbrst - usb reset signalling was detected while waiting.
// k_aborted - traffic occurred on the control pipe while waiting (probably a mass storage reset).
// k_timeout - timeout limit exceeded.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//
// History:
// 06/18/02 tbh - modified ata_read_status() to leave the ata interrupt masked.
// - modified this routine to break out if ata irq bit seen via polling.
// - this cut about 270usec off the begin burst, decreasing cbw time.
//------------------------------------------------------------------------------
t_result ata_wait_irq_with_timeout(uint16 ticks) reentrant;
t_result ata_wait_irq_with_timeout(uint16 ticks) reentrant
{
t_sync sync;
trace1(0, ata, 1, "ata_wait_irq_with_timeout(ticks:%d)", ticks);
_stack_check();
// do this to get kbm_sync_abort delivered of there is traffic on the control pipe
_isr_bind_dma_owner(g_tid, kbm_sync_none);
thread_set_timer(ticks+1);
do
{
sync = thread_got_sync(kbm_sync_abort |kbm_sync_usbrst |kbm_sync_timer |kbm_sync_ata_irq);
_thread_clr_sync(sync);
if (sync & kbm_sync_usbrst)
{
trace0(0, ata, 1, "ata_wait_irq_with_timeout() - error: kbm_sync_usbrst");
return k_usbreset;
}
if (sync & kbm_sync_abort)
{
trace0(0, ata, 1, "ata_wait_irq_with_timeout() - error: kbm_sync_abort");
return k_aborted;
}
if (sync & kbm_sync_timer)
{
trace0(0, ata, 1, "ata_wait_irq_with_timeout() - error: timeout awaiting irq");
return k_timeout;
}
if (_mcu_register_rd(x_isr0) & kbm_isr0_ata_irq) break;
} while (!(sync & kbm_sync_ata_irq));
trace0(0, ata, 1, "ata_wait_irq_with_timeout() - got the ata irq");
return k_success;
}
extern xdata uint8 g_sector_buffer[];
//+-----------------------------------------------------------------------------
// Name:
// iddev_word
//
// Declaration:
// static uint16 iddev_word(uint16 word_offset);
//
// Purpose:
// Build a 16 bit word by extracting 2 bytee from pnr 4 at the specified offset.
//
// Arguments:
// word_offset - a uint16 specifying the offset into pnr 4 to get the result from.
//
// Return:
// A uint16 containing the 2 bytes extracted from pnr 4.
//
// Notes:
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
static uint16 iddev_word(uint16 word_offset) reentrant;
static uint16 iddev_word(uint16 word_offset) reentrant
{
uint16 byte_offset;
t_uw16 word;
byte_offset = 2 * word_offset;
#if 0
_mcu_register_wr(x_sram_addr_lo, k_pkt_addrlo[4] + _l(byte_offset));
_mcu_register_wr(x_sram_addr_hi, k_pkt_addrhi[4] + _h(byte_offset));
word.u8.lo = _mcu_register_rd(x_sram_data);
word.u8.hi = _mcu_register_rd(x_sram_data);
#else
word.u8.lo = g_sector_buffer[byte_offset++];
word.u8.hi = g_sector_buffer[byte_offset];
#endif
return word.u16;
}
//+-----------------------------------------------------------------------------
// Name:
// ata_identify_device
//
// Declaration:
// void ata_identify_device(uint8 cmd);
//
// Purpose:
// Poll the ata status register to watch for specific bits matching specific values.
//
// Arguments:
// cmd - a uint8 representing the "identify" command to issue to the drive.
//
// Return:
// A t_result indicating:
// k_success - device successfully identified.
// k_error - device failed to identify in a potentially recoverable way.
// OR
// No return - dfa ends on unrecoverable error.
//
// Notes:
// This is a FUNCTION, not a DFA, but must be called from within a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result ata_identify_device(uint8 cmd) reentrant
{
uint8 status;
t_result result;
#if 0
uint8 i;
#else
uint16 i;
#endif
uint16 devword;
//uint8 mode_sel;
uint8 yes_no_flag;
trace0(0, ata, 1, "ata_identify_device()");
_stack_check();
_thread_clr_sync(kbm_sync_all);
// select master drive
ata_register_wr(&ata_device_head, kbm_ata_dev_0);
// select the identify-device / identify-packet_device function
ata_register_wr(&ata_command, cmd);
ata_read_status();
result = k_error;
while (k_success != result) // WARNING! WARNING! DANGER, WILL ROBINSON!!!
{
trace1(0, ata, 0, "-- imr0:0x%02X", x_imr0);
//result = ata_wait_irq_with_timeout(5000);
result = ata_wait_irq_with_timeout(1000);
if (k_success != result)
{
trace0(0, ata, 1, "ata_identify_device() - error: no irq");
return k_error;
}
}
trace0(0, ata, 1, "ata_identify_device() - got the ata irq");
// BSY=0
status = ata_read_status();
if (!(status & kbm_ata_status_drq))
{
// BSY=0, DRQ=0, therefore command is done
trace0(0, ata, 1, "ata_identify_device() - warning: drive has no data");
return k_error;
}
// BSY=0, DRQ=1, therefore the drive wants to send more data
// read the data
_mcu_begin_critical_section();
#if 0 // since the bot layer is now a high priority thread at irq level
// cannot use packet buffers here... switch to using xdata buffer
_mcu_register_wr(x_sram_addr_lo, k_pkt_addrlo[4]);
_mcu_register_wr(x_sram_addr_hi, k_pkt_addrhi[4]);
// there are always 256 words of device data
for (i=255; i; i--)
{
_mcu_register_wr(x_sram_data, ata_register_rd(&ata_data));
_mcu_register_wr(x_sram_data, _mcu_register_rd(x_msb_ata));
}
_mcu_register_wr(x_sram_data, ata_register_rd(&ata_data));
_mcu_register_wr(x_sram_data, _mcu_register_rd(x_msb_ata));
#else
// there are always 256 words of device data
for (i=0; i<512; i+=2)
{
g_sector_buffer[i] = ata_register_rd(&ata_data);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -