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