Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 493 → Rev 494

/shark/trunk/drivers/linuxcom/int.c
53,7 → 53,7
handlers[irq].flags = flags;
handlers[irq].data = dev_id;
 
handler_set(irq, linux_intr, NIL);
handler_set(irq, linux_intr, NIL, TRUE);
/*if (fdev_intr_alloc(irq, linux_intr, (void *)irq, 0)) {
handlers[irq].func = 0;
return (-EBUSY);
71,6 → 71,6
*/
void free_irq(unsigned int irq, void *a)
{
handler_set(irq, NULL, NIL);
handler_set(irq, NULL, NIL, FALSE);
handlers[irq].func = 0;
}
/shark/trunk/drivers/linuxcom/makefile
15,7 → 15,7
misc.o \
auto_irq.o \
int.o \
net_init.o
net_init.o \
 
C_OPT += -I../linuxcom/include
/shark/trunk/drivers/input/joystick/analog.c
0,0 → 1,778
/*
* $Id: analog.c,v 1.1 2004-03-08 18:47:38 giacomo Exp $
*
* Copyright (c) 1996-2001 Vojtech Pavlik
*/
 
/*
* Analog joystick and gamepad driver for Linux
*/
 
/*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/gameport.h>
#include <asm/timex.h>
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Analog joystick and gamepad driver");
MODULE_LICENSE("GPL");
 
/*
* Option parsing.
*/
 
#define ANALOG_PORTS 16
 
static char *js[ANALOG_PORTS];
static int analog_options[ANALOG_PORTS];
MODULE_PARM(js, "1-" __MODULE_STRING(ANALOG_PORTS) "s");
MODULE_PARM_DESC(js, "Analog joystick options");
 
/*
* Times, feature definitions.
*/
 
#define ANALOG_RUDDER 0x00004
#define ANALOG_THROTTLE 0x00008
#define ANALOG_AXES_STD 0x0000f
#define ANALOG_BTNS_STD 0x000f0
 
#define ANALOG_BTNS_CHF 0x00100
#define ANALOG_HAT1_CHF 0x00200
#define ANALOG_HAT2_CHF 0x00400
#define ANALOG_HAT_FCS 0x00800
#define ANALOG_HATS_ALL 0x00e00
#define ANALOG_BTN_TL 0x01000
#define ANALOG_BTN_TR 0x02000
#define ANALOG_BTN_TL2 0x04000
#define ANALOG_BTN_TR2 0x08000
#define ANALOG_BTNS_TLR 0x03000
#define ANALOG_BTNS_TLR2 0x0c000
#define ANALOG_BTNS_GAMEPAD 0x0f000
 
#define ANALOG_HBTN_CHF 0x10000
#define ANALOG_ANY_CHF 0x10700
#define ANALOG_SAITEK 0x20000
#define ANALOG_EXTENSIONS 0x7ff00
#define ANALOG_GAMEPAD 0x80000
 
#define ANALOG_MAX_TIME 3 /* 3 ms */
#define ANALOG_LOOP_TIME 2000 /* 2 * loop */
#define ANALOG_REFRESH_TIME HZ/100 /* 10 ms */
#define ANALOG_SAITEK_DELAY 200 /* 200 us */
#define ANALOG_SAITEK_TIME 2000 /* 2000 us */
#define ANALOG_AXIS_TIME 2 /* 2 * refresh */
#define ANALOG_INIT_RETRIES 8 /* 8 times */
#define ANALOG_FUZZ_BITS 2 /* 2 bit more */
#define ANALOG_FUZZ_MAGIC 36 /* 36 u*ms/loop */
 
#define ANALOG_MAX_NAME_LENGTH 128
#define ANALOG_MAX_PHYS_LENGTH 32
 
static short analog_axes[] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE };
static short analog_hats[] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
static short analog_pads[] = { BTN_Y, BTN_Z, BTN_TL, BTN_TR };
static short analog_exts[] = { ANALOG_HAT1_CHF, ANALOG_HAT2_CHF, ANALOG_HAT_FCS };
static short analog_pad_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_TL2, BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_BASE };
static short analog_joy_btn[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2,
BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_BASE6 };
 
static unsigned char analog_chf[] = { 0xf, 0x0, 0x1, 0x9, 0x2, 0x4, 0xc, 0x8, 0x3, 0x5, 0xb, 0x7, 0xd, 0xe, 0xa, 0x6 };
 
struct analog {
struct input_dev dev;
int mask;
short *buttons;
char name[ANALOG_MAX_NAME_LENGTH];
char phys[ANALOG_MAX_PHYS_LENGTH];
};
 
struct analog_port {
struct gameport *gameport;
struct timer_list timer;
struct analog analog[2];
unsigned char mask;
char saitek;
char cooked;
int bads;
int reads;
int speed;
int loop;
int fuzz;
int axes[4];
int buttons;
int initial[4];
int used;
int axtime;
};
 
/*
* Time macros.
*/
 
#ifdef __i386__
#define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0)
#define DELTA(x,y) (cpu_has_tsc?((y)-(x)):((x)-(y)+((x)<(y)?1193182L/HZ:0)))
#define TIME_NAME (cpu_has_tsc?"TSC":"PIT")
static unsigned int get_time_pit(void)
{
extern spinlock_t i8253_lock;
unsigned long flags;
unsigned int count;
 
spin_lock_irqsave(&i8253_lock, flags);
outb_p(0x00, 0x43);
count = inb_p(0x40);
count |= inb_p(0x40) << 8;
spin_unlock_irqrestore(&i8253_lock, flags);
 
return count;
}
#elif __x86_64__
#define GET_TIME(x) rdtscl(x)
#define DELTA(x,y) ((y)-(x))
#define TIME_NAME "TSC"
#elif __alpha__
#define GET_TIME(x) do { x = get_cycles(); } while (0)
#define DELTA(x,y) ((y)-(x))
#define TIME_NAME "PCC"
#else
#define FAKE_TIME
static unsigned long analog_faketime = 0;
#define GET_TIME(x) do { x = analog_faketime++; } while(0)
#define DELTA(x,y) ((y)-(x))
#define TIME_NAME "Unreliable"
#warning Precise timer not defined for this architecture.
#endif
 
/*
* analog_decode() decodes analog joystick data and reports input events.
*/
 
static void analog_decode(struct analog *analog, int *axes, int *initial, int buttons)
{
struct input_dev *dev = &analog->dev;
int i, j;
 
if (analog->mask & ANALOG_HAT_FCS)
for (i = 0; i < 4; i++)
if (axes[3] < ((initial[3] * ((i << 1) + 1)) >> 3)) {
buttons |= 1 << (i + 14);
break;
}
 
for (i = j = 0; i < 6; i++)
if (analog->mask & (0x10 << i))
input_report_key(dev, analog->buttons[j++], (buttons >> i) & 1);
 
if (analog->mask & ANALOG_HBTN_CHF)
for (i = 0; i < 4; i++)
input_report_key(dev, analog->buttons[j++], (buttons >> (i + 10)) & 1);
 
if (analog->mask & ANALOG_BTN_TL)
input_report_key(dev, analog_pads[0], axes[2] < (initial[2] >> 1));
if (analog->mask & ANALOG_BTN_TR)
input_report_key(dev, analog_pads[1], axes[3] < (initial[3] >> 1));
if (analog->mask & ANALOG_BTN_TL2)
input_report_key(dev, analog_pads[2], axes[2] > (initial[2] + (initial[2] >> 1)));
if (analog->mask & ANALOG_BTN_TR2)
input_report_key(dev, analog_pads[3], axes[3] > (initial[3] + (initial[3] >> 1)));
 
for (i = j = 0; i < 4; i++)
if (analog->mask & (1 << i))
input_report_abs(dev, analog_axes[j++], axes[i]);
 
for (i = j = 0; i < 3; i++)
if (analog->mask & analog_exts[i]) {
input_report_abs(dev, analog_hats[j++],
((buttons >> ((i << 2) + 7)) & 1) - ((buttons >> ((i << 2) + 9)) & 1));
input_report_abs(dev, analog_hats[j++],
((buttons >> ((i << 2) + 8)) & 1) - ((buttons >> ((i << 2) + 6)) & 1));
}
 
input_sync(dev);
}
 
/*
* analog_cooked_read() reads analog joystick data.
*/
 
static int analog_cooked_read(struct analog_port *port)
{
struct gameport *gameport = port->gameport;
unsigned int time[4], start, loop, now, loopout, timeout;
unsigned char data[4], this, last;
unsigned long flags;
int i, j;
 
loopout = (ANALOG_LOOP_TIME * port->loop) / 1000;
timeout = ANALOG_MAX_TIME * port->speed;
local_irq_save(flags);
gameport_trigger(gameport);
GET_TIME(now);
local_irq_restore(flags);
 
start = now;
this = port->mask;
i = 0;
 
do {
loop = now;
last = this;
 
local_irq_disable();
this = gameport_read(gameport) & port->mask;
GET_TIME(now);
local_irq_restore(flags);
 
if ((last ^ this) && (DELTA(loop, now) < loopout)) {
data[i] = last ^ this;
time[i] = now;
i++;
}
 
} while (this && (i < 4) && (DELTA(start, now) < timeout));
 
this <<= 4;
 
for (--i; i >= 0; i--) {
this |= data[i];
for (j = 0; j < 4; j++)
if (data[i] & (1 << j))
port->axes[j] = (DELTA(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop;
}
 
return -(this != port->mask);
}
 
static int analog_button_read(struct analog_port *port, char saitek, char chf)
{
unsigned char u;
int t = 1, i = 0;
int strobe = gameport_time(port->gameport, ANALOG_SAITEK_TIME);
 
u = gameport_read(port->gameport);
 
if (!chf) {
port->buttons = (~u >> 4) & 0xf;
return 0;
}
 
port->buttons = 0;
 
while ((~u & 0xf0) && (i < 16) && t) {
port->buttons |= 1 << analog_chf[(~u >> 4) & 0xf];
if (!saitek) return 0;
udelay(ANALOG_SAITEK_DELAY);
t = strobe;
gameport_trigger(port->gameport);
while (((u = gameport_read(port->gameport)) & port->mask) && t) t--;
i++;
}
 
return -(!t || (i == 16));
}
 
/*
* analog_timer() repeatedly polls the Analog joysticks.
*/
 
static void analog_timer(unsigned long data)
{
struct analog_port *port = (void *) data;
int i;
 
char saitek = !!(port->analog[0].mask & ANALOG_SAITEK);
char chf = !!(port->analog[0].mask & ANALOG_ANY_CHF);
 
if (port->cooked) {
port->bads -= gameport_cooked_read(port->gameport, port->axes, &port->buttons);
if (chf)
port->buttons = port->buttons ? (1 << analog_chf[port->buttons]) : 0;
port->reads++;
} else {
if (!port->axtime--) {
port->bads -= analog_cooked_read(port);
port->bads -= analog_button_read(port, saitek, chf);
port->reads++;
port->axtime = ANALOG_AXIS_TIME - 1;
} else {
if (!saitek)
analog_button_read(port, saitek, chf);
}
}
 
for (i = 0; i < 2; i++)
if (port->analog[i].mask)
analog_decode(port->analog + i, port->axes, port->initial, port->buttons);
 
mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
}
 
/*
* analog_open() is a callback from the input open routine.
*/
 
static int analog_open(struct input_dev *dev)
{
struct analog_port *port = dev->private;
if (!port->used++)
mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
return 0;
}
 
/*
* analog_close() is a callback from the input close routine.
*/
 
static void analog_close(struct input_dev *dev)
{
struct analog_port *port = dev->private;
if (!--port->used)
del_timer(&port->timer);
}
 
/*
* analog_calibrate_timer() calibrates the timer and computes loop
* and timeout values for a joystick port.
*/
 
static void analog_calibrate_timer(struct analog_port *port)
{
struct gameport *gameport = port->gameport;
unsigned int i, t, tx, t1, t2, t3;
unsigned long flags;
 
local_irq_save(flags);
GET_TIME(t1);
#ifdef FAKE_TIME
analog_faketime += 830;
#endif
udelay(1000);
GET_TIME(t2);
GET_TIME(t3);
local_irq_restore(flags);
 
port->speed = DELTA(t1, t2) - DELTA(t2, t3);
 
tx = ~0;
 
for (i = 0; i < 50; i++) {
local_irq_save(flags);
GET_TIME(t1);
for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); }
GET_TIME(t3);
local_irq_restore(flags);
udelay(i);
t = DELTA(t1, t2) - DELTA(t2, t3);
if (t < tx) tx = t;
}
 
port->loop = tx / 50;
}
 
/*
* analog_name() constructs a name for an analog joystick.
*/
 
static void analog_name(struct analog *analog)
{
sprintf26(analog->name, "Analog %d-axis %d-button",
hweight8(analog->mask & ANALOG_AXES_STD),
hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
 
if (analog->mask & ANALOG_HATS_ALL)
sprintf26(analog->name, "%s %d-hat",
analog->name, hweight16(analog->mask & ANALOG_HATS_ALL));
 
if (analog->mask & ANALOG_HAT_FCS)
strcat(analog->name, " FCS");
if (analog->mask & ANALOG_ANY_CHF)
strcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF");
 
strcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick");
}
 
/*
* analog_init_device()
*/
 
static void analog_init_device(struct analog_port *port, struct analog *analog, int index)
{
int i, j, t, v, w, x, y, z;
 
analog_name(analog);
sprintf26(analog->phys, "%s/input%d", port->gameport->phys, index);
analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn;
 
init_input_dev(&analog->dev);
 
analog->dev.name = analog->name;
analog->dev.phys = analog->phys;
analog->dev.id.bustype = BUS_GAMEPORT;
analog->dev.id.vendor = GAMEPORT_ID_VENDOR_ANALOG;
analog->dev.id.product = analog->mask >> 4;
analog->dev.id.version = 0x0100;
 
analog->dev.open = analog_open;
analog->dev.close = analog_close;
analog->dev.private = port;
analog->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (i = j = 0; i < 4; i++)
if (analog->mask & (1 << i)) {
t = analog_axes[j];
x = port->axes[i];
y = (port->axes[0] + port->axes[1]) >> 1;
z = y - port->axes[i];
z = z > 0 ? z : -z;
v = (x >> 3);
w = (x >> 3);
 
set_bit(t, analog->dev.absbit);
 
if ((i == 2 || i == 3) && (j == 2 || j == 3) && (z > (y >> 3)))
x = y;
 
if (analog->mask & ANALOG_SAITEK) {
if (i == 2) x = port->axes[i];
v = x - (x >> 2);
w = (x >> 4);
}
 
analog->dev.absmax[t] = (x << 1) - v;
analog->dev.absmin[t] = v;
analog->dev.absfuzz[t] = port->fuzz;
analog->dev.absflat[t] = w;
 
j++;
}
 
for (i = j = 0; i < 3; i++)
if (analog->mask & analog_exts[i])
for (x = 0; x < 2; x++) {
t = analog_hats[j++];
set_bit(t, analog->dev.absbit);
analog->dev.absmax[t] = 1;
analog->dev.absmin[t] = -1;
}
 
for (i = j = 0; i < 4; i++)
if (analog->mask & (0x10 << i))
set_bit(analog->buttons[j++], analog->dev.keybit);
 
if (analog->mask & ANALOG_BTNS_CHF)
for (i = 0; i < 2; i++)
set_bit(analog->buttons[j++], analog->dev.keybit);
 
if (analog->mask & ANALOG_HBTN_CHF)
for (i = 0; i < 4; i++)
set_bit(analog->buttons[j++], analog->dev.keybit);
 
for (i = 0; i < 4; i++)
if (analog->mask & (ANALOG_BTN_TL << i))
set_bit(analog_pads[i], analog->dev.keybit);
 
analog_decode(analog, port->axes, port->initial, port->buttons);
 
input_register_device(&analog->dev);
 
printk(KERN_INFO "input: %s at %s", analog->name, port->gameport->phys);
 
if (port->cooked)
printk(" [ADC port]\n");
else
printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME,
port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed,
port->speed > 10000 ? "M" : "k",
port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000)
: (port->loop * 1000000) / port->speed);
}
 
/*
* analog_init_devices() sets up device-specific values and registers the input devices.
*/
 
static int analog_init_masks(struct analog_port *port)
{
int i;
struct analog *analog = port->analog;
int max[4];
 
if (!port->mask)
return -1;
 
if ((port->mask & 3) != 3 && port->mask != 0xc) {
printk(KERN_WARNING "analog.c: Unknown joystick device found "
"(data=%#x, %s), probably not analog joystick.\n",
port->mask, port->gameport->phys);
return -1;
}
 
 
i = analog_options[0]; /* FIXME !!! - need to specify options for different ports */
 
analog[0].mask = i & 0xfffff;
 
analog[0].mask &= ~(ANALOG_AXES_STD | ANALOG_HAT_FCS | ANALOG_BTNS_GAMEPAD)
| port->mask | ((port->mask << 8) & ANALOG_HAT_FCS)
| ((port->mask << 10) & ANALOG_BTNS_TLR) | ((port->mask << 12) & ANALOG_BTNS_TLR2);
 
analog[0].mask &= ~(ANALOG_HAT2_CHF)
| ((analog[0].mask & ANALOG_HBTN_CHF) ? 0 : ANALOG_HAT2_CHF);
 
analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_BTN_TR | ANALOG_BTN_TR2)
| ((~analog[0].mask & ANALOG_HAT_FCS) >> 8)
| ((~analog[0].mask & ANALOG_HAT_FCS) << 2)
| ((~analog[0].mask & ANALOG_HAT_FCS) << 4);
 
analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_RUDDER)
| (((~analog[0].mask & ANALOG_BTNS_TLR ) >> 10)
& ((~analog[0].mask & ANALOG_BTNS_TLR2) >> 12));
 
analog[1].mask = ((i >> 20) & 0xff) | ((i >> 12) & 0xf0000);
 
analog[1].mask &= (analog[0].mask & ANALOG_EXTENSIONS) ? ANALOG_GAMEPAD
: (((ANALOG_BTNS_STD | port->mask) & ~analog[0].mask) | ANALOG_GAMEPAD);
 
if (port->cooked) {
 
for (i = 0; i < 4; i++) max[i] = port->axes[i] << 1;
 
if ((analog[0].mask & 0x7) == 0x7) max[2] = (max[0] + max[1]) >> 1;
if ((analog[0].mask & 0xb) == 0xb) max[3] = (max[0] + max[1]) >> 1;
if ((analog[0].mask & ANALOG_BTN_TL) && !(analog[0].mask & ANALOG_BTN_TL2)) max[2] >>= 1;
if ((analog[0].mask & ANALOG_BTN_TR) && !(analog[0].mask & ANALOG_BTN_TR2)) max[3] >>= 1;
if ((analog[0].mask & ANALOG_HAT_FCS)) max[3] >>= 1;
 
gameport_calibrate(port->gameport, port->axes, max);
}
for (i = 0; i < 4; i++)
port->initial[i] = port->axes[i];
 
return -!(analog[0].mask || analog[1].mask);
}
 
static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, struct analog_port *port)
{
int i, t, u, v;
 
gameport->private = port;
port->gameport = gameport;
init_timer(&port->timer);
port->timer.data = (long) port;
port->timer.function = analog_timer;
 
if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
 
analog_calibrate_timer(port);
 
gameport_trigger(gameport);
t = gameport_read(gameport);
wait_ms(ANALOG_MAX_TIME);
port->mask = (gameport_read(gameport) ^ t) & t & 0xf;
port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS;
for (i = 0; i < ANALOG_INIT_RETRIES; i++) {
if (!analog_cooked_read(port)) break;
wait_ms(ANALOG_MAX_TIME);
}
 
u = v = 0;
 
wait_ms(ANALOG_MAX_TIME);
t = gameport_time(gameport, ANALOG_MAX_TIME * 1000);
gameport_trigger(gameport);
while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++;
udelay(ANALOG_SAITEK_DELAY);
t = gameport_time(gameport, ANALOG_SAITEK_TIME);
gameport_trigger(gameport);
while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++;
 
if (v < (u >> 1)) { /* FIXME - more than one port */
analog_options[0] |= /* FIXME - more than one port */
ANALOG_SAITEK | ANALOG_BTNS_CHF | ANALOG_HBTN_CHF | ANALOG_HAT1_CHF;
return 0;
}
 
gameport_close(gameport);
}
 
if (!gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
 
for (i = 0; i < ANALOG_INIT_RETRIES; i++)
if (!gameport_cooked_read(gameport, port->axes, &port->buttons))
break;
for (i = 0; i < 4; i++)
if (port->axes[i] != -1) port->mask |= 1 << i;
 
port->fuzz = gameport->fuzz;
port->cooked = 1;
return 0;
}
 
if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
return 0;
 
return -1;
}
 
static void analog_connect(struct gameport *gameport, struct gameport_dev *dev)
{
struct analog_port *port;
int i;
 
if (!(port = kmalloc(sizeof(struct analog_port), GFP_KERNEL)))
return;
memset(port, 0, sizeof(struct analog_port));
 
if (analog_init_port(gameport, dev, port)) {
kfree(port);
return;
}
 
if (analog_init_masks(port)) {
gameport_close(gameport);
kfree(port);
return;
}
 
for (i = 0; i < 2; i++)
if (port->analog[i].mask)
analog_init_device(port, port->analog + i, i);
}
 
static void analog_disconnect(struct gameport *gameport)
{
int i;
 
struct analog_port *port = gameport->private;
for (i = 0; i < 2; i++)
if (port->analog[i].mask)
input_unregister_device(&port->analog[i].dev);
gameport_close(gameport);
printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on %s failed\n",
port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0,
port->gameport->phys);
kfree(port);
}
 
struct analog_types {
char *name;
int value;
};
 
struct analog_types analog_types[] = {
{ "none", 0x00000000 },
{ "auto", 0x000000ff },
{ "2btn", 0x0000003f },
{ "y-joy", 0x0cc00033 },
{ "y-pad", 0x8cc80033 },
{ "fcs", 0x000008f7 },
{ "chf", 0x000002ff },
{ "fullchf", 0x000007ff },
{ "gamepad", 0x000830f3 },
{ "gamepad8", 0x0008f0f3 },
{ NULL, 0 }
};
 
static void analog_parse_options(void)
{
int i, j;
char *end;
 
for (i = 0; i < ANALOG_PORTS && js[i]; i++) {
 
for (j = 0; analog_types[j].name; j++)
if (!strcmp(analog_types[j].name, js[i])) {
analog_options[i] = analog_types[j].value;
break;
}
if (analog_types[j].name) continue;
 
analog_options[i] = simple_strtoul(js[i], &end, 0);
if (end != js[i]) continue;
 
analog_options[i] = 0xff;
if (!strlen(js[i])) continue;
 
printk(KERN_WARNING "analog.c: Bad config for port %d - \"%s\"\n", i, js[i]);
}
 
for (; i < ANALOG_PORTS; i++)
analog_options[i] = 0xff;
}
 
/*
* The gameport device structure.
*/
 
static struct gameport_dev analog_dev = {
.connect = analog_connect,
.disconnect = analog_disconnect,
};
 
#ifndef MODULE
static int __init analog_setup(char *str)
{
char *s = str;
int i = 0;
 
if (!str || !*str) return 0;
 
while ((str = s) && (i < ANALOG_PORTS)) {
if ((s = strchr(str,','))) *s++ = 0;
js[i++] = str;
}
 
return 1;
}
__setup("js=", analog_setup);
#endif
 
int __init analog_init(void)
{
analog_parse_options();
gameport_register_device(&analog_dev);
return 0;
}
 
void __exit analog_exit(void)
{
gameport_unregister_device(&analog_dev);
}
 
module_init(analog_init);
module_exit(analog_exit);
/shark/trunk/drivers/input/joystick/joydump.c
0,0 → 1,153
/*
* $Id: joydump.c,v 1.1 2004-03-08 18:47:38 giacomo Exp $
*
* Copyright (c) 1996-2001 Vojtech Pavlik
*/
 
/*
* This is just a very simple driver that can dump the data
* out of the joystick port into the syslog ...
*/
 
/*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
 
#include <linuxcomp.h>
 
#include <linux/module.h>
#include <linux/gameport.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Gameport data dumper module");
MODULE_LICENSE("GPL");
 
#define BUF_SIZE 256
 
struct joydump {
unsigned int time;
unsigned char data;
};
 
static void __devinit joydump_connect(struct gameport *gameport, struct gameport_dev *dev)
{
struct joydump buf[BUF_SIZE];
int axes[4], buttons;
int i, j, t, timeout;
unsigned long flags;
unsigned char u;
 
printk(KERN_INFO "joydump: ,------------------- START ------------------.\n");
printk(KERN_INFO "joydump: | Dumping gameport%s.\n", gameport->phys);
printk(KERN_INFO "joydump: | Speed: %4d kHz. |\n", gameport->speed);
 
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
 
printk(KERN_INFO "joydump: | Raw mode not available - trying cooked. |\n");
 
if (gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
printk(KERN_INFO "joydump: | Cooked not available either. Failing. |\n");
printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
return;
}
 
gameport_cooked_read(gameport, axes, &buttons);
 
for (i = 0; i < 4; i++)
printk(KERN_INFO "joydump: | Axis %d: %4d. |\n", i, axes[i]);
printk(KERN_INFO "joydump: | Buttons %02x. |\n", buttons);
printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
}
 
timeout = gameport_time(gameport, 10000); /* 10 ms */
t = 0;
i = 1;
 
local_irq_save(flags);
 
u = gameport_read(gameport);
 
buf[0].data = u;
buf[0].time = t;
 
gameport_trigger(gameport);
 
while (i < BUF_SIZE && t < timeout) {
 
buf[i].data = gameport_read(gameport);
 
if (buf[i].data ^ u) {
u = buf[i].data;
buf[i].time = t;
i++;
}
t++;
}
 
local_irq_restore(flags);
 
/*
* Dump data.
*/
 
t = i;
 
printk(KERN_INFO "joydump: >------------------- DATA -------------------<\n");
printk(KERN_INFO "joydump: | index: %3d delta: %3d.%02d us data: ", 0, 0, 0);
for (j = 7; j >= 0; j--)
printk("%d",(buf[0].data >> j) & 1);
printk(" |\n");
for (i = 1; i < t; i++) {
printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ",
i, buf[i].time - buf[i-1].time);
for (j = 7; j >= 0; j--)
printk("%d",(buf[i].data >> j) & 1);
printk(" |\n");
}
 
printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
}
 
static void __devexit joydump_disconnect(struct gameport *gameport)
{
gameport_close(gameport);
}
 
static struct gameport_dev joydump_dev = {
.connect = joydump_connect,
.disconnect = joydump_disconnect,
};
 
/*static*/ int __init joydump_init(void)
{
gameport_register_device(&joydump_dev);
return 0;
}
 
/*static*/ void __exit joydump_exit(void)
{
gameport_unregister_device(&joydump_dev);
}
 
module_init(joydump_init);
module_exit(joydump_exit);
/shark/trunk/drivers/input/input.c
0,0 → 1,766
/*
* The input core
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*/
 
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
 
#include <linuxcomp.h>
 
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/major.h>
#include <linux/pm.h>
#include <linux/proc_fs.h>
#include <linux/kmod.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
 
#define INPUT_DEBUG
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input core");
MODULE_LICENSE("GPL");
 
EXPORT_SYMBOL(input_register_device);
EXPORT_SYMBOL(input_unregister_device);
EXPORT_SYMBOL(input_register_handler);
EXPORT_SYMBOL(input_unregister_handler);
EXPORT_SYMBOL(input_grab_device);
EXPORT_SYMBOL(input_release_device);
EXPORT_SYMBOL(input_open_device);
EXPORT_SYMBOL(input_close_device);
EXPORT_SYMBOL(input_accept_process);
EXPORT_SYMBOL(input_flush_device);
EXPORT_SYMBOL(input_event);
EXPORT_SYMBOL(input_class);
 
#define INPUT_DEVICES 256
 
static LIST_HEAD(input_dev_list);
static LIST_HEAD(input_handler_list);
 
static struct input_handler *input_table[8];
 
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_bus_input_dir;
DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);
static int input_devices_state;
#endif
 
static inline unsigned int ms_to_jiffies(unsigned int ms)
{
unsigned int j;
j = (ms * HZ + 500) / 1000;
return (j > 0) ? j : 1;
}
 
 
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct input_handle *handle;
 
if (dev->pm_dev)
pm_access(dev->pm_dev);
 
if (type > EV_MAX || !test_bit(type, dev->evbit))
return;
 
//!!!add_mouse_randomness((type << 4) ^ code ^ (code >> 4) ^ value);
 
switch (type) {
 
case EV_SYN:
switch (code) {
case SYN_CONFIG:
if (dev->event) dev->event(dev, type, code, value);
break;
 
case SYN_REPORT:
if (dev->sync) return;
dev->sync = 1;
break;
}
break;
 
case EV_KEY:
 
if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
return;
 
if (value == 2)
break;
 
change_bit(code, dev->key);
 
if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->timer.data && value) {
dev->repeat_key = code;
mod_timer(&dev->timer, jiffies26 + ms_to_jiffies(dev->rep[REP_DELAY]));
}
 
break;
case EV_ABS:
 
if (code > ABS_MAX || !test_bit(code, dev->absbit))
return;
 
if (dev->absfuzz[code]) {
if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) &&
(value < dev->abs[code] + (dev->absfuzz[code] >> 1)))
return;
 
if ((value > dev->abs[code] - dev->absfuzz[code]) &&
(value < dev->abs[code] + dev->absfuzz[code]))
value = (dev->abs[code] * 3 + value) >> 2;
 
if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) &&
(value < dev->abs[code] + (dev->absfuzz[code] << 1)))
value = (dev->abs[code] + value) >> 1;
}
 
if (dev->abs[code] == value)
return;
 
dev->abs[code] = value;
break;
 
case EV_REL:
 
if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0))
return;
 
break;
 
case EV_MSC:
 
if (code > MSC_MAX || !test_bit(code, dev->mscbit))
return;
 
if (dev->event) dev->event(dev, type, code, value);
break;
 
case EV_LED:
if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
return;
 
change_bit(code, dev->led);
if (dev->event) dev->event(dev, type, code, value);
break;
 
case EV_SND:
if (code > SND_MAX || !test_bit(code, dev->sndbit))
return;
 
if (dev->event) dev->event(dev, type, code, value);
break;
 
case EV_REP:
 
if (code > REP_MAX || value < 0 || dev->rep[code] == value) return;
 
dev->rep[code] = value;
if (dev->event) dev->event(dev, type, code, value);
 
break;
 
case EV_FF:
if (dev->event) dev->event(dev, type, code, value);
break;
}
 
if (type != EV_SYN)
dev->sync = 0;
 
if (dev->grab)
dev->grab->handler->event(dev->grab, type, code, value);
else
list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle, type, code, value);
}
 
static void input_repeat_key(unsigned long data)
{
struct input_dev *dev = (void *) data;
 
if (!test_bit(dev->repeat_key, dev->key))
return;
 
input_event(dev, EV_KEY, dev->repeat_key, 2);
input_sync(dev);
 
mod_timer(&dev->timer, jiffies26 + ms_to_jiffies(dev->rep[REP_PERIOD]));
}
 
int input_accept_process(struct input_handle *handle, struct file *file)
{
if (handle->dev->accept)
return handle->dev->accept(handle->dev, file);
 
return 0;
}
 
int input_grab_device(struct input_handle *handle)
{
if (handle->dev->grab)
return -EBUSY;
 
handle->dev->grab = handle;
return 0;
}
 
void input_release_device(struct input_handle *handle)
{
if (handle->dev->grab == handle)
handle->dev->grab = NULL;
}
 
int input_open_device(struct input_handle *handle)
{
if (handle->dev->pm_dev)
pm_access(handle->dev->pm_dev);
handle->open++;
if (handle->dev->open)
return handle->dev->open(handle->dev);
return 0;
}
 
int input_flush_device(struct input_handle* handle, struct file* file)
{
if (handle->dev->flush)
return handle->dev->flush(handle->dev, file);
 
return 0;
}
 
void input_close_device(struct input_handle *handle)
{
input_release_device(handle);
if (handle->dev->pm_dev)
pm_dev_idle(handle->dev->pm_dev);
if (handle->dev->close)
handle->dev->close(handle->dev);
handle->open--;
}
 
static void input_link_handle(struct input_handle *handle)
{
list_add_tail(&handle->d_node, &handle->dev->h_list);
list_add_tail(&handle->h_node, &handle->handler->h_list);
}
 
#define MATCH_BIT(bit, max) \
for (i = 0; i < NBITS(max); i++) \
if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
break; \
if (i != NBITS(max)) \
continue;
 
static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev)
{
int i;
 
for (; id->flags || id->driver_info; id++) {
 
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
if (id->id.bustype != dev->id.bustype)
continue;
 
if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
if (id->id.vendor != dev->id.vendor)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
if (id->id.product != dev->id.product)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
if (id->id.version != dev->id.version)
continue;
 
MATCH_BIT(evbit, EV_MAX);
MATCH_BIT(keybit, KEY_MAX);
MATCH_BIT(relbit, REL_MAX);
MATCH_BIT(absbit, ABS_MAX);
MATCH_BIT(mscbit, MSC_MAX);
MATCH_BIT(ledbit, LED_MAX);
MATCH_BIT(sndbit, SND_MAX);
MATCH_BIT(ffbit, FF_MAX);
 
return id;
}
 
return NULL;
}
 
/*
* Input hotplugging interface - loading event handlers based on
* device bitfields.
*/
 
#ifdef CONFIG_HOTPLUG
 
/*
* Input hotplugging invokes what /proc/sys/kernel/hotplug says
* (normally /sbin/hotplug) when input devices get added or removed.
*
* This invokes a user mode policy agent, typically helping to load driver
* or other modules, configure the device, and more. Drivers can provide
* a MODULE_DEVICE_TABLE to help with module loading subtasks.
*
*/
 
#define SPRINTF_BIT_A(bit, name, max) \
do { \
envp[i++] = scratch; \
scratch += sprintf26(scratch, name); \
for (j = NBITS(max) - 1; j >= 0; j--) \
if (dev->bit[j]) break; \
for (; j >= 0; j--) \
scratch += sprintf26(scratch, "%lx ", dev->bit[j]); \
scratch++; \
} while (0)
 
#define SPRINTF_BIT_A2(bit, name, max, ev) \
do { \
if (test_bit(ev, dev->evbit)) \
SPRINTF_BIT_A(bit, name, max); \
} while (0)
 
static void input_call_hotplug(char *verb, struct input_dev *dev)
{
char *argv[3], **envp, *buf, *scratch;
int i = 0, j, value;
 
if (!hotplug_path[0]) {
printk(KERN_ERR "input.c: calling hotplug without a hotplug agent defined\n");
return;
}
if (in_interrupt()) {
printk(KERN_ERR "input.c: calling hotplug from interrupt\n");
return;
}
if (!current->fs->root) {
printk(KERN_WARNING "input.c: calling hotplug without valid filesystem\n");
return;
}
if (!(envp = (char **) kmalloc(20 * sizeof(char *), GFP_KERNEL))) {
printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n");
return;
}
if (!(buf = kmalloc(1024, GFP_KERNEL))) {
kfree (envp);
printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n");
return;
}
 
argv[0] = hotplug_path;
argv[1] = "input";
argv[2] = 0;
 
envp[i++] = "HOME=/";
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
 
scratch = buf;
 
envp[i++] = scratch;
scratch += sprintf26(scratch, "ACTION=%s", verb) + 1;
 
envp[i++] = scratch;
scratch += sprintf26(scratch, "PRODUCT=%x/%x/%x/%x",
dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version) + 1;
if (dev->name) {
envp[i++] = scratch;
scratch += sprintf26(scratch, "NAME=%s", dev->name) + 1;
}
 
if (dev->phys) {
envp[i++] = scratch;
scratch += sprintf26(scratch, "PHYS=%s", dev->phys) + 1;
}
 
SPRINTF_BIT_A(evbit, "EV=", EV_MAX);
SPRINTF_BIT_A2(keybit, "KEY=", KEY_MAX, EV_KEY);
SPRINTF_BIT_A2(relbit, "REL=", REL_MAX, EV_REL);
SPRINTF_BIT_A2(absbit, "ABS=", ABS_MAX, EV_ABS);
SPRINTF_BIT_A2(mscbit, "MSC=", MSC_MAX, EV_MSC);
SPRINTF_BIT_A2(ledbit, "LED=", LED_MAX, EV_LED);
SPRINTF_BIT_A2(sndbit, "SND=", SND_MAX, EV_SND);
SPRINTF_BIT_A2(ffbit, "FF=", FF_MAX, EV_FF);
 
envp[i++] = 0;
 
#ifdef INPUT_DEBUG
printk(KERN_DEBUG "input.c: calling %s %s [%s %s %s %s %s]\n",
argv[0], argv[1], envp[0], envp[1], envp[2], envp[3], envp[4]);
#endif
 
value = call_usermodehelper(argv [0], argv, envp, 0);
 
kfree(buf);
kfree(envp);
 
#ifdef INPUT_DEBUG
if (value != 0)
printk(KERN_DEBUG "input.c: hotplug returned %d\n", value);
#endif
}
 
#endif
 
void input_register_device(struct input_dev *dev)
{
struct input_handle *handle;
struct input_handler *handler;
struct input_device_id *id;
 
set_bit(EV_SYN, dev->evbit);
 
/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
*/
 
init_timer(&dev->timer);
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
dev->rep[REP_DELAY] = 250;
dev->rep[REP_PERIOD] = 33;
}
 
INIT_LIST_HEAD(&dev->h_list);
list_add_tail(&dev->node, &input_dev_list);
 
list_for_each_entry(handler, &input_handler_list, node)
if ((id = input_match_device(handler->id_table, dev)))
if ((handle = handler->connect(handler, dev, id)))
input_link_handle(handle);
 
#ifdef CONFIG_HOTPLUG
input_call_hotplug("add", dev);
#endif
 
#ifdef CONFIG_PROC_FS
input_devices_state++;
wake_up(&input_devices_poll_wait);
#endif
}
 
void input_unregister_device(struct input_dev *dev)
{
struct list_head * node, * next;
 
if (!dev) return;
 
if (dev->pm_dev)
pm_unregister(dev->pm_dev);
 
del_timer_sync(&dev->timer);
 
list_for_each_safe(node, next, &dev->h_list) {
struct input_handle * handle = to_handle(node);
list_del_init(&handle->d_node);
list_del_init(&handle->h_node);
handle->handler->disconnect(handle);
}
 
#ifdef CONFIG_HOTPLUG
input_call_hotplug("remove", dev);
#endif
 
list_del_init(&dev->node);
 
#ifdef CONFIG_PROC_FS
input_devices_state++;
wake_up(&input_devices_poll_wait);
#endif
}
 
void input_register_handler(struct input_handler *handler)
{
struct input_dev *dev;
struct input_handle *handle;
struct input_device_id *id;
 
if (!handler) return;
 
INIT_LIST_HEAD(&handler->h_list);
 
if (handler->fops != NULL)
input_table[handler->minor >> 5] = handler;
 
list_add_tail(&handler->node, &input_handler_list);
list_for_each_entry(dev, &input_dev_list, node)
if ((id = input_match_device(handler->id_table, dev)))
if ((handle = handler->connect(handler, dev, id)))
input_link_handle(handle);
 
#ifdef CONFIG_PROC_FS
input_devices_state++;
wake_up(&input_devices_poll_wait);
#endif
}
 
void input_unregister_handler(struct input_handler *handler)
{
struct list_head * node, * next;
 
list_for_each_safe(node, next, &handler->h_list) {
struct input_handle * handle = to_handle_h(node);
list_del_init(&handle->h_node);
list_del_init(&handle->d_node);
handler->disconnect(handle);
}
 
list_del_init(&handler->node);
 
if (handler->fops != NULL)
input_table[handler->minor >> 5] = NULL;
 
#ifdef CONFIG_PROC_FS
input_devices_state++;
wake_up(&input_devices_poll_wait);
#endif
}
 
static int input_open_file(struct inode *inode, struct file *file)
{
struct input_handler *handler = input_table[iminor(inode) >> 5];
struct file_operations *old_fops, *new_fops = NULL;
int err;
 
/* No load-on-demand here? */
if (!handler || !(new_fops = fops_get(handler->fops)))
return -ENODEV;
 
/*
* That's _really_ odd. Usually NULL ->open means "nothing special",
* not "no device". Oh, well...
*/
if (!new_fops->open) {
fops_put(new_fops);
return -ENODEV;
}
old_fops = file->f_op;
file->f_op = new_fops;
 
err = new_fops->open(inode, file);
 
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
return err;
}
 
static struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};
 
#ifdef CONFIG_PROC_FS
 
#define SPRINTF_BIT_B(bit, name, max) \
do { \
len += sprintf26(buf + len, "B: %s", name); \
for (i = NBITS(max) - 1; i >= 0; i--) \
if (dev->bit[i]) break; \
for (; i >= 0; i--) \
len += sprintf26(buf + len, "%lx ", dev->bit[i]); \
len += sprintf26(buf + len, "\n"); \
} while (0)
 
#define SPRINTF_BIT_B2(bit, name, max, ev) \
do { \
if (test_bit(ev, dev->evbit)) \
SPRINTF_BIT_B(bit, name, max); \
} while (0)
 
 
static unsigned int input_devices_poll(struct file *file, poll_table *wait)
{
int state = input_devices_state;
poll_wait(file, &input_devices_poll_wait, wait);
if (state != input_devices_state)
return POLLIN | POLLRDNORM;
return 0;
}
 
static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data)
{
struct input_dev *dev;
struct input_handle *handle;
 
off_t at = 0;
int i, len, cnt = 0;
 
list_for_each_entry(dev, &input_dev_list, node) {
 
len = sprintf26(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n",
dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version);
 
len += sprintf26(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : "");
len += sprintf26(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : "");
len += sprintf26(buf + len, "H: Handlers=");
 
list_for_each_entry(handle, &dev->h_list, d_node)
len += sprintf26(buf + len, "%s ", handle->name);
 
len += sprintf26(buf + len, "\n");
 
SPRINTF_BIT_B(evbit, "EV=", EV_MAX);
SPRINTF_BIT_B2(keybit, "KEY=", KEY_MAX, EV_KEY);
SPRINTF_BIT_B2(relbit, "REL=", REL_MAX, EV_REL);
SPRINTF_BIT_B2(absbit, "ABS=", ABS_MAX, EV_ABS);
SPRINTF_BIT_B2(mscbit, "MSC=", MSC_MAX, EV_MSC);
SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED);
SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND);
SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF);
 
len += sprintf26(buf + len, "\n");
 
at += len;
 
if (at >= pos) {
if (!*start) {
*start = buf + (pos - (at - len));
cnt = at - pos;
} else cnt += len;
buf += len;
if (cnt >= count)
break;
}
}
 
if (&dev->node == &input_dev_list)
*eof = 1;
 
return (count > cnt) ? cnt : count;
}
 
static int input_handlers_read(char *buf, char **start, off_t pos, int count, int *eof, void *data)
{
struct input_handler *handler;
 
off_t at = 0;
int len = 0, cnt = 0;
int i = 0;
 
list_for_each_entry(handler, &input_handler_list, node) {
 
if (handler->fops)
len = sprintf26(buf, "N: Number=%d Name=%s Minor=%d\n",
i++, handler->name, handler->minor);
else
len = sprintf26(buf, "N: Number=%d Name=%s\n",
i++, handler->name);
 
at += len;
 
if (at >= pos) {
if (!*start) {
*start = buf + (pos - (at - len));
cnt = at - pos;
} else cnt += len;
buf += len;
if (cnt >= count)
break;
}
}
if (&handler->node == &input_handler_list)
*eof = 1;
 
return (count > cnt) ? cnt : count;
}
 
static int __init input_proc_init(void)
{
struct proc_dir_entry *entry;
 
proc_bus_input_dir = proc_mkdir("input", proc_bus);
if (proc_bus_input_dir == NULL)
return -ENOMEM;
proc_bus_input_dir->owner = THIS_MODULE;
entry = create_proc_read_entry("devices", 0, proc_bus_input_dir, input_devices_read, NULL);
if (entry == NULL) {
remove_proc_entry("input", proc_bus);
return -ENOMEM;
}
entry->owner = THIS_MODULE;
entry->proc_fops->poll = input_devices_poll;
entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
if (entry == NULL) {
remove_proc_entry("devices", proc_bus_input_dir);
remove_proc_entry("input", proc_bus);
return -ENOMEM;
}
entry->owner = THIS_MODULE;
return 0;
}
#else /* !CONFIG_PROC_FS */
static inline int input_proc_init(void) { return 0; }
#endif
 
struct class input_class = {
.name = "input",
};
 
/*static*/ int __init input_init(void)
{
int retval = -ENOMEM;
 
class_register(&input_class);
input_proc_init();
retval = register_chrdev(INPUT_MAJOR, "input", &input_fops);
if (retval) {
printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
remove_proc_entry("devices", proc_bus_input_dir);
remove_proc_entry("handlers", proc_bus_input_dir);
remove_proc_entry("input", proc_bus);
return retval;
}
 
retval = devfs_mk_dir("input");
if (retval) {
remove_proc_entry("devices", proc_bus_input_dir);
remove_proc_entry("handlers", proc_bus_input_dir);
remove_proc_entry("input", proc_bus);
unregister_chrdev(INPUT_MAJOR, "input");
}
return retval;
}
 
/*static*/ void __exit input_exit(void)
{
remove_proc_entry("devices", proc_bus_input_dir);
remove_proc_entry("handlers", proc_bus_input_dir);
remove_proc_entry("input", proc_bus);
 
devfs_remove("input");
unregister_chrdev(INPUT_MAJOR, "input");
class_unregister(&input_class);
}
 
subsys_initcall(input_init);
module_exit(input_exit);
/shark/trunk/drivers/input/serio/serport.c
0,0 → 1,220
/*
* Input device TTY line discipline
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*
* This is a module that converts a tty line into a much simpler
* 'serial io port' abstraction that the input device drivers use.
*/
 
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
 
#include <linuxcomp.h>
 
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/tty.h>
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Input device TTY line discipline");
MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_MOUSE);
 
#define SERPORT_BUSY 1
 
struct serport {
struct tty_struct *tty;
wait_queue_head_t wait;
struct serio serio;
unsigned long flags;
char phys[32];
};
 
char serport_name[] = "Serial port";
 
/*
* Callback functions from the serio code.
*/
 
static int serport_serio_write(struct serio *serio, unsigned char data)
{
struct serport *serport = serio->driver;
return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1);
}
 
static int serport_serio_open(struct serio *serio)
{
return 0;
}
 
static void serport_serio_close(struct serio *serio)
{
struct serport *serport = serio->driver;
 
serport->serio.type = 0;
wake_up_interruptible(&serport->wait);
}
 
/*
* serport_ldisc_open() is the routine that is called upon setting our line
* discipline on a tty. It prepares the serio struct.
*/
 
static int serport_ldisc_open(struct tty_struct *tty)
{
struct serport *serport;
char name[64];
 
serport = kmalloc(sizeof(struct serport), GFP_KERNEL);
if (unlikely(!serport))
return -ENOMEM;
memset(serport, 0, sizeof(struct serport));
 
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
serport->tty = tty;
tty->disc_data = serport;
 
snprintf26(serport->phys, sizeof(serport->phys), "%s/serio0", tty_name(tty, name));
 
serport->serio.name = serport_name;
serport->serio.phys = serport->phys;
 
serport->serio.type = SERIO_RS232;
serport->serio.write = serport_serio_write;
serport->serio.open = serport_serio_open;
serport->serio.close = serport_serio_close;
serport->serio.driver = serport;
 
init_waitqueue_head(&serport->wait);
 
return 0;
}
 
/*
* serport_ldisc_close() is the opposite of serport_ldisc_open()
*/
 
static void serport_ldisc_close(struct tty_struct *tty)
{
struct serport *serport = (struct serport*) tty->disc_data;
kfree(serport);
}
 
/*
* serport_ldisc_receive() is called by the low level tty driver when characters
* are ready for us. We forward the characters, one by one to the 'interrupt'
* routine.
*
* FIXME: We should get pt_regs from the tty layer and forward them to
* serio_interrupt here.
*/
 
static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
{
struct serport *serport = (struct serport*) tty->disc_data;
int i;
for (i = 0; i < count; i++)
serio_interrupt(&serport->serio, cp[i], 0, NULL);
}
 
/*
* serport_ldisc_room() reports how much room we do have for receiving data.
* Although we in fact have infinite room, we need to specify some value
* here, and 256 seems to be reasonable.
*/
 
static int serport_ldisc_room(struct tty_struct *tty)
{
return 256;
}
 
/*
* serport_ldisc_read() just waits indefinitely if everything goes well.
* However, when the serio driver closes the serio port, it finishes,
* returning 0 characters.
*/
 
static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char * buf, size_t nr)
{
struct serport *serport = (struct serport*) tty->disc_data;
char name[64];
 
if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
return -EBUSY;
 
serio_register_port(&serport->serio);
printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name));
wait_event_interruptible(serport->wait, !serport->serio.type);
serio_unregister_port(&serport->serio);
 
clear_bit(SERPORT_BUSY, &serport->flags);
 
return 0;
}
 
/*
* serport_ldisc_ioctl() allows to set the port protocol, and device ID
*/
 
static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
{
struct serport *serport = (struct serport*) tty->disc_data;
if (cmd == SPIOCSTYPE)
return get_user(serport->serio.type, (unsigned long *) arg);
 
return -EINVAL;
}
 
static void serport_ldisc_write_wakeup(struct tty_struct * tty)
{
struct serport *sp = (struct serport *) tty->disc_data;
 
serio_dev_write_wakeup(&sp->serio);
}
 
/*
* The line discipline structure.
*/
 
static struct tty_ldisc serport_ldisc = {
.owner = THIS_MODULE,
.name = "input",
.open = serport_ldisc_open,
.close = serport_ldisc_close,
.read = serport_ldisc_read,
.ioctl = serport_ldisc_ioctl,
.receive_buf = serport_ldisc_receive,
.receive_room = serport_ldisc_room,
.write_wakeup = serport_ldisc_write_wakeup
};
 
/*
* The functions for insering/removing us as a module.
*/
 
/*static*/ int __init serport_init(void)
{
int retval;
retval = tty_register_ldisc(N_MOUSE, &serport_ldisc);
if (retval)
printk(KERN_ERR "serport.c: Error registering line discipline.\n");
 
return retval;
}
 
/*static*/ void __exit serport_exit(void)
{
tty_register_ldisc(N_MOUSE, NULL);
}
 
module_init(serport_init);
module_exit(serport_exit);
/shark/trunk/drivers/input/serio/i8042-io.h
0,0 → 1,87
#ifndef _I8042_IO_H
#define _I8042_IO_H
 
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
 
/*
* Names.
*/
 
#define I8042_KBD_PHYS_DESC "isa0060/serio0"
#define I8042_AUX_PHYS_DESC "isa0060/serio1"
#define I8042_MUX_PHYS_DESC "isa0060/serio%d"
 
/*
* IRQs.
*/
 
#ifdef __alpha__
# define I8042_KBD_IRQ 1
# define I8042_AUX_IRQ (RTC_PORT(0) == 0x170 ? 9 : 12) /* Jensen is special */
#elif defined(__ia64__)
# define I8042_KBD_IRQ isa_irq_to_vector(1)
# define I8042_AUX_IRQ isa_irq_to_vector(12)
#else
# define I8042_KBD_IRQ 1
# define I8042_AUX_IRQ 12
#endif
 
/*
* Register numbers.
*/
 
#define I8042_COMMAND_REG 0x64
#define I8042_STATUS_REG 0x64
#define I8042_DATA_REG 0x60
 
static inline int i8042_read_data(void)
{
return inb(I8042_DATA_REG);
}
 
static inline int i8042_read_status(void)
{
return inb(I8042_STATUS_REG);
}
 
static inline void i8042_write_data(int val)
{
outb(val, I8042_DATA_REG);
return;
}
 
static inline void i8042_write_command(int val)
{
outb(val, I8042_COMMAND_REG);
return;
}
 
static inline int i8042_platform_init(void)
{
/*
* On ix86 platforms touching the i8042 data register region can do really
* bad things. Because of this the region is always reserved on ix86 boxes.
*/
#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__)
if (!request_region(I8042_DATA_REG, 16, "i8042"))
return -1;
#endif
 
#if !defined(__i386__) && !defined(__x86_64__)
i8042_reset = 1;
#endif
return 0;
}
 
static inline void i8042_platform_exit(void)
{
#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__)
release_region(I8042_DATA_REG, 16);
#endif
}
 
#endif /* _I8042_IO_H */
/shark/trunk/drivers/input/serio/serio.c
0,0 → 1,273
/*
* $Id: serio.c,v 1.1 2004-03-08 18:47:41 giacomo Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
 
/*
* The Serio abstraction 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*
* Changes:
* 20 Jul. 2003 Daniele Bellucci <bellucda@tiscali.it>
* Minor cleanups.
*/
 
#include <linuxcomp.h>
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/serio.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/suspend.h>
#include <linux/slab.h>
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serio abstraction core");
MODULE_LICENSE("GPL");
 
EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(serio_register_port);
EXPORT_SYMBOL(serio_register_slave_port);
EXPORT_SYMBOL(serio_unregister_port);
EXPORT_SYMBOL(serio_unregister_slave_port);
EXPORT_SYMBOL(serio_register_device);
EXPORT_SYMBOL(serio_unregister_device);
EXPORT_SYMBOL(serio_open);
EXPORT_SYMBOL(serio_close);
EXPORT_SYMBOL(serio_rescan);
 
struct serio_event {
int type;
struct serio *serio;
struct list_head node;
};
 
static DECLARE_MUTEX(serio_sem);
static LIST_HEAD(serio_list);
static LIST_HEAD(serio_dev_list);
static LIST_HEAD(serio_event_list);
static int serio_pid;
 
static void serio_find_dev(struct serio *serio)
{
struct serio_dev *dev;
 
list_for_each_entry(dev, &serio_dev_list, node) {
if (serio->dev)
break;
if (dev->connect)
dev->connect(serio, dev);
}
}
 
#define SERIO_RESCAN 1
 
static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
static DECLARE_COMPLETION(serio_exited);
 
void serio_handle_events(void)
{
struct list_head *node, *next;
struct serio_event *event;
 
list_for_each_safe(node, next, &serio_event_list) {
event = container_of(node, struct serio_event, node);
 
switch (event->type) {
case SERIO_RESCAN :
//!!!down(&serio_sem);
if (event->serio->dev && event->serio->dev->disconnect)
event->serio->dev->disconnect(event->serio);
serio_find_dev(event->serio);
//!!!up(&serio_sem);
break;
default:
break;
}
list_del_init(node);
kfree(event);
}
}
 
static int serio_thread(void *nothing)
{
/*lock_kernel();
daemonize("kseriod");
allow_signal(SIGTERM);
 
do {
serio_handle_events();
wait_event_interruptible(serio_wait, !list_empty(&serio_event_list));
if (current->flags & PF_FREEZE)
refrigerator(PF_IOTHREAD);
} while (!signal_pending(current));
 
printk(KERN_DEBUG "serio: kseriod exiting\n");
 
unlock_kernel();
complete_and_exit(&serio_exited, 0);*/
return 1;
}
 
void serio_rescan(struct serio *serio)
{
struct serio_event *event;
 
if (!(event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC)))
return;
 
event->type = SERIO_RESCAN;
event->serio = serio;
 
list_add_tail(&event->node, &serio_event_list);
//!!!wake_up(&serio_wait);
}
 
irqreturn_t serio_interrupt(struct serio *serio,
unsigned char data, unsigned int flags, struct pt_regs *regs)
{
irqreturn_t ret = IRQ_NONE;
 
if (serio->dev && serio->dev->interrupt) {
ret = serio->dev->interrupt(serio, data, flags, regs);
} else {
if (!flags) {
serio_rescan(serio);
ret = IRQ_HANDLED;
}
}
return ret;
}
 
void serio_register_port(struct serio *serio)
{
//!!!down(&serio_sem);
list_add_tail(&serio->node, &serio_list);
serio_find_dev(serio);
//!!!up(&serio_sem);
}
 
/*
* Same as serio_register_port but does not try to acquire serio_sem.
* Should be used when registering a serio from other input device's
* connect() function.
*/
void serio_register_slave_port(struct serio *serio)
{
list_add_tail(&serio->node, &serio_list);
serio_find_dev(serio);
}
 
void serio_unregister_port(struct serio *serio)
{
//!!!down(&serio_sem);
list_del_init(&serio->node);
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
//!!!up(&serio_sem);
}
 
/*
* Same as serio_unregister_port but does not try to acquire serio_sem.
* Should be used when unregistering a serio from other input device's
* disconnect() function.
*/
void serio_unregister_slave_port(struct serio *serio)
{
list_del_init(&serio->node);
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
}
 
void serio_register_device(struct serio_dev *dev)
{
struct serio *serio;
//!!!down(&serio_sem);
list_add_tail(&dev->node, &serio_dev_list);
list_for_each_entry(serio, &serio_list, node)
if (!serio->dev && dev->connect)
dev->connect(serio, dev);
//!!!up(&serio_sem);
}
 
void serio_unregister_device(struct serio_dev *dev)
{
struct serio *serio;
 
//!!!down(&serio_sem);
list_del_init(&dev->node);
 
list_for_each_entry(serio, &serio_list, node) {
if (serio->dev == dev && dev->disconnect)
dev->disconnect(serio);
serio_find_dev(serio);
}
//!!!up(&serio_sem);
}
 
/* called from serio_dev->connect/disconnect methods under serio_sem */
int serio_open(struct serio *serio, struct serio_dev *dev)
{
serio->dev = dev;
if (serio->open(serio)) {
serio->dev = NULL;
return -1;
}
return 0;
}
 
/* called from serio_dev->connect/disconnect methods under serio_sem */
void serio_close(struct serio *serio)
{
serio->close(serio);
serio->dev = NULL;
}
 
/*static*/ int __init serio_init(void)
{
int pid = 1;
 
//!!!pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL);
 
if (!pid) {
printk(KERN_WARNING "serio: Failed to start kseriod\n");
return -1;
}
 
serio_pid = pid;
 
return 0;
}
 
/*static*/ void __exit serio_exit(void)
{
//!!!kill_proc(serio_pid, SIGTERM, 1);
wait_for_completion(&serio_exited);
}
 
module_init(serio_init);
module_exit(serio_exit);
/shark/trunk/drivers/input/serio/i8042-ppcio.h
0,0 → 1,136
#ifndef _I8042_PPCIO_H
#define _I8042_PPCIO_H
 
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
 
#if defined(CONFIG_WALNUT)
 
#define I8042_KBD_IRQ 25
#define I8042_AUX_IRQ 26
 
#define I8042_KBD_PHYS_DESC "walnutps2/serio0"
#define I8042_AUX_PHYS_DESC "walnutps2/serio1"
#define I8042_MUX_PHYS_DESC "walnutps2/serio%d"
 
extern void *kb_cs;
extern void *kb_data;
 
#define I8042_COMMAND_REG (*(int *)kb_cs)
#define I8042_DATA_REG (*(int *)kb_data)
 
static inline int i8042_read_data(void)
{
return readb(kb_data);
}
 
static inline int i8042_read_status(void)
{
return readb(kb_cs);
}
 
static inline void i8042_write_data(int val)
{
writeb(val, kb_data);
}
 
static inline void i8042_write_command(int val)
{
writeb(val, kb_cs);
}
 
static inline int i8042_platform_init(void)
{
i8042_reset = 1;
return 0;
}
 
static inline void i8042_platform_exit(void)
{
}
 
#elif defined(CONFIG_SPRUCE)
 
#define I8042_KBD_IRQ 22
#define I8042_AUX_IRQ 21
 
#define I8042_KBD_PHYS_DESC "spruceps2/serio0"
#define I8042_AUX_PHYS_DESC "spruceps2/serio1"
#define I8042_MUX_PHYS_DESC "spruceps2/serio%d"
 
#define I8042_COMMAND_REG 0xff810000
#define I8042_DATA_REG 0xff810001
 
static inline int i8042_read_data(void)
{
unsigned long kbd_data;
 
__raw_writel(0x00000088, 0xff500008);
eieio();
 
__raw_writel(0x03000000, 0xff50000c);
eieio();
 
asm volatile("lis 7,0xff88 \n\
lswi 6,7,0x8 \n\
mr %0,6"
: "=r" (kbd_data) :: "6", "7");
 
__raw_writel(0x00000000, 0xff50000c);
eieio();
 
return (unsigned char)(kbd_data >> 24);
}
 
static inline int i8042_read_status(void)
{
unsigned long kbd_status;
 
__raw_writel(0x00000088, 0xff500008);
eieio();
 
__raw_writel(0x03000000, 0xff50000c);
eieio();
 
asm volatile("lis 7,0xff88 \n\
ori 7,7,0x8 \n\
lswi 6,7,0x8 \n\
mr %0,6"
: "=r" (kbd_status) :: "6", "7");
 
__raw_writel(0x00000000, 0xff50000c);
eieio();
 
return (unsigned char)(kbd_status >> 24);
}
 
static inline void i8042_write_data(int val)
{
*((unsigned char *)0xff810000) = (char)val;
}
 
static inline void i8042_write_command(int val)
{
*((unsigned char *)0xff810001) = (char)val;
}
 
static inline int i8042_platform_init(void)
{
i8042_reset = 1;
return 0;
}
 
static inline void i8042_platform_exit(void)
{
}
 
#else
 
#include "i8042-io.h"
 
#endif
 
#endif /* _I8042_PPCIO_H */
/shark/trunk/drivers/input/serio/i8042.c
0,0 → 1,851
/*
* i8042 keyboard and mouse controller driver for Linux
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*/
 
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
 
#include <linuxcomp.h>
 
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/config.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/serio.h>
 
#include <asm/io.h>
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
MODULE_LICENSE("GPL");
 
MODULE_PARM(i8042_noaux, "1i");
MODULE_PARM(i8042_nomux, "1i");
MODULE_PARM(i8042_unlock, "1i");
MODULE_PARM(i8042_reset, "1i");
MODULE_PARM(i8042_direct, "1i");
MODULE_PARM(i8042_dumbkbd, "1i");
 
static int i8042_reset;
static int i8042_noaux;
static int i8042_nomux;
static int i8042_unlock;
static int i8042_direct;
static int i8042_dumbkbd;
 
#undef DEBUG
#include "i8042.h"
 
spinlock_t i8042_lock = SPIN_LOCK_UNLOCKED;
 
struct i8042_values {
int irq;
unsigned char disable;
unsigned char irqen;
unsigned char exists;
signed char mux;
unsigned char *name;
unsigned char *phys;
};
 
static struct serio i8042_kbd_port;
static struct serio i8042_aux_port;
static unsigned char i8042_initial_ctr;
static unsigned char i8042_ctr;
static unsigned char i8042_mux_open;
struct timer_list i8042_timer;
 
/*
* Shared IRQ's require a device pointer, but this driver doesn't support
* multiple devices
*/
#define i8042_request_irq_cookie (&i8042_timer)
 
static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
/*
* The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
* be ready for reading values from it / writing values to it.
*/
 
static int i8042_wait_read(void)
{
int i = 0;
while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
udelay(50);
i++;
}
return -(i == I8042_CTL_TIMEOUT);
}
 
static int i8042_wait_write(void)
{
int i = 0;
while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
udelay(50);
i++;
}
return -(i == I8042_CTL_TIMEOUT);
}
 
/*
* i8042_flush() flushes all data that may be in the keyboard and mouse buffers
* of the i8042 down the toilet.
*/
 
static int i8042_flush(void)
{
unsigned long flags;
unsigned char data;
int i = 0;
 
spin_lock_irqsave(&i8042_lock, flags);
 
while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE)) {
data = i8042_read_data();
dbg("%02x <- i8042 (flush, %s)", data,
i8042_read_status() & I8042_STR_AUXDATA ? "aux" : "kbd");
}
 
spin_unlock_irqrestore(&i8042_lock, flags);
 
return i;
}
 
/*
* i8042_command() executes a command on the i8042. It also sends the input
* parameter(s) of the commands to it, and receives the output value(s). The
* parameters are to be stored in the param array, and the output is placed
* into the same array. The number of the parameters and output values is
* encoded in bits 8-11 of the command number.
*/
 
static int i8042_command(unsigned char *param, int command)
{
unsigned long flags;
int retval = 0, i = 0;
 
spin_lock_irqsave(&i8042_lock, flags);
 
retval = i8042_wait_write();
if (!retval) {
dbg("%02x -> i8042 (command)", command & 0xff);
i8042_write_command(command & 0xff);
}
if (!retval)
for (i = 0; i < ((command >> 12) & 0xf); i++) {
if ((retval = i8042_wait_write())) break;
dbg("%02x -> i8042 (parameter)", param[i]);
i8042_write_data(param[i]);
}
 
if (!retval)
for (i = 0; i < ((command >> 8) & 0xf); i++) {
if ((retval = i8042_wait_read())) break;
if (i8042_read_status() & I8042_STR_AUXDATA)
param[i] = ~i8042_read_data();
else
param[i] = i8042_read_data();
dbg("%02x <- i8042 (return)", param[i]);
}
 
spin_unlock_irqrestore(&i8042_lock, flags);
 
if (retval)
dbg(" -- i8042 (timeout)");
 
return retval;
}
 
/*
* i8042_kbd_write() sends a byte out through the keyboard interface.
*/
 
static int i8042_kbd_write(struct serio *port, unsigned char c)
{
unsigned long flags;
int retval = 0;
 
spin_lock_irqsave(&i8042_lock, flags);
 
if(!(retval = i8042_wait_write())) {
dbg("%02x -> i8042 (kbd-data)", c);
i8042_write_data(c);
}
 
spin_unlock_irqrestore(&i8042_lock, flags);
 
return retval;
}
 
/*
* i8042_aux_write() sends a byte out through the aux interface.
*/
 
static int i8042_aux_write(struct serio *port, unsigned char c)
{
struct i8042_values *values = port->driver;
int retval;
 
/*
* Send the byte out.
*/
 
if (values->mux == -1)
retval = i8042_command(&c, I8042_CMD_AUX_SEND);
else
retval = i8042_command(&c, I8042_CMD_MUX_SEND + values->mux);
 
/*
* Make sure the interrupt happens and the character is received even
* in the case the IRQ isn't wired, so that we can receive further
* characters later.
*/
 
i8042_interrupt(0, NULL, NULL);
return retval;
}
 
/*
* i8042_open() is called when a port is open by the higher layer.
* It allocates the interrupt and enables it in the chip.
*/
 
static int i8042_open(struct serio *port)
{
struct i8042_values *values = port->driver;
 
i8042_flush();
 
if (values->mux != -1)
if (i8042_mux_open++)
return 0;
 
if (request_irq(values->irq, i8042_interrupt,
SA_SHIRQ, "i8042", i8042_request_irq_cookie)) {
printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", values->irq, values->name);
values->exists = 0;
serio_unregister_port(port);
return -1;
}
 
i8042_ctr |= values->irqen;
 
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042.c: Can't write CTR while opening %s.\n", values->name);
return -1;
}
 
i8042_interrupt(0, NULL, NULL);
 
return 0;
}
 
/*
* i8042_close() frees the interrupt, so that it can possibly be used
* by another driver. We never know - if the user doesn't have a mouse,
* the BIOS could have used the AUX interrupt for PCI.
*/
 
static void i8042_close(struct serio *port)
{
struct i8042_values *values = port->driver;
 
if (values->mux != -1)
if (--i8042_mux_open)
return;
 
i8042_ctr &= ~values->irqen;
 
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042.c: Can't write CTR while closing %s.\n", values->name);
return;
}
 
free_irq(values->irq, i8042_request_irq_cookie);
 
i8042_flush();
}
 
/*
* Structures for registering the devices in the serio.c module.
*/
 
static struct i8042_values i8042_kbd_values = {
.irqen = I8042_CTR_KBDINT,
.disable = I8042_CTR_KBDDIS,
.name = "KBD",
.mux = -1,
};
 
static struct serio i8042_kbd_port =
{
.type = SERIO_8042_XL,
.write = i8042_kbd_write,
.open = i8042_open,
.close = i8042_close,
.driver = &i8042_kbd_values,
.name = "i8042 Kbd Port",
.phys = I8042_KBD_PHYS_DESC,
};
 
static struct i8042_values i8042_aux_values = {
.irqen = I8042_CTR_AUXINT,
.disable = I8042_CTR_AUXDIS,
.name = "AUX",
.mux = -1,
};
 
static struct serio i8042_aux_port =
{
.type = SERIO_8042,
.write = i8042_aux_write,
.open = i8042_open,
.close = i8042_close,
.driver = &i8042_aux_values,
.name = "i8042 Aux Port",
.phys = I8042_AUX_PHYS_DESC,
};
 
static struct i8042_values i8042_mux_values[4];
static struct serio i8042_mux_port[4];
static char i8042_mux_names[4][32];
static char i8042_mux_short[4][16];
static char i8042_mux_phys[4][32];
 
/*
* i8042_interrupt() is the most important function in this driver -
* it handles the interrupts from the i8042, and sends incoming bytes
* to the upper layers.
*/
 
static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
unsigned char str, data;
unsigned int dfl;
struct {
int data;
int str;
} buffer[I8042_BUFFER_SIZE];
int i, j = 0;
 
spin_lock_irqsave(&i8042_lock, flags);
 
while (j < I8042_BUFFER_SIZE &&
(buffer[j].str = i8042_read_status()) & I8042_STR_OBF)
buffer[j++].data = i8042_read_data();
 
spin_unlock_irqrestore(&i8042_lock, flags);
 
for (i = 0; i < j; i++) {
 
str = buffer[i].str;
data = buffer[i].data;
 
dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
 
if (i8042_mux_values[0].exists && (str & I8042_STR_AUXDATA)) {
 
if (str & I8042_STR_MUXERR) {
switch (data) {
case 0xfd:
case 0xfe: dfl = SERIO_TIMEOUT; break;
case 0xff: dfl = SERIO_PARITY; break;
}
data = 0xfe;
} else dfl = 0;
 
dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)",
data, (str >> 6), irq,
dfl & SERIO_PARITY ? ", bad parity" : "",
dfl & SERIO_TIMEOUT ? ", timeout" : "");
 
serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, regs);
continue;
}
 
dbg("%02x <- i8042 (interrupt, %s, %d%s%s)",
data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq,
dfl & SERIO_PARITY ? ", bad parity" : "",
dfl & SERIO_TIMEOUT ? ", timeout" : "");
 
if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) {
serio_interrupt(&i8042_aux_port, data, dfl, regs);
continue;
}
 
if (!i8042_kbd_values.exists)
continue;
 
serio_interrupt(&i8042_kbd_port, data, dfl, regs);
}
 
return IRQ_RETVAL(j);
}
 
/*
* i8042_controller init initializes the i8042 controller, and,
* most importantly, sets it into non-xlated mode if that's
* desired.
*/
static int __init i8042_controller_init(void)
{
 
/*
* Test the i8042. We need to know if it thinks it's working correctly
* before doing anything else.
*/
 
i8042_flush();
 
if (i8042_reset) {
 
unsigned char param;
 
if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
return -1;
}
 
if (param != I8042_RET_CTL_TEST) {
printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
param, I8042_RET_CTL_TEST);
return -1;
}
}
 
/*
* Save the CTR for restoral on unload / reboot.
*/
 
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {
printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n");
return -1;
}
 
i8042_initial_ctr = i8042_ctr;
 
/*
* Disable the keyboard interface and interrupt.
*/
 
i8042_ctr |= I8042_CTR_KBDDIS;
i8042_ctr &= ~I8042_CTR_KBDINT;
 
/*
* Handle keylock.
*/
 
if (~i8042_read_status() & I8042_STR_KEYLOCK) {
if (i8042_unlock)
i8042_ctr |= I8042_CTR_IGNKEYLOCK;
else
printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
}
 
/*
* If the chip is configured into nontranslated mode by the BIOS, don't
* bother enabling translating and be happy.
*/
 
if (~i8042_ctr & I8042_CTR_XLATE)
i8042_direct = 1;
 
/*
* Set nontranslated mode for the kbd interface if requested by an option.
* After this the kbd interface becomes a simple serial in/out, like the aux
* interface is. We don't do this by default, since it can confuse notebook
* BIOSes.
*/
 
if (i8042_direct) {
i8042_ctr &= ~I8042_CTR_XLATE;
i8042_kbd_port.type = SERIO_8042;
}
 
/*
* Write CTR back.
*/
 
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n");
return -1;
}
 
return 0;
}
 
/*
* Here we try to reset everything back to a state in which the BIOS will be
* able to talk to the hardware when rebooting.
*/
 
void i8042_controller_cleanup(void)
{
int i;
 
i8042_flush();
 
/*
* Reset anything that is connected to the ports.
*/
 
if (i8042_kbd_values.exists)
serio_cleanup(&i8042_kbd_port);
 
if (i8042_aux_values.exists)
serio_cleanup(&i8042_aux_port);
 
for (i = 0; i < 4; i++)
if (i8042_mux_values[i].exists)
serio_cleanup(i8042_mux_port + i);
 
/*
* Reset the controller.
*/
 
if (i8042_reset) {
unsigned char param;
 
if (i8042_command(&param, I8042_CMD_CTL_TEST))
printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n");
}
 
/*
* Restore the original control register setting.
*/
 
i8042_ctr = i8042_initial_ctr;
 
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
printk(KERN_WARNING "i8042.c: Can't restore CTR.\n");
 
}
 
/*
* i8042_check_mux() checks whether the controller supports the PS/2 Active
* Multiplexing specification by Synaptics, Phoenix, Insyde and
* LCS/Telegraphics.
*/
 
static int __init i8042_check_mux(struct i8042_values *values)
{
unsigned char param;
static int i8042_check_mux_cookie;
int i;
 
/*
* Check if AUX irq is available.
*/
 
if (request_irq(values->irq, i8042_interrupt, SA_SHIRQ,
"i8042", &i8042_check_mux_cookie))
return -1;
free_irq(values->irq, &i8042_check_mux_cookie);
 
/*
* Get rid of bytes in the queue.
*/
 
i8042_flush();
 
/*
* Internal loopback test - send three bytes, they should come back from the
* mouse interface, the last should be version. Note that we negate mouseport
* command responses for the i8042_check_aux() routine.
*/
 
param = 0xf0;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0x0f)
return -1;
param = 0x56;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9)
return -1;
param = 0xa4;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b)
return -1;
 
printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
(~param >> 4) & 0xf, ~param & 0xf);
 
/*
* Disable all muxed ports by disabling AUX.
*/
 
i8042_ctr |= I8042_CTR_AUXDIS;
i8042_ctr &= ~I8042_CTR_AUXINT;
 
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
return -1;
 
/*
* Enable all muxed ports.
*/
 
for (i = 0; i < 4; i++) {
i8042_command(&param, I8042_CMD_MUX_PFX + i);
i8042_command(&param, I8042_CMD_AUX_ENABLE);
}
 
return 0;
}
 
/*
* i8042_check_aux() applies as much paranoia as it can at detecting
* the presence of an AUX interface.
*/
 
static int __init i8042_check_aux(struct i8042_values *values)
{
unsigned char param;
static int i8042_check_aux_cookie;
 
/*
* Check if AUX irq is available. If it isn't, then there is no point
* in trying to detect AUX presence.
*/
 
if (request_irq(values->irq, i8042_interrupt, SA_SHIRQ,
"i8042", &i8042_check_aux_cookie))
return -1;
free_irq(values->irq, &i8042_check_aux_cookie);
 
/*
* Get rid of bytes in the queue.
*/
 
i8042_flush();
 
/*
* Internal loopback test - filters out AT-type i8042's. Unfortunately
* SiS screwed up and their 5597 doesn't support the LOOP command even
* though it has an AUX port.
*/
 
param = 0x5a;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa5) {
 
/*
* External connection test - filters out AT-soldered PS/2 i8042's
* 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error
* 0xfa - no error on some notebooks which ignore the spec
* Because it's common for chipsets to return error on perfectly functioning
* AUX ports, we test for this only when the LOOP command failed.
*/
 
if (i8042_command(&param, I8042_CMD_AUX_TEST)
|| (param && param != 0xfa && param != 0xff))
return -1;
}
 
/*
* Bit assignment test - filters out PS/2 i8042's in AT mode
*/
if (i8042_command(&param, I8042_CMD_AUX_DISABLE))
return -1;
if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS))
return -1;
 
if (i8042_command(&param, I8042_CMD_AUX_ENABLE))
return -1;
if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS))
return -1;
 
/*
* Disable the interface.
*/
 
i8042_ctr |= I8042_CTR_AUXDIS;
i8042_ctr &= ~I8042_CTR_AUXINT;
 
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
return -1;
 
return 0;
}
 
/*
* i8042_port_register() marks the device as existing,
* registers it, and reports to the user.
*/
 
static int __init i8042_port_register(struct i8042_values *values, struct serio *port)
{
values->exists = 1;
 
i8042_ctr &= ~values->disable;
 
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n");
return -1;
}
 
serio_register_port(port);
 
printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n",
values->name,
(unsigned long) I8042_DATA_REG,
(unsigned long) I8042_COMMAND_REG,
values->irq);
 
return 0;
}
 
static void i8042_timer_func(unsigned long data)
{
i8042_interrupt(0, NULL, NULL);
mod_timer(&i8042_timer, jiffies26 + I8042_POLL_PERIOD);
}
 
#ifndef MODULE
static int __init i8042_setup_reset(char *str)
{
i8042_reset = 1;
return 1;
}
static int __init i8042_setup_noaux(char *str)
{
i8042_noaux = 1;
i8042_nomux = 1;
return 1;
}
static int __init i8042_setup_nomux(char *str)
{
i8042_nomux = 1;
return 1;
}
static int __init i8042_setup_unlock(char *str)
{
i8042_unlock = 1;
return 1;
}
static int __init i8042_setup_direct(char *str)
{
i8042_direct = 1;
return 1;
}
static int __init i8042_setup_dumbkbd(char *str)
{
i8042_dumbkbd = 1;
return 1;
}
 
__setup("i8042_reset", i8042_setup_reset);
__setup("i8042_noaux", i8042_setup_noaux);
__setup("i8042_nomux", i8042_setup_nomux);
__setup("i8042_unlock", i8042_setup_unlock);
__setup("i8042_direct", i8042_setup_direct);
__setup("i8042_dumbkbd", i8042_setup_dumbkbd);
#endif
 
/*
* We need to reset the 8042 back to original mode on system shutdown,
* because otherwise BIOSes will be confused.
*/
 
static int i8042_notify_sys(struct notifier_block *this, unsigned long code,
void *unused)
{
if (code==SYS_DOWN || code==SYS_HALT)
i8042_controller_cleanup();
return NOTIFY_DONE;
}
 
static struct notifier_block i8042_notifier=
{
i8042_notify_sys,
NULL,
0
};
 
static void __init i8042_init_mux_values(struct i8042_values *values, struct serio *port, int index)
{
memcpy(port, &i8042_aux_port, sizeof(struct serio));
memcpy(values, &i8042_aux_values, sizeof(struct i8042_values));
sprintf26(i8042_mux_names[index], "i8042 Aux-%d Port", index);
sprintf26(i8042_mux_phys[index], I8042_MUX_PHYS_DESC, index + 1);
sprintf26(i8042_mux_short[index], "AUX%d", index);
port->name = i8042_mux_names[index];
port->phys = i8042_mux_phys[index];
port->driver = values;
values->name = i8042_mux_short[index];
values->mux = index;
}
 
int __init i8042_init(void)
{
int i;
 
dbg_init();
 
if (i8042_platform_init())
return -EBUSY;
 
i8042_aux_values.irq = I8042_AUX_IRQ;
i8042_kbd_values.irq = I8042_KBD_IRQ;
 
if (i8042_controller_init())
return -ENODEV;
 
if (i8042_dumbkbd)
i8042_kbd_port.write = NULL;
 
for (i = 0; i < 4; i++)
i8042_init_mux_values(i8042_mux_values + i, i8042_mux_port + i, i);
 
if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values))
for (i = 0; i < 4; i++)
i8042_port_register(i8042_mux_values + i, i8042_mux_port + i);
else
if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values))
i8042_port_register(&i8042_aux_values, &i8042_aux_port);
 
i8042_port_register(&i8042_kbd_values, &i8042_kbd_port);
 
init_timer(&i8042_timer);
i8042_timer.function = i8042_timer_func;
mod_timer(&i8042_timer, jiffies26 + I8042_POLL_PERIOD);
 
//!!!register_reboot_notifier(&i8042_notifier);
 
return 0;
}
 
void __exit i8042_exit(void)
{
int i;
 
//!!!unregister_reboot_notifier(&i8042_notifier);
 
del_timer(&i8042_timer);
 
i8042_controller_cleanup();
if (i8042_kbd_values.exists)
serio_unregister_port(&i8042_kbd_port);
 
if (i8042_aux_values.exists)
serio_unregister_port(&i8042_aux_port);
for (i = 0; i < 4; i++)
if (i8042_mux_values[i].exists)
serio_unregister_port(i8042_mux_port + i);
 
i8042_platform_exit();
}
 
module_init(i8042_init);
module_exit(i8042_exit);
/shark/trunk/drivers/input/serio/i8042-sparcio.h
0,0 → 1,116
#ifndef _I8042_SPARCIO_H
#define _I8042_SPARCIO_H
 
#include <linux/config.h>
#include <asm/io.h>
 
#ifdef CONFIG_PCI
#include <asm/oplib.h>
#include <asm/ebus.h>
#endif
 
static int i8042_kbd_irq = -1;
static int i8042_aux_irq = -1;
#define I8042_KBD_IRQ i8042_kbd_irq
#define I8042_AUX_IRQ i8042_aux_irq
 
#define I8042_KBD_PHYS_DESC "sparcps2/serio0"
#define I8042_AUX_PHYS_DESC "sparcps2/serio1"
#define I8042_MUX_PHYS_DESC "sparcps2/serio%d"
 
static unsigned long kbd_iobase;
 
#define I8042_COMMAND_REG (kbd_iobase + 0x64UL)
#define I8042_DATA_REG (kbd_iobase + 0x60UL)
 
static inline int i8042_read_data(void)
{
return readb(kbd_iobase + 0x60UL);
}
 
static inline int i8042_read_status(void)
{
return readb(kbd_iobase + 0x64UL);
}
 
static inline void i8042_write_data(int val)
{
writeb(val, kbd_iobase + 0x60UL);
}
 
static inline void i8042_write_command(int val)
{
writeb(val, kbd_iobase + 0x64UL);
}
 
#define OBP_PS2KBD_NAME1 "kb_ps2"
#define OBP_PS2KBD_NAME2 "keyboard"
#define OBP_PS2MS_NAME1 "kdmouse"
#define OBP_PS2MS_NAME2 "mouse"
 
static int i8042_platform_init(void)
{
#ifndef CONFIG_PCI
return -1;
#else
char prop[128];
int len;
 
len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
if (len < 0) {
printk("i8042: Cannot get name property of root OBP node.\n");
return -1;
}
if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) {
/* Hardcoded values for MrCoffee. */
i8042_kbd_irq = i8042_aux_irq = 13 | 0x20;
kbd_iobase = (unsigned long) ioremap(0x71300060, 8);
if (!kbd_iobase)
return -1;
} else {
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
struct linux_ebus_child *child;
 
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "8042"))
goto edev_found;
}
}
return -1;
 
edev_found:
for_each_edevchild(edev, child) {
if (!strcmp(child->prom_name, OBP_PS2KBD_NAME1) ||
!strcmp(child->prom_name, OBP_PS2KBD_NAME2)) {
i8042_kbd_irq = child->irqs[0];
kbd_iobase = (unsigned long)
ioremap(child->resource[0].start, 8);
}
if (!strcmp(child->prom_name, OBP_PS2MS_NAME1) ||
!strcmp(child->prom_name, OBP_PS2MS_NAME2))
i8042_aux_irq = child->irqs[0];
}
if (i8042_kbd_irq == -1 ||
i8042_aux_irq == -1) {
printk("i8042: Error, 8042 device lacks both kbd and "
"mouse nodes.\n");
return -1;
}
}
 
i8042_reset = 1;
 
return 0;
#endif /* CONFIG_PCI */
}
 
static inline void i8042_platform_exit(void)
{
#ifdef CONFIG_PCI
iounmap((void *)kbd_iobase);
#endif
}
 
#endif /* _I8042_SPARCIO_H */
/shark/trunk/drivers/input/serio/i8042.h
0,0 → 1,114
#ifndef _I8042_H
#define _I8042_H
 
/*
* Copyright (c) 1999-2002 Vojtech Pavlik
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
 
/*
* Arch-dependent inline functions and defines.
*/
 
#if defined(CONFIG_PPC)
#include "i8042-ppcio.h"
#elif defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64)
#include "i8042-sparcio.h"
#else
#include "i8042-io.h"
#endif
 
/*
* This is in 50us units, the time we wait for the i8042 to react. This
* has to be long enough for the i8042 itself to timeout on sending a byte
* to a non-existent mouse.
*/
 
#define I8042_CTL_TIMEOUT 10000
 
/*
* When the device isn't opened and it's interrupts aren't used, we poll it at
* regular intervals to see if any characters arrived. If yes, we can start
* probing for any mouse / keyboard connected. This is the period of the
* polling.
*/
 
#define I8042_POLL_PERIOD HZ/20
 
/*
* Status register bits.
*/
 
#define I8042_STR_PARITY 0x80
#define I8042_STR_TIMEOUT 0x40
#define I8042_STR_AUXDATA 0x20
#define I8042_STR_KEYLOCK 0x10
#define I8042_STR_CMDDAT 0x08
#define I8042_STR_MUXERR 0x04
#define I8042_STR_IBF 0x02
#define I8042_STR_OBF 0x01
 
/*
* Control register bits.
*/
 
#define I8042_CTR_KBDINT 0x01
#define I8042_CTR_AUXINT 0x02
#define I8042_CTR_IGNKEYLOCK 0x08
#define I8042_CTR_KBDDIS 0x10
#define I8042_CTR_AUXDIS 0x20
#define I8042_CTR_XLATE 0x40
 
/*
* Commands.
*/
 
#define I8042_CMD_CTL_RCTR 0x0120
#define I8042_CMD_CTL_WCTR 0x1060
#define I8042_CMD_CTL_TEST 0x01aa
 
#define I8042_CMD_KBD_DISABLE 0x00ad
#define I8042_CMD_KBD_ENABLE 0x00ae
#define I8042_CMD_KBD_TEST 0x01ab
#define I8042_CMD_KBD_LOOP 0x11d2
 
#define I8042_CMD_AUX_DISABLE 0x00a7
#define I8042_CMD_AUX_ENABLE 0x00a8
#define I8042_CMD_AUX_TEST 0x01a9
#define I8042_CMD_AUX_SEND 0x10d4
#define I8042_CMD_AUX_LOOP 0x11d3
 
#define I8042_CMD_MUX_PFX 0x0090
#define I8042_CMD_MUX_SEND 0x1090
 
/*
* Return codes.
*/
 
#define I8042_RET_CTL_TEST 0x55
 
/*
* Expected maximum internal i8042 buffer size. This is used for flushing
* the i8042 buffers. 32 should be more than enough.
*/
 
#define I8042_BUFFER_SIZE 32
 
/*
* Debug.
*/
 
#ifdef DEBUG
static unsigned long i8042_start;
#define dbg_init() do { i8042_start = jiffies26; } while (0)
#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format " [%d]\n" ,\
## arg, (int) (jiffies26 - i8042_start))
#else
#define dbg_init() do { } while (0)
#define dbg(format, arg...) do {} while (0)
#endif
 
#endif /* _I8042_H */
/shark/trunk/drivers/input/joydev.c
0,0 → 1,512
/*
* Joystick device driver for the input driver suite.
*
* Copyright (c) 1999-2002 Vojtech Pavlik
* Copyright (c) 1999 Colin Van Dyke
*
* 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.
*/
 
#include <linuxcomp.h>
 
#include <asm/io.h>
#include <asm/system.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/joystick.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Joystick device interfaces");
MODULE_SUPPORTED_DEVICE("input/js");
MODULE_LICENSE("GPL");
 
#define JOYDEV_MINOR_BASE 0
#define JOYDEV_MINORS 16
#define JOYDEV_BUFFER_SIZE 64
 
#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
 
struct joydev {
int exist;
int open;
int minor;
char name[16];
struct input_handle handle;
wait_queue_head_t wait;
struct list_head list;
struct js_corr corr[ABS_MAX];
struct JS_DATA_SAVE_TYPE glue;
int nabs;
int nkey;
__u16 keymap[KEY_MAX - BTN_MISC];
__u16 keypam[KEY_MAX - BTN_MISC];
__u8 absmap[ABS_MAX];
__u8 abspam[ABS_MAX];
__s16 abs[ABS_MAX];
};
 
struct joydev_list {
struct js_event buffer[JOYDEV_BUFFER_SIZE];
int head;
int tail;
int startup;
struct fasync_struct *fasync;
struct joydev *joydev;
struct list_head node;
};
 
static struct joydev *joydev_table[JOYDEV_MINORS];
 
static int joydev_correct(int value, struct js_corr *corr)
{
switch (corr->type) {
case JS_CORR_NONE:
break;
case JS_CORR_BROKEN:
value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
((corr->coef[2] * (value - corr->coef[0])) >> 14);
break;
default:
return 0;
}
 
if (value < -32767) return -32767;
if (value > 32767) return 32767;
 
return value;
}
 
static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
struct joydev *joydev = handle->private;
struct joydev_list *list;
struct js_event event;
 
switch (type) {
 
case EV_KEY:
if (code < BTN_MISC || value == 2) return;
event.type = JS_EVENT_BUTTON;
event.number = joydev->keymap[code - BTN_MISC];
event.value = value;
break;
 
case EV_ABS:
event.type = JS_EVENT_AXIS;
event.number = joydev->absmap[code];
event.value = joydev_correct(value, joydev->corr + event.number);
if (event.value == joydev->abs[event.number]) return;
joydev->abs[event.number] = event.value;
break;
 
default:
return;
}
 
event.time = MSECS(jiffies);
 
list_for_each_entry(list, &joydev->list, node) {
 
memcpy(list->buffer + list->head, &event, sizeof(struct js_event));
 
if (list->startup == joydev->nabs + joydev->nkey)
if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
list->startup = 0;
 
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
 
wake_up_interruptible(&joydev->wait);
}
 
static int joydev_fasync(int fd, struct file *file, int on)
{
int retval;
struct joydev_list *list = file->private_data;
retval = fasync_helper(fd, file, on, &list->fasync);
return retval < 0 ? retval : 0;
}
 
static void joydev_free(struct joydev *joydev)
{
devfs_remove("js%d", joydev->minor);
joydev_table[joydev->minor] = NULL;
kfree(joydev);
}
 
static int joydev_release(struct inode * inode, struct file * file)
{
struct joydev_list *list = file->private_data;
 
joydev_fasync(-1, file, 0);
 
list_del(&list->node);
 
if (!--list->joydev->open) {
if (list->joydev->exist)
input_close_device(&list->joydev->handle);
else
joydev_free(list->joydev);
}
 
kfree(list);
return 0;
}
 
static int joydev_open(struct inode *inode, struct file *file)
{
struct joydev_list *list;
int i = iminor(inode) - JOYDEV_MINOR_BASE;
 
if (i >= JOYDEV_MINORS || !joydev_table[i])
return -ENODEV;
 
if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL)))
return -ENOMEM;
memset(list, 0, sizeof(struct joydev_list));
 
list->joydev = joydev_table[i];
list_add_tail(&list->node, &joydev_table[i]->list);
file->private_data = list;
 
if (!list->joydev->open++)
if (list->joydev->exist)
input_open_device(&list->joydev->handle);
 
return 0;
}
 
static ssize_t joydev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
{
return -EINVAL;
}
 
static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
struct joydev_list *list = file->private_data;
struct joydev *joydev = list->joydev;
struct input_dev *input = joydev->handle.dev;
int retval = 0;
 
if (!list->joydev->exist)
return -ENODEV;
 
if (count < sizeof(struct js_event))
return -EINVAL;
 
if (count == sizeof(struct JS_DATA_TYPE)) {
 
struct JS_DATA_TYPE data;
int i;
 
for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
 
if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
return -EFAULT;
 
list->startup = 0;
list->tail = list->head;
 
return sizeof(struct JS_DATA_TYPE);
}
 
if (list->startup == joydev->nabs + joydev->nkey
&& list->head == list->tail && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
 
retval = wait_event_interruptible(list->joydev->wait, list->joydev->exist
&& (list->startup < joydev->nabs + joydev->nkey || list->head != list->tail));
 
if (retval)
return retval;
 
if (!list->joydev->exist)
return -ENODEV;
 
while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
 
struct js_event event;
 
event.time = MSECS(jiffies);
 
if (list->startup < joydev->nkey) {
event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
event.number = list->startup;
event.value = !!test_bit(joydev->keypam[event.number], input->key);
} else {
event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
event.number = list->startup - joydev->nkey;
event.value = joydev->abs[event.number];
}
 
if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
return -EFAULT;
 
list->startup++;
retval += sizeof(struct js_event);
}
 
while (list->head != list->tail && retval + sizeof(struct js_event) <= count) {
 
if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event)))
return -EFAULT;
 
list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
retval += sizeof(struct js_event);
}
 
return retval;
}
 
/* No kernel lock - fine */
static unsigned int joydev_poll(struct file *file, poll_table *wait)
{
struct joydev_list *list = file->private_data;
poll_wait(file, &list->joydev->wait, wait);
if (list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey)
return POLLIN | POLLRDNORM;
return 0;
}
 
static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct joydev_list *list = file->private_data;
struct joydev *joydev = list->joydev;
struct input_dev *dev = joydev->handle.dev;
int i;
 
if (!joydev->exist) return -ENODEV;
 
switch (cmd) {
 
case JS_SET_CAL:
return copy_from_user(&joydev->glue.JS_CORR, (struct JS_DATA_TYPE *) arg,
sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
case JS_GET_CAL:
return copy_to_user((struct JS_DATA_TYPE *) arg, &joydev->glue.JS_CORR,
sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
case JS_SET_TIMEOUT:
return get_user(joydev->glue.JS_TIMEOUT, (int *) arg);
case JS_GET_TIMEOUT:
return put_user(joydev->glue.JS_TIMEOUT, (int *) arg);
case JS_SET_TIMELIMIT:
return get_user(joydev->glue.JS_TIMELIMIT, (long *) arg);
case JS_GET_TIMELIMIT:
return put_user(joydev->glue.JS_TIMELIMIT, (long *) arg);
case JS_SET_ALL:
return copy_from_user(&joydev->glue, (struct JS_DATA_SAVE_TYPE *) arg,
sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
case JS_GET_ALL:
return copy_to_user((struct JS_DATA_SAVE_TYPE *) arg, &joydev->glue,
sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
 
case JSIOCGVERSION:
return put_user(JS_VERSION, (__u32 *) arg);
case JSIOCGAXES:
return put_user(joydev->nabs, (__u8 *) arg);
case JSIOCGBUTTONS:
return put_user(joydev->nkey, (__u8 *) arg);
case JSIOCSCORR:
return copy_from_user(joydev->corr, (struct js_corr *) arg,
sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
case JSIOCGCORR:
return copy_to_user((struct js_corr *) arg, joydev->corr,
sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
case JSIOCSAXMAP:
if (copy_from_user(joydev->abspam, (__u8 *) arg, sizeof(__u8) * ABS_MAX))
return -EFAULT;
for (i = 0; i < joydev->nabs; i++) {
if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
joydev->absmap[joydev->abspam[i]] = i;
}
return 0;
case JSIOCGAXMAP:
return copy_to_user((__u8 *) arg, joydev->abspam,
sizeof(__u8) * ABS_MAX) ? -EFAULT : 0;
case JSIOCSBTNMAP:
if (copy_from_user(joydev->keypam, (__u16 *) arg, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
return -EFAULT;
for (i = 0; i < joydev->nkey; i++) {
if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
}
return 0;
case JSIOCGBTNMAP:
return copy_to_user((__u16 *) arg, joydev->keypam,
sizeof(__u16) * (KEY_MAX - BTN_MISC)) ? -EFAULT : 0;
default:
if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
int len;
if (!dev->name) return 0;
len = strlen(dev->name) + 1;
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
if (copy_to_user((char *) arg, dev->name, len)) return -EFAULT;
return len;
}
}
return -EINVAL;
}
 
static struct file_operations joydev_fops = {
.owner = THIS_MODULE,
.read = joydev_read,
.write = joydev_write,
.poll = joydev_poll,
.open = joydev_open,
.release = joydev_release,
.ioctl = joydev_ioctl,
.fasync = joydev_fasync,
};
 
static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
{
struct joydev *joydev;
int i, j, t, minor;
 
/* Avoid tablets */
if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit))
return NULL;
 
for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
if (minor == JOYDEV_MINORS) {
printk(KERN_ERR "joydev: no more free joydev devices\n");
return NULL;
}
 
if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL)))
return NULL;
memset(joydev, 0, sizeof(struct joydev));
 
INIT_LIST_HEAD(&joydev->list);
init_waitqueue_head(&joydev->wait);
 
joydev->minor = minor;
joydev->exist = 1;
joydev->handle.dev = dev;
joydev->handle.name = joydev->name;
joydev->handle.handler = handler;
joydev->handle.private = joydev;
sprintf26(joydev->name, "js%d", minor);
 
for (i = 0; i < ABS_MAX; i++)
if (test_bit(i, dev->absbit)) {
joydev->absmap[i] = joydev->nabs;
joydev->abspam[joydev->nabs] = i;
joydev->nabs++;
}
 
for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC; i++)
if (test_bit(i + BTN_MISC, dev->keybit)) {
joydev->keymap[i] = joydev->nkey;
joydev->keypam[joydev->nkey] = i + BTN_MISC;
joydev->nkey++;
}
 
for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++)
if (test_bit(i + BTN_MISC, dev->keybit)) {
joydev->keymap[i] = joydev->nkey;
joydev->keypam[joydev->nkey] = i + BTN_MISC;
joydev->nkey++;
}
 
for (i = 0; i < joydev->nabs; i++) {
j = joydev->abspam[i];
if (dev->absmax[j] == dev->absmin[j]) {
joydev->corr[i].type = JS_CORR_NONE;
continue;
}
joydev->corr[i].type = JS_CORR_BROKEN;
joydev->corr[i].prec = dev->absfuzz[j];
joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j])))
continue;
joydev->corr[i].coef[2] = (1 << 29) / t;
joydev->corr[i].coef[3] = (1 << 29) / t;
 
joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
}
 
joydev_table[minor] = joydev;
devfs_mk_cdev(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
S_IFCHR|S_IRUGO|S_IWUSR, "js%d", minor);
 
return &joydev->handle;
}
 
static void joydev_disconnect(struct input_handle *handle)
{
struct joydev *joydev = handle->private;
 
joydev->exist = 0;
 
if (joydev->open)
input_close_device(handle);
else
joydev_free(joydev);
}
 
static struct input_device_id joydev_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_ABS) },
.absbit = { BIT(ABS_X) },
},
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_ABS) },
.absbit = { BIT(ABS_WHEEL) },
},
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_ABS) },
.absbit = { BIT(ABS_THROTTLE) },
},
{ }, /* Terminating entry */
};
 
MODULE_DEVICE_TABLE(input, joydev_ids);
 
static struct input_handler joydev_handler = {
.event = joydev_event,
.connect = joydev_connect,
.disconnect = joydev_disconnect,
.fops = &joydev_fops,
.minor = JOYDEV_MINOR_BASE,
.name = "joydev",
.id_table = joydev_ids,
};
 
/*static*/ int __init joydev_init(void)
{
input_register_handler(&joydev_handler);
return 0;
}
 
/*static*/ void __exit joydev_exit(void)
{
input_unregister_handler(&joydev_handler);
}
 
module_init(joydev_init);
module_exit(joydev_exit);
/shark/trunk/drivers/input/mouse/logips2pp.c
0,0 → 1,232
/*
* Logitech PS/2++ mouse driver
*
* Copyright (c) 1999-2003 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2003 Eric Wong <eric@yhbt.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
 
#include <linuxcomp.h>
 
#include <linux/input.h>
#include "psmouse.h"
#include "logips2pp.h"
 
#define DUBUG
 
/*
* Process a PS2++ or PS2T++ packet.
*/
 
void ps2pp_process_packet(struct psmouse *psmouse)
{
struct input_dev *dev = &psmouse->dev;
unsigned char *packet = psmouse->packet;
 
if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) {
 
switch ((packet[1] >> 4) | (packet[0] & 0x30)) {
 
case 0x0d: /* Mouse extra info */
 
input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
(int) (packet[2] & 8) - (int) (packet[2] & 7));
input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
 
break;
 
case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */
 
input_report_key(dev, BTN_SIDE, (packet[2]) & 1);
input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1);
input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1);
input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1);
input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1);
 
break;
 
case 0x0f: /* TouchPad extra info */
 
input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
(int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7));
packet[0] = packet[2] | 0x08;
break;
 
#ifdef DEBUG
default:
printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
(packet[1] >> 4) | (packet[0] & 0x30));
#endif
}
 
packet[0] &= 0x0f;
packet[1] = 0;
packet[2] = 0;
 
}
}
 
/*
* ps2pp_cmd() sends a PS2++ command, sliced into two bit
* pieces through the SETRES command. This is needed to send extended
* commands to mice on notebooks that try to understand the PS/2 protocol
* Ugly.
*/
 
static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
{
unsigned char d;
int i;
 
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
return -1;
 
for (i = 6; i >= 0; i -= 2) {
d = (command >> i) & 3;
if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
return -1;
}
 
if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
return -1;
 
return 0;
}
 
/*
* SmartScroll / CruiseControl for some newer Logitech mice Defaults to
* enabled if we do nothing to it. Of course I put this in because I want it
* disabled :P
* 1 - enabled (if previously disabled, also default)
* 0/2 - disabled
*/
 
static void ps2pp_set_smartscroll(struct psmouse *psmouse)
{
unsigned char param[4];
 
ps2pp_cmd(psmouse, param, 0x32);
 
param[0] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
 
if (psmouse_smartscroll == 1)
param[0] = 1;
else
if (psmouse_smartscroll > 2)
return;
 
/* else leave param[0] == 0 to disable */
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
}
 
/*
* Support 800 dpi resolution _only_ if the user wants it (there are good
* reasons to not use it even if the mouse supports it, and of course there are
* also good reasons to use it, let the user decide).
*/
 
void ps2pp_set_800dpi(struct psmouse *psmouse)
{
unsigned char param = 3;
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, &param, PSMOUSE_CMD_SETRES);
}
 
/*
* Detect the exact model and features of a PS2++ or PS2T++ Logitech mouse or
* touchpad.
*/
 
int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param)
{
int i;
static int logitech_4btn[] = { 12, 40, 41, 42, 43, 52, 73, 80, -1 };
static int logitech_wheel[] = { 52, 53, 75, 76, 80, 81, 83, 88, 112, -1 };
static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75,
76, 80, 81, 83, 88, 96, 97, 112, -1 };
static int logitech_mx[] = { 112, -1 };
 
psmouse->vendor = "Logitech";
psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
 
if (param[1] < 3)
clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
if (param[1] < 2)
clear_bit(BTN_RIGHT, psmouse->dev.keybit);
 
psmouse->type = PSMOUSE_PS2;
 
for (i = 0; logitech_ps2pp[i] != -1; i++)
if (logitech_ps2pp[i] == psmouse->model)
psmouse->type = PSMOUSE_PS2PP;
 
if (psmouse->type == PSMOUSE_PS2PP) {
 
for (i = 0; logitech_4btn[i] != -1; i++)
if (logitech_4btn[i] == psmouse->model)
set_bit(BTN_SIDE, psmouse->dev.keybit);
 
for (i = 0; logitech_wheel[i] != -1; i++)
if (logitech_wheel[i] == psmouse->model) {
set_bit(REL_WHEEL, psmouse->dev.relbit);
psmouse->name = "Wheel Mouse";
}
 
for (i = 0; logitech_mx[i] != -1; i++)
if (logitech_mx[i] == psmouse->model) {
set_bit(BTN_SIDE, psmouse->dev.keybit);
set_bit(BTN_EXTRA, psmouse->dev.keybit);
set_bit(BTN_BACK, psmouse->dev.keybit);
set_bit(BTN_FORWARD, psmouse->dev.keybit);
set_bit(BTN_TASK, psmouse->dev.keybit);
psmouse->name = "MX Mouse";
}
 
/*
* Do Logitech PS2++ / PS2T++ magic init.
*/
 
if (psmouse->model == 97) { /* TouchPad 3 */
 
set_bit(REL_WHEEL, psmouse->dev.relbit);
set_bit(REL_HWHEEL, psmouse->dev.relbit);
 
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */
psmouse_command(psmouse, param, 0x30d1);
param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */
psmouse_command(psmouse, param, 0x30d1);
param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */
psmouse_command(psmouse, param, 0x30d1);
 
param[0] = 0;
if (!psmouse_command(psmouse, param, 0x13d1) &&
param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
psmouse->name = "TouchPad 3";
return PSMOUSE_PS2TPP;
}
 
} else {
 
param[0] = param[1] = param[2] = 0;
ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
ps2pp_cmd(psmouse, param, 0xDB);
 
if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 &&
(param[2] & 3) == ((param[1] >> 2) & 3)) {
ps2pp_set_smartscroll(psmouse);
return PSMOUSE_PS2PP;
}
}
}
 
return 0;
}
/shark/trunk/drivers/input/mouse/psmouse.h
0,0 → 1,59
#ifndef _PSMOUSE_H
#define _PSMOUSE_H
 
#define PSMOUSE_CMD_SETSCALE11 0x00e6
#define PSMOUSE_CMD_SETRES 0x10e8
#define PSMOUSE_CMD_GETINFO 0x03e9
#define PSMOUSE_CMD_SETSTREAM 0x00ea
#define PSMOUSE_CMD_POLL 0x03eb
#define PSMOUSE_CMD_GETID 0x02f2
#define PSMOUSE_CMD_SETRATE 0x10f3
#define PSMOUSE_CMD_ENABLE 0x00f4
#define PSMOUSE_CMD_RESET_DIS 0x00f6
#define PSMOUSE_CMD_RESET_BAT 0x02ff
 
#define PSMOUSE_RET_BAT 0xaa
#define PSMOUSE_RET_ID 0x00
#define PSMOUSE_RET_ACK 0xfa
#define PSMOUSE_RET_NAK 0xfe
 
/* psmouse states */
#define PSMOUSE_NEW_DEVICE 0
#define PSMOUSE_ACTIVATED 1
#define PSMOUSE_IGNORE 2
 
struct psmouse {
void *private;
struct input_dev dev;
struct serio *serio;
char *vendor;
char *name;
unsigned char cmdbuf[8];
unsigned char packet[8];
unsigned char cmdcnt;
unsigned char pktcnt;
unsigned char type;
unsigned char model;
unsigned long last;
unsigned char state;
char acking;
volatile char ack;
char error;
char devname[64];
char phys[32];
};
 
#define PSMOUSE_PS2 1
#define PSMOUSE_PS2PP 2
#define PSMOUSE_PS2TPP 3
#define PSMOUSE_GENPS 4
#define PSMOUSE_IMPS 5
#define PSMOUSE_IMEX 6
#define PSMOUSE_SYNAPTICS 7
 
int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
 
extern int psmouse_smartscroll;
extern unsigned int psmouse_resetafter;
 
#endif /* _PSMOUSE_H */
/shark/trunk/drivers/input/mouse/sermouse.c
0,0 → 1,312
/*
* $Id: sermouse.c,v 1.1 2004-03-08 18:47:40 giacomo Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
 
/*
* Serial mouse driver for Linux
*/
 
/*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
 
#include <linuxcomp.h>
 
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/config.h>
#include <linux/serio.h>
#include <linux/init.h>
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serial mouse driver");
MODULE_LICENSE("GPL");
 
static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse",
"Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse",
"Logitech MZ++ Mouse"};
 
struct sermouse {
struct input_dev dev;
signed char buf[8];
unsigned char count;
unsigned char type;
unsigned long last;
char phys[32];
};
 
/*
* sermouse_process_msc() analyzes the incoming MSC/Sun bytestream and
* applies some prediction to the data, resulting in 96 updates per
* second, which is as good as a PS/2 or USB mouse.
*/
 
static void sermouse_process_msc(struct sermouse *sermouse, signed char data, struct pt_regs *regs)
{
struct input_dev *dev = &sermouse->dev;
signed char *buf = sermouse->buf;
 
input_regs(dev, regs);
 
switch (sermouse->count) {
 
case 0:
if ((data & 0xf8) != 0x80) return;
input_report_key(dev, BTN_LEFT, !(data & 4));
input_report_key(dev, BTN_RIGHT, !(data & 1));
input_report_key(dev, BTN_MIDDLE, !(data & 2));
break;
 
case 1:
case 3:
input_report_rel(dev, REL_X, data / 2);
input_report_rel(dev, REL_Y, -buf[1]);
buf[0] = data - data / 2;
break;
 
case 2:
case 4:
input_report_rel(dev, REL_X, buf[0]);
input_report_rel(dev, REL_Y, buf[1] - data);
buf[1] = data / 2;
break;
}
 
input_sync(dev);
 
if (++sermouse->count == (5 - ((sermouse->type == SERIO_SUN) << 1)))
sermouse->count = 0;
}
 
/*
* sermouse_process_ms() anlyzes the incoming MS(Z/+/++) bytestream and
* generates events. With prediction it gets 80 updates/sec, assuming
* standard 3-byte packets and 1200 bps.
*/
 
static void sermouse_process_ms(struct sermouse *sermouse, signed char data, struct pt_regs *regs)
{
struct input_dev *dev = &sermouse->dev;
signed char *buf = sermouse->buf;
 
if (data & 0x40) sermouse->count = 0;
 
input_regs(dev, regs);
 
switch (sermouse->count) {
 
case 0:
buf[1] = data;
input_report_key(dev, BTN_LEFT, (data >> 5) & 1);
input_report_key(dev, BTN_RIGHT, (data >> 4) & 1);
break;
 
case 1:
buf[2] = data;
data = (signed char) (((buf[1] << 6) & 0xc0) | (data & 0x3f));
input_report_rel(dev, REL_X, data / 2);
input_report_rel(dev, REL_Y, buf[4]);
buf[3] = data - data / 2;
break;
 
case 2:
/* Guessing the state of the middle button on 3-button MS-protocol mice - ugly. */
if ((sermouse->type == SERIO_MS) && !data && !buf[2] && !((buf[0] & 0xf0) ^ buf[1]))
input_report_key(dev, BTN_MIDDLE, !test_bit(BTN_MIDDLE, dev->key));
buf[0] = buf[1];
 
data = (signed char) (((buf[1] << 4) & 0xc0) | (data & 0x3f));
input_report_rel(dev, REL_X, buf[3]);
input_report_rel(dev, REL_Y, data - buf[4]);
buf[4] = data / 2;
break;
 
case 3:
 
switch (sermouse->type) {
case SERIO_MS:
sermouse->type = SERIO_MP;
 
case SERIO_MP:
if ((data >> 2) & 3) break; /* M++ Wireless Extension packet. */
input_report_key(dev, BTN_MIDDLE, (data >> 5) & 1);
input_report_key(dev, BTN_SIDE, (data >> 4) & 1);
break;
 
case SERIO_MZP:
case SERIO_MZPP:
input_report_key(dev, BTN_SIDE, (data >> 5) & 1);
 
case SERIO_MZ:
input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1);
input_report_rel(dev, REL_WHEEL, (data & 8) - (data & 7));
break;
}
break;
 
case 4:
case 6: /* MZ++ packet type. We can get these bytes for M++ too but we ignore them later. */
buf[1] = (data >> 2) & 0x0f;
break;
 
case 5:
case 7: /* Ignore anything besides MZ++ */
if (sermouse->type != SERIO_MZPP) break;
 
switch (buf[1]) {
 
case 1: /* Extra mouse info */
 
input_report_key(dev, BTN_SIDE, (data >> 4) & 1);
input_report_key(dev, BTN_EXTRA, (data >> 5) & 1);
input_report_rel(dev, data & 0x80 ? REL_HWHEEL : REL_WHEEL, (data & 7) - (data & 8));
 
break;
 
default: /* We don't decode anything else yet. */
 
printk(KERN_WARNING
"sermouse.c: Received MZ++ packet %x, don't know how to handle.\n", buf[1]);
break;
}
 
break;
}
 
input_sync(dev);
 
sermouse->count++;
}
 
/*
* sermouse_interrupt() handles incoming characters, either gathering them into
* packets or passing them to the command routine as command output.
*/
 
static irqreturn_t sermouse_interrupt(struct serio *serio,
unsigned char data, unsigned int flags, struct pt_regs *regs)
{
struct sermouse *sermouse = serio->private;
 
if (time_after(jiffies26, sermouse->last + HZ/10)) sermouse->count = 0;
sermouse->last = jiffies26;
 
if (sermouse->type > SERIO_SUN)
sermouse_process_ms(sermouse, data, regs);
else
sermouse_process_msc(sermouse, data, regs);
return IRQ_HANDLED;
}
 
/*
* sermouse_disconnect() cleans up after we don't want talk
* to the mouse anymore.
*/
 
static void sermouse_disconnect(struct serio *serio)
{
struct sermouse *sermouse = serio->private;
input_unregister_device(&sermouse->dev);
serio_close(serio);
kfree(sermouse);
}
 
/*
* sermouse_connect() is a callback form the serio module when
* an unhandled serio port is found.
*/
 
static void sermouse_connect(struct serio *serio, struct serio_dev *dev)
{
struct sermouse *sermouse;
unsigned char c;
if ((serio->type & SERIO_TYPE) != SERIO_RS232)
return;
 
if (!(serio->type & SERIO_PROTO) || ((serio->type & SERIO_PROTO) > SERIO_MZPP))
return;
 
if (!(sermouse = kmalloc(sizeof(struct sermouse), GFP_KERNEL)))
return;
 
memset(sermouse, 0, sizeof(struct sermouse));
 
init_input_dev(&sermouse->dev);
sermouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
sermouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
sermouse->dev.private = sermouse;
 
serio->private = sermouse;
 
sermouse->type = serio->type & SERIO_PROTO;
c = (serio->type & SERIO_EXTRA) >> 16;
 
if (c & 0x01) set_bit(BTN_MIDDLE, sermouse->dev.keybit);
if (c & 0x02) set_bit(BTN_SIDE, sermouse->dev.keybit);
if (c & 0x04) set_bit(BTN_EXTRA, sermouse->dev.keybit);
if (c & 0x10) set_bit(REL_WHEEL, sermouse->dev.relbit);
if (c & 0x20) set_bit(REL_HWHEEL, sermouse->dev.relbit);
 
sprintf26(sermouse->phys, "%s/input0", serio->phys);
 
sermouse->dev.name = sermouse_protocols[sermouse->type];
sermouse->dev.phys = sermouse->phys;
sermouse->dev.id.bustype = BUS_RS232;
sermouse->dev.id.vendor = sermouse->type;
sermouse->dev.id.product = c;
sermouse->dev.id.version = 0x0100;
 
if (serio_open(serio, dev)) {
kfree(sermouse);
return;
}
 
input_register_device(&sermouse->dev);
printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys);
}
 
static struct serio_dev sermouse_dev = {
.interrupt = sermouse_interrupt,
.connect = sermouse_connect,
.disconnect = sermouse_disconnect
};
 
int __init sermouse_init(void)
{
serio_register_device(&sermouse_dev);
return 0;
}
 
void __exit sermouse_exit(void)
{
serio_unregister_device(&sermouse_dev);
}
 
module_init(sermouse_init);
module_exit(sermouse_exit);
/shark/trunk/drivers/input/mouse/psmouse-base.c
0,0 → 1,676
/*
* PS/2 mouse driver
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*/
 
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
 
#include <linuxcomp.h>
 
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/pm.h>
#include "psmouse.h"
//#include "synaptics.h"
#include "logips2pp.h"
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("PS/2 mouse driver");
MODULE_PARM(psmouse_noext, "1i");
MODULE_PARM_DESC(psmouse_noext, "Disable any protocol extensions. Useful for KVM switches.");
MODULE_PARM(psmouse_resolution, "i");
MODULE_PARM_DESC(psmouse_resolution, "Resolution, in dpi.");
MODULE_PARM(psmouse_rate, "i");
MODULE_PARM_DESC(psmouse_rate, "Report rate, in reports per second.");
MODULE_PARM(psmouse_smartscroll, "i");
MODULE_PARM_DESC(psmouse_smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
MODULE_PARM(psmouse_resetafter, "i");
MODULE_PARM_DESC(psmouse_resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never).");
MODULE_LICENSE("GPL");
 
static int psmouse_noext;
int psmouse_resolution = 200;
unsigned int psmouse_rate = 100;
int psmouse_smartscroll = 1;
unsigned int psmouse_resetafter;
 
static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"};
 
/*
* psmouse_process_packet() analyzes the PS/2 mouse packet contents and
* reports relevant events to the input module.
*/
 
static void psmouse_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
{
struct input_dev *dev = &psmouse->dev;
unsigned char *packet = psmouse->packet;
 
input_regs(dev, regs);
 
/*
* The PS2++ protocol is a little bit complex
*/
 
if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP)
ps2pp_process_packet(psmouse);
 
/*
* Scroll wheel on IntelliMice, scroll buttons on NetMice
*/
 
if (psmouse->type == PSMOUSE_IMPS || psmouse->type == PSMOUSE_GENPS)
input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
 
/*
* Scroll wheel and buttons on IntelliMouse Explorer
*/
 
if (psmouse->type == PSMOUSE_IMEX) {
input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
}
 
/*
* Extra buttons on Genius NewNet 3D
*/
 
if (psmouse->type == PSMOUSE_GENPS) {
input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1);
input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1);
}
 
/*
* Generic PS/2 Mouse
*/
 
input_report_key(dev, BTN_LEFT, packet[0] & 1);
input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
 
input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
 
input_sync(dev);
}
 
/*
* psmouse_interrupt() handles incoming characters, either gathering them into
* packets or passing them to the command routine as command output.
*/
 
static irqreturn_t psmouse_interrupt(struct serio *serio,
unsigned char data, unsigned int flags, struct pt_regs *regs)
{
struct psmouse *psmouse = serio->private;
 
if (psmouse->state == PSMOUSE_IGNORE)
goto out;
 
if (psmouse->acking) {
switch (data) {
case PSMOUSE_RET_ACK:
psmouse->ack = 1;
break;
case PSMOUSE_RET_NAK:
psmouse->ack = -1;
break;
default:
psmouse->ack = 1; /* Workaround for mice which don't ACK the Get ID command */
if (psmouse->cmdcnt)
psmouse->cmdbuf[--psmouse->cmdcnt] = data;
break;
}
psmouse->acking = 0;
goto out;
}
 
if (psmouse->cmdcnt) {
psmouse->cmdbuf[--psmouse->cmdcnt] = data;
goto out;
}
 
if (psmouse->pktcnt && time_after(jiffies26, psmouse->last + HZ/2)) {
printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
psmouse->name, psmouse->phys, psmouse->pktcnt);
psmouse->pktcnt = 0;
}
 
psmouse->last = jiffies26;
psmouse->packet[psmouse->pktcnt++] = data;
 
if (psmouse->packet[0] == PSMOUSE_RET_BAT) {
if (psmouse->pktcnt == 1)
goto out;
if (psmouse->pktcnt == 2) {
if (psmouse->packet[1] == PSMOUSE_RET_ID) {
psmouse->state = PSMOUSE_IGNORE;
serio_rescan(serio);
goto out;
}
if (psmouse->type == PSMOUSE_SYNAPTICS) {
/* neither 0xAA nor 0x00 are valid first bytes
* for a packet in absolute mode
*/
psmouse->pktcnt = 0;
goto out;
}
}
}
 
if (psmouse->type == PSMOUSE_SYNAPTICS) {
/*
* The synaptics driver has its own resync logic,
* so it needs to receive all bytes one at a time.
*/
//!!!synaptics_process_byte(psmouse, regs);
goto out;
}
 
if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
psmouse_process_packet(psmouse, regs);
psmouse->pktcnt = 0;
goto out;
}
out:
return IRQ_HANDLED;
}
 
/*
* psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge.
* It doesn't handle retransmission, though it could - because when there would
* be need for retransmissions, the mouse has to be replaced anyway.
*/
 
static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte)
{
int timeout = 10000; /* 100 msec */
psmouse->ack = 0;
psmouse->acking = 1;
 
if (serio_write(psmouse->serio, byte)) {
psmouse->acking = 0;
return -1;
}
 
while (!psmouse->ack && timeout--) udelay(10);
 
return -(psmouse->ack <= 0);
}
 
/*
* psmouse_command() sends a command and its parameters to the mouse,
* then waits for the response and puts it in the param array.
*/
 
int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
{
int timeout = 500000; /* 500 msec */
int send = (command >> 12) & 0xf;
int receive = (command >> 8) & 0xf;
int i;
 
psmouse->cmdcnt = receive;
 
if (command == PSMOUSE_CMD_RESET_BAT)
timeout = 4000000; /* 4 sec */
 
if (command & 0xff)
if (psmouse_sendbyte(psmouse, command & 0xff))
return (psmouse->cmdcnt = 0) - 1;
 
for (i = 0; i < send; i++)
if (psmouse_sendbyte(psmouse, param[i]))
return (psmouse->cmdcnt = 0) - 1;
 
while (psmouse->cmdcnt && timeout--) {
if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT)
timeout = 100000;
 
if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID &&
psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) {
psmouse->cmdcnt = 0;
break;
}
 
udelay(1);
}
 
for (i = 0; i < receive; i++)
param[i] = psmouse->cmdbuf[(receive - 1) - i];
 
if (psmouse->cmdcnt)
return (psmouse->cmdcnt = 0) - 1;
 
return 0;
}
 
/*
* psmouse_extensions() probes for any extensions to the basic PS/2 protocol
* the mouse may have.
*/
 
static int psmouse_extensions(struct psmouse *psmouse)
{
unsigned char param[4];
 
param[0] = 0;
psmouse->vendor = "Generic";
psmouse->name = "Mouse";
psmouse->model = 0;
 
if (psmouse_noext)
return PSMOUSE_PS2;
 
/*
* Try Synaptics TouchPad magic ID
*/
 
param[0] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
 
if (param[1] == 0x47) {
psmouse->vendor = "Synaptics";
psmouse->name = "TouchPad";
/*if (!synaptics_init(psmouse))
return PSMOUSE_SYNAPTICS;
else*/
return PSMOUSE_PS2;
}
 
/*
* Try Genius NetMouse magic init.
*/
 
param[0] = 3;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
 
if (param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55) {
 
set_bit(BTN_EXTRA, psmouse->dev.keybit);
set_bit(BTN_SIDE, psmouse->dev.keybit);
set_bit(REL_WHEEL, psmouse->dev.relbit);
 
psmouse->vendor = "Genius";
psmouse->name = "Wheel Mouse";
return PSMOUSE_GENPS;
}
 
/*
* Try Logitech magic ID.
*/
 
param[0] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
param[1] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
 
if (param[1]) {
int type = ps2pp_detect_model(psmouse, param);
if (type)
return type;
}
 
/*
* Try IntelliMouse magic init.
*/
 
param[0] = 200;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
param[0] = 100;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
param[0] = 80;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
if (param[0] == 3) {
 
set_bit(REL_WHEEL, psmouse->dev.relbit);
 
/*
* Try IntelliMouse/Explorer magic init.
*/
 
param[0] = 200;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
param[0] = 200;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
param[0] = 80;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
 
if (param[0] == 4) {
 
set_bit(BTN_SIDE, psmouse->dev.keybit);
set_bit(BTN_EXTRA, psmouse->dev.keybit);
 
psmouse->name = "Explorer Mouse";
return PSMOUSE_IMEX;
}
 
psmouse->name = "Wheel Mouse";
return PSMOUSE_IMPS;
}
 
/*
* Okay, all failed, we have a standard mouse here. The number of the buttons
* is still a question, though. We assume 3.
*/
 
return PSMOUSE_PS2;
}
 
/*
* psmouse_probe() probes for a PS/2 mouse.
*/
 
static int psmouse_probe(struct psmouse *psmouse)
{
unsigned char param[2];
 
/*
* First, we check if it's a mouse. It should send 0x00 or 0x03
* in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
*/
 
param[0] = param[1] = 0xa5;
 
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID))
return -1;
 
if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
return -1;
 
/*
* Then we reset and disable the mouse so that it doesn't generate events.
*/
 
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS))
return -1;
 
/*
* And here we try to determine if it has any extensions over the
* basic PS/2 3-button mouse.
*/
 
return psmouse->type = psmouse_extensions(psmouse);
}
 
/*
* Here we set the mouse resolution.
*/
 
static void psmouse_set_resolution(struct psmouse *psmouse)
{
unsigned char param[1];
 
if (psmouse->type == PSMOUSE_PS2PP && psmouse_resolution > 400) {
ps2pp_set_800dpi(psmouse);
return;
}
 
if (!psmouse_resolution || psmouse_resolution >= 200)
param[0] = 3;
else if (psmouse_resolution >= 100)
param[0] = 2;
else if (psmouse_resolution >= 50)
param[0] = 1;
else if (psmouse_resolution)
param[0] = 0;
 
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
}
 
/*
* Here we set the mouse report rate.
*/
 
static void psmouse_set_rate(struct psmouse *psmouse)
{
unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
int i = 0;
 
while (rates[i] > psmouse_rate) i++;
psmouse_command(psmouse, rates + i, PSMOUSE_CMD_SETRATE);
}
 
/*
* psmouse_initialize() initializes the mouse to a sane state.
*/
 
static void psmouse_initialize(struct psmouse *psmouse)
{
unsigned char param[2];
/*
* We set the mouse report rate, resolution and scaling.
*/
 
if (!psmouse_noext) {
psmouse_set_rate(psmouse);
psmouse_set_resolution(psmouse);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
}
 
/*
* We set the mouse into streaming mode.
*/
 
psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
}
 
/*
* psmouse_activate() enables the mouse so that we get motion reports from it.
*/
 
static void psmouse_activate(struct psmouse *psmouse)
{
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
 
psmouse->state = PSMOUSE_ACTIVATED;
}
 
/*
* psmouse_cleanup() resets the mouse into power-on state.
*/
 
static void psmouse_cleanup(struct serio *serio)
{
struct psmouse *psmouse = serio->private;
unsigned char param[2];
psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT);
}
 
/*
* psmouse_disconnect() closes and frees.
*/
 
static void psmouse_disconnect(struct serio *serio)
{
struct psmouse *psmouse = serio->private;
 
psmouse->state = PSMOUSE_IGNORE;
//!!!synaptics_disconnect(psmouse);
input_unregister_device(&psmouse->dev);
serio_close(serio);
kfree(psmouse);
}
 
/*
* Reinitialize mouse hardware after software suspend.
*/
 
static int psmouse_pm_callback(struct pm_dev *dev, pm_request_t request, void *data)
{
struct psmouse *psmouse = dev->data;
struct serio_dev *ser_dev = psmouse->serio->dev;
 
//!!!synaptics_disconnect(psmouse);
 
/* We need to reopen the serio port to reinitialize the i8042 controller */
serio_close(psmouse->serio);
serio_open(psmouse->serio, ser_dev);
 
/* Probe and re-initialize the mouse */
psmouse_probe(psmouse);
psmouse_initialize(psmouse);
//!!!synaptics_pt_init(psmouse);
psmouse_activate(psmouse);
 
return 0;
}
 
/*
* psmouse_connect() is a callback from the serio module when
* an unhandled serio port is found.
*/
 
static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
{
struct psmouse *psmouse;
struct pm_dev *pmdev;
if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
(serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
return;
 
if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
return;
 
memset(psmouse, 0, sizeof(struct psmouse));
 
init_input_dev(&psmouse->dev);
psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
 
psmouse->state = PSMOUSE_NEW_DEVICE;
psmouse->serio = serio;
psmouse->dev.private = psmouse;
 
serio->private = psmouse;
 
if (serio_open(serio, dev)) {
kfree(psmouse);
return;
}
 
if (psmouse_probe(psmouse) <= 0) {
serio_close(serio);
kfree(psmouse);
return;
}
pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, psmouse_pm_callback);
if (pmdev) {
psmouse->dev.pm_dev = pmdev;
pmdev->data = psmouse;
}
 
sprintf26(psmouse->devname, "%s %s %s",
psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
sprintf26(psmouse->phys, "%s/input0",
serio->phys);
 
psmouse->dev.name = psmouse->devname;
psmouse->dev.phys = psmouse->phys;
psmouse->dev.id.bustype = BUS_I8042;
psmouse->dev.id.vendor = 0x0002;
psmouse->dev.id.product = psmouse->type;
psmouse->dev.id.version = psmouse->model;
 
input_register_device(&psmouse->dev);
printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
 
psmouse_initialize(psmouse);
 
//!!!synaptics_pt_init(psmouse);
 
psmouse_activate(psmouse);
}
 
static struct serio_dev psmouse_dev = {
.interrupt = psmouse_interrupt,
.connect = psmouse_connect,
.disconnect = psmouse_disconnect,
.cleanup = psmouse_cleanup,
};
 
#ifndef MODULE
static int __init psmouse_noext_setup(char *str)
{
psmouse_noext = 1;
return 1;
}
 
static int __init psmouse_resolution_setup(char *str)
{
get_option(&str, &psmouse_resolution);
return 1;
}
 
static int __init psmouse_smartscroll_setup(char *str)
{
get_option(&str, &psmouse_smartscroll);
return 1;
}
 
static int __init psmouse_resetafter_setup(char *str)
{
get_option(&str, &psmouse_resetafter);
return 1;
}
 
static int __init psmouse_rate_setup(char *str)
{
get_option(&str, &psmouse_rate);
return 1;
}
 
__setup("psmouse_noext", psmouse_noext_setup);
__setup("psmouse_resolution=", psmouse_resolution_setup);
__setup("psmouse_smartscroll=", psmouse_smartscroll_setup);
__setup("psmouse_resetafter=", psmouse_resetafter_setup);
__setup("psmouse_rate=", psmouse_rate_setup);
 
#endif
 
int __init psmouse_init(void)
{
serio_register_device(&psmouse_dev);
return 0;
}
 
void __exit psmouse_exit(void)
{
serio_unregister_device(&psmouse_dev);
}
 
module_init(psmouse_init);
module_exit(psmouse_exit);
/shark/trunk/drivers/input/mouse/logips2pp.h
0,0 → 1,17
/*
* Logitech PS/2++ mouse driver header
*
* Copyright (c) 2003 Vojtech Pavlik <vojtech@suse.cz>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
 
#ifndef _LOGIPS2PP_H
#define _LOGIPS2PP_H
struct psmouse;
void ps2pp_process_packet(struct psmouse *psmouse);
void ps2pp_set_800dpi(struct psmouse *psmouse);
int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param);
#endif
/shark/trunk/drivers/input/shark_input.c
0,0 → 1,246
/*
* Project: S.Ha.R.K.
*
* Coordinators:
* Giorgio Buttazzo <giorgio@sssup.it>
* Paolo Gai <pj@gandalf.sssup.it>
*
* Authors :
* Mauro Marinoni <mauro.marinoni@unipv.it>
*
*
* ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
*
* http://www.sssup.it
* http://retis.sssup.it
* http://shark.sssup.it
*/
 
#include <kernel/func.h>
 
/* System */
extern int input_init(void);
extern int input_exit(void);
 
extern int serio_init(void);
extern int serio_exit(void);
 
/* Controllers */
extern int i8042_init(void);
extern int i8042_exit(void);
 
/*extern int serport_init(void);
extern int serport_exit(void);*/
 
/* Devices */
extern int atkbd_init(void);
extern int atkbd_exit(void);
 
extern int pcspkr_init(void);
extern int pcspkr_exit(void);
 
extern int psmouse_init(void);
extern int psmouse_exit(void);
 
extern int ns558_init(void);
extern int ns558_exit(void);
 
extern int analog_init(void);
extern int analog_exit(void);
 
extern int joydump_init(void);
extern int joydump_exit(void);
 
/* Handlers */
extern int evbug_init(void);
extern int evbug_exit(void);
 
/*extern int evdev_init(void);
extern int evdev_exit(void);
 
extern int mousedev_init(void);
extern int mousedev_exit(void);
 
extern int joydev_init(void);
extern int joydev_exit(void);*/
 
int input_initialized = 0;
 
/* Init the Linux Input Layer */
int INPUT26_init() {
 
int ret;
 
ret = input_init();
if (ret) {
printk(KERN_DEBUG "Input_Init return: %d\n", ret);
return -1;
}
 
ret = serio_init();
if (ret) {
printk(KERN_DEBUG "Serio_Init return: %d\n", ret);
return -1;
}
 
ret = i8042_init();
if (ret) {
printk(KERN_DEBUG "i8042_Init return: %d\n", ret);
return -1;
}
 
/* TODO
ret = serport_init();
if (ret) {
printk(KERN_DEBUG "SerPort_Init return: %d\n", ret);
return -1;
} */
 
input_initialized = 1;
 
return ret;
}
 
int INPUT26_close() {
 
if (input_initialized) {
i8042_exit();
serio_exit();
input_exit();
}
 
return 0;
}
 
/* Init the Linux Keyboard Driver */
int KEYB26_init() {
 
int ret;
 
if (!input_initialized)
if (INPUT26_init()) {
printk(KERN_ERR "Unable to open Input SubSystem.\n");
return -1;
}
 
printk(KERN_DEBUG "AtKbd_Init start.\n");
ret = atkbd_init();
if (ret) {
printk(KERN_DEBUG "AtKbd_Init return: %d\n", ret);
return -1;
}
 
return 0;
}
 
int KEYB26_close() {
 
atkbd_exit();
return 0;
}
 
/* Init the Linux Speaker Driver */
int SPEAK26_init() {
 
int ret;
 
if (!input_initialized)
if (INPUT26_init()) {
printk(KERN_ERR "Unable to open Input SubSystem.\n");
return -1;
}
 
ret = pcspkr_init();
if (ret) {
printk(KERN_DEBUG "PcSpkr_Init return: %d\n", ret);
return -1;
}
 
return 0;
}
 
int SPEAK26_close() {
 
pcspkr_exit();
return 0;
}
 
/* Init the Linux Speaker Driver */
int MOUSE26_init() {
 
int ret;
 
if (!input_initialized)
if (INPUT26_init()) {
printk(KERN_ERR "Unable to open Input SubSystem.\n");
return -1;
}
 
ret = psmouse_init();
if (ret) {
printk(KERN_DEBUG "PsMouse_Init return: %d\n", ret);
return -1;
}
 
return 0;
}
 
int MOUSE26_close() {
 
psmouse_exit();
return 0;
}
 
/* Init the Linux Speaker Driver */
/*int joystick_init() {
 
int ret;
 
if (!input_initialized)
if (shark_input_init()) {
printk(KERN_ERR "Unable to open Input SubSystem.\n");
return -1;
}
 
ret = ns558_init();
if (ret) {
printk(KERN_DEBUG "Gameport_Init return: %d\n", ret);
return -1;
}
 
//ret = analog_init();
ret = joydump_init();
if (ret) {
printk(KERN_DEBUG "Joystick_Init return: %d\n", ret);
return -1;
}
 
return 0;
}
 
int joystick_exit() {
 
//analog_exit();
joydump_exit();
ns558_exit();
return 0;
}*/
 
int events_init() {
//mousedev_init();
//joydev_init();
//evdev_init();
evbug_init();
 
return 0;
}
 
int events_exit() {
evbug_exit();
//evdev_exit();
//joydev_exit();
//mousedev_exit();
 
return 0;
}
 
/shark/trunk/drivers/input/mousedev.c
0,0 → 1,575
/*
* Input driver to ExplorerPS/2 device driver module.
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
 
#include <linuxcomp.h>
 
#define MOUSEDEV_MINOR_BASE 32
#define MOUSEDEV_MINORS 32
#define MOUSEDEV_MIX 31
 
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/config.h>
#include <linux/smp_lock.h>
#include <linux/random.h>
#include <linux/major.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
#include <linux/miscdevice.h>
#endif
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces");
MODULE_LICENSE("GPL");
 
#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
 
struct mousedev {
int exist;
int open;
int minor;
int misc;
char name[16];
wait_queue_head_t wait;
struct list_head list;
struct input_handle handle;
};
 
struct mousedev_list {
struct fasync_struct *fasync;
struct mousedev *mousedev;
struct list_head node;
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;
};
 
#define MOUSEDEV_SEQ_LEN 6
 
static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
 
static struct input_handler mousedev_handler;
 
static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
static struct mousedev mousedev_mix;
 
static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X;
static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
 
static void mousedev_abs_event(struct input_handle *handle, struct mousedev_list *list, 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 mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL };
struct mousedev **mousedev = mousedevs;
struct mousedev_list *list;
int index, wake;
 
while (*mousedev) {
 
wake = 0;
 
list_for_each_entry(list, &(*mousedev)->list, node)
switch (type) {
case EV_ABS:
mousedev_abs_event(handle, list, 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: if (list->mode) 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: if (list->mode == 2) { index = 4; break; }
case BTN_STYLUS:
case BTN_1:
case BTN_RIGHT: index = 1; break;
case BTN_3:
case BTN_BACK:
case BTN_SIDE: if (list->mode == 2) { 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:
list->ready = 1;
kill_fasync(&list->fasync, SIGIO, POLL_IN);
wake = 1;
break;
}
}
 
if (wake)
wake_up_interruptible(&((*mousedev)->wait));
 
mousedev++;
}
}
 
static int mousedev_fasync(int fd, struct file *file, int on)
{
int retval;
struct mousedev_list *list = file->private_data;
retval = fasync_helper(fd, file, on, &list->fasync);
return retval < 0 ? retval : 0;
}
 
static void mousedev_free(struct mousedev *mousedev)
{
devfs_remove("input/mouse%d", mousedev->minor);
mousedev_table[mousedev->minor] = NULL;
kfree(mousedev);
}
 
static int mixdev_release(void)
{
struct input_handle *handle;
 
list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
struct mousedev *mousedev = handle->private;
 
if (!mousedev->open) {
if (mousedev->exist)
input_close_device(&mousedev->handle);
else
mousedev_free(mousedev);
}
}
 
return 0;
}
 
static int mousedev_release(struct inode * inode, struct file * file)
{
struct mousedev_list *list = file->private_data;
 
mousedev_fasync(-1, file, 0);
 
list_del(&list->node);
 
if (!--list->mousedev->open) {
if (list->mousedev->minor == MOUSEDEV_MIX)
return mixdev_release();
 
if (!mousedev_mix.open) {
if (list->mousedev->exist)
input_close_device(&list->mousedev->handle);
else
mousedev_free(list->mousedev);
}
}
kfree(list);
return 0;
}
 
static int mousedev_open(struct inode * inode, struct file * file)
{
struct mousedev_list *list;
struct input_handle *handle;
struct mousedev *mousedev;
int i;
 
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (imajor(inode) == MISC_MAJOR)
i = MOUSEDEV_MIX;
else
#endif
i = iminor(inode) - MOUSEDEV_MINOR_BASE;
 
if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
return -ENODEV;
 
if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
return -ENOMEM;
memset(list, 0, sizeof(struct mousedev_list));
 
list->mousedev = mousedev_table[i];
list_add_tail(&list->node, &mousedev_table[i]->list);
file->private_data = list;
 
if (!list->mousedev->open++) {
if (list->mousedev->minor == MOUSEDEV_MIX) {
list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
mousedev = handle->private;
if (!mousedev->open && mousedev->exist)
input_open_device(handle);
}
} else
if (!mousedev_mix.open && list->mousedev->exist)
input_open_device(&list->mousedev->handle);
}
 
return 0;
}
 
static void mousedev_packet(struct mousedev_list *list, unsigned char off)
{
list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07);
list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx));
list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy));
list->dx -= list->ps2[off + 1];
list->dy -= list->ps2[off + 2];
list->bufsiz = off + 3;
 
if (list->mode == 2) {
list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : list->dz));
list->dz -= list->ps2[off + 3];
list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1);
list->bufsiz++;
}
if (list->mode == 1) {
list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz));
list->dz -= list->ps2[off + 3];
list->bufsiz++;
}
 
if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0;
list->buffer = list->bufsiz;
}
 
 
static ssize_t mousedev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
{
struct mousedev_list *list = file->private_data;
unsigned char c;
unsigned int i;
 
for (i = 0; i < count; i++) {
 
if (get_user(c, buffer + i))
return -EFAULT;
 
if (c == mousedev_imex_seq[list->imexseq]) {
if (++list->imexseq == MOUSEDEV_SEQ_LEN) {
list->imexseq = 0;
list->mode = 2;
}
} else list->imexseq = 0;
 
if (c == mousedev_imps_seq[list->impsseq]) {
if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
list->impsseq = 0;
list->mode = 1;
}
} else list->impsseq = 0;
 
list->ps2[0] = 0xfa;
list->bufsiz = 1;
 
switch (c) {
 
case 0xeb: /* Poll */
mousedev_packet(list, 1);
break;
 
case 0xf2: /* Get ID */
switch (list->mode) {
case 0: list->ps2[1] = 0; break;
case 1: list->ps2[1] = 3; break;
case 2: list->ps2[1] = 4; break;
}
list->bufsiz = 2;
break;
 
case 0xe9: /* Get info */
list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200;
list->bufsiz = 4;
break;
 
case 0xff: /* Reset */
list->impsseq = 0;
list->imexseq = 0;
list->mode = 0;
list->ps2[0] = 0xaa;
list->ps2[1] = 0x00;
list->bufsiz = 2;
break;
}
 
list->buffer = list->bufsiz;
}
 
kill_fasync(&list->fasync, SIGIO, POLL_IN);
 
wake_up_interruptible(&list->mousedev->wait);
return count;
}
 
static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
{
struct mousedev_list *list = file->private_data;
int retval = 0;
 
if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
 
retval = wait_event_interruptible(list->mousedev->wait, list->ready || list->buffer);
 
if (retval)
return retval;
 
if (!list->buffer && list->ready)
mousedev_packet(list, 0);
 
if (count > list->buffer)
count = list->buffer;
 
list->buffer -= count;
 
if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count))
return -EFAULT;
 
return count;
}
 
/* No kernel lock - fine */
static unsigned int mousedev_poll(struct file *file, poll_table *wait)
{
struct mousedev_list *list = file->private_data;
poll_wait(file, &list->mousedev->wait, wait);
if (list->ready || list->buffer)
return POLLIN | POLLRDNORM;
return 0;
}
 
struct file_operations mousedev_fops = {
.owner = THIS_MODULE,
.read = mousedev_read,
.write = mousedev_write,
.poll = mousedev_poll,
.open = mousedev_open,
.release = mousedev_release,
.fasync = mousedev_fasync,
};
 
static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
{
struct mousedev *mousedev;
int minor = 0;
 
for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
if (minor == MOUSEDEV_MINORS) {
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
return NULL;
}
 
if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
return NULL;
memset(mousedev, 0, sizeof(struct mousedev));
 
INIT_LIST_HEAD(&mousedev->list);
init_waitqueue_head(&mousedev->wait);
 
mousedev->minor = minor;
mousedev->exist = 1;
mousedev->handle.dev = dev;
mousedev->handle.name = mousedev->name;
mousedev->handle.handler = handler;
mousedev->handle.private = mousedev;
sprintf26(mousedev->name, "mouse%d", minor);
 
if (mousedev_mix.open)
input_open_device(&mousedev->handle);
 
mousedev_table[minor] = mousedev;
 
devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor);
 
return &mousedev->handle;
}
 
static void mousedev_disconnect(struct input_handle *handle)
{
struct mousedev *mousedev = handle->private;
 
mousedev->exist = 0;
 
if (mousedev->open) {
input_close_device(handle);
} else {
if (mousedev_mix.open)
input_close_device(handle);
mousedev_free(mousedev);
}
}
 
static struct input_device_id mousedev_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, mousedev_ids);
static struct input_handler mousedev_handler = {
.event = mousedev_event,
.connect = mousedev_connect,
.disconnect = mousedev_disconnect,
.fops = &mousedev_fops,
.minor = MOUSEDEV_MINOR_BASE,
.name = "mousedev",
.id_table = mousedev_ids,
};
 
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
static struct miscdevice psaux_mouse = {
PSMOUSE_MINOR, "psaux", &mousedev_fops
};
#endif
 
/*static*/ int __init mousedev_init(void)
{
input_register_handler(&mousedev_handler);
 
memset(&mousedev_mix, 0, sizeof(struct mousedev));
INIT_LIST_HEAD(&mousedev_mix.list);
init_waitqueue_head(&mousedev_mix.wait);
mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
mousedev_mix.exist = 1;
mousedev_mix.minor = MOUSEDEV_MIX;
 
devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX),
S_IFCHR|S_IRUGO|S_IWUSR, "input/mice");
 
 
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (!(mousedev_mix.misc = !misc_register(&psaux_mouse)))
printk(KERN_WARNING "mice: could not misc_register the device\n");
#endif
 
printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
 
return 0;
}
 
/*static*/ void __exit mousedev_exit(void)
{
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (mousedev_mix.misc)
misc_deregister(&psaux_mouse);
#endif
devfs_remove("input/mice");
input_unregister_handler(&mousedev_handler);
}
 
module_init(mousedev_init);
module_exit(mousedev_exit);
 
MODULE_PARM(xres, "i");
MODULE_PARM_DESC(xres, "Horizontal screen resolution");
MODULE_PARM(yres, "i");
MODULE_PARM_DESC(yres, "Vertical screen resolution");
/shark/trunk/drivers/input/evbug.c
0,0 → 1,105
/*
* $Id: evbug.c,v 1.1 2004-03-08 18:47:36 giacomo Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
 
/*
* Input driver event debug module - dumps all events into syslog
*/
 
/*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
 
#include <linuxcomp.h>
 
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/device.h>
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Input driver event debug module");
MODULE_LICENSE("GPL");
 
static char evbug_name[] = "evbug";
 
static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value);
}
 
static struct input_handle *evbug_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 = evbug_name;
 
input_open_device(handle);
 
printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys);
 
return handle;
}
 
static void evbug_disconnect(struct input_handle *handle)
{
printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);
input_close_device(handle);
 
kfree(handle);
}
 
static struct input_device_id evbug_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
 
MODULE_DEVICE_TABLE(input, evbug_ids);
static struct input_handler evbug_handler = {
.event = evbug_event,
.connect = evbug_connect,
.disconnect = evbug_disconnect,
.name = "evbug",
.id_table = evbug_ids,
};
 
int __init evbug_init(void)
{
input_register_handler(&evbug_handler);
return 0;
}
 
void __exit evbug_exit(void)
{
input_unregister_handler(&evbug_handler);
}
 
module_init(evbug_init);
module_exit(evbug_exit);
/shark/trunk/drivers/input/evdev.c
0,0 → 1,481
/*
* Event char devices, giving access to raw input device events.
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
 
#include <linuxcomp.h>
 
#define EVDEV_MINOR_BASE 64
#define EVDEV_MINORS 32
#define EVDEV_BUFFER_SIZE 64
 
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/major.h>
#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
 
struct evdev {
int exist;
int open;
int minor;
char name[16];
struct input_handle handle;
wait_queue_head_t wait;
struct evdev_list *grab;
struct list_head list;
};
 
struct evdev_list {
struct input_event buffer[EVDEV_BUFFER_SIZE];
int head;
int tail;
struct fasync_struct *fasync;
struct evdev *evdev;
struct list_head node;
};
 
static struct evdev *evdev_table[EVDEV_MINORS];
 
static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private;
struct evdev_list *list;
 
if (evdev->grab) {
list = evdev->grab;
 
do_gettimeofday(&list->buffer[list->head].time);
list->buffer[list->head].type = type;
list->buffer[list->head].code = code;
list->buffer[list->head].value = value;
list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
 
kill_fasync(&list->fasync, SIGIO, POLL_IN);
} else
list_for_each_entry(list, &evdev->list, node) {
 
do_gettimeofday(&list->buffer[list->head].time);
list->buffer[list->head].type = type;
list->buffer[list->head].code = code;
list->buffer[list->head].value = value;
list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
 
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
 
wake_up_interruptible(&evdev->wait);
}
 
static int evdev_fasync(int fd, struct file *file, int on)
{
int retval;
struct evdev_list *list = file->private_data;
retval = fasync_helper(fd, file, on, &list->fasync);
return retval < 0 ? retval : 0;
}
 
static int evdev_flush(struct file * file)
{
struct evdev_list *list = file->private_data;
if (!list->evdev->exist) return -ENODEV;
return input_flush_device(&list->evdev->handle, file);
}
 
static void evdev_free(struct evdev *evdev)
{
devfs_remove("input/event%d", evdev->minor);
evdev_table[evdev->minor] = NULL;
kfree(evdev);
}
 
static int evdev_release(struct inode * inode, struct file * file)
{
struct evdev_list *list = file->private_data;
 
if (list->evdev->grab == list) {
input_release_device(&list->evdev->handle);
list->evdev->grab = NULL;
}
 
evdev_fasync(-1, file, 0);
list_del(&list->node);
 
if (!--list->evdev->open) {
if (list->evdev->exist)
input_close_device(&list->evdev->handle);
else
evdev_free(list->evdev);
}
 
kfree(list);
return 0;
}
 
static int evdev_open(struct inode * inode, struct file * file)
{
struct evdev_list *list;
int i = iminor(inode) - EVDEV_MINOR_BASE;
int accept_err;
 
if (i >= EVDEV_MINORS || !evdev_table[i])
return -ENODEV;
 
if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file)))
return accept_err;
 
if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
return -ENOMEM;
memset(list, 0, sizeof(struct evdev_list));
 
list->evdev = evdev_table[i];
list_add_tail(&list->node, &evdev_table[i]->list);
file->private_data = list;
 
if (!list->evdev->open++)
if (list->evdev->exist)
input_open_device(&list->evdev->handle);
 
return 0;
}
 
static ssize_t evdev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
{
struct evdev_list *list = file->private_data;
struct input_event event;
int retval = 0;
 
if (!list->evdev->exist) return -ENODEV;
 
while (retval < count) {
 
if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
return -EFAULT;
input_event(list->evdev->handle.dev, event.type, event.code, event.value);
retval += sizeof(struct input_event);
}
 
return retval;
}
 
static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
{
struct evdev_list *list = file->private_data;
int retval;
 
if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
 
retval = wait_event_interruptible(list->evdev->wait,
list->head != list->tail && list->evdev->exist);
 
if (retval)
return retval;
 
if (!list->evdev->exist)
return -ENODEV;
 
while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
if (copy_to_user(buffer + retval, list->buffer + list->tail,
sizeof(struct input_event))) return -EFAULT;
list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
retval += sizeof(struct input_event);
}
 
return retval;
}
 
/* No kernel lock - fine */
static unsigned int evdev_poll(struct file *file, poll_table *wait)
{
struct evdev_list *list = file->private_data;
poll_wait(file, &list->evdev->wait, wait);
if (list->head != list->tail)
return POLLIN | POLLRDNORM;
return 0;
}
 
static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct evdev_list *list = file->private_data;
struct evdev *evdev = list->evdev;
struct input_dev *dev = evdev->handle.dev;
struct input_absinfo abs;
int i, t, u, v;
 
if (!evdev->exist) return -ENODEV;
 
switch (cmd) {
 
case EVIOCGVERSION:
return put_user(EV_VERSION, (int *) arg);
 
case EVIOCGID:
return copy_to_user((void *) arg, &dev->id, sizeof(struct input_id)) ? -EFAULT : 0;
case EVIOCGKEYCODE:
if (get_user(t, ((int *) arg) + 0)) return -EFAULT;
if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
if (put_user(INPUT_KEYCODE(dev, t), ((int *) arg) + 1)) return -EFAULT;
return 0;
 
case EVIOCSKEYCODE:
if (get_user(t, ((int *) arg) + 0)) return -EFAULT;
if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
if (get_user(v, ((int *) arg) + 1)) return -EFAULT;
u = INPUT_KEYCODE(dev, t);
INPUT_KEYCODE(dev, t) = v;
for (i = 0; i < dev->keycodemax; i++) if (v == u) break;
if (i == dev->keycodemax) clear_bit(u, dev->keybit);
set_bit(v, dev->keybit);
return 0;
 
case EVIOCSFF:
if (dev->upload_effect) {
struct ff_effect effect;
int err;
 
if (copy_from_user((void*)(&effect), (void*)arg, sizeof(effect)))
return -EFAULT;
err = dev->upload_effect(dev, &effect);
if (put_user(effect.id, &(((struct ff_effect*)arg)->id)))
return -EFAULT;
return err;
}
else return -ENOSYS;
 
case EVIOCRMFF:
if (dev->erase_effect) {
return dev->erase_effect(dev, (int)arg);
}
else return -ENOSYS;
 
case EVIOCGEFFECTS:
if (put_user(dev->ff_effects_max, (int*) arg))
return -EFAULT;
return 0;
 
case EVIOCGRAB:
if (arg) {
if (evdev->grab)
return -EBUSY;
if (input_grab_device(&evdev->handle))
return -EBUSY;
evdev->grab = list;
return 0;
} else {
if (evdev->grab != list)
return -EINVAL;
input_release_device(&evdev->handle);
evdev->grab = NULL;
return 0;
}
 
default:
 
if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
return -EINVAL;
 
if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
 
long *bits;
int len;
 
switch (_IOC_NR(cmd) & EV_MAX) {
case 0: bits = dev->evbit; len = EV_MAX; break;
case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
case EV_REL: bits = dev->relbit; len = REL_MAX; break;
case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
default: return -EINVAL;
}
len = NBITS(len) * sizeof(long);
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, bits, len) ? -EFAULT : len;
}
 
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
int len;
len = NBITS(KEY_MAX) * sizeof(long);
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, dev->key, len) ? -EFAULT : len;
}
 
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
int len;
len = NBITS(LED_MAX) * sizeof(long);
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, dev->led, len) ? -EFAULT : len;
}
 
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
int len;
len = NBITS(SND_MAX) * sizeof(long);
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, dev->snd, len) ? -EFAULT : len;
}
 
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
int len;
if (!dev->name) return -ENOENT;
len = strlen(dev->name) + 1;
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, dev->name, len) ? -EFAULT : len;
}
 
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
int len;
if (!dev->phys) return -ENOENT;
len = strlen(dev->phys) + 1;
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, dev->phys, len) ? -EFAULT : len;
}
 
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
int len;
if (!dev->uniq) return -ENOENT;
len = strlen(dev->uniq) + 1;
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
return copy_to_user((char *) arg, dev->uniq, len) ? -EFAULT : len;
}
 
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
 
int t = _IOC_NR(cmd) & ABS_MAX;
 
abs.value = dev->abs[t];
abs.minimum = dev->absmin[t];
abs.maximum = dev->absmax[t];
abs.fuzz = dev->absfuzz[t];
abs.flat = dev->absflat[t];
 
if (copy_to_user((void *) arg, &abs, sizeof(struct input_absinfo)))
return -EFAULT;
 
return 0;
}
 
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
 
int t = _IOC_NR(cmd) & ABS_MAX;
 
if (copy_from_user(&abs, (void *) arg, sizeof(struct input_absinfo)))
return -EFAULT;
 
dev->abs[t] = abs.value;
dev->absmin[t] = abs.minimum;
dev->absmax[t] = abs.maximum;
dev->absfuzz[t] = abs.fuzz;
dev->absflat[t] = abs.flat;
 
return 0;
}
}
return -EINVAL;
}
 
static struct file_operations evdev_fops = {
.owner = THIS_MODULE,
.read = evdev_read,
.write = evdev_write,
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
.ioctl = evdev_ioctl,
.fasync = evdev_fasync,
.flush = evdev_flush
};
 
static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
{
struct evdev *evdev;
int minor;
 
for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: no more free evdev devices\n");
return NULL;
}
 
if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))
return NULL;
memset(evdev, 0, sizeof(struct evdev));
 
INIT_LIST_HEAD(&evdev->list);
init_waitqueue_head(&evdev->wait);
 
evdev->exist = 1;
evdev->minor = minor;
evdev->handle.dev = dev;
evdev->handle.name = evdev->name;
evdev->handle.handler = handler;
evdev->handle.private = evdev;
sprintf26(evdev->name, "event%d", minor);
 
evdev_table[minor] = evdev;
 
devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
S_IFCHR|S_IRUGO|S_IWUSR, "input/event%d", minor);
 
return &evdev->handle;
}
 
static void evdev_disconnect(struct input_handle *handle)
{
struct evdev *evdev = handle->private;
 
evdev->exist = 0;
 
if (evdev->open) {
input_close_device(handle);
wake_up_interruptible(&evdev->wait);
} else
evdev_free(evdev);
}
 
static struct input_device_id evdev_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
 
MODULE_DEVICE_TABLE(input, evdev_ids);
 
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
 
/*static*/ int __init evdev_init(void)
{
input_register_handler(&evdev_handler);
return 0;
}
 
/*static*/ void __exit evdev_exit(void)
{
input_unregister_handler(&evdev_handler);
}
 
module_init(evdev_init);
module_exit(evdev_exit);
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Input driver event char devices");
MODULE_LICENSE("GPL");
/shark/trunk/drivers/input/misc/pcspkr.c
0,0 → 1,96
/*
* PC Speaker beeper driver for Linux
*
* Copyright (c) 2002 Vojtech Pavlik
* Copyright (c) 1992 Orest Zborowski
*
*/
 
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation
*/
 
#include <linuxcomp.h>
 
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <asm/io.h>
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("PC Speaker beeper driver");
MODULE_LICENSE("GPL");
 
static char pcspkr_name[] = "PC Speaker";
static char pcspkr_phys[] = "isa0061/input0";
static struct input_dev pcspkr_dev;
 
spinlock_t i8253_beep_lock = SPIN_LOCK_UNLOCKED;
 
static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
unsigned int count = 0;
unsigned long flags;
 
if (type != EV_SND)
return -1;
 
switch (code) {
case SND_BELL: if (value) value = 1000;
case SND_TONE: break;
default: return -1;
}
 
if (value > 20 && value < 32767)
count = CLOCK_TICK_RATE / value;
spin_lock_irqsave(&i8253_beep_lock, flags);
 
if (count) {
/* enable counter 2 */
outb_p(inb_p(0x61) | 3, 0x61);
/* set command for counter 2, 2 byte write */
outb_p(0xB6, 0x43);
/* select desired HZ */
outb_p(count & 0xff, 0x42);
outb((count >> 8) & 0xff, 0x42);
} else {
/* disable counter 2 */
outb(inb_p(0x61) & 0xFC, 0x61);
}
 
spin_unlock_irqrestore(&i8253_beep_lock, flags);
 
return 0;
}
 
/*static*/ int __init pcspkr_init(void)
{
pcspkr_dev.evbit[0] = BIT(EV_SND);
pcspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
pcspkr_dev.event = pcspkr_event;
 
pcspkr_dev.name = pcspkr_name;
pcspkr_dev.phys = pcspkr_phys;
pcspkr_dev.id.bustype = BUS_ISA;
pcspkr_dev.id.vendor = 0x001f;
pcspkr_dev.id.product = 0x0001;
pcspkr_dev.id.version = 0x0100;
 
input_register_device(&pcspkr_dev);
 
printk(KERN_INFO "input: %s\n", pcspkr_name);
 
return 0;
}
 
/*static*/ void __exit pcspkr_exit(void)
{
input_unregister_device(&pcspkr_dev);
}
 
module_init(pcspkr_init);
module_exit(pcspkr_exit);
/shark/trunk/drivers/input/cmdline.c
0,0 → 1,122
/*
* linux/lib/cmdline.c
* Helper functions generally used for parsing kernel command line
* and module options.
*
* Code and copyrights come from init/main.c and arch/i386/kernel/setup.c.
*
* This source code is licensed under the GNU General Public License,
* Version 2. See the file COPYING for more details.
*
* GNU Indent formatting options for this file: -kr -i8 -npsl -pcs
*
*/
 
#include <linuxcomp.h>
 
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
 
 
/**
* get_option - Parse integer from an option string
* @str: option string
* @pint: (output) integer value parsed from @str
*
* Read an int from an option string; if available accept a subsequent
* comma as well.
*
* Return values:
* 0 : no int in string
* 1 : int found, no subsequent comma
* 2 : int found including a subsequent comma
*/
 
int get_option (char **str, int *pint)
{
char *cur = *str;
 
if (!cur || !(*cur))
return 0;
*pint = simple_strtol (cur, str, 0);
if (cur == *str)
return 0;
if (**str == ',') {
(*str)++;
return 2;
}
 
return 1;
}
 
/**
* get_options - Parse a string into a list of integers
* @str: String to be parsed
* @nints: size of integer array
* @ints: integer array
*
* This function parses a string containing a comma-separated
* list of integers. The parse halts when the array is
* full, or when no more numbers can be retrieved from the
* string.
*
* Return value is the character in the string which caused
* the parse to end (typically a null terminator, if @str is
* completely parseable).
*/
char *get_options(const char *str, int nints, int *ints)
{
int res, i = 1;
 
while (i < nints) {
res = get_option ((char **)&str, ints + i);
if (res == 0)
break;
i++;
if (res == 1)
break;
}
ints[0] = i - 1;
return (char *)str;
}
 
/**
* memparse - parse a string with mem suffixes into a number
* @ptr: Where parse begins
* @retptr: (output) Pointer to next char after parse completes
*
* Parses a string into a number. The number stored at @ptr is
* potentially suffixed with %K (for kilobytes, or 1024 bytes),
* %M (for megabytes, or 1048576 bytes), or %G (for gigabytes, or
* 1073741824). If the number is suffixed with K, M, or G, then
* the return value is the number multiplied by one kilobyte, one
* megabyte, or one gigabyte, respectively.
*/
 
unsigned long long memparse (char *ptr, char **retptr)
{
unsigned long long ret = simple_strtoull (ptr, retptr, 0);
 
switch (**retptr) {
case 'G':
case 'g':
ret <<= 10;
case 'M':
case 'm':
ret <<= 10;
case 'K':
case 'k':
ret <<= 10;
(*retptr)++;
default:
break;
}
return ret;
}
 
 
EXPORT_SYMBOL(memparse);
EXPORT_SYMBOL(get_option);
EXPORT_SYMBOL(get_options);
/shark/trunk/drivers/input/makefile
0,0 → 1,28
# PCI support from linux 2.6.0
 
ifndef BASE
BASE=../..
endif
 
include $(BASE)/config/config.mk
 
LIBRARY = input
 
OBJS_PATH = $(BASE)/drivers/input
 
OBJS = input.o cmdline.o evbug.o\
serio/serio.o serio/i8042.o\
mouse/psmouse-base.o mouse/logips2pp.o\
keyboard/atkbd.o\
misc/pcspkr.o\
shark_input.o
 
OTHERINCL += -I$(BASE)/drivers/linuxc26/include
 
C_OPT += -D__KERNEL__
 
include $(BASE)/config/lib.mk
 
clean::
rm -f $(OBJS)
 
/shark/trunk/drivers/input/makefile.full
0,0 → 1,30
# PCI support from linux 2.6.0
 
ifndef BASE
BASE=../..
endif
 
include $(BASE)/config/config.mk
 
LIBRARY = input
 
OBJS_PATH = $(BASE)/drivers/input
 
OBJS = input.o cmdline.o evbug.o evdev.o mousedev.o joydev.o\
serio/serio.o serio/i8042.o serio/serport.o\
mouse/psmouse-base.o mouse/logips2pp.o mouse/sermouse.o\
keyboard/atkbd.o\
misc/pcspkr.o\
gameport/gameport.o gameport/ns558.o\
joystick/analog.o joystick/joydump.o\
shark_input.o
 
OTHERINCL += -I$(BASE)/drivers/linuxc26/include
 
C_OPT += -D__KERNEL__
 
include $(BASE)/config/lib.mk
 
clean::
rm -f $(OBJS)
 
/shark/trunk/drivers/input/gameport/gameport.c
0,0 → 1,182
/*
* Generic gameport layer
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*/
 
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
 
#include <linuxcomp.h>
 
#include <asm/io.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/slab.h>
#include <linux/stddef.h>
#include <linux/delay.h>
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Generic gameport layer");
MODULE_LICENSE("GPL");
 
EXPORT_SYMBOL(gameport_register_port);
EXPORT_SYMBOL(gameport_unregister_port);
EXPORT_SYMBOL(gameport_register_device);
EXPORT_SYMBOL(gameport_unregister_device);
EXPORT_SYMBOL(gameport_open);
EXPORT_SYMBOL(gameport_close);
EXPORT_SYMBOL(gameport_rescan);
EXPORT_SYMBOL(gameport_cooked_read);
 
static LIST_HEAD(gameport_list);
static LIST_HEAD(gameport_dev_list);
 
#ifdef __i386__
 
#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193182/HZ:0))
#define GET_TIME(x) do { x = get_time_pit(); } while (0)
 
static unsigned int get_time_pit(void)
{
extern spinlock_t i8253_lock;
unsigned long flags;
unsigned int count;
 
spin_lock_irqsave(&i8253_lock, flags);
outb_p(0x00, 0x43);
count = inb_p(0x40);
count |= inb_p(0x40) << 8;
spin_unlock_irqrestore(&i8253_lock, flags);
 
return count;
}
 
#endif
 
/*
* gameport_measure_speed() measures the gameport i/o speed.
*/
 
static int gameport_measure_speed(struct gameport *gameport)
{
#ifdef __i386__
 
unsigned int i, t, t1, t2, t3, tx;
unsigned long flags;
 
if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
return 0;
 
tx = 1 << 30;
 
for(i = 0; i < 50; i++) {
local_irq_save(flags);
GET_TIME(t1);
for(t = 0; t < 50; t++) gameport_read(gameport);
GET_TIME(t2);
GET_TIME(t3);
local_irq_restore(flags);
udelay(i * 10);
if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
}
 
gameport_close(gameport);
return 59659 / (tx < 1 ? 1 : tx);
 
#else
 
unsigned int j, t = 0;
 
j = jiffies; while (j == jiffies);
j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); }
 
gameport_close(gameport);
return t * HZ / 1000;
 
#endif
}
 
static void gameport_find_dev(struct gameport *gameport)
{
struct gameport_dev *dev;
 
list_for_each_entry(dev, &gameport_dev_list, node) {
if (gameport->dev)
break;
if (dev->connect)
dev->connect(gameport, dev);
}
}
 
void gameport_rescan(struct gameport *gameport)
{
gameport_close(gameport);
gameport_find_dev(gameport);
}
 
void gameport_register_port(struct gameport *gameport)
{
list_add_tail(&gameport->node, &gameport_list);
gameport->speed = gameport_measure_speed(gameport);
gameport_find_dev(gameport);
}
 
void gameport_unregister_port(struct gameport *gameport)
{
list_del_init(&gameport->node);
if (gameport->dev && gameport->dev->disconnect)
gameport->dev->disconnect(gameport);
}
 
void gameport_register_device(struct gameport_dev *dev)
{
struct gameport *gameport;
 
list_add_tail(&dev->node, &gameport_dev_list);
list_for_each_entry(gameport, &gameport_list, node)
if (!gameport->dev && dev->connect)
dev->connect(gameport, dev);
}
 
void gameport_unregister_device(struct gameport_dev *dev)
{
struct gameport *gameport;
 
list_del_init(&dev->node);
list_for_each_entry(gameport, &gameport_list, node) {
if (gameport->dev == dev && dev->disconnect)
dev->disconnect(gameport);
gameport_find_dev(gameport);
}
}
 
int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode)
{
if (gameport->open) {
if (gameport->open(gameport, mode))
return -1;
} else {
if (mode != GAMEPORT_MODE_RAW)
return -1;
}
 
if (gameport->dev)
return -1;
 
gameport->dev = dev;
return 0;
}
 
void gameport_close(struct gameport *gameport)
{
gameport->dev = NULL;
if (gameport->close)
gameport->close(gameport);
}
/shark/trunk/drivers/input/gameport/ns558.c
0,0 → 1,291
/*
* $Id: ns558.c,v 1.1 2004-03-08 18:47:38 giacomo Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
* Copyright (c) 1999 Brian Gerst
*/
 
/*
* NS558 based standard IBM game port driver for Linux
*/
 
/*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
 
#include <linuxcomp.h>
 
#include <asm/io.h>
 
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/slab.h>
#include <linux/pnp.h>
 
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Classic gameport (ISA/PnP) driver");
MODULE_LICENSE("GPL");
 
#define NS558_ISA 1
#define NS558_PNP 2
 
static int ns558_isa_portlist[] = { 0x201, 0x200, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
 
struct ns558 {
int type;
int size;
struct pnp_dev *dev;
struct list_head node;
struct gameport gameport;
char phys[32];
char name[32];
};
static LIST_HEAD(ns558_list);
 
/*
* ns558_isa_probe() tries to find an isa gameport at the
* specified address, and also checks for mirrors.
* A joystick must be attached for this to work.
*/
 
static void ns558_isa_probe(int io)
{
int i, j, b;
unsigned char c, u, v;
struct ns558 *port;
 
/*
* No one should be using this address.
*/
 
//!!!if (check_region(io, 1))
//!!! return;
 
/*
* We must not be able to write arbitrary values to the port.
* The lower two axis bits must be 1 after a write.
*/
 
c = inb(io);
outb(~c & ~3, io);
if (~(u = v = inb(io)) & 3) {
outb(c, io);
return;
}
/*
* After a trigger, there must be at least some bits changing.
*/
 
for (i = 0; i < 1000; i++) v &= inb(io);
 
if (u == v) {
outb(c, io);
return;
}
wait_ms(3);
/*
* After some time (4ms) the axes shouldn't change anymore.
*/
 
u = inb(io);
for (i = 0; i < 1000; i++)
if ((u ^ inb(io)) & 0xf) {
outb(c, io);
return;
}
/*
* And now find the number of mirrors of the port.
*/
 
for (i = 1; i < 5; i++) {
 
//!!!if (check_region(io & (-1 << i), (1 << i))) /* Don't disturb anyone */
//!!! break;
 
outb(0xff, io & (-1 << i));
for (j = b = 0; j < 1000; j++)
if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
wait_ms(3);
 
if (b > 300) /* We allow 30% difference */
break;
}
 
i--;
 
if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
printk(KERN_ERR "ns558: Memory allocation failed.\n");
return;
}
memset(port, 0, sizeof(struct ns558));
port->type = NS558_ISA;
port->size = (1 << i);
port->gameport.io = io;
port->gameport.phys = port->phys;
port->gameport.name = port->name;
port->gameport.id.bustype = BUS_ISA;
 
sprintf26(port->phys, "isa%04x/gameport0", io & (-1 << i));
sprintf26(port->name, "NS558 ISA");
 
request_region(io & (-1 << i), (1 << i), "ns558-isa");
 
gameport_register_port(&port->gameport);
 
printk(KERN_INFO "gameport: NS558 ISA at %#x", port->gameport.io);
if (port->size > 1) printk(" size %d", port->size);
printk(" speed %d kHz\n", port->gameport.speed);
 
list_add(&port->node, &ns558_list);
}
 
#ifdef CONFIG_PNP
 
static struct pnp_device_id pnp_devids[] = {
{ .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */
{ .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */
{ .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */
{ .id = "@P@2001", .driver_data = 0 }, /* ALS 120 */
{ .id = "ASB16fd", .driver_data = 0 }, /* AdLib NSC16 */
{ .id = "AZT3001", .driver_data = 0 }, /* AZT1008 */
{ .id = "CDC0001", .driver_data = 0 }, /* Opl3-SAx */
{ .id = "CSC0001", .driver_data = 0 }, /* CS4232 */
{ .id = "CSC000f", .driver_data = 0 }, /* CS4236 */
{ .id = "CSC0101", .driver_data = 0 }, /* CS4327 */
{ .id = "CTL7001", .driver_data = 0 }, /* SB16 */
{ .id = "CTL7002", .driver_data = 0 }, /* AWE64 */
{ .id = "CTL7005", .driver_data = 0 }, /* Vibra16 */
{ .id = "ENS2020", .driver_data = 0 }, /* SoundscapeVIVO */
{ .id = "ESS0001", .driver_data = 0 }, /* ES1869 */
{ .id = "ESS0005", .driver_data = 0 }, /* ES1878 */
{ .id = "ESS6880", .driver_data = 0 }, /* ES688 */
{ .id = "IBM0012", .driver_data = 0 }, /* CS4232 */
{ .id = "OPT0001", .driver_data = 0 }, /* OPTi Audio16 */
{ .id = "YMH0006", .driver_data = 0 }, /* Opl3-SA */
{ .id = "YMH0022", .driver_data = 0 }, /* Opl3-SAx */
{ .id = "PNPb02f", .driver_data = 0 }, /* Generic */
{ .id = "", },
};
 
MODULE_DEVICE_TABLE(pnp, pnp_devids);
 
static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
{
int ioport, iolen;
struct ns558 *port;
 
if (!pnp_port_valid(dev, 0)) {
printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n");
return -ENODEV;
}
 
ioport = pnp_port_start(dev,0);
iolen = pnp_port_len(dev,0);
 
if (!request_region(ioport, iolen, "ns558-pnp"))
return -EBUSY;
 
if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
printk(KERN_ERR "ns558: Memory allocation failed.\n");
return -ENOMEM;
}
memset(port, 0, sizeof(struct ns558));
 
port->type = NS558_PNP;
port->size = iolen;
port->dev = dev;
 
port->gameport.io = ioport;
port->gameport.phys = port->phys;
port->gameport.name = port->name;
port->gameport.id.bustype = BUS_ISAPNP;
port->gameport.id.version = 0x100;
 
sprintf26(port->phys, "pnp%s/gameport0", dev->dev.bus_id);
sprintf26(port->name, "%s", "NS558 PnP Gameport");
 
gameport_register_port(&port->gameport);
 
printk(KERN_INFO "gameport: NS558 PnP at pnp%s io %#x",
dev->dev.bus_id, port->gameport.io);
if (iolen > 1) printk(" size %d", iolen);
printk(" speed %d kHz\n", port->gameport.speed);
 
list_add_tail(&port->node, &ns558_list);
return 0;
}
 
static struct pnp_driver ns558_pnp_driver = {
.name = "ns558",
.id_table = pnp_devids,
.probe = ns558_pnp_probe,
};
 
#else
 
static struct pnp_driver ns558_pnp_driver;
 
#endif
 
int __init ns558_init(void)
{
int i = 0;
 
/*
* Probe for ISA ports.
*/
 
while (ns558_isa_portlist[i])
ns558_isa_probe(ns558_isa_portlist[i++]);
 
pnp_register_driver(&ns558_pnp_driver);
return list_empty(&ns558_list) ? -ENODEV : 0;
}
 
void __exit ns558_exit(void)
{
struct ns558 *port;
 
list_for_each_entry(port, &ns558_list, node) {
gameport_unregister_port(&port->gameport);
switch (port->type) {
 
#ifdef CONFIG_PNP
case NS558_PNP:
/* fall through */
#endif
case NS558_ISA:
release_region(port->gameport.io & ~(port->size - 1), port->size);
break;
default:
break;
}
}
pnp_unregister_driver(&ns558_pnp_driver);
}
 
module_init(ns558_init);
module_exit(ns558_exit);
/shark/trunk/drivers/linuxc26/include/linux/timer.h
18,6 → 18,9
unsigned long data;
 
struct tvec_t_base_s *base;
 
/* Added by Nino */
int event_timer;
};
 
#define TIMER_MAGIC 0x4b87ad6e
38,12 → 41,13
* init_timer() must be done to a timer prior calling *any* of the
* other timer functions.
*/
static inline void init_timer(struct timer_list * timer)
/*static inline void init_timer(struct timer_list * timer)
{
timer->base = NULL;
timer->magic = TIMER_MAGIC;
spin_lock_init(&timer->lock);
}
}*/
extern void init_timer(struct timer_list * timer);
 
/***
* timer_pending - is a timer pending?
55,10 → 59,11
*
* return value: 1 if the timer is pending, 0 if not.
*/
static inline int timer_pending(const struct timer_list * timer)
/*static inline int timer_pending(const struct timer_list * timer)
{
return timer->base != NULL;
}
}*/
extern int timer_pending(struct timer_list * timer);
 
extern void add_timer_on(struct timer_list *timer, int cpu);
extern int del_timer(struct timer_list * timer);
79,10 → 84,11
* Timers with an ->expired field in the past will be executed in the next
* timer tick.
*/
static inline void add_timer(struct timer_list * timer)
/*static inline void add_timer(struct timer_list * timer)
{
__mod_timer(timer, timer->expires);
}
}*/
extern void add_timer(struct timer_list * timer);
 
#ifdef CONFIG_SMP
extern int del_timer_sync(struct timer_list * timer);
/shark/trunk/drivers/linuxc26/include/linuxcomp.h
1,6 → 1,10
#ifndef __LINUX_COMP__
#define __LINUX_COMP__
 
#ifndef __i386__
#define __i386__
#endif
 
#define CONFIG_M386
 
#define va_list void*
32,4 → 36,27
void shark_internal_sem_wait(void *sem);
void shark_internal_sem_post(void *sem);
 
 
#define CONFIG_GAMEPORT
 
#ifndef _STRUCT_TIMESPEC
#define _STRUCT_TIMESPEC
struct timespec {
long tv_sec; /* Seconds */
long tv_nsec; /* Nanoseconds */
};
#endif /* _STRUCT_TIMESPEC */
 
extern TIME sys_gettime(struct timespec *t);
 
#define jiffies26 (sys_gettime(NULL)*HZ/1000000) /* Has to be controlled... */
//#define jiffies26 (TIME)0
 
int shark_event_post(struct timespec *time, void (*handler)(void *p), void *par);
int shark_event_delete(int index);
 
/* Interrupt handler installation and removal */
int shark_handler_set(int no, void (*fast)(int), int pi);
int shark_handler_remove(int no);
 
#endif
/shark/trunk/drivers/linuxc26/makefile
11,7 → 11,8
OBJS_PATH = $(BASE)/drivers/linuxc26
 
OBJS = bus.o linuxcomp.o core.o driver.o vsprintf.o interface.o kobject.o\
shark_linuxc26.o shark_glue.o class.o
shark_linuxc26.o shark_glue.o class.o\
int.o timer.o
 
C_OPT += -I../linuxc26/include