Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pcmad.c
Go to the documentation of this file.
1 /*
2  comedi/drivers/pcmad.c
3  Hardware driver for Winsystems PCM-A/D12 and PCM-A/D16
4 
5  COMEDI - Linux Control and Measurement Device Interface
6  Copyright (C) 2000,2001 David A. Schleef <[email protected]>
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22 */
23 /*
24 Driver: pcmad
25 Description: Winsystems PCM-A/D12, PCM-A/D16
26 Author: ds
27 Devices: [Winsystems] PCM-A/D12 (pcmad12), PCM-A/D16 (pcmad16)
28 Status: untested
29 
30 This driver was written on a bet that I couldn't write a driver
31 in less than 2 hours. I won the bet, but never got paid. =(
32 
33 Configuration options:
34  [0] - I/O port base
35  [1] - unused
36  [2] - Analog input reference
37  0 = single ended
38  1 = differential
39  [3] - Analog input encoding (must match jumpers)
40  0 = straight binary
41  1 = two's complement
42 */
43 
44 #include <linux/interrupt.h>
45 #include "../comedidev.h"
46 
47 #include <linux/ioport.h>
48 
49 #define PCMAD_SIZE 4
50 
51 #define PCMAD_STATUS 0
52 #define PCMAD_LSB 1
53 #define PCMAD_MSB 2
54 #define PCMAD_CONVERT 1
55 
57  const char *name;
58  int n_ai_bits;
59 };
60 
63  int twos_comp;
64 };
65 #define devpriv ((struct pcmad_priv_struct *)dev->private)
66 
67 #define TIMEOUT 100
68 
69 static int pcmad_ai_insn_read(struct comedi_device *dev,
70  struct comedi_subdevice *s,
71  struct comedi_insn *insn, unsigned int *data)
72 {
73  const struct pcmad_board_struct *board = comedi_board(dev);
74  int i;
75  int chan;
76  int n;
77 
78  chan = CR_CHAN(insn->chanspec);
79 
80  for (n = 0; n < insn->n; n++) {
81  outb(chan, dev->iobase + PCMAD_CONVERT);
82 
83  for (i = 0; i < TIMEOUT; i++) {
84  if ((inb(dev->iobase + PCMAD_STATUS) & 0x3) == 0x3)
85  break;
86  }
87  data[n] = inb(dev->iobase + PCMAD_LSB);
88  data[n] |= (inb(dev->iobase + PCMAD_MSB) << 8);
89 
90  if (devpriv->twos_comp)
91  data[n] ^= (1 << (board->n_ai_bits - 1));
92  }
93 
94  return n;
95 }
96 
97 /*
98  * options:
99  * 0 i/o base
100  * 1 unused
101  * 2 0=single ended 1=differential
102  * 3 0=straight binary 1=two's comp
103  */
104 static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it)
105 {
106  const struct pcmad_board_struct *board = comedi_board(dev);
107  int ret;
108  struct comedi_subdevice *s;
109  unsigned long iobase;
110 
111  iobase = it->options[0];
112  printk(KERN_INFO "comedi%d: pcmad: 0x%04lx ", dev->minor, iobase);
113  if (!request_region(iobase, PCMAD_SIZE, "pcmad")) {
114  printk(KERN_CONT "I/O port conflict\n");
115  return -EIO;
116  }
117  printk(KERN_CONT "\n");
118  dev->iobase = iobase;
119 
120  ret = comedi_alloc_subdevices(dev, 1);
121  if (ret)
122  return ret;
123 
124  ret = alloc_private(dev, sizeof(struct pcmad_priv_struct));
125  if (ret < 0)
126  return ret;
127 
128  dev->board_name = board->name;
129 
130  s = &dev->subdevices[0];
131  s->type = COMEDI_SUBD_AI;
133  s->n_chan = 16; /* XXX */
134  s->len_chanlist = 1;
135  s->insn_read = pcmad_ai_insn_read;
136  s->maxdata = (1 << board->n_ai_bits) - 1;
138 
139  return 0;
140 }
141 
142 static void pcmad_detach(struct comedi_device *dev)
143 {
144  if (dev->irq)
145  free_irq(dev->irq, dev);
146  if (dev->iobase)
148 }
149 
150 static const struct pcmad_board_struct pcmad_boards[] = {
151  {
152  .name = "pcmad12",
153  .n_ai_bits = 12,
154  }, {
155  .name = "pcmad16",
156  .n_ai_bits = 16,
157  },
158 };
159 static struct comedi_driver pcmad_driver = {
160  .driver_name = "pcmad",
161  .module = THIS_MODULE,
162  .attach = pcmad_attach,
163  .detach = pcmad_detach,
164  .board_name = &pcmad_boards[0].name,
165  .num_names = ARRAY_SIZE(pcmad_boards),
166  .offset = sizeof(pcmad_boards[0]),
167 };
168 module_comedi_driver(pcmad_driver);
169 
170 MODULE_AUTHOR("Comedi http://www.comedi.org");
171 MODULE_DESCRIPTION("Comedi low-level driver");
172 MODULE_LICENSE("GPL");