Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
skel.c
Go to the documentation of this file.
1 /*
2  comedi/drivers/skel.c
3  Skeleton code for a Comedi driver
4 
5  COMEDI - Linux Control and Measurement Device Interface
6  Copyright (C) 2000 David A. Schleef <[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 /*
24 Driver: skel
25 Description: Skeleton driver, an example for driver writers
26 Devices:
27 Author: ds
28 Updated: Mon, 18 Mar 2002 15:34:01 -0800
29 Status: works
30 
31 This driver is a documented example on how Comedi drivers are
32 written.
33 
34 Configuration Options:
35  none
36 */
37 
38 /*
39  * The previous block comment is used to automatically generate
40  * documentation in Comedi and Comedilib. The fields:
41  *
42  * Driver: the name of the driver
43  * Description: a short phrase describing the driver. Don't list boards.
44  * Devices: a full list of the boards that attempt to be supported by
45  * the driver. Format is "(manufacturer) board name [comedi name]",
46  * where comedi_name is the name that is used to configure the board.
47  * See the comment near board_name: in the struct comedi_driver structure
48  * below. If (manufacturer) or [comedi name] is missing, the previous
49  * value is used.
50  * Author: you
51  * Updated: date when the _documentation_ was last updated. Use 'date -R'
52  * to get a value for this.
53  * Status: a one-word description of the status. Valid values are:
54  * works - driver works correctly on most boards supported, and
55  * passes comedi_test.
56  * unknown - unknown. Usually put there by ds.
57  * experimental - may not work in any particular release. Author
58  * probably wants assistance testing it.
59  * bitrotten - driver has not been update in a long time, probably
60  * doesn't work, and probably is missing support for significant
61  * Comedi interface features.
62  * untested - author probably wrote it "blind", and is believed to
63  * work, but no confirmation.
64  *
65  * These headers should be followed by a blank line, and any comments
66  * you wish to say about the driver. The comment area is the place
67  * to put any known bugs, limitations, unsupported features, supported
68  * command triggers, whether or not commands are supported on particular
69  * subdevices, etc.
70  *
71  * Somewhere in the comment should be information about configuration
72  * options that are used with comedi_config.
73  */
74 
75 #include "../comedidev.h"
76 
77 #include <linux/pci.h> /* for PCI devices */
78 
79 #include "comedi_fc.h"
80 
81 /* Imaginary registers for the imaginary board */
82 
83 #define SKEL_SIZE 0
84 
85 #define SKEL_START_AI_CONV 0
86 #define SKEL_AI_READ 0
87 
88 /*
89  * Board descriptions for two imaginary boards. Describing the
90  * boards in this way is optional, and completely driver-dependent.
91  * Some drivers use arrays such as this, other do not.
92  */
93 struct skel_board {
94  const char *name;
95  int ai_chans;
96  int ai_bits;
97  int have_dio;
98 };
99 
100 static const struct skel_board skel_boards[] = {
101  {
102  .name = "skel-100",
103  .ai_chans = 16,
104  .ai_bits = 12,
105  .have_dio = 1,
106  },
107  {
108  .name = "skel-200",
109  .ai_chans = 8,
110  .ai_bits = 16,
111  .have_dio = 0,
112  },
113 };
114 
115 /* This is used by modprobe to translate PCI IDs to drivers. Should
116  * only be used for PCI and ISA-PnP devices */
117 /* Please add your PCI vendor ID to comedidev.h, and it will be forwarded
118  * upstream. */
119 #define PCI_VENDOR_ID_SKEL 0xdafe
120 static DEFINE_PCI_DEVICE_TABLE(skel_pci_table) = {
121  { PCI_DEVICE(PCI_VENDOR_ID_SKEL, 0x0100) },
122  { PCI_DEVICE(PCI_VENDOR_ID_SKEL, 0x0200) },
123  { 0 }
124 };
125 
126 MODULE_DEVICE_TABLE(pci, skel_pci_table);
127 
128 /*
129  * Useful for shorthand access to the particular board structure
130  */
131 #define thisboard ((const struct skel_board *)dev->board_ptr)
132 
133 /* this structure is for data unique to this hardware driver. If
134  several hardware drivers keep similar information in this structure,
135  feel free to suggest moving the variable to the struct comedi_device struct.
136  */
137 struct skel_private {
138 
139  int data;
140 
141  /* would be useful for a PCI device */
142  struct pci_dev *pci_dev;
143 
144  /* Used for AO readback */
145  unsigned int ao_readback[2];
146 };
147 
148 /*
149  * most drivers define the following macro to make it easy to
150  * access the private structure.
151  */
152 #define devpriv ((struct skel_private *)dev->private)
153 
154 /*
155  * The struct comedi_driver structure tells the Comedi core module
156  * which functions to call to configure/deconfigure (attach/detach)
157  * the board, and also about the kernel module that contains
158  * the device code.
159  */
160 static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it);
161 static void skel_detach(struct comedi_device *dev);
162 static struct comedi_driver driver_skel = {
163  .driver_name = "dummy",
164  .module = THIS_MODULE,
165  .attach = skel_attach,
166  .detach = skel_detach,
167 /* It is not necessary to implement the following members if you are
168  * writing a driver for a ISA PnP or PCI card */
169  /* Most drivers will support multiple types of boards by
170  * having an array of board structures. These were defined
171  * in skel_boards[] above. Note that the element 'name'
172  * was first in the structure -- Comedi uses this fact to
173  * extract the name of the board without knowing any details
174  * about the structure except for its length.
175  * When a device is attached (by comedi_config), the name
176  * of the device is given to Comedi, and Comedi tries to
177  * match it by going through the list of board names. If
178  * there is a match, the address of the pointer is put
179  * into dev->board_ptr and driver->attach() is called.
180  *
181  * Note that these are not necessary if you can determine
182  * the type of board in software. ISA PnP, PCI, and PCMCIA
183  * devices are such boards.
184  */
185  .board_name = &skel_boards[0].name,
186  .offset = sizeof(struct skel_board),
187  .num_names = ARRAY_SIZE(skel_boards),
188 };
189 
190 static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
191  struct comedi_insn *insn, unsigned int *data);
192 static int skel_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
193  struct comedi_insn *insn, unsigned int *data);
194 static int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
195  struct comedi_insn *insn, unsigned int *data);
196 static int skel_dio_insn_bits(struct comedi_device *dev,
197  struct comedi_subdevice *s,
198  struct comedi_insn *insn, unsigned int *data);
199 static int skel_dio_insn_config(struct comedi_device *dev,
200  struct comedi_subdevice *s,
201  struct comedi_insn *insn, unsigned int *data);
202 static int skel_ai_cmdtest(struct comedi_device *dev,
203  struct comedi_subdevice *s, struct comedi_cmd *cmd);
204 static int skel_ns_to_timer(unsigned int *ns, int round);
205 
206 /*
207  * Attach is called by the Comedi core to configure the driver
208  * for a particular board. If you specified a board_name array
209  * in the driver structure, dev->board_ptr contains that
210  * address.
211  */
212 static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it)
213 {
214  struct comedi_subdevice *s;
215  int ret;
216 
217  pr_info("comedi%d: skel: ", dev->minor);
218 
219 /*
220  * If you can probe the device to determine what device in a series
221  * it is, this is the place to do it. Otherwise, dev->board_ptr
222  * should already be initialized.
223  */
224  /* dev->board_ptr = skel_probe(dev, it); */
225 
226 /*
227  * Initialize dev->board_name. Note that we can use the "thisboard"
228  * macro now, since we just initialized it in the last line.
229  */
230  dev->board_name = thisboard->name;
231 
232 /*
233  * Allocate the private structure area. alloc_private() is a
234  * convenient macro defined in comedidev.h.
235  */
236  if (alloc_private(dev, sizeof(struct skel_private)) < 0)
237  return -ENOMEM;
238 
239  ret = comedi_alloc_subdevices(dev, 3);
240  if (ret)
241  return ret;
242 
243  s = &dev->subdevices[0];
244  /* dev->read_subdev=s; */
245  /* analog input subdevice */
246  s->type = COMEDI_SUBD_AI;
247  /* we support single-ended (ground) and differential */
249  s->n_chan = thisboard->ai_chans;
250  s->maxdata = (1 << thisboard->ai_bits) - 1;
252  s->len_chanlist = 16; /* This is the maximum chanlist length that
253  the board can handle */
254  s->insn_read = skel_ai_rinsn;
255 /*
256 * s->subdev_flags |= SDF_CMD_READ;
257 * s->do_cmd = skel_ai_cmd;
258 */
259  s->do_cmdtest = skel_ai_cmdtest;
260 
261  s = &dev->subdevices[1];
262  /* analog output subdevice */
263  s->type = COMEDI_SUBD_AO;
265  s->n_chan = 1;
266  s->maxdata = 0xffff;
268  s->insn_write = skel_ao_winsn;
269  s->insn_read = skel_ao_rinsn;
270 
271  s = &dev->subdevices[2];
272  /* digital i/o subdevice */
273  if (thisboard->have_dio) {
274  s->type = COMEDI_SUBD_DIO;
276  s->n_chan = 16;
277  s->maxdata = 1;
279  s->insn_bits = skel_dio_insn_bits;
280  s->insn_config = skel_dio_insn_config;
281  } else {
283  }
284 
285  pr_info("attached\n");
286 
287  return 0;
288 }
289 
290 /*
291  * _detach is called to deconfigure a device. It should deallocate
292  * resources.
293  * This function is also called when _attach() fails, so it should be
294  * careful not to release resources that were not necessarily
295  * allocated by _attach(). dev->private and dev->subdevices are
296  * deallocated automatically by the core.
297  */
298 static void skel_detach(struct comedi_device *dev)
299 {
300 }
301 
302 /*
303  * "instructions" read/write data in "one-shot" or "software-triggered"
304  * mode.
305  */
306 static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
307  struct comedi_insn *insn, unsigned int *data)
308 {
309  int n, i;
310  unsigned int d;
311  unsigned int status;
312 
313  /* a typical programming sequence */
314 
315  /* write channel to multiplexer */
316  /* outw(chan,dev->iobase + SKEL_MUX); */
317 
318  /* don't wait for mux to settle */
319 
320  /* convert n samples */
321  for (n = 0; n < insn->n; n++) {
322  /* trigger conversion */
323  /* outw(0,dev->iobase + SKEL_CONVERT); */
324 
325 #define TIMEOUT 100
326  /* wait for conversion to end */
327  for (i = 0; i < TIMEOUT; i++) {
328  status = 1;
329  /* status = inb(dev->iobase + SKEL_STATUS); */
330  if (status)
331  break;
332  }
333  if (i == TIMEOUT) {
334  /* printk() should be used instead of printk()
335  * whenever the code can be called from real-time. */
336  pr_info("timeout\n");
337  return -ETIMEDOUT;
338  }
339 
340  /* read data */
341  /* d = inw(dev->iobase + SKEL_AI_DATA); */
342  d = 0;
343 
344  /* mangle the data as necessary */
345  d ^= 1 << (thisboard->ai_bits - 1);
346 
347  data[n] = d;
348  }
349 
350  /* return the number of samples read/written */
351  return n;
352 }
353 
354 /*
355  * cmdtest tests a particular command to see if it is valid.
356  * Using the cmdtest ioctl, a user can create a valid cmd
357  * and then have it executes by the cmd ioctl.
358  *
359  * cmdtest returns 1,2,3,4 or 0, depending on which tests
360  * the command passes.
361  */
362 static int skel_ai_cmdtest(struct comedi_device *dev,
363  struct comedi_subdevice *s,
364  struct comedi_cmd *cmd)
365 {
366  int err = 0;
367  int tmp;
368 
369  /* Step 1 : check if triggers are trivially valid */
370 
371  err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
372  err |= cfc_check_trigger_src(&cmd->scan_begin_src,
373  TRIG_TIMER | TRIG_EXT);
374  err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
375  err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
376  err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
377 
378  if (err)
379  return 1;
380 
381  /* Step 2a : make sure trigger sources are unique */
382 
383  err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
384  err |= cfc_check_trigger_is_unique(cmd->convert_src);
385  err |= cfc_check_trigger_is_unique(cmd->stop_src);
386 
387  /* Step 2b : and mutually compatible */
388 
389  if (err)
390  return 2;
391 
392  /* step 3: make sure arguments are trivially compatible */
393 
394  if (cmd->start_arg != 0) {
395  cmd->start_arg = 0;
396  err++;
397  }
398 #define MAX_SPEED 10000 /* in nanoseconds */
399 #define MIN_SPEED 1000000000 /* in nanoseconds */
400 
401  if (cmd->scan_begin_src == TRIG_TIMER) {
402  if (cmd->scan_begin_arg < MAX_SPEED) {
403  cmd->scan_begin_arg = MAX_SPEED;
404  err++;
405  }
406  if (cmd->scan_begin_arg > MIN_SPEED) {
407  cmd->scan_begin_arg = MIN_SPEED;
408  err++;
409  }
410  } else {
411  /* external trigger */
412  /* should be level/edge, hi/lo specification here */
413  /* should specify multiple external triggers */
414  if (cmd->scan_begin_arg > 9) {
415  cmd->scan_begin_arg = 9;
416  err++;
417  }
418  }
419  if (cmd->convert_src == TRIG_TIMER) {
420  if (cmd->convert_arg < MAX_SPEED) {
421  cmd->convert_arg = MAX_SPEED;
422  err++;
423  }
424  if (cmd->convert_arg > MIN_SPEED) {
425  cmd->convert_arg = MIN_SPEED;
426  err++;
427  }
428  } else {
429  /* external trigger */
430  /* see above */
431  if (cmd->convert_arg > 9) {
432  cmd->convert_arg = 9;
433  err++;
434  }
435  }
436 
437  if (cmd->scan_end_arg != cmd->chanlist_len) {
438  cmd->scan_end_arg = cmd->chanlist_len;
439  err++;
440  }
441  if (cmd->stop_src == TRIG_COUNT) {
442  if (cmd->stop_arg > 0x00ffffff) {
443  cmd->stop_arg = 0x00ffffff;
444  err++;
445  }
446  } else {
447  /* TRIG_NONE */
448  if (cmd->stop_arg != 0) {
449  cmd->stop_arg = 0;
450  err++;
451  }
452  }
453 
454  if (err)
455  return 3;
456 
457  /* step 4: fix up any arguments */
458 
459  if (cmd->scan_begin_src == TRIG_TIMER) {
460  tmp = cmd->scan_begin_arg;
461  skel_ns_to_timer(&cmd->scan_begin_arg,
462  cmd->flags & TRIG_ROUND_MASK);
463  if (tmp != cmd->scan_begin_arg)
464  err++;
465  }
466  if (cmd->convert_src == TRIG_TIMER) {
467  tmp = cmd->convert_arg;
468  skel_ns_to_timer(&cmd->convert_arg,
469  cmd->flags & TRIG_ROUND_MASK);
470  if (tmp != cmd->convert_arg)
471  err++;
472  if (cmd->scan_begin_src == TRIG_TIMER &&
473  cmd->scan_begin_arg <
474  cmd->convert_arg * cmd->scan_end_arg) {
475  cmd->scan_begin_arg =
476  cmd->convert_arg * cmd->scan_end_arg;
477  err++;
478  }
479  }
480 
481  if (err)
482  return 4;
483 
484  return 0;
485 }
486 
487 /* This function doesn't require a particular form, this is just
488  * what happens to be used in some of the drivers. It should
489  * convert ns nanoseconds to a counter value suitable for programming
490  * the device. Also, it should adjust ns so that it cooresponds to
491  * the actual time that the device will use. */
492 static int skel_ns_to_timer(unsigned int *ns, int round)
493 {
494  /* trivial timer */
495  /* if your timing is done through two cascaded timers, the
496  * i8253_cascade_ns_to_timer() function in 8253.h can be
497  * very helpful. There are also i8254_load() and i8254_mm_load()
498  * which can be used to load values into the ubiquitous 8254 counters
499  */
500 
501  return *ns;
502 }
503 
504 static int skel_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
505  struct comedi_insn *insn, unsigned int *data)
506 {
507  int i;
508  int chan = CR_CHAN(insn->chanspec);
509 
510  pr_info("skel_ao_winsn\n");
511  /* Writing a list of values to an AO channel is probably not
512  * very useful, but that's how the interface is defined. */
513  for (i = 0; i < insn->n; i++) {
514  /* a typical programming sequence */
515  /* outw(data[i],dev->iobase + SKEL_DA0 + chan); */
516  devpriv->ao_readback[chan] = data[i];
517  }
518 
519  /* return the number of samples read/written */
520  return i;
521 }
522 
523 /* AO subdevices should have a read insn as well as a write insn.
524  * Usually this means copying a value stored in devpriv. */
525 static int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
526  struct comedi_insn *insn, unsigned int *data)
527 {
528  int i;
529  int chan = CR_CHAN(insn->chanspec);
530 
531  for (i = 0; i < insn->n; i++)
532  data[i] = devpriv->ao_readback[chan];
533 
534  return i;
535 }
536 
537 /* DIO devices are slightly special. Although it is possible to
538  * implement the insn_read/insn_write interface, it is much more
539  * useful to applications if you implement the insn_bits interface.
540  * This allows packed reading/writing of the DIO channels. The
541  * comedi core can convert between insn_bits and insn_read/write */
542 static int skel_dio_insn_bits(struct comedi_device *dev,
543  struct comedi_subdevice *s,
544  struct comedi_insn *insn, unsigned int *data)
545 {
546  /* The insn data is a mask in data[0] and the new data
547  * in data[1], each channel cooresponding to a bit. */
548  if (data[0]) {
549  s->state &= ~data[0];
550  s->state |= data[0] & data[1];
551  /* Write out the new digital output lines */
552  /* outw(s->state,dev->iobase + SKEL_DIO); */
553  }
554 
555  /* on return, data[1] contains the value of the digital
556  * input and output lines. */
557  /* data[1]=inw(dev->iobase + SKEL_DIO); */
558  /* or we could just return the software copy of the output values if
559  * it was a purely digital output subdevice */
560  /* data[1]=s->state; */
561 
562  return insn->n;
563 }
564 
565 static int skel_dio_insn_config(struct comedi_device *dev,
566  struct comedi_subdevice *s,
567  struct comedi_insn *insn, unsigned int *data)
568 {
569  int chan = CR_CHAN(insn->chanspec);
570 
571  /* The input or output configuration of each digital line is
572  * configured by a special insn_config instruction. chanspec
573  * contains the channel to be changed, and data[0] contains the
574  * value COMEDI_INPUT or COMEDI_OUTPUT. */
575  switch (data[0]) {
577  s->io_bits |= 1 << chan;
578  break;
580  s->io_bits &= ~(1 << chan);
581  break;
583  data[1] =
584  (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
585  return insn->n;
586  break;
587  default:
588  return -EINVAL;
589  break;
590  }
591  /* outw(s->io_bits,dev->iobase + SKEL_DIO_CONFIG); */
592 
593  return insn->n;
594 }
595 
596 #ifdef CONFIG_COMEDI_PCI_DRIVERS
597 static int __devinit driver_skel_pci_probe(struct pci_dev *dev,
598  const struct pci_device_id *ent)
599 {
600  return comedi_pci_auto_config(dev, &driver_skel);
601 }
602 
603 static void __devexit driver_skel_pci_remove(struct pci_dev *dev)
604 {
606 }
607 
608 static struct pci_driver driver_skel_pci_driver = {
609  .id_table = skel_pci_table,
610  .probe = &driver_skel_pci_probe,
611  .remove = __devexit_p(&driver_skel_pci_remove)
612 };
613 
614 static int __init driver_skel_init_module(void)
615 {
616  int retval;
617 
618  retval = comedi_driver_register(&driver_skel);
619  if (retval < 0)
620  return retval;
621 
622  driver_skel_pci_driver.name = (char *)driver_skel.driver_name;
623  return pci_register_driver(&driver_skel_pci_driver);
624 }
625 
626 static void __exit driver_skel_cleanup_module(void)
627 {
628  pci_unregister_driver(&driver_skel_pci_driver);
629  comedi_driver_unregister(&driver_skel);
630 }
631 
632 module_init(driver_skel_init_module);
633 module_exit(driver_skel_cleanup_module);
634 #else
635 static int __init driver_skel_init_module(void)
636 {
637  return comedi_driver_register(&driver_skel);
638 }
639 
640 static void __exit driver_skel_cleanup_module(void)
641 {
642  comedi_driver_unregister(&driver_skel);
643 }
644 
645 module_init(driver_skel_init_module);
646 module_exit(driver_skel_cleanup_module);
647 #endif
648 
649 MODULE_AUTHOR("Comedi http://www.comedi.org");
650 MODULE_DESCRIPTION("Comedi low-level driver");
651 MODULE_LICENSE("GPL");