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 "../comedidev.h" 44 45 #include "8255.h" 46 47 static int dev_8255_attach(struct comedi_device *dev, 48 struct comedi_devconfig *it) 49 { 50 struct comedi_subdevice *s; 51 unsigned long iobase; 52 int ret; 53 int i; 54 55 for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) { 56 iobase = it->options[i]; 57 if (!iobase) 58 break; 59 } 60 if (i == 0) { 61 dev_warn(dev->class_dev, "no devices specified\n"); 62 return -EINVAL; 63 } 64 65 ret = comedi_alloc_subdevices(dev, i); 66 if (ret) 67 return ret; 68 69 for (i = 0; i < dev->n_subdevices; i++) { 70 s = &dev->subdevices[i]; 71 iobase = it->options[i]; 72 73 /* 74 * __comedi_request_region() does not set dev->iobase. 75 * 76 * For 8255 devices that are manually attached using 77 * comedi_config, the 'iobase' is the actual I/O port 78 * base address of the chip. 79 */ 80 ret = __comedi_request_region(dev, iobase, I8255_SIZE); 81 if (ret) { 82 s->type = COMEDI_SUBD_UNUSED; 83 } else { 84 ret = subdev_8255_init(dev, s, NULL, iobase); 85 if (ret) { 86 /* 87 * Release the I/O port region here, as the 88 * "detach" handler cannot find it. 89 */ 90 release_region(iobase, I8255_SIZE); 91 s->type = COMEDI_SUBD_UNUSED; 92 return ret; 93 } 94 } 95 } 96 97 return 0; 98 } 99 100 static void dev_8255_detach(struct comedi_device *dev) 101 { 102 struct comedi_subdevice *s; 103 int i; 104 105 for (i = 0; i < dev->n_subdevices; i++) { 106 s = &dev->subdevices[i]; 107 if (s->type != COMEDI_SUBD_UNUSED) { 108 unsigned long regbase = subdev_8255_regbase(s); 109 110 release_region(regbase, I8255_SIZE); 111 } 112 } 113 } 114 115 static struct comedi_driver dev_8255_driver = { 116 .driver_name = "8255", 117 .module = THIS_MODULE, 118 .attach = dev_8255_attach, 119 .detach = dev_8255_detach, 120 }; 121 module_comedi_driver(dev_8255_driver); 122 123 MODULE_AUTHOR("Comedi https://www.comedi.org"); 124 MODULE_DESCRIPTION("Comedi driver for standalone 8255 devices"); 125 MODULE_LICENSE("GPL"); 126