summaryrefslogtreecommitdiffstats
path: root/drivers/comedi/drivers/8255.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/comedi/drivers/8255.c')
-rw-r--r--drivers/comedi/drivers/8255.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/drivers/comedi/drivers/8255.c b/drivers/comedi/drivers/8255.c
new file mode 100644
index 000000000..ced8ea09d
--- /dev/null
+++ b/drivers/comedi/drivers/8255.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * comedi/drivers/8255.c
+ * Driver for 8255
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1998 David A. Schleef <ds@schleef.org>
+ */
+
+/*
+ * Driver: 8255
+ * Description: generic 8255 support
+ * Devices: [standard] 8255 (8255)
+ * Author: ds
+ * Status: works
+ * Updated: Fri, 7 Jun 2002 12:56:45 -0700
+ *
+ * The classic in digital I/O. The 8255 appears in Comedi as a single
+ * digital I/O subdevice with 24 channels. The channel 0 corresponds
+ * to the 8255's port A, bit 0; channel 23 corresponds to port C, bit
+ * 7. Direction configuration is done in blocks, with channels 0-7,
+ * 8-15, 16-19, and 20-23 making up the 4 blocks. The only 8255 mode
+ * supported is mode 0.
+ *
+ * You should enable compilation this driver if you plan to use a board
+ * that has an 8255 chip. For multifunction boards, the main driver will
+ * configure the 8255 subdevice automatically.
+ *
+ * This driver also works independently with ISA and PCI cards that
+ * directly map the 8255 registers to I/O ports, including cards with
+ * multiple 8255 chips. To configure the driver for such a card, the
+ * option list should be a list of the I/O port bases for each of the
+ * 8255 chips. For example,
+ *
+ * comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c
+ *
+ * Note that most PCI 8255 boards do NOT work with this driver, and
+ * need a separate driver as a wrapper. For those that do work, the
+ * I/O port base address can be found in the output of 'lspci -v'.
+ */
+
+#include <linux/module.h>
+#include <linux/comedi/comedidev.h>
+#include <linux/comedi/comedi_8255.h>
+
+static int dev_8255_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ unsigned long iobase;
+ int ret;
+ int i;
+
+ for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) {
+ iobase = it->options[i];
+ if (!iobase)
+ break;
+ }
+ if (i == 0) {
+ dev_warn(dev->class_dev, "no devices specified\n");
+ return -EINVAL;
+ }
+
+ ret = comedi_alloc_subdevices(dev, i);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < dev->n_subdevices; i++) {
+ s = &dev->subdevices[i];
+ iobase = it->options[i];
+
+ /*
+ * __comedi_request_region() does not set dev->iobase.
+ *
+ * For 8255 devices that are manually attached using
+ * comedi_config, the 'iobase' is the actual I/O port
+ * base address of the chip.
+ */
+ ret = __comedi_request_region(dev, iobase, I8255_SIZE);
+ if (ret) {
+ s->type = COMEDI_SUBD_UNUSED;
+ } else {
+ ret = subdev_8255_init(dev, s, NULL, iobase);
+ if (ret) {
+ /*
+ * Release the I/O port region here, as the
+ * "detach" handler cannot find it.
+ */
+ release_region(iobase, I8255_SIZE);
+ s->type = COMEDI_SUBD_UNUSED;
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void dev_8255_detach(struct comedi_device *dev)
+{
+ struct comedi_subdevice *s;
+ int i;
+
+ for (i = 0; i < dev->n_subdevices; i++) {
+ s = &dev->subdevices[i];
+ if (s->type != COMEDI_SUBD_UNUSED) {
+ unsigned long regbase = subdev_8255_regbase(s);
+
+ release_region(regbase, I8255_SIZE);
+ }
+ }
+}
+
+static struct comedi_driver dev_8255_driver = {
+ .driver_name = "8255",
+ .module = THIS_MODULE,
+ .attach = dev_8255_attach,
+ .detach = dev_8255_detach,
+};
+module_comedi_driver(dev_8255_driver);
+
+MODULE_AUTHOR("Comedi https://www.comedi.org");
+MODULE_DESCRIPTION("Comedi driver for standalone 8255 devices");
+MODULE_LICENSE("GPL");