0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/hrtimer.h>
0013 #include <linux/slab.h>
0014 #include <linux/stm.h>
0015
0016 #define STM_HEARTBEAT_MAX 32
0017
0018 static int nr_devs = 4;
0019 static int interval_ms = 10;
0020
0021 module_param(nr_devs, int, 0400);
0022 module_param(interval_ms, int, 0600);
0023
0024 static struct stm_heartbeat {
0025 struct stm_source_data data;
0026 struct hrtimer hrtimer;
0027 unsigned int active;
0028 } stm_heartbeat[STM_HEARTBEAT_MAX];
0029
0030 static const char str[] = "heartbeat stm source driver is here to serve you";
0031
0032 static enum hrtimer_restart stm_heartbeat_hrtimer_handler(struct hrtimer *hr)
0033 {
0034 struct stm_heartbeat *heartbeat = container_of(hr, struct stm_heartbeat,
0035 hrtimer);
0036
0037 stm_source_write(&heartbeat->data, 0, str, sizeof str);
0038 if (heartbeat->active)
0039 hrtimer_forward_now(hr, ms_to_ktime(interval_ms));
0040
0041 return heartbeat->active ? HRTIMER_RESTART : HRTIMER_NORESTART;
0042 }
0043
0044 static int stm_heartbeat_link(struct stm_source_data *data)
0045 {
0046 struct stm_heartbeat *heartbeat =
0047 container_of(data, struct stm_heartbeat, data);
0048
0049 heartbeat->active = 1;
0050 hrtimer_start(&heartbeat->hrtimer, ms_to_ktime(interval_ms),
0051 HRTIMER_MODE_ABS);
0052
0053 return 0;
0054 }
0055
0056 static void stm_heartbeat_unlink(struct stm_source_data *data)
0057 {
0058 struct stm_heartbeat *heartbeat =
0059 container_of(data, struct stm_heartbeat, data);
0060
0061 heartbeat->active = 0;
0062 hrtimer_cancel(&heartbeat->hrtimer);
0063 }
0064
0065 static int stm_heartbeat_init(void)
0066 {
0067 int i, ret;
0068
0069 if (nr_devs < 0 || nr_devs > STM_HEARTBEAT_MAX)
0070 return -EINVAL;
0071
0072 for (i = 0; i < nr_devs; i++) {
0073 stm_heartbeat[i].data.name =
0074 kasprintf(GFP_KERNEL, "heartbeat.%d", i);
0075 if (!stm_heartbeat[i].data.name) {
0076 ret = -ENOMEM;
0077 goto fail_unregister;
0078 }
0079
0080 stm_heartbeat[i].data.nr_chans = 1;
0081 stm_heartbeat[i].data.link = stm_heartbeat_link;
0082 stm_heartbeat[i].data.unlink = stm_heartbeat_unlink;
0083 hrtimer_init(&stm_heartbeat[i].hrtimer, CLOCK_MONOTONIC,
0084 HRTIMER_MODE_ABS);
0085 stm_heartbeat[i].hrtimer.function =
0086 stm_heartbeat_hrtimer_handler;
0087
0088 ret = stm_source_register_device(NULL, &stm_heartbeat[i].data);
0089 if (ret)
0090 goto fail_free;
0091 }
0092
0093 return 0;
0094
0095 fail_unregister:
0096 for (i--; i >= 0; i--) {
0097 stm_source_unregister_device(&stm_heartbeat[i].data);
0098 fail_free:
0099 kfree(stm_heartbeat[i].data.name);
0100 }
0101
0102 return ret;
0103 }
0104
0105 static void stm_heartbeat_exit(void)
0106 {
0107 int i;
0108
0109 for (i = 0; i < nr_devs; i++) {
0110 stm_source_unregister_device(&stm_heartbeat[i].data);
0111 kfree(stm_heartbeat[i].data.name);
0112 }
0113 }
0114
0115 module_init(stm_heartbeat_init);
0116 module_exit(stm_heartbeat_exit);
0117
0118 MODULE_LICENSE("GPL v2");
0119 MODULE_DESCRIPTION("stm_heartbeat driver");
0120 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");