![]() |
RTXI 1.3
|
00001 /* 00002 * comedi/drivers/adl_pci9118.c 00003 * 00004 * hardware driver for ADLink cards: 00005 * card: PCI-9118DG, PCI-9118HG, PCI-9118HR 00006 * driver: pci9118dg, pci9118hg, pci9118hr 00007 * 00008 * Author: Michal Dobes <dobes@tesnet.cz> 00009 * 00010 */ 00011 /* 00012 Driver: adl_pci9118 00013 Description: Adlink PCI-9118DG, PCI-9118HG, PCI-9118HR 00014 Author: Michal Dobes <dobes@tesnet.cz> 00015 Devices: [ADLink] PCI-9118DG (pci9118dg), PCI-9118HG (pci9118hg), 00016 PCI-9118HR (pci9118hr) 00017 Status: works 00018 00019 This driver supports AI, AO, DI and DO subdevices. 00020 AI subdevice supports cmd and insn interface, 00021 other subdevices support only insn interface. 00022 For AI: 00023 - If cmd->scan_begin_src=TRIG_EXT then trigger input is TGIN (pin 46). 00024 - If cmd->convert_src=TRIG_EXT then trigger input is EXTTRG (pin 44). 00025 - If cmd->start_src/stop_src=TRIG_EXT then trigger input is TGIN (pin 46). 00026 - It is not neccessary to have cmd.scan_end_arg=cmd.chanlist_len but 00027 cmd.scan_end_arg modulo cmd.chanlist_len must by 0. 00028 - If return value of cmdtest is 5 then you've bad channel list 00029 (it isn't possible mixture S.E. and DIFF inputs or bipolar and unipolar 00030 ranges). 00031 00032 There are some hardware limitations: 00033 a) You cann't use mixture of unipolar/bipoar ranges or differencial/single 00034 ended inputs. 00035 b) DMA transfers must have the length aligned to two samples (32 bit), 00036 so there is some problems if cmd->chanlist_len is odd. This driver tries 00037 bypass this with adding one sample to the end of the every scan and discard 00038 it on output but this cann't be used if cmd->scan_begin_src=TRIG_FOLLOW 00039 and is used flag TRIG_WAKE_EOS, then driver switch to interrupt driven mode 00040 with interrupt after every sample. 00041 c) If isn't used DMA then you can use only mode where 00042 cmd->scan_begin_src=TRIG_FOLLOW. 00043 00044 Configuration options: 00045 [0] - PCI bus of device (optional) 00046 [1] - PCI slot of device (optional) 00047 If bus/slot is not specified, then first available PCI 00048 card will be used. 00049 [2] - 0= standard 8 DIFF/16 SE channels configuration 00050 n= external multiplexer connected, 1<=n<=256 00051 [3] - 0=autoselect DMA or EOC interrupts operation 00052 1=disable DMA mode 00053 3=disable DMA and INT, only insn interface will work 00054 [4] - sample&hold signal - card can generate signal for external S&H board 00055 0=use SSHO (pin 45) signal is generated in onboard hardware S&H logic 00056 0!=use ADCHN7 (pin 23) signal is generated from driver, number 00057 say how long delay is requested in ns and sign polarity of the hold 00058 (in this case external multiplexor can serve only 128 channels) 00059 [5] - 0=stop measure on all hardware errors 00060 2|=ignore ADOR - A/D Overrun status 00061 8|=ignore Bover - A/D Burst Mode Overrun status 00062 256|=ignore nFull - A/D FIFO Full status 00063 00064 */ 00065 #include <linux/comedidev.h> 00066 00067 #include <linux/delay.h> 00068 00069 #include "amcc_s5933.h" 00070 #include "8253.h" 00071 #include "comedi_pci.h" 00072 #include "comedi_fc.h" 00073 00074 /* paranoid checks are broken */ 00075 #undef PCI9118_PARANOIDCHECK /* if defined, then is used code which control correct channel number on every 12 bit sample */ 00076 00077 #undef PCI9118_EXTDEBUG /* if defined then driver prints a lot of messages */ 00078 00079 #undef DPRINTK 00080 #ifdef PCI9118_EXTDEBUG 00081 #define DPRINTK(fmt, args...) rt_printk(fmt, ## args) 00082 #else 00083 #define DPRINTK(fmt, args...) 00084 #endif 00085 00086 #define IORANGE_9118 64 /* I hope */ 00087 #define PCI9118_CHANLEN 255 /* len of chanlist, some source say 256, but reality looks like 255 :-( */ 00088 00089 #define PCI9118_CNT0 0x00 /* R/W: 8254 couter 0 */ 00090 #define PCI9118_CNT1 0x04 /* R/W: 8254 couter 0 */ 00091 #define PCI9118_CNT2 0x08 /* R/W: 8254 couter 0 */ 00092 #define PCI9118_CNTCTRL 0x0c /* W: 8254 counter control */ 00093 #define PCI9118_AD_DATA 0x10 /* R: A/D data */ 00094 #define PCI9118_DA1 0x10 /* W: D/A registers */ 00095 #define PCI9118_DA2 0x14 00096 #define PCI9118_ADSTAT 0x18 /* R: A/D status register */ 00097 #define PCI9118_ADCNTRL 0x18 /* W: A/D control register */ 00098 #define PCI9118_DI 0x1c /* R: digi input register */ 00099 #define PCI9118_DO 0x1c /* W: digi output register */ 00100 #define PCI9118_SOFTTRG 0x20 /* W: soft trigger for A/D */ 00101 #define PCI9118_GAIN 0x24 /* W: A/D gain/channel register */ 00102 #define PCI9118_BURST 0x28 /* W: A/D burst number register */ 00103 #define PCI9118_SCANMOD 0x2c /* W: A/D auto scan mode */ 00104 #define PCI9118_ADFUNC 0x30 /* W: A/D function register */ 00105 #define PCI9118_DELFIFO 0x34 /* W: A/D data FIFO reset */ 00106 #define PCI9118_INTSRC 0x38 /* R: interrupt reason register */ 00107 #define PCI9118_INTCTRL 0x38 /* W: interrupt control register */ 00108 00109 // bits from A/D control register (PCI9118_ADCNTRL) 00110 #define AdControl_UniP 0x80 /* 1=bipolar, 0=unipolar */ 00111 #define AdControl_Diff 0x40 /* 1=differential, 0= single end inputs */ 00112 #define AdControl_SoftG 0x20 /* 1=8254 counter works, 0=counter stops */ 00113 #define AdControl_ExtG 0x10 /* 1=8254 countrol controlled by TGIN(pin 46), 0=controled by SoftG */ 00114 #define AdControl_ExtM 0x08 /* 1=external hardware trigger (pin 44), 0=internal trigger */ 00115 #define AdControl_TmrTr 0x04 /* 1=8254 is iternal trigger source, 0=software trigger is source (register PCI9118_SOFTTRG) */ 00116 #define AdControl_Int 0x02 /* 1=enable INT, 0=disable */ 00117 #define AdControl_Dma 0x01 /* 1=enable DMA, 0=disable */ 00118 00119 // bits from A/D function register (PCI9118_ADFUNC) 00120 #define AdFunction_PDTrg 0x80 /* 1=positive, 0=negative digital trigger (only positive is correct) */ 00121 #define AdFunction_PETrg 0x40 /* 1=positive, 0=negative external trigger (only positive is correct) */ 00122 #define AdFunction_BSSH 0x20 /* 1=with sample&hold, 0=without */ 00123 #define AdFunction_BM 0x10 /* 1=burst mode, 0=normal mode */ 00124 #define AdFunction_BS 0x08 /* 1=burst mode start, 0=burst mode stop */ 00125 #define AdFunction_PM 0x04 /* 1=post trigger mode, 0=not post trigger */ 00126 #define AdFunction_AM 0x02 /* 1=about trigger mode, 0=not about trigger */ 00127 #define AdFunction_Start 0x01 /* 1=trigger start, 0=trigger stop */ 00128 00129 // bits from A/D status register (PCI9118_ADSTAT) 00130 #define AdStatus_nFull 0x100 /* 0=FIFO full (fatal), 1=not full */ 00131 #define AdStatus_nHfull 0x080 /* 0=FIFO half full, 1=FIFO not half full */ 00132 #define AdStatus_nEpty 0x040 /* 0=FIFO empty, 1=FIFO not empty */ 00133 #define AdStatus_Acmp 0x020 /* */ 00134 #define AdStatus_DTH 0x010 /* 1=external digital trigger */ 00135 #define AdStatus_Bover 0x008 /* 1=burst mode overrun (fatal) */ 00136 #define AdStatus_ADOS 0x004 /* 1=A/D over speed (warning) */ 00137 #define AdStatus_ADOR 0x002 /* 1=A/D overrun (fatal) */ 00138 #define AdStatus_ADrdy 0x001 /* 1=A/D already ready, 0=not ready */ 00139 00140 // bits for interrupt reason and control (PCI9118_INTSRC, PCI9118_INTCTRL) 00141 // 1=interrupt occur, enable source, 0=interrupt not occur, disable source 00142 #define Int_Timer 0x08 /* timer interrupt */ 00143 #define Int_About 0x04 /* about trigger complete */ 00144 #define Int_Hfull 0x02 /* A/D FIFO hlaf full */ 00145 #define Int_DTrg 0x01 /* external digital trigger */ 00146 00147 #define START_AI_EXT 0x01 /* start measure on external trigger */ 00148 #define STOP_AI_EXT 0x02 /* stop measure on external trigger */ 00149 #define START_AI_INT 0x04 /* start measure on internal trigger */ 00150 #define STOP_AI_INT 0x08 /* stop measure on internal trigger */ 00151 00152 #define EXTTRG_AI 0 /* ext trg is used by AI */ 00153 00154 static const comedi_lrange range_pci9118dg_hr = { 8, { 00155 BIP_RANGE(5), 00156 BIP_RANGE(2.5), 00157 BIP_RANGE(1.25), 00158 BIP_RANGE(0.625), 00159 UNI_RANGE(10), 00160 UNI_RANGE(5), 00161 UNI_RANGE(2.5), 00162 UNI_RANGE(1.25) 00163 } 00164 }; 00165 00166 static const comedi_lrange range_pci9118hg = { 8, { 00167 BIP_RANGE(5), 00168 BIP_RANGE(0.5), 00169 BIP_RANGE(0.05), 00170 BIP_RANGE(0.005), 00171 UNI_RANGE(10), 00172 UNI_RANGE(1), 00173 UNI_RANGE(0.1), 00174 UNI_RANGE(0.01) 00175 } 00176 }; 00177 00178 #define PCI9118_BIPOLAR_RANGES 4 /* used for test on mixture of BIP/UNI ranges */ 00179 00180 static int pci9118_attach(comedi_device * dev, comedi_devconfig * it); 00181 static int pci9118_detach(comedi_device * dev); 00182 00183 typedef struct { 00184 const char *name; // board name 00185 int vendor_id; // PCI vendor a device ID of card 00186 int device_id; 00187 int iorange_amcc; // iorange for own S5933 region 00188 int iorange_9118; // pass thru card region size 00189 int n_aichan; // num of A/D chans 00190 int n_aichand; // num of A/D chans in diff mode 00191 int mux_aichan; // num of A/D chans with external multiplexor 00192 int n_aichanlist; // len of chanlist 00193 int n_aochan; // num of D/A chans 00194 int ai_maxdata; // resolution of A/D 00195 int ao_maxdata; // resolution of D/A 00196 const comedi_lrange *rangelist_ai; // rangelist for A/D 00197 const comedi_lrange *rangelist_ao; // rangelist for D/A 00198 unsigned int ai_ns_min; // max sample speed of card v ns 00199 unsigned int ai_pacer_min; // minimal pacer value (c1*c2 or c1 in burst) 00200 int half_fifo_size; // size of FIFO/2 00201 00202 } boardtype; 00203 00204 static DEFINE_PCI_DEVICE_TABLE(pci9118_pci_table) = { 00205 {PCI_VENDOR_ID_AMCC, 0x80d9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 00206 {0} 00207 }; 00208 00209 MODULE_DEVICE_TABLE(pci, pci9118_pci_table); 00210 00211 static const boardtype boardtypes[] = { 00212 {"pci9118dg", PCI_VENDOR_ID_AMCC, 0x80d9, 00213 AMCC_OP_REG_SIZE, IORANGE_9118, 00214 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff, 00215 &range_pci9118dg_hr, &range_bipolar10, 00216 3000, 12, 512}, 00217 {"pci9118hg", PCI_VENDOR_ID_AMCC, 0x80d9, 00218 AMCC_OP_REG_SIZE, IORANGE_9118, 00219 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff, 00220 &range_pci9118hg, &range_bipolar10, 00221 3000, 12, 512}, 00222 {"pci9118hr", PCI_VENDOR_ID_AMCC, 0x80d9, 00223 AMCC_OP_REG_SIZE, IORANGE_9118, 00224 16, 8, 256, PCI9118_CHANLEN, 2, 0xffff, 0x0fff, 00225 &range_pci9118dg_hr, &range_bipolar10, 00226 10000, 40, 512}, 00227 }; 00228 00229 #define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype)) 00230 00231 static comedi_driver driver_pci9118 = { 00232 driver_name:"adl_pci9118", 00233 module:THIS_MODULE, 00234 attach:pci9118_attach, 00235 detach:pci9118_detach, 00236 num_names:n_boardtypes, 00237 board_name:&boardtypes[0].name, 00238 offset:sizeof(boardtype), 00239 }; 00240 00241 COMEDI_PCI_INITCLEANUP(driver_pci9118, pci9118_pci_table); 00242 00243 typedef struct { 00244 unsigned long iobase_a; // base+size for AMCC chip 00245 unsigned int master; // master capable 00246 struct pci_dev *pcidev; // ptr to actual pcidev 00247 unsigned int usemux; // we want to use external multiplexor! 00248 #ifdef PCI9118_PARANOIDCHECK 00249 unsigned short chanlist[PCI9118_CHANLEN + 1]; // list of scaned channel 00250 unsigned char chanlistlen; // number of scanlist 00251 #endif 00252 unsigned char AdControlReg; // A/D control register 00253 unsigned char IntControlReg; // Interrupt control register 00254 unsigned char AdFunctionReg; // A/D function register 00255 char valid; // driver is ok 00256 char ai_neverending; // we do unlimited AI 00257 unsigned int i8254_osc_base; // frequence of onboard oscilator 00258 unsigned int ai_do; // what do AI? 0=nothing, 1 to 4 mode 00259 unsigned int ai_act_scan; // how many scans we finished 00260 unsigned int ai_buf_ptr; // data buffer ptr in samples 00261 unsigned int ai_n_chan; // how many channels is measured 00262 unsigned int ai_n_scanlen; // len of actual scanlist 00263 unsigned int ai_n_realscanlen; // what we must transfer for one outgoing scan include front/back adds 00264 unsigned int ai_act_dmapos; // position in actual real stream 00265 unsigned int ai_add_front; // how many channels we must add before scan to satisfy S&H? 00266 unsigned int ai_add_back; // how many channels we must add before scan to satisfy DMA? 00267 unsigned int *ai_chanlist; // actaul chanlist 00268 unsigned int ai_timer1; 00269 unsigned int ai_timer2; 00270 unsigned int ai_flags; 00271 char ai12_startstop; // measure can start/stop on external trigger 00272 unsigned int ai_divisor1, ai_divisor2; // divisors for start of measure on external start 00273 unsigned int ai_data_len; 00274 sampl_t *ai_data; 00275 sampl_t ao_data[2]; // data output buffer 00276 unsigned int ai_scans; // number of scans to do 00277 char dma_doublebuf; // we can use double buffring 00278 unsigned int dma_actbuf; // which buffer is used now 00279 sampl_t *dmabuf_virt[2]; // pointers to begin of DMA buffer 00280 unsigned long dmabuf_hw[2]; // hw address of DMA buff 00281 unsigned int dmabuf_size[2]; // size of dma buffer in bytes 00282 unsigned int dmabuf_use_size[2]; // which size we may now used for transfer 00283 unsigned int dmabuf_used_size[2]; // which size was trully used 00284 unsigned int dmabuf_panic_size[2]; 00285 unsigned int dmabuf_samples[2]; // size in samples 00286 int dmabuf_pages[2]; // number of pages in buffer 00287 unsigned char cnt0_users; // bit field of 8254 CNT0 users (0-unused, 1-AO, 2-DI, 3-DO) 00288 unsigned char exttrg_users; // bit field of external trigger users (0-AI, 1-AO, 2-DI, 3-DO) 00289 unsigned int cnt0_divisor; // actual CNT0 divisor 00290 void (*int_ai_func) (comedi_device *, comedi_subdevice *, unsigned short, unsigned int, unsigned short); // ptr to actual interrupt AI function 00291 unsigned char ai16bits; // =1 16 bit card 00292 unsigned char usedma; // =1 use DMA transfer and not INT 00293 unsigned char useeoshandle; // =1 change WAKE_EOS DMA transfer to fit on every second 00294 unsigned char usessh; // =1 turn on S&H support 00295 int softsshdelay; // >0 use software S&H, numer is requested delay in ns 00296 unsigned char softsshsample; // polarity of S&H signal in sample state 00297 unsigned char softsshhold; // polarity of S&H signal in hold state 00298 unsigned int ai_maskerr; // which warning was printed 00299 unsigned int ai_maskharderr; // on which error bits stops 00300 unsigned int ai_inttrig_start; // TRIG_INT for start 00301 } pci9118_private; 00302 00303 #define devpriv ((pci9118_private *)dev->private) 00304 #define this_board ((boardtype *)dev->board_ptr) 00305 00306 /* 00307 ============================================================================== 00308 */ 00309 00310 static int check_channel_list(comedi_device * dev, comedi_subdevice * s, 00311 int n_chan, unsigned int *chanlist, int frontadd, int backadd); 00312 static int setup_channel_list(comedi_device * dev, comedi_subdevice * s, 00313 int n_chan, unsigned int *chanlist, int rot, int frontadd, int backadd, 00314 int usedma, char eoshandle); 00315 static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, 00316 unsigned int divisor2); 00317 static int pci9118_reset(comedi_device * dev); 00318 static int pci9118_exttrg_add(comedi_device * dev, unsigned char source); 00319 static int pci9118_exttrg_del(comedi_device * dev, unsigned char source); 00320 static int pci9118_ai_cancel(comedi_device * dev, comedi_subdevice * s); 00321 static void pci9118_calc_divisors(char mode, comedi_device * dev, 00322 comedi_subdevice * s, unsigned int *tim1, unsigned int *tim2, 00323 unsigned int flags, int chans, unsigned int *div1, unsigned int *div2, 00324 char usessh, unsigned int chnsshfront); 00325 00326 /* 00327 ============================================================================== 00328 */ 00329 static int pci9118_insn_read_ai(comedi_device * dev, comedi_subdevice * s, 00330 comedi_insn * insn, lsampl_t * data) 00331 { 00332 00333 int n, timeout; 00334 00335 devpriv->AdControlReg = AdControl_Int & 0xff; 00336 devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; 00337 outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); // positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop 00338 00339 if (!setup_channel_list(dev, s, 1, &insn->chanspec, 0, 0, 0, 0, 0)) 00340 return -EINVAL; 00341 00342 outl(0, dev->iobase + PCI9118_DELFIFO); // flush FIFO 00343 00344 for (n = 0; n < insn->n; n++) { 00345 outw(0, dev->iobase + PCI9118_SOFTTRG); /* start conversion */ 00346 comedi_udelay(2); 00347 timeout = 100; 00348 while (timeout--) { 00349 if (inl(dev->iobase + PCI9118_ADSTAT) & AdStatus_ADrdy) 00350 goto conv_finish; 00351 comedi_udelay(1); 00352 } 00353 00354 comedi_error(dev, "A/D insn timeout"); 00355 data[n] = 0; 00356 outl(0, dev->iobase + PCI9118_DELFIFO); // flush FIFO 00357 return -ETIME; 00358 00359 conv_finish: 00360 if (devpriv->ai16bits) { 00361 data[n] = 00362 (inl(dev->iobase + 00363 PCI9118_AD_DATA) & 0xffff) ^ 0x8000; 00364 } else { 00365 data[n] = 00366 (inw(dev->iobase + 00367 PCI9118_AD_DATA) >> 4) & 0xfff; 00368 } 00369 } 00370 00371 outl(0, dev->iobase + PCI9118_DELFIFO); // flush FIFO 00372 return n; 00373 00374 } 00375 00376 /* 00377 ============================================================================== 00378 */ 00379 static int pci9118_insn_write_ao(comedi_device * dev, comedi_subdevice * s, 00380 comedi_insn * insn, lsampl_t * data) 00381 { 00382 int n, chanreg, ch; 00383 00384 ch = CR_CHAN(insn->chanspec); 00385 if (ch) { 00386 chanreg = PCI9118_DA2; 00387 } else { 00388 chanreg = PCI9118_DA1; 00389 } 00390 00391 for (n = 0; n < insn->n; n++) { 00392 outl(data[n], dev->iobase + chanreg); 00393 devpriv->ao_data[ch] = data[n]; 00394 } 00395 00396 return n; 00397 } 00398 00399 /* 00400 ============================================================================== 00401 */ 00402 static int pci9118_insn_read_ao(comedi_device * dev, comedi_subdevice * s, 00403 comedi_insn * insn, lsampl_t * data) 00404 { 00405 int n, chan; 00406 00407 chan = CR_CHAN(insn->chanspec); 00408 for (n = 0; n < insn->n; n++) 00409 data[n] = devpriv->ao_data[chan]; 00410 00411 return n; 00412 } 00413 00414 /* 00415 ============================================================================== 00416 */ 00417 static int pci9118_insn_bits_di(comedi_device * dev, comedi_subdevice * s, 00418 comedi_insn * insn, lsampl_t * data) 00419 { 00420 data[1] = inl(dev->iobase + PCI9118_DI) & 0xf; 00421 00422 return 2; 00423 } 00424 00425 /* 00426 ============================================================================== 00427 */ 00428 static int pci9118_insn_bits_do(comedi_device * dev, comedi_subdevice * s, 00429 comedi_insn * insn, lsampl_t * data) 00430 { 00431 if (data[0]) { 00432 s->state &= ~data[0]; 00433 s->state |= (data[0] & data[1]); 00434 outl(s->state & 0x0f, dev->iobase + PCI9118_DO); 00435 } 00436 data[1] = s->state; 00437 00438 return 2; 00439 } 00440 00441 /* 00442 ============================================================================== 00443 */ 00444 static void interrupt_pci9118_ai_mode4_switch(comedi_device * dev) 00445 { 00446 devpriv->AdFunctionReg = 00447 AdFunction_PDTrg | AdFunction_PETrg | AdFunction_AM; 00448 outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); 00449 outl(0x30, dev->iobase + PCI9118_CNTCTRL); 00450 outl((devpriv->dmabuf_hw[1 - devpriv->dma_actbuf] >> 1) & 0xff, 00451 dev->iobase + PCI9118_CNT0); 00452 outl((devpriv->dmabuf_hw[1 - devpriv->dma_actbuf] >> 9) & 0xff, 00453 dev->iobase + PCI9118_CNT0); 00454 devpriv->AdFunctionReg |= AdFunction_Start; 00455 outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); 00456 } 00457 00458 static unsigned int defragment_dma_buffer(comedi_device * dev, 00459 comedi_subdevice * s, sampl_t * dma_buffer, unsigned int num_samples) 00460 { 00461 unsigned int i = 0, j = 0; 00462 unsigned int start_pos = devpriv->ai_add_front, 00463 stop_pos = devpriv->ai_add_front + devpriv->ai_n_chan; 00464 unsigned int raw_scanlen = devpriv->ai_add_front + devpriv->ai_n_chan + 00465 devpriv->ai_add_back; 00466 00467 for (i = 0; i < num_samples; i++) { 00468 if (devpriv->ai_act_dmapos >= start_pos && 00469 devpriv->ai_act_dmapos < stop_pos) { 00470 dma_buffer[j++] = dma_buffer[i]; 00471 } 00472 devpriv->ai_act_dmapos++; 00473 devpriv->ai_act_dmapos %= raw_scanlen; 00474 } 00475 00476 return j; 00477 } 00478 00479 /* 00480 ============================================================================== 00481 */ 00482 static unsigned int move_block_from_dma(comedi_device * dev, 00483 comedi_subdevice * s, sampl_t * dma_buffer, unsigned int num_samples) 00484 { 00485 unsigned int num_bytes; 00486 00487 num_samples = defragment_dma_buffer(dev, s, dma_buffer, num_samples); 00488 devpriv->ai_act_scan += 00489 (s->async->cur_chan + num_samples) / devpriv->ai_n_scanlen; 00490 s->async->cur_chan += num_samples; 00491 s->async->cur_chan %= devpriv->ai_n_scanlen; 00492 num_bytes = 00493 cfc_write_array_to_buffer(s, dma_buffer, 00494 num_samples * sizeof(sampl_t)); 00495 if (num_bytes < num_samples * sizeof(sampl_t)) 00496 return -1; 00497 return 0; 00498 } 00499 00500 /* 00501 ============================================================================== 00502 */ 00503 static char pci9118_decode_error_status(comedi_device * dev, 00504 comedi_subdevice * s, unsigned char m) 00505 { 00506 if (m & 0x100) { 00507 comedi_error(dev, "A/D FIFO Full status (Fatal Error!)"); 00508 devpriv->ai_maskerr &= ~0x100L; 00509 } 00510 if (m & 0x008) { 00511 comedi_error(dev, 00512 "A/D Burst Mode Overrun Status (Fatal Error!)"); 00513 devpriv->ai_maskerr &= ~0x008L; 00514 } 00515 if (m & 0x004) { 00516 comedi_error(dev, "A/D Over Speed Status (Warning!)"); 00517 devpriv->ai_maskerr &= ~0x004L; 00518 } 00519 if (m & 0x002) { 00520 comedi_error(dev, "A/D Overrun Status (Fatal Error!)"); 00521 devpriv->ai_maskerr &= ~0x002L; 00522 } 00523 if (m & devpriv->ai_maskharderr) { 00524 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; 00525 pci9118_ai_cancel(dev, s); 00526 comedi_event(dev, s); 00527 return 1; 00528 } 00529 00530 return 0; 00531 } 00532 00533 static void pci9118_ai_munge(comedi_device * dev, comedi_subdevice * s, 00534 void *data, unsigned int num_bytes, unsigned int start_chan_index) 00535 { 00536 unsigned int i, num_samples = num_bytes / sizeof(sampl_t); 00537 sampl_t *array = data; 00538 00539 for (i = 0; i < num_samples; i++) { 00540 if (devpriv->usedma) 00541 array[i] = be16_to_cpu(array[i]); 00542 if (devpriv->ai16bits) { 00543 array[i] ^= 0x8000; 00544 } else { 00545 array[i] = (array[i] >> 4) & 0x0fff; 00546 } 00547 } 00548 } 00549 00550 /* 00551 ============================================================================== 00552 */ 00553 static void interrupt_pci9118_ai_onesample(comedi_device * dev, 00554 comedi_subdevice * s, unsigned short int_adstat, unsigned int int_amcc, 00555 unsigned short int_daq) 00556 { 00557 register sampl_t sampl; 00558 00559 s->async->events = 0; 00560 00561 if (int_adstat & devpriv->ai_maskerr) 00562 if (pci9118_decode_error_status(dev, s, int_adstat)) 00563 return; 00564 00565 sampl = inw(dev->iobase + PCI9118_AD_DATA); 00566 00567 #ifdef PCI9118_PARANOIDCHECK 00568 if (devpriv->ai16bits == 0) { 00569 if ((sampl & 0x000f) != devpriv->chanlist[s->async->cur_chan]) { // data dropout! 00570 rt_printk 00571 ("comedi: A/D SAMPL - data dropout: received channel %d, expected %d!\n", 00572 sampl & 0x000f, 00573 devpriv->chanlist[s->async->cur_chan]); 00574 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; 00575 pci9118_ai_cancel(dev, s); 00576 comedi_event(dev, s); 00577 return; 00578 } 00579 } 00580 #endif 00581 cfc_write_to_buffer(s, sampl); 00582 s->async->cur_chan++; 00583 if (s->async->cur_chan >= devpriv->ai_n_scanlen) { /* one scan done */ 00584 s->async->cur_chan %= devpriv->ai_n_scanlen; 00585 devpriv->ai_act_scan++; 00586 if (!(devpriv->ai_neverending)) 00587 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */ 00588 pci9118_ai_cancel(dev, s); 00589 s->async->events |= COMEDI_CB_EOA; 00590 } 00591 } 00592 00593 if (s->async->events) 00594 comedi_event(dev, s); 00595 } 00596 00597 /* 00598 ============================================================================== 00599 */ 00600 static void interrupt_pci9118_ai_dma(comedi_device * dev, comedi_subdevice * s, 00601 unsigned short int_adstat, unsigned int int_amcc, 00602 unsigned short int_daq) 00603 { 00604 unsigned int next_dma_buf, samplesinbuf, sampls, m; 00605 00606 if (int_amcc & MASTER_ABORT_INT) { 00607 comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!"); 00608 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; 00609 pci9118_ai_cancel(dev, s); 00610 comedi_event(dev, s); 00611 return; 00612 } 00613 00614 if (int_amcc & TARGET_ABORT_INT) { 00615 comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!"); 00616 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; 00617 pci9118_ai_cancel(dev, s); 00618 comedi_event(dev, s); 00619 return; 00620 } 00621 00622 if (int_adstat & devpriv->ai_maskerr) 00623 // if (int_adstat & 0x106) 00624 if (pci9118_decode_error_status(dev, s, int_adstat)) 00625 return; 00626 00627 samplesinbuf = devpriv->dmabuf_use_size[devpriv->dma_actbuf] >> 1; // number of received real samples 00628 // DPRINTK("dma_actbuf=%d\n",devpriv->dma_actbuf); 00629 00630 if (devpriv->dma_doublebuf) { // switch DMA buffers if is used double buffering 00631 next_dma_buf = 1 - devpriv->dma_actbuf; 00632 outl(devpriv->dmabuf_hw[next_dma_buf], 00633 devpriv->iobase_a + AMCC_OP_REG_MWAR); 00634 outl(devpriv->dmabuf_use_size[next_dma_buf], 00635 devpriv->iobase_a + AMCC_OP_REG_MWTC); 00636 devpriv->dmabuf_used_size[next_dma_buf] = 00637 devpriv->dmabuf_use_size[next_dma_buf]; 00638 if (devpriv->ai_do == 4) 00639 interrupt_pci9118_ai_mode4_switch(dev); 00640 } 00641 00642 if (samplesinbuf) { 00643 m = devpriv->ai_data_len >> 1; // how many samples is to end of buffer 00644 // DPRINTK("samps=%d m=%d %d %d\n",samplesinbuf,m,s->async->buf_int_count,s->async->buf_int_ptr); 00645 sampls = m; 00646 move_block_from_dma(dev, s, 00647 devpriv->dmabuf_virt[devpriv->dma_actbuf], 00648 samplesinbuf); 00649 m = m - sampls; // m= how many samples was transfered 00650 } 00651 // DPRINTK("YYY\n"); 00652 00653 if (!devpriv->ai_neverending) 00654 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */ 00655 pci9118_ai_cancel(dev, s); 00656 s->async->events |= COMEDI_CB_EOA; 00657 } 00658 00659 if (devpriv->dma_doublebuf) { // switch dma buffers 00660 devpriv->dma_actbuf = 1 - devpriv->dma_actbuf; 00661 } else { // restart DMA if is not used double buffering 00662 outl(devpriv->dmabuf_hw[0], 00663 devpriv->iobase_a + AMCC_OP_REG_MWAR); 00664 outl(devpriv->dmabuf_use_size[0], 00665 devpriv->iobase_a + AMCC_OP_REG_MWTC); 00666 if (devpriv->ai_do == 4) 00667 interrupt_pci9118_ai_mode4_switch(dev); 00668 } 00669 00670 comedi_event(dev, s); 00671 } 00672 00673 /* 00674 ============================================================================== 00675 */ 00676 static irqreturn_t interrupt_pci9118(int irq, void *d PT_REGS_ARG) 00677 { 00678 comedi_device *dev = d; 00679 unsigned int int_daq = 0, int_amcc, int_adstat; 00680 00681 if (!dev->attached) 00682 return IRQ_NONE; // not fully initialized 00683 00684 int_daq = inl(dev->iobase + PCI9118_INTSRC) & 0xf; // get IRQ reasons from card 00685 int_amcc = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR); // get INT register from AMCC chip 00686 00687 // DPRINTK("INT daq=0x%01x amcc=0x%08x MWAR=0x%08x MWTC=0x%08x ADSTAT=0x%02x ai_do=%d\n", int_daq, int_amcc, inl(devpriv->iobase_a+AMCC_OP_REG_MWAR), inl(devpriv->iobase_a+AMCC_OP_REG_MWTC), inw(dev->iobase+PCI9118_ADSTAT)&0x1ff,devpriv->ai_do); 00688 00689 if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) 00690 return IRQ_NONE; // interrupt from other source 00691 00692 outl(int_amcc | 0x00ff0000, devpriv->iobase_a + AMCC_OP_REG_INTCSR); // shutdown IRQ reasons in AMCC 00693 00694 int_adstat = inw(dev->iobase + PCI9118_ADSTAT) & 0x1ff; // get STATUS register 00695 00696 if (devpriv->ai_do) { 00697 if (devpriv->ai12_startstop) 00698 if ((int_adstat & AdStatus_DTH) && (int_daq & Int_DTrg)) { // start stop of measure 00699 if (devpriv->ai12_startstop & START_AI_EXT) { 00700 devpriv->ai12_startstop &= 00701 ~START_AI_EXT; 00702 if (!(devpriv->ai12_startstop & 00703 STOP_AI_EXT)) 00704 pci9118_exttrg_del(dev, EXTTRG_AI); // deactivate EXT trigger 00705 start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1, devpriv->ai_divisor2); // start pacer 00706 outl(devpriv->AdControlReg, 00707 dev->iobase + PCI9118_ADCNTRL); 00708 } else { 00709 if (devpriv-> 00710 ai12_startstop & STOP_AI_EXT) { 00711 devpriv->ai12_startstop &= 00712 ~STOP_AI_EXT; 00713 pci9118_exttrg_del(dev, EXTTRG_AI); // deactivate EXT trigger 00714 devpriv->ai_neverending = 0; //well, on next interrupt from DMA/EOC measure will stop 00715 } 00716 } 00717 } 00718 00719 (devpriv->int_ai_func) (dev, dev->subdevices + 0, int_adstat, 00720 int_amcc, int_daq); 00721 00722 } 00723 return IRQ_HANDLED; 00724 } 00725 00726 /* 00727 ============================================================================== 00728 */ 00729 static int pci9118_ai_inttrig(comedi_device * dev, comedi_subdevice * s, 00730 unsigned int trignum) 00731 { 00732 if (trignum != devpriv->ai_inttrig_start) 00733 return -EINVAL; 00734 00735 devpriv->ai12_startstop &= ~START_AI_INT; 00736 s->async->inttrig = NULL; 00737 00738 outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); 00739 outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); 00740 if (devpriv->ai_do != 3) { 00741 start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1, 00742 devpriv->ai_divisor2); 00743 devpriv->AdControlReg |= AdControl_SoftG; 00744 } 00745 outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); 00746 00747 return 1; 00748 } 00749 00750 /* 00751 ============================================================================== 00752 */ 00753 static int pci9118_ai_cmdtest(comedi_device * dev, comedi_subdevice * s, 00754 comedi_cmd * cmd) 00755 { 00756 int err = 0; 00757 int tmp, divisor1, divisor2; 00758 00759 /* step 1: make sure trigger sources are trivially valid */ 00760 00761 tmp = cmd->start_src; 00762 cmd->start_src &= TRIG_NOW | TRIG_EXT | TRIG_INT; 00763 if (!cmd->start_src || tmp != cmd->start_src) 00764 err++; 00765 00766 tmp = cmd->scan_begin_src; 00767 if (devpriv->master) { 00768 cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW; 00769 } else { 00770 cmd->scan_begin_src &= TRIG_FOLLOW; 00771 } 00772 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 00773 err++; 00774 00775 tmp = cmd->convert_src; 00776 if (devpriv->master) { 00777 cmd->convert_src &= TRIG_TIMER | TRIG_EXT | TRIG_NOW; 00778 } else { 00779 cmd->convert_src &= TRIG_TIMER | TRIG_EXT; 00780 } 00781 if (!cmd->convert_src || tmp != cmd->convert_src) 00782 err++; 00783 00784 tmp = cmd->scan_end_src; 00785 cmd->scan_end_src &= TRIG_COUNT; 00786 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 00787 err++; 00788 00789 tmp = cmd->stop_src; 00790 cmd->stop_src &= TRIG_COUNT | TRIG_NONE | TRIG_EXT; 00791 if (!cmd->stop_src || tmp != cmd->stop_src) 00792 err++; 00793 00794 if (err) 00795 return 1; 00796 00797 /* step 2: make sure trigger sources are unique and mutually compatible */ 00798 00799 if (cmd->start_src != TRIG_NOW && 00800 cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT) { 00801 cmd->start_src = TRIG_NOW; 00802 err++; 00803 } 00804 00805 if (cmd->scan_begin_src != TRIG_TIMER && 00806 cmd->scan_begin_src != TRIG_EXT && 00807 cmd->scan_begin_src != TRIG_INT && 00808 cmd->scan_begin_src != TRIG_FOLLOW) { 00809 cmd->scan_begin_src = TRIG_FOLLOW; 00810 err++; 00811 } 00812 00813 if (cmd->convert_src != TRIG_TIMER && 00814 cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) { 00815 cmd->convert_src = TRIG_TIMER; 00816 err++; 00817 } 00818 00819 if (cmd->scan_end_src != TRIG_COUNT) { 00820 cmd->scan_end_src = TRIG_COUNT; 00821 err++; 00822 } 00823 00824 if (cmd->stop_src != TRIG_NONE && 00825 cmd->stop_src != TRIG_COUNT && 00826 cmd->stop_src != TRIG_INT && cmd->stop_src != TRIG_EXT) { 00827 cmd->stop_src = TRIG_COUNT; 00828 err++; 00829 } 00830 00831 if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) { 00832 cmd->start_src = TRIG_NOW; 00833 err++; 00834 } 00835 00836 if (cmd->start_src == TRIG_INT && cmd->scan_begin_src == TRIG_INT) { 00837 cmd->start_src = TRIG_NOW; 00838 err++; 00839 } 00840 00841 if ((cmd->scan_begin_src & (TRIG_TIMER | TRIG_EXT)) && 00842 (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW)))) { 00843 cmd->convert_src = TRIG_TIMER; 00844 err++; 00845 } 00846 00847 if ((cmd->scan_begin_src == TRIG_FOLLOW) && 00848 (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT)))) { 00849 cmd->convert_src = TRIG_TIMER; 00850 err++; 00851 } 00852 00853 if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) { 00854 cmd->stop_src = TRIG_COUNT; 00855 err++; 00856 } 00857 00858 if (err) 00859 return 2; 00860 00861 /* step 3: make sure arguments are trivially compatible */ 00862 00863 if (cmd->start_src & (TRIG_NOW | TRIG_EXT)) 00864 if (cmd->start_arg != 0) { 00865 cmd->start_arg = 0; 00866 err++; 00867 } 00868 00869 if (cmd->scan_begin_src & (TRIG_FOLLOW | TRIG_EXT)) 00870 if (cmd->scan_begin_arg != 0) { 00871 cmd->scan_begin_arg = 0; 00872 err++; 00873 } 00874 00875 if ((cmd->scan_begin_src == TRIG_TIMER) && 00876 (cmd->convert_src == TRIG_TIMER) && (cmd->scan_end_arg == 1)) { 00877 cmd->scan_begin_src = TRIG_FOLLOW; 00878 cmd->convert_arg = cmd->scan_begin_arg; 00879 cmd->scan_begin_arg = 0; 00880 } 00881 00882 if (cmd->scan_begin_src == TRIG_TIMER) 00883 if (cmd->scan_begin_arg < this_board->ai_ns_min) { 00884 cmd->scan_begin_arg = this_board->ai_ns_min; 00885 err++; 00886 } 00887 00888 if (cmd->scan_begin_src == TRIG_EXT) 00889 if (cmd->scan_begin_arg) { 00890 cmd->scan_begin_arg = 0; 00891 err++; 00892 if (cmd->scan_end_arg > 65535) { 00893 cmd->scan_end_arg = 65535; 00894 err++; 00895 } 00896 } 00897 00898 if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) 00899 if (cmd->convert_arg < this_board->ai_ns_min) { 00900 cmd->convert_arg = this_board->ai_ns_min; 00901 err++; 00902 } 00903 00904 if (cmd->convert_src == TRIG_EXT) 00905 if (cmd->convert_arg) { 00906 cmd->convert_arg = 0; 00907 err++; 00908 } 00909 00910 if (cmd->stop_src == TRIG_COUNT) { 00911 if (!cmd->stop_arg) { 00912 cmd->stop_arg = 1; 00913 err++; 00914 } 00915 } else { /* TRIG_NONE */ 00916 if (cmd->stop_arg != 0) { 00917 cmd->stop_arg = 0; 00918 err++; 00919 } 00920 } 00921 00922 if (!cmd->chanlist_len) { 00923 cmd->chanlist_len = 1; 00924 err++; 00925 } 00926 00927 if (cmd->chanlist_len > this_board->n_aichanlist) { 00928 cmd->chanlist_len = this_board->n_aichanlist; 00929 err++; 00930 } 00931 00932 if (cmd->scan_end_arg < cmd->chanlist_len) { 00933 cmd->scan_end_arg = cmd->chanlist_len; 00934 err++; 00935 } 00936 00937 if ((cmd->scan_end_arg % cmd->chanlist_len)) { 00938 cmd->scan_end_arg = 00939 cmd->chanlist_len * (cmd->scan_end_arg / 00940 cmd->chanlist_len); 00941 err++; 00942 } 00943 00944 if (err) 00945 return 3; 00946 00947 /* step 4: fix up any arguments */ 00948 00949 if (cmd->scan_begin_src == TRIG_TIMER) { 00950 tmp = cmd->scan_begin_arg; 00951 // rt_printk("S1 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); 00952 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, 00953 &divisor2, &cmd->scan_begin_arg, 00954 cmd->flags & TRIG_ROUND_MASK); 00955 // rt_printk("S2 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); 00956 if (cmd->scan_begin_arg < this_board->ai_ns_min) 00957 cmd->scan_begin_arg = this_board->ai_ns_min; 00958 if (tmp != cmd->scan_begin_arg) 00959 err++; 00960 } 00961 00962 if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) { 00963 tmp = cmd->convert_arg; 00964 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, 00965 &divisor2, &cmd->convert_arg, 00966 cmd->flags & TRIG_ROUND_MASK); 00967 // rt_printk("s1 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); 00968 if (cmd->convert_arg < this_board->ai_ns_min) 00969 cmd->convert_arg = this_board->ai_ns_min; 00970 if (tmp != cmd->convert_arg) 00971 err++; 00972 if (cmd->scan_begin_src == TRIG_TIMER 00973 && cmd->convert_src == TRIG_NOW) { 00974 if (cmd->convert_arg == 0) { 00975 if (cmd->scan_begin_arg < 00976 this_board->ai_ns_min * 00977 (cmd->scan_end_arg + 2)) { 00978 cmd->scan_begin_arg = 00979 this_board->ai_ns_min * 00980 (cmd->scan_end_arg + 2); 00981 // rt_printk("s2 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); 00982 err++; 00983 } 00984 } else { 00985 if (cmd->scan_begin_arg < 00986 cmd->convert_arg * cmd->chanlist_len) { 00987 cmd->scan_begin_arg = 00988 cmd->convert_arg * 00989 cmd->chanlist_len; 00990 // rt_printk("s3 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); 00991 err++; 00992 } 00993 } 00994 } 00995 } 00996 00997 if (err) 00998 return 4; 00999 01000 if (cmd->chanlist) 01001 if (!check_channel_list(dev, s, cmd->chanlist_len, 01002 cmd->chanlist, 0, 0)) 01003 return 5; // incorrect channels list 01004 01005 return 0; 01006 } 01007 01008 /* 01009 ============================================================================== 01010 */ 01011 static int Compute_and_setup_dma(comedi_device * dev) 01012 { 01013 unsigned int dmalen0, dmalen1, i; 01014 01015 DPRINTK("adl_pci9118 EDBG: BGN: Compute_and_setup_dma()\n"); 01016 dmalen0 = devpriv->dmabuf_size[0]; 01017 dmalen1 = devpriv->dmabuf_size[1]; 01018 DPRINTK("1 dmalen0=%d dmalen1=%d ai_data_len=%d\n", dmalen0, dmalen1, 01019 devpriv->ai_data_len); 01020 // isn't output buff smaller that our DMA buff? 01021 if (dmalen0 > (devpriv->ai_data_len)) { 01022 dmalen0 = devpriv->ai_data_len & ~3L; // allign to 32bit down 01023 } 01024 if (dmalen1 > (devpriv->ai_data_len)) { 01025 dmalen1 = devpriv->ai_data_len & ~3L; // allign to 32bit down 01026 } 01027 DPRINTK("2 dmalen0=%d dmalen1=%d \n", dmalen0, dmalen1); 01028 01029 // we want wake up every scan? 01030 if (devpriv->ai_flags & TRIG_WAKE_EOS) { 01031 if (dmalen0 < (devpriv->ai_n_realscanlen << 1)) { 01032 // uff, too short DMA buffer, disable EOS support! 01033 devpriv->ai_flags &= (~TRIG_WAKE_EOS); 01034 rt_printk 01035 ("comedi%d: WAR: DMA0 buf too short, cann't support TRIG_WAKE_EOS (%d<%d)\n", 01036 dev->minor, dmalen0, 01037 devpriv->ai_n_realscanlen << 1); 01038 } else { 01039 // short first DMA buffer to one scan 01040 dmalen0 = devpriv->ai_n_realscanlen << 1; 01041 DPRINTK("21 dmalen0=%d ai_n_realscanlen=%d useeoshandle=%d\n", dmalen0, devpriv->ai_n_realscanlen, devpriv->useeoshandle); 01042 if (devpriv->useeoshandle) 01043 dmalen0 += 2; 01044 if (dmalen0 < 4) { 01045 rt_printk 01046 ("comedi%d: ERR: DMA0 buf len bug? (%d<4)\n", 01047 dev->minor, dmalen0); 01048 dmalen0 = 4; 01049 } 01050 } 01051 } 01052 if (devpriv->ai_flags & TRIG_WAKE_EOS) { 01053 if (dmalen1 < (devpriv->ai_n_realscanlen << 1)) { 01054 // uff, too short DMA buffer, disable EOS support! 01055 devpriv->ai_flags &= (~TRIG_WAKE_EOS); 01056 rt_printk 01057 ("comedi%d: WAR: DMA1 buf too short, cann't support TRIG_WAKE_EOS (%d<%d)\n", 01058 dev->minor, dmalen1, 01059 devpriv->ai_n_realscanlen << 1); 01060 } else { 01061 // short second DMA buffer to one scan 01062 dmalen1 = devpriv->ai_n_realscanlen << 1; 01063 DPRINTK("22 dmalen1=%d ai_n_realscanlen=%d useeoshandle=%d\n", dmalen1, devpriv->ai_n_realscanlen, devpriv->useeoshandle); 01064 if (devpriv->useeoshandle) 01065 dmalen1 -= 2; 01066 if (dmalen1 < 4) { 01067 rt_printk 01068 ("comedi%d: ERR: DMA1 buf len bug? (%d<4)\n", 01069 dev->minor, dmalen1); 01070 dmalen1 = 4; 01071 } 01072 } 01073 } 01074 01075 DPRINTK("3 dmalen0=%d dmalen1=%d \n", dmalen0, dmalen1); 01076 // transfer without TRIG_WAKE_EOS 01077 if (!(devpriv->ai_flags & TRIG_WAKE_EOS)) { 01078 // if it's possible then allign DMA buffers to length of scan 01079 i = dmalen0; 01080 dmalen0 = 01081 (dmalen0 / (devpriv->ai_n_realscanlen << 1)) * 01082 (devpriv->ai_n_realscanlen << 1); 01083 dmalen0 &= ~3L; 01084 if (!dmalen0) 01085 dmalen0 = i; // uff. very long scan? 01086 i = dmalen1; 01087 dmalen1 = 01088 (dmalen1 / (devpriv->ai_n_realscanlen << 1)) * 01089 (devpriv->ai_n_realscanlen << 1); 01090 dmalen1 &= ~3L; 01091 if (!dmalen1) 01092 dmalen1 = i; // uff. very long scan? 01093 // if measure isn't neverending then test, if it whole fits into one or two DMA buffers 01094 if (!devpriv->ai_neverending) { 01095 // fits whole measure into one DMA buffer? 01096 if (dmalen0 > 01097 ((devpriv->ai_n_realscanlen << 1) * 01098 devpriv->ai_scans)) { 01099 DPRINTK("3.0 ai_n_realscanlen=%d ai_scans=%d \n", devpriv->ai_n_realscanlen, devpriv->ai_scans); 01100 dmalen0 = 01101 (devpriv->ai_n_realscanlen << 1) * 01102 devpriv->ai_scans; 01103 DPRINTK("3.1 dmalen0=%d dmalen1=%d \n", dmalen0, 01104 dmalen1); 01105 dmalen0 &= ~3L; 01106 } else { // fits whole measure into two DMA buffer? 01107 if (dmalen1 > 01108 ((devpriv->ai_n_realscanlen << 1) * 01109 devpriv->ai_scans - dmalen0)) 01110 dmalen1 = 01111 (devpriv-> 01112 ai_n_realscanlen << 1) * 01113 devpriv->ai_scans - dmalen0; 01114 DPRINTK("3.2 dmalen0=%d dmalen1=%d \n", dmalen0, 01115 dmalen1); 01116 dmalen1 &= ~3L; 01117 } 01118 } 01119 } 01120 01121 DPRINTK("4 dmalen0=%d dmalen1=%d \n", dmalen0, dmalen1); 01122 01123 // these DMA buffer size we'll be used 01124 devpriv->dma_actbuf = 0; 01125 devpriv->dmabuf_use_size[0] = dmalen0; 01126 devpriv->dmabuf_use_size[1] = dmalen1; 01127 01128 DPRINTK("5 dmalen0=%d dmalen1=%d \n", dmalen0, dmalen1); 01129 #if 0 01130 if (devpriv->ai_n_scanlen < this_board->half_fifo_size) { 01131 devpriv->dmabuf_panic_size[0] = 01132 (this_board->half_fifo_size / devpriv->ai_n_scanlen + 01133 1) * devpriv->ai_n_scanlen * sizeof(sampl_t); 01134 devpriv->dmabuf_panic_size[1] = 01135 (this_board->half_fifo_size / devpriv->ai_n_scanlen + 01136 1) * devpriv->ai_n_scanlen * sizeof(sampl_t); 01137 } else { 01138 devpriv->dmabuf_panic_size[0] = 01139 (devpriv->ai_n_scanlen << 1) % devpriv->dmabuf_size[0]; 01140 devpriv->dmabuf_panic_size[1] = 01141 (devpriv->ai_n_scanlen << 1) % devpriv->dmabuf_size[1]; 01142 } 01143 #endif 01144 01145 outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) & (~EN_A2P_TRANSFERS), devpriv->iobase_a + AMCC_OP_REG_MCSR); // stop DMA 01146 outl(devpriv->dmabuf_hw[0], devpriv->iobase_a + AMCC_OP_REG_MWAR); 01147 outl(devpriv->dmabuf_use_size[0], devpriv->iobase_a + AMCC_OP_REG_MWTC); 01148 // init DMA transfer 01149 outl(0x00000000 | AINT_WRITE_COMPL, 01150 devpriv->iobase_a + AMCC_OP_REG_INTCSR); 01151 // outl(0x02000000|AINT_WRITE_COMPL, devpriv->iobase_a+AMCC_OP_REG_INTCSR); 01152 01153 outl(inl(devpriv->iobase_a + 01154 AMCC_OP_REG_MCSR) | RESET_A2P_FLAGS | A2P_HI_PRIORITY | 01155 EN_A2P_TRANSFERS, devpriv->iobase_a + AMCC_OP_REG_MCSR); 01156 outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | EN_A2P_TRANSFERS, devpriv->iobase_a + AMCC_OP_REG_INTCSR); // allow bus mastering 01157 01158 DPRINTK("adl_pci9118 EDBG: END: Compute_and_setup_dma()\n"); 01159 return 0; 01160 } 01161 01162 /* 01163 ============================================================================== 01164 */ 01165 static int pci9118_ai_docmd_sampl(comedi_device * dev, comedi_subdevice * s) 01166 { 01167 DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_sampl(%d,) [%d]\n", 01168 dev->minor, devpriv->ai_do); 01169 switch (devpriv->ai_do) { 01170 case 1: 01171 devpriv->AdControlReg |= AdControl_TmrTr; 01172 break; 01173 case 2: 01174 comedi_error(dev, "pci9118_ai_docmd_sampl() mode 2 bug!\n"); 01175 return -EIO; 01176 case 3: 01177 devpriv->AdControlReg |= AdControl_ExtM; 01178 break; 01179 case 4: 01180 comedi_error(dev, "pci9118_ai_docmd_sampl() mode 4 bug!\n"); 01181 return -EIO; 01182 default: 01183 comedi_error(dev, 01184 "pci9118_ai_docmd_sampl() mode number bug!\n"); 01185 return -EIO; 01186 }; 01187 01188 devpriv->int_ai_func = interrupt_pci9118_ai_onesample; //transfer function 01189 01190 if (devpriv->ai12_startstop) 01191 pci9118_exttrg_add(dev, EXTTRG_AI); // activate EXT trigger 01192 01193 if ((devpriv->ai_do == 1) || (devpriv->ai_do == 2)) 01194 devpriv->IntControlReg |= Int_Timer; 01195 01196 devpriv->AdControlReg |= AdControl_Int; 01197 01198 outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, devpriv->iobase_a + AMCC_OP_REG_INTCSR); // allow INT in AMCC 01199 01200 if (!(devpriv->ai12_startstop & (START_AI_EXT | START_AI_INT))) { 01201 outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); 01202 outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); 01203 if (devpriv->ai_do != 3) { 01204 start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1, 01205 devpriv->ai_divisor2); 01206 devpriv->AdControlReg |= AdControl_SoftG; 01207 } 01208 outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); 01209 } 01210 01211 DPRINTK("adl_pci9118 EDBG: END: pci9118_ai_docmd_sampl()\n"); 01212 return 0; 01213 } 01214 01215 /* 01216 ============================================================================== 01217 */ 01218 static int pci9118_ai_docmd_dma(comedi_device * dev, comedi_subdevice * s) 01219 { 01220 DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_dma(%d,) [%d,%d]\n", 01221 dev->minor, devpriv->ai_do, devpriv->usedma); 01222 Compute_and_setup_dma(dev); 01223 01224 switch (devpriv->ai_do) { 01225 case 1: 01226 devpriv->AdControlReg |= 01227 ((AdControl_TmrTr | AdControl_Dma) & 0xff); 01228 break; 01229 case 2: 01230 devpriv->AdControlReg |= 01231 ((AdControl_TmrTr | AdControl_Dma) & 0xff); 01232 devpriv->AdFunctionReg = 01233 AdFunction_PDTrg | AdFunction_PETrg | AdFunction_BM | 01234 AdFunction_BS; 01235 if (devpriv->usessh && (!devpriv->softsshdelay)) 01236 devpriv->AdFunctionReg |= AdFunction_BSSH; 01237 outl(devpriv->ai_n_realscanlen, dev->iobase + PCI9118_BURST); 01238 break; 01239 case 3: 01240 devpriv->AdControlReg |= 01241 ((AdControl_ExtM | AdControl_Dma) & 0xff); 01242 devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; 01243 break; 01244 case 4: 01245 devpriv->AdControlReg |= 01246 ((AdControl_TmrTr | AdControl_Dma) & 0xff); 01247 devpriv->AdFunctionReg = 01248 AdFunction_PDTrg | AdFunction_PETrg | AdFunction_AM; 01249 outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); 01250 outl(0x30, dev->iobase + PCI9118_CNTCTRL); 01251 outl((devpriv->dmabuf_hw[0] >> 1) & 0xff, 01252 dev->iobase + PCI9118_CNT0); 01253 outl((devpriv->dmabuf_hw[0] >> 9) & 0xff, 01254 dev->iobase + PCI9118_CNT0); 01255 devpriv->AdFunctionReg |= AdFunction_Start; 01256 break; 01257 default: 01258 comedi_error(dev, "pci9118_ai_docmd_dma() mode number bug!\n"); 01259 return -EIO; 01260 }; 01261 01262 if (devpriv->ai12_startstop) { 01263 pci9118_exttrg_add(dev, EXTTRG_AI); // activate EXT trigger 01264 } 01265 01266 devpriv->int_ai_func = interrupt_pci9118_ai_dma; //transfer function 01267 01268 outl(0x02000000 | AINT_WRITE_COMPL, 01269 devpriv->iobase_a + AMCC_OP_REG_INTCSR); 01270 01271 if (!(devpriv->ai12_startstop & (START_AI_EXT | START_AI_INT))) { 01272 outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); 01273 outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); 01274 if (devpriv->ai_do != 3) { 01275 start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1, 01276 devpriv->ai_divisor2); 01277 devpriv->AdControlReg |= AdControl_SoftG; 01278 } 01279 outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); 01280 } 01281 01282 DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_dma()\n"); 01283 return 0; 01284 } 01285 01286 /* 01287 ============================================================================== 01288 */ 01289 static int pci9118_ai_cmd(comedi_device * dev, comedi_subdevice * s) 01290 { 01291 comedi_cmd *cmd = &s->async->cmd; 01292 unsigned int addchans = 0; 01293 int ret = 0; 01294 01295 DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_cmd(%d,)\n", dev->minor); 01296 devpriv->ai12_startstop = 0; 01297 devpriv->ai_flags = cmd->flags; 01298 devpriv->ai_n_chan = cmd->chanlist_len; 01299 devpriv->ai_n_scanlen = cmd->scan_end_arg; 01300 devpriv->ai_chanlist = cmd->chanlist; 01301 devpriv->ai_data = s->async->prealloc_buf; 01302 devpriv->ai_data_len = s->async->prealloc_bufsz; 01303 devpriv->ai_timer1 = 0; 01304 devpriv->ai_timer2 = 0; 01305 devpriv->ai_add_front = 0; 01306 devpriv->ai_add_back = 0; 01307 devpriv->ai_maskerr = 0x10e; 01308 01309 // prepare for start/stop conditions 01310 if (cmd->start_src == TRIG_EXT) 01311 devpriv->ai12_startstop |= START_AI_EXT; 01312 if (cmd->stop_src == TRIG_EXT) { 01313 devpriv->ai_neverending = 1; 01314 devpriv->ai12_startstop |= STOP_AI_EXT; 01315 } 01316 if (cmd->start_src == TRIG_INT) { 01317 devpriv->ai12_startstop |= START_AI_INT; 01318 devpriv->ai_inttrig_start = cmd->start_arg; 01319 s->async->inttrig = pci9118_ai_inttrig; 01320 } 01321 #if 0 01322 if (cmd->stop_src == TRIG_INT) { 01323 devpriv->ai_neverending = 1; 01324 devpriv->ai12_startstop |= STOP_AI_INT; 01325 } 01326 #endif 01327 if (cmd->stop_src == TRIG_NONE) 01328 devpriv->ai_neverending = 1; 01329 if (cmd->stop_src == TRIG_COUNT) { 01330 devpriv->ai_scans = cmd->stop_arg; 01331 devpriv->ai_neverending = 0; 01332 } else { 01333 devpriv->ai_scans = 0; 01334 } 01335 01336 // use sample&hold signal? 01337 if (cmd->convert_src == TRIG_NOW) { 01338 devpriv->usessh = 1; 01339 } // yes 01340 else { 01341 devpriv->usessh = 0; 01342 } // no 01343 01344 DPRINTK("1 neverending=%d scans=%u usessh=%d ai_startstop=0x%2x\n", 01345 devpriv->ai_neverending, devpriv->ai_scans, devpriv->usessh, 01346 devpriv->ai12_startstop); 01347 01348 // use additional sample at end of every scan to satisty DMA 32 bit transfer? 01349 devpriv->ai_add_front = 0; 01350 devpriv->ai_add_back = 0; 01351 devpriv->useeoshandle = 0; 01352 if (devpriv->master) { 01353 devpriv->usedma = 1; 01354 if ((cmd->flags & TRIG_WAKE_EOS) && 01355 (devpriv->ai_n_scanlen == 1)) { 01356 if (cmd->convert_src == TRIG_NOW) { 01357 devpriv->ai_add_back = 1; 01358 } 01359 if (cmd->convert_src == TRIG_TIMER) { 01360 devpriv->usedma = 0; // use INT transfer if scanlist have only one channel 01361 } 01362 } 01363 if ((cmd->flags & TRIG_WAKE_EOS) && 01364 (devpriv->ai_n_scanlen & 1) && 01365 (devpriv->ai_n_scanlen > 1)) { 01366 if (cmd->scan_begin_src == TRIG_FOLLOW) { 01367 //vpriv->useeoshandle=1; // change DMA transfer block to fit EOS on every second call 01368 devpriv->usedma = 0; // XXX maybe can be corrected to use 16 bit DMA 01369 } else { // well, we must insert one sample to end of EOS to meet 32 bit transfer 01370 devpriv->ai_add_back = 1; 01371 } 01372 } 01373 } else { // interrupt transfer don't need any correction 01374 devpriv->usedma = 0; 01375 } 01376 01377 // we need software S&H signal? It add two samples before every scan as minimum 01378 if (devpriv->usessh && devpriv->softsshdelay) { 01379 devpriv->ai_add_front = 2; 01380 if ((devpriv->usedma == 1) && (devpriv->ai_add_back == 1)) { // move it to front 01381 devpriv->ai_add_front++; 01382 devpriv->ai_add_back = 0; 01383 } 01384 if (cmd->convert_arg < this_board->ai_ns_min) 01385 cmd->convert_arg = this_board->ai_ns_min; 01386 addchans = devpriv->softsshdelay / cmd->convert_arg; 01387 if (devpriv->softsshdelay % cmd->convert_arg) 01388 addchans++; 01389 if (addchans > (devpriv->ai_add_front - 1)) { // uff, still short :-( 01390 devpriv->ai_add_front = addchans + 1; 01391 if (devpriv->usedma == 1) 01392 if ((devpriv->ai_add_front + 01393 devpriv->ai_n_chan + 01394 devpriv->ai_add_back) & 1) 01395 devpriv->ai_add_front++; // round up to 32 bit 01396 } 01397 } // well, we now know what must be all added 01398 01399 devpriv->ai_n_realscanlen = // what we must take from card in real to have ai_n_scanlen on output? 01400 (devpriv->ai_add_front + devpriv->ai_n_chan + 01401 devpriv->ai_add_back) * (devpriv->ai_n_scanlen / 01402 devpriv->ai_n_chan); 01403 01404 DPRINTK("2 usedma=%d realscan=%d af=%u n_chan=%d ab=%d n_scanlen=%d\n", 01405 devpriv->usedma, 01406 devpriv->ai_n_realscanlen, devpriv->ai_add_front, 01407 devpriv->ai_n_chan, devpriv->ai_add_back, 01408 devpriv->ai_n_scanlen); 01409 01410 // check and setup channel list 01411 if (!check_channel_list(dev, s, devpriv->ai_n_chan, 01412 devpriv->ai_chanlist, devpriv->ai_add_front, 01413 devpriv->ai_add_back)) 01414 return -EINVAL; 01415 if (!setup_channel_list(dev, s, devpriv->ai_n_chan, 01416 devpriv->ai_chanlist, 0, devpriv->ai_add_front, 01417 devpriv->ai_add_back, devpriv->usedma, 01418 devpriv->useeoshandle)) 01419 return -EINVAL; 01420 01421 // compute timers settings 01422 // simplest way, fr=4Mhz/(tim1*tim2), channel manipulation without timers effect 01423 if (((cmd->scan_begin_src == TRIG_FOLLOW) || (cmd->scan_begin_src == TRIG_EXT) || (cmd->scan_begin_src == TRIG_INT)) && (cmd->convert_src == TRIG_TIMER)) { // both timer is used for one time 01424 if (cmd->scan_begin_src == TRIG_EXT) { 01425 devpriv->ai_do = 4; 01426 } else { 01427 devpriv->ai_do = 1; 01428 } 01429 pci9118_calc_divisors(devpriv->ai_do, dev, s, 01430 &cmd->scan_begin_arg, &cmd->convert_arg, 01431 devpriv->ai_flags, devpriv->ai_n_realscanlen, 01432 &devpriv->ai_divisor1, &devpriv->ai_divisor2, 01433 devpriv->usessh, devpriv->ai_add_front); 01434 devpriv->ai_timer2 = cmd->convert_arg; 01435 } 01436 01437 if ((cmd->scan_begin_src == TRIG_TIMER) && ((cmd->convert_src == TRIG_TIMER) || (cmd->convert_src == TRIG_NOW))) { // double timed action 01438 if (!devpriv->usedma) { 01439 comedi_error(dev, 01440 "cmd->scan_begin_src=TRIG_TIMER works only with bus mastering!"); 01441 return -EIO; 01442 } 01443 01444 devpriv->ai_do = 2; 01445 pci9118_calc_divisors(devpriv->ai_do, dev, s, 01446 &cmd->scan_begin_arg, &cmd->convert_arg, 01447 devpriv->ai_flags, devpriv->ai_n_realscanlen, 01448 &devpriv->ai_divisor1, &devpriv->ai_divisor2, 01449 devpriv->usessh, devpriv->ai_add_front); 01450 devpriv->ai_timer1 = cmd->scan_begin_arg; 01451 devpriv->ai_timer2 = cmd->convert_arg; 01452 } 01453 01454 if ((cmd->scan_begin_src == TRIG_FOLLOW) 01455 && (cmd->convert_src == TRIG_EXT)) { 01456 devpriv->ai_do = 3; 01457 } 01458 01459 start_pacer(dev, -1, 0, 0); // stop pacer 01460 01461 devpriv->AdControlReg = 0; // bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable DMA 01462 outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); 01463 devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; // positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop 01464 outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); 01465 comedi_udelay(1); 01466 outl(0, dev->iobase + PCI9118_DELFIFO); // flush FIFO 01467 inl(dev->iobase + PCI9118_ADSTAT); // flush A/D and INT status register 01468 inl(dev->iobase + PCI9118_INTSRC); 01469 01470 devpriv->ai_act_scan = 0; 01471 devpriv->ai_act_dmapos = 0; 01472 s->async->cur_chan = 0; 01473 devpriv->ai_buf_ptr = 0; 01474 01475 if (devpriv->usedma) { 01476 ret = pci9118_ai_docmd_dma(dev, s); 01477 } else { 01478 ret = pci9118_ai_docmd_sampl(dev, s); 01479 } 01480 01481 DPRINTK("adl_pci9118 EDBG: END: pci9118_ai_cmd()\n"); 01482 return ret; 01483 } 01484 01485 /* 01486 ============================================================================== 01487 */ 01488 static int check_channel_list(comedi_device * dev, comedi_subdevice * s, 01489 int n_chan, unsigned int *chanlist, int frontadd, int backadd) 01490 { 01491 unsigned int i, differencial = 0, bipolar = 0; 01492 01493 /* correct channel and range number check itself comedi/range.c */ 01494 if (n_chan < 1) { 01495 comedi_error(dev, "range/channel list is empty!"); 01496 return 0; 01497 } 01498 if ((frontadd + n_chan + backadd) > s->len_chanlist) { 01499 rt_printk 01500 ("comedi%d: range/channel list is too long for actual configuration (%d>%d)!", 01501 dev->minor, n_chan, 01502 s->len_chanlist - frontadd - backadd); 01503 return 0; 01504 } 01505 01506 if (CR_AREF(chanlist[0]) == AREF_DIFF) 01507 differencial = 1; // all input must be diff 01508 if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES) 01509 bipolar = 1; // all input must be bipolar 01510 if (n_chan > 1) 01511 for (i = 1; i < n_chan; i++) { // check S.E/diff 01512 if ((CR_AREF(chanlist[i]) == AREF_DIFF) != 01513 (differencial)) { 01514 comedi_error(dev, 01515 "Differencial and single ended inputs cann't be mixtured!"); 01516 return 0; 01517 } 01518 if ((CR_RANGE(chanlist[i]) < PCI9118_BIPOLAR_RANGES) != 01519 (bipolar)) { 01520 comedi_error(dev, 01521 "Bipolar and unipolar ranges cann't be mixtured!"); 01522 return 0; 01523 } 01524 if ((!devpriv->usemux) & (differencial) & 01525 (CR_CHAN(chanlist[i]) >= 01526 this_board->n_aichand)) { 01527 comedi_error(dev, 01528 "If AREF_DIFF is used then is available only first 8 channels!"); 01529 return 0; 01530 } 01531 } 01532 01533 return 1; 01534 } 01535 01536 /* 01537 ============================================================================== 01538 */ 01539 static int setup_channel_list(comedi_device * dev, comedi_subdevice * s, 01540 int n_chan, unsigned int *chanlist, int rot, int frontadd, int backadd, 01541 int usedma, char useeos) 01542 { 01543 unsigned int i, differencial = 0, bipolar = 0; 01544 unsigned int scanquad, gain, ssh = 0x00; 01545 01546 DPRINTK("adl_pci9118 EDBG: BGN: setup_channel_list(%d,.,%d,.,%d,%d,%d,%d)\n", dev->minor, n_chan, rot, frontadd, backadd, usedma); 01547 01548 if (usedma == 1) { 01549 rot = 8; 01550 usedma = 0; 01551 } 01552 01553 if (CR_AREF(chanlist[0]) == AREF_DIFF) 01554 differencial = 1; // all input must be diff 01555 if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES) 01556 bipolar = 1; // all input must be bipolar 01557 01558 // All is ok, so we can setup channel/range list 01559 01560 if (!bipolar) { 01561 devpriv->AdControlReg |= AdControl_UniP; // set unibipolar 01562 } else { 01563 devpriv->AdControlReg &= ((~AdControl_UniP) & 0xff); // enable bipolar 01564 } 01565 01566 if (differencial) { 01567 devpriv->AdControlReg |= AdControl_Diff; // enable diff inputs 01568 } else { 01569 devpriv->AdControlReg &= ((~AdControl_Diff) & 0xff); // set single ended inputs 01570 } 01571 01572 outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); // setup mode 01573 01574 outl(2, dev->iobase + PCI9118_SCANMOD); // gods know why this sequence! 01575 outl(0, dev->iobase + PCI9118_SCANMOD); 01576 outl(1, dev->iobase + PCI9118_SCANMOD); 01577 01578 #ifdef PCI9118_PARANOIDCHECK 01579 devpriv->chanlistlen = n_chan; 01580 for (i = 0; i < (PCI9118_CHANLEN + 1); i++) 01581 devpriv->chanlist[i] = 0x55aa; 01582 #endif 01583 01584 if (frontadd) { // insert channels for S&H 01585 ssh = devpriv->softsshsample; 01586 DPRINTK("FA: %04x: ", ssh); 01587 for (i = 0; i < frontadd; i++) { // store range list to card 01588 scanquad = CR_CHAN(chanlist[0]); // get channel number; 01589 gain = CR_RANGE(chanlist[0]); // get gain number 01590 scanquad |= ((gain & 0x03) << 8); 01591 outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); 01592 DPRINTK("%02x ", scanquad | ssh); 01593 ssh = devpriv->softsshhold; 01594 } 01595 DPRINTK("\n "); 01596 } 01597 01598 DPRINTK("SL: ", ssh); 01599 for (i = 0; i < n_chan; i++) { // store range list to card 01600 scanquad = CR_CHAN(chanlist[i]); // get channel number; 01601 #ifdef PCI9118_PARANOIDCHECK 01602 devpriv->chanlist[i ^ usedma] = (scanquad & 0xf) << rot; 01603 #endif 01604 gain = CR_RANGE(chanlist[i]); // get gain number 01605 scanquad |= ((gain & 0x03) << 8); 01606 outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); 01607 DPRINTK("%02x ", scanquad | ssh); 01608 } 01609 DPRINTK("\n "); 01610 01611 if (backadd) { // insert channels for fit onto 32bit DMA 01612 DPRINTK("BA: %04x: ", ssh); 01613 for (i = 0; i < backadd; i++) { // store range list to card 01614 scanquad = CR_CHAN(chanlist[0]); // get channel number; 01615 gain = CR_RANGE(chanlist[0]); // get gain number 01616 scanquad |= ((gain & 0x03) << 8); 01617 outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); 01618 DPRINTK("%02x ", scanquad | ssh); 01619 } 01620 DPRINTK("\n "); 01621 } 01622 #ifdef PCI9118_PARANOIDCHECK 01623 devpriv->chanlist[n_chan ^ usedma] = devpriv->chanlist[0 ^ usedma]; // for 32bit oerations 01624 if (useeos) { 01625 for (i = 1; i < n_chan; i++) { // store range list to card 01626 devpriv->chanlist[(n_chan + i) ^ usedma] = 01627 (CR_CHAN(chanlist[i]) & 0xf) << rot; 01628 } 01629 devpriv->chanlist[(2 * n_chan) ^ usedma] = devpriv->chanlist[0 ^ usedma]; // for 32bit oerations 01630 useeos = 2; 01631 } else { 01632 useeos = 1; 01633 } 01634 #ifdef PCI9118_EXTDEBUG 01635 DPRINTK("CHL: "); 01636 for (i = 0; i <= (useeos * n_chan); i++) { 01637 DPRINTK("%04x ", devpriv->chanlist[i]); 01638 } 01639 DPRINTK("\n "); 01640 #endif 01641 #endif 01642 outl(0, dev->iobase + PCI9118_SCANMOD); // close scan queue 01643 // comedi_udelay(100); // important delay, or first sample will be cripled 01644 01645 DPRINTK("adl_pci9118 EDBG: END: setup_channel_list()\n"); 01646 return 1; // we can serve this with scan logic 01647 } 01648 01649 /* 01650 ============================================================================== 01651 calculate 8254 divisors if they are used for dual timing 01652 */ 01653 static void pci9118_calc_divisors(char mode, comedi_device * dev, 01654 comedi_subdevice * s, unsigned int *tim1, unsigned int *tim2, 01655 unsigned int flags, int chans, unsigned int *div1, unsigned int *div2, 01656 char usessh, unsigned int chnsshfront) 01657 { 01658 DPRINTK("adl_pci9118 EDBG: BGN: pci9118_calc_divisors(%d,%d,.,%u,%u,%u,%d,.,.,,%u,%u)\n", mode, dev->minor, *tim1, *tim2, flags, chans, usessh, chnsshfront); 01659 switch (mode) { 01660 case 1: 01661 case 4: 01662 if (*tim2 < this_board->ai_ns_min) 01663 *tim2 = this_board->ai_ns_min; 01664 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, div1, div2, 01665 tim2, flags & TRIG_ROUND_NEAREST); 01666 DPRINTK("OSC base=%u div1=%u div2=%u timer1=%u\n", 01667 devpriv->i8254_osc_base, *div1, *div2, *tim1); 01668 break; 01669 case 2: 01670 if (*tim2 < this_board->ai_ns_min) 01671 *tim2 = this_board->ai_ns_min; 01672 DPRINTK("1 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, 01673 *tim1, *tim2); 01674 *div1 = *tim2 / devpriv->i8254_osc_base; // convert timer (burst) 01675 DPRINTK("2 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, 01676 *tim1, *tim2); 01677 if (*div1 < this_board->ai_pacer_min) 01678 *div1 = this_board->ai_pacer_min; 01679 DPRINTK("3 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, 01680 *tim1, *tim2); 01681 *div2 = *tim1 / devpriv->i8254_osc_base; // scan timer 01682 DPRINTK("4 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, 01683 *tim1, *tim2); 01684 *div2 = *div2 / *div1; // major timer is c1*c2 01685 DPRINTK("5 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, 01686 *tim1, *tim2); 01687 if (*div2 < chans) 01688 *div2 = chans; 01689 DPRINTK("6 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, 01690 *tim1, *tim2); 01691 01692 *tim2 = *div1 * devpriv->i8254_osc_base; // real convert timer 01693 01694 if (usessh & (chnsshfront == 0)) // use BSSH signal 01695 if (*div2 < (chans + 2)) 01696 *div2 = chans + 2; 01697 01698 DPRINTK("7 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, 01699 *tim1, *tim2); 01700 *tim1 = *div1 * *div2 * devpriv->i8254_osc_base; 01701 DPRINTK("OSC base=%u div1=%u div2=%u timer1=%u timer2=%u\n", 01702 devpriv->i8254_osc_base, *div1, *div2, *tim1, *tim2); 01703 break; 01704 } 01705 DPRINTK("adl_pci9118 EDBG: END: pci9118_calc_divisors(%u,%u)\n", 01706 *div1, *div2); 01707 } 01708 01709 /* 01710 ============================================================================== 01711 */ 01712 static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, 01713 unsigned int divisor2) 01714 { 01715 outl(0x74, dev->iobase + PCI9118_CNTCTRL); 01716 outl(0xb4, dev->iobase + PCI9118_CNTCTRL); 01717 // outl(0x30, dev->iobase + PCI9118_CNTCTRL); 01718 comedi_udelay(1); 01719 01720 if ((mode == 1) || (mode == 2) || (mode == 4)) { 01721 outl(divisor2 & 0xff, dev->iobase + PCI9118_CNT2); 01722 outl((divisor2 >> 8) & 0xff, dev->iobase + PCI9118_CNT2); 01723 outl(divisor1 & 0xff, dev->iobase + PCI9118_CNT1); 01724 outl((divisor1 >> 8) & 0xff, dev->iobase + PCI9118_CNT1); 01725 } 01726 } 01727 01728 /* 01729 ============================================================================== 01730 */ 01731 static int pci9118_exttrg_add(comedi_device * dev, unsigned char source) 01732 { 01733 if (source > 3) 01734 return -1; // incorrect source 01735 devpriv->exttrg_users |= (1 << source); 01736 devpriv->IntControlReg |= Int_DTrg; 01737 outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); 01738 outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, devpriv->iobase_a + AMCC_OP_REG_INTCSR); // allow INT in AMCC 01739 return 0; 01740 } 01741 01742 /* 01743 ============================================================================== 01744 */ 01745 static int pci9118_exttrg_del(comedi_device * dev, unsigned char source) 01746 { 01747 if (source > 3) 01748 return -1; // incorrect source 01749 devpriv->exttrg_users &= ~(1 << source); 01750 if (!devpriv->exttrg_users) { // shutdown ext trg intterrupts 01751 devpriv->IntControlReg &= ~Int_DTrg; 01752 if (!devpriv->IntControlReg) // all IRQ disabled 01753 outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) & (~0x00001f00), devpriv->iobase_a + AMCC_OP_REG_INTCSR); // disable int in AMCC 01754 outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); 01755 } 01756 return 0; 01757 } 01758 01759 /* 01760 ============================================================================== 01761 */ 01762 static int pci9118_ai_cancel(comedi_device * dev, comedi_subdevice * s) 01763 { 01764 if (devpriv->usedma) 01765 outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) & (~EN_A2P_TRANSFERS), devpriv->iobase_a + AMCC_OP_REG_MCSR); // stop DMA 01766 pci9118_exttrg_del(dev, EXTTRG_AI); 01767 start_pacer(dev, 0, 0, 0); // stop 8254 counters 01768 devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; 01769 outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); // positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop 01770 devpriv->AdControlReg = 0x00; 01771 outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); // bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable INT and DMA 01772 outl(0, dev->iobase + PCI9118_BURST); 01773 outl(1, dev->iobase + PCI9118_SCANMOD); 01774 outl(2, dev->iobase + PCI9118_SCANMOD); // reset scan queue 01775 outl(0, dev->iobase + PCI9118_DELFIFO); // flush FIFO 01776 01777 devpriv->ai_do = 0; 01778 devpriv->usedma = 0; 01779 01780 devpriv->ai_act_scan = 0; 01781 devpriv->ai_act_dmapos = 0; 01782 s->async->cur_chan = 0; 01783 s->async->inttrig = NULL; 01784 devpriv->ai_buf_ptr = 0; 01785 devpriv->ai_neverending = 0; 01786 devpriv->dma_actbuf = 0; 01787 01788 if (!devpriv->IntControlReg) 01789 outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, devpriv->iobase_a + AMCC_OP_REG_INTCSR); // allow INT in AMCC 01790 01791 return 0; 01792 } 01793 01794 /* 01795 ============================================================================== 01796 */ 01797 static int pci9118_reset(comedi_device * dev) 01798 { 01799 devpriv->IntControlReg = 0; 01800 devpriv->exttrg_users = 0; 01801 inl(dev->iobase + PCI9118_INTCTRL); 01802 outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); // disable interrupts source 01803 outl(0x30, dev->iobase + PCI9118_CNTCTRL); 01804 // outl(0xb4, dev->iobase + PCI9118_CNTCTRL); 01805 start_pacer(dev, 0, 0, 0); // stop 8254 counters 01806 devpriv->AdControlReg = 0; 01807 outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); // bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable INT and DMA 01808 outl(0, dev->iobase + PCI9118_BURST); 01809 outl(1, dev->iobase + PCI9118_SCANMOD); 01810 outl(2, dev->iobase + PCI9118_SCANMOD); // reset scan queue 01811 devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; 01812 outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); // positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop 01813 01814 devpriv->ao_data[0] = 2047; 01815 devpriv->ao_data[1] = 2047; 01816 outl(devpriv->ao_data[0], dev->iobase + PCI9118_DA1); // reset A/D outs to 0V 01817 outl(devpriv->ao_data[1], dev->iobase + PCI9118_DA2); 01818 outl(0, dev->iobase + PCI9118_DO); // reset digi outs to L 01819 comedi_udelay(10); 01820 inl(dev->iobase + PCI9118_AD_DATA); 01821 outl(0, dev->iobase + PCI9118_DELFIFO); // flush FIFO 01822 outl(0, dev->iobase + PCI9118_INTSRC); // remove INT requests 01823 inl(dev->iobase + PCI9118_ADSTAT); // flush A/D status register 01824 inl(dev->iobase + PCI9118_INTSRC); // flush INT requests 01825 devpriv->AdControlReg = 0; 01826 outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); // bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable INT and DMA 01827 01828 devpriv->cnt0_users = 0; 01829 devpriv->exttrg_users = 0; 01830 01831 return 0; 01832 } 01833 01834 /* 01835 ============================================================================== 01836 */ 01837 static int pci9118_attach(comedi_device * dev, comedi_devconfig * it) 01838 { 01839 comedi_subdevice *s; 01840 int ret, pages, i; 01841 unsigned short master; 01842 unsigned int irq; 01843 unsigned long iobase_a, iobase_9; 01844 struct pci_dev *pcidev; 01845 int opt_bus, opt_slot; 01846 const char *errstr; 01847 unsigned char pci_bus, pci_slot, pci_func; 01848 u16 u16w; 01849 01850 rt_printk("comedi%d: adl_pci9118: board=%s", dev->minor, 01851 this_board->name); 01852 01853 opt_bus = it->options[0]; 01854 opt_slot = it->options[1]; 01855 if (it->options[3] & 1) { 01856 master = 0; // user don't want use bus master 01857 } else { 01858 master = 1; 01859 } 01860 01861 if ((ret = alloc_private(dev, sizeof(pci9118_private))) < 0) { 01862 rt_printk(" - Allocation failed!\n"); 01863 return -ENOMEM; 01864 } 01865 01866 /* Look for matching PCI device */ 01867 errstr = "not found!"; 01868 pcidev = NULL; 01869 while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_AMCC, 01870 this_board->device_id, pcidev))) { 01871 /* Found matching vendor/device. */ 01872 if (opt_bus || opt_slot) { 01873 /* Check bus/slot. */ 01874 if (opt_bus != pcidev->bus->number 01875 || opt_slot != PCI_SLOT(pcidev->devfn)) 01876 continue; /* no match */ 01877 } 01878 /* 01879 * Look for device that isn't in use. 01880 * Enable PCI device and request regions. 01881 */ 01882 if (comedi_pci_enable(pcidev, "adl_pci9118")) { 01883 errstr = "failed to enable PCI device and request regions!"; 01884 continue; 01885 } 01886 break; 01887 } 01888 01889 if (!pcidev) { 01890 if (opt_bus || opt_slot) { 01891 rt_printk(" - Card at b:s %d:%d %s\n", 01892 opt_bus, opt_slot, errstr); 01893 } else { 01894 rt_printk(" - Card %s\n", errstr); 01895 } 01896 return -EIO; 01897 } 01898 01899 if (master) { 01900 pci_set_master(pcidev); 01901 } 01902 01903 pci_bus = pcidev->bus->number; 01904 pci_slot = PCI_SLOT(pcidev->devfn); 01905 pci_func = PCI_FUNC(pcidev->devfn); 01906 irq = pcidev->irq; 01907 iobase_a = pci_resource_start(pcidev, 0); 01908 iobase_9 = pci_resource_start(pcidev, 2); 01909 01910 rt_printk(", b:s:f=%d:%d:%d, io=0x%4lx, 0x%4lx", pci_bus, pci_slot, 01911 pci_func, iobase_9, iobase_a); 01912 01913 dev->iobase = iobase_9; 01914 dev->board_name = this_board->name; 01915 01916 devpriv->pcidev = pcidev; 01917 devpriv->iobase_a = iobase_a; 01918 01919 pci9118_reset(dev); 01920 01921 if (it->options[3] & 2) 01922 irq = 0; // user don't want use IRQ 01923 if (irq > 0) { 01924 if (comedi_request_irq(irq, interrupt_pci9118, IRQF_SHARED, 01925 "ADLink PCI-9118", dev)) { 01926 rt_printk(", unable to allocate IRQ %d, DISABLING IT", 01927 irq); 01928 irq = 0; /* Can't use IRQ */ 01929 } else { 01930 rt_printk(", irq=%u", irq); 01931 } 01932 } else { 01933 rt_printk(", IRQ disabled"); 01934 } 01935 01936 dev->irq = irq; 01937 01938 if (master) { // alloc DMA buffers 01939 devpriv->dma_doublebuf = 0; 01940 for (i = 0; i < 2; i++) { 01941 for (pages = 4; pages >= 0; pages--) 01942 if ((devpriv->dmabuf_virt[i] = (sampl_t *) 01943 __get_free_pages(GFP_KERNEL, 01944 pages))) 01945 break; 01946 if (devpriv->dmabuf_virt[i]) { 01947 devpriv->dmabuf_pages[i] = pages; 01948 devpriv->dmabuf_size[i] = PAGE_SIZE * pages; 01949 devpriv->dmabuf_samples[i] = 01950 devpriv->dmabuf_size[i] >> 1; 01951 devpriv->dmabuf_hw[i] = 01952 virt_to_bus((void *)devpriv-> 01953 dmabuf_virt[i]); 01954 } 01955 } 01956 if (!devpriv->dmabuf_virt[0]) { 01957 rt_printk(", Can't allocate DMA buffer, DMA disabled!"); 01958 master = 0; 01959 } 01960 01961 if (devpriv->dmabuf_virt[1]) 01962 devpriv->dma_doublebuf = 1; 01963 01964 } 01965 01966 if ((devpriv->master = master)) { 01967 rt_printk(", bus master"); 01968 } else { 01969 rt_printk(", no bus master"); 01970 } 01971 01972 devpriv->usemux = 0; 01973 if (it->options[2] > 0) { 01974 devpriv->usemux = it->options[2]; 01975 if (devpriv->usemux > 256) 01976 devpriv->usemux = 256; // max 256 channels! 01977 if (it->options[4] > 0) 01978 if (devpriv->usemux > 128) { 01979 devpriv->usemux = 128; // max 128 channels with softare S&H! 01980 } 01981 rt_printk(", ext. mux %d channels", devpriv->usemux); 01982 } 01983 01984 devpriv->softsshdelay = it->options[4]; 01985 if (devpriv->softsshdelay < 0) { // select sample&hold signal polarity 01986 devpriv->softsshdelay = -devpriv->softsshdelay; 01987 devpriv->softsshsample = 0x80; 01988 devpriv->softsshhold = 0x00; 01989 } else { 01990 devpriv->softsshsample = 0x00; 01991 devpriv->softsshhold = 0x80; 01992 } 01993 01994 rt_printk(".\n"); 01995 01996 pci_read_config_word(devpriv->pcidev, PCI_COMMAND, &u16w); 01997 pci_write_config_word(devpriv->pcidev, PCI_COMMAND, u16w | 64); // Enable parity check for parity error 01998 01999 if ((ret = alloc_subdevices(dev, 4)) < 0) 02000 return ret; 02001 02002 s = dev->subdevices + 0; 02003 dev->read_subdev = s; 02004 s->type = COMEDI_SUBD_AI; 02005 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; 02006 if (devpriv->usemux) { 02007 s->n_chan = devpriv->usemux; 02008 } else { 02009 s->n_chan = this_board->n_aichan; 02010 } 02011 s->maxdata = this_board->ai_maxdata; 02012 s->len_chanlist = this_board->n_aichanlist; 02013 s->range_table = this_board->rangelist_ai; 02014 s->cancel = pci9118_ai_cancel; 02015 s->insn_read = pci9118_insn_read_ai; 02016 if (dev->irq) { 02017 s->subdev_flags |= SDF_CMD_READ; 02018 s->do_cmdtest = pci9118_ai_cmdtest; 02019 s->do_cmd = pci9118_ai_cmd; 02020 s->munge = pci9118_ai_munge; 02021 } 02022 02023 s = dev->subdevices + 1; 02024 s->type = COMEDI_SUBD_AO; 02025 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; 02026 s->n_chan = this_board->n_aochan; 02027 s->maxdata = this_board->ao_maxdata; 02028 s->len_chanlist = this_board->n_aochan; 02029 s->range_table = this_board->rangelist_ao; 02030 s->insn_write = pci9118_insn_write_ao; 02031 s->insn_read = pci9118_insn_read_ao; 02032 02033 s = dev->subdevices + 2; 02034 s->type = COMEDI_SUBD_DI; 02035 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; 02036 s->n_chan = 4; 02037 s->maxdata = 1; 02038 s->len_chanlist = 4; 02039 s->range_table = &range_digital; 02040 s->io_bits = 0; /* all bits input */ 02041 s->insn_bits = pci9118_insn_bits_di; 02042 02043 s = dev->subdevices + 3; 02044 s->type = COMEDI_SUBD_DO; 02045 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; 02046 s->n_chan = 4; 02047 s->maxdata = 1; 02048 s->len_chanlist = 4; 02049 s->range_table = &range_digital; 02050 s->io_bits = 0xf; /* all bits output */ 02051 s->insn_bits = pci9118_insn_bits_do; 02052 02053 devpriv->valid = 1; 02054 devpriv->i8254_osc_base = 250; // 250ns=4MHz 02055 devpriv->ai_maskharderr = 0x10a; // default measure crash condition 02056 if (it->options[5]) // disable some requested 02057 devpriv->ai_maskharderr &= ~it->options[5]; 02058 02059 switch (this_board->ai_maxdata) { 02060 case 0xffff: 02061 devpriv->ai16bits = 1; 02062 break; 02063 default: 02064 devpriv->ai16bits = 0; 02065 break; 02066 } 02067 return 0; 02068 } 02069 02070 /* 02071 ============================================================================== 02072 */ 02073 static int pci9118_detach(comedi_device * dev) 02074 { 02075 if (dev->private) { 02076 if (devpriv->valid) 02077 pci9118_reset(dev); 02078 if (dev->irq) 02079 comedi_free_irq(dev->irq, dev); 02080 if (devpriv->pcidev) { 02081 if (dev->iobase) { 02082 comedi_pci_disable(devpriv->pcidev); 02083 } 02084 pci_dev_put(devpriv->pcidev); 02085 } 02086 if (devpriv->dmabuf_virt[0]) 02087 free_pages((unsigned long)devpriv->dmabuf_virt[0], 02088 devpriv->dmabuf_pages[0]); 02089 if (devpriv->dmabuf_virt[1]) 02090 free_pages((unsigned long)devpriv->dmabuf_virt[1], 02091 devpriv->dmabuf_pages[1]); 02092 } 02093 02094 return 0; 02095 } 02096 02097 /* 02098 ============================================================================== 02099 */