Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
das08.c
Go to the documentation of this file.
1 /*
2  * comedi/drivers/das08.c
3  * DAS08 driver
4  *
5  * COMEDI - Linux Control and Measurement Device Interface
6  * Copyright (C) 2000 David A. Schleef <[email protected]>
7  * Copyright (C) 2001,2002,2003 Frank Mori Hess <[email protected]>
8  * Copyright (C) 2004 Salvador E. Tropea <[email protected]> <[email protected]>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  *****************************************************************
25  */
26 
27 /*
28  * Driver: das08
29  * Description: DAS-08 compatible boards
30  * Author: Warren Jasper, ds, Frank Hess
31  * Devices: [Keithley Metrabyte] DAS08 (isa-das08),
32  * [ComputerBoards] DAS08 (isa-das08), DAS08-PGM (das08-pgm),
33  * DAS08-PGH (das08-pgh), DAS08-PGL (das08-pgl), DAS08-AOH (das08-aoh),
34  * DAS08-AOL (das08-aol), DAS08-AOM (das08-aom), DAS08/JR-AO (das08/jr-ao),
35  * DAS08/JR-16-AO (das08jr-16-ao), PCI-DAS08 (pci-das08),
36  * PC104-DAS08 (pc104-das08), DAS08/JR/16 (das08jr/16)
37  * Updated: Fri, 31 Aug 2012 19:19:06 +0100
38  * Status: works
39  *
40  * This is a rewrite of the das08 and das08jr drivers.
41  *
42  * Options (for ISA cards):
43  * [0] - base io address
44  *
45  * Manual configuration of PCI cards is not supported; they are
46  * configured automatically.
47  *
48  * The das08 driver doesn't support asynchronous commands, since
49  * the cheap das08 hardware doesn't really support them. The
50  * comedi_rt_timer driver can be used to emulate commands for this
51  * driver.
52  */
53 
54 #include "../comedidev.h"
55 
56 #include <linux/delay.h>
57 
58 #include "8255.h"
59 #include "8253.h"
60 #include "das08.h"
61 
62 #define DRV_NAME "das08"
63 
64 #define DO_ISA IS_ENABLED(CONFIG_COMEDI_DAS08_ISA)
65 #define DO_PCI IS_ENABLED(CONFIG_COMEDI_DAS08_PCI)
66 #define DO_COMEDI_DRIVER_REGISTER (DO_ISA || DO_PCI)
67 
68 #define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307
69 #define PCI_DEVICE_ID_PCIDAS08 0x29
70 #define PCIDAS08_SIZE 0x54
71 
72 /* pci configuration registers */
73 #define INTCSR 0x4c
74 #define INTR1_ENABLE 0x1
75 #define INTR1_HIGH_POLARITY 0x2
76 #define PCI_INTR_ENABLE 0x40
77 #define INTR1_EDGE_TRIG 0x100 /* requires high polarity */
78 #define CNTRL 0x50
79 #define CNTRL_DIR 0x2
80 #define CNTRL_INTR 0x4
81 
82 /*
83  cio-das08.pdf
84 
85  "isa-das08"
86 
87  0 a/d bits 0-3 start 8 bit
88  1 a/d bits 4-11 start 12 bit
89  2 eoc, ip1-3, irq, mux op1-4, inte, mux
90  3 unused unused
91  4567 8254
92  89ab 8255
93 
94  requires hard-wiring for async ai
95 
96 */
97 
98 #define DAS08_LSB 0
99 #define DAS08_MSB 1
100 #define DAS08_TRIG_12BIT 1
101 #define DAS08_STATUS 2
102 #define DAS08_EOC (1<<7)
103 #define DAS08_IRQ (1<<3)
104 #define DAS08_IP(x) (((x)>>4)&0x7)
105 #define DAS08_CONTROL 2
106 #define DAS08_MUX_MASK 0x7
107 #define DAS08_MUX(x) ((x) & DAS08_MUX_MASK)
108 #define DAS08_INTE (1<<3)
109 #define DAS08_DO_MASK 0xf0
110 #define DAS08_OP(x) (((x) << 4) & DAS08_DO_MASK)
111 
112 /*
113  cio-das08jr.pdf
114 
115  "das08/jr-ao"
116 
117  0 a/d bits 0-3 unused
118  1 a/d bits 4-11 start 12 bit
119  2 eoc, mux mux
120  3 di do
121  4 unused ao0_lsb
122  5 unused ao0_msb
123  6 unused ao1_lsb
124  7 unused ao1_msb
125 
126 */
127 
128 #define DAS08JR_DIO 3
129 #define DAS08JR_AO_LSB(x) ((x) ? 6 : 4)
130 #define DAS08JR_AO_MSB(x) ((x) ? 7 : 5)
131 
132 /*
133  cio-das08_aox.pdf
134 
135  "das08-aoh"
136  "das08-aol"
137  "das08-aom"
138 
139  0 a/d bits 0-3 start 8 bit
140  1 a/d bits 4-11 start 12 bit
141  2 eoc, ip1-3, irq, mux op1-4, inte, mux
142  3 mux, gain status gain control
143  4567 8254
144  8 unused ao0_lsb
145  9 unused ao0_msb
146  a unused ao1_lsb
147  b unused ao1_msb
148  89ab
149  cdef 8255
150 */
151 
152 #define DAS08AO_GAIN_CONTROL 3
153 #define DAS08AO_GAIN_STATUS 3
154 
155 #define DAS08AO_AO_LSB(x) ((x) ? 0xa : 8)
156 #define DAS08AO_AO_MSB(x) ((x) ? 0xb : 9)
157 #define DAS08AO_AO_UPDATE 8
158 
159 /* gainlist same as _pgx_ below */
160 
161 static const struct comedi_lrange range_das08_pgl = { 9, {
162  BIP_RANGE(10),
163  BIP_RANGE(5),
164  BIP_RANGE(2.5),
165  BIP_RANGE(1.25),
166  BIP_RANGE(0.625),
167  UNI_RANGE(10),
168  UNI_RANGE(5),
169  UNI_RANGE(2.5),
170  UNI_RANGE(1.25)
171  }
172 };
173 
174 static const struct comedi_lrange range_das08_pgh = { 12, {
175  BIP_RANGE(10),
176  BIP_RANGE(5),
177  BIP_RANGE(1),
178  BIP_RANGE(0.5),
179  BIP_RANGE(0.1),
180  BIP_RANGE(0.05),
181  BIP_RANGE(0.01),
182  BIP_RANGE(0.005),
183  UNI_RANGE(10),
184  UNI_RANGE(1),
185  UNI_RANGE(0.1),
186  UNI_RANGE(0.01),
187  }
188 };
189 
190 static const struct comedi_lrange range_das08_pgm = { 9, {
191  BIP_RANGE(10),
192  BIP_RANGE(5),
193  BIP_RANGE(0.5),
194  BIP_RANGE(0.05),
195  BIP_RANGE(0.01),
196  UNI_RANGE(10),
197  UNI_RANGE(1),
198  UNI_RANGE(0.1),
199  UNI_RANGE(0.01)
200  }
201 }; /*
202  cio-das08jr.pdf
203 
204  "das08/jr-ao"
205 
206  0 a/d bits 0-3 unused
207  1 a/d bits 4-11 start 12 bit
208  2 eoc, mux mux
209  3 di do
210  4 unused ao0_lsb
211  5 unused ao0_msb
212  6 unused ao1_lsb
213  7 unused ao1_msb
214 
215  */
216 
217 static const struct comedi_lrange *const das08_ai_lranges[] = {
218  &range_unknown,
220  &range_das08_pgh,
221  &range_das08_pgl,
222  &range_das08_pgm,
223 };
224 
225 static const int das08_pgh_gainlist[] = {
226  8, 0, 10, 2, 12, 4, 14, 6, 1, 3, 5, 7
227 };
228 static const int das08_pgl_gainlist[] = { 8, 0, 2, 4, 6, 1, 3, 5, 7 };
229 static const int das08_pgm_gainlist[] = { 8, 0, 10, 12, 14, 9, 11, 13, 15 };
230 
231 static const int *const das08_gainlists[] = {
232  NULL,
233  NULL,
234  das08_pgh_gainlist,
235  das08_pgl_gainlist,
236  das08_pgm_gainlist,
237 };
238 
239 static inline bool is_isa_board(const struct das08_board_struct *board)
240 {
241  return DO_ISA && board->bustype == isa;
242 }
243 
244 static inline bool is_pci_board(const struct das08_board_struct *board)
245 {
246  return DO_PCI && board->bustype == pci;
247 }
248 
249 #define TIMEOUT 100000
250 
251 static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
252  struct comedi_insn *insn, unsigned int *data)
253 {
254  const struct das08_board_struct *thisboard = comedi_board(dev);
255  struct das08_private_struct *devpriv = dev->private;
256  int i, n;
257  int chan;
258  int range;
259  int lsb, msb;
260 
261  chan = CR_CHAN(insn->chanspec);
262  range = CR_RANGE(insn->chanspec);
263 
264  /* clear crap */
265  inb(dev->iobase + DAS08_LSB);
266  inb(dev->iobase + DAS08_MSB);
267 
268  /* set multiplexer */
269  /* lock to prevent race with digital output */
270  spin_lock(&dev->spinlock);
271  devpriv->do_mux_bits &= ~DAS08_MUX_MASK;
272  devpriv->do_mux_bits |= DAS08_MUX(chan);
273  outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL);
274  spin_unlock(&dev->spinlock);
275 
276  if (s->range_table->length > 1) {
277  /* set gain/range */
278  range = CR_RANGE(insn->chanspec);
279  outb(devpriv->pg_gainlist[range],
281  }
282 
283  for (n = 0; n < insn->n; n++) {
284  /* clear over-range bits for 16-bit boards */
285  if (thisboard->ai_nbits == 16)
286  if (inb(dev->iobase + DAS08_MSB) & 0x80)
287  dev_info(dev->class_dev, "over-range\n");
288 
289  /* trigger conversion */
290  outb_p(0, dev->iobase + DAS08_TRIG_12BIT);
291 
292  for (i = 0; i < TIMEOUT; i++) {
293  if (!(inb(dev->iobase + DAS08_STATUS) & DAS08_EOC))
294  break;
295  }
296  if (i == TIMEOUT) {
297  dev_err(dev->class_dev, "timeout\n");
298  return -ETIME;
299  }
300  msb = inb(dev->iobase + DAS08_MSB);
301  lsb = inb(dev->iobase + DAS08_LSB);
302  if (thisboard->ai_encoding == das08_encode12) {
303  data[n] = (lsb >> 4) | (msb << 4);
304  } else if (thisboard->ai_encoding == das08_pcm_encode12) {
305  data[n] = (msb << 8) + lsb;
306  } else if (thisboard->ai_encoding == das08_encode16) {
307  /* FPOS 16-bit boards are sign-magnitude */
308  if (msb & 0x80)
309  data[n] = (1 << 15) | lsb | ((msb & 0x7f) << 8);
310  else
311  data[n] = (1 << 15) - (lsb | (msb & 0x7f) << 8);
312  } else {
313  comedi_error(dev, "bug! unknown ai encoding");
314  return -1;
315  }
316  }
317 
318  return n;
319 }
320 
321 static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
322  struct comedi_insn *insn, unsigned int *data)
323 {
324  data[0] = 0;
325  data[1] = DAS08_IP(inb(dev->iobase + DAS08_STATUS));
326 
327  return insn->n;
328 }
329 
330 static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
331  struct comedi_insn *insn, unsigned int *data)
332 {
333  struct das08_private_struct *devpriv = dev->private;
334  int wbits;
335 
336  /* get current settings of digital output lines */
337  wbits = (devpriv->do_mux_bits >> 4) & 0xf;
338  /* null bits we are going to set */
339  wbits &= ~data[0];
340  /* set new bit values */
341  wbits |= data[0] & data[1];
342  /* remember digital output bits */
343  /* prevent race with setting of analog input mux */
344  spin_lock(&dev->spinlock);
345  devpriv->do_mux_bits &= ~DAS08_DO_MASK;
346  devpriv->do_mux_bits |= DAS08_OP(wbits);
347  outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL);
348  spin_unlock(&dev->spinlock);
349 
350  data[1] = wbits;
351 
352  return insn->n;
353 }
354 
355 static int das08jr_di_rbits(struct comedi_device *dev,
356  struct comedi_subdevice *s,
357  struct comedi_insn *insn, unsigned int *data)
358 {
359  data[0] = 0;
360  data[1] = inb(dev->iobase + DAS08JR_DIO);
361 
362  return insn->n;
363 }
364 
365 static int das08jr_do_wbits(struct comedi_device *dev,
366  struct comedi_subdevice *s,
367  struct comedi_insn *insn, unsigned int *data)
368 {
369  struct das08_private_struct *devpriv = dev->private;
370 
371  /* null bits we are going to set */
372  devpriv->do_bits &= ~data[0];
373  /* set new bit values */
374  devpriv->do_bits |= data[0] & data[1];
375  outb(devpriv->do_bits, dev->iobase + DAS08JR_DIO);
376 
377  data[1] = devpriv->do_bits;
378 
379  return insn->n;
380 }
381 
382 static void das08_ao_set_data(struct comedi_device *dev,
383  unsigned int chan, unsigned int data)
384 {
385  const struct das08_board_struct *thisboard = comedi_board(dev);
386  struct das08_private_struct *devpriv = dev->private;
387  unsigned char lsb;
388  unsigned char msb;
389 
390  lsb = data & 0xff;
391  msb = (data >> 8) & 0xff;
392  if (thisboard->is_jr) {
393  outb(lsb, dev->iobase + DAS08JR_AO_LSB(chan));
394  outb(msb, dev->iobase + DAS08JR_AO_MSB(chan));
395  /* load DACs */
396  inb(dev->iobase + DAS08JR_DIO);
397  } else {
398  outb(lsb, dev->iobase + DAS08AO_AO_LSB(chan));
399  outb(msb, dev->iobase + DAS08AO_AO_MSB(chan));
400  /* load DACs */
401  inb(dev->iobase + DAS08AO_AO_UPDATE);
402  }
403  devpriv->ao_readback[chan] = data;
404 }
405 
406 static void das08_ao_initialize(struct comedi_device *dev,
407  struct comedi_subdevice *s)
408 {
409  int n;
410  unsigned int data;
411 
412  data = s->maxdata / 2; /* should be about 0 volts */
413  for (n = 0; n < s->n_chan; n++)
414  das08_ao_set_data(dev, n, data);
415 }
416 
417 static int das08_ao_winsn(struct comedi_device *dev,
418  struct comedi_subdevice *s,
419  struct comedi_insn *insn, unsigned int *data)
420 {
421  unsigned int n;
422  unsigned int chan;
423 
424  chan = CR_CHAN(insn->chanspec);
425 
426  for (n = 0; n < insn->n; n++)
427  das08_ao_set_data(dev, chan, *data);
428 
429  return n;
430 }
431 
432 static int das08_ao_rinsn(struct comedi_device *dev,
433  struct comedi_subdevice *s,
434  struct comedi_insn *insn, unsigned int *data)
435 {
436  struct das08_private_struct *devpriv = dev->private;
437  unsigned int n;
438  unsigned int chan;
439 
440  chan = CR_CHAN(insn->chanspec);
441 
442  for (n = 0; n < insn->n; n++)
443  data[n] = devpriv->ao_readback[chan];
444 
445  return n;
446 }
447 
448 static void i8254_initialize(struct comedi_device *dev)
449 {
450  const struct das08_board_struct *thisboard = comedi_board(dev);
451  unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
452  unsigned int mode = I8254_MODE0 | I8254_BINARY;
453  int i;
454 
455  for (i = 0; i < 3; ++i)
456  i8254_set_mode(i8254_iobase, 0, i, mode);
457 }
458 
459 static int das08_counter_read(struct comedi_device *dev,
460  struct comedi_subdevice *s,
461  struct comedi_insn *insn, unsigned int *data)
462 {
463  const struct das08_board_struct *thisboard = comedi_board(dev);
464  unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
465  int chan = insn->chanspec;
466 
467  data[0] = i8254_read(i8254_iobase, 0, chan);
468  return 1;
469 }
470 
471 static int das08_counter_write(struct comedi_device *dev,
472  struct comedi_subdevice *s,
473  struct comedi_insn *insn, unsigned int *data)
474 {
475  const struct das08_board_struct *thisboard = comedi_board(dev);
476  unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
477  int chan = insn->chanspec;
478 
479  i8254_write(i8254_iobase, 0, chan, data[0]);
480  return 1;
481 }
482 
483 static int das08_counter_config(struct comedi_device *dev,
484  struct comedi_subdevice *s,
485  struct comedi_insn *insn, unsigned int *data)
486 {
487  const struct das08_board_struct *thisboard = comedi_board(dev);
488  unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
489  int chan = insn->chanspec;
490 
491  switch (data[0]) {
493  i8254_set_mode(i8254_iobase, 0, chan, data[1]);
494  break;
496  data[1] = i8254_status(i8254_iobase, 0, chan);
497  break;
498  default:
499  return -EINVAL;
500  break;
501  }
502  return 2;
503 }
504 
505 #if DO_COMEDI_DRIVER_REGISTER
506 static const struct das08_board_struct das08_boards[] = {
507 #if DO_ISA
508  {
509  .name = "isa-das08", /* cio-das08.pdf */
510  .bustype = isa,
511  .ai_nbits = 12,
512  .ai_pg = das08_pg_none,
513  .ai_encoding = das08_encode12,
514  .di_nchan = 3,
515  .do_nchan = 4,
516  .i8255_offset = 8,
517  .i8254_offset = 4,
518  .iosize = 16, /* unchecked */
519  },
520  {
521  .name = "das08-pgm", /* cio-das08pgx.pdf */
522  .bustype = isa,
523  .ai_nbits = 12,
524  .ai_pg = das08_pgm,
525  .ai_encoding = das08_encode12,
526  .di_nchan = 3,
527  .do_nchan = 4,
528  .i8255_offset = 0,
529  .i8254_offset = 0x04,
530  .iosize = 16, /* unchecked */
531  },
532  {
533  .name = "das08-pgh", /* cio-das08pgx.pdf */
534  .bustype = isa,
535  .ai_nbits = 12,
536  .ai_pg = das08_pgh,
537  .ai_encoding = das08_encode12,
538  .di_nchan = 3,
539  .do_nchan = 4,
540  .i8254_offset = 0x04,
541  .iosize = 16, /* unchecked */
542  },
543  {
544  .name = "das08-pgl", /* cio-das08pgx.pdf */
545  .bustype = isa,
546  .ai_nbits = 12,
547  .ai_pg = das08_pgl,
548  .ai_encoding = das08_encode12,
549  .di_nchan = 3,
550  .do_nchan = 4,
551  .i8254_offset = 0x04,
552  .iosize = 16, /* unchecked */
553  },
554  {
555  .name = "das08-aoh", /* cio-das08_aox.pdf */
556  .bustype = isa,
557  .ai_nbits = 12,
558  .ai_pg = das08_pgh,
559  .ai_encoding = das08_encode12,
560  .ao_nbits = 12,
561  .di_nchan = 3,
562  .do_nchan = 4,
563  .i8255_offset = 0x0c,
564  .i8254_offset = 0x04,
565  .iosize = 16, /* unchecked */
566  },
567  {
568  .name = "das08-aol", /* cio-das08_aox.pdf */
569  .bustype = isa,
570  .ai_nbits = 12,
571  .ai_pg = das08_pgl,
572  .ai_encoding = das08_encode12,
573  .ao_nbits = 12,
574  .di_nchan = 3,
575  .do_nchan = 4,
576  .i8255_offset = 0x0c,
577  .i8254_offset = 0x04,
578  .iosize = 16, /* unchecked */
579  },
580  {
581  .name = "das08-aom", /* cio-das08_aox.pdf */
582  .bustype = isa,
583  .ai_nbits = 12,
584  .ai_pg = das08_pgm,
585  .ai_encoding = das08_encode12,
586  .ao_nbits = 12,
587  .di_nchan = 3,
588  .do_nchan = 4,
589  .i8255_offset = 0x0c,
590  .i8254_offset = 0x04,
591  .iosize = 16, /* unchecked */
592  },
593  {
594  .name = "das08/jr-ao", /* cio-das08-jr-ao.pdf */
595  .bustype = isa,
596  .is_jr = true,
597  .ai_nbits = 12,
598  .ai_pg = das08_pg_none,
599  .ai_encoding = das08_encode12,
600  .ao_nbits = 12,
601  .di_nchan = 8,
602  .do_nchan = 8,
603  .iosize = 16, /* unchecked */
604  },
605  {
606  .name = "das08jr-16-ao", /* cio-das08jr-16-ao.pdf */
607  .bustype = isa,
608  .is_jr = true,
609  .ai_nbits = 16,
610  .ai_pg = das08_pg_none,
611  .ai_encoding = das08_encode16,
612  .ao_nbits = 16,
613  .di_nchan = 8,
614  .do_nchan = 8,
615  .i8254_offset = 0x04,
616  .iosize = 16, /* unchecked */
617  },
618  {
619  .name = "pc104-das08",
620  .bustype = isa,
621  .ai_nbits = 12,
622  .ai_pg = das08_pg_none,
623  .ai_encoding = das08_encode12,
624  .di_nchan = 3,
625  .do_nchan = 4,
626  .i8254_offset = 4,
627  .iosize = 16, /* unchecked */
628  },
629  {
630  .name = "das08jr/16",
631  .bustype = isa,
632  .is_jr = true,
633  .ai_nbits = 16,
634  .ai_pg = das08_pg_none,
635  .ai_encoding = das08_encode16,
636  .di_nchan = 8,
637  .do_nchan = 8,
638  .iosize = 16, /* unchecked */
639  },
640 #endif /* DO_ISA */
641 #if DO_PCI
642  {
643  .name = "pci-das08", /* pci-das08 */
645  .bustype = pci,
646  .ai_nbits = 12,
647  .ai_pg = das08_bipolar5,
648  .ai_encoding = das08_encode12,
649  .di_nchan = 3,
650  .do_nchan = 4,
651  .i8254_offset = 4,
652  .iosize = 8,
653  },
654 #endif /* DO_PCI */
655 };
656 #endif /* DO_COMEDI_DRIVER_REGISTER */
657 
658 int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
659 {
660  const struct das08_board_struct *thisboard = comedi_board(dev);
661  struct das08_private_struct *devpriv = dev->private;
662  struct comedi_subdevice *s;
663  int ret;
664 
665  dev->iobase = iobase;
666 
667  dev->board_name = thisboard->name;
668 
669  ret = comedi_alloc_subdevices(dev, 6);
670  if (ret)
671  return ret;
672 
673  s = &dev->subdevices[0];
674  /* ai */
675  if (thisboard->ai_nbits) {
676  s->type = COMEDI_SUBD_AI;
677  /* XXX some boards actually have differential
678  * inputs instead of single ended.
679  * The driver does nothing with arefs though,
680  * so it's no big deal.
681  */
683  s->n_chan = 8;
684  s->maxdata = (1 << thisboard->ai_nbits) - 1;
685  s->range_table = das08_ai_lranges[thisboard->ai_pg];
686  s->insn_read = das08_ai_rinsn;
687  devpriv->pg_gainlist = das08_gainlists[thisboard->ai_pg];
688  } else {
690  }
691 
692  s = &dev->subdevices[1];
693  /* ao */
694  if (thisboard->ao_nbits) {
695  s->type = COMEDI_SUBD_AO;
697  s->n_chan = 2;
698  s->maxdata = (1 << thisboard->ao_nbits) - 1;
700  s->insn_write = das08_ao_winsn;
701  s->insn_read = das08_ao_rinsn;
702  das08_ao_initialize(dev, s);
703  } else {
705  }
706 
707  s = &dev->subdevices[2];
708  /* di */
709  if (thisboard->di_nchan) {
710  s->type = COMEDI_SUBD_DI;
712  s->n_chan = thisboard->di_nchan;
713  s->maxdata = 1;
715  s->insn_bits =
716  thisboard->is_jr ? das08jr_di_rbits : das08_di_rbits;
717  } else {
719  }
720 
721  s = &dev->subdevices[3];
722  /* do */
723  if (thisboard->do_nchan) {
724  s->type = COMEDI_SUBD_DO;
726  s->n_chan = thisboard->do_nchan;
727  s->maxdata = 1;
729  s->insn_bits =
730  thisboard->is_jr ? das08jr_do_wbits : das08_do_wbits;
731  } else {
733  }
734 
735  s = &dev->subdevices[4];
736  /* 8255 */
737  if (thisboard->i8255_offset != 0) {
738  subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase +
739  thisboard->
740  i8255_offset));
741  } else {
743  }
744 
745  s = &dev->subdevices[5];
746  /* 8254 */
747  if (thisboard->i8254_offset != 0) {
750  s->n_chan = 3;
751  s->maxdata = 0xFFFF;
752  s->insn_read = das08_counter_read;
753  s->insn_write = das08_counter_write;
754  s->insn_config = das08_counter_config;
755  i8254_initialize(dev);
756  } else {
758  }
759 
760  return 0;
761 }
763 
764 static const struct das08_board_struct *
765 das08_find_pci_board(struct pci_dev *pdev)
766 {
767 #if DO_COMEDI_DRIVER_REGISTER
768  unsigned int i;
769  for (i = 0; i < ARRAY_SIZE(das08_boards); i++)
770  if (is_pci_board(&das08_boards[i]) &&
771  pdev->device == das08_boards[i].id)
772  return &das08_boards[i];
773 #endif
774  return NULL;
775 }
776 
777 /* only called in the PCI probe path, via comedi_pci_auto_config() */
778 static int __devinit __maybe_unused
779 das08_attach_pci(struct comedi_device *dev, struct pci_dev *pdev)
780 {
781  unsigned long iobase;
782  int ret;
783 
784  if (!DO_PCI)
785  return -EINVAL;
786  ret = alloc_private(dev, sizeof(struct das08_private_struct));
787  if (ret < 0)
788  return ret;
789  dev_info(dev->class_dev, "attach pci %s\n", pci_name(pdev));
790  dev->board_ptr = das08_find_pci_board(pdev);
791  if (dev->board_ptr == NULL) {
792  dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
793  return -EINVAL;
794  }
795  comedi_set_hw_dev(dev, &pdev->dev);
796  /* enable PCI device and reserve I/O spaces */
797  if (comedi_pci_enable(pdev, dev->driver->driver_name)) {
798  dev_err(dev->class_dev,
799  "Error enabling PCI device and requesting regions\n");
800  return -EIO;
801  }
802  /* read base addresses */
803  iobase = pci_resource_start(pdev, 2);
804  return das08_common_attach(dev, iobase);
805 }
806 
807 static int __maybe_unused
808 das08_attach(struct comedi_device *dev, struct comedi_devconfig *it)
809 {
810  const struct das08_board_struct *thisboard = comedi_board(dev);
812  int ret;
813  unsigned long iobase;
814 
815  ret = alloc_private(dev, sizeof(struct das08_private_struct));
816  if (ret < 0)
817  return ret;
818  devpriv = dev->private;
819 
820  dev_info(dev->class_dev, "attach\n");
821  if (is_pci_board(thisboard)) {
822  dev_err(dev->class_dev,
823  "Manual configuration of PCI board '%s' is not supported\n",
824  thisboard->name);
825  return -EIO;
826  } else if (is_isa_board(thisboard)) {
827  iobase = it->options[0];
828  dev_info(dev->class_dev, "iobase 0x%lx\n", iobase);
829  if (!request_region(iobase, thisboard->iosize, DRV_NAME)) {
830  dev_err(dev->class_dev, "I/O port conflict\n");
831  return -EIO;
832  }
833  return das08_common_attach(dev, iobase);
834  } else
835  return -EIO;
836 }
837 
839 {
840  if (dev->subdevices)
841  subdev_8255_cleanup(dev, &dev->subdevices[4]);
842 }
844 
845 static void __maybe_unused das08_detach(struct comedi_device *dev)
846 {
847  const struct das08_board_struct *thisboard = comedi_board(dev);
848 
849  if (!thisboard)
850  return;
851  das08_common_detach(dev);
852  if (is_isa_board(thisboard)) {
853  if (dev->iobase)
854  release_region(dev->iobase, thisboard->iosize);
855  } else if (is_pci_board(thisboard)) {
856  struct pci_dev *pdev = comedi_to_pci_dev(dev);
857  if (pdev) {
858  if (dev->iobase)
859  comedi_pci_disable(pdev);
860  }
861  }
862 }
863 
864 #if DO_COMEDI_DRIVER_REGISTER
865 static struct comedi_driver das08_driver = {
867  .module = THIS_MODULE,
868  .attach = das08_attach,
869  .attach_pci = das08_attach_pci,
870  .detach = das08_detach,
871  .board_name = &das08_boards[0].name,
872  .num_names = sizeof(das08_boards) / sizeof(struct das08_board_struct),
873  .offset = sizeof(struct das08_board_struct),
874 };
875 #endif
876 
877 #if DO_PCI
878 static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = {
880  {0}
881 };
882 
883 MODULE_DEVICE_TABLE(pci, das08_pci_table);
884 
885 static int __devinit das08_pci_probe(struct pci_dev *dev,
886  const struct pci_device_id *ent)
887 {
888  return comedi_pci_auto_config(dev, &das08_driver);
889 }
890 
891 static void __devexit das08_pci_remove(struct pci_dev *dev)
892 {
894 }
895 
896 static struct pci_driver das08_pci_driver = {
897  .id_table = das08_pci_table,
898  .name = DRV_NAME,
899  .probe = &das08_pci_probe,
900  .remove = __devexit_p(&das08_pci_remove)
901 };
902 #endif /* DO_PCI */
903 
904 #if DO_COMEDI_DRIVER_REGISTER
905 #if DO_PCI
906 module_comedi_pci_driver(das08_driver, das08_pci_driver);
907 #else
908 module_comedi_driver(das08_driver);
909 #endif
910 #else /* DO_COMEDI_DRIVER_REGISTER */
911 static int __init das08_init(void)
912 {
913  return 0;
914 }
915 
916 static void __exit das08_exit(void)
917 {
918 }
919 
920 module_init(das08_init);
921 module_exit(das08_exit);
922 #endif /* DO_COMEDI_DRIVER_REGISTER */
923 
924 MODULE_AUTHOR("Comedi http://www.comedi.org");
925 MODULE_DESCRIPTION("Comedi low-level driver");
926 MODULE_LICENSE("GPL");