1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2023 Intel Corporation 4 */ 5 6 #include <linux/debugfs.h> 7 #include <linux/kernel.h> 8 9 #include <drm/drm_drv.h> 10 #include <drm/drm_file.h> 11 12 #include "intel_display_core.h" 13 #include "intel_display_debugfs_params.h" 14 #include "intel_display_params.h" 15 16 /* int param */ 17 static int intel_display_param_int_show(struct seq_file *m, void *data) 18 { 19 int *value = m->private; 20 21 seq_printf(m, "%d\n", *value); 22 23 return 0; 24 } 25 26 static int intel_display_param_int_open(struct inode *inode, struct file *file) 27 { 28 return single_open(file, intel_display_param_int_show, inode->i_private); 29 } 30 31 static ssize_t intel_display_param_int_write(struct file *file, 32 const char __user *ubuf, size_t len, 33 loff_t *offp) 34 { 35 struct seq_file *m = file->private_data; 36 int *value = m->private; 37 int ret; 38 39 ret = kstrtoint_from_user(ubuf, len, 0, value); 40 if (ret) { 41 /* support boolean values too */ 42 bool b; 43 44 ret = kstrtobool_from_user(ubuf, len, &b); 45 if (!ret) 46 *value = b; 47 } 48 49 return ret ?: len; 50 } 51 52 static const struct file_operations intel_display_param_int_fops = { 53 .owner = THIS_MODULE, 54 .open = intel_display_param_int_open, 55 .read = seq_read, 56 .write = intel_display_param_int_write, 57 .llseek = default_llseek, 58 .release = single_release, 59 }; 60 61 static const struct file_operations intel_display_param_int_fops_ro = { 62 .owner = THIS_MODULE, 63 .open = intel_display_param_int_open, 64 .read = seq_read, 65 .llseek = default_llseek, 66 .release = single_release, 67 }; 68 69 /* unsigned int param */ 70 static int intel_display_param_uint_show(struct seq_file *m, void *data) 71 { 72 unsigned int *value = m->private; 73 74 seq_printf(m, "%u\n", *value); 75 76 return 0; 77 } 78 79 static int intel_display_param_uint_open(struct inode *inode, struct file *file) 80 { 81 return single_open(file, intel_display_param_uint_show, inode->i_private); 82 } 83 84 static ssize_t intel_display_param_uint_write(struct file *file, 85 const char __user *ubuf, size_t len, 86 loff_t *offp) 87 { 88 struct seq_file *m = file->private_data; 89 unsigned int *value = m->private; 90 int ret; 91 92 ret = kstrtouint_from_user(ubuf, len, 0, value); 93 if (ret) { 94 /* support boolean values too */ 95 bool b; 96 97 ret = kstrtobool_from_user(ubuf, len, &b); 98 if (!ret) 99 *value = b; 100 } 101 102 return ret ?: len; 103 } 104 105 static const struct file_operations intel_display_param_uint_fops = { 106 .owner = THIS_MODULE, 107 .open = intel_display_param_uint_open, 108 .read = seq_read, 109 .write = intel_display_param_uint_write, 110 .llseek = default_llseek, 111 .release = single_release, 112 }; 113 114 static const struct file_operations intel_display_param_uint_fops_ro = { 115 .owner = THIS_MODULE, 116 .open = intel_display_param_uint_open, 117 .read = seq_read, 118 .llseek = default_llseek, 119 .release = single_release, 120 }; 121 122 #define RO(mode) (((mode) & 0222) == 0) 123 124 __maybe_unused static struct dentry * 125 intel_display_debugfs_create_int(const char *name, umode_t mode, 126 struct dentry *parent, int *value) 127 { 128 return debugfs_create_file_unsafe(name, mode, parent, value, 129 RO(mode) ? &intel_display_param_int_fops_ro : 130 &intel_display_param_int_fops); 131 } 132 133 __maybe_unused static struct dentry * 134 intel_display_debugfs_create_uint(const char *name, umode_t mode, 135 struct dentry *parent, unsigned int *value) 136 { 137 return debugfs_create_file_unsafe(name, mode, parent, value, 138 RO(mode) ? &intel_display_param_uint_fops_ro : 139 &intel_display_param_uint_fops); 140 } 141 142 #define _intel_display_param_create_file(parent, name, mode, valp) \ 143 do { \ 144 if (mode) \ 145 _Generic(valp, \ 146 bool * : debugfs_create_bool, \ 147 int * : intel_display_debugfs_create_int, \ 148 unsigned int * : intel_display_debugfs_create_uint, \ 149 unsigned long * : debugfs_create_ulong, \ 150 char ** : debugfs_create_str) \ 151 (name, mode, parent, valp); \ 152 } while (0) 153 154 /* add a subdirectory with files for each intel display param */ 155 void intel_display_debugfs_params(struct intel_display *display) 156 { 157 struct drm_minor *minor = display->drm->primary; 158 struct dentry *dir; 159 char dirname[16]; 160 161 snprintf(dirname, sizeof(dirname), "%s_params", display->drm->driver->name); 162 dir = debugfs_lookup(dirname, minor->debugfs_root); 163 if (!dir) 164 dir = debugfs_create_dir(dirname, minor->debugfs_root); 165 if (IS_ERR(dir)) 166 return; 167 168 /* 169 * Note: We could create files for params needing special handling 170 * here. Set mode in params to 0 to skip the generic create file, or 171 * just let the generic create file fail silently with -EEXIST. 172 */ 173 174 #define REGISTER(T, x, unused, mode, ...) _intel_display_param_create_file( \ 175 dir, #x, mode, &display->params.x); 176 INTEL_DISPLAY_PARAMS_FOR_EACH(REGISTER); 177 #undef REGISTER 178 } 179