bochs_fbdev.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * This program is free software; you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License as published by
  4. * the Free Software Foundation; either version 2 of the License, or
  5. * (at your option) any later version.
  6. */
  7. #include "bochs.h"
  8. /* ---------------------------------------------------------------------- */
  9. static struct fb_ops bochsfb_ops = {
  10. .owner = THIS_MODULE,
  11. .fb_check_var = drm_fb_helper_check_var,
  12. .fb_set_par = drm_fb_helper_set_par,
  13. .fb_fillrect = sys_fillrect,
  14. .fb_copyarea = sys_copyarea,
  15. .fb_imageblit = sys_imageblit,
  16. .fb_pan_display = drm_fb_helper_pan_display,
  17. .fb_blank = drm_fb_helper_blank,
  18. .fb_setcmap = drm_fb_helper_setcmap,
  19. };
  20. static int bochsfb_create_object(struct bochs_device *bochs,
  21. struct drm_mode_fb_cmd2 *mode_cmd,
  22. struct drm_gem_object **gobj_p)
  23. {
  24. struct drm_device *dev = bochs->dev;
  25. struct drm_gem_object *gobj;
  26. u32 size;
  27. int ret = 0;
  28. size = mode_cmd->pitches[0] * mode_cmd->height;
  29. ret = bochs_gem_create(dev, size, true, &gobj);
  30. if (ret)
  31. return ret;
  32. *gobj_p = gobj;
  33. return ret;
  34. }
  35. static int bochsfb_create(struct drm_fb_helper *helper,
  36. struct drm_fb_helper_surface_size *sizes)
  37. {
  38. struct bochs_device *bochs =
  39. container_of(helper, struct bochs_device, fb.helper);
  40. struct drm_device *dev = bochs->dev;
  41. struct fb_info *info;
  42. struct drm_framebuffer *fb;
  43. struct drm_mode_fb_cmd2 mode_cmd;
  44. struct device *device = &dev->pdev->dev;
  45. struct drm_gem_object *gobj = NULL;
  46. struct bochs_bo *bo = NULL;
  47. int size, ret;
  48. if (sizes->surface_bpp != 32)
  49. return -EINVAL;
  50. mode_cmd.width = sizes->surface_width;
  51. mode_cmd.height = sizes->surface_height;
  52. mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
  53. mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
  54. sizes->surface_depth);
  55. size = mode_cmd.pitches[0] * mode_cmd.height;
  56. /* alloc, pin & map bo */
  57. ret = bochsfb_create_object(bochs, &mode_cmd, &gobj);
  58. if (ret) {
  59. DRM_ERROR("failed to create fbcon backing object %d\n", ret);
  60. return ret;
  61. }
  62. bo = gem_to_bochs_bo(gobj);
  63. ret = ttm_bo_reserve(&bo->bo, true, false, false, 0);
  64. if (ret)
  65. return ret;
  66. ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
  67. if (ret) {
  68. DRM_ERROR("failed to pin fbcon\n");
  69. ttm_bo_unreserve(&bo->bo);
  70. return ret;
  71. }
  72. ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages,
  73. &bo->kmap);
  74. if (ret) {
  75. DRM_ERROR("failed to kmap fbcon\n");
  76. ttm_bo_unreserve(&bo->bo);
  77. return ret;
  78. }
  79. ttm_bo_unreserve(&bo->bo);
  80. /* init fb device */
  81. info = framebuffer_alloc(0, device);
  82. if (info == NULL)
  83. return -ENOMEM;
  84. info->par = &bochs->fb.helper;
  85. ret = bochs_framebuffer_init(bochs->dev, &bochs->fb.gfb, &mode_cmd, gobj);
  86. if (ret)
  87. return ret;
  88. bochs->fb.size = size;
  89. /* setup helper */
  90. fb = &bochs->fb.gfb.base;
  91. bochs->fb.helper.fb = fb;
  92. bochs->fb.helper.fbdev = info;
  93. strcpy(info->fix.id, "bochsdrmfb");
  94. info->flags = FBINFO_DEFAULT;
  95. info->fbops = &bochsfb_ops;
  96. drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
  97. drm_fb_helper_fill_var(info, &bochs->fb.helper, sizes->fb_width,
  98. sizes->fb_height);
  99. info->screen_base = bo->kmap.virtual;
  100. info->screen_size = size;
  101. #if 0
  102. /* FIXME: get this right for mmap(/dev/fb0) */
  103. info->fix.smem_start = bochs_bo_mmap_offset(bo);
  104. info->fix.smem_len = size;
  105. #endif
  106. ret = fb_alloc_cmap(&info->cmap, 256, 0);
  107. if (ret) {
  108. DRM_ERROR("%s: can't allocate color map\n", info->fix.id);
  109. return -ENOMEM;
  110. }
  111. return 0;
  112. }
  113. static int bochs_fbdev_destroy(struct bochs_device *bochs)
  114. {
  115. struct bochs_framebuffer *gfb = &bochs->fb.gfb;
  116. struct fb_info *info;
  117. DRM_DEBUG_DRIVER("\n");
  118. if (bochs->fb.helper.fbdev) {
  119. info = bochs->fb.helper.fbdev;
  120. unregister_framebuffer(info);
  121. if (info->cmap.len)
  122. fb_dealloc_cmap(&info->cmap);
  123. framebuffer_release(info);
  124. }
  125. if (gfb->obj) {
  126. drm_gem_object_unreference_unlocked(gfb->obj);
  127. gfb->obj = NULL;
  128. }
  129. drm_fb_helper_fini(&bochs->fb.helper);
  130. drm_framebuffer_unregister_private(&gfb->base);
  131. drm_framebuffer_cleanup(&gfb->base);
  132. return 0;
  133. }
  134. void bochs_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
  135. u16 blue, int regno)
  136. {
  137. }
  138. void bochs_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
  139. u16 *blue, int regno)
  140. {
  141. *red = regno;
  142. *green = regno;
  143. *blue = regno;
  144. }
  145. static struct drm_fb_helper_funcs bochs_fb_helper_funcs = {
  146. .gamma_set = bochs_fb_gamma_set,
  147. .gamma_get = bochs_fb_gamma_get,
  148. .fb_probe = bochsfb_create,
  149. };
  150. int bochs_fbdev_init(struct bochs_device *bochs)
  151. {
  152. int ret;
  153. bochs->fb.helper.funcs = &bochs_fb_helper_funcs;
  154. ret = drm_fb_helper_init(bochs->dev, &bochs->fb.helper,
  155. 1, 1);
  156. if (ret)
  157. return ret;
  158. drm_fb_helper_single_add_all_connectors(&bochs->fb.helper);
  159. drm_helper_disable_unused_functions(bochs->dev);
  160. drm_fb_helper_initial_config(&bochs->fb.helper, 32);
  161. bochs->fb.initialized = true;
  162. return 0;
  163. }
  164. void bochs_fbdev_fini(struct bochs_device *bochs)
  165. {
  166. if (!bochs->fb.initialized)
  167. return;
  168. bochs_fbdev_destroy(bochs);
  169. bochs->fb.initialized = false;
  170. }