xref: /linux/drivers/comedi/drivers/8255.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
18ffdff6aSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
28ffdff6aSGreg Kroah-Hartman /*
38ffdff6aSGreg Kroah-Hartman  * comedi/drivers/8255.c
48ffdff6aSGreg Kroah-Hartman  * Driver for 8255
58ffdff6aSGreg Kroah-Hartman  *
68ffdff6aSGreg Kroah-Hartman  * COMEDI - Linux Control and Measurement Device Interface
78ffdff6aSGreg Kroah-Hartman  * Copyright (C) 1998 David A. Schleef <ds@schleef.org>
88ffdff6aSGreg Kroah-Hartman  */
98ffdff6aSGreg Kroah-Hartman 
108ffdff6aSGreg Kroah-Hartman /*
118ffdff6aSGreg Kroah-Hartman  * Driver: 8255
128ffdff6aSGreg Kroah-Hartman  * Description: generic 8255 support
138ffdff6aSGreg Kroah-Hartman  * Devices: [standard] 8255 (8255)
148ffdff6aSGreg Kroah-Hartman  * Author: ds
158ffdff6aSGreg Kroah-Hartman  * Status: works
168ffdff6aSGreg Kroah-Hartman  * Updated: Fri,  7 Jun 2002 12:56:45 -0700
178ffdff6aSGreg Kroah-Hartman  *
188ffdff6aSGreg Kroah-Hartman  * The classic in digital I/O.  The 8255 appears in Comedi as a single
198ffdff6aSGreg Kroah-Hartman  * digital I/O subdevice with 24 channels.  The channel 0 corresponds
208ffdff6aSGreg Kroah-Hartman  * to the 8255's port A, bit 0; channel 23 corresponds to port C, bit
218ffdff6aSGreg Kroah-Hartman  * 7.  Direction configuration is done in blocks, with channels 0-7,
228ffdff6aSGreg Kroah-Hartman  * 8-15, 16-19, and 20-23 making up the 4 blocks.  The only 8255 mode
238ffdff6aSGreg Kroah-Hartman  * supported is mode 0.
248ffdff6aSGreg Kroah-Hartman  *
258ffdff6aSGreg Kroah-Hartman  * You should enable compilation this driver if you plan to use a board
268ffdff6aSGreg Kroah-Hartman  * that has an 8255 chip.  For multifunction boards, the main driver will
278ffdff6aSGreg Kroah-Hartman  * configure the 8255 subdevice automatically.
288ffdff6aSGreg Kroah-Hartman  *
298ffdff6aSGreg Kroah-Hartman  * This driver also works independently with ISA and PCI cards that
308ffdff6aSGreg Kroah-Hartman  * directly map the 8255 registers to I/O ports, including cards with
318ffdff6aSGreg Kroah-Hartman  * multiple 8255 chips.  To configure the driver for such a card, the
328ffdff6aSGreg Kroah-Hartman  * option list should be a list of the I/O port bases for each of the
338ffdff6aSGreg Kroah-Hartman  * 8255 chips.  For example,
348ffdff6aSGreg Kroah-Hartman  *
358ffdff6aSGreg Kroah-Hartman  *   comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c
368ffdff6aSGreg Kroah-Hartman  *
378ffdff6aSGreg Kroah-Hartman  * Note that most PCI 8255 boards do NOT work with this driver, and
388ffdff6aSGreg Kroah-Hartman  * need a separate driver as a wrapper.  For those that do work, the
398ffdff6aSGreg Kroah-Hartman  * I/O port base address can be found in the output of 'lspci -v'.
408ffdff6aSGreg Kroah-Hartman  */
418ffdff6aSGreg Kroah-Hartman 
428ffdff6aSGreg Kroah-Hartman #include <linux/module.h>
43df0e68c1SIan Abbott #include <linux/comedi/comedidev.h>
44631e272bSIan Abbott #include <linux/comedi/comedi_8255.h>
458ffdff6aSGreg Kroah-Hartman 
dev_8255_attach(struct comedi_device * dev,struct comedi_devconfig * it)468ffdff6aSGreg Kroah-Hartman static int dev_8255_attach(struct comedi_device *dev,
478ffdff6aSGreg Kroah-Hartman 			   struct comedi_devconfig *it)
488ffdff6aSGreg Kroah-Hartman {
498ffdff6aSGreg Kroah-Hartman 	struct comedi_subdevice *s;
508ffdff6aSGreg Kroah-Hartman 	unsigned long iobase;
518ffdff6aSGreg Kroah-Hartman 	int ret;
528ffdff6aSGreg Kroah-Hartman 	int i;
538ffdff6aSGreg Kroah-Hartman 
548ffdff6aSGreg Kroah-Hartman 	for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) {
558ffdff6aSGreg Kroah-Hartman 		iobase = it->options[i];
568ffdff6aSGreg Kroah-Hartman 		if (!iobase)
578ffdff6aSGreg Kroah-Hartman 			break;
588ffdff6aSGreg Kroah-Hartman 	}
598ffdff6aSGreg Kroah-Hartman 	if (i == 0) {
608ffdff6aSGreg Kroah-Hartman 		dev_warn(dev->class_dev, "no devices specified\n");
618ffdff6aSGreg Kroah-Hartman 		return -EINVAL;
628ffdff6aSGreg Kroah-Hartman 	}
638ffdff6aSGreg Kroah-Hartman 
648ffdff6aSGreg Kroah-Hartman 	ret = comedi_alloc_subdevices(dev, i);
658ffdff6aSGreg Kroah-Hartman 	if (ret)
668ffdff6aSGreg Kroah-Hartman 		return ret;
678ffdff6aSGreg Kroah-Hartman 
688ffdff6aSGreg Kroah-Hartman 	for (i = 0; i < dev->n_subdevices; i++) {
698ffdff6aSGreg Kroah-Hartman 		s = &dev->subdevices[i];
708ffdff6aSGreg Kroah-Hartman 		iobase = it->options[i];
718ffdff6aSGreg Kroah-Hartman 
728ffdff6aSGreg Kroah-Hartman 		/*
738ffdff6aSGreg Kroah-Hartman 		 * __comedi_request_region() does not set dev->iobase.
748ffdff6aSGreg Kroah-Hartman 		 *
758ffdff6aSGreg Kroah-Hartman 		 * For 8255 devices that are manually attached using
768ffdff6aSGreg Kroah-Hartman 		 * comedi_config, the 'iobase' is the actual I/O port
778ffdff6aSGreg Kroah-Hartman 		 * base address of the chip.
788ffdff6aSGreg Kroah-Hartman 		 */
798ffdff6aSGreg Kroah-Hartman 		ret = __comedi_request_region(dev, iobase, I8255_SIZE);
808ffdff6aSGreg Kroah-Hartman 		if (ret) {
818ffdff6aSGreg Kroah-Hartman 			s->type = COMEDI_SUBD_UNUSED;
828ffdff6aSGreg Kroah-Hartman 		} else {
83*5c57b1ccSIan Abbott 			ret = subdev_8255_io_init(dev, s, iobase);
848ffdff6aSGreg Kroah-Hartman 			if (ret) {
858ffdff6aSGreg Kroah-Hartman 				/*
868ffdff6aSGreg Kroah-Hartman 				 * Release the I/O port region here, as the
878ffdff6aSGreg Kroah-Hartman 				 * "detach" handler cannot find it.
888ffdff6aSGreg Kroah-Hartman 				 */
898ffdff6aSGreg Kroah-Hartman 				release_region(iobase, I8255_SIZE);
908ffdff6aSGreg Kroah-Hartman 				s->type = COMEDI_SUBD_UNUSED;
918ffdff6aSGreg Kroah-Hartman 				return ret;
928ffdff6aSGreg Kroah-Hartman 			}
938ffdff6aSGreg Kroah-Hartman 		}
948ffdff6aSGreg Kroah-Hartman 	}
958ffdff6aSGreg Kroah-Hartman 
968ffdff6aSGreg Kroah-Hartman 	return 0;
978ffdff6aSGreg Kroah-Hartman }
988ffdff6aSGreg Kroah-Hartman 
dev_8255_detach(struct comedi_device * dev)998ffdff6aSGreg Kroah-Hartman static void dev_8255_detach(struct comedi_device *dev)
1008ffdff6aSGreg Kroah-Hartman {
1018ffdff6aSGreg Kroah-Hartman 	struct comedi_subdevice *s;
1028ffdff6aSGreg Kroah-Hartman 	int i;
1038ffdff6aSGreg Kroah-Hartman 
1048ffdff6aSGreg Kroah-Hartman 	for (i = 0; i < dev->n_subdevices; i++) {
1058ffdff6aSGreg Kroah-Hartman 		s = &dev->subdevices[i];
1068ffdff6aSGreg Kroah-Hartman 		if (s->type != COMEDI_SUBD_UNUSED) {
1078ffdff6aSGreg Kroah-Hartman 			unsigned long regbase = subdev_8255_regbase(s);
1088ffdff6aSGreg Kroah-Hartman 
1098ffdff6aSGreg Kroah-Hartman 			release_region(regbase, I8255_SIZE);
1108ffdff6aSGreg Kroah-Hartman 		}
1118ffdff6aSGreg Kroah-Hartman 	}
1128ffdff6aSGreg Kroah-Hartman }
1138ffdff6aSGreg Kroah-Hartman 
1148ffdff6aSGreg Kroah-Hartman static struct comedi_driver dev_8255_driver = {
1158ffdff6aSGreg Kroah-Hartman 	.driver_name	= "8255",
1168ffdff6aSGreg Kroah-Hartman 	.module		= THIS_MODULE,
1178ffdff6aSGreg Kroah-Hartman 	.attach		= dev_8255_attach,
1188ffdff6aSGreg Kroah-Hartman 	.detach		= dev_8255_detach,
1198ffdff6aSGreg Kroah-Hartman };
1208ffdff6aSGreg Kroah-Hartman module_comedi_driver(dev_8255_driver);
1218ffdff6aSGreg Kroah-Hartman 
1228ffdff6aSGreg Kroah-Hartman MODULE_AUTHOR("Comedi https://www.comedi.org");
1238ffdff6aSGreg Kroah-Hartman MODULE_DESCRIPTION("Comedi driver for standalone 8255 devices");
1248ffdff6aSGreg Kroah-Hartman MODULE_LICENSE("GPL");
125