📄 ni_pcidio.c
字号:
/* comedi/drivers/ni_pcidio.c driver for National Instruments PCI-DIO-96/PCI-6508 National Instruments PCI-DIO-32HS National Instruments PCI-6503 COMEDI - Linux Control and Measurement Device Interface Copyright (C) 1999,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.*//*Driver: ni_pcidio.oDescription: National Instruments PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503Author: dsStatus: worksDevices: [National Instruments] PCI-DIO-32HS (ni_pcidio), PXI-6533, PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X, PXI-6503, PCI-6534, PCI-6533Updated: Sun, 21 Apr 2002 21:03:38 -0700The DIO-96 appears as four 8255 subdevices. See the 8255driver notes for details.The DIO32HS board appears as one subdevice, with 32 channels.Each channel is individually I/O configurable. The channel orderis 0=A0, 1=A1, 2=A2, ... 8=B0, 16=C0, 24=D0. The driver onlysupports simple digital I/O; no handshaking is supported.DMA mostly works for the PCI-DIO32HS, but only in timed input mode.This driver could be easily modified to support AT-MIO32HS andAT-MIO96.*//* This driver is for both the NI PCI-DIO-32HS and the PCI-DIO-96, which have very different architectures. But, since the '96 is so simple, it is included here. Manuals (available from ftp://ftp.natinst.com/support/manuals) 320938c.pdf PCI-DIO-96/PXI-6508/PCI-6503 User Manual 321464b.pdf AT/PCI-DIO-32HS User Manual 341329A.pdf PCI-6533 Register-Level Programmer Manual 341330A.pdf DAQ-DIO Technical Reference Manual */#define USE_DMA#define DEBUG 1#define DEBUG_FLAGS#include <linux/comedidev.h>#include <linux/irq.h> /* for disable_irq */#include "mite.h"#include "8255.h"#undef DPRINTK#ifdef DEBUG#define DPRINTK(format, args...) printk(format, ## args)#else#define DPRINTK(format, args...)#endif#define PCI_VENDOR_ID_NATINST 0x1093#define PCI_DIO_SIZE 4096#define PCI_MITE_SIZE 4096/* defines for the PCI-DIO-96 */#define NIDIO_8255_BASE(x) ((x)*4)#define NIDIO_A 0#define NIDIO_B 4#define NIDIO_C 8#define NIDIO_D 12/* defines for the PCI-DIO-32HS */#define Window_Address 4 /* W */#define Interrupt_And_Window_Status 4 /* R */ #define IntStatus1 (1<<0) #define IntStatus2 (1<<1) #define WindowAddressStatus_mask 0x7c#define Master_DMA_And_Interrupt_Control 5 /* W */ #define InterruptLine(x) ((x)&3) #define OpenInt (1<<2)#define Group_Status 5 /* R */ #define DataLeft (1<<0) #define Req (1<<2) #define StopTrig (1<<3)#define Group_1_Flags 6 /* R */#define Group_2_Flags 7 /* R */ #define TransferReady (1<<0) #define CountExpired (1<<1) #define Waited (1<<5) #define PrimaryTC (1<<6) #define SecondaryTC (1<<7) //#define SerialRose //#define ReqRose //#define Paused#define Group_1_First_Clear 6 /* W */#define Group_2_First_Clear 7 /* W */ #define ClearWaited (1<<3) #define ClearPrimaryTC (1<<4) #define ClearSecondaryTC (1<<5) #define DMAReset (1<<6) #define FIFOReset (1<<7) #define ClearAll 0xf8#define Group_1_FIFO 8 /* W */#define Group_2_FIFO 12 /* W */#define Transfer_Count 20#define Chip_ID_D 24#define Chip_ID_I 25#define Chip_ID_O 26#define Chip_Version 27#define Port_IO(x) (28+(x))#define Port_Pin_Directions(x) (32+(x))#define Port_Pin_Mask(x) (36+(x))#define Port_Pin_Polarities(x) (40+(x))#define Master_Clock_Routing 45 #define RTSIClocking(x) (((x)&3)<<4)#define Group_1_Second_Clear 46 /* W */#define Group_2_Second_Clear 47 /* W */ #define ClearExpired (1<<0)#define Port_Pattern(x) (48+(x))#define Data_Path 64 #define FIFOEnableA (1<<0) #define FIFOEnableB (1<<1) #define FIFOEnableC (1<<2) #define FIFOEnableD (1<<3) #define Funneling(x) (((x)&3)<<4) #define GroupDirection (1<<7)#define Protocol_Register_1 65#define OpMode Protocol_Register_1 #define RunMode(x) ((x)&7) #define Numbered (1<<3)#define Protocol_Register_2 66#define ClockReg Protocol_Register_2 #define ClockLine(x) (((x)&3)<<5) #define InvertStopTrig (1<<7)#define Protocol_Register_3 67#define Sequence Protocol_Register_3#define Protocol_Register_14 68 /* 16 bit */#define ClockSpeed Protocol_Register_14#define Protocol_Register_4 70#define ReqReg Protocol_Register_4 #define ReqConditioning(x) (((x)&7)<<3)#define Protocol_Register_5 71#define BlockMode Protocol_Register_5#define FIFO_Control 72 #define ReadyLevel(x) ((x)&7)#define Protocol_Register_6 73#define LinePolarities Protocol_Register_6 #define InvertAck (1<<0) #define InvertReq (1<<1) #define InvertClock (1<<2) #define InvertSerial (1<<3) #define OpenAck (1<<4) #define OpenClock (1<<5)#define Protocol_Register_7 74#define AckSer Protocol_Register_7 #define AckLine(x) (((x)&3)<<2) #define ExchangePins (1<<7)#define Interrupt_Control 75 /* bits same as flags */#define DMA_Line_Control 76 #define DMAChannel(x) ((x)&0xf)#define Transfer_Size_Control 77 #define TransferWidth(x) ((x)&3) #define TransferLength(x) (((x)&3)<<3) #define RequireRLevel (1<<5)#define Protocol_Register_15 79#define DAQOptions Protocol_Register_15 #define StartSource(x) ((x)&0x3) #define InvertStart (1<<2) #define StopSource(x) (((x)&0x3)<<3) #define ReqStart (1<<6) #define PreStart (1<<7)#define Pattern_Detection 81 #define DetectionMethod (1<<0) #define InvertMatch (1<<1) #define IE_Pattern_Detection (1<<2)#define Protocol_Register_9 82#define ReqDelay Protocol_Register_9#define Protocol_Register_10 83#define ReqNotDelay Protocol_Register_10#define Protocol_Register_11 84#define AckDelay Protocol_Register_11#define Protocol_Register_12 85#define AckNotDelay Protocol_Register_12#define Protocol_Register_13 86#define Data1Delay Protocol_Register_13#define Protocol_Register_8 88 /* 32 bit */#define StartDelay Protocol_Register_8#define TIMER_BASE 50 /* nanoseconds */#ifdef USE_DMA#define IntEn (CountExpired|Waited|PrimaryTC|SecondaryTC)#else#define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC)#endifenum mite_dma_channels{ DI_DMA_CHAN = 1,};static int nidio_attach(comedi_device *dev,comedi_devconfig *it);static int nidio_detach(comedi_device *dev);static comedi_driver driver_pcidio={ driver_name: "ni_pcidio", module: THIS_MODULE, attach: nidio_attach, detach: nidio_detach,};COMEDI_INITCLEANUP(driver_pcidio);typedef struct{ int dev_id; char *name; int n_8255; unsigned int is_diodaq : 1;}nidio_board;static nidio_board nidio_boards[]={ { dev_id: 0x1150, name: "pci-dio-32hs", n_8255: 0, is_diodaq: 1, }, { dev_id: 0x1320, name: "pxi-6533", n_8255: 0, is_diodaq: 1, }, { dev_id: 0x12b0, name: "pci-6534", n_8255: 0, is_diodaq: 1, }, { dev_id: 0x0160, name: "pci-dio-96", n_8255: 4, is_diodaq: 0, }, { dev_id: 0x1630, name: "pci-dio-96b", n_8255: 4, is_diodaq: 0, }, { dev_id: 0x13c0, name: "pxi-6508", n_8255: 4, is_diodaq: 0, }, { dev_id: 0x0400, name: "pci-6503", n_8255: 1, is_diodaq: 0, }, { dev_id: 0x1250, name: "pci-6503b", n_8255: 1, is_diodaq: 0, }, { dev_id: 0x17d0, name: "pci-6503x", n_8255: 1, is_diodaq: 0, }, { dev_id: 0x1800, name: "pxi-6503", n_8255: 1, is_diodaq: 0, },};#define n_nidio_boards (sizeof(nidio_boards)/sizeof(nidio_boards[0]))#define this_board ((nidio_board *)dev->board_ptr)static struct pci_device_id ni_pcidio_pci_table[] __devinitdata = { { PCI_VENDOR_ID_NATINST, 0x1150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_NATINST, 0x1320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_NATINST, 0x12b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_NATINST, 0x0160, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_NATINST, 0x1630, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_NATINST, 0x13c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_NATINST, 0x0400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_NATINST, 0x1250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_NATINST, 0x17d0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_NATINST, 0x1800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0 }};MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table);typedef struct{ struct mite_struct *mite; int boardtype; int dio;}nidio96_private;#define devpriv ((nidio96_private *)dev->private)static int ni_pcidio_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd);static int ni_pcidio_cmd(comedi_device *dev,comedi_subdevice *s);static int ni_pcidio_inttrig(comedi_device *dev, comedi_subdevice *s, unsigned int trignum);static int nidio_find_device(comedi_device *dev,int bus,int slot);static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode);static void setup_mite_dma(comedi_device *dev,comedi_subdevice *s);#ifdef DEBUG_FLAGSstatic void ni_pcidio_print_flags(unsigned int flags);static void ni_pcidio_print_status(unsigned int status);#else#define ni_pcidio_print_flags(x)#define ni_pcidio_print_status(x)#endifstatic int nidio96_8255_cb(int dir,int port,int data,unsigned long iobase){ if(dir){ writeb(data,iobase+port); return 0; }else{ return readb(iobase+port); }}static void nidio_interrupt(int irq, void *d, struct pt_regs *regs){ comedi_device *dev=d; comedi_subdevice *s = dev->subdevices; comedi_async *async = s->async; struct mite_struct *mite = devpriv->mite; struct mite_channel *mite_chan = &mite->channels[ DI_DMA_CHAN ]; //int i, j; long int AuxData = 0; sampl_t data1 = 0; sampl_t data2 = 0; int flags; int status; int work = 0; unsigned int m_status; status = readb(dev->iobase+Interrupt_And_Window_Status); flags = readb(dev->iobase+Group_1_Flags); m_status = readl(mite->mite_io_addr + MITE_CHSR + CHAN_OFFSET( DI_DMA_CHAN )); //interrupcions parasites if(dev->attached == 0){ comedi_error(dev,"premature interrupt"); async->events |= COMEDI_CB_ERROR|COMEDI_CB_EOA; } DPRINTK("ni_pcidio_interrupt: status=0x%02x,flags=0x%02x,m_status=0x%08x\n", status,flags,m_status); ni_pcidio_print_flags(flags); ni_pcidio_print_status(status);#ifdef MITE_DEBUG mite_print_chsr(m_status);#endif //printk("mite_bytes_transferred: %d\n",mite_bytes_transferred(mite,DI_DMA_CHAN)); //mite_dump_regs(mite); //printk("buf[0]=%08x\n",*(unsigned int *)async->prealloc_buf); //printk("buf[4096]=%08x\n",*(unsigned int *)(async->prealloc_buf+4096)); if(m_status & CHSR_INT){ if(m_status & CHSR_LINKC){ unsigned int count; writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(DI_DMA_CHAN)); count = le32_to_cpu(mite_chan->ring[mite_chan->current_link].count); /* XXX need to byteswap */ async->buf_write_count += count; async->buf_write_ptr += count; if(async->buf_write_ptr >= async->prealloc_bufsz){ async->buf_write_ptr -= async->prealloc_bufsz; } mite_chan->current_link++; if(mite_chan->current_link >= mite_chan->n_links){ mite_chan->current_link=0; } } if(m_status & CHSR_DONE){ writel(CHOR_CLRDONE, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET( DI_DMA_CHAN )); } if(m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_DRDY | CHSR_DRQ1)){ DPRINTK("unknown mite interrupt, disabling IRQ\n"); writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET( DI_DMA_CHAN )); disable_irq(dev->irq); } async->events |= COMEDI_CB_BLOCK; } while(status&DataLeft){ work++; if(work>20){ DPRINTK("too much work in interrupt\n"); writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control); break; } flags &= IntEn; if(flags & TransferReady){ //DPRINTK("TransferReady\n"); while(flags & TransferReady){ work++; if(work>100){ DPRINTK("too much work in interrupt\n"); writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control); goto out; } AuxData = readl(dev->iobase+Group_1_FIFO); data1 = AuxData & 0xffff; data2 = (AuxData & 0xffff0000) >> 16; comedi_buf_put(async,data1); comedi_buf_put(async,data2); //DPRINTK("read:%d, %d\n",data1,data2); flags = readb(dev->iobase+Group_1_Flags); } //DPRINTK("buf_int_count: %d\n",async->buf_int_count); //DPRINTK("1) IntEn=%d,flags=%d,status=%d\n",IntEn,flags,status); //ni_pcidio_print_flags(flags); //ni_pcidio_print_status(status); async->events |= COMEDI_CB_BLOCK; } if(flags & CountExpired){ DPRINTK("CountExpired\n"); writeb(ClearExpired,dev->iobase+Group_1_Second_Clear); async->events |= COMEDI_CB_EOA; writeb(0x00,dev->iobase+OpMode); writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);#ifdef USE_DMA mite_dma_disarm(mite, DI_DMA_CHAN); writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET( DI_DMA_CHAN ));#endif break; }else if(flags & Waited){ DPRINTK("Waited\n"); writeb(ClearWaited,dev->iobase+Group_1_First_Clear); writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;#ifdef USE_DMA mite_dma_disarm(mite, DI_DMA_CHAN); writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET( DI_DMA_CHAN ));#endif break; }else if(flags & PrimaryTC){ DPRINTK("PrimaryTC\n"); writeb(ClearPrimaryTC,dev->iobase+Group_1_First_Clear); async->events |= COMEDI_CB_EOA; writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control); }else if(flags & SecondaryTC){ DPRINTK("SecondaryTC\n"); writeb(ClearSecondaryTC,dev->iobase+Group_1_First_Clear);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -