fix: handle the strange scan code sequence on Virtualbox's PS/2 keyboard.
fix: incompatible pointer type passing in devfs.
chore: refactoring and clean up.
正常,**因为Bochs不支持SATA**。请使用QEMU或VirtualBox。
-#### 问题#4:键盘的上下方向键(用于滚屏)在VirtualBox下有时不好使
-
-可以试试`Shift+<方向键>`,这个问题的解决需要重写键盘驱动的状态机。我会找时间去做,毕竟这不是燃眉之急。
-
## 参考教程
**没有!!** 本教程以及该操作系统均为原创,没有基于任何市面上现行的操作系统开发教程,且并非是基于任何的开源内核的二次开发。
device_getbyid(struct llist_header* devlist, dev_t id);
struct device*
-device_getbyhname(struct llist_header* devlist, struct hstr* name);
+device_getbyhname(struct device* root_dev, struct hstr* name);
struct device*
-device_getbyname(struct llist_header* devlist, const char* name, size_t len);
+device_getbyname(struct device* root_dev, const char* name, size_t len);
struct device*
-device_getbyoffset(struct llist_header* devlist, int pos);
+device_getbyoffset(struct device* root_dev, int pos);
#endif /* __LUNAIX_DEVICE_H */
size_t
fifo_putone(struct fifo_buf* fbuf, uint8_t data);
+size_t
+fifo_readone_async(struct fifo_buf* fbuf, uint8_t* data);
+
+void
+fifo_set_rdptr(struct fifo_buf* fbuf, size_t rdptr);
+
+void
+fifo_set_wrptr(struct fifo_buf* fbuf, size_t wrptr);
+
void
fifo_init(struct fifo_buf* buf, void* data_buffer, size_t buf_size, int flags);
struct lx_timer* flush_timer;
struct fifo_buf output;
struct fifo_buf input;
- unsigned int erd_pos;
- unsigned int lines;
+ size_t wnd_start;
+ size_t lines;
};
#endif /* __LUNAIX_CONSOLE_H */
#ifndef __LUNAIX_TTY_H
#define __LUNAIX_TTY_H
+
+#include <lunaix/ds/fifo.h>
+
typedef unsigned short vga_attribute;
#define VGA_COLOR_BLACK 0
vga_attribute
tty_get_theme();
-size_t
-tty_flush_buffer(char* data, size_t pos, size_t limit, size_t buf_size);
+void
+tty_flush_buffer(struct fifo_buf* buf);
void
tty_clear_line(int line_num);
#include <lunaix/foptions.h>
#include <lunaix/input.h>
#include <lunaix/lunistd.h>
+#include <lunaix/proc.h>
#include <ulibc/stdio.h>
#define STDIN 1
int fd = open("/dev/input/i8042-kbd", 0);
if (fd < 0) {
- printf("fail to open (%d)", fd);
+ printf("fail to open (%d)", geterrno());
return;
}
action = "release";
}
- printf("%u: %s '%c', class=0x%x, scan=%d\n",
+ printf("%u: %s '%c', class=0x%x, scan=%x\n",
event.timestamp,
action,
event.sys_code & 0xff,
char buf[512];
char *cmd, *argpart;
+ printf("\n Simple shell. Use <PG_UP> or <PG_DOWN> to scroll.\n\n");
+
while (1) {
getcwd(pwd, 512);
- printf("%s> ", pwd);
+ printf("%s$ ", pwd);
size_t sz = read(stdin, buf, 512);
if (sz < 0) {
printf("fail to read user input (%d)\n", geterrno());
}
buf[sz - 1] = '\0';
parse_cmdline(buf, &cmd, &argpart);
+ if (cmd[0] == 0) {
+ goto cont;
+ }
if (streq(cmd, "cd")) {
if (chdir(argpart) < 0) {
sh_printerr();
} else {
printf("unknow command");
}
+ cont:
printf("\n");
}
}
\ No newline at end of file
int
devfs_dirlookup(struct v_inode* this, struct v_dnode* dnode)
{
- struct device* dev = device_getbyhname(this->data, &dnode->name);
+ struct device* dev =
+ device_getbyhname((struct device*)this->data, &dnode->name);
if (!dev) {
return ENOENT;
}
int
devfs_readdir(struct v_file* file, struct dir_context* dctx)
{
- struct device* holder = (struct device*)(file->inode->data);
struct device* dev =
- device_getbyoffset(holder ? &holder->children : NULL, dctx->index);
+ device_getbyoffset((struct device*)(file->inode->data), dctx->index);
if (!dev) {
return 0;
}
}
struct device*
-device_getbyhname(struct llist_header* devlist, struct hstr* name)
+device_getbyhname(struct device* root_dev, struct hstr* name)
{
- devlist = devlist ? devlist : &root_list;
+ struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
struct device *pos, *n;
llist_for_each(pos, n, devlist, siblings)
{
}
struct device*
-device_getbyname(struct llist_header* devlist, const char* name, size_t len)
+device_getbyname(struct device* root_dev, const char* name, size_t len)
{
struct hstr hname = HSTR(name, len);
hstr_rehash(&hname, HSTR_FULL_HASH);
- return device_getbyhname(devlist, &hname);
+ return device_getbyhname(root_dev, &hname);
}
void
}
struct device*
-device_getbyoffset(struct llist_header* devlist, int offset)
+device_getbyoffset(struct device* root_dev, int offset)
{
- devlist = devlist ? devlist : &root_list;
+ struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
struct device *pos, *n;
int off = 0;
llist_for_each(pos, n, devlist, siblings)
return 1;
}
+size_t
+fifo_readone_async(struct fifo_buf* fbuf, uint8_t* data)
+{
+ if (fbuf->free_len == fbuf->size) {
+ return 0;
+ }
+
+ uint8_t* dest = fbuf->data;
+ *data = dest[fbuf->rd_pos];
+ fbuf->rd_pos = (fbuf->rd_pos + 1) % fbuf->size;
+ fbuf->free_len++;
+
+ return 1;
+}
+
+void
+fifo_set_rdptr(struct fifo_buf* fbuf, size_t rdptr)
+{
+ fbuf->rd_pos = rdptr;
+ if (rdptr <= fbuf->wr_pos) {
+ fbuf->free_len = fbuf->size - fbuf->wr_pos + rdptr;
+ } else {
+ fbuf->free_len = rdptr - fbuf->wr_pos;
+ }
+}
+
+void
+fifo_set_wrptr(struct fifo_buf* fbuf, size_t wrptr)
+{
+ fbuf->wr_pos = wrptr;
+ if (wrptr <= fbuf->rd_pos) {
+ fbuf->free_len = fbuf->size - fbuf->rd_pos + wrptr;
+ } else {
+ fbuf->free_len = wrptr - fbuf->rd_pos;
+ }
+}
+
size_t
fifo_write(struct fifo_buf* fbuf, void* data, size_t count)
{
#define KBD_STATE_KWAIT 0x00
#define KBD_STATE_KSPECIAL 0x01
#define KBD_STATE_KRELEASED 0x02
+#define KBD_STATE_E012 0x03
+#define KBD_STATE_KRELEASED_E0 0x04
#define KBD_STATE_CMDPROCS 0x40
-#define KBD_ENABLE_SPIRQ_FIX
+// #define KBD_ENABLE_SPIRQ_FIX
+#define KBD_ENABLE_SPIRQ_FIX2
// #define KBD_DBGLOG
void
}
#endif
+#ifdef KBD_ENABLE_SPIRQ_FIX2
+ if (scancode == PS2_RESULT_ACK || scancode == PS2_RESULT_NAK) {
+ return;
+ }
+#endif
+
#ifdef KBD_DBGLOG
kprintf(KDEBUG "%x\n", scancode & 0xff);
#endif
}
break;
case KBD_STATE_KSPECIAL:
- if (scancode == 0xf0) { // release code
- kbd_state.state = KBD_STATE_KRELEASED;
+ if (scancode == 0x12) {
+ kbd_state.state = KBD_STATE_E012;
+ } else if (scancode == 0xf0) { // release code
+ kbd_state.state = KBD_STATE_KRELEASED_E0;
} else {
key = kbd_state.translation_table[scancode];
kbd_buffer_key_event(key, scancode, KBD_KEY_FPRESSED);
kbd_state.translation_table = scancode_set2;
}
break;
+ // handle the '0xE0, 0x12, 0xE0, xx' sequence
+ case KBD_STATE_E012:
+ if (scancode == 0xe0) {
+ kbd_state.state = KBD_STATE_KSPECIAL;
+ kbd_state.translation_table = scancode_set2_ex;
+ }
+ break;
+ case KBD_STATE_KRELEASED_E0:
+ if (scancode == 0x12) {
+ goto escape_release;
+ }
+ // fall through
case KBD_STATE_KRELEASED:
key = kbd_state.translation_table[scancode];
kbd_buffer_key_event(key, scancode, KBD_KEY_FRELEASED);
+ escape_release:
// reset the translation table to scancode_set2
kbd_state.state = KBD_STATE_KWAIT;
kbd_state.translation_table = scancode_set2;
uint32_t keycode = dev->current_pkt.sys_code;
uint32_t type = dev->current_pkt.pkt_type;
if (type == PKT_PRESS) {
- if (keycode == KEY_UP) {
+ if (keycode == KEY_PG_UP) {
console_view_up();
- } else if (keycode == KEY_DOWN) {
+ } else if (keycode == KEY_PG_DOWN) {
console_view_down();
}
goto done;
lxconsole_init()
{
memset(&lx_console, 0, sizeof(lx_console));
- fifo_init(&lx_console.output, vzalloc(8192), 8192, 0);
+ fifo_init(&lx_console.output, valloc(8192), 8192, 0);
fifo_init(&lx_console.input, valloc(4096), 4096, 0);
lx_console.flush_timer = NULL;
// TODO make the flush on-demand rather than periodic
}
-void
-console_view_up()
+size_t
+__find_next_line(size_t start)
{
+ size_t p = start - 1;
struct fifo_buf* buffer = &lx_console.output;
- mutex_lock(&buffer->lock);
- size_t p = lx_console.erd_pos - 2;
- while (p < lx_console.erd_pos && p != buffer->wr_pos &&
- ((char*)buffer->data)[p] != '\n') {
+ do {
+ p = (p + 1) % buffer->size;
+ } while (p != buffer->wr_pos && ((char*)buffer->data)[p] != '\n');
+ return p + (((char*)buffer->data)[p] == '\n');
+}
+
+size_t
+__find_prev_line(size_t start)
+{
+ size_t p = start - 1;
+ struct fifo_buf* buffer = &lx_console.output;
+ do {
p--;
- }
- p++;
+ } while (p < lx_console.wnd_start && p != buffer->wr_pos &&
+ ((char*)buffer->data)[p] != '\n');
- if (p > lx_console.erd_pos) {
- p = 0;
+ if (p > lx_console.wnd_start) {
+ return 0;
}
+ return p + 1;
+}
+void
+console_view_up()
+{
+ struct fifo_buf* buffer = &lx_console.output;
+ mutex_lock(&buffer->lock);
+ fifo_set_rdptr(buffer, __find_prev_line(buffer->rd_pos));
buffer->flags |= FIFO_DIRTY;
- lx_console.erd_pos = p;
mutex_unlock(&buffer->lock);
-}
-size_t
-__find_next_line(size_t start)
-{
- size_t p = start;
- while (p != lx_console.output.wr_pos &&
- ((char*)lx_console.output.data)[p] != '\n') {
- p = (p + 1) % lx_console.output.size;
- }
- return p + 1;
+ console_flush();
}
void
struct fifo_buf* buffer = &lx_console.output;
mutex_lock(&buffer->lock);
- lx_console.erd_pos = __find_next_line(lx_console.erd_pos);
+ size_t wnd = lx_console.wnd_start;
+ size_t p = __find_next_line(buffer->rd_pos);
+ fifo_set_rdptr(buffer, p > wnd ? wnd : p);
buffer->flags |= FIFO_DIRTY;
mutex_unlock(&buffer->lock);
+
+ console_flush();
}
void
return;
}
- tty_flush_buffer(lx_console.output.data,
- lx_console.erd_pos,
- lx_console.output.wr_pos,
- lx_console.output.size);
+ size_t rdpos_save = lx_console.output.rd_pos;
+ tty_flush_buffer(&lx_console.output);
+ fifo_set_rdptr(&lx_console.output, rdpos_save);
+
lx_console.output.flags &= ~FIFO_DIRTY;
}
void
console_write(struct console* console, uint8_t* data, size_t size)
{
+ struct fifo_buf* fbuf = &console->output;
mutex_lock(&console->output.lock);
- uint8_t* buffer = console->output.data;
- uintptr_t ptr = console->output.wr_pos;
- uintptr_t rd_ptr = console->output.rd_pos;
+ fifo_set_rdptr(fbuf, console->wnd_start);
+
+ uint8_t* buffer = fbuf->data;
+ uintptr_t ptr = fbuf->wr_pos;
+ uintptr_t rd_ptr = fbuf->rd_pos;
char c;
- int lines = 0;
int j = 0;
for (size_t i = 0; i < size; i++) {
c = data[i];
if (!c) {
continue;
}
- buffer[(ptr + j) % console->output.size] = c;
- lines += (c == '\n');
+ if (c == '\n') {
+ console->lines++;
+ }
+ buffer[(ptr + j) % fbuf->size] = c;
j++;
}
- size = j;
-
- uintptr_t new_ptr = (ptr + size) % console->output.size;
- console->output.wr_pos = new_ptr;
-
- if (console->lines > TTY_HEIGHT && lines > 0) {
- console->output.rd_pos =
- __find_next_line((size + rd_ptr) % console->output.size);
- }
+ fifo_set_wrptr(fbuf, (ptr + j) % fbuf->size);
- if (new_ptr < ptr + size && new_ptr > rd_ptr) {
- console->output.rd_pos = new_ptr;
+ while (console->lines >= TTY_HEIGHT) {
+ rd_ptr = __find_next_line(rd_ptr);
+ console->lines--;
}
- console->lines += lines;
- console->erd_pos = console->output.rd_pos;
- console->output.flags |= FIFO_DIRTY;
- mutex_unlock(&console->output.lock);
+ fifo_set_rdptr(&lx_console.output, rd_ptr);
+ console->wnd_start = rd_ptr;
+ fbuf->flags |= FIFO_DIRTY;
+ mutex_unlock(&fbuf->lock);
}
void
vga_attribute tty_theme_color = VGA_COLOR_BLACK;
-#define TTY_CLEAR \
- asm volatile("rep stosw" ::"D"(tty_vga_buffer), \
- "c"(TTY_HEIGHT * TTY_WIDTH), \
- "a"(tty_theme_color) \
+inline void
+tty_clear()
+{
+ asm volatile("rep stosw" ::"D"(tty_vga_buffer),
+ "c"(TTY_HEIGHT * TTY_WIDTH),
+ "a"(tty_theme_color)
: "memory");
+}
void
tty_init(void* vga_buf)
{
tty_vga_buffer = (vga_attribute*)vga_buf;
- TTY_CLEAR
+ tty_clear();
io_outb(0x3D4, 0x0A);
io_outb(0x3D5, (io_inb(0x3D5) & 0xC0) | 13);
tty_theme_color = (bg << 4 | fg) << 8;
}
-size_t
-tty_flush_buffer(char* data, size_t pos, size_t limit, size_t buf_size)
+void
+tty_flush_buffer(struct fifo_buf* buf)
{
int x = 0, y = 0;
// Clear screen
- TTY_CLEAR
+ tty_clear();
+ char chr;
int state = 0;
int g[2] = { 0, 0 };
vga_attribute current_theme = tty_theme_color;
- while (1) {
- size_t ptr = pos % buf_size;
- if (pos == limit) {
- break;
- }
- char chr = data[pos];
+ while (fifo_readone_async(buf, &chr)) {
if (state == 0 && chr == '\033') {
state = 1;
} else if (state == 1 && chr == '[') {
break;
}
}
- pos++;
}
tty_set_cursor(x, y);
- return pos;
}
void