📄 ni_6527.c
字号:
/* comedi/drivers/ni_6527.c driver for National Instruments PCI-6527 COMEDI - Linux Control and Measurement Device Interface Copyright (C) 1999,2002,2003 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: ni6527.oDescription: National Instruments 6527Author: dsStatus: worksDevices: [National Instruments] 6527Updated: Sat, 25 Jan 2003 13:24:40 -0800*//* Manuals (available from ftp://ftp.natinst.com/support/manuals) 370106b.pdf 6527 Register Level Programmer Manual */#define DEBUG 1#define DEBUG_FLAGS#include <linux/comedidev.h>#include "mite.h"#define NI6527_DIO_SIZE 4096#define NI6527_MITE_SIZE 4096#define Port_Register(x) (0x00+(x))#define ID_Register 0x06#define Clear_Register 0x07#define ClrEdge 0x08#define ClrOverflow 0x04#define ClrFilter 0x02#define ClrInterval 0x01#define Filter_Interval(x) (0x08+(x))#define Filter_Enable(x) (0x0c+(x))#define Change_Status 0x14#define MasterInterruptStatus 0x04#define Overflow 0x02#define EdgeStatus 0x01#define Master_Interrupt_Control 0x15#define FallingEdgeIntEnable 0x10#define RisingEdgeIntEnable 0x08#define MasterInterruptEnable 0x04#define OverflowIntEnable 0x02#define EdgeIntEnable 0x01#define Rising_Edge_Detection_Enable(x) (0x018+(x))#define Falling_Edge_Detection_Enable(x) (0x020+(x))static int ni6527_attach(comedi_device *dev,comedi_devconfig *it);static int ni6527_detach(comedi_device *dev);static comedi_driver driver_ni6527={ driver_name: "ni6527", module: THIS_MODULE, attach: ni6527_attach, detach: ni6527_detach,};COMEDI_INITCLEANUP(driver_ni6527);typedef struct{ int dev_id; char *name;}ni6527_board;static ni6527_board ni6527_boards[] = { { dev_id: 0x2b20, name: "pci-6527", }, { dev_id: 0x2b10, name: "pxi-6527", },};#define n_ni6527_boards (sizeof(ni6527_boards)/sizeof(ni6527_boards[0]))#define this_board ((ni6527_board *)dev->board_ptr)static struct pci_device_id ni6527_pci_table[] __devinitdata = { { PCI_VENDOR_ID_NATINST, 0x2b10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_NATINST, 0x2b20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0 }};MODULE_DEVICE_TABLE(pci, ni6527_pci_table);typedef struct{ struct mite_struct *mite; unsigned int filter_interval; unsigned int filter_enable;}ni6527_private;#define devpriv ((ni6527_private *)dev->private)static int ni6527_find_device(comedi_device *dev,int bus,int slot);static int ni6527_di_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ int chan = CR_CHAN(insn->chanspec); unsigned int interval; if(insn->n!=2)return -EINVAL; if(data[0] != INSN_CONFIG_FILTER)return -EINVAL; if(data[1]){ interval = (data[1]+100)/200; data[1] = interval*200; if(interval!=devpriv->filter_interval){ writeb(interval&0xff, dev->iobase + Filter_Interval(0)); writeb((interval>>8)&0xff, dev->iobase + Filter_Interval(1)); writeb((interval>>16)&0x0f, dev->iobase + Filter_Interval(1)); writeb(ClrInterval, dev->iobase + Clear_Register); devpriv->filter_interval = interval; } devpriv->filter_enable |= 1<<chan; }else{ devpriv->filter_enable &= ~(1<<chan); } writeb(devpriv->filter_enable, dev->iobase + Filter_Enable(0)); writeb(devpriv->filter_enable>>8, dev->iobase + Filter_Enable(1)); writeb(devpriv->filter_enable>>16, dev->iobase + Filter_Enable(2)); return 2;}static int ni6527_di_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ if(insn->n!=2)return -EINVAL; data[1] = readb(dev->iobase+Port_Register(0)); data[1] |= readb(dev->iobase+Port_Register(0))<<8; data[1] |= readb(dev->iobase+Port_Register(0))<<16; return 2;}static int ni6527_do_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ if(insn->n!=2)return -EINVAL; if(data[0]){ s->state &= ~data[0]; s->state |= (data[0]&data[1]); /* The open relay state on the board cooresponds to 1, * but in Comedi, it is represented by 0. */ if(data[0]&0x0000ff){ writeb((s->state^0xff),dev->iobase+Port_Register(3)); } if(data[0]&0x00ff00){ writeb((s->state>>8)^0xff,dev->iobase+Port_Register(4)); } if(data[0]&0xff0000){ writeb((s->state>>16)^0xff,dev->iobase+Port_Register(5)); } } data[1] = s->state; return 2;}static void ni6527_interrupt(int irq, void *d, struct pt_regs *regs){ comedi_device *dev = d; comedi_subdevice *s = dev->subdevices + 2; unsigned int status; status = readb(dev->iobase + Change_Status); if(!status&MasterInterruptStatus)return; if(!status&EdgeStatus)return; writeb(ClrEdge | ClrOverflow, dev->iobase + Clear_Register); comedi_buf_put(s->async, 0); s->async->events |= COMEDI_CB_EOS; comedi_event(dev,s,s->async->events);}static int ni6527_intr_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd){ int err=0; int tmp; /* step 1: make sure trigger sources are trivially valid */ tmp=cmd->start_src; cmd->start_src &= TRIG_NOW; if(!cmd->start_src || tmp!=cmd->start_src)err++; tmp=cmd->scan_begin_src; cmd->scan_begin_src &= TRIG_OTHER; if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++; tmp=cmd->convert_src; cmd->convert_src &= TRIG_FOLLOW; if(!cmd->convert_src || tmp!=cmd->convert_src)err++; tmp=cmd->scan_end_src; cmd->scan_end_src &= TRIG_COUNT; if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++; tmp=cmd->stop_src; cmd->stop_src &= TRIG_COUNT; if(!cmd->stop_src || tmp!=cmd->stop_src)err++; if(err)return 1; /* step 2: make sure trigger sources are unique and mutually compatible */ if(err)return 2; /* step 3: make sure arguments are trivially compatible */ if(cmd->start_arg!=0){ cmd->start_arg=0; err++; } if(cmd->scan_begin_arg!=0){ cmd->scan_begin_arg = 0; err++; } if(cmd->convert_arg!=0){ cmd->convert_arg = 0; err++; } if(cmd->scan_end_arg!=1){ cmd->scan_end_arg=1; err++; } if(cmd->stop_arg!=0){ cmd->stop_arg=0; err++; } if(err)return 3; /* step 4: fix up any arguments */ if(err)return 4; return 0;}static int ni6527_intr_cmd(comedi_device *dev,comedi_subdevice *s){ //comedi_cmd *cmd = &s->async->cmd; writeb(ClrEdge|ClrOverflow, dev->iobase + Clear_Register); writeb(FallingEdgeIntEnable|RisingEdgeIntEnable| MasterInterruptEnable|EdgeIntEnable, dev->iobase + Master_Interrupt_Control); return 0;}static int ni6527_intr_cancel(comedi_device *dev,comedi_subdevice *s){ writeb(0x00, dev->iobase + Master_Interrupt_Control); return 0;}static int ni6527_intr_insn_bits(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ if(insn->n < 1)return -EINVAL; data[1] = 0; return 2;}static int ni6527_intr_insn_config(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ if(insn->n < 1)return -EINVAL; if(data[0] != INSN_CONFIG_CHANGE_NOTIFY)return -EINVAL; writeb(data[1], dev->iobase + Rising_Edge_Detection_Enable(0)); writeb(data[1]>>8, dev->iobase + Rising_Edge_Detection_Enable(1)); writeb(data[1]>>16, dev->iobase + Rising_Edge_Detection_Enable(2)); writeb(data[2], dev->iobase + Falling_Edge_Detection_Enable(0)); writeb(data[2]>>8, dev->iobase + Falling_Edge_Detection_Enable(1)); writeb(data[2]>>16, dev->iobase + Falling_Edge_Detection_Enable(2)); return 2;}static int ni6527_attach(comedi_device *dev,comedi_devconfig *it){ comedi_subdevice *s; int ret; printk("comedi%d: ni6527:",dev->minor); if((ret=alloc_private(dev,sizeof(ni6527_private)))<0) return ret; ret=ni6527_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=this_board->name; dev->irq=mite_irq(devpriv->mite); printk(" %s",dev->board_name); printk(" ID=0x%02x", readb(dev->iobase + ID_Register)); if((ret=alloc_subdevices(dev,2))<0) return ret; s=dev->subdevices+0; s->type=COMEDI_SUBD_DI; s->subdev_flags=SDF_READABLE; s->n_chan=24; s->range_table=&range_digital; s->maxdata=1; s->insn_config = ni6527_di_insn_config; s->insn_bits = ni6527_di_insn_bits; s=dev->subdevices+1; s->type=COMEDI_SUBD_DO; s->subdev_flags=SDF_READABLE|SDF_WRITABLE; s->n_chan=24; s->range_table=&range_unknown; /* FIXME: actually conductance */ s->maxdata=1; s->insn_bits = ni6527_do_insn_bits; s=dev->subdevices + 2; dev->read_subdev = s; s->type=COMEDI_SUBD_DI; s->subdev_flags=SDF_READABLE; s->n_chan=1; s->range_table=&range_unknown; s->maxdata=1; s->do_cmdtest = ni6527_intr_cmdtest; s->do_cmd = ni6527_intr_cmd; s->cancel = ni6527_intr_cancel; s->insn_bits = ni6527_intr_insn_bits; s->insn_config = ni6527_intr_insn_config; writeb(0x00, dev->iobase + Filter_Enable(0)); writeb(0x00, dev->iobase + Filter_Enable(1)); writeb(0x00, dev->iobase + Filter_Enable(2)); writeb(ClrEdge|ClrOverflow|ClrFilter|ClrInterval, dev->iobase + Clear_Register); writeb(0x00, dev->iobase + Master_Interrupt_Control); ret=comedi_request_irq(dev->irq,ni6527_interrupt,SA_SHIRQ,"ni6527",dev); if(ret<0){ dev->irq=0; printk(" irq not available"); } printk("\n"); return 0;}static int ni6527_detach(comedi_device *dev){ if(dev->iobase){ writeb(0x00, dev->iobase + Master_Interrupt_Control); } if(dev->irq){ comedi_free_irq(dev->irq,dev); } if(devpriv && devpriv->mite){ mite_unsetup(devpriv->mite); } return 0;}static int ni6527_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_ni6527_boards;i++){ if(mite_device_id(mite)==ni6527_boards[i].dev_id){ dev->board_ptr = ni6527_boards + i; devpriv->mite=mite; return 0; } } } printk("no device found\n"); mite_list_devices(); return -EIO;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -