drivers/comedi/drivers/ni_at_a2150.c

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

File Facts

System
Linux kernel
Corpus path
drivers/comedi/drivers/ni_at_a2150.c
Extension
.c
Size
21565 bytes
Lines
782
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 a2150_board {
	const char *name;
	int clock[4];		/* master clock periods, in nanoseconds */
	int num_clocks;		/* number of available master clock speeds */
	int ai_speed;		/* maximum conversion rate in nanoseconds */
};

/* analog input range */
static const struct comedi_lrange range_a2150 = {
	1, {
		BIP_RANGE(2.828)
	}
};

/* enum must match board indices */
enum { a2150_c, a2150_s };
static const struct a2150_board a2150_boards[] = {
	{
	 .name = "at-a2150c",
	 .clock = {31250, 22676, 20833, 19531},
	 .num_clocks = 4,
	 .ai_speed = 19531,
	 },
	{
	 .name = "at-a2150s",
	 .clock = {62500, 50000, 41667, 0},
	 .num_clocks = 3,
	 .ai_speed = 41667,
	 },
};

struct a2150_private {
	struct comedi_isadma *dma;
	unsigned int count;	/* number of data points left to be taken */
	int irq_dma_bits;	/* irq/dma register bits */
	int config_bits;	/* config register bits */
};

/* interrupt service routine */
static irqreturn_t a2150_interrupt(int irq, void *d)
{
	struct comedi_device *dev = d;
	struct a2150_private *devpriv = dev->private;
	struct comedi_isadma *dma = devpriv->dma;
	struct comedi_isadma_desc *desc = &dma->desc[0];
	struct comedi_subdevice *s = dev->read_subdev;
	struct comedi_async *async = s->async;
	struct comedi_cmd *cmd = &async->cmd;
	unsigned short *buf = desc->virt_addr;
	unsigned int max_points, num_points, residue, leftover;
	unsigned short dpnt;
	int status;
	int i;

	if (!dev->attached)
		return IRQ_HANDLED;

	status = inw(dev->iobase + STATUS_REG);
	if ((status & INTR_BIT) == 0)
		return IRQ_NONE;

	if (status & OVFL_BIT) {
		async->events |= COMEDI_CB_ERROR;
		comedi_handle_events(dev, s);
	}

	if ((status & DMA_TC_BIT) == 0) {
		async->events |= COMEDI_CB_ERROR;
		comedi_handle_events(dev, s);
		return IRQ_HANDLED;
	}

	/*
	 * residue is the number of bytes left to be done on the dma
	 * transfer.  It should always be zero at this point unless
	 * the stop_src is set to external triggering.
	 */
	residue = comedi_isadma_disable(desc->chan);

	/* figure out how many points to read */
	max_points = comedi_bytes_to_samples(s, desc->size);
	num_points = max_points - comedi_bytes_to_samples(s, residue);
	if (devpriv->count < num_points && cmd->stop_src == TRIG_COUNT)
		num_points = devpriv->count;

	/* figure out how many points will be stored next time */
	leftover = 0;
	if (cmd->stop_src == TRIG_NONE) {
		leftover = comedi_bytes_to_samples(s, desc->size);
	} else if (devpriv->count > max_points) {

Annotation

Implementation Notes