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