drivers/comedi/drivers/rti800.c

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

File Facts

System
Linux kernel
Corpus path
drivers/comedi/drivers/rti800.c
Extension
.c
Size
8628 bytes
Lines
359
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 rti800_board {
	const char *name;
	int has_ao;
};

static const struct rti800_board rti800_boardtypes[] = {
	{
		.name		= "rti800",
	}, {
		.name		= "rti815",
		.has_ao		= 1,
	},
};

struct rti800_private {
	bool adc_2comp;
	bool dac_2comp[2];
	const struct comedi_lrange *ao_range_type_list[2];
	unsigned char muxgain_bits;
};

static int rti800_ai_eoc(struct comedi_device *dev,
			 struct comedi_subdevice *s,
			 struct comedi_insn *insn,
			 unsigned long context)
{
	unsigned char status;

	status = inb(dev->iobase + RTI800_CSR);
	if (status & RTI800_CSR_OVERRUN) {
		outb(0, dev->iobase + RTI800_CLRFLAGS);
		return -EOVERFLOW;
	}
	if (status & RTI800_CSR_DONE)
		return 0;
	return -EBUSY;
}

static int rti800_ai_insn_read(struct comedi_device *dev,
			       struct comedi_subdevice *s,
			       struct comedi_insn *insn,
			       unsigned int *data)
{
	struct rti800_private *devpriv = dev->private;
	unsigned int chan = CR_CHAN(insn->chanspec);
	unsigned int gain = CR_RANGE(insn->chanspec);
	unsigned char muxgain_bits;
	int ret;
	int i;

	inb(dev->iobase + RTI800_ADCHI);
	outb(0, dev->iobase + RTI800_CLRFLAGS);

	muxgain_bits = chan | (gain << 5);
	if (muxgain_bits != devpriv->muxgain_bits) {
		devpriv->muxgain_bits = muxgain_bits;
		outb(devpriv->muxgain_bits, dev->iobase + RTI800_MUXGAIN);
		/*
		 * Without a delay here, the RTI_CSR_OVERRUN bit
		 * gets set, and you will have an error.
		 */
		if (insn->n > 0) {
			int delay = (gain == 0) ? 10 :
				    (gain == 1) ? 20 :
				    (gain == 2) ? 40 : 80;

			udelay(delay);
		}
	}

	for (i = 0; i < insn->n; i++) {
		unsigned int val;

		outb(0, dev->iobase + RTI800_CONVERT);

		ret = comedi_timeout(dev, s, insn, rti800_ai_eoc, 0);
		if (ret)
			return ret;

		val = inb(dev->iobase + RTI800_ADCLO);
		val |= (inb(dev->iobase + RTI800_ADCHI) & 0xf) << 8;

		if (devpriv->adc_2comp)
			val = comedi_offset_munge(s, val);

		data[i] = val;
	}

	return insn->n;
}

Annotation

Implementation Notes