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