1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * pcl724.c
4 * Comedi driver for 8255 based ISA and PC/104 DIO boards
5 *
6 * Michal Dobes <dobes@tesnet.cz>
7 */
8
9 /*
10 * Driver: pcl724
11 * Description: Comedi driver for 8255 based ISA DIO boards
12 * Devices: [Advantech] PCL-724 (pcl724), PCL-722 (pcl722), PCL-731 (pcl731),
13 * [ADLink] ACL-7122 (acl7122), ACL-7124 (acl7124), PET-48DIO (pet48dio),
14 * [WinSystems] PCM-IO48 (pcmio48),
15 * [Diamond Systems] ONYX-MM-DIO (onyx-mm-dio)
16 * Author: Michal Dobes <dobes@tesnet.cz>
17 * Status: untested
18 *
19 * Configuration options:
20 * [0] - IO Base
21 * [1] - IRQ (not supported)
22 * [2] - number of DIO (pcl722 and acl7122 boards)
23 * 0, 144: 144 DIO configuration
24 * 1, 96: 96 DIO configuration
25 */
26
27 #include <linux/module.h>
28 #include <linux/comedi/comedidev.h>
29 #include <linux/comedi/comedi_8255.h>
30
31 struct pcl724_board {
32 const char *name;
33 unsigned int io_range;
34 unsigned int min_io_start;
35 unsigned int max_io_end;
36 unsigned int can_have96:1;
37 unsigned int is_pet48:1;
38 int numofports;
39 };
40
41 static const struct pcl724_board boardtypes[] = {
42 {
43 .name = "pcl724",
44 .io_range = 0x04,
45 .min_io_start = 0x200,
46 .max_io_end = 0x3ff,
47 .numofports = 1, /* 24 DIO channels */
48 }, {
49 .name = "pcl722",
50 .io_range = 0x20,
51 .min_io_start = 0x200,
52 .max_io_end = 0x3ff,
53 .can_have96 = 1,
54 .numofports = 6, /* 144 (or 96) DIO channels */
55 }, {
56 .name = "pcl731",
57 .io_range = 0x08,
58 .min_io_start = 0,
59 .max_io_end = 0x3ff,
60 .numofports = 2, /* 48 DIO channels */
61 }, {
62 .name = "acl7122",
63 .io_range = 0x20,
64 .min_io_start = 0x200,
65 .max_io_end = 0x3ff,
66 .can_have96 = 1,
67 .numofports = 6, /* 144 (or 96) DIO channels */
68 }, {
69 .name = "acl7124",
70 .io_range = 0x04,
71 .min_io_start = 0x200,
72 .max_io_end = 0x3ff,
73 .numofports = 1, /* 24 DIO channels */
74 }, {
75 .name = "pet48dio",
76 .io_range = 0x02,
77 .min_io_start = 0,
78 .max_io_end = 0x3ff,
79 .is_pet48 = 1,
80 .numofports = 2, /* 48 DIO channels */
81 }, {
82 .name = "pcmio48",
83 .io_range = 0x08,
84 .min_io_start = 0x100,
85 .max_io_end = 0x17f,
86 .numofports = 2, /* 48 DIO channels */
87 }, {
88 .name = "onyx-mm-dio",
89 .io_range = 0x10,
90 .min_io_start = 0,
91 .max_io_end = 0x3ff,
92 .numofports = 2, /* 48 DIO channels */
93 },
94 };
95
pcl724_8255mapped_io(struct comedi_device * dev,int dir,int port,int data,unsigned long iobase)96 static int pcl724_8255mapped_io(struct comedi_device *dev,
97 int dir, int port, int data,
98 unsigned long iobase)
99 {
100 int movport = I8255_SIZE * (iobase >> 12);
101
102 iobase &= 0x0fff;
103
104 outb(port + movport, iobase);
105 if (dir) {
106 outb(data, iobase + 1);
107 return 0;
108 }
109 return inb(iobase + 1);
110 }
111
pcl724_attach(struct comedi_device * dev,struct comedi_devconfig * it)112 static int pcl724_attach(struct comedi_device *dev,
113 struct comedi_devconfig *it)
114 {
115 const struct pcl724_board *board = dev->board_ptr;
116 struct comedi_subdevice *s;
117 unsigned long iobase;
118 unsigned int iorange;
119 int n_subdevices;
120 int ret;
121 int i;
122
123 iorange = board->io_range;
124 n_subdevices = board->numofports;
125
126 /* Handle PCL-724 in 96 DIO configuration */
127 if (board->can_have96 &&
128 (it->options[2] == 1 || it->options[2] == 96)) {
129 iorange = 0x10;
130 n_subdevices = 4;
131 }
132
133 ret = comedi_check_request_region(dev, it->options[0], iorange,
134 board->min_io_start,
135 board->max_io_end, iorange);
136 if (ret)
137 return ret;
138
139 ret = comedi_alloc_subdevices(dev, n_subdevices);
140 if (ret)
141 return ret;
142
143 for (i = 0; i < dev->n_subdevices; i++) {
144 s = &dev->subdevices[i];
145 if (board->is_pet48) {
146 iobase = dev->iobase + (i * 0x1000);
147 ret = subdev_8255_cb_init(dev, s, pcl724_8255mapped_io,
148 iobase);
149 } else {
150 ret = subdev_8255_io_init(dev, s, i * I8255_SIZE);
151 }
152 if (ret)
153 return ret;
154 }
155
156 return 0;
157 }
158
159 static struct comedi_driver pcl724_driver = {
160 .driver_name = "pcl724",
161 .module = THIS_MODULE,
162 .attach = pcl724_attach,
163 .detach = comedi_legacy_detach,
164 .board_name = &boardtypes[0].name,
165 .num_names = ARRAY_SIZE(boardtypes),
166 .offset = sizeof(struct pcl724_board),
167 };
168 module_comedi_driver(pcl724_driver);
169
170 MODULE_AUTHOR("Comedi https://www.comedi.org");
171 MODULE_DESCRIPTION("Comedi driver for 8255 based ISA and PC/104 DIO boards");
172 MODULE_LICENSE("GPL");
173