| 1 | |
| 2 | |
| 3 | * comedi/range.c
|
| 4 | * comedi routines for voltage ranges
|
| 5 | *
|
| 6 | * COMEDI - Linux Control and Measurement Device Interface
|
| 7 | * Copyright (C) 1997-8 David A. Schleef <[email protected]>
|
| 8 |
|
| 9 |
|
| 10 | #include <linux/uaccess.h>
|
| 11 | #include <linux/comedi/comedidev.h>
|
| 12 | #include "comedi_internal.h"
|
| 13 |
|
| 14 | const struct comedi_lrange range_bipolar10 = { 1, {BIP_RANGE(10)} };
|
| 15 | EXPORT_SYMBOL_GPL(range_bipolar10);
|
| 16 | const struct comedi_lrange range_bipolar5 = { 1, {BIP_RANGE(5)} };
|
| 17 | EXPORT_SYMBOL_GPL(range_bipolar5);
|
| 18 | const struct comedi_lrange range_bipolar2_5 = { 1, {BIP_RANGE(2.5)} };
|
| 19 | EXPORT_SYMBOL_GPL(range_bipolar2_5);
|
| 20 | const struct comedi_lrange range_unipolar10 = { 1, {UNI_RANGE(10)} };
|
| 21 | EXPORT_SYMBOL_GPL(range_unipolar10);
|
| 22 | const struct comedi_lrange range_unipolar5 = { 1, {UNI_RANGE(5)} };
|
| 23 | EXPORT_SYMBOL_GPL(range_unipolar5);
|
| 24 | const struct comedi_lrange range_unipolar2_5 = { 1, {UNI_RANGE(2.5)} };
|
| 25 | EXPORT_SYMBOL_GPL(range_unipolar2_5);
|
| 26 | const struct comedi_lrange range_0_20mA = { 1, {RANGE_mA(0, 20)} };
|
| 27 | EXPORT_SYMBOL_GPL(range_0_20mA);
|
| 28 | const struct comedi_lrange range_4_20mA = { 1, {RANGE_mA(4, 20)} };
|
| 29 | EXPORT_SYMBOL_GPL(range_4_20mA);
|
| 30 | const struct comedi_lrange range_0_32mA = { 1, {RANGE_mA(0, 32)} };
|
| 31 | EXPORT_SYMBOL_GPL(range_0_32mA);
|
| 32 | const struct comedi_lrange range_unknown = { 1, {{0, 1000000, UNIT_none} } };
|
| 33 | EXPORT_SYMBOL_GPL(range_unknown);
|
| 34 |
|
| 35 | |
| 36 | * COMEDI_RANGEINFO ioctl
|
| 37 | * range information
|
| 38 | *
|
| 39 | * arg:
|
| 40 | * pointer to comedi_rangeinfo structure
|
| 41 | *
|
| 42 | * reads:
|
| 43 | * comedi_rangeinfo structure
|
| 44 | *
|
| 45 | * writes:
|
| 46 | * array of comedi_krange structures to rangeinfo->range_ptr pointer
|
| 47 |
|
| 48 | int do_rangeinfo_ioctl(struct comedi_device *dev,
|
| 49 | struct comedi_rangeinfo *it)
|
| 50 | {
|
| 51 | int subd, chan;
|
| 52 | const struct comedi_lrange *lr;
|
| 53 | struct comedi_subdevice *s;
|
| 54 |
|
| 55 | subd = (it->range_type >> 24) & 0xff;
|
| 56 | chan = (it->range_type >> 16) & 0xff;
|
| 57 |
|
| 58 | if (!dev->attached)
|
| 59 | return -EINVAL;
|
| 60 | if (subd >= dev->n_subdevices)
|
| 61 | return -EINVAL;
|
| 62 | s = &dev->subdevices[subd];
|
| 63 | if (s->range_table) {
|
| 64 | lr = s->range_table;
|
| 65 | } else if (s->range_table_list) {
|
| 66 | if (chan >= s->n_chan)
|
| 67 | return -EINVAL;
|
| 68 | lr = s->range_table_list[chan];
|
| 69 | } else {
|
| 70 | return -EINVAL;
|
| 71 | }
|
| 72 |
|
| 73 | if (RANGE_LENGTH(it->range_type) != lr->length) {
|
| 74 | dev_dbg(dev->class_dev,
|
| 75 | "wrong length %d should be %d (0x%08x)\n",
|
| 76 | RANGE_LENGTH(it->range_type),
|
| 77 | lr->length, it->range_type);
|
| 78 | return -EINVAL;
|
| 79 | }
|
| 80 |
|
| 81 | if (copy_to_user(it->range_ptr, lr->range,
|
| 82 | sizeof(struct comedi_krange) * lr->length))
|
| 83 | return -EFAULT;
|
| 84 |
|
| 85 | return 0;
|
| 86 | }
|
| 87 |
|
| 88 | |
| 89 | * comedi_check_chanlist() - Validate each element in a chanlist.
|
| 90 | * @s: comedi_subdevice struct
|
| 91 | * @n: number of elements in the chanlist
|
| 92 | * @chanlist: the chanlist to validate
|
| 93 | *
|
| 94 | * Each element consists of a channel number, a range index, an analog
|
| 95 | * reference type and some flags, all packed into an unsigned int.
|
| 96 | *
|
| 97 | * This checks that the channel number and range index are supported by
|
| 98 | * the comedi subdevice. It does not check whether the analog reference
|
| 99 | * type and the flags are supported. Drivers that care should check those
|
| 100 | * themselves.
|
| 101 | *
|
| 102 | * Return: %0 if all @chanlist elements are valid (success),
|
| 103 | * %-EINVAL if one or more elements are invalid.
|
| 104 |
|
| 105 | int comedi_check_chanlist(struct comedi_subdevice *s, int n,
|
| 106 | unsigned int *chanlist)
|
| 107 | {
|
| 108 | struct comedi_device *dev = s->device;
|
| 109 | unsigned int chanspec;
|
| 110 | int chan, range_len, i;
|
| 111 |
|
| 112 | for (i = 0; i < n; i++) {
|
| 113 | chanspec = chanlist[i];
|
| 114 | chan = CR_CHAN(chanspec);
|
| 115 | if (s->range_table)
|
| 116 | range_len = s->range_table->length;
|
| 117 | else if (s->range_table_list && chan < s->n_chan)
|
| 118 | range_len = s->range_table_list[chan]->length;
|
| 119 | else
|
| 120 | range_len = 0;
|
| 121 | if (chan >= s->n_chan ||
|
| 122 | CR_RANGE(chanspec) >= range_len) {
|
| 123 | dev_warn(dev->class_dev,
|
| 124 | "bad chanlist[%d]=0x%08x chan=%d range length=%d\n",
|
| 125 | i, chanspec, chan, range_len);
|
| 126 | return -EINVAL;
|
| 127 | }
|
| 128 | }
|
| 129 | return 0;
|
| 130 | }
|
| 131 | EXPORT_SYMBOL_GPL(comedi_check_chanlist);
|