Staging: comedi: add mite comedi pci driver

Hardware driver for NI Mite PCI interface chip

From: David Schleef <ds@schleef.org>
Cc: Frank Mori Hess <fmhess@users.sourceforge.net>
Cc: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
David Schleef 2008-11-14 14:43:55 -08:00 committed by Greg Kroah-Hartman
parent a9f23e00c1
commit bede729096
3 changed files with 1265 additions and 0 deletions

View File

@ -3,3 +3,6 @@
# Comedi "helper" modules # Comedi "helper" modules
obj-$(CONFIG_COMEDI) += comedi_fc.o obj-$(CONFIG_COMEDI) += comedi_fc.o
# Comedi PCI drivers
obj-$(CONFIG_COMEDI_PCI_DRIVERS) += mite.o

View File

@ -0,0 +1,809 @@
/*
comedi/drivers/mite.c
Hardware driver for NI Mite PCI interface chip
COMEDI - Linux Control and Measurement Device Interface
Copyright (C) 1997-2002 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.
*/
/*
The PCI-MIO E series driver was originally written by
Tomasz Motylewski <...>, and ported to comedi by ds.
References for specifications:
321747b.pdf Register Level Programmer Manual (obsolete)
321747c.pdf Register Level Programmer Manual (new)
DAQ-STC reference manual
Other possibly relevant info:
320517c.pdf User manual (obsolete)
320517f.pdf User manual (new)
320889a.pdf delete
320906c.pdf maximum signal ratings
321066a.pdf about 16x
321791a.pdf discontinuation of at-mio-16e-10 rev. c
321808a.pdf about at-mio-16e-10 rev P
321837a.pdf discontinuation of at-mio-16de-10 rev d
321838a.pdf about at-mio-16de-10 rev N
ISSUES:
*/
//#define USE_KMALLOC
#include "mite.h"
#include "comedi_fc.h"
#include "comedi_pci.h"
#include "../comedidev.h"
#include <asm/system.h>
#define PCI_MITE_SIZE 4096
#define PCI_DAQ_SIZE 4096
#define PCI_DAQ_SIZE_660X 8192
MODULE_LICENSE("GPL");
struct mite_struct *mite_devices = NULL;
#define TOP_OF_PAGE(x) ((x)|(~(PAGE_MASK)))
void mite_init(void)
{
struct pci_dev *pcidev;
struct mite_struct *mite;
for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
pcidev != NULL;
pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
if (pcidev->vendor == PCI_VENDOR_ID_NATINST) {
unsigned i;
mite = kzalloc(sizeof(*mite), GFP_KERNEL);
if (!mite) {
printk("mite: allocation failed\n");
pci_dev_put(pcidev);
return;
}
spin_lock_init(&mite->lock);
mite->pcidev = pci_dev_get(pcidev);
for (i = 0; i < MAX_MITE_DMA_CHANNELS; ++i) {
mite->channels[i].mite = mite;
mite->channels[i].channel = i;
mite->channels[i].done = 1;
}
mite->next = mite_devices;
mite_devices = mite;
}
}
}
static void dump_chip_signature(u32 csigr_bits)
{
printk("mite: version = %i, type = %i, mite mode = %i, interface mode = %i\n", mite_csigr_version(csigr_bits), mite_csigr_type(csigr_bits), mite_csigr_mmode(csigr_bits), mite_csigr_imode(csigr_bits));
printk("mite: num channels = %i, write post fifo depth = %i, wins = %i, iowins = %i\n", mite_csigr_dmac(csigr_bits), mite_csigr_wpdep(csigr_bits), mite_csigr_wins(csigr_bits), mite_csigr_iowins(csigr_bits));
}
unsigned mite_fifo_size(struct mite_struct * mite, unsigned channel)
{
unsigned fcr_bits = readl(mite->mite_io_addr +
MITE_FCR(channel));
unsigned empty_count = (fcr_bits >> 16) & 0xff;
unsigned full_count = fcr_bits & 0xff;
return empty_count + full_count;
}
int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1)
{
unsigned long length;
resource_size_t addr;
int i;
u32 csigr_bits;
unsigned unknown_dma_burst_bits;
if (comedi_pci_enable(mite->pcidev, "mite")) {
printk("error enabling mite and requesting io regions\n");
return -EIO;
}
pci_set_master(mite->pcidev);
addr = pci_resource_start(mite->pcidev, 0);
mite->mite_phys_addr = addr;
mite->mite_io_addr = ioremap(addr, PCI_MITE_SIZE);
if (!mite->mite_io_addr) {
printk("failed to remap mite io memory address\n");
return -ENOMEM;
}
printk("MITE:0x%08llx mapped to %p ",
(unsigned long long)mite->mite_phys_addr, mite->mite_io_addr);
addr = pci_resource_start(mite->pcidev, 1);
mite->daq_phys_addr = addr;
length = pci_resource_len(mite->pcidev, 1);
// In case of a 660x board, DAQ size is 8k instead of 4k (see as shown by lspci output)
mite->daq_io_addr = ioremap(mite->daq_phys_addr, length);
if (!mite->daq_io_addr) {
printk("failed to remap daq io memory address\n");
return -ENOMEM;
}
printk("DAQ:0x%08llx mapped to %p\n",
(unsigned long long)mite->daq_phys_addr, mite->daq_io_addr);
if (use_iodwbsr_1) {
writel(0, mite->mite_io_addr + MITE_IODWBSR);
printk("mite: using I/O Window Base Size register 1\n");
writel(mite->
daq_phys_addr | WENAB |
MITE_IODWBSR_1_WSIZE_bits(length),
mite->mite_io_addr + MITE_IODWBSR_1);
writel(0, mite->mite_io_addr + MITE_IODWCR_1);
} else {
writel(mite->daq_phys_addr | WENAB,
mite->mite_io_addr + MITE_IODWBSR);
}
/* make sure dma bursts work. I got this from running a bus analyzer
on a pxi-6281 and a pxi-6713. 6713 powered up with register value
of 0x61f and bursts worked. 6281 powered up with register value of
0x1f and bursts didn't work. The NI windows driver reads the register,
then does a bitwise-or of 0x600 with it and writes it back.
*/
unknown_dma_burst_bits =
readl(mite->mite_io_addr + MITE_UNKNOWN_DMA_BURST_REG);
unknown_dma_burst_bits |= UNKNOWN_DMA_BURST_ENABLE_BITS;
writel(unknown_dma_burst_bits,
mite->mite_io_addr + MITE_UNKNOWN_DMA_BURST_REG);
csigr_bits = readl(mite->mite_io_addr + MITE_CSIGR);
mite->num_channels = mite_csigr_dmac(csigr_bits);
if (mite->num_channels > MAX_MITE_DMA_CHANNELS) {
printk("mite: bug? chip claims to have %i dma channels. Setting to %i.\n", mite->num_channels, MAX_MITE_DMA_CHANNELS);
mite->num_channels = MAX_MITE_DMA_CHANNELS;
}
dump_chip_signature(csigr_bits);
for (i = 0; i < mite->num_channels; i++) {
writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR(i));
/* disable interrupts */
writel(CHCR_CLR_DMA_IE | CHCR_CLR_LINKP_IE | CHCR_CLR_SAR_IE |
CHCR_CLR_DONE_IE | CHCR_CLR_MRDY_IE | CHCR_CLR_DRDY_IE |
CHCR_CLR_LC_IE | CHCR_CLR_CONT_RB_IE,
mite->mite_io_addr + MITE_CHCR(i));
}
mite->fifo_size = mite_fifo_size(mite, 0);
printk("mite: fifo size is %i.\n", mite->fifo_size);
mite->used = 1;
return 0;
}
int mite_setup(struct mite_struct *mite)
{
return mite_setup2(mite, 0);
}
void mite_cleanup(void)
{
struct mite_struct *mite, *next;
for (mite = mite_devices; mite; mite = next) {
pci_dev_put(mite->pcidev);
next = mite->next;
kfree(mite);
}
}
void mite_unsetup(struct mite_struct *mite)
{
//unsigned long offset, start, length;
if (!mite)
return;
if (mite->mite_io_addr) {
iounmap(mite->mite_io_addr);
mite->mite_io_addr = NULL;
}
if (mite->daq_io_addr) {
iounmap(mite->daq_io_addr);
mite->daq_io_addr = NULL;
}
if (mite->mite_phys_addr) {
comedi_pci_disable(mite->pcidev);
mite->mite_phys_addr = 0;
}
mite->used = 0;
}
void mite_list_devices(void)
{
struct mite_struct *mite, *next;
printk("Available NI device IDs:");
if (mite_devices)
for (mite = mite_devices; mite; mite = next) {
next = mite->next;
printk(" 0x%04x", mite_device_id(mite));
if (mite->used)
printk("(used)");
}
printk("\n");
}
struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite,
struct mite_dma_descriptor_ring *ring, unsigned min_channel,
unsigned max_channel)
{
int i;
unsigned long flags;
struct mite_channel *channel = NULL;
// spin lock so mite_release_channel can be called safely from interrupts
comedi_spin_lock_irqsave(&mite->lock, flags);
for (i = min_channel; i <= max_channel; ++i) {
if (mite->channel_allocated[i] == 0) {
mite->channel_allocated[i] = 1;
channel = &mite->channels[i];
channel->ring = ring;
break;
}
}
comedi_spin_unlock_irqrestore(&mite->lock, flags);
return channel;
}
void mite_release_channel(struct mite_channel *mite_chan)
{
struct mite_struct *mite = mite_chan->mite;
unsigned long flags;
// spin lock to prevent races with mite_request_channel
comedi_spin_lock_irqsave(&mite->lock, flags);
if (mite->channel_allocated[mite_chan->channel]) {
mite_dma_disarm(mite_chan);
mite_dma_reset(mite_chan);
/* disable all channel's interrupts (do it after disarm/reset so
MITE_CHCR reg isn't changed while dma is still active!) */
writel(CHCR_CLR_DMA_IE | CHCR_CLR_LINKP_IE |
CHCR_CLR_SAR_IE | CHCR_CLR_DONE_IE |
CHCR_CLR_MRDY_IE | CHCR_CLR_DRDY_IE |
CHCR_CLR_LC_IE | CHCR_CLR_CONT_RB_IE,
mite->mite_io_addr + MITE_CHCR(mite_chan->channel));
mite->channel_allocated[mite_chan->channel] = 0;
mite_chan->ring = NULL;
mmiowb();
}
comedi_spin_unlock_irqrestore(&mite->lock, flags);
}
void mite_dma_arm(struct mite_channel *mite_chan)
{
struct mite_struct *mite = mite_chan->mite;
int chor;
unsigned long flags;
MDPRINTK("mite_dma_arm ch%i\n", channel);
/* memory barrier is intended to insure any twiddling with the buffer
is done before writing to the mite to arm dma transfer */
smp_mb();
/* arm */
chor = CHOR_START;
comedi_spin_lock_irqsave(&mite->lock, flags);
mite_chan->done = 0;
writel(chor, mite->mite_io_addr + MITE_CHOR(mite_chan->channel));
mmiowb();
comedi_spin_unlock_irqrestore(&mite->lock, flags);
// mite_dma_tcr(mite, channel);
}
/**************************************/
int mite_buf_change(struct mite_dma_descriptor_ring *ring, comedi_async * async)
{
unsigned int n_links;
int i;
if (ring->descriptors) {
dma_free_coherent(ring->hw_dev,
ring->n_links * sizeof(struct mite_dma_descriptor),
ring->descriptors, ring->descriptors_dma_addr);
}
ring->descriptors = NULL;
ring->descriptors_dma_addr = 0;
ring->n_links = 0;
if (async->prealloc_bufsz == 0) {
return 0;
}
n_links = async->prealloc_bufsz >> PAGE_SHIFT;
MDPRINTK("ring->hw_dev=%p, n_links=0x%04x\n", ring->hw_dev, n_links);
ring->descriptors =
dma_alloc_coherent(ring->hw_dev,
n_links * sizeof(struct mite_dma_descriptor),
&ring->descriptors_dma_addr, GFP_KERNEL);
if (!ring->descriptors) {
printk("mite: ring buffer allocation failed\n");
return -ENOMEM;
}
ring->n_links = n_links;
for (i = 0; i < n_links; i++) {
ring->descriptors[i].count = cpu_to_le32(PAGE_SIZE);
ring->descriptors[i].addr =
cpu_to_le32(async->buf_page_list[i].dma_addr);
ring->descriptors[i].next =
cpu_to_le32(ring->descriptors_dma_addr + (i +
1) * sizeof(struct mite_dma_descriptor));
}
ring->descriptors[n_links - 1].next =
cpu_to_le32(ring->descriptors_dma_addr);
/* barrier is meant to insure that all the writes to the dma descriptors
have completed before the dma controller is commanded to read them */
smp_wmb();
return 0;
}
void mite_prep_dma(struct mite_channel *mite_chan,
unsigned int num_device_bits, unsigned int num_memory_bits)
{
unsigned int chor, chcr, mcr, dcr, lkcr;
struct mite_struct *mite = mite_chan->mite;
MDPRINTK("mite_prep_dma ch%i\n", mite_chan->channel);
/* reset DMA and FIFO */
chor = CHOR_DMARESET | CHOR_FRESET;
writel(chor, mite->mite_io_addr + MITE_CHOR(mite_chan->channel));
/* short link chaining mode */
chcr = CHCR_SET_DMA_IE | CHCR_LINKSHORT | CHCR_SET_DONE_IE |
CHCR_BURSTEN;
/*
* Link Complete Interrupt: interrupt every time a link
* in MITE_RING is completed. This can generate a lot of
* extra interrupts, but right now we update the values
* of buf_int_ptr and buf_int_count at each interrupt. A
* better method is to poll the MITE before each user
* "read()" to calculate the number of bytes available.
*/
chcr |= CHCR_SET_LC_IE;
if (num_memory_bits == 32 && num_device_bits == 16) {
/* Doing a combined 32 and 16 bit byteswap gets the 16 bit samples into the fifo in the right order.
Tested doing 32 bit memory to 16 bit device transfers to the analog out of a pxi-6281,
which has mite version = 1, type = 4. This also works for dma reads from the counters
on e-series boards. */
chcr |= CHCR_BYTE_SWAP_DEVICE | CHCR_BYTE_SWAP_MEMORY;
}
if (mite_chan->dir == COMEDI_INPUT) {
chcr |= CHCR_DEV_TO_MEM;
}
writel(chcr, mite->mite_io_addr + MITE_CHCR(mite_chan->channel));
/* to/from memory */
mcr = CR_RL(64) | CR_ASEQUP;
switch (num_memory_bits) {
case 8:
mcr |= CR_PSIZE8;
break;
case 16:
mcr |= CR_PSIZE16;
break;
case 32:
mcr |= CR_PSIZE32;
break;
default:
rt_printk
("mite: bug! invalid mem bit width for dma transfer\n");
break;
}
writel(mcr, mite->mite_io_addr + MITE_MCR(mite_chan->channel));
/* from/to device */
dcr = CR_RL(64) | CR_ASEQUP;
dcr |= CR_PORTIO | CR_AMDEVICE | CR_REQSDRQ(mite_chan->channel);
switch (num_device_bits) {
case 8:
dcr |= CR_PSIZE8;
break;
case 16:
dcr |= CR_PSIZE16;
break;
case 32:
dcr |= CR_PSIZE32;
break;
default:
rt_printk
("mite: bug! invalid dev bit width for dma transfer\n");
break;
}
writel(dcr, mite->mite_io_addr + MITE_DCR(mite_chan->channel));
/* reset the DAR */
writel(0, mite->mite_io_addr + MITE_DAR(mite_chan->channel));
/* the link is 32bits */
lkcr = CR_RL(64) | CR_ASEQUP | CR_PSIZE32;
writel(lkcr, mite->mite_io_addr + MITE_LKCR(mite_chan->channel));
/* starting address for link chaining */
writel(mite_chan->ring->descriptors_dma_addr,
mite->mite_io_addr + MITE_LKAR(mite_chan->channel));
MDPRINTK("exit mite_prep_dma\n");
}
u32 mite_device_bytes_transferred(struct mite_channel *mite_chan)
{
struct mite_struct *mite = mite_chan->mite;
return readl(mite->mite_io_addr + MITE_DAR(mite_chan->channel));
}
u32 mite_bytes_in_transit(struct mite_channel * mite_chan)
{
struct mite_struct *mite = mite_chan->mite;
return readl(mite->mite_io_addr +
MITE_FCR(mite_chan->channel)) & 0x000000FF;
}
// returns lower bound for number of bytes transferred from device to memory
u32 mite_bytes_written_to_memory_lb(struct mite_channel * mite_chan)
{
u32 device_byte_count;
device_byte_count = mite_device_bytes_transferred(mite_chan);
return device_byte_count - mite_bytes_in_transit(mite_chan);
}
// returns upper bound for number of bytes transferred from device to memory
u32 mite_bytes_written_to_memory_ub(struct mite_channel * mite_chan)
{
u32 in_transit_count;
in_transit_count = mite_bytes_in_transit(mite_chan);
return mite_device_bytes_transferred(mite_chan) - in_transit_count;
}
// returns lower bound for number of bytes read from memory for transfer to device
u32 mite_bytes_read_from_memory_lb(struct mite_channel * mite_chan)
{
u32 device_byte_count;
device_byte_count = mite_device_bytes_transferred(mite_chan);
return device_byte_count + mite_bytes_in_transit(mite_chan);
}
// returns upper bound for number of bytes read from memory for transfer to device
u32 mite_bytes_read_from_memory_ub(struct mite_channel * mite_chan)
{
u32 in_transit_count;
in_transit_count = mite_bytes_in_transit(mite_chan);
return mite_device_bytes_transferred(mite_chan) + in_transit_count;
}
unsigned mite_dma_tcr(struct mite_channel *mite_chan)
{
struct mite_struct *mite = mite_chan->mite;
int tcr;
int lkar;
lkar = readl(mite->mite_io_addr + MITE_LKAR(mite_chan->channel));
tcr = readl(mite->mite_io_addr + MITE_TCR(mite_chan->channel));
MDPRINTK("mite_dma_tcr ch%i, lkar=0x%08x tcr=%d\n", mite_chan->channel,
lkar, tcr);
return tcr;
}
void mite_dma_disarm(struct mite_channel *mite_chan)
{
struct mite_struct *mite = mite_chan->mite;
unsigned chor;
/* disarm */
chor = CHOR_ABORT;
writel(chor, mite->mite_io_addr + MITE_CHOR(mite_chan->channel));
}
int mite_sync_input_dma(struct mite_channel *mite_chan, comedi_async * async)
{
int count;
unsigned int nbytes, old_alloc_count;
const unsigned bytes_per_scan = cfc_bytes_per_scan(async->subdevice);
old_alloc_count = async->buf_write_alloc_count;
// write alloc as much as we can
comedi_buf_write_alloc(async, async->prealloc_bufsz);
nbytes = mite_bytes_written_to_memory_lb(mite_chan);
if ((int)(mite_bytes_written_to_memory_ub(mite_chan) -
old_alloc_count) > 0) {
rt_printk("mite: DMA overwrite of free area\n");
async->events |= COMEDI_CB_OVERFLOW;
return -1;
}
count = nbytes - async->buf_write_count;
/* it's possible count will be negative due to
* conservative value returned by mite_bytes_written_to_memory_lb */
if (count <= 0) {
return 0;
}
comedi_buf_write_free(async, count);
async->scan_progress += count;
if (async->scan_progress >= bytes_per_scan) {
async->scan_progress %= bytes_per_scan;
async->events |= COMEDI_CB_EOS;
}
async->events |= COMEDI_CB_BLOCK;
return 0;
}
int mite_sync_output_dma(struct mite_channel *mite_chan, comedi_async * async)
{
int count;
u32 nbytes_ub, nbytes_lb;
unsigned int old_alloc_count;
u32 stop_count =
async->cmd.stop_arg * cfc_bytes_per_scan(async->subdevice);
old_alloc_count = async->buf_read_alloc_count;
// read alloc as much as we can
comedi_buf_read_alloc(async, async->prealloc_bufsz);
nbytes_lb = mite_bytes_read_from_memory_lb(mite_chan);
if (async->cmd.stop_src == TRIG_COUNT &&
(int)(nbytes_lb - stop_count) > 0)
nbytes_lb = stop_count;
nbytes_ub = mite_bytes_read_from_memory_ub(mite_chan);
if (async->cmd.stop_src == TRIG_COUNT &&
(int)(nbytes_ub - stop_count) > 0)
nbytes_ub = stop_count;
if ((int)(nbytes_ub - old_alloc_count) > 0) {
rt_printk("mite: DMA underrun\n");
async->events |= COMEDI_CB_OVERFLOW;
return -1;
}
count = nbytes_lb - async->buf_read_count;
if (count <= 0) {
return 0;
}
if (count) {
comedi_buf_read_free(async, count);
async->events |= COMEDI_CB_BLOCK;
}
return 0;
}
unsigned mite_get_status(struct mite_channel *mite_chan)
{
struct mite_struct *mite = mite_chan->mite;
unsigned status;
unsigned long flags;
comedi_spin_lock_irqsave(&mite->lock, flags);
status = readl(mite->mite_io_addr + MITE_CHSR(mite_chan->channel));
if (status & CHSR_DONE) {
mite_chan->done = 1;
writel(CHOR_CLRDONE,
mite->mite_io_addr + MITE_CHOR(mite_chan->channel));
}
mmiowb();
comedi_spin_unlock_irqrestore(&mite->lock, flags);
return status;
}
int mite_done(struct mite_channel *mite_chan)
{
struct mite_struct *mite = mite_chan->mite;
unsigned long flags;
int done;
mite_get_status(mite_chan);
comedi_spin_lock_irqsave(&mite->lock, flags);
done = mite_chan->done;
comedi_spin_unlock_irqrestore(&mite->lock, flags);
return done;
}
#ifdef DEBUG_MITE
static void mite_decode(char **bit_str, unsigned int bits);
/* names of bits in mite registers */
static const char *const mite_CHOR_strings[] = {
"start", "cont", "stop", "abort",
"freset", "clrlc", "clrrb", "clrdone",
"clr_lpause", "set_lpause", "clr_send_tc",
"set_send_tc", "12", "13", "14",
"15", "16", "17", "18",
"19", "20", "21", "22",
"23", "24", "25", "26",
"27", "28", "29", "30",
"dmareset",
};
static const char *const mite_CHCR_strings[] = {
"continue", "ringbuff", "2", "3",
"4", "5", "6", "7",
"8", "9", "10", "11",
"12", "13", "bursten", "fifodis",
"clr_cont_rb_ie", "set_cont_rb_ie", "clr_lc_ie", "set_lc_ie",
"clr_drdy_ie", "set_drdy_ie", "clr_mrdy_ie", "set_mrdy_ie",
"clr_done_ie", "set_done_ie", "clr_sar_ie", "set_sar_ie",
"clr_linkp_ie", "set_linkp_ie", "clr_dma_ie", "set_dma_ie",
};
static const char *const mite_MCR_strings[] = {
"amdevice", "1", "2", "3",
"4", "5", "portio", "portvxi",
"psizebyte", "psizehalf (byte & half = word)", "aseqxp1", "11",
"12", "13", "blocken", "berhand",
"reqsintlim/reqs0", "reqs1", "reqs2", "rd32",
"rd512", "rl1", "rl2", "rl8",
"24", "25", "26", "27",
"28", "29", "30", "stopen",
};
static const char *const mite_DCR_strings[] = {
"amdevice", "1", "2", "3",
"4", "5", "portio", "portvxi",
"psizebyte", "psizehalf (byte & half = word)", "aseqxp1", "aseqxp2",
"aseqxp8", "13", "blocken", "berhand",
"reqsintlim", "reqs1", "reqs2", "rd32",
"rd512", "rl1", "rl2", "rl8",
"23", "24", "25", "27",
"28", "wsdevc", "wsdevs", "rwdevpack",
};
static const char *const mite_LKCR_strings[] = {
"amdevice", "1", "2", "3",
"4", "5", "portio", "portvxi",
"psizebyte", "psizehalf (byte & half = word)", "asequp", "aseqdown",
"12", "13", "14", "berhand",
"16", "17", "18", "rd32",
"rd512", "rl1", "rl2", "rl8",
"24", "25", "26", "27",
"28", "29", "30", "chngend",
};
static const char *const mite_CHSR_strings[] = {
"d.err0", "d.err1", "m.err0", "m.err1",
"l.err0", "l.err1", "drq0", "drq1",
"end", "xferr", "operr0", "operr1",
"stops", "habort", "sabort", "error",
"16", "conts_rb", "18", "linkc",
"20", "drdy", "22", "mrdy",
"24", "done", "26", "sars",
"28", "lpauses", "30", "int",
};
void mite_dump_regs(struct mite_channel *mite_chan)
{
unsigned long mite_io_addr =
(unsigned long)mite_chan->mite->mite_io_addr;
unsigned long addr = 0;
unsigned long temp = 0;
printk("mite_dump_regs ch%i\n", mite_chan->channel);
printk("mite address is =0x%08lx\n", mite_io_addr);
addr = mite_io_addr + MITE_CHOR(channel);
printk("mite status[CHOR]at 0x%08lx =0x%08lx\n", addr, temp =
readl(addr));
mite_decode(mite_CHOR_strings, temp);
addr = mite_io_addr + MITE_CHCR(channel);
printk("mite status[CHCR]at 0x%08lx =0x%08lx\n", addr, temp =
readl(addr));
mite_decode(mite_CHCR_strings, temp);
addr = mite_io_addr + MITE_TCR(channel);
printk("mite status[TCR] at 0x%08lx =0x%08x\n", addr, readl(addr));
addr = mite_io_addr + MITE_MCR(channel);
printk("mite status[MCR] at 0x%08lx =0x%08lx\n", addr, temp =
readl(addr));
mite_decode(mite_MCR_strings, temp);
addr = mite_io_addr + MITE_MAR(channel);
printk("mite status[MAR] at 0x%08lx =0x%08x\n", addr, readl(addr));
addr = mite_io_addr + MITE_DCR(channel);
printk("mite status[DCR] at 0x%08lx =0x%08lx\n", addr, temp =
readl(addr));
mite_decode(mite_DCR_strings, temp);
addr = mite_io_addr + MITE_DAR(channel);
printk("mite status[DAR] at 0x%08lx =0x%08x\n", addr, readl(addr));
addr = mite_io_addr + MITE_LKCR(channel);
printk("mite status[LKCR]at 0x%08lx =0x%08lx\n", addr, temp =
readl(addr));
mite_decode(mite_LKCR_strings, temp);
addr = mite_io_addr + MITE_LKAR(channel);
printk("mite status[LKAR]at 0x%08lx =0x%08x\n", addr, readl(addr));
addr = mite_io_addr + MITE_CHSR(channel);
printk("mite status[CHSR]at 0x%08lx =0x%08lx\n", addr, temp =
readl(addr));
mite_decode(mite_CHSR_strings, temp);
addr = mite_io_addr + MITE_FCR(channel);
printk("mite status[FCR] at 0x%08lx =0x%08x\n\n", addr, readl(addr));
}
static void mite_decode(char **bit_str, unsigned int bits)
{
int i;
for (i = 31; i >= 0; i--) {
if (bits & (1 << i)) {
printk(" %s", bit_str[i]);
}
}
printk("\n");
}
#endif
#ifdef MODULE
int __init init_module(void)
{
mite_init();
mite_list_devices();
return 0;
}
void __exit cleanup_module(void)
{
mite_cleanup();
}
EXPORT_SYMBOL(mite_dma_tcr);
EXPORT_SYMBOL(mite_dma_arm);
EXPORT_SYMBOL(mite_dma_disarm);
EXPORT_SYMBOL(mite_sync_input_dma);
EXPORT_SYMBOL(mite_sync_output_dma);
EXPORT_SYMBOL(mite_setup);
EXPORT_SYMBOL(mite_setup2);
EXPORT_SYMBOL(mite_unsetup);
#if 0
EXPORT_SYMBOL(mite_kvmem_segment_load);
EXPORT_SYMBOL(mite_ll_from_kvmem);
EXPORT_SYMBOL(mite_setregs);
#endif
EXPORT_SYMBOL(mite_devices);
EXPORT_SYMBOL(mite_list_devices);
EXPORT_SYMBOL(mite_request_channel_in_range);
EXPORT_SYMBOL(mite_release_channel);
EXPORT_SYMBOL(mite_prep_dma);
EXPORT_SYMBOL(mite_buf_change);
EXPORT_SYMBOL(mite_bytes_written_to_memory_lb);
EXPORT_SYMBOL(mite_bytes_written_to_memory_ub);
EXPORT_SYMBOL(mite_bytes_read_from_memory_lb);
EXPORT_SYMBOL(mite_bytes_read_from_memory_ub);
EXPORT_SYMBOL(mite_bytes_in_transit);
EXPORT_SYMBOL(mite_get_status);
EXPORT_SYMBOL(mite_done);
#ifdef DEBUG_MITE
EXPORT_SYMBOL(mite_decode);
EXPORT_SYMBOL(mite_dump_regs);
#endif
#endif

View File

@ -0,0 +1,453 @@
/*
module/mite.h
Hardware driver for NI Mite PCI interface chip
COMEDI - Linux Control and Measurement Device Interface
Copyright (C) 1999 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.
*/
#ifndef _MITE_H_
#define _MITE_H_
#include "../comedidev.h"
#include "../pci.h"
#define PCI_VENDOR_ID_NATINST 0x1093
// #define DEBUG_MITE
#define PCIMIO_COMPAT
#ifdef DEBUG_MITE
#define MDPRINTK(format,args...) printk(format , ## args )
#else
#define MDPRINTK(format,args...)
#endif
#define MAX_MITE_DMA_CHANNELS 8
struct mite_dma_descriptor {
u32 count;
u32 addr;
u32 next;
u32 dar;
};
struct mite_dma_descriptor_ring {
struct device *hw_dev;
unsigned int n_links;
struct mite_dma_descriptor *descriptors;
dma_addr_t descriptors_dma_addr;
};
struct mite_channel {
struct mite_struct *mite;
unsigned channel;
int dir;
int done;
struct mite_dma_descriptor_ring *ring;
};
struct mite_struct {
struct mite_struct *next;
int used;
struct pci_dev *pcidev;
resource_size_t mite_phys_addr;
void *mite_io_addr;
resource_size_t daq_phys_addr;
void *daq_io_addr;
struct mite_channel channels[MAX_MITE_DMA_CHANNELS];
short channel_allocated[MAX_MITE_DMA_CHANNELS];
int num_channels;
unsigned fifo_size;
spinlock_t lock;
};
static inline struct mite_dma_descriptor_ring *mite_alloc_ring(struct
mite_struct *mite)
{
struct mite_dma_descriptor_ring *ring =
kmalloc(sizeof(struct mite_dma_descriptor_ring), GFP_KERNEL);
if (ring == NULL)
return ring;
ring->hw_dev = get_device(&mite->pcidev->dev);
if (ring->hw_dev == NULL) {
kfree(ring);
return NULL;
}
ring->n_links = 0;
ring->descriptors = NULL;
ring->descriptors_dma_addr = 0;
return ring;
};
static inline void mite_free_ring(struct mite_dma_descriptor_ring *ring)
{
if (ring) {
if (ring->descriptors) {
dma_free_coherent(ring->hw_dev,
ring->n_links *
sizeof(struct mite_dma_descriptor),
ring->descriptors, ring->descriptors_dma_addr);
}
put_device(ring->hw_dev);
kfree(ring);
}
};
extern struct mite_struct *mite_devices;
static inline unsigned int mite_irq(struct mite_struct *mite)
{
return mite->pcidev->irq;
};
static inline unsigned int mite_device_id(struct mite_struct *mite)
{
return mite->pcidev->device;
};
void mite_init(void);
void mite_cleanup(void);
int mite_setup(struct mite_struct *mite);
int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1);
void mite_unsetup(struct mite_struct *mite);
void mite_list_devices(void);
struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite,
struct mite_dma_descriptor_ring *ring, unsigned min_channel,
unsigned max_channel);
static inline struct mite_channel *mite_request_channel(struct mite_struct
*mite, struct mite_dma_descriptor_ring *ring)
{
return mite_request_channel_in_range(mite, ring, 0,
mite->num_channels - 1);
}
void mite_release_channel(struct mite_channel *mite_chan);
unsigned mite_dma_tcr(struct mite_channel *mite_chan);
void mite_dma_arm(struct mite_channel *mite_chan);
void mite_dma_disarm(struct mite_channel *mite_chan);
int mite_sync_input_dma(struct mite_channel *mite_chan, comedi_async * async);
int mite_sync_output_dma(struct mite_channel *mite_chan, comedi_async * async);
u32 mite_bytes_written_to_memory_lb(struct mite_channel *mite_chan);
u32 mite_bytes_written_to_memory_ub(struct mite_channel *mite_chan);
u32 mite_bytes_read_from_memory_lb(struct mite_channel *mite_chan);
u32 mite_bytes_read_from_memory_ub(struct mite_channel *mite_chan);
u32 mite_bytes_in_transit(struct mite_channel *mite_chan);
unsigned mite_get_status(struct mite_channel *mite_chan);
int mite_done(struct mite_channel *mite_chan);
#if 0
unsigned long mite_ll_from_kvmem(struct mite_struct *mite, comedi_async * async,
int len);
void mite_setregs(struct mite_struct *mite, unsigned long ll_start, int chan,
int dir);
#endif
void mite_prep_dma(struct mite_channel *mite_chan,
unsigned int num_device_bits, unsigned int num_memory_bits);
int mite_buf_change(struct mite_dma_descriptor_ring *ring,
comedi_async * async);
#ifdef DEBUG_MITE
void mite_print_chsr(unsigned int chsr);
void mite_dump_regs(struct mite_channel *mite_chan);
#endif
static inline int CHAN_OFFSET(int channel)
{
return 0x500 + 0x100 * channel;
};
enum mite_registers {
/* The bits 0x90180700 in MITE_UNKNOWN_DMA_BURST_REG can be
written and read back. The bits 0x1f always read as 1.
The rest always read as zero. */
MITE_UNKNOWN_DMA_BURST_REG = 0x28,
MITE_IODWBSR = 0xc0, //IO Device Window Base Size Register
MITE_IODWBSR_1 = 0xc4, // IO Device Window Base Size Register 1
MITE_IODWCR_1 = 0xf4,
MITE_PCI_CONFIG_OFFSET = 0x300,
MITE_CSIGR = 0x460 //chip signature
};
static inline int MITE_CHOR(int channel) // channel operation
{
return CHAN_OFFSET(channel) + 0x0;
};
static inline int MITE_CHCR(int channel) // channel control
{
return CHAN_OFFSET(channel) + 0x4;
};
static inline int MITE_TCR(int channel) // transfer count
{
return CHAN_OFFSET(channel) + 0x8;
};
static inline int MITE_MCR(int channel) // memory configuration
{
return CHAN_OFFSET(channel) + 0xc;
};
static inline int MITE_MAR(int channel) // memory address
{
return CHAN_OFFSET(channel) + 0x10;
};
static inline int MITE_DCR(int channel) // device configuration
{
return CHAN_OFFSET(channel) + 0x14;
};
static inline int MITE_DAR(int channel) // device address
{
return CHAN_OFFSET(channel) + 0x18;
};
static inline int MITE_LKCR(int channel) // link configuration
{
return CHAN_OFFSET(channel) + 0x1c;
};
static inline int MITE_LKAR(int channel) // link address
{
return CHAN_OFFSET(channel) + 0x20;
};
static inline int MITE_LLKAR(int channel) // see mite section of tnt5002 manual
{
return CHAN_OFFSET(channel) + 0x24;
};
static inline int MITE_BAR(int channel) // base address
{
return CHAN_OFFSET(channel) + 0x28;
};
static inline int MITE_BCR(int channel) // base count
{
return CHAN_OFFSET(channel) + 0x2c;
};
static inline int MITE_SAR(int channel) // ? address
{
return CHAN_OFFSET(channel) + 0x30;
};
static inline int MITE_WSCR(int channel) // ?
{
return CHAN_OFFSET(channel) + 0x34;
};
static inline int MITE_WSER(int channel) // ?
{
return CHAN_OFFSET(channel) + 0x38;
};
static inline int MITE_CHSR(int channel) // channel status
{
return CHAN_OFFSET(channel) + 0x3c;
};
static inline int MITE_FCR(int channel) // fifo count
{
return CHAN_OFFSET(channel) + 0x40;
};
enum MITE_IODWBSR_bits {
WENAB = 0x80, // window enable
};
static inline unsigned MITE_IODWBSR_1_WSIZE_bits(unsigned size)
{
unsigned order = 0;
while (size >>= 1)
++order;
BUG_ON(order < 1);
return (order - 1) & 0x1f;
}
enum MITE_UNKNOWN_DMA_BURST_bits {
UNKNOWN_DMA_BURST_ENABLE_BITS = 0x600
};
static inline int mite_csigr_version(u32 csigr_bits)
{
return csigr_bits & 0xf;
};
static inline int mite_csigr_type(u32 csigr_bits)
{ // original mite = 0, minimite = 1
return (csigr_bits >> 4) & 0xf;
};
static inline int mite_csigr_mmode(u32 csigr_bits)
{ // mite mode, minimite = 1
return (csigr_bits >> 8) & 0x3;
};
static inline int mite_csigr_imode(u32 csigr_bits)
{ // cpu port interface mode, pci = 0x3
return (csigr_bits >> 12) & 0x3;
};
static inline int mite_csigr_dmac(u32 csigr_bits)
{ // number of dma channels
return (csigr_bits >> 16) & 0xf;
};
static inline int mite_csigr_wpdep(u32 csigr_bits)
{ // write post fifo depth
unsigned int wpdep_bits = (csigr_bits >> 20) & 0x7;
if (wpdep_bits == 0)
return 0;
else
return 1 << (wpdep_bits - 1);
};
static inline int mite_csigr_wins(u32 csigr_bits)
{
return (csigr_bits >> 24) & 0x1f;
};
static inline int mite_csigr_iowins(u32 csigr_bits)
{ // number of io windows
return (csigr_bits >> 29) & 0x7;
};
enum MITE_MCR_bits {
MCRPON = 0,
};
enum MITE_DCR_bits {
DCR_NORMAL = (1 << 29),
DCRPON = 0,
};
enum MITE_CHOR_bits {
CHOR_DMARESET = (1 << 31),
CHOR_SET_SEND_TC = (1 << 11),
CHOR_CLR_SEND_TC = (1 << 10),
CHOR_SET_LPAUSE = (1 << 9),
CHOR_CLR_LPAUSE = (1 << 8),
CHOR_CLRDONE = (1 << 7),
CHOR_CLRRB = (1 << 6),
CHOR_CLRLC = (1 << 5),
CHOR_FRESET = (1 << 4),
CHOR_ABORT = (1 << 3), /* stop without emptying fifo */
CHOR_STOP = (1 << 2), /* stop after emptying fifo */
CHOR_CONT = (1 << 1),
CHOR_START = (1 << 0),
CHOR_PON = (CHOR_CLR_SEND_TC | CHOR_CLR_LPAUSE),
};
enum MITE_CHCR_bits {
CHCR_SET_DMA_IE = (1 << 31),
CHCR_CLR_DMA_IE = (1 << 30),
CHCR_SET_LINKP_IE = (1 << 29),
CHCR_CLR_LINKP_IE = (1 << 28),
CHCR_SET_SAR_IE = (1 << 27),
CHCR_CLR_SAR_IE = (1 << 26),
CHCR_SET_DONE_IE = (1 << 25),
CHCR_CLR_DONE_IE = (1 << 24),
CHCR_SET_MRDY_IE = (1 << 23),
CHCR_CLR_MRDY_IE = (1 << 22),
CHCR_SET_DRDY_IE = (1 << 21),
CHCR_CLR_DRDY_IE = (1 << 20),
CHCR_SET_LC_IE = (1 << 19),
CHCR_CLR_LC_IE = (1 << 18),
CHCR_SET_CONT_RB_IE = (1 << 17),
CHCR_CLR_CONT_RB_IE = (1 << 16),
CHCR_FIFODIS = (1 << 15),
CHCR_FIFO_ON = 0,
CHCR_BURSTEN = (1 << 14),
CHCR_NO_BURSTEN = 0,
CHCR_BYTE_SWAP_DEVICE = (1 << 6),
CHCR_BYTE_SWAP_MEMORY = (1 << 4),
CHCR_DIR = (1 << 3),
CHCR_DEV_TO_MEM = CHCR_DIR,
CHCR_MEM_TO_DEV = 0,
CHCR_NORMAL = (0 << 0),
CHCR_CONTINUE = (1 << 0),
CHCR_RINGBUFF = (2 << 0),
CHCR_LINKSHORT = (4 << 0),
CHCR_LINKLONG = (5 << 0),
CHCRPON =
(CHCR_CLR_DMA_IE | CHCR_CLR_LINKP_IE | CHCR_CLR_SAR_IE |
CHCR_CLR_DONE_IE | CHCR_CLR_MRDY_IE | CHCR_CLR_DRDY_IE |
CHCR_CLR_LC_IE | CHCR_CLR_CONT_RB_IE),
};
enum ConfigRegister_bits {
CR_REQS_MASK = 0x7 << 16,
CR_ASEQDONT = 0x0 << 10,
CR_ASEQUP = 0x1 << 10,
CR_ASEQDOWN = 0x2 << 10,
CR_ASEQ_MASK = 0x3 << 10,
CR_PSIZE8 = (1 << 8),
CR_PSIZE16 = (2 << 8),
CR_PSIZE32 = (3 << 8),
CR_PORTCPU = (0 << 6),
CR_PORTIO = (1 << 6),
CR_PORTVXI = (2 << 6),
CR_PORTMXI = (3 << 6),
CR_AMDEVICE = (1 << 0),
};
static inline int CR_REQS(int source)
{
return (source & 0x7) << 16;
};
static inline int CR_REQSDRQ(unsigned drq_line)
{
/* This also works on m-series when
using channels (drq_line) 4 or 5. */
return CR_REQS((drq_line & 0x3) | 0x4);
}
static inline int CR_RL(unsigned int retry_limit)
{
int value = 0;
while (retry_limit) {
retry_limit >>= 1;
value++;
}
if (value > 0x7)
rt_printk("comedi: bug! retry_limit too large\n");
return (value & 0x7) << 21;
}
enum CHSR_bits {
CHSR_INT = (1 << 31),
CHSR_LPAUSES = (1 << 29),
CHSR_SARS = (1 << 27),
CHSR_DONE = (1 << 25),
CHSR_MRDY = (1 << 23),
CHSR_DRDY = (1 << 21),
CHSR_LINKC = (1 << 19),
CHSR_CONTS_RB = (1 << 17),
CHSR_ERROR = (1 << 15),
CHSR_SABORT = (1 << 14),
CHSR_HABORT = (1 << 13),
CHSR_STOPS = (1 << 12),
CHSR_OPERR_mask = (3 << 10),
CHSR_OPERR_NOERROR = (0 << 10),
CHSR_OPERR_FIFOERROR = (1 << 10),
CHSR_OPERR_LINKERROR = (1 << 10), /* ??? */
CHSR_XFERR = (1 << 9),
CHSR_END = (1 << 8),
CHSR_DRQ1 = (1 << 7),
CHSR_DRQ0 = (1 << 6),
CHSR_LxERR_mask = (3 << 4),
CHSR_LBERR = (1 << 4),
CHSR_LRERR = (2 << 4),
CHSR_LOERR = (3 << 4),
CHSR_MxERR_mask = (3 << 2),
CHSR_MBERR = (1 << 2),
CHSR_MRERR = (2 << 2),
CHSR_MOERR = (3 << 2),
CHSR_DxERR_mask = (3 << 0),
CHSR_DBERR = (1 << 0),
CHSR_DRERR = (2 << 0),
CHSR_DOERR = (3 << 0),
};
static inline void mite_dma_reset(struct mite_channel *mite_chan)
{
writel(CHOR_DMARESET | CHOR_FRESET,
mite_chan->mite->mite_io_addr + MITE_CHOR(mite_chan->channel));
};
#endif