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