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); |