KVM: x86: update KVM_SAVE_MSRS_BEGIN to correct value
[cascardo/linux.git] / drivers / staging / comedi / drivers / pcmmio.c
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 <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 /*
23 Driver: pcmmio
24 Description: A driver for the PCM-MIO multifunction board
25 Devices: [Winsystems] PCM-MIO (pcmmio)
26 Author: Calin Culianu <calin@ajvar.org>
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
136
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;
162         const struct comedi_lrange *ai_range_table, *ao_range_table;
163         int (*ai_rinsn) (struct comedi_device *dev,
164                         struct comedi_subdevice *s,
165                         struct comedi_insn *insn,
166                         unsigned int *data);
167         int (*ao_rinsn) (struct comedi_device *dev,
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 /*
187  * Useful for shorthand access to the particular board structure
188  */
189 #define thisboard ((const struct pcmmio_board *)dev->board_ptr)
190
191 /* this structure is for data unique to this subdevice.  */
192 struct pcmmio_subdev_private {
193
194         union {
195                 /* for DIO: mapping of halfwords (bytes)
196                    in port/chanarray to iobase */
197                 unsigned long iobases[PORTS_PER_SUBDEV];
198
199                 /* for AI/AO */
200                 unsigned long iobase;
201         };
202         union {
203                 struct {
204
205                         /* The below is only used for intr subdevices */
206                         struct {
207                                 /*
208                                  * if non-negative, this subdev has an
209                                  * interrupt asic
210                                  */
211                                 int asic;
212                                 /*
213                                  * if nonnegative, the first channel id for
214                                  * interrupts.
215                                  */
216                                 int first_chan;
217                                 /*
218                                  * the number of asic channels in this subdev
219                                  * that have interrutps
220                                  */
221                                 int num_asic_chans;
222                                 /*
223                                  * if nonnegative, the first channel id with
224                                  * respect to the asic that has interrupts
225                                  */
226                                 int asic_chan;
227                                 /*
228                                  * subdev-relative channel mask for channels
229                                  * we are interested in
230                                  */
231                                 int enabled_mask;
232                                 int active;
233                                 int stop_count;
234                                 int continuous;
235                                 spinlock_t spinlock;
236                         } intr;
237                 } dio;
238                 struct {
239                         /* the last unsigned int data written */
240                         unsigned int shadow_samples[8];
241                 } ao;
242         };
243 };
244
245 /*
246  * this structure is for data unique to this hardware driver.  If
247  * several hardware drivers keep similar information in this structure,
248  * feel free to suggest moving the variable to the struct comedi_device struct.
249  */
250 struct pcmmio_private {
251         /* stuff for DIO */
252         struct {
253                 unsigned char pagelock; /* current page and lock */
254                 /* shadow of POLx registers */
255                 unsigned char pol[NUM_PAGED_REGS];
256                 /* shadow of ENABx registers */
257                 unsigned char enab[NUM_PAGED_REGS];
258                 int num;
259                 unsigned long iobase;
260                 unsigned int irq;
261                 spinlock_t spinlock;
262         } asics[MAX_ASICS];
263         struct pcmmio_subdev_private *sprivs;
264 };
265
266 /*
267  * most drivers define the following macro to make it easy to
268  * access the private structure.
269  */
270 #define devpriv ((struct pcmmio_private *)dev->private)
271 #define subpriv ((struct pcmmio_subdev_private *)s->private)
272
273 /* DIO devices are slightly special.  Although it is possible to
274  * implement the insn_read/insn_write interface, it is much more
275  * useful to applications if you implement the insn_bits interface.
276  * This allows packed reading/writing of the DIO channels.  The
277  * comedi core can convert between insn_bits and insn_read/write */
278 static int pcmmio_dio_insn_bits(struct comedi_device *dev,
279                                 struct comedi_subdevice *s,
280                                 struct comedi_insn *insn, unsigned int *data)
281 {
282         int byte_no;
283         if (insn->n != 2)
284                 return -EINVAL;
285
286         /* NOTE:
287            reading a 0 means this channel was high
288            writine a 0 sets the channel high
289            reading a 1 means this channel was low
290            writing a 1 means set this channel low
291
292            Therefore everything is always inverted. */
293
294         /* The insn data is a mask in data[0] and the new data
295          * in data[1], each channel cooresponding to a bit. */
296
297 #ifdef DAMMIT_ITS_BROKEN
298         /* DEBUG */
299         printk(KERN_DEBUG "write mask: %08x  data: %08x\n", data[0], data[1]);
300 #endif
301
302         s->state = 0;
303
304         for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
305                 /* address of 8-bit port */
306                 unsigned long ioaddr = subpriv->iobases[byte_no],
307                     /* bit offset of port in 32-bit doubleword */
308                     offset = byte_no * 8;
309                 /* this 8-bit port's data */
310                 unsigned char byte = 0,
311                     /* The write mask for this port (if any) */
312                     write_mask_byte = (data[0] >> offset) & 0xff,
313                     /* The data byte for this port */
314                     data_byte = (data[1] >> offset) & 0xff;
315
316                 byte = inb(ioaddr);     /* read all 8-bits for this port */
317
318 #ifdef DAMMIT_ITS_BROKEN
319                 /* DEBUG */
320                 printk
321                     (KERN_DEBUG "byte %d wmb %02x db %02x offset %02d io %04x,"
322                      " data_in %02x ", byte_no, (unsigned)write_mask_byte,
323                      (unsigned)data_byte, offset, ioaddr, (unsigned)byte);
324 #endif
325
326                 if (write_mask_byte) {
327                         /*
328                          * this byte has some write_bits
329                          * -- so set the output lines
330                          */
331                         /* clear bits for write mask */
332                         byte &= ~write_mask_byte;
333                         /* set to inverted data_byte */
334                         byte |= ~data_byte & write_mask_byte;
335                         /* Write out the new digital output state */
336                         outb(byte, ioaddr);
337                 }
338 #ifdef DAMMIT_ITS_BROKEN
339                 /* DEBUG */
340                 printk(KERN_DEBUG "data_out_byte %02x\n", (unsigned)byte);
341 #endif
342                 /* save the digital input lines for this byte.. */
343                 s->state |= ((unsigned int)byte) << offset;
344         }
345
346         /* now return the DIO lines to data[1] - note they came inverted! */
347         data[1] = ~s->state;
348
349 #ifdef DAMMIT_ITS_BROKEN
350         /* DEBUG */
351         printk(KERN_DEBUG "s->state %08x data_out %08x\n", s->state, data[1]);
352 #endif
353
354         return 2;
355 }
356
357 /* The input or output configuration of each digital line is
358  * configured by a special insn_config instruction.  chanspec
359  * contains the channel to be changed, and data[0] contains the
360  * value COMEDI_INPUT or COMEDI_OUTPUT. */
361 static int pcmmio_dio_insn_config(struct comedi_device *dev,
362                                   struct comedi_subdevice *s,
363                                   struct comedi_insn *insn, unsigned int *data)
364 {
365         int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
366             chan % 8;
367         unsigned long ioaddr;
368         unsigned char byte;
369
370         /* Compute ioaddr for this channel */
371         ioaddr = subpriv->iobases[byte_no];
372
373         /* NOTE:
374            writing a 0 an IO channel's bit sets the channel to INPUT
375            and pulls the line high as well
376
377            writing a 1 to an IO channel's  bit pulls the line low
378
379            All channels are implicitly always in OUTPUT mode -- but when
380            they are high they can be considered to be in INPUT mode..
381
382            Thus, we only force channels low if the config request was INPUT,
383            otherwise we do nothing to the hardware.    */
384
385         switch (data[0]) {
386         case INSN_CONFIG_DIO_OUTPUT:
387                 /* save to io_bits -- don't actually do anything since
388                    all input channels are also output channels... */
389                 s->io_bits |= 1 << chan;
390                 break;
391         case INSN_CONFIG_DIO_INPUT:
392                 /* write a 0 to the actual register representing the channel
393                    to set it to 'input'.  0 means "float high". */
394                 byte = inb(ioaddr);
395                 byte &= ~(1 << bit_no);
396                                 /**< set input channel to '0' */
397
398                 /*
399                  * write out byte -- this is the only time we actually affect
400                  * the hardware as all channels are implicitly output
401                  * -- but input channels are set to float-high
402                  */
403                 outb(byte, ioaddr);
404
405                 /* save to io_bits */
406                 s->io_bits &= ~(1 << chan);
407                 break;
408
409         case INSN_CONFIG_DIO_QUERY:
410                 /* retrieve from shadow register */
411                 data[1] =
412                     (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
413                 return insn->n;
414                 break;
415
416         default:
417                 return -EINVAL;
418                 break;
419         }
420
421         return insn->n;
422 }
423
424 static void switch_page(struct comedi_device *dev, int asic, int page)
425 {
426         if (asic < 0 || asic >= thisboard->dio_num_asics)
427                 return;         /* paranoia */
428         if (page < 0 || page >= NUM_PAGES)
429                 return;         /* more paranoia */
430
431         devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
432         devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
433
434         /* now write out the shadow register */
435         outb(devpriv->asics[asic].pagelock,
436              devpriv->asics[asic].iobase + REG_PAGELOCK);
437 }
438
439 static void init_asics(struct comedi_device *dev)
440 {                               /* sets up an
441                                    ASIC chip to defaults */
442         int asic;
443
444         for (asic = 0; asic < thisboard->dio_num_asics; ++asic) {
445                 int port, page;
446                 unsigned long baseaddr = devpriv->asics[asic].iobase;
447
448                 switch_page(dev, asic, 0);      /* switch back to page 0 */
449
450                 /* first, clear all the DIO port bits */
451                 for (port = 0; port < PORTS_PER_ASIC; ++port)
452                         outb(0, baseaddr + REG_PORT0 + port);
453
454                 /* Next, clear all the paged registers for each page */
455                 for (page = 1; page < NUM_PAGES; ++page) {
456                         int reg;
457                         /* now clear all the paged registers */
458                         switch_page(dev, asic, page);
459                         for (reg = FIRST_PAGED_REG;
460                              reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
461                                 outb(0, baseaddr + reg);
462                 }
463
464                 /* DEBUG  set rising edge interrupts on port0 of both asics */
465                 /*switch_page(dev, asic, PAGE_POL);
466                    outb(0xff, baseaddr + REG_POL0);
467                    switch_page(dev, asic, PAGE_ENAB);
468                    outb(0xff, baseaddr + REG_ENAB0); */
469                 /* END DEBUG */
470
471                 /* switch back to default page 0 */
472                 switch_page(dev, asic, 0);
473         }
474 }
475
476 #ifdef notused
477 static void lock_port(struct comedi_device *dev, int asic, int port)
478 {
479         if (asic < 0 || asic >= thisboard->dio_num_asics)
480                 return;         /* paranoia */
481         if (port < 0 || port >= PORTS_PER_ASIC)
482                 return;         /* more paranoia */
483
484         devpriv->asics[asic].pagelock |= 0x1 << port;
485         /* now write out the shadow register */
486         outb(devpriv->asics[asic].pagelock,
487              devpriv->asics[asic].iobase + REG_PAGELOCK);
488         return;
489 }
490
491 static void unlock_port(struct comedi_device *dev, int asic, int port)
492 {
493         if (asic < 0 || asic >= thisboard->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 = 0;
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
530         for (asic = 0; asic < MAX_ASICS; ++asic) {
531                 if (irq == devpriv->asics[asic].irq) {
532                         unsigned long flags;
533                         unsigned triggered = 0;
534                         unsigned long iobase = devpriv->asics[asic].iobase;
535                         /* it is an interrupt for ASIC #asic */
536                         unsigned char int_pend;
537
538                         spin_lock_irqsave(&devpriv->asics[asic].spinlock,
539                                           flags);
540
541                         int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
542
543                         if (int_pend) {
544                                 int port;
545                                 for (port = 0; port < INTR_PORTS_PER_ASIC;
546                                      ++port) {
547                                         if (int_pend & (0x1 << port)) {
548                                                 unsigned char
549                                                     io_lines_with_edges = 0;
550                                                 switch_page(dev, asic,
551                                                             PAGE_INT_ID);
552                                                 io_lines_with_edges =
553                                                     inb(iobase +
554                                                         REG_INT_ID0 + port);
555
556                                                 if (io_lines_with_edges)
557                                                         /*
558                                                          * clear pending
559                                                          * interrupt
560                                                          */
561                                                         outb(0, iobase +
562                                                              REG_INT_ID0 +
563                                                              port);
564
565                                                 triggered |=
566                                                     io_lines_with_edges <<
567                                                     port * 8;
568                                         }
569                                 }
570
571                                 ++got1;
572                         }
573
574                         spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
575                                                flags);
576
577                         if (triggered) {
578                                 struct comedi_subdevice *s;
579                                 /*
580                                  * TODO here: dispatch io lines to subdevs
581                                  * with commands..
582                                  */
583                                 printk
584                                     (KERN_DEBUG "got edge detect interrupt %d asic %d which_chans: %06x\n",
585                                      irq, asic, triggered);
586                                 for (s = dev->subdevices + 2;
587                                      s < dev->subdevices + dev->n_subdevices;
588                                      ++s) {
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
597                                                 spin_lock_irqsave(&subpriv->dio.
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                                                                     &&
634                                                                     comedi_buf_put
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 = 0;
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         struct comedi_subdevice *s;
1016         int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
1017             thisasic_chanct = 0;
1018         unsigned long iobase;
1019         unsigned int irq[MAX_ASICS];
1020
1021         iobase = it->options[0];
1022         irq[0] = it->options[1];
1023
1024         printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
1025                         dev->driver->driver_name, iobase);
1026
1027         dev->iobase = iobase;
1028
1029         if (!iobase || !request_region(iobase,
1030                                        thisboard->total_iosize,
1031                                        dev->driver->driver_name)) {
1032                 printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
1033                 return -EIO;
1034         }
1035
1036 /*
1037  * Initialize dev->board_name.  Note that we can use the "thisboard"
1038  * macro now, since we just initialized it in the last line.
1039  */
1040         dev->board_name = thisboard->name;
1041
1042 /*
1043  * Allocate the private structure area.  alloc_private() is a
1044  * convenient macro defined in comedidev.h.
1045  */
1046         if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
1047                 printk(KERN_ERR "comedi%d: cannot allocate private data structure\n",
1048                                 dev->minor);
1049                 return -ENOMEM;
1050         }
1051
1052         for (asic = 0; asic < MAX_ASICS; ++asic) {
1053                 devpriv->asics[asic].num = asic;
1054                 devpriv->asics[asic].iobase =
1055                     dev->iobase + 16 + asic * ASIC_IOSIZE;
1056                 /*
1057                  * this gets actually set at the end of this function when we
1058                  * request_irqs
1059                  */
1060                 devpriv->asics[asic].irq = 0;
1061                 spin_lock_init(&devpriv->asics[asic].spinlock);
1062         }
1063
1064         chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
1065         n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
1066         n_subdevs = n_dio_subdevs + 2;
1067         devpriv->sprivs =
1068             kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
1069                     GFP_KERNEL);
1070         if (!devpriv->sprivs) {
1071                 printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
1072                                 dev->minor);
1073                 return -ENOMEM;
1074         }
1075         /*
1076          * Allocate the subdevice structures.  alloc_subdevice() is a
1077          * convenient macro defined in comedidev.h.
1078          *
1079          * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
1080          */
1081         if (alloc_subdevices(dev, n_subdevs) < 0) {
1082                 printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n",
1083                                 dev->minor);
1084                 return -ENOMEM;
1085         }
1086
1087         /* First, AI */
1088         sdev_no = 0;
1089         s = dev->subdevices + sdev_no;
1090         s->private = devpriv->sprivs + sdev_no;
1091         s->maxdata = (1 << thisboard->ai_bits) - 1;
1092         s->range_table = thisboard->ai_range_table;
1093         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
1094         s->type = COMEDI_SUBD_AI;
1095         s->n_chan = thisboard->n_ai_chans;
1096         s->len_chanlist = s->n_chan;
1097         s->insn_read = thisboard->ai_rinsn;
1098         subpriv->iobase = dev->iobase + 0;
1099         /* initialize the resource enable register by clearing it */
1100         outb(0, subpriv->iobase + 3);
1101         outb(0, subpriv->iobase + 4 + 3);
1102
1103         /* Next, AO */
1104         ++sdev_no;
1105         s = dev->subdevices + sdev_no;
1106         s->private = devpriv->sprivs + sdev_no;
1107         s->maxdata = (1 << thisboard->ao_bits) - 1;
1108         s->range_table = thisboard->ao_range_table;
1109         s->subdev_flags = SDF_READABLE;
1110         s->type = COMEDI_SUBD_AO;
1111         s->n_chan = thisboard->n_ao_chans;
1112         s->len_chanlist = s->n_chan;
1113         s->insn_read = thisboard->ao_rinsn;
1114         s->insn_write = thisboard->ao_winsn;
1115         subpriv->iobase = dev->iobase + 8;
1116         /* initialize the resource enable register by clearing it */
1117         outb(0, subpriv->iobase + 3);
1118         outb(0, subpriv->iobase + 4 + 3);
1119
1120         ++sdev_no;
1121         port = 0;
1122         asic = 0;
1123         for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
1124                 int byte_no;
1125
1126                 s = dev->subdevices + sdev_no;
1127                 s->private = devpriv->sprivs + sdev_no;
1128                 s->maxdata = 1;
1129                 s->range_table = &range_digital;
1130                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1131                 s->type = COMEDI_SUBD_DIO;
1132                 s->insn_bits = pcmmio_dio_insn_bits;
1133                 s->insn_config = pcmmio_dio_insn_config;
1134                 s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
1135                 subpriv->dio.intr.asic = -1;
1136                 subpriv->dio.intr.first_chan = -1;
1137                 subpriv->dio.intr.asic_chan = -1;
1138                 subpriv->dio.intr.num_asic_chans = -1;
1139                 subpriv->dio.intr.active = 0;
1140                 s->len_chanlist = 1;
1141
1142                 /* save the ioport address for each 'port' of 8 channels in the
1143                    subdevice */
1144                 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
1145                         if (port >= PORTS_PER_ASIC) {
1146                                 port = 0;
1147                                 ++asic;
1148                                 thisasic_chanct = 0;
1149                         }
1150                         subpriv->iobases[byte_no] =
1151                             devpriv->asics[asic].iobase + port;
1152
1153                         if (thisasic_chanct <
1154                             CHANS_PER_PORT * INTR_PORTS_PER_ASIC
1155                             && subpriv->dio.intr.asic < 0) {
1156                                 /*
1157                                  * this is an interrupt subdevice,
1158                                  * so setup the struct
1159                                  */
1160                                 subpriv->dio.intr.asic = asic;
1161                                 subpriv->dio.intr.active = 0;
1162                                 subpriv->dio.intr.stop_count = 0;
1163                                 subpriv->dio.intr.first_chan = byte_no * 8;
1164                                 subpriv->dio.intr.asic_chan = thisasic_chanct;
1165                                 subpriv->dio.intr.num_asic_chans =
1166                                     s->n_chan - subpriv->dio.intr.first_chan;
1167                                 s->cancel = pcmmio_cancel;
1168                                 s->do_cmd = pcmmio_cmd;
1169                                 s->do_cmdtest = pcmmio_cmdtest;
1170                                 s->len_chanlist =
1171                                     subpriv->dio.intr.num_asic_chans;
1172                         }
1173                         thisasic_chanct += CHANS_PER_PORT;
1174                 }
1175                 spin_lock_init(&subpriv->dio.intr.spinlock);
1176
1177                 chans_left -= s->n_chan;
1178
1179                 if (!chans_left) {
1180                         /*
1181                          * reset the asic to our first asic,
1182                          * to do intr subdevs
1183                          */
1184                         asic = 0;
1185                         port = 0;
1186                 }
1187
1188         }
1189
1190         init_asics(dev);        /* clear out all the registers, basically */
1191
1192         for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
1193                 if (irq[asic]
1194                     && request_irq(irq[asic], interrupt_pcmmio,
1195                                    IRQF_SHARED, thisboard->name, dev)) {
1196                         int i;
1197                         /* unroll the allocated irqs.. */
1198                         for (i = asic - 1; i >= 0; --i) {
1199                                 free_irq(irq[i], dev);
1200                                 devpriv->asics[i].irq = irq[i] = 0;
1201                         }
1202                         irq[asic] = 0;
1203                 }
1204                 devpriv->asics[asic].irq = irq[asic];
1205         }
1206
1207         dev->irq = irq[0];      /*
1208                                  * grr.. wish comedi dev struct supported
1209                                  * multiple irqs..
1210                                  */
1211
1212         if (irq[0]) {
1213                 printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]);
1214                 if (thisboard->dio_num_asics == 2 && irq[1])
1215                         printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n",
1216                                         dev->minor, irq[1]);
1217         } else {
1218                 printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor);
1219         }
1220
1221         printk(KERN_INFO "comedi%d: attached\n", dev->minor);
1222
1223         return 1;
1224 }
1225
1226 static void pcmmio_detach(struct comedi_device *dev)
1227 {
1228         int i;
1229
1230         if (dev->iobase)
1231                 release_region(dev->iobase, thisboard->total_iosize);
1232         for (i = 0; i < MAX_ASICS; ++i) {
1233                 if (devpriv && devpriv->asics[i].irq)
1234                         free_irq(devpriv->asics[i].irq, dev);
1235         }
1236         if (devpriv && devpriv->sprivs)
1237                 kfree(devpriv->sprivs);
1238 }
1239
1240 static const struct pcmmio_board pcmmio_boards[] = {
1241         {
1242                 .name           = "pcmmio",
1243                 .dio_num_asics  = 1,
1244                 .dio_num_ports  = 6,
1245                 .total_iosize   = 32,
1246                 .ai_bits        = 16,
1247                 .ao_bits        = 16,
1248                 .n_ai_chans     = 16,
1249                 .n_ao_chans     = 8,
1250                 .ai_range_table = &ranges_ai,
1251                 .ao_range_table = &ranges_ao,
1252                 .ai_rinsn       = ai_rinsn,
1253                 .ao_rinsn       = ao_rinsn,
1254                 .ao_winsn       = ao_winsn
1255         },
1256 };
1257
1258 static struct comedi_driver pcmmio_driver = {
1259         .driver_name    = "pcmmio",
1260         .module         = THIS_MODULE,
1261         .attach         = pcmmio_attach,
1262         .detach         = pcmmio_detach,
1263         .board_name     = &pcmmio_boards[0].name,
1264         .offset         = sizeof(struct pcmmio_board),
1265         .num_names      = ARRAY_SIZE(pcmmio_boards),
1266 };
1267 module_comedi_driver(pcmmio_driver);
1268
1269 MODULE_AUTHOR("Comedi http://www.comedi.org");
1270 MODULE_DESCRIPTION("Comedi low-level driver");
1271 MODULE_LICENSE("GPL");