Skip to content

Commit

Permalink
added PS/2 mouse support with the new device /dev/psaux #94
Browse files Browse the repository at this point in the history
  • Loading branch information
mikaku committed Sep 25, 2024
1 parent 51ea8e4 commit c4a2854
Show file tree
Hide file tree
Showing 6 changed files with 345 additions and 0 deletions.
3 changes: 3 additions & 0 deletions docs/devices.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ Major | Minor | Device name | Description
6 Parallel printer devices
0 lp0 first parallel printer port

10 Non-serial mice
1 psaux PS/2-style mouse port

29 Universal framebuffer
0 fb0 first framebuffer

Expand Down
3 changes: 3 additions & 0 deletions drivers/char/ps2.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <fiwix/asm.h>
#include <fiwix/kernel.h>
#include <fiwix/config.h>
#include <fiwix/ps2.h>
#include <fiwix/keyboard.h>
#include <fiwix/psaux.h>
Expand Down Expand Up @@ -214,9 +215,11 @@ void ps2_init(void)
if(supp_ports) {
ps2_write(PS2_COMMAND, PS2_CMD_ENABLE_CH1);
keyboard_init();
#ifdef CONFIG_PSAUX
if(supp_ports > 1) {
ps2_write(PS2_COMMAND, PS2_CMD_ENABLE_CH2);
psaux_init();
}
#endif /* CONFIG_PSAUX */
}
}
294 changes: 294 additions & 0 deletions drivers/char/psaux.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
/*
* fiwix/drivers/char/psaux.c
*
* Copyright 2024, Jordi Sanfeliu. All rights reserved.
* Distributed under the terms of the Fiwix License.
*/

#include <fiwix/asm.h>
#include <fiwix/kernel.h>
#include <fiwix/devices.h>
#include <fiwix/fs.h>
#include <fiwix/errno.h>
#include <fiwix/ps2.h>
#include <fiwix/psaux.h>
#include <fiwix/pic.h>
#include <fiwix/irq.h>
#include <fiwix/fcntl.h>
#include <fiwix/sched.h>
#include <fiwix/sleep.h>
#include <fiwix/stdio.h>
#include <fiwix/string.h>

#ifdef CONFIG_PSAUX
static struct fs_operations psaux_driver_fsop = {
0,
0,

psaux_open,
psaux_close,
psaux_read,
psaux_write,
NULL, /* ioctl */
NULL, /* llseek */
NULL, /* readdir */
NULL, /* readdir64 */
NULL, /* mmap */
psaux_select,

NULL, /* readlink */
NULL, /* followlink */
NULL, /* bmap */
NULL, /* lockup */
NULL, /* rmdir */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* mknod */
NULL, /* truncate */
NULL, /* create */
NULL, /* rename */

NULL, /* read_block */
NULL, /* write_block */

NULL, /* read_inode */
NULL, /* write_inode */
NULL, /* ialloc */
NULL, /* ifree */
NULL, /* statfs */
NULL, /* read_superblock */
NULL, /* remount_fs */
NULL, /* write_superblock */
NULL /* release_superblock */
};

static struct device psaux_device = {
"psaux",
PSAUX_MAJOR,
{ 0, 0, 0, 0, 0, 0, 0, 0 },
0,
NULL,
&psaux_driver_fsop,
NULL,
NULL,
NULL
};

struct psaux psaux_table;

static struct interrupt irq_config_psaux = { 0, "psaux", &irq_psaux, NULL };

extern volatile unsigned char ack;
static unsigned char status[3] = { 0, 0, 0};
static unsigned char is_ps2 = 0;
static char id = -1;

static void ps2_command_write(const unsigned char byte)
{
ps2_write(PS2_COMMAND, PS2_CMD_CH2_PREFIX);
ps2_write(PS2_DATA, byte);
if(ps2_wait_ack()) {
printk("WARNING: %s(): ACK not received on %x command!\n", __FUNCTION__, byte);
}
}

static void psaux_identify(void)
{
/* disable */
ps2_command_write(PS2_AUX_DISABLE);

/* status information */
ps2_command_write(PS2_DEV_GETINFO);
status[0] = ps2_read(PS2_DATA); /* status */
status[2] = ps2_read(PS2_DATA); /* resolution */
status[2] = ps2_read(PS2_DATA); /* sample rate */

/* identify */
ps2_command_write(PS2_DEV_RATE);
ps2_command_write(200);
ps2_command_write(PS2_DEV_RATE);
ps2_command_write(100);
ps2_command_write(PS2_DEV_RATE);
ps2_command_write(80);
ps2_command_write(PS2_DEV_IDENTIFY);
id = ps2_read(PS2_DATA);
ps2_clear_buffer();

/* enable */
ps2_command_write(PS2_DEV_ENABLE);
}

void irq_psaux(int num, struct sigcontext *sc)
{
unsigned char ch;

ch = inport_b(PS2_DATA);

/* aux controller said 'acknowledge!' */
if(ch == DEV_ACK) {
ack = 1;
}
if(!psaux_table.count) {
return;
}
charq_putchar(&psaux_table.read_q, ch);
wakeup(&psaux_read);
wakeup(&do_select);
}

int psaux_open(struct inode *i, struct fd *fd_table)
{
int minor;

minor = MINOR(i->rdev);
if(!TEST_MINOR(psaux_device.minors, minor)) {
return -ENXIO;
}
if(psaux_table.count++) {
return 0;
}
memset_b(&psaux_table.read_q, 0, sizeof(struct clist));
memset_b(&psaux_table.write_q, 0, sizeof(struct clist));
return 0;
}

int psaux_close(struct inode *i, struct fd *fdtable)
{
int minor;

minor = MINOR(i->rdev);
if(!TEST_MINOR(psaux_device.minors, minor)) {
return -ENXIO;
}
psaux_table.count--;
return 0;
}

int psaux_read(struct inode *i, struct fd *fdtable, char *buffer, __size_t count)
{
int minor, bytes_read;
unsigned char ch;

minor = MINOR(i->rdev);
if(!TEST_MINOR(psaux_device.minors, minor)) {
return -ENXIO;
}

for(;;) {
if(!psaux_table.read_q.count) {
if(fd_table->flags & O_NONBLOCK) {
return -EAGAIN;
}
if(sleep(&psaux_read, PROC_INTERRUPTIBLE)) {
return -EINTR;
}
continue;
}
break;
}
bytes_read = 0;
while(bytes_read < count) {
if(psaux_table.read_q.count) {
ch = charq_getchar(&psaux_table.read_q);
buffer[bytes_read++] = ch;
continue;
}
break;
}
if(bytes_read) {
i->i_atime = CURRENT_TIME;
}
return bytes_read;
}

int psaux_write(struct inode *i, struct fd *fdtable, const char *buffer, __size_t count)
{
int minor, bytes_written;
unsigned char ch;

minor = MINOR(i->rdev);
if(!TEST_MINOR(psaux_device.minors, minor)) {
return -ENXIO;
}
bytes_written = 0;
while(bytes_written < count) {
ch = buffer[bytes_written++];
ps2_command_write(ch);
}
if(bytes_written) {
i->i_mtime = CURRENT_TIME;
}
return bytes_written;
}

int psaux_select(struct inode *i, int flag)
{
int minor;

minor = MINOR(i->rdev);
if(!TEST_MINOR(psaux_device.minors, minor)) {
return -ENXIO;
}

switch(flag) {
case SEL_R:
if(psaux_table.read_q.count) {
return 1;
}
break;
}
return 0;
}

void psaux_init(void)
{
int errno;

/*add_bh(&psaux_bh);*/
if(!register_irq(PSAUX_IRQ, &irq_config_psaux)) {
enable_irq(PSAUX_IRQ);
}

/* reset device */
ps2_command_write(PS2_DEV_RESET);
if((errno = ps2_read(PS2_DATA)) != DEV_RESET_OK) {
printk("WARNING: %s(): psaux returned 0x%x on reset.\n", __FUNCTION__, errno);
}
if(ps2_read(PS2_DATA) == 0) {
is_ps2 = 1;
}

ps2_clear_buffer();
psaux_identify();
printk("psaux 0x%04x-0x%04x %d", 0x60, 0x64, PSAUX_IRQ);
printk("\ttype=%s", is_ps2 ? "PS/2" : "unknown");
switch(id) {
case -1:
printk(", unknown ID %x", id & 0xFF);
break;
case 0:
printk(", standard mouse");
break;
case 2:
printk(", track ball");
break;
case 3:
printk(", 3-button wheel mouse");
break;
case 4:
printk(", 5-button wheel mouse");
break;
default:
printk(", unknown mouse");
break;
}
printk("\n");
memset_b(&psaux_table, 0, sizeof(struct psaux));
SET_MINOR(psaux_device.minors, 1);
if(register_device(CHR_DEV, &psaux_device)) {
printk("WARNING: %s(): unable to register psaux device.\n", __FUNCTION__);
}
}
#endif /* CONFIG_PSAUX */
1 change: 1 addition & 0 deletions include/fiwix/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#undef CONFIG_MMAP2
#define CONFIG_NET
#define CONFIG_PRINTK64
#define CONFIG_PSAUX


/* configuration options to help debugging */
Expand Down
4 changes: 4 additions & 0 deletions include/fiwix/ps2.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#define PS2_CMD_DISABLE_CH1 0xAD /* disable first channel */
#define PS2_CMD_ENABLE_CH1 0xAE /* enable first channel */
#define PS2_CMD_GET_IFACE 0xCA /* get the current interface */
#define PS2_CMD_CH2_PREFIX 0xD4 /* second channel (mouse) prefix */
#define PS2_CMD_HOTRESET 0xFE /* Hot Reset */

/* device commands */
Expand All @@ -42,11 +43,14 @@
#define PS2_DEV_RATE 0xF3 /* set typematic rate/delay */
#define PS2_DEV_ENABLE 0xF4 /* keyboard enable scanning */
#define PS2_KB_DISABLE 0xF5 /* keyboard disable scanning */
#define PS2_AUX_DISABLE 0xF6 /* mouse disable scanning */
#define PS2_DEV_RESET 0xFF /* device reset */

#define DEV_RESET_OK 0xAA /* self-test passed */
#define DEV_ACK 0xFA /* acknowledge */

#define PS2_TIMEOUT 500000

extern volatile unsigned char ack;

int ps2_wait_ack(void);
Expand Down
40 changes: 40 additions & 0 deletions include/fiwix/psaux.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* fiwix/include/fiwix/psaux.h
*
* Copyright 2024, Jordi Sanfeliu. All rights reserved.
* Distributed under the terms of the Fiwix License.
*/

#ifdef CONFIG_PSAUX

#ifndef _FIWIX_PSAUX_H
#define _FIWIX_PSAUX_H

#include <fiwix/fs.h>
#include <fiwix/charq.h>
#include <fiwix/sigcontext.h>

#define PSAUX_IRQ 12

#define PSAUX_MAJOR 10 /* major number for /dev/psaux */
#define PSAUX_MINORS 1

struct psaux {
int count;
struct clist read_q;
struct clist write_q;
};
extern struct psaux psaux_table;

int psaux_open(struct inode *, struct fd *);
int psaux_close(struct inode *, struct fd *);
int psaux_read(struct inode *, struct fd *, char *, __size_t);
int psaux_write(struct inode *, struct fd *, const char *, __size_t);
int psaux_select(struct inode *, int);

void irq_psaux(int num, struct sigcontext *);
void psaux_init(void);

#endif /* _FIWIX_PSAUX_H */

#endif /* CONFIG_PSAUX */

0 comments on commit c4a2854

Please sign in to comment.