/* comedi/drivers/ni_670x.c Hardware driver for NI 670x devices COMEDI - Linux Control and Measurement Device Interface Copyright (C) 1997-2001 David A. Schleef 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_670x.o Description: National Instruments 670x Author: Bart Joris Updated: Wed, 22 Aug 2001 22:47:32 -0700 Devices: [National Instruments] PCI-6703 (ni_670x), PCI-6704 Status: unknown The driver currently does not recognize the 6704, because the PCI ID is not known. Commands are not supported. */ /* Bart Joris Last updated on 20/08/2001 */ #include #include "mite.h" #define PCI_VENDOR_ID_NATINST 0x1093 #define AO_VALUE_OFFSET 0x00 #define AO_CHAN_OFFSET 0x0c #define AO_STATUS_OFFSET 0x10 #define AO_CONTROL_OFFSET 0x10 #define DIO_PORT0_DIR_OFFSET 0x20 #define DIO_PORT0_DATA_OFFSET 0x24 #define DIO_PORT1_DIR_OFFSET 0x28 #define DIO_PORT1_DATA_OFFSET 0x2c #define MISC_STATUS_OFFSET 0x14 #define MISC_CONTROL_OFFSET 0x14 /* Board description*/ typedef struct ni_670x_board_struct { unsigned short dev_id; char *name; unsigned short ao_chans; unsigned short ao_bits; }ni_670x_board; static ni_670x_board ni_670x_boards[] = { { dev_id : 0x2c90, name : "PCI-6703", ao_chans : 16, ao_bits : 16, }, { dev_id : 0x0, /* ????? */ name : "PCI-6704", ao_chans : 32, ao_bits : 16, }, }; static struct pci_device_id ni_670x_pci_table[] __devinitdata = { { PCI_VENDOR_ID_NATINST, 0x2c90, 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_670x_pci_table); #define thisboard ((ni_670x_board *)dev->board_ptr) typedef struct { struct mite_struct *mite; int boardtype; int dio; lsampl_t ao_readback[32]; }ni_670x_private; #define devpriv ((ni_670x_private *)dev->private) #define n_ni_670x_boards (sizeof(ni_670x_boards)/sizeof(ni_670x_boards[0])) static int ni_670x_attach(comedi_device *dev,comedi_devconfig *it); static int ni_670x_detach(comedi_device *dev); static comedi_driver driver_ni_670x= { driver_name: "ni_670x", module: THIS_MODULE, attach: ni_670x_attach, detach: ni_670x_detach, }; COMEDI_INITCLEANUP(driver_ni_670x); static int ni_670x_find_device(comedi_device *dev,int bus,int slot); static int ni_670x_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data); static int ni_670x_ao_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data); static int ni_670x_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data); static int ni_670x_dio_insn_config(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data); static int ni_670x_attach(comedi_device *dev,comedi_devconfig *it) { comedi_subdevice *s; int ret; printk("comedi%d: ni_670x: ",dev->minor); if((ret=alloc_private(dev,sizeof(ni_670x_private)))<0) return ret; ret=ni_670x_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=2; if(alloc_subdevices(dev)<0) return -ENOMEM; s=dev->subdevices+0; /* analog output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; s->n_chan = thisboard->ao_chans; s->maxdata = 0xffff; s->range_table = &range_bipolar10; s->insn_write = &ni_670x_ao_winsn; s->insn_read = &ni_670x_ao_rinsn; s=dev->subdevices+1; /* digital i/o subdevice */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE|SDF_WRITABLE; s->n_chan = 8; s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = ni_670x_dio_insn_bits; s->insn_config = ni_670x_dio_insn_config; writel(0x10 ,dev->iobase + MISC_CONTROL_OFFSET); /* Config of misc registers */ writel(0x00 ,dev->iobase + AO_CONTROL_OFFSET); /* Config of ao registers */ printk("attached\n"); return 1; } static int ni_670x_detach(comedi_device *dev) { printk("comedi%d: ni_670x: 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_670x_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data) { int i; int chan = CR_CHAN(insn->chanspec); /* Channel number mapping : NI 6703/ NI 6704 | NI 6704 Only ---------------------------------------------------- vch(0) : 0 | ich(16) : 1 vch(1) : 2 | ich(17) : 3 . : . | . . . : . | . . . : . | . . vch(15) : 30 | ich(31) : 31 */ if (chan>15) chan = (chan-15)*2-1; else chan = chan*2; for(i=0;in;i++) { writel(chan,dev->iobase + AO_CHAN_OFFSET); /* First write in channel register which channel to use */ writel(data[i],dev->iobase + AO_VALUE_OFFSET); /* write channel value */ devpriv->ao_readback[chan] = data[i]; } return i; } static int ni_670x_ao_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data) { int i; int chan = CR_CHAN(insn->chanspec); for(i=0;in;i++) data[i] = devpriv->ao_readback[chan]; return i; } static int ni_670x_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data) { if(insn->n!=2)return -EINVAL; /* The insn data is a mask in data[0] and the new data * in data[1], each channel cooresponding to a bit. */ if(data[0]) { s->state &= ~data[0]; s->state |= data[0]&data[1]; writel(s->state,dev->iobase + DIO_PORT0_DATA_OFFSET); } /* on return, data[1] contains the value of the digital * input lines. */ data[1]=readl(dev->iobase + DIO_PORT0_DATA_OFFSET); return 2; } static int ni_670x_dio_insn_config(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data) { int chan=CR_CHAN(insn->chanspec); if(insn->n!=1) return -EINVAL; if(data[0]==COMEDI_OUTPUT) { s->io_bits |= 1<io_bits &= ~(1<io_bits,dev->iobase + DIO_PORT0_DIR_OFFSET); return 1; } static int ni_670x_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;iboard_ptr=ni_670x_boards+i; devpriv->mite=mite; return 0; } } } printk("no device found\n"); mite_list_devices(); return -EIO; }