/* 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 */ }
/* 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); }
/* 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); }
/* 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 */ }
/* 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 */ }
/* 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)); }
/* 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; }
/* 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); }
/* 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); }
/* 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); }
/* 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); }
/* 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); }
/* 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); } }
/* 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; }
/* 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); }
/* 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 */ }
/* 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; }
/* 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); }
/* 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 */ }
/* 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; }
/* 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; }
/* 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 */ }
/* 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 */ }
/* 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); }
/* 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); }
/* 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); }
/* 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); }
/* 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); }