drivers/comedi/drivers/pcmda12.c

Source file repositories/reference/linux-study-clean/drivers/comedi/drivers/pcmda12.c

File Facts

System
Linux kernel
Corpus path
drivers/comedi/drivers/pcmda12.c
Extension
.c
Size
4604 bytes
Lines
173
Domain
Driver Families
Bucket
drivers/comedi
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct pcmda12_private {
	int simultaneous_xfer_mode;
};

static int pcmda12_ao_insn_write(struct comedi_device *dev,
				 struct comedi_subdevice *s,
				 struct comedi_insn *insn,
				 unsigned int *data)
{
	struct pcmda12_private *devpriv = dev->private;
	unsigned int chan = CR_CHAN(insn->chanspec);
	unsigned int val = s->readback[chan];
	unsigned long ioreg = dev->iobase + (chan * 2);
	int i;

	for (i = 0; i < insn->n; ++i) {
		val = data[i];
		outb(val & 0xff, ioreg);
		outb((val >> 8) & 0xff, ioreg + 1);

		/*
		 * Initiate transfer if not in simultaneaous xfer
		 * mode by reading one of the AO registers.
		 */
		if (!devpriv->simultaneous_xfer_mode)
			inb(ioreg);
	}
	s->readback[chan] = val;

	return insn->n;
}

static int pcmda12_ao_insn_read(struct comedi_device *dev,
				struct comedi_subdevice *s,
				struct comedi_insn *insn,
				unsigned int *data)
{
	struct pcmda12_private *devpriv = dev->private;

	/*
	 * Initiate simultaneaous xfer mode by reading one of the
	 * AO registers. All analog outputs will then be updated.
	 */
	if (devpriv->simultaneous_xfer_mode)
		inb(dev->iobase);

	return comedi_readback_insn_read(dev, s, insn, data);
}

static void pcmda12_ao_reset(struct comedi_device *dev,
			     struct comedi_subdevice *s)
{
	int i;

	for (i = 0; i < s->n_chan; ++i) {
		outb(0, dev->iobase + (i * 2));
		outb(0, dev->iobase + (i * 2) + 1);
	}
	/* Initiate transfer by reading one of the AO registers. */
	inb(dev->iobase);
}

static int pcmda12_attach(struct comedi_device *dev,
			  struct comedi_devconfig *it)
{
	struct pcmda12_private *devpriv;
	struct comedi_subdevice *s;
	int ret;

	/*
	 * The datasheet says it requires 16 contiguous addresses and is
	 * "configurable on any even sixteen port boundary".  So require
	 * a 32-byte boundary and assume it uses 10-bit addresses like
	 * similar boards.
	 */
	ret = comedi_check_request_region(dev, it->options[0], 0x10,
					  0, 0x3ff, 32);
	if (ret)
		return ret;

	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
	if (!devpriv)
		return -ENOMEM;

	devpriv->simultaneous_xfer_mode = it->options[1];

	ret = comedi_alloc_subdevices(dev, 1);
	if (ret)
		return ret;

Annotation

Implementation Notes