Update TTY device + Fix signals error + Change process TTY management

This commit is contained in:
Yann MAGNIN 2020-05-01 11:23:56 +02:00
parent 7140bb1631
commit 126a619942
69 changed files with 1607 additions and 967 deletions

View File

@ -4,82 +4,130 @@
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#include <kernel/drivers/screen.h>
#include <kernel/drivers/keyboard.h>
#include <display.h>
// Define default buffer size.
// TODO: remove me ?
//#define TTY_BUFFER_LINES (DISPLAY_VCHAR_MAX * 3)
//#define TTY_BUFFER_COLUMNS (DISPLAY_HCHAR_MAX)
#include <pthread.h>
// Define TTY major
#define TTY_DEV_MAJOR (4)
struct tty_s
// Internal TTY informations
#define TTY_INPUT_BUFFSIZE (256)
#define TTY_OUTPUT_BUFFSIZE (1024)
struct tty
{
// Internal buffers
// TODO: move me ?
struct {
char input[256];
char **output;
char input[TTY_INPUT_BUFFSIZE];
char output[TTY_OUTPUT_BUFFSIZE];
} buffers;
// Window size informations used by the write primitive
// Screen abstraction part
struct {
unsigned short ws_col;
unsigned short ws_row;
unsigned short ws_xpixel;
unsigned short ws_ypixel;
} winsize;
// Cursor informations
struct {
int16_t x;
int16_t y;
// Window size informations used by the write primitive
struct {
int16_t x;
int16_t y;
} max;
} cursor;
unsigned short ws_col;
unsigned short ws_row;
unsigned short ws_xpixel;
unsigned short ws_ypixel;
} winsize;
// Object used by the drawing library.
// It's store video ram and font informations
display_t disp;
};
// internal strct used by the TTY read primitives
// TODO: Move me ?
// TODO: Add internal keyboard buffer !!!
struct keyboard_obj_s
{
struct {
uint8_t *addr;
size_t size;
size_t clen;
off_t cursor;
} buffer;
struct {
uint8_t enter : 1;
uint8_t maj : 1;
uint8_t special : 1;
uint8_t ctrl : 1;
uint8_t const : 4;
} mode;
uint8_t cvisible;
struct {
// Cursor informations
struct {
// Drawing cursors
struct {
int16_t x;
int16_t y;
} cursor;
} tty;
struct {
uint8_t keycode;
off_t cursor;
} signal;
} saved;
} disp;
// FIXME Dirty place, remove / move me !
struct tty_s *tty;
// Internal output buffer cursor
int write;
int flush;
} cursor;
// Private data
struct {
// Object used by the drawing library.
// It's store video ram and font informations
display_t disp;
// The timer is used to flush the internal
// output buffer
struct {
// Timer ID used to flush the output
// buffer on the screen
int id;
// Used to indicate that the output flush timer
// is currently used
int status;
} timer;
// used to indicate if we want to not use the cache
int nocache;
// screen abstraction mutex
pthread_mutex_t mutex;
} private;
} screen;
// Internal keyboard informations
struct {
// Internal keyboard mode for cannonical (cooked)
// keyboard configurations
struct {
uint8_t enter : 1;
uint8_t maj : 1;
uint8_t special : 1;
uint8_t ctrl : 1;
uint8_t const : 4;
} mode;
// Internal saved values, used for the echoing
// mecanism
struct {
struct {
struct {
int16_t x;
int16_t y;
} cursor;
} tty;
struct {
uint8_t keycode;
off_t cursor;
} signal;
} saved;
// Private data
// TODO: keyboard configuration ? (raw / cannonical)
struct {
// Internal cursor informations for the input
// buffer
off_t cursor;
off_t cursor_max;
// The timer is used to blink the currsor position
struct {
// Timer ID
int id;
// Used to count the number of "timer_start()"
// and known if we can stop the timer.
int used;
} timer;
// Internal mutex to avoid atomic operation
pthread_mutex_t mutex;
} private;
} keyboard;
// Internal device data
struct {
int open_cnt;
} private;
};
// primitives.
@ -88,7 +136,26 @@ extern ssize_t tty_write(void *inode, const void *buffer, size_t count);
extern ssize_t tty_read(void *inode, void *buffer, size_t count);
extern int tty_close(void *inode);
// IOCTL.
// Internal utilities (keyboard abstraction)
extern int tty_keyboard_constructor(struct tty *tty);
extern int tty_keyboard_buffer_insert(struct tty *tty, char n);
extern int tty_keyboard_buffer_update(struct tty *tty, key_t key);
extern int tty_keyboard_check_special(struct tty *tty, key_t key);
extern void tty_keyboard_check_signal(struct tty *tty);
extern void tty_keyboard_buffer_remove(struct tty *tty, off_t cursor);
extern void tty_keyboard_buffer_flush(struct tty *tty);
extern void tty_keyboard_buffer_echoing(struct tty *tty);
extern void tty_keyboard_destructor(struct tty *tty);
// Internal utilities (screen abstraction)
extern int tty_screen_constructor(struct tty *tty);
extern ssize_t tty_screen_buffer_update(struct tty *tty, const uint8_t *buffer, size_t count);
extern void tty_screen_buffer_flush(struct tty *tty);
extern void tty_screen_display_callback(struct tty *tty);
extern int tty_screen_discipline_char(struct tty *tty, char n, int action);
extern void tty_screen_destructor(struct tty *tty);
// IOCTL (remove me ?)
#define TTY_IOCTL_GETDX (0x00)
#define TTY_IOCTL_GETDY (0x01)
extern void tty_ioctl(void *inode, uint32_t cmd, ...);

View File

@ -0,0 +1,28 @@
#ifndef __KERNEL_DRIVERS_CPG_H__
# define __KERNEL_DRIVERS_CPG_H__
#include <stddef.h>
#include <stdint.h>
struct cpg
{
uint32_t fll_freq;
uint32_t pll_freq;
uint32_t cpu_freq;
uint32_t bus_freq;
uint32_t per_freq;
};
enum cpg_module
{
CPG_FLL,
CPG_PLL,
CPG_CPU,
CPG_BUS,
CPG_PERIPHERAL
};
// Getter
extern uint32_t cpg_get_frequency(enum cpg_module module);
#endif /*__KERNEL_DRIVERS_CPG_H__*/

View File

@ -16,6 +16,17 @@ struct keycache_s
struct keycache_s *next;
};
// Structure used by the keybaord abstraction
// FIXME: this macros is hardware specific !!
#define KEYBOARD_NB_KEYS (96)
struct keyscan_s
{
uint8_t keycode;
uint32_t counter;
};
typedef struct keyscan_s keyscan_t;
typedef enum key_e
{
KEY_F1 = 0x41,
@ -85,6 +96,6 @@ extern ssize_t keyboard_read(void *buffer, size_t count);
extern int keyboard_close(void);
// Helpers
extern void keyboard_wait_event(void);
extern void keyboard_wait_event(keyscan_t *list);
#endif /*__KERNEL_DEVICES_KEYBOARD_H__*/

View File

@ -13,6 +13,6 @@ typedef enum {
// Internal hardware abstract
extern size_t screen_get(screen_getter_t getter);
extern void (*screen_update)(void *vram);
extern void screen_update(void *vram);
#endif /*__KERNEL_DRIVERS_SCREEN_H__*/

View File

@ -23,9 +23,11 @@ typedef enum {
} tmode_t;
// Prototypes
extern int timer_uninstall(int timer_ID);
extern int timer_install(void *callback, void *arg, uint32_t ticks, tmode_t mode);
extern int timer_start(int timer_ID);
extern int timer_stop(int timer_ID);
extern int timer_uninstall(int timerID);
extern int timer_install(void *callback, void *arg, int hertz, tmode_t mode);
extern int timer_set_callback(int timerID, void *callback, void *arg);
extern int timer_set_ticks(int timerID, uint32_t ticks);
extern int timer_start(int timerID);
extern int timer_stop(int timerID);
#endif /*__KERNEL_UTIL_TIMER_H__*/

View File

@ -76,8 +76,10 @@ struct dentry
// File name.
char name[VFS_DENTRY_NAME_LENGHT];
// Internal inode
// Internal inode OR device address / informations
void *inode;
struct device *device;
dev_t dev_id;
// Internal counter used by opne() and close()
uint32_t counter;

View File

@ -7,6 +7,7 @@
#include <kernel/fs/file.h>
#include <kernel/fs/filesystem.h>
#include <kernel/devices/device.h>
#include <fcntl.h>
// Internal VFS macros
#define VFS_MOUNT_ROOT (-1)

View File

@ -5,7 +5,7 @@
#include <stdint.h>
#include <kernel/fs/file.h>
#include <kernel/process.h>
#include <kernel/util/elf.h>
#include <elf.h>
// Function
extern int loader(struct process *process, const char *path);

View File

@ -19,7 +19,6 @@
struct sched_task;
// define process struct.
//TODO: signal !
struct process
{
//---
@ -48,7 +47,6 @@ struct process
FILE file;
} opfile[PROCESS_NB_OPEN_FILE];
struct dentry *working_dir;
FILE tty;
//---

View File

@ -55,10 +55,11 @@ struct font_block_s
// Draw primitives
extern int dopen(display_t *disp, const char *fontname);
extern void dclear(display_t *disp);
extern void dascii(display_t *disp, int row, int colomn, char const c);
extern void dascii(display_t *disp, int row, int colomn, char const c, int mode);
extern size_t dprint(display_t *disp, int x, int y, char const *str, ...);
extern void dscroll(display_t *disp, int line);
extern void dreverse(display_t *disp, int x, int y, int width, int height);
extern void drect(display_t *disp, int x, int y, int width, int height);
extern void dupdate(display_t *disp);
#endif /*__LIB_DISPLAY_H__*/

30
include/lib/pthread.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef __LIB_PTHREAD_H__
# define __LIB_PTHREAD_H__
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
// Define internal Posix thread mutex
// FIXME: this is a custom implemetation
struct __pthread_mutex_s
{
pid_t owner;
int lock;
};
typedef struct __pthread_mutex_s pthread_mutex_t;
// Define internal Posix thread mutex attributes
struct __pthread_mutexattr_s
{
int attr;
};
/* Mutex part */
extern int pthread_mutex_init(struct __pthread_mutex_s *mutex, const struct __pthread_mutexattr_s *attr);
extern int pthread_mutex_lock(struct __pthread_mutex_s *mutex);
extern int pthread_mutex_unlock(struct __pthread_mutex_s *mutex);
extern int pthread_mutex_destroy(struct __pthread_mutex_s *mutex);
#endif /*__LIB_PTHREAD_H__*/

View File

@ -230,6 +230,6 @@ int start(void)
sched_start();
// normally the kernel SHOULD / CAN not arrive here.
earlyterm_write("Kernel job fini !");
earlyterm_write("Kernel job fini !\n");
while (1) { __asm__ volatile ("sleep"); }
}

View File

@ -49,7 +49,7 @@ static void print_base(struct earlyterm *earlyterm, uint32_t nb,
while (--digits >= 0)
{
dascii(&earlyterm->display, earlyterm->cursor.x,
earlyterm->cursor.y, buffer[digits]);
earlyterm->cursor.y, buffer[digits], 0);
earlyterm_horizontal_update(earlyterm);
}
}
@ -93,6 +93,13 @@ void earlyterm_write(const char *format, ...)
// String format "simple"
if (format[i] == '%')
{
if (format[i + 1] == 'c') {
nb = (char)va_arg(ap, int);
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, nb, 0);
earlyterm_horizontal_update(&earlyterm);
i = i + 1;
continue;
}
if (format[i + 1] == 'd' || format[i + 1] == 'x')
{
// Check negative value
@ -101,7 +108,7 @@ void earlyterm_write(const char *format, ...)
if (nb < 0 && format[i + 1] == 'd')
{
nb = 0 - nb;
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, '-');
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, '-', 0);
earlyterm_horizontal_update(&earlyterm);
}
print_base(&earlyterm, nb, (format[i + 1] == 'd') ? 10 : 16, 1);
@ -113,14 +120,14 @@ void earlyterm_write(const char *format, ...)
// add @ if 'p' (pointer)
if (format[i + 1] == 'p')
{
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, '@');
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, '@', 0);
earlyterm_horizontal_update(&earlyterm);
}
// Add "0x"
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, '0');
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, '0', 0);
earlyterm_horizontal_update(&earlyterm);
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, 'x');
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, 'x', 0);
earlyterm_horizontal_update(&earlyterm);
// Get value
@ -138,7 +145,7 @@ void earlyterm_write(const char *format, ...)
{
if (line_discipline(&earlyterm, *(char*)nb) != 0)
continue;
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, *(char*)nb);
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, *(char*)nb, 0);
earlyterm_horizontal_update(&earlyterm);
}
i = i + 1;
@ -147,7 +154,7 @@ void earlyterm_write(const char *format, ...)
}
// Default, display character
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, format[i]);
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, format[i], 0);
earlyterm_horizontal_update(&earlyterm);
}

View File

@ -1,22 +1,27 @@
#include <kernel/devices/tty.h>
#include <kernel/drivers/timer.h>
#include <kernel/util/atomic.h>
#include <kernel/util/kmem.h>
int tty_close(void *inode)
{
struct tty_s *tty;
int line;
struct tty *tty;
// Get tty object
tty = inode;
// Free'd all allocated memory for the
// output buffer
line = tty->cursor.max.y;
while (line >= 0)
kmem_free(tty->buffers.output[line]);
kmem_free(tty->buffers.output);
// Force flush internal buffers
tty_keyboard_buffer_flush(tty);
tty_screen_buffer_flush(tty);
// Free'd tty object
kmem_free(tty);
// Start atomic operations
atomic_start();
// Call each module destructors
tty_keyboard_destructor(tty);
tty_screen_destructor(tty);
// Stop atomic operations
atomic_stop();
return (0);
}

View File

@ -1,70 +1,43 @@
#include <kernel/devices/tty.h>
#include <kernel/devices/earlyterm.h>
#include <kernel/drivers/screen.h>
#include <kernel/util/atomic.h>
#include <kernel/util/kmem.h>
#include <lib/display.h>
#include <lib/string.h>
#include <string.h>
// TTY device
struct tty tty;
static void tty_default_init(struct tty *tty)
{
// Wipe all object data
memset(tty, 0x00, sizeof(struct tty));
// Force default value
// TODO: move to "./utils/<module>" appropriate part ?
tty->keyboard.private.timer.id = -1;
tty->screen.private.timer.id = -1;
}
void *tty_open(dev_t major, dev_t minor)
{
struct tty_s *tty;
int line;
// TODO: handle major / minor !!
(void)major;
(void)minor;
// Try to allocate tty object
tty = (struct tty_s*)kmem_alloc(sizeof(struct tty_s));
if (tty == NULL)
return (NULL);
// Start atomic operations
atomic_start();
// Get the font used by the tty.
if (dopen(&tty->disp, "default") != 0)
// Initialize TTY
tty_default_init(&tty);
if (tty_screen_constructor(&tty) != 0
|| tty_keyboard_constructor(&tty) != 0)
{
kmem_free(tty);
tty_close(&tty);
atomic_stop();
return (NULL);
}
// Generate "visible" informations for the write primitive
tty->winsize.ws_xpixel = screen_get(SCREEN_WIDTH);
tty->winsize.ws_ypixel = screen_get(SCREEN_HEIGHT);
tty->winsize.ws_col = tty->winsize.ws_xpixel / (tty->disp.font->font.width + 1);
tty->winsize.ws_row = tty->winsize.ws_ypixel / (tty->disp.font->font.height + 1);
// Generate formated output buffer indicator
tty->cursor.max.x = screen_get(SCREEN_WIDTH) / (tty->disp.font->font.width + 1);
tty->cursor.max.y = screen_get(SCREEN_HEIGHT) / (tty->disp.font->font.height + 1);
tty->cursor.max.y = tty->cursor.max.y * 4;
// Try to alloc new tty output buffer
tty->buffers.output = (char **)kmem_alloc(sizeof(char *) * tty->cursor.max.y);
if (tty->buffers.output == NULL)
{
kmem_free(tty);
return (NULL);
}
// Try to alloc each line of the output buffer
line = tty->cursor.max.y;
while (--line >= 0)
{
// Try to alloc the line
tty->buffers.output[line] = (char*)kmem_alloc(tty->cursor.max.x);
if (tty->buffers.output[line] != NULL) {
memset(tty->buffers.output[line], '\0', tty->cursor.max.x);
continue;
}
// Release all allocated space and return NULL
while (++line < tty->cursor.max.y)
kmem_free(tty->buffers.output[line]);
kmem_free(tty->buffers.output);
kmem_free(tty);
return (NULL);
}
// Initialize default TTY cursor position.
tty->cursor.x = 0;
tty->cursor.y = 0;
return (tty);
// Stop atomic operations and return the device
atomic_stop();
return (&tty);
}

View File

@ -3,408 +3,129 @@
#include <kernel/drivers/keyboard.h>
#include <kernel/drivers/timer.h>
#include <kernel/util/atomic.h>
#include <kernel/util/casio.h>
#include <kernel/context.h>
#include <kernel/syscall.h>
#include <kernel/signal.h>
#include <lib/string.h>
#include <sys/signal.h>
#include <pthread.h>
#include <string.h>
// Intenral functions
static void check_signal(struct keyboard_obj_s *keyboard);
static int check_special(struct keyboard_obj_s *keyboard, key_t key);
static int update_buffer(struct keyboard_obj_s *keyboard, key_t key);
static int buffer_insert(struct keyboard_obj_s *keyboard, char n);
static void tty_buffer_display(struct keyboard_obj_s *keyboard);
static void cursor_callback(struct keyboard_obj_s *keyboard);
//FIXME: this function is device-specifique !!
//FIXME: shared device error !!!
ssize_t tty_read(void *inode, void *buffer, size_t count)
static void tty_init_internal(struct tty *tty)
{
extern struct keycache_s *keylist;
struct keyboard_obj_s keyboard;
struct keycache_s *keynode;
int first_key;
//int timer_fd;
// Wait TTY keyboard availability
pthread_mutex_lock(&tty->keyboard.private.mutex);
// Check potential error.
if (count < 2)
return (0);
// Initialize internal struc.
memset(buffer, '\0', count);
keyboard.buffer.addr = buffer;
keyboard.buffer.size = count;
keyboard.buffer.cursor = 0;
keyboard.buffer.clen = 0;
keyboard.mode.enter = 0;
keyboard.mode.maj = 0;
keyboard.mode.special = 0;
keyboard.cvisible = 0;
keyboard.tty = inode;
// Wait TTY screen availability
pthread_mutex_lock(&tty->screen.private.mutex);
// save TTY informations.
keyboard.saved.tty.cursor.x = keyboard.tty->cursor.x;
keyboard.saved.tty.cursor.y = keyboard.tty->cursor.y;
tty->keyboard.saved.tty.cursor.x = tty->screen.cursor.disp.x;
tty->keyboard.saved.tty.cursor.y = tty->screen.cursor.disp.y;
// Initialize timer for cursor.
// FIXME: find real ticks value !!
//timer_fd = timer_install(&cursor_callback, &keyboard, 500 * 500 * 2, TIMER_START);
//if (timer_fd == -1)
// return (0);
// Unlock the TTY screen
pthread_mutex_unlock(&tty->screen.private.mutex);
// Start timer (if needed) for cursor blink.
if (tty->keyboard.private.timer.used == 0)
timer_start(tty->keyboard.private.timer.id);
tty->keyboard.private.timer.used += 1;
// Unlock device
pthread_mutex_unlock(&tty->keyboard.private.mutex);
}
//FIXME: user mutex and remove atomic_* !!
//FIXME: with mutex use DMA transfert insted of memset() !
static ssize_t tty_uninit_internal(struct tty *tty, void *buffer, size_t count)
{
// Wait device availability
pthread_mutex_lock(&tty->keyboard.private.mutex);
// Get the real size to dump
if (count > tty->keyboard.private.cursor_max)
count = tty->keyboard.private.cursor_max;
// Dump internal buffer
memcpy(buffer, tty->buffers.input, count);
// Update the input buffer if needed
if (count < tty->keyboard.private.cursor_max) {
memcpy(tty->buffers.input, &tty->buffers.input[count],
tty->keyboard.private.cursor_max - count);
}
// Update internal cursor
tty->keyboard.private.cursor_max = 0;
tty->keyboard.private.cursor = 0;
// Stop the cursor timer if needed.
tty->keyboard.private.timer.used -= 1;
if (tty->keyboard.private.timer.used == 0)
timer_stop(tty->keyboard.private.timer.id);
// Unlock device
pthread_mutex_unlock(&tty->keyboard.private.mutex);
// Return the number of input char.
return (count);
}
//FIXME: user mutex and remove atomic_* !!
ssize_t tty_read(void *inode, void *buffer, size_t count)
{
keyscan_t keylist[KEYBOARD_NB_KEYS];
struct tty *tty;
// Check potential error.
if (count == 0)
return (0);
// Get tty devie
tty = inode;
// Intialize internal struct
tty_init_internal(tty);
// Main Loop, wait [EXE] key.
while (keyboard.mode.enter == 0)
{
// Wait user interruption.
keyboard_wait_event();
// TODO: use thread !!!
do {
// Wait user interactions
keyboard_wait_event(keylist);
// Start atomic operations and check
// signal, special key then update
// the buffer.
atomic_start();
keynode = keylist;
first_key = 0;
keyboard.mode.ctrl = 0;
keyboard.saved.signal.keycode = KEY_UNUSED;
while (keynode != NULL &&
(keynode->counter == 1 || keynode->keycode == KEY_OPTN ||
(first_key == 0 && keynode->counter > 10 && (keynode->counter & 1) == 0)))
// Wait device availability
pthread_mutex_lock(&tty->keyboard.private.mutex);
// Check the keys list
tty->keyboard.mode.ctrl = 0;
tty->keyboard.mode.enter = 0;
tty->keyboard.saved.signal.keycode = KEY_UNUSED;
for (int i = 0 ; keylist[i].keycode != KEY_UNUSED && i < KEYBOARD_NB_KEYS ; ++i)
{
// Check key validity
if (!(keylist[i].keycode == KEY_OPTN || keylist[i].counter == 1
|| (i == 0 && keylist[i].counter > 10 && (keylist[i].counter & 1) == 0)))
continue;
// Handle current key
if (check_special(&keyboard, keynode->keycode) == 0)
update_buffer(&keyboard, keynode->keycode);
if (tty_keyboard_check_special(tty, keylist[i].keycode) == 0)
tty_keyboard_buffer_update(tty, keylist[i].keycode);
// Dump the the fist pressed key
if (first_key == 0) {
keyboard.saved.signal.keycode = keynode->keycode;
keyboard.saved.signal.cursor = keyboard.buffer.cursor;
// @note: this is a workaround for the signal management
if (i == 0) {
tty->keyboard.saved.signal.keycode = keylist[i].keycode;
tty->keyboard.saved.signal.cursor = tty->keyboard.private.cursor;
}
first_key = 1;
// Get next key.
keynode = keynode->next;
}
// Unlock device
pthread_mutex_unlock(&tty->keyboard.private.mutex);
// Check signal
check_signal(&keyboard);
tty_keyboard_check_signal(tty);
// Stop atomic operations
atomic_stop();
// Display buffer on TTY.
tty_buffer_display(&keyboard);
}
// uninstall cursor timer.
//timer_uninstall(timer_fd);
// Return the number of input char.
return (keyboard.buffer.clen);
}
//TODO: move me
static void check_signal(struct keyboard_obj_s *keyboard)
{
extern struct process *process_current;
struct { uint8_t keycode; int signal; } echapment[3] = {
{.keycode = KEY_LN, .signal = SIGINT},
{.keycode = KEY_DIV, .signal = SIGQUIT},
{.keycode = KEY_0, .signal = SIGTSTP}
};
int signal;
// Check signal sending request
if (keyboard->mode.ctrl == 0)
return;
// Try to find the signal to send
signal = -1;
for (int i = 0 ; i < 3 ; ++i) {
if (echapment[i].keycode != keyboard->saved.signal.keycode)
continue;
signal = echapment[i].signal;
break;
}
if (signal == -1)
return;
// Remove the cheracter
if (keyboard->saved.signal.cursor > 0)
{
// Move seconde part.
memcpy(
&keyboard->buffer.addr[keyboard->buffer.cursor - 1],
&keyboard->buffer.addr[keyboard->buffer.cursor],
keyboard->buffer.clen - keyboard->buffer.cursor
);
// Add null char and update clen.
keyboard->buffer.clen = keyboard->buffer.clen - 1;
keyboard->buffer.addr[keyboard->buffer.clen] = '\0';
keyboard->buffer.cursor = keyboard->buffer.cursor - 1;
}
// Send signal
signal_raise(process_current, signal);
}
// TODO: move me
// TODO: update me
static int check_special(struct keyboard_obj_s *keyboard, key_t key)
{
extern fx9860_context_t casio_context;
extern fx9860_context_t vhex_context;
// Check CTRL key (KEY_OPT)
if (key == KEY_OPTN) {
keyboard->mode.ctrl = 1;
return (1);
}
// Check MAJ.
if (key == KEY_ALPHA) {
keyboard->mode.maj ^= 1;
return (1);
}
// Check Alpha / num mode. (special)
if (key == KEY_SHIFT) {
keyboard->mode.special ^= 0x01;
return (1);
}
// Check space key (workaround)
if (key == KEY_DOT && keyboard->mode.special == 0) {
buffer_insert(keyboard, ' ');
return (1);
}
// Check DEL key.
if (key == KEY_DEL)
{
// Check potential error.
if (keyboard->buffer.cursor <= 0)
return (1);
// Move seconde part.
memcpy(
&keyboard->buffer.addr[keyboard->buffer.cursor - 1],
&keyboard->buffer.addr[keyboard->buffer.cursor],
keyboard->buffer.clen - keyboard->buffer.cursor
);
// Add null char and update clen.
keyboard->buffer.clen = keyboard->buffer.clen - 1;
keyboard->buffer.addr[keyboard->buffer.clen] = '\0';
keyboard->buffer.cursor = keyboard->buffer.cursor - 1;
return (1);
}
// Check MENU key.
// TODO: fix me !
if (key == KEY_MENU)
{
// Save current Vhex context and restore Casio's context.
atomic_start();
fx9860_context_save(&vhex_context);
fx9860_context_restore(&casio_context);
atomic_stop();
// Inject MENU key and call GetKey().
// TODO !!!
//casio_GetKeyWait(&row, &column, 0, 0, 0, &key);
casio_GetKey(&key);
// Save current Casio's context and restore Vhex's context.
atomic_start();
fx9860_context_save(&casio_context);
fx9860_context_restore(&vhex_context);
atomic_stop();
return (1);
}
// Check EXE key.
if (key == KEY_EXE)
{
// Add new line character.
keyboard->buffer.addr[keyboard->buffer.clen] = '\n';
keyboard->buffer.clen = keyboard->buffer.clen + 1;
keyboard->buffer.addr[keyboard->buffer.clen] = '\0';
// indicate that the EXE has been pressed.
keyboard->mode.enter = 1;
return (1);
}
// Check LEFT key.
if (key == KEY_LEFT)
{
// Check potential error.
if (keyboard->buffer.cursor <= 0)
return (1);
// Move cursor.
keyboard->buffer.cursor = keyboard->buffer.cursor - 1;
return (1);
}
// Check RIGHT key.
if (key == KEY_RIGHT)
{
// Check limit
if (keyboard->buffer.cursor >= keyboard->buffer.clen)
return (1);
// Move cursor.
keyboard->buffer.cursor = keyboard->buffer.cursor + 1;
return (1);
}
return (0);
}
static void tty_buffer_display(struct keyboard_obj_s *keyboard)
{
size_t size;
// Restore TTY X/Y axis positions.
keyboard->tty->cursor.x = keyboard->saved.tty.cursor.x;
keyboard->tty->cursor.y = keyboard->saved.tty.cursor.y;
// Workaround for [EXE] key.
size = keyboard->buffer.clen;
if (keyboard->mode.enter == 0)
size = keyboard->buffer.clen + 1;
// Write buffer.
tty_write(keyboard->tty, keyboard->buffer.addr, size);
}
static int update_buffer(struct keyboard_obj_s *keyboard, key_t key)
{
static const uint8_t keylist_alpha[] = {
KEY_XOT, KEY_LOG, KEY_LN, KEY_SIN, KEY_COS, KEY_TAN,
KEY_FRAC, KEY_FD, KEY_LEFTP, KEY_RIGHTP, KEY_COMMA, KEY_ARROW,
KEY_7, KEY_8, KEY_9,
KEY_4, KEY_5, KEY_6, KEY_MUL, KEY_DIV,
KEY_1, KEY_2, KEY_3, KEY_PLUS, KEY_MINUS,
KEY_0, KEY_UNUSED
};
static const uint8_t keylist_num[] = {
KEY_0, KEY_1, KEY_2, KEY_3, KEY_4,
KEY_5, KEY_6, KEY_7, KEY_8, KEY_9,
KEY_PLUS, KEY_MINUS, KEY_MUL, KEY_DIV,
KEY_LEFTP, KEY_RIGHTP, KEY_COMMA, KEY_POWER,
KEY_DOT, KEY_FD, KEY_ARROW, KEY_UNUSED
};
static const char keylist_num_char[] = "0123456789+-x/(),^.|_";
const uint8_t *keycode_list;
char character;
int i;
// Get the appropriate key list.
keycode_list = keylist_alpha;
if (keyboard->mode.special == 1)
keycode_list = keylist_num;
// Try to find the pressed key.
i = -1;
while (keycode_list[++i] != KEY_UNUSED && keycode_list[i] != key);
if (keycode_list[i] != key)
return (0);
// If the key match, update buffer and get the
// character to be written
character = keylist_num_char[i];
if (keyboard->mode.special == 0) {
character = 'a' + i;
if (keyboard->mode.maj == 1)
character = 'A' + i;;
}
// Insert new character if possible.
buffer_insert(keyboard, character);
return (1);
}
static int buffer_insert(struct keyboard_obj_s *keyboard, char n)
{
// Check if the buffer is full.
if (keyboard->buffer.clen + 1 >= keyboard->buffer.size)
return (1);
// Move the seconds par of the buffer is needed
if (keyboard->buffer.cursor < keyboard->buffer.clen)
{
int i = keyboard->buffer.clen + 1;
while (--i >= (int)keyboard->buffer.cursor)
keyboard->buffer.addr[i] = keyboard->buffer.addr[i - 1];
}
// Add the new character.
keyboard->buffer.addr[keyboard->buffer.cursor] = n;
// Update cursor and character len.
keyboard->buffer.cursor = keyboard->buffer.cursor + 1;
keyboard->buffer.clen = keyboard->buffer.clen + 1;
return (0);
}
static void cursor_callback(struct keyboard_obj_s *keyboard)
{
// static int test = 0;
// Draw cursor if needed
if (keyboard->cvisible == 0)
{
// Force atomic operation
atomic_start();
// Geneate TTY buffer cursor position.
int x = keyboard->buffer.cursor + keyboard->saved.tty.cursor.x;
int y = x / keyboard->tty->cursor.max.x;
x = x - (y * keyboard->tty->cursor.max.x);
y = y + keyboard->saved.tty.cursor.y;
// Check circular limit
if (y >= keyboard->tty->cursor.max.y)
y = y - keyboard->tty->cursor.max.y;
// Get window row
int line = -1;
while (++line < keyboard->tty->winsize.ws_row - 1)
{
// Update row cursor.
if (--y < 0)
y = keyboard->tty->cursor.max.y - 1;
// Check if the line existe.
if (keyboard->tty->buffers.output[y][0] == '\0')
break;
}
//if (line != test) {
// earlyterm_write("line = %d - %d\n", line, keyboard->tty->winsize.ws_row);
// test = line;
// DBG_WAIT;
//}
// Get "real" X and Y position (pixel)
x = x * (keyboard->tty->disp.font->font.width + 1);
y = line * (keyboard->tty->disp.font->font.height + 1);
// Display cursor.
dreverse(
&keyboard->tty->disp, x, y,
(keyboard->tty->disp.font->font.width + 1),
(keyboard->tty->disp.font->font.height + 1)
);
(*screen_update)(keyboard->tty->disp.vram);
// Stop atomic operations
atomic_stop();
}
// Update cursor status.
keyboard->cvisible = keyboard->cvisible ^ 1;
// Display intput buffer on TTY.
tty_keyboard_buffer_echoing(tty);
} while (tty->keyboard.mode.enter == 0);
return (tty_uninit_internal(tty, buffer, count));
}

View File

@ -1,186 +1,35 @@
#include <kernel/devices/tty.h>
#include <kernel/devices/earlyterm.h>
#include <kernel/drivers/screen.h>
#include <kernel/util/atomic.h>
#include <lib/string.h>
/* tty_vertical_update() - Check / update TTY vertical cursor */
static void tty_vertical_update(struct tty_s *tty)
{
// Get next line.
tty->cursor.y = tty->cursor.y + 1;
if (tty->cursor.y >= tty->cursor.max.y)
tty->cursor.y = 0;
// Wipe new line.
memset(tty->buffers.output[tty->cursor.y], '\0', tty->cursor.max.x);
}
/* tty_horizontal_update() - Check / update TTY horizotal cursor */
static int tty_horizontal_update(struct tty_s *tty)
{
tty->cursor.x = tty->cursor.x + 1;
if (tty->cursor.x >= tty->cursor.max.x)
{
tty_vertical_update(tty);
tty->cursor.x = 0;
return (1);
}
return (0);
}
/* tty_buffer_update() - Line discipline */
static ssize_t tty_buffer_update(struct tty_s *tty, const uint8_t *buffer, size_t count)
{
int16_t offset;
ssize_t i;
i = -1;
while (++i < (ssize_t)count)
{
// Check bell char.
if (buffer[i] == '\a')
{
// TODO
continue;
}
// Check backspace.
if (buffer[i] == '\b')
{
if (tty->cursor.x > 0)
tty->cursor.x = tty->cursor.x - 1;
tty->buffers.output[tty->cursor.y][tty->cursor.x] = '\0';
continue;
}
// Check horizotal tab.
if (buffer[i] == '\t')
{
// Check if we need a new line or not.
offset = 5 - (tty->cursor.x - ((tty->cursor.x / 5) * 5));
if (tty->cursor.x + offset < tty->cursor.max.x)
{
memset(&tty->buffers.output[tty->cursor.y][tty->cursor.x], ' ', offset);
tty->cursor.x = tty->cursor.x + offset;
continue;
}
// If a new line is required char.
// Generate a new line.
tty->cursor.x = 0;
tty_vertical_update(tty);
continue;
}
// Check new line char.
if (buffer[i] == '\n')
{
tty->buffers.output[tty->cursor.y][tty->cursor.x] = '\n';
tty->cursor.x = 0;
tty_vertical_update(tty);
continue;
}
// Check 'form feed' and 'vertical tab' char.
// @note: for now this character is interpreted like '\v'
if (buffer[i] == '\f' || buffer[i] == '\v')
{
tty_vertical_update(tty);
memset(tty->buffers.output[tty->cursor.y], ' ', tty->cursor.x);
continue;
}
// Check carriage return.
if (buffer[i] == '\r') { tty->cursor.x = 0; continue;}
// Update TTY buffer char.
tty->buffers.output[tty->cursor.y][tty->cursor.x] = buffer[i];
tty_horizontal_update(tty);
}
tty->buffers.output[tty->cursor.y][tty->cursor.x] = '\0';
return (i);
}
// FIXME: this function is device-specific !
// TODO: Update me ?
static void tty_display(struct tty_s *tty)
{
int test_row;
int line_len;
int start;
int line;
int y;
// Start atomic operation.
atomic_start();
// Get the "first" line and number of line.
// @note: circular buffer.
line = -1;
test_row = tty->cursor.y;
while (++line < tty->winsize.ws_row)
{
// Update check line.
start = test_row;
if (--test_row < 0)
test_row = tty->cursor.max.y - 1;
// Check if the line existe.
if (tty->buffers.output[test_row][0] == '\0')
break;
}
//TODO
//TODO Display only the new char !
//TODO Use scroll drawing function to avoid draw time !
//TODO
// clear screen
dclear(&tty->disp);
// Display "on-screen" string lines.
y = -1;
while (++y <= line && y < tty->winsize.ws_row)
{
// Display line
line_len = -1;
while (tty->buffers.output[start][++line_len] != '\0') {
if (tty->buffers.output[start][line_len] != '\n')
dascii(&tty->disp, line_len, y, tty->buffers.output[start][line_len]);
}
// Update row index
if (++start >= tty->cursor.max.y)
start = 0;
}
// Display on screen.
(*screen_update)(tty->disp.vram);
// Stop atomic operation
atomic_stop();
}
/* tty_write() - TTY write primitive ! */
ssize_t tty_write(void *inode, const void *buffer, size_t count)
{
ssize_t written;
struct tty *tty;
// Start atomic operation.
// Get tty device
tty = inode;
// Start atomic operation
atomic_start();
// Update internal buffer and display
// TTY on the screen.
written = tty_buffer_update(inode, buffer, count);
// TODO: Monotonic display ?
tty_display(inode);
// Check STDERR ouput mode (force print)
// FIXME: move me !!!!
if (tty->screen.private.nocache == 1) {
size_t i = -1;
while (++i < count)
tty_screen_discipline_char(tty, ((char*)buffer)[i], 1);
screen_update(tty->screen.private.disp.vram);
tty->screen.private.nocache = 0;
atomic_stop();
return (i);
}
// Stop atomic operation
atomic_stop();
// Return the number of char written into
// TTY's internal buffer.
return (written);
// Update internal output buffer
// @note: it will be displayed monotoinically using
// hardware timer (~16hz)
return (tty_screen_buffer_update(inode, buffer, count));
}

View File

@ -0,0 +1,179 @@
#include <kernel/devices/tty.h>
#include <kernel/devices/earlyterm.h>
#include <kernel/drivers/screen.h>
#include <kernel/util/atomic.h>
#include <lib/pthread.h>
#include <lib/display.h>
#include <lib/string.h>
/* tty_keyboard_buffer_flush() - force flush the internal buffer */
void tty_keyboard_buffer_flush(struct tty *tty)
{
// Start atomic operation
atomic_start();
// Force echo the internal buffer
tty_keyboard_buffer_echoing(tty);
tty->keyboard.private.cursor = 0;
tty->keyboard.private.cursor_max = 0;
// Stop atomic operations
atomic_stop();
}
/*
** tty_buffer_remove() - Remove the character based on current
** cursor position
** @note: this function should be called ONLY if the device
** is locked
*/
// TODO: use DMA ?
void tty_keyboard_buffer_remove(struct tty *tty, off_t cursor)
{
if (cursor <= 0 || cursor > tty->keyboard.private.cursor_max) {
pthread_mutex_unlock(&tty->keyboard.private.mutex);
return;
}
// Remove target char using areas overlaps (if needed)
if (cursor < tty->keyboard.private.cursor_max)
{
memcpy(
&tty->buffers.input[cursor - 1],
&tty->buffers.input[cursor],
tty->keyboard.private.cursor_max - cursor
);
}
// Update keyboard cu
tty->keyboard.private.cursor_max = tty->keyboard.private.cursor_max - 1;
tty->keyboard.private.cursor = tty->keyboard.private.cursor - 1;
}
/*
** tty_buffer_insert() - Insert new character based on current
** cursor position
** @note: this function should be called ONLY if the device
** is locked
*/
int tty_keyboard_buffer_insert(struct tty *tty, char n)
{
// Check if the buffer is full.
if (tty->keyboard.private.cursor_max + 1 >= TTY_INPUT_BUFFSIZE)
return (1);
// Move the seconds par of the buffer is needed
// TODO: use DMA ?
if (tty->keyboard.private.cursor < tty->keyboard.private.cursor_max)
{
int i = tty->keyboard.private.cursor_max + 1;
while (--i >= (int)tty->keyboard.private.cursor)
tty->buffers.input[i] = tty->buffers.input[i - 1];
}
// Add the new character.
tty->buffers.input[tty->keyboard.private.cursor] = n;
// Update cursor and character len.
tty->keyboard.private.cursor = tty->keyboard.private.cursor + 1;
tty->keyboard.private.cursor_max = tty->keyboard.private.cursor_max + 1;
return (0);
}
/* tty_keyboard_buffer_echoing() - Display the internal buffer */
void tty_keyboard_buffer_echoing(struct tty *tty)
{
// Start atomic operation
atomic_start();
// Save current TTY cursor positions
//saved_tty_x = tty->screen.cursor.disp.x;
//saved_tty_y = tty->screen.cursor.disp.y;
// Set "real" position
tty->screen.cursor.disp.x = tty->keyboard.saved.tty.cursor.x;
tty->screen.cursor.disp.y = tty->keyboard.saved.tty.cursor.y;
// Walk into input buffer and simulate the character
// echoing to force the internal line discipline to
// update TTY cursor position
for (off_t i = 0 ; i < tty->keyboard.private.cursor_max ; ++i)
{
// Clear the area
drect(&tty->screen.private.disp,
tty->screen.cursor.disp.x * (tty->screen.private.disp.font->font.width + 1),
tty->screen.cursor.disp.y * (tty->screen.private.disp.font->font.height + 1),
tty->screen.private.disp.font->font.width + 1,
tty->screen.private.disp.font->font.height + 1);
// Update cursor and display char if needed
tty_screen_discipline_char((void*)tty, tty->buffers.input[i], 1);
}
// workaround for the DEL actions
drect(&tty->screen.private.disp,
tty->screen.cursor.disp.x * (tty->screen.private.disp.font->font.width + 1),
tty->screen.cursor.disp.y * (tty->screen.private.disp.font->font.height + 1),
tty->screen.private.disp.font->font.width + 1,
tty->screen.private.disp.font->font.height + 1);
// Update screen
screen_update((void *)tty->screen.private.disp.vram);
// Stop atomic operation
atomic_stop();
}
/*
** tty_keyboard_buffer_update() - Udate the internal buffer
** with the given key code
** @note: this function should be called ONLY if the device
** is locked
*/
int tty_keyboard_buffer_update(struct tty *tty, key_t key)
{
static const uint8_t keylist_alpha[] = {
KEY_XOT, KEY_LOG, KEY_LN, KEY_SIN, KEY_COS, KEY_TAN,
KEY_FRAC, KEY_FD, KEY_LEFTP, KEY_RIGHTP, KEY_COMMA, KEY_ARROW,
KEY_7, KEY_8, KEY_9,
KEY_4, KEY_5, KEY_6, KEY_MUL, KEY_DIV,
KEY_1, KEY_2, KEY_3, KEY_PLUS, KEY_MINUS,
KEY_0, KEY_UNUSED
};
static const uint8_t keylist_num[] = {
KEY_0, KEY_1, KEY_2, KEY_3, KEY_4,
KEY_5, KEY_6, KEY_7, KEY_8, KEY_9,
KEY_PLUS, KEY_MINUS, KEY_MUL, KEY_DIV,
KEY_LEFTP, KEY_RIGHTP, KEY_COMMA, KEY_POWER,
KEY_DOT, KEY_FD, KEY_ARROW, KEY_UNUSED
};
static const char keylist_num_char[] = "0123456789+-x/(),^.|_";
const uint8_t *keycode_list;
char character;
int i;
// Get the appropriate key list.
keycode_list = keylist_alpha;
if (tty->keyboard.mode.special == 1)
keycode_list = keylist_num;
// Try to find the pressed key.
i = -1;
while (keycode_list[++i] != KEY_UNUSED && keycode_list[i] != key);
if (keycode_list[i] != key)
return (0);
// If the key match, update buffer and get the
// character to be written
character = keylist_num_char[i];
if (tty->keyboard.mode.special == 0) {
character = 'a' + i;
if (tty->keyboard.mode.maj == 1)
character = 'A' + i;;
}
// Insert new character if possible.
tty_keyboard_buffer_insert(tty, character);
return (1);
}

View File

@ -0,0 +1,55 @@
#include <kernel/devices/tty.h>
#include <kernel/drivers/screen.h>
#include <kernel/util/atomic.h>
void tty_cursor_callback(volatile struct tty *tty)
{
static int cursor_visible = 0;
int saved_tty_x;
int saved_tty_y;
int x;
int y;
// Force atomic operation
atomic_start();
// Draw cursor if needed
if (cursor_visible == 0)
{
// Save current TTY cursor positions
saved_tty_x = tty->screen.cursor.disp.x;
saved_tty_y = tty->screen.cursor.disp.y;
// Set "real" position
tty->screen.cursor.disp.x = tty->keyboard.saved.tty.cursor.x;
tty->screen.cursor.disp.y = tty->keyboard.saved.tty.cursor.y;
// Walk into input buffer and simulate the character
// echoing to force the internal line discipline to
// update TTY cursor position
for (off_t i = 0 ; i < tty->keyboard.private.cursor ; ++i)
tty_screen_discipline_char((void*)tty, tty->buffers.input[i], 0);
// Get "real" X and Y position (pixel)
x = tty->screen.cursor.disp.x * (tty->screen.private.disp.font->font.width + 1);
y = tty->screen.cursor.disp.y * (tty->screen.private.disp.font->font.height + 1);
// Draw and display cursor.
dreverse(
(void *)&tty->screen.private.disp, x, y,
(tty->screen.private.disp.font->font.width + 1),
(tty->screen.private.disp.font->font.height + 1)
);
screen_update((void *)tty->screen.private.disp.vram);
// Restore old TTY position
tty->screen.cursor.disp.x = saved_tty_x;
tty->screen.cursor.disp.y = saved_tty_y;
}
// Update cursor status.
cursor_visible ^= 1;
// Stop atomic operations
atomic_stop();
}

View File

@ -0,0 +1,135 @@
#include <kernel/devices/tty.h>
#include <kernel/drivers/keyboard.h>
#include <kernel/util/casio.h>
#include <kernel/util/atomic.h>
#include <kernel/signal.h>
//FIXME: SIGINT and SIGQUIT is send by the hardware driver ?!
void tty_keyboard_check_signal(struct tty *tty)
{
extern struct process *process_current;
struct { uint8_t keycode; int signal; } echapment[3] = {
{.keycode = KEY_LN, .signal = SIGINT},
{.keycode = KEY_DIV, .signal = SIGQUIT},
{.keycode = KEY_0, .signal = SIGTSTP}
};
int signal;
// Check signal sending request
if (tty->keyboard.mode.ctrl == 0) {
pthread_mutex_unlock(&tty->keyboard.private.mutex);
return;
}
// Try to find the signal to send
signal = -1;
for (int i = 0 ; i < 3 ; ++i) {
if (echapment[i].keycode != tty->keyboard.saved.signal.keycode)
continue;
signal = echapment[i].signal;
break;
}
if (signal == -1) {
pthread_mutex_unlock(&tty->keyboard.private.mutex);
return;
}
// Remove first saved character
tty_keyboard_buffer_remove(tty, tty->keyboard.saved.signal.cursor);
// Send signal
// TODO: display signal ?
signal_raise(process_current, signal);
}
//TODO update ?
//@note: Call this function ONLY if the device is locked !!
int tty_keyboard_check_special(struct tty *tty, key_t key)
{
extern fx9860_context_t casio_context;
extern fx9860_context_t vhex_context;
// Check CTRL key (KEY_OPT)
if (key == KEY_OPTN) {
tty->keyboard.mode.ctrl = 1;
return (1);
}
// Check MAJ.
if (key == KEY_ALPHA) {
tty->keyboard.mode.maj ^= 1;
return (1);
}
// Check Alpha / num mode. (special)
if (key == KEY_SHIFT) {
tty->keyboard.mode.special ^= 0x01;
return (1);
}
// Check space key (workaround)
if (key == KEY_DOT && tty->keyboard.mode.special == 0) {
tty_keyboard_buffer_insert(tty, ' ');
return (1);
}
// Check DEL key.
if (key == KEY_DEL){
tty_keyboard_buffer_remove(tty, tty->keyboard.private.cursor);
return (1);
}
// Check MENU key.
// TODO: fix me !
if (key == KEY_MENU)
{
// Save current Vhex context and restore Casio's context.
atomic_start();
fx9860_context_save(&vhex_context);
fx9860_context_restore(&casio_context);
atomic_stop();
// Inject MENU key and call GetKey().
// FIXME !!!
//casio_GetKeyWait(&row, &column, 0, 0, 0, &key);
casio_GetKey(&key);
// Save current Casio's context and restore Vhex's context.
atomic_start();
fx9860_context_save(&casio_context);
fx9860_context_restore(&vhex_context);
atomic_stop();
return (1);
}
// Check EXE key.
if (key == KEY_EXE)
{
// Add new line character.
tty->buffers.input[tty->keyboard.private.cursor_max] = '\n';
tty->keyboard.private.cursor_max += 1;
tty->buffers.input[tty->keyboard.private.cursor_max] = '\0';
// indicate that the EXE has been pressed.
tty->keyboard.mode.enter = 1;
return (1);
}
// Check LEFT key.
if (key == KEY_LEFT)
{
if (tty->keyboard.private.cursor > 0)
tty->keyboard.private.cursor -= 1;
return (1);
}
// Check RIGHT key.
if (key == KEY_RIGHT)
{
if (tty->keyboard.private.cursor < tty->keyboard.private.cursor_max)
tty->keyboard.private.cursor += 1;
return (1);
}
return (0);
}

View File

@ -0,0 +1,37 @@
#include <kernel/devices/tty.h>
#include <kernel/drivers/timer.h>
#include <kernel/devices/earlyterm.h>
#include <kernel/util/atomic.h>
#include <pthread.h>
int tty_keyboard_constructor(struct tty *tty)
{
extern void tty_cursor_callback(volatile struct tty *tty);
// Start atomic
atomic_start();
// Try to get hardware timer slot
tty->keyboard.private.timer.id = timer_install(&tty_cursor_callback, tty, 2, TIMER_STOP);
if (tty->keyboard.private.timer.id < 0) {
earlyterm_write("TTY: keyboard cursor's timer error\n");
return (0);
}
// Intitialise internal data used by the
// abstraction primitive
tty->keyboard.private.cursor = 0;
tty->keyboard.private.cursor_max = 0;
// Initialize internal mutex
pthread_mutex_init(&tty->keyboard.private.mutex, NULL);
// Intialize internal keyboard mode
tty->keyboard.mode.enter = 0;
tty->keyboard.mode.maj = 0;
tty->keyboard.mode.special = 0;
// Start atomic
atomic_stop();
return (0);
}

View File

@ -0,0 +1,12 @@
#include <kernel/devices/tty.h>
#include <kernel/drivers/timer.h>
void tty_keyboard_destructor(struct tty *tty)
{
// Uninstall hardware timer
if (tty->keyboard.private.timer.id != -1)
timer_uninstall(tty->keyboard.private.timer.id);
// Destroy internal mutex
pthread_mutex_destroy(&tty->keyboard.private.mutex);
}

View File

@ -0,0 +1,93 @@
#include <kernel/devices/tty.h>
#include <kernel/devices/earlyterm.h>
#include <kernel/drivers/timer.h>
#include <kernel/util/atomic.h>
#include <string.h>
/*
** tty_screen_buffer_flush() - Force display all character
** currently in the output buffer
*/
void tty_screen_buffer_flush(struct tty *tty)
{
// start atomic operations
atomic_start();
// Force flush
while (tty->screen.cursor.flush != tty->screen.cursor.write)
tty_screen_display_callback(tty);
// Stop atomic operations
atomic_stop();
}
/* Wait flush syncronisation (wait flush timer) */
static void wait_sync_flush(struct tty *tty)
{
// Wait syncro
while (1) {
// Check syncro
if (tty->screen.cursor.flush == tty->screen.cursor.write)
return;
// Wait schedule
// FIXME: force schedule and preemptive !!
__asm__ volatile ("sleep");
}
}
// TODO: use DMA !!!!!!
ssize_t tty_screen_buffer_update(struct tty *tty, const uint8_t *buffer, size_t count)
{
size_t transaction_size;
size_t size;
int counter;
int again;
// Check useless action
if (count == 0)
return (0);
// Wait TTY screen part
pthread_mutex_lock(&tty->screen.private.mutex);
// Start flush timer
again = tty->screen.private.timer.status;
tty->screen.private.timer.status += 1;
if (again == 0)
timer_start(tty->screen.private.timer.id);
// Send buffer data in the output buffer
size = 0;
counter = 0;
transaction_size = 0;
while (size < count)
{
// Get the transaction size
transaction_size = (count - size) / (TTY_OUTPUT_BUFFSIZE / 2);
if (transaction_size == 0)
transaction_size = count - size;
else
transaction_size = TTY_OUTPUT_BUFFSIZE / 2;
// Check output buffer limit
if (tty->screen.cursor.write + transaction_size >= TTY_OUTPUT_BUFFSIZE)
transaction_size = TTY_OUTPUT_BUFFSIZE - tty->screen.cursor.write;
// Wait output buffer syncro and send data
wait_sync_flush(tty);
memcpy(&tty->buffers.output[tty->screen.cursor.write], &buffer[size], transaction_size);
// Update current written size
size = size + transaction_size;
// Update buffer write cursor
tty->screen.cursor.write += transaction_size;
if (tty->screen.cursor.write >= TTY_OUTPUT_BUFFSIZE)
tty->screen.cursor.write -= TTY_OUTPUT_BUFFSIZE;
}
// Indicate that we have finish to write
tty->screen.private.timer.status -= 1;
return (count);
}

View File

@ -0,0 +1,36 @@
#include <kernel/devices/tty.h>
#include <kernel/devices/earlyterm.h>
#include <kernel/drivers/screen.h>
#include <kernel/drivers/timer.h>
#include <kernel/util/kmem.h>
#include <string.h>
int tty_screen_constructor(struct tty *tty)
{
// Try to get the font used by the tty.
// @note: we use drawing lib primitives
if (dopen(&tty->screen.private.disp, "default") != 0)
return (-1);
// Try to get hardware timer slot
tty->screen.private.timer.id = timer_install(&tty_screen_display_callback, tty, 16, TIMER_STOP);
if (tty->screen.private.timer.id < 0) {
earlyterm_write("TTY: screen flush timer error\n");
return (-1);
}
// Generate "visible" informations for the write primitive
tty->screen.winsize.ws_xpixel = screen_get(SCREEN_WIDTH);
tty->screen.winsize.ws_ypixel = screen_get(SCREEN_HEIGHT);
tty->screen.winsize.ws_col = tty->screen.winsize.ws_xpixel / (tty->screen.private.disp.font->font.width + 1);
tty->screen.winsize.ws_row = tty->screen.winsize.ws_ypixel / (tty->screen.private.disp.font->font.height + 1);
// Initialize default TTY screen abstraction cursor position.
tty->screen.cursor.disp.x = 0;
tty->screen.cursor.disp.y = 0;
// Intializei buffer cursor
tty->screen.cursor.flush = 0;
tty->screen.cursor.write = 0;
return (0);
}

View File

@ -0,0 +1,12 @@
#include <kernel/devices/tty.h>
#include <kernel/drivers/timer.h>
void tty_screen_destructor(struct tty *tty)
{
// Uninstall hardware timer
if (tty->screen.private.timer.id != -1)
timer_uninstall(tty->screen.private.timer.id);
// Destroy internal mutex
pthread_mutex_destroy(&tty->screen.private.mutex);
}

View File

@ -0,0 +1,84 @@
#include <kernel/devices/tty.h>
/* tty_vertical_update() - Check / update TTY vertical cursor */
static void tty_vertical_update(struct tty *tty)
{
tty->screen.cursor.disp.y = tty->screen.cursor.disp.y + 1;
if (tty->screen.cursor.disp.y >= tty->screen.winsize.ws_row)
{
dscroll(&tty->screen.private.disp, tty->screen.private.disp.font->font.height + 1);
tty->screen.cursor.disp.y = tty->screen.winsize.ws_row - 1;
}
}
/* tty_horizontal_update() - Check / update TTY horizotal cursor */
static int tty_horizontal_update(struct tty *tty)
{
tty->screen.cursor.disp.x = tty->screen.cursor.disp.x + 1;
if (tty->screen.cursor.disp.x >= tty->screen.winsize.ws_col)
{
tty->screen.cursor.disp.x = 0;
tty_vertical_update(tty);
return (1);
}
return (0);
}
/* tty_vertical_clear() - Form feed emulation */
static void tty_vertical_clear(struct tty *tty)
{
dscroll(
&tty->screen.private.disp,
tty->screen.private.disp.font->font.height * tty->screen.winsize.ws_row
);
}
int tty_screen_discipline_char(struct tty *tty, char n, int action)
{
int offset;
switch (n)
{
// Check bell char (TODO)
case '\a': break;
// Check backspace.
case '\b':
if (tty->screen.cursor.disp.x > 0)
tty->screen.cursor.disp.x -= 1;
break;
// Check tabulation
case '\t':
// Check if we need a new line or not.
offset = 5 - (tty->screen.cursor.disp.x - ((tty->screen.cursor.disp.x / 5) * 5));
if (tty->screen.cursor.disp.x + offset < tty->screen.winsize.ws_col) {
tty->screen.cursor.disp.x = tty->screen.cursor.disp.x + offset;
break;
}
// If a new line is required char.
// Generate a new line.
tty->screen.cursor.disp.x = 0;
tty_vertical_update(tty);
break;
// Check 'form feed'
// Check 'vertical tab'
// Check 'new line'
// Check 'cariage return'
case '\f': tty->screen.cursor.disp.y = 0; tty_vertical_clear(tty); break;
case '\v': tty_vertical_update(tty); break;
case '\n': tty->screen.cursor.disp.x = 0; tty_vertical_update(tty); break;
case '\r': tty->screen.cursor.disp.x = 0; break;
default:
if (action != 0) {
dascii(&tty->screen.private.disp,
tty->screen.cursor.disp.x, tty->screen.cursor.disp.y,
n, 0);
}
tty_horizontal_update(tty);
return (0);
}
return (0);
}

View File

@ -0,0 +1,39 @@
#include <kernel/devices/tty.h>
#include <kernel/devices/earlyterm.h>
#include <kernel/drivers/screen.h>
#include <kernel/drivers/timer.h>
#include <kernel/util/atomic.h>
#include <display.h>
/* tty_screen_display_callback() - flush ony characte of the output buffer */
void tty_screen_display_callback(struct tty *tty)
{
int update;
// Force atomic operation
atomic_start();
// Check useless action
update = 0;
while (tty->screen.cursor.flush != tty->screen.cursor.write)
{
tty_screen_discipline_char(tty, tty->buffers.output[tty->screen.cursor.flush], 1);
tty->screen.cursor.flush = tty->screen.cursor.flush + 1;
if (tty->screen.cursor.flush >= TTY_OUTPUT_BUFFSIZE)
tty->screen.cursor.flush = 0;
update = 1;
}
// Update screen if needed
if (update == 1)
screen_update(tty->screen.private.disp.vram);
// Stop timer if needed
if (tty->screen.private.timer.status == 0) {
timer_stop(tty->screen.private.timer.id);
pthread_mutex_unlock(&tty->screen.private.mutex);
}
// Stop atomic operation
atomic_stop();
}

View File

@ -0,0 +1,44 @@
#include <kernel/drivers/cpg.h>
#include <kernel/hardware/cpg.h>
#include <kernel/devices/earlyterm.h>
// Internal struct
struct cpg cpg_info;
__attribute__((constructor))
static void cpg_init(void)
{
// Calculate FLL frequency (Khz)
// @note: RCLK = 32 768 Hz
cpg_info.fll_freq = SH7305_CPG.FLLFRQ.FLF * 32768; // Hz
cpg_info.fll_freq /= (1 << SH7305_CPG.FLLFRQ.SELXM); // Check FLL output division
// Calculate PLL frequency (Khz)
cpg_info.pll_freq = cpg_info.fll_freq * (SH7305_CPG.FRQCRA.STC + 1);
// Calculate CPU clock frequency !
cpg_info.cpu_freq = cpg_info.pll_freq / (1 << (SH7305_CPG.FRQCRA.IFC + 1));
// Calculate BUS clock frequency !
cpg_info.bus_freq = cpg_info.pll_freq / (1 << (SH7305_CPG.FRQCRA.BFC + 1));
// Calculate Peripheral clock frequency !
cpg_info.per_freq = cpg_info.pll_freq / (1 << (SH7305_CPG.FRQCRA.PFC + 1));
// Debug
earlyterm_write("Calibrate frequencies...\n");
earlyterm_write(
"* FLL freq: %d.%d Mhz\n"
"* PLL freq: %d.%d Mhz\n"
"* CPU freq: %d.%d Mhz\n"
"* BUS freq: %d.%d Mhz\n"
"* Per freq: %d.%d Mhz\n",
cpg_info.fll_freq / 1000000, (((cpg_info.fll_freq - ((cpg_info.fll_freq / 1000000)) * 1000000)) + 999) / 1000,
cpg_info.pll_freq / 1000000, (((cpg_info.pll_freq - ((cpg_info.pll_freq / 1000000)) * 1000000)) + 999) / 1000,
cpg_info.cpu_freq / 1000000, (((cpg_info.cpu_freq - ((cpg_info.cpu_freq / 1000000)) * 1000000)) + 999) / 1000,
cpg_info.bus_freq / 1000000, (((cpg_info.bus_freq - ((cpg_info.bus_freq / 1000000)) * 1000000)) + 999) / 1000,
cpg_info.per_freq / 1000000, (((cpg_info.per_freq - ((cpg_info.per_freq / 1000000)) * 1000000)) + 999) / 1000
);
DBG_WAIT;
}

View File

@ -0,0 +1,16 @@
#include <kernel/drivers/cpg.h>
uint32_t cpg_get_frequency(enum cpg_module module)
{
extern struct cpg cpg_info;
switch (module)
{
case CPG_FLL: return (cpg_info.fll_freq);
case CPG_PLL: return (cpg_info.pll_freq);
case CPG_CPU: return (cpg_info.cpu_freq);
case CPG_BUS: return (cpg_info.bus_freq);
case CPG_PERIPHERAL: return (cpg_info.per_freq);
}
return (0);
}

View File

@ -1,18 +1,41 @@
#include <kernel/drivers/keyboard.h>
#include <kernel/util/atomic.h>
/*keyboard_wait_event() - Wait keys events (press or release) */
void keyboard_wait_event(void)
void keyboard_wait_event(keyscan_t *list)
{
extern volatile uint8_t keylist_isUpdate;
extern struct keycache_s *keylist;
struct keycache_s *keynode;
int i;
// Wait key list update.
// @note:
// To ensure reentrace and avoid data corruption
// we should wait kernel indication.
// TODO: explain correctly x)
// @note : each tim the user press or relase key(s)
// the hardware driver will set the "keylist_isUpdate" to 1.
// TODO: schedule !!
while (keylist_isUpdate == 0)
{
__asm__ volatile ("sleep");
}
// Start atomic operations
atomic_start();
// Dump all keys
i = 0;
keynode = keylist;
while (keynode != NULL)
{
list[i].counter = keynode->counter;
list[i].keycode = keynode->keycode;
keynode = keynode->next;
i = i + 1;
}
list[i].keycode = KEY_UNUSED;
// Indicate that the key buffer has been readed
keylist_isUpdate = 0;
// Stop atomic operations
atomic_stop();
}

View File

@ -5,7 +5,7 @@ extern void t6k11_variant_lcd_driver(void *vram);
extern void t6k11_lcd_driver(void *vram);
// Primitives
void (*screen_update)(void *vram);
void (*screen_driver)(void *vram);
__attribute__((constructor))
void screen_driver_load(void)
@ -13,9 +13,9 @@ void screen_driver_load(void)
// Check T6K11 variant which appear during
// the OS >= 03.00.0000
if (*(uint8_t*)0xa0010021 == '3') {
screen_update = (void*)&t6k11_variant_lcd_driver;
screen_driver = (void*)&t6k11_variant_lcd_driver;
return;
}
// Default driver
screen_update = &t6k11_lcd_driver;
screen_driver = &t6k11_lcd_driver;
}

View File

@ -0,0 +1,11 @@
#include <kernel/drivers/screen.h>
void screen_update(void *vram)
{
extern void (*screen_driver)(void *vram);
// Check driver validity
if (screen_driver == NULL)
return;
screen_driver(vram);
}

View File

@ -0,0 +1,63 @@
#include <kernel/drivers/timer.h>
#include <kernel/drivers/cpg.h>
#include <kernel/hardware/tmu.h>
#include <kernel/util/atomic.h>
/*
** int timer_instal(void*, void*, tmode_t)
**
** @info
** This function will try to setup an hardware timer.
*/
int timer_install(void *callback, void *arg, int hertz, tmode_t mode)
{
extern struct timer_cache_s timercache[TIMER_NUMBER];
int prescaler[8] = {4, 16, 64, 256, 1024, 4, 4, 4};
uint32_t ticks;
int timerID;
// Do atomic operation because of
// sheared timer cache and I/O access.
atomic_start();
// Find free timer.
timerID = -1;
while (++timerID < TIMER_NUMBER &&
timercache[timerID].status != TIMER_UNUSED);
if (timerID >= TIMER_NUMBER)
{
atomic_stop();
return (-1);
}
// Initialise internal timer data.
timercache[timerID].callback = callback;
timercache[timerID].status = mode;
timercache[timerID].arg = arg;
// Initialise hardware module.
SH7305_TMU.TSTR.BYTE &= ~(1 << timerID); // Stop timer.
// Calculate real ticks needed
// FIXME: correct ticks calculation (remove / 2 ?)
ticks = cpg_get_frequency(CPG_PERIPHERAL) / 2;
ticks = ticks / prescaler[SH7305_TMU.TIMER[timerID].TCR.TPSC];
ticks = ticks / hertz;
// Setup Timer
SH7305_TMU.TIMER[timerID].TCOR = ticks;
SH7305_TMU.TIMER[timerID].TCNT = ticks;
// Configure timer
SH7305_TMU.TIMER[timerID].TCR.UNF = 0; // Clear interrupt flag.
SH7305_TMU.TIMER[timerID].TCR.UNIE = 1; // Enable interrupt.
// Start timer if needed.
if (mode == TIMER_START)
SH7305_TMU.TSTR.BYTE |= 1 << timerID;
// End of atomic operations.
// and return the timer ID.
atomic_stop();
return (timerID);
}

View File

@ -0,0 +1,22 @@
#include <kernel/drivers/timer.h>
#include <kernel/util/atomic.h>
int timer_set_callback(int timerID, void *callback, void *arg)
{
extern struct timer_cache_s timercache[TIMER_NUMBER];
// Check bad ID
if (timerID < 0 || timerID >= TIMER_NUMBER)
return (-1);
// Start Atomic operation.
atomic_start();
// Set new callback and arg
timercache[timerID].callback = callback;
timercache[timerID].arg = arg;
// Stop atomic operation and return.
atomic_stop();
return (0);
}

View File

@ -0,0 +1,31 @@
#include <kernel/drivers/timer.h>
#include <kernel/hardware/tmu.h>
#include <kernel/util/atomic.h>
int timer_set_ticks(int timerID, uint32_t ticks)
{
extern struct timer_cache_s timercache[TIMER_NUMBER];
uint8_t status;
// Check bad ID
if (timerID < 0 || timerID >= TIMER_NUMBER)
return (-1);
// Start Atomic operation.
atomic_start();
// Save current timer status (start / stop)
status = SH7305_TMU.TSTR.BYTE &= 1 << timerID; // save
SH7305_TMU.TSTR.BYTE &= ~(1 << timerID); // stop
// Setup Timer timer
SH7305_TMU.TIMER[timerID].TCOR = ticks;
SH7305_TMU.TIMER[timerID].TCNT = ticks;
// Start hardware timer.
SH7305_TMU.TSTR.BYTE |= status;
// Stop atomic operation and return.
atomic_stop();
return (0);
}

View File

@ -1,54 +0,0 @@
#include <kernel/drivers/timer.h>
#include <kernel/hardware/tmu.h>
#include <kernel/util/atomic.h>
/*
** int timer_instal(void*, void*, tmode_t)
**
** @info
** This function will try to setup an hardware timer.
*/
int timer_install(void *callback, void *arg, uint32_t ticks, tmode_t mode)
{
extern struct timer_cache_s timercache[TIMER_NUMBER];
int timer_ID;
// Do atomic operation because of
// sheared timer cache and I/O access.
atomic_start();
// Find free timer.
timer_ID = -1;
while (++timer_ID < TIMER_NUMBER &&
timercache[timer_ID].status != TIMER_UNUSED);
if (timer_ID >= TIMER_NUMBER)
{
atomic_stop();
return (-1);
}
// Initialise internal timer data.
timercache[timer_ID].callback = callback;
timercache[timer_ID].status = mode;
timercache[timer_ID].arg = arg;
// Initialise hardware module.
SH7305_TMU.TSTR.BYTE &= ~(1 << timer_ID); // Stop timer.
// Setup Timer
SH7305_TMU.TIMER[timer_ID].TCOR = ticks;
SH7305_TMU.TIMER[timer_ID].TCNT = ticks;
// Configure timer
SH7305_TMU.TIMER[timer_ID].TCR.UNF = 0; // Clear interrupt flag.
SH7305_TMU.TIMER[timer_ID].TCR.UNIE = 1; // Enable interrupt.
// Start timer if needed.
if (mode == TIMER_START)
SH7305_TMU.TSTR.BYTE |= 1 << timer_ID;
// End of atomic operations.
// and return the timer ID.
atomic_stop();
return (timer_ID);
}

View File

@ -6,13 +6,9 @@ int sys_close(int fd)
extern struct process *process_current;
// Check fd validity
if (fd < 0 || fd - 3 >= PROCESS_NB_OPEN_FILE)
if (fd < 0 || fd >= PROCESS_NB_OPEN_FILE)
return (-1);
// Check virtual file (TTY)
if (fd < 3)
return (0);
// Call VFS close primitive
return (vfs_close(&process_current->opfile[fd - 3].file));
return (vfs_close(&process_current->opfile[fd].file));
}

View File

@ -6,13 +6,9 @@ off_t sys_lseek(int fd, off_t offset, int whence)
extern struct process *process_current;
// Check fd
if (fd < 0 || fd - 3 >= PROCESS_NB_OPEN_FILE)
if (fd < 0 || fd >= PROCESS_NB_OPEN_FILE)
return (-1);
// Check virtual file (TTY)
if (fd < 3)
return (0);
// Call VFS lseek primitive
return (vfs_lseek(&process_current->opfile[fd - 3].file, offset, whence));
return (vfs_lseek(&process_current->opfile[fd].file, offset, whence));
}

View File

@ -4,13 +4,14 @@
int sys_open(const char *pathname, int flags, ...)
{
extern struct process *process_current;
int fd;
// Get current process
if (process_current == NULL)
return (-1);
// Try to find free file slot
int fd = -1;
fd = -1;
while (++fd < PROCESS_NB_OPEN_FILE &&
process_current->opfile[fd].status == PROCESS_FILE_SLOT_USED);
if (fd >= PROCESS_NB_OPEN_FILE)
@ -24,9 +25,5 @@ int sys_open(const char *pathname, int flags, ...)
return (-1);
// Return the file descriptor
// @note:
// * fd = 0 -> STDOUT_FILENO
// * fd = 1 -> STDERR_FILENO
// * fd = 2 -> STDIN_FILENO
return (fd + 3);
return (fd);
}

View File

@ -7,17 +7,9 @@ ssize_t sys_pread(int fd, void *buf, size_t count, off_t offset)
extern struct process *process_current;
// Check fd
if (fd < 0 || fd - 3 >= PROCESS_NB_OPEN_FILE)
if (fd < 0 || fd >= PROCESS_NB_OPEN_FILE)
return (-1);
// Check virtual file (TTY) and open it if needed
if (fd < 3) {
if (process_current->tty.private == NULL &&
vfs_open(&process_current->tty, "/dev/tty", O_RDWR) != 0)
return (-1);
return (vfs_pread(&process_current->tty, buf, count, offset));
}
// call VFS read primitive
return (vfs_pread(&process_current->opfile[fd - 3].file, buf, count, offset));
return (vfs_pread(&process_current->opfile[fd].file, buf, count, offset));
}

View File

@ -7,17 +7,9 @@ ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t offset)
extern struct process *process_current;
// Check fd
if (fd < 0 || fd - 3 >= PROCESS_NB_OPEN_FILE)
if (fd < 0 || fd >= PROCESS_NB_OPEN_FILE)
return (-1);
// Check virtual file (TTY) and open it if needed
if (fd < 3) {
if (process_current->tty.private == NULL &&
vfs_open(&process_current->tty, "/dev/tty", O_RDWR) != 0)
return (-1);
return (vfs_pwrite(&process_current->tty, buf, count, offset));
}
// call VFS read primitive
return (vfs_pwrite(&process_current->opfile[fd].file, buf, count, offset));
}

View File

@ -7,17 +7,9 @@ ssize_t sys_read(int fd, void *buf, size_t count)
extern struct process *process_current;
// Check fd
if (fd < 0 || fd - 3 >= PROCESS_NB_OPEN_FILE)
if (fd < 0 || fd >= PROCESS_NB_OPEN_FILE)
return (-1);
// Check virtual file (TTY) and open it if needed
if (fd < 3) {
if (process_current->tty.private == NULL &&
vfs_open(&process_current->tty, "/dev/tty", O_RDWR) != 0)
return (-1);
return (vfs_read(&process_current->tty, buf, count));
}
// call VFS read primitive
return (vfs_read(&process_current->opfile[fd - 3].file, buf, count));
return (vfs_read(&process_current->opfile[fd].file, buf, count));
}

View File

@ -7,17 +7,9 @@ ssize_t sys_write(int fd, const void *buf, size_t count)
extern struct process *process_current;
// Check fd
if (fd < 0 || fd - 3 >= PROCESS_NB_OPEN_FILE)
if (fd < 0 || fd >= PROCESS_NB_OPEN_FILE)
return (-1);
// Check virtual file (TTY) and open it if needed
if (fd < 3) {
if (process_current->tty.private == NULL &&
vfs_open(&process_current->tty, "/dev/tty", O_RDWR) != 0)
return (-1);
return (vfs_write(&process_current->tty, buf, count));
}
// call VFS write primitive
return (vfs_write(&process_current->opfile[fd].file, buf, count));
}

View File

@ -12,6 +12,9 @@ struct dentry *vfs_dentry_alloc(const char *name, mode_t mode)
if (node == NULL)
return (NULL);
// Wipe all informations
memset(node, 0x00, sizeof(struct dentry));
// Initialize dentry
memset(node->name, 0x00, VFS_DENTRY_NAME_LENGHT);
@ -24,6 +27,7 @@ struct dentry *vfs_dentry_alloc(const char *name, mode_t mode)
// Set default value
node->inode = NULL;
node->device = NULL;
node->parent = NULL;
node->child = NULL;
node->next = NULL;

View File

@ -1,14 +1,37 @@
#include <kernel/fs/vfs.h>
#include <kernel/fs/stat.h>
#include <kernel/util/atomic.h>
int vfs_close(FILE *file)
{
struct dentry *dentry;
// Check error
if (file == NULL)
return (-1);
//TODO: call close primitive for device !
// Get the dentry
dentry = file->private;
// Start atomic operations
atomic_start();
// Update internal dentry counter
((struct dentry*)file->private)->counter -= 1;
dentry->counter = dentry->counter - 1;
// Call close primitive for the device if needed
if ((dentry->mode & __S_IFCHR) != 0 && dentry->counter == 0) {
dentry->device->close(dentry->inode);
dentry->inode = NULL;
}
// Wipe all inforations
file->cursor = 0;
file->file_op = NULL;
file->permission = 0;
file->private = NULL;
// Stop atomic operations
atomic_stop();
return (0);
}

View File

@ -1,6 +1,7 @@
#include <kernel/fs/vfs.h>
#include <kernel/fs/stat.h>
#include <kernel/devices/earlyterm.h>
#include <kernel/util/atomic.h>
/* vfs_open() - Open file named pathname */
int vfs_open(FILE *file, char const *pathname, int flags)
@ -14,30 +15,44 @@ int vfs_open(FILE *file, char const *pathname, int flags)
dentry = vfs_dentry_resolve(pathname, 0);
if (dentry == NULL)
{
earlyterm_write("VFS_open() error !\n");
earlyterm_write("* path error '%s'\n", pathname);
earlyterm_write("VFS_open() path error !\n");
DBG_WAIT;
return (-1);
}
// Start atomic operations
atomic_start();
// Check directory.
if ((dentry->mode & __S_IFDIR) != 0)
{
earlyterm_write("VFS_open(): file type error '%s'\n", pathname);
DBG_WAIT;
atomic_stop();
return (-2);
}
//TODO: call FS specific open() primitive ?
// Debug
/* earlyterm_write("vfs_open(): inode found !");
earlyterm_write("* path: %s", pathname);
earlyterm_write("* name: %s", dentry->name);
earlyterm_write("* inode: %p", dentry->inode);
earlyterm_write("* file_op: %p", dentry->dentry_op.file_op);
DBG_WAIT;*/
// Call device specific open() primitive if needed
if ((dentry->mode & __S_IFCHR) != 0 && dentry->counter == 0)
{
// Check potential error
if (dentry->device == NULL) {
earlyterm_write("VFS_open: device does not exist\n");
DBG_WAIT;
atomic_stop();
return (-3);
}
// Open the device
dentry->inode = dentry->device->open(dev_get_major(dentry->dev_id), dev_get_minor(dentry->dev_id));
if (dentry->inode == NULL) {
earlyterm_write("VFS_open: device open error !!\n");
DBG_WAIT;
atomic_stop();
return (-4);
}
}
// Update interne dentry counter
dentry->counter = dentry->counter + 1;
@ -46,5 +61,8 @@ int vfs_open(FILE *file, char const *pathname, int flags)
file->permission = dentry->mode & (~__S_IFMT);
file->file_op = dentry->dentry_op.file_op;
file->cursor = 0;
// Stop atomic operations
atomic_stop();
return (0);
}

View File

@ -10,15 +10,13 @@ ssize_t vfs_read(FILE *file, void *buf, size_t count)
return (-1);
// Get / check file's informations
if (file->private == NULL ||
file->file_op == NULL ||
file->file_op->read == NULL)
return (-1);
if (file->private == NULL)
return (-2);
if (file->file_op == NULL)
return (-3);
if (file->file_op->read == NULL)
return (-4);
// Check error
if (file->cursor == 0xffffffff)
earlyterm_write("pos = %#x\n", file->cursor);
// Read with FS specifique primitive and return the numbe of reading bytes.
ssize_t read = file->file_op->read(((struct dentry*)file->private)->inode, buf, count, file->cursor);
if (read > 0)

View File

@ -9,14 +9,16 @@ ssize_t vfs_write(FILE *file, const void *buf, size_t count)
return (-1);
// Get / check file's informations
if (file->private == NULL ||
file->file_op == NULL ||
file->file_op->write == NULL)
return (-1);
if (file->private == NULL)
return (-2);
if (file->file_op == NULL)
return (-3);
if (file->file_op->write == NULL)
return (-4);
// Writa with FS specifique primitive and return the numbe of reading bytes.
ssize_t write = file->file_op->write(((struct dentry*)file->private)->inode, buf, count, file->cursor);
if (write != -1)
if (write > 0)
file->cursor = file->cursor + write;
return (write);
}

View File

@ -50,27 +50,24 @@ int vfs_mknod(const char *pathname, mode_t mode, dev_t dev)
name = (name == NULL) ? (void *)pathname : &name[1];
// Try to find the device
// TODO: handle othe file (mode) !!!
// TODO: handle other file (mode) !!!
device = device_get(dev_get_major(dev));
if (device == NULL) {
atomic_stop();
return (-2);
}
// Tru to create empty node
// Try to create empty node
file = vfs_dentry_alloc(name, mode | __S_IFCHR);
if (file == NULL) {
atomic_stop();
return (-3);
}
// Try to open device
file->inode = device->open(dev_get_major(dev), dev_get_minor(dev));
if (file->inode == NULL) {
atomic_stop();
return (-4);
}
// Indicate device file
file->inode = NULL;
file->device = device;
file->dev_id = dev;
// Set file operations
file->dentry_op.file_op = &device->file_op;

View File

@ -1,9 +1,9 @@
#include <kernel/loader.h>
#include <kernel/fs/vfs.h>
#include <kernel/fs/file.h>
#include <kernel/util/elf.h>
#include <kernel/devices/earlyterm.h>
#include <fcntl.h>
#include <elf.h>
//
// TODO: write doc

View File

@ -2,8 +2,10 @@
#include <asm/unistd_32.h>
#include <kernel/memory.h>
#include <kernel/devices/earlyterm.h>
#include <lib/string.h>
#include <kernel/fs/vfs.h>
#include <sys/signal.h>
#include <string.h>
#include <unistd.h>
/* proc_stacks_create() - create user and kernel stack */
static int proc_stacks_create(struct process *proc)
@ -81,9 +83,18 @@ static void proc_file_init(struct process *proc)
proc->opfile[i].file.cursor = 0;
}
// Initialize "special" file
// Initialize working directory path
proc->working_dir = vfs_root_node;
proc->tty.private = NULL;
// Open TTY for stdin, stdout, stderr
// TODO: add correct stderr configurations
// TODO: do not open TTY each time ?
vfs_open(&proc->opfile[STDIN_FILENO].file, "/dev/tty", O_RDWR);
vfs_open(&proc->opfile[STDOUT_FILENO].file, "/dev/tty", O_RDWR);
vfs_open(&proc->opfile[STDERR_FILENO].file, "/dev/tty", O_RDWR);
proc->opfile[STDIN_FILENO].status = PROCESS_FILE_SLOT_USED;
proc->opfile[STDOUT_FILENO].status = PROCESS_FILE_SLOT_USED;
proc->opfile[STDERR_FILENO].status = PROCESS_FILE_SLOT_USED;
}
/* proc_signal_init() - Initialize signal management */

View File

@ -1,14 +1,29 @@
#include <kernel/process.h>
#include <kernel/scheduler.h>
#include <kernel/devices/earlyterm.h>
#include <kernel/util/atomic.h>
#include <kernel/fs/vfs.h>
#include <kernel/memory.h>
static void first_proc_term(int __stat_lock)
{
earlyterm_write("Kernel PANIK !!\n");
earlyterm_write("First process terminate [%d]\n", __stat_lock);
// TODO: restore Casio context / environnement
earlyterm_write("Wait manual reset...");
while (1);
}
void process_terminate(struct process *proc, int __stat_lock)
{
struct pm_heap_page **page;
void *tmp;
// Check first process termination
if (proc->parent == NULL)
first_proc_term(__stat_lock);
// Start atomic operation
atomic_start();

View File

@ -1,7 +1,9 @@
#include <kernel/scheduler.h>
#include <kernel/process.h>
#include <kernel/signal.h>
//TODO: assembly !
//TODO: assembly ?
//TODO: preemptive handling !!
// @note: This part *SHOULD* be exeption safe !
int sched_schedule(common_context_t **context_current, common_context_t **context_next)
{
@ -20,7 +22,7 @@ int sched_schedule(common_context_t **context_current, common_context_t **contex
{
// Check process validity
if (task_next->status == SCHED_TASK_RUNNING
&& signal_deliver_pending(task_next->process) == 0)
&& signal_deliver_pending((void*)task_next->process) == 0)
break;
// Get next task
@ -30,8 +32,12 @@ int sched_schedule(common_context_t **context_current, common_context_t **contex
}
// Check error
if (task_next == sched_task_current)
// FIXME: check terminate signal ?!
if (task_next == sched_task_current) {
if (task_next != NULL)
signal_deliver_pending((void*)task_next->process);
return (-1);
}
// Get contexts
*context_current = NULL;

View File

@ -3,107 +3,48 @@
#include <kernel/hardware/tmu.h>
#include <kernel/devices/earlyterm.h>
#include <kernel/drivers/timer.h>
#include <kernel/drivers/cpg.h>
// Internal data used by the scheduler handler
uint32_t sched_timer_id = 0;
int sched_timer_id = 0;
uint32_t sched_timer_address = 0;
uint32_t sched_timer_intevt = 0;
uint32_t sched_timer_tstr_bit = 0;
// Internal private function
//void sched_handler(void);
//FIXME: remove me and wrap timer interrupt when occur !!
/*static void scheduler_timer_callback(void)
{
common_context_t *context_current;
common_context_t *context_next;
//TODO: quantum handling !!
//TODO: scheduler block / unblock options !!
//FIXME: Get SPC, SSR, ... !!
// Get current context and
if (sched_schedule(&context_current, &context_next) != 0)
return;
// Debug
//dclear(&kdisplay);
//earlyterm_write(&kdisplay, 0, 0, "Scheduler_schudele !");
//earlyterm_write(&kdisplay, 0, 1, "context current = %p", context_current);
//earlyterm_write(&kdisplay, 0, 2, "context next = %p", context_next);
//(*screen_update)(kdisplay.vram);
//earlyterm_write(&kdisplay, 0, 3, "context switch !");
//(*screen_update)(kdisplay.vram);
//DBG_WAIT;
// Context switch
sched_context_switch(context_current, context_next);
}*/
// TODO: generate quantum and quantum counter for preemption !
void sched_start(void)
{
extern struct sched_task *sched_task_queue;
extern struct process *process_current;
uint32_t fll_freq;
uint32_t pll_freq;
uint32_t cpu_freq;
uint32_t bus_freq;
uint32_t per_freq;
// Calculate FLL frequency (Khz)
// @note: RCLK = 32 768 Hz
fll_freq = SH7305_CPG.FLLFRQ.FLF * 32768; // Hz
fll_freq = fll_freq / (1 << SH7305_CPG.FLLFRQ.SELXM); // Check FLL output division
// Calculate PLL frequency (Khz)
pll_freq = fll_freq * (SH7305_CPG.FRQCRA.STC + 1);
// Calculate CPU clock frequency !
cpu_freq = pll_freq / (1 << (SH7305_CPG.FRQCRA.IFC + 1));
// Calculate BUS clock frequency !
bus_freq = pll_freq / (1 << (SH7305_CPG.FRQCRA.BFC + 1));
// Calculate Peripheral clock frequency !
per_freq = pll_freq / (1 << (SH7305_CPG.FRQCRA.PFC + 1));
// Debug
earlyterm_write(
"* FLL freq: %d.%d Mhz\n"
"* PLL freq: %d.%d Mhz\n"
"* CPU freq: %d.%d Mhz\n"
"* BUS freq: %d.%d Mhz\n"
"* Per freq: %d.%d Mhz\n",
fll_freq / 1000000, (((fll_freq - ((fll_freq / 1000000)) * 1000000)) + 999) / 1000,
pll_freq / 1000000, (((pll_freq - ((pll_freq / 1000000)) * 1000000)) + 999) / 1000,
cpu_freq / 1000000, (((cpu_freq - ((cpu_freq / 1000000)) * 1000000)) + 999) / 1000,
bus_freq / 1000000, (((bus_freq - ((bus_freq / 1000000)) * 1000000)) + 999) / 1000,
per_freq / 1000000, (((per_freq - ((per_freq / 1000000)) * 1000000)) + 999) / 1000
);
DBG_WAIT;
// Register first process !
process_current = sched_task_queue->process;
// Setup TMU0 (scheduler) interrupt !
// @note: I use Po/4 on TMU prescaler
// TODO: generate quantum and quantum counter for preemption !
uint32_t ticks = (per_freq / 4) / 32;
sched_timer_id = timer_install(NULL, NULL, ticks, 0);
sched_timer_id = timer_install(NULL, NULL, 32, TIMER_STOP);
if (sched_timer_id < 0) {
earlyterm_write("scheduler FATAL error (timer)\n");
earlyterm_write("wait manuall reset...");
while (1);
}
// Setup appropriate ticks timing fior the timer
// @note: I use Po/4 on TMU prescaler and I want 32 process switch per second
//timer_set_ticks(sched_timer_id, (cpg_get_frequency(CPG_PERIPHERAL) / 4) / 32);
// Initialize internal precalculated data wich will be used
// when scheduler timer interrupt occur.
sched_timer_address = (uint32_t)&SH7305_TMU.TIMER[sched_timer_id].TCR;
sched_timer_intevt = 0x400 + (0x20 * sched_timer_id);
sched_timer_tstr_bit = 1 << sched_timer_id;
// Debug
earlyterm_write("* timer ID: %d\n", sched_timer_id);
earlyterm_write("* timer addr: %#x\n", sched_timer_address);
earlyterm_write("* timer event: %#x\n", sched_timer_intevt);
earlyterm_write("* timer TSTR: %#x\n", sched_timer_tstr_bit);
DBG_WAIT;
//earlyterm_write("* timer ID: %d\n", sched_timer_id);
//earlyterm_write("* timer addr: %#x\n", sched_timer_address);
//earlyterm_write("* timer event: %#x\n", sched_timer_intevt);
//earlyterm_write("* timer TSTR: %#x\n", sched_timer_tstr_bit);
//DBG_WAIT;
// Start scheduler timer
timer_start(sched_timer_id);

View File

@ -11,15 +11,11 @@
//TODO
static void proc_dump_shared(struct process *child, struct process *parent)
{
// Dump all opened file
for (int i = 0 ; i < PROCESS_NB_OPEN_FILE ; ++i)
{
memcpy(&child->opfile[i].file, &parent->opfile[i].file, sizeof(FILE));
child->opfile[i].status = parent->opfile[i].status;
}
// Dump specific
memcpy(&child->tty, &parent->tty, sizeof(FILE));
}
static int generate_arguments(struct process *proc, char **argv, char **envp)
@ -80,7 +76,7 @@ pid_t sys_fexecve(const char *pathname, char **argv, char **envp)
// Try to load binary into physical memory
if (loader(proc, pathname) != 0)
{
earlyterm_write("sys_fexecve: loader error !");
earlyterm_write("sys_fexecve: loader error !\n");
DBG_WAIT;
process_free(proc);
atomic_stop();
@ -104,7 +100,7 @@ pid_t sys_fexecve(const char *pathname, char **argv, char **envp)
// Add new process into task queue
if (sched_task_add(proc))
{
earlyterm_write("sys_fexecve: scheduler error !");
earlyterm_write("sys_fexecve: scheduler error !\n");
DBG_WAIT;
process_free(proc);
atomic_stop();

54
src/kernel/util/mutex.c Normal file
View File

@ -0,0 +1,54 @@
#include <kernel/process.h>
#include <kernel/util/atomic.h>
#include <lib/pthread.h>
#include <lib/unistd.h>
int pthread_mutex_init(struct __pthread_mutex_s *mutex,
const struct __pthread_mutexattr_s *attr)
{
// FIXME: handle attribute
(void)attr;
// Initialize mutex
mutex->lock = 0;
return (0);
}
int pthread_mutex_lock(struct __pthread_mutex_s *mutex)
{
// Wait util the mutex is unlocked
while (1)
{
// Check if the mutex is unlock
atomic_start();
if (mutex->lock == 0)
break;
atomic_stop();
// TODO: schedule
__asm__ volatile ("sleep");
}
// Lock the mutex
mutex->lock = 1;
// Stop atomic operations
atomic_stop();
return (0);
}
int pthread_mutex_unlock(struct __pthread_mutex_s *mutex)
{
// Check validity and unlock mutex if possible
atomic_start();
mutex->lock = 0;
atomic_stop();
return (0);
}
//TODO
int pthread_mutex_destroy(struct __pthread_mutex_s *mutex)
{
(void)mutex;
return (-1);
}

View File

@ -1,6 +1,7 @@
#include <display.h>
static void font_draw_core(uint32_t *vram, struct font_s *font, struct font_block_s *fblock)
static void font_draw_core(uint32_t *vram, struct font_s *font,
struct font_block_s *fblock, int mode)
{
uint8_t vram_offset_y;
uint32_t pixel_cursor;
@ -34,6 +35,9 @@ static void font_draw_core(uint32_t *vram, struct font_s *font, struct font_bloc
{
vram[((fblock->x + x) >> 5) + vram_offset_y] |=
0x80000000 >> ((fblock->x + x) & 31);
} else if (mode == 1) {
vram[((fblock->x + x) >> 5) + vram_offset_y] &=
~(0x80000000 >> ((fblock->x + x) & 31));
}
}
@ -45,7 +49,7 @@ static void font_draw_core(uint32_t *vram, struct font_s *font, struct font_bloc
/* dascii() - Draw ASCII character into Video RAM */
void dascii(display_t *disp, int x, int y, char const c)
void dascii(display_t *disp, int x, int y, char const c, int mode)
{
struct font_block_s fblock;
@ -94,5 +98,5 @@ void dascii(display_t *disp, int x, int y, char const c)
return;
// Draw ASCII character.
font_draw_core(disp->vram, disp->font, &fblock);
font_draw_core(disp->vram, disp->font, &fblock, mode);
}

57
src/lib/display/drect.c Normal file
View File

@ -0,0 +1,57 @@
#include <display.h>
void drect(display_t *disp, int x, int y, int width, int height)
{
int vram_offset_y;
int j;
// Check error.
if (width < 0 || height < 0)
return;
// Get "real" X position and area width.
if (x < 0)
{
width = width + x;
x = 0;
} else {
if (x + width >= (int)disp->display.width)
width = disp->display.width - x;
}
// Get "real" Y position and area height.
if (y < 0)
{
height = height + x;
y = 0;
} else {
if (y + height >= (int)disp->display.height)
height = disp->display.height - x;
}
// Check potential error.
// @note we do not check height because the while()
// while do the job for us.
if (width < 0)
return;
// Generate VRAM offset for Y axis.
// @note:
// The screen width size is always 128 and we
// use 4-aligned Video RAM so 32 pixels per "slot"
// and 128 / 32 = 4.
// y * 4 can be optimised by used shift operator,
// this is why we use y << 2 because 2^2 = 4.
vram_offset_y = (y + height - 1) << 2;
// Reverse area
while (--height >= 0)
{
j = width + x;
while (--j >= x)
{
disp->vram[(j >> 5) + vram_offset_y] &= ~(0x80000000 >> (j & 31));
}
vram_offset_y = vram_offset_y - 4;
}
}

View File

@ -13,7 +13,7 @@ int main(void)
int argc;
// Shell main loop.
write(STDOUT_FILENO, "Boot Complete !\n", 16);
printf("Boot Complete !\n");
// Ignore internal signals (keyboard)
//signal(SIGINT, SIG_IGN);
@ -29,12 +29,12 @@ int main(void)
cmd_size = read(STDIN_FILENO, input, 12);
// Check no char
if (cmd_size == 1)
if (cmd_size < 1)
continue;
// Generate argc / argv.
if (strtotab(&argc, &argv, input) != 0) {
printf("parser: internal error\n");
write(STDOUT_FILENO, "\n", 1);
continue;
}

View File

@ -33,7 +33,8 @@ SECTIONS
/* Procedure Linkage Table */
*(.plt)
/* GLobal Offset Table */
/* Global Offset Table */
/* TODO: move me into .data section ? */
*(.got.plt)
*(.got.*)
*(.got)

View File

@ -4,25 +4,48 @@
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
int manual_proc_call(char **argv)
{
char pathname[32];
pid_t child;
char c[1024];
int ret;
int fd;
// Try to open test file
(void)argv;
fd = open("/mnt/casio/VHEX/text.txt", O_RDONLY);
if (fd < 0) {
dprintf(STDERR_FILENO, "unable to open test file\n");
return (84);
}
// Display file
while (1)
{
ret = read(fd, c, 1020);
if (ret <= 0)
break;
write(STDOUT_FILENO, c, ret);
}
return (0);
// char pathname[32];
// pid_t child;
// Generate pathname
// TODO: handle PATH
strcpy(pathname, "/mnt/casio/VHEX/");
strcat(pathname, argv[0]);
//strcpy(pathname, "/mnt/casio/VHEX/");
//strcat(pathname, argv[0]);
// Try to call binary from eeprom
printf("try to call '%s'\n", pathname);
for(int i = 0 ; i < 3000000 ; ++i);
child = fexecve(pathname, argv, NULL);
if (child != 0)
return (-1);
// printf("try to call '%s'\n", pathname);
// for(int i = 0 ; i < 3000000 ; ++i);
// child = fexecve(pathname, argv, NULL);
// if (child != 0)
// return (-1);
// Wait child process
wait_child(child);
return (0);
// wait_child(child);
// return (0);
}

View File

@ -43,9 +43,6 @@ void wait_child(pid_t pid)
// Wait child death
waitpid(pid, &wstatus, 0);
// FIXME: workaround dto display
printf("\n");
// Check exit() return
if (WIFEXITED(wstatus))
{

View File

@ -28,10 +28,13 @@ int main(int argc, char **argv)
break;
write(STDOUT_FILENO, c, ret);
}
printf("test oui:");
// Wait signal
// TODO: better signal management (kernel)
printf("wait signal....\n");
while (read(STDIN_FILENO, c, 3) != 4);
if (argc != 1) {
printf("wait signal....\n");
while (read(STDIN_FILENO, c, 3) != 4);
}
return (0);
}