GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / staging / comedi / drivers / pcl724.c
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
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
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 http://www.comedi.org");
152 MODULE_DESCRIPTION("Comedi driver for 8255 based ISA and PC/104 DIO boards");
153 MODULE_LICENSE("GPL");