-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Bart Joris
authored and
Greg Kroah-Hartman
committed
Apr 3, 2009
1 parent
80bb740
commit 208adcc
Showing
2 changed files
with
335 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 58dd7c0a2a6e76aab156aef625c7b53a6eaaace3 | ||
refs/heads/master: 3c5e17227eb9e94caebda842452c7596a8cb6d80 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,334 @@ | ||
/* | ||
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 <ds@schleef.org> | ||
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 | ||
Description: National Instruments 670x | ||
Author: Bart Joris <bjoris@advalvas.be> | ||
Updated: Wed, 11 Dec 2002 18:25:35 -0800 | ||
Devices: [National Instruments] PCI-6703 (ni_670x), PCI-6704 | ||
Status: unknown | ||
Commands are not supported. | ||
*/ | ||
|
||
/* | ||
Bart Joris <bjoris@advalvas.be> Last updated on 20/08/2001 | ||
Manuals: | ||
322110a.pdf PCI/PXI-6704 User Manual | ||
322110b.pdf PCI/PXI-6703/6704 User Manual | ||
*/ | ||
|
||
#include "../comedidev.h" | ||
|
||
#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; | ||
const char *name; | ||
unsigned short ao_chans; | ||
unsigned short ao_bits; | ||
} ni_670x_board; | ||
static const ni_670x_board ni_670x_boards[] = { | ||
{ | ||
dev_id: 0x2c90, | ||
name: "PCI-6703", | ||
ao_chans:16, | ||
ao_bits: 16, | ||
}, | ||
{ | ||
dev_id: 0x1920, | ||
name: "PXI-6704", | ||
ao_chans:32, | ||
ao_bits: 16, | ||
}, | ||
{ | ||
dev_id: 0x1290, | ||
name: "PCI-6704", | ||
ao_chans:32, | ||
ao_bits: 16, | ||
}, | ||
}; | ||
|
||
static DEFINE_PCI_DEVICE_TABLE(ni_670x_pci_table) = { | ||
{PCI_VENDOR_ID_NATINST, 0x2c90, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
{PCI_VENDOR_ID_NATINST, 0x1920, 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_PCI_INITCLEANUP(driver_ni_670x, ni_670x_pci_table); | ||
|
||
static comedi_lrange range_0_20mA = { 1, {RANGE_mA(0, 20)} }; | ||
|
||
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; | ||
int i; | ||
|
||
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->board_name = thisboard->name; | ||
dev->irq = mite_irq(devpriv->mite); | ||
printk(" %s", dev->board_name); | ||
|
||
if (alloc_subdevices(dev, 2) < 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; | ||
if (s->n_chan == 32) { | ||
const comedi_lrange **range_table_list; | ||
|
||
range_table_list = kmalloc(sizeof(comedi_lrange *) * 32, | ||
GFP_KERNEL); | ||
if (!range_table_list) | ||
return -ENOMEM; | ||
s->range_table_list = range_table_list; | ||
for (i = 0; i < 16; i++) { | ||
range_table_list[i] = &range_bipolar10; | ||
range_table_list[16 + i] = &range_0_20mA; | ||
} | ||
} else { | ||
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, devpriv->mite->daq_io_addr + MISC_CONTROL_OFFSET); /* Config of misc registers */ | ||
writel(0x00, devpriv->mite->daq_io_addr + 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->subdevices[0].range_table_list) { | ||
kfree(dev->subdevices[0].range_table_list); | ||
} | ||
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 */ | ||
|
||
for (i = 0; i < insn->n; i++) { | ||
writel(((chan & 15) << 1) | ((chan & 16) >> 4), devpriv->mite->daq_io_addr + AO_CHAN_OFFSET); /* First write in channel register which channel to use */ | ||
writel(data[i], devpriv->mite->daq_io_addr + 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; i < insn->n; 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, | ||
devpriv->mite->daq_io_addr + DIO_PORT0_DATA_OFFSET); | ||
} | ||
|
||
/* on return, data[1] contains the value of the digital | ||
* input lines. */ | ||
data[1] = readl(devpriv->mite->daq_io_addr + 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); | ||
|
||
switch (data[0]) { | ||
case INSN_CONFIG_DIO_OUTPUT: | ||
s->io_bits |= 1 << chan; | ||
break; | ||
case INSN_CONFIG_DIO_INPUT: | ||
s->io_bits &= ~(1 << chan); | ||
break; | ||
case INSN_CONFIG_DIO_QUERY: | ||
data[1] = | ||
(s-> | ||
io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; | ||
return insn->n; | ||
break; | ||
default: | ||
return -EINVAL; | ||
break; | ||
} | ||
writel(s->io_bits, devpriv->mite->daq_io_addr + DIO_PORT0_DIR_OFFSET); | ||
|
||
return insn->n; | ||
} | ||
|
||
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; i < n_ni_670x_boards; i++) { | ||
if (mite_device_id(mite) == ni_670x_boards[i].dev_id) { | ||
dev->board_ptr = ni_670x_boards + i; | ||
devpriv->mite = mite; | ||
|
||
return 0; | ||
} | ||
} | ||
} | ||
printk("no device found\n"); | ||
mite_list_devices(); | ||
return -EIO; | ||
} |