RTXI 1.3
comedi/comedi/drivers/s626.c
Go to the documentation of this file.
00001 /*
00002   comedi/drivers/s626.c
00003   Sensoray s626 Comedi driver
00004 
00005   COMEDI - Linux Control and Measurement Device Interface
00006   Copyright (C) 2000 David A. Schleef <ds@schleef.org>
00007 
00008   Based on Sensoray Model 626 Linux driver Version 0.2
00009   Copyright (C) 2002-2004 Sensoray Co., Inc.
00010 
00011   This program is free software; you can redistribute it and/or modify
00012   it under the terms of the GNU General Public License as published by
00013   the Free Software Foundation; either version 2 of the License, or
00014   (at your option) any later version.
00015 
00016   This program is distributed in the hope that it will be useful,
00017   but WITHOUT ANY WARRANTY; without even the implied warranty of
00018   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019   GNU General Public License for more details.
00020 
00021   You should have received a copy of the GNU General Public License
00022   along with this program; if not, write to the Free Software
00023   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024 
00025 */
00026 
00027 /*
00028 Driver: s626
00029 Description: Sensoray 626 driver
00030 Devices: [Sensoray] 626 (s626)
00031 Authors: Gianluca Palli <gpalli@deis.unibo.it>,
00032 Updated: Fri, 15 Feb 2008 10:28:42 +0000
00033 Status: experimental
00034 
00035 Configuration options:
00036   [0] - PCI bus of device (optional)
00037   [1] - PCI slot of device (optional)
00038   If bus/slot is not specified, the first supported
00039   PCI device found will be used.
00040 
00041 INSN_CONFIG instructions:
00042   analog input:
00043    none
00044 
00045   analog output:
00046    none
00047 
00048   digital channel:
00049    s626 has 3 dio subdevices (2,3 and 4) each with 16 i/o channels
00050    supported configuration options:
00051    INSN_CONFIG_DIO_QUERY
00052    COMEDI_INPUT
00053    COMEDI_OUTPUT
00054 
00055   encoder:
00056    Every channel must be configured before reading.
00057 
00058    Example code
00059 
00060    insn.insn=INSN_CONFIG;   //configuration instruction
00061    insn.n=1;                //number of operation (must be 1)
00062    insn.data=&initialvalue; //initial value loaded into encoder
00063                             //during configuration
00064    insn.subdev=5;           //encoder subdevice
00065    insn.chanspec=CR_PACK(encoder_channel,0,AREF_OTHER); //encoder_channel
00066                                                         //to configure
00067 
00068    comedi_do_insn(cf,&insn); //executing configuration
00069 */
00070 
00071 #include <linux/kernel.h>
00072 #include <linux/types.h>
00073 
00074 #include <linux/comedidev.h>
00075 
00076 #include "comedi_pci.h"
00077 
00078 #include "comedi_fc.h"
00079 #include "s626.h"
00080 
00081 MODULE_AUTHOR("Gianluca Palli <gpalli@deis.unibo.it>");
00082 MODULE_DESCRIPTION("Sensoray 626 Comedi driver module");
00083 MODULE_LICENSE("GPL");
00084 
00085 typedef struct s626_board_struct {
00086         const char *name;
00087         int ai_chans;
00088         int ai_bits;
00089         int ao_chans;
00090         int ao_bits;
00091         int dio_chans;
00092         int dio_banks;
00093         int enc_chans;
00094 } s626_board;
00095 
00096 static const s626_board s626_boards[] = {
00097         {
00098               name:     "s626",
00099               ai_chans:S626_ADC_CHANNELS,
00100               ai_bits:  14,
00101               ao_chans:S626_DAC_CHANNELS,
00102               ao_bits:  13,
00103               dio_chans:S626_DIO_CHANNELS,
00104               dio_banks:S626_DIO_BANKS,
00105               enc_chans:S626_ENCODER_CHANNELS,
00106                 }
00107 };
00108 
00109 #define thisboard ((const s626_board *)dev->board_ptr)
00110 #define PCI_VENDOR_ID_S626 0x1131
00111 #define PCI_DEVICE_ID_S626 0x7146
00112 #define PCI_SUBVENDOR_ID_S626 0x6000
00113 #define PCI_SUBDEVICE_ID_S626 0x0272
00114 
00115 static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = {
00116         {PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626,
00117                 PCI_SUBVENDOR_ID_S626, PCI_SUBDEVICE_ID_S626, 0, 0, 0},
00118         {0}
00119 };
00120 
00121 MODULE_DEVICE_TABLE(pci, s626_pci_table);
00122 
00123 static int s626_attach(comedi_device * dev, comedi_devconfig * it);
00124 static int s626_detach(comedi_device * dev);
00125 
00126 static comedi_driver driver_s626 = {
00127       driver_name:"s626",
00128       module:THIS_MODULE,
00129       attach:s626_attach,
00130       detach:s626_detach,
00131 };
00132 
00133 typedef struct {
00134         struct pci_dev *pdev;
00135         void *base_addr;
00136         int got_regions;
00137         short allocatedBuf;
00138         uint8_t ai_cmd_running; // ai_cmd is running
00139         uint8_t ai_continous;   // continous aquisition
00140         int ai_sample_count;    // number of samples to aquire
00141         unsigned int ai_sample_timer;   // time between samples in
00142         // units of the timer
00143         int ai_convert_count;   // conversion counter
00144         unsigned int ai_convert_timer;  // time between conversion in
00145         // units of the timer
00146         uint16_t CounterIntEnabs;       //Counter interrupt enable
00147         //mask for MISC2 register.
00148         uint8_t AdcItems;       //Number of items in ADC poll
00149         //list.
00150         DMABUF RPSBuf;          //DMA buffer used to hold ADC
00151         //(RPS1) program.
00152         DMABUF ANABuf;          //DMA buffer used to receive
00153         //ADC data and hold DAC data.
00154         uint32_t *pDacWBuf;     //Pointer to logical adrs of
00155         //DMA buffer used to hold DAC
00156         //data.
00157         uint16_t Dacpol;        //Image of DAC polarity
00158         //register.
00159         uint8_t TrimSetpoint[12];       //Images of TrimDAC setpoints.
00160         //registers.
00161         uint16_t ChargeEnabled; //Image of MISC2 Battery
00162         //Charge Enabled (0 or
00163         //WRMISC2_CHARGE_ENABLE).
00164         uint16_t WDInterval;    //Image of MISC2 watchdog
00165         //interval control bits.
00166         uint32_t I2CAdrs;       //I2C device address for
00167         //onboard EEPROM (board rev
00168         //dependent).
00169         //  short         I2Cards;
00170         lsampl_t ao_readback[S626_DAC_CHANNELS];
00171 } s626_private;
00172 
00173 typedef struct {
00174         uint16_t RDDIn;
00175         uint16_t WRDOut;
00176         uint16_t RDEdgSel;
00177         uint16_t WREdgSel;
00178         uint16_t RDCapSel;
00179         uint16_t WRCapSel;
00180         uint16_t RDCapFlg;
00181         uint16_t RDIntSel;
00182         uint16_t WRIntSel;
00183 } dio_private;
00184 
00185 static dio_private dio_private_A = {
00186       RDDIn:LP_RDDINA,
00187       WRDOut:LP_WRDOUTA,
00188       RDEdgSel:LP_RDEDGSELA,
00189       WREdgSel:LP_WREDGSELA,
00190       RDCapSel:LP_RDCAPSELA,
00191       WRCapSel:LP_WRCAPSELA,
00192       RDCapFlg:LP_RDCAPFLGA,
00193       RDIntSel:LP_RDINTSELA,
00194       WRIntSel:LP_WRINTSELA,
00195 };
00196 
00197 static dio_private dio_private_B = {
00198       RDDIn:LP_RDDINB,
00199       WRDOut:LP_WRDOUTB,
00200       RDEdgSel:LP_RDEDGSELB,
00201       WREdgSel:LP_WREDGSELB,
00202       RDCapSel:LP_RDCAPSELB,
00203       WRCapSel:LP_WRCAPSELB,
00204       RDCapFlg:LP_RDCAPFLGB,
00205       RDIntSel:LP_RDINTSELB,
00206       WRIntSel:LP_WRINTSELB,
00207 };
00208 
00209 static dio_private dio_private_C = {
00210       RDDIn:LP_RDDINC,
00211       WRDOut:LP_WRDOUTC,
00212       RDEdgSel:LP_RDEDGSELC,
00213       WREdgSel:LP_WREDGSELC,
00214       RDCapSel:LP_RDCAPSELC,
00215       WRCapSel:LP_WRCAPSELC,
00216       RDCapFlg:LP_RDCAPFLGC,
00217       RDIntSel:LP_RDINTSELC,
00218       WRIntSel:LP_WRINTSELC,
00219 };
00220 
00221 /* to group dio devices (48 bits mask and data are not allowed ???)
00222 static dio_private *dio_private_word[]={
00223   &dio_private_A,
00224   &dio_private_B,
00225   &dio_private_C,
00226 };
00227 */
00228 
00229 #define devpriv ((s626_private *)dev->private)
00230 #define diopriv ((dio_private *)s->private)
00231 
00232 COMEDI_PCI_INITCLEANUP_NOMODULE(driver_s626, s626_pci_table);
00233 
00234 //ioctl routines
00235 static int s626_ai_insn_config(comedi_device * dev, comedi_subdevice * s,
00236         comedi_insn * insn, lsampl_t * data);
00237 /* static int s626_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data); */
00238 static int s626_ai_insn_read(comedi_device * dev, comedi_subdevice * s,
00239         comedi_insn * insn, lsampl_t * data);
00240 static int s626_ai_cmd(comedi_device * dev, comedi_subdevice * s);
00241 static int s626_ai_cmdtest(comedi_device * dev, comedi_subdevice * s,
00242         comedi_cmd * cmd);
00243 static int s626_ai_cancel(comedi_device * dev, comedi_subdevice * s);
00244 static int s626_ao_winsn(comedi_device * dev, comedi_subdevice * s,
00245         comedi_insn * insn, lsampl_t * data);
00246 static int s626_ao_rinsn(comedi_device * dev, comedi_subdevice * s,
00247         comedi_insn * insn, lsampl_t * data);
00248 static int s626_dio_insn_bits(comedi_device * dev, comedi_subdevice * s,
00249         comedi_insn * insn, lsampl_t * data);
00250 static int s626_dio_insn_config(comedi_device * dev, comedi_subdevice * s,
00251         comedi_insn * insn, lsampl_t * data);
00252 static int s626_dio_set_irq(comedi_device * dev, unsigned int chan);
00253 static int s626_dio_reset_irq(comedi_device * dev, unsigned int gruop,
00254         unsigned int mask);
00255 static int s626_dio_clear_irq(comedi_device * dev);
00256 static int s626_enc_insn_config(comedi_device * dev, comedi_subdevice * s,
00257         comedi_insn * insn, lsampl_t * data);
00258 static int s626_enc_insn_read(comedi_device * dev, comedi_subdevice * s,
00259         comedi_insn * insn, lsampl_t * data);
00260 static int s626_enc_insn_write(comedi_device * dev, comedi_subdevice * s,
00261         comedi_insn * insn, lsampl_t * data);
00262 static int s626_ns_to_timer(int *nanosec, int round_mode);
00263 static int s626_ai_load_polllist(uint8_t * ppl, comedi_cmd * cmd);
00264 static int s626_ai_inttrig(comedi_device * dev, comedi_subdevice * s,
00265         unsigned int trignum);
00266 static irqreturn_t s626_irq_handler(int irq, void *d PT_REGS_ARG);
00267 static lsampl_t s626_ai_reg_to_uint(int data);
00268 /* static lsampl_t s626_uint_to_reg(comedi_subdevice *s, int data); */
00269 
00270 //end ioctl routines
00271 
00272 //internal routines
00273 static void s626_dio_init(comedi_device * dev);
00274 static void ResetADC(comedi_device * dev, uint8_t * ppl);
00275 static void LoadTrimDACs(comedi_device * dev);
00276 static void WriteTrimDAC(comedi_device * dev, uint8_t LogicalChan,
00277         uint8_t DacData);
00278 static uint8_t I2Cread(comedi_device * dev, uint8_t addr);
00279 static uint32_t I2Chandshake(comedi_device * dev, uint32_t val);
00280 static void SetDAC(comedi_device * dev, uint16_t chan, short dacdata);
00281 static void SendDAC(comedi_device * dev, uint32_t val);
00282 static void WriteMISC2(comedi_device * dev, uint16_t NewImage);
00283 static void DEBItransfer(comedi_device * dev);
00284 static uint16_t DEBIread(comedi_device * dev, uint16_t addr);
00285 static void DEBIwrite(comedi_device * dev, uint16_t addr, uint16_t wdata);
00286 static void DEBIreplace(comedi_device * dev, uint16_t addr, uint16_t mask,
00287         uint16_t wdata);
00288 static void CloseDMAB(comedi_device * dev, DMABUF * pdma, size_t bsize);
00289 
00290 // COUNTER OBJECT ------------------------------------------------
00291 typedef struct enc_private_struct {
00292         // Pointers to functions that differ for A and B counters:
00293         uint16_t(*GetEnable) (comedi_device * dev, struct enc_private_struct *);        //Return clock enable.
00294         uint16_t(*GetIntSrc) (comedi_device * dev, struct enc_private_struct *);        //Return interrupt source.
00295         uint16_t(*GetLoadTrig) (comedi_device * dev, struct enc_private_struct *);      //Return preload trigger source.
00296         uint16_t(*GetMode) (comedi_device * dev, struct enc_private_struct *);  //Return standardized operating mode.
00297         void (*PulseIndex) (comedi_device * dev, struct enc_private_struct *);  //Generate soft index strobe.
00298         void (*SetEnable) (comedi_device * dev, struct enc_private_struct *, uint16_t enab);    //Program clock enable.
00299         void (*SetIntSrc) (comedi_device * dev, struct enc_private_struct *, uint16_t IntSource);       //Program interrupt source.
00300         void (*SetLoadTrig) (comedi_device * dev, struct enc_private_struct *, uint16_t Trig);  //Program preload trigger source.
00301         void (*SetMode) (comedi_device * dev, struct enc_private_struct *, uint16_t Setup, uint16_t DisableIntSrc);     //Program standardized operating mode.
00302         void (*ResetCapFlags) (comedi_device * dev, struct enc_private_struct *);       //Reset event capture flags.
00303 
00304         uint16_t MyCRA;         //   Address of CRA register.
00305         uint16_t MyCRB;         //   Address of CRB register.
00306         uint16_t MyLatchLsw;    //   Address of Latch least-significant-word
00307         //   register.
00308         uint16_t MyEventBits[4];        //   Bit translations for IntSrc -->RDMISC2.
00309 } enc_private;                  //counter object
00310 
00311 #define encpriv ((enc_private *)(dev->subdevices+5)->private)
00312 
00313 //counters routines
00314 static void s626_timer_load(comedi_device * dev, enc_private * k, int tick);
00315 static uint32_t ReadLatch(comedi_device * dev, enc_private * k);
00316 static void ResetCapFlags_A(comedi_device * dev, enc_private * k);
00317 static void ResetCapFlags_B(comedi_device * dev, enc_private * k);
00318 static uint16_t GetMode_A(comedi_device * dev, enc_private * k);
00319 static uint16_t GetMode_B(comedi_device * dev, enc_private * k);
00320 static void SetMode_A(comedi_device * dev, enc_private * k, uint16_t Setup,
00321         uint16_t DisableIntSrc);
00322 static void SetMode_B(comedi_device * dev, enc_private * k, uint16_t Setup,
00323         uint16_t DisableIntSrc);
00324 static void SetEnable_A(comedi_device * dev, enc_private * k, uint16_t enab);
00325 static void SetEnable_B(comedi_device * dev, enc_private * k, uint16_t enab);
00326 static uint16_t GetEnable_A(comedi_device * dev, enc_private * k);
00327 static uint16_t GetEnable_B(comedi_device * dev, enc_private * k);
00328 static void SetLatchSource(comedi_device * dev, enc_private * k,
00329         uint16_t value);
00330 /* static uint16_t GetLatchSource(comedi_device *dev, enc_private *k ); */
00331 static void SetLoadTrig_A(comedi_device * dev, enc_private * k, uint16_t Trig);
00332 static void SetLoadTrig_B(comedi_device * dev, enc_private * k, uint16_t Trig);
00333 static uint16_t GetLoadTrig_A(comedi_device * dev, enc_private * k);
00334 static uint16_t GetLoadTrig_B(comedi_device * dev, enc_private * k);
00335 static void SetIntSrc_B(comedi_device * dev, enc_private * k,
00336         uint16_t IntSource);
00337 static void SetIntSrc_A(comedi_device * dev, enc_private * k,
00338         uint16_t IntSource);
00339 static uint16_t GetIntSrc_A(comedi_device * dev, enc_private * k);
00340 static uint16_t GetIntSrc_B(comedi_device * dev, enc_private * k);
00341 /* static void SetClkMult(comedi_device *dev, enc_private *k, uint16_t value ) ; */
00342 /* static uint16_t GetClkMult(comedi_device *dev, enc_private *k ) ; */
00343 /* static void SetIndexPol(comedi_device *dev, enc_private *k, uint16_t value ); */
00344 /* static uint16_t GetClkPol(comedi_device *dev, enc_private *k ) ; */
00345 /* static void SetIndexSrc( comedi_device *dev,enc_private *k, uint16_t value );  */
00346 /* static uint16_t GetClkSrc( comedi_device *dev,enc_private *k );  */
00347 /* static void SetIndexSrc( comedi_device *dev,enc_private *k, uint16_t value );  */
00348 /* static uint16_t GetIndexSrc( comedi_device *dev,enc_private *k );  */
00349 static void PulseIndex_A(comedi_device * dev, enc_private * k);
00350 static void PulseIndex_B(comedi_device * dev, enc_private * k);
00351 static void Preload(comedi_device * dev, enc_private * k, uint32_t value);
00352 static void CountersInit(comedi_device * dev);
00353 //end internal routines
00354 
00356 // Counter objects constructor.
00357 
00358 // Counter overflow/index event flag masks for RDMISC2.
00359 #define INDXMASK(C)             ( 1 << ( ( (C) > 2 ) ? ( (C) * 2 - 1 ) : ( (C) * 2 +  4 ) ) )
00360 #define OVERMASK(C)             ( 1 << ( ( (C) > 2 ) ? ( (C) * 2 + 5 ) : ( (C) * 2 + 10 ) ) )
00361 #define EVBITS(C)               { 0, OVERMASK(C), INDXMASK(C), OVERMASK(C) | INDXMASK(C) }
00362 
00363 // Translation table to map IntSrc into equivalent RDMISC2 event flag
00364 // bits.
00365 //static const uint16_t EventBits[][4] = { EVBITS(0), EVBITS(1), EVBITS(2), EVBITS(3), EVBITS(4), EVBITS(5) };
00366 
00367 /* enc_private; */
00368 static enc_private enc_private_data[] = {
00369         {
00370               GetEnable:GetEnable_A,
00371               GetIntSrc:GetIntSrc_A,
00372               GetLoadTrig:GetLoadTrig_A,
00373               GetMode:  GetMode_A,
00374               PulseIndex:PulseIndex_A,
00375               SetEnable:SetEnable_A,
00376               SetIntSrc:SetIntSrc_A,
00377               SetLoadTrig:SetLoadTrig_A,
00378               SetMode:  SetMode_A,
00379               ResetCapFlags:ResetCapFlags_A,
00380               MyCRA:    LP_CR0A,
00381               MyCRB:    LP_CR0B,
00382               MyLatchLsw:LP_CNTR0ALSW,
00383               MyEventBits:EVBITS(0),
00384                 },
00385         {
00386               GetEnable:GetEnable_A,
00387               GetIntSrc:GetIntSrc_A,
00388               GetLoadTrig:GetLoadTrig_A,
00389               GetMode:  GetMode_A,
00390               PulseIndex:PulseIndex_A,
00391               SetEnable:SetEnable_A,
00392               SetIntSrc:SetIntSrc_A,
00393               SetLoadTrig:SetLoadTrig_A,
00394               SetMode:  SetMode_A,
00395               ResetCapFlags:ResetCapFlags_A,
00396               MyCRA:    LP_CR1A,
00397               MyCRB:    LP_CR1B,
00398               MyLatchLsw:LP_CNTR1ALSW,
00399               MyEventBits:EVBITS(1),
00400                 },
00401         {
00402               GetEnable:GetEnable_A,
00403               GetIntSrc:GetIntSrc_A,
00404               GetLoadTrig:GetLoadTrig_A,
00405               GetMode:  GetMode_A,
00406               PulseIndex:PulseIndex_A,
00407               SetEnable:SetEnable_A,
00408               SetIntSrc:SetIntSrc_A,
00409               SetLoadTrig:SetLoadTrig_A,
00410               SetMode:  SetMode_A,
00411               ResetCapFlags:ResetCapFlags_A,
00412               MyCRA:    LP_CR2A,
00413               MyCRB:    LP_CR2B,
00414               MyLatchLsw:LP_CNTR2ALSW,
00415               MyEventBits:EVBITS(2),
00416                 },
00417         {
00418               GetEnable:GetEnable_B,
00419               GetIntSrc:GetIntSrc_B,
00420               GetLoadTrig:GetLoadTrig_B,
00421               GetMode:  GetMode_B,
00422               PulseIndex:PulseIndex_B,
00423               SetEnable:SetEnable_B,
00424               SetIntSrc:SetIntSrc_B,
00425               SetLoadTrig:SetLoadTrig_B,
00426               SetMode:  SetMode_B,
00427               ResetCapFlags:ResetCapFlags_B,
00428               MyCRA:    LP_CR0A,
00429               MyCRB:    LP_CR0B,
00430               MyLatchLsw:LP_CNTR0BLSW,
00431               MyEventBits:EVBITS(3),
00432                 },
00433         {
00434               GetEnable:GetEnable_B,
00435               GetIntSrc:GetIntSrc_B,
00436               GetLoadTrig:GetLoadTrig_B,
00437               GetMode:  GetMode_B,
00438               PulseIndex:PulseIndex_B,
00439               SetEnable:SetEnable_B,
00440               SetIntSrc:SetIntSrc_B,
00441               SetLoadTrig:SetLoadTrig_B,
00442               SetMode:  SetMode_B,
00443               ResetCapFlags:ResetCapFlags_B,
00444               MyCRA:    LP_CR1A,
00445               MyCRB:    LP_CR1B,
00446               MyLatchLsw:LP_CNTR1BLSW,
00447               MyEventBits:EVBITS(4),
00448                 },
00449         {
00450               GetEnable:GetEnable_B,
00451               GetIntSrc:GetIntSrc_B,
00452               GetLoadTrig:GetLoadTrig_B,
00453               GetMode:  GetMode_B,
00454               PulseIndex:PulseIndex_B,
00455               SetEnable:SetEnable_B,
00456               SetIntSrc:SetIntSrc_B,
00457               SetLoadTrig:SetLoadTrig_B,
00458               SetMode:  SetMode_B,
00459               ResetCapFlags:ResetCapFlags_B,
00460               MyCRA:    LP_CR2A,
00461               MyCRB:    LP_CR2B,
00462               MyLatchLsw:LP_CNTR2BLSW,
00463               MyEventBits:EVBITS(5),
00464                 },
00465 };
00466 
00467 // enab/disable a function or test status bit(s) that are accessed
00468 // through Main Control Registers 1 or 2.
00469 #define MC_ENABLE( REGADRS, CTRLWORD )  writel(  ( (uint32_t)( CTRLWORD ) << 16 ) | (uint32_t)( CTRLWORD ),devpriv->base_addr+( REGADRS ) )
00470 
00471 #define MC_DISABLE( REGADRS, CTRLWORD ) writel(  (uint32_t)( CTRLWORD ) << 16 , devpriv->base_addr+( REGADRS ) )
00472 
00473 #define MC_TEST( REGADRS, CTRLWORD )    ( ( readl(devpriv->base_addr+( REGADRS )) & CTRLWORD ) != 0 )
00474 
00475 /* #define WR7146(REGARDS,CTRLWORD)
00476     writel(CTRLWORD,(uint32_t)(devpriv->base_addr+(REGARDS))) */
00477 #define WR7146(REGARDS,CTRLWORD) writel(CTRLWORD,devpriv->base_addr+(REGARDS))
00478 
00479 /* #define RR7146(REGARDS)
00480     readl((uint32_t)(devpriv->base_addr+(REGARDS))) */
00481 #define RR7146(REGARDS)         readl(devpriv->base_addr+(REGARDS))
00482 
00483 #define BUGFIX_STREG(REGADRS)   ( REGADRS - 4 )
00484 
00485 // Write a time slot control record to TSL2.
00486 #define VECTPORT( VECTNUM )             (P_TSL2 + ( (VECTNUM) << 2 ))
00487 #define SETVECT( VECTNUM, VECTVAL )     WR7146(VECTPORT( VECTNUM ), (VECTVAL))
00488 
00489 // Code macros used for constructing I2C command bytes.
00490 #define I2C_B2(ATTR,VAL)        ( ( (ATTR) << 6 ) | ( (VAL) << 24 ) )
00491 #define I2C_B1(ATTR,VAL)        ( ( (ATTR) << 4 ) | ( (VAL) << 16 ) )
00492 #define I2C_B0(ATTR,VAL)        ( ( (ATTR) << 2 ) | ( (VAL) <<  8 ) )
00493 
00494 static const comedi_lrange s626_range_table = { 2, {
00495                         RANGE(-5, 5),
00496                         RANGE(-10, 10),
00497         }
00498 };
00499 
00500 static int s626_attach(comedi_device * dev, comedi_devconfig * it)
00501 {
00502 /*   uint8_t    PollList; */
00503 /*   uint16_t   AdcData; */
00504 /*   uint16_t   StartVal; */
00505 /*   uint16_t   index; */
00506 /*   unsigned int data[16]; */
00507         int result;
00508         int i;
00509         int ret;
00510         resource_size_t resourceStart;
00511         dma_addr_t appdma;
00512         comedi_subdevice *s;
00513         struct pci_dev *pdev;
00514 
00515         if (alloc_private(dev, sizeof(s626_private)) < 0)
00516                 return -ENOMEM;
00517 
00518         for (pdev = pci_get_subsys(PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626,
00519                         PCI_SUBVENDOR_ID_S626, PCI_SUBDEVICE_ID_S626, NULL);
00520                 pdev != NULL;
00521                 pdev = pci_get_subsys(PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626,
00522                         PCI_SUBVENDOR_ID_S626, PCI_SUBDEVICE_ID_S626, pdev)) {
00523                 if (it->options[0] || it->options[1]) {
00524                         if (pdev->bus->number == it->options[0] &&
00525                                 PCI_SLOT(pdev->devfn) == it->options[1]) {
00526                                 /* matches requested bus/slot */
00527                                 break;
00528                         }
00529                 } else {
00530                         /* no bus/slot specified */
00531                         break;
00532                 }
00533         }
00534         devpriv->pdev = pdev;
00535 
00536         if (pdev == NULL) {
00537                 printk("s626_attach: Board not present!!!\n");
00538                 return -ENODEV;
00539         }
00540 
00541         if ((result = comedi_pci_enable(pdev, "s626")) < 0) {
00542                 printk("s626_attach: comedi_pci_enable fails\n");
00543                 return -ENODEV;
00544         }
00545         devpriv->got_regions = 1;
00546 
00547         resourceStart = pci_resource_start(devpriv->pdev, 0);
00548 
00549         devpriv->base_addr = ioremap(resourceStart, SIZEOF_ADDRESS_SPACE);
00550         if (devpriv->base_addr == NULL) {
00551                 printk("s626_attach: IOREMAP failed\n");
00552                 return -ENODEV;
00553         }
00554 
00555         if (devpriv->base_addr) {
00556                 //disable master interrupt
00557                 writel(0, devpriv->base_addr + P_IER);
00558 
00559                 //soft reset
00560                 writel(MC1_SOFT_RESET, devpriv->base_addr + P_MC1);
00561 
00562                 //DMA FIXME DMA//
00563                 DEBUG("s626_attach: DMA ALLOCATION\n");
00564 
00565                 //adc buffer allocation
00566                 devpriv->allocatedBuf = 0;
00567 
00568                 if ((devpriv->ANABuf.LogicalBase =
00569                                 pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE,
00570                                         &appdma)) == NULL) {
00571                         printk("s626_attach: DMA Memory mapping error\n");
00572                         return -ENOMEM;
00573                 }
00574 
00575                 devpriv->ANABuf.PhysicalBase = appdma;
00576 
00577                 DEBUG("s626_attach: AllocDMAB ADC Logical=%p, bsize=%d, Physical=0x%x\n", devpriv->ANABuf.LogicalBase, DMABUF_SIZE, (uint32_t) devpriv->ANABuf.PhysicalBase);
00578 
00579                 devpriv->allocatedBuf++;
00580 
00581                 if ((devpriv->RPSBuf.LogicalBase =
00582                                 pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE,
00583                                         &appdma)) == NULL) {
00584                         printk("s626_attach: DMA Memory mapping error\n");
00585                         return -ENOMEM;
00586                 }
00587 
00588                 devpriv->RPSBuf.PhysicalBase = appdma;
00589 
00590                 DEBUG("s626_attach: AllocDMAB RPS Logical=%p, bsize=%d, Physical=0x%x\n", devpriv->RPSBuf.LogicalBase, DMABUF_SIZE, (uint32_t) devpriv->RPSBuf.PhysicalBase);
00591 
00592                 devpriv->allocatedBuf++;
00593 
00594         }
00595 
00596         dev->board_ptr = s626_boards;
00597         dev->board_name = thisboard->name;
00598 
00599         if (alloc_subdevices(dev, 6) < 0)
00600                 return -ENOMEM;
00601 
00602         dev->iobase = (unsigned long)devpriv->base_addr;
00603         dev->irq = devpriv->pdev->irq;
00604 
00605         //set up interrupt handler
00606         if (dev->irq == 0) {
00607                 printk(" unknown irq (bad)\n");
00608         } else {
00609                 if ((ret = comedi_request_irq(dev->irq, s626_irq_handler,
00610                                         IRQF_SHARED, "s626", dev)) < 0) {
00611                         printk(" irq not available\n");
00612                         dev->irq = 0;
00613                 }
00614         }
00615 
00616         DEBUG("s626_attach: -- it opts  %d,%d -- \n",
00617                 it->options[0], it->options[1]);
00618 
00619         s = dev->subdevices + 0;
00620         /* analog input subdevice */
00621         dev->read_subdev = s;
00622         /* we support single-ended (ground) and differential */
00623         s->type = COMEDI_SUBD_AI;
00624         s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_CMD_READ;
00625         s->n_chan = thisboard->ai_chans;
00626         s->maxdata = (0xffff >> 2);
00627         s->range_table = &s626_range_table;
00628         s->len_chanlist = thisboard->ai_chans;  /* This is the maximum chanlist
00629                                                    length that the board can
00630                                                    handle */
00631         s->insn_config = s626_ai_insn_config;
00632         s->insn_read = s626_ai_insn_read;
00633         s->do_cmd = s626_ai_cmd;
00634         s->do_cmdtest = s626_ai_cmdtest;
00635         s->cancel = s626_ai_cancel;
00636 
00637         s = dev->subdevices + 1;
00638         /* analog output subdevice */
00639         s->type = COMEDI_SUBD_AO;
00640         s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
00641         s->n_chan = thisboard->ao_chans;
00642         s->maxdata = (0x3fff);
00643         s->range_table = &range_bipolar10;
00644         s->insn_write = s626_ao_winsn;
00645         s->insn_read = s626_ao_rinsn;
00646 
00647         s = dev->subdevices + 2;
00648         /* digital I/O subdevice */
00649         s->type = COMEDI_SUBD_DIO;
00650         s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
00651         s->n_chan = S626_DIO_CHANNELS;
00652         s->maxdata = 1;
00653         s->io_bits = 0xffff;
00654         s->private = &dio_private_A;
00655         s->range_table = &range_digital;
00656         s->insn_config = s626_dio_insn_config;
00657         s->insn_bits = s626_dio_insn_bits;
00658 
00659         s = dev->subdevices + 3;
00660         /* digital I/O subdevice */
00661         s->type = COMEDI_SUBD_DIO;
00662         s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
00663         s->n_chan = 16;
00664         s->maxdata = 1;
00665         s->io_bits = 0xffff;
00666         s->private = &dio_private_B;
00667         s->range_table = &range_digital;
00668         s->insn_config = s626_dio_insn_config;
00669         s->insn_bits = s626_dio_insn_bits;
00670 
00671         s = dev->subdevices + 4;
00672         /* digital I/O subdevice */
00673         s->type = COMEDI_SUBD_DIO;
00674         s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
00675         s->n_chan = 16;
00676         s->maxdata = 1;
00677         s->io_bits = 0xffff;
00678         s->private = &dio_private_C;
00679         s->range_table = &range_digital;
00680         s->insn_config = s626_dio_insn_config;
00681         s->insn_bits = s626_dio_insn_bits;
00682 
00683         s = dev->subdevices + 5;
00684         /* encoder (counter) subdevice */
00685         s->type = COMEDI_SUBD_COUNTER;
00686         s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL;
00687         s->n_chan = thisboard->enc_chans;
00688         s->private = enc_private_data;
00689         s->insn_config = s626_enc_insn_config;
00690         s->insn_read = s626_enc_insn_read;
00691         s->insn_write = s626_enc_insn_write;
00692         s->maxdata = 0xffffff;
00693         s->range_table = &range_unknown;
00694 
00695         //stop ai_command
00696         devpriv->ai_cmd_running = 0;
00697 
00698         if (devpriv->base_addr && (devpriv->allocatedBuf == 2)) {
00699                 dma_addr_t pPhysBuf;
00700                 uint16_t chan;
00701 
00702                 // enab DEBI and audio pins, enable I2C interface.
00703                 MC_ENABLE(P_MC1, MC1_DEBI | MC1_AUDIO | MC1_I2C);
00704                 // Configure DEBI operating mode.
00705                 WR7146(P_DEBICFG, DEBI_CFG_SLAVE16      // Local bus is 16
00706                         // bits wide.
00707                         | (DEBI_TOUT << DEBI_CFG_TOUT_BIT)      // Declare DEBI
00708                         // transfer timeout
00709                         // interval.
00710                         | DEBI_SWAP     // Set up byte lane
00711                         // steering.
00712                         | DEBI_CFG_INTEL);      // Intel-compatible
00713                 // local bus (DEBI
00714                 // never times out).
00715                 DEBUG("s626_attach: %d debi init -- %d\n",
00716                         DEBI_CFG_SLAVE16 | (DEBI_TOUT << DEBI_CFG_TOUT_BIT) |
00717                         DEBI_SWAP | DEBI_CFG_INTEL,
00718                         DEBI_CFG_INTEL | DEBI_CFG_TOQ | DEBI_CFG_INCQ |
00719                         DEBI_CFG_16Q);
00720 
00721                 //DEBI INIT S626 WR7146( P_DEBICFG, DEBI_CFG_INTEL | DEBI_CFG_TOQ
00722                 //| DEBI_CFG_INCQ| DEBI_CFG_16Q); //end
00723 
00724                 // Paging is disabled.
00725                 WR7146(P_DEBIPAGE, DEBI_PAGE_DISABLE);  // Disable MMU paging.
00726 
00727                 // Init GPIO so that ADC Start* is negated.
00728                 WR7146(P_GPIO, GPIO_BASE | GPIO1_HI);
00729 
00730                 //IsBoardRevA is a boolean that indicates whether the board is
00731                 //RevA.
00732 
00733                 // VERSION 2.01 CHANGE: REV A & B BOARDS NOW SUPPORTED BY DYNAMIC
00734                 // EEPROM ADDRESS SELECTION.  Initialize the I2C interface, which
00735                 // is used to access the onboard serial EEPROM.  The EEPROM's I2C
00736                 // DeviceAddress is hardwired to a value that is dependent on the
00737                 // 626 board revision.  On all board revisions, the EEPROM stores
00738                 // TrimDAC calibration constants for analog I/O.  On RevB and
00739                 // higher boards, the DeviceAddress is hardwired to 0 to enable
00740                 // the EEPROM to also store the PCI SubVendorID and SubDeviceID;
00741                 // this is the address at which the SAA7146 expects a
00742                 // configuration EEPROM to reside.  On RevA boards, the EEPROM
00743                 // device address, which is hardwired to 4, prevents the SAA7146
00744                 // from retrieving PCI sub-IDs, so the SAA7146 uses its built-in
00745                 // default values, instead.
00746 
00747                 //    devpriv->I2Cards= IsBoardRevA ? 0xA8 : 0xA0; // Set I2C EEPROM
00748                 // DeviceType (0xA0)
00749                 // and DeviceAddress<<1.
00750 
00751                 devpriv->I2CAdrs = 0xA0;        // I2C device address for onboard
00752                 // eeprom(revb)
00753 
00754                 // Issue an I2C ABORT command to halt any I2C operation in
00755                 //progress and reset BUSY flag.
00756                 WR7146(P_I2CSTAT, I2C_CLKSEL | I2C_ABORT);      // Write I2C control:
00757                 // abort any I2C
00758                 // activity.
00759                 MC_ENABLE(P_MC2, MC2_UPLD_IIC); // Invoke command
00760                 // upload
00761                 while ((RR7146(P_MC2) & MC2_UPLD_IIC) == 0) ;   // and wait for
00762                 // upload to
00763                 // complete.
00764 
00765                 // Per SAA7146 data sheet, write to STATUS reg twice to reset all
00766                 // I2C error flags.
00767                 for (i = 0; i < 2; i++) {
00768                         WR7146(P_I2CSTAT, I2C_CLKSEL);  // Write I2C control: reset
00769                         // error flags.
00770                         MC_ENABLE(P_MC2, MC2_UPLD_IIC); // Invoke command upload
00771                         while (!MC_TEST(P_MC2, MC2_UPLD_IIC)) ; //   and wait for
00772                         //   upload to
00773                         //   complete.
00774                 }
00775 
00776                 // Init audio interface functional attributes: set DAC/ADC serial
00777                 // clock rates, invert DAC serial clock so that DAC data setup
00778                 // times are satisfied, enable DAC serial clock out.
00779                 WR7146(P_ACON2, ACON2_INIT);
00780 
00781                 // Set up TSL1 slot list, which is used to control the
00782                 // accumulation of ADC data: RSD1 = shift data in on SD1.  SIB_A1
00783                 // = store data uint8_t at next available location in FB BUFFER1
00784                 // register.
00785                 WR7146(P_TSL1, RSD1 | SIB_A1);  // Fetch ADC high data
00786                 // uint8_t.
00787                 WR7146(P_TSL1 + 4, RSD1 | SIB_A1 | EOS);        // Fetch ADC low data
00788                 // uint8_t; end of
00789                 // TSL1.
00790 
00791                 // enab TSL1 slot list so that it executes all the time.
00792                 WR7146(P_ACON1, ACON1_ADCSTART);
00793 
00794                 // Initialize RPS registers used for ADC.
00795 
00796                 //Physical start of RPS program.
00797                 WR7146(P_RPSADDR1, (uint32_t) devpriv->RPSBuf.PhysicalBase);
00798 
00799                 WR7146(P_RPSPAGE1, 0);  // RPS program performs no
00800                 // explicit mem writes.
00801                 WR7146(P_RPS1_TOUT, 0); // Disable RPS timeouts.
00802 
00803                 // SAA7146 BUG WORKAROUND.  Initialize SAA7146 ADC interface to a
00804                 // known state by invoking ADCs until FB BUFFER 1 register shows
00805                 // that it is correctly receiving ADC data.  This is necessary
00806                 // because the SAA7146 ADC interface does not start up in a
00807                 // defined state after a PCI reset.
00808 
00809 /*     PollList = EOPL;                 // Create a simple polling */
00810 /*                                      // list for analog input */
00811 /*                                      // channel 0. */
00812 /*     ResetADC( dev, &PollList ); */
00813 
00814 /*     s626_ai_rinsn(dev,dev->subdevices,NULL,data); //( &AdcData ); // */
00815 /*                                                //Get initial ADC */
00816 /*                                                //value. */
00817 
00818 /*     StartVal = data[0]; */
00819 
00820 /*     // VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED EXECUTION. */
00821 /*     // Invoke ADCs until the new ADC value differs from the initial */
00822 /*     // value or a timeout occurs.  The timeout protects against the */
00823 /*     // possibility that the driver is restarting and the ADC data is a */
00824 /*     // fixed value resulting from the applied ADC analog input being */
00825 /*     // unusually quiet or at the rail. */
00826 
00827 /*     for ( index = 0; index < 500; index++ ) */
00828 /*       { */
00829 /*      s626_ai_rinsn(dev,dev->subdevices,NULL,data); */
00830 /*      AdcData = data[0];      //ReadADC(  &AdcData ); */
00831 /*      if ( AdcData != StartVal ) */
00832 /*        break; */
00833 /*       } */
00834 
00835                 // end initADC
00836 
00837                 // init the DAC interface
00838 
00839                 // Init Audio2's output DMAC attributes: burst length = 1 DWORD,
00840                 // threshold = 1 DWORD.
00841                 WR7146(P_PCI_BT_A, 0);
00842 
00843                 // Init Audio2's output DMA physical addresses.  The protection
00844                 // address is set to 1 DWORD past the base address so that a
00845                 // single DWORD will be transferred each time a DMA transfer is
00846                 // enabled.
00847 
00848                 pPhysBuf =
00849                         devpriv->ANABuf.PhysicalBase +
00850                         (DAC_WDMABUF_OS * sizeof(uint32_t));
00851 
00852                 WR7146(P_BASEA2_OUT, (uint32_t) pPhysBuf);      // Buffer base adrs.
00853                 WR7146(P_PROTA2_OUT, (uint32_t) (pPhysBuf + sizeof(uint32_t))); // Protection address.
00854 
00855                 // Cache Audio2's output DMA buffer logical address.  This is
00856                 // where DAC data is buffered for A2 output DMA transfers.
00857                 devpriv->pDacWBuf =
00858                         (uint32_t *) devpriv->ANABuf.LogicalBase +
00859                         DAC_WDMABUF_OS;
00860 
00861                 // Audio2's output channels does not use paging.  The protection
00862                 // violation handling bit is set so that the DMAC will
00863                 // automatically halt and its PCI address pointer will be reset
00864                 // when the protection address is reached.
00865                 WR7146(P_PAGEA2_OUT, 8);
00866 
00867                 // Initialize time slot list 2 (TSL2), which is used to control
00868                 // the clock generation for and serialization of data to be sent
00869                 // to the DAC devices.  Slot 0 is a NOP that is used to trap TSL
00870                 // execution; this permits other slots to be safely modified
00871                 // without first turning off the TSL sequencer (which is
00872                 // apparently impossible to do).  Also, SD3 (which is driven by a
00873                 // pull-up resistor) is shifted in and stored to the MSB of
00874                 // FB_BUFFER2 to be used as evidence that the slot sequence has
00875                 // not yet finished executing.
00876                 SETVECT(0, XSD2 | RSD3 | SIB_A2 | EOS); // Slot 0: Trap TSL
00877                 // execution, shift 0xFF
00878                 // into FB_BUFFER2.
00879 
00880                 // Initialize slot 1, which is constant.  Slot 1 causes a DWORD to
00881                 // be transferred from audio channel 2's output FIFO to the FIFO's
00882                 // output buffer so that it can be serialized and sent to the DAC
00883                 // during subsequent slots.  All remaining slots are dynamically
00884                 // populated as required by the target DAC device.
00885                 SETVECT(1, LF_A2);      // Slot 1: Fetch DWORD from Audio2's
00886                 // output FIFO.
00887 
00888                 // Start DAC's audio interface (TSL2) running.
00889                 WR7146(P_ACON1, ACON1_DACSTART);
00890 
00892 
00893                 // end init DAC interface
00894 
00895                 // Init Trim DACs to calibrated values.  Do it twice because the
00896                 // SAA7146 audio channel does not always reset properly and
00897                 // sometimes causes the first few TrimDAC writes to malfunction.
00898 
00899                 LoadTrimDACs(dev);
00900                 LoadTrimDACs(dev);      // Insurance.
00901 
00903                 // Manually init all gate array hardware in case this is a soft
00904                 // reset (we have no way of determining whether this is a warm or
00905                 // cold start).  This is necessary because the gate array will
00906                 // reset only in response to a PCI hard reset; there is no soft
00907                 // reset function.
00908 
00909                 // Init all DAC outputs to 0V and init all DAC setpoint and
00910                 // polarity images.
00911                 for (chan = 0; chan < S626_DAC_CHANNELS; chan++)
00912                         SetDAC(dev, chan, 0);
00913 
00914                 // Init image of WRMISC2 Battery Charger Enabled control bit.
00915                 // This image is used when the state of the charger control bit,
00916                 // which has no direct hardware readback mechanism, is queried.
00917                 devpriv->ChargeEnabled = 0;
00918 
00919                 // Init image of watchdog timer interval in WRMISC2.  This image
00920                 // maintains the value of the control bits of MISC2 are
00921                 // continuously reset to zero as long as the WD timer is disabled.
00922                 devpriv->WDInterval = 0;
00923 
00924                 // Init Counter Interrupt enab mask for RDMISC2.  This mask is
00925                 // applied against MISC2 when testing to determine which timer
00926                 // events are requesting interrupt service.
00927                 devpriv->CounterIntEnabs = 0;
00928 
00929                 // Init counters.
00930                 CountersInit(dev);
00931 
00932                 // Without modifying the state of the Battery Backup enab, disable
00933                 // the watchdog timer, set DIO channels 0-5 to operate in the
00934                 // standard DIO (vs. counter overflow) mode, disable the battery
00935                 // charger, and reset the watchdog interval selector to zero.
00936                 WriteMISC2(dev, (uint16_t) (DEBIread(dev,
00937                                         LP_RDMISC2) & MISC2_BATT_ENABLE));
00938 
00939                 // Initialize the digital I/O subsystem.
00940                 s626_dio_init(dev);
00941 
00942                 //enable interrupt test
00943                 // writel(IRQ_GPIO3 | IRQ_RPS1,devpriv->base_addr+P_IER);
00944         }
00945 
00946         DEBUG("s626_attach: comedi%d s626 attached %04x\n", dev->minor,
00947                 (uint32_t) devpriv->base_addr);
00948 
00949         return 1;
00950 }
00951 
00952 static lsampl_t s626_ai_reg_to_uint(int data)
00953 {
00954         lsampl_t tempdata;
00955 
00956         tempdata = (data >> 18);
00957         if (tempdata & 0x2000)
00958                 tempdata &= 0x1fff;
00959         else
00960                 tempdata += (1 << 13);
00961 
00962         return tempdata;
00963 }
00964 
00965 /* static lsampl_t s626_uint_to_reg(comedi_subdevice *s, int data){ */
00966 /*   return 0; */
00967 /* } */
00968 
00969 static irqreturn_t s626_irq_handler(int irq, void *d PT_REGS_ARG)
00970 {
00971         comedi_device *dev = d;
00972         comedi_subdevice *s;
00973         comedi_cmd *cmd;
00974         enc_private *k;
00975         unsigned long flags;
00976         int32_t *readaddr;
00977         uint32_t irqtype, irqstatus;
00978         int i = 0;
00979         sampl_t tempdata;
00980         uint8_t group;
00981         uint16_t irqbit;
00982 
00983         DEBUG("s626_irq_handler: interrupt request recieved!!!\n");
00984 
00985         if (dev->attached == 0)
00986                 return IRQ_NONE;
00987         // lock to avoid race with comedi_poll
00988         comedi_spin_lock_irqsave(&dev->spinlock, flags);
00989 
00990         //save interrupt enable register state
00991         irqstatus = readl(devpriv->base_addr + P_IER);
00992 
00993         //read interrupt type
00994         irqtype = readl(devpriv->base_addr + P_ISR);
00995 
00996         //disable master interrupt
00997         writel(0, devpriv->base_addr + P_IER);
00998 
00999         //clear interrupt
01000         writel(irqtype, devpriv->base_addr + P_ISR);
01001 
01002         //do somethings
01003         DEBUG("s626_irq_handler: interrupt type %d\n", irqtype);
01004 
01005         switch (irqtype) {
01006         case IRQ_RPS1:          // end_of_scan occurs
01007 
01008                 DEBUG("s626_irq_handler: RPS1 irq detected\n");
01009 
01010                 // manage ai subdevice
01011                 s = dev->subdevices;
01012                 cmd = &(s->async->cmd);
01013 
01014                 // Init ptr to DMA buffer that holds new ADC data.  We skip the
01015                 // first uint16_t in the buffer because it contains junk data from
01016                 // the final ADC of the previous poll list scan.
01017                 readaddr = (int32_t *) devpriv->ANABuf.LogicalBase + 1;
01018 
01019                 // get the data and hand it over to comedi
01020                 for (i = 0; i < (s->async->cmd.chanlist_len); i++) {
01021                         // Convert ADC data to 16-bit integer values and copy to application
01022                         // buffer.
01023                         tempdata = s626_ai_reg_to_uint((int)*readaddr);
01024                         readaddr++;
01025 
01026                         //put data into read buffer
01027                         // comedi_buf_put(s->async, tempdata);
01028                         if (cfc_write_to_buffer(s, tempdata) == 0)
01029                                 printk("s626_irq_handler: cfc_write_to_buffer error!\n");
01030 
01031                         DEBUG("s626_irq_handler: ai channel %d acquired: %d\n",
01032                                 i, tempdata);
01033                 }
01034 
01035                 //end of scan occurs
01036                 s->async->events |= COMEDI_CB_EOS;
01037 
01038                 if (!(devpriv->ai_continous))
01039                         devpriv->ai_sample_count--;
01040                 if (devpriv->ai_sample_count <= 0) {
01041                         devpriv->ai_cmd_running = 0;
01042 
01043                         // Stop RPS program.
01044                         MC_DISABLE(P_MC1, MC1_ERPS1);
01045 
01046                         //send end of acquisition
01047                         s->async->events |= COMEDI_CB_EOA;
01048 
01049                         //disable master interrupt
01050                         irqstatus = 0;
01051                 }
01052 
01053                 if (devpriv->ai_cmd_running && cmd->scan_begin_src == TRIG_EXT) {
01054                         DEBUG("s626_irq_handler: enable interrupt on dio channel %d\n", cmd->scan_begin_arg);
01055 
01056                         s626_dio_set_irq(dev, cmd->scan_begin_arg);
01057 
01058                         DEBUG("s626_irq_handler: External trigger is set!!!\n");
01059                 }
01060                 // tell comedi that data is there
01061                 DEBUG("s626_irq_handler: events %d\n", s->async->events);
01062                 comedi_event(dev, s);
01063                 break;
01064         case IRQ_GPIO3: //check dio and conter interrupt
01065 
01066                 DEBUG("s626_irq_handler: GPIO3 irq detected\n");
01067 
01068                 // manage ai subdevice
01069                 s = dev->subdevices;
01070                 cmd = &(s->async->cmd);
01071 
01072                 //s626_dio_clear_irq(dev);
01073 
01074                 for (group = 0; group < S626_DIO_BANKS; group++) {
01075                         irqbit = 0;
01076                         //read interrupt type
01077                         irqbit = DEBIread(dev,
01078                                 ((dio_private *) (dev->subdevices + 2 +
01079                                                 group)->private)->RDCapFlg);
01080 
01081                         //check if interrupt is generated from dio channels
01082                         if (irqbit) {
01083                                 s626_dio_reset_irq(dev, group, irqbit);
01084                                 DEBUG("s626_irq_handler: check interrupt on dio group %d %d\n", group, i);
01085                                 if (devpriv->ai_cmd_running) {
01086                                         //check if interrupt is an ai acquisition start trigger
01087                                         if ((irqbit >> (cmd->start_arg -
01088                                                                 (16 * group)))
01089                                                 == 1
01090                                                 && cmd->start_src == TRIG_EXT) {
01091                                                 DEBUG("s626_irq_handler: Edge capture interrupt recieved from channel %d\n", cmd->start_arg);
01092 
01093                                                 // Start executing the RPS program.
01094                                                 MC_ENABLE(P_MC1, MC1_ERPS1);
01095 
01096                                                 DEBUG("s626_irq_handler: aquisition start triggered!!!\n");
01097 
01098                                                 if (cmd->scan_begin_src ==
01099                                                         TRIG_EXT) {
01100                                                         DEBUG("s626_ai_cmd: enable interrupt on dio channel %d\n", cmd->scan_begin_arg);
01101 
01102                                                         s626_dio_set_irq(dev,
01103                                                                 cmd->
01104                                                                 scan_begin_arg);
01105 
01106                                                         DEBUG("s626_irq_handler: External scan trigger is set!!!\n");
01107                                                 }
01108                                         }
01109                                         if ((irqbit >> (cmd->scan_begin_arg -
01110                                                                 (16 * group)))
01111                                                 == 1
01112                                                 && cmd->scan_begin_src ==
01113                                                 TRIG_EXT) {
01114                                                 DEBUG("s626_irq_handler: Edge capture interrupt recieved from channel %d\n", cmd->scan_begin_arg);
01115 
01116                                                 // Trigger ADC scan loop start by setting RPS Signal 0.
01117                                                 MC_ENABLE(P_MC2, MC2_ADC_RPS);
01118 
01119                                                 DEBUG("s626_irq_handler: scan triggered!!! %d\n", devpriv->ai_sample_count);
01120                                                 if (cmd->convert_src ==
01121                                                         TRIG_EXT) {
01122 
01123                                                         DEBUG("s626_ai_cmd: enable interrupt on dio channel %d group %d\n", cmd->convert_arg - (16 * group), group);
01124 
01125                                                         devpriv->
01126                                                                 ai_convert_count
01127                                                                 =
01128                                                                 cmd->
01129                                                                 chanlist_len;
01130 
01131                                                         s626_dio_set_irq(dev,
01132                                                                 cmd->
01133                                                                 convert_arg);
01134 
01135                                                         DEBUG("s626_irq_handler: External convert trigger is set!!!\n");
01136                                                 }
01137 
01138                                                 if (cmd->convert_src ==
01139                                                         TRIG_TIMER) {
01140                                                         k = &encpriv[5];
01141                                                         devpriv->
01142                                                                 ai_convert_count
01143                                                                 =
01144                                                                 cmd->
01145                                                                 chanlist_len;
01146                                                         k->SetEnable(dev, k,
01147                                                                 CLKENAB_ALWAYS);
01148                                                 }
01149                                         }
01150                                         if ((irqbit >> (cmd->convert_arg -
01151                                                                 (16 * group)))
01152                                                 == 1
01153                                                 && cmd->convert_src ==
01154                                                 TRIG_EXT) {
01155                                                 DEBUG("s626_irq_handler: Edge capture interrupt recieved from channel %d\n", cmd->convert_arg);
01156 
01157                                                 // Trigger ADC scan loop start by setting RPS Signal 0.
01158                                                 MC_ENABLE(P_MC2, MC2_ADC_RPS);
01159 
01160                                                 DEBUG("s626_irq_handler: adc convert triggered!!!\n");
01161 
01162                                                 devpriv->ai_convert_count--;
01163 
01164                                                 if (devpriv->ai_convert_count >
01165                                                         0) {
01166 
01167                                                         DEBUG("s626_ai_cmd: enable interrupt on dio channel %d group %d\n", cmd->convert_arg - (16 * group), group);
01168 
01169                                                         s626_dio_set_irq(dev,
01170                                                                 cmd->
01171                                                                 convert_arg);
01172 
01173                                                         DEBUG("s626_irq_handler: External trigger is set!!!\n");
01174                                                 }
01175                                         }
01176                                 }
01177                                 break;
01178                         }
01179                 }
01180 
01181                 //read interrupt type
01182                 irqbit = DEBIread(dev, LP_RDMISC2);
01183 
01184                 //check interrupt on counters
01185                 DEBUG("s626_irq_handler: check counters interrupt %d\n",
01186                         irqbit);
01187 
01188                 if (irqbit & IRQ_COINT1A) {
01189                         DEBUG("s626_irq_handler: interrupt on counter 1A overflow\n");
01190                         k = &encpriv[0];
01191 
01192                         //clear interrupt capture flag
01193                         k->ResetCapFlags(dev, k);
01194                 }
01195                 if (irqbit & IRQ_COINT2A) {
01196                         DEBUG("s626_irq_handler: interrupt on counter 2A overflow\n");
01197                         k = &encpriv[1];
01198 
01199                         //clear interrupt capture flag
01200                         k->ResetCapFlags(dev, k);
01201                 }
01202                 if (irqbit & IRQ_COINT3A) {
01203                         DEBUG("s626_irq_handler: interrupt on counter 3A overflow\n");
01204                         k = &encpriv[2];
01205 
01206                         //clear interrupt capture flag
01207                         k->ResetCapFlags(dev, k);
01208                 }
01209                 if (irqbit & IRQ_COINT1B) {
01210                         DEBUG("s626_irq_handler: interrupt on counter 1B overflow\n");
01211                         k = &encpriv[3];
01212 
01213                         //clear interrupt capture flag
01214                         k->ResetCapFlags(dev, k);
01215                 }
01216                 if (irqbit & IRQ_COINT2B) {
01217                         DEBUG("s626_irq_handler: interrupt on counter 2B overflow\n");
01218                         k = &encpriv[4];
01219 
01220                         //clear interrupt capture flag
01221                         k->ResetCapFlags(dev, k);
01222 
01223                         if (devpriv->ai_convert_count > 0) {
01224                                 devpriv->ai_convert_count--;
01225                                 if (devpriv->ai_convert_count == 0)
01226                                         k->SetEnable(dev, k, CLKENAB_INDEX);
01227 
01228                                 if (cmd->convert_src == TRIG_TIMER) {
01229                                         DEBUG("s626_irq_handler: conver timer trigger!!! %d\n", devpriv->ai_convert_count);
01230 
01231                                         // Trigger ADC scan loop start by setting RPS Signal 0.
01232                                         MC_ENABLE(P_MC2, MC2_ADC_RPS);
01233                                 }
01234                         }
01235                 }
01236                 if (irqbit & IRQ_COINT3B) {
01237                         DEBUG("s626_irq_handler: interrupt on counter 3B overflow\n");
01238                         k = &encpriv[5];
01239 
01240                         //clear interrupt capture flag
01241                         k->ResetCapFlags(dev, k);
01242 
01243                         if (cmd->scan_begin_src == TRIG_TIMER) {
01244                                 DEBUG("s626_irq_handler: scan timer trigger!!!\n");
01245 
01246                                 // Trigger ADC scan loop start by setting RPS Signal 0.
01247                                 MC_ENABLE(P_MC2, MC2_ADC_RPS);
01248                         }
01249 
01250                         if (cmd->convert_src == TRIG_TIMER) {
01251                                 DEBUG("s626_irq_handler: convert timer trigger is set\n");
01252                                 k = &encpriv[4];
01253                                 devpriv->ai_convert_count = cmd->chanlist_len;
01254                                 k->SetEnable(dev, k, CLKENAB_ALWAYS);
01255                         }
01256                 }
01257         }
01258 
01259         //enable interrupt
01260         writel(irqstatus, devpriv->base_addr + P_IER);
01261 
01262         DEBUG("s626_irq_handler: exit interrupt service routine.\n");
01263 
01264         comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
01265         return IRQ_HANDLED;
01266 }
01267 
01268 static int s626_detach(comedi_device * dev)
01269 {
01270         if (devpriv) {
01271                 //stop ai_command
01272                 devpriv->ai_cmd_running = 0;
01273 
01274                 if (devpriv->base_addr) {
01275                         //interrupt mask
01276                         WR7146(P_IER, 0);       // Disable master interrupt.
01277                         WR7146(P_ISR, IRQ_GPIO3 | IRQ_RPS1);    // Clear board's IRQ status flag.
01278 
01279                         // Disable the watchdog timer and battery charger.
01280                         WriteMISC2(dev, 0);
01281 
01282                         // Close all interfaces on 7146 device.
01283                         WR7146(P_MC1, MC1_SHUTDOWN);
01284                         WR7146(P_ACON1, ACON1_BASE);
01285 
01286                         CloseDMAB(dev, &devpriv->RPSBuf, DMABUF_SIZE);
01287                         CloseDMAB(dev, &devpriv->ANABuf, DMABUF_SIZE);
01288                 }
01289 
01290                 if (dev->irq) {
01291                         comedi_free_irq(dev->irq, dev);
01292                 }
01293 
01294                 if (devpriv->base_addr) {
01295                         iounmap(devpriv->base_addr);
01296                 }
01297 
01298                 if (devpriv->pdev) {
01299                         if (devpriv->got_regions) {
01300                                 comedi_pci_disable(devpriv->pdev);
01301                         }
01302                         pci_dev_put(devpriv->pdev);
01303                 }
01304         }
01305 
01306         DEBUG("s626_detach: S626 detached!\n");
01307 
01308         return 0;
01309 }
01310 
01311 /*
01312  * this functions build the RPS program for hardware driven acquistion
01313  */
01314 void ResetADC(comedi_device * dev, uint8_t * ppl)
01315 {
01316         register uint32_t *pRPS;
01317         uint32_t JmpAdrs;
01318         uint16_t i;
01319         uint16_t n;
01320         uint32_t LocalPPL;
01321         comedi_cmd *cmd = &(dev->subdevices->async->cmd);
01322 
01323         // Stop RPS program in case it is currently running.
01324         MC_DISABLE(P_MC1, MC1_ERPS1);
01325 
01326         // Set starting logical address to write RPS commands.
01327         pRPS = (uint32_t *) devpriv->RPSBuf.LogicalBase;
01328 
01329         // Initialize RPS instruction pointer.
01330         WR7146(P_RPSADDR1, (uint32_t) devpriv->RPSBuf.PhysicalBase);
01331 
01332         // Construct RPS program in RPSBuf DMA buffer
01333 
01334         if (cmd != NULL && cmd->scan_begin_src != TRIG_FOLLOW) {
01335                 DEBUG("ResetADC: scan_begin pause inserted\n");
01336                 // Wait for Start trigger.
01337                 *pRPS++ = RPS_PAUSE | RPS_SIGADC;
01338                 *pRPS++ = RPS_CLRSIGNAL | RPS_SIGADC;
01339         }
01340         // SAA7146 BUG WORKAROUND Do a dummy DEBI Write.  This is necessary
01341         // because the first RPS DEBI Write following a non-RPS DEBI write
01342         // seems to always fail.  If we don't do this dummy write, the ADC
01343         // gain might not be set to the value required for the first slot in
01344         // the poll list; the ADC gain would instead remain unchanged from
01345         // the previously programmed value.
01346         *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); // Write DEBI Write command
01347         // and address to shadow RAM.
01348         *pRPS++ = DEBI_CMD_WRWORD | LP_GSEL;
01349         *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2);  // Write DEBI immediate data
01350         // to shadow RAM:
01351         *pRPS++ = GSEL_BIPOLAR5V;       // arbitrary immediate data
01352         // value.
01353         *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI;     // Reset "shadow RAM
01354         // uploaded" flag.
01355         *pRPS++ = RPS_UPLOAD | RPS_DEBI;        // Invoke shadow RAM upload.
01356         *pRPS++ = RPS_PAUSE | RPS_DEBI; // Wait for shadow upload to finish.
01357 
01358         // Digitize all slots in the poll list. This is implemented as a
01359         // for loop to limit the slot count to 16 in case the application
01360         // forgot to set the EOPL flag in the final slot.
01361         for (devpriv->AdcItems = 0; devpriv->AdcItems < 16; devpriv->AdcItems++) {
01362                 // Convert application's poll list item to private board class
01363                 // format.  Each app poll list item is an uint8_t with form
01364                 // (EOPL,x,x,RANGE,CHAN<3:0>), where RANGE code indicates 0 =
01365                 // +-10V, 1 = +-5V, and EOPL = End of Poll List marker.
01366                 LocalPPL =
01367                         (*ppl << 8) | (*ppl & 0x10 ? GSEL_BIPOLAR5V :
01368                         GSEL_BIPOLAR10V);
01369 
01370                 // Switch ADC analog gain.
01371                 *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); // Write DEBI command
01372                 // and address to
01373                 // shadow RAM.
01374                 *pRPS++ = DEBI_CMD_WRWORD | LP_GSEL;
01375                 *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2);  // Write DEBI
01376                 // immediate data to
01377                 // shadow RAM.
01378                 *pRPS++ = LocalPPL;
01379                 *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI;     // Reset "shadow RAM uploaded"
01380                 // flag.
01381                 *pRPS++ = RPS_UPLOAD | RPS_DEBI;        // Invoke shadow RAM upload.
01382                 *pRPS++ = RPS_PAUSE | RPS_DEBI; // Wait for shadow upload to
01383                 // finish.
01384 
01385                 // Select ADC analog input channel.
01386                 *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); // Write DEBI command
01387                 // and address to
01388                 // shadow RAM.
01389                 *pRPS++ = DEBI_CMD_WRWORD | LP_ISEL;
01390                 *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2);  // Write DEBI
01391                 // immediate data to
01392                 // shadow RAM.
01393                 *pRPS++ = LocalPPL;
01394                 *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI;     // Reset "shadow RAM uploaded"
01395                 // flag.
01396                 *pRPS++ = RPS_UPLOAD | RPS_DEBI;        // Invoke shadow RAM upload.
01397                 *pRPS++ = RPS_PAUSE | RPS_DEBI; // Wait for shadow upload to
01398                 // finish.
01399 
01400                 // Delay at least 10 microseconds for analog input settling.
01401                 // Instead of padding with NOPs, we use RPS_JUMP instructions
01402                 // here; this allows us to produce a longer delay than is
01403                 // possible with NOPs because each RPS_JUMP flushes the RPS'
01404                 // instruction prefetch pipeline.
01405                 JmpAdrs =
01406                         (uint32_t) devpriv->RPSBuf.PhysicalBase +
01407                         (uint32_t) ((unsigned long)pRPS -
01408                         (unsigned long)devpriv->RPSBuf.LogicalBase);
01409                 for (i = 0; i < (10 * RPSCLK_PER_US / 2); i++) {
01410                         JmpAdrs += 8;   // Repeat to implement time delay:
01411                         *pRPS++ = RPS_JUMP;     // Jump to next RPS instruction.
01412                         *pRPS++ = JmpAdrs;
01413                 }
01414 
01415                 if (cmd != NULL && cmd->convert_src != TRIG_NOW) {
01416                         DEBUG("ResetADC: convert pause inserted\n");
01417                         // Wait for Start trigger.
01418                         *pRPS++ = RPS_PAUSE | RPS_SIGADC;
01419                         *pRPS++ = RPS_CLRSIGNAL | RPS_SIGADC;
01420                 }
01421                 // Start ADC by pulsing GPIO1.
01422                 *pRPS++ = RPS_LDREG | (P_GPIO >> 2);    // Begin ADC Start pulse.
01423                 *pRPS++ = GPIO_BASE | GPIO1_LO;
01424                 *pRPS++ = RPS_NOP;
01425                 // VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE.
01426                 *pRPS++ = RPS_LDREG | (P_GPIO >> 2);    // End ADC Start pulse.
01427                 *pRPS++ = GPIO_BASE | GPIO1_HI;
01428 
01429                 // Wait for ADC to complete (GPIO2 is asserted high when ADC not
01430                 // busy) and for data from previous conversion to shift into FB
01431                 // BUFFER 1 register.
01432                 *pRPS++ = RPS_PAUSE | RPS_GPIO2;        // Wait for ADC done.
01433 
01434                 // Transfer ADC data from FB BUFFER 1 register to DMA buffer.
01435                 *pRPS++ = RPS_STREG | (BUGFIX_STREG(P_FB_BUFFER1) >> 2);
01436                 *pRPS++ =
01437                         (uint32_t) devpriv->ANABuf.PhysicalBase +
01438                         (devpriv->AdcItems << 2);
01439 
01440                 // If this slot's EndOfPollList flag is set, all channels have
01441                 // now been processed.
01442                 if (*ppl++ & EOPL) {
01443                         devpriv->AdcItems++;    // Adjust poll list item count.
01444                         break;  // Exit poll list processing loop.
01445                 }
01446         }
01447         DEBUG("ResetADC: ADC items %d \n", devpriv->AdcItems);
01448 
01449         // VERSION 2.01 CHANGE: DELAY CHANGED FROM 250NS to 2US.  Allow the
01450         // ADC to stabilize for 2 microseconds before starting the final
01451         // (dummy) conversion.  This delay is necessary to allow sufficient
01452         // time between last conversion finished and the start of the dummy
01453         // conversion.  Without this delay, the last conversion's data value
01454         // is sometimes set to the previous conversion's data value.
01455         for (n = 0; n < (2 * RPSCLK_PER_US); n++)
01456                 *pRPS++ = RPS_NOP;
01457 
01458         // Start a dummy conversion to cause the data from the last
01459         // conversion of interest to be shifted in.
01460         *pRPS++ = RPS_LDREG | (P_GPIO >> 2);    // Begin ADC Start pulse.
01461         *pRPS++ = GPIO_BASE | GPIO1_LO;
01462         *pRPS++ = RPS_NOP;
01463         // VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE.
01464         *pRPS++ = RPS_LDREG | (P_GPIO >> 2);    // End ADC Start pulse.
01465         *pRPS++ = GPIO_BASE | GPIO1_HI;
01466 
01467         // Wait for the data from the last conversion of interest to arrive
01468         // in FB BUFFER 1 register.
01469         *pRPS++ = RPS_PAUSE | RPS_GPIO2;        // Wait for ADC done.
01470 
01471         // Transfer final ADC data from FB BUFFER 1 register to DMA buffer.
01472         *pRPS++ = RPS_STREG | (BUGFIX_STREG(P_FB_BUFFER1) >> 2);        //
01473         *pRPS++ =
01474                 (uint32_t) devpriv->ANABuf.PhysicalBase +
01475                 (devpriv->AdcItems << 2);
01476 
01477         // Indicate ADC scan loop is finished.
01478         // *pRPS++= RPS_CLRSIGNAL | RPS_SIGADC ;  // Signal ReadADC() that scan is done.
01479 
01480         //invoke interrupt
01481         if (devpriv->ai_cmd_running == 1) {
01482                 DEBUG("ResetADC: insert irq in ADC RPS task\n");
01483                 *pRPS++ = RPS_IRQ;
01484         }
01485         // Restart RPS program at its beginning.
01486         *pRPS++ = RPS_JUMP;     // Branch to start of RPS program.
01487         *pRPS++ = (uint32_t) devpriv->RPSBuf.PhysicalBase;
01488 
01489         // End of RPS program build
01490         // ------------------------------------------------------------
01491 }
01492 
01493 /* TO COMPLETE, IF NECESSARY */
01494 static int s626_ai_insn_config(comedi_device * dev, comedi_subdevice * s,
01495         comedi_insn * insn, lsampl_t * data)
01496 {
01497 
01498         return -EINVAL;
01499 }
01500 
01501 /* static int s626_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data) */
01502 /* { */
01503 /*   register uint8_t   i; */
01504 /*   register int32_t   *readaddr; */
01505 
01506 /*   DEBUG("as626_ai_rinsn: ai_rinsn enter \n");  */
01507 
01508 /*   // Trigger ADC scan loop start by setting RPS Signal 0. */
01509 /*   MC_ENABLE( P_MC2, MC2_ADC_RPS ); */
01510 
01511 /*   // Wait until ADC scan loop is finished (RPS Signal 0 reset). */
01512 /*   while ( MC_TEST( P_MC2, MC2_ADC_RPS ) ); */
01513 
01514 /*   // Init ptr to DMA buffer that holds new ADC data.  We skip the */
01515 /*   // first uint16_t in the buffer because it contains junk data from */
01516 /*   // the final ADC of the previous poll list scan. */
01517 /*   readaddr = (uint32_t *)devpriv->ANABuf.LogicalBase + 1; */
01518 
01519 /*   // Convert ADC data to 16-bit integer values and copy to application */
01520 /*   // buffer.  */
01521 /*   for ( i = 0; i < devpriv->AdcItems; i++ ) { */
01522 /*     *data = s626_ai_reg_to_uint( *readaddr++ ); */
01523 /*     DEBUG("s626_ai_rinsn: data %d \n",*data); */
01524 /*     data++; */
01525 /*   } */
01526 
01527 /*   DEBUG("s626_ai_rinsn: ai_rinsn escape \n"); */
01528 /*   return i; */
01529 /* } */
01530 
01531 static int s626_ai_insn_read(comedi_device * dev, comedi_subdevice * s,
01532         comedi_insn * insn, lsampl_t * data)
01533 {
01534         uint16_t chan = CR_CHAN(insn->chanspec);
01535         uint16_t range = CR_RANGE(insn->chanspec);
01536         uint16_t AdcSpec = 0;
01537         uint32_t GpioImage;
01538         int n;
01539 
01540 /*   //interrupt call test  */
01541 /*   writel(IRQ_GPIO3,devpriv->base_addr+P_PSR); //Writing a logical 1 */
01542 /*                                           //into any of the RPS_PSR */
01543 /*                                           //bits causes the */
01544 /*                                           //corresponding interrupt */
01545 /*                                           //to be generated if */
01546 /*                                           //enabled */
01547 
01548         DEBUG("s626_ai_insn_read: entering\n");
01549 
01550         // Convert application's ADC specification into form
01551         // appropriate for register programming.
01552         if (range == 0)
01553                 AdcSpec = (chan << 8) | (GSEL_BIPOLAR5V);
01554         else
01555                 AdcSpec = (chan << 8) | (GSEL_BIPOLAR10V);
01556 
01557         // Switch ADC analog gain.
01558         DEBIwrite(dev, LP_GSEL, AdcSpec);       // Set gain.
01559 
01560         // Select ADC analog input channel.
01561         DEBIwrite(dev, LP_ISEL, AdcSpec);       // Select channel.
01562 
01563         for (n = 0; n < insn->n; n++) {
01564 
01565                 // Delay 10 microseconds for analog input settling.
01566                 comedi_udelay(10);
01567 
01568                 // Start ADC by pulsing GPIO1 low.
01569                 GpioImage = RR7146(P_GPIO);
01570                 // Assert ADC Start command
01571                 WR7146(P_GPIO, GpioImage & ~GPIO1_HI);
01572                 //   and stretch it out.
01573                 WR7146(P_GPIO, GpioImage & ~GPIO1_HI);
01574                 WR7146(P_GPIO, GpioImage & ~GPIO1_HI);
01575                 // Negate ADC Start command.
01576                 WR7146(P_GPIO, GpioImage | GPIO1_HI);
01577 
01578                 // Wait for ADC to complete (GPIO2 is asserted high when
01579                 // ADC not busy) and for data from previous conversion to
01580                 // shift into FB BUFFER 1 register.
01581 
01582                 // Wait for ADC done.
01583                 while (!(RR7146(P_PSR) & PSR_GPIO2)) ;
01584 
01585                 // Fetch ADC data.
01586                 if (n != 0)
01587                         data[n - 1] = s626_ai_reg_to_uint(RR7146(P_FB_BUFFER1));
01588 
01589                 // Allow the ADC to stabilize for 4 microseconds before
01590                 // starting the next (final) conversion.  This delay is
01591                 // necessary to allow sufficient time between last
01592                 // conversion finished and the start of the next
01593                 // conversion.  Without this delay, the last conversion's
01594                 // data value is sometimes set to the previous
01595                 // conversion's data value.
01596                 comedi_udelay(4);
01597         }
01598 
01599         // Start a dummy conversion to cause the data from the
01600         // previous conversion to be shifted in.
01601         GpioImage = RR7146(P_GPIO);
01602 
01603         //Assert ADC Start command
01604         WR7146(P_GPIO, GpioImage & ~GPIO1_HI);
01605         //   and stretch it out.
01606         WR7146(P_GPIO, GpioImage & ~GPIO1_HI);
01607         WR7146(P_GPIO, GpioImage & ~GPIO1_HI);
01608         // Negate ADC Start command.
01609         WR7146(P_GPIO, GpioImage | GPIO1_HI);
01610 
01611         // Wait for the data to arrive in FB BUFFER 1 register.
01612 
01613         // Wait for ADC done.
01614         while (!(RR7146(P_PSR) & PSR_GPIO2)) ;
01615 
01616         // Fetch ADC data from audio interface's input shift
01617         // register.
01618 
01619         // Fetch ADC data.
01620         if (n != 0)
01621                 data[n - 1] = s626_ai_reg_to_uint(RR7146(P_FB_BUFFER1));
01622 
01623         DEBUG("s626_ai_insn_read: samples %d, data %d\n", n, data[n - 1]);
01624 
01625         return n;
01626 }
01627 
01628 static int s626_ai_load_polllist(uint8_t * ppl, comedi_cmd * cmd)
01629 {
01630 
01631         int n;
01632 
01633         for (n = 0; n < cmd->chanlist_len; n++) {
01634                 if (CR_RANGE((cmd->chanlist)[n]) == 0)
01635                         ppl[n] = (CR_CHAN((cmd->chanlist)[n])) | (RANGE_5V);
01636                 else
01637                         ppl[n] = (CR_CHAN((cmd->chanlist)[n])) | (RANGE_10V);
01638         }
01639         ppl[n - 1] |= EOPL;
01640 
01641         return n;
01642 }
01643 
01644 static int s626_ai_inttrig(comedi_device * dev, comedi_subdevice * s,
01645         unsigned int trignum)
01646 {
01647         if (trignum != 0)
01648                 return -EINVAL;
01649 
01650         DEBUG("s626_ai_inttrig: trigger adc start...");
01651 
01652         // Start executing the RPS program.
01653         MC_ENABLE(P_MC1, MC1_ERPS1);
01654 
01655         s->async->inttrig = NULL;
01656 
01657         DEBUG(" done\n");
01658 
01659         return 1;
01660 }
01661 
01662 /*  TO COMPLETE  */
01663 static int s626_ai_cmd(comedi_device * dev, comedi_subdevice * s)
01664 {
01665 
01666         uint8_t ppl[16];
01667         comedi_cmd *cmd = &s->async->cmd;
01668         enc_private *k;
01669         int tick;
01670 
01671         DEBUG("s626_ai_cmd: entering command function\n");
01672 
01673         if (devpriv->ai_cmd_running) {
01674                 printk("s626_ai_cmd: Another ai_cmd is running %d\n",
01675                         dev->minor);
01676                 return -EBUSY;
01677         }
01678         //disable interrupt
01679         writel(0, devpriv->base_addr + P_IER);
01680 
01681         //clear interrupt request
01682         writel(IRQ_RPS1 | IRQ_GPIO3, devpriv->base_addr + P_ISR);
01683 
01684         //clear any pending interrupt
01685         s626_dio_clear_irq(dev);
01686         //  s626_enc_clear_irq(dev);
01687 
01688         //reset ai_cmd_running flag
01689         devpriv->ai_cmd_running = 0;
01690 
01691         // test if cmd is valid
01692         if (cmd == NULL) {
01693                 DEBUG("s626_ai_cmd: NULL command\n");
01694                 return -EINVAL;
01695         } else {
01696                 DEBUG("s626_ai_cmd: command recieved!!!\n");
01697         }
01698 
01699         if (dev->irq == 0) {
01700                 comedi_error(dev,
01701                         "s626_ai_cmd: cannot run command without an irq");
01702                 return -EIO;
01703         }
01704 
01705         s626_ai_load_polllist(ppl, cmd);
01706         devpriv->ai_cmd_running = 1;
01707         devpriv->ai_convert_count = 0;
01708 
01709         switch (cmd->scan_begin_src) {
01710         case TRIG_FOLLOW:
01711                 break;
01712         case TRIG_TIMER:
01713                 // set a conter to generate adc trigger at scan_begin_arg interval
01714                 k = &encpriv[5];
01715                 tick = s626_ns_to_timer((int *)&cmd->scan_begin_arg,
01716                         cmd->flags & TRIG_ROUND_MASK);
01717 
01718                 //load timer value and enable interrupt
01719                 s626_timer_load(dev, k, tick);
01720                 k->SetEnable(dev, k, CLKENAB_ALWAYS);
01721 
01722                 DEBUG("s626_ai_cmd: scan trigger timer is set with value %d\n",
01723                         tick);
01724 
01725                 break;
01726         case TRIG_EXT:
01727                 // set the digital line and interrupt for scan trigger
01728                 if (cmd->start_src != TRIG_EXT)
01729                         s626_dio_set_irq(dev, cmd->scan_begin_arg);
01730 
01731                 DEBUG("s626_ai_cmd: External scan trigger is set!!!\n");
01732 
01733                 break;
01734         }
01735 
01736         switch (cmd->convert_src) {
01737         case TRIG_NOW:
01738                 break;
01739         case TRIG_TIMER:
01740                 // set a conter to generate adc trigger at convert_arg interval
01741                 k = &encpriv[4];
01742                 tick = s626_ns_to_timer((int *)&cmd->convert_arg,
01743                         cmd->flags & TRIG_ROUND_MASK);
01744 
01745                 //load timer value and enable interrupt
01746                 s626_timer_load(dev, k, tick);
01747                 k->SetEnable(dev, k, CLKENAB_INDEX);
01748 
01749                 DEBUG("s626_ai_cmd: convert trigger timer is set with value %d\n", tick);
01750                 break;
01751         case TRIG_EXT:
01752                 // set the digital line and interrupt for convert trigger
01753                 if (cmd->scan_begin_src != TRIG_EXT
01754                         && cmd->start_src == TRIG_EXT)
01755                         s626_dio_set_irq(dev, cmd->convert_arg);
01756 
01757                 DEBUG("s626_ai_cmd: External convert trigger is set!!!\n");
01758 
01759                 break;
01760         }
01761 
01762         switch (cmd->stop_src) {
01763         case TRIG_COUNT:
01764                 // data arrives as one packet
01765                 devpriv->ai_sample_count = cmd->stop_arg;
01766                 devpriv->ai_continous = 0;
01767                 break;
01768         case TRIG_NONE:
01769                 // continous aquisition
01770                 devpriv->ai_continous = 1;
01771                 devpriv->ai_sample_count = 0;
01772                 break;
01773         }
01774 
01775         ResetADC(dev, ppl);
01776 
01777         switch (cmd->start_src) {
01778         case TRIG_NOW:
01779                 // Trigger ADC scan loop start by setting RPS Signal 0.
01780                 // MC_ENABLE( P_MC2, MC2_ADC_RPS );
01781 
01782                 // Start executing the RPS program.
01783                 MC_ENABLE(P_MC1, MC1_ERPS1);
01784 
01785                 DEBUG("s626_ai_cmd: ADC triggered\n");
01786                 s->async->inttrig = NULL;
01787                 break;
01788         case TRIG_EXT:
01789                 //configure DIO channel for acquisition trigger
01790                 s626_dio_set_irq(dev, cmd->start_arg);
01791 
01792                 DEBUG("s626_ai_cmd: External start trigger is set!!!\n");
01793 
01794                 s->async->inttrig = NULL;
01795                 break;
01796         case TRIG_INT:
01797                 s->async->inttrig = s626_ai_inttrig;
01798                 break;
01799         }
01800 
01801         //enable interrupt
01802         writel(IRQ_GPIO3 | IRQ_RPS1, devpriv->base_addr + P_IER);
01803 
01804         DEBUG("s626_ai_cmd: command function terminated\n");
01805 
01806         return 0;
01807 }
01808 
01809 static int s626_ai_cmdtest(comedi_device * dev, comedi_subdevice * s,
01810         comedi_cmd * cmd)
01811 {
01812         int err = 0;
01813         int tmp;
01814 
01815         /* cmdtest tests a particular command to see if it is valid.  Using
01816          * the cmdtest ioctl, a user can create a valid cmd and then have it
01817          * executes by the cmd ioctl.
01818          *
01819          * cmdtest returns 1,2,3,4 or 0, depending on which tests the
01820          * command passes. */
01821 
01822         /* step 1: make sure trigger sources are trivially valid */
01823 
01824         tmp = cmd->start_src;
01825         cmd->start_src &= TRIG_NOW | TRIG_INT | TRIG_EXT;
01826         if (!cmd->start_src || tmp != cmd->start_src)
01827                 err++;
01828 
01829         tmp = cmd->scan_begin_src;
01830         cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW;
01831         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
01832                 err++;
01833 
01834         tmp = cmd->convert_src;
01835         cmd->convert_src &= TRIG_TIMER | TRIG_EXT | TRIG_NOW;
01836         if (!cmd->convert_src || tmp != cmd->convert_src)
01837                 err++;
01838 
01839         tmp = cmd->scan_end_src;
01840         cmd->scan_end_src &= TRIG_COUNT;
01841         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
01842                 err++;
01843 
01844         tmp = cmd->stop_src;
01845         cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
01846         if (!cmd->stop_src || tmp != cmd->stop_src)
01847                 err++;
01848 
01849         if (err)
01850                 return 1;
01851 
01852         /* step 2: make sure trigger sources are unique and mutually
01853            compatible */
01854 
01855         /* note that mutual compatiblity is not an issue here */
01856         if (cmd->scan_begin_src != TRIG_TIMER &&
01857                 cmd->scan_begin_src != TRIG_EXT
01858                 && cmd->scan_begin_src != TRIG_FOLLOW)
01859                 err++;
01860         if (cmd->convert_src != TRIG_TIMER &&
01861                 cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW)
01862                 err++;
01863         if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
01864                 err++;
01865 
01866         if (err)
01867                 return 2;
01868 
01869         /* step 3: make sure arguments are trivially compatible */
01870 
01871         if (cmd->start_src != TRIG_EXT && cmd->start_arg != 0) {
01872                 cmd->start_arg = 0;
01873                 err++;
01874         }
01875 
01876         if (cmd->start_src == TRIG_EXT && cmd->start_arg < 0) {
01877                 cmd->start_arg = 0;
01878                 err++;
01879         }
01880 
01881         if (cmd->start_src == TRIG_EXT && cmd->start_arg > 39) {
01882                 cmd->start_arg = 39;
01883                 err++;
01884         }
01885 
01886         if (cmd->scan_begin_src == TRIG_EXT && cmd->scan_begin_arg < 0) {
01887                 cmd->scan_begin_arg = 0;
01888                 err++;
01889         }
01890 
01891         if (cmd->scan_begin_src == TRIG_EXT && cmd->scan_begin_arg > 39) {
01892                 cmd->scan_begin_arg = 39;
01893                 err++;
01894         }
01895 
01896         if (cmd->convert_src == TRIG_EXT && cmd->convert_arg < 0) {
01897                 cmd->convert_arg = 0;
01898                 err++;
01899         }
01900 
01901         if (cmd->convert_src == TRIG_EXT && cmd->convert_arg > 39) {
01902                 cmd->convert_arg = 39;
01903                 err++;
01904         }
01905 #define MAX_SPEED       200000  /* in nanoseconds */
01906 #define MIN_SPEED       2000000000      /* in nanoseconds */
01907 
01908         if (cmd->scan_begin_src == TRIG_TIMER) {
01909                 if (cmd->scan_begin_arg < MAX_SPEED) {
01910                         cmd->scan_begin_arg = MAX_SPEED;
01911                         err++;
01912                 }
01913                 if (cmd->scan_begin_arg > MIN_SPEED) {
01914                         cmd->scan_begin_arg = MIN_SPEED;
01915                         err++;
01916                 }
01917         } else {
01918                 /* external trigger */
01919                 /* should be level/edge, hi/lo specification here */
01920                 /* should specify multiple external triggers */
01921 /*     if(cmd->scan_begin_arg>9){ */
01922 /*       cmd->scan_begin_arg=9; */
01923 /*       err++; */
01924 /*     } */
01925         }
01926         if (cmd->convert_src == TRIG_TIMER) {
01927                 if (cmd->convert_arg < MAX_SPEED) {
01928                         cmd->convert_arg = MAX_SPEED;
01929                         err++;
01930                 }
01931                 if (cmd->convert_arg > MIN_SPEED) {
01932                         cmd->convert_arg = MIN_SPEED;
01933                         err++;
01934                 }
01935         } else {
01936                 /* external trigger */
01937                 /* see above */
01938 /*     if(cmd->convert_arg>9){ */
01939 /*       cmd->convert_arg=9; */
01940 /*       err++; */
01941 /*     } */
01942         }
01943 
01944         if (cmd->scan_end_arg != cmd->chanlist_len) {
01945                 cmd->scan_end_arg = cmd->chanlist_len;
01946                 err++;
01947         }
01948         if (cmd->stop_src == TRIG_COUNT) {
01949                 if (cmd->stop_arg > 0x00ffffff) {
01950                         cmd->stop_arg = 0x00ffffff;
01951                         err++;
01952                 }
01953         } else {
01954                 /* TRIG_NONE */
01955                 if (cmd->stop_arg != 0) {
01956                         cmd->stop_arg = 0;
01957                         err++;
01958                 }
01959         }
01960 
01961         if (err)
01962                 return 3;
01963 
01964         /* step 4: fix up any arguments */
01965 
01966         if (cmd->scan_begin_src == TRIG_TIMER) {
01967                 tmp = cmd->scan_begin_arg;
01968                 s626_ns_to_timer((int *)&cmd->scan_begin_arg,
01969                         cmd->flags & TRIG_ROUND_MASK);
01970                 if (tmp != cmd->scan_begin_arg)
01971                         err++;
01972         }
01973         if (cmd->convert_src == TRIG_TIMER) {
01974                 tmp = cmd->convert_arg;
01975                 s626_ns_to_timer((int *)&cmd->convert_arg,
01976                         cmd->flags & TRIG_ROUND_MASK);
01977                 if (tmp != cmd->convert_arg)
01978                         err++;
01979                 if (cmd->scan_begin_src == TRIG_TIMER &&
01980                         cmd->scan_begin_arg <
01981                         cmd->convert_arg * cmd->scan_end_arg) {
01982                         cmd->scan_begin_arg =
01983                                 cmd->convert_arg * cmd->scan_end_arg;
01984                         err++;
01985                 }
01986         }
01987 
01988         if (err)
01989                 return 4;
01990 
01991         return 0;
01992 }
01993 
01994 static int s626_ai_cancel(comedi_device * dev, comedi_subdevice * s)
01995 {
01996         // Stop RPS program in case it is currently running.
01997         MC_DISABLE(P_MC1, MC1_ERPS1);
01998 
01999         //disable master interrupt
02000         writel(0, devpriv->base_addr + P_IER);
02001 
02002         devpriv->ai_cmd_running = 0;
02003 
02004         return 0;
02005 }
02006 
02007 /* This function doesn't require a particular form, this is just what
02008  * happens to be used in some of the drivers.  It should convert ns
02009  * nanoseconds to a counter value suitable for programming the device.
02010  * Also, it should adjust ns so that it cooresponds to the actual time
02011  * that the device will use. */
02012 static int s626_ns_to_timer(int *nanosec, int round_mode)
02013 {
02014         int divider, base;
02015 
02016         base = 500;             //2MHz internal clock
02017 
02018         switch (round_mode) {
02019         case TRIG_ROUND_NEAREST:
02020         default:
02021                 divider = (*nanosec + base / 2) / base;
02022                 break;
02023         case TRIG_ROUND_DOWN:
02024                 divider = (*nanosec) / base;
02025                 break;
02026         case TRIG_ROUND_UP:
02027                 divider = (*nanosec + base - 1) / base;
02028                 break;
02029         }
02030 
02031         *nanosec = base * divider;
02032         return divider - 1;
02033 }
02034 
02035 static int s626_ao_winsn(comedi_device * dev, comedi_subdevice * s,
02036         comedi_insn * insn, lsampl_t * data)
02037 {
02038 
02039         int i;
02040         uint16_t chan = CR_CHAN(insn->chanspec);
02041         int16_t dacdata;
02042 
02043         for (i = 0; i < insn->n; i++) {
02044                 dacdata = (int16_t) data[i];
02045                 devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[i];
02046                 dacdata -= (0x1fff);
02047 
02048                 SetDAC(dev, chan, dacdata);
02049         }
02050 
02051         return i;
02052 }
02053 
02054 static int s626_ao_rinsn(comedi_device * dev, comedi_subdevice * s,
02055         comedi_insn * insn, lsampl_t * data)
02056 {
02057         int i;
02058 
02059         for (i = 0; i < insn->n; i++) {
02060                 data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
02061         }
02062 
02063         return i;
02064 }
02065 
02069 // All DIO functions address a group of DIO channels by means of
02070 // "group" argument.  group may be 0, 1 or 2, which correspond to DIO
02071 // ports A, B and C, respectively.
02073 
02074 static void s626_dio_init(comedi_device * dev)
02075 {
02076         uint16_t group;
02077         comedi_subdevice *s;
02078 
02079         // Prepare to treat writes to WRCapSel as capture disables.
02080         DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP);
02081 
02082         // For each group of sixteen channels ...
02083         for (group = 0; group < S626_DIO_BANKS; group++) {
02084                 s = dev->subdevices + 2 + group;
02085                 DEBIwrite(dev, diopriv->WRIntSel, 0);   // Disable all interrupts.
02086                 DEBIwrite(dev, diopriv->WRCapSel, 0xFFFF);      // Disable all event
02087                 // captures.
02088                 DEBIwrite(dev, diopriv->WREdgSel, 0);   // Init all DIOs to
02089                 // default edge
02090                 // polarity.
02091                 DEBIwrite(dev, diopriv->WRDOut, 0);     // Program all outputs
02092                 // to inactive state.
02093         }
02094         DEBUG("s626_dio_init: DIO initialized \n");
02095 }
02096 
02097 /* DIO devices are slightly special.  Although it is possible to
02098  * implement the insn_read/insn_write interface, it is much more
02099  * useful to applications if you implement the insn_bits interface.
02100  * This allows packed reading/writing of the DIO channels.  The comedi
02101  * core can convert between insn_bits and insn_read/write */
02102 
02103 static int s626_dio_insn_bits(comedi_device * dev, comedi_subdevice * s,
02104         comedi_insn * insn, lsampl_t * data)
02105 {
02106 
02107         /* Length of data must be 2 (mask and new data, see below) */
02108         if (insn->n == 0) {
02109                 return 0;
02110         }
02111         if (insn->n != 2) {
02112                 printk("comedi%d: s626: s626_dio_insn_bits(): Invalid instruction length\n", dev->minor);
02113                 return -EINVAL;
02114         }
02115 
02116         /*
02117          * The insn data consists of a mask in data[0] and the new data in
02118          * data[1]. The mask defines which bits we are concerning about.
02119          * The new data must be anded with the mask.  Each channel
02120          * corresponds to a bit.
02121          */
02122         if (data[0]) {
02123                 /* Check if requested ports are configured for output */
02124                 if ((s->io_bits & data[0]) != data[0])
02125                         return -EIO;
02126 
02127                 s->state &= ~data[0];
02128                 s->state |= data[0] & data[1];
02129 
02130                 /* Write out the new digital output lines */
02131 
02132                 DEBIwrite(dev, diopriv->WRDOut, s->state);
02133         }
02134         data[1] = DEBIread(dev, diopriv->RDDIn);
02135 
02136         return 2;
02137 }
02138 
02139 static int s626_dio_insn_config(comedi_device * dev, comedi_subdevice * s,
02140         comedi_insn * insn, lsampl_t * data)
02141 {
02142 
02143         switch (data[0]) {
02144         case INSN_CONFIG_DIO_QUERY:
02145                 data[1] =
02146                         (s->io_bits & (1 << CR_CHAN(insn->
02147                                         chanspec))) ? COMEDI_OUTPUT :
02148                         COMEDI_INPUT;
02149                 return insn->n;
02150                 break;
02151         case COMEDI_INPUT:
02152                 s->io_bits &= ~(1 << CR_CHAN(insn->chanspec));
02153                 break;
02154         case COMEDI_OUTPUT:
02155                 s->io_bits |= 1 << CR_CHAN(insn->chanspec);
02156                 break;
02157         default:
02158                 return -EINVAL;
02159                 break;
02160         }
02161         DEBIwrite(dev, diopriv->WRDOut, s->io_bits);
02162 
02163         return 1;
02164 }
02165 
02166 static int s626_dio_set_irq(comedi_device * dev, unsigned int chan)
02167 {
02168         unsigned int group;
02169         unsigned int bitmask;
02170         unsigned int status;
02171 
02172         //select dio bank
02173         group = chan / 16;
02174         bitmask = 1 << (chan - (16 * group));
02175         DEBUG("s626_dio_set_irq: enable interrupt on dio channel %d group %d\n",
02176                 chan - (16 * group), group);
02177 
02178         //set channel to capture positive edge
02179         status = DEBIread(dev,
02180                 ((dio_private *) (dev->subdevices + 2 +
02181                                 group)->private)->RDEdgSel);
02182         DEBIwrite(dev,
02183                 ((dio_private *) (dev->subdevices + 2 +
02184                                 group)->private)->WREdgSel, bitmask | status);
02185 
02186         //enable interrupt on selected channel
02187         status = DEBIread(dev,
02188                 ((dio_private *) (dev->subdevices + 2 +
02189                                 group)->private)->RDIntSel);
02190         DEBIwrite(dev,
02191                 ((dio_private *) (dev->subdevices + 2 +
02192                                 group)->private)->WRIntSel, bitmask | status);
02193 
02194         //enable edge capture write command
02195         DEBIwrite(dev, LP_MISC1, MISC1_EDCAP);
02196 
02197         //enable edge capture on selected channel
02198         status = DEBIread(dev,
02199                 ((dio_private *) (dev->subdevices + 2 +
02200                                 group)->private)->RDCapSel);
02201         DEBIwrite(dev,
02202                 ((dio_private *) (dev->subdevices + 2 +
02203                                 group)->private)->WRCapSel, bitmask | status);
02204 
02205         return 0;
02206 }
02207 
02208 static int s626_dio_reset_irq(comedi_device * dev, unsigned int group,
02209         unsigned int mask)
02210 {
02211         DEBUG("s626_dio_reset_irq: disable  interrupt on dio channel %d group %d\n", mask, group);
02212 
02213         //disable edge capture write command
02214         DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP);
02215 
02216         //enable edge capture on selected channel
02217         DEBIwrite(dev,
02218                 ((dio_private *) (dev->subdevices + 2 +
02219                                 group)->private)->WRCapSel, mask);
02220 
02221         return 0;
02222 }
02223 
02224 static int s626_dio_clear_irq(comedi_device * dev)
02225 {
02226         unsigned int group;
02227 
02228         //disable edge capture write command
02229         DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP);
02230 
02231         for (group = 0; group < S626_DIO_BANKS; group++) {
02232                 //clear pending events and interrupt
02233                 DEBIwrite(dev,
02234                         ((dio_private *) (dev->subdevices + 2 +
02235                                         group)->private)->WRCapSel, 0xffff);
02236         }
02237 
02238         return 0;
02239 }
02240 
02241 /* Now this function initializes the value of the counter (data[0])
02242    and set the subdevice. To complete with trigger and interrupt
02243    configuration */
02244 static int s626_enc_insn_config(comedi_device * dev, comedi_subdevice * s,
02245         comedi_insn * insn, lsampl_t * data)
02246 {
02247         uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | // Preload upon
02248                 // index.
02249                 (INDXSRC_SOFT << BF_INDXSRC) |  // Disable hardware index.
02250                 (CLKSRC_COUNTER << BF_CLKSRC) | // Operating mode is Counter.
02251                 (CLKPOL_POS << BF_CLKPOL) |     // Active high clock.
02252                 //( CNTDIR_UP << BF_CLKPOL ) |      // Count direction is Down.
02253                 (CLKMULT_1X << BF_CLKMULT) |    // Clock multiplier is 1x.
02254                 (CLKENAB_INDEX << BF_CLKENAB);
02255         /*   uint16_t DisableIntSrc=TRUE; */
02256         // uint32_t Preloadvalue;              //Counter initial value
02257         uint16_t valueSrclatch = LATCHSRC_AB_READ;
02258         uint16_t enab = CLKENAB_ALWAYS;
02259         enc_private *k = &encpriv[CR_CHAN(insn->chanspec)];
02260 
02261         DEBUG("s626_enc_insn_config: encoder config\n");
02262 
02263         //  (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]);
02264 
02265         k->SetMode(dev, k, Setup, TRUE);
02266         Preload(dev, k, *(insn->data));
02267         k->PulseIndex(dev, k);
02268         SetLatchSource(dev, k, valueSrclatch);
02269         k->SetEnable(dev, k, (uint16_t) (enab != 0));
02270 
02271         return insn->n;
02272 }
02273 
02274 static int s626_enc_insn_read(comedi_device * dev, comedi_subdevice * s,
02275         comedi_insn * insn, lsampl_t * data)
02276 {
02277 
02278         int n;
02279         enc_private *k = &encpriv[CR_CHAN(insn->chanspec)];
02280 
02281         DEBUG("s626_enc_insn_read: encoder read channel %d \n",
02282                 CR_CHAN(insn->chanspec));
02283 
02284         for (n = 0; n < insn->n; n++)
02285                 data[n] = ReadLatch(dev, k);
02286 
02287         DEBUG("s626_enc_insn_read: encoder sample %d\n", data[n]);
02288 
02289         return n;
02290 }
02291 
02292 static int s626_enc_insn_write(comedi_device * dev, comedi_subdevice * s,
02293         comedi_insn * insn, lsampl_t * data)
02294 {
02295 
02296         enc_private *k = &encpriv[CR_CHAN(insn->chanspec)];
02297 
02298         DEBUG("s626_enc_insn_write: encoder write channel %d \n",
02299                 CR_CHAN(insn->chanspec));
02300 
02301         // Set the preload register
02302         Preload(dev, k, data[0]);
02303 
02304         // Software index pulse forces the preload register to load
02305         // into the counter
02306         k->SetLoadTrig(dev, k, 0);
02307         k->PulseIndex(dev, k);
02308         k->SetLoadTrig(dev, k, 2);
02309 
02310         DEBUG("s626_enc_insn_write: End encoder write\n");
02311 
02312         return 1;
02313 }
02314 
02315 static void s626_timer_load(comedi_device * dev, enc_private * k, int tick)
02316 {
02317         uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | // Preload upon
02318                 // index.
02319                 (INDXSRC_SOFT << BF_INDXSRC) |  // Disable hardware index.
02320                 (CLKSRC_TIMER << BF_CLKSRC) |   // Operating mode is Timer.
02321                 (CLKPOL_POS << BF_CLKPOL) |     // Active high clock.
02322                 (CNTDIR_DOWN << BF_CLKPOL) |    // Count direction is Down.
02323                 (CLKMULT_1X << BF_CLKMULT) |    // Clock multiplier is 1x.
02324                 (CLKENAB_INDEX << BF_CLKENAB);
02325         uint16_t valueSrclatch = LATCHSRC_A_INDXA;
02326         //  uint16_t enab=CLKENAB_ALWAYS;
02327 
02328         k->SetMode(dev, k, Setup, FALSE);
02329 
02330         // Set the preload register
02331         Preload(dev, k, tick);
02332 
02333         // Software index pulse forces the preload register to load
02334         // into the counter
02335         k->SetLoadTrig(dev, k, 0);
02336         k->PulseIndex(dev, k);
02337 
02338         //set reload on counter overflow
02339         k->SetLoadTrig(dev, k, 1);
02340 
02341         //set interrupt on overflow
02342         k->SetIntSrc(dev, k, INTSRC_OVER);
02343 
02344         SetLatchSource(dev, k, valueSrclatch);
02345         //  k->SetEnable(dev,k,(uint16_t)(enab != 0));
02346 }
02347 
02351 
02352 // Slot 0 base settings.
02353 #define VECT0   ( XSD2 | RSD3 | SIB_A2 )        // Slot 0 always shifts in
02354                                          // 0xFF and store it to
02355                                          // FB_BUFFER2.
02356 
02357 // TrimDac LogicalChan-to-PhysicalChan mapping table.
02358 static uint8_t trimchan[] = { 10, 9, 8, 3, 2, 7, 6, 1, 0, 5, 4 };
02359 
02360 // TrimDac LogicalChan-to-EepromAdrs mapping table.
02361 static uint8_t trimadrs[] =
02362         { 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 };
02363 
02364 static void LoadTrimDACs(comedi_device * dev)
02365 {
02366         register uint8_t i;
02367 
02368         // Copy TrimDac setpoint values from EEPROM to TrimDacs.
02369         for (i = 0; i < (sizeof(trimchan) / sizeof(trimchan[0])); i++)
02370                 WriteTrimDAC(dev, i, I2Cread(dev, trimadrs[i]));
02371 }
02372 
02373 static void WriteTrimDAC(comedi_device * dev, uint8_t LogicalChan,
02374         uint8_t DacData)
02375 {
02376         uint32_t chan;
02377 
02378         // Save the new setpoint in case the application needs to read it back later.
02379         devpriv->TrimSetpoint[LogicalChan] = (uint8_t) DacData;
02380 
02381         // Map logical channel number to physical channel number.
02382         chan = (uint32_t) trimchan[LogicalChan];
02383 
02384         // Set up TSL2 records for TrimDac write operation.  All slots shift
02385         // 0xFF in from pulled-up SD3 so that the end of the slot sequence
02386         // can be detected.
02387         SETVECT(2, XSD2 | XFIFO_1 | WS3);       // Slot 2: Send high uint8_t
02388         // to target TrimDac.
02389         SETVECT(3, XSD2 | XFIFO_0 | WS3);       // Slot 3: Send low uint8_t to
02390         // target TrimDac.
02391         SETVECT(4, XSD2 | XFIFO_3 | WS1);       // Slot 4: Send NOP high
02392         // uint8_t to DAC0 to keep
02393         // clock running.
02394         SETVECT(5, XSD2 | XFIFO_2 | WS1 | EOS); // Slot 5: Send NOP low
02395         // uint8_t to DAC0.
02396 
02397         // Construct and transmit target DAC's serial packet: ( 0000 AAAA
02398         // ),( DDDD DDDD ),( 0x00 ),( 0x00 ) where A<3:0> is the DAC
02399         // channel's address, and D<7:0> is the DAC setpoint.  Append a WORD
02400         // value (that writes a channel 0 NOP command to a non-existent main
02401         // DAC channel) that serves to keep the clock running after the
02402         // packet has been sent to the target DAC.
02403 
02404         SendDAC(dev, ((uint32_t) chan << 8)     // Address the DAC channel
02405                 // within the trimdac device.
02406                 | (uint32_t) DacData);  // Include DAC setpoint data.
02407 }
02408 
02412 
02414 // Read uint8_t from EEPROM.
02415 
02416 static uint8_t I2Cread(comedi_device * dev, uint8_t addr)
02417 {
02418         uint8_t rtnval;
02419 
02420         // Send EEPROM target address.
02421         if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CW)       // Byte2 = I2C
02422                         // command:
02423                         // write to
02424                         // I2C EEPROM
02425                         // device.
02426                         | I2C_B1(I2C_ATTRSTOP, addr)    // Byte1 = EEPROM
02427                         // internal target
02428                         // address.
02429                         | I2C_B0(I2C_ATTRNOP, 0)))      // Byte0 = Not
02430                 // sent.
02431         {
02432                 // Abort function and declare error if handshake failed.
02433                 DEBUG("I2Cread: error handshake I2Cread  a\n");
02434                 return 0;
02435         }
02436         // Execute EEPROM read.
02437         if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CR)       // Byte2 = I2C
02438                         // command: read
02439                         // from I2C EEPROM
02440                         // device.
02441                         | I2C_B1(I2C_ATTRSTOP, 0)       // Byte1 receives
02442                         // uint8_t from
02443                         // EEPROM.
02444                         | I2C_B0(I2C_ATTRNOP, 0)))      // Byte0 = Not
02445                 // sent.
02446         {
02447                 // Abort function and declare error if handshake failed.
02448                 DEBUG("I2Cread: error handshake I2Cread b\n");
02449                 return 0;
02450         }
02451         // Return copy of EEPROM value.
02452         rtnval = (uint8_t) (RR7146(P_I2CCTRL) >> 16);
02453         return rtnval;
02454 }
02455 
02456 static uint32_t I2Chandshake(comedi_device * dev, uint32_t val)
02457 {
02458         // Write I2C command to I2C Transfer Control shadow register.
02459         WR7146(P_I2CCTRL, val);
02460 
02461         // Upload I2C shadow registers into working registers and wait for
02462         // upload confirmation.
02463 
02464         MC_ENABLE(P_MC2, MC2_UPLD_IIC);
02465         while (!MC_TEST(P_MC2, MC2_UPLD_IIC)) ;
02466 
02467         // Wait until I2C bus transfer is finished or an error occurs.
02468         while ((RR7146(P_I2CCTRL) & (I2C_BUSY | I2C_ERR)) == I2C_BUSY) ;
02469 
02470         // Return non-zero if I2C error occured.
02471         return RR7146(P_I2CCTRL) & I2C_ERR;
02472 
02473 }
02474 
02475 // Private helper function: Write setpoint to an application DAC channel.
02476 
02477 static void SetDAC(comedi_device * dev, uint16_t chan, short dacdata)
02478 {
02479         register uint16_t signmask;
02480         register uint32_t WSImage;
02481 
02482         // Adjust DAC data polarity and set up Polarity Control Register
02483         // image.
02484         signmask = 1 << chan;
02485         if (dacdata < 0) {
02486                 dacdata = -dacdata;
02487                 devpriv->Dacpol |= signmask;
02488         } else
02489                 devpriv->Dacpol &= ~signmask;
02490 
02491         // Limit DAC setpoint value to valid range.
02492         if ((uint16_t) dacdata > 0x1FFF)
02493                 dacdata = 0x1FFF;
02494 
02495         // Set up TSL2 records (aka "vectors") for DAC update.  Vectors V2
02496         // and V3 transmit the setpoint to the target DAC.  V4 and V5 send
02497         // data to a non-existent TrimDac channel just to keep the clock
02498         // running after sending data to the target DAC.  This is necessary
02499         // to eliminate the clock glitch that would otherwise occur at the
02500         // end of the target DAC's serial data stream.  When the sequence
02501         // restarts at V0 (after executing V5), the gate array automatically
02502         // disables gating for the DAC clock and all DAC chip selects.
02503         WSImage = (chan & 2) ? WS1 : WS2;       // Choose DAC chip select to
02504         // be asserted.
02505         SETVECT(2, XSD2 | XFIFO_1 | WSImage);   // Slot 2: Transmit high
02506         // data byte to target DAC.
02507         SETVECT(3, XSD2 | XFIFO_0 | WSImage);   // Slot 3: Transmit low data
02508         // byte to target DAC.
02509         SETVECT(4, XSD2 | XFIFO_3 | WS3);       // Slot 4: Transmit to
02510         // non-existent TrimDac
02511         // channel to keep clock
02512         SETVECT(5, XSD2 | XFIFO_2 | WS3 | EOS); // Slot 5: running after
02513         // writing target DAC's
02514         // low data byte.
02515 
02516         // Construct and transmit target DAC's serial packet: ( A10D DDDD
02517         // ),( DDDD DDDD ),( 0x0F ),( 0x00 ) where A is chan<0>, and D<12:0>
02518         // is the DAC setpoint.  Append a WORD value (that writes to a
02519         // non-existent TrimDac channel) that serves to keep the clock
02520         // running after the packet has been sent to the target DAC.
02521         SendDAC(dev, 0x0F000000 //Continue clock after target DAC
02522                 //data (write to non-existent
02523                 //trimdac).
02524                 | 0x00004000    // Address the two main dual-DAC
02525                 // devices (TSL's chip select enables
02526                 // target device).
02527                 | ((uint32_t) (chan & 1) << 15) // Address the DAC
02528                 // channel within the
02529                 // device.
02530                 | (uint32_t) dacdata);  // Include DAC setpoint data.
02531 
02532 }
02533 
02535 // Private helper function: Transmit serial data to DAC via Audio
02536 // channel 2.  Assumes: (1) TSL2 slot records initialized, and (2)
02537 // Dacpol contains valid target image.
02538 
02539 static void SendDAC(comedi_device * dev, uint32_t val)
02540 {
02541 
02542         // START THE SERIAL CLOCK RUNNING -------------
02543 
02544         // Assert DAC polarity control and enable gating of DAC serial clock
02545         // and audio bit stream signals.  At this point in time we must be
02546         // assured of being in time slot 0.  If we are not in slot 0, the
02547         // serial clock and audio stream signals will be disabled; this is
02548         // because the following DEBIwrite statement (which enables signals
02549         // to be passed through the gate array) would execute before the
02550         // trailing edge of WS1/WS3 (which turns off the signals), thus
02551         // causing the signals to be inactive during the DAC write.
02552         DEBIwrite(dev, LP_DACPOL, devpriv->Dacpol);
02553 
02554         // TRANSFER OUTPUT DWORD VALUE INTO A2'S OUTPUT FIFO ----------------
02555 
02556         // Copy DAC setpoint value to DAC's output DMA buffer.
02557 
02558         //WR7146( (uint32_t)devpriv->pDacWBuf, val );
02559         *devpriv->pDacWBuf = val;
02560 
02561         // enab the output DMA transfer.  This will cause the DMAC to copy
02562         // the DAC's data value to A2's output FIFO.  The DMA transfer will
02563         // then immediately terminate because the protection address is
02564         // reached upon transfer of the first DWORD value.
02565         MC_ENABLE(P_MC1, MC1_A2OUT);
02566 
02567         // While the DMA transfer is executing ...
02568 
02569         // Reset Audio2 output FIFO's underflow flag (along with any other
02570         // FIFO underflow/overflow flags).  When set, this flag will
02571         // indicate that we have emerged from slot 0.
02572         WR7146(P_ISR, ISR_AFOU);
02573 
02574         // Wait for the DMA transfer to finish so that there will be data
02575         // available in the FIFO when time slot 1 tries to transfer a DWORD
02576         // from the FIFO to the output buffer register.  We test for DMA
02577         // Done by polling the DMAC enable flag; this flag is automatically
02578         // cleared when the transfer has finished.
02579         while ((RR7146(P_MC1) & MC1_A2OUT) != 0) ;
02580 
02581         // START THE OUTPUT STREAM TO THE TARGET DAC --------------------
02582 
02583         // FIFO data is now available, so we enable execution of time slots
02584         // 1 and higher by clearing the EOS flag in slot 0.  Note that SD3
02585         // will be shifted in and stored in FB_BUFFER2 for end-of-slot-list
02586         // detection.
02587         SETVECT(0, XSD2 | RSD3 | SIB_A2);
02588 
02589         // Wait for slot 1 to execute to ensure that the Packet will be
02590         // transmitted.  This is detected by polling the Audio2 output FIFO
02591         // underflow flag, which will be set when slot 1 execution has
02592         // finished transferring the DAC's data DWORD from the output FIFO
02593         // to the output buffer register.
02594         while ((RR7146(P_SSR) & SSR_AF2_OUT) == 0) ;
02595 
02596         // Set up to trap execution at slot 0 when the TSL sequencer cycles
02597         // back to slot 0 after executing the EOS in slot 5.  Also,
02598         // simultaneously shift out and in the 0x00 that is ALWAYS the value
02599         // stored in the last byte to be shifted out of the FIFO's DWORD
02600         // buffer register.
02601         SETVECT(0, XSD2 | XFIFO_2 | RSD2 | SIB_A2 | EOS);
02602 
02603         // WAIT FOR THE TRANSACTION TO FINISH -----------------------
02604 
02605         // Wait for the TSL to finish executing all time slots before
02606         // exiting this function.  We must do this so that the next DAC
02607         // write doesn't start, thereby enabling clock/chip select signals:
02608         // 1. Before the TSL sequence cycles back to slot 0, which disables
02609         // the clock/cs signal gating and traps slot // list execution.  If
02610         // we have not yet finished slot 5 then the clock/cs signals are
02611         // still gated and we have // not finished transmitting the stream.
02612         // 2. While slots 2-5 are executing due to a late slot 0 trap.  In
02613         // this case, the slot sequence is currently // repeating, but with
02614         // clock/cs signals disabled.  We must wait for slot 0 to trap
02615         // execution before setting // up the next DAC setpoint DMA transfer
02616         // and enabling the clock/cs signals.  To detect the end of slot 5,
02617         // we test for the FB_BUFFER2 MSB contents to be equal to 0xFF.  If
02618         // the TSL has not yet finished executing slot 5 ...
02619         if ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0) {
02620                 // The trap was set on time and we are still executing somewhere
02621                 // in slots 2-5, so we now wait for slot 0 to execute and trap
02622                 // TSL execution.  This is detected when FB_BUFFER2 MSB changes
02623                 // from 0xFF to 0x00, which slot 0 causes to happen by shifting
02624                 // out/in on SD2 the 0x00 that is always referenced by slot 5.
02625                 while ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0) ;
02626         }
02627         // Either (1) we were too late setting the slot 0 trap; the TSL
02628         // sequencer restarted slot 0 before we could set the EOS trap flag,
02629         // or (2) we were not late and execution is now trapped at slot 0.
02630         // In either case, we must now change slot 0 so that it will store
02631         // value 0xFF (instead of 0x00) to FB_BUFFER2 next time it executes.
02632         // In order to do this, we reprogram slot 0 so that it will shift in
02633         // SD3, which is driven only by a pull-up resistor.
02634         SETVECT(0, RSD3 | SIB_A2 | EOS);
02635 
02636         // Wait for slot 0 to execute, at which time the TSL is setup for
02637         // the next DAC write.  This is detected when FB_BUFFER2 MSB changes
02638         // from 0x00 to 0xFF.
02639         while ((RR7146(P_FB_BUFFER2) & 0xFF000000) == 0) ;
02640 }
02641 
02642 static void WriteMISC2(comedi_device * dev, uint16_t NewImage)
02643 {
02644         DEBIwrite(dev, LP_MISC1, MISC1_WENABLE);        // enab writes to
02645         // MISC2 register.
02646         DEBIwrite(dev, LP_WRMISC2, NewImage);   // Write new image to MISC2.
02647         DEBIwrite(dev, LP_MISC1, MISC1_WDISABLE);       // Disable writes to MISC2.
02648 }
02649 
02651 // Initialize the DEBI interface for all transfers.
02652 
02653 static uint16_t DEBIread(comedi_device * dev, uint16_t addr)
02654 {
02655         uint16_t retval;
02656 
02657         // Set up DEBI control register value in shadow RAM.
02658         WR7146(P_DEBICMD, DEBI_CMD_RDWORD | addr);
02659 
02660         // Execute the DEBI transfer.
02661         DEBItransfer(dev);
02662 
02663         // Fetch target register value.
02664         retval = (uint16_t) RR7146(P_DEBIAD);
02665 
02666         // Return register value.
02667         return retval;
02668 }
02669 
02670 // Execute a DEBI transfer.  This must be called from within a
02671 // critical section.
02672 static void DEBItransfer(comedi_device * dev)
02673 {
02674         // Initiate upload of shadow RAM to DEBI control register.
02675         MC_ENABLE(P_MC2, MC2_UPLD_DEBI);
02676 
02677         // Wait for completion of upload from shadow RAM to DEBI control
02678         // register.
02679         while (!MC_TEST(P_MC2, MC2_UPLD_DEBI)) ;
02680 
02681         // Wait until DEBI transfer is done.
02682         while (RR7146(P_PSR) & PSR_DEBI_S) ;
02683 }
02684 
02685 // Write a value to a gate array register.
02686 static void DEBIwrite(comedi_device * dev, uint16_t addr, uint16_t wdata)
02687 {
02688 
02689         // Set up DEBI control register value in shadow RAM.
02690         WR7146(P_DEBICMD, DEBI_CMD_WRWORD | addr);
02691         WR7146(P_DEBIAD, wdata);
02692 
02693         // Execute the DEBI transfer.
02694         DEBItransfer(dev);
02695 }
02696 
02698 // Replace the specified bits in a gate array register.  Imports: mask
02699 // specifies bits that are to be preserved, wdata is new value to be
02700 // or'd with the masked original.
02701 static void DEBIreplace(comedi_device * dev, uint16_t addr, uint16_t mask,
02702         uint16_t wdata)
02703 {
02704 
02705         // Copy target gate array register into P_DEBIAD register.
02706         WR7146(P_DEBICMD, DEBI_CMD_RDWORD | addr);      // Set up DEBI control
02707         // reg value in shadow
02708         // RAM.
02709         DEBItransfer(dev);      // Execute the DEBI
02710         // Read transfer.
02711 
02712         // Write back the modified image.
02713         WR7146(P_DEBICMD, DEBI_CMD_WRWORD | addr);      // Set up DEBI control
02714         // reg value in shadow
02715         // RAM.
02716 
02717         WR7146(P_DEBIAD, wdata | ((uint16_t) RR7146(P_DEBIAD) & mask)); // Modify the register image.
02718         DEBItransfer(dev);      // Execute the DEBI Write transfer.
02719 }
02720 
02721 static void CloseDMAB(comedi_device * dev, DMABUF * pdma, size_t bsize)
02722 {
02723         void *vbptr;
02724         dma_addr_t vpptr;
02725 
02726         DEBUG("CloseDMAB: Entering S626DRV_CloseDMAB():\n");
02727         if (pdma == NULL)
02728                 return;
02729         //find the matching allocation from the board struct
02730 
02731         vbptr = pdma->LogicalBase;
02732         vpptr = pdma->PhysicalBase;
02733         if (vbptr) {
02734                 pci_free_consistent(devpriv->pdev, bsize, vbptr, vpptr);
02735                 pdma->LogicalBase = 0;
02736                 pdma->PhysicalBase = 0;
02737 
02738                 DEBUG("CloseDMAB(): Logical=%p, bsize=%d, Physical=0x%x\n",
02739                         vbptr, bsize, (uint32_t) vpptr);
02740         }
02741 }
02742 
02746 // All counter functions address a specific counter by means of the
02747 // "Counter" argument, which is a logical counter number.  The Counter
02748 // argument may have any of the following legal values: 0=0A, 1=1A,
02749 // 2=2A, 3=0B, 4=1B, 5=2B.
02751 
02752 // Forward declarations for functions that are common to both A and B
02753 // counters:
02754 
02758 
02760 // Read a counter's output latch.
02761 
02762 static uint32_t ReadLatch(comedi_device * dev, enc_private * k)
02763 {
02764         register uint32_t value;
02765         //DEBUG FIXME DEBUG("ReadLatch: Read Latch enter\n");
02766 
02767         // Latch counts and fetch LSW of latched counts value.
02768         value = (uint32_t) DEBIread(dev, k->MyLatchLsw);
02769 
02770         // Fetch MSW of latched counts and combine with LSW.
02771         value |= ((uint32_t) DEBIread(dev, k->MyLatchLsw + 2) << 16);
02772 
02773         // DEBUG FIXME DEBUG("ReadLatch: Read Latch exit\n");
02774 
02775         // Return latched counts.
02776         return value;
02777 }
02778 
02780 // Reset a counter's index and overflow event capture flags.
02781 
02782 static void ResetCapFlags_A(comedi_device * dev, enc_private * k)
02783 {
02784         DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL),
02785                 CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A);
02786 }
02787 
02788 static void ResetCapFlags_B(comedi_device * dev, enc_private * k)
02789 {
02790         DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL),
02791                 CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B);
02792 }
02793 
02795 // Return counter setup in a format (COUNTER_SETUP) that is consistent
02796 // for both A and B counters.
02797 
02798 static uint16_t GetMode_A(comedi_device * dev, enc_private * k)
02799 {
02800         register uint16_t cra;
02801         register uint16_t crb;
02802         register uint16_t setup;
02803 
02804         // Fetch CRA and CRB register images.
02805         cra = DEBIread(dev, k->MyCRA);
02806         crb = DEBIread(dev, k->MyCRB);
02807 
02808         // Populate the standardized counter setup bit fields.  Note:
02809         // IndexSrc is restricted to ENC_X or IndxPol.
02810         setup = ((cra & STDMSK_LOADSRC) // LoadSrc  = LoadSrcA.
02811                 | ((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC)      // LatchSrc = LatchSrcA.
02812                 | ((cra << (STDBIT_INTSRC - CRABIT_INTSRC_A)) & STDMSK_INTSRC)  // IntSrc   = IntSrcA.
02813                 | ((cra << (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1))) & STDMSK_INDXSRC) // IndxSrc  = IndxSrcA<1>.
02814                 | ((cra >> (CRABIT_INDXPOL_A - STDBIT_INDXPOL)) & STDMSK_INDXPOL)       // IndxPol  = IndxPolA.
02815                 | ((crb >> (CRBBIT_CLKENAB_A - STDBIT_CLKENAB)) & STDMSK_CLKENAB));     // ClkEnab  = ClkEnabA.
02816 
02817         // Adjust mode-dependent parameters.
02818         if (cra & (2 << CRABIT_CLKSRC_A))       // If Timer mode (ClkSrcA<1> == 1):
02819                 setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC)       //   Indicate Timer mode.
02820                         | ((cra << (STDBIT_CLKPOL - CRABIT_CLKSRC_A)) & STDMSK_CLKPOL)  //   Set ClkPol to indicate count direction (ClkSrcA<0>).
02821                         | (MULT_X1 << STDBIT_CLKMULT)); //   ClkMult must be 1x in Timer mode.
02822 
02823         else                    // If Counter mode (ClkSrcA<1> == 0):
02824                 setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC)     //   Indicate Counter mode.
02825                         | ((cra >> (CRABIT_CLKPOL_A - STDBIT_CLKPOL)) & STDMSK_CLKPOL)  //   Pass through ClkPol.
02826                         | (((cra & CRAMSK_CLKMULT_A) == (MULT_X0 << CRABIT_CLKMULT_A)) ?        //   Force ClkMult to 1x if not legal, else pass through.
02827                                 (MULT_X1 << STDBIT_CLKMULT) :
02828                                 ((cra >> (CRABIT_CLKMULT_A -
02829                                                         STDBIT_CLKMULT)) &
02830                                         STDMSK_CLKMULT)));
02831 
02832         // Return adjusted counter setup.
02833         return setup;
02834 }
02835 
02836 static uint16_t GetMode_B(comedi_device * dev, enc_private * k)
02837 {
02838         register uint16_t cra;
02839         register uint16_t crb;
02840         register uint16_t setup;
02841 
02842         // Fetch CRA and CRB register images.
02843         cra = DEBIread(dev, k->MyCRA);
02844         crb = DEBIread(dev, k->MyCRB);
02845 
02846         // Populate the standardized counter setup bit fields.  Note:
02847         // IndexSrc is restricted to ENC_X or IndxPol.
02848         setup = (((crb << (STDBIT_INTSRC - CRBBIT_INTSRC_B)) & STDMSK_INTSRC)   // IntSrc   = IntSrcB.
02849                 | ((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC)      // LatchSrc = LatchSrcB.
02850                 | ((crb << (STDBIT_LOADSRC - CRBBIT_LOADSRC_B)) & STDMSK_LOADSRC)       // LoadSrc  = LoadSrcB.
02851                 | ((crb << (STDBIT_INDXPOL - CRBBIT_INDXPOL_B)) & STDMSK_INDXPOL)       // IndxPol  = IndxPolB.
02852                 | ((crb >> (CRBBIT_CLKENAB_B - STDBIT_CLKENAB)) & STDMSK_CLKENAB)       // ClkEnab  = ClkEnabB.
02853                 | ((cra >> ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC)) & STDMSK_INDXSRC));       // IndxSrc  = IndxSrcB<1>.
02854 
02855         // Adjust mode-dependent parameters.
02856         if ((crb & CRBMSK_CLKMULT_B) == (MULT_X0 << CRBBIT_CLKMULT_B))  // If Extender mode (ClkMultB == MULT_X0):
02857                 setup |= ((CLKSRC_EXTENDER << STDBIT_CLKSRC)    //   Indicate Extender mode.
02858                         | (MULT_X1 << STDBIT_CLKMULT)   //   Indicate multiplier is 1x.
02859                         | ((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL));        //   Set ClkPol equal to Timer count direction (ClkSrcB<0>).
02860 
02861         else if (cra & (2 << CRABIT_CLKSRC_B))  // If Timer mode (ClkSrcB<1> == 1):
02862                 setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC)       //   Indicate Timer mode.
02863                         | (MULT_X1 << STDBIT_CLKMULT)   //   Indicate multiplier is 1x.
02864                         | ((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL));        //   Set ClkPol equal to Timer count direction (ClkSrcB<0>).
02865 
02866         else                    // If Counter mode (ClkSrcB<1> == 0):
02867                 setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC)     //   Indicate Timer mode.
02868                         | ((crb >> (CRBBIT_CLKMULT_B - STDBIT_CLKMULT)) & STDMSK_CLKMULT)       //   Clock multiplier is passed through.
02869                         | ((crb << (STDBIT_CLKPOL - CRBBIT_CLKPOL_B)) & STDMSK_CLKPOL));        //   Clock polarity is passed through.
02870 
02871         // Return adjusted counter setup.
02872         return setup;
02873 }
02874 
02876 // Set the operating mode for the specified counter.  The setup
02877 // parameter is treated as a COUNTER_SETUP data type.  The following
02878 // parameters are programmable (all other parms are ignored): ClkMult,
02879 // ClkPol, ClkEnab, IndexSrc, IndexPol, LoadSrc.
02880 
02881 static void SetMode_A(comedi_device * dev, enc_private * k, uint16_t Setup,
02882         uint16_t DisableIntSrc)
02883 {
02884         register uint16_t cra;
02885         register uint16_t crb;
02886         register uint16_t setup = Setup;        // Cache the Standard Setup.
02887 
02888         // Initialize CRA and CRB images.
02889         cra = ((setup & CRAMSK_LOADSRC_A)       // Preload trigger is passed through.
02890                 | ((setup & STDMSK_INDXSRC) >> (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1))));     // IndexSrc is restricted to ENC_X or IndxPol.
02891 
02892         crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A   // Reset any pending CounterA event captures.
02893                 | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_A - STDBIT_CLKENAB)));   // Clock enable is passed through.
02894 
02895         // Force IntSrc to Disabled if DisableIntSrc is asserted.
02896         if (!DisableIntSrc)
02897                 cra |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC -
02898                                 CRABIT_INTSRC_A));
02899 
02900         // Populate all mode-dependent attributes of CRA & CRB images.
02901         switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) {
02902         case CLKSRC_EXTENDER:   // Extender Mode: Force to Timer mode
02903                 // (Extender valid only for B counters).
02904 
02905         case CLKSRC_TIMER:      // Timer Mode:
02906                 cra |= ((2 << CRABIT_CLKSRC_A)  //   ClkSrcA<1> selects system clock
02907                         | ((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRABIT_CLKSRC_A))        //     with count direction (ClkSrcA<0>) obtained from ClkPol.
02908                         | (1 << CRABIT_CLKPOL_A)        //   ClkPolA behaves as always-on clock enable.
02909                         | (MULT_X1 << CRABIT_CLKMULT_A));       //   ClkMult must be 1x.
02910                 break;
02911 
02912         default:                // Counter Mode:
02913                 cra |= (CLKSRC_COUNTER  //   Select ENC_C and ENC_D as clock/direction inputs.
02914                         | ((setup & STDMSK_CLKPOL) << (CRABIT_CLKPOL_A - STDBIT_CLKPOL))        //   Clock polarity is passed through.
02915                         | (((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ?  //   Force multiplier to x1 if not legal, otherwise pass through.
02916                                 (MULT_X1 << CRABIT_CLKMULT_A) :
02917                                 ((setup & STDMSK_CLKMULT) << (CRABIT_CLKMULT_A -
02918                                                 STDBIT_CLKMULT))));
02919         }
02920 
02921         // Force positive index polarity if IndxSrc is software-driven only,
02922         // otherwise pass it through.
02923         if (~setup & STDMSK_INDXSRC)
02924                 cra |= ((setup & STDMSK_INDXPOL) << (CRABIT_INDXPOL_A -
02925                                 STDBIT_INDXPOL));
02926 
02927         // If IntSrc has been forced to Disabled, update the MISC2 interrupt
02928         // enable mask to indicate the counter interrupt is disabled.
02929         if (DisableIntSrc)
02930                 devpriv->CounterIntEnabs &= ~k->MyEventBits[3];
02931 
02932         // While retaining CounterB and LatchSrc configurations, program the
02933         // new counter operating mode.
02934         DEBIreplace(dev, k->MyCRA, CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B, cra);
02935         DEBIreplace(dev, k->MyCRB,
02936                 (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A)), crb);
02937 }
02938 
02939 static void SetMode_B(comedi_device * dev, enc_private * k, uint16_t Setup,
02940         uint16_t DisableIntSrc)
02941 {
02942         register uint16_t cra;
02943         register uint16_t crb;
02944         register uint16_t setup = Setup;        // Cache the Standard Setup.
02945 
02946         // Initialize CRA and CRB images.
02947         cra = ((setup & STDMSK_INDXSRC) << ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC));  // IndexSrc field is restricted to ENC_X or IndxPol.
02948 
02949         crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B   // Reset event captures and disable interrupts.
02950                 | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_B - STDBIT_CLKENAB))     // Clock enable is passed through.
02951                 | ((setup & STDMSK_LOADSRC) >> (STDBIT_LOADSRC - CRBBIT_LOADSRC_B)));   // Preload trigger source is passed through.
02952 
02953         // Force IntSrc to Disabled if DisableIntSrc is asserted.
02954         if (!DisableIntSrc)
02955                 crb |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC -
02956                                 CRBBIT_INTSRC_B));
02957 
02958         // Populate all mode-dependent attributes of CRA & CRB images.
02959         switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) {
02960         case CLKSRC_TIMER:      // Timer Mode:
02961                 cra |= ((2 << CRABIT_CLKSRC_B)  //   ClkSrcB<1> selects system clock
02962                         | ((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL)));      //     with direction (ClkSrcB<0>) obtained from ClkPol.
02963                 crb |= ((1 << CRBBIT_CLKPOL_B)  //   ClkPolB behaves as always-on clock enable.
02964                         | (MULT_X1 << CRBBIT_CLKMULT_B));       //   ClkMultB must be 1x.
02965                 break;
02966 
02967         case CLKSRC_EXTENDER:   // Extender Mode:
02968                 cra |= ((2 << CRABIT_CLKSRC_B)  //   ClkSrcB source is OverflowA (same as "timer")
02969                         | ((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL)));      //     with direction obtained from ClkPol.
02970                 crb |= ((1 << CRBBIT_CLKPOL_B)  //   ClkPolB controls IndexB -- always set to active.
02971                         | (MULT_X0 << CRBBIT_CLKMULT_B));       //   ClkMultB selects OverflowA as the clock source.
02972                 break;
02973 
02974         default:                // Counter Mode:
02975                 cra |= (CLKSRC_COUNTER << CRABIT_CLKSRC_B);     //   Select ENC_C and ENC_D as clock/direction inputs.
02976                 crb |= (((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRBBIT_CLKPOL_B))  //   ClkPol is passed through.
02977                         | (((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ?  //   Force ClkMult to x1 if not legal, otherwise pass through.
02978                                 (MULT_X1 << CRBBIT_CLKMULT_B) :
02979                                 ((setup & STDMSK_CLKMULT) << (CRBBIT_CLKMULT_B -
02980                                                 STDBIT_CLKMULT))));
02981         }
02982 
02983         // Force positive index polarity if IndxSrc is software-driven only,
02984         // otherwise pass it through.
02985         if (~setup & STDMSK_INDXSRC)
02986                 crb |= ((setup & STDMSK_INDXPOL) >> (STDBIT_INDXPOL -
02987                                 CRBBIT_INDXPOL_B));
02988 
02989         // If IntSrc has been forced to Disabled, update the MISC2 interrupt
02990         // enable mask to indicate the counter interrupt is disabled.
02991         if (DisableIntSrc)
02992                 devpriv->CounterIntEnabs &= ~k->MyEventBits[3];
02993 
02994         // While retaining CounterA and LatchSrc configurations, program the
02995         // new counter operating mode.
02996         DEBIreplace(dev, k->MyCRA,
02997                 (uint16_t) (~(CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B)), cra);
02998         DEBIreplace(dev, k->MyCRB, CRBMSK_CLKENAB_A | CRBMSK_LATCHSRC, crb);
02999 }
03000 
03002 // Return/set a counter's enable.  enab: 0=always enabled, 1=enabled by index.
03003 
03004 static void SetEnable_A(comedi_device * dev, enc_private * k, uint16_t enab)
03005 {
03006         DEBUG("SetEnable_A: SetEnable_A enter 3541\n");
03007         DEBIreplace(dev, k->MyCRB,
03008                 (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A)),
03009                 (uint16_t) (enab << CRBBIT_CLKENAB_A));
03010 }
03011 
03012 static void SetEnable_B(comedi_device * dev, enc_private * k, uint16_t enab)
03013 {
03014         DEBIreplace(dev, k->MyCRB,
03015                 (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_B)),
03016                 (uint16_t) (enab << CRBBIT_CLKENAB_B));
03017 }
03018 
03019 static uint16_t GetEnable_A(comedi_device * dev, enc_private * k)
03020 {
03021         return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_A) & 1;
03022 }
03023 
03024 static uint16_t GetEnable_B(comedi_device * dev, enc_private * k)
03025 {
03026         return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_B) & 1;
03027 }
03028 
03030 // Return/set a counter pair's latch trigger source.  0: On read
03031 // access, 1: A index latches A, 2: B index latches B, 3: A overflow
03032 // latches B.
03033 
03034 static void SetLatchSource(comedi_device * dev, enc_private * k, uint16_t value)
03035 {
03036         DEBUG("SetLatchSource: SetLatchSource enter 3550 \n");
03037         DEBIreplace(dev, k->MyCRB,
03038                 (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_LATCHSRC)),
03039                 (uint16_t) (value << CRBBIT_LATCHSRC));
03040 
03041         DEBUG("SetLatchSource: SetLatchSource exit \n");
03042 }
03043 
03044 /* static uint16_t GetLatchSource(comedi_device *dev, enc_private *k ) */
03045 /* { */
03046 /*   return ( DEBIread( dev, k->MyCRB) >> CRBBIT_LATCHSRC ) & 3; */
03047 /* } */
03048 
03050 // Return/set the event that will trigger transfer of the preload
03051 // register into the counter.  0=ThisCntr_Index, 1=ThisCntr_Overflow,
03052 // 2=OverflowA (B counters only), 3=disabled.
03053 
03054 static void SetLoadTrig_A(comedi_device * dev, enc_private * k, uint16_t Trig)
03055 {
03056         DEBIreplace(dev, k->MyCRA, (uint16_t) (~CRAMSK_LOADSRC_A),
03057                 (uint16_t) (Trig << CRABIT_LOADSRC_A));
03058 }
03059 
03060 static void SetLoadTrig_B(comedi_device * dev, enc_private * k, uint16_t Trig)
03061 {
03062         DEBIreplace(dev, k->MyCRB,
03063                 (uint16_t) (~(CRBMSK_LOADSRC_B | CRBMSK_INTCTRL)),
03064                 (uint16_t) (Trig << CRBBIT_LOADSRC_B));
03065 }
03066 
03067 static uint16_t GetLoadTrig_A(comedi_device * dev, enc_private * k)
03068 {
03069         return (DEBIread(dev, k->MyCRA) >> CRABIT_LOADSRC_A) & 3;
03070 }
03071 
03072 static uint16_t GetLoadTrig_B(comedi_device * dev, enc_private * k)
03073 {
03074         return (DEBIread(dev, k->MyCRB) >> CRBBIT_LOADSRC_B) & 3;
03075 }
03076 
03078 // Return/set counter interrupt source and clear any captured
03079 // index/overflow events.  IntSource: 0=Disabled, 1=OverflowOnly,
03080 // 2=IndexOnly, 3=IndexAndOverflow.
03081 
03082 static void SetIntSrc_A(comedi_device * dev, enc_private * k,
03083         uint16_t IntSource)
03084 {
03085         // Reset any pending counter overflow or index captures.
03086         DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL),
03087                 CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A);
03088 
03089         // Program counter interrupt source.
03090         DEBIreplace(dev, k->MyCRA, ~CRAMSK_INTSRC_A,
03091                 (uint16_t) (IntSource << CRABIT_INTSRC_A));
03092 
03093         // Update MISC2 interrupt enable mask.
03094         devpriv->CounterIntEnabs =
03095                 (devpriv->CounterIntEnabs & ~k->MyEventBits[3]) | k->
03096                 MyEventBits[IntSource];
03097 }
03098 
03099 static void SetIntSrc_B(comedi_device * dev, enc_private * k,
03100         uint16_t IntSource)
03101 {
03102         uint16_t crb;
03103 
03104         // Cache writeable CRB register image.
03105         crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL;
03106 
03107         // Reset any pending counter overflow or index captures.
03108         DEBIwrite(dev, k->MyCRB,
03109                 (uint16_t) (crb | CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B));
03110 
03111         // Program counter interrupt source.
03112         DEBIwrite(dev, k->MyCRB,
03113                 (uint16_t) ((crb & ~CRBMSK_INTSRC_B) | (IntSource <<
03114                                 CRBBIT_INTSRC_B)));
03115 
03116         // Update MISC2 interrupt enable mask.
03117         devpriv->CounterIntEnabs =
03118                 (devpriv->CounterIntEnabs & ~k->MyEventBits[3]) | k->
03119                 MyEventBits[IntSource];
03120 }
03121 
03122 static uint16_t GetIntSrc_A(comedi_device * dev, enc_private * k)
03123 {
03124         return (DEBIread(dev, k->MyCRA) >> CRABIT_INTSRC_A) & 3;
03125 }
03126 
03127 static uint16_t GetIntSrc_B(comedi_device * dev, enc_private * k)
03128 {
03129         return (DEBIread(dev, k->MyCRB) >> CRBBIT_INTSRC_B) & 3;
03130 }
03131 
03133 // Return/set the clock multiplier.
03134 
03135 /* static void SetClkMult(comedi_device *dev, enc_private *k, uint16_t value )  */
03136 /* { */
03137 /*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKMULT ) | ( value << STDBIT_CLKMULT ) ), FALSE ); */
03138 /* } */
03139 
03140 /* static uint16_t GetClkMult(comedi_device *dev, enc_private *k )  */
03141 /* { */
03142 /*   return ( k->GetMode(dev, k ) >> STDBIT_CLKMULT ) & 3; */
03143 /* } */
03144 
03145 /* ////////////////////////////////////////////////////////////////////////// */
03146 /* // Return/set the clock polarity. */
03147 
03148 /* static void SetClkPol( comedi_device *dev,enc_private *k, uint16_t value )  */
03149 /* { */
03150 /*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKPOL ) | ( value << STDBIT_CLKPOL ) ), FALSE ); */
03151 /* } */
03152 
03153 /* static uint16_t GetClkPol(comedi_device *dev, enc_private *k )  */
03154 /* { */
03155 /*   return ( k->GetMode(dev, k ) >> STDBIT_CLKPOL ) & 1; */
03156 /* } */
03157 
03158 /* /////////////////////////////////////////////////////////////////////// */
03159 /* // Return/set the clock source. */
03160 
03161 /* static void SetClkSrc( comedi_device *dev,enc_private *k, uint16_t value )  */
03162 /* { */
03163 /*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKSRC ) | ( value << STDBIT_CLKSRC ) ), FALSE ); */
03164 /* } */
03165 
03166 /* static uint16_t GetClkSrc( comedi_device *dev,enc_private *k )  */
03167 /* { */
03168 /*   return ( k->GetMode(dev, k ) >> STDBIT_CLKSRC ) & 3; */
03169 /* } */
03170 
03171 /* //////////////////////////////////////////////////////////////////////// */
03172 /* // Return/set the index polarity. */
03173 
03174 /* static void SetIndexPol(comedi_device *dev, enc_private *k, uint16_t value )  */
03175 /* { */
03176 /*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXPOL ) | ( (value != 0) << STDBIT_INDXPOL ) ), FALSE ); */
03177 /* } */
03178 
03179 /* static uint16_t GetIndexPol(comedi_device *dev, enc_private *k )  */
03180 /* { */
03181 /*   return ( k->GetMode(dev, k ) >> STDBIT_INDXPOL ) & 1; */
03182 /* } */
03183 
03184 /* //////////////////////////////////////////////////////////////////////// */
03185 /* // Return/set the index source. */
03186 
03187 /* static void SetIndexSrc(comedi_device *dev, enc_private *k, uint16_t value )  */
03188 /* { */
03189 /*   DEBUG("SetIndexSrc: set index src enter 3700\n"); */
03190 /*   k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXSRC ) | ( (value != 0) << STDBIT_INDXSRC ) ), FALSE ); */
03191 /* } */
03192 
03193 /* static uint16_t GetIndexSrc(comedi_device *dev, enc_private *k )  */
03194 /* { */
03195 /*   return ( k->GetMode(dev, k ) >> STDBIT_INDXSRC ) & 1; */
03196 /* } */
03197 
03199 // Generate an index pulse.
03200 
03201 static void PulseIndex_A(comedi_device * dev, enc_private * k)
03202 {
03203         register uint16_t cra;
03204 
03205         DEBUG("PulseIndex_A: pulse index enter\n");
03206 
03207         cra = DEBIread(dev, k->MyCRA);  // Pulse index.
03208         DEBIwrite(dev, k->MyCRA, (uint16_t) (cra ^ CRAMSK_INDXPOL_A));
03209         DEBUG("PulseIndex_A: pulse index step1\n");
03210         DEBIwrite(dev, k->MyCRA, cra);
03211 }
03212 
03213 static void PulseIndex_B(comedi_device * dev, enc_private * k)
03214 {
03215         register uint16_t crb;
03216 
03217         crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL;        // Pulse index.
03218         DEBIwrite(dev, k->MyCRB, (uint16_t) (crb ^ CRBMSK_INDXPOL_B));
03219         DEBIwrite(dev, k->MyCRB, crb);
03220 }
03221 
03223 // Write value into counter preload register.
03224 
03225 static void Preload(comedi_device * dev, enc_private * k, uint32_t value)
03226 {
03227         DEBUG("Preload: preload enter\n");
03228         DEBIwrite(dev, (uint16_t) (k->MyLatchLsw), (uint16_t) value);   // Write value to preload register.
03229         DEBUG("Preload: preload step 1\n");
03230         DEBIwrite(dev, (uint16_t) (k->MyLatchLsw + 2),
03231                 (uint16_t) (value >> 16));
03232 }
03233 
03234 static void CountersInit(comedi_device * dev)
03235 {
03236         int chan;
03237         enc_private *k;
03238         uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | // Preload upon
03239                 // index.
03240                 (INDXSRC_SOFT << BF_INDXSRC) |  // Disable hardware index.
03241                 (CLKSRC_COUNTER << BF_CLKSRC) | // Operating mode is counter.
03242                 (CLKPOL_POS << BF_CLKPOL) |     // Active high clock.
03243                 (CNTDIR_UP << BF_CLKPOL) |      // Count direction is up.
03244                 (CLKMULT_1X << BF_CLKMULT) |    // Clock multiplier is 1x.
03245                 (CLKENAB_INDEX << BF_CLKENAB);  // Enabled by index
03246 
03247         // Disable all counter interrupts and clear any captured counter events.
03248         for (chan = 0; chan < S626_ENCODER_CHANNELS; chan++) {
03249                 k = &encpriv[chan];
03250                 k->SetMode(dev, k, Setup, TRUE);
03251                 k->SetIntSrc(dev, k, 0);
03252                 k->ResetCapFlags(dev, k);
03253                 k->SetEnable(dev, k, CLKENAB_ALWAYS);
03254         }
03255         DEBUG("CountersInit: counters initialized \n");
03256 
03257 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines