1 #include "fbtft.h" 2 #include "internal.h" 3 4 static int get_next_ulong(char **str_p, unsigned long *val, char *sep, int base) 5 { 6 char *p_val; 7 int ret; 8 9 if (!str_p || !(*str_p)) 10 return -EINVAL; 11 12 p_val = strsep(str_p, sep); 13 14 if (!p_val) 15 return -EINVAL; 16 17 ret = kstrtoul(p_val, base, val); 18 if (ret) 19 return -EINVAL; 20 21 return 0; 22 } 23 24 int fbtft_gamma_parse_str(struct fbtft_par *par, unsigned long *curves, 25 const char *str, int size) 26 { 27 char *str_p, *curve_p = NULL; 28 char *tmp; 29 unsigned long val = 0; 30 int ret = 0; 31 int curve_counter, value_counter; 32 33 fbtft_par_dbg(DEBUG_SYSFS, par, "%s() str=\n", __func__); 34 35 if (!str || !curves) 36 return -EINVAL; 37 38 fbtft_par_dbg(DEBUG_SYSFS, par, "%s\n", str); 39 40 tmp = kmemdup(str, size + 1, GFP_KERNEL); 41 if (!tmp) 42 return -ENOMEM; 43 44 /* replace optional separators */ 45 str_p = tmp; 46 while (*str_p) { 47 if (*str_p == ',') 48 *str_p = ' '; 49 if (*str_p == ';') 50 *str_p = '\n'; 51 str_p++; 52 } 53 54 str_p = strim(tmp); 55 56 curve_counter = 0; 57 while (str_p) { 58 if (curve_counter == par->gamma.num_curves) { 59 dev_err(par->info->device, "Gamma: Too many curves\n"); 60 ret = -EINVAL; 61 goto out; 62 } 63 curve_p = strsep(&str_p, "\n"); 64 value_counter = 0; 65 while (curve_p) { 66 if (value_counter == par->gamma.num_values) { 67 dev_err(par->info->device, 68 "Gamma: Too many values\n"); 69 ret = -EINVAL; 70 goto out; 71 } 72 ret = get_next_ulong(&curve_p, &val, " ", 16); 73 if (ret) 74 goto out; 75 curves[curve_counter * par->gamma.num_values + value_counter] = val; 76 value_counter++; 77 } 78 if (value_counter != par->gamma.num_values) { 79 dev_err(par->info->device, "Gamma: Too few values\n"); 80 ret = -EINVAL; 81 goto out; 82 } 83 curve_counter++; 84 } 85 if (curve_counter != par->gamma.num_curves) { 86 dev_err(par->info->device, "Gamma: Too few curves\n"); 87 ret = -EINVAL; 88 goto out; 89 } 90 91 out: 92 kfree(tmp); 93 return ret; 94 } 95 96 static ssize_t 97 sprintf_gamma(struct fbtft_par *par, unsigned long *curves, char *buf) 98 { 99 ssize_t len = 0; 100 unsigned int i, j; 101 102 mutex_lock(&par->gamma.lock); 103 for (i = 0; i < par->gamma.num_curves; i++) { 104 for (j = 0; j < par->gamma.num_values; j++) 105 len += scnprintf(&buf[len], PAGE_SIZE, 106 "%04lx ", curves[i * par->gamma.num_values + j]); 107 buf[len - 1] = '\n'; 108 } 109 mutex_unlock(&par->gamma.lock); 110 111 return len; 112 } 113 114 static ssize_t store_gamma_curve(struct device *device, 115 struct device_attribute *attr, 116 const char *buf, size_t count) 117 { 118 struct fb_info *fb_info = dev_get_drvdata(device); 119 struct fbtft_par *par = fb_info->par; 120 unsigned long tmp_curves[FBTFT_GAMMA_MAX_VALUES_TOTAL]; 121 int ret; 122 123 ret = fbtft_gamma_parse_str(par, tmp_curves, buf, count); 124 if (ret) 125 return ret; 126 127 ret = par->fbtftops.set_gamma(par, tmp_curves); 128 if (ret) 129 return ret; 130 131 mutex_lock(&par->gamma.lock); 132 memcpy(par->gamma.curves, tmp_curves, 133 par->gamma.num_curves * par->gamma.num_values * sizeof(tmp_curves[0])); 134 mutex_unlock(&par->gamma.lock); 135 136 return count; 137 } 138 139 static ssize_t show_gamma_curve(struct device *device, 140 struct device_attribute *attr, char *buf) 141 { 142 struct fb_info *fb_info = dev_get_drvdata(device); 143 struct fbtft_par *par = fb_info->par; 144 145 return sprintf_gamma(par, par->gamma.curves, buf); 146 } 147 148 static struct device_attribute gamma_device_attrs[] = { 149 __ATTR(gamma, 0660, show_gamma_curve, store_gamma_curve), 150 }; 151 152 void fbtft_expand_debug_value(unsigned long *debug) 153 { 154 switch (*debug & 0x7) { 155 case 1: 156 *debug |= DEBUG_LEVEL_1; 157 break; 158 case 2: 159 *debug |= DEBUG_LEVEL_2; 160 break; 161 case 3: 162 *debug |= DEBUG_LEVEL_3; 163 break; 164 case 4: 165 *debug |= DEBUG_LEVEL_4; 166 break; 167 case 5: 168 *debug |= DEBUG_LEVEL_5; 169 break; 170 case 6: 171 *debug |= DEBUG_LEVEL_6; 172 break; 173 case 7: 174 *debug = 0xFFFFFFFF; 175 break; 176 } 177 } 178 179 static ssize_t store_debug(struct device *device, 180 struct device_attribute *attr, 181 const char *buf, size_t count) 182 { 183 struct fb_info *fb_info = dev_get_drvdata(device); 184 struct fbtft_par *par = fb_info->par; 185 int ret; 186 187 ret = kstrtoul(buf, 10, &par->debug); 188 if (ret) 189 return ret; 190 fbtft_expand_debug_value(&par->debug); 191 192 return count; 193 } 194 195 static ssize_t show_debug(struct device *device, 196 struct device_attribute *attr, char *buf) 197 { 198 struct fb_info *fb_info = dev_get_drvdata(device); 199 struct fbtft_par *par = fb_info->par; 200 201 return snprintf(buf, PAGE_SIZE, "%lu\n", par->debug); 202 } 203 204 static struct device_attribute debug_device_attr = \ 205 __ATTR(debug, 0660, show_debug, store_debug); 206 207 void fbtft_sysfs_init(struct fbtft_par *par) 208 { 209 device_create_file(par->info->dev, &debug_device_attr); 210 if (par->gamma.curves && par->fbtftops.set_gamma) 211 device_create_file(par->info->dev, &gamma_device_attrs[0]); 212 } 213 214 void fbtft_sysfs_exit(struct fbtft_par *par) 215 { 216 device_remove_file(par->info->dev, &debug_device_attr); 217 if (par->gamma.curves && par->fbtftops.set_gamma) 218 device_remove_file(par->info->dev, &gamma_device_attrs[0]); 219 } 220