xref: /linux/drivers/comedi/drivers/pcl724.c (revision cb4eb6771c0f8fd1c52a8f6fdec7762fb087380a)
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