1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * A dummy STM device for stm/stm_source class testing. 4 * Copyright (c) 2014, Intel Corporation. 5 * 6 * STM class implements generic infrastructure for System Trace Module devices 7 * as defined in MIPI STPv2 specification. 8 */ 9 10 #undef DEBUG 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/slab.h> 14 #include <linux/stm.h> 15 #include <uapi/linux/stm.h> 16 17 static ssize_t notrace 18 dummy_stm_packet(struct stm_data *stm_data, unsigned int master, 19 unsigned int channel, unsigned int packet, unsigned int flags, 20 unsigned int size, const unsigned char *payload) 21 { 22 #ifdef DEBUG 23 u64 pl = 0; 24 25 if (payload) 26 pl = *(u64 *)payload; 27 28 if (size < 8) 29 pl &= (1ull << (size * 8)) - 1; 30 trace_printk("[%u:%u] [pkt: %x/%x] (%llx)\n", master, channel, 31 packet, size, pl); 32 #endif 33 return size; 34 } 35 36 #define DUMMY_STM_MAX 32 37 38 static struct stm_data dummy_stm[DUMMY_STM_MAX]; 39 40 static int nr_dummies = 4; 41 42 module_param(nr_dummies, int, 0400); 43 44 static unsigned int fail_mode; 45 46 module_param(fail_mode, int, 0600); 47 48 static unsigned int master_min; 49 50 module_param(master_min, int, 0400); 51 52 static unsigned int master_max = STP_MASTER_MAX; 53 54 module_param(master_max, int, 0400); 55 56 static unsigned int nr_channels = STP_CHANNEL_MAX; 57 58 module_param(nr_channels, int, 0400); 59 60 static int dummy_stm_link(struct stm_data *data, unsigned int master, 61 unsigned int channel) 62 { 63 if (fail_mode && (channel & fail_mode)) 64 return -EINVAL; 65 66 return 0; 67 } 68 69 static int dummy_stm_init(void) 70 { 71 int i, ret = -ENOMEM; 72 73 if (nr_dummies < 0 || nr_dummies > DUMMY_STM_MAX) 74 return -EINVAL; 75 76 if (master_min > master_max || 77 master_max > STP_MASTER_MAX || 78 nr_channels > STP_CHANNEL_MAX) 79 return -EINVAL; 80 81 for (i = 0; i < nr_dummies; i++) { 82 dummy_stm[i].name = kasprintf(GFP_KERNEL, "dummy_stm.%d", i); 83 if (!dummy_stm[i].name) 84 goto fail_unregister; 85 86 dummy_stm[i].sw_start = master_min; 87 dummy_stm[i].sw_end = master_max; 88 dummy_stm[i].sw_nchannels = nr_channels; 89 dummy_stm[i].packet = dummy_stm_packet; 90 dummy_stm[i].link = dummy_stm_link; 91 92 ret = stm_register_device(NULL, &dummy_stm[i], THIS_MODULE); 93 if (ret) 94 goto fail_free; 95 } 96 97 return 0; 98 99 fail_unregister: 100 for (i--; i >= 0; i--) { 101 stm_unregister_device(&dummy_stm[i]); 102 fail_free: 103 kfree(dummy_stm[i].name); 104 } 105 106 return ret; 107 108 } 109 110 static void dummy_stm_exit(void) 111 { 112 int i; 113 114 for (i = 0; i < nr_dummies; i++) { 115 stm_unregister_device(&dummy_stm[i]); 116 kfree(dummy_stm[i].name); 117 } 118 } 119 120 module_init(dummy_stm_init); 121 module_exit(dummy_stm_exit); 122 123 MODULE_LICENSE("GPL v2"); 124 MODULE_DESCRIPTION("dummy_stm device"); 125 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>"); 126