Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / os-support / bus / Sbus.c
CommitLineData
a09e091a
JB
1/*
2 * SBUS and OpenPROM access functions.
3 *
4 * Copyright (C) 2000 Jakub Jelinek (jakub@redhat.com)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * JAKUB JELINEK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#ifdef HAVE_XORG_CONFIG_H
25#include <xorg-config.h>
26#endif
27
28#include <fcntl.h>
29#include <stdio.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <sys/ioctl.h>
33#include <sys/mman.h>
34#ifdef sun
35#include <sys/utsname.h>
36#endif
37#include "xf86.h"
38#include "xf86Priv.h"
39#include "xf86_OSlib.h"
40
41#include "xf86sbusBus.h"
42#include "xf86Sbus.h"
43
44int promRootNode;
45
46static int promFd = -1;
47static int promCurrentNode;
48static int promOpenCount = 0;
49static int promP1275 = -1;
50
51#define MAX_PROP 128
52#define MAX_VAL (4096-128-4)
53static struct openpromio *promOpio;
54
55sbusDevicePtr *xf86SbusInfo = NULL;
56
57struct sbus_devtable sbusDeviceTable[] = {
58 {SBUS_DEVICE_BW2, FBTYPE_SUN2BW, "bwtwo", "sunbw2",
59 "Sun Monochrome (bwtwo)"},
60 {SBUS_DEVICE_CG2, FBTYPE_SUN2COLOR, "cgtwo", NULL, "Sun Color2 (cgtwo)"},
61 {SBUS_DEVICE_CG3, FBTYPE_SUN3COLOR, "cgthree", "suncg3",
62 "Sun Color3 (cgthree)"},
63 {SBUS_DEVICE_CG4, FBTYPE_SUN4COLOR, "cgfour", NULL, "Sun Color4 (cgfour)"},
64 {SBUS_DEVICE_CG6, FBTYPE_SUNFAST_COLOR, "cgsix", "suncg6", "Sun GX"},
65 {SBUS_DEVICE_CG8, FBTYPE_MEMCOLOR, "cgeight", NULL, "Sun CG8/RasterOps"},
66 {SBUS_DEVICE_CG12, FBTYPE_SUNGP3, "cgtwelve", NULL, "Sun GS (cgtwelve)"},
67 {SBUS_DEVICE_CG14, FBTYPE_MDICOLOR, "cgfourteen", "suncg14", "Sun SX"},
68 {SBUS_DEVICE_GT, FBTYPE_SUNGT, "gt", NULL, "Sun Graphics Tower"},
69 {SBUS_DEVICE_MGX, -1, "mgx", NULL, "Quantum 3D MGXplus"},
70 {SBUS_DEVICE_LEO, FBTYPE_SUNLEO, "leo", "sunleo", "Sun ZX or Turbo ZX"},
71 {SBUS_DEVICE_TCX, FBTYPE_TCXCOLOR, "tcx", "suntcx", "Sun TCX"},
72 {SBUS_DEVICE_FFB, FBTYPE_CREATOR, "ffb", "sunffb", "Sun FFB"},
73 {SBUS_DEVICE_FFB, FBTYPE_CREATOR, "afb", "sunffb", "Sun Elite3D"},
74 {0, 0, NULL}
75};
76
77int
78promGetSibling(int node)
79{
80 promOpio->oprom_size = sizeof(int);
81
82 if (node == -1)
83 return 0;
84 *(int *) promOpio->oprom_array = node;
85 if (ioctl(promFd, OPROMNEXT, promOpio) < 0)
86 return 0;
87 promCurrentNode = *(int *) promOpio->oprom_array;
88 return *(int *) promOpio->oprom_array;
89}
90
91int
92promGetChild(int node)
93{
94 promOpio->oprom_size = sizeof(int);
95
96 if (!node || node == -1)
97 return 0;
98 *(int *) promOpio->oprom_array = node;
99 if (ioctl(promFd, OPROMCHILD, promOpio) < 0)
100 return 0;
101 promCurrentNode = *(int *) promOpio->oprom_array;
102 return *(int *) promOpio->oprom_array;
103}
104
105char *
106promGetProperty(const char *prop, int *lenp)
107{
108 promOpio->oprom_size = MAX_VAL;
109
110 strcpy(promOpio->oprom_array, prop);
111 if (ioctl(promFd, OPROMGETPROP, promOpio) < 0)
112 return 0;
113 if (lenp)
114 *lenp = promOpio->oprom_size;
115 return promOpio->oprom_array;
116}
117
118int
119promGetBool(const char *prop)
120{
121 promOpio->oprom_size = 0;
122
123 *(int *) promOpio->oprom_array = 0;
124 for (;;) {
125 promOpio->oprom_size = MAX_PROP;
126 if (ioctl(promFd, OPROMNXTPROP, promOpio) < 0)
127 return 0;
128 if (!promOpio->oprom_size)
129 return 0;
130 if (!strcmp(promOpio->oprom_array, prop))
131 return 1;
132 }
133}
134
135#define PROM_NODE_SIBLING 0x01
136#define PROM_NODE_PREF 0x02
137#define PROM_NODE_SBUS 0x04
138#define PROM_NODE_EBUS 0x08
139#define PROM_NODE_PCI 0x10
140
141static int
142promSetNode(sbusPromNodePtr pnode)
143{
144 int node;
145
146 if (!pnode->node || pnode->node == -1)
147 return -1;
148 if (pnode->cookie[0] & PROM_NODE_SIBLING)
149 node = promGetSibling(pnode->cookie[1]);
150 else
151 node = promGetChild(pnode->cookie[1]);
152 if (pnode->node != node)
153 return -1;
154 return 0;
155}
156
157static void
158promIsP1275(void)
159{
160#ifdef linux
161 FILE *f;
162 char buffer[1024];
163
164 if (promP1275 != -1)
165 return;
166 promP1275 = 0;
167 f = fopen("/proc/cpuinfo", "r");
168 if (!f)
169 return;
170 while (fgets(buffer, 1024, f) != NULL)
171 if (!strncmp(buffer, "type", 4) && strstr(buffer, "sun4u")) {
172 promP1275 = 1;
173 break;
174 }
175 fclose(f);
176#elif defined(sun)
177 struct utsname buffer;
178
179 if ((uname(&buffer) >= 0) && !strcmp(buffer.machine, "sun4u"))
180 promP1275 = TRUE;
181 else
182 promP1275 = FALSE;
183#elif defined(__FreeBSD__)
184 promP1275 = TRUE;
185#else
186#error Missing promIsP1275() function for this OS
187#endif
188}
189
190void
191sparcPromClose(void)
192{
193 if (promOpenCount > 1) {
194 promOpenCount--;
195 return;
196 }
197 if (promFd != -1) {
198 close(promFd);
199 promFd = -1;
200 }
201 free(promOpio);
202 promOpio = NULL;
203 promOpenCount = 0;
204}
205
206int
207sparcPromInit(void)
208{
209 if (promOpenCount) {
210 promOpenCount++;
211 return 0;
212 }
213 promFd = open("/dev/openprom", O_RDONLY, 0);
214 if (promFd == -1)
215 return -1;
216 promOpio = (struct openpromio *) malloc(4096);
217 if (!promOpio) {
218 sparcPromClose();
219 return -1;
220 }
221 promRootNode = promGetSibling(0);
222 if (!promRootNode) {
223 sparcPromClose();
224 return -1;
225 }
226 promIsP1275();
227 promOpenCount++;
228
229 return 0;
230}
231
232char *
233sparcPromGetProperty(sbusPromNodePtr pnode, const char *prop, int *lenp)
234{
235 if (promSetNode(pnode))
236 return NULL;
237 return promGetProperty(prop, lenp);
238}
239
240int
241sparcPromGetBool(sbusPromNodePtr pnode, const char *prop)
242{
243 if (promSetNode(pnode))
244 return 0;
245 return promGetBool(prop);
246}
247
248static char *
249promWalkGetDriverName(int node, int oldnode)
250{
251 int nextnode;
252 int len;
253 char *prop;
254 int devId, i;
255
256 prop = promGetProperty("device_type", &len);
257 if (prop && (len > 0))
258 do {
259 if (!strcmp(prop, "display")) {
260 prop = promGetProperty("name", &len);
261 if (!prop || len <= 0)
262 break;
263 while ((*prop >= 'A' && *prop <= 'Z') || *prop == ',')
264 prop++;
265 for (i = 0; sbusDeviceTable[i].devId; i++)
266 if (!strcmp(prop, sbusDeviceTable[i].promName))
267 break;
268 devId = sbusDeviceTable[i].devId;
269 if (!devId)
270 break;
271 if (sbusDeviceTable[i].driverName)
272 return sbusDeviceTable[i].driverName;
273 }
274 } while (0);
275
276 nextnode = promGetChild(node);
277 if (nextnode) {
278 char *name;
279
280 name = promWalkGetDriverName(nextnode, node);
281 if (name)
282 return name;
283 }
284
285 nextnode = promGetSibling(node);
286 if (nextnode)
287 return promWalkGetDriverName(nextnode, node);
288 return NULL;
289}
290
291char *
292sparcDriverName(void)
293{
294 char *name;
295
296 if (sparcPromInit() < 0)
297 return NULL;
298 promGetSibling(0);
299 name = promWalkGetDriverName(promRootNode, 0);
300 sparcPromClose();
301 return name;
302}
303
304static void
305promWalkAssignNodes(int node, int oldnode, int flags,
306 sbusDevicePtr * devicePtrs)
307{
308 int nextnode;
309 int len, sbus = flags & PROM_NODE_SBUS;
310 char *prop;
311 int devId, i, j;
312 sbusPromNode pNode, pNode2;
313
314 prop = promGetProperty("device_type", &len);
315 if (prop && (len > 0))
316 do {
317 if (!strcmp(prop, "display")) {
318 prop = promGetProperty("name", &len);
319 if (!prop || len <= 0)
320 break;
321 while ((*prop >= 'A' && *prop <= 'Z') || *prop == ',')
322 prop++;
323 for (i = 0; sbusDeviceTable[i].devId; i++)
324 if (!strcmp(prop, sbusDeviceTable[i].promName))
325 break;
326 devId = sbusDeviceTable[i].devId;
327 if (!devId)
328 break;
329 if (!sbus) {
330 if (devId == SBUS_DEVICE_FFB) {
331 /*
332 * All /SUNW,ffb outside of SBUS tree come before all
333 * /SUNW,afb outside of SBUS tree in Linux.
334 */
335 if (!strcmp(prop, "afb"))
336 flags |= PROM_NODE_PREF;
337 }
338 else if (devId != SBUS_DEVICE_CG14)
339 break;
340 }
341 for (i = 0; i < 32; i++) {
342 if (!devicePtrs[i] || devicePtrs[i]->devId != devId)
343 continue;
344 if (devicePtrs[i]->node.node) {
345 if ((devicePtrs[i]->node.
346 cookie[0] & ~PROM_NODE_SIBLING) <=
347 (flags & ~PROM_NODE_SIBLING))
348 continue;
349 for (j = i + 1, pNode = devicePtrs[i]->node; j < 32;
350 j++) {
351 if (!devicePtrs[j] || devicePtrs[j]->devId != devId)
352 continue;
353 pNode2 = devicePtrs[j]->node;
354 devicePtrs[j]->node = pNode;
355 pNode = pNode2;
356 }
357 }
358 devicePtrs[i]->node.node = node;
359 devicePtrs[i]->node.cookie[0] = flags;
360 devicePtrs[i]->node.cookie[1] = oldnode;
361 break;
362 }
363 break;
364 }
365 } while (0);
366
367 prop = promGetProperty("name", &len);
368 if (prop && len > 0) {
369 if (!strcmp(prop, "sbus") || !strcmp(prop, "sbi"))
370 sbus = PROM_NODE_SBUS;
371 }
372
373 nextnode = promGetChild(node);
374 if (nextnode)
375 promWalkAssignNodes(nextnode, node, sbus, devicePtrs);
376
377 nextnode = promGetSibling(node);
378 if (nextnode)
379 promWalkAssignNodes(nextnode, node, PROM_NODE_SIBLING | sbus,
380 devicePtrs);
381}
382
383void
384sparcPromAssignNodes(void)
385{
386 sbusDevicePtr psdp, *psdpp;
387 int n, holes = 0, i, j;
388 FILE *f;
389 sbusDevicePtr devicePtrs[32];
390
391 memset(devicePtrs, 0, sizeof(devicePtrs));
392 for (psdpp = xf86SbusInfo, n = 0; (psdp = *psdpp); psdpp++, n++) {
393 if (psdp->fbNum != n)
394 holes = 1;
395 devicePtrs[psdp->fbNum] = psdp;
396 }
397 if (holes && (f = fopen("/proc/fb", "r")) != NULL) {
398 /* We could not open one of fb devices, check /proc/fb to see what
399 * were the types of the cards missed. */
400 char buffer[64];
401 int fbNum, devId;
402 static struct {
403 int devId;
404 char *prefix;
405 } procFbPrefixes[] = {
406 {SBUS_DEVICE_BW2, "BWtwo"},
407 {SBUS_DEVICE_CG14, "CGfourteen"},
408 {SBUS_DEVICE_CG6, "CGsix"},
409 {SBUS_DEVICE_CG3, "CGthree"},
410 {SBUS_DEVICE_FFB, "Creator"},
411 {SBUS_DEVICE_FFB, "Elite 3D"},
412 {SBUS_DEVICE_LEO, "Leo"},
413 {SBUS_DEVICE_TCX, "TCX"},
414 {0, NULL},
415 };
416
417 while (fscanf(f, "%d %63s\n", &fbNum, buffer) == 2) {
418 for (i = 0; procFbPrefixes[i].devId; i++)
419 if (!strncmp(procFbPrefixes[i].prefix, buffer,
420 strlen(procFbPrefixes[i].prefix)))
421 break;
422 devId = procFbPrefixes[i].devId;
423 if (!devId)
424 continue;
425 if (devicePtrs[fbNum]) {
426 if (devicePtrs[fbNum]->devId != devId)
427 xf86ErrorF("Inconsistent /proc/fb with FBIOGATTR\n");
428 }
429 else if (!devicePtrs[fbNum]) {
430 devicePtrs[fbNum] = psdp = xnfcalloc(sizeof(sbusDevice), 1);
431 psdp->devId = devId;
432 psdp->fbNum = fbNum;
433 psdp->fd = -2;
434 }
435 }
436 fclose(f);
437 }
438 promGetSibling(0);
439 promWalkAssignNodes(promRootNode, 0, PROM_NODE_PREF, devicePtrs);
440 for (i = 0, j = 0; i < 32; i++)
441 if (devicePtrs[i] && devicePtrs[i]->fbNum == -1)
442 j++;
443 xf86SbusInfo = xnfrealloc(xf86SbusInfo, sizeof(psdp) * (n + j + 1));
444 for (i = 0, psdpp = xf86SbusInfo; i < 32; i++)
445 if (devicePtrs[i]) {
446 if (devicePtrs[i]->fbNum == -1) {
447 memmove(psdpp + 1, psdpp, sizeof(psdpp) * (n + 1));
448 *psdpp = devicePtrs[i];
449 }
450 else
451 n--;
452 }
453}
454
455static char *
456promGetReg(int type)
457{
458 char *prop;
459 int len;
460 static char regstr[40];
461
462 regstr[0] = 0;
463 prop = promGetProperty("reg", &len);
464 if (prop && len >= 4) {
465 unsigned int *reg = (unsigned int *) prop;
466
467 if (!promP1275 || (type == PROM_NODE_SBUS) || (type == PROM_NODE_EBUS))
468 snprintf(regstr, sizeof(regstr), "@%x,%x", reg[0], reg[1]);
469 else if (type == PROM_NODE_PCI) {
470 if ((reg[0] >> 8) & 7)
471 snprintf(regstr, sizeof(regstr), "@%x,%x",
472 (reg[0] >> 11) & 0x1f, (reg[0] >> 8) & 7);
473 else
474 snprintf(regstr, sizeof(regstr), "@%x", (reg[0] >> 11) & 0x1f);
475 }
476 else if (len == 4)
477 snprintf(regstr, sizeof(regstr), "@%x", reg[0]);
478 else {
479 unsigned int regs[2];
480
481 /* Things get more complicated on UPA. If upa-portid exists,
482 then address is @upa-portid,second-int-in-reg, otherwise
483 it is @first-int-in-reg/16,second-int-in-reg (well, probably
484 upa-portid always exists, but just to be safe). */
485 memcpy(regs, reg, sizeof(regs));
486 prop = promGetProperty("upa-portid", &len);
487 if (prop && len == 4) {
488 reg = (unsigned int *) prop;
489 snprintf(regstr, sizeof(regstr), "@%x,%x", reg[0], regs[1]);
490 }
491 else
492 snprintf(regstr, sizeof(regstr), "@%x,%x", regs[0] >> 4,
493 regs[1]);
494 }
495 }
496 return regstr;
497}
498
499static int
500promWalkNode2Pathname(char *path, int parent, int node, int searchNode,
501 int type)
502{
503 int nextnode;
504 int len, ntype = type;
505 char *prop, *p;
506
507 prop = promGetProperty("name", &len);
508 *path = '/';
509 if (!prop || len <= 0)
510 return 0;
511 if ((!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) && !type)
512 ntype = PROM_NODE_SBUS;
513 else if (!strcmp(prop, "ebus") && type == PROM_NODE_PCI)
514 ntype = PROM_NODE_EBUS;
515 else if (!strcmp(prop, "pci") && !type)
516 ntype = PROM_NODE_PCI;
517 strcpy(path + 1, prop);
518 p = promGetReg(type);
519 if (*p)
520 strcat(path, p);
521 if (node == searchNode)
522 return 1;
523 nextnode = promGetChild(node);
524 if (nextnode &&
525 promWalkNode2Pathname(strchr(path, 0), node, nextnode, searchNode,
526 ntype))
527 return 1;
528 nextnode = promGetSibling(node);
529 if (nextnode &&
530 promWalkNode2Pathname(path, parent, nextnode, searchNode, type))
531 return 1;
532 return 0;
533}
534
535char *
536sparcPromNode2Pathname(sbusPromNodePtr pnode)
537{
538 char *ret;
539
540 if (!pnode->node)
541 return NULL;
542 ret = malloc(4096);
543 if (!ret)
544 return NULL;
545 if (promWalkNode2Pathname
546 (ret, promRootNode, promGetChild(promRootNode), pnode->node, 0))
547 return ret;
548 free(ret);
549 return NULL;
550}
551
552static int
553promWalkPathname2Node(char *name, char *regstr, int parent, int type)
554{
555 int len, node, ret;
556 char *prop, *p;
557
558 for (;;) {
559 prop = promGetProperty("name", &len);
560 if (!prop || len <= 0)
561 return 0;
562 if ((!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) && !type)
563 type = PROM_NODE_SBUS;
564 else if (!strcmp(prop, "ebus") && type == PROM_NODE_PCI)
565 type = PROM_NODE_EBUS;
566 else if (!strcmp(prop, "pci") && !type)
567 type = PROM_NODE_PCI;
568 for (node = promGetChild(parent); node; node = promGetSibling(node)) {
569 prop = promGetProperty("name", &len);
570 if (!prop || len <= 0)
571 continue;
572 if (*name && strcmp(name, prop))
573 continue;
574 if (*regstr) {
575 p = promGetReg(type);
576 if (!*p || strcmp(p + 1, regstr))
577 continue;
578 }
579 break;
580 }
581 if (!node) {
582 for (node = promGetChild(parent); node; node = promGetSibling(node)) {
583 ret = promWalkPathname2Node(name, regstr, node, type);
584 if (ret)
585 return ret;
586 }
587 return 0;
588 }
589 name = strchr(regstr, 0) + 1;
590 if (!*name)
591 return node;
592 p = strchr(name, '/');
593 if (p)
594 *p = 0;
595 else
596 p = strchr(name, 0);
597 regstr = strchr(name, '@');
598 if (regstr)
599 *regstr++ = 0;
600 else
601 regstr = p;
602 if (name == regstr)
603 return 0;
604 parent = node;
605 }
606}
607
608int
609sparcPromPathname2Node(const char *pathName)
610{
611 int i;
612 char *name, *regstr, *p;
613
614 i = strlen(pathName);
615 name = malloc(i + 2);
616 if (!name)
617 return 0;
618 strcpy(name, pathName);
619 name[i + 1] = 0;
620 if (name[0] != '/') {
621 free(name);
622 return 0;
623 }
624 p = strchr(name + 1, '/');
625 if (p)
626 *p = 0;
627 else
628 p = strchr(name, 0);
629 regstr = strchr(name, '@');
630 if (regstr)
631 *regstr++ = 0;
632 else
633 regstr = p;
634 if (name + 1 == regstr) {
635 free(name);
636 return 0;
637 }
638 promGetSibling(0);
639 i = promWalkPathname2Node(name + 1, regstr, promRootNode, 0);
640 free(name);
641 return i;
642}
643
644pointer
645xf86MapSbusMem(sbusDevicePtr psdp, unsigned long offset, unsigned long size)
646{
647 pointer ret;
648 unsigned long pagemask = getpagesize() - 1;
649 unsigned long off = offset & ~pagemask;
650 unsigned long len = ((offset + size + pagemask) & ~pagemask) - off;
651
652 if (psdp->fd == -1) {
653 psdp->fd = open(psdp->device, O_RDWR);
654 if (psdp->fd == -1)
655 return NULL;
656 }
657 else if (psdp->fd < 0)
658 return NULL;
659
660 ret = (pointer) mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE,
661 psdp->fd, off);
662 if (ret == (pointer) -1) {
663 ret = (pointer) mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED,
664 psdp->fd, off);
665 }
666 if (ret == (pointer) -1)
667 return NULL;
668
669 return (char *) ret + (offset - off);
670}
671
672void
673xf86UnmapSbusMem(sbusDevicePtr psdp, pointer addr, unsigned long size)
674{
675 unsigned long mask = getpagesize() - 1;
676 unsigned long base = (unsigned long) addr & ~mask;
677 unsigned long len = (((unsigned long) addr + size + mask) & ~mask) - base;
678
679 munmap((pointer) base, len);
680}
681
682/* Tell OS that we are driving the HW cursor ourselves. */
683void
684xf86SbusHideOsHwCursor(sbusDevicePtr psdp)
685{
686 struct fbcursor fbcursor;
687 unsigned char zeros[8];
688
689 memset(&fbcursor, 0, sizeof(fbcursor));
690 memset(&zeros, 0, sizeof(zeros));
691 fbcursor.cmap.count = 2;
692 fbcursor.cmap.red = zeros;
693 fbcursor.cmap.green = zeros;
694 fbcursor.cmap.blue = zeros;
695 fbcursor.image = (char *) zeros;
696 fbcursor.mask = (char *) zeros;
697 fbcursor.size.x = 32;
698 fbcursor.size.y = 1;
699 fbcursor.set = FB_CUR_SETALL;
700 ioctl(psdp->fd, FBIOSCURSOR, &fbcursor);
701}
702
703/* Set HW cursor colormap. */
704void
705xf86SbusSetOsHwCursorCmap(sbusDevicePtr psdp, int bg, int fg)
706{
707 struct fbcursor fbcursor;
708 unsigned char red[2], green[2], blue[2];
709
710 memset(&fbcursor, 0, sizeof(fbcursor));
711 red[0] = bg >> 16;
712 green[0] = bg >> 8;
713 blue[0] = bg;
714 red[1] = fg >> 16;
715 green[1] = fg >> 8;
716 blue[1] = fg;
717 fbcursor.cmap.count = 2;
718 fbcursor.cmap.red = red;
719 fbcursor.cmap.green = green;
720 fbcursor.cmap.blue = blue;
721 fbcursor.set = FB_CUR_SETCMAP;
722 ioctl(psdp->fd, FBIOSCURSOR, &fbcursor);
723}