fbsysfs.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * fbsysfs.c - framebuffer device class and attributes
  4. *
  5. * Copyright (c) 2004 James Simmons <jsimmons@infradead.org>
  6. */
  7. #include <linux/console.h>
  8. #include <linux/fb.h>
  9. #include <linux/fbcon.h>
  10. #include <linux/major.h>
  11. #include "fb_internal.h"
  12. static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
  13. {
  14. int err;
  15. var->activate |= FB_ACTIVATE_FORCE;
  16. console_lock();
  17. lock_fb_info(fb_info);
  18. err = fb_set_var(fb_info, var);
  19. if (!err)
  20. fbcon_update_vcs(fb_info, var->activate & FB_ACTIVATE_ALL);
  21. unlock_fb_info(fb_info);
  22. console_unlock();
  23. if (err)
  24. return err;
  25. return 0;
  26. }
  27. static int mode_string(char *buf, unsigned int offset,
  28. const struct fb_videomode *mode)
  29. {
  30. char m = 'U';
  31. char v = 'p';
  32. if (mode->flag & FB_MODE_IS_DETAILED)
  33. m = 'D';
  34. if (mode->flag & FB_MODE_IS_VESA)
  35. m = 'V';
  36. if (mode->flag & FB_MODE_IS_STANDARD)
  37. m = 'S';
  38. if (mode->vmode & FB_VMODE_INTERLACED)
  39. v = 'i';
  40. if (mode->vmode & FB_VMODE_DOUBLE)
  41. v = 'd';
  42. return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d%c-%d\n",
  43. m, mode->xres, mode->yres, v, mode->refresh);
  44. }
  45. static ssize_t store_mode(struct device *device, struct device_attribute *attr,
  46. const char *buf, size_t count)
  47. {
  48. struct fb_info *fb_info = dev_get_drvdata(device);
  49. char mstr[100];
  50. struct fb_var_screeninfo var;
  51. struct fb_modelist *modelist;
  52. struct fb_videomode *mode;
  53. size_t i;
  54. int err;
  55. memset(&var, 0, sizeof(var));
  56. list_for_each_entry(modelist, &fb_info->modelist, list) {
  57. mode = &modelist->mode;
  58. i = mode_string(mstr, 0, mode);
  59. if (strncmp(mstr, buf, max(count, i)) == 0) {
  60. var = fb_info->var;
  61. fb_videomode_to_var(&var, mode);
  62. if ((err = activate(fb_info, &var)))
  63. return err;
  64. fb_info->mode = mode;
  65. return count;
  66. }
  67. }
  68. return -EINVAL;
  69. }
  70. static ssize_t show_mode(struct device *device, struct device_attribute *attr,
  71. char *buf)
  72. {
  73. struct fb_info *fb_info = dev_get_drvdata(device);
  74. if (!fb_info->mode)
  75. return 0;
  76. return mode_string(buf, 0, fb_info->mode);
  77. }
  78. static ssize_t store_modes(struct device *device,
  79. struct device_attribute *attr,
  80. const char *buf, size_t count)
  81. {
  82. struct fb_info *fb_info = dev_get_drvdata(device);
  83. LIST_HEAD(old_list);
  84. int i = count / sizeof(struct fb_videomode);
  85. if (i * sizeof(struct fb_videomode) != count)
  86. return -EINVAL;
  87. console_lock();
  88. lock_fb_info(fb_info);
  89. list_splice(&fb_info->modelist, &old_list);
  90. fb_videomode_to_modelist((const struct fb_videomode *)buf, i,
  91. &fb_info->modelist);
  92. if (fb_new_modelist(fb_info)) {
  93. fb_destroy_modelist(&fb_info->modelist);
  94. list_splice(&old_list, &fb_info->modelist);
  95. } else
  96. fb_destroy_modelist(&old_list);
  97. unlock_fb_info(fb_info);
  98. console_unlock();
  99. return 0;
  100. }
  101. static ssize_t show_modes(struct device *device, struct device_attribute *attr,
  102. char *buf)
  103. {
  104. struct fb_info *fb_info = dev_get_drvdata(device);
  105. unsigned int i;
  106. struct fb_modelist *modelist;
  107. const struct fb_videomode *mode;
  108. i = 0;
  109. list_for_each_entry(modelist, &fb_info->modelist, list) {
  110. mode = &modelist->mode;
  111. i += mode_string(buf, i, mode);
  112. }
  113. return i;
  114. }
  115. static ssize_t store_bpp(struct device *device, struct device_attribute *attr,
  116. const char *buf, size_t count)
  117. {
  118. struct fb_info *fb_info = dev_get_drvdata(device);
  119. struct fb_var_screeninfo var;
  120. char ** last = NULL;
  121. int err;
  122. var = fb_info->var;
  123. var.bits_per_pixel = simple_strtoul(buf, last, 0);
  124. if ((err = activate(fb_info, &var)))
  125. return err;
  126. return count;
  127. }
  128. static ssize_t show_bpp(struct device *device, struct device_attribute *attr,
  129. char *buf)
  130. {
  131. struct fb_info *fb_info = dev_get_drvdata(device);
  132. return sysfs_emit(buf, "%d\n", fb_info->var.bits_per_pixel);
  133. }
  134. static ssize_t store_rotate(struct device *device,
  135. struct device_attribute *attr,
  136. const char *buf, size_t count)
  137. {
  138. struct fb_info *fb_info = dev_get_drvdata(device);
  139. struct fb_var_screeninfo var;
  140. char **last = NULL;
  141. int err;
  142. var = fb_info->var;
  143. var.rotate = simple_strtoul(buf, last, 0);
  144. if ((err = activate(fb_info, &var)))
  145. return err;
  146. return count;
  147. }
  148. static ssize_t show_rotate(struct device *device,
  149. struct device_attribute *attr, char *buf)
  150. {
  151. struct fb_info *fb_info = dev_get_drvdata(device);
  152. return sysfs_emit(buf, "%d\n", fb_info->var.rotate);
  153. }
  154. static ssize_t store_virtual(struct device *device,
  155. struct device_attribute *attr,
  156. const char *buf, size_t count)
  157. {
  158. struct fb_info *fb_info = dev_get_drvdata(device);
  159. struct fb_var_screeninfo var;
  160. char *last = NULL;
  161. int err;
  162. var = fb_info->var;
  163. var.xres_virtual = simple_strtoul(buf, &last, 0);
  164. last++;
  165. if (last - buf >= count)
  166. return -EINVAL;
  167. var.yres_virtual = simple_strtoul(last, &last, 0);
  168. if ((err = activate(fb_info, &var)))
  169. return err;
  170. return count;
  171. }
  172. static ssize_t show_virtual(struct device *device,
  173. struct device_attribute *attr, char *buf)
  174. {
  175. struct fb_info *fb_info = dev_get_drvdata(device);
  176. return sysfs_emit(buf, "%d,%d\n", fb_info->var.xres_virtual,
  177. fb_info->var.yres_virtual);
  178. }
  179. static ssize_t show_stride(struct device *device,
  180. struct device_attribute *attr, char *buf)
  181. {
  182. struct fb_info *fb_info = dev_get_drvdata(device);
  183. return sysfs_emit(buf, "%d\n", fb_info->fix.line_length);
  184. }
  185. static ssize_t store_blank(struct device *device,
  186. struct device_attribute *attr,
  187. const char *buf, size_t count)
  188. {
  189. struct fb_info *fb_info = dev_get_drvdata(device);
  190. char *last = NULL;
  191. int err, arg;
  192. arg = simple_strtoul(buf, &last, 0);
  193. console_lock();
  194. err = fb_blank(fb_info, arg);
  195. /* might again call into fb_blank */
  196. fbcon_fb_blanked(fb_info, arg);
  197. console_unlock();
  198. if (err < 0)
  199. return err;
  200. return count;
  201. }
  202. static ssize_t show_blank(struct device *device, struct device_attribute *attr, char *buf)
  203. {
  204. struct fb_info *fb_info = dev_get_drvdata(device);
  205. return sysfs_emit(buf, "%d\n", fb_info->blank);
  206. }
  207. static ssize_t store_console(struct device *device,
  208. struct device_attribute *attr,
  209. const char *buf, size_t count)
  210. {
  211. // struct fb_info *fb_info = dev_get_drvdata(device);
  212. return 0;
  213. }
  214. static ssize_t show_console(struct device *device,
  215. struct device_attribute *attr, char *buf)
  216. {
  217. // struct fb_info *fb_info = dev_get_drvdata(device);
  218. return 0;
  219. }
  220. static ssize_t store_cursor(struct device *device,
  221. struct device_attribute *attr,
  222. const char *buf, size_t count)
  223. {
  224. // struct fb_info *fb_info = dev_get_drvdata(device);
  225. return 0;
  226. }
  227. static ssize_t show_cursor(struct device *device,
  228. struct device_attribute *attr, char *buf)
  229. {
  230. // struct fb_info *fb_info = dev_get_drvdata(device);
  231. return 0;
  232. }
  233. static ssize_t store_pan(struct device *device,
  234. struct device_attribute *attr,
  235. const char *buf, size_t count)
  236. {
  237. struct fb_info *fb_info = dev_get_drvdata(device);
  238. struct fb_var_screeninfo var;
  239. char *last = NULL;
  240. int err;
  241. var = fb_info->var;
  242. var.xoffset = simple_strtoul(buf, &last, 0);
  243. last++;
  244. if (last - buf >= count)
  245. return -EINVAL;
  246. var.yoffset = simple_strtoul(last, &last, 0);
  247. console_lock();
  248. err = fb_pan_display(fb_info, &var);
  249. console_unlock();
  250. if (err < 0)
  251. return err;
  252. return count;
  253. }
  254. static ssize_t show_pan(struct device *device,
  255. struct device_attribute *attr, char *buf)
  256. {
  257. struct fb_info *fb_info = dev_get_drvdata(device);
  258. return sysfs_emit(buf, "%d,%d\n", fb_info->var.xoffset,
  259. fb_info->var.yoffset);
  260. }
  261. static ssize_t show_name(struct device *device,
  262. struct device_attribute *attr, char *buf)
  263. {
  264. struct fb_info *fb_info = dev_get_drvdata(device);
  265. return sysfs_emit(buf, "%s\n", fb_info->fix.id);
  266. }
  267. static ssize_t store_fbstate(struct device *device,
  268. struct device_attribute *attr,
  269. const char *buf, size_t count)
  270. {
  271. struct fb_info *fb_info = dev_get_drvdata(device);
  272. u32 state;
  273. char *last = NULL;
  274. state = simple_strtoul(buf, &last, 0);
  275. console_lock();
  276. lock_fb_info(fb_info);
  277. fb_set_suspend(fb_info, (int)state);
  278. unlock_fb_info(fb_info);
  279. console_unlock();
  280. return count;
  281. }
  282. static ssize_t show_fbstate(struct device *device,
  283. struct device_attribute *attr, char *buf)
  284. {
  285. struct fb_info *fb_info = dev_get_drvdata(device);
  286. return sysfs_emit(buf, "%d\n", fb_info->state);
  287. }
  288. #if IS_ENABLED(CONFIG_FB_BACKLIGHT)
  289. static ssize_t store_bl_curve(struct device *device,
  290. struct device_attribute *attr,
  291. const char *buf, size_t count)
  292. {
  293. struct fb_info *fb_info = dev_get_drvdata(device);
  294. u8 tmp_curve[FB_BACKLIGHT_LEVELS];
  295. unsigned int i;
  296. /* Some drivers don't use framebuffer_alloc(), but those also
  297. * don't have backlights.
  298. */
  299. if (!fb_info || !fb_info->bl_dev)
  300. return -ENODEV;
  301. if (count != (FB_BACKLIGHT_LEVELS / 8 * 24))
  302. return -EINVAL;
  303. for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i)
  304. if (sscanf(&buf[i * 24],
  305. "%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n",
  306. &tmp_curve[i * 8 + 0],
  307. &tmp_curve[i * 8 + 1],
  308. &tmp_curve[i * 8 + 2],
  309. &tmp_curve[i * 8 + 3],
  310. &tmp_curve[i * 8 + 4],
  311. &tmp_curve[i * 8 + 5],
  312. &tmp_curve[i * 8 + 6],
  313. &tmp_curve[i * 8 + 7]) != 8)
  314. return -EINVAL;
  315. /* If there has been an error in the input data, we won't
  316. * reach this loop.
  317. */
  318. mutex_lock(&fb_info->bl_curve_mutex);
  319. for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
  320. fb_info->bl_curve[i] = tmp_curve[i];
  321. mutex_unlock(&fb_info->bl_curve_mutex);
  322. return count;
  323. }
  324. static ssize_t show_bl_curve(struct device *device,
  325. struct device_attribute *attr, char *buf)
  326. {
  327. struct fb_info *fb_info = dev_get_drvdata(device);
  328. ssize_t len = 0;
  329. unsigned int i;
  330. /* Some drivers don't use framebuffer_alloc(), but those also
  331. * don't have backlights.
  332. */
  333. if (!fb_info || !fb_info->bl_dev)
  334. return -ENODEV;
  335. mutex_lock(&fb_info->bl_curve_mutex);
  336. for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
  337. len += scnprintf(&buf[len], PAGE_SIZE - len, "%8ph\n",
  338. fb_info->bl_curve + i);
  339. mutex_unlock(&fb_info->bl_curve_mutex);
  340. return len;
  341. }
  342. #endif
  343. /* When cmap is added back in it should be a binary attribute
  344. * not a text one. Consideration should also be given to converting
  345. * fbdev to use configfs instead of sysfs */
  346. static DEVICE_ATTR(bits_per_pixel, 0644, show_bpp, store_bpp);
  347. static DEVICE_ATTR(blank, 0644, show_blank, store_blank);
  348. static DEVICE_ATTR(console, 0644, show_console, store_console);
  349. static DEVICE_ATTR(cursor, 0644, show_cursor, store_cursor);
  350. static DEVICE_ATTR(mode, 0644, show_mode, store_mode);
  351. static DEVICE_ATTR(modes, 0644, show_modes, store_modes);
  352. static DEVICE_ATTR(pan, 0644, show_pan, store_pan);
  353. static DEVICE_ATTR(virtual_size, 0644, show_virtual, store_virtual);
  354. static DEVICE_ATTR(name, 0444, show_name, NULL);
  355. static DEVICE_ATTR(stride, 0444, show_stride, NULL);
  356. static DEVICE_ATTR(rotate, 0644, show_rotate, store_rotate);
  357. static DEVICE_ATTR(state, 0644, show_fbstate, store_fbstate);
  358. #if IS_ENABLED(CONFIG_FB_BACKLIGHT)
  359. static DEVICE_ATTR(bl_curve, 0644, show_bl_curve, store_bl_curve);
  360. #endif
  361. static struct attribute *fb_device_attrs[] = {
  362. &dev_attr_bits_per_pixel.attr,
  363. &dev_attr_blank.attr,
  364. &dev_attr_console.attr,
  365. &dev_attr_cursor.attr,
  366. &dev_attr_mode.attr,
  367. &dev_attr_modes.attr,
  368. &dev_attr_pan.attr,
  369. &dev_attr_virtual_size.attr,
  370. &dev_attr_name.attr,
  371. &dev_attr_stride.attr,
  372. &dev_attr_rotate.attr,
  373. &dev_attr_state.attr,
  374. #if IS_ENABLED(CONFIG_FB_BACKLIGHT)
  375. &dev_attr_bl_curve.attr,
  376. #endif
  377. NULL,
  378. };
  379. ATTRIBUTE_GROUPS(fb_device);
  380. int fb_device_create(struct fb_info *fb_info)
  381. {
  382. int node = fb_info->node;
  383. dev_t devt = MKDEV(FB_MAJOR, node);
  384. int ret;
  385. fb_info->dev = device_create_with_groups(fb_class, fb_info->device, devt, fb_info,
  386. fb_device_groups, "fb%d", node);
  387. if (IS_ERR(fb_info->dev)) {
  388. /* Not fatal */
  389. ret = PTR_ERR(fb_info->dev);
  390. pr_warn("Unable to create device for framebuffer %d; error %d\n", node, ret);
  391. fb_info->dev = NULL;
  392. }
  393. return 0;
  394. }
  395. void fb_device_destroy(struct fb_info *fb_info)
  396. {
  397. dev_t devt = MKDEV(FB_MAJOR, fb_info->node);
  398. if (!fb_info->dev)
  399. return;
  400. device_destroy(fb_class, devt);
  401. fb_info->dev = NULL;
  402. }