ホイールマウス

PS/2マウスは特別な初期化をすることでホイール対応にすることができます。

以下参考にしたリンクです。

マウスの初期化部分とマウスデータのデコード部分を以下のように書き換えます。サンプリングレートを200, 100, 80 の順に設定するのが、ホイール初期化パスワードのようです。

ちなみに QEMU ではホイールマウスは有効になりませんでしたが、VMWare Player では無事有効になりました。ホイールで遊ぶためには、VMWare Player か実機が必要です。

bootpack.h

/* mouse.c */
struct MOUSE_DEC {
    unsigned char buf[4], phase;
    int x, y, btn, scroll, scrollmode;
};

mouse.c

void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec)
{
    int result, i;
    static unsigned char cmd[7] = {
        0xF3, /* サンプリングレート設定 */
        0xC8, /* 200 */
        0xF3, /* サンプリングレート設定 */
        0x64, /* 100 */
        0xF3, /* サンプリングレート設定 */
        0x50, /* 80 */
        0xF2  /* デバイスタイプ取得 */
    };

    /* 書き込み先のFIFOバッファを記憶 */
    mousefifo = fifo;
    mousedata0 = data0;

    /* ホイールマウス初期化 */
    for (i = 0; i < 7; i++) {
        wait_KBC_sendready();
        io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
        wait_KBC_sendready();
        io_out8(PORT_KEYDAT, cmd[i]);
    }

    /* デバイスタイプ取得 */
    io_cli();
    for (i = 0; i < 8; i++) {
        result = io_in8(PORT_KEYDAT);
    }
    io_sti();

    /* ホイールが有効かどうかチェック */
    if (result == 0x03) {
        mdec->scrollmode = 1;
    } else {
        mdec->scrollmode = 0;
    }

    /* マウス有効 */
    wait_KBC_sendready();
    io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
    wait_KBC_sendready();
    io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);
    /* うまくいくとACK(0xfa)が送信されてくる */
    mdec->phase = 0; /* マウスの0xfaを待っている段階 */
    return;
}

int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat)
{
    if (mdec->phase == 0) {
        /* マウスの0xfaを待っている段階 */
        if (dat == 0xfa) {
            mdec->phase = 1;
        }
        return 0;
    }
    if (mdec->phase == 1) {
        /* マウスの1バイト目を待っている段階 */
        if ((dat & 0xc8) == 0x08) {
            /* 正しい1バイト目だった */
            mdec->buf[0] = dat;
            mdec->phase = 2;
        }
        return 0;
    }
    if (mdec->phase == 2) {
        /* マウスの2バイト目を待っている段階 */
        mdec->buf[1] = dat;
        mdec->phase = 3;
        return 0;
    }
    if (mdec->phase == 3) {
        /* マウスの3バイト目を待っている段階 */
        mdec->buf[2] = dat;
        if (mdec->scrollmode != 0) {
            mdec->phase = 4;
        } else {
            mdec->phase = 1;
        }
        mdec->btn = mdec->buf[0] & 0x07;
        mdec->x = mdec->buf[1];
        mdec->y = mdec->buf[2];
        if ((mdec->buf[0] & 0x10) != 0) {
            mdec->x |= 0xffffff00;
        }
        if ((mdec->buf[0] & 0x20) != 0) {
            mdec->y |= 0xffffff00;
        }
        mdec->y = - mdec->y; /* マウスではy方向の符号が画面と反対 */
        if (mdec->scrollmode != 0) {
            return 0;
        } else {
            return 1;
        }
    }
    if (mdec->phase == 4) {
        /* マウスの4バイト目を待っている段階 */
        mdec->buf[3] = dat;
        /* スクロール対応マウスのみスクロール */
        mdec->phase  = 1;
        /* mdec.buf[3]は、下位4ビットだけが有効な値である */
        /* とりあえず解析せずに値をしまう */
        mdec->scroll = mdec->buf[3] & 0x0f;
        if (mdec->scroll & 0x08) {
            /* マイナスの値だった */
            mdec->scroll |= 0xfffffff0;
        }
        return 1;
    }
    return -1; /* ここに来ることはないはず */
}