blob: 6931f1075089fb47c378f2715050aed741c6da3c [file] [log] [blame]
Calin Culianu6baef152009-02-19 09:13:10 -08001/*
2 comedi/drivers/pcmmio.c
3 Driver for Winsystems PC-104 based multifunction IO board.
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2007 Calin A. Culianu <calin@ajvar.org>
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/*
23Driver: pcmmio
24Description: A driver for the PCM-MIO multifunction board
25Devices: [Winsystems] PCM-MIO (pcmmio)
26Author: Calin Culianu <calin@ajvar.org>
27Updated: Wed, May 16 2007 16:21:10 -0500
28Status: works
29
30A driver for the relatively new PCM-MIO multifunction board from
31Winsystems. This board is a PC-104 based I/O board. It contains
32four subdevices:
33 subdevice 0 - 16 channels of 16-bit AI
34 subdevice 1 - 8 channels of 16-bit AO
35 subdevice 2 - first 24 channels of the 48 channel of DIO (with edge-triggered interrupt support)
36 subdevice 3 - last 24 channels of the 48 channel DIO (no interrupt support for this bank of channels)
37
38 Some notes:
39
40 Synchronous reads and writes are the only things implemented for AI and AO,
41 even though the hardware itself can do streaming acquisition, etc. Anyone
42 want to add asynchronous I/O for AI/AO as a feature? Be my guest...
43
44 Asynchronous I/O for the DIO subdevices *is* implemented, however! They are
45 basically edge-triggered interrupts for any configuration of the first
46 24 DIO-lines.
47
48 Also note that this interrupt support is untested.
49
50 A few words about edge-detection IRQ support (commands on DIO):
51
52 * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
53 of the board to the comedi_config command. The board IRQ is not jumpered
54 but rather configured through software, so any IRQ from 1-15 is OK.
55
56 * Due to the genericity of the comedi API, you need to create a special
57 comedi_command in order to use edge-triggered interrupts for DIO.
58
59 * Use comedi_commands with TRIG_NOW. Your callback will be called each
60 time an edge is detected on the specified DIO line(s), and the data
61 values will be two sample_t's, which should be concatenated to form
62 one 32-bit unsigned int. This value is the mask of channels that had
63 edges detected from your channel list. Note that the bits positions
64 in the mask correspond to positions in your chanlist when you
65 specified the command and *not* channel id's!
66
67 * To set the polarity of the edge-detection interrupts pass a nonzero value
68 for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
69 value for both CR_RANGE and CR_AREF if you want edge-down polarity.
70
71Configuration Options:
72 [0] - I/O port base address
73 [1] - IRQ (optional -- for edge-detect interrupt support only, leave out if you don't need this feature)
74*/
75
Greg Kroah-Hartman25436dc2009-04-27 15:14:34 -070076#include <linux/interrupt.h>
Calin Culianu6baef152009-02-19 09:13:10 -080077#include "../comedidev.h"
78#include <linux/pci.h> /* for PCI devices */
79
Bill Pemberton53106ae2009-04-09 16:07:21 -040080#define MIN(a, b) (((a) < (b)) ? (a) : (b))
Calin Culianu6baef152009-02-19 09:13:10 -080081
82/* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
83#define CHANS_PER_PORT 8
84#define PORTS_PER_ASIC 6
85#define INTR_PORTS_PER_ASIC 3
86#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */
87#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
88#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
89#define INTR_CHANS_PER_ASIC 24
90#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
91#define MAX_DIO_CHANS (PORTS_PER_ASIC*1*CHANS_PER_PORT)
92#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC)
93#define SDEV_NO ((int)(s - dev->subdevices))
94#define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
95/* IO Memory sizes */
96#define ASIC_IOSIZE (0x0B)
97#define PCMMIO48_IOSIZE ASIC_IOSIZE
98
99/* Some offsets - these are all in the 16byte IO memory offset from
100 the base address. Note that there is a paging scheme to swap out
101 offsets 0x8-0xA using the PAGELOCK register. See the table below.
102
103 Register(s) Pages R/W? Description
104 --------------------------------------------------------------
105 REG_PORTx All R/W Read/Write/Configure IO
106 REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int.
107 REG_PAGELOCK All WriteOnly Select a page
108 REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity
109 REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int.
110 REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints.
111 */
112#define REG_PORT0 0x0
113#define REG_PORT1 0x1
114#define REG_PORT2 0x2
115#define REG_PORT3 0x3
116#define REG_PORT4 0x4
117#define REG_PORT5 0x5
118#define REG_INT_PENDING 0x6
119#define REG_PAGELOCK 0x7 /* page selector register, upper 2 bits select a page
120 and bits 0-5 are used to 'lock down' a particular
121 port above to make it readonly. */
122#define REG_POL0 0x8
123#define REG_POL1 0x9
124#define REG_POL2 0xA
125#define REG_ENAB0 0x8
126#define REG_ENAB1 0x9
127#define REG_ENAB2 0xA
128#define REG_INT_ID0 0x8
129#define REG_INT_ID1 0x9
130#define REG_INT_ID2 0xA
131
132#define NUM_PAGED_REGS 3
133#define NUM_PAGES 4
134#define FIRST_PAGED_REG 0x8
135#define REG_PAGE_BITOFFSET 6
136#define REG_LOCK_BITOFFSET 0
137#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
138#define REG_LOCK_MASK ~(REG_PAGE_MASK)
139#define PAGE_POL 1
140#define PAGE_ENAB 2
141#define PAGE_INT_ID 3
142
Bill Pemberton34c43922009-03-16 22:05:14 -0400143typedef int (*comedi_insn_fn_t) (struct comedi_device *, struct comedi_subdevice *,
Bill Pemberton90035c02009-03-16 22:05:53 -0400144 struct comedi_insn *, unsigned int *);
Calin Culianu6baef152009-02-19 09:13:10 -0800145
Bill Pemberton90035c02009-03-16 22:05:53 -0400146static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *,
Bill Pemberton790c5542009-03-16 22:05:02 -0400147 unsigned int *);
Bill Pemberton90035c02009-03-16 22:05:53 -0400148static int ao_rinsn(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *,
Bill Pemberton790c5542009-03-16 22:05:02 -0400149 unsigned int *);
Bill Pemberton90035c02009-03-16 22:05:53 -0400150static int ao_winsn(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *,
Bill Pemberton790c5542009-03-16 22:05:02 -0400151 unsigned int *);
Calin Culianu6baef152009-02-19 09:13:10 -0800152
153/*
154 * Board descriptions for two imaginary boards. Describing the
155 * boards in this way is optional, and completely driver-dependent.
156 * Some drivers use arrays such as this, other do not.
157 */
Bill Pemberton657f81e2009-03-16 22:19:04 -0400158struct pcmmio_board {
Calin Culianu6baef152009-02-19 09:13:10 -0800159 const char *name;
160 const int dio_num_asics;
161 const int dio_num_ports;
162 const int total_iosize;
163 const int ai_bits;
164 const int ao_bits;
165 const int n_ai_chans;
166 const int n_ao_chans;
Bill Pemberton9ced1de2009-03-16 22:05:31 -0400167 const struct comedi_lrange *ai_range_table, *ao_range_table;
Calin Culianu6baef152009-02-19 09:13:10 -0800168 comedi_insn_fn_t ai_rinsn, ao_rinsn, ao_winsn;
Bill Pemberton657f81e2009-03-16 22:19:04 -0400169};
Calin Culianu6baef152009-02-19 09:13:10 -0800170
Bill Pemberton9ced1de2009-03-16 22:05:31 -0400171static const struct comedi_lrange ranges_ai =
Calin Culianu6baef152009-02-19 09:13:10 -0800172 { 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0.,
173 10.)}
174};
175
Bill Pemberton9ced1de2009-03-16 22:05:31 -0400176static const struct comedi_lrange ranges_ao =
Calin Culianu6baef152009-02-19 09:13:10 -0800177 { 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
178 RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
179};
180
Bill Pemberton657f81e2009-03-16 22:19:04 -0400181static const struct pcmmio_board pcmmio_boards[] = {
Calin Culianu6baef152009-02-19 09:13:10 -0800182 {
Bill Pemberton68c3dbf2009-04-22 21:11:49 -0400183 .name = "pcmmio",
184 .dio_num_asics = 1,
185 .dio_num_ports = 6,
186 .total_iosize = 32,
187 .ai_bits = 16,
188 .ao_bits = 16,
189 .n_ai_chans = 16,
190 .n_ao_chans = 8,
191 .ai_range_table = &ranges_ai,
192 .ao_range_table = &ranges_ao,
193 .ai_rinsn = ai_rinsn,
194 .ao_rinsn = ao_rinsn,
195 .ao_winsn = ao_winsn},
Calin Culianu6baef152009-02-19 09:13:10 -0800196};
197
198/*
199 * Useful for shorthand access to the particular board structure
200 */
Bill Pemberton657f81e2009-03-16 22:19:04 -0400201#define thisboard ((const struct pcmmio_board *)dev->board_ptr)
Calin Culianu6baef152009-02-19 09:13:10 -0800202
203/* this structure is for data unique to this subdevice. */
Bill Pemberton4467df92009-03-16 22:19:37 -0400204struct pcmmio_subdev_private {
Calin Culianu6baef152009-02-19 09:13:10 -0800205
206 union {
207 /* for DIO: mapping of halfwords (bytes) in port/chanarray to iobase */
208 unsigned long iobases[PORTS_PER_SUBDEV];
209
210 /* for AI/AO */
211 unsigned long iobase;
212 };
213 union {
214 struct {
215
216 /* The below is only used for intr subdevices */
217 struct {
218 int asic; /* if non-negative, this subdev has an interrupt asic */
219 int first_chan; /* if nonnegative, the first channel id for
220 interrupts. */
221 int num_asic_chans; /* the number of asic channels in this subdev
222 that have interrutps */
223 int asic_chan; /* if nonnegative, the first channel id with
224 respect to the asic that has interrupts */
225 int enabled_mask; /* subdev-relative channel mask for channels
226 we are interested in */
227 int active;
228 int stop_count;
229 int continuous;
230 spinlock_t spinlock;
231 } intr;
232 } dio;
233 struct {
Bill Pemberton790c5542009-03-16 22:05:02 -0400234 unsigned int shadow_samples[8]; /* the last unsigned int data written */
Calin Culianu6baef152009-02-19 09:13:10 -0800235 } ao;
236 };
Bill Pemberton4467df92009-03-16 22:19:37 -0400237};
Calin Culianu6baef152009-02-19 09:13:10 -0800238
239/* this structure is for data unique to this hardware driver. If
240 several hardware drivers keep similar information in this structure,
Bill Pemberton71b5f4f2009-03-16 22:05:08 -0400241 feel free to suggest moving the variable to the struct comedi_device struct. */
Bill Pembertone56ab712009-03-16 22:20:30 -0400242struct pcmmio_private {
Calin Culianu6baef152009-02-19 09:13:10 -0800243 /* stuff for DIO */
244 struct {
245 unsigned char pagelock; /* current page and lock */
246 unsigned char pol[NUM_PAGED_REGS]; /* shadow of POLx registers */
247 unsigned char enab[NUM_PAGED_REGS]; /* shadow of ENABx registers */
248 int num;
249 unsigned long iobase;
250 unsigned int irq;
251 spinlock_t spinlock;
252 } asics[MAX_ASICS];
Bill Pemberton4467df92009-03-16 22:19:37 -0400253 struct pcmmio_subdev_private *sprivs;
Bill Pembertone56ab712009-03-16 22:20:30 -0400254};
Calin Culianu6baef152009-02-19 09:13:10 -0800255
256/*
257 * most drivers define the following macro to make it easy to
258 * access the private structure.
259 */
Bill Pembertone56ab712009-03-16 22:20:30 -0400260#define devpriv ((struct pcmmio_private *)dev->private)
Bill Pemberton4467df92009-03-16 22:19:37 -0400261#define subpriv ((struct pcmmio_subdev_private *)s->private)
Calin Culianu6baef152009-02-19 09:13:10 -0800262/*
Bill Pemberton139dfbd2009-03-16 22:05:25 -0400263 * The struct comedi_driver structure tells the Comedi core module
Calin Culianu6baef152009-02-19 09:13:10 -0800264 * which functions to call to configure/deconfigure (attach/detach)
265 * the board, and also about the kernel module that contains
266 * the device code.
267 */
Bill Pembertonda91b262009-04-09 16:07:03 -0400268static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it);
269static int pcmmio_detach(struct comedi_device *dev);
Calin Culianu6baef152009-02-19 09:13:10 -0800270
Bill Pemberton139dfbd2009-03-16 22:05:25 -0400271static struct comedi_driver driver = {
Bill Pemberton68c3dbf2009-04-22 21:11:49 -0400272 .driver_name = "pcmmio",
273 .module = THIS_MODULE,
274 .attach = pcmmio_attach,
275 .detach = pcmmio_detach,
Calin Culianu6baef152009-02-19 09:13:10 -0800276/* It is not necessary to implement the following members if you are
277 * writing a driver for a ISA PnP or PCI card */
278 /* Most drivers will support multiple types of boards by
279 * having an array of board structures. These were defined
280 * in pcmmio_boards[] above. Note that the element 'name'
281 * was first in the structure -- Comedi uses this fact to
282 * extract the name of the board without knowing any details
283 * about the structure except for its length.
284 * When a device is attached (by comedi_config), the name
285 * of the device is given to Comedi, and Comedi tries to
286 * match it by going through the list of board names. If
287 * there is a match, the address of the pointer is put
288 * into dev->board_ptr and driver->attach() is called.
289 *
290 * Note that these are not necessary if you can determine
291 * the type of board in software. ISA PnP, PCI, and PCMCIA
292 * devices are such boards.
293 */
Bill Pemberton68c3dbf2009-04-22 21:11:49 -0400294 .board_name = &pcmmio_boards[0].name,
295 .offset = sizeof(struct pcmmio_board),
Bill Pemberton8629efa2009-04-23 15:54:56 -0400296 .num_names = ARRAY_SIZE(pcmmio_boards),
Calin Culianu6baef152009-02-19 09:13:10 -0800297};
298
Bill Pemberton814900c2009-04-23 15:54:54 -0400299static int pcmmio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
300 struct comedi_insn *insn, unsigned int *data);
301static int pcmmio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
302 struct comedi_insn *insn, unsigned int *data);
Calin Culianu6baef152009-02-19 09:13:10 -0800303
Jiri Slaby70265d22009-03-26 09:34:06 +0100304static irqreturn_t interrupt_pcmmio(int irq, void *d);
Bill Pemberton34c43922009-03-16 22:05:14 -0400305static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
Bill Pemberton814900c2009-04-23 15:54:54 -0400306static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
307static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
308static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
309 struct comedi_cmd *cmd);
Calin Culianu6baef152009-02-19 09:13:10 -0800310
311/* some helper functions to deal with specifics of this device's registers */
Bill Pemberton814900c2009-04-23 15:54:54 -0400312static void init_asics(struct comedi_device *dev); /* sets up/clears ASIC chips to defaults */
313static void switch_page(struct comedi_device *dev, int asic, int page);
Calin Culianu6baef152009-02-19 09:13:10 -0800314#ifdef notused
Bill Pemberton814900c2009-04-23 15:54:54 -0400315static void lock_port(struct comedi_device *dev, int asic, int port);
316static void unlock_port(struct comedi_device *dev, int asic, int port);
Calin Culianu6baef152009-02-19 09:13:10 -0800317#endif
318
319/*
320 * Attach is called by the Comedi core to configure the driver
321 * for a particular board. If you specified a board_name array
322 * in the driver structure, dev->board_ptr contains that
323 * address.
324 */
Bill Pembertonda91b262009-04-09 16:07:03 -0400325static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
Calin Culianu6baef152009-02-19 09:13:10 -0800326{
Bill Pemberton34c43922009-03-16 22:05:14 -0400327 struct comedi_subdevice *s;
Calin Culianu6baef152009-02-19 09:13:10 -0800328 int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
329 thisasic_chanct = 0;
330 unsigned long iobase;
331 unsigned int irq[MAX_ASICS];
332
333 iobase = it->options[0];
334 irq[0] = it->options[1];
335
336 printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name,
337 iobase);
338
339 dev->iobase = iobase;
340
341 if (!iobase || !request_region(iobase,
342 thisboard->total_iosize, driver.driver_name)) {
343 printk("I/O port conflict\n");
344 return -EIO;
345 }
346
347/*
348 * Initialize dev->board_name. Note that we can use the "thisboard"
349 * macro now, since we just initialized it in the last line.
350 */
351 dev->board_name = thisboard->name;
352
353/*
354 * Allocate the private structure area. alloc_private() is a
355 * convenient macro defined in comedidev.h.
356 */
Bill Pembertone56ab712009-03-16 22:20:30 -0400357 if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
Calin Culianu6baef152009-02-19 09:13:10 -0800358 printk("cannot allocate private data structure\n");
359 return -ENOMEM;
360 }
361
362 for (asic = 0; asic < MAX_ASICS; ++asic) {
363 devpriv->asics[asic].num = asic;
364 devpriv->asics[asic].iobase =
365 dev->iobase + 16 + asic * ASIC_IOSIZE;
366 devpriv->asics[asic].irq = 0; /* this gets actually set at the end of
367 this function when we
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700368 request_irqs */
Calin Culianu6baef152009-02-19 09:13:10 -0800369 spin_lock_init(&devpriv->asics[asic].spinlock);
370 }
371
372 chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
373 n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
374 n_subdevs = n_dio_subdevs + 2;
375 devpriv->sprivs =
Bill Pemberton4467df92009-03-16 22:19:37 -0400376 kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private), GFP_KERNEL);
Calin Culianu6baef152009-02-19 09:13:10 -0800377 if (!devpriv->sprivs) {
378 printk("cannot allocate subdevice private data structures\n");
379 return -ENOMEM;
380 }
381 /*
382 * Allocate the subdevice structures. alloc_subdevice() is a
383 * convenient macro defined in comedidev.h.
384 *
385 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
386 */
387 if (alloc_subdevices(dev, n_subdevs) < 0) {
388 printk("cannot allocate subdevice data structures\n");
389 return -ENOMEM;
390 }
391
392 /* First, AI */
393 sdev_no = 0;
394 s = dev->subdevices + sdev_no;
395 s->private = devpriv->sprivs + sdev_no;
396 s->maxdata = (1 << thisboard->ai_bits) - 1;
397 s->range_table = thisboard->ai_range_table;
398 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
399 s->type = COMEDI_SUBD_AI;
400 s->n_chan = thisboard->n_ai_chans;
401 s->len_chanlist = s->n_chan;
402 s->insn_read = thisboard->ai_rinsn;
403 subpriv->iobase = dev->iobase + 0;
404 /* initialize the resource enable register by clearing it */
405 outb(0, subpriv->iobase + 3);
406 outb(0, subpriv->iobase + 4 + 3);
407
408 /* Next, AO */
409 ++sdev_no;
410 s = dev->subdevices + sdev_no;
411 s->private = devpriv->sprivs + sdev_no;
412 s->maxdata = (1 << thisboard->ao_bits) - 1;
413 s->range_table = thisboard->ao_range_table;
414 s->subdev_flags = SDF_READABLE;
415 s->type = COMEDI_SUBD_AO;
416 s->n_chan = thisboard->n_ao_chans;
417 s->len_chanlist = s->n_chan;
418 s->insn_read = thisboard->ao_rinsn;
419 s->insn_write = thisboard->ao_winsn;
420 subpriv->iobase = dev->iobase + 8;
421 /* initialize the resource enable register by clearing it */
422 outb(0, subpriv->iobase + 3);
423 outb(0, subpriv->iobase + 4 + 3);
424
425 ++sdev_no;
426 port = 0;
427 asic = 0;
428 for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
429 int byte_no;
430
431 s = dev->subdevices + sdev_no;
432 s->private = devpriv->sprivs + sdev_no;
433 s->maxdata = 1;
434 s->range_table = &range_digital;
435 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
436 s->type = COMEDI_SUBD_DIO;
437 s->insn_bits = pcmmio_dio_insn_bits;
438 s->insn_config = pcmmio_dio_insn_config;
439 s->n_chan = MIN(chans_left, MAX_CHANS_PER_SUBDEV);
440 subpriv->dio.intr.asic = -1;
441 subpriv->dio.intr.first_chan = -1;
442 subpriv->dio.intr.asic_chan = -1;
443 subpriv->dio.intr.num_asic_chans = -1;
444 subpriv->dio.intr.active = 0;
445 s->len_chanlist = 1;
446
447 /* save the ioport address for each 'port' of 8 channels in the
448 subdevice */
449 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
450 if (port >= PORTS_PER_ASIC) {
451 port = 0;
452 ++asic;
453 thisasic_chanct = 0;
454 }
455 subpriv->iobases[byte_no] =
456 devpriv->asics[asic].iobase + port;
457
458 if (thisasic_chanct <
459 CHANS_PER_PORT * INTR_PORTS_PER_ASIC
460 && subpriv->dio.intr.asic < 0) {
461 /* this is an interrupt subdevice, so setup the struct */
462 subpriv->dio.intr.asic = asic;
463 subpriv->dio.intr.active = 0;
464 subpriv->dio.intr.stop_count = 0;
465 subpriv->dio.intr.first_chan = byte_no * 8;
466 subpriv->dio.intr.asic_chan = thisasic_chanct;
467 subpriv->dio.intr.num_asic_chans =
468 s->n_chan -
469 subpriv->dio.intr.first_chan;
470 s->cancel = pcmmio_cancel;
471 s->do_cmd = pcmmio_cmd;
472 s->do_cmdtest = pcmmio_cmdtest;
473 s->len_chanlist =
474 subpriv->dio.intr.num_asic_chans;
475 }
476 thisasic_chanct += CHANS_PER_PORT;
477 }
478 spin_lock_init(&subpriv->dio.intr.spinlock);
479
480 chans_left -= s->n_chan;
481
482 if (!chans_left) {
483 asic = 0; /* reset the asic to our first asic, to do intr subdevs */
484 port = 0;
485 }
486
487 }
488
489 init_asics(dev); /* clear out all the registers, basically */
490
491 for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
492 if (irq[asic]
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700493 && request_irq(irq[asic], interrupt_pcmmio,
Calin Culianu6baef152009-02-19 09:13:10 -0800494 IRQF_SHARED, thisboard->name, dev)) {
495 int i;
496 /* unroll the allocated irqs.. */
497 for (i = asic - 1; i >= 0; --i) {
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700498 free_irq(irq[i], dev);
Calin Culianu6baef152009-02-19 09:13:10 -0800499 devpriv->asics[i].irq = irq[i] = 0;
500 }
501 irq[asic] = 0;
502 }
503 devpriv->asics[asic].irq = irq[asic];
504 }
505
506 dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple
507 irqs.. */
508
509 if (irq[0]) {
510 printk("irq: %u ", irq[0]);
511 if (irq[1] && thisboard->dio_num_asics == 2)
512 printk("second ASIC irq: %u ", irq[1]);
513 } else {
514 printk("(IRQ mode disabled) ");
515 }
516
517 printk("attached\n");
518
519 return 1;
520}
521
522/*
523 * _detach is called to deconfigure a device. It should deallocate
524 * resources.
525 * This function is also called when _attach() fails, so it should be
526 * careful not to release resources that were not necessarily
527 * allocated by _attach(). dev->private and dev->subdevices are
528 * deallocated automatically by the core.
529 */
Bill Pembertonda91b262009-04-09 16:07:03 -0400530static int pcmmio_detach(struct comedi_device *dev)
Calin Culianu6baef152009-02-19 09:13:10 -0800531{
532 int i;
533
534 printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
535 if (dev->iobase)
536 release_region(dev->iobase, thisboard->total_iosize);
537
538 for (i = 0; i < MAX_ASICS; ++i) {
539 if (devpriv && devpriv->asics[i].irq)
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700540 free_irq(devpriv->asics[i].irq, dev);
Calin Culianu6baef152009-02-19 09:13:10 -0800541 }
542
543 if (devpriv && devpriv->sprivs)
544 kfree(devpriv->sprivs);
545
546 return 0;
547}
548
549/* DIO devices are slightly special. Although it is possible to
550 * implement the insn_read/insn_write interface, it is much more
551 * useful to applications if you implement the insn_bits interface.
552 * This allows packed reading/writing of the DIO channels. The
553 * comedi core can convert between insn_bits and insn_read/write */
Bill Pembertonda91b262009-04-09 16:07:03 -0400554static int pcmmio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
555 struct comedi_insn *insn, unsigned int *data)
Calin Culianu6baef152009-02-19 09:13:10 -0800556{
557 int byte_no;
558 if (insn->n != 2)
559 return -EINVAL;
560
561 /* NOTE:
562 reading a 0 means this channel was high
563 writine a 0 sets the channel high
564 reading a 1 means this channel was low
565 writing a 1 means set this channel low
566
567 Therefore everything is always inverted. */
568
569 /* The insn data is a mask in data[0] and the new data
570 * in data[1], each channel cooresponding to a bit. */
571
572#ifdef DAMMIT_ITS_BROKEN
573 /* DEBUG */
574 printk("write mask: %08x data: %08x\n", data[0], data[1]);
575#endif
576
577 s->state = 0;
578
579 for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
580 /* address of 8-bit port */
581 unsigned long ioaddr = subpriv->iobases[byte_no],
582 /* bit offset of port in 32-bit doubleword */
583 offset = byte_no * 8;
584 /* this 8-bit port's data */
585 unsigned char byte = 0,
586 /* The write mask for this port (if any) */
587 write_mask_byte = (data[0] >> offset) & 0xff,
588 /* The data byte for this port */
589 data_byte = (data[1] >> offset) & 0xff;
590
591 byte = inb(ioaddr); /* read all 8-bits for this port */
592
593#ifdef DAMMIT_ITS_BROKEN
594 /* DEBUG */
595 printk("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ", byte_no, (unsigned)write_mask_byte, (unsigned)data_byte, offset, ioaddr, (unsigned)byte);
596#endif
597
598 if (write_mask_byte) {
599 /* this byte has some write_bits -- so set the output lines */
600 byte &= ~write_mask_byte; /* clear bits for write mask */
601 byte |= ~data_byte & write_mask_byte; /* set to inverted data_byte */
602 /* Write out the new digital output state */
603 outb(byte, ioaddr);
604 }
605#ifdef DAMMIT_ITS_BROKEN
606 /* DEBUG */
607 printk("data_out_byte %02x\n", (unsigned)byte);
608#endif
609 /* save the digital input lines for this byte.. */
610 s->state |= ((unsigned int)byte) << offset;
611 }
612
613 /* now return the DIO lines to data[1] - note they came inverted! */
614 data[1] = ~s->state;
615
616#ifdef DAMMIT_ITS_BROKEN
617 /* DEBUG */
618 printk("s->state %08x data_out %08x\n", s->state, data[1]);
619#endif
620
621 return 2;
622}
623
624/* The input or output configuration of each digital line is
625 * configured by a special insn_config instruction. chanspec
626 * contains the channel to be changed, and data[0] contains the
627 * value COMEDI_INPUT or COMEDI_OUTPUT. */
Bill Pembertonda91b262009-04-09 16:07:03 -0400628static int pcmmio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
629 struct comedi_insn *insn, unsigned int *data)
Calin Culianu6baef152009-02-19 09:13:10 -0800630{
631 int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
632 chan % 8;
633 unsigned long ioaddr;
634 unsigned char byte;
635
636 /* Compute ioaddr for this channel */
637 ioaddr = subpriv->iobases[byte_no];
638
639 /* NOTE:
640 writing a 0 an IO channel's bit sets the channel to INPUT
641 and pulls the line high as well
642
643 writing a 1 to an IO channel's bit pulls the line low
644
645 All channels are implicitly always in OUTPUT mode -- but when
646 they are high they can be considered to be in INPUT mode..
647
648 Thus, we only force channels low if the config request was INPUT,
649 otherwise we do nothing to the hardware. */
650
651 switch (data[0]) {
652 case INSN_CONFIG_DIO_OUTPUT:
653 /* save to io_bits -- don't actually do anything since
654 all input channels are also output channels... */
655 s->io_bits |= 1 << chan;
656 break;
657 case INSN_CONFIG_DIO_INPUT:
658 /* write a 0 to the actual register representing the channel
659 to set it to 'input'. 0 means "float high". */
660 byte = inb(ioaddr);
661 byte &= ~(1 << bit_no);
662 /**< set input channel to '0' */
663
664 /* write out byte -- this is the only time we actually affect the
665 hardware as all channels are implicitly output -- but input
666 channels are set to float-high */
667 outb(byte, ioaddr);
668
669 /* save to io_bits */
670 s->io_bits &= ~(1 << chan);
671 break;
672
673 case INSN_CONFIG_DIO_QUERY:
674 /* retreive from shadow register */
675 data[1] =
676 (s->
677 io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
678 return insn->n;
679 break;
680
681 default:
682 return -EINVAL;
683 break;
684 }
685
686 return insn->n;
687}
688
Bill Pembertonda91b262009-04-09 16:07:03 -0400689static void init_asics(struct comedi_device *dev)
Calin Culianu6baef152009-02-19 09:13:10 -0800690{ /* sets up an
691 ASIC chip to defaults */
692 int asic;
693
694 for (asic = 0; asic < thisboard->dio_num_asics; ++asic) {
695 int port, page;
696 unsigned long baseaddr = devpriv->asics[asic].iobase;
697
698 switch_page(dev, asic, 0); /* switch back to page 0 */
699
700 /* first, clear all the DIO port bits */
701 for (port = 0; port < PORTS_PER_ASIC; ++port)
702 outb(0, baseaddr + REG_PORT0 + port);
703
704 /* Next, clear all the paged registers for each page */
705 for (page = 1; page < NUM_PAGES; ++page) {
706 int reg;
707 /* now clear all the paged registers */
708 switch_page(dev, asic, page);
709 for (reg = FIRST_PAGED_REG;
710 reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
711 outb(0, baseaddr + reg);
712 }
713
714 /* DEBUG set rising edge interrupts on port0 of both asics */
715 /*switch_page(dev, asic, PAGE_POL);
716 outb(0xff, baseaddr + REG_POL0);
717 switch_page(dev, asic, PAGE_ENAB);
718 outb(0xff, baseaddr + REG_ENAB0); */
719 /* END DEBUG */
720
721 switch_page(dev, asic, 0); /* switch back to default page 0 */
722
723 }
724}
725
Bill Pembertonda91b262009-04-09 16:07:03 -0400726static void switch_page(struct comedi_device *dev, int asic, int page)
Calin Culianu6baef152009-02-19 09:13:10 -0800727{
728 if (asic < 0 || asic >= thisboard->dio_num_asics)
729 return; /* paranoia */
730 if (page < 0 || page >= NUM_PAGES)
731 return; /* more paranoia */
732
733 devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
734 devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
735
736 /* now write out the shadow register */
737 outb(devpriv->asics[asic].pagelock,
738 devpriv->asics[asic].iobase + REG_PAGELOCK);
739}
740
741#ifdef notused
Bill Pembertonda91b262009-04-09 16:07:03 -0400742static void lock_port(struct comedi_device *dev, int asic, int port)
Calin Culianu6baef152009-02-19 09:13:10 -0800743{
744 if (asic < 0 || asic >= thisboard->dio_num_asics)
745 return; /* paranoia */
746 if (port < 0 || port >= PORTS_PER_ASIC)
747 return; /* more paranoia */
748
749 devpriv->asics[asic].pagelock |= 0x1 << port;
750 /* now write out the shadow register */
751 outb(devpriv->asics[asic].pagelock,
752 devpriv->asics[asic].iobase + REG_PAGELOCK);
753 return;
754}
755
Bill Pembertonda91b262009-04-09 16:07:03 -0400756static void unlock_port(struct comedi_device *dev, int asic, int port)
Calin Culianu6baef152009-02-19 09:13:10 -0800757{
758 if (asic < 0 || asic >= thisboard->dio_num_asics)
759 return; /* paranoia */
760 if (port < 0 || port >= PORTS_PER_ASIC)
761 return; /* more paranoia */
762 devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
763 /* now write out the shadow register */
764 outb(devpriv->asics[asic].pagelock,
765 devpriv->asics[asic].iobase + REG_PAGELOCK);
766}
767#endif /* notused */
768
Jiri Slaby70265d22009-03-26 09:34:06 +0100769static irqreturn_t interrupt_pcmmio(int irq, void *d)
Calin Culianu6baef152009-02-19 09:13:10 -0800770{
771 int asic, got1 = 0;
Bill Pemberton71b5f4f2009-03-16 22:05:08 -0400772 struct comedi_device *dev = (struct comedi_device *) d;
Calin Culianu6baef152009-02-19 09:13:10 -0800773
774 for (asic = 0; asic < MAX_ASICS; ++asic) {
775 if (irq == devpriv->asics[asic].irq) {
776 unsigned long flags;
777 unsigned triggered = 0;
778 unsigned long iobase = devpriv->asics[asic].iobase;
779 /* it is an interrupt for ASIC #asic */
780 unsigned char int_pend;
781
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700782 spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -0800783
784 int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
785
786 if (int_pend) {
787 int port;
788 for (port = 0; port < INTR_PORTS_PER_ASIC;
789 ++port) {
790 if (int_pend & (0x1 << port)) {
791 unsigned char
792 io_lines_with_edges = 0;
793 switch_page(dev, asic,
794 PAGE_INT_ID);
795 io_lines_with_edges =
796 inb(iobase +
797 REG_INT_ID0 + port);
798
799 if (io_lines_with_edges)
800 /* clear pending interrupt */
801 outb(0, iobase +
802 REG_INT_ID0 +
803 port);
804
805 triggered |=
806 io_lines_with_edges <<
807 port * 8;
808 }
809 }
810
811 ++got1;
812 }
813
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700814 spin_unlock_irqrestore(&devpriv->asics[asic]. spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -0800815
816 if (triggered) {
Bill Pemberton34c43922009-03-16 22:05:14 -0400817 struct comedi_subdevice *s;
Calin Culianu6baef152009-02-19 09:13:10 -0800818 /* TODO here: dispatch io lines to subdevs with commands.. */
819 printk("PCMMIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n", irq, asic, triggered);
820 for (s = dev->subdevices + 2;
821 s < dev->subdevices + dev->n_subdevices;
822 ++s) {
823 if (subpriv->dio.intr.asic == asic) { /* this is an interrupt subdev, and it matches this asic! */
824 unsigned long flags;
825 unsigned oldevents;
826
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700827 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -0800828
829 oldevents = s->async->events;
830
831 if (subpriv->dio.intr.active) {
832 unsigned mytrig =
833 ((triggered >>
834 subpriv->
835 dio.
836 intr.
837 asic_chan)
838 & ((0x1 << subpriv->dio.intr.num_asic_chans) - 1)) << subpriv->dio.intr.first_chan;
839 if (mytrig & subpriv->
840 dio.intr.
841 enabled_mask) {
Bill Pemberton790c5542009-03-16 22:05:02 -0400842 unsigned int val =
Calin Culianu6baef152009-02-19 09:13:10 -0800843 0;
844 unsigned int n,
845 ch, len;
846
847 len = s->async->
848 cmd.
849 chanlist_len;
850 for (n = 0;
851 n < len;
852 n++) {
853 ch = CR_CHAN(s->async->cmd.chanlist[n]);
854 if (mytrig & (1U << ch)) {
855 val |= (1U << n);
856 }
857 }
858 /* Write the scan to the buffer. */
Bill Pemberton9b9bcba2009-04-23 15:54:53 -0400859 if (comedi_buf_put(s->async, ((short *) &val)[0])
Calin Culianu6baef152009-02-19 09:13:10 -0800860 &&
861 comedi_buf_put
Bill Pemberton9b9bcba2009-04-23 15:54:53 -0400862 (s->async, ((short *) &val)[1])) {
Calin Culianu6baef152009-02-19 09:13:10 -0800863 s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
864 } else {
865 /* Overflow! Stop acquisition!! */
866 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
867 pcmmio_stop_intr
868 (dev,
869 s);
870 }
871
872 /* Check for end of acquisition. */
873 if (!subpriv->
874 dio.
875 intr.
876 continuous)
877 {
878 /* stop_src == TRIG_COUNT */
879 if (subpriv->dio.intr.stop_count > 0) {
880 subpriv->
881 dio.
882 intr.
883 stop_count--;
884 if (subpriv->dio.intr.stop_count == 0) {
885 s->async->events |= COMEDI_CB_EOA;
886 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
887 pcmmio_stop_intr
888 (dev,
889 s);
890 }
891 }
892 }
893 }
894 }
895
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700896 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -0800897
898 if (oldevents !=
899 s->async->events) {
900 comedi_event(dev, s);
901 }
902
903 }
904
905 }
906 }
907
908 }
909 }
910 if (!got1)
911 return IRQ_NONE; /* interrupt from other source */
912 return IRQ_HANDLED;
913}
914
Bill Pembertonda91b262009-04-09 16:07:03 -0400915static void pcmmio_stop_intr(struct comedi_device *dev, struct comedi_subdevice *s)
Calin Culianu6baef152009-02-19 09:13:10 -0800916{
917 int nports, firstport, asic, port;
918
Bill Pembertonc3744132009-04-22 21:11:47 -0400919 asic = subpriv->dio.intr.asic;
920 if (asic < 0)
Calin Culianu6baef152009-02-19 09:13:10 -0800921 return; /* not an interrupt subdev */
922
923 subpriv->dio.intr.enabled_mask = 0;
924 subpriv->dio.intr.active = 0;
925 s->async->inttrig = 0;
926 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
927 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
928 switch_page(dev, asic, PAGE_ENAB);
929 for (port = firstport; port < firstport + nports; ++port) {
930 /* disable all intrs for this subdev.. */
931 outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
932 }
933}
934
Bill Pembertonda91b262009-04-09 16:07:03 -0400935static int pcmmio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s)
Calin Culianu6baef152009-02-19 09:13:10 -0800936{
937 if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
938 /* An empty acquisition! */
939 s->async->events |= COMEDI_CB_EOA;
940 subpriv->dio.intr.active = 0;
941 return 1;
942 } else {
943 unsigned bits = 0, pol_bits = 0, n;
944 int nports, firstport, asic, port;
Bill Pembertonea6d0d42009-03-16 22:05:47 -0400945 struct comedi_cmd *cmd = &s->async->cmd;
Calin Culianu6baef152009-02-19 09:13:10 -0800946
Bill Pembertonc3744132009-04-22 21:11:47 -0400947 asic = subpriv->dio.intr.asic;
948 if (asic < 0)
Calin Culianu6baef152009-02-19 09:13:10 -0800949 return 1; /* not an interrupt
950 subdev */
951 subpriv->dio.intr.enabled_mask = 0;
952 subpriv->dio.intr.active = 1;
953 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
954 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
955 if (cmd->chanlist) {
956 for (n = 0; n < cmd->chanlist_len; n++) {
957 bits |= (1U << CR_CHAN(cmd->chanlist[n]));
958 pol_bits |= (CR_AREF(cmd->chanlist[n])
959 || CR_RANGE(cmd->chanlist[n]) ? 1U : 0U)
960 << CR_CHAN(cmd->chanlist[n]);
961 }
962 }
963 bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
964 1) << subpriv->dio.intr.first_chan;
965 subpriv->dio.intr.enabled_mask = bits;
966
967 { /* the below code configures the board to use a specific IRQ from 0-15. */
968 unsigned char b;
969 /* set resource enable register to enable IRQ operation */
970 outb(1 << 4, dev->iobase + 3);
971 /* set bits 0-3 of b to the irq number from 0-15 */
972 b = dev->irq & ((1 << 4) - 1);
973 outb(b, dev->iobase + 2);
974 /* done, we told the board what irq to use */
975 }
976
977 switch_page(dev, asic, PAGE_ENAB);
978 for (port = firstport; port < firstport + nports; ++port) {
979 unsigned enab =
980 bits >> (subpriv->dio.intr.first_chan + (port -
981 firstport) * 8) & 0xff, pol =
982 pol_bits >> (subpriv->dio.intr.first_chan +
983 (port - firstport) * 8) & 0xff;
984 /* set enab intrs for this subdev.. */
985 outb(enab,
986 devpriv->asics[asic].iobase + REG_ENAB0 + port);
987 switch_page(dev, asic, PAGE_POL);
988 outb(pol,
989 devpriv->asics[asic].iobase + REG_ENAB0 + port);
990 }
991 }
992 return 0;
993}
994
Bill Pembertonda91b262009-04-09 16:07:03 -0400995static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
Calin Culianu6baef152009-02-19 09:13:10 -0800996{
997 unsigned long flags;
998
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700999 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -08001000 if (subpriv->dio.intr.active)
1001 pcmmio_stop_intr(dev, s);
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001002 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -08001003
1004 return 0;
1005}
1006
1007/*
1008 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
1009 */
1010static int
Bill Pembertonda91b262009-04-09 16:07:03 -04001011pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
Calin Culianu6baef152009-02-19 09:13:10 -08001012 unsigned int trignum)
1013{
1014 unsigned long flags;
1015 int event = 0;
1016
1017 if (trignum != 0)
1018 return -EINVAL;
1019
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001020 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -08001021 s->async->inttrig = 0;
1022 if (subpriv->dio.intr.active) {
1023 event = pcmmio_start_intr(dev, s);
1024 }
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001025 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -08001026
1027 if (event) {
1028 comedi_event(dev, s);
1029 }
1030
1031 return 1;
1032}
1033
1034/*
1035 * 'do_cmd' function for an 'INTERRUPT' subdevice.
1036 */
Bill Pembertonda91b262009-04-09 16:07:03 -04001037static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
Calin Culianu6baef152009-02-19 09:13:10 -08001038{
Bill Pembertonea6d0d42009-03-16 22:05:47 -04001039 struct comedi_cmd *cmd = &s->async->cmd;
Calin Culianu6baef152009-02-19 09:13:10 -08001040 unsigned long flags;
1041 int event = 0;
1042
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001043 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -08001044 subpriv->dio.intr.active = 1;
1045
1046 /* Set up end of acquisition. */
1047 switch (cmd->stop_src) {
1048 case TRIG_COUNT:
1049 subpriv->dio.intr.continuous = 0;
1050 subpriv->dio.intr.stop_count = cmd->stop_arg;
1051 break;
1052 default:
1053 /* TRIG_NONE */
1054 subpriv->dio.intr.continuous = 1;
1055 subpriv->dio.intr.stop_count = 0;
1056 break;
1057 }
1058
1059 /* Set up start of acquisition. */
1060 switch (cmd->start_src) {
1061 case TRIG_INT:
1062 s->async->inttrig = pcmmio_inttrig_start_intr;
1063 break;
1064 default:
1065 /* TRIG_NOW */
1066 event = pcmmio_start_intr(dev, s);
1067 break;
1068 }
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001069 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -08001070
1071 if (event) {
1072 comedi_event(dev, s);
1073 }
1074
1075 return 0;
1076}
1077
1078/*
1079 * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
1080 */
1081static int
Bill Pembertonda91b262009-04-09 16:07:03 -04001082pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd)
Calin Culianu6baef152009-02-19 09:13:10 -08001083{
1084 int err = 0;
1085 unsigned int tmp;
1086
1087 /* step 1: make sure trigger sources are trivially valid */
1088
1089 tmp = cmd->start_src;
1090 cmd->start_src &= (TRIG_NOW | TRIG_INT);
1091 if (!cmd->start_src || tmp != cmd->start_src)
1092 err++;
1093
1094 tmp = cmd->scan_begin_src;
1095 cmd->scan_begin_src &= TRIG_EXT;
1096 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1097 err++;
1098
1099 tmp = cmd->convert_src;
1100 cmd->convert_src &= TRIG_NOW;
1101 if (!cmd->convert_src || tmp != cmd->convert_src)
1102 err++;
1103
1104 tmp = cmd->scan_end_src;
1105 cmd->scan_end_src &= TRIG_COUNT;
1106 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1107 err++;
1108
1109 tmp = cmd->stop_src;
1110 cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
1111 if (!cmd->stop_src || tmp != cmd->stop_src)
1112 err++;
1113
1114 if (err)
1115 return 1;
1116
1117 /* step 2: make sure trigger sources are unique and mutually compatible */
1118
1119 /* these tests are true if more than one _src bit is set */
1120 if ((cmd->start_src & (cmd->start_src - 1)) != 0)
1121 err++;
1122 if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
1123 err++;
1124 if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
1125 err++;
1126 if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
1127 err++;
1128 if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
1129 err++;
1130
1131 if (err)
1132 return 2;
1133
1134 /* step 3: make sure arguments are trivially compatible */
1135
1136 /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */
1137 if (cmd->start_arg != 0) {
1138 cmd->start_arg = 0;
1139 err++;
1140 }
1141
1142 /* cmd->scan_begin_src == TRIG_EXT */
1143 if (cmd->scan_begin_arg != 0) {
1144 cmd->scan_begin_arg = 0;
1145 err++;
1146 }
1147
1148 /* cmd->convert_src == TRIG_NOW */
1149 if (cmd->convert_arg != 0) {
1150 cmd->convert_arg = 0;
1151 err++;
1152 }
1153
1154 /* cmd->scan_end_src == TRIG_COUNT */
1155 if (cmd->scan_end_arg != cmd->chanlist_len) {
1156 cmd->scan_end_arg = cmd->chanlist_len;
1157 err++;
1158 }
1159
1160 switch (cmd->stop_src) {
1161 case TRIG_COUNT:
1162 /* any count allowed */
1163 break;
1164 case TRIG_NONE:
1165 if (cmd->stop_arg != 0) {
1166 cmd->stop_arg = 0;
1167 err++;
1168 }
1169 break;
1170 default:
1171 break;
1172 }
1173
1174 if (err)
1175 return 3;
1176
1177 /* step 4: fix up any arguments */
1178
1179 /* if (err) return 4; */
1180
1181 return 0;
1182}
1183
1184static int adc_wait_ready(unsigned long iobase)
1185{
1186 unsigned long retry = 100000;
1187 while (retry--)
1188 if (inb(iobase + 3) & 0x80)
1189 return 0;
1190 return 1;
1191}
1192
1193/* All this is for AI and AO */
Bill Pembertonda91b262009-04-09 16:07:03 -04001194static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1195 struct comedi_insn *insn, unsigned int *data)
Calin Culianu6baef152009-02-19 09:13:10 -08001196{
1197 int n;
1198 unsigned long iobase = subpriv->iobase;
1199
1200 /*
1201 1. write the CMD byte (to BASE+2)
1202 2. read junk lo byte (BASE+0)
1203 3. read junk hi byte (BASE+1)
1204 4. (mux settled so) write CMD byte again (BASE+2)
1205 5. read valid lo byte(BASE+0)
1206 6. read valid hi byte(BASE+1)
1207
1208 Additionally note that the BASE += 4 if the channel >= 8
1209 */
1210
1211 /* convert n samples */
1212 for (n = 0; n < insn->n; n++) {
1213 unsigned chan = CR_CHAN(insn->chanspec), range =
1214 CR_RANGE(insn->chanspec), aref =
1215 CR_AREF(insn->chanspec);
1216 unsigned char command_byte = 0;
1217 unsigned iooffset = 0;
Bill Pemberton790c5542009-03-16 22:05:02 -04001218 short sample, adc_adjust = 0;
Calin Culianu6baef152009-02-19 09:13:10 -08001219
1220 if (chan > 7)
1221 chan -= 8, iooffset = 4; /* use the second dword for channels > 7 */
1222
1223 if (aref != AREF_DIFF) {
1224 aref = AREF_GROUND;
1225 command_byte |= 1 << 7; /* set bit 7 to indicate single-ended */
1226 }
1227 if (range < 2)
1228 adc_adjust = 0x8000; /* bipolar ranges (-5,5 .. -10,10 need to be adjusted -- that is.. they need to wrap around by adding 0x8000 */
1229
1230 if (chan % 2) {
1231 command_byte |= 1 << 6; /* odd-numbered channels have bit 6 set */
1232 }
1233
1234 /* select the channel, bits 4-5 == chan/2 */
1235 command_byte |= ((chan / 2) & 0x3) << 4;
1236
1237 /* set the range, bits 2-3 */
1238 command_byte |= (range & 0x3) << 2;
1239
1240 /* need to do this twice to make sure mux settled */
1241 outb(command_byte, iobase + iooffset + 2); /* chan/range/aref select */
1242
1243 adc_wait_ready(iobase + iooffset); /* wait for the adc to say it finised the conversion */
1244
1245 outb(command_byte, iobase + iooffset + 2); /* select the chan/range/aref AGAIN */
1246
1247 adc_wait_ready(iobase + iooffset);
1248
1249 sample = inb(iobase + iooffset + 0); /* read data lo byte */
1250 sample |= inb(iobase + iooffset + 1) << 8; /* read data hi byte */
1251 sample += adc_adjust; /* adjustment .. munge data */
1252 data[n] = sample;
1253 }
1254 /* return the number of samples read/written */
1255 return n;
1256}
1257
Bill Pembertonda91b262009-04-09 16:07:03 -04001258static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1259 struct comedi_insn *insn, unsigned int *data)
Calin Culianu6baef152009-02-19 09:13:10 -08001260{
1261 int n;
1262 for (n = 0; n < insn->n; n++) {
1263 unsigned chan = CR_CHAN(insn->chanspec);
1264 if (chan < s->n_chan)
1265 data[n] = subpriv->ao.shadow_samples[chan];
1266 }
1267 return n;
1268}
1269
1270static int wait_dac_ready(unsigned long iobase)
1271{
1272 unsigned long retry = 100000L;
1273
1274 /* This may seem like an absurd way to handle waiting and violates the
1275 "no busy waiting" policy. The fact is that the hardware is
1276 normally so fast that we usually only need one time through the loop
1277 anyway. The longer timeout is for rare occasions and for detecting
1278 non-existant hardware. */
1279
1280 while (retry--) {
1281 if (inb(iobase + 3) & 0x80)
1282 return 0;
1283
1284 }
1285 return 1;
1286}
1287
Bill Pembertonda91b262009-04-09 16:07:03 -04001288static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
1289 struct comedi_insn *insn, unsigned int *data)
Calin Culianu6baef152009-02-19 09:13:10 -08001290{
1291 int n;
1292 unsigned iobase = subpriv->iobase, iooffset = 0;
1293
1294 for (n = 0; n < insn->n; n++) {
1295 unsigned chan = CR_CHAN(insn->chanspec), range =
1296 CR_RANGE(insn->chanspec);
1297 if (chan < s->n_chan) {
1298 unsigned char command_byte = 0, range_byte =
1299 range & ((1 << 4) - 1);
1300 if (chan >= 4)
1301 chan -= 4, iooffset += 4;
1302 /* set the range.. */
1303 outb(range_byte, iobase + iooffset + 0);
1304 outb(0, iobase + iooffset + 1);
1305
1306 /* tell it to begin */
1307 command_byte = (chan << 1) | 0x60;
1308 outb(command_byte, iobase + iooffset + 2);
1309
1310 wait_dac_ready(iobase + iooffset);
1311
1312 outb(data[n] & 0xff, iobase + iooffset + 0); /* low order byte */
1313 outb((data[n] >> 8) & 0xff, iobase + iooffset + 1); /* high order byte */
1314 command_byte = 0x70 | (chan << 1); /* set bit 4 of command byte to indicate data is loaded and trigger conversion */
1315 /* trigger converion */
1316 outb(command_byte, iobase + iooffset + 2);
1317
1318 wait_dac_ready(iobase + iooffset);
1319
1320 subpriv->ao.shadow_samples[chan] = data[n]; /* save to shadow register for ao_rinsn */
1321 }
1322 }
1323 return n;
1324}
1325
1326/*
1327 * A convenient macro that defines init_module() and cleanup_module(),
1328 * as necessary.
1329 */
1330COMEDI_INITCLEANUP(driver);