It's the same principle with most Linux drivers.
https://raw.githubusercontent.com/nsaspook/daq_gert/master/daq_gert.c
https://forum.allaboutcircuits.com/threads/raspberry-pi-daq-system.75543/post-865187
https://forum.allaboutcircuits.com/threads/raspberry-pi-daq-system.75543/post-866607
https://raw.githubusercontent.com/nsaspook/daq_gert/master/daq_gert.c
C:
if (devpriv->num_subdev > 1) { /* setup comedi for on-board devices */
/* daq_gert ai */
if (devpriv->use_hunking)
dev_info(dev->class_dev,
"hunk ai transfers enabled, length: %i\n",
hunk_len);
s = &dev->subdevices[1];
s->private = devpriv->ai_spi;
s->type = COMEDI_SUBD_AI;
/* default setups, we support single-ended (ground) */
s->n_chan = devpriv->ai_spi->chan;
s->len_chanlist = devpriv->ai_spi->chan;
s->maxdata = (1 << (thisboard->n_aichan_bits - devpriv->ai_spi->device_spi->n_chan_bits)) - 1;
if (devpriv->ai_spi->range)
s->range_table = &daqgert_ai_range2_048;
else
s->range_table = &daqgert_ai_range3_300;
s->insn_read = daqgert_ai_rinsn;
if (devpriv->smp) {
s->subdev_flags = devpriv->ai_spi->device_spi->ai_subdev_flags;
s->do_cmdtest = daqgert_ai_cmdtest;
s->do_cmd = daqgert_ai_cmd;
s->poll = daqgert_ai_poll;
s->cancel = daqgert_ai_cancel;
} else {
s->subdev_flags = devpriv->ai_spi->device_spi->ai_subdev_flags - SDF_CMD_READ;
}
if (devpriv->ai_spi->device_type == ads1220) {
/* we support single-ended (ground) & diff bipolar 24-bit samples */
/* 32 bit buffers */
lsamp_size = SDF_LSAMPL;
s->maxdata = (1 << devpriv->ai_spi->device_spi->n_chan_bits) - 1;
s->range_table = &range_ads1220_ai;
s->n_chan = devpriv->ai_spi->device_spi->n_chan;
s->len_chanlist = devpriv->ai_spi->device_spi->n_chan;
s->insn_config = daqgert_ai_insn_config;
if (devpriv->smp) {
s->subdev_flags = devpriv->ai_spi->device_spi->ai_subdev_flags;
s->do_cmdtest = daqgert_ai_cmdtest;
s->do_cmd = daqgert_ai_cmd;
s->poll = daqgert_ai_poll;
s->cancel = daqgert_ai_cancel;
} else {
s->subdev_flags = devpriv->ai_spi->device_spi->ai_subdev_flags - SDF_CMD_READ;
}
}
if (devpriv->ai_spi->device_type == ads8330 || devpriv->ai_spi->device_type == special) {
/* we support single-ended (ground) & diff 16-bit samples */
s->maxdata = (1 << devpriv->ai_spi->device_spi->n_chan_bits) - 1;
s->range_table = &daqgert_ai_range3_300;
s->n_chan = devpriv->ai_spi->device_spi->n_chan;
s->len_chanlist = devpriv->ai_spi->device_spi->n_chan;
s->insn_config = daqgert_ai_insn_config;
if (devpriv->smp) {
s->subdev_flags = devpriv->ai_spi->device_spi->ai_subdev_flags;
s->do_cmdtest = daqgert_ai_cmdtest;
s->do_cmd = daqgert_ai_cmd;
s->poll = daqgert_ai_poll;
s->cancel = daqgert_ai_cancel;
} else {
s->subdev_flags = devpriv->ai_spi->device_spi->ai_subdev_flags - SDF_CMD_READ;
}
}
if (lsamp_size != SDF_LSAMPL) {
lsamp_size = 0;
dev_info(dev->class_dev, "16 bit and less device buffers set to 16 bits\n");
}
dev->read_subdev = s;
/* daq-gert ao */
s = &dev->subdevices[2];
s->private = devpriv->ao_spi;
s->type = COMEDI_SUBD_AO;
/* we support single-ended (ground) */
s->n_chan = thisboard->n_aochan;
s->len_chanlist = thisboard->n_aochan;
/* analog resolution depends on the DAC chip 8,10,12 bits */
s->maxdata = (1 << thisboard->n_aochan_bits) - 1;
s->range_table = &daqgert_ao_range;
s->insn_write = daqgert_ao_winsn;
s->insn_read = comedi_readback_insn_read;
if (devpriv->smp) {
s->subdev_flags = devpriv->ao_spi->device_spi->ao_subdev_flags;
s->do_cmdtest = daqgert_ao_cmdtest;
s->do_cmd = daqgert_ao_cmd;
s->cancel = daqgert_ao_cancel;
} else {
s->subdev_flags = devpriv->ao_spi->device_spi->ao_subdev_flags - SDF_CMD_WRITE;
}
ret = comedi_alloc_subdev_readback(s);
if (ret) {
dev_err(dev->class_dev,
"alloc subdevice readback failed!\n");
return ret;
}
}
https://forum.allaboutcircuits.com/threads/raspberry-pi-daq-system.75543/post-866607
It seems a complex way just to setup a SPI device the Linux way but by using non-global pointers to variables, dynamic variables with queues and lists it's possible to write easily reusable C code that can automatically adjust to changes in the hardware with just a few table entries, avoid data duplication and reduce the number of program locks needed for correct operation on multi-processor machines like the new RPI2 4 core board.