static void pcl711_set_changain(struct comedi_device *dev, int chan) { const struct pcl711_board *board = comedi_board(dev); int chan_register; outb(CR_RANGE(chan), dev->iobase + PCL711_GAIN); chan_register = CR_CHAN(chan); if (board->is_8112) { /* * Set the correct channel. The two channel banks are switched * using the mask value. * NB: To use differential channels, you should use * mask = 0x30, but I haven't written the support for this * yet. /JJ */ if (chan_register >= 8) chan_register = 0x20 | (chan_register & 0x7); else chan_register |= 0x10; } else { outb(chan_register, dev->iobase + PCL711_MUX); } }
static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { const struct das16_board *board = comedi_board(dev); unsigned long flags; spin_lock_irqsave(&dev->spinlock, flags); /* disable interrupts, dma and pacer clocked conversions */ devpriv->control_state &= ~DAS16_INTE & ~PACING_MASK & ~DMA_ENABLE; outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); if (devpriv->dma_chan) disable_dma(devpriv->dma_chan); /* disable SW timer */ if (devpriv->timer_mode && devpriv->timer_running) { devpriv->timer_running = 0; del_timer(&devpriv->timer); } /* disable burst mode */ if (board->size > 0x400) outb(0, dev->iobase + DAS1600_BURST); spin_unlock_irqrestore(&dev->spinlock, flags); return 0; }
static irqreturn_t pcl711_interrupt(int irq, void *d) { int lo, hi; int data; struct comedi_device *dev = d; const struct pcl711_board *board = comedi_board(dev); struct comedi_subdevice *s = &dev->subdevices[0]; if (!dev->attached) { comedi_error(dev, "spurious interrupt"); return IRQ_HANDLED; } hi = inb(dev->iobase + PCL711_AD_HI); lo = inb(dev->iobase + PCL711_AD_LO); outb(0, dev->iobase + PCL711_CLRINTR); data = (hi << 8) | lo; /* FIXME! Nothing else sets ntrig! */ if (!(--devpriv->ntrig)) { if (board->is_8112) outb(1, dev->iobase + PCL711_MODE); else outb(0, dev->iobase + PCL711_MODE); s->async->events |= COMEDI_CB_EOA; } comedi_event(dev, s); return IRQ_HANDLED; }
static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct das08_board_struct *thisboard = comedi_board(dev); struct das08_private_struct *devpriv = dev->private; int i, n; int chan; int range; int lsb, msb; chan = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); /* clear crap */ inb(dev->iobase + DAS08_LSB); inb(dev->iobase + DAS08_MSB); /* set multiplexer */ /* lock to prevent race with digital output */ spin_lock(&dev->spinlock); devpriv->do_mux_bits &= ~DAS08_MUX_MASK; devpriv->do_mux_bits |= DAS08_MUX(chan); outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL); spin_unlock(&dev->spinlock); if (s->range_table->length > 1) { /* set gain/range */ range = CR_RANGE(insn->chanspec); outb(devpriv->pg_gainlist[range], dev->iobase + DAS08AO_GAIN_CONTROL); } for (n = 0; n < insn->n; n++) { /* clear over-range bits for 16-bit boards */ if (thisboard->ai_nbits == 16) if (inb(dev->iobase + DAS08_MSB) & 0x80) dev_info(dev->class_dev, "over-range\n"); /* trigger conversion */ outb_p(0, dev->iobase + DAS08_TRIG_12BIT); for (i = 0; i < TIMEOUT; i++) { if (!(inb(dev->iobase + DAS08_STATUS) & DAS08_EOC)) break; } if (i == TIMEOUT) { dev_err(dev->class_dev, "timeout\n"); return -ETIME; } msb = inb(dev->iobase + DAS08_MSB); lsb = inb(dev->iobase + DAS08_LSB); if (thisboard->ai_encoding == das08_encode12) { data[n] = (lsb >> 4) | (msb << 4); } else if (thisboard->ai_encoding == das08_pcm_encode12) {
/* * Read 32-bit register. */ static unsigned int dio200_read32(struct comedi_device *dev, unsigned int offset) { const struct dio200_board *thisboard = comedi_board(dev); offset <<= thisboard->mainshift; if (dev->mmio) return readl(dev->mmio + offset); return inl(dev->iobase + offset); }
/* * Write 32-bit register. */ static void dio200_write32(struct comedi_device *dev, unsigned int offset, unsigned int val) { const struct dio200_board *thisboard = comedi_board(dev); offset <<= thisboard->mainshift; if (dev->mmio) writel(val, dev->mmio + offset); else outl(val, dev->iobase + offset); }
static void dio200_pci_detach(struct comedi_device *dev) { const struct dio200_board *thisboard = comedi_board(dev); struct dio200_private *devpriv = dev->private; if (!thisboard || !devpriv) return; amplc_dio200_common_detach(dev); if (devpriv->io.regtype == mmio_regtype) iounmap(devpriv->io.u.membase); comedi_pci_disable(dev); }
static void pcl724_detach(struct comedi_device *dev) { const struct pcl724_board *board = comedi_board(dev); int i; for (i = 0; i < dev->n_subdevices; i++) subdev_8255_cleanup(dev, dev->subdevices + i); #ifdef PCL724_IRQ if (dev->irq) free_irq(dev->irq, dev); #endif release_region(dev->iobase, board->io_range); }
void labpc_handle_dma_status(struct comedi_device *dev) { const struct labpc_boardinfo *board = comedi_board(dev); struct labpc_private *devpriv = dev->private; /* * if a dma terminal count of external stop trigger * has occurred */ if (devpriv->stat1 & STAT1_GATA0 || (board->is_labpc1200 && devpriv->stat2 & STAT2_OUTA1)) handle_isa_dma(dev); }
static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct das16_board *board = comedi_board(dev); int i, n; int range; int chan; int msb, lsb; /* disable interrupts and pacing */ devpriv->control_state &= ~DAS16_INTE & ~DMA_ENABLE & ~PACING_MASK; outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); /* set multiplexer */ chan = CR_CHAN(insn->chanspec); chan |= CR_CHAN(insn->chanspec) << 4; outb(chan, dev->iobase + DAS16_MUX); /* set gain */ if (board->ai_pg != das16_pg_none) { range = CR_RANGE(insn->chanspec); outb((das16_gainlists[board->ai_pg])[range], dev->iobase + DAS16_GAIN); } for (n = 0; n < insn->n; n++) { /* trigger conversion */ outb_p(0, dev->iobase + DAS16_TRIG); for (i = 0; i < DAS16_TIMEOUT; i++) { if (!(inb(dev->iobase + DAS16_STATUS) & BUSY)) break; } if (i == DAS16_TIMEOUT) { printk("das16: timeout\n"); return -ETIME; } msb = inb(dev->iobase + DAS16_AI_MSB); lsb = inb(dev->iobase + DAS16_AI_LSB); if (board->ai_nbits == 12) data[n] = ((lsb >> 4) & 0xf) | (msb << 4); else data[n] = lsb | (msb << 8); }
static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl724_board *board = comedi_board(dev); struct comedi_subdevice *s; unsigned long iobase; unsigned int iorange; int n_subdevices; int ret; int i; iorange = board->io_range; n_subdevices = board->numofports; /* Handle PCL-724 in 96 DIO configuration */ if (board->can_have96 && (it->options[2] == 1 || it->options[2] == 96)) { iorange = 0x10; n_subdevices = 4; } ret = comedi_request_region(dev, it->options[0], iorange); if (ret) return ret; ret = comedi_alloc_subdevices(dev, n_subdevices); if (ret) return ret; for (i = 0; i < dev->n_subdevices; i++) { s = &dev->subdevices[i]; if (board->is_pet48) { iobase = dev->iobase + (i * 0x1000); ret = subdev_8255_init(dev, s, pcl724_8255mapped_io, iobase); } else { iobase = dev->iobase + (i * SIZE_8255); ret = subdev_8255_init(dev, s, NULL, iobase); } if (ret) return ret; } return 0; }
static int pcl711_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct pcl711_board *board = comedi_board(dev); int i, n; int hi, lo; pcl711_set_changain(dev, insn->chanspec); for (n = 0; n < insn->n; n++) { /* * Write the correct mode (software polling) and start polling * by writing to the trigger register */ outb(1, dev->iobase + PCL711_MODE); if (!board->is_8112) outb(0, dev->iobase + PCL711_SOFTTRIG); i = PCL711_TIMEOUT; while (--i) { hi = inb(dev->iobase + PCL711_AD_HI); if (!(hi & PCL711_DRDY)) goto ok; udelay(1); } printk(KERN_ERR "comedi%d: pcl711: A/D timeout\n", dev->minor); return -ETIME; ok: lo = inb(dev->iobase + PCL711_AD_LO); data[n] = ((hi & 0xf) << 8) | lo; } return n; }
static unsigned int ni_65xx_num_ports(struct comedi_device *dev) { const struct ni_65xx_board *board = comedi_board(dev); return board->num_dio_ports + board->num_di_ports + board->num_do_ports; }
static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl724_board *board = comedi_board(dev); unsigned long iobase; unsigned int iorange; int ret, i, n_subdevices; #ifdef PCL724_IRQ unsigned int irq; #endif iobase = it->options[0]; iorange = board->io_range; if ((board->can_have96) && ((it->options[1] == 1) || (it->options[1] == 96))) iorange = PCL722_96_SIZE; /* PCL-724 in 96 DIO configuration */ printk(KERN_INFO "comedi%d: pcl724: board=%s, 0x%03lx ", dev->minor, board->name, iobase); if (!request_region(iobase, iorange, "pcl724")) { printk("I/O port conflict\n"); return -EIO; } dev->iobase = iobase; dev->board_name = board->name; #ifdef PCL724_IRQ irq = 0; if (board->IRQbits != 0) { /* board support IRQ */ irq = it->options[1]; if (irq) { /* we want to use IRQ */ if (((1 << irq) & board->IRQbits) == 0) { printk(KERN_WARNING ", IRQ %u is out of allowed range, " "DISABLING IT", irq); irq = 0; /* Bad IRQ */ } else { if (request_irq (irq, interrupt_pcl724, 0, "pcl724", dev)) { printk(KERN_WARNING ", unable to allocate IRQ %u, " "DISABLING IT", irq); irq = 0; /* Can't use IRQ */ } else { printk(", irq=%u", irq); } } } } dev->irq = irq; #endif printk("\n"); n_subdevices = board->numofports; if ((board->can_have96) && ((it->options[1] == 1) || (it->options[1] == 96))) n_subdevices = 4; /* PCL-724 in 96 DIO configuration */ ret = comedi_alloc_subdevices(dev, n_subdevices); if (ret) return ret; for (i = 0; i < dev->n_subdevices; i++) { if (board->is_pet48) { subdev_8255_init(dev, dev->subdevices + i, subdev_8255mapped_cb, (unsigned long)(dev->iobase + i * 0x1000)); } else subdev_8255_init(dev, dev->subdevices + i, subdev_8255_cb, (unsigned long)(dev->iobase + SIZE_8255 * i)); } return 0; }
static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) { const struct das16_board *board = comedi_board(dev); struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int byte; unsigned long flags; int range; if (devpriv->dma_chan == 0 || (dev->irq == 0 && devpriv->timer_mode == 0)) { comedi_error(dev, "irq (or use of 'timer mode') dma required to " "execute comedi_cmd"); return -1; } if (cmd->flags & TRIG_RT) { comedi_error(dev, "isa dma transfers cannot be performed with " "TRIG_RT, aborting"); return -1; } devpriv->adc_byte_count = cmd->stop_arg * cmd->chanlist_len * sizeof(uint16_t); /* disable conversions for das1600 mode */ if (board->size > 0x400) outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV); /* set scan limits */ byte = CR_CHAN(cmd->chanlist[0]); byte |= CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]) << 4; outb(byte, dev->iobase + DAS16_MUX); /* set gain (this is also burst rate register but according to * computer boards manual, burst rate does nothing, even on * keithley cards) */ if (board->ai_pg != das16_pg_none) { range = CR_RANGE(cmd->chanlist[0]); outb((das16_gainlists[board->ai_pg])[range], dev->iobase + DAS16_GAIN); } /* set counter mode and counts */ cmd->convert_arg = das16_set_pacer(dev, cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); DEBUG_PRINT("pacer period: %d ns\n", cmd->convert_arg); /* enable counters */ byte = 0; /* Enable burst mode if appropriate. */ if (board->size > 0x400) { if (cmd->convert_src == TRIG_NOW) { outb(DAS1600_BURST_VAL, dev->iobase + DAS1600_BURST); /* set burst length */ byte |= BURST_LEN_BITS(cmd->chanlist_len - 1); } else { outb(0, dev->iobase + DAS1600_BURST); } } outb(byte, dev->iobase + DAS16_PACER); /* set up dma transfer */ flags = claim_dma_lock(); disable_dma(devpriv->dma_chan); /* clear flip-flop to make sure 2-byte registers for * count and address get set correctly */ clear_dma_ff(devpriv->dma_chan); devpriv->current_buffer = 0; set_dma_addr(devpriv->dma_chan, devpriv->dma_buffer_addr[devpriv->current_buffer]); /* set appropriate size of transfer */ devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, *cmd); set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); enable_dma(devpriv->dma_chan); release_dma_lock(flags); /* set up interrupt */ if (devpriv->timer_mode) { devpriv->timer_running = 1; devpriv->timer.expires = jiffies + timer_period(); add_timer(&devpriv->timer); devpriv->control_state &= ~DAS16_INTE; } else { /* clear interrupt bit */ outb(0x00, dev->iobase + DAS16_STATUS); /* enable interrupts */ devpriv->control_state |= DAS16_INTE; } devpriv->control_state |= DMA_ENABLE; devpriv->control_state &= ~PACING_MASK; if (cmd->convert_src == TRIG_EXT) devpriv->control_state |= EXT_PACER; else devpriv->control_state |= INT_PACER; outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); /* Enable conversions if using das1600 mode */ if (board->size > 0x400) outb(0, dev->iobase + DAS1600_CONV); return 0; }
static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct das16_board *board = comedi_board(dev); int err = 0, tmp; int gain, start_chan, i; int mask; /* make sure triggers are valid */ tmp = cmd->start_src; cmd->start_src &= TRIG_NOW; if (!cmd->start_src || tmp != cmd->start_src) err++; tmp = cmd->scan_begin_src; mask = TRIG_FOLLOW; /* if board supports burst mode */ if (board->size > 0x400) mask |= TRIG_TIMER | TRIG_EXT; cmd->scan_begin_src &= mask; if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++; tmp = cmd->convert_src; mask = TRIG_TIMER | TRIG_EXT; /* if board supports burst mode */ if (board->size > 0x400) mask |= TRIG_NOW; cmd->convert_src &= mask; if (!cmd->convert_src || tmp != cmd->convert_src) err++; tmp = cmd->scan_end_src; cmd->scan_end_src &= TRIG_COUNT; if (!cmd->scan_end_src || tmp != cmd->scan_end_src) err++; tmp = cmd->stop_src; cmd->stop_src &= TRIG_COUNT | TRIG_NONE; if (!cmd->stop_src || tmp != cmd->stop_src) err++; if (err) return 1; /** * step 2: make sure trigger sources are unique and * mutually compatible */ if (cmd->scan_begin_src != TRIG_TIMER && cmd->scan_begin_src != TRIG_EXT && cmd->scan_begin_src != TRIG_FOLLOW) err++; if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) err++; if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) err++; /* make sure scan_begin_src and convert_src dont conflict */ if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) err++; if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW) err++; if (err) return 2; /* step 3: make sure arguments are trivially compatible */ if (cmd->start_arg != 0) { cmd->start_arg = 0; err++; } if (cmd->scan_begin_src == TRIG_FOLLOW) { /* internal trigger */ if (cmd->scan_begin_arg != 0) { cmd->scan_begin_arg = 0; err++; } } if (cmd->scan_end_arg != cmd->chanlist_len) { cmd->scan_end_arg = cmd->chanlist_len; err++; } /* check against maximum frequency */ if (cmd->scan_begin_src == TRIG_TIMER) { if (cmd->scan_begin_arg < board->ai_speed * cmd->chanlist_len) { cmd->scan_begin_arg = board->ai_speed * cmd->chanlist_len; err++; } } if (cmd->convert_src == TRIG_TIMER) { if (cmd->convert_arg < board->ai_speed) { cmd->convert_arg = board->ai_speed; err++; } } if (cmd->stop_src == TRIG_NONE) { if (cmd->stop_arg != 0) { cmd->stop_arg = 0; err++; } } if (err) return 3; /* step 4: fix up arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { unsigned int tmp = cmd->scan_begin_arg; /* set divisors, correct timing arguments */ i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1), &(devpriv->divisor2), &(cmd->scan_begin_arg), cmd->flags & TRIG_ROUND_MASK); err += (tmp != cmd->scan_begin_arg); } if (cmd->convert_src == TRIG_TIMER) { unsigned int tmp = cmd->convert_arg; /* set divisors, correct timing arguments */ i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1), &(devpriv->divisor2), &(cmd->convert_arg), cmd->flags & TRIG_ROUND_MASK); err += (tmp != cmd->convert_arg); } if (err) return 4; /* check channel/gain list against card's limitations */ if (cmd->chanlist) { gain = CR_RANGE(cmd->chanlist[0]); start_chan = CR_CHAN(cmd->chanlist[0]); for (i = 1; i < cmd->chanlist_len; i++) { if (CR_CHAN(cmd->chanlist[i]) != (start_chan + i) % s->n_chan) { comedi_error(dev, "entries in chanlist must be " "consecutive channels, " "counting upwards\n"); err++; } if (CR_RANGE(cmd->chanlist[i]) != gain) { comedi_error(dev, "entries in chanlist must all " "have the same gain\n"); err++; } } } if (err) return 5; return 0; }
/* options[0] Board base address options[1] IRQ options[2] Input configuration 0 == single-ended 1 == differential 2 == pseudo-differential options[3] Analog input range configuration 0 == bipolar 5 (-5V -- +5V) 1 == bipolar 2.5V (-2.5V -- +2.5V) 2 == unipolar 5V (0V -- +5V) options[4] Analog output 0 range configuration 0 == bipolar 5 (-5V -- +5V) 1 == bipolar 2.5V (-2.5V -- +2.5V) 2 == unipolar 5V (0V -- +5V) options[5] Analog output 1 range configuration 0 == bipolar 5 (-5V -- +5V) 1 == bipolar 2.5V (-2.5V -- +2.5V) 2 == unipolar 5V (0V -- +5V) */ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) { /* int i, irq; */ /* unsigned long irqs; */ /* long flags; */ const struct dt2811_board *board = comedi_board(dev); int ret; struct comedi_subdevice *s; unsigned long iobase; iobase = it->options[0]; printk(KERN_INFO "comedi%d: dt2811:base=0x%04lx\n", dev->minor, iobase); if (!request_region(iobase, DT2811_SIZE, driver_name)) { printk(KERN_ERR "I/O port conflict\n"); return -EIO; } dev->iobase = iobase; dev->board_name = board->name; #if 0 outb(0, dev->iobase + DT2811_ADCSR); udelay(100); i = inb(dev->iobase + DT2811_ADDATLO); i = inb(dev->iobase + DT2811_ADDATHI); #endif #if 0 irq = it->options[1]; if (irq < 0) { save_flags(flags); sti(); irqs = probe_irq_on(); outb(DT2811_CLRERROR | DT2811_INTENB, dev->iobase + DT2811_ADCSR); outb(0, dev->iobase + DT2811_ADGCR); udelay(100); irq = probe_irq_off(irqs); restore_flags(flags); /*outb(DT2811_CLRERROR|DT2811_INTENB, dev->iobase+DT2811_ADCSR);*/ if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR) printk(KERN_ERR "error probing irq (bad)\n"); dev->irq = 0; if (irq > 0) { i = inb(dev->iobase + DT2811_ADDATLO); i = inb(dev->iobase + DT2811_ADDATHI); printk(KERN_INFO "(irq = %d)\n", irq); ret = request_irq(irq, dt2811_interrupt, 0, driver_name, dev); if (ret < 0) return -EIO; dev->irq = irq; } else if (irq == 0) { printk(KERN_INFO "(no irq)\n"); } else { printk(KERN_ERR "( multiple irq's -- this is bad! )\n"); } } #endif ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; ret = alloc_private(dev, sizeof(struct dt2811_private)); if (ret < 0) return ret; switch (it->options[2]) { case 0: devpriv->adc_mux = adc_singleended; break; case 1: devpriv->adc_mux = adc_diff; break; case 2: devpriv->adc_mux = adc_pseudo_diff; break; default: devpriv->adc_mux = adc_singleended; break; } switch (it->options[4]) { case 0: devpriv->dac_range[0] = dac_bipolar_5; break; case 1: devpriv->dac_range[0] = dac_bipolar_2_5; break; case 2: devpriv->dac_range[0] = dac_unipolar_5; break; default: devpriv->dac_range[0] = dac_bipolar_5; break; } switch (it->options[5]) { case 0: devpriv->dac_range[1] = dac_bipolar_5; break; case 1: devpriv->dac_range[1] = dac_bipolar_2_5; break; case 2: devpriv->dac_range[1] = dac_unipolar_5; break; default: devpriv->dac_range[1] = dac_bipolar_5; break; } s = &dev->subdevices[0]; /* initialize the ADC subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16; s->insn_read = dt2811_ai_insn; s->maxdata = 0xfff; switch (it->options[3]) { case 0: default: s->range_table = board->bip_5; break; case 1: s->range_table = board->bip_2_5; break; case 2: s->range_table = board->unip_5; break; } s = &dev->subdevices[1]; /* ao subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; s->insn_write = dt2811_ao_insn; s->insn_read = dt2811_ao_insn_read; s->maxdata = 0xfff; s->range_table_list = devpriv->range_type_list; devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]]; devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]]; s = &dev->subdevices[2]; /* di subdevice */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = 8; s->insn_bits = dt2811_di_insn_bits; s->maxdata = 1; s->range_table = &range_digital; s = &dev->subdevices[3]; /* do subdevice */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; s->n_chan = 8; s->insn_bits = dt2811_do_insn_bits; s->maxdata = 1; s->state = 0; s->range_table = &range_digital; return 0; }
static inline const struct dio200_layout * dio200_dev_layout(struct comedi_device *dev) { return dio200_board_layout(comedi_board(dev)); }