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