📄 adv_pci1710.c
字号:
/* * comedi/drivers/adv_pci1710.c * * Author: Michal Dobes <dobes@tesnet.cz> * * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn> * for testing and informations. * * hardware driver for Advantech cards: * card: PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720, PCI-1731 * driver: pci1710, pci1710hg, pci1711, pci1713, pci1720, pci1731 * * Options: * [0] - PCI bus number - if bus number and slot number are 0, * then driver search for first unused card * [1] - PCI slot number * *//*Driver: adv_pci1710.oDescription: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, Advantech PCI-1720, PCI-1731Author: Michal Dobes <dobes@tesnet.cz>Devices: [Advantech] PCI-1710 (pci1710), PCI-1710HG (pci1710hg), PCI-1711 (pci1711), PCI-1713 (pci1713), PCI-1720 (pci1720), PCI-1731 (pci1731)Status: worksThis driver supports AI, AO, DI and DO subdevices.AI subdevice supports cmd and insn interface,other subdevices support only insn interface.The PCI-1710 and PCI-1710HG have the same PCI device ID, so thedriver cannot distinguish between them, as would be normal for aPCI driver.Configuration options: [0] - PCI bus of device (optional) [1] - PCI slot of device (optional) If bus/slot is not specified, the first available PCI device will be used.*/#include <linux/comedidev.h>#include <linux/pci.h>#include "8253.h"#include "amcc_s5933.h"#define PCI171x_PARANOIDCHECK /* if defined, then is used code which control correct channel number on every 12 bit sample */#undef PCI171X_EXTDEBUG#undef DPRINTK#ifdef PCI171X_EXTDEBUG#define DPRINTK(fmt, args...) rt_printk(fmt, ## args)#else#define DPRINTK(fmt, args...)#endif// hardware types of the cards#define TYPE_PCI171X 0#define TYPE_PCI1713 2#define TYPE_PCI1720 3#define IORANGE_171x 32 #define IORANGE_1720 16 #define PCI171x_AD_DATA 0 /* R: A/D data */#define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */#define PCI171x_RANGE 2 /* W: A/D gain/range register */#define PCI171x_MUX 4 /* W: A/D multiplexor control */#define PCI171x_STATUS 6 /* R: status register */#define PCI171x_CONTROL 6 /* W: control register */#define PCI171x_CLRINT 8 /* W: clear interrupts request */#define PCI171x_CLRFIFO 9 /* W: clear FIFO */#define PCI171x_DA1 10 /* W: D/A register */#define PCI171x_DA2 12 /* W: D/A register */#define PCI171x_DAREF 14 /* W: D/A reference control */#define PCI171x_DI 16 /* R: digi inputs */#define PCI171x_DO 16 /* R: digi inputs */#define PCI171x_CNT0 24 /* R/W: 8254 couter 0 */#define PCI171x_CNT1 26 /* R/W: 8254 couter 1 */#define PCI171x_CNT2 28 /* R/W: 8254 couter 2 */#define PCI171x_CNTCTRL 30 /* W: 8254 counter control */// upper bits from status register (PCI171x_STATUS) (lower is same woth control reg)#define Status_FE 0x0100 /* 1=FIFO is empty */#define Status_FH 0x0200 /* 1=FIFO is half full */#define Status_FF 0x0400 /* 1=FIFO is full, fatal error */#define Status_IRQ 0x0800 /* 1=IRQ occured */// bits from control register (PCI171x_CONTROL)#define Control_CNT0 0x0040 /* 1=CNT0 have external source, 0=have internal 100kHz source */#define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */#define Control_IRQEN 0x0010 /* 1=enable IRQ */#define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */#define Control_EXT 0x0004 /* 1=external trigger source */#define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */#define Control_SW 0x0001 /* 1=enable software trigger source */#define PCI1720_DA0 0 /* W: D/A register 0 */#define PCI1720_DA1 2 /* W: D/A register 1 */#define PCI1720_DA2 4 /* W: D/A register 2 */#define PCI1720_DA3 6 /* W: D/A register 3 */#define PCI1720_RANGE 8 /* R/W: D/A range register */#define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */#define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */// D/A synchronized control (PCI1720_SYNCONT)#define Syncont_SC0 1 /* set synchronous output mode */static comedi_lrange range_pci1710_3={ 9, { BIP_RANGE(5), BIP_RANGE(2.5), BIP_RANGE(1.25), BIP_RANGE(0.625), BIP_RANGE(10), UNI_RANGE(10), UNI_RANGE(5), UNI_RANGE(2.5), UNI_RANGE(1.25) }};static char range_codes_pci1710_3[]={0x00, 0x01, 0x02, 0x03, 0x04, 0x10, 0x11, 0x12, 0x13 };static comedi_lrange range_pci1710hg={ 12, { BIP_RANGE(5), BIP_RANGE(0.5), BIP_RANGE(0.05), BIP_RANGE(0.005), BIP_RANGE(10), BIP_RANGE(1), BIP_RANGE(0.1), BIP_RANGE(0.01), UNI_RANGE(10), UNI_RANGE(1), UNI_RANGE(0.1), UNI_RANGE(0.01) }};static char range_codes_pci1710hg[]={0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13 };static comedi_lrange range_pci17x1={ 5, { BIP_RANGE(10), BIP_RANGE(5), BIP_RANGE(2.5), BIP_RANGE(1.25), BIP_RANGE(0.625) }};static char range_codes_pci17x1[]={0x00, 0x01, 0x02, 0x03, 0x04 };static comedi_lrange range_pci1720={ 4, { UNI_RANGE(5), UNI_RANGE(10), BIP_RANGE(5), BIP_RANGE(10) }};static comedi_lrange range_pci171x_da={ 2, { UNI_RANGE(5), UNI_RANGE(10), }};static int pci1710_attach(comedi_device *dev,comedi_devconfig *it);static int pci1710_detach(comedi_device *dev);static unsigned short pci_list_builded=0; /*=1 list of card is know */typedef struct { char *name; // driver name int device_id; int iorange; // I/O range len char have_irq; // 1=card support IRQ char cardtype; // 0=1710& co. 2=1713, ... int n_aichan; // num of A/D chans int n_aichand; // num of A/D chans in diff mode int n_aochan; // num of D/A chans int n_dichan; // num of DI chans int n_dochan; // num of DO chans int ai_maxdata; // resolution of A/D int ao_maxdata; // resolution of D/A comedi_lrange *rangelist_ai; // rangelist for A/D char *rangecode_ai; // range codes for programming comedi_lrange *rangelist_ao; // rangelist for D/A unsigned int ai_ns_min; // max sample speed of card v ns unsigned int fifo_half_size; // size of FIFO/2} boardtype;static struct pci_device_id pci1710_pci_table[] = __devinitdata { { PCI_VENDOR_ID_ADVANTECH, 0x1710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_ADVANTECH, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_ADVANTECH, 0x1713, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_ADVANTECH, 0x1720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_ADVANTECH, 0x1731, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0 }};MODULE_DEVICE_TABLE(pci, pci1710_pci_table);static boardtype boardtypes[] ={ {"pci1710", 0x1710, IORANGE_171x, 1, TYPE_PCI171X, 16, 8, 2, 16, 16, 0x0fff, 0x0fff, &range_pci1710_3, range_codes_pci1710_3, &range_pci171x_da, 10000, 2048 }, {"pci1710hg", 0x1710, IORANGE_171x, 1, TYPE_PCI171X, 16, 8, 2, 16, 16, 0x0fff, 0x0fff, &range_pci1710hg, range_codes_pci1710hg, &range_pci171x_da, 10000, 2048 }, {"pci1711", 0x1711, IORANGE_171x, 1, TYPE_PCI171X, 16, 0, 2, 16, 16, 0x0fff, 0x0fff, &range_pci17x1, range_codes_pci17x1, &range_pci171x_da, 10000, 512 }, {"pci1713", 0x1713, IORANGE_171x, 1, TYPE_PCI1713, 32,16, 0, 0, 0, 0x0fff, 0x0000, &range_pci17x1, range_codes_pci1710_3, NULL, 10000, 2048 }, {"pci1720", 0x1720, IORANGE_1720, 0, TYPE_PCI1720, 0, 0, 4, 0, 0, 0x0000, 0x0fff, NULL, NULL, &range_pci1720, 0, 0 }, {"pci1731", 0x1731, IORANGE_171x, 1, TYPE_PCI171X, 16, 0, 0, 16, 16, 0x0fff, 0x0000, &range_pci17x1, range_codes_pci17x1, NULL, 10000, 512 },};#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))static comedi_driver driver_pci1710={ driver_name: "adv_pci1710", module: THIS_MODULE, attach: pci1710_attach, detach: pci1710_detach, num_names: n_boardtypes, board_name: boardtypes, offset: sizeof(boardtype),};typedef struct{ char valid; // card is usable char neverending_ai; // we do unlimited AI unsigned int CntrlReg; // Control register unsigned int i8254_osc_base; // frequence of onboard oscilator unsigned int ai_do; // what do AI? 0=nothing, 1 to 4 mode unsigned int ai_act_scan;// how many scans we finished unsigned int ai_act_chan;// actual position in actual scan unsigned int ai_buf_ptr; // data buffer ptr in samples unsigned char ai_eos; // 1=EOS wake up unsigned char ai_et; unsigned int ai_et_CntrlReg; unsigned int ai_et_MuxVal; unsigned int ai_et_div1, ai_et_div2; unsigned int act_chanlist[32];// list of scaned channel unsigned char act_chanlist_len;// len of scanlist unsigned char act_chanlist_pos;// actual position in MUX list unsigned char da_ranges; // copy of D/A outpit range register unsigned int ai_scans; // len of scanlist unsigned int ai_n_chan; // how many channels is measured unsigned int *ai_chanlist; // actaul chanlist unsigned int ai_flags; // flaglist unsigned int ai_data_len; // len of data buffer sampl_t *ai_data; // data buffer unsigned int ai_timer1; // timers unsigned int ai_timer2; sampl_t ao_data[4]; // data output buffer} pci1710_private;#define devpriv ((pci1710_private *)dev->private)#define this_board ((boardtype *)dev->board_ptr)/* ==============================================================================*/static int check_channel_list(comedi_device * dev, comedi_subdevice * s, unsigned int *chanlist, unsigned int n_chan);static void setup_channel_list(comedi_device * dev, comedi_subdevice * s, unsigned int *chanlist, unsigned int n_chan, unsigned int seglen);static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2);static int pci1710_reset(comedi_device *dev);static int pci171x_ai_cancel(comedi_device * dev, comedi_subdevice * s);static unsigned int muxonechan[] ={ 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, // used for gain list programming 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f, 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717, 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f};/* ==============================================================================*/static int pci171x_insn_read_ai(comedi_device * dev, comedi_subdevice * s, comedi_insn *insn, lsampl_t *data) { int n,timeout;#ifdef PCI171x_PARANOIDCHECK unsigned int idata;#endif DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n"); devpriv->CntrlReg&=Control_CNT0; devpriv->CntrlReg|=Control_SW; // set software trigger outw(devpriv->CntrlReg, dev->iobase+PCI171x_CONTROL); outb(0,dev->iobase + PCI171x_CLRFIFO); outb(0,dev->iobase + PCI171x_CLRINT); setup_channel_list(dev,s,&insn->chanspec, 1, 1); DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",inw(dev->iobase+PCI171x_STATUS), dev->iobase+PCI171x_STATUS); for (n=0; n<insn->n; n++) { outw(0, dev->iobase+PCI171x_SOFTTRG); /* start conversion */ DPRINTK("adv_pci1710 B n=%d ST=%4x\n",n,inw(dev->iobase+PCI171x_STATUS)); //comedi_udelay(1); DPRINTK("adv_pci1710 C n=%d ST=%4x\n",n,inw(dev->iobase+PCI171x_STATUS)); timeout=100; while (timeout--) { if (!(inw(dev->iobase+PCI171x_STATUS) & Status_FE)) goto conv_finish; if (!(timeout%10)) DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n",n,timeout,inw(dev->iobase+PCI171x_STATUS)); } comedi_error(dev,"A/D insn timeout"); outb(0,dev->iobase + PCI171x_CLRFIFO); outb(0,dev->iobase + PCI171x_CLRINT); data[n]=0; DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",n); return -ETIME;conv_finish:#ifdef PCI171x_PARANOIDCHECK idata=inw(dev->iobase+PCI171x_AD_DATA); if (this_board->cardtype!=TYPE_PCI1713) if ((idata & 0xf000)!=devpriv->act_chanlist[0]) { comedi_error(dev,"A/D insn data droput!"); return -ETIME; } data[n] = idata & 0x0fff; #else data[n] = inw(dev->iobase+PCI171x_AD_DATA) & 0x0fff; #endif } outb(0,dev->iobase + PCI171x_CLRFIFO); outb(0,dev->iobase + PCI171x_CLRINT); DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",n); return n;}/* ==============================================================================*/static int pci171x_insn_write_ao(comedi_device * dev, comedi_subdevice * s, comedi_insn *insn, lsampl_t *data) { int n,chan,range,ofs; chan=CR_CHAN(insn->chanspec); range=CR_RANGE(insn->chanspec); if (chan) { devpriv->da_ranges&=0xfb; devpriv->da_ranges|=(range<<2); outw(devpriv->da_ranges, dev->iobase+PCI171x_DAREF); ofs=PCI171x_DA2; } else { devpriv->da_ranges&=0xfe; devpriv->da_ranges|=range; outw(devpriv->da_ranges, dev->iobase+PCI171x_DAREF); ofs=PCI171x_DA1; } for (n=0; n<insn->n; n++) outw(data[n], dev->iobase + ofs); devpriv->ao_data[chan]=data[n]; return n;}/* ==============================================================================*/static int pci171x_insn_read_ao(comedi_device * dev, comedi_subdevice * s, comedi_insn *insn, lsampl_t *data) { int n,chan; chan=CR_CHAN(insn->chanspec); for (n=0; n<insn->n; n++) data[n]=devpriv->ao_data[chan]; return n;}/*==============================================================================*/static int pci171x_insn_bits_di(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ data[1] = inw(dev->iobase + PCI171x_DI); return 2;}/*==============================================================================*/static int pci171x_insn_bits_do(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ if(data[0]){ s->state &= ~data[0]; s->state |= (data[0]&data[1]); outw(s->state, dev->iobase + PCI171x_DO); } data[1] = s->state; return 2;}/* ==============================================================================*/static int pci1720_insn_write_ao(comedi_device * dev, comedi_subdevice * s, comedi_insn *insn, lsampl_t *data) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -