//------------------------------------------------- // write_sector (stage II) //------------------------------------------------- void wd2010_device::complete_write_sector(UINT8 data) { UINT8 newstatus = STATUS_RDY | STATUS_SC; m_out_bdrq_cb(0); // DE-Assert BDRQ (...and DRQ !) m_status &= ~(STATUS_DRQ); // (When drive changed) : SCAN_ID / GET CYL# auto_scan_id(data); // has drive number changed? (*** UNIMPLEMENTED ***) // Assume YES : CYL.register + internal CYL.register SAME? (if NO => SEEK!) // Assume : SEEK_COMPLETE = YES if (!m_in_drdy_cb() || m_in_wf_cb()) // DRIVE IS READY / NO WF? { m_error = ERROR_AC; // ABORTED_COMMAND complete_cmd(newstatus | STATUS_ERR); return; } else { // -------------------------------------------------------- // (*** UNIMPLEMENTED ***) Search for ID field... // < Correct ID found > // (*** UNIMPLEMENTED ***) : 'ID NOT FOUND' - set bit 4 error register // ........................: => SCAN_ID => RE-SEEK (2-10 INDEX PULSES) / Set ERR bit 0 status register .. m_status &= ~(STATUS_SC); // "WRITE_GATE valid when SEEK_COMPLETE = 0" (see Rainbow 100 Addendum!) m_out_bcs_cb(1); m_out_wg_cb(1); // (!) m_out_bcr_cb(0); // strobe BCR m_out_bcr_cb(1); // Assume: DRIVE IS READY / NO WF if (!m_in_drdy_cb() || m_in_wf_cb()) // DRDY de-asserted or WF asserted? { m_error = ERROR_AC; // ABORTED_COMMAND complete_cmd(newstatus | STATUS_ERR); return; } else { // ====> WRITE DATA TO SECTOR <==== m_out_wg_cb(0); // (!) // Assume: (single sector transfer; M = 0) } // (INNER IF): No WF and DRIVE IS READY. } // -------------------------------------------------------- // 'complete_cmd' ON THE FALLING EDGE OF _BUFFER_READY_ ( set by WRITE_SECTOR ) ! deassert_write_when_buffer_ready_low->adjust(attotime::from_usec(1), newstatus); }
static void at_task_run_no_bytes(struct at_info *ati) { if (AT_RX_STATE_URC == ati->rx_state) { /* * Then we are waiting for the rest of a URC response. * Ensure that we have not passed the URC timeout period. * Honestly, we should NEVER really get here, or if we do, * we should never timeout on a URC. Doing so likely * indicates a bug in usage or architecture. */ if (is_timed_out(ati->timing.urc_start_ms, AT_URC_TIMEOUT_MS)) { pr_warning("[at] Timed out in a URC!?!. " "Should never happen. Likely a bug.\r\n"); return complete_urc(ati, AT_RSP_STATUS_TIMEOUT); } } else if (AT_CMD_STATE_IN_PROGRESS == ati->cmd_state) { /* * If here, then we received no data, but a command is in * progress. In this case, ensure that the command hasn't * reached its timeout period. */ if (is_timed_out(ati->timing.cmd_start_ms, ati->cmd_ip->timeout_ms)) { printk(dbg_lvl, "[at] Command timed out\r\n"); return complete_cmd(ati, AT_RSP_STATUS_TIMEOUT); } } /* * If here, then either we are not in the correct state or nothing * has timed out. Move along. */ }
static void test_set(void) { char *buf; reset_completion(); assert_int_equal(0, complete_cmd("se")); buf = next_completion(); assert_string_equal("set", buf); free(buf); }
static void process_cmd_msg(struct at_info *ati, char *msg) { /* We always strip trialing message characters on cmd messages */ const size_t msg_len = serial_msg_strlen(msg); msg[msg_len] = '\0'; _process_msg_generic(ati, AT_RX_STATE_CMD, msg); enum at_rsp_status status; if (is_rsp_status(&status, msg)) complete_cmd(ati, status); }
static void test_dont_remove_range(void) { char *completion; reset_completion(); assert_int_equal(2, complete_cmd("% del")); assert_int_equal(3, get_completion_count()); if(get_completion_count() == 0) return; completion = next_completion(); assert_string_equal("delcommand", completion); free(completion); reset_completion(); assert_int_equal(1, complete_cmd("3del")); assert_int_equal(3, get_completion_count()); if(get_completion_count() == 0) return; completion = next_completion(); assert_string_equal("delcommand", completion); free(completion); }
static void test_empty_line_completion(void) { char *buf; reset_completion(); assert_int_equal(0, complete_cmd("")); buf = next_completion(); assert_string_equal("!", buf); free(buf); buf = next_completion(); assert_string_equal("alink", buf); free(buf); }
static void test_delc_completion(void) { char *completion; assert_int_equal(0, execute_cmd("command udf a")); reset_completion(); assert_int_equal(5, complete_cmd("delc u")); assert_int_equal(2, get_completion_count()); if(get_completion_count() == 0) return; completion = next_completion(); assert_string_equal("udf", completion); free(completion); }
static void test_skip_abbreviations(void) { char *completion; reset_completion(); assert_int_equal(0, complete_cmd("d")); assert_int_equal(3, get_completion_count()); if(get_completion_count() == 0) return; completion = next_completion(); assert_string_equal("delcommand", completion); free(completion); completion = next_completion(); assert_string_equal("delete", completion); free(completion); }
static void test_skip_complete_args(void) { char *completion; reset_completion(); assert_int_equal(17, complete_cmd("% dele fast slow ")); assert_int_equal(3, get_completion_count()); if(get_completion_count() == 0) return; completion = next_completion(); assert_string_equal("fastrun", completion); free(completion); completion = next_completion(); assert_string_equal("followlinks", completion); free(completion); }
// FIXME: NO ID HANDLING (ID FOUND / NOT FOUND), NO BAD BLOCK; NO CRC void wd2010_device::scan_id(UINT8 data) { UINT8 newstatus = STATUS_RDY; m_out_intrq_cb(CLEAR_LINE); m_error = 0; m_status = STATUS_BSY | STATUS_CIP; // Assume DRIVE READY. // < TODO: Search for ANY ID FIELD. > // Assume ID FOUND : update_sdh( 32, 0, 0, 1 ); // (NEW:) SECTOR_SIZE, HEAD, CYLINDER, SECTOR_NR // NO BAD BLOCK. // NO CRC ERROR. complete_cmd(newstatus); }
static void test_skip_goto(void) { char *completion; reset_completion(); assert_int_equal(0, complete_cmd("")); assert_int_equal(5, get_completion_count()); if(get_completion_count() == 0) return; completion = next_completion(); assert_string_equal("comclear", completion); free(completion); completion = next_completion(); assert_string_equal("command", completion); free(completion); completion = next_completion(); assert_string_equal("delcommand", completion); free(completion); }
//------------------------------------------------- // compute_correction - //------------------------------------------------- void wd2010_device::compute_correction(UINT8 data) { UINT8 newstatus = STATUS_RDY | STATUS_SC; complete_cmd(newstatus); }
//------------------------------------------------- // restore - //------------------------------------------------- void wd2010_device::restore(UINT8 data) { UINT8 newstatus = STATUS_RDY | STATUS_SC; m_out_intrq_cb(CLEAR_LINE); // reset INTRQ, errors, set BUSY, CIP m_error = 0; m_status = STATUS_BSY | STATUS_CIP; m_out_rwc_cb(0); // reset RWC, set direction = OUT // datasheet: DIRIN HIGH = in ; LOW = out m_out_dirin_cb(0); // 0 = heads move away from the spindle, towards track O. // TODO: store step rate m_present_cylinder = 0; // (sse WD2010-05 datasheet) m_task_file[TASK_FILE_CYLINDER_HIGH] = 0; m_task_file[TASK_FILE_CYLINDER_LOW] = 0; int step_pulses = 0; while (step_pulses < STEP_LIMIT) { while (!m_in_sc_cb()) { if (!m_in_drdy_cb() || m_in_wf_cb()) // drive not ready or write fault? { m_out_bcr_cb(0); // pulse BCR m_out_bcr_cb(1); m_error = ERROR_AC; // ERROR : ABORTED COMMAND complete_cmd(newstatus | STATUS_ERR); return; } } //if (m_in_tk000_cb()) if (step_pulses == STEP_LIMIT - 2) // Simulate TRACK 00 signal (normally from DRIVE) { m_out_bcr_cb(0); // pulse BCR m_out_bcr_cb(1); newstatus &= ~(STATUS_BSY | STATUS_CIP); // prepare new status; (INTRQ later) reset BSY, CIP complete_cmd(newstatus); return; } if (step_pulses == STEP_LIMIT - 1) // NOTE: STEP_LIMIT - differs - between WD2010 and WD1010 { m_error = ERROR_TK; // ERROR: track 0 not reached within limit newstatus = newstatus | STATUS_ERR; m_out_bcr_cb(0); // pulse BCR m_out_bcr_cb(1); newstatus &= ~(STATUS_BSY | STATUS_CIP); // prepare new status; (INTRQ later) reset BSY, CIP complete_cmd(newstatus); return; } m_out_step_cb(1); // issue a step pulse m_out_step_cb(0); step_pulses++; } assert(1); }
// NOT IMPLEMENTED: IMPLIED SEEK ("wait until rising edge of SC signal") void wd2010_device::seek(UINT8 data) { UINT8 newstatus = STATUS_RDY | STATUS_SC; m_out_intrq_cb(CLEAR_LINE); // reset INTRQ, errors, set BUSY, CIP m_error = 0; m_status = STATUS_BSY | STATUS_CIP; // TODO : store STEP RATE. auto_scan_id(data); // has drive number changed? int direction; // 0 = towards 0 int step_pulses; // Calculate number of steps by comparing the cylinder registers // HI/LO with the internally stored position. UINT32 cylinder_registers = CYLINDER; if (m_present_cylinder > cylinder_registers) { step_pulses = m_present_cylinder - cylinder_registers; direction = 0; } else { step_pulses = cylinder_registers - m_present_cylinder; direction = 1; } logerror("SEEK - direction = %u, step_pulses = %u\n", direction, step_pulses); m_out_dirin_cb(direction); if (!m_in_drdy_cb() || m_in_wf_cb()) // DRDY de-asserted or WF asserted? { m_error = ERROR_AC; complete_cmd(newstatus | STATUS_ERR); return; } else { while (step_pulses > 0) // issue STEP PULSES { if (direction == 0) { m_out_step_cb(1); // issue a step pulse m_out_step_cb(0); if (m_present_cylinder > 0) m_present_cylinder--; } else { m_out_step_cb(0); m_out_step_cb(1); m_present_cylinder++; } step_pulses--; // TODO: delay according to rate field } // ALL STEPS ISSUED NOW if (!m_in_drdy_cb()) // DRDY not asserted = > ABORTED COMMAND { m_error = ERROR_AC; complete_cmd(newstatus | STATUS_ERR); return; } } // AFTER ALL STEPS ARE ISSUED ... // UPDATE INTERNAL CYLINDER POSITION REGISTER (from WD1010 spec -> "SEEK COMMAND") m_present_cylinder = cylinder_registers; logerror("SEEK (END) - m_present_cylinder = %u\n", m_present_cylinder); cmd_timer->adjust(attotime::from_msec(35), newstatus); // 35 msecs makes "SEEK_TIMING" test happy. }
//------------------------------------------------- // read_sector - //------------------------------------------------- // FIXME: multiple sector transfers, ID / CYL / HEAD / SIZE match // + ERROR HANDLING (...) void wd2010_device::read_sector(UINT8 data) { UINT8 newstatus = STATUS_RDY | STATUS_SC; int intrq_at_end = 0; // (default) : (I = 1 INTRQ occurs when the command m_out_intrq_cb(CLEAR_LINE); // reset INTRQ, errors, set BUSY, CIP m_error = 0; m_status = STATUS_BSY | STATUS_CIP; // Assume: drive NO # has not changed... (else: SCAN_ID; GET CYL#) auto_scan_id(data); // has drive number changed? // CYL REGISTERS and INTERNAL CYL. SAME ? // TODO: < NOT SAME? THEN _SEEK_ > // DRIVE NOT READY? OR WF? if ( (!m_in_drdy_cb()) || m_in_wf_cb() ) { m_error = ERROR_AC; // ABORTED_COMMAND complete_cmd(newstatus | STATUS_ERR); return; } else { m_out_bcs_cb(1); // activate BCS (!) m_out_bcr_cb(0); // strobe BCR m_out_bcr_cb(1); if (!m_in_drdy_cb()) // DRIVE NOT READY? { m_error = ERROR_AC; // ABORTED_COMMAND complete_cmd(newstatus | STATUS_ERR); return; } else { // < SEARCH FOR ID FIELD > // < CYL / HEAD / SEC.SIZE MATCH ? > // < ID NOT FOUND > if (SECTOR_NUMBER > MAX_MFM_SECTORS) { // prepare new status; (later IRQ +) reset BSY, CIP m_error = ERROR_ID; complete_cmd(newstatus | STATUS_ERR); return; } // LOOP OVER 10 INDEXES : SCAN_ID / GET CYL.# (not implemented: ID NOT FOUND) // CYL / HEAD / SEC.SIZE MATCH ? => (ID FOUND) // // NO "BAD BLOCK DETECT" (** NOT IMPLEMENTED **) // NO "CRC ERROR" (** NOT IMPLEMENTED **) // AND "DAM FOUND" (** NOT IMPLEMENTED **) // ====> THEN "TRANSFER SECTOR TO BUFFER" <==== m_out_bcr_cb(0); // strobe BCR m_out_bcr_cb(1); // NO "CRC ERROR" // FLAG "M" SET? (MULTIPLE SECTOR TRANSFERS) if (data & 4) logerror("WD2010 (READ): MULTIPLE SECTOR READ (M = 1).\n"); // Assume: NO "M" (MULTIPLE SECTOR TRANSFERS) m_out_bcs_cb(0); // deactivate BCS (!) m_out_bcr_cb(0); // strobe BCR m_out_bcr_cb(1); // set BDRQ (NOTE: DRQ status bit 3 reflects state of BDRQ) m_status |= STATUS_DRQ; m_out_bdrq_cb(1); // reset BUSY (* after * TRANSFER OF SECTOR in READ) m_status &= ~(STATUS_BSY); // FLAG "I" SET? if (!(data & 8)) // (I = 0 INTRQ occurs with BDRQ/DRQ indicating the Sector Buffer is full...) { m_out_intrq_cb(ASSERT_LINE); if (!(data & 4)) // (...valid only when M = 0) intrq_at_end = STATUS_DWC; // 'reuse' unused DWC bit! } else { intrq_at_end = 0; // (default): (I = 1 INTRQ occurs when the command is completed and the Host has read the Sector Buffer) } // (WAIT FOR): BRDY LOW TO HIGH? (see -> TIMER) } // DRIVE_READY ? (inner) } // DRIVE_READY ? (outer) // NOTE : (intrq_at_end = 0) - INTRQ occurs when the command is completed newstatus |= (m_status & ~(STATUS_CIP | STATUS_DRQ)) | intrq_at_end; // de-assert CIP + DRQ (BSY already reset) deassert_read_when_buffer_ready_high->adjust(attotime::from_usec(1), newstatus); // complete command ON *RISING EDGE * OF BUFFER_READY }
//------------------------------------------------- // set_parameter - //------------------------------------------------- void wd2010_device::set_parameter(UINT8 data) { UINT8 newstatus = STATUS_RDY | STATUS_SC; complete_cmd(newstatus); }
SETUP() { static int option_changed; optval_t def = { .str_val = "/tmp" }; cfg.slow_fs_list = strdup(""); init_builtin_functions(); stats.line = wcsdup(L"set "); stats.index = wcslen(stats.line); stats.curs_pos = 0; stats.len = stats.index; stats.cmd_pos = -1; stats.complete_continue = 0; stats.history_search = 0; stats.line_buf = NULL; stats.complete = &complete_cmd; init_commands(); execute_cmd("command bar a"); execute_cmd("command baz b"); execute_cmd("command foo c"); init_options(&option_changed); add_option("fusehome", "fh", OPT_STR, 0, NULL, fusehome_handler, def); assert_int_equal(0, chdir("test-data/existing-files")); } TEARDOWN() { assert_int_equal(0, chdir("../..")); free(cfg.slow_fs_list); cfg.slow_fs_list = NULL; free(stats.line); reset_cmds(); clear_options(); function_reset_all(); } static void fusehome_handler(OPT_OP op, optval_t val) { } TEST(leave_spaces_at_begin) { char *buf; vle_compl_reset(); assert_int_equal(1, complete_cmd(" qui", NULL)); buf = vle_compl_next(); assert_string_equal("quit", buf); free(buf); buf = vle_compl_next(); assert_string_equal("quit", buf); free(buf); } TEST(only_user) { char *buf; vle_compl_reset(); assert_int_equal(8, complete_cmd("command ", NULL)); buf = vle_compl_next(); assert_string_equal("bar", buf); free(buf); vle_compl_reset(); assert_int_equal(9, complete_cmd(" command ", NULL)); buf = vle_compl_next(); assert_string_equal("bar", buf); free(buf); vle_compl_reset(); assert_int_equal(10, complete_cmd(" command ", NULL)); buf = vle_compl_next(); assert_string_equal("bar", buf); free(buf); } TEST(test_set_completion) { vle_compl_reset(); assert_success(line_completion(&stats)); assert_wstring_equal(L"set all", stats.line); } TEST(no_sdquoted_completion_does_nothing) { free(stats.line); stats.line = wcsdup(L"command '"); stats.len = wcslen(stats.line); stats.index = stats.len; vle_compl_reset(); assert_success(line_completion(&stats)); assert_wstring_equal(L"command '", stats.line); } static void prepare_for_line_completion(const wchar_t str[]) { free(stats.line); stats.line = wcsdup(str); stats.len = wcslen(stats.line); stats.index = stats.len; stats.complete_continue = 0; vle_compl_reset(); }
// SECTOR NUMBER REG.= number of bytes - 3 (for GAP 1 + 3) // = 40 decimal on DEC RD51 with WUTIL 3.2 //-------------------------------------------------------- void wd2010_device::format(UINT8 data) { UINT8 newstatus = STATUS_RDY; m_out_intrq_cb(CLEAR_LINE); m_error = 0; m_status = STATUS_BSY | STATUS_CIP; m_status |= STATUS_DRQ; m_out_bdrq_cb(1); // < WAIT UNTIL BRDY ASSERTED > // Datasheet says [DRQ] must go LOW... // ...delayed here _until BRDY goes high_ (=> TIMER EVENT <=): // m_out_bdrq_cb(0); // m_status &= ~(STATUS_DRQ); auto_scan_id(data); // has drive number changed? // TODO: Seek to desired cylinder // Assume : SEEK COMPLETE. m_out_bcr_cb(0); // strobe BCR m_out_bcr_cb(1); m_out_bcs_cb(1); // activate BCS (!) if (!m_in_drdy_cb() || m_in_wf_cb()) { m_error = ERROR_AC; // ABORTED_COMMAND complete_cmd(newstatus | STATUS_ERR); return; } // WAIT FOR INDEX m_out_wg_cb(1); // Have Index, activate WRITE GATE // Check for WRITE FAULT (WF) if (m_in_wf_cb()) { m_error = ERROR_AC; // ABORTED_COMMAND complete_cmd(newstatus | STATUS_ERR); return; } // UINT8 format_sector_count = m_task_file[TASK_FILE_SECTOR_COUNT]; // do // { // < WRITE GAP 1 or GAP 3 > // < Wait for SEEK_COMPLETE=1 (extend GAP if SEEK_COMPLETE = 0) > // < Assume SEEK COMPLETE > // format_sector_count--; // if (format_sector_count != 0) { // The Rainbow 100 driver does ignore multiple sector // transfers so WRITE FORMAT does not actually write - m_out_wg_cb(0); // (transition from WG 1 -> 0) // NOTE: decrementing TASK_FILE_SECTOR_COUNT does * NOT WORK * } // else // { // < Write 4Es until INDEX (*** UNIMPLEMENTED ****) > // } // } while (format_sector_count > 0); // ** DELAY INTRQ UNTIL WRITE IS COMPLETE : complete_write_when_buffer_ready_high->adjust(attotime::from_usec(1), newstatus | STATUS_DRQ); // 1 USECs }