summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-06-25 01:20:01 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-06-25 01:20:01 +0000
commit3797ba0b62debb71af4606910acacc9896a9ae3b (patch)
tree414eea76253c7871bfdf3bd9d1817771eb40917c /drivers
parent2b6c0c580795a4404f72d2a794214dd9e080709d (diff)
Merge with Linux 2.4.0-test2.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/DAC960.c3
-rw-r--r--drivers/block/acsi_slm.c2
-rw-r--r--drivers/block/cpqarray.c494
-rw-r--r--drivers/block/elevator.c232
-rw-r--r--drivers/block/floppy.c4
-rw-r--r--drivers/block/ida_cmd.h4
-rw-r--r--drivers/block/ll_rw_blk.c462
-rw-r--r--drivers/block/loop.c2
-rw-r--r--drivers/block/md.c2
-rw-r--r--drivers/block/nbd.c6
-rw-r--r--drivers/block/paride/pg.c2
-rw-r--r--drivers/block/paride/pt.c4
-rw-r--r--drivers/block/rd.c6
-rw-r--r--drivers/block/smart1,2.h7
-rw-r--r--drivers/cdrom/aztcd.c4
-rw-r--r--drivers/cdrom/cdrom.c4
-rw-r--r--drivers/cdrom/gscd.c4
-rw-r--r--drivers/cdrom/optcd.c4
-rw-r--r--drivers/cdrom/sbpcd.c4
-rw-r--r--drivers/cdrom/sjcd.c4
-rw-r--r--drivers/cdrom/sonycd535.c4
-rw-r--r--drivers/char/applicom.c1
-rw-r--r--drivers/char/dsp56k.c4
-rw-r--r--drivers/char/dtlk.c4
-rw-r--r--drivers/char/ftape/zftape/zftape-init.c24
-rw-r--r--drivers/char/i2c-old.c8
-rw-r--r--drivers/char/ip2main.c12
-rw-r--r--drivers/char/istallion.c2
-rw-r--r--drivers/char/joystick/Config.in64
-rw-r--r--drivers/char/joystick/Makefile217
-rw-r--r--drivers/char/joystick/a3d.c387
-rw-r--r--drivers/char/joystick/adi.c554
-rw-r--r--drivers/char/joystick/amijoy.c149
-rw-r--r--drivers/char/joystick/analog.c758
-rw-r--r--drivers/char/joystick/cobra.c250
-rw-r--r--drivers/char/joystick/db9.c423
-rw-r--r--drivers/char/joystick/gamecon.c668
-rw-r--r--drivers/char/joystick/gameport.c198
-rw-r--r--drivers/char/joystick/gf2k.c359
-rw-r--r--drivers/char/joystick/grip.c423
-rw-r--r--drivers/char/joystick/interact.c306
-rw-r--r--drivers/char/joystick/joy-amiga.c143
-rw-r--r--drivers/char/joystick/joy-analog.c295
-rw-r--r--drivers/char/joystick/joy-analog.h287
-rw-r--r--drivers/char/joystick/joy-assassin.c396
-rw-r--r--drivers/char/joystick/joy-console.c811
-rw-r--r--drivers/char/joystick/joy-creative.c267
-rw-r--r--drivers/char/joystick/joy-db9.c421
-rw-r--r--drivers/char/joystick/joy-gravis.c383
-rw-r--r--drivers/char/joystick/joy-lightning.c351
-rw-r--r--drivers/char/joystick/joy-logitech.c534
-rw-r--r--drivers/char/joystick/joy-magellan.c395
-rw-r--r--drivers/char/joystick/joy-pci.c254
-rw-r--r--drivers/char/joystick/joy-sidewinder.c835
-rw-r--r--drivers/char/joystick/joy-spaceball.c343
-rw-r--r--drivers/char/joystick/joy-spaceorb.c301
-rw-r--r--drivers/char/joystick/joy-thrustmaster.c280
-rw-r--r--drivers/char/joystick/joy-turbografx.c267
-rw-r--r--drivers/char/joystick/joy-warrior.c301
-rw-r--r--drivers/char/joystick/joystick.c864
-rw-r--r--drivers/char/joystick/lightning.c300
-rw-r--r--drivers/char/joystick/magellan.c210
-rw-r--r--drivers/char/joystick/ns558.c366
-rw-r--r--drivers/char/joystick/pcigame.c198
-rw-r--r--drivers/char/joystick/serio.c132
-rw-r--r--drivers/char/joystick/serport.c220
-rw-r--r--drivers/char/joystick/sidewinder.c756
-rw-r--r--drivers/char/joystick/spaceball.c231
-rw-r--r--drivers/char/joystick/spaceorb.c225
-rw-r--r--drivers/char/joystick/tmdc.c348
-rw-r--r--drivers/char/joystick/turbografx.c258
-rw-r--r--drivers/char/joystick/warrior.c212
-rw-r--r--drivers/char/lp.c4
-rw-r--r--drivers/char/mem.c12
-rw-r--r--drivers/char/misc.c4
-rw-r--r--drivers/char/ppdev.c2
-rw-r--r--drivers/char/stallion.c2
-rw-r--r--drivers/char/tpqic02.c32
-rw-r--r--drivers/char/tty_io.c13
-rw-r--r--drivers/char/vc_screen.c16
-rw-r--r--drivers/char/videodev.c19
-rw-r--r--drivers/ide/ide-cd.c4
-rw-r--r--drivers/ide/ide-tape.c8
-rw-r--r--drivers/ide/ide.c2
-rw-r--r--drivers/isdn/avmb1/capi.c6
-rw-r--r--drivers/isdn/isdn_common.c20
-rw-r--r--drivers/macintosh/adb.c4
-rw-r--r--drivers/net/Config.in2
-rw-r--r--drivers/net/dmfe.c245
-rw-r--r--drivers/net/dummy.c2
-rw-r--r--drivers/net/irda/irport.c7
-rw-r--r--drivers/net/irda/irtty.c9
-rw-r--r--drivers/net/irda/nsc-ircc.c10
-rw-r--r--drivers/net/irda/toshoboe.c53
-rw-r--r--drivers/net/irda/w83977af_ir.c14
-rw-r--r--drivers/net/ppp_generic.c4
-rw-r--r--drivers/net/wan/cosa.c2
-rw-r--r--drivers/pcmcia/yenta.c29
-rw-r--r--drivers/pnp/isapnp.c55
-rw-r--r--drivers/s390/block/dasd.c5
-rw-r--r--drivers/sbus/audio/audio.c6
-rw-r--r--drivers/sbus/char/bpp.c2
-rw-r--r--drivers/sbus/char/jsflash.c7
-rw-r--r--drivers/sbus/char/sunkbd.c4
-rw-r--r--drivers/sbus/char/vfc_dev.c4
-rw-r--r--drivers/scsi/aic7xxx.c1638
-rw-r--r--drivers/scsi/aic7xxx.h18
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.seq192
-rw-r--r--drivers/scsi/aic7xxx_proc.c1
-rw-r--r--drivers/scsi/aic7xxx_seq.c694
-rw-r--r--drivers/scsi/scsi.c5
-rw-r--r--drivers/scsi/scsi_lib.c12
-rw-r--r--drivers/scsi/scsi_scan.c4
-rw-r--r--drivers/scsi/sg.c4
-rw-r--r--drivers/scsi/sr.c5
-rw-r--r--drivers/scsi/st.c8
-rw-r--r--drivers/sgi/char/shmiq.c6
-rw-r--r--drivers/sound/sound_core.c4
-rw-r--r--drivers/sound/soundcard.c4
-rw-r--r--drivers/telephony/ixj.h1
-rw-r--r--drivers/usb/Config.in5
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/devio.c2
-rw-r--r--drivers/usb/evdev.c36
-rw-r--r--drivers/usb/iforce.c335
-rw-r--r--drivers/usb/input.c4
-rw-r--r--drivers/usb/joydev.c54
-rw-r--r--drivers/usb/mousedev.c55
-rw-r--r--drivers/usb/pegasus.c269
-rw-r--r--drivers/usb/serial/usbserial.c128
-rw-r--r--drivers/usb/serial/visor.c29
-rw-r--r--drivers/usb/usb-storage.c730
-rw-r--r--drivers/usb/usb-storage.h3
-rw-r--r--drivers/usb/wmforce.c190
-rw-r--r--drivers/video/Config.in1
-rw-r--r--drivers/video/fbmem.c4
-rw-r--r--drivers/video/sisfb.c28
137 files changed, 11597 insertions, 10735 deletions
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index c6f8531f4..41ec3e2f5 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -1473,9 +1473,8 @@ static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
Command->SegmentCount = Request->nr_segments;
Command->BufferHeader = Request->bh;
RequestBuffer = Request->buffer;
- Request->rq_status = RQ_INACTIVE;
blkdev_dequeue_request(Request);
- wake_up(&wait_for_request);
+ blkdev_release_request(Request);
if (Command->SegmentCount == 1)
{
DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
index 51bb6b1a3..62758a297 100644
--- a/drivers/block/acsi_slm.c
+++ b/drivers/block/acsi_slm.c
@@ -1009,7 +1009,7 @@ int slm_init( void )
devfs_handle = devfs_mk_dir (NULL, "slm", 3, NULL);
devfs_register_series (devfs_handle, "%u", MAX_SLM, DEVFS_FL_DEFAULT,
- MAJOR_NR, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ MAJOR_NR, 0, S_IFCHR | S_IRUSR | S_IWUSR,
&slm_fops, NULL);
return 0;
}
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 40e639830..9bbe50523 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -22,7 +22,7 @@
* driver, you'll probably need the Compaq Array Controller Interface
* Specificiation (Document number ECG086/1198)
*/
-#include <linux/config.h>
+#include <linux/config.h> /* CONFIG_PROC_FS */
#include <linux/module.h>
#include <linux/version.h>
#include <linux/types.h>
@@ -44,8 +44,8 @@
#define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0.4)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(1,0,4)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.0)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,0)
#define MAJOR_NR COMPAQ_SMART2_MAJOR
#include <linux/blk.h>
#include <linux/blkdev.h>
@@ -73,7 +73,7 @@ static int eisa[8] = { 0, 0 ,0 ,0, 0, 0 ,0 ,0 };
* product = Marketing Name for the board
* access = Address of the struct of function pointers
*/
-struct board_type products[] = {
+static struct board_type products[] = {
{ 0x0040110E, "IDA", &smart1_access },
{ 0x0140110E, "IDA-2", &smart1_access },
{ 0x1040110E, "IAES", &smart1_access },
@@ -87,6 +87,7 @@ struct board_type products[] = {
{ 0x40400E11, "Integrated Array", &smart4_access },
{ 0x40500E11, "Smart Array 4200", &smart4_access },
{ 0x40510E11, "Smart Array 4250ES", &smart4_access },
+ { 0x40580E11, "Smart Array 431", &smart4_access },
};
static struct hd_struct * ida;
@@ -95,7 +96,7 @@ static int * ida_blocksizes;
static int * ida_hardsizes;
static struct gendisk ida_gendisk[MAX_CTLR];
-struct proc_dir_entry *proc_array = NULL;
+static struct proc_dir_entry *proc_array = NULL;
/* Debug... */
#define DBG(s) do { s } while(0)
@@ -106,7 +107,7 @@ struct proc_dir_entry *proc_array = NULL;
/* Debug Extra Paranoid... */
#define DBGPX(s) do { } while(0)
-void cpqarray_init(void);
+int cpqarray_init(void);
static int cpqarray_pci_detect(void);
static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn);
static ulong remap_pci_mem(ulong base, ulong size);
@@ -312,9 +313,8 @@ EXPORT_NO_SYMBOLS;
/* This is a bit of a hack... */
int __init init_module(void)
{
- cpqarray_init();
- if (nr_ctlr == 0)
- return -EIO;
+ if (cpqarray_init() == 0) /* all the block dev numbers already used */
+ return -EIO; /* or no controllers were found */
return 0;
}
@@ -357,8 +357,9 @@ void cleanup_module(void)
/*
* This is it. Find all the controllers and register them. I really hate
* stealing all these major device numbers.
+ * returns the number of block devices registered.
*/
-void __init cpqarray_init(void)
+int __init cpqarray_init(void)
{
void (*request_fns[MAX_CTLR])(request_queue_t *) = {
do_ida_request0, do_ida_request1,
@@ -367,31 +368,52 @@ void __init cpqarray_init(void)
do_ida_request6, do_ida_request7,
};
int i,j;
+ int num_cntlrs_reg = 0;
/* detect controllers */
cpqarray_pci_detect();
cpqarray_eisa_detect();
if (nr_ctlr == 0)
- return;
+ return(num_cntlrs_reg);
printk(DRIVER_NAME "\n");
printk("Found %d controller(s)\n", nr_ctlr);
/* allocate space for disk structs */
ida = kmalloc(sizeof(struct hd_struct)*nr_ctlr*NWD*16, GFP_KERNEL);
-
if(ida==NULL)
- goto bail;
- ida_sizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+ {
+ printk( KERN_ERR "cpqarray: out of memory");
+ return(num_cntlrs_reg);
+ }
+
+ ida_sizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
if(ida_sizes==NULL)
- goto bail2;
+ {
+ kfree(ida);
+ printk( KERN_ERR "cpqarray: out of memory");
+ return(num_cntlrs_reg);
+ }
+
ida_blocksizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
if(ida_blocksizes==NULL)
- goto bail3;
- ida_hardsizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+ {
+ kfree(ida);
+ kfree(ida_sizes);
+ printk( KERN_ERR "cpqarray: out of memory");
+ return(num_cntlrs_reg);
+ }
+
+ ida_hardsizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
if(ida_hardsizes==NULL)
- goto bail4;
+ {
+ kfree(ida);
+ kfree(ida_sizes);
+ kfree(ida_blocksizes);
+ printk( KERN_ERR "cpqarray: out of memory");
+ return(num_cntlrs_reg);
+ }
memset(ida, 0, sizeof(struct hd_struct)*nr_ctlr*NWD*16);
memset(ida_sizes, 0, sizeof(int)*nr_ctlr*NWD*16);
@@ -399,74 +421,90 @@ void __init cpqarray_init(void)
memset(ida_hardsizes, 0, sizeof(int)*nr_ctlr*NWD*16);
memset(ida_gendisk, 0, sizeof(struct gendisk)*MAX_CTLR);
- /*
+ /*
* register block devices
* Find disks and fill in structs
* Get an interrupt, set the Q depth and get into /proc
*/
for(i=0; i< nr_ctlr; i++) {
+ /* If this successful it should insure that we are the only */
+ /* instance of the driver */
+ if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {
+ printk(KERN_ERR "cpqarray: Unable to get major number %d for ida\n",
+ MAJOR_NR+i);
+ continue;
+ }
+
+
hba[i]->access.set_intr_mask(hba[i], 0);
if (request_irq(hba[i]->intr, do_ida_intr,
SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) {
- printk("Unable to get irq %d for %s\n",
+ printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n",
hba[i]->intr, hba[i]->devname);
+ unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
continue;
}
- if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {
- printk("Unable to get major number %d for ida\n",
- MAJOR_NR+i);
- continue;
- }
-
+ num_cntlrs_reg++;
hba[i]->cmd_pool = (cmdlist_t *)kmalloc(
NR_CMDS * sizeof(cmdlist_t), GFP_KERNEL);
hba[i]->cmd_pool_bits = (__u32*)kmalloc(
((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
- if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL)
+ if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL)
{
- int j;
+ nr_ctlr = i;
if(hba[i]->cmd_pool_bits)
kfree(hba[i]->cmd_pool_bits);
if(hba[i]->cmd_pool)
kfree(hba[i]->cmd_pool);
- for(j=0;i<i;j++)
- {
- free_irq(hba[j]->intr, hba[j]);
- unregister_blkdev(MAJOR_NR+j, hba[j]->devname);
- kfree(hba[j]->cmd_pool_bits);
- kfree(hba[j]->cmd_pool);
- }
free_irq(hba[i]->intr, hba[i]);
unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
- goto bail5;
+ num_cntlrs_reg--;
+ printk( KERN_ERR "cpqarray: out of memory");
+
+ /* If num_cntlrs_reg == 0, no controllers worked.
+ * init_module will fail, so clean up global
+ * memory that clean_module would do.
+ */
+
+ if (num_cntlrs_reg == 0)
+ {
+ kfree(ida);
+ kfree(ida_sizes);
+ kfree(ida_hardsizes);
+ kfree(ida_blocksizes);
+ }
+ return(num_cntlrs_reg);
+
}
memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t));
memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32));
- printk("Finding drives on %s", hba[i]->devname);
+ printk(KERN_INFO "cpqarray: Finding drives on %s",
+ hba[i]->devname);
getgeometry(i);
start_fwbk(i);
hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY);
+
ida_procinit(i);
-
- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i), request_fns[i]);
- blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR + i), 0);
+ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i),
+ request_fns[i]);
+ blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR + i), 0);
blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256);
hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256);
-
read_ahead[MAJOR_NR+i] = READ_AHEAD;
+
ida_gendisk[i].major = MAJOR_NR + i;
ida_gendisk[i].major_name = "ida";
ida_gendisk[i].minor_shift = NWD_SHIFT;
ida_gendisk[i].max_p = 16;
ida_gendisk[i].part = ida + (i*256);
ida_gendisk[i].sizes = ida_sizes + (i*256);
- /* ida_gendisk[i].nr_real is handled by getgeometry */
-
+ ida_gendisk[i].nr_real = 0;
+
/* Get on the disk list */
ida_gendisk[i].next = gendisk_head;
gendisk_head = &ida_gendisk[i];
@@ -479,21 +517,13 @@ void __init cpqarray_init(void)
ida_geninit(i);
for(j=0; j<NWD; j++)
- register_disk(&ida_gendisk[i], MKDEV(MAJOR_NR+i,j<<4),
- 16, &ida_fops, hba[i]->drv[j].nr_blks);
+ register_disk(&ida_gendisk[i],
+ MKDEV(MAJOR_NR+i,j<<4),
+ 16, &ida_fops, hba[i]->drv[j].nr_blks);
+
}
/* done ! */
- return;
-bail5:
- kfree(ida_hardsizes);
-bail4:
- kfree(ida_blocksizes);
-bail3:
- kfree(ida_sizes);
-bail2:
- kfree(ida);
-bail:
- printk(KERN_ERR "cpqarray: out of memory.\n");
+ return(num_cntlrs_reg);
}
/*
@@ -506,103 +536,68 @@ static int cpqarray_pci_detect(void)
{
int index;
unchar bus=0, dev_fn=0;
-
- /* This seems dumb, surely we could use an array of types to match ?? */
-
- for(index=0; ; index++) {
- if (pcibios_find_device(PCI_VENDOR_ID_DEC,
- PCI_DEVICE_ID_COMPAQ_42XX, index, &bus, &dev_fn))
- break;
- printk(KERN_DEBUG "42XX Device has been found at %x %x\n",
- bus, dev_fn);
- if (index == 1000000) break;
- if (nr_ctlr == 8) {
- printk("This driver supports a maximum of "
- "8 controllers.\n");
- break;
- }
-
- hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
- if(hba[nr_ctlr]==NULL)
- {
- printk(KERN_ERR "cpqarray: out of memory.\n");
- continue;
- }
- memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
- if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
- continue;
- sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
- hba[nr_ctlr]->ctlr = nr_ctlr;
- nr_ctlr++;
- }
-
- for(index=0; ; index++) {
- unsigned short subvendor=0;
- if (pcibios_find_device(PCI_VENDOR_ID_NCR,
- PCI_DEVICE_ID_NCR_53C1510, index, &bus, &dev_fn))
- break;
- printk(KERN_DEBUG "Integrated RAID Chip has been found at %x %x\n",
- bus, dev_fn);
- if(pcibios_read_config_word(bus, dev_fn,
- PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
- {
- printk(KERN_DEBUG "cpqarray failed to read subvendor\n");
- break;
- }
- if(subvendor != PCI_VENDOR_ID_COMPAQ)
- break;
- printk(KERN_DEBUG "Its a compaq RAID Chip\n");
- if (index == 1000000) break;
- if (nr_ctlr == 8) {
- printk("This driver supports a maximum of "
- "8 controllers.\n");
- break;
- }
+#define IDA_BOARD_TYPES 3
+ static int ida_vendor_id[IDA_BOARD_TYPES] = { PCI_VENDOR_ID_DEC,
+ PCI_VENDOR_ID_NCR, PCI_VENDOR_ID_COMPAQ };
+ static int ida_device_id[IDA_BOARD_TYPES] = { PCI_DEVICE_ID_COMPAQ_42XX, PCI_DEVICE_ID_NCR_53C1510, PCI_DEVICE_ID_COMPAQ_SMART2P };
+ int brdtype;
+
+ /* search for all PCI board types that could be for this driver */
+ for(brdtype=0; brdtype<IDA_BOARD_TYPES; brdtype++)
+ {
+ for(index=0; ; index++) {
+ if (pcibios_find_device(ida_vendor_id[brdtype],
+ ida_device_id[brdtype], index, &bus, &dev_fn))
+ break;
+ printk(KERN_DEBUG "cpqarray: Device %x has been found at %x %x\n",
+ ida_vendor_id[brdtype], bus, dev_fn);
+ if (index == 1000000) break;
+ if (nr_ctlr == 8) {
+ printk(KERN_WARNING "cpqarray: This driver"
+ " supports a maximum of 8 controllers.\n");
+ break;
+ }
- hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
- if(hba[nr_ctlr]==NULL)
- {
- printk(KERN_ERR "cpqarray: out of memory.\n");
- continue;
- }
- memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
- /* DOESNT THIS LEAK MEMORY ?????? - AC */
- if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
- continue;
- sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
- hba[nr_ctlr]->ctlr = nr_ctlr;
- nr_ctlr++;
- }
+/* if it is a PCI_DEVICE_ID_NCR_53C1510, make sure it's the Compaq version of the chip */
+
+ if (ida_device_id[brdtype] == PCI_DEVICE_ID_NCR_53C1510) {
+ unsigned short subvendor=0;
+ if(pcibios_read_config_word(bus, dev_fn,
+ PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
+ {
+ printk(KERN_DEBUG "cpqarray: failed to read subvendor\n");
+ continue;
+ }
+ if(subvendor != PCI_VENDOR_ID_COMPAQ)
+ {
+ printk(KERN_DEBUG
+ "cpqarray: not a Compaq integrated array controller\n");
+ continue;
+ }
+ }
- for(index=0; ; index++) {
- if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ,
- PCI_DEVICE_ID_COMPAQ_SMART2P, index, &bus, &dev_fn))
- break;
+ hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); if(hba[nr_ctlr]==NULL)
+ {
+ printk(KERN_ERR "cpqarray: out of memory.\n");
+ continue;
+ }
+ memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
+ if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
+ {
+ kfree(hba[nr_ctlr]);
+ continue;
+ }
+ sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
+ hba[nr_ctlr]->ctlr = nr_ctlr;
+ nr_ctlr++;
- if (index == 1000000) break;
- if (nr_ctlr == 8) {
- printk("This driver supports a maximum of "
- "8 controllers.\n");
- break;
}
-
- hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
- if(hba[nr_ctlr]==NULL)
- {
- printk(KERN_ERR "cpqarray: out of memory.\n");
- continue;
- }
- memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
- if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
- continue;
- sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
- hba[nr_ctlr]->ctlr = nr_ctlr;
- nr_ctlr++;
}
return nr_ctlr;
}
+
/*
* Find the IO address of the controller, its IRQ and so forth. Fill
* in some basic stuff into the ctlr_info_t structure.
@@ -671,8 +666,9 @@ DBGINFO(
}
}
if (i == NR_PRODUCTS) {
- printk("Sorry, I don't know how to access the SMART Array"
- " controller %08lx\n", (unsigned long)board_id);
+ printk(KERN_WARNING "cpqarray: Sorry, I don't know how"
+ " to access the SMART Array controller %08lx\n",
+ (unsigned long)board_id);
return -1;
}
@@ -734,8 +730,8 @@ static int cpqarray_eisa_detect(void)
while(i<8 && eisa[i]) {
if (nr_ctlr == 8) {
- printk("This driver supports a maximum of "
- "8 controllers.\n");
+ printk(KERN_WARNING "cpqarray: This driver supports"
+ " a maximum of 8 controllers.\n");
break;
}
board_id = inl(eisa[i]+0xC80);
@@ -744,11 +740,11 @@ static int cpqarray_eisa_detect(void)
break;
if (j == NR_PRODUCTS) {
- printk("Sorry, I don't know how to access the SMART"
- " Array controller %08lx\n", (unsigned long)board_id);
+ printk(KERN_WARNING "cpqarray: Sorry, I don't know how"
+ " to access the SMART Array controller %08lx\n", (unsigned long)board_id);
continue;
}
- hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+ hba[nr_ctlr] = (ctlr_info_t *) kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
if(hba[nr_ctlr]==NULL)
{
printk(KERN_ERR "cpqarray: out of memory.\n");
@@ -885,21 +881,34 @@ static void do_ida_request(int ctlr)
queue_head = &blk_dev[MAJOR_NR+ctlr].request_queue.queue_head;
if (list_empty(queue_head))
- goto doreq_done;
+ {
+ start_io(h);
+ return;
+ }
+
creq = blkdev_entry_next_request(queue_head);
if (creq->rq_status == RQ_INACTIVE)
- goto doreq_done;
+ {
+ start_io(h);
+ return;
+ }
+
if (ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ||
- ctlr > nr_ctlr || h == NULL) {
+ ctlr > nr_ctlr || h == NULL)
+ {
printk("doreq cmd for %d, %x at %p\n",
ctlr, creq->rq_dev, creq);
complete_buffers(creq->bh, 0);
- goto doreq_done;
+ start_io(h);
+ return;
}
if ((c = cmd_alloc(h)) == NULL)
- goto doreq_done;
+ {
+ start_io(h);
+ return;
+ }
bh = creq->bh;
@@ -972,9 +981,9 @@ DBGPX( printk("Done with %p\n", creq); );
/* Put the request on the tail of the request queue */
addQ(&h->reqQ, c);
h->Qdepth++;
- if (h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth;
+ if (h->Qdepth > h->maxQsinceinit)
+ h->maxQsinceinit = h->Qdepth;
-doreq_done:
start_io(h);
}
@@ -1022,28 +1031,24 @@ static inline void complete_buffers(struct buffer_head *bh, int ok)
*/
static inline void complete_command(cmdlist_t *cmd, int timeout)
{
- char buf[80];
int ok=1;
if (cmd->req.hdr.rcode & RCODE_NONFATAL &&
(hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) {
- sprintf(buf, "Non Fatal error on ida/c%dd%d\n",
+ printk(KERN_WARNING "Non Fatal error on ida/c%dd%d\n",
cmd->ctlr, cmd->hdr.unit);
- console_print(buf);
hba[cmd->ctlr]->misc_tflags |= MISC_NONFATAL_WARN;
}
if (cmd->req.hdr.rcode & RCODE_FATAL) {
- sprintf(buf, "Fatal error on ida/c%dd%d\n",
+ printk(KERN_WARNING "Fatal error on ida/c%dd%d\n",
cmd->ctlr, cmd->hdr.unit);
- console_print(buf);
ok = 0;
}
if (cmd->req.hdr.rcode & RCODE_INVREQ) {
- sprintf(buf, "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n",
+ printk(KERN_WARNING "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n",
cmd->ctlr, cmd->hdr.unit, cmd->req.hdr.cmd,
cmd->req.hdr.blk, cmd->req.hdr.blk_cnt,
cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);
- console_print(buf);
ok = 0;
}
if (timeout) ok = 0;
@@ -1077,10 +1082,15 @@ static void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs)
if (istat & FIFO_NOT_EMPTY) {
while((a = h->access.command_completed(h))) {
a1 = a; a &= ~3;
- if ((c = h->cmpQ) == NULL) goto bad_completion;
+ if ((c = h->cmpQ) == NULL)
+ {
+ printk(KERN_WARNING "cpqarray: Completion of %08lx ignored\n", (unsigned long)a1);
+ continue;
+ }
while(c->busaddr != a) {
c = c->next;
- if (c == h->cmpQ) break;
+ if (c == h->cmpQ)
+ break;
}
/*
* If we've found the command, take it off the
@@ -1096,8 +1106,6 @@ static void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs)
}
continue;
}
-bad_completion:
- printk("Completion of %08lx ignored\n", (unsigned long)a1);
}
}
@@ -1227,16 +1235,27 @@ static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io)
switch(io->cmd) {
case PASSTHRU_A:
p = kmalloc(io->sg[0].size, GFP_KERNEL);
- if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+ if (!p)
+ {
+ error = -ENOMEM;
+ cmd_free(NULL, c);
+ return(error);
+ }
copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size);
- c->req.bp = virt_to_bus(&(io->c));
+ c->req.hdr.blk = virt_to_bus(&(io->c));
c->req.sg[0].size = io->sg[0].size;
c->req.sg[0].addr = virt_to_bus(p);
c->req.hdr.sg_cnt = 1;
break;
case IDA_READ:
p = kmalloc(io->sg[0].size, GFP_KERNEL);
- if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+ if (!p)
+ {
+ error = -ENOMEM;
+ cmd_free(NULL, c);
+ return(error);
+ }
+
c->req.sg[0].size = io->sg[0].size;
c->req.sg[0].addr = virt_to_bus(p);
c->req.hdr.sg_cnt = 1;
@@ -1245,7 +1264,12 @@ static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io)
case IDA_WRITE_MEDIA:
case DIAG_PASS_THRU:
p = kmalloc(io->sg[0].size, GFP_KERNEL);
- if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+ if (!p)
+ {
+ error = -ENOMEM;
+ cmd_free(NULL, c);
+ return(error);
+ }
copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size);
c->req.sg[0].size = io->sg[0].size;
c->req.sg[0].addr = virt_to_bus(p);
@@ -1284,10 +1308,8 @@ static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io)
}
io->rcode = c->req.hdr.rcode;
- error = 0;
-ioctl_err_exit:
cmd_free(NULL, c);
- return error;
+ return(0);
}
/*
@@ -1390,8 +1412,8 @@ static int sendcmd(
}
udelay(10);
DBG(
- printk("ida%d: idaSendPciCmd FIFO full, waiting!\n",
- ctlr);
+ printk(KERN_WARNING "cpqarray ida%d: idaSendPciCmd FIFO full,"
+ " waiting!\n", ctlr);
);
}
/*
@@ -1401,16 +1423,16 @@ DBG(
complete = pollcomplete(ctlr);
if (complete != 1) {
if (complete != c->busaddr) {
- printk(
- "ida%d: idaSendPciCmd "
+ printk( KERN_WARNING
+ "cpqarray ida%d: idaSendPciCmd "
"Invalid command list address returned! (%08lx)\n",
ctlr, (unsigned long)complete);
cmd_free(info_p, c);
return (IO_ERROR);
}
} else {
- printk(
- "ida%d: idaSendPciCmd Timeout out, "
+ printk( KERN_WARNING
+ "cpqarray ida%d: idaSendPciCmd Timeout out, "
"No command list address returned!\n",
ctlr);
cmd_free(info_p, c);
@@ -1419,9 +1441,9 @@ DBG(
if (c->req.hdr.rcode & 0x00FE) {
if (!(c->req.hdr.rcode & BIG_PROBLEM)) {
- printk(
- "ida%d: idaSendPciCmd, error: Controller failed "
- "at init time "
+ printk( KERN_WARNING
+ "cpqarray ida%d: idaSendPciCmd, error: "
+ "Controller failed at init time "
"cmd: 0x%x, return code = 0x%x\n",
ctlr, c->req.hdr.cmd, c->req.hdr.rcode);
@@ -1461,8 +1483,8 @@ static int revalidate_allvol(kdev_t dev)
spin_lock_irqsave(&io_request_lock, flags);
if (hba[ctlr]->usage_count > 1) {
spin_unlock_irqrestore(&io_request_lock, flags);
- printk("Device busy for volume revalidation (usage=%d)\n",
- hba[ctlr]->usage_count);
+ printk(KERN_WARNING "cpqarray: Device busy for volume"
+ " revalidation (usage=%d)\n", hba[ctlr]->usage_count);
return -EBUSY;
}
spin_unlock_irqrestore(&io_request_lock, flags);
@@ -1514,8 +1536,9 @@ static int revalidate_logvol(kdev_t dev, int maxusage)
spin_lock_irqsave(&io_request_lock, flags);
if (hba[ctlr]->drv[target].usage_count > maxusage) {
spin_unlock_irqrestore(&io_request_lock, flags);
- printk("Device busy for revalidation (usage=%d)\n",
- hba[ctlr]->drv[target].usage_count);
+ printk(KERN_WARNING "cpqarray: Device busy for "
+ "revalidation (usage=%d)\n",
+ hba[ctlr]->drv[target].usage_count);
return -EBUSY;
}
@@ -1581,22 +1604,28 @@ static void start_fwbk(int ctlr)
id_ctlr_t *id_ctlr_buf;
int ret_code;
- if( hba[ctlr]->board_id != 0x40400E11)
+ if( (hba[ctlr]->board_id != 0x40400E11)
+ && (hba[ctlr]->board_id != 0x40480E11) )
+
/* Not a Integrated Raid, so there is nothing for us to do */
return;
- printk(KERN_DEBUG "Starting firmware's background processing\n");
+ printk(KERN_DEBUG "cpqarray: Starting firmware's background"
+ " processing\n");
/* Command does not return anything, but idasend command needs a
buffer */
id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
if(id_ctlr_buf==NULL)
{
- printk(KERN_WARNING "Out of memory. Unable to start background processing.\n");
+ printk(KERN_WARNING "cpqarray: Out of memory. "
+ "Unable to start background processing.\n");
return;
}
ret_code = sendcmd(RESUME_BACKGROUND_ACTIVITY, ctlr,
id_ctlr_buf, 0, 0, 0, 0);
if(ret_code != IO_OK)
- printk(KERN_WARNING "Unable to start background processing\n");
+ printk(KERN_WARNING "cpqarray: Unable to start"
+ " background processing\n");
+
kfree(id_ctlr_buf);
}
/*****************************************************************
@@ -1620,16 +1649,38 @@ static void getgeometry(int ctlr)
id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
if(id_ldrive == NULL)
+ {
+ printk( KERN_ERR "cpqarray: out of memory.\n");
return;
+ }
+
id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
if(id_ctlr_buf == NULL)
- goto bail2;
+ {
+ kfree(id_ldrive);
+ printk( KERN_ERR "cpqarray: out of memory.\n");
+ return;
+ }
+
id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
if(id_lstatus_buf == NULL)
- goto bail3;
+ {
+ kfree(id_ctlr_buf);
+ kfree(id_ldrive);
+ printk( KERN_ERR "cpqarray: out of memory.\n");
+ return;
+ }
+
sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL);
if(sense_config_buf == NULL)
- goto bail4;
+ {
+ kfree(id_lstatus_buf);
+ kfree(id_ctlr_buf);
+ kfree(id_ldrive);
+ printk( KERN_ERR "cpqarray: out of memory.\n");
+ return;
+ }
+
memset(id_ldrive, 0, sizeof(id_log_drv_t));
memset(id_ctlr_buf, 0, sizeof(id_ctlr_t));
memset(id_lstatus_buf, 0, sizeof(sense_log_drv_stat_t));
@@ -1648,8 +1699,15 @@ static void getgeometry(int ctlr)
* so the idastubopen will fail on all logical drives
* on the controller.
*/
- goto geo_ret; /* release the buf and return */
- }
+ /* Free all the buffers and return */
+ printk(KERN_ERR "cpqarray: error sending ID controller\n");
+ kfree(sense_config_buf);
+ kfree(id_lstatus_buf);
+ kfree(id_ctlr_buf);
+ kfree(id_ldrive);
+ return;
+ }
+
info_p->log_drives = id_ctlr_buf->nr_drvs;;
*(__u32*)(info_p->firm_rev) = *(__u32*)(id_ctlr_buf->firm_rev);
info_p->ctlr_sig = id_ctlr_buf->cfg_sig;
@@ -1663,8 +1721,9 @@ static void getgeometry(int ctlr)
* Get drive geometry for all logical drives
*/
if (id_ctlr_buf->nr_drvs > 16)
- printk("ida%d: This driver supports 16 logical drives "
- "per controller.\n. Additional drives will not be "
+ printk(KERN_WARNING "cpqarray ida%d: This driver supports "
+ "16 logical drives per controller.\n. "
+ " Additional drives will not be "
"detected\n", ctlr);
for (log_unit = 0;
@@ -1687,13 +1746,17 @@ static void getgeometry(int ctlr)
on the controller.
*/
info_p->log_drv_map = 0;
- printk(
- "ida%d: idaGetGeometry - Controller failed "
- "to report status of logical drive %d\n"
+ printk( KERN_WARNING
+ "cpqarray ida%d: idaGetGeometry - Controller"
+ " failed to report status of logical drive %d\n"
"Access to this controller has been disabled\n",
ctlr, log_unit);
- goto geo_ret; /* release the buf and return */
-
+ /* Free all the buffers and return */
+ kfree(sense_config_buf);
+ kfree(id_lstatus_buf);
+ kfree(id_ctlr_buf);
+ kfree(id_ldrive);
+ return;
}
/*
Make sure the logical drive is configured
@@ -1715,14 +1778,21 @@ static void getgeometry(int ctlr)
drv->sectors = id_ldrive->drv.sect_per_track;
info_p->log_drv_map |= (1 << log_unit);
- printk("ida/c%dd%d: blksz=%d nr_blks=%d\n",
+ printk(KERN_INFO "cpqarray ida/c%dd%d: blksz=%d nr_blks=%d\n",
ctlr, log_unit, drv->blk_size, drv->nr_blks);
ret_code = sendcmd(SENSE_CONFIG,
ctlr, sense_config_buf,
sizeof(config_t), 0, 0, log_unit);
if (ret_code == IO_ERROR) {
info_p->log_drv_map = 0;
- goto geo_ret; /* release the buf and return */
+ /* Free all the buffers and return */
+ printk(KERN_ERR "cpqarray: error sending sense config\n");
+ kfree(sense_config_buf);
+ kfree(id_lstatus_buf);
+ kfree(id_ctlr_buf);
+ kfree(id_ldrive);
+ return;
+
}
info_p->phys_drives =
sense_config_buf->ctlr_phys_drv;
@@ -1736,12 +1806,10 @@ static void getgeometry(int ctlr)
log_index = log_index + 1;
} /* end of if logical drive configured */
} /* end of for log_unit */
-geo_ret:
kfree(sense_config_buf);
-bail4:
- kfree(id_ldrive);
-bail3:
- kfree(id_lstatus_buf);
-bail2:
+ kfree(id_ldrive);
+ kfree(id_lstatus_buf);
kfree(id_ctlr_buf);
+ return;
+
}
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c
index 26f02abe3..2bf92251c 100644
--- a/drivers/block/elevator.c
+++ b/drivers/block/elevator.c
@@ -4,6 +4,16 @@
* Block device elevator/IO-scheduler.
*
* Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
+ *
+ * 30042000 Jens Axboe <axboe@suse.de> :
+ *
+ * Split the elevator a bit so that it is possible to choose a different
+ * one or even write a new "plug in". There are three pieces:
+ * - elevator_fn, inserts a new request in the queue list
+ * - elevator_merge_fn, decides whether a new buffer can be merged with
+ * an existing request
+ * - elevator_dequeue_fn, called when a request is taken off the active list
+ *
*/
#include <linux/fs.h>
@@ -12,9 +22,9 @@
#include <linux/blk.h>
#include <asm/uaccess.h>
-static void elevator_default(struct request * req, elevator_t * elevator,
- struct list_head * real_head,
- struct list_head * head, int orig_latency)
+void elevator_default(struct request *req, elevator_t * elevator,
+ struct list_head * real_head,
+ struct list_head * head, int orig_latency)
{
struct list_head * entry = real_head, * point = NULL;
struct request * tmp;
@@ -22,6 +32,12 @@ static void elevator_default(struct request * req, elevator_t * elevator,
int latency = orig_latency -= elevator->nr_segments, pass = 0;
int point_latency = 0xbeefbeef;
+ if (list_empty(real_head)) {
+ req->elevator_sequence = elevator_sequence(elevator, orig_latency);
+ list_add(&req->queue, real_head);
+ return;
+ }
+
while ((entry = entry->prev) != head) {
if (!point && latency >= 0) {
point = entry;
@@ -49,19 +65,189 @@ static void elevator_default(struct request * req, elevator_t * elevator,
req->elevator_sequence = elevator_sequence(elevator, latency);
}
+int elevator_default_merge(request_queue_t *q, struct request **req,
+ struct buffer_head *bh, int rw,
+ int *max_sectors, int *max_segments)
+{
+ struct list_head *entry, *head = &q->queue_head;
+ unsigned int count = bh->b_size >> 9;
+ elevator_t *elevator = &q->elevator;
+ int orig_latency, latency, sequence, action, starving = 0;
+
+ /*
+ * Avoid write-bombs as not to hurt interactiveness of reads
+ */
+ if (rw == WRITE)
+ *max_segments = elevator->max_bomb_segments;
+
+ latency = orig_latency = elevator_request_latency(elevator, rw);
+ sequence = elevator->sequence;
+
+ entry = head;
+ if (q->head_active && !q->plugged)
+ head = head->next;
+
+ while ((entry = entry->prev) != head && !starving) {
+ *req = blkdev_entry_to_request(entry);
+ latency += (*req)->nr_segments;
+ if (elevator_sequence_before((*req)->elevator_sequence, sequence))
+ starving = 1;
+ if (latency < 0)
+ continue;
+ if ((*req)->sem)
+ continue;
+ if ((*req)->cmd != rw)
+ continue;
+ if ((*req)->nr_sectors + count > *max_sectors)
+ continue;
+ if ((*req)->rq_dev != bh->b_rdev)
+ continue;
+ if ((*req)->sector + (*req)->nr_sectors == bh->b_rsector) {
+ if (latency - (*req)->nr_segments < 0)
+ break;
+ action = ELEVATOR_BACK_MERGE;
+ } else if ((*req)->sector - count == bh->b_rsector) {
+ if (starving)
+ break;
+ action = ELEVATOR_FRONT_MERGE;
+ } else {
+ continue;
+ }
+ q->elevator.sequence++;
+ return action;
+ }
+ return ELEVATOR_NO_MERGE;
+}
+
+inline void elevator_default_dequeue(struct request *req)
+{
+ if (req->cmd == READ)
+ req->e->read_pendings--;
+
+ req->e->nr_segments -= req->nr_segments;
+}
+
+/*
+ * Order ascending, but only allow a request to be skipped a certain
+ * number of times
+ */
+void elevator_linus(struct request *req, elevator_t *elevator,
+ struct list_head *real_head,
+ struct list_head *head, int orig_latency)
+{
+ struct list_head *entry = real_head;
+ struct request *tmp;
+
+ if (list_empty(real_head)) {
+ list_add(&req->queue, real_head);
+ return;
+ }
+
+ while ((entry = entry->prev) != head) {
+ tmp = blkdev_entry_to_request(entry);
+ if (!tmp->elevator_sequence)
+ break;
+ if (IN_ORDER(tmp, req))
+ break;
+ tmp->elevator_sequence--;
+ }
+ list_add(&req->queue, entry);
+}
+
+int elevator_linus_merge(request_queue_t *q, struct request **req,
+ struct buffer_head *bh, int rw,
+ int *max_sectors, int *max_segments)
+{
+ struct list_head *entry, *head = &q->queue_head;
+ unsigned int count = bh->b_size >> 9;
+
+ entry = head;
+ if (q->head_active && !q->plugged)
+ head = head->next;
+
+ while ((entry = entry->prev) != head) {
+ *req = blkdev_entry_to_request(entry);
+ if (!(*req)->elevator_sequence)
+ break;
+ if ((*req)->sem)
+ continue;
+ if ((*req)->cmd != rw)
+ continue;
+ if ((*req)->nr_sectors + count > *max_sectors)
+ continue;
+ if ((*req)->rq_dev != bh->b_rdev)
+ continue;
+ if ((*req)->sector + (*req)->nr_sectors == bh->b_rsector)
+ return ELEVATOR_BACK_MERGE;
+ if ((*req)->sector - count == bh->b_rsector)
+ return ELEVATOR_FRONT_MERGE;
+ (*req)->elevator_sequence--;
+ }
+ return ELEVATOR_NO_MERGE;
+}
+
+/*
+ * No request sorting, just add it to the back of the list
+ */
+void elevator_noop(struct request *req, elevator_t *elevator,
+ struct list_head *real_head, struct list_head *head,
+ int orig_latency)
+{
+ list_add_tail(&req->queue, real_head);
+}
+
+/*
+ * See if we can find a request that is buffer can be coalesced with.
+ */
+int elevator_noop_merge(request_queue_t *q, struct request **req,
+ struct buffer_head *bh, int rw,
+ int *max_sectors, int *max_segments)
+{
+ struct list_head *entry, *head = &q->queue_head;
+ unsigned int count = bh->b_size >> 9;
+
+ if (q->head_active && !q->plugged)
+ head = head->next;
+
+ entry = head;
+ while ((entry = entry->prev) != head) {
+ *req = blkdev_entry_to_request(entry);
+ if ((*req)->sem)
+ continue;
+ if ((*req)->cmd != rw)
+ continue;
+ if ((*req)->nr_sectors + count > *max_sectors)
+ continue;
+ if ((*req)->rq_dev != bh->b_rdev)
+ continue;
+ if ((*req)->sector + (*req)->nr_sectors == bh->b_rsector)
+ return ELEVATOR_BACK_MERGE;
+ if ((*req)->sector - count == bh->b_rsector)
+ return ELEVATOR_FRONT_MERGE;
+ }
+ return ELEVATOR_NO_MERGE;
+}
+
+/*
+ * The noop "elevator" does not do any accounting
+ */
+void elevator_noop_dequeue(struct request *req) {}
+
#ifdef ELEVATOR_DEBUG
-void elevator_debug(request_queue_t * q, kdev_t dev)
+void elevator_default_debug(request_queue_t * q, kdev_t dev)
{
int read_pendings = 0, nr_segments = 0;
elevator_t * elevator = &q->elevator;
struct list_head * entry = &q->queue_head;
static int counter;
+ if (elevator->elevator_fn != elevator_default)
+ return;
+
if (counter++ % 100)
return;
- while ((entry = entry->prev) != &q->queue_head)
- {
+ while ((entry = entry->prev) != &q->queue_head) {
struct request * req;
req = blkdev_entry_to_request(entry);
@@ -81,16 +267,14 @@ void elevator_debug(request_queue_t * q, kdev_t dev)
nr_segments += req->nr_segments;
}
- if (read_pendings != elevator->read_pendings)
- {
+ if (read_pendings != elevator->read_pendings) {
printk(KERN_WARNING
"%s: elevator read_pendings %d should be %d\n",
kdevname(dev), elevator->read_pendings,
read_pendings);
elevator->read_pendings = read_pendings;
}
- if (nr_segments != elevator->nr_segments)
- {
+ if (nr_segments != elevator->nr_segments) {
printk(KERN_WARNING
"%s: elevator nr_segments %d should be %d\n",
kdevname(dev), elevator->nr_segments,
@@ -102,7 +286,6 @@ void elevator_debug(request_queue_t * q, kdev_t dev)
int blkelvget_ioctl(elevator_t * elevator, blkelv_ioctl_arg_t * arg)
{
- int ret;
blkelv_ioctl_arg_t output;
output.queue_ID = elevator->queue_ID;
@@ -110,44 +293,37 @@ int blkelvget_ioctl(elevator_t * elevator, blkelv_ioctl_arg_t * arg)
output.write_latency = elevator->write_latency;
output.max_bomb_segments = elevator->max_bomb_segments;
- ret = -EFAULT;
if (copy_to_user(arg, &output, sizeof(blkelv_ioctl_arg_t)))
- goto out;
- ret = 0;
- out:
- return ret;
+ return -EFAULT;
+
+ return 0;
}
int blkelvset_ioctl(elevator_t * elevator, const blkelv_ioctl_arg_t * arg)
{
blkelv_ioctl_arg_t input;
- int ret;
- ret = -EFAULT;
if (copy_from_user(&input, arg, sizeof(blkelv_ioctl_arg_t)))
- goto out;
+ return -EFAULT;
- ret = -EINVAL;
if (input.read_latency < 0)
- goto out;
+ return -EINVAL;
if (input.write_latency < 0)
- goto out;
+ return -EINVAL;
if (input.max_bomb_segments <= 0)
- goto out;
+ return -EINVAL;
elevator->read_latency = input.read_latency;
elevator->write_latency = input.write_latency;
elevator->max_bomb_segments = input.max_bomb_segments;
- ret = 0;
- out:
- return ret;
+ return 0;
}
-void elevator_init(elevator_t * elevator)
+void elevator_init(elevator_t * elevator, elevator_t type)
{
static unsigned int queue_ID;
- *elevator = ELEVATOR_DEFAULTS;
+ *elevator = type;
elevator->queue_ID = queue_ID++;
}
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 8f4734818..1fcd8b73f 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3878,10 +3878,10 @@ static void __init register_devfs_entries (int drive)
char name[16];
sprintf (name, "%d%s", drive, table[table_sup[UDP->cmos][i]]);
- devfs_register (devfs_handle, name, 0, DEVFS_FL_DEFAULT, MAJOR_NR,
+ devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, MAJOR_NR,
base_minor + (table_sup[UDP->cmos][i] << 2),
S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP,
- 0, 0, &floppy_fops, NULL);
+ &floppy_fops, NULL);
} while (table_sup[UDP->cmos][i++]);
}
}
diff --git a/drivers/block/ida_cmd.h b/drivers/block/ida_cmd.h
index 056863b60..6d57a85ee 100644
--- a/drivers/block/ida_cmd.h
+++ b/drivers/block/ida_cmd.h
@@ -191,7 +191,7 @@ typedef struct {
__u8 expn_fail;
__u8 unit_flags;
__u16 big_fail_map[8];
- __u16 big_remap_map[8];
+ __u16 big_remap_map[128];
__u16 big_repl_map[8];
__u16 big_act_spare_map[8];
__u8 big_spar_repl_map[128];
@@ -336,7 +336,7 @@ typedef struct {
__u32 sense_info;
__u8 sense_code;
__u8 sense_qual;
- __u8 residual;
+ __u32 residual;
__u8 reserved[4];
__u8 cdb[12];
} scsi_param_t;
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 18c7dc1fa..2ed93b300 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -4,6 +4,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1994, Karl Keyte: Added support for disk statistics
* Elevator latency, (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
+ * Queue request tables / lock, selectable elevator, Jens Axboe <axboe@suse.de>
*/
/*
@@ -37,10 +38,9 @@ extern int mac_floppy_init(void);
#endif
/*
- * The request-struct contains all necessary data
- * to load a nr of sectors into memory
+ * For the allocated request tables
*/
-static struct request all_requests[NR_REQUEST];
+static kmem_cache_t *request_cachep;
/*
* The "disk" task queue is used to start the actual requests
@@ -62,11 +62,6 @@ DECLARE_TASK_QUEUE(tq_disk);
*/
spinlock_t io_request_lock = SPIN_LOCK_UNLOCKED;
-/*
- * used to wait on when there are no free requests
- */
-DECLARE_WAIT_QUEUE_HEAD(wait_for_request);
-
/* This specifies how many sectors to read ahead on the disk. */
int read_ahead[MAX_BLKDEV];
@@ -127,29 +122,61 @@ static inline int get_max_sectors(kdev_t dev)
return max_sectors[MAJOR(dev)][MINOR(dev)];
}
+static inline request_queue_t *__blk_get_queue(kdev_t dev)
+{
+ struct blk_dev_struct *bdev = blk_dev + MAJOR(dev);
+
+ if (bdev->queue)
+ return bdev->queue(dev);
+ else
+ return &blk_dev[MAJOR(dev)].request_queue;
+}
+
/*
* NOTE: the device-specific queue() functions
* have to be atomic!
*/
-request_queue_t * blk_get_queue (kdev_t dev)
+request_queue_t *blk_get_queue(kdev_t dev)
{
- int major = MAJOR(dev);
- struct blk_dev_struct *bdev = blk_dev + major;
- unsigned long flags;
request_queue_t *ret;
+ unsigned long flags;
spin_lock_irqsave(&io_request_lock,flags);
- if (bdev->queue)
- ret = bdev->queue(dev);
- else
- ret = &blk_dev[major].request_queue;
+ ret = __blk_get_queue(dev);
spin_unlock_irqrestore(&io_request_lock,flags);
return ret;
}
+/*
+ * Hopefully the low level driver has finished any out standing requests
+ * first...
+ */
void blk_cleanup_queue(request_queue_t * q)
{
+ struct list_head *entry;
+ struct request *rq;
+ int i = QUEUE_NR_REQUESTS;
+
+ if (list_empty(&q->request_freelist))
+ return;
+
+ if (q->queue_requests)
+ BUG();
+
+ entry = &q->request_freelist;
+ entry = entry->next;
+ do {
+ rq = list_entry(entry, struct request, table);
+ entry = entry->next;
+ list_del(&rq->table);
+ kmem_cache_free(request_cachep, rq);
+ i--;
+ } while (!list_empty(&q->request_freelist));
+
+ if (i)
+ printk("blk_cleanup_queue: leaked requests (%d)\n", i);
+
memset(q, 0, sizeof(*q));
}
@@ -222,7 +249,7 @@ static int ll_merge_requests_fn(request_queue_t *q, struct request *req,
* This is called with interrupts off and no requests on the queue.
* (and with the request spinlock aquired)
*/
-static void generic_plug_device (request_queue_t *q, kdev_t dev)
+static void generic_plug_device(request_queue_t *q, kdev_t dev)
{
#ifdef CONFIG_BLK_DEV_MD
if (MAJOR(dev) == MD_MAJOR) {
@@ -230,25 +257,51 @@ static void generic_plug_device (request_queue_t *q, kdev_t dev)
BUG();
}
#endif
- if (!list_empty(&q->queue_head))
+ /*
+ * no need to replug device
+ */
+ if (!list_empty(&q->queue_head) || q->plugged)
return;
q->plugged = 1;
queue_task(&q->plug_tq, &tq_disk);
}
+static void blk_init_free_list(request_queue_t *q)
+{
+ struct request *rq;
+ int i;
+
+ /*
+ * Divide requests in half between read and write. This used to
+ * be a 2/3 advantage for reads, but now reads can steal from
+ * the write free list.
+ */
+ for (i = 0; i < QUEUE_NR_REQUESTS; i++) {
+ rq = kmem_cache_alloc(request_cachep, SLAB_KERNEL);
+ rq->rq_status = RQ_INACTIVE;
+ list_add(&rq->table, &q->request_freelist);
+ }
+
+ q->queue_requests = 0;
+ init_waitqueue_head(&q->wait_for_request);
+ spin_lock_init(&q->request_lock);
+}
+
void blk_init_queue(request_queue_t * q, request_fn_proc * rfn)
{
INIT_LIST_HEAD(&q->queue_head);
- elevator_init(&q->elevator);
+ INIT_LIST_HEAD(&q->request_freelist);
+ elevator_init(&q->elevator, ELEVATOR_LINUS);
+ blk_init_free_list(q);
q->request_fn = rfn;
q->back_merge_fn = ll_back_merge_fn;
q->front_merge_fn = ll_front_merge_fn;
q->merge_requests_fn = ll_merge_requests_fn;
q->make_request_fn = NULL;
- q->plug_tq.sync = 0;
+ q->plug_tq.sync = 0;
q->plug_tq.routine = &generic_unplug_device;
- q->plug_tq.data = q;
+ q->plug_tq.data = q;
q->plugged = 0;
/*
* These booleans describe the queue properties. We set the
@@ -263,89 +316,88 @@ void blk_init_queue(request_queue_t * q, request_fn_proc * rfn)
/*
* remove the plug and let it rip..
*/
-void generic_unplug_device(void * data)
+static inline void __generic_unplug_device(request_queue_t *q)
{
- request_queue_t * q = (request_queue_t *) data;
- unsigned long flags;
-
- spin_lock_irqsave(&io_request_lock,flags);
if (q->plugged) {
q->plugged = 0;
if (!list_empty(&q->queue_head))
- (q->request_fn)(q);
+ q->request_fn(q);
}
- spin_unlock_irqrestore(&io_request_lock,flags);
}
+void generic_unplug_device(void *data)
+{
+ request_queue_t *q = (request_queue_t *) data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ __generic_unplug_device(q);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+#define blkdev_free_rq(list) list_entry((list)->next, struct request, table);
/*
- * look for a free request in the first N entries.
- * NOTE: interrupts must be disabled on the way in (on SMP the request queue
- * spinlock has to be aquired), and will still be disabled on the way out.
+ * Get a free request. io_request_lock must be held and interrupts
+ * disabled on the way in.
*/
-static inline struct request * get_request(int n, kdev_t dev)
+static inline struct request *get_request(request_queue_t *q, int rw)
{
- static struct request *prev_found = NULL, *prev_limit = NULL;
- register struct request *req, *limit;
+ register struct request *rq = NULL;
- if (n <= 0)
- panic("get_request(%d): impossible!\n", n);
+ if (!list_empty(&q->request_freelist)) {
+ elevator_t *e = &q->elevator;
- limit = all_requests + n;
- if (limit != prev_limit) {
- prev_limit = limit;
- prev_found = all_requests;
- }
- req = prev_found;
- for (;;) {
- req = ((req > all_requests) ? req : limit) - 1;
- if (req->rq_status == RQ_INACTIVE)
- break;
- if (req == prev_found)
+ if ((q->queue_requests > QUEUE_WRITES_MAX) && (rw == WRITE))
return NULL;
+
+ rq = blkdev_free_rq(&q->request_freelist);
+ list_del(&rq->table);
+ rq->rq_status = RQ_ACTIVE;
+ rq->special = NULL;
+ rq->q = q;
+ if (rq->cmd == READ)
+ rq->elevator_sequence = e->read_latency;
+ else
+ rq->elevator_sequence = e->write_latency;
+ q->queue_requests++;
}
- prev_found = req;
- req->rq_status = RQ_ACTIVE;
- req->rq_dev = dev;
- req->special = NULL;
- return req;
+ return rq;
}
/*
- * wait until a free request in the first N entries is available.
+ * No available requests for this queue, unplug the device.
*/
-static struct request * __get_request_wait(int n, kdev_t dev)
+static struct request *__get_request_wait(request_queue_t *q, int rw)
{
- register struct request *req;
+ register struct request *rq;
DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- add_wait_queue_exclusive(&wait_for_request, &wait);
+ add_wait_queue_exclusive(&q->wait_for_request, &wait);
for (;;) {
- __set_current_state(TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE);
- spin_lock_irqsave(&io_request_lock,flags);
- req = get_request(n, dev);
- spin_unlock_irqrestore(&io_request_lock,flags);
- if (req)
+ __set_current_state(TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ spin_lock_irq(&io_request_lock);
+ rq = get_request(q, rw);
+ spin_unlock_irq(&io_request_lock);
+ if (rq)
break;
- run_task_queue(&tq_disk);
+ generic_unplug_device(q);
schedule();
}
- remove_wait_queue(&wait_for_request, &wait);
+ remove_wait_queue(&q->wait_for_request, &wait);
current->state = TASK_RUNNING;
- return req;
+ return rq;
}
-static inline struct request * get_request_wait(int n, kdev_t dev)
+static inline struct request *get_request_wait(request_queue_t *q, int rw)
{
- register struct request *req;
- unsigned long flags;
-
- spin_lock_irqsave(&io_request_lock,flags);
- req = get_request(n, dev);
- spin_unlock_irqrestore(&io_request_lock,flags);
- if (req)
- return req;
- return __get_request_wait(n, dev);
+ register struct request *rq;
+
+ spin_lock_irq(&io_request_lock);
+ rq = get_request(q, rw);
+ spin_unlock_irq(&io_request_lock);
+ if (rq)
+ return rq;
+ return __get_request_wait(q, rw);
}
/* RO fail safe mechanism */
@@ -405,36 +457,45 @@ inline void drive_stat_acct (kdev_t dev, int rw,
*/
static inline void add_request(request_queue_t * q, struct request * req,
- struct list_head * head, int latency)
+ struct list_head *head, int lat)
{
int major;
drive_stat_acct(req->rq_dev, req->cmd, req->nr_sectors, 1);
-
- elevator_account_request(&q->elevator, req);
- if (list_empty(head)) {
- req->elevator_sequence = elevator_sequence(&q->elevator, latency);
- list_add(&req->queue, &q->queue_head);
- return;
- }
- q->elevator.elevator_fn(req, &q->elevator, &q->queue_head, head, latency);
-
+ elevator_account_request(req);
/*
+ * let selected elevator insert the request
+ */
+ q->elevator.elevator_fn(req, &q->elevator, &q->queue_head, head, lat);
+
+ /*
* FIXME(eric) I don't understand why there is a need for this
* special case code. It clearly doesn't fit any more with
* the new queueing architecture, and it got added in 2.3.10.
* I am leaving this in here until I hear back from the COMPAQ
* people.
- */
+ */
major = MAJOR(req->rq_dev);
if (major >= COMPAQ_SMART2_MAJOR+0 && major <= COMPAQ_SMART2_MAJOR+7)
- {
(q->request_fn)(q);
- }
-
if (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7)
- {
(q->request_fn)(q);
+}
+
+/*
+ * Must be called with io_request_lock held and interrupts disabled
+ */
+void inline blkdev_release_request(struct request *req)
+{
+ req->rq_status = RQ_INACTIVE;
+
+ /*
+ * Request may not have originated from ll_rw_blk
+ */
+ if (req->q) {
+ list_add(&req->table, &req->q->request_freelist);
+ req->q->queue_requests--;
+ wake_up(&req->q->wait_for_request);
}
}
@@ -462,13 +523,12 @@ static void attempt_merge(request_queue_t * q,
if(!(q->merge_requests_fn)(q, req, next, max_segments))
return;
- elevator_merge_requests(&q->elevator, req, next);
+ elevator_merge_requests(req, next);
req->bhtail->b_reqnext = next->bh;
req->bhtail = next->bhtail;
req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors;
- next->rq_status = RQ_INACTIVE;
list_del(&next->queue);
- wake_up (&wait_for_request);
+ blkdev_release_request(next);
}
static inline void attempt_back_merge(request_queue_t * q,
@@ -496,18 +556,16 @@ static inline void attempt_front_merge(request_queue_t * q,
}
static inline void __make_request(request_queue_t * q, int rw,
- struct buffer_head * bh)
+ struct buffer_head * bh)
{
int major = MAJOR(bh->b_rdev);
unsigned int sector, count;
int max_segments = MAX_SEGMENTS;
- struct request * req;
- int rw_ahead, max_req, max_sectors;
- unsigned long flags;
-
- int orig_latency, latency, starving, sequence;
- struct list_head * entry, * head = &q->queue_head;
- elevator_t * elevator;
+ struct request * req = NULL;
+ int rw_ahead, max_sectors, el_ret;
+ struct list_head *head = &q->queue_head;
+ int latency;
+ elevator_t *elevator = &q->elevator;
count = bh->b_size >> 9;
sector = bh->b_rsector;
@@ -541,7 +599,6 @@ static inline void __make_request(request_queue_t * q, int rw,
if (buffer_uptodate(bh)) /* Hmmph! Already have it */
goto end_io;
kstat.pgpgin++;
- max_req = NR_REQUEST; /* reads take precedence */
break;
case WRITERAW:
rw = WRITE;
@@ -558,7 +615,6 @@ static inline void __make_request(request_queue_t * q, int rw,
* requests are only for reads.
*/
kstat.pgpgout++;
- max_req = (NR_REQUEST * 2) / 3;
break;
default:
BUG();
@@ -583,158 +639,82 @@ static inline void __make_request(request_queue_t * q, int rw,
/* look for a free request. */
/*
- * Loop uses two requests, 1 for loop and 1 for the real device.
- * Cut max_req in half to avoid running out and deadlocking.
- */
- if ((major == LOOP_MAJOR) || (major == NBD_MAJOR))
- max_req >>= 1;
-
- /*
* Try to coalesce the new request with old requests
*/
max_sectors = get_max_sectors(bh->b_rdev);
- elevator = &q->elevator;
- orig_latency = elevator_request_latency(elevator, rw);
+ latency = elevator_request_latency(elevator, rw);
/*
* Now we acquire the request spinlock, we have to be mega careful
* not to schedule or do something nonatomic
*/
- spin_lock_irqsave(&io_request_lock,flags);
- elevator_debug(q, bh->b_rdev);
+ spin_lock_irq(&io_request_lock);
+ elevator_default_debug(q, bh->b_rdev);
if (list_empty(head)) {
q->plug_device_fn(q, bh->b_rdev); /* is atomic */
goto get_rq;
}
- /* avoid write-bombs to not hurt iteractiveness of reads */
- if (rw != READ && elevator->read_pendings)
- max_segments = elevator->max_bomb_segments;
-
- sequence = elevator->sequence;
- latency = orig_latency - elevator->nr_segments;
- starving = 0;
- entry = head;
+ el_ret = elevator->elevator_merge_fn(q, &req, bh, rw, &max_sectors, &max_segments);
+ switch (el_ret) {
- /*
- * The scsi disk and cdrom drivers completely remove the request
- * from the queue when they start processing an entry. For this
- * reason it is safe to continue to add links to the top entry
- * for those devices.
- *
- * All other drivers need to jump over the first entry, as that
- * entry may be busy being processed and we thus can't change
- * it.
- */
- if (q->head_active && !q->plugged)
- head = head->next;
-
- while ((entry = entry->prev) != head && !starving) {
- req = blkdev_entry_to_request(entry);
- if (!req->q)
- break;
- latency += req->nr_segments;
- if (elevator_sequence_before(req->elevator_sequence, sequence))
- starving = 1;
- if (latency < 0)
- continue;
-
- if (req->sem)
- continue;
- if (req->cmd != rw)
- continue;
- if (req->nr_sectors + count > max_sectors)
- continue;
- if (req->rq_dev != bh->b_rdev)
- continue;
- /* Can we add it to the end of this request? */
- if (req->sector + req->nr_sectors == sector) {
- if (latency - req->nr_segments < 0)
- break;
- /*
- * The merge_fn is a more advanced way
- * of accomplishing the same task. Instead
- * of applying a fixed limit of some sort
- * we instead define a function which can
- * determine whether or not it is safe to
- * merge the request or not.
- *
- * See if this queue has rules that
- * may suggest that we shouldn't merge
- * this
- */
- if(!(q->back_merge_fn)(q, req, bh, max_segments))
+ case ELEVATOR_BACK_MERGE:
+ if (!q->back_merge_fn(q, req, bh, max_segments))
break;
req->bhtail->b_reqnext = bh;
req->bhtail = bh;
- req->nr_sectors = req->hard_nr_sectors += count;
+ req->nr_sectors = req->hard_nr_sectors += count;
+ req->e = elevator;
drive_stat_acct(req->rq_dev, req->cmd, count, 0);
-
- elevator_merge_after(elevator, req, latency);
-
- /* Can we now merge this req with the next? */
attempt_back_merge(q, req, max_sectors, max_segments);
- /* or to the beginning? */
- } else if (req->sector - count == sector) {
- if (starving)
- break;
- /*
- * The merge_fn is a more advanced way
- * of accomplishing the same task. Instead
- * of applying a fixed limit of some sort
- * we instead define a function which can
- * determine whether or not it is safe to
- * merge the request or not.
- *
- * See if this queue has rules that
- * may suggest that we shouldn't merge
- * this
- */
- if(!(q->front_merge_fn)(q, req, bh, max_segments))
+ goto out;
+
+ case ELEVATOR_FRONT_MERGE:
+ if (!q->front_merge_fn(q, req, bh, max_segments))
break;
- bh->b_reqnext = req->bh;
- req->bh = bh;
- req->buffer = bh->b_data;
- req->current_nr_sectors = count;
- req->sector = req->hard_sector = sector;
- req->nr_sectors = req->hard_nr_sectors += count;
+ bh->b_reqnext = req->bh;
+ req->bh = bh;
+ req->buffer = bh->b_data;
+ req->current_nr_sectors = count;
+ req->sector = req->hard_sector = sector;
+ req->nr_sectors = req->hard_nr_sectors += count;
+ req->e = elevator;
drive_stat_acct(req->rq_dev, req->cmd, count, 0);
-
- elevator_merge_before(elevator, req, latency);
-
attempt_front_merge(q, head, req, max_sectors, max_segments);
- } else
- continue;
-
- q->elevator.sequence++;
- spin_unlock_irqrestore(&io_request_lock,flags);
- return;
+ goto out;
+ /*
+ * elevator says don't/can't merge. get new request
+ */
+ case ELEVATOR_NO_MERGE:
+ break;
+ default:
+ printk("elevator returned crap (%d)\n", el_ret);
+ BUG();
}
-
-/* find an unused request. */
-get_rq:
- req = get_request(max_req, bh->b_rdev);
-
+
/*
- * if no request available: if rw_ahead, forget it,
- * otherwise try again blocking..
+ * Grab a free request from the freelist. Read first try their
+ * own queue - if that is empty, we steal from the write list.
+ * Writes must block if the write list is empty, and read aheads
+ * are not crucial.
*/
- if (!req) {
- spin_unlock_irqrestore(&io_request_lock,flags);
+get_rq:
+ if ((req = get_request(q, rw)) == NULL) {
+ spin_unlock_irq(&io_request_lock);
if (rw_ahead)
goto end_io;
- req = __get_request_wait(max_req, bh->b_rdev);
- spin_lock_irqsave(&io_request_lock,flags);
- /* revalidate elevator */
- head = &q->queue_head;
- if (q->head_active && !q->plugged)
- head = head->next;
+ req = __get_request_wait(q, rw);
+ spin_lock_irq(&io_request_lock);
}
+ head = &q->queue_head;
+ if (q->head_active && !q->plugged)
+ head = head->next;
+
/* fill up the request-info, and add it to the queue */
req->cmd = rw;
req->errors = 0;
@@ -747,19 +727,18 @@ get_rq:
req->sem = NULL;
req->bh = bh;
req->bhtail = bh;
- req->q = q;
- add_request(q, req, head, orig_latency);
-
- spin_unlock_irqrestore(&io_request_lock, flags);
+ req->rq_dev = bh->b_rdev;
+ req->e = elevator;
+ add_request(q, req, head, latency);
+out:
+ spin_unlock_irq(&io_request_lock);
return;
-
end_io:
bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
}
int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
{
- unsigned long flags;
int ret;
/*
@@ -767,7 +746,6 @@ int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
* still free to implement/resolve their own stacking
* by explicitly returning 0)
*/
-
while (q->make_request_fn) {
ret = q->make_request_fn(q, rw, bh);
if (ret > 0) {
@@ -781,10 +759,10 @@ int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
* the IO request? (normal case)
*/
__make_request(q, rw, bh);
- spin_lock_irqsave(&io_request_lock,flags);
+ spin_lock_irq(&io_request_lock);
if (q && !q->plugged)
(q->request_fn)(q);
- spin_unlock_irqrestore(&io_request_lock,flags);
+ spin_unlock_irq(&io_request_lock);
return 0;
}
@@ -923,28 +901,27 @@ int end_that_request_first (struct request *req, int uptodate, char *name)
void end_that_request_last(struct request *req)
{
- if (req->q)
+ if (req->e) {
+ printk("end_that_request_last called with non-dequeued req\n");
BUG();
+ }
if (req->sem != NULL)
up(req->sem);
- req->rq_status = RQ_INACTIVE;
- wake_up(&wait_for_request);
+
+ blkdev_release_request(req);
}
int __init blk_dev_init(void)
{
- struct request * req;
struct blk_dev_struct *dev;
- for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;) {
+ request_cachep = kmem_cache_create("blkdev_requests",
+ sizeof(struct request),
+ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+ for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;)
dev->queue = NULL;
- blk_init_queue(&dev->request_queue, NULL);
- }
- req = all_requests + NR_REQUEST;
- while (--req >= all_requests) {
- req->rq_status = RQ_INACTIVE;
- }
memset(ro_bits,0,sizeof(ro_bits));
memset(max_readahead, 0, sizeof(max_readahead));
memset(max_sectors, 0, sizeof(max_sectors));
@@ -1070,3 +1047,4 @@ EXPORT_SYMBOL(blk_queue_headactive);
EXPORT_SYMBOL(blk_queue_pluggable);
EXPORT_SYMBOL(blk_queue_make_request);
EXPORT_SYMBOL(generic_make_request);
+EXPORT_SYMBOL(blkdev_release_request);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 96dacdc22..89018e54a 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -785,7 +785,7 @@ int __init loop_init(void)
devfs_handle = devfs_mk_dir (NULL, "loop", 0, NULL);
devfs_register_series (devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT,
MAJOR_NR, 0,
- S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+ S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
&lo_fops, NULL);
if ((max_loop < 1) || (max_loop > 255)) {
diff --git a/drivers/block/md.c b/drivers/block/md.c
index 918dbdaf2..617990e77 100644
--- a/drivers/block/md.c
+++ b/drivers/block/md.c
@@ -3629,7 +3629,7 @@ int md__init md_init (void)
}
devfs_handle = devfs_mk_dir (NULL, "md", 0, NULL);
devfs_register_series (devfs_handle, "%u",MAX_MD_DEVS,DEVFS_FL_DEFAULT,
- MAJOR_NR, 0, S_IFBLK | S_IRUSR | S_IWUSR, 0, 0,
+ MAJOR_NR, 0, S_IFBLK | S_IRUSR | S_IWUSR,
&md_fops, NULL);
blk_dev[MD_MAJOR].queue = md_get_queue;
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 8256c57bd..222622c35 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -519,9 +519,9 @@ int nbd_init(void)
}
devfs_handle = devfs_mk_dir (NULL, "nbd", 0, NULL);
devfs_register_series (devfs_handle, "%u", MAX_NBD,
- DEVFS_FL_DEFAULT, MAJOR_NR, 0,
- S_IFBLK | S_IRUSR | S_IWUSR, 0, 0,
- &nbd_fops, NULL);
+ DEVFS_FL_DEFAULT, MAJOR_NR, 0,
+ S_IFBLK | S_IRUSR | S_IWUSR,
+ &nbd_fops, NULL);
return 0;
}
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
index 3cb11286d..5c4dbbee8 100644
--- a/drivers/block/paride/pg.c
+++ b/drivers/block/paride/pg.c
@@ -309,7 +309,7 @@ int pg_init (void) /* preliminary initialisation */
}
devfs_handle = devfs_mk_dir (NULL, "pg", 2, NULL);
devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
- major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ major, 0, S_IFCHR | S_IRUSR | S_IWUSR,
&pg_fops, NULL);
return 0;
}
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index 739755a93..52c67d017 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -314,10 +314,10 @@ int pt_init (void) /* preliminary initialisation */
devfs_handle = devfs_mk_dir (NULL, "pt", 2, NULL);
devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
- major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ major, 0, S_IFCHR | S_IRUSR | S_IWUSR,
&pt_fops, NULL);
devfs_register_series (devfs_handle, "%un", 4, DEVFS_FL_DEFAULT,
- major, 128, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ major, 128, S_IFCHR | S_IRUSR | S_IWUSR,
&pt_fops, NULL);
return 0;
}
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 211550d1e..26c0509d2 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -107,9 +107,7 @@ static struct inode *rd_inode[NUM_RAMDISKS]; /* Protected device inodes */
* architecture-specific setup routine (from the stored boot sector
* information).
*/
-
-int rd_size = CONFIG_BLK_DEV_RAM_SIZE; /* Size of the RAM disks */
-
+int rd_size = 4096; /* Size of the RAM disks */
/*
* It would be very desiderable to have a soft-blocksize (that in the case
* of the ramdisk driver is also the hardblocksize ;) of PAGE_SIZE because
@@ -413,7 +411,7 @@ int __init rd_init (void)
devfs_handle = devfs_mk_dir (NULL, "rd", 0, NULL);
devfs_register_series (devfs_handle, "%u", NUM_RAMDISKS,
DEVFS_FL_DEFAULT, MAJOR_NR, 0,
- S_IFBLK | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFBLK | S_IRUSR | S_IWUSR,
&fd_fops, NULL);
for (i = 0; i < NUM_RAMDISKS; i++)
diff --git a/drivers/block/smart1,2.h b/drivers/block/smart1,2.h
index 221e4a5f3..015980013 100644
--- a/drivers/block/smart1,2.h
+++ b/drivers/block/smart1,2.h
@@ -62,13 +62,14 @@ static void smart4_intr_mask(ctlr_info_t *h, unsigned long val)
}
/*
- * For this card fifo is full if reading this port returns 0!
+ * For older cards FIFO Full = 0.
+ * On this card 0 means there is room, anything else FIFO Full.
*
*/
static unsigned long smart4_fifo_full(ctlr_info_t *h)
{
- return (~readl(h->vaddr + S42XX_REQUEST_PORT_OFFSET));
+ return (!readl(h->vaddr + S42XX_REQUEST_PORT_OFFSET));
}
/* This type of controller returns -1 if the fifo is empty,
@@ -81,7 +82,7 @@ static unsigned long smart4_completed(ctlr_info_t *h)
= readl(h->vaddr + S42XX_REPLY_PORT_OFFSET);
/* Fifo is empty */
- if( register_value == -1)
+ if( register_value == 0xffffffff)
return 0;
/* Need to let it know we got the reply */
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
index aaad8e0c6..e32238d32 100644
--- a/drivers/cdrom/aztcd.c
+++ b/drivers/cdrom/aztcd.c
@@ -1791,8 +1791,8 @@ int __init aztcd_init(void)
return -EIO;
}
}
- devfs_register (NULL, "aztcd", 0, DEVFS_FL_DEFAULT, MAJOR_NR, 0,
- S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, &azt_fops, NULL);
+ devfs_register (NULL, "aztcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
+ S_IFBLK | S_IRUGO | S_IWUGO, &azt_fops, NULL);
if (devfs_register_blkdev(MAJOR_NR, "aztcd", &azt_fops) != 0)
{
printk("aztcd: Unable to get major %d for Aztech CD-ROM\n",
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 6b117a6be..caa3900b3 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -408,9 +408,9 @@ int register_cdrom(struct cdrom_device_info *cdi)
}
else {
cdi->de =
- devfs_register (devfs_handle, vname, 0, DEVFS_FL_DEFAULT,
+ devfs_register (devfs_handle, vname, DEVFS_FL_DEFAULT,
MAJOR (cdi->dev), MINOR (cdi->dev),
- S_IFBLK | S_IRUGO | S_IWUGO, 0, 0,
+ S_IFBLK | S_IRUGO | S_IWUGO,
&cdrom_fops, NULL);
}
cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
index f563a16c0..b0fa47b3e 100644
--- a/drivers/cdrom/gscd.c
+++ b/drivers/cdrom/gscd.c
@@ -1075,8 +1075,8 @@ int result;
MAJOR_NR);
return -EIO;
}
- devfs_register (NULL, "gscd", 0, DEVFS_FL_DEFAULT, MAJOR_NR, 0,
- S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, &gscd_fops, NULL);
+ devfs_register (NULL, "gscd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
+ S_IFBLK | S_IRUGO | S_IWUGO, &gscd_fops, NULL);
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
blksize_size[MAJOR_NR] = gscd_blocksizes;
diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
index 07f1f030c..480a01833 100644
--- a/drivers/cdrom/optcd.c
+++ b/drivers/cdrom/optcd.c
@@ -2064,8 +2064,8 @@ int __init optcd_init(void)
printk(KERN_ERR "optcd: unable to get major %d\n", MAJOR_NR);
return -EIO;
}
- devfs_register (NULL, "optcd", 0, DEVFS_FL_DEFAULT, MAJOR_NR, 0,
- S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, &opt_fops, NULL);
+ devfs_register (NULL, "optcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
+ S_IFBLK | S_IRUGO | S_IWUGO, &opt_fops, NULL);
hardsect_size[MAJOR_NR] = &hsecsize;
blksize_size[MAJOR_NR] = &blksize;
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
index 01dd94bf5..08400a52c 100644
--- a/drivers/cdrom/sbpcd.c
+++ b/drivers/cdrom/sbpcd.c
@@ -5803,9 +5803,9 @@ int __init SBPCD_INIT(void)
sprintf (nbuff, "c%dt%d/cd", SBPCD_ISSUE - 1, D_S[j].drv_id);
sbpcd_infop->de =
- devfs_register (devfs_handle, nbuff, 0, DEVFS_FL_DEFAULT,
+ devfs_register (devfs_handle, nbuff, DEVFS_FL_DEFAULT,
MAJOR_NR, j, S_IFBLK | S_IRUGO | S_IWUGO,
- 0, 0, &cdrom_fops, NULL);
+ &cdrom_fops, NULL);
if (register_cdrom(sbpcd_infop))
{
printk(" sbpcd: Unable to register with Uniform CD-ROm driver\n");
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
index 82dd5e5b9..a867c3819 100644
--- a/drivers/cdrom/sjcd.c
+++ b/drivers/cdrom/sjcd.c
@@ -1565,8 +1565,8 @@ int __init sjcd_init( void ){
}
printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base);
- devfs_register (NULL, "sjcd", 0, DEVFS_FL_DEFAULT, MAJOR_NR, 0,
- S_IFBLK | S_IRUGO | S_IWUGO, 0, 0, &sjcd_fops, NULL);
+ devfs_register (NULL, "sjcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
+ S_IFBLK | S_IRUGO | S_IWUGO, &sjcd_fops, NULL);
sjcd_present++;
return( 0 );
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
index 1f5fea7b9..d85fbc01f 100644
--- a/drivers/cdrom/sonycd535.c
+++ b/drivers/cdrom/sonycd535.c
@@ -1587,11 +1587,11 @@ sony535_init(void)
printk("IRQ%d, ", tmp_irq);
printk("using %d byte buffer\n", sony_buffer_size);
- devfs_register (NULL, CDU535_HANDLE, 0,
+ devfs_register (NULL, CDU535_HANDLE,
DEVFS_FL_DEFAULT,
MAJOR_NR, 0,
S_IFBLK | S_IRUGO | S_IWUGO,
- 0, 0, &cdu_fops, NULL);
+ &cdu_fops, NULL);
if (devfs_register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) {
printk("Unable to get major %d for %s\n",
MAJOR_NR, CDU535_MESSAGE_NAME);
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 3fc7005ed..d5091ff4d 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -226,7 +226,6 @@ int __init applicom_init(void)
continue;
}
- /* &ac_open as dev_id? David, could you pass me this joint? */
if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &ac_open)) {
printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq);
iounmap(RamIO);
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index dc076dd5a..6fe41e118 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -519,9 +519,9 @@ int __init dsp56k_init(void)
printk("DSP56k driver: Unable to register driver\n");
return -ENODEV;
}
- devfs_handle = devfs_register (NULL, "dsp56k", 0, DEVFS_FL_NONE,
+ devfs_handle = devfs_register (NULL, "dsp56k", DEVFS_FL_DEFAULT,
DSP56K_MAJOR, 0,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&dsp56k_fops, NULL);
dsp56k.in_use = 0;
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
index 730b69b17..475e1d052 100644
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -352,9 +352,9 @@ static int __init dtlk_init(void)
}
if (dtlk_dev_probe() == 0)
printk(", MAJOR %d\n", dtlk_major);
- devfs_handle = devfs_register (NULL, "dtlk", 0, DEVFS_FL_NONE,
+ devfs_handle = devfs_register (NULL, "dtlk", DEVFS_FL_DEFAULT,
dtlk_major, DTLK_MINOR,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&dtlk_fops, NULL);
init_timer(&dtlk_timer);
diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c
index 883f4a106..e6cb87d1e 100644
--- a/drivers/char/ftape/zftape/zftape-init.c
+++ b/drivers/char/ftape/zftape/zftape-init.c
@@ -439,34 +439,34 @@ KERN_INFO
char devname[9];
sprintf (devname, "qft%i", i);
- devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
QIC117_TAPE_MAJOR, i,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&zft_cdev, NULL);
sprintf (devname, "nqft%i", i);
- devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
QIC117_TAPE_MAJOR, i + 4,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&zft_cdev, NULL);
sprintf (devname, "zqft%i", i);
- devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
QIC117_TAPE_MAJOR, i + 16,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&zft_cdev, NULL);
sprintf (devname, "nzqft%i", i);
- devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
QIC117_TAPE_MAJOR, i + 20,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&zft_cdev, NULL);
sprintf (devname, "rawqft%i", i);
- devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
QIC117_TAPE_MAJOR, i + 32,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&zft_cdev, NULL);
sprintf (devname, "nrawqft%i", i);
- devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
QIC117_TAPE_MAJOR, i + 36,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&zft_cdev, NULL);
}
diff --git a/drivers/char/i2c-old.c b/drivers/char/i2c-old.c
index b509c9a18..bd9750fc3 100644
--- a/drivers/char/i2c-old.c
+++ b/drivers/char/i2c-old.c
@@ -37,8 +37,8 @@ static struct i2c_driver *drivers[I2C_DRIVER_MAX];
static int bus_count = 0, driver_count = 0;
#ifdef CONFIG_VIDEO_BT848
-extern int tuner_init_module(void);
-extern int msp3400_init_module(void);
+extern int i2c_tuner_init(void);
+extern int msp3400c_init(void);
#endif
#ifdef CONFIG_VIDEO_BUZ
extern int saa7111_init(void);
@@ -55,8 +55,8 @@ int i2c_init(void)
scan ? " (i2c bus scan enabled)" : "");
/* anything to do here ? */
#ifdef CONFIG_VIDEO_BT848
- tuner_init_module();
- msp3400_init_module();
+ i2c_tuner_init();
+ msp3400c_init();
#endif
#ifdef CONFIG_VIDEO_BUZ
saa7111_init();
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
index 033eb9aaf..a645832c4 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2main.c
@@ -877,19 +877,19 @@ old_ip2_init(void)
#ifdef CONFIG_DEVFS_FS
sprintf( name, "ipl%d", i );
i2BoardPtrTable[i]->devfs_ipl_handle =
- devfs_register (devfs_handle, name, 0,
- DEVFS_FL_NONE,
+ devfs_register (devfs_handle, name,
+ DEVFS_FL_DEFAULT,
IP2_IPL_MAJOR, 4 * i,
S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
- 0, 0, &ip2_ipl, NULL);
+ &ip2_ipl, NULL);
sprintf( name, "stat%d", i );
i2BoardPtrTable[i]->devfs_stat_handle =
- devfs_register (devfs_handle, name, 0,
- DEVFS_FL_NONE,
+ devfs_register (devfs_handle, name,
+ DEVFS_FL_DEFAULT,
IP2_IPL_MAJOR, 4 * i + 1,
S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
- 0, 0, &ip2_ipl, NULL);
+ &ip2_ipl, NULL);
for ( box = 0; box < ABS_MAX_BOXES; ++box )
{
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 8d16c9daf..81421c032 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -5310,7 +5310,7 @@ int __init stli_init(void)
devfs_handle = devfs_mk_dir (NULL, "staliomem", 9, NULL);
devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
STL_SIOMEMMAJOR, 0,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&stli_fsiomem, NULL);
/*
diff --git a/drivers/char/joystick/Config.in b/drivers/char/joystick/Config.in
index 3e371744e..1547e5f38 100644
--- a/drivers/char/joystick/Config.in
+++ b/drivers/char/joystick/Config.in
@@ -1,34 +1,56 @@
#
-# Joystick driver
+# Joystick driver configuration
#
mainmenu_option next_comment
comment 'Joysticks'
tristate 'Joystick support' CONFIG_JOYSTICK
-
if [ "$CONFIG_JOYSTICK" != "n" ]; then
- dep_tristate ' Classic PC analog' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK
- dep_tristate ' FPGaming and MadCatz A3D' CONFIG_JOY_ASSASSIN $CONFIG_JOYSTICK
- dep_tristate ' Gravis GrIP' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK
- dep_tristate ' Logitech ADI' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK
- dep_tristate ' Microsoft SideWinder' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK
- dep_tristate ' ThrustMaster DirectConnect' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK
- dep_tristate ' Creative Labs Blaster' CONFIG_JOY_CREATIVE $CONFIG_JOYSTICK
- dep_tristate ' PDPI Lightning 4 card' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK
- dep_tristate ' Trident 4DWave and Aureal Vortex gameport' CONFIG_JOY_PCI $CONFIG_JOYSTICK
- dep_tristate ' Magellan and Space Mouse' CONFIG_JOY_MAGELLAN $CONFIG_JOYSTICK
- dep_tristate ' SpaceTec SpaceOrb 360 and SpaceBall Avenger' CONFIG_JOY_SPACEORB $CONFIG_JOYSTICK
- dep_tristate ' SpaceTec SpaceBall 4000 FLX' CONFIG_JOY_SPACEBALL $CONFIG_JOYSTICK
- dep_tristate ' Logitech WingMan Warrior' CONFIG_JOY_WARRIOR $CONFIG_JOYSTICK
+
+ define_tristate CONFIG_USB $CONFIG_JOYSTICK
+ define_tristate CONFIG_INPUT_JOYDEV $CONFIG_JOYSTICK
+
+ comment 'Game port support'
+ dep_tristate ' ns558 gameports' CONFIG_INPUT_NS558 $CONFIG_JOYSTICK
+ dep_tristate ' PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_JOYSTICK
+ dep_tristate ' Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_JOYSTICK
+
+ comment 'Gameport joysticks'
+ dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_JOYSTICK
+ dep_tristate ' Assasin 3D and MadCatz Panther devices' CONFIG_INPUT_A3D $CONFIG_JOYSTICK
+ dep_tristate ' Logitech ADI digital joysticks and gamepads' CONFIG_INPUT_ADI $CONFIG_JOYSTICK
+ dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_INPUT_COBRA $CONFIG_JOYSTICK
+ dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_INPUT_GF2K $CONFIG_JOYSTICK
+ dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_INPUT_GRIP $CONFIG_JOYSTICK
+ dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_INPUT_INTERACT $CONFIG_JOYSTICK
+ dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_INPUT_TMDC $CONFIG_JOYSTICK
+ dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_INPUT_SIDEWINDER $CONFIG_JOYSTICK
+
+ comment 'Serial port support'
+ dep_tristate ' Serial port input line discipline' CONFIG_INPUT_SERPORT $CONFIG_JOYSTICK
+
+ comment 'Serial port joysticks'
+ dep_tristate ' Logitech WingMan Warrior joystick' CONFIG_INPUT_WARRIOR $CONFIG_JOYSTICK
+ dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_JOYSTICK
+ dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_JOYSTICK
+ dep_tristate ' SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_JOYSTICK
+ dep_tristate ' I-Force joysticks/wheels' CONFIG_INPUT_IFORCE_232 $CONFIG_JOYSTICK
+ if [ "$CONFIG_INPUT_IFORCE_232" != "n" ]; then
+ define_tristate CONFIG_INPUT_IFORCE $CONFIG_INPUT_IFORCE_232
+ fi
+
if [ "$CONFIG_PARPORT" != "n" ]; then
- dep_tristate ' NES, SNES, PSX, N64, Multi' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT
- dep_tristate ' Sega, Multi' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT
- dep_tristate ' TurboGraFX interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT
- fi
+ comment 'Parallel port joysticks'
+ dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_INPUT_DB9 $CONFIG_JOYSTICK
+ dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_INPUT_GAMECON $CONFIG_JOYSTICK
+ dep_tristate ' Multisystem joysticks via TurboGraFX device' CONFIG_INPUT_TURBOGRAFX $CONFIG_JOYSTICK
+ fi
+
if [ "$CONFIG_AMIGA" = "y" ]; then
- dep_tristate ' Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK
+ comment 'System joysticks'
+ dep_tristate ' Amiga joysticks' CONFIG_INPUT_AMIJOY $CONFIG_JOYSTICK
fi
fi
-
+
endmenu
diff --git a/drivers/char/joystick/Makefile b/drivers/char/joystick/Makefile
index 2bb5870b0..2ad452618 100644
--- a/drivers/char/joystick/Makefile
+++ b/drivers/char/joystick/Makefile
@@ -2,154 +2,73 @@
# Makefile for the joystick drivers.
#
-O_TARGET := js.o
-OX_OBJS :=
-O_OBJS :=
-MX_OBJS :=
-M_OBJS :=
-
-ifeq ($(CONFIG_JOYSTICK),y)
-OX_OBJS += joystick.o
-else
- ifeq ($(CONFIG_JOYSTICK),m)
- MX_OBJS += joystick.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_AMIGA),y)
-O_OBJS += joy-amiga.o
-else
- ifeq ($(CONFIG_JOY_AMIGA),m)
- M_OBJS += joy-amiga.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_ANALOG),y)
-O_OBJS += joy-analog.o
-else
- ifeq ($(CONFIG_JOY_ANALOG),m)
- M_OBJS += joy-analog.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_ASSASSIN),y)
-O_OBJS += joy-assassin.o
-else
- ifeq ($(CONFIG_JOY_ASSASSIN),m)
- M_OBJS += joy-assassin.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_CONSOLE),y)
-O_OBJS += joy-console.o
-else
- ifeq ($(CONFIG_JOY_CONSOLE),m)
- M_OBJS += joy-console.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_CREATIVE),y)
-O_OBJS += joy-creative.o
-else
- ifeq ($(CONFIG_JOY_CREATIVE),m)
- M_OBJS += joy-creative.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_DB9),y)
-O_OBJS += joy-db9.o
-else
- ifeq ($(CONFIG_JOY_DB9),m)
- M_OBJS += joy-db9.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_GRAVIS),y)
-O_OBJS += joy-gravis.o
-else
- ifeq ($(CONFIG_JOY_GRAVIS),m)
- M_OBJS += joy-gravis.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_LIGHTNING),y)
-O_OBJS += joy-lightning.o
-else
- ifeq ($(CONFIG_JOY_LIGHTNING),m)
- M_OBJS += joy-lightning.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_LOGITECH),y)
-O_OBJS += joy-logitech.o
-else
- ifeq ($(CONFIG_JOY_LOGITECH),m)
- M_OBJS += joy-logitech.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_MAGELLAN),y)
-O_OBJS += joy-magellan.o
-else
- ifeq ($(CONFIG_JOY_MAGELLAN),m)
- M_OBJS += joy-magellan.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_PCI),y)
-O_OBJS += joy-pci.o
-else
- ifeq ($(CONFIG_JOY_PCI),m)
- M_OBJS += joy-pci.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_SIDEWINDER),y)
-O_OBJS += joy-sidewinder.o
-else
- ifeq ($(CONFIG_JOY_SIDEWINDER),m)
- M_OBJS += joy-sidewinder.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_SPACEORB),y)
-O_OBJS += joy-spaceorb.o
-else
- ifeq ($(CONFIG_JOY_SPACEORB),m)
- M_OBJS += joy-spaceorb.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_SPACEBALL),y)
-O_OBJS += joy-spaceball.o
-else
- ifeq ($(CONFIG_JOY_SPACEBALL),m)
- M_OBJS += joy-spaceball.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_THRUSTMASTER),y)
-O_OBJS += joy-thrustmaster.o
-else
- ifeq ($(CONFIG_JOY_THRUSTMASTER),m)
- M_OBJS += joy-thrustmaster.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_TURBOGRAFX),y)
-O_OBJS += joy-turbografx.o
-else
- ifeq ($(CONFIG_JOY_TURBOGRAFX),m)
- M_OBJS += joy-turbografx.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_WARRIOR),y)
-O_OBJS += joy-warrior.o
-else
- ifeq ($(CONFIG_JOY_WARRIOR),m)
- M_OBJS += joy-warrior.o
- endif
-endif
+# Subdirs.
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+MOD_IN_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+# The target object and module list name.
+
+O_TARGET := js.o
+M_OBJS :=
+O_OBJS :=
+#MOD_LIST_NAME := INPUT_MODULES
+
+# Objects that export symbols.
+
+export-objs := serio.o gameport.o
+
+# Object file lists.
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_INPUT_SERPORT) += serport.o serio.o
+
+obj-$(CONFIG_INPUT_NS558) += ns558.o gameport.o
+obj-$(CONFIG_INPUT_LIGHTNING) += lightning.o gameport.o
+obj-$(CONFIG_INPUT_PCIGAME) += pcigame.o gameport.o
+
+obj-$(CONFIG_INPUT_WARRIOR) += warrior.o serio.o
+obj-$(CONFIG_INPUT_MAGELLAN) += magellan.o serio.o
+obj-$(CONFIG_INPUT_SPACEORB) += spaceorb.o serio.o
+obj-$(CONFIG_INPUT_SPACEBALL) += spaceball.o serio.o
+obj-$(CONFIG_INPUT_IFORCE_232) += serio.o
+
+obj-$(CONFIG_INPUT_ANALOG) += analog.o gameport.o
+obj-$(CONFIG_INPUT_A3D) += a3d.o gameport.o
+obj-$(CONFIG_INPUT_ADI) += adi.o gameport.o
+obj-$(CONFIG_INPUT_COBRA) += cobra.o gameport.o
+obj-$(CONFIG_INPUT_GF2K) += gf2k.o gameport.o
+obj-$(CONFIG_INPUT_GRIP) += grip.o gameport.o
+obj-$(CONFIG_INPUT_INTERACT) += interact.o gameport.o
+obj-$(CONFIG_INPUT_TMDC) += tmdc.o gameport.o
+obj-$(CONFIG_INPUT_SIDEWINDER) += sidewinder.o gameport.o
+
+obj-$(CONFIG_INPUT_DB9) += db9.o
+obj-$(CONFIG_INPUT_GAMECON) += gamecon.o
+obj-$(CONFIG_INPUT_TURBOGRAFX) += turbografx.o
+
+obj-$(CONFIG_INPUT_AMIJOY) += amijoy.o
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m := $(filter-out $(obj-y), $(obj-m))
+int-m := $(filter-out $(int-y), $(int-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))
+OX_OBJS := $(sort $(filter $(export-objs), $(obj-y)))
+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
+
+# The global Rules.make.
include $(TOPDIR)/Rules.make
diff --git a/drivers/char/joystick/a3d.c b/drivers/char/joystick/a3d.c
new file mode 100644
index 000000000..bd17f8de2
--- /dev/null
+++ b/drivers/char/joystick/a3d.c
@@ -0,0 +1,387 @@
+/*
+ * $Id: a3d.c,v 1.10 2000/05/29 11:19:50 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * FP-Gaming Assasin 3D joystick driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define A3D_MAX_START 400 /* 400 us */
+#define A3D_MAX_STROBE 60 /* 40 us */
+#define A3D_DELAY_READ 3 /* 3 ms */
+#define A3D_MAX_LENGTH 40 /* 40*3 bits */
+#define A3D_REFRESH_TIME HZ/50 /* 20 ms */
+
+#define A3D_MODE_A3D 1 /* Assassin 3D */
+#define A3D_MODE_PAN 2 /* Panther */
+#define A3D_MODE_OEM 3 /* Panther OEM version */
+#define A3D_MODE_PXL 4 /* Panther XL */
+
+char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
+ "MadCatz Panther XL", "MadCatz Panther XL w/ rudder" };
+
+struct a3d {
+ struct gameport *gameport;
+ struct gameport adc;
+ struct input_dev dev;
+ struct timer_list timer;
+ int axes[4];
+ int buttons;
+ int mode;
+ int length;
+ int used;
+ int reads;
+ int bads;
+};
+
+/*
+ * a3d_read_packet() reads an Assassin 3D packet.
+ */
+
+static int a3d_read_packet(struct gameport *gameport, int length, char *data)
+{
+ unsigned long flags;
+ unsigned char u, v;
+ unsigned int t, s;
+ int i;
+
+ i = 0;
+ t = gameport_time(gameport, A3D_MAX_START);
+ s = gameport_time(gameport, A3D_MAX_STROBE);
+
+ __save_flags(flags);
+ __cli();
+ gameport_trigger(gameport);
+ v = gameport_read(gameport);
+
+ while (t > 0 && i < length) {
+ t--;
+ u = v; v = gameport_read(gameport);
+ if (~v & u & 0x10) {
+ data[i++] = v >> 5;
+ t = s;
+ }
+ }
+
+ __restore_flags(flags);
+
+ return i;
+}
+
+/*
+ * a3d_csum() computes checksum of triplet packet
+ */
+
+static int a3d_csum(char *data, int count)
+{
+ int i, csum = 0;
+ for (i = 0; i < count - 2; i++) csum += data[i];
+ return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
+}
+
+static void a3d_read(struct a3d *a3d, unsigned char *data)
+{
+ struct input_dev *dev = &a3d->dev;
+
+ switch (a3d->mode) {
+
+ case A3D_MODE_A3D:
+ case A3D_MODE_OEM:
+ case A3D_MODE_PAN:
+
+ input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7));
+ input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7));
+
+ input_report_key(dev, BTN_RIGHT, data[2] & 1);
+ input_report_key(dev, BTN_LEFT, data[3] & 2);
+ input_report_key(dev, BTN_MIDDLE, data[3] & 4);
+
+ a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
+ a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
+ a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
+ a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
+
+ a3d->buttons = ((data[3] << 3) | data[4]) & 0xf;
+
+ return;
+
+ case A3D_MODE_PXL:
+
+ input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7));
+ input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7));
+
+ input_report_key(dev, BTN_RIGHT, data[2] & 1);
+ input_report_key(dev, BTN_LEFT, data[3] & 2);
+ input_report_key(dev, BTN_MIDDLE, data[3] & 4);
+ input_report_key(dev, BTN_SIDE, data[7] & 2);
+ input_report_key(dev, BTN_EXTRA, data[7] & 4);
+
+ input_report_abs(dev, ABS_X, ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128);
+ input_report_abs(dev, ABS_Y, ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128);
+ input_report_abs(dev, ABS_RUDDER, ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128);
+ input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128);
+
+ input_report_abs(dev, ABS_HAT0X, ( data[5] & 1) - ((data[5] >> 2) & 1));
+ input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1));
+ input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3] & 1));
+ input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4] & 1));
+
+ input_report_key(dev, BTN_TRIGGER, data[8] & 1);
+ input_report_key(dev, BTN_THUMB, data[8] & 2);
+ input_report_key(dev, BTN_TOP, data[8] & 4);
+ input_report_key(dev, BTN_PINKIE, data[7] & 1);
+
+ return;
+ }
+}
+
+
+/*
+ * a3d_timer() reads and analyzes A3D joystick data.
+ */
+
+static void a3d_timer(unsigned long private)
+{
+ struct a3d *a3d = (void *) private;
+ unsigned char data[A3D_MAX_LENGTH];
+ a3d->reads++;
+ if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length
+ || data[0] != a3d->mode || a3d_csum(data, a3d->length))
+ a3d->bads++; else a3d_read(a3d, data);
+ mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
+}
+
+/*
+ * a3d_adc_cooked_read() copies the acis and button data to the
+ * callers arrays. It could do the read itself, but the caller could
+ * call this more than 50 times a second, which would use too much CPU.
+ */
+
+int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+ struct a3d *a3d = gameport->driver;
+ int i;
+ for (i = 0; i < 4; i++)
+ axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
+ *buttons = a3d->buttons;
+ return 0;
+}
+
+/*
+ * a3d_adc_open() is the gameport open routine. It refuses to serve
+ * any but cooked data.
+ */
+
+int a3d_adc_open(struct gameport *gameport, int mode)
+{
+ struct a3d *a3d = gameport->driver;
+ if (mode != GAMEPORT_MODE_COOKED)
+ return -1;
+ if (!a3d->used++)
+ mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
+ return 0;
+}
+
+/*
+ * a3d_adc_close() is a callback from the input close routine.
+ */
+
+static void a3d_adc_close(struct gameport *gameport)
+{
+ struct a3d *a3d = gameport->driver;
+ if (!--a3d->used)
+ del_timer(&a3d->timer);
+}
+
+/*
+ * a3d_open() is a callback from the input open routine.
+ */
+
+static int a3d_open(struct input_dev *dev)
+{
+ struct a3d *a3d = dev->private;
+ if (!a3d->used++)
+ mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
+ return 0;
+}
+
+/*
+ * a3d_close() is a callback from the input close routine.
+ */
+
+static void a3d_close(struct input_dev *dev)
+{
+ struct a3d *a3d = dev->private;
+ if (!--a3d->used)
+ del_timer(&a3d->timer);
+}
+
+/*
+ * a3d_connect() probes for A3D joysticks.
+ */
+
+static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct a3d *a3d;
+ unsigned char data[A3D_MAX_LENGTH];
+ int i;
+
+ if (!(a3d = kmalloc(sizeof(struct a3d), GFP_KERNEL)))
+ return;
+ memset(a3d, 0, sizeof(struct a3d));
+
+ gameport->private = a3d;
+
+ a3d->gameport = gameport;
+ init_timer(&a3d->timer);
+ a3d->timer.data = (long) a3d;
+ a3d->timer.function = a3d_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ goto fail1;
+
+ i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data);
+
+ if (!i || a3d_csum(data, i))
+ goto fail2;
+
+ a3d->mode = data[0];
+
+ if (!a3d->mode || a3d->mode > 5) {
+ printk(KERN_WARNING "a3d.c: Unknown A3D device detected "
+ "(gameport%d, id=%d), contact <vojtech@suse.cz>\n", gameport->number, a3d->mode);
+ goto fail2;
+ }
+
+
+ if (a3d->mode == A3D_MODE_PXL) {
+
+ int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
+
+ a3d->length = 33;
+
+ a3d->dev.evbit[0] |= BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
+ a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
+ a3d->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_RUDDER)
+ | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) | BIT(ABS_HAT1X) | BIT(ABS_HAT1Y);
+
+ a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE)
+ | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+
+ a3d->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_PINKIE);
+
+ a3d_read(a3d, data);
+
+ for (i = 0; i < 4; i++) {
+ if (i < 2) {
+ a3d->dev.absmin[axes[i]] = 48;
+ a3d->dev.absmax[axes[i]] = a3d->dev.abs[axes[i]] * 2 - 48;
+ a3d->dev.absflat[axes[i]] = 8;
+ } else {
+ a3d->dev.absmin[axes[i]] = 2;
+ a3d->dev.absmax[axes[i]] = 253;
+ }
+ a3d->dev.absmin[ABS_HAT0X + i] = -1;
+ a3d->dev.absmax[ABS_HAT0X + i] = 1;
+ }
+
+ } else {
+ a3d->length = 29;
+
+ a3d->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL);
+ a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
+ a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
+
+ a3d->adc.driver = a3d;
+ a3d->adc.open = a3d_adc_open;
+ a3d->adc.close = a3d_adc_close;
+ a3d->adc.cooked_read = a3d_adc_cooked_read;
+ a3d->adc.fuzz = 1;
+ a3d->adc.type = GAMEPORT_EXT;
+
+ a3d_read(a3d, data);
+
+ gameport_register_port(&a3d->adc);
+ printk(KERN_INFO "gameport%d: %s on gameport%d.0\n",
+ a3d->adc.number, a3d_names[a3d->mode], gameport->number);
+ }
+
+ a3d->dev.private = a3d;
+ a3d->dev.open = a3d_open;
+ a3d->dev.close = a3d_close;
+
+ a3d->dev.name = a3d_names[a3d->mode];
+ a3d->dev.idbus = BUS_GAMEPORT;
+ a3d->dev.idvendor = GAMEPORT_ID_VENDOR_MADCATZ;
+ a3d->dev.idproduct = a3d->mode;
+ a3d->dev.idversion = 0x0100;
+
+ input_register_device(&a3d->dev);
+ printk(KERN_INFO "input%d: %s on gameport%d.0\n",
+ a3d->dev.number, a3d_names[a3d->mode], gameport->number);
+
+ return;
+fail2: gameport_close(gameport);
+fail1: kfree(a3d);
+}
+
+static void a3d_disconnect(struct gameport *gameport)
+{
+
+ struct a3d *a3d = gameport->private;
+ input_unregister_device(&a3d->dev);
+ if (a3d->mode < A3D_MODE_PXL)
+ gameport_unregister_port(&a3d->adc);
+ gameport_close(gameport);
+ kfree(a3d);
+}
+
+static struct gameport_dev a3d_dev = {
+ connect: a3d_connect,
+ disconnect: a3d_disconnect,
+};
+
+int __init a3d_init(void)
+{
+ gameport_register_device(&a3d_dev);
+ return 0;
+}
+
+void __exit a3d_exit(void)
+{
+ gameport_unregister_device(&a3d_dev);
+}
+
+module_init(a3d_init);
+module_exit(a3d_exit);
diff --git a/drivers/char/joystick/adi.c b/drivers/char/joystick/adi.c
new file mode 100644
index 000000000..3195fce03
--- /dev/null
+++ b/drivers/char/joystick/adi.c
@@ -0,0 +1,554 @@
+/*
+ * $Id: adi.c,v 1.12 2000/06/03 20:18:52 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Logitech ADI joystick family driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/input.h>
+#include <linux/gameport.h>
+#include <linux/init.h>
+
+/*
+ * Times, array sizes, flags, ids.
+ */
+
+#define ADI_MAX_START 200 /* Trigger to packet timeout [200us] */
+#define ADI_MAX_STROBE 40 /* Single bit timeout [40us] */
+#define ADI_REFRESH_TIME HZ/50 /* How often to poll the joystick [20 ms] */
+#define ADI_INIT_DELAY 10 /* Delay after init packet [10ms] */
+#define ADI_DATA_DELAY 4 /* Delay after data packet [4ms] */
+
+#define ADI_MAX_LENGTH 256
+#define ADI_MIN_LENGTH 8
+#define ADI_MIN_LEN_LENGTH 10
+#define ADI_MIN_ID_LENGTH 66
+#define ADI_MAX_NAME_LENGTH 48
+#define ADI_MAX_CNAME_LENGTH 16
+
+#define ADI_FLAG_HAT 0x04
+#define ADI_FLAG_10BIT 0x08
+
+#define ADI_ID_TPD 0x01
+#define ADI_ID_WGP 0x06
+#define ADI_ID_WGPE 0x08
+#define ADI_ID_MAX 0x0a
+
+/*
+ * Names, buttons, axes ...
+ */
+
+static char *adi_names[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2",
+ "WingMan Interceptor", "WingMan Formula", "WingMan GamePad",
+ "WingMan Extreme Digital 3D", "WingMan GamePad Extreme",
+ "WingMan GamePad USB", "Unknown Device %#x" };
+
+static char adi_wmgpe_abs[] = { ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y };
+static char adi_wmi_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
+static char adi_wmed3d_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y };
+static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
+static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
+
+static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
+static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
+static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
+static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
+
+static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs,
+ adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs };
+
+static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key,
+ adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key };
+
+/*
+ * Hat to axis conversion arrays.
+ */
+
+static struct {
+ int x;
+ int y;
+} adi_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+/*
+ * Per-port information.
+ */
+
+struct adi {
+ struct input_dev dev;
+ int length;
+ int ret;
+ int idx;
+ unsigned char id;
+ char buttons;
+ char axes10;
+ char axes8;
+ signed char pad;
+ char hats;
+ char *abs;
+ short *key;
+ char name[ADI_MAX_NAME_LENGTH];
+ char cname[ADI_MAX_CNAME_LENGTH];
+ unsigned char data[ADI_MAX_LENGTH];
+};
+
+struct adi_port {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct adi adi[2];
+ int bad;
+ int reads;
+ int used;
+};
+
+/*
+ * adi_read_packet() reads a Logitech ADI packet.
+ */
+
+static void adi_read_packet(struct adi_port *port)
+{
+ struct adi *adi = port->adi;
+ struct gameport *gameport = port->gameport;
+ unsigned char u, v, w, x, z;
+ int t[2], s[2], i;
+ unsigned long flags;
+
+ for (i = 0; i < 2; i++) {
+ adi[i].ret = -1;
+ t[i] = gameport_time(gameport, ADI_MAX_START);
+ s[i] = 0;
+ }
+
+ __save_flags(flags);
+ __cli();
+
+ gameport_trigger(gameport);
+ v = z = gameport_read(gameport);
+
+ do {
+ u = v;
+ w = u ^ (v = x = gameport_read(gameport));
+ for (i = 0; i < 2; i++, w >>= 2, x >>= 2) {
+ t[i]--;
+ if ((w & 0x30) && s[i]) {
+ if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) {
+ adi[i].data[++adi[i].ret] = w;
+ t[i] = gameport_time(gameport, ADI_MAX_STROBE);
+ } else t[i] = 0;
+ } else if (!(x & 0x30)) s[i] = 1;
+ }
+ } while (t[0] > 0 || t[1] > 0);
+
+ __restore_flags(flags);
+
+ return;
+}
+
+/*
+ * adi_move_bits() detects a possible 2-stream mode, and moves
+ * the bits accordingly.
+ */
+
+static void adi_move_bits(struct adi_port *port, int length)
+{
+ int i;
+ struct adi *adi = port->adi;
+
+ adi[0].idx = adi[1].idx = 0;
+
+ if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
+ if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
+
+ for (i = 1; i <= adi[1].ret; i++)
+ adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i];
+
+ adi[0].ret += adi[1].ret;
+ adi[1].ret = -1;
+}
+
+/*
+ * adi_get_bits() gathers bits from the data packet.
+ */
+
+static inline int adi_get_bits(struct adi *adi, int count)
+{
+ int bits = 0;
+ int i;
+ if ((adi->idx += count) > adi->ret) return 0;
+ for (i = 0; i < count; i++)
+ bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i;
+ return bits;
+}
+
+/*
+ * adi_decode() decodes Logitech joystick data into input events.
+ */
+
+static int adi_decode(struct adi *adi)
+{
+ struct input_dev *dev = &adi->dev;
+ char *abs = adi->abs;
+ short *key = adi->key;
+ int i, t;
+
+ if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4)))
+ return -1;
+
+ for (i = 0; i < adi->axes10; i++)
+ input_report_abs(dev, *abs++, adi_get_bits(adi, 10));
+
+ for (i = 0; i < adi->axes8; i++)
+ input_report_abs(dev, *abs++, adi_get_bits(adi, 8));
+
+ for (i = 0; i < adi->buttons && i < 63; i++) {
+ if (i == adi->pad) {
+ t = adi_get_bits(adi, 4);
+ input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t & 1));
+ input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1));
+ }
+ input_report_key(dev, *key++, adi_get_bits(adi, 1));
+ }
+
+ for (i = 0; i < adi->hats; i++) {
+ if ((t = adi_get_bits(adi, 4)) > 8) t = 0;
+ input_report_abs(dev, *abs++, adi_hat_to_axis[t].x);
+ input_report_abs(dev, *abs++, adi_hat_to_axis[t].y);
+ }
+
+ for (i = 63; i < adi->buttons; i++)
+ input_report_key(dev, *key++, adi_get_bits(adi, 1));
+
+ return 0;
+}
+
+/*
+ * adi_read() reads the data packet and decodes it.
+ */
+
+static int adi_read(struct adi_port *port)
+{
+ int i;
+ int result = 0;
+
+ adi_read_packet(port);
+ adi_move_bits(port, port->adi[0].length);
+
+ for (i = 0; i < 2; i++)
+ if (port->adi[i].length)
+ result |= adi_decode(port->adi + i);
+
+ return result;
+}
+
+/*
+ * adi_timer() repeatedly polls the Logitech joysticks.
+ */
+
+static void adi_timer(unsigned long data)
+{
+ struct adi_port *port = (void *) data;
+ port->bad -= adi_read(port);
+ port->reads++;
+ mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
+}
+
+/*
+ * adi_open() is a callback from the input open routine.
+ */
+
+static int adi_open(struct input_dev *dev)
+{
+ struct adi_port *port = dev->private;
+ if (!port->used++)
+ mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
+ return 0;
+}
+
+/*
+ * adi_close() is a callback from the input close routine.
+ */
+
+static void adi_close(struct input_dev *dev)
+{
+ struct adi_port *port = dev->private;
+ if (!--port->used)
+ del_timer(&port->timer);
+}
+
+/*
+ * adi_init_digital() sends a trigger & delay sequence
+ * to reset and initialize a Logitech joystick into digital mode.
+ */
+
+static void adi_init_digital(struct gameport *gameport)
+{
+ int seq[] = { 3, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
+ int i;
+
+ for (i = 0; seq[i]; i++) {
+ gameport_trigger(gameport);
+ if (seq[i] > 0) wait_ms(seq[i]);
+ if (seq[i] < 0) mdelay(-seq[i]);
+ }
+}
+
+static void adi_id_decode(struct adi *adi, struct adi_port *port)
+{
+ int i, t;
+
+ if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */
+ return;
+
+ if (adi->ret < (t = adi_get_bits(adi, 10))) {
+ printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret);
+ return;
+ }
+
+ adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4);
+
+ if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++;
+
+ adi->length = adi_get_bits(adi, 10);
+
+ if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) {
+ printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length);
+ adi->length = 0;
+ return;
+ }
+
+ adi->axes8 = adi_get_bits(adi, 4);
+ adi->buttons = adi_get_bits(adi, 6);
+
+ if (adi_get_bits(adi, 6) != 8 && adi->hats) {
+ printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n");
+ adi->length = 0;
+ return;
+ }
+
+ adi->buttons += adi_get_bits(adi, 6);
+ adi->hats += adi_get_bits(adi, 4);
+
+ i = adi_get_bits(adi, 4);
+
+ if (t & ADI_FLAG_10BIT) {
+ adi->axes10 = adi->axes8 - i;
+ adi->axes8 = i;
+ }
+
+ t = adi_get_bits(adi, 4);
+
+ for (i = 0; i < t; i++)
+ adi->cname[i] = adi_get_bits(adi, 8);
+ adi->cname[i] = 0;
+
+ if (adi->length != (t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4)) {
+ printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length);
+ adi->length = 0;
+ return;
+ }
+
+ switch (adi->id) {
+ case ADI_ID_TPD:
+ adi->pad = 4;
+ adi->buttons -= 4;
+ break;
+ case ADI_ID_WGP:
+ adi->pad = 0;
+ adi->buttons -= 4;
+ break;
+ default:
+ adi->pad = -1;
+ break;
+ }
+}
+
+static void adi_init_input(struct adi *adi, struct adi_port *port)
+{
+ int i, t;
+ char buf[ADI_MAX_NAME_LENGTH];
+
+ if (!adi->length) return;
+
+ t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX;
+
+ sprintf(buf, adi_names[t], adi->id);
+ sprintf(adi->name, "Logitech %s", buf);
+
+ adi->abs = adi_abs[t];
+ adi->key = adi_key[t];
+
+ adi->dev.open = adi_open;
+ adi->dev.close = adi_close;
+
+ adi->dev.name = adi->name;
+ adi->dev.idbus = BUS_GAMEPORT;
+ adi->dev.idvendor = GAMEPORT_ID_VENDOR_LOGITECH;
+ adi->dev.idproduct = adi->id;
+ adi->dev.idversion = 0x0100;
+
+ adi->dev.private = port;
+ adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (i = 0; i < adi->axes10 + adi->axes8 + adi->hats * 2; i++)
+ set_bit(adi->abs[i], &adi->dev.absbit);
+
+ for (i = 0; i < adi->buttons; i++)
+ set_bit(adi->key[i], &adi->dev.keybit);
+}
+
+static void adi_init_center(struct adi *adi)
+{
+ int i, t, x;
+
+ if (!adi->length) return;
+
+ for (i = 0; i < adi->axes10 + adi->axes8 + adi->hats * 2; i++) {
+
+ t = adi->abs[i];
+ x = adi->dev.abs[t];
+
+ if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) {
+ if (i < adi->axes10) x = 512; else x = 128;
+ }
+
+ if (i < adi->axes10) {
+ adi->dev.absmax[t] = x * 2 - 64;
+ adi->dev.absmin[t] = 64;
+ adi->dev.absfuzz[t] = 2;
+ adi->dev.absflat[t] = 16;
+ continue;
+ }
+
+ if (i < adi->axes10 + adi->axes8) {
+ adi->dev.absmax[t] = x * 2 - 48;
+ adi->dev.absmin[t] = 48;
+ adi->dev.absfuzz[t] = 1;
+ adi->dev.absflat[t] = 16;
+ continue;
+ }
+
+ adi->dev.absmax[t] = 1;
+ adi->dev.absmin[t] = -1;
+ }
+}
+
+/*
+ * adi_connect() probes for Logitech ADI joysticks.
+ */
+
+static void adi_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct adi_port *port;
+ int i;
+
+ if (!(port = kmalloc(sizeof(struct adi_port), GFP_KERNEL)))
+ return;
+ memset(port, 0, sizeof(struct adi_port));
+
+ gameport->private = port;
+
+ port->gameport = gameport;
+ init_timer(&port->timer);
+ port->timer.data = (long) port;
+ port->timer.function = adi_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
+ kfree(port);
+ return;
+ }
+
+ adi_init_digital(gameport);
+ adi_read_packet(port);
+
+ if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH)
+ adi_move_bits(port, adi_get_bits(port->adi, 10));
+
+ for (i = 0; i < 2; i++) {
+ adi_id_decode(port->adi + i, port);
+ adi_init_input(port->adi + i, port);
+ }
+
+ if (!port->adi[0].length && !port->adi[1].length) {
+ gameport_close(gameport);
+ kfree(port);
+ return;
+ }
+
+ wait_ms(ADI_INIT_DELAY);
+ if (adi_read(port)) {
+ wait_ms(ADI_DATA_DELAY);
+ adi_read(port);
+ }
+
+ for (i = 0; i < 2; i++)
+ if (port->adi[i].length > 0) {
+ adi_init_center(port->adi + i);
+ input_register_device(&port->adi[i].dev);
+ printk(KERN_INFO "input%d: %s [%s] on gameport%d.%d\n",
+ port->adi[i].dev.number, port->adi[i].name, port->adi[i].cname, gameport->number, i);
+ }
+}
+
+static void adi_disconnect(struct gameport *gameport)
+{
+ int i;
+
+ struct adi_port *port = gameport->private;
+ for (i = 0; i < 2; i++)
+ if (port->adi[i].length > 0)
+ input_unregister_device(&port->adi[i].dev);
+ gameport_close(gameport);
+ kfree(port);
+}
+
+/*
+ * The gameport device structure.
+ */
+
+static struct gameport_dev adi_dev = {
+ connect: adi_connect,
+ disconnect: adi_disconnect,
+};
+
+int __init adi_init(void)
+{
+ gameport_register_device(&adi_dev);
+ return 0;
+}
+
+void __exit adi_exit(void)
+{
+ gameport_unregister_device(&adi_dev);
+}
+
+module_init(adi_init);
+module_exit(adi_exit);
diff --git a/drivers/char/joystick/amijoy.c b/drivers/char/joystick/amijoy.c
new file mode 100644
index 000000000..f17aeda24
--- /dev/null
+++ b/drivers/char/joystick/amijoy.c
@@ -0,0 +1,149 @@
+/*
+ * $Id: amijoy.c,v 1.4 2000/05/29 10:39:54 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Driver for Amiga joysticks for Linux/m68k
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+
+#include <asm/system.h>
+#include <asm/amigahw.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_PARM(amijoy, "1-2i");
+
+static int amijoy[2] = { 0, 1 };
+static int amijoy_used[2] = { 0, 0 };
+static struct input_dev amijoy_dev[2];
+
+static char *amijoy_name = "Amiga joystick";
+
+static void amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+ int i, data = 0, button = 0;
+
+ for (i = 0; i < 2; i++)
+ if (amijoy[i]) {
+
+ switch (i) {
+ case 0: data = ~custom.joy0dat; button = (~ciaa.pra >> 6) & 1; break;
+ case 1: data = ~custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break;
+ }
+
+ input_report_key(amijoy_dev + i, BTN_TRIGGER, button);
+
+ input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1);
+ data = ~(data ^ (data << 1));
+ input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1);
+ }
+}
+
+static int amijoy_open(struct input_dev *dev)
+{
+ int *used = dev->private;
+
+ if ((*used)++)
+ return 0;
+
+ if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", NULL)) {
+ amijoy_used--;
+ printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", amijoy_irq);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static void amijoy_close(struct input_dev *dev)
+{
+ int *used = dev->private;
+
+ if (!--(*port->used))
+ free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
+}
+
+static int __init amijoy_setup(char *str)
+{
+ int i;
+ int ints[4]
+ str = get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 2; i++) amijoy[i] = ints[i+1];
+ return 1;
+}
+__setup("amijoy=", amijoy_setup);
+
+static int __init amijoy_init(void)
+{
+ int i, j;
+
+ init_timer(amijoy_timer);
+ port->timer.function = amijoy_timer;
+
+ for (i = 0; i < 2; i++)
+ if (amijoy[i]) {
+
+ amijoy_dev[i].open = amijoy_open;
+ amijoy_dev[i].close = amijoy_close;
+ amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+ amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ for (j = 0; j < 2; j++)
+ amijoy_dev[i].absmin[ABS_X + j] = -1;
+ amijoy_dev[i].absmax[ABS_X + j] = 1;
+ }
+
+ amijoy->dev[i].name = amijoy_name;
+ amijoy->dev[i].idbus = BUS_AMIGA;
+ amijoy->dev[i].idvendor = 0x0001;
+ amijoy->dev[i].idproduct = 0x0003;
+ amijoy->dev[i].version = 0x0100;
+
+ amijoy_dev[i].private = amijoy_used + i;
+
+ input_register_device(amijoy_dev + i);
+ printk(KERN_INFO "input%d: %s at joy%ddat\n", amijoy_dev[i].number, amijoy_name, i);
+ }
+}
+
+static void _exit amijoy_exit(void)
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (amijoy[i])
+ input_unregister_device(amijoy_dev + i);
+}
+
+module_init(amijoy_init);
+module_exit(amijoy_exit);
diff --git a/drivers/char/joystick/analog.c b/drivers/char/joystick/analog.c
new file mode 100644
index 000000000..6514bef9b
--- /dev/null
+++ b/drivers/char/joystick/analog.c
@@ -0,0 +1,758 @@
+/*
+ * $Id: analog.c,v 1.52 2000/06/07 13:07:06 vojtech Exp $
+ *
+ * Copyright (c) 1996-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Analog joystick and gamepad driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/gameport.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+
+/*
+ * Option parsing.
+ */
+
+MODULE_PARM(js,"1-16s");
+
+#define ANALOG_PORTS 16
+
+static char *js[ANALOG_PORTS];
+static int analog_options[ANALOG_PORTS];
+
+/*
+ * Times, feature definitions.
+ */
+
+#define ANALOG_RUDDER 0x00004
+#define ANALOG_THROTTLE 0x00008
+#define ANALOG_AXES_STD 0x0000f
+#define ANALOG_BTNS_STD 0x000f0
+
+#define ANALOG_BTNS_CHF 0x00100
+#define ANALOG_HAT1_CHF 0x00200
+#define ANALOG_HAT2_CHF 0x00400
+#define ANALOG_HAT_FCS 0x00800
+#define ANALOG_HATS_ALL 0x00e00
+#define ANALOG_BTN_TL 0x01000
+#define ANALOG_BTN_TR 0x02000
+#define ANALOG_BTN_TL2 0x04000
+#define ANALOG_BTN_TR2 0x08000
+#define ANALOG_BTNS_TLR 0x03000
+#define ANALOG_BTNS_TLR2 0x0c000
+#define ANALOG_BTNS_GAMEPAD 0x0f000
+
+#define ANALOG_HBTN_CHF 0x10000
+#define ANALOG_ANY_CHF 0x10700
+#define ANALOG_SAITEK 0x20000
+#define ANALOG_EXTENSIONS 0x7ff00
+#define ANALOG_GAMEPAD 0x80000
+
+#define ANALOG_MAX_TIME 3 /* 3 ms */
+#define ANALOG_LOOP_TIME 2000 /* 2 * loop */
+#define ANALOG_REFRESH_TIME HZ/100 /* 10 ms */
+#define ANALOG_SAITEK_DELAY 200 /* 200 us */
+#define ANALOG_SAITEK_TIME 2000 /* 2000 us */
+#define ANALOG_AXIS_TIME 2 /* 2 * refresh */
+#define ANALOG_INIT_RETRIES 8 /* 8 times */
+#define ANALOG_FUZZ_BITS 2 /* 2 bit more */
+#define ANALOG_FUZZ_MAGIC 36 /* 36 u*ms/loop */
+
+#define ANALOG_MAX_NAME_LENGTH 128
+
+static short analog_axes[] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE };
+static short analog_hats[] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
+static short analog_pads[] = { BTN_Y, BTN_Z, BTN_TL, BTN_TR };
+static short analog_exts[] = { ANALOG_HAT1_CHF, ANALOG_HAT2_CHF, ANALOG_HAT_FCS };
+static short analog_pad_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_TL2, BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_BASE };
+static short analog_joy_btn[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2,
+ BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_BASE6 };
+
+static unsigned char analog_chf[] = { 0xf, 0x0, 0x1, 0x9, 0x2, 0x4, 0xc, 0x8, 0x3, 0x5, 0xb, 0x7, 0xd, 0xe, 0xa, 0x6 };
+
+struct analog {
+ struct input_dev dev;
+ int mask;
+ short *buttons;
+ char name[ANALOG_MAX_NAME_LENGTH];
+};
+
+struct analog_port {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct analog analog[2];
+ unsigned char mask;
+ char saitek;
+ char cooked;
+ int bads;
+ int reads;
+ int speed;
+ int loop;
+ int fuzz;
+ int axes[4];
+ int buttons;
+ int initial[4];
+ int used;
+ int axtime;
+};
+
+/*
+ * Time macros.
+ */
+
+#ifdef __i386__
+#ifdef CONFIG_X86_TSC
+#define GET_TIME(x) __asm__ __volatile__ ( "rdtsc" : "=a" (x) : : "dx" )
+#define DELTA(x,y) ((y)-(x))
+#define TIME_NAME "TSC"
+#else
+#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
+#define DELTA(x,y) ((x)-(y)+((x)<(y)?1193180L/HZ:0))
+#define TIME_NAME "PIT"
+#endif
+#elif __alpha__
+#define GET_TIME(x) __asm__ __volatile__ ( "rpcc %0" : "=r" (x) )
+#define DELTA(x,y) ((y)-(x))
+#define TIME_NAME "PCC"
+#endif
+
+#ifndef GET_TIME
+#define FAKE_TIME
+static unsigned long analog_faketime = 0;
+#define GET_TIME(x) do { x = analog_faketime++; } while(0)
+#define DELTA(x,y) ((y)-(x))
+#define TIME_NAME "Unreliable"
+#endif
+
+/*
+ * analog_decode() decodes analog joystick data and reports input events.
+ */
+
+static void analog_decode(struct analog *analog, int *axes, int *initial, int buttons)
+{
+ struct input_dev *dev = &analog->dev;
+ int i, j;
+
+ if (analog->mask & ANALOG_HAT_FCS)
+ for (i = 0; i < 4; i++)
+ if (axes[3] < ((initial[3] * ((i << 1) + 1)) >> 3)) {
+ buttons |= 1 << (i + 14);
+ break;
+ }
+
+ for (i = j = 0; i < 6; i++)
+ if (analog->mask & (0x10 << i))
+ input_report_key(dev, analog->buttons[j++], (buttons >> i) & 1);
+
+ if (analog->mask & ANALOG_HBTN_CHF)
+ for (i = 0; i < 4; i++)
+ input_report_key(dev, analog->buttons[j++], (buttons >> (i + 10)) & 1);
+
+ if (analog->mask & ANALOG_BTN_TL)
+ input_report_key(dev, analog_pads[0], axes[2] < (initial[2] >> 1));
+ if (analog->mask & ANALOG_BTN_TR)
+ input_report_key(dev, analog_pads[1], axes[3] < (initial[3] >> 1));
+ if (analog->mask & ANALOG_BTN_TL2)
+ input_report_key(dev, analog_pads[2], axes[2] > (initial[2] + (initial[2] >> 1)));
+ if (analog->mask & ANALOG_BTN_TR2)
+ input_report_key(dev, analog_pads[3], axes[3] > (initial[3] + (initial[3] >> 1)));
+
+ for (i = j = 0; i < 4; i++)
+ if (analog->mask & (1 << i))
+ input_report_abs(dev, analog_axes[j++], axes[i]);
+
+ for (i = j = 0; i < 3; i++)
+ if (analog->mask & analog_exts[i]) {
+ input_report_abs(dev, analog_hats[j++],
+ ((buttons >> ((i << 2) + 7)) & 1) - ((buttons >> ((i << 2) + 9)) & 1));
+ input_report_abs(dev, analog_hats[j++],
+ ((buttons >> ((i << 2) + 8)) & 1) - ((buttons >> ((i << 2) + 6)) & 1));
+ }
+}
+
+/*
+ * analog_cooked_read() reads analog joystick data.
+ */
+
+static int analog_cooked_read(struct analog_port *port)
+{
+ struct gameport *gameport = port->gameport;
+ unsigned int time[4], start, loop, now, loopout, timeout;
+ unsigned char data[4], this, last;
+ unsigned long flags;
+ int i, j;
+
+ loopout = (ANALOG_LOOP_TIME * port->loop) / 1000;
+ timeout = ANALOG_MAX_TIME * port->speed;
+
+ __save_flags(flags);
+ __cli();
+ gameport_trigger(gameport);
+ GET_TIME(now);
+ __restore_flags(flags);
+
+ start = now;
+ this = port->mask;
+ i = 0;
+
+ do {
+ loop = now;
+ last = this;
+
+ __cli();
+ this = gameport_read(gameport) & port->mask;
+ GET_TIME(now);
+ __restore_flags(flags);
+
+ if ((last ^ this) && (DELTA(loop, now) < loopout)) {
+ data[i] = last ^ this;
+ time[i] = now;
+ i++;
+ }
+
+ } while (this && (i < 4) && (DELTA(start, now) < timeout));
+
+ this <<= 4;
+
+ for (--i; i >= 0; i--) {
+ this |= data[i];
+ for (j = 0; j < 4; j++)
+ if (data[i] & (1 << j))
+ port->axes[j] = (DELTA(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop;
+ }
+
+ return -(this != port->mask);
+}
+
+static int analog_button_read(struct analog_port *port, char saitek, char chf)
+{
+ unsigned char u;
+ int t = 1, i = 0;
+ int strobe = gameport_time(port->gameport, ANALOG_SAITEK_TIME);
+
+ u = gameport_read(port->gameport);
+
+ if (!chf) {
+ port->buttons = (~u >> 4) & 0xf;
+ return 0;
+ }
+
+ port->buttons = 0;
+
+ while ((~u & 0xf0) && (i < 16) && t) {
+ port->buttons |= 1 << analog_chf[(~u >> 4) & 0xf];
+ if (!saitek) return 0;
+ udelay(ANALOG_SAITEK_DELAY);
+ t = strobe;
+ gameport_trigger(port->gameport);
+ while (((u = gameport_read(port->gameport)) & port->mask) && t) t--;
+ i++;
+ }
+
+ return -(!t || (i == 16));
+}
+
+/*
+ * analog_timer() repeatedly polls the Analog joysticks.
+ */
+
+static void analog_timer(unsigned long data)
+{
+ struct analog_port *port = (void *) data;
+ int i;
+
+ char saitek = !!(port->analog[0].mask & ANALOG_SAITEK);
+ char chf = !!(port->analog[0].mask & ANALOG_ANY_CHF);
+
+ if (port->cooked) {
+ port->bads -= gameport_cooked_read(port->gameport, port->axes, &port->buttons);
+ if (chf)
+ port->buttons = port->buttons ? (1 << analog_chf[port->buttons]) : 0;
+ port->reads++;
+ } else {
+ if (!port->axtime--) {
+ port->bads -= analog_cooked_read(port);
+ port->bads -= analog_button_read(port, saitek, chf);
+ port->reads++;
+ port->axtime = ANALOG_AXIS_TIME - 1;
+ } else {
+ if (!saitek)
+ analog_button_read(port, saitek, chf);
+ }
+ }
+
+ for (i = 0; i < 2; i++)
+ if (port->analog[i].mask)
+ analog_decode(port->analog + i, port->axes, port->initial, port->buttons);
+
+ mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
+}
+
+/*
+ * analog_open() is a callback from the input open routine.
+ */
+
+static int analog_open(struct input_dev *dev)
+{
+ struct analog_port *port = dev->private;
+ if (!port->used++)
+ mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
+ return 0;
+}
+
+/*
+ * analog_close() is a callback from the input close routine.
+ */
+
+static void analog_close(struct input_dev *dev)
+{
+ struct analog_port *port = dev->private;
+ if (!--port->used)
+ del_timer(&port->timer);
+}
+
+/*
+ * analog_calibrate_timer() calibrates the timer and computes loop
+ * and timeout values for a joystick port.
+ */
+
+static void analog_calibrate_timer(struct analog_port *port)
+{
+ struct gameport *gameport = port->gameport;
+ unsigned int i, t, tx, t1, t2, t3;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ GET_TIME(t1);
+#ifdef FAKE_TIME
+ analog_faketime += 830;
+#endif
+ udelay(1000);
+ GET_TIME(t2);
+ GET_TIME(t3);
+ restore_flags(flags);
+
+ port->speed = DELTA(t1, t2) - DELTA(t2, t3);
+
+ tx = ~0;
+
+ for (i = 0; i < 50; i++) {
+ save_flags(flags);
+ cli();
+ GET_TIME(t1);
+ for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); }
+ GET_TIME(t3);
+ restore_flags(flags);
+ udelay(i);
+ t = DELTA(t1, t2) - DELTA(t2, t3);
+ if (t < tx) tx = t;
+ }
+
+ port->loop = tx / 50;
+}
+
+/*
+ * analog_name() constructs a name for an analog joystick.
+ */
+
+static void analog_name(struct analog *analog)
+{
+ sprintf(analog->name, "Analog %d-axis %d-button",
+ hweight8(analog->mask & ANALOG_AXES_STD),
+ hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
+ hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
+
+ if (analog->mask & ANALOG_HATS_ALL)
+ sprintf(analog->name, "%s %d-hat",
+ analog->name, hweight16(analog->mask & ANALOG_HATS_ALL));
+
+ if (analog->mask & ANALOG_HAT_FCS)
+ strcat(analog->name, " FCS");
+ if (analog->mask & ANALOG_ANY_CHF)
+ strcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF");
+
+ strcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick");
+}
+
+/*
+ * analog_init_device()
+ */
+
+static void analog_init_device(struct analog_port *port, struct analog *analog, int index)
+{
+ int i, j, t, v, w, x, y, z;
+
+ analog_name(analog);
+
+ analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn;
+
+ analog->dev.name = analog->name;
+ analog->dev.idbus = BUS_GAMEPORT;
+ analog->dev.idvendor = GAMEPORT_ID_VENDOR_ANALOG;
+ analog->dev.idproduct = analog->mask >> 4;
+ analog->dev.idversion = 0x0100;
+
+ analog->dev.open = analog_open;
+ analog->dev.close = analog_close;
+ analog->dev.private = port;
+ analog->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (i = j = 0; i < 4; i++)
+ if (analog->mask & (1 << i)) {
+
+ t = analog_axes[j];
+ x = port->axes[i];
+ y = (port->axes[0] + port->axes[1]) >> 1;
+ z = y - port->axes[i];
+ z = z > 0 ? z : -z;
+ v = (x >> 3);
+ w = (x >> 3);
+
+ set_bit(t, analog->dev.absbit);
+
+ if ((i == 2 || i == 3) && (j == 2 || j == 3) && (z > (y >> 3)))
+ x = y;
+
+ if (analog->mask & ANALOG_SAITEK) {
+ if (i == 2) x = port->axes[i];
+ v = x - (x >> 2);
+ w = (x >> 4);
+ }
+
+ analog->dev.absmax[t] = (x << 1) - v;
+ analog->dev.absmin[t] = v;
+ analog->dev.absfuzz[t] = port->fuzz;
+ analog->dev.absflat[t] = w;
+
+ j++;
+ }
+
+ for (i = j = 0; i < 3; i++)
+ if (analog->mask & analog_exts[i])
+ for (x = 0; x < 2; x++) {
+ t = analog_hats[j++];
+ set_bit(t, analog->dev.absbit);
+ analog->dev.absmax[t] = 1;
+ analog->dev.absmin[t] = -1;
+ }
+
+ for (i = j = 0; i < 4; i++)
+ if (analog->mask & (0x10 << i))
+ set_bit(analog->buttons[j++], analog->dev.keybit);
+
+ if (analog->mask & ANALOG_BTNS_CHF)
+ for (i = 0; i < 2; i++)
+ set_bit(analog->buttons[j++], analog->dev.keybit);
+
+ if (analog->mask & ANALOG_HBTN_CHF)
+ for (i = 0; i < 4; i++)
+ set_bit(analog->buttons[j++], analog->dev.keybit);
+
+ for (i = 0; i < 4; i++)
+ if (analog->mask & (ANALOG_BTN_TL << i))
+ set_bit(analog_pads[i], analog->dev.keybit);
+
+ analog_decode(analog, port->axes, port->initial, port->buttons);
+
+ input_register_device(&analog->dev);
+
+ printk(KERN_INFO "input%d: %s at gameport%d.%d",
+ analog->dev.number, analog->name, port->gameport->number, index);
+
+ if (port->cooked)
+ printk(" [ADC port]\n");
+ else
+ printk(" ["TIME_NAME" timer, %d %sHz clock, %d ns res]\n",
+ port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed,
+ port->speed > 10000 ? "M" : "k", (port->loop * 1000000) / port->speed);
+}
+
+/*
+ * analog_init_devices() sets up device-specific values and registers the input devices.
+ */
+
+static int analog_init_masks(struct analog_port *port)
+{
+ int i;
+ struct analog *analog = port->analog;
+ int max[4];
+
+ if (!port->mask)
+ return -1;
+
+ if ((port->mask & 3) != 3 && port->mask != 0xc) {
+ printk(KERN_WARNING "analog.c: Unknown joystick device found "
+ "(data=%#x, gameport%d), probably not analog joystick.\n",
+ port->mask, port->gameport->number);
+ return -1;
+ }
+
+ i = port->gameport->number < ANALOG_PORTS ? analog_options[port->gameport->number] : 0xff;
+
+ analog[0].mask = i & 0xfffff;
+
+ analog[0].mask &= ~(ANALOG_AXES_STD | ANALOG_HAT_FCS | ANALOG_BTNS_GAMEPAD)
+ | port->mask | ((port->mask << 8) & ANALOG_HAT_FCS)
+ | ((port->mask << 10) & ANALOG_BTNS_TLR) | ((port->mask << 12) & ANALOG_BTNS_TLR2);
+
+ analog[0].mask &= ~(ANALOG_HAT2_CHF)
+ | ((analog[0].mask & ANALOG_HBTN_CHF) ? 0 : ANALOG_HAT2_CHF);
+
+ analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_BTN_TR | ANALOG_BTN_TR2)
+ | ((~analog[0].mask & ANALOG_HAT_FCS) >> 8)
+ | ((~analog[0].mask & ANALOG_HAT_FCS) << 2)
+ | ((~analog[0].mask & ANALOG_HAT_FCS) << 4);
+
+ analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_RUDDER)
+ | (((~analog[0].mask & ANALOG_BTNS_TLR ) >> 10)
+ & ((~analog[0].mask & ANALOG_BTNS_TLR2) >> 12));
+
+ analog[1].mask = ((i >> 20) & 0xff) | ((i >> 12) & 0xf0000);
+
+ analog[1].mask &= (analog[0].mask & ANALOG_EXTENSIONS) ? ANALOG_GAMEPAD
+ : (((ANALOG_BTNS_STD | port->mask) & ~analog[0].mask) | ANALOG_GAMEPAD);
+
+ if (port->cooked) {
+
+ for (i = 0; i < 4; i++) max[i] = port->axes[i] << 1;
+
+ if ((analog[0].mask & 0x7) == 0x7) max[2] = (max[0] + max[1]) >> 1;
+ if ((analog[0].mask & 0xb) == 0xb) max[3] = (max[0] + max[1]) >> 1;
+ if ((analog[0].mask & ANALOG_BTN_TL) && !(analog[0].mask & ANALOG_BTN_TL2)) max[2] >>= 1;
+ if ((analog[0].mask & ANALOG_BTN_TR) && !(analog[0].mask & ANALOG_BTN_TR2)) max[3] >>= 1;
+ if ((analog[0].mask & ANALOG_HAT_FCS)) max[3] >>= 1;
+
+ gameport_calibrate(port->gameport, port->axes, max);
+ }
+
+ for (i = 0; i < 4; i++)
+ port->initial[i] = port->axes[i];
+
+ return -!(analog[0].mask || analog[1].mask);
+}
+
+static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, struct analog_port *port)
+{
+ int i, t, u, v;
+
+ gameport->private = port;
+ port->gameport = gameport;
+ init_timer(&port->timer);
+ port->timer.data = (long) port;
+ port->timer.function = analog_timer;
+
+ if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
+
+ analog_calibrate_timer(port);
+
+ gameport_trigger(gameport);
+ t = gameport_read(gameport);
+ wait_ms(ANALOG_MAX_TIME);
+ port->mask = (gameport_read(gameport) ^ t) & t & 0xf;
+ port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS;
+
+ for (i = 0; i < ANALOG_INIT_RETRIES; i++) {
+ if (!analog_cooked_read(port)) break;
+ wait_ms(ANALOG_MAX_TIME);
+ }
+
+ u = v = 0;
+
+ wait_ms(ANALOG_MAX_TIME);
+ t = gameport_time(gameport, ANALOG_MAX_TIME * 1000);
+ gameport_trigger(gameport);
+ while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++;
+ udelay(ANALOG_SAITEK_DELAY);
+ t = gameport_time(gameport, ANALOG_SAITEK_TIME);
+ gameport_trigger(gameport);
+ while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++;
+
+ if (v < (u >> 1) && port->gameport->number < ANALOG_PORTS) {
+ analog_options[port->gameport->number] |=
+ ANALOG_SAITEK | ANALOG_BTNS_CHF | ANALOG_HBTN_CHF | ANALOG_HAT1_CHF;
+ return 0;
+ }
+
+ gameport_close(gameport);
+ }
+
+ if (!gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
+
+ for (i = 0; i < ANALOG_INIT_RETRIES; i++)
+ if (!gameport_cooked_read(gameport, port->axes, &port->buttons))
+ break;
+ for (i = 0; i < 4; i++)
+ if (port->axes[i] != -1) port->mask |= 1 << i;
+
+ port->fuzz = gameport->fuzz;
+ port->cooked = 1;
+ return 0;
+ }
+
+ if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ return 0;
+
+ return -1;
+}
+
+static void analog_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct analog_port *port;
+ int i;
+
+ if (!(port = kmalloc(sizeof(struct analog_port), GFP_KERNEL)))
+ return;
+ memset(port, 0, sizeof(struct analog_port));
+
+ if (analog_init_port(gameport, dev, port)) {
+ kfree(port);
+ return;
+ }
+
+ if (analog_init_masks(port)) {
+ gameport_close(gameport);
+ kfree(port);
+ return;
+ }
+
+ for (i = 0; i < 2; i++)
+ if (port->analog[i].mask)
+ analog_init_device(port, port->analog + i, i);
+}
+
+static void analog_disconnect(struct gameport *gameport)
+{
+ int i;
+
+ struct analog_port *port = gameport->private;
+ for (i = 0; i < 2; i++)
+ if (port->analog[i].mask)
+ input_unregister_device(&port->analog[i].dev);
+ gameport_close(gameport);
+ printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on gameport%d failed\n",
+ port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0,
+ port->gameport->number);
+ kfree(port);
+}
+
+struct analog_types {
+ char *name;
+ int value;
+};
+
+struct analog_types analog_types[] = {
+ { "none", 0x00000000 },
+ { "auto", 0x000000ff },
+ { "2btn", 0x0000003f },
+ { "y-joy", 0x0cc00033 },
+ { "y-pad", 0x8cc80033 },
+ { "fcs", 0x000008f7 },
+ { "chf", 0x000002ff },
+ { "fullchf", 0x000007ff },
+ { "gamepad", 0x000830f3 },
+ { "gamepad8", 0x0008f0f3 },
+ { NULL, 0 }
+};
+
+static void analog_parse_options(void)
+{
+ int i, j;
+ char *end;
+
+ for (i = 0; i < ANALOG_PORTS && js[i]; i++) {
+
+ for (j = 0; analog_types[j].name; j++)
+ if (!strcmp(analog_types[j].name, js[i])) {
+ analog_options[i] = analog_types[j].value;
+ break;
+ }
+ if (analog_types[j].name) continue;
+
+ analog_options[i] = simple_strtoul(js[i], &end, 0);
+ if (end != js[i]) continue;
+
+ analog_options[i] = 0xff;
+ if (!strlen(js[i])) continue;
+
+ printk(KERN_WARNING "analog.c: Bad config for port %d - \"%s\"\n", i, js[i]);
+ }
+
+ for (; i < ANALOG_PORTS; i++)
+ analog_options[i] = 0xff;
+}
+
+/*
+ * The gameport device structure.
+ */
+
+static struct gameport_dev analog_dev = {
+ connect: analog_connect,
+ disconnect: analog_disconnect,
+};
+
+#ifndef MODULE
+static int __init analog_setup(char *str)
+{
+ char *s = str;
+ int i = 0;
+
+ if (!str || !*str) return 0;
+
+ while ((str = s) && (i < ANALOG_PORTS)) {
+ if ((s = strchr(str,','))) *s++ = 0;
+ js[i++] = str;
+ }
+
+ return 1;
+}
+__setup("js=", analog_setup);
+#endif
+
+int __init analog_init(void)
+{
+ analog_parse_options();
+ gameport_register_device(&analog_dev);
+ return 0;
+}
+
+void __exit analog_exit(void)
+{
+ gameport_unregister_device(&analog_dev);
+}
+
+module_init(analog_init);
+module_exit(analog_exit);
diff --git a/drivers/char/joystick/cobra.c b/drivers/char/joystick/cobra.c
new file mode 100644
index 000000000..f059a2ff6
--- /dev/null
+++ b/drivers/char/joystick/cobra.c
@@ -0,0 +1,250 @@
+/*
+ * $Id: cobra.c,v 1.10 2000/06/08 10:23:45 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Creative Labd Blaster GamePad Cobra driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */
+#define COBRA_REFRESH_TIME HZ/50 /* 20 ms between reads */
+#define COBRA_LENGTH 36
+
+static char* cobra_name = "Creative Labs Blaster GamePad Cobra";
+
+static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 };
+
+struct cobra {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct input_dev dev[2];
+ int used;
+ int reads;
+ int bads;
+ unsigned char exists;
+};
+
+static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data)
+{
+ unsigned long flags;
+ unsigned char u, v, w;
+ __u64 buf[2];
+ int r[2], t[2];
+ int i, j, ret;
+
+ int strobe = gameport_time(gameport, COBRA_MAX_STROBE);
+
+ for (i = 0; i < 2; i++) {
+ r[i] = buf[i] = 0;
+ t[i] = COBRA_MAX_STROBE;
+ }
+
+ __save_flags(flags);
+ __cli();
+
+ u = gameport_read(gameport);
+
+ do {
+ t[0]--; t[1]--;
+ v = gameport_read(gameport);
+ for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2)
+ if (w & 0x30) {
+ if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) {
+ buf[i] |= (__u64)((w >> 5) & 1) << r[i]++;
+ t[i] = strobe;
+ u = v;
+ } else t[i] = 0;
+ }
+ } while (t[0] > 0 || t[1] > 0);
+
+ __restore_flags(flags);
+
+ ret = 0;
+
+ for (i = 0; i < 2; i++) {
+
+ if (r[i] != COBRA_LENGTH) continue;
+
+ for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++)
+ buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1));
+
+ if (j < COBRA_LENGTH) ret |= (1 << i);
+
+ data[i] = ((buf[i] >> 7) & 0x000001f) | ((buf[i] >> 8) & 0x00003e0)
+ | ((buf[i] >> 9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000)
+ | ((buf[i] >> 11) & 0x1f00000);
+
+ }
+
+ return ret;
+}
+
+static void cobra_timer(unsigned long private)
+{
+ struct cobra *cobra = (void *) private;
+ struct input_dev *dev;
+ unsigned int data[2];
+ int i, j, r;
+
+ cobra->reads++;
+
+ if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists)
+ cobra->bads++;
+
+ for (i = 0; i < 2; i++)
+ if (cobra->exists & r & (1 << i)) {
+
+ dev = cobra->dev + i;
+
+ input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1));
+ input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1));
+
+ for (j = 0; cobra_btn[j]; j++)
+ input_report_key(dev, cobra_btn[j], data[i] & (0x20 << i));
+
+ }
+
+ mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
+}
+
+static int cobra_open(struct input_dev *dev)
+{
+ struct cobra *cobra = dev->private;
+ if (!cobra->used++)
+ mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
+ return 0;
+}
+
+static void cobra_close(struct input_dev *dev)
+{
+ struct cobra *cobra = dev->private;
+ if (!--cobra->used)
+ del_timer(&cobra->timer);
+}
+
+static void cobra_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct cobra *cobra;
+ unsigned int data[2];
+ int i, j;
+
+ if (!(cobra = kmalloc(sizeof(struct cobra), GFP_KERNEL)))
+ return;
+ memset(cobra, 0, sizeof(struct cobra));
+
+ gameport->private = cobra;
+
+ cobra->gameport = gameport;
+ init_timer(&cobra->timer);
+ cobra->timer.data = (long) cobra;
+ cobra->timer.function = cobra_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ goto fail1;
+
+ cobra->exists = cobra_read_packet(gameport, data);
+
+ for (i = 0; i < 2; i++)
+ if ((cobra->exists >> i) & data[i] & 1) {
+ printk(KERN_WARNING "cobra.c: Device on gameport%d.%d has the Ext bit set. ID is: %d"
+ " Contact vojtech@suse.cz\n", gameport->number, i, (data[i] >> 2) & 7);
+ cobra->exists &= ~(1 << i);
+ }
+
+ if (!cobra->exists)
+ goto fail2;
+
+ for (i = 0; i < 2; i++)
+ if ((cobra->exists >> i) & 1) {
+
+ cobra->dev[i].private = cobra;
+ cobra->dev[i].open = cobra_open;
+ cobra->dev[i].close = cobra_close;
+
+ cobra->dev[i].name = cobra_name;
+ cobra->dev[i].idbus = BUS_GAMEPORT;
+ cobra->dev[i].idvendor = GAMEPORT_ID_VENDOR_CREATIVE;
+ cobra->dev[i].idproduct = 0x0008;
+ cobra->dev[i].idversion = 0x0100;
+
+ cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+ for (j = 0; cobra_btn[j]; j++)
+ set_bit(cobra_btn[j], cobra->dev[i].keybit);
+
+ cobra->dev[i].absmin[ABS_X] = -1; cobra->dev[i].absmax[ABS_X] = 1;
+ cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1;
+
+ input_register_device(cobra->dev + i);
+ printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
+ cobra->dev[i].number, cobra_name, gameport->number, i);
+ }
+
+
+ return;
+fail2: gameport_close(gameport);
+fail1: kfree(cobra);
+}
+
+static void cobra_disconnect(struct gameport *gameport)
+{
+ int i;
+
+ struct cobra *cobra = gameport->private;
+ for (i = 0; i < 2; i++)
+ if ((cobra->exists >> i) & 1)
+ input_unregister_device(cobra->dev + i);
+ gameport_close(gameport);
+ kfree(cobra);
+}
+
+static struct gameport_dev cobra_dev = {
+ connect: cobra_connect,
+ disconnect: cobra_disconnect,
+};
+
+int __init cobra_init(void)
+{
+ gameport_register_device(&cobra_dev);
+ return 0;
+}
+
+void __exit cobra_exit(void)
+{
+ gameport_unregister_device(&cobra_dev);
+}
+
+module_init(cobra_init);
+module_exit(cobra_exit);
diff --git a/drivers/char/joystick/db9.c b/drivers/char/joystick/db9.c
new file mode 100644
index 000000000..f9edd0755
--- /dev/null
+++ b/drivers/char/joystick/db9.c
@@ -0,0 +1,423 @@
+/*
+ * $Id: db9.c,v 1.5 2000/05/29 20:39:38 vojtech Exp $
+ *
+ * Copyright (c) 1999 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Andree Borrmann Mats Sjövall
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_PARM(db9, "2i");
+MODULE_PARM(db9_2, "2i");
+MODULE_PARM(db9_3, "2i");
+
+#define DB9_MULTI_STICK 0x01
+#define DB9_MULTI2_STICK 0x02
+#define DB9_GENESIS_PAD 0x03
+#define DB9_GENESIS5_PAD 0x05
+#define DB9_GENESIS6_PAD 0x06
+#define DB9_SATURN_PAD 0x07
+#define DB9_MULTI_0802 0x08
+#define DB9_MULTI_0802_2 0x09
+#define DB9_CD32_PAD 0x0A
+#define DB9_MAX_PAD 0x0B
+
+#define DB9_UP 0x01
+#define DB9_DOWN 0x02
+#define DB9_LEFT 0x04
+#define DB9_RIGHT 0x08
+#define DB9_FIRE1 0x10
+#define DB9_FIRE2 0x20
+#define DB9_FIRE3 0x40
+#define DB9_FIRE4 0x80
+
+#define DB9_NORMAL 0x0a
+#define DB9_NOSELECT 0x08
+
+#define DB9_SATURN0 0x00
+#define DB9_SATURN1 0x02
+#define DB9_SATURN2 0x04
+#define DB9_SATURN3 0x06
+
+#define DB9_GENESIS6_DELAY 14
+#define DB9_REFRESH_TIME HZ/100
+
+static int db9[] __initdata = { -1, 0 };
+static int db9_2[] __initdata = { -1, 0 };
+static int db9_3[] __initdata = { -1, 0 };
+
+struct db9 {
+ struct input_dev dev[2];
+ struct timer_list timer;
+ struct pardevice *pd;
+ int mode;
+ int used;
+};
+
+static struct db9 *db9_base[3];
+
+static short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB };
+static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE };
+static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START };
+
+static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 8, 1, 1, 7 };
+static short *db9_btn[DB9_MAX_PAD] = { db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn,
+ db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn };
+static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad",
+ NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick",
+ "Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad" };
+
+static void db9_timer(unsigned long private)
+{
+ struct db9 *db9 = (void *) private;
+ struct parport *port = db9->pd->port;
+ struct input_dev *dev = db9->dev;
+ int data, i;
+
+ switch(db9->mode) {
+ case DB9_MULTI_0802_2:
+
+ data = parport_read_data(port) >> 3;
+
+ input_report_abs(dev + 1, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev + 1, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1));
+ input_report_key(dev + 1, BTN_TRIGGER, ~data&DB9_FIRE1);
+
+ case DB9_MULTI_0802:
+
+ data = parport_read_status(port) >> 3;
+
+ input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1));
+ input_report_key(dev, BTN_TRIGGER, data&DB9_FIRE1);
+ break;
+
+ case DB9_MULTI_STICK:
+
+ data = parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1));
+ input_report_key(dev, BTN_TRIGGER, ~data&DB9_FIRE1);
+ break;
+
+ case DB9_MULTI2_STICK:
+
+ data = parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1));
+ input_report_key(dev, BTN_TRIGGER, ~data&DB9_FIRE1);
+ input_report_key(dev, BTN_THUMB, ~data&DB9_FIRE2);
+ break;
+
+ case DB9_GENESIS_PAD:
+
+ parport_write_control(port, DB9_NOSELECT);
+ data = parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1));
+ input_report_key(dev, BTN_B, ~data&DB9_FIRE1);
+ input_report_key(dev, BTN_C, ~data&DB9_FIRE2);
+
+ parport_write_control(port, DB9_NORMAL);
+ data=parport_read_data(port);
+
+ input_report_key(dev, BTN_A, ~data&DB9_FIRE1);
+ input_report_key(dev, BTN_START, ~data&DB9_FIRE2);
+ break;
+
+ case DB9_GENESIS5_PAD:
+
+ parport_write_control(port, DB9_NOSELECT);
+ data=parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1));
+ input_report_key(dev, BTN_B, ~data&DB9_FIRE1);
+ input_report_key(dev, BTN_C, ~data&DB9_FIRE2);
+
+ parport_write_control(port, DB9_NORMAL);
+ data=parport_read_data(port);
+
+ input_report_key(dev, BTN_A, ~data&DB9_FIRE1);
+ input_report_key(dev, BTN_X, ~data&DB9_FIRE2);
+ input_report_key(dev, BTN_Y, ~data&DB9_LEFT);
+ input_report_key(dev, BTN_START, ~data&DB9_RIGHT);
+ break;
+
+ case DB9_GENESIS6_PAD:
+
+ parport_write_control(port, DB9_NOSELECT); /* 1 */
+ udelay(DB9_GENESIS6_DELAY);
+ data=parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1));
+ input_report_key(dev, BTN_B, ~data&DB9_FIRE1);
+ input_report_key(dev, BTN_C, ~data&DB9_FIRE2);
+
+ parport_write_control(port, DB9_NORMAL);
+ udelay(DB9_GENESIS6_DELAY);
+ data=parport_read_data(port);
+
+ input_report_key(dev, BTN_A, ~data&DB9_FIRE1);
+ input_report_key(dev, BTN_X, ~data&DB9_FIRE2);
+
+ parport_write_control(port, DB9_NOSELECT); /* 2 */
+ udelay(DB9_GENESIS6_DELAY);
+ parport_write_control(port, DB9_NORMAL);
+ udelay(DB9_GENESIS6_DELAY);
+ parport_write_control(port, DB9_NOSELECT); /* 3 */
+ udelay(DB9_GENESIS6_DELAY);
+ data=parport_read_data(port);
+
+ input_report_key(dev, BTN_Y, ~data&DB9_LEFT);
+ input_report_key(dev, BTN_Z, ~data&DB9_DOWN);
+ input_report_key(dev, BTN_MODE, ~data&DB9_UP);
+ input_report_key(dev, BTN_START, ~data&DB9_RIGHT);
+
+ parport_write_control(port, DB9_NORMAL);
+ udelay(DB9_GENESIS6_DELAY);
+ parport_write_control(port, DB9_NOSELECT); /* 4 */
+ udelay(DB9_GENESIS6_DELAY);
+ parport_write_control(port, DB9_NORMAL);
+ break;
+
+ case DB9_SATURN_PAD:
+
+ parport_write_control(port, DB9_SATURN0);
+ data = parport_read_data(port);
+
+ input_report_key(dev, BTN_Y, ~data&DB9_LEFT);
+ input_report_key(dev, BTN_Z, ~data&DB9_DOWN);
+ input_report_key(dev, BTN_TL,~data&DB9_UP);
+ input_report_key(dev, BTN_TR,~data&DB9_RIGHT);
+
+ parport_write_control(port, DB9_SATURN2);
+ data = parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1));
+
+ parport_write_control(port, DB9_NORMAL);
+ data = parport_read_data(port);
+
+ input_report_key(dev, BTN_A, ~data&DB9_LEFT);
+ input_report_key(dev, BTN_B, ~data&DB9_UP);
+ input_report_key(dev, BTN_C, ~data&DB9_DOWN);
+ input_report_key(dev, BTN_X, ~data&DB9_RIGHT);
+ break;
+
+ case DB9_CD32_PAD:
+
+ data=parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1));
+
+ parport_write_control(port, 0x0a);
+
+ for (i = 0; i < 7; i++) {
+ data = parport_read_data(port);
+ parport_write_control(port, 0x02);
+ parport_write_control(port, 0x0a);
+ input_report_key(dev, db9_cd32_btn[i], ~data&DB9_FIRE2);
+ }
+
+ parport_write_control(port, 0x00);
+ break;
+ }
+
+ mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
+}
+
+static int db9_open(struct input_dev *dev)
+{
+ struct db9 *db9 = dev->private;
+ struct parport *port = db9->pd->port;
+
+ if (!db9->used++) {
+ parport_claim(db9->pd);
+ parport_write_data(port, 0xff);
+ parport_data_reverse(port);
+ parport_write_control(port, DB9_NORMAL);
+ mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
+ }
+
+ return 0;
+}
+
+static void db9_close(struct input_dev *dev)
+{
+ struct db9 *db9 = dev->private;
+ struct parport *port = db9->pd->port;
+
+ if (!--db9->used) {
+ del_timer(&db9->timer);
+ parport_write_control(port, 0x00);
+ parport_data_forward(port);
+ parport_release(db9->pd);
+ }
+}
+
+static struct db9 __init *db9_probe(int *config)
+{
+ struct db9 *db9;
+ struct parport *pp;
+ int i, j;
+
+ if (config[0] < 0)
+ return NULL;
+ if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) {
+ printk(KERN_ERR "db9.c: bad config\n");
+ return NULL;
+ }
+
+ for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
+ config[0]--;
+
+ if (!pp) {
+ printk(KERN_ERR "db9.c: no such parport\n");
+ return NULL;
+ }
+
+ if (!(pp->modes & PARPORT_MODE_TRISTATE) && config[1] != DB9_MULTI_0802) {
+ printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
+ return NULL;
+ }
+
+ if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL)))
+ return NULL;
+ memset(db9, 0, sizeof(struct db9));
+
+ db9->mode = config[1];
+ init_timer(&db9->timer);
+ db9->timer.data = (long) db9;
+ db9->timer.function = db9_timer;
+
+ db9->pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+
+ if (!db9->pd) {
+ printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n");
+ kfree(db9);
+ return NULL;
+ }
+
+ for (i = 0; i < 1 + (db9->mode == DB9_MULTI_0802_2); i++) {
+
+ db9->dev[i].private = db9;
+ db9->dev[i].open = db9_open;
+ db9->dev[i].close = db9_close;
+
+ db9->dev[i].name = db9_name[db9->mode];
+ db9->dev[i].idbus = BUS_PARPORT;
+ db9->dev[i].idvendor = 0x0002;
+ db9->dev[i].idproduct = config[1];
+ db9->dev[i].idversion = 0x0100;
+
+ db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ db9->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+ for (j = 0; j < db9_buttons[db9->mode]; j++)
+ set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit);
+
+ db9->dev[i].absmin[ABS_X] = -1; db9->dev[i].absmax[ABS_X] = 1;
+ db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1;
+
+ input_register_device(db9->dev + i);
+ printk(KERN_INFO "input%d: %s on %s\n",
+ db9->dev[i].number, db9_name[db9->mode], db9->pd->port->name);
+ }
+
+ return db9;
+}
+
+#ifndef MODULE
+int __init db9_setup(char *str)
+{
+ int i, ints[3];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 2; i++) db9[i] = ints[i + 1];
+ return 1;
+}
+int __init db9_setup_2(char *str)
+{
+ int i, ints[3];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 2; i++) db9_2[i] = ints[i + 1];
+ return 1;
+}
+int __init db9_setup_3(char *str)
+{
+ int i, ints[3];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 2; i++) db9_3[i] = ints[i + 1];
+ return 1;
+}
+__setup("db9=", db9_setup);
+__setup("db9_2=", db9_setup_2);
+__setup("db9_3=", db9_setup_3);
+#endif
+
+int __init db9_init(void)
+{
+ db9_base[0] = db9_probe(db9);
+ db9_base[1] = db9_probe(db9_2);
+ db9_base[2] = db9_probe(db9_3);
+
+ if (db9_base[0] || db9_base[1] || db9_base[2])
+ return 0;
+
+ return -ENODEV;
+}
+
+void __exit db9_exit(void)
+{
+ int i, j;
+
+ for (i = 0; i < 3; i++)
+ if (db9_base[i]) {
+ for (j = 0; j < 1 + (db9_base[i]->mode == DB9_MULTI_0802_2); j++)
+ input_unregister_device(db9_base[i]->dev + j);
+ parport_unregister_device(db9_base[i]->pd);
+ }
+}
+
+module_init(db9_init);
+module_exit(db9_exit);
diff --git a/drivers/char/joystick/gamecon.c b/drivers/char/joystick/gamecon.c
new file mode 100644
index 000000000..a92ef58a9
--- /dev/null
+++ b/drivers/char/joystick/gamecon.c
@@ -0,0 +1,668 @@
+/*
+ * $Id: gamecon.c,v 1.4 2000/05/29 21:08:45 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Andree Borrmann John Dahlstrom
+ * David Kuder
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * NES, SNES, N64, Multi1, Multi2, PSX gamepad driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_PARM(gc, "2-6i");
+MODULE_PARM(gc_2,"2-6i");
+MODULE_PARM(gc_3,"2-6i");
+
+#define GC_SNES 1
+#define GC_NES 2
+#define GC_NES4 3
+#define GC_MULTI 4
+#define GC_MULTI2 5
+#define GC_N64 6
+#define GC_PSX 7
+
+#define GC_MAX 7
+
+#define GC_REFRESH_TIME HZ/100
+
+struct gc {
+ struct pardevice *pd;
+ struct input_dev dev[5];
+ struct timer_list timer;
+ unsigned char pads[GC_PSX + 1];
+ int used;
+};
+
+static struct gc *gc_base[3];
+
+static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 };
+static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
+static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 };
+
+static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
+
+static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
+ "Multisystem 2-button joystick", "N64 controller", "PSX pad",
+ "PSX NegCon", "PSX Analog contoller" };
+/*
+ * N64 support.
+ */
+
+static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
+static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START };
+
+#define GC_N64_LENGTH 32 /* N64 bit length, not including stop bit */
+#define GC_N64_REQUEST_LENGTH 37 /* transmit request sequence is 9 bits long */
+#define GC_N64_DELAY 133 /* delay between transmit request, and response ready (us) */
+#define GC_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */
+#define GC_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */
+ /* GC_N64_DWS > 24 is known to fail */
+#define GC_N64_POWER_W 0xe2 /* power during write (transmit request) */
+#define GC_N64_POWER_R 0xfd /* power during read */
+#define GC_N64_OUT 0x1d /* output bits to the 4 pads */
+ /* Reading the main axes of any N64 pad is known to fail if the corresponding bit */
+ /* in GC_N64_OUT is pulled low on the output port (by any routine) for more */
+ /* than 123 us */
+#define GC_N64_CLOCK 0x02 /* clock bits for read */
+
+/*
+ * gc_n64_read_packet() reads an N64 packet.
+ * Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
+ */
+
+static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
+{
+ int i;
+ unsigned long flags;
+
+/*
+ * Request the pad to transmit data
+ */
+
+ __save_flags(flags);
+ __cli();
+ for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) {
+ parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0));
+ udelay(GC_N64_DWS);
+ }
+ __restore_flags(flags);
+
+/*
+ * Wait for the pad response to be loaded into the 33-bit register of the adapter
+ */
+
+ udelay(GC_N64_DELAY);
+
+/*
+ * Grab data (ignoring the last bit, which is a stop bit)
+ */
+
+ for (i = 0; i < GC_N64_LENGTH; i++) {
+ parport_write_data(gc->pd->port, GC_N64_POWER_R);
+ data[i] = parport_read_status(gc->pd->port);
+ parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK);
+ }
+
+/*
+ * We must wait 200 ms here for the controller to reinitialize before the next read request.
+ * No worries as long as gc_read is polled less frequently than this.
+ */
+
+}
+
+/*
+ * NES/SNES support.
+ */
+
+#define GC_NES_DELAY 6 /* Delay between bits - 6us */
+#define GC_NES_LENGTH 8 /* The NES pads use 8 bits of data */
+#define GC_SNES_LENGTH 12 /* The SNES true length is 16, but the last 4 bits are unused */
+
+#define GC_NES_POWER 0xfc
+#define GC_NES_CLOCK 0x01
+#define GC_NES_LATCH 0x02
+
+static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
+static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
+static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_START, BTN_SELECT, BTN_X, BTN_Y, BTN_TL, BTN_TR };
+
+/*
+ * gc_nes_read_packet() reads a NES/SNES packet.
+ * Each pad uses one bit per byte. So all pads connected to
+ * this port are read in parallel.
+ */
+
+static void gc_nes_read_packet(struct gc *gc, int length, unsigned char *data)
+{
+ int i;
+
+ parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK | GC_NES_LATCH);
+ udelay(GC_NES_DELAY * 2);
+ parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
+
+ for (i = 0; i < length; i++) {
+ udelay(GC_NES_DELAY);
+ parport_write_data(gc->pd->port, GC_NES_POWER);
+ data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
+ udelay(GC_NES_DELAY);
+ parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
+ }
+}
+
+/*
+ * Multisystem joystick support
+ */
+
+#define GC_MULTI_LENGTH 5 /* Multi system joystick packet length is 5 */
+#define GC_MULTI2_LENGTH 6 /* One more bit for one more button */
+
+/*
+ * gc_multi_read_packet() reads a Multisystem joystick packet.
+ */
+
+static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data)
+{
+ int i;
+
+ for (i = 0; i < length; i++) {
+ parport_write_data(gc->pd->port, ~(1 << i));
+ data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
+ }
+}
+
+/*
+ * PSX support
+ */
+
+#define GC_PSX_DELAY 10
+#define GC_PSX_LENGTH 8 /* talk to the controller in bytes */
+
+#define GC_PSX_MOUSE 0x12 /* PSX Mouse */
+#define GC_PSX_NEGCON 0x23 /* NegCon pad */
+#define GC_PSX_NORMAL 0x41 /* Standard Digital controller */
+#define GC_PSX_ANALOGR 0x73 /* Analog controller in Red mode */
+#define GC_PSX_ANALOGG 0x53 /* Analog controller in Green mode */
+
+#define GC_PSX_CLOCK 0x04 /* Pin 3 */
+#define GC_PSX_COMMAND 0x01 /* Pin 1 */
+#define GC_PSX_POWER 0xf8 /* Pins 5-9 */
+#define GC_PSX_SELECT 0x02 /* Pin 2 */
+#define GC_PSX_NOPOWER 0x04
+
+static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
+static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
+ BTN_START, BTN_SELECT, BTN_THUMB, BTN_THUMB2 };
+
+/*
+ * gc_psx_command() writes 8bit command and reads 8bit data from
+ * the psx pad.
+ */
+
+static int gc_psx_command(struct gc *gc, int b)
+{
+ int i, cmd, ret = 0;
+
+ cmd = (b & 1) ? GC_PSX_COMMAND : 0;
+ for (i = 0; i < 8; i++) {
+ parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
+ udelay(GC_PSX_DELAY);
+ ret |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0;
+ cmd = (b & 1) ? GC_PSX_COMMAND : 0;
+ parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
+ udelay(GC_PSX_DELAY);
+ b >>= 1;
+ }
+ return ret;
+}
+
+/*
+ * gc_psx_read_packet() reads a whole psx packet and returns
+ * device identifier code.
+ */
+
+static int gc_psx_read_packet(struct gc *gc, int length, unsigned char *data)
+{
+ int i, ret;
+ unsigned long flags;
+
+ __save_flags(flags);
+ __cli();
+
+ parport_write_data(gc->pd->port, GC_PSX_POWER);
+
+ parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */
+ udelay(GC_PSX_DELAY * 2);
+ gc_psx_command(gc, 0x01); /* Access pad */
+ ret = gc_psx_command(gc, 0x42); /* Get device id */
+ if (gc_psx_command(gc, 0) == 'Z') /* okay? */
+ for (i = 0; i < length; i++)
+ data[i] = gc_psx_command(gc, 0);
+ else ret = -1;
+
+ parport_write_data(gc->pd->port, GC_PSX_SELECT | GC_PSX_CLOCK | GC_PSX_POWER);
+ __restore_flags(flags);
+
+ return ret;
+}
+
+/*
+ * gc_timer() reads and analyzes console pads data.
+ */
+
+#define GC_MAX_LENGTH GC_N64_LENGTH
+
+static void gc_timer(unsigned long private)
+{
+ struct gc *gc = (void *) private;
+ struct input_dev *dev = gc->dev;
+ unsigned char data[GC_MAX_LENGTH];
+ int i, j, s;
+
+/*
+ * N64 pads - must be read first, any read confuses them for 200 us
+ */
+
+ if (gc->pads[GC_N64]) {
+
+ gc_n64_read_packet(gc, data);
+
+ for (i = 0; i < 5; i++) {
+
+ s = gc_status_bit[i];
+
+ if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) {
+
+ signed char axes[2];
+ axes[0] = axes[1] = 0;
+
+ for (j = 0; j < 8; j++) {
+ if (data[23 - j] & s) axes[0] |= 1 << j;
+ if (data[31 - j] & s) axes[1] |= 1 << j;
+ }
+
+ input_report_abs(dev + i, ABS_X, axes[0]);
+ input_report_abs(dev + i, ABS_Y, -axes[1]);
+
+ input_report_abs(dev + i, ABS_HAT0X, !!(s & data[7]) - !!(s & data[6]));
+ input_report_abs(dev + i, ABS_HAT0Y, !!(s & data[5]) - !!(s & data[4]));
+
+ for (j = 0; j < 10; j++)
+ input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]);
+ }
+ }
+ }
+
+/*
+ * NES and SNES pads
+ */
+
+ if (gc->pads[GC_NES] || gc->pads[GC_SNES]) {
+
+ gc_nes_read_packet(gc, gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH, data);
+
+ for (i = 0; i < 5; i++) {
+
+ s = gc_status_bit[i];
+
+ if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
+ input_report_abs(dev + i, ABS_X, !!(s & data[7]) - !!(s & data[6]));
+ input_report_abs(dev + i, ABS_Y, !!(s & data[5]) - !!(s & data[4]));
+ }
+
+ if (s & gc->pads[GC_NES])
+ for (j = 0; j < 4; j++)
+ input_report_key(dev + i, gc_snes_btn[j], s & data[gc_nes_bytes[j]]);
+
+ if (s & gc->pads[GC_SNES])
+ for (j = 0; j < 8; j++)
+ input_report_key(dev + i, gc_snes_btn[j], s & data[gc_snes_bytes[j]]);
+ }
+ }
+
+/*
+ * Multi and Multi2 joysticks
+ */
+
+ if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2]) {
+
+ gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data);
+
+ for (i = 0; i < 5; i++) {
+
+ s = gc_status_bit[i];
+
+ if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) {
+ input_report_abs(dev + i, ABS_X, !!(s & data[3]) - !!(s & data[2]));
+ input_report_abs(dev + i, ABS_Y, !!(s & data[1]) - !!(s & data[0]));
+ input_report_key(dev + i, BTN_TRIGGER, s & data[4]);
+ }
+
+ if (s & gc->pads[GC_MULTI2])
+ input_report_key(dev + i, BTN_THUMB, s & data[5]);
+ }
+ }
+
+/*
+ * PSX controllers
+ */
+
+ if (gc->pads[GC_PSX]) {
+
+ for (i = 0; i < 5; i++)
+ if (gc->pads[GC_PSX] & gc_status_bit[i])
+ break;
+
+ switch (gc_psx_read_packet(gc, 6, data)) {
+
+ case GC_PSX_ANALOGG:
+
+ for (j = 0; j < 4; j++)
+ input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]);
+
+ input_report_abs(dev + i, ABS_HAT0X, !!(data[0]&0x20) - !!(data[0]&0x80));
+ input_report_abs(dev + i, ABS_HAT0Y, !!(data[0]&0x40) - !!(data[0]&0x10));
+
+ for (j = 0; j < 8; j++)
+ input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << i));
+
+ input_report_key(dev + i, BTN_START, ~data[0] & 0x08);
+ input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
+
+ break;
+
+ case GC_PSX_ANALOGR:
+
+ input_report_key(dev + i, BTN_THUMB, ~data[0] & 0x04);
+ input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
+
+ case GC_PSX_NORMAL:
+ case GC_PSX_NEGCON:
+
+ input_report_abs(dev + i, ABS_X, 128 + !!(data[0] & 0x20) * 127 - !!(data[0] & 0x80) * 128);
+ input_report_abs(dev + i, ABS_Y, 128 + !!(data[0] & 0x40) * 127 - !!(data[0] & 0x10) * 128);
+
+ for (j = 0; j < 8; j++)
+ input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << i));
+
+ input_report_key(dev + i, BTN_START, ~data[0] & 0x08);
+ input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
+
+ break;
+ }
+ }
+
+ mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
+}
+
+static int gc_open(struct input_dev *dev)
+{
+ struct gc *gc = dev->private;
+ if (!gc->used++) {
+ parport_claim(gc->pd);
+ parport_write_control(gc->pd->port, 0x04);
+ mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
+ }
+ return 0;
+}
+
+static void gc_close(struct input_dev *dev)
+{
+ struct gc *gc = dev->private;
+ if (!--gc->used) {
+ del_timer(&gc->timer);
+ parport_write_control(gc->pd->port, 0x00);
+ parport_release(gc->pd);
+ }
+}
+
+
+
+static struct gc __init *gc_probe(int *config)
+{
+ struct gc *gc;
+ struct parport *pp;
+ int i, j, psx, pbtn;
+ unsigned char data[2];
+
+ if (config[0] < 0)
+ return NULL;
+
+ for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
+ config[0]--;
+
+ if (!pp) {
+ printk(KERN_ERR "gamecon.c: no such parport\n");
+ return NULL;
+ }
+
+ if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL)))
+ return NULL;
+ memset(gc, 0, sizeof(struct gc));
+
+ gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+
+ if (!gc->pd) {
+ printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n");
+ kfree(gc);
+ return NULL;
+ }
+
+ parport_claim(gc->pd);
+
+ init_timer(&gc->timer);
+ gc->timer.data = (long) gc;
+ gc->timer.function = gc_timer;
+
+ for (i = 0; i < 5; i++) {
+
+ if (!config[i + 1])
+ continue;
+
+ if (config[i + 1] < 1 || config[i + 1] > GC_MAX) {
+ printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", config[i + 1]);
+ continue;
+ }
+
+ gc->dev[i].private = gc;
+ gc->dev[i].open = gc_open;
+ gc->dev[i].close = gc_close;
+
+ gc->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (j = 0; j < 2; j++) {
+ set_bit(ABS_X + j, gc->dev[i].absbit);
+ gc->dev[i].absmin[ABS_X + j] = -1;
+ gc->dev[i].absmax[ABS_X + j] = 1;
+ }
+
+ gc->pads[0] |= gc_status_bit[i];
+ gc->pads[config[i + 1]] |= gc_status_bit[i];
+
+ switch(config[i + 1]) {
+
+ case GC_N64:
+ for (j = 0; j < 10; j++)
+ set_bit(gc_n64_btn[j], gc->dev[j].keybit);
+
+ for (j = 0; j < 2; j++) {
+ set_bit(ABS_X + j, gc->dev[i].absbit);
+ gc->dev[i].absmin[ABS_X + j] = -127;
+ gc->dev[i].absmax[ABS_X + j] = 126;
+ gc->dev[i].absflat[ABS_X + j] = 2;
+ set_bit(ABS_HAT0X + j, gc->dev[i].absbit);
+ gc->dev[i].absmin[ABS_HAT0X + j] = -1;
+ gc->dev[i].absmax[ABS_HAT0X + j] = 1;
+ }
+
+ break;
+
+ case GC_SNES:
+ for (j = 0; j < 8; j++)
+ set_bit(gc_snes_btn[j], gc->dev[j].keybit);
+ break;
+
+ case GC_NES:
+ for (j = 0; j < 4; j++)
+ set_bit(gc_snes_btn[j], gc->dev[j].keybit);
+ break;
+
+ case GC_MULTI2:
+ set_bit(BTN_THUMB, gc->dev[i].keybit);
+
+ case GC_MULTI:
+ set_bit(BTN_TRIGGER, gc->dev[i].keybit);
+ break;
+
+ case GC_PSX:
+
+ psx = gc_psx_read_packet(gc, 2, data);
+
+ switch(psx) {
+ case GC_PSX_NEGCON:
+ config[i + 1] += 1;
+ case GC_PSX_NORMAL:
+ pbtn = 10;
+ break;
+
+ case GC_PSX_ANALOGG:
+ case GC_PSX_ANALOGR:
+ config[i + 1] += 2;
+ pbtn = 12;
+ for (j = 0; j < 6; j++) {
+ psx = gc_psx_abs[j];
+ set_bit(psx, gc->dev[i].absbit);
+ gc->dev[i].absmin[psx] = 4;
+ gc->dev[i].absmax[psx] = 252;
+ gc->dev[i].absflat[psx] = 2;
+ }
+ break;
+
+ case -1:
+ gc->pads[GC_PSX] &= ~gc_status_bit[i];
+ pbtn = 0;
+ printk(KERN_ERR "gamecon.c: No PSX controller found.\n");
+ break;
+
+ default:
+ gc->pads[GC_PSX] &= ~gc_status_bit[i];
+ pbtn = 0;
+ printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x,"
+ " please report to <vojtech@suse.cz>.\n", psx);
+ }
+
+ for (j = 0; j < pbtn; j++)
+ set_bit(gc_psx_btn[j], gc->dev[i].keybit);
+
+ break;
+ }
+
+ gc->dev[i].name = gc_names[config[i + 1]];
+ gc->dev[i].idbus = BUS_PARPORT;
+ gc->dev[i].idvendor = 0x0001;
+ gc->dev[i].idproduct = config[i + 1];
+ gc->dev[i].idversion = 0x0100;
+ }
+
+ parport_release(gc->pd);
+
+ if (!gc->pads[0]) {
+ parport_unregister_device(gc->pd);
+ kfree(gc);
+ return NULL;
+ }
+
+ for (i = 0; i < 5; i++)
+ if (gc->pads[0] & gc_status_bit[i]) {
+ input_register_device(gc->dev + i);
+ printk(KERN_INFO "input%d: %s on %s\n", gc->dev[i].number, gc->dev[i].name, gc->pd->port->name);
+ }
+
+ return gc;
+}
+
+#ifndef MODULE
+int __init gc_setup(char *str)
+{
+ int i, ints[7];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 6; i++) gc[i] = ints[i + 1];
+ return 1;
+}
+int __init gc_setup_2(char *str)
+{
+ int i, ints[7];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 6; i++) gc_2[i] = ints[i + 1];
+ return 1;
+}
+int __init gc_setup_3(char *str)
+{
+ int i, ints[7];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 6; i++) gc_3[i] = ints[i + 1];
+ return 1;
+}
+__setup("gc=", gc_setup);
+__setup("gc_2=", gc_setup_2);
+__setup("gc_3=", gc_setup_3);
+#endif
+
+int __init gc_init(void)
+{
+ gc_base[0] = gc_probe(gc);
+ gc_base[1] = gc_probe(gc_2);
+ gc_base[2] = gc_probe(gc_3);
+
+ if (gc_base[0] || gc_base[1] || gc_base[2])
+ return 0;
+
+ return -ENODEV;
+}
+
+void __exit gc_exit(void)
+{
+ int i, j;
+
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 5; j++)
+ if (gc_base[i]->pads[0] & gc_status_bit[j])
+ input_unregister_device(gc_base[i]->dev + j);
+ parport_unregister_device(gc_base[i]->pd);
+ }
+}
+
+module_init(gc_init);
+module_exit(gc_exit);
diff --git a/drivers/char/joystick/gameport.c b/drivers/char/joystick/gameport.c
new file mode 100644
index 000000000..5a5e1219b
--- /dev/null
+++ b/drivers/char/joystick/gameport.c
@@ -0,0 +1,198 @@
+/*
+ * $Id: gameport.c,v 1.5 2000/05/29 10:54:53 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * 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 <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, 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/malloc.h>
+#include <linux/isapnp.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+
+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 = NULL;
+static struct gameport_dev *gameport_dev = NULL;
+static int gameport_number = 0;
+
+/*
+ * gameport_measure_speed() measures the gameport i/o speed.
+ */
+
+static int gameport_measure_speed(struct gameport *gameport)
+{
+#ifdef __i386__
+
+#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->number = gameport_number++;
+ 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);
+
+ gameport_number--;
+}
+
+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);
+}
diff --git a/drivers/char/joystick/gf2k.c b/drivers/char/joystick/gf2k.c
new file mode 100644
index 000000000..cad8be16b
--- /dev/null
+++ b/drivers/char/joystick/gf2k.c
@@ -0,0 +1,359 @@
+/*
+ * $Id: gf2k.c,v 1.12 2000/06/04 14:53:44 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Genius Flight 2000 joystick driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/gameport.h>
+
+#define GF2K_START 400 /* The time we wait for the first bit [400 us] */
+#define GF2K_STROBE 40 /* The time we wait for the first bit [40 us] */
+#define GF2K_TIMEOUT 4 /* Wait for everything to settle [4 ms] */
+#define GF2K_LENGTH 80 /* Max number of triplets in a packet */
+#define GF2K_REFRESH HZ/50 /* Time between joystick polls [20 ms] */
+
+/*
+ * Genius joystick ids ...
+ */
+
+#define GF2K_ID_G09 1
+#define GF2K_ID_F30D 2
+#define GF2K_ID_F30 3
+#define GF2K_ID_F31D 4
+#define GF2K_ID_F305 5
+#define GF2K_ID_F23P 6
+#define GF2K_ID_F31 7
+#define GF2K_ID_MAX 7
+
+static char gf2k_length[] = { 40, 40, 40, 40, 40, 40, 40, 40 };
+static char gf2k_hat_to_axis[][2] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+static char *gf2k_names[] = {"", "Genius G-09D", "Genius F-30D", "Genius F-30", "Genius MaxFighter F-31D",
+ "Genius F-30-5", "Genius Flight2000 F-23", "Genius F-31"};
+static unsigned char gf2k_hats[] = { 0, 2, 0, 0, 2, 0, 2, 0 };
+static unsigned char gf2k_axes[] = { 0, 2, 0, 0, 4, 0, 4, 0 };
+static unsigned char gf2k_joys[] = { 0, 0, 0, 0,10, 0, 8, 0 };
+static unsigned char gf2k_pads[] = { 0, 6, 0, 0, 0, 0, 0, 0 };
+static unsigned char gf2k_lens[] = { 0,18, 0, 0,18, 0,18, 0 };
+
+static unsigned char gf2k_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_GAS, ABS_BRAKE };
+static short gf2k_btn_joy[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 };
+static short gf2k_btn_pad[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_START, BTN_SELECT };
+
+
+static short gf2k_seq_reset[] = { 240, 340, 0 };
+static short gf2k_seq_digital[] = { 590, 320, 860, 0 };
+
+struct gf2k {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct input_dev dev;
+ int reads;
+ int bads;
+ int used;
+ unsigned char id;
+ unsigned char length;
+};
+
+/*
+ * gf2k_read_packet() reads a Genius Flight2000 packet.
+ */
+
+static int gf2k_read_packet(struct gameport *gameport, int length, char *data)
+{
+ unsigned char u, v;
+ int i;
+ unsigned int t, p;
+ unsigned long flags;
+
+ t = gameport_time(gameport, GF2K_START);
+ p = gameport_time(gameport, GF2K_STROBE);
+
+ i = 0;
+
+ __save_flags(flags);
+ __cli();
+
+ gameport_trigger(gameport);
+ v = gameport_read(gameport);;
+
+ while (t > 0 && i < length) {
+ t--; u = v;
+ v = gameport_read(gameport);
+ if (v & ~u & 0x10) {
+ data[i++] = v >> 5;
+ t = p;
+ }
+ }
+
+ __restore_flags(flags);
+
+ return i;
+}
+
+/*
+ * gf2k_trigger_seq() initializes a Genius Flight2000 joystick
+ * into digital mode.
+ */
+
+static void gf2k_trigger_seq(struct gameport *gameport, short *seq)
+{
+
+ unsigned long flags;
+ int i, t;
+
+ __save_flags(flags);
+ __cli();
+
+ i = 0;
+ do {
+ gameport_trigger(gameport);
+ t = gameport_time(gameport, GF2K_TIMEOUT * 1000);
+ while ((gameport_read(gameport) & 1) && t) t--;
+ udelay(seq[i]);
+ } while (seq[++i]);
+
+ gameport_trigger(gameport);
+
+ __restore_flags(flags);
+}
+
+/*
+ * js_sw_get_bits() composes bits from the triplet buffer into a __u64.
+ * Parameter 'pos' is bit number inside packet where to start at, 'num' is number
+ * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
+ * is number of bits per triplet.
+ */
+
+#define GB(p,n,s) gf2k_get_bits(data, p, n, s)
+
+static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift)
+{
+ __u64 data = 0;
+ int i;
+
+ for (i = 0; i < num / 3 + 2; i++)
+ data |= buf[pos / 3 + i] << (i * 3);
+ data >>= pos % 3;
+ data &= (1 << num) - 1;
+ data <<= shift;
+
+ return data;
+}
+
+static void gf2k_read(struct gf2k *gf2k, unsigned char *data)
+{
+ struct input_dev *dev = &gf2k->dev;
+ int i, t;
+
+ for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++)
+ input_report_abs(dev, gf2k_abs[i], GB(i<<3,8,0) | GB(i+46,1,8) | GB(i+50,1,9));
+
+ for (i = 0; i < 2 && i < gf2k_axes[gf2k->id] - 4; i++)
+ input_report_abs(dev, gf2k_abs[i], GB(i*9+60,8,0) | GB(i+54,1,9));
+
+ t = GB(40,4,0);
+
+ for (i = 0; i < gf2k_hats[gf2k->id]; i++)
+ input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]);
+
+ t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10);
+
+ for (i = 0; i < gf2k_joys[gf2k->id]; i++)
+ input_report_key(dev, gf2k_btn_joy[i], (t >> i) & 1);
+
+ for (i = 0; i < gf2k_pads[gf2k->id]; i++)
+ input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1);
+}
+
+/*
+ * gf2k_timer() reads and analyzes Genius joystick data.
+ */
+
+static void gf2k_timer(unsigned long private)
+{
+ struct gf2k *gf2k = (void *) private;
+ unsigned char data[GF2K_LENGTH];
+
+ gf2k->reads++;
+
+ if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) {
+ gf2k->bads++;
+ } else gf2k_read(gf2k, data);
+
+ mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
+}
+
+static int gf2k_open(struct input_dev *dev)
+{
+ struct gf2k *gf2k = dev->private;
+ if (!gf2k->used++)
+ mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
+ return 0;
+}
+
+static void gf2k_close(struct input_dev *dev)
+{
+ struct gf2k *gf2k = dev->private;
+ if (!--gf2k->used)
+ del_timer(&gf2k->timer);
+}
+
+/*
+ * gf2k_connect() probes for Genius id joysticks.
+ */
+
+static void gf2k_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct gf2k *gf2k;
+ unsigned char data[GF2K_LENGTH];
+ int i;
+
+ if (!(gf2k = kmalloc(sizeof(struct gf2k), GFP_KERNEL)))
+ return;
+ memset(gf2k, 0, sizeof(struct gf2k));
+
+ gameport->private = gf2k;
+
+ gf2k->gameport = gameport;
+ init_timer(&gf2k->timer);
+ gf2k->timer.data = (long) gf2k;
+ gf2k->timer.function = gf2k_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ goto fail1;
+
+ gf2k_trigger_seq(gameport, gf2k_seq_reset);
+
+ wait_ms(GF2K_TIMEOUT);
+
+ gf2k_trigger_seq(gameport, gf2k_seq_digital);
+
+ wait_ms(GF2K_TIMEOUT);
+
+ if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12)
+ goto fail2;
+
+ if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5)))
+ goto fail2;
+
+#ifdef RESET_WORKS
+ if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) ||
+ (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5))))
+ goto fail2;
+#else
+ gf2k->id = 6;
+#endif
+
+ if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) {
+ printk(KERN_WARNING "gf2k.c: Not yet supported joystick on gameport%d. [id: %d type:%s]\n",
+ gameport->number, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]);
+ goto fail2;
+ }
+
+ gf2k->length = gf2k_lens[gf2k->id];
+
+ gf2k->dev.private = gf2k;
+ gf2k->dev.open = gf2k_open;
+ gf2k->dev.close = gf2k_close;
+ gf2k->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ gf2k->dev.name = gf2k_names[gf2k->id];
+ gf2k->dev.idbus = BUS_GAMEPORT;
+ gf2k->dev.idvendor = GAMEPORT_ID_VENDOR_GENIUS;
+ gf2k->dev.idproduct = gf2k->id;
+ gf2k->dev.idversion = 0x0100;
+
+ for (i = 0; i < gf2k_axes[gf2k->id]; i++)
+ set_bit(gf2k_abs[i], gf2k->dev.absbit);
+
+ for (i = 0; i < gf2k_hats[gf2k->id]; i++) {
+ set_bit(ABS_HAT0X + i, gf2k->dev.absbit);
+ gf2k->dev.absmin[ABS_HAT0X + i] = -1;
+ gf2k->dev.absmax[ABS_HAT0X + i] = 1;
+ }
+
+ for (i = 0; i < gf2k_joys[gf2k->id]; i++)
+ set_bit(gf2k_btn_joy[i], gf2k->dev.keybit);
+
+ for (i = 0; i < gf2k_pads[gf2k->id]; i++)
+ set_bit(gf2k_btn_pad[i], gf2k->dev.keybit);
+
+ gf2k_read_packet(gameport, gf2k->length, data);
+ gf2k_read(gf2k, data);
+
+ for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
+ gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
+ gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
+ gf2k->dev.absmin[gf2k_abs[i]] = 32;
+ gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
+ gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
+ }
+
+ input_register_device(&gf2k->dev);
+ printk(KERN_INFO "input%d: %s on gameport%d.0\n",
+ gf2k->dev.number, gf2k_names[gf2k->id], gameport->number);
+
+ return;
+fail2: gameport_close(gameport);
+fail1: kfree(gf2k);
+}
+
+static void gf2k_disconnect(struct gameport *gameport)
+{
+ struct gf2k *gf2k = gameport->private;
+ input_unregister_device(&gf2k->dev);
+ gameport_close(gameport);
+ kfree(gf2k);
+}
+
+static struct gameport_dev gf2k_dev = {
+ connect: gf2k_connect,
+ disconnect: gf2k_disconnect,
+};
+
+int __init gf2k_init(void)
+{
+ gameport_register_device(&gf2k_dev);
+ return 0;
+}
+
+void __exit gf2k_exit(void)
+{
+ gameport_unregister_device(&gf2k_dev);
+}
+
+module_init(gf2k_init);
+module_exit(gf2k_exit);
diff --git a/drivers/char/joystick/grip.c b/drivers/char/joystick/grip.c
new file mode 100644
index 000000000..4cedd7892
--- /dev/null
+++ b/drivers/char/joystick/grip.c
@@ -0,0 +1,423 @@
+/*
+ * $Id: grip.c,v 1.14 2000/06/06 21:13:36 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Gravis/Kensington GrIP protocol joystick and gamepad driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define GRIP_MODE_GPP 1
+#define GRIP_MODE_BD 2
+#define GRIP_MODE_XT 3
+#define GRIP_MODE_DC 4
+
+#define GRIP_LENGTH_GPP 24
+#define GRIP_STROBE_GPP 200 /* 200 us */
+#define GRIP_LENGTH_XT 4
+#define GRIP_STROBE_XT 64 /* 64 us */
+#define GRIP_MAX_CHUNKS_XT 10
+#define GRIP_MAX_BITS_XT 30
+
+#define GRIP_REFRESH_TIME HZ/50 /* 20 ms */
+
+struct grip {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct input_dev dev[2];
+ unsigned char mode[2];
+ int used;
+ int reads;
+ int bads;
+};
+
+static int grip_btn_gpp[] = { BTN_START, BTN_SELECT, BTN_TR2, BTN_Y, 0, BTN_TL2, BTN_A, BTN_B, BTN_X, 0, BTN_TL, BTN_TR, -1 };
+static int grip_btn_bd[] = { BTN_THUMB, BTN_THUMB2, BTN_TRIGGER, BTN_TOP, BTN_BASE, -1 };
+static int grip_btn_xt[] = { BTN_TRIGGER, BTN_THUMB, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_SELECT, BTN_START, BTN_MODE, -1 };
+static int grip_btn_dc[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, -1 };
+
+static int grip_abs_gpp[] = { ABS_X, ABS_Y, -1 };
+static int grip_abs_bd[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
+static int grip_abs_xt[] = { ABS_X, ABS_Y, ABS_BRAKE, ABS_GAS, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, -1 };
+static int grip_abs_dc[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
+
+static char *grip_name[] = { NULL, "Gravis GamePad Pro", "Gravis Blackhawk Digital",
+ "Gravis Xterminator Digital", "Gravis Xterminator DualControl" };
+static int *grip_abs[] = { 0, grip_abs_gpp, grip_abs_bd, grip_abs_xt, grip_abs_dc };
+static int *grip_btn[] = { 0, grip_btn_gpp, grip_btn_bd, grip_btn_xt, grip_btn_dc };
+static char grip_anx[] = { 0, 0, 3, 5, 5 };
+static char grip_cen[] = { 0, 0, 2, 2, 4 };
+
+/*
+ * grip_gpp_read_packet() reads a Gravis GamePad Pro packet.
+ */
+
+static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned int *data)
+{
+ unsigned long flags;
+ unsigned char u, v;
+ unsigned int t;
+ int i;
+
+ int strobe = gameport_time(gameport, GRIP_STROBE_GPP);
+
+ data[0] = 0;
+ t = strobe;
+ i = 0;
+
+ __save_flags(flags);
+ __cli();
+
+ v = gameport_read(gameport) >> shift;
+
+ do {
+ t--;
+ u = v; v = (gameport_read(gameport) >> shift) & 3;
+ if (~v & u & 1) {
+ data[0] |= (v >> 1) << i++;
+ t = strobe;
+ }
+ } while (i < GRIP_LENGTH_GPP && t > 0);
+
+ __restore_flags(flags);
+
+ if (i < GRIP_LENGTH_GPP) return -1;
+
+ for (i = 0; i < GRIP_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++)
+ data[0] = data[0] >> 1 | (data[0] & 1) << (GRIP_LENGTH_GPP - 1);
+
+ return -(i == GRIP_LENGTH_GPP);
+}
+
+/*
+ * grip_xt_read_packet() reads a Gravis Xterminator packet.
+ */
+
+static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned int *data)
+{
+ unsigned int i, j, buf, crc;
+ unsigned char u, v, w;
+ unsigned long flags;
+ unsigned int t;
+ char status;
+
+ int strobe = gameport_time(gameport, GRIP_STROBE_XT);
+
+ data[0] = data[1] = data[2] = data[3] = 0;
+ status = buf = i = j = 0;
+ t = strobe;
+
+ __save_flags(flags);
+ __cli();
+
+ v = w = (gameport_read(gameport) >> shift) & 3;
+
+ do {
+ t--;
+ u = (gameport_read(gameport) >> shift) & 3;
+
+ if (u ^ v) {
+
+ if ((u ^ v) & 1) {
+ buf = (buf << 1) | (u >> 1);
+ t = strobe;
+ i++;
+ } else
+
+ if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) {
+ if (i == 20) {
+ crc = buf ^ (buf >> 7) ^ (buf >> 14);
+ if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) {
+ data[buf >> 18] = buf >> 4;
+ status |= 1 << (buf >> 18);
+ }
+ j++;
+ }
+ t = strobe;
+ buf = 0;
+ i = 0;
+ }
+ w = v;
+ v = u;
+ }
+
+ } while (status != 0xf && i < GRIP_MAX_BITS_XT && j < GRIP_MAX_CHUNKS_XT && t > 0);
+
+ __restore_flags(flags);
+
+ return -(status != 0xf);
+}
+
+/*
+ * grip_timer() repeatedly polls the joysticks and generates events.
+ */
+
+static void grip_timer(unsigned long private)
+{
+ struct grip *grip = (void*) private;
+ unsigned int data[GRIP_LENGTH_XT];
+ struct input_dev *dev;
+ int i, j;
+
+ for (i = 0; i < 2; i++) {
+
+ dev = grip->dev + i;
+ grip->reads++;
+
+ switch (grip->mode[i]) {
+
+ case GRIP_MODE_GPP:
+
+ if (grip_gpp_read_packet(grip->gameport, (i << 1) + 4, data)) {
+ grip->bads++;
+ break;
+ }
+
+ input_report_abs(dev, ABS_X, ((*data >> 15) & 1) - ((*data >> 16) & 1));
+ input_report_abs(dev, ABS_Y, ((*data >> 13) & 1) - ((*data >> 12) & 1));
+
+ for (j = 0; j < 12; j++)
+ if (grip_btn_gpp[j])
+ input_report_key(dev, grip_btn_gpp[j], (*data >> j) & 1);
+
+ break;
+
+ case GRIP_MODE_BD:
+
+ if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
+ grip->bads++;
+ break;
+ }
+
+ input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
+ input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f));
+ input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
+
+ input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
+ input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
+
+ for (j = 0; j < 5; j++)
+ input_report_key(dev, grip_btn_bd[j], (data[3] >> (j + 4)) & 1);
+
+ break;
+
+ case GRIP_MODE_XT:
+
+ if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
+ grip->bads++;
+ break;
+ }
+
+ input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
+ input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f));
+ input_report_abs(dev, ABS_BRAKE, (data[1] >> 2) & 0x3f);
+ input_report_abs(dev, ABS_GAS, (data[1] >> 8) & 0x3f);
+ input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
+
+ input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
+ input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
+ input_report_abs(dev, ABS_HAT1X, ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1));
+ input_report_abs(dev, ABS_HAT1Y, ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1));
+
+ for (j = 0; j < 11; j++)
+ input_report_key(dev, grip_btn_xt[j], (data[3] >> (j + 3)) & 1);
+ break;
+
+ case GRIP_MODE_DC:
+
+ if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
+ grip->bads++;
+ break;
+ }
+
+ input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
+ input_report_abs(dev, ABS_Y, (data[0] >> 8) & 0x3f);
+ input_report_abs(dev, ABS_RX, (data[1] >> 2) & 0x3f);
+ input_report_abs(dev, ABS_RY, (data[1] >> 8) & 0x3f);
+ input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
+
+ input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
+ input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
+
+ for (j = 0; j < 9; j++)
+ input_report_key(dev, grip_btn_dc[j], (data[3] >> (j + 3)) & 1);
+ break;
+
+
+ }
+ }
+
+ mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
+}
+
+static int grip_open(struct input_dev *dev)
+{
+ struct grip *grip = dev->private;
+ if (!grip->used++)
+ mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
+ return 0;
+}
+
+static void grip_close(struct input_dev *dev)
+{
+ struct grip *grip = dev->private;
+ if (!--grip->used)
+ del_timer(&grip->timer);
+}
+
+static void grip_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct grip *grip;
+ unsigned int data[GRIP_LENGTH_XT];
+ int i, j, t;
+
+ if (!(grip = kmalloc(sizeof(struct grip), GFP_KERNEL)))
+ return;
+ memset(grip, 0, sizeof(struct grip));
+
+ gameport->private = grip;
+
+ grip->gameport = gameport;
+ init_timer(&grip->timer);
+ grip->timer.data = (long) grip;
+ grip->timer.function = grip_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ goto fail1;
+
+ for (i = 0; i < 2; i++) {
+ if (!grip_gpp_read_packet(gameport, (i << 1) + 4, data)) {
+ grip->mode[i] = GRIP_MODE_GPP;
+ continue;
+ }
+ if (!grip_xt_read_packet(gameport, (i << 1) + 4, data)) {
+ if (!(data[3] & 7)) {
+ grip->mode[i] = GRIP_MODE_BD;
+ continue;
+ }
+ if (!(data[2] & 0xf0)) {
+ grip->mode[i] = GRIP_MODE_XT;
+ continue;
+ }
+ grip->mode[i] = GRIP_MODE_DC;
+ continue;
+ }
+ }
+
+ if (!grip->mode[0] && !grip->mode[1])
+ goto fail2;
+
+ for (i = 0; i < 2; i++)
+ if (grip->mode[i]) {
+
+ grip->dev[i].private = grip;
+
+ grip->dev[i].open = grip_open;
+ grip->dev[i].close = grip_close;
+
+ grip->dev[i].name = grip_name[grip->mode[i]];
+ grip->dev[i].idbus = BUS_GAMEPORT;
+ grip->dev[i].idvendor = GAMEPORT_ID_VENDOR_GRAVIS;
+ grip->dev[i].idproduct = grip->mode[i];
+ grip->dev[i].idversion = 0x0100;
+
+ grip->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) {
+
+ set_bit(t, grip->dev[i].absbit);
+
+ if (j < grip_cen[grip->mode[i]]) {
+ grip->dev[i].absmin[t] = 14;
+ grip->dev[i].absmax[t] = 52;
+ grip->dev[i].absfuzz[t] = 1;
+ grip->dev[i].absflat[t] = 2;
+ continue;
+ }
+
+ if (j < grip_anx[grip->mode[i]]) {
+ grip->dev[i].absmin[t] = 3;
+ grip->dev[i].absmax[t] = 57;
+ grip->dev[i].absfuzz[t] = 1;
+ continue;
+ }
+
+ grip->dev[i].absmin[t] = -1;
+ grip->dev[i].absmax[t] = 1;
+ }
+
+ for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++)
+ if (t > 0)
+ set_bit(t, grip->dev[i].keybit);
+
+ input_register_device(grip->dev + i);
+
+ printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
+ grip->dev[i].number, grip_name[grip->mode[i]], gameport->number, i);
+ }
+
+ return;
+fail2: gameport_close(gameport);
+fail1: kfree(grip);
+}
+
+static void grip_disconnect(struct gameport *gameport)
+{
+ int i;
+
+ struct grip *grip = gameport->private;
+ for (i = 0; i < 2; i++)
+ if (grip->mode[i])
+ input_unregister_device(grip->dev + i);
+ gameport_close(gameport);
+ kfree(grip);
+}
+
+static struct gameport_dev grip_dev = {
+ connect: grip_connect,
+ disconnect: grip_disconnect,
+};
+
+int __init grip_init(void)
+{
+ gameport_register_device(&grip_dev);
+ return 0;
+}
+
+void __exit grip_exit(void)
+{
+ gameport_unregister_device(&grip_dev);
+}
+
+module_init(grip_init);
+module_exit(grip_exit);
diff --git a/drivers/char/joystick/interact.c b/drivers/char/joystick/interact.c
new file mode 100644
index 000000000..7104e5d49
--- /dev/null
+++ b/drivers/char/joystick/interact.c
@@ -0,0 +1,306 @@
+/*
+ * $Id: interact.c,v 1.8 2000/05/29 11:19:51 vojtech Exp $
+ *
+ * Copyright (c) 2000 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Toby Deshane
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * InterAct digital gamepad/joystick driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define INTERACT_MAX_START 400 /* 400 us */
+#define INTERACT_MAX_STROBE 40 /* 40 us */
+#define INTERACT_MAX_LENGTH 32 /* 32 bits */
+#define INTERACT_REFRESH_TIME HZ/50 /* 20 ms */
+
+#define INTERACT_TYPE_HHFX 0 /* HammerHead/FX */
+#define INTERACT_TYPE_PP8D 1 /* ProPad 8 */
+
+struct interact {
+ struct gameport *gameport;
+ struct input_dev dev;
+ struct timer_list timer;
+ int used;
+ int bads;
+ int reads;
+ unsigned char type;
+ unsigned char length;
+};
+
+static short interact_abs_hhfx[] =
+ { ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 };
+static short interact_abs_pp8d[] =
+ { ABS_X, ABS_Y, -1 };
+
+static short interact_btn_hhfx[] =
+ { BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL, BTN_TL2, BTN_TR2, BTN_MODE, BTN_SELECT, -1 };
+static short interact_btn_pp8d[] =
+ { BTN_C, BTN_TL, BTN_TR, BTN_A, BTN_B, BTN_Y, BTN_Z, BTN_X, -1 };
+
+struct interact_type {
+ int id;
+ short *abs;
+ short *btn;
+ char *name;
+ unsigned char length;
+ unsigned char b8;
+};
+
+static struct interact_type interact_type[] = {
+ { 0x6202, interact_abs_hhfx, interact_btn_hhfx, "InterAct HammerHead/FX", 32, 4 },
+ { 0x53f8, interact_abs_pp8d, interact_btn_pp8d, "InterAct ProPad 8 Digital", 16, 0 },
+ { 0 }};
+
+/*
+ * interact_read_packet() reads and InterAct joystick data.
+ */
+
+static int interact_read_packet(struct gameport *gameport, int length, u32 *data)
+{
+ unsigned long flags;
+ unsigned char u, v;
+ unsigned int t, s;
+ int i;
+
+ i = 0;
+ data[0] = data[1] = data[2] = 0;
+ t = gameport_time(gameport, INTERACT_MAX_START);
+ s = gameport_time(gameport, INTERACT_MAX_STROBE);
+
+ __save_flags(flags);
+ __cli();
+ gameport_trigger(gameport);
+ v = gameport_read(gameport);
+
+ while (t > 0 && i < length) {
+ t--;
+ u = v; v = gameport_read(gameport);
+ if (v & ~u & 0x40) {
+ data[0] = (data[0] << 1) | ((v >> 4) & 1);
+ data[1] = (data[1] << 1) | ((v >> 5) & 1);
+ data[2] = (data[2] << 1) | ((v >> 7) & 1);
+ i++;
+ t = s;
+ }
+ }
+
+ __restore_flags(flags);
+
+ return i;
+}
+
+/*
+ * interact_timer() reads and analyzes InterAct joystick data.
+ */
+
+static void interact_timer(unsigned long private)
+{
+ struct interact *interact = (struct interact *) private;
+ struct input_dev *dev = &interact->dev;
+ u32 data[3];
+ int i;
+
+ interact->reads++;
+
+ if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) {
+ interact->bads++;
+ } else
+
+ for (i = 0; i < 3; i++)
+ data[i] <<= INTERACT_MAX_LENGTH - interact->length;
+
+ switch (interact->type) {
+
+ case INTERACT_TYPE_HHFX:
+
+ for (i = 0; i < 4; i++)
+ input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff);
+
+ for (i = 0; i < 2; i++)
+ input_report_abs(dev, ABS_HAT0Y - i,
+ ((data[1] >> ((i << 1) + 17)) & 1) - ((data[1] >> ((i << 1) + 16)) & 1));
+
+ for (i = 0; i < 8; i++)
+ input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1);
+
+ for (i = 0; i < 4; i++)
+ input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1);
+
+ break;
+
+ case INTERACT_TYPE_PP8D:
+
+ for (i = 0; i < 2; i++)
+ input_report_abs(dev, interact_abs_pp8d[i],
+ ((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1));
+
+ for (i = 0; i < 8; i++)
+ input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1);
+
+ break;
+ }
+
+ mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
+
+}
+
+/*
+ * interact_open() is a callback from the input open routine.
+ */
+
+static int interact_open(struct input_dev *dev)
+{
+ struct interact *interact = dev->private;
+ if (!interact->used++)
+ mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
+ return 0;
+}
+
+/*
+ * interact_close() is a callback from the input close routine.
+ */
+
+static void interact_close(struct input_dev *dev)
+{
+ struct interact *interact = dev->private;
+ if (!--interact->used)
+ del_timer(&interact->timer);
+}
+
+/*
+ * interact_connect() probes for InterAct joysticks.
+ */
+
+static void interact_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct interact *interact;
+ __u32 data[3];
+ int i, t;
+
+ if (!(interact = kmalloc(sizeof(struct interact), GFP_KERNEL)))
+ return;
+ memset(interact, 0, sizeof(struct interact));
+
+ gameport->private = interact;
+
+ interact->gameport = gameport;
+ init_timer(&interact->timer);
+ interact->timer.data = (long) interact;
+ interact->timer.function = interact_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ goto fail1;
+
+ i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data);
+
+ if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) {
+ goto fail2;
+ }
+
+ for (i = 0; interact_type[i].length; i++)
+ if (interact_type[i].id == (data[2] >> 16))
+ break;
+
+ if (!interact_type[i].length) {
+ printk(KERN_WARNING "interact.c: Unknown joystick on gameport%d. [len %d d0 %08x d1 %08x i2 %08x]\n",
+ gameport->number, i, data[0], data[1], data[2]);
+ goto fail2;
+ }
+
+ interact->type = i;
+ interact->length = interact_type[i].length;
+
+ interact->dev.private = interact;
+ interact->dev.open = interact_open;
+ interact->dev.close = interact_close;
+
+ interact->dev.name = interact_type[i].name;
+ interact->dev.idbus = BUS_GAMEPORT;
+ interact->dev.idvendor = GAMEPORT_ID_VENDOR_INTERACT;
+ interact->dev.idproduct = interact_type[i].id;
+ interact->dev.idversion = 0x0100;
+
+ interact->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) {
+ set_bit(t, interact->dev.absbit);
+ if (i < interact_type[interact->type].b8) {
+ interact->dev.absmin[t] = 0;
+ interact->dev.absmax[t] = 255;
+ } else {
+ interact->dev.absmin[t] = -1;
+ interact->dev.absmax[t] = 1;
+ }
+ }
+
+ for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++)
+ set_bit(t, interact->dev.keybit);
+
+ input_register_device(&interact->dev);
+ printk(KERN_INFO "input%d: %s on gameport%d.0\n",
+ interact->dev.number, interact_type[interact->type].name, gameport->number);
+
+ return;
+fail2: gameport_close(gameport);
+fail1: kfree(interact);
+}
+
+static void interact_disconnect(struct gameport *gameport)
+{
+ struct interact *interact = gameport->private;
+ input_unregister_device(&interact->dev);
+ gameport_close(gameport);
+ kfree(interact);
+}
+
+static struct gameport_dev interact_dev = {
+ connect: interact_connect,
+ disconnect: interact_disconnect,
+};
+
+int __init interact_init(void)
+{
+ gameport_register_device(&interact_dev);
+ return 0;
+}
+
+void __exit interact_exit(void)
+{
+ gameport_unregister_device(&interact_dev);
+}
+
+module_init(interact_init);
+module_exit(interact_exit);
diff --git a/drivers/char/joystick/joy-amiga.c b/drivers/char/joystick/joy-amiga.c
deleted file mode 100644
index 8c0ba6923..000000000
--- a/drivers/char/joystick/joy-amiga.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * joy-amiga.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * microswitch based joystick connected to Amiga joystick port.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/system.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/amigahw.h>
-#include <linux/init.h>
-
-static struct js_port* js_am_port __initdata = NULL;
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_am, "1-2i");
-
-static int __initdata js_am[] = { 0, 0 };
-
-/*
- * js_am_read() reads and Amiga joystick data.
- */
-
-static int js_am_read(void *info, int **axes, int **buttons)
-{
- int data = 0;
-
- switch (*(int*)info) {
- case 0:
- data = ~custom.joy0dat;
- buttons[0][0] = (~ciaa.pra >> 6) & 1;
- break;
-
- case 1:
- data = ~custom.joy1dat;
- buttons[0][0] = (~ciaa.pra >> 7) & 1;
- break;
-
- default:
- return -1;
- }
-
- axes[0][0] = ((data >> 1) & 1) - ((data >> 9) & 1);
- data = ~(data ^ (data << 1));
- axes[0][1] = ((data >> 1) & 1) - ((data >> 9) & 1);
-
- return 0;
-}
-
-/*
- * js_am_init_corr() initializes correction values of
- * Amiga joysticks.
- */
-
-static void __init js_am_init_corr(struct js_corr **corr)
-{
- int i;
-
- for (i = 0; i < 2; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = 0;
- corr[0][i].coef[0] = 0;
- corr[0][i].coef[1] = 0;
- corr[0][i].coef[2] = (1 << 29);
- corr[0][i].coef[3] = (1 << 29);
- }
-}
-
-#ifndef MODULE
-int __init js_am_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_am[i] = ints[i+1];
- return 1;
-}
-__setup("js_am=", js_am_setup);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_am_init(void)
-#endif
-{
- int i;
-
- for (i = 0; i < 2; i++)
- if (js_am[i]) {
- js_am_port = js_register_port(js_am_port, &i, 1, sizeof(int), js_am_read);
- printk(KERN_INFO "js%d: Amiga joystick at joy%ddat\n",
- js_register_device(js_am_port, 0, 2, 1, "Amiga joystick", THIS_MODULE, NULL, NULL), i);
- js_am_init_corr(js_am_port->corr);
- }
- if (js_am_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-amiga: no joysticks specified\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- while (js_am_port) {
- if (js_am_port->devs[0])
- js_unregister_device(js_am_port->devs[0]);
- js_am_port = js_unregister_port(js_am_port);
- }
-}
-#endif
diff --git a/drivers/char/joystick/joy-analog.c b/drivers/char/joystick/joy-analog.c
deleted file mode 100644
index f73ee8ded..000000000
--- a/drivers/char/joystick/joy-analog.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * joy-analog.c Version 1.2
- *
- * Copyright (c) 1996-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * up to two analog (or CHF/FCS) joysticks on a single joystick port.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/param.h>
-#include <asm/system.h>
-#include <linux/config.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#define JS_AN_MAX_TIME 3000 /* 3 ms */
-#define JS_AN_LOOP_TIME 2000 /* 2 t */
-
-static int js_an_port_list[] __initdata = {0x201, 0};
-static struct js_port* js_an_port __initdata = NULL;
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_an, "2-24i");
-
-static int __initdata js_an[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 };
-
-#include "joy-analog.h"
-
-struct js_ax_info {
- int io;
- int speed;
- int loop;
- int timeout;
- struct js_an_info an;
-};
-
-/*
- * Time macros.
- */
-
-#ifdef __i386__
-#ifdef CONFIG_X86_TSC
-#define GET_TIME(x) __asm__ __volatile__ ( "rdtsc" : "=a" (x) : : "dx" )
-#define DELTA(x,y) ((x)-(y))
-#define TIME_NAME "TSC"
-#else
-#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))
-#define TIME_NAME "PIT"
-#endif
-#elif __alpha__
-#define GET_TIME(x) __asm__ __volatile__ ( "rpcc %0" : "=r" (x) )
-#define DELTA(x,y) ((x)-(y))
-#define TIME_NAME "PCC"
-#endif
-
-#ifndef GET_TIME
-#define FAKE_TIME
-static unsigned long js_an_faketime = 0;
-#define GET_TIME(x) do { x = js_an_faketime++; } while(0)
-#define DELTA(x,y) ((x)-(y))
-#define TIME_NAME "Unreliable"
-#endif
-
-/*
- * js_an_read() reads analog joystick data.
- */
-
-static int js_an_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_ax_info *info = xinfo;
- struct js_an_info *an = &info->an;
- int io = info->io;
- unsigned long flags;
- unsigned char buf[4];
- unsigned int time[4];
- unsigned char u, v, w;
- unsigned int p, q, r, s, t;
- int i, j;
-
- an->buttons = ~inb(io) >> 4;
-
- i = 0;
- w = ((an->mask[0] | an->mask[1]) & JS_AN_AXES_STD) | (an->extensions & JS_AN_HAT_FCS)
- | ((an->extensions & JS_AN_BUTTONS_PXY_XY) >> 2) | ((an->extensions & JS_AN_BUTTONS_PXY_UV) >> 4);
- p = info->loop;
- q = info->timeout;
-
- __save_flags(flags);
- __cli();
- outb(0xff,io);
- GET_TIME(r);
- __restore_flags(flags);
- t = r;
- v = w;
- do {
- s = t;
- u = v;
- __cli();
- v = inb(io) & w;
- GET_TIME(t);
- __restore_flags(flags);
- if ((u ^ v) && (DELTA(t,s) < p)) {
- time[i] = t;
- buf[i] = u ^ v;
- i++;
- }
- } while (v && (i < 4) && (DELTA(t,r) < q));
-
- v <<= 4;
-
- for (--i; i >= 0; i--) {
- v |= buf[i];
- for (j = 0; j < 4; j++)
- if (buf[i] & (1 << j)) an->axes[j] = (DELTA(time[i],r) << 10) / info->speed;
- }
-
- js_an_decode(an, axes, buttons);
-
- return -(v != w);
-}
-
-/*
- * js_an_calibrate_timer() calibrates the timer and computes loop
- * and timeout values for a joystick port.
- */
-
-static void __init js_an_calibrate_timer(struct js_ax_info *info)
-{
- unsigned int i, t, tx, t1, t2, t3;
- unsigned long flags;
- int io = info->io;
-
- save_flags(flags);
- cli();
- GET_TIME(t1);
-#ifdef FAKE_TIME
- js_an_faketime += 830;
-#endif
- udelay(1000);
- GET_TIME(t2);
- GET_TIME(t3);
- restore_flags(flags);
-
- info->speed = DELTA(t2, t1) - DELTA(t3, t2);
-
- tx = 1 << 30;
-
- for(i = 0; i < 50; i++) {
- save_flags(flags);
- cli();
- GET_TIME(t1);
- for(t = 0; t < 50; t++) { inb(io); GET_TIME(t2); }
- GET_TIME(t3);
- restore_flags(flags);
- udelay(i);
- if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
- }
-
- info->loop = (JS_AN_LOOP_TIME * t) / 50000;
- info->timeout = (JS_AN_MAX_TIME * info->speed) / 1000;
-}
-
-/*
- * js_an_probe() probes for analog joysticks.
- */
-
-static struct js_port __init *js_an_probe(int io, int mask0, int mask1, struct js_port *port)
-{
- struct js_ax_info info, *ax;
- int i, numdev;
- unsigned char u;
-
- if (io < 0) return port;
-
- if (check_region(io, 1)) return port;
-
- outb(0xff,io);
- u = inb(io);
- udelay(JS_AN_MAX_TIME);
- u = (inb(io) ^ u) & u;
-
- if (!u) return port;
- if (u & 0xf0) return port;
-
- if ((numdev = js_an_probe_devs(&info.an, u, mask0, mask1, port)) <= 0)
- return port;
-
- info.io = io;
- js_an_calibrate_timer(&info);
-
- request_region(info.io, 1, "joystick (analog)");
- port = js_register_port(port, &info, numdev, sizeof(struct js_ax_info), js_an_read);
- ax = port->info;
-
- for (i = 0; i < numdev; i++)
- printk(KERN_INFO "js%d: %s at %#x ["TIME_NAME" timer, %d %sHz clock, %d ns res]\n",
- js_register_device(port, i, js_an_axes(i, &ax->an), js_an_buttons(i, &ax->an),
- js_an_name(i, &ax->an), THIS_MODULE, NULL, NULL),
- js_an_name(i, &ax->an),
- ax->io,
- ax->speed > 10000 ? (ax->speed + 800) / 1000 : ax->speed,
- ax->speed > 10000 ? "M" : "k",
- ax->loop * 1000000000 / JS_AN_LOOP_TIME / ax->speed);
-
- js_an_read(ax, port->axes, port->buttons);
- js_an_init_corr(&ax->an, port->axes, port->corr, 8);
-
- return port;
-}
-
-#ifndef MODULE
-int __init js_an_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(24);
- for (i = 0; i <= ints[0] && i < 24; i++) js_an[i] = ints[i+1];
- return 1;
-}
-__setup("js_an=", js_an_setup);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_an_init(void)
-#endif
-{
- int i;
-
- if (js_an[0] >= 0) {
- for (i = 0; (js_an[i*3] >= 0) && i < 8; i++)
- js_an_port = js_an_probe(js_an[i*3], js_an[i*3+1], js_an[i*3+2], js_an_port);
- } else {
- for (i = 0; js_an_port_list[i]; i++)
- js_an_port = js_an_probe(js_an_port_list[i], 0, 0, js_an_port);
- }
- if (js_an_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-analog: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_ax_info *info;
-
- while (js_an_port) {
- for (i = 0; i < js_an_port->ndevs; i++)
- if (js_an_port->devs[i])
- js_unregister_device(js_an_port->devs[i]);
- info = js_an_port->info;
- release_region(info->io, 1);
- js_an_port = js_unregister_port(js_an_port);
- }
-
-}
-#endif
diff --git a/drivers/char/joystick/joy-analog.h b/drivers/char/joystick/joy-analog.h
deleted file mode 100644
index a1644350c..000000000
--- a/drivers/char/joystick/joy-analog.h
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * joy-analog.h Version 1.2
- *
- * Copyright (c) 1996-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This file is designed to be included in any joystick driver
- * that communicates with standard analog joysticks. This currently
- * is: joy-analog.c, joy-assassin.c, and joy-lightning.c
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/bitops.h>
-
-#define JS_AN_AXES_STD 0x0f
-#define JS_AN_BUTTONS_STD 0xf0
-
-#define JS_AN_BUTTONS_CHF 0x01
-#define JS_AN_HAT1_CHF 0x02
-#define JS_AN_HAT2_CHF 0x04
-#define JS_AN_ANY_CHF 0x07
-#define JS_AN_HAT_FCS 0x08
-#define JS_AN_HATS_ALL 0x0e
-#define JS_AN_BUTTON_PXY_X 0x10
-#define JS_AN_BUTTON_PXY_Y 0x20
-#define JS_AN_BUTTON_PXY_U 0x40
-#define JS_AN_BUTTON_PXY_V 0x80
-#define JS_AN_BUTTONS_PXY_XY 0x30
-#define JS_AN_BUTTONS_PXY_UV 0xc0
-#define JS_AN_BUTTONS_PXY 0xf0
-
-static struct {
- int x;
- int y;
-} js_an_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1, 0}, { 0, 1}, {-1, 0}};
-
-struct js_an_info {
- unsigned char mask[2];
- unsigned int extensions;
- int axes[4];
- int initial[4];
- unsigned char buttons;
-};
-
-/*
- * js_an_decode() decodes analog joystick data.
- */
-
-static void js_an_decode(struct js_an_info *info, int **axes, int **buttons)
-{
- int i, j, k;
- int hat1, hat2, hat3;
-
- hat1 = hat2 = hat3 = 0;
- if (info->mask[0] & JS_AN_BUTTONS_STD) buttons[0][0] = 0;
- if (info->mask[1] & JS_AN_BUTTONS_STD) buttons[1][0] = 0;
-
- if (info->extensions & JS_AN_ANY_CHF) {
- switch (info->buttons & 0xf) {
- case 0x1: buttons[0][0] = 0x01; break;
- case 0x2: buttons[0][0] = 0x02; break;
- case 0x4: buttons[0][0] = 0x04; break;
- case 0x8: buttons[0][0] = 0x08; break;
- case 0x5: buttons[0][0] = 0x10; break;
- case 0x9: buttons[0][0] = 0x20; break;
- case 0xf: hat1 = 1; break;
- case 0xb: hat1 = 2; break;
- case 0x7: hat1 = 3; break;
- case 0x3: hat1 = 4; break;
- case 0xe: hat2 = 1; break;
- case 0xa: hat2 = 2; break;
- case 0x6: hat2 = 3; break;
- case 0xc: hat2 = 4; break;
- }
- k = info->extensions & JS_AN_BUTTONS_CHF ? 6 : 4;
- } else {
- for (i = 1; i >= 0; i--)
- for (j = k = 0; j < 4; j++)
- if (info->mask[i] & (0x10 << j))
- buttons[i][0] |= ((info->buttons >> j) & 1) << k++;
- }
-
- if (info->extensions & JS_AN_BUTTON_PXY_X)
- buttons[0][0] |= (info->axes[2] < (info->initial[2] >> 1)) << k++;
- if (info->extensions & JS_AN_BUTTON_PXY_Y)
- buttons[0][0] |= (info->axes[3] < (info->initial[3] >> 1)) << k++;
- if (info->extensions & JS_AN_BUTTON_PXY_U)
- buttons[0][0] |= (info->axes[2] > (info->initial[2] + (info->initial[2] >> 1))) << k++;
- if (info->extensions & JS_AN_BUTTON_PXY_V)
- buttons[0][0] |= (info->axes[3] > (info->initial[3] + (info->initial[3] >> 1))) << k++;
-
- if (info->extensions & JS_AN_HAT_FCS)
- for (j = 0; j < 4; j++)
- if (info->axes[3] < ((info->initial[3] * ((j << 1) + 1)) >> 3)) {
- hat3 = j + 1;
- break;
- }
-
- for (i = 1; i >= 0; i--)
- for (j = k = 0; j < 4; j++)
- if (info->mask[i] & (1 << j))
- axes[i][k++] = info->axes[j];
-
- if (info->extensions & JS_AN_HAT1_CHF) {
- axes[0][k++] = js_an_hat_to_axis[hat1].x;
- axes[0][k++] = js_an_hat_to_axis[hat1].y;
- }
- if (info->extensions & JS_AN_HAT2_CHF) {
- axes[0][k++] = js_an_hat_to_axis[hat2].x;
- axes[0][k++] = js_an_hat_to_axis[hat2].y;
- }
- if (info->extensions & JS_AN_HAT_FCS) {
- axes[0][k++] = js_an_hat_to_axis[hat3].x;
- axes[0][k++] = js_an_hat_to_axis[hat3].y;
- }
-}
-
-
-/*
- * js_an_init_corr() initializes the correction values for
- * analog joysticks.
- */
-
-static void __init js_an_init_corr(struct js_an_info *info, int **axes, struct js_corr **corr, int prec)
-{
- int i, j, t;
-
- for (i = 0; i < 2; i++)
- for (j = 0; j < hweight8(info->mask[i] & 0xf); j++) {
-
- if ((j == 2 && (info->mask[i] & 0xb) == 0xb) ||
- (j == 3 && (info->mask[i] & 0xf) == 0xf)) {
- t = (axes[i][0] + axes[i][1]) >> 1;
- } else {
- t = axes[i][j];
- }
-
- corr[i][j].type = JS_CORR_BROKEN;
- corr[i][j].prec = prec;
- corr[i][j].coef[0] = t - (t >> 3);
- corr[i][j].coef[1] = t + (t >> 3);
- corr[i][j].coef[2] = (1 << 29) / (t - (t >> 2) + 1);
- corr[i][j].coef[3] = (1 << 29) / (t - (t >> 2) + 1);
- }
-
- i = hweight8(info->mask[0] & 0xf);
-
- for (j = i; j < i + (hweight8(info->extensions & JS_AN_HATS_ALL) << 1); j++) {
- corr[0][j].type = JS_CORR_BROKEN;
- corr[0][j].prec = 0;
- corr[0][j].coef[0] = 0;
- corr[0][j].coef[1] = 0;
- corr[0][j].coef[2] = (1 << 29);
- corr[0][j].coef[3] = (1 << 29);
- }
-
- for (i = 0; i < 4; i++)
- info->initial[i] = info->axes[i];
-}
-
-
-/*
- * js_an_probe_devs() probes for analog joysticks.
- */
-
-static int __init js_an_probe_devs(struct js_an_info *info, int exist, int mask0, int mask1, struct js_port *port)
-{
- info->mask[0] = info->mask[1] = info->extensions = 0;
-
- if (mask0 || mask1) {
- info->mask[0] = mask0 & (exist | 0xf0);
- info->mask[1] = mask1 & (exist | 0xf0) & ~info->mask[0];
- info->extensions = (mask0 >> 8) & ((exist & JS_AN_HAT_FCS) | ((exist << 2) & JS_AN_BUTTONS_PXY_XY) |
- ((exist << 4) & JS_AN_BUTTONS_PXY_UV) | JS_AN_ANY_CHF);
-
- if (info->extensions & JS_AN_BUTTONS_PXY) {
- info->mask[0] &= ~((info->extensions & JS_AN_BUTTONS_PXY_XY) >> 2);
- info->mask[0] &= ~((info->extensions & JS_AN_BUTTONS_PXY_UV) >> 4);
- info->mask[1] = 0;
- }
- if (info->extensions & JS_AN_HAT_FCS) {
- info->mask[0] &= ~JS_AN_HAT_FCS;
- info->mask[1] = 0;
- info->extensions &= ~(JS_AN_BUTTON_PXY_Y | JS_AN_BUTTON_PXY_V);
- }
- if (info->extensions & JS_AN_ANY_CHF) {
- info->mask[0] |= 0xf0;
- info->mask[1] = 0;
- }
- if (!(info->mask[0] | info->mask[1])) return -1;
- } else {
- switch (exist) {
- case 0x0:
- return -1;
- case 0x3:
- info->mask[0] = 0xf3; /* joystick 0, assuming 4-button */
- break;
- case 0xb:
- info->mask[0] = 0xfb; /* 3-axis, 4-button joystick */
- break;
- case 0xc:
- info->mask[0] = 0xcc; /* joystick 1 */
- break;
- case 0xf:
- info->mask[0] = 0xff; /* 4-axis 4-button joystick */
- break;
- default:
- printk(KERN_WARNING "joy-analog: Unknown joystick device detected "
- "(data=%#x), contact <vojtech@suse.cz>\n", exist);
- return -1;
- }
- }
-
- return !!info->mask[0] + !!info->mask[1];
-}
-
-/*
- * js_an_axes() returns the number of axes for an analog joystick.
- */
-
-static inline int js_an_axes(int i, struct js_an_info *info)
-{
- return hweight8(info->mask[i] & 0x0f) + hweight8(info->extensions & JS_AN_HATS_ALL) * 2;
-}
-
-/*
- * js_an_buttons() returns the number of buttons for an analog joystick.
- */
-
-static inline int js_an_buttons(int i, struct js_an_info *info)
-{
- return hweight8(info->mask[i] & 0xf0) +
- (info->extensions & JS_AN_BUTTONS_CHF) * 2 +
- hweight8(info->extensions & JS_AN_BUTTONS_PXY);
-}
-
-/*
- * js_an_name() constructs a name for an analog joystick.
- */
-
-static char js_an_name_buf[128] __initdata = "";
-
-static char __init *js_an_name(int i, struct js_an_info *info)
-{
-
- sprintf(js_an_name_buf, "Analog %d-axis %d-button",
- hweight8(info->mask[i] & 0x0f),
- js_an_buttons(i, info));
-
- if (info->extensions & JS_AN_HATS_ALL)
- sprintf(js_an_name_buf, "%s %d-hat",
- js_an_name_buf,
- hweight8(info->extensions & JS_AN_HATS_ALL));
-
- strcat(js_an_name_buf, " joystick");
-
- if (info->extensions)
- sprintf(js_an_name_buf, "%s with%s%s%s extensions",
- js_an_name_buf,
- info->extensions & JS_AN_ANY_CHF ? " CHF" : "",
- info->extensions & JS_AN_HAT_FCS ? " FCS" : "",
- info->extensions & JS_AN_BUTTONS_PXY ? " XY/UV" : "");
-
- return js_an_name_buf;
-}
diff --git a/drivers/char/joystick/joy-assassin.c b/drivers/char/joystick/joy-assassin.c
deleted file mode 100644
index 469c6c8ce..000000000
--- a/drivers/char/joystick/joy-assassin.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * joy-assassin.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * joysticks using FP-Gaming's Assassin 3D protocol.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#define JS_AS_MAX_START 1000
-#define JS_AS_DELAY_READ 3000
-#define JS_AS_MAX_LENGTH 40
-
-#define JS_AS_MODE_A3D 1 /* Assassin 3D */
-#define JS_AS_MODE_PAN 2 /* Panther */
-#define JS_AS_MODE_OEM 3 /* Panther OEM version */
-#define JS_AS_MODE_PXL 4 /* Panther XL */
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_as, "2-24i");
-
-static int __initdata js_as[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 };
-
-static int js_as_port_list[] __initdata = {0x201, 0};
-static struct js_port* js_as_port __initdata = NULL;
-
-#include "joy-analog.h"
-
-struct js_as_info {
- int io;
- char mode;
- char rudder;
- struct js_an_info an;
-};
-
-/*
- * js_as_read_packet() reads an Assassin 3D packet.
- */
-
-static int js_as_read_packet(int io, int length, char *data)
-{
- unsigned char u, v;
- int i;
- unsigned int t, p;
- unsigned long flags;
-
- i = 0;
-
- __save_flags(flags);
- __cli();
-
- outb(0xff,io);
- v = inb(io);
- t = p = JS_AS_MAX_START;
-
- while (t > 0 && i < length) {
- t--;
- u = v; v = inb(io);
- if (~v & u & 0x10) {
- data[i++] = v >> 5;
- p = t = (p - t) << 3;
- }
- }
-
- __restore_flags(flags);
-
- return i;
-}
-
-/*
- * js_as_csum() computes checksum of triplet packet
- */
-
-static int js_as_csum(char *data, int count)
-{
- int i, csum = 0;
- for (i = 0; i < count - 2; i++) csum += data[i];
- return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
-}
-
-/*
- * js_as_read() reads and analyzes A3D joystick data.
- */
-
-static int js_as_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_as_info *info = xinfo;
- char data[JS_AS_MAX_LENGTH];
-
- switch (info->mode) {
-
- case JS_AS_MODE_A3D:
- case JS_AS_MODE_OEM:
- case JS_AS_MODE_PAN:
-
- if (js_as_read_packet(info->io, 29, data) != 29) return -1;
- if (data[0] != info->mode) return -1;
- if (js_as_csum(data, 29)) return -1;
-
- axes[0][0] = ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7);
- axes[0][1] = ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7);
-
- buttons[0][0] = (data[2] << 2) | (data[3] >> 1);
-
- info->an.axes[0] = ((char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
- info->an.axes[1] = ((char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
- info->an.axes[2] = ((char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
- info->an.axes[3] = ((char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
-
- info->an.buttons = ((data[3] << 3) | data[4]) & 0xf;
-
- js_an_decode(&info->an, axes + 1, buttons + 1);
-
- return 0;
-
- case JS_AS_MODE_PXL:
-
- if (js_as_read_packet(info->io, 33, data) != 33) return -1;
- if (data[0] != info->mode) return -1;
- if (js_as_csum(data, 33)) return -1;
-
- axes[0][0] = ((char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128;
- axes[0][1] = ((char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128;
- info->an.axes[0] = ((char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128;
- axes[0][2] = ((char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128;
-
- axes[0][3] = ( data[5] & 1) - ((data[5] >> 2) & 1);
- axes[0][4] = ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1);
- axes[0][5] = ((data[4] >> 1) & 1) - ( data[3] & 1);
- axes[0][6] = ((data[4] >> 2) & 1) - ( data[4] & 1);
-
- axes[0][7] = ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7);
- axes[0][8] = ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7);
-
- buttons[0][0] = (data[2] << 8) | ((data[3] & 6) << 5) | (data[7] << 3) | data[8];
-
- if (info->rudder) axes[1][0] = info->an.axes[0];
-
- return 0;
- }
- return -1;
-}
-
-/*
- * js_as_pxl_init_corr() initializes the correction values for
- * the Panther XL.
- */
-
-static void __init js_as_pxl_init_corr(struct js_corr **corr, int **axes)
-{
- int i;
-
- for (i = 0; i < 2; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = 0;
- corr[0][i].coef[0] = axes[0][i] - 4;
- corr[0][i].coef[1] = axes[0][i] + 4;
- corr[0][i].coef[2] = (1 << 29) / (127 - 32);
- corr[0][i].coef[3] = (1 << 29) / (127 - 32);
- }
-
- corr[0][2].type = JS_CORR_BROKEN;
- corr[0][2].prec = 0;
- corr[0][2].coef[0] = 127 - 4;
- corr[0][2].coef[1] = 128 + 4;
- corr[0][2].coef[2] = (1 << 29) / (127 - 6);
- corr[0][2].coef[3] = (1 << 29) / (127 - 6);
-
- for (i = 3; i < 7; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = 0;
- corr[0][i].coef[0] = 0;
- corr[0][i].coef[1] = 0;
- corr[0][i].coef[2] = (1 << 29);
- corr[0][i].coef[3] = (1 << 29);
- }
-
- for (i = 7; i < 9; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = -1;
- corr[0][i].coef[0] = 0;
- corr[0][i].coef[1] = 0;
- corr[0][i].coef[2] = (104 << 14);
- corr[0][i].coef[3] = (104 << 14);
- }
-}
-
-/*
- * js_as_as_init_corr() initializes the correction values for
- * the Panther and Assassin.
- */
-
-static void __init js_as_as_init_corr(struct js_corr **corr)
-{
- int i;
-
- for (i = 0; i < 2; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = -1;
- corr[0][i].coef[0] = 0;
- corr[0][i].coef[1] = 0;
- corr[0][i].coef[2] = (104 << 14);
- corr[0][i].coef[3] = (104 << 14);
- }
-}
-
-/*
- * js_as_rudder_init_corr() initializes the correction values for
- * the Panther XL connected rudder.
- */
-
-static void __init js_as_rudder_init_corr(struct js_corr **corr, int **axes)
-{
- corr[1][0].type = JS_CORR_BROKEN;
- corr[1][0].prec = 0;
- corr[1][0].coef[0] = axes[1][0] - (axes[1][0] >> 3);
- corr[1][0].coef[1] = axes[1][0] + (axes[1][0] >> 3);
- corr[1][0].coef[2] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1);
- corr[1][0].coef[3] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1);
-}
-
-/*
- * js_as_probe() probes for A3D joysticks.
- */
-
-static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct js_port *port)
-{
- struct js_as_info iniinfo;
- struct js_as_info *info = &iniinfo;
- char *name;
- char data[JS_AS_MAX_LENGTH];
- unsigned char u;
- int i;
- int numdev;
-
- memset(info, 0, sizeof(struct js_as_info));
-
- if (io < 0) return port;
-
- if (check_region(io, 1)) return port;
-
- i = js_as_read_packet(io, JS_AS_MAX_LENGTH, data);
-
- printk("%d\n", i);
-
- if (!i) return port;
- if (js_as_csum(data, i)) return port;
-
- if (data[0] && data[0] <= 4) {
- info->mode = data[0];
- info->io = io;
- request_region(io, 1, "joystick (assassin)");
- port = js_register_port(port, info, 3, sizeof(struct js_as_info), js_as_read);
- info = port->info;
- } else {
- printk(KERN_WARNING "joy-assassin: unknown joystick device detected "
- "(io=%#x, id=%d), contact <vojtech@suse.cz>\n", io, data[0]);
- return port;
- }
-
- udelay(JS_AS_DELAY_READ);
-
- if (info->mode == JS_AS_MODE_PXL) {
- printk(KERN_INFO "js%d: MadCatz Panther XL at %#x\n",
- js_register_device(port, 0, 9, 9, "MadCatz Panther XL", THIS_MODULE, NULL, NULL),
- info->io);
- js_as_read(port->info, port->axes, port->buttons);
- js_as_pxl_init_corr(port->corr, port->axes);
- if (info->an.axes[0] < 254) {
- printk(KERN_INFO "js%d: Analog rudder on MadCatz Panther XL\n",
- js_register_device(port, 1, 1, 0, "Analog rudder", THIS_MODULE, NULL, NULL));
- info->rudder = 1;
- port->axes[1][0] = info->an.axes[0];
- js_as_rudder_init_corr(port->corr, port->axes);
- }
- return port;
- }
-
- switch (info->mode) {
- case JS_AS_MODE_A3D: name = "FP-Gaming Assassin 3D"; break;
- case JS_AS_MODE_PAN: name = "MadCatz Panther"; break;
- case JS_AS_MODE_OEM: name = "OEM Assassin 3D"; break;
- default: name = "This cannot happen"; break;
- }
-
- printk(KERN_INFO "js%d: %s at %#x\n",
- js_register_device(port, 0, 2, 3, name, THIS_MODULE, NULL, NULL),
- name, info->io);
-
- js_as_as_init_corr(port->corr);
-
- js_as_read(port->info, port->axes, port->buttons);
-
- for (i = u = 0; i < 4; i++) if (info->an.axes[i] < 254) u |= 1 << i;
-
- if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0)
- return port;
-
- for (i = 0; i < numdev; i++)
- printk(KERN_INFO "js%d: %s on %s\n",
- js_register_device(port, i + 1, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
- js_an_name(i, &info->an), THIS_MODULE, NULL, NULL),
- js_an_name(i, &info->an), name);
-
- js_an_decode(&info->an, port->axes + 1, port->buttons + 1);
- js_an_init_corr(&info->an, port->axes + 1, port->corr + 1, 0);
-
- return port;
-}
-
-#ifndef MODULE
-int __init js_as_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(24);
- for (i = 0; i <= ints[0] && i < 24; i++) js_as[i] = ints[i+1];
- return 1;
-}
-__setup("js_as=", js_as_setup);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_as_init(void)
-#endif
-{
- int i;
-
- if (js_as[0] >= 0) {
- for (i = 0; (js_as[i*3] >= 0) && i < 8; i++)
- js_as_port = js_as_probe(js_as[i*3], js_as[i*3+1], js_as[i*3+2], js_as_port);
- } else {
- for (i = 0; js_as_port_list[i]; i++) js_as_port = js_as_probe(js_as_port_list[i], 0, 0, js_as_port);
- }
- if (js_as_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-assassin: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_as_info *info;
-
- while (js_as_port) {
- for (i = 0; i < js_as_port->ndevs; i++)
- if (js_as_port->devs[i])
- js_unregister_device(js_as_port->devs[i]);
- info = js_as_port->info;
- release_region(info->io, 1);
- js_as_port = js_unregister_port(js_as_port);
- }
-
-}
-#endif
diff --git a/drivers/char/joystick/joy-console.c b/drivers/char/joystick/joy-console.c
deleted file mode 100644
index e56da540a..000000000
--- a/drivers/char/joystick/joy-console.c
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- * joy-console.c Version 0.14V
- *
- * Copyright (c) 1998 Andree Borrmann
- * Copyright (c) 1999 John Dahlstrom
- * Copyright (c) 1999 David Kuder
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * console (NES, SNES, N64, Multi1, Multi2, PSX) gamepads
- * connected via parallel port. Up to five such controllers
- * can be connected to one parallel port.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_console, "2-6i");
-MODULE_PARM(js_console_2,"2-6i");
-MODULE_PARM(js_console_3,"2-6i");
-
-
-#define JS_NO_PAD 0
-#define JS_SNES_PAD 1
-#define JS_NES_PAD 2
-#define JS_NES4_PAD 3
-#define JS_MULTI_STICK 4
-#define JS_MULTI2_STICK 5
-#define JS_PSX_PAD 6
-#define JS_N64_PAD 7
-#define JS_N64_PAD_DPP 8 /* DirectPad Pro compatible layout */
-
-#define JS_MAX_PAD JS_N64_PAD_DPP
-
-struct js_console_info {
- struct pardevice *port; /* parport device */
- int pads; /* total number of pads */
- int pad_to_device[5]; /* pad to js device mapping (js0, js1, etc.) */
- int snes; /* SNES pads */
- int nes; /* NES pads */
- int n64; /* N64 pads */
- int n64_dpp; /* bits indicate N64 pads treated 14 button, 2 axis */
- int multi; /* Multi joysticks */
- int multi2; /* Multi joysticks with 2 buttons */
- int psx; /* PSX controllers */
-};
-
-static struct js_port* js_console_port = NULL;
-
-static int js_console[] __initdata = { -1, 0, 0, 0, 0, 0 };
-static int js_console_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
-static int js_console_3[] __initdata = { -1, 0, 0, 0, 0, 0 };
-
-static int status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
-
-/*
- * NES/SNES support.
- */
-
-#define JS_NES_DELAY 6 /* Delay between bits - 6us */
-
-#define JS_NES_LENGTH 8 /* The NES pads use 8 bits of data */
-
-#define JS_NES_A 0
-#define JS_NES_B 1
-#define JS_NES_START 2
-#define JS_NES_SELECT 3
-#define JS_NES_UP 4
-#define JS_NES_DOWN 5
-#define JS_NES_LEFT 6
-#define JS_NES_RIGHT 7
-
-#define JS_SNES_LENGTH 12 /* The SNES true length is 16, but the last 4 bits are unused */
-
-#define JS_SNES_B 0
-#define JS_SNES_Y 1
-#define JS_SNES_START 2
-#define JS_SNES_SELECT 3
-#define JS_SNES_UP 4
-#define JS_SNES_DOWN 5
-#define JS_SNES_LEFT 6
-#define JS_SNES_RIGHT 7
-#define JS_SNES_A 8
-#define JS_SNES_X 9
-#define JS_SNES_L 10
-#define JS_SNES_R 11
-
-#define JS_NES_POWER 0xfc
-#define JS_NES_CLOCK 0x01
-#define JS_NES_LATCH 0x02
-
-/*
- * js_nes_read_packet() reads a NES/SNES packet.
- * Each pad uses one bit per byte. So all pads connected to
- * this port are read in parallel.
- */
-
-static void js_nes_read_packet(struct js_console_info *info, int length, unsigned char *data)
-{
- int i;
-
- JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK | JS_NES_LATCH, info->port);
- udelay(JS_NES_DELAY * 2);
- JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK, info->port);
-
- for (i = 0; i < length; i++) {
- udelay(JS_NES_DELAY);
- JS_PAR_DATA_OUT(JS_NES_POWER, info->port);
- data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
- udelay(JS_NES_DELAY);
- JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK, info->port);
- }
-}
-
-/*
- * N64 support.
- */
-
-#define JS_N64_A 0
-#define JS_N64_B 1
-#define JS_N64_Z 2
-#define JS_N64_START 3
-#define JS_N64_UP 4
-#define JS_N64_DOWN 5
-#define JS_N64_LEFT 6
-#define JS_N64_RIGHT 7
-#define JS_N64_UNUSED1 8
-#define JS_N64_UNUSED2 9
-#define JS_N64_L 10
-#define JS_N64_R 11
-#define JS_N64_CU 12
-#define JS_N64_CD 13
-#define JS_N64_CL 14
-#define JS_N64_CR 15
-#define JS_N64_X 23 /* 16 - 23, signed 8-bit int */
-#define JS_N64_Y 31 /* 24 - 31, signed 8-bit int */
-
-#define JS_N64_LENGTH 32 /* N64 bit length, not including stop bit */
-#define JS_N64_REQUEST_LENGTH 37 /* transmit request sequence is 9 bits long */
-#define JS_N64_DELAY 133 /* delay between transmit request, and response ready (us) */
-#define JS_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */
-#define JS_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */
- /* JS_N64_DWS > 24 is known to fail */
-#define JS_N64_POWER_W 0xe2 /* power during write (transmit request) */
-#define JS_N64_POWER_R 0xfd /* power during read */
-#define JS_N64_OUT 0x1d /* output bits to the 4 pads */
- /* Reading the main axes of any N64 pad is known to fail if the corresponding bit */
- /* in JS_N64_OUT is pulled low on the output port (by any routine) for more */
- /* than 0.123 consecutive ms */
-#define JS_N64_CLOCK 0x02 /* clock bits for read */
-
-/*
- * js_n64_read_packet() reads an N64 packet.
- * Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
- */
-
-static void js_n64_read_packet(struct js_console_info *info, unsigned char *data)
-{
- int i;
- unsigned long flags;
-
-/*
- * Request the pad to transmit data
- */
-
- save_flags(flags);
- cli();
- for (i = 0; i < JS_N64_REQUEST_LENGTH; i++) {
- JS_PAR_DATA_OUT(JS_N64_POWER_W | ((JS_N64_REQUEST >> i) & 1 ? JS_N64_OUT : 0), info->port);
- udelay(JS_N64_DWS);
- }
- restore_flags(flags);
-
-/*
- * Wait for the pad response to be loaded into the 33-bit register of the adapter
- */
-
- udelay(JS_N64_DELAY);
-
-/*
- * Grab data (ignoring the last bit, which is a stop bit)
- */
-
- for (i = 0; i < JS_N64_LENGTH; i++) {
- JS_PAR_DATA_OUT(JS_N64_POWER_R, info->port);
- data[i] = JS_PAR_STATUS(info->port);
- JS_PAR_DATA_OUT(JS_N64_POWER_R | JS_N64_CLOCK, info->port);
- }
-
-/*
- * We must wait ~0.2 ms here for the controller to reinitialize before the next read request.
- * No worries as long as js_console_read is polled less frequently than this.
- */
-
-}
-
-/*
- * Multisystem joystick support
- */
-
-#define JS_MULTI_LENGTH 5 /* Multi system joystick packet lenght is 5 */
-#define JS_MULTI2_LENGTH 6 /* One more bit for one more button */
-
-#define JS_MULTI_UP 0
-#define JS_MULTI_DOWN 1
-#define JS_MULTI_LEFT 2
-#define JS_MULTI_RIGHT 3
-#define JS_MULTI_BUTTON 4
-#define JS_MULTI_BUTTON2 5
-
-/*
- * js_multi_read_packet() reads a Multisystem joystick packet.
- */
-
-static void js_multi_read_packet(struct js_console_info *info, int length, unsigned char *data)
-{
- int i;
-
- for (i = 0; i < length; i++) {
- JS_PAR_DATA_OUT(~(1 << i), info->port);
- data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
- printk(" %d", data[i]);
- }
- printk("\n");
-}
-
-/*
- * PSX support
- */
-
-#define JS_PSX_DELAY 10
-#define JS_PSX_LENGTH 8 /* talk to the controller in bytes */
-
-#define JS_PSX_NORMAL 0x41 /* Standard Digital controller */
-#define JS_PSX_NEGCON 0x23 /* NegCon pad */
-#define JS_PSX_MOUSE 0x12 /* PSX Mouse */
-#define JS_PSX_ANALOGR 0x73 /* Analog controller in Red mode */
-#define JS_PSX_ANALOGG 0x53 /* Analog controller in Green mode */
-
-#define JS_PSX_JOYR 0x02 /* These are for the Analog/Dual Shock controller in RED mode */
-#define JS_PSX_JOYL 0x04 /* I'm not sure the exact purpose of these but its in the docs */
-#define JS_PSX_SELBUT 0x01 /* Standard buttons on almost all PSX controllers. */
-#define JS_PSX_START 0x08
-#define JS_PSX_UP 0x10 /* Digital direction pad */
-#define JS_PSX_RIGHT 0x20
-#define JS_PSX_DOWN 0x40
-#define JS_PSX_LEFT 0x80
-
-#define JS_PSX_CLOCK 0x04 /* Pin 3 */
-#define JS_PSX_COMMAND 0x01 /* Pin 1 */
-#define JS_PSX_POWER 0xf8 /* Pins 5-9 */
-#define JS_PSX_SELECT 0x02 /* Pin 2 */
-#define JS_PSX_NOPOWER 0x04
-
-/*
- * js_psx_command() writes 8bit command and reads 8bit data from
- * the psx pad.
- */
-
-static int js_psx_command(struct js_console_info *info, int b)
-{
- int i, cmd, ret=0;
-
- cmd = (b&1)?JS_PSX_COMMAND:0;
- for (i=0; i<8; i++) {
- JS_PAR_DATA_OUT(cmd | JS_PSX_POWER, info->port);
- udelay(JS_PSX_DELAY);
- ret |= ((JS_PAR_STATUS(info->port) ^ JS_PAR_STATUS_INVERT ) & info->psx) ? (1<<i) : 0;
- cmd = (b&1)?JS_PSX_COMMAND:0;
- JS_PAR_DATA_OUT(cmd | JS_PSX_CLOCK | JS_PSX_POWER, info->port);
- udelay(JS_PSX_DELAY);
- b >>= 1;
- }
- return ret;
-}
-
-/*
- * js_psx_read_packet() reads a whole psx packet and returns
- * device identifier code.
- */
-
-static int js_psx_read_packet(struct js_console_info *info, int length, unsigned char *data)
-{
- int i, ret;
- unsigned long flags;
-
- __save_flags(flags);
- __cli();
-
- JS_PAR_DATA_OUT(JS_PSX_POWER, info->port);
-
- JS_PAR_DATA_OUT(JS_PSX_CLOCK | JS_PSX_SELECT | JS_PSX_POWER, info->port); /* Select pad */
- udelay(JS_PSX_DELAY*2);
- js_psx_command(info, 0x01); /* Access pad */
- ret = js_psx_command(info, 0x42); /* Get device id */
- if (js_psx_command(info, 0)=='Z') /* okay? */
- for (i=0; i<length; i++)
- data[i]=js_psx_command(info, 0);
- else ret = -1;
-
- JS_PAR_DATA_OUT(JS_PSX_SELECT | JS_PSX_CLOCK | JS_PSX_POWER, info->port);
- __restore_flags(flags);
-
- return ret;
-}
-
-
-/*
- * js_console_read() reads and analyzes console pads data.
- */
-
-#define JS_MAX_LENGTH JS_N64_LENGTH
-
-static int js_console_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_console_info *info = xinfo;
- unsigned char data[JS_MAX_LENGTH];
-
- int i, j, s;
- int n = 0;
-
-/*
- * NES and SNES pads
- */
-
- if (info->nes || info->snes) {
-
- js_nes_read_packet(info, info->snes ? JS_SNES_LENGTH : JS_NES_LENGTH, data);
-
- for (i = 0; i < 5; i++) {
- s = status_bit[i];
- n = info->pad_to_device[i];
- if (info->nes & s) {
- axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0);
- axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP] &s?1:0);
-
- buttons[n][0] = (data[JS_NES_A] &s?1:0) | (data[JS_NES_B] &s?2:0)
- | (data[JS_NES_START]&s?4:0) | (data[JS_NES_SELECT]&s?8:0);
- } else
- if (info->snes & s) {
- axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0);
- axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP] &s?1:0);
-
- buttons[n][0] = (data[JS_SNES_A] &s?0x01:0) | (data[JS_SNES_B] &s?0x02:0)
- | (data[JS_SNES_X] &s?0x04:0) | (data[JS_SNES_Y] &s?0x08:0)
- | (data[JS_SNES_L] &s?0x10:0) | (data[JS_SNES_R] &s?0x20:0)
- | (data[JS_SNES_START]&s?0x40:0) | (data[JS_SNES_SELECT]&s?0x80:0);
- }
- }
- }
-
-/*
- * N64 pads
- */
-
- if (info->n64) {
- if ( (info->nes || info->snes) && (info->n64 & status_bit[0]) ) {
- /* SNES/NES compatibility */
- udelay(240); /* 200 us delay + 20% tolerance */
- }
-
- js_n64_read_packet(info, data);
-
- for (i = 0; i < 5; i++) {
- s = status_bit[i];
- n = info->pad_to_device[i];
- if (info->n64 & s & ~(data[JS_N64_UNUSED1] | data[JS_N64_UNUSED2])) {
-
- buttons[n][0] = ( ((data[JS_N64_A]&s) ? 0x01:0) | ((data[JS_N64_B] & s ) ? 0x02:0)
- | ((data[JS_N64_Z]&s) ? 0x04:0) | ((data[JS_N64_L] & s ) ? 0x08:0)
- | ((data[JS_N64_R]&s) ? 0x10:0) | ((data[JS_N64_START]&s)? 0x20:0)
- | ((data[JS_N64_CU]&s)? 0x40:0) | ((data[JS_N64_CR]&s) ? 0x80:0)
- | ((data[JS_N64_CD]&s)?0x100:0) | ((data[JS_N64_CL]&s) ?0x200:0) );
-
- if (info->n64_dpp & s) {
- buttons[n][0] |= ((data[JS_N64_LEFT]&s) ? 0x400:0) | ((data[JS_N64_UP] & s)? 0x800:0)
- |((data[JS_N64_RIGHT]&s)?0x1000:0) | ((data[JS_N64_DOWN]&s)?0x2000:0);
- } else {
- axes[n][2] = (data[JS_N64_RIGHT]&s?1:0) - (data[JS_N64_LEFT]&s?1:0);
- axes[n][3] = (data[JS_N64_DOWN] &s?1:0) - (data[JS_N64_UP] &s?1:0);
- }
-
- /* build int from bits of signed 8-bit int's */
- j = 7;
- axes[n][0] = (data[JS_N64_X - j] & s) ? ~0x7f : 0;
- axes[n][1] = (data[JS_N64_Y - j] & s) ? ~0x7f : 0;
- while ( j-- > 0 ) {
- axes[n][0] |= (data[JS_N64_X - j] & s) ? (1 << j) : 0;
- axes[n][1] |= (data[JS_N64_Y - j] & s) ? (1 << j) : 0;
- }
- /* flip Y-axis for conformity */
- axes[n][1] = -axes[n][1];
-
- }
- }
- }
-
-/*
- * Multi and Multi2 joysticks
- */
-
- if (info->multi || info->multi2) {
-
- js_multi_read_packet(info, info->multi2 ? JS_MULTI2_LENGTH : JS_MULTI_LENGTH, data);
-
- for (i = 0; i < 5; i++) {
- s = status_bit[i];
- n = info->pad_to_device[i];
- if (info->multi & s) {
- axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0);
- axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP] &s?1:0);
-
- buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0;
- } else
- if (info->multi2 & s) {
- axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0);
- axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP] &s?1:0);
-
- buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0 | (data[JS_MULTI_BUTTON2]&s)?2:0;
- }
- }
- }
-
-/*
- * PSX controllers
- */
-
- if (info->psx) {
-
- for ( i = 0; i < 5; i++ )
- if ( info->psx & status_bit[i] ) {
- n = info->pad_to_device[i];
- break;
- }
-
- buttons[n][0] = 0;
-
- switch (js_psx_read_packet(info, 6, data)) {
-
- case JS_PSX_ANALOGR:
-
- buttons[n][0] |= (data[0]&JS_PSX_JOYL?0:0x800) | (data[0]&JS_PSX_JOYR?0:0x400);
-
- case JS_PSX_ANALOGG:
-
- axes[n][2] = data[2];
- axes[n][3] = data[3];
- axes[n][4] = data[4];
- axes[n][5] = data[5];
-
- case JS_PSX_NORMAL:
- case JS_PSX_NEGCON:
-
- axes[n][0] = (data[0]&JS_PSX_RIGHT?0:1) - (data[0]&JS_PSX_LEFT?0:1);
- axes[n][1] = (data[0]&JS_PSX_DOWN ?0:1) - (data[0]&JS_PSX_UP ?0:1);
-
- buttons[n][0] |= ((~data[1]&0xf)<<4) | ((~data[1]&0xf0)>>4) |
- (data[0]&JS_PSX_START?0:0x200) | (data[0]&JS_PSX_SELBUT?0:0x100);
-
- break;
-
- }
- }
-
- return 0;
-}
-
-/*
- * open callback: claim parport.
- * FIXME: if parport_claim() will sleep we can get into mess.
- */
-
-int js_console_open(struct js_dev *dev)
-{
- struct js_console_info *info = dev->port->info;
- if (!MOD_IN_USE && parport_claim(info->port)) return -EBUSY;
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * close callback: release parport
- */
-
-int js_console_close(struct js_dev *dev)
-{
- struct js_console_info *info = dev->port->info;
- MOD_DEC_USE_COUNT;
- if (!MOD_IN_USE) parport_release(info->port);
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- struct js_console_info *info;
- int i;
-
- while (js_console_port) {
- for (i = 0; i < js_console_port->ndevs; i++)
- if (js_console_port->devs[i])
- js_unregister_device(js_console_port->devs[i]);
- info = js_console_port->info;
- parport_unregister_device(info->port);
- js_console_port = js_unregister_port(js_console_port);
- }
-}
-#endif
-
-/*
- * js_console_init_corr() initializes correction values of
- * console gamepads.
- */
-
-static void __init js_console_init_corr(int num_axes, int type, struct js_corr *corr)
-{
- int i;
-
- for (i = 0; i < num_axes; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 29);
- corr[i].coef[3] = (1 << 29);
- }
-
- if (type == JS_N64_PAD || type == JS_N64_PAD_DPP) {
- for (i = 0; i < 2; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 22);
- corr[i].coef[3] = (1 << 22);
- }
- }
-
- if (type == JS_PSX_ANALOGG || type == JS_PSX_ANALOGR) {
- for (i = 2; i < 6; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 127 - 2;
- corr[i].coef[1] = 128 + 2;
- corr[i].coef[2] = (1 << 29) / (127 - 4);
- corr[i].coef[3] = (1 << 29) / (127 - 4);
- }
- }
-}
-
-/*
- * js_console_probe() probes for console gamepads.
- * Only PSX pads can really be probed for.
- */
-
-static struct js_port __init *js_console_probe(int *config, struct js_port *port)
-{
- char *name[5];
- int i, psx, axes[5], buttons[5], type[5];
- unsigned char data[2]; /* used for PSX probe */
- struct js_console_info info;
- struct parport *pp;
-
- memset(&info, 0, sizeof(struct js_console_info));
-
- if (config[0] < 0) return port;
-
- if (config[0] > 0x10)
- for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
- else
- for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;
-
- if (!pp) {
- printk(KERN_ERR "joy-console: no such parport\n");
- return port;
- }
-
- info.port = parport_register_device(pp, "joystick (console)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
- if (!info.port)
- return port;
-
- if (parport_claim(info.port))
- {
- parport_unregister_device(info.port); /* port currently not available ... */
- return port;
- }
-
- for (i = 0; i < 5; i++) {
-
- type[info.pads] = config[i+1];
- info.pad_to_device[i] = info.pads;
-
- switch(config[i+1]) {
-
- case JS_NO_PAD:
-
- break;
-
- case JS_SNES_PAD:
-
- axes[info.pads] = 2;
- buttons[info.pads] = 8;
- name[info.pads] = "SNES pad";
- info.snes |= status_bit[i];
- info.pads++;
- break;
-
- case JS_NES_PAD:
-
- axes[info.pads] = 2;
- buttons[info.pads] = 4;
- name[info.pads] = "NES pad";
- info.nes |= status_bit[i];
- info.pads++;
- break;
-
- case JS_N64_PAD:
- axes[info.pads] = 4;
- buttons[info.pads] = 10;
- name[info.pads] = "N64 pad";
- info.n64 |= status_bit[i];
- info.pads++;
- break;
-
- case JS_N64_PAD_DPP:
- axes[info.pads] = 2;
- buttons[info.pads] = 14;
- name[info.pads] = "N64 pad (DPP mode)";
- info.n64 |= status_bit[i];
- info.n64_dpp |= status_bit[i];
- info.pads++;
- break;
-
- case JS_MULTI_STICK:
-
- axes[info.pads] = 2;
- buttons[info.pads] = 1;
- name[info.pads] = "Multisystem joystick";
- info.multi |= status_bit[i];
- info.pads++;
- break;
-
- case JS_MULTI2_STICK:
-
- axes[info.pads] = 2;
- buttons[info.pads] = 2;
- name[info.pads] = "Multisystem joystick (2 fire)";
- info.multi |= status_bit[i];
- info.pads++;
- break;
-
- case JS_PSX_PAD:
-
- info.psx |= status_bit[i];
- psx = js_psx_read_packet(&info, 2, data);
- psx = js_psx_read_packet(&info, 2, data);
- info.psx &= ~status_bit[i];
-
- type[i] = psx;
-
- switch(psx) {
- case JS_PSX_NORMAL:
- axes[info.pads] = 2;
- buttons[info.pads] = 10;
- name[info.pads] = "PSX pad";
- info.psx |= status_bit[i];
- info.pads++;
- break;
-
- case JS_PSX_ANALOGR:
- axes[info.pads] = 6;
- buttons[info.pads] = 12;
- name[info.pads] = "Analog Red PSX pad";
- info.psx |= status_bit[i];
- info.pads++;
- break;
-
- case JS_PSX_ANALOGG:
- axes[info.pads] = 6;
- buttons[info.pads] = 10;
- name[info.pads] = "Analog Green PSX pad";
- info.psx |= status_bit[i];
- info.pads++;
- break;
-
- case JS_PSX_NEGCON:
- axes[info.pads] = 2;
- buttons[info.pads] = 10;
- name[info.pads] = "NegCon PSX pad";
- info.psx |= status_bit[i];
- info.pads++;
- break;
-
- case JS_PSX_MOUSE:
- printk(KERN_WARNING "joy-psx: PSX mouse not supported...\n");
- break;
-
- case -1:
- printk(KERN_ERR "joy-psx: no PSX controller found...\n");
- break;
-
- default:
- printk(KERN_WARNING "joy-psx: PSX controller unknown: 0x%x,"
- " please report to <vojtech@suse.cz>.\n", psx);
- }
- break;
-
- default:
-
- printk(KERN_WARNING "joy-console: pad type %d unknown\n", config[i+1]);
- }
- }
-
- if (!info.pads) {
- parport_release(info.port);
- parport_unregister_device(info.port);
- return port;
- }
-
- port = js_register_port(port, &info, info.pads, sizeof(struct js_console_info), js_console_read);
-
- for (i = 0; i < info.pads; i++) {
- printk(KERN_INFO "js%d: %s on %s\n",
- js_register_device(port, i, axes[i], buttons[i], name[i], NULL, js_console_open, js_console_close),
- name[i], info.port->port->name);
-
- js_console_init_corr(axes[i], type[i], port->corr[i]);
- }
-
- parport_release(info.port);
- return port;
-}
-
-#ifndef MODULE
-int __init js_console_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(6);
- for (i = 0; i <= ints[0] && i < 6; i++) js_console[i] = ints[i+1];
- return 1;
-}
-int __init js_console_setup_2(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(6);
- for (i = 0; i <= ints[0] && i < 6; i++) js_console_2[i] = ints[i+1];
- return 1;
-}
-int __init js_console_setup_3(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(6);
- for (i = 0; i <= ints[0] && i < 6; i++) js_console_3[i] = ints[i+1];
- return 1;
-}
-__setup("js_console=", js_console_setup);
-__setup("js_console_2=", js_console_setup_2);
-__setup("js_console_3=", js_console_setup_3);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_console_init(void)
-#endif
-{
- js_console_port = js_console_probe(js_console, js_console_port);
- js_console_port = js_console_probe(js_console_2, js_console_port);
- js_console_port = js_console_probe(js_console_3, js_console_port);
-
- if (js_console_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-console: no joysticks specified\n");
-#endif
- return -ENODEV;
-}
diff --git a/drivers/char/joystick/joy-creative.c b/drivers/char/joystick/joy-creative.c
deleted file mode 100644
index b5ae4c019..000000000
--- a/drivers/char/joystick/joy-creative.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * joy-creative.c Version 1.2
- *
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * Creative Labs Blaster gamepad family.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#define JS_CR_MAX_STROBE 100 /* 100 us max wait for first strobe */
-#define JS_CR_LENGTH 36
-
-#define JS_CR_MODE_BGPC 8
-
-static int js_cr_port_list[] __initdata = {0x201, 0};
-static struct js_port* js_cr_port __initdata = NULL;
-
-struct js_cr_info {
- int io;
- unsigned char mode[2];
-};
-
-/*
- * js_cr_read_packet() reads a Blaster gamepad packet.
- */
-
-static int js_cr_read_packet(int io, unsigned int *data)
-{
- unsigned long flags;
- unsigned char u, v, w;
- __u64 buf[2];
- int r[2], t[2], p[2];
- int i, j, ret;
-
- for (i = 0; i < 2; i++) {
- r[i] = buf[i] = 0;
- p[i] = t[i] = JS_CR_MAX_STROBE;
- p[i] += JS_CR_MAX_STROBE;
- }
-
- __save_flags(flags);
- __cli();
-
- u = inb(io);
-
- do {
- t[0]--; t[1]--;
- v = inb(io);
- for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2)
- if (w & 0x30) {
- if ((w & 0x30) < 0x30 && r[i] < JS_CR_LENGTH && t[i] > 0) {
- buf[i] |= (__u64)((w >> 5) & 1) << r[i]++;
- p[i] = t[i] = (p[i] - t[i]) << 1;
- u = v;
- } else t[i] = 0;
- }
- } while (t[0] > 0 || t[1] > 0);
-
- __restore_flags(flags);
-
-
- ret = 0;
-
- for (i = 0; i < 2; i++) {
-
- if (r[i] != JS_CR_LENGTH) continue;
-
- for (j = 0; j < JS_CR_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++)
- buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (JS_CR_LENGTH - 1));
-
- if (j < JS_CR_LENGTH) ret |= (1 << i);
-
- data[i] = ((buf[i] >> 7) & 0x000001f) | ((buf[i] >> 8) & 0x00003e0)
- | ((buf[i] >> 9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000)
- | ((buf[i] >> 11) & 0x1f00000);
-
- }
-
- return ret;
-}
-
-/*
- * js_cr_read() reads and analyzes Blaster gamepad data.
- */
-
-static int js_cr_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_cr_info *info = xinfo;
- unsigned int data[2];
- int i, r;
-
- if (!(r = js_cr_read_packet(info->io, data)))
- return -1;
-
- for (i = 0; i < 2; i++)
- if (r & (1 << i)) {
- switch (info->mode[i]) {
-
- case JS_CR_MODE_BGPC:
-
- axes[i][0] = ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1);
- axes[i][1] = ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1);
-
- buttons[i][0] = ((data[i] >> 12) & 0x007) | ((data[i] >> 6) & 0x038)
- | ((data[i] >> 1) & 0x0c0) | ((data[i] >> 7) & 0x300)
- | ((data[i] << 5) & 0xc00);
-
- break;
-
- default:
- break;
-
- }
- }
-
- return 0;
-}
-
-/*
- * js_cr_init_corr() initializes correction values of
- * Blaster gamepads.
- */
-
-static void __init js_cr_init_corr(int mode, struct js_corr *corr)
-{
- int i;
-
- switch (mode) {
-
- case JS_CR_MODE_BGPC:
-
- for (i = 0; i < 2; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 29);
- corr[i].coef[3] = (1 << 29);
- }
-
- break;
-
- }
-}
-
-/*
- * js_cr_probe() probes for Blaster gamepads.
- */
-
-static struct js_port __init *js_cr_probe(int io, struct js_port *port)
-{
- struct js_cr_info info;
- char *names[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Blaster GamePad Cobra" };
- char axes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 2 };
- char buttons[] = { 0, 0, 0, 0, 0, 0, 0, 0, 12 };
- unsigned int data[2];
- int i, r;
-
- if (check_region(io, 1)) return port;
-
- info.mode[0] = info.mode[1] = 0;
-
- if (!(r = js_cr_read_packet(io, data)))
- return port;
-
- for (i = 0; i < 2; i++) {
- if (r & (1 << i)) {
- if (~data[i] & 1) {
- info.mode[i] = JS_CR_MODE_BGPC;
- } else {
- info.mode[i] = (data[i] >> 2) & 7;
- }
- if (!names[info.mode[i]]) {
- printk(KERN_WARNING "joy-creative: Unknown Creative device %d at %#x\n",
- info.mode[i], io);
- info.mode[i] = 0;
- }
- }
- }
-
- if (!info.mode[0] && !info.mode[1]) return port;
-
- info.io = io;
-
- request_region(io, 1, "joystick (creative)");
- port = js_register_port(port, &info, 2, sizeof(struct js_cr_info), js_cr_read);
-
- for (i = 0; i < 2; i++)
- if (info.mode[i]) {
- printk(KERN_INFO "js%d: %s at %#x\n",
- js_register_device(port, i, axes[info.mode[i]], buttons[info.mode[i]],
- names[info.mode[i]], THIS_MODULE, NULL, NULL),
- names[info.mode[i]], io);
- js_cr_init_corr(info.mode[i], port->corr[i]);
- }
-
- return port;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_cr_init(void)
-#endif
-{
- int *p;
-
- for (p = js_cr_port_list; *p; p++) js_cr_port = js_cr_probe(*p, js_cr_port);
- if (js_cr_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-creative: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_cr_info *info;
-
- while (js_cr_port) {
- for (i = 0; i < js_cr_port->ndevs; i++)
- if (js_cr_port->devs[i])
- js_unregister_device(js_cr_port->devs[i]);
- info = js_cr_port->info;
- release_region(info->io, 1);
- js_cr_port = js_unregister_port(js_cr_port);
- }
-}
-#endif
diff --git a/drivers/char/joystick/joy-db9.c b/drivers/char/joystick/joy-db9.c
deleted file mode 100644
index 41169b12c..000000000
--- a/drivers/char/joystick/joy-db9.c
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * joy-db9.c Version 0.6V
- *
- * Copyright (c) 1998 Andree Borrmann
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * console (Atari, Amstrad, Commodore, Amiga, Sega) joysticks
- * and gamepads connected to the parallel port.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_db9, "2i");
-MODULE_PARM(js_db9_2, "2i");
-MODULE_PARM(js_db9_3, "2i");
-
-#define JS_MULTI_STICK 0x01
-#define JS_MULTI2_STICK 0x02
-#define JS_GENESIS_PAD 0x03
-#define JS_GENESIS5_PAD 0x05
-#define JS_GENESIS6_PAD 0x06
-#define JS_SATURN_PAD 0x07
-#define JS_MULTI_0802 0x08
-#define JS_MULTI_0802_2 0x09
-#define JS_MAX_PAD 0x0A
-
-#define JS_DB9_UP 0x01
-#define JS_DB9_DOWN 0x02
-#define JS_DB9_LEFT 0x04
-#define JS_DB9_RIGHT 0x08
-#define JS_DB9_FIRE1 0x10
-#define JS_DB9_FIRE2 0x20
-#define JS_DB9_FIRE3 0x40
-#define JS_DB9_FIRE4 0x80
-
-#define JS_DB9_NORMAL 0x2a
-#define JS_DB9_NOSELECT 0x28
-
-#define JS_DB9_SATURN0 0x20
-#define JS_DB9_SATURN1 0x22
-#define JS_DB9_SATURN2 0x24
-#define JS_DB9_SATURN3 0x26
-
-#define JS_GENESIS6_DELAY 14
-
-static struct js_port* js_db9_port = NULL;
-
-static int js_db9[] __initdata = { -1, 0 };
-static int js_db9_2[] __initdata = { -1, 0 };
-static int js_db9_3[] __initdata = { -1, 0 };
-
-struct js_db9_info {
- struct pardevice *port; /* parport device */
- int mode; /* pad mode */
-};
-
-/*
- * js_db9_read() reads and analyzes db9 joystick data.
- */
-
-static int js_db9_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_db9_info *info = xinfo;
- int data;
-
- switch(info->mode)
- {
- case JS_MULTI_0802_2:
-
- data = JS_PAR_DATA_IN(info->port) >> 3;
-
- axes[1][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[1][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[1][0] = (data&JS_DB9_FIRE1?0:1);
-
- case JS_MULTI_0802:
-
- data = JS_PAR_STATUS(info->port) >> 3;
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[0][0] = (data&JS_DB9_FIRE1?1:0);
-
- break;
-
- case JS_MULTI_STICK:
-
- data = JS_PAR_DATA_IN(info->port);
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[0][0] = (data&JS_DB9_FIRE1?0:1);
-
- break;
-
- case JS_MULTI2_STICK:
-
- data=JS_PAR_DATA_IN(info->port);
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[0][0] = (data&JS_DB9_FIRE1?0:1) | (data&JS_DB9_FIRE2?0:2);
-
- break;
-
- case JS_GENESIS_PAD:
-
- JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port);
- data = JS_PAR_DATA_IN(info->port);
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[0][0] = (data&JS_DB9_FIRE1?0:2) | (data&JS_DB9_FIRE2?0:4);
-
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL,info->port);
- data=JS_PAR_DATA_IN(info->port);
-
- buttons[0][0] |= (data&JS_DB9_FIRE1?0:1) | (data&JS_DB9_FIRE2?0:8);
-
- break;
-
- case JS_GENESIS5_PAD:
-
- JS_PAR_CTRL_OUT(JS_DB9_NOSELECT,info->port);
- data=JS_PAR_DATA_IN(info->port);
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[0][0] = (data&JS_DB9_FIRE1?0:0x02) | (data&JS_DB9_FIRE2?0:0x04);
-
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
- data=JS_PAR_DATA_IN(info->port);
-
- buttons[0][0] |= (data&JS_DB9_FIRE1?0:0x01) | (data&JS_DB9_FIRE2?0:0x08) |
- (data&JS_DB9_LEFT ?0:0x10) | (data&JS_DB9_RIGHT?0:0x20);
- break;
-
- case JS_GENESIS6_PAD:
-
- JS_PAR_CTRL_OUT(JS_DB9_NOSELECT,info->port); /* 1 */
- udelay(JS_GENESIS6_DELAY);
- data=JS_PAR_DATA_IN(info->port);
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[0][0] = (data&JS_DB9_FIRE1?0:0x02) | (data&JS_DB9_FIRE2?0:0x04);
-
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
- udelay(JS_GENESIS6_DELAY);
- data=JS_PAR_DATA_IN(info->port);
-
- buttons[0][0] |= (data&JS_DB9_FIRE1?0:0x01) | (data&JS_DB9_FIRE2?0:0x08);
-
- JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 2 */
- udelay(JS_GENESIS6_DELAY);
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
- udelay(JS_GENESIS6_DELAY);
- JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 3 */
- udelay(JS_GENESIS6_DELAY);
- data=JS_PAR_DATA_IN(info->port);
-
- buttons[0][0] |= (data&JS_DB9_LEFT?0:0x10) | (data&JS_DB9_DOWN ?0:0x20) |
- (data&JS_DB9_UP ?0:0x40) | (data&JS_DB9_RIGHT?0:0x80);
-
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
- udelay(JS_GENESIS6_DELAY);
- JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 4 */
- udelay(JS_GENESIS6_DELAY);
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
-
- break;
-
- case JS_SATURN_PAD:
-
- JS_PAR_CTRL_OUT(JS_DB9_SATURN0, info->port);
- data = JS_PAR_DATA_IN(info->port);
-
- buttons[0][0] = (data&JS_DB9_UP ?0:0x20) | (data&JS_DB9_DOWN ?0:0x10) |
- (data&JS_DB9_LEFT?0:0x08) | (data&JS_DB9_RIGHT?0:0x40);
-
- JS_PAR_CTRL_OUT(JS_DB9_SATURN2, info->port);
- data = JS_PAR_DATA_IN(info->port);
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
- data = JS_PAR_DATA_IN(info->port);
-
- buttons[0][0] |= (data&JS_DB9_UP ?0:0x02) | (data&JS_DB9_DOWN ?0:0x04) |
- (data&JS_DB9_LEFT?0:0x01) | (data&JS_DB9_RIGHT?0:0x80);
-
-
- break;
-
- default:
- return -1;
- }
-
- return 0;
-}
-
-/*
- * open callback: claim parport.
- * FIXME: race possible.
- */
-
-int js_db9_open(struct js_dev *dev)
-{
- struct js_db9_info *info = dev->port->info;
-
- if (!MOD_IN_USE) {
- if (parport_claim(info->port)) return -EBUSY;
-
- JS_PAR_DATA_OUT(0xff, info->port);
- if (info->mode != JS_MULTI_0802)
- JS_PAR_ECTRL_OUT(0x35,info->port); /* enable PS/2 mode: */
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL,info->port); /* reverse direction, enable Select signal */
- }
-
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * close callback: release parport
- */
-
-int js_db9_close(struct js_dev *dev)
-{
- struct js_db9_info *info = dev->port->info;
-
- MOD_DEC_USE_COUNT;
-
- if (!MOD_IN_USE) {
-
- JS_PAR_CTRL_OUT(0x00,info->port); /* normal direction */
- if (info->mode != JS_MULTI_0802)
- JS_PAR_ECTRL_OUT(0x15,info->port); /* enable normal mode */
-
- parport_release(info->port);
- }
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- struct js_db9_info *info;
- int i;
-
- while (js_db9_port) {
- info = js_db9_port->info;
-
- for (i = 0; i < js_db9_port->ndevs; i++)
- if (js_db9_port->devs[i])
- js_unregister_device(js_db9_port->devs[i]);
- parport_unregister_device(info->port);
- js_db9_port = js_unregister_port(js_db9_port);
- }
-
-}
-#endif
-
-/*
- * js_db9_init_corr() initializes correction values of
- * db9 gamepads.
- */
-
-static void __init js_db9_init_corr(struct js_corr *corr)
-{
- int i;
-
- for (i = 0; i < 2; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 29);
- corr[i].coef[3] = (1 << 29);
- }
-}
-
-/*
- * js_db9_probe() probes for db9 gamepads.
- */
-
-static struct js_port __init *js_db9_probe(int *config, struct js_port *port)
-{
- struct js_db9_info info;
- struct parport *pp;
- int i;
- char buttons[JS_MAX_PAD] = {0,1,2,4,0,6,8,8,1,1};
- char *name[JS_MAX_PAD] = {NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad",
- NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick",
- "Multisystem (0.8.0.2-dual) joystick"};
-
- if (config[0] < 0) return port;
- if (config[1] < 0 || config[1] >= JS_MAX_PAD || !name[config[1]]) return port;
-
- info.mode = config[1];
-
- if (config[0] > 0x10)
- for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
- else
- for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;
-
- if (!pp) {
- printk(KERN_ERR "joy-db9: no such parport\n");
- return port;
- }
-
- if (!(pp->modes & (PARPORT_MODE_PCPS2 | PARPORT_MODE_PCECPPS2)) && info.mode != JS_MULTI_0802) {
- printk(KERN_ERR "js-db9: specified parport is not bidirectional\n");
- return port;
- }
-
- info.port = parport_register_device(pp, "joystick (db9)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
- if (!info.port)
- return port;
-
- port = js_register_port(port, &info, 1 + (info.mode == JS_MULTI_0802_2), sizeof(struct js_db9_info), js_db9_read);
-
- for (i = 0; i < 1 + (info.mode == JS_MULTI_0802_2); i++) {
- printk(KERN_INFO "js%d: %s on %s\n",
- js_register_device(port, i, 2, buttons[info.mode], name[info.mode], NULL, js_db9_open, js_db9_close),
- name[info.mode], info.port->port->name);
-
- js_db9_init_corr(port->corr[i]);
- }
-
-
- return port;
-}
-
-#ifndef MODULE
-int __init js_db9_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_db9[i] = ints[i+1];
- return 1;
-}
-int __init js_db9_setup_2(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_db9_2[i] = ints[i+1];
- return 1;
-}
-int __init js_db9_setup_3(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_db9_3[i] = ints[i+1];
- return 1;
-}
-__setup("js_db9=", js_db9_setup);
-__setup("js_db9_2=", js_db9_setup_2);
-__setup("js_db9_3=", js_db9_setup_3);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_db9_init(void)
-#endif
-{
- js_db9_port = js_db9_probe(js_db9, js_db9_port);
- js_db9_port = js_db9_probe(js_db9_2, js_db9_port);
- js_db9_port = js_db9_probe(js_db9_3, js_db9_port);
-
- if (js_db9_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-db9: no joysticks specified\n");
-#endif
- return -ENODEV;
-}
diff --git a/drivers/char/joystick/joy-gravis.c b/drivers/char/joystick/joy-gravis.c
deleted file mode 100644
index 84a6def16..000000000
--- a/drivers/char/joystick/joy-gravis.c
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * joy-gravis.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * Gravis GrIP digital joystick family.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#define JS_GR_MODE_GPP 1
-#define JS_GR_LENGTH_GPP 24
-#define JS_GR_STROBE_GPP 400
-
-#define JS_GR_MODE_XT 2
-#define JS_GR_MODE_BD 3
-#define JS_GR_LENGTH_XT 4
-#define JS_GR_STROBE_XT 200
-#define JS_GR_MAX_CHUNKS_XT 10
-#define JS_GR_MAX_BITS_XT 30
-
-static int js_gr_port_list[] __initdata = {0x201, 0};
-static struct js_port* js_gr_port __initdata = NULL;
-
-struct js_gr_info {
- int io;
- unsigned char mode[2];
-};
-
-/*
- * js_gr_gpp_read_packet() reads a Gravis GamePad Pro packet.
- */
-
-static int js_gr_gpp_read_packet(int io, int shift, unsigned int *data)
-{
- unsigned long flags;
- unsigned char u, v;
- unsigned int t, p;
- int i;
-
- i = 0;
- data[0] = 0;
- p = t = JS_GR_STROBE_GPP;
- p += JS_GR_STROBE_GPP;
-
- __save_flags(flags);
- __cli();
-
- v = inb(io) >> shift;
-
- do {
- t--;
- u = v; v = (inb(io) >> shift) & 3;
- if (~v & u & 1) {
- data[0] |= (v >> 1) << i++;
- p = t = (p - t) << 1;
- }
- } while (i < JS_GR_LENGTH_GPP && t > 0);
-
- __restore_flags(flags);
-
- if (i < JS_GR_LENGTH_GPP) return -1;
-
- for (i = 0; i < JS_GR_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++)
- data[0] = data[0] >> 1 | (data[0] & 1) << (JS_GR_LENGTH_GPP - 1);
-
- return -(i == JS_GR_LENGTH_GPP);
-}
-
-/*
- * js_gr_xt_read_packet() reads a Gravis Xterminator packet.
- */
-
-static int js_gr_xt_read_packet(int io, int shift, unsigned int *data)
-{
- unsigned int i, j, buf, crc;
- unsigned char u, v, w;
- unsigned long flags;
- unsigned int t, p;
- char status;
-
- data[0] = data[1] = data[2] = data[3] = 0;
- status = buf = i = j = 0;
- p = t = JS_GR_STROBE_XT;
- p += JS_GR_STROBE_XT;
-
- __save_flags(flags);
- __cli();
-
- v = w = (inb(io) >> shift) & 3;
-
- do {
- t--;
- u = (inb(io) >> shift) & 3;
-
- if (u ^ v) {
-
- if ((u ^ v) & 1) {
- p = t = (p - t) << 2;
- buf = (buf << 1) | (u >> 1);
- i++;
- } else
-
- if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) {
- p = t = (p - t) << 2;
- if (i == 20) {
- crc = buf ^ (buf >> 7) ^ (buf >> 14);
- if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) {
- data[buf >> 18] = buf >> 4;
- status |= 1 << (buf >> 18);
- }
- j++;
- }
- buf = 0;
- i = 0;
- }
-
- w = v;
- v = u;
- }
-
- } while (status != 0xf && i < JS_GR_MAX_BITS_XT && j < JS_GR_MAX_CHUNKS_XT && t > 0);
-
- __restore_flags(flags);
-
- return -(status != 0xf);
-}
-
-/*
- * js_gr_read() reads and analyzes GrIP joystick data.
- */
-
-static int js_gr_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_gr_info *info = xinfo;
- unsigned int data[JS_GR_LENGTH_XT];
- int i;
-
- for (i = 0; i < 2; i++)
- switch (info->mode[i]) {
-
- case JS_GR_MODE_GPP:
-
- if (js_gr_gpp_read_packet(info->io, (i << 1) + 4, data)) return -1;
-
- axes[i][0] = ((data[0] >> 15) & 1) - ((data[0] >> 16) & 1);
- axes[i][1] = ((data[0] >> 13) & 1) - ((data[0] >> 12) & 1);
-
- data[0] = ((data[0] >> 6) & 0x37) | (data[0] & 0x08) | ((data[0] << 1) & 0x40) |
- ((data[0] << 5) & 0x80) | ((data[0] << 8) & 0x300);
-
- buttons[i][0] = (data[0] & 0xfc) | ((data[0] >> 1) & 0x101) | ((data[0] << 1) & 0x202);
-
- break;
-
- case JS_GR_MODE_XT:
-
- if (js_gr_xt_read_packet(info->io, (i << 1) + 4, data)) return -1;
-
- axes[i][0] = (data[0] >> 2) & 0x3f;
- axes[i][1] = 63 - ((data[0] >> 8) & 0x3f);
- axes[i][2] = (data[1] >> 2) & 0x3f;
- axes[i][3] = (data[1] >> 8) & 0x3f;
- axes[i][4] = (data[2] >> 8) & 0x3f;
-
- axes[i][5] = ((data[2] >> 1) & 1) - ( data[2] & 1);
- axes[i][6] = ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1);
- axes[i][7] = ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1);
- axes[i][8] = ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1);
-
- buttons[i][0] = (data[3] >> 3) & 0x7ff;
-
- break;
-
- case JS_GR_MODE_BD:
-
- if (js_gr_xt_read_packet(info->io, (i << 1) + 4, data)) return -1;
-
- axes[i][0] = (data[0] >> 2) & 0x3f;
- axes[i][1] = 63 - ((data[0] >> 8) & 0x3f);
- axes[i][2] = (data[2] >> 8) & 0x3f;
-
- axes[i][3] = ((data[2] >> 1) & 1) - ( data[2] & 1);
- axes[i][4] = ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1);
-
- buttons[i][0] = ((data[3] >> 6) & 0x01) | ((data[3] >> 3) & 0x06)
- | ((data[3] >> 4) & 0x18);
-
- break;
-
- default:
- break;
-
- }
-
-
- return 0;
-}
-
-/*
- * js_gr_init_corr() initializes correction values of
- * GrIP joysticks.
- */
-
-static void __init js_gr_init_corr(int mode, struct js_corr *corr)
-{
- int i;
-
- switch (mode) {
-
- case JS_GR_MODE_GPP:
-
- for (i = 0; i < 2; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 29);
- corr[i].coef[3] = (1 << 29);
- }
-
- break;
-
- case JS_GR_MODE_XT:
-
- for (i = 0; i < 5; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 31 - 4;
- corr[i].coef[1] = 32 + 4;
- corr[i].coef[2] = (1 << 29) / (32 - 14);
- corr[i].coef[3] = (1 << 29) / (32 - 14);
- }
-
- for (i = 5; i < 9; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 29);
- corr[i].coef[3] = (1 << 29);
- }
-
- break;
-
- case JS_GR_MODE_BD:
-
- for (i = 0; i < 3; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 31 - 4;
- corr[i].coef[1] = 32 + 4;
- corr[i].coef[2] = (1 << 29) / (32 - 14);
- corr[i].coef[3] = (1 << 29) / (32 - 14);
- }
-
- for (i = 3; i < 5; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 29);
- corr[i].coef[3] = (1 << 29);
- }
-
- break;
-
- }
-}
-
-/*
- * js_gr_probe() probes for GrIP joysticks.
- */
-
-static struct js_port __init *js_gr_probe(int io, struct js_port *port)
-{
- struct js_gr_info info;
- char *names[] = { NULL, "Gravis GamePad Pro", "Gravis Xterminator", "Gravis Blackhawk Digital"};
- char axes[] = { 0, 2, 9, 5};
- char buttons[] = { 0, 10, 11, 5};
- unsigned int data[JS_GR_LENGTH_XT];
- int i;
-
- if (check_region(io, 1)) return port;
-
- info.mode[0] = info.mode[1] = 0;
-
- for (i = 0; i < 2; i++) {
- if (!js_gr_gpp_read_packet(io, (i << 1) + 4, data)) info.mode[i] = JS_GR_MODE_GPP;
- if (!js_gr_xt_read_packet(io, (i << 1) + 4, data)) {
- if ((data[3] & 7) == 7)
- info.mode[i] = JS_GR_MODE_XT;
- if ((data[3] & 7) == 0)
- info.mode[i] = JS_GR_MODE_BD;
- }
- }
-
- if (!info.mode[0] && !info.mode[1]) return port;
-
- info.io = io;
-
- request_region(io, 1, "joystick (gravis)");
- port = js_register_port(port, &info, 2, sizeof(struct js_gr_info), js_gr_read);
-
- for (i = 0; i < 2; i++)
- if (info.mode[i]) {
- printk(KERN_INFO "js%d: %s at %#x\n",
- js_register_device(port, i, axes[info.mode[i]], buttons[info.mode[i]],
- names[info.mode[i]], THIS_MODULE, NULL, NULL),
- names[info.mode[i]], io);
- js_gr_init_corr(info.mode[i], port->corr[i]);
- }
-
- return port;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_gr_init(void)
-#endif
-{
- int *p;
-
- for (p = js_gr_port_list; *p; p++) js_gr_port = js_gr_probe(*p, js_gr_port);
- if (js_gr_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-gravis: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_gr_info *info;
-
- while (js_gr_port) {
- for (i = 0; i < js_gr_port->ndevs; i++)
- if (js_gr_port->devs[i])
- js_unregister_device(js_gr_port->devs[i]);
- info = js_gr_port->info;
- release_region(info->io, 1);
- js_gr_port = js_unregister_port(js_gr_port);
- }
-}
-#endif
diff --git a/drivers/char/joystick/joy-lightning.c b/drivers/char/joystick/joy-lightning.c
deleted file mode 100644
index 26c18856a..000000000
--- a/drivers/char/joystick/joy-lightning.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * joy-lightning.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * PDPI Lightning 4 gamecards and analog joysticks connected
- * to them.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#define JS_L4_PORT 0x201
-#define JS_L4_SELECT_ANALOG 0xa4
-#define JS_L4_SELECT_DIGITAL 0xa5
-#define JS_L4_SELECT_SECONDARY 0xa6
-#define JS_L4_CMD_ID 0x80
-#define JS_L4_CMD_GETCAL 0x92
-#define JS_L4_CMD_SETCAL 0x93
-#define JS_L4_ID 0x04
-#define JS_L4_BUSY 0x01
-#define JS_L4_TIMEOUT 80 /* 80 us */
-
-static struct js_port* __initdata js_l4_port = NULL;
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_l4, "2-24i");
-
-static int __initdata js_l4[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 };
-
-#include "joy-analog.h"
-
-struct js_l4_info {
- int port;
- struct js_an_info an;
-};
-
-/*
- * js_l4_wait_ready() waits for the L4 to become ready.
- */
-
-static int js_l4_wait_ready(void)
-{
- unsigned int t;
- t = JS_L4_TIMEOUT;
- while ((inb(JS_L4_PORT) & JS_L4_BUSY) && t > 0) t--;
- return -(t<=0);
-}
-
-/*
- * js_l4_read() reads data from the Lightning 4.
- */
-
-static int js_l4_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_l4_info *info = xinfo;
- int i;
- unsigned char status;
-
- outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
- outb(JS_L4_SELECT_DIGITAL + (info->port >> 2), JS_L4_PORT);
-
- if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1;
- outb(info->port & 3, JS_L4_PORT);
-
- if (js_l4_wait_ready()) return -1;
- status = inb(JS_L4_PORT);
-
- for (i = 0; i < 4; i++)
- if (status & (1 << i)) {
- if (js_l4_wait_ready()) return -1;
- info->an.axes[i] = inb(JS_L4_PORT);
- }
-
- if (status & 0x10) {
- if (js_l4_wait_ready()) return -1;
- info->an.buttons = inb(JS_L4_PORT);
- }
-
- js_an_decode(&info->an, axes, buttons);
-
- return 0;
-}
-
-/*
- * js_l4_getcal() reads the L4 with calibration values.
- */
-
-static int js_l4_getcal(int port, int *cal)
-{
- int i;
-
- outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
- outb(JS_L4_SELECT_DIGITAL + (port >> 2), JS_L4_PORT);
-
- if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1;
- outb(JS_L4_CMD_GETCAL, JS_L4_PORT);
-
- if (js_l4_wait_ready()) return -1;
- if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + (port >> 2)) return -1;
-
- if (js_l4_wait_ready()) return -1;
- outb(port & 3, JS_L4_PORT);
-
- for (i = 0; i < 4; i++) {
- if (js_l4_wait_ready()) return -1;
- cal[i] = inb(JS_L4_PORT);
- }
-
- return 0;
-}
-
-/*
- * js_l4_setcal() programs the L4 with calibration values.
- */
-
-static int js_l4_setcal(int port, int *cal)
-{
- int i;
-
- outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
- outb(JS_L4_SELECT_DIGITAL + (port >> 2), JS_L4_PORT);
-
- if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1;
- outb(JS_L4_CMD_SETCAL, JS_L4_PORT);
-
- if (js_l4_wait_ready()) return -1;
- if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + (port >> 2)) return -1;
-
- if (js_l4_wait_ready()) return -1;
- outb(port & 3, JS_L4_PORT);
-
- for (i = 0; i < 4; i++) {
- if (js_l4_wait_ready()) return -1;
- outb(cal[i], JS_L4_PORT);
- }
-
- return 0;
-}
-
-/*
- * js_l4_calibrate() calibrates the L4 for the attached device, so
- * that the device's resistance fits into the L4's 8-bit range.
- */
-
-static void js_l4_calibrate(struct js_l4_info *info)
-{
- int i;
- int cal[4];
- int axes[4];
- int t;
-
- js_l4_getcal(info->port, cal);
-
- for (i = 0; i < 4; i++)
- axes[i] = info->an.axes[i];
-
- if ((info->an.extensions & JS_AN_BUTTON_PXY_X) && !(info->an.extensions & JS_AN_BUTTON_PXY_U))
- axes[2] >>= 1; /* Pad button X */
-
- if ((info->an.extensions & JS_AN_BUTTON_PXY_Y) && !(info->an.extensions & JS_AN_BUTTON_PXY_V))
- axes[3] >>= 1; /* Pad button Y */
-
- if (info->an.extensions & JS_AN_HAT_FCS)
- axes[3] >>= 1; /* FCS hat */
-
- if (((info->an.mask[0] & 0xb) == 0xb) || ((info->an.mask[1] & 0xb) == 0xb))
- axes[3] = (axes[0] + axes[1]) >> 1; /* Throttle */
-
- for (i = 0; i < 4; i++) {
- t = (axes[i] * cal[i]) / 100;
- if (t > 255) t = 255;
- info->an.axes[i] = (info->an.axes[i] * cal[i]) / t;
- cal[i] = t;
- }
-
- js_l4_setcal(info->port, cal);
-}
-
-/*
- * js_l4_probe() probes for joysticks on the L4 cards.
- */
-
-static struct js_port __init *js_l4_probe(unsigned char *cards, int l4port, int mask0, int mask1, struct js_port *port)
-{
- struct js_l4_info iniinfo;
- struct js_l4_info *info = &iniinfo;
- int cal[4] = {255,255,255,255};
- int i, numdev;
- unsigned char u;
-
- if (l4port < 0) return port;
- if (!cards[(l4port >> 2)]) return port;
-
- memset(info, 0, sizeof(struct js_l4_info));
- info->port = l4port;
-
- if (cards[l4port >> 2] > 0x28) js_l4_setcal(info->port, cal);
- if (js_l4_read(info, NULL, NULL)) return port;
-
- for (i = u = 0; i < 4; i++) if (info->an.axes[i] < 253) u |= 1 << i;
-
- if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0)
- return port;
-
- port = js_register_port(port, info, numdev, sizeof(struct js_l4_info), js_l4_read);
-
- info = port->info;
-
- for (i = 0; i < numdev; i++)
- printk(KERN_INFO "js%d: %s on L4 port %d\n",
- js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
- js_an_name(i, &info->an), THIS_MODULE, NULL, NULL),
- js_an_name(i, &info->an), info->port);
-
- js_l4_calibrate(info);
- js_l4_read(info, port->axes, port->buttons);
- js_an_init_corr(&info->an, port->axes, port->corr, 0);
-
- return port;
-}
-
-/*
- * js_l4_card_probe() probes for presence of the L4 card(s).
- */
-
-static void __init js_l4_card_probe(unsigned char *cards)
-{
- int i;
- unsigned char rev = 0;
-
- if (check_region(JS_L4_PORT, 1)) return;
-
- for (i = 0; i < 2; i++) {
-
- outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
- outb(JS_L4_SELECT_DIGITAL + i, JS_L4_PORT); /* Select card 0-1 */
-
- if (inb(JS_L4_PORT) & JS_L4_BUSY) continue;
- outb(JS_L4_CMD_ID, JS_L4_PORT); /* Get card ID & rev */
-
- if (js_l4_wait_ready()) continue;
- if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + i) continue;
-
- if (js_l4_wait_ready()) continue;
- if (inb(JS_L4_PORT) != JS_L4_ID) continue;
-
- if (js_l4_wait_ready()) continue;
- rev = inb(JS_L4_PORT);
-
- cards[i] = rev;
-
- printk(KERN_INFO "js: PDPI Lightning 4 %s card (ports %d-%d) firmware v%d.%d at %#x\n",
- i ? "secondary" : "primary", (i << 2), (i << 2) + 3, rev >> 4, rev & 0xf, JS_L4_PORT);
- }
-
-}
-
-#ifndef MODULE
-int __init js_l4_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(24);
- for (i = 0; i <= ints[0] && i < 24; i++) js_l4[i] = ints[i+1];
- return 1;
-}
-__setup("js_l4=", js_l4_setup);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_l4_init(void)
-#endif
-{
- int i;
- unsigned char cards[2] = {0, 0};
-
- js_l4_card_probe(cards);
-
- if (js_l4[0] >= 0) {
- for (i = 0; (js_l4[i*3] >= 0) && i < 8; i++)
- js_l4_port = js_l4_probe(cards, js_l4[i*3], js_l4[i*3+1], js_l4[i*3+2], js_l4_port);
- } else {
- for (i = 0; i < 8; i++)
- js_l4_port = js_l4_probe(cards, i, 0, 0, js_l4_port);
- }
-
- if (!js_l4_port) {
-#ifdef MODULE
- printk(KERN_WARNING "joy-lightning: no joysticks found\n");
-#endif
- return -ENODEV;
- }
-
- request_region(JS_L4_PORT, 1, "joystick (lightning)");
-
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- int cal[4] = {59, 59, 59, 59};
- struct js_l4_info *info;
-
- while (js_l4_port) {
- for (i = 0; i < js_l4_port->ndevs; i++)
- if (js_l4_port->devs[i])
- js_unregister_device(js_l4_port->devs[i]);
- info = js_l4_port->info;
- js_l4_setcal(info->port, cal);
- js_l4_port = js_unregister_port(js_l4_port);
- }
- outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
- release_region(JS_L4_PORT, 1);
-}
-#endif
diff --git a/drivers/char/joystick/joy-logitech.c b/drivers/char/joystick/joy-logitech.c
deleted file mode 100644
index 6044cbfb0..000000000
--- a/drivers/char/joystick/joy-logitech.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * joy-logitech.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * Logitech ADI joystick family.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/malloc.h>
-#include <linux/init.h>
-
-/*
- * Times array sizes, flags, ids.
- */
-
-#undef JS_LT_DEBUG
-
-#define JS_LT_MAX_START 400 /* Trigger to packet timeout [400us] */
-
-#define JS_LT_MAX_LENGTH 256
-#define JS_LT_MIN_LENGTH 8
-#define JS_LT_MIN_LEN_LENGTH 10
-#define JS_LT_MIN_ID_LENGTH 66
-#define JS_LT_MAX_NAME_LENGTH 16
-
-#define JS_LT_INIT_DELAY 10 /* Delay after init packet [10ms] */
-#define JS_LT_DATA_DELAY 4 /* Delay after data packet [4ms] */
-
-#define JS_LT_FLAG_HAT 0x04
-#define JS_LT_FLAG_10BIT 0x08
-
-#define JS_LT_ID_WMED 0x00
-#define JS_LT_ID_TPD 0x01
-#define JS_LT_ID_WMI 0x04
-#define JS_LT_ID_WGP 0x06
-#define JS_LT_ID_WM3D 0x07
-#define JS_LT_ID_WGPE 0x08
-
-#define JS_LT_BUG_BUTTONS 0x01
-#define JS_LT_BUG_LONGID 0x02
-#define JS_LT_BUG_LONGDATA 0x04
-#define JS_LT_BUG_IGNTRIG 0x08
-
-/*
- * Port probing variables.
- */
-
-static int js_lt_port_list[] __initdata = { 0x201, 0 };
-static struct js_port* js_lt_port __initdata = NULL;
-
-/*
- * Device names.
- */
-
-#define JS_LT_MAX_ID 10
-
-static char *js_lt_names[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2",
- "WingMan Interceptor", "WingMan Formula", "WingMan GamePad",
- "WingMan Extreme Digital 3D", "WingMan GamePad Extreme",
- "WingMan GamePad USB", "Unknown Device %#x"};
-
-/*
- * Hat to axis conversion arrays.
- */
-
-static struct {
- int x;
- int y;
-} js_lt_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-/*
- * Per-port information.
- */
-
-struct js_lt_info {
- int io;
- int length[2];
- int ret[2];
- int idx[2];
- unsigned char id[2];
- char buttons[2];
- char axes10[2];
- char axes8[2];
- char pad[2];
- char hats[2];
- char name[2][JS_LT_MAX_NAME_LENGTH];
- unsigned char data[2][JS_LT_MAX_LENGTH];
- char bugs[2];
-};
-
-/*
- * js_lt_read_packet() reads a Logitech ADI packet.
- */
-
-static void js_lt_read_packet(struct js_lt_info *info)
-{
- unsigned char u, v, w, x, z;
- int t[2], s[2], p[2], i;
- unsigned long flags;
-
- for (i = 0; i < 2; i++) {
- info->ret[i] = -1;
- p[i] = t[i] = JS_LT_MAX_START;
- s[i] = 0;
- }
-
- __save_flags(flags);
- __cli();
-
- outb(0xff, info->io);
- v = z = inb(info->io);
-
- do {
- u = v;
- w = u ^ (v = x = inb(info->io));
- for (i = 0; i < 2; i++, w >>= 2, x >>= 2) {
- t[i]--;
- if ((w & 0x30) && s[i]) {
- if ((w & 0x30) < 0x30 && info->ret[i] < JS_LT_MAX_LENGTH && t[i] > 0) {
- info->data[i][++info->ret[i]] = w;
- p[i] = t[i] = (p[i] - t[i]) << 1;
- } else t[i] = 0;
- } else if (!(x & 0x30)) s[i] = 1;
- }
- } while (t[0] > 0 || t[1] > 0);
-
- __restore_flags(flags);
-
- for (i = 0; i < 2; i++, z >>= 2)
- if ((z & 0x30) && info->ret[i] > 0)
- info->bugs[i] |= JS_LT_BUG_BUTTONS;
-
-#ifdef JS_LT_DEBUG
- printk(KERN_DEBUG "joy-logitech: read %d %d bits\n", info->ret[0], info->ret[1]);
- printk(KERN_DEBUG "joy-logitech: stream0:");
- for (i = 0; i <= info->ret[0]; i++) printk("%d", (info->data[0][i] >> 5) & 1);
- printk("\n");
- printk(KERN_DEBUG "joy-logitech: stream1:");
- for (i = 0; i <= info->ret[1]; i++) printk("%d", (info->data[1][i] >> 5) & 1);
- printk("\n");
-#endif
-
- return;
-}
-
-/*
- * js_lt_move_bits() detects a possible 2-stream mode, and moves
- * the bits accordingly.
- */
-
-static void js_lt_move_bits(struct js_lt_info *info, int length)
-{
- int i;
-
- info->idx[0] = info->idx[1] = 0;
-
- if (info->ret[0] <= 0 || info->ret[1] <= 0) return;
- if (info->data[0][0] & 0x20 || ~info->data[1][0] & 0x20) return;
-
- for (i = 1; i <= info->ret[1]; i++)
- info->data[0][((length - 1) >> 1) + i + 1] = info->data[1][i];
-
- info->ret[0] += info->ret[1];
- info->ret[1] = -1;
-}
-
-/*
- * js_lt_get_bits() gathers bits from the data packet.
- */
-
-static inline int js_lt_get_bits(struct js_lt_info *info, int device, int count)
-{
- int bits = 0;
- int i;
- if ((info->idx[device] += count) > info->ret[device]) return 0;
- for (i = 0; i < count; i++) bits |= ((info->data[device][info->idx[device] - i] >> 5) & 1) << i;
- return bits;
-}
-
-/*
- * js_lt_read() reads and analyzes Logitech joystick data.
- */
-
-static int js_lt_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_lt_info *info = xinfo;
- int i, j, k, l, t;
- int ret = 0;
-
- js_lt_read_packet(info);
- js_lt_move_bits(info, info->length[0]);
-
- for (i = 0; i < 2; i++) {
-
- if (!info->length[i]) continue;
-
- if (info->length[i] > info->ret[i] ||
- info->id[i] != (js_lt_get_bits(info, i, 4) | (js_lt_get_bits(info, i, 4) << 4))) {
- ret = -1;
- continue;
- }
-
- if (info->length[i] < info->ret[i])
- info->bugs[i] |= JS_LT_BUG_LONGDATA;
-
- k = l = 0;
-
- for (j = 0; j < info->axes10[i]; j++)
- axes[i][k++] = js_lt_get_bits(info, i, 10);
-
- for (j = 0; j < info->axes8[i]; j++)
- axes[i][k++] = js_lt_get_bits(info, i, 8);
-
- for (j = 0; j <= (info->buttons[i] - 1) >> 5; j++) buttons[i][j] = 0;
-
- for (j = 0; j < info->buttons[i] && j < 63; j++) {
- if (j == info->pad[i]) {
- t = js_lt_get_bits(info, i, 4);
- axes[i][k++] = ((t >> 2) & 1) - ( t & 1);
- axes[i][k++] = ((t >> 1) & 1) - ((t >> 3) & 1);
- }
- buttons[i][l >> 5] |= js_lt_get_bits(info, i, 1) << (l & 0x1f);
- l++;
- }
-
- for (j = 0; j < info->hats[i]; j++) {
- if((t = js_lt_get_bits(info, i, 4)) > 8) {
- if (t != 15) ret = -1; /* Hat press */
- t = 0;
- }
- axes[i][k++] = js_lt_hat_to_axis[t].x;
- axes[i][k++] = js_lt_hat_to_axis[t].y;
- }
-
- for (j = 63; j < info->buttons[i]; j++) {
- buttons[i][l >> 5] |= js_lt_get_bits(info, i, 1) << (l & 0x1f);
- l++;
- }
- }
-
- return ret;
-}
-
-/*
- * js_lt_init_digital() sends a trigger & delay sequence
- * to reset and initialize a Logitech joystick into digital mode.
- */
-
-static void __init js_lt_init_digital(int io)
-{
- int seq[] = { 3, 2, 3, 10, 6, 11, 7, 9, 11, 0 };
- int i;
-
- for (i = 0; seq[i]; i++) {
- outb(0xff,io);
- mdelay(seq[i]);
- }
-}
-
-/*
- * js_lt_init_corr() initializes the correction values for
- * Logitech joysticks.
- */
-
-static void __init js_lt_init_corr(int id, int naxes10, int naxes8, int naxes1, int *axes, struct js_corr *corr)
-{
- int j;
-
- if (id == JS_LT_ID_WMED) axes[2] = 128; /* Throttle fixup */
- if (id == JS_LT_ID_WMI) axes[2] = 512;
- if (id == JS_LT_ID_WM3D) axes[3] = 128;
-
- if (id == JS_LT_ID_WGPE) { /* Tilt fixup */
- axes[0] = 512;
- axes[1] = 512;
- }
-
- for (j = 0; j < naxes10; j++) {
- corr[j].type = JS_CORR_BROKEN;
- corr[j].prec = 2;
- corr[j].coef[0] = axes[j] - 16;
- corr[j].coef[1] = axes[j] + 16;
- corr[j].coef[2] = (1 << 29) / (256 - 32);
- corr[j].coef[3] = (1 << 29) / (256 - 32);
- }
-
- for (; j < naxes8 + naxes10; j++) {
- corr[j].type = JS_CORR_BROKEN;
- corr[j].prec = 1;
- corr[j].coef[0] = axes[j] - 2;
- corr[j].coef[1] = axes[j] + 2;
- corr[j].coef[2] = (1 << 29) / (64 - 16);
- corr[j].coef[3] = (1 << 29) / (64 - 16);
- }
-
- for (; j < naxes1 + naxes8 + naxes10; j++) {
- corr[j].type = JS_CORR_BROKEN;
- corr[j].prec = 0;
- corr[j].coef[0] = 0;
- corr[j].coef[1] = 0;
- corr[j].coef[2] = (1 << 29);
- corr[j].coef[3] = (1 << 29);
- }
-}
-
-/*
- * js_lt_probe() probes for Logitech type joysticks.
- */
-
-static struct js_port __init *js_lt_probe(int io, struct js_port *port)
-{
- struct js_lt_info iniinfo;
- struct js_lt_info *info = &iniinfo;
- char name[32];
- int i, j, t;
-
- if (check_region(io, 1)) return port;
-
- js_lt_init_digital(io);
-
- memset(info, 0, sizeof(struct js_lt_info));
-
- info->length[0] = info->length[1] = JS_LT_MAX_LENGTH;
-
- info->io = io;
- js_lt_read_packet(info);
-
- if (info->ret[0] >= JS_LT_MIN_LEN_LENGTH)
- js_lt_move_bits(info, js_lt_get_bits(info, 0, 10));
-
- info->length[0] = info->length[1] = 0;
-
- for (i = 0; i < 2; i++) {
-
- if (info->ret[i] < JS_LT_MIN_ID_LENGTH) continue; /* Minimum ID packet length */
-
- if (info->ret[i] < (t = js_lt_get_bits(info, i, 10))) {
- printk(KERN_WARNING "joy-logitech: Short ID packet: reported: %d != read: %d\n",
- t, info->ret[i]);
- continue;
- }
-
- if (info->ret[i] > t)
- info->bugs[i] |= JS_LT_BUG_LONGID;
-
-#ifdef JS_LT_DEBUG
- printk(KERN_DEBUG "joy-logitech: id %d length %d", i, t);
-#endif
-
- info->id[i] = js_lt_get_bits(info, i, 4) | (js_lt_get_bits(info, i, 4) << 4);
-
- if ((t = js_lt_get_bits(info, i, 4)) & JS_LT_FLAG_HAT) info->hats[i]++;
-
-#ifdef JS_LT_DEBUG
- printk(KERN_DEBUG "joy-logitech: id %d flags %d", i, t);
-#endif
-
- if ((info->length[i] = js_lt_get_bits(info, i, 10)) >= JS_LT_MAX_LENGTH) {
- printk(KERN_WARNING "joy-logitech: Expected packet length too long (%d).\n",
- info->length[i]);
- continue;
- }
-
- if (info->length[i] < JS_LT_MIN_LENGTH) {
- printk(KERN_WARNING "joy-logitech: Expected packet length too short (%d).\n",
- info->length[i]);
- continue;
- }
-
- info->axes8[i] = js_lt_get_bits(info, i, 4);
- info->buttons[i] = js_lt_get_bits(info, i, 6);
-
- if (js_lt_get_bits(info, i, 6) != 8 && info->hats[i]) {
- printk(KERN_WARNING "joy-logitech: Other than 8-dir POVs not supported yet.\n");
- continue;
- }
-
- info->buttons[i] += js_lt_get_bits(info, i, 6);
- info->hats[i] += js_lt_get_bits(info, i, 4);
-
- j = js_lt_get_bits(info, i, 4);
-
- if (t & JS_LT_FLAG_10BIT) {
- info->axes10[i] = info->axes8[i] - j;
- info->axes8[i] = j;
- }
-
- t = js_lt_get_bits(info, i, 4);
-
- for (j = 0; j < t; j++)
- info->name[i][j] = js_lt_get_bits(info, i, 8);
- info->name[i][j] = 0;
-
- switch (info->id[i]) {
- case JS_LT_ID_TPD:
- info->pad[i] = 4;
- info->buttons[i] -= 4;
- break;
- case JS_LT_ID_WGP:
- info->pad[i] = 0;
- info->buttons[i] -= 4;
- break;
- default:
- info->pad[i] = -1;
- break;
- }
-
- if (info->length[i] !=
- (t = 8 + info->buttons[i] + info->axes10[i] * 10 + info->axes8[i] * 8 +
- info->hats[i] * 4 + (info->pad[i] != -1) * 4)) {
- printk(KERN_WARNING "js%d: Expected lenght %d != data length %d\n", i, t, info->length[i]);
- }
-
- }
-
- if (!info->length[0] && !info->length[1])
- return port;
-
- request_region(io, 1, "joystick (logitech)");
-
- port = js_register_port(port, info, 2, sizeof(struct js_lt_info), js_lt_read);
- info = port->info;
-
- for (i = 0; i < 2; i++)
- if (info->length[i] > 0) {
- sprintf(name, info->id[i] < JS_LT_MAX_ID ?
- js_lt_names[info->id[i]] : js_lt_names[JS_LT_MAX_ID], info->id[i]);
- printk(KERN_INFO "js%d: %s [%s] at %#x\n",
- js_register_device(port, i,
- info->axes10[i] + info->axes8[i] + ((info->hats[i] + (info->pad[i] >= 0)) << 1),
- info->buttons[i], name, THIS_MODULE, NULL, NULL), name, info->name[i], io);
- }
-
- mdelay(JS_LT_INIT_DELAY);
- if (js_lt_read(info, port->axes, port->buttons)) {
- if (info->ret[0] < 1) info->bugs[0] |= JS_LT_BUG_IGNTRIG;
- if (info->ret[1] < 1) info->bugs[1] |= JS_LT_BUG_IGNTRIG;
- mdelay(JS_LT_DATA_DELAY);
- js_lt_read(info, port->axes, port->buttons);
- }
-
- for (i = 0; i < 2; i++)
- if (info->length[i] > 0) {
-#ifdef JS_LT_DEBUG
- printk(KERN_DEBUG "js%d: length %d ret %d id %d buttons %d axes10 %d axes8 %d "
- "pad %d hats %d name %s explen %d\n",
- i, info->length[i], info->ret[i], info->id[i],
- info->buttons[i], info->axes10[i], info->axes8[i],
- info->pad[i], info->hats[i], info->name[i],
- 8 + info->buttons[i] + info->axes10[i] * 10 + info->axes8[i] * 8 +
- info->hats[i] * 4 + (info->pad[i] != -1) * 4);
-#endif
- if (info->bugs[i]) {
- printk(KERN_WARNING "js%d: Firmware bugs detected:%s%s%s%s\n", i,
- info->bugs[i] & JS_LT_BUG_BUTTONS ? " init_buttons" : "",
- info->bugs[i] & JS_LT_BUG_LONGID ? " long_id" : "",
- info->bugs[i] & JS_LT_BUG_LONGDATA ? " long_data" : "",
- info->bugs[i] & JS_LT_BUG_IGNTRIG ? " ignore_trigger" : "");
- }
- js_lt_init_corr(info->id[i], info->axes10[i], info->axes8[i],
- ((info->pad[i] >= 0) + info->hats[i]) << 1, port->axes[i], port->corr[i]);
- }
-
- return port;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_lt_init(void)
-#endif
-{
- int *p;
-
- for (p = js_lt_port_list; *p; p++) js_lt_port = js_lt_probe(*p, js_lt_port);
- if (js_lt_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-logitech: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_lt_info *info;
-
- while (js_lt_port) {
- for (i = 0; i < js_lt_port->ndevs; i++)
- if (js_lt_port->devs[i])
- js_unregister_device(js_lt_port->devs[i]);
- info = js_lt_port->info;
- release_region(info->io, 1);
- js_lt_port = js_unregister_port(js_lt_port);
- }
-}
-#endif
diff --git a/drivers/char/joystick/joy-magellan.c b/drivers/char/joystick/joy-magellan.c
deleted file mode 100644
index cb14646e8..000000000
--- a/drivers/char/joystick/joy-magellan.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * joy-magellan.c Version 0.1
- *
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * the Magellan and Space Mouse 6dof controllers.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-/*
- * Constants.
- */
-
-#define N_JOYSTICK_MAG 14
-#define JS_MAG_MAX_LENGTH 64
-
-/*
- * List of Magellans.
- */
-
-static struct js_port* js_mag_port = NULL;
-
-/*
- * Per-Magellan data.
- */
-
-struct js_mag_info {
- struct tty_struct* tty;
- struct js_port* port;
- int idx;
- unsigned char data[JS_MAG_MAX_LENGTH];
- unsigned char name[JS_MAG_MAX_LENGTH];
- char ack;
- char used;
-};
-
-/*
- * js_mag_crunch_nibbles() verifies that the bytes sent from the Magellan
- * have correct upper nibbles for the lower ones, if not, the packet will
- * be thrown away. It also strips these upper halves to simplify further
- * processing.
- */
-
-static int js_mag_crunch_nibbles(unsigned char *data, int count)
-{
- static unsigned char nibbles[16] = "0AB3D56GH9:K<MN?";
-
- do {
- if (data[count] == nibbles[data[count] & 0xf])
- data[count] = data[count] & 0xf;
- else
- return -1;
- } while (--count);
-
- return 0;
-}
-
-/*
- * js_mag_process_packet() decodes packets the driver receives from the
- * Magellan. It updates the data accordingly, and sets an ACK flag
- * to the type of last packet received, if received OK.
- */
-
-static void js_mag_process_packet(struct js_mag_info* info)
-{
- int i;
-
- if (!info->idx) return;
-
- switch (info->data[0]) {
-
- case 'd': /* Axis data */
- if (info->idx != 25) return;
- if (js_mag_crunch_nibbles(info->data, 24)) return;
- if (!info->port->devs[0]) return;
- for (i = 0; i < 6; i++) {
- info->port->axes[0][i] =
- ( info->data[(i << 2) + 1] << 12 | info->data[(i << 2) + 2] << 8 |
- info->data[(i << 2) + 3] << 4 | info->data[(i << 2) + 4] )
- - 32768;
- }
- break;
-
- case 'e': /* Error packet */
- if (info->idx != 4) return;
- if (js_mag_crunch_nibbles(info->data, 3)) return;
- switch (info->data[1]) {
- case 1:
- printk(KERN_ERR "joy-magellan: Received command error packet. Failing command byte: %c\n",
- info->data[2] | (info->data[3] << 4));
- break;
- case 2:
- printk(KERN_ERR "joy-magellan: Received framing error packet.\n");
- break;
- default:
- printk(KERN_ERR "joy-magellan: Received unknown error packet.\n");
- }
- break;
-
- case 'k': /* Button data */
- if (info->idx != 4) return;
- if (js_mag_crunch_nibbles(info->data, 3)) return;
- if (!info->port->devs[0]) return;
- info->port->buttons[0][0] = (info->data[1] << 1) | (info->data[2] << 5) | info->data[3];
- break;
-
- case 'm': /* Mode */
- if (info->idx != 2) return;
- if (js_mag_crunch_nibbles(info->data, 1)) return;
- break;
-
- case 'n': /* Null radius */
- if (info->idx != 2) return;
- if (js_mag_crunch_nibbles(info->data, 1)) return;
- break;
-
- case 'p': /* Data rate */
- if (info->idx != 3) return;
- if (js_mag_crunch_nibbles(info->data, 2)) return;
- break;
-
- case 'q': /* Sensitivity */
- if (info->idx != 3) return;
- if (js_mag_crunch_nibbles(info->data, 2)) return;
- break;
-
- case 'v': /* Version string */
- info->data[info->idx] = 0;
- for (i = 1; i < info->idx && info->data[i] == ' '; i++);
- memcpy(info->name, info->data + i, info->idx - i);
- break;
-
- case 'z': /* Zero position */
- break;
-
- default:
- printk("joy-magellan: Unknown packet %d length %d:", info->data[0], info->idx);
- for (i = 0; i < info->idx; i++) printk(" %02x", info->data[i]);
- printk("\n");
- return;
- }
-
- info->ack = info->data[0];
-}
-
-/*
- * js_mag_command() sends a command to the Magellan, and waits for
- * acknowledge.
- */
-
-static int js_mag_command(struct js_mag_info *info, char *command, int timeout)
-{
- info->ack = 0;
- if (info->tty->driver.write(info->tty, 0, command, strlen(command)) != strlen(command)) return -1;
- while (!info->ack && timeout--) mdelay(1);
- return -(info->ack != command[0]);
-}
-
-/*
- * js_mag_setup() initializes the Magellan to sane state. Also works as
- * a probe for Magellan existence.
- */
-
-static int js_mag_setup(struct js_mag_info *info)
-{
-
- if (js_mag_command(info, "vQ\r", 800)) /* Read version */
- return -1;
- if (js_mag_command(info, "m3\r", 50)) /* Set full 3d mode */
- return -1;
- if (js_mag_command(info, "pBB\r", 50)) /* Set 16 reports/second (max) */
- return -1;
- if (js_mag_command(info, "z\r", 50)) /* Set zero position */
- return -1;
-
- return 0;
-}
-
-/*
- * js_mag_read() updates the axis and button data upon startup.
- */
-
-static int js_mag_read(struct js_mag_info *info)
-{
- memset(info->port->axes[0],0, sizeof(int) * 6); /* Axes are 0 after zero postition cmd */
-
- if (js_mag_command(info, "kQ\r", 50)) /* Read buttons */
- return -1;
-
- return 0;
-}
-
-/*
- * js_mag_open() is a callback from the joystick device open routine.
- */
-
-static int js_mag_open(struct js_dev *jd)
-{
- struct js_mag_info *info = jd->port->info;
- info->used++;
- return 0;
-}
-
-/*
- * js_mag_close() is a callback from the joystick device release routine.
- */
-
-static int js_mag_close(struct js_dev *jd)
-{
- struct js_mag_info *info = jd->port->info;
- if (!--info->used) {
- js_unregister_device(jd->port->devs[0]);
- js_mag_port = js_unregister_port(jd->port);
- }
- return 0;
-}
-
-/*
- * js_mag_init_corr() initializes the correction values for the Magellan.
- * It asumes gain setting of 0, question is, what we should do for higher
- * gain settings ...
- */
-
-static void js_mag_init_corr(struct js_corr **corr)
-{
- int i;
-
- for (i = 0; i < 6; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = 0;
- corr[0][i].coef[0] = 0;
- corr[0][i].coef[1] = 0;
- corr[0][i].coef[2] = (1 << 29) / 256;
- corr[0][i].coef[3] = (1 << 29) / 256;
- }
-}
-
-/*
- * js_mag_ldisc_open() is the routine that is called upon setting our line
- * discipline on a tty. It looks for the Magellan, and if found, registers
- * it as a joystick device.
- */
-
-static int js_mag_ldisc_open(struct tty_struct *tty)
-{
- struct js_mag_info iniinfo;
- struct js_mag_info *info = &iniinfo;
-
- info->tty = tty;
- info->idx = 0;
- info->used = 1;
-
- js_mag_port = js_register_port(js_mag_port, info, 1, sizeof(struct js_mag_info), NULL);
-
- info = js_mag_port->info;
- info->port = js_mag_port;
- tty->disc_data = info;
-
- if (js_mag_setup(info)) {
- js_mag_port = js_unregister_port(info->port);
- return -ENODEV;
- }
-
- printk(KERN_INFO "js%d: Magellan [%s] on %s%d\n",
- js_register_device(js_mag_port, 0, 6, 9, "Magellan", THIS_MODULE, js_mag_open, js_mag_close),
- info->name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
-
-
- js_mag_read(info);
- js_mag_init_corr(js_mag_port->corr);
-
- MOD_INC_USE_COUNT;
-
- return 0;
-}
-
-/*
- * js_mag_ldisc_close() is the opposite of js_mag_ldisc_open()
- */
-
-static void js_mag_ldisc_close(struct tty_struct *tty)
-{
- struct js_mag_info* info = (struct js_mag_info*) tty->disc_data;
- if (!--info->used) {
- js_unregister_device(info->port->devs[0]);
- js_mag_port = js_unregister_port(info->port);
- }
- MOD_DEC_USE_COUNT;
-}
-
-/*
- * js_mag_ldisc_receive() 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 js_mag_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
-{
- struct js_mag_info* info = (struct js_mag_info*) tty->disc_data;
- int i;
-
- for (i = 0; i < count; i++)
- if (cp[i] == '\r') {
- js_mag_process_packet(info);
- info->idx = 0;
- } else {
- if (info->idx < JS_MAG_MAX_LENGTH)
- info->data[info->idx++] = cp[i];
- }
-}
-
-/*
- * js_mag_ldisc_room() reports how much room we do have for receiving data.
- * Although we in fact have infinite room, we need to specify some value
- * here, so why not the size of our packet buffer. It's big anyway.
- */
-
-static int js_mag_ldisc_room(struct tty_struct *tty)
-{
- return JS_MAG_MAX_LENGTH;
-}
-
-/*
- * The line discipline structure.
- */
-
-static struct tty_ldisc js_mag_ldisc = {
- magic: TTY_LDISC_MAGIC,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
- name: "magellan",
-#endif
- open: js_mag_ldisc_open,
- close: js_mag_ldisc_close,
- receive_buf: js_mag_ldisc_receive,
- receive_room: js_mag_ldisc_room,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_mag_init(void)
-#endif
-{
- if (tty_register_ldisc(N_JOYSTICK_MAG, &js_mag_ldisc)) {
- printk(KERN_ERR "joy-magellan: Error registering line discipline.\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- tty_register_ldisc(N_JOYSTICK_MAG, NULL);
-}
-#endif
diff --git a/drivers/char/joystick/joy-pci.c b/drivers/char/joystick/joy-pci.c
deleted file mode 100644
index fbf9125e5..000000000
--- a/drivers/char/joystick/joy-pci.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * joy-pci.c Version 0.4.0
- *
- * Copyright (c) 1999 Raymond Ingles
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting the
- * gameports on Trident 4DWave and Aureal Vortex soundcards, and
- * analog joysticks connected to them.
- */
-
-/*
- * 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 <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
-#include <linux/init.h>
-
-MODULE_AUTHOR("Raymond Ingles <sorceror@tir.com>");
-MODULE_PARM(js_pci, "3-32i");
-
-#define NUM_CARDS 8
-static int js_pci[NUM_CARDS * 4] __initdata = { -1,0,0,0,-1,0,0,0,-1,0,0,0,-1,0,0,0,
- -1,0,0,0,-1,0,0,0,-1,0,0,0,-1,0,0,0 };
-
-static struct js_port * js_pci_port __initdata = NULL;
-
-#include "joy-analog.h"
-
-struct js_pci_info;
-typedef void (*js_pci_func)(struct js_pci_info *);
-
-struct js_pci_data {
- int vendor; /* PCI Vendor ID */
- int model; /* PCI Model ID */
- int size; /* Memory / IO region size */
- int lcr; /* Aureal Legacy Control Register */
- int gcr; /* Gameport control register */
- int buttons; /* Buttons location */
- int axes; /* Axes start */
- int axsize; /* Axis field size */
- int axmax; /* Axis field max value */
- js_pci_func init;
- js_pci_func cleanup;
- char *name;
-};
-
-struct js_pci_info {
- unsigned char *base;
- struct pci_dev *pci_p;
- __u32 lcr;
- struct js_pci_data *data;
- struct js_an_info an;
-};
-
-/*
- * js_pci_*_init() sets the info->base field, disables legacy gameports,
- * and enables the enhanced ones.
- */
-
-static void js_pci_4dwave_init(struct js_pci_info *info)
-{
- info->base = ioremap(BASE_ADDRESS(info->pci_p, 1), info->data->size);
- pci_read_config_word(info->pci_p, info->data->lcr, (unsigned short *)&info->lcr);
- pci_write_config_word(info->pci_p, info->data->lcr, info->lcr & ~0x20);
- writeb(0x80, info->base + info->data->gcr);
-}
-
-static void js_pci_vortex_init(struct js_pci_info *info)
-{
- info->base = ioremap(BASE_ADDRESS(info->pci_p, 0), info->data->size);
- info->lcr = readl(info->base + info->data->lcr);
- writel(info->lcr & ~0x8, info->base + info->data->lcr);
- writel(0x40, info->base + info->data->gcr);
-}
-
-/*
- * js_pci_*_cleanup does the opposite of the above functions.
- */
-
-static void js_pci_4dwave_cleanup(struct js_pci_info *info)
-{
- pci_write_config_word(info->pci_p, info->data->lcr, info->lcr);
- writeb(0x00, info->base + info->data->gcr);
- iounmap(info->base);
-}
-
-static void js_pci_vortex_cleanup(struct js_pci_info *info)
-{
- writel(info->lcr, info->base + info->data->lcr);
- writel(0x00, info->base + info->data->gcr);
- iounmap(info->base);
-}
-
-static struct js_pci_data js_pci_data[] =
-{{ PCI_VENDOR_ID_TRIDENT, 0x2000, 0x10000, 0x00044 ,0x00030, 0x00031, 0x00034, 2, 0xffff,
- js_pci_4dwave_init, js_pci_4dwave_cleanup, "Trident 4DWave DX" },
- { PCI_VENDOR_ID_TRIDENT, 0x2001, 0x10000, 0x00044, 0x00030, 0x00031, 0x00034, 2, 0xffff,
- js_pci_4dwave_init, js_pci_4dwave_cleanup, "Trident 4DWave NX" },
- { PCI_VENDOR_ID_AUREAL, 0x0001, 0x40000, 0x1280c, 0x1100c, 0x11008, 0x11010, 4, 0x1fff,
- js_pci_vortex_init, js_pci_vortex_cleanup, "Aureal Vortex1" },
- { PCI_VENDOR_ID_AUREAL, 0x0002, 0x40000, 0x2a00c, 0x2880c, 0x28808, 0x28810, 4, 0x1fff,
- js_pci_vortex_init, js_pci_vortex_cleanup, "Aureal Vortex2" },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL }};
-
-/*
- * js_pci_read() reads data from a PCI gameport.
- */
-
-static int js_pci_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_pci_info *info = xinfo;
- int i;
-
- info->an.buttons = ~readb(info->base + info->data->buttons) >> 4;
-
- for (i = 0; i < 4; i++)
- info->an.axes[i] = readw(info->base + info->data->axes + i * info->data->axsize);
-
- js_an_decode(&info->an, axes, buttons);
-
- return 0;
-}
-
-static struct js_port * __init js_pci_probe(struct js_port *port, int type, int number,
- struct pci_dev *pci_p, struct js_pci_data *data)
-{
- int i;
- unsigned char u;
- int mask0, mask1, numdev;
- struct js_pci_info iniinfo;
- struct js_pci_info *info = &iniinfo;
-
- mask0 = mask1 = 0;
-
- for (i = 0; i < NUM_CARDS; i++)
- if (js_pci[i * 4] == type && js_pci[i * 4 + 1] == number) {
- mask0 = js_pci[i * 4 + 2];
- mask1 = js_pci[i * 4 + 3];
- if (!mask0 && !mask1) return port;
- break;
- }
-
- memset(info, 0, sizeof(struct js_pci_info));
-
- info->data = data;
- info->pci_p = pci_p;
- data->init(info);
-
- mdelay(10);
- js_pci_read(info, NULL, NULL);
-
- for (i = u = 0; i < 4; i++)
- if (info->an.axes[i] < info->data->axmax) u |= 1 << i;
-
- if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0)
- return port;
-
- port = js_register_port(port, info, numdev, sizeof(struct js_pci_info), js_pci_read);
-
- info = port->info;
-
- for (i = 0; i < numdev; i++)
- printk(KERN_WARNING "js%d: %s on %s #%d\n",
- js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
- js_an_name(i, &info->an), THIS_MODULE, NULL, NULL), js_an_name(i, &info->an), data->name, number);
-
- js_pci_read(info, port->axes, port->buttons);
- js_an_init_corr(&info->an, port->axes, port->corr, 32);
-
- return port;
-}
-
-#ifndef MODULE
-int __init js_pci_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(NUM_CARDS*4);
- for (i = 0; i <= ints[0] && i < NUM_CARDS*4; i++)
- js_pci[i] = ints[i+1];
- return 1;
-}
-__setup("js_pci=", js_pci_setup);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_pci_init(void)
-#endif
-{
- struct pci_dev *pci_p = NULL;
- int i, j;
-
- for (i = 0; js_pci_data[i].vendor; i++)
- for (j = 0; (pci_p = pci_find_device(js_pci_data[i].vendor, js_pci_data[i].model, pci_p)); j++)
- if (pci_enable_device(pci_p) == 0)
- js_pci_port = js_pci_probe(js_pci_port, i, j, pci_p, js_pci_data + i);
-
- if (!js_pci_port) {
-#ifdef MODULE
- printk(KERN_WARNING "joy-pci: no joysticks found\n");
-#endif
- return -ENODEV;
- }
-
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_pci_info *info;
-
- while (js_pci_port) {
- for (i = 0; i < js_pci_port->ndevs; i++)
- if (js_pci_port->devs[i])
- js_unregister_device(js_pci_port->devs[i]);
- info = js_pci_port->info;
- info->data->cleanup(info);
- js_pci_port = js_unregister_port(js_pci_port);
- }
-}
-#endif
diff --git a/drivers/char/joystick/joy-sidewinder.c b/drivers/char/joystick/joy-sidewinder.c
deleted file mode 100644
index da11598f4..000000000
--- a/drivers/char/joystick/joy-sidewinder.c
+++ /dev/null
@@ -1,835 +0,0 @@
-/*
- * joy-sidewinder.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * Microsoft SideWinder digital joystick family.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-/*
- * These are really magic values. Changing them can make a problem go away,
- * as well as break everything.
- */
-
-#undef JS_SW_DEBUG
-
-#define JS_SW_START 400 /* The time we wait for the first bit [400 us] */
-#define JS_SW_STROBE 45 /* Max time per bit [45 us] */
-#define JS_SW_TIMEOUT 4000 /* Wait for everything to settle [4 ms] */
-#define JS_SW_KICK 45 /* Wait after A0 fall till kick [45 us] */
-#define JS_SW_END 8 /* Number of bits before end of packet to kick */
-#define JS_SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */
-#define JS_SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */
-#define JS_SW_OK 64 /* Number of packet read successes to switch optimization back on */
-#define JS_SW_LENGTH 512 /* Max number of bits in a packet */
-
-/*
- * SideWinder joystick types ...
- */
-
-#define JS_SW_TYPE_3DP 1
-#define JS_SW_TYPE_F23 2
-#define JS_SW_TYPE_GP 3
-#define JS_SW_TYPE_PP 4
-#define JS_SW_TYPE_FFP 5
-#define JS_SW_TYPE_FSP 6
-#define JS_SW_TYPE_FFW 7
-
-static int js_sw_port_list[] __initdata = {0x201, 0};
-static struct js_port* js_sw_port __initdata = NULL;
-
-static struct {
- int x;
- int y;
-} js_sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-struct js_sw_info {
- int io;
- int length;
- int speed;
- unsigned char type;
- unsigned char bits;
- unsigned char number;
- unsigned char fail;
- unsigned char ok;
-};
-
-/*
- * Gameport speed.
- */
-
-unsigned int js_sw_io_speed = 0;
-
-/*
- * js_sw_measure_speed() measures the gameport i/o speed.
- */
-
-static int __init js_sw_measure_speed(int io)
-{
-#ifdef __i386__
-
-#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;
-
- 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++) inb(io);
- 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 / t;
-
-#else
-
- unsigned int j, t = 0;
-
- j = jiffies; while (j == jiffies);
- j = jiffies; while (j == jiffies) { t++; inb(0x201); }
-
- return t * HZ / 1000;
-
-#endif
-}
-
-/*
- * js_sw_read_packet() is a function which reads either a data packet, or an
- * identification packet from a SideWinder joystick. Better don't try to
- * understand this, since all the ugliness of the Microsoft Digital
- * Overdrive protocol is concentrated in this function. If you really want
- * to know how this works, first go watch a couple horror movies, so that
- * you are well prepared, read US patent #5628686 and then e-mail me,
- * and I'll send you an explanation.
- * Vojtech <vojtech@suse.cz>
- */
-
-static int js_sw_read_packet(int io, int speed, unsigned char *buf, int length, int id)
-{
- unsigned long flags;
- int timeout, bitout, sched, i, kick, start, strobe;
- unsigned char pending, u, v;
-
- i = -id; /* Don't care about data, only want ID */
- timeout = id ? (JS_SW_TIMEOUT * speed) >> 10 : 0; /* Set up global timeout for ID packet */
- kick = id ? (JS_SW_KICK * speed) >> 10 : 0; /* Set up kick timeout for ID packet */
- start = (JS_SW_START * speed) >> 10;
- strobe = (JS_SW_STROBE * speed) >> 10;
- bitout = start;
- pending = 0;
- sched = 0;
-
- __save_flags(flags); /* Quiet, please */
- __cli();
-
- outb(0xff, io); /* Trigger */
- v = inb(io);
-
- do {
- bitout--;
- u = v;
- v = inb(io);
- } while (!(~v & u & 0x10) && (bitout > 0)); /* Wait for first falling edge on clock */
-
- if (bitout > 0) bitout = strobe; /* Extend time if not timed out */
-
- while ((timeout > 0 || bitout > 0) && (i < length)) {
-
- timeout--;
- bitout--; /* Decrement timers */
- sched--;
-
- u = v;
- v = inb(io);
-
- if ((~u & v & 0x10) && (bitout > 0)) { /* Rising edge on clock - data bit */
- if (i >= 0) /* Want this data */
- buf[i] = v >> 5; /* Store it */
- i++; /* Advance index */
- bitout = strobe; /* Extend timeout for next bit */
- }
-
- if (kick && (~v & u & 0x01)) { /* Falling edge on axis 0 */
- sched = kick; /* Schedule second trigger */
- kick = 0; /* Don't schedule next time on falling edge */
- pending = 1; /* Mark schedule */
- }
-
- if (pending && sched < 0 && (i > -JS_SW_END)) { /* Second trigger time */
- outb(0xff, io); /* Trigger */
- bitout = start; /* Long bit timeout */
- pending = 0; /* Unmark schedule */
- timeout = 0; /* Switch from global to bit timeouts */
- }
- }
-
- __restore_flags(flags); /* Done - relax */
-
-#ifdef JS_SW_DEBUG
- {
- int j;
- printk(KERN_DEBUG "joy-sidewinder: Read %d triplets. [", i);
- for (j = 0; j < i; j++) printk("%d", buf[j]);
- printk("]\n");
- }
-#endif
-
- return i;
-}
-
-/*
- * js_sw_get_bits() and GB() compose bits from the triplet buffer into a __u64.
- * Parameter 'pos' is bit number inside packet where to start at, 'num' is number
- * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
- * is number of bits per triplet.
- */
-
-#define GB(pos,num,shift) js_sw_get_bits(buf, pos, num, shift, info->bits)
-
-static __u64 js_sw_get_bits(unsigned char *buf, int pos, int num, char shift, char bits)
-{
- __u64 data = 0;
- int tri = pos % bits; /* Start position */
- int i = pos / bits;
- int bit = shift;
-
- while (num--) {
- data |= (__u64)((buf[i] >> tri++) & 1) << bit++; /* Transfer bit */
- if (tri == bits) {
- i++; /* Next triplet */
- tri = 0;
- }
- }
-
- return data;
-}
-
-/*
- * js_sw_init_digital() initializes a SideWinder 3D Pro joystick
- * into digital mode.
- */
-
-static void js_sw_init_digital(int io, int speed)
-{
- int seq[] = { 140, 140+725, 140+300, 0 };
- unsigned long flags;
- int i, t;
-
- __save_flags(flags);
- __cli();
-
- i = 0;
- do {
- outb(0xff, io); /* Trigger */
- t = (JS_SW_TIMEOUT * speed) >> 10;
- while ((inb(io) & 1) && t) t--; /* Wait for axis to fall back to 0 */
- udelay(seq[i]); /* Delay magic time */
- } while (seq[++i]);
-
- outb(0xff, io); /* Last trigger */
-
- __restore_flags(flags);
-}
-
-/*
- * js_sw_parity() computes parity of __u64
- */
-
-static int js_sw_parity(__u64 t)
-{
- int x = t ^ (t >> 32);
- x ^= x >> 16;
- x ^= x >> 8;
- x ^= x >> 4;
- x ^= x >> 2;
- x ^= x >> 1;
- return x & 1;
-}
-
-/*
- * js_sw_ccheck() checks synchronization bits and computes checksum of nibbles.
- */
-
-static int js_sw_check(__u64 t)
-{
- char sum = 0;
-
- if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */
- return -1;
-
- while (t) { /* Sum */
- sum += t & 0xf;
- t >>= 4;
- }
-
- return sum & 0xf;
-}
-
-/*
- * js_sw_parse() analyzes SideWinder joystick data, and writes the results into
- * the axes and buttons arrays.
- */
-
-static int js_sw_parse(unsigned char *buf, struct js_sw_info *info, int **axes, int **buttons)
-{
- int hat, i;
-
- switch (info->type) {
-
- case JS_SW_TYPE_3DP:
- case JS_SW_TYPE_F23:
-
- if (js_sw_check(GB(0,64,0)) || (hat = GB(6,1,3) | GB(60,3,0)) > 8) return -1;
-
- axes[0][0] = GB( 3,3,7) | GB(16,7,0);
- axes[0][1] = GB( 0,3,7) | GB(24,7,0);
- axes[0][2] = GB(35,2,7) | GB(40,7,0);
- axes[0][3] = GB(32,3,7) | GB(48,7,0);
- axes[0][4] = js_sw_hat_to_axis[hat].x;
- axes[0][5] = js_sw_hat_to_axis[hat].y;
- buttons[0][0] = ~(GB(37,1,8) | GB(38,1,7) | GB(8,7,0));
-
- return 0;
-
- case JS_SW_TYPE_GP:
-
- for (i = 0; i < info->number * 15; i += 15) {
-
- if (js_sw_parity(GB(i,15,0))) return -1;
-
- axes[i][0] = GB(i+3,1,0) - GB(i+2,1,0);
- axes[i][1] = GB(i+0,1,0) - GB(i+1,1,0);
- buttons[i][0] = ~GB(i+4,10,0);
-
- }
-
- return 0;
-
- case JS_SW_TYPE_PP:
- case JS_SW_TYPE_FFP:
-
- if (!js_sw_parity(GB(0,48,0)) || (hat = GB(42,4,0)) > 8) return -1;
-
- axes[0][0] = GB( 9,10,0);
- axes[0][1] = GB(19,10,0);
- axes[0][2] = GB(36, 6,0);
- axes[0][3] = GB(29, 7,0);
- axes[0][4] = js_sw_hat_to_axis[hat].x;
- axes[0][5] = js_sw_hat_to_axis[hat].y;
- buttons[0][0] = ~GB(0,9,0);
-
- return 0;
-
- case JS_SW_TYPE_FSP:
-
- if (!js_sw_parity(GB(0,43,0)) || (hat = GB(28,4,0)) > 8) return -1;
-
- axes[0][0] = GB( 0,10,0);
- axes[0][1] = GB(16,10,0);
- axes[0][2] = GB(32, 6,0);
- axes[0][3] = js_sw_hat_to_axis[hat].x;
- axes[0][4] = js_sw_hat_to_axis[hat].y;
- buttons[0][0] = ~(GB(10,6,0) | GB(26,2,6) | GB(38,2,8));
-
- return 0;
-
- case JS_SW_TYPE_FFW:
-
- if (!js_sw_parity(GB(0,33,0))) return -1;
-
- axes[0][0] = GB( 0,10,0);
- axes[0][1] = GB(10, 6,0);
- axes[0][2] = GB(16, 6,0);
- buttons[0][0] = ~GB(22,8,0);
-
- return 0;
- }
-
- return -1;
-}
-
-/*
- * js_sw_read() reads SideWinder joystick data, and reinitializes
- * the joystick in case of persistent problems. This is the function that is
- * called from the generic code to poll the joystick.
- */
-
-static int js_sw_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_sw_info *info = xinfo;
- unsigned char buf[JS_SW_LENGTH];
- int i;
-
- i = js_sw_read_packet(info->io, info->speed, buf, info->length, 0);
-
- if (info->type <= JS_SW_TYPE_F23 && info->length == 66 && i != 66) { /* Broken packet, try to fix */
-
- if (i == 64 && !js_sw_check(js_sw_get_bits(buf,0,64,0,1))) { /* Last init failed, 1 bit mode */
- printk(KERN_WARNING "joy-sidewinder: Joystick in wrong mode on %#x"
- " - going to reinitialize.\n", info->io);
- info->fail = JS_SW_FAIL; /* Reinitialize */
- i = 128; /* Bogus value */
- }
-
- if (i < 66 && GB(0,64,0) == GB(i*3-66,64,0)) /* 1 == 3 */
- i = 66; /* Everything is fine */
-
- if (i < 66 && GB(0,64,0) == GB(66,64,0)) /* 1 == 2 */
- i = 66; /* Everything is fine */
-
- if (i < 66 && GB(i*3-132,64,0) == GB(i*3-66,64,0)) { /* 2 == 3 */
- memmove(buf, buf + i - 22, 22); /* Move data */
- i = 66; /* Carry on */
- }
- }
-
- if (i == info->length && !js_sw_parse(buf, info, axes, buttons)) { /* Parse data */
-
- info->fail = 0;
- info->ok++;
-
- if (info->type <= JS_SW_TYPE_F23 && info->length == 66 /* Many packets OK */
- && info->ok > JS_SW_OK) {
-
- printk(KERN_INFO "joy-sidewinder: No more trouble on %#x"
- " - enabling optimization again.\n", info->io);
- info->length = 22;
- }
-
- return 0;
- }
-
- info->ok = 0;
- info->fail++;
-
- if (info->type <= JS_SW_TYPE_F23 && info->length == 22 /* Consecutive bad packets */
- && info->fail > JS_SW_BAD) {
-
- printk(KERN_INFO "joy-sidewinder: Many bit errors on %#x"
- " - disabling optimization.\n", info->io);
- info->length = 66;
- }
-
- if (info->fail < JS_SW_FAIL) return -1; /* Not enough, don't reinitialize yet */
-
- printk(KERN_WARNING "joy-sidewinder: Too many bit errors on %#x"
- " - reinitializing joystick.\n", info->io);
-
- if (!i && info->type <= JS_SW_TYPE_F23) { /* 3D Pro can be in analog mode */
- udelay(3 * JS_SW_TIMEOUT);
- js_sw_init_digital(info->io, info->speed);
- }
-
- udelay(JS_SW_TIMEOUT);
- i = js_sw_read_packet(info->io, info->speed, buf, JS_SW_LENGTH, 0); /* Read normal data packet */
- udelay(JS_SW_TIMEOUT);
- js_sw_read_packet(info->io, info->speed, buf, JS_SW_LENGTH, i); /* Read ID packet, this initializes the stick */
-
- info->fail = JS_SW_FAIL;
-
- return -1;
-}
-
-/*
- * js_sw_init_corr() initializes the correction values for
- * SideWinders.
- */
-
-static void __init js_sw_init_corr(int num_axes, int type, int number, struct js_corr **corr)
-{
- int i, j;
-
- for (i = 0; i < number; i++) {
-
- for (j = 0; j < num_axes; j++) {
- corr[i][j].type = JS_CORR_BROKEN;
- corr[i][j].prec = 8;
- corr[i][j].coef[0] = 511 - 32;
- corr[i][j].coef[1] = 512 + 32;
- corr[i][j].coef[2] = (1 << 29) / (511 - 32);
- corr[i][j].coef[3] = (1 << 29) / (511 - 32);
- }
-
- switch (type) {
-
- case JS_SW_TYPE_3DP:
- case JS_SW_TYPE_F23:
-
- corr[i][2].type = JS_CORR_BROKEN;
- corr[i][2].prec = 4;
- corr[i][2].coef[0] = 255 - 16;
- corr[i][2].coef[1] = 256 + 16;
- corr[i][2].coef[2] = (1 << 29) / (255 - 16);
- corr[i][2].coef[3] = (1 << 29) / (255 - 16);
-
- j = 4;
-
- break;
-
- case JS_SW_TYPE_PP:
- case JS_SW_TYPE_FFP:
-
- corr[i][2].type = JS_CORR_BROKEN;
- corr[i][2].prec = 0;
- corr[i][2].coef[0] = 31 - 2;
- corr[i][2].coef[1] = 32 + 2;
- corr[i][2].coef[2] = (1 << 29) / (31 - 2);
- corr[i][2].coef[3] = (1 << 29) / (31 - 2);
-
- corr[i][3].type = JS_CORR_BROKEN;
- corr[i][3].prec = 1;
- corr[i][3].coef[0] = 63 - 4;
- corr[i][3].coef[1] = 64 + 4;
- corr[i][3].coef[2] = (1 << 29) / (63 - 4);
- corr[i][3].coef[3] = (1 << 29) / (63 - 4);
-
- j = 4;
-
- break;
-
- case JS_SW_TYPE_FFW:
-
- corr[i][0].type = JS_CORR_BROKEN;
- corr[i][0].prec = 2;
- corr[i][0].coef[0] = 511 - 8;
- corr[i][0].coef[1] = 512 + 8;
- corr[i][0].coef[2] = (1 << 29) / (511 - 8);
- corr[i][0].coef[3] = (1 << 29) / (511 - 8);
-
- corr[i][1].type = JS_CORR_BROKEN;
- corr[i][1].prec = 1;
- corr[i][1].coef[0] = 63;
- corr[i][1].coef[1] = 63;
- corr[i][1].coef[2] = (1 << 29) / -63;
- corr[i][1].coef[3] = (1 << 29) / -63;
-
- corr[i][2].type = JS_CORR_BROKEN;
- corr[i][2].prec = 1;
- corr[i][2].coef[0] = 63;
- corr[i][2].coef[1] = 63;
- corr[i][2].coef[2] = (1 << 29) / -63;
- corr[i][2].coef[3] = (1 << 29) / -63;
-
- j = 3;
-
- break;
-
- case JS_SW_TYPE_FSP:
-
- corr[i][2].type = JS_CORR_BROKEN;
- corr[i][2].prec = 0;
- corr[i][2].coef[0] = 31 - 2;
- corr[i][2].coef[1] = 32 + 2;
- corr[i][2].coef[2] = (1 << 29) / (31 - 2);
- corr[i][2].coef[3] = (1 << 29) / (31 - 2);
-
- j = 3;
-
- break;
-
- default:
-
- j = 0;
- }
-
- for (; j < num_axes; j++) { /* Hats & other binary axes */
- corr[i][j].type = JS_CORR_BROKEN;
- corr[i][j].prec = 0;
- corr[i][j].coef[0] = 0;
- corr[i][j].coef[1] = 0;
- corr[i][j].coef[2] = (1 << 29);
- corr[i][j].coef[3] = (1 << 29);
- }
- }
-}
-
-/*
- * js_sw_print_packet() prints the contents of a SideWinder packet.
- */
-
-static void js_sw_print_packet(char *name, int length, unsigned char *buf, char bits)
-{
- int i;
-
- printk("joy-sidewinder: %s packet, %d bits. [", name, length);
- for (i = (((length + 3) >> 2) - 1); i >= 0; i--)
- printk("%x", (int)js_sw_get_bits(buf, i << 2, 4, 0, bits));
- printk("]\n");
-}
-
-/*
- * js_sw_3dp_id() translates the 3DP id into a human legible string.
- * Unfortunately I don't know how to do this for the other SW types.
- */
-
-static void js_sw_3dp_id(unsigned char *buf, char *comment)
-{
- int i;
- char pnp[8], rev[9];
-
- for (i = 0; i < 7; i++) /* ASCII PnP ID */
- pnp[i] = js_sw_get_bits(buf, 24+8*i, 8, 0, 1);
-
- for (i = 0; i < 8; i++) /* ASCII firmware revision */
- rev[i] = js_sw_get_bits(buf, 88+8*i, 8, 0, 1);
-
- pnp[7] = rev[8] = 0;
-
- sprintf(comment, " [PnP %d.%02d id %s rev %s]",
- (int) (js_sw_get_bits(buf, 8, 6, 6, 1) | /* Two 6-bit values */
- js_sw_get_bits(buf, 16, 6, 0, 1)) / 100,
- (int) (js_sw_get_bits(buf, 8, 6, 6, 1) |
- js_sw_get_bits(buf, 16, 6, 0, 1)) % 100,
- pnp, rev);
-}
-
-/*
- * js_sw_guess_mode() checks the upper two button bits for toggling -
- * indication of that the joystick is in 3-bit mode. This is documented
- * behavior for 3DP ID packet, and for example the FSP does this in
- * normal packets instead. Fun ...
- */
-
-static int js_sw_guess_mode(unsigned char *buf, int len)
-{
- int i;
- unsigned char xor = 0;
- for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6;
- return !!xor * 2 + 1;
-}
-
-/*
- * js_sw_probe() probes for SideWinder type joysticks.
- */
-
-static struct js_port __init *js_sw_probe(int io, struct js_port *port)
-{
- struct js_sw_info info;
- char *names[] = {NULL, "SideWinder 3D Pro", "Flight2000 F-23", "SideWinder GamePad", "SideWinder Precision Pro",
- "SideWinder Force Feedback Pro", "SideWinder FreeStyle Pro", "SideWinder Force Feedback Wheel" };
- char axes[] = { 0, 6, 6, 2, 6, 6, 5, 3 };
- char buttons[] = { 0, 9, 9, 10, 9, 9, 10, 8 };
- int i, j, k, l, speed;
- unsigned char buf[JS_SW_LENGTH];
- unsigned char idbuf[JS_SW_LENGTH];
- unsigned char m = 1;
- char comment[40];
-
- comment[0] = 0;
-
- if (check_region(io, 1)) return port;
-
- speed = js_sw_measure_speed(io);
-
- i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Read normal packet */
- m |= js_sw_guess_mode(buf, i); /* Data packet (1-bit) can carry mode info [FSP] */
- udelay(JS_SW_TIMEOUT);
-
-#ifdef JS_SW_DEBUG
- printk(KERN_DEBUG "joy-sidewinder: Init 1: Mode %d. Length %d.\n", m , i);
-#endif
-
- if (!i) { /* No data. 3d Pro analog mode? */
- js_sw_init_digital(io, speed); /* Switch to digital */
- udelay(JS_SW_TIMEOUT);
- i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Retry reading packet */
- udelay(JS_SW_TIMEOUT);
-#ifdef JS_SW_DEBUG
- printk(KERN_DEBUG "joy-sidewinder: Init 1b: Length %d.\n", i);
-#endif
- if (!i) return port; /* No data -> FAIL */
- }
-
- j = js_sw_read_packet(io, speed, idbuf, JS_SW_LENGTH, i); /* Read ID. This initializes the stick */
- m |= js_sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */
-
-#ifdef JS_SW_DEBUG
- printk(KERN_DEBUG "joy-sidewinder: Init 2: Mode %d. ID Length %d.\n", m , j);
-#endif
-
- if (!j) { /* Read ID failed. Happens in 1-bit mode on PP */
- udelay(JS_SW_TIMEOUT);
- i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Retry reading packet */
-#ifdef JS_SW_DEBUG
- printk(KERN_DEBUG "joy-sidewinder: Init 2b: Mode %d. Length %d.\n", m , i);
-#endif
- if (!i) return port;
- udelay(JS_SW_TIMEOUT);
- j = js_sw_read_packet(io, speed, idbuf, JS_SW_LENGTH, i);/* Retry reading ID */
-#ifdef JS_SW_DEBUG
- printk(KERN_DEBUG "joy-sidewinder: Init 2c: ID Length %d.\n", j);
-#endif
-
- }
-
- k = JS_SW_FAIL; /* Try JS_SW_FAIL times */
- l = 0;
-
- do {
- k--;
- udelay(JS_SW_TIMEOUT);
- i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Read data packet */
-#ifdef JS_SW_DEBUG
- printk(KERN_DEBUG "joy-sidewinder: Init 3: Length %d.\n", i);
-#endif
-
- if (i > l) { /* Longer? As we can only lose bits, it makes */
- /* no sense to try detection for a packet shorter */
- l = i; /* than the previous one */
-
- info.number = 1;
- info.io = io;
- info.speed = speed;
- info.length = i;
- info.bits = m;
- info.fail = 0;
- info.ok = 0;
- info.type = 0;
-
- switch (i * m) {
- case 60:
- info.number++;
- case 45: /* Ambiguous packet length */
- if (j <= 40) { /* ID length less or eq 40 -> FSP */
- case 43:
- info.type = JS_SW_TYPE_FSP;
- break;
- }
- info.number++;
- case 30:
- info.number++;
- case 15:
- info.type = JS_SW_TYPE_GP;
- break;
- case 33:
- case 31:
- info.type = JS_SW_TYPE_FFW;
- break;
- case 48: /* Ambiguous */
- if (j == 14) { /* ID lenght 14*3 -> FFP */
- info.type = JS_SW_TYPE_FFP;
- sprintf(comment, " [AC %s]", js_sw_get_bits(idbuf,38,1,0,3) ? "off" : "on");
- } else
- info.type = JS_SW_TYPE_PP;
- break;
- case 198:
- info.length = 22;
- case 64:
- info.type = JS_SW_TYPE_3DP;
- if (j == 160) js_sw_3dp_id(idbuf, comment);
- break;
- }
- }
-
- } while (k && !info.type);
-
- if (!info.type) {
- printk(KERN_WARNING "joy-sidewinder: unknown joystick device detected "
- "(io=%#x), contact <vojtech@suse.cz>\n", io);
- js_sw_print_packet("ID", j * 3, idbuf, 3);
- js_sw_print_packet("Data", i * m, buf, m);
- return port;
- }
-
-#ifdef JS_SW_DEBUG
- js_sw_print_packet("ID", j * 3, idbuf, 3);
- js_sw_print_packet("Data", i * m, buf, m);
-#endif
-
- k = i;
-
- request_region(io, 1, "joystick (sidewinder)");
-
- port = js_register_port(port, &info, info.number, sizeof(struct js_sw_info), js_sw_read);
-
- for (i = 0; i < info.number; i++)
- printk(KERN_INFO "js%d: %s%s at %#x [%d ns res %d-bit id %d data %d]\n",
- js_register_device(port, i, axes[info.type], buttons[info.type],
- names[info.type], THIS_MODULE, NULL, NULL), names[info.type], comment, io,
- 1000000 / speed, m, j, k);
-
- js_sw_init_corr(axes[info.type], info.type, info.number, port->corr);
-
- return port;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_sw_init(void)
-#endif
-{
- int *p;
-
- for (p = js_sw_port_list; *p; p++) js_sw_port = js_sw_probe(*p, js_sw_port);
- if (js_sw_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-sidewinder: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_sw_info *info;
-
- while (js_sw_port) {
- for (i = 0; i < js_sw_port->ndevs; i++)
- if (js_sw_port->devs[i])
- js_unregister_device(js_sw_port->devs[i]);
- info = js_sw_port->info;
- release_region(info->io, 1);
- js_sw_port = js_unregister_port(js_sw_port);
- }
-
-}
-#endif
diff --git a/drivers/char/joystick/joy-spaceball.c b/drivers/char/joystick/joy-spaceball.c
deleted file mode 100644
index 3ace13642..000000000
--- a/drivers/char/joystick/joy-spaceball.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * joy-spaceball.c Version 0.1
- *
- * Copyright (c) 1998 David Thompson
- * Copyright (c) 1999 Vojtech Pavlik
- * Copyright (c) 1999 Joseph Krahn
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * the SpaceTec SpaceBall 4000 FLX.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-/*
- * Constants.
- */
-
-#define N_JOYSTICK_SBALL 12
-#define JS_SBALL_MAX_LENGTH 128
-
-/*
- * List of SpaceBalls.
- */
-
-static struct js_port* js_sball_port = NULL;
-
-/*
- * Per-Ball data.
- */
-
-struct js_sball_info {
- struct tty_struct* tty;
- struct js_port* port;
- int idx;
- unsigned char data[JS_SBALL_MAX_LENGTH];
- int js;
- char used;
-};
-
-/*
- * js_sball_process_packet() decodes packets the driver receives from the
- * SpaceBall.
- */
-
-static void js_sball_process_packet(struct js_sball_info* info)
-{
- int i,b;
- int **axes = info->port->axes;
- int **buttons = info->port->buttons;
- unsigned char *data = info->data;
-
- if (info->idx < 2) return;
-
- switch (info->data[0]) {
-
- case '@': /* Reset packet */
- info->data[info->idx - 1] = 0;
- for (i = 1; i < info->idx && info->data[i] == ' '; i++);
-
- printk(KERN_INFO "js%d: SpaceBall 4000FLX [%s] on %s%d\n",
- info->js, info->data + i, info->tty->driver.name,
- MINOR(info->tty->device) - info->tty->driver.minor_start);
-
- memset(axes[0], 0, sizeof(int) * 6); /* All axes, buttons should be zero */
- buttons[0][0] = 0;
- break;
-
- case 'D': /* Ball data */
- if (info->idx != 16) return;
- if (!info->port->devs[0]) return;
- axes[0][0] = ((data[3] << 8) | data[4] );
- axes[0][1] = ((data[5] << 8) | data[6] );
- axes[0][2] = ((data[7] << 8) | data[8] );
- axes[0][3] = ((data[9] << 8) | data[10]);
- axes[0][4] = ((data[11]<< 8) | data[12]);
- axes[0][5] = ((data[13]<< 8) | data[14]);
- for(i = 0; i < 6; i ++) if (axes[0][i] & 0x8000) axes[0][i] -= 0x10000;
- break;
-
- case 'K': /* Button data, part1 */
- /* We can ignore this packet for the SB 4000FLX. */
- break;
-
- case '.': /* Button data, part2 */
- if (info->idx != 4) return;
- if (!info->port->devs[0]) return;
- b = (data[1] & 0xbf) << 8 | (data[2] & 0xbf);
- buttons[0][0] = ((b & 0x1f80) >> 1 | (b & 0x3f));
- break;
-
- case '?': /* Error packet */
- info->data[info->idx - 1] = 0;
- printk(KERN_ERR "joy-spaceball: Device error. [%s]\n",info->data+1);
- break;
-
- case 'A': /* reply to A command (ID# report) */
- case 'B': /* reply to B command (beep) */
- case 'H': /* reply to H command (firmware report) */
- case 'S': /* reply to S command (single beep) */
- case 'Y': /* reply to Y command (scale flag) */
- case '"': /* reply to "n command (report info, part n) */
- break;
-
- case 'P': /* Pulse (update) speed */
- if (info->idx != 3) return; /* data[2],data[3] = hex digits for speed 00-FF */
- break;
-
- default:
- printk("joy-spaceball: Unknown packet %d length %d:", data[0], info->idx);
- for (i = 0; i < info->idx; i++) printk(" %02x", data[i]);
- printk("\n");
- return;
- }
-}
-
-/*
- * js_sball_open() is a callback from the joystick device open routine.
- */
-
-static int js_sball_open(struct js_dev *jd)
-{
- struct js_sball_info *info = jd->port->info;
- info->used++;
- return 0;
-}
-
-/*
- * js_sball_close() is a callback from the joystick device release routine.
- */
-
-static int js_sball_close(struct js_dev *jd)
-{
- struct js_sball_info *info = jd->port->info;
- if (!--info->used) {
- js_unregister_device(jd->port->devs[0]);
- js_sball_port = js_unregister_port(jd->port);
- }
- return 0;
-}
-
-/*
- * js_sball_init_corr() initializes the correction values for the SpaceBall.
- */
-
-static void __init js_sball_init_corr(struct js_corr **corr)
-{
- int j;
-
- for (j = 0; j < 3; j++) {
- corr[0][j].type = JS_CORR_BROKEN;
- corr[0][j].prec = 0;
- corr[0][j].coef[0] = 0;
- corr[0][j].coef[1] = 0;
- corr[0][j].coef[2] = 50000;
- corr[0][j].coef[3] = 50000;
- }
- for (j = 3; j < 6; j++) {
- corr[0][j].type = JS_CORR_BROKEN;
- corr[0][j].prec = 0;
- corr[0][j].coef[0] = 0;
- corr[0][j].coef[1] = 0;
- corr[0][j].coef[2] = 300000;
- corr[0][j].coef[3] = 300000;
- }
-}
-
-/*
- * js_sball_ldisc_open() is the routine that is called upon setting our line
- * discipline on a tty.
- */
-
-static int js_sball_ldisc_open(struct tty_struct *tty)
-{
- struct js_sball_info iniinfo;
- struct js_sball_info *info = &iniinfo;
-
- MOD_INC_USE_COUNT;
-
- info->tty = tty;
- info->idx = 0;
- info->used = 1;
-
- js_sball_port = js_register_port(js_sball_port, info, 1, sizeof(struct js_sball_info), NULL);
-
- info = js_sball_port->info;
- info->port = js_sball_port;
- tty->disc_data = info;
-
- info->js = js_register_device(js_sball_port, 0, 6, 12, "SpaceBall 4000 FLX", THIS_MODULE, js_sball_open, js_sball_close);
-
- js_sball_init_corr(js_sball_port->corr);
-
- return 0;
-}
-
-/*
- * js_sball_ldisc_close() is the opposite of js_sball_ldisc_open()
- */
-
-static void js_sball_ldisc_close(struct tty_struct *tty)
-{
- struct js_sball_info* info = (struct js_sball_info*) tty->disc_data;
- if (!--info->used) {
- js_unregister_device(info->port->devs[0]);
- js_sball_port = js_unregister_port(info->port);
- }
- MOD_DEC_USE_COUNT;
-}
-
-/*
- * js_sball_ldisc_receive() 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 js_sball_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
-{
- struct js_sball_info* info = (struct js_sball_info*) tty->disc_data;
- int i;
- int esc_flag = 0;
-
-/*
- * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor,
- * and end in 0x0d. It uses '^' as an escape for 0x0d characters which can
- * occur in the axis values. ^M, ^Q and ^S all mean 0x0d, depending (I think)
- * on whether the axis value is increasing, decreasing, or same as before.
- * (I don't see why this is useful).
- *
- * There may be a nicer whay to handle the escapes, but I wanted to be sure to
- * allow for an escape at the end of the buffer.
- */
- for (i = 0; i < count; i++) {
- if (esc_flag) { /* If the last char was an escape, overwrite it with the escaped value */
-
- switch (cp[i]){
- case 'M':
- case 'Q':
- case 'S':
- info->data[info->idx]=0x0d;
- break;
- case '^': /* escaped escape; leave as is */
- break;
- default:
- printk("joy-spaceball: Unknown escape character: %02x\n", cp[i]);
- }
-
- esc_flag = 0;
-
- } else {
-
- if (info->idx < JS_SBALL_MAX_LENGTH)
- info->data[info->idx++] = cp[i];
-
- if (cp[i] == 0x0D) {
- if (info->idx)
- js_sball_process_packet(info);
- info->idx = 0;
- } else
- if (cp[i] == '^') esc_flag = 1;
-
- }
- }
-}
-
-/*
- * js_sball_ldisc_room() reports how much room we do have for receiving data.
- * Although we in fact have infinite room, we need to specify some value
- * here, so why not the size of our packet buffer. It's big anyway.
- */
-
-static int js_sball_ldisc_room(struct tty_struct *tty)
-{
- return JS_SBALL_MAX_LENGTH;
-}
-
-/*
- * The line discipline structure.
- */
-
-static struct tty_ldisc js_sball_ldisc = {
- magic: TTY_LDISC_MAGIC,
- name: "spaceball",
- open: js_sball_ldisc_open,
- close: js_sball_ldisc_close,
- receive_buf: js_sball_ldisc_receive,
- receive_room: js_sball_ldisc_room,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_sball_init(void)
-#endif
-{
- if (tty_register_ldisc(N_JOYSTICK_SBALL, &js_sball_ldisc)) {
- printk(KERN_ERR "joy-spaceball: Error registering line discipline.\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- tty_register_ldisc(N_JOYSTICK_SBALL, NULL);
-}
-#endif
diff --git a/drivers/char/joystick/joy-spaceorb.c b/drivers/char/joystick/joy-spaceorb.c
deleted file mode 100644
index 0fb4f4c71..000000000
--- a/drivers/char/joystick/joy-spaceorb.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * joy-spaceorb.c Version 0.1
- *
- * Copyright (c) 1998 David Thompson
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * the SpaceTec SpaceOrb 360 and SpaceBall Avenger 6dof controllers.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-/*
- * Constants.
- */
-
-#define N_JOYSTICK_ORB 15
-#define JS_ORB_MAX_LENGTH 64
-
-/*
- * List of SpaceOrbs.
- */
-
-static struct js_port* js_orb_port = NULL;
-
-/*
- * Per-Orb data.
- */
-
-struct js_orb_info {
- struct tty_struct* tty;
- struct js_port* port;
- int idx;
- unsigned char data[JS_ORB_MAX_LENGTH];
- int js;
- char used;
-};
-
-static unsigned char js_orb_xor[] = "SpaceWare";
-
-static unsigned char *js_orb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout",
- "Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" };
-
-/*
- * js_orb_process_packet() decodes packets the driver receives from the
- * SpaceOrb.
- */
-
-static void js_orb_process_packet(struct js_orb_info* info)
-{
- int i;
- int **axes = info->port->axes;
- int **buttons = info->port->buttons;
- unsigned char *data = info->data;
- unsigned char c = 0;
-
- if (info->idx < 2) return;
- for (i = 0; i < info->idx; i++) c ^= data[i];
- if (c) return;
-
- switch (info->data[0]) {
-
- case 'R': /* Reset packet */
- info->data[info->idx - 1] = 0;
- for (i = 1; i < info->idx && info->data[i] == ' '; i++);
- printk(KERN_INFO "js%d: SpaceOrb 360 [%s] on %s%d\n",
- info->js, info->data + i, info->tty->driver.name,
- MINOR(info->tty->device) - info->tty->driver.minor_start);
- break;
-
- case 'D': /* Ball + button data */
- if (info->idx != 12) return;
- if (!info->port->devs[0]) return;
- for (i = 0; i < 9; i++) info->data[i+2] ^= js_orb_xor[i];
- axes[0][0] = ( data[2] << 3) | (data[ 3] >> 4);
- axes[0][1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1);
- axes[0][2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5);
- axes[0][3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2);
- axes[0][4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6);
- axes[0][5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3);
- for(i = 0; i < 6; i ++) if (axes[0][i] & 0x200) axes[0][i] -= 1024;
- buttons[0][0] = data[1];
- break;
-
- case 'K': /* Button data */
- if (info->idx != 5) return;
- if (!info->port->devs[0]) return;
- buttons[0][0] = data[2];
- break;
-
- case 'E': /* Error packet */
- if (info->idx != 4) return;
- printk(KERN_ERR "joy-spaceorb: Device error. [ ");
- for (i = 0; i < 7; i++)
- if (data[1] & (1 << i))
- printk("%s ", js_orb_errors[i]);
- printk("]\n");
- break;
-
- case 'N': /* Null region */
- if (info->idx != 3) return;
- break;
-
- case 'P': /* Pulse (update) speed */
- if (info->idx != 4) return;
- break;
-
- default:
- printk("joy-spaceorb: Unknown packet %d length %d:", data[0], info->idx);
- for (i = 0; i < info->idx; i++) printk(" %02x", data[i]);
- printk("\n");
- return;
- }
-}
-
-/*
- * js_orb_open() is a callback from the joystick device open routine.
- */
-
-static int js_orb_open(struct js_dev *jd)
-{
- struct js_orb_info *info = jd->port->info;
- info->used++;
- return 0;
-}
-
-/*
- * js_orb_close() is a callback from the joystick device release routine.
- */
-
-static int js_orb_close(struct js_dev *jd)
-{
- struct js_orb_info *info = jd->port->info;
- if (!--info->used) {
- js_unregister_device(jd->port->devs[0]);
- js_orb_port = js_unregister_port(jd->port);
- }
- return 0;
-}
-
-/*
- * js_orb_init_corr() initializes the correction values for the SpaceOrb.
- */
-
-static void __init js_orb_init_corr(struct js_corr **corr)
-{
- int j;
-
- for (j = 0; j < 6; j++) {
- corr[0][j].type = JS_CORR_BROKEN;
- corr[0][j].prec = 0;
- corr[0][j].coef[0] = 0 ;
- corr[0][j].coef[1] = 0 ;
- corr[0][j].coef[2] = (1 << 29) / 511;
- corr[0][j].coef[3] = (1 << 29) / 511;
- }
-}
-
-/*
- * js_orb_ldisc_open() is the routine that is called upon setting our line
- * discipline on a tty.
- */
-
-static int js_orb_ldisc_open(struct tty_struct *tty)
-{
- struct js_orb_info iniinfo;
- struct js_orb_info *info = &iniinfo;
-
- MOD_INC_USE_COUNT;
-
- info->tty = tty;
- info->idx = 0;
- info->used = 1;
-
- js_orb_port = js_register_port(js_orb_port, info, 1, sizeof(struct js_orb_info), NULL);
-
- info = js_orb_port->info;
- info->port = js_orb_port;
- tty->disc_data = info;
-
- info->js = js_register_device(js_orb_port, 0, 6, 7, "SpaceOrb 360", THIS_MODULE, js_orb_open, js_orb_close);
-
- js_orb_init_corr(js_orb_port->corr);
-
- return 0;
-}
-
-/*
- * js_orb_ldisc_close() is the opposite of js_orb_ldisc_open()
- */
-
-static void js_orb_ldisc_close(struct tty_struct *tty)
-{
- struct js_orb_info* info = (struct js_orb_info*) tty->disc_data;
- if (!--info->used) {
- js_unregister_device(info->port->devs[0]);
- js_orb_port = js_unregister_port(info->port);
- }
- MOD_DEC_USE_COUNT;
-}
-
-/*
- * js_orb_ldisc_receive() 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 js_orb_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
-{
- struct js_orb_info* info = (struct js_orb_info*) tty->disc_data;
- int i;
-
- for (i = 0; i < count; i++) {
- if (~cp[i] & 0x80) {
- if (info->idx) js_orb_process_packet(info);
- info->idx = 0;
- }
- if (info->idx < JS_ORB_MAX_LENGTH)
- info->data[info->idx++] = cp[i] & 0x7f;
- }
-}
-
-/*
- * js_orb_ldisc_room() reports how much room we do have for receiving data.
- * Although we in fact have infinite room, we need to specify some value
- * here, so why not the size of our packet buffer. It's big anyway.
- */
-
-static int js_orb_ldisc_room(struct tty_struct *tty)
-{
- return JS_ORB_MAX_LENGTH;
-}
-
-/*
- * The line discipline structure.
- */
-
-static struct tty_ldisc js_orb_ldisc = {
- magic: TTY_LDISC_MAGIC,
- name: "spaceorb",
- open: js_orb_ldisc_open,
- close: js_orb_ldisc_close,
- receive_buf: js_orb_ldisc_receive,
- receive_room: js_orb_ldisc_room,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_orb_init(void)
-#endif
-{
- if (tty_register_ldisc(N_JOYSTICK_ORB, &js_orb_ldisc)) {
- printk(KERN_ERR "joy-spaceorb: Error registering line discipline.\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- tty_register_ldisc(N_JOYSTICK_ORB, NULL);
-}
-#endif
diff --git a/drivers/char/joystick/joy-thrustmaster.c b/drivers/char/joystick/joy-thrustmaster.c
deleted file mode 100644
index 56e043a59..000000000
--- a/drivers/char/joystick/joy-thrustmaster.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * joy-thrustmaster.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * ThrustMaster DirectConnect (BSP) joystick family.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#define JS_TM_MAX_START 400
-#define JS_TM_MAX_STROBE 45
-#define JS_TM_MAX_LENGTH 13
-
-#define JS_TM_MODE_M3DI 1
-#define JS_TM_MODE_3DRP 3
-#define JS_TM_MODE_FGP 163
-
-#define JS_TM_BYTE_ID 10
-#define JS_TM_BYTE_REV 11
-#define JS_TM_BYTE_DEF 12
-
-static int js_tm_port_list[] __initdata = {0x201, 0};
-static struct js_port* js_tm_port __initdata = NULL;
-
-static unsigned char js_tm_byte_a[16] = { 0, 1, 3, 4, 6, 7 };
-static unsigned char js_tm_byte_d[16] = { 2, 5, 8, 9 };
-
-struct js_tm_info {
- int io;
- unsigned char mode;
-};
-
-/*
- * js_tm_read_packet() reads a ThrustMaster packet.
- */
-
-static int js_tm_read_packet(int io, unsigned char *data)
-{
- unsigned int t, p;
- unsigned char u, v, error;
- int i, j;
- unsigned long flags;
-
- error = 0;
- i = j = 0;
- p = t = JS_TM_MAX_START;
-
- __save_flags(flags);
- __cli();
- outb(0xff,io);
-
- v = inb(io) >> 4;
-
- do {
- t--;
- u = v; v = inb(io) >> 4;
- if (~v & u & 2) {
- if (j) {
- if (j < 9) { /* Data bit */
- data[i] |= (~v & 1) << (j - 1);
- j++;
- } else { /* Stop bit */
- error |= v & 1;
- j = 0;
- i++;
- }
- } else { /* Start bit */
- data[i] = 0;
- error |= ~v & 1;
- j++;
- }
- p = t = (p - t) << 1;
- }
- } while (!error && i < JS_TM_MAX_LENGTH && t > 0);
-
- __restore_flags(flags);
-
- return -(i != JS_TM_MAX_LENGTH);
-}
-
-/*
- * js_tm_read() reads and analyzes ThrustMaster joystick data.
- */
-
-static int js_tm_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_tm_info *info = xinfo;
- unsigned char data[JS_TM_MAX_LENGTH];
- int i;
-
- if (js_tm_read_packet(info->io, data)) return -1;
- if (data[JS_TM_BYTE_ID] != info->mode) return -1;
-
- for (i = 0; i < data[JS_TM_BYTE_DEF] >> 4; i++) axes[0][i] = data[js_tm_byte_a[i]];
-
- switch (info->mode) {
-
- case JS_TM_MODE_M3DI:
-
- axes[0][4] = ((data[js_tm_byte_d[0]] >> 3) & 1) - ((data[js_tm_byte_d[0]] >> 1) & 1);
- axes[0][5] = ((data[js_tm_byte_d[0]] >> 2) & 1) - ( data[js_tm_byte_d[0]] & 1);
-
- buttons[0][0] = ((data[js_tm_byte_d[0]] >> 6) & 0x01) | ((data[js_tm_byte_d[0]] >> 3) & 0x06)
- | ((data[js_tm_byte_d[0]] >> 4) & 0x08) | ((data[js_tm_byte_d[1]] >> 2) & 0x30);
-
- return 0;
-
- case JS_TM_MODE_3DRP:
- case JS_TM_MODE_FGP:
-
- buttons[0][0] = (data[js_tm_byte_d[0]] & 0x3f) | ((data[js_tm_byte_d[1]] << 6) & 0xc0)
- | (( ((int) data[js_tm_byte_d[0]]) << 2) & 0x300);
-
- return 0;
-
- default:
-
- buttons[0][0] = 0;
-
- for (i = 0; i < (data[JS_TM_BYTE_DEF] & 0xf); i++)
- buttons[0][0] |= ((int) data[js_tm_byte_d[i]]) << (i << 3);
-
- return 0;
-
- }
-
- return -1;
-}
-
-/*
- * js_tm_init_corr() initializes the correction values for
- * ThrustMaster joysticks.
- */
-
-static void __init js_tm_init_corr(int num_axes, int mode, int **axes, struct js_corr **corr)
-{
- int j = 0;
-
- for (; j < num_axes; j++) {
- corr[0][j].type = JS_CORR_BROKEN;
- corr[0][j].prec = 0;
- corr[0][j].coef[0] = 127 - 2;
- corr[0][j].coef[1] = 128 + 2;
- corr[0][j].coef[2] = (1 << 29) / (127 - 4);
- corr[0][j].coef[3] = (1 << 29) / (127 - 4);
- }
-
- switch (mode) {
- case JS_TM_MODE_M3DI: j = 4; break;
- default: break;
- }
-
- for (; j < num_axes; j++) {
- corr[0][j].type = JS_CORR_BROKEN;
- corr[0][j].prec = 0;
- corr[0][j].coef[0] = 0;
- corr[0][j].coef[1] = 0;
- corr[0][j].coef[2] = (1 << 29);
- corr[0][j].coef[3] = (1 << 29);
- }
-
-}
-
-/*
- * js_tm_probe() probes for ThrustMaster type joysticks.
- */
-
-static struct js_port __init *js_tm_probe(int io, struct js_port *port)
-{
- struct js_tm_info info;
- struct js_rm_models {
- unsigned char id;
- char *name;
- char axes;
- char buttons;
- } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 6 },
- { 3, "ThrustMaster Rage 3D Gamepad", 2, 10 },
- { 163, "Thrustmaster Fusion GamePad", 2, 10 },
- { 0, NULL, 0, 0 }};
- char name[64];
- unsigned char data[JS_TM_MAX_LENGTH];
- unsigned char a, b;
- int i;
-
- if (check_region(io, 1)) return port;
-
- if (js_tm_read_packet(io, data)) return port;
-
- info.io = io;
- info.mode = data[JS_TM_BYTE_ID];
-
- if (!info.mode) return port;
-
- for (i = 0; models[i].id && models[i].id != info.mode; i++);
-
- if (models[i].id != info.mode) {
- a = data[JS_TM_BYTE_DEF] >> 4;
- b = (data[JS_TM_BYTE_DEF] & 0xf) << 3;
- sprintf(name, "Unknown %d-axis, %d-button TM device %d", a, b, info.mode);
- } else {
- sprintf(name, models[i].name);
- a = models[i].axes;
- b = models[i].buttons;
- }
-
- request_region(io, 1, "joystick (thrustmaster)");
- port = js_register_port(port, &info, 1, sizeof(struct js_tm_info), js_tm_read);
- printk(KERN_INFO "js%d: %s revision %d at %#x\n",
- js_register_device(port, 0, a, b, name, THIS_MODULE, NULL, NULL), name, data[JS_TM_BYTE_REV], io);
- js_tm_init_corr(a, info.mode, port->axes, port->corr);
-
- return port;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_tm_init(void)
-#endif
-{
- int *p;
-
- for (p = js_tm_port_list; *p; p++) js_tm_port = js_tm_probe(*p, js_tm_port);
- if (js_tm_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-thrustmaster: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- struct js_tm_info *info;
-
- while (js_tm_port) {
- js_unregister_device(js_tm_port->devs[0]);
- info = js_tm_port->info;
- release_region(info->io, 1);
- js_tm_port = js_unregister_port(js_tm_port);
- }
-}
-#endif
diff --git a/drivers/char/joystick/joy-turbografx.c b/drivers/char/joystick/joy-turbografx.c
deleted file mode 100644
index c138a99d0..000000000
--- a/drivers/char/joystick/joy-turbografx.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * joy-turbografx.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * Steffen Schwenke's <schwenke@burg-halle.de> TurboGraFX parallel port
- * interface.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_tg, "2-8i");
-MODULE_PARM(js_tg_2, "2-8i");
-MODULE_PARM(js_tg_3, "2-8i");
-
-#define JS_TG_BUTTON1 0x08
-#define JS_TG_UP 0x10
-#define JS_TG_DOWN 0x20
-#define JS_TG_LEFT 0x40
-#define JS_TG_RIGHT 0x80
-
-#define JS_TG_BUTTON2 0x02
-#define JS_TG_BUTTON3 0x04
-#define JS_TG_BUTTON4 0x01
-#define JS_TG_BUTTON5 0x08
-
-static struct js_port* js_tg_port __initdata = NULL;
-
-static int js_tg[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-static int js_tg_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-static int js_tg_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-
-struct js_tg_info {
- struct pardevice *port; /* parport device */
- int sticks; /* joysticks connected */
-};
-
-/*
- * js_tg_read() reads and analyzes tg joystick data.
- */
-
-static int js_tg_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_tg_info *info = xinfo;
- int data1, data2, i;
-
- for (i = 0; i < 7; i++)
- if ((info->sticks >> i) & 1) {
-
- JS_PAR_DATA_OUT(~(1 << i), info->port);
- data1 = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
- data2 = JS_PAR_CTRL_IN(info->port) ^ JS_PAR_CTRL_INVERT;
-
- axes[i][0] = ((data1 & JS_TG_RIGHT) ? 1 : 0) - ((data1 & JS_TG_LEFT) ? 1 : 0);
- axes[i][1] = ((data1 & JS_TG_DOWN ) ? 1 : 0) - ((data1 & JS_TG_UP ) ? 1 : 0);
-
- buttons[i][0] = ((data1 & JS_TG_BUTTON1) ? 0x01 : 0) | ((data2 & JS_TG_BUTTON2) ? 0x02 : 0)
- | ((data2 & JS_TG_BUTTON3) ? 0x04 : 0) | ((data2 & JS_TG_BUTTON4) ? 0x08 : 0)
- | ((data2 & JS_TG_BUTTON5) ? 0x10 : 0);
-
- }
-
- return 0;
-}
-
-/*
- * open callback: claim parport.
- * FIXME: race possible here.
- */
-
-int js_tg_open(struct js_dev *dev)
-{
- struct js_tg_info *info = dev->port->info;
-
- if (!MOD_IN_USE) {
- if (parport_claim(info->port)) return -EBUSY;
- JS_PAR_CTRL_OUT(0x04, info->port);
- }
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * close callback: release parport
- */
-
-int js_tg_close(struct js_dev *dev)
-{
- struct js_tg_info *info = dev->port->info;
-
- MOD_DEC_USE_COUNT;
- if (!MOD_IN_USE) {
- JS_PAR_CTRL_OUT(0x00, info->port);
- parport_release(info->port);
- }
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- struct js_tg_info *info;
- int i;
-
- while (js_tg_port) {
- for (i = 0; i < js_tg_port->ndevs; i++)
- if (js_tg_port->devs[i])
- js_unregister_device(js_tg_port->devs[i]);
- info = js_tg_port->info;
- parport_unregister_device(info->port);
- js_tg_port = js_unregister_port(js_tg_port);
- }
-}
-#endif
-
-/*
- * js_tg_init_corr() initializes correction values of
- * tg gamepads.
- */
-
-static void __init js_tg_init_corr(int sticks, struct js_corr **corr)
-{
- int i, j;
-
- for (i = 0; i < 7; i++)
- if ((sticks >> i) & 1)
- for (j = 0; j < 2; j++) {
- corr[i][j].type = JS_CORR_BROKEN;
- corr[i][j].prec = 0;
- corr[i][j].coef[0] = 0;
- corr[i][j].coef[1] = 0;
- corr[i][j].coef[2] = (1 << 29);
- corr[i][j].coef[3] = (1 << 29);
- }
-}
-
-/*
- * js_tg_probe() probes for tg gamepads.
- */
-
-static struct js_port __init *js_tg_probe(int *config, struct js_port *port)
-{
- struct js_tg_info iniinfo;
- struct js_tg_info *info = &iniinfo;
- struct parport *pp;
- int i;
-
- if (config[0] < 0) return port;
-
-
- if (config[0] > 0x10)
- for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
- else
- for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;
-
- if (!pp) {
- printk(KERN_ERR "joy-tg: no such parport\n");
- return port;
- }
-
- info->port = parport_register_device(pp, "joystick (turbografx)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
- if (!info->port)
- return port;
-
- port = js_register_port(port, info, 7, sizeof(struct js_tg_info), js_tg_read);
- info = port->info;
-
- info->sticks = 0;
-
- for (i = 0; i < 7; i++)
- if (config[i+1] > 0 && config[i+1] < 6) {
- printk(KERN_INFO "js%d: Multisystem joystick on %s\n",
- js_register_device(port, i, 2, config[i+1], "Multisystem joystick", NULL, js_tg_open, js_tg_close),
- info->port->port->name);
- info->sticks |= (1 << i);
- }
-
- if (!info->sticks) {
- parport_unregister_device(info->port);
- return port;
- }
-
- js_tg_init_corr(info->sticks, port->corr);
-
- return port;
-}
-
-#ifndef MODULE
-int __init js_tg_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_tg[i] = ints[i+1];
- return 1;
-}
-int __init js_tg_setup_2(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_tg_2[i] = ints[i+1];
- return 1;
-}
-int __init js_tg_setup_3(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_tg_3[i] = ints[i+1];
- return 1;
-}
-__setup("js_tg=", js_tg_setup);
-__setup("js_tg_2=", js_tg_setup_2);
-__setup("js_tg_3=", js_tg_setup_3);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_tg_init(void)
-#endif
-{
- js_tg_port = js_tg_probe(js_tg, js_tg_port);
- js_tg_port = js_tg_probe(js_tg_2, js_tg_port);
- js_tg_port = js_tg_probe(js_tg_3, js_tg_port);
-
- if (js_tg_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-tg: no joysticks specified\n");
-#endif
- return -ENODEV;
-}
diff --git a/drivers/char/joystick/joy-warrior.c b/drivers/char/joystick/joy-warrior.c
deleted file mode 100644
index 232699859..000000000
--- a/drivers/char/joystick/joy-warrior.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * joy-warrior.c Version 0.1
- *
- * Copyright (c) 1998 David Thompson
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * the Logitech WingMan Warrior joystick.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-/*
- * Constants.
- */
-
-#define N_JOYSTICK_WAR 13
-#define JS_WAR_MAX_LENGTH 16
-
-/*
- * List of Warriors.
- */
-
-static struct js_port* js_war_port = NULL;
-
-static char js_war_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 };
-
-/*
- * Per-Warrior data.
- */
-
-struct js_war_info {
- struct tty_struct* tty;
- struct js_port* port;
- int idx;
- int len;
- unsigned char data[JS_WAR_MAX_LENGTH];
- char used;
-};
-
-/*
- * js_war_process_packet() decodes packets the driver receives from the
- * Warrior. It updates the data accordingly.
- */
-
-static void js_war_process_packet(struct js_war_info* info)
-{
- int **axes = info->port->axes;
- int **buttons = info->port->buttons;
- unsigned char *data = info->data;
- int i;
-
- if (!info->idx) return;
-
- switch ((data[0] >> 4) & 7) {
-
- case 1: /* Button data */
- if (!info->port->devs[0]) return;
- buttons[0][0] = ((data[3] & 0xa) >> 1) | ((data[3] & 0x5) << 1);
- return;
- case 3: /* XY-axis info->data */
- if (!info->port->devs[0]) return;
- axes[0][0] = ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5));
- axes[0][1] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7);
- return;
- break;
- case 5: /* Throttle, spinner, hat info->data */
- if (!info->port->devs[0]) return;
- axes[0][2] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7);
- axes[0][3] = (data[3] & 2 ? 1 : 0) - (info->data[3] & 1 ? 1 : 0);
- axes[0][4] = (data[3] & 8 ? 1 : 0) - (info->data[3] & 4 ? 1 : 0);
- axes[0][5] = (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5);
- return;
- case 2: /* Static status (Send !S to get one) */
- case 4: /* Dynamic status */
- return;
- default:
- printk("joy-warrior: Unknown packet %d length %d:", (data[0] >> 4) & 7, info->idx);
- for (i = 0; i < info->idx; i++)
- printk(" %02x", data[i]);
- printk("\n");
- return;
- }
-}
-
-/*
- * js_war_open() is a callback from the joystick device open routine.
- */
-
-static int js_war_open(struct js_dev *jd)
-{
- struct js_war_info *info = jd->port->info;
- info->used++;
- return 0;
-}
-
-/*
- * js_war_close() is a callback from the joystick device release routine.
- */
-
-static int js_war_close(struct js_dev *jd)
-{
- struct js_war_info *info = jd->port->info;
- if (!--info->used) {
- js_unregister_device(jd->port->devs[0]);
- js_war_port = js_unregister_port(jd->port);
- }
- return 0;
-}
-
-/*
- * js_war_init_corr() initializes the correction values for the Warrior.
- */
-
-static void __init js_war_init_corr(struct js_corr **corr)
-{
- int i;
-
- for (i = 0; i < 6; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = 0;
- corr[0][i].coef[0] = -8;
- corr[0][i].coef[1] = 8;
- corr[0][i].coef[2] = (1 << 29) / (128 - 64);
- corr[0][i].coef[3] = (1 << 29) / (128 - 64);
- }
-
- corr[0][2].coef[2] = (1 << 29) / (128 - 16);
- corr[0][2].coef[3] = (1 << 29) / (128 - 16);
-
- for (i = 3; i < 5; i++) {
- corr[0][i].coef[0] = 0;
- corr[0][i].coef[1] = 0;
- corr[0][i].coef[2] = (1 << 29);
- corr[0][i].coef[3] = (1 << 29);
- }
-
- corr[0][5].prec = -1;
- corr[0][5].coef[0] = 0;
- corr[0][5].coef[1] = 0;
- corr[0][5].coef[2] = (1 << 29) / 128;
- corr[0][5].coef[3] = (1 << 29) / 128;
-}
-
-/*
- * js_war_ldisc_open() is the routine that is called upon setting our line
- * discipline on a tty.
- */
-
-static int js_war_ldisc_open(struct tty_struct *tty)
-{
- struct js_war_info iniinfo;
- struct js_war_info *info = &iniinfo;
-
- MOD_INC_USE_COUNT;
-
- info->tty = tty;
- info->idx = 0;
- info->len = 0;
- info->used = 1;
-
- js_war_port = js_register_port(js_war_port, info, 1, sizeof(struct js_war_info), NULL);
-
- info = js_war_port->info;
- info->port = js_war_port;
- tty->disc_data = info;
-
- printk(KERN_INFO "js%d: WingMan Warrior on %s%d\n",
- js_register_device(js_war_port, 0, 6, 4, "WingMan Warrior", THIS_MODULE, js_war_open, js_war_close),
- tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
-
- js_war_init_corr(js_war_port->corr);
-
- return 0;
-}
-
-/*
- * js_war_ldisc_close() is the opposite of js_war_ldisc_open()
- */
-
-static void js_war_ldisc_close(struct tty_struct *tty)
-{
- struct js_war_info* info = (struct js_war_info*) tty->disc_data;
- if (!--info->used) {
- js_unregister_device(info->port->devs[0]);
- js_war_port = js_unregister_port(info->port);
- }
- MOD_DEC_USE_COUNT;
-}
-
-/*
- * js_war_ldisc_receive() 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 js_war_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
-{
- struct js_war_info* info = (struct js_war_info*) tty->disc_data;
- int i;
-
- for (i = 0; i < count; i++) {
- if (cp[i] & 0x80) {
- if (info->idx)
- js_war_process_packet(info);
- info->idx = 0;
- info->len = js_war_lengths[(cp[i] >> 4) & 7];
- }
-
- if (info->idx < JS_WAR_MAX_LENGTH)
- info->data[info->idx++] = cp[i];
-
- if (info->idx == info->len) {
- if (info->idx)
- js_war_process_packet(info);
- info->idx = 0;
- info->len = 0;
- }
- }
-}
-
-/*
- * js_war_ldisc_room() reports how much room we do have for receiving data.
- * Although we in fact have infinite room, we need to specify some value
- * here, so why not the size of our packet buffer. It's big anyway.
- */
-
-static int js_war_ldisc_room(struct tty_struct *tty)
-{
- return JS_WAR_MAX_LENGTH;
-}
-
-/*
- * The line discipline structure.
- */
-
-static struct tty_ldisc js_war_ldisc = {
- magic: TTY_LDISC_MAGIC,
- name: "warrior",
- open: js_war_ldisc_open,
- close: js_war_ldisc_close,
- receive_buf: js_war_ldisc_receive,
- receive_room: js_war_ldisc_room,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_war_init(void)
-#endif
-{
- if (tty_register_ldisc(N_JOYSTICK_WAR, &js_war_ldisc)) {
- printk(KERN_ERR "joy-warrior: Error registering line discipline.\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- tty_register_ldisc(N_JOYSTICK_WAR, NULL);
-}
-#endif
diff --git a/drivers/char/joystick/joystick.c b/drivers/char/joystick/joystick.c
deleted file mode 100644
index c9bd56ce3..000000000
--- a/drivers/char/joystick/joystick.c
+++ /dev/null
@@ -1,864 +0,0 @@
-/*
- * joystick.c Version 1.2
- *
- * Copyright (c) 1996-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is the main joystick driver for Linux. It doesn't support any
- * devices directly, rather is lets you use sub-modules to do that job. See
- * Documentation/joystick.txt for more info.
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/joystick.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/config.h>
-#include <linux/init.h>
-
-/*
- * Configurable parameters.
- */
-
-#define JS_REFRESH_TIME HZ/50 /* Time between two reads of joysticks (20ms) */
-
-/*
- * Exported symbols.
- */
-
-EXPORT_SYMBOL(js_register_port);
-EXPORT_SYMBOL(js_unregister_port);
-EXPORT_SYMBOL(js_register_device);
-EXPORT_SYMBOL(js_unregister_device);
-
-/*
- * Buffer macros.
- */
-
-#define ROT(A,B,C) ((((A)<(C))&&(((B)>(A))&&((B)<(C))))||(((A)>(C))&&(((B)>(A))||((B)<(C)))))
-#define GOF(X) (((X)==JS_BUFF_SIZE-1)?0:(X)+1)
-#define GOB(X) ((X)?(X)-1:JS_BUFF_SIZE-1)
-#define DIFF(X,Y) ((X)>(Y)?(X)-(Y):(Y)-(X))
-
-/*
- * Global variables.
- */
-
-static struct JS_DATA_SAVE_TYPE js_comp_glue;
-static struct js_port *js_port = NULL;
-static struct js_dev *js_dev = NULL;
-static struct timer_list js_timer;
-spinlock_t js_lock = SPIN_LOCK_UNLOCKED;
-static int js_use_count = 0;
-
-/*
- * Module info.
- */
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_SUPPORTED_DEVICE("js");
-
-/*
- * js_correct() performs correction of raw joystick data.
- */
-
-static int js_correct(int value, struct js_corr *corr)
-{
- switch (corr->type) {
- case JS_CORR_NONE:
- break;
- case JS_CORR_BROKEN:
- value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
- ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
- ((corr->coef[2] * (value - corr->coef[0])) >> 14);
- break;
-
- default:
- return 0;
- }
-
- if (value < -32767) return -32767;
- if (value > 32767) return 32767;
-
- return value;
-}
-
-/*
- * js_button() returns value of button number i.
- */
-
-static inline int js_button(int *buttons, int i)
-{
- return (buttons[i >> 5] >> (i & 0x1f)) & 1;
-}
-
-/*
- * js_add_event() adds an event to the buffer. This requires additional
- * queue post-processing done by js_sync_buff.
- */
-
-static void js_add_event(struct js_dev *jd, __u32 time, __u8 type, __u8 number, __s16 value)
-{
- jd->buff[jd->ahead].time = time;
- jd->buff[jd->ahead].type = type;
- jd->buff[jd->ahead].number = number;
- jd->buff[jd->ahead].value = value;
- if (++jd->ahead == JS_BUFF_SIZE) jd->ahead = 0;
-}
-
-/*
- * js_flush_data() does the same as js_process_data, except for that it doesn't
- * generate any events - it just copies the data from new to cur.
- */
-
-static void js_flush_data(struct js_dev *jd)
-{
- int i;
-
- for (i = 0; i < ((jd->num_buttons - 1) >> 5) + 1; i++)
- jd->cur.buttons[i] = jd->new.buttons[i];
- for (i = 0; i < jd->num_axes; i++)
- jd->cur.axes[i] = jd->new.axes[i];
-}
-
-/*
- * js_process_data() finds changes in button states and axis positions and adds
- * them as events to the buffer.
- */
-
-static void js_process_data(struct js_dev *jd)
-{
- int i, t;
-
- for (i = 0; i < jd->num_buttons; i++)
- if ((t = js_button(jd->new.buttons, i)) != js_button(jd->cur.buttons, i)) {
- js_add_event(jd, jiffies, JS_EVENT_BUTTON, i, t);
- jd->cur.buttons[i >> 5] ^= (1 << (i & 0x1f));
- }
-
- for (i = 0; i < jd->num_axes; i++) {
- t = js_correct(jd->new.axes[i], &jd->corr[i]);
- if (((jd->corr[i].prec == -1) && t) ||
- ((DIFF(jd->new.axes[i], jd->cur.axes[i]) > jd->corr[i].prec) &&
- (t != js_correct(jd->cur.axes[i], &jd->corr[i])))) {
- js_add_event(jd, jiffies, JS_EVENT_AXIS, i, t);
- jd->cur.axes[i] = jd->new.axes[i];
- }
- }
-}
-
-/*
- * js_sync_buff() checks for all overflows caused by recent additions to the buffer.
- * These happen only if some process is reading the data too slowly. It
- * wakes up any process waiting for data.
- */
-
-static void js_sync_buff(struct js_dev *jd)
-{
- struct js_list *curl = jd->list;
-
- if (jd->bhead != jd->ahead) {
- if(ROT(jd->bhead, jd->tail, jd->ahead) || (jd->tail == jd->bhead)) {
- while (curl) {
- if (ROT(jd->bhead, curl->tail, jd->ahead) || (curl->tail == jd->bhead)) {
- curl->tail = jd->ahead;
- curl->startup = 0;
- }
- curl = curl->next;
- }
- jd->tail = jd->ahead;
- }
- jd->bhead = jd->ahead;
- wake_up_interruptible(&jd->wait);
- }
-}
-
-/*
- * js_do_timer() acts as an interrupt replacement. It reads the data
- * from all ports and then generates events for all devices.
- */
-
-static void js_do_timer(unsigned long data)
-{
- struct js_port *curp = js_port;
- struct js_dev *curd = js_dev;
- unsigned long flags;
-
- while (curp) {
- if (curp->read)
- if (curp->read(curp->info, curp->axes, curp->buttons))
- curp->fail++;
- curp->total++;
- curp = curp->next;
- }
-
- spin_lock_irqsave(&js_lock, flags);
-
- while (curd) {
- if (data) {
- js_process_data(curd);
- js_sync_buff(curd);
- } else {
- js_flush_data(curd);
- }
- curd = curd->next;
- }
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- js_timer.expires = jiffies + JS_REFRESH_TIME;
- add_timer(&js_timer);
-}
-
-/*
- * js_read() copies one or more entries from jsd[].buff to user
- * space.
- */
-
-static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct js_event *buff = (void *) buf;
- struct js_list *curl;
- struct js_dev *jd;
- unsigned long blocks = count / sizeof(struct js_event);
- int written = 0;
- int new_tail, orig_tail;
- int retval = 0;
- unsigned long flags;
-
- curl = file->private_data;
- jd = curl->dev;
- orig_tail = curl->tail;
-
-/*
- * Check user data.
- */
-
- if (!blocks)
- return -EINVAL;
-
-/*
- * Lock it.
- */
-
- spin_lock_irqsave(&js_lock, flags);
-
-/*
- * Handle (non)blocking i/o.
- */
- if (count != sizeof(struct JS_DATA_TYPE)) {
-
- if (GOF(curl->tail) == jd->bhead && curl->startup == jd->num_axes + jd->num_buttons) {
-
- __set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&jd->wait, &wait);
-
- while (GOF(curl->tail) == jd->bhead) {
-
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-
- spin_unlock_irqrestore(&js_lock, flags);
- schedule();
- spin_lock_irqsave(&js_lock, flags);
-
- }
-
- current->state = TASK_RUNNING;
- remove_wait_queue(&jd->wait, &wait);
- }
-
- if (retval) {
- spin_unlock_irqrestore(&js_lock, flags);
- return retval;
- }
-
-/*
- * Initial state.
- */
-
- while (curl->startup < jd->num_axes + jd->num_buttons && written < blocks && !retval) {
-
- struct js_event tmpevent;
-
- if (curl->startup < jd->num_buttons) {
- tmpevent.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
- tmpevent.value = js_button(jd->cur.buttons, curl->startup);
- tmpevent.number = curl->startup;
- } else {
- tmpevent.type = JS_EVENT_AXIS | JS_EVENT_INIT;
- tmpevent.value = js_correct(jd->cur.axes[curl->startup - jd->num_buttons],
- &jd->corr[curl->startup - jd->num_buttons]);
- tmpevent.number = curl->startup - jd->num_buttons;
- }
-
- tmpevent.time = jiffies * (1000/HZ);
-
- if (copy_to_user(&buff[written], &tmpevent, sizeof(struct js_event)))
- retval = -EFAULT;
-
- curl->startup++;
- written++;
- }
-
-/*
- * Buffer data.
- */
-
- while ((jd->bhead != (new_tail = GOF(curl->tail))) && (written < blocks) && !retval) {
-
- if (copy_to_user(&buff[written], &jd->buff[new_tail], sizeof(struct js_event)))
- retval = -EFAULT;
- if (put_user((__u32)(jd->buff[new_tail].time * (1000/HZ)), &buff[written].time))
- retval = -EFAULT;
-
- curl->tail = new_tail;
- written++;
- }
- }
-
- else
-
-/*
- * Handle version 0.x compatibility.
- */
-
- {
- struct JS_DATA_TYPE data;
-
- data.buttons = jd->new.buttons[0];
- data.x = jd->num_axes < 1 ? 0 :
- ((js_correct(jd->new.axes[0], &jd->corr[0]) / 256) + 128) >> js_comp_glue.JS_CORR.x;
- data.y = jd->num_axes < 2 ? 0 :
- ((js_correct(jd->new.axes[1], &jd->corr[1]) / 256) + 128) >> js_comp_glue.JS_CORR.y;
-
- retval = copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
-
- curl->startup = jd->num_axes + jd->num_buttons;
- curl->tail = GOB(jd->bhead);
- if (!retval) retval = sizeof(struct JS_DATA_TYPE);
- }
-
-/*
- * Check main tail and move it.
- */
-
- if (orig_tail == jd->tail) {
- new_tail = curl->tail;
- curl = jd->list;
- while (curl && curl->tail != jd->tail) {
- if (ROT(jd->bhead, new_tail, curl->tail) ||
- (jd->bhead == curl->tail)) new_tail = curl->tail;
- curl = curl->next;
- }
- if (!curl) jd->tail = new_tail;
- }
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- return retval ? retval : written * sizeof(struct js_event);
-}
-
-/*
- * js_poll() does select() support.
- */
-
-static unsigned int js_poll(struct file *file, poll_table *wait)
-{
- struct js_list *curl = file->private_data;
- unsigned long flags;
- int retval = 0;
- poll_wait(file, &curl->dev->wait, wait);
- spin_lock_irqsave(&js_lock, flags);
- if (GOF(curl->tail) != curl->dev->bhead ||
- curl->startup < curl->dev->num_axes + curl->dev->num_buttons) retval = POLLIN | POLLRDNORM;
- spin_unlock_irqrestore(&js_lock, flags);
- return retval;
-}
-
-/*
- * js_ioctl handles misc ioctl calls.
- */
-
-static int js_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct js_list *curl;
- struct js_dev *jd;
- int len;
-
- curl = file->private_data;
- jd = curl->dev;
-
- switch (cmd) {
-
-/*
- * 0.x compatibility
- */
-
- case JS_SET_CAL:
- return copy_from_user(&js_comp_glue.JS_CORR, (struct JS_DATA_TYPE *) arg,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
- case JS_GET_CAL:
- return copy_to_user((struct JS_DATA_TYPE *) arg, &js_comp_glue.JS_CORR,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
- case JS_SET_TIMEOUT:
- return get_user(js_comp_glue.JS_TIMEOUT, (int *) arg);
- case JS_GET_TIMEOUT:
- return put_user(js_comp_glue.JS_TIMEOUT, (int *) arg);
- case JS_SET_TIMELIMIT:
- return get_user(js_comp_glue.JS_TIMELIMIT, (long *) arg);
- case JS_GET_TIMELIMIT:
- return put_user(js_comp_glue.JS_TIMELIMIT, (long *) arg);
- case JS_SET_ALL:
- return copy_from_user(&js_comp_glue, (struct JS_DATA_SAVE_TYPE *) arg,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
- case JS_GET_ALL:
- return copy_to_user((struct JS_DATA_SAVE_TYPE *) arg, &js_comp_glue,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
-
-/*
- * 1.x ioctl calls
- */
-
- case JSIOCGVERSION:
- return put_user(JS_VERSION, (__u32 *) arg);
- case JSIOCGAXES:
- return put_user(jd->num_axes, (__u8 *) arg);
- case JSIOCGBUTTONS:
- return put_user(jd->num_buttons, (__u8 *) arg);
- case JSIOCSCORR:
- return copy_from_user(jd->corr, (struct js_corr *) arg,
- sizeof(struct js_corr) * jd->num_axes) ? -EFAULT : 0;
- case JSIOCGCORR:
- return copy_to_user((struct js_corr *) arg, jd->corr,
- sizeof(struct js_corr) * jd->num_axes) ? -EFAULT : 0;
- default:
- if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
- len = strlen(jd->name) + 1;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- if (copy_to_user((char *) arg, jd->name, len)) return -EFAULT;
- return len;
- }
- }
-
- return -EINVAL;
-}
-
-/*
- * js_open() performs necessary initialization and adds
- * an entry to the linked list.
- */
-
-static int js_open(struct inode *inode, struct file *file)
-{
- struct js_list *curl, *new;
- struct js_dev *jd = js_dev;
- int i = MINOR(inode->i_rdev);
- unsigned long flags;
- int result;
-
- if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR)
- return -EINVAL;
-
-
- spin_lock_irqsave(&js_lock, flags);
-
- while (i > 0 && jd) {
- jd = jd->next;
- i--;
- }
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- if (!jd) return -ENODEV;
-
- if (jd->owner)
- __MOD_INC_USE_COUNT(jd->owner);
- if (jd->open && (result = jd->open(jd))) {
- if (jd->owner)
- __MOD_DEC_USE_COUNT(jd->owner);
- return result;
- }
-
- new = kmalloc(sizeof(struct js_list), GFP_KERNEL);
- if (!new) {
- if (jd->close)
- jd->close(jd);
- if (jd->owner)
- __MOD_DEC_USE_COUNT(jd->owner);
-
- return -ENOMEM;
- }
-
- spin_lock_irqsave(&js_lock, flags);
-
- curl = jd->list;
-
- jd->list = new;
- jd->list->next = curl;
- jd->list->dev = jd;
- jd->list->startup = 0;
- jd->list->tail = GOB(jd->bhead);
- file->private_data = jd->list;
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- if (!js_use_count++) js_do_timer(0);
-
- return 0;
-}
-
-/*
- * js_release() removes an entry from list and deallocates memory
- * used by it.
- */
-
-static int js_release(struct inode *inode, struct file *file)
-{
- struct js_list *curl = file->private_data;
- struct js_dev *jd = curl->dev;
- struct js_list **curp = &jd->list;
- int new_tail;
- unsigned long flags;
-
- spin_lock_irqsave(&js_lock, flags);
-
- while (*curp && (*curp != curl)) curp = &((*curp)->next);
- *curp = (*curp)->next;
-
- if (jd->list)
- if (curl->tail == jd->tail) {
- curl = jd->list;
- new_tail = curl->tail;
- while (curl && curl->tail != jd->tail) {
- if (ROT(jd->bhead, new_tail, curl->tail) ||
- (jd->bhead == curl->tail)) new_tail = curl->tail;
- curl = curl->next;
- }
- if (!curl) jd->tail = new_tail;
- }
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- kfree(file->private_data);
-
- if (!--js_use_count) del_timer(&js_timer);
-
- if (jd->close)
- jd->close(jd);
- if (jd->owner)
- __MOD_DEC_USE_COUNT(jd->owner);
-
- return 0;
-}
-
-/*
- * js_dump_mem() dumps all data structures in memory.
- * It's used for debugging only.
- */
-
-struct js_port *js_register_port(struct js_port *port,
- void *info, int devs, int infos, js_read_func read)
-{
- struct js_port **ptrp = &js_port;
- struct js_port *curp;
- void *all;
- int i;
- unsigned long flags;
-
- if (!(all = kmalloc(sizeof(struct js_port) + 4 * devs * sizeof(void*) + infos, GFP_KERNEL)))
- return NULL;
-
- curp = all;
-
- curp->next = NULL;
- curp->prev = port;
- curp->read = read;
- curp->ndevs = devs;
- curp->fail = 0;
- curp->total = 0;
-
- curp->devs = all += sizeof(struct js_port);
- for (i = 0; i < devs; i++) curp->devs[i] = NULL;
-
- curp->axes = all += devs * sizeof(void*);
- curp->buttons = (void*) all += devs * sizeof(void*);
- curp->corr = all += devs * sizeof(void*);
-
- if (infos) {
- curp->info = all += devs * sizeof(void*);
- memcpy(curp->info, info, infos);
- } else {
- curp->info = NULL;
- }
-
- spin_lock_irqsave(&js_lock, flags);
-
- while (*ptrp) ptrp=&((*ptrp)->next);
- *ptrp = curp;
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- return curp;
-}
-
-struct js_port *js_unregister_port(struct js_port *port)
-{
- struct js_port **curp = &js_port;
- struct js_port *prev;
- unsigned long flags;
-
- spin_lock_irqsave(&js_lock, flags);
-
- printk("js: There were %d failures out of %d read attempts.\n", port->fail, port->total);
-
- while (*curp && (*curp != port)) curp = &((*curp)->next);
- *curp = (*curp)->next;
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- prev = port->prev;
- kfree(port);
-
- return prev;
-}
-
-extern struct file_operations js_fops;
-
-static devfs_handle_t devfs_handle = NULL;
-
-int js_register_device(struct js_port *port, int number, int axes,
- int buttons, char *name, struct module *owner,
- js_ops_func open, js_ops_func close)
-{
- struct js_dev **ptrd = &js_dev;
- struct js_dev *curd;
- void *all;
- int i = 0;
- unsigned long flags;
- char devfs_name[8];
-
- if (!(all = kmalloc(sizeof(struct js_dev) + 2 * axes * sizeof(int) +
- 2 * (((buttons - 1) >> 5) + 1) * sizeof(int) +
- axes * sizeof(struct js_corr) + strlen(name) + 1, GFP_KERNEL)))
- return -1;
-
- curd = all;
-
- curd->next = NULL;
- curd->list = NULL;
- curd->port = port;
- curd->open = open;
- curd->close = close;
- curd->owner = owner;
-
- init_waitqueue_head(&curd->wait);
-
- curd->ahead = 0;
- curd->bhead = 0;
- curd->tail = JS_BUFF_SIZE - 1;
- curd->num_axes = axes;
- curd->num_buttons = buttons;
-
- curd->cur.axes = all += sizeof(struct js_dev);
- curd->cur.buttons = all += axes * sizeof(int);
- curd->new.axes = all += (((buttons - 1) >> 5) + 1) * sizeof(int);
- curd->new.buttons = all += axes * sizeof(int);
- curd->corr = all += (((buttons -1 ) >> 5) + 1) * sizeof(int);
-
- curd->name = all += axes * sizeof(struct js_corr);
- strcpy(curd->name, name);
-
- port->devs[number] = curd;
- port->axes[number] = curd->new.axes;
- port->buttons[number] = curd->new.buttons;
- port->corr[number] = curd->corr;
-
- spin_lock_irqsave(&js_lock, flags);
-
- while (*ptrd) { ptrd=&(*ptrd)->next; i++; }
- *ptrd = curd;
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- sprintf(devfs_name, "js%d", i);
- curd->devfs_handle = devfs_register(devfs_handle, devfs_name, 0,
- DEVFS_FL_DEFAULT,
- JOYSTICK_MAJOR, i,
- S_IFCHR | S_IRUGO | S_IWUSR, 0, 0,
- &js_fops, NULL);
-
- return i;
-}
-
-void js_unregister_device(struct js_dev *dev)
-{
- struct js_dev **curd = &js_dev;
- unsigned long flags;
-
- spin_lock_irqsave(&js_lock, flags);
-
- while (*curd && (*curd != dev)) curd = &((*curd)->next);
- *curd = (*curd)->next;
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- devfs_unregister(dev->devfs_handle);
- kfree(dev);
-}
-
-/*
- * The operations structure.
- */
-
-static struct file_operations js_fops =
-{
- owner: THIS_MODULE,
- read: js_read,
- poll: js_poll,
- ioctl: js_ioctl,
- open: js_open,
- release: js_release,
-};
-
-/*
- * js_init() registers the driver and calls the probe function.
- * also initializes some crucial variables.
- */
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_init(void)
-#endif
-{
-
- if (devfs_register_chrdev(JOYSTICK_MAJOR, "js", &js_fops)) {
- printk(KERN_ERR "js: unable to get major %d for joystick\n", JOYSTICK_MAJOR);
- return -EBUSY;
- }
- devfs_handle = devfs_mk_dir(NULL, "joysticks", 9, NULL);
-
- printk(KERN_INFO "js: Joystick driver v%d.%d.%d (c) 1999 Vojtech Pavlik <vojtech@suse.cz>\n",
- JS_VERSION >> 16 & 0xff, JS_VERSION >> 8 & 0xff, JS_VERSION & 0xff);
-
- spin_lock_init(&js_lock);
-
- init_timer(&js_timer);
- js_timer.function = js_do_timer;
- js_timer.data = 1;
-
- memset(&js_comp_glue, 0, sizeof(struct JS_DATA_SAVE_TYPE));
- js_comp_glue.JS_TIMEOUT = JS_DEF_TIMEOUT;
- js_comp_glue.JS_TIMELIMIT = JS_DEF_TIMELIMIT;
-
-#ifndef MODULE
-#ifdef CONFIG_JOY_PCI
- js_pci_init();
-#endif
-#ifdef CONFIG_JOY_LIGHTNING
- js_l4_init();
-#endif
-#ifdef CONFIG_JOY_SIDEWINDER
- js_sw_init();
-#endif
-#ifdef CONFIG_JOY_ASSASSIN
- js_as_init();
-#endif
-#ifdef CONFIG_JOY_LOGITECH
- js_lt_init();
-#endif
-#ifdef CONFIG_JOY_THRUSTMASTER
- js_tm_init();
-#endif
-#ifdef CONFIG_JOY_GRAVIS
- js_gr_init();
-#endif
-#ifdef CONFIG_JOY_CREATIVE
- js_cr_init();
-#endif
-#ifdef CONFIG_JOY_ANALOG
- js_an_init();
-#endif
-#ifdef CONFIG_JOY_CONSOLE
- js_console_init();
-#endif
-#ifdef CONFIG_JOY_DB9
- js_db9_init();
-#endif
-#ifdef CONFIG_JOY_TURBOGRAFX
- js_tg_init();
-#endif
-#ifdef CONFIG_JOY_AMIGA
- js_am_init();
-#endif
-#ifdef CONFIG_JOY_MAGELLAN
- js_mag_init();
-#endif
-#ifdef CONFIG_JOY_WARRIOR
- js_war_init();
-#endif
-#ifdef CONFIG_JOY_SPACEORB
- js_orb_init();
-#endif
-#ifdef CONFIG_JOY_SPACEBALL
- js_sball_init();
-#endif
-#endif
-
- return 0;
-}
-
-/*
- * cleanup_module() handles module removal.
- */
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- del_timer(&js_timer);
- devfs_unregister(devfs_handle);
- if (devfs_unregister_chrdev(JOYSTICK_MAJOR, "js"))
- printk(KERN_ERR "js: can't unregister device\n");
-}
-#endif
-
diff --git a/drivers/char/joystick/lightning.c b/drivers/char/joystick/lightning.c
new file mode 100644
index 000000000..69dfd1112
--- /dev/null
+++ b/drivers/char/joystick/lightning.c
@@ -0,0 +1,300 @@
+/*
+ * $Id: lightning.c,v 1.7 2000/05/24 19:36:03 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * 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 <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, 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/malloc.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 <vojtech@suse.cz>");
+
+struct l4 {
+ struct gameport gameport;
+ unsigned char port;
+} *l4_port[8];
+
+/*
+ * 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;
+
+ gameport = &l4->gameport;
+ gameport->driver = l4;
+ gameport->open = l4_open;
+ gameport->cooked_read = l4_cooked_read;
+ gameport->calibrate = l4_calibrate;
+ gameport->type = GAMEPORT_EXT;
+
+ if (!i && !j) {
+ gameport->io = L4_PORT;
+ gameport->size = 1;
+ }
+
+ if (rev > 0x28) /* on 2.9+ the setcal command works correctly */
+ l4_setcal(l4->port, cal);
+
+ gameport_register_port(gameport);
+ }
+
+ printk(KERN_INFO "gameport%d,%d,%d,%d: PDPI Lightning 4 %s card v%d.%d at %#x\n",
+ l4_port[i * 4 + 0]->gameport.number, l4_port[i * 4 + 1]->gameport.number,
+ l4_port[i * 4 + 2]->gameport.number, l4_port[i * 4 + 3]->gameport.number,
+ 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);
diff --git a/drivers/char/joystick/magellan.c b/drivers/char/joystick/magellan.c
new file mode 100644
index 000000000..e8c77f48e
--- /dev/null
+++ b/drivers/char/joystick/magellan.c
@@ -0,0 +1,210 @@
+/*
+ * $Id: magellan.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Magellan and Space Mouse 6dof controller driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define MAGELLAN_MAX_LENGTH 32
+
+static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8};
+static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ};
+static char *magellan_name = "LogiCad3D Magellan";
+
+/*
+ * Per-Magellan data.
+ */
+
+struct magellan {
+ struct input_dev dev;
+ int idx;
+ unsigned char data[MAGELLAN_MAX_LENGTH];
+};
+
+/*
+ * magellan_crunch_nibbles() verifies that the bytes sent from the Magellan
+ * have correct upper nibbles for the lower ones, if not, the packet will
+ * be thrown away. It also strips these upper halves to simplify further
+ * processing.
+ */
+
+static int magellan_crunch_nibbles(unsigned char *data, int count)
+{
+ static unsigned char nibbles[16] = "0AB3D56GH9:K<MN?";
+
+ do {
+ if (data[count] == nibbles[data[count] & 0xf])
+ data[count] = data[count] & 0xf;
+ else
+ return -1;
+ } while (--count);
+
+ return 0;
+}
+
+static void magellan_process_packet(struct magellan* magellan)
+{
+ struct input_dev *dev = &magellan->dev;
+ unsigned char *data = magellan->data;
+ int i, t;
+
+ if (!magellan->idx) return;
+
+ switch (magellan->data[0]) {
+
+ case 'd': /* Axis data */
+ if (magellan->idx != 25) return;
+ if (magellan_crunch_nibbles(data, 24)) return;
+ for (i = 0; i < 6; i++)
+ input_report_abs(dev, magellan_axes[i],
+ (data[(i << 2) + 1] << 12 | data[(i << 2) + 2] << 8 |
+ data[(i << 2) + 3] << 4 | data[(i << 2) + 4]) - 32768);
+ break;
+
+ case 'k': /* Button data */
+ if (magellan->idx != 4) return;
+ if (magellan_crunch_nibbles(data, 3)) return;
+ t = (data[1] << 1) | (data[2] << 5) | data[3];
+ for (i = 0; i < 9; i++) input_report_key(dev, magellan_buttons[i], (t >> i) & 1);
+ break;
+ }
+}
+
+static void magellan_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct magellan* magellan = serio->private;
+
+ if (data == '\r') {
+ magellan_process_packet(magellan);
+ magellan->idx = 0;
+ } else {
+ if (magellan->idx < MAGELLAN_MAX_LENGTH)
+ magellan->data[magellan->idx++] = data;
+ }
+}
+
+/*
+ * magellan_disconnect() is the opposite of magellan_connect()
+ */
+
+static void magellan_disconnect(struct serio *serio)
+{
+ struct magellan* magellan = serio->private;
+ input_unregister_device(&magellan->dev);
+ serio_close(serio);
+ kfree(magellan);
+}
+
+/*
+ * magellan_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the Magellan, and if found, registers
+ * it as an input device.
+ */
+
+static void magellan_connect(struct serio *serio, struct serio_dev *dev)
+{
+ struct magellan *magellan;
+ int i, t;
+
+ if (serio->type != (SERIO_RS232 | SERIO_MAGELLAN))
+ return;
+
+ if (!(magellan = kmalloc(sizeof(struct magellan), GFP_KERNEL)))
+ return;
+
+ memset(magellan, 0, sizeof(struct magellan));
+
+ magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (i = 0; i < 9; i++)
+ set_bit(magellan_buttons[i], &magellan->dev.keybit);
+
+ for (i = 0; i < 6; i++) {
+ t = magellan_axes[i];
+ set_bit(t, magellan->dev.absbit);
+ magellan->dev.absmin[t] = -360;
+ magellan->dev.absmax[t] = 360;
+ }
+
+ magellan->dev.private = magellan;
+ magellan->dev.name = magellan_name;
+ magellan->dev.idbus = BUS_RS232;
+ magellan->dev.idvendor = SERIO_MAGELLAN;
+ magellan->dev.idproduct = 0x0001;
+ magellan->dev.idversion = 0x0100;
+
+ serio->private = magellan;
+
+ if (serio_open(serio, dev)) {
+ kfree(magellan);
+ return;
+ }
+
+ input_register_device(&magellan->dev);
+
+ printk(KERN_INFO "input%d: %s on serio%d\n", magellan->dev.number, magellan_name, serio->number);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev magellan_dev = {
+ interrupt: magellan_interrupt,
+ connect: magellan_connect,
+ disconnect: magellan_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init magellan_init(void)
+{
+ serio_register_device(&magellan_dev);
+ return 0;
+}
+
+void __exit magellan_exit(void)
+{
+ serio_unregister_device(&magellan_dev);
+}
+
+module_init(magellan_init);
+module_exit(magellan_exit);
diff --git a/drivers/char/joystick/ns558.c b/drivers/char/joystick/ns558.c
new file mode 100644
index 000000000..f34a18640
--- /dev/null
+++ b/drivers/char/joystick/ns558.c
@@ -0,0 +1,366 @@
+/*
+ * $Id: ns558.c,v 1.11 2000/06/20 23:35:03 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ * Copyright (c) 1999 Brian Gerst
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * NS558 based standard IBM game port driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, 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/malloc.h>
+#include <linux/isapnp.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+
+#define NS558_ISA 1
+#define NS558_PNP 2
+#define NS558_PCI 3
+
+static int ns558_isa_portlist[] = { 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
+ 0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
+
+struct ns558 {
+ int type;
+ struct pci_dev *dev;
+ struct ns558 *next;
+ struct gameport gameport;
+};
+
+static struct ns558 *ns558 = NULL;
+
+/*
+ * ns558_isa_probe() tries to find an isa gameport at the
+ * specified address, and also checks for mirrors.
+ * A joystick must be attached for this to work.
+ */
+
+static struct ns558* ns558_isa_probe(int io, struct ns558 *next)
+{
+ int i, j, b;
+ unsigned char c, u, v;
+ struct ns558 *port;
+
+/*
+ * No one should be using this address.
+ */
+
+ if (check_region(io, 1))
+ return next;
+
+/*
+ * We must not be able to write arbitrary values to the port.
+ * The lower two axis bits must be 1 after a write.
+ */
+
+ c = inb(io);
+ outb(~c & ~3, io);
+ if (~(u = v = inb(io)) & 3) {
+ outb(c, io);
+ return next;
+ }
+/*
+ * After a trigger, there must be at least some bits changing.
+ */
+
+ for (i = 0; i < 1000; i++) v &= inb(io);
+
+ if (u == v) {
+ outb(c, io);
+ return next;
+ }
+ wait_ms(3);
+/*
+ * After some time (4ms) the axes shouldn't change anymore.
+ */
+
+ u = inb(io);
+ for (i = 0; i < 1000; i++)
+ if ((u ^ inb(io)) & 0xf) {
+ outb(c, io);
+ return next;
+ }
+/*
+ * And now find the number of mirrors of the port.
+ */
+
+ for (i = 1; i < 5; i++) {
+
+ if (check_region(io & (-1 << i), (1 << i))) /* Don't disturb anyone */
+ break;
+
+ outb(0xff, io & (-1 << i));
+ for (j = b = 0; j < 1000; j++)
+ if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
+ wait_ms(3);
+
+ if (b > 300) /* We allow 30% difference */
+ break;
+ }
+
+ i--;
+
+ if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
+ printk(KERN_ERR "Memory allocation failed.\n");
+ return next;
+ }
+ memset(port, 0, sizeof(struct ns558));
+
+ port->next = next;
+ port->type = NS558_ISA;
+ port->gameport.io = io;
+ port->gameport.size = (1 << i);
+
+ request_region(port->gameport.io, port->gameport.size, "ns558-isa");
+
+ gameport_register_port(&port->gameport);
+
+ printk(KERN_INFO "gameport%d: NS558 ISA at %#x", port->gameport.number, port->gameport.io);
+ if (port->gameport.size > 1) printk(" size %d", port->gameport.size);
+ printk(" speed %d kHz\n", port->gameport.speed);
+
+ return port;
+}
+
+#ifdef CONFIG_PCI
+static struct pci_device_id ns558_pci_tbl[] __devinitdata = {
+ { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB Live! gameport */
+ { 0x125d, 0x1969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, /* ESS Solo 1 */
+ { 0x5333, 0xca00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, /* S3 SonicVibes */
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, ns558_pci_tbl);
+
+static int __devinit ns558_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int ioport, iolen;
+ int rc;
+ struct ns558 *port;
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ printk(KERN_ERR "ns558: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
+ pdev->bus->number, pdev->devfn, rc);
+ return rc;
+ }
+
+ ioport = pci_resource_start(pdev, ent->driver_data);
+ iolen = pci_resource_len(pdev, ent->driver_data);
+
+ if (!request_region(ioport, iolen, "ns558-pci"))
+ return -EBUSY;
+
+ if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
+ printk(KERN_ERR "Memory allocation failed.\n");
+ return -ENOMEM;
+ }
+ memset(port, 0, sizeof(struct ns558));
+
+ port->next = ns558;
+ port->type = NS558_PCI;
+ port->gameport.io = ioport;
+ port->gameport.size = iolen;
+ port->dev = pdev;
+ ns558 = port;
+
+ pdev->driver_data = port;
+
+ gameport_register_port(&port->gameport);
+
+ printk(KERN_INFO "gameport%d: NS558 PCI at %#x", port->gameport.number, port->gameport.io);
+ if (port->gameport.size > 1) printk(" size %d", port->gameport.size);
+ printk(" speed %d kHz\n", port->gameport.speed);
+
+ return 0;
+}
+
+static void __devexit ns558_pci_remove(struct pci_dev *pdev)
+{
+ struct ns558 *port = (struct ns558 *)pdev->driver_data;
+ release_region(port->gameport.io, port->gameport.size);
+}
+
+static struct pci_driver ns558_pci_driver = {
+ name: "PCI Gameport",
+ id_table: ns558_pci_tbl,
+ probe: ns558_pci_probe,
+ remove: ns558_pci_remove,
+};
+#endif /* CONFIG_PCI */
+
+
+#ifdef CONFIG_ISAPNP
+/*
+ * PnP IDs:
+ *
+ * CTL00c1 - SB AWE32 PnP
+ * CTL00c3 - SB AWE64 PnP
+ * CTL00f0 - SB16 PnP / Vibra 16x
+ * CTL7001 - SB Vibra16C PnP
+ * CSC0b35 - Crystal ** doesn't have compatibility ID **
+ * TER1141 - Terratec AD1818
+ * YMM0800 - Yamaha OPL3-SA3
+ *
+ * PNPb02f - Generic gameport
+ */
+
+static struct pnp_devid {
+ unsigned int vendor, device;
+} pnp_devids[] = {
+ { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002) },
+ { ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35) },
+ { ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f) },
+ { 0, },
+};
+
+static struct ns558* ns558_pnp_probe(struct pci_dev *dev, struct ns558 *next)
+{
+ int ioport, iolen;
+ struct ns558 *port;
+
+ if (dev->prepare && dev->prepare(dev) < 0)
+ return next;
+
+ if (!(dev->resource[0].flags & IORESOURCE_IO)) {
+ printk(KERN_WARNING "No i/o ports on a gameport? Weird\n");
+ return next;
+ }
+
+ if (dev->activate && dev->activate(dev) < 0) {
+ printk(KERN_ERR "PnP resource allocation failed\n");
+ return next;
+ }
+
+ ioport = pci_resource_start(dev, 0);
+ iolen = pci_resource_len(dev, 0);
+
+ if (!request_region(ioport, iolen, "ns558-pnp"))
+ goto deactivate;
+
+ if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
+ printk(KERN_ERR "Memory allocation failed.\n");
+ goto deactivate;
+ }
+ memset(port, 0, sizeof(struct ns558));
+
+ port->next = next;
+ port->type = NS558_PNP;
+ port->gameport.io = ioport;
+ port->gameport.size = iolen;
+ port->dev = dev;
+
+ gameport_register_port(&port->gameport);
+
+ printk(KERN_INFO "gameport%d: NS558 PnP at %#x", port->gameport.number, port->gameport.io);
+ if (port->gameport.size > 1) printk(" size %d", port->gameport.size);
+ printk(" speed %d kHz\n", port->gameport.speed);
+
+ return port;
+
+deactivate:
+ if (dev->deactivate)
+ dev->deactivate(dev);
+ return next;
+}
+#endif
+
+int __init ns558_init(void)
+{
+ int i = 0;
+#ifdef CONFIG_ISAPNP
+ struct pci_dev *dev = NULL;
+ struct pnp_devid *devid;
+#endif
+
+/*
+ * Probe for ISA ports.
+ */
+
+ while (ns558_isa_portlist[i])
+ ns558 = ns558_isa_probe(ns558_isa_portlist[i++], ns558);
+
+/*
+ * Probe for PCI ports.
+ */
+#ifdef CONFIG_PCI
+ pci_register_driver(&ns558_pci_driver);
+#endif
+
+/*
+ * Probe for PnP ports.
+ */
+
+#ifdef CONFIG_ISAPNP
+ for (devid = pnp_devids; devid->vendor; devid++) {
+ while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->device, dev))) {
+ ns558 = ns558_pnp_probe(dev, ns558);
+ }
+ }
+#endif
+
+ return -!ns558;
+}
+
+void __exit ns558_exit(void)
+{
+ struct ns558 *port = ns558;
+
+ while (port) {
+ gameport_unregister_port(&port->gameport);
+ switch (port->type) {
+
+#ifdef CONFIG_ISAPNP
+ case NS558_PNP:
+ if (port->dev->deactivate)
+ port->dev->deactivate(port->dev);
+ /* fall through */
+#endif
+
+ case NS558_ISA:
+ release_region(port->gameport.io, port->gameport.size);
+ break;
+
+ default:
+ break;
+ }
+
+ port = port->next;
+ }
+
+#ifdef CONFIG_PCI
+ pci_unregister_driver(&ns558_pci_driver);
+#endif
+}
+
+module_init(ns558_init);
+module_exit(ns558_exit);
diff --git a/drivers/char/joystick/pcigame.c b/drivers/char/joystick/pcigame.c
new file mode 100644
index 000000000..0348ba08b
--- /dev/null
+++ b/drivers/char/joystick/pcigame.c
@@ -0,0 +1,198 @@
+/*
+ * $Id: pcigame.c,v 1.6 2000/05/25 12:05:24 vojtech Exp $
+ *
+ * Copyright (c) 2000 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Raymond Ingles
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * 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 <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, 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/pci_ids.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+
+#define PCI_VENDOR_ID_AUREAL 0x12eb
+
+#define PCIGAME_DATA_WAIT 20 /* 20 ms */
+
+#define PCIGAME_4DWAVE 0
+#define PCIGAME_VORTEX 1
+#define PCIGAME_VORTEX2 2
+
+struct pcigame_data {
+ int gcr; /* Gameport control register */
+ int legacy; /* Legacy port location */
+ int axes; /* Axes start */
+ int axsize; /* Axis field size */
+ int axmax; /* Axis field max value */
+ int adcmode; /* Value to enable ADC mode in GCR */
+};
+
+static struct pcigame_data pcigame_data[] __devinitdata =
+{{ 0x00030, 0x00031, 0x00034, 2, 0xffff, 0x80 },
+ { 0x1100c, 0x11008, 0x11010, 4, 0x1fff, 0x40 },
+ { 0x2880c, 0x28808, 0x28810, 4, 0x1fff, 0x40 },
+ { 0 }};
+
+struct pcigame {
+ struct gameport gameport;
+ struct pci_dev *dev;
+ unsigned char *base;
+ struct pcigame_data *data;
+};
+
+static unsigned char pcigame_read(struct gameport *gameport)
+{
+ struct pcigame *pcigame = gameport->driver;
+ return readb(pcigame->base + pcigame->data->legacy);
+}
+
+static void pcigame_trigger(struct gameport *gameport)
+{
+ struct pcigame *pcigame = gameport->driver;
+ writeb(0xff, pcigame->base + pcigame->data->legacy);
+}
+
+static int pcigame_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+ struct pcigame *pcigame = gameport->driver;
+ int i;
+
+ *buttons = (~readb(pcigame->base + pcigame->data->legacy) >> 4) & 0xf;
+
+ for (i = 0; i < 4; i++) {
+ axes[i] = readw(pcigame->base + pcigame->data->axes + i * pcigame->data->axsize);
+ if (axes[i] == pcigame->data->axmax) axes[i] = -1;
+ }
+
+ return 0;
+}
+
+static int pcigame_open(struct gameport *gameport, int mode)
+{
+ struct pcigame *pcigame = gameport->driver;
+
+ switch (mode) {
+ case GAMEPORT_MODE_COOKED:
+ writeb(pcigame->data->adcmode, pcigame->base + pcigame->data->gcr);
+ wait_ms(PCIGAME_DATA_WAIT);
+ return 0;
+ case GAMEPORT_MODE_RAW:
+ writeb(0, pcigame->base + pcigame->data->gcr);
+ return 0;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct pcigame *pcigame;
+ int i;
+
+ if (!(pcigame = kmalloc(sizeof(struct pcigame), GFP_KERNEL)))
+ return -1;
+ memset(pcigame, 0, sizeof(struct pcigame));
+
+
+ pcigame->data = pcigame_data + id->driver_data;
+
+ pcigame->dev = dev;
+ dev->driver_data = pcigame;
+
+ pcigame->gameport.driver = pcigame;
+ pcigame->gameport.type = GAMEPORT_EXT;
+ pcigame->gameport.fuzz = 64;
+
+ pcigame->gameport.read = pcigame_read;
+ pcigame->gameport.trigger = pcigame_trigger;
+ pcigame->gameport.cooked_read = pcigame_cooked_read;
+ pcigame->gameport.open = pcigame_open;
+
+ for (i = 0; i < 6; i++)
+ if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
+ break;
+
+ pci_enable_device(dev);
+
+ pcigame->base = ioremap(pci_resource_start(pcigame->dev, i),
+ pci_resource_len(pcigame->dev, i));
+
+ gameport_register_port(&pcigame->gameport);
+
+ printk(KERN_INFO "gameport%d: %s at pci%02x:%02x.%x speed %d kHz\n",
+ pcigame->gameport.number, dev->name, dev->bus->number,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), pcigame->gameport.speed);
+
+ return 0;
+}
+
+static void __devexit pcigame_remove(struct pci_dev *dev)
+{
+ struct pcigame *pcigame = dev->driver_data;
+ gameport_unregister_port(&pcigame->gameport);
+ iounmap(pcigame->base);
+ kfree(pcigame);
+}
+
+static struct pci_device_id pcigame_id_table[] __devinitdata =
+{{ PCI_VENDOR_ID_TRIDENT, 0x2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE },
+ { PCI_VENDOR_ID_TRIDENT, 0x2001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE },
+ { PCI_VENDOR_ID_AUREAL, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX },
+ { PCI_VENDOR_ID_AUREAL, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX2 },
+ { 0 }};
+
+static struct pci_driver pcigame_driver = {
+ name: "pcigame",
+ id_table: pcigame_id_table,
+ probe: pcigame_probe,
+ remove: pcigame_remove,
+};
+
+int __init pcigame_init(void)
+{
+ return pci_module_init(&pcigame_driver);
+}
+
+void __exit pcigame_exit(void)
+{
+ pci_unregister_driver(&pcigame_driver);
+}
+
+module_init(pcigame_init);
+module_exit(pcigame_exit);
diff --git a/drivers/char/joystick/serio.c b/drivers/char/joystick/serio.c
new file mode 100644
index 000000000..9595f0a6c
--- /dev/null
+++ b/drivers/char/joystick/serio.c
@@ -0,0 +1,132 @@
+/*
+ * $Id: serio.c,v 1.5 2000/06/04 17:44:59 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * The Serio abstraction module
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+
+EXPORT_SYMBOL(serio_register_port);
+EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_register_device);
+EXPORT_SYMBOL(serio_unregister_device);
+EXPORT_SYMBOL(serio_open);
+EXPORT_SYMBOL(serio_close);
+EXPORT_SYMBOL(serio_rescan);
+
+static struct serio *serio_list = NULL;
+static struct serio_dev *serio_dev = NULL;
+static int serio_number = 0;
+
+static void serio_find_dev(struct serio *serio)
+{
+ struct serio_dev *dev = serio_dev;
+
+ while (dev && !serio->dev) {
+ if (dev->connect)
+ dev->connect(serio, dev);
+ dev = dev->next;
+ }
+}
+
+void serio_rescan(struct serio *serio)
+{
+ if (serio->dev && serio->dev->disconnect)
+ serio->dev->disconnect(serio);
+ serio_find_dev(serio);
+}
+
+void serio_register_port(struct serio *serio)
+{
+ serio->number = serio_number++;
+ serio->next = serio_list;
+ serio_list = serio;
+ serio_find_dev(serio);
+}
+
+void serio_unregister_port(struct serio *serio)
+{
+ struct serio **serioptr = &serio_list;
+
+ while (*serioptr && (*serioptr != serio)) serioptr = &((*serioptr)->next);
+ *serioptr = (*serioptr)->next;
+
+ if (serio->dev && serio->dev->disconnect)
+ serio->dev->disconnect(serio);
+
+ serio_number--;
+}
+
+void serio_register_device(struct serio_dev *dev)
+{
+ struct serio *serio = serio_list;
+
+ dev->next = serio_dev;
+ serio_dev = dev;
+
+ while (serio) {
+ if (!serio->dev && dev->connect)
+ dev->connect(serio, dev);
+ serio = serio->next;
+ }
+}
+
+void serio_unregister_device(struct serio_dev *dev)
+{
+ struct serio_dev **devptr = &serio_dev;
+ struct serio *serio = serio_list;
+
+ while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
+ *devptr = (*devptr)->next;
+
+ while (serio) {
+ if (serio->dev == dev && dev->disconnect)
+ dev->disconnect(serio);
+ serio_find_dev(serio);
+ serio = serio->next;
+ }
+}
+
+int serio_open(struct serio *serio, struct serio_dev *dev)
+{
+ if (serio->open(serio))
+ return -1;
+ serio->dev = dev;
+ return 0;
+}
+
+void serio_close(struct serio *serio)
+{
+ serio->close(serio);
+ serio->dev = NULL;
+}
diff --git a/drivers/char/joystick/serport.c b/drivers/char/joystick/serport.c
new file mode 100644
index 000000000..453e674d7
--- /dev/null
+++ b/drivers/char/joystick/serport.c
@@ -0,0 +1,220 @@
+/*
+ * $Id: serport.c,v 1.4 2000/05/29 10:54:53 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * This is a module that converts a tty line into a much simpler
+ * 'serial io port' abstraction that the input device drivers use.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+#include <linux/tty.h>
+
+struct serport {
+ struct tty_struct *tty;
+ wait_queue_head_t wait;
+ struct serio serio;
+};
+
+/*
+ * Callback functions from the serio code.
+ */
+
+static int serport_serio_write(struct serio *serio, unsigned char data)
+{
+ struct serport *serport = serio->driver;
+ return -(serport->tty->driver.write(serport->tty, 0, &data, 1) != 1);
+}
+
+static int serport_serio_open(struct serio *serio)
+{
+ return 0;
+}
+
+static void serport_serio_close(struct serio *serio)
+{
+ struct serport *serport = serio->driver;
+ wake_up_interruptible(&serport->wait);
+}
+
+/*
+ * serport_ldisc_open() is the routine that is called upon setting our line
+ * discipline on a tty. It looks for the Mag, and if found, registers
+ * it as a joystick device.
+ */
+
+static int serport_ldisc_open(struct tty_struct *tty)
+{
+ struct serport *serport;
+
+ MOD_INC_USE_COUNT;
+
+ if (!(serport = kmalloc(sizeof(struct serport), GFP_KERNEL))) {
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+
+ memset(serport, 0, sizeof(struct serport));
+
+ serport->tty = tty;
+ tty->disc_data = serport;
+
+ serport->serio.type = SERIO_RS232;
+ serport->serio.write = serport_serio_write;
+ serport->serio.open = serport_serio_open;
+ serport->serio.close = serport_serio_close;
+ serport->serio.driver = serport;
+
+ init_waitqueue_head(&serport->wait);
+
+ return 0;
+}
+
+/*
+ * serport_ldisc_close() is the opposite of serport_ldisc_open()
+ */
+
+static void serport_ldisc_close(struct tty_struct *tty)
+{
+ struct serport *serport = (struct serport*) tty->disc_data;
+ kfree(serport);
+ MOD_DEC_USE_COUNT;
+}
+
+/*
+ * serport_ldisc_receive() is called by the low level tty driver when characters
+ * are ready for us. We forward the characters, one by one to the 'interrupt'
+ * routine.
+ */
+
+static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+{
+ struct serport *serport = (struct serport*) tty->disc_data;
+ int i;
+ for (i = 0; i < count; i++)
+ if (serport->serio.dev)
+ serport->serio.dev->interrupt(&serport->serio, cp[i], 0);
+}
+
+/*
+ * serport_ldisc_room() reports how much room we do have for receiving data.
+ * Although we in fact have infinite room, we need to specify some value
+ * here, and 256 seems to be reasonable.
+ */
+
+static int serport_ldisc_room(struct tty_struct *tty)
+{
+ return 256;
+}
+
+/*
+ * serport_ldisc_read() just waits indefinitely if everything goes well.
+ * However, when the serio driver closes the serio port, it finishes,
+ * returning 0 characters.
+ */
+
+static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char * buf, size_t nr)
+{
+ struct serport *serport = (struct serport*) tty->disc_data;
+ DECLARE_WAITQUEUE(wait, current);
+ char name[32];
+
+ sprintf(name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
+
+ serio_register_port(&serport->serio);
+
+ printk(KERN_INFO "serio%d: Serial port %s\n", serport->serio.number, name);
+
+ add_wait_queue(&serport->wait, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+
+ while(serport->serio.type && !signal_pending(current)) schedule();
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&serport->wait, &wait);
+
+ serio_unregister_port(&serport->serio);
+
+ return 0;
+}
+
+/*
+ * serport_ldisc_ioctl() allows to set the port protocol, and device ID
+ */
+
+static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct serport *serport = (struct serport*) tty->disc_data;
+
+ switch (cmd) {
+ case SPIOCSTYPE:
+ return get_user(serport->serio.type, (unsigned long *) arg);
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * The line discipline structure.
+ */
+
+static struct tty_ldisc serport_ldisc = {
+ name: "input",
+ open: serport_ldisc_open,
+ close: serport_ldisc_close,
+ read: serport_ldisc_read,
+ ioctl: serport_ldisc_ioctl,
+ receive_buf: serport_ldisc_receive,
+ receive_room: serport_ldisc_room,
+};
+
+/*
+ * The functions for insering/removing us as a module.
+ */
+
+int __init serport_init(void)
+{
+ if (tty_register_ldisc(N_MOUSE, &serport_ldisc)) {
+ printk(KERN_ERR "serport.c: Error registering line discipline.\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+void __exit serport_exit(void)
+{
+ tty_register_ldisc(N_MOUSE, NULL);
+}
+
+module_init(serport_init);
+module_exit(serport_exit);
diff --git a/drivers/char/joystick/sidewinder.c b/drivers/char/joystick/sidewinder.c
new file mode 100644
index 000000000..861966b4e
--- /dev/null
+++ b/drivers/char/joystick/sidewinder.c
@@ -0,0 +1,756 @@
+/*
+ * $Id: sidewinder.c,v 1.14 2000/05/29 11:27:55 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Microsoft SideWinder joystick family driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/gameport.h>
+
+/*
+ * These are really magic values. Changing them can make a problem go away,
+ * as well as break everything.
+ */
+
+#undef SW_DEBUG
+
+#define SW_START 400 /* The time we wait for the first bit [400 us] */
+#define SW_STROBE 45 /* Max time per bit [45 us] */
+#define SW_TIMEOUT 4000 /* Wait for everything to settle [4 ms] */
+#define SW_KICK 45 /* Wait after A0 fall till kick [45 us] */
+#define SW_END 8 /* Number of bits before end of packet to kick */
+#define SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */
+#define SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */
+#define SW_OK 64 /* Number of packet read successes to switch optimization back on */
+#define SW_LENGTH 512 /* Max number of bits in a packet */
+#define SW_REFRESH HZ/50 /* Time to wait between updates of joystick data [20 ms] */
+
+#ifdef SW_DEBUG
+#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+
+/*
+ * SideWinder joystick types ...
+ */
+
+#define SW_ID_3DP 0
+#define SW_ID_GP 1
+#define SW_ID_PP 2
+#define SW_ID_FFP 3
+#define SW_ID_FSP 4
+#define SW_ID_FFW 5
+
+/*
+ * Names, buttons, axes ...
+ */
+
+static char *sw_name[] = { "3D Pro", "GamePad", "Precision Pro", "Force Feedback Pro", "FreeStyle Pro",
+ "Force Feedback Wheel" };
+
+static char sw_abs[][7] = {
+ { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
+ { ABS_X, ABS_Y },
+ { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
+ { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
+ { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
+ { ABS_RX, ABS_RUDDER, ABS_THROTTLE }};
+
+static char sw_bit[][7] = {
+ { 10, 10, 9, 10, 1, 1 },
+ { 1, 1 },
+ { 10, 10, 6, 7, 1, 1 },
+ { 10, 10, 6, 7, 1, 1 },
+ { 10, 10, 6, 1, 1 },
+ { 10, 7, 7, 1, 1 }};
+
+static short sw_btn[][12] = {
+ { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_MODE },
+ { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE },
+ { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
+ { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
+ { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT },
+ { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3 }};
+
+static struct {
+ int x;
+ int y;
+} sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+struct sw {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct input_dev dev[4];
+ char name[64];
+ int length;
+ int type;
+ int bits;
+ int number;
+ int fail;
+ int ok;
+ int reads;
+ int bads;
+ int used;
+};
+
+/*
+ * sw_read_packet() is a function which reads either a data packet, or an
+ * identification packet from a SideWinder joystick. The protocol is very,
+ * very, very braindamaged. Microsoft patented it in US patent #5628686.
+ */
+
+static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int length, int id)
+{
+ unsigned long flags;
+ int timeout, bitout, sched, i, kick, start, strobe;
+ unsigned char pending, u, v;
+
+ i = -id; /* Don't care about data, only want ID */
+ timeout = id ? gameport_time(gameport, SW_TIMEOUT) : 0; /* Set up global timeout for ID packet */
+ kick = id ? gameport_time(gameport, SW_KICK) : 0; /* Set up kick timeout for ID packet */
+ start = gameport_time(gameport, SW_START);
+ strobe = gameport_time(gameport, SW_STROBE);
+ bitout = start;
+ pending = 0;
+ sched = 0;
+
+ __save_flags(flags); /* Quiet, please */
+ __cli();
+
+ gameport_trigger(gameport); /* Trigger */
+ v = gameport_read(gameport);
+
+ do {
+ bitout--;
+ u = v;
+ v = gameport_read(gameport);
+ } while (!(~v & u & 0x10) && (bitout > 0)); /* Wait for first falling edge on clock */
+
+ if (bitout > 0) bitout = strobe; /* Extend time if not timed out */
+
+ while ((timeout > 0 || bitout > 0) && (i < length)) {
+
+ timeout--;
+ bitout--; /* Decrement timers */
+ sched--;
+
+ u = v;
+ v = gameport_read(gameport);
+
+ if ((~u & v & 0x10) && (bitout > 0)) { /* Rising edge on clock - data bit */
+ if (i >= 0) /* Want this data */
+ buf[i] = v >> 5; /* Store it */
+ i++; /* Advance index */
+ bitout = strobe; /* Extend timeout for next bit */
+ }
+
+ if (kick && (~v & u & 0x01)) { /* Falling edge on axis 0 */
+ sched = kick; /* Schedule second trigger */
+ kick = 0; /* Don't schedule next time on falling edge */
+ pending = 1; /* Mark schedule */
+ }
+
+ if (pending && sched < 0 && (i > -SW_END)) { /* Second trigger time */
+ gameport_trigger(gameport); /* Trigger */
+ bitout = start; /* Long bit timeout */
+ pending = 0; /* Unmark schedule */
+ timeout = 0; /* Switch from global to bit timeouts */
+ }
+ }
+
+ __restore_flags(flags); /* Done - relax */
+
+#ifdef SW_DEBUG
+ {
+ int j;
+ printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i);
+ for (j = 0; j < i; j++) printk("%d", buf[j]);
+ printk("]\n");
+ }
+#endif
+
+ return i;
+}
+
+/*
+ * sw_get_bits() and GB() compose bits from the triplet buffer into a __u64.
+ * Parameter 'pos' is bit number inside packet where to start at, 'num' is number
+ * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
+ * is number of bits per triplet.
+ */
+
+#define GB(pos,num) sw_get_bits(buf, pos, num, sw->bits)
+
+static __u64 sw_get_bits(unsigned char *buf, int pos, int num, char bits)
+{
+ __u64 data = 0;
+ int tri = pos % bits; /* Start position */
+ int i = pos / bits;
+ int bit = 0;
+
+ while (num--) {
+ data |= (__u64)((buf[i] >> tri++) & 1) << bit++; /* Transfer bit */
+ if (tri == bits) {
+ i++; /* Next triplet */
+ tri = 0;
+ }
+ }
+
+ return data;
+}
+
+/*
+ * sw_init_digital() initializes a SideWinder 3D Pro joystick
+ * into digital mode.
+ */
+
+static void sw_init_digital(struct gameport *gameport)
+{
+ int seq[] = { 140, 140+725, 140+300, 0 };
+ unsigned long flags;
+ int i, t;
+
+ __save_flags(flags);
+ __cli();
+
+ i = 0;
+ do {
+ gameport_trigger(gameport); /* Trigger */
+ t = gameport_time(gameport, SW_TIMEOUT);
+ while ((gameport_read(gameport) & 1) && t) t--; /* Wait for axis to fall back to 0 */
+ udelay(seq[i]); /* Delay magic time */
+ } while (seq[++i]);
+
+ gameport_trigger(gameport); /* Last trigger */
+
+ __restore_flags(flags);
+}
+
+/*
+ * sw_parity() computes parity of __u64
+ */
+
+static int sw_parity(__u64 t)
+{
+ int x = t ^ (t >> 32);
+ x ^= x >> 16;
+ x ^= x >> 8;
+ x ^= x >> 4;
+ x ^= x >> 2;
+ x ^= x >> 1;
+ return x & 1;
+}
+
+/*
+ * sw_ccheck() checks synchronization bits and computes checksum of nibbles.
+ */
+
+static int sw_check(__u64 t)
+{
+ unsigned char sum = 0;
+
+ if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */
+ return -1;
+
+ while (t) { /* Sum */
+ sum += t & 0xf;
+ t >>= 4;
+ }
+
+ return sum & 0xf;
+}
+
+/*
+ * sw_parse() analyzes SideWinder joystick data, and writes the results into
+ * the axes and buttons arrays.
+ */
+
+static int sw_parse(unsigned char *buf, struct sw *sw)
+{
+ int hat, i, j;
+ struct input_dev *dev = sw->dev;
+
+ switch (sw->type) {
+
+ case SW_ID_3DP:
+
+ if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) return -1;
+
+ input_report_abs(dev, ABS_X, (GB( 3,3) << 7) | GB(16,7));
+ input_report_abs(dev, ABS_Y, (GB( 0,3) << 7) | GB(24,7));
+ input_report_abs(dev, ABS_RZ, (GB(35,2) << 7) | GB(40,7));
+ input_report_abs(dev, ABS_THROTTLE, (GB(32,3) << 7) | GB(48,7));
+
+ input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
+ input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
+
+ for (j = 0; j < 7; j++)
+ input_report_key(dev, sw_btn[SW_ID_3DP][j], !GB(j+8,1));
+
+ input_report_key(dev, BTN_BASE4, !GB(38,1));
+ input_report_key(dev, BTN_BASE5, !GB(37,1));
+
+ return 0;
+
+ case SW_ID_GP:
+
+ for (i = 0; i < sw->number; i ++) {
+
+ if (sw_parity(GB(i*15,15))) return -1;
+
+ input_report_key(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1));
+ input_report_key(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
+
+ for (j = 0; j < 10; j++)
+ input_report_key(dev, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1));
+ }
+
+ return 0;
+
+ case SW_ID_PP:
+ case SW_ID_FFP:
+
+ if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) return -1;
+
+ input_report_abs(dev, ABS_X, GB( 9,10));
+ input_report_abs(dev, ABS_Y, GB(19,10));
+ input_report_abs(dev, ABS_RZ, GB(36, 6));
+ input_report_abs(dev, ABS_THROTTLE, GB(29, 7));
+
+ input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
+ input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
+
+ for (j = 0; j < 9; j++)
+ input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1));
+
+ return 0;
+
+ case SW_ID_FSP:
+
+ if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) return -1;
+
+ input_report_abs(dev, ABS_X, GB( 0,10));
+ input_report_abs(dev, ABS_Y, GB(16,10));
+ input_report_abs(dev, ABS_THROTTLE, GB(32, 6));
+
+ input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
+ input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
+
+ for (j = 0; j < 6; j++)
+ input_report_key(dev, sw_btn[SW_ID_FSP][j], !GB(j+10,1));
+
+ input_report_key(dev, BTN_TR, GB(26,1));
+ input_report_key(dev, BTN_START, GB(27,1));
+ input_report_key(dev, BTN_MODE, GB(38,1));
+ input_report_key(dev, BTN_SELECT, GB(39,1));
+
+ return 0;
+
+ case SW_ID_FFW:
+
+ if (!sw_parity(GB(0,33))) return -1;
+
+ input_report_abs(dev, ABS_RX, GB( 0,10));
+ input_report_abs(dev, ABS_RUDDER, GB(10, 6));
+ input_report_abs(dev, ABS_THROTTLE, GB(16, 6));
+
+ for (j = 0; j < 8; j++)
+ input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1));
+
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * sw_read() reads SideWinder joystick data, and reinitializes
+ * the joystick in case of persistent problems. This is the function that is
+ * called from the generic code to poll the joystick.
+ */
+
+static int sw_read(struct sw *sw)
+{
+ unsigned char buf[SW_LENGTH];
+ int i;
+
+ i = sw_read_packet(sw->gameport, buf, sw->length, 0);
+
+ if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) { /* Broken packet, try to fix */
+
+ if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) { /* Last init failed, 1 bit mode */
+ printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on gameport%d"
+ " - going to reinitialize.\n", sw->gameport->number);
+ sw->fail = SW_FAIL; /* Reinitialize */
+ i = 128; /* Bogus value */
+ }
+
+ if (i < 66 && GB(0,64) == GB(i*3-66,64)) /* 1 == 3 */
+ i = 66; /* Everything is fine */
+
+ if (i < 66 && GB(0,64) == GB(66,64)) /* 1 == 2 */
+ i = 66; /* Everything is fine */
+
+ if (i < 66 && GB(i*3-132,64) == GB(i*3-66,64)) { /* 2 == 3 */
+ memmove(buf, buf + i - 22, 22); /* Move data */
+ i = 66; /* Carry on */
+ }
+ }
+
+ if (i == sw->length && !sw_parse(buf, sw)) { /* Parse data */
+
+ sw->fail = 0;
+ sw->ok++;
+
+ if (sw->type == SW_ID_3DP && sw->length == 66 /* Many packets OK */
+ && sw->ok > SW_OK) {
+
+ printk(KERN_INFO "sidewinder.c: No more trouble on gameport%d"
+ " - enabling optimization again.\n", sw->gameport->number);
+ sw->length = 22;
+ }
+
+ return 0;
+ }
+
+ sw->ok = 0;
+ sw->fail++;
+
+ if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) { /* Consecutive bad packets */
+
+ printk(KERN_INFO "sidewinder.c: Many bit errors on gameport%d"
+ " - disabling optimization.\n", sw->gameport->number);
+ sw->length = 66;
+ }
+
+ if (sw->fail < SW_FAIL) return -1; /* Not enough, don't reinitialize yet */
+
+ printk(KERN_WARNING "sidewinder.c: Too many bit errors on gameport%d"
+ " - reinitializing joystick.\n", sw->gameport->number);
+
+ if (!i && sw->type == SW_ID_3DP) { /* 3D Pro can be in analog mode */
+ udelay(3 * SW_TIMEOUT);
+ sw_init_digital(sw->gameport);
+ }
+
+ udelay(SW_TIMEOUT);
+ i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0); /* Read normal data packet */
+ udelay(SW_TIMEOUT);
+ sw_read_packet(sw->gameport, buf, SW_LENGTH, i); /* Read ID packet, this initializes the stick */
+
+ sw->fail = SW_FAIL;
+
+ return -1;
+}
+
+static void sw_timer(unsigned long private)
+{
+ struct sw *sw = (void *) private;
+
+ sw->reads++;
+ if (sw_read(sw)) sw->bads++;
+ mod_timer(&sw->timer, jiffies + SW_REFRESH);
+}
+
+static int sw_open(struct input_dev *dev)
+{
+ struct sw *sw = dev->private;
+ if (!sw->used++)
+ mod_timer(&sw->timer, jiffies + SW_REFRESH);
+ return 0;
+}
+
+static void sw_close(struct input_dev *dev)
+{
+ struct sw *sw = dev->private;
+ if (!--sw->used)
+ del_timer(&sw->timer);
+}
+
+/*
+ * sw_print_packet() prints the contents of a SideWinder packet.
+ */
+
+static void sw_print_packet(char *name, int length, unsigned char *buf, char bits)
+{
+ int i;
+
+ printk(KERN_INFO "sidewinder.c: %s packet, %d bits. [", name, length);
+ for (i = (((length + 3) >> 2) - 1); i >= 0; i--)
+ printk("%x", (int)sw_get_bits(buf, i << 2, 4, bits));
+ printk("]\n");
+}
+
+/*
+ * sw_3dp_id() translates the 3DP id into a human legible string.
+ * Unfortunately I don't know how to do this for the other SW types.
+ */
+
+static void sw_3dp_id(unsigned char *buf, char *comment)
+{
+ int i;
+ char pnp[8], rev[9];
+
+ for (i = 0; i < 7; i++) /* ASCII PnP ID */
+ pnp[i] = sw_get_bits(buf, 24+8*i, 8, 1);
+
+ for (i = 0; i < 8; i++) /* ASCII firmware revision */
+ rev[i] = sw_get_bits(buf, 88+8*i, 8, 1);
+
+ pnp[7] = rev[8] = 0;
+
+ sprintf(comment, " [PnP %d.%02d id %s rev %s]",
+ (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | /* Two 6-bit values */
+ sw_get_bits(buf, 16, 6, 1)) / 100,
+ (int) ((sw_get_bits(buf, 8, 6, 1) << 6) |
+ sw_get_bits(buf, 16, 6, 1)) % 100,
+ pnp, rev);
+}
+
+/*
+ * sw_guess_mode() checks the upper two button bits for toggling -
+ * indication of that the joystick is in 3-bit mode. This is documented
+ * behavior for 3DP ID packet, and for example the FSP does this in
+ * normal packets instead. Fun ...
+ */
+
+static int sw_guess_mode(unsigned char *buf, int len)
+{
+ int i;
+ unsigned char xor = 0;
+ for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6;
+ return !!xor * 2 + 1;
+}
+
+/*
+ * sw_connect() probes for SideWinder type joysticks.
+ */
+
+static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct sw *sw;
+ int i, j, k, l;
+ unsigned char buf[SW_LENGTH];
+ unsigned char idbuf[SW_LENGTH];
+ unsigned char m = 1;
+ char comment[40];
+
+ comment[0] = 0;
+
+ if (!(sw = kmalloc(sizeof(struct sw), GFP_KERNEL))) return;
+ memset(sw, 0, sizeof(struct sw));
+
+ gameport->private = sw;
+
+ sw->gameport = gameport;
+ init_timer(&sw->timer);
+ sw->timer.data = (long) sw;
+ sw->timer.function = sw_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ goto fail1;
+
+ i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read normal packet */
+ m |= sw_guess_mode(buf, i); /* Data packet (1-bit) can carry mode info [FSP] */
+ udelay(SW_TIMEOUT);
+ dbg("Init 1: Mode %d. Length %d.", m , i);
+
+ if (!i) { /* No data. 3d Pro analog mode? */
+ sw_init_digital(gameport); /* Switch to digital */
+ udelay(SW_TIMEOUT);
+ i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */
+ udelay(SW_TIMEOUT);
+ dbg("Init 1b: Length %d.", i);
+ if (!i) goto fail2; /* No data -> FAIL */
+ }
+
+ j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Read ID. This initializes the stick */
+ m |= sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */
+ dbg("Init 2: Mode %d. ID Length %d.", m , j);
+
+ if (!j) { /* Read ID failed. Happens in 1-bit mode on PP */
+ udelay(SW_TIMEOUT);
+ i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */
+ dbg("Init 2b: Mode %d. Length %d.", m, i);
+ if (!i) goto fail2;
+ udelay(SW_TIMEOUT);
+ j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Retry reading ID */
+ dbg("Init 2c: ID Length %d.", j);
+ }
+
+ sw->type = -1;
+ k = SW_FAIL; /* Try SW_FAIL times */
+ l = 0;
+
+ do {
+ k--;
+ udelay(SW_TIMEOUT);
+ i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read data packet */
+ dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k);
+
+ if (i > l) { /* Longer? As we can only lose bits, it makes */
+ /* no sense to try detection for a packet shorter */
+ l = i; /* than the previous one */
+
+ sw->number = 1;
+ sw->gameport = gameport;
+ sw->length = i;
+ sw->bits = m;
+
+ dbg("Init 3a: Case %d.\n", i * m);
+
+ switch (i * m) {
+ case 60:
+ sw->number++;
+ case 45: /* Ambiguous packet length */
+ if (j <= 40) { /* ID length less or eq 40 -> FSP */
+ case 43:
+ sw->type = SW_ID_FSP;
+ break;
+ }
+ sw->number++;
+ case 30:
+ sw->number++;
+ case 15:
+ sw->type = SW_ID_GP;
+ break;
+ case 33:
+ case 31:
+ sw->type = SW_ID_FFW;
+ break;
+ case 48: /* Ambiguous */
+ if (j == 14) { /* ID length 14*3 -> FFP */
+ sw->type = SW_ID_FFP;
+ sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on");
+ } else
+ sw->type = SW_ID_PP;
+ break;
+ case 198:
+ sw->length = 22;
+ case 64:
+ sw->type = SW_ID_3DP;
+ if (j == 160) sw_3dp_id(idbuf, comment);
+ break;
+ }
+ }
+
+ } while (k && (sw->type == -1));
+
+ if (sw->type == -1) {
+ printk(KERN_WARNING "sidewinder.c: unknown joystick device detected "
+ "on gameport%d, contact <vojtech@suse.cz>\n", gameport->number);
+ sw_print_packet("ID", j * 3, idbuf, 3);
+ sw_print_packet("Data", i * m, buf, m);
+ goto fail2;
+ }
+
+#ifdef SW_DEBUG
+ sw_print_packet("ID", j * 3, idbuf, 3);
+ sw_print_packet("Data", i * m, buf, m);
+#endif
+
+ k = i;
+ l = j;
+
+ for (i = 0; i < sw->number; i++) {
+ int bits, code;
+
+ sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]);
+
+ sw->dev[i].private = sw;
+
+ sw->dev[i].open = sw_open;
+ sw->dev[i].close = sw_close;
+
+ sw->dev[i].name = sw->name;
+ sw->dev[i].idbus = BUS_GAMEPORT;
+ sw->dev[i].idvendor = GAMEPORT_ID_VENDOR_MICROSOFT;
+ sw->dev[i].idproduct = sw->type;
+ sw->dev[i].idversion = 0x0100;
+
+ sw->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (j = 0; (bits = sw_bit[sw->type][j]); j++) {
+ code = sw_abs[sw->type][j];
+ set_bit(code, sw->dev[i].absbit);
+ sw->dev[i].absmax[code] = (1 << bits) - 1;
+ sw->dev[i].absmin[code] = (bits == 1) ? -1 : 0;
+ sw->dev[i].absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0;
+ if (code != ABS_THROTTLE)
+ sw->dev[i].absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0;
+ }
+
+ for (j = 0; (code = sw_btn[sw->type][j]); j++)
+ set_bit(code, sw->dev[i].keybit);
+
+ input_register_device(sw->dev + i);
+ printk(KERN_INFO "input%d: %s%s on gameport%d.%d [%d-bit id %d data %d]\n",
+ sw->dev[i].number, sw->name, comment, gameport->number, i, m, l, k);
+ }
+
+ return;
+fail2: gameport_close(gameport);
+fail1: kfree(sw);
+}
+
+static void sw_disconnect(struct gameport *gameport)
+{
+ int i;
+
+ struct sw *sw = gameport->private;
+ for (i = 0; i < sw->number; i++)
+ input_unregister_device(sw->dev + i);
+ gameport_close(gameport);
+ kfree(sw);
+}
+
+static struct gameport_dev sw_dev = {
+ connect: sw_connect,
+ disconnect: sw_disconnect,
+};
+
+int __init sw_init(void)
+{
+ gameport_register_device(&sw_dev);
+ return 0;
+}
+
+void __exit sw_exit(void)
+{
+ gameport_unregister_device(&sw_dev);
+}
+
+module_init(sw_init);
+module_exit(sw_exit);
diff --git a/drivers/char/joystick/spaceball.c b/drivers/char/joystick/spaceball.c
new file mode 100644
index 000000000..4f5059330
--- /dev/null
+++ b/drivers/char/joystick/spaceball.c
@@ -0,0 +1,231 @@
+/*
+ * $Id: spaceball.c,v 1.6 2000/05/29 11:19:51 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * David Thompson
+ * Joseph Krahn
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * SpaceTec SpaceBall 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 <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+
+/*
+ * Constants.
+ */
+
+#define JS_SBALL_MAX_LENGTH 128
+static int spaceball_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
+static char *spaceball_name = "SpaceTec SpaceBall 4000 FLX";
+
+/*
+ * Per-Ball data.
+ */
+
+struct spaceball {
+ struct input_dev dev;
+ struct serio *serio;
+ int idx;
+ int escape;
+ unsigned char data[JS_SBALL_MAX_LENGTH];
+};
+
+/*
+ * 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, d;
+
+ if (spaceball->idx < 2) return;
+
+ switch (spaceball->data[0]) {
+
+ case '@': /* Reset packet */
+ spaceball->data[spaceball->idx - 1] = 0;
+ for (i = 1; i < spaceball->idx && spaceball->data[i] == ' '; i++);
+ printk(KERN_INFO "input%d: %s [%s] on serio%d\n",
+ spaceball->dev.number, spaceball_name, spaceball->data + i, spaceball->serio->number);
+ break;
+
+ case 'D': /* Ball data */
+ if (spaceball->idx != 16) return;
+ for (i = 0; i < 6; i++) {
+ d = ((data[2 * i + 3] << 8) | data[2 * i + 2]);
+ input_report_abs(dev, spaceball_axes[i], d - ((d & 0x8000) ? 0x10000 : 0));
+ }
+ break;
+
+ case '.': /* Button data, part2 */
+ if (spaceball->idx != 4) return;
+ input_report_key(dev, BTN_LEFT, data[2] & 1);
+ input_report_key(dev, BTN_RIGHT, data[2] & 2);
+ break;
+
+ case '?': /* Error packet */
+ spaceball->data[spaceball->idx - 1] = 0;
+ printk(KERN_ERR "spaceball: Device error. [%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 0x0d characters which can
+ * occur in the axis values. ^M, ^Q and ^S all mean 0x0d, depending (I think)
+ * on whether the axis value is increasing, decreasing, or same as before.
+ * (I don't see why this is useful).
+ */
+
+static void spaceball_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct spaceball *spaceball = serio->private;
+
+ switch (data) {
+ case 0xd:
+ if (spaceball->idx)
+ spaceball_process_packet(spaceball);
+ spaceball->idx = 0;
+ spaceball->escape = 0;
+ return;
+ case 'M':
+ case 'Q':
+ case 'S':
+ if (spaceball->escape)
+ data = 0xd;
+ case '^':
+ spaceball->escape ^= 1;
+ default:
+ if (spaceball->escape) {
+ printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x\n", data);
+ spaceball->escape = 0;
+ }
+ if (spaceball->idx < JS_SBALL_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;
+
+ if (serio->type != (SERIO_RS232 | SERIO_SPACEBALL))
+ 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);
+ spaceball->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
+
+ for (i = 0; i < 6; i++) {
+ t = spaceball_axes[i];
+ set_bit(t, spaceball->dev.absbit);
+ spaceball->dev.absmin[t] = i < 3 ? -10000 : -2000;
+ spaceball->dev.absmax[t] = i < 3 ? 10000 : 2000;
+ spaceball->dev.absflat[t] = i < 3 ? 50 : 10;
+ spaceball->dev.absfuzz[t] = i < 3 ? 12 : 2;
+ }
+
+ spaceball->serio = serio;
+ spaceball->dev.private = spaceball;
+
+ spaceball->dev.name = spaceball_name;
+ spaceball->dev.idbus = BUS_RS232;
+ spaceball->dev.idvendor = SERIO_SPACEBALL;
+ spaceball->dev.idproduct = 0x0001;
+ spaceball->dev.idversion = 0x0100;
+
+ serio->private = spaceball;
+
+ if (serio_open(serio, dev)) {
+ kfree(spaceball);
+ return;
+ }
+
+ input_register_device(&spaceball->dev);
+}
+
+/*
+ * 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);
diff --git a/drivers/char/joystick/spaceorb.c b/drivers/char/joystick/spaceorb.c
new file mode 100644
index 000000000..866e1ba50
--- /dev/null
+++ b/drivers/char/joystick/spaceorb.c
@@ -0,0 +1,225 @@
+/*
+ * $Id: spaceorb.c,v 1.7 2000/05/29 11:19:51 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * David Thompson
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * 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 <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+
+/*
+ * Constants.
+ */
+
+#define SPACEORB_MAX_LENGTH 64
+
+static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A, BTN_MODE};
+static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ};
+static char *spaceorb_name = "SpaceTec SpaceOrb 360";
+
+/*
+ * Per-Orb data.
+ */
+
+struct spaceorb {
+ struct input_dev dev;
+ struct serio *serio;
+ int idx;
+ unsigned char data[SPACEORB_MAX_LENGTH];
+};
+
+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%d: %s [%s] on serio%d\n",
+ spaceorb->dev.number, spaceorb_name, spaceorb->data + i, spaceorb->serio->number);
+ 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 < 8; 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 < 7; 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;
+
+ spaceorb->dev.name = spaceorb_name;
+ 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);
diff --git a/drivers/char/joystick/tmdc.c b/drivers/char/joystick/tmdc.c
new file mode 100644
index 000000000..f356f7dd5
--- /dev/null
+++ b/drivers/char/joystick/tmdc.c
@@ -0,0 +1,348 @@
+/*
+ * $Id: tmdc.c,v 1.18 2000/06/08 19:59:59 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ *
+ * 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 <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#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_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_PAD 10
+#define TMDC_BTN_JOY 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 unsigned char tmdc_abs[TMDC_ABS] =
+ { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ };
+static unsigned char tmdc_abs_hat[TMDC_ABS_HAT] =
+ { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
+static unsigned short tmdc_btn_pad[TMDC_BTN_PAD] =
+ { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
+static unsigned short tmdc_btn_joy[TMDC_BTN_JOY] =
+ { 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 };
+
+struct tmdc {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct input_dev dev[2];
+ char name[2][64];
+ int mode[2];
+ 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;
+
+ tmdc->reads++;
+
+ if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists)
+ bad = 1;
+
+ 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 < data[j][TMDC_BYTE_DEF] >> 4; i++)
+ input_report_abs(dev, tmdc_abs[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));
+
+ for (i = 0; i < 4; i++)
+ input_report_key(dev, tmdc_btn_joy[i],
+ (data[j][tmdc_byte_d[0]] >> (i + 4)) & 1);
+ for (i = 0; i < 2; i++)
+ input_report_key(dev, tmdc_btn_joy[i + 4],
+ (data[j][tmdc_byte_d[1]] >> (i + 6)) & 1);
+
+ break;
+
+ case TMDC_MODE_3DRP:
+ case TMDC_MODE_FGP:
+
+ for (i = 0; i < 10; i++)
+ input_report_key(dev, tmdc_btn_pad[i],
+ (data[j][tmdc_byte_d[i >> 3]] >> (i & 7)) & 1);
+
+ break;
+
+ default:
+
+ for (i = 0; i < ((data[j][TMDC_BYTE_DEF] & 0xf) << 3) && i < TMDC_BTN_JOY; i++)
+ input_report_key(dev, tmdc_btn_joy[i],
+ (data[j][tmdc_byte_d[i >> 3]] >> (i & 7)) & 1);
+
+ break;
+
+ }
+ }
+
+ 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 tmdc *tmdc;
+ struct js_tm_models {
+ unsigned char id;
+ char *name;
+ char abs;
+ char hats;
+ char joybtn;
+ char padbtn;
+ } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 0, 6, 0 },
+ { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, 0, 10 },
+ { 163, "Thrustmaster Fusion GamePad", 2, 0, 0, 10 },
+ { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, 0, 0 }};
+ unsigned char data[2][TMDC_MAX_LENGTH];
+ int i, j, 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++);
+
+ if (!models[m].id) {
+ models[m].abs = data[j][TMDC_BYTE_DEF] >> 4;
+ models[m].joybtn = (data[j][TMDC_BYTE_DEF] & 0xf) << 3;
+ }
+
+ sprintf(tmdc->name[j], models[m].name, models[m].abs, models[m].joybtn, tmdc->mode[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].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++) {
+ set_bit(tmdc_abs[i], tmdc->dev[j].absbit);
+ tmdc->dev[j].absmin[tmdc_abs[i]] = 8;
+ tmdc->dev[j].absmax[tmdc_abs[i]] = 248;
+ tmdc->dev[j].absfuzz[tmdc_abs[i]] = 2;
+ tmdc->dev[j].absflat[tmdc_abs[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 (i = 0; i < models[m].joybtn && i < TMDC_BTN_JOY; i++)
+ set_bit(tmdc_btn_joy[i], tmdc->dev[j].keybit);
+
+ for (i = 0; i < models[m].padbtn && i < TMDC_BTN_PAD; i++)
+ set_bit(tmdc_btn_pad[i], tmdc->dev[j].keybit);
+
+ input_register_device(tmdc->dev + j);
+ printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
+ tmdc->dev[j].number, tmdc->name[j], gameport->number, j);
+ }
+
+ 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);
diff --git a/drivers/char/joystick/turbografx.c b/drivers/char/joystick/turbografx.c
new file mode 100644
index 000000000..0e2dedcd0
--- /dev/null
+++ b/drivers/char/joystick/turbografx.c
@@ -0,0 +1,258 @@
+/*
+ * $Id: turbografx.c,v 1.8 2000/05/29 20:39:38 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Steffen Schwenke
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * 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 <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, 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 <vojtech@suse.cz>");
+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];
+ 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;
+
+ tgfx->dev[i].name = tgfx_name;
+ 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: %d-button Multisystem joystick on %s\n",
+ tgfx->dev[i].number, 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);
diff --git a/drivers/char/joystick/warrior.c b/drivers/char/joystick/warrior.c
new file mode 100644
index 000000000..7000b8560
--- /dev/null
+++ b/drivers/char/joystick/warrior.c
@@ -0,0 +1,212 @@
+/*
+ * $Id: warrior.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * 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 <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+/*
+ * 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];
+};
+
+/*
+ * 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);
+
+ warrior->dev.name = warrior_name;
+ 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%d: Logitech WingMan Warrior on serio%d\n", warrior->dev.number, serio->number);
+}
+
+/*
+ * 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);
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index c2df7ea18..bbbcad9a7 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -675,9 +675,9 @@ static int lp_register(int nr, struct parport *port)
lp_reset(nr);
sprintf (name, "%d", nr);
- devfs_register (devfs_handle, name, 0,
+ devfs_register (devfs_handle, name,
DEVFS_FL_DEFAULT, LP_MAJOR, nr,
- S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ S_IFCHR | S_IRUGO | S_IWUGO,
&lp_fops, NULL);
printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name,
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 40e6c7ba6..3b5a2c497 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -18,7 +18,6 @@
#include <linux/mman.h>
#include <linux/random.h>
#include <linux/init.h>
-#include <linux/joystick.h>
#include <linux/raw.h>
#include <linux/capability.h>
@@ -608,9 +607,9 @@ void __init memory_devfs_register (void)
int i;
for (i=0; i<(sizeof(list)/sizeof(*list)); i++)
- devfs_register (NULL, list[i].name, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, list[i].name, DEVFS_FL_NONE,
MEM_MAJOR, list[i].minor,
- list[i].mode | S_IFCHR, 0, 0,
+ list[i].mode | S_IFCHR,
list[i].fops, NULL);
}
@@ -654,13 +653,6 @@ int __init chr_dev_init(void)
#ifdef CONFIG_SPARCAUDIO
sparcaudio_init();
#endif
-#ifdef CONFIG_JOYSTICK
- /*
- * Some joysticks only appear when the sound card they are
- * connected to is configured. Keep the sound/joystick ordering.
- */
- js_init();
-#endif
#if CONFIG_QIC02_TAPE
qic02_tape_init();
#endif
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index df1e97494..c26a58eea 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -193,9 +193,9 @@ int misc_register(struct miscdevice * misc)
if (!devfs_handle)
devfs_handle = devfs_mk_dir (NULL, "misc", 4, NULL);
misc->devfs_handle =
- devfs_register (devfs_handle, misc->name, 0, DEVFS_FL_NONE,
+ devfs_register (devfs_handle, misc->name, DEVFS_FL_NONE,
MISC_MAJOR, misc->minor,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
misc->fops, NULL);
/*
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 819ed0b1a..af52cf98f 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -665,7 +665,7 @@ static int __init ppdev_init (void)
devfs_handle = devfs_mk_dir (NULL, "parports", 0, NULL);
devfs_register_series (devfs_handle, "%u", PARPORT_MAX,
DEVFS_FL_DEFAULT, PP_MAJOR, 0,
- S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ S_IFCHR | S_IRUGO | S_IWUGO,
&pp_fops, NULL);
printk (KERN_INFO PP_VERSION "\n");
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index fdaeeaea0..ba1b9caa9 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -3194,7 +3194,7 @@ int __init stl_init(void)
devfs_handle = devfs_mk_dir (NULL, "staliomem", 9, NULL);
devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
STL_SIOMEMMAJOR, 0,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&stl_fsiomem, NULL);
/*
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index 133f19aac..09b502a72 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -2905,37 +2905,37 @@ int __init qic02_tape_init(void)
#endif
return -ENODEV;
}
- devfs_register (NULL, "ntpqic11", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "ntpqic11", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 2,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "tpqic11", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "tpqic11", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 3,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "ntpqic24", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "ntpqic24", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 4,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "tpqic24", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "tpqic24", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 5,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "ntpqic120", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "ntpqic120", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 6,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "tpqic120", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "tpqic120", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 7,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "ntpqic150", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "ntpqic150", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 8,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "tpqic150", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "tpqic150", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 9,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
init_waitqueue_head(&qic02_tape_transfer);
/* prepare timer */
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 8a03fed26..613b2f967 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1971,8 +1971,6 @@ void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
{
#ifdef CONFIG_DEVFS_FS
umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR;
- uid_t uid = 0;
- gid_t gid = 0;
struct tty_struct tty;
char buf[32];
@@ -1996,14 +1994,11 @@ void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
}
# ifdef CONFIG_UNIX98_PTYS
if ( (driver->major >= UNIX98_PTY_SLAVE_MAJOR) &&
- (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) ) {
- uid = current->uid;
- gid = current->gid;
- }
+ (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) )
+ flags |= DEVFS_FL_CURRENT_OWNER;
# endif
- devfs_register (NULL, tty_name (&tty, buf), 0,flags | DEVFS_FL_DEFAULT,
- driver->major, minor, mode, uid, gid,
- &tty_fops, NULL);
+ devfs_register (NULL, tty_name (&tty, buf), flags | DEVFS_FL_DEFAULT,
+ driver->major, minor, mode, &tty_fops, NULL);
#endif /* CONFIG_DEVFS_FS */
}
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index 5138c76b8..67ff8d856 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -476,12 +476,12 @@ void vcs_make_devfs (unsigned int index, int unregister)
}
else
{
- devfs_register (devfs_handle, name + 1, 0, DEVFS_FL_DEFAULT,
+ devfs_register (devfs_handle, name + 1, DEVFS_FL_DEFAULT,
VCS_MAJOR, index + 1,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL);
- devfs_register (devfs_handle, name, 0, DEVFS_FL_DEFAULT,
+ S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
+ devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT,
VCS_MAJOR, index + 129,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL);
+ S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
}
#endif /* CONFIG_DEVFS_FS */
}
@@ -496,12 +496,12 @@ int __init vcs_init(void)
printk("unable to get major %d for vcs device", VCS_MAJOR);
devfs_handle = devfs_mk_dir (NULL, "vcc", 3, NULL);
- devfs_register (devfs_handle, "0", 1, DEVFS_FL_DEFAULT,
+ devfs_register (devfs_handle, "0", DEVFS_FL_DEFAULT,
VCS_MAJOR, 0,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL);
- devfs_register (devfs_handle, "a", 1, DEVFS_FL_DEFAULT,
+ S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
+ devfs_register (devfs_handle, "a", DEVFS_FL_DEFAULT,
VCS_MAJOR, 128,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL);
+ S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
return error;
}
diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c
index ababd833f..4a3bfb859 100644
--- a/drivers/char/videodev.c
+++ b/drivers/char/videodev.c
@@ -62,7 +62,7 @@ LIST_HEAD(videodev_proc_list);
#ifdef CONFIG_VIDEO_BT848
-extern int tuner_init_module(struct video_init *);
+extern int i2c_tuner_init(struct video_init *);
#endif
#ifdef CONFIG_VIDEO_BWQCAM
extern int init_bw_qcams(struct video_init *);
@@ -79,7 +79,7 @@ extern int init_zoran_cards(struct video_init *);
static struct video_init video_init_list[]={
#ifdef CONFIG_VIDEO_BT848
- {"i2c-tuner", tuner_init_module},
+ {"i2c-tuner", i2c_tuner_init},
#endif
#ifdef CONFIG_VIDEO_BWQCAM
{"bw-qcam", init_bw_qcams},
@@ -286,6 +286,14 @@ static int videodev_proc_read(char *page, char **start, off_t off,
PRINT_VID_TYPE(VID_TYPE_MJPEG_ENCODER);
out += sprintf (out, "\n");
out += sprintf (out, "hardware : 0x%x\n", vfd->hardware);
+#if 0
+ out += sprintf (out, "channels : %d\n", d->vcap.channels);
+ out += sprintf (out, "audios : %d\n", d->vcap.audios);
+ out += sprintf (out, "maxwidth : %d\n", d->vcap.maxwidth);
+ out += sprintf (out, "maxheight : %d\n", d->vcap.maxheight);
+ out += sprintf (out, "minwidth : %d\n", d->vcap.minwidth);
+ out += sprintf (out, "minheight : %d\n", d->vcap.minheight);
+#endif
skip:
len = out - page;
@@ -351,6 +359,8 @@ static void videodev_proc_create_dev (struct video_device *vfd, char *name)
d->vdev = vfd;
strcpy (d->name, name);
+ /* How can I get capability information ? */
+
list_add (&d->proc_list, &videodev_proc_list);
}
@@ -459,9 +469,9 @@ int video_register_device(struct video_device *vfd, int type)
* has serious privacy issues.
*/
vfd->devfs_handle =
- devfs_register (NULL, name, 0, DEVFS_FL_DEFAULT,
+ devfs_register (NULL, name, DEVFS_FL_DEFAULT,
VIDEO_MAJOR, vfd->minor,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&video_fops, NULL);
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
@@ -564,4 +574,3 @@ EXPORT_SYMBOL(video_unregister_device);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("Device registrar for Video4Linux drivers");
-
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index ab4d3afbb..53f6b5a9e 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -2199,9 +2199,9 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
if (!CDROM_CONFIG_FLAGS (drive)->close_tray)
devinfo->mask |= CDC_CLOSE_TRAY;
- devinfo->de = devfs_register(drive->de, "cd", 2, DEVFS_FL_DEFAULT,
+ devinfo->de = devfs_register(drive->de, "cd", DEVFS_FL_DEFAULT,
HWIF(drive)->major, minor,
- S_IFBLK | S_IRUGO | S_IWUGO, 0, 0,
+ S_IFBLK | S_IRUGO | S_IWUGO,
ide_fops, NULL);
return register_cdrom(devinfo);
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 09e1b12fb..911234014 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -5987,14 +5987,14 @@ int idetape_init (void)
idetape_setup (drive, tape, minor);
idetape_chrdevs[minor].drive = drive;
tape->de_r =
- devfs_register (drive->de, "mt", 2, DEVFS_FL_DEFAULT,
+ devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
HWIF(drive)->major, minor,
- S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ S_IFCHR | S_IRUGO | S_IWUGO,
&idetape_fops, NULL);
tape->de_n =
- devfs_register (drive->de, "mtn", 3, DEVFS_FL_DEFAULT,
+ devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
HWIF(drive)->major, minor + 128,
- S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ S_IFCHR | S_IRUGO | S_IWUGO,
&idetape_fops, NULL);
devfs_register_tape (tape->de_r);
supported++; failed--;
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 932c6f114..b9aa05d4d 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -805,7 +805,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
spin_lock_irqsave(&io_request_lock, flags);
blkdev_dequeue_request(rq);
HWGROUP(drive)->rq = NULL;
- rq->rq_status = RQ_INACTIVE;
+ blkdev_release_request(rq);
spin_unlock_irqrestore(&io_request_lock, flags);
if (rq->sem != NULL)
up(rq->sem); /* inform originator that rq has been serviced */
diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c
index 972019295..8169df482 100644
--- a/drivers/isdn/avmb1/capi.c
+++ b/drivers/isdn/avmb1/capi.c
@@ -2053,11 +2053,11 @@ int capi_init(void)
devfs_register_series (NULL, "capi/r%u", CAPINC_NR_PORTS,
DEVFS_FL_DEFAULT,
capi_rawmajor, 0,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&capinc_raw_fops, NULL);
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- devfs_register (NULL, "isdn/capi20", 0, DEVFS_FL_DEFAULT,
- capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ devfs_register (NULL, "isdn/capi20", DEVFS_FL_DEFAULT,
+ capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR,
&capi_fops, NULL);
printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major);
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index aca716184..fa5a3d844 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -2581,14 +2581,14 @@ static void isdn_register_devfs(int k)
sprintf (buf, "isdn%d", k);
dev->devfs_handle_isdnX[k] =
- devfs_register (devfs_handle, buf, 0, DEVFS_FL_DEFAULT,
- ISDN_MAJOR, ISDN_MINOR_B + k,0600 | S_IFCHR, 0, 0,
+ devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT,
+ ISDN_MAJOR, ISDN_MINOR_B + k,0600 | S_IFCHR,
&isdn_fops, NULL);
sprintf (buf, "isdnctrl%d", k);
dev->devfs_handle_isdnctrlX[k] =
- devfs_register (devfs_handle, buf, 0, DEVFS_FL_DEFAULT,
+ devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT,
ISDN_MAJOR, ISDN_MINOR_CTRL + k, 0600 | S_IFCHR,
- 0, 0, &isdn_fops, NULL);
+ &isdn_fops, NULL);
}
static void isdn_unregister_devfs(int k)
@@ -2610,19 +2610,19 @@ static void isdn_init_devfs(void)
sprintf (buf, "ippp%d", i);
dev->devfs_handle_ipppX[i] =
- devfs_register (devfs_handle, buf, 0, DEVFS_FL_DEFAULT,
+ devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT,
ISDN_MAJOR, ISDN_MINOR_PPP + i,
- 0600 | S_IFCHR, 0, 0, &isdn_fops, NULL);
+ 0600 | S_IFCHR, &isdn_fops, NULL);
}
# endif
dev->devfs_handle_isdninfo =
- devfs_register (devfs_handle, "isdninfo", 0, DEVFS_FL_DEFAULT,
+ devfs_register (devfs_handle, "isdninfo", DEVFS_FL_DEFAULT,
ISDN_MAJOR, ISDN_MINOR_STATUS, 0600 | S_IFCHR,
- 0, 0, &isdn_fops, NULL);
+ &isdn_fops, NULL);
dev->devfs_handle_isdnctrl =
- devfs_register (devfs_handle, "isdnctrl", 0, DEVFS_FL_DEFAULT,
- ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR, 0, 0,
+ devfs_register (devfs_handle, "isdnctrl", DEVFS_FL_DEFAULT,
+ ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR,
&isdn_fops, NULL);
}
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 2fc74f806..ff6f18ee1 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -674,8 +674,8 @@ void adbdev_init()
if (devfs_register_chrdev(ADB_MAJOR, "adb", &adb_fops))
printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
else
- devfs_register (NULL, "adb", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "adb", DEVFS_FL_DEFAULT,
ADB_MAJOR, 0,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&adb_fops, NULL);
}
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index 7592e0bc8..5084ea70e 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -197,7 +197,7 @@ endmenu
bool 'FDDI driver support' CONFIG_FDDI
if [ "$CONFIG_FDDI" = "y" ]; then
- dep_tristate ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX $CONFIG_FDDI
+ tristate ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP
fi
diff --git a/drivers/net/dmfe.c b/drivers/net/dmfe.c
index d0f4257da..b425513b0 100644
--- a/drivers/net/dmfe.c
+++ b/drivers/net/dmfe.c
@@ -1,8 +1,9 @@
/*
- dmfe.c: Version 1.28 01/18/2000
+ dmfe.c: Version 1.30 06/11/2000
A Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver for Linux.
Copyright (C) 1997 Sten Wang
+ (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -46,20 +47,29 @@
Made it compile in 2.3 (device to net_device)
Alan Cox <alan@redhat.com> :
+ Cleaned up for kernel merge.
Removed the back compatibility support
Reformatted, fixing spelling etc as I went
Removed IRQ 0-15 assumption
-
+
+ Jeff Garzik <jgarzik@mandrakesoft.com> :
+ Updated to use new PCI driver API.
+ Resource usage cleanups.
+ Report driver version to user.
+
TODO
-
+
+ Implement pci_driver::suspend() and pci_driver::resume()
+ power management methods.
+
Check and fix on 64bit and big endian boxes.
- Sort out the PCI latency.
-
- (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
-
- Cleaned up for kernel merge by Alan Cox (alan@redhat.com)
+
+ Test and make sure PCI latency is now correct for all cases.
+
*/
+#define DMFE_VERSION "1.30 (June 11, 2000)"
+
#include <linux/module.h>
#include <linux/kernel.h>
@@ -142,7 +152,9 @@
#define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US;
-#define CHK_IO_SIZE(pci_id, dev_rev) ( (pci_id==PCI_DM9132_ID) || (dev_rev >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE
+#define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE
+#define CHK_IO_SIZE(pci_dev, dev_rev) \
+ __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev)
/* Structure/enum declaration ------------------------------- */
@@ -164,7 +176,7 @@ struct rx_desc {
struct dmfe_board_info {
u32 chip_id; /* Chip vendor/Device ID */
- u32 chip_revesion; /* Chip revesion */
+ u32 chip_revision; /* Chip revision */
struct net_device *next_dev; /* next device */
struct pci_dev *net_dev; /* PCI device */
@@ -221,7 +233,6 @@ enum dmfe_CR6_bits {
/* Global variable declaration ----------------------------- */
static int dmfe_debug = 0;
static unsigned char dmfe_media_mode = 8;
-static struct net_device *dmfe_root_dev = NULL; /* First device */
static u32 dmfe_cr6_user_set = 0;
/* For module input parameter */
@@ -299,7 +310,6 @@ static unsigned long CrcTable[256] =
};
/* function declaration ------------------------------------- */
-static int dmfe_probe(void);
static int dmfe_open(struct net_device *);
static int dmfe_start_xmit(struct sk_buff *, struct net_device *);
static int dmfe_stop(struct net_device *);
@@ -333,111 +343,117 @@ static unsigned long cal_CRC(unsigned char *, unsigned int, u8);
* Search DM910X board, allocate space and register it
*/
-static int __init dmfe_probe(void)
+
+static int __init dmfe_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
unsigned long pci_iobase;
- u16 dm9102_count = 0;
u8 pci_irqline;
- static int index = 0; /* For multiple call */
struct dmfe_board_info *db; /* Point a board information structure */
int i;
- struct pci_dev *net_dev = NULL;
struct net_device *dev;
+ u32 dev_rev;
DMFE_DBUG(0, "dmfe_probe()", 0);
- if (!pci_present())
- return -ENODEV;
+ pci_iobase = pci_resource_start(pdev, 0);
+ pci_irqline = pdev->irq;
- index = 0;
- while ((net_dev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, net_dev)))
- {
- u32 pci_id;
- u32 dev_rev;
+ /* Interrupt check */
+ if (pci_irqline == 0) {
+ printk(KERN_ERR "dmfe: Interrupt wrong : IRQ=%d\n",
+ pci_irqline);
+ goto err_out;
+ }
- index++;
- if (pci_read_config_dword(net_dev, PCI_VENDOR_ID, &pci_id) != DMFE_SUCC)
- continue;
+ /* iobase check */
+ if (pci_iobase == 0) {
+ printk(KERN_ERR "dmfe: I/O base is zero\n");
+ goto err_out;
+ }
- if ((net_dev->device != PCI_DM9102_ID) && (net_dev->device != PCI_DM9132_ID))
- continue;
+ /* Enable Master/IO access, Disable memory access */
+ if (pci_enable_device(pdev))
+ goto err_out;
+ pci_set_master(pdev);
- pci_iobase = pci_resource_start (net_dev, 0);
- pci_irqline = net_dev->irq;
-
- /* Enable Master/IO access, Disable memory access */
-
- if (pci_enable_device(net_dev))
- continue;
- pci_set_master(net_dev);
-
- /* Set Latency Timer 80h */
-
- /* FIXME: setting values > 32 breaks some SiS 559x stuff.
- Need a PCI quirk.. */
-
- pci_write_config_byte(net_dev, PCI_LATENCY_TIMER, 0x80);
+#if 0 /* pci_{enable_device,set_master} sets minimum latency for us now */
- /* Read Chip revesion */
- pci_read_config_dword(net_dev, PCI_REVISION_ID, &dev_rev);
-
- /* IO range check */
- if (check_region(pci_iobase, CHK_IO_SIZE(pci_id, dev_rev))) {
- continue;
- }
- /* Interrupt check */
- if (pci_irqline == 0) {
- printk(KERN_ERR "dmfe: Interrupt wrong : IRQ=%d\n", pci_irqline);
- continue;
- }
+ /* Set Latency Timer 80h */
+ /* FIXME: setting values > 32 breaks some SiS 559x stuff.
+ Need a PCI quirk.. */
- /* Found DM9102 card and PCI resource allocated OK */
- dm9102_count++; /* Found a DM9102 card */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
+#endif
- /* Init network device */
- dev = init_etherdev(NULL, sizeof(*db));
- if (dev == NULL)
- continue;
-
- db = dev->priv;
+ /* Read Chip revision */
+ pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev);
+
+ /* Init network device */
+ dev = init_etherdev(NULL, sizeof(*db));
+ if (dev == NULL)
+ goto err_out;
- memset(db, 0, sizeof(*db));
- db->next_dev = dmfe_root_dev;
- dmfe_root_dev = dev;
+ /* IO range check */
+ if (!request_region(pci_iobase, CHK_IO_SIZE(pdev, dev_rev), dev->name)) {
+ printk(KERN_ERR "dmfe: I/O conflict : IO=%lx Range=%x\n",
+ pci_iobase, CHK_IO_SIZE(pdev, dev_rev));
+ goto err_out_netdev;
+ }
- db->chip_id = pci_id; /* keep Chip vandor/Device ID */
- db->ioaddr = pci_iobase;
- db->chip_revesion = dev_rev;
+ db = dev->priv;
+ pdev->driver_data = dev;
- db->net_dev = net_dev;
+ db->chip_id = ent->driver_data;
+ db->ioaddr = pci_iobase;
+ db->chip_revision = dev_rev;
- dev->base_addr = pci_iobase;
- dev->irq = pci_irqline;
- dev->open = &dmfe_open;
- dev->hard_start_xmit = &dmfe_start_xmit;
- dev->stop = &dmfe_stop;
- dev->get_stats = &dmfe_get_stats;
- dev->set_multicast_list = &dmfe_set_filter_mode;
- dev->do_ioctl = &dmfe_do_ioctl;
+ db->net_dev = pdev;
- request_region(pci_iobase, CHK_IO_SIZE(pci_id, dev_rev), dev->name);
+ dev->base_addr = pci_iobase;
+ dev->irq = pci_irqline;
+ dev->open = &dmfe_open;
+ dev->hard_start_xmit = &dmfe_start_xmit;
+ dev->stop = &dmfe_stop;
+ dev->get_stats = &dmfe_get_stats;
+ dev->set_multicast_list = &dmfe_set_filter_mode;
+ dev->do_ioctl = &dmfe_do_ioctl;
- /* read 64 word srom data */
- for (i = 0; i < 64; i++)
- ((u16 *) db->srom)[i] = read_srom_word(pci_iobase, i);
+ /* read 64 word srom data */
+ for (i = 0; i < 64; i++)
+ ((u16 *) db->srom)[i] = read_srom_word(pci_iobase, i);
- /* Set Node address */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = db->srom[20 + i];
+ /* Set Node address */
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = db->srom[20 + i];
+
+ return 0;
+
+err_out_netdev:
+ unregister_netdev(dev);
+ kfree(dev);
+err_out:
+ return -ENODEV;
+}
- }
- if (!dm9102_count)
- printk(KERN_WARNING "dmfe: Can't find DM910X board\n");
+static void __exit dmfe_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ struct dmfe_board_info *db;
+
+ DMFE_DBUG(0, "dmfe_remove_one()", 0);
+
+ db = dev->priv;
+
+ unregister_netdev(dev);
+ release_region(dev->base_addr, CHK_IO_SIZE(pdev, db->chip_revision));
+ kfree(dev); /* free board information */
- return dm9102_count ? 0 : -ENODEV;
+ DMFE_DBUG(0, "dmfe_remove_one() exit", 0);
}
+
/*
* Open the interface.
* The interface is opened whenever "ifconfig" actives it.
@@ -482,7 +498,7 @@ static int dmfe_open(struct net_device *dev)
db->in_reset_state = 0;
db->rx_error_cnt = 0;
- if (!chkmode || (db->chip_id == PCI_DM9132_ID) || (db->chip_revesion >= 0x02000030)) {
+ if (!chkmode || (db->chip_id == PCI_DM9132_ID) || (db->chip_revision >= 0x02000030)) {
//db->cr6_data &= ~CR6_SFT; /* Used Tx threshold */
//db->cr6_data |= CR6_NO_PURGE; /* No purge if rx unavailable */
db->cr0_data = 0xc00000; /* TX/RX desc burst mode */
@@ -933,8 +949,8 @@ static void dmfe_timer(unsigned long data)
else
tmp_cr12 = inb(db->ioaddr + DCR12); /* DM9102/DM9102A */
- if (((db->chip_id == PCI_DM9102_ID) && (db->chip_revesion == 0x02000030)) ||
- ((db->chip_id == PCI_DM9132_ID) && (db->chip_revesion == 0x02000010))) {
+ if (((db->chip_id == PCI_DM9102_ID) && (db->chip_revision == 0x02000030)) ||
+ ((db->chip_id == PCI_DM9132_ID) && (db->chip_revision == 0x02000010))) {
/* DM9102A Chip */
if (tmp_cr12 & 2)
tmp_cr12 = 0x0; /* Link failed */
@@ -1532,6 +1548,21 @@ unsigned long cal_CRC(unsigned char *Data, unsigned int Len, u8 flag)
}
+static struct pci_device_id dmfe_pci_tbl[] __initdata = {
+ { 0x1282, 0x9132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9132_ID },
+ { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID },
+ { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl);
+
+static struct pci_driver dmfe_driver = {
+ name: "dmfe",
+ id_table: dmfe_pci_tbl,
+ probe: dmfe_init_one,
+ remove: dmfe_remove_one,
+};
+
MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
MODULE_DESCRIPTION("Davicom DM910X fast ethernet driver");
MODULE_PARM(debug, "i");
@@ -1546,6 +1577,8 @@ MODULE_PARM(chkmode, "i");
static int __init dmfe_init_module(void)
{
+ int rc;
+
DMFE_DBUG(0, "init_module() ", debug);
if (debug)
@@ -1565,32 +1598,26 @@ static int __init dmfe_init_module(void)
break;
}
- return dmfe_probe(); /* search board and register */
+ rc = pci_register_driver(&dmfe_driver);
+ if (rc < 0)
+ return rc;
+ if (rc > 0) {
+ printk (KERN_INFO "Davicom DM91xx net driver loaded, version "
+ DMFE_VERSION "\n");
+ return 0;
+ }
+ return -ENODEV;
}
/*
* Description:
* when user used rmmod to delete module, system invoked clean_module()
- * to un-register device.
+ * to un-register all registered services.
*/
static void __exit dmfe_cleanup_module(void)
{
- struct net_device *next_dev;
- struct dmfe_board_info *db;
-
- DMFE_DBUG(0, "clean_module()", 0);
-
- while (dmfe_root_dev) {
- db = dmfe_root_dev->priv;
- next_dev = db->next_dev;
- unregister_netdev(dmfe_root_dev);
- release_region(dmfe_root_dev->base_addr, CHK_IO_SIZE(db->chip_id, db->chip_revesion));
- kfree(db); /* free board information */
- kfree(dmfe_root_dev); /* free device structure */
- dmfe_root_dev = next_dev;
- }
- DMFE_DBUG(0, "clean_module() exit", 0);
+ pci_unregister_driver(&dmfe_driver);
}
module_init(dmfe_init_module);
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index bec5eb631..ccb0d42de 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -110,12 +110,12 @@ int __init dummy_init(struct net_device *dev)
static int dummy_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct net_device_stats *stats;
- dev_kfree_skb(skb);
stats = (struct net_device_stats *)dev->priv;
stats->tx_packets++;
stats->tx_bytes+=skb->len;
+ dev_kfree_skb(skb);
return 0;
}
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index bb6314456..03944f066 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -941,12 +941,7 @@ static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
- /*
- * This function will also be used by IrLAP to change the
- * speed, so we still must allow for speed change within
- * interrupt context.
- */
- if (!in_interrupt() && !capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
irda_task_execute(self, __irport_change_speed, NULL, NULL,
(void *) irq->ifr_baudrate);
diff --git a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c
index c174dfa71..1fd3acda9 100644
--- a/drivers/net/irda/irtty.c
+++ b/drivers/net/irda/irtty.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Dec 9 21:18:38 1997
- * Modified at: Tue Apr 25 21:17:49 2000
+ * Modified at: Sat Mar 11 07:43:30 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
@@ -962,12 +962,7 @@ static int irtty_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
- /*
- * This function will also be used by IrLAP to change the
- * speed, so we still must allow for speed change within
- * interrupt context.
- */
- if (!in_interrupt() && !capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
irda_task_execute(self, irtty_change_speed, NULL, NULL,
(void *) irq->ifr_baudrate);
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 4fe1a764b..df9c63621 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -56,7 +56,6 @@
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
-#include <asm/hardirq.h>
#include <linux/pm.h>
@@ -1948,15 +1947,8 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
- /*
- * This function will also be used by IrLAP to change the
- * speed, so we still must allow for speed change within
- * interrupt context.
- */
- if (!in_interrupt() && !capable(CAP_NET_ADMIN)) {
- IRDA_DEBUG(0, __FUNCTION__ "(), not capable sysadm\n");
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
- }
nsc_ircc_change_speed(self, irq->ifr_baudrate);
break;
case SIOCSMEDIABUSY: /* Set media busy */
diff --git a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c
index 1f1f2cb14..387208e2f 100644
--- a/drivers/net/irda/toshoboe.c
+++ b/drivers/net/irda/toshoboe.c
@@ -603,12 +603,7 @@ static int toshoboe_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
- /*
- * This function will also be used by IrLAP to change the
- * speed, so we still must allow for speed change within
- * interrupt context.
- */
- if (!in_interrupt() && !capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* toshoboe_setbaud(self, irq->ifr_baudrate); */
/* Just change speed once - inserted by Paul Bristow */
@@ -722,7 +717,7 @@ toshoboe_open (struct pci_dev *pci_dev)
self->open = 0;
self->stopped = 0;
self->pdev = pci_dev;
- self->base = pci_resource_start (pci_dev, 0);
+ self->base = pci_dev->resource[0].start;
self->io.sir_base = self->base;
self->io.irq = pci_dev->irq;
@@ -905,6 +900,7 @@ toshoboe_gotosleep (struct toshoboe_cb *self)
static void
toshoboe_wakeup (struct toshoboe_cb *self)
{
+ struct net_device *dev = self->netdev;
unsigned long flags;
if (!self->stopped)
@@ -956,26 +952,36 @@ int __init toshoboe_init (void)
struct pci_dev *pci_dev = NULL;
int found = 0;
- while ((pci_dev = pci_find_device (PCI_VENDOR_ID_TOSHIBA,
- PCI_DEVICE_ID_FIR701, pci_dev)) != NULL) {
- if (pci_enable_device(pci_dev))
- continue;
+ do
+ {
+ pci_dev = pci_find_device (PCI_VENDOR_ID_TOSHIBA,
+ PCI_DEVICE_ID_FIR701, pci_dev);
+ if (pci_dev)
+ {
printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n",
- pci_resource_start (pci_dev, 0),
+ pci_dev->resource[0].start,
pci_dev->irq);
if (!toshoboe_open (pci_dev))
found++;
- }
+ }
+
+ }
+ while (pci_dev);
+
if (found)
+ {
return 0;
+ }
return -ENODEV;
}
+#ifdef MODULE
-static void __exit toshoboe_cleanup (void)
+static void
+toshoboe_cleanup (void)
{
int i;
@@ -991,8 +997,19 @@ static void __exit toshoboe_cleanup (void)
}
-#ifdef MODULE
-module_init(toshoboe_init);
-#endif
-module_exit(toshoboe_cleanup);
+int
+init_module (void)
+{
+ return toshoboe_init ();
+}
+
+
+void
+cleanup_module (void)
+{
+ toshoboe_cleanup ();
+}
+
+
+#endif
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index c262c7e30..2456e012d 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -255,12 +255,13 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq,
dev->get_stats = w83977af_net_get_stats;
rtnl_lock();
- err = register_netdevice(dev);
+ err = register_netdev(dev);
rtnl_unlock();
if (err) {
- ERROR(__FUNCTION__ "(), register_netdevice() failed!\n");
+ ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
return -1;
}
+
MESSAGE("IrDA: Registered device %s\n", dev->name);
return 0;
@@ -301,7 +302,7 @@ static int w83977af_close(struct w83977af_ir *self)
/* Release the PORT that this driver is using */
IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n",
- self->io.fir_base);
+ self->io.fir_base);
release_region(self->io.fir_base, self->io.fir_ext);
if (self->tx_buff.head)
@@ -1331,12 +1332,7 @@ static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
- /*
- * This function will also be used by IrLAP to change the
- * speed, so we still must allow for speed change within
- * interrupt context.
- */
- if (!in_interrupt() && !capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
w83977af_change_speed(self, irq->ifr_baudrate);
break;
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index b9d5ebfc3..e43e3b394 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -718,9 +718,9 @@ int __init ppp_init(void)
err = devfs_register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops);
if (err)
printk(KERN_ERR "failed to register PPP device (%d)\n", err);
- devfs_handle = devfs_register(NULL, "ppp", 0, DEVFS_FL_NONE,
+ devfs_handle = devfs_register(NULL, "ppp", DEVFS_FL_DEFAULT,
PPP_MAJOR, 0,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&ppp_device_fops, NULL);
return 0;
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 6885d5fb1..c27d89ca9 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -398,7 +398,7 @@ static int __init cosa_init(void)
devfs_handle = devfs_mk_dir (NULL, "cosa", 4, NULL);
devfs_register_series (devfs_handle, "%u", nr_cards, DEVFS_FL_DEFAULT,
cosa_major, 0,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&cosa_fops, NULL);
if (!nr_cards) {
printk(KERN_WARNING "cosa: no devices found.\n");
diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c
index a945167c5..36d0a5d6a 100644
--- a/drivers/pcmcia/yenta.c
+++ b/drivers/pcmcia/yenta.c
@@ -127,6 +127,8 @@ static int yenta_get_status(pci_socket_t *socket, unsigned int *value)
val = (state & CB_3VCARD) ? SS_3VCARD : 0;
val |= (state & CB_XVCARD) ? SS_XVCARD : 0;
+ val |= (state & (CB_CDETECT1 | CB_CDETECT2 | CB_5VCARD | CB_3VCARD
+ | CB_XVCARD | CB_YVCARD)) ? 0 : SS_PENDING;
if (state & CB_CBCARD) {
val |= SS_CARDBUS;
@@ -556,30 +558,6 @@ static void yenta_clear_maps(pci_socket_t *socket)
}
}
-/*
- * Many chipsets (all TI chips?) seem to have
- * problems sensing the power state of the card
- * that was inserted at chip init time, so force
- * it if necessary..
- */
-static void yenta_power_sense(pci_socket_t *socket)
-{
- u32 status = cb_readl(socket, CB_SOCKET_STATE);
-
- /*
- * Nothing inserted, nothing to sense..
- * ..or sense status already available.
- */
- if (status & (CB_CDETECT1 | CB_CDETECT2 | CB_5VCARD | CB_3VCARD | CB_XVCARD | CB_YVCARD))
- return;
-
- /*
- * Ho humm. It reports a card, but it doesn't report
- * any voltages. Need to redo the VS test..
- */
- cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST);
-}
-
/* Called at resume and initialization events */
static int yenta_init(pci_socket_t *socket)
{
@@ -620,7 +598,8 @@ static int yenta_init(pci_socket_t *socket)
exca_writeb(socket, I365_GBLCTL, 0x00);
exca_writeb(socket, I365_GENCTL, 0x00);
- yenta_power_sense(socket);
+ /* Redo card voltage interrogation */
+ cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST);
yenta_clear_maps(socket);
return 0;
diff --git a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c
index 497879619..2115cdac9 100644
--- a/drivers/pnp/isapnp.c
+++ b/drivers/pnp/isapnp.c
@@ -500,6 +500,7 @@ static void __init isapnp_add_irq_resource(struct pci_dev *dev,
int dependent, int size)
{
unsigned char tmp[3];
+ int i;
struct isapnp_irq *irq, *ptr;
isapnp_peek(tmp, size);
@@ -526,6 +527,9 @@ static void __init isapnp_add_irq_resource(struct pci_dev *dev,
ptr->next = irq;
else
(*res)->irq = irq;
+ for (i=0; i<16; i++)
+ if (irq->map & i)
+ pcibios_penalize_isa_irq(i);
}
/*
@@ -1603,6 +1607,14 @@ static int isapnp_check_interrupt(struct isapnp_cfgtmp *cfg, int irq, int idx)
return 1;
}
}
+#ifdef CONFIG_PCI
+ if (!isapnp_skip_pci_scan) {
+ pci_for_each_dev(dev) {
+ if (dev->irq == irq)
+ return 1;
+ }
+ }
+#endif
if (request_irq(irq, isapnp_test_handler, SA_INTERRUPT, "isapnp", NULL))
return 1;
free_irq(irq, NULL);
@@ -2070,45 +2082,6 @@ static void isapnp_free_all_resources(void)
#endif
}
-static int __init isapnp_do_reserve_irq(int irq)
-{
- int i;
-
- if (irq < 0 || irq > 15)
- return -EINVAL;
- for (i = 0; i < 16; i++) {
- if (isapnp_reserve_irq[i] == irq)
- return 0;
- }
- for (i = 0; i < 16; i++) {
- if (isapnp_reserve_irq[i] < 0) {
- isapnp_reserve_irq[i] = irq;
-#ifdef ISAPNP_DEBUG
- printk("isapnp: IRQ %i is reserved now.\n", irq);
-#endif
- return 0;
- }
- }
- return -ENOMEM;
-}
-
-#ifdef CONFIG_PCI
-
-static void __init isapnp_pci_init(void)
-{
- struct pci_dev *dev;
-
- pci_for_each_dev(dev) {
-#ifdef ISAPNP_DEBUG
- printk("isapnp: PCI: reserved IRQ: %i\n", dev->irq);
-#endif
- if (dev->irq > 0)
- isapnp_do_reserve_irq(dev->irq);
- }
-}
-
-#endif /* CONFIG_PCI */
-
EXPORT_SYMBOL(isapnp_cards);
EXPORT_SYMBOL(isapnp_devices);
EXPORT_SYMBOL(isapnp_present);
@@ -2200,10 +2173,6 @@ int __init isapnp_init(void)
} else {
printk("isapnp: No Plug & Play card found\n");
}
-#ifdef CONFIG_PCI
- if (!isapnp_skip_pci_scan)
- isapnp_pci_init();
-#endif
#ifdef CONFIG_PROC_FS
isapnp_proc_init();
#endif
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 79e8f27dc..55e27c7d8 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -792,11 +792,10 @@ register_dasd_last (int di)
dasd_info[di]->info.devno,'\0' );
dasd_info[di] -> devfs_entry =
devfs_register ( NULL /* dir */,
- name, strlen(name),
- 0 /* flags */,
+ name,
+ DEVFS_FL_DEFAULT /* flags */,
DASD_MAJOR, minor,
0755 /* mode */,
- 0 /* uid */ , 0 /* gid */,
&dasd_device_operations,
(void *)dasd_info[di]);
}
diff --git a/drivers/sbus/audio/audio.c b/drivers/sbus/audio/audio.c
index 31856af31..586945b10 100644
--- a/drivers/sbus/audio/audio.c
+++ b/drivers/sbus/audio/audio.c
@@ -1,4 +1,4 @@
-/* $Id: audio.c,v 1.51 2000/06/19 06:24:47 davem Exp $
+/* $Id: audio.c,v 1.52 2000/06/22 11:42:27 davem Exp $
* drivers/sbus/audio/audio.c
*
* Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
@@ -2010,9 +2010,9 @@ int register_sparcaudio_driver(struct sparcaudio_driver *drv, int duplex)
for (i=0; i < sizeof (dev_list) / sizeof (*dev_list); i++) {
sparcaudio_mkname (name_buf, dev_list[i].name, dev);
minor = (dev << SPARCAUDIO_DEVICE_SHIFT) | dev_list[i].minor;
- devfs_register (devfs_handle, name_buf, 0, DEVFS_FL_NONE,
+ devfs_register (devfs_handle, name_buf, DEVFS_FL_NONE,
SOUND_MAJOR, minor, S_IFCHR | dev_list[i].mode,
- 0, 0, &sparcaudio_fops, NULL);
+ &sparcaudio_fops, NULL);
}
/* Setup the circular queues of output and input buffers
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index ba6810017..6dfc4c132 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -1031,7 +1031,7 @@ int __init bpp_init(void)
}
devfs_handle = devfs_mk_dir (NULL, "bpp", 3, NULL);
devfs_register_series (devfs_handle, "%u", BPP_NO, DEVFS_FL_DEFAULT,
- BPP_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ BPP_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR,
&bpp_fops, NULL);
return 0;
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
index d31ef5193..458fe20af 100644
--- a/drivers/sbus/char/jsflash.c
+++ b/drivers/sbus/char/jsflash.c
@@ -271,7 +271,7 @@ static loff_t jsf_lseek(struct file * file, loff_t offset, int orig)
}
/*
- * P3: OS SIMM Cannot be read in other size but a 32bits word.
+ * OS SIMM Cannot be read in other size but a 32bits word.
*/
static ssize_t jsf_read(struct file * file, char * buf,
size_t togo, loff_t *ppos)
@@ -647,8 +647,7 @@ int jsfd_init(void) {
int i;
if (jsf0.base == 0) {
- printk("jsfd_init: no flash\n"); /* P3 */
- return -EIO;
+ return -ENXIO;
}
if (register_blkdev(JSFD_MAJOR, "jsfd", &jsfd_fops)) {
@@ -657,8 +656,6 @@ int jsfd_init(void) {
return -EIO;
}
- printk("jsfd0: at major %d\n", MAJOR_NR); /* P3 */
-
blksize_size[JSFD_MAJOR] = jsfd_blksizes;
blk_size[JSFD_MAJOR] = jsfd_sizes;
diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c
index 5f7ea6923..8004569ab 100644
--- a/drivers/sbus/char/sunkbd.c
+++ b/drivers/sbus/char/sunkbd.c
@@ -1605,9 +1605,9 @@ void __init keyboard_zsinit(void (*put_char)(unsigned char))
spin_unlock_irq(&sunkbd_lock);
/* Register the /dev/kbd interface */
- devfs_register (NULL, "kbd", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "kbd", DEVFS_FL_DEFAULT,
KBD_MAJOR, 0,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH,
&kbd_fops, NULL);
if (devfs_register_chrdev (KBD_MAJOR, "kbd", &kbd_fops)){
printk ("Could not register /dev/kbd device\n");
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index dee47f98b..589b787d0 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -166,9 +166,9 @@ int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, int instance)
return -EIO;
sprintf (devname, "%d", instance);
- dev->de = devfs_register (devfs_handle, devname, 0, DEVFS_FL_DEFAULT,
+ dev->de = devfs_register (devfs_handle, devname, DEVFS_FL_DEFAULT,
VFC_MAJOR, instance,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&vfc_fops, NULL);
return 0;
}
diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c
index 67648bc75..d9f952ca6 100644
--- a/drivers/scsi/aic7xxx.c
+++ b/drivers/scsi/aic7xxx.c
@@ -243,6 +243,8 @@
#include <linux/blk.h>
#include <linux/tqueue.h>
#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
#include "sd.h"
#include "scsi.h"
#include "hosts.h"
@@ -264,7 +266,7 @@
*/
#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
-#define AIC7XXX_C_VERSION "5.2.0"
+#define AIC7XXX_C_VERSION "5.2.1"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
@@ -281,45 +283,12 @@
# define FALSE 0
#endif
-/*
- * We need the bios32.h file if we are kernel version 2.1.92 or less. The
- * full set of pci_* changes wasn't in place until 2.1.93
- */
-
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92)
-# if defined(__sparc_v9__) || defined(__powerpc__)
-# error "PPC and Sparc platforms are only support under 2.1.92 and above"
-# endif
-# include <linux/bios32.h>
-#endif
-
-#if defined(__powerpc__)
+#if defined(__powerpc__) || defined(__i386)
# define MMAPIO
-# ifdef mb
-# undef mb
-# endif
-# define mb() \
- __asm__ __volatile__("eieio" ::: "memory")
-#elif defined(__i386__)
-# define MMAPIO
-# ifdef mb
-# undef mb
-# endif
-# define mb() \
- __asm__ __volatile__("lock ; addl $0,0(%%esp)": : :"memory")
-#elif defined(__alpha__)
-# ifdef mb
-# undef mb
-# endif
-# define mb() \
- __asm__ __volatile__("mb": : :"memory")
#endif
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
-# include <linux/spinlock.h>
-# include <linux/smp.h>
-# define cpuid smp_processor_id()
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+# define cpuid smp_processor_id()
# define DRIVER_LOCK_INIT \
spin_lock_init(&p->spin_lock);
# define DRIVER_LOCK \
@@ -337,17 +306,6 @@
# define DRIVER_LOCK
# define DRIVER_UNLOCK
# endif
-#else
-# define cpuid 0
-# define DRIVER_LOCK_INIT
-# define DRIVER_LOCK \
- save_flags(cpu_flags); \
- cli();
-# define DRIVER_UNLOCK \
- restore_flags(cpu_flags);
-# define le32_to_cpu(x) (x)
-# define cpu_to_le32(x) (x)
-#endif
/*
* You can try raising me if tagged queueing is enabled, or lowering
@@ -359,13 +317,6 @@
#define AIC7XXX_CMDS_PER_DEVICE 8
#endif
-/* Set this to the delay in seconds after SCSI bus reset. */
-#ifdef CONFIG_AIC7XXX_RESET_DELAY
-#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
-#else
-#define AIC7XXX_RESET_DELAY 5
-#endif
-
/*
* Control collection of SCSI transfer statistics for the /proc filesystem.
*
@@ -377,28 +328,6 @@
#endif
/*
- * NOTE: Uncommenting the define below no longer has any effect, the
- * tagged queue value array is always active now. I've added
- * a setup option to set this particular array and I'm hoping
- * insmod will be smart enough to set it properly as well. It's
- * by use of this array that a person can enable tagged queueing.
- * The DEFAULT_TAG_COMMANDS define has been changed to disable
- * tagged queueing by default, so if your devices can handle tagged
- * queueing you will need to add a line to their lilo.conf file like:
- * append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}"
- * which will result in the first four devices on the first two
- * controllers being set to a tagged queue depth of 32.
- *
- * Set this for defining the number of tagged commands on a device
- * by device, and controller by controller basis. The first set
- * of tagged commands will be used for the first detected aic7xxx
- * controller, the second set will be used for the second detected
- * aic7xxx controller, and so on. These values will *only* be used
- * for targets that are tagged queueing capable; these values will
- * be ignored in all other cases. The tag_commands is an array of
- * 16 to allow for wide and twin adapters. Twin adapters will use
- * indexes 0-7 for channel 0, and indexes 8-15 for channel 1.
- *
* *** Determining commands per LUN ***
*
* When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its
@@ -408,7 +337,6 @@
* use an internal queue depth of 3, with no more than one of those
* three commands active at one time.
*/
-/* #define AIC7XXX_TAGGED_QUEUEING_BY_DEVICE */
typedef struct
{
@@ -453,8 +381,8 @@ typedef struct
/*
* NOTE: The below structure is for reference only, the actual structure
- * to modify in order to change things is located around line
- * number 1305
+ * to modify in order to change things is found after this fake one.
+ *
adapter_tag_info_t aic7xxx_tag_info[] =
{
{DEFAULT_TAG_COMMANDS},
@@ -509,6 +437,7 @@ static const char *board_names[] = {
"Adaptec AHA-394X Ultra SCSI host adapter", /* AIC_7882 */
"Adaptec AHA-398X Ultra SCSI host adapter", /* AIC_7883 */
"Adaptec AHA-2944 Ultra SCSI host adapter", /* AIC_7884 */
+ "Adaptec AHA-2940UW Pro Ultra SCSI host adapter", /* AIC_7887 */
"Adaptec AIC-7895 Ultra SCSI host adapter", /* AIC_7895 */
"Adaptec AIC-7890/1 Ultra2 SCSI host adapter", /* AIC_7890 */
"Adaptec AHA-293X Ultra2 SCSI host adapter", /* AIC_7890 */
@@ -565,7 +494,7 @@ static const char *board_names[] = {
* AIC-7770 I/O range to reserve for a card
*/
#define MINREG 0xC00
-#define MAXREG 0xCBF
+#define MAXREG 0xCFF
#define INTDEF 0x5C /* Interrupt Definition Register */
@@ -828,7 +757,8 @@ typedef enum {
* and what flags weren't. This way, I could clean up the flag usage on
* a use by use basis. Doug Ledford
*/
- AHC_NO_STPWR = 0x00040000,
+ AHC_MOTHERBOARD = 0x00020000,
+ AHC_NO_STPWEN = 0x00040000,
AHC_RESET_DELAY = 0x00080000,
AHC_A_SCANNED = 0x00100000,
AHC_B_SCANNED = 0x00200000,
@@ -1056,11 +986,8 @@ struct aic7xxx_host {
struct timer_list dev_timer;
unsigned long dev_expires[MAX_TARGETS];
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
spinlock_t spin_lock;
volatile unsigned char cpu_lock_count[NR_CPUS];
-#endif
-
Scsi_Cmnd *dev_dtr_cmnd[MAX_TARGETS];
@@ -1384,9 +1311,7 @@ static int aic7xxx_seltime = 0x10;
*/
#ifdef MODULE
static char * aic7xxx = NULL;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,18)
MODULE_PARM(aic7xxx, "s");
-#endif
/*
* Just in case someone uses commas to separate items on the insmod
@@ -1444,32 +1369,6 @@ static void aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer);
*
***************************************************************************/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
-static inline void
-mdelay(int milliseconds)
-{
- int i;
-
- for(i=0; i<milliseconds; i++)
- udelay(1000);
-}
-
-static inline int
-time_after_eq(unsigned long a, unsigned long b)
-{
- return((long)((a) - (b)) >= 0L);
-}
-
-static inline int
-timer_pending(struct timer_list *timer)
-{
- return( timer->prev != NULL );
-}
-
-#define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075
-
-#endif
-
static inline unsigned char
aic_inb(struct aic7xxx_host *p, long port)
{
@@ -1483,7 +1382,6 @@ aic_inb(struct aic7xxx_host *p, long port)
{
x = inb(p->base + port);
}
- mb();
return(x);
#else
return(inb(p->base + port));
@@ -1497,14 +1395,17 @@ aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
if(p->maddr)
{
writeb(val, p->maddr + port);
+ mb(); /* locked operation in order to force CPU ordering */
+ readb(p->maddr + HCNTRL); /* dummy read to flush the PCI write */
}
else
{
outb(val, p->base + port);
+ mb(); /* locked operation in order to force CPU ordering */
}
- mb();
#else
outb(val, p->base + port);
+ mb(); /* locked operation in order to force CPU ordering */
#endif
}
@@ -1642,7 +1543,7 @@ aic7xxx_setup(char *s)
}
else if (!strncmp(p, "verbose", n))
{
- *(options[i].flag) = 0xff09;
+ *(options[i].flag) = 0xff29;
}
else
{
@@ -1669,7 +1570,7 @@ __setup("aic7xxx=", aic7xxx_setup);
* is important since the sequencer can disable pausing for critical
* sections.
*-F*************************************************************************/
-static inline void
+static void
pause_sequencer(struct aic7xxx_host *p)
{
aic_outb(p, p->pause, HCNTRL);
@@ -1677,6 +1578,10 @@ pause_sequencer(struct aic7xxx_host *p)
{
;
}
+ if(p->features & AHC_ULTRA2)
+ {
+ aic_inb(p, CCSCBCTL);
+ }
}
/*+F*************************************************************************
@@ -1687,7 +1592,7 @@ pause_sequencer(struct aic7xxx_host *p)
* Unpause the sequencer. Unremarkable, yet done often enough to
* warrant an easy way to do it.
*-F*************************************************************************/
-static inline void
+static void
unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
{
if (unpause_always ||
@@ -1706,7 +1611,7 @@ unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
* Restart the sequencer program from address zero. This assumes
* that the sequencer is already paused.
*-F*************************************************************************/
-static inline void
+static void
restart_sequencer(struct aic7xxx_host *p)
{
aic_outb(p, 0, SEQADDR0);
@@ -1787,7 +1692,6 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr,
struct ins_format1 *fmt1_ins;
struct ins_format3 *fmt3_ins;
unsigned char opcode;
- volatile unsigned char hcntrl;
instr = *(union ins_formats*) &seqprog[instrptr * 4];
@@ -1889,14 +1793,10 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr,
}
}
aic_outb(p, (instr.integer & 0xff), SEQRAM);
- hcntrl = aic_inb(p, HCNTRL);
aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM);
- hcntrl = aic_inb(p, HCNTRL);
aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM);
- hcntrl = aic_inb(p, HCNTRL);
aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM);
- hcntrl = aic_inb(p, HCNTRL);
- udelay(50);
+ udelay(10);
break;
default:
@@ -2151,7 +2051,7 @@ aic7xxx_find_syncrate(struct aic7xxx_host *p, unsigned int *period,
* Use async transfers for this target
*/
*options = 0;
- *period = 0;
+ *period = 255;
syncrate = NULL;
}
return (syncrate);
@@ -2950,6 +2850,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
#define WIDE_INQUIRY_BITS 0x60
#define SYNC_INQUIRY_BITS 0x10
#define SCSI_VERSION_BITS 0x07
+#define SCSI_DT_BIT 0x04
if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
(p->features & AHC_WIDE) )
{
@@ -2968,48 +2869,66 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
AHC_TRANS_CUR) );
unpause_sequencer(p, FALSE);
}
- if (buffer[7] & SYNC_INQUIRY_BITS)
+ if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
+ p->transinfo[tindex].user_offset )
{
- p->needsdtr |= (1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
-
p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
- if (p->transinfo[tindex].user_offset)
+ if (p->features & AHC_ULTRA2)
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+ else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ else
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) ||
+ (buffer[56] & SCSI_DT_BIT) ||
+ (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
+ (p->transinfo[tindex].user_period <= 9) &&
+ (p->transinfo[tindex].user_options) )
{
- if (p->features & AHC_ULTRA2)
- p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
- else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
- p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
- else
- p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ p->needppr |= (1<<tindex);
+ p->needppr_copy |= (1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ p->needwdtr &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
+ p->dev_flags[tindex] |= DEVICE_SCSI_3;
+ }
+ else
+ {
+ p->needsdtr |= (1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
+ p->transinfo[tindex].goal_period =
+ MAX(10, p->transinfo[tindex].goal_period);
+ p->transinfo[tindex].goal_options = 0;
}
}
else
{
p->needsdtr &= ~(1<<tindex);
p->needsdtr_copy &= ~(1<<tindex);
- p->transinfo[tindex].goal_period = 0;
+ p->transinfo[tindex].goal_period = 255;
p->transinfo[tindex].goal_offset = 0;
p->transinfo[tindex].goal_options = 0;
}
- if ( (buffer[2] & SCSI_VERSION_BITS) == 3 )
+ /*
+ * This is needed to work around a sequencer bug for now. Regardless
+ * of the controller in use, if we have a Quantum drive, we need to
+ * limit the speed to 80MByte/sec. As soon as I get a fixed version
+ * of the sequencer, this code will get yanked.
+ */
+ if(!strncmp(buffer + 8, "QUANTUM", 7) &&
+ p->transinfo[tindex].goal_options )
{
- p->dev_flags[tindex] |= DEVICE_SCSI_3;
- /*
- * OK, we are a SCSI 3 device and we are in need of negotiation.
- * Use PPR messages instead of WDTR and SDTR messages.
- */
- if ( (p->needsdtr & (1<<tindex)) ||
- (p->needwdtr & (1<<tindex)) )
- {
- p->needppr |= (1<<tindex);
- p->needppr_copy |= (1<<tindex);
- }
- p->needwdtr &= ~(1<<tindex);
- p->needwdtr_copy &= ~(1<<tindex);
- p->needsdtr &= ~(1<<tindex);
- p->needsdtr_copy &= ~(1<<tindex);
+ p->transinfo[tindex].goal_period =
+ MAX(p->transinfo[tindex].goal_period, 10);
+ p->transinfo[tindex].goal_options = 0;
+ p->needppr &= ~(1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr |= (1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
+ p->needwdtr |= (1<<tindex);
+ p->needwdtr_copy |= (1<<tindex);
}
/*
* Get the INQUIRY checksum. We use this on Ultra 160/m
@@ -3039,6 +2958,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
#undef WIDE_INQUIRY_BITS
#undef SYNC_INQUIRY_BITS
#undef SCSI_VERSION_BITS
+#undef SCSI_DT_BIT
}
}
else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
@@ -4170,12 +4090,7 @@ aic7xxx_pci_intr(struct aic7xxx_host *p)
{
unsigned char status1;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_read_config_byte(p->pdev, PCI_STATUS + 1, &status1);
-#else
- pcibios_read_config_byte(p->pci_bus, p->pci_device_fn,
- PCI_STATUS + 1, &status1);
-#endif
if ( (status1 & DPE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
printk(WARN_LEAD "Data Parity Error during PCI address or PCI write"
@@ -4196,12 +4111,7 @@ aic7xxx_pci_intr(struct aic7xxx_host *p)
printk(WARN_LEAD "Data Parity Error has been reported via PCI pin "
"PERR#\n", p->host_no, -1, -1, -1);
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_write_config_byte(p->pdev, PCI_STATUS + 1, status1);
-#else
- pcibios_write_config_byte(p->pci_bus, p->pci_device_fn,
- PCI_STATUS + 1, status1);
-#endif
if (status1 & (DPR|RMA|RTA))
aic_outb(p, CLRPARERR, CLRINT);
@@ -4226,11 +4136,7 @@ aic7xxx_timer(struct aic7xxx_host *p)
unsigned long cpu_flags = 0;
struct aic7xxx_scb *scb;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
- DRIVER_LOCK
-#else
spin_lock_irqsave(&io_request_lock, cpu_flags);
-#endif
p->dev_timer_active &= ~(0x01 << MAX_TARGETS);
if ( (p->dev_timer_active & (0x01 << p->scsi_id)) &&
time_after_eq(jiffies, p->dev_expires[p->scsi_id]) )
@@ -4287,11 +4193,7 @@ aic7xxx_timer(struct aic7xxx_host *p)
}
aic7xxx_run_waiting_queues(p);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
- DRIVER_UNLOCK
-#else
spin_unlock_irqrestore(&io_request_lock, cpu_flags);
-#endif
}
/*+F*************************************************************************
@@ -4673,7 +4575,9 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
* As per the draft specs, any device capable of supporting any of
* the option values other than 0 are not allowed to reject the
* PPR message. Instead, they must negotiate out what they do
- * support instead of rejecting our offering.
+ * support instead of rejecting our offering or else they cause
+ * a parity error during msg_out phase to signal that they don't
+ * like our settings.
*/
p->needppr &= ~target_mask;
p->needppr_copy &= ~target_mask;
@@ -4813,39 +4717,36 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
case CHECK_CONDITION:
if ( !(scb->flags & SCB_SENSE) )
{
- unsigned char *sense_buffer;
- /*
- * XXX - How do we save the residual (if there is one).
- */
- if ( hscb->residual_SG_segment_count != 0 )
- aic7xxx_calculate_residual(p, scb);
-
/*
- * Send a sense command to the requesting target.
+ * Send a sense command to the requesting target.
* XXX - revisit this and get rid of the memcopys.
- */
+ */
memcpy(scb->sense_cmd, &generic_sense[0],
sizeof(generic_sense));
scb->sense_cmd[1] = (cmd->lun << 5);
scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
- sense_buffer = cmd->sense_buffer;
scb->sg_list[0].length =
cpu_to_le32(sizeof(cmd->sense_buffer));
+ scb->sg_list[0].address =
+ cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer,
+ sizeof(cmd->sense_buffer),
+ PCI_DMA_FROMDEVICE));
/*
* XXX - We should allow disconnection, but can't as it
* might allow overlapped tagged commands.
*/
- /* hscb->control &= DISCENB; */
+ /* hscb->control &= DISCENB; */
hscb->control = 0;
hscb->target_status = 0;
hscb->SG_list_pointer =
cpu_to_le32(SCB_DMA_ADDR(scb, scb->sg_list));
- hscb->data_count = scb->sg_list[0].length;
hscb->SCSI_cmd_pointer =
cpu_to_le32(SCB_DMA_ADDR(scb, scb->sense_cmd));
+ hscb->data_count = scb->sg_list[0].length;
+ hscb->data_pointer = scb->sg_list[0].address;
hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
hscb->residual_SG_segment_count = 0;
hscb->residual_data_count[0] = 0;
@@ -4855,53 +4756,6 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
scb->sg_count = hscb->SG_segment_count = 1;
scb->sg_length = sizeof(cmd->sense_buffer);
scb->tag_action = 0;
- /*
- * This problem could be caused if the target has lost power
- * or found some other way to loose the negotiation settings,
- * so if needed, we'll re-negotiate while doing the sense cmd.
- * However, if this SCB already was attempting to negotiate,
- * then we assume this isn't the problem and skip this part.
- */
- if ( (scb->cmd->cmnd[0] != TEST_UNIT_READY) &&
- (p->dev_flags[tindex] & DEVICE_SCANNED) &&
- !(p->dtr_pending & target_mask) )
- {
- p->needppr |= (p->needppr_copy & target_mask);
- p->needwdtr |= (p->needwdtr_copy & target_mask);
- p->needsdtr |= (p->needsdtr_copy & target_mask);
- }
- else if ( scb->cmd == p->dev_dtr_cmnd[tindex] )
- {
- /*
- * This is already a negotiation command, so we must have
- * already done PPR, WDTR or SDTR. Since our negotiation
- * could have gotten rejected, we don't really know the
- * full state of things. Don't do anything here, and allow
- * the negotiation_complete() handler to do the right
- * thing.
- */
-
- /*
- * This is the important part though. We are getting sense
- * info back from this device. It's going into a fake
- * command. We need to put that into the real command
- * instead so that the mid level SCSI code can act upon it.
- * So, when we set up these fake commands, the next pointer
- * is used to point to the real command. Use that to change
- * the address of our sense_buffer[] to the real command.
- * However, don't do this if the real command is also a
- * TEST_UNIT_READY as it will most likely pull down its own
- * SENSE information anyway.
- */
- if (cmd->next->cmnd[0] != TEST_UNIT_READY)
- sense_buffer = cmd->next->sense_buffer;
- }
- scb->sg_list[0].address =
- cpu_to_le32(pci_map_single(p->pdev, sense_buffer,
- sizeof(cmd->sense_buffer),
- PCI_DMA_FROMDEVICE));
- hscb->data_pointer = scb->sg_list[0].address;
-
scb->flags |= SCB_SENSE;
/*
* Ensure the target is busy since this will be an
@@ -4924,7 +4778,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
aic7xxx_error(cmd) = DID_OK;
break;
} /* first time sense, no errors */
- aic7xxx_error(cmd) = DID_OK;
+ aic7xxx_error(cmd) = DID_ERROR;
scb->flags &= ~SCB_SENSE;
break;
@@ -5171,51 +5025,14 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
}
else if (scb->flags & SCB_MSGOUT_PPR)
{
- unsigned int max_sync, period;
- unsigned char options = 0;
-
- if (p->features & AHC_ULTRA2)
- {
- if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
- !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
- {
- if( (p->features & AHC_ULTRA3) &&
- (p->dev_flags[tindex] & DEVICE_SCSI_3) &&
- (p->transinfo[tindex].goal_width ==
- MSG_EXT_WDTR_BUS_16_BIT) &&
- (p->transinfo[tindex].goal_options != 0) )
- {
- max_sync = AHC_SYNCRATE_ULTRA3;
- options = p->transinfo[tindex].goal_options;
- }
- else
- {
- max_sync = AHC_SYNCRATE_ULTRA2;
- }
- }
- else
- {
- max_sync = AHC_SYNCRATE_ULTRA;
- }
- }
- else if (p->features & AHC_ULTRA)
- {
- max_sync = AHC_SYNCRATE_ULTRA;
- }
- else
- {
- max_sync = AHC_SYNCRATE_FAST;
- }
- period = p->transinfo[tindex].goal_period;
- aic7xxx_find_syncrate(p, &period, max_sync, &options);
- p->transinfo[tindex].goal_period = period;
- p->transinfo[tindex].goal_options = options;
if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n",
- p->host_no, CTL_OF_SCB(scb), period,
+ p->host_no, CTL_OF_SCB(scb),
+ p->transinfo[tindex].goal_period,
p->transinfo[tindex].goal_offset,
- p->transinfo[tindex].goal_width, options);
+ p->transinfo[tindex].goal_width,
+ p->transinfo[tindex].goal_options);
}
aic7xxx_construct_ppr(p, scb);
}
@@ -5261,8 +5078,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no,
- CTL_OF_SCB(scb),
- p->transinfo[tindex].goal_period,
+ CTL_OF_SCB(scb), period,
p->transinfo[tindex].goal_offset);
}
aic7xxx_construct_sdtr(p, period,
@@ -5375,15 +5191,15 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
(aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
- (aic_inb(p, SCB_RESID_DCNT + 2) << 24);
- index = scb->sg_count - resid_sgcnt;
+ (aic_inb(p, SCB_RESID_DCNT + 2) << 16);
+ index = scb->sg_count - (resid_sgcnt + 1);
native_addr = le32_to_cpu(scb->sg_list[index].address);
native_length = le32_to_cpu(scb->sg_list[index].length);
/*
* Make sure this is a valid sg_seg for the given pointer
*/
if(cur_addr < native_addr ||
- cur_addr > (native_addr + native_length))
+ cur_addr > (native_addr + native_length + 1))
{
printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n",
p->host_no, CTL_OF_SCB(scb), cur_addr);
@@ -5400,16 +5216,31 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
p->host_no, CTL_OF_SCB(scb),
le32_to_cpu(scb->sg_list[index + 1].address),
le32_to_cpu(scb->sg_list[index + 1].length));
+ printk(WARN_LEAD " cur_address:0x%x resid_dcnt:0x%06x\n",
+ p->host_no, CTL_OF_SCB(scb),
+ cur_addr, resid_dcnt);
break;
}
- /*
- * If our current address matches the sg_seg->address then we
- * have to back up the sg array to the previous segment and set
- * it up to have only one byte of transfer left to go.
- */
- if(cur_addr == native_addr)
+ if( (resid_sgcnt == 0) &&
+ ((resid_dcnt == 0) || (resid_dcnt == 0xffffff)))
+ {
+ /*
+ * We are at the end of the transfer and this is about a byte
+ * we ignored already (because the sequencer knew this was
+ * the last segment and set the adapter to ignore any wide
+ * residue bytes that might come through, which is only done
+ * on the last scatter gather segment of transfers).
+ */
+ break;
+ }
+ else if(cur_addr == native_addr)
{
+ /*
+ * If our current address matches the sg_seg->address then we
+ * have to back up the sg array to the previous segment and set
+ * it up to have only one byte of transfer left to go.
+ */
if(index == 0)
{
printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
@@ -5439,39 +5270,6 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
- /*
- * The sequencer actually wants to find the new address and byte
- * count in the SHCNT and SHADDR register sets. These registers
- * are a shadow of the regular HCNT and HADDR registers. On the
- * Ultra2 controllers, these registers are read only and the way
- * we have to set their values is to put the values we want into
- * the HCNT and HADDR registers and then output PRELOADEN into
- * the DFCNTRL register which causes the card to latch the current
- * values in the HADDR and HCNT registers and drop it through to
- * the shadow registers. On older cards we copy them directly
- * across by hand.
- */
- if(p->features & AHC_ULTRA2)
- {
- aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
- i=0;
- udelay(1);
- while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
- {
- aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
- udelay(1);
- }
- }
- else
- {
- aic_outb(p, 1, STCNT);
- aic_outb(p, 0, STCNT + 1);
- aic_outb(p, 0, STCNT + 2);
- aic_outb(p, cur_addr & 0xff, SHADDR);
- aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
- aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
- aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
- }
}
else
{
@@ -5491,28 +5289,46 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
- if(p->features & AHC_ULTRA2)
+ }
+ /*
+ * The sequencer actually wants to find the new address and byte
+ * count in the SHCNT and SHADDR register sets. These registers
+ * are a shadow of the regular HCNT and HADDR registers. On the
+ * Ultra2 controllers, these registers are read only and the way
+ * we have to set their values is to put the values we want into
+ * the HCNT and HADDR registers and then output PRELOADEN into
+ * the DFCNTRL register which causes the card to latch the current
+ * values in the HADDR and HCNT registers and drop it through to
+ * the shadow registers. On older cards we copy them directly
+ * across by hand.
+ */
+ if(p->features & AHC_ULTRA2)
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ i=0;
+ udelay(1);
+ while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
{
- aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
- i=0;
udelay(1);
- while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
- {
- aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
- udelay(1);
- }
}
- else
+ aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL);
+ i=0;
+ udelay(1);
+ while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000))
{
- aic_outb(p, resid_dcnt & 0xff, STCNT);
- aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1);
- aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2);
- aic_outb(p, cur_addr & 0xff, SHADDR);
- aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
- aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
- aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+ udelay(1);
}
}
+ else
+ {
+ aic_outb(p, resid_dcnt & 0xff, STCNT);
+ aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1);
+ aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2);
+ aic_outb(p, cur_addr & 0xff, SHADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+ }
}
break;
@@ -5921,6 +5737,7 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
reply = TRUE;
scb->flags &= ~SCB_MSGOUT_BITS;
scb->flags |= SCB_MSGOUT_PPR;
+ p->dev_flags[tindex] |= DEVICE_SCSI_3;
if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
{
/*
@@ -5954,7 +5771,6 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
p->transinfo[tindex].user_width;
p->transinfo[tindex].goal_options =
p->transinfo[tindex].user_options;
- p->needppr_copy |= target_mask;
}
if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
@@ -5988,6 +5804,25 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
break;
}
}
+ if ( (p->transinfo[tindex].goal_period > 9) ||
+ (p->transinfo[tindex].goal_options == 0) )
+ {
+ scb->flags &= ~SCB_MSGOUT_BITS;
+ reject = TRUE;
+ reply = FALSE;
+ p->needppr &= ~(1 << tindex);
+ p->needppr_copy &= ~(1 << tindex);
+ if ( p->transinfo[tindex].goal_offset )
+ {
+ p->needsdtr |= (1 << tindex);
+ p->needsdtr_copy |= (1 << tindex);
+ }
+ if ( p->transinfo[tindex].goal_width )
+ {
+ p->needwdtr |= (1 << tindex);
+ p->needwdtr_copy |= (1 << tindex);
+ }
+ }
}
else
{
@@ -5995,7 +5830,7 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
default:
{
- reply = TRUE;
+ reject = TRUE;
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
(aic7xxx_verbose > 0xffff)) )
@@ -6021,27 +5856,18 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
}
}
- aic7xxx_set_width(p, target, channel, lun, bus_width,
- AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
- syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
- &new_trans_options);
- aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
- aic7xxx_set_syncrate(p, syncrate, target, channel, period,
- offset, new_trans_options,
- AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-
- if( (offset != saved_offset) ||
- (trans_options != new_trans_options) ||
- ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
- (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) )
+ if ( !reject )
{
aic7xxx_set_width(p, target, channel, lun, bus_width,
- AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
+ &new_trans_options);
+ aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
aic7xxx_set_syncrate(p, syncrate, target, channel, period,
offset, new_trans_options,
- AHC_TRANS_GOAL|AHC_TRANS_QUITE);
- reply = TRUE;
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
}
+
p->dtr_pending &= ~target_mask;
p->needppr &= ~target_mask;
if(reply)
@@ -6445,15 +6271,33 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
}
}
/*
- * Restarting the sequencer will stop the selection and make sure devices
- * are allowed to reselect in.
+ * Keep the sequencer from trying to restart any selections
+ */
+ aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+ /*
+ * Make sure the data bits on the bus are released
+ * Don't do this on 7770 chipsets, it makes them give us
+ * a BRKADDRINT and kills the card.
*/
- aic_outb(p, 0, SCSISEQ);
+ if( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI )
+ aic_outb(p, 0, SCSIBUSL);
+
+ /*
+ * Delay for the selection timeout delay period then stop the selection
+ */
+ udelay(301);
aic_outb(p, CLRSELINGO, CLRSINT0);
+ /*
+ * Clear out all the interrupt status bits
+ */
aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1);
p->flags &= ~AHC_HANDLING_REQINITS;
aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1);
aic_outb(p, CLRSCSIINT, CLRINT);
+ /*
+ * Restarting the sequencer will stop the selection and make sure devices
+ * are allowed to reselect in.
+ */
restart_sequencer(p);
unpause_sequencer(p, TRUE);
}
@@ -6519,7 +6363,9 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
* A parity error has occurred during a data
* transfer phase. Flag it and continue.
*/
- if( (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) && (lastphase == P_DATAIN) )
+ if( (p->features & AHC_ULTRA3) &&
+ (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) &&
+ (lastphase == P_DATAIN) )
{
printk(WARN_LEAD "CRC error during %s phase.\n",
p->host_no, CTL_OF_SCB(scb), phase);
@@ -6544,13 +6390,50 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
p->host_no, CTL_OF_SCB(scb));
}
}
- else
+ else if( (lastphase == P_MESGOUT) &&
+ (cmd == p->dev_dtr_cmnd[tindex]) &&
+ (scb->flags & SCB_MSGOUT_PPR) )
{
- printk(WARN_LEAD "Parity error during %s phase.\n",
- p->host_no, CTL_OF_SCB(scb), phase);
+ /*
+ * As per the draft specs, any device capable of supporting any of
+ * the option values other than 0 are not allowed to reject the
+ * PPR message. Instead, they must negotiate out what they do
+ * support instead of rejecting our offering or else they cause
+ * a parity error during msg_out phase to signal that they don't
+ * like our settings.
+ */
+ p->needppr &= ~(1 << tindex);
+ p->needppr_copy &= ~(1 << tindex);
+ aic7xxx_set_width(p, scb->cmd->target, scb->cmd->channel, scb->cmd->lun,
+ MSG_EXT_WDTR_BUS_8_BIT,
+ (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
+ aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0,
+ 0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+ p->transinfo[tindex].goal_options = 0;
+ p->dtr_pending &= ~(1 << tindex);
+ scb->flags &= ~SCB_MSGOUT_BITS;
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "parity error during PPR message, reverting "
+ "to WDTR/SDTR\n", p->host_no, CTL_OF_SCB(scb));
+ }
+ if ( p->transinfo[tindex].goal_width )
+ {
+ p->needwdtr |= (1 << tindex);
+ p->needwdtr_copy |= (1 << tindex);
+ }
+ if ( p->transinfo[tindex].goal_offset )
+ {
+ if( p->transinfo[tindex].goal_period <= 9 )
+ {
+ p->transinfo[tindex].goal_period = 10;
+ }
+ p->needsdtr |= (1 << tindex);
+ p->needsdtr_copy |= (1 << tindex);
+ }
+ scb = NULL;
}
-
- if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
+ else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
{
struct aic7xxx_syncrate *syncrate;
unsigned int period = p->transinfo[tindex].cur_period;
@@ -6562,6 +6445,8 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
* instead of slowing down if those exist. That's hard to do with simple
* checksums though.
*/
+ printk(WARN_LEAD "Parity error during %s phase.\n",
+ p->host_no, CTL_OF_SCB(scb), phase);
if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
{
syncrate++;
@@ -6569,20 +6454,59 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
(!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
{
p->transinfo[tindex].goal_period = syncrate->period;
- if( !(syncrate->sxfr_ultra2 & 0x40) )
+ if( p->transinfo[tindex].goal_period > 9 )
{
p->transinfo[tindex].goal_options = 0;
+ p->needppr &= ~(1<<tindex);
+ p->needsdtr |= (1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
+ if (p->transinfo[tindex].goal_width)
+ {
+ p->needwdtr |= (1<<tindex);
+ p->needwdtr_copy |= (1<<tindex);
+ }
+ }
+ }
+ else if (p->transinfo[tindex].goal_width)
+ {
+ p->transinfo[tindex].goal_width = 0;
+ p->needwdtr &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
+ p->transinfo[tindex].goal_offset =
+ p->transinfo[tindex].user_offset;
+ p->transinfo[tindex].goal_period =
+ p->transinfo[tindex].user_period;
+ p->transinfo[tindex].goal_options =
+ p->transinfo[tindex].user_options;
+ if( p->transinfo[tindex].goal_period <= 9 )
+ {
+ p->needppr |= (1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needppr_copy |= (1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ }
+ else
+ {
+ p->needppr &= ~(1<<tindex);
+ p->needsdtr |= (1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
}
}
else
{
p->transinfo[tindex].goal_offset = 0;
- p->transinfo[tindex].goal_period = 0;
+ p->transinfo[tindex].goal_period = 255;
p->transinfo[tindex].goal_options = 0;
+ p->transinfo[tindex].goal_width = 0;
+ p->needppr &= ~(1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needwdtr &= ~(1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
}
- p->needppr |= (p->needppr_copy & (1<<tindex));
- p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
- p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
}
p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR;
}
@@ -6600,6 +6524,7 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
if (mesg_out != MSG_NOOP)
{
aic_outb(p, mesg_out, MSG_OUT);
+ aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
scb = NULL;
}
aic_outb(p, CLRSCSIPERR, CLRSINT1);
@@ -6791,7 +6716,7 @@ aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
{
struct aic7xxx_scb *scb = NULL;
Scsi_Cmnd *cmd;
- unsigned char scb_index;
+ unsigned char scb_index, tindex;
#ifdef AIC7XXX_VERBOSE_DEBUGGING
if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
@@ -6817,23 +6742,21 @@ aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
scb_index = p->qoutfifo[p->qoutfifonext];
p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
if ( scb_index >= p->scb_data->numscbs )
- scb = NULL;
- else
- scb = p->scb_data->scb_array[scb_index];
- if (scb == NULL)
{
printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
-1, -1, -1, scb_index);
continue;
}
- else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+ scb = p->scb_data->scb_array[scb_index];
+ if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
{
printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
"0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
(unsigned long) scb->cmd);
continue;
}
- else if (scb->flags & SCB_QUEUED_ABORT)
+ tindex = TARGET_INDEX(scb->cmd);
+ if (scb->flags & SCB_QUEUED_ABORT)
{
pause_sequencer(p);
if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) &&
@@ -6856,6 +6779,43 @@ aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
*/
scb->flags &= ~(SCB_ABORT|SCB_RESET);
}
+ else if (scb->flags & SCB_SENSE)
+ {
+ char *buffer = &scb->cmd->sense_buffer[0];
+ if (scb->cmd == p->dev_dtr_cmnd[tindex])
+ {
+ struct aic7xxx_scb *old_scb;
+ /*
+ * We have valid sense data, send it back immediately.
+ */
+ old_scb = p->scb_data->scb_array[scb->cmd->next->tag];
+ *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer;
+ old_scb->hscb->target_status = scb->hscb->target_status;
+ old_scb->cmd->result = scb->hscb->target_status;
+ old_scb->cmd->result |= (DID_ERROR << 16);
+ aic7xxx_status(old_scb->cmd) = scb->hscb->target_status;
+ scbq_remove(&p->waiting_scbs, old_scb);
+ scbq_remove(&p->delayed_scbs[tindex], old_scb);
+ scb->cmd->next = NULL;
+ aic7xxx_done(p, scb);
+ aic7xxx_done(p, old_scb);
+ continue;
+ }
+ else if (buffer[12] == 0x47 || buffer[12] == 0x54)
+ {
+ /*
+ * SCSI errors, run domain validation and re-run negotiation
+ */
+ p->needdv |= (1<<tindex);
+ /*
+ * Signal that we need to re-negotiate things, this also gets us our
+ * INQUIRY command to re-checksum off of.
+ */
+ p->needppr |= (p->needppr_copy & (1<<tindex));
+ p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+ p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+ }
+ }
switch (status_byte(scb->hscb->target_status))
{
case QUEUE_FULL:
@@ -6985,6 +6945,13 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
if (intstat & SEQINT)
{
+ /*
+ * Read the CCSCBCTL register to work around a bug in the Ultra2 cards
+ */
+ if(p->features & AHC_ULTRA2)
+ {
+ aic_inb(p, CCSCBCTL);
+ }
aic7xxx_handle_seqint(p, intstat);
}
@@ -7019,10 +6986,10 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
p = (struct aic7xxx_host *)dev_id;
if(!p)
return;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
spin_lock_irqsave(&io_request_lock, cpu_flags);
if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags))
{
+ spin_unlock_irqrestore(&io_request_lock, cpu_flags);
return;
}
do
@@ -7033,21 +7000,6 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
aic7xxx_run_waiting_queues(p);
clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags);
spin_unlock_irqrestore(&io_request_lock, cpu_flags);
-#else
- if(set_bit(AHC_IN_ISR_BIT, (int *)&p->flags))
- {
- return;
- }
- DRIVER_LOCK
- do
- {
- aic7xxx_isr(irq, dev_id, regs);
- } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
- DRIVER_UNLOCK
- aic7xxx_done_cmds_complete(p);
- aic7xxx_run_waiting_queues(p);
- clear_bit(AHC_IN_ISR_BIT, (int *)&p->flags);
-#endif
}
/*+F*************************************************************************
@@ -7067,7 +7019,7 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
* with queue depths for individual devices. It also allows tagged
* queueing to be [en|dis]abled for a specific adapter.
*-F*************************************************************************/
-static void
+static int
aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
{
int default_depth = 3;
@@ -7077,6 +7029,14 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
tindex = device->id | (device->channel << 3);
target_mask = (1 << tindex);
+ if (p->dev_max_queue_depth[tindex] > 1)
+ {
+ /*
+ * We've already scanned this device, leave it alone
+ */
+ return(p->dev_max_queue_depth[tindex]);
+ }
+
device->queue_depth = default_depth;
p->dev_temp_queue_depth[tindex] = 1;
p->dev_max_queue_depth[tindex] = 1;
@@ -7145,6 +7105,7 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
}
}
}
+ return(p->dev_max_queue_depth[tindex]);
}
/*+F*************************************************************************
@@ -7172,8 +7133,7 @@ aic7xxx_select_queue_depth(struct Scsi_Host *host,
{
if (device->host == host)
{
- aic7xxx_device_queue_depth(p, device);
- scbnum += device->queue_depth;
+ scbnum += aic7xxx_device_queue_depth(p, device);
}
}
while (scbnum > p->scb_data->numscbs)
@@ -7481,7 +7441,6 @@ release_seeprom(struct aic7xxx_host *p)
*/
CLOCK_PULSE(p);
aic_outb(p, 0, SEECTL);
- CLOCK_PULSE(p);
}
/*+F*************************************************************************
@@ -7757,8 +7716,6 @@ write_brdctl(struct aic7xxx_host *p, unsigned char value)
}
}
-#undef CLOCK_PULSE
-
/*+F*************************************************************************
* Function:
* aic785x_cable_detect
@@ -7773,16 +7730,64 @@ aic785x_cable_detect(struct aic7xxx_host *p, int *int_50,
unsigned char brdctl;
aic_outb(p, BRDRW | BRDCS, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
aic_outb(p, 0, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
brdctl = aic_inb(p, BRDCTL);
- udelay(1);
+ CLOCK_PULSE(p);
*int_50 = !(brdctl & BRDDAT5);
*ext_present = !(brdctl & BRDDAT6);
*eeprom = (aic_inb(p, SPIOCAP) & EEPROM);
}
+#undef CLOCK_PULSE
+
+/*+F*************************************************************************
+ * Function:
+ * aic2940_uwpro_cable_detect
+ *
+ * Description:
+ * Detect the cables that are present on the 2940-UWPro cards
+ *
+ * NOTE: This functions assumes the SEEPROM will have already been aquired
+ * prior to invocation of this function.
+ *-F*************************************************************************/
+static void
+aic2940_uwpro_wide_cable_detect(struct aic7xxx_host *p, int *int_68,
+ int *ext_68, int *eeprom)
+{
+ unsigned char brdctl;
+
+ /*
+ * First read the status of our cables. Set the rom bank to
+ * 0 since the bank setting serves as a multiplexor for the
+ * cable detection logic. BRDDAT5 controls the bank switch.
+ */
+ write_brdctl(p, 0);
+
+ /*
+ * Now we read the state of the internal 68 connector. BRDDAT6
+ * is don't care, BRDDAT7 is internal 68. The cable is
+ * present if the bit is 0
+ */
+ brdctl = read_brdctl(p);
+ *int_68 = !(brdctl & BRDDAT7);
+
+ /*
+ * Set the bank bit in brdctl and then read the external cable state
+ * and the EEPROM status
+ */
+ write_brdctl(p, BRDDAT5);
+ brdctl = read_brdctl(p);
+
+ *ext_68 = !(brdctl & BRDDAT6);
+ *eeprom = !(brdctl & BRDDAT7);
+
+ /*
+ * We're done, the calling function will release the SEEPROM for us
+ */
+}
+
/*+F*************************************************************************
* Function:
* aic787x_cable_detect
@@ -7887,59 +7892,182 @@ configure_termination(struct aic7xxx_host *p)
max_target = 8;
aic_outb(p, SEEMS | SEECS, SEECTL);
sxfrctl1 &= ~STPWEN;
- if ( (p->adapter_control & CFAUTOTERM) ||
- (p->features & AHC_NEW_AUTOTERM) )
+ /*
+ * The termination/cable detection logic is split into three distinct
+ * groups. Ultra2 and later controllers, 2940UW-Pro controllers, and
+ * older 7850, 7860, 7870, 7880, and 7895 controllers. Each has its
+ * own unique way of detecting their cables and writing the results
+ * back to the card.
+ */
+ if (p->features & AHC_ULTRA2)
{
- if ( (p->adapter_control & CFAUTOTERM) &&
- !(p->features & AHC_NEW_AUTOTERM) )
+ /*
+ * As long as user hasn't overridden term settings, always check the
+ * cable detection logic
+ */
+ if (aic7xxx_override_term == -1)
{
- printk(KERN_INFO "(scsi%d) Warning - detected auto-termination\n",
- p->host_no);
- printk(KERN_INFO "(scsi%d) Please verify driver detected settings are "
- "correct.\n", p->host_no);
- printk(KERN_INFO "(scsi%d) If not, then please properly set the device "
- "termination\n", p->host_no);
- printk(KERN_INFO "(scsi%d) in the Adaptec SCSI BIOS by hitting CTRL-A "
- "when prompted\n", p->host_no);
- printk(KERN_INFO "(scsi%d) during machine bootup.\n", p->host_no);
+ aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high,
+ &enableLVD_low, &enableLVD_high,
+ &eprom_present);
+ }
+
+ /*
+ * If the user is overriding settings, then they have been preserved
+ * to here as fake adapter_control entries. Parse them and allow
+ * them to override the detected settings (if we even did detection).
+ */
+ if (!(p->adapter_control & CFSEAUTOTERM))
+ {
+ enableSE_low = (p->adapter_control & CFSTERM);
+ enableSE_high = (p->adapter_control & CFWSTERM);
+ }
+ if (!(p->adapter_control & CFAUTOTERM))
+ {
+ enableLVD_low = enableLVD_high = (p->adapter_control & CFLVDSTERM);
}
- /* Configure auto termination. */
- if (p->features & AHC_NEW_AUTOTERM)
+ /*
+ * Now take those settings that we have and translate them into the
+ * values that must be written into the registers.
+ *
+ * Flash Enable = BRDDAT7
+ * Secondary High Term Enable = BRDDAT6
+ * Secondary Low Term Enable = BRDDAT5
+ * LVD/Primary High Term Enable = BRDDAT4
+ * LVD/Primary Low Term Enable = STPWEN bit in SXFRCTL1
+ */
+ if (enableLVD_low != 0)
{
- if (aic7xxx_override_term == -1)
- aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high,
- &enableLVD_low, &enableLVD_high,
- &eprom_present);
- if (!(p->adapter_control & CFSEAUTOTERM))
+ sxfrctl1 |= STPWEN;
+ p->flags |= AHC_TERM_ENB_LVD;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) LVD/Primary Low byte termination "
+ "Enabled\n", p->host_no);
+ }
+
+ if (enableLVD_high != 0)
+ {
+ brddat |= BRDDAT4;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) LVD/Primary High byte termination "
+ "Enabled\n", p->host_no);
+ }
+
+ if (enableSE_low != 0)
+ {
+ brddat |= BRDDAT5;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) Secondary Low byte termination "
+ "Enabled\n", p->host_no);
+ }
+
+ if (enableSE_high != 0)
+ {
+ brddat |= BRDDAT6;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) Secondary High byte termination "
+ "Enabled\n", p->host_no);
+ }
+ }
+ else if (p->features & AHC_NEW_AUTOTERM)
+ {
+ /*
+ * The 50 pin connector termination is controlled by STPWEN in the
+ * SXFRCTL1 register. Since the Adaptec docs typically say the
+ * controller is not allowed to be in the middle of a cable and
+ * this is the only connection on that stub of the bus, there is
+ * no need to even check for narrow termination, it's simply
+ * always on.
+ */
+ sxfrctl1 |= STPWEN;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) Narrow channel termination Enabled\n",
+ p->host_no);
+
+ if (p->adapter_control & CFAUTOTERM)
+ {
+ aic2940_uwpro_wide_cable_detect(p, &internal68_present,
+ &external_present,
+ &eprom_present);
+ printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, "
+ "Ext-68 %s)\n", p->host_no,
+ "Don't Care",
+ internal68_present ? "YES" : "NO",
+ external_present ? "YES" : "NO");
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no,
+ eprom_present ? "is" : "is not");
+ if (internal68_present && external_present)
{
- enableSE_low = (p->adapter_control & CFSTERM);
- enableSE_high = (p->adapter_control & CFWSTERM);
+ brddat = 0;
+ p->flags &= ~AHC_TERM_ENB_SE_HIGH;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) Wide channel termination Disabled\n",
+ p->host_no);
}
- if (!(p->adapter_control & CFAUTOTERM))
+ else
{
- enableLVD_low = enableLVD_high = (p->adapter_control & CFLVDSTERM);
+ brddat = BRDDAT6;
+ p->flags |= AHC_TERM_ENB_SE_HIGH;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n",
+ p->host_no);
}
- internal50_present = 0;
- internal68_present = 1;
- external_present = 1;
- }
- else if ( (p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870 )
- {
- aic787x_cable_detect(p, &internal50_present, &internal68_present,
- &external_present, &eprom_present);
}
else
{
- aic785x_cable_detect(p, &internal50_present, &external_present,
- &eprom_present);
+ /*
+ * The termination of the Wide channel is done more like normal
+ * though, and the setting of this termination is done by writing
+ * either a 0 or 1 to BRDDAT6 of the BRDDAT register
+ */
+ if (p->adapter_control & CFWSTERM)
+ {
+ brddat = BRDDAT6;
+ p->flags |= AHC_TERM_ENB_SE_HIGH;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n",
+ p->host_no);
+ }
+ else
+ {
+ brddat = 0;
+ }
}
-
- if (max_target <= 8)
- internal68_present = 0;
-
- if ( !(p->features & AHC_NEW_AUTOTERM) )
+ }
+ else
+ {
+ if (p->adapter_control & CFAUTOTERM)
{
+ if (p->flags & AHC_MOTHERBOARD)
+ {
+ printk(KERN_INFO "(scsi%d) Warning - detected auto-termination\n",
+ p->host_no);
+ printk(KERN_INFO "(scsi%d) Please verify driver detected settings "
+ "are correct.\n", p->host_no);
+ printk(KERN_INFO "(scsi%d) If not, then please properly set the "
+ "device termination\n", p->host_no);
+ printk(KERN_INFO "(scsi%d) in the Adaptec SCSI BIOS by hitting "
+ "CTRL-A when prompted\n", p->host_no);
+ printk(KERN_INFO "(scsi%d) during machine bootup.\n", p->host_no);
+ }
+ /* Configure auto termination. */
+
+ if ( (p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870 )
+ {
+ aic787x_cable_detect(p, &internal50_present, &internal68_present,
+ &external_present, &eprom_present);
+ }
+ else
+ {
+ aic785x_cable_detect(p, &internal50_present, &external_present,
+ &eprom_present);
+ }
+
+ if (max_target <= 8)
+ internal68_present = 0;
+
if (max_target > 8)
{
printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, "
@@ -7955,100 +8083,73 @@ configure_termination(struct aic7xxx_host *p)
internal50_present ? "YES" : "NO",
external_present ? "YES" : "NO");
}
- }
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no,
- eprom_present ? "is" : "is not");
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no,
+ eprom_present ? "is" : "is not");
- /*
- * Now set the termination based on what we found. BRDDAT6
- * controls wide termination enable.
- * Flash Enable = BRDDAT7
- * SE High Term Enable = BRDDAT6
- * SE Low Term Enable = BRDDAT5 (7890)
- * LVD High Term Enable = BRDDAT4 (7890)
- */
- if ( !(p->features & AHC_NEW_AUTOTERM) &&
- (internal50_present && internal68_present && external_present) )
- {
- printk(KERN_INFO "(scsi%d) Illegal cable configuration!! Only two\n",
- p->host_no);
- printk(KERN_INFO "(scsi%d) connectors on the SCSI controller may be "
- "in use at a time!\n", p->host_no);
/*
- * Force termination (low and high byte) on. This is safer than
- * leaving it completely off, especially since this message comes
- * most often from motherboard controllers that don't even have 3
- * connectors, but instead are failing the cable detection.
+ * Now set the termination based on what we found. BRDDAT6
+ * controls wide termination enable.
+ * Flash Enable = BRDDAT7
+ * SE High Term Enable = BRDDAT6
*/
- internal50_present = external_present = 0;
- enableSE_high = enableSE_low = 1;
- }
-
- if ((max_target > 8) &&
- ((external_present == 0) || (internal68_present == 0) ||
- (enableSE_high != 0)))
- {
- brddat |= BRDDAT6;
- p->flags |= AHC_TERM_ENB_SE_HIGH;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
+ if (internal50_present && internal68_present && external_present)
+ {
+ printk(KERN_INFO "(scsi%d) Illegal cable configuration!! Only two\n",
p->host_no);
- }
+ printk(KERN_INFO "(scsi%d) connectors on the SCSI controller may be "
+ "in use at a time!\n", p->host_no);
+ /*
+ * Force termination (low and high byte) on. This is safer than
+ * leaving it completely off, especially since this message comes
+ * most often from motherboard controllers that don't even have 3
+ * connectors, but instead are failing the cable detection.
+ */
+ internal50_present = external_present = 0;
+ enableSE_high = enableSE_low = 1;
+ }
- if ( (((internal50_present ? 1 : 0) +
- (internal68_present ? 1 : 0) +
- (external_present ? 1 : 0)) <= 1) ||
- (enableSE_low != 0) )
- {
- if (p->features & AHC_NEW_AUTOTERM)
- brddat |= BRDDAT5;
- else
- sxfrctl1 |= STPWEN;
- p->flags |= AHC_TERM_ENB_SE_LOW;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
- p->host_no);
- }
+ if ((max_target > 8) &&
+ ((external_present == 0) || (internal68_present == 0)) )
+ {
+ brddat |= BRDDAT6;
+ p->flags |= AHC_TERM_ENB_SE_HIGH;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
+ p->host_no);
+ }
- if (enableLVD_low != 0)
- {
- sxfrctl1 |= STPWEN;
- p->flags |= AHC_TERM_ENB_LVD;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) LVD Low byte termination Enabled\n",
- p->host_no);
- }
-
- if (enableLVD_high != 0)
- {
- brddat |= BRDDAT4;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) LVD High byte termination Enabled\n",
- p->host_no);
+ if ( ((internal50_present ? 1 : 0) +
+ (internal68_present ? 1 : 0) +
+ (external_present ? 1 : 0)) <= 1 )
+ {
+ sxfrctl1 |= STPWEN;
+ p->flags |= AHC_TERM_ENB_SE_LOW;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
+ p->host_no);
+ }
}
- }
- else
- {
- if (p->adapter_control & CFSTERM)
+ else /* p->adapter_control & CFAUTOTERM */
{
- if (p->features & AHC_NEW_AUTOTERM)
- brddat |= BRDDAT5;
- else
+ if (p->adapter_control & CFSTERM)
+ {
sxfrctl1 |= STPWEN;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
- p->host_no);
- }
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
+ p->host_no);
+ }
- if (p->adapter_control & CFWSTERM)
- {
- brddat |= BRDDAT6;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
- p->host_no);
+ if (p->adapter_control & CFWSTERM)
+ {
+ brddat |= BRDDAT6;
+ if (aic7xxx_verbose & VERBOSE_PROBE2)
+ printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
+ p->host_no);
+ }
}
}
+
aic_outb(p, sxfrctl1, SXFRCTL1);
write_brdctl(p, brddat);
release_seeprom(p);
@@ -8236,23 +8337,8 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
}
aic_outb(p, 0, SEQ_FLAGS);
- /*
- * We are starting to do real work on the card....it's possible we could
- * generate some spurious interrupts at this point, especially in the
- * event of a PCI error or some such. If there are other devices already
- * registered on the same interrupt as us, this could cause the machine
- * to lock up. So, we disable the interrupt this card is on until we
- * finish our card setup. We only need to do this for modules, if we are
- * compiled into the kernel then interrupts are already off during this
- * part of the code.
- */
-#ifdef MODULE
- disable_irq(p->irq);
-#endif
-
detect_maxscb(p);
-
printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
if (aic7xxx_verbose & VERBOSE_PROBE2)
{
@@ -8277,12 +8363,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
{
unsigned char devconfig;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_read_config_byte(p->pdev, DEVCONFIG, &devconfig);
-#else
- pcibios_read_config_byte(p->pci_bus, p->pci_device_fn,
- DEVCONFIG, &devconfig);
-#endif
if ( (aic7xxx_stpwlev >> p->instance) & 0x01 )
{
devconfig |= STPWLEVEL;
@@ -8295,12 +8376,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
if (aic7xxx_verbose & VERBOSE_PROBE2)
printk("(scsi%d) Force clearing STPWLEVEL bit\n", p->host_no);
}
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_write_config_byte(p->pdev, DEVCONFIG, devconfig);
-#else
- pcibios_write_config_byte(p->pci_bus, p->pci_device_fn,
- DEVCONFIG, devconfig);
-#endif
}
}
#endif
@@ -8404,7 +8480,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
* we won't have a power source for the SCSI termination, which means
* we'll see infinite incoming bus resets.
*/
- if(p->flags & AHC_NO_STPWR)
+ if(p->flags & AHC_NO_STPWEN)
aic_outb(p, ENSELTIMO | ENSCSIPERR, SIMODE1);
else
aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
@@ -8484,9 +8560,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
printk("(scsi%d) Unable to allocate hardware SCB array; "
"failing detection.\n", p->host_no);
aic_outb(p, 0, SIMODE1);
-#ifdef MODULE
- enable_irq(p->irq);
-#endif
p->irq = 0;
return(0);
}
@@ -8670,9 +8743,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring "
"controller.\n", p->host_no, p->irq);
aic_outb(p, 0, SIMODE1);
-#ifdef MODULE
- enable_irq(p->irq);
-#endif
p->irq = 0;
return (0);
}
@@ -8682,10 +8752,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
p->host_no, -1, -1 , -1);
aic7xxx_clear_intstat(p);
-#ifdef MODULE
- enable_irq(p->irq);
-#endif
-
unpause_sequencer(p, /* unpause_always */ TRUE);
return (found);
@@ -8715,10 +8781,10 @@ aic7xxx_chip_reset(struct aic7xxx_host *p)
* In the future, we may call this function as a last resort for
* error handling. Let's be nice and not do any unecessary delays.
*/
- wait = 1000; /* 1 second (1000 * 1 msec) */
+ wait = 1000; /* 1 msec (1000 * 1 msec) */
while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK))
{
- udelay(1); /* 1 msec */
+ udelay(1); /* 1 usec */
}
pause_sequencer(p);
@@ -8794,7 +8860,7 @@ aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
p->orderedtag = 0;
for (i=0; i<MAX_TARGETS; i++)
{
- p->transinfo[i].goal_period = 0;
+ p->transinfo[i].goal_period = 255;
p->transinfo[i].goal_offset = 0;
p->transinfo[i].goal_options = 0;
p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
@@ -9369,11 +9435,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
/*
* PCI-bus probe.
*/
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
if (pci_present())
-#else
- if (pcibios_present())
-#endif
{
struct
{
@@ -9412,7 +9474,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
AHC_AIC7860_FE, 7,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
AHC_AIC7860_FE, 7,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_AIC7860,
@@ -9420,7 +9482,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
AHC_AIC7860_FE, 8,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870,
- AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 9,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
+ AHC_AIC7870_FE, 9,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_AIC7870,
AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 10,
@@ -9437,7 +9500,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 13,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880,
- AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 14,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
+ AHC_AIC7880_FE, 14,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_AIC7880,
AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 15,
@@ -9460,106 +9524,93 @@ aic7xxx_detect(Scsi_Host_Template *template)
AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880,
- AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 18,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 19,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880,
AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7895_FE, 19,
+ AHC_AIC7895_FE, 20,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890, AHC_AIC7890,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7890_FE, 20,
+ AHC_AIC7890_FE, 21,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7890_FE, 20,
+ AHC_AIC7890_FE, 21,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7890_FE, 21,
+ AHC_AIC7890_FE, 22,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7890_FE, 22,
+ AHC_AIC7890_FE, 23,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7896_FE, 23,
+ AHC_AIC7896_FE, 24,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7896_FE, 24,
+ AHC_AIC7896_FE, 25,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7896_FE, 25,
+ AHC_AIC7896_FE, 26,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWR,
- AHC_AIC7860_FE, 26,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWEN,
+ AHC_AIC7860_FE, 27,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7892_FE, 27,
+ AHC_AIC7892_FE, 28,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7892_FE, 27,
+ AHC_AIC7892_FE, 28,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7892_FE, 27,
+ AHC_AIC7892_FE, 28,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7892_FE, 27,
+ AHC_AIC7892_FE, 28,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7899_FE, 28,
+ AHC_AIC7899_FE, 29,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7899_FE, 28,
+ AHC_AIC7899_FE, 29,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7899_FE, 28,
+ AHC_AIC7899_FE, 29,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7899_FE, 28,
+ AHC_AIC7899_FE, 29,
32, C56_66 },
};
unsigned short command;
unsigned int devconfig, i, oldverbose;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
struct pci_dev *pdev = NULL;
-#else
- int index;
- unsigned int piobase, mmapbase;
- unsigned char pci_bus, pci_devfn, pci_irq;
-#endif
for (i = 0; i < NUMBER(aic_pdevs); i++)
{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pdev = NULL;
while ((pdev = pci_find_device(aic_pdevs[i].vendor_id,
aic_pdevs[i].device_id,
pdev))) {
if (pci_enable_device(pdev))
continue;
-#else
- index = 0;
- while (!(pcibios_find_device(aic_pdevs[i].vendor_id,
- aic_pdevs[i].device_id,
- index++, &pci_bus, &pci_devfn)) ) {
-#endif
if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */
{
if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2))
@@ -9583,7 +9634,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
/*
* Read sundry information from PCI BIOS.
*/
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
temp_p->irq = pdev->irq;
temp_p->pdev = pdev;
temp_p->pci_bus = pdev->bus->number;
@@ -9595,7 +9645,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
{
if ( ((current_p->pci_bus == temp_p->pci_bus) &&
(current_p->pci_device_fn == temp_p->pci_device_fn)) ||
- (current_p->base == temp_p->base) )
+ (temp_p->base && (current_p->base == temp_p->base)) ||
+ (temp_p->mbase && (current_p->mbase == temp_p->mbase)) )
{
/* duplicate PCI entry, skip it */
kfree(temp_p);
@@ -9635,69 +9686,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
devconfig |= 0x80000040;
pci_write_config_dword(pdev, DEVCONFIG, devconfig);
#endif /* AIC7XXX_STRICT_PCI_SETUP */
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
- temp_p->pci_bus = pci_bus;
- temp_p->pci_device_fn = pci_devfn;
- pcibios_read_config_byte(pci_bus, pci_devfn, PCI_INTERRUPT_LINE,
- &pci_irq);
- temp_p->irq = pci_irq;
- pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0,
- &piobase);
- temp_p->base = piobase;
- pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_1,
- &mmapbase);
- temp_p->mbase = mmapbase;
- temp_p->base &= PCI_BASE_ADDRESS_IO_MASK;
- temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
- current_p = list_p;
- while(current_p)
- {
- if ( ((current_p->pci_bus == temp_p->pci_bus) &&
- (current_p->pci_device_fn == temp_p->pci_device_fn)) ||
- (current_p->base == temp_p->base) )
- {
- /* duplicate PCI entry, skip it */
- kfree(temp_p);
- temp_p = NULL;
- }
- current_p = current_p->next;
- }
- if ( temp_p == NULL )
- continue;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
- board_names[aic_pdevs[i].board_name_index],
- temp_p->pci_bus,
- PCI_SLOT(temp_p->pci_device_fn),
- PCI_FUNC(temp_p->pci_device_fn));
- pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk("aic7xxx: Initial PCI_COMMAND value was 0x%x\n",
- (int)command);
- }
-#ifdef AIC7XXX_STRICT_PCI_SETUP
- command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
- PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
-#else
- command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
-#endif
- command &= ~PCI_COMMAND_INVALIDATE;
- if (aic7xxx_pci_parity == 0)
- command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
- pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND, command);
-#ifdef AIC7XXX_STRICT_PCI_SETUP
- pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG, &devconfig);
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
- }
- devconfig |= 0x80000040;
- pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG, devconfig);
-#endif /* AIC7XXX_STRICT_PCI_SETUP */
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
- if(check_region(temp_p->base, MAXREG - MINREG))
+ if(temp_p->base && check_region(temp_p->base, MAXREG - MINREG))
{
printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
@@ -9728,7 +9718,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
}
#ifdef MMAPIO
- if ( !(temp_p->flags & AHC_MULTI_CHANNEL) ||
+ if ( !(temp_p->base) || !(temp_p->flags & AHC_MULTI_CHANNEL) ||
((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) &&
(temp_p->chip != (AHC_AIC7880 | AHC_PCI))) )
{
@@ -9736,11 +9726,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
base = temp_p->mbase & PAGE_MASK;
page_offset = temp_p->mbase - base;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
temp_p->maddr = ioremap_nocache(base, page_offset + 256);
-#else
- temp_p->maddr = vremap(base, page_offset + 256);
-#endif
if(temp_p->maddr)
{
temp_p->maddr += page_offset;
@@ -9760,12 +9746,20 @@ aic7xxx_detect(Scsi_Host_Template *template)
PCI_FUNC(temp_p->pci_device_fn));
printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to "
"Programmed I/O.\n");
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
iounmap((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
-#else
- vfree((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
-#endif
temp_p->maddr = 0;
+ if(temp_p->base == 0)
+ {
+ printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
+ board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
+ PCI_SLOT(temp_p->pci_device_fn),
+ PCI_FUNC(temp_p->pci_device_fn));
+ printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
+ kfree(temp_p);
+ temp_p = NULL;
+ continue;
+ }
}
}
}
@@ -9774,7 +9768,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
/*
* Lock out other contenders for our i/o space.
*/
- request_region(temp_p->base, MAXREG - MINREG, "aic7xxx");
+ if(temp_p->base)
+ request_region(temp_p->base, MAXREG - MINREG, "aic7xxx");
/*
* We HAVE to make sure the first pause_sequencer() and all other
@@ -9826,12 +9821,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
* bit of DEVCONFIG
*/
aic_outb(temp_p, sxfrctl1, SXFRCTL1);
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
- pcibios_write_config_dword(temp_p->pci_bus, temp_p->pci_device_fn,
- DEVCONFIG, devconfig);
-#else
pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig);
-#endif
sxfrctl1 &= STPWEN;
/*
@@ -9866,7 +9856,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
case AHC_AIC7895: /* 7895 */
case AHC_AIC7896: /* 7896/7 */
case AHC_AIC7899: /* 7899 */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
if (PCI_FUNC(pdev->devfn) != 0)
{
temp_p->flags |= AHC_CHNLB;
@@ -9882,25 +9871,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
devconfig |= SCBSIZE32;
pci_write_config_dword(pdev, DEVCONFIG, devconfig);
}
-#else
- if (PCI_FUNC(temp_p->pci_device_fn) != 0)
- {
- temp_p->flags |= AHC_CHNLB;
- }
- /*
- * The 7895 is the only chipset that sets the SCBSIZE32 param
- * in the DEVCONFIG register. The Ultra2 chipsets use
- * the DSCOMMAND0 register instead.
- */
- if ((temp_p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
- {
- pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG,
- &devconfig);
- devconfig |= SCBSIZE32;
- pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG,
- devconfig);
- }
-#endif
break;
default:
break;
@@ -9965,12 +9935,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
/*
* Check the rev of the chipset before we change DSCOMMAND0
*/
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
-#else
- pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG,
- &devconfig);
-#endif
if ((devconfig & 0xff) >= 1)
{
aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
@@ -10040,12 +10005,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
case AHC_AIC7895:
case AHC_AIC7896:
case AHC_AIC7899:
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
-#else
- pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG,
- &devconfig);
-#endif
if (temp_p->features & AHC_ULTRA2)
{
if ( (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) &&
@@ -10087,12 +10047,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
"but not enabled\n");
}
}
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_write_config_dword(pdev, DEVCONFIG, devconfig);
-#else
- pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG,
- devconfig);
-#endif
if ( (temp_p->flags & AHC_EXTERNAL_SRAM) &&
(temp_p->flags & AHC_CHNLB) )
aic_outb(temp_p, 1, CCSCBBADDR);
@@ -10687,20 +10642,59 @@ aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
(!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
{
p->transinfo[tindex].goal_period = syncrate->period;
- if( !(syncrate->sxfr_ultra2 & 0x40) )
+ if( p->transinfo[tindex].goal_period > 9 )
{
p->transinfo[tindex].goal_options = 0;
+ p->needppr &= ~(1<<tindex);
+ p->needsdtr |= (1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
+ if (p->transinfo[tindex].goal_width)
+ {
+ p->needwdtr |= (1<<tindex);
+ p->needwdtr_copy |= (1<<tindex);
+ }
+ }
+ }
+ else if (p->transinfo[tindex].goal_width)
+ {
+ p->transinfo[tindex].goal_width = 0;
+ p->needwdtr &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
+ p->transinfo[tindex].goal_offset =
+ p->transinfo[tindex].user_offset;
+ p->transinfo[tindex].goal_period =
+ p->transinfo[tindex].user_period;
+ p->transinfo[tindex].goal_options =
+ p->transinfo[tindex].user_options;
+ if( p->transinfo[tindex].goal_period <= 9 )
+ {
+ p->needppr |= (1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needppr_copy |= (1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ }
+ else
+ {
+ p->needppr &= ~(1<<tindex);
+ p->needsdtr |= (1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
}
}
else
{
p->transinfo[tindex].goal_offset = 0;
- p->transinfo[tindex].goal_period = 0;
+ p->transinfo[tindex].goal_period = 255;
p->transinfo[tindex].goal_options = 0;
+ p->transinfo[tindex].goal_width = 0;
+ p->needppr &= ~(1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needwdtr &= ~(1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
}
- p->needppr |= (p->needppr_copy & (1<<tindex));
- p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
- p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
}
p->needdv &= ~(1<<tindex);
}
@@ -10751,8 +10745,16 @@ aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
* and we didn't follow up with SDTR yet, then this will get it started.
* For all other cases, this should work out to be a no-op, unless we are
* doing domain validation and happen to need a new negotiation command.
+ *
+ * In case we don't want this to go any further, the cmdcmplt interrupt
+ * handler will NULL out the cmd->next entry so that the real SCSI command
+ * can be sent back to the mid layer code with SENSE data intact. We'll
+ * finish things up when the cmd gets sent back down to us, so no worries.
*/
- aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
+ if(cmd->next)
+ {
+ aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
+ }
return;
}
@@ -10874,13 +10876,13 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
*/
hscb->control = 0;
scb->tag_action = 0;
+ cmd->tag = hscb->tag;
if (p->discenable & mask)
{
hscb->control |= DISCENB;
if ( (p->tagenable & mask) &&
(cmd->cmnd[0] != TEST_UNIT_READY) )
{
- cmd->tag = hscb->tag;
p->dev_commands_sent[tindex]++;
if (p->dev_commands_sent[tindex] < 200)
{
@@ -11322,13 +11324,6 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
void
aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
- int i, mask, found, need_tag;
- struct aic7xxx_scb *scb;
- unsigned char qinpos, hscbp;
-
- found = FALSE;
-#endif
printk("aic7xxx driver version %s/%s\n", AIC7XXX_C_VERSION,
UTS_RELEASE);
@@ -11341,121 +11336,7 @@ aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
disable_irq(p->irq);
aic7xxx_print_card(p);
aic7xxx_print_scratch_ram(p);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
- for(i=0; i<MAX_TARGETS; i++)
- {
- if(p->dev_flags[i] & DEVICE_PRESENT)
- {
- mask = (0x01 << i);
- printk(INFO_LEAD "dev_flags=0x%x, Pending:%c, PPR:%c/%c, WDTR:%c/%c, "
- "SDTR:%c/%c, q_depth=%d:%d\n",
- p->host_no, 0, i, 0, p->dev_flags[i],
- (p->dtr_pending & mask) ? 'Y' : 'N',
- (p->needppr & mask) ? 'Y' : 'N',
- (p->needppr_copy & mask) ? 'Y' : 'N',
- (p->needwdtr & mask) ? 'Y' : 'N',
- (p->needwdtr_copy & mask) ? 'Y' : 'N',
- (p->needsdtr & mask) ? 'Y' : 'N',
- (p->needsdtr_copy & mask) ? 'Y' : 'N',
- p->dev_active_cmds[i],
- p->dev_max_queue_depth[i] );
- printk(INFO_LEAD "targ_scsirate=0x%x", p->host_no, 0, i, 0,
- aic_inb(p, TARG_SCSIRATE + i));
- if (p->features & AHC_ULTRA2)
- printk(", targ_offset=%d", aic_inb(p, TARG_OFFSET + i));
- printk("\n");
- }
- }
- /*
- * Search for this command and see if we can't track it down, it's the
- * one causing the timeout. Print out this command first, then all other
- * active commands afterwords.
- */
- need_tag = -1;
- if ( cmd )
- {
- scb = p->scb_data->scb_array[aic7xxx_position(cmd)];
- if ( (scb->flags & SCB_ACTIVE) && (scb->cmd == cmd) )
- {
- printk("Timed out command is scb #%d:\n", scb->hscb->tag);
- printk("Tag%d: flags=0x%x, control=0x%x, TCL=0x%x, %s\n", scb->hscb->tag,
- scb->flags, scb->hscb->control, scb->hscb->target_channel_lun,
- (scb->flags & SCB_WAITINGQ) ? "WAITINGQ" : "Sent" );
- need_tag = scb->hscb->tag;
- if (scb->flags & SCB_WAITINGQ) found=TRUE;
- }
- }
- printk("QINFIFO: (TAG) ");
- qinpos = aic_inb(p, QINPOS);
- while ( qinpos != p->qinfifonext )
- {
- if (p->qinfifo[qinpos] == need_tag)
- found=TRUE;
- printk("%d ", p->qinfifo[qinpos++]);
- }
- printk("\n");
- printk("Current SCB: (SCBPTR/TAG/CONTROL) %d/%d/0x%x\n", aic_inb(p, SCBPTR),
- aic_inb(p, SCB_TAG), aic_inb(p, SCB_CONTROL) );
- if (aic_inb(p, SCB_TAG) == need_tag) found=TRUE;
- printk("WAITING_SCBS: (SCBPTR/TAG/CONTROL) %d->",
- hscbp = aic_inb(p, WAITING_SCBH));
- while (hscbp != SCB_LIST_NULL)
- {
- aic_outb(p, hscbp, SCBPTR);
- printk("%d/%d/0x%x ", hscbp, aic_inb(p, SCB_TAG), aic_inb(p, SCB_CONTROL));
- hscbp = aic_inb(p, SCB_NEXT);
- if (aic_inb(p, SCB_TAG) == need_tag) found=TRUE;
- }
- printk("\n");
- printk("DISCONNECTED_SCBS: (SCBPTR/TAG/CONTROL) %d->",
- hscbp = aic_inb(p, DISCONNECTED_SCBH));
- while (hscbp != SCB_LIST_NULL)
- {
- aic_outb(p, hscbp, SCBPTR);
- printk("%d/%d/0x%x ", hscbp, aic_inb(p, SCB_TAG), aic_inb(p, SCB_CONTROL));
- hscbp = aic_inb(p, SCB_NEXT);
- if (aic_inb(p, SCB_TAG) == need_tag) found=TRUE;
- }
- printk("\n");
- printk("FREE_SCBS: (SCBPTR/TAG/CONTROL) %d->",
- hscbp = aic_inb(p, FREE_SCBH));
- while (hscbp != SCB_LIST_NULL)
- {
- aic_outb(p, hscbp, SCBPTR);
- printk("%d/%d/0x%x ", hscbp, aic_inb(p, SCB_TAG), aic_inb(p, SCB_CONTROL));
- hscbp = aic_inb(p, SCB_NEXT);
- }
- printk("\n");
-
- if (found == FALSE)
- {
- /*
- * We haven't found the offending SCB yet, and it should be around
- * somewhere, so go look for it in the cards SCBs.
- */
- printk("SCBPTR CONTROL TAG NEXT\n");
- for(i=0; i<p->scb_data->maxhscbs; i++)
- {
- aic_outb(p, i, SCBPTR);
- printk(" %3d %02x %02x %02x\n", i,
- aic_inb(p, SCB_CONTROL), aic_inb(p, SCB_TAG),
- aic_inb(p, SCB_NEXT));
- }
- }
-
-
- for (i=0; i < p->scb_data->numscbs; i++)
- {
- scb = p->scb_data->scb_array[i];
- if ( (scb->flags & SCB_ACTIVE) && (scb->cmd != cmd) )
- {
- printk("Tag%d: flags=0x%x, control=0x%x, TCL=0x%x, %s\n", scb->hscb->tag,
- scb->flags, scb->hscb->control, scb->hscb->target_channel_lun,
- (scb->flags & SCB_WAITINGQ) ? "WAITINGQ" : "Sent" );
- }
- }
-#endif
- sti();
+ spin_unlock_irq(&io_request_lock);
for(;;) barrier();
}
@@ -11501,7 +11382,6 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
* we are following a straight code path without entering the scheduler
* code.
*/
-
pause_sequencer(p);
while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
{
@@ -12164,15 +12044,12 @@ aic7xxx_release(struct Scsi_Host *host)
if(p->irq)
free_irq(p->irq, p);
- release_region(p->base, MAXREG - MINREG);
+ if(p->base)
+ release_region(p->base, MAXREG - MINREG);
#ifdef MMAPIO
if(p->maddr)
{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
- vfree((void *) (((unsigned long) p->maddr) & PAGE_MASK));
-#else
iounmap((void *) (((unsigned long) p->maddr) & PAGE_MASK));
-#endif
}
#endif /* MMAPIO */
prev = NULL;
@@ -12243,31 +12120,7 @@ aic7xxx_print_card(struct aic7xxx_host *p)
0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
0xe0, 0xf1, 0xf4, 0xfc} },
};
-#ifdef CONFIG_PCI
- static struct register_ranges cards_ns[] = {
- { 0, {0,} }, /* none */
- { 0, {0,} }, /* 7771 */
- { 7, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x28, 0x2b, 0x30, 0x33,
- 0x3c, 0x41, 0x43, 0x47} },
- { 7, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x28, 0x2b, 0x30, 0x33,
- 0x3c, 0x41, 0x43, 0x47} },
- { 5, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x30, 0x33, 0x3c, 0x41} },
- { 5, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x30, 0x34, 0x3c, 0x47} },
- { 5, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3} },
- { 6, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x30, 0x34, 0x3c, 0x47,
- 0xdc, 0xe3} },
- { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
- 0xff, 0xff} },
- { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
- 0xff, 0xff} },
- { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
- 0xff, 0xff} }
- };
-#endif
chip = p->chip & AHC_CHIPID_MASK;
- /*
- * Let's run through the PCI space first....
- */
printk("%s at ",
board_names[p->board_name_index]);
switch(p->chip & ~AHC_CHIPID_MASK)
@@ -12285,38 +12138,8 @@ aic7xxx_print_card(struct aic7xxx_host *p)
break;
}
-#ifdef CONFIG_PCI
- {
- unsigned char temp;
-
- printk("PCI Dump:\n");
- k=0;
- for(i=0; i<cards_ns[chip].num_ranges; i++)
- {
- for(j = cards_ns[chip].range_val[ i * 2 ];
- j <= cards_ns[chip].range_val[ i * 2 + 1 ] ;
- j++)
- {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
- pci_read_config_byte(p->pdev, j, &temp);
-#else
- pcibios_read_config_byte(p->pci_bus, p->pci_device_fn, j, &temp);
-#endif
- printk("%02x:%02x ", j, temp);
- if(++k == 13)
- {
- printk("\n");
- k = 0;
- }
- }
- }
- }
- if(k != 0)
- printk("\n");
-#endif /* CONFIG_PCI */
-
/*
- * Now the registers on the card....
+ * the registers on the card....
*/
printk("Card Dump:\n");
k = 0;
@@ -12336,21 +12159,6 @@ aic7xxx_print_card(struct aic7xxx_host *p)
}
if(k != 0)
printk("\n");
- if (p->flags & AHC_SEEPROM_FOUND)
- {
- unsigned short *sc1;
- sc1 = (unsigned short *)&p->sc;
-
- printk("SEEPROM dump.\n");
- for(i=1; i<=32; i++)
- {
- printk("0x%04x", sc1[i-1]);
- if ( (i % 8) == 0 )
- printk("\n");
- else
- printk(" ");
- }
- }
/*
* If this was an Ultra2 controller, then we just hosed the card in terms
diff --git a/drivers/scsi/aic7xxx.h b/drivers/scsi/aic7xxx.h
index ffcedd96d..de438cac7 100644
--- a/drivers/scsi/aic7xxx.h
+++ b/drivers/scsi/aic7xxx.h
@@ -23,21 +23,7 @@
#ifndef _aic7xxx_h
#define _aic7xxx_h
-#define AIC7XXX_H_VERSION "3.2.4"
-
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-#ifndef KERNEL_VERSION
-#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
-#endif
-
-#if defined(__i386__)
-# define AIC7XXX_BIOSPARAM aic7xxx_biosparam
-#else
-# define AIC7XXX_BIOSPARAM NULL
-#endif
+#define AIC7XXX_H_VERSION "5.2.0"
/*
* Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
@@ -61,7 +47,7 @@
abort: aic7xxx_abort, \
reset: aic7xxx_reset, \
slave_attach: NULL, \
- bios_param: AIC7XXX_BIOSPARAM, \
+ bios_param: aic7xxx_biosparam, \
can_queue: 255, /* max simultaneous cmds */\
this_id: -1, /* scsi id of host adapter */\
sg_tablesize: 0, /* max scatter-gather cmds */\
diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq
index de3afbf92..15c887167 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.seq
+++ b/drivers/scsi/aic7xxx/aic7xxx.seq
@@ -60,11 +60,7 @@ reset:
clr SCSISIGO; /* De-assert BSY */
and SXFRCTL1, ~BITBUCKET;
/* Always allow reselection */
- if ((p->flags & AHC_TARGETMODE) != 0) {
- mvi SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
- } else {
- mvi SCSISEQ, ENRSELI|ENAUTOATNP;
- }
+ mvi SCSISEQ, ENRSELI|ENAUTOATNP;
if ((p->features & AHC_CMD_CHAN) != 0) {
/* Ensure that no DMA operations are in progress */
@@ -182,6 +178,15 @@ initialize_scsiid:
and SCSIID, OID; /* Clear old target */
or SCSIID, A;
}
+ mov SCSIDATL, ALLZEROS; /* clear out the latched */
+ /* data register, this */
+ /* fixes a bug on some */
+ /* controllers where the */
+ /* last byte written to */
+ /* this register can leak */
+ /* onto the data bus at */
+ /* bad times, such as during */
+ /* selection timeouts */
mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
/*
@@ -227,118 +232,6 @@ ndx_dtr_2:
selection:
test SSTAT0,SELDO jnz select_out;
-select_in:
- if ((p->flags & AHC_TARGETMODE) != 0) {
- test SSTAT0, TARGET jz initiator_reselect;
- /*
- * We've just been selected. Assert BSY and
- * setup the phase for receiving the messages
- * from the target.
- */
- mvi SCSISIGO, P_MESGOUT|BSYO;
- mvi CLRSINT0, CLRSELDO;
-
- /*
- * If ATN isn't asserted, go directly to bus free.
- */
- test SCSISIGI, ATNI jz target_busfree;
-
- /*
- * Setup the DMA for sending the identify and
- * command information.
- */
- mov A, TMODE_CMDADDR_NEXT;
- mvi DINDEX, HADDR;
- mvi TMODE_CMDADDR call set_32byte_addr;
- mvi DFCNTRL, FIFORESET;
-
- clr SINDEX;
- /* Watch ATN closely now */
-message_loop:
- or SXFRCTL0, SPIOEN;
- test SSTAT0, SPIORDY jz .;
- and SXFRCTL0, ~SPIOEN;
- mov DINDEX, SCSIDATL;
- mov DFDAT, DINDEX;
- inc SINDEX;
-
- /* Message Testing... */
- test DINDEX, MSG_IDENTIFYFLAG jz . + 2;
- mov ARG_1, DINDEX;
-
- test SCSISIGI, ATNI jnz message_loop;
- add A, -4, SINDEX;
- jc target_cmdphase;
- mvi DFDAT, SCB_LIST_NULL; /* Terminate the message list */
-
-target_cmdphase:
- add HCNT[0], 1, A;
- clr HCNT[1];
- clr HCNT[2];
- mvi SCSISIGO, P_COMMAND|BSYO;
- or SXFRCTL0, SPIOEN;
- test SSTAT0, SPIORDY jz .;
- mov A, SCSIDATL;
- mov DFDAT, A; /* Store for host */
-
- /*
- * Determine the number of bytes to read
- * based on the command group code. Count is
- * one less than the total since we've already
- * fetched the first byte.
- */
- clr SINDEX;
- shr A, CMD_GROUP_CODE_SHIFT;
- add SEQADDR0, A;
-
- add SINDEX, CMD_GROUP0_BYTE_DELTA;
- nop; /* Group 1 and 2 are the same */
- add SINDEX, CMD_GROUP2_BYTE_DELTA;
- nop; /* Group 3 is reserved */
- add SINDEX, CMD_GROUP4_BYTE_DELTA;
- add SINDEX, CMD_GROUP5_BYTE_DELTA;
- /* Group 6 and 7 are not handled yet */
-
- mov A, SINDEX;
- add HCNT[0], A;
-
-command_loop:
- test SSTAT0, SPIORDY jz .;
- cmp SINDEX, 1 jne . + 2;
- and SXFRCTL0, ~SPIOEN; /* Last Byte */
- mov DFDAT, SCSIDATL;
- dec SINDEX;
- test SINDEX, 0xFF jnz command_loop;
-
- or DFCNTRL, HDMAEN|FIFOFLUSH;
-
- call dma_finish;
-
- test ARG_1, MSG_IDENTIFY_DISCFLAG jz selectin_post;
-
- mvi SCSISIGO, P_MESGIN|BSYO;
-
- or SXFRCTL0, SPIOEN;
-
- mvi MSG_DISCONNECT call target_outb;
-
-selectin_post:
- inc TMODE_CMDADDR_NEXT;
- cmp TMODE_CMDADDR_NEXT, TMODE_NUMCMDS jne . + 2;
- clr TMODE_CMDADDR_NEXT;
- mvi QOUTFIFO, SCB_LIST_NULL;
- mvi INTSTAT,CMDCMPLT;
-
- test ARG_1, MSG_IDENTIFY_DISCFLAG jnz target_busfree;
-
- /* Busy loop on something then go to data or status phase */
-
-target_busfree:
- clr SCSISIGO;
- jmp poll_for_work;
-
- }
-
/*
* Reselection has been initiated by a target. Make a note that we've been
* reselected, but haven't seen an IDENTIFY message from the target yet.
@@ -444,13 +337,14 @@ clear_target_state:
* STCNT may have been cleared, so restore it from the residual field.
*/
data_phase_reinit:
- if ((p->features & AHC_CMD_CHAN) != 0) {
- if ((p->features & AHC_ULTRA2) != 0) {
- bmov HADDR, SHADDR, 4;
- bmov HCNT, SCB_RESID_DCNT, 3;
- }
+ if ((p->features & AHC_ULTRA2) != 0) {
+ bmov HADDR, SHADDR, 4;
+ bmov HCNT, SCB_RESID_DCNT, 3;
+ }
+ if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
bmov STCNT, SCB_RESID_DCNT, 3;
- } else {
+ }
+ if ((p->features & AHC_CMD_CHAN) == 0) {
mvi DINDEX, STCNT;
mvi SCB_RESID_DCNT call bcopy_3;
}
@@ -677,10 +571,13 @@ ultra2_dmafifoflush:
test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
test DFSTATUS, MREQPEND jnz .;
ultra2_dmahalt:
- and DFCNTRL, ~HDMAEN;
- test DFCNTRL, HDMAEN jnz .;
- and DFCNTRL, ~SCSIEN;
- test DFCNTRL, SCSIEN jnz .;
+ test SCSIOFFSET, 0x7f jnz ultra2_shutdown;
+ultra2_await_nreq:
+ test SCSISIGI, REQI jz ultra2_shutdown;
+ test SSTAT1, (PHASEMIS|REQINIT) jz ultra2_await_nreq;
+ultra2_shutdown:
+ and DFCNTRL, ~(HDMAEN|SCSIEN);
+ test DFCNTRL, (HDMAEN|SCSIEN) jnz .;
bmov SCB_RESID_DCNT, STCNT, 3;
mov SCB_RESID_SGCNT, SG_COUNT;
or SXFRCTL0, CLRSTCNT|CLRCHN;
@@ -719,10 +616,11 @@ p_command_dma_loop:
test SSTAT0, SDONE jnz p_command_ultra2_dma_done;
test SSTAT1,PHASEMIS jz p_command_dma_loop; /* ie. underrun */
p_command_ultra2_dma_done:
- and DFCNTRL, ~HDMAEN;
- test DFCNTRL, HDMAEN jnz .;
- and DFCNTRL, ~SCSIEN;
- test DFCNTRL, SCSIEN jnz .;
+ test SCSISIGI, REQI jz p_command_ultra2_shutdown;
+ test SSTAT1, (PHASEMIS|REQINIT) jz p_command_ultra2_dma_done;
+p_command_ultra2_shutdown:
+ and DFCNTRL, ~(HDMAEN|SCSIEN);
+ test DFCNTRL, (HDMAEN|SCSIEN) jnz .;
or SXFRCTL0, CLRSTCNT|CLRCHN;
}
jmp ITloop;
@@ -1069,25 +967,12 @@ mesgin_wide_residue:
mvi ARG_1 call inb_next; /* ACK the wide_residue and get */
/* the size byte */
/*
- * See if we'll ignore this wide residue (because it's an overrun byte)
- */
- if ((p->features & AHC_ULTRA2) != 0) {
- test SSTAT2, WIDE_RES jnz mesgin_done;
- } else {
- test SCB_RESID_SGCNT,0xff jnz wide_residue_int;
- test SCB_RESID_DCNT[0],0xff jnz wide_residue_int;
- test SCB_RESID_DCNT[1],0xff jnz wide_residue_int;
- test SCB_RESID_DCNT[2],0xff jnz wide_residue_int;
- jmp mesgin_done;
- }
-wide_residue_int:
-/*
* In order for this to be reliable, we have to do all sorts of horrible
* magic in terms of resetting the datafifo and reloading the shadow layer
* with the correct new values (so that a subsequent save data pointers
* message will do the right thing). We let the kernel do that work.
*/
- mvi INTSTAT,WIDE_RESIDUE;
+ mvi INTSTAT, WIDE_RESIDUE;
jmp mesgin_done;
/*
@@ -1136,17 +1021,6 @@ inb_first:
inb_last:
mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/
-if ((p->flags & AHC_TARGETMODE) != 0) {
- /*
- * Send a byte to an initiator in Automatic PIO mode.
- * SPIOEN must be on prior to calling this routine.
- */
-target_outb:
- mov SCSIDATL, SINDEX;
- test SSTAT0, SPIORDY jz .;
- ret;
-}
-
mesgin_phasemis:
/*
* We expected to receive another byte, but the target changed phase
@@ -1191,6 +1065,12 @@ dma_fifoempty:
* actually off first lest we get an ILLSADDR.
*/
dma_dmadone:
+ cmp LASTPHASE, P_COMMAND je dma_await_nreq;
+ test SCSIRATE, 0x0f jnz dma_shutdown;
+dma_await_nreq:
+ test SCSISIGI, REQI jz dma_shutdown;
+ test SSTAT1, (PHASEMIS|REQINIT) jz dma_await_nreq;
+dma_shutdown:
and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
dma_halt:
/*
diff --git a/drivers/scsi/aic7xxx_proc.c b/drivers/scsi/aic7xxx_proc.c
index ec80af90d..7320eb6b6 100644
--- a/drivers/scsi/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx_proc.c
@@ -172,7 +172,6 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
#else
size += sprintf(BLS, " AIC7XXX_PROC_STATS : Disabled\n");
#endif
- size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY);
size += sprintf(BLS, "\n");
size += sprintf(BLS, "Adapter Configuration:\n");
size += sprintf(BLS, " SCSI Adapter: %s\n",
diff --git a/drivers/scsi/aic7xxx_seq.c b/drivers/scsi/aic7xxx_seq.c
index 511bfcb73..047a34de0 100644
--- a/drivers/scsi/aic7xxx_seq.c
+++ b/drivers/scsi/aic7xxx_seq.c
@@ -4,34 +4,33 @@
static unsigned char seqprog[] = {
0xff, 0x6a, 0x06, 0x08,
0x7f, 0x02, 0x04, 0x08,
- 0x32, 0x6a, 0x00, 0x00,
0x12, 0x6a, 0x00, 0x00,
0xff, 0x6a, 0xd6, 0x09,
0xff, 0x6a, 0xdc, 0x09,
- 0x00, 0x65, 0x42, 0x59,
+ 0x00, 0x65, 0xca, 0x58,
0xf7, 0x01, 0x02, 0x08,
0xff, 0x4e, 0xc8, 0x08,
0xbf, 0x60, 0xc0, 0x08,
0x60, 0x0b, 0x86, 0x68,
- 0x40, 0x00, 0x0e, 0x68,
+ 0x40, 0x00, 0x0c, 0x68,
0x08, 0x1f, 0x3e, 0x10,
0x60, 0x0b, 0x86, 0x68,
- 0x40, 0x00, 0x0e, 0x68,
+ 0x40, 0x00, 0x0c, 0x68,
0x08, 0x1f, 0x3e, 0x10,
- 0xff, 0x3e, 0x4a, 0x60,
- 0x40, 0xfa, 0x12, 0x78,
+ 0xff, 0x3e, 0x48, 0x60,
+ 0x40, 0xfa, 0x10, 0x78,
0xff, 0xf6, 0xd4, 0x08,
0x01, 0x4e, 0x9c, 0x18,
0x40, 0x60, 0xc0, 0x00,
- 0x00, 0x4d, 0x12, 0x70,
+ 0x00, 0x4d, 0x10, 0x70,
0x01, 0x4e, 0x9c, 0x18,
0xbf, 0x60, 0xc0, 0x08,
- 0x00, 0x6a, 0xbe, 0x5c,
+ 0x00, 0x6a, 0x3e, 0x5c,
0xff, 0x4e, 0xc8, 0x18,
- 0x02, 0x6a, 0xd4, 0x5b,
+ 0x02, 0x6a, 0x54, 0x5b,
0xff, 0x52, 0x20, 0x09,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0x52, 0x4a, 0x5c,
+ 0x00, 0x52, 0xca, 0x5b,
0x03, 0xb0, 0x52, 0x31,
0xff, 0xb0, 0x52, 0x09,
0xff, 0xb1, 0x54, 0x09,
@@ -40,8 +39,8 @@ static unsigned char seqprog[] = {
0xff, 0x3e, 0x74, 0x09,
0xff, 0x90, 0x7c, 0x08,
0xff, 0x3e, 0x20, 0x09,
- 0x00, 0x65, 0x50, 0x58,
- 0x00, 0x65, 0x0e, 0x40,
+ 0x00, 0x65, 0x4e, 0x58,
+ 0x00, 0x65, 0x0c, 0x40,
0xf7, 0x1f, 0xca, 0x08,
0x08, 0xa1, 0xc8, 0x08,
0x00, 0x65, 0xca, 0x00,
@@ -52,6 +51,7 @@ static unsigned char seqprog[] = {
0xf0, 0xa1, 0xc8, 0x08,
0x0f, 0x05, 0x0a, 0x08,
0x00, 0x05, 0x0a, 0x00,
+ 0xff, 0x6a, 0x0c, 0x08,
0x5a, 0x6a, 0x00, 0x04,
0x12, 0x65, 0x02, 0x00,
0x31, 0x6a, 0xca, 0x00,
@@ -69,74 +69,14 @@ static unsigned char seqprog[] = {
0xff, 0x6c, 0x0a, 0x08,
0x20, 0x64, 0xca, 0x18,
0xff, 0x6c, 0x08, 0x0c,
- 0x40, 0x0b, 0x0e, 0x69,
- 0x80, 0x0b, 0x00, 0x79,
- 0xa4, 0x6a, 0x06, 0x00,
- 0x40, 0x6a, 0x16, 0x00,
- 0x10, 0x03, 0xfc, 0x78,
- 0xff, 0x50, 0xc8, 0x08,
- 0x88, 0x6a, 0xcc, 0x00,
- 0x49, 0x6a, 0x3a, 0x5c,
- 0x01, 0x6a, 0x26, 0x01,
- 0xff, 0x6a, 0xca, 0x08,
- 0x08, 0x01, 0x02, 0x00,
- 0x02, 0x0b, 0x9c, 0x78,
- 0xf7, 0x01, 0x02, 0x08,
- 0xff, 0x06, 0xcc, 0x08,
- 0xff, 0x66, 0x32, 0x09,
- 0x01, 0x65, 0xca, 0x18,
- 0x80, 0x66, 0xaa, 0x78,
- 0xff, 0x66, 0xa2, 0x08,
- 0x10, 0x03, 0x9a, 0x68,
- 0xfc, 0x65, 0xc8, 0x18,
- 0x00, 0x65, 0xb2, 0x48,
- 0xff, 0x6a, 0x32, 0x01,
- 0x01, 0x64, 0x18, 0x19,
- 0xff, 0x6a, 0x1a, 0x09,
- 0xff, 0x6a, 0x1c, 0x09,
- 0x84, 0x6a, 0x06, 0x00,
- 0x08, 0x01, 0x02, 0x00,
- 0x02, 0x0b, 0xbc, 0x78,
- 0xff, 0x06, 0xc8, 0x08,
- 0xff, 0x64, 0x32, 0x09,
- 0xff, 0x6a, 0xca, 0x08,
- 0x5b, 0x64, 0xc8, 0x28,
- 0x00, 0x62, 0xc4, 0x18,
- 0xfc, 0x65, 0xca, 0x18,
- 0xff, 0x6a, 0xd4, 0x08,
- 0xfa, 0x65, 0xca, 0x18,
- 0xff, 0x6a, 0xd4, 0x08,
- 0x04, 0x65, 0xca, 0x18,
- 0x0b, 0x65, 0xca, 0x18,
- 0xff, 0x65, 0xc8, 0x08,
- 0x00, 0x8c, 0x18, 0x19,
- 0x02, 0x0b, 0xd8, 0x78,
- 0x01, 0x65, 0xde, 0x60,
- 0xf7, 0x01, 0x02, 0x08,
- 0xff, 0x06, 0x32, 0x09,
- 0xff, 0x65, 0xca, 0x18,
- 0xff, 0x65, 0xd8, 0x68,
- 0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0xb0, 0x5c,
- 0x40, 0x51, 0xf0, 0x78,
- 0xe4, 0x6a, 0x06, 0x00,
- 0x08, 0x01, 0x02, 0x00,
- 0x04, 0x6a, 0x6c, 0x5b,
- 0x01, 0x50, 0xa0, 0x18,
- 0x00, 0x50, 0xf6, 0xe0,
- 0xff, 0x6a, 0xa0, 0x08,
- 0xff, 0x6a, 0x3a, 0x01,
- 0x02, 0x6a, 0x22, 0x01,
- 0x40, 0x51, 0xfc, 0x68,
- 0xff, 0x6a, 0x06, 0x08,
- 0x00, 0x65, 0x0e, 0x40,
+ 0x40, 0x0b, 0x96, 0x68,
0x20, 0x6a, 0x16, 0x00,
0xf0, 0x19, 0x6e, 0x08,
0x08, 0x6a, 0x18, 0x00,
0x08, 0x11, 0x22, 0x00,
0x08, 0x6a, 0x66, 0x58,
0x08, 0x6a, 0x68, 0x00,
- 0x00, 0x65, 0x22, 0x41,
+ 0x00, 0x65, 0xaa, 0x40,
0x12, 0x6a, 0x00, 0x00,
0x40, 0x6a, 0x16, 0x00,
0xff, 0x3e, 0x20, 0x09,
@@ -147,21 +87,21 @@ static unsigned char seqprog[] = {
0x08, 0x6a, 0x66, 0x58,
0x80, 0x6a, 0x68, 0x00,
0x80, 0x36, 0x6c, 0x00,
- 0x00, 0x65, 0x1e, 0x5c,
+ 0x00, 0x65, 0x9e, 0x5b,
0xff, 0x3d, 0xc8, 0x08,
- 0xbf, 0x64, 0x5a, 0x79,
- 0x80, 0x64, 0x22, 0x72,
- 0xa0, 0x64, 0x52, 0x72,
- 0xc0, 0x64, 0x4a, 0x72,
- 0xe0, 0x64, 0x92, 0x72,
+ 0xbf, 0x64, 0xe2, 0x78,
+ 0x80, 0x64, 0xac, 0x71,
+ 0xa0, 0x64, 0xdc, 0x71,
+ 0xc0, 0x64, 0xd4, 0x71,
+ 0xe0, 0x64, 0x1c, 0x72,
0x01, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0x22, 0x41,
+ 0x00, 0x65, 0xaa, 0x40,
0xf7, 0x11, 0x22, 0x08,
- 0x00, 0x65, 0x42, 0x59,
+ 0x00, 0x65, 0xca, 0x58,
0xff, 0x06, 0xd4, 0x08,
0xf7, 0x01, 0x02, 0x08,
- 0x09, 0x0c, 0x3c, 0x79,
- 0x08, 0x0c, 0x0e, 0x68,
+ 0x09, 0x0c, 0xc4, 0x78,
+ 0x08, 0x0c, 0x0c, 0x68,
0x01, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0x26, 0x09,
0x02, 0x6a, 0x08, 0x30,
@@ -173,25 +113,25 @@ static unsigned char seqprog[] = {
0x03, 0xa9, 0x18, 0x31,
0x03, 0xa9, 0x10, 0x30,
0x08, 0x6a, 0xcc, 0x00,
- 0xa9, 0x6a, 0x34, 0x5c,
- 0x00, 0x65, 0x7a, 0x41,
+ 0xa9, 0x6a, 0xb4, 0x5b,
+ 0x00, 0x65, 0x02, 0x41,
0xa8, 0x6a, 0x6a, 0x00,
0x79, 0x6a, 0x6a, 0x00,
- 0x40, 0x3d, 0x62, 0x69,
+ 0x40, 0x3d, 0xea, 0x68,
0x04, 0x35, 0x6a, 0x00,
- 0x00, 0x65, 0x8e, 0x5b,
+ 0x00, 0x65, 0x0e, 0x5b,
0x80, 0x6a, 0xd4, 0x01,
- 0x10, 0x36, 0x4e, 0x69,
+ 0x10, 0x36, 0xd6, 0x68,
0x10, 0x36, 0x6c, 0x00,
0x07, 0xac, 0x10, 0x31,
0x03, 0x8c, 0x10, 0x30,
0x05, 0xa3, 0x70, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0xac, 0x6a, 0x2c, 0x5c,
- 0x00, 0x65, 0x26, 0x5c,
+ 0xac, 0x6a, 0xac, 0x5b,
+ 0x00, 0x65, 0xa6, 0x5b,
0x38, 0x6a, 0xcc, 0x00,
- 0xa3, 0x6a, 0x30, 0x5c,
- 0xff, 0x38, 0x8a, 0x69,
+ 0xa3, 0x6a, 0xb0, 0x5b,
+ 0xff, 0x38, 0x12, 0x69,
0x80, 0x02, 0x04, 0x00,
0xe7, 0x35, 0x6a, 0x08,
0x03, 0x69, 0x18, 0x31,
@@ -199,338 +139,334 @@ static unsigned char seqprog[] = {
0xff, 0x6a, 0x10, 0x00,
0xff, 0x6a, 0x12, 0x00,
0xff, 0x6a, 0x14, 0x00,
- 0x01, 0x38, 0x90, 0x61,
+ 0x01, 0x38, 0x18, 0x61,
0xbf, 0x35, 0x6a, 0x08,
0x02, 0x6a, 0xf8, 0x01,
0xff, 0x69, 0xca, 0x08,
0xff, 0x35, 0x26, 0x09,
- 0x04, 0x0b, 0x94, 0x69,
- 0x04, 0x0b, 0xa0, 0x69,
- 0x10, 0x0c, 0x96, 0x79,
- 0x04, 0x0b, 0xa0, 0x69,
+ 0x04, 0x0b, 0x1c, 0x69,
+ 0x04, 0x0b, 0x28, 0x69,
+ 0x10, 0x0c, 0x1e, 0x79,
+ 0x04, 0x0b, 0x28, 0x69,
0xff, 0x6a, 0xca, 0x08,
- 0x00, 0x35, 0x76, 0x5b,
- 0x80, 0x02, 0xf4, 0x69,
- 0xff, 0x65, 0xe4, 0x79,
+ 0x00, 0x35, 0xee, 0x5a,
+ 0x80, 0x02, 0x7c, 0x69,
+ 0xff, 0x65, 0x6c, 0x79,
0xff, 0x38, 0x70, 0x18,
- 0xff, 0x38, 0xe4, 0x79,
- 0x80, 0xea, 0xc0, 0x61,
+ 0xff, 0x38, 0x6c, 0x79,
+ 0x80, 0xea, 0x48, 0x61,
0xef, 0x38, 0xc8, 0x18,
0x80, 0x6a, 0xc8, 0x00,
- 0x00, 0x65, 0xb2, 0x49,
+ 0x00, 0x65, 0x3a, 0x49,
0x33, 0x38, 0xc8, 0x28,
0xff, 0x64, 0xd0, 0x09,
0x04, 0x39, 0xc0, 0x31,
0x09, 0x6a, 0xd6, 0x01,
- 0x80, 0xeb, 0xb8, 0x79,
+ 0x80, 0xeb, 0x40, 0x79,
0xf7, 0xeb, 0xd6, 0x09,
- 0x08, 0xeb, 0xbc, 0x69,
+ 0x08, 0xeb, 0x44, 0x69,
0x01, 0x6a, 0xd6, 0x01,
0x08, 0xe9, 0x10, 0x31,
0x03, 0x8c, 0x10, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0x39, 0x6a, 0x32, 0x5c,
+ 0x39, 0x6a, 0xb2, 0x5b,
0x08, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x0d, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0xb0, 0x5c,
- 0x88, 0x6a, 0xa0, 0x5c,
- 0x00, 0x65, 0x26, 0x5c,
+ 0x00, 0x65, 0x30, 0x5c,
+ 0x88, 0x6a, 0x20, 0x5c,
+ 0x00, 0x65, 0xa6, 0x5b,
0xff, 0x6a, 0xc8, 0x08,
0x08, 0x39, 0x72, 0x18,
0x00, 0x3a, 0x74, 0x20,
- 0x01, 0x0c, 0xdc, 0x79,
- 0x10, 0x0c, 0x7a, 0x79,
+ 0x01, 0x0c, 0x64, 0x79,
+ 0x10, 0x0c, 0x02, 0x79,
0xff, 0x35, 0x26, 0x09,
- 0x04, 0x0b, 0xe2, 0x69,
- 0x00, 0x65, 0xfc, 0x59,
+ 0x04, 0x0b, 0x6a, 0x69,
+ 0x00, 0x65, 0x84, 0x59,
0x03, 0x08, 0x52, 0x31,
0xff, 0x38, 0x50, 0x09,
0xff, 0x08, 0x52, 0x09,
0xff, 0x09, 0x54, 0x09,
0xff, 0x0a, 0x56, 0x09,
0xff, 0x38, 0x50, 0x09,
- 0x00, 0x65, 0x22, 0x41,
- 0x00, 0x65, 0xfc, 0x59,
+ 0x00, 0x65, 0xaa, 0x40,
+ 0x00, 0x65, 0x84, 0x59,
0x7f, 0x02, 0x04, 0x08,
0xe1, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0x22, 0x41,
- 0x04, 0x93, 0x12, 0x6a,
+ 0x00, 0x65, 0xaa, 0x40,
+ 0x04, 0x93, 0x9a, 0x69,
0xdf, 0x93, 0x26, 0x09,
- 0x20, 0x93, 0x00, 0x6a,
+ 0x20, 0x93, 0x88, 0x69,
0x02, 0x93, 0x26, 0x01,
- 0x01, 0x94, 0x02, 0x7a,
- 0x01, 0x94, 0x02, 0x7a,
- 0x01, 0x94, 0x02, 0x7a,
- 0x01, 0x94, 0x02, 0x7a,
- 0x01, 0x94, 0x02, 0x7a,
- 0x01, 0x94, 0x02, 0x7a,
- 0x10, 0x94, 0x10, 0x6a,
- 0xf7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0x14, 0x6a,
- 0xdf, 0x93, 0x26, 0x09,
- 0x20, 0x93, 0x18, 0x6a,
+ 0x01, 0x94, 0x8a, 0x79,
+ 0x01, 0x94, 0x8a, 0x79,
+ 0x01, 0x94, 0x8a, 0x79,
+ 0x01, 0x94, 0x8a, 0x79,
+ 0x01, 0x94, 0x8a, 0x79,
+ 0x01, 0x94, 0x8a, 0x79,
+ 0x10, 0x94, 0x98, 0x69,
+ 0x7f, 0x05, 0xa0, 0x69,
+ 0x02, 0x03, 0xa0, 0x79,
+ 0x11, 0x0c, 0x9c, 0x79,
+ 0xd7, 0x93, 0x26, 0x09,
+ 0x28, 0x93, 0xa2, 0x69,
0x03, 0x08, 0x52, 0x31,
0xff, 0x38, 0x50, 0x09,
0x12, 0x01, 0x02, 0x00,
0xff, 0x6a, 0xd4, 0x0c,
- 0x00, 0x65, 0x8e, 0x5b,
+ 0x00, 0x65, 0x0e, 0x5b,
0x05, 0xb4, 0x10, 0x31,
0x02, 0x6a, 0x1a, 0x31,
0x03, 0x8c, 0x10, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0xb4, 0x6a, 0x30, 0x5c,
+ 0xb4, 0x6a, 0xb0, 0x5b,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
- 0x00, 0x65, 0x26, 0x5c,
- 0x3d, 0x6a, 0x76, 0x5b,
+ 0x00, 0x65, 0xa6, 0x5b,
+ 0x3d, 0x6a, 0xee, 0x5a,
0xac, 0x6a, 0x26, 0x01,
- 0x04, 0x0b, 0x38, 0x6a,
- 0x04, 0x0b, 0x3e, 0x6a,
- 0x10, 0x0c, 0x3a, 0x7a,
- 0xf7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0x40, 0x6a,
- 0xdf, 0x93, 0x26, 0x09,
- 0x20, 0x93, 0x44, 0x6a,
+ 0x04, 0x0b, 0xc2, 0x69,
+ 0x04, 0x0b, 0xc8, 0x69,
+ 0x10, 0x0c, 0xc4, 0x79,
+ 0x02, 0x03, 0xcc, 0x79,
+ 0x11, 0x0c, 0xc8, 0x79,
+ 0xd7, 0x93, 0x26, 0x09,
+ 0x28, 0x93, 0xce, 0x69,
0x12, 0x01, 0x02, 0x00,
- 0x00, 0x65, 0x22, 0x41,
- 0x00, 0x65, 0x8e, 0x5b,
+ 0x00, 0x65, 0xaa, 0x40,
+ 0x00, 0x65, 0x0e, 0x5b,
0xff, 0x06, 0x44, 0x09,
- 0x00, 0x65, 0x22, 0x41,
+ 0x00, 0x65, 0xaa, 0x40,
0x10, 0x3d, 0x06, 0x00,
0xff, 0x34, 0xca, 0x08,
- 0x80, 0x65, 0x76, 0x62,
+ 0x80, 0x65, 0x00, 0x62,
0x0f, 0xa1, 0xca, 0x08,
0x07, 0xa1, 0xca, 0x08,
0x40, 0xa0, 0xc8, 0x08,
0x00, 0x65, 0xca, 0x00,
0x80, 0x65, 0xca, 0x00,
- 0x80, 0xa0, 0x66, 0x7a,
+ 0x80, 0xa0, 0xf0, 0x79,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0x78, 0x42,
- 0x20, 0xa0, 0x7e, 0x7a,
+ 0x00, 0x65, 0x02, 0x42,
+ 0x20, 0xa0, 0x08, 0x7a,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0x1e, 0x5c,
- 0xa0, 0x3d, 0x86, 0x62,
+ 0x00, 0x65, 0x9e, 0x5b,
+ 0xa0, 0x3d, 0x10, 0x62,
0x23, 0xa0, 0x0c, 0x08,
- 0x00, 0x65, 0x1e, 0x5c,
- 0xa0, 0x3d, 0x86, 0x62,
- 0x00, 0xb9, 0x7e, 0x42,
- 0xff, 0x65, 0x7e, 0x62,
+ 0x00, 0x65, 0x9e, 0x5b,
+ 0xa0, 0x3d, 0x10, 0x62,
+ 0x00, 0xb9, 0x08, 0x42,
+ 0xff, 0x65, 0x08, 0x62,
0xa1, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
- 0x10, 0x51, 0x86, 0x72,
+ 0x10, 0x51, 0x10, 0x72,
0x40, 0x6a, 0x18, 0x00,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0x1e, 0x5c,
- 0xa0, 0x3d, 0x50, 0x72,
+ 0x00, 0x65, 0x9e, 0x5b,
+ 0xa0, 0x3d, 0xda, 0x71,
0x40, 0x6a, 0x18, 0x00,
0xff, 0x34, 0xa6, 0x08,
- 0x80, 0x34, 0x8e, 0x62,
+ 0x80, 0x34, 0x18, 0x62,
0x7f, 0xa0, 0x40, 0x09,
0x08, 0x6a, 0x68, 0x00,
- 0x00, 0x65, 0x22, 0x41,
- 0x64, 0x6a, 0x66, 0x5b,
- 0x80, 0x64, 0x04, 0x6b,
- 0x04, 0x64, 0xe6, 0x72,
- 0x02, 0x64, 0xec, 0x72,
- 0x00, 0x6a, 0xae, 0x72,
- 0x03, 0x64, 0x00, 0x73,
- 0x01, 0x64, 0xe2, 0x72,
- 0x07, 0x64, 0x42, 0x73,
- 0x08, 0x64, 0xaa, 0x72,
- 0x23, 0x64, 0x46, 0x73,
+ 0x00, 0x65, 0xaa, 0x40,
+ 0x64, 0x6a, 0xe4, 0x5a,
+ 0x80, 0x64, 0x8e, 0x6a,
+ 0x04, 0x64, 0x70, 0x72,
+ 0x02, 0x64, 0x76, 0x72,
+ 0x00, 0x6a, 0x38, 0x72,
+ 0x03, 0x64, 0x8a, 0x72,
+ 0x01, 0x64, 0x6c, 0x72,
+ 0x07, 0x64, 0xcc, 0x72,
+ 0x08, 0x64, 0x34, 0x72,
+ 0x23, 0x64, 0xd0, 0x72,
0x11, 0x6a, 0x22, 0x01,
- 0x07, 0x6a, 0x58, 0x5b,
+ 0x07, 0x6a, 0xd6, 0x5a,
0xff, 0x06, 0xd4, 0x08,
- 0x00, 0x65, 0x22, 0x41,
- 0xff, 0xa8, 0xb2, 0x6a,
- 0xff, 0xa2, 0xca, 0x7a,
+ 0x00, 0x65, 0xaa, 0x40,
+ 0xff, 0xa8, 0x3c, 0x6a,
+ 0xff, 0xa2, 0x54, 0x7a,
0x01, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0x4a, 0x5c,
- 0xff, 0xa2, 0xca, 0x7a,
+ 0x00, 0xb9, 0xca, 0x5b,
+ 0xff, 0xa2, 0x54, 0x7a,
0x71, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
- 0x40, 0x51, 0xca, 0x62,
+ 0x40, 0x51, 0x54, 0x62,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0x4a, 0x5c,
+ 0x00, 0xb9, 0xca, 0x5b,
0xff, 0x3e, 0x74, 0x09,
0xff, 0x90, 0x7c, 0x08,
- 0x00, 0x65, 0x50, 0x58,
- 0x00, 0x65, 0x34, 0x41,
- 0x20, 0xa0, 0xd2, 0x6a,
+ 0x00, 0x65, 0x4e, 0x58,
+ 0x00, 0x65, 0xbc, 0x40,
+ 0x20, 0xa0, 0x5c, 0x6a,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0x6a, 0xf4, 0x5b,
- 0xff, 0x6a, 0x0a, 0x5c,
+ 0x00, 0x6a, 0x74, 0x5b,
+ 0xff, 0x6a, 0x8a, 0x5b,
0xff, 0xf8, 0xc8, 0x08,
0xff, 0x4f, 0xc8, 0x08,
- 0x01, 0x6a, 0xf4, 0x5b,
- 0x00, 0xb9, 0x0a, 0x5c,
+ 0x01, 0x6a, 0x74, 0x5b,
+ 0x00, 0xb9, 0x8a, 0x5b,
0x01, 0x4f, 0x9e, 0x18,
0x02, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0xb8, 0x5c,
- 0x00, 0x65, 0x34, 0x41,
+ 0x00, 0x65, 0x38, 0x5c,
+ 0x00, 0x65, 0xbc, 0x40,
0x41, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0x22, 0x41,
+ 0x00, 0x65, 0xaa, 0x40,
0x04, 0xa0, 0x40, 0x01,
- 0x00, 0x65, 0xd0, 0x5c,
- 0x00, 0x65, 0x34, 0x41,
- 0x10, 0x36, 0xaa, 0x7a,
+ 0x00, 0x65, 0x50, 0x5c,
+ 0x00, 0x65, 0xbc, 0x40,
+ 0x10, 0x36, 0x34, 0x7a,
0x05, 0x38, 0x46, 0x31,
0x04, 0x14, 0x58, 0x31,
0x03, 0xa9, 0x60, 0x31,
0xa3, 0x6a, 0xcc, 0x00,
- 0x38, 0x6a, 0x30, 0x5c,
+ 0x38, 0x6a, 0xb0, 0x5b,
0xac, 0x6a, 0xcc, 0x00,
- 0x14, 0x6a, 0x32, 0x5c,
- 0xa9, 0x6a, 0x34, 0x5c,
- 0x00, 0x65, 0xaa, 0x42,
+ 0x14, 0x6a, 0xb2, 0x5b,
+ 0xa9, 0x6a, 0xb4, 0x5b,
+ 0x00, 0x65, 0x34, 0x42,
0xef, 0x36, 0x6c, 0x08,
- 0x00, 0x65, 0xaa, 0x42,
+ 0x00, 0x65, 0x34, 0x42,
0x0f, 0x64, 0xc8, 0x08,
0x07, 0x64, 0xc8, 0x08,
0x00, 0x37, 0x6e, 0x00,
0xff, 0x6a, 0xa4, 0x00,
- 0x00, 0x65, 0xc4, 0x5b,
- 0xff, 0x51, 0x16, 0x73,
- 0x20, 0x36, 0x20, 0x7b,
- 0x00, 0x90, 0xb2, 0x5b,
- 0x00, 0x65, 0x22, 0x43,
+ 0x00, 0x65, 0x44, 0x5b,
+ 0xff, 0x51, 0xa0, 0x72,
+ 0x20, 0x36, 0xaa, 0x7a,
+ 0x00, 0x90, 0x32, 0x5b,
+ 0x00, 0x65, 0xac, 0x42,
0xff, 0x06, 0xd4, 0x08,
- 0x00, 0x65, 0x1e, 0x5c,
- 0xe0, 0x3d, 0x3c, 0x63,
- 0x20, 0x12, 0x3c, 0x63,
- 0x51, 0x6a, 0x5c, 0x5b,
- 0x00, 0x65, 0xac, 0x5b,
+ 0x00, 0x65, 0x9e, 0x5b,
+ 0xe0, 0x3d, 0xc6, 0x62,
+ 0x20, 0x12, 0xc6, 0x62,
+ 0x51, 0x6a, 0xda, 0x5a,
+ 0x00, 0x65, 0x2c, 0x5b,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0xa1, 0x34, 0x63,
- 0x04, 0xa0, 0x34, 0x7b,
+ 0x00, 0xa1, 0xbe, 0x62,
+ 0x04, 0xa0, 0xbe, 0x7a,
0xfb, 0xa0, 0x40, 0x09,
0x80, 0x36, 0x6c, 0x00,
- 0x80, 0xa0, 0xaa, 0x7a,
+ 0x80, 0xa0, 0x34, 0x7a,
0x7f, 0xa0, 0x40, 0x09,
- 0xff, 0x6a, 0x58, 0x5b,
- 0x00, 0x65, 0xaa, 0x42,
- 0x04, 0xa0, 0x3a, 0x7b,
- 0x00, 0x65, 0xd0, 0x5c,
- 0x00, 0x65, 0x3c, 0x43,
- 0x00, 0x65, 0xb8, 0x5c,
+ 0xff, 0x6a, 0xd6, 0x5a,
+ 0x00, 0x65, 0x34, 0x42,
+ 0x04, 0xa0, 0xc4, 0x7a,
+ 0x00, 0x65, 0x50, 0x5c,
+ 0x00, 0x65, 0xc6, 0x42,
+ 0x00, 0x65, 0x38, 0x5c,
0x31, 0x6a, 0x22, 0x01,
- 0x0c, 0x6a, 0x58, 0x5b,
- 0x00, 0x65, 0xaa, 0x42,
+ 0x0c, 0x6a, 0xd6, 0x5a,
+ 0x00, 0x65, 0x34, 0x42,
0x61, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0xaa, 0x42,
- 0x51, 0x6a, 0x5c, 0x5b,
- 0x20, 0x0d, 0xaa, 0x6a,
- 0xff, 0xa8, 0x54, 0x6b,
- 0xff, 0xa9, 0x54, 0x6b,
- 0xff, 0xaa, 0x54, 0x6b,
- 0xff, 0xab, 0x54, 0x6b,
- 0x00, 0x65, 0xaa, 0x42,
+ 0x00, 0x65, 0x34, 0x42,
+ 0x51, 0x6a, 0xda, 0x5a,
0x51, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0xaa, 0x42,
+ 0x00, 0x65, 0x34, 0x42,
0x10, 0x3d, 0x06, 0x00,
0xff, 0x65, 0x68, 0x0c,
0xff, 0x06, 0xd4, 0x08,
- 0x01, 0x0c, 0x5e, 0x7b,
- 0x04, 0x0c, 0x60, 0x6b,
+ 0x01, 0x0c, 0xdc, 0x7a,
+ 0x04, 0x0c, 0xde, 0x6a,
0xe0, 0x03, 0x7a, 0x08,
- 0xe0, 0x3d, 0x72, 0x63,
+ 0xe0, 0x3d, 0xea, 0x62,
0xff, 0x65, 0xcc, 0x08,
0xff, 0x12, 0xda, 0x0c,
0xff, 0x06, 0xd4, 0x0c,
- 0xff, 0x65, 0x0c, 0x08,
- 0x02, 0x0b, 0x6e, 0x7b,
- 0xff, 0x6a, 0xd4, 0x0c,
0xd1, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0x22, 0x41,
+ 0x00, 0x65, 0xaa, 0x40,
0xff, 0x65, 0x26, 0x09,
- 0x01, 0x0b, 0x86, 0x6b,
- 0x10, 0x0c, 0x78, 0x7b,
- 0x04, 0x0b, 0x80, 0x6b,
+ 0x01, 0x0b, 0xfe, 0x6a,
+ 0x10, 0x0c, 0xf0, 0x7a,
+ 0x04, 0x0b, 0xf8, 0x6a,
0xff, 0x6a, 0xca, 0x08,
- 0x04, 0x93, 0x84, 0x6b,
- 0x01, 0x94, 0x82, 0x7b,
- 0x10, 0x94, 0x84, 0x6b,
+ 0x04, 0x93, 0xfc, 0x6a,
+ 0x01, 0x94, 0xfa, 0x7a,
+ 0x10, 0x94, 0xfc, 0x6a,
+ 0x80, 0x3d, 0x02, 0x73,
+ 0x0f, 0x04, 0x06, 0x6b,
+ 0x02, 0x03, 0x06, 0x7b,
+ 0x11, 0x0c, 0x02, 0x7b,
0xc7, 0x93, 0x26, 0x09,
0xff, 0x99, 0xd4, 0x08,
- 0x38, 0x93, 0x88, 0x6b,
+ 0x38, 0x93, 0x08, 0x6b,
0xff, 0x6a, 0xd4, 0x0c,
- 0x80, 0x36, 0x8c, 0x6b,
+ 0x80, 0x36, 0x0c, 0x6b,
0x21, 0x6a, 0x22, 0x05,
0xff, 0x65, 0x20, 0x09,
- 0xff, 0x51, 0x9a, 0x63,
+ 0xff, 0x51, 0x1a, 0x63,
0xff, 0x37, 0xc8, 0x08,
- 0xa1, 0x6a, 0xa6, 0x43,
+ 0xa1, 0x6a, 0x26, 0x43,
0xff, 0x51, 0xc8, 0x08,
- 0xb9, 0x6a, 0xa6, 0x43,
+ 0xb9, 0x6a, 0x26, 0x43,
0xff, 0x90, 0xa4, 0x08,
- 0xff, 0xba, 0xaa, 0x73,
+ 0xff, 0xba, 0x2a, 0x73,
0xff, 0xba, 0x20, 0x09,
0xff, 0x65, 0xca, 0x18,
- 0x00, 0x6c, 0x9e, 0x63,
+ 0x00, 0x6c, 0x1e, 0x63,
0xff, 0x90, 0xca, 0x0c,
0xff, 0x6a, 0xca, 0x04,
- 0x20, 0x36, 0xbe, 0x7b,
- 0x00, 0x90, 0x92, 0x5b,
- 0xff, 0x65, 0xbe, 0x73,
- 0xff, 0x52, 0xbc, 0x73,
+ 0x20, 0x36, 0x3e, 0x7b,
+ 0x00, 0x90, 0x12, 0x5b,
+ 0xff, 0x65, 0x3e, 0x73,
+ 0xff, 0x52, 0x3c, 0x73,
0xff, 0xba, 0xcc, 0x08,
0xff, 0x52, 0x20, 0x09,
0xff, 0x66, 0x74, 0x09,
0xff, 0x65, 0x20, 0x0d,
0xff, 0xba, 0x7e, 0x0c,
- 0x00, 0x6a, 0xbe, 0x5c,
+ 0x00, 0x6a, 0x3e, 0x5c,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0x51, 0x4a, 0x44,
- 0xff, 0x3f, 0x18, 0x74,
+ 0x00, 0x51, 0xca, 0x43,
+ 0xff, 0x3f, 0x98, 0x73,
0xff, 0x6a, 0xa2, 0x00,
- 0x00, 0x3f, 0x92, 0x5b,
- 0xff, 0x65, 0x18, 0x74,
+ 0x00, 0x3f, 0x12, 0x5b,
+ 0xff, 0x65, 0x98, 0x73,
0x20, 0x36, 0x6c, 0x00,
- 0x20, 0xa0, 0xd2, 0x6b,
+ 0x20, 0xa0, 0x52, 0x6b,
0xff, 0xb9, 0xa2, 0x0c,
0xff, 0x6a, 0xa2, 0x04,
0xff, 0x65, 0xa4, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0x3e, 0x5c,
+ 0x45, 0x6a, 0xbe, 0x5b,
0x01, 0x6a, 0xd0, 0x01,
0x09, 0x6a, 0xd6, 0x01,
- 0x80, 0xeb, 0xde, 0x7b,
+ 0x80, 0xeb, 0x5e, 0x7b,
0x01, 0x6a, 0xd6, 0x01,
0x01, 0xe9, 0xa4, 0x34,
0x88, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0x3e, 0x5c,
+ 0x45, 0x6a, 0xbe, 0x5b,
0x01, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x0d, 0x6a, 0x26, 0x01,
- 0x00, 0x65, 0xb0, 0x5c,
+ 0x00, 0x65, 0x30, 0x5c,
0xff, 0x99, 0xa4, 0x0c,
0xff, 0x65, 0xa4, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0x3e, 0x5c,
+ 0x45, 0x6a, 0xbe, 0x5b,
0x01, 0x6a, 0xd0, 0x01,
0x01, 0x6a, 0xdc, 0x05,
0x88, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0x3e, 0x5c,
+ 0x45, 0x6a, 0xbe, 0x5b,
0x01, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x01, 0x6a, 0x26, 0x05,
0x01, 0x65, 0xd8, 0x31,
0x09, 0xee, 0xdc, 0x01,
- 0x80, 0xee, 0x0e, 0x7c,
+ 0x80, 0xee, 0x8e, 0x7b,
0xff, 0x6a, 0xdc, 0x0d,
0xff, 0x65, 0x32, 0x09,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0xb0, 0x44,
+ 0x00, 0x65, 0x30, 0x44,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0x6a, 0xd4, 0x5b,
+ 0x00, 0x6a, 0x54, 0x5b,
0xff, 0x52, 0xa2, 0x0c,
- 0x01, 0x0c, 0x1e, 0x7c,
- 0x04, 0x0c, 0x1e, 0x6c,
+ 0x01, 0x0c, 0x9e, 0x7b,
+ 0x04, 0x0c, 0x9e, 0x6b,
0xe0, 0x03, 0x06, 0x08,
0xe0, 0x03, 0x7a, 0x0c,
0xff, 0x8c, 0x10, 0x08,
@@ -553,29 +489,29 @@ static unsigned char seqprog[] = {
0x00, 0x6c, 0xda, 0x24,
0xff, 0x65, 0xc8, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x41, 0x6a, 0x3a, 0x5c,
+ 0x41, 0x6a, 0xba, 0x5b,
0xff, 0x90, 0xe2, 0x09,
0x20, 0x6a, 0xd0, 0x01,
- 0x04, 0x35, 0x5c, 0x7c,
+ 0x04, 0x35, 0xdc, 0x7b,
0x1d, 0x6a, 0xdc, 0x01,
- 0xdc, 0xee, 0x58, 0x64,
- 0x00, 0x65, 0x68, 0x44,
+ 0xdc, 0xee, 0xd8, 0x63,
+ 0x00, 0x65, 0xe8, 0x43,
0x01, 0x6a, 0xdc, 0x01,
0x20, 0xa0, 0xd8, 0x31,
0x09, 0xee, 0xdc, 0x01,
- 0x80, 0xee, 0x62, 0x7c,
+ 0x80, 0xee, 0xe2, 0x7b,
0x19, 0x6a, 0xdc, 0x01,
- 0xd8, 0xee, 0x66, 0x64,
+ 0xd8, 0xee, 0xe6, 0x63,
0xff, 0x6a, 0xdc, 0x09,
- 0x18, 0xee, 0x6a, 0x6c,
+ 0x18, 0xee, 0xea, 0x6b,
0xff, 0x6a, 0xd4, 0x0c,
0x88, 0x6a, 0xcc, 0x00,
- 0x41, 0x6a, 0x3a, 0x5c,
+ 0x41, 0x6a, 0xba, 0x5b,
0x20, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0xff, 0x35, 0x26, 0x09,
- 0x04, 0x35, 0x94, 0x6c,
+ 0x04, 0x35, 0x14, 0x6c,
0xa0, 0x6a, 0xca, 0x00,
0x20, 0x65, 0xc8, 0x18,
0xff, 0x6c, 0x32, 0x09,
@@ -586,14 +522,14 @@ static unsigned char seqprog[] = {
0xff, 0x6c, 0x32, 0x09,
0xff, 0x6c, 0x32, 0x09,
0xff, 0x6c, 0x32, 0x09,
- 0x00, 0x65, 0x80, 0x64,
+ 0x00, 0x65, 0x00, 0x64,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0xb0, 0x5c,
- 0x04, 0x35, 0x8c, 0x7b,
- 0xa0, 0x6a, 0xa0, 0x5c,
- 0x00, 0x65, 0xa2, 0x5c,
- 0x00, 0x65, 0xa2, 0x5c,
- 0x00, 0x65, 0xa2, 0x44,
+ 0x00, 0x65, 0x30, 0x5c,
+ 0x04, 0x35, 0x0c, 0x7b,
+ 0xa0, 0x6a, 0x20, 0x5c,
+ 0x00, 0x65, 0x22, 0x5c,
+ 0x00, 0x65, 0x22, 0x5c,
+ 0x00, 0x65, 0x22, 0x44,
0xff, 0x65, 0xcc, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
@@ -602,19 +538,19 @@ static unsigned char seqprog[] = {
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x0c,
- 0x08, 0x94, 0xb0, 0x7c,
+ 0x08, 0x94, 0x30, 0x7c,
0xf7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0xb4, 0x6c,
+ 0x08, 0x93, 0x34, 0x6c,
0xff, 0x6a, 0xd4, 0x0c,
0xff, 0x40, 0x74, 0x09,
0xff, 0x90, 0x80, 0x08,
0xff, 0x6a, 0x72, 0x05,
- 0xff, 0x40, 0xcc, 0x64,
- 0xff, 0x3f, 0xc4, 0x64,
+ 0xff, 0x40, 0x4c, 0x64,
+ 0xff, 0x3f, 0x44, 0x64,
0xff, 0x6a, 0xca, 0x04,
0xff, 0x3f, 0x20, 0x09,
0x01, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0x4a, 0x5c,
+ 0x00, 0xb9, 0xca, 0x5b,
0xff, 0xba, 0x7e, 0x0c,
0xff, 0x40, 0x20, 0x09,
0xff, 0xba, 0x80, 0x0c,
@@ -622,20 +558,12 @@ static unsigned char seqprog[] = {
0xff, 0x90, 0x7e, 0x0c,
};
-static int aic7xxx_patch13_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch13_func(struct aic7xxx_host *p)
-{
- return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
-}
-
static int aic7xxx_patch12_func(struct aic7xxx_host *p);
static int
aic7xxx_patch12_func(struct aic7xxx_host *p)
{
- return ((p->features & AHC_CMD_CHAN) == 0);
+ return ((p->features & AHC_WIDE) != 0);
}
static int aic7xxx_patch11_func(struct aic7xxx_host *p);
@@ -643,7 +571,7 @@ static int aic7xxx_patch11_func(struct aic7xxx_host *p);
static int
aic7xxx_patch11_func(struct aic7xxx_host *p)
{
- return ((p->features & AHC_WIDE) != 0);
+ return ((p->features & AHC_ULTRA2) == 0);
}
static int aic7xxx_patch10_func(struct aic7xxx_host *p);
@@ -651,7 +579,7 @@ static int aic7xxx_patch10_func(struct aic7xxx_host *p);
static int
aic7xxx_patch10_func(struct aic7xxx_host *p)
{
- return ((p->features & AHC_ULTRA2) == 0);
+ return ((p->features & AHC_CMD_CHAN) == 0);
}
static int aic7xxx_patch9_func(struct aic7xxx_host *p);
@@ -659,7 +587,7 @@ static int aic7xxx_patch9_func(struct aic7xxx_host *p);
static int
aic7xxx_patch9_func(struct aic7xxx_host *p)
{
- return ((p->features & AHC_ULTRA) != 0);
+ return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
}
static int aic7xxx_patch8_func(struct aic7xxx_host *p);
@@ -667,7 +595,7 @@ static int aic7xxx_patch8_func(struct aic7xxx_host *p);
static int
aic7xxx_patch8_func(struct aic7xxx_host *p)
{
- return ((p->features & AHC_ULTRA2) != 0);
+ return ((p->features & AHC_ULTRA) != 0);
}
static int aic7xxx_patch7_func(struct aic7xxx_host *p);
@@ -675,7 +603,7 @@ static int aic7xxx_patch7_func(struct aic7xxx_host *p);
static int
aic7xxx_patch7_func(struct aic7xxx_host *p)
{
- return ((p->flags & AHC_PAGESCBS) == 0);
+ return ((p->features & AHC_ULTRA2) != 0);
}
static int aic7xxx_patch6_func(struct aic7xxx_host *p);
@@ -683,7 +611,7 @@ static int aic7xxx_patch6_func(struct aic7xxx_host *p);
static int
aic7xxx_patch6_func(struct aic7xxx_host *p)
{
- return ((p->flags & AHC_PAGESCBS) != 0);
+ return ((p->flags & AHC_PAGESCBS) == 0);
}
static int aic7xxx_patch5_func(struct aic7xxx_host *p);
@@ -691,7 +619,7 @@ static int aic7xxx_patch5_func(struct aic7xxx_host *p);
static int
aic7xxx_patch5_func(struct aic7xxx_host *p)
{
- return ((p->features & AHC_QUEUE_REGS) != 0);
+ return ((p->flags & AHC_PAGESCBS) != 0);
}
static int aic7xxx_patch4_func(struct aic7xxx_host *p);
@@ -699,7 +627,7 @@ static int aic7xxx_patch4_func(struct aic7xxx_host *p);
static int
aic7xxx_patch4_func(struct aic7xxx_host *p)
{
- return ((p->features & AHC_TWIN) != 0);
+ return ((p->features & AHC_QUEUE_REGS) != 0);
}
static int aic7xxx_patch3_func(struct aic7xxx_host *p);
@@ -707,7 +635,7 @@ static int aic7xxx_patch3_func(struct aic7xxx_host *p);
static int
aic7xxx_patch3_func(struct aic7xxx_host *p)
{
- return ((p->features & AHC_QUEUE_REGS) == 0);
+ return ((p->features & AHC_TWIN) != 0);
}
static int aic7xxx_patch2_func(struct aic7xxx_host *p);
@@ -715,7 +643,7 @@ static int aic7xxx_patch2_func(struct aic7xxx_host *p);
static int
aic7xxx_patch2_func(struct aic7xxx_host *p)
{
- return ((p->features & AHC_CMD_CHAN) != 0);
+ return ((p->features & AHC_QUEUE_REGS) == 0);
}
static int aic7xxx_patch1_func(struct aic7xxx_host *p);
@@ -723,7 +651,7 @@ static int aic7xxx_patch1_func(struct aic7xxx_host *p);
static int
aic7xxx_patch1_func(struct aic7xxx_host *p)
{
- return ((p->flags & AHC_TARGETMODE) != 0);
+ return ((p->features & AHC_CMD_CHAN) != 0);
}
static int aic7xxx_patch0_func(struct aic7xxx_host *p);
@@ -740,84 +668,78 @@ struct sequencer_patch {
skip_instr :10,
skip_patch :12;
} sequencer_patches[] = {
- { aic7xxx_patch1_func, 2, 1, 2 },
- { aic7xxx_patch0_func, 3, 1, 1 },
- { aic7xxx_patch2_func, 4, 2, 1 },
- { aic7xxx_patch3_func, 8, 1, 1 },
- { aic7xxx_patch3_func, 9, 1, 1 },
- { aic7xxx_patch4_func, 12, 4, 1 },
- { aic7xxx_patch5_func, 17, 3, 2 },
- { aic7xxx_patch0_func, 20, 4, 1 },
- { aic7xxx_patch6_func, 24, 1, 1 },
- { aic7xxx_patch7_func, 27, 1, 1 },
- { aic7xxx_patch2_func, 30, 1, 2 },
- { aic7xxx_patch0_func, 31, 3, 1 },
- { aic7xxx_patch4_func, 40, 4, 1 },
- { aic7xxx_patch8_func, 44, 3, 2 },
- { aic7xxx_patch0_func, 47, 3, 1 },
- { aic7xxx_patch9_func, 52, 7, 1 },
- { aic7xxx_patch4_func, 60, 3, 1 },
- { aic7xxx_patch8_func, 63, 2, 1 },
- { aic7xxx_patch1_func, 68, 60, 1 },
- { aic7xxx_patch8_func, 162, 1, 2 },
- { aic7xxx_patch0_func, 163, 2, 1 },
- { aic7xxx_patch2_func, 167, 3, 3 },
- { aic7xxx_patch8_func, 167, 2, 1 },
- { aic7xxx_patch0_func, 170, 2, 1 },
- { aic7xxx_patch8_func, 173, 1, 2 },
- { aic7xxx_patch0_func, 174, 1, 1 },
- { aic7xxx_patch2_func, 178, 1, 1 },
- { aic7xxx_patch2_func, 181, 3, 2 },
- { aic7xxx_patch0_func, 184, 5, 1 },
- { aic7xxx_patch2_func, 192, 2, 3 },
- { aic7xxx_patch8_func, 192, 1, 1 },
- { aic7xxx_patch0_func, 194, 3, 1 },
- { aic7xxx_patch10_func, 198, 1, 2 },
- { aic7xxx_patch0_func, 199, 1, 1 },
- { aic7xxx_patch8_func, 200, 7, 2 },
- { aic7xxx_patch0_func, 207, 1, 1 },
- { aic7xxx_patch2_func, 212, 14, 3 },
- { aic7xxx_patch10_func, 225, 1, 1 },
- { aic7xxx_patch0_func, 226, 9, 1 },
- { aic7xxx_patch8_func, 240, 2, 1 },
- { aic7xxx_patch8_func, 242, 1, 1 },
- { aic7xxx_patch10_func, 243, 6, 3 },
- { aic7xxx_patch2_func, 243, 2, 2 },
- { aic7xxx_patch0_func, 245, 4, 1 },
- { aic7xxx_patch8_func, 250, 1, 1 },
- { aic7xxx_patch8_func, 254, 19, 1 },
- { aic7xxx_patch2_func, 274, 3, 3 },
- { aic7xxx_patch10_func, 276, 1, 1 },
- { aic7xxx_patch0_func, 277, 5, 1 },
- { aic7xxx_patch10_func, 282, 1, 2 },
- { aic7xxx_patch0_func, 283, 9, 1 },
- { aic7xxx_patch11_func, 299, 1, 2 },
- { aic7xxx_patch0_func, 300, 1, 1 },
- { aic7xxx_patch5_func, 361, 1, 2 },
- { aic7xxx_patch0_func, 362, 1, 1 },
- { aic7xxx_patch3_func, 365, 1, 1 },
- { aic7xxx_patch2_func, 375, 3, 2 },
- { aic7xxx_patch0_func, 378, 5, 1 },
- { aic7xxx_patch11_func, 386, 1, 2 },
- { aic7xxx_patch0_func, 387, 1, 1 },
- { aic7xxx_patch6_func, 392, 1, 1 },
- { aic7xxx_patch8_func, 420, 1, 2 },
- { aic7xxx_patch0_func, 421, 5, 1 },
- { aic7xxx_patch1_func, 438, 3, 1 },
- { aic7xxx_patch10_func, 443, 11, 1 },
- { aic7xxx_patch2_func, 491, 7, 2 },
- { aic7xxx_patch0_func, 498, 8, 1 },
- { aic7xxx_patch2_func, 507, 4, 2 },
- { aic7xxx_patch0_func, 511, 6, 1 },
- { aic7xxx_patch2_func, 517, 4, 2 },
- { aic7xxx_patch0_func, 521, 3, 1 },
- { aic7xxx_patch12_func, 531, 10, 1 },
- { aic7xxx_patch2_func, 550, 17, 4 },
- { aic7xxx_patch13_func, 558, 4, 2 },
- { aic7xxx_patch0_func, 562, 2, 1 },
- { aic7xxx_patch0_func, 567, 33, 1 },
- { aic7xxx_patch12_func, 600, 4, 1 },
- { aic7xxx_patch6_func, 604, 2, 1 },
- { aic7xxx_patch6_func, 607, 9, 1 },
+ { aic7xxx_patch1_func, 3, 2, 1 },
+ { aic7xxx_patch2_func, 7, 1, 1 },
+ { aic7xxx_patch2_func, 8, 1, 1 },
+ { aic7xxx_patch3_func, 11, 4, 1 },
+ { aic7xxx_patch4_func, 16, 3, 2 },
+ { aic7xxx_patch0_func, 19, 4, 1 },
+ { aic7xxx_patch5_func, 23, 1, 1 },
+ { aic7xxx_patch6_func, 26, 1, 1 },
+ { aic7xxx_patch1_func, 29, 1, 2 },
+ { aic7xxx_patch0_func, 30, 3, 1 },
+ { aic7xxx_patch3_func, 39, 4, 1 },
+ { aic7xxx_patch7_func, 43, 3, 2 },
+ { aic7xxx_patch0_func, 46, 3, 1 },
+ { aic7xxx_patch8_func, 52, 7, 1 },
+ { aic7xxx_patch3_func, 60, 3, 1 },
+ { aic7xxx_patch7_func, 63, 2, 1 },
+ { aic7xxx_patch7_func, 102, 1, 2 },
+ { aic7xxx_patch0_func, 103, 2, 1 },
+ { aic7xxx_patch7_func, 107, 2, 1 },
+ { aic7xxx_patch9_func, 109, 1, 1 },
+ { aic7xxx_patch10_func, 110, 2, 1 },
+ { aic7xxx_patch7_func, 113, 1, 2 },
+ { aic7xxx_patch0_func, 114, 1, 1 },
+ { aic7xxx_patch1_func, 118, 1, 1 },
+ { aic7xxx_patch1_func, 121, 3, 2 },
+ { aic7xxx_patch0_func, 124, 5, 1 },
+ { aic7xxx_patch1_func, 132, 2, 3 },
+ { aic7xxx_patch7_func, 132, 1, 1 },
+ { aic7xxx_patch0_func, 134, 3, 1 },
+ { aic7xxx_patch11_func, 138, 1, 2 },
+ { aic7xxx_patch0_func, 139, 1, 1 },
+ { aic7xxx_patch7_func, 140, 7, 2 },
+ { aic7xxx_patch0_func, 147, 1, 1 },
+ { aic7xxx_patch1_func, 152, 14, 3 },
+ { aic7xxx_patch11_func, 165, 1, 1 },
+ { aic7xxx_patch0_func, 166, 9, 1 },
+ { aic7xxx_patch7_func, 180, 2, 1 },
+ { aic7xxx_patch7_func, 182, 1, 1 },
+ { aic7xxx_patch11_func, 183, 6, 3 },
+ { aic7xxx_patch1_func, 183, 2, 2 },
+ { aic7xxx_patch0_func, 185, 4, 1 },
+ { aic7xxx_patch7_func, 190, 1, 1 },
+ { aic7xxx_patch7_func, 194, 20, 1 },
+ { aic7xxx_patch1_func, 215, 3, 3 },
+ { aic7xxx_patch11_func, 217, 1, 1 },
+ { aic7xxx_patch0_func, 218, 5, 1 },
+ { aic7xxx_patch11_func, 223, 1, 2 },
+ { aic7xxx_patch0_func, 224, 9, 1 },
+ { aic7xxx_patch12_func, 240, 1, 2 },
+ { aic7xxx_patch0_func, 241, 1, 1 },
+ { aic7xxx_patch4_func, 302, 1, 2 },
+ { aic7xxx_patch0_func, 303, 1, 1 },
+ { aic7xxx_patch2_func, 306, 1, 1 },
+ { aic7xxx_patch1_func, 316, 3, 2 },
+ { aic7xxx_patch0_func, 319, 5, 1 },
+ { aic7xxx_patch12_func, 327, 1, 2 },
+ { aic7xxx_patch0_func, 328, 1, 1 },
+ { aic7xxx_patch5_func, 333, 1, 1 },
+ { aic7xxx_patch11_func, 375, 15, 1 },
+ { aic7xxx_patch1_func, 427, 7, 2 },
+ { aic7xxx_patch0_func, 434, 8, 1 },
+ { aic7xxx_patch1_func, 443, 4, 2 },
+ { aic7xxx_patch0_func, 447, 6, 1 },
+ { aic7xxx_patch1_func, 453, 4, 2 },
+ { aic7xxx_patch0_func, 457, 3, 1 },
+ { aic7xxx_patch10_func, 467, 10, 1 },
+ { aic7xxx_patch1_func, 486, 17, 4 },
+ { aic7xxx_patch9_func, 494, 4, 2 },
+ { aic7xxx_patch0_func, 498, 2, 1 },
+ { aic7xxx_patch0_func, 503, 33, 1 },
+ { aic7xxx_patch10_func, 536, 4, 1 },
+ { aic7xxx_patch5_func, 540, 2, 1 },
+ { aic7xxx_patch5_func, 543, 9, 1 },
};
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 6ae59e9dd..b7d3b9cc1 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -176,6 +176,8 @@ extern void scsi_old_times_out(Scsi_Cmnd * SCpnt);
*/
void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt) {
blk_init_queue(&SDpnt->request_queue, scsi_request_fn);
+ blk_queue_headactive(&SDpnt->request_queue, 0);
+ SDpnt->request_queue.queuedata = (void *) SDpnt;
}
#ifdef MODULE
@@ -2567,7 +2569,6 @@ static void scsi_dump_status(int level)
}
}
}
- printk("wait_for_request = %p\n", &wait_for_request);
#endif /* CONFIG_SCSI_LOGGING */ /* } */
}
#endif /* CONFIG_PROC_FS */
@@ -2728,8 +2729,6 @@ Scsi_Device * scsi_get_host_dev(struct Scsi_Host * SHpnt)
scsi_build_commandblocks(SDpnt);
scsi_initialize_queue(SDpnt, SHpnt);
- blk_queue_headactive(&SDpnt->request_queue, 0);
- SDpnt->request_queue.queuedata = (void *) SDpnt;
SDpnt->online = TRUE;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index d4a1fd5fb..042493e3e 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -855,10 +855,9 @@ void scsi_request_fn(request_queue_t * q)
* if the device itself is blocked, or if the host is fully
* occupied.
*/
- if (SHpnt->in_recovery
- || q->plugged) {
+ if (SHpnt->in_recovery || q->plugged)
return;
- }
+
/*
* To start with, we keep looping until the queue is empty, or until
* the host is no longer able to accept any more requests.
@@ -869,10 +868,8 @@ void scsi_request_fn(request_queue_t * q)
* released the lock and grabbed it again, so each time
* we need to check to see if the queue is plugged or not.
*/
- if (SHpnt->in_recovery
- || q->plugged) {
+ if (SHpnt->in_recovery || q->plugged)
return;
- }
/*
* If the device cannot accept another request, then quit.
@@ -1019,8 +1016,7 @@ void scsi_request_fn(request_queue_t * q)
* We have copied the data out of the request block - it is now in
* a field in SCpnt. Release the request block.
*/
- req->rq_status = RQ_INACTIVE;
- wake_up(&wait_for_request);
+ blkdev_release_request(req);
}
/*
* Now it is finally safe to release the lock. We are
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 56ef67cb2..152f8afc3 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -271,8 +271,8 @@ void scan_scsis(struct Scsi_Host *shpnt,
if (SDpnt) {
memset(SDpnt, 0, sizeof(Scsi_Device));
/*
- * Register the queue for the device. All I/O requests will come
- * in through here. We also need to register a pointer to
+ * Register the queue for the device. All I/O requests will
+ * come in through here. We also need to register a pointer to
* ourselves, since the queue handler won't know what device
* the queue actually represents. We could look it up, but it
* is pointless work.
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 71b93e379..4bfdc59f4 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1230,9 +1230,9 @@ static int sg_attach(Scsi_Device * scsidp)
sdp->detached = 0;
sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k);
- sdp->de = devfs_register (scsidp->de, "generic", 7, DEVFS_FL_NONE,
+ sdp->de = devfs_register (scsidp->de, "generic", DEVFS_FL_DEFAULT,
SCSI_GENERIC_MAJOR, k,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
&sg_fops, NULL);
sg_template.nr_dev++;
sg_dev_arr[k] = sdp;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index e568c6d1b..cd3f7a488 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -777,9 +777,9 @@ void sr_finish()
sprintf(name, "sr%d", i);
strcpy(scsi_CDs[i].cdi.name, name);
scsi_CDs[i].cdi.de =
- devfs_register (scsi_CDs[i].device->de, "cd", 2,
+ devfs_register (scsi_CDs[i].device->de, "cd",
DEVFS_FL_DEFAULT, MAJOR_NR, i,
- S_IFBLK | S_IRUGO | S_IWUGO, 0, 0,
+ S_IFBLK | S_IRUGO | S_IWUGO,
&cdrom_fops, NULL);
register_cdrom(&scsi_CDs[i].cdi);
}
@@ -857,7 +857,6 @@ void cleanup_module(void)
}
blksize_size[MAJOR_NR] = NULL;
hardsect_size[MAJOR_NR] = NULL;
- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
blk_size[MAJOR_NR] = NULL;
read_ahead[MAJOR_NR] = 0;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index a9d08c165..bdc3e8002 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -3509,17 +3509,17 @@ static int st_attach(Scsi_Device * SDp)
/* Rewind entry */
sprintf (name, "mt%s", formats[mode]);
tpnt->de_r[mode] =
- devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
+ devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
MAJOR_NR, i + (mode << 5),
S_IFCHR | S_IRUGO | S_IWUGO,
- 0, 0, &st_fops, NULL);
+ &st_fops, NULL);
/* No-rewind entry */
sprintf (name, "mt%sn", formats[mode]);
tpnt->de_n[mode] =
- devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
+ devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
MAJOR_NR, i + (mode << 5) + 128,
S_IFCHR | S_IRUGO | S_IWUGO,
- 0, 0, &st_fops, NULL);
+ &st_fops, NULL);
}
devfs_register_tape (tpnt->de_r[0]);
tpnt->device = SDp;
diff --git a/drivers/sgi/char/shmiq.c b/drivers/sgi/char/shmiq.c
index 18009a65a..5df43bf8b 100644
--- a/drivers/sgi/char/shmiq.c
+++ b/drivers/sgi/char/shmiq.c
@@ -457,11 +457,11 @@ shmiq_init (void)
{
printk ("SHMIQ setup\n");
devfs_register_chrdev(SHMIQ_MAJOR, "shmiq", &shmiq_fops);
- devfs_register (NULL, "shmiq", 0, DEVFS_FL_DEFAULT,
- SHMIQ_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ devfs_register (NULL, "shmiq", DEVFS_FL_DEFAULT,
+ SHMIQ_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR,
&shmiq_fops, NULL);
devfs_register_series (NULL, "qcntl%u", 2, DEVFS_FL_DEFAULT,
SHMIQ_MAJOR, 1,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&shmiq_fops, NULL);
}
diff --git a/drivers/sound/sound_core.c b/drivers/sound/sound_core.c
index da0cfe51c..9ec821b91 100644
--- a/drivers/sound/sound_core.c
+++ b/drivers/sound/sound_core.c
@@ -175,9 +175,9 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f
sprintf (name_buf, "%s", name);
else
sprintf (name_buf, "%s%d", name, (r - low) / SOUND_STEP);
- s->de = devfs_register (devfs_handle, name_buf, 0,
+ s->de = devfs_register (devfs_handle, name_buf,
DEVFS_FL_NONE, SOUND_MAJOR, s->unit_minor,
- S_IFCHR | mode, 0, 0, fops, NULL);
+ S_IFCHR | mode, fops, NULL);
return r;
}
diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c
index 5018ad1e7..aa7b82280 100644
--- a/drivers/sound/soundcard.c
+++ b/drivers/sound/soundcard.c
@@ -565,9 +565,9 @@ static void soundcard_register_devfs (int do_register)
for (j = 0; j < num || j == 0; j++) {
soundcard_make_name (name_buf, dev_list[i].name, j);
if (do_register)
- devfs_register (NULL, name_buf, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, name_buf, DEVFS_FL_NONE,
SOUND_MAJOR, dev_list[i].minor+ (j* 0x10),
- S_IFCHR | dev_list[i].mode, 0, 0,
+ S_IFCHR | dev_list[i].mode,
&oss_sound_fops, NULL);
else {
devfs_handle_t de;
diff --git a/drivers/telephony/ixj.h b/drivers/telephony/ixj.h
index d88013c2f..3559cc5c0 100644
--- a/drivers/telephony/ixj.h
+++ b/drivers/telephony/ixj.h
@@ -879,7 +879,6 @@ typedef struct {
typedef struct {
struct phone_device p;
- struct semaphore mutex;
unsigned int board;
unsigned int DSPbase;
unsigned int XILINXbase;
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 042f742da..5032a9b75 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -70,7 +70,10 @@ comment 'USB HID'
dep_tristate ' USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB
fi
dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB
- dep_tristate ' Logitech WingMan Force joystick support' CONFIG_USB_WMFORCE $CONFIG_USB
+ dep_tristate ' I-Force joysticks/wheels' CONFIG_INPUT_IFORCE_USB $CONFIG_USB
+ if [ "$CONFIG_INPUT_IFORCE_USB" != "n" ]; then
+ define_tristate CONFIG_INPUT_IFORCE $CONFIG_INPUT_IFORCE_USB
+ fi
dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB
dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB
if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index ec8687ae6..7d95c0c98 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -61,7 +61,7 @@ obj-$(CONFIG_USB_MOUSE) += usbmouse.o input.o
obj-$(CONFIG_USB_HID) += hid.o input.o
obj-$(CONFIG_USB_KBD) += usbkbd.o input.o
obj-$(CONFIG_USB_WACOM) += wacom.o input.o
-obj-$(CONFIG_USB_WMFORCE) += wmforce.o input.o
+obj-$(CONFIG_INPUT_IFORCE) += iforce.o input.o
obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o input.o
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o input.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o input.o
diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c
index 235385515..d6cedee9b 100644
--- a/drivers/usb/devio.c
+++ b/drivers/usb/devio.c
@@ -1044,7 +1044,7 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
kfree (buf);
return -EFAULT;
} else
- memset (arg, size, 0);
+ memset (arg, 0, size);
}
/* ioctl to device */
diff --git a/drivers/usb/evdev.c b/drivers/usb/evdev.c
index 3e21f6cb5..7eca5e304 100644
--- a/drivers/usb/evdev.c
+++ b/drivers/usb/evdev.c
@@ -1,5 +1,5 @@
/*
- * $Id: evdev.c,v 1.8 2000/05/29 09:01:52 vojtech Exp $
+ * $Id: evdev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $
*
* Copyright (c) 1999-2000 Vojtech Pavlik
*
@@ -39,7 +39,7 @@
#include <linux/input.h>
struct evdev {
- int used;
+ int exist;
int open;
int minor;
struct input_handle handle;
@@ -99,13 +99,14 @@ static int evdev_release(struct inode * inode, struct file * file)
listptr = &((*listptr)->next);
*listptr = (*listptr)->next;
- if (!--list->evdev->open)
- input_close_device(&list->evdev->handle);
-
- if (!--list->evdev->used) {
- input_unregister_minor(list->evdev->devfs);
- evdev_table[list->evdev->minor] = NULL;
- kfree(list->evdev);
+ if (!--list->evdev->open) {
+ if (list->evdev->exist) {
+ input_close_device(&list->evdev->handle);
+ } else {
+ input_unregister_minor(list->evdev->devfs);
+ evdev_table[list->evdev->minor] = NULL;
+ kfree(list->evdev);
+ }
}
kfree(list);
@@ -121,9 +122,8 @@ static int evdev_open(struct inode * inode, struct file * file)
if (i > EVDEV_MINORS || !evdev_table[i])
return -ENODEV;
- if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) {
+ if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
return -ENOMEM;
- }
memset(list, 0, sizeof(struct evdev_list));
list->evdev = evdev_table[i];
@@ -132,10 +132,9 @@ static int evdev_open(struct inode * inode, struct file * file)
file->private_data = list;
- list->evdev->used++;
-
if (!list->evdev->open++)
- input_open_device(&list->evdev->handle);
+ if (list->evdev->exist)
+ input_open_device(&list->evdev->handle);
return 0;
}
@@ -303,7 +302,7 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct
evdev->handle.handler = handler;
evdev->handle.private = evdev;
- evdev->used = 1;
+ evdev->exist = 1;
evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE);
@@ -316,10 +315,11 @@ static void evdev_disconnect(struct input_handle *handle)
{
struct evdev *evdev = handle->private;
- if (evdev->open)
- input_close_device(handle);
+ evdev->exist = 0;
- if (!--evdev->used) {
+ if (evdev->open) {
+ input_close_device(handle);
+ } else {
input_unregister_minor(evdev->devfs);
evdev_table[evdev->minor] = NULL;
kfree(evdev);
diff --git a/drivers/usb/iforce.c b/drivers/usb/iforce.c
new file mode 100644
index 000000000..a61b7801f
--- /dev/null
+++ b/drivers/usb/iforce.c
@@ -0,0 +1,335 @@
+/*
+ * $Id: iforce.c,v 1.7 2000/06/04 14:03:36 vojtech Exp $
+ *
+ * Copyright (c) 2000 Vojtech Pavlik
+ *
+ * USB/RS232 I-Force joysticks and wheels.
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * 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 <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/serio.h>
+#include <linux/config.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+
+#define USB_VENDOR_ID_LOGITECH 0x046d
+#define USB_DEVICE_ID_LOGITECH_WMFORCE 0xc281
+
+#define IFORCE_MAX_LENGTH 16
+
+#if defined(CONFIG_INPUT_IFORCE_232) || defined(CONFIG_INPUT_IFORCE_232_MODULE)
+#define IFORCE_232
+#endif
+#if defined(CONFIG_INPUT_IFORCE_USB) || defined(CONFIG_INPUT_IFORCE_USB_MODULE)
+#define IFORCE_USB
+#endif
+
+struct iforce {
+ signed char data[IFORCE_MAX_LENGTH];
+ struct input_dev dev;
+ struct urb irq;
+ int open;
+ int idx, pkt, len, id;
+ unsigned char csum;
+};
+
+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}};
+
+static char *iforce_name = "I-Force joystick/wheel";
+
+static void iforce_process_packet(struct input_dev *dev, unsigned char id, int idx, unsigned char *data)
+{
+ switch (id) {
+
+ case 1: /* joystick position data */
+ case 3: /* wheel position data */
+
+ if (id == 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]);
+ } 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);
+
+ input_report_key(dev, BTN_TRIGGER, data[5] & 0x01);
+ input_report_key(dev, BTN_TOP, data[5] & 0x02);
+ input_report_key(dev, BTN_THUMB, data[5] & 0x04);
+ input_report_key(dev, BTN_TOP2, data[5] & 0x08);
+ input_report_key(dev, BTN_BASE, data[5] & 0x10);
+ input_report_key(dev, BTN_BASE2, data[5] & 0x20);
+ input_report_key(dev, BTN_BASE3, data[5] & 0x40);
+ input_report_key(dev, BTN_BASE4, data[5] & 0x80);
+ input_report_key(dev, BTN_BASE5, data[6] & 0x01);
+ input_report_key(dev, BTN_A, data[6] & 0x02);
+ input_report_key(dev, BTN_B, data[6] & 0x04);
+ input_report_key(dev, BTN_C, data[6] & 0x08);
+ break;
+
+ case 2: /* force feedback effect status */
+ break;
+ }
+}
+
+
+static int iforce_open(struct input_dev *dev)
+{
+ struct iforce *iforce = dev->private;
+
+ if (dev->idbus == BUS_USB && !iforce->open++)
+ if (usb_submit_urb(&iforce->irq))
+ return -EIO;
+
+ return 0;
+}
+
+static void iforce_close(struct input_dev *dev)
+{
+ struct iforce *iforce = dev->private;
+
+ if (dev->idbus == BUS_USB && !--iforce->open)
+ usb_unlink_urb(&iforce->irq);
+}
+
+static void iforce_input_setup(struct iforce *iforce)
+{
+ int i;
+
+ iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ iforce->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_TOP) | BIT(BTN_THUMB) | BIT(BTN_TOP2) |
+ BIT(BTN_BASE) | BIT(BTN_BASE2) | BIT(BTN_BASE3) | BIT(BTN_BASE4) | BIT(BTN_BASE5);
+ iforce->dev.keybit[LONG(BTN_GAMEPAD)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C);
+ iforce->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y)
+ | BIT(ABS_WHEEL) | BIT(ABS_GAS) | BIT(ABS_BRAKE);
+
+ for (i = ABS_X; i <= ABS_Y; i++) {
+ iforce->dev.absmax[i] = 1920;
+ iforce->dev.absmin[i] = -1920;
+ iforce->dev.absflat[i] = 128;
+ iforce->dev.absfuzz[i] = 16;
+ }
+
+ for (i = ABS_THROTTLE; i <= ABS_RUDDER; i++) {
+ iforce->dev.absmax[i] = 255;
+ iforce->dev.absmin[i] = 0;
+ }
+
+ for (i = ABS_HAT0X; i <= ABS_HAT0Y; i++) {
+ iforce->dev.absmax[i] = 1;
+ iforce->dev.absmin[i] = -1;
+ }
+
+ iforce->dev.private = iforce;
+ iforce->dev.open = iforce_open;
+ iforce->dev.close = iforce_close;
+
+ input_register_device(&iforce->dev);
+}
+
+#ifdef IFORCE_USB
+
+static void iforce_usb_irq(struct urb *urb)
+{
+ struct iforce *iforce = urb->context;
+ if (urb->status) return;
+ iforce_process_packet(&iforce->dev, iforce->data[0], 8, iforce->data + 1);
+}
+
+static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum)
+{
+ struct usb_endpoint_descriptor *endpoint;
+ struct iforce *iforce;
+
+ if (dev->descriptor.idVendor != USB_VENDOR_ID_LOGITECH ||
+ dev->descriptor.idProduct != USB_DEVICE_ID_LOGITECH_WMFORCE)
+ return NULL;
+
+ endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
+
+ if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return NULL;
+ memset(iforce, 0, sizeof(struct iforce));
+
+ iforce->dev.name = iforce_name;
+ iforce->dev.idbus = BUS_USB;
+ iforce->dev.idvendor = dev->descriptor.idVendor;
+ iforce->dev.idproduct = dev->descriptor.idProduct;
+ iforce->dev.idversion = dev->descriptor.bcdDevice;
+
+ FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ iforce->data, 8, iforce_usb_irq, iforce, endpoint->bInterval);
+
+ iforce_input_setup(iforce);
+
+ printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
+ iforce->dev.number, iforce_name, dev->bus->busnum, dev->devnum, ifnum);
+
+ 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_driver iforce_usb_driver = {
+ name: "iforce",
+ probe: iforce_usb_probe,
+ disconnect: iforce_usb_disconnect,
+};
+
+#endif
+
+#ifdef IFORCE_232
+
+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) {
+ 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->dev, iforce->id, 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->dev.name = iforce_name;
+ iforce->dev.idbus = BUS_RS232;
+ iforce->dev.idvendor = SERIO_IFORCE;
+ iforce->dev.idproduct = 0x0001;
+ iforce->dev.idversion = 0x0100;
+
+ serio->private = iforce;
+
+ if (serio_open(serio, dev)) {
+ kfree(iforce);
+ return;
+ }
+
+ iforce_input_setup(iforce);
+
+ printk(KERN_INFO "input%d: %s on serio%d\n",
+ iforce->dev.number, iforce_name, serio->number);
+}
+
+static void iforce_serio_disconnect(struct serio *serio)
+{
+ struct iforce* iforce = serio->private;
+ input_unregister_device(&iforce->dev);
+ serio_close(serio);
+ kfree(iforce);
+}
+
+static struct serio_dev iforce_serio_dev = {
+ interrupt: iforce_serio_irq,
+ connect: iforce_serio_connect,
+ disconnect: iforce_serio_disconnect,
+};
+
+#endif
+
+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);
diff --git a/drivers/usb/input.c b/drivers/usb/input.c
index 66a3d2911..4fb2985af 100644
--- a/drivers/usb/input.c
+++ b/drivers/usb/input.c
@@ -386,8 +386,8 @@ devfs_handle_t input_register_minor(char *name, int minor, int minor_base)
{
char devfs_name[16];
sprintf(devfs_name, name, minor);
- return devfs_register(input_devfs_handle, devfs_name, 0, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base,
- S_IFCHR | S_IRUGO | S_IWUSR, 0, 0, &input_fops, NULL);
+ return devfs_register(input_devfs_handle, devfs_name, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base,
+ S_IFCHR | S_IRUGO | S_IWUSR, &input_fops, NULL);
}
void input_unregister_minor(devfs_handle_t handle)
diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c
index 0f0bb2773..5349d515c 100644
--- a/drivers/usb/joydev.c
+++ b/drivers/usb/joydev.c
@@ -1,7 +1,7 @@
/*
- * $Id: joydev.c,v 1.7 2000/05/29 09:01:52 vojtech Exp $
+ * $Id: joydev.c,v 1.11 2000/06/23 09:23:00 vojtech Exp $
*
- * Copyright (c) 1999-2000 Vojtech Pavlik
+ * Copyright (c) 1999-2000 Vojtech Pavlik
* Copyright (c) 1999 Colin Van Dyke
*
* Joystick device driver for the input driver suite.
@@ -50,7 +50,7 @@
#define JOYDEV_BUFFER_SIZE 64
struct joydev {
- int used;
+ int exist;
int open;
int minor;
struct input_handle handle;
@@ -66,6 +66,7 @@ struct joydev {
__u16 keypam[KEY_MAX - BTN_MISC];
__u8 absmap[ABS_MAX];
__u8 abspam[ABS_MAX];
+ __s16 abs[ABS_MAX];
};
struct joydev_list {
@@ -121,7 +122,9 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
case EV_ABS:
event.type = JS_EVENT_AXIS;
event.number = joydev->absmap[code];
- event.value = joydev_correct(value, &joydev->corr[event.number]);
+ event.value = joydev_correct(value, joydev->corr + event.number);
+ if (event.value == joydev->abs[event.number]) return;
+ joydev->abs[event.number] = event.value;
break;
default:
@@ -165,13 +168,14 @@ static int joydev_release(struct inode * inode, struct file * file)
listptr = &((*listptr)->next);
*listptr = (*listptr)->next;
- if (!--list->joydev->open)
- input_close_device(&list->joydev->handle);
-
- if (!--list->joydev->used) {
- input_unregister_minor(list->joydev->devfs);
- joydev_table[list->joydev->minor] = NULL;
- kfree(list->joydev);
+ if (!--list->joydev->open) {
+ if (list->joydev->exist) {
+ input_close_device(&list->joydev->handle);
+ } else {
+ input_unregister_minor(list->joydev->devfs);
+ joydev_table[list->joydev->minor] = NULL;
+ kfree(list->joydev);
+ }
}
kfree(list);
@@ -187,9 +191,8 @@ static int joydev_open(struct inode *inode, struct file *file)
if (i > JOYDEV_MINORS || !joydev_table[i])
return -ENODEV;
- if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) {
+ if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL)))
return -ENOMEM;
- }
memset(list, 0, sizeof(struct joydev_list));
list->joydev = joydev_table[i];
@@ -198,10 +201,9 @@ static int joydev_open(struct inode *inode, struct file *file)
file->private_data = list;
- list->joydev->used++;
-
if (!list->joydev->open++)
- input_open_device(&list->joydev->handle);
+ if (list->joydev->exist)
+ input_open_device(&list->joydev->handle);
return 0;
}
@@ -228,8 +230,8 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p
data.buttons = ((joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0) |
((joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0);
- data.x = ((joydev_correct(input->abs[ABS_X], &joydev->corr[0]) / 256) + 128) >> joydev->glue.JS_CORR.x;
- data.y = ((joydev_correct(input->abs[ABS_Y], &joydev->corr[1]) / 256) + 128) >> joydev->glue.JS_CORR.y;
+ data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
+ data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
return -EFAULT;
@@ -274,13 +276,12 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p
if (list->startup < joydev->nkey) {
event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
- event.value = !!test_bit(joydev->keypam[list->startup], input->key);
event.number = list->startup;
+ event.value = !!test_bit(joydev->keypam[event.number], input->key);
} else {
event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
- event.value = joydev_correct(input->abs[joydev->abspam[list->startup - joydev->nkey]],
- &joydev->corr[list->startup - joydev->nkey]);
event.number = list->startup - joydev->nkey;
+ event.value = joydev->abs[event.number];
}
if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
@@ -407,7 +408,7 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
joydev->handle.handler = handler;
joydev->handle.private = joydev;
- joydev->used = 1;
+ joydev->exist = 1;
for (i = 0; i < ABS_MAX; i++)
if (test_bit(i, dev->absbit)) {
@@ -442,6 +443,8 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
joydev->corr[i].coef[2] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]);
joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]);
+
+ joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
}
joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE);
@@ -455,10 +458,11 @@ static void joydev_disconnect(struct input_handle *handle)
{
struct joydev *joydev = handle->private;
- if (joydev->open)
- input_close_device(handle);
+ joydev->exist = 0;
- if (!--joydev->used) {
+ if (joydev->open) {
+ input_close_device(handle);
+ } else {
input_unregister_minor(joydev->devfs);
joydev_table[joydev->minor] = NULL;
kfree(joydev);
diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c
index 399d2a0c0..5c871a88d 100644
--- a/drivers/usb/mousedev.c
+++ b/drivers/usb/mousedev.c
@@ -1,5 +1,5 @@
/*
- * $Id: mousedev.c,v 1.8 2000/05/28 17:31:36 vojtech Exp $
+ * $Id: mousedev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $
*
* Copyright (c) 1999-2000 Vojtech Pavlik
*
@@ -47,7 +47,7 @@
#endif
struct mousedev {
- int used;
+ int exist;
int open;
int minor;
wait_queue_head_t wait;
@@ -172,22 +172,30 @@ static int mousedev_release(struct inode * inode, struct file * file)
struct input_handle *handle = mousedev_handler.handle;
while (handle) {
struct mousedev *mousedev = handle->private;
- if (!mousedev->open)
- input_close_device(handle);
+ if (!mousedev->open) {
+ if (mousedev->exist) {
+ input_close_device(&mousedev->handle);
+ } else {
+ input_unregister_minor(mousedev->devfs);
+ mousedev_table[mousedev->minor] = NULL;
+ kfree(mousedev);
+ }
+ }
handle = handle->hnext;
}
} else {
- if (!mousedev_mix.open)
- input_close_device(&list->mousedev->handle);
+ if (!mousedev_mix.open) {
+ if (list->mousedev->exist) {
+ input_close_device(&list->mousedev->handle);
+ } else {
+ input_unregister_minor(list->mousedev->devfs);
+ mousedev_table[list->mousedev->minor] = NULL;
+ kfree(list->mousedev);
+ }
+ }
}
}
- if (!--list->mousedev->used) {
- input_unregister_minor(list->mousedev->devfs);
- mousedev_table[list->mousedev->minor] = NULL;
- kfree(list->mousedev);
- }
-
kfree(list);
return 0;
@@ -210,20 +218,20 @@ static int mousedev_open(struct inode * inode, struct file * file)
mousedev_table[i]->list = list;
file->private_data = list;
- list->mousedev->used++;
-
if (!list->mousedev->open++) {
if (list->mousedev->minor == MOUSEDEV_MIX) {
struct input_handle *handle = mousedev_handler.handle;
while (handle) {
struct mousedev *mousedev = handle->private;
if (!mousedev->open)
- input_open_device(handle);
+ if (mousedev->exist)
+ input_open_device(handle);
handle = handle->hnext;
}
} else {
- if (!mousedev_mix.open)
- input_open_device(&list->mousedev->handle);
+ if (!mousedev_mix.open)
+ if (list->mousedev->exist)
+ input_open_device(&list->mousedev->handle);
}
}
@@ -402,7 +410,7 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru
memset(mousedev, 0, sizeof(struct mousedev));
init_waitqueue_head(&mousedev->wait);
- mousedev->used = 1;
+ mousedev->exist = 1;
mousedev->minor = minor;
mousedev_table[minor] = mousedev;
@@ -424,10 +432,13 @@ static void mousedev_disconnect(struct input_handle *handle)
{
struct mousedev *mousedev = handle->private;
- if (mousedev->open || mousedev_mix.open)
- input_close_device(handle);
+ mousedev->exist = 0;
- if (!--mousedev->used) {
+ if (mousedev->open) {
+ input_close_device(handle);
+ } else {
+ if (mousedev_mix.open)
+ input_close_device(handle);
input_unregister_minor(mousedev->devfs);
mousedev_table[mousedev->minor] = NULL;
kfree(mousedev);
@@ -449,7 +460,7 @@ static int __init mousedev_init(void)
memset(&mousedev_mix, 0, sizeof(struct mousedev));
init_waitqueue_head(&mousedev_mix.wait);
mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
- mousedev_mix.used = 1;
+ mousedev_mix.exist = 1;
mousedev_mix.minor = MOUSEDEV_MIX;
mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);
diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
index 80b82bba2..8c588f79e 100644
--- a/drivers/usb/pegasus.c
+++ b/drivers/usb/pegasus.c
@@ -1,11 +1,37 @@
/*
** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
**
-** Copyright (R) 1999,2000 Petko Manolov - Petkan (petkan@spct.net)
+** Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@spct.net)
+**
**
-** Distribute under GPL version 2 or later.
+** ChangeLog:
+** .... Most of the time spend reading sources & docs.
+** v0.2.x First official release for the Linux kernel.
+** v0.3.0 Beutified and structured, some bugs fixed.
+** v0.3.x URBifying bulk requests and bugfixing. First relatively
+** stable release. Still can touch device's registers only
+** from top-halves.
+** v0.4.0 Control messages remained unurbified are now URBs.
+** Now we can touch the HW at any time.
*/
+/*
+ * 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/module.h>
#include <linux/sched.h>
#include <linux/malloc.h>
@@ -16,7 +42,7 @@
#include <linux/usb.h>
-static const char *version = __FILE__ ": v0.3.14 2000/06/09 (C) 1999-2000 Petko Manolov (petkan@spct.net)\n";
+static const char *version = __FILE__ ": v0.4.0 2000/06/15 (C) 1999-2000 Petko Manolov (petkan@spct.net)\n";
#define PEGASUS_MTU 1500
@@ -24,17 +50,39 @@ static const char *version = __FILE__ ": v0.3.14 2000/06/09 (C) 1999-2000 Petko
#define SROM_WRITE 0x01
#define SROM_READ 0x02
#define PEGASUS_TX_TIMEOUT (HZ*5)
+#define PEGASUS_CTRL_TIMEOUT 1000
#define PEGASUS_RESET 1
#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES)))
+enum pegasus_registers {
+ EthCtrl0 = 0,
+ EthCtrl1 = 1,
+ EthCtrl2 = 2,
+ EthID = 0x10,
+ EpromOffset = 0x20,
+ EpromData = 0x21, /* 0x21 low, 0x22 high byte */
+ EpromCtrl = 0x23,
+ PhyAddr = 0x25,
+ PhyData = 0x26, /* 0x26 low, 0x27 high byte */
+ PhyCtrl = 0x28,
+ UsbStst = 0x2a,
+ EthTxStat0 = 0x2b,
+ EthTxStat1 = 0x2c,
+ EthRxStat = 0x2d,
+ Gpio0 = 0x7e,
+ Gpio1 = 0x7f,
+};
+
+
struct pegasus {
struct usb_device *usb;
struct net_device *net;
struct net_device_stats stats;
int flags;
- spinlock_t pegasus_lock;
- struct urb rx_urb, tx_urb, intr_urb;
+ spinlock_t pegasus_lock, ctrl_lock;
+ struct urb rx_urb, tx_urb, intr_urb, ctrl_urb;
+ devrequest dr;
unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]);
unsigned char ALIGN(tx_buff[PEGASUS_MAX_MTU]);
unsigned char ALIGN(intr_buff[8]);
@@ -64,7 +112,7 @@ static struct usb_eth_dev usb_dev_id[] = {
{"D-Link DSB-650TX", 0x2001, 0x4001, NULL},
{"D-Link DSB-650TX", 0x2001, 0x4002, NULL},
{"D-Link DSB-650TX(PNA)", 0x2001, 0x4003, NULL},
- {"D-Link DU-10", 0x07b8, 0xabc1, NULL},
+ {"D-Link DU-E10", 0x07b8, 0xabc1, NULL},
{"D-Link DU-E100", 0x07b8, 0x4002, NULL},
{"Linksys USB100TX", 0x066b, 0x2203, NULL},
{"Linksys USB100TX", 0x066b, 0x2204, NULL},
@@ -78,23 +126,120 @@ static struct usb_eth_dev usb_dev_id[] = {
};
-#define pegasus_get_registers(dev, indx, size, data)\
- usb_control_msg(dev, usb_rcvctrlpipe(dev,0), 0xf0, 0xc0, 0, indx, data, size, HZ);
-#define pegasus_set_registers(dev, indx, size, data)\
- usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0xf1, 0x40, 0, indx, data, size, HZ);
-#define pegasus_set_register(dev, indx, value) \
- { __u8 __data = value; \
- usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0xf1, 0x40, __data, indx, &__data, 1, HZ);}
+
+static void pegasus_ctrl_end( urb_t *urb )
+{
+ if ( urb->status )
+ warn("ctrl_urb end status %d", urb->status);
+}
-static int pegasus_read_phy_word(struct usb_device *dev, __u8 index, __u16 *regdata)
+static int pegasus_ctrl_timeout( urb_t *ctrl_urb )
+{
+ int timeout=0;
+
+ while ( ctrl_urb->status == -EINPROGRESS ) {
+ if ( timeout++ < PEGASUS_CTRL_TIMEOUT ) {
+ udelay(100);
+ continue;
+ }
+ err("ctrl urb busy %d", ctrl_urb->status);
+ usb_unlink_urb( ctrl_urb );
+ return ctrl_urb->status;
+ }
+ return 0;
+}
+
+
+static int pegasus_get_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data )
+{
+ int ret;
+
+
+ spin_lock( &pegasus->ctrl_lock );
+ pegasus->dr.requesttype = 0xc0;
+ pegasus->dr.request = 0xf0;
+ pegasus->dr.value = 0x0;
+ pegasus->dr.index = indx;
+ pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = size;
+
+ FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+ usb_rcvctrlpipe(pegasus->usb,0), (char *)&pegasus->dr,
+ data, size, pegasus_ctrl_end, pegasus );
+
+ if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) )
+ err("BAD CTRLs %d", ret);
+ else
+ ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb );
+
+ spin_unlock( &pegasus->ctrl_lock );
+
+ return ret;
+}
+
+
+static int pegasus_set_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data )
+{
+ int ret;
+
+
+ spin_lock( &pegasus->ctrl_lock );
+ pegasus->dr.requesttype = 0x40;
+ pegasus->dr.request = 0xf1;
+ pegasus->dr.value = 0x0;
+ pegasus->dr.index = indx;
+ pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = size;
+
+ FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+ usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr,
+ data, size, pegasus_ctrl_end, pegasus );
+
+ if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) )
+ err("BAD CTRL %d", ret);
+ else
+ ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb );
+
+ spin_unlock( &pegasus->ctrl_lock );
+
+ return ret;
+}
+
+
+static int pegasus_set_register( struct pegasus *pegasus, __u16 indx,__u8 data )
+{
+ int ret;
+
+
+ spin_lock( &pegasus->ctrl_lock );
+ pegasus->dr.requesttype = 0x40;
+ pegasus->dr.request = 0xf1;
+ pegasus->dr.value = data;
+ pegasus->dr.index = indx;
+ pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = 1;
+
+ FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+ usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr,
+ &data, 1, pegasus_ctrl_end, pegasus );
+
+ if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) )
+ err("BAD CTRL %d", ret);
+ else
+ ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb );
+
+ spin_unlock( &pegasus->ctrl_lock );
+
+ return ret;
+}
+
+
+static int pegasus_read_phy_word(struct pegasus *pegasus, __u8 index, __u16 *regdata)
{
int i;
__u8 data[4] = { 1, 0, 0, 0x40 + index };
- pegasus_set_registers(dev, 0x25, 4, data);
+ pegasus_set_registers(pegasus, PhyAddr, 4, data);
for (i = 0; i < 100; i++) {
- pegasus_get_registers(dev, 0x26, 3, data);
+ pegasus_get_registers(pegasus, PhyData, 3, data);
if (data[2] & 0x80) {
*regdata = *(__u16 *)(data);
return 0;
@@ -107,14 +252,14 @@ static int pegasus_read_phy_word(struct usb_device *dev, __u8 index, __u16 *regd
}
-static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regdata)
+static int pegasus_write_phy_word(struct pegasus *pegasus, __u8 index, __u16 regdata)
{
int i;
__u8 data[4] = { 1, regdata, regdata >> 8, 0x20 + index };
- pegasus_set_registers(dev, 0x25, 4, data);
+ pegasus_set_registers(pegasus, PhyAddr, 4, data);
for (i = 0; i < 100; i++) {
- pegasus_get_registers(dev, 0x28, 1, data);
+ pegasus_get_registers(pegasus, PhyCtrl, 1, data);
if (data[0] & 0x80)
return 0;
udelay(100);
@@ -125,51 +270,51 @@ static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regd
}
-static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata, __u8 direction)
+static int pegasus_rw_eprom_word(struct pegasus *pegasus, __u8 index, __u16 *retdata, __u8 direction)
{
int i;
__u8 data[4] = { index, 0, 0, direction };
- pegasus_set_registers(dev, 0x20, 4, data);
+ pegasus_set_registers(pegasus, EpromOffset, 4, data);
for (i = 0; i < 100; i++) {
- pegasus_get_registers(dev, 0x23, 1, data);
+ pegasus_get_registers(pegasus, EpromCtrl, 1, data);
if (data[0] & 4) {
- pegasus_get_registers(dev, 0x21, 2, data);
+ pegasus_get_registers(pegasus, EpromData, 2, data);
*retdata = *(__u16 *)data;
return 0;
}
}
- warn("pegasus_rw_srom_word() failed");
+ warn("pegasus_rw_eprom_word() failed");
return 1;
}
-static int pegasus_get_node_id(struct usb_device *dev, __u8 *id)
+static int pegasus_get_node_id(struct pegasus *pegasus, __u8 *id)
{
int i;
for (i = 0; i < 3; i++)
- if (pegasus_rw_srom_word(dev,i,(__u16 *)&id[i * 2],SROM_READ))
+ if (pegasus_rw_eprom_word(pegasus,i,(__u16 *)&id[i*2],SROM_READ))
return 1;
return 0;
}
-static int pegasus_reset_mac(struct usb_device *dev)
+static int pegasus_reset_mac(struct pegasus *pegasus)
{
__u8 data = 0x8;
int i;
- pegasus_set_register(dev, 1, data);
+ pegasus_set_register(pegasus, EthCtrl1, data);
for (i = 0; i < 100; i++) {
- pegasus_get_registers(dev, 1, 1, &data);
+ pegasus_get_registers(pegasus, EthCtrl1, 1, &data);
if (~data & 0x08) {
if (loopback & 1)
return 0;
if (loopback & 2)
- pegasus_write_phy_word(dev, 0, 0x4000);
- pegasus_set_register(dev, 0x7e, 0x24);
- pegasus_set_register(dev, 0x7e, 0x27);
+ pegasus_write_phy_word(pegasus, 0, 0x4000);
+ pegasus_set_register(pegasus, Gpio0, 0x24);
+ pegasus_set_register(pegasus, Gpio0, 0x27);
return 0;
}
}
@@ -183,22 +328,22 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
__u16 partmedia, temp;
__u8 node_id[6];
__u8 data[4];
+ struct pegasus *pegasus = dev->priv;
- if (pegasus_get_node_id(usb, node_id))
+ if (pegasus_get_node_id(pegasus, node_id))
return 1;
- pegasus_set_registers(usb, 0x10, 6, node_id);
+ pegasus_set_registers(pegasus, EthID, 6, node_id);
memcpy(dev->dev_addr, node_id, 6);
- if (pegasus_read_phy_word(usb, 1, &temp))
+ if (pegasus_read_phy_word(pegasus, 1, &temp))
return 2;
if ((~temp & 4) && !loopback) {
- warn("%s: link NOT established (0x%x), check the cable.",
+ warn("%s: link NOT established (0x%x) - check the cable.",
dev->name, temp);
- /* return 3; FIXME */
}
- if (pegasus_read_phy_word(usb, 5, &partmedia))
+ if (pegasus_read_phy_word(pegasus, 5, &partmedia))
return 4;
if ((partmedia & 0x1f) != 1) {
@@ -210,7 +355,7 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
data[1] = (partmedia & 0x100) ? 0x30 : ((partmedia & 0x80) ? 0x10 : 0);
data[2] = (loopback & 1) ? 0x09 : 0x01;
- pegasus_set_registers(usb, 0, 3, data);
+ pegasus_set_registers(pegasus, EthCtrl0, 3, data);
return 0;
}
@@ -281,24 +426,26 @@ static void pegasus_write_bulk(struct urb *urb)
{
struct pegasus *pegasus = urb->context;
- spin_lock(&pegasus->pegasus_lock);
if (urb->status)
info("%s: TX status %d", pegasus->net->name, urb->status);
+#if 1 /* Should be fixed */
+ if (urb->status == -ETIMEDOUT)
+ pegasus_reset_mac(pegasus);
+#endif
netif_wake_queue(pegasus->net);
-
- spin_unlock(&pegasus->pegasus_lock);
}
static void pegasus_tx_timeout(struct net_device *net)
{
struct pegasus *pegasus = net->priv;
- warn("%s: Tx timed out. Reseting...", net->name);
+
usb_unlink_urb(&pegasus->tx_urb);
+ warn("%s: Tx timed out. Reseting...", net->name);
+ pegasus_reset_mac( pegasus );
pegasus->stats.tx_errors++;
net->trans_start = jiffies;
- pegasus->flags |= PEGASUS_RESET;
netif_wake_queue(net);
}
@@ -372,6 +519,8 @@ static int pegasus_close(struct net_device *net)
netif_stop_queue(net);
+ if ( pegasus->ctrl_urb.status == -EINPROGRESS )
+ usb_unlink_urb(&pegasus->ctrl_urb);
if ( pegasus->rx_urb.status == -EINPROGRESS )
usb_unlink_urb(&pegasus->rx_urb);
if ( pegasus->tx_urb.status == -EINPROGRESS )
@@ -394,12 +543,12 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
case SIOCDEVPRIVATE:
data[0] = 1;
case SIOCDEVPRIVATE+1:
- pegasus_read_phy_word(pegasus->usb, data[1] & 0x1f, &data[3]);
+ pegasus_read_phy_word(pegasus, data[1] & 0x1f, &data[3]);
return 0;
case SIOCDEVPRIVATE+2:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- pegasus_write_phy_word(pegasus->usb, data[1] & 0x1f, data[2]);
+ pegasus_write_phy_word(pegasus, data[1] & 0x1f, data[2]);
return 0;
default:
return -EOPNOTSUPP;
@@ -410,19 +559,23 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
static void pegasus_set_rx_mode(struct net_device *net)
{
struct pegasus *pegasus = net->priv;
+ __u8 tmp;
netif_stop_queue(net);
if (net->flags & IFF_PROMISC) {
info("%s: Promiscuous mode enabled", net->name);
-/* pegasus_set_register(pegasus->usb, 2, 0x04); FIXME */
+ pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp);
+ pegasus_set_register(pegasus, EthCtrl2, tmp | 4);
} else if ((net->mc_count > multicast_filter_limit) ||
(net->flags & IFF_ALLMULTI)) {
- pegasus_set_register(pegasus->usb, 0, 0xfa);
- pegasus_set_register(pegasus->usb, 2, 0);
+ pegasus_set_register(pegasus, EthCtrl0, 0xfa);
+ pegasus_set_register(pegasus, EthCtrl2, 0);
info("%s set allmulti", net->name);
} else {
info("%s: set Rx mode", net->name);
+ pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp);
+ pegasus_set_register(pegasus, EthCtrl2, tmp & ~4);
}
netif_wake_queue(net);
@@ -464,12 +617,6 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
}
memset(pegasus, 0, sizeof(struct pegasus));
- if (pegasus_reset_mac(dev)) {
- err("can't reset MAC");
- kfree(pegasus);
- return NULL;
- }
-
net = init_etherdev(0, 0);
net->priv = pegasus;
net->open = pegasus_open;
@@ -485,6 +632,7 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
pegasus->usb = dev;
pegasus->net = net;
pegasus->pegasus_lock = SPIN_LOCK_UNLOCKED;
+ pegasus->ctrl_lock = SPIN_LOCK_UNLOCKED;
FILL_BULK_URB(&pegasus->rx_urb, dev, usb_rcvbulkpipe(dev, 1),
pegasus->rx_buff, PEGASUS_MAX_MTU, pegasus_read_bulk,
@@ -495,7 +643,12 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3),
pegasus->intr_buff, 8, pegasus_irq, pegasus, 500);
-
+ if (pegasus_reset_mac(pegasus)) {
+ err("can't reset MAC");
+ kfree(pegasus);
+ return NULL;
+ }
+
printk(KERN_INFO "%s: %s\n", net->name, usb_dev_id[dev_indx].name);
return pegasus;
@@ -515,7 +668,9 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr)
dev_close(pegasus->net);
unregister_netdev(pegasus->net);
-
+
+ if ( pegasus->ctrl_urb.status == -EINPROGRESS )
+ usb_unlink_urb(&pegasus->ctrl_urb);
if ( pegasus->rx_urb.status == -EINPROGRESS )
usb_unlink_urb(&pegasus->rx_urb);
if ( pegasus->tx_urb.status == -EINPROGRESS )
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index b2e18bd8e..d60fd8e33 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -14,6 +14,9 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (06/23/2000) gkh
+ * Cleaned up debugging statements in a quest to find UHCI timeout bug.
+ *
* (05/22/2000) gkh
* Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be
* removed from the individual device source files.
@@ -358,7 +361,7 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor)
int i, j;
int good_spot;
- dbg("get_free_serial %d", num_ports);
+ dbg(__FUNCTION__ " %d", num_ports);
*minor = 0;
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
@@ -373,14 +376,14 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor)
continue;
if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) {
- err("Out of memory");
+ err(__FUNCTION__ " - Out of memory");
return NULL;
}
memset(serial, 0, sizeof(struct usb_serial));
serial->magic = USB_SERIAL_MAGIC;
serial_table[i] = serial;
*minor = i;
- dbg("minor base = %d", *minor);
+ dbg(__FUNCTION__ " - minor base = %d", *minor);
for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
serial_table[i] = serial;
return serial;
@@ -393,7 +396,7 @@ static void return_serial (struct usb_serial *serial)
{
int i;
- dbg("return_serial");
+ dbg(__FUNCTION__);
if (serial == NULL)
return;
@@ -418,7 +421,7 @@ int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *da
// dbg("ezusb_writememory %x, %d", address, length);
if (!transfer_buffer) {
- err("ezusb_writememory: kmalloc(%d) failed.", length);
+ err(__FUNCTION__ " - kmalloc(%d) failed.", length);
return -ENOMEM;
}
memcpy (transfer_buffer, data, length);
@@ -431,10 +434,10 @@ int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *da
int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
{
int response;
- dbg("ezusb_set_reset: %d", reset_bit);
+ dbg(__FUNCTION__ " - %d", reset_bit);
response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0);
if (response < 0) {
- err("ezusb_set_reset %d failed", reset_bit);
+ err(__FUNCTION__ "- %d failed", reset_bit);
}
return response;
}
@@ -451,7 +454,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
struct usb_serial_port *port;
int portNumber;
- dbg("serial_open");
+ dbg(__FUNCTION__);
/* initialize the pointer incase something fails */
tty->driver_data = NULL;
@@ -459,7 +462,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
/* get the serial object associated with this tty pointer */
serial = get_serial_by_minor (MINOR(tty->device));
- if (serial_paranoia_check (serial, "serial_open")) {
+ if (serial_paranoia_check (serial, __FUNCTION__)) {
return -ENODEV;
}
@@ -481,16 +484,16 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
static void serial_close(struct tty_struct *tty, struct file * filp)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_close");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return;
}
- dbg("serial_close port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not opened");
+ dbg (__FUNCTION__ " - port not opened");
return;
}
@@ -506,16 +509,16 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_write");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return -ENODEV;
}
- dbg("serial_write port %d, %d byte(s)", port->number, count);
+ dbg(__FUNCTION__ " - port %d, %d byte(s)", port->number, count);
if (!port->active) {
- dbg ("port not opened");
+ dbg (__FUNCTION__ " - port not opened");
return -EINVAL;
}
@@ -531,16 +534,16 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned
static int serial_write_room (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_write_room");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return -ENODEV;
}
- dbg("serial_write_room port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return -EINVAL;
}
@@ -556,14 +559,14 @@ static int serial_write_room (struct tty_struct *tty)
static int serial_chars_in_buffer (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_chars_in_buffer");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return -ENODEV;
}
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return -EINVAL;
}
@@ -579,16 +582,16 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
static void serial_throttle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_throttle");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return;
}
- dbg("serial_throttle port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return;
}
@@ -604,16 +607,16 @@ static void serial_throttle (struct tty_struct * tty)
static void serial_unthrottle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_unthrottle");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return;
}
- dbg("serial_unthrottle port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return;
}
@@ -629,16 +632,16 @@ static void serial_unthrottle (struct tty_struct * tty)
static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_ioctl");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return -ENODEV;
}
- dbg("serial_ioctl port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return -ENODEV;
}
@@ -654,16 +657,16 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
static void serial_set_termios (struct tty_struct *tty, struct termios * old)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_set_termios");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return;
}
- dbg("serial_set_termios port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return;
}
@@ -679,16 +682,16 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
static void serial_break (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_break");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return;
}
- dbg("serial_break port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return;
}
@@ -708,10 +711,10 @@ static int generic_open (struct usb_serial_port *port, struct file *filp)
{
struct usb_serial *serial = port->serial;
- dbg("generic_open port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (port->active) {
- dbg ("device already open");
+ dbg (__FUNCTION__ " - device already open");
return -EINVAL;
}
port->active = 1;
@@ -720,7 +723,7 @@ static int generic_open (struct usb_serial_port *port, struct file *filp)
if (serial->num_bulk_in) {
/*Start reading from the device*/
if (usb_submit_urb(port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
+ dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
}
return (0);
@@ -731,7 +734,7 @@ static void generic_close (struct usb_serial_port *port, struct file * filp)
{
struct usb_serial *serial = port->serial;
- dbg("generic_close port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
/* shutdown any bulk reads that might be going on */
if (serial->num_bulk_out) {
@@ -749,22 +752,33 @@ static int generic_write (struct usb_serial_port *port, int from_user, const uns
{
struct usb_serial *serial = port->serial;
- dbg("generic_serial_write port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (count == 0) {
- dbg("write request of 0 bytes");
+ dbg(__FUNCTION__ " - write request of 0 bytes");
return (0);
}
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
if (port->write_urb->status == -EINPROGRESS) {
- dbg ("already writing");
+ dbg (__FUNCTION__ " - already writing");
return (0);
}
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+#ifdef DEBUG
+ {
+ int i;
+ printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
+ for (i = 0; i < count; ++i) {
+ printk ("%.2x ", buf[i]);
+ }
+ printk ("\n");
+ }
+#endif
+
if (from_user) {
copy_from_user(port->write_urb->transfer_buffer, buf, count);
}
@@ -776,7 +790,7 @@ static int generic_write (struct usb_serial_port *port, int from_user, const uns
port->write_urb->transfer_buffer_length = count;
if (usb_submit_urb(port->write_urb))
- dbg("usb_submit_urb(write bulk) failed");
+ dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed");
return (count);
}
@@ -791,14 +805,14 @@ static int generic_write_room (struct usb_serial_port *port)
struct usb_serial *serial = port->serial;
int room;
- dbg("generic_write_room port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (serial->num_bulk_out) {
if (port->write_urb->status == -EINPROGRESS)
room = 0;
else
room = port->bulk_out_size;
- dbg("generic_write_room returns %d", room);
+ dbg(__FUNCTION__ " returns %d", room);
return (room);
}
@@ -810,7 +824,7 @@ static int generic_chars_in_buffer (struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
- dbg("generic_chars_in_buffer port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (serial->num_bulk_out) {
if (port->write_urb->status == -EINPROGRESS) {
@@ -825,23 +839,25 @@ static int generic_chars_in_buffer (struct usb_serial_port *port)
static void generic_read_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial = get_usb_serial (port, "generic_read_bulk_callback");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int i;
+ dbg (__FUNCTION__ " - enter");
+
if (!serial) {
return;
}
if (urb->status) {
- dbg("nonzero read bulk status received: %d", urb->status);
+ dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
return;
}
#ifdef DEBUG
if (urb->actual_length) {
- printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", urb->actual_length);
for (i = 0; i < urb->actual_length; ++i) {
printk ("%.2x ", data[i]);
}
@@ -859,8 +875,10 @@ static void generic_read_bulk_callback (struct urb *urb)
/* Continue trying to always read */
if (usb_submit_urb(urb))
- dbg("failed resubmitting read urb");
+ dbg(__FUNCTION__ " - failed resubmitting read urb");
+ dbg (__FUNCTION__ " - exit");
+
return;
}
@@ -868,15 +886,17 @@ static void generic_read_bulk_callback (struct urb *urb)
static void generic_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial = get_usb_serial (port, "generic_write_bulk_callback");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
struct tty_struct *tty;
+ dbg (__FUNCTION__ " - enter");
+
if (!serial) {
return;
}
if (urb->status) {
- dbg("nonzero write bulk status received: %d", urb->status);
+ dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
return;
}
@@ -886,6 +906,8 @@ static void generic_write_bulk_callback (struct urb *urb)
wake_up_interruptible(&tty->write_wait);
+ dbg (__FUNCTION__ " - exit");
+
return;
}
@@ -1255,7 +1277,7 @@ int usb_serial_init(void)
serial_tty_driver.init_termios = tty_std_termios;
serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
if (tty_register_driver (&serial_tty_driver)) {
- err("failed to register tty driver");
+ err(__FUNCTION__ " - failed to register tty driver");
return -1;
}
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 5cfb4c42a..8be2dd351 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -11,6 +11,9 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (06/23/2000) gkh
+ * Cleaned up debugging statements in a quest to find UHCI timeout bug.
+ *
* (04/27/2000) Ryan VanderBijl
* Fixed memory leak in visor_close
*
@@ -80,10 +83,10 @@ struct usb_serial_device_type handspring_device = {
******************************************************************************/
static int visor_open (struct usb_serial_port *port, struct file *filp)
{
- dbg("visor_open port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (port->active) {
- dbg ("device already open");
+ dbg (__FUNCTION__ " - device already open");
return -EINVAL;
}
@@ -91,7 +94,7 @@ static int visor_open (struct usb_serial_port *port, struct file *filp)
/*Start reading from the device*/
if (usb_submit_urb(port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
+ dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
return (0);
}
@@ -102,10 +105,10 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
struct usb_serial *serial = port->serial;
unsigned char *transfer_buffer = kmalloc (0x12, GFP_KERNEL);
- dbg("visor_close port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!transfer_buffer) {
- err("visor_close: kmalloc(%d) failed.", 0x12);
+ err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
} else {
/* send a shutdown message to the device */
usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
@@ -122,7 +125,7 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
static void visor_throttle (struct usb_serial_port *port)
{
- dbg("visor_throttle port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
usb_unlink_urb (port->read_urb);
@@ -132,10 +135,10 @@ static void visor_throttle (struct usb_serial_port *port)
static void visor_unthrottle (struct usb_serial_port *port)
{
- dbg("visor_unthrottle port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (usb_unlink_urb (port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
+ dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
return;
}
@@ -148,20 +151,20 @@ static int visor_startup (struct usb_serial *serial)
unsigned char *transfer_buffer = kmalloc (256, GFP_KERNEL);
if (!transfer_buffer) {
- err("visor_startup: kmalloc(%d) failed.", 256);
+ err(__FUNCTION__ " - kmalloc(%d) failed.", 256);
return -ENOMEM;
}
- dbg("visor_startup");
+ dbg(__FUNCTION__);
- dbg("visor_setup: Set config to 1");
+ dbg(__FUNCTION__ " - Set config to 1");
usb_set_configuration (serial->dev, 1);
/* send a get connection info request */
response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION,
0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
if (response < 0) {
- err("visor_startup: error getting connection information");
+ err(__FUNCTION__ " - error getting connection information");
} else {
struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
char *string;
@@ -195,7 +198,7 @@ static int visor_startup (struct usb_serial *serial)
response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE,
0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
if (response < 0) {
- err("visor_startup: error getting bytes available request");
+ err(__FUNCTION__ " - error getting bytes available request");
}
kfree (transfer_buffer);
diff --git a/drivers/usb/usb-storage.c b/drivers/usb/usb-storage.c
index b9cead4fe..6d88d360b 100644
--- a/drivers/usb/usb-storage.c
+++ b/drivers/usb/usb-storage.c
@@ -1,11 +1,16 @@
/* Driver for USB Mass Storage compliant devices
*
- * Initial work by:
- * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ * $Id: usb-storage.c,v 1.11 2000/06/20 03:19:31 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
+ * Developed with the assistance of:
+ * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *
+ * Initial work by:
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
* This driver is based on the 'USB Mass Storage Class' document. This
* describes in detail the protocol used to communicate with such
* devices. Clearly, the designers had SCSI and ATAPI commands in
@@ -22,6 +27,20 @@
*
* Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
* information about this driver.
+ *
+ * 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, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
@@ -88,6 +107,7 @@ struct us_data {
char *protocol_name;
u8 subclass;
u8 protocol;
+ u8 max_lun;
/* information about the device -- only good if device is attached */
u8 ifnum; /* interface number */
@@ -536,8 +556,9 @@ static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
/* save the old command */
memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
+ /* set the command and the LUN */
srb->cmnd[0] = REQUEST_SENSE;
- srb->cmnd[1] = 0;
+ srb->cmnd[1] = old_cmnd[1] & 0xE0;
srb->cmnd[2] = 0;
srb->cmnd[3] = 0;
srb->cmnd[4] = 18;
@@ -791,7 +812,7 @@ static int Bulk_max_lun(struct us_data *us)
result, data);
/* if we have a successful request, return the result */
- if (!result)
+ if (result == 1)
return data;
/* if we get a STALL, clear the stall */
@@ -839,6 +860,9 @@ static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
usb_clear_halt(us->pusb_dev, pipe);
+ } else if (result) {
+ /* unknown error -- we've got a problem */
+ return USB_STOR_TRANSPORT_ERROR;
}
/* if the command transfered well, then we go to the data stage */
@@ -976,25 +1000,17 @@ static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
srb->cmnd[0] = srb->cmnd[0] | 0x20;
break;
} /* end switch on cmnd[0] */
+
+ /* convert MODE_SELECT data here */
+ if (old_cmnd == MODE_SELECT)
+ usb_stor_scsiSense6to10(srb);
/* send the command to the transport layer */
invoke_transport(srb, us);
- /* Fix the MODE_SENSE data if we translated the command
- */
- if (old_cmnd == MODE_SENSE) {
- unsigned char *dta = (unsigned char *)us->srb->request_buffer;
-
- /* FIXME: we need to compress the entire data structure here
- */
- dta[0] = dta[1]; /* data len */
- dta[1] = dta[2]; /* med type */
- dta[2] = dta[3]; /* dev-spec prm */
- dta[3] = dta[7]; /* block desc len */
- printk (KERN_DEBUG USB_STORAGE
- "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
- dta[0], dta[1], dta[2], dta[3]);
- }
+ /* Fix the MODE_SENSE data if we translated the command */
+ if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD))
+ usb_stor_scsiSense10to6(srb);
/* Fix-up the return data from an INQUIRY command to show
* ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
@@ -1084,24 +1100,16 @@ static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
break;
} /* end switch on cmnd[0] */
+ /* convert MODE_SELECT data here */
+ if (old_cmnd == MODE_SELECT)
+ usb_stor_scsiSense6to10(srb);
+
/* send the command to the transport layer */
invoke_transport(srb, us);
- /* Fix the MODE_SENSE data here if we had to translate the command
- */
- if (old_cmnd == MODE_SENSE) {
- unsigned char *dta = (unsigned char *)us->srb->request_buffer;
-
- /* FIXME: we need to compress the entire data structure here
- */
- dta[0] = dta[1]; /* data len */
- dta[1] = dta[2]; /* med type */
- dta[2] = dta[3]; /* dev-spec prm */
- dta[3] = dta[7]; /* block desc len */
- printk (KERN_DEBUG USB_STORAGE
- "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
- dta[0], dta[1], dta[2], dta[3]);
- }
+ /* Fix the MODE_SENSE data if we translated the command */
+ if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD))
+ usb_stor_scsiSense10to6(srb);
/* Fix-up the return data from an INQUIRY command to show
* ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
@@ -1310,9 +1318,8 @@ static int us_release(struct Scsi_Host *psh)
down(&(us->notify));
/* free the data structure we were using */
- US_DEBUGP("-- freeing private host data structure\n");
+ US_DEBUGP("-- freeing URB\n");
kfree(us->current_urb);
- kfree(us);
(struct us_data*)psh->hostdata[0] = NULL;
/* we always have a successful release */
@@ -1536,11 +1543,10 @@ static int usb_stor_control_thread(void * __us)
switch (action) {
case US_ACT_COMMAND:
- /* reject if target != 0 or if single-lun device
- * and LUN != 0
+ /* reject if target != 0 or if LUN is higher than
+ * the maximum known LUN
*/
- if (us->srb->target ||
- ((us->flags & US_FL_SINGLE_LUN) && us->srb->lun)) {
+ if (us->srb->target || (us->srb->lun > us->max_lun)) {
US_DEBUGP("Bad device number (%d/%d)\n",
us->srb->target, us->srb->lun);
@@ -1623,32 +1629,37 @@ static int usb_stor_control_thread(void * __us)
/* This is the list of devices we recognize, along with their flag data */
static struct us_unusual_dev us_unusual_dev_list[] = {
- { 0x03f0, 0x0107, 0x0200,
- "HP USB CD-Writer Plus", US_SC_8070, US_PR_CB, 0},
- { 0x04e6, 0x0001, 0x0200,
- "Matshita LS-120", US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN},
- { 0x04e6, 0x0002, 0x0100,
- "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x04e6, 0x0006, 0x0100,
- "Shuttle eUSB MMC Adapter", US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN},
- { 0x057b, 0x0000, 0x0114,
- "Y-E Data Flashbuster-U", US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN},
- { 0x059b, 0x0030, 0x0100,
- "Iomega Zip 250", US_SC_SCSI, US_PR_BULK, US_FL_SINGLE_LUN},
- { 0x0693, 0x0002, 0x0100,
- "Hagiwara FlashGate SmartMedia", US_SC_SCSI, US_PR_BULK,
- US_FL_ALT_LENGTH},
- { 0x0781, 0x0001, 0x0200,
- "Sandisk ImageMate (SDDR-01)", US_SC_SCSI, US_PR_CB,
- US_FL_SINGLE_LUN | US_FL_START_STOP},
- { 0x0781, 0x0002, 0x0009,
- "Sandisk Imagemate (SDDR-31)", US_SC_SCSI, US_PR_BULK,
- US_FL_SINGLE_LUN | US_FL_IGNORE_SER},
- { 0x07af, 0x0005, 0x0100,
- "Microtech USB-SCSI-HD50", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x0000, 0x0000, 0x0,
- "", 0, 0, 0}
-};
+ { 0x03f0, 0x0107, 0x0200, 0x0200, "HP USB CD-Writer Plus",
+ US_SC_8070, US_PR_CB, 0},
+ { 0x04e6, 0x0001, 0x0200, 0x0200, "Matshita LS-120",
+ US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN},
+ { 0x04e6, 0x0002, 0x0100, 0x0100, "Shuttle eUSCSI Bridge",
+ US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x04e6, 0x0006, 0x0100, 0x0100, "Shuttle eUSB MMC Adapter",
+ US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN},
+ { 0x054c, 0x0010, 0x0210, 0x0210, "Sony DSC-S30",
+ US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP |
+ US_FL_MODE_XLATE | US_FL_ALT_LENGTH},
+ { 0x054c, 0x002d, 0x0100, 0x0100, "Sony Memorystick MSAC-US1",
+ US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP |
+ US_FL_MODE_XLATE | US_FL_ALT_LENGTH},
+ { 0x057b, 0x0000, 0x0000, 0x0299, "Y-E Data Flashbuster-U",
+ US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN},
+ { 0x057b, 0x0000, 0x0300, 0x9999, "Y-E Data Flashbuster-U",
+ US_SC_UFI, US_PR_CBI, US_FL_SINGLE_LUN},
+ { 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara FlashGate SmartMedia",
+ US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk ImageMate (SDDR-01)",
+ US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP},
+ { 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk Imagemate (SDDR-31)",
+ US_SC_SCSI, US_PR_BULK, US_FL_IGNORE_SER},
+ { 0x07af, 0x0005, 0x0100, 0x0100, "Microtech USB-SCSI-HD50",
+ US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x05ab, 0x0031, 0x0100, 0x0100, "In-System USB/IDE Bridge",
+ US_SC_8070, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x0693, 0x0005, 0x0100, 0x0100, "Hagiwara Flashgate",
+ US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0 }};
/* Search our ususual device list, based on vendor/product combinations
* to see if we can support this device. Returns a pointer to a structure
@@ -1667,7 +1678,8 @@ static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct,
while ((ptr->idVendor != 0x0000) &&
!((ptr->idVendor == idVendor) &&
(ptr->idProduct == idProduct) &&
- (ptr->bcdDevice == bcdDevice)))
+ (ptr->bcdDeviceMin <= bcdDevice) &&
+ (ptr->bcdDeviceMax >= bcdDevice)))
ptr++;
/* if the search ended because we hit the end record, we failed */
@@ -1968,20 +1980,21 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
ss->transport_name = "Control/Bulk";
ss->transport = CB_transport;
ss->transport_reset = CB_reset;
+ ss->max_lun = 7;
break;
case US_PR_CBI:
ss->transport_name = "Control/Bulk/Interrupt";
ss->transport = CBI_transport;
ss->transport_reset = CB_reset;
+ ss->max_lun = 7;
break;
case US_PR_BULK:
ss->transport_name = "Bulk";
ss->transport = Bulk_transport;
ss->transport_reset = Bulk_reset;
- /* FIXME: for testing purposes only */
- Bulk_max_lun(ss);
+ ss->max_lun = Bulk_max_lun(ss);
break;
default:
@@ -1994,6 +2007,10 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
}
US_DEBUGP("Transport: %s\n", ss->transport_name);
+ /* fix for single-lun devices */
+ if (ss->flags & US_FL_SINGLE_LUN)
+ ss->max_lun = 0;
+
switch (ss->subclass) {
case US_SC_RBC:
ss->protocol_name = "Reduced Block Commands (RBC)";
@@ -2134,6 +2151,576 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
up(&(ss->dev_semaphore));
}
+/**************************************************************
+ **************************************************************/
+
+#define USB_STOR_SCSI_SENSE_HDRSZ 4
+#define USB_STOR_SCSI_SENSE_10_HDRSZ 8
+
+struct usb_stor_scsi_sense_hdr
+{
+ __u8* dataLength;
+ __u8* mediumType;
+ __u8* devSpecParms;
+ __u8* blkDescLength;
+};
+
+typedef struct usb_stor_scsi_sense_hdr Usb_Stor_Scsi_Sense_Hdr;
+
+union usb_stor_scsi_sense_hdr_u
+{
+ Usb_Stor_Scsi_Sense_Hdr hdr;
+ __u8* array[USB_STOR_SCSI_SENSE_HDRSZ];
+};
+
+typedef union usb_stor_scsi_sense_hdr_u Usb_Stor_Scsi_Sense_Hdr_u;
+
+struct usb_stor_scsi_sense_hdr_10
+{
+ __u8* dataLengthMSB;
+ __u8* dataLengthLSB;
+ __u8* mediumType;
+ __u8* devSpecParms;
+ __u8* reserved1;
+ __u8* reserved2;
+ __u8* blkDescLengthMSB;
+ __u8* blkDescLengthLSB;
+};
+
+typedef struct usb_stor_scsi_sense_hdr_10 Usb_Stor_Scsi_Sense_Hdr_10;
+
+union usb_stor_scsi_sense_hdr_10_u
+{
+ Usb_Stor_Scsi_Sense_Hdr_10 hdr;
+ __u8* array[USB_STOR_SCSI_SENSE_10_HDRSZ];
+};
+
+typedef union usb_stor_scsi_sense_hdr_10_u Usb_Stor_Scsi_Sense_Hdr_10_u;
+
+void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* , Usb_Stor_Scsi_Sense_Hdr_u*,
+ Usb_Stor_Scsi_Sense_Hdr_10_u*, int* );
+void usb_stor_print_Scsi_Cmnd( Scsi_Cmnd* cmd );
+
+int
+usb_stor_scsiSense10to6( Scsi_Cmnd* the10 )
+{
+ __u8 *buffer=0;
+ int outputBufferSize = 0;
+ int length=0;
+ struct scatterlist *sg = 0;
+ int i=0, j=0, element=0;
+ Usb_Stor_Scsi_Sense_Hdr_u the6Locations;
+ Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations;
+ int sb=0,si=0,db=0,di=0;
+ int sgLength=0;
+
+#if 0
+ /* Make sure we get a MODE_SENSE_10 command */
+ if ( the10->cmnd[0] != MODE_SENSE_10 )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Scsi_Cmnd was not a MODE_SENSE_10.\n" );
+ return -1;
+ }
+
+ /* Now start to format the output */
+ the10->cmnd[0] = MODE_SENSE;
+#endif
+ US_DEBUGP("-- converting 10 byte sense data to 6 byte\n");
+ the10->cmnd[0] = the10->cmnd[0] & 0xBF;
+
+ /* Determine buffer locations */
+ usb_stor_scsiSenseParseBuffer( the10, &the6Locations, &the10Locations,
+ &length );
+
+ /* Work out minimum buffer to output */
+ outputBufferSize = *the10Locations.hdr.dataLengthLSB;
+ outputBufferSize += USB_STOR_SCSI_SENSE_HDRSZ;
+
+ /* Check to see if we need to truncate the output */
+ if ( outputBufferSize > length )
+ {
+ printk( KERN_WARNING USB_STORAGE
+ "Had to truncate MODE_SENSE_10 buffer into MODE_SENSE.\n" );
+ printk( KERN_WARNING USB_STORAGE
+ "outputBufferSize is %d and length is %d.\n",
+ outputBufferSize, length );
+ }
+ outputBufferSize = length;
+
+ /* Data length */
+ if ( *the10Locations.hdr.dataLengthMSB != 0 ) /* MSB must be zero */
+ {
+ printk( KERN_WARNING USB_STORAGE
+ "Command will be truncated to fit in SENSE6 buffer.\n" );
+ *the6Locations.hdr.dataLength = 0xff;
+ }
+ else
+ {
+ *the6Locations.hdr.dataLength = *the10Locations.hdr.dataLengthLSB;
+ }
+
+ /* Medium type and DevSpecific parms */
+ *the6Locations.hdr.mediumType = *the10Locations.hdr.mediumType;
+ *the6Locations.hdr.devSpecParms = *the10Locations.hdr.devSpecParms;
+
+ /* Block descriptor length */
+ if ( *the10Locations.hdr.blkDescLengthMSB != 0 ) /* MSB must be zero */
+ {
+ printk( KERN_WARNING USB_STORAGE
+ "Command will be truncated to fit in SENSE6 buffer.\n" );
+ *the6Locations.hdr.blkDescLength = 0xff;
+ }
+ else
+ {
+ *the6Locations.hdr.blkDescLength = *the10Locations.hdr.blkDescLengthLSB;
+ }
+
+ if ( the10->use_sg == 0 )
+ {
+ buffer = the10->request_buffer;
+ /* Copy the rest of the data */
+ memmove( &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]),
+ &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
+ outputBufferSize - USB_STOR_SCSI_SENSE_HDRSZ );
+ /* initialise last bytes left in buffer due to smaller header */
+ memset( &(buffer[outputBufferSize
+ -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ)]),
+ 0,
+ USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ );
+ }
+ else
+ {
+ sg = (struct scatterlist *) the10->request_buffer;
+ /* scan through this scatterlist and figure out starting positions */
+ for ( i=0; i < the10->use_sg; i++)
+ {
+ sgLength = sg[i].length;
+ for ( j=0; j<sgLength; j++ )
+ {
+ /* get to end of header */
+ if ( element == USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ db=i;
+ di=j;
+ }
+ if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ sb=i;
+ si=j;
+ /* we've found both sets now, exit loops */
+ j=sgLength;
+ i=the10->use_sg;
+ }
+ element++;
+ }
+ }
+
+ /* Now we know where to start the copy from */
+ element = USB_STOR_SCSI_SENSE_HDRSZ;
+ while ( element < outputBufferSize
+ -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) )
+ {
+ /* check limits */
+ if ( sb >= the10->use_sg ||
+ si >= sg[sb].length ||
+ db >= the10->use_sg ||
+ di >= sg[db].length )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Buffer overrun averted, this shouldn't happen!\n" );
+ break;
+ }
+
+ /* copy one byte */
+ sg[db].address[di] = sg[sb].address[si];
+
+ /* get next destination */
+ if ( sg[db].length-1 == di )
+ {
+ db++;
+ di=0;
+ }
+ else
+ {
+ di++;
+ }
+
+ /* get next source */
+ if ( sg[sb].length-1 == si )
+ {
+ sb++;
+ si=0;
+ }
+ else
+ {
+ si++;
+ }
+
+ element++;
+ }
+ /* zero the remaining bytes */
+ while ( element < outputBufferSize )
+ {
+ /* check limits */
+ if ( db >= the10->use_sg ||
+ di >= sg[db].length )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Buffer overrun averted, this shouldn't happen!\n" );
+ break;
+ }
+
+ sg[db].address[di] = 0;
+
+ /* get next destination */
+ if ( sg[db].length-1 == di )
+ {
+ db++;
+ di=0;
+ }
+ else
+ {
+ di++;
+ }
+ element++;
+ }
+ }
+
+ /* All done any everything was fine */
+ return 0;
+}
+
+int
+usb_stor_scsiSense6to10( Scsi_Cmnd* the6 )
+{
+ /* will be used to store part of buffer */
+ __u8 tempBuffer[USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ],
+ *buffer=0;
+ int outputBufferSize = 0;
+ int length=0;
+ struct scatterlist *sg = 0;
+ int i=0, j=0, element=0;
+ Usb_Stor_Scsi_Sense_Hdr_u the6Locations;
+ Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations;
+ int sb=0,si=0,db=0,di=0;
+ int lsb=0,lsi=0,ldb=0,ldi=0;
+
+#if 0
+ /* Make sure we get a MODE_SENSE command */
+ if ( the6->cmnd[0] != MODE_SENSE )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Scsi_Cmnd was not MODE_SENSE.\n" );
+ return -1;
+ }
+
+ /* Now start to format the output */
+ the6->cmnd[0] = MODE_SENSE_10;
+#endif
+ US_DEBUGP("-- converting 6 byte sense data to 10 byte\n");
+ the6->cmnd[0] = the6->cmnd[0] | 0x40;
+
+ /* Determine buffer locations */
+ usb_stor_scsiSenseParseBuffer( the6, &the6Locations, &the10Locations,
+ &length );
+
+ /* Work out minimum buffer to output */
+ outputBufferSize = *the6Locations.hdr.dataLength;
+ outputBufferSize += USB_STOR_SCSI_SENSE_10_HDRSZ;
+
+ /* Check to see if we need to trucate the output */
+ if ( outputBufferSize > length )
+ {
+ printk( KERN_WARNING USB_STORAGE
+ "Had to truncate MODE_SENSE into MODE_SENSE_10 buffer.\n" );
+ printk( KERN_WARNING USB_STORAGE
+ "outputBufferSize is %d and length is %d.\n",
+ outputBufferSize, length );
+ }
+ outputBufferSize = length;
+
+ /* Block descriptor length - save these before overwriting */
+ tempBuffer[2] = *the10Locations.hdr.blkDescLengthMSB;
+ tempBuffer[3] = *the10Locations.hdr.blkDescLengthLSB;
+ *the10Locations.hdr.blkDescLengthLSB = *the6Locations.hdr.blkDescLength;
+ *the10Locations.hdr.blkDescLengthMSB = 0;
+
+ /* reserved - save these before overwriting */
+ tempBuffer[0] = *the10Locations.hdr.reserved1;
+ tempBuffer[1] = *the10Locations.hdr.reserved2;
+ *the10Locations.hdr.reserved1 = *the10Locations.hdr.reserved2 = 0;
+
+ /* Medium type and DevSpecific parms */
+ *the10Locations.hdr.devSpecParms = *the6Locations.hdr.devSpecParms;
+ *the10Locations.hdr.mediumType = *the6Locations.hdr.mediumType;
+
+ /* Data length */
+ *the10Locations.hdr.dataLengthLSB = *the6Locations.hdr.dataLength;
+ *the10Locations.hdr.dataLengthMSB = 0;
+
+ if ( !the6->use_sg )
+ {
+ buffer = the6->request_buffer;
+ /* Copy the rest of the data */
+ memmove( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
+ &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]),
+ outputBufferSize-USB_STOR_SCSI_SENSE_10_HDRSZ );
+ /* Put the first four bytes (after header) in place */
+ memcpy( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
+ tempBuffer,
+ USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ );
+ }
+ else
+ {
+ sg = (struct scatterlist *) the6->request_buffer;
+ /* scan through this scatterlist and figure out ending positions */
+ for ( i=0; i < the6->use_sg; i++)
+ {
+ for ( j=0; j<sg[i].length; j++ )
+ {
+ /* get to end of header */
+ if ( element == USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ ldb=i;
+ ldi=j;
+ }
+ if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ lsb=i;
+ lsi=j;
+ /* we've found both sets now, exit loops */
+ j=sg[i].length;
+ i=the6->use_sg;
+ break;
+ }
+ element++;
+ }
+ }
+ /* scan through this scatterlist and figure out starting positions */
+ element = length-1;
+ /* destination is the last element */
+ db=the6->use_sg-1;
+ di=sg[db].length-1;
+ for ( i=the6->use_sg-1; i >= 0; i--)
+ {
+ for ( j=sg[i].length-1; j>=0; j-- )
+ {
+ /* get to end of header and find source for copy */
+ if ( element == length - 1
+ - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) )
+ {
+ sb=i;
+ si=j;
+ /* we've found both sets now, exit loops */
+ j=-1;
+ i=-1;
+ }
+ element--;
+ }
+ }
+ /* Now we know where to start the copy from */
+ element = length-1
+ - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ);
+ while ( element >= USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ /* check limits */
+ if ( ( sb <= lsb && si < lsi ) ||
+ ( db <= ldb && di < ldi ) )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Buffer overrun averted, this shouldn't happen!\n" );
+ break;
+ }
+
+ /* copy one byte */
+ sg[db].address[di] = sg[sb].address[si];
+
+ /* get next destination */
+ if ( di == 0 )
+ {
+ db--;
+ di=sg[db].length-1;
+ }
+ else
+ {
+ di--;
+ }
+
+ /* get next source */
+ if ( si == 0 )
+ {
+ sb--;
+ si=sg[sb].length-1;
+ }
+ else
+ {
+ si--;
+ }
+
+ element--;
+ }
+ /* copy the remaining four bytes */
+ while ( element >= USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ /* check limits */
+ if ( db <= ldb && di < ldi )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Buffer overrun averted, this shouldn't happen!\n" );
+ break;
+ }
+
+ sg[db].address[di] = tempBuffer[element-USB_STOR_SCSI_SENSE_HDRSZ];
+
+ /* get next destination */
+ if ( di == 0 )
+ {
+ db--;
+ di=sg[db].length-1;
+ }
+ else
+ {
+ di--;
+ }
+ element--;
+ }
+ }
+
+ /* All done and everything was fine */
+ return 0;
+}
+
+void
+usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* srb, Usb_Stor_Scsi_Sense_Hdr_u* the6,
+ Usb_Stor_Scsi_Sense_Hdr_10_u* the10,
+ int* length_p )
+
+{
+ int i = 0, j=0, element=0;
+ struct scatterlist *sg = 0;
+ int length = 0;
+ __u8* buffer=0;
+
+ /* are we scatter-gathering? */
+ if ( srb->use_sg != 0 )
+ {
+ /* loop over all the scatter gather structures and
+ * get pointer to the data members in the headers
+ * (also work out the length while we're here)
+ */
+ sg = (struct scatterlist *) srb->request_buffer;
+ for (i = 0; i < srb->use_sg; i++)
+ {
+ length += sg[i].length;
+ /* We only do the inner loop for the headers */
+ if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ /* scan through this scatterlist */
+ for ( j=0; j<sg[i].length; j++ )
+ {
+ if ( element < USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ /* fill in the pointers for both header types */
+ the6->array[element] = &(sg[i].address[j]);
+ the10->array[element] = &(sg[i].address[j]);
+ }
+ else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ /* only the longer headers still cares now */
+ the10->array[element] = &(sg[i].address[j]);
+ }
+ /* increase element counter */
+ element++;
+ }
+ }
+ }
+ }
+ else
+ {
+ length = srb->request_bufflen;
+ buffer = srb->request_buffer;
+ if ( length < USB_STOR_SCSI_SENSE_10_HDRSZ )
+ printk( KERN_ERR USB_STORAGE
+ "Buffer length smaller than header!!" );
+ for( i=0; i<USB_STOR_SCSI_SENSE_10_HDRSZ; i++ )
+ {
+ if ( i < USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ the6->array[i] = &(buffer[i]);
+ the10->array[i] = &(buffer[i]);
+ }
+ else
+ {
+ the10->array[i] = &(buffer[i]);
+ }
+ }
+ }
+
+ /* Set value of length passed in */
+ *length_p = length;
+}
+
+void
+usb_stor_print_Scsi_Cmnd( Scsi_Cmnd* cmd )
+{
+ int i=0, bufferSize = cmd->request_bufflen;
+ __u8* buffer = cmd->request_buffer;
+ struct scatterlist* sg = (struct scatterlist*)cmd->request_buffer;
+
+ printk( KERN_ERR "Dumping information about %p.\n", cmd );
+ printk( KERN_ERR "cmd->cmnd[0] value is %d.\n", cmd->cmnd[0] );
+ printk( KERN_ERR "(MODE_SENSE is %d and MODE_SENSE_10 is %d)\n",
+ MODE_SENSE, MODE_SENSE_10 );
+
+ printk( KERN_ERR "buffer is %p with length %d.\n", buffer, bufferSize );
+ for ( i=0; i<bufferSize; i+=16 )
+ {
+ printk( KERN_ERR "%2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
+ buffer[i],
+ buffer[i+1],
+ buffer[i+2],
+ buffer[i+3],
+ buffer[i+4],
+ buffer[i+5],
+ buffer[i+6],
+ buffer[i+7],
+ buffer[i+8],
+ buffer[i+9],
+ buffer[i+10],
+ buffer[i+11],
+ buffer[i+12],
+ buffer[i+13],
+ buffer[i+14],
+ buffer[i+15] );
+ }
+
+ printk( KERN_ERR "Buffer has %d scatterlists.\n", cmd->use_sg );
+ for ( i=0; i<cmd->use_sg; i++ )
+ {
+ printk( KERN_ERR "Length of scatterlist %d is %d.\n", i, sg[i].length );
+ printk( KERN_ERR "%2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
+ sg[i].address[0],
+ sg[i].address[1],
+ sg[i].address[2],
+ sg[i].address[3],
+ sg[i].address[4],
+ sg[i].address[5],
+ sg[i].address[6],
+ sg[i].address[7],
+ sg[i].address[8],
+ sg[i].address[9],
+ sg[i].address[10],
+ sg[i].address[11],
+ sg[i].address[12],
+ sg[i].address[13],
+ sg[i].address[14],
+ sg[i].address[15] );
+ }
+}
+
+/**************************************************************
+ **************************************************************/
/***********************************************************************
* Initialization and registration
@@ -2183,6 +2770,11 @@ void __exit usb_stor_exit(void)
US_DEBUGP("-- calling scsi_unregister_module()\n");
scsi_unregister_module(MODULE_SCSI_HA, &(us_list->htmplt));
+ /* Now that scsi_unregister_module is done with the host
+ * template, we can free the us_data structure (the host
+ * template is inline in this structure). */
+ kfree (us_list);
+
/* advance the list pointer */
us_list = next;
}
diff --git a/drivers/usb/usb-storage.h b/drivers/usb/usb-storage.h
index 6e54b059b..82475f094 100644
--- a/drivers/usb/usb-storage.h
+++ b/drivers/usb/usb-storage.h
@@ -139,7 +139,8 @@ struct us_unusual_dev {
/* we search the list based on these parameters */
__u16 idVendor;
__u16 idProduct;
- __u16 bcdDevice;
+ __u16 bcdDeviceMin;
+ __u16 bcdDeviceMax;
/* the list specifies these parameters */
const char* name;
diff --git a/drivers/usb/wmforce.c b/drivers/usb/wmforce.c
deleted file mode 100644
index dff963b74..000000000
--- a/drivers/usb/wmforce.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * $Id: wmforce.c,v 1.6 2000/05/29 09:01:52 vojtech Exp $
- *
- * Copyright (c) 2000 Vojtech Pavlik
- *
- * USB Logitech WingMan Force joystick support
- *
- * Sponsored by SuSE
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-
-#define USB_VENDOR_ID_LOGITECH 0x046d
-#define USB_DEVICE_ID_LOGITECH_WMFORCE 0xc281
-
-struct wmforce {
- signed char data[8];
- struct input_dev dev;
- struct urb irq;
- int open;
-};
-
-static struct {
- __s32 x;
- __s32 y;
-} wmforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-static char *wmforce_name = "Logitech WingMan Force";
-
-static void wmforce_irq(struct urb *urb)
-{
- struct wmforce *wmforce = urb->context;
- unsigned char *data = wmforce->data;
- struct input_dev *dev = &wmforce->dev;
-
- if (urb->status) return;
-
- if (data[0] != 1) {
- if (data[0] != 2)
- warn("received unknown report #%d", data[0]);
- return;
- }
-
- input_report_abs(dev, ABS_X, (__s16) (((__s16)data[2] << 8) | data[1]));
- input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[4] << 8) | data[3]));
- input_report_abs(dev, ABS_THROTTLE, data[5]);
- input_report_abs(dev, ABS_HAT0X, wmforce_hat_to_axis[data[7] >> 4].x);
- input_report_abs(dev, ABS_HAT0Y, wmforce_hat_to_axis[data[7] >> 4].y);
-
- input_report_key(dev, BTN_TRIGGER, data[6] & 0x01);
- input_report_key(dev, BTN_TOP, data[6] & 0x02);
- input_report_key(dev, BTN_THUMB, data[6] & 0x04);
- input_report_key(dev, BTN_TOP2, data[6] & 0x08);
- input_report_key(dev, BTN_BASE, data[6] & 0x10);
- input_report_key(dev, BTN_BASE2, data[6] & 0x20);
- input_report_key(dev, BTN_BASE3, data[6] & 0x40);
- input_report_key(dev, BTN_BASE4, data[6] & 0x80);
- input_report_key(dev, BTN_BASE5, data[7] & 0x01);
-}
-
-static int wmforce_open(struct input_dev *dev)
-{
- struct wmforce *wmforce = dev->private;
-
- if (wmforce->open++)
- return 0;
-
- if (usb_submit_urb(&wmforce->irq))
- return -EIO;
-
- return 0;
-}
-
-static void wmforce_close(struct input_dev *dev)
-{
- struct wmforce *wmforce = dev->private;
-
- if (!--wmforce->open)
- usb_unlink_urb(&wmforce->irq);
-}
-
-static void *wmforce_probe(struct usb_device *dev, unsigned int ifnum)
-{
- struct usb_endpoint_descriptor *endpoint;
- struct wmforce *wmforce;
- int i;
-
- if (dev->descriptor.idVendor != USB_VENDOR_ID_LOGITECH ||
- dev->descriptor.idProduct != USB_DEVICE_ID_LOGITECH_WMFORCE)
- return NULL;
-
- endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
-
- if (!(wmforce = kmalloc(sizeof(struct wmforce), GFP_KERNEL))) return NULL;
- memset(wmforce, 0, sizeof(struct wmforce));
-
- wmforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- wmforce->dev.keybit[LONG(BTN_JOYSTICK)] = BIT(BTN_TRIGGER) | BIT(BTN_TOP) | BIT(BTN_THUMB) | BIT(BTN_TOP2) |
- BIT(BTN_BASE) | BIT(BTN_BASE2) | BIT(BTN_BASE3) | BIT(BTN_BASE4) | BIT(BTN_BASE5);
- wmforce->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y);
-
- for (i = ABS_X; i <= ABS_Y; i++) {
- wmforce->dev.absmax[i] = 1920;
- wmforce->dev.absmin[i] = -1920;
- wmforce->dev.absflat[i] = 128;
- }
-
- wmforce->dev.absmax[ABS_THROTTLE] = 255;
- wmforce->dev.absmin[ABS_THROTTLE] = 0;
-
- for (i = ABS_HAT0X; i <= ABS_HAT0Y; i++) {
- wmforce->dev.absmax[i] = 1;
- wmforce->dev.absmin[i] = -1;
- }
-
- wmforce->dev.private = wmforce;
- wmforce->dev.open = wmforce_open;
- wmforce->dev.close = wmforce_close;
-
- wmforce->dev.name = wmforce_name;
- wmforce->dev.idbus = BUS_USB;
- wmforce->dev.idvendor = dev->descriptor.idVendor;
- wmforce->dev.idproduct = dev->descriptor.idProduct;
- wmforce->dev.idversion = dev->descriptor.bcdDevice;
-
- FILL_INT_URB(&wmforce->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
- wmforce->data, 8, wmforce_irq, wmforce, endpoint->bInterval);
-
- input_register_device(&wmforce->dev);
-
- printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
- wmforce->dev.number, wmforce_name, dev->bus->busnum, dev->devnum, ifnum);
-
- return wmforce;
-}
-
-static void wmforce_disconnect(struct usb_device *dev, void *ptr)
-{
- struct wmforce *wmforce = ptr;
- usb_unlink_urb(&wmforce->irq);
- input_unregister_device(&wmforce->dev);
- kfree(wmforce);
-}
-
-static struct usb_driver wmforce_driver = {
- name: "wmforce",
- probe: wmforce_probe,
- disconnect: wmforce_disconnect,
-};
-
-static int __init wmforce_init(void)
-{
- usb_register(&wmforce_driver);
- return 0;
-}
-
-static void __exit wmforce_exit(void)
-{
- usb_deregister(&wmforce_driver);
-}
-
-module_init(wmforce_init);
-module_exit(wmforce_exit);
diff --git a/drivers/video/Config.in b/drivers/video/Config.in
index 83e5dace8..6529b53c5 100644
--- a/drivers/video/Config.in
+++ b/drivers/video/Config.in
@@ -120,6 +120,7 @@ if [ "$CONFIG_FB" = "y" ]; then
tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
tristate ' ATI Rage 128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128
bool ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
+ tristate ' SIS 630/540 display support (EXPERIMENTAL)' CONFIG_FB_SIS
fi
fi
if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index ee1248a23..864e30f0c 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -654,8 +654,8 @@ register_framebuffer(struct fb_info *fb_info)
}
sprintf (name_buf, "%d", i);
fb_info->devfs_handle =
- devfs_register (devfs_handle, name_buf, 0, DEVFS_FL_NONE,
- FB_MAJOR, i, S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ devfs_register (devfs_handle, name_buf, DEVFS_FL_DEFAULT,
+ FB_MAJOR, i, S_IFCHR | S_IRUGO | S_IWUGO,
&fb_fops, NULL);
return 0;
diff --git a/drivers/video/sisfb.c b/drivers/video/sisfb.c
index 7b83f69c4..d42448fbf 100644
--- a/drivers/video/sisfb.c
+++ b/drivers/video/sisfb.c
@@ -43,9 +43,10 @@
#define FALSE 0
#define TRUE 1
-/* Draw Function */
+/* Draw Function
#define FBIOGET_GLYPH 0x4620
#define FBIOGET_HWCINFO 0x4621
+*/
#define BR(x) (0x8200 | (x) << 2)
#define BITBLT 0x00000000
@@ -115,7 +116,8 @@
#define MMIO_SIZE 0x20000 /* 128K MMIO capability */
#define MAX_ROM_SCAN 0x10000
-#define RESERVED_MEM_SIZE 0x400000 /* 4M */
+#define RESERVED_MEM_SIZE_4M 0x400000 /* 4M */
+#define RESERVED_MEM_SIZE_8M 0x800000 /* 8M */
/* Mode set stuff */
#define DEFAULT_MODE 0
@@ -173,9 +175,9 @@ static struct board {
const char *name;
} dev_list[] = {
{
- PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS_300, "SIS 300"}, {
- PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS_540, "SIS 540"}, {
- PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS_630, "SIS 630"}, {
+ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, {
+ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540, "SIS 540"}, {
+ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, "SIS 630"}, {
0, 0, NULL}
};
@@ -1020,8 +1022,11 @@ static int sisfb_heap_init(void)
struct OH *poh;
u8 jTemp, tq_state;
- heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE;
- //heap_start = (unsigned long)ivideo.video_vbase + (video_size - RESERVED_MEM_SIZE);
+ if(ivideo.video_size > 0x800000) /* video ram is large than 8M */
+ heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_8M;
+ else
+ heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_4M;
+
heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
heap_size = heap_end - heap_start;
@@ -1398,6 +1403,7 @@ static u32 get_reg3(u16 port)
static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo)
{
+#if 0
unsigned char ModeID;
u16 modeidlength;
u16 usModeIDOffset;
@@ -1411,6 +1417,8 @@ static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo)
ModeID = *((unsigned char *) (ROMAddr + usModeIDOffset));
}
return (modeidlength);
+#endif
+ return(10);
}
static int search_modeID(unsigned long ROMAddr, u16 ModeNo)
@@ -2467,7 +2475,11 @@ static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
strcpy(fix->id, fb_info.modename);
fix->smem_start = ivideo.video_base;
- fix->smem_len = RESERVED_MEM_SIZE; /* reserved for Xserver */
+ if(ivideo.video_size > 0x800000)
+ fix->smem_len = RESERVED_MEM_SIZE_8M; /* reserved for Xserver */
+ else
+ fix->smem_len = RESERVED_MEM_SIZE_4M; /* reserved for Xserver */
+
fix->type = video_type;
fix->type_aux = 0;
if (ivideo.video_bpp == 8)