lfbvideo.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2014-2018 K. Lange
  5. *
  6. * Generic linear framebuffer driver.
  7. *
  8. * Supports several cases:
  9. * - Bochs/QEMU/VirtualBox "Bochs VBE" with modesetting.
  10. * - VMware SVGA with modesetting.
  11. * - Linear framebuffers set by the bootloader with no modesetting.
  12. */
  13. #include <kernel/system.h>
  14. #include <kernel/fs.h>
  15. #include <kernel/printf.h>
  16. #include <kernel/types.h>
  17. #include <kernel/logging.h>
  18. #include <kernel/pci.h>
  19. #include <kernel/boot.h>
  20. #include <kernel/args.h>
  21. #include <kernel/tokenize.h>
  22. #include <kernel/module.h>
  23. #include <kernel/video.h>
  24. #include <kernel/mod/procfs.h>
  25. #define PREFERRED_W 1024
  26. #define PREFERRED_H 768
  27. #define PREFERRED_VY 4096
  28. #define PREFERRED_B 32
  29. /* Exported to other modules */
  30. uint16_t lfb_resolution_x = 0;
  31. uint16_t lfb_resolution_y = 0;
  32. uint16_t lfb_resolution_b = 0;
  33. uint32_t lfb_resolution_s = 0;
  34. uint8_t * lfb_vid_memory = (uint8_t *)0xE0000000;
  35. const char * lfb_driver_name = NULL;
  36. static fs_node_t * lfb_device = NULL;
  37. static int lfb_init(char * c);
  38. /* Where to send display size change signals */
  39. static pid_t display_change_recipient = 0;
  40. /* Driver-specific modesetting function */
  41. static void (*lfb_resolution_impl)(uint16_t,uint16_t) = NULL;
  42. /* Called by ioctl on /dev/fb0 */
  43. void lfb_set_resolution(uint16_t x, uint16_t y) {
  44. if (lfb_resolution_impl) {
  45. lfb_resolution_impl(x,y);
  46. if (display_change_recipient) {
  47. send_signal(display_change_recipient, SIGWINEVENT, 1);
  48. debug_print(WARNING, "Telling %d to SIGWINEVENT", display_change_recipient);
  49. }
  50. }
  51. }
  52. /**
  53. * Framebuffer control ioctls.
  54. * Used by the compositor to get display sizes and by the
  55. * resolution changer to initiate modesetting.
  56. */
  57. static int ioctl_vid(fs_node_t * node, int request, void * argp) {
  58. switch (request) {
  59. case IO_VID_WIDTH:
  60. /* Get framebuffer width */
  61. validate(argp);
  62. *((size_t *)argp) = lfb_resolution_x;
  63. return 0;
  64. case IO_VID_HEIGHT:
  65. /* Get framebuffer height */
  66. validate(argp);
  67. *((size_t *)argp) = lfb_resolution_y;
  68. return 0;
  69. case IO_VID_DEPTH:
  70. /* Get framebuffer bit depth */
  71. validate(argp);
  72. *((size_t *)argp) = lfb_resolution_b;
  73. return 0;
  74. case IO_VID_STRIDE:
  75. /* Get framebuffer scanline stride */
  76. validate(argp);
  77. *((size_t *)argp) = lfb_resolution_s;
  78. return 0;
  79. case IO_VID_ADDR:
  80. /* Get framebuffer address - TODO: map the framebuffer? */
  81. validate(argp);
  82. *((uintptr_t *)argp) = (uintptr_t)lfb_vid_memory;
  83. return 0;
  84. case IO_VID_SIGNAL:
  85. /* ioctl to register for a signal (vid device change? idk) on display change */
  86. display_change_recipient = getpid();
  87. return 0;
  88. case IO_VID_SET:
  89. /* Initiate mode setting */
  90. validate(argp);
  91. lfb_set_resolution(((struct vid_size *)argp)->width, ((struct vid_size *)argp)->height);
  92. return 0;
  93. case IO_VID_DRIVER:
  94. validate(argp);
  95. memcpy(argp, lfb_driver_name, strlen(lfb_driver_name));
  96. return 0;
  97. case IO_VID_REINIT:
  98. if (current_process->user != 0) {
  99. return -EPERM;
  100. }
  101. validate(argp);
  102. return lfb_init(argp);
  103. default:
  104. return -EINVAL;
  105. }
  106. }
  107. /* Framebuffer device file initializer */
  108. static fs_node_t * lfb_video_device_create(void /* TODO */) {
  109. fs_node_t * fnode = malloc(sizeof(fs_node_t));
  110. memset(fnode, 0x00, sizeof(fs_node_t));
  111. sprintf(fnode->name, "fb0"); /* TODO */
  112. fnode->length = 0;
  113. fnode->flags = FS_BLOCKDEVICE; /* Framebuffers are block devices */
  114. fnode->mask = 0660; /* Only accessible to root user/group */
  115. fnode->ioctl = ioctl_vid; /* control function defined above */
  116. return fnode;
  117. }
  118. /**
  119. * Framebuffer fatal error presentation.
  120. *
  121. * This is called by a kernel hook to render fatal error messages
  122. * (panic / oops / bsod) to the graphraical framebuffer. Mostly,
  123. * that means the "out of memory" error. Bescause this is a fatal
  124. * error condition, we don't care much about speed, so we can do
  125. * silly things like ready from the framebuffer, which we do to
  126. * produce a vignetting and desaturation effect.
  127. */
  128. static int vignette_at(int x, int y) {
  129. int amount = 0;
  130. int level = 100;
  131. if (x < level) amount += (level - x);
  132. if (x > lfb_resolution_x - level) amount += (level - (lfb_resolution_x - x));
  133. if (y < level) amount += (level - y);
  134. if (y > lfb_resolution_y - level) amount += (level - (lfb_resolution_y - y));
  135. return amount;
  136. }
  137. #include "../apps/terminal-font.h"
  138. /* XXX Why is this not defined in the font header... */
  139. #define char_height 20
  140. #define char_width 9
  141. /* Set point in framebuffer */
  142. static void set_point(int x, int y, uint32_t value) {
  143. uint32_t * disp = (uint32_t *)lfb_vid_memory;
  144. uint32_t * cell = &disp[y * (lfb_resolution_s / 4) + x];
  145. *cell = value;
  146. }
  147. /* Draw text on framebuffer */
  148. static void write_char(int x, int y, int val, uint32_t color) {
  149. if (val > 128) {
  150. val = 4;
  151. }
  152. uint16_t * c = large_font[val];
  153. for (uint8_t i = 0; i < char_height; ++i) {
  154. for (uint8_t j = 0; j < char_width; ++j) {
  155. if (c[i] & (1 << (15-j))) {
  156. set_point(x+j,y+i,color);
  157. }
  158. }
  159. }
  160. }
  161. #define _RED(color) ((color & 0x00FF0000) / 0x10000)
  162. #define _GRE(color) ((color & 0x0000FF00) / 0x100)
  163. #define _BLU(color) ((color & 0x000000FF) / 0x1)
  164. #define _ALP(color) ((color & 0xFF000000) / 0x1000000)
  165. static void lfb_video_panic(char ** msgs) {
  166. /* Desaturate the display */
  167. uint32_t * disp = (uint32_t *)lfb_vid_memory;
  168. for (int y = 0; y < lfb_resolution_y; y++) {
  169. for (int x = 0; x < lfb_resolution_x; x++) {
  170. uint32_t * cell = &disp[y * (lfb_resolution_s / 4) + x];
  171. int r = _RED(*cell);
  172. int g = _GRE(*cell);
  173. int b = _BLU(*cell);
  174. int l = 3 * r + 6 * g + 1 * b;
  175. r = (l) / 10;
  176. g = (l) / 10;
  177. b = (l) / 10;
  178. r = r > 255 ? 255 : r;
  179. g = g > 255 ? 255 : g;
  180. b = b > 255 ? 255 : b;
  181. int amount = vignette_at(x,y);
  182. r = (r - amount < 0) ? 0 : r - amount;
  183. g = (g - amount < 0) ? 0 : g - amount;
  184. b = (b - amount < 0) ? 0 : b - amount;
  185. *cell = 0xFF000000 + ((0xFF & r) * 0x10000) + ((0xFF & g) * 0x100) + ((0xFF & b) * 0x1);
  186. }
  187. }
  188. /* Now print the message, divided on line feeds, into the center of the screen */
  189. int num_entries = 0;
  190. for (char ** m = msgs; *m; m++, num_entries++);
  191. int y = (lfb_resolution_y - (num_entries * char_height)) / 2;
  192. for (char ** message = msgs; *message; message++) {
  193. int x = (lfb_resolution_x - (strlen(*message) * char_width)) / 2;
  194. for (char * c = *message; *c; c++) {
  195. write_char(x+1, y+1, *c, 0xFF000000);
  196. write_char(x, y, *c, 0xFFFF0000);
  197. x += char_width;
  198. }
  199. y += char_height;
  200. }
  201. }
  202. static uint32_t framebuffer_func(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) {
  203. char * buf = malloc(4096);
  204. if (lfb_driver_name) {
  205. sprintf(buf,
  206. "Driver:\t%s\n"
  207. "XRes:\t%d\n"
  208. "YRes:\t%d\n"
  209. "BitsPerPixel:\t%d\n"
  210. "Stride:\t%d\n"
  211. "Address:\t0x%x\n",
  212. lfb_driver_name,
  213. lfb_resolution_x,
  214. lfb_resolution_y,
  215. lfb_resolution_b,
  216. lfb_resolution_s,
  217. lfb_vid_memory);
  218. } else {
  219. sprintf(buf, "Driver:\tnone\n");
  220. }
  221. size_t _bsize = strlen(buf);
  222. if (offset > _bsize) {
  223. free(buf);
  224. return 0;
  225. }
  226. if (size > _bsize - offset) size = _bsize - offset;
  227. memcpy(buffer, buf + offset, size);
  228. free(buf);
  229. return size;
  230. }
  231. static struct procfs_entry framebuffer_entry = {
  232. 0,
  233. "framebuffer",
  234. framebuffer_func,
  235. };
  236. /* Install framebuffer device */
  237. static void finalize_graphics(const char * driver) {
  238. lfb_driver_name = driver;
  239. lfb_device->length = lfb_resolution_s * lfb_resolution_y; /* Size is framebuffer size in bytes */
  240. debug_video_crash = lfb_video_panic;
  241. int (*procfs_install)(struct procfs_entry *) = (int (*)(struct procfs_entry *))(uintptr_t)hashmap_get(modules_get_symbols(),"procfs_install");
  242. if (procfs_install) {
  243. procfs_install(&framebuffer_entry);
  244. }
  245. }
  246. /* Bochs support {{{ */
  247. static void bochs_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) {
  248. if ((v == 0x1234 && d == 0x1111) ||
  249. (v == 0x80EE && d == 0xBEEF) ||
  250. (v == 0x10de && d == 0x0a20)) {
  251. uintptr_t t = pci_read_field(device, PCI_BAR0, 4);
  252. if (t > 0) {
  253. *((uint8_t **)extra) = (uint8_t *)(t & 0xFFFFFFF0);
  254. }
  255. }
  256. }
  257. static void bochs_set_resolution(uint16_t x, uint16_t y) {
  258. outports(0x1CE, 0x04);
  259. outports(0x1CF, 0x00);
  260. /* Uh oh, here we go. */
  261. outports(0x1CE, 0x01);
  262. outports(0x1CF, x);
  263. /* Set Y resolution to 768 */
  264. outports(0x1CE, 0x02);
  265. outports(0x1CF, y);
  266. /* Set bpp to 32 */
  267. outports(0x1CE, 0x03);
  268. outports(0x1CF, PREFERRED_B);
  269. /* Set Virtual Height to stuff */
  270. outports(0x1CE, 0x07);
  271. outports(0x1CF, PREFERRED_VY);
  272. /* Turn it back on */
  273. outports(0x1CE, 0x04);
  274. outports(0x1CF, 0x41);
  275. /* Read X to see if it's something else */
  276. outports(0x1CE, 0x01);
  277. uint16_t new_x = inports(0x1CF);
  278. if (x != new_x) {
  279. x = new_x;
  280. }
  281. lfb_resolution_x = x;
  282. lfb_resolution_s = x * 4;
  283. lfb_resolution_y = y;
  284. lfb_resolution_b = 32;
  285. }
  286. static void graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) {
  287. uint32_t vid_memsize;
  288. debug_print(NOTICE, "Setting up BOCHS/QEMU graphics controller...");
  289. outports(0x1CE, 0x00);
  290. uint16_t i = inports(0x1CF);
  291. if (i < 0xB0C0 || i > 0xB0C6) {
  292. return;
  293. }
  294. outports(0x1CF, 0xB0C4);
  295. i = inports(0x1CF);
  296. bochs_set_resolution(resolution_x, resolution_y);
  297. resolution_x = lfb_resolution_x; /* may have changed */
  298. pci_scan(bochs_scan_pci, -1, &lfb_vid_memory);
  299. lfb_resolution_impl = &bochs_set_resolution;
  300. if (!lfb_vid_memory) {
  301. debug_print(ERROR, "Failed to locate video memory.");
  302. return;
  303. }
  304. /* Enable the higher memory */
  305. uintptr_t fb_offset = (uintptr_t)lfb_vid_memory;
  306. for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) {
  307. page_t * p = get_page(i, 1, kernel_directory);
  308. dma_frame(p, 0, 1, i);
  309. p->pat = 1;
  310. p->writethrough = 1;
  311. p->cachedisable = 1;
  312. }
  313. outports(0x1CE, 0x0a);
  314. i = inports(0x1CF);
  315. if (i > 1) {
  316. vid_memsize = (uint32_t)i * 64 * 1024;
  317. } else {
  318. vid_memsize = inportl(0x1CF);
  319. }
  320. debug_print(WARNING, "Video memory size is 0x%x", vid_memsize);
  321. for (uintptr_t i = (uintptr_t)lfb_vid_memory; i <= (uintptr_t)lfb_vid_memory + vid_memsize; i += 0x1000) {
  322. dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
  323. }
  324. finalize_graphics("bochs");
  325. }
  326. static void graphics_install_preset(uint16_t w, uint16_t h) {
  327. if (!(mboot_ptr && (mboot_ptr->flags & (1 << 12)))) {
  328. debug_print(ERROR, "Failed to locate preset video memory - missing multiboot header.");
  329. return;
  330. }
  331. /* Extract framebuffer information from multiboot */
  332. lfb_vid_memory = (void *)mboot_ptr->framebuffer_addr;
  333. lfb_resolution_x = mboot_ptr->framebuffer_width;
  334. lfb_resolution_y = mboot_ptr->framebuffer_height;
  335. lfb_resolution_s = mboot_ptr->framebuffer_pitch;
  336. lfb_resolution_b = 32;
  337. debug_print(WARNING, "Mode was set by bootloader: %dx%d bpp should be 32, framebuffer is at 0x%x", w, h, (uintptr_t)lfb_vid_memory);
  338. for (uintptr_t i = (uintptr_t)lfb_vid_memory; i <= (uintptr_t)lfb_vid_memory + w * h * 4; i += 0x1000) {
  339. page_t * p = get_page(i, 1, kernel_directory);
  340. dma_frame(p, 0, 1, i);
  341. p->pat = 1;
  342. p->writethrough = 1;
  343. p->cachedisable = 1;
  344. }
  345. finalize_graphics("preset");
  346. }
  347. static void graphics_install_kludge(uint16_t w, uint16_t h) {
  348. uint32_t * herp = (uint32_t *)0xA0000;
  349. herp[0] = 0xA5ADFACE;
  350. herp[1] = 0xFAF42943;
  351. for (int i = 2; i < 1000; i += 2) {
  352. herp[i] = 0xFF00FF00;
  353. herp[i+1] = 0x00FF00FF;
  354. }
  355. for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) {
  356. /* Enable the higher memory */
  357. for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) {
  358. dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
  359. }
  360. /* Go find it */
  361. for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) {
  362. if (((uintptr_t *)x)[0] == 0xA5ADFACE && ((uintptr_t *)x)[1] == 0xFAF42943) {
  363. lfb_vid_memory = (uint8_t *)x;
  364. debug_print(INFO, "Had to futz around, but found video memory at 0x%x", lfb_vid_memory);
  365. goto mem_found;
  366. }
  367. }
  368. }
  369. mem_found:
  370. lfb_resolution_x = w;
  371. lfb_resolution_y = h;
  372. lfb_resolution_s = w * 4;
  373. lfb_resolution_b = 32;
  374. for (uintptr_t i = (uintptr_t)lfb_vid_memory; i <= (uintptr_t)lfb_vid_memory + w * h * 4; i += 0x1000) {
  375. page_t * p = get_page(i, 1, kernel_directory);
  376. dma_frame(p, 0, 1, i);
  377. p->pat = 1;
  378. p->writethrough = 1;
  379. p->cachedisable = 1;
  380. }
  381. finalize_graphics("kludge");
  382. }
  383. #define SVGA_IO_BASE (vmware_io)
  384. #define SVGA_IO_MUL 1
  385. #define SVGA_INDEX_PORT 0
  386. #define SVGA_VALUE_PORT 1
  387. #define SVGA_REG_ID 0
  388. #define SVGA_REG_ENABLE 1
  389. #define SVGA_REG_WIDTH 2
  390. #define SVGA_REG_HEIGHT 3
  391. #define SVGA_REG_BITS_PER_PIXEL 7
  392. #define SVGA_REG_BYTES_PER_LINE 12
  393. #define SVGA_REG_FB_START 13
  394. static uint32_t vmware_io = 0;
  395. static void vmware_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) {
  396. if ((v == 0x15ad && d == 0x0405)) {
  397. uintptr_t t = pci_read_field(device, PCI_BAR0, 4);
  398. if (t > 0) {
  399. *((uint8_t **)extra) = (uint8_t *)(t & 0xFFFFFFF0);
  400. }
  401. }
  402. }
  403. static void vmware_write(int reg, int value) {
  404. outportl(SVGA_IO_MUL * SVGA_INDEX_PORT + SVGA_IO_BASE, reg);
  405. outportl(SVGA_IO_MUL * SVGA_VALUE_PORT + SVGA_IO_BASE, value);
  406. }
  407. static uint32_t vmware_read(int reg) {
  408. outportl(SVGA_IO_MUL * SVGA_INDEX_PORT + SVGA_IO_BASE, reg);
  409. return inportl(SVGA_IO_MUL * SVGA_VALUE_PORT + SVGA_IO_BASE);
  410. }
  411. static void vmware_set_resolution(uint16_t w, uint16_t h) {
  412. vmware_write(SVGA_REG_ENABLE, 0);
  413. vmware_write(SVGA_REG_ID, 0);
  414. vmware_write(SVGA_REG_WIDTH, w);
  415. vmware_write(SVGA_REG_HEIGHT, h);
  416. vmware_write(SVGA_REG_BITS_PER_PIXEL, 32);
  417. vmware_write(SVGA_REG_ENABLE, 1);
  418. uint32_t bpl = vmware_read(SVGA_REG_BYTES_PER_LINE);
  419. lfb_resolution_x = w;
  420. lfb_resolution_s = bpl;
  421. lfb_resolution_y = h;
  422. lfb_resolution_b = 32;
  423. }
  424. static void graphics_install_vmware(uint16_t w, uint16_t h) {
  425. pci_scan(vmware_scan_pci, -1, &vmware_io);
  426. if (!vmware_io) {
  427. debug_print(ERROR, "No vmware device found?");
  428. return;
  429. } else {
  430. debug_print(WARNING, "vmware io base: 0x%x", vmware_io);
  431. }
  432. vmware_set_resolution(w,h);
  433. lfb_resolution_impl = &vmware_set_resolution;
  434. uint32_t fb_addr = vmware_read(SVGA_REG_FB_START);
  435. debug_print(WARNING, "vmware fb address: 0x%x", fb_addr);
  436. uint32_t fb_size = vmware_read(15);
  437. debug_print(WARNING, "vmware fb size: 0x%x", fb_size);
  438. lfb_vid_memory = (uint8_t *)fb_addr;
  439. uintptr_t fb_offset = (uintptr_t)lfb_vid_memory;
  440. for (uintptr_t i = fb_offset; i <= fb_offset + fb_size; i += 0x1000) {
  441. page_t * p = get_page(i, 1, kernel_directory);
  442. dma_frame(p, 0, 1, i);
  443. p->pat = 1;
  444. p->writethrough = 1;
  445. p->cachedisable = 1;
  446. }
  447. finalize_graphics("vmware");
  448. }
  449. struct disp_mode {
  450. int16_t x;
  451. int16_t y;
  452. int set;
  453. };
  454. static void auto_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) {
  455. struct disp_mode * mode = extra;
  456. if (mode->set) return;
  457. if ((v == 0x1234 && d == 0x1111) ||
  458. (v == 0x80EE && d == 0xBEEF) ||
  459. (v == 0x10de && d == 0x0a20)) {
  460. mode->set = 1;
  461. graphics_install_bochs(mode->x, mode->y);
  462. } else if ((v == 0x15ad && d == 0x0405)) {
  463. mode->set = 1;
  464. graphics_install_vmware(mode->x, mode->y);
  465. }
  466. }
  467. static int lfb_init(char * c) {
  468. char * arg = strdup(c);
  469. char * argv[10];
  470. int argc = tokenize(arg, ",", argv);
  471. uint16_t x, y;
  472. if (argc < 3) {
  473. x = PREFERRED_W;
  474. y = PREFERRED_H;
  475. } else {
  476. x = atoi(argv[1]);
  477. y = atoi(argv[2]);
  478. }
  479. int ret_val = 0;
  480. if (!strcmp(argv[0], "auto")) {
  481. /* Attempt autodetection */
  482. debug_print(NOTICE, "Automatically detecting display driver...");
  483. struct disp_mode mode = {x,y,0};
  484. pci_scan(auto_scan_pci, -1, &mode);
  485. if (!mode.set) {
  486. graphics_install_preset(x,y);
  487. }
  488. } else if (!strcmp(argv[0], "qemu")) {
  489. /* Bochs / Qemu Video Device */
  490. graphics_install_bochs(x,y);
  491. } else if (!strcmp(argv[0],"vmware")) {
  492. /* VMware SVGA */
  493. graphics_install_vmware(x,y);
  494. } else if (!strcmp(argv[0],"preset")) {
  495. /* Set by bootloader (UEFI) */
  496. graphics_install_preset(x,y);
  497. } else if (!strcmp(argv[0],"kludge")) {
  498. /* Old hack to find vid memory from the VGA window */
  499. graphics_install_kludge(x,y);
  500. } else {
  501. debug_print(WARNING, "Unrecognized video adapter: %s", argv[0]);
  502. ret_val = 1;
  503. }
  504. free(arg);
  505. return ret_val;
  506. }
  507. static int init(void) {
  508. if (mboot_ptr->vbe_mode_info) {
  509. lfb_vid_memory = (uint8_t *)((vbe_info_t *)(mboot_ptr->vbe_mode_info))->physbase;
  510. }
  511. lfb_device = lfb_video_device_create();
  512. vfs_mount("/dev/fb0", lfb_device);
  513. char * c;
  514. if ((c = args_value("vid"))) {
  515. debug_print(NOTICE, "Video mode requested: %s", c);
  516. lfb_init(c);
  517. }
  518. return 0;
  519. }
  520. static int fini(void) {
  521. return 0;
  522. }
  523. MODULE_DEF(lfbvideo, init, fini);