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