xf86sbusBus.c revision 05b261ec
1/*
2 * SBUS bus-specific code.
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 <ctype.h>
29#include <stdio.h>
30#include <unistd.h>
31#include <X11/X.h>
32#include "os.h"
33#include "xf86.h"
34#include "xf86Priv.h"
35#include "xf86_OSlib.h"
36#include "xf86Resources.h"
37#include "xf86cmap.h"
38
39#include "xf86Bus.h"
40
41#include "xf86sbusBus.h"
42#include "xf86Sbus.h"
43
44Bool sbusSlotClaimed = FALSE;
45
46static int xf86nSbusInfo;
47
48static void
49CheckSbusDevice(const char *device, int fbNum)
50{
51    int fd, i;
52    struct fbgattr fbattr;
53    sbusDevicePtr psdp;
54
55    fd = open(device, O_RDONLY, 0);
56    if (fd < 0)
57	return;
58    memset(&fbattr, 0, sizeof(fbattr));
59    if (ioctl(fd, FBIOGATTR, &fbattr) < 0) {
60	if (ioctl(fd, FBIOGTYPE, &fbattr.fbtype) < 0) {
61	    close(fd);
62	    return;
63	}
64    }
65    close(fd);
66    for (i = 0; sbusDeviceTable[i].devId; i++)
67	if (sbusDeviceTable[i].fbType == fbattr.fbtype.fb_type)
68	    break;
69    if (! sbusDeviceTable[i].devId)
70	return;
71    xf86SbusInfo = xnfrealloc(xf86SbusInfo, sizeof(psdp) * (++xf86nSbusInfo + 1));
72    xf86SbusInfo[xf86nSbusInfo] = NULL;
73    xf86SbusInfo[xf86nSbusInfo - 1] = psdp = xnfcalloc(sizeof (sbusDevice), 1);
74    psdp->devId = sbusDeviceTable[i].devId;
75    psdp->fbNum = fbNum;
76    psdp->device = xnfstrdup(device);
77    psdp->width = fbattr.fbtype.fb_width;
78    psdp->height = fbattr.fbtype.fb_height;
79    psdp->fd = -1;
80}
81
82void
83xf86SbusProbe(void)
84{
85    int i, useProm = 0;
86    char fbDevName[32];
87    sbusDevicePtr psdp, *psdpp;
88
89    xf86SbusInfo = xalloc(sizeof(psdp));
90    *xf86SbusInfo = NULL;
91    for (i = 0; i < 32; i++) {
92	sprintf(fbDevName, "/dev/fb%d", i);
93	CheckSbusDevice(fbDevName, i);
94    }
95    if (sparcPromInit() >= 0) {
96	useProm = 1;
97	sparcPromAssignNodes();
98    }
99    for (psdpp = xf86SbusInfo; (psdp = *psdpp); psdpp++) {
100	for (i = 0; sbusDeviceTable[i].devId; i++)
101	    if (sbusDeviceTable[i].devId == psdp->devId)
102		psdp->descr = sbusDeviceTable[i].descr;
103	/*
104	 * If we can use PROM information and found the PROM node for this
105	 * device, we can tell more about the card.
106	 */
107	if (useProm && psdp->node.node) {
108	    char *prop, *promPath;
109	    int len, chiprev, vmsize;
110
111	    switch (psdp->devId) {
112	    case SBUS_DEVICE_MGX:
113		prop = sparcPromGetProperty(&psdp->node, "fb_size", &len);
114		if (prop && len == 4 && *(int *)prop == 0x400000)
115		    psdp->descr = "Quantum 3D MGXplus with 4M VRAM";
116		break;
117	    case SBUS_DEVICE_CG6:
118		chiprev = 0;
119		vmsize = 0;
120		prop = sparcPromGetProperty(&psdp->node, "chiprev", &len);
121		if (prop && len == 4)
122		    chiprev = *(int *)prop;
123		prop = sparcPromGetProperty(&psdp->node, "vmsize", &len);
124		if (prop && len == 4)
125		    vmsize = *(int *)prop;
126		switch (chiprev) {
127		case 1:
128		case 2:
129		case 3:
130		case 4:
131		    psdp->descr = "Sun Double width GX"; break;
132		case 5:
133		case 6:
134		case 7:
135		case 8:
136		case 9:
137		    psdp->descr = "Sun Single width GX"; break;
138		case 11:
139		    switch (vmsize) {
140		    case 2:
141			psdp->descr = "Sun Turbo GX with 1M VSIMM"; break;
142		    case 4:
143			psdp->descr = "Sun Turbo GX Plus"; break;
144		    default:
145			psdp->descr = "Sun Turbo GX"; break;
146		    }
147		}
148		break;
149	    case SBUS_DEVICE_CG14:
150		prop = sparcPromGetProperty(&psdp->node, "reg", &len);
151		vmsize = 0;
152		if (prop && !(len % 12) && len > 0)
153		    vmsize = *(int *)(prop + len - 4);
154		switch (vmsize) {
155		case 0x400000:
156		    psdp->descr = "Sun SX with 4M VSIMM"; break;
157		case 0x800000:
158		    psdp->descr = "Sun SX with 8M VSIMM"; break;
159		}
160		break;
161	    case SBUS_DEVICE_LEO:
162		prop = sparcPromGetProperty(&psdp->node, "model", &len);
163		if (prop && len > 0 && !strstr(prop, "501-2503"))
164		    psdp->descr = "Sun Turbo ZX";
165		break;
166	    case SBUS_DEVICE_TCX:
167		if (sparcPromGetBool(&psdp->node, "tcx-8-bit"))
168		    psdp->descr = "Sun TCX (8bit)";
169		else
170		    psdp->descr = "Sun TCX (S24)";
171		break;
172	    case SBUS_DEVICE_FFB:
173		prop = sparcPromGetProperty(&psdp->node, "name", &len);
174		chiprev = 0;
175		prop = sparcPromGetProperty(&psdp->node, "board_type", &len);
176		if (prop && len == 4)
177		    chiprev = *(int *)prop;
178		if (strstr (prop, "afb")) {
179		    if (chiprev == 3)
180			psdp->descr = "Sun|Elite3D-M6 Horizontal";
181		} else {
182		    switch (chiprev) {
183		    case 0x08:
184			psdp->descr = "Sun FFB 67MHz Creator"; break;
185		    case 0x0b:
186			psdp->descr = "Sun FFB 67MHz Creator 3D"; break;
187		    case 0x1b:
188			psdp->descr = "Sun FFB 75MHz Creator 3D"; break;
189		    case 0x20:
190		    case 0x28:
191			psdp->descr = "Sun FFB2 Vertical Creator"; break;
192		    case 0x23:
193		    case 0x2b:
194			psdp->descr = "Sun FFB2 Vertical Creator 3D"; break;
195		    case 0x30:
196			psdp->descr = "Sun FFB2+ Vertical Creator"; break;
197		    case 0x33:
198			psdp->descr = "Sun FFB2+ Vertical Creator 3D"; break;
199		    case 0x40:
200		    case 0x48:
201			psdp->descr = "Sun FFB2 Horizontal Creator"; break;
202		    case 0x43:
203		    case 0x4b:
204			psdp->descr = "Sun FFB2 Horizontal Creator 3D"; break;
205		    }
206		}
207		break;
208	    }
209
210	    xf86Msg(X_PROBED, "SBUS:(0x%08x) %s", psdp->node.node, psdp->descr);
211	    promPath = sparcPromNode2Pathname (&psdp->node);
212	    if (promPath) {
213		xf86ErrorF(" at %s", promPath);
214		xfree(promPath);
215	    }
216	} else
217	    xf86Msg(X_PROBED, "SBUS: %s", psdp->descr);
218	xf86ErrorF("\n");
219    }
220    if (useProm)
221	sparcPromClose();
222}
223
224/*
225 * Parse a BUS ID string, and return the SBUS bus parameters if it was
226 * in the correct format for a SBUS bus id.
227 */
228
229Bool
230xf86ParseSbusBusString(const char *busID, int *fbNum)
231{
232    /*
233     * The format is assumed to be one of:
234     * "fbN", e.g. "fb1", which means the device corresponding to /dev/fbN
235     * "nameN", e.g. "cgsix0", which means Nth instance of card NAME
236     * "/prompath", e.g. "/sbus@0,10001000/cgsix@3,0" which is PROM pathname
237     * to the device.
238     */
239
240    const char *id;
241    int i, len;
242
243    if (StringToBusType(busID, &id) != BUS_SBUS)
244	return FALSE;
245
246    if (*id != '/') {
247	if (!strncmp (id, "fb", 2)) {
248	    if (!isdigit(id[2]))
249		return FALSE;
250	    *fbNum = atoi(id + 2);
251	    return TRUE;
252	} else {
253	    sbusDevicePtr *psdpp;
254	    int devId;
255
256	    for (i = 0, len = 0; sbusDeviceTable[i].devId; i++) {
257		len = strlen(sbusDeviceTable[i].promName);
258		if (!strncmp (sbusDeviceTable[i].promName, id, len)
259		    && isdigit(id[len]))
260		    break;
261	    }
262	    devId = sbusDeviceTable[i].devId;
263	    if (!devId) return FALSE;
264	    i = atoi(id + len);
265	    for (psdpp = xf86SbusInfo; *psdpp; ++psdpp) {
266		if ((*psdpp)->devId != devId)
267		    continue;
268		if (!i) {
269		    *fbNum = (*psdpp)->fbNum;
270		    return TRUE;
271		}
272		i--;
273	    }
274	}
275	return FALSE;
276    }
277
278    if (sparcPromInit() >= 0) {
279	i = sparcPromPathname2Node(id);
280	sparcPromClose();
281	if (i) {
282	    sbusDevicePtr *psdpp;
283	    for (psdpp = xf86SbusInfo; *psdpp; ++psdpp) {
284		if ((*psdpp)->node.node == i) {
285		    *fbNum = (*psdpp)->fbNum;
286		    return TRUE;
287		}
288	    }
289	}
290    }
291    return FALSE;
292}
293
294/*
295 * Compare a BUS ID string with a SBUS bus id.  Return TRUE if they match.
296 */
297
298Bool
299xf86CompareSbusBusString(const char *busID, int fbNum)
300{
301    int iFbNum;
302
303    if (xf86ParseSbusBusString(busID, &iFbNum)) {
304	return fbNum == iFbNum;
305    } else {
306	return FALSE;
307    }
308}
309
310/*
311 * Check if the slot requested is free.  If it is already in use, return FALSE.
312 */
313
314Bool
315xf86CheckSbusSlot(int fbNum)
316{
317    int i;
318    EntityPtr p;
319
320    for (i = 0; i < xf86NumEntities; i++) {
321	p = xf86Entities[i];
322	/* Check if this SBUS slot is taken */
323	if (p->busType == BUS_SBUS && p->sbusBusId.fbNum == fbNum)
324	    return FALSE;
325    }
326
327    return TRUE;
328}
329
330/*
331 * If the slot requested is already in use, return -1.
332 * Otherwise, claim the slot for the screen requesting it.
333 */
334
335int
336xf86ClaimSbusSlot(sbusDevicePtr psdp, DriverPtr drvp,
337		  GDevPtr dev, Bool active)
338{
339    EntityPtr p = NULL;
340
341    int num;
342
343    if (xf86CheckSbusSlot(psdp->fbNum)) {
344        num = xf86AllocateEntity();
345        p = xf86Entities[num];
346        p->driver = drvp;
347        p->chipset = -1;
348        p->busType = BUS_SBUS;
349        xf86AddDevToEntity(num, dev);
350        p->sbusBusId.fbNum = psdp->fbNum;
351        p->active = active;
352        p->inUse = FALSE;
353        /* Here we initialize the access structure */
354        p->access = xnfcalloc(1,sizeof(EntityAccessRec));
355	p->access->fallback = &AccessNULL;
356        p->access->pAccess = &AccessNULL;
357	sbusSlotClaimed = TRUE;
358	return num;
359    } else
360	return -1;
361}
362
363_X_EXPORT int
364xf86MatchSbusInstances(const char *driverName, int sbusDevId,
365		       GDevPtr *devList, int numDevs, DriverPtr drvp,
366		       int **foundEntities)
367{
368    int i,j;
369    sbusDevicePtr psdp, *psdpp;
370    int numClaimedInstances = 0;
371    int allocatedInstances = 0;
372    int numFound = 0;
373    GDevPtr devBus = NULL;
374    GDevPtr dev = NULL;
375    int *retEntities = NULL;
376    int useProm = 0;
377
378    struct Inst {
379	sbusDevicePtr	sbus;
380	GDevPtr		dev;
381	Bool		claimed;  /* BusID matches with a device section */
382    } *instances = NULL;
383
384    *foundEntities = NULL;
385    for (psdpp = xf86SbusInfo, psdp = *psdpp; psdp; psdp = *++psdpp) {
386	if (psdp->devId != sbusDevId)
387	    continue;
388	if (psdp->fd == -2)
389	    continue;
390	++allocatedInstances;
391	instances = xnfrealloc(instances,
392			       allocatedInstances * sizeof(struct Inst));
393	instances[allocatedInstances - 1].sbus = psdp;
394	instances[allocatedInstances - 1].dev = NULL;
395	instances[allocatedInstances - 1].claimed = FALSE;
396	numFound++;
397    }
398
399    /*
400     * This may be debatable, but if no SBUS devices with a matching vendor
401     * type is found, return zero now.  It is probably not desirable to
402     * allow the config file to override this.
403     */
404    if (allocatedInstances <= 0) {
405	xfree(instances);
406	return 0;
407    }
408
409    if (xf86DoProbe) {
410	xfree(instances);
411	return numFound;
412    }
413
414    if (sparcPromInit() >= 0)
415	useProm = 1;
416
417    if (xf86DoConfigure && xf86DoConfigurePass1) {
418	GDevPtr pGDev;
419	int actualcards = 0;
420	for (i = 0; i < allocatedInstances; i++) {
421	    actualcards++;
422	    pGDev = xf86AddBusDeviceToConfigure(drvp->driverName, BUS_SBUS,
423						instances[i].sbus, -1);
424	    if (pGDev) {
425		/*
426		 * XF86Match???Instances() treat chipID and chipRev as
427		 * overrides, so clobber them here.
428		 */
429		pGDev->chipID = pGDev->chipRev = -1;
430	    }
431	}
432	xfree(instances);
433	if (useProm)
434	    sparcPromClose();
435	return actualcards;
436    }
437
438#ifdef DEBUG
439    ErrorF("%s instances found: %d\n", driverName, allocatedInstances);
440#endif
441
442    for (i = 0; i < allocatedInstances; i++) {
443	char *promPath = NULL;
444
445	psdp = instances[i].sbus;
446	devBus = NULL;
447	dev = NULL;
448	if (useProm && psdp->node.node)
449	    promPath = sparcPromNode2Pathname(&psdp->node);
450
451	for (j = 0; j < numDevs; j++) {
452	    if (devList[j]->busID && *devList[j]->busID) {
453		if (xf86CompareSbusBusString(devList[j]->busID, psdp->fbNum)) {
454		    if (devBus)
455			xf86MsgVerb(X_WARNING,0,
456			    "%s: More than one matching Device section for "
457			    "instance (BusID: %s) found: %s\n",
458			    driverName,devList[j]->identifier,
459			    devList[j]->busID);
460		    else
461			devBus = devList[j];
462		}
463	    } else {
464		if (!dev && !devBus) {
465		    if (promPath)
466			xf86Msg(X_PROBED, "Assigning device section with no busID to SBUS:%s\n",
467				promPath);
468		    else
469			xf86Msg(X_PROBED, "Assigning device section with no busID to SBUS:fb%d\n",
470				psdp->fbNum);
471		    dev = devList[j];
472		} else
473		    xf86MsgVerb(X_WARNING, 0,
474			    "%s: More than one matching Device section "
475			    "found: %s\n", driverName, devList[j]->identifier);
476	    }
477	}
478	if (devBus) dev = devBus;  /* busID preferred */
479	if (!dev && psdp->fd != -2) {
480	    if (promPath) {
481		xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section "
482			    "for instance (BusID SBUS:%s) found\n",
483			    driverName, promPath);
484	    } else
485		xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section "
486			    "for instance (BusID SBUS:fb%d) found\n",
487			    driverName, psdp->fbNum);
488	} else if (dev) {
489	    numClaimedInstances++;
490	    instances[i].claimed = TRUE;
491	    instances[i].dev = dev;
492	}
493	if (promPath)
494	    xfree(promPath);
495    }
496
497#ifdef DEBUG
498    ErrorF("%s instances found: %d\n", driverName, numClaimedInstances);
499#endif
500
501    /*
502     * Of the claimed instances, check that another driver hasn't already
503     * claimed its slot.
504     */
505    numFound = 0;
506    for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) {
507	if (!instances[i].claimed)
508	    continue;
509	psdp = instances[i].sbus;
510	if (!xf86CheckSbusSlot(psdp->fbNum))
511	    continue;
512
513#ifdef DEBUG
514	ErrorF("%s: card at fb%d %08x is claimed by a Device section\n",
515	       driverName, psdp->fbNum, psdp->node.node);
516#endif
517
518	/* Allocate an entry in the lists to be returned */
519	numFound++;
520	retEntities = xnfrealloc(retEntities, numFound * sizeof(int));
521	retEntities[numFound - 1]
522	    = xf86ClaimSbusSlot(psdp, drvp, instances[i].dev,instances[i].dev->active ?
523				TRUE : FALSE);
524    }
525    xfree(instances);
526    if (numFound > 0) {
527	*foundEntities = retEntities;
528    }
529
530    if (useProm)
531	sparcPromClose();
532
533    return numFound;
534}
535
536/*
537 * xf86GetSbusInfoForEntity() -- Get the sbusDevicePtr of entity.
538 */
539_X_EXPORT sbusDevicePtr
540xf86GetSbusInfoForEntity(int entityIndex)
541{
542    sbusDevicePtr *psdpp;
543    EntityPtr p = xf86Entities[entityIndex];
544
545    if (entityIndex >= xf86NumEntities
546	|| p->busType != BUS_SBUS) return NULL;
547
548    for (psdpp = xf86SbusInfo; *psdpp != NULL; psdpp++) {
549	if (p->sbusBusId.fbNum == (*psdpp)->fbNum)
550	    return (*psdpp);
551    }
552    return NULL;
553}
554
555_X_EXPORT int
556xf86GetEntityForSbusInfo(sbusDevicePtr psdp)
557{
558    int i;
559
560    for (i = 0; i < xf86NumEntities; i++) {
561	EntityPtr p = xf86Entities[i];
562	if (p->busType != BUS_SBUS) continue;
563
564	if (p->sbusBusId.fbNum == psdp->fbNum)
565	    return i;
566    }
567    return -1;
568}
569
570_X_EXPORT void
571xf86SbusUseBuiltinMode(ScrnInfoPtr pScrn, sbusDevicePtr psdp)
572{
573    DisplayModePtr mode;
574
575    mode = xnfcalloc(sizeof(DisplayModeRec), 1);
576    mode->name = "current";
577    mode->next = mode;
578    mode->prev = mode;
579    mode->type = M_T_BUILTIN;
580    mode->Clock = 100000000;
581    mode->HDisplay = psdp->width;
582    mode->HSyncStart = psdp->width;
583    mode->HSyncEnd = psdp->width;
584    mode->HTotal = psdp->width;
585    mode->VDisplay = psdp->height;
586    mode->VSyncStart = psdp->height;
587    mode->VSyncEnd = psdp->height;
588    mode->VTotal = psdp->height;
589    mode->SynthClock = mode->Clock;
590    mode->CrtcHDisplay = mode->HDisplay;
591    mode->CrtcHSyncStart = mode->HSyncStart;
592    mode->CrtcHSyncEnd = mode->HSyncEnd;
593    mode->CrtcHTotal = mode->HTotal;
594    mode->CrtcVDisplay = mode->VDisplay;
595    mode->CrtcVSyncStart = mode->VSyncStart;
596    mode->CrtcVSyncEnd = mode->VSyncEnd;
597    mode->CrtcVTotal = mode->VTotal;
598    mode->CrtcHAdjusted = FALSE;
599    mode->CrtcVAdjusted = FALSE;
600    pScrn->modes = mode;
601    pScrn->virtualX = psdp->width;
602    pScrn->virtualY = psdp->height;
603}
604
605static int sbusPaletteIndex = -1;
606static unsigned long sbusPaletteGeneration = 0;
607typedef struct _sbusCmap {
608    sbusDevicePtr psdp;
609    CloseScreenProcPtr CloseScreen;
610    Bool origCmapValid;
611    unsigned char origRed[16];
612    unsigned char origGreen[16];
613    unsigned char origBlue[16];
614} sbusCmapRec, *sbusCmapPtr;
615
616#define SBUSCMAPPTR(pScreen) ((sbusCmapPtr)((pScreen)->devPrivates[sbusPaletteIndex].ptr))
617
618static void
619xf86SbusCmapLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
620			LOCO *colors, VisualPtr pVisual)
621{
622    int i, index;
623    sbusCmapPtr cmap;
624    struct fbcmap fbcmap;
625    unsigned char *data = ALLOCATE_LOCAL(numColors*3);
626
627    cmap = SBUSCMAPPTR(pScrn->pScreen);
628    if (!cmap) return;
629    fbcmap.count = 0;
630    fbcmap.index = indices[0];
631    fbcmap.red = data;
632    fbcmap.green = data + numColors;
633    fbcmap.blue = fbcmap.green + numColors;
634    for (i = 0; i < numColors; i++) {
635	index = indices[i];
636	if (fbcmap.count && index != fbcmap.index + fbcmap.count) {
637	    ioctl (cmap->psdp->fd, FBIOPUTCMAP, &fbcmap);
638	    fbcmap.count = 0;
639	    fbcmap.index = index;
640	}
641	fbcmap.red[fbcmap.count] = colors[index].red;
642	fbcmap.green[fbcmap.count] = colors[index].green;
643	fbcmap.blue[fbcmap.count++] = colors[index].blue;
644    }
645    ioctl (cmap->psdp->fd, FBIOPUTCMAP, &fbcmap);
646    DEALLOCATE_LOCAL(data);
647}
648
649static Bool
650xf86SbusCmapCloseScreen(int i, ScreenPtr pScreen)
651{
652    sbusCmapPtr cmap;
653    struct fbcmap fbcmap;
654
655    cmap = SBUSCMAPPTR(pScreen);
656    if (cmap->origCmapValid) {
657	fbcmap.index = 0;
658	fbcmap.count = 16;
659	fbcmap.red = cmap->origRed;
660	fbcmap.green = cmap->origGreen;
661	fbcmap.blue = cmap->origBlue;
662	ioctl (cmap->psdp->fd, FBIOPUTCMAP, &fbcmap);
663    }
664    pScreen->CloseScreen = cmap->CloseScreen;
665    xfree (cmap);
666    return (*pScreen->CloseScreen) (i, pScreen);
667}
668
669_X_EXPORT Bool
670xf86SbusHandleColormaps(ScreenPtr pScreen, sbusDevicePtr psdp)
671{
672    sbusCmapPtr cmap;
673    struct fbcmap fbcmap;
674    unsigned char data[2];
675
676    if(sbusPaletteGeneration != serverGeneration) {
677	if((sbusPaletteIndex = AllocateScreenPrivateIndex()) < 0)
678	    return FALSE;
679	sbusPaletteGeneration = serverGeneration;
680    }
681    cmap = xnfcalloc(1, sizeof(sbusCmapRec));
682    pScreen->devPrivates[sbusPaletteIndex].ptr = cmap;
683    cmap->psdp = psdp;
684    fbcmap.index = 0;
685    fbcmap.count = 16;
686    fbcmap.red = cmap->origRed;
687    fbcmap.green = cmap->origGreen;
688    fbcmap.blue = cmap->origBlue;
689    if (ioctl (psdp->fd, FBIOGETCMAP, &fbcmap) >= 0)
690	cmap->origCmapValid = TRUE;
691    fbcmap.index = 0;
692    fbcmap.count = 2;
693    fbcmap.red = data;
694    fbcmap.green = data;
695    fbcmap.blue = data;
696    if (pScreen->whitePixel == 0) {
697	data[0] = 255;
698	data[1] = 0;
699    } else {
700	data[0] = 0;
701	data[1] = 255;
702    }
703    ioctl (psdp->fd, FBIOPUTCMAP, &fbcmap);
704    cmap->CloseScreen = pScreen->CloseScreen;
705    pScreen->CloseScreen = xf86SbusCmapCloseScreen;
706    return xf86HandleColormaps(pScreen, 256, 8,
707			       xf86SbusCmapLoadPalette, NULL, 0);
708}
709