fix(kernel): allow command-phase byte reception while ATN is asserted #3
@ -108,16 +108,26 @@ static void emit_record(u8 kind, u8 value, u8 flags)
|
|||||||
|
|
||||||
/* --- busy-poll helper ---------------------------------------------------- */
|
/* --- busy-poll helper ---------------------------------------------------- */
|
||||||
/*
|
/*
|
||||||
* Spin until CLK reaches `want_asserted`, or timeout/ATN/RESET. Caller holds
|
* Spin until CLK reaches `want_asserted`, or timeout/ATN-change/RESET. Caller
|
||||||
* local IRQs disabled. Uses a microsecond budget rather than a fixed udelay so
|
* holds local IRQs disabled. Uses a microsecond budget rather than a fixed
|
||||||
* a slightly-fast C64 is handled correctly (research §1.3).
|
* udelay so a slightly-fast C64 is handled correctly (research §1.3).
|
||||||
|
*
|
||||||
|
* The ATN abort is phase-relative, and IEC_RX_ATN means "ATN changed, abort":
|
||||||
|
* - data_phase: ATN is released; abort if it ASSERTS (C64 interrupts data
|
||||||
|
* transfer with a new command).
|
||||||
|
* - command phase: ATN is asserted for the whole command byte; abort if it
|
||||||
|
* RELEASES (the command sequence is over -> hand back to the state machine).
|
||||||
|
* Treating any asserted ATN as an abort (the previous behaviour) made command
|
||||||
|
* reception impossible: ATN is legitimately low the entire command phase, so
|
||||||
|
* the very first poll aborted before a single bit was clocked.
|
||||||
*/
|
*/
|
||||||
static enum iec_rx wait_clk(bool want_asserted, unsigned int timeout_us)
|
static enum iec_rx wait_clk(bool want_asserted, unsigned int timeout_us,
|
||||||
|
bool data_phase)
|
||||||
{
|
{
|
||||||
unsigned int waited = 0;
|
unsigned int waited = 0;
|
||||||
|
|
||||||
while (iec_clk_asserted() != want_asserted) {
|
while (iec_clk_asserted() != want_asserted) {
|
||||||
if (iec_atn_asserted())
|
if (iec_atn_asserted() == data_phase)
|
||||||
return IEC_RX_ATN;
|
return IEC_RX_ATN;
|
||||||
if (iec_reset_asserted())
|
if (iec_reset_asserted())
|
||||||
return IEC_RX_RESET;
|
return IEC_RX_RESET;
|
||||||
@ -143,7 +153,7 @@ static enum iec_rx receive_byte(u8 *out, bool *eoi, bool data_phase)
|
|||||||
*eoi = false;
|
*eoi = false;
|
||||||
|
|
||||||
/* 1. READY-FOR-DATA: wait for talker to release CLK, then release DATA */
|
/* 1. READY-FOR-DATA: wait for talker to release CLK, then release DATA */
|
||||||
rc = wait_clk(false /* released */, IEC_CLK_TIMEOUT_US);
|
rc = wait_clk(false /* released */, IEC_CLK_TIMEOUT_US, data_phase);
|
||||||
if (rc != IEC_RX_OK)
|
if (rc != IEC_RX_OK)
|
||||||
return rc;
|
return rc;
|
||||||
iec_data_release();
|
iec_data_release();
|
||||||
@ -171,10 +181,12 @@ static enum iec_rx receive_byte(u8 *out, bool *eoi, bool data_phase)
|
|||||||
|
|
||||||
/* 3. RECEIVE 8 BITS, LSB first */
|
/* 3. RECEIVE 8 BITS, LSB first */
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
rc = wait_clk(true /* asserted: data invalid/setup */, IEC_CLK_TIMEOUT_US);
|
rc = wait_clk(true /* asserted: data invalid/setup */,
|
||||||
|
IEC_CLK_TIMEOUT_US, data_phase);
|
||||||
if (rc != IEC_RX_OK)
|
if (rc != IEC_RX_OK)
|
||||||
goto out;
|
goto out;
|
||||||
rc = wait_clk(false /* released: data valid -> sample */, IEC_CLK_TIMEOUT_US);
|
rc = wait_clk(false /* released: data valid -> sample */,
|
||||||
|
IEC_CLK_TIMEOUT_US, data_phase);
|
||||||
if (rc != IEC_RX_OK)
|
if (rc != IEC_RX_OK)
|
||||||
goto out;
|
goto out;
|
||||||
/* released(high) = bit 1, asserted(low) = bit 0 */
|
/* released(high) = bit 1, asserted(low) = bit 0 */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user