Subversion Repositories shark

Rev

Rev 538 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 *  Input driver mouse module
 */


/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */


#include <linuxcomp.h>

#include <linux/slab.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/device.h>

//#define DEBUG_MOUSE

MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Input driver mouse module");
MODULE_LICENSE("GPL");

extern void shark_mouse_exec(void);

#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
#define CONFIG_INPUT_MOUSEDEV_SCREEN_X  1024
#endif
#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y
#define CONFIG_INPUT_MOUSEDEV_SCREEN_Y  768
#endif

static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X;
static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;

/* Buffer Ssize */
#define MOUSE_BUFFERSIZE 256

/* Buffer Mask ( i=(i+1)&MASK is better than i=(i+1)%SIZE ) */
#define MOUSE_BUFFERMASK 0xff

/* Circular Buffer */
static struct mouse_event {
        unsigned long buttons;
        int dx, dy, dz;
} mbuffer[MOUSE_BUFFERSIZE];

/*
 * Buffer Pointers
 * data is inserted to mhead
 * data is kept from mtail+1
 * (mhead point to mtail+1 when buffer is empty)
 */

static unsigned mtail, mhead;

static char mouse_name[] = "mouse";

struct mouse_list {
        int dx, dy, dz, oldx, oldy;
        signed char ps2[6];
        unsigned long buttons;
        /*unsigned char ready, buffer, bufsiz;
        unsigned char mode, imexseq, impsseq;*/

        int finger;
};

static struct mouse_list m_list;
static struct mouse_list *list = &m_list;

/*
 * Get data from the mouse
 */

int mouse_get(int *dx, int *dy, int *dz, unsigned long *buttons)
{
        if ( ((mtail+1) & MOUSE_BUFFERMASK) == ((mhead) & MOUSE_BUFFERMASK) )
                return -1;
               
        mtail = (mtail+1) & MOUSE_BUFFERMASK;
       
        *dx      = mbuffer[mtail].dx;
        *dy      = mbuffer[mtail].dy;
        *dz      = mbuffer[mtail].dz;
        *buttons = mbuffer[mtail].buttons;
       
#ifdef DEBUG_MOUSE
        printk(KERN_DEBUG "mouse.c: ( %3d %3d %3d - %6x)\n", *dx, *dy, *dz, *(int *)buttons);
#endif
        return 0;
}

static void mouse_abs_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
        int size;

        /* Ignore joysticks */
        if (test_bit(BTN_TRIGGER, handle->dev->keybit))
                return;

        /* Handle touchpad data */
        if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) {

                if (list->finger && list->finger < 3)
                        list->finger++;

                switch (code) {
                        case ABS_X:
                                if (list->finger == 3)
                                        list->dx += (value - list->oldx) / 8;
                                list->oldx = value;
                                return;
                        case ABS_Y:
                                if (list->finger == 3)
                                        list->dy -= (value - list->oldy) / 8;
                                list->oldy = value;
                                return;
                }
                return;
        }

        /* Handle tablet data */
        switch (code) {
                case ABS_X:
                        size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
                        if (size == 0) size = xres;
                        list->dx += (value * xres - list->oldx) / size;
                        list->oldx += list->dx * size;
                        return;
                case ABS_Y:
                        size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
                        if (size == 0) size = yres;
                        list->dy -= (value * yres - list->oldy) / size;
                        list->oldy -= list->dy * size;
                        return;
        }
}

static void mouse_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
        int index;

#ifdef DEBUG_MOUSE
        printk(KERN_DEBUG "mouse.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value);
#endif

        switch (type) {
                case EV_ABS:
                        mouse_abs_event(handle, type, code, value);
                        break;

                case EV_REL:
                        switch (code) {
                                case REL_X:     list->dx += value; break;
                                case REL_Y:     list->dy -= value; break;
                                case REL_WHEEL: list->dz -= value; break;
                        }
                        break;

                case EV_KEY:
                        switch (code) {
                                case BTN_TOUCH: /* Handle touchpad data */
                                        if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) {
                                                list->finger = value;
                                                return;
                                        }
                                case BTN_0:
                                case BTN_FORWARD:
                                case BTN_LEFT:   index = 0; break;
                                case BTN_4:
                                case BTN_EXTRA:  index = 4; break;
                                case BTN_STYLUS:
                                case BTN_1:
                                case BTN_RIGHT:  index = 1; break;
                                case BTN_3:
                                case BTN_BACK:
                                case BTN_SIDE:   index = 3; break;
                                case BTN_2:
                                case BTN_STYLUS2:
                                case BTN_MIDDLE: index = 2; break;     
                                default: return;
                        }
                        switch (value) {
                                case 0: clear_bit(index, &list->buttons); break;
                                case 1: set_bit(index, &list->buttons); break;
                                case 2: return;
                        }
                        break;

                case EV_SYN:
                        switch (code) {
                                case SYN_REPORT:
                                        if (mtail != mhead) {
                                                mbuffer[mhead].buttons = list->buttons;
                                                mbuffer[mhead].dx = list->dx;
                                                mbuffer[mhead].dy = list->dy;
                                                mbuffer[mhead].dz = list->dz;
                                                mhead = (mhead+1) & MOUSE_BUFFERMASK;
                                                list->dx = list->dy = list->dz = 0;
                                        }
                                        shark_mouse_exec();
                                        break;
                        }
        }
}

static struct input_handle *mouse_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
{
        struct input_handle *handle;

        if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
                return NULL;
        memset(handle, 0, sizeof(struct input_handle));

        handle->dev = dev;
        handle->handler = handler;
        handle->name = mouse_name;

        input_open_device(handle);

#ifdef DEBUG_MOUSE
        printk(KERN_DEBUG "mouse.c: Connected device: \"%s\", %s\n", dev->name, dev->phys);
#endif

        return handle;
}

static void mouse_disconnect(struct input_handle *handle)
{
#ifdef DEBUG_MOUSE
        printk(KERN_DEBUG "mouse.c: Disconnected device: %s\n", handle->dev->phys);
#endif
       
        input_close_device(handle);

        kfree(handle);
}

static struct input_device_id mouse_ids[] = {
        {
                .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
                .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
                .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
                .relbit = { BIT(REL_X) | BIT(REL_Y) },
        },      // A mouse like device, at least one button, two relative axes
        {
                .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
                .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
                .relbit = { BIT(REL_WHEEL) },
        },      // A separate scrollwheel
        {
                .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
                .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
                .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
                .absbit = { BIT(ABS_X) | BIT(ABS_Y) },
        },      // A tablet like device, at least touch detection, two absolute axes
        {
                .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
                .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
                .keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) },
                .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) },
        },      // A touchpad

        { },    // Terminating entry
};

MODULE_DEVICE_TABLE(input, mouse_ids);
       
static struct input_handler mouse_handler = {
        .event =        mouse_event,
        .connect =      mouse_connect,
        .disconnect =   mouse_disconnect,
        .name =         "mouse",
        .id_table =     mouse_ids,
};

int __init mouse_init(void)
{
        /* Initialize Buffer Variables */
        mhead=1;
        mtail=0;

        input_register_handler(&mouse_handler);
        return 0;
}

void __exit mouse_exit(void)
{
        input_unregister_handler(&mouse_handler);
}

module_init(mouse_init);
module_exit(mouse_exit);