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 can_have96:1;
35 unsigned int is_pet48:1;
36 int numofports;
37 };
38
39 static const struct pcl724_board boardtypes[] = {
40 {
41 .name = "pcl724",
42 .io_range = 0x04,
43 .numofports = 1, /* 24 DIO channels */
44 }, {
45 .name = "pcl722",
46 .io_range = 0x20,
47 .can_have96 = 1,
48 .numofports = 6, /* 144 (or 96) DIO channels */
49 }, {
50 .name = "pcl731",
51 .io_range = 0x08,
52 .numofports = 2, /* 48 DIO channels */
53 }, {
54 .name = "acl7122",
55 .io_range = 0x20,
56 .can_have96 = 1,
57 .numofports = 6, /* 144 (or 96) DIO channels */
58 }, {
59 .name = "acl7124",
60 .io_range = 0x04,
61 .numofports = 1, /* 24 DIO channels */
62 }, {
63 .name = "pet48dio",
64 .io_range = 0x02,
65 .is_pet48 = 1,
66 .numofports = 2, /* 48 DIO channels */
67 }, {
68 .name = "pcmio48",
69 .io_range = 0x08,
70 .numofports = 2, /* 48 DIO channels */
71 }, {
72 .name = "onyx-mm-dio",
73 .io_range = 0x10,
74 .numofports = 2, /* 48 DIO channels */
75 },
76 };
77
pcl724_8255mapped_io(struct comedi_device * dev,int dir,int port,int data,unsigned long iobase)78 static int pcl724_8255mapped_io(struct comedi_device *dev,
79 int dir, int port, int data,
80 unsigned long iobase)
81 {
82 int movport = I8255_SIZE * (iobase >> 12);
83
84 iobase &= 0x0fff;
85
86 outb(port + movport, iobase);
87 if (dir) {
88 outb(data, iobase + 1);
89 return 0;
90 }
91 return inb(iobase + 1);
92 }
93
pcl724_attach(struct comedi_device * dev,struct comedi_devconfig * it)94 static int pcl724_attach(struct comedi_device *dev,
95 struct comedi_devconfig *it)
96 {
97 const struct pcl724_board *board = dev->board_ptr;
98 struct comedi_subdevice *s;
99 unsigned long iobase;
100 unsigned int iorange;
101 int n_subdevices;
102 int ret;
103 int i;
104
105 iorange = board->io_range;
106 n_subdevices = board->numofports;
107
108 /* Handle PCL-724 in 96 DIO configuration */
109 if (board->can_have96 &&
110 (it->options[2] == 1 || it->options[2] == 96)) {
111 iorange = 0x10;
112 n_subdevices = 4;
113 }
114
115 ret = comedi_request_region(dev, it->options[0], iorange);
116 if (ret)
117 return ret;
118
119 ret = comedi_alloc_subdevices(dev, n_subdevices);
120 if (ret)
121 return ret;
122
123 for (i = 0; i < dev->n_subdevices; i++) {
124 s = &dev->subdevices[i];
125 if (board->is_pet48) {
126 iobase = dev->iobase + (i * 0x1000);
127 ret = subdev_8255_init(dev, s, pcl724_8255mapped_io,
128 iobase);
129 } else {
130 ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE);
131 }
132 if (ret)
133 return ret;
134 }
135
136 return 0;
137 }
138
139 static struct comedi_driver pcl724_driver = {
140 .driver_name = "pcl724",
141 .module = THIS_MODULE,
142 .attach = pcl724_attach,
143 .detach = comedi_legacy_detach,
144 .board_name = &boardtypes[0].name,
145 .num_names = ARRAY_SIZE(boardtypes),
146 .offset = sizeof(struct pcl724_board),
147 };
148 module_comedi_driver(pcl724_driver);
149
150 MODULE_AUTHOR("Comedi https://www.comedi.org");
151 MODULE_DESCRIPTION("Comedi driver for 8255 based ISA and PC/104 DIO boards");
152 MODULE_LICENSE("GPL");
153