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);
};
......
This diff is collapsed.
......@@ -5,22 +5,21 @@
#include <fs/file.h>
/**
* Virtual terminal device, built on top of text_display interface.
* This device allow to control one or more VT100-like terminals, each of them
* Virtual terminal TTY, built on top of text_display interface.
* This TTY allow to have one or more VT100-like terminals, each of them
* using a private instance of text display and keyboard handling.
*
* Only one (or zero) virtual terminal can be enable at a time.
* Each virtual term is accessible using minor from 0 to (VT_MAX_TERMINALS - 1).
* FIXME for now the keyboard handling use some fx9860-specific functions.
*/
// special characters for cursor
#define VT_CURSOR_CHAR ((char)177)
// first minor number reserver in TTY device, and number of terminals
#define VT_MINOR_BASE 0
#define VT_MAX_TERMINALS 2
extern const struct device virtual_term_device;
// call this function to add the given character as keyboard input
void vt_key_stroke(int code);
......@@ -32,17 +31,11 @@ void vt_key_stroke(int code);
void vt_set_active(int term);
/**
* Initialize virtual terminal subsystem and add each corresponding TTY to
* TTY device.
*/
void vt_init();
int vt_open(uint16 minor, struct file *filep);
int vt_release(struct file *filep);
ssize_t vt_write(struct file *filep, void *source, size_t len);
ssize_t vt_read(struct file *filep, void *dest, size_t len);
int vt_ioctl(struct file *filep, int cmd, void *data);
#endif //_DEVICE_TERMINAL_VIRTUAL_TERM_H
#include <fs/file_operations.h>
#include <fs/file.h>
#include "tty.h"
static struct tty *_ttydev_minors[TTYDEV_MINOR_MAX] = {NULL};
// private definitions
static void ttydev_init();
static int ttydev_open(uint16 minor, struct file *filep);
static int ttydev_release(struct file *filep);
static ssize_t ttydev_write(struct file *filep, void *source, size_t len);
static ssize_t ttydev_read(struct file *filep, void *dest, size_t len);
static int ttydev_ioctl(struct file *filep, int cmd, void *data);
// structs for device and file manipulation
struct device ttydev_device = {
.name = "tty",
.init = &ttydev_init,
.open = &ttydev_open
};
static const struct file_operations _ttydev_fop = {
.release = &ttydev_release,
.write = &ttydev_write,
.read = &ttydev_read,
.ioctl = &ttydev_ioctl
};
struct tty *ttydev_get_minor(uint16 minor) {
return minor < TTYDEV_MINOR_MAX ? _ttydev_minors[minor] : NULL;
}
int ttydev_set_minor(uint16 minor, struct tty *tty) {
if(minor < TTYDEV_MINOR_MAX) {
_ttydev_minors[minor] = tty;
return 0;
}
return -1;
}
static void ttydev_init() {
}
static int ttydev_open(uint16 minor, struct file *filep) {
if(minor < TTYDEV_MINOR_MAX) {
struct tty *tty = _ttydev_minors[minor];
filep->op = &_ttydev_fop;
filep->private_data = tty;
return tty_open(tty);
}
return -ENXIO;
}
static int ttydev_release(struct file *filep) {
tty_release(filep->private_data);
return 0;
}
static ssize_t ttydev_write(struct file *filep, void *source, size_t len) {
return tty_write(filep->private_data, source, len);
}
static ssize_t ttydev_read(struct file *filep, void *dest, size_t len) {
return tty_read(filep->private_data, dest, len);
}
static int ttydev_ioctl(struct file *filep, int cmd, void *data) {
return tty_ioctl(filep->private_data, cmd, data);
}
#ifndef _DEVICE_TTY_H
#define _DEVICE_TTY_H
#include <sys/tty.h>
#include <device/device.h>
/**
* TTY device driver, which centralized each TTY implementation inside a
* single device (each TTY has the same major, and different minors).
* The generic TTY implementation is defined in sys/tty.h
*/
// number of TTY minors handle by the TTY device
#define TTYDEV_MINOR_MAX 10
extern struct device ttydev_device;
/**
* Get/set a TTY from its minor number inside the TTY device.
* ttydev_set_minor() returns non-zero if queried minor is outside
* [0, TTYDEV_MINOR_MAX[ range.
*/
struct tty *ttydev_get_minor(uint16 minor);
int ttydev_set_minor(uint16 minor, struct tty *tty);
#endif //_DEVICE_TTY_H
......@@ -4,114 +4,51 @@
#include <utils/strutils.h>
#include <interface/fixos/errno.h>
#include <sys/tty.h>
static struct tty *acm_get_tty(uint16 minor);
const struct device _acm_usb_device = {
.name = "usb-acm",
.init = acm_usb_init,
.open = acm_usb_open,
.get_tty = acm_get_tty
};
static const struct file_operations _fop_acm_usb = {
.release = acm_usb_release,
.write = acm_usb_write,
.read = acm_usb_read,
.ioctl = acm_usb_ioctl
};
#include <device/tty.h>
static int acm_tty_is_ready(struct tty *tty);
static int acm_tty_write(struct tty *tty, const char *data, size_t len);
static int acm_tty_putchar(struct tty *tty, char c);
static const struct tty_ops _acm_tty_ops = {
.ioctl_setwinsize = NULL,
.ioctl_getwinsize = NULL,
.is_ready = &acm_tty_is_ready,
.tty_write = &acm_tty_write
};
static struct tty _acm_tty = {
.ops = &_acm_tty_ops,
.private = NULL,
.controler = 0,
.fpgid = 0
.tty_write = &acm_tty_write,
.putchar = &acm_tty_putchar
};
static struct tty _acm_tty;
void acm_usb_init() {
cdc_acm_init();
}
int acm_usb_open(uint16 minor, struct file *filep) {
if(minor == ACM_DEVICE_MINOR) {
filep->op = &_fop_acm_usb;
return 0;
}
return -ENXIO;
}
static struct tty *acm_get_tty(uint16 minor) {
if(minor == ACM_DEVICE_MINOR) {
return &_acm_tty;
}
return NULL;
}
int acm_usb_release(struct file *filep) {
// callback used to do TTY job for each input character
static int acm_input_char(char c) {
tty_input_char(&_acm_tty, c);
return 0;
}
void acm_usb_init() {
tty_default_init(&_acm_tty);
_acm_tty.ops = &_acm_tty_ops;
_acm_tty.private = NULL;
ssize_t acm_usb_write(struct file *filep, void *source, size_t len) {
if(cdc_acm_is_ready()) {
return cdc_acm_send(source, len);
}
return -EIO;
}
ssize_t acm_usb_read(struct file *filep, void *dest, size_t len) {
if(cdc_acm_is_ready()) {
return cdc_acm_receive(dest, len);
}
return -EIO;
}
cdc_acm_init();
cdc_acm_set_receive_callback(&acm_input_char);
int acm_usb_ioctl(struct file *filep, int cmd, void *data) {
int ret;
ret = tty_ioctl(&_acm_tty, cmd, data);
if(ret == -EFAULT) {
// device-level ioctl command, if any
return -EINVAL;
}
else {
return ret;
}
// add the CDC/ACM TTY to the TTY device
ttydev_set_minor(ACM_USB_TTY_MINOR, &_acm_tty);
}
static int acm_tty_is_ready(struct tty *tty) {
(void)tty;
return cdc_acm_is_ready();
}
static int acm_tty_write(struct tty *tty, const char *data, size_t len) {
(void)tty;
if(cdc_acm_is_ready()) {
......@@ -119,3 +56,9 @@ static int acm_tty_write(struct tty *tty, const char *data, size_t len) {
}
return -EIO;
}
static int acm_tty_putchar(struct tty *tty, char c) {
acm_tty_write(tty, &c, 1);
return 0;
}
......@@ -11,20 +11,8 @@
#include <fs/file.h>
#define ACM_DEVICE_MINOR 0
extern const struct device _acm_usb_device;
#define ACM_USB_TTY_MINOR 6
void acm_usb_init();
int acm_usb_open(uint16 minor, struct file *filep);
int acm_usb_release(struct file *filep);
ssize_t acm_usb_write(struct file *filep, void *source, size_t len);
ssize_t acm_usb_read(struct file *filep, void *dest, size_t len);
int acm_usb_ioctl(struct file *filep, int cmd, void *data);
#endif //_DEVICE_USB_CDC_ACM_ACM_DEVICE_H
......@@ -157,9 +157,6 @@ static struct usb_endpoint_ability _cdc_enpoints[3] = {
};