--- comedi/drivers/ni_660x.c	2002-12-13 20:53:22.000000000 -0500
+++ comedi/drivers/ni_660x.c.new	2002-11-08 13:03:35.000000000 -0500
@@ -0,0 +1,335 @@
+/*
+    comedi/drivers/ni_660x.c
+    Hardware driver for NI 660x devices
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+   Driver: ni_660x.o
+   Description: National Instruments 660x
+   Author: J.P. Mellor <jpmellor@rose-hulman.edu>
+   Updated: 
+   Devices: [National Instruments] PCI-6601 (ni_660x), PCI-6602
+   Status: unknown
+
+   Commands are not supported.
+*/
+
+/* Things to do:
+
+   Add General-Purpose Counter/Timer as a subdevice
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/errno.h> 
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include <linux/comedidev.h>
+#include "mite.h"
+
+#define PCI_VENDOR_ID_NATINST	0x1093
+
+#define DATA_1B 0x1
+#define DATA_2B 0x2
+#define DATA_4B 0x4
+
+/* Board description*/
+
+typedef struct ni_660x_board_struct
+{
+	unsigned short dev_id;
+	char *name;
+}ni_660x_board;
+
+static ni_660x_board ni_660x_boards[] = 
+{
+	{
+	dev_id		: 0x2c60,
+	name		: "PCI-6601",
+	},
+	{
+	dev_id		: 0x0,			/* ????? */
+	name		: "PCI-6602",
+	},
+};
+
+static struct pci_device_id ni_660x_pci_table[] __devinitdata = {
+	{ PCI_VENDOR_ID_NATINST, 0x2c60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	//{ PCI_VENDOR_ID_NATINST, 0x0000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, ni_660x_pci_table);
+
+#define thisboard ((ni_660x_board *)dev->board_ptr)
+
+typedef struct
+{
+	struct mite_struct *mite;
+	int boardtype;
+}ni_660x_private;
+
+#define devpriv ((ni_660x_private *)dev->private)
+#define n_ni_660x_boards (sizeof(ni_660x_boards)/sizeof(ni_660x_boards[0]))
+
+static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it);
+static int ni_660x_detach(comedi_device *dev);
+
+static comedi_driver driver_ni_660x=
+{
+	driver_name:	"ni_660x",
+	module:		THIS_MODULE,
+	attach:		ni_660x_attach,
+	detach:		ni_660x_detach,
+};
+
+COMEDI_INITCLEANUP(driver_ni_660x);
+
+static int ni_660x_find_device(comedi_device *dev,int bus,int slot);
+
+static int ni_660x_tio_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
+static int ni_660x_tio_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
+static int ni_660x_tio_insn_bits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
+static int ni_660x_tio_insn_config(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
+
+
+static int ni_660x_attach(comedi_device *dev,comedi_devconfig *it)
+{
+  comedi_subdevice *s;
+  int ret;
+
+  printk("comedi%d: ni_660x: ",dev->minor);
+
+  if ((ret=alloc_private(dev,sizeof(ni_660x_private))) < 0) return ret;
+
+  ret = ni_660x_find_device(dev, it->options[0], it->options[1]);
+  if (ret<0) return ret;
+
+  ret = mite_setup(devpriv->mite);
+  if (ret < 0) {
+    printk("error setting up mite\n");
+    return ret;
+  }
+  dev->iobase = mite_iobase(devpriv->mite);
+  dev->board_name = thisboard->name;
+  dev->irq = mite_irq(devpriv->mite);
+  printk(" %s ", dev->board_name);
+
+  dev->n_subdevices = 1;
+	
+  if (alloc_subdevices(dev)<0) return -ENOMEM;
+
+  s=dev->subdevices+0;
+  /* general-purpose counter/time ASIC */
+  s->type			=	COMEDI_SUBD_COUNTER;
+  s->subdev_flags		=	SDF_CMD|SDF_READABLE|SDF_WRITABLE;
+  s->n_chan			= 	8;
+  s->maxdata			=	1;
+  s->range_table		=	&range_digital;
+  s->insn_write 		= 	&ni_660x_tio_winsn;
+  s->insn_read	 		= 	&ni_660x_tio_rinsn;
+  s->insn_bits			= 	ni_660x_tio_insn_bits;
+  s->insn_config 		= 	ni_660x_tio_insn_config;
+
+  printk("attached\n");
+
+  return 1;
+}
+
+
+static int
+ni_660x_detach(comedi_device *dev)
+{
+  printk("comedi%d: ni_660x: remove\n",dev->minor);
+
+  if (dev->private && devpriv->mite)
+    mite_unsetup(devpriv->mite);
+
+  if(dev->irq)
+    comedi_free_irq(dev->irq,dev);
+
+  return 0;
+}
+
+static int
+ni_660x_tio_winsn(comedi_device *dev, comedi_subdevice *s,
+		  comedi_insn *insn, lsampl_t *data)
+{
+  int i=0;
+
+  switch (insn->chanspec) {
+
+  case DATA_1B:
+    for (i=0; i<insn->n; i+=2) {
+      writeb(data[i+1], dev->iobase+data[i]);
+    }
+    break;
+
+  case DATA_2B:
+    for (i=0; i<insn->n; i+=2) {
+      writew(data[i+1], dev->iobase+data[i]);
+    }
+    break;
+
+  case DATA_4B:
+    for (i=0; i<insn->n; i+=2) {
+      writel(data[i+1], dev->iobase+data[i]);
+    }
+    break;
+
+  default:
+    return insn->n;
+
+  }
+
+  return i;
+}
+
+static int
+ni_660x_tio_rinsn(comedi_device *dev, comedi_subdevice *s,
+		  comedi_insn *insn, lsampl_t *data)
+{
+  int i=0;
+
+  switch (insn->chanspec) {
+
+  case DATA_1B:
+    for (i=0; i<insn->n; i+=2) {
+      data[i+1] = readb(dev->iobase+data[i]);
+    }
+    break;
+
+  case DATA_2B:
+    for (i=0; i<insn->n; i+=2) {
+      data[i+1] = readw(dev->iobase+data[i]);
+    }
+    break;
+
+  case DATA_4B:
+    for (i=0; i<insn->n; i+=2) {
+      data[i+1] = readl(dev->iobase+data[i]);
+    }
+    break;
+
+  default:
+    return insn->n;
+
+  }
+
+  return i;
+}
+
+// this is being called as part of opening the device
+static int
+ni_660x_tio_insn_bits(comedi_device *dev, comedi_subdevice *s,
+		      comedi_insn *insn, lsampl_t *data)
+{
+  int i=0;
+
+  switch (insn->chanspec) {
+
+  case DATA_1B:
+    for (i=0; i<insn->n; i+=2) {
+      data[i+1] = readb(dev->iobase+data[i]);
+    }
+    break;
+
+  case DATA_2B:
+    for (i=0; i<insn->n; i+=2) {
+      data[i+1] = readw(dev->iobase+data[i]);
+    }
+    break;
+
+  case DATA_4B:
+    for (i=0; i<insn->n; i+=2) {
+      data[i+1] = readl(dev->iobase+data[i]);
+    }
+    break;
+
+  default:
+    return insn->n;
+
+  }
+
+  return i;
+}
+
+static int
+ni_660x_tio_insn_config(comedi_device *dev, comedi_subdevice *s, 
+			comedi_insn *insn, lsampl_t *data)
+{
+  int i=0;
+
+  switch (insn->chanspec) {
+
+  case DATA_1B:
+    for (i=0; i<insn->n; i+=2) {
+      writeb(data[i+1], dev->iobase+data[i]);
+    }
+    break;
+
+  case DATA_2B:
+    for (i=0; i<insn->n; i+=2) {
+      writew(data[i+1], dev->iobase+data[i]);
+    }
+    break;
+
+  case DATA_4B:
+    for (i=0; i<insn->n; i+=2) {
+      writel(data[i+1], dev->iobase+data[i]);
+    }
+    break;
+
+  default:
+    return insn->n;
+
+  }
+
+  return i;
+}
+
+static int
+ni_660x_find_device(comedi_device *dev, int bus, int slot)
+{
+  struct mite_struct *mite;
+  int i;
+
+  for (mite=mite_devices; mite; mite=mite->next) {
+    if (mite->used) continue;
+    if (bus || slot) {
+      if (bus!=mite->pcidev->bus->number ||
+	  slot!=PCI_SLOT(mite->pcidev->devfn)) continue;
+    }
+
+    for (i=0; i<n_ni_660x_boards; i++) {
+      if (mite_device_id(mite)==ni_660x_boards[i].dev_id) {
+	dev->board_ptr=ni_660x_boards+i;
+	devpriv->mite=mite;
+	return 0;
+      }
+    }
+  }
+  printk("no device found\n");
+  mite_list_devices();
+  return -EIO;
+}
--- comedi/drivers/Makefile.in	2002-10-23 12:20:20.000000000 -0500
+++ comedi/drivers/Makefile.in.new	2002-10-23 12:20:21.000000000 -0500
@@ -30,6 +30,7 @@
 select(CONFIG_COMEDI_MITE mite.o)
 select(CONFIG_COMEDI_MULTIQ3 multiq3.o)
 select(CONFIG_COMEDI_MPC8260CPM mpc8260cpm.o)
+select(CONFIG_COMEDI_NI_660X ni_660x.o)
 select(CONFIG_COMEDI_NI_670X ni_670x.o)
 select(CONFIG_COMEDI_NI_ATMIO ni_atmio.o)
 select(CONFIG_COMEDI_NI_MIO_CS ni_mio_cs.o)
--- comedi/comedi_fops.c	2002-12-13 20:55:30.000000000 -0500
+++ comedi/comedi_fops.c.new	2002-11-08 13:03:35.000000000 -0500
@@ -557,7 +557,7 @@
 		ret = parse_insn(dev,insns+i,data,file);
 		if(ret<0)goto error;
 		if(ret!=insns[i].n){
-			printk("BUG: result of insn != insn.n\n");
+			printk("BUG: result of insn (%d) != insn.n (%d)\n", ret, insns[i].n);
 			ret=-EINVAL;
 			goto error;
 		}
@@ -732,7 +732,7 @@
 
 	/* This is where the behavior of insn and insnlist deviate. */
 	if(insn.n>MAX_SAMPLES)insn.n=MAX_SAMPLES;
-	if(insn.insn&INSN_MASK_WRITE){
+	if((insn.insn&INSN_MASK_WRITE)||(insn.insn&INSN_MASK_READ)){
 		if(copy_from_user(data,insn.data,insn.n*sizeof(lsampl_t))){
 			ret=-EFAULT;
 			goto error;
--- comedi/Config.in	2002-10-23 12:20:20.000000000 -0500
+++ comedi/Config.in.new	2002-10-23 12:20:21.000000000 -0500
@@ -57,11 +57,12 @@
 	if [ "$CONFIG_PCI" = "y" ];then
 		dep_tristate '  PCI-MIO E series' CONFIG_COMEDI_NI_PCIMIO $CONFIG_COMEDI
 		dep_tristate '  NI PCI-DIO series' CONFIG_COMEDI_NI_PCIDIO $CONFIG_COMEDI
+		dep_tristate '  NI 660x series' CONFIG_COMEDI_NI_660X $CONFIG_COMEDI
 		dep_tristate '  NI 670x series' CONFIG_COMEDI_NI_670X $CONFIG_COMEDI
-		if [ "$CONFIG_COMEDI_NI_PCIMIO" = "y" -o "$CONFIG_COMEDI_NI_PCIDIO" = "y" -o "$CONFIG_COMEDI_NI_670X" = "y" ];then
+		if [ "$CONFIG_COMEDI_NI_PCIMIO" = "y" -o "$CONFIG_COMEDI_NI_PCIDIO" = "y" -o "$CONFIG_COMEDI_NI_660X" = "y" -o "$CONFIG_COMEDI_NI_670X" = "y" ];then
 			define_bool CONFIG_COMEDI_MITE y
 		else
-			if [ "$CONFIG_COMEDI_NI_PCIMIO" = "m" -o "$CONFIG_COMEDI_NI_PCIDIO" = "m" -o "$CONFIG_COMEDI_NI_670X" = "m" ];then
+			if [ "$CONFIG_COMEDI_NI_PCIMIO" = "m" -o "$CONFIG_COMEDI_NI_PCIDIO" = "m" -o "$CONFIG_COMEDI_NI_660X" = "m" -o "$CONFIG_COMEDI_NI_670X" = "m" ];then
 				define_bool CONFIG_COMEDI_MITE m
 			fi
 		fi
