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 | |
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(value: port + movport, port: iobase); |
87 | if (dir) { |
88 | outb(value: data, port: iobase + 1); |
89 | return 0; |
90 | } |
91 | return inb(port: iobase + 1); |
92 | } |
93 | |
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, start: it->options[0], len: iorange); |
116 | if (ret) |
117 | return ret; |
118 | |
119 | ret = comedi_alloc_subdevices(dev, num_subdevices: 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_cb_init(dev, s, io: pcl724_8255mapped_io, |
128 | context: iobase); |
129 | } else { |
130 | ret = subdev_8255_io_init(dev, s, regbase: 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 | |