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 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 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