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:43:45
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/serio In directory usw-pr-cvs1:/tmp/cvs-serv11792 Modified Files: Tag: 1.8 i8042.h Log Message: Moved. --- NEW FILE: i8042.h --- #ifndef _I8042_H #define _I8042_H /* * $Id: i8042.h,v 1.8 2002/01/22 20:43:42 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik */ /* * 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 */ /* * If you want to reset your i8042 upon boot, define this. */ #undef I8042_RESET /* * If you want to trace all the i/o the i8042 module does for * debugging purposes, define this. */ #undef I8042_DEBUG_IO /* * On most PC based systems the keyboard IRQ is 1. */ #define I8042_KBD_IRQ CONFIG_I8042_KBD_IRQ /* * On most PC based systems the aux port IRQ is 12. There are exceptions, * though. Unfortunately IRQ probing is not possible without touching * the device attached to the port. */ #define I8042_AUX_IRQ CONFIG_I8042_AUX_IRQ /* * The speed of the i8042's varies. This timeout equals 100 ms on a system * with 8.3 MHz i8042 clock, which should be most common. It should not need * to be raised / lowered. */ #define I8042_CTL_TIMEOUT 83000 /* * Register numbers. */ #define I8042_COMMAND_REG CONFIG_I8042_REG_BASE + 4 #define I8042_STATUS_REG CONFIG_I8042_REG_BASE + 4 #define I8042_DATA_REG CONFIG_I8042_REG_BASE /* * Status register bits. */ #define I8042_STR_PARITY 0x80 #define I8042_STR_TIMEOUT 0x40 #define I8042_STR_AUXDATA 0x20 #define I8042_STR_KEYLOCK 0x10 #define I8042_STR_CMDDAT 0x08 #define I8042_STR_IBF 0x02 #define I8042_STR_OBF 0x01 /* * Control register bits. */ #define I8042_CTR_KBDINT 0x01 #define I8042_CTR_AUXINT 0x02 #define I8042_CTR_IGNKEYLOCK 0x08 #define I8042_CTR_KBDDIS 0x10 #define I8042_CTR_AUXDIS 0x20 #define I8042_CTR_XLATE 0x40 /* * Commands. */ #define I8042_CMD_CTL_RCTR 0x0120 #define I8042_CMD_CTL_WCTR 0x1060 #define I8042_CMD_CTL_TEST 0x01aa #define I8042_CMD_KBD_DISABLE 0x00ad #define I8042_CMD_KBD_ENABLE 0x00ae #define I8042_CMD_KBD_TEST 0x01ab #define I8042_CMD_KBD_LOOP 0x11d2 #define I8042_CMD_AUX_DISABLE 0x00a7 #define I8042_CMD_AUX_ENABLE 0x00a8 #define I8042_CMD_AUX_TEST 0x01a9 #define I8042_CMD_AUX_SEND 0x10d4 #define I8042_CMD_AUX_LOOP 0x11d3 /* * Return codes. */ #define I8042_RET_CTL_TEST 0x55 /* * Expected maximum internal i8042 buffer size. This is used for flushing * the i8042 buffers. 32 should be more than enough. */ #define I8042_BUFFER_SIZE 32 #endif _I8042_H |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:43:26
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/serio In directory usw-pr-cvs1:/tmp/cvs-serv11619 Modified Files: Tag: 1.16 i8042.c Log Message: Moved. --- NEW FILE: i8042.c --- /* * $Id: i8042.c,v 1.16 2002/01/22 20:43:24 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik */ /* * i8042 keyboard and mouse 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 <asm/io.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/ioport.h> #include <linux/config.h> #include <linux/reboot.h> #include <linux/init.h> #include <linux/serio.h> #include "i8042.h" MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>"); MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); MODULE_LICENSE("GPL"); MODULE_PARM(i8042_noaux, "1i"); MODULE_PARM(i8042_unlock, "1i"); MODULE_PARM(i8042_reset, "1i"); MODULE_PARM(i8042_direct, "1i"); static int i8042_noaux; static int i8042_unlock; static int i8042_reset; static int i8042_direct; spinlock_t i8042_lock = SPIN_LOCK_UNLOCKED; struct i8042_values { int irq; unsigned char disable; unsigned char irqen; unsigned char exists; unsigned char *name; unsigned char *phys; }; static struct serio i8042_kbd_port; static struct serio i8042_aux_port; static unsigned char i8042_initial_ctr; static unsigned char i8042_ctr; #ifdef I8042_DEBUG_IO static unsigned long i8042_start; #endif static unsigned long i8042_unxlate_seen[128 / BITS_PER_LONG]; static unsigned char i8042_unxlate_table[128] = { 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 }; static void i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); /* * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to * be ready for reading values from it / writing values to it. */ static int i8042_wait_read(void) { int i = 0; while ((~inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) i++; return -(i == I8042_CTL_TIMEOUT); } static int i8042_wait_write(void) { int i = 0; while ((inb(I8042_STATUS_REG) & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) i++; return -(i == I8042_CTL_TIMEOUT); } /* * i8042_flush() flushes all data that may be in the keyboard and mouse buffers * of the i8042 down the toilet. */ static int i8042_flush(void) { unsigned long flags; int i = 0; spin_lock_irqsave(&i8042_lock, flags); while ((inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE)) #ifdef I8042_DEBUG_IO printk(KERN_DEBUG "i8042.c: %02x <- i8042 (flush) [%d]\n", inb(I8042_DATA_REG), (int) (jiffies - i8042_start)); #else inb(I8042_DATA_REG); #endif spin_unlock_irqrestore(&i8042_lock, flags); return i; } /* * i8042_command() executes a command on the i8042. It also sends the input parameter(s) * of the commands to it, and receives the output value(s). The parameters are to be * stored in the param array, and the output is placed into the same array. The number * of the parameters and output values is encoded in bits 8-11 of the command * number. */ static int i8042_command(unsigned char *param, int command) { unsigned long flags; int retval = 0, i = 0; spin_lock_irqsave(&i8042_lock, flags); retval = i8042_wait_write(); if (!retval) { #ifdef I8042_DEBUG_IO printk(KERN_DEBUG "i8042.c: %02x -> i8042 (command) [%d]\n", command & 0xff, (int) (jiffies - i8042_start)); #endif outb(command & 0xff, I8042_COMMAND_REG); } if (!retval) for (i = 0; i < ((command >> 12) & 0xf); i++) { if ((retval = i8042_wait_write())) break; #ifdef I8042_DEBUG_IO printk(KERN_DEBUG "i8042.c: %02x -> i8042 (parameter) [%d]\n", param[i], (int) (jiffies - i8042_start)); #endif outb(param[i], I8042_DATA_REG); } if (!retval) for (i = 0; i < ((command >> 8) & 0xf); i++) { if ((retval = i8042_wait_read())) break; if (inb(I8042_STATUS_REG) & I8042_STR_AUXDATA) param[i] = ~inb(I8042_DATA_REG); else param[i] = inb(I8042_DATA_REG); #ifdef I8042_DEBUG_IO printk(KERN_DEBUG "i8042.c: %02x <- i8042 (return) [%d]\n", param[i], (int) (jiffies - i8042_start)); #endif } spin_unlock_irqrestore(&i8042_lock, flags); return retval; } /* * i8042_kbd_write() sends a byte out through the keyboard interface. * It also automatically refreshes the CTR value, since some i8042's * trash their CTR after attempting to send data to an nonexistent * device. */ static int i8042_kbd_write(struct serio *port, unsigned char c) { unsigned long flags; int retval = 0; spin_lock_irqsave(&i8042_lock, flags); if(!(retval = i8042_wait_write())) { #ifdef I8042_DEBUG_IO printk(KERN_DEBUG "i8042.c: %02x -> i8042 (kbd-data) [%d]\n", c, (int) (jiffies - i8042_start)); #endif outb(c, I8042_DATA_REG); } spin_unlock_irqrestore(&i8042_lock, flags); return retval; } /* * i8042_aux_write() sends a byte out through the aux interface. */ static int i8042_aux_write(struct serio *port, unsigned char c) { int retval; /* * Send the byte out. */ retval = i8042_command(&c, I8042_CMD_AUX_SEND); /* * Here we restore the CTR value. I don't know why, but i8042's in half-AT * mode tend to trash their CTR when doing the AUX_SEND command. */ retval += i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR); /* * Make sure the interrupt happens and the character is received even * in the case the IRQ isn't wired, so that we can receive further * characters later. */ i8042_interrupt(0, port, NULL); return retval; } /* * i8042_open() is called when a port is open by the higher layer. * It allocates an interrupt and enables the port. */ static int i8042_open(struct serio *port) { struct i8042_values *values = port->driver; /* * Allocate the interrupt */ if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL)) { printk(KERN_ERR "i8042.c: Can't get irq %d for %s\n", values->irq, values->name); return -1; } /* * Enable the device and its interrupt. */ i8042_ctr |= values->irqen; i8042_ctr &= ~values->disable; if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { printk(KERN_ERR "i8042.c: Can't write CTR while opening %s.\n", values->name); return -1; } /* * Flush buffers */ i8042_flush(); return 0; } /* * i8042_close() frees the interrupt, and disables the interface when the * upper layer doesn't need it anymore. */ static void i8042_close(struct serio *port) { struct i8042_values *values = port->driver; /* * Disable the device and its interrupt. */ i8042_ctr &= ~values->irqen; i8042_ctr |= values->disable; if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { printk(KERN_ERR "i8042.c: Can't write CTR while closing %s.\n", values->name); return; } /* * Free the interrupt */ free_irq(values->irq, NULL); } /* * Structures for registering the devices in the serio.c module. */ static struct i8042_values i8042_kbd_values = { irq: I8042_KBD_IRQ, irqen: I8042_CTR_KBDINT, disable: I8042_CTR_KBDDIS, name: "KBD", exists: 0, }; static struct serio i8042_kbd_port = { type: SERIO_8042, write: i8042_kbd_write, open: i8042_open, close: i8042_close, driver: &i8042_kbd_values, name: "i8042 Kbd Port", phys: "isa0060/serio0", }; static struct i8042_values i8042_aux_values = { irq: I8042_AUX_IRQ, irqen: I8042_CTR_AUXINT, disable: I8042_CTR_AUXDIS, name: "AUX", exists: 0, }; static struct serio i8042_aux_port = { type: SERIO_8042, write: i8042_aux_write, open: i8042_open, close: i8042_close, driver: &i8042_aux_values, name: "i8042 Aux Port", phys: "isa0060/serio1", }; /* * i8042_interrupt() is the most important function in this driver - * it handles the interrupts from the i8042, and sends incoming bytes * to the upper layers. */ static void i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; unsigned char str, data; spin_lock_irqsave(&i8042_lock, flags); while ((str = inb(I8042_STATUS_REG)) & I8042_STR_OBF) { data = inb(I8042_DATA_REG); #ifdef I8042_DEBUG_IO printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt-%s) [%d]\n", data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", (int) (jiffies - i8042_start)); #endif if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) { if (i8042_aux_port.dev) i8042_aux_port.dev->interrupt(&i8042_aux_port, data, 0); } else { if (i8042_kbd_values.exists && i8042_kbd_port.dev) { if (!i8042_direct) { if (data > 0x7f) { if (test_and_clear_bit(data & 0x7f, i8042_unxlate_seen)) { i8042_kbd_port.dev->interrupt(&i8042_kbd_port, 0xf0, 0); data = i8042_unxlate_table[data & 0x7f]; } } else { set_bit(data, i8042_unxlate_seen); data = i8042_unxlate_table[data]; } } i8042_kbd_port.dev->interrupt(&i8042_kbd_port, data, 0); } } } spin_unlock_irqrestore(&i8042_lock, flags); } /* * i8042_controller init initializes the i8042 controller, and, * most importantly, sets it into non-xlated mode. */ static int __init i8042_controller_init(void) { /* * Check the i/o region before we touch it. */ #if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) if (check_region(I8042_DATA_REG, 16)) { printk(KERN_ERR "i8042.c: %#x port already in use!\n", I8042_DATA_REG); return -1; } #endif /* * Test the i8042. We need to know if it thinks it's working correctly * before doing anything else. */ i8042_flush(); if (i8042_reset) { unsigned char param; if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); return -1; } if (param != I8042_RET_CTL_TEST) { printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", param, I8042_RET_CTL_TEST); return -1; } } /* * Read the CTR. */ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); return -1; } /* * Save the CTR for restoral on unload / reboot. */ i8042_initial_ctr = i8042_ctr; /* * Disable both interfaces and their interrupts. */ i8042_ctr |= I8042_CTR_KBDDIS; i8042_ctr &= ~I8042_CTR_KBDINT; /* * Handle keylock. */ if (~inb(I8042_STATUS_REG) & I8042_STR_KEYLOCK) { if (i8042_unlock) { i8042_ctr |= I8042_CTR_IGNKEYLOCK; } else { printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); } } /* * Set nontranslated mode for the kbd interface. This is vital for a working * scancode set 2/3 support. After this the kbd interface becomes a simple serial * in/out, like the aux interface is. If the user doesn't wish this, the driver * tries to untranslate the values after the i8042 translates them. */ if (i8042_direct) i8042_ctr &= ~I8042_CTR_XLATE; /* * Write CTR back. */ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); return -1; } return 0; } /* * Here we try to reset everything back to a state in which the BIOS will be * able to talk to the hardware when rebooting. */ void i8042_controller_cleanup(void) { /* * Reset the controller. */ if (i8042_reset) { unsigned char param; if (i8042_command(¶m, I8042_CMD_CTL_TEST)) printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n"); } /* * Restore the original control register setting. */ i8042_ctr = i8042_initial_ctr; if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); /* * Reset anything that is connected to the ports if the ports * are enabled in the original config. */ if (i8042_kbd_values.exists) i8042_kbd_write(&i8042_kbd_port, 0xff); if (i8042_aux_values.exists) i8042_aux_write(&i8042_aux_port, 0xff); } /* * i8042_check_aux() applies as much paranoia as it can at detecting * the presence of an AUX interface. */ static int __init i8042_check_aux(struct i8042_values *values, struct serio *port) { unsigned char param; i8042_flush(); /* * Internal loopback test - filters out AT-type i8042's */ param = 0x5a; if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xa5) return -1; /* * External connection test - filters out AT-soldered PS/2 i8042's */ if (i8042_command(¶m, I8042_CMD_AUX_TEST) || param) return -1; /* * Bit assignment test - filters out PS/2 i8042's in AT mode */ if (i8042_command(¶m, I8042_CMD_AUX_DISABLE)) return -1; if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS)) return -1; if (i8042_command(¶m, I8042_CMD_AUX_TEST) || param) { /* * We've got an old AMI i8042 with 'Bad Cache' commands. */ i8042_command(¶m, I8042_CMD_AUX_ENABLE); return -1; } if (i8042_command(¶m, I8042_CMD_AUX_ENABLE)) return -1; if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS)) return -1; /* * Disable the interface. */ i8042_ctr |= I8042_CTR_AUXDIS; i8042_ctr &= ~I8042_CTR_AUXINT; if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) return -1; return 0; } /* * i8042_port_register() marks the device as existing, * registers it, and reports to the user. */ static int __init i8042_port_register(struct i8042_values *values, struct serio *port) { values->exists = 1; serio_register_port(port); printk(KERN_INFO "serio: i8042 %s port at %#x,%#x irq %d\n", values->name, I8042_DATA_REG, I8042_COMMAND_REG, values->irq); return 0; } /* * Module init and cleanup functions. */ void __init i8042_setup(char *str, int *ints) { if (!strcmp(str, "i8042_reset=1")) i8042_reset = 1; if (!strcmp(str, "i8042_noaux=1")) i8042_noaux = 1; if (!strcmp(str, "i8042_unlock=1")) i8042_unlock = 1; if (!strcmp(str, "i8042_direct=1")) i8042_direct = 1; } /* * Reset the 8042 back to original mode. */ static int i8042_notify_sys(struct notifier_block *this, unsigned long code, void *unused) { if (code==SYS_DOWN || code==SYS_HALT) i8042_controller_cleanup(); return NOTIFY_DONE; } static struct notifier_block i8042_notifier= { i8042_notify_sys, NULL, 0 }; int __init i8042_init(void) { #ifdef I8042_DEBUG_IO i8042_start = jiffies; #endif if (i8042_controller_init()) return -ENODEV; i8042_port_register(&i8042_kbd_values, &i8042_kbd_port); if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values, &i8042_aux_port)) i8042_port_register(&i8042_aux_values, &i8042_aux_port); /* * On ix86 platforms touching the i8042 data register region can do really * bad things. Because of this the region is always reserved on ix86 boxes. */ #if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) request_region(I8042_DATA_REG, 16, "i8042"); #endif register_reboot_notifier(&i8042_notifier); return 0; } void __exit i8042_exit(void) { unregister_reboot_notifier(&i8042_notifier); if (i8042_kbd_values.exists) serio_unregister_port(&i8042_kbd_port); if (i8042_aux_values.exists) serio_unregister_port(&i8042_aux_port); i8042_controller_cleanup(); #if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) release_region(I8042_DATA_REG, 16); #endif } module_init(i8042_init); module_exit(i8042_exit); |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:43:08
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/serio In directory usw-pr-cvs1:/tmp/cvs-serv11486 Modified Files: Tag: 1.12 ct82c710.c Log Message: Moved. --- NEW FILE: ct82c710.c --- /* * $Id: ct82c710.c,v 1.12 2002/01/22 20:43:05 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik */ /* * 82C710 C&T mouse port chip 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/module.h> #include <linux/ioport.h> #include <linux/config.h> #include <linux/init.h> #include <linux/serio.h> MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>"); MODULE_DESCRIPTION("82C710 C&T mouse port chip driver"); MODULE_LICENSE("GPL"); static char ct82c710_name[] = "C&T 82c710 mouse port"; static char ct82c710_phys[16]; /* * ct82c710 interface */ #define CT82C710_DEV_IDLE 0x01 /* Device Idle */ #define CT82C710_RX_FULL 0x02 /* Device Char received */ #define CT82C710_TX_IDLE 0x04 /* Device XMIT Idle */ #define CT82C710_RESET 0x08 /* Device Reset */ #define CT82C710_INTS_ON 0x10 /* Device Interrupt On */ #define CT82C710_ERROR_FLAG 0x20 /* Device Error */ #define CT82C710_CLEAR 0x40 /* Device Clear */ #define CT82C710_ENABLE 0x80 /* Device Enable */ #define CT82C710_IRQ 12 static int ct82c710_data = 0; static int ct82c710_status = 0; static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs); /* * Wait for device to send output char and flush any input char. */ static int ct82c170_wait(void) { int timeout = 60000; while ((inb(ct82c710_status) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE)) != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) { if (inb_p(ct82c710_status) & CT82C710_RX_FULL) inb_p(ct82c710_data); udelay(1); timeout--; } return !timeout; } static void ct82c710_close(struct serio *serio) { if (ct82c170_wait()) printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); outb_p(inb_p(ct82c710_status) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), ct82c710_status); if (ct82c170_wait()) printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); free_irq(CT82C710_IRQ, NULL); } static int ct82c710_open(struct serio *serio) { unsigned char status; if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL)) return -1; status = inb_p(ct82c710_status); status |= (CT82C710_ENABLE | CT82C710_RESET); outb_p(status, ct82c710_status); status &= ~(CT82C710_RESET); outb_p(status, ct82c710_status); status |= CT82C710_INTS_ON; outb_p(status, ct82c710_status); /* Enable interrupts */ while (ct82c170_wait()) { printk(KERN_ERR "ct82c710: Device busy in open()\n"); status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON); outb_p(status, ct82c710_status); free_irq(CT82C710_IRQ, NULL); return -1; } return 0; } /* * Write to the 82C710 mouse device. */ static int ct82c710_write(struct serio *port, unsigned char c) { if (ct82c170_wait()) return -1; outb_p(c, ct82c710_data); return 0; } static struct serio ct82c710_port = { type: SERIO_8042, name: ct82c710_name, phys: ct82c710_phys, write: ct82c710_write, open: ct82c710_open, close: ct82c710_close, }; /* * Interrupt handler for the 82C710 mouse port. A character * is waiting in the 82C710. */ static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs) { if (ct82c710_port.dev) ct82c710_port.dev->interrupt(&ct82c710_port, inb(ct82c710_data), 0); } /* * See if we can find a 82C710 device. Read mouse address. */ static int __init ct82c710_probe(void) { outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */ outb_p(0xaa, 0x3fa); /* Inverse of 55 */ outb_p(0x36, 0x3fa); /* Address the chip */ outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */ outb_p(0x1b, 0x2fa); /* Inverse of e4 */ outb_p(0x0f, 0x390); /* Write index */ if (inb_p(0x391) != 0xe4) /* Config address found? */ return -1; /* No: no 82C710 here */ outb_p(0x0d, 0x390); /* Write index */ ct82c710_data = inb_p(0x391) << 2; /* Get mouse I/O address */ ct82c710_status = ct82c710_data + 1; outb_p(0x0f, 0x390); outb_p(0x0f, 0x391); /* Close config mode */ return 0; } int __init ct82c710_init(void) { if (ct82c710_probe()) return -ENODEV; if (request_region(ct82c710_data, 2, "ct82c710")) return -EBUSY; sprintf(ct82c710_phys, "isa%04x/serio0", ct82c710_data); serio_register_port(&ct82c710_port); printk(KERN_INFO "serio: C&T 82c710 mouse port at %#x irq %d\n", ct82c710_data, CT82C710_IRQ); return 0; } void __exit ct82c710_exit(void) { serio_unregister_port(&ct82c710_port); release_region(ct82c710_data, 2); } module_init(ct82c710_init); module_exit(ct82c710_exit); |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:41:48
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/gameport In directory usw-pr-cvs1:/tmp/cvs-serv10934 Modified Files: Tag: 1.3 vortex.c Log Message: Moved. --- NEW FILE: vortex.c --- /* * $Id: vortex.c,v 1.3 2002/01/22 20:41:45 vojtech 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_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(PCIGAME_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, 0x1100c }, { 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x2880c }, { 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: Vojtech P. <vo...@us...> - 2002-01-22 20:41:34
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/gameport In directory usw-pr-cvs1:/tmp/cvs-serv10822 Modified Files: Tag: 1.20 lightning.c Log Message: Moved. --- NEW FILE: lightning.c --- /* * $Id: lightning.c,v 1.20 2002/01/22 20:41:31 vojtech 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: Vojtech P. <vo...@us...> - 2002-01-22 20:41:16
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/gameport In directory usw-pr-cvs1:/tmp/cvs-serv10695 Modified Files: Tag: 1.18 gameport.c Log Message: Moved. --- NEW FILE: gameport.c --- /* * $Id: gameport.c,v 1.18 2002/01/22 20:41:14 vojtech 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: Vojtech P. <vo...@us...> - 2002-01-22 20:41:03
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/gameport In directory usw-pr-cvs1:/tmp/cvs-serv10535 Modified Files: Tag: 1 fm801-gp.c Log Message: Moved. Index: fm801-gp.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/input/gameport/fm801-gp.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- fm801-gp.c 2002/01/22 19:38:27 1.1 +++ fm801-gp.c 2002/01/22 20:41:00 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; } |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:40:49
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/gameport In directory usw-pr-cvs1:/tmp/cvs-serv10407 Modified Files: Tag: 1.8 emu10k1-gp.c Log Message: Moved. --- NEW FILE: emu10k1-gp.c --- /* * $Id: emu10k1-gp.c,v 1.8 2002/01/22 20:40:46 vojtech 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: Vojtech P. <vo...@us...> - 2002-01-22 20:38:00
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/keyboard In directory usw-pr-cvs1:/tmp/cvs-serv9146 Added Files: Tag: 1.2 maple_keyb.c Log Message: Moved. --- NEW FILE: maple_keyb.c --- /* * $Id: maple_keyb.c,v 1.2 2002/01/22 20:37:57 vojtech Exp $ * SEGA Dreamcast keyboard driver * Based on drivers/usb/usbkbd.c */ #include <linux/kernel.h> #include <linux/malloc.h> #include <linux/input.h> #include <linux/module.h> #include <linux/init.h> #include <linux/timer.h> #include <linux/maple.h> MODULE_AUTHOR("YAEGASHI Takeshi <t...@ke...>"); MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver"); static unsigned char dc_kbd_keycode[256] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113, 115,114, 0, 0, 0,124, 0,181,182,183,184,185,186,187,188,189, 190,191,192,193,194,195,196,197,198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, 150,158,159,128,136,177,178,176,142,152,173,140 }; struct dc_kbd { struct input_dev dev; unsigned char new[8]; unsigned char old[8]; int open; }; static void dc_scan_kbd(struct dc_kbd *kbd) { int i; struct input_dev *dev = &kbd->dev; for(i=0; i<8; i++) input_report_key(dev, dc_kbd_keycode[i+224], (kbd->new[0]>>i)&1); for(i=2; i<8; i++) { if(kbd->old[i]>3&&memscan(kbd->new+2, kbd->old[i], 6)==NULL) { if(dc_kbd_keycode[kbd->old[i]]) input_report_key(dev, dc_kbd_keycode[kbd->old[i]], 0); else printk("Unknown key (scancode %#x) released.", kbd->old[i]); } if(kbd->new[i]>3&&memscan(kbd->old+2, kbd->new[i], 6)!=NULL) { if(dc_kbd_keycode[kbd->new[i]]) input_report_key(dev, dc_kbd_keycode[kbd->new[i]], 1); else printk("Unknown key (scancode %#x) pressed.", kbd->new[i]); } } memcpy(kbd->old, kbd->new, 8); } static void dc_kbd_callback(struct mapleq *mq) { struct maple_device *mapledev = mq->dev; struct dc_kbd *kbd = mapledev->private_data; unsigned long *buf = mq->recvbuf; if (buf[1] == mapledev->function) { memcpy(kbd->new, buf+2, 8); dc_scan_kbd(kbd); } } static int dc_kbd_open(struct input_dev *dev) { struct dc_kbd *kbd = dev->private; kbd->open++; return 0; } static void dc_kbd_close(struct input_dev *dev) { struct dc_kbd *kbd = dev->private; kbd->open--; } static int dc_kbd_connect(struct maple_device *dev) { int i; unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); struct dc_kbd *kbd; if (!(kbd = kmalloc(sizeof(struct dc_kbd), GFP_KERNEL))) return -1; memset(kbd, 0, sizeof(struct dc_kbd)); dev->private_data = kbd; kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); for (i=0; i<255; i++) set_bit(dc_kbd_keycode[i], kbd->dev.keybit); clear_bit(0, kbd->dev.keybit); kbd->dev.private = kbd; kbd->dev.open = dc_kbd_open; kbd->dev.close = dc_kbd_close; kbd->dev.event = NULL; kbd->dev.name = dev->product_name; kbd->dev.idbus = BUS_MAPLE; input_register_device(&kbd->dev); maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD); printk(KERN_INFO "input%d: keyboard(0x%lx): %s\n", kbd->dev.number, data, kbd->dev.name); MOD_INC_USE_COUNT; return 0; } static void dc_kbd_disconnect(struct maple_device *dev) { struct dc_kbd *kbd = dev->private_data; input_unregister_device(&kbd->dev); kfree(kbd); MOD_DEC_USE_COUNT; } static struct maple_driver dc_kbd_driver = { function: MAPLE_FUNC_KEYBOARD, name: "Dreamcast keyboard", connect: dc_kbd_connect, disconnect: dc_kbd_disconnect, }; static int __init dc_kbd_init(void) { maple_register_driver(&dc_kbd_driver); return 0; } static void __exit dc_kbd_exit(void) { maple_unregister_driver(&dc_kbd_driver); } module_init(dc_kbd_init); module_exit(dc_kbd_exit); /* * Local variables: * c-basic-offset: 8 * End: */ |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:37:45
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/keyboard In directory usw-pr-cvs1:/tmp/cvs-serv9032 Added Files: Tag: 1.12 xtkbd.c Log Message: Moved. --- NEW FILE: xtkbd.c --- /* * $Id: xtkbd.c,v 1.12 2002/01/22 20:37:42 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik */ /* * XT keyboard 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/slab.h> #include <linux/module.h> #include <linux/input.h> #include <linux/init.h> #include <linux/serio.h> MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>"); MODULE_DESCRIPTION("XT keyboard driver"); MODULE_LICENSE("GPL"); #define XTKBD_EMUL0 0xe0 #define XTKBD_EMUL1 0xe1 #define XTKBD_KEY 0x7f #define XTKBD_RELEASE 0x80 static unsigned char xtkbd_keycode[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 0, 0, 0, 87, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 88, 0, 0, 0, 0,110,111,103,108,105, 106 }; static char *xtkbd_name = "XT Keyboard"; struct xtkbd { unsigned char keycode[256]; struct input_dev dev; struct serio *serio; char phys[32]; }; void xtkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { struct xtkbd *xtkbd = serio->private; switch (data) { case XTKBD_EMUL0: case XTKBD_EMUL1: return; default: if (xtkbd->keycode[data & XTKBD_KEY]) { input_report_key(&xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE)); } else { printk(KERN_WARNING "xtkbd.c: Unknown key (scancode %#x) %s.\n", data & XTKBD_KEY, data & XTKBD_RELEASE ? "released" : "pressed"); } } } void xtkbd_connect(struct serio *serio, struct serio_dev *dev) { struct xtkbd *xtkbd; int i; if ((serio->type & SERIO_TYPE) != SERIO_XT) return; if (!(xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL))) return; memset(xtkbd, 0, sizeof(struct xtkbd)); xtkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); xtkbd->serio = serio; xtkbd->dev.keycode = xtkbd->keycode; xtkbd->dev.private = xtkbd; serio->private = xtkbd; if (serio_open(serio, dev)) { kfree(xtkbd); return; } memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode)); for (i = 0; i < 255; i++) set_bit(xtkbd->keycode[i], xtkbd->dev.keybit); clear_bit(0, xtkbd->dev.keybit); sprintf(xtkbd->phys, "%s/input0", serio->phys); xtkbd->dev.name = xtkbd_name; xtkbd->dev.phys = xtkbd->phys; xtkbd->dev.idbus = BUS_XTKBD; xtkbd->dev.idvendor = 0x0001; xtkbd->dev.idproduct = 0x0001; xtkbd->dev.idversion = 0x0100; input_register_device(&xtkbd->dev); printk(KERN_INFO "input: %s on %s\n", xtkbd_name, serio->phys); } void xtkbd_disconnect(struct serio *serio) { struct xtkbd *xtkbd = serio->private; input_unregister_device(&xtkbd->dev); serio_close(serio); kfree(xtkbd); } struct serio_dev xtkbd_dev = { interrupt: xtkbd_interrupt, connect: xtkbd_connect, disconnect: xtkbd_disconnect }; int __init xtkbd_init(void) { serio_register_device(&xtkbd_dev); return 0; } void __exit xtkbd_exit(void) { serio_unregister_device(&xtkbd_dev); } module_init(xtkbd_init); module_exit(xtkbd_exit); |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:37:30
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/keyboard In directory usw-pr-cvs1:/tmp/cvs-serv8893 Added Files: Tag: 1.15 sunkbd.c Log Message: Moved. --- NEW FILE: sunkbd.c --- /* * $Id: sunkbd.c,v 1.15 2002/01/22 20:37:27 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik */ /* * Sun keyboard 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/slab.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/input.h> #include <linux/serio.h> MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>"); MODULE_DESCRIPTION("Sun keyboard driver"); MODULE_LICENSE("GPL"); static unsigned char sunkbd_keycode[128] = { 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64, 0, 65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, 14,110,113, 98, 55, 116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,111,127, 71, 72, 73, 74,134,135,107, 0, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 28, 96, 75, 76, 77, 82,136, 104,137, 69, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,101, 79, 80, 81, 0, 0, 0,138, 58,125, 57,126,109, 86, 78 }; #define SUNKBD_CMD_RESET 0x1 #define SUNKBD_CMD_BELLON 0x2 #define SUNKBD_CMD_BELLOFF 0x3 #define SUNKBD_CMD_CLICK 0xa #define SUNKBD_CMD_NOCLICK 0xb #define SUNKBD_CMD_SETLED 0xe #define SUNKBD_CMD_LAYOUT 0xf #define SUNKBD_RET_RESET 0xff #define SUNKBD_RET_ALLUP 0x7f #define SUNKBD_RET_LAYOUT 0xfe #define SUNKBD_LAYOUT_5_MASK 0x20 #define SUNKBD_RELEASE 0x80 #define SUNKBD_KEY 0x7f /* * Per-keyboard data. */ struct sunkbd { unsigned char keycode[128]; struct input_dev dev; struct serio *serio; struct tq_struct tq; char name[64]; char phys[32]; char type; char reset; char layout; }; /* * sunkbd_interrupt() is called by the low level driver when a character * is received. */ static void sunkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { struct sunkbd* sunkbd = serio->private; if (sunkbd->reset <= -1) { /* If cp[i] is 0xff, sunkbd->reset will stay -1. */ sunkbd->reset = data; /* The keyboard sends 0xff 0xff 0xID on powerup */ return; } if (sunkbd->layout == -1) { sunkbd->layout = data; return; } switch (data) { case SUNKBD_RET_RESET: queue_task(&sunkbd->tq, &tq_immediate); mark_bh(IMMEDIATE_BH); sunkbd->reset = -1; return; case SUNKBD_RET_LAYOUT: sunkbd->layout = -1; return; case SUNKBD_RET_ALLUP: /* All keys released */ return; default: if (sunkbd->keycode[data & SUNKBD_KEY]) { input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE)); } else { printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n", data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed"); } } } /* * sunkbd_event() handles events from the input module. */ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct sunkbd *sunkbd = dev->private; switch (type) { case EV_LED: sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); sunkbd->serio->write(sunkbd->serio, (!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led)); return 0; case EV_SND: switch (code) { case SND_CLICK: sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); return 0; case SND_BELL: sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); return 0; } break; } return -1; } /* * sunkbd_initialize() checks for a Sun keyboard attached, and determines * its type. */ static int sunkbd_initialize(struct sunkbd *sunkbd) { int t; t = 1000; sunkbd->reset = -2; sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET); while (sunkbd->reset < 0 && --t) mdelay(1); if (!t) return -1; sunkbd->type = sunkbd->reset; if (sunkbd->type == 4) { /* Type 4 keyboard */ t = 250; sunkbd->layout = -2; sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT); while (sunkbd->layout < 0 && --t) mdelay(1); if (!t) return -1; if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5; } return 0; } /* * sunkbd_reinit() sets leds and beeps to a state the computer remembers they * were in. */ static void sunkbd_reinit(void *data) { struct sunkbd *sunkbd = data; int t = 1000; while (sunkbd->reset < 0 && --t) mdelay(1); sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); sunkbd->serio->write(sunkbd->serio, (!!test_bit(LED_CAPSL, sunkbd->dev.led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev.led) << 2) | (!!test_bit(LED_COMPOSE, sunkbd->dev.led) << 1) | !!test_bit(LED_NUML, sunkbd->dev.led)); sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev.snd)); sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev.snd)); } /* * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures. */ static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) { struct sunkbd *sunkbd; int i; if ((serio->type & SERIO_TYPE) != SERIO_RS232) return; if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_SUNKBD) return; if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL))) return; memset(sunkbd, 0, sizeof(struct sunkbd)); sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP); sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML); sunkbd->dev.sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL); sunkbd->serio = serio; sunkbd->tq.routine = sunkbd_reinit; sunkbd->tq.data = sunkbd; sunkbd->dev.keycode = sunkbd->keycode; sunkbd->dev.event = sunkbd_event; sunkbd->dev.private = sunkbd; serio->private = sunkbd; if (serio_open(serio, dev)) { kfree(sunkbd); return; } if (sunkbd_initialize(sunkbd) < 0) { serio_close(serio); kfree(sunkbd); return; } sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type); memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode)); for (i = 0; i < 255; i++) set_bit(sunkbd->keycode[i], sunkbd->dev.keybit); clear_bit(0, sunkbd->dev.keybit); sprintf(sunkbd->name, "%s/input", serio->phys); sunkbd->dev.name = sunkbd->name; sunkbd->dev.phys = sunkbd->phys; sunkbd->dev.idbus = BUS_RS232; sunkbd->dev.idvendor = SERIO_SUNKBD; sunkbd->dev.idproduct = sunkbd->type; sunkbd->dev.idversion = 0x0100; input_register_device(&sunkbd->dev); printk(KERN_INFO "input: %s on %s\n", sunkbd->name, serio->phys); } /* * sunkbd_disconnect() unregisters and closes behind us. */ static void sunkbd_disconnect(struct serio *serio) { struct sunkbd *sunkbd = serio->private; input_unregister_device(&sunkbd->dev); serio_close(serio); kfree(sunkbd); } static struct serio_dev sunkbd_dev = { interrupt: sunkbd_interrupt, connect: sunkbd_connect, disconnect: sunkbd_disconnect }; /* * The functions for insering/removing us as a module. */ int __init sunkbd_init(void) { serio_register_device(&sunkbd_dev); return 0; } void __exit sunkbd_exit(void) { serio_unregister_device(&sunkbd_dev); } module_init(sunkbd_init); module_exit(sunkbd_exit); |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:37:18
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/keyboard In directory usw-pr-cvs1:/tmp/cvs-serv8793 Added Files: Tag: 1.30 atkbd.c Log Message: Moved. --- NEW FILE: atkbd.c --- /* * $Id: atkbd.c,v 1.30 2002/01/22 20:37:14 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik */ /* * 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/module.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/input.h> #include <linux/serio.h> MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>"); MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); MODULE_PARM(atkbd_set, "1i"); MODULE_LICENSE("GPL"); static int atkbd_set = 2; /* * Scancode to keycode tables. These are just the default setting, and * are loadable via an userland utility. */ static unsigned char atkbd_set2_keycode[512] = { 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85, 0, 56, 42, 0, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90, 0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0, 0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0, 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, 122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0, 85, 86, 90, 91, 92, 93, 14, 94, 95, 79, 0, 75, 71,121, 0,123, 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, 252, 0, 0, 65, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, 0, 0, 92, 90, 85, 0,137, 0, 0, 0, 0, 91, 89,144,115, 0, 136,100,255, 0, 97,149,164, 0,156, 0, 0,140,115, 0, 0,125, 0,150, 0,154,152,163,151,126,112,166, 0,140, 0,147, 0,127, 159,167,139,160,163, 0, 0,116,158, 0,150,165, 0, 0, 0,142, 157, 0,114,166,168, 0, 0, 0,155, 0, 98,113, 0,148, 0,138, 0, 0, 0, 0, 0, 0,153,140, 0, 0, 96, 0, 0, 0,143, 0, 133, 0,116, 0,143, 0,174,133, 0,107, 0,105,102, 0, 0,112, 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119 }; static unsigned char atkbd_set3_keycode[512] = { 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60, 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62, 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64, 136, 49, 48, 35, 34, 21, 7, 65,137,100, 50, 36, 22, 8, 9, 66, 125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68, 113,114, 40, 84, 26, 13, 87, 99,100, 54, 28, 27, 43, 84, 88, 70, 108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104, 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55, 85, 89, 90, 91, 92, 74, 0, 0, 0, 0, 0, 0,125,126,127,112, 0, 0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168, 148,149,147,140, 0, 0, 0, 0, 0, 0,251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255 }; #define ATKBD_CMD_SETLEDS 0x10ed #define ATKBD_CMD_GSCANSET 0x11f0 #define ATKBD_CMD_SSCANSET 0x10f0 #define ATKBD_CMD_GETID 0x02f2 #define ATKBD_CMD_ENABLE 0x00f4 #define ATKBD_CMD_RESET_DIS 0x00f5 #define ATKBD_CMD_SETALL_MB 0x00f8 #define ATKBD_CMD_EX_ENABLE 0x10ea #define ATKBD_CMD_EX_SETLEDS 0x20eb #define ATKBD_RET_ACK 0xfa #define ATKBD_RET_NAK 0xfe #define ATKBD_KEY_UNKNOWN 0 #define ATKBD_KEY_BAT 251 #define ATKBD_KEY_EMUL0 252 #define ATKBD_KEY_EMUL1 253 #define ATKBD_KEY_RELEASE 254 #define ATKBD_KEY_NULL 255 /* * The atkbd control structure */ struct atkbd { unsigned char keycode[512]; struct input_dev dev; struct serio *serio; char name[64]; char phys[32]; struct tq_struct tq; unsigned char cmdbuf[4]; unsigned char cmdcnt; unsigned char set; char release; char ack; char emul; char error; unsigned short id; }; /* * atkbd_interrupt(). Here takes place processing of data received from * the keyboard into events. */ static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { struct atkbd *atkbd = serio->private; int code = data; #ifdef ATKBD_DEBUG printk(KERN_DEBUG "atkbd.c: Received %02x\n", data); #endif switch (code) { case ATKBD_RET_ACK: atkbd->ack = 1; return; case ATKBD_RET_NAK: atkbd->ack = -1; return; } if (atkbd->cmdcnt) { atkbd->cmdbuf[--atkbd->cmdcnt] = code; return; } switch (atkbd->keycode[code]) { case ATKBD_KEY_BAT: queue_task(&atkbd->tq, &tq_immediate); mark_bh(IMMEDIATE_BH); return; case ATKBD_KEY_EMUL0: atkbd->emul = 1; return; case ATKBD_KEY_EMUL1: atkbd->emul = 2; return; case ATKBD_KEY_RELEASE: atkbd->release = 1; return; } if (atkbd->emul) { if (--atkbd->emul) return; code |= 0x100; } switch (atkbd->keycode[code]) { case ATKBD_KEY_NULL: break; case ATKBD_KEY_UNKNOWN: printk(KERN_WARNING "atkbd.c: Unknown key (set %d, scancode %#x, on %s) %s.\n", atkbd->set, code, serio->phys, atkbd->release ? "released" : "pressed"); break; default: input_report_key(&atkbd->dev, atkbd->keycode[code], !atkbd->release); } atkbd->release = 0; } /* * atkbd_sendbyte() sends a byte to the keyboard, and waits for * acknowledge. It doesn't handle resends according to the keyboard * protocol specs, because if these are needed, the keyboard needs * replacement anyway, and they only make a mess in the protocol. */ static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) { int timeout = 1000; /* 10 msec */ atkbd->ack = 0; #ifdef ATKBD_DEBUG printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte); #endif serio_write(atkbd->serio, byte); while (!atkbd->ack && timeout--) udelay(10); return -(atkbd->ack <= 0); } /* * atkbd_command() sends a command, and its parameters to the keyboard, * then waits for the response and puts it in the param array. */ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) { int timeout = 10000; /* 100 msec */ int send = (command >> 12) & 0xf; int receive = (command >> 8) & 0xf; int i; atkbd->cmdcnt = receive; if (command & 0xff) if (atkbd_sendbyte(atkbd, command & 0xff)) return (atkbd->cmdcnt = 0) - 1; for (i = 0; i < send; i++) if (atkbd_sendbyte(atkbd, param[i])) return (atkbd->cmdcnt = 0) - 1; while (atkbd->cmdcnt && timeout--) udelay(10); for (i = 0; i < receive; i++) param[i] = atkbd->cmdbuf[(receive - 1) - i]; if (atkbd->cmdcnt) return (atkbd->cmdcnt = 0) - 1; return 0; } /* * Event callback from the input module. Events that change the state of * the hardware are processed here. */ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct atkbd *atkbd = dev->private; char param[2]; switch (type) { case EV_LED: *param = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) | (test_bit(LED_NUML, dev->led) ? 2 : 0) | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS); if (atkbd->set == 4) { param[0] = 0; param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); atkbd_command(atkbd, param, ATKBD_CMD_EX_SETLEDS); } return 0; } return -1; } /* * atkbd_set_3 checks if a keyboard has a working Set 3 support, and * sets it into that. Unfortunately there are keyboards that can be switched * to Set 3, but don't work well in that (BTC Multimedia ...) */ static int atkbd_set_3(struct atkbd *atkbd) { unsigned char param; /* * For known special keyboards we can go ahead and set the correct set. */ if (atkbd->id == 0xaca1) { param = 3; atkbd_command(atkbd, ¶m, ATKBD_CMD_SSCANSET); return 3; } /* * We check for the extra keys on an some keyboards that need extra * command to get enabled. This shouldn't harm any keyboards not * knowing the command. */ param = 0x71; if (!atkbd_command(atkbd, ¶m, ATKBD_CMD_EX_ENABLE)) return 4; /* * Try to set the set we want. */ param = atkbd_set; if (atkbd_command(atkbd, ¶m, ATKBD_CMD_SSCANSET)) return 2; /* * Read set number. Beware here. Some keyboards always send '2' * or some other number regardless into what mode they have been * attempted to be set. Other keyboards treat the '0' command as * 'set to set 0', and not 'report current set' as they should. * In that case we time out, and return 2. */ param = 0; if (atkbd_command(atkbd, ¶m, ATKBD_CMD_GSCANSET)) return 2; /* * Here we return the set number the keyboard reports about * itself. */ return (param == 3) ? 3 : 2; } /* * atkbd_probe() probes for an AT keyboard on a serio port. */ static int atkbd_probe(struct atkbd *atkbd) { unsigned char param[2]; /* * Full reset with selftest can on some keyboards be annoyingly slow, * so we just do a reset-and-disable on the keyboard, which * is considerably faster, but doesn't have to reset everything. */ if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_DIS)) return -1; /* * Next, we check if it's a keyboard. It should send 0xab83 * (0xab84 on IBM ThinkPad, and 0xaca1 on a NCD Sun layout keyboard, * 0xab02 on unxlated i8042 and 0xab03 on unxlated ThinkPad, 0xab7f * on Fujitsu Lifebook). * If it's a mouse, it'll only send 0x00 (0x03 if it's MS mouse), * and we'll time out here, and report an error. */ param[0] = param[1] = 0; if (atkbd_command(atkbd, param, ATKBD_CMD_GETID)) return -1; atkbd->id = (param[0] << 8) | param[1]; if (atkbd->id != 0xab83 && atkbd->id != 0xab84 && atkbd->id != 0xaca1 && atkbd->id != 0xab7f && atkbd->id != 0xab02 && atkbd->id != 0xab03) printk(KERN_WARNING "atkbd.c: Unusual keyboard ID: %#x on %s\n", atkbd->id, atkbd->serio->phys); return 0; } /* * atkbd_initialize() sets the keyboard into a sane state. */ static void atkbd_initialize(struct atkbd *atkbd) { unsigned char param; /* * Disable autorepeat. We don't need it, as we do it in software anyway, * because that way can get faster repeat, and have less system load * (less accesses to the slow ISA hardware). If this fails, we don't care, * and will just ignore the repeated keys. */ atkbd_command(atkbd, NULL, ATKBD_CMD_SETALL_MB); /* * We also shut off all the leds. The console code will turn them back on, * if needed. */ param = 0; atkbd_command(atkbd, ¶m, ATKBD_CMD_SETLEDS); /* * Last, we enable the keyboard so that we get keypresses from it. */ if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE)) printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n", atkbd->serio->phys); } /* * atkbd_disconnect() cleans up behind us ... */ static void atkbd_disconnect(struct serio *serio) { struct atkbd *atkbd = serio->private; input_unregister_device(&atkbd->dev); serio_close(serio); kfree(atkbd); } /* * atkbd_powerup() is called when the keyboard sends the 0xaa character, * meaning that it was disconnected and reconnected. We close the port * in that case and let the upper layer find an appropriate driver for * the device that was connected. It may be a mouse, or a keyboard, we * don't know yet. */ static void atkbd_powerup(void *data) { struct atkbd *atkbd = data; mdelay(40); /* FIXME!!! Wait some nicer way */ serio_rescan(atkbd->serio); } /* * atkbd_connect() is called when the serio module finds and interface * that isn't handled yet by an appropriate device driver. We check if * there is an AT keyboard out there and if yes, we register ourselves * to the input module. */ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) { struct atkbd *atkbd; int i; if ((serio->type & SERIO_TYPE) != SERIO_8042) return; if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL))) return; memset(atkbd, 0, sizeof(struct atkbd)); atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); atkbd->serio = serio; atkbd->dev.keycode = atkbd->keycode; atkbd->dev.event = atkbd_event; atkbd->dev.private = atkbd; atkbd->tq.routine = atkbd_powerup; atkbd->tq.data = atkbd; serio->private = atkbd; if (serio_open(serio, dev)) { kfree(atkbd); return; } if (atkbd_probe(atkbd)) { serio_close(serio); kfree(atkbd); return; } atkbd->set = atkbd_set_3(atkbd); if (atkbd->set == 4) { atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE); sprintf(atkbd->name, "AT Set 2 Extended keyboard\n"); } else sprintf(atkbd->name, "AT Set %d keyboard", atkbd->set); sprintf(atkbd->phys, "%s/input0", serio->phys); if (atkbd->set == 3) memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); else memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); atkbd->dev.name = atkbd->name; atkbd->dev.phys = atkbd->phys; atkbd->dev.idbus = BUS_I8042; atkbd->dev.idvendor = 0x0001; atkbd->dev.idproduct = atkbd->set; atkbd->dev.idversion = atkbd->id; for (i = 0; i < 512; i++) if (atkbd->keycode[i] && atkbd->keycode[i] <= 250) set_bit(atkbd->keycode[i], atkbd->dev.keybit); input_register_device(&atkbd->dev); printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); atkbd_initialize(atkbd); } static struct serio_dev atkbd_dev = { interrupt: atkbd_interrupt, connect: atkbd_connect, disconnect: atkbd_disconnect }; /* * Module init and exit. */ void __init atkbd_setup(char *str, int *ints) { if (!ints[0]) atkbd_set = ints[1]; } int __init atkbd_init(void) { serio_register_device(&atkbd_dev); return 0; } void __exit atkbd_exit(void) { serio_unregister_device(&atkbd_dev); } module_init(atkbd_init); module_exit(atkbd_exit); |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:34:36
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick/iforce In directory usw-pr-cvs1:/tmp/cvs-serv7694 Added Files: Tag: 1.5 iforce.h Log Message: Moved. --- NEW FILE: iforce.h --- /* * $Id: iforce.h,v 1.5 2002/01/22 20:34:33 vojtech Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik <vo...@uc...> * Copyright (c) 2001 Johann Deneux <de...@if...> * * USB/RS232 I-Force joysticks and wheels. */ /* * 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/input.h> #include <linux/module.h> #include <linux/init.h> #include <linux/spinlock.h> #include <linux/usb.h> #include <linux/serio.h> #include <linux/config.h> #include <linux/circ_buf.h> #include <asm/semaphore.h> /* FF: This module provides arbitrary resource management routines. * I use it to manage the device's memory. * Despite the name of this module, I am *not* going to access the ioports. */ #include <linux/ioport.h> #define IFORCE_MAX_LENGTH 16 #if defined(CONFIG_INPUT_IFORCE_232) || defined(CONFIG_INPUT_IFORCE_232_MODULE) #define IFORCE_232 1 #endif #if defined(CONFIG_INPUT_IFORCE_USB) || defined(CONFIG_INPUT_IFORCE_USB_MODULE) #define IFORCE_USB 2 #endif #define FALSE 0 #define TRUE 1 #define FF_EFFECTS_MAX 32 /* Each force feedback effect is made of one core effect, which can be * associated to at most to effect modifiers */ #define FF_MOD1_IS_USED 0 #define FF_MOD2_IS_USED 1 #define FF_CORE_IS_USED 2 #define FF_CORE_IS_PLAYED 3 /* Effect is actually being played */ #define FF_CORE_SHOULD_PLAY 4 /* User wants the effect to be played */ #define FF_CORE_UPDATE 5 /* Effect is being updated */ #define FF_MODCORE_MAX 5 #define CHECK_OWNERSHIP(i, iforce) \ ((i) < FF_EFFECTS_MAX && i >= 0 && \ test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \ (current->pid == 0 || \ (iforce)->core_effects[(i)].owner == current->pid)) struct iforce_core_effect { /* Information about where modifiers are stored in the device's memory */ struct resource mod1_chunk; struct resource mod2_chunk; unsigned long flags[NBITS(FF_MODCORE_MAX)]; pid_t owner; /* Used to keep track of parameters of an effect. They are needed * to know what parts of an effect changed in an update operation. * We try to send only parameter packets if possible, as sending * effect parameter requires the effect to be stoped and restarted */ struct ff_effect effect; }; #define FF_CMD_EFFECT 0x010e #define FF_CMD_SHAPE 0x0208 #define FF_CMD_MAGNITUDE 0x0303 #define FF_CMD_PERIOD 0x0407 #define FF_CMD_INTERACT 0x050a #define FF_CMD_AUTOCENTER 0x4002 #define FF_CMD_PLAY 0x4103 #define FF_CMD_ENABLE 0x4201 #define FF_CMD_GAIN 0x4301 #define FF_CMD_QUERY 0xff01 /* Buffer for async write */ #define XMIT_SIZE 256 #define XMIT_INC(var, n) (var)+=n; (var)&= XMIT_SIZE -1 /* iforce::xmit_flags */ #define IFORCE_XMIT_RUNNING 0 #define IFORCE_XMIT_AGAIN 1 struct iforce_device { u16 idvendor; u16 idproduct; char *name; signed short *btn; signed short *abs; signed short *ff; }; struct iforce { struct input_dev dev; /* Input device interface */ struct iforce_device *type; char name[64]; char phys[64]; int open; int bus; unsigned char data[IFORCE_MAX_LENGTH]; unsigned char edata[IFORCE_MAX_LENGTH]; u16 ecmd; u16 expect_packet; #ifdef IFORCE_232 struct serio *serio; /* RS232 transfer */ int idx, pkt, len, id; unsigned char csum; #endif #ifdef IFORCE_USB struct usb_device *usbdev; /* USB transfer */ struct urb irq, out, ctrl; struct usb_ctrlrequest dr; #endif spinlock_t xmit_lock; /* Buffer used for asynchronous sending of bytes to the device */ struct circ_buf xmit; unsigned char xmit_data[XMIT_SIZE]; long xmit_flags[1]; /* Force Feedback */ wait_queue_head_t wait; struct resource device_memory; struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; struct semaphore mem_mutex; }; /* Get hi and low bytes of a 16-bits int */ #define HI(a) ((unsigned char)((a) >> 8)) #define LO(a) ((unsigned char)((a) & 0xff)) /* For many parameters, it seems that 0x80 is a special value that should * be avoided. Instead, we replace this value by 0x7f */ #define HIFIX80(a) ((unsigned char)(((a)<0? (a)+255 : (a))>>8)) /* Encode a time value */ #define TIME_SCALE(a) ((a) == 0xffff ? 0xffff : (a) * 1000 / 256) /* Public functions */ /* iforce-serio.c */ void iforce_serial_xmit(struct iforce *iforce); /* iforce-usb.c */ void iforce_usb_xmit(struct iforce *iforce); /* iforce-main.c */ int iforce_init_device(struct iforce *iforce); /* iforce-packets.c */ int iforce_control_playback(struct iforce*, u16 id, unsigned int); void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data); int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data); void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ; int iforce_get_id_packet(struct iforce *iforce, char *packet); /* iforce-ff.c */ int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update); int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); int iforce_upload_interactive(struct iforce*, struct ff_effect*, int is_update); /* Public variables */ extern struct serio_dev iforce_serio_dev; extern struct usb_driver iforce_usb_driver; |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:34:23
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick/iforce In directory usw-pr-cvs1:/tmp/cvs-serv7598 Added Files: Tag: 1.5 iforce-usb.c Log Message: Moved. --- NEW FILE: iforce-usb.c --- /* * $Id: iforce-usb.c,v 1.5 2002/01/22 20:34:21 vojtech Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik <vo...@uc...> * Copyright (c) 2001 Johann Deneux <de...@if...> * * USB/RS232 I-Force joysticks and wheels. */ /* * 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 "iforce.h" void iforce_usb_xmit(struct iforce *iforce) { int n, c; unsigned long flags; spin_lock_irqsave(&iforce->xmit_lock, flags); if (iforce->xmit.head == iforce->xmit.tail) { spin_unlock_irqrestore(&iforce->xmit_lock, flags); return; } ((char *)iforce->out.transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); n = iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); iforce->out.transfer_buffer_length = n + 2; iforce->out.dev = iforce->usbdev; /* Copy rest of data then */ c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE); if (n < c) c=n; memcpy(iforce->out.transfer_buffer + 1, &iforce->xmit.buf[iforce->xmit.tail], c); if (n != c) { memcpy(iforce->out.transfer_buffer + 1 + c, &iforce->xmit.buf[0], n-c); } XMIT_INC(iforce->xmit.tail, n); if ( (n=usb_submit_urb(&iforce->out)) ) { printk(KERN_WARNING "iforce.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n); } spin_unlock_irqrestore(&iforce->xmit_lock, flags); } static void iforce_usb_irq(struct urb *urb) { struct iforce *iforce = urb->context; if (urb->status) return; iforce_process_packet(iforce, (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1); } static void iforce_usb_out(struct urb *urb) { struct iforce *iforce = urb->context; if (urb->status) return; iforce_usb_xmit(iforce); if (waitqueue_active(&iforce->wait)) wake_up(&iforce->wait); } static void iforce_usb_ctrl(struct urb *urb) { struct iforce *iforce = urb->context; if (urb->status) return; iforce->ecmd = 0xff00 | urb->actual_length; if (waitqueue_active(&iforce->wait)) wake_up(&iforce->wait); } static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) { struct usb_endpoint_descriptor *epirq, *epout; struct iforce *iforce; epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1; if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL; memset(iforce, 0, sizeof(struct iforce)); iforce->bus = IFORCE_USB; iforce->usbdev = dev; iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; iforce->dr.wIndex = 0; iforce->dr.wLength = 16; FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); FILL_BULK_URB(&iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress), iforce + 1, 32, iforce_usb_out, iforce); FILL_CONTROL_URB(&iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), (void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce); if (iforce_init_device(iforce)) { kfree(iforce); return NULL; } return iforce; } static void iforce_usb_disconnect(struct usb_device *dev, void *ptr) { struct iforce *iforce = ptr; usb_unlink_urb(&iforce->irq); input_unregister_device(&iforce->dev); kfree(iforce); } static struct usb_device_id iforce_usb_ids [] = { { USB_DEVICE(0x044f, 0xa01c) }, /* Thrustmaster Motor Sport GT */ { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */ { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */ { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */ { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */ { USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */ { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ { USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, iforce_usb_ids); struct usb_driver iforce_usb_driver = { name: "iforce", probe: iforce_usb_probe, disconnect: iforce_usb_disconnect, id_table: iforce_usb_ids, }; |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:34:10
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick/iforce In directory usw-pr-cvs1:/tmp/cvs-serv7518 Added Files: Tag: 1.3 iforce-serio.c Log Message: Moved. --- NEW FILE: iforce-serio.c --- /* * $Id: iforce-serio.c,v 1.3 2002/01/22 20:34:07 vojtech Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik <vo...@uc...> * Copyright (c) 2001 Johann Deneux <de...@if...> * * USB/RS232 I-Force joysticks and wheels. */ /* * 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 "iforce.h" void iforce_serial_xmit(struct iforce *iforce) { unsigned char cs; int i; unsigned long flags; if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags); return; } spin_lock_irqsave(&iforce->xmit_lock, flags); again: if (iforce->xmit.head == iforce->xmit.tail) { clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); spin_unlock_irqrestore(&iforce->xmit_lock, flags); return; } cs = 0x2b; serio_write(iforce->serio, 0x2b); serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); cs ^= iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); cs ^= iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); } serio_write(iforce->serio, cs); if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) goto again; clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); spin_unlock_irqrestore(&iforce->xmit_lock, flags); } static void iforce_serio_write_wakeup(struct serio *serio) { iforce_serial_xmit((struct iforce *)serio->private); } static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags) { struct iforce* iforce = serio->private; if (!iforce->pkt) { if (data != 0x2b) { return; } iforce->pkt = 1; return; } if (!iforce->id) { if (data > 3 && data != 0xff) { iforce->pkt = 0; return; } iforce->id = data; return; } if (!iforce->len) { if (data > IFORCE_MAX_LENGTH) { iforce->pkt = 0; iforce->id = 0; return; } iforce->len = data; return; } if (iforce->idx < iforce->len) { iforce->csum += iforce->data[iforce->idx++] = data; return; } if (iforce->idx == iforce->len) { iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); iforce->pkt = 0; iforce->id = 0; iforce->len = 0; iforce->idx = 0; iforce->csum = 0; } } static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) { struct iforce *iforce; if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) return; if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return; memset(iforce, 0, sizeof(struct iforce)); iforce->bus = IFORCE_232; iforce->serio = serio; serio->private = iforce; if (serio_open(serio, dev)) { kfree(iforce); return; } if (iforce_init_device(iforce)) { serio_close(serio); kfree(iforce); return; } } static void iforce_serio_disconnect(struct serio *serio) { struct iforce* iforce = serio->private; input_unregister_device(&iforce->dev); serio_close(serio); kfree(iforce); } struct serio_dev iforce_serio_dev = { write_wakeup: iforce_serio_write_wakeup, interrupt: iforce_serio_irq, connect: iforce_serio_connect, disconnect: iforce_serio_disconnect, }; |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:33:56
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick/iforce In directory usw-pr-cvs1:/tmp/cvs-serv7395 Added Files: Tag: 1.6 iforce-packets.c Log Message: Moved. --- NEW FILE: iforce-packets.c --- /* * $Id: iforce-packets.c,v 1.6 2002/01/22 20:33:53 vojtech Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik <vo...@uc...> * Copyright (c) 2001 Johann Deneux <de...@if...> * * USB/RS232 I-Force joysticks and wheels. */ /* * 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 "iforce.h" static struct { __s32 x; __s32 y; } iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) { int i; printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd); for (i = 0; i < LO(cmd); i++) printk("%02x ", data[i]); printk(")\n"); } /* * Send a packet of bytes to the device */ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) { /* Copy data to buffer */ int n = LO(cmd); int c; int empty; int head, tail; unsigned long flags; /* * Update head and tail of xmit buffer */ spin_lock_irqsave(&iforce->xmit_lock, flags); head = iforce->xmit.head; tail = iforce->xmit.tail; if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) { printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n"); spin_unlock_irqrestore(&iforce->xmit_lock, flags); return -1; } empty = head == tail; XMIT_INC(iforce->xmit.head, n+2); /* * Store packet in xmit buffer */ iforce->xmit.buf[head] = HI(cmd); XMIT_INC(head, 1); iforce->xmit.buf[head] = LO(cmd); XMIT_INC(head, 1); c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE); if (n < c) c=n; memcpy(&iforce->xmit.buf[head], data, c); if (n != c) { memcpy(&iforce->xmit.buf[0], data + c, n - c); } XMIT_INC(head, n); spin_unlock_irqrestore(&iforce->xmit_lock, flags); /* * If necessary, start the transmission */ switch (iforce->bus) { #ifdef IFORCE_232 case IFORCE_232: if (empty) iforce_serial_xmit(iforce); break; #endif #ifdef IFORCE_USB case IFORCE_USB: if (empty & !iforce->out.status) { iforce_usb_xmit(iforce); } break; #endif } return 0; } /* Start or stop an effect */ int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value) { unsigned char data[3]; printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value); data[0] = LO(id); data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0; data[2] = LO(value); return iforce_send_packet(iforce, FF_CMD_PLAY, data); } /* Mark an effect that was being updated as ready. That means it can be updated * again */ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) { int i; for (i=0; i<iforce->dev.ff_effects_max; ++i) { if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && (iforce->core_effects[i].mod1_chunk.start == addr || iforce->core_effects[i].mod2_chunk.start == addr)) { clear_bit(FF_CORE_UPDATE, iforce->core_effects[i].flags); return 0; } } printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr); return -1; } void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) { struct input_dev *dev = &iforce->dev; int i; static int being_used = 0; if (being_used) printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used); being_used++; #ifdef IFORCE_232 if (HI(iforce->expect_packet) == HI(cmd)) { iforce->expect_packet = 0; iforce->ecmd = cmd; memcpy(iforce->edata, data, IFORCE_MAX_LENGTH); if (waitqueue_active(&iforce->wait)) wake_up(&iforce->wait); } #endif if (!iforce->type) { being_used--; return; } switch (HI(cmd)) { case 0x01: /* joystick position data */ case 0x03: /* wheel position data */ if (HI(cmd) == 1) { input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); } else { input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); input_report_abs(dev, ABS_GAS, 255 - data[2]); input_report_abs(dev, ABS_BRAKE, 255 - data[3]); } input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); for (i = 0; iforce->type->btn[i] >= 0; i++) input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); break; case 0x02: /* status report */ input_report_key(dev, BTN_DEAD, data[0] & 0x02); /* Check if an effect was just started or stopped */ i = data[1] & 0x7f; if (data[1] & 0x80) { if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { /* Report play event */ input_report_ff_status(dev, i, FF_STATUS_PLAYING); } } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { /* Report stop event */ input_report_ff_status(dev, i, FF_STATUS_STOPPED); } if (LO(cmd) > 3) { int j; for (j=3; j<LO(cmd); j+=2) { mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); } } break; } being_used--; } int iforce_get_id_packet(struct iforce *iforce, char *packet) { DECLARE_WAITQUEUE(wait, current); int timeout = HZ; /* 1 second */ switch (iforce->bus) { #ifdef IFORCE_USB case IFORCE_USB: iforce->dr.bRequest = packet[0]; iforce->ctrl.dev = iforce->usbdev; set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&iforce->wait, &wait); if (usb_submit_urb(&iforce->ctrl)) { set_current_state(TASK_RUNNING); remove_wait_queue(&iforce->wait, &wait); return -1; } while (timeout && iforce->ctrl.status == -EINPROGRESS) timeout = schedule_timeout(timeout); set_current_state(TASK_RUNNING); remove_wait_queue(&iforce->wait, &wait); if (!timeout) { usb_unlink_urb(&iforce->ctrl); return -1; } break; #endif #ifdef IFORCE_232 case IFORCE_232: iforce->expect_packet = FF_CMD_QUERY; iforce_send_packet(iforce, FF_CMD_QUERY, packet); set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&iforce->wait, &wait); while (timeout && iforce->expect_packet) timeout = schedule_timeout(timeout); set_current_state(TASK_RUNNING); remove_wait_queue(&iforce->wait, &wait); if (!timeout) { iforce->expect_packet = 0; return -1; } break; #endif } return -(iforce->edata[0] != packet[0]); } |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:33:40
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick/iforce In directory usw-pr-cvs1:/tmp/cvs-serv7301 Added Files: Tag: 1.6 iforce-main.c Log Message: Moved. --- NEW FILE: iforce-main.c --- /* * $Id: iforce-main.c,v 1.6 2002/01/22 20:33:38 vojtech Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik <vo...@uc...> * Copyright (c) 2001 Johann Deneux <de...@if...> * * USB/RS232 I-Force joysticks and wheels. */ /* * 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 "iforce.h" #include "usbpath.h" MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>, Johann Deneux <de...@if...>"); MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); MODULE_LICENSE("GPL"); static signed short btn_joystick[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 }; static signed short btn_wheel[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; static signed short btn_avb_tw[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 }; static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; static signed short abs_joystick2[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_HAT0X, ABS_HAT0Y, -1 }; static signed short abs_wheel[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 }; static signed short ff_iforce[] = { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION, FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, FF_AUTOCENTER, -1 }; static struct iforce_device iforce_device[] = { { 0x044f, 0xa01c, "Thrustmaster Motor Sport GT", btn_wheel, abs_wheel, ff_iforce }, { 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce }, { 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce }, { 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_joystick, abs_joystick2, ff_iforce }, { 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_wheel, abs_wheel, ff_iforce }, { 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_avb_tw, abs_wheel, ff_iforce }, { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } }; static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct iforce* iforce = (struct iforce*)(dev->private); unsigned char data[3]; printk(KERN_DEBUG "iforce.c: input_event(type = %d, code = %d, value = %d)\n", type, code, value); if (type != EV_FF) return -1; switch (code) { case FF_GAIN: data[0] = value >> 9; iforce_send_packet(iforce, FF_CMD_GAIN, data); return 0; case FF_AUTOCENTER: data[0] = 0x03; data[1] = value >> 9; iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); data[0] = 0x04; data[1] = 0x01; iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); return 0; default: /* Play or stop an effect */ if (!CHECK_OWNERSHIP(code, iforce)) { return -1; } if (value > 0) { set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); } else { clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); } iforce_control_playback(iforce, code, value); return 0; } return -1; } /* * Function called when an ioctl is performed on the event dev entry. * It uploads an effect to the device */ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) { struct iforce* iforce = (struct iforce*)(dev->private); int id; int ret; int is_update; /* * If we want to create a new effect, get a free id */ if (effect->id == -1) { for (id=0; id < FF_EFFECTS_MAX; ++id) if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break; if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max) return -ENOMEM; effect->id = id; iforce->core_effects[id].owner = current->pid; iforce->core_effects[id].flags[0] = (1<<FF_CORE_IS_USED); /* Only IS_USED bit must be set */ is_update = FALSE; } else { /* We want to update an effect */ if (!CHECK_OWNERSHIP(effect->id, iforce)) return -EACCES; /* Parameter type cannot be updated */ if (effect->type != iforce->core_effects[effect->id].effect.type) return -EINVAL; /* Check the effect is not already being updated */ if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) { return -EAGAIN; } is_update = TRUE; } /* * Upload the effect */ switch (effect->type) { case FF_PERIODIC: ret = iforce_upload_periodic(iforce, effect, is_update); break; case FF_CONSTANT: ret = iforce_upload_constant(iforce, effect, is_update); break; case FF_SPRING: case FF_FRICTION: ret = iforce_upload_interactive(iforce, effect, is_update); break; default: return -EINVAL; } if (ret == 0) { /* A packet was sent, forbid new updates until we are notified * that the packet was updated */ set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags); } iforce->core_effects[effect->id].effect = *effect; return ret; } /* * Erases an effect: it frees the effect id and mark as unused the memory * allocated for the parameters */ static int iforce_erase_effect(struct input_dev *dev, int effect_id) { struct iforce* iforce = (struct iforce*)(dev->private); int err = 0; struct iforce_core_effect* core_effect; /* Check who is trying to erase this effect */ if (iforce->core_effects[effect_id].owner != current->pid) { printk(KERN_WARNING "iforce.c: %d tried to erase an effect belonging to %d\n", current->pid, iforce->core_effects[effect_id].owner); return -EACCES; } if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) return -EINVAL; core_effect = iforce->core_effects + effect_id; if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk)); if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk)); /*TODO: remember to change that if more FF_MOD* bits are added */ core_effect->flags[0] = 0; return err; } static int iforce_open(struct input_dev *dev) { struct iforce *iforce = dev->private; switch (iforce->bus) { #ifdef IFORCE_USB case IFORCE_USB: if (iforce->open++) break; iforce->irq.dev = iforce->usbdev; if (usb_submit_urb(&iforce->irq)) return -EIO; break; #endif } /* Enable force feedback */ iforce_send_packet(iforce, FF_CMD_ENABLE, "\004"); return 0; } static int iforce_flush(struct input_dev *dev, struct file *file) { struct iforce *iforce = dev->private; int i; /* Erase all effects this process owns */ for (i=0; i<dev->ff_effects_max; ++i) { if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && current->pid == iforce->core_effects[i].owner) { /* Stop effect */ input_report_ff(dev, i, 0); /* Free ressources assigned to effect */ if (iforce_erase_effect(dev, i)) { printk(KERN_WARNING "iforce_flush: (%s) erase effect %d failed\n", dev->phys, i); } } } return 0; } static void iforce_close(struct input_dev *dev) { struct iforce *iforce = dev->private; printk(KERN_DEBUG "iforce.c: in iforce_close\n"); /* Disable force feedback playback */ iforce_send_packet(iforce, FF_CMD_ENABLE, "\001"); switch (iforce->bus) { #ifdef IFORCE_USB case IFORCE_USB: if (!--iforce->open) usb_unlink_urb(&iforce->irq); break; #endif } } int iforce_init_device(struct iforce *iforce) { unsigned char c[] = "CEOV"; char path[64]; int i; init_waitqueue_head(&iforce->wait); spin_lock_init(&iforce->xmit_lock); init_MUTEX(&iforce->mem_mutex); iforce->xmit.buf = iforce->xmit_data; iforce->dev.ff_effects_max = 10; switch (iforce->bus) { #ifdef IFORCE_232 case IFORCE_232: strcpy(path, iforce->serio->phys); break; #endif #ifdef IFORCE_USB case IFORCE_USB: usb_make_path(iforce->usbdev, path, 64); break; #endif } sprintf(iforce->phys, "%s/input0", path); /* * Input device fields. */ iforce->dev.idbus = BUS_USB; iforce->dev.private = iforce; iforce->dev.name = iforce->phys; iforce->dev.open = iforce_open; iforce->dev.close = iforce_close; iforce->dev.flush = iforce_flush; iforce->dev.event = iforce_input_event; iforce->dev.upload_effect = iforce_upload_effect; iforce->dev.erase_effect = iforce_erase_effect; /* * On-device memory allocation. */ iforce->device_memory.name = "I-Force device effect memory"; iforce->device_memory.start = 0; iforce->device_memory.end = 200; iforce->device_memory.flags = IORESOURCE_MEM; iforce->device_memory.parent = NULL; iforce->device_memory.child = NULL; iforce->device_memory.sibling = NULL; /* * Wait until device ready - until it sends its first response. */ for (i = 0; i < 20; i++) if (!iforce_get_id_packet(iforce, "O")) break; if (i == 20) { /* 5 seconds */ printk(KERN_ERR "iforce.c: Timeout waiting for response from device.\n"); iforce_close(&iforce->dev); return -1; } /* * Get device info. */ if (!iforce_get_id_packet(iforce, "M")) iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1]; if (!iforce_get_id_packet(iforce, "P")) iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1]; if (!iforce_get_id_packet(iforce, "B")) iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; if (!iforce_get_id_packet(iforce, "N")) iforce->dev.ff_effects_max = iforce->edata[1]; /* Check if the device can store more effects than the driver can really handle */ if (iforce->dev.ff_effects_max > FF_EFFECTS_MAX) { printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.c\n", iforce->dev.ff_effects_max, FF_EFFECTS_MAX); iforce->dev.ff_effects_max = FF_EFFECTS_MAX; } /* * Display additional info. */ for (i = 0; c[i]; i++) if (!iforce_get_id_packet(iforce, c + i)) iforce_dump_packet("info", iforce->ecmd, iforce->edata); /* * Disable spring, enable force feedback. * FIXME: We should use iforce_set_autocenter() et al here. */ iforce_send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000"); /* * Find appropriate device entry */ for (i = 0; iforce_device[i].idvendor; i++) if (iforce_device[i].idvendor == iforce->dev.idvendor && iforce_device[i].idproduct == iforce->dev.idproduct) break; iforce->type = iforce_device + i; sprintf(iforce->name, iforce->type->name, iforce->dev.idproduct, iforce->dev.idvendor); /* * Set input device bitfields and ranges. */ iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); for (i = 0; iforce->type->btn[i] >= 0; i++) { signed short t = iforce->type->btn[i]; set_bit(t, iforce->dev.keybit); if (t != BTN_DEAD) set_bit(FF_BTN(t), iforce->dev.ffbit); } for (i = 0; iforce->type->abs[i] >= 0; i++) { signed short t = iforce->type->abs[i]; set_bit(t, iforce->dev.absbit); switch (t) { case ABS_X: case ABS_Y: case ABS_WHEEL: iforce->dev.absmax[t] = 1920; iforce->dev.absmin[t] = -1920; iforce->dev.absflat[t] = 128; iforce->dev.absfuzz[t] = 16; set_bit(FF_ABS(t), iforce->dev.ffbit); break; case ABS_THROTTLE: case ABS_GAS: case ABS_BRAKE: iforce->dev.absmax[t] = 255; iforce->dev.absmin[t] = 0; break; case ABS_RUDDER: iforce->dev.absmax[t] = 127; iforce->dev.absmin[t] = -128; break; case ABS_HAT0X: case ABS_HAT0Y: iforce->dev.absmax[t] = 1; iforce->dev.absmin[t] = -1; break; } } for (i = 0; iforce->type->ff[i] >= 0; i++) set_bit(iforce->type->ff[i], iforce->dev.ffbit); /* * Register input device. */ input_register_device(&iforce->dev); printk(KERN_INFO "input: %s [%d effects, %ld bytes memory] on %s\n", iforce->dev.name, iforce->dev.ff_effects_max, iforce->device_memory.end, path); return 0; } static int __init iforce_init(void) { #ifdef IFORCE_USB usb_register(&iforce_usb_driver); #endif #ifdef IFORCE_232 serio_register_device(&iforce_serio_dev); #endif return 0; } static void __exit iforce_exit(void) { #ifdef IFORCE_USB usb_deregister(&iforce_usb_driver); #endif #ifdef IFORCE_232 serio_unregister_device(&iforce_serio_dev); #endif } module_init(iforce_init); module_exit(iforce_exit); |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:33:27
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick/iforce In directory usw-pr-cvs1:/tmp/cvs-serv7222 Added Files: Tag: 1.7 iforce-ff.c Log Message: Moved. --- NEW FILE: iforce-ff.c --- /* * $Id: iforce-ff.c,v 1.7 2002/01/22 20:33:25 vojtech Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik <vo...@uc...> * Copyright (c) 2001 Johann Deneux <de...@if...> * * USB/RS232 I-Force joysticks and wheels. */ /* * 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 "iforce.h" /* * Set the magnitude of a constant force effect * Return error code * * Note: caller must ensure exclusive access to device */ static int make_magnitude_modifier(struct iforce* iforce, struct resource* mod_chunk, int no_alloc, __s16 level) { unsigned char data[3]; if (!no_alloc) { down(&iforce->mem_mutex); if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, iforce->device_memory.start, iforce->device_memory.end, 2L, NULL, NULL)) { up(&iforce->mem_mutex); return -ENOMEM; } up(&iforce->mem_mutex); } data[0] = LO(mod_chunk->start); data[1] = HI(mod_chunk->start); data[2] = HIFIX80(level); iforce_send_packet(iforce, FF_CMD_MAGNITUDE, data); iforce_dump_packet("magnitude: ", FF_CMD_MAGNITUDE, data); return 0; } /* * Upload the component of an effect dealing with the period, phase and magnitude */ static int make_period_modifier(struct iforce* iforce, struct resource* mod_chunk, int no_alloc, __s16 magnitude, __s16 offset, u16 period, u16 phase) { unsigned char data[7]; period = TIME_SCALE(period); if (!no_alloc) { down(&iforce->mem_mutex); if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, iforce->device_memory.start, iforce->device_memory.end, 2L, NULL, NULL)) { up(&iforce->mem_mutex); return -ENOMEM; } up(&iforce->mem_mutex); } data[0] = LO(mod_chunk->start); data[1] = HI(mod_chunk->start); data[2] = HIFIX80(magnitude); data[3] = HIFIX80(offset); data[4] = HI(phase); data[5] = LO(period); data[6] = HI(period); iforce_send_packet(iforce, FF_CMD_PERIOD, data); return 0; } /* * Uploads the part of an effect setting the shape of the force */ static int make_shape_modifier(struct iforce* iforce, struct resource* mod_chunk, int no_alloc, u16 attack_duration, __s16 initial_level, u16 fade_duration, __s16 final_level) { unsigned char data[8]; attack_duration = TIME_SCALE(attack_duration); fade_duration = TIME_SCALE(fade_duration); if (!no_alloc) { down(&iforce->mem_mutex); if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, iforce->device_memory.start, iforce->device_memory.end, 2L, NULL, NULL)) { up(&iforce->mem_mutex); return -ENOMEM; } up(&iforce->mem_mutex); } data[0] = LO(mod_chunk->start); data[1] = HI(mod_chunk->start); data[2] = LO(attack_duration); data[3] = HI(attack_duration); data[4] = HI(initial_level); data[5] = LO(fade_duration); data[6] = HI(fade_duration); data[7] = HI(final_level); iforce_send_packet(iforce, FF_CMD_SHAPE, data); return 0; } /* * Component of spring, friction, inertia... effects */ static int make_interactive_modifier(struct iforce* iforce, struct resource* mod_chunk, int no_alloc, __u16 rsat, __u16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center) { unsigned char data[10]; if (!no_alloc) { down(&iforce->mem_mutex); if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, iforce->device_memory.start, iforce->device_memory.end, 2L, NULL, NULL)) { up(&iforce->mem_mutex); return -ENOMEM; } up(&iforce->mem_mutex); } data[0] = LO(mod_chunk->start); data[1] = HI(mod_chunk->start); data[2] = (100*rk)>>15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ data[3] = (100*lk)>>15; /* This code is incorrect on cpus lacking arith shift */ center = (500*center)>>15; data[4] = LO(center); data[5] = HI(center); db = (1000*db)>>16; data[6] = LO(db); data[7] = HI(db); data[8] = (100*rsat)>>16; data[9] = (100*lsat)>>16; iforce_send_packet(iforce, FF_CMD_INTERACT, data); iforce_dump_packet("interactive", FF_CMD_INTERACT, data); return 0; } static unsigned char find_button(struct iforce *iforce, signed short button) { int i; for (i = 1; iforce->type->btn[i] >= 0; i++) if (iforce->type->btn[i] == button) return i + 1; return 0; } /* * Analyse the changes in an effect, and tell if we need to send an interactive * parameter packet */ static int need_interactive_modifier(struct iforce* iforce, struct ff_effect* new) { int id = new->id; struct ff_effect* old = &iforce->core_effects[id].effect; if (new->type != FF_SPRING && new->type != FF_FRICTION) { printk(KERN_WARNING "iforce.c: bad effect type in need_interactive_modifier\n"); return FALSE; } return (old->u.interactive.right_saturation != new->u.interactive.right_saturation || old->u.interactive.left_saturation != new->u.interactive.left_saturation || old->u.interactive.right_coeff != new->u.interactive.right_coeff || old->u.interactive.left_coeff != new->u.interactive.left_coeff || old->u.interactive.deadband != new->u.interactive.deadband || old->u.interactive.center != new->u.interactive.center); } /* * Analyse the changes in an effect, and tell if we need to send a magnitude * parameter packet */ static int need_magnitude_modifier(struct iforce* iforce, struct ff_effect* effect) { int id = effect->id; struct ff_effect* old = &iforce->core_effects[id].effect; if (effect->type != FF_CONSTANT) { printk(KERN_WARNING "iforce.c: bad effect type in need_shape_modifier\n"); return FALSE; } return (old->u.constant.level != effect->u.constant.level); } /* * Analyse the changes in an effect, and tell if we need to send a shape * parameter packet */ static int need_shape_modifier(struct iforce* iforce, struct ff_effect* effect) { int id = effect->id; struct ff_effect* old = &iforce->core_effects[id].effect; switch (effect->type) { case FF_CONSTANT: if (old->u.constant.shape.attack_length != effect->u.constant.shape.attack_length || old->u.constant.shape.attack_level != effect->u.constant.shape.attack_level || old->u.constant.shape.fade_length != effect->u.constant.shape.fade_length || old->u.constant.shape.fade_level != effect->u.constant.shape.fade_level) return TRUE; break; case FF_PERIODIC: if (old->u.periodic.shape.attack_length != effect->u.periodic.shape.attack_length || old->u.periodic.shape.attack_level != effect->u.periodic.shape.attack_level || old->u.periodic.shape.fade_length != effect->u.periodic.shape.fade_length || old->u.periodic.shape.fade_level != effect->u.periodic.shape.fade_level) return TRUE; break; default: printk(KERN_WARNING "iforce.c: bad effect type in need_shape_modifier\n"); } return FALSE; } /* * Analyse the changes in an effect, and tell if we need to send a periodic * parameter effect */ static int need_period_modifier(struct iforce* iforce, struct ff_effect* new) { int id = new->id; struct ff_effect* old = &iforce->core_effects[id].effect; if (new->type != FF_PERIODIC) { printk(KERN_WARNING "iforce.c: bad effect type in need_periodic_modifier\n"); return FALSE; } return (old->u.periodic.period != new->u.periodic.period || old->u.periodic.magnitude != new->u.periodic.magnitude || old->u.periodic.offset != new->u.periodic.offset || old->u.periodic.phase != new->u.periodic.phase); } /* * Analyse the changes in an effect, and tell if we need to send an effect * packet */ static int need_core(struct iforce* iforce, struct ff_effect* new) { int id = new->id; struct ff_effect* old = &iforce->core_effects[id].effect; if (old->direction != new->direction || old->trigger.button != new->trigger.button || old->trigger.interval != new->trigger.interval || old->replay.length != new->replay.length || old->replay.delay != new->replay.delay) return TRUE; return FALSE; } /* * Send the part common to all effects to the device */ static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button, u16 interval, u16 direction) { unsigned char data[14]; duration = TIME_SCALE(duration); delay = TIME_SCALE(delay); interval = TIME_SCALE(interval); data[0] = LO(id); data[1] = effect_type; data[2] = LO(axes) | find_button(iforce, button); data[3] = LO(duration); data[4] = HI(duration); data[5] = HI(direction); data[6] = LO(interval); data[7] = HI(interval); data[8] = LO(mod_id1); data[9] = HI(mod_id1); data[10] = LO(mod_id2); data[11] = HI(mod_id2); data[12] = LO(delay); data[13] = HI(delay); /* Stop effect */ /* iforce_control_playback(iforce, id, 0);*/ iforce_send_packet(iforce, FF_CMD_EFFECT, data); /* If needed, restart effect */ if (test_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[id].flags)) { /* BUG: perhaps we should replay n times, instead of 1. But we do not know n */ iforce_control_playback(iforce, id, 1); } return 0; } /* * Upload a periodic effect to the device * See also iforce_upload_constant. */ int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int is_update) { u8 wave_code; int core_id = effect->id; struct iforce_core_effect* core_effect = iforce->core_effects + core_id; struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); int param1_err = 1; int param2_err = 1; int core_err = 0; if (!is_update || need_period_modifier(iforce, effect)) { param1_err = make_period_modifier(iforce, mod1_chunk, is_update, effect->u.periodic.magnitude, effect->u.periodic.offset, effect->u.periodic.period, effect->u.periodic.phase); if (param1_err) return param1_err; set_bit(FF_MOD1_IS_USED, core_effect->flags); } if (!is_update || need_shape_modifier(iforce, effect)) { param2_err = make_shape_modifier(iforce, mod2_chunk, is_update, effect->u.periodic.shape.attack_length, effect->u.periodic.shape.attack_level, effect->u.periodic.shape.fade_length, effect->u.periodic.shape.fade_level); if (param2_err) return param2_err; set_bit(FF_MOD2_IS_USED, core_effect->flags); } switch (effect->u.periodic.waveform) { case FF_SQUARE: wave_code = 0x20; break; case FF_TRIANGLE: wave_code = 0x21; break; case FF_SINE: wave_code = 0x22; break; case FF_SAW_UP: wave_code = 0x23; break; case FF_SAW_DOWN: wave_code = 0x24; break; default: wave_code = 0x20; break; } if (!is_update || need_core(iforce, effect)) { core_err = make_core(iforce, effect->id, mod1_chunk->start, mod2_chunk->start, wave_code, 0x20, effect->replay.length, effect->replay.delay, effect->trigger.button, effect->trigger.interval, effect->direction); } /* If one of the parameter creation failed, we already returned an * error code. * If the core creation failed, we return its error code. * Else: if one parameter at least was created, we return 0 * else we return 1; */ return core_err < 0 ? core_err : (param1_err && param2_err); } /* * Upload a constant force effect * Return value: * <0 Error code * 0 Ok, effect created or updated * 1 effect did not change since last upload, and no packet was therefore sent */ int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int is_update) { int core_id = effect->id; struct iforce_core_effect* core_effect = iforce->core_effects + core_id; struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); int param1_err = 1; int param2_err = 1; int core_err = 0; if (!is_update || need_magnitude_modifier(iforce, effect)) { param1_err = make_magnitude_modifier(iforce, mod1_chunk, is_update, effect->u.constant.level); if (param1_err) return param1_err; set_bit(FF_MOD1_IS_USED, core_effect->flags); } if (!is_update || need_shape_modifier(iforce, effect)) { param2_err = make_shape_modifier(iforce, mod2_chunk, is_update, effect->u.constant.shape.attack_length, effect->u.constant.shape.attack_level, effect->u.constant.shape.fade_length, effect->u.constant.shape.fade_level); if (param2_err) return param2_err; set_bit(FF_MOD2_IS_USED, core_effect->flags); } if (!is_update || need_core(iforce, effect)) { core_err = make_core(iforce, effect->id, mod1_chunk->start, mod2_chunk->start, 0x00, 0x20, effect->replay.length, effect->replay.delay, effect->trigger.button, effect->trigger.interval, effect->direction); } /* If one of the parameter creation failed, we already returned an * error code. * If the core creation failed, we return its error code. * Else: if one parameter at least was created, we return 0 * else we return 1; */ return core_err < 0 ? core_err : (param1_err && param2_err); } /* * Upload an interactive effect. Those are for example friction, inertia, springs... */ int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* effect, int is_update) { int core_id = effect->id; struct iforce_core_effect* core_effect = iforce->core_effects + core_id; struct resource* mod_chunk = &(core_effect->mod1_chunk); u8 type, axes; u16 mod1, mod2, direction; int param_err = 1; int core_err = 0; switch (effect->type) { case FF_SPRING: type = 0x40; break; case FF_FRICTION: type = 0x41; break; default: return -1; } if (!is_update || need_interactive_modifier(iforce, effect)) { param_err = make_interactive_modifier(iforce, mod_chunk, is_update, effect->u.interactive.right_saturation, effect->u.interactive.left_saturation, effect->u.interactive.right_coeff, effect->u.interactive.left_coeff, effect->u.interactive.deadband, effect->u.interactive.center); if (param_err) return param_err; set_bit(FF_MOD1_IS_USED, core_effect->flags); } switch ((test_bit(ABS_X, &effect->u.interactive.axis) || test_bit(ABS_WHEEL, &effect->u.interactive.axis)) | (!!test_bit(ABS_Y, &effect->u.interactive.axis) << 1)) { case 0: /* Only one axis, choose orientation */ mod1 = mod_chunk->start; mod2 = 0xffff; direction = effect->direction; axes = 0x20; break; case 1: /* Only X axis */ mod1 = mod_chunk->start; mod2 = 0xffff; direction = 0x5a00; axes = 0x40; break; case 2: /* Only Y axis */ mod1 = 0xffff; mod2 = mod_chunk->start; direction = 0xb400; axes = 0x80; break; case 3: /* Both X and Y axes */ /* TODO: same setting for both axes is not mandatory */ mod1 = mod_chunk->start; mod2 = mod_chunk->start; direction = 0x6000; axes = 0xc0; break; default: return -1; } if (!is_update || need_core(iforce, effect)) { core_err = make_core(iforce, effect->id, mod1, mod2, type, axes, effect->replay.length, effect->replay.delay, effect->trigger.button, effect->trigger.interval, direction); } /* If the parameter creation failed, we already returned an * error code. * If the core creation failed, we return its error code. * Else: if a parameter was created, we return 0 * else we return 1; */ return core_err < 0 ? core_err : param_err; } |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:32:12
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick In directory usw-pr-cvs1:/tmp/cvs-serv6791 Added Files: Tag: 1.14 warrior.c Log Message: Moved. --- NEW FILE: warrior.c --- /* * $Id: warrior.c,v 1.14 2002/01/22 20:32:10 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik */ /* * Logitech WingMan Warrior joystick driver for Linux */ /* * This program is free warftware; 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("Logitech WingMan Warrior joystick driver"); MODULE_LICENSE("GPL"); /* * Constants. */ #define WARRIOR_MAX_LENGTH 16 static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 }; static char *warrior_name = "Logitech WingMan Warrior"; /* * Per-Warrior data. */ struct warrior { struct input_dev dev; int idx, len; unsigned char data[WARRIOR_MAX_LENGTH]; char phys[32]; }; /* * warrior_process_packet() decodes packets the driver receives from the * Warrior. It updates the data accordingly. */ static void warrior_process_packet(struct warrior *warrior) { struct input_dev *dev = &warrior->dev; unsigned char *data = warrior->data; if (!warrior->idx) return; switch ((data[0] >> 4) & 7) { case 1: /* Button data */ input_report_key(dev, BTN_TRIGGER, data[3] & 1); input_report_key(dev, BTN_THUMB, (data[3] >> 1) & 1); input_report_key(dev, BTN_TOP, (data[3] >> 2) & 1); input_report_key(dev, BTN_TOP2, (data[3] >> 3) & 1); return; case 3: /* XY-axis info->data */ input_report_abs(dev, ABS_X, ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5))); input_report_abs(dev, ABS_Y, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7)); return; case 5: /* Throttle, spinner, hat info->data */ input_report_abs(dev, ABS_THROTTLE, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7)); input_report_abs(dev, ABS_HAT0X, (data[3] & 2 ? 1 : 0) - (data[3] & 1 ? 1 : 0)); input_report_abs(dev, ABS_HAT0Y, (data[3] & 8 ? 1 : 0) - (data[3] & 4 ? 1 : 0)); input_report_rel(dev, REL_DIAL, (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5)); return; } } /* * warrior_interrupt() is called by the low level driver when characters * are ready for us. We then buffer them for further processing, or call the * packet processing routine. */ static void warrior_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { struct warrior* warrior = serio->private; if (data & 0x80) { if (warrior->idx) warrior_process_packet(warrior); warrior->idx = 0; warrior->len = warrior_lengths[(data >> 4) & 7]; } if (warrior->idx < warrior->len) warrior->data[warrior->idx++] = data; if (warrior->idx == warrior->len) { if (warrior->idx) warrior_process_packet(warrior); warrior->idx = 0; warrior->len = 0; } } /* * warrior_disconnect() is the opposite of warrior_connect() */ static void warrior_disconnect(struct serio *serio) { struct warrior* warrior = serio->private; input_unregister_device(&warrior->dev); serio_close(serio); kfree(warrior); } /* * warrior_connect() is the routine that is called when someone adds a * new serio device. It looks for the Warrior, and if found, registers * it as an input device. */ static void warrior_connect(struct serio *serio, struct serio_dev *dev) { struct warrior *warrior; int i; if (serio->type != (SERIO_RS232 | SERIO_WARRIOR)) return; if (!(warrior = kmalloc(sizeof(struct warrior), GFP_KERNEL))) return; memset(warrior, 0, sizeof(struct warrior)); warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); warrior->dev.keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2); warrior->dev.relbit[0] = BIT(REL_DIAL); warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y); sprintf(warrior->phys, "%s/input0", serio->phys); warrior->dev.name = warrior_name; warrior->dev.phys = warrior->phys; warrior->dev.idbus = BUS_RS232; warrior->dev.idvendor = SERIO_WARRIOR; warrior->dev.idproduct = 0x0001; warrior->dev.idversion = 0x0100; for (i = 0; i < 2; i++) { warrior->dev.absmax[ABS_X+i] = -64; warrior->dev.absmin[ABS_X+i] = 64; warrior->dev.absflat[ABS_X+i] = 8; } warrior->dev.absmax[ABS_THROTTLE] = -112; warrior->dev.absmin[ABS_THROTTLE] = 112; for (i = 0; i < 2; i++) { warrior->dev.absmax[ABS_HAT0X+i] = -1; warrior->dev.absmin[ABS_HAT0X+i] = 1; } warrior->dev.private = warrior; serio->private = warrior; if (serio_open(serio, dev)) { kfree(warrior); return; } input_register_device(&warrior->dev); printk(KERN_INFO "input: Logitech WingMan Warrior on %s\n", serio->phys); } /* * The serio device structure. */ static struct serio_dev warrior_dev = { interrupt: warrior_interrupt, connect: warrior_connect, disconnect: warrior_disconnect, }; /* * The functions for inserting/removing us as a module. */ int __init warrior_init(void) { serio_register_device(&warrior_dev); return 0; } void __exit warrior_exit(void) { serio_unregister_device(&warrior_dev); } module_init(warrior_init); module_exit(warrior_exit); |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:31:56
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick In directory usw-pr-cvs1:/tmp/cvs-serv6622 Added Files: Tag: 1.5 twidjoy.c Log Message: Moved. --- NEW FILE: twidjoy.c --- /* * $Id: twidjoy.c,v 1.5 2002/01/22 20:31:53 vojtech Exp $ * * derived from CVS-ID "stinger.c,v 1.5 2001/05/29 12:57:18 vojtech Exp" * * Copyright (c) 2001 Arndt Schoenewald * Copyright (c) 2000-2001 Vojtech Pavlik * Copyright (c) 2000 Mark Fletcher * * Sponsored by Quelltext AG (http://www.quelltext-ag.de), Dortmund, Germany */ /* * Driver to use Handykey's Twiddler (the first edition, i.e. the one with * the RS232 interface) as a joystick under Linux * * The Twiddler is a one-handed chording keyboard featuring twelve buttons on * the front, six buttons on the top, and a built-in tilt sensor. The buttons * on the front, which are grouped as four rows of three buttons, are pressed * by the four fingers (this implies only one button per row can be held down * at the same time) and the buttons on the top are for the thumb. The tilt * sensor delivers X and Y axis data depending on how the Twiddler is held. * Additional information can be found at http://www.handykey.com. * * This driver does not use the Twiddler for its intended purpose, i.e. as * a chording keyboard, but as a joystick: pressing and releasing a button * immediately sends a corresponding button event, and tilting it generates * corresponding ABS_X and ABS_Y events. This turns the Twiddler into a game * controller with amazing 18 buttons :-) * * Note: The Twiddler2 (the successor of the Twiddler that connects directly * to the PS/2 keyboard and mouse ports) is NOT supported by this driver! * * For questions or feedback regarding this driver module please contact: * Arndt Schoenewald <ar...@qu...> */ /* * 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 <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/serio.h> #include <linux/init.h> /* * Constants. */ #define TWIDJOY_MAX_LENGTH 5 static char *twidjoy_name = "Handykey Twiddler"; static struct twidjoy_button_spec { int bitshift; int bitmask; int buttons[3]; } twidjoy_buttons[] = { { 0, 3, { BTN_A, BTN_B, BTN_C } }, { 2, 3, { BTN_X, BTN_Y, BTN_Z } }, { 4, 3, { BTN_TL, BTN_TR, BTN_TR2 } }, { 6, 3, { BTN_SELECT, BTN_START, BTN_MODE } }, { 8, 1, { BTN_BASE5 } }, { 9, 1, { BTN_BASE } }, { 10, 1, { BTN_BASE3 } }, { 11, 1, { BTN_BASE4 } }, { 12, 1, { BTN_BASE2 } }, { 13, 1, { BTN_BASE6 } }, { 0, 0, { 0 } } }; /* * Per-Twiddler data. */ struct twidjoy { struct input_dev dev; int idx; unsigned char data[TWIDJOY_MAX_LENGTH]; char phys[32]; }; /* * twidjoy_process_packet() decodes packets the driver receives from the * Twiddler. It updates the data accordingly. */ static void twidjoy_process_packet(struct twidjoy *twidjoy) { if (twidjoy->idx == TWIDJOY_MAX_LENGTH) { struct input_dev *dev = &twidjoy->dev; unsigned char *data = twidjoy->data; struct twidjoy_button_spec *bp; int button_bits, abs_x, abs_y; button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f); for (bp = twidjoy_buttons; bp->bitmask; bp++) { int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift; int i; for (i = 0; i < bp->bitmask; i++) input_report_key(dev, bp->buttons[i], i+1 == value); } abs_x = ((data[4] & 0x07) << 5) | ((data[3] & 0x7C) >> 2); if (data[4] & 0x08) abs_x -= 256; abs_y = ((data[3] & 0x01) << 7) | ((data[2] & 0x7F) >> 0); if (data[3] & 0x02) abs_y -= 256; input_report_abs(dev, ABS_X, -abs_x); input_report_abs(dev, ABS_Y, +abs_y); } return; } /* * twidjoy_interrupt() is called by the low level driver when characters * are ready for us. We then buffer them for further processing, or call the * packet processing routine. */ static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { struct twidjoy *twidjoy = serio->private; /* All Twiddler packets are 5 bytes. The fact that the first byte * has a MSB of 0 and all other bytes have a MSB of 1 can be used * to check and regain sync. */ if ((data & 0x80) == 0) twidjoy->idx = 0; /* this byte starts a new packet */ else if (twidjoy->idx == 0) return; /* wrong MSB -- ignore this byte */ if (twidjoy->idx < TWIDJOY_MAX_LENGTH) twidjoy->data[twidjoy->idx++] = data; if (twidjoy->idx == TWIDJOY_MAX_LENGTH) { twidjoy_process_packet(twidjoy); twidjoy->idx = 0; } return; } /* * twidjoy_disconnect() is the opposite of twidjoy_connect() */ static void twidjoy_disconnect(struct serio *serio) { struct twidjoy *twidjoy = serio->private; input_unregister_device(&twidjoy->dev); serio_close(serio); kfree(twidjoy); } /* * twidjoy_connect() is the routine that is called when someone adds a * new serio device. It looks for the Twiddler, and if found, registers * it as an input device. */ static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) { struct twidjoy_button_spec *bp; struct twidjoy *twidjoy; int i; if (serio->type != (SERIO_RS232 | SERIO_TWIDJOY)) return; if (!(twidjoy = kmalloc(sizeof(struct twidjoy), GFP_KERNEL))) return; memset(twidjoy, 0, sizeof(struct twidjoy)); sprintf(twidjoy->phys, "%s/input0", serio->phys); twidjoy->dev.name = twidjoy_name; twidjoy->dev.phys = twidjoy->phys; twidjoy->dev.idbus = BUS_RS232; twidjoy->dev.idvendor = SERIO_TWIDJOY; twidjoy->dev.idproduct = 0x0001; twidjoy->dev.idversion = 0x0100; twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (bp = twidjoy_buttons; bp->bitmask; bp++) { for (i = 0; i < bp->bitmask; i++) set_bit(bp->buttons[i], twidjoy->dev.keybit); } twidjoy->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); for (i = 0; i < 2; i++) { twidjoy->dev.absmax[ABS_X+i] = 50; twidjoy->dev.absmin[ABS_X+i] = -50; /* TODO: arndt 20010708: Are these values appropriate? */ twidjoy->dev.absfuzz[ABS_X+i] = 4; twidjoy->dev.absflat[ABS_X+i] = 4; } twidjoy->dev.private = twidjoy; serio->private = twidjoy; if (serio_open(serio, dev)) { kfree(twidjoy); return; } input_register_device(&twidjoy->dev); printk(KERN_INFO "input: %s on %s\n", twidjoy_name, serio->phys); } /* * The serio device structure. */ static struct serio_dev twidjoy_dev = { interrupt: twidjoy_interrupt, connect: twidjoy_connect, disconnect: twidjoy_disconnect, }; /* * The functions for inserting/removing us as a module. */ int __init twidjoy_init(void) { serio_register_device(&twidjoy_dev); return 0; } void __exit twidjoy_exit(void) { serio_unregister_device(&twidjoy_dev); } module_init(twidjoy_init); module_exit(twidjoy_exit); |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:30:43
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick In directory usw-pr-cvs1:/tmp/cvs-serv6018 Added Files: Tag: 1.14 turbografx.c Log Message: Moved. --- NEW FILE: turbografx.c --- /* * $Id: turbografx.c,v 1.14 2002/01/22 20:30:39 vojtech Exp $ * * Copyright (c) 1998-2001 Vojtech Pavlik * * Based on the work of: * Steffen Schwenke */ /* * TurboGraFX parallel port interface 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/parport.h> #include <linux/input.h> #include <linux/module.h> #include <linux/init.h> MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>"); MODULE_DESCRIPTION("TurboGraFX parallel port interface driver"); MODULE_LICENSE("GPL"); MODULE_PARM(tgfx, "2-8i"); MODULE_PARM(tgfx_2, "2-8i"); MODULE_PARM(tgfx_3, "2-8i"); #define TGFX_REFRESH_TIME HZ/100 /* 10 ms */ #define TGFX_TRIGGER 0x08 #define TGFX_UP 0x10 #define TGFX_DOWN 0x20 #define TGFX_LEFT 0x40 #define TGFX_RIGHT 0x80 #define TGFX_THUMB 0x02 #define TGFX_THUMB2 0x04 #define TGFX_TOP 0x01 #define TGFX_TOP2 0x08 static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 }; static char *tgfx_name = "TurboGraFX Multisystem joystick"; struct tgfx { struct pardevice *pd; struct timer_list timer; struct input_dev dev[7]; char phys[7][32]; int sticks; int used; } *tgfx_base[3]; /* * tgfx_timer() reads and analyzes TurboGraFX joystick data. */ static void tgfx_timer(unsigned long private) { struct tgfx *tgfx = (void *) private; struct input_dev *dev; int data1, data2, i; for (i = 0; i < 7; i++) if (tgfx->sticks & (1 << i)) { dev = tgfx->dev + i; parport_write_data(tgfx->pd->port, ~(1 << i)); data1 = parport_read_status(tgfx->pd->port) ^ 0x7f; data2 = parport_read_control(tgfx->pd->port) ^ 0x04; /* CAVEAT parport */ input_report_abs(dev, ABS_X, !!(data1 & TGFX_RIGHT) - !!(data1 & TGFX_LEFT)); input_report_abs(dev, ABS_Y, !!(data1 & TGFX_DOWN ) - !!(data1 & TGFX_UP )); input_report_key(dev, BTN_TRIGGER, (data1 & TGFX_TRIGGER)); input_report_key(dev, BTN_THUMB, (data2 & TGFX_THUMB )); input_report_key(dev, BTN_THUMB2, (data2 & TGFX_THUMB2 )); input_report_key(dev, BTN_TOP, (data2 & TGFX_TOP )); input_report_key(dev, BTN_TOP2, (data2 & TGFX_TOP2 )); } mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); } static int tgfx_open(struct input_dev *dev) { struct tgfx *tgfx = dev->private; if (!tgfx->used++) { parport_claim(tgfx->pd); parport_write_control(tgfx->pd->port, 0x04); mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); } return 0; } static void tgfx_close(struct input_dev *dev) { struct tgfx *tgfx = dev->private; if (!--tgfx->used) { del_timer(&tgfx->timer); parport_write_control(tgfx->pd->port, 0x00); parport_release(tgfx->pd); } } /* * tgfx_probe() probes for tg gamepads. */ static struct tgfx __init *tgfx_probe(int *config) { struct tgfx *tgfx; struct parport *pp; int i, j; if (config[0] < 0) return NULL; for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next) config[0]--; if (!pp) { printk(KERN_ERR "turbografx.c: no such parport\n"); return NULL; } if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) return NULL; memset(tgfx, 0, sizeof(struct tgfx)); tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); if (!tgfx->pd) { printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n"); kfree(tgfx); return NULL; } init_timer(&tgfx->timer); tgfx->timer.data = (long) tgfx; tgfx->timer.function = tgfx_timer; tgfx->sticks = 0; for (i = 0; i < 7; i++) if (config[i+1] > 0 && config[i+1] < 6) { tgfx->sticks |= (1 << i); tgfx->dev[i].private = tgfx; tgfx->dev[i].open = tgfx_open; tgfx->dev[i].close = tgfx_close; sprintf(tgfx->phys[i], "%s/input0", tgfx->pd->port->name); tgfx->dev[i].name = tgfx_name; tgfx->dev[i].phys = tgfx->phys[i]; tgfx->dev[i].idbus = BUS_PARPORT; tgfx->dev[i].idvendor = 0x0003; tgfx->dev[i].idproduct = config[i+1]; tgfx->dev[i].idversion = 0x0100; tgfx->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); for (j = 0; j < config[i+1]; j++) set_bit(tgfx_buttons[j], tgfx->dev[i].keybit); tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1; tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1; input_register_device(tgfx->dev + i); printk(KERN_INFO "input: %d-button Multisystem joystick on %s\n", config[i+1], tgfx->pd->port->name); } if (!tgfx->sticks) { parport_unregister_device(tgfx->pd); kfree(tgfx); return NULL; } return tgfx; } #ifndef MODULE int __init tgfx_setup(char *str) { int i, ints[9]; get_options(str, ARRAY_SIZE(ints), ints); for (i = 0; i <= ints[0] && i < 8; i++) tgfx[i] = ints[i + 1]; return 1; } int __init tgfx_setup_2(char *str) { int i, ints[9]; get_options(str, ARRAY_SIZE(ints), ints); for (i = 0; i <= ints[0] && i < 8; i++) tgfx_2[i] = ints[i + 1]; return 1; } int __init tgfx_setup_3(char *str) { int i, ints[9]; get_options(str, ARRAY_SIZE(ints), ints); for (i = 0; i <= ints[0] && i < 8; i++) tgfx_3[i] = ints[i + 1]; return 1; } __setup("tgfx=", tgfx_setup); __setup("tgfx_2=", tgfx_setup_2); __setup("tgfx_3=", tgfx_setup_3); #endif int __init tgfx_init(void) { tgfx_base[0] = tgfx_probe(tgfx); tgfx_base[1] = tgfx_probe(tgfx_2); tgfx_base[2] = tgfx_probe(tgfx_3); if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2]) return 0; return -ENODEV; } void __exit tgfx_exit(void) { int i, j; for (i = 0; i < 3; i++) if (tgfx_base[i]) { for (j = 0; j < 7; j++) if (tgfx_base[i]->sticks & (1 << j)) input_unregister_device(tgfx_base[i]->dev + j); parport_unregister_device(tgfx_base[i]->pd); } } module_init(tgfx_init); module_exit(tgfx_exit); |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:29:54
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick In directory usw-pr-cvs1:/tmp/cvs-serv5801 Added Files: Tag: 1.31 tmdc.c Log Message: Moved. --- NEW FILE: tmdc.c --- /* * $Id: tmdc.c,v 1.31 2002/01/22 20:29:52 vojtech Exp $ * * Copyright (c) 1998-2001 Vojtech Pavlik * * Based on the work of: * Trystan Larey-Williams */ /* * ThrustMaster DirectConnect (BSP) 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/slab.h> #include <linux/module.h> #include <linux/init.h> #include <linux/gameport.h> #include <linux/input.h> MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>"); MODULE_DESCRIPTION("ThrustMaster DirectConnect joystick driver"); MODULE_LICENSE("GPL"); #define TMDC_MAX_START 400 /* 400 us */ #define TMDC_MAX_STROBE 45 /* 45 us */ #define TMDC_MAX_LENGTH 13 #define TMDC_REFRESH_TIME HZ/50 /* 20 ms */ #define TMDC_MODE_M3DI 1 #define TMDC_MODE_3DRP 3 #define TMDC_MODE_AT 4 #define TMDC_MODE_FM 8 #define TMDC_MODE_FGP 163 #define TMDC_BYTE_ID 10 #define TMDC_BYTE_REV 11 #define TMDC_BYTE_DEF 12 #define TMDC_ABS 7 #define TMDC_ABS_HAT 4 #define TMDC_BTN 16 static unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 }; static unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 }; static signed char tmdc_abs[TMDC_ABS] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ }; static signed char tmdc_abs_hat[TMDC_ABS_HAT] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y }; static signed char tmdc_abs_at[TMDC_ABS] = { ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE }; static signed char tmdc_abs_fm[TMDC_ABS] = { ABS_RX, ABS_RY, ABS_X, ABS_Y }; static short tmdc_btn_pad[TMDC_BTN] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR }; static short tmdc_btn_joy[TMDC_BTN] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE, BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z }; static short tmdc_btn_fm[TMDC_BTN] = { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 }; static short tmdc_btn_at[TMDC_BTN] = { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4, BTN_BASE3, BTN_BASE2, BTN_BASE }; static struct { int x; int y; } tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}}; struct tmdc { struct gameport *gameport; struct timer_list timer; struct input_dev dev[2]; char name[2][64]; char phys[2][32]; int mode[2]; signed char *abs[2]; short *btn[2]; unsigned char absc[2]; unsigned char btnc[2][4]; unsigned char btno[2][4]; int used; int reads; int bads; unsigned char exists; }; /* * tmdc_read_packet() reads a ThrustMaster packet. */ static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMDC_MAX_LENGTH]) { unsigned char u, v, w, x; unsigned long flags; int i[2], j[2], t[2], p, k; p = gameport_time(gameport, TMDC_MAX_STROBE); for (k = 0; k < 2; k++) { t[k] = gameport_time(gameport, TMDC_MAX_START); i[k] = j[k] = 0; } __save_flags(flags); __cli(); gameport_trigger(gameport); w = gameport_read(gameport) >> 4; do { x = w; w = gameport_read(gameport) >> 4; for (k = 0, v = w, u = x; k < 2; k++, v >>= 2, u >>= 2) { if (~v & u & 2) { if (t[k] <= 0 || i[k] >= TMDC_MAX_LENGTH) continue; t[k] = p; if (j[k] == 0) { /* Start bit */ if (~v & 1) t[k] = 0; data[k][i[k]] = 0; j[k]++; continue; } if (j[k] == 9) { /* Stop bit */ if (v & 1) t[k] = 0; j[k] = 0; i[k]++; continue; } data[k][i[k]] |= (~v & 1) << (j[k]++ - 1); /* Data bit */ } t[k]--; } } while (t[0] > 0 || t[1] > 0); __restore_flags(flags); return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1); } /* * tmdc_read() reads and analyzes ThrustMaster joystick data. */ static void tmdc_timer(unsigned long private) { unsigned char data[2][TMDC_MAX_LENGTH]; struct tmdc *tmdc = (void *) private; struct input_dev *dev; unsigned char r, bad = 0; int i, j, k, l; tmdc->reads++; if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists) bad = 1; else for (j = 0; j < 2; j++) if (r & (1 << j) & tmdc->exists) { if (data[j][TMDC_BYTE_ID] != tmdc->mode[j]) { bad = 1; continue; } dev = tmdc->dev + j; for (i = 0; i < tmdc->absc[j]; i++) { if (tmdc->abs[j][i] < 0) continue; input_report_abs(dev, tmdc->abs[j][i], data[j][tmdc_byte_a[i]]); } switch (tmdc->mode[j]) { case TMDC_MODE_M3DI: i = tmdc_byte_d[0]; input_report_abs(dev, ABS_HAT0X, ((data[j][i] >> 3) & 1) - ((data[j][i] >> 1) & 1)); input_report_abs(dev, ABS_HAT0Y, ((data[j][i] >> 2) & 1) - ( data[j][i] & 1)); break; case TMDC_MODE_AT: i = tmdc_byte_a[3]; input_report_abs(dev, ABS_HAT0X, tmdc_hat_to_axis[(data[j][i] - 141) / 25].x); input_report_abs(dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[j][i] - 141) / 25].y); break; } for (k = l = 0; k < 4; k++) { for (i = 0; i < tmdc->btnc[j][k]; i++) input_report_key(dev, tmdc->btn[j][i + l], ((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1)); l += tmdc->btnc[j][k]; } } tmdc->bads += bad; mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME); } static int tmdc_open(struct input_dev *dev) { struct tmdc *tmdc = dev->private; if (!tmdc->used++) mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME); return 0; } static void tmdc_close(struct input_dev *dev) { struct tmdc *tmdc = dev->private; if (!--tmdc->used) del_timer(&tmdc->timer); } /* * tmdc_probe() probes for ThrustMaster type joysticks. */ static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev) { struct models { unsigned char id; char *name; char abs; char hats; char btnc[4]; char btno[4]; signed char *axes; short *buttons; } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy }, { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, { 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at }, { 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm }, { 163, "Thrustmaster Fusion GamePad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }}; unsigned char data[2][TMDC_MAX_LENGTH]; struct tmdc *tmdc; int i, j, k, l, m; if (!(tmdc = kmalloc(sizeof(struct tmdc), GFP_KERNEL))) return; memset(tmdc, 0, sizeof(struct tmdc)); gameport->private = tmdc; tmdc->gameport = gameport; init_timer(&tmdc->timer); tmdc->timer.data = (long) tmdc; tmdc->timer.function = tmdc_timer; if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) goto fail1; if (!(tmdc->exists = tmdc_read_packet(gameport, data))) goto fail2; for (j = 0; j < 2; j++) if (tmdc->exists & (1 << j)) { tmdc->mode[j] = data[j][TMDC_BYTE_ID]; for (m = 0; models[m].id && models[m].id != tmdc->mode[j]; m++); tmdc->abs[j] = models[m].axes; tmdc->btn[j] = models[m].buttons; if (!models[m].id) { models[m].abs = data[j][TMDC_BYTE_DEF] >> 4; for (k = 0; k < 4; k++) models[m].btnc[k] = k < (data[j][TMDC_BYTE_DEF] & 0xf) ? 8 : 0; } tmdc->absc[j] = models[m].abs; for (k = 0; k < 4; k++) { tmdc->btnc[j][k] = models[m].btnc[k]; tmdc->btno[j][k] = models[m].btno[k]; } sprintf(tmdc->name[j], models[m].name, models[m].abs, (data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]); sprintf(tmdc->phys[j], "%s/input%d", gameport->phys, j); tmdc->dev[j].private = tmdc; tmdc->dev[j].open = tmdc_open; tmdc->dev[j].close = tmdc_close; tmdc->dev[j].name = tmdc->name[j]; tmdc->dev[j].phys = tmdc->phys[j]; tmdc->dev[j].idbus = BUS_GAMEPORT; tmdc->dev[j].idvendor = GAMEPORT_ID_VENDOR_THRUSTMASTER; tmdc->dev[j].idproduct = models[m].id; tmdc->dev[j].idversion = 0x0100; tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) { if (tmdc->abs[i] < 0) continue; set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit); tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8; tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248; tmdc->dev[j].absfuzz[tmdc->abs[j][i]] = 2; tmdc->dev[j].absflat[tmdc->abs[j][i]] = 4; } for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) { set_bit(tmdc_abs_hat[i], tmdc->dev[j].absbit); tmdc->dev[j].absmin[tmdc_abs_hat[i]] = -1; tmdc->dev[j].absmax[tmdc_abs_hat[i]] = 1; } for (k = l = 0; k < 4; k++) { for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++) set_bit(tmdc->btn[j][i + l], tmdc->dev[j].keybit); l += models[m].btnc[k]; } input_register_device(tmdc->dev + j); printk(KERN_INFO "input: %s on %s\n", tmdc->name[j], gameport->phys); } return; fail2: gameport_close(gameport); fail1: kfree(tmdc); } static void tmdc_disconnect(struct gameport *gameport) { struct tmdc *tmdc = gameport->private; int i; for (i = 0; i < 2; i++) if (tmdc->exists & (1 << i)) input_unregister_device(tmdc->dev + i); gameport_close(gameport); kfree(tmdc); } static struct gameport_dev tmdc_dev = { connect: tmdc_connect, disconnect: tmdc_disconnect, }; int __init tmdc_init(void) { gameport_register_device(&tmdc_dev); return 0; } void __exit tmdc_exit(void) { gameport_unregister_device(&tmdc_dev); } module_init(tmdc_init); module_exit(tmdc_exit); |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:29:34
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick In directory usw-pr-cvs1:/tmp/cvs-serv5674 Added Files: Tag: 1.10 stinger.c Log Message: Moved. --- NEW FILE: stinger.c --- /* * $Id: stinger.c,v 1.10 2002/01/22 20:29:31 vojtech Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik * Copyright (c) 2000 Mark Fletcher */ /* * Gravis Stinger gamepad driver for Linux */ /* * This program is free warftware; 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("Gravis Stinger gamepad driver"); MODULE_LICENSE("GPL"); /* * Constants. */ #define STINGER_MAX_LENGTH 8 static char *stinger_name = "Gravis Stinger"; /* * Per-Stinger data. */ struct stinger { struct input_dev dev; int idx; unsigned char data[STINGER_MAX_LENGTH]; char phys[32]; }; /* * stinger_process_packet() decodes packets the driver receives from the * Stinger. It updates the data accordingly. */ static void stinger_process_packet(struct stinger *stinger) { struct input_dev *dev = &stinger->dev; unsigned char *data = stinger->data; if (!stinger->idx) return; input_report_key(dev, BTN_A, ((data[0] & 0x20) >> 5)); input_report_key(dev, BTN_B, ((data[0] & 0x10) >> 4)); input_report_key(dev, BTN_C, ((data[0] & 0x08) >> 3)); input_report_key(dev, BTN_X, ((data[0] & 0x04) >> 2)); input_report_key(dev, BTN_Y, ((data[3] & 0x20) >> 5)); input_report_key(dev, BTN_Z, ((data[3] & 0x10) >> 4)); input_report_key(dev, BTN_TL, ((data[3] & 0x08) >> 3)); input_report_key(dev, BTN_TR, ((data[3] & 0x04) >> 2)); input_report_key(dev, BTN_SELECT, ((data[3] & 0x02) >> 1)); input_report_key(dev, BTN_START, (data[3] & 0x01)); input_report_abs(dev, ABS_X, (data[1] & 0x3F) - ((data[0] & 0x01) << 6)); input_report_abs(dev, ABS_Y, ((data[0] & 0x02) << 5) - (data[2] & 0x3F)); return; } /* * stinger_interrupt() is called by the low level driver when characters * are ready for us. We then buffer them for further processing, or call the * packet processing routine. */ static void stinger_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { struct stinger* stinger = serio->private; /* All Stinger packets are 4 bytes */ if (stinger->idx < STINGER_MAX_LENGTH) stinger->data[stinger->idx++] = data; if (stinger->idx == 4) { stinger_process_packet(stinger); stinger->idx = 0; } return; } /* * stinger_disconnect() is the opposite of stinger_connect() */ static void stinger_disconnect(struct serio *serio) { struct stinger* stinger = serio->private; input_unregister_device(&stinger->dev); serio_close(serio); kfree(stinger); } /* * stinger_connect() is the routine that is called when someone adds a * new serio device. It looks for the Stinger, and if found, registers * it as an input device. */ static void stinger_connect(struct serio *serio, struct serio_dev *dev) { struct stinger *stinger; int i; if (serio->type != (SERIO_RS232 | SERIO_STINGER)) return; if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL))) return; memset(stinger, 0, sizeof(struct stinger)); stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \ BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \ BIT(BTN_START) | BIT(BTN_SELECT); stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); sprintf(stinger->phys, "%s/serio0", serio->phys); stinger->dev.name = stinger_name; stinger->dev.phys = stinger->phys; stinger->dev.idbus = BUS_RS232; stinger->dev.idvendor = SERIO_STINGER; stinger->dev.idproduct = 0x0001; stinger->dev.idversion = 0x0100; for (i = 0; i < 2; i++) { stinger->dev.absmax[ABS_X+i] = 64; stinger->dev.absmin[ABS_X+i] = -64; stinger->dev.absflat[ABS_X+i] = 4; } stinger->dev.private = stinger; serio->private = stinger; if (serio_open(serio, dev)) { kfree(stinger); return; } input_register_device(&stinger->dev); printk(KERN_INFO "input: %s on %s\n", stinger_name, serio->phys); } /* * The serio device structure. */ static struct serio_dev stinger_dev = { interrupt: stinger_interrupt, connect: stinger_connect, disconnect: stinger_disconnect, }; /* * The functions for inserting/removing us as a module. */ int __init stinger_init(void) { serio_register_device(&stinger_dev); return 0; } void __exit stinger_exit(void) { serio_unregister_device(&stinger_dev); } module_init(stinger_init); module_exit(stinger_exit); |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:29:22
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick In directory usw-pr-cvs1:/tmp/cvs-serv5599 Added Files: Tag: 1.15 spaceorb.c Log Message: Moved. --- NEW FILE: spaceorb.c --- /* * $Id: spaceorb.c,v 1.15 2002/01/22 20:29:19 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik * * Based on the work of: * David Thompson */ /* * SpaceTec SpaceOrb 360 and Avenger 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/slab.h> #include <linux/module.h> #include <linux/init.h> #include <linux/input.h> #include <linux/serio.h> MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>"); MODULE_DESCRIPTION("SpaceTec SpaceOrb 360 and Avenger 6dof controller driver"); MODULE_LICENSE("GPL"); /* * Constants. */ #define SPACEORB_MAX_LENGTH 64 static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A }; static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; static char *spaceorb_name = "SpaceTec SpaceOrb 360 / Avenger"; /* * Per-Orb data. */ struct spaceorb { struct input_dev dev; struct serio *serio; int idx; unsigned char data[SPACEORB_MAX_LENGTH]; char phys[32]; }; static unsigned char spaceorb_xor[] = "SpaceWare"; static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout", "Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" }; /* * spaceorb_process_packet() decodes packets the driver receives from the * SpaceOrb. */ static void spaceorb_process_packet(struct spaceorb *spaceorb) { struct input_dev *dev = &spaceorb->dev; unsigned char *data = spaceorb->data; unsigned char c = 0; int axes[6]; int i; if (spaceorb->idx < 2) return; for (i = 0; i < spaceorb->idx; i++) c ^= data[i]; if (c) return; switch (data[0]) { case 'R': /* Reset packet */ spaceorb->data[spaceorb->idx - 1] = 0; for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++); printk(KERN_INFO "input: %s [%s] on %s\n", spaceorb_name, spaceorb->data + i, spaceorb->serio->phys); break; case 'D': /* Ball + button data */ if (spaceorb->idx != 12) return; for (i = 0; i < 9; i++) spaceorb->data[i+2] ^= spaceorb_xor[i]; axes[0] = ( data[2] << 3) | (data[ 3] >> 4); axes[1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1); axes[2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5); axes[3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2); axes[4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6); axes[5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3); for (i = 0; i < 6; i++) input_report_abs(dev, spaceorb_axes[i], axes[i] - ((axes[i] & 0x200) ? 1024 : 0)); for (i = 0; i < 6; i++) input_report_key(dev, spaceorb_buttons[i], (data[1] >> i) & 1); break; case 'K': /* Button data */ if (spaceorb->idx != 5) return; for (i = 0; i < 7; i++) input_report_key(dev, spaceorb_buttons[i], (data[2] >> i) & 1); break; case 'E': /* Error packet */ if (spaceorb->idx != 4) return; printk(KERN_ERR "joy-spaceorb: Device error. [ "); for (i = 0; i < 7; i++) if (data[1] & (1 << i)) printk("%s ", spaceorb_errors[i]); printk("]\n"); break; } } static void spaceorb_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { struct spaceorb* spaceorb = serio->private; if (~data & 0x80) { if (spaceorb->idx) spaceorb_process_packet(spaceorb); spaceorb->idx = 0; } if (spaceorb->idx < SPACEORB_MAX_LENGTH) spaceorb->data[spaceorb->idx++] = data & 0x7f; } /* * spaceorb_disconnect() is the opposite of spaceorb_connect() */ static void spaceorb_disconnect(struct serio *serio) { struct spaceorb* spaceorb = serio->private; input_unregister_device(&spaceorb->dev); serio_close(serio); kfree(spaceorb); } /* * spaceorb_connect() is the routine that is called when someone adds a * new serio device. It looks for the SpaceOrb/Avenger, and if found, registers * it as an input device. */ static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) { struct spaceorb *spaceorb; int i, t; if (serio->type != (SERIO_RS232 | SERIO_SPACEORB)) return; if (!(spaceorb = kmalloc(sizeof(struct spaceorb), GFP_KERNEL))) return; memset(spaceorb, 0, sizeof(struct spaceorb)); spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < 6; i++) set_bit(spaceorb_buttons[i], spaceorb->dev.keybit); for (i = 0; i < 6; i++) { t = spaceorb_axes[i]; set_bit(t, spaceorb->dev.absbit); spaceorb->dev.absmin[t] = -508; spaceorb->dev.absmax[t] = 508; } spaceorb->serio = serio; spaceorb->dev.private = spaceorb; sprintf(spaceorb->phys, "%s/input0", serio->phys); spaceorb->dev.name = spaceorb_name; spaceorb->dev.phys = spaceorb->phys; spaceorb->dev.idbus = BUS_RS232; spaceorb->dev.idvendor = SERIO_SPACEORB; spaceorb->dev.idproduct = 0x0001; spaceorb->dev.idversion = 0x0100; serio->private = spaceorb; if (serio_open(serio, dev)) { kfree(spaceorb); return; } input_register_device(&spaceorb->dev); } /* * The serio device structure. */ static struct serio_dev spaceorb_dev = { interrupt: spaceorb_interrupt, connect: spaceorb_connect, disconnect: spaceorb_disconnect, }; /* * The functions for inserting/removing us as a module. */ int __init spaceorb_init(void) { serio_register_device(&spaceorb_dev); return 0; } void __exit spaceorb_exit(void) { serio_unregister_device(&spaceorb_dev); } module_init(spaceorb_init); module_exit(spaceorb_exit); |
From: Vojtech P. <vo...@us...> - 2002-01-22 20:29:06
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input/joystick In directory usw-pr-cvs1:/tmp/cvs-serv5480 Added Files: Tag: 1.17 spaceball.c Log Message: Moved. --- NEW FILE: spaceball.c --- /* * $Id: spaceball.c,v 1.17 2002/01/22 20:29:03 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik * * Based on the work of: * David Thompson * Joseph Krahn */ /* * SpaceTec SpaceBall 2003/3003/4000 FLX 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/init.h> #include <linux/input.h> #include <linux/serio.h> MODULE_AUTHOR("Vojtech Pavlik <vo...@uc...>"); MODULE_DESCRIPTION("SpaceTec SpaceBall 2003/3003/4000 FLX driver"); MODULE_LICENSE("GPL"); /* * Constants. */ #define SPACEBALL_MAX_LENGTH 128 #define SPACEBALL_MAX_ID 8 #define SPACEBALL_1003 1 #define SPACEBALL_2003B 3 #define SPACEBALL_2003C 4 #define SPACEBALL_3003C 7 #define SPACEBALL_4000FLX 8 #define SPACEBALL_4000FLX_L 9 static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY }; static char *spaceball_names[] = { "?", "SpaceTec SpaceBall 1003", "SpaceTec SpaceBall 2003", "SpaceTec SpaceBall 2003B", "SpaceTec SpaceBall 2003C", "SpaceTec SpaceBall 3003", "SpaceTec SpaceBall SpaceController", "SpaceTec SpaceBall 3003C", "SpaceTec SpaceBall 4000FLX", "SpaceTec SpaceBall 4000FLX Lefty" }; /* * Per-Ball data. */ struct spaceball { struct input_dev dev; struct serio *serio; int idx; int escape; unsigned char data[SPACEBALL_MAX_LENGTH]; char phys[32]; }; /* * spaceball_process_packet() decodes packets the driver receives from the * SpaceBall. */ static void spaceball_process_packet(struct spaceball* spaceball) { struct input_dev *dev = &spaceball->dev; unsigned char *data = spaceball->data; int i; if (spaceball->idx < 2) return; switch (spaceball->data[0]) { case 'D': /* Ball data */ if (spaceball->idx != 15) return; for (i = 0; i < 6; i++) input_report_abs(dev, spaceball_axes[i], (__s16)((data[2 * i + 3] << 8) | data[2 * i + 2])); break; case 'K': /* Button data */ if (spaceball->idx != 3) return; input_report_key(dev, BTN_1, (data[2] & 0x01) || (data[2] & 0x20)); input_report_key(dev, BTN_2, data[2] & 0x02); input_report_key(dev, BTN_3, data[2] & 0x04); input_report_key(dev, BTN_4, data[2] & 0x08); input_report_key(dev, BTN_5, data[1] & 0x01); input_report_key(dev, BTN_6, data[1] & 0x02); input_report_key(dev, BTN_7, data[1] & 0x04); input_report_key(dev, BTN_8, data[1] & 0x10); break; case '.': /* Advanced button data */ if (spaceball->idx != 3) return; input_report_key(dev, BTN_1, data[2] & 0x01); input_report_key(dev, BTN_2, data[2] & 0x02); input_report_key(dev, BTN_3, data[2] & 0x04); input_report_key(dev, BTN_4, data[2] & 0x08); input_report_key(dev, BTN_5, data[2] & 0x10); input_report_key(dev, BTN_6, data[2] & 0x20); input_report_key(dev, BTN_7, data[2] & 0x80); input_report_key(dev, BTN_8, data[1] & 0x01); input_report_key(dev, BTN_9, data[1] & 0x02); input_report_key(dev, BTN_A, data[1] & 0x04); input_report_key(dev, BTN_B, data[1] & 0x08); input_report_key(dev, BTN_C, data[1] & 0x10); input_report_key(dev, BTN_MODE, data[1] & 0x20); break; case 'E': /* Device error */ spaceball->data[spaceball->idx - 1] = 0; printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1); break; case '?': /* Bad command packet */ spaceball->data[spaceball->idx - 1] = 0; printk(KERN_ERR "spaceball: Bad command. [%s]\n", spaceball->data + 1); break; } } /* * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor, * and end in 0x0d. It uses '^' as an escape for CR, XOFF and XON characters which * can occur in the axis values. */ static void spaceball_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { struct spaceball *spaceball = serio->private; switch (data) { case 0xd: spaceball_process_packet(spaceball); spaceball->idx = 0; spaceball->escape = 0; return; case '^': if (!spaceball->escape) { spaceball->escape = 1; return; } spaceball->escape = 0; case 'M': case 'Q': case 'S': if (spaceball->escape) { spaceball->escape = 0; data &= 0x1f; } default: if (spaceball->escape) spaceball->escape = 0; if (spaceball->idx < SPACEBALL_MAX_LENGTH) spaceball->data[spaceball->idx++] = data; return; } } /* * spaceball_disconnect() is the opposite of spaceball_connect() */ static void spaceball_disconnect(struct serio *serio) { struct spaceball* spaceball = serio->private; input_unregister_device(&spaceball->dev); serio_close(serio); kfree(spaceball); } /* * spaceball_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 spaceball_connect(struct serio *serio, struct serio_dev *dev) { struct spaceball *spaceball; int i, t, id; if ((serio->type & ~SERIO_ID) != (SERIO_RS232 | SERIO_SPACEBALL)) return; if ((id = (serio->type & SERIO_ID) >> 8) > SPACEBALL_MAX_ID) return; if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL))) return; memset(spaceball, 0, sizeof(struct spaceball)); spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); switch (id) { case SPACEBALL_4000FLX: case SPACEBALL_4000FLX_L: spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_9); spaceball->dev.keybit[LONG(BTN_A)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_MODE); default: spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7) | BIT(BTN_8); case SPACEBALL_3003C: spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_1) | BIT(BTN_8); } for (i = 0; i < 6; i++) { t = spaceball_axes[i]; set_bit(t, spaceball->dev.absbit); spaceball->dev.absmin[t] = i < 3 ? -8000 : -1600; spaceball->dev.absmax[t] = i < 3 ? 8000 : 1600; spaceball->dev.absflat[t] = i < 3 ? 40 : 8; spaceball->dev.absfuzz[t] = i < 3 ? 8 : 2; } spaceball->serio = serio; spaceball->dev.private = spaceball; sprintf(spaceball->phys, "%s/input0", serio->phys); spaceball->dev.name = spaceball_names[id]; spaceball->dev.phys = spaceball->phys; spaceball->dev.idbus = BUS_RS232; spaceball->dev.idvendor = SERIO_SPACEBALL; spaceball->dev.idproduct = id; spaceball->dev.idversion = 0x0100; serio->private = spaceball; if (serio_open(serio, dev)) { kfree(spaceball); return; } input_register_device(&spaceball->dev); printk(KERN_INFO "input: %s on serio%s\n", spaceball_names[id], serio->phys); } /* * The serio device structure. */ static struct serio_dev spaceball_dev = { interrupt: spaceball_interrupt, connect: spaceball_connect, disconnect: spaceball_disconnect, }; /* * The functions for inserting/removing us as a module. */ int __init spaceball_init(void) { serio_register_device(&spaceball_dev); return 0; } void __exit spaceball_exit(void) { serio_unregister_device(&spaceball_dev); } module_init(spaceball_init); module_exit(spaceball_exit); |