2 * SBUS and OpenPROM access functions.
4 * Copyright (C) 2000 Jakub Jelinek (jakub@redhat.com)
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
24 #ifdef HAVE_XORG_CONFIG_H
25 #include <xorg-config.h>
32 #include <sys/ioctl.h>
35 #include <sys/utsname.h>
39 #include "xf86_OSlib.h"
41 #include "xf86sbusBus.h"
46 static int promFd
= -1;
47 static int promCurrentNode
;
48 static int promOpenCount
= 0;
49 static int promP1275
= -1;
51 #define MAX_VAL (4096-128-4)
52 static struct openpromio
*promOpio
;
54 sbusDevicePtr
*xf86SbusInfo
= NULL
;
56 struct sbus_devtable sbusDeviceTable
[] = {
57 { SBUS_DEVICE_BW2
, FBTYPE_SUN2BW
, "bwtwo", "Sun Monochrome (bwtwo)" },
58 { SBUS_DEVICE_CG2
, FBTYPE_SUN2COLOR
, "cgtwo", "Sun Color2 (cgtwo)" },
59 { SBUS_DEVICE_CG3
, FBTYPE_SUN3COLOR
, "cgthree", "Sun Color3 (cgthree)" },
60 { SBUS_DEVICE_CG4
, FBTYPE_SUN4COLOR
, "cgfour", "Sun Color4 (cgfour)" },
61 { SBUS_DEVICE_CG6
, FBTYPE_SUNFAST_COLOR
, "cgsix", "Sun GX" },
62 { SBUS_DEVICE_CG8
, FBTYPE_MEMCOLOR
, "cgeight", "Sun CG8/RasterOps" },
63 { SBUS_DEVICE_CG12
, FBTYPE_SUNGP3
, "cgtwelve", "Sun GS (cgtwelve)" },
64 { SBUS_DEVICE_CG14
, FBTYPE_MDICOLOR
, "cgfourteen", "Sun SX" },
65 { SBUS_DEVICE_GT
, FBTYPE_SUNGT
, "gt", "Sun Graphics Tower" },
66 { SBUS_DEVICE_MGX
, -1, "mgx", "Quantum 3D MGXplus" },
67 { SBUS_DEVICE_LEO
, FBTYPE_SUNLEO
, "leo", "Sun ZX or Turbo ZX" },
68 { SBUS_DEVICE_TCX
, FBTYPE_TCXCOLOR
, "tcx", "Sun TCX" },
69 { SBUS_DEVICE_FFB
, FBTYPE_CREATOR
, "ffb", "Sun FFB" },
70 { SBUS_DEVICE_FFB
, FBTYPE_CREATOR
, "afb", "Sun Elite3D" },
75 promGetSibling(int node
)
77 promOpio
->oprom_size
= sizeof(int);
79 if (node
== -1) return 0;
80 *(int *)promOpio
->oprom_array
= node
;
81 if (ioctl(promFd
, OPROMNEXT
, promOpio
) < 0)
83 promCurrentNode
= *(int *)promOpio
->oprom_array
;
84 return *(int *)promOpio
->oprom_array
;
88 promGetChild(int node
)
90 promOpio
->oprom_size
= sizeof(int);
92 if (!node
|| node
== -1) return 0;
93 *(int *)promOpio
->oprom_array
= node
;
94 if (ioctl(promFd
, OPROMCHILD
, promOpio
) < 0)
96 promCurrentNode
= *(int *)promOpio
->oprom_array
;
97 return *(int *)promOpio
->oprom_array
;
101 promGetProperty(const char *prop
, int *lenp
)
103 promOpio
->oprom_size
= MAX_VAL
;
105 strcpy(promOpio
->oprom_array
, prop
);
106 if (ioctl(promFd
, OPROMGETPROP
, promOpio
) < 0)
108 if (lenp
) *lenp
= promOpio
->oprom_size
;
109 return promOpio
->oprom_array
;
113 promGetBool(const char *prop
)
115 promOpio
->oprom_size
= 0;
117 *(int *)promOpio
->oprom_array
= 0;
119 promOpio
->oprom_size
= MAX_PROP
;
120 if (ioctl(promFd
, OPROMNXTPROP
, promOpio
) < 0)
122 if (!promOpio
->oprom_size
)
124 if (!strcmp(promOpio
->oprom_array
, prop
))
129 #define PROM_NODE_SIBLING 0x01
130 #define PROM_NODE_PREF 0x02
131 #define PROM_NODE_SBUS 0x04
132 #define PROM_NODE_EBUS 0x08
133 #define PROM_NODE_PCI 0x10
136 promSetNode(sbusPromNodePtr pnode
)
140 if (!pnode
->node
|| pnode
->node
== -1)
142 if (pnode
->cookie
[0] & PROM_NODE_SIBLING
)
143 node
= promGetSibling(pnode
->cookie
[1]);
145 node
= promGetChild(pnode
->cookie
[1]);
146 if (pnode
->node
!= node
)
161 f
= fopen("/proc/cpuinfo","r");
163 while (fgets(buffer
, 1024, f
) != NULL
)
164 if (!strncmp (buffer
, "type", 4) && strstr (buffer
, "sun4u")) {
170 struct utsname buffer
;
172 if ((uname(&buffer
) >= 0) && !strcmp(buffer
.machine
, "sun4u"))
176 #elif defined(__FreeBSD__)
179 #error Missing promIsP1275() function for this OS
186 if (promOpenCount
> 1) {
208 promFd
= open("/dev/openprom", O_RDONLY
, 0);
211 promOpio
= (struct openpromio
*)xalloc(4096);
216 promRootNode
= promGetSibling(0);
228 sparcPromGetProperty(sbusPromNodePtr pnode
, const char *prop
, int *lenp
)
230 if (promSetNode(pnode
))
232 return promGetProperty(prop
, lenp
);
236 sparcPromGetBool(sbusPromNodePtr pnode
, const char *prop
)
238 if (promSetNode(pnode
))
240 return promGetBool(prop
);
244 promWalkAssignNodes(int node
, int oldnode
, int flags
, sbusDevicePtr
*devicePtrs
)
247 int len
, sbus
= flags
& PROM_NODE_SBUS
;
250 sbusPromNode pNode
, pNode2
;
252 prop
= promGetProperty("device_type", &len
);
253 if (prop
&& (len
> 0)) do {
254 if (!strcmp(prop
, "display")) {
255 prop
= promGetProperty("name", &len
);
256 if (!prop
|| len
<= 0)
258 while ((*prop
>= 'A' && *prop
<= 'Z') || *prop
== ',')
260 for (i
= 0; sbusDeviceTable
[i
].devId
; i
++)
261 if (!strcmp(prop
, sbusDeviceTable
[i
].promName
))
263 devId
= sbusDeviceTable
[i
].devId
;
267 if (devId
== SBUS_DEVICE_FFB
) {
269 * All /SUNW,ffb outside of SBUS tree come before all
270 * /SUNW,afb outside of SBUS tree in Linux.
272 if (!strcmp(prop
, "afb"))
273 flags
|= PROM_NODE_PREF
;
274 } else if (devId
!= SBUS_DEVICE_CG14
)
277 for (i
= 0; i
< 32; i
++) {
278 if (!devicePtrs
[i
] || devicePtrs
[i
]->devId
!= devId
)
280 if (devicePtrs
[i
]->node
.node
) {
281 if ((devicePtrs
[i
]->node
.cookie
[0] & ~PROM_NODE_SIBLING
) <=
282 (flags
& ~PROM_NODE_SIBLING
))
284 for (j
= i
+ 1, pNode
= devicePtrs
[i
]->node
; j
< 32; j
++) {
285 if (!devicePtrs
[j
] || devicePtrs
[j
]->devId
!= devId
)
287 pNode2
= devicePtrs
[j
]->node
;
288 devicePtrs
[j
]->node
= pNode
;
292 devicePtrs
[i
]->node
.node
= node
;
293 devicePtrs
[i
]->node
.cookie
[0] = flags
;
294 devicePtrs
[i
]->node
.cookie
[1] = oldnode
;
301 prop
= promGetProperty("name", &len
);
302 if (prop
&& len
> 0) {
303 if (!strcmp(prop
, "sbus") || !strcmp(prop
, "sbi"))
304 sbus
= PROM_NODE_SBUS
;
307 nextnode
= promGetChild(node
);
309 promWalkAssignNodes(nextnode
, node
, sbus
, devicePtrs
);
311 nextnode
= promGetSibling(node
);
313 promWalkAssignNodes(nextnode
, node
, PROM_NODE_SIBLING
| sbus
, devicePtrs
);
317 sparcPromAssignNodes(void)
319 sbusDevicePtr psdp
, *psdpp
;
320 int n
, holes
= 0, i
, j
;
322 sbusDevicePtr devicePtrs
[32];
324 (void)memset(devicePtrs
, 0, sizeof(devicePtrs
));
325 for (psdpp
= xf86SbusInfo
, n
= 0; (psdp
= *psdpp
); psdpp
++, n
++) {
326 if (psdp
->fbNum
!= n
)
328 devicePtrs
[psdp
->fbNum
] = psdp
;
330 if (holes
&& (f
= fopen("/proc/fb", "r")) != NULL
) {
331 /* We could not open one of fb devices, check /proc/fb to see what
332 * were the types of the cards missed. */
338 } procFbPrefixes
[] = {
339 { SBUS_DEVICE_BW2
, "BWtwo" },
340 { SBUS_DEVICE_CG14
, "CGfourteen" },
341 { SBUS_DEVICE_CG6
, "CGsix" },
342 { SBUS_DEVICE_CG3
, "CGthree" },
343 { SBUS_DEVICE_FFB
, "Creator" },
344 { SBUS_DEVICE_FFB
, "Elite 3D" },
345 { SBUS_DEVICE_LEO
, "Leo" },
346 { SBUS_DEVICE_TCX
, "TCX" },
350 while (fscanf(f
, "%d %63s\n", &fbNum
, buffer
) == 2) {
351 for (i
= 0; procFbPrefixes
[i
].devId
; i
++)
352 if (! strncmp(procFbPrefixes
[i
].prefix
, buffer
,
353 strlen(procFbPrefixes
[i
].prefix
)))
355 devId
= procFbPrefixes
[i
].devId
;
356 if (! devId
) continue;
357 if (devicePtrs
[fbNum
]) {
358 if (devicePtrs
[fbNum
]->devId
!= devId
)
359 xf86ErrorF("Inconsistent /proc/fb with FBIOGATTR\n");
360 } else if (!devicePtrs
[fbNum
]) {
361 devicePtrs
[fbNum
] = psdp
= xnfcalloc(sizeof (sbusDevice
), 1);
370 promWalkAssignNodes(promRootNode
, 0, PROM_NODE_PREF
, devicePtrs
);
371 for (i
= 0, j
= 0; i
< 32; i
++)
372 if (devicePtrs
[i
] && devicePtrs
[i
]->fbNum
== -1)
374 xf86SbusInfo
= xnfrealloc(xf86SbusInfo
, sizeof(psdp
) * (n
+ j
+ 1));
375 for (i
= 0, psdpp
= xf86SbusInfo
; i
< 32; i
++)
377 if (devicePtrs
[i
]->fbNum
== -1) {
378 memmove(psdpp
+ 1, psdpp
, sizeof(psdpp
) * (n
+ 1));
379 *psdpp
= devicePtrs
[i
];
390 static char regstr
[40];
393 prop
= promGetProperty("reg", &len
);
394 if (prop
&& len
>= 4) {
395 unsigned int *reg
= (unsigned int *)prop
;
396 if (!promP1275
|| (type
== PROM_NODE_SBUS
) || (type
== PROM_NODE_EBUS
))
397 sprintf (regstr
, "@%x,%x", reg
[0], reg
[1]);
398 else if (type
== PROM_NODE_PCI
) {
399 if ((reg
[0] >> 8) & 7)
400 sprintf (regstr
, "@%x,%x", (reg
[0] >> 11) & 0x1f, (reg
[0] >> 8) & 7);
402 sprintf (regstr
, "@%x", (reg
[0] >> 11) & 0x1f);
404 sprintf (regstr
, "@%x", reg
[0]);
406 unsigned int regs
[2];
408 /* Things get more complicated on UPA. If upa-portid exists,
409 then address is @upa-portid,second-int-in-reg, otherwise
410 it is @first-int-in-reg/16,second-int-in-reg (well, probably
411 upa-portid always exists, but just to be safe). */
412 memcpy (regs
, reg
, sizeof(regs
));
413 prop
= promGetProperty("upa-portid", &len
);
414 if (prop
&& len
== 4) {
415 reg
= (unsigned int *)prop
;
416 sprintf (regstr
, "@%x,%x", reg
[0], regs
[1]);
418 sprintf (regstr
, "@%x,%x", regs
[0] >> 4, regs
[1]);
425 promWalkNode2Pathname(char *path
, int parent
, int node
, int searchNode
, int type
)
428 int len
, ntype
= type
;
431 prop
= promGetProperty("name", &len
);
433 if (!prop
|| len
<= 0)
435 if ((!strcmp(prop
, "sbus") || !strcmp(prop
, "sbi")) && !type
)
436 ntype
= PROM_NODE_SBUS
;
437 else if (!strcmp(prop
, "ebus") && type
== PROM_NODE_PCI
)
438 ntype
= PROM_NODE_EBUS
;
439 else if (!strcmp(prop
, "pci") && !type
)
440 ntype
= PROM_NODE_PCI
;
441 strcpy (path
+ 1, prop
);
442 p
= promGetReg(type
);
445 if (node
== searchNode
)
447 nextnode
= promGetChild(node
);
449 promWalkNode2Pathname(strchr(path
, 0), node
, nextnode
, searchNode
, ntype
))
451 nextnode
= promGetSibling(node
);
453 promWalkNode2Pathname(path
, parent
, nextnode
, searchNode
, type
))
459 sparcPromNode2Pathname(sbusPromNodePtr pnode
)
463 if (!pnode
->node
) return NULL
;
465 if (!ret
) return NULL
;
466 if (promWalkNode2Pathname(ret
, promRootNode
, promGetChild(promRootNode
), pnode
->node
, 0))
473 promWalkPathname2Node(char *name
, char *regstr
, int parent
, int type
)
479 prop
= promGetProperty("name", &len
);
480 if (!prop
|| len
<= 0)
482 if ((!strcmp(prop
, "sbus") || !strcmp(prop
, "sbi")) && !type
)
483 type
= PROM_NODE_SBUS
;
484 else if (!strcmp(prop
, "ebus") && type
== PROM_NODE_PCI
)
485 type
= PROM_NODE_EBUS
;
486 else if (!strcmp(prop
, "pci") && !type
)
487 type
= PROM_NODE_PCI
;
488 for (node
= promGetChild(parent
); node
; node
= promGetSibling(node
)) {
489 prop
= promGetProperty("name", &len
);
490 if (!prop
|| len
<= 0)
492 if (*name
&& strcmp(name
, prop
))
495 p
= promGetReg(type
);
496 if (! *p
|| strcmp(p
+ 1, regstr
))
502 for (node
= promGetChild(parent
); node
; node
= promGetSibling(node
)) {
503 ret
= promWalkPathname2Node(name
, regstr
, node
, type
);
508 name
= strchr(regstr
, 0) + 1;
511 p
= strchr(name
, '/');
516 regstr
= strchr(name
, '@');
528 sparcPromPathname2Node(const char *pathName
)
531 char *name
, *regstr
, *p
;
533 i
= strlen(pathName
);
534 name
= xalloc(i
+ 2);
535 if (! name
) return 0;
536 strcpy (name
, pathName
);
540 p
= strchr(name
+ 1, '/');
545 regstr
= strchr(name
, '@');
550 if (name
+ 1 == regstr
)
553 i
= promWalkPathname2Node(name
+ 1, regstr
, promRootNode
, 0);
559 xf86MapSbusMem(sbusDevicePtr psdp
, unsigned long offset
, unsigned long size
)
562 unsigned long pagemask
= xf86getpagesize() - 1;
563 unsigned long off
= offset
& ~pagemask
;
564 unsigned long len
= ((offset
+ size
+ pagemask
) & ~pagemask
) - off
;
566 if (psdp
->fd
== -1) {
567 psdp
->fd
= open(psdp
->device
, O_RDWR
);
570 } else if (psdp
->fd
< 0)
573 ret
= (pointer
) mmap (NULL
, len
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
,
575 if (ret
== (pointer
) -1) {
576 ret
= (pointer
) mmap (NULL
, len
, PROT_READ
| PROT_WRITE
, MAP_SHARED
,
579 if (ret
== (pointer
) -1)
582 return (char *)ret
+ (offset
- off
);
586 xf86UnmapSbusMem(sbusDevicePtr psdp
, pointer addr
, unsigned long size
)
588 unsigned long mask
= xf86getpagesize() - 1;
589 unsigned long base
= (unsigned long)addr
& ~mask
;
590 unsigned long len
= (((unsigned long)addr
+ size
+ mask
) & ~mask
) - base
;
592 munmap ((pointer
)base
, len
);
595 /* Tell OS that we are driving the HW cursor ourselves. */
597 xf86SbusHideOsHwCursor(sbusDevicePtr psdp
)
599 struct fbcursor fbcursor
;
600 unsigned char zeros
[8];
602 memset(&fbcursor
, 0, sizeof(fbcursor
));
603 memset(&zeros
, 0, sizeof(zeros
));
604 fbcursor
.cmap
.count
= 2;
605 fbcursor
.cmap
.red
= zeros
;
606 fbcursor
.cmap
.green
= zeros
;
607 fbcursor
.cmap
.blue
= zeros
;
608 fbcursor
.image
= (char *)zeros
;
609 fbcursor
.mask
= (char *)zeros
;
610 fbcursor
.size
.x
= 32;
612 fbcursor
.set
= FB_CUR_SETALL
;
613 ioctl(psdp
->fd
, FBIOSCURSOR
, &fbcursor
);
616 /* Set HW cursor colormap. */
618 xf86SbusSetOsHwCursorCmap(sbusDevicePtr psdp
, int bg
, int fg
)
620 struct fbcursor fbcursor
;
621 unsigned char red
[2], green
[2], blue
[2];
623 memset(&fbcursor
, 0, sizeof(fbcursor
));
630 fbcursor
.cmap
.count
= 2;
631 fbcursor
.cmap
.red
= red
;
632 fbcursor
.cmap
.green
= green
;
633 fbcursor
.cmap
.blue
= blue
;
634 fbcursor
.set
= FB_CUR_SETCMAP
;
635 ioctl(psdp
->fd
, FBIOSCURSOR
, &fbcursor
);