Hardware driver for NI Mite PCI interface chip
COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1997-8 David A. Schleef <ds@stm.lbl.gov>
+ 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
struct mite_struct *mite_devices = NULL;
-
+
#define TOP_OF_PAGE(x) ((x)|(~(PAGE_MASK)))
#ifdef PCI_SUPPORT_VER1
}
#endif
+#ifdef PCIMIO_COMPAT
/* DMA setup */
for(i=0;i<MITE_RING_SIZE-1;i++){
- mite->ring[i].next=virt_to_bus(mite->ring+i+1);
+ mite->ring[i].next=cpu_to_le32(virt_to_bus(mite->ring+i+1));
}
mite->ring[i].next=0;
+#endif
mite->used = 1;
offset=((int)kvmem)&(PAGE_SIZE-1);
- mite->ring[i].addr = kvirt_to_bus((int)kvmem);
+ mite->ring[i].addr = cpu_to_le32(kvirt_to_bus((int)kvmem));
+ //mite->ring[i].dar = cpu_to_le32(0x1c);
count=PAGE_SIZE-offset;
if(count>len)count=len;
- mite->ring[i].count = count;
+ mite->ring[i].count = cpu_to_le32(count);
return count;
}
-void mite_dma_prep(struct mite_struct *mite,comedi_subdevice *s)
-{
- int i,n;
- int chor,chcr,mcr,dcr,lkcr;
-
- for(i=0;i<MITE_RING_SIZE;i++){
- n=s->async->prealloc_bufsz-s->async->buf_int_ptr;
- n=mite_kvmem_segment_load(mite,i,s->async->data+s->async->buf_int_ptr,n);
- s->async->buf_int_ptr+=n;
- if(s->async->buf_int_ptr>=s->async->prealloc_bufsz)
- s->async->buf_int_ptr=0;
- }
-
- chor = CHOR_DMARESET | CHOR_FRESET;
- writel(chor,mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(0));
-
- // Should this be LINKLONG for 32HS?
- chcr = CHCR_LINKSHORT | CHCR_DEV_TO_MEM;
- writel(chcr,mite->mite_io_addr+MITE_CHCR+CHAN_OFFSET(0));
-
- mcr = CR_RL64 | CR_ASEQxP1 | CR_PSIZEHALF;
- writel(mcr,mite->mite_io_addr+MITE_MCR+CHAN_OFFSET(0));
-
- dcr = CR_RL64 | CR_PSIZEHALF | CR_PORTIO | CR_AMDEVICE;
- dcr |= CR_REQSDRQ0;
- writel(dcr,mite->mite_io_addr+MITE_DCR+CHAN_OFFSET(0));
-
- lkcr = CR_RL64 | CR_ASEQUP | CR_PSIZEWORD;
- writel(lkcr,mite->mite_io_addr+MITE_LKCR+CHAN_OFFSET(0));
-
- writel(virt_to_bus(mite->ring),mite->mite_io_addr+MITE_LKAR+CHAN_OFFSET(0));
-}
-
-
/*
* Create the short linkchaining MITE linked list using kernel memory
- * a drop in replacement for mite_ll_from_user( )
*/
unsigned long mite_ll_from_kvmem(struct mite_struct *mite,comedi_async *async,int reqlen)
{
int i,size_so_far, continuous_aq, len;
unsigned long nup;
unsigned long prealloc_buf,prealloc_bufsz;
- //comedi_subdevice *s;
- //struct mite_struct *mite=NULL;
- //comedi_async *async=NULL;
- //int len;
MDPRINTK("mite_ll_from_kvmem\n");
- //s=dev->subdevices+cmd->subdev;
- //mite=devpriv->mite;
prealloc_buf=(unsigned long)async->prealloc_buf;
prealloc_bufsz=async->prealloc_bufsz;
len = (reqlen>prealloc_bufsz?prealloc_bufsz:reqlen);
}
- //if(async->data_len<len) {
- // printk("<1>Comedi Error: preallocated DMA buffer is too small to hold the samples.");
- //}
-
//find the kernel's memory pages.
nup = (unsigned long)async->data;
i=0;
int count;
count = 1+TOP_OF_PAGE(nup)-nup;
if(count>len-size_so_far) count = len-size_so_far;
- mite->ring[i].addr =kvirt_to_bus(nup);// it's already a kernel address :-)
- mite->ring[i].count=count;
- mite->ring[i].next=virt_to_bus(mite->ring+i+1);
- size_so_far += mite->ring[i].count;
- nup += mite->ring[i].count;
+ mite->ring[i].addr = cpu_to_le32(kvirt_to_bus((void *)nup));// it's already a kernel address :-)
+ mite->ring[i].count = cpu_to_le32(count);
+ //mite->ring[i].dar = cpu_to_le32(0x1c);
+ mite->ring[i].next = cpu_to_le32(virt_to_bus(mite->ring+i+1));
+ size_so_far += count;
+ nup += count;
i++;
}
/*End the mite->ring by setting the last element's count to 0.
To make a looping ring for continuous acquisition,
- mite->ring[i-1].next = virt_to_bus(mite->ring);
+ mite->ring[i-1].next = cpu_to_le32(virt_to_bus(mite->ring));
*/
//mite->ring[i].count=0;
if (continuous_aq&&(i>0)) {
- mite->ring[i-1].next = virt_to_bus(mite->ring+0);
+ mite->ring[i-1].next = cpu_to_le32(virt_to_bus(mite->ring+0));
mite->DMA_CheckNearEnd = 0;
}else if (prealloc_bufsz < reqlen) {
- mite->ring[i-1].next = virt_to_bus(mite->ring+0);
+ mite->ring[i-1].next = cpu_to_le32(virt_to_bus(mite->ring+0));
mite->DMA_CheckNearEnd = 1;
}
else {
if(size_so_far<len) {
printk("<1>Comedi Error: MITE_RING_SIZE is too small to hold the needed buffer\n");
}
- #if 0 //#ifdef DEBUG_MITE
+#ifdef DEBUG_MITE
for(i=0; i<MITE_RING_SIZE;i++){
- printk("i=%3d, addr=0x%08x, next=0x%08x, count=0x%08x\n",i,mite->ring[i].addr,
- mite->ring[i].next, mite->ring[i].count);
+ printk("i=%3d, addr=0x%08x, next=0x%08x, count=0x%08x dar=%08x\n",i,mite->ring[i].addr,
+ mite->ring[i].next, mite->ring[i].count, mite->ring[i].dar);
}
- #endif
+#endif
MDPRINTK("exit mite_ll_from_kvmem\n");
return virt_to_bus(&(mite->ring[0]));
}
-/* This function would be used to DMA directly into user memory.
-Since Comedi won't support that for a while, this should probably be removed. --Tim Ousley
-unsigned long mite_ll_from_user(comedi_device *dev, comedi_cmd *cmd)
-{
- int i,size_so_far,len;
- unsigned long nup;
-
- comedi_subdevice *s;
- struct mite_struct *mite;
-
- MDPRINTK("mite_ll_from_user\n");
- s=dev->subdevices+cmd->subdev;
- //mite=devpriv->mite;
- len = cmd->data_len;
-
- //find the users memory pages.
- nup = (unsigned long)cmd->data; i=0; size_so_far=0;
- MDPRINTK("buf=0x%08lx bufsz=0x%08x\n",
- (unsigned long)cmd->data,cmd->data_len);
- while(((void*)nup < ((void*)cmd->data+len))&&(i<(MITE_RING_SIZE-1))) {
- mite->ring[i].addr =uvirt_to_bus(nup);
- mite->ring[i].count=min(1+TOP_OF_PAGE(nup)-nup,len-size_so_far);
- mite->ring[i].next=virt_to_bus(mite->ring+i+1);
- size_so_far += mite->ring[i].count;
- nup += mite->ring[i].count;
- i++;
- }
- mite->ring[i].count=0;
- MDPRINTK("i was %d, size_so_far was %d\n",i,size_so_far);
- if(size_so_far<len) {
- printk("<1>Comedi Error: MITE_RING_SIZE is too small to hold the needed buffer\n");
- printk("<1>Comedi Error: MITE_RING_SIZE is %d, buffer is %d bytes\n",
- MITE_RING_SIZE, len);
- }
-
- #if 0 //#ifdef DEBUG_MITE
- for(i=0; i<MITE_RING_SIZE;i++){
- printk("i=%3d, addr=0x%08x, next=0x%08x, count=0x%08x\n",i,mite->ring[i].addr,
- mite->ring[i].next, mite->ring[i].count);
- }
- #endif
- MDPRINTK("exit mite_ll_from_user\n");
- return virt_to_bus(&(mite->ring[0]));
-}
-*/
void mite_dma_arm(struct mite_struct *mite)
{
/* arm */
chor = CHOR_START;
- writel(chor,mite->mite_io_addr+CHAN_OFFSET(0)+MITE_CHOR);
+ writel(chor,mite->mite_io_addr+CHAN_OFFSET(mite->chan)+MITE_CHOR);
mite_dma_tcr(mite);
}
MDPRINTK("exit mite_setregs\n");
}
+
+/**************************************/
+
+int mite_load_buffer(struct mite_struct *mite, comedi_async *async)
+{
+ unsigned int n_links;
+ int i;
+
+ MDPRINTK("mite_load_buffer\n");
+
+ if(mite->ring){
+ kfree(mite->ring);
+ }
+
+ if(async->prealloc_bufsz==0){
+ return 0;
+ }
+
+ n_links = async->prealloc_bufsz >> PAGE_SHIFT;
+
+ MDPRINTK("buf=%p bufsz=0x%08x n_links=0x%04x\n",
+ async->prealloc_buf, async->prealloc_bufsz, n_links);
+
+ mite->ring = kmalloc(n_links*sizeof(struct mite_dma_chain),GFP_KERNEL);
+ if(!mite->ring){
+ printk("mite: ring buffer allocation failed\n");
+ return -ENOMEM;
+ }
+ mite->n_links = n_links;
+ mite->current_link = 0;
+
+ for(i=0;i<n_links;i++){
+ mite->ring[i].count = cpu_to_le32(PAGE_SIZE);
+ mite->ring[i].addr = cpu_to_le32(
+ virt_to_bus(async->prealloc_buf + i*PAGE_SIZE));
+ mite->ring[i].next = cpu_to_le32(virt_to_bus(mite->ring+i+1));
+ mite->ring[i].dar = 0x1c;
+ }
+
+ mite->ring[n_links-1].next = cpu_to_le32(virt_to_bus(mite->ring));
+
+ return 0;
+}
+
+int mite_buf_alloc(struct mite_struct *mite, comedi_async *async,
+ unsigned long new_size)
+{
+ MDPRINTK("mite_buf_alloc\n");
+
+ if(async->prealloc_buf && async->prealloc_bufsz == new_size){
+ return 0;
+ }
+
+ if(async->prealloc_bufsz){
+ kfree(async->prealloc_buf);
+ async->prealloc_buf = NULL;
+ async->prealloc_bufsz = 0;
+ }
+
+ if(new_size){
+ async->prealloc_buf = kmalloc(new_size, GFP_KERNEL);
+ if(async->prealloc_buf == NULL){
+ async->prealloc_bufsz = 0;
+ return -ENOMEM;
+ }
+ }
+ async->prealloc_bufsz = new_size;
+
+ mite_load_buffer(mite,async);
+
+ return 0;
+}
+
+void mite_prep_dma(struct mite_struct *mite)
+{
+ unsigned int chor,chcr,mcr,dcr,lkcr;
+ int chan = mite->chan;
+
+ MDPRINTK("mite_prep_dma\n");
+
+ /* reset DMA and FIFO */
+ chor = CHOR_DMARESET | CHOR_FRESET;
+ writel(chor,mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(chan));
+
+ /* short link chaining mode */
+ chcr = CHCR_SET_DMA_IE| CHCR_LINKSHORT | CHCR_SET_DONE_IE;
+ /*
+ * 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.
+ * mite_bytes_transferred() is provided to get the number
+ * of bytes transferred to system memory so far.
+ */
+ chcr |= CHCR_SET_LC_IE;
+
+ if(mite->dir == COMEDI_INPUT){
+ chcr |= CHCR_DEV_TO_MEM;
+ }
+ writel(chcr,mite->mite_io_addr+MITE_CHCR+CHAN_OFFSET(chan));
+
+ /* 16 bits, to memory */
+ mcr = CR_RL64 | CR_ASEQxP1 | CR_PSIZEHALF;
+ writel(mcr,mite->mite_io_addr+MITE_MCR+CHAN_OFFSET(chan));
+
+ /* 16 bits, from device */
+ dcr = CR_RL64 | CR_ASEQx(1) | CR_PSIZEHALF;
+ dcr |= CR_PORTIO | CR_AMDEVICE | CR_REQS(0x4+chan);
+ writel(dcr,mite->mite_io_addr+MITE_DCR+CHAN_OFFSET(chan));
+
+ /* reset the DAR */
+ writel(0,mite->mite_io_addr+MITE_DAR+CHAN_OFFSET(chan));
+
+ /* the link is 32bits */
+ lkcr = CR_RL64 | CR_ASEQUP | CR_PSIZEWORD;
+ writel(lkcr,mite->mite_io_addr+MITE_LKCR+CHAN_OFFSET(chan));
+
+ /* starting address for link chaining */
+ writel(virt_to_bus(mite->ring),
+ mite->mite_io_addr+MITE_LKAR+CHAN_OFFSET(chan));
+
+ MDPRINTK("exit mite_prep_dma\n");
+}
+
+
int mite_bytes_transferred(struct mite_struct *mite, int chan)
{
int dar, fcr;
int tcr;
int lkar;
- lkar=readl(mite->mite_io_addr+CHAN_OFFSET(0)+MITE_LKAR);
- tcr=readl(mite->mite_io_addr+CHAN_OFFSET(0)+MITE_TCR);
+ lkar=readl(mite->mite_io_addr+CHAN_OFFSET(mite->chan)+MITE_LKAR);
+ tcr=readl(mite->mite_io_addr+CHAN_OFFSET(mite->chan)+MITE_TCR);
MDPRINTK("lkar=0x%08x tcr=%d\n",lkar,tcr);
return tcr;
/* disarm */
chor = CHOR_ABORT;
- writel(chor,mite->mite_io_addr+CHAN_OFFSET(0)+MITE_CHOR);
+ writel(chor,mite->mite_io_addr+CHAN_OFFSET(mite->chan)+MITE_CHOR);
}
void mite_dump_regs(struct mite_struct *mite)
addr = mite_io_addr+MITE_CHSR+CHAN_OFFSET(0);
printk("mite status[CHSR]at 0x%08lx =0x%08lx\n",addr, temp=readl(addr));
+ mite_print_chsr(temp);
//mite_decode(mite_CHSR_strings,temp);
addr = mite_io_addr+MITE_FCR+CHAN_OFFSET(0);
printk("mite status[FCR] at 0x%08lx =0x%08x\n\n",addr, readl(addr));
}
+#ifdef DEBUG_MITE
+static char *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_print_chsr(unsigned int bits)
+{
+ int i;
+
+ printk("chsr:");
+ for(i=31;i>=0;i--){
+ if(bits&(1<<i)){
+ printk(" %s",chsr_strings[i]);
+ }
+ }
+ printk("\n");
+}
+#endif
#ifdef MODULE
#include <linux/symtab_begin.h>
X(mite_dma_arm),
X(mite_dma_disarm),
- X(mite_dma_prep),
X(mite_setup),
X(mite_unsetup),
X(mite_kvmem_segment_load),
EXPORT_SYMBOL(mite_dma_tcr);
EXPORT_SYMBOL(mite_dma_arm);
EXPORT_SYMBOL(mite_dma_disarm);
-EXPORT_SYMBOL(mite_dma_prep);
EXPORT_SYMBOL(mite_setup);
EXPORT_SYMBOL(mite_unsetup);
EXPORT_SYMBOL(mite_kvmem_segment_load);
EXPORT_SYMBOL(mite_devices);
EXPORT_SYMBOL(mite_list_devices);
+EXPORT_SYMBOL(mite_print_chsr);
+EXPORT_SYMBOL(mite_prep_dma);
+EXPORT_SYMBOL(mite_buf_alloc);
//Tim's debugging function
EXPORT_SYMBOL(mite_dump_regs);
-//EXPORT_SYMBOL(mite_ll_from_user); //obsolete
EXPORT_SYMBOL(mite_ll_from_kvmem);
EXPORT_SYMBOL(mite_setregs);
EXPORT_SYMBOL(mite_bytes_transferred);