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 153 void fbtft_expand_debug_value(unsigned long *debug) 154 { 155 switch (*debug & 0x7) { 156 case 1: 157 *debug |= DEBUG_LEVEL_1; 158 break; 159 case 2: 160 *debug |= DEBUG_LEVEL_2; 161 break; 162 case 3: 163 *debug |= DEBUG_LEVEL_3; 164 break; 165 case 4: 166 *debug |= DEBUG_LEVEL_4; 167 break; 168 case 5: 169 *debug |= DEBUG_LEVEL_5; 170 break; 171 case 6: 172 *debug |= DEBUG_LEVEL_6; 173 break; 174 case 7: 175 *debug = 0xFFFFFFFF; 176 break; 177 } 178 } 179 180 static ssize_t store_debug(struct device *device, 181 struct device_attribute *attr, 182 const char *buf, size_t count) 183 { 184 struct fb_info *fb_info = dev_get_drvdata(device); 185 struct fbtft_par *par = fb_info->par; 186 int ret; 187 188 ret = kstrtoul(buf, 10, &par->debug); 189 if (ret) 190 return ret; 191 fbtft_expand_debug_value(&par->debug); 192 193 return count; 194 } 195 196 static ssize_t show_debug(struct device *device, 197 struct device_attribute *attr, char *buf) 198 { 199 struct fb_info *fb_info = dev_get_drvdata(device); 200 struct fbtft_par *par = fb_info->par; 201 202 return snprintf(buf, PAGE_SIZE, "%lu\n", par->debug); 203 } 204 205 static struct device_attribute debug_device_attr = \ 206 __ATTR(debug, 0660, show_debug, store_debug); 207 208 209 void fbtft_sysfs_init(struct fbtft_par *par) 210 { 211 device_create_file(par->info->dev, &debug_device_attr); 212 if (par->gamma.curves && par->fbtftops.set_gamma) 213 device_create_file(par->info->dev, &gamma_device_attrs[0]); 214 } 215 216 void fbtft_sysfs_exit(struct fbtft_par *par) 217 { 218 device_remove_file(par->info->dev, &debug_device_attr); 219 if (par->gamma.curves && par->fbtftops.set_gamma) 220 device_remove_file(par->info->dev, &gamma_device_attrs[0]); 221 } 222