Пример #1
0
/* the serial writer thread: */
static void
_tme_posix_serial_th_writer(struct tme_posix_serial *serial)
{
  tme_uint8_t buffer_output[1024];
  unsigned int buffer_output_size;
  int rc;

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

  /* loop forever: */
  for (;;) {

    /* if there is no data to write, wait on the writer condition,
       after which there must be data to write: */
    if (tme_serial_buffer_is_empty(&serial->tme_posix_serial_buffer_out)) {
      tme_cond_wait_yield(&serial->tme_posix_serial_cond_writer,
			  &serial->tme_posix_serial_mutex);
    }

    /* get the data to write: */
    buffer_output_size = 
      tme_serial_buffer_copyout(&serial->tme_posix_serial_buffer_out,
				buffer_output,
				sizeof(buffer_output),
				NULL,
				TME_SERIAL_COPY_PEEK);
    assert(buffer_output_size > 0);

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

    /* try to write the device: */
    rc = tme_thread_write_yield(serial->tme_posix_serial_fd_out,
				buffer_output,
				buffer_output_size);

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

    /* if the write was successful: */
    if (rc > 0) {

      /* remove the written data from the output buffer: */
      tme_serial_buffer_copyout(&serial->tme_posix_serial_buffer_out,
				NULL,
				rc,
				NULL,
				TME_SERIAL_COPY_NORMAL);

      /* call out for more data: */
      _tme_posix_serial_callout(serial);
    }
  }
  /* NOTREACHED */
}
Пример #2
0
/* the serial read callin function: */
static int
_tme_posix_serial_read(struct tme_serial_connection *conn_serial, 
		       tme_uint8_t *data, unsigned int count,
		       tme_serial_data_flags_t *_data_flags)
{
  struct tme_posix_serial *serial;
  unsigned int rc;

  /* recover our data structure: */
  serial = conn_serial->tme_serial_connection.tme_connection_element->tme_element_private;

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

  /* copy data out of the input buffer: */
  rc = tme_serial_buffer_copyout(&serial->tme_posix_serial_buffer_in,
				 data, count,
				 _data_flags,
				 TME_SERIAL_COPY_NORMAL);

  /* if the input buffer is now empty, our connection shouldn't read
     again until we have filled some of the buffer.  we don't call
     this transition out, because the convention dictates that
     our connection forget that we're readable: */
  if (rc < count) {
    serial->tme_posix_serial_ctrl_callout &= ~TME_SERIAL_CTRL_OK_READ;
    serial->tme_posix_serial_ctrl_callout_last &= ~TME_SERIAL_CTRL_OK_READ;
  }

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

  /* done: */
  return (rc);
}
Пример #3
0
/* this makes a new connection: */
static int
_tme_posix_serial_connection_make(struct tme_connection *conn, unsigned int state)
{
  struct tme_posix_serial *serial;

  /* recover our serial: */
  serial = conn->tme_connection_element->tme_element_private;

  /* both sides must be generic bus connections: */
  assert(conn->tme_connection_type == TME_CONNECTION_SERIAL);
  assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_SERIAL);

  /* serials are always set up to answer calls across the connection,
     so we only have to do work when the connection has gone full,
     namely taking the other side of the connection: */
  if (state == TME_CONNECTION_FULL) {

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

    /* save our connection: */
    serial->tme_posix_serial_connection =
      (struct tme_serial_connection *) conn->tme_connection_other;

    /* do any pending callouts: */
    _tme_posix_serial_callout(serial);

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

  return (TME_OK);
}
Пример #4
0
/* the sun4 timer thread: */
static void
_tme_sun4_timer_th(struct tme_sun4_timer *timer)
{
  struct tme_sun4 *sun4;
  struct timeval now;
  struct timeval sleep;

  /* recover our sun4: */
  sun4 = timer->tme_sun4_timer_sun4;

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

  /* loop forever: */
  for (;;) {

    /* update this timer: */
    _tme_sun4_timer_update(timer, &now, &sleep);

    /* call out any interrupts: */
    _tme_sun4_timer_callout(sun4);

    /* sleep, but wake up if our timer configuration changes: */
    tme_cond_sleep_yield(&timer->tme_sun4_timer_cond,
			 &sun4->tme_sun4_mutex,
			 &sleep);
  }
  /* NOTREACHED */
}
Пример #5
0
/* this enters native floating-point operation: */
void
tme_float_enter(int rounding_mode, void (*exception_handler)(int, void *), void *exception_handler_private)
{

  /* lock the native floating-point mutex: */
  tme_mutex_lock(&_tme_float_mutex);

  /* set any user exception handler: */
  _tme_float_exception_handler = exception_handler;
  _tme_float_exception_handler_private = exception_handler_private;

  /* establish a signal handler: */
  /* XXX FIXME this assumes that a handler installed once in one thread
     will catch signals for all threads.  obviously, whether or not this
     is true depends on how the threads package deals with signals: */
  if (!_tme_float_sigfpe_handler_installed) {
    signal(SIGFPE, _tme_float_sigfpe_handler);
    _tme_float_sigfpe_handler_installed = TRUE;
  }
  
  /* set the rounding mode: */
#ifdef HAVE_FPSETROUND
  fpsetround(rounding_mode);
#endif /* HAVE_FPSETROUND */

  /* clear the exception status: */
  _tme_float_exceptions = 0;
#ifdef HAVE_FPSETSTICKY
  fpsetsticky(0);
#endif /* HAVE_FPSETSTICKY */

  /* unmask all exceptions: */
#ifdef HAVE_FPSETMASK
  fpsetmask(0
#ifdef FP_X_INV
  | FP_X_INV
#endif
#ifdef FP_X_DNML
  | FP_X_DNML
#endif
#ifdef FP_X_DZ
  | FP_X_DZ
#endif
#ifdef FP_X_OFL
  | FP_X_OFL
#endif
#ifdef FP_X_UFL
  | FP_X_UFL
#endif
#ifdef FP_X_IMP
  | FP_X_IMP
#endif
#ifdef FP_X_IOV
  | FP_X_IOV
#endif
	    );
#endif /* HAVE_FPSETMASK */
}
Пример #6
0
/* this enters: */
struct tme_stp22xx *
tme_stp22xx_enter(struct tme_stp22xx *stp22xx)
{

  /* lock the mutex: */
  tme_mutex_lock(&stp22xx->tme_stp22xx_mutex);

  /* finish the enter: */
  return (_tme_stp22xx_enter_locked(stp22xx));
}
Пример #7
0
/* the am7930 callout function.  it must be called with the mutex locked: */
static void
_tme_am7930_callout(struct tme_am7930 *am7930)
{
  struct tme_bus_connection *conn_bus;
  int again;
  int rc;
  int int_asserted;

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

  /* callouts are now running: */
  am7930->tme_am7930_callout_flags |= TME_AM7930_CALLOUTS_RUNNING;

  /* loop while we have work to do: */
  do {
    again = FALSE;

    /* if we need to call out an interrupt: */
    int_asserted = FALSE;
    if (!!am7930->tme_am7930_int_asserted != int_asserted) {
      again = TRUE;

      /* note the new state of the interrupt signal: */
      am7930->tme_am7930_int_asserted = int_asserted;

      /* get our bus connection: */
      conn_bus = tme_memory_atomic_pointer_read(struct tme_bus_connection *,
						am7930->tme_am7930_device.tme_bus_device_connection,
						&am7930->tme_am7930_device.tme_bus_device_connection_rwlock);

      /* unlock our mutex: */
      tme_mutex_unlock(&am7930->tme_am7930_mutex);
      
      /* call out the bus interrupt signal edge: */
      rc = (*conn_bus->tme_bus_signal)
	(conn_bus,
	 TME_BUS_SIGNAL_INT_UNSPEC
	 | (int_asserted
	    ? TME_BUS_SIGNAL_LEVEL_ASSERTED
	    : TME_BUS_SIGNAL_LEVEL_NEGATED));
      assert (rc == TME_OK);
      
      /* lock our mutex: */
      tme_mutex_lock(&am7930->tme_am7930_mutex);
    }
  } while (again);

  /* clear that callouts are running: */
  am7930->tme_am7930_callout_flags &= ~TME_AM7930_CALLOUTS_RUNNING;
}
Пример #8
0
/* the serial control callin function: */
static int
_tme_posix_serial_ctrl(struct tme_serial_connection *conn_serial, unsigned int control)
{
  struct tme_posix_serial *serial;
  int modem_state;
  int rc;

  /* recover our data structure: */
  serial = conn_serial->tme_serial_connection.tme_connection_element->tme_element_private;

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

  /* get the current output device modem state: */
  rc = ioctl(serial->tme_posix_serial_fd_out, TIOCMGET, &modem_state);

  /* update the modem state: */
  if (control & TME_SERIAL_CTRL_DTR) {
    modem_state |= TIOCM_DTR;
  }
  else {
    modem_state &= TIOCM_DTR;
  }
  if (control & TME_SERIAL_CTRL_RTS) {
    modem_state |= TIOCM_RTS;
  }
  else {
    modem_state &= TIOCM_RTS;
  }

  /* set the new modem state: */
  rc = ioctl(serial->tme_posix_serial_fd_out, TIOCMSET, &modem_state);

  /* send a break: */
  if (control & TME_SERIAL_CTRL_BREAK) {
    tcsendbreak(serial->tme_posix_serial_fd_out, 0);
  }

  /* remember these controls.  if the OK_READ is set, call out a read: */
  serial->tme_posix_serial_ctrl_callin = control;
  if (control & TME_SERIAL_CTRL_OK_READ) {
    _tme_posix_serial_callout(serial);
  }

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

  /* done: */
  return (TME_OK);
}
Пример #9
0
/* this makes a new framebuffer connection: */
static int
_tme_gtk_screen_connection_make(struct tme_connection *conn,
				unsigned int state)
{
  struct tme_gtk_display *display;
  struct tme_gtk_screen *screen;
  struct tme_fb_connection *conn_fb;
  struct tme_fb_connection *conn_fb_other;

  /* recover our data structures: */
  display = (struct tme_gtk_display *) conn->tme_connection_element->tme_element_private;
  conn_fb = (struct tme_fb_connection *) conn;
  conn_fb_other = (struct tme_fb_connection *) conn->tme_connection_other;

  /* both sides must be framebuffer connections: */
  assert(conn->tme_connection_type
	 == TME_CONNECTION_FRAMEBUFFER);
  assert(conn->tme_connection_other->tme_connection_type
	 == TME_CONNECTION_FRAMEBUFFER);

  /* we're always set up to answer calls across the connection, so we
     only have to do work when the connection has gone full, namely
     taking the other side of the connection: */
  if (state == TME_CONNECTION_FULL) {

    /* lock our mutex: */
    tme_mutex_lock(&display->tme_gtk_display_mutex);

    /* if our initial screen is already connected, make a new screen: */
    screen = display->tme_gtk_display_screens;
    if (screen->tme_gtk_screen_fb != NULL) {
      screen = _tme_gtk_screen_new(display);
    }

    /* save our connection: */
    screen->tme_gtk_screen_fb = conn_fb;

    /* unlock our mutex: */
    tme_mutex_unlock(&display->tme_gtk_display_mutex);

    /* call our mode change function: */
    _tme_gtk_screen_mode_change(conn_fb);
  }

  return (TME_OK);
}
Пример #10
0
/* this can be called to force an immediate timer interrupt: */
void
_tme_sun4_timer_int_force(struct tme_sun4 *sun4,
			  struct tme_sun4_timer *timer)
{

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

  /* force an immediate timer interrupt: */
  timer->tme_sun4_timer_counter = TME_SUN4_32_TIMER_LIMIT;
  timer->tme_sun4_timer_limit |= TME_SUN4_32_TIMER_LIMIT;

  /* call out any interrupts: */
  _tme_sun4_timer_callout(sun4);

  /* unlock our mutex: */
  tme_mutex_unlock(&sun4->tme_sun4_mutex);
}
Пример #11
0
/* this makes a new connection: */
static int
_tme_sun_obie_connection_make(struct tme_connection *conn, unsigned int state)
{
  struct tme_sun_obie *sun_obie;
  struct tme_sun_obie_connection *conn_sun_obie;
  struct tme_bus_connection *conn_bus;

  /* both sides must be generic bus connections: */
  assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
  assert(conn->tme_connection_other->tme_connection_type
	 == conn->tme_connection_type);

  /* recover our data structures: */
  sun_obie = conn->tme_connection_element->tme_element_private;
  conn_sun_obie = (struct tme_sun_obie_connection *)conn;
  conn_bus = &conn_sun_obie->tme_sun_obie_connection;

  /* we're always set up to answer calls across the connection, so we
     only have to do work when the connection has gone full, namely
     taking the other side of the connection: */
  if (state == TME_CONNECTION_FULL) {

    /* lock our mutex: */
    tme_mutex_lock(&sun_obie->tme_sun_obie_mutex);

    /* save our connection: */
    if (conn_bus->tme_bus_signals_add != NULL) {
      sun_obie->tme_sun_obie_conn_i825x6 = (struct tme_bus_connection *) conn->tme_connection_other;
    }
    else if (conn_sun_obie->tme_sun_obie_connection_regs) {
      sun_obie->tme_sun_obie_conn_regs = (struct tme_bus_connection *) conn->tme_connection_other;
    }
    else {
      sun_obie->tme_sun_obie_conn_memory = (struct tme_bus_connection *) conn->tme_connection_other;
    }

    /* unlock our mutex: */
    tme_mutex_unlock(&sun_obie->tme_sun_obie_mutex);
  }

  return (TME_OK);
}
Пример #12
0
/* the am7930 bus signal handler: */
static int
_tme_am7930_signal(void *_am7930, 
		   unsigned int signal)
{
  struct tme_am7930 *am7930;
  unsigned int level;

  /* recover our data structure: */
  am7930 = (struct tme_am7930 *) _am7930;

  /* lock the mutex: */
  tme_mutex_lock(&am7930->tme_am7930_mutex);

  /* take out the signal level: */
  level = signal & TME_BUS_SIGNAL_LEVEL_MASK;
  signal = TME_BUS_SIGNAL_WHICH(signal);

  /* dispatch on the generic bus signals: */
  switch (signal) {
  case TME_BUS_SIGNAL_RESET:
    if (level == TME_BUS_SIGNAL_LEVEL_ASSERTED) {
      _tme_am7930_reset(am7930);
    }
    break;
  default:
    signal = TME_BUS_SIGNAL_IGNORE;
    break;
  }

  /* if we didn't ignore this bus signal: */
  if (signal != TME_BUS_SIGNAL_IGNORE) {

    /* make any new callouts: */
    _tme_am7930_callout(am7930);
  }

  /* unlock the mutex: */
  tme_mutex_unlock(&am7930->tme_am7930_mutex);

  /* no faults: */
  return (TME_OK);
}
Пример #13
0
/* this sets the screen size: */
static void
_tme_gtk_screen_scale_set(GtkWidget *widget,
			  struct tme_gtk_screen *screen,
			  int scale_new)
{
  struct tme_gtk_display *display;
  int scale_old;
  int rc;

  /* return now if the menu item isn't active: */
  if (!GTK_CHECK_MENU_ITEM(GTK_MENU_ITEM(widget))->active) {
    return;
  }

  /* get the display: */
  display = screen->tme_gtk_screen_display;

  /* lock our mutex: */
  tme_mutex_lock(&display->tme_gtk_display_mutex);

  /* get the old scaling and set the new scaling: */
  scale_old = screen->tme_gtk_screen_fb_scale;
  if (scale_old < 0
      && scale_new < 0) {
    scale_new = scale_old;
  }
  screen->tme_gtk_screen_fb_scale = scale_new;

  /* unlock our mutex: */
  tme_mutex_unlock(&display->tme_gtk_display_mutex);

  /* call the mode change function if the scaling has changed: */
  if (scale_new != scale_old) {
    rc = _tme_gtk_screen_mode_change(screen->tme_gtk_screen_fb);
    assert (rc == TME_OK);
  }
}
Пример #14
0
/* the sun_obie callout function.  it must be called with the mutex locked: */
static void
_tme_sun_obie_callout(struct tme_sun_obie *sun_obie, int new_callouts)
{
  struct tme_bus_connection *conn_i825x6;
  struct tme_bus_connection *conn_bus;
  tme_uint16_t csr, csr_diff;
  unsigned int signal, level;
  int callouts, later_callouts;
  int rc;
  int int_asserted;
  
  /* add in any new callouts: */
  sun_obie->tme_sun_obie_callout_flags |= new_callouts;

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

  /* callouts are now running: */
  sun_obie->tme_sun_obie_callout_flags |= TME_SUN_OBIE_CALLOUT_RUNNING;

  /* assume that we won't need any later callouts: */
  later_callouts = 0;

  /* loop while callouts are needed: */
  for (; (callouts = sun_obie->tme_sun_obie_callout_flags) & TME_SUN_OBIE_CALLOUTS_MASK; ) {

    /* clear the needed callouts: */
    sun_obie->tme_sun_obie_callout_flags = callouts & ~TME_SUN_OBIE_CALLOUTS_MASK;
    callouts &= TME_SUN_OBIE_CALLOUTS_MASK;

    /* if we need to call out one or more signals to the i825x6: */
    if (callouts & TME_SUN_OBIE_CALLOUT_SIGNALS) {

      /* get the current CSR value: */
      csr = TME_SUN_OBIE_CSR_GET(sun_obie);

      /* get the next signal to call out to the i825x6: */
      csr_diff = ((csr
		   ^ sun_obie->tme_sun_obie_csr_i825x6)
		  & (TME_SUN_OBIE_CSR_NORESET
		     | TME_SUN_OBIE_CSR_NOLOOP
		     | TME_SUN_OBIE_CSR_CA));
      csr_diff = (csr_diff ^ (csr_diff - 1)) & csr_diff;
      
      /* if there is a signal to call out: */
      if (csr_diff != 0) {

	/* assume that if the signal's bit is set in the CSR, it will
	   be asserted: */
	level = csr & csr_diff;

	/* assume that we're calling out an i825x6 signal: */
	signal = (_tme_sun_obie_bus_signals_generic.tme_bus_signals_first
		  + TME_BUS_SIGNAL_X(_tme_sun_obie_bus_signals_generic.tme_bus_signals_count));

	/* dispatch on the CSR bit: */
	switch (csr_diff) {
	default:
	  assert (FALSE);
	case TME_SUN_OBIE_CSR_NORESET:
	  signal = TME_BUS_SIGNAL_RESET;
	  level = !level;
	  break;
	case TME_SUN_OBIE_CSR_NOLOOP:
	  signal += TME_I825X6_SIGNAL_LOOP;
	  level = !level;
	  break;
	case TME_SUN_OBIE_CSR_CA:
	  signal += TME_I825X6_SIGNAL_CA;
	  break;
	}

	/* create a real signal level value: */
	level = (level
		 ? TME_BUS_SIGNAL_LEVEL_ASSERTED
		 : TME_BUS_SIGNAL_LEVEL_NEGATED);

	/* get this card's i825x6 connection: */
	conn_i825x6 = sun_obie->tme_sun_obie_conn_i825x6;

	/* unlock the mutex: */
	tme_mutex_unlock(&sun_obie->tme_sun_obie_mutex);
      
	/* do the callout: */
	rc = (conn_i825x6 != NULL
	      ? ((*conn_i825x6->tme_bus_signal)
		 (conn_i825x6,
		  signal | level))
	      : TME_OK);
	
	/* lock the mutex: */
	tme_mutex_lock(&sun_obie->tme_sun_obie_mutex);
      
	/* if the callout was unsuccessful, remember that at some later
	   time this callout should be attempted again: */
	if (rc != TME_OK) {
	  later_callouts |= TME_SUN_OBIE_CALLOUT_SIGNALS;
	}

	/* otherwise, the callout was successful: */
	else {

	  /* update the i825x6 image of the CSR: */
	  sun_obie->tme_sun_obie_csr_i825x6 = 
	    ((sun_obie->tme_sun_obie_csr_i825x6 & ~csr_diff)
	     | (csr & csr_diff));

	  /* there may be more signals to call out, so attempt this
             callout again now: */
	  sun_obie->tme_sun_obie_callout_flags |= TME_SUN_OBIE_CALLOUT_SIGNALS;
	}
      }
    }

    /* if we need to call out a possible change to our interrupt
       signal: */
    if (callouts & TME_SUN_OBIE_CALLOUT_INT) {

      /* get the current CSR value: */
      csr = TME_SUN_OBIE_CSR_GET(sun_obie);

      /* see if the interrupt signal should be asserted or negated: */
      int_asserted = ((csr & (TME_SUN_OBIE_CSR_IE
			      | TME_SUN_OBIE_CSR_INTR))
		      == (TME_SUN_OBIE_CSR_IE
			  | TME_SUN_OBIE_CSR_INTR));

      /* if the interrupt signal doesn't already have the right state: */
      if (!int_asserted != !sun_obie->tme_sun_obie_int_asserted) {

	/* get our bus connection: */
	conn_bus = sun_obie->tme_sun_obie_conn_regs;
	
	/* unlock our mutex: */
	tme_mutex_unlock(&sun_obie->tme_sun_obie_mutex);
	
	/* call out the bus interrupt signal edge: */
	rc = (conn_bus != NULL
	      ? ((*conn_bus->tme_bus_signal)
		 (conn_bus,
		  TME_BUS_SIGNAL_INT_UNSPEC
		  | (int_asserted
		     ? TME_BUS_SIGNAL_LEVEL_ASSERTED
		     : TME_BUS_SIGNAL_LEVEL_NEGATED)))
	      : TME_OK);

	/* lock our mutex: */
	tme_mutex_lock(&sun_obie->tme_sun_obie_mutex);
	
	/* if this callout was successful, note the new state of the
	   interrupt signal: */
	if (rc == TME_OK) {
	  sun_obie->tme_sun_obie_int_asserted = int_asserted;
	}

	/* otherwise, remember that at some later time this callout
	   should be attempted again: */
	else {
	  later_callouts |= TME_SUN_OBIE_CALLOUT_INT;
	}
      }
    }
  }
  
  /* put in any later callouts, and clear that callouts are running: */
  sun_obie->tme_sun_obie_callout_flags = later_callouts;
}
Пример #15
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);
}
Пример #16
0
/* the isil7170 timer thread: */
static void
_tme_isil7170_th_timer(struct tme_isil7170 *isil7170)
{
  tme_uint8_t int_mask;
  tme_uint32_t sleep_usec;
#ifdef TME_ISIL7170_TRACK_INT_RATE
  struct timeval now;
#endif /* TME_ISIL7170_TRACK_INT_RATE */

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

  /* loop forever: */
  for (;;) {

    /* if we were sleeping: */
    int_mask = isil7170->tme_isil7170_timer_sleeping;
    isil7170->tme_isil7170_timer_sleeping = 0;
    if (int_mask) {

#ifdef TME_ISIL7170_TRACK_INT_RATE

      /* if no interrupt is pending, and this interrupt is not masked,
	 we will deliver another interrupt: */
      if (!(isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT]
	    & TME_ISIL7170_INT_PENDING)
	  && (int_mask
	      & isil7170->tme_isil7170_int_mask)) {
	isil7170->tme_isil7170_int_sample++;
      }

      /* if the sample time has finished, report on the interrupt rate: */
      gettimeofday(&now, NULL);
      if (now.tv_sec > isil7170->tme_isil7170_int_sample_time.tv_sec
	  || (now.tv_sec == isil7170->tme_isil7170_int_sample_time.tv_sec
	      && now.tv_usec > isil7170->tme_isil7170_int_sample_time.tv_usec)) {
	if (isil7170->tme_isil7170_int_sample > 0) {
	  tme_log(TME_ISIL7170_LOG_HANDLE(isil7170),
		  0, TME_OK,
		  (TME_ISIL7170_LOG_HANDLE(isil7170),
		   "timer interrupt rate: %ld/sec",
		   (isil7170->tme_isil7170_int_sample
		    / (TME_ISIL7170_TRACK_INT_RATE
		       + (unsigned long) (now.tv_sec
					  - isil7170->tme_isil7170_int_sample_time.tv_sec)))));
	}

	/* reset the sample: */
	isil7170->tme_isil7170_int_sample_time.tv_sec = now.tv_sec + TME_ISIL7170_TRACK_INT_RATE;
	isil7170->tme_isil7170_int_sample_time.tv_usec = now.tv_usec;
	isil7170->tme_isil7170_int_sample = 0;
      }

#endif /* TME_ISIL7170_TRACK_INT_RATE */

      /* update the interrupt register: */
      isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] |= int_mask;

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

    /* get the interrupt mask: */
    int_mask = isil7170->tme_isil7170_int_mask;

    /* if the 1/100 second periodic interrupt is unmasked: */
    if (int_mask & TME_ISIL7170_INT_HSEC) {
      int_mask = TME_ISIL7170_INT_HSEC;
      sleep_usec = isil7170->tme_isil7170_clock_hsec_usec;
    }

    /* if the 1/10 second periodic interrupt is unmasked: */
    else if (int_mask & TME_ISIL7170_INT_TSEC) {
      int_mask = TME_ISIL7170_INT_TSEC;
      sleep_usec = isil7170->tme_isil7170_clock_tsec_usec;
    }

    /* otherwise, all periodic interrupts are masked.  wait until one
       of them is not: */
    else {
      tme_cond_wait_yield(&isil7170->tme_isil7170_cond_timer,
			  &isil7170->tme_isil7170_mutex);
      continue;
    }

    /* we are sleeping: */
    isil7170->tme_isil7170_timer_sleeping = int_mask;

    /* unlock our mutex: */
    tme_mutex_unlock(&isil7170->tme_isil7170_mutex);

    /* sleep: */
    tme_thread_sleep_yield(0, sleep_usec);

    /* lock our mutex: */
    tme_mutex_unlock(&isil7170->tme_isil7170_mutex);
  }
  /* NOTREACHED */
}
Пример #17
0
/* this makes isil7170 callouts.  it must be called with the mutex held: */
static void
_tme_isil7170_callout(struct tme_isil7170 *isil7170)
{
  struct tme_bus_connection *conn_bus;
  int again;
  int int_asserted;
  int rc;

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

  /* callouts are now running: */
  isil7170->tme_isil7170_callouts_running = TRUE;

  /* get our bus connection: */
  conn_bus = tme_memory_atomic_pointer_read(struct tme_bus_connection *,
					    isil7170->tme_isil7170_device.tme_bus_device_connection,
					    &isil7170->tme_isil7170_device.tme_bus_device_connection_rwlock);

  /* loop forever: */
  for (again = TRUE; again;) {
    again = FALSE;

    /* see if there are any pending, unmasked interrupts: */
    int_asserted = (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT]
		    & isil7170->tme_isil7170_int_mask);

    /* update our interrupt-pending flag: */
    if (int_asserted) {
      isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT]
	= ((isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT]
	    & ~TME_ISIL7170_INT_PENDING)
	   | (int_asserted
	      ? TME_ISIL7170_INT_PENDING
	      : 0));
    }

    /* see if our interrupt signal should be asserted: */
    int_asserted
      = (int_asserted
	 && (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD]
	     & TME_ISIL7170_CMD_INTENA));

    /* if our interrupt signal has changed: */
    if (!int_asserted != !isil7170->tme_isil7170_int_asserted) {

      /* unlock our mutex: */
      tme_mutex_unlock(&isil7170->tme_isil7170_mutex);

      rc = (*conn_bus->tme_bus_signal)
	(conn_bus,
	 isil7170->tme_isil7170_int_signal
	 | (int_asserted
	    ? TME_BUS_SIGNAL_LEVEL_ASSERTED
	    : TME_BUS_SIGNAL_LEVEL_NEGATED));

      /* lock our mutex: */
      tme_mutex_lock(&isil7170->tme_isil7170_mutex);
      
      /* if this call out succeeded, update the interrupt-asserted flag: */
      if (rc == TME_OK) {
	isil7170->tme_isil7170_int_asserted = int_asserted;
	again = TRUE;
      }
    }
  }

  /* there are no more callouts to make: */
  isil7170->tme_isil7170_callouts_running = FALSE;
}
Пример #18
0
/* the am7930 bus cycle handler: */
static int
_tme_am7930_bus_cycle(void *_am7930, struct tme_bus_cycle *cycle_init)
{
  struct tme_am7930 *am7930;
  unsigned int reg;
  tme_uint8_t value;

  /* recover our data structure: */
  am7930 = (struct tme_am7930 *) _am7930;

  /* the address must be within range: */
  assert(cycle_init->tme_bus_cycle_address < TME_AM7930_SIZ_REGS);
  assert(cycle_init->tme_bus_cycle_size <= (TME_AM7930_SIZ_REGS - cycle_init->tme_bus_cycle_address));

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

  /* lock the mutex: */
  tme_mutex_lock(&am7930->tme_am7930_mutex);

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

    /* turn the address into a proper register number for writing: */
    if ((TME_AM7930_REGS_RW & TME_BIT(reg)) != 0) {
      reg = TME_AM7930_REG_RW(reg);
    }
    else {
      reg = TME_AM7930_REG_WO(reg);
    }

    /* run the bus cycle: */
    tme_bus_cycle_xfer_reg(cycle_init, 
			   &value,
			   TME_BUS8_LOG2);

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

    default:
      break;
    }
  }
	    
  /* otherwise, this is a read: */
  else {
    assert (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ);

    /* get the value to read: */
    value = 0;

    /* run the bus cycle: */
    tme_bus_cycle_xfer_reg(cycle_init, 
			   &value,
			   TME_BUS8_LOG2);
  }

  /* make any new callouts: */
  _tme_am7930_callout(am7930);

  /* unlock the mutex: */
  tme_mutex_unlock(&am7930->tme_am7930_mutex);

  /* no faults: */
  return (TME_OK);
}
Пример #19
0
/* the GTK screens update thread: */
void
_tme_gtk_screen_th_update(struct tme_gtk_display *display)
{
  struct tme_gtk_screen *screen;
  struct tme_fb_connection *conn_fb_other;
  int changed;
  int rc;
  
  /* loop forever: */
  for (;;) {

    /* lock the mutex: */
    tme_mutex_lock(&display->tme_gtk_display_mutex);

    /* loop over all screens: */
    for (screen = display->tme_gtk_display_screens;
	 screen != NULL;
	 screen = screen->tme_gtk_screen_next) {

      /* skip this screen if it's unconnected: */
      if (screen->tme_gtk_screen_fb == NULL) {
	continue;
      }

      /* get the other side of this connection: */
      conn_fb_other
	= ((struct tme_fb_connection *) 
	   screen->tme_gtk_screen_fb->tme_fb_connection.tme_connection_other);

      /* if the framebuffer has an update function, call it: */
      if (conn_fb_other->tme_fb_connection_update != NULL) {
	rc = (*conn_fb_other->tme_fb_connection_update)(conn_fb_other);
	assert (rc == TME_OK);
      }

      /* if this framebuffer needs a full redraw: */
      if (screen->tme_gtk_screen_full_redraw) {

	/* force the next translation to retranslate the entire buffer: */
	tme_fb_xlat_redraw(conn_fb_other);
	conn_fb_other->tme_fb_connection_offset_updated_first = 0;
	conn_fb_other->tme_fb_connection_offset_updated_last = 0 - (tme_uint32_t) 1;

	/* clear the full redraw flag: */
	screen->tme_gtk_screen_full_redraw = FALSE;
      }

      /* translate this framebuffer's contents: */
      changed = (*screen->tme_gtk_screen_fb_xlat)
	(((struct tme_fb_connection *) 
	  screen->tme_gtk_screen_fb->tme_fb_connection.tme_connection_other),
	 screen->tme_gtk_screen_fb);

      /* if those contents changed, redraw the widget: */
      if (changed) {
	gtk_widget_queue_draw(screen->tme_gtk_screen_gtkimage);
      }
    }

    /* unlock the mutex: */
    tme_mutex_unlock(&display->tme_gtk_display_mutex);

    /* update again in .5 seconds: */
    tme_thread_sleep_yield(0, 500000);
  }
  /* NOTREACHED */
}
Пример #20
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;
}
Пример #21
0
/* this makes timer callouts.  it must be called with the mutex held: */
static void
_tme_sun4_timer_callout(struct tme_sun4 *sun4)
{
  struct tme_bus_connection *conn_bus;
  struct tme_sun4_timer *timer;
  unsigned int int_asserted;
  int again;
  int rc;

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

  /* callouts are now running: */
  sun4->tme_sun4_timer_callouts_running = TRUE;

  /* get our bus connection: */
  conn_bus = sun4->tme_sun4_buses[TME_SUN4_32_CONN_REG_TIMER];

  /* loop forever: */
  for (again = TRUE; again;) {
    again = FALSE;

    /* check all of the timers for changes: */
    timer = &sun4->tme_sun4_timers[0];
    do {
      
      /* if this timer needs an interrupt callout: */
      int_asserted = (timer->tme_sun4_timer_counter & TME_SUN4_32_TIMER_LIMIT) != 0;
      if (!int_asserted
	  != !timer->tme_sun4_timer_int_asserted) {

	/* unlock our mutex: */
	tme_mutex_unlock(&sun4->tme_sun4_mutex);

	/* call out the bus interrupt signal edge: */
	rc = (*conn_bus->tme_bus_signal)
	  (conn_bus,
	   ((timer == &sun4->tme_sun4_timers[0]
	     ? TME_BUS_SIGNAL_INT(10)
	     : TME_BUS_SIGNAL_INT(14))
	    | (int_asserted
	       ? TME_BUS_SIGNAL_LEVEL_ASSERTED
	       : TME_BUS_SIGNAL_LEVEL_NEGATED)));

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

	/* if this callout was successful, note the new state of the
	   interrupt signal: */
	if (rc == TME_OK) {
	  timer->tme_sun4_timer_int_asserted = int_asserted;
	  again = TRUE;
	}

	/* otherwise, abort: */
	else {
	  abort();
	}
      }
    } while (++timer != (&sun4->tme_sun4_timers[0] + TME_ARRAY_ELS(sun4->tme_sun4_timers)));

  }

  /* there are no more callouts to make: */
  sun4->tme_sun4_timer_callouts_running = FALSE;
}
Пример #22
0
/* the serial control thread: */
static void
_tme_posix_serial_th_ctrl(struct tme_posix_serial *serial)
{
  int modem_state, modem_state_out;
  unsigned int ctrl;

  /* loop forever: */
  for (;;) {
   
    /* get the modem state of the input device: */
    if (ioctl(serial->tme_posix_serial_fd_in, TIOCMGET, &modem_state) < 0) {
      modem_state = 0;
    }

    /* if the output device is different, get the modem state of the
       output device and merge it in: */
    if (serial->tme_posix_serial_fd_out
	!= serial->tme_posix_serial_fd_in) {
      if (ioctl(serial->tme_posix_serial_fd_in, TIOCMGET, &modem_state_out) < 0) {
	modem_state_out = 0;
      }
      modem_state &= ~(TIOCM_DTR | TIOCM_RTS | TIOCM_CTS);
      modem_state |= modem_state_out & ~(TIOCM_CD | TIOCM_RI | TIOCM_DSR);
    }
    
    /* lock the mutex: */
    tme_mutex_lock(&serial->tme_posix_serial_mutex);
    
    /* update the control outputs: */
    ctrl = (serial->tme_posix_serial_ctrl_callout
	    & ~(TME_SERIAL_CTRL_CTS
		| TME_SERIAL_CTRL_DCD
		| TME_SERIAL_CTRL_RI
		| TME_SERIAL_CTRL_BREAK));
    if (modem_state & TIOCM_CTS) {
      ctrl |= TME_SERIAL_CTRL_CTS;
    }
    if (modem_state & TIOCM_CD) {
      ctrl |= TME_SERIAL_CTRL_DCD;
    }
    if (modem_state & TIOCM_RI) {
      ctrl |= TME_SERIAL_CTRL_RI;
    }
    if (serial->tme_posix_serial_ctrl_callout_break > 0) {
      ctrl |= TME_SERIAL_CTRL_BREAK;
      serial->tme_posix_serial_ctrl_callout_break--;
    }
    
    /* if the control outputs have changed, call out the change: */
    if (ctrl != serial->tme_posix_serial_ctrl_callout) {
      serial->tme_posix_serial_ctrl_callout = ctrl;
      _tme_posix_serial_callout(serial);
    }
    
    /* unlock the mutex: */
    tme_mutex_unlock(&serial->tme_posix_serial_mutex);

    /* check the controls again in .5 seconds: */
    tme_thread_sleep_yield(0, 500000);
  }
  /* NOTREACHED */
}
Пример #23
0
/* the serial reader thread: */
static void
_tme_posix_serial_th_reader(struct tme_posix_serial *serial)
{
  tme_uint8_t buffer_input[1024];
  tme_uint8_t buffer_slack[10];
  tme_uint8_t byte, *byte_head, *byte_tail;
  int scanner_state;
  int buffer_was_empty;
  int rc;

  /* loop forever: */
  for (;;) {

    /* try to read the device: */
    rc = tme_thread_read_yield(serial->tme_posix_serial_fd_in,
			       buffer_input,
			       sizeof(buffer_input));

    /* if the read failed: */
    if (rc < 0) {
      /* XXX diagnostic */
      continue;
    }

    /* if we hit EOF: */
    if (rc == 0) {
      return;
    }

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

    /* remember if this buffer was empty: */
    buffer_was_empty =
      tme_serial_buffer_is_empty(&serial->tme_posix_serial_buffer_in);

    /* scan the input: */
    byte_head = buffer_input;
    scanner_state = serial->tme_posix_serial_input_scanner_state;
    for (; rc > 0; ) {
	  
      /* in state zero, we haven't seen anything interesting: */
      if (scanner_state == 0) {
	
	/* scan quickly, stopping only when we see an escape: */
	byte_tail = byte_head;
	if (serial->tme_posix_serial_emulate_break) {
	  do {
	    byte = *(byte_head++);
	    if (byte == 0xff
		|| byte == '^') {
	      break;
	    }
	  } while (--rc > 0);
	}
	else {
	  do {
	    byte = *(byte_head++);
	    if (byte == 0xff) {
	      break;
	    }
	  } while (--rc > 0);
	}
	
	/* if we stopped scanning because we saw an escape, back up: */
	if (rc > 0) {
	  byte_head--;
	}

	/* add in the normal data we scanned quickly: */
	if (byte_head > byte_tail) {
	  (void) tme_serial_buffer_copyin(&serial->tme_posix_serial_buffer_in,
					  byte_tail,
					  (byte_head - byte_tail),
					  TME_SERIAL_DATA_NORMAL,
					  TME_SERIAL_COPY_FULL_IS_OVERRUN);
	}

	/* if this byte is an 0xff, move to state one: */
	if (byte == 0xff) {
	  byte_head++;
	  --rc;
	  scanner_state = 1;
	}

	/* if we're emulating breaks, and this is a carat, move to
	   state eight: */
	else if (serial->tme_posix_serial_emulate_break
		 && byte == '^') {
	  byte_head++;
	  --rc;
	  scanner_state = 8;
	}
	
	/* otherwise, we must have drained everything: */
	else {
	  assert(rc == 0);
	}
      }

      /* in state one, we have seen 0xff: */
      else if (scanner_state == 1) {

	/* get the next byte: */
	byte = *(byte_head++);
	--rc;
	
	/* if this is an 0x00, move to state two: */
	if (byte == 0x00) {
	  scanner_state = 2;
	}
	
	/* otherwise, receive 0xff, and if this is not an 0xff, return
	   it to the buffer.  move to state zero: */
	else {
	  buffer_slack[0] = 0xff;
	  (void) tme_serial_buffer_copyin(&serial->tme_posix_serial_buffer_in,
					  buffer_slack,
					  1,
					  TME_SERIAL_DATA_NORMAL,
					  TME_SERIAL_COPY_FULL_IS_OVERRUN);
	  if (byte != 0xff) {
	    byte_head--;
	    ++rc;
	  }
	  scanner_state = 0;
	}
      }

      /* in state two, we have seen 0xff 0x00: */
      else if (scanner_state == 2) {

	/* get the next byte: */
	byte = *(byte_head++);
	--rc;
	
	/* if this is an 0x00, this is a break: */
	if (byte == 0x00) {

	  /* if break isn't already being asserted, assert it and call
	     out the change.  always reset the assertion time: */
	  if (!(serial->tme_posix_serial_ctrl_callout & TME_SERIAL_CTRL_BREAK)) {
	    serial->tme_posix_serial_ctrl_callout |= TME_SERIAL_CTRL_BREAK;
	    _tme_posix_serial_callout(serial);
	  }
	  serial->tme_posix_serial_ctrl_callout_break = 2;
	}

	/* otherwise, this byte was received with bad framing or
	   parity.  we can't tell which, so call it bad parity: */
	else {
	  (void) tme_serial_buffer_copyin(&serial->tme_posix_serial_buffer_in,
					  byte_head - 1,
					  1,
					  TME_SERIAL_DATA_BAD_PARITY,
					  TME_SERIAL_COPY_FULL_IS_OVERRUN);
	}
	
	/* move to state zero: */
	scanner_state = 0;
      }

      /* in states eight and nine, we have seen one or two break escapes,
	 respectively: */
      else if (scanner_state == 8
	       || scanner_state == 9) {
	assert(serial->tme_posix_serial_emulate_break);
	
	/* get the next byte: */
	byte = *(byte_head++);
	--rc;
	
	/* if this isn't also a break escape, return it to the
	   buffer, receive the break escapes, and move to state
	   zero: */
	if (byte != '^') {
	  byte_head--;
	  ++rc;
	  buffer_slack[0] = buffer_slack[1] = '^';
	  (void) tme_serial_buffer_copyin(&serial->tme_posix_serial_buffer_in,
					  buffer_slack,
					  scanner_state - 7,
					  TME_SERIAL_DATA_NORMAL,
					  TME_SERIAL_COPY_FULL_IS_OVERRUN);
	  scanner_state = 0;
	}
	
	/* otherwise, this is a break escape.  if we have now seen
	   three total, this is a break, and move to state zero: */
	else if (++scanner_state == 10) {

	  /* if break isn't already being asserted, assert it and call
	     out the change.  always reset the assertion time: */
	  if (!(serial->tme_posix_serial_ctrl_callout & TME_SERIAL_CTRL_BREAK)) {
	    serial->tme_posix_serial_ctrl_callout |= TME_SERIAL_CTRL_BREAK;
	    _tme_posix_serial_callout(serial);
	  }
	  serial->tme_posix_serial_ctrl_callout_break = 2;
	  scanner_state = 0;
	}
      }
      
      /* any other state is impossible: */
      else {
	assert(FALSE);
      }
    }
	      
    /* update the scanner state: */
    serial->tme_posix_serial_input_scanner_state = scanner_state;

    /* if the input buffer was previously empty, and it is now not
       empty, call out that we can be read again: */
    if (buffer_was_empty
	&& !tme_serial_buffer_is_empty(&serial->tme_posix_serial_buffer_in)) {
      serial->tme_posix_serial_ctrl_callout |= TME_SERIAL_CTRL_OK_READ;
      _tme_posix_serial_callout(serial);
    }

    /* unlock the mutex: */
    tme_mutex_unlock(&serial->tme_posix_serial_mutex);
  }
  /* NOTREACHED */
}
Пример #24
0
/* the serial configuration callin function: */
static int
_tme_posix_serial_config(struct tme_serial_connection *conn_serial, struct tme_serial_config *config)
{
  struct tme_posix_serial *serial;
  struct termios serial_termios;
  tme_uint32_t config_baud;
  speed_t termios_baud;
  int is_input, rc;

  /* recover our data structure: */
  serial = conn_serial->tme_serial_connection.tme_connection_element->tme_element_private;

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

  /* loop over the input and output devices: */
  for (is_input = 2; is_input-- > 0; ) {

    /* get the current configuration of the device: */
    rc = tcgetattr((is_input
		    ? serial->tme_posix_serial_fd_in
		    : serial->tme_posix_serial_fd_out),
		   &serial_termios);
    
    /* update the configuration: */
    
    /* baud rate: */
    config_baud = config->tme_serial_config_baud;
    termios_baud = (config_baud == 0 ? B0
		    : config_baud <= 50 ? B50
		    : config_baud <= 75 ? B75
		    : config_baud <= 110 ? B110
		    : config_baud <= 134 ? B134
		    : config_baud <= 150 ? B150
		    : config_baud <= 200 ? B200
		    : config_baud <= 300 ? B300
		    : config_baud <= 600 ? B600
		    : config_baud <= 1200 ? B1200
		    : config_baud <= 1800 ? B1800
		    : config_baud <= 2400 ? B2400
		    : config_baud <= 4800 ? B4800
		    : config_baud <= 9600 ? B9600
		    : config_baud <= 19200 ? B19200
		    : config_baud <= 38400 ? B38400
		    : (speed_t) -1);
    if (termios_baud == (speed_t) -1) {
      /* XXX diagnostic */
      termios_baud = B38400;
    }
    rc = cfsetspeed(&serial_termios, termios_baud);

    /* input mode or output mode: */
    if (is_input) {
      serial_termios.c_iflag = PARMRK;
      if (config->tme_serial_config_flags & TME_SERIAL_FLAGS_CHECK_PARITY) {
	serial_termios.c_iflag = INPCK;
      }
    }
    else {
      serial_termios.c_oflag = 0;
    }

    /* control mode: */
    serial_termios.c_cflag = CREAD | CLOCAL;
    switch (config->tme_serial_config_bits_data) {
    case 5: serial_termios.c_cflag |= CS5; break;
    case 6: serial_termios.c_cflag |= CS6; break;
    case 7: serial_termios.c_cflag |= CS7; break;
    default: assert(FALSE);
    case 8: serial_termios.c_cflag |= CS8; break;
    }
    switch (config->tme_serial_config_bits_stop) {
    case 1: break;
    default: assert(FALSE);
    case 2: serial_termios.c_cflag |= CSTOPB; break;
    }
    switch (config->tme_serial_config_parity) {
    default: assert(FALSE);
    case TME_SERIAL_PARITY_NONE: break;
    case TME_SERIAL_PARITY_ODD: serial_termios.c_cflag |= PARENB | PARODD; break;
    case TME_SERIAL_PARITY_EVEN: serial_termios.c_cflag |= PARENB; break;
    }
  
    /* local mode: */
    serial_termios.c_lflag = 0;

    /* set the configuration on the devices: */
    rc = tcsetattr((is_input
		    ? serial->tme_posix_serial_fd_in
		    : serial->tme_posix_serial_fd_out),
		   TCSADRAIN,
		   &serial_termios);
  }

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

  /* done: */
  return (TME_OK);
}
Пример #25
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);
}
Пример #26
0
/* the sun_obie bus cycle handler for the board registers: */
static int
_tme_sun_obie_bus_cycle_regs(void *_sun_obie, 
			     struct tme_bus_cycle *cycle_init)
{
  struct tme_sun_obie *sun_obie;
  tme_uint16_t csr_old, csr_new, csr_diff;
  int new_callouts;

  /* recover our data structure: */
  sun_obie = (struct tme_sun_obie *) _sun_obie;

  /* assume we won't need any new callouts: */
  new_callouts = 0;

  /* lock the mutex: */
  tme_mutex_lock(&sun_obie->tme_sun_obie_mutex);

  /* get the previous CSR value: */
  csr_old = TME_SUN_OBIE_CSR_GET(sun_obie);

  /* run the cycle: */
  tme_bus_cycle_xfer_memory(cycle_init, 
			    sun_obie->tme_sun_obie_regs,
			    TME_SUN_OBIE_SIZ_REGS - 1);

  /* get the current CSR value, and put back any bits that
     software can't change: */
  csr_new = ((TME_SUN_OBIE_CSR_GET(sun_obie)
	      & ~TME_SUN_OBIE_CSR_READONLY)
	     | (csr_old
		& TME_SUN_OBIE_CSR_READONLY));
  TME_SUN_OBIE_CSR_PUT(sun_obie, csr_new);

  /* get the sets of CSR bits that have changed: */
  csr_diff = (csr_old ^ csr_new);

  /* if this is a NORESET, NOLOOP or CA change, possibly call out the
     appropriate signal change to the i825x6: */
  if (csr_diff & (TME_SUN_OBIE_CSR_NORESET
		  | TME_SUN_OBIE_CSR_NOLOOP
		  | TME_SUN_OBIE_CSR_CA)) {
    new_callouts |= TME_SUN_OBIE_CALLOUT_SIGNALS;
  }
  
  /* if this is an interrupt mask change, possibly call out an
     interrupt signal change to the bus: */
  if (csr_diff & TME_SUN_OBIE_CSR_IE) {
    new_callouts |= TME_SUN_OBIE_CALLOUT_INT;
  }
  
#ifndef TME_NO_LOG
  if (csr_new != sun_obie->tme_sun_obie_last_log_csr) {
    sun_obie->tme_sun_obie_last_log_csr = csr_new;
    tme_log(&sun_obie->tme_sun_obie_element->tme_element_log_handle,
	    1000, TME_OK,
	    (&sun_obie->tme_sun_obie_element->tme_element_log_handle,
	     "csr now 0x%04x",
	     csr_new));
  }
#endif /* !TME_NO_LOG */

  /* make any new callouts: */
  _tme_sun_obie_callout(sun_obie, new_callouts);

  /* unlock the mutex: */
  tme_mutex_unlock(&sun_obie->tme_sun_obie_mutex);

  /* no faults: */
  return (TME_OK);
}
Пример #27
0
/* the sun_obie bus signal handler: */
static int
_tme_sun_obie_bus_signal(struct tme_bus_connection *conn_bus, 
			 unsigned int signal)
{
  struct tme_sun_obie *sun_obie;
  tme_uint16_t csr;
  int new_callouts;

  /* return now if this is not a generic bus signal: */
  if (TME_BUS_SIGNAL_INDEX(signal)
      > _tme_sun_obie_bus_signals_generic.tme_bus_signals_count) {
    return (TME_OK);
  }

  /* recover our data structures: */
  sun_obie = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;

  /* assume that we won't need any new callouts: */
  new_callouts = TME_SUN_OBIE_CALLOUT_CHECK;

  /* lock the mutex: */
  tme_mutex_lock(&sun_obie->tme_sun_obie_mutex);

  /* get the current CSR value: */
  csr = TME_SUN_OBIE_CSR_GET(sun_obie);

  /* if this bus signal is from the i825x6: */
  if (conn_bus->tme_bus_connection.tme_connection_other
      == &sun_obie->tme_sun_obie_conn_i825x6->tme_bus_connection) {

    /* this must be the unspecified interrupt signal: */
    assert (TME_BUS_SIGNAL_WHICH(signal) == TME_BUS_SIGNAL_INT_UNSPEC);

    /* update the CSR value: */
    csr
      = ((csr
	  & ~TME_SUN_OBIE_CSR_INTR)
	 | (((signal & TME_BUS_SIGNAL_LEVEL_MASK)
	     == TME_BUS_SIGNAL_LEVEL_ASSERTED)
	    ? TME_SUN_OBIE_CSR_INTR
	    : 0));

    /* possibly call out an interrupt change to obio: */
    new_callouts = TME_SUN_OBIE_CALLOUT_INT;
  }

  /* otherwise, this bus signal must be from obio: */
  else {
    assert (conn_bus->tme_bus_connection.tme_connection_other
	    == &sun_obie->tme_sun_obie_conn_regs->tme_bus_connection);

    /* if this is the negating edge of the reset signal: */
    if (TME_BUS_SIGNAL_WHICH(signal) == TME_BUS_SIGNAL_RESET
	&& (signal & TME_BUS_SIGNAL_LEVEL_MASK) == TME_BUS_SIGNAL_LEVEL_NEGATED) {

      /* update the CSR value: */
      csr &= TME_SUN_OBIE_CSR_NOLOOP;

      /* possibly call out bus signal changes to the i825x6: */
      new_callouts = TME_SUN_OBIE_CALLOUT_SIGNALS;
    }
  }

  /* put the new CSR value: */
  TME_SUN_OBIE_CSR_PUT(sun_obie, csr);

  /* make any new callouts: */
  if (new_callouts != TME_SUN_OBIE_CALLOUT_CHECK) {
    _tme_sun_obie_callout(sun_obie, new_callouts);
  }

  /* unlock the mutex: */
  tme_mutex_unlock(&sun_obie->tme_sun_obie_mutex);

  return (TME_OK);
}
Пример #28
0
/* this is called for a mode change: */
int
_tme_gtk_screen_mode_change(struct tme_fb_connection *conn_fb)
{
  struct tme_gtk_display *display;
  struct tme_gtk_screen *screen;
  struct tme_fb_connection *conn_fb_other;
  struct tme_fb_xlat fb_xlat_q;
  const struct tme_fb_xlat *fb_xlat_a;
  int scale;
  unsigned long fb_area, avail_area, percentage;
  gint width, height;
  gint height_extra;
  const void *map_g_old;
  const void *map_r_old;
  const void *map_b_old;
  const tme_uint32_t *map_pixel_old;
  tme_uint32_t map_pixel_count_old;  
  tme_uint32_t colorset;
  GdkImage *gdkimage;
  GdkVisual *visual;
  tme_uint32_t color_count, color_i;
  tme_uint32_t color_count_distinct;
  tme_uint32_t color_j;
  struct tme_fb_color *colors_tme;
  GdkColor *colors_gdk;
  gboolean *success;
  gboolean warned_color_alloc;

  /* recover our data structures: */
  display = conn_fb->tme_fb_connection.tme_connection_element->tme_element_private;
  conn_fb_other = (struct tme_fb_connection *) conn_fb->tme_fb_connection.tme_connection_other;

  /* lock our mutex: */
  tme_mutex_lock(&display->tme_gtk_display_mutex);

  /* find the screen that this framebuffer connection references: */
  for (screen = display->tme_gtk_display_screens;
       (screen != NULL
	&& screen->tme_gtk_screen_fb != conn_fb);
       screen = screen->tme_gtk_screen_next);
  assert (screen != NULL);

  /* if the user hasn't specified a scaling, pick one: */
  scale = screen->tme_gtk_screen_fb_scale;
  if (scale < 0) {

    /* calulate the areas, in square pixels, of the emulated
       framebuffer and the host's screen: */
    fb_area = (conn_fb_other->tme_fb_connection_width
	       * conn_fb_other->tme_fb_connection_height);
    avail_area = (gdk_screen_width()
		  * gdk_screen_height());

    /* see what percentage of the host's screen would be taken up by
       an unscaled emulated framebuffer: */
    percentage = (fb_area * 100) / avail_area;

    /* if this is at least 70%, halve the emulated framebuffer, else
       if this is 30% or less, double the emulated framebuffer: */
    if (percentage >= 70) {
      scale = TME_FB_XLAT_SCALE_HALF;
    }
    else if (percentage <= 30) {
      scale = TME_FB_XLAT_SCALE_DOUBLE;
    }
    else {
      scale = TME_FB_XLAT_SCALE_NONE;
    }

    screen->tme_gtk_screen_fb_scale = -scale;
  }

  /* get the system's default visual: */
  visual = gdk_visual_get_system();

  /* get the required dimensions for the GdkImage: */
  width = ((conn_fb_other->tme_fb_connection_width
	    * scale)
	   / TME_FB_XLAT_SCALE_NONE);
  height = ((conn_fb_other->tme_fb_connection_height
	     * scale)
	    / TME_FB_XLAT_SCALE_NONE);
  /* NB: we need to allocate an extra scanline's worth (or, if we're
     doubling, an extra two scanlines' worth) of image, because the
     framebuffer translation functions can sometimes overtranslate
     (see the explanation of TME_FB_XLAT_RUN in fb-xlat-auto.sh): */
  height_extra
    = (scale == TME_FB_XLAT_SCALE_DOUBLE
       ? 2
       : 1);

  /* if the previous gdkimage isn't the right size: */
  gdkimage = screen->tme_gtk_screen_gdkimage;
  if (gdkimage->width != width
      || gdkimage->height != (height + height_extra)) {

    /* allocate a new gdkimage: */
    gdkimage = gdk_image_new(GDK_IMAGE_FASTEST,
			     visual,
			     width,
			     height
			     + height_extra);

    /* set the new image on the image widget: */
    gtk_image_set(GTK_IMAGE(screen->tme_gtk_screen_gtkimage),
		  gdkimage,
		  NULL);

    /* destroy the previous gdkimage and remember the new one: */
    gdk_image_destroy(screen->tme_gtk_screen_gdkimage);
    screen->tme_gtk_screen_gdkimage = gdkimage;
  }

  /* remember all previously allocated maps and colors, but otherwise
     remove them from our framebuffer structure: */
  map_g_old = conn_fb->tme_fb_connection_map_g;
  map_r_old = conn_fb->tme_fb_connection_map_r;
  map_b_old = conn_fb->tme_fb_connection_map_b;
  map_pixel_old = conn_fb->tme_fb_connection_map_pixel;
  map_pixel_count_old = conn_fb->tme_fb_connection_map_pixel_count;
  conn_fb->tme_fb_connection_map_g = NULL;
  conn_fb->tme_fb_connection_map_r = NULL;
  conn_fb->tme_fb_connection_map_b = NULL;
  conn_fb->tme_fb_connection_map_pixel = NULL;
  conn_fb->tme_fb_connection_map_pixel_count = 0;

  /* update our framebuffer connection: */
  conn_fb->tme_fb_connection_width = width;
  conn_fb->tme_fb_connection_height = height;
  conn_fb->tme_fb_connection_depth = gdkimage->depth;
  conn_fb->tme_fb_connection_bits_per_pixel = _tme_gtk_gdkimage_bipp(gdkimage);
  conn_fb->tme_fb_connection_skipx = 0;
  conn_fb->tme_fb_connection_scanline_pad = _tme_gtk_gdkimage_scanline_pad(gdkimage);
  conn_fb->tme_fb_connection_order = (gdkimage->byte_order == GDK_LSB_FIRST
				      ? TME_ENDIAN_LITTLE
				      : TME_ENDIAN_BIG);
  conn_fb->tme_fb_connection_buffer = gdkimage->mem;
  switch (visual->type) {
  case GDK_VISUAL_STATIC_GRAY: 
  case GDK_VISUAL_GRAYSCALE:
    conn_fb->tme_fb_connection_class = TME_FB_XLAT_CLASS_MONOCHROME;
    break;
  default:
    assert(FALSE);
    /* FALLTHROUGH */
  case GDK_VISUAL_STATIC_COLOR:
  case GDK_VISUAL_PSEUDO_COLOR:
  case GDK_VISUAL_DIRECT_COLOR:
  case GDK_VISUAL_TRUE_COLOR:
    conn_fb->tme_fb_connection_class = TME_FB_XLAT_CLASS_COLOR;
    break;
  }
  switch (visual->type) {
  case GDK_VISUAL_DIRECT_COLOR:
    /* we set the primary maps to anything non-NULL, to indicate that
       primaries are index mapped: */
    conn_fb->tme_fb_connection_map_g = conn_fb;
    conn_fb->tme_fb_connection_map_r = conn_fb;
    conn_fb->tme_fb_connection_map_b = conn_fb;
    /* FALLTHROUGH */
  case GDK_VISUAL_TRUE_COLOR:
    conn_fb->tme_fb_connection_mask_g = visual->green_mask;
    conn_fb->tme_fb_connection_mask_r = visual->red_mask;
    conn_fb->tme_fb_connection_mask_b = visual->blue_mask;
    break;
  default:
    conn_fb->tme_fb_connection_mask_g = 0;
    conn_fb->tme_fb_connection_mask_r = 0;
    conn_fb->tme_fb_connection_mask_b = 0;
    break;
  }

  /* get the needed colors: */
  colorset = tme_fb_xlat_colors_get(conn_fb_other, scale, conn_fb, &colors_tme);
  color_count = conn_fb->tme_fb_connection_map_pixel_count;

  /* if we need to allocate colors, but the colorset is not tied to
     the source framebuffer characteristics, and is identical to the
     currently allocated colorset, we can reuse the previously
     allocated maps and colors: */
  if (color_count > 0
      && colorset != TME_FB_COLORSET_NONE
      && colorset == screen->tme_gtk_screen_colorset) {

    /* free the requested color array: */
    tme_free(colors_tme);

    /* restore the previously allocated maps and colors: */
    conn_fb->tme_fb_connection_map_g = map_g_old;
    conn_fb->tme_fb_connection_map_r = map_r_old;
    conn_fb->tme_fb_connection_map_b = map_b_old;
    conn_fb->tme_fb_connection_map_pixel = map_pixel_old;
    conn_fb->tme_fb_connection_map_pixel_count = map_pixel_count_old;
  }

  /* otherwise, we may need to free and/or allocate colors: */
  else {

    /* save the colorset signature: */
    screen->tme_gtk_screen_colorset = colorset;

    /* free any previously allocated maps and colors: */
    if (map_g_old != NULL) {
      tme_free((void *) map_g_old);
    }
    if (map_r_old != NULL) {
      tme_free((void *) map_r_old);
    }
    if (map_b_old != NULL) {
      tme_free((void *) map_b_old);
    }
    if (map_pixel_old != NULL) {

      /* recreate the array of GdkColor: */
      colors_gdk = tme_new(GdkColor, map_pixel_count_old);
      color_i = 0;
      do {
	colors_gdk[color_i].pixel = map_pixel_old[color_i];
      } while (++color_i < map_pixel_count_old);

      /* free the colors: */
      gdk_colormap_free_colors(gdk_colormap_get_system(),
			       colors_gdk,
			       map_pixel_count_old);
      tme_free(colors_gdk);
      tme_free((void *) map_pixel_old);
    }

    /* if we need to allocate colors: */
    if (color_count > 0) {

      /* make the GdkColor array, and count the number of distinct colors: */
      colors_gdk = tme_new(GdkColor, color_count * 2);
      color_count_distinct = 0;
      for (color_i = 0; color_i < color_count; color_i++) {
	color_j = colors_tme[color_i].tme_fb_color_pixel;
	colors_gdk[color_j].green = colors_tme[color_i].tme_fb_color_value_g;
	colors_gdk[color_j].red   = colors_tme[color_i].tme_fb_color_value_r;
	colors_gdk[color_j].blue  = colors_tme[color_i].tme_fb_color_value_b;
	if (color_j >= color_count_distinct) {
	  color_count_distinct = color_j + 1;
	}
      }
      success = tme_new(gboolean, color_count_distinct);

      /* allocate exact matches for as many colors as possible: */
      gdk_colormap_alloc_colors(gdk_colormap_get_system(),
				colors_gdk,
				color_count_distinct,
				FALSE,
				FALSE,
				success);

      /* allocate read-only best matches for any colors we failed to
	 allocate exactly: */
      warned_color_alloc = FALSE;
      for (color_i = 0; color_i < color_count; color_i++) {
	color_j = colors_tme[color_i].tme_fb_color_pixel;
	if (!success[color_j]) {
	  if (!gdk_colormap_alloc_color(gdk_colormap_get_system(),
					&colors_gdk[color_j],
					FALSE,
					TRUE)) {
	    if (!warned_color_alloc) {
	      warned_color_alloc = TRUE;
	      tme_log(&display->tme_gtk_display_element->tme_element_log_handle, 0, ENOMEM,
		      (&display->tme_gtk_display_element->tme_element_log_handle,
		       _("could not allocate all colors")));
	    }
	  }
	}
	colors_tme[color_i].tme_fb_color_pixel = colors_gdk[color_j].pixel;
      }

      /* free the arrays used with gdk_colormap_alloc_colors(): */
      tme_free(success);
      tme_free(colors_gdk);

      /* set the needed colors: */
      tme_fb_xlat_colors_set(conn_fb_other, scale, conn_fb, colors_tme);
    }
  }

  /* compose the framebuffer translation question: */
  fb_xlat_q.tme_fb_xlat_width			= conn_fb_other->tme_fb_connection_width;
  fb_xlat_q.tme_fb_xlat_height			= conn_fb_other->tme_fb_connection_height;
  fb_xlat_q.tme_fb_xlat_scale			= (unsigned int) scale;
  fb_xlat_q.tme_fb_xlat_src_depth		= conn_fb_other->tme_fb_connection_depth;
  fb_xlat_q.tme_fb_xlat_src_bits_per_pixel	= conn_fb_other->tme_fb_connection_bits_per_pixel;
  fb_xlat_q.tme_fb_xlat_src_skipx		= conn_fb_other->tme_fb_connection_skipx;
  fb_xlat_q.tme_fb_xlat_src_scanline_pad	= conn_fb_other->tme_fb_connection_scanline_pad;
  fb_xlat_q.tme_fb_xlat_src_order		= conn_fb_other->tme_fb_connection_order;
  fb_xlat_q.tme_fb_xlat_src_class		= conn_fb_other->tme_fb_connection_class;
  fb_xlat_q.tme_fb_xlat_src_map			= (conn_fb_other->tme_fb_connection_map_g != NULL
						   ? TME_FB_XLAT_MAP_INDEX
						   : TME_FB_XLAT_MAP_LINEAR);
  fb_xlat_q.tme_fb_xlat_src_map_bits		= conn_fb_other->tme_fb_connection_map_bits;
  fb_xlat_q.tme_fb_xlat_src_mask_g		= conn_fb_other->tme_fb_connection_mask_g;
  fb_xlat_q.tme_fb_xlat_src_mask_r		= conn_fb_other->tme_fb_connection_mask_r;
  fb_xlat_q.tme_fb_xlat_src_mask_b		= conn_fb_other->tme_fb_connection_mask_b;
  fb_xlat_q.tme_fb_xlat_dst_depth		= conn_fb->tme_fb_connection_depth;
  fb_xlat_q.tme_fb_xlat_dst_bits_per_pixel	= conn_fb->tme_fb_connection_bits_per_pixel;
  fb_xlat_q.tme_fb_xlat_dst_skipx		= conn_fb->tme_fb_connection_skipx;
  fb_xlat_q.tme_fb_xlat_dst_scanline_pad	= conn_fb->tme_fb_connection_scanline_pad;
  fb_xlat_q.tme_fb_xlat_dst_order		= conn_fb->tme_fb_connection_order;
  fb_xlat_q.tme_fb_xlat_dst_map			= (conn_fb->tme_fb_connection_map_g != NULL
						   ? TME_FB_XLAT_MAP_INDEX
						   : TME_FB_XLAT_MAP_LINEAR);
  fb_xlat_q.tme_fb_xlat_dst_mask_g		= conn_fb->tme_fb_connection_mask_g;
  fb_xlat_q.tme_fb_xlat_dst_mask_r		= conn_fb->tme_fb_connection_mask_r;
  fb_xlat_q.tme_fb_xlat_dst_mask_b		= conn_fb->tme_fb_connection_mask_b;

  /* ask the framebuffer translation question: */
  fb_xlat_a = tme_fb_xlat_best(&fb_xlat_q);

  /* if this translation isn't optimal, log a note: */
  if (!tme_fb_xlat_is_optimal(fb_xlat_a)) {
    tme_log(&display->tme_gtk_display_element->tme_element_log_handle, 0, TME_OK,
	    (&display->tme_gtk_display_element->tme_element_log_handle,
	     _("no optimal framebuffer translation function available")));
  }

  /* save the translation function: */
  screen->tme_gtk_screen_fb_xlat = fb_xlat_a->tme_fb_xlat_func;

  /* force the next translation to do a complete redraw: */
  screen->tme_gtk_screen_full_redraw = TRUE;

  /* unlock our mutex: */
  tme_mutex_unlock(&display->tme_gtk_display_mutex);

  /* done: */
  return (TME_OK);
}