Commit c4270637ff379163d22721b897f0dc5592794c68

Authored by Antonino A. Daplas
Committed by Linus Torvalds
1 parent 464bdd33e9

fbdev: fix obvious bug in show_pan()

show_pan will display the value of the xoffset twice, instead of the xoffset
and yoffset.  Fix.

Signed-off-by: Antonino Daplas <adaplas@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 1 changed file with 1 additions and 1 deletions Inline Diff

drivers/video/fbsysfs.c
1 /* 1 /*
2 * fbsysfs.c - framebuffer device class and attributes 2 * fbsysfs.c - framebuffer device class and attributes
3 * 3 *
4 * Copyright (c) 2004 James Simmons <jsimmons@infradead.org> 4 * Copyright (c) 2004 James Simmons <jsimmons@infradead.org>
5 * 5 *
6 * This program is free software you can redistribute it and/or 6 * This program is free software you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License 7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version. 9 * 2 of the License, or (at your option) any later version.
10 */ 10 */
11 11
12 /* 12 /*
13 * Note: currently there's only stubs for framebuffer_alloc and 13 * Note: currently there's only stubs for framebuffer_alloc and
14 * framebuffer_release here. The reson for that is that until all drivers 14 * framebuffer_release here. The reson for that is that until all drivers
15 * are converted to use it a sysfsification will open OOPSable races. 15 * are converted to use it a sysfsification will open OOPSable races.
16 */ 16 */
17 17
18 #include <linux/kernel.h> 18 #include <linux/kernel.h>
19 #include <linux/fb.h> 19 #include <linux/fb.h>
20 #include <linux/console.h> 20 #include <linux/console.h>
21 #include <linux/module.h> 21 #include <linux/module.h>
22 22
23 #define FB_SYSFS_FLAG_ATTR 1 23 #define FB_SYSFS_FLAG_ATTR 1
24 24
25 /** 25 /**
26 * framebuffer_alloc - creates a new frame buffer info structure 26 * framebuffer_alloc - creates a new frame buffer info structure
27 * 27 *
28 * @size: size of driver private data, can be zero 28 * @size: size of driver private data, can be zero
29 * @dev: pointer to the device for this fb, this can be NULL 29 * @dev: pointer to the device for this fb, this can be NULL
30 * 30 *
31 * Creates a new frame buffer info structure. Also reserves @size bytes 31 * Creates a new frame buffer info structure. Also reserves @size bytes
32 * for driver private data (info->par). info->par (if any) will be 32 * for driver private data (info->par). info->par (if any) will be
33 * aligned to sizeof(long). 33 * aligned to sizeof(long).
34 * 34 *
35 * Returns the new structure, or NULL if an error occured. 35 * Returns the new structure, or NULL if an error occured.
36 * 36 *
37 */ 37 */
38 struct fb_info *framebuffer_alloc(size_t size, struct device *dev) 38 struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
39 { 39 {
40 #define BYTES_PER_LONG (BITS_PER_LONG/8) 40 #define BYTES_PER_LONG (BITS_PER_LONG/8)
41 #define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG)) 41 #define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
42 int fb_info_size = sizeof(struct fb_info); 42 int fb_info_size = sizeof(struct fb_info);
43 struct fb_info *info; 43 struct fb_info *info;
44 char *p; 44 char *p;
45 45
46 if (size) 46 if (size)
47 fb_info_size += PADDING; 47 fb_info_size += PADDING;
48 48
49 p = kzalloc(fb_info_size + size, GFP_KERNEL); 49 p = kzalloc(fb_info_size + size, GFP_KERNEL);
50 50
51 if (!p) 51 if (!p)
52 return NULL; 52 return NULL;
53 53
54 info = (struct fb_info *) p; 54 info = (struct fb_info *) p;
55 55
56 if (size) 56 if (size)
57 info->par = p + fb_info_size; 57 info->par = p + fb_info_size;
58 58
59 info->device = dev; 59 info->device = dev;
60 60
61 #ifdef CONFIG_FB_BACKLIGHT 61 #ifdef CONFIG_FB_BACKLIGHT
62 mutex_init(&info->bl_curve_mutex); 62 mutex_init(&info->bl_curve_mutex);
63 #endif 63 #endif
64 64
65 return info; 65 return info;
66 #undef PADDING 66 #undef PADDING
67 #undef BYTES_PER_LONG 67 #undef BYTES_PER_LONG
68 } 68 }
69 EXPORT_SYMBOL(framebuffer_alloc); 69 EXPORT_SYMBOL(framebuffer_alloc);
70 70
71 /** 71 /**
72 * framebuffer_release - marks the structure available for freeing 72 * framebuffer_release - marks the structure available for freeing
73 * 73 *
74 * @info: frame buffer info structure 74 * @info: frame buffer info structure
75 * 75 *
76 * Drop the reference count of the device embedded in the 76 * Drop the reference count of the device embedded in the
77 * framebuffer info structure. 77 * framebuffer info structure.
78 * 78 *
79 */ 79 */
80 void framebuffer_release(struct fb_info *info) 80 void framebuffer_release(struct fb_info *info)
81 { 81 {
82 kfree(info); 82 kfree(info);
83 } 83 }
84 EXPORT_SYMBOL(framebuffer_release); 84 EXPORT_SYMBOL(framebuffer_release);
85 85
86 static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var) 86 static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
87 { 87 {
88 int err; 88 int err;
89 89
90 var->activate |= FB_ACTIVATE_FORCE; 90 var->activate |= FB_ACTIVATE_FORCE;
91 acquire_console_sem(); 91 acquire_console_sem();
92 fb_info->flags |= FBINFO_MISC_USEREVENT; 92 fb_info->flags |= FBINFO_MISC_USEREVENT;
93 err = fb_set_var(fb_info, var); 93 err = fb_set_var(fb_info, var);
94 fb_info->flags &= ~FBINFO_MISC_USEREVENT; 94 fb_info->flags &= ~FBINFO_MISC_USEREVENT;
95 release_console_sem(); 95 release_console_sem();
96 if (err) 96 if (err)
97 return err; 97 return err;
98 return 0; 98 return 0;
99 } 99 }
100 100
101 static int mode_string(char *buf, unsigned int offset, 101 static int mode_string(char *buf, unsigned int offset,
102 const struct fb_videomode *mode) 102 const struct fb_videomode *mode)
103 { 103 {
104 char m = 'U'; 104 char m = 'U';
105 char v = 'p'; 105 char v = 'p';
106 106
107 if (mode->flag & FB_MODE_IS_DETAILED) 107 if (mode->flag & FB_MODE_IS_DETAILED)
108 m = 'D'; 108 m = 'D';
109 if (mode->flag & FB_MODE_IS_VESA) 109 if (mode->flag & FB_MODE_IS_VESA)
110 m = 'V'; 110 m = 'V';
111 if (mode->flag & FB_MODE_IS_STANDARD) 111 if (mode->flag & FB_MODE_IS_STANDARD)
112 m = 'S'; 112 m = 'S';
113 113
114 if (mode->vmode & FB_VMODE_INTERLACED) 114 if (mode->vmode & FB_VMODE_INTERLACED)
115 v = 'i'; 115 v = 'i';
116 if (mode->vmode & FB_VMODE_DOUBLE) 116 if (mode->vmode & FB_VMODE_DOUBLE)
117 v = 'd'; 117 v = 'd';
118 118
119 return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d%c-%d\n", 119 return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d%c-%d\n",
120 m, mode->xres, mode->yres, v, mode->refresh); 120 m, mode->xres, mode->yres, v, mode->refresh);
121 } 121 }
122 122
123 static ssize_t store_mode(struct device *device, struct device_attribute *attr, 123 static ssize_t store_mode(struct device *device, struct device_attribute *attr,
124 const char *buf, size_t count) 124 const char *buf, size_t count)
125 { 125 {
126 struct fb_info *fb_info = dev_get_drvdata(device); 126 struct fb_info *fb_info = dev_get_drvdata(device);
127 char mstr[100]; 127 char mstr[100];
128 struct fb_var_screeninfo var; 128 struct fb_var_screeninfo var;
129 struct fb_modelist *modelist; 129 struct fb_modelist *modelist;
130 struct fb_videomode *mode; 130 struct fb_videomode *mode;
131 struct list_head *pos; 131 struct list_head *pos;
132 size_t i; 132 size_t i;
133 int err; 133 int err;
134 134
135 memset(&var, 0, sizeof(var)); 135 memset(&var, 0, sizeof(var));
136 136
137 list_for_each(pos, &fb_info->modelist) { 137 list_for_each(pos, &fb_info->modelist) {
138 modelist = list_entry(pos, struct fb_modelist, list); 138 modelist = list_entry(pos, struct fb_modelist, list);
139 mode = &modelist->mode; 139 mode = &modelist->mode;
140 i = mode_string(mstr, 0, mode); 140 i = mode_string(mstr, 0, mode);
141 if (strncmp(mstr, buf, max(count, i)) == 0) { 141 if (strncmp(mstr, buf, max(count, i)) == 0) {
142 142
143 var = fb_info->var; 143 var = fb_info->var;
144 fb_videomode_to_var(&var, mode); 144 fb_videomode_to_var(&var, mode);
145 if ((err = activate(fb_info, &var))) 145 if ((err = activate(fb_info, &var)))
146 return err; 146 return err;
147 fb_info->mode = mode; 147 fb_info->mode = mode;
148 return count; 148 return count;
149 } 149 }
150 } 150 }
151 return -EINVAL; 151 return -EINVAL;
152 } 152 }
153 153
154 static ssize_t show_mode(struct device *device, struct device_attribute *attr, 154 static ssize_t show_mode(struct device *device, struct device_attribute *attr,
155 char *buf) 155 char *buf)
156 { 156 {
157 struct fb_info *fb_info = dev_get_drvdata(device); 157 struct fb_info *fb_info = dev_get_drvdata(device);
158 158
159 if (!fb_info->mode) 159 if (!fb_info->mode)
160 return 0; 160 return 0;
161 161
162 return mode_string(buf, 0, fb_info->mode); 162 return mode_string(buf, 0, fb_info->mode);
163 } 163 }
164 164
165 static ssize_t store_modes(struct device *device, 165 static ssize_t store_modes(struct device *device,
166 struct device_attribute *attr, 166 struct device_attribute *attr,
167 const char *buf, size_t count) 167 const char *buf, size_t count)
168 { 168 {
169 struct fb_info *fb_info = dev_get_drvdata(device); 169 struct fb_info *fb_info = dev_get_drvdata(device);
170 LIST_HEAD(old_list); 170 LIST_HEAD(old_list);
171 int i = count / sizeof(struct fb_videomode); 171 int i = count / sizeof(struct fb_videomode);
172 172
173 if (i * sizeof(struct fb_videomode) != count) 173 if (i * sizeof(struct fb_videomode) != count)
174 return -EINVAL; 174 return -EINVAL;
175 175
176 acquire_console_sem(); 176 acquire_console_sem();
177 list_splice(&fb_info->modelist, &old_list); 177 list_splice(&fb_info->modelist, &old_list);
178 fb_videomode_to_modelist((const struct fb_videomode *)buf, i, 178 fb_videomode_to_modelist((const struct fb_videomode *)buf, i,
179 &fb_info->modelist); 179 &fb_info->modelist);
180 if (fb_new_modelist(fb_info)) { 180 if (fb_new_modelist(fb_info)) {
181 fb_destroy_modelist(&fb_info->modelist); 181 fb_destroy_modelist(&fb_info->modelist);
182 list_splice(&old_list, &fb_info->modelist); 182 list_splice(&old_list, &fb_info->modelist);
183 } else 183 } else
184 fb_destroy_modelist(&old_list); 184 fb_destroy_modelist(&old_list);
185 185
186 release_console_sem(); 186 release_console_sem();
187 187
188 return 0; 188 return 0;
189 } 189 }
190 190
191 static ssize_t show_modes(struct device *device, struct device_attribute *attr, 191 static ssize_t show_modes(struct device *device, struct device_attribute *attr,
192 char *buf) 192 char *buf)
193 { 193 {
194 struct fb_info *fb_info = dev_get_drvdata(device); 194 struct fb_info *fb_info = dev_get_drvdata(device);
195 unsigned int i; 195 unsigned int i;
196 struct list_head *pos; 196 struct list_head *pos;
197 struct fb_modelist *modelist; 197 struct fb_modelist *modelist;
198 const struct fb_videomode *mode; 198 const struct fb_videomode *mode;
199 199
200 i = 0; 200 i = 0;
201 list_for_each(pos, &fb_info->modelist) { 201 list_for_each(pos, &fb_info->modelist) {
202 modelist = list_entry(pos, struct fb_modelist, list); 202 modelist = list_entry(pos, struct fb_modelist, list);
203 mode = &modelist->mode; 203 mode = &modelist->mode;
204 i += mode_string(buf, i, mode); 204 i += mode_string(buf, i, mode);
205 } 205 }
206 return i; 206 return i;
207 } 207 }
208 208
209 static ssize_t store_bpp(struct device *device, struct device_attribute *attr, 209 static ssize_t store_bpp(struct device *device, struct device_attribute *attr,
210 const char *buf, size_t count) 210 const char *buf, size_t count)
211 { 211 {
212 struct fb_info *fb_info = dev_get_drvdata(device); 212 struct fb_info *fb_info = dev_get_drvdata(device);
213 struct fb_var_screeninfo var; 213 struct fb_var_screeninfo var;
214 char ** last = NULL; 214 char ** last = NULL;
215 int err; 215 int err;
216 216
217 var = fb_info->var; 217 var = fb_info->var;
218 var.bits_per_pixel = simple_strtoul(buf, last, 0); 218 var.bits_per_pixel = simple_strtoul(buf, last, 0);
219 if ((err = activate(fb_info, &var))) 219 if ((err = activate(fb_info, &var)))
220 return err; 220 return err;
221 return count; 221 return count;
222 } 222 }
223 223
224 static ssize_t show_bpp(struct device *device, struct device_attribute *attr, 224 static ssize_t show_bpp(struct device *device, struct device_attribute *attr,
225 char *buf) 225 char *buf)
226 { 226 {
227 struct fb_info *fb_info = dev_get_drvdata(device); 227 struct fb_info *fb_info = dev_get_drvdata(device);
228 return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel); 228 return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel);
229 } 229 }
230 230
231 static ssize_t store_rotate(struct device *device, 231 static ssize_t store_rotate(struct device *device,
232 struct device_attribute *attr, 232 struct device_attribute *attr,
233 const char *buf, size_t count) 233 const char *buf, size_t count)
234 { 234 {
235 struct fb_info *fb_info = dev_get_drvdata(device); 235 struct fb_info *fb_info = dev_get_drvdata(device);
236 struct fb_var_screeninfo var; 236 struct fb_var_screeninfo var;
237 char **last = NULL; 237 char **last = NULL;
238 int err; 238 int err;
239 239
240 var = fb_info->var; 240 var = fb_info->var;
241 var.rotate = simple_strtoul(buf, last, 0); 241 var.rotate = simple_strtoul(buf, last, 0);
242 242
243 if ((err = activate(fb_info, &var))) 243 if ((err = activate(fb_info, &var)))
244 return err; 244 return err;
245 245
246 return count; 246 return count;
247 } 247 }
248 248
249 249
250 static ssize_t show_rotate(struct device *device, 250 static ssize_t show_rotate(struct device *device,
251 struct device_attribute *attr, char *buf) 251 struct device_attribute *attr, char *buf)
252 { 252 {
253 struct fb_info *fb_info = dev_get_drvdata(device); 253 struct fb_info *fb_info = dev_get_drvdata(device);
254 254
255 return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate); 255 return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate);
256 } 256 }
257 257
258 static ssize_t store_virtual(struct device *device, 258 static ssize_t store_virtual(struct device *device,
259 struct device_attribute *attr, 259 struct device_attribute *attr,
260 const char *buf, size_t count) 260 const char *buf, size_t count)
261 { 261 {
262 struct fb_info *fb_info = dev_get_drvdata(device); 262 struct fb_info *fb_info = dev_get_drvdata(device);
263 struct fb_var_screeninfo var; 263 struct fb_var_screeninfo var;
264 char *last = NULL; 264 char *last = NULL;
265 int err; 265 int err;
266 266
267 var = fb_info->var; 267 var = fb_info->var;
268 var.xres_virtual = simple_strtoul(buf, &last, 0); 268 var.xres_virtual = simple_strtoul(buf, &last, 0);
269 last++; 269 last++;
270 if (last - buf >= count) 270 if (last - buf >= count)
271 return -EINVAL; 271 return -EINVAL;
272 var.yres_virtual = simple_strtoul(last, &last, 0); 272 var.yres_virtual = simple_strtoul(last, &last, 0);
273 273
274 if ((err = activate(fb_info, &var))) 274 if ((err = activate(fb_info, &var)))
275 return err; 275 return err;
276 return count; 276 return count;
277 } 277 }
278 278
279 static ssize_t show_virtual(struct device *device, 279 static ssize_t show_virtual(struct device *device,
280 struct device_attribute *attr, char *buf) 280 struct device_attribute *attr, char *buf)
281 { 281 {
282 struct fb_info *fb_info = dev_get_drvdata(device); 282 struct fb_info *fb_info = dev_get_drvdata(device);
283 return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xres_virtual, 283 return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xres_virtual,
284 fb_info->var.yres_virtual); 284 fb_info->var.yres_virtual);
285 } 285 }
286 286
287 static ssize_t show_stride(struct device *device, 287 static ssize_t show_stride(struct device *device,
288 struct device_attribute *attr, char *buf) 288 struct device_attribute *attr, char *buf)
289 { 289 {
290 struct fb_info *fb_info = dev_get_drvdata(device); 290 struct fb_info *fb_info = dev_get_drvdata(device);
291 return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->fix.line_length); 291 return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->fix.line_length);
292 } 292 }
293 293
294 static ssize_t store_blank(struct device *device, 294 static ssize_t store_blank(struct device *device,
295 struct device_attribute *attr, 295 struct device_attribute *attr,
296 const char *buf, size_t count) 296 const char *buf, size_t count)
297 { 297 {
298 struct fb_info *fb_info = dev_get_drvdata(device); 298 struct fb_info *fb_info = dev_get_drvdata(device);
299 char *last = NULL; 299 char *last = NULL;
300 int err; 300 int err;
301 301
302 acquire_console_sem(); 302 acquire_console_sem();
303 fb_info->flags |= FBINFO_MISC_USEREVENT; 303 fb_info->flags |= FBINFO_MISC_USEREVENT;
304 err = fb_blank(fb_info, simple_strtoul(buf, &last, 0)); 304 err = fb_blank(fb_info, simple_strtoul(buf, &last, 0));
305 fb_info->flags &= ~FBINFO_MISC_USEREVENT; 305 fb_info->flags &= ~FBINFO_MISC_USEREVENT;
306 release_console_sem(); 306 release_console_sem();
307 if (err < 0) 307 if (err < 0)
308 return err; 308 return err;
309 return count; 309 return count;
310 } 310 }
311 311
312 static ssize_t show_blank(struct device *device, 312 static ssize_t show_blank(struct device *device,
313 struct device_attribute *attr, char *buf) 313 struct device_attribute *attr, char *buf)
314 { 314 {
315 // struct fb_info *fb_info = dev_get_drvdata(device); 315 // struct fb_info *fb_info = dev_get_drvdata(device);
316 return 0; 316 return 0;
317 } 317 }
318 318
319 static ssize_t store_console(struct device *device, 319 static ssize_t store_console(struct device *device,
320 struct device_attribute *attr, 320 struct device_attribute *attr,
321 const char *buf, size_t count) 321 const char *buf, size_t count)
322 { 322 {
323 // struct fb_info *fb_info = dev_get_drvdata(device); 323 // struct fb_info *fb_info = dev_get_drvdata(device);
324 return 0; 324 return 0;
325 } 325 }
326 326
327 static ssize_t show_console(struct device *device, 327 static ssize_t show_console(struct device *device,
328 struct device_attribute *attr, char *buf) 328 struct device_attribute *attr, char *buf)
329 { 329 {
330 // struct fb_info *fb_info = dev_get_drvdata(device); 330 // struct fb_info *fb_info = dev_get_drvdata(device);
331 return 0; 331 return 0;
332 } 332 }
333 333
334 static ssize_t store_cursor(struct device *device, 334 static ssize_t store_cursor(struct device *device,
335 struct device_attribute *attr, 335 struct device_attribute *attr,
336 const char *buf, size_t count) 336 const char *buf, size_t count)
337 { 337 {
338 // struct fb_info *fb_info = dev_get_drvdata(device); 338 // struct fb_info *fb_info = dev_get_drvdata(device);
339 return 0; 339 return 0;
340 } 340 }
341 341
342 static ssize_t show_cursor(struct device *device, 342 static ssize_t show_cursor(struct device *device,
343 struct device_attribute *attr, char *buf) 343 struct device_attribute *attr, char *buf)
344 { 344 {
345 // struct fb_info *fb_info = dev_get_drvdata(device); 345 // struct fb_info *fb_info = dev_get_drvdata(device);
346 return 0; 346 return 0;
347 } 347 }
348 348
349 static ssize_t store_pan(struct device *device, 349 static ssize_t store_pan(struct device *device,
350 struct device_attribute *attr, 350 struct device_attribute *attr,
351 const char *buf, size_t count) 351 const char *buf, size_t count)
352 { 352 {
353 struct fb_info *fb_info = dev_get_drvdata(device); 353 struct fb_info *fb_info = dev_get_drvdata(device);
354 struct fb_var_screeninfo var; 354 struct fb_var_screeninfo var;
355 char *last = NULL; 355 char *last = NULL;
356 int err; 356 int err;
357 357
358 var = fb_info->var; 358 var = fb_info->var;
359 var.xoffset = simple_strtoul(buf, &last, 0); 359 var.xoffset = simple_strtoul(buf, &last, 0);
360 last++; 360 last++;
361 if (last - buf >= count) 361 if (last - buf >= count)
362 return -EINVAL; 362 return -EINVAL;
363 var.yoffset = simple_strtoul(last, &last, 0); 363 var.yoffset = simple_strtoul(last, &last, 0);
364 364
365 acquire_console_sem(); 365 acquire_console_sem();
366 err = fb_pan_display(fb_info, &var); 366 err = fb_pan_display(fb_info, &var);
367 release_console_sem(); 367 release_console_sem();
368 368
369 if (err < 0) 369 if (err < 0)
370 return err; 370 return err;
371 return count; 371 return count;
372 } 372 }
373 373
374 static ssize_t show_pan(struct device *device, 374 static ssize_t show_pan(struct device *device,
375 struct device_attribute *attr, char *buf) 375 struct device_attribute *attr, char *buf)
376 { 376 {
377 struct fb_info *fb_info = dev_get_drvdata(device); 377 struct fb_info *fb_info = dev_get_drvdata(device);
378 return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset, 378 return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset,
379 fb_info->var.xoffset); 379 fb_info->var.yoffset);
380 } 380 }
381 381
382 static ssize_t show_name(struct device *device, 382 static ssize_t show_name(struct device *device,
383 struct device_attribute *attr, char *buf) 383 struct device_attribute *attr, char *buf)
384 { 384 {
385 struct fb_info *fb_info = dev_get_drvdata(device); 385 struct fb_info *fb_info = dev_get_drvdata(device);
386 386
387 return snprintf(buf, PAGE_SIZE, "%s\n", fb_info->fix.id); 387 return snprintf(buf, PAGE_SIZE, "%s\n", fb_info->fix.id);
388 } 388 }
389 389
390 static ssize_t store_fbstate(struct device *device, 390 static ssize_t store_fbstate(struct device *device,
391 struct device_attribute *attr, 391 struct device_attribute *attr,
392 const char *buf, size_t count) 392 const char *buf, size_t count)
393 { 393 {
394 struct fb_info *fb_info = dev_get_drvdata(device); 394 struct fb_info *fb_info = dev_get_drvdata(device);
395 u32 state; 395 u32 state;
396 char *last = NULL; 396 char *last = NULL;
397 397
398 state = simple_strtoul(buf, &last, 0); 398 state = simple_strtoul(buf, &last, 0);
399 399
400 acquire_console_sem(); 400 acquire_console_sem();
401 fb_set_suspend(fb_info, (int)state); 401 fb_set_suspend(fb_info, (int)state);
402 release_console_sem(); 402 release_console_sem();
403 403
404 return count; 404 return count;
405 } 405 }
406 406
407 static ssize_t show_fbstate(struct device *device, 407 static ssize_t show_fbstate(struct device *device,
408 struct device_attribute *attr, char *buf) 408 struct device_attribute *attr, char *buf)
409 { 409 {
410 struct fb_info *fb_info = dev_get_drvdata(device); 410 struct fb_info *fb_info = dev_get_drvdata(device);
411 return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state); 411 return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state);
412 } 412 }
413 413
414 #ifdef CONFIG_FB_BACKLIGHT 414 #ifdef CONFIG_FB_BACKLIGHT
415 static ssize_t store_bl_curve(struct device *device, 415 static ssize_t store_bl_curve(struct device *device,
416 struct device_attribute *attr, 416 struct device_attribute *attr,
417 const char *buf, size_t count) 417 const char *buf, size_t count)
418 { 418 {
419 struct fb_info *fb_info = dev_get_drvdata(device); 419 struct fb_info *fb_info = dev_get_drvdata(device);
420 u8 tmp_curve[FB_BACKLIGHT_LEVELS]; 420 u8 tmp_curve[FB_BACKLIGHT_LEVELS];
421 unsigned int i; 421 unsigned int i;
422 422
423 /* Some drivers don't use framebuffer_alloc(), but those also 423 /* Some drivers don't use framebuffer_alloc(), but those also
424 * don't have backlights. 424 * don't have backlights.
425 */ 425 */
426 if (!fb_info || !fb_info->bl_dev) 426 if (!fb_info || !fb_info->bl_dev)
427 return -ENODEV; 427 return -ENODEV;
428 428
429 if (count != (FB_BACKLIGHT_LEVELS / 8 * 24)) 429 if (count != (FB_BACKLIGHT_LEVELS / 8 * 24))
430 return -EINVAL; 430 return -EINVAL;
431 431
432 for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i) 432 for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i)
433 if (sscanf(&buf[i * 24], 433 if (sscanf(&buf[i * 24],
434 "%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n", 434 "%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n",
435 &tmp_curve[i * 8 + 0], 435 &tmp_curve[i * 8 + 0],
436 &tmp_curve[i * 8 + 1], 436 &tmp_curve[i * 8 + 1],
437 &tmp_curve[i * 8 + 2], 437 &tmp_curve[i * 8 + 2],
438 &tmp_curve[i * 8 + 3], 438 &tmp_curve[i * 8 + 3],
439 &tmp_curve[i * 8 + 4], 439 &tmp_curve[i * 8 + 4],
440 &tmp_curve[i * 8 + 5], 440 &tmp_curve[i * 8 + 5],
441 &tmp_curve[i * 8 + 6], 441 &tmp_curve[i * 8 + 6],
442 &tmp_curve[i * 8 + 7]) != 8) 442 &tmp_curve[i * 8 + 7]) != 8)
443 return -EINVAL; 443 return -EINVAL;
444 444
445 /* If there has been an error in the input data, we won't 445 /* If there has been an error in the input data, we won't
446 * reach this loop. 446 * reach this loop.
447 */ 447 */
448 mutex_lock(&fb_info->bl_curve_mutex); 448 mutex_lock(&fb_info->bl_curve_mutex);
449 for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i) 449 for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
450 fb_info->bl_curve[i] = tmp_curve[i]; 450 fb_info->bl_curve[i] = tmp_curve[i];
451 mutex_unlock(&fb_info->bl_curve_mutex); 451 mutex_unlock(&fb_info->bl_curve_mutex);
452 452
453 return count; 453 return count;
454 } 454 }
455 455
456 static ssize_t show_bl_curve(struct device *device, 456 static ssize_t show_bl_curve(struct device *device,
457 struct device_attribute *attr, char *buf) 457 struct device_attribute *attr, char *buf)
458 { 458 {
459 struct fb_info *fb_info = dev_get_drvdata(device); 459 struct fb_info *fb_info = dev_get_drvdata(device);
460 ssize_t len = 0; 460 ssize_t len = 0;
461 unsigned int i; 461 unsigned int i;
462 462
463 /* Some drivers don't use framebuffer_alloc(), but those also 463 /* Some drivers don't use framebuffer_alloc(), but those also
464 * don't have backlights. 464 * don't have backlights.
465 */ 465 */
466 if (!fb_info || !fb_info->bl_dev) 466 if (!fb_info || !fb_info->bl_dev)
467 return -ENODEV; 467 return -ENODEV;
468 468
469 mutex_lock(&fb_info->bl_curve_mutex); 469 mutex_lock(&fb_info->bl_curve_mutex);
470 for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8) 470 for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
471 len += snprintf(&buf[len], PAGE_SIZE, 471 len += snprintf(&buf[len], PAGE_SIZE,
472 "%02x %02x %02x %02x %02x %02x %02x %02x\n", 472 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
473 fb_info->bl_curve[i + 0], 473 fb_info->bl_curve[i + 0],
474 fb_info->bl_curve[i + 1], 474 fb_info->bl_curve[i + 1],
475 fb_info->bl_curve[i + 2], 475 fb_info->bl_curve[i + 2],
476 fb_info->bl_curve[i + 3], 476 fb_info->bl_curve[i + 3],
477 fb_info->bl_curve[i + 4], 477 fb_info->bl_curve[i + 4],
478 fb_info->bl_curve[i + 5], 478 fb_info->bl_curve[i + 5],
479 fb_info->bl_curve[i + 6], 479 fb_info->bl_curve[i + 6],
480 fb_info->bl_curve[i + 7]); 480 fb_info->bl_curve[i + 7]);
481 mutex_unlock(&fb_info->bl_curve_mutex); 481 mutex_unlock(&fb_info->bl_curve_mutex);
482 482
483 return len; 483 return len;
484 } 484 }
485 #endif 485 #endif
486 486
487 /* When cmap is added back in it should be a binary attribute 487 /* When cmap is added back in it should be a binary attribute
488 * not a text one. Consideration should also be given to converting 488 * not a text one. Consideration should also be given to converting
489 * fbdev to use configfs instead of sysfs */ 489 * fbdev to use configfs instead of sysfs */
490 static struct device_attribute device_attrs[] = { 490 static struct device_attribute device_attrs[] = {
491 __ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp), 491 __ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),
492 __ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank), 492 __ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),
493 __ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console), 493 __ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),
494 __ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor), 494 __ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),
495 __ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode), 495 __ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),
496 __ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes), 496 __ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),
497 __ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan), 497 __ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),
498 __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual), 498 __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
499 __ATTR(name, S_IRUGO, show_name, NULL), 499 __ATTR(name, S_IRUGO, show_name, NULL),
500 __ATTR(stride, S_IRUGO, show_stride, NULL), 500 __ATTR(stride, S_IRUGO, show_stride, NULL),
501 __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), 501 __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
502 __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate), 502 __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),
503 #ifdef CONFIG_FB_BACKLIGHT 503 #ifdef CONFIG_FB_BACKLIGHT
504 __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve), 504 __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),
505 #endif 505 #endif
506 }; 506 };
507 507
508 int fb_init_device(struct fb_info *fb_info) 508 int fb_init_device(struct fb_info *fb_info)
509 { 509 {
510 int i, error = 0; 510 int i, error = 0;
511 511
512 dev_set_drvdata(fb_info->dev, fb_info); 512 dev_set_drvdata(fb_info->dev, fb_info);
513 513
514 fb_info->class_flag |= FB_SYSFS_FLAG_ATTR; 514 fb_info->class_flag |= FB_SYSFS_FLAG_ATTR;
515 515
516 for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { 516 for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
517 error = device_create_file(fb_info->dev, &device_attrs[i]); 517 error = device_create_file(fb_info->dev, &device_attrs[i]);
518 518
519 if (error) 519 if (error)
520 break; 520 break;
521 } 521 }
522 522
523 if (error) { 523 if (error) {
524 while (--i >= 0) 524 while (--i >= 0)
525 device_remove_file(fb_info->dev, &device_attrs[i]); 525 device_remove_file(fb_info->dev, &device_attrs[i]);
526 fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR; 526 fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;
527 } 527 }
528 528
529 return 0; 529 return 0;
530 } 530 }
531 531
532 void fb_cleanup_device(struct fb_info *fb_info) 532 void fb_cleanup_device(struct fb_info *fb_info)
533 { 533 {
534 unsigned int i; 534 unsigned int i;
535 535
536 if (fb_info->class_flag & FB_SYSFS_FLAG_ATTR) { 536 if (fb_info->class_flag & FB_SYSFS_FLAG_ATTR) {
537 for (i = 0; i < ARRAY_SIZE(device_attrs); i++) 537 for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
538 device_remove_file(fb_info->dev, &device_attrs[i]); 538 device_remove_file(fb_info->dev, &device_attrs[i]);
539 539
540 fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR; 540 fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;
541 } 541 }
542 } 542 }
543 543
544 #ifdef CONFIG_FB_BACKLIGHT 544 #ifdef CONFIG_FB_BACKLIGHT
545 /* This function generates a linear backlight curve 545 /* This function generates a linear backlight curve
546 * 546 *
547 * 0: off 547 * 0: off
548 * 1-7: min 548 * 1-7: min
549 * 8-127: linear from min to max 549 * 8-127: linear from min to max
550 */ 550 */
551 void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max) 551 void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
552 { 552 {
553 unsigned int i, flat, count, range = (max - min); 553 unsigned int i, flat, count, range = (max - min);
554 554
555 mutex_lock(&fb_info->bl_curve_mutex); 555 mutex_lock(&fb_info->bl_curve_mutex);
556 556
557 fb_info->bl_curve[0] = off; 557 fb_info->bl_curve[0] = off;
558 558
559 for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat) 559 for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
560 fb_info->bl_curve[flat] = min; 560 fb_info->bl_curve[flat] = min;
561 561
562 count = FB_BACKLIGHT_LEVELS * 15 / 16; 562 count = FB_BACKLIGHT_LEVELS * 15 / 16;
563 for (i = 0; i < count; ++i) 563 for (i = 0; i < count; ++i)
564 fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count); 564 fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count);
565 565
566 mutex_unlock(&fb_info->bl_curve_mutex); 566 mutex_unlock(&fb_info->bl_curve_mutex);
567 } 567 }
568 EXPORT_SYMBOL_GPL(fb_bl_default_curve); 568 EXPORT_SYMBOL_GPL(fb_bl_default_curve);
569 #endif 569 #endif
570 570