Пример #1
0
/* the isil7170 bus cycle handler: */
static int
_tme_isil7170_bus_cycle(void *_isil7170, struct tme_bus_cycle *cycle_init)
{
  struct tme_isil7170 *isil7170;
  tme_bus_addr32_t address, isil7170_address_last;
  tme_uint8_t buffer, value, value_old;
  struct tme_bus_cycle cycle_resp;
  unsigned int reg;
  struct timeval now;
  time_t _now;
  struct tm *now_tm, now_tm_buffer;

  /* recover our data structure: */
  isil7170 = (struct tme_isil7170 *) _isil7170;

  /* the requested cycle must be within range: */
  isil7170_address_last = isil7170->tme_isil7170_device.tme_bus_device_address_last;
  assert(cycle_init->tme_bus_cycle_address <= isil7170_address_last);
  assert(cycle_init->tme_bus_cycle_size <= (isil7170_address_last - cycle_init->tme_bus_cycle_address) + 1);

  /* get the register being accessed: */
  address = cycle_init->tme_bus_cycle_address;
  reg = address >> isil7170->tme_isil7170_addr_shift;

  /* lock the mutex: */
  tme_mutex_lock(&isil7170->tme_isil7170_mutex);

  /* if the clock is running and this address is in the time-of-day
     registers, or if this is a write to the command register: */
  if (((isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] & TME_ISIL7170_CMD_RUN)
       && reg <= TME_ISIL7170_REG_DOW)
      || (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE
	  && reg == TME_ISIL7170_REG_CMD)) {

    /* sample the time of day: */
    gettimeofday(&now, NULL);
    _now = now.tv_sec;
    now_tm = gmtime_r(&_now, &now_tm_buffer);

    /* put the time-of-day into the registers: */
    isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CSEC] = now.tv_usec / 10000;
    isil7170->tme_isil7170_regs[TME_ISIL7170_REG_HOUR] = now_tm->tm_hour;
    isil7170->tme_isil7170_regs[TME_ISIL7170_REG_MIN] = now_tm->tm_min;
    isil7170->tme_isil7170_regs[TME_ISIL7170_REG_SEC] = now_tm->tm_sec;
    isil7170->tme_isil7170_regs[TME_ISIL7170_REG_MON] = now_tm->tm_mon + 1;
    isil7170->tme_isil7170_regs[TME_ISIL7170_REG_DAY] = now_tm->tm_mday;
    isil7170->tme_isil7170_regs[TME_ISIL7170_REG_YEAR] = (1900 + now_tm->tm_year) - TME_ISIL7170_REG_YEAR_0;
    isil7170->tme_isil7170_regs[TME_ISIL7170_REG_DOW] = now_tm->tm_wday;
  }

  /* if this is a write: */
  if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {

    /* run the bus cycle: */
    cycle_resp.tme_bus_cycle_buffer = &buffer;
    cycle_resp.tme_bus_cycle_lane_routing = tme_isil7170_router;
    cycle_resp.tme_bus_cycle_address = 0;
    cycle_resp.tme_bus_cycle_buffer_increment = 1;
    cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_READ;
    cycle_resp.tme_bus_cycle_size = sizeof(buffer);
    cycle_resp.tme_bus_cycle_port = 
      TME_BUS_CYCLE_PORT(isil7170->tme_isil7170_port_least_lane,
			 TME_BUS8_LOG2);
    tme_bus_cycle_xfer(cycle_init, &cycle_resp);
    value = buffer;
    
    /* log this write: */
    tme_log(TME_ISIL7170_LOG_HANDLE(isil7170), 100000, TME_OK,
	    (TME_ISIL7170_LOG_HANDLE(isil7170),
	     "reg %d write %02x",
	     reg, value));

    /* dispatch on the register: */
    switch (reg) {

    case TME_ISIL7170_REG_CSEC:
    case TME_ISIL7170_REG_HOUR:
    case TME_ISIL7170_REG_MIN:
    case TME_ISIL7170_REG_SEC:
    case TME_ISIL7170_REG_MON:
    case TME_ISIL7170_REG_DAY:
    case TME_ISIL7170_REG_YEAR:
    case TME_ISIL7170_REG_DOW:

      /* flag that the time-of-day needs to be updated: */
      isil7170->tme_isil7170_tod_update = TRUE;

      /* FALLTHROUGH */

    case TME_ISIL7170_REG_CMP_CSEC:
    case TME_ISIL7170_REG_CMP_HOUR:
    case TME_ISIL7170_REG_CMP_MIN:
    case TME_ISIL7170_REG_CMP_SEC:
    case TME_ISIL7170_REG_CMP_MON:
    case TME_ISIL7170_REG_CMP_DAY:
    case TME_ISIL7170_REG_CMP_YEAR:
    case TME_ISIL7170_REG_CMP_DOW:

      /* update the register: */
      isil7170->tme_isil7170_regs[reg] = value;
      break;

    case TME_ISIL7170_REG_INT:

      /* we don't support the alarm interrupt, or any of the daily,
	 hourly, etc., interrupts: */
      if (value & (TME_ISIL7170_INT_DAY
		   | TME_ISIL7170_INT_HOUR
		   | TME_ISIL7170_INT_MIN
		   | TME_ISIL7170_INT_SEC
		   | TME_ISIL7170_INT_ALARM)) {
	abort();
      }

      /* update the interrupt mask: */
      isil7170->tme_isil7170_int_mask = (value & ~TME_ISIL7170_INT_PENDING);

      /* callout to update our interrupt signal: */
      _tme_isil7170_callout(isil7170);

      /* notify the timer thread: */
      tme_cond_notify(&isil7170->tme_isil7170_cond_timer, FALSE);

      break;

    case TME_ISIL7170_REG_CMD:

      /* we don't support the test mode: */
      if (value & TME_ISIL7170_CMD_TEST) {
	abort();
      }

      /* update the command register: */
      value_old = isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD];
      isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] = value;

      /* if the frequency changed, update our periodic intervals: */
      if ((value_old ^ value) & TME_ISIL7170_CMD_FREQ_MASK) {
	_tme_isil7170_freq(isil7170);
      }

      /* if the interrupt enable changed, callout to update our
         interrupt signal: */
      if ((value_old ^ value) & TME_ISIL7170_CMD_INTENA) {
	_tme_isil7170_callout(isil7170);
      }

      break;

    default:
      /* ignore */
      break;
    }
  }

  /* otherwise, this is a read: */
  else {
    assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
    
    /* dispatch on the register: */
    switch (reg) {

    case TME_ISIL7170_REG_CSEC:
    case TME_ISIL7170_REG_HOUR:
    case TME_ISIL7170_REG_MIN:
    case TME_ISIL7170_REG_SEC:
    case TME_ISIL7170_REG_MON:
    case TME_ISIL7170_REG_DAY:
    case TME_ISIL7170_REG_YEAR:
    case TME_ISIL7170_REG_DOW:
    case TME_ISIL7170_REG_CMP_CSEC:
    case TME_ISIL7170_REG_CMP_HOUR:
    case TME_ISIL7170_REG_CMP_MIN:
    case TME_ISIL7170_REG_CMP_SEC:
    case TME_ISIL7170_REG_CMP_MON:
    case TME_ISIL7170_REG_CMP_DAY:
    case TME_ISIL7170_REG_CMP_YEAR:
    case TME_ISIL7170_REG_CMP_DOW:

      /* read the register: */
      value = isil7170->tme_isil7170_regs[reg];
      break;

    case TME_ISIL7170_REG_INT:

      /* reading the Interrupt register clears the interrupt: */
      value = isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT];
      isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] = 0;

      /* callout to update our interrupt signal: */
      _tme_isil7170_callout(isil7170);

      break;

      /* the Command register, and all undefined registers, return
         garbage when read: */
    case TME_ISIL7170_REG_CMD:
    default:
      value = 0xff;
      break;
    }

    /* log this read: */
    tme_log(TME_ISIL7170_LOG_HANDLE(isil7170), 100000, TME_OK,
	    (TME_ISIL7170_LOG_HANDLE(isil7170),
	     "reg %d read %02x",
	     reg, value));

    /* run the bus cycle: */
    buffer = value;
    cycle_resp.tme_bus_cycle_buffer = &buffer;
    cycle_resp.tme_bus_cycle_lane_routing = tme_isil7170_router;
    cycle_resp.tme_bus_cycle_address = 0;
    cycle_resp.tme_bus_cycle_buffer_increment = 1;
    cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_WRITE;
    cycle_resp.tme_bus_cycle_size = sizeof(buffer);
    cycle_resp.tme_bus_cycle_port = 
      TME_BUS_CYCLE_PORT(isil7170->tme_isil7170_port_least_lane,
			 TME_BUS8_LOG2);
    tme_bus_cycle_xfer(cycle_init, &cycle_resp);
  }

  /* if the time-of-day registers have been updated, and the clock
     is running: */
  if (isil7170->tme_isil7170_tod_update
      && (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD]
	  & TME_ISIL7170_CMD_RUN)) {
    
    /* XXX update the host's time-of-day clock? */
    isil7170->tme_isil7170_tod_update = FALSE;
  }
    
  /* unlock the mutex: */
  tme_mutex_unlock(&isil7170->tme_isil7170_mutex);

  /* no faults: */
  return (TME_OK);
}
Пример #2
0
/* the sun4 timer control bus cycle handler: */
int
_tme_sun4_timer_cycle_control(void *_sun4, struct tme_bus_cycle *cycle_init)
{
  struct tme_sun4 *sun4;
  unsigned int timer_i;
  struct tme_sun4_timer *timer;
  tme_uint32_t reg;
  tme_uint32_t value32;
  struct tme_bus_cycle cycle_resp;
  struct timeval now;
  struct timeval last_reset;
  tme_uint32_t counter_one;
  tme_uint32_t usecs;
  tme_uint32_t ticks;

  /* recover our sun4: */
  sun4 = (struct tme_sun4 *) _sun4;

  /* this must be a full 32-bit register access: */
  if ((cycle_init->tme_bus_cycle_address % sizeof(tme_uint32_t)) != 0
      || cycle_init->tme_bus_cycle_size != sizeof(tme_uint32_t)) {
    abort();
  }

  /* get the timer and register accessed: */
  if (TME_SUN4_IS_SUN44C(sun4)) {
    timer_i = cycle_init->tme_bus_cycle_address / TME_SUN44C_TIMER_SIZ_REG;
    reg = cycle_init->tme_bus_cycle_address & TME_SUN4_32_TIMER_SIZ_COUNTER;
  }
  else {
    abort();
  }
  timer = &sun4->tme_sun4_timers[timer_i];

  /* lock our mutex: */
  tme_mutex_lock(&sun4->tme_sun4_mutex);

  /* if this is a read: */
  if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ) {

    /* dispatch on the register: */
    switch (reg) {
    default: assert(FALSE);
    case TME_SUN4_32_TIMER_REG_COUNTER:

      /* update the timers: */
      _tme_sun4_timer_update(timer, &now, &last_reset);

      /* get the time of the last reset: */
      last_reset = timer->tme_sun4_timer_limit_next;
      if (last_reset.tv_usec < timer->tme_sun4_timer_period.tv_usec) {
	last_reset.tv_sec -= 1;
	last_reset.tv_usec += 1000000;
      }
      last_reset.tv_sec -= timer->tme_sun4_timer_period.tv_sec;
      last_reset.tv_usec -= timer->tme_sun4_timer_period.tv_usec;

      /* get the number of microseconds since the last reset: */
      usecs = now.tv_sec - last_reset.tv_sec;
      usecs *= 1000000;
      usecs
	+= (((tme_int32_t) now.tv_usec)
	    - ((tme_int32_t) last_reset.tv_usec));

      /* to keep things simpler, we always use the sun4m 500ns tick: */
      counter_one = TME_SUN4_IS_SUN44C(sun4) ? 2 : 1;

      /* convert the number of microseconds until this timer resets again,
	 to the 500ns tick counter value for the timer.  NB that we
	 account for the fact that timers count from [1..limit), and not
	 [0..limit): */
      ticks = (usecs * 2) + counter_one;
      TME_FIELD_MASK_DEPOSITU(timer->tme_sun4_timer_counter, 
			      TME_SUN4M_TIMER_MASK,
			      ticks);

      /* read this timer's counter register: */
      value32 = timer->tme_sun4_timer_counter;
      break;

    case TME_SUN4_32_TIMER_REG_LIMIT:

      /* read this timer's limit register: */
      value32 = timer->tme_sun4_timer_limit;	

      /* a read of the limit register is used to acknowledge an
	 interrupt, which probably means clearing the limit bit on the
	 counter register: */
      timer->tme_sun4_timer_counter = 0;
      timer->tme_sun4_timer_limit &= ~TME_SUN4_32_TIMER_LIMIT;
      break;
    }

    tme_log(TME_SUN4_LOG_HANDLE(sun4), 2000, TME_OK,
	    (TME_SUN4_LOG_HANDLE(sun4),
	     _("timer #%d %s -> 0x%08x"),
	     timer_i,
	     (reg == TME_SUN4_32_TIMER_REG_COUNTER
	      ? "counter"
	      : "limit"),
	     value32));

    /* byteswap the register value: */
    value32 = tme_htobe_u32(value32);
  }

  /* run the bus cycle: */
  cycle_resp.tme_bus_cycle_buffer = (tme_uint8_t *) &value32;
  cycle_resp.tme_bus_cycle_buffer_increment = 1;
  cycle_resp.tme_bus_cycle_lane_routing = cycle_init->tme_bus_cycle_lane_routing;
  cycle_resp.tme_bus_cycle_address = 0;
  cycle_resp.tme_bus_cycle_type = (cycle_init->tme_bus_cycle_type
				   ^ (TME_BUS_CYCLE_WRITE
				      | TME_BUS_CYCLE_READ));
  cycle_resp.tme_bus_cycle_port = TME_BUS_CYCLE_PORT(0, TME_BUS32_LOG2);
  tme_bus_cycle_xfer(cycle_init, &cycle_resp);

  /* if this is a write: */
  if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {

    /* byteswap the register value: */
    value32 = tme_htobe_u32(value32);

    tme_log(TME_SUN4_LOG_HANDLE(sun4), 2000, TME_OK,
	    (TME_SUN4_LOG_HANDLE(sun4),
	     _("timer #%d %s <- 0x%08x"),
	     timer_i,
	     (reg == TME_SUN4_32_TIMER_REG_COUNTER
	      ? "counter"
	      : "limit"),
	     value32));

    /* dispatch on the register: */
    switch (reg) {
    default: assert(FALSE);
    case TME_SUN4_32_TIMER_REG_COUNTER:
      abort();

    case TME_SUN4_32_TIMER_REG_LIMIT:

      /* write the timer's limit register: */
      timer->tme_sun4_timer_limit = value32;

      /* reset this timer: */
      _tme_sun4_timer_reset(timer);

      /* wake up the thread for this timer: */
      tme_cond_notify(&timer->tme_sun4_timer_cond, FALSE);
      break;
    }
  }

  /* make any callouts: */
  _tme_sun4_timer_callout(sun4);
    
  /* unlock the mutex: */
  tme_mutex_unlock(&sun4->tme_sun4_mutex);

  /* no faults: */
  return (TME_OK);
}
Пример #3
0
/* the serial callout function.  it must be called with the mutex locked: */
static void
_tme_posix_serial_callout(struct tme_posix_serial *serial)
{
  struct tme_serial_connection *conn_serial;
  unsigned int ctrl;
  tme_uint8_t buffer_input[1024];
  unsigned int buffer_input_size;
  tme_serial_data_flags_t data_flags;
  int rc;
  int again;

  /* if this function is already running in another thread, return
     now.  the other thread will do our work: */
  if (serial->tme_posix_serial_callouts_running) {
    return;
  }

  /* callouts are now running: */
  serial->tme_posix_serial_callouts_running = TRUE;

  /* loop running callouts until there is nothing to do: */
  for (again = TRUE; again;) {
    again = FALSE;

    /* if we're connected: */
    conn_serial = serial->tme_posix_serial_connection;
    if (conn_serial != NULL) {

      /* if we need to notify our connection of new ctrl bits: */
      ctrl = serial->tme_posix_serial_ctrl_callout;
      if (ctrl != serial->tme_posix_serial_ctrl_callout_last) {

	/* unlock the mutex: */
	tme_mutex_unlock(&serial->tme_posix_serial_mutex);

	/* try to do the notify: */
	rc = (*conn_serial->tme_serial_connection_ctrl)(conn_serial, ctrl);

	/* lock the mutex: */
	tme_mutex_lock(&serial->tme_posix_serial_mutex);

	/* if the notify was successful, note what we sent, and allow
	   the outermost loop to run again: */
	if (rc == TME_OK) {
	  serial->tme_posix_serial_ctrl_callout_last = ctrl;
	  again = TRUE;
	}
      }

      /* if our connection is readable, and our output buffer isn't full,
	 read the connection: */
      if ((serial->tme_posix_serial_ctrl_callin & TME_SERIAL_CTRL_OK_READ)
	  && !tme_serial_buffer_is_full(&serial->tme_posix_serial_buffer_out)) {

	/* get the minimum of the free space in the output buffer and
	   the size of our stack buffer: */
	buffer_input_size = tme_serial_buffer_space_free(&serial->tme_posix_serial_buffer_out);
	buffer_input_size = TME_MIN(buffer_input_size, sizeof(buffer_input));

	/* unlock the mutex: */
	tme_mutex_unlock(&serial->tme_posix_serial_mutex);

	/* do the read: */
	rc = (*conn_serial->tme_serial_connection_read)
	  (conn_serial,
	   buffer_input, 
	   buffer_input_size,
	   &data_flags);

	/* lock the mutex: */
	tme_mutex_lock(&serial->tme_posix_serial_mutex);

	/* if the read was successful, add what we got and notify the
	   writer so that it may try to write: */
	if (rc > 0) {
	  (void) tme_serial_buffer_copyin(&serial->tme_posix_serial_buffer_out,
					  buffer_input,
					  rc,
					  data_flags,
					  TME_SERIAL_COPY_NORMAL);
	  tme_cond_notify(&serial->tme_posix_serial_cond_writer, TRUE);

	  /* allow the outermost loop to run again: */
	  again = TRUE;
	}

	/* otherwise, the read failed, and the convention dictates
	   that we forget this connection was readable: */
	else {
	  serial->tme_posix_serial_ctrl_callin &= ~TME_SERIAL_CTRL_OK_READ;
	}
      }
    }
  }

  /* there are no more callouts to make: */
  serial->tme_posix_serial_callouts_running = FALSE;
}