linux/drivers/comedi/drivers/8255.c
<<
>>
Prefs
   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
  47static 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
 100static 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
 115static 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};
 121module_comedi_driver(dev_8255_driver);
 122
 123MODULE_AUTHOR("Comedi https://www.comedi.org");
 124MODULE_DESCRIPTION("Comedi driver for standalone 8255 devices");
 125MODULE_LICENSE("GPL");
 126