// reset.c

#include "1394.h"
#include "data_structures.h"
#include "phy_services.h"
#include "arb.h"
#include "shared.h"

void arb_power_reset() {
  initiated_reset = TRUE;
  reset_duration = RESET_TIME;
  loop_to_detect = FALSE;
  bus_initialize_active = FALSE;
  gap_count_reset_disable = FALSE;
  while (power_reset)
    ;
  PH_EVENT_indication(PH_LINK_ON, 0, 0);  // only for power classes 0-4
      // for a min of 166 usecs (16384 PClk cycles).
      // see Clause 14.4 for full requirements
}

boolean reset_detected() {              // Qualify BUS_RESET with port status / history
  int i;
  if ( PHY_state == R0 || PHY_state == R1 // Ignore during (or just before) reset...
     || isbr_OK || phy_response)        // ...or if busy with a PHY command
    return(FALSE);
  for (i = 0; i < NPORT; i++)
    if (disabled[i])                    // Ignore completely if disabled
      continue;
    else if ((Beta_mode[i] || bias[i]) && (portRarb[i] == BUS_RESET))
      if (active[i]) {
        reset_duration = (PHY_state == RX) ? SHORT_RESET_TIME : RESET_TIME;
        return(TRUE);
      } else if (resume[i] && OK_to_detect_reset && !bus_initialize_active) {
        resumption_done = TRUE;
        reset_duration = (boundary_node) ? RESET_TIME : SHORT_RESET_TIME;
        return(TRUE);
      } else if (attach[i] && ((NPORT==1) ||
                               ((i == test_port) && send_attach))) {
        reset_duration = SHORT_RESET_TIME;  // Found a reset returned in response to
                                            // an ATTACH_REQUEST issued, so attempt a
                                            // short reset.  Note well: this should only
                                            // test true on a single port phy or an
                                            // isolated node as any other node retains
                                            // control of the bus while awaiting the
                                            // return reset
        return(TRUE);
      }
  return(FALSE);
}

void reset_start_actions() {            // Transmit BUS_RESET for reset_duration on all ports
  int i;

  if (!bus_initialize_active) {
    bus_initialize_active = TRUE;
    if (gap_count_reset_disable)        // First reset since setting gap_count?
      gap_count_reset_disable = FALSE;  // If so, leave it as is and arm it for next
    else
      gap_count = 0x3F;                 // Otherwise, set it to the maximum
  }
  if (isolated_node)
    force_root = FALSE;                 // No point in waiting to become root if isolated

  PH_EVENT_indication(PH_BUS_RESET_START, 0, 0);  // Optional upon reentry to R0 from R1
  waitPH_EVENT_response();
  // flush out all queued requests from the link and set even async and isoc phases
  cancel_requests();
  odd_isoch_phase = FALSE;
  odd_async_phase = FALSE;
  iso_cycle = FALSE;
  did_arbrst = FALSE;
  // note that arb_enable is NOT reset (just like 1394a)
  OK_to_grant = defer_grant = grant_self = FALSE;

  B_bus = TRUE;                         // initially an isolated node!
  root = FALSE;
  senior_border = FALSE;
  
  receive_port = NPORT+1;               // not receiving, not transmitting
  link_concatenation = FALSE;
  send_null_packet = FALSE;
  DS_stuck = FALSE;

  ibr = isbr = isbr_OK = FALSE;         // Don't replicate resets!
  phy_response = ping_response = FALSE; // Invalidate stale information
  arb_timer = 0;                        // not important, just good practice
  T0_timeout = FALSE;
  children = physical_ID = 0;
  max_Legacy_path_speed = (link == Legacy_Link) ? S400: S100; 
  if (!loop_to_detect) {                // loop timout detect, while its true, look for
                                        // config timeout, arb_state timeout, more than 2 resets
                                        // or loss of sync on a port
    loop_to_detect = TRUE;              // set false once node gets to S1 or S2
    reset_count = 0;                    // count the resets that never make it that far
  } else reset_count++;
  need_new_LTP = TRUE;
  HR_G = 0;                             // value not important
  HR_mode = LTP_TEST;
  in_control = FALSE;
  for (i = 0; i < NPORT; i++) {
    // check for untested ports
    if (loop_disabled[i])
      loop_disabled[i] = FALSE;
    child[i] = FALSE;
    child_ID_complete[i] = FALSE;
    if (!Beta_mode[i]) port_speed[i] = S100; // Reset default speed for all DS ports
  }
  for (i = 0; i < NPORT; i++) {
    if (Beta_mode[i]) {                 // have to notify all stood-by ports that a reset has occurred
      
      reset_notify[i] = TRUE;   
    }
    
    portTarb(i, BUS_RESET);             // propagate on active ports, 
    if ((resume[i] && resumption_done) || attach[i]) {
      portT[i].arb = BUS_RESET;         // Also propagate on resuming or attaching ports
      portT[i].speed = DEFAULT;
      portT[i].tag = ARB_STATE;
    }
  }
}

void reset_wait_actions() {             // Transmit IDLE
  int i;
  for (i = 0; i < NPORT; i++) {
    portTarb(i, IDLE);
    if ((resume[i] && resumption_done) || attach[i]) {
      portT[i].arb = IDLE;              // Also propagate on resuming or attaching ports
      portT[i].speed = DEFAULT;
      portT[i].tag = ARB_STATE;
    }
  }
  arb_timer = 0;                        // Restart timer
}

boolean reset_complete() {              // TRUE when all ports idle or in tree-ID
  int i;
  for (i = 0; i < NPORT; i ++) {
    if (active[i])
      if ((portRarb[i] != IDLE) && (portRarb[i] != PARENT_NOTIFY))
        return(FALSE);
  }
  return(TRUE);                         // Transition to tree identify
}
