/* * joy-intv2pc.c Version 1.0 * * Copyright (c) 1999, Joseph Zbiciak. * Based on "joy-turbografx.c", which is Copyright (c) 1998, Vojtech Pavlik */ /* * This module supports the INTV2PC parallel port interface provided * by Division Software, http://www3.sympatico.ca/division.software/ * * INTV2PC decoding routines by Joseph Zbiciak * "The Rest" by Vojtech Pavlik * * Usage: js_intv2pc=port,[sticks,[udelay,[raw]]] * * 'port' port number (either parportX if 2.2, or I/O port if 2.0) * * 'sticks' 2-bit bitfield saying which controllers to read (l or r) * default == 3 (both controllers attached). * * 'udelay' delay in usec between port write and read (dfl == 10) * * 'raw' raw = 0: Provide normal joystick output, buttons 0..14 * raw = 1: Provide additional "exact", "inval" bits, 15..16 * raw = 2: Provide joystick-switch information, 17..25 * raw = 3: Provide the pre-decode joystick data 17..25 * Default is raw == 0. */ /* * 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 by * e-mail - mail your message to . */ #include #include #include #include #include #include #include #include #include MODULE_AUTHOR("Joseph Zbiciak "); MODULE_PARM(js_intv, "1-4i"); MODULE_PARM(js_intv_2, "1-4i"); MODULE_PARM(js_intv_3, "1-4i"); /* * Note: Most of the following #defines are here for documentation purposes * only. They describe the assignment of bits in the lookup table. */ /* * The Intellivision hand-controller has 8 different position switches, * so it can return 16 unique directions. This joystick driver does not * actually return the individual position switch information, but rather * relies on the "disc direction" value for calculating X/Y axis * positioning. */ #define JS_INTV_DISC_R (0x01000000) /* Disc "right" */ #define JS_INTV_DISC_UR (0x02000000) /* Disc "up-right" */ #define JS_INTV_DISC_U (0x04000000) /* Disc "up" */ #define JS_INTV_DISC_UL (0x08000000) /* Disc "up-left" */ #define JS_INTV_DISC_L (0x10000000) /* Disc "left" */ #define JS_INTV_DISC_DL (0x20000000) /* Disc "down-left" */ #define JS_INTV_DISC_D (0x40000000) /* Disc "down" */ #define JS_INTV_DISC_DR (0x80000000) /* Disc "down-right" */ #define JS_INTV_DISC_MASK (0x00F00000) /* Disc direction (0 - 15) */ #define JS_INTV_IS_DISC (0xFF000000) /* MASK: Decoded value has disc */ #define JS_INTV_DISC_DIR(x) (((x) & JS_INTV_DISC_MASK) >> 20) /* * The Intellivision hand-controller has 12 different keypad buttons and * 3 different action buttons. */ #define JS_INTV_KEY_1 (0x00000001) /* Keypad key 1 */ #define JS_INTV_KEY_2 (0x00000002) /* Keypad key 2 */ #define JS_INTV_KEY_3 (0x00000004) /* Keypad key 3 */ #define JS_INTV_KEY_4 (0x00000008) /* Keypad key 4 */ #define JS_INTV_KEY_5 (0x00000010) /* Keypad key 5 */ #define JS_INTV_KEY_6 (0x00000020) /* Keypad key 6 */ #define JS_INTV_KEY_7 (0x00000040) /* Keypad key 7 */ #define JS_INTV_KEY_8 (0x00000080) /* Keypad key 8 */ #define JS_INTV_KEY_9 (0x00000100) /* Keypad key 9 */ #define JS_INTV_KEY_C (0x00000200) /* Keypad key Clear */ #define JS_INTV_KEY_0 (0x00000400) /* Keypad key 0 */ #define JS_INTV_KEY_E (0x00000800) /* Keypad key Enter */ #define JS_INTV_ACT_0 (0x00001000) /* Upper action button */ #define JS_INTV_ACT_1 (0x00002000) /* Left lower action button */ #define JS_INTV_ACT_2 (0x00004000) /* Right lower action button */ /* * The following pseudo-buttons report the state of the decode: * * -- Exact: Decoding is exact, since the particular joystick encoding * maps to exactly one decoding. * * -- Invalid: Decoding is invalid, since the particular joystic encoding * maps to a (theoretically impossible) joystick position. * * These two states are linearly independent of each other, since an * encoding may be both Exact and Invalid simultaneously, or Ambiguous * (opposite of Exact) and Valid. Therefore, two separate "buttons" * are allocated. */ #define JS_INTV_INVAL (0x00008000) /* Decoding is not 100% valid */ #define JS_INTV_EXACT (0x00010000) /* Decoding is exact. */ /* * The following mask teases out the actual button information from * the table. Changing this mask would allow returning position-switch * information as button presses also. */ #define JS_INTV_BUTTON (0x00007FFF) /* Mask for button-press flags */ #define JS_INTV_BUTTON_R (0x0001FFFF) /* Mask for button-press flags */ /* * The following table contains all of the decode information for each * of the possible Intellivision Hand-Controller return values. * * The Intellivision hand-controllers are interesting beasts. Each * controller has 15 different buttons and a 16-direction "disc". All of * this is connected to an 8-bit port. * * Individual button presses throw groups of switches, so that all 31 * different inputs can be resolved independently. Things get interesting, * though, when multiple inputs are provided simultaneously: Aliasing * between inputs occurs. * * The table contains four possible decodes for each 8-bit input. The * right-most entry in each row is the "most preferred decoding", and the * left-most is the "least preferred". In the absence of other inputs, * the decoder routine will always pick the decoding from the rightmost * column. If "previous input" information is around for a controller, * this is used to pick one of the other colums. * * Some of the decodings in the table are marked "Invalid". These * represent joystick encodings that are technically "impossible" to reach * with the Intellivision joystick, but which occur anyway when _real_ * controllers (complete with dirty contacts, etc) are used. * * Some entries are marked "Exact", meaning there is exactly one valid * decoding for a particular encoding. These entries are precious few. * The remaining entries are ambiguous to some extent. * * Disambiguation is performed by finding the decoding which represents * the fewest bit-changes from the current decoding. The idea is that * an ambiguous state is usually reached from a non-ambiguous state that * is similar to it, so we'll try to narrow down the possibilities by * remembering how we got to where we're at. */ static unsigned js_intv_tbl[1024] = { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x40C10000, 0x40C10000, 0x40C10000, 0x40C10000, 0x01010000, 0x01010000, 0x01010000, 0x01010000, 0xC0D10000, 0xC0D10000, 0xC0D10000, 0xC0D10000, 0x04410000, 0x04410000, 0x04410000, 0x04410000, 0x44C18000, 0x44C18000, 0x44C18000, 0x44C18000, 0x03110000, 0x03110000, 0x03110000, 0x03110000, 0x47D08000, 0xC4D08000, 0xC3D08000, 0xC3D08000, 0x10810000, 0x10810000, 0x10810000, 0x10810000, 0x30910000, 0x30910000, 0x30910000, 0x30910000, 0x11818000, 0x11818000, 0x11818000, 0x11818000, 0xD1D08000, 0x31908000, 0xF0D08000, 0xF0D08000, 0x0C510000, 0x0C510000, 0x0C510000, 0x0C510000, 0x74D08000, 0x4CD08000, 0x3CD08000, 0x3CD08000, 0x1DD08000, 0x13908000, 0x0F508000, 0x0F508000, 0x4FD08000, 0x3DD08000, 0x33908000, 0xCCD08000, 0x18708000, 0x60B08000, 0x06308000, 0x60B08000, 0x60B10000, 0x60B10000, 0x60B10000, 0x60B10000, 0x81F10000, 0x81F10000, 0x81F10000, 0x81F10000, 0x80E10000, 0x80E10000, 0x80E10000, 0x80E10000, 0x06310000, 0x06310000, 0x06310000, 0x06310000, 0x64F08000, 0x46F08000, 0x66B08000, 0x66B08000, 0x02210000, 0x02210000, 0x02210000, 0x02210000, 0x84E08000, 0x42E08000, 0x62B08000, 0x82E08000, 0x18710000, 0x18710000, 0x18710000, 0x18710000, 0x20A10000, 0x20A10000, 0x20A10000, 0x20A10000, 0x99F18000, 0x99F18000, 0x99F18000, 0x99F18000, 0x91F08000, 0x98F08000, 0x21A08000, 0xA0E08000, 0x08610000, 0x08610000, 0x08610000, 0x08610000, 0x24E08000, 0x26B08000, 0x48E08000, 0x28E08000, 0x19708000, 0x12A08000, 0x89F08000, 0x0A608000, 0x4AE08000, 0x29E08000, 0x22A08000, 0x88E08000, 0x00009000, 0x0000A000, 0x00008004, 0x00008004, 0x00010004, 0x00010004, 0x00010004, 0x00010004, 0x00010020, 0x00010020, 0x00010020, 0x00010020, 0x00000024, 0x01000004, 0xC0D00020, 0xC0D00004, 0x00010100, 0x00010100, 0x00010100, 0x00010100, 0x00000104, 0x40C00100, 0x04400004, 0x04400004, 0x00000120, 0x04400020, 0x03100100, 0x03100020, 0x01000104, 0x04400024, 0xC0D00100, 0x03100004, 0x00010800, 0x00010800, 0x00010800, 0x00010800, 0x00000804, 0x40C00800, 0x30900800, 0x30900004, 0x00000820, 0x01000800, 0x10800020, 0x10800020, 0x01000804, 0x10800024, 0xC0D00800, 0x30900020, 0x00000900, 0x10800100, 0x0C500800, 0x0C500100, 0x04400804, 0x10800104, 0x30900100, 0x0C500004, 0x04400820, 0x10800120, 0x03100800, 0x0C500020, 0xC0D00900, 0x03100804, 0x30900120, 0x0C500024, 0x81F08020, 0x18708800, 0x60B08004, 0x06308100, 0x60B10004, 0x60B10004, 0x60B10004, 0x60B10004, 0x81F10020, 0x81F10020, 0x81F10020, 0x81F10020, 0x60B00020, 0x80E00020, 0x80E00004, 0x80E00004, 0x06310100, 0x06310100, 0x06310100, 0x06310100, 0x60B00100, 0x06300004, 0x06300004, 0x06300004, 0x81F00100, 0x02200100, 0x02200020, 0x02200020, 0x60B00120, 0x80E00100, 0x02200004, 0x02200004, 0x18710800, 0x18710800, 0x18710800, 0x18710800, 0x18700004, 0x20A00800, 0x20A00004, 0x20A00004, 0x81F00800, 0x18700020, 0x18700020, 0x18700020, 0x18700024, 0x80E00800, 0x20A00020, 0x20A00020, 0x06300800, 0x08600800, 0x08600100, 0x08600100, 0x06300804, 0x20A00100, 0x08600004, 0x08600004, 0x81F00900, 0x02200800, 0x08600020, 0x08600020, 0x80E00900, 0x02200804, 0x20A00120, 0x08600024, 0x0000A000, 0x0000C000, 0x00008002, 0x00008002, 0x00010002, 0x00010002, 0x00010002, 0x00010002, 0x00010010, 0x00010010, 0x00010010, 0x00010010, 0x00000012, 0x01000002, 0xC0D00010, 0xC0D00002, 0x00010080, 0x00010080, 0x00010080, 0x00010080, 0x00000082, 0x40C00080, 0x04400002, 0x04400002, 0x00000090, 0x04400010, 0x03100080, 0x03100010, 0x01000082, 0x04400012, 0xC0D00080, 0x03100002, 0x00010400, 0x00010400, 0x00010400, 0x00010400, 0x00000402, 0x40C00400, 0x30900400, 0x30900002, 0x00000410, 0x01000400, 0x10800010, 0x10800010, 0x01000402, 0x10800012, 0xC0D00400, 0x30900010, 0x00000480, 0x10800080, 0x0C500400, 0x0C500080, 0x04400402, 0x10800082, 0x30900080, 0x0C500002, 0x04400410, 0x10800090, 0x03100400, 0x0C500010, 0xC0D00480, 0x03100402, 0x30900090, 0x0C500012, 0x81F08010, 0x18708400, 0x60B08002, 0x06308080, 0x60B10002, 0x60B10002, 0x60B10002, 0x60B10002, 0x81F10010, 0x81F10010, 0x81F10010, 0x81F10010, 0x60B00010, 0x80E00010, 0x80E00002, 0x80E00002, 0x06310080, 0x06310080, 0x06310080, 0x06310080, 0x60B00080, 0x06300002, 0x06300002, 0x06300002, 0x81F00080, 0x02200080, 0x02200010, 0x02200010, 0x60B00090, 0x80E00080, 0x02200002, 0x02200002, 0x18710400, 0x18710400, 0x18710400, 0x18710400, 0x18700002, 0x20A00400, 0x20A00002, 0x20A00002, 0x81F00400, 0x18700010, 0x18700010, 0x18700010, 0x18700012, 0x80E00400, 0x20A00010, 0x20A00010, 0x06300400, 0x08600400, 0x08600080, 0x08600080, 0x06300402, 0x20A00080, 0x08600002, 0x08600002, 0x81F00480, 0x02200400, 0x08600010, 0x08600010, 0x80E00480, 0x02200402, 0x20A00090, 0x08600012, 0x00012000, 0x00012000, 0x00012000, 0x00012000, 0x00000006, 0x00002004, 0x00002002, 0x40C02000, 0x00000030, 0x00002020, 0x00002010, 0x01002000, 0xC0D00006, 0x00000014, 0x00000022, 0xC0D02000, 0x00000180, 0x00002100, 0x00002080, 0x04402000, 0x04402004, 0x04402002, 0x00000084, 0x00000102, 0x03100030, 0x000000A0, 0x00000110, 0x03102000, 0x03100022, 0x03100006, 0x03102004, 0x03102002, 0x00000C00, 0x00002800, 0x00002400, 0x10802000, 0x30900006, 0x00000404, 0x00000802, 0x30902000, 0x10802020, 0x10802010, 0x00000420, 0x00000810, 0x30900014, 0x30900022, 0x30902020, 0x30902010, 0x0C500180, 0x00000500, 0x00000880, 0x0C502000, 0x0C500102, 0x0C500006, 0x0C502004, 0x0C502002, 0x0C500110, 0x0C500030, 0x0C502020, 0x0C502010, 0x309000A0, 0x30900110, 0x0C500014, 0x0C500022, 0x1870A000, 0x60B0A000, 0x0630A000, 0x0000A000, 0x60B00006, 0x60B02000, 0x60B02000, 0x60B02000, 0x81F00030, 0x81F02000, 0x81F02000, 0x81F02000, 0x80E00014, 0x80E00022, 0x80E00006, 0x80E02000, 0x06300180, 0x06302000, 0x06302000, 0x06302000, 0x06300102, 0x06300006, 0x06302004, 0x06302002, 0x022000A0, 0x02200110, 0x02200030, 0x02202000, 0x02200022, 0x02200006, 0x02202004, 0x02202002, 0x18700C00, 0x18702000, 0x18702000, 0x18702000, 0x20A00404, 0x20A00802, 0x20A00006, 0x20A02000, 0x18700810, 0x18700030, 0x18702020, 0x18702010, 0x20A00014, 0x20A00022, 0x20A02020, 0x20A02010, 0x08600500, 0x08600880, 0x08600180, 0x08602000, 0x08600102, 0x08600006, 0x08602004, 0x08602002, 0x08600110, 0x08600030, 0x08602020, 0x08602010, 0x20A000A0, 0x20A00110, 0x08600014, 0x08600022, 0x00009000, 0x0000C000, 0x00008001, 0x00008001, 0x00010001, 0x00010001, 0x00010001, 0x00010001, 0x00010008, 0x00010008, 0x00010008, 0x00010008, 0x00000009, 0x01000001, 0xC0D00008, 0xC0D00001, 0x00010040, 0x00010040, 0x00010040, 0x00010040, 0x00000041, 0x40C00040, 0x04400001, 0x04400001, 0x00000048, 0x04400008, 0x03100040, 0x03100008, 0x01000041, 0x04400009, 0xC0D00040, 0x03100001, 0x00010200, 0x00010200, 0x00010200, 0x00010200, 0x00000201, 0x40C00200, 0x30900200, 0x30900001, 0x00000208, 0x01000200, 0x10800008, 0x10800008, 0x01000201, 0x10800009, 0xC0D00200, 0x30900008, 0x00000240, 0x10800040, 0x0C500200, 0x0C500040, 0x04400201, 0x10800041, 0x30900040, 0x0C500001, 0x04400208, 0x10800048, 0x03100200, 0x0C500008, 0xC0D00240, 0x03100201, 0x30900048, 0x0C500009, 0x81F08008, 0x18708200, 0x60B08001, 0x06308040, 0x60B10001, 0x60B10001, 0x60B10001, 0x60B10001, 0x81F10008, 0x81F10008, 0x81F10008, 0x81F10008, 0x60B00008, 0x80E00008, 0x80E00001, 0x80E00001, 0x06310040, 0x06310040, 0x06310040, 0x06310040, 0x60B00040, 0x06300001, 0x06300001, 0x06300001, 0x81F00040, 0x02200040, 0x02200008, 0x02200008, 0x60B00048, 0x80E00040, 0x02200001, 0x02200001, 0x18710200, 0x18710200, 0x18710200, 0x18710200, 0x18700001, 0x20A00200, 0x20A00001, 0x20A00001, 0x81F00200, 0x18700008, 0x18700008, 0x18700008, 0x18700009, 0x80E00200, 0x20A00008, 0x20A00008, 0x06300200, 0x08600200, 0x08600040, 0x08600040, 0x06300201, 0x20A00040, 0x08600001, 0x08600001, 0x81F00240, 0x02200200, 0x08600008, 0x08600008, 0x80E00240, 0x02200201, 0x20A00048, 0x08600009, 0x00011000, 0x00011000, 0x00011000, 0x00011000, 0x00000005, 0x00001004, 0x00001001, 0x40C01000, 0x00000028, 0x00001020, 0x00001008, 0x01001000, 0xC0D00005, 0x0000000C, 0x00000021, 0xC0D01000, 0x00000140, 0x00001100, 0x00001040, 0x04401000, 0x04401004, 0x04401001, 0x00000044, 0x00000101, 0x03100028, 0x00000060, 0x00000108, 0x03101000, 0x03100021, 0x03100005, 0x03101004, 0x03101001, 0x00000A00, 0x00001800, 0x00001200, 0x10801000, 0x30900005, 0x00000204, 0x00000801, 0x30901000, 0x10801020, 0x10801008, 0x00000220, 0x00000808, 0x3090000C, 0x30900021, 0x30901020, 0x30901008, 0x0C500140, 0x00000300, 0x00000840, 0x0C501000, 0x0C500101, 0x0C500005, 0x0C501004, 0x0C501001, 0x0C500108, 0x0C500028, 0x0C501020, 0x0C501008, 0x30900060, 0x30900108, 0x0C50000C, 0x0C500021, 0x18709000, 0x60B09000, 0x06309000, 0x00009000, 0x60B00005, 0x60B01000, 0x60B01000, 0x60B01000, 0x81F00028, 0x81F01000, 0x81F01000, 0x81F01000, 0x80E0000C, 0x80E00021, 0x80E00005, 0x80E01000, 0x06300140, 0x06301000, 0x06301000, 0x06301000, 0x06300101, 0x06300005, 0x06301004, 0x06301001, 0x02200060, 0x02200108, 0x02200028, 0x02201000, 0x02200021, 0x02200005, 0x02201004, 0x02201001, 0x18700A00, 0x18701000, 0x18701000, 0x18701000, 0x20A00204, 0x20A00801, 0x20A00005, 0x20A01000, 0x18700808, 0x18700028, 0x18701020, 0x18701008, 0x20A0000C, 0x20A00021, 0x20A01020, 0x20A01008, 0x08600300, 0x08600840, 0x08600140, 0x08601000, 0x08600101, 0x08600005, 0x08601004, 0x08601001, 0x08600108, 0x08600028, 0x08601020, 0x08601008, 0x20A00060, 0x20A00108, 0x0860000C, 0x08600021, 0x00014000, 0x00014000, 0x00014000, 0x00014000, 0x00000003, 0x00004002, 0x00004001, 0x40C04000, 0x00000018, 0x00004010, 0x00004008, 0x01004000, 0xC0D00003, 0x0000000A, 0x00000011, 0xC0D04000, 0x000000C0, 0x00004080, 0x00004040, 0x04404000, 0x04404002, 0x04404001, 0x00000042, 0x00000081, 0x03100018, 0x00000050, 0x00000088, 0x03104000, 0x03100011, 0x03100003, 0x03104002, 0x03104001, 0x00000600, 0x00004400, 0x00004200, 0x10804000, 0x30900003, 0x00000202, 0x00000401, 0x30904000, 0x10804010, 0x10804008, 0x00000210, 0x00000408, 0x3090000A, 0x30900011, 0x30904010, 0x30904008, 0x0C5000C0, 0x00000280, 0x00000440, 0x0C504000, 0x0C500081, 0x0C500003, 0x0C504002, 0x0C504001, 0x0C500088, 0x0C500018, 0x0C504010, 0x0C504008, 0x30900050, 0x30900088, 0x0C50000A, 0x0C500011, 0x1870C000, 0x60B0C000, 0x0630C000, 0x0000C000, 0x60B00003, 0x60B04000, 0x60B04000, 0x60B04000, 0x81F00018, 0x81F04000, 0x81F04000, 0x81F04000, 0x80E0000A, 0x80E00011, 0x80E00003, 0x80E04000, 0x063000C0, 0x06304000, 0x06304000, 0x06304000, 0x06300081, 0x06300003, 0x06304002, 0x06304001, 0x02200050, 0x02200088, 0x02200018, 0x02204000, 0x02200011, 0x02200003, 0x02204002, 0x02204001, 0x18700600, 0x18704000, 0x18704000, 0x18704000, 0x20A00202, 0x20A00401, 0x20A00003, 0x20A04000, 0x18700408, 0x18700018, 0x18704010, 0x18704008, 0x20A0000A, 0x20A00011, 0x20A04010, 0x20A04008, 0x08600280, 0x08600440, 0x086000C0, 0x08604000, 0x08600081, 0x08600003, 0x08604002, 0x08604001, 0x08600088, 0x08600018, 0x08604010, 0x08604008, 0x20A00050, 0x20A00088, 0x0860000A, 0x08600011, 0x00006000, 0x00005000, 0x00003000, 0x00003000, 0x40C03000, 0x00004004, 0x00002001, 0x00001002, 0x01003000, 0x00004020, 0x00002008, 0x00001010, 0xC0D01010, 0xC0D01002, 0xC0D05000, 0xC0D03000, 0x04403000, 0x00004100, 0x00002040, 0x00001080, 0x40C01080, 0x04404004, 0x04402001, 0x04401002, 0x03101080, 0x03101010, 0x03105000, 0x03103000, 0xC0D01080, 0x03104004, 0x03102001, 0x03101002, 0x10803000, 0x00004800, 0x00002200, 0x00001400, 0x30901400, 0x30901002, 0x30905000, 0x30903000, 0x01001400, 0x10804020, 0x10802008, 0x10801010, 0xC0D01400, 0x30904020, 0x30902008, 0x30901010, 0x0C501400, 0x0C501080, 0x0C505000, 0x0C503000, 0x30901080, 0x0C504004, 0x0C502001, 0x0C501002, 0x03101400, 0x0C504020, 0x0C502008, 0x0C501010, 0x0C501022, 0x0C501012, 0x0C50100A, 0x0C501011, 0x0630B000, 0x0000D000, 0x0000B000, 0x0000B000, 0x60B06000, 0x60B01002, 0x60B05000, 0x60B03000, 0x81F06000, 0x81F01010, 0x81F05000, 0x81F03000, 0x80E01010, 0x80E01002, 0x80E05000, 0x80E03000, 0x06306000, 0x06301080, 0x06305000, 0x06303000, 0x60B01080, 0x06304004, 0x06302001, 0x06301002, 0x02201080, 0x02201010, 0x02205000, 0x02203000, 0x80E01080, 0x02204004, 0x02202001, 0x02201002, 0x18706000, 0x18701400, 0x18705000, 0x18703000, 0x20A01400, 0x20A01002, 0x20A05000, 0x20A03000, 0x81F01400, 0x18704020, 0x18702008, 0x18701010, 0x80E01400, 0x20A04020, 0x20A02008, 0x20A01010, 0x08601400, 0x08601080, 0x08605000, 0x08603000, 0x20A01080, 0x08604004, 0x08602001, 0x08601002, 0x02201400, 0x08604020, 0x08602008, 0x08601010, 0x08601022, 0x08601012, 0x0860100A, 0x08601011, }; /* * X-axis and Y-axis values to report for each of 16 different Intellivision * joystick directions. These represent points on a circle. */ static short js_intv_dir[16] = { 0x7FFF, 0x7640, 0x5A81, 0x30FB, 0x0000, 0xCF05, 0xA57F, 0x89C0, 0x8001, 0x89C0, 0xA57F, 0xCF05, 0x0000, 0x30FB, 0x5A81, 0x7640 }; static struct js_port* js_intv_port = NULL; static int js_intv[] __initdata = { -1, 3, 10, 0 }; static int js_intv_2[] __initdata = { -1, 3, 10, 0 }; static int js_intv_3[] __initdata = { -1, 3, 10, 0 }; struct js_intv_info { #ifdef USE_PARPORT struct pardevice *port; /* parport device */ #else int port; /* hw port */ #endif int sticks; /* joysticks connected */ int udelay; /* Delay time */ int raw; /* Raw mode */ unsigned pd[2]; /* previous decode */ }; /* * js_intv_bits() counts bits in a word. */ static int js_intv_bits(unsigned w) { int b = 0; for (b = 0; w; w &= w - 1) b++; return b; } /* * js_intv_read() reads and analyzes intellivision joystick data. */ static int js_intv_read(void *xinfo, int **axes, int **buttons) { struct js_intv_info *info = xinfo; int data1, data2, i, j, data, dir, is_disc; unsigned dec, ndec, pdec; int bc, bbc; for (i = 0; i < 2; i++) if ((info->sticks >> i) & 1) { /* Read low nibble */ JS_PAR_DATA_OUT(((2 << i) | 1), info->port); udelay(info->udelay); data1 = JS_PAR_STATUS(info->port); /* Read high nibble */ JS_PAR_DATA_OUT(((2 << i) | 0), info->port); udelay(info->udelay); data2 = JS_PAR_STATUS(info->port); /* Deselect both joysticks when done. */ JS_PAR_DATA_OUT(0, info->port); /* * TODO: Rewrite lookup table to avoid needing * to invert bits after reading port. */ data = (((data1 >> 2) & 0x03C) | ((data2 << 2 )& 0x3C0)) ^ 0x1DF; /* Decode the port data into button & direction info. * * Disambiguate the new value by finding the decoding * which has the fewest bit-changes as compared to * the old decoding (if there _was_ an old decoding). * * If there was no previous decoding, merely take the * first element we find in the table. */ pdec = info->pd[i]; j = pdec ? 4 : 1; dec = 0; bbc = 33; while (j-->0) { ndec = js_intv_tbl[data--]; bc = js_intv_bits((ndec^pdec) & ~JS_INTV_DISC_MASK); if (bc < bbc) { dec = ndec; bbc = bc; } } data++; dir = JS_INTV_DISC_DIR(dec); is_disc = dec & JS_INTV_IS_DISC; axes[i][0] = is_disc ? js_intv_dir[(dir ) & 15] : 0; axes[i][1] = is_disc ? js_intv_dir[(dir + 4) & 15] : 0; buttons[i][0] = dec & (info->raw ? JS_INTV_BUTTON_R : JS_INTV_BUTTON); /* If raw==2, return directional switch info as buttons */ if (info->raw == 2) buttons[i][0] |= (dec >> 7) & 0x1FE0000; /* If raw==3, is selected, return the pre-decode data. */ if (info->raw == 3) buttons[i][0] |= (data << 15) & 0x1FE0000; /* Remember this decoding as the new "old" decoding. */ info->pd[i] = dec; } return 0; } /* * open callback: claim parport. */ int js_intv_open(struct js_dev *dev) { struct js_intv_info *info = dev->port->info; if (!MOD_IN_USE) { #ifdef USE_PARPORT if (parport_claim(info->port)) return -EBUSY; #endif JS_PAR_CTRL_OUT(0x04, info->port); } MOD_INC_USE_COUNT; return 0; } /* * close callback: release parport */ int js_intv_close(struct js_dev *dev) { struct js_intv_info *info = dev->port->info; MOD_DEC_USE_COUNT; if (!MOD_IN_USE) { JS_PAR_CTRL_OUT(0x00, info->port); #ifdef USE_PARPORT parport_release(info->port); #endif } return 0; } #ifdef MODULE void cleanup_module(void) { struct js_intv_info *info; int i; while (js_intv_port != NULL) { for (i = 0; i < js_intv_port->ndevs; i++) if (js_intv_port->devs[i] != NULL) js_unregister_device(js_intv_port->devs[i]); info = js_intv_port->info; #ifdef USE_PARPORT parport_unregister_device(info->port); #else release_region(info->port, 3); #endif js_intv_port = js_unregister_port(js_intv_port); } } #endif /* * js_intv_init_corr() initializes correction values of * intellivision gamepads. */ static void __init js_intv_init_corr(int sticks, struct js_corr **corr) { int i, j; for (i = 0; i < 2; i++) if ((sticks >> i) & 1) for (j = 0; j < 2; j++) { corr[i][j].type = JS_CORR_NONE; corr[i][j].prec = 0; corr[i][j].coef[0] = 0; corr[i][j].coef[1] = 0; corr[i][j].coef[2] = 0; corr[i][j].coef[3] = 0; } } /* * js_intv_probe() probes for intellivision gamepads. */ static struct js_port __init *js_intv_probe(int *config, struct js_port *port) { struct js_intv_info iniinfo; struct js_intv_info *info = &iniinfo; int i; int buttons; char *name; if (config[0] < 0) return port; #ifdef USE_PARPORT { struct parport *pp; if (config[0] > 0x10) for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next) { } else for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) { config[0]--; } if (pp == NULL) { printk(KERN_ERR "joy-intv: no such parport\n"); return port; } info->port = parport_register_device(pp, "joystick (intv2pc)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); if (!info->port) return port; } #else info->port = config[0]; if (check_region(info->port, 3)) return port; request_region(info->port, 3, "joystick (intv2pc)"); #endif port = js_register_port(port, info, 7, sizeof(struct js_intv_info), js_intv_read); info = port->info; info->sticks = config[1] & 3; info->udelay = config[2] < 1 ? 1 : config[2] > 400 ? 400 : config[2]; info->raw = config[3]; switch (info->raw) { default: case 0: buttons = 15; name = "INTV2PC"; break; case 1: buttons = 17; name = "INTV2PC-xi"; break; case 2: buttons = 25; name = "INTV2PC-xid"; break; case 3: buttons = 25; name = "INTV2PC-raw"; break; } for (i = 0; i < 2; i++) if ((info->sticks >> i) & 1) { #ifdef USE_PARPORT printk(KERN_INFO "js%d: INTV2PC on %s\n", js_register_device(port, i, 2, buttons, name, js_intv_open, js_intv_close), info->port->port->name); #else printk(KERN_INFO "js%d: INTV2PC at %#x\n", js_register_device(port, i, 2, buttons, name, js_intv_open, js_intv_close), info->port); #endif } if (!info->sticks) { #ifdef USE_PARPORT parport_unregister_device(info->port); #else release_region(info->port, 3); #endif printk(KERN_INFO "js-intv2pc: No joysticks registered\n"); return port; } js_intv_init_corr(info->sticks, port->corr); return port; } #ifndef MODULE void __init js_intv_setup(char *str, int *ints) { int i; if (!strcmp(str,"js_intv2pc")) for (i = 0; i <= ints[0] && i < 2; i++) js_intv[i] = ints[i+1]; if (!strcmp(str,"js_intv2pc_2")) for (i = 0; i <= ints[0] && i < 2; i++) js_intv_2[i] = ints[i+1]; if (!strcmp(str,"js_intv2pc_3")) for (i = 0; i <= ints[0] && i < 2; i++) js_intv_3[i] = ints[i+1]; } #endif #ifdef MODULE int init_module(void) #else int __init js_intv_init(void) #endif { js_intv_port = js_intv_probe(js_intv, js_intv_port); js_intv_port = js_intv_probe(js_intv_2, js_intv_port); js_intv_port = js_intv_probe(js_intv_3, js_intv_port); if (js_intv_port) return 0; #ifdef MODULE printk(KERN_WARNING "joy-intv: no joysticks specified\n"); #endif return -ENODEV; }