📄 cb_pcimdas.c
字号:
// request_mem_region(BADR0, BADR0_SIZE, "cb_pcimdas");// devpriv->BADR0 = BADR0; request_region(BADR1, BADR1_SIZE, "cb_pcimdas"); devpriv->BADR1 = BADR1; request_region(BADR2, BADR2_SIZE, "cb_pcimdas"); devpriv->BADR2 = BADR2; request_region(BADR3, BADR3_SIZE, "cb_pcimdas"); devpriv->BADR3 = BADR3; request_region(BADR4, BADR4_SIZE, "cb_pcimdas"); devpriv->BADR4 = BADR4;#ifdef CBPCIMDAS_DEBUG printk("devpriv->BADR0 = %d\n",devpriv->BADR0); printk("devpriv->BADR1 = %d\n",devpriv->BADR1); printk("devpriv->BADR2 = %d\n",devpriv->BADR2); printk("devpriv->BADR3 = %d\n",devpriv->BADR3); printk("devpriv->BADR4 = %d\n",devpriv->BADR4);#endif// Dont support IRQ yet// // get irq// if(comedi_request_irq(devpriv->pci_dev->irq, cb_pcimdas_interrupt, SA_SHIRQ, "cb_pcimdas", dev ))// {// printk(" unable to allocate irq %d\n", devpriv->pci_dev->irq);// return -EINVAL;// }// dev->irq = devpriv->pci_dev->irq; //Initialize dev->board_name dev->board_name = thisboard->name;/* * Allocate the subdevice structures. alloc_subdevice() is a * convenient macro defined in comedidev.h. */ if(alloc_subdevices(dev, 3)<0) return -ENOMEM; s=dev->subdevices+0; //dev->read_subdev=s; // analog input subdevice s->type=COMEDI_SUBD_AI; s->subdev_flags=SDF_READABLE|SDF_GROUND; s->n_chan=thisboard->ai_se_chans; s->maxdata=(1<<thisboard->ai_bits)-1; s->range_table=&range_unknown; s->len_chanlist=1; // This is the maximum chanlist length that // the board can handle s->insn_read = cb_pcimdas_ai_rinsn; s=dev->subdevices+1; // analog output subdevice s->type=COMEDI_SUBD_AO; s->subdev_flags=SDF_WRITABLE; s->n_chan=thisboard->ao_nchan; s->maxdata=1<<thisboard->ao_bits; s->range_table=&range_unknown; //ranges are hardware settable, but not software readable. s->insn_write = &cb_pcimdas_ao_winsn; s->insn_read = &cb_pcimdas_ao_rinsn; s=dev->subdevices+2; /* digital i/o subdevice */ if(thisboard->has_dio){ s->type=COMEDI_SUBD_DIO; s->subdev_flags=SDF_READABLE|SDF_WRITABLE; s->n_chan=thisboard->dio_bits; s->maxdata=1; s->range_table=&range_digital; s->insn_bits = cb_pcimdas_dio_insn_bits; s->insn_config = cb_pcimdas_dio_insn_config; }else{ s->type = COMEDI_SUBD_UNUSED; } printk("attached\n"); return 1;}/* * _detach is called to deconfigure a device. It should deallocate * resources. * This function is also called when _attach() fails, so it should be * careful not to release resources that were not necessarily * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */static int cb_pcimdas_detach(comedi_device *dev){#ifdef CBPCIMDAS_DEBUG printk("devpriv->BADR0 = %d\n",devpriv->BADR0); printk("devpriv->BADR1 = %d\n",devpriv->BADR1); printk("devpriv->BADR2 = %d\n",devpriv->BADR2); printk("devpriv->BADR3 = %d\n",devpriv->BADR3); printk("devpriv->BADR4 = %d\n",devpriv->BADR4);#endif printk("comedi%d: cb_pcimdas: remove\n",dev->minor); if(devpriv->BADR0) release_mem_region(devpriv->BADR0, BADR0_SIZE); if(devpriv->BADR1) release_region(devpriv->BADR1, BADR1_SIZE); if(devpriv->BADR2) release_region(devpriv->BADR2, BADR2_SIZE); if(devpriv->BADR3) release_region(devpriv->BADR3, BADR3_SIZE); if(devpriv->BADR4) release_region(devpriv->BADR4, BADR4_SIZE); if(dev->irq) comedi_free_irq(dev->irq, dev); return 0;}/* * "instructions" read/write data in "one-shot" or "software-triggered" * mode. */static int cb_pcimdas_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ int n,i; unsigned int d; unsigned int busy; int chan = CR_CHAN(insn->chanspec); unsigned short chanlims; int maxchans; // only support sw initiated reads from a single channel //check channel number if ((inb(devpriv->BADR3+2) & 0x20)==0) //differential mode maxchans=thisboard->ai_diff_chans; else maxchans=thisboard->ai_se_chans; if (chan>(maxchans-1)) return -ETIMEDOUT; //*** Wrong error code. Fixme. //configure for sw initiated read d=inb(devpriv->BADR3+5); if ((d & 0x03)>0) { //only reset if needed. d=d & 0xfd; outb(d,devpriv->BADR3+5); } outb(0x01,devpriv->BADR3+6); //set bursting off, conversions on outb(0x00,devpriv->BADR3+7); //set range to 10V. UP/BP is controlled by a switch on the board // write channel limits to multiplexer, set Low (bits 0-3) and High (bits 4-7) channels to chan. chanlims=chan | (chan<<4); outb(chanlims,devpriv->BADR3+0); /* convert n samples */ for(n=0;n<insn->n;n++){ /* trigger conversion */ outw(0,devpriv->BADR2+0);#define TIMEOUT 1000 //typically takes 5 loops on a lightly loaded Pentium 100MHz, //this is likely to be 100 loops on a 2GHz machine, so set 1000 as the limit. /* wait for conversion to end */ for(i=0;i<TIMEOUT;i++){ busy = inb(devpriv->BADR3+2)&0x80; if(!busy)break; } if(i==TIMEOUT){ printk("timeout\n"); return -ETIMEDOUT; } /* read data */ d = inw(devpriv->BADR2+0); /* mangle the data as necessary */ //d ^= 1<<(thisboard->ai_bits-1); // 16 bit data from ADC, so no mangle needed. data[n] = d; } /* return the number of samples read/written */ return n;}static int cb_pcimdas_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ int i; int chan = CR_CHAN(insn->chanspec); /* Writing a list of values to an AO channel is probably not * very useful, but that's how the interface is defined. */ for(i=0;i<insn->n;i++){ switch ( chan ) { case 0: outw(data[i] & 0x0FFF,devpriv->BADR2+DAC0_OFFSET); break; case 1: outw(data[i] & 0x0FFF,devpriv->BADR2+DAC1_OFFSET); break; default: return -1; } devpriv->ao_readback[chan] = data[i]; } /* return the number of samples read/written */ return i;}/* AO subdevices should have a read insn as well as a write insn. * Usually this means copying a value stored in devpriv. */static int cb_pcimdas_ao_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ int i; int chan = CR_CHAN(insn->chanspec); for(i=0;i<insn->n;i++) data[i] = devpriv->ao_readback[chan]; return i;}/* DIO devices are slightly special. Although it is possible to * implement the insn_read/insn_write interface, it is much more * useful to applications if you implement the insn_bits interface. * This allows packed reading/writing of the DIO channels. The * comedi core can convert between insn_bits and insn_read/write */static int cb_pcimdas_dio_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){// Much of this based on the 8255 driver. if(data[0]){ s->state &= ~data[0]; s->state |= (data[0]&data[1]); if(data[0]&PORT_A_MASK) { devpriv->port_a=s->state&0xff; outb(devpriv->port_a,devpriv->BADR4+PORT_A); } if(data[0]&PORT_B_MASK) { devpriv->port_b=(s->state>>8)&0xff; outb(devpriv->port_b,devpriv->BADR4+PORT_B); } if(data[0]&PORT_C_MASK) { devpriv->port_c=(s->state>>16)&0xff; outb(devpriv->port_c,devpriv->BADR4+PORT_C); } } data[1]=inb(devpriv->BADR4+PORT_A); data[1]|=(inb(devpriv->BADR4+PORT_B)<<8); data[1]|=(inb(devpriv->BADR4+PORT_C)<<16); return 2; //should this be 2?}static int cb_pcimdas_dio_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){// DIO config on this card is per port (or half port for port C), not per line. unsigned int mask; unsigned int bits; int config; mask=1<<CR_CHAN(insn->chanspec); if(mask&PORT_A_MASK){ bits=PORT_A_MASK; }else if(mask&PORT_B_MASK){ bits=PORT_B_MASK; }else if(mask&PORT_CL_MASK){ bits=PORT_CL_MASK; }else{ bits=PORT_CH_MASK; } switch(data[0]){ case COMEDI_INPUT: s->io_bits&=~bits; break; case COMEDI_OUTPUT: s->io_bits|=bits; break; default: return -EINVAL; } config=ALL_OUTPUT; /* 0 in io_bits indicates output, 1 in config indicates input */ if(!(s->io_bits&PORT_A_MASK)) config|=PORT_A_IN; if(!(s->io_bits&PORT_B_MASK)) config|=PORT_B_IN; if(!(s->io_bits&PORT_CL_MASK)) config|=PORT_CL_IN; if(!(s->io_bits&PORT_CH_MASK)) config|=PORT_CH_IN; outb(config,devpriv->BADR4+DIO_CONFIG); devpriv->dio_mode=config; return 1;} /* * A convenient macro that defines init_module() and cleanup_module(), * as necessary. */COMEDI_INITCLEANUP(driver_cb_pcimdas);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -