Commit 7f699021 authored by Léo Grange's avatar Léo Grange

fixed #7 (Merge branch 'tty_input_mode')

parents f5fe475c f50793a8
......@@ -33,6 +33,9 @@ static struct cyclic_fifo _usb_fifo_ep1o = {
// setup callback
usb_setup_callback_t _usb_setup_callback = NULL;
// ep1 receive callback
usb_receive_callback_t _usb_ep1_receive_callback = NULL;
// debug stuff
extern int _magic_lock;
......@@ -172,6 +175,12 @@ int usb_receive(int endpoint, char *data, size_t size, int flags) {
}
void usb_set_receive_callback(int endpoint, usb_receive_callback_t callback) {
if(endpoint == USB_EP_EP1)
_usb_ep1_receive_callback = callback;
}
static void usb_sh3_ep1_read(int nbread) {
(void)nbread; // not used for now
......@@ -354,24 +363,32 @@ void usb_sh3_interrupt_handler() {
int i;
int nbreceived = USB.EPSZ1;
// try to copy received data to ep1 buffer
if(_usb_fifo_ep1o.size + nbreceived <= _usb_fifo_ep1o.max_size) {
// copy in cyclic FIFO need some additionnal things :
int bufpos = (_usb_fifo_ep1o.top + _usb_fifo_ep1o.size) % _usb_fifo_ep1o.max_size;
for(i=0; i<nbreceived; i++, bufpos = bufpos >= _usb_fifo_ep1o.max_size - 1 ? 0 : bufpos+1 ) {
_usb_fifo_ep1o.buffer[bufpos] = USB.EPDR1;
}
_usb_fifo_ep1o.size += nbreceived;
// call the async receive callback?
if(_usb_ep1_receive_callback != NULL) {
for(i=0; i<nbreceived; i++)
_usb_ep1_receive_callback(USB.EPDR1);
USB.TRG.BIT.EP1RDFN = 1;
}
else {
//printk(LOG_DEBUG, "usb: no enougth space for ep1o\n");
// in addition, EP1FULL interrupt is disabled
// the function usb_sh3_ep1_read() is used to signal some part of
// the buffer was read, and maybe EP1FULL can be re-enabled
USB.IER0.BIT.EP1FULL = 0;
// try to copy received data to ep1 buffer
if(_usb_fifo_ep1o.size + nbreceived <= _usb_fifo_ep1o.max_size) {
// copy in cyclic FIFO need some additionnal things :
int bufpos = (_usb_fifo_ep1o.top + _usb_fifo_ep1o.size) % _usb_fifo_ep1o.max_size;
for(i=0; i<nbreceived; i++, bufpos = bufpos >= _usb_fifo_ep1o.max_size - 1 ? 0 : bufpos+1 ) {
_usb_fifo_ep1o.buffer[bufpos] = USB.EPDR1;
}
_usb_fifo_ep1o.size += nbreceived;
USB.TRG.BIT.EP1RDFN = 1;
}
else {
//printk(LOG_DEBUG, "usb: no enougth space for ep1o\n");
// in addition, EP1FULL interrupt is disabled
// the function usb_sh3_ep1_read() is used to signal some part of
// the buffer was read, and maybe EP1FULL can be re-enabled
USB.IER0.BIT.EP1FULL = 0;
}
}
USB.IFR0.BIT.EP1FULL = 0;
......
......@@ -98,6 +98,8 @@ void kdebug_oops(const char *errstr) {
kdebug_print_vmspace(proc);
printk_force_flush();
// print each kernel context information
kdebug_print_trace();
......@@ -113,5 +115,7 @@ void kdebug_oops(const char *errstr) {
cont = cont->previous;
}
printk_force_flush();
while(1);
}
......@@ -9,6 +9,14 @@ size_t disp_mono_height() {
return 64;
}
// TODO find a way to inline these functions AND to keep generic aspect
uint32 disp_mono_get_pixel(int x, int y, void *vram) {
// no check on (x;y) to keep performances...
return !!( ((char*)vram)[y*16 + x/8] & (1 << x%8));
}
void disp_mono_draw_bitmap(int x, int y, unsigned char *bitmap, short w, short h, void *vvram)
{
unsigned char *vram = vvram;
......
#ifndef DISPLAY_T6K11_H
#define DISPLAY_T6K11_H
// real type of vram_t
typedef unsigned char *vram_t;
typedef int color_t;
struct _mono_bitmap {
unsigned char *bitmap;
int w;
int h;
};
typedef struct _mono_bitmap bitmap_t;
// Colors Typedef :
#define PIXEL_WHITE 0
#define PIXEL_BLACK 1
#define PIXEL_XOR 2
// Return 0xFFFFFFFF if it's a dark color, 0x00000000 else
unsigned int mask_color();
#endif //DISPLAY_T6K11_H
......@@ -29,6 +29,11 @@ void disp_mono_copy_to_dd(void *vram);
*/
void disp_mono_set_pixel(int x, int y, uint32 color, void *vram);
/**
* Read a pixel from the VRAM, and return its color.
*/
uint32 disp_mono_get_pixel(int x, int y, void *vram);
/**
* Returns width/height of the display, in pixels.
*/
......
......@@ -104,7 +104,7 @@ int kdb_convert_keymatrix_code(int matrixcode) {
case K_NEG: return KEY_; break;
case K_EXE: return '\n'; break;
case K_AC: return '\x7F'; break;
case K_AC: return ASCII_CTRL('U'); break;
}
}
else if(_kbd_status & KBD_STATE_SHIFT) {
......@@ -167,7 +167,7 @@ int kdb_convert_keymatrix_code(int matrixcode) {
case K_NEG: return KEY_; break;
case K_EXE: return '\n'; break;
case K_AC: return '\x7F'; break;
case K_AC: return ASCII_CTRL('U'); break;
}
}
else {
......@@ -230,7 +230,7 @@ int kdb_convert_keymatrix_code(int matrixcode) {
case K_NEG: return '_'; break;
case K_EXE: return '\n'; break;
case K_AC: return '\x7F'; break;
case K_AC: return ASCII_CTRL('U'); break;
}
}
return -1;
......
......@@ -7,7 +7,8 @@ include device/usb/subdir.mk
C_SRC_L:= \
device_registering.c
device_registering.c \
tty.c
CURDIR:=device
......
......@@ -140,6 +140,18 @@ static const unsigned char _font_3x5[129][5] = {
};
// union used to be sure char_bmp is 4-bytes aligned
union bmp_fast_4x6{
unsigned char char_bmp[6]; // 4*6 bitmap, containing character and borders
unsigned int fast[2]; // for fast operations
};
// used to store/restore a single character area
static union bmp_fast_4x6 _stored_char;
void term_prim_write_character(unsigned int posx, unsigned int posy, int front_c, int back_c, char c, void *vram) {
unsigned int backcolor, frontcolor;
......@@ -152,11 +164,7 @@ void term_prim_write_character(unsigned int posx, unsigned int posy, int front_c
&& (y>-5) && (y<64))
{
const unsigned char *raw_char;
// union used to be sure char_bmp is 4-bytes aligned
union {
unsigned char char_bmp[6]; // 6*4 bitmap, containing character and borders
unsigned int fast[2]; // for fast operations
} bmp;
union bmp_fast_4x6 bmp;
if(c>=0)
raw_char = _font_3x5[(int)c];
......@@ -178,6 +186,33 @@ void term_prim_write_character(unsigned int posx, unsigned int posy, int front_c
}
void term_prim_store_character(unsigned int posx, unsigned int posy,
void *vram)
{
int x = posx * 4;
int y = posy * 6;
int i, j;
// the algorithm used here is... hum... a bit stupid and slow?
for(j=0; j<6; j++) {
char curline = 0x00;
for(i=0; i<4; i++) {
curline |= (disp_mono_get_pixel(x+i, y+j, vram)) << i;
}
_stored_char.char_bmp[j] = curline;
}
}
void term_prim_restore_character(unsigned int posx, unsigned int posy,
void *vram)
{
int x = posx * 4;
int y = posy * 6;
disp_mono_draw_bitmap(x, y, _stored_char.char_bmp, 4, 6, vram);
}
void term_prim_scroll_up(void *vram, int back_c) {
int i;
unsigned int *l_vram = (unsigned int*)vram;
......
......@@ -7,11 +7,25 @@
#define FX9860_TERM_CURSOR_CHAR ((char)177)
/**
* write a character with the terminal font
*/
void term_prim_write_character(unsigned int posx, unsigned int posy, int front_c, int back_c, char c, void *vram);
void term_prim_write_character(unsigned int posx, unsigned int posy,
int front_c, int back_c, char c, void *vram);
/**
* Special set of functions designed for cursor implementation.
* Save/restore the VRAM content of a character location (saved internally
* in a single slot, so each call to term_prim_store_character() destroy the
* previously stored data).
*/
void term_prim_store_character(unsigned int posx, unsigned int posy,
void *vram);
void term_prim_restore_character(unsigned int posx, unsigned int posy,
void *vram);
/**
* Scroll up the terminal display from 1 character high
......
......@@ -15,7 +15,10 @@ const struct text_display fx9860_text_display = {
.scroll = &fx9860_tdisp_scroll,
.set_color = &fx9860_tdisp_set_color,
.set_active = &fx9860_tdisp_set_active,
.flush = &fx9860_tdisp_flush
.flush = &fx9860_tdisp_flush,
.set_cursor_pos = &fx9860_tdisp_set_cursor_pos,
.set_cursor = &fx9860_tdisp_set_cursor
};
......@@ -23,6 +26,10 @@ const struct text_display fx9860_text_display = {
void fx9860_tdisp_init_disp(struct tdisp_data *disp) {
disp->back = 0; //TODO white
disp->front = 1; //TODO black
disp->cursx = 0;
disp->cursy = 0;
disp->cursor = TEXT_CURSOR_NORMAL;
disp->vram = arch_pm_get_free_page(MEM_PM_CACHED);
memset(disp->vram, 0, 1024);
......@@ -68,11 +75,43 @@ void fx9860_tdisp_set_color(struct tdisp_data *disp, enum text_color front,
void fx9860_tdisp_set_active(struct tdisp_data *disp, int active) {
// not a lot of stuff to do here, only update the display after activation
if(active == 1) {
disp_mono_copy_to_dd(disp->vram);
fx9860_tdisp_flush(disp);
}
}
void fx9860_tdisp_flush(struct tdisp_data *disp) {
// here is the little trick for cursor display : we display it only before
// flushing, and remove it juste before (so the VRAM is always "clean")
int cursor_displayed = 0;
if(disp->cursor != TEXT_CURSOR_DISABLE && disp->cursx < FX9860_TERM_WIDTH
&& disp->cursy < FX9860_TERM_HEIGHT)
{
cursor_displayed = 1;
term_prim_store_character(disp->cursx, disp->cursy, disp->vram);
// TODO display other kind of cursors (alpha/shift...)
term_prim_write_character(disp->cursx, disp->cursy,
DISPLAY_COLOR_BLACK, DISPLAY_COLOR_WHITE,
FX9860_TERM_CURSOR_CHAR, disp->vram);
}
disp_mono_copy_to_dd(disp->vram);
if(cursor_displayed)
term_prim_restore_character(disp->cursx, disp->cursy, disp->vram);
}
// cursor related functions are not very useful because of some tricks done
// to display it just before a display flush, but may be useful
void fx9860_tdisp_set_cursor_pos(struct tdisp_data *disp, size_t posx,
size_t posy)
{
disp->cursx = posx;
disp->cursy = posy;
}
void fx9860_tdisp_set_cursor(struct tdisp_data *disp, enum text_cursor curs) {
disp->cursor = curs;
}
......@@ -6,6 +6,12 @@
struct tdisp_data {
int front;
int back;
// data to handle the visual cursor
size_t cursx;
size_t cursy;
enum text_cursor cursor;
unsigned char *vram;
};
......@@ -26,6 +32,10 @@ void fx9860_tdisp_set_active(struct tdisp_data *disp, int active);
void fx9860_tdisp_flush(struct tdisp_data *disp);
void fx9860_tdisp_set_cursor_pos(struct tdisp_data *disp, size_t posx,
size_t posy);
void fx9860_tdisp_set_cursor(struct tdisp_data *disp, enum text_cursor curs);
#endif //_DEVICE_TERMINAL_FX9860_TEXT_DISPLAY_H
......@@ -18,6 +18,12 @@ enum text_color {
TEXT_COLOR_WHITE
};
// possible kind of cursor (will be extended to display shift/alpha modes)
enum text_cursor {
TEXT_CURSOR_DISABLE,
TEXT_CURSOR_NORMAL
};
struct text_display {
size_t cwidth;
size_t cheight;
......@@ -61,6 +67,18 @@ struct text_display {
* Should be call each time we need to be sure the display is up to date.
*/
void (*flush)(struct tdisp_data *disp);
/**
* Set cursor position, if supported.
* Cursor in text_display interface is only a visual hint, it does nothing
* like controlling where characters are displayed!
*/
void (*set_cursor_pos)(struct tdisp_data *disp, size_t posx, size_t posy);
/**
* Set cursor type, if supported.
*/
void (*set_cursor)(struct tdisp_data *disp, enum text_cursor curs);
};
......
#include "virtual_term.h"
#include <utils/cyclic_fifo.h>
#include <fs/file_operations.h>
#include <sys/waitqueue.h>
#include <interface/fixos/errno.h>
#include <sys/tty.h>
#include <sys/process.h>
#include "text_display.h"
#include <sys/stimer.h>
#include <sys/time.h>
#include <device/tty.h>
#include <device/terminal/fx9860/text_display.h>
#include <utils/log.h>
#define VT_INPUT_BUFFER 256
#define VT_LINE_BUFFER 128
// for VT100 escape code handling :
// not in an escape sequence
......@@ -53,15 +50,6 @@ struct vt_instance {
int saved_posx;
int saved_posy;
// for input control :
char fifo_buf[VT_INPUT_BUFFER];
struct cyclic_fifo fifo;
char line_buf[VT_LINE_BUFFER];
int line_pos;
struct wait_queue wqueue;
struct tty tty;
struct vt100_esc_state esc_state;
......@@ -71,27 +59,9 @@ struct vt_instance {
static struct vt_instance _vts[VT_MAX_TERMINALS];
static int _vt_current;
static struct tty *vt_get_tty(uint16 minor);
const struct device virtual_term_device = {
.name = "v-term",
.init = &vt_init,
.open = &vt_open,
.get_tty = &vt_get_tty
};
static const struct file_operations _vt_fop = {
.release = &vt_release,
.write = &vt_write,
.read = &vt_read,
.ioctl = &vt_ioctl
};
static const struct text_display *_tdisp = &fx9860_text_display;
static int vt_ioctl_getwinsize(struct tty *tty, struct winsize *size);
static int vt_ioctl_setwinsize(struct tty *tty, const struct winsize *size);
......@@ -101,16 +71,29 @@ static int vt_tty_is_ready(struct tty *tty) {
return 1;
}
static int vt_tty_putchar(struct tty *tty, char c);
static int vt_tty_write(struct tty *tty, const char *data, size_t len);
static int vt_tty_force_flush(struct tty *tty);
static const struct tty_ops _vt_tty_ops = {
.ioctl_setwinsize = &vt_ioctl_setwinsize,
.ioctl_getwinsize = &vt_ioctl_getwinsize,
.is_ready = &vt_tty_is_ready,
.tty_write = &vt_tty_write
.tty_write = &vt_tty_write,
.putchar = &vt_tty_putchar,
.force_flush = &vt_tty_force_flush
};
// soft timer used to flush the display (VRAM to display)
static void vt_flush_display(void *data);
static int _vt_flush_delayed = 0;
/**
* Clear the given VT escape parser data to get a clean state again.
*/
......@@ -132,51 +115,66 @@ void vt_init() {
for(i=0; i<VT_MAX_TERMINALS; i++) {
_tdisp->init_disp(& _vts[i].disp);
_vts[i].fifo.buffer = _vts[i].fifo_buf;
_vts[i].fifo.max_size = VT_INPUT_BUFFER;
_vts[i].fifo.size = 0;
_vts[i].fifo.top = 0;
_vts[i].line_pos = 0;
_vts[i].posx = 0;
_vts[i].posy = 0;
_vts[i].saved_posx = 0;
_vts[i].saved_posy = 0;
INIT_WAIT_QUEUE(& _vts[i].wqueue);
vt_clear_escape_code(_vts + i);
_vts[i].tty.controler = 0;
_vts[i].tty.fpgid = 0;
// set TTY default settings, and add it to TTY device
tty_default_init(&_vts[i].tty);
_vts[i].tty.private = & _vts[i];
_vts[i].tty.ops = &_vt_tty_ops;
vt_clear_escape_code(_vts + i);
ttydev_set_minor(VT_MINOR_BASE + i, &_vts[i].tty);
}
}
/**
* Soft timer used to display the screen only once per tick if needed.
* This allow minimal drawing without catastrophic counterpart.
*/
static void vt_flush_display(void *data) {
(void)data;
if(_vt_current >= 0 && _vt_current < VT_MAX_TERMINALS) {
_tdisp->flush(& _vts[_vt_current].disp);
}
_vt_flush_delayed = 0;
}
// use a delay of more or less 20 ms after the first call
static void vt_delay_flush() {
if(!_vt_flush_delayed) {
_vt_flush_delayed = 1;
stimer_add(&vt_flush_display, NULL, TICKS_MSEC_NOTNULL(20));
}
}
// direct flush without waiting delayed flushing
static int vt_tty_force_flush(struct tty *tty) {
_tdisp->flush(& ((struct vt_instance*)tty->private)->disp);
return 0;
}
/**
* Move the cursor from its current position to (newx, newy), after checking
* screen boundaries.
* TODO the cursor should be implemented in terminal_disp directly to avoid
* overwriting characters when moving it using VT100 sequences!
*/
static void vt_move_cursor(struct vt_instance *term, int newx, int newy) {
_tdisp->print_char(& term->disp, term->posx, term->posy, ' ');
term->posx = newx > _tdisp->cwidth-1 ? _tdisp->cwidth-1
: (newx < 0 ? 0 : newx);
term->posy = newy > _tdisp->cheight-1 ? _tdisp->cheight-1
: (newy < 0 ? 0 : newy);
// print cursor at current position
_tdisp->print_char(& term->disp, term->posx, term->posy,
VT_CURSOR_CHAR);
_tdisp->set_cursor_pos(& term->disp, term->posx, term->posy);
_tdisp->flush(& term->disp);
vt_delay_flush();
}
/**
......@@ -373,165 +371,118 @@ static void vt_read_escape_code(struct vt_instance *term, char str_char) {
term->esc_state.discovery_state = newstate;
}
/**
* Function used to print characters (as well written to term and echoed input from
* keyboard).
* If mayesc is not-zero, try to check VT100-like escape sequences from source data.
* Echo a character to the screen, without flushing to display driver
*/
static void vt_term_print(struct vt_instance *term, const void *source, size_t len,
int mayesc)
{
int i;
const unsigned char *str = source;
for(i=0; i<len; i++) {
if(!mayesc || (term->esc_state.discovery_state == VT100_STATE_NONE && str[i] != '\x1B')) {
// We aren't in a vt100 escape code
if(str[i] == '\n') {
// remove the current cursor display before line feed
_tdisp->print_char(& term->disp, term->posx, term->posy, ' ');
term->posx = 0;
term->posy++;
}
else if(str[i] == '\r') term->posx=0;
else {
_tdisp->print_char(& term->disp, term->posx, term->posy, str[i]);
term->posx++;
}
if(term->posx >= _tdisp->cwidth) {