You can subscribe to this list here.
| 2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(135) |
Nov
(123) |
Dec
(83) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2002 |
Jan
(244) |
Feb
(72) |
Mar
(221) |
Apr
(91) |
May
(104) |
Jun
(93) |
Jul
(78) |
Aug
(1) |
Sep
(1) |
Oct
(29) |
Nov
(98) |
Dec
(20) |
| 2003 |
Jan
|
Feb
(21) |
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
(18) |
Sep
(18) |
Oct
(23) |
Nov
(12) |
Dec
(6) |
| 2004 |
Jan
(2) |
Feb
(32) |
Mar
|
Apr
(12) |
May
(11) |
Jun
(11) |
Jul
|
Aug
(9) |
Sep
|
Oct
(15) |
Nov
|
Dec
|
| 2005 |
Jan
|
Feb
(2) |
Mar
(11) |
Apr
(6) |
May
(1) |
Jun
(9) |
Jul
(7) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
| 2006 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| 2007 |
Jan
|
Feb
(2) |
Mar
|
Apr
(25) |
May
(2) |
Jun
|
Jul
(5) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| 2008 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| 2009 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| 2010 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(13) |
Oct
|
Nov
(2) |
Dec
(2) |
| 2011 |
Jan
|
Feb
|
Mar
(10) |
Apr
(10) |
May
(1) |
Jun
(6) |
Jul
|
Aug
(2) |
Sep
(5) |
Oct
|
Nov
|
Dec
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:28:54
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv5362
Added Files:
Tag: 1.29
sidewinder.c
Log Message:
Moved.
--- NEW FILE: sidewinder.c ---
/*
* $Id: sidewinder.c,v 1.29 2002/01/22 20:28:51 vojtech Exp $
*
* Copyright (c) 1998-2001 Vojtech Pavlik
*/
/*
* Microsoft SideWinder joystick family 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/gameport.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("Microsoft SideWinder joystick family driver");
MODULE_LICENSE("GPL");
/*
* These are really magic values. Changing them can make a problem go away,
* as well as break everything.
*/
#define SW_DEBUG
#define SW_START 400 /* The time we wait for the first bit [400 us] */
#define SW_STROBE 45 /* Max time per bit [45 us] */
#define SW_TIMEOUT 4000 /* Wait for everything to settle [4 ms] */
#define SW_KICK 45 /* Wait after A0 fall till kick [45 us] */
#define SW_END 8 /* Number of bits before end of packet to kick */
#define SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */
#define SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */
#define SW_OK 64 /* Number of packet read successes to switch optimization back on */
#define SW_LENGTH 512 /* Max number of bits in a packet */
#define SW_REFRESH HZ/50 /* Time to wait between updates of joystick data [20 ms] */
#ifdef SW_DEBUG
#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
#else
#define dbg(format, arg...) do {} while (0)
#endif
/*
* SideWinder joystick types ...
*/
#define SW_ID_3DP 0
#define SW_ID_GP 1
#define SW_ID_PP 2
#define SW_ID_FFP 3
#define SW_ID_FSP 4
#define SW_ID_FFW 5
/*
* Names, buttons, axes ...
*/
static char *sw_name[] = { "3D Pro", "GamePad", "Precision Pro", "Force Feedback Pro", "FreeStyle Pro",
"Force Feedback Wheel" };
static char sw_abs[][7] = {
{ ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
{ ABS_X, ABS_Y },
{ ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
{ ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
{ ABS_RX, ABS_RUDDER, ABS_THROTTLE }};
static char sw_bit[][7] = {
{ 10, 10, 9, 10, 1, 1 },
{ 1, 1 },
{ 10, 10, 6, 7, 1, 1 },
{ 10, 10, 6, 7, 1, 1 },
{ 10, 10, 6, 1, 1 },
{ 10, 7, 7, 1, 1 }};
static short sw_btn[][12] = {
{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_MODE },
{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE },
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT },
{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }};
static struct {
int x;
int y;
} sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
struct sw {
struct gameport *gameport;
struct timer_list timer;
struct input_dev dev[4];
char name[64];
char phys[4][32];
int length;
int type;
int bits;
int number;
int fail;
int ok;
int reads;
int bads;
int used;
};
/*
* sw_read_packet() is a function which reads either a data packet, or an
* identification packet from a SideWinder joystick. The protocol is very,
* very, very braindamaged. Microsoft patented it in US patent #5628686.
*/
static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int length, int id)
{
unsigned long flags;
int timeout, bitout, sched, i, kick, start, strobe;
unsigned char pending, u, v;
i = -id; /* Don't care about data, only want ID */
timeout = id ? gameport_time(gameport, SW_TIMEOUT) : 0; /* Set up global timeout for ID packet */
kick = id ? gameport_time(gameport, SW_KICK) : 0; /* Set up kick timeout for ID packet */
start = gameport_time(gameport, SW_START);
strobe = gameport_time(gameport, SW_STROBE);
bitout = start;
pending = 0;
sched = 0;
__save_flags(flags); /* Quiet, please */
__cli();
gameport_trigger(gameport); /* Trigger */
v = gameport_read(gameport);
do {
bitout--;
u = v;
v = gameport_read(gameport);
} while (!(~v & u & 0x10) && (bitout > 0)); /* Wait for first falling edge on clock */
if (bitout > 0) bitout = strobe; /* Extend time if not timed out */
while ((timeout > 0 || bitout > 0) && (i < length)) {
timeout--;
bitout--; /* Decrement timers */
sched--;
u = v;
v = gameport_read(gameport);
if ((~u & v & 0x10) && (bitout > 0)) { /* Rising edge on clock - data bit */
if (i >= 0) /* Want this data */
buf[i] = v >> 5; /* Store it */
i++; /* Advance index */
bitout = strobe; /* Extend timeout for next bit */
}
if (kick && (~v & u & 0x01)) { /* Falling edge on axis 0 */
sched = kick; /* Schedule second trigger */
kick = 0; /* Don't schedule next time on falling edge */
pending = 1; /* Mark schedule */
}
if (pending && sched < 0 && (i > -SW_END)) { /* Second trigger time */
gameport_trigger(gameport); /* Trigger */
bitout = start; /* Long bit timeout */
pending = 0; /* Unmark schedule */
timeout = 0; /* Switch from global to bit timeouts */
}
}
__restore_flags(flags); /* Done - relax */
#ifdef SW_DEBUG
{
int j;
printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i);
for (j = 0; j < i; j++) printk("%d", buf[j]);
printk("]\n");
}
#endif
return i;
}
/*
* sw_get_bits() and GB() compose bits from the triplet buffer into a __u64.
* Parameter 'pos' is bit number inside packet where to start at, 'num' is number
* of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
* is number of bits per triplet.
*/
#define GB(pos,num) sw_get_bits(buf, pos, num, sw->bits)
static __u64 sw_get_bits(unsigned char *buf, int pos, int num, char bits)
{
__u64 data = 0;
int tri = pos % bits; /* Start position */
int i = pos / bits;
int bit = 0;
while (num--) {
data |= (__u64)((buf[i] >> tri++) & 1) << bit++; /* Transfer bit */
if (tri == bits) {
i++; /* Next triplet */
tri = 0;
}
}
return data;
}
/*
* sw_init_digital() initializes a SideWinder 3D Pro joystick
* into digital mode.
*/
static void sw_init_digital(struct gameport *gameport)
{
int seq[] = { 140, 140+725, 140+300, 0 };
unsigned long flags;
int i, t;
__save_flags(flags);
__cli();
i = 0;
do {
gameport_trigger(gameport); /* Trigger */
t = gameport_time(gameport, SW_TIMEOUT);
while ((gameport_read(gameport) & 1) && t) t--; /* Wait for axis to fall back to 0 */
udelay(seq[i]); /* Delay magic time */
} while (seq[++i]);
gameport_trigger(gameport); /* Last trigger */
__restore_flags(flags);
}
/*
* sw_parity() computes parity of __u64
*/
static int sw_parity(__u64 t)
{
int x = t ^ (t >> 32);
x ^= x >> 16;
x ^= x >> 8;
x ^= x >> 4;
x ^= x >> 2;
x ^= x >> 1;
return x & 1;
}
/*
* sw_ccheck() checks synchronization bits and computes checksum of nibbles.
*/
static int sw_check(__u64 t)
{
unsigned char sum = 0;
if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */
return -1;
while (t) { /* Sum */
sum += t & 0xf;
t >>= 4;
}
return sum & 0xf;
}
/*
* sw_parse() analyzes SideWinder joystick data, and writes the results into
* the axes and buttons arrays.
*/
static int sw_parse(unsigned char *buf, struct sw *sw)
{
int hat, i, j;
struct input_dev *dev = sw->dev;
switch (sw->type) {
case SW_ID_3DP:
if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) return -1;
input_report_abs(dev, ABS_X, (GB( 3,3) << 7) | GB(16,7));
input_report_abs(dev, ABS_Y, (GB( 0,3) << 7) | GB(24,7));
input_report_abs(dev, ABS_RZ, (GB(35,2) << 7) | GB(40,7));
input_report_abs(dev, ABS_THROTTLE, (GB(32,3) << 7) | GB(48,7));
input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
for (j = 0; j < 7; j++)
input_report_key(dev, sw_btn[SW_ID_3DP][j], !GB(j+8,1));
input_report_key(dev, BTN_BASE4, !GB(38,1));
input_report_key(dev, BTN_BASE5, !GB(37,1));
return 0;
case SW_ID_GP:
for (i = 0; i < sw->number; i ++) {
if (sw_parity(GB(i*15,15))) return -1;
input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1));
input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
for (j = 0; j < 10; j++)
input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1));
}
return 0;
case SW_ID_PP:
case SW_ID_FFP:
if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) return -1;
input_report_abs(dev, ABS_X, GB( 9,10));
input_report_abs(dev, ABS_Y, GB(19,10));
input_report_abs(dev, ABS_RZ, GB(36, 6));
input_report_abs(dev, ABS_THROTTLE, GB(29, 7));
input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
for (j = 0; j < 9; j++)
input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1));
return 0;
case SW_ID_FSP:
if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) return -1;
input_report_abs(dev, ABS_X, GB( 0,10));
input_report_abs(dev, ABS_Y, GB(16,10));
input_report_abs(dev, ABS_THROTTLE, GB(32, 6));
input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
for (j = 0; j < 6; j++)
input_report_key(dev, sw_btn[SW_ID_FSP][j], !GB(j+10,1));
input_report_key(dev, BTN_TR, GB(26,1));
input_report_key(dev, BTN_START, GB(27,1));
input_report_key(dev, BTN_MODE, GB(38,1));
input_report_key(dev, BTN_SELECT, GB(39,1));
return 0;
case SW_ID_FFW:
if (!sw_parity(GB(0,33))) return -1;
input_report_abs(dev, ABS_RX, GB( 0,10));
input_report_abs(dev, ABS_RUDDER, GB(10, 6));
input_report_abs(dev, ABS_THROTTLE, GB(16, 6));
for (j = 0; j < 8; j++)
input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1));
return 0;
}
return -1;
}
/*
* sw_read() reads SideWinder joystick data, and reinitializes
* the joystick in case of persistent problems. This is the function that is
* called from the generic code to poll the joystick.
*/
static int sw_read(struct sw *sw)
{
unsigned char buf[SW_LENGTH];
int i;
i = sw_read_packet(sw->gameport, buf, sw->length, 0);
if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) { /* Broken packet, try to fix */
if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) { /* Last init failed, 1 bit mode */
printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on %s"
" - going to reinitialize.\n", sw->gameport->phys);
sw->fail = SW_FAIL; /* Reinitialize */
i = 128; /* Bogus value */
}
if (i < 66 && GB(0,64) == GB(i*3-66,64)) /* 1 == 3 */
i = 66; /* Everything is fine */
if (i < 66 && GB(0,64) == GB(66,64)) /* 1 == 2 */
i = 66; /* Everything is fine */
if (i < 66 && GB(i*3-132,64) == GB(i*3-66,64)) { /* 2 == 3 */
memmove(buf, buf + i - 22, 22); /* Move data */
i = 66; /* Carry on */
}
}
if (i == sw->length && !sw_parse(buf, sw)) { /* Parse data */
sw->fail = 0;
sw->ok++;
if (sw->type == SW_ID_3DP && sw->length == 66 /* Many packets OK */
&& sw->ok > SW_OK) {
printk(KERN_INFO "sidewinder.c: No more trouble on %s"
" - enabling optimization again.\n", sw->gameport->phys);
sw->length = 22;
}
return 0;
}
sw->ok = 0;
sw->fail++;
if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) { /* Consecutive bad packets */
printk(KERN_INFO "sidewinder.c: Many bit errors on %s"
" - disabling optimization.\n", sw->gameport->phys);
sw->length = 66;
}
if (sw->fail < SW_FAIL) return -1; /* Not enough, don't reinitialize yet */
printk(KERN_WARNING "sidewinder.c: Too many bit errors on %s"
" - reinitializing joystick.\n", sw->gameport->phys);
if (!i && sw->type == SW_ID_3DP) { /* 3D Pro can be in analog mode */
udelay(3 * SW_TIMEOUT);
sw_init_digital(sw->gameport);
}
udelay(SW_TIMEOUT);
i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0); /* Read normal data packet */
udelay(SW_TIMEOUT);
sw_read_packet(sw->gameport, buf, SW_LENGTH, i); /* Read ID packet, this initializes the stick */
sw->fail = SW_FAIL;
return -1;
}
static void sw_timer(unsigned long private)
{
struct sw *sw = (void *) private;
sw->reads++;
if (sw_read(sw)) sw->bads++;
mod_timer(&sw->timer, jiffies + SW_REFRESH);
}
static int sw_open(struct input_dev *dev)
{
struct sw *sw = dev->private;
if (!sw->used++)
mod_timer(&sw->timer, jiffies + SW_REFRESH);
return 0;
}
static void sw_close(struct input_dev *dev)
{
struct sw *sw = dev->private;
if (!--sw->used)
del_timer(&sw->timer);
}
/*
* sw_print_packet() prints the contents of a SideWinder packet.
*/
static void sw_print_packet(char *name, int length, unsigned char *buf, char bits)
{
int i;
printk(KERN_INFO "sidewinder.c: %s packet, %d bits. [", name, length);
for (i = (((length + 3) >> 2) - 1); i >= 0; i--)
printk("%x", (int)sw_get_bits(buf, i << 2, 4, bits));
printk("]\n");
}
/*
* sw_3dp_id() translates the 3DP id into a human legible string.
* Unfortunately I don't know how to do this for the other SW types.
*/
static void sw_3dp_id(unsigned char *buf, char *comment)
{
int i;
char pnp[8], rev[9];
for (i = 0; i < 7; i++) /* ASCII PnP ID */
pnp[i] = sw_get_bits(buf, 24+8*i, 8, 1);
for (i = 0; i < 8; i++) /* ASCII firmware revision */
rev[i] = sw_get_bits(buf, 88+8*i, 8, 1);
pnp[7] = rev[8] = 0;
sprintf(comment, " [PnP %d.%02d id %s rev %s]",
(int) ((sw_get_bits(buf, 8, 6, 1) << 6) | /* Two 6-bit values */
sw_get_bits(buf, 16, 6, 1)) / 100,
(int) ((sw_get_bits(buf, 8, 6, 1) << 6) |
sw_get_bits(buf, 16, 6, 1)) % 100,
pnp, rev);
}
/*
* sw_guess_mode() checks the upper two button bits for toggling -
* indication of that the joystick is in 3-bit mode. This is documented
* behavior for 3DP ID packet, and for example the FSP does this in
* normal packets instead. Fun ...
*/
static int sw_guess_mode(unsigned char *buf, int len)
{
int i;
unsigned char xor = 0;
for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6;
return !!xor * 2 + 1;
}
/*
* sw_connect() probes for SideWinder type joysticks.
*/
static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
{
struct sw *sw;
int i, j, k, l;
unsigned char buf[SW_LENGTH];
unsigned char idbuf[SW_LENGTH];
unsigned char m = 1;
char comment[40];
comment[0] = 0;
if (!(sw = kmalloc(sizeof(struct sw), GFP_KERNEL))) return;
memset(sw, 0, sizeof(struct sw));
gameport->private = sw;
sw->gameport = gameport;
init_timer(&sw->timer);
sw->timer.data = (long) sw;
sw->timer.function = sw_timer;
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
goto fail1;
dbg("Init 0: Opened %s, io %#x, speed %d",
gameport->phys, gameport->io, gameport->speed);
i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read normal packet */
m |= sw_guess_mode(buf, i); /* Data packet (1-bit) can carry mode info [FSP] */
udelay(SW_TIMEOUT);
dbg("Init 1: Mode %d. Length %d.", m , i);
if (!i) { /* No data. 3d Pro analog mode? */
sw_init_digital(gameport); /* Switch to digital */
udelay(SW_TIMEOUT);
i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */
udelay(SW_TIMEOUT);
dbg("Init 1b: Length %d.", i);
if (!i) goto fail2; /* No data -> FAIL */
}
j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Read ID. This initializes the stick */
m |= sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */
dbg("Init 2: Mode %d. ID Length %d.", m , j);
if (!j) { /* Read ID failed. Happens in 1-bit mode on PP */
udelay(SW_TIMEOUT);
i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */
dbg("Init 2b: Mode %d. Length %d.", m, i);
if (!i) goto fail2;
udelay(SW_TIMEOUT);
j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Retry reading ID */
dbg("Init 2c: ID Length %d.", j);
}
sw->type = -1;
k = SW_FAIL; /* Try SW_FAIL times */
l = 0;
do {
k--;
udelay(SW_TIMEOUT);
i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read data packet */
dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k);
if (i > l) { /* Longer? As we can only lose bits, it makes */
/* no sense to try detection for a packet shorter */
l = i; /* than the previous one */
sw->number = 1;
sw->gameport = gameport;
sw->length = i;
sw->bits = m;
dbg("Init 3a: Case %d.\n", i * m);
switch (i * m) {
case 60:
sw->number++;
case 45: /* Ambiguous packet length */
if (j <= 40) { /* ID length less or eq 40 -> FSP */
case 43:
sw->type = SW_ID_FSP;
break;
}
sw->number++;
case 30:
sw->number++;
case 15:
sw->type = SW_ID_GP;
break;
case 33:
case 31:
sw->type = SW_ID_FFW;
break;
case 48: /* Ambiguous */
if (j == 14) { /* ID length 14*3 -> FFP */
sw->type = SW_ID_FFP;
sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on");
} else
sw->type = SW_ID_PP;
break;
case 198:
sw->length = 22;
case 64:
sw->type = SW_ID_3DP;
if (j == 160) sw_3dp_id(idbuf, comment);
break;
}
}
} while (k && (sw->type == -1));
if (sw->type == -1) {
printk(KERN_WARNING "sidewinder.c: unknown joystick device detected "
"on %s, contact <vo...@uc...>\n", gameport->phys);
sw_print_packet("ID", j * 3, idbuf, 3);
sw_print_packet("Data", i * m, buf, m);
goto fail2;
}
#ifdef SW_DEBUG
sw_print_packet("ID", j * 3, idbuf, 3);
sw_print_packet("Data", i * m, buf, m);
#endif
k = i;
l = j;
for (i = 0; i < sw->number; i++) {
int bits, code;
sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]);
sprintf(sw->phys[i], "%s/input%d", gameport->phys, i);
sw->dev[i].private = sw;
sw->dev[i].open = sw_open;
sw->dev[i].close = sw_close;
sw->dev[i].name = sw->name;
sw->dev[i].phys = sw->phys[i];
sw->dev[i].idbus = BUS_GAMEPORT;
sw->dev[i].idvendor = GAMEPORT_ID_VENDOR_MICROSOFT;
sw->dev[i].idproduct = sw->type;
sw->dev[i].idversion = 0x0100;
sw->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (j = 0; (bits = sw_bit[sw->type][j]); j++) {
code = sw_abs[sw->type][j];
set_bit(code, sw->dev[i].absbit);
sw->dev[i].absmax[code] = (1 << bits) - 1;
sw->dev[i].absmin[code] = (bits == 1) ? -1 : 0;
sw->dev[i].absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0;
if (code != ABS_THROTTLE)
sw->dev[i].absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0;
}
for (j = 0; (code = sw_btn[sw->type][j]); j++)
set_bit(code, sw->dev[i].keybit);
input_register_device(sw->dev + i);
printk(KERN_INFO "input: %s%s on %s [%d-bit id %d data %d]\n",
sw->name, comment, gameport->phys, m, l, k);
}
return;
fail2: gameport_close(gameport);
fail1: kfree(sw);
}
static void sw_disconnect(struct gameport *gameport)
{
int i;
struct sw *sw = gameport->private;
for (i = 0; i < sw->number; i++)
input_unregister_device(sw->dev + i);
gameport_close(gameport);
kfree(sw);
}
static struct gameport_dev sw_dev = {
connect: sw_connect,
disconnect: sw_disconnect,
};
int __init sw_init(void)
{
gameport_register_device(&sw_dev);
return 0;
}
void __exit sw_exit(void)
{
gameport_unregister_device(&sw_dev);
}
module_init(sw_init);
module_exit(sw_exit);
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:28:41
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv5270
Added Files:
Tag: 1.16
magellan.c
Log Message:
Moved.
--- NEW FILE: magellan.c ---
/*
* $Id: magellan.c,v 1.16 2002/01/22 20:28:39 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
/*
* Magellan and Space Mouse 6dof controller 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("Magellan and SpaceMouse 6dof controller driver");
MODULE_LICENSE("GPL");
/*
* Definitions & global arrays.
*/
#define MAGELLAN_MAX_LENGTH 32
static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
static char *magellan_name = "LogiCad3D Magellan / SpaceMouse";
/*
* Per-Magellan data.
*/
struct magellan {
struct input_dev dev;
int idx;
unsigned char data[MAGELLAN_MAX_LENGTH];
char phys[32];
};
/*
* magellan_crunch_nibbles() verifies that the bytes sent from the Magellan
* have correct upper nibbles for the lower ones, if not, the packet will
* be thrown away. It also strips these upper halves to simplify further
* processing.
*/
static int magellan_crunch_nibbles(unsigned char *data, int count)
{
static unsigned char nibbles[16] = "0AB3D56GH9:K<MN?";
do {
if (data[count] == nibbles[data[count] & 0xf])
data[count] = data[count] & 0xf;
else
return -1;
} while (--count);
return 0;
}
static void magellan_process_packet(struct magellan* magellan)
{
struct input_dev *dev = &magellan->dev;
unsigned char *data = magellan->data;
int i, t;
if (!magellan->idx) return;
switch (magellan->data[0]) {
case 'd': /* Axis data */
if (magellan->idx != 25) return;
if (magellan_crunch_nibbles(data, 24)) return;
for (i = 0; i < 6; i++)
input_report_abs(dev, magellan_axes[i],
(data[(i << 2) + 1] << 12 | data[(i << 2) + 2] << 8 |
data[(i << 2) + 3] << 4 | data[(i << 2) + 4]) - 32768);
break;
case 'k': /* Button data */
if (magellan->idx != 4) return;
if (magellan_crunch_nibbles(data, 3)) return;
t = (data[1] << 1) | (data[2] << 5) | data[3];
for (i = 0; i < 9; i++) input_report_key(dev, magellan_buttons[i], (t >> i) & 1);
break;
}
}
static void magellan_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
{
struct magellan* magellan = serio->private;
if (data == '\r') {
magellan_process_packet(magellan);
magellan->idx = 0;
} else {
if (magellan->idx < MAGELLAN_MAX_LENGTH)
magellan->data[magellan->idx++] = data;
}
}
/*
* magellan_disconnect() is the opposite of magellan_connect()
*/
static void magellan_disconnect(struct serio *serio)
{
struct magellan* magellan = serio->private;
input_unregister_device(&magellan->dev);
serio_close(serio);
kfree(magellan);
}
/*
* magellan_connect() is the routine that is called when someone adds a
* new serio device. It looks for the Magellan, and if found, registers
* it as an input device.
*/
static void magellan_connect(struct serio *serio, struct serio_dev *dev)
{
struct magellan *magellan;
int i, t;
if (serio->type != (SERIO_RS232 | SERIO_MAGELLAN))
return;
if (!(magellan = kmalloc(sizeof(struct magellan), GFP_KERNEL)))
return;
memset(magellan, 0, sizeof(struct magellan));
magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (i = 0; i < 9; i++)
set_bit(magellan_buttons[i], &magellan->dev.keybit);
for (i = 0; i < 6; i++) {
t = magellan_axes[i];
set_bit(t, magellan->dev.absbit);
magellan->dev.absmin[t] = -360;
magellan->dev.absmax[t] = 360;
}
sprintf(magellan->phys, "%s/input0", serio->phys);
magellan->dev.private = magellan;
magellan->dev.name = magellan_name;
magellan->dev.phys = magellan->phys;
magellan->dev.idbus = BUS_RS232;
magellan->dev.idvendor = SERIO_MAGELLAN;
magellan->dev.idproduct = 0x0001;
magellan->dev.idversion = 0x0100;
serio->private = magellan;
if (serio_open(serio, dev)) {
kfree(magellan);
return;
}
input_register_device(&magellan->dev);
printk(KERN_INFO "input: %s on %s\n", magellan_name, serio->phys);
}
/*
* The serio device structure.
*/
static struct serio_dev magellan_dev = {
interrupt: magellan_interrupt,
connect: magellan_connect,
disconnect: magellan_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
int __init magellan_init(void)
{
serio_register_device(&magellan_dev);
return 0;
}
void __exit magellan_exit(void)
{
serio_unregister_device(&magellan_dev);
}
module_init(magellan_init);
module_exit(magellan_exit);
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:28:28
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv5161
Added Files:
Tag: 1.16
interact.c
Log Message:
Moved.
--- NEW FILE: interact.c ---
/*
* $Id: interact.c,v 1.16 2002/01/22 20:28:25 vojtech Exp $
*
* Copyright (c) 2001 Vojtech Pavlik
*
* Based on the work of:
* Toby Deshane
*/
/*
* InterAct digital gamepad/joystick 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/input.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("InterAct digital joystick driver");
MODULE_LICENSE("GPL");
#define INTERACT_MAX_START 400 /* 400 us */
#define INTERACT_MAX_STROBE 40 /* 40 us */
#define INTERACT_MAX_LENGTH 32 /* 32 bits */
#define INTERACT_REFRESH_TIME HZ/50 /* 20 ms */
#define INTERACT_TYPE_HHFX 0 /* HammerHead/FX */
#define INTERACT_TYPE_PP8D 1 /* ProPad 8 */
struct interact {
struct gameport *gameport;
struct input_dev dev;
struct timer_list timer;
int used;
int bads;
int reads;
unsigned char type;
unsigned char length;
char phys[32];
};
static short interact_abs_hhfx[] =
{ ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 };
static short interact_abs_pp8d[] =
{ ABS_X, ABS_Y, -1 };
static short interact_btn_hhfx[] =
{ BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL, BTN_TL2, BTN_TR2, BTN_MODE, BTN_SELECT, -1 };
static short interact_btn_pp8d[] =
{ BTN_C, BTN_TL, BTN_TR, BTN_A, BTN_B, BTN_Y, BTN_Z, BTN_X, -1 };
struct interact_type {
int id;
short *abs;
short *btn;
char *name;
unsigned char length;
unsigned char b8;
};
static struct interact_type interact_type[] = {
{ 0x6202, interact_abs_hhfx, interact_btn_hhfx, "InterAct HammerHead/FX", 32, 4 },
{ 0x53f8, interact_abs_pp8d, interact_btn_pp8d, "InterAct ProPad 8 Digital", 16, 0 },
{ 0 }};
/*
* interact_read_packet() reads and InterAct joystick data.
*/
static int interact_read_packet(struct gameport *gameport, int length, u32 *data)
{
unsigned long flags;
unsigned char u, v;
unsigned int t, s;
int i;
i = 0;
data[0] = data[1] = data[2] = 0;
t = gameport_time(gameport, INTERACT_MAX_START);
s = gameport_time(gameport, INTERACT_MAX_STROBE);
__save_flags(flags);
__cli();
gameport_trigger(gameport);
v = gameport_read(gameport);
while (t > 0 && i < length) {
t--;
u = v; v = gameport_read(gameport);
if (v & ~u & 0x40) {
data[0] = (data[0] << 1) | ((v >> 4) & 1);
data[1] = (data[1] << 1) | ((v >> 5) & 1);
data[2] = (data[2] << 1) | ((v >> 7) & 1);
i++;
t = s;
}
}
__restore_flags(flags);
return i;
}
/*
* interact_timer() reads and analyzes InterAct joystick data.
*/
static void interact_timer(unsigned long private)
{
struct interact *interact = (struct interact *) private;
struct input_dev *dev = &interact->dev;
u32 data[3];
int i;
interact->reads++;
if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) {
interact->bads++;
} else {
for (i = 0; i < 3; i++)
data[i] <<= INTERACT_MAX_LENGTH - interact->length;
switch (interact->type) {
case INTERACT_TYPE_HHFX:
for (i = 0; i < 4; i++)
input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff);
for (i = 0; i < 2; i++)
input_report_abs(dev, ABS_HAT0Y - i,
((data[1] >> ((i << 1) + 17)) & 1) - ((data[1] >> ((i << 1) + 16)) & 1));
for (i = 0; i < 8; i++)
input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1);
for (i = 0; i < 4; i++)
input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1);
break;
case INTERACT_TYPE_PP8D:
for (i = 0; i < 2; i++)
input_report_abs(dev, interact_abs_pp8d[i],
((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1));
for (i = 0; i < 8; i++)
input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1);
break;
}
}
mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
}
/*
* interact_open() is a callback from the input open routine.
*/
static int interact_open(struct input_dev *dev)
{
struct interact *interact = dev->private;
if (!interact->used++)
mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
return 0;
}
/*
* interact_close() is a callback from the input close routine.
*/
static void interact_close(struct input_dev *dev)
{
struct interact *interact = dev->private;
if (!--interact->used)
del_timer(&interact->timer);
}
/*
* interact_connect() probes for InterAct joysticks.
*/
static void interact_connect(struct gameport *gameport, struct gameport_dev *dev)
{
struct interact *interact;
__u32 data[3];
int i, t;
if (!(interact = kmalloc(sizeof(struct interact), GFP_KERNEL)))
return;
memset(interact, 0, sizeof(struct interact));
gameport->private = interact;
interact->gameport = gameport;
init_timer(&interact->timer);
interact->timer.data = (long) interact;
interact->timer.function = interact_timer;
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
goto fail1;
i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data);
if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) {
goto fail2;
}
for (i = 0; interact_type[i].length; i++)
if (interact_type[i].id == (data[2] >> 16))
break;
if (!interact_type[i].length) {
printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x i2 %08x]\n",
gameport->phys, i, data[0], data[1], data[2]);
goto fail2;
}
sprintf(interact->phys, "%s/input0", gameport->phys);
interact->type = i;
interact->length = interact_type[i].length;
interact->dev.private = interact;
interact->dev.open = interact_open;
interact->dev.close = interact_close;
interact->dev.name = interact_type[i].name;
interact->dev.phys = interact->phys;
interact->dev.idbus = BUS_GAMEPORT;
interact->dev.idvendor = GAMEPORT_ID_VENDOR_INTERACT;
interact->dev.idproduct = interact_type[i].id;
interact->dev.idversion = 0x0100;
interact->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) {
set_bit(t, interact->dev.absbit);
if (i < interact_type[interact->type].b8) {
interact->dev.absmin[t] = 0;
interact->dev.absmax[t] = 255;
} else {
interact->dev.absmin[t] = -1;
interact->dev.absmax[t] = 1;
}
}
for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++)
set_bit(t, interact->dev.keybit);
input_register_device(&interact->dev);
printk(KERN_INFO "input: %s on %s\n",
interact_type[interact->type].name, gameport->phys);
return;
fail2: gameport_close(gameport);
fail1: kfree(interact);
}
static void interact_disconnect(struct gameport *gameport)
{
struct interact *interact = gameport->private;
input_unregister_device(&interact->dev);
gameport_close(gameport);
kfree(interact);
}
static struct gameport_dev interact_dev = {
connect: interact_connect,
disconnect: interact_disconnect,
};
int __init interact_init(void)
{
gameport_register_device(&interact_dev);
return 0;
}
void __exit interact_exit(void)
{
gameport_unregister_device(&interact_dev);
}
module_init(interact_init);
module_exit(interact_exit);
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:28:15
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv5057
Added Files:
Tag: 1.10
guillemot.c
Log Message:
Moved.
--- NEW FILE: guillemot.c ---
/*
* $Id: guillemot.c,v 1.10 2002/01/22 20:28:12 vojtech Exp $
*
* Copyright (c) 2001 Vojtech Pavlik
*/
/*
* Guillemot Digital Interface Protocol 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/input.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("Guillemot Digital joystick driver");
MODULE_LICENSE("GPL");
#define GUILLEMOT_MAX_START 600 /* 600 us */
#define GUILLEMOT_MAX_STROBE 60 /* 60 us */
#define GUILLEMOT_MAX_LENGTH 17 /* 17 bytes */
#define GUILLEMOT_REFRESH_TIME HZ/50 /* 20 ms */
static short guillemot_abs_pad[] =
{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 };
static short guillemot_btn_pad[] =
{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_MODE, BTN_SELECT, -1 };
static struct {
int x;
int y;
} guillemot_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
struct guillemot_type {
unsigned char id;
short *abs;
short *btn;
int hat;
char *name;
};
struct guillemot {
struct gameport *gameport;
struct input_dev dev;
struct timer_list timer;
int used;
int bads;
int reads;
struct guillemot_type *type;
unsigned char length;
char phys[32];
};
static struct guillemot_type guillemot_type[] = {
{ 0x00, guillemot_abs_pad, guillemot_btn_pad, 1, "Guillemot Pad" },
{ 0 }};
/*
* guillemot_read_packet() reads Guillemot joystick data.
*/
static int guillemot_read_packet(struct gameport *gameport, u8 *data)
{
unsigned long flags;
unsigned char u, v;
unsigned int t, s;
int i;
for (i = 0; i < GUILLEMOT_MAX_LENGTH; i++)
data[i] = 0;
i = 0;
t = gameport_time(gameport, GUILLEMOT_MAX_START);
s = gameport_time(gameport, GUILLEMOT_MAX_STROBE);
__save_flags(flags);
__cli();
gameport_trigger(gameport);
v = gameport_read(gameport);
while (t > 0 && i < GUILLEMOT_MAX_LENGTH * 8) {
t--;
u = v; v = gameport_read(gameport);
if (v & ~u & 0x10) {
data[i >> 3] |= ((v >> 5) & 1) << (i & 7);
i++;
t = s;
}
}
__restore_flags(flags);
return i;
}
/*
* guillemot_timer() reads and analyzes Guillemot joystick data.
*/
static void guillemot_timer(unsigned long private)
{
struct guillemot *guillemot = (struct guillemot *) private;
struct input_dev *dev = &guillemot->dev;
u8 data[GUILLEMOT_MAX_LENGTH];
int i;
guillemot->reads++;
if (guillemot_read_packet(guillemot->gameport, data) != GUILLEMOT_MAX_LENGTH * 8 ||
data[0] != 0x55 || data[16] != 0xaa) {
guillemot->bads++;
} else {
for (i = 0; i < 6 && guillemot->type->abs[i] >= 0; i++)
input_report_abs(dev, guillemot->type->abs[i], data[i + 5]);
if (guillemot->type->hat) {
input_report_abs(dev, ABS_HAT0X, guillemot_hat_to_axis[data[4] >> 4].x);
input_report_abs(dev, ABS_HAT0Y, guillemot_hat_to_axis[data[4] >> 4].y);
}
for (i = 0; i < 16 && guillemot->type->btn[i] >= 0; i++)
input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1);
}
mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
}
/*
* guillemot_open() is a callback from the input open routine.
*/
static int guillemot_open(struct input_dev *dev)
{
struct guillemot *guillemot = dev->private;
if (!guillemot->used++)
mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
return 0;
}
/*
* guillemot_close() is a callback from the input close routine.
*/
static void guillemot_close(struct input_dev *dev)
{
struct guillemot *guillemot = dev->private;
if (!--guillemot->used)
del_timer(&guillemot->timer);
}
/*
* guillemot_connect() probes for Guillemot joysticks.
*/
static void guillemot_connect(struct gameport *gameport, struct gameport_dev *dev)
{
struct guillemot *guillemot;
u8 data[GUILLEMOT_MAX_LENGTH];
int i, t;
if (!(guillemot = kmalloc(sizeof(struct guillemot), GFP_KERNEL)))
return;
memset(guillemot, 0, sizeof(struct guillemot));
gameport->private = guillemot;
guillemot->gameport = gameport;
init_timer(&guillemot->timer);
guillemot->timer.data = (long) guillemot;
guillemot->timer.function = guillemot_timer;
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
goto fail1;
i = guillemot_read_packet(gameport, data);
if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa)
goto fail2;
for (i = 0; guillemot_type[i].name; i++)
if (guillemot_type[i].id == data[11])
break;
if (!guillemot_type[i].name) {
printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n",
gameport->phys, data[12], data[13], data[11], data[14], data[15]);
goto fail2;
}
sprintf(guillemot->phys, "%s/input0", gameport->phys);
guillemot->type = guillemot_type + i;
guillemot->dev.private = guillemot;
guillemot->dev.open = guillemot_open;
guillemot->dev.close = guillemot_close;
guillemot->dev.name = guillemot_type[i].name;
guillemot->dev.phys = guillemot->phys;
guillemot->dev.idbus = BUS_GAMEPORT;
guillemot->dev.idvendor = GAMEPORT_ID_VENDOR_GUILLEMOT;
guillemot->dev.idproduct = guillemot_type[i].id;
guillemot->dev.idversion = (int)data[14] << 8 | data[15];
guillemot->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) {
set_bit(t, guillemot->dev.absbit);
guillemot->dev.absmin[t] = 0;
guillemot->dev.absmax[t] = 255;
}
if (guillemot->type->hat)
for (i = 0; i < 2; i++) {
t = ABS_HAT0X + i;
set_bit(t, guillemot->dev.absbit);
guillemot->dev.absmin[t] = -1;
guillemot->dev.absmax[t] = 1;
}
for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++)
set_bit(t, guillemot->dev.keybit);
input_register_device(&guillemot->dev);
printk(KERN_INFO "input: %s ver %d.%02d on %s\n",
guillemot->type->name, data[14], data[15], gameport->phys);
return;
fail2: gameport_close(gameport);
fail1: kfree(guillemot);
}
static void guillemot_disconnect(struct gameport *gameport)
{
struct guillemot *guillemot = gameport->private;
printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys);
input_unregister_device(&guillemot->dev);
gameport_close(gameport);
kfree(guillemot);
}
static struct gameport_dev guillemot_dev = {
connect: guillemot_connect,
disconnect: guillemot_disconnect,
};
int __init guillemot_init(void)
{
gameport_register_device(&guillemot_dev);
return 0;
}
void __exit guillemot_exit(void)
{
gameport_unregister_device(&guillemot_dev);
}
module_init(guillemot_init);
module_exit(guillemot_exit);
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:28:02
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv4931
Added Files:
Tag: 1.21
grip.c
Log Message:
Moved.
--- NEW FILE: grip.c ---
/*
* $Id: grip.c,v 1.21 2002/01/22 20:27:57 vojtech Exp $
*
* Copyright (c) 1998-2001 Vojtech Pavlik
*/
/*
* Gravis/Kensington GrIP protocol 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/gameport.h>
#include <linux/input.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("Gravis GrIP protocol joystick driver");
MODULE_LICENSE("GPL");
#define GRIP_MODE_GPP 1
#define GRIP_MODE_BD 2
#define GRIP_MODE_XT 3
#define GRIP_MODE_DC 4
#define GRIP_LENGTH_GPP 24
#define GRIP_STROBE_GPP 200 /* 200 us */
#define GRIP_LENGTH_XT 4
#define GRIP_STROBE_XT 64 /* 64 us */
#define GRIP_MAX_CHUNKS_XT 10
#define GRIP_MAX_BITS_XT 30
#define GRIP_REFRESH_TIME HZ/50 /* 20 ms */
struct grip {
struct gameport *gameport;
struct timer_list timer;
struct input_dev dev[2];
unsigned char mode[2];
int used;
int reads;
int bads;
char phys[2][32];
};
static int grip_btn_gpp[] = { BTN_START, BTN_SELECT, BTN_TR2, BTN_Y, 0, BTN_TL2, BTN_A, BTN_B, BTN_X, 0, BTN_TL, BTN_TR, -1 };
static int grip_btn_bd[] = { BTN_THUMB, BTN_THUMB2, BTN_TRIGGER, BTN_TOP, BTN_BASE, -1 };
static int grip_btn_xt[] = { BTN_TRIGGER, BTN_THUMB, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_SELECT, BTN_START, BTN_MODE, -1 };
static int grip_btn_dc[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, -1 };
static int grip_abs_gpp[] = { ABS_X, ABS_Y, -1 };
static int grip_abs_bd[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
static int grip_abs_xt[] = { ABS_X, ABS_Y, ABS_BRAKE, ABS_GAS, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, -1 };
static int grip_abs_dc[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
static char *grip_name[] = { NULL, "Gravis GamePad Pro", "Gravis Blackhawk Digital",
"Gravis Xterminator Digital", "Gravis Xterminator DualControl" };
static int *grip_abs[] = { 0, grip_abs_gpp, grip_abs_bd, grip_abs_xt, grip_abs_dc };
static int *grip_btn[] = { 0, grip_btn_gpp, grip_btn_bd, grip_btn_xt, grip_btn_dc };
static char grip_anx[] = { 0, 0, 3, 5, 5 };
static char grip_cen[] = { 0, 0, 2, 2, 4 };
/*
* grip_gpp_read_packet() reads a Gravis GamePad Pro packet.
*/
static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned int *data)
{
unsigned long flags;
unsigned char u, v;
unsigned int t;
int i;
int strobe = gameport_time(gameport, GRIP_STROBE_GPP);
data[0] = 0;
t = strobe;
i = 0;
__save_flags(flags);
__cli();
v = gameport_read(gameport) >> shift;
do {
t--;
u = v; v = (gameport_read(gameport) >> shift) & 3;
if (~v & u & 1) {
data[0] |= (v >> 1) << i++;
t = strobe;
}
} while (i < GRIP_LENGTH_GPP && t > 0);
__restore_flags(flags);
if (i < GRIP_LENGTH_GPP) return -1;
for (i = 0; i < GRIP_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++)
data[0] = data[0] >> 1 | (data[0] & 1) << (GRIP_LENGTH_GPP - 1);
return -(i == GRIP_LENGTH_GPP);
}
/*
* grip_xt_read_packet() reads a Gravis Xterminator packet.
*/
static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned int *data)
{
unsigned int i, j, buf, crc;
unsigned char u, v, w;
unsigned long flags;
unsigned int t;
char status;
int strobe = gameport_time(gameport, GRIP_STROBE_XT);
data[0] = data[1] = data[2] = data[3] = 0;
status = buf = i = j = 0;
t = strobe;
__save_flags(flags);
__cli();
v = w = (gameport_read(gameport) >> shift) & 3;
do {
t--;
u = (gameport_read(gameport) >> shift) & 3;
if (u ^ v) {
if ((u ^ v) & 1) {
buf = (buf << 1) | (u >> 1);
t = strobe;
i++;
} else
if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) {
if (i == 20) {
crc = buf ^ (buf >> 7) ^ (buf >> 14);
if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) {
data[buf >> 18] = buf >> 4;
status |= 1 << (buf >> 18);
}
j++;
}
t = strobe;
buf = 0;
i = 0;
}
w = v;
v = u;
}
} while (status != 0xf && i < GRIP_MAX_BITS_XT && j < GRIP_MAX_CHUNKS_XT && t > 0);
__restore_flags(flags);
return -(status != 0xf);
}
/*
* grip_timer() repeatedly polls the joysticks and generates events.
*/
static void grip_timer(unsigned long private)
{
struct grip *grip = (void*) private;
unsigned int data[GRIP_LENGTH_XT];
struct input_dev *dev;
int i, j;
for (i = 0; i < 2; i++) {
dev = grip->dev + i;
grip->reads++;
switch (grip->mode[i]) {
case GRIP_MODE_GPP:
if (grip_gpp_read_packet(grip->gameport, (i << 1) + 4, data)) {
grip->bads++;
break;
}
input_report_abs(dev, ABS_X, ((*data >> 15) & 1) - ((*data >> 16) & 1));
input_report_abs(dev, ABS_Y, ((*data >> 13) & 1) - ((*data >> 12) & 1));
for (j = 0; j < 12; j++)
if (grip_btn_gpp[j])
input_report_key(dev, grip_btn_gpp[j], (*data >> j) & 1);
break;
case GRIP_MODE_BD:
if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
grip->bads++;
break;
}
input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f));
input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
for (j = 0; j < 5; j++)
input_report_key(dev, grip_btn_bd[j], (data[3] >> (j + 4)) & 1);
break;
case GRIP_MODE_XT:
if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
grip->bads++;
break;
}
input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f));
input_report_abs(dev, ABS_BRAKE, (data[1] >> 2) & 0x3f);
input_report_abs(dev, ABS_GAS, (data[1] >> 8) & 0x3f);
input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
input_report_abs(dev, ABS_HAT1X, ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1));
input_report_abs(dev, ABS_HAT1Y, ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1));
for (j = 0; j < 11; j++)
input_report_key(dev, grip_btn_xt[j], (data[3] >> (j + 3)) & 1);
break;
case GRIP_MODE_DC:
if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
grip->bads++;
break;
}
input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
input_report_abs(dev, ABS_Y, (data[0] >> 8) & 0x3f);
input_report_abs(dev, ABS_RX, (data[1] >> 2) & 0x3f);
input_report_abs(dev, ABS_RY, (data[1] >> 8) & 0x3f);
input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
for (j = 0; j < 9; j++)
input_report_key(dev, grip_btn_dc[j], (data[3] >> (j + 3)) & 1);
break;
}
}
mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
}
static int grip_open(struct input_dev *dev)
{
struct grip *grip = dev->private;
if (!grip->used++)
mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
return 0;
}
static void grip_close(struct input_dev *dev)
{
struct grip *grip = dev->private;
if (!--grip->used)
del_timer(&grip->timer);
}
static void grip_connect(struct gameport *gameport, struct gameport_dev *dev)
{
struct grip *grip;
unsigned int data[GRIP_LENGTH_XT];
int i, j, t;
if (!(grip = kmalloc(sizeof(struct grip), GFP_KERNEL)))
return;
memset(grip, 0, sizeof(struct grip));
gameport->private = grip;
grip->gameport = gameport;
init_timer(&grip->timer);
grip->timer.data = (long) grip;
grip->timer.function = grip_timer;
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
goto fail1;
for (i = 0; i < 2; i++) {
if (!grip_gpp_read_packet(gameport, (i << 1) + 4, data)) {
grip->mode[i] = GRIP_MODE_GPP;
continue;
}
if (!grip_xt_read_packet(gameport, (i << 1) + 4, data)) {
if (!(data[3] & 7)) {
grip->mode[i] = GRIP_MODE_BD;
continue;
}
if (!(data[2] & 0xf0)) {
grip->mode[i] = GRIP_MODE_XT;
continue;
}
grip->mode[i] = GRIP_MODE_DC;
continue;
}
}
if (!grip->mode[0] && !grip->mode[1])
goto fail2;
for (i = 0; i < 2; i++)
if (grip->mode[i]) {
sprintf(grip->phys[i], "%s/input%d", gameport->phys, i);
grip->dev[i].private = grip;
grip->dev[i].open = grip_open;
grip->dev[i].close = grip_close;
grip->dev[i].name = grip_name[grip->mode[i]];
grip->dev[i].phys = grip->phys[i];
grip->dev[i].idbus = BUS_GAMEPORT;
grip->dev[i].idvendor = GAMEPORT_ID_VENDOR_GRAVIS;
grip->dev[i].idproduct = grip->mode[i];
grip->dev[i].idversion = 0x0100;
grip->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) {
set_bit(t, grip->dev[i].absbit);
if (j < grip_cen[grip->mode[i]]) {
grip->dev[i].absmin[t] = 14;
grip->dev[i].absmax[t] = 52;
grip->dev[i].absfuzz[t] = 1;
grip->dev[i].absflat[t] = 2;
continue;
}
if (j < grip_anx[grip->mode[i]]) {
grip->dev[i].absmin[t] = 3;
grip->dev[i].absmax[t] = 57;
grip->dev[i].absfuzz[t] = 1;
continue;
}
grip->dev[i].absmin[t] = -1;
grip->dev[i].absmax[t] = 1;
}
for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++)
if (t > 0)
set_bit(t, grip->dev[i].keybit);
input_register_device(grip->dev + i);
printk(KERN_INFO "input: %s on %s\n",
grip_name[grip->mode[i]], gameport->phys);
}
return;
fail2: gameport_close(gameport);
fail1: kfree(grip);
}
static void grip_disconnect(struct gameport *gameport)
{
int i;
struct grip *grip = gameport->private;
for (i = 0; i < 2; i++)
if (grip->mode[i])
input_unregister_device(grip->dev + i);
gameport_close(gameport);
kfree(grip);
}
static struct gameport_dev grip_dev = {
connect: grip_connect,
disconnect: grip_disconnect,
};
int __init grip_init(void)
{
gameport_register_device(&grip_dev);
return 0;
}
void __exit grip_exit(void)
{
gameport_unregister_device(&grip_dev);
}
module_init(grip_init);
module_exit(grip_exit);
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:27:46
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv4772
Added Files:
Tag: 1.19
gf2k.c
Log Message:
Moved.
--- NEW FILE: gf2k.c ---
/*
* $Id: gf2k.c,v 1.19 2002/01/22 20:27:43 vojtech Exp $
*
* Copyright (c) 1998-2001 Vojtech Pavlik
*/
/*
* Genius Flight 2000 joystick 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/gameport.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("Genius Flight 2000 joystick driver");
MODULE_LICENSE("GPL");
#define GF2K_START 400 /* The time we wait for the first bit [400 us] */
#define GF2K_STROBE 40 /* The time we wait for the first bit [40 us] */
#define GF2K_TIMEOUT 4 /* Wait for everything to settle [4 ms] */
#define GF2K_LENGTH 80 /* Max number of triplets in a packet */
#define GF2K_REFRESH HZ/50 /* Time between joystick polls [20 ms] */
/*
* Genius joystick ids ...
*/
#define GF2K_ID_G09 1
#define GF2K_ID_F30D 2
#define GF2K_ID_F30 3
#define GF2K_ID_F31D 4
#define GF2K_ID_F305 5
#define GF2K_ID_F23P 6
#define GF2K_ID_F31 7
#define GF2K_ID_MAX 7
static char gf2k_length[] = { 40, 40, 40, 40, 40, 40, 40, 40 };
static char gf2k_hat_to_axis[][2] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
static char *gf2k_names[] = {"", "Genius G-09D", "Genius F-30D", "Genius F-30", "Genius MaxFighter F-31D",
"Genius F-30-5", "Genius Flight2000 F-23", "Genius F-31"};
static unsigned char gf2k_hats[] = { 0, 2, 0, 0, 2, 0, 2, 0 };
static unsigned char gf2k_axes[] = { 0, 2, 0, 0, 4, 0, 4, 0 };
static unsigned char gf2k_joys[] = { 0, 0, 0, 0,10, 0, 8, 0 };
static unsigned char gf2k_pads[] = { 0, 6, 0, 0, 0, 0, 0, 0 };
static unsigned char gf2k_lens[] = { 0,18, 0, 0,18, 0,18, 0 };
static unsigned char gf2k_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_GAS, ABS_BRAKE };
static short gf2k_btn_joy[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 };
static short gf2k_btn_pad[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_START, BTN_SELECT };
static short gf2k_seq_reset[] = { 240, 340, 0 };
static short gf2k_seq_digital[] = { 590, 320, 860, 0 };
struct gf2k {
struct gameport *gameport;
struct timer_list timer;
struct input_dev dev;
int reads;
int bads;
int used;
unsigned char id;
unsigned char length;
char phys[32];
};
/*
* gf2k_read_packet() reads a Genius Flight2000 packet.
*/
static int gf2k_read_packet(struct gameport *gameport, int length, char *data)
{
unsigned char u, v;
int i;
unsigned int t, p;
unsigned long flags;
t = gameport_time(gameport, GF2K_START);
p = gameport_time(gameport, GF2K_STROBE);
i = 0;
__save_flags(flags);
__cli();
gameport_trigger(gameport);
v = gameport_read(gameport);;
while (t > 0 && i < length) {
t--; u = v;
v = gameport_read(gameport);
if (v & ~u & 0x10) {
data[i++] = v >> 5;
t = p;
}
}
__restore_flags(flags);
return i;
}
/*
* gf2k_trigger_seq() initializes a Genius Flight2000 joystick
* into digital mode.
*/
static void gf2k_trigger_seq(struct gameport *gameport, short *seq)
{
unsigned long flags;
int i, t;
__save_flags(flags);
__cli();
i = 0;
do {
gameport_trigger(gameport);
t = gameport_time(gameport, GF2K_TIMEOUT * 1000);
while ((gameport_read(gameport) & 1) && t) t--;
udelay(seq[i]);
} while (seq[++i]);
gameport_trigger(gameport);
__restore_flags(flags);
}
/*
* js_sw_get_bits() composes bits from the triplet buffer into a __u64.
* Parameter 'pos' is bit number inside packet where to start at, 'num' is number
* of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
* is number of bits per triplet.
*/
#define GB(p,n,s) gf2k_get_bits(data, p, n, s)
static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift)
{
__u64 data = 0;
int i;
for (i = 0; i < num / 3 + 2; i++)
data |= buf[pos / 3 + i] << (i * 3);
data >>= pos % 3;
data &= (1 << num) - 1;
data <<= shift;
return data;
}
static void gf2k_read(struct gf2k *gf2k, unsigned char *data)
{
struct input_dev *dev = &gf2k->dev;
int i, t;
for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++)
input_report_abs(dev, gf2k_abs[i], GB(i<<3,8,0) | GB(i+46,1,8) | GB(i+50,1,9));
for (i = 0; i < 2 && i < gf2k_axes[gf2k->id] - 4; i++)
input_report_abs(dev, gf2k_abs[i], GB(i*9+60,8,0) | GB(i+54,1,9));
t = GB(40,4,0);
for (i = 0; i < gf2k_hats[gf2k->id]; i++)
input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]);
t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10);
for (i = 0; i < gf2k_joys[gf2k->id]; i++)
input_report_key(dev, gf2k_btn_joy[i], (t >> i) & 1);
for (i = 0; i < gf2k_pads[gf2k->id]; i++)
input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1);
}
/*
* gf2k_timer() reads and analyzes Genius joystick data.
*/
static void gf2k_timer(unsigned long private)
{
struct gf2k *gf2k = (void *) private;
unsigned char data[GF2K_LENGTH];
gf2k->reads++;
if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) {
gf2k->bads++;
} else gf2k_read(gf2k, data);
mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
}
static int gf2k_open(struct input_dev *dev)
{
struct gf2k *gf2k = dev->private;
if (!gf2k->used++)
mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
return 0;
}
static void gf2k_close(struct input_dev *dev)
{
struct gf2k *gf2k = dev->private;
if (!--gf2k->used)
del_timer(&gf2k->timer);
}
/*
* gf2k_connect() probes for Genius id joysticks.
*/
static void gf2k_connect(struct gameport *gameport, struct gameport_dev *dev)
{
struct gf2k *gf2k;
unsigned char data[GF2K_LENGTH];
int i;
if (!(gf2k = kmalloc(sizeof(struct gf2k), GFP_KERNEL)))
return;
memset(gf2k, 0, sizeof(struct gf2k));
gameport->private = gf2k;
gf2k->gameport = gameport;
init_timer(&gf2k->timer);
gf2k->timer.data = (long) gf2k;
gf2k->timer.function = gf2k_timer;
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
goto fail1;
gf2k_trigger_seq(gameport, gf2k_seq_reset);
wait_ms(GF2K_TIMEOUT);
gf2k_trigger_seq(gameport, gf2k_seq_digital);
wait_ms(GF2K_TIMEOUT);
if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12)
goto fail2;
if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5)))
goto fail2;
#ifdef RESET_WORKS
if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) ||
(gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5))))
goto fail2;
#else
gf2k->id = 6;
#endif
if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) {
printk(KERN_WARNING "gf2k.c: Not yet supported joystick on %s. [id: %d type:%s]\n",
gameport->phys, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]);
goto fail2;
}
sprintf(gf2k->phys, "%s/input0", gameport->phys);
gf2k->length = gf2k_lens[gf2k->id];
gf2k->dev.private = gf2k;
gf2k->dev.open = gf2k_open;
gf2k->dev.close = gf2k_close;
gf2k->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
gf2k->dev.name = gf2k_names[gf2k->id];
gf2k->dev.phys = gf2k->phys;
gf2k->dev.idbus = BUS_GAMEPORT;
gf2k->dev.idvendor = GAMEPORT_ID_VENDOR_GENIUS;
gf2k->dev.idproduct = gf2k->id;
gf2k->dev.idversion = 0x0100;
for (i = 0; i < gf2k_axes[gf2k->id]; i++)
set_bit(gf2k_abs[i], gf2k->dev.absbit);
for (i = 0; i < gf2k_hats[gf2k->id]; i++) {
set_bit(ABS_HAT0X + i, gf2k->dev.absbit);
gf2k->dev.absmin[ABS_HAT0X + i] = -1;
gf2k->dev.absmax[ABS_HAT0X + i] = 1;
}
for (i = 0; i < gf2k_joys[gf2k->id]; i++)
set_bit(gf2k_btn_joy[i], gf2k->dev.keybit);
for (i = 0; i < gf2k_pads[gf2k->id]; i++)
set_bit(gf2k_btn_pad[i], gf2k->dev.keybit);
gf2k_read_packet(gameport, gf2k->length, data);
gf2k_read(gf2k, data);
for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
gf2k->dev.absmin[gf2k_abs[i]] = 32;
gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
}
input_register_device(&gf2k->dev);
printk(KERN_INFO "input: %s on %s\n", gf2k_names[gf2k->id], gameport->phys);
return;
fail2: gameport_close(gameport);
fail1: kfree(gf2k);
}
static void gf2k_disconnect(struct gameport *gameport)
{
struct gf2k *gf2k = gameport->private;
input_unregister_device(&gf2k->dev);
gameport_close(gameport);
kfree(gf2k);
}
static struct gameport_dev gf2k_dev = {
connect: gf2k_connect,
disconnect: gf2k_disconnect,
};
int __init gf2k_init(void)
{
gameport_register_device(&gf2k_dev);
return 0;
}
void __exit gf2k_exit(void)
{
gameport_unregister_device(&gf2k_dev);
}
module_init(gf2k_init);
module_exit(gf2k_exit);
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:27:30
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv4639
Added Files:
Tag: 1.21
gamecon.c
Log Message:
Moved.
--- NEW FILE: gamecon.c ---
/*
* $Id: gamecon.c,v 1.21 2002/01/22 20:27:27 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Based on the work of:
* Andree Borrmann John Dahlstrom
* David Kuder Nathan Hand
*/
/*
* NES, SNES, N64, MultiSystem, PSX 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/parport.h>
#include <linux/input.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver");
MODULE_LICENSE("GPL");
MODULE_PARM(gc, "2-6i");
MODULE_PARM(gc_2,"2-6i");
MODULE_PARM(gc_3,"2-6i");
#define GC_SNES 1
#define GC_NES 2
#define GC_NES4 3
#define GC_MULTI 4
#define GC_MULTI2 5
#define GC_N64 6
#define GC_PSX 7
#define GC_MAX 7
#define GC_REFRESH_TIME HZ/100
struct gc {
struct pardevice *pd;
struct input_dev dev[5];
struct timer_list timer;
unsigned char pads[GC_MAX + 1];
int used;
char phys[5][32];
};
static struct gc *gc_base[3];
static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 };
static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 };
static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
"Multisystem 2-button joystick", "N64 controller", "PSX controller" };
/*
* N64 support.
*/
static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START };
#define GC_N64_LENGTH 32 /* N64 bit length, not including stop bit */
#define GC_N64_REQUEST_LENGTH 37 /* transmit request sequence is 9 bits long */
#define GC_N64_DELAY 133 /* delay between transmit request, and response ready (us) */
#define GC_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */
#define GC_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */
/* GC_N64_DWS > 24 is known to fail */
#define GC_N64_POWER_W 0xe2 /* power during write (transmit request) */
#define GC_N64_POWER_R 0xfd /* power during read */
#define GC_N64_OUT 0x1d /* output bits to the 4 pads */
/* Reading the main axes of any N64 pad is known to fail if the corresponding bit */
/* in GC_N64_OUT is pulled low on the output port (by any routine) for more */
/* than 123 us */
#define GC_N64_CLOCK 0x02 /* clock bits for read */
/*
* gc_n64_read_packet() reads an N64 packet.
* Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
*/
static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
{
int i;
unsigned long flags;
/*
* Request the pad to transmit data
*/
__save_flags(flags);
__cli();
for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) {
parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0));
udelay(GC_N64_DWS);
}
__restore_flags(flags);
/*
* Wait for the pad response to be loaded into the 33-bit register of the adapter
*/
udelay(GC_N64_DELAY);
/*
* Grab data (ignoring the last bit, which is a stop bit)
*/
for (i = 0; i < GC_N64_LENGTH; i++) {
parport_write_data(gc->pd->port, GC_N64_POWER_R);
data[i] = parport_read_status(gc->pd->port);
parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK);
}
/*
* We must wait 200 ms here for the controller to reinitialize before the next read request.
* No worries as long as gc_read is polled less frequently than this.
*/
}
/*
* NES/SNES support.
*/
#define GC_NES_DELAY 6 /* Delay between bits - 6us */
#define GC_NES_LENGTH 8 /* The NES pads use 8 bits of data */
#define GC_SNES_LENGTH 12 /* The SNES true length is 16, but the last 4 bits are unused */
#define GC_NES_POWER 0xfc
#define GC_NES_CLOCK 0x01
#define GC_NES_LATCH 0x02
static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR };
/*
* gc_nes_read_packet() reads a NES/SNES packet.
* Each pad uses one bit per byte. So all pads connected to
* this port are read in parallel.
*/
static void gc_nes_read_packet(struct gc *gc, int length, unsigned char *data)
{
int i;
parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK | GC_NES_LATCH);
udelay(GC_NES_DELAY * 2);
parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
for (i = 0; i < length; i++) {
udelay(GC_NES_DELAY);
parport_write_data(gc->pd->port, GC_NES_POWER);
data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
udelay(GC_NES_DELAY);
parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
}
}
/*
* Multisystem joystick support
*/
#define GC_MULTI_LENGTH 5 /* Multi system joystick packet length is 5 */
#define GC_MULTI2_LENGTH 6 /* One more bit for one more button */
/*
* gc_multi_read_packet() reads a Multisystem joystick packet.
*/
static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data)
{
int i;
for (i = 0; i < length; i++) {
parport_write_data(gc->pd->port, ~(1 << i));
data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
}
}
/*
* PSX support
*
* See documentation at:
* http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt
* http://www.gamesx.com/controldata/psxcont/psxcont.htm
* ftp://milano.usal.es/pablo/
*
*/
#define GC_PSX_DELAY 60 /* 60 usec */
#define GC_PSX_LENGTH 8 /* talk to the controller in bytes */
#define GC_PSX_MOUSE 1 /* Mouse */
#define GC_PSX_NEGCON 2 /* NegCon */
#define GC_PSX_NORMAL 4 /* Digital / Analog or Rumble in Digital mode */
#define GC_PSX_ANALOG 5 /* Analog in Analog mode / Rumble in Green mode */
#define GC_PSX_RUMBLE 7 /* Rumble in Red mode */
#define GC_PSX_CLOCK 0x04 /* Pin 4 */
#define GC_PSX_COMMAND 0x01 /* Pin 1 */
#define GC_PSX_POWER 0xf8 /* Pins 5-9 */
#define GC_PSX_SELECT 0x02 /* Pin 3 */
#define GC_PSX_ID(x) ((x) >> 4) /* High nibble is device type */
#define GC_PSX_LEN(x) ((x) & 0xf) /* Low nibble is length in words */
static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
/*
* gc_psx_command() writes 8bit command and reads 8bit data from
* the psx pad.
*/
static int gc_psx_command(struct gc *gc, int b)
{
int i, cmd, data = 0;
for (i = 0; i < 8; i++, b >>= 1) {
cmd = (b & 1) ? GC_PSX_COMMAND : 0;
parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
udelay(GC_PSX_DELAY);
data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0;
parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
udelay(GC_PSX_DELAY);
}
return data;
}
/*
* gc_psx_read_packet() reads a whole psx packet and returns
* device identifier code.
*/
static int gc_psx_read_packet(struct gc *gc, unsigned char *data)
{
int i, id;
unsigned long flags;
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */
udelay(GC_PSX_DELAY * 2);
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */
udelay(GC_PSX_DELAY * 2);
__save_flags(flags);
__cli();
gc_psx_command(gc, 0x01); /* Access pad */
id = gc_psx_command(gc, 0x42); /* Get device id */
if (gc_psx_command(gc, 0) == 0x5a) { /* Okay? */
for (i = 0; i < GC_PSX_LEN(id) * 2; i++)
data[i] = gc_psx_command(gc, 0);
} else id = 0;
__restore_flags(flags);
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
return GC_PSX_ID(id);
}
/*
* gc_timer() reads and analyzes console pads data.
*/
#define GC_MAX_LENGTH GC_N64_LENGTH
static void gc_timer(unsigned long private)
{
struct gc *gc = (void *) private;
struct input_dev *dev = gc->dev;
unsigned char data[GC_MAX_LENGTH];
int i, j, s;
/*
* N64 pads - must be read first, any read confuses them for 200 us
*/
if (gc->pads[GC_N64]) {
gc_n64_read_packet(gc, data);
for (i = 0; i < 5; i++) {
s = gc_status_bit[i];
if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) {
signed char axes[2];
axes[0] = axes[1] = 0;
for (j = 0; j < 8; j++) {
if (data[23 - j] & s) axes[0] |= 1 << j;
if (data[31 - j] & s) axes[1] |= 1 << j;
}
input_report_abs(dev + i, ABS_X, axes[0]);
input_report_abs(dev + i, ABS_Y, -axes[1]);
input_report_abs(dev + i, ABS_HAT0X, !(s & data[6]) - !(s & data[7]));
input_report_abs(dev + i, ABS_HAT0Y, !(s & data[4]) - !(s & data[5]));
for (j = 0; j < 10; j++)
input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]);
}
}
}
/*
* NES and SNES pads
*/
if (gc->pads[GC_NES] || gc->pads[GC_SNES]) {
gc_nes_read_packet(gc, gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH, data);
for (i = 0; i < 5; i++) {
s = gc_status_bit[i];
if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
input_report_abs(dev + i, ABS_X, !(s & data[6]) - !(s & data[7]));
input_report_abs(dev + i, ABS_Y, !(s & data[4]) - !(s & data[5]));
}
if (s & gc->pads[GC_NES])
for (j = 0; j < 4; j++)
input_report_key(dev + i, gc_snes_btn[j], s & data[gc_nes_bytes[j]]);
if (s & gc->pads[GC_SNES])
for (j = 0; j < 8; j++)
input_report_key(dev + i, gc_snes_btn[j], s & data[gc_snes_bytes[j]]);
}
}
/*
* Multi and Multi2 joysticks
*/
if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2]) {
gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data);
for (i = 0; i < 5; i++) {
s = gc_status_bit[i];
if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) {
input_report_abs(dev + i, ABS_X, !(s & data[2]) - !(s & data[3]));
input_report_abs(dev + i, ABS_Y, !(s & data[0]) - !(s & data[1]));
input_report_key(dev + i, BTN_TRIGGER, s & data[4]);
}
if (s & gc->pads[GC_MULTI2])
input_report_key(dev + i, BTN_THUMB, s & data[5]);
}
}
/*
* PSX controllers
*/
if (gc->pads[GC_PSX]) {
for (i = 0; i < 5; i++)
if (gc->pads[GC_PSX] & gc_status_bit[i])
break;
switch (gc_psx_read_packet(gc, data)) {
case GC_PSX_RUMBLE:
input_report_key(dev + i, BTN_THUMB, ~data[0] & 0x04);
input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
case GC_PSX_NEGCON:
case GC_PSX_ANALOG:
for (j = 0; j < 4; j++)
input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]);
input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) - !(data[0] & 0x80));
input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) - !(data[0] & 0x10));
for (j = 0; j < 8; j++)
input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j));
input_report_key(dev + i, BTN_START, ~data[0] & 0x08);
input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
break;
case GC_PSX_NORMAL:
input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128);
input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128);
for (j = 0; j < 8; j++)
input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j));
input_report_key(dev + i, BTN_START, ~data[0] & 0x08);
input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
break;
}
}
mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
}
static int gc_open(struct input_dev *dev)
{
struct gc *gc = dev->private;
if (!gc->used++) {
parport_claim(gc->pd);
parport_write_control(gc->pd->port, 0x04);
mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
}
return 0;
}
static void gc_close(struct input_dev *dev)
{
struct gc *gc = dev->private;
if (!--gc->used) {
del_timer(&gc->timer);
parport_write_control(gc->pd->port, 0x00);
parport_release(gc->pd);
}
}
static struct gc __init *gc_probe(int *config)
{
struct gc *gc;
struct parport *pp;
int i, j, psx;
unsigned char data[32];
if (config[0] < 0)
return NULL;
for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
config[0]--;
if (!pp) {
printk(KERN_ERR "gamecon.c: no such parport\n");
return NULL;
}
if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL)))
return NULL;
memset(gc, 0, sizeof(struct gc));
gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
if (!gc->pd) {
printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n");
kfree(gc);
return NULL;
}
parport_claim(gc->pd);
init_timer(&gc->timer);
gc->timer.data = (long) gc;
gc->timer.function = gc_timer;
for (i = 0; i < 5; i++) {
if (!config[i + 1])
continue;
if (config[i + 1] < 1 || config[i + 1] > GC_MAX) {
printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", config[i + 1]);
continue;
}
gc->dev[i].private = gc;
gc->dev[i].open = gc_open;
gc->dev[i].close = gc_close;
gc->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (j = 0; j < 2; j++) {
set_bit(ABS_X + j, gc->dev[i].absbit);
gc->dev[i].absmin[ABS_X + j] = -1;
gc->dev[i].absmax[ABS_X + j] = 1;
}
gc->pads[0] |= gc_status_bit[i];
gc->pads[config[i + 1]] |= gc_status_bit[i];
switch(config[i + 1]) {
case GC_N64:
for (j = 0; j < 10; j++)
set_bit(gc_n64_btn[j], gc->dev[i].keybit);
for (j = 0; j < 2; j++) {
set_bit(ABS_X + j, gc->dev[i].absbit);
gc->dev[i].absmin[ABS_X + j] = -127;
gc->dev[i].absmax[ABS_X + j] = 126;
gc->dev[i].absflat[ABS_X + j] = 2;
set_bit(ABS_HAT0X + j, gc->dev[i].absbit);
gc->dev[i].absmin[ABS_HAT0X + j] = -1;
gc->dev[i].absmax[ABS_HAT0X + j] = 1;
}
break;
case GC_SNES:
for (j = 4; j < 8; j++)
set_bit(gc_snes_btn[j], gc->dev[i].keybit);
case GC_NES:
for (j = 0; j < 4; j++)
set_bit(gc_snes_btn[j], gc->dev[i].keybit);
break;
case GC_MULTI2:
set_bit(BTN_THUMB, gc->dev[i].keybit);
case GC_MULTI:
set_bit(BTN_TRIGGER, gc->dev[i].keybit);
break;
case GC_PSX:
psx = gc_psx_read_packet(gc, data);
switch(psx) {
case GC_PSX_NEGCON:
case GC_PSX_NORMAL:
case GC_PSX_ANALOG:
case GC_PSX_RUMBLE:
for (j = 0; j < 6; j++) {
psx = gc_psx_abs[j];
set_bit(psx, gc->dev[i].absbit);
if (j < 4) {
gc->dev[i].absmin[psx] = 4;
gc->dev[i].absmax[psx] = 252;
gc->dev[i].absflat[psx] = 2;
} else {
gc->dev[i].absmin[psx] = -1;
gc->dev[i].absmax[psx] = 1;
}
}
for (j = 0; j < 12; j++)
set_bit(gc_psx_btn[j], gc->dev[i].keybit);
break;
case 0:
gc->pads[GC_PSX] &= ~gc_status_bit[i];
printk(KERN_ERR "gamecon.c: No PSX controller found.\n");
break;
default:
gc->pads[GC_PSX] &= ~gc_status_bit[i];
printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x,"
" please report to <vo...@uc...>.\n", psx);
}
break;
}
sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i);
gc->dev[i].name = gc_names[config[i + 1]];
gc->dev[i].phys = gc->phys[i];
gc->dev[i].idbus = BUS_PARPORT;
gc->dev[i].idvendor = 0x0001;
gc->dev[i].idproduct = config[i + 1];
gc->dev[i].idversion = 0x0100;
}
parport_release(gc->pd);
if (!gc->pads[0]) {
parport_unregister_device(gc->pd);
kfree(gc);
return NULL;
}
for (i = 0; i < 5; i++)
if (gc->pads[0] & gc_status_bit[i]) {
input_register_device(gc->dev + i);
printk(KERN_INFO "input: %s on %s\n", gc->dev[i].name, gc->pd->port->name);
}
return gc;
}
#ifndef MODULE
int __init gc_setup(char *str)
{
int i, ints[7];
get_options(str, ARRAY_SIZE(ints), ints);
for (i = 0; i <= ints[0] && i < 6; i++) gc[i] = ints[i + 1];
return 1;
}
int __init gc_setup_2(char *str)
{
int i, ints[7];
get_options(str, ARRAY_SIZE(ints), ints);
for (i = 0; i <= ints[0] && i < 6; i++) gc_2[i] = ints[i + 1];
return 1;
}
int __init gc_setup_3(char *str)
{
int i, ints[7];
get_options(str, ARRAY_SIZE(ints), ints);
for (i = 0; i <= ints[0] && i < 6; i++) gc_3[i] = ints[i + 1];
return 1;
}
__setup("gc=", gc_setup);
__setup("gc_2=", gc_setup_2);
__setup("gc_3=", gc_setup_3);
#endif
int __init gc_init(void)
{
gc_base[0] = gc_probe(gc);
gc_base[1] = gc_probe(gc_2);
gc_base[2] = gc_probe(gc_3);
if (gc_base[0] || gc_base[1] || gc_base[2])
return 0;
return -ENODEV;
}
void __exit gc_exit(void)
{
int i, j;
for (i = 0; i < 3; i++)
if (gc_base[i]) {
for (j = 0; j < 5; j++)
if (gc_base[i]->pads[0] & gc_status_bit[j])
input_unregister_device(gc_base[i]->dev + j);
parport_unregister_device(gc_base[i]->pd);
}
}
module_init(gc_init);
module_exit(gc_exit);
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:27:08
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv4472
Added Files:
Tag: 1.12
db9.c
Log Message:
Moved.
--- NEW FILE: db9.c ---
/*
* $Id: db9.c,v 1.12 2002/01/22 20:27:05 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Based on the work of:
* Andree Borrmann Mats Sjövall
*/
/*
* Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/parport.h>
#include <linux/input.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver");
MODULE_LICENSE("GPL");
MODULE_PARM(db9, "2i");
MODULE_PARM(db9_2, "2i");
MODULE_PARM(db9_3, "2i");
#define DB9_MULTI_STICK 0x01
#define DB9_MULTI2_STICK 0x02
#define DB9_GENESIS_PAD 0x03
#define DB9_GENESIS5_PAD 0x05
#define DB9_GENESIS6_PAD 0x06
#define DB9_SATURN_PAD 0x07
#define DB9_MULTI_0802 0x08
#define DB9_MULTI_0802_2 0x09
#define DB9_CD32_PAD 0x0A
#define DB9_MAX_PAD 0x0B
#define DB9_UP 0x01
#define DB9_DOWN 0x02
#define DB9_LEFT 0x04
#define DB9_RIGHT 0x08
#define DB9_FIRE1 0x10
#define DB9_FIRE2 0x20
#define DB9_FIRE3 0x40
#define DB9_FIRE4 0x80
#define DB9_NORMAL 0x0a
#define DB9_NOSELECT 0x08
#define DB9_SATURN0 0x00
#define DB9_SATURN1 0x02
#define DB9_SATURN2 0x04
#define DB9_SATURN3 0x06
#define DB9_GENESIS6_DELAY 14
#define DB9_REFRESH_TIME HZ/100
static int db9[] __initdata = { -1, 0 };
static int db9_2[] __initdata = { -1, 0 };
static int db9_3[] __initdata = { -1, 0 };
struct db9 {
struct input_dev dev[2];
struct timer_list timer;
struct pardevice *pd;
int mode;
int used;
char phys[2][32];
};
static struct db9 *db9_base[3];
static short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB };
static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE };
static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START };
static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 8, 1, 1, 7 };
static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn,
db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn };
static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad",
NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick",
"Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad" };
static void db9_timer(unsigned long private)
{
struct db9 *db9 = (void *) private;
struct parport *port = db9->pd->port;
struct input_dev *dev = db9->dev;
int data, i;
switch(db9->mode) {
case DB9_MULTI_0802_2:
data = parport_read_data(port) >> 3;
input_report_abs(dev + 1, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
input_report_abs(dev + 1, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
input_report_key(dev + 1, BTN_TRIGGER, ~data & DB9_FIRE1);
case DB9_MULTI_0802:
data = parport_read_status(port) >> 3;
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
input_report_key(dev, BTN_TRIGGER, data & DB9_FIRE1);
break;
case DB9_MULTI_STICK:
data = parport_read_data(port);
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
break;
case DB9_MULTI2_STICK:
data = parport_read_data(port);
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
input_report_key(dev, BTN_THUMB, ~data & DB9_FIRE2);
break;
case DB9_GENESIS_PAD:
parport_write_control(port, DB9_NOSELECT);
data = parport_read_data(port);
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
parport_write_control(port, DB9_NORMAL);
data=parport_read_data(port);
input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
input_report_key(dev, BTN_START, ~data & DB9_FIRE2);
break;
case DB9_GENESIS5_PAD:
parport_write_control(port, DB9_NOSELECT);
data=parport_read_data(port);
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
parport_write_control(port, DB9_NORMAL);
data=parport_read_data(port);
input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
input_report_key(dev, BTN_X, ~data & DB9_FIRE2);
input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
break;
case DB9_GENESIS6_PAD:
parport_write_control(port, DB9_NOSELECT); /* 1 */
udelay(DB9_GENESIS6_DELAY);
data=parport_read_data(port);
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
parport_write_control(port, DB9_NORMAL);
udelay(DB9_GENESIS6_DELAY);
data=parport_read_data(port);
input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
input_report_key(dev, BTN_X, ~data & DB9_FIRE2);
parport_write_control(port, DB9_NOSELECT); /* 2 */
udelay(DB9_GENESIS6_DELAY);
parport_write_control(port, DB9_NORMAL);
udelay(DB9_GENESIS6_DELAY);
parport_write_control(port, DB9_NOSELECT); /* 3 */
udelay(DB9_GENESIS6_DELAY);
data=parport_read_data(port);
input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
input_report_key(dev, BTN_Z, ~data & DB9_DOWN);
input_report_key(dev, BTN_MODE, ~data & DB9_UP);
input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
parport_write_control(port, DB9_NORMAL);
udelay(DB9_GENESIS6_DELAY);
parport_write_control(port, DB9_NOSELECT); /* 4 */
udelay(DB9_GENESIS6_DELAY);
parport_write_control(port, DB9_NORMAL);
break;
case DB9_SATURN_PAD:
parport_write_control(port, DB9_SATURN0);
data = parport_read_data(port);
input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
input_report_key(dev, BTN_Z, ~data & DB9_DOWN);
input_report_key(dev, BTN_TL, ~data & DB9_UP);
input_report_key(dev, BTN_TR, ~data & DB9_RIGHT);
parport_write_control(port, DB9_SATURN2);
data = parport_read_data(port);
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
parport_write_control(port, DB9_NORMAL);
data = parport_read_data(port);
input_report_key(dev, BTN_A, ~data & DB9_LEFT);
input_report_key(dev, BTN_B, ~data & DB9_UP);
input_report_key(dev, BTN_C, ~data & DB9_DOWN);
input_report_key(dev, BTN_X, ~data & DB9_RIGHT);
break;
case DB9_CD32_PAD:
data=parport_read_data(port);
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
parport_write_control(port, 0x0a);
for (i = 0; i < 7; i++) {
data = parport_read_data(port);
parport_write_control(port, 0x02);
parport_write_control(port, 0x0a);
input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2);
}
parport_write_control(port, 0x00);
break;
}
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
}
static int db9_open(struct input_dev *dev)
{
struct db9 *db9 = dev->private;
struct parport *port = db9->pd->port;
if (!db9->used++) {
parport_claim(db9->pd);
parport_write_data(port, 0xff);
parport_data_reverse(port);
parport_write_control(port, DB9_NORMAL);
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
}
return 0;
}
static void db9_close(struct input_dev *dev)
{
struct db9 *db9 = dev->private;
struct parport *port = db9->pd->port;
if (!--db9->used) {
del_timer(&db9->timer);
parport_write_control(port, 0x00);
parport_data_forward(port);
parport_release(db9->pd);
}
}
static struct db9 __init *db9_probe(int *config)
{
struct db9 *db9;
struct parport *pp;
int i, j;
if (config[0] < 0)
return NULL;
if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) {
printk(KERN_ERR "db9.c: bad config\n");
return NULL;
}
for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
config[0]--;
if (!pp) {
printk(KERN_ERR "db9.c: no such parport\n");
return NULL;
}
if (!(pp->modes & PARPORT_MODE_TRISTATE) && config[1] != DB9_MULTI_0802) {
printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
return NULL;
}
if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL)))
return NULL;
memset(db9, 0, sizeof(struct db9));
db9->mode = config[1];
init_timer(&db9->timer);
db9->timer.data = (long) db9;
db9->timer.function = db9_timer;
db9->pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
if (!db9->pd) {
printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n");
kfree(db9);
return NULL;
}
for (i = 0; i < 1 + (db9->mode == DB9_MULTI_0802_2); i++) {
sprintf(db9->phys[i], "%s/input%d", db9->pd->port->name, i);
db9->dev[i].private = db9;
db9->dev[i].open = db9_open;
db9->dev[i].close = db9_close;
db9->dev[i].name = db9_name[db9->mode];
db9->dev[i].phys = db9->phys[i];
db9->dev[i].idbus = BUS_PARPORT;
db9->dev[i].idvendor = 0x0002;
db9->dev[i].idproduct = config[1];
db9->dev[i].idversion = 0x0100;
db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
db9->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
for (j = 0; j < db9_buttons[db9->mode]; j++)
set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit);
db9->dev[i].absmin[ABS_X] = -1; db9->dev[i].absmax[ABS_X] = 1;
db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1;
input_register_device(db9->dev + i);
printk(KERN_INFO "input: %s on %s\n", db9->dev[i].name, db9->pd->port->name);
}
return db9;
}
#ifndef MODULE
int __init db9_setup(char *str)
{
int i, ints[3];
get_options(str, ARRAY_SIZE(ints), ints);
for (i = 0; i <= ints[0] && i < 2; i++) db9[i] = ints[i + 1];
return 1;
}
int __init db9_setup_2(char *str)
{
int i, ints[3];
get_options(str, ARRAY_SIZE(ints), ints);
for (i = 0; i <= ints[0] && i < 2; i++) db9_2[i] = ints[i + 1];
return 1;
}
int __init db9_setup_3(char *str)
{
int i, ints[3];
get_options(str, ARRAY_SIZE(ints), ints);
for (i = 0; i <= ints[0] && i < 2; i++) db9_3[i] = ints[i + 1];
return 1;
}
__setup("db9=", db9_setup);
__setup("db9_2=", db9_setup_2);
__setup("db9_3=", db9_setup_3);
#endif
int __init db9_init(void)
{
db9_base[0] = db9_probe(db9);
db9_base[1] = db9_probe(db9_2);
db9_base[2] = db9_probe(db9_3);
if (db9_base[0] || db9_base[1] || db9_base[2])
return 0;
return -ENODEV;
}
void __exit db9_exit(void)
{
int i, j;
for (i = 0; i < 3; i++)
if (db9_base[i]) {
for (j = 0; j < 1 + (db9_base[i]->mode == DB9_MULTI_0802_2); j++)
input_unregister_device(db9_base[i]->dev + j);
parport_unregister_device(db9_base[i]->pd);
}
}
module_init(db9_init);
module_exit(db9_exit);
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:26:54
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv4328
Added Files:
Tag: 1.19
cobra.c
Log Message:
Moved.
--- NEW FILE: cobra.c ---
/*
* $Id: cobra.c,v 1.19 2002/01/22 20:26:52 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
/*
* Creative Labs Blaster GamePad Cobra 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/input.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("Creative Labs Blaster GamePad Cobra driver");
MODULE_LICENSE("GPL");
#define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */
#define COBRA_REFRESH_TIME HZ/50 /* 20 ms between reads */
#define COBRA_LENGTH 36
static char* cobra_name = "Creative Labs Blaster GamePad Cobra";
static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 };
struct cobra {
struct gameport *gameport;
struct timer_list timer;
struct input_dev dev[2];
int used;
int reads;
int bads;
unsigned char exists;
char phys[2][32];
};
static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data)
{
unsigned long flags;
unsigned char u, v, w;
__u64 buf[2];
int r[2], t[2];
int i, j, ret;
int strobe = gameport_time(gameport, COBRA_MAX_STROBE);
for (i = 0; i < 2; i++) {
r[i] = buf[i] = 0;
t[i] = COBRA_MAX_STROBE;
}
__save_flags(flags);
__cli();
u = gameport_read(gameport);
do {
t[0]--; t[1]--;
v = gameport_read(gameport);
for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2)
if (w & 0x30) {
if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) {
buf[i] |= (__u64)((w >> 5) & 1) << r[i]++;
t[i] = strobe;
u = v;
} else t[i] = 0;
}
} while (t[0] > 0 || t[1] > 0);
__restore_flags(flags);
ret = 0;
for (i = 0; i < 2; i++) {
if (r[i] != COBRA_LENGTH) continue;
for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++)
buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1));
if (j < COBRA_LENGTH) ret |= (1 << i);
data[i] = ((buf[i] >> 7) & 0x000001f) | ((buf[i] >> 8) & 0x00003e0)
| ((buf[i] >> 9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000)
| ((buf[i] >> 11) & 0x1f00000);
}
return ret;
}
static void cobra_timer(unsigned long private)
{
struct cobra *cobra = (void *) private;
struct input_dev *dev;
unsigned int data[2];
int i, j, r;
cobra->reads++;
if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists)
cobra->bads++;
else
for (i = 0; i < 2; i++)
if (cobra->exists & r & (1 << i)) {
dev = cobra->dev + i;
input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1));
input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1));
for (j = 0; cobra_btn[j]; j++)
input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j));
}
mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
}
static int cobra_open(struct input_dev *dev)
{
struct cobra *cobra = dev->private;
if (!cobra->used++)
mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
return 0;
}
static void cobra_close(struct input_dev *dev)
{
struct cobra *cobra = dev->private;
if (!--cobra->used)
del_timer(&cobra->timer);
}
static void cobra_connect(struct gameport *gameport, struct gameport_dev *dev)
{
struct cobra *cobra;
unsigned int data[2];
int i, j;
if (!(cobra = kmalloc(sizeof(struct cobra), GFP_KERNEL)))
return;
memset(cobra, 0, sizeof(struct cobra));
gameport->private = cobra;
cobra->gameport = gameport;
init_timer(&cobra->timer);
cobra->timer.data = (long) cobra;
cobra->timer.function = cobra_timer;
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
goto fail1;
cobra->exists = cobra_read_packet(gameport, data);
for (i = 0; i < 2; i++)
if ((cobra->exists >> i) & data[i] & 1) {
printk(KERN_WARNING "cobra.c: Device %d on %s has the Ext bit set. ID is: %d"
" Contact vo...@uc...\n", i, gameport->phys, (data[i] >> 2) & 7);
cobra->exists &= ~(1 << i);
}
if (!cobra->exists)
goto fail2;
for (i = 0; i < 2; i++)
if ((cobra->exists >> i) & 1) {
sprintf(cobra->phys[i], "%s/input%d", gameport->phys, i);
cobra->dev[i].private = cobra;
cobra->dev[i].open = cobra_open;
cobra->dev[i].close = cobra_close;
cobra->dev[i].name = cobra_name;
cobra->dev[i].phys = cobra->phys[i];
cobra->dev[i].idbus = BUS_GAMEPORT;
cobra->dev[i].idvendor = GAMEPORT_ID_VENDOR_CREATIVE;
cobra->dev[i].idproduct = 0x0008;
cobra->dev[i].idversion = 0x0100;
cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
for (j = 0; cobra_btn[j]; j++)
set_bit(cobra_btn[j], cobra->dev[i].keybit);
cobra->dev[i].absmin[ABS_X] = -1; cobra->dev[i].absmax[ABS_X] = 1;
cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1;
input_register_device(cobra->dev + i);
printk(KERN_INFO "input: %s on %s\n", cobra_name, gameport->phys);
}
return;
fail2: gameport_close(gameport);
fail1: kfree(cobra);
}
static void cobra_disconnect(struct gameport *gameport)
{
int i;
struct cobra *cobra = gameport->private;
for (i = 0; i < 2; i++)
if ((cobra->exists >> i) & 1)
input_unregister_device(cobra->dev + i);
gameport_close(gameport);
kfree(cobra);
}
static struct gameport_dev cobra_dev = {
connect: cobra_connect,
disconnect: cobra_disconnect,
};
int __init cobra_init(void)
{
gameport_register_device(&cobra_dev);
return 0;
}
void __exit cobra_exit(void)
{
gameport_unregister_device(&cobra_dev);
}
module_init(cobra_init);
module_exit(cobra_exit);
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:26:35
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv4206
Added Files:
Tag: 1.13
amijoy.c
Log Message:
Moved.
--- NEW FILE: amijoy.c ---
/*
* $Id: amijoy.c,v 1.13 2002/01/22 20:26:32 vojtech Exp $
*
* Copyright (c) 1998-2001 Vojtech Pavlik
*/
/*
* Driver for Amiga joysticks for Linux/m68k
*/
/*
* 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <asm/system.h>
#include <asm/amigahw.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("Driver for Amiga joysticks");
MODULE_PARM(amijoy, "1-2i");
MODULE_LICENSE("GPL");
static int amijoy[2] = { 0, 1 };
static int amijoy_used[2] = { 0, 0 };
static struct input_dev amijoy_dev[2];
static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
static char *amijoy_name = "Amiga joystick";
static void amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
int i, data = 0, button = 0;
for (i = 0; i < 2; i++)
if (amijoy[i]) {
switch (i) {
case 0: data = ~custom.joy0dat; button = (~ciaa.pra >> 6) & 1; break;
case 1: data = ~custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break;
}
input_report_key(amijoy_dev + i, BTN_TRIGGER, button);
input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1));
data = ~(data ^ (data << 1));
input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1));
}
}
static int amijoy_open(struct input_dev *dev)
{
int *used = dev->private;
if ((*used)++)
return 0;
if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", NULL)) {
(*used)--;
printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", amijoy_irq);
return -EBUSY;
}
return 0;
}
static void amijoy_close(struct input_dev *dev)
{
int *used = dev->private;
if (!--(*used))
free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
}
static int __init amijoy_setup(char *str)
{
int i;
int ints[4]
str = get_options(str, ARRAY_SIZE(ints), ints);
for (i = 0; i <= ints[0] && i < 2; i++) amijoy[i] = ints[i+1];
return 1;
}
__setup("amijoy=", amijoy_setup);
static int __init amijoy_init(void)
{
int i, j;
init_timer(amijoy_timer);
port->timer.function = amijoy_timer;
for (i = 0; i < 2; i++)
if (amijoy[i]) {
if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2,
"amijoy [Denise]")) {
if (i == 1 && amijoy[0]) {
input_unregister_device(amijoy_dev);
release_mem_region(CUSTOM_PHYSADDR+10, 2);
}
return -EBUSY;
}
amijoy_dev[i].open = amijoy_open;
amijoy_dev[i].close = amijoy_close;
amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
for (j = 0; j < 2; j++) {
amijoy_dev[i].absmin[ABS_X + j] = -1;
amijoy_dev[i].absmax[ABS_X + j] = 1;
}
amijoy->dev[i].name = amijoy_name;
amijoy->dev[i].phys = amijoy_phys[i];
amijoy->dev[i].idbus = BUS_AMIGA;
amijoy->dev[i].idvendor = 0x0001;
amijoy->dev[i].idproduct = 0x0003;
amijoy->dev[i].version = 0x0100;
amijoy_dev[i].private = amijoy_used + i;
input_register_device(amijoy_dev + i);
printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
}
return 0;
}
static void _exit amijoy_exit(void)
{
int i;
for (i = 0; i < 2; i++)
if (amijoy[i]) {
input_unregister_device(amijoy_dev + i);
release_mem_region(CUSTOM_PHYSADDR+10+i*2, 2);
}
}
module_init(amijoy_init);
module_exit(amijoy_exit);
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:26:20
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv4105
Added Files:
Tag: 1.23
adi.c
Log Message:
Moved.
--- NEW FILE: adi.c ---
/*
* $Id: adi.c,v 1.23 2002/01/22 20:26:17 vojtech Exp $
*
* Copyright (c) 1998-2001 Vojtech Pavlik
*/
/*
* Logitech ADI joystick family 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/gameport.h>
#include <linux/init.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("Logitech ADI joystick family driver");
MODULE_LICENSE("GPL");
/*
* Times, array sizes, flags, ids.
*/
#define ADI_MAX_START 200 /* Trigger to packet timeout [200us] */
#define ADI_MAX_STROBE 40 /* Single bit timeout [40us] */
#define ADI_REFRESH_TIME HZ/50 /* How often to poll the joystick [20 ms] */
#define ADI_INIT_DELAY 10 /* Delay after init packet [10ms] */
#define ADI_DATA_DELAY 4 /* Delay after data packet [4ms] */
#define ADI_MAX_LENGTH 256
#define ADI_MIN_LENGTH 8
#define ADI_MIN_LEN_LENGTH 10
#define ADI_MIN_ID_LENGTH 66
#define ADI_MAX_NAME_LENGTH 48
#define ADI_MAX_CNAME_LENGTH 16
#define ADI_MAX_PHYS_LENGTH 32
#define ADI_FLAG_HAT 0x04
#define ADI_FLAG_10BIT 0x08
#define ADI_ID_TPD 0x01
#define ADI_ID_WGP 0x06
#define ADI_ID_WGPE 0x08
#define ADI_ID_MAX 0x0a
/*
* Names, buttons, axes ...
*/
static char *adi_names[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2",
"WingMan Interceptor", "WingMan Formula", "WingMan GamePad",
"WingMan Extreme Digital 3D", "WingMan GamePad Extreme",
"WingMan GamePad USB", "Unknown Device %#x" };
static char adi_wmgpe_abs[] = { ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y };
static char adi_wmi_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
static char adi_wmed3d_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y };
static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs,
adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs };
static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key,
adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key };
/*
* Hat to axis conversion arrays.
*/
static struct {
int x;
int y;
} adi_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
/*
* Per-port information.
*/
struct adi {
struct input_dev dev;
int length;
int ret;
int idx;
unsigned char id;
char buttons;
char axes10;
char axes8;
signed char pad;
char hats;
char *abs;
short *key;
char name[ADI_MAX_NAME_LENGTH];
char cname[ADI_MAX_CNAME_LENGTH];
char phys[ADI_MAX_PHYS_LENGTH];
unsigned char data[ADI_MAX_LENGTH];
};
struct adi_port {
struct gameport *gameport;
struct timer_list timer;
struct adi adi[2];
int bad;
int reads;
int used;
};
/*
* adi_read_packet() reads a Logitech ADI packet.
*/
static void adi_read_packet(struct adi_port *port)
{
struct adi *adi = port->adi;
struct gameport *gameport = port->gameport;
unsigned char u, v, w, x, z;
int t[2], s[2], i;
unsigned long flags;
for (i = 0; i < 2; i++) {
adi[i].ret = -1;
t[i] = gameport_time(gameport, ADI_MAX_START);
s[i] = 0;
}
__save_flags(flags);
__cli();
gameport_trigger(gameport);
v = z = gameport_read(gameport);
do {
u = v;
w = u ^ (v = x = gameport_read(gameport));
for (i = 0; i < 2; i++, w >>= 2, x >>= 2) {
t[i]--;
if ((w & 0x30) && s[i]) {
if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) {
adi[i].data[++adi[i].ret] = w;
t[i] = gameport_time(gameport, ADI_MAX_STROBE);
} else t[i] = 0;
} else if (!(x & 0x30)) s[i] = 1;
}
} while (t[0] > 0 || t[1] > 0);
__restore_flags(flags);
return;
}
/*
* adi_move_bits() detects a possible 2-stream mode, and moves
* the bits accordingly.
*/
static void adi_move_bits(struct adi_port *port, int length)
{
int i;
struct adi *adi = port->adi;
adi[0].idx = adi[1].idx = 0;
if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
for (i = 1; i <= adi[1].ret; i++)
adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i];
adi[0].ret += adi[1].ret;
adi[1].ret = -1;
}
/*
* adi_get_bits() gathers bits from the data packet.
*/
static inline int adi_get_bits(struct adi *adi, int count)
{
int bits = 0;
int i;
if ((adi->idx += count) > adi->ret) return 0;
for (i = 0; i < count; i++)
bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i;
return bits;
}
/*
* adi_decode() decodes Logitech joystick data into input events.
*/
static int adi_decode(struct adi *adi)
{
struct input_dev *dev = &adi->dev;
char *abs = adi->abs;
short *key = adi->key;
int i, t;
if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4)))
return -1;
for (i = 0; i < adi->axes10; i++)
input_report_abs(dev, *abs++, adi_get_bits(adi, 10));
for (i = 0; i < adi->axes8; i++)
input_report_abs(dev, *abs++, adi_get_bits(adi, 8));
for (i = 0; i < adi->buttons && i < 63; i++) {
if (i == adi->pad) {
t = adi_get_bits(adi, 4);
input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t & 1));
input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1));
}
input_report_key(dev, *key++, adi_get_bits(adi, 1));
}
for (i = 0; i < adi->hats; i++) {
if ((t = adi_get_bits(adi, 4)) > 8) t = 0;
input_report_abs(dev, *abs++, adi_hat_to_axis[t].x);
input_report_abs(dev, *abs++, adi_hat_to_axis[t].y);
}
for (i = 63; i < adi->buttons; i++)
input_report_key(dev, *key++, adi_get_bits(adi, 1));
return 0;
}
/*
* adi_read() reads the data packet and decodes it.
*/
static int adi_read(struct adi_port *port)
{
int i;
int result = 0;
adi_read_packet(port);
adi_move_bits(port, port->adi[0].length);
for (i = 0; i < 2; i++)
if (port->adi[i].length)
result |= adi_decode(port->adi + i);
return result;
}
/*
* adi_timer() repeatedly polls the Logitech joysticks.
*/
static void adi_timer(unsigned long data)
{
struct adi_port *port = (void *) data;
port->bad -= adi_read(port);
port->reads++;
mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
}
/*
* adi_open() is a callback from the input open routine.
*/
static int adi_open(struct input_dev *dev)
{
struct adi_port *port = dev->private;
if (!port->used++)
mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
return 0;
}
/*
* adi_close() is a callback from the input close routine.
*/
static void adi_close(struct input_dev *dev)
{
struct adi_port *port = dev->private;
if (!--port->used)
del_timer(&port->timer);
}
/*
* adi_init_digital() sends a trigger & delay sequence
* to reset and initialize a Logitech joystick into digital mode.
*/
static void adi_init_digital(struct gameport *gameport)
{
int seq[] = { 3, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
int i;
for (i = 0; seq[i]; i++) {
gameport_trigger(gameport);
if (seq[i] > 0) wait_ms(seq[i]);
if (seq[i] < 0) mdelay(-seq[i]);
}
}
static void adi_id_decode(struct adi *adi, struct adi_port *port)
{
int i, t;
if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */
return;
if (adi->ret < (t = adi_get_bits(adi, 10))) {
printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret);
return;
}
adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4);
if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++;
adi->length = adi_get_bits(adi, 10);
if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) {
printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length);
adi->length = 0;
return;
}
adi->axes8 = adi_get_bits(adi, 4);
adi->buttons = adi_get_bits(adi, 6);
if (adi_get_bits(adi, 6) != 8 && adi->hats) {
printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n");
adi->length = 0;
return;
}
adi->buttons += adi_get_bits(adi, 6);
adi->hats += adi_get_bits(adi, 4);
i = adi_get_bits(adi, 4);
if (t & ADI_FLAG_10BIT) {
adi->axes10 = adi->axes8 - i;
adi->axes8 = i;
}
t = adi_get_bits(adi, 4);
for (i = 0; i < t; i++)
adi->cname[i] = adi_get_bits(adi, 8);
adi->cname[i] = 0;
t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4;
if (adi->length != t && adi->length != t + (t & 1)) {
printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length);
adi->length = 0;
return;
}
switch (adi->id) {
case ADI_ID_TPD:
adi->pad = 4;
adi->buttons -= 4;
break;
case ADI_ID_WGP:
adi->pad = 0;
adi->buttons -= 4;
break;
default:
adi->pad = -1;
break;
}
}
static void adi_init_input(struct adi *adi, struct adi_port *port, int half)
{
int i, t;
char buf[ADI_MAX_NAME_LENGTH];
if (!adi->length) return;
t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX;
sprintf(buf, adi_names[t], adi->id);
sprintf(adi->name, "Logitech %s", buf);
sprintf(adi->phys, "%s/input%d", port->gameport->phys, half);
adi->abs = adi_abs[t];
adi->key = adi_key[t];
adi->dev.open = adi_open;
adi->dev.close = adi_close;
adi->dev.name = adi->name;
adi->dev.phys = adi->phys;
adi->dev.idbus = BUS_GAMEPORT;
adi->dev.idvendor = GAMEPORT_ID_VENDOR_LOGITECH;
adi->dev.idproduct = adi->id;
adi->dev.idversion = 0x0100;
adi->dev.private = port;
adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++)
set_bit(adi->abs[i], &adi->dev.absbit);
for (i = 0; i < adi->buttons; i++)
set_bit(adi->key[i], &adi->dev.keybit);
}
static void adi_init_center(struct adi *adi)
{
int i, t, x;
if (!adi->length) return;
for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) {
t = adi->abs[i];
x = adi->dev.abs[t];
if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) {
if (i < adi->axes10) x = 512; else x = 128;
}
if (i < adi->axes10) {
adi->dev.absmax[t] = x * 2 - 64;
adi->dev.absmin[t] = 64;
adi->dev.absfuzz[t] = 2;
adi->dev.absflat[t] = 16;
continue;
}
if (i < adi->axes10 + adi->axes8) {
adi->dev.absmax[t] = x * 2 - 48;
adi->dev.absmin[t] = 48;
adi->dev.absfuzz[t] = 1;
adi->dev.absflat[t] = 16;
continue;
}
adi->dev.absmax[t] = 1;
adi->dev.absmin[t] = -1;
}
}
/*
* adi_connect() probes for Logitech ADI joysticks.
*/
static void adi_connect(struct gameport *gameport, struct gameport_dev *dev)
{
struct adi_port *port;
int i;
if (!(port = kmalloc(sizeof(struct adi_port), GFP_KERNEL)))
return;
memset(port, 0, sizeof(struct adi_port));
gameport->private = port;
port->gameport = gameport;
init_timer(&port->timer);
port->timer.data = (long) port;
port->timer.function = adi_timer;
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
kfree(port);
return;
}
adi_init_digital(gameport);
adi_read_packet(port);
if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH)
adi_move_bits(port, adi_get_bits(port->adi, 10));
for (i = 0; i < 2; i++) {
adi_id_decode(port->adi + i, port);
adi_init_input(port->adi + i, port, i);
}
if (!port->adi[0].length && !port->adi[1].length) {
gameport_close(gameport);
kfree(port);
return;
}
wait_ms(ADI_INIT_DELAY);
if (adi_read(port)) {
wait_ms(ADI_DATA_DELAY);
adi_read(port);
}
for (i = 0; i < 2; i++)
if (port->adi[i].length > 0) {
adi_init_center(port->adi + i);
input_register_device(&port->adi[i].dev);
printk(KERN_INFO "input: %s [%s] on %s\n",
port->adi[i].name, port->adi[i].cname, gameport->phys);
}
}
static void adi_disconnect(struct gameport *gameport)
{
int i;
struct adi_port *port = gameport->private;
for (i = 0; i < 2; i++)
if (port->adi[i].length > 0)
input_unregister_device(&port->adi[i].dev);
gameport_close(gameport);
kfree(port);
}
/*
* The gameport device structure.
*/
static struct gameport_dev adi_dev = {
connect: adi_connect,
disconnect: adi_disconnect,
};
int __init adi_init(void)
{
gameport_register_device(&adi_dev);
return 0;
}
void __exit adi_exit(void)
{
gameport_unregister_device(&adi_dev);
}
module_init(adi_init);
module_exit(adi_exit);
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:22:01
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input
In directory usw-pr-cvs1:/tmp/cvs-serv2215
Modified Files:
fm801-gp.c ns558.c tsdev.c
Removed Files:
a3d.c analog.c
Log Message:
Fixes.
Index: fm801-gp.c
===================================================================
RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/input/fm801-gp.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- fm801-gp.c 2001/12/13 16:30:17 1.1
+++ fm801-gp.c 2002/01/22 20:21:58 1.2
@@ -39,6 +39,8 @@
struct fm801_gp {
struct gameport gameport;
struct resource *res_port;
+ char phys[32];
+ char name[32];
};
#ifdef HAVE_COOKED
@@ -96,19 +98,26 @@
pci_enable_device(pci);
gp->gameport.io = pci_resource_start(pci, 0);
if ((gp->res_port = request_region(gp->gameport.io, 0x10, "FM801 GP")) == NULL) {
+ kfree(gp);
printk("unable to grab region 0x%x-0x%x\n", gp->gameport.io, gp->gameport.io + 0x0f);
return -1;
}
+ gp->gameport.phys = gp->phys;
+ gp->gameport.name = gp->name;
+ gp->gameport.idbus = BUS_PCI;
+ gp->gameport.idvendor = pci->vendor;
+ gp->gameport.idproduct = pci->device;
+
pci_set_drvdata(pci, gp);
- gameport_register_port(&gp->gameport);
-
+
outb(0x60, gp->gameport.io + 0x0d); /* enable joystick 1 and 2 */
- printk(KERN_INFO "gameport%d: %s at pci%02x:%02x.%x speed %d kHz\n",
- gp->gameport.number, pci->name, pci->bus->number,
- PCI_SLOT(pci->devfn), PCI_FUNC(pci->devfn), gp->gameport.speed);
-
+ gameport_register_port(&gp->gameport);
+
+ printk(KERN_INFO "gameport: %s at pci%s speed %d kHz\n",
+ pci->name, pci->slot_name, gp->gameport.speed);
+
return 0;
}
Index: ns558.c
===================================================================
RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/input/ns558.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -d -r1.41 -r1.42
--- ns558.c 2001/12/26 21:08:33 1.41
+++ ns558.c 2002/01/22 20:21:58 1.42
@@ -145,9 +145,6 @@
port->gameport.phys = port->phys;
port->gameport.name = port->name;
port->gameport.idbus = BUS_ISA;
- port->gameport.idvendor = 0x0000;
- port->gameport.idproduct = 0x0000;
- port->gameport.idversion = 0x0000;
sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i));
sprintf(port->name, "NS558 ISA");
Index: tsdev.c
===================================================================
RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/input/tsdev.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- tsdev.c 2002/01/20 03:54:46 1.11
+++ tsdev.c 2002/01/22 20:21:58 1.12
@@ -302,7 +302,7 @@
wake_up_interruptible(&tsdev->wait);
}
-static struct input_handle *tsdev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *tsdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
{
struct tsdev *tsdev;
int minor;
--- a3d.c DELETED ---
--- analog.c DELETED ---
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:18:35
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv1006
Added Files:
Tag: 1.68
analog.c
Log Message:
Moved.
--- NEW FILE: analog.c ---
/*
* $Id: analog.c,v 1.68 2002/01/22 20:18:32 vojtech 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#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 <vo...@uc...>");
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 TSC_PRESENT (test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability))
#define GET_TIME(x) do { if (TSC_PRESENT) rdtscl(x); else x = get_time_pit(); } while (0)
#define DELTA(x,y) (TSC_PRESENT?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0)))
#define TIME_NAME (TSC_PRESENT?"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) get_cycles(x)
#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));
}
}
/*
* 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;
__save_flags(flags);
__cli();
gameport_trigger(gameport);
GET_TIME(now);
__restore_flags(flags);
start = now;
this = port->mask;
i = 0;
do {
loop = now;
last = this;
__cli();
this = gameport_read(gameport) & port->mask;
GET_TIME(now);
__restore_flags(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;
save_flags(flags);
cli();
GET_TIME(t1);
#ifdef FAKE_TIME
analog_faketime += 830;
#endif
udelay(1000);
GET_TIME(t2);
GET_TIME(t3);
restore_flags(flags);
port->speed = DELTA(t1, t2) - DELTA(t2, t3);
tx = ~0;
for (i = 0; i < 50; i++) {
save_flags(flags);
cli();
GET_TIME(t1);
for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); }
GET_TIME(t3);
restore_flags(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)
{
sprintf(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)
sprintf(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);
sprintf(analog->phys, "%s/input%d", port->gameport->phys, index);
analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn;
analog->dev.name = analog->name;
analog->dev.phys = analog->phys;
analog->dev.idbus = BUS_GAMEPORT;
analog->dev.idvendor = GAMEPORT_ID_VENDOR_ANALOG;
analog->dev.idproduct = analog->mask >> 4;
analog->dev.idversion = 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);
|
|
From: Vojtech P. <vo...@us...> - 2002-01-22 20:11:52
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick
In directory usw-pr-cvs1:/tmp/cvs-serv30758
Modified Files:
Tag: 1.21
a3d.c
Log Message:
Moved.
--- NEW FILE: a3d.c ---
/*
* $Id: a3d.c,v 1.21 2002/01/22 20:11:50 vojtech Exp $
*
* Copyright (c) 1998-2001 Vojtech Pavlik
*/
/*
* FP-Gaming Assasin 3D joystick 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/input.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("FP-Gaming Assasin 3D joystick driver");
MODULE_LICENSE("GPL");
#define A3D_MAX_START 400 /* 400 us */
#define A3D_MAX_STROBE 60 /* 40 us */
#define A3D_DELAY_READ 3 /* 3 ms */
#define A3D_MAX_LENGTH 40 /* 40*3 bits */
#define A3D_REFRESH_TIME HZ/50 /* 20 ms */
#define A3D_MODE_A3D 1 /* Assassin 3D */
#define A3D_MODE_PAN 2 /* Panther */
#define A3D_MODE_OEM 3 /* Panther OEM version */
#define A3D_MODE_PXL 4 /* Panther XL */
char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
"MadCatz Panther XL", "MadCatz Panther XL w/ rudder" };
struct a3d {
struct gameport *gameport;
struct gameport adc;
struct input_dev dev;
struct timer_list timer;
int axes[4];
int buttons;
int mode;
int length;
int used;
int reads;
int bads;
char phys[32];
char adcphys[32];
};
/*
* a3d_read_packet() reads an Assassin 3D packet.
*/
static int a3d_read_packet(struct gameport *gameport, int length, char *data)
{
unsigned long flags;
unsigned char u, v;
unsigned int t, s;
int i;
i = 0;
t = gameport_time(gameport, A3D_MAX_START);
s = gameport_time(gameport, A3D_MAX_STROBE);
__save_flags(flags);
__cli();
gameport_trigger(gameport);
v = gameport_read(gameport);
while (t > 0 && i < length) {
t--;
u = v; v = gameport_read(gameport);
if (~v & u & 0x10) {
data[i++] = v >> 5;
t = s;
}
}
__restore_flags(flags);
return i;
}
/*
* a3d_csum() computes checksum of triplet packet
*/
static int a3d_csum(char *data, int count)
{
int i, csum = 0;
for (i = 0; i < count - 2; i++) csum += data[i];
return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
}
static void a3d_read(struct a3d *a3d, unsigned char *data)
{
struct input_dev *dev = &a3d->dev;
switch (a3d->mode) {
case A3D_MODE_A3D:
case A3D_MODE_OEM:
case A3D_MODE_PAN:
input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7));
input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7));
input_report_key(dev, BTN_RIGHT, data[2] & 1);
input_report_key(dev, BTN_LEFT, data[3] & 2);
input_report_key(dev, BTN_MIDDLE, data[3] & 4);
a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
a3d->buttons = ((data[3] << 3) | data[4]) & 0xf;
return;
case A3D_MODE_PXL:
input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7));
input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7));
input_report_key(dev, BTN_RIGHT, data[2] & 1);
input_report_key(dev, BTN_LEFT, data[3] & 2);
input_report_key(dev, BTN_MIDDLE, data[3] & 4);
input_report_key(dev, BTN_SIDE, data[7] & 2);
input_report_key(dev, BTN_EXTRA, data[7] & 4);
input_report_abs(dev, ABS_X, ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128);
input_report_abs(dev, ABS_Y, ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128);
input_report_abs(dev, ABS_RUDDER, ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128);
input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128);
input_report_abs(dev, ABS_HAT0X, ( data[5] & 1) - ((data[5] >> 2) & 1));
input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1));
input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3] & 1));
input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4] & 1));
input_report_key(dev, BTN_TRIGGER, data[8] & 1);
input_report_key(dev, BTN_THUMB, data[8] & 2);
input_report_key(dev, BTN_TOP, data[8] & 4);
input_report_key(dev, BTN_PINKIE, data[7] & 1);
return;
}
}
/*
* a3d_timer() reads and analyzes A3D joystick data.
*/
static void a3d_timer(unsigned long private)
{
struct a3d *a3d = (void *) private;
unsigned char data[A3D_MAX_LENGTH];
a3d->reads++;
if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length
|| data[0] != a3d->mode || a3d_csum(data, a3d->length))
a3d->bads++; else a3d_read(a3d, data);
mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
}
/*
* a3d_adc_cooked_read() copies the acis and button data to the
* callers arrays. It could do the read itself, but the caller could
* call this more than 50 times a second, which would use too much CPU.
*/
int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
{
struct a3d *a3d = gameport->driver;
int i;
for (i = 0; i < 4; i++)
axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
*buttons = a3d->buttons;
return 0;
}
/*
* a3d_adc_open() is the gameport open routine. It refuses to serve
* any but cooked data.
*/
int a3d_adc_open(struct gameport *gameport, int mode)
{
struct a3d *a3d = gameport->driver;
if (mode != GAMEPORT_MODE_COOKED)
return -1;
if (!a3d->used++)
mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
return 0;
}
/*
* a3d_adc_close() is a callback from the input close routine.
*/
static void a3d_adc_close(struct gameport *gameport)
{
struct a3d *a3d = gameport->driver;
if (!--a3d->used)
del_timer(&a3d->timer);
}
/*
* a3d_open() is a callback from the input open routine.
*/
static int a3d_open(struct input_dev *dev)
{
struct a3d *a3d = dev->private;
if (!a3d->used++)
mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
return 0;
}
/*
* a3d_close() is a callback from the input close routine.
*/
static void a3d_close(struct input_dev *dev)
{
struct a3d *a3d = dev->private;
if (!--a3d->used)
del_timer(&a3d->timer);
}
/*
* a3d_connect() probes for A3D joysticks.
*/
static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev)
{
struct a3d *a3d;
unsigned char data[A3D_MAX_LENGTH];
int i;
if (!(a3d = kmalloc(sizeof(struct a3d), GFP_KERNEL)))
return;
memset(a3d, 0, sizeof(struct a3d));
gameport->private = a3d;
a3d->gameport = gameport;
init_timer(&a3d->timer);
a3d->timer.data = (long) a3d;
a3d->timer.function = a3d_timer;
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
goto fail1;
i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data);
if (!i || a3d_csum(data, i))
goto fail2;
a3d->mode = data[0];
if (!a3d->mode || a3d->mode > 5) {
printk(KERN_WARNING "a3d.c: Unknown A3D device detected "
"(%s, id=%d), contact <vo...@uc...>\n", gameport->phys, a3d->mode);
goto fail2;
}
sprintf(a3d->phys, "%s/input0", gameport->phys);
sprintf(a3d->adcphys, "%s/gameport0", gameport->phys);
if (a3d->mode == A3D_MODE_PXL) {
int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
a3d->length = 33;
a3d->dev.evbit[0] |= BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
a3d->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_RUDDER)
| BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) | BIT(ABS_HAT1X) | BIT(ABS_HAT1Y);
a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE)
| BIT(BTN_SIDE) | BIT(BTN_EXTRA);
a3d->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_PINKIE);
a3d_read(a3d, data);
for (i = 0; i < 4; i++) {
if (i < 2) {
a3d->dev.absmin[axes[i]] = 48;
a3d->dev.absmax[axes[i]] = a3d->dev.abs[axes[i]] * 2 - 48;
a3d->dev.absflat[axes[i]] = 8;
} else {
a3d->dev.absmin[axes[i]] = 2;
a3d->dev.absmax[axes[i]] = 253;
}
a3d->dev.absmin[ABS_HAT0X + i] = -1;
a3d->dev.absmax[ABS_HAT0X + i] = 1;
}
} else {
a3d->length = 29;
a3d->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL);
a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
a3d->adc.driver = a3d;
a3d->adc.open = a3d_adc_open;
a3d->adc.close = a3d_adc_close;
a3d->adc.cooked_read = a3d_adc_cooked_read;
a3d->adc.fuzz = 1;
a3d->adc.name = a3d_names[a3d->mode];
a3d->adc.phys = a3d->adcphys;
a3d->adc.idbus = BUS_GAMEPORT;
a3d->adc.idvendor = GAMEPORT_ID_VENDOR_MADCATZ;
a3d->adc.idproduct = a3d->mode;
a3d->adc.idversion = 0x0100;
a3d_read(a3d, data);
gameport_register_port(&a3d->adc);
printk(KERN_INFO "gameport: %s on %s\n", a3d_names[a3d->mode], gameport->phys);
}
a3d->dev.private = a3d;
a3d->dev.open = a3d_open;
a3d->dev.close = a3d_close;
a3d->dev.name = a3d_names[a3d->mode];
a3d->dev.phys = a3d->phys;
a3d->dev.idbus = BUS_GAMEPORT;
a3d->dev.idvendor = GAMEPORT_ID_VENDOR_MADCATZ;
a3d->dev.idproduct = a3d->mode;
a3d->dev.idversion = 0x0100;
input_register_device(&a3d->dev);
printk(KERN_INFO "input: %s on %s\n", a3d_names[a3d->mode], a3d->phys);
return;
fail2: gameport_close(gameport);
fail1: kfree(a3d);
}
static void a3d_disconnect(struct gameport *gameport)
{
struct a3d *a3d = gameport->private;
input_unregister_device(&a3d->dev);
if (a3d->mode < A3D_MODE_PXL)
gameport_unregister_port(&a3d->adc);
gameport_close(gameport);
kfree(a3d);
}
static struct gameport_dev a3d_dev = {
connect: a3d_connect,
disconnect: a3d_disconnect,
};
int __init a3d_init(void)
{
gameport_register_device(&a3d_dev);
return 0;
}
void __exit a3d_exit(void)
{
gameport_unregister_device(&a3d_dev);
}
module_init(a3d_init);
module_exit(a3d_exit);
|
|
From: James S. <jsi...@us...> - 2002-01-22 19:38:30
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/gameport
In directory usw-pr-cvs1:/tmp/cvs-serv17374
Added Files:
fm801-gp.c
Log Message:
Moving files around.
--- NEW FILE: fm801-gp.c ---
/*
* FM801 gameport driver for Linux
*
* Copyright (c) by Takashi Iwai <ti...@su...>
*
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/gameport.h>
#define PCI_VENDOR_ID_FORTEMEDIA 0x1319
#define PCI_DEVICE_ID_FM801_GP 0x0802
#define HAVE_COOKED
struct fm801_gp {
struct gameport gameport;
struct resource *res_port;
};
#ifdef HAVE_COOKED
static int fm801_gp_cooked_read(struct gameport *gameport, int *axes, int *buttons)
{
unsigned short w;
w = inw(gameport->io + 2);
*buttons = (~w >> 14) & 0x03;
axes[0] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
w = inw(gameport->io + 4);
axes[1] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
w = inw(gameport->io + 6);
*buttons |= ((~w >> 14) & 0x03) << 2;
axes[2] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
w = inw(gameport->io + 8);
axes[3] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
outw(0xff, gameport->io); /* reset */
return 0;
}
#endif
static int fm801_gp_open(struct gameport *gameport, int mode)
{
switch (mode) {
#ifdef HAVE_COOKED
case GAMEPORT_MODE_COOKED:
return 0;
#endif
case GAMEPORT_MODE_RAW:
return 0;
default:
return -1;
}
return 0;
}
static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id)
{
struct fm801_gp *gp;
if (! (gp = kmalloc(sizeof(*gp), GFP_KERNEL))) {
printk("cannot malloc for fm801-gp\n");
return -1;
}
memset(gp, 0, sizeof(*gp));
gp->gameport.open = fm801_gp_open;
#ifdef HAVE_COOKED
gp->gameport.cooked_read = fm801_gp_cooked_read;
#endif
pci_enable_device(pci);
gp->gameport.io = pci_resource_start(pci, 0);
if ((gp->res_port = request_region(gp->gameport.io, 0x10, "FM801 GP")) == NULL) {
printk("unable to grab region 0x%x-0x%x\n", gp->gameport.io, gp->gameport.io + 0x0f);
return -1;
}
pci_set_drvdata(pci, gp);
gameport_register_port(&gp->gameport);
outb(0x60, gp->gameport.io + 0x0d); /* enable joystick 1 and 2 */
printk(KERN_INFO "gameport%d: %s at pci%02x:%02x.%x speed %d kHz\n",
gp->gameport.number, pci->name, pci->bus->number,
PCI_SLOT(pci->devfn), PCI_FUNC(pci->devfn), gp->gameport.speed);
return 0;
}
static void __devexit fm801_gp_remove(struct pci_dev *pci)
{
struct fm801_gp *gp = pci_get_drvdata(pci);
if (gp) {
gameport_unregister_port(&gp->gameport);
release_resource(gp->res_port);
kfree(gp);
}
}
static struct pci_device_id fm801_gp_id_table[] __devinitdata = {
{ PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0 }
};
static struct pci_driver fm801_gp_driver = {
name: "FM801 GP",
id_table: fm801_gp_id_table,
probe: fm801_gp_probe,
remove: fm801_gp_remove,
};
int __init fm801_gp_init(void)
{
return pci_module_init(&fm801_gp_driver);
}
void __exit fm801_gp_exit(void)
{
pci_unregister_driver(&fm801_gp_driver);
}
module_init(fm801_gp_init);
module_exit(fm801_gp_exit);
MODULE_DEVICE_TABLE(pci, fm801_gp_id_table);
MODULE_AUTHOR("Takashi Iwai <ti...@su...>");
MODULE_LICENSE("GPL");
|
|
From: James S. <jsi...@us...> - 2002-01-22 19:38:22
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/gameport In directory usw-pr-cvs1:/tmp/cvs-serv17309 Added Files: cs461x.c Log Message: Moving files around. --- NEW FILE: cs461x.c --- /* The all defines and part of code (such as cs461x_*) are contributed from ALSA 0.5.8 sources. See http://www.alsa-project.org/ for sources Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610 */ #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/pci.h> MODULE_AUTHOR("Victor Krapivin <vi...@be...>"); MODULE_LICENSE("GPL"); /* These options are experimental #define CS461X_FULL_MAP */ #ifndef PCI_VENDOR_ID_CIRRUS #define PCI_VENDOR_ID_CIRRUS 0x1013 #endif #ifndef PCI_DEVICE_ID_CIRRUS_4610 #define PCI_DEVICE_ID_CIRRUS_4610 0x6001 #endif #ifndef PCI_DEVICE_ID_CIRRUS_4612 #define PCI_DEVICE_ID_CIRRUS_4612 0x6003 #endif #ifndef PCI_DEVICE_ID_CIRRUS_4615 #define PCI_DEVICE_ID_CIRRUS_4615 0x6004 #endif /* Registers */ #define BA0_JSPT 0x00000480 #define BA0_JSCTL 0x00000484 #define BA0_JSC1 0x00000488 #define BA0_JSC2 0x0000048C #define BA0_JSIO 0x000004A0 /* Bits for JSPT */ #define JSPT_CAX 0x00000001 #define JSPT_CAY 0x00000002 #define JSPT_CBX 0x00000004 #define JSPT_CBY 0x00000008 #define JSPT_BA1 0x00000010 #define JSPT_BA2 0x00000020 #define JSPT_BB1 0x00000040 #define JSPT_BB2 0x00000080 /* Bits for JSCTL */ #define JSCTL_SP_MASK 0x00000003 #define JSCTL_SP_SLOW 0x00000000 #define JSCTL_SP_MEDIUM_SLOW 0x00000001 #define JSCTL_SP_MEDIUM_FAST 0x00000002 #define JSCTL_SP_FAST 0x00000003 #define JSCTL_ARE 0x00000004 /* Data register pairs masks */ #define JSC1_Y1V_MASK 0x0000FFFF #define JSC1_X1V_MASK 0xFFFF0000 #define JSC1_Y1V_SHIFT 0 #define JSC1_X1V_SHIFT 16 #define JSC2_Y2V_MASK 0x0000FFFF #define JSC2_X2V_MASK 0xFFFF0000 #define JSC2_Y2V_SHIFT 0 #define JSC2_X2V_SHIFT 16 /* JS GPIO */ #define JSIO_DAX 0x00000001 #define JSIO_DAY 0x00000002 #define JSIO_DBX 0x00000004 #define JSIO_DBY 0x00000008 #define JSIO_AXOE 0x00000010 #define JSIO_AYOE 0x00000020 #define JSIO_BXOE 0x00000040 #define JSIO_BYOE 0x00000080 /* The card initialization code is obfuscated; the module cs461x need to be loaded after ALSA modules initialized and something played on the CS 4610 chip (see sources for details of CS4610 initialization code from ALSA) */ /* Card specific definitions */ #define CS461X_BA0_SIZE 0x2000 #define CS461X_BA1_DATA0_SIZE 0x3000 #define CS461X_BA1_DATA1_SIZE 0x3800 #define CS461X_BA1_PRG_SIZE 0x7000 #define CS461X_BA1_REG_SIZE 0x0100 #define BA1_SP_DMEM0 0x00000000 #define BA1_SP_DMEM1 0x00010000 #define BA1_SP_PMEM 0x00020000 #define BA1_SP_REG 0x00030000 #define BA1_DWORD_SIZE (13 * 1024 + 512) #define BA1_MEMORY_COUNT 3 /* Only one CS461x card is still suppoted; the code requires redesign to avoid this limitatuion. */ static unsigned long ba0_addr; static unsigned int *ba0; static char phys[32]; static char name[] = "CS416x Gameport"; #ifdef CS461X_FULL_MAP static unsigned long ba1_addr; static union ba1_t { struct { unsigned int *data0; unsigned int *data1; unsigned int *pmem; unsigned int *reg; } name; unsigned int *idx[4]; } ba1; static void cs461x_poke(unsigned long reg, unsigned int val) { ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff] = val; } static unsigned int cs461x_peek(unsigned long reg) { return ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]; } #endif static void cs461x_pokeBA0(unsigned long reg, unsigned int val) { ba0[reg >> 2] = val; } static unsigned int cs461x_peekBA0(unsigned long reg) { return ba0[reg >> 2]; } static int cs461x_free(struct pci_dev *pdev) { struct gameport *port = (struct gameport *)pdev->driver_data; if(port){ gameport_unregister_port(port); kfree(port); } if (ba0) iounmap(ba0); #ifdef CS461X_FULL_MAP if (ba1.name.data0) iounmap(ba1.name.data0); if (ba1.name.data1) iounmap(ba1.name.data1); if (ba1.name.pmem) iounmap(ba1.name.pmem); if (ba1.name.reg) iounmap(ba1.name.reg); #endif return 0; } static void cs461x_gameport_trigger(struct gameport *gameport) { cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF); } static unsigned char cs461x_gameport_read(struct gameport *gameport) { return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io); } static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons) { unsigned js1, js2, jst; js1 = cs461x_peekBA0(BA0_JSC1); js2 = cs461x_peekBA0(BA0_JSC2); jst = cs461x_peekBA0(BA0_JSPT); *buttons = (~jst >> 4) & 0x0F; axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF; axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF; axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF; axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF; for(jst=0;jst<4;++jst) if(axes[jst]==0xFFFF) axes[jst] = -1; return 0; } static int cs461x_gameport_open(struct gameport *gameport, int mode) { switch (mode) { case GAMEPORT_MODE_COOKED: case GAMEPORT_MODE_RAW: return 0; default: return -1; } return 0; } static struct pci_device_id cs461x_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */ { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */ { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */ { 0, } }; MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl); static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int rc; struct gameport* port; rc = pci_enable_device(pdev); if (rc) { printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n", pdev->bus->number, pdev->devfn, rc); return rc; } ba0_addr = pci_resource_start(pdev, 0); #ifdef CS461X_FULL_MAP ba1_addr = pci_resource_start(pdev, 1); #endif if (ba0_addr == 0 || ba0_addr == ~0 #ifdef CS461X_FULL_MAP || ba1_addr == 0 || ba1_addr == ~0 #endif ) { printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr); #ifdef CS461X_FULL_MAP printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr); #endif cs461x_free(pdev); return -ENOMEM; } ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE); #ifdef CS461X_FULL_MAP ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE); ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE); ba1.name.pmem = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE); ba1.name.reg = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE); if (ba0 == NULL || ba1.name.data0 == NULL || ba1.name.data1 == NULL || ba1.name.pmem == NULL || ba1.name.reg == NULL) { cs461x_free(pdev); return -ENOMEM; } #else if (ba0 == NULL){ cs461x_free(pdev); return -ENOMEM; } #endif if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) { printk(KERN_ERR "Memory allocation failed.\n"); cs461x_free(pdev); return -ENOMEM; } memset(port, 0, sizeof(struct gameport)); pdev->driver_data = port; port->open = cs461x_gameport_open; port->trigger = cs461x_gameport_trigger; port->read = cs461x_gameport_read; port->cooked_read = cs461x_gameport_cooked_read; sprintf(phys, "pci%s/gameport0", pdev->slot_name); port->name = name; port->phys = phys; port->idbus = BUS_PCI; port->idvendor = pdev->vendor; port->idproduct = pdev->device; cs461x_pokeBA0(BA0_JSIO, 0xFF); // ? cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW); gameport_register_port(port); printk(KERN_INFO "gameport: %s on pci%s speed %d kHz\n", name, pdev->slot_name, port->speed); return 0; } static void __devexit cs461x_pci_remove(struct pci_dev *pdev) { cs461x_free(pdev); } static struct pci_driver cs461x_pci_driver = { name: "CS461x Gameport", id_table: cs461x_pci_tbl, probe: cs461x_pci_probe, remove: cs461x_pci_remove, }; int __init cs461x_init(void) { return pci_module_init(&cs461x_pci_driver); } void __exit cs461x_exit(void) { pci_unregister_driver(&cs461x_pci_driver); } module_init(cs461x_init); module_exit(cs461x_exit); |
|
From: James S. <jsi...@us...> - 2002-01-22 19:37:47
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/gameport
In directory usw-pr-cvs1:/tmp/cvs-serv17069
Added Files:
Tag: 1.2
vortex.c
Log Message:
Moving files around.
--- NEW FILE: vortex.c ---
/*
* $Id: vortex.c,v 1.2 2002/01/22 19:37:44 jsimmons Exp $
*
* Copyright (c) 2000-2001 Vojtech Pavlik
*
* Based on the work of:
* Raymond Ingles
*/
/*
* Trident 4DWave and Aureal Vortex gameport 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/gameport.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver");
MODULE_LICENSE("GPL");
#define VORTEX_GCR 0x0c /* Gameport control register */
#define VORTEX_LEG 0x08 /* Legacy port location */
#define VORTEX_AXD 0x10 /* Axes start */
#define VORTEX_DATA_WAIT 20 /* 20 ms */
struct vortex {
struct gameport gameport;
struct pci_dev *dev;
unsigned char *base;
unsigned char *io;
char phys[32];
};
static unsigned char vortex_read(struct gameport *gameport)
{
struct vortex *vortex = gameport->driver;
return readb(vortex->io + VORTEX_LEG);
}
static void vortex_trigger(struct gameport *gameport)
{
struct vortex *vortex = gameport->driver;
writeb(0xff, vortex->io + VORTEX_LEG);
}
static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
{
struct vortex *vortex = gameport->driver;
int i;
*buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
for (i = 0; i < 4; i++) {
axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32));
if (axes[i] == 0x1fff) axes[i] = -1;
}
return 0;
}
static int vortex_open(struct gameport *gameport, int mode)
{
struct vortex *vortex = gameport->driver;
switch (mode) {
case GAMEPORT_MODE_COOKED:
writeb(0x40, vortex->io + VORTEX_GCR);
wait_ms(VORTEX_DATA_WAIT);
return 0;
case GAMEPORT_MODE_RAW:
writeb(0x00, vortex->io + VORTEX_GCR);
return 0;
default:
return -1;
}
return 0;
}
static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
struct vortex *vortex;
int i;
if (!(vortex = kmalloc(sizeof(struct vortex), GFP_KERNEL)))
return -1;
memset(vortex, 0, sizeof(struct vortex));
vortex->dev = dev;
sprintf(vortex->phys, "pci%s/gameport0", dev->slot_name);
dev->driver_data = vortex;
vortex->gameport.driver = vortex;
vortex->gameport.fuzz = 64;
vortex->gameport.read = vortex_read;
vortex->gameport.trigger = vortex_trigger;
vortex->gameport.cooked_read = vortex_cooked_read;
vortex->gameport.open = vortex_open;
vortex->gameport.name = dev->name;
vortex->gameport.phys = vortex->phys;
vortex->gameport.idbus = BUS_PCI;
vortex->gameport.idvendor = dev->vendor;
vortex->gameport.idproduct = dev->device;
for (i = 0; i < 6; i++)
if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
break;
pci_enable_device(dev);
vortex->base = ioremap(pci_resource_start(vortex->dev, i),
pci_resource_len(vortex->dev, i));
vortex->io = vortex->base + id->driver_data;
gameport_register_port(&vortex->gameport);
printk(KERN_INFO "gameport: %s at pci%s speed %d kHz\n",
dev->name, dev->slot_name, vortex->gameport.speed);
return 0;
}
static void __devexit vortex_remove(struct pci_dev *dev)
{
struct vortex *vortex = dev->driver_data;
gameport_unregister_port(&vortex->gameport);
iounmap(vortex->base);
kfree(vortex);
}
static struct pci_device_id vortex_id_table[] __devinitdata =
{{ 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
{ 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
{ 0 }};
static struct pci_driver vortex_driver = {
name: "vortex",
id_table: vortex_id_table,
probe: vortex_probe,
remove: vortex_remove,
};
int __init vortex_init(void)
{
return pci_module_init(&vortex_driver);
}
void __exit vortex_exit(void)
{
pci_unregister_driver(&vortex_driver);
}
module_init(vortex_init);
module_exit(vortex_exit);
|
|
From: James S. <jsi...@us...> - 2002-01-22 19:36:48
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/gameport
In directory usw-pr-cvs1:/tmp/cvs-serv16613
Added Files:
Tag: 1.41
ns558.c
Log Message:
Moving files around.
--- NEW FILE: ns558.c ---
/*
* $Id: ns558.c,v 1.41 2002/01/22 19:36:45 jsimmons 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#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/isapnp.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("Classic gameport (ISA/PnP) driver");
MODULE_LICENSE("GPL");
#define NS558_ISA 1
#define NS558_PNP 2
static int ns558_isa_portlist[] = { 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
struct ns558 {
int type;
int size;
struct pci_dev *dev;
struct ns558 *next;
struct gameport gameport;
char phys[32];
char name[32];
};
static struct ns558 *ns558;
/*
* 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 struct ns558* ns558_isa_probe(int io, struct ns558 *next)
{
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 next;
/*
* 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 next;
}
/*
* 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 next;
}
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 next;
}
/*
* 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 next;
}
memset(port, 0, sizeof(struct ns558));
port->next = next;
port->type = NS558_ISA;
port->size = (1 << i);
port->gameport.io = io & (-1 << i);
port->gameport.phys = port->phys;
port->gameport.name = port->name;
port->gameport.idbus = BUS_ISA;
port->gameport.idvendor = 0x0000;
port->gameport.idproduct = 0x0000;
port->gameport.idversion = 0x0000;
sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i));
sprintf(port->name, "NS558 ISA");
request_region(port->gameport.io, (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);
return port;
}
#ifdef __ISAPNP__
#define NS558_DEVICE(a,b,c,d)\
card_vendor: ISAPNP_ANY_ID, card_device: ISAPNP_ANY_ID,\
vendor: ISAPNP_VENDOR(a,b,c), function: ISAPNP_DEVICE(d)
static struct isapnp_device_id pnp_devids[] = {
{ NS558_DEVICE('@','P','@',0x0001) }, /* ALS 100 */
{ NS558_DEVICE('@','P','@',0x0020) }, /* ALS 200 */
{ NS558_DEVICE('@','P','@',0x1001) }, /* ALS 100+ */
{ NS558_DEVICE('@','P','@',0x2001) }, /* ALS 120 */
{ NS558_DEVICE('A','S','B',0x16fd) }, /* AdLib NSC16 */
{ NS558_DEVICE('A','Z','T',0x3001) }, /* AZT1008 */
{ NS558_DEVICE('C','D','C',0x0001) }, /* Opl3-SAx */
{ NS558_DEVICE('C','S','C',0x0001) }, /* CS4232 */
{ NS558_DEVICE('C','S','C',0x000f) }, /* CS4236 */
{ NS558_DEVICE('C','S','C',0x0101) }, /* CS4327 */
{ NS558_DEVICE('C','T','L',0x7001) }, /* SB16 */
{ NS558_DEVICE('C','T','L',0x7002) }, /* AWE64 */
{ NS558_DEVICE('C','T','L',0x7005) }, /* Vibra16 */
{ NS558_DEVICE('E','N','S',0x2020) }, /* SoundscapeVIVO */
{ NS558_DEVICE('E','S','S',0x0001) }, /* ES1869 */
{ NS558_DEVICE('E','S','S',0x0005) }, /* ES1878 */
{ NS558_DEVICE('E','S','S',0x6880) }, /* ES688 */
{ NS558_DEVICE('I','B','M',0x0012) }, /* CS4232 */
{ NS558_DEVICE('O','P','T',0x0001) }, /* OPTi Audio16 */
{ NS558_DEVICE('Y','M','H',0x0006) }, /* Opl3-SA */
{ NS558_DEVICE('Y','M','H',0x0022) }, /* Opl3-SAx */
{ NS558_DEVICE('P','N','P',0xb02f) }, /* Generic */
{ 0, },
};
MODULE_DEVICE_TABLE(isapnp, pnp_devids);
static struct ns558* ns558_pnp_probe(struct pci_dev *dev, struct ns558 *next)
{
int ioport, iolen;
struct ns558 *port;
if (dev->prepare && dev->prepare(dev) < 0)
return next;
if (!(dev->resource[0].flags & IORESOURCE_IO)) {
printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n");
return next;
}
if (dev->activate && dev->activate(dev) < 0) {
printk(KERN_ERR "ns558: PnP resource allocation failed\n");
return next;
}
ioport = pci_resource_start(dev, 0);
iolen = pci_resource_len(dev, 0);
if (!request_region(ioport, iolen, "ns558-pnp"))
goto deactivate;
if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
printk(KERN_ERR "ns558: Memory allocation failed.\n");
goto deactivate;
}
memset(port, 0, sizeof(struct ns558));
port->next = next;
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.idbus = BUS_ISAPNP;
port->gameport.idvendor = dev->vendor;
port->gameport.idproduct = dev->device;
port->gameport.idversion = 0x100;
sprintf(port->phys, "isapnp%d.%d/gameport0", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
sprintf(port->name, "%s", dev->name[0] ? dev->name : "NS558 PnP Gameport");
gameport_register_port(&port->gameport);
printk(KERN_INFO "gameport: NS558 PnP at isapnp%d.%d io %#x",
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), port->gameport.io);
if (iolen > 1) printk(" size %d", iolen);
printk(" speed %d kHz\n", port->gameport.speed);
return port;
deactivate:
if (dev->deactivate)
dev->deactivate(dev);
return next;
}
#endif
int __init ns558_init(void)
{
int i = 0;
#ifdef __ISAPNP__
struct isapnp_device_id *devid;
struct pci_dev *dev = NULL;
#endif
/*
* Probe for ISA ports.
*/
while (ns558_isa_portlist[i])
ns558 = ns558_isa_probe(ns558_isa_portlist[i++], ns558);
/*
* Probe for PnP ports.
*/
#ifdef __ISAPNP__
for (devid = pnp_devids; devid->vendor; devid++) {
while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, dev))) {
ns558 = ns558_pnp_probe(dev, ns558);
}
}
#endif
return ns558 ? 0 : -ENODEV;
}
void __exit ns558_exit(void)
{
struct ns558 *next, *port = ns558;
while (port) {
gameport_unregister_port(&port->gameport);
switch (port->type) {
#ifdef __ISAPNP__
case NS558_PNP:
if (port->dev->deactivate)
port->dev->deactivate(port->dev);
/* fall through */
#endif
case NS558_ISA:
release_region(port->gameport.io, port->size);
break;
default:
break;
}
next = port->next;
kfree(port);
port = next;
}
}
module_init(ns558_init);
module_exit(ns558_exit);
|
|
From: James S. <jsi...@us...> - 2002-01-22 19:36:22
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/gameport
In directory usw-pr-cvs1:/tmp/cvs-serv16413
Added Files:
Tag: 1.19
lightning.c
Log Message:
Moving files around.
--- NEW FILE: lightning.c ---
/*
* $Id: lightning.c,v 1.19 2002/01/22 19:36:19 jsimmons Exp $
*
* Copyright (c) 1998-2001 Vojtech Pavlik
*/
/*
* PDPI Lightning 4 gamecard 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/slab.h>
#define L4_PORT 0x201
#define L4_SELECT_ANALOG 0xa4
#define L4_SELECT_DIGITAL 0xa5
#define L4_SELECT_SECONDARY 0xa6
#define L4_CMD_ID 0x80
#define L4_CMD_GETCAL 0x92
#define L4_CMD_SETCAL 0x93
#define L4_ID 0x04
#define L4_BUSY 0x01
#define L4_TIMEOUT 80 /* 80 us */
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("PDPI Lightning 4 gamecard driver");
MODULE_LICENSE("GPL");
struct l4 {
struct gameport gameport;
unsigned char port;
char phys[32];
} *l4_port[8];
char l4_name[] = "PDPI Lightning 4";
/*
* l4_wait_ready() waits for the L4 to become ready.
*/
static int l4_wait_ready(void)
{
unsigned int t;
t = L4_TIMEOUT;
while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--;
return -(t<=0);
}
/*
* l4_cooked_read() reads data from the Lightning 4.
*/
static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
{
struct l4 *l4 = gameport->driver;
unsigned char status;
int i, result = -1;
outb(L4_SELECT_ANALOG, L4_PORT);
outb(L4_SELECT_DIGITAL + (l4->port >> 2), L4_PORT);
if (inb(L4_PORT) & L4_BUSY) goto fail;
outb(l4->port & 3, L4_PORT);
if (l4_wait_ready()) goto fail;
status = inb(L4_PORT);
for (i = 0; i < 4; i++)
if (status & (1 << i)) {
if (l4_wait_ready()) goto fail;
axes[i] = inb(L4_PORT);
if (axes[i] > 252) axes[i] = -1;
}
if (status & 0x10) {
if (l4_wait_ready()) goto fail;
*buttons = inb(L4_PORT) & 0x0f;
}
result = 0;
fail: outb(L4_SELECT_ANALOG, L4_PORT);
return result;
}
static int l4_open(struct gameport *gameport, int mode)
{
struct l4 *l4 = gameport->driver;
if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
return -1;
outb(L4_SELECT_ANALOG, L4_PORT);
return 0;
}
/*
* l4_getcal() reads the L4 with calibration values.
*/
static int l4_getcal(int port, int *cal)
{
int i, result = -1;
outb(L4_SELECT_ANALOG, L4_PORT);
outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
if (inb(L4_PORT) & L4_BUSY) goto fail;
outb(L4_CMD_GETCAL, L4_PORT);
if (l4_wait_ready()) goto fail;
if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
if (l4_wait_ready()) goto fail;
outb(port & 3, L4_PORT);
for (i = 0; i < 4; i++) {
if (l4_wait_ready()) goto fail;
cal[i] = inb(L4_PORT);
}
result = 0;
fail: outb(L4_SELECT_ANALOG, L4_PORT);
return result;
}
/*
* l4_setcal() programs the L4 with calibration values.
*/
static int l4_setcal(int port, int *cal)
{
int i, result = -1;
outb(L4_SELECT_ANALOG, L4_PORT);
outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
if (inb(L4_PORT) & L4_BUSY) goto fail;
outb(L4_CMD_SETCAL, L4_PORT);
if (l4_wait_ready()) goto fail;
if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
if (l4_wait_ready()) goto fail;
outb(port & 3, L4_PORT);
for (i = 0; i < 4; i++) {
if (l4_wait_ready()) goto fail;
outb(cal[i], L4_PORT);
}
result = 0;
fail: outb(L4_SELECT_ANALOG, L4_PORT);
return result;
}
/*
* l4_calibrate() calibrates the L4 for the attached device, so
* that the device's resistance fits into the L4's 8-bit range.
*/
static int l4_calibrate(struct gameport *gameport, int *axes, int *max)
{
int i, t;
int cal[4];
struct l4 *l4 = gameport->driver;
if (l4_getcal(l4->port, cal))
return -1;
for (i = 0; i < 4; i++) {
t = (max[i] * cal[i]) / 200;
t = (t < 1) ? 1 : ((t > 255) ? 255 : t);
axes[i] = (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t;
axes[i] = (axes[i] > 252) ? 252 : axes[i];
cal[i] = t;
}
if (l4_setcal(l4->port, cal))
return -1;
return 0;
}
int __init l4_init(void)
{
int cal[4] = {255,255,255,255};
int i, j, rev, cards = 0;
struct gameport *gameport;
struct l4 *l4;
if (!request_region(L4_PORT, 1, "lightning"))
return -1;
for (i = 0; i < 2; i++) {
outb(L4_SELECT_ANALOG, L4_PORT);
outb(L4_SELECT_DIGITAL + i, L4_PORT);
if (inb(L4_PORT) & L4_BUSY) continue;
outb(L4_CMD_ID, L4_PORT);
if (l4_wait_ready()) continue;
if (inb(L4_PORT) != L4_SELECT_DIGITAL + i) continue;
if (l4_wait_ready()) continue;
if (inb(L4_PORT) != L4_ID) continue;
if (l4_wait_ready()) continue;
rev = inb(L4_PORT);
if (!rev) continue;
if (!(l4_port[i * 4] = kmalloc(sizeof(struct l4) * 4, GFP_KERNEL))) {
printk(KERN_ERR "lightning: Out of memory allocating ports.\n");
continue;
}
memset(l4_port[i * 4], 0, sizeof(struct l4) * 4);
for (j = 0; j < 4; j++) {
l4 = l4_port[i * 4 + j] = l4_port[i * 4] + j;
l4->port = i * 4 + j;
sprintf(l4->phys, "isa%04x/gameport%d", L4_PORT, 4 * i + j);
gameport = &l4->gameport;
gameport->driver = l4;
gameport->open = l4_open;
gameport->cooked_read = l4_cooked_read;
gameport->calibrate = l4_calibrate;
gameport->name = l4_name;
gameport->phys = l4->phys;
gameport->idbus = BUS_ISA;
if (!i && !j)
gameport->io = L4_PORT;
if (rev > 0x28) /* on 2.9+ the setcal command works correctly */
l4_setcal(l4->port, cal);
gameport_register_port(gameport);
}
printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n",
i ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
cards++;
}
outb(L4_SELECT_ANALOG, L4_PORT);
if (!cards) {
release_region(L4_PORT, 1);
return -1;
}
return 0;
}
void __init l4_exit(void)
{
int i;
int cal[4] = {59, 59, 59, 59};
for (i = 0; i < 8; i++)
if (l4_port[i]) {
l4_setcal(l4_port[i]->port, cal);
gameport_unregister_port(&l4_port[i]->gameport);
}
outb(L4_SELECT_ANALOG, L4_PORT);
release_region(L4_PORT, 1);
}
module_init(l4_init);
module_exit(l4_exit);
|
|
From: James S. <jsi...@us...> - 2002-01-22 19:36:05
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/gameport
In directory usw-pr-cvs1:/tmp/cvs-serv16246
Added Files:
Tag: 1.17
gameport.c
Log Message:
Moving files around.
--- NEW FILE: gameport.c ---
/*
* $Id: gameport.c,v 1.17 2002/01/22 19:36:01 jsimmons Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
/*
* Generic gameport layer
*/
/*
* 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#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/isapnp.h>
#include <linux/stddef.h>
#include <linux/delay.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
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 struct gameport *gameport_list;
static struct gameport_dev *gameport_dev;
/*
* gameport_measure_speed() measures the gameport i/o speed.
*/
static int gameport_measure_speed(struct gameport *gameport)
{
#if defined(__i386__) || defined(__x86_64__)
#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0))
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++) {
save_flags(flags); /* Yes, all CPUs */
cli();
GET_TIME(t1);
for(t = 0; t < 50; t++) gameport_read(gameport);
GET_TIME(t2);
GET_TIME(t3);
restore_flags(flags);
udelay(i * 10);
if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
}
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); }
return t * HZ / 1000;
#endif
gameport_close(gameport);
}
static void gameport_find_dev(struct gameport *gameport)
{
struct gameport_dev *dev = gameport_dev;
while (dev && !gameport->dev) {
if (dev->connect)
dev->connect(gameport, dev);
dev = dev->next;
}
}
void gameport_rescan(struct gameport *gameport)
{
gameport_close(gameport);
gameport_find_dev(gameport);
}
void gameport_register_port(struct gameport *gameport)
{
gameport->next = gameport_list;
gameport_list = gameport;
gameport->speed = gameport_measure_speed(gameport);
gameport_find_dev(gameport);
}
void gameport_unregister_port(struct gameport *gameport)
{
struct gameport **gameportptr = &gameport_list;
while (*gameportptr && (*gameportptr != gameport)) gameportptr = &((*gameportptr)->next);
*gameportptr = (*gameportptr)->next;
if (gameport->dev && gameport->dev->disconnect)
gameport->dev->disconnect(gameport);
}
void gameport_register_device(struct gameport_dev *dev)
{
struct gameport *gameport = gameport_list;
dev->next = gameport_dev;
gameport_dev = dev;
while (gameport) {
if (!gameport->dev && dev->connect)
dev->connect(gameport, dev);
gameport = gameport->next;
}
}
void gameport_unregister_device(struct gameport_dev *dev)
{
struct gameport_dev **devptr = &gameport_dev;
struct gameport *gameport = gameport_list;
while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
*devptr = (*devptr)->next;
while (gameport) {
if (gameport->dev == dev && dev->disconnect)
dev->disconnect(gameport);
gameport_find_dev(gameport);
gameport = gameport->next;
}
}
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);
}
|
|
From: James S. <jsi...@us...> - 2002-01-22 19:35:37
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/gameport
In directory usw-pr-cvs1:/tmp/cvs-serv16081
Added Files:
Tag: 1.7
emu10k1-gp.c
Log Message:
Moving files around.
--- NEW FILE: emu10k1-gp.c ---
/*
* $Id: emu10k1-gp.c,v 1.7 2002/01/22 19:35:32 jsimmons Exp $
*
* Copyright (c) 2001 Vojtech Pavlik
*/
/*
* EMU10k1 - SB Live / Audigy - gameport 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#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/pci.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("EMU10k1 gameport driver");
MODULE_LICENSE("GPL");
struct emu {
struct pci_dev *dev;
struct emu *next;
struct gameport gameport;
int size;
char phys[32];
};
static struct pci_device_id emu_tbl[] __devinitdata = {
{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
{ 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, emu_tbl);
static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int ioemu, iolen;
struct emu *emu;
if (pci_enable_device(pdev))
return -EBUSY;
ioemu = pci_resource_start(pdev, 0);
iolen = pci_resource_len(pdev, 0);
if (!request_region(ioemu, iolen, "emu10k1-gp"))
return -EBUSY;
if (!(emu = kmalloc(sizeof(struct emu), GFP_KERNEL))) {
printk(KERN_ERR "emu10k1-gp: Memory allocation failed.\n");
release_region(ioemu, iolen);
return -ENOMEM;
}
memset(emu, 0, sizeof(struct emu));
sprintf(emu->phys, "pci%s/gameport0", pdev->slot_name);
emu->size = iolen;
emu->dev = pdev;
emu->gameport.io = ioemu;
emu->gameport.name = pdev->name;
emu->gameport.phys = emu->phys;
emu->gameport.idbus = BUS_PCI;
emu->gameport.idvendor = pdev->vendor;
emu->gameport.idproduct = pdev->device;
pdev->driver_data = emu;
gameport_register_port(&emu->gameport);
printk(KERN_INFO "gameport: %s at pci%s speed %d kHz\n",
pdev->name, pdev->slot_name, emu->gameport.speed);
return 0;
}
static void __devexit emu_remove(struct pci_dev *pdev)
{
struct emu *emu = (void *)pdev->driver_data;
gameport_unregister_port(&emu->gameport);
release_region(emu->gameport.io, emu->size);
kfree(emu);
}
static struct pci_driver emu_driver = {
name: "Emu10k1 Gameport",
id_table: emu_tbl,
probe: emu_probe,
remove: emu_remove,
};
int __init emu_init(void)
{
return pci_module_init(&emu_driver);
}
void __exit emu_exit(void)
{
pci_unregister_driver(&emu_driver);
}
module_init(emu_init);
module_exit(emu_exit);
|
|
From: James S. <jsi...@us...> - 2002-01-22 19:19:57
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/serio
In directory usw-pr-cvs1:/tmp/cvs-serv11208
Added Files:
Tag: 1.8
serport_old.c
Log Message:
moving stuff around.
--- NEW FILE: serport_old.c ---
/*
* $Id: serport_old.c,v 1.8 2002/01/22 19:19:55 jsimmons Exp $
*
* Copyright (c) 1999-2001 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 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#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 <vo...@uc...>");
MODULE_DESCRIPTION("Input device TTY line discipline");
MODULE_LICENSE("GPL");
struct serport {
struct tty_struct *tty;
wait_queue_head_t wait;
struct serio serio;
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;
wake_up_interruptible(&serport->wait);
}
/*
* serport_ldisc_open() is the routine that is called upon setting our line
* discipline on a tty. It looks for the Mag, and if found, registers
* it as a joystick device.
*/
static int serport_ldisc_open(struct tty_struct *tty)
{
struct serport *serport;
char ttyname[64];
int i;
MOD_INC_USE_COUNT;
if (!(serport = kmalloc(sizeof(struct serport), GFP_KERNEL))) {
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(serport, 0, sizeof(struct serport));
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
serport->tty = tty;
tty->disc_data = serport;
strcpy(ttyname, tty->driver.name);
for (i = 0; ttyname[i] != 0 && ttyname[i] != '/'; i++);
ttyname[i] = 0;
sprintf(serport->phys, "%s%d/serio0", ttyname, MINOR(tty->device) - tty->driver.minor_start);
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);
MOD_DEC_USE_COUNT;
}
/*
* 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.
*/
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++)
if (serport->serio.dev)
serport->serio.dev->interrupt(&serport->serio, cp[i], 0);
}
/*
* 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;
DECLARE_WAITQUEUE(wait, current);
char name[32];
#ifdef CONFIG_DEVFS_FS
sprintf(name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
#else
sprintf(name, "%s%d", tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
#endif
serio_register_port(&serport->serio);
printk(KERN_INFO "serio: Serial port %s\n", name);
add_wait_queue(&serport->wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
while(serport->serio.type && !signal_pending(current)) schedule();
set_current_state(TASK_RUNNING);
remove_wait_queue(&serport->wait, &wait);
serio_unregister_port(&serport->serio);
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;
switch (cmd) {
case 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 = {
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.
*/
int __init serport_init(void)
{
if (tty_register_ldisc(N_MOUSE, &serport_ldisc)) {
printk(KERN_ERR "serport.c: Error registering line discipline.\n");
return -ENODEV;
}
return 0;
}
void __exit serport_exit(void)
{
tty_register_ldisc(N_MOUSE, NULL);
}
module_init(serport_init);
module_exit(serport_exit);
|
|
From: James S. <jsi...@us...> - 2002-01-22 19:18:30
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/serio
In directory usw-pr-cvs1:/tmp/cvs-serv10728
Added Files:
Tag: 1.13
serport.c
Log Message:
moving stuff around.
--- NEW FILE: serport.c ---
/*
* $Id: serport.c,v 1.13 2002/01/22 19:18:27 jsimmons Exp $
*/
/*
* 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 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
*/
#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>
#include <linux/circ_buf.h>
static DECLARE_MUTEX(port_sem);
/*
* Callback functions from the serio code.
*/
static int serport_serio_write(struct serio *serio, unsigned char data)
{
struct uart_info *info = serio->driver;
unsigned long flags;
int retval = -1;
if (!info->xmit.buf)
return retval;
save_flags(flags); cli();
if (CIRC_SPACE(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE) != 0) { info->xmit.buf[info->xmit.head] = ch;
info->xmit.head = (info->xmit.head + 1) & (UART_XMIT_SIZE - 1);
retval = 0;
}
restore_flags(flags);
return retval;
}
static int serport_serio_open(struct serio *serio)
{
struct uart_info *info = serio->driver;
int retval = -ENODEV;
/*
if (!try_inc_mod_count(drv->owner))
goto fail;
*/
if (!info)
goto out;
/*
* If the port is in the middle of closing, bail out now.
*/
if (info->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&info->close_wait);
retval = (info->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS;
goto out;
}
/*
* Make sure the device is in D0 state.
*/
if (info->state->count == 1)
#ifdef CONFIG_PM
pm_send(info->state->pm, PM_RESUME, (void *)0);
#else
if (info->ops->pm)
info->ops->pm(info->port, 0, 3);
#endif
/*
* Start up the serial port
*/
retval = uart_startup(info);
if (retval)
goto out;
uart_change_speed(info, NULL);
out:
if (drv->owner)
__MOD_DEC_USE_COUNT(drv->owner);
fail:
return retval;
}
static void serport_serio_close(struct serio *serio)
{
struct uart_info *info = serio->private;
struct uart_state *state = info->state;
down(&state->count_sem);
save_flags(flags); cli();
if (state->count) {
restore_flags(flags);
up(&state->count_sem);
goto done;
}
info->flags |= ASYNC_CLOSING;
restore_flags(flags);
up(&state->count_sem);
/*
* At this point, we stop accepting input. To do this, we
* disable the receive line status interrupts.
*/
if (info->flags & ASYNC_INITIALIZED) {
info->ops->stop_rx(info->port);
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
* important if there is a transmit FIFO!
*/
uart_wait_until_sent(tty, info->timeout);
}
uart_shutdown(info);
info->event = 0;
if (info->blocked_open) {
if (info->state->close_delay) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(info->state->close_delay);
set_current_state(TASK_RUNNING);
}
wake_up_interruptible(&info->open_wait);
} else {
#ifdef CONFIG_PM
/*
* Put device into D3 state.
*/
pm_send(info->state->pm, PM_SUSPEND, (void *)3);
#else
if (info->ops->pm)
info->ops->pm(info->port, 3, 0);
#endif
}
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
ASYNC_CLOSING);
wake_up_interruptible(&info->close_wait);
done:
if (drv->owner)
__MOD_DEC_USE_COUNT(drv->owner);
}
/*
* The functions for insering/removing us as a module.
*/
int __init serport_init(void)
{
struct uart_driver *input;
uart_register_driver(&input)
return 0;
}
void __exit serport_exit(void)
{
uart_unregister_driver(&input);
}
module_init(serport_init);
module_exit(serport_exit);
|
|
From: James S. <jsi...@us...> - 2002-01-22 19:17:58
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/serio
In directory usw-pr-cvs1:/tmp/cvs-serv10563
Added Files:
Tag: 1.14
serio.c
Log Message:
moving stuff around.
--- NEW FILE: serio.c ---
/*
* $Id: serio.c,v 1.14 2002/01/22 19:17:56 jsimmons 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/serio.h>
#include <linux/errno.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("Serio abstraction core");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(serio_register_port);
EXPORT_SYMBOL(serio_unregister_port);
EXPORT_SYMBOL(serio_register_device);
EXPORT_SYMBOL(serio_unregister_device);
EXPORT_SYMBOL(serio_open);
EXPORT_SYMBOL(serio_close);
EXPORT_SYMBOL(serio_rescan);
static struct serio *serio_list;
static struct serio_dev *serio_dev;
static void serio_find_dev(struct serio *serio)
{
struct serio_dev *dev = serio_dev;
while (dev && !serio->dev) {
if (dev->connect)
dev->connect(serio, dev);
dev = dev->next;
}
}
void serio_rescan(struct serio *serio)
{
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
serio_find_dev(serio);
}
void serio_register_port(struct serio *serio)
{
serio->next = serio_list;
serio_list = serio;
serio_find_dev(serio);
}
void serio_unregister_port(struct serio *serio)
{
struct serio **serioptr = &serio_list;
while (*serioptr && (*serioptr != serio)) serioptr = &((*serioptr)->next);
*serioptr = (*serioptr)->next;
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
}
void serio_register_device(struct serio_dev *dev)
{
struct serio *serio = serio_list;
dev->next = serio_dev;
serio_dev = dev;
while (serio) {
if (!serio->dev && dev->connect)
dev->connect(serio, dev);
serio = serio->next;
}
}
void serio_unregister_device(struct serio_dev *dev)
{
struct serio_dev **devptr = &serio_dev;
struct serio *serio = serio_list;
while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
*devptr = (*devptr)->next;
while (serio) {
if (serio->dev == dev && dev->disconnect)
dev->disconnect(serio);
serio_find_dev(serio);
serio = serio->next;
}
}
int serio_open(struct serio *serio, struct serio_dev *dev)
{
if (serio->open(serio))
return -1;
serio->dev = dev;
return 0;
}
void serio_close(struct serio *serio)
{
serio->close(serio);
serio->dev = NULL;
}
|
|
From: James S. <jsi...@us...> - 2002-01-22 19:17:18
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/serio
In directory usw-pr-cvs1:/tmp/cvs-serv10297
Added Files:
Tag: 1.7
rpckbd.c
Log Message:
moving stuff around.
--- NEW FILE: rpckbd.c ---
/*
* $Id: rpckbd.c,v 1.7 2002/01/22 19:17:15 jsimmons Exp $
*
* Copyright (c) 2000-2001 Vojtech Pavlik
*
* Based on the work of:
* unknown author
*/
/*
* Acorn RiscPC PS/2 keyboard controller driver for Linux/ARM
*/
/*
* 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 <vo...@uc...>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/iomd.h>
#include <asm/system.h>
MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>");
MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
MODULE_LICENSE("GPL");
static inline void rpckbd_write(unsigned char val)
{
while(!(inb(IOMD_KCTRL) & (1 << 7)));
outb(val, IOMD_KARTTX);
}
static struct serio rpckbd_port =
{
type: SERIO_8042,
write: rpckbd_write,
name: "RiscPC PS/2 kbd port",
phys: "rpckbd/serio0",
};
static void rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs)
{
kbd_pt_regs = regs;
while (inb(IOMD_KCTRL) & (1 << 5))
if (rpckbd_port.dev)
rpckbd_port.dev->interrupt(&rpckbd_port, inb(IOMD_KARTRX), 0);
}
static void rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs)
{
}
static int __init rpckbd_init(void)
{
unsigned long flags;
/* Reset the keyboard state machine. */
outb(0, IOMD_KCTRL);
outb(8, IOMD_KCTRL);
save_flags_cli(flags);
if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", NULL) != 0) {
printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ!\n")
return -EBUSY;
}
if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", NULL) != 0) {
printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ!\n")
free_irq(IRQ_KEYBOARDRX, NULL);
return -EBUSY;
}
disable_irq(IRQ_KEYBOARDTX);
(void)IOMD_KARTRX;
restore_flags(flags);
register_serio_port(&rpckbd_port);
printk(KERN_INFO "serio: RiscPC PS/2 kbd port irq %d %d\n", IRQ_KEYBOARDRX, IRQ_KEYBOARDTX);
return 0;
}
static void __exit rpckbd_exit(void)
{
free_irq(IRQ_KEYBOARDRX, NULL);
free_irq(IRQ_KEYBOARDTX, NULL);
unregister_serio_port(&rpckbd_port);
}
module_init(rpckbd_init);
module_exit(rpckbd_exit);
|