blob: e1ad03e234b784c4d8f83f4f53c92c1bdaa4f453 [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
Calin Culianu6baef152009-02-19 09:13:10 -080080/* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
81#define CHANS_PER_PORT 8
82#define PORTS_PER_ASIC 6
83#define INTR_PORTS_PER_ASIC 3
84#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */
85#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
86#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
87#define INTR_CHANS_PER_ASIC 24
88#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
89#define MAX_DIO_CHANS (PORTS_PER_ASIC*1*CHANS_PER_PORT)
90#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC)
91#define SDEV_NO ((int)(s - dev->subdevices))
92#define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
93/* IO Memory sizes */
94#define ASIC_IOSIZE (0x0B)
95#define PCMMIO48_IOSIZE ASIC_IOSIZE
96
97/* Some offsets - these are all in the 16byte IO memory offset from
98 the base address. Note that there is a paging scheme to swap out
99 offsets 0x8-0xA using the PAGELOCK register. See the table below.
100
101 Register(s) Pages R/W? Description
102 --------------------------------------------------------------
103 REG_PORTx All R/W Read/Write/Configure IO
104 REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int.
105 REG_PAGELOCK All WriteOnly Select a page
106 REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity
107 REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int.
108 REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints.
109 */
110#define REG_PORT0 0x0
111#define REG_PORT1 0x1
112#define REG_PORT2 0x2
113#define REG_PORT3 0x3
114#define REG_PORT4 0x4
115#define REG_PORT5 0x5
116#define REG_INT_PENDING 0x6
117#define REG_PAGELOCK 0x7 /* page selector register, upper 2 bits select a page
118 and bits 0-5 are used to 'lock down' a particular
119 port above to make it readonly. */
120#define REG_POL0 0x8
121#define REG_POL1 0x9
122#define REG_POL2 0xA
123#define REG_ENAB0 0x8
124#define REG_ENAB1 0x9
125#define REG_ENAB2 0xA
126#define REG_INT_ID0 0x8
127#define REG_INT_ID1 0x9
128#define REG_INT_ID2 0xA
129
130#define NUM_PAGED_REGS 3
131#define NUM_PAGES 4
132#define FIRST_PAGED_REG 0x8
133#define REG_PAGE_BITOFFSET 6
134#define REG_LOCK_BITOFFSET 0
135#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
136#define REG_LOCK_MASK ~(REG_PAGE_MASK)
137#define PAGE_POL 1
138#define PAGE_ENAB 2
139#define PAGE_INT_ID 3
140
Bill Pemberton34c43922009-03-16 22:05:14 -0400141typedef int (*comedi_insn_fn_t) (struct comedi_device *, struct comedi_subdevice *,
Bill Pemberton90035c02009-03-16 22:05:53 -0400142 struct comedi_insn *, unsigned int *);
Calin Culianu6baef152009-02-19 09:13:10 -0800143
Bill Pemberton90035c02009-03-16 22:05:53 -0400144static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *,
Bill Pemberton790c5542009-03-16 22:05:02 -0400145 unsigned int *);
Bill Pemberton90035c02009-03-16 22:05:53 -0400146static int ao_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_winsn(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *,
Bill Pemberton790c5542009-03-16 22:05:02 -0400149 unsigned int *);
Calin Culianu6baef152009-02-19 09:13:10 -0800150
151/*
152 * Board descriptions for two imaginary boards. Describing the
153 * boards in this way is optional, and completely driver-dependent.
154 * Some drivers use arrays such as this, other do not.
155 */
Bill Pemberton657f81e2009-03-16 22:19:04 -0400156struct pcmmio_board {
Calin Culianu6baef152009-02-19 09:13:10 -0800157 const char *name;
158 const int dio_num_asics;
159 const int dio_num_ports;
160 const int total_iosize;
161 const int ai_bits;
162 const int ao_bits;
163 const int n_ai_chans;
164 const int n_ao_chans;
Bill Pemberton9ced1de2009-03-16 22:05:31 -0400165 const struct comedi_lrange *ai_range_table, *ao_range_table;
Calin Culianu6baef152009-02-19 09:13:10 -0800166 comedi_insn_fn_t ai_rinsn, ao_rinsn, ao_winsn;
Bill Pemberton657f81e2009-03-16 22:19:04 -0400167};
Calin Culianu6baef152009-02-19 09:13:10 -0800168
Bill Pemberton9ced1de2009-03-16 22:05:31 -0400169static const struct comedi_lrange ranges_ai =
Calin Culianu6baef152009-02-19 09:13:10 -0800170 { 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0.,
171 10.)}
172};
173
Bill Pemberton9ced1de2009-03-16 22:05:31 -0400174static const struct comedi_lrange ranges_ao =
Calin Culianu6baef152009-02-19 09:13:10 -0800175 { 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
176 RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
177};
178
Bill Pemberton657f81e2009-03-16 22:19:04 -0400179static const struct pcmmio_board pcmmio_boards[] = {
Calin Culianu6baef152009-02-19 09:13:10 -0800180 {
Bill Pemberton68c3dbf2009-04-22 21:11:49 -0400181 .name = "pcmmio",
182 .dio_num_asics = 1,
183 .dio_num_ports = 6,
184 .total_iosize = 32,
185 .ai_bits = 16,
186 .ao_bits = 16,
187 .n_ai_chans = 16,
188 .n_ao_chans = 8,
189 .ai_range_table = &ranges_ai,
190 .ao_range_table = &ranges_ao,
191 .ai_rinsn = ai_rinsn,
192 .ao_rinsn = ao_rinsn,
193 .ao_winsn = ao_winsn},
Calin Culianu6baef152009-02-19 09:13:10 -0800194};
195
196/*
197 * Useful for shorthand access to the particular board structure
198 */
Bill Pemberton657f81e2009-03-16 22:19:04 -0400199#define thisboard ((const struct pcmmio_board *)dev->board_ptr)
Calin Culianu6baef152009-02-19 09:13:10 -0800200
201/* this structure is for data unique to this subdevice. */
Bill Pemberton4467df92009-03-16 22:19:37 -0400202struct pcmmio_subdev_private {
Calin Culianu6baef152009-02-19 09:13:10 -0800203
204 union {
205 /* for DIO: mapping of halfwords (bytes) in port/chanarray to iobase */
206 unsigned long iobases[PORTS_PER_SUBDEV];
207
208 /* for AI/AO */
209 unsigned long iobase;
210 };
211 union {
212 struct {
213
214 /* The below is only used for intr subdevices */
215 struct {
216 int asic; /* if non-negative, this subdev has an interrupt asic */
217 int first_chan; /* if nonnegative, the first channel id for
218 interrupts. */
219 int num_asic_chans; /* the number of asic channels in this subdev
220 that have interrutps */
221 int asic_chan; /* if nonnegative, the first channel id with
222 respect to the asic that has interrupts */
223 int enabled_mask; /* subdev-relative channel mask for channels
224 we are interested in */
225 int active;
226 int stop_count;
227 int continuous;
228 spinlock_t spinlock;
229 } intr;
230 } dio;
231 struct {
Bill Pemberton790c5542009-03-16 22:05:02 -0400232 unsigned int shadow_samples[8]; /* the last unsigned int data written */
Calin Culianu6baef152009-02-19 09:13:10 -0800233 } ao;
234 };
Bill Pemberton4467df92009-03-16 22:19:37 -0400235};
Calin Culianu6baef152009-02-19 09:13:10 -0800236
237/* this structure is for data unique to this hardware driver. If
238 several hardware drivers keep similar information in this structure,
Bill Pemberton71b5f4f2009-03-16 22:05:08 -0400239 feel free to suggest moving the variable to the struct comedi_device struct. */
Bill Pembertone56ab712009-03-16 22:20:30 -0400240struct pcmmio_private {
Calin Culianu6baef152009-02-19 09:13:10 -0800241 /* stuff for DIO */
242 struct {
243 unsigned char pagelock; /* current page and lock */
244 unsigned char pol[NUM_PAGED_REGS]; /* shadow of POLx registers */
245 unsigned char enab[NUM_PAGED_REGS]; /* shadow of ENABx registers */
246 int num;
247 unsigned long iobase;
248 unsigned int irq;
249 spinlock_t spinlock;
250 } asics[MAX_ASICS];
Bill Pemberton4467df92009-03-16 22:19:37 -0400251 struct pcmmio_subdev_private *sprivs;
Bill Pembertone56ab712009-03-16 22:20:30 -0400252};
Calin Culianu6baef152009-02-19 09:13:10 -0800253
254/*
255 * most drivers define the following macro to make it easy to
256 * access the private structure.
257 */
Bill Pembertone56ab712009-03-16 22:20:30 -0400258#define devpriv ((struct pcmmio_private *)dev->private)
Bill Pemberton4467df92009-03-16 22:19:37 -0400259#define subpriv ((struct pcmmio_subdev_private *)s->private)
Calin Culianu6baef152009-02-19 09:13:10 -0800260/*
Bill Pemberton139dfbd2009-03-16 22:05:25 -0400261 * The struct comedi_driver structure tells the Comedi core module
Calin Culianu6baef152009-02-19 09:13:10 -0800262 * which functions to call to configure/deconfigure (attach/detach)
263 * the board, and also about the kernel module that contains
264 * the device code.
265 */
Bill Pembertonda91b262009-04-09 16:07:03 -0400266static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it);
267static int pcmmio_detach(struct comedi_device *dev);
Calin Culianu6baef152009-02-19 09:13:10 -0800268
Bill Pemberton139dfbd2009-03-16 22:05:25 -0400269static struct comedi_driver driver = {
Bill Pemberton68c3dbf2009-04-22 21:11:49 -0400270 .driver_name = "pcmmio",
271 .module = THIS_MODULE,
272 .attach = pcmmio_attach,
273 .detach = pcmmio_detach,
Calin Culianu6baef152009-02-19 09:13:10 -0800274/* It is not necessary to implement the following members if you are
275 * writing a driver for a ISA PnP or PCI card */
276 /* Most drivers will support multiple types of boards by
277 * having an array of board structures. These were defined
278 * in pcmmio_boards[] above. Note that the element 'name'
279 * was first in the structure -- Comedi uses this fact to
280 * extract the name of the board without knowing any details
281 * about the structure except for its length.
282 * When a device is attached (by comedi_config), the name
283 * of the device is given to Comedi, and Comedi tries to
284 * match it by going through the list of board names. If
285 * there is a match, the address of the pointer is put
286 * into dev->board_ptr and driver->attach() is called.
287 *
288 * Note that these are not necessary if you can determine
289 * the type of board in software. ISA PnP, PCI, and PCMCIA
290 * devices are such boards.
291 */
Bill Pemberton68c3dbf2009-04-22 21:11:49 -0400292 .board_name = &pcmmio_boards[0].name,
293 .offset = sizeof(struct pcmmio_board),
Bill Pemberton8629efa2009-04-23 15:54:56 -0400294 .num_names = ARRAY_SIZE(pcmmio_boards),
Calin Culianu6baef152009-02-19 09:13:10 -0800295};
296
Bill Pemberton814900c2009-04-23 15:54:54 -0400297static int pcmmio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
298 struct comedi_insn *insn, unsigned int *data);
299static int pcmmio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
300 struct comedi_insn *insn, unsigned int *data);
Calin Culianu6baef152009-02-19 09:13:10 -0800301
Jiri Slaby70265d22009-03-26 09:34:06 +0100302static irqreturn_t interrupt_pcmmio(int irq, void *d);
Bill Pemberton34c43922009-03-16 22:05:14 -0400303static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
Bill Pemberton814900c2009-04-23 15:54:54 -0400304static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
305static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
306static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
307 struct comedi_cmd *cmd);
Calin Culianu6baef152009-02-19 09:13:10 -0800308
309/* some helper functions to deal with specifics of this device's registers */
Bill Pemberton814900c2009-04-23 15:54:54 -0400310static void init_asics(struct comedi_device *dev); /* sets up/clears ASIC chips to defaults */
311static void switch_page(struct comedi_device *dev, int asic, int page);
Calin Culianu6baef152009-02-19 09:13:10 -0800312#ifdef notused
Bill Pemberton814900c2009-04-23 15:54:54 -0400313static void lock_port(struct comedi_device *dev, int asic, int port);
314static void unlock_port(struct comedi_device *dev, int asic, int port);
Calin Culianu6baef152009-02-19 09:13:10 -0800315#endif
316
317/*
318 * Attach is called by the Comedi core to configure the driver
319 * for a particular board. If you specified a board_name array
320 * in the driver structure, dev->board_ptr contains that
321 * address.
322 */
Bill Pembertonda91b262009-04-09 16:07:03 -0400323static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
Calin Culianu6baef152009-02-19 09:13:10 -0800324{
Bill Pemberton34c43922009-03-16 22:05:14 -0400325 struct comedi_subdevice *s;
Calin Culianu6baef152009-02-19 09:13:10 -0800326 int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
327 thisasic_chanct = 0;
328 unsigned long iobase;
329 unsigned int irq[MAX_ASICS];
330
331 iobase = it->options[0];
332 irq[0] = it->options[1];
333
334 printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name,
335 iobase);
336
337 dev->iobase = iobase;
338
339 if (!iobase || !request_region(iobase,
340 thisboard->total_iosize, driver.driver_name)) {
341 printk("I/O port conflict\n");
342 return -EIO;
343 }
344
345/*
346 * Initialize dev->board_name. Note that we can use the "thisboard"
347 * macro now, since we just initialized it in the last line.
348 */
349 dev->board_name = thisboard->name;
350
351/*
352 * Allocate the private structure area. alloc_private() is a
353 * convenient macro defined in comedidev.h.
354 */
Bill Pembertone56ab712009-03-16 22:20:30 -0400355 if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
Calin Culianu6baef152009-02-19 09:13:10 -0800356 printk("cannot allocate private data structure\n");
357 return -ENOMEM;
358 }
359
360 for (asic = 0; asic < MAX_ASICS; ++asic) {
361 devpriv->asics[asic].num = asic;
362 devpriv->asics[asic].iobase =
363 dev->iobase + 16 + asic * ASIC_IOSIZE;
364 devpriv->asics[asic].irq = 0; /* this gets actually set at the end of
365 this function when we
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700366 request_irqs */
Calin Culianu6baef152009-02-19 09:13:10 -0800367 spin_lock_init(&devpriv->asics[asic].spinlock);
368 }
369
370 chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
371 n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
372 n_subdevs = n_dio_subdevs + 2;
373 devpriv->sprivs =
Bill Pemberton4467df92009-03-16 22:19:37 -0400374 kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private), GFP_KERNEL);
Calin Culianu6baef152009-02-19 09:13:10 -0800375 if (!devpriv->sprivs) {
376 printk("cannot allocate subdevice private data structures\n");
377 return -ENOMEM;
378 }
379 /*
380 * Allocate the subdevice structures. alloc_subdevice() is a
381 * convenient macro defined in comedidev.h.
382 *
383 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
384 */
385 if (alloc_subdevices(dev, n_subdevs) < 0) {
386 printk("cannot allocate subdevice data structures\n");
387 return -ENOMEM;
388 }
389
390 /* First, AI */
391 sdev_no = 0;
392 s = dev->subdevices + sdev_no;
393 s->private = devpriv->sprivs + sdev_no;
394 s->maxdata = (1 << thisboard->ai_bits) - 1;
395 s->range_table = thisboard->ai_range_table;
396 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
397 s->type = COMEDI_SUBD_AI;
398 s->n_chan = thisboard->n_ai_chans;
399 s->len_chanlist = s->n_chan;
400 s->insn_read = thisboard->ai_rinsn;
401 subpriv->iobase = dev->iobase + 0;
402 /* initialize the resource enable register by clearing it */
403 outb(0, subpriv->iobase + 3);
404 outb(0, subpriv->iobase + 4 + 3);
405
406 /* Next, AO */
407 ++sdev_no;
408 s = dev->subdevices + sdev_no;
409 s->private = devpriv->sprivs + sdev_no;
410 s->maxdata = (1 << thisboard->ao_bits) - 1;
411 s->range_table = thisboard->ao_range_table;
412 s->subdev_flags = SDF_READABLE;
413 s->type = COMEDI_SUBD_AO;
414 s->n_chan = thisboard->n_ao_chans;
415 s->len_chanlist = s->n_chan;
416 s->insn_read = thisboard->ao_rinsn;
417 s->insn_write = thisboard->ao_winsn;
418 subpriv->iobase = dev->iobase + 8;
419 /* initialize the resource enable register by clearing it */
420 outb(0, subpriv->iobase + 3);
421 outb(0, subpriv->iobase + 4 + 3);
422
423 ++sdev_no;
424 port = 0;
425 asic = 0;
426 for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
427 int byte_no;
428
429 s = dev->subdevices + sdev_no;
430 s->private = devpriv->sprivs + sdev_no;
431 s->maxdata = 1;
432 s->range_table = &range_digital;
433 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
434 s->type = COMEDI_SUBD_DIO;
435 s->insn_bits = pcmmio_dio_insn_bits;
436 s->insn_config = pcmmio_dio_insn_config;
Bill Pemberton214e7b52009-05-14 15:24:28 -0400437 s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
Calin Culianu6baef152009-02-19 09:13:10 -0800438 subpriv->dio.intr.asic = -1;
439 subpriv->dio.intr.first_chan = -1;
440 subpriv->dio.intr.asic_chan = -1;
441 subpriv->dio.intr.num_asic_chans = -1;
442 subpriv->dio.intr.active = 0;
443 s->len_chanlist = 1;
444
445 /* save the ioport address for each 'port' of 8 channels in the
446 subdevice */
447 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
448 if (port >= PORTS_PER_ASIC) {
449 port = 0;
450 ++asic;
451 thisasic_chanct = 0;
452 }
453 subpriv->iobases[byte_no] =
454 devpriv->asics[asic].iobase + port;
455
456 if (thisasic_chanct <
457 CHANS_PER_PORT * INTR_PORTS_PER_ASIC
458 && subpriv->dio.intr.asic < 0) {
459 /* this is an interrupt subdevice, so setup the struct */
460 subpriv->dio.intr.asic = asic;
461 subpriv->dio.intr.active = 0;
462 subpriv->dio.intr.stop_count = 0;
463 subpriv->dio.intr.first_chan = byte_no * 8;
464 subpriv->dio.intr.asic_chan = thisasic_chanct;
465 subpriv->dio.intr.num_asic_chans =
466 s->n_chan -
467 subpriv->dio.intr.first_chan;
468 s->cancel = pcmmio_cancel;
469 s->do_cmd = pcmmio_cmd;
470 s->do_cmdtest = pcmmio_cmdtest;
471 s->len_chanlist =
472 subpriv->dio.intr.num_asic_chans;
473 }
474 thisasic_chanct += CHANS_PER_PORT;
475 }
476 spin_lock_init(&subpriv->dio.intr.spinlock);
477
478 chans_left -= s->n_chan;
479
480 if (!chans_left) {
481 asic = 0; /* reset the asic to our first asic, to do intr subdevs */
482 port = 0;
483 }
484
485 }
486
487 init_asics(dev); /* clear out all the registers, basically */
488
489 for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
490 if (irq[asic]
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700491 && request_irq(irq[asic], interrupt_pcmmio,
Calin Culianu6baef152009-02-19 09:13:10 -0800492 IRQF_SHARED, thisboard->name, dev)) {
493 int i;
494 /* unroll the allocated irqs.. */
495 for (i = asic - 1; i >= 0; --i) {
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700496 free_irq(irq[i], dev);
Calin Culianu6baef152009-02-19 09:13:10 -0800497 devpriv->asics[i].irq = irq[i] = 0;
498 }
499 irq[asic] = 0;
500 }
501 devpriv->asics[asic].irq = irq[asic];
502 }
503
504 dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple
505 irqs.. */
506
507 if (irq[0]) {
508 printk("irq: %u ", irq[0]);
509 if (irq[1] && thisboard->dio_num_asics == 2)
510 printk("second ASIC irq: %u ", irq[1]);
511 } else {
512 printk("(IRQ mode disabled) ");
513 }
514
515 printk("attached\n");
516
517 return 1;
518}
519
520/*
521 * _detach is called to deconfigure a device. It should deallocate
522 * resources.
523 * This function is also called when _attach() fails, so it should be
524 * careful not to release resources that were not necessarily
525 * allocated by _attach(). dev->private and dev->subdevices are
526 * deallocated automatically by the core.
527 */
Bill Pembertonda91b262009-04-09 16:07:03 -0400528static int pcmmio_detach(struct comedi_device *dev)
Calin Culianu6baef152009-02-19 09:13:10 -0800529{
530 int i;
531
532 printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
533 if (dev->iobase)
534 release_region(dev->iobase, thisboard->total_iosize);
535
536 for (i = 0; i < MAX_ASICS; ++i) {
537 if (devpriv && devpriv->asics[i].irq)
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700538 free_irq(devpriv->asics[i].irq, dev);
Calin Culianu6baef152009-02-19 09:13:10 -0800539 }
540
541 if (devpriv && devpriv->sprivs)
542 kfree(devpriv->sprivs);
543
544 return 0;
545}
546
547/* DIO devices are slightly special. Although it is possible to
548 * implement the insn_read/insn_write interface, it is much more
549 * useful to applications if you implement the insn_bits interface.
550 * This allows packed reading/writing of the DIO channels. The
551 * comedi core can convert between insn_bits and insn_read/write */
Bill Pembertonda91b262009-04-09 16:07:03 -0400552static int pcmmio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
553 struct comedi_insn *insn, unsigned int *data)
Calin Culianu6baef152009-02-19 09:13:10 -0800554{
555 int byte_no;
556 if (insn->n != 2)
557 return -EINVAL;
558
559 /* NOTE:
560 reading a 0 means this channel was high
561 writine a 0 sets the channel high
562 reading a 1 means this channel was low
563 writing a 1 means set this channel low
564
565 Therefore everything is always inverted. */
566
567 /* The insn data is a mask in data[0] and the new data
568 * in data[1], each channel cooresponding to a bit. */
569
570#ifdef DAMMIT_ITS_BROKEN
571 /* DEBUG */
572 printk("write mask: %08x data: %08x\n", data[0], data[1]);
573#endif
574
575 s->state = 0;
576
577 for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
578 /* address of 8-bit port */
579 unsigned long ioaddr = subpriv->iobases[byte_no],
580 /* bit offset of port in 32-bit doubleword */
581 offset = byte_no * 8;
582 /* this 8-bit port's data */
583 unsigned char byte = 0,
584 /* The write mask for this port (if any) */
585 write_mask_byte = (data[0] >> offset) & 0xff,
586 /* The data byte for this port */
587 data_byte = (data[1] >> offset) & 0xff;
588
589 byte = inb(ioaddr); /* read all 8-bits for this port */
590
591#ifdef DAMMIT_ITS_BROKEN
592 /* DEBUG */
593 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);
594#endif
595
596 if (write_mask_byte) {
597 /* this byte has some write_bits -- so set the output lines */
598 byte &= ~write_mask_byte; /* clear bits for write mask */
599 byte |= ~data_byte & write_mask_byte; /* set to inverted data_byte */
600 /* Write out the new digital output state */
601 outb(byte, ioaddr);
602 }
603#ifdef DAMMIT_ITS_BROKEN
604 /* DEBUG */
605 printk("data_out_byte %02x\n", (unsigned)byte);
606#endif
607 /* save the digital input lines for this byte.. */
608 s->state |= ((unsigned int)byte) << offset;
609 }
610
611 /* now return the DIO lines to data[1] - note they came inverted! */
612 data[1] = ~s->state;
613
614#ifdef DAMMIT_ITS_BROKEN
615 /* DEBUG */
616 printk("s->state %08x data_out %08x\n", s->state, data[1]);
617#endif
618
619 return 2;
620}
621
622/* The input or output configuration of each digital line is
623 * configured by a special insn_config instruction. chanspec
624 * contains the channel to be changed, and data[0] contains the
625 * value COMEDI_INPUT or COMEDI_OUTPUT. */
Bill Pembertonda91b262009-04-09 16:07:03 -0400626static int pcmmio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
627 struct comedi_insn *insn, unsigned int *data)
Calin Culianu6baef152009-02-19 09:13:10 -0800628{
629 int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
630 chan % 8;
631 unsigned long ioaddr;
632 unsigned char byte;
633
634 /* Compute ioaddr for this channel */
635 ioaddr = subpriv->iobases[byte_no];
636
637 /* NOTE:
638 writing a 0 an IO channel's bit sets the channel to INPUT
639 and pulls the line high as well
640
641 writing a 1 to an IO channel's bit pulls the line low
642
643 All channels are implicitly always in OUTPUT mode -- but when
644 they are high they can be considered to be in INPUT mode..
645
646 Thus, we only force channels low if the config request was INPUT,
647 otherwise we do nothing to the hardware. */
648
649 switch (data[0]) {
650 case INSN_CONFIG_DIO_OUTPUT:
651 /* save to io_bits -- don't actually do anything since
652 all input channels are also output channels... */
653 s->io_bits |= 1 << chan;
654 break;
655 case INSN_CONFIG_DIO_INPUT:
656 /* write a 0 to the actual register representing the channel
657 to set it to 'input'. 0 means "float high". */
658 byte = inb(ioaddr);
659 byte &= ~(1 << bit_no);
660 /**< set input channel to '0' */
661
662 /* write out byte -- this is the only time we actually affect the
663 hardware as all channels are implicitly output -- but input
664 channels are set to float-high */
665 outb(byte, ioaddr);
666
667 /* save to io_bits */
668 s->io_bits &= ~(1 << chan);
669 break;
670
671 case INSN_CONFIG_DIO_QUERY:
672 /* retreive from shadow register */
673 data[1] =
674 (s->
675 io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
676 return insn->n;
677 break;
678
679 default:
680 return -EINVAL;
681 break;
682 }
683
684 return insn->n;
685}
686
Bill Pembertonda91b262009-04-09 16:07:03 -0400687static void init_asics(struct comedi_device *dev)
Calin Culianu6baef152009-02-19 09:13:10 -0800688{ /* sets up an
689 ASIC chip to defaults */
690 int asic;
691
692 for (asic = 0; asic < thisboard->dio_num_asics; ++asic) {
693 int port, page;
694 unsigned long baseaddr = devpriv->asics[asic].iobase;
695
696 switch_page(dev, asic, 0); /* switch back to page 0 */
697
698 /* first, clear all the DIO port bits */
699 for (port = 0; port < PORTS_PER_ASIC; ++port)
700 outb(0, baseaddr + REG_PORT0 + port);
701
702 /* Next, clear all the paged registers for each page */
703 for (page = 1; page < NUM_PAGES; ++page) {
704 int reg;
705 /* now clear all the paged registers */
706 switch_page(dev, asic, page);
707 for (reg = FIRST_PAGED_REG;
708 reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
709 outb(0, baseaddr + reg);
710 }
711
712 /* DEBUG set rising edge interrupts on port0 of both asics */
713 /*switch_page(dev, asic, PAGE_POL);
714 outb(0xff, baseaddr + REG_POL0);
715 switch_page(dev, asic, PAGE_ENAB);
716 outb(0xff, baseaddr + REG_ENAB0); */
717 /* END DEBUG */
718
719 switch_page(dev, asic, 0); /* switch back to default page 0 */
720
721 }
722}
723
Bill Pembertonda91b262009-04-09 16:07:03 -0400724static void switch_page(struct comedi_device *dev, int asic, int page)
Calin Culianu6baef152009-02-19 09:13:10 -0800725{
726 if (asic < 0 || asic >= thisboard->dio_num_asics)
727 return; /* paranoia */
728 if (page < 0 || page >= NUM_PAGES)
729 return; /* more paranoia */
730
731 devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
732 devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
733
734 /* now write out the shadow register */
735 outb(devpriv->asics[asic].pagelock,
736 devpriv->asics[asic].iobase + REG_PAGELOCK);
737}
738
739#ifdef notused
Bill Pembertonda91b262009-04-09 16:07:03 -0400740static void lock_port(struct comedi_device *dev, int asic, int port)
Calin Culianu6baef152009-02-19 09:13:10 -0800741{
742 if (asic < 0 || asic >= thisboard->dio_num_asics)
743 return; /* paranoia */
744 if (port < 0 || port >= PORTS_PER_ASIC)
745 return; /* more paranoia */
746
747 devpriv->asics[asic].pagelock |= 0x1 << port;
748 /* now write out the shadow register */
749 outb(devpriv->asics[asic].pagelock,
750 devpriv->asics[asic].iobase + REG_PAGELOCK);
751 return;
752}
753
Bill Pembertonda91b262009-04-09 16:07:03 -0400754static void unlock_port(struct comedi_device *dev, int asic, int port)
Calin Culianu6baef152009-02-19 09:13:10 -0800755{
756 if (asic < 0 || asic >= thisboard->dio_num_asics)
757 return; /* paranoia */
758 if (port < 0 || port >= PORTS_PER_ASIC)
759 return; /* more paranoia */
760 devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
761 /* now write out the shadow register */
762 outb(devpriv->asics[asic].pagelock,
763 devpriv->asics[asic].iobase + REG_PAGELOCK);
764}
765#endif /* notused */
766
Jiri Slaby70265d22009-03-26 09:34:06 +0100767static irqreturn_t interrupt_pcmmio(int irq, void *d)
Calin Culianu6baef152009-02-19 09:13:10 -0800768{
769 int asic, got1 = 0;
Bill Pemberton71b5f4f2009-03-16 22:05:08 -0400770 struct comedi_device *dev = (struct comedi_device *) d;
Calin Culianu6baef152009-02-19 09:13:10 -0800771
772 for (asic = 0; asic < MAX_ASICS; ++asic) {
773 if (irq == devpriv->asics[asic].irq) {
774 unsigned long flags;
775 unsigned triggered = 0;
776 unsigned long iobase = devpriv->asics[asic].iobase;
777 /* it is an interrupt for ASIC #asic */
778 unsigned char int_pend;
779
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700780 spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -0800781
782 int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
783
784 if (int_pend) {
785 int port;
786 for (port = 0; port < INTR_PORTS_PER_ASIC;
787 ++port) {
788 if (int_pend & (0x1 << port)) {
789 unsigned char
790 io_lines_with_edges = 0;
791 switch_page(dev, asic,
792 PAGE_INT_ID);
793 io_lines_with_edges =
794 inb(iobase +
795 REG_INT_ID0 + port);
796
797 if (io_lines_with_edges)
798 /* clear pending interrupt */
799 outb(0, iobase +
800 REG_INT_ID0 +
801 port);
802
803 triggered |=
804 io_lines_with_edges <<
805 port * 8;
806 }
807 }
808
809 ++got1;
810 }
811
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700812 spin_unlock_irqrestore(&devpriv->asics[asic]. spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -0800813
814 if (triggered) {
Bill Pemberton34c43922009-03-16 22:05:14 -0400815 struct comedi_subdevice *s;
Calin Culianu6baef152009-02-19 09:13:10 -0800816 /* TODO here: dispatch io lines to subdevs with commands.. */
817 printk("PCMMIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n", irq, asic, triggered);
818 for (s = dev->subdevices + 2;
819 s < dev->subdevices + dev->n_subdevices;
820 ++s) {
821 if (subpriv->dio.intr.asic == asic) { /* this is an interrupt subdev, and it matches this asic! */
822 unsigned long flags;
823 unsigned oldevents;
824
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700825 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -0800826
827 oldevents = s->async->events;
828
829 if (subpriv->dio.intr.active) {
830 unsigned mytrig =
831 ((triggered >>
832 subpriv->
833 dio.
834 intr.
835 asic_chan)
836 & ((0x1 << subpriv->dio.intr.num_asic_chans) - 1)) << subpriv->dio.intr.first_chan;
837 if (mytrig & subpriv->
838 dio.intr.
839 enabled_mask) {
Bill Pemberton790c5542009-03-16 22:05:02 -0400840 unsigned int val =
Calin Culianu6baef152009-02-19 09:13:10 -0800841 0;
842 unsigned int n,
843 ch, len;
844
845 len = s->async->
846 cmd.
847 chanlist_len;
848 for (n = 0;
849 n < len;
850 n++) {
851 ch = CR_CHAN(s->async->cmd.chanlist[n]);
852 if (mytrig & (1U << ch)) {
853 val |= (1U << n);
854 }
855 }
856 /* Write the scan to the buffer. */
Bill Pemberton9b9bcba2009-04-23 15:54:53 -0400857 if (comedi_buf_put(s->async, ((short *) &val)[0])
Calin Culianu6baef152009-02-19 09:13:10 -0800858 &&
859 comedi_buf_put
Bill Pemberton9b9bcba2009-04-23 15:54:53 -0400860 (s->async, ((short *) &val)[1])) {
Calin Culianu6baef152009-02-19 09:13:10 -0800861 s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
862 } else {
863 /* Overflow! Stop acquisition!! */
864 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
865 pcmmio_stop_intr
866 (dev,
867 s);
868 }
869
870 /* Check for end of acquisition. */
871 if (!subpriv->
872 dio.
873 intr.
874 continuous)
875 {
876 /* stop_src == TRIG_COUNT */
877 if (subpriv->dio.intr.stop_count > 0) {
878 subpriv->
879 dio.
880 intr.
881 stop_count--;
882 if (subpriv->dio.intr.stop_count == 0) {
883 s->async->events |= COMEDI_CB_EOA;
884 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
885 pcmmio_stop_intr
886 (dev,
887 s);
888 }
889 }
890 }
891 }
892 }
893
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700894 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -0800895
896 if (oldevents !=
897 s->async->events) {
898 comedi_event(dev, s);
899 }
900
901 }
902
903 }
904 }
905
906 }
907 }
908 if (!got1)
909 return IRQ_NONE; /* interrupt from other source */
910 return IRQ_HANDLED;
911}
912
Bill Pembertonda91b262009-04-09 16:07:03 -0400913static void pcmmio_stop_intr(struct comedi_device *dev, struct comedi_subdevice *s)
Calin Culianu6baef152009-02-19 09:13:10 -0800914{
915 int nports, firstport, asic, port;
916
Bill Pembertonc3744132009-04-22 21:11:47 -0400917 asic = subpriv->dio.intr.asic;
918 if (asic < 0)
Calin Culianu6baef152009-02-19 09:13:10 -0800919 return; /* not an interrupt subdev */
920
921 subpriv->dio.intr.enabled_mask = 0;
922 subpriv->dio.intr.active = 0;
923 s->async->inttrig = 0;
924 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
925 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
926 switch_page(dev, asic, PAGE_ENAB);
927 for (port = firstport; port < firstport + nports; ++port) {
928 /* disable all intrs for this subdev.. */
929 outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
930 }
931}
932
Bill Pembertonda91b262009-04-09 16:07:03 -0400933static int pcmmio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s)
Calin Culianu6baef152009-02-19 09:13:10 -0800934{
935 if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
936 /* An empty acquisition! */
937 s->async->events |= COMEDI_CB_EOA;
938 subpriv->dio.intr.active = 0;
939 return 1;
940 } else {
941 unsigned bits = 0, pol_bits = 0, n;
942 int nports, firstport, asic, port;
Bill Pembertonea6d0d42009-03-16 22:05:47 -0400943 struct comedi_cmd *cmd = &s->async->cmd;
Calin Culianu6baef152009-02-19 09:13:10 -0800944
Bill Pembertonc3744132009-04-22 21:11:47 -0400945 asic = subpriv->dio.intr.asic;
946 if (asic < 0)
Calin Culianu6baef152009-02-19 09:13:10 -0800947 return 1; /* not an interrupt
948 subdev */
949 subpriv->dio.intr.enabled_mask = 0;
950 subpriv->dio.intr.active = 1;
951 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
952 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
953 if (cmd->chanlist) {
954 for (n = 0; n < cmd->chanlist_len; n++) {
955 bits |= (1U << CR_CHAN(cmd->chanlist[n]));
956 pol_bits |= (CR_AREF(cmd->chanlist[n])
957 || CR_RANGE(cmd->chanlist[n]) ? 1U : 0U)
958 << CR_CHAN(cmd->chanlist[n]);
959 }
960 }
961 bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
962 1) << subpriv->dio.intr.first_chan;
963 subpriv->dio.intr.enabled_mask = bits;
964
965 { /* the below code configures the board to use a specific IRQ from 0-15. */
966 unsigned char b;
967 /* set resource enable register to enable IRQ operation */
968 outb(1 << 4, dev->iobase + 3);
969 /* set bits 0-3 of b to the irq number from 0-15 */
970 b = dev->irq & ((1 << 4) - 1);
971 outb(b, dev->iobase + 2);
972 /* done, we told the board what irq to use */
973 }
974
975 switch_page(dev, asic, PAGE_ENAB);
976 for (port = firstport; port < firstport + nports; ++port) {
977 unsigned enab =
978 bits >> (subpriv->dio.intr.first_chan + (port -
979 firstport) * 8) & 0xff, pol =
980 pol_bits >> (subpriv->dio.intr.first_chan +
981 (port - firstport) * 8) & 0xff;
982 /* set enab intrs for this subdev.. */
983 outb(enab,
984 devpriv->asics[asic].iobase + REG_ENAB0 + port);
985 switch_page(dev, asic, PAGE_POL);
986 outb(pol,
987 devpriv->asics[asic].iobase + REG_ENAB0 + port);
988 }
989 }
990 return 0;
991}
992
Bill Pembertonda91b262009-04-09 16:07:03 -0400993static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
Calin Culianu6baef152009-02-19 09:13:10 -0800994{
995 unsigned long flags;
996
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -0700997 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -0800998 if (subpriv->dio.intr.active)
999 pcmmio_stop_intr(dev, s);
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001000 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -08001001
1002 return 0;
1003}
1004
1005/*
1006 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
1007 */
1008static int
Bill Pembertonda91b262009-04-09 16:07:03 -04001009pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
Calin Culianu6baef152009-02-19 09:13:10 -08001010 unsigned int trignum)
1011{
1012 unsigned long flags;
1013 int event = 0;
1014
1015 if (trignum != 0)
1016 return -EINVAL;
1017
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001018 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -08001019 s->async->inttrig = 0;
1020 if (subpriv->dio.intr.active) {
1021 event = pcmmio_start_intr(dev, s);
1022 }
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001023 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -08001024
1025 if (event) {
1026 comedi_event(dev, s);
1027 }
1028
1029 return 1;
1030}
1031
1032/*
1033 * 'do_cmd' function for an 'INTERRUPT' subdevice.
1034 */
Bill Pembertonda91b262009-04-09 16:07:03 -04001035static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
Calin Culianu6baef152009-02-19 09:13:10 -08001036{
Bill Pembertonea6d0d42009-03-16 22:05:47 -04001037 struct comedi_cmd *cmd = &s->async->cmd;
Calin Culianu6baef152009-02-19 09:13:10 -08001038 unsigned long flags;
1039 int event = 0;
1040
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001041 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -08001042 subpriv->dio.intr.active = 1;
1043
1044 /* Set up end of acquisition. */
1045 switch (cmd->stop_src) {
1046 case TRIG_COUNT:
1047 subpriv->dio.intr.continuous = 0;
1048 subpriv->dio.intr.stop_count = cmd->stop_arg;
1049 break;
1050 default:
1051 /* TRIG_NONE */
1052 subpriv->dio.intr.continuous = 1;
1053 subpriv->dio.intr.stop_count = 0;
1054 break;
1055 }
1056
1057 /* Set up start of acquisition. */
1058 switch (cmd->start_src) {
1059 case TRIG_INT:
1060 s->async->inttrig = pcmmio_inttrig_start_intr;
1061 break;
1062 default:
1063 /* TRIG_NOW */
1064 event = pcmmio_start_intr(dev, s);
1065 break;
1066 }
Greg Kroah-Hartman5f74ea12009-04-27 14:44:31 -07001067 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
Calin Culianu6baef152009-02-19 09:13:10 -08001068
1069 if (event) {
1070 comedi_event(dev, s);
1071 }
1072
1073 return 0;
1074}
1075
1076/*
1077 * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
1078 */
1079static int
Bill Pembertonda91b262009-04-09 16:07:03 -04001080pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd)
Calin Culianu6baef152009-02-19 09:13:10 -08001081{
1082 int err = 0;
1083 unsigned int tmp;
1084
1085 /* step 1: make sure trigger sources are trivially valid */
1086
1087 tmp = cmd->start_src;
1088 cmd->start_src &= (TRIG_NOW | TRIG_INT);
1089 if (!cmd->start_src || tmp != cmd->start_src)
1090 err++;
1091
1092 tmp = cmd->scan_begin_src;
1093 cmd->scan_begin_src &= TRIG_EXT;
1094 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1095 err++;
1096
1097 tmp = cmd->convert_src;
1098 cmd->convert_src &= TRIG_NOW;
1099 if (!cmd->convert_src || tmp != cmd->convert_src)
1100 err++;
1101
1102 tmp = cmd->scan_end_src;
1103 cmd->scan_end_src &= TRIG_COUNT;
1104 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1105 err++;
1106
1107 tmp = cmd->stop_src;
1108 cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
1109 if (!cmd->stop_src || tmp != cmd->stop_src)
1110 err++;
1111
1112 if (err)
1113 return 1;
1114
1115 /* step 2: make sure trigger sources are unique and mutually compatible */
1116
1117 /* these tests are true if more than one _src bit is set */
1118 if ((cmd->start_src & (cmd->start_src - 1)) != 0)
1119 err++;
1120 if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
1121 err++;
1122 if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
1123 err++;
1124 if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
1125 err++;
1126 if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
1127 err++;
1128
1129 if (err)
1130 return 2;
1131
1132 /* step 3: make sure arguments are trivially compatible */
1133
1134 /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */
1135 if (cmd->start_arg != 0) {
1136 cmd->start_arg = 0;
1137 err++;
1138 }
1139
1140 /* cmd->scan_begin_src == TRIG_EXT */
1141 if (cmd->scan_begin_arg != 0) {
1142 cmd->scan_begin_arg = 0;
1143 err++;
1144 }
1145
1146 /* cmd->convert_src == TRIG_NOW */
1147 if (cmd->convert_arg != 0) {
1148 cmd->convert_arg = 0;
1149 err++;
1150 }
1151
1152 /* cmd->scan_end_src == TRIG_COUNT */
1153 if (cmd->scan_end_arg != cmd->chanlist_len) {
1154 cmd->scan_end_arg = cmd->chanlist_len;
1155 err++;
1156 }
1157
1158 switch (cmd->stop_src) {
1159 case TRIG_COUNT:
1160 /* any count allowed */
1161 break;
1162 case TRIG_NONE:
1163 if (cmd->stop_arg != 0) {
1164 cmd->stop_arg = 0;
1165 err++;
1166 }
1167 break;
1168 default:
1169 break;
1170 }
1171
1172 if (err)
1173 return 3;
1174
1175 /* step 4: fix up any arguments */
1176
1177 /* if (err) return 4; */
1178
1179 return 0;
1180}
1181
1182static int adc_wait_ready(unsigned long iobase)
1183{
1184 unsigned long retry = 100000;
1185 while (retry--)
1186 if (inb(iobase + 3) & 0x80)
1187 return 0;
1188 return 1;
1189}
1190
1191/* All this is for AI and AO */
Bill Pembertonda91b262009-04-09 16:07:03 -04001192static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1193 struct comedi_insn *insn, unsigned int *data)
Calin Culianu6baef152009-02-19 09:13:10 -08001194{
1195 int n;
1196 unsigned long iobase = subpriv->iobase;
1197
1198 /*
1199 1. write the CMD byte (to BASE+2)
1200 2. read junk lo byte (BASE+0)
1201 3. read junk hi byte (BASE+1)
1202 4. (mux settled so) write CMD byte again (BASE+2)
1203 5. read valid lo byte(BASE+0)
1204 6. read valid hi byte(BASE+1)
1205
1206 Additionally note that the BASE += 4 if the channel >= 8
1207 */
1208
1209 /* convert n samples */
1210 for (n = 0; n < insn->n; n++) {
1211 unsigned chan = CR_CHAN(insn->chanspec), range =
1212 CR_RANGE(insn->chanspec), aref =
1213 CR_AREF(insn->chanspec);
1214 unsigned char command_byte = 0;
1215 unsigned iooffset = 0;
Bill Pemberton790c5542009-03-16 22:05:02 -04001216 short sample, adc_adjust = 0;
Calin Culianu6baef152009-02-19 09:13:10 -08001217
1218 if (chan > 7)
1219 chan -= 8, iooffset = 4; /* use the second dword for channels > 7 */
1220
1221 if (aref != AREF_DIFF) {
1222 aref = AREF_GROUND;
1223 command_byte |= 1 << 7; /* set bit 7 to indicate single-ended */
1224 }
1225 if (range < 2)
1226 adc_adjust = 0x8000; /* bipolar ranges (-5,5 .. -10,10 need to be adjusted -- that is.. they need to wrap around by adding 0x8000 */
1227
1228 if (chan % 2) {
1229 command_byte |= 1 << 6; /* odd-numbered channels have bit 6 set */
1230 }
1231
1232 /* select the channel, bits 4-5 == chan/2 */
1233 command_byte |= ((chan / 2) & 0x3) << 4;
1234
1235 /* set the range, bits 2-3 */
1236 command_byte |= (range & 0x3) << 2;
1237
1238 /* need to do this twice to make sure mux settled */
1239 outb(command_byte, iobase + iooffset + 2); /* chan/range/aref select */
1240
1241 adc_wait_ready(iobase + iooffset); /* wait for the adc to say it finised the conversion */
1242
1243 outb(command_byte, iobase + iooffset + 2); /* select the chan/range/aref AGAIN */
1244
1245 adc_wait_ready(iobase + iooffset);
1246
1247 sample = inb(iobase + iooffset + 0); /* read data lo byte */
1248 sample |= inb(iobase + iooffset + 1) << 8; /* read data hi byte */
1249 sample += adc_adjust; /* adjustment .. munge data */
1250 data[n] = sample;
1251 }
1252 /* return the number of samples read/written */
1253 return n;
1254}
1255
Bill Pembertonda91b262009-04-09 16:07:03 -04001256static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1257 struct comedi_insn *insn, unsigned int *data)
Calin Culianu6baef152009-02-19 09:13:10 -08001258{
1259 int n;
1260 for (n = 0; n < insn->n; n++) {
1261 unsigned chan = CR_CHAN(insn->chanspec);
1262 if (chan < s->n_chan)
1263 data[n] = subpriv->ao.shadow_samples[chan];
1264 }
1265 return n;
1266}
1267
1268static int wait_dac_ready(unsigned long iobase)
1269{
1270 unsigned long retry = 100000L;
1271
1272 /* This may seem like an absurd way to handle waiting and violates the
1273 "no busy waiting" policy. The fact is that the hardware is
1274 normally so fast that we usually only need one time through the loop
1275 anyway. The longer timeout is for rare occasions and for detecting
1276 non-existant hardware. */
1277
1278 while (retry--) {
1279 if (inb(iobase + 3) & 0x80)
1280 return 0;
1281
1282 }
1283 return 1;
1284}
1285
Bill Pembertonda91b262009-04-09 16:07:03 -04001286static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
1287 struct comedi_insn *insn, unsigned int *data)
Calin Culianu6baef152009-02-19 09:13:10 -08001288{
1289 int n;
1290 unsigned iobase = subpriv->iobase, iooffset = 0;
1291
1292 for (n = 0; n < insn->n; n++) {
1293 unsigned chan = CR_CHAN(insn->chanspec), range =
1294 CR_RANGE(insn->chanspec);
1295 if (chan < s->n_chan) {
1296 unsigned char command_byte = 0, range_byte =
1297 range & ((1 << 4) - 1);
1298 if (chan >= 4)
1299 chan -= 4, iooffset += 4;
1300 /* set the range.. */
1301 outb(range_byte, iobase + iooffset + 0);
1302 outb(0, iobase + iooffset + 1);
1303
1304 /* tell it to begin */
1305 command_byte = (chan << 1) | 0x60;
1306 outb(command_byte, iobase + iooffset + 2);
1307
1308 wait_dac_ready(iobase + iooffset);
1309
1310 outb(data[n] & 0xff, iobase + iooffset + 0); /* low order byte */
1311 outb((data[n] >> 8) & 0xff, iobase + iooffset + 1); /* high order byte */
1312 command_byte = 0x70 | (chan << 1); /* set bit 4 of command byte to indicate data is loaded and trigger conversion */
1313 /* trigger converion */
1314 outb(command_byte, iobase + iooffset + 2);
1315
1316 wait_dac_ready(iobase + iooffset);
1317
1318 subpriv->ao.shadow_samples[chan] = data[n]; /* save to shadow register for ao_rinsn */
1319 }
1320 }
1321 return n;
1322}
1323
1324/*
1325 * A convenient macro that defines init_module() and cleanup_module(),
1326 * as necessary.
1327 */
1328COMEDI_INITCLEANUP(driver);