/* * These are really magic values. Changing them can make a problem go away, * as well as break everything.
*/
#undef SW_DEBUG #undef SW_DEBUG_DATA
#define SW_START 600 /* The time we wait for the first bit [600 us] */ #define SW_STROBE 60 /* Max time per bit [60 us] */ #define SW_TIMEOUT 6 /* Wait for everything to settle [6 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 */
#ifdef SW_DEBUG #define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg) #else #define dbg(format, arg...) do {} while (0) #endif
struct sw { struct gameport *gameport; 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;
};
/* * 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.
*/
staticint sw_read_packet(struct gameport *gameport, unsignedchar *buf, int length, int id)
{ unsignedlong flags; int timeout, bitout, sched, i, kick, start, strobe; unsignedchar pending, u, v;
i = -id; /* Don't care about data, only want ID */
timeout = id ? gameport_time(gameport, SW_TIMEOUT * 1000) : 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;
local_irq_save(flags); /* Quiet, please */
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)) {
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 */
}
}
/* * 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.
*/
static __u64 sw_get_bits(unsignedchar *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.
*/
staticvoid sw_init_digital(struct gameport *gameport)
{ staticconstint seq[] = { 140, 140+725, 140+300, 0 }; unsignedlong flags; int i, t;
local_irq_save(flags);
i = 0; do {
gameport_trigger(gameport); /* Trigger */
t = gameport_time(gameport, SW_TIMEOUT * 1000); 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 */
local_irq_restore(flags);
}
/* * sw_parity() computes parity of __u64
*/
staticint 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.
*/
staticint sw_check(__u64 t)
{ unsignedchar sum = 0;
/* * 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.
*/
staticint sw_read(struct sw *sw)
{ unsignedchar 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 */
mdelay(3 * SW_TIMEOUT);
sw_init_digital(sw->gameport);
}
mdelay(SW_TIMEOUT);
i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0); /* Read normal data packet */
mdelay(SW_TIMEOUT);
sw_read_packet(sw->gameport, buf, SW_LENGTH, i); /* Read ID packet, this initializes the stick */
/* * 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 ...
*/
staticint sw_guess_mode(unsignedchar *buf, int len)
{ int i; unsignedcharxor = 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.
*/
i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read normal packet */
msleep(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 */
msleep(SW_TIMEOUT);
i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */
msleep(SW_TIMEOUT);
dbg("Init 1b: Length %d.", i); if (!i) { /* No data -> FAIL */
err = -ENODEV; goto fail2;
}
}
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 <= 0) { /* Read ID failed. Happens in 1-bit mode on PP */
msleep(SW_TIMEOUT);
i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */
m |= sw_guess_mode(buf, i);
dbg("Init 2b: Mode %d. Length %d.", m, i); if (!i) {
err = -ENODEV; goto fail2;
}
msleep(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--;
msleep(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 */
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.