1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * comedi/drivers/dt2817.c |
4 | * Hardware driver for Data Translation DT2817 |
5 | * |
6 | * COMEDI - Linux Control and Measurement Device Interface |
7 | * Copyright (C) 1998 David A. Schleef <ds@schleef.org> |
8 | */ |
9 | /* |
10 | * Driver: dt2817 |
11 | * Description: Data Translation DT2817 |
12 | * Author: ds |
13 | * Status: complete |
14 | * Devices: [Data Translation] DT2817 (dt2817) |
15 | * |
16 | * A very simple digital I/O card. Four banks of 8 lines, each bank |
17 | * is configurable for input or output. One wonders why it takes a |
18 | * 50 page manual to describe this thing. |
19 | * |
20 | * The driver (which, btw, is much less than 50 pages) has 1 subdevice |
21 | * with 32 channels, configurable in groups of 8. |
22 | * |
23 | * Configuration options: |
24 | * [0] - I/O port base base address |
25 | */ |
26 | |
27 | #include <linux/module.h> |
28 | #include <linux/comedi/comedidev.h> |
29 | |
30 | #define DT2817_CR 0 |
31 | #define DT2817_DATA 1 |
32 | |
33 | static int dt2817_dio_insn_config(struct comedi_device *dev, |
34 | struct comedi_subdevice *s, |
35 | struct comedi_insn *insn, |
36 | unsigned int *data) |
37 | { |
38 | unsigned int chan = CR_CHAN(insn->chanspec); |
39 | unsigned int oe = 0; |
40 | unsigned int mask; |
41 | int ret; |
42 | |
43 | if (chan < 8) |
44 | mask = 0x000000ff; |
45 | else if (chan < 16) |
46 | mask = 0x0000ff00; |
47 | else if (chan < 24) |
48 | mask = 0x00ff0000; |
49 | else |
50 | mask = 0xff000000; |
51 | |
52 | ret = comedi_dio_insn_config(dev, s, insn, data, mask); |
53 | if (ret) |
54 | return ret; |
55 | |
56 | if (s->io_bits & 0x000000ff) |
57 | oe |= 0x1; |
58 | if (s->io_bits & 0x0000ff00) |
59 | oe |= 0x2; |
60 | if (s->io_bits & 0x00ff0000) |
61 | oe |= 0x4; |
62 | if (s->io_bits & 0xff000000) |
63 | oe |= 0x8; |
64 | |
65 | outb(value: oe, port: dev->iobase + DT2817_CR); |
66 | |
67 | return insn->n; |
68 | } |
69 | |
70 | static int dt2817_dio_insn_bits(struct comedi_device *dev, |
71 | struct comedi_subdevice *s, |
72 | struct comedi_insn *insn, |
73 | unsigned int *data) |
74 | { |
75 | unsigned long iobase = dev->iobase + DT2817_DATA; |
76 | unsigned int mask; |
77 | unsigned int val; |
78 | |
79 | mask = comedi_dio_update_state(s, data); |
80 | if (mask) { |
81 | if (mask & 0x000000ff) |
82 | outb(value: s->state & 0xff, port: iobase + 0); |
83 | if (mask & 0x0000ff00) |
84 | outb(value: (s->state >> 8) & 0xff, port: iobase + 1); |
85 | if (mask & 0x00ff0000) |
86 | outb(value: (s->state >> 16) & 0xff, port: iobase + 2); |
87 | if (mask & 0xff000000) |
88 | outb(value: (s->state >> 24) & 0xff, port: iobase + 3); |
89 | } |
90 | |
91 | val = inb(port: iobase + 0); |
92 | val |= (inb(port: iobase + 1) << 8); |
93 | val |= (inb(port: iobase + 2) << 16); |
94 | val |= (inb(port: iobase + 3) << 24); |
95 | |
96 | data[1] = val; |
97 | |
98 | return insn->n; |
99 | } |
100 | |
101 | static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it) |
102 | { |
103 | int ret; |
104 | struct comedi_subdevice *s; |
105 | |
106 | ret = comedi_request_region(dev, start: it->options[0], len: 0x5); |
107 | if (ret) |
108 | return ret; |
109 | |
110 | ret = comedi_alloc_subdevices(dev, num_subdevices: 1); |
111 | if (ret) |
112 | return ret; |
113 | |
114 | s = &dev->subdevices[0]; |
115 | |
116 | s->n_chan = 32; |
117 | s->type = COMEDI_SUBD_DIO; |
118 | s->subdev_flags = SDF_READABLE | SDF_WRITABLE; |
119 | s->range_table = &range_digital; |
120 | s->maxdata = 1; |
121 | s->insn_bits = dt2817_dio_insn_bits; |
122 | s->insn_config = dt2817_dio_insn_config; |
123 | |
124 | s->state = 0; |
125 | outb(value: 0, port: dev->iobase + DT2817_CR); |
126 | |
127 | return 0; |
128 | } |
129 | |
130 | static struct comedi_driver dt2817_driver = { |
131 | .driver_name = "dt2817" , |
132 | .module = THIS_MODULE, |
133 | .attach = dt2817_attach, |
134 | .detach = comedi_legacy_detach, |
135 | }; |
136 | module_comedi_driver(dt2817_driver); |
137 | |
138 | MODULE_AUTHOR("Comedi https://www.comedi.org" ); |
139 | MODULE_DESCRIPTION("Comedi low-level driver" ); |
140 | MODULE_LICENSE("GPL" ); |
141 | |