Advertisement
Perka

fbmem.c

Aug 6th, 2013
251
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 46.92 KB | None | 0 0
  1. /*
  2. * linux/drivers/video/fbmem.c
  3. *
  4. * Copyright (C) 1994 Martin Schaller
  5. *
  6. * 2001 - Documented with DocBook
  7. * - Brad Douglas <brad@neruo.com>
  8. *
  9. * This file is subject to the terms and conditions of the GNU General Public
  10. * License. See the file COPYING in the main directory of this archive
  11. * for more details.
  12. */
  13.  
  14. #include <linux/module.h>
  15.  
  16. #include <linux/compat.h>
  17. #include <linux/types.h>
  18. #include <linux/errno.h>
  19. #include <linux/kernel.h>
  20. #include <linux/major.h>
  21. #include <linux/slab.h>
  22. #include <linux/mm.h>
  23. #include <linux/mman.h>
  24. #include <linux/vt.h>
  25. #include <linux/init.h>
  26. #include <linux/linux_logo.h>
  27. #include <linux/proc_fs.h>
  28. #include <linux/seq_file.h>
  29. #include <linux/console.h>
  30. #include <linux/kmod.h>
  31. #include <linux/err.h>
  32. #include <linux/device.h>
  33. #include <linux/efi.h>
  34. #include <linux/fb.h>
  35.  
  36. #include <asm/fb.h>
  37. #include <linux/cma.h>
  38.  
  39.  
  40. /*
  41. * Frame buffer device initialization and setup routines
  42. */
  43.  
  44. #define FBPIXMAPSIZE (1024 * 8)
  45.  
  46. static DEFINE_MUTEX(registration_lock);
  47. struct fb_info *registered_fb[FB_MAX] __read_mostly;
  48. int num_registered_fb __read_mostly;
  49.  
  50. static struct fb_info *get_fb_info(unsigned int idx)
  51. {
  52. struct fb_info *fb_info;
  53.  
  54. if (idx >= FB_MAX)
  55. return ERR_PTR(-ENODEV);
  56.  
  57. mutex_lock(&registration_lock);
  58. fb_info = registered_fb[idx];
  59. if (fb_info)
  60. atomic_inc(&fb_info->count);
  61. mutex_unlock(&registration_lock);
  62.  
  63. return fb_info;
  64. }
  65.  
  66. static void put_fb_info(struct fb_info *fb_info)
  67. {
  68. if (!atomic_dec_and_test(&fb_info->count))
  69. return;
  70. if (fb_info->fbops->fb_destroy)
  71. fb_info->fbops->fb_destroy(fb_info);
  72. }
  73.  
  74. int lock_fb_info(struct fb_info *info)
  75. {
  76. mutex_lock(&info->lock);
  77. if (!info->fbops) {
  78. mutex_unlock(&info->lock);
  79. return 0;
  80. }
  81. return 1;
  82. }
  83. EXPORT_SYMBOL(lock_fb_info);
  84.  
  85. /*
  86. * Helpers
  87. */
  88.  
  89. int fb_get_color_depth(struct fb_var_screeninfo *var,
  90. struct fb_fix_screeninfo *fix)
  91. {
  92. int depth = 0;
  93.  
  94. if (fix->visual == FB_VISUAL_MONO01 ||
  95. fix->visual == FB_VISUAL_MONO10)
  96. depth = 1;
  97. else {
  98. if (var->green.length == var->blue.length &&
  99. var->green.length == var->red.length &&
  100. var->green.offset == var->blue.offset &&
  101. var->green.offset == var->red.offset)
  102. depth = var->green.length;
  103. else
  104. depth = var->green.length + var->red.length +
  105. var->blue.length;
  106. }
  107.  
  108. return depth;
  109. }
  110. EXPORT_SYMBOL(fb_get_color_depth);
  111.  
  112. /*
  113. * Data padding functions.
  114. */
  115. void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height)
  116. {
  117. __fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height);
  118. }
  119. EXPORT_SYMBOL(fb_pad_aligned_buffer);
  120.  
  121. void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height,
  122. u32 shift_high, u32 shift_low, u32 mod)
  123. {
  124. u8 mask = (u8) (0xfff << shift_high), tmp;
  125. int i, j;
  126.  
  127. for (i = height; i--; ) {
  128. for (j = 0; j < idx; j++) {
  129. tmp = dst[j];
  130. tmp &= mask;
  131. tmp |= *src >> shift_low;
  132. dst[j] = tmp;
  133. tmp = *src << shift_high;
  134. dst[j+1] = tmp;
  135. src++;
  136. }
  137. tmp = dst[idx];
  138. tmp &= mask;
  139. tmp |= *src >> shift_low;
  140. dst[idx] = tmp;
  141. if (shift_high < mod) {
  142. tmp = *src << shift_high;
  143. dst[idx+1] = tmp;
  144. }
  145. src++;
  146. dst += d_pitch;
  147. }
  148. }
  149. EXPORT_SYMBOL(fb_pad_unaligned_buffer);
  150.  
  151. /*
  152. * we need to lock this section since fb_cursor
  153. * may use fb_imageblit()
  154. */
  155. char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size)
  156. {
  157. u32 align = buf->buf_align - 1, offset;
  158. char *addr = buf->addr;
  159.  
  160. /* If IO mapped, we need to sync before access, no sharing of
  161. * the pixmap is done
  162. */
  163. if (buf->flags & FB_PIXMAP_IO) {
  164. if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
  165. info->fbops->fb_sync(info);
  166. return addr;
  167. }
  168.  
  169. /* See if we fit in the remaining pixmap space */
  170. offset = buf->offset + align;
  171. offset &= ~align;
  172. if (offset + size > buf->size) {
  173. /* We do not fit. In order to be able to re-use the buffer,
  174. * we must ensure no asynchronous DMA'ing or whatever operation
  175. * is in progress, we sync for that.
  176. */
  177. if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
  178. info->fbops->fb_sync(info);
  179. offset = 0;
  180. }
  181. buf->offset = offset + size;
  182. addr += offset;
  183.  
  184. return addr;
  185. }
  186.  
  187. #ifdef CONFIG_LOGO
  188.  
  189. static inline unsigned safe_shift(unsigned d, int n)
  190. {
  191. return n < 0 ? d >> -n : d << n;
  192. }
  193.  
  194. static void fb_set_logocmap(struct fb_info *info,
  195. const struct linux_logo *logo)
  196. {
  197. struct fb_cmap palette_cmap;
  198. u16 palette_green[16];
  199. u16 palette_blue[16];
  200. u16 palette_red[16];
  201. int i, j, n;
  202. const unsigned char *clut = logo->clut;
  203.  
  204. palette_cmap.start = 0;
  205. palette_cmap.len = 16;
  206. palette_cmap.red = palette_red;
  207. palette_cmap.green = palette_green;
  208. palette_cmap.blue = palette_blue;
  209. palette_cmap.transp = NULL;
  210.  
  211. for (i = 0; i < logo->clutsize; i += n) {
  212. n = logo->clutsize - i;
  213. /* palette_cmap provides space for only 16 colors at once */
  214. if (n > 16)
  215. n = 16;
  216. palette_cmap.start = 32 + i;
  217. palette_cmap.len = n;
  218. for (j = 0; j < n; ++j) {
  219. palette_cmap.red[j] = clut[0] << 8 | clut[0];
  220. palette_cmap.green[j] = clut[1] << 8 | clut[1];
  221. palette_cmap.blue[j] = clut[2] << 8 | clut[2];
  222. clut += 3;
  223. }
  224. fb_set_cmap(&palette_cmap, info);
  225. }
  226. }
  227.  
  228. static void fb_set_logo_truepalette(struct fb_info *info,
  229. const struct linux_logo *logo,
  230. u32 *palette)
  231. {
  232. static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
  233. unsigned char redmask, greenmask, bluemask;
  234. int redshift, greenshift, blueshift;
  235. int i;
  236. const unsigned char *clut = logo->clut;
  237.  
  238. /*
  239. * We have to create a temporary palette since console palette is only
  240. * 16 colors long.
  241. */
  242. /* Bug: Doesn't obey msb_right ... (who needs that?) */
  243. redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8];
  244. greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8];
  245. bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8];
  246. redshift = info->var.red.offset - (8 - info->var.red.length);
  247. greenshift = info->var.green.offset - (8 - info->var.green.length);
  248. blueshift = info->var.blue.offset - (8 - info->var.blue.length);
  249.  
  250. for ( i = 0; i < logo->clutsize; i++) {
  251. palette[i+32] = (safe_shift((clut[0] & redmask), redshift) |
  252. safe_shift((clut[1] & greenmask), greenshift) |
  253. safe_shift((clut[2] & bluemask), blueshift));
  254. clut += 3;
  255. }
  256. }
  257.  
  258. static void fb_set_logo_directpalette(struct fb_info *info,
  259. const struct linux_logo *logo,
  260. u32 *palette)
  261. {
  262. int redshift, greenshift, blueshift;
  263. int i;
  264.  
  265. redshift = info->var.red.offset;
  266. greenshift = info->var.green.offset;
  267. blueshift = info->var.blue.offset;
  268.  
  269. for (i = 32; i < 32 + logo->clutsize; i++)
  270. palette[i] = i << redshift | i << greenshift | i << blueshift;
  271. }
  272.  
  273. static void fb_set_logo(struct fb_info *info,
  274. const struct linux_logo *logo, u8 *dst,
  275. int depth)
  276. {
  277. int i, j, k;
  278. const u8 *src = logo->data;
  279. u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
  280. u8 fg = 1, d;
  281.  
  282. switch (fb_get_color_depth(&info->var, &info->fix)) {
  283. case 1:
  284. fg = 1;
  285. break;
  286. case 2:
  287. fg = 3;
  288. break;
  289. default:
  290. fg = 7;
  291. break;
  292. }
  293.  
  294. if (info->fix.visual == FB_VISUAL_MONO01 ||
  295. info->fix.visual == FB_VISUAL_MONO10)
  296. fg = ~((u8) (0xfff << info->var.green.length));
  297.  
  298. switch (depth) {
  299. case 4:
  300. for (i = 0; i < logo->height; i++)
  301. for (j = 0; j < logo->width; src++) {
  302. *dst++ = *src >> 4;
  303. j++;
  304. if (j < logo->width) {
  305. *dst++ = *src & 0x0f;
  306. j++;
  307. }
  308. }
  309. break;
  310. case 1:
  311. for (i = 0; i < logo->height; i++) {
  312. for (j = 0; j < logo->width; src++) {
  313. d = *src ^ xor;
  314. for (k = 7; k >= 0; k--) {
  315. *dst++ = ((d >> k) & 1) ? fg : 0;
  316. j++;
  317. }
  318. }
  319. }
  320. break;
  321. }
  322. }
  323.  
  324. /*
  325. * Three (3) kinds of logo maps exist. linux_logo_clut224 (>16 colors),
  326. * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors). Depending on
  327. * the visual format and color depth of the framebuffer, the DAC, the
  328. * pseudo_palette, and the logo data will be adjusted accordingly.
  329. *
  330. * Case 1 - linux_logo_clut224:
  331. * Color exceeds the number of console colors (16), thus we set the hardware DAC
  332. * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set.
  333. *
  334. * For visuals that require color info from the pseudo_palette, we also construct
  335. * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags
  336. * will be set.
  337. *
  338. * Case 2 - linux_logo_vga16:
  339. * The number of colors just matches the console colors, thus there is no need
  340. * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie,
  341. * each byte contains color information for two pixels (upper and lower nibble).
  342. * To be consistent with fb_imageblit() usage, we therefore separate the two
  343. * nibbles into separate bytes. The "depth" flag will be set to 4.
  344. *
  345. * Case 3 - linux_logo_mono:
  346. * This is similar with Case 2. Each byte contains information for 8 pixels.
  347. * We isolate each bit and expand each into a byte. The "depth" flag will
  348. * be set to 1.
  349. */
  350. static struct logo_data {
  351. int depth;
  352. int needs_directpalette;
  353. int needs_truepalette;
  354. int needs_cmapreset;
  355. const struct linux_logo *logo;
  356. } fb_logo __read_mostly;
  357.  
  358. static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
  359. {
  360. u32 size = width * height, i;
  361.  
  362. out += size - 1;
  363.  
  364. for (i = size; i--; )
  365. *out-- = *in++;
  366. }
  367.  
  368. static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height)
  369. {
  370. int i, j, h = height - 1;
  371.  
  372. for (i = 0; i < height; i++)
  373. for (j = 0; j < width; j++)
  374. out[height * j + h - i] = *in++;
  375. }
  376.  
  377. static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height)
  378. {
  379. int i, j, w = width - 1;
  380.  
  381. for (i = 0; i < height; i++)
  382. for (j = 0; j < width; j++)
  383. out[height * (w - j) + i] = *in++;
  384. }
  385.  
  386. static void fb_rotate_logo(struct fb_info *info, u8 *dst,
  387. struct fb_image *image, int rotate)
  388. {
  389. u32 tmp;
  390.  
  391. if (rotate == FB_ROTATE_UD) {
  392. fb_rotate_logo_ud(image->data, dst, image->width,
  393. image->height);
  394. image->dx = info->var.xres - image->width - image->dx;
  395. image->dy = info->var.yres - image->height - image->dy;
  396. } else if (rotate == FB_ROTATE_CW) {
  397. fb_rotate_logo_cw(image->data, dst, image->width,
  398. image->height);
  399. tmp = image->width;
  400. image->width = image->height;
  401. image->height = tmp;
  402. tmp = image->dy;
  403. image->dy = image->dx;
  404. image->dx = info->var.xres - image->width - tmp;
  405. } else if (rotate == FB_ROTATE_CCW) {
  406. fb_rotate_logo_ccw(image->data, dst, image->width,
  407. image->height);
  408. tmp = image->width;
  409. image->width = image->height;
  410. image->height = tmp;
  411. tmp = image->dx;
  412. image->dx = image->dy;
  413. image->dy = info->var.yres - image->height - tmp;
  414. }
  415.  
  416. image->data = dst;
  417. }
  418.  
  419. static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
  420. int rotate, unsigned int num)
  421. {
  422. unsigned int x;
  423.  
  424. if (rotate == FB_ROTATE_UR) {
  425. for (x = 0;
  426. x < num && image->dx + image->width <= info->var.xres;
  427. x++) {
  428. info->fbops->fb_imageblit(info, image);
  429. image->dx += image->width + 8;
  430. }
  431. } else if (rotate == FB_ROTATE_UD) {
  432. for (x = 0; x < num && image->dx >= 0; x++) {
  433. info->fbops->fb_imageblit(info, image);
  434. image->dx -= image->width + 8;
  435. }
  436. } else if (rotate == FB_ROTATE_CW) {
  437. for (x = 0;
  438. x < num && image->dy + image->height <= info->var.yres;
  439. x++) {
  440. info->fbops->fb_imageblit(info, image);
  441. image->dy += image->height + 8;
  442. }
  443. } else if (rotate == FB_ROTATE_CCW) {
  444. for (x = 0; x < num && image->dy >= 0; x++) {
  445. info->fbops->fb_imageblit(info, image);
  446. image->dy -= image->height + 8;
  447. }
  448. }
  449. }
  450.  
  451. static int fb_show_logo_line(struct fb_info *info, int rotate,
  452. const struct linux_logo *logo, int y,
  453. unsigned int n)
  454. {
  455. u32 *palette = NULL, *saved_pseudo_palette = NULL;
  456. unsigned char *logo_new = NULL, *logo_rotate = NULL;
  457. struct fb_image image;
  458.  
  459. /* Return if the frame buffer is not mapped or suspended */
  460. if (logo == NULL || info->state != FBINFO_STATE_RUNNING ||
  461. info->flags & FBINFO_MODULE)
  462. return 0;
  463.  
  464. image.depth = 8;
  465. image.data = logo->data;
  466.  
  467. if (fb_logo.needs_cmapreset)
  468. fb_set_logocmap(info, logo);
  469.  
  470. if (fb_logo.needs_truepalette ||
  471. fb_logo.needs_directpalette) {
  472. palette = kmalloc(256 * 4, GFP_KERNEL);
  473. if (palette == NULL)
  474. return 0;
  475.  
  476. if (fb_logo.needs_truepalette)
  477. fb_set_logo_truepalette(info, logo, palette);
  478. else
  479. fb_set_logo_directpalette(info, logo, palette);
  480.  
  481. saved_pseudo_palette = info->pseudo_palette;
  482. info->pseudo_palette = palette;
  483. }
  484.  
  485. if (fb_logo.depth <= 4) {
  486. logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL);
  487. if (logo_new == NULL) {
  488. kfree(palette);
  489. if (saved_pseudo_palette)
  490. info->pseudo_palette = saved_pseudo_palette;
  491. return 0;
  492. }
  493. image.data = logo_new;
  494. fb_set_logo(info, logo, logo_new, fb_logo.depth);
  495. }
  496.  
  497. image.dx = 0;
  498. image.dy = y;
  499. image.width = logo->width;
  500. image.height = logo->height;
  501.  
  502. if (rotate) {
  503. logo_rotate = kmalloc(logo->width *
  504. logo->height, GFP_KERNEL);
  505. if (logo_rotate)
  506. fb_rotate_logo(info, logo_rotate, &image, rotate);
  507. }
  508.  
  509. fb_do_show_logo(info, &image, rotate, n);
  510.  
  511. kfree(palette);
  512. if (saved_pseudo_palette != NULL)
  513. info->pseudo_palette = saved_pseudo_palette;
  514. kfree(logo_new);
  515. kfree(logo_rotate);
  516. return logo->height;
  517. }
  518.  
  519.  
  520. #ifdef CONFIG_FB_LOGO_EXTRA
  521.  
  522. #define FB_LOGO_EX_NUM_MAX 10
  523. static struct logo_data_extra {
  524. const struct linux_logo *logo;
  525. unsigned int n;
  526. } fb_logo_ex[FB_LOGO_EX_NUM_MAX];
  527. static unsigned int fb_logo_ex_num;
  528.  
  529. void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n)
  530. {
  531. if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX)
  532. return;
  533.  
  534. fb_logo_ex[fb_logo_ex_num].logo = logo;
  535. fb_logo_ex[fb_logo_ex_num].n = n;
  536. fb_logo_ex_num++;
  537. }
  538.  
  539. static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height,
  540. unsigned int yres)
  541. {
  542. unsigned int i;
  543.  
  544. /* FIXME: logo_ex supports only truecolor fb. */
  545. if (info->fix.visual != FB_VISUAL_TRUECOLOR)
  546. fb_logo_ex_num = 0;
  547.  
  548. for (i = 0; i < fb_logo_ex_num; i++) {
  549. if (fb_logo_ex[i].logo->type != fb_logo.logo->type) {
  550. fb_logo_ex[i].logo = NULL;
  551. continue;
  552. }
  553. height += fb_logo_ex[i].logo->height;
  554. if (height > yres) {
  555. height -= fb_logo_ex[i].logo->height;
  556. fb_logo_ex_num = i;
  557. break;
  558. }
  559. }
  560. return height;
  561. }
  562.  
  563. static int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
  564. {
  565. unsigned int i;
  566.  
  567. for (i = 0; i < fb_logo_ex_num; i++)
  568. y += fb_show_logo_line(info, rotate,
  569. fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
  570.  
  571. return y;
  572. }
  573.  
  574. #else /* !CONFIG_FB_LOGO_EXTRA */
  575.  
  576. static inline int fb_prepare_extra_logos(struct fb_info *info,
  577. unsigned int height,
  578. unsigned int yres)
  579. {
  580. return height;
  581. }
  582.  
  583. static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
  584. {
  585. return y;
  586. }
  587.  
  588. #endif /* CONFIG_FB_LOGO_EXTRA */
  589.  
  590.  
  591. int fb_prepare_logo(struct fb_info *info, int rotate)
  592. {
  593. int depth = fb_get_color_depth(&info->var, &info->fix);
  594. unsigned int yres;
  595.  
  596. memset(&fb_logo, 0, sizeof(struct logo_data));
  597.  
  598. if (info->flags & FBINFO_MISC_TILEBLITTING ||
  599. info->flags & FBINFO_MODULE)
  600. return 0;
  601.  
  602. if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
  603. depth = info->var.blue.length;
  604. if (info->var.red.length < depth)
  605. depth = info->var.red.length;
  606. if (info->var.green.length < depth)
  607. depth = info->var.green.length;
  608. }
  609.  
  610. if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) {
  611. /* assume console colormap */
  612. depth = 4;
  613. }
  614.  
  615. /* Return if no suitable logo was found */
  616. fb_logo.logo = fb_find_logo(depth);
  617.  
  618. if (!fb_logo.logo) {
  619. return 0;
  620. }
  621.  
  622. if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)
  623. yres = info->var.yres;
  624. else
  625. yres = info->var.xres;
  626.  
  627. if (fb_logo.logo->height > yres) {
  628. fb_logo.logo = NULL;
  629. return 0;
  630. }
  631.  
  632. /* What depth we asked for might be different from what we get */
  633. if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
  634. fb_logo.depth = 8;
  635. else if (fb_logo.logo->type == LINUX_LOGO_VGA16)
  636. fb_logo.depth = 4;
  637. else
  638. fb_logo.depth = 1;
  639.  
  640.  
  641. if (fb_logo.depth > 4 && depth > 4) {
  642. switch (info->fix.visual) {
  643. case FB_VISUAL_TRUECOLOR:
  644. fb_logo.needs_truepalette = 1;
  645. break;
  646. case FB_VISUAL_DIRECTCOLOR:
  647. fb_logo.needs_directpalette = 1;
  648. fb_logo.needs_cmapreset = 1;
  649. break;
  650. case FB_VISUAL_PSEUDOCOLOR:
  651. fb_logo.needs_cmapreset = 1;
  652. break;
  653. }
  654. }
  655.  
  656. return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
  657. }
  658.  
  659. int fb_show_logo(struct fb_info *info, int rotate)
  660. {
  661. int y;
  662.  
  663. y = fb_show_logo_line(info, rotate, fb_logo.logo, 0,
  664. num_online_cpus());
  665. y = fb_show_extra_logos(info, y, rotate);
  666.  
  667. return y;
  668. }
  669. #else
  670. int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
  671. int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
  672. #endif /* CONFIG_LOGO */
  673.  
  674. static void *fb_seq_start(struct seq_file *m, loff_t *pos)
  675. {
  676. mutex_lock(&registration_lock);
  677. return (*pos < FB_MAX) ? pos : NULL;
  678. }
  679.  
  680. static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos)
  681. {
  682. (*pos)++;
  683. return (*pos < FB_MAX) ? pos : NULL;
  684. }
  685.  
  686. static void fb_seq_stop(struct seq_file *m, void *v)
  687. {
  688. mutex_unlock(&registration_lock);
  689. }
  690.  
  691. static int fb_seq_show(struct seq_file *m, void *v)
  692. {
  693. int i = *(loff_t *)v;
  694. struct fb_info *fi = registered_fb[i];
  695.  
  696. if (fi)
  697. seq_printf(m, "%d %s\n", fi->node, fi->fix.id);
  698. return 0;
  699. }
  700.  
  701. static const struct seq_operations proc_fb_seq_ops = {
  702. .start = fb_seq_start,
  703. .next = fb_seq_next,
  704. .stop = fb_seq_stop,
  705. .show = fb_seq_show,
  706. };
  707.  
  708. static int proc_fb_open(struct inode *inode, struct file *file)
  709. {
  710. return seq_open(file, &proc_fb_seq_ops);
  711. }
  712.  
  713. static const struct file_operations fb_proc_fops = {
  714. .owner = THIS_MODULE,
  715. .open = proc_fb_open,
  716. .read = seq_read,
  717. .llseek = seq_lseek,
  718. .release = seq_release,
  719. };
  720.  
  721. /*
  722. * We hold a reference to the fb_info in file->private_data,
  723. * but if the current registered fb has changed, we don't
  724. * actually want to use it.
  725. *
  726. * So look up the fb_info using the inode minor number,
  727. * and just verify it against the reference we have.
  728. */
  729. static struct fb_info *file_fb_info(struct file *file)
  730. {
  731. struct inode *inode = file->f_path.dentry->d_inode;
  732. int fbidx = iminor(inode);
  733. struct fb_info *info = registered_fb[fbidx];
  734.  
  735. if (info != file->private_data)
  736. info = NULL;
  737. return info;
  738. }
  739.  
  740. static ssize_t
  741. fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
  742. {
  743. unsigned long p = *ppos;
  744. struct fb_info *info = file_fb_info(file);
  745. u8 *buffer, *dst;
  746. u8 __iomem *src;
  747. int c, cnt = 0, err = 0;
  748. unsigned long total_size;
  749.  
  750. if (!info || ! info->screen_base)
  751. return -ENODEV;
  752.  
  753. if (info->state != FBINFO_STATE_RUNNING)
  754. return -EPERM;
  755.  
  756. if (info->fbops->fb_read)
  757. return info->fbops->fb_read(info, buf, count, ppos);
  758.  
  759. total_size = info->screen_size;
  760.  
  761. if (total_size == 0)
  762. total_size = info->fix.smem_len;
  763.  
  764. if (p >= total_size)
  765. return 0;
  766.  
  767. if (count >= total_size)
  768. count = total_size;
  769.  
  770. if (count + p > total_size)
  771. count = total_size - p;
  772.  
  773. buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
  774. GFP_KERNEL);
  775. if (!buffer)
  776. return -ENOMEM;
  777.  
  778. src = (u8 __iomem *) (info->screen_base + p);
  779.  
  780. if (info->fbops->fb_sync)
  781. info->fbops->fb_sync(info);
  782.  
  783. while (count) {
  784. c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
  785. dst = buffer;
  786. fb_memcpy_fromfb(dst, src, c);
  787. dst += c;
  788. src += c;
  789.  
  790. if (copy_to_user(buf, buffer, c)) {
  791. err = -EFAULT;
  792. break;
  793. }
  794. *ppos += c;
  795. buf += c;
  796. cnt += c;
  797. count -= c;
  798. }
  799.  
  800. kfree(buffer);
  801.  
  802. return (err) ? err : cnt;
  803. }
  804.  
  805. static ssize_t
  806. fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
  807. {
  808. unsigned long p = *ppos;
  809. struct fb_info *info = file_fb_info(file);
  810. u8 *buffer, *src;
  811. u8 __iomem *dst;
  812. int c, cnt = 0, err = 0;
  813. unsigned long total_size;
  814.  
  815. if (!info || !info->screen_base)
  816. return -ENODEV;
  817.  
  818. if (info->state != FBINFO_STATE_RUNNING)
  819. return -EPERM;
  820.  
  821. if (info->fbops->fb_write)
  822. return info->fbops->fb_write(info, buf, count, ppos);
  823.  
  824. total_size = info->screen_size;
  825.  
  826. if (total_size == 0)
  827. total_size = info->fix.smem_len;
  828.  
  829. if (p > total_size)
  830. return -EFBIG;
  831.  
  832. if (count > total_size) {
  833. err = -EFBIG;
  834. count = total_size;
  835. }
  836.  
  837. if (count + p > total_size) {
  838. if (!err)
  839. err = -ENOSPC;
  840.  
  841. count = total_size - p;
  842. }
  843.  
  844. buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
  845. GFP_KERNEL);
  846. if (!buffer)
  847. return -ENOMEM;
  848.  
  849. dst = (u8 __iomem *) (info->screen_base + p);
  850.  
  851. if (info->fbops->fb_sync)
  852. info->fbops->fb_sync(info);
  853.  
  854. while (count) {
  855. c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
  856. src = buffer;
  857.  
  858. if (copy_from_user(src, buf, c)) {
  859. err = -EFAULT;
  860. break;
  861. }
  862.  
  863. fb_memcpy_tofb(dst, src, c);
  864. dst += c;
  865. src += c;
  866. *ppos += c;
  867. buf += c;
  868. cnt += c;
  869. count -= c;
  870. }
  871.  
  872. kfree(buffer);
  873.  
  874. return (cnt) ? cnt : err;
  875. }
  876.  
  877. int
  878. fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
  879. {
  880. struct fb_fix_screeninfo *fix = &info->fix;
  881. unsigned int yres = info->var.yres;
  882. int err = 0;
  883.  
  884. if (var->yoffset > 0) {
  885. if (var->vmode & FB_VMODE_YWRAP) {
  886. if (!fix->ywrapstep || (var->yoffset % fix->ywrapstep))
  887. err = -EINVAL;
  888. else
  889. yres = 0;
  890. } else if (!fix->ypanstep || (var->yoffset % fix->ypanstep))
  891. err = -EINVAL;
  892. }
  893.  
  894. if (var->xoffset > 0 && (!fix->xpanstep ||
  895. (var->xoffset % fix->xpanstep)))
  896. err = -EINVAL;
  897.  
  898. if (err || !info->fbops->fb_pan_display ||
  899. var->yoffset > info->var.yres_virtual - yres ||
  900. var->xoffset > info->var.xres_virtual - info->var.xres)
  901. return -EINVAL;
  902.  
  903. if ((err = info->fbops->fb_pan_display(var, info)))
  904. return err;
  905. info->var.xoffset = var->xoffset;
  906. info->var.yoffset = var->yoffset;
  907. if (var->vmode & FB_VMODE_YWRAP)
  908. info->var.vmode |= FB_VMODE_YWRAP;
  909. else
  910. info->var.vmode &= ~FB_VMODE_YWRAP;
  911. return 0;
  912. }
  913.  
  914. static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
  915. u32 activate)
  916. {
  917. struct fb_event event;
  918. struct fb_blit_caps caps, fbcaps;
  919. int err = 0;
  920.  
  921. memset(&caps, 0, sizeof(caps));
  922. memset(&fbcaps, 0, sizeof(fbcaps));
  923. caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0;
  924. event.info = info;
  925. event.data = &caps;
  926. fb_notifier_call_chain(FB_EVENT_GET_REQ, &event);
  927. info->fbops->fb_get_caps(info, &fbcaps, var);
  928.  
  929. if (((fbcaps.x ^ caps.x) & caps.x) ||
  930. ((fbcaps.y ^ caps.y) & caps.y) ||
  931. (fbcaps.len < caps.len))
  932. err = -EINVAL;
  933.  
  934. return err;
  935. }
  936.  
  937. int
  938. fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
  939. {
  940. int flags = info->flags;
  941. int ret = 0;
  942.  
  943. if (var->activate & FB_ACTIVATE_INV_MODE) {
  944. struct fb_videomode mode1, mode2;
  945.  
  946. fb_var_to_videomode(&mode1, var);
  947. fb_var_to_videomode(&mode2, &info->var);
  948. /* make sure we don't delete the videomode of current var */
  949. ret = fb_mode_is_equal(&mode1, &mode2);
  950.  
  951. if (!ret) {
  952. struct fb_event event;
  953.  
  954. event.info = info;
  955. event.data = &mode1;
  956. ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event);
  957. }
  958.  
  959. if (!ret)
  960. fb_delete_videomode(&mode1, &info->modelist);
  961.  
  962.  
  963. ret = (ret) ? -EINVAL : 0;
  964. goto done;
  965. }
  966.  
  967. if ((var->activate & FB_ACTIVATE_FORCE) ||
  968. memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
  969. u32 activate = var->activate;
  970.  
  971. if (!info->fbops->fb_check_var) {
  972. *var = info->var;
  973. goto done;
  974. }
  975.  
  976. ret = info->fbops->fb_check_var(var, info);
  977.  
  978. if (ret)
  979. goto done;
  980.  
  981. if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
  982. struct fb_var_screeninfo old_var;
  983. struct fb_videomode mode;
  984.  
  985. if (info->fbops->fb_get_caps) {
  986. ret = fb_check_caps(info, var, activate);
  987.  
  988. if (ret)
  989. goto done;
  990. }
  991.  
  992. old_var = info->var;
  993. info->var = *var;
  994.  
  995. if (info->fbops->fb_set_par) {
  996. ret = info->fbops->fb_set_par(info);
  997.  
  998. if (ret) {
  999. info->var = old_var;
  1000. printk(KERN_WARNING "detected "
  1001. "fb_set_par error, "
  1002. "error code: %d\n", ret);
  1003. goto done;
  1004. }
  1005. }
  1006.  
  1007. fb_pan_display(info, &info->var);
  1008. fb_set_cmap(&info->cmap, info);
  1009. fb_var_to_videomode(&mode, &info->var);
  1010.  
  1011. if (info->modelist.prev && info->modelist.next &&
  1012. !list_empty(&info->modelist))
  1013. ret = fb_add_videomode(&mode, &info->modelist);
  1014.  
  1015. if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
  1016. struct fb_event event;
  1017. int evnt = (activate & FB_ACTIVATE_ALL) ?
  1018. FB_EVENT_MODE_CHANGE_ALL :
  1019. FB_EVENT_MODE_CHANGE;
  1020.  
  1021. info->flags &= ~FBINFO_MISC_USEREVENT;
  1022. event.info = info;
  1023. event.data = &mode;
  1024. fb_notifier_call_chain(evnt, &event);
  1025. }
  1026. }
  1027. }
  1028.  
  1029. done:
  1030. return ret;
  1031. }
  1032.  
  1033. int
  1034. fb_blank(struct fb_info *info, int blank)
  1035. {
  1036. struct fb_event event;
  1037. int ret = -EINVAL, early_ret;
  1038.  
  1039. if (blank > FB_BLANK_POWERDOWN)
  1040. blank = FB_BLANK_POWERDOWN;
  1041.  
  1042. event.info = info;
  1043. event.data = &blank;
  1044.  
  1045. early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event);
  1046.  
  1047. if (info->fbops->fb_blank)
  1048. ret = info->fbops->fb_blank(blank, info);
  1049.  
  1050. if (!ret)
  1051. fb_notifier_call_chain(FB_EVENT_BLANK, &event);
  1052. else {
  1053. /*
  1054. * if fb_blank is failed then revert effects of
  1055. * the early blank event.
  1056. */
  1057. if (!early_ret)
  1058. fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK, &event);
  1059. }
  1060.  
  1061. return ret;
  1062. }
  1063.  
  1064. static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
  1065. unsigned long arg)
  1066. {
  1067. struct fb_ops *fb;
  1068. struct fb_var_screeninfo var;
  1069. struct fb_fix_screeninfo fix;
  1070. struct fb_con2fbmap con2fb;
  1071. struct fb_cmap cmap_from;
  1072. struct fb_cmap_user cmap;
  1073. struct fb_event event;
  1074. void __user *argp = (void __user *)arg;
  1075. long ret = 0;
  1076.  
  1077. switch (cmd) {
  1078. case FBIOGET_VSCREENINFO:
  1079. if (!lock_fb_info(info))
  1080. return -ENODEV;
  1081. var = info->var;
  1082. unlock_fb_info(info);
  1083.  
  1084. ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;
  1085. break;
  1086. case FBIOPUT_VSCREENINFO:
  1087. if (copy_from_user(&var, argp, sizeof(var)))
  1088. return -EFAULT;
  1089. if (!lock_fb_info(info))
  1090. return -ENODEV;
  1091. console_lock();
  1092. info->flags |= FBINFO_MISC_USEREVENT;
  1093. ret = fb_set_var(info, &var);
  1094. info->flags &= ~FBINFO_MISC_USEREVENT;
  1095. console_unlock();
  1096. unlock_fb_info(info);
  1097. if (!ret && copy_to_user(argp, &var, sizeof(var)))
  1098. ret = -EFAULT;
  1099. break;
  1100. case FBIOGET_FSCREENINFO:
  1101. if (!lock_fb_info(info))
  1102. return -ENODEV;
  1103. fix = info->fix;
  1104. unlock_fb_info(info);
  1105.  
  1106. ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
  1107. break;
  1108. case FBIOPUTCMAP:
  1109. if (copy_from_user(&cmap, argp, sizeof(cmap)))
  1110. return -EFAULT;
  1111. ret = fb_set_user_cmap(&cmap, info);
  1112. break;
  1113. case FBIOGETCMAP:
  1114. if (copy_from_user(&cmap, argp, sizeof(cmap)))
  1115. return -EFAULT;
  1116. if (!lock_fb_info(info))
  1117. return -ENODEV;
  1118. cmap_from = info->cmap;
  1119. unlock_fb_info(info);
  1120. ret = fb_cmap_to_user(&cmap_from, &cmap);
  1121. break;
  1122. case FBIOPAN_DISPLAY:
  1123. if (copy_from_user(&var, argp, sizeof(var)))
  1124. return -EFAULT;
  1125. if (!lock_fb_info(info))
  1126. return -ENODEV;
  1127. console_lock();
  1128. ret = fb_pan_display(info, &var);
  1129. console_unlock();
  1130. unlock_fb_info(info);
  1131. if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
  1132. return -EFAULT;
  1133. break;
  1134. case FBIO_CURSOR:
  1135. ret = -EINVAL;
  1136. break;
  1137. case FBIOGET_CON2FBMAP:
  1138. if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
  1139. return -EFAULT;
  1140. if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
  1141. return -EINVAL;
  1142. con2fb.framebuffer = -1;
  1143. event.data = &con2fb;
  1144. if (!lock_fb_info(info))
  1145. return -ENODEV;
  1146. event.info = info;
  1147. fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
  1148. unlock_fb_info(info);
  1149. ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
  1150. break;
  1151. case FBIOPUT_CON2FBMAP:
  1152. if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
  1153. return -EFAULT;
  1154. if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
  1155. return -EINVAL;
  1156. if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
  1157. return -EINVAL;
  1158. if (!registered_fb[con2fb.framebuffer])
  1159. request_module("fb%d", con2fb.framebuffer);
  1160. if (!registered_fb[con2fb.framebuffer]) {
  1161. ret = -EINVAL;
  1162. break;
  1163. }
  1164. event.data = &con2fb;
  1165. if (!lock_fb_info(info))
  1166. return -ENODEV;
  1167. console_lock();
  1168. event.info = info;
  1169. ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
  1170. console_unlock();
  1171. unlock_fb_info(info);
  1172. break;
  1173. case FBIOBLANK:
  1174. if (!lock_fb_info(info))
  1175. return -ENODEV;
  1176. console_lock();
  1177. info->flags |= FBINFO_MISC_USEREVENT;
  1178. ret = fb_blank(info, arg);
  1179. info->flags &= ~FBINFO_MISC_USEREVENT;
  1180. console_unlock();
  1181. unlock_fb_info(info);
  1182. break;
  1183. default:
  1184. if (!lock_fb_info(info))
  1185. return -ENODEV;
  1186. fb = info->fbops;
  1187. if (fb->fb_ioctl)
  1188. ret = fb->fb_ioctl(info, cmd, arg);
  1189. else
  1190. ret = -ENOTTY;
  1191. unlock_fb_info(info);
  1192. }
  1193. return ret;
  1194. }
  1195.  
  1196. static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  1197. {
  1198. struct fb_info *info = file_fb_info(file);
  1199.  
  1200. if (!info)
  1201. return -ENODEV;
  1202. return do_fb_ioctl(info, cmd, arg);
  1203. }
  1204.  
  1205. #ifdef CONFIG_COMPAT
  1206. struct fb_fix_screeninfo32 {
  1207. char id[16];
  1208. compat_caddr_t smem_start;
  1209. u32 smem_len;
  1210. u32 type;
  1211. u32 type_aux;
  1212. u32 visual;
  1213. u16 xpanstep;
  1214. u16 ypanstep;
  1215. u16 ywrapstep;
  1216. u32 line_length;
  1217. compat_caddr_t mmio_start;
  1218. u32 mmio_len;
  1219. u32 accel;
  1220. u16 reserved[3];
  1221. };
  1222.  
  1223. struct fb_cmap32 {
  1224. u32 start;
  1225. u32 len;
  1226. compat_caddr_t red;
  1227. compat_caddr_t green;
  1228. compat_caddr_t blue;
  1229. compat_caddr_t transp;
  1230. };
  1231.  
  1232. static int fb_getput_cmap(struct fb_info *info, unsigned int cmd,
  1233. unsigned long arg)
  1234. {
  1235. struct fb_cmap_user __user *cmap;
  1236. struct fb_cmap32 __user *cmap32;
  1237. __u32 data;
  1238. int err;
  1239.  
  1240. cmap = compat_alloc_user_space(sizeof(*cmap));
  1241. cmap32 = compat_ptr(arg);
  1242.  
  1243. if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
  1244. return -EFAULT;
  1245.  
  1246. if (get_user(data, &cmap32->red) ||
  1247. put_user(compat_ptr(data), &cmap->red) ||
  1248. get_user(data, &cmap32->green) ||
  1249. put_user(compat_ptr(data), &cmap->green) ||
  1250. get_user(data, &cmap32->blue) ||
  1251. put_user(compat_ptr(data), &cmap->blue) ||
  1252. get_user(data, &cmap32->transp) ||
  1253. put_user(compat_ptr(data), &cmap->transp))
  1254. return -EFAULT;
  1255.  
  1256. err = do_fb_ioctl(info, cmd, (unsigned long) cmap);
  1257.  
  1258. if (!err) {
  1259. if (copy_in_user(&cmap32->start,
  1260. &cmap->start,
  1261. 2 * sizeof(__u32)))
  1262. err = -EFAULT;
  1263. }
  1264. return err;
  1265. }
  1266.  
  1267. static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
  1268. struct fb_fix_screeninfo32 __user *fix32)
  1269. {
  1270. __u32 data;
  1271. int err;
  1272.  
  1273. err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id));
  1274.  
  1275. data = (__u32) (unsigned long) fix->smem_start;
  1276. err |= put_user(data, &fix32->smem_start);
  1277.  
  1278. err |= put_user(fix->smem_len, &fix32->smem_len);
  1279. err |= put_user(fix->type, &fix32->type);
  1280. err |= put_user(fix->type_aux, &fix32->type_aux);
  1281. err |= put_user(fix->visual, &fix32->visual);
  1282. err |= put_user(fix->xpanstep, &fix32->xpanstep);
  1283. err |= put_user(fix->ypanstep, &fix32->ypanstep);
  1284. err |= put_user(fix->ywrapstep, &fix32->ywrapstep);
  1285. err |= put_user(fix->line_length, &fix32->line_length);
  1286.  
  1287. data = (__u32) (unsigned long) fix->mmio_start;
  1288. err |= put_user(data, &fix32->mmio_start);
  1289.  
  1290. err |= put_user(fix->mmio_len, &fix32->mmio_len);
  1291. err |= put_user(fix->accel, &fix32->accel);
  1292. err |= copy_to_user(fix32->reserved, fix->reserved,
  1293. sizeof(fix->reserved));
  1294.  
  1295. return err;
  1296. }
  1297.  
  1298. static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
  1299. unsigned long arg)
  1300. {
  1301. mm_segment_t old_fs;
  1302. struct fb_fix_screeninfo fix;
  1303. struct fb_fix_screeninfo32 __user *fix32;
  1304. int err;
  1305.  
  1306. fix32 = compat_ptr(arg);
  1307.  
  1308. old_fs = get_fs();
  1309. set_fs(KERNEL_DS);
  1310. err = do_fb_ioctl(info, cmd, (unsigned long) &fix);
  1311. set_fs(old_fs);
  1312.  
  1313. if (!err)
  1314. err = do_fscreeninfo_to_user(&fix, fix32);
  1315.  
  1316. return err;
  1317. }
  1318.  
  1319. static long fb_compat_ioctl(struct file *file, unsigned int cmd,
  1320. unsigned long arg)
  1321. {
  1322. struct fb_info *info = file_fb_info(file);
  1323. struct fb_ops *fb;
  1324. long ret = -ENOIOCTLCMD;
  1325.  
  1326. if (!info)
  1327. return -ENODEV;
  1328. fb = info->fbops;
  1329. switch(cmd) {
  1330. case FBIOGET_VSCREENINFO:
  1331. case FBIOPUT_VSCREENINFO:
  1332. case FBIOPAN_DISPLAY:
  1333. case FBIOGET_CON2FBMAP:
  1334. case FBIOPUT_CON2FBMAP:
  1335. arg = (unsigned long) compat_ptr(arg);
  1336. case FBIOBLANK:
  1337. ret = do_fb_ioctl(info, cmd, arg);
  1338. break;
  1339.  
  1340. case FBIOGET_FSCREENINFO:
  1341. ret = fb_get_fscreeninfo(info, cmd, arg);
  1342. break;
  1343.  
  1344. case FBIOGETCMAP:
  1345. case FBIOPUTCMAP:
  1346. ret = fb_getput_cmap(info, cmd, arg);
  1347. break;
  1348.  
  1349. default:
  1350. if (fb->fb_compat_ioctl)
  1351. ret = fb->fb_compat_ioctl(info, cmd, arg);
  1352. break;
  1353. }
  1354. return ret;
  1355. }
  1356. #endif
  1357.  
  1358. static int
  1359. fb_mmap(struct file *file, struct vm_area_struct * vma)
  1360. {
  1361. struct fb_info *info = file_fb_info(file);
  1362. struct fb_ops *fb;
  1363. unsigned long mmio_pgoff;
  1364. unsigned long start;
  1365. u32 len;
  1366.  
  1367. if (!info)
  1368. return -ENODEV;
  1369. fb = info->fbops;
  1370. if (!fb)
  1371. return -ENODEV;
  1372. mutex_lock(&info->mm_lock);
  1373. if (fb->fb_mmap) {
  1374. int res;
  1375. res = fb->fb_mmap(info, vma);
  1376. mutex_unlock(&info->mm_lock);
  1377. return res;
  1378. }
  1379.  
  1380. /* frame buffer memory */
  1381. start = info->fix.smem_start;
  1382. len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
  1383.  
  1384. #if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412)
  1385. if (!cma_is_registered_region(start, len)) {
  1386. pr_err("%s: %x@%x is allowed to map\n",
  1387. __func__, (unsigned int)start,
  1388. (unsigned int)len);
  1389. mutex_unlock(&info->mm_lock);
  1390. return -EINVAL;
  1391. }
  1392. #endif
  1393.  
  1394. if (off >= len) {
  1395. /* memory mapped io */
  1396. off -= len;
  1397. if (info->var.accel_flags) {
  1398. mutex_unlock(&info->mm_lock);
  1399. return -EINVAL;
  1400. }
  1401. start = info->fix.mmio_start;
  1402. len = info->fix.mmio_len;
  1403. }
  1404. mutex_unlock(&info->mm_lock);
  1405.  
  1406. vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
  1407. fb_pgprotect(file, vma, start);
  1408.  
  1409. return vm_iomap_memory(vma, start, len);
  1410. }
  1411.  
  1412. static int
  1413. fb_open(struct inode *inode, struct file *file)
  1414. __acquires(&info->lock)
  1415. __releases(&info->lock)
  1416. {
  1417. int fbidx = iminor(inode);
  1418. struct fb_info *info;
  1419. int res = 0;
  1420.  
  1421. info = get_fb_info(fbidx);
  1422. if (!info) {
  1423. request_module("fb%d", fbidx);
  1424. info = get_fb_info(fbidx);
  1425. if (!info)
  1426. return -ENODEV;
  1427. }
  1428. if (IS_ERR(info))
  1429. return PTR_ERR(info);
  1430.  
  1431. mutex_lock(&info->lock);
  1432. if (!try_module_get(info->fbops->owner)) {
  1433. res = -ENODEV;
  1434. goto out;
  1435. }
  1436. file->private_data = info;
  1437. if (info->fbops->fb_open) {
  1438. res = info->fbops->fb_open(info,1);
  1439. if (res)
  1440. module_put(info->fbops->owner);
  1441. }
  1442. #ifdef CONFIG_FB_DEFERRED_IO
  1443. if (info->fbdefio)
  1444. fb_deferred_io_open(info, inode, file);
  1445. #endif
  1446. out:
  1447. mutex_unlock(&info->lock);
  1448. if (res)
  1449. put_fb_info(info);
  1450. return res;
  1451. }
  1452.  
  1453. static int
  1454. fb_release(struct inode *inode, struct file *file)
  1455. __acquires(&info->lock)
  1456. __releases(&info->lock)
  1457. {
  1458. struct fb_info * const info = file->private_data;
  1459.  
  1460. mutex_lock(&info->lock);
  1461. if (info->fbops->fb_release)
  1462. info->fbops->fb_release(info,1);
  1463. module_put(info->fbops->owner);
  1464. mutex_unlock(&info->lock);
  1465. put_fb_info(info);
  1466. return 0;
  1467. }
  1468.  
  1469. static const struct file_operations fb_fops = {
  1470. .owner = THIS_MODULE,
  1471. .read = fb_read,
  1472. .write = fb_write,
  1473. .unlocked_ioctl = fb_ioctl,
  1474. #ifdef CONFIG_COMPAT
  1475. .compat_ioctl = fb_compat_ioctl,
  1476. #endif
  1477. .mmap = fb_mmap,
  1478. .open = fb_open,
  1479. .release = fb_release,
  1480. #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
  1481. .get_unmapped_area = get_fb_unmapped_area,
  1482. #endif
  1483. #ifdef CONFIG_FB_DEFERRED_IO
  1484. .fsync = fb_deferred_io_fsync,
  1485. #endif
  1486. .llseek = default_llseek,
  1487. };
  1488.  
  1489. struct class *fb_class;
  1490. EXPORT_SYMBOL(fb_class);
  1491.  
  1492. static int fb_check_foreignness(struct fb_info *fi)
  1493. {
  1494. const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN;
  1495.  
  1496. fi->flags &= ~FBINFO_FOREIGN_ENDIAN;
  1497.  
  1498. #ifdef __BIG_ENDIAN
  1499. fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH;
  1500. #else
  1501. fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0;
  1502. #endif /* __BIG_ENDIAN */
  1503.  
  1504. if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) {
  1505. pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to "
  1506. "support this framebuffer\n", fi->fix.id);
  1507. return -ENOSYS;
  1508. } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) {
  1509. pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to "
  1510. "support this framebuffer\n", fi->fix.id);
  1511. return -ENOSYS;
  1512. }
  1513.  
  1514. return 0;
  1515. }
  1516.  
  1517. static bool apertures_overlap(struct aperture *gen, struct aperture *hw)
  1518. {
  1519. /* is the generic aperture base the same as the HW one */
  1520. if (gen->base == hw->base)
  1521. return true;
  1522. /* is the generic aperture base inside the hw base->hw base+size */
  1523. if (gen->base > hw->base && gen->base < hw->base + hw->size)
  1524. return true;
  1525. return false;
  1526. }
  1527.  
  1528. static bool fb_do_apertures_overlap(struct apertures_struct *gena,
  1529. struct apertures_struct *hwa)
  1530. {
  1531. int i, j;
  1532. if (!hwa || !gena)
  1533. return false;
  1534.  
  1535. for (i = 0; i < hwa->count; ++i) {
  1536. struct aperture *h = &hwa->ranges[i];
  1537. for (j = 0; j < gena->count; ++j) {
  1538. struct aperture *g = &gena->ranges[j];
  1539. printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n",
  1540. (unsigned long long)g->base,
  1541. (unsigned long long)g->size,
  1542. (unsigned long long)h->base,
  1543. (unsigned long long)h->size);
  1544. if (apertures_overlap(g, h))
  1545. return true;
  1546. }
  1547. }
  1548.  
  1549. return false;
  1550. }
  1551.  
  1552. static int do_unregister_framebuffer(struct fb_info *fb_info);
  1553.  
  1554. #define VGA_FB_PHYS 0xA0000
  1555. static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
  1556. const char *name, bool primary)
  1557. {
  1558. int i;
  1559.  
  1560. /* check all firmware fbs and kick off if the base addr overlaps */
  1561. for (i = 0 ; i < FB_MAX; i++) {
  1562. struct apertures_struct *gen_aper;
  1563. if (!registered_fb[i])
  1564. continue;
  1565.  
  1566. if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE))
  1567. continue;
  1568.  
  1569. gen_aper = registered_fb[i]->apertures;
  1570. if (fb_do_apertures_overlap(gen_aper, a) ||
  1571. (primary && gen_aper && gen_aper->count &&
  1572. gen_aper->ranges[0].base == VGA_FB_PHYS)) {
  1573.  
  1574. printk(KERN_INFO "fb: conflicting fb hw usage "
  1575. "%s vs %s - removing generic driver\n",
  1576. name, registered_fb[i]->fix.id);
  1577. do_unregister_framebuffer(registered_fb[i]);
  1578. }
  1579. }
  1580. }
  1581.  
  1582. static int do_register_framebuffer(struct fb_info *fb_info)
  1583. {
  1584. int i;
  1585. struct fb_event event;
  1586. struct fb_videomode mode;
  1587.  
  1588. if (fb_check_foreignness(fb_info))
  1589. return -ENOSYS;
  1590.  
  1591. do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
  1592. fb_is_primary_device(fb_info));
  1593.  
  1594. if (num_registered_fb == FB_MAX)
  1595. return -ENXIO;
  1596.  
  1597. num_registered_fb++;
  1598. for (i = 0 ; i < FB_MAX; i++)
  1599. if (!registered_fb[i])
  1600. break;
  1601. fb_info->node = i;
  1602. atomic_set(&fb_info->count, 1);
  1603. mutex_init(&fb_info->lock);
  1604. mutex_init(&fb_info->mm_lock);
  1605.  
  1606. fb_info->dev = device_create(fb_class, fb_info->device,
  1607. MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
  1608. if (IS_ERR(fb_info->dev)) {
  1609. /* Not fatal */
  1610. printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
  1611. fb_info->dev = NULL;
  1612. } else
  1613. fb_init_device(fb_info);
  1614.  
  1615. if (fb_info->pixmap.addr == NULL) {
  1616. fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
  1617. if (fb_info->pixmap.addr) {
  1618. fb_info->pixmap.size = FBPIXMAPSIZE;
  1619. fb_info->pixmap.buf_align = 1;
  1620. fb_info->pixmap.scan_align = 1;
  1621. fb_info->pixmap.access_align = 32;
  1622. fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
  1623. }
  1624. }
  1625. fb_info->pixmap.offset = 0;
  1626.  
  1627. if (!fb_info->pixmap.blit_x)
  1628. fb_info->pixmap.blit_x = ~(u32)0;
  1629.  
  1630. if (!fb_info->pixmap.blit_y)
  1631. fb_info->pixmap.blit_y = ~(u32)0;
  1632.  
  1633. if (!fb_info->modelist.prev || !fb_info->modelist.next)
  1634. INIT_LIST_HEAD(&fb_info->modelist);
  1635.  
  1636. fb_var_to_videomode(&mode, &fb_info->var);
  1637. fb_add_videomode(&mode, &fb_info->modelist);
  1638. registered_fb[i] = fb_info;
  1639.  
  1640. event.info = fb_info;
  1641. if (!lock_fb_info(fb_info))
  1642. return -ENODEV;
  1643. console_lock();
  1644. fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
  1645. console_unlock();
  1646. unlock_fb_info(fb_info);
  1647. return 0;
  1648. }
  1649.  
  1650. static int do_unregister_framebuffer(struct fb_info *fb_info)
  1651. {
  1652. struct fb_event event;
  1653. int i, ret = 0;
  1654.  
  1655. i = fb_info->node;
  1656. if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
  1657. return -EINVAL;
  1658.  
  1659. if (!lock_fb_info(fb_info))
  1660. return -ENODEV;
  1661. console_lock();
  1662. event.info = fb_info;
  1663. ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
  1664. console_unlock();
  1665. unlock_fb_info(fb_info);
  1666.  
  1667. if (ret)
  1668. return -EINVAL;
  1669.  
  1670. unlink_framebuffer(fb_info);
  1671. if (fb_info->pixmap.addr &&
  1672. (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
  1673. kfree(fb_info->pixmap.addr);
  1674. fb_destroy_modelist(&fb_info->modelist);
  1675. registered_fb[i] = NULL;
  1676. num_registered_fb--;
  1677. fb_cleanup_device(fb_info);
  1678. event.info = fb_info;
  1679. console_lock();
  1680. fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
  1681. console_unlock();
  1682.  
  1683. /* this may free fb info */
  1684. put_fb_info(fb_info);
  1685. return 0;
  1686. }
  1687.  
  1688. int unlink_framebuffer(struct fb_info *fb_info)
  1689. {
  1690. int i;
  1691.  
  1692. i = fb_info->node;
  1693. if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
  1694. return -EINVAL;
  1695.  
  1696. if (fb_info->dev) {
  1697. device_destroy(fb_class, MKDEV(FB_MAJOR, i));
  1698. fb_info->dev = NULL;
  1699. }
  1700. return 0;
  1701. }
  1702. EXPORT_SYMBOL(unlink_framebuffer);
  1703.  
  1704. void remove_conflicting_framebuffers(struct apertures_struct *a,
  1705. const char *name, bool primary)
  1706. {
  1707. mutex_lock(&registration_lock);
  1708. do_remove_conflicting_framebuffers(a, name, primary);
  1709. mutex_unlock(&registration_lock);
  1710. }
  1711. EXPORT_SYMBOL(remove_conflicting_framebuffers);
  1712.  
  1713. /**
  1714. * register_framebuffer - registers a frame buffer device
  1715. * @fb_info: frame buffer info structure
  1716. *
  1717. * Registers a frame buffer device @fb_info.
  1718. *
  1719. * Returns negative errno on error, or zero for success.
  1720. *
  1721. */
  1722. int
  1723. register_framebuffer(struct fb_info *fb_info)
  1724. {
  1725. int ret;
  1726.  
  1727. mutex_lock(&registration_lock);
  1728. ret = do_register_framebuffer(fb_info);
  1729. mutex_unlock(&registration_lock);
  1730.  
  1731. return ret;
  1732. }
  1733.  
  1734. /**
  1735. * unregister_framebuffer - releases a frame buffer device
  1736. * @fb_info: frame buffer info structure
  1737. *
  1738. * Unregisters a frame buffer device @fb_info.
  1739. *
  1740. * Returns negative errno on error, or zero for success.
  1741. *
  1742. * This function will also notify the framebuffer console
  1743. * to release the driver.
  1744. *
  1745. * This is meant to be called within a driver's module_exit()
  1746. * function. If this is called outside module_exit(), ensure
  1747. * that the driver implements fb_open() and fb_release() to
  1748. * check that no processes are using the device.
  1749. */
  1750. int
  1751. unregister_framebuffer(struct fb_info *fb_info)
  1752. {
  1753. int ret;
  1754.  
  1755. mutex_lock(&registration_lock);
  1756. ret = do_unregister_framebuffer(fb_info);
  1757. mutex_unlock(&registration_lock);
  1758.  
  1759. return ret;
  1760. }
  1761.  
  1762. /**
  1763. * fb_set_suspend - low level driver signals suspend
  1764. * @info: framebuffer affected
  1765. * @state: 0 = resuming, !=0 = suspending
  1766. *
  1767. * This is meant to be used by low level drivers to
  1768. * signal suspend/resume to the core & clients.
  1769. * It must be called with the console semaphore held
  1770. */
  1771. void fb_set_suspend(struct fb_info *info, int state)
  1772. {
  1773. struct fb_event event;
  1774.  
  1775. event.info = info;
  1776. if (state) {
  1777. fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
  1778. info->state = FBINFO_STATE_SUSPENDED;
  1779. } else {
  1780. info->state = FBINFO_STATE_RUNNING;
  1781. fb_notifier_call_chain(FB_EVENT_RESUME, &event);
  1782. }
  1783. }
  1784.  
  1785. /**
  1786. * fbmem_init - init frame buffer subsystem
  1787. *
  1788. * Initialize the frame buffer subsystem.
  1789. *
  1790. * NOTE: This function is _only_ to be called by drivers/char/mem.c.
  1791. *
  1792. */
  1793.  
  1794. static int __init
  1795. fbmem_init(void)
  1796. {
  1797. proc_create("fb", 0, NULL, &fb_proc_fops);
  1798.  
  1799. if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
  1800. printk("unable to get major %d for fb devs\n", FB_MAJOR);
  1801.  
  1802. fb_class = class_create(THIS_MODULE, "graphics");
  1803. if (IS_ERR(fb_class)) {
  1804. printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
  1805. fb_class = NULL;
  1806. }
  1807. return 0;
  1808. }
  1809.  
  1810. #ifdef MODULE
  1811. module_init(fbmem_init);
  1812. static void __exit
  1813. fbmem_exit(void)
  1814. {
  1815. remove_proc_entry("fb", NULL);
  1816. class_destroy(fb_class);
  1817. unregister_chrdev(FB_MAJOR, "fb");
  1818. }
  1819.  
  1820. module_exit(fbmem_exit);
  1821. MODULE_LICENSE("GPL");
  1822. MODULE_DESCRIPTION("Framebuffer base");
  1823. #else
  1824. subsys_initcall(fbmem_init);
  1825. #endif
  1826.  
  1827. int fb_new_modelist(struct fb_info *info)
  1828. {
  1829. struct fb_event event;
  1830. struct fb_var_screeninfo var = info->var;
  1831. struct list_head *pos, *n;
  1832. struct fb_modelist *modelist;
  1833. struct fb_videomode *m, mode;
  1834. int err = 1;
  1835.  
  1836. list_for_each_safe(pos, n, &info->modelist) {
  1837. modelist = list_entry(pos, struct fb_modelist, list);
  1838. m = &modelist->mode;
  1839. fb_videomode_to_var(&var, m);
  1840. var.activate = FB_ACTIVATE_TEST;
  1841. err = fb_set_var(info, &var);
  1842. fb_var_to_videomode(&mode, &var);
  1843. if (err || !fb_mode_is_equal(m, &mode)) {
  1844. list_del(pos);
  1845. kfree(pos);
  1846. }
  1847. }
  1848.  
  1849. err = 1;
  1850.  
  1851. if (!list_empty(&info->modelist)) {
  1852. event.info = info;
  1853. err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
  1854. }
  1855.  
  1856. return err;
  1857. }
  1858.  
  1859. static char *video_options[FB_MAX] __read_mostly;
  1860. static int ofonly __read_mostly;
  1861.  
  1862. /**
  1863. * fb_get_options - get kernel boot parameters
  1864. * @name: framebuffer name as it would appear in
  1865. * the boot parameter line
  1866. * (video=<name>:<options>)
  1867. * @option: the option will be stored here
  1868. *
  1869. * NOTE: Needed to maintain backwards compatibility
  1870. */
  1871. int fb_get_options(char *name, char **option)
  1872. {
  1873. char *opt, *options = NULL;
  1874. int retval = 0;
  1875. int name_len = strlen(name), i;
  1876.  
  1877. if (name_len && ofonly && strncmp(name, "offb", 4))
  1878. retval = 1;
  1879.  
  1880. if (name_len && !retval) {
  1881. for (i = 0; i < FB_MAX; i++) {
  1882. if (video_options[i] == NULL)
  1883. continue;
  1884. if (!video_options[i][0])
  1885. continue;
  1886. opt = video_options[i];
  1887. if (!strncmp(name, opt, name_len) &&
  1888. opt[name_len] == ':')
  1889. options = opt + name_len + 1;
  1890. }
  1891. }
  1892. if (options && !strncmp(options, "off", 3))
  1893. retval = 1;
  1894.  
  1895. if (option)
  1896. *option = options;
  1897.  
  1898. return retval;
  1899. }
  1900.  
  1901. #ifndef MODULE
  1902. /**
  1903. * video_setup - process command line options
  1904. * @options: string of options
  1905. *
  1906. * Process command line options for frame buffer subsystem.
  1907. *
  1908. * NOTE: This function is a __setup and __init function.
  1909. * It only stores the options. Drivers have to call
  1910. * fb_get_options() as necessary.
  1911. *
  1912. * Returns zero.
  1913. *
  1914. */
  1915. static int __init video_setup(char *options)
  1916. {
  1917. int i, global = 0;
  1918.  
  1919. if (!options || !*options)
  1920. global = 1;
  1921.  
  1922. if (!global && !strncmp(options, "ofonly", 6)) {
  1923. ofonly = 1;
  1924. global = 1;
  1925. }
  1926.  
  1927. if (!global && !strchr(options, ':')) {
  1928. fb_mode_option = options;
  1929. global = 1;
  1930. }
  1931.  
  1932. if (!global) {
  1933. for (i = 0; i < FB_MAX; i++) {
  1934. if (video_options[i] == NULL) {
  1935. video_options[i] = options;
  1936. break;
  1937. }
  1938.  
  1939. }
  1940. }
  1941.  
  1942. return 1;
  1943. }
  1944. __setup("video=", video_setup);
  1945. #endif
  1946.  
  1947. /*
  1948. * Visible symbols for modules
  1949. */
  1950.  
  1951. EXPORT_SYMBOL(register_framebuffer);
  1952. EXPORT_SYMBOL(unregister_framebuffer);
  1953. EXPORT_SYMBOL(num_registered_fb);
  1954. EXPORT_SYMBOL(registered_fb);
  1955. EXPORT_SYMBOL(fb_show_logo);
  1956. EXPORT_SYMBOL(fb_set_var);
  1957. EXPORT_SYMBOL(fb_blank);
  1958. EXPORT_SYMBOL(fb_pan_display);
  1959. EXPORT_SYMBOL(fb_get_buffer_offset);
  1960. EXPORT_SYMBOL(fb_set_suspend);
  1961. EXPORT_SYMBOL(fb_get_options);
  1962.  
  1963. MODULE_LICENSE("GPL");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement