xf86sbusBus.c revision 706f2543
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->size = fbattr.fbtype.fb_size;
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 = malloc(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		free(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->bus.type == BUS_SBUS && p->bus.id.sbus.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->bus.type = BUS_SBUS;
349        xf86AddDevToEntity(num, dev);
350        p->bus.id.sbus.fbNum = psdp->fbNum;
351        p->active = active;
352        p->inUse = FALSE;
353	sbusSlotClaimed = TRUE;
354	return num;
355    } else
356	return -1;
357}
358
359int
360xf86MatchSbusInstances(const char *driverName, int sbusDevId,
361		       GDevPtr *devList, int numDevs, DriverPtr drvp,
362		       int **foundEntities)
363{
364    int i,j;
365    sbusDevicePtr psdp, *psdpp;
366    int numClaimedInstances = 0;
367    int allocatedInstances = 0;
368    int numFound = 0;
369    GDevPtr devBus = NULL;
370    GDevPtr dev = NULL;
371    int *retEntities = NULL;
372    int useProm = 0;
373
374    struct Inst {
375	sbusDevicePtr	sbus;
376	GDevPtr		dev;
377	Bool		claimed;  /* BusID matches with a device section */
378    } *instances = NULL;
379
380    *foundEntities = NULL;
381    for (psdpp = xf86SbusInfo, psdp = *psdpp; psdp; psdp = *++psdpp) {
382	if (psdp->devId != sbusDevId)
383	    continue;
384	if (psdp->fd == -2)
385	    continue;
386	++allocatedInstances;
387	instances = xnfrealloc(instances,
388			       allocatedInstances * sizeof(struct Inst));
389	instances[allocatedInstances - 1].sbus = psdp;
390	instances[allocatedInstances - 1].dev = NULL;
391	instances[allocatedInstances - 1].claimed = FALSE;
392	numFound++;
393    }
394
395    /*
396     * This may be debatable, but if no SBUS devices with a matching vendor
397     * type is found, return zero now.  It is probably not desirable to
398     * allow the config file to override this.
399     */
400    if (allocatedInstances <= 0) {
401	free(instances);
402	return 0;
403    }
404
405    if (sparcPromInit() >= 0)
406	useProm = 1;
407
408    if (xf86DoConfigure && xf86DoConfigurePass1) {
409	GDevPtr pGDev;
410	int actualcards = 0;
411	for (i = 0; i < allocatedInstances; i++) {
412	    actualcards++;
413	    pGDev = xf86AddBusDeviceToConfigure(drvp->driverName, BUS_SBUS,
414						instances[i].sbus, -1);
415	    if (pGDev) {
416		/*
417		 * XF86Match???Instances() treat chipID and chipRev as
418		 * overrides, so clobber them here.
419		 */
420		pGDev->chipID = pGDev->chipRev = -1;
421	    }
422	}
423	free(instances);
424	if (useProm)
425	    sparcPromClose();
426	return actualcards;
427    }
428
429    DebugF("%s instances found: %d\n", driverName, allocatedInstances);
430
431    for (i = 0; i < allocatedInstances; i++) {
432	char *promPath = NULL;
433
434	psdp = instances[i].sbus;
435	devBus = NULL;
436	dev = NULL;
437	if (useProm && psdp->node.node)
438	    promPath = sparcPromNode2Pathname(&psdp->node);
439
440	for (j = 0; j < numDevs; j++) {
441	    if (devList[j]->busID && *devList[j]->busID) {
442		if (xf86CompareSbusBusString(devList[j]->busID, psdp->fbNum)) {
443		    if (devBus)
444			xf86MsgVerb(X_WARNING,0,
445			    "%s: More than one matching Device section for "
446			    "instance (BusID: %s) found: %s\n",
447			    driverName,devList[j]->identifier,
448			    devList[j]->busID);
449		    else
450			devBus = devList[j];
451		}
452	    } else {
453		if (!dev && !devBus) {
454		    if (promPath)
455			xf86Msg(X_PROBED, "Assigning device section with no busID to SBUS:%s\n",
456				promPath);
457		    else
458			xf86Msg(X_PROBED, "Assigning device section with no busID to SBUS:fb%d\n",
459				psdp->fbNum);
460		    dev = devList[j];
461		} else
462		    xf86MsgVerb(X_WARNING, 0,
463			    "%s: More than one matching Device section "
464			    "found: %s\n", driverName, devList[j]->identifier);
465	    }
466	}
467	if (devBus) dev = devBus;  /* busID preferred */
468	if (!dev && psdp->fd != -2) {
469	    if (promPath) {
470		xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section "
471			    "for instance (BusID SBUS:%s) found\n",
472			    driverName, promPath);
473	    } else
474		xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section "
475			    "for instance (BusID SBUS:fb%d) found\n",
476			    driverName, psdp->fbNum);
477	} else if (dev) {
478	    numClaimedInstances++;
479	    instances[i].claimed = TRUE;
480	    instances[i].dev = dev;
481	}
482	free(promPath);
483    }
484
485    DebugF("%s instances found: %d\n", driverName, numClaimedInstances);
486
487    /*
488     * Of the claimed instances, check that another driver hasn't already
489     * claimed its slot.
490     */
491    numFound = 0;
492    for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) {
493	if (!instances[i].claimed)
494	    continue;
495	psdp = instances[i].sbus;
496	if (!xf86CheckSbusSlot(psdp->fbNum))
497	    continue;
498
499	DebugF("%s: card at fb%d %08x is claimed by a Device section\n",
500	       driverName, psdp->fbNum, psdp->node.node);
501
502	/* Allocate an entry in the lists to be returned */
503	numFound++;
504	retEntities = xnfrealloc(retEntities, numFound * sizeof(int));
505	retEntities[numFound - 1]
506	    = xf86ClaimSbusSlot(psdp, drvp, instances[i].dev,instances[i].dev->active ?
507				TRUE : FALSE);
508    }
509    free(instances);
510    if (numFound > 0) {
511	*foundEntities = retEntities;
512    }
513
514    if (useProm)
515	sparcPromClose();
516
517    return numFound;
518}
519
520/*
521 * xf86GetSbusInfoForEntity() -- Get the sbusDevicePtr of entity.
522 */
523sbusDevicePtr
524xf86GetSbusInfoForEntity(int entityIndex)
525{
526    sbusDevicePtr *psdpp;
527    EntityPtr p = xf86Entities[entityIndex];
528
529    if (entityIndex >= xf86NumEntities
530	|| p->bus.type != BUS_SBUS) return NULL;
531
532    for (psdpp = xf86SbusInfo; *psdpp != NULL; psdpp++) {
533	if (p->bus.id.sbus.fbNum == (*psdpp)->fbNum)
534	    return *psdpp;
535    }
536    return NULL;
537}
538
539int
540xf86GetEntityForSbusInfo(sbusDevicePtr psdp)
541{
542    int i;
543
544    for (i = 0; i < xf86NumEntities; i++) {
545	EntityPtr p = xf86Entities[i];
546	if (p->bus.type != BUS_SBUS) continue;
547
548	if (p->bus.id.sbus.fbNum == psdp->fbNum)
549	    return i;
550    }
551    return -1;
552}
553
554void
555xf86SbusUseBuiltinMode(ScrnInfoPtr pScrn, sbusDevicePtr psdp)
556{
557    DisplayModePtr mode;
558
559    mode = xnfcalloc(sizeof(DisplayModeRec), 1);
560    mode->name = "current";
561    mode->next = mode;
562    mode->prev = mode;
563    mode->type = M_T_BUILTIN;
564    mode->Clock = 100000000;
565    mode->HDisplay = psdp->width;
566    mode->HSyncStart = psdp->width;
567    mode->HSyncEnd = psdp->width;
568    mode->HTotal = psdp->width;
569    mode->VDisplay = psdp->height;
570    mode->VSyncStart = psdp->height;
571    mode->VSyncEnd = psdp->height;
572    mode->VTotal = psdp->height;
573    mode->SynthClock = mode->Clock;
574    mode->CrtcHDisplay = mode->HDisplay;
575    mode->CrtcHSyncStart = mode->HSyncStart;
576    mode->CrtcHSyncEnd = mode->HSyncEnd;
577    mode->CrtcHTotal = mode->HTotal;
578    mode->CrtcVDisplay = mode->VDisplay;
579    mode->CrtcVSyncStart = mode->VSyncStart;
580    mode->CrtcVSyncEnd = mode->VSyncEnd;
581    mode->CrtcVTotal = mode->VTotal;
582    mode->CrtcHAdjusted = FALSE;
583    mode->CrtcVAdjusted = FALSE;
584    pScrn->modes = mode;
585    pScrn->virtualX = psdp->width;
586    pScrn->virtualY = psdp->height;
587}
588
589static DevPrivateKeyRec sbusPaletteKeyIndex = { .initialized = 0 };
590static DevPrivateKey sbusPaletteKey = &sbusPaletteKeyIndex;
591typedef struct _sbusCmap {
592    sbusDevicePtr psdp;
593    CloseScreenProcPtr CloseScreen;
594    Bool origCmapValid;
595    unsigned char origRed[16];
596    unsigned char origGreen[16];
597    unsigned char origBlue[16];
598} sbusCmapRec, *sbusCmapPtr;
599
600#define SBUSCMAPPTR(pScreen) ((sbusCmapPtr) \
601    dixLookupPrivate(&(pScreen)->devPrivates, sbusPaletteKey))
602
603static void
604xf86SbusCmapLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
605			LOCO *colors, VisualPtr pVisual)
606{
607    int i, index, ret;
608    sbusCmapPtr cmap;
609    struct fbcmap fbcmap;
610    unsigned char *data = malloc(numColors*3);
611
612    cmap = SBUSCMAPPTR(pScrn->pScreen);
613    if (!cmap) return;
614    fbcmap.count = 0;
615    fbcmap.index = indices[0];
616    fbcmap.red = data;
617    fbcmap.green = data + numColors;
618    fbcmap.blue = fbcmap.green + numColors;
619    for (i = 0; i < numColors; i++) {
620	index = indices[i];
621	if (fbcmap.count && index != fbcmap.index + fbcmap.count) {
622	    ret = ioctl (cmap->psdp->fd, FBIOPUTCMAP, &fbcmap);
623    	    if (ret != 0)
624	        xf86Msg(X_ERROR, "%s: ioctl(%d, FBIOPUTCMAP): %d %d\n",
625		  __func__, cmap->psdp->fd, ret, errno);
626	    fbcmap.count = 0;
627	    fbcmap.index = index;
628	}
629	fbcmap.red[fbcmap.count] = colors[index].red;
630	fbcmap.green[fbcmap.count] = colors[index].green;
631	fbcmap.blue[fbcmap.count++] = colors[index].blue;
632    }
633    ret = ioctl (cmap->psdp->fd, FBIOPUTCMAP, &fbcmap);
634    if (ret != 0)
635        xf86Msg(X_ERROR, "%s: ioctl(%d, FBIOPUTCMAP): %d %d\n", __func__,
636          cmap->psdp->fd, ret, errno);
637    free(data);
638}
639
640static Bool
641xf86SbusCmapCloseScreen(int i, ScreenPtr pScreen)
642{
643    sbusCmapPtr cmap;
644    struct fbcmap fbcmap;
645
646    cmap = SBUSCMAPPTR(pScreen);
647    if (cmap->origCmapValid) {
648	fbcmap.index = 0;
649	fbcmap.count = 16;
650	fbcmap.red = cmap->origRed;
651	fbcmap.green = cmap->origGreen;
652	fbcmap.blue = cmap->origBlue;
653	ioctl (cmap->psdp->fd, FBIOPUTCMAP, &fbcmap);
654    }
655    pScreen->CloseScreen = cmap->CloseScreen;
656    free(cmap);
657    return (*pScreen->CloseScreen) (i, pScreen);
658}
659
660Bool
661xf86SbusHandleColormaps(ScreenPtr pScreen, sbusDevicePtr psdp)
662{
663    sbusCmapPtr cmap;
664    struct fbcmap fbcmap;
665    int ret;
666    unsigned char data[2];
667
668    cmap = xnfcalloc(1, sizeof(sbusCmapRec));
669    if (!dixPrivateKeyRegistered(sbusPaletteKey)) {
670        dixRegisterPrivateKey(sbusPaletteKey, PRIVATE_SCREEN, 0);
671    }
672    dixSetPrivate(&pScreen->devPrivates, sbusPaletteKey, cmap);
673    cmap->psdp = psdp;
674    fbcmap.index = 0;
675    fbcmap.count = 16;
676    fbcmap.red = cmap->origRed;
677    fbcmap.green = cmap->origGreen;
678    fbcmap.blue = cmap->origBlue;
679    if ((ret = ioctl (psdp->fd, FBIOGETCMAP, &fbcmap)) >= 0)
680	cmap->origCmapValid = TRUE;
681    fbcmap.index = 0;
682    fbcmap.count = 2;
683    fbcmap.red = data;
684    fbcmap.green = data;
685    fbcmap.blue = data;
686    if (pScreen->whitePixel == 0) {
687	data[0] = 255;
688	data[1] = 0;
689    } else {
690	data[0] = 0;
691	data[1] = 255;
692    }
693    ret = ioctl (psdp->fd, FBIOPUTCMAP, &fbcmap);
694    if (ret != 0)
695        xf86Msg(X_ERROR, "%s: ioctl(%d, FBIOPUTCMAP): %d %d\n", __func__,
696	  psdp->fd, ret, errno);
697    cmap->CloseScreen = pScreen->CloseScreen;
698    pScreen->CloseScreen = xf86SbusCmapCloseScreen;
699    return xf86HandleColormaps(pScreen, 256, 8,
700			       xf86SbusCmapLoadPalette, NULL, 0);
701}
702
703Bool
704xf86SbusConfigure(void *busData, sbusDevicePtr sBus)
705{
706    if (sBus && sBus->fbNum == ((sbusDevicePtr) busData)->fbNum)
707        return 0;
708    return 1;
709}
710
711void
712xf86SbusConfigureNewDev(void *busData, sbusDevicePtr sBus, GDevRec *GDev)
713{
714    char *promPath = NULL;
715
716    sBus = (sbusDevicePtr) busData;
717    GDev->identifier = sBus->descr;
718    if (sparcPromInit() >= 0) {
719        promPath = sparcPromNode2Pathname(&sBus->node);
720        sparcPromClose();
721    }
722    if (promPath) {
723        XNFasprintf(&GDev->busID, "SBUS:%s", promPath);
724        free(promPath);
725    } else {
726        XNFasprintf(&GDev->busID, "SBUS:fb%d", sBus->fbNum);
727    }
728}
729