Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pcmmio.c
Go to the documentation of this file.
1 /*
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 <[email protected]>
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 /*
23 Driver: pcmmio
24 Description: A driver for the PCM-MIO multifunction board
25 Devices: [Winsystems] PCM-MIO (pcmmio)
26 Author: Calin Culianu <[email protected]>
27 Updated: Wed, May 16 2007 16:21:10 -0500
28 Status: works
29 
30 A driver for the relatively new PCM-MIO multifunction board from
31 Winsystems. This board is a PC-104 based I/O board. It contains
32 four 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
36  (with edge-triggered interrupt support)
37  subdevice 3 - last 24 channels of the 48 channel DIO
38  (no interrupt support for this bank of channels)
39 
40  Some notes:
41 
42  Synchronous reads and writes are the only things implemented for AI and AO,
43  even though the hardware itself can do streaming acquisition, etc. Anyone
44  want to add asynchronous I/O for AI/AO as a feature? Be my guest...
45 
46  Asynchronous I/O for the DIO subdevices *is* implemented, however! They are
47  basically edge-triggered interrupts for any configuration of the first
48  24 DIO-lines.
49 
50  Also note that this interrupt support is untested.
51 
52  A few words about edge-detection IRQ support (commands on DIO):
53 
54  * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
55  of the board to the comedi_config command. The board IRQ is not jumpered
56  but rather configured through software, so any IRQ from 1-15 is OK.
57 
58  * Due to the genericity of the comedi API, you need to create a special
59  comedi_command in order to use edge-triggered interrupts for DIO.
60 
61  * Use comedi_commands with TRIG_NOW. Your callback will be called each
62  time an edge is detected on the specified DIO line(s), and the data
63  values will be two sample_t's, which should be concatenated to form
64  one 32-bit unsigned int. This value is the mask of channels that had
65  edges detected from your channel list. Note that the bits positions
66  in the mask correspond to positions in your chanlist when you
67  specified the command and *not* channel id's!
68 
69  * To set the polarity of the edge-detection interrupts pass a nonzero value
70  for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
71  value for both CR_RANGE and CR_AREF if you want edge-down polarity.
72 
73 Configuration Options:
74  [0] - I/O port base address
75  [1] - IRQ (optional -- for edge-detect interrupt support only,
76  leave out if you don't need this feature)
77 */
78 
79 #include <linux/interrupt.h>
80 #include <linux/slab.h>
81 #include "../comedidev.h"
82 #include "pcm_common.h"
83 #include <linux/pci.h> /* for PCI devices */
84 
85 /* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
86 #define CHANS_PER_PORT 8
87 #define PORTS_PER_ASIC 6
88 #define INTR_PORTS_PER_ASIC 3
89 #define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */
90 #define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
91 #define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
92 #define INTR_CHANS_PER_ASIC 24
93 #define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
94 #define MAX_DIO_CHANS (PORTS_PER_ASIC*1*CHANS_PER_PORT)
95 #define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC)
96 #define SDEV_NO ((int)(s - dev->subdevices))
97 #define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
98 /* IO Memory sizes */
99 #define ASIC_IOSIZE (0x0B)
100 #define PCMMIO48_IOSIZE ASIC_IOSIZE
101 
102 /* Some offsets - these are all in the 16byte IO memory offset from
103  the base address. Note that there is a paging scheme to swap out
104  offsets 0x8-0xA using the PAGELOCK register. See the table below.
105 
106  Register(s) Pages R/W? Description
107  --------------------------------------------------------------
108  REG_PORTx All R/W Read/Write/Configure IO
109  REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int.
110  REG_PAGELOCK All WriteOnly Select a page
111  REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity
112  REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int.
113  REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints.
114  */
115 #define REG_PORT0 0x0
116 #define REG_PORT1 0x1
117 #define REG_PORT2 0x2
118 #define REG_PORT3 0x3
119 #define REG_PORT4 0x4
120 #define REG_PORT5 0x5
121 #define REG_INT_PENDING 0x6
122 #define REG_PAGELOCK 0x7 /*
123  * page selector register, upper 2 bits select
124  * a page and bits 0-5 are used to 'lock down'
125  * a particular port above to make it readonly.
126  */
127 #define REG_POL0 0x8
128 #define REG_POL1 0x9
129 #define REG_POL2 0xA
130 #define REG_ENAB0 0x8
131 #define REG_ENAB1 0x9
132 #define REG_ENAB2 0xA
133 #define REG_INT_ID0 0x8
134 #define REG_INT_ID1 0x9
135 #define REG_INT_ID2 0xA
137 #define NUM_PAGED_REGS 3
138 #define NUM_PAGES 4
139 #define FIRST_PAGED_REG 0x8
140 #define REG_PAGE_BITOFFSET 6
141 #define REG_LOCK_BITOFFSET 0
142 #define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
143 #define REG_LOCK_MASK (~(REG_PAGE_MASK))
144 #define PAGE_POL 1
145 #define PAGE_ENAB 2
146 #define PAGE_INT_ID 3
147 
148 /*
149  * Board descriptions for two imaginary boards. Describing the
150  * boards in this way is optional, and completely driver-dependent.
151  * Some drivers use arrays such as this, other do not.
152  */
153 struct pcmmio_board {
154  const char *name;
155  const int dio_num_asics;
156  const int dio_num_ports;
157  const int total_iosize;
158  const int ai_bits;
159  const int ao_bits;
160  const int n_ai_chans;
161  const int n_ao_chans;
164  struct comedi_subdevice *s,
165  struct comedi_insn *insn,
166  unsigned int *data);
168  struct comedi_subdevice *s,
169  struct comedi_insn *insn,
170  unsigned int *data);
171  int (*ao_winsn) (struct comedi_device *dev,
172  struct comedi_subdevice *s,
173  struct comedi_insn *insn,
174  unsigned int *data);
175 };
176 
177 static const struct comedi_lrange ranges_ai = {
178  4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)}
179 };
180 
181 static const struct comedi_lrange ranges_ao = {
182  6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
183  RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
184 };
185 
186 /* this structure is for data unique to this subdevice. */
187 struct pcmmio_subdev_private {
189  union {
190  /* for DIO: mapping of halfwords (bytes)
191  in port/chanarray to iobase */
192  unsigned long iobases[PORTS_PER_SUBDEV];
193 
194  /* for AI/AO */
195  unsigned long iobase;
196  };
197  union {
198  struct {
199 
200  /* The below is only used for intr subdevices */
201  struct {
202  /*
203  * if non-negative, this subdev has an
204  * interrupt asic
205  */
206  int asic;
207  /*
208  * if nonnegative, the first channel id for
209  * interrupts.
210  */
211  int first_chan;
212  /*
213  * the number of asic channels in this subdev
214  * that have interrutps
215  */
216  int num_asic_chans;
217  /*
218  * if nonnegative, the first channel id with
219  * respect to the asic that has interrupts
220  */
221  int asic_chan;
222  /*
223  * subdev-relative channel mask for channels
224  * we are interested in
225  */
227  int active;
228  int stop_count;
229  int continuous;
231  } intr;
232  } dio;
233  struct {
234  /* the last unsigned int data written */
235  unsigned int shadow_samples[8];
236  } ao;
237  };
238 };
239 
240 /*
241  * this structure is for data unique to this hardware driver. If
242  * several hardware drivers keep similar information in this structure,
243  * feel free to suggest moving the variable to the struct comedi_device struct.
244  */
245 struct pcmmio_private {
246  /* stuff for DIO */
247  struct {
248  unsigned char pagelock; /* current page and lock */
249  /* shadow of POLx registers */
250  unsigned char pol[NUM_PAGED_REGS];
251  /* shadow of ENABx registers */
252  unsigned char enab[NUM_PAGED_REGS];
253  int num;
254  unsigned long iobase;
255  unsigned int irq;
257  } asics[MAX_ASICS];
259 };
260 
261 /*
262  * most drivers define the following macro to make it easy to
263  * access the private structure.
264  */
265 #define devpriv ((struct pcmmio_private *)dev->private)
266 #define subpriv ((struct pcmmio_subdev_private *)s->private)
267 
268 /* DIO devices are slightly special. Although it is possible to
269  * implement the insn_read/insn_write interface, it is much more
270  * useful to applications if you implement the insn_bits interface.
271  * This allows packed reading/writing of the DIO channels. The
272  * comedi core can convert between insn_bits and insn_read/write */
273 static int pcmmio_dio_insn_bits(struct comedi_device *dev,
274  struct comedi_subdevice *s,
275  struct comedi_insn *insn, unsigned int *data)
276 {
277  int byte_no;
278 
279  /* NOTE:
280  reading a 0 means this channel was high
281  writine a 0 sets the channel high
282  reading a 1 means this channel was low
283  writing a 1 means set this channel low
284 
285  Therefore everything is always inverted. */
286 
287  /* The insn data is a mask in data[0] and the new data
288  * in data[1], each channel cooresponding to a bit. */
289 
290 #ifdef DAMMIT_ITS_BROKEN
291  /* DEBUG */
292  printk(KERN_DEBUG "write mask: %08x data: %08x\n", data[0], data[1]);
293 #endif
294 
295  s->state = 0;
296 
297  for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
298  /* address of 8-bit port */
299  unsigned long ioaddr = subpriv->iobases[byte_no],
300  /* bit offset of port in 32-bit doubleword */
301  offset = byte_no * 8;
302  /* this 8-bit port's data */
303  unsigned char byte = 0,
304  /* The write mask for this port (if any) */
305  write_mask_byte = (data[0] >> offset) & 0xff,
306  /* The data byte for this port */
307  data_byte = (data[1] >> offset) & 0xff;
308 
309  byte = inb(ioaddr); /* read all 8-bits for this port */
310 
311 #ifdef DAMMIT_ITS_BROKEN
312  /* DEBUG */
313  printk
314  (KERN_DEBUG "byte %d wmb %02x db %02x offset %02d io %04x,"
315  " data_in %02x ", byte_no, (unsigned)write_mask_byte,
316  (unsigned)data_byte, offset, ioaddr, (unsigned)byte);
317 #endif
318 
319  if (write_mask_byte) {
320  /*
321  * this byte has some write_bits
322  * -- so set the output lines
323  */
324  /* clear bits for write mask */
325  byte &= ~write_mask_byte;
326  /* set to inverted data_byte */
327  byte |= ~data_byte & write_mask_byte;
328  /* Write out the new digital output state */
329  outb(byte, ioaddr);
330  }
331 #ifdef DAMMIT_ITS_BROKEN
332  /* DEBUG */
333  printk(KERN_DEBUG "data_out_byte %02x\n", (unsigned)byte);
334 #endif
335  /* save the digital input lines for this byte.. */
336  s->state |= ((unsigned int)byte) << offset;
337  }
338 
339  /* now return the DIO lines to data[1] - note they came inverted! */
340  data[1] = ~s->state;
341 
342 #ifdef DAMMIT_ITS_BROKEN
343  /* DEBUG */
344  printk(KERN_DEBUG "s->state %08x data_out %08x\n", s->state, data[1]);
345 #endif
346 
347  return insn->n;
348 }
349 
350 /* The input or output configuration of each digital line is
351  * configured by a special insn_config instruction. chanspec
352  * contains the channel to be changed, and data[0] contains the
353  * value COMEDI_INPUT or COMEDI_OUTPUT. */
354 static int pcmmio_dio_insn_config(struct comedi_device *dev,
355  struct comedi_subdevice *s,
356  struct comedi_insn *insn, unsigned int *data)
357 {
358  int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
359  chan % 8;
360  unsigned long ioaddr;
361  unsigned char byte;
362 
363  /* Compute ioaddr for this channel */
364  ioaddr = subpriv->iobases[byte_no];
365 
366  /* NOTE:
367  writing a 0 an IO channel's bit sets the channel to INPUT
368  and pulls the line high as well
369 
370  writing a 1 to an IO channel's bit pulls the line low
371 
372  All channels are implicitly always in OUTPUT mode -- but when
373  they are high they can be considered to be in INPUT mode..
374 
375  Thus, we only force channels low if the config request was INPUT,
376  otherwise we do nothing to the hardware. */
377 
378  switch (data[0]) {
380  /* save to io_bits -- don't actually do anything since
381  all input channels are also output channels... */
382  s->io_bits |= 1 << chan;
383  break;
385  /* write a 0 to the actual register representing the channel
386  to set it to 'input'. 0 means "float high". */
387  byte = inb(ioaddr);
388  byte &= ~(1 << bit_no);
391  /*
392  * write out byte -- this is the only time we actually affect
393  * the hardware as all channels are implicitly output
394  * -- but input channels are set to float-high
395  */
396  outb(byte, ioaddr);
397 
398  /* save to io_bits */
399  s->io_bits &= ~(1 << chan);
400  break;
401 
403  /* retrieve from shadow register */
404  data[1] =
405  (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
406  return insn->n;
407  break;
408 
409  default:
410  return -EINVAL;
411  break;
412  }
413 
414  return insn->n;
415 }
416 
417 static void switch_page(struct comedi_device *dev, int asic, int page)
418 {
419  const struct pcmmio_board *board = comedi_board(dev);
420 
421  if (asic < 0 || asic >= board->dio_num_asics)
422  return; /* paranoia */
424  return; /* more paranoia */
425 
426  devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
427  devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
428 
429  /* now write out the shadow register */
430  outb(devpriv->asics[asic].pagelock,
431  devpriv->asics[asic].iobase + REG_PAGELOCK);
432 }
433 
434 static void init_asics(struct comedi_device *dev)
435 { /* sets up an
436  ASIC chip to defaults */
437  const struct pcmmio_board *board = comedi_board(dev);
438  int asic;
439 
440  for (asic = 0; asic < board->dio_num_asics; ++asic) {
441  int port, page;
442  unsigned long baseaddr = devpriv->asics[asic].iobase;
443 
444  switch_page(dev, asic, 0); /* switch back to page 0 */
445 
446  /* first, clear all the DIO port bits */
447  for (port = 0; port < PORTS_PER_ASIC; ++port)
448  outb(0, baseaddr + REG_PORT0 + port);
449 
450  /* Next, clear all the paged registers for each page */
451  for (page = 1; page < NUM_PAGES; ++page) {
452  int reg;
453  /* now clear all the paged registers */
454  switch_page(dev, asic, page);
455  for (reg = FIRST_PAGED_REG;
457  outb(0, baseaddr + reg);
458  }
459 
460  /* DEBUG set rising edge interrupts on port0 of both asics */
461  /*switch_page(dev, asic, PAGE_POL);
462  outb(0xff, baseaddr + REG_POL0);
463  switch_page(dev, asic, PAGE_ENAB);
464  outb(0xff, baseaddr + REG_ENAB0); */
465  /* END DEBUG */
466 
467  /* switch back to default page 0 */
468  switch_page(dev, asic, 0);
469  }
470 }
471 
472 #ifdef notused
473 static void lock_port(struct comedi_device *dev, int asic, int port)
474 {
475  const struct pcmmio_board *board = comedi_board(dev);
476 
477  if (asic < 0 || asic >= board->dio_num_asics)
478  return; /* paranoia */
479  if (port < 0 || port >= PORTS_PER_ASIC)
480  return; /* more paranoia */
481 
482  devpriv->asics[asic].pagelock |= 0x1 << port;
483  /* now write out the shadow register */
484  outb(devpriv->asics[asic].pagelock,
485  devpriv->asics[asic].iobase + REG_PAGELOCK);
486  return;
487 }
488 
489 static void unlock_port(struct comedi_device *dev, int asic, int port)
490 {
491  const struct pcmmio_board *board = comedi_board(dev);
492 
493  if (asic < 0 || asic >= board->dio_num_asics)
494  return; /* paranoia */
495  if (port < 0 || port >= PORTS_PER_ASIC)
496  return; /* more paranoia */
497  devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
498  /* now write out the shadow register */
499  outb(devpriv->asics[asic].pagelock,
500  devpriv->asics[asic].iobase + REG_PAGELOCK);
501 }
502 #endif /* notused */
503 
504 static void pcmmio_stop_intr(struct comedi_device *dev,
505  struct comedi_subdevice *s)
506 {
507  int nports, firstport, asic, port;
508 
509  asic = subpriv->dio.intr.asic;
510  if (asic < 0)
511  return; /* not an interrupt subdev */
512 
513  subpriv->dio.intr.enabled_mask = 0;
514  subpriv->dio.intr.active = 0;
515  s->async->inttrig = NULL;
516  nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
517  firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
518  switch_page(dev, asic, PAGE_ENAB);
519  for (port = firstport; port < firstport + nports; ++port) {
520  /* disable all intrs for this subdev.. */
521  outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
522  }
523 }
524 
525 static irqreturn_t interrupt_pcmmio(int irq, void *d)
526 {
527  int asic, got1 = 0;
528  struct comedi_device *dev = (struct comedi_device *)d;
529  int i;
530 
531  for (asic = 0; asic < MAX_ASICS; ++asic) {
532  if (irq == devpriv->asics[asic].irq) {
533  unsigned long flags;
534  unsigned triggered = 0;
535  unsigned long iobase = devpriv->asics[asic].iobase;
536  /* it is an interrupt for ASIC #asic */
537  unsigned char int_pend;
538 
539  spin_lock_irqsave(&devpriv->asics[asic].spinlock,
540  flags);
541 
542  int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
543 
544  if (int_pend) {
545  int port;
546  for (port = 0; port < INTR_PORTS_PER_ASIC;
547  ++port) {
548  if (int_pend & (0x1 << port)) {
549  unsigned char
550  io_lines_with_edges = 0;
551  switch_page(dev, asic,
552  PAGE_INT_ID);
553  io_lines_with_edges =
554  inb(iobase +
555  REG_INT_ID0 + port);
556 
557  if (io_lines_with_edges)
558  /*
559  * clear pending
560  * interrupt
561  */
562  outb(0, iobase +
563  REG_INT_ID0 +
564  port);
565 
566  triggered |=
567  io_lines_with_edges <<
568  port * 8;
569  }
570  }
571 
572  ++got1;
573  }
574 
575  spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
576  flags);
577 
578  if (triggered) {
579  struct comedi_subdevice *s;
580  /*
581  * TODO here: dispatch io lines to subdevs
582  * with commands..
583  */
584  printk
585  (KERN_DEBUG "got edge detect interrupt %d asic %d which_chans: %06x\n",
586  irq, asic, triggered);
587  for (i = 2; i < dev->n_subdevices; i++) {
588  s = &dev->subdevices[i];
589  /*
590  * this is an interrupt subdev,
591  * and it matches this asic!
592  */
593  if (subpriv->dio.intr.asic == asic) {
594  unsigned long flags;
595  unsigned oldevents;
596 
598  intr.spinlock,
599  flags);
600 
601  oldevents = s->async->events;
602 
603  if (subpriv->dio.intr.active) {
604  unsigned mytrig =
605  ((triggered >>
606  subpriv->dio.intr.asic_chan)
607  &
608  ((0x1 << subpriv->
609  dio.intr.
610  num_asic_chans) -
611  1)) << subpriv->
612  dio.intr.first_chan;
613  if (mytrig &
614  subpriv->dio.
615  intr.enabled_mask) {
616  unsigned int val
617  = 0;
618  unsigned int n,
619  ch, len;
620 
621  len =
622  s->
623  async->cmd.chanlist_len;
624  for (n = 0;
625  n < len;
626  n++) {
627  ch = CR_CHAN(s->async->cmd.chanlist[n]);
628  if (mytrig & (1U << ch))
629  val |= (1U << n);
630  }
631  /* Write the scan to the buffer. */
632  if (comedi_buf_put(s->async, ((short *)&val)[0])
633  &&
635  (s->async,
636  ((short *)
637  &val)[1])) {
638  s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
639  } else {
640  /* Overflow! Stop acquisition!! */
641  /* TODO: STOP_ACQUISITION_CALL_HERE!! */
642  pcmmio_stop_intr
643  (dev,
644  s);
645  }
646 
647  /* Check for end of acquisition. */
648  if (!subpriv->dio.intr.continuous) {
649  /* stop_src == TRIG_COUNT */
650  if (subpriv->dio.intr.stop_count > 0) {
651  subpriv->dio.intr.stop_count--;
652  if (subpriv->dio.intr.stop_count == 0) {
653  s->async->events |= COMEDI_CB_EOA;
654  /* TODO: STOP_ACQUISITION_CALL_HERE!! */
655  pcmmio_stop_intr
656  (dev,
657  s);
658  }
659  }
660  }
661  }
662  }
663 
664  spin_unlock_irqrestore
665  (&subpriv->dio.intr.
666  spinlock, flags);
667 
668  if (oldevents !=
669  s->async->events) {
670  comedi_event(dev, s);
671  }
672 
673  }
674 
675  }
676  }
677 
678  }
679  }
680  if (!got1)
681  return IRQ_NONE; /* interrupt from other source */
682  return IRQ_HANDLED;
683 }
684 
685 static int pcmmio_start_intr(struct comedi_device *dev,
686  struct comedi_subdevice *s)
687 {
688  if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
689  /* An empty acquisition! */
690  s->async->events |= COMEDI_CB_EOA;
691  subpriv->dio.intr.active = 0;
692  return 1;
693  } else {
694  unsigned bits = 0, pol_bits = 0, n;
695  int nports, firstport, asic, port;
696  struct comedi_cmd *cmd = &s->async->cmd;
697 
698  asic = subpriv->dio.intr.asic;
699  if (asic < 0)
700  return 1; /* not an interrupt
701  subdev */
702  subpriv->dio.intr.enabled_mask = 0;
703  subpriv->dio.intr.active = 1;
704  nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
705  firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
706  if (cmd->chanlist) {
707  for (n = 0; n < cmd->chanlist_len; n++) {
708  bits |= (1U << CR_CHAN(cmd->chanlist[n]));
709  pol_bits |= (CR_AREF(cmd->chanlist[n])
710  || CR_RANGE(cmd->
711  chanlist[n]) ? 1U : 0U)
712  << CR_CHAN(cmd->chanlist[n]);
713  }
714  }
715  bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
716  1) << subpriv->dio.intr.first_chan;
717  subpriv->dio.intr.enabled_mask = bits;
718 
719  {
720  /*
721  * the below code configures the board
722  * to use a specific IRQ from 0-15.
723  */
724  unsigned char b;
725  /*
726  * set resource enable register
727  * to enable IRQ operation
728  */
729  outb(1 << 4, dev->iobase + 3);
730  /* set bits 0-3 of b to the irq number from 0-15 */
731  b = dev->irq & ((1 << 4) - 1);
732  outb(b, dev->iobase + 2);
733  /* done, we told the board what irq to use */
734  }
735 
736  switch_page(dev, asic, PAGE_ENAB);
737  for (port = firstport; port < firstport + nports; ++port) {
738  unsigned enab =
739  bits >> (subpriv->dio.intr.first_chan + (port -
740  firstport)
741  * 8) & 0xff, pol =
742  pol_bits >> (subpriv->dio.intr.first_chan +
743  (port - firstport) * 8) & 0xff;
744  /* set enab intrs for this subdev.. */
745  outb(enab,
746  devpriv->asics[asic].iobase + REG_ENAB0 + port);
747  switch_page(dev, asic, PAGE_POL);
748  outb(pol,
749  devpriv->asics[asic].iobase + REG_ENAB0 + port);
750  }
751  }
752  return 0;
753 }
754 
755 static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
756 {
757  unsigned long flags;
758 
759  spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
760  if (subpriv->dio.intr.active)
761  pcmmio_stop_intr(dev, s);
762  spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
763 
764  return 0;
765 }
766 
767 /*
768  * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
769  */
770 static int
771 pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
772  unsigned int trignum)
773 {
774  unsigned long flags;
775  int event = 0;
776 
777  if (trignum != 0)
778  return -EINVAL;
779 
780  spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
781  s->async->inttrig = NULL;
782  if (subpriv->dio.intr.active)
783  event = pcmmio_start_intr(dev, s);
784  spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
785 
786  if (event)
787  comedi_event(dev, s);
788 
789  return 1;
790 }
791 
792 /*
793  * 'do_cmd' function for an 'INTERRUPT' subdevice.
794  */
795 static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
796 {
797  struct comedi_cmd *cmd = &s->async->cmd;
798  unsigned long flags;
799  int event = 0;
800 
801  spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
802  subpriv->dio.intr.active = 1;
803 
804  /* Set up end of acquisition. */
805  switch (cmd->stop_src) {
806  case TRIG_COUNT:
807  subpriv->dio.intr.continuous = 0;
808  subpriv->dio.intr.stop_count = cmd->stop_arg;
809  break;
810  default:
811  /* TRIG_NONE */
812  subpriv->dio.intr.continuous = 1;
813  subpriv->dio.intr.stop_count = 0;
814  break;
815  }
816 
817  /* Set up start of acquisition. */
818  switch (cmd->start_src) {
819  case TRIG_INT:
820  s->async->inttrig = pcmmio_inttrig_start_intr;
821  break;
822  default:
823  /* TRIG_NOW */
824  event = pcmmio_start_intr(dev, s);
825  break;
826  }
827  spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
828 
829  if (event)
830  comedi_event(dev, s);
831 
832  return 0;
833 }
834 
835 static int
836 pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
837  struct comedi_cmd *cmd)
838 {
839  return comedi_pcm_cmdtest(dev, s, cmd);
840 }
841 
842 static int adc_wait_ready(unsigned long iobase)
843 {
844  unsigned long retry = 100000;
845  while (retry--)
846  if (inb(iobase + 3) & 0x80)
847  return 0;
848  return 1;
849 }
850 
851 /* All this is for AI and AO */
852 static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
853  struct comedi_insn *insn, unsigned int *data)
854 {
855  int n;
856  unsigned long iobase = subpriv->iobase;
857 
858  /*
859  1. write the CMD byte (to BASE+2)
860  2. read junk lo byte (BASE+0)
861  3. read junk hi byte (BASE+1)
862  4. (mux settled so) write CMD byte again (BASE+2)
863  5. read valid lo byte(BASE+0)
864  6. read valid hi byte(BASE+1)
865 
866  Additionally note that the BASE += 4 if the channel >= 8
867  */
868 
869  /* convert n samples */
870  for (n = 0; n < insn->n; n++) {
871  unsigned chan = CR_CHAN(insn->chanspec), range =
872  CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
873  unsigned char command_byte = 0;
874  unsigned iooffset = 0;
875  short sample, adc_adjust = 0;
876 
877  if (chan > 7)
878  chan -= 8, iooffset = 4; /*
879  * use the second dword
880  * for channels > 7
881  */
882 
883  if (aref != AREF_DIFF) {
884  aref = AREF_GROUND;
885  command_byte |= 1 << 7; /*
886  * set bit 7 to indicate
887  * single-ended
888  */
889  }
890  if (range < 2)
891  adc_adjust = 0x8000; /*
892  * bipolar ranges
893  * (-5,5 .. -10,10 need to be
894  * adjusted -- that is.. they
895  * need to wrap around by
896  * adding 0x8000
897  */
898 
899  if (chan % 2) {
900  command_byte |= 1 << 6; /*
901  * odd-numbered channels
902  * have bit 6 set
903  */
904  }
905 
906  /* select the channel, bits 4-5 == chan/2 */
907  command_byte |= ((chan / 2) & 0x3) << 4;
908 
909  /* set the range, bits 2-3 */
910  command_byte |= (range & 0x3) << 2;
911 
912  /* need to do this twice to make sure mux settled */
913  /* chan/range/aref select */
914  outb(command_byte, iobase + iooffset + 2);
915 
916  /* wait for the adc to say it finised the conversion */
917  adc_wait_ready(iobase + iooffset);
918 
919  /* select the chan/range/aref AGAIN */
920  outb(command_byte, iobase + iooffset + 2);
921 
922  adc_wait_ready(iobase + iooffset);
923 
924  /* read data lo byte */
925  sample = inb(iobase + iooffset + 0);
926 
927  /* read data hi byte */
928  sample |= inb(iobase + iooffset + 1) << 8;
929  sample += adc_adjust; /* adjustment .. munge data */
930  data[n] = sample;
931  }
932  /* return the number of samples read/written */
933  return n;
934 }
935 
936 static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
937  struct comedi_insn *insn, unsigned int *data)
938 {
939  int n;
940  for (n = 0; n < insn->n; n++) {
941  unsigned chan = CR_CHAN(insn->chanspec);
942  if (chan < s->n_chan)
943  data[n] = subpriv->ao.shadow_samples[chan];
944  }
945  return n;
946 }
947 
948 static int wait_dac_ready(unsigned long iobase)
949 {
950  unsigned long retry = 100000L;
951 
952  /* This may seem like an absurd way to handle waiting and violates the
953  "no busy waiting" policy. The fact is that the hardware is
954  normally so fast that we usually only need one time through the loop
955  anyway. The longer timeout is for rare occasions and for detecting
956  non-existent hardware. */
957 
958  while (retry--) {
959  if (inb(iobase + 3) & 0x80)
960  return 0;
961 
962  }
963  return 1;
964 }
965 
966 static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
967  struct comedi_insn *insn, unsigned int *data)
968 {
969  int n;
970  unsigned iobase = subpriv->iobase, iooffset = 0;
971 
972  for (n = 0; n < insn->n; n++) {
973  unsigned chan = CR_CHAN(insn->chanspec), range =
974  CR_RANGE(insn->chanspec);
975  if (chan < s->n_chan) {
976  unsigned char command_byte = 0, range_byte =
977  range & ((1 << 4) - 1);
978  if (chan >= 4)
979  chan -= 4, iooffset += 4;
980  /* set the range.. */
981  outb(range_byte, iobase + iooffset + 0);
982  outb(0, iobase + iooffset + 1);
983 
984  /* tell it to begin */
985  command_byte = (chan << 1) | 0x60;
986  outb(command_byte, iobase + iooffset + 2);
987 
988  wait_dac_ready(iobase + iooffset);
989 
990  /* low order byte */
991  outb(data[n] & 0xff, iobase + iooffset + 0);
992 
993  /* high order byte */
994  outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);
995 
996  /*
997  * set bit 4 of command byte to indicate
998  * data is loaded and trigger conversion
999  */
1000  command_byte = 0x70 | (chan << 1);
1001  /* trigger converion */
1002  outb(command_byte, iobase + iooffset + 2);
1003 
1004  wait_dac_ready(iobase + iooffset);
1005 
1006  /* save to shadow register for ao_rinsn */
1007  subpriv->ao.shadow_samples[chan] = data[n];
1008  }
1009  }
1010  return n;
1011 }
1012 
1013 static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1014 {
1015  const struct pcmmio_board *board = comedi_board(dev);
1016  struct comedi_subdevice *s;
1017  int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
1018  thisasic_chanct = 0;
1019  unsigned long iobase;
1020  unsigned int irq[MAX_ASICS];
1021  int ret;
1022 
1023  iobase = it->options[0];
1024  irq[0] = it->options[1];
1025 
1026  printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
1027  dev->driver->driver_name, iobase);
1028 
1029  dev->iobase = iobase;
1030 
1031  if (!iobase || !request_region(iobase,
1032  board->total_iosize,
1033  dev->driver->driver_name)) {
1034  printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
1035  return -EIO;
1036  }
1037 
1038  dev->board_name = board->name;
1039 
1040 /*
1041  * Allocate the private structure area. alloc_private() is a
1042  * convenient macro defined in comedidev.h.
1043  */
1044  if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
1045  printk(KERN_ERR "comedi%d: cannot allocate private data structure\n",
1046  dev->minor);
1047  return -ENOMEM;
1048  }
1049 
1050  for (asic = 0; asic < MAX_ASICS; ++asic) {
1051  devpriv->asics[asic].num = asic;
1052  devpriv->asics[asic].iobase =
1053  dev->iobase + 16 + asic * ASIC_IOSIZE;
1054  /*
1055  * this gets actually set at the end of this function when we
1056  * request_irqs
1057  */
1058  devpriv->asics[asic].irq = 0;
1059  spin_lock_init(&devpriv->asics[asic].spinlock);
1060  }
1061 
1062  chans_left = CHANS_PER_ASIC * board->dio_num_asics;
1063  n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
1064  n_subdevs = n_dio_subdevs + 2;
1065  devpriv->sprivs =
1066  kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
1067  GFP_KERNEL);
1068  if (!devpriv->sprivs) {
1069  printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
1070  dev->minor);
1071  return -ENOMEM;
1072  }
1073 
1074  ret = comedi_alloc_subdevices(dev, n_subdevs);
1075  if (ret)
1076  return ret;
1077 
1078  /* First, AI */
1079  s = &dev->subdevices[0];
1080  s->private = &devpriv->sprivs[0];
1081  s->maxdata = (1 << board->ai_bits) - 1;
1082  s->range_table = board->ai_range_table;
1084  s->type = COMEDI_SUBD_AI;
1085  s->n_chan = board->n_ai_chans;
1086  s->len_chanlist = s->n_chan;
1087  s->insn_read = board->ai_rinsn;
1088  subpriv->iobase = dev->iobase + 0;
1089  /* initialize the resource enable register by clearing it */
1090  outb(0, subpriv->iobase + 3);
1091  outb(0, subpriv->iobase + 4 + 3);
1092 
1093  /* Next, AO */
1094  s = &dev->subdevices[1];
1095  s->private = &devpriv->sprivs[1];
1096  s->maxdata = (1 << board->ao_bits) - 1;
1097  s->range_table = board->ao_range_table;
1099  s->type = COMEDI_SUBD_AO;
1100  s->n_chan = board->n_ao_chans;
1101  s->len_chanlist = s->n_chan;
1102  s->insn_read = board->ao_rinsn;
1103  s->insn_write = board->ao_winsn;
1104  subpriv->iobase = dev->iobase + 8;
1105  /* initialize the resource enable register by clearing it */
1106  outb(0, subpriv->iobase + 3);
1107  outb(0, subpriv->iobase + 4 + 3);
1108 
1109  port = 0;
1110  asic = 0;
1111  for (sdev_no = 2; sdev_no < dev->n_subdevices; ++sdev_no) {
1112  int byte_no;
1113 
1114  s = &dev->subdevices[sdev_no];
1115  s->private = &devpriv->sprivs[sdev_no];
1116  s->maxdata = 1;
1117  s->range_table = &range_digital;
1119  s->type = COMEDI_SUBD_DIO;
1120  s->insn_bits = pcmmio_dio_insn_bits;
1121  s->insn_config = pcmmio_dio_insn_config;
1122  s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
1123  subpriv->dio.intr.asic = -1;
1124  subpriv->dio.intr.first_chan = -1;
1125  subpriv->dio.intr.asic_chan = -1;
1126  subpriv->dio.intr.num_asic_chans = -1;
1127  subpriv->dio.intr.active = 0;
1128  s->len_chanlist = 1;
1129 
1130  /* save the ioport address for each 'port' of 8 channels in the
1131  subdevice */
1132  for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
1133  if (port >= PORTS_PER_ASIC) {
1134  port = 0;
1135  ++asic;
1136  thisasic_chanct = 0;
1137  }
1138  subpriv->iobases[byte_no] =
1139  devpriv->asics[asic].iobase + port;
1140 
1141  if (thisasic_chanct <
1142  CHANS_PER_PORT * INTR_PORTS_PER_ASIC
1143  && subpriv->dio.intr.asic < 0) {
1144  /*
1145  * this is an interrupt subdevice,
1146  * so setup the struct
1147  */
1148  subpriv->dio.intr.asic = asic;
1149  subpriv->dio.intr.active = 0;
1150  subpriv->dio.intr.stop_count = 0;
1151  subpriv->dio.intr.first_chan = byte_no * 8;
1152  subpriv->dio.intr.asic_chan = thisasic_chanct;
1153  subpriv->dio.intr.num_asic_chans =
1154  s->n_chan - subpriv->dio.intr.first_chan;
1155  s->cancel = pcmmio_cancel;
1156  s->do_cmd = pcmmio_cmd;
1157  s->do_cmdtest = pcmmio_cmdtest;
1158  s->len_chanlist =
1159  subpriv->dio.intr.num_asic_chans;
1160  }
1161  thisasic_chanct += CHANS_PER_PORT;
1162  }
1163  spin_lock_init(&subpriv->dio.intr.spinlock);
1164 
1165  chans_left -= s->n_chan;
1166 
1167  if (!chans_left) {
1168  /*
1169  * reset the asic to our first asic,
1170  * to do intr subdevs
1171  */
1172  asic = 0;
1173  port = 0;
1174  }
1175 
1176  }
1177 
1178  init_asics(dev); /* clear out all the registers, basically */
1179 
1180  for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
1181  if (irq[asic]
1182  && request_irq(irq[asic], interrupt_pcmmio,
1183  IRQF_SHARED, board->name, dev)) {
1184  int i;
1185  /* unroll the allocated irqs.. */
1186  for (i = asic - 1; i >= 0; --i) {
1187  free_irq(irq[i], dev);
1188  devpriv->asics[i].irq = irq[i] = 0;
1189  }
1190  irq[asic] = 0;
1191  }
1192  devpriv->asics[asic].irq = irq[asic];
1193  }
1194 
1195  dev->irq = irq[0]; /*
1196  * grr.. wish comedi dev struct supported
1197  * multiple irqs..
1198  */
1199 
1200  printk(KERN_INFO "comedi%d: attached\n", dev->minor);
1201 
1202  return 1;
1203 }
1204 
1205 static void pcmmio_detach(struct comedi_device *dev)
1206 {
1207  const struct pcmmio_board *board = comedi_board(dev);
1208  int i;
1209 
1210  if (dev->iobase)
1211  release_region(dev->iobase, board->total_iosize);
1212  for (i = 0; i < MAX_ASICS; ++i) {
1213  if (devpriv && devpriv->asics[i].irq)
1214  free_irq(devpriv->asics[i].irq, dev);
1215  }
1216  if (devpriv && devpriv->sprivs)
1217  kfree(devpriv->sprivs);
1218 }
1219 
1220 static const struct pcmmio_board pcmmio_boards[] = {
1221  {
1222  .name = "pcmmio",
1223  .dio_num_asics = 1,
1224  .dio_num_ports = 6,
1225  .total_iosize = 32,
1226  .ai_bits = 16,
1227  .ao_bits = 16,
1228  .n_ai_chans = 16,
1229  .n_ao_chans = 8,
1230  .ai_range_table = &ranges_ai,
1231  .ao_range_table = &ranges_ao,
1232  .ai_rinsn = ai_rinsn,
1233  .ao_rinsn = ao_rinsn,
1234  .ao_winsn = ao_winsn
1235  },
1236 };
1237 
1238 static struct comedi_driver pcmmio_driver = {
1239  .driver_name = "pcmmio",
1240  .module = THIS_MODULE,
1241  .attach = pcmmio_attach,
1242  .detach = pcmmio_detach,
1243  .board_name = &pcmmio_boards[0].name,
1244  .offset = sizeof(struct pcmmio_board),
1245  .num_names = ARRAY_SIZE(pcmmio_boards),
1246 };
1247 module_comedi_driver(pcmmio_driver);
1248 
1249 MODULE_AUTHOR("Comedi http://www.comedi.org");
1250 MODULE_DESCRIPTION("Comedi low-level driver");
1251 MODULE_LICENSE("GPL");