Changeset c637571 in mainline for uspace/drv/char/ps2mouse/ps2mouse.c


Ignore:
Timestamp:
2011-12-31T15:05:32Z (13 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
c322fd6
Parents:
db9ef0c
Message:

ps2mouse: Add support for IntelliMouse wheel extension.

Tested on qemu and VirtualBox.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/char/ps2mouse/ps2mouse.c

    rdb9ef0c rc637571  
    4545#include "ps2mouse.h"
    4646
    47 #define PS2_MOUSE_OUT_INIT  0xf4
    48 #define PS2_MOUSE_ACK       0xfa
    49 
    50 #define BUFSIZE 3
    51 
     47#define PS2_MOUSE_GET_DEVICE_ID   0xf2
     48#define PS2_MOUSE_SET_SAMPLE_RATE   0xf3
     49#define PS2_MOUSE_ENABLE_DATA_REPORT   0xf4
     50#define PS2_MOUSE_ACK   0xfa
     51
     52#define PS2_BUFSIZE 3
     53#define INTELLIMOUSE_BUFSIZE 4
     54
     55#define Z_SIGN (1 << 3)
    5256#define X_SIGN (1 << 4)
    5357#define Y_SIGN (1 << 5)
     
    5862#define BUTTON_RIGHT   1
    5963#define BUTTON_MIDDLE   2
    60 #define BUTTON_COUNT   3
    61 
    62 #define BUTTON_MASK(button) (1 << button)
    63 
     64#define PS2_BUTTON_COUNT   3
     65#define INTELLIMOUSE_BUTTON_COUNT 5
     66
     67#define PS2_BUTTON_MASK(button) (1 << button)
     68
     69#define MOUSE_READ_BYTE_TEST(sess, value) \
     70do { \
     71        uint8_t data = 0; \
     72        const ssize_t size = char_dev_read(session, &data, 1); \
     73        if (size != 1) { \
     74                ddf_msg(LVL_ERROR, "Failed reading byte: %d)", size);\
     75                return size < 0 ? size : EIO; \
     76        } \
     77        if (data != value) { \
     78                ddf_msg(LVL_ERROR, "Failed testing byte: got %hhx vs. %hhx)", \
     79                    data, value); \
     80                return EIO; \
     81        } \
     82} while (0)
     83#define MOUSE_WRITE_BYTE(sess, value) \
     84do { \
     85        uint8_t data = value; \
     86        const ssize_t size = char_dev_write(session, &data, 1); \
     87        if (size < 0 ) { \
     88                ddf_msg(LVL_ERROR, "Failed writing byte: %hhx", value); \
     89                return size; \
     90        } \
     91} while (0)
    6492/*----------------------------------------------------------------------------*/
    6593static int polling_ps2(void *);
     94static int polling_intellimouse(void *);
     95static int probe_intellimouse(async_sess_t *);
    6696static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
    6797/*----------------------------------------------------------------------------*/
     
    111141                return ENOMEM;
    112142        }
     143        /* Probe IntelliMouse extensions. */
     144        int (*polling_f)(void*) = polling_ps2;
     145        if (probe_intellimouse(mouse->parent_sess) == EOK) {
     146                ddf_msg(LVL_NOTE, "Enabled IntelliMouse extensions");
     147                polling_f = polling_intellimouse;
     148        }
    113149        /* Enable mouse data reporting. */
    114         uint8_t report = PS2_MOUSE_OUT_INIT;
     150        uint8_t report = PS2_MOUSE_ENABLE_DATA_REPORT;
    115151        ssize_t size = char_dev_write(mouse->parent_sess, &report, 1);
    116152        if (size != 1) {
    117                 ddf_msg(LVL_ERROR, "Failed to write INIT.");
     153                ddf_msg(LVL_ERROR, "Failed to enable data reporting.");
    118154                async_hangup(mouse->parent_sess);
    119155                ddf_fun_unbind(mouse->mouse_fun);
     
    125161        size = char_dev_read(mouse->parent_sess, &report, 1);
    126162        if (size != 1 || report != PS2_MOUSE_ACK) {
    127                 ddf_msg(LVL_ERROR, "MOUSE FAILED TO ACK %hhx.", report);
     163                ddf_msg(LVL_ERROR, "Failed to confirm data reporting: %hhx.",
     164                    report);
    128165                async_hangup(mouse->parent_sess);
    129166                ddf_fun_unbind(mouse->mouse_fun);
     
    133170        }
    134171
    135         mouse->polling_fibril = fibril_create(polling_ps2, mouse);
     172        mouse->polling_fibril = fibril_create(polling_f, mouse);
    136173        if (!mouse->polling_fibril) {
    137174                async_hangup(mouse->parent_sess);
     
    155192
    156193        assert(mouse->parent_sess);
    157         bool buttons[BUTTON_COUNT] = {};
     194        bool buttons[PS2_BUTTON_COUNT] = {};
    158195        while (1) {
    159196
    160                 uint8_t packet[BUFSIZE] = {};
     197                uint8_t packet[PS2_BUFSIZE] = {};
    161198                const ssize_t size =
    162                     char_dev_read(mouse->parent_sess, packet, BUFSIZE);
    163 
    164                 if (size != 3) {
     199                    char_dev_read(mouse->parent_sess, packet, PS2_BUFSIZE);
     200
     201                if (size != PS2_BUFSIZE) {
    165202                        ddf_msg(LVL_WARN, "Incorrect packet size: %zd.", size);
    166203                        continue;
     
    178215
    179216                /* Buttons */
    180                 for (unsigned i = 0; i < BUTTON_COUNT; ++i) {
    181                         if (buttons[i] != (bool)(packet[0] & BUTTON_MASK(i))) {
    182                                 buttons[i] = !buttons[i];
     217                for (unsigned i = 0; i < PS2_BUTTON_COUNT; ++i) {
     218                        const bool status = (packet[0] & PS2_BUTTON_MASK(i));
     219                        if (buttons[i] != status) {
     220                                buttons[i] = status;
    183221                                async_msg_2(exch, MOUSEEV_BUTTON_EVENT, i + 1,
    184222                                    buttons[i]);
     
    197235                async_exchange_end(exch);
    198236        }
     237}
     238/*----------------------------------------------------------------------------*/
     239/** Get data and parse ps2 protocol with intellimouse extension packets.
     240 * @param arg Pointer to ps2_mouse_t structure.
     241 * @return Never.
     242 */
     243static int polling_intellimouse(void *arg)
     244{
     245        assert(arg);
     246        const ps2_mouse_t *mouse = arg;
     247
     248        assert(mouse->parent_sess);
     249        bool buttons[INTELLIMOUSE_BUTTON_COUNT] = {};
     250        while (1) {
     251
     252                uint8_t packet[INTELLIMOUSE_BUFSIZE] = {};
     253                const ssize_t size = char_dev_read(
     254                    mouse->parent_sess, packet, INTELLIMOUSE_BUFSIZE);
     255
     256                if (size != INTELLIMOUSE_BUFSIZE) {
     257                        ddf_msg(LVL_WARN, "Incorrect packet size: %zd.", size);
     258                        continue;
     259                }
     260                ddf_msg(LVL_DEBUG2, "Got packet: %hhx:%hhx:%hhx:%hhx.",
     261                    packet[0], packet[1], packet[2], packet[3]);
     262
     263                async_exch_t *exch =
     264                    async_exchange_begin(mouse->input_sess);
     265                if (!exch) {
     266                        ddf_msg(LVL_ERROR,
     267                            "Failed to create input exchange.");
     268                        continue;
     269                }
     270                /* ps/2 Buttons */
     271                for (unsigned i = 0; i < PS2_BUTTON_COUNT; ++i) {
     272                        const bool status = (packet[0] & PS2_BUTTON_MASK(i));
     273                        if (buttons[i] != status) {
     274                                buttons[i] = status;
     275                                async_msg_2(exch, MOUSEEV_BUTTON_EVENT, i + 1,
     276                                    buttons[i]);
     277                        }
     278                }
     279
     280                /* Movement */
     281                const int16_t move_x =
     282                    ((packet[0] & X_SIGN) ? 0xff00 : 0) | packet[1];
     283                const int16_t move_y =
     284                    (((packet[0] & Y_SIGN) ? 0xff00 : 0) | packet[2]);
     285                const int8_t move_z =
     286                    (((packet[3] & Z_SIGN) ? 0xf0 : 0) | (packet[3] & 0xf));
     287                ddf_msg(LVL_DEBUG2, "Parsed moves: %d:%d:%hhd", move_x, move_y,
     288                    move_z);
     289                //TODO: Consider overflow bit
     290                if (move_x != 0 || move_y != 0 || move_z != 0) {
     291                        async_msg_3(exch, MOUSEEV_MOVE_EVENT,
     292                            move_x, -move_y, -move_z);
     293                }
     294                async_exchange_end(exch);
     295        }
     296}
     297/*----------------------------------------------------------------------------*/
     298static int probe_intellimouse(async_sess_t *session)
     299{
     300        assert(session);
     301
     302        MOUSE_WRITE_BYTE(session, PS2_MOUSE_SET_SAMPLE_RATE);
     303        MOUSE_READ_BYTE_TEST(session, PS2_MOUSE_ACK);
     304        MOUSE_WRITE_BYTE(session, 200);
     305        MOUSE_READ_BYTE_TEST(session, PS2_MOUSE_ACK);
     306
     307        MOUSE_WRITE_BYTE(session, PS2_MOUSE_SET_SAMPLE_RATE);
     308        MOUSE_READ_BYTE_TEST(session, PS2_MOUSE_ACK);
     309        MOUSE_WRITE_BYTE(session, 100);
     310        MOUSE_READ_BYTE_TEST(session, PS2_MOUSE_ACK);
     311
     312        MOUSE_WRITE_BYTE(session, PS2_MOUSE_SET_SAMPLE_RATE);
     313        MOUSE_READ_BYTE_TEST(session, PS2_MOUSE_ACK);
     314        MOUSE_WRITE_BYTE(session, 80);
     315        MOUSE_READ_BYTE_TEST(session, PS2_MOUSE_ACK);
     316
     317        MOUSE_WRITE_BYTE(session, PS2_MOUSE_GET_DEVICE_ID);
     318        MOUSE_READ_BYTE_TEST(session, PS2_MOUSE_ACK);
     319        MOUSE_READ_BYTE_TEST(session, 3);
     320
     321        return EOK;
    199322}
    200323/*----------------------------------------------------------------------------*/
Note: See TracChangeset for help on using the changeset viewer.