root/drivers/staging/comedi/drivers/pcmad.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pcmad_ai_eoc
  2. pcmad_ai_insn_read
  3. pcmad_attach

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * pcmad.c
   4  * Hardware driver for Winsystems PCM-A/D12 and PCM-A/D16
   5  *
   6  * COMEDI - Linux Control and Measurement Device Interface
   7  * Copyright (C) 2000,2001 David A. Schleef <ds@schleef.org>
   8  */
   9 
  10 /*
  11  * Driver: pcmad
  12  * Description: Winsystems PCM-A/D12, PCM-A/D16
  13  * Devices: [Winsystems] PCM-A/D12 (pcmad12), PCM-A/D16 (pcmad16)
  14  * Author: ds
  15  * Status: untested
  16  *
  17  * This driver was written on a bet that I couldn't write a driver
  18  * in less than 2 hours.  I won the bet, but never got paid.  =(
  19  *
  20  * Configuration options:
  21  *   [0] - I/O port base
  22  *   [1] - IRQ (unused)
  23  *   [2] - Analog input reference (must match jumpers)
  24  *         0 = single-ended (16 channels)
  25  *         1 = differential (8 channels)
  26  *   [3] - Analog input encoding (must match jumpers)
  27  *         0 = straight binary (0-5V input range)
  28  *         1 = two's complement (+-10V input range)
  29  */
  30 
  31 #include <linux/module.h>
  32 #include "../comedidev.h"
  33 
  34 #define PCMAD_STATUS            0
  35 #define PCMAD_LSB               1
  36 #define PCMAD_MSB               2
  37 #define PCMAD_CONVERT           1
  38 
  39 struct pcmad_board_struct {
  40         const char *name;
  41         unsigned int ai_maxdata;
  42 };
  43 
  44 static const struct pcmad_board_struct pcmad_boards[] = {
  45         {
  46                 .name           = "pcmad12",
  47                 .ai_maxdata     = 0x0fff,
  48         }, {
  49                 .name           = "pcmad16",
  50                 .ai_maxdata     = 0xffff,
  51         },
  52 };
  53 
  54 static int pcmad_ai_eoc(struct comedi_device *dev,
  55                         struct comedi_subdevice *s,
  56                         struct comedi_insn *insn,
  57                         unsigned long context)
  58 {
  59         unsigned int status;
  60 
  61         status = inb(dev->iobase + PCMAD_STATUS);
  62         if ((status & 0x3) == 0x3)
  63                 return 0;
  64         return -EBUSY;
  65 }
  66 
  67 static int pcmad_ai_insn_read(struct comedi_device *dev,
  68                               struct comedi_subdevice *s,
  69                               struct comedi_insn *insn,
  70                               unsigned int *data)
  71 {
  72         unsigned int chan = CR_CHAN(insn->chanspec);
  73         unsigned int range = CR_RANGE(insn->chanspec);
  74         unsigned int val;
  75         int ret;
  76         int i;
  77 
  78         for (i = 0; i < insn->n; i++) {
  79                 outb(chan, dev->iobase + PCMAD_CONVERT);
  80 
  81                 ret = comedi_timeout(dev, s, insn, pcmad_ai_eoc, 0);
  82                 if (ret)
  83                         return ret;
  84 
  85                 val = inb(dev->iobase + PCMAD_LSB) |
  86                       (inb(dev->iobase + PCMAD_MSB) << 8);
  87 
  88                 /* data is shifted on the pcmad12, fix it */
  89                 if (s->maxdata == 0x0fff)
  90                         val >>= 4;
  91 
  92                 if (comedi_range_is_bipolar(s, range)) {
  93                         /* munge the two's complement value */
  94                         val ^= ((s->maxdata + 1) >> 1);
  95                 }
  96 
  97                 data[i] = val;
  98         }
  99 
 100         return insn->n;
 101 }
 102 
 103 static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 104 {
 105         const struct pcmad_board_struct *board = dev->board_ptr;
 106         struct comedi_subdevice *s;
 107         int ret;
 108 
 109         ret = comedi_request_region(dev, it->options[0], 0x04);
 110         if (ret)
 111                 return ret;
 112 
 113         ret = comedi_alloc_subdevices(dev, 1);
 114         if (ret)
 115                 return ret;
 116 
 117         s = &dev->subdevices[0];
 118         s->type         = COMEDI_SUBD_AI;
 119         if (it->options[1]) {
 120                 /* 8 differential channels */
 121                 s->subdev_flags = SDF_READABLE | AREF_DIFF;
 122                 s->n_chan       = 8;
 123         } else {
 124                 /* 16 single-ended channels */
 125                 s->subdev_flags = SDF_READABLE | AREF_GROUND;
 126                 s->n_chan       = 16;
 127         }
 128         s->len_chanlist = 1;
 129         s->maxdata      = board->ai_maxdata;
 130         s->range_table  = it->options[2] ? &range_bipolar10 : &range_unipolar5;
 131         s->insn_read    = pcmad_ai_insn_read;
 132 
 133         return 0;
 134 }
 135 
 136 static struct comedi_driver pcmad_driver = {
 137         .driver_name    = "pcmad",
 138         .module         = THIS_MODULE,
 139         .attach         = pcmad_attach,
 140         .detach         = comedi_legacy_detach,
 141         .board_name     = &pcmad_boards[0].name,
 142         .num_names      = ARRAY_SIZE(pcmad_boards),
 143         .offset         = sizeof(pcmad_boards[0]),
 144 };
 145 module_comedi_driver(pcmad_driver);
 146 
 147 MODULE_AUTHOR("Comedi http://www.comedi.org");
 148 MODULE_DESCRIPTION("Comedi low-level driver");
 149 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */