GNU Linux-libre 6.8.7-gnu
[releases.git] / drivers / comedi / drivers / 8255.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * comedi/drivers/8255.c
4  * Driver for 8255
5  *
6  * COMEDI - Linux Control and Measurement Device Interface
7  * Copyright (C) 1998 David A. Schleef <ds@schleef.org>
8  */
9
10 /*
11  * Driver: 8255
12  * Description: generic 8255 support
13  * Devices: [standard] 8255 (8255)
14  * Author: ds
15  * Status: works
16  * Updated: Fri,  7 Jun 2002 12:56:45 -0700
17  *
18  * The classic in digital I/O.  The 8255 appears in Comedi as a single
19  * digital I/O subdevice with 24 channels.  The channel 0 corresponds
20  * to the 8255's port A, bit 0; channel 23 corresponds to port C, bit
21  * 7.  Direction configuration is done in blocks, with channels 0-7,
22  * 8-15, 16-19, and 20-23 making up the 4 blocks.  The only 8255 mode
23  * supported is mode 0.
24  *
25  * You should enable compilation this driver if you plan to use a board
26  * that has an 8255 chip.  For multifunction boards, the main driver will
27  * configure the 8255 subdevice automatically.
28  *
29  * This driver also works independently with ISA and PCI cards that
30  * directly map the 8255 registers to I/O ports, including cards with
31  * multiple 8255 chips.  To configure the driver for such a card, the
32  * option list should be a list of the I/O port bases for each of the
33  * 8255 chips.  For example,
34  *
35  *   comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c
36  *
37  * Note that most PCI 8255 boards do NOT work with this driver, and
38  * need a separate driver as a wrapper.  For those that do work, the
39  * I/O port base address can be found in the output of 'lspci -v'.
40  */
41
42 #include <linux/module.h>
43 #include <linux/comedi/comedidev.h>
44 #include <linux/comedi/comedi_8255.h>
45
46 static int dev_8255_attach(struct comedi_device *dev,
47                            struct comedi_devconfig *it)
48 {
49         struct comedi_subdevice *s;
50         unsigned long iobase;
51         int ret;
52         int i;
53
54         for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) {
55                 iobase = it->options[i];
56                 if (!iobase)
57                         break;
58         }
59         if (i == 0) {
60                 dev_warn(dev->class_dev, "no devices specified\n");
61                 return -EINVAL;
62         }
63
64         ret = comedi_alloc_subdevices(dev, i);
65         if (ret)
66                 return ret;
67
68         for (i = 0; i < dev->n_subdevices; i++) {
69                 s = &dev->subdevices[i];
70                 iobase = it->options[i];
71
72                 /*
73                  * __comedi_request_region() does not set dev->iobase.
74                  *
75                  * For 8255 devices that are manually attached using
76                  * comedi_config, the 'iobase' is the actual I/O port
77                  * base address of the chip.
78                  */
79                 ret = __comedi_request_region(dev, iobase, I8255_SIZE);
80                 if (ret) {
81                         s->type = COMEDI_SUBD_UNUSED;
82                 } else {
83                         ret = subdev_8255_io_init(dev, s, iobase);
84                         if (ret) {
85                                 /*
86                                  * Release the I/O port region here, as the
87                                  * "detach" handler cannot find it.
88                                  */
89                                 release_region(iobase, I8255_SIZE);
90                                 s->type = COMEDI_SUBD_UNUSED;
91                                 return ret;
92                         }
93                 }
94         }
95
96         return 0;
97 }
98
99 static void dev_8255_detach(struct comedi_device *dev)
100 {
101         struct comedi_subdevice *s;
102         int i;
103
104         for (i = 0; i < dev->n_subdevices; i++) {
105                 s = &dev->subdevices[i];
106                 if (s->type != COMEDI_SUBD_UNUSED) {
107                         unsigned long regbase = subdev_8255_regbase(s);
108
109                         release_region(regbase, I8255_SIZE);
110                 }
111         }
112 }
113
114 static struct comedi_driver dev_8255_driver = {
115         .driver_name    = "8255",
116         .module         = THIS_MODULE,
117         .attach         = dev_8255_attach,
118         .detach         = dev_8255_detach,
119 };
120 module_comedi_driver(dev_8255_driver);
121
122 MODULE_AUTHOR("Comedi https://www.comedi.org");
123 MODULE_DESCRIPTION("Comedi driver for standalone 8255 devices");
124 MODULE_LICENSE("GPL");