Files
linux-bredos/drivers/comedi/drivers/ssv_dnp.c
Greg Kroah-Hartman 8ffdff6a8c staging: comedi: move out of staging directory
The comedi code came into the kernel back in 2008, but traces its
lifetime to much much earlier.  It's been polished and buffed and
there's really nothing preventing it from being part of the "real"
portion of the kernel.

So move it to drivers/comedi/ as it belongs there.

Many thanks to the hundreds of developers who did the work to make this
happen.

Cc: Ian Abbott <abbotti@mev.co.uk>
Cc: H Hartley Sweeten <hsweeten@visionengravers.com>
Link: https://lore.kernel.org/r/YHauop4u3sP6lz8j@kroah.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-04-15 09:26:25 +02:00

181 lines
4.8 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* ssv_dnp.c
* generic comedi driver for SSV Embedded Systems' DIL/Net-PCs
* Copyright (C) 2001 Robert Schwebel <robert@schwebel.de>
*
* COMEDI - Linux Control and Measurement Device Interface
* Copyright (C) 2000 David A. Schleef <ds@schleef.org>
*/
/*
* Driver: ssv_dnp
* Description: SSV Embedded Systems DIL/Net-PC
* Author: Robert Schwebel <robert@schwebel.de>
* Devices: [SSV Embedded Systems] DIL/Net-PC 1486 (dnp-1486)
* Status: unknown
*/
/* include files ----------------------------------------------------------- */
#include <linux/module.h>
#include "../comedidev.h"
/* Some global definitions: the registers of the DNP ----------------------- */
/* */
/* For port A and B the mode register has bits corresponding to the output */
/* pins, where Bit-N = 0 -> input, Bit-N = 1 -> output. Note that bits */
/* 4 to 7 correspond to pin 0..3 for port C data register. Ensure that bits */
/* 0..3 remain unchanged! For details about Port C Mode Register see */
/* the remarks in dnp_insn_config() below. */
#define CSCIR 0x22 /* Chip Setup and Control Index Register */
#define CSCDR 0x23 /* Chip Setup and Control Data Register */
#define PAMR 0xa5 /* Port A Mode Register */
#define PADR 0xa9 /* Port A Data Register */
#define PBMR 0xa4 /* Port B Mode Register */
#define PBDR 0xa8 /* Port B Data Register */
#define PCMR 0xa3 /* Port C Mode Register */
#define PCDR 0xa7 /* Port C Data Register */
static int dnp_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
unsigned int mask;
unsigned int val;
/*
* Ports A and B are straight forward: each bit corresponds to an
* output pin with the same order. Port C is different: bits 0...3
* correspond to bits 4...7 of the output register (PCDR).
*/
mask = comedi_dio_update_state(s, data);
if (mask) {
outb(PADR, CSCIR);
outb(s->state & 0xff, CSCDR);
outb(PBDR, CSCIR);
outb((s->state >> 8) & 0xff, CSCDR);
outb(PCDR, CSCIR);
val = inb(CSCDR) & 0x0f;
outb(((s->state >> 12) & 0xf0) | val, CSCDR);
}
outb(PADR, CSCIR);
val = inb(CSCDR);
outb(PBDR, CSCIR);
val |= (inb(CSCDR) << 8);
outb(PCDR, CSCIR);
val |= ((inb(CSCDR) & 0xf0) << 12);
data[1] = val;
return insn->n;
}
static int dnp_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int mask;
unsigned int val;
int ret;
ret = comedi_dio_insn_config(dev, s, insn, data, 0);
if (ret)
return ret;
if (chan < 8) { /* Port A */
mask = 1 << chan;
outb(PAMR, CSCIR);
} else if (chan < 16) { /* Port B */
mask = 1 << (chan - 8);
outb(PBMR, CSCIR);
} else { /* Port C */
/*
* We have to pay attention with port C.
* This is the meaning of PCMR:
* Bit in PCMR: 7 6 5 4 3 2 1 0
* Corresponding port C pin: d 3 d 2 d 1 d 0 d= don't touch
*
* Multiplication by 2 brings bits into correct position
* for PCMR!
*/
mask = 1 << ((chan - 16) * 2);
outb(PCMR, CSCIR);
}
val = inb(CSCDR);
if (data[0] == COMEDI_OUTPUT)
val |= mask;
else
val &= ~mask;
outb(val, CSCDR);
return insn->n;
}
static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
int ret;
/*
* We use I/O ports 0x22, 0x23 and 0xa3-0xa9, which are always
* allocated for the primary 8259, so we don't need to allocate
* them ourselves.
*/
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
return ret;
s = &dev->subdevices[0];
/* digital i/o subdevice */
s->type = COMEDI_SUBD_DIO;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
s->n_chan = 20;
s->maxdata = 1;
s->range_table = &range_digital;
s->insn_bits = dnp_dio_insn_bits;
s->insn_config = dnp_dio_insn_config;
/* configure all ports as input (default) */
outb(PAMR, CSCIR);
outb(0x00, CSCDR);
outb(PBMR, CSCIR);
outb(0x00, CSCDR);
outb(PCMR, CSCIR);
outb((inb(CSCDR) & 0xAA), CSCDR);
return 0;
}
static void dnp_detach(struct comedi_device *dev)
{
outb(PAMR, CSCIR);
outb(0x00, CSCDR);
outb(PBMR, CSCIR);
outb(0x00, CSCDR);
outb(PCMR, CSCIR);
outb((inb(CSCDR) & 0xAA), CSCDR);
}
static struct comedi_driver dnp_driver = {
.driver_name = "dnp-1486",
.module = THIS_MODULE,
.attach = dnp_attach,
.detach = dnp_detach,
};
module_comedi_driver(dnp_driver);
MODULE_AUTHOR("Comedi https://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");