|
@@ -36,7 +36,15 @@
|
|
|
* generate sample waveforms on systems that don't have data acquisition
|
|
|
* hardware.
|
|
|
*
|
|
|
- * Configuration options:
|
|
|
+ * Auto-configuration is the default mode if no parameter is supplied during
|
|
|
+ * module loading. Manual configuration requires COMEDI userspace tool.
|
|
|
+ * To disable auto-configuration mode, pass "noauto=1" parameter for module
|
|
|
+ * loading. Refer modinfo or MODULE_PARM_DESC description below for details.
|
|
|
+ *
|
|
|
+ * Auto-configuration options:
|
|
|
+ * Refer modinfo or MODULE_PARM_DESC description below for details.
|
|
|
+ *
|
|
|
+ * Manual configuration options:
|
|
|
* [0] - Amplitude in microvolts for fake waveforms (default 1 volt)
|
|
|
* [1] - Period in microseconds for fake waveforms (default 0.1 sec)
|
|
|
*
|
|
@@ -53,8 +61,27 @@
|
|
|
#include <linux/timer.h>
|
|
|
#include <linux/ktime.h>
|
|
|
#include <linux/jiffies.h>
|
|
|
+#include <linux/device.h>
|
|
|
+#include <linux/kdev_t.h>
|
|
|
|
|
|
#define N_CHANS 8
|
|
|
+#define DEV_NAME "comedi_testd"
|
|
|
+#define CLASS_NAME "comedi_test"
|
|
|
+
|
|
|
+static bool config_mode;
|
|
|
+static unsigned int set_amplitude;
|
|
|
+static unsigned int set_period;
|
|
|
+static struct class *ctcls;
|
|
|
+static struct device *ctdev;
|
|
|
+
|
|
|
+module_param_named(noauto, config_mode, bool, 0444);
|
|
|
+MODULE_PARM_DESC(noauto, "Disable auto-configuration: (1=disable [defaults to enable])");
|
|
|
+
|
|
|
+module_param_named(amplitude, set_amplitude, uint, 0444);
|
|
|
+MODULE_PARM_DESC(amplitude, "Set auto mode wave amplitude in microvolts: (defaults to 1 volt)");
|
|
|
+
|
|
|
+module_param_named(period, set_period, uint, 0444);
|
|
|
+MODULE_PARM_DESC(period, "Set auto mode wave period in microseconds: (defaults to 0.1 sec)");
|
|
|
|
|
|
/* Data unique to this driver */
|
|
|
struct waveform_private {
|
|
@@ -607,13 +634,11 @@ static int waveform_ao_insn_write(struct comedi_device *dev,
|
|
|
return insn->n;
|
|
|
}
|
|
|
|
|
|
-static int waveform_attach(struct comedi_device *dev,
|
|
|
- struct comedi_devconfig *it)
|
|
|
+static int waveform_common_attach(struct comedi_device *dev,
|
|
|
+ int amplitude, int period)
|
|
|
{
|
|
|
struct waveform_private *devpriv;
|
|
|
struct comedi_subdevice *s;
|
|
|
- int amplitude = it->options[0];
|
|
|
- int period = it->options[1];
|
|
|
int i;
|
|
|
int ret;
|
|
|
|
|
@@ -621,12 +646,6 @@ static int waveform_attach(struct comedi_device *dev,
|
|
|
if (!devpriv)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- /* set default amplitude and period */
|
|
|
- if (amplitude <= 0)
|
|
|
- amplitude = 1000000; /* 1 volt */
|
|
|
- if (period <= 0)
|
|
|
- period = 100000; /* 0.1 sec */
|
|
|
-
|
|
|
devpriv->wf_amplitude = amplitude;
|
|
|
devpriv->wf_period = period;
|
|
|
|
|
@@ -678,6 +697,36 @@ static int waveform_attach(struct comedi_device *dev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int waveform_attach(struct comedi_device *dev,
|
|
|
+ struct comedi_devconfig *it)
|
|
|
+{
|
|
|
+ int amplitude = it->options[0];
|
|
|
+ int period = it->options[1];
|
|
|
+
|
|
|
+ /* set default amplitude and period */
|
|
|
+ if (amplitude <= 0)
|
|
|
+ amplitude = 1000000; /* 1 volt */
|
|
|
+ if (period <= 0)
|
|
|
+ period = 100000; /* 0.1 sec */
|
|
|
+
|
|
|
+ return waveform_common_attach(dev, amplitude, period);
|
|
|
+}
|
|
|
+
|
|
|
+static int waveform_auto_attach(struct comedi_device *dev,
|
|
|
+ unsigned long context_unused)
|
|
|
+{
|
|
|
+ int amplitude = set_amplitude;
|
|
|
+ int period = set_period;
|
|
|
+
|
|
|
+ /* set default amplitude and period */
|
|
|
+ if (!amplitude)
|
|
|
+ amplitude = 1000000; /* 1 volt */
|
|
|
+ if (!period)
|
|
|
+ period = 100000; /* 0.1 sec */
|
|
|
+
|
|
|
+ return waveform_common_attach(dev, amplitude, period);
|
|
|
+}
|
|
|
+
|
|
|
static void waveform_detach(struct comedi_device *dev)
|
|
|
{
|
|
|
struct waveform_private *devpriv = dev->private;
|
|
@@ -692,9 +741,71 @@ static struct comedi_driver waveform_driver = {
|
|
|
.driver_name = "comedi_test",
|
|
|
.module = THIS_MODULE,
|
|
|
.attach = waveform_attach,
|
|
|
+ .auto_attach = waveform_auto_attach,
|
|
|
.detach = waveform_detach,
|
|
|
};
|
|
|
-module_comedi_driver(waveform_driver);
|
|
|
+
|
|
|
+/*
|
|
|
+ * For auto-configuration, a device is created to stand in for a
|
|
|
+ * real hardware device.
|
|
|
+ */
|
|
|
+static int __init comedi_test_init(void)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = comedi_driver_register(&waveform_driver);
|
|
|
+ if (ret) {
|
|
|
+ pr_err("comedi_test: unable to register driver\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!config_mode) {
|
|
|
+ ctcls = class_create(THIS_MODULE, CLASS_NAME);
|
|
|
+ if (IS_ERR(ctcls)) {
|
|
|
+ pr_warn("comedi_test: unable to create class\n");
|
|
|
+ goto clean3;
|
|
|
+ }
|
|
|
+
|
|
|
+ ctdev = device_create(ctcls, NULL, MKDEV(0, 0), NULL, DEV_NAME);
|
|
|
+ if (IS_ERR(ctdev)) {
|
|
|
+ pr_warn("comedi_test: unable to create device\n");
|
|
|
+ goto clean2;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = comedi_auto_config(ctdev, &waveform_driver, 0);
|
|
|
+ if (ret) {
|
|
|
+ pr_warn("comedi_test: unable to auto-configure device\n");
|
|
|
+ goto clean;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+clean:
|
|
|
+ device_destroy(ctcls, MKDEV(0, 0));
|
|
|
+clean2:
|
|
|
+ class_destroy(ctcls);
|
|
|
+ ctdev = NULL;
|
|
|
+clean3:
|
|
|
+ ctcls = NULL;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+module_init(comedi_test_init);
|
|
|
+
|
|
|
+static void __exit comedi_test_exit(void)
|
|
|
+{
|
|
|
+ if (ctdev)
|
|
|
+ comedi_auto_unconfig(ctdev);
|
|
|
+
|
|
|
+ if (ctcls) {
|
|
|
+ device_destroy(ctcls, MKDEV(0, 0));
|
|
|
+ class_destroy(ctcls);
|
|
|
+ }
|
|
|
+
|
|
|
+ comedi_driver_unregister(&waveform_driver);
|
|
|
+}
|
|
|
+module_exit(comedi_test_exit);
|
|
|
|
|
|
MODULE_AUTHOR("Comedi http://www.comedi.org");
|
|
|
MODULE_DESCRIPTION("Comedi low-level driver");
|