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.
23
/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/bus/Sbus.c,v 1.2tsi Exp $ */
25
#ifdef HAVE_XORG_CONFIG_H
26
#include <xorg-config.h>
33
#include <sys/ioctl.h>
36
#include <sys/utsname.h>
40
#include "xf86_OSlib.h"
42
#include "xf86sbusBus.h"
47
static int promFd = -1;
48
static int promCurrentNode;
49
static int promOpenCount = 0;
50
static int promP1275 = -1;
52
#define MAX_VAL (4096-128-4)
53
static struct openpromio *promOpio;
55
sbusDevicePtr *xf86SbusInfo = NULL;
57
struct sbus_devtable sbusDeviceTable[] = {
58
{ SBUS_DEVICE_BW2, FBTYPE_SUN2BW, "bwtwo", "Sun Monochrome (bwtwo)" },
59
{ SBUS_DEVICE_CG2, FBTYPE_SUN2COLOR, "cgtwo", "Sun Color2 (cgtwo)" },
60
{ SBUS_DEVICE_CG3, FBTYPE_SUN3COLOR, "cgthree", "Sun Color3 (cgthree)" },
61
{ SBUS_DEVICE_CG4, FBTYPE_SUN4COLOR, "cgfour", "Sun Color4 (cgfour)" },
62
{ SBUS_DEVICE_CG6, FBTYPE_SUNFAST_COLOR, "cgsix", "Sun GX" },
63
{ SBUS_DEVICE_CG8, FBTYPE_MEMCOLOR, "cgeight", "Sun CG8/RasterOps" },
64
{ SBUS_DEVICE_CG12, FBTYPE_SUNGP3, "cgtwelve", "Sun GS (cgtwelve)" },
65
{ SBUS_DEVICE_CG14, FBTYPE_MDICOLOR, "cgfourteen", "Sun SX" },
66
{ SBUS_DEVICE_GT, FBTYPE_SUNGT, "gt", "Sun Graphics Tower" },
67
{ SBUS_DEVICE_MGX, -1, "mgx", "Quantum 3D MGXplus" },
68
{ SBUS_DEVICE_LEO, FBTYPE_SUNLEO, "leo", "Sun ZX or Turbo ZX" },
69
{ SBUS_DEVICE_TCX, FBTYPE_TCXCOLOR, "tcx", "Sun TCX" },
70
{ SBUS_DEVICE_FFB, FBTYPE_CREATOR, "ffb", "Sun FFB" },
71
{ SBUS_DEVICE_FFB, FBTYPE_CREATOR, "afb", "Sun Elite3D" },
76
promGetSibling(int node)
78
promOpio->oprom_size = sizeof(int);
80
if (node == -1) return 0;
81
*(int *)promOpio->oprom_array = node;
82
if (ioctl(promFd, OPROMNEXT, promOpio) < 0)
84
promCurrentNode = *(int *)promOpio->oprom_array;
85
return *(int *)promOpio->oprom_array;
89
promGetChild(int node)
91
promOpio->oprom_size = sizeof(int);
93
if (!node || node == -1) return 0;
94
*(int *)promOpio->oprom_array = node;
95
if (ioctl(promFd, OPROMCHILD, promOpio) < 0)
97
promCurrentNode = *(int *)promOpio->oprom_array;
98
return *(int *)promOpio->oprom_array;
102
promGetProperty(const char *prop, int *lenp)
104
promOpio->oprom_size = MAX_VAL;
106
strcpy(promOpio->oprom_array, prop);
107
if (ioctl(promFd, OPROMGETPROP, promOpio) < 0)
109
if (lenp) *lenp = promOpio->oprom_size;
110
return promOpio->oprom_array;
114
promGetBool(const char *prop)
116
promOpio->oprom_size = 0;
118
*(int *)promOpio->oprom_array = 0;
120
promOpio->oprom_size = MAX_PROP;
121
if (ioctl(promFd, OPROMNXTPROP, promOpio) < 0)
123
if (!promOpio->oprom_size)
125
if (!strcmp(promOpio->oprom_array, prop))
130
#define PROM_NODE_SIBLING 0x01
131
#define PROM_NODE_PREF 0x02
132
#define PROM_NODE_SBUS 0x04
133
#define PROM_NODE_EBUS 0x08
134
#define PROM_NODE_PCI 0x10
137
promSetNode(sbusPromNodePtr pnode)
141
if (!pnode->node || pnode->node == -1)
143
if (pnode->cookie[0] & PROM_NODE_SIBLING)
144
node = promGetSibling(pnode->cookie[1]);
146
node = promGetChild(pnode->cookie[1]);
147
if (pnode->node != node)
162
f = fopen("/proc/cpuinfo","r");
164
while (fgets(buffer, 1024, f) != NULL)
165
if (!strncmp (buffer, "type", 4) && strstr (buffer, "sun4u")) {
171
struct utsname buffer;
173
if ((uname(&buffer) >= 0) && !strcmp(buffer.machine, "sun4u"))
177
#elif defined(__FreeBSD__)
180
#error Missing promIsP1275() function for this OS
187
if (promOpenCount > 1) {
209
promFd = open("/dev/openprom", O_RDONLY, 0);
212
promOpio = (struct openpromio *)xalloc(4096);
217
promRootNode = promGetSibling(0);
229
sparcPromGetProperty(sbusPromNodePtr pnode, const char *prop, int *lenp)
231
if (promSetNode(pnode))
233
return promGetProperty(prop, lenp);
237
sparcPromGetBool(sbusPromNodePtr pnode, const char *prop)
239
if (promSetNode(pnode))
241
return promGetBool(prop);
245
promWalkAssignNodes(int node, int oldnode, int flags, sbusDevicePtr *devicePtrs)
248
int len, sbus = flags & PROM_NODE_SBUS;
251
sbusPromNode pNode, pNode2;
253
prop = promGetProperty("device_type", &len);
254
if (prop && (len > 0)) do {
255
if (!strcmp(prop, "display")) {
256
prop = promGetProperty("name", &len);
257
if (!prop || len <= 0)
259
while ((*prop >= 'A' && *prop <= 'Z') || *prop == ',')
261
for (i = 0; sbusDeviceTable[i].devId; i++)
262
if (!strcmp(prop, sbusDeviceTable[i].promName))
264
devId = sbusDeviceTable[i].devId;
268
if (devId == SBUS_DEVICE_FFB) {
270
* All /SUNW,ffb outside of SBUS tree come before all
271
* /SUNW,afb outside of SBUS tree in Linux.
273
if (!strcmp(prop, "afb"))
274
flags |= PROM_NODE_PREF;
275
} else if (devId != SBUS_DEVICE_CG14)
278
for (i = 0; i < 32; i++) {
279
if (!devicePtrs[i] || devicePtrs[i]->devId != devId)
281
if (devicePtrs[i]->node.node) {
282
if ((devicePtrs[i]->node.cookie[0] & ~PROM_NODE_SIBLING) <=
283
(flags & ~PROM_NODE_SIBLING))
285
for (j = i + 1, pNode = devicePtrs[i]->node; j < 32; j++) {
286
if (!devicePtrs[j] || devicePtrs[j]->devId != devId)
288
pNode2 = devicePtrs[j]->node;
289
devicePtrs[j]->node = pNode;
293
devicePtrs[i]->node.node = node;
294
devicePtrs[i]->node.cookie[0] = flags;
295
devicePtrs[i]->node.cookie[1] = oldnode;
302
prop = promGetProperty("name", &len);
303
if (prop && len > 0) {
304
if (!strcmp(prop, "sbus") || !strcmp(prop, "sbi"))
305
sbus = PROM_NODE_SBUS;
308
nextnode = promGetChild(node);
310
promWalkAssignNodes(nextnode, node, sbus, devicePtrs);
312
nextnode = promGetSibling(node);
314
promWalkAssignNodes(nextnode, node, PROM_NODE_SIBLING | sbus, devicePtrs);
318
sparcPromAssignNodes(void)
320
sbusDevicePtr psdp, *psdpp;
321
int n, holes = 0, i, j;
323
sbusDevicePtr devicePtrs[32];
325
(void)memset(devicePtrs, 0, sizeof(devicePtrs));
326
for (psdpp = xf86SbusInfo, n = 0; (psdp = *psdpp); psdpp++, n++) {
327
if (psdp->fbNum != n)
329
devicePtrs[psdp->fbNum] = psdp;
331
if (holes && (f = fopen("/proc/fb", "r")) != NULL) {
332
/* We could not open one of fb devices, check /proc/fb to see what
333
* were the types of the cards missed. */
339
} procFbPrefixes[] = {
340
{ SBUS_DEVICE_BW2, "BWtwo" },
341
{ SBUS_DEVICE_CG14, "CGfourteen" },
342
{ SBUS_DEVICE_CG6, "CGsix" },
343
{ SBUS_DEVICE_CG3, "CGthree" },
344
{ SBUS_DEVICE_FFB, "Creator" },
345
{ SBUS_DEVICE_FFB, "Elite 3D" },
346
{ SBUS_DEVICE_LEO, "Leo" },
347
{ SBUS_DEVICE_TCX, "TCX" },
351
while (fscanf(f, "%d %63s\n", &fbNum, buffer) == 2) {
352
for (i = 0; procFbPrefixes[i].devId; i++)
353
if (! strncmp(procFbPrefixes[i].prefix, buffer,
354
strlen(procFbPrefixes[i].prefix)))
356
devId = procFbPrefixes[i].devId;
357
if (! devId) continue;
358
if (devicePtrs[fbNum]) {
359
if (devicePtrs[fbNum]->devId != devId)
360
xf86ErrorF("Inconsistent /proc/fb with FBIOGATTR\n");
361
} else if (!devicePtrs[fbNum]) {
362
devicePtrs[fbNum] = psdp = xnfcalloc(sizeof (sbusDevice), 1);
371
promWalkAssignNodes(promRootNode, 0, PROM_NODE_PREF, devicePtrs);
372
for (i = 0, j = 0; i < 32; i++)
373
if (devicePtrs[i] && devicePtrs[i]->fbNum == -1)
375
xf86SbusInfo = xnfrealloc(xf86SbusInfo, sizeof(psdp) * (n + j + 1));
376
for (i = 0, psdpp = xf86SbusInfo; i < 32; i++)
378
if (devicePtrs[i]->fbNum == -1) {
379
memmove(psdpp + 1, psdpp, sizeof(psdpp) * (n + 1));
380
*psdpp = devicePtrs[i];
391
static char regstr[40];
394
prop = promGetProperty("reg", &len);
395
if (prop && len >= 4) {
396
unsigned int *reg = (unsigned int *)prop;
397
if (!promP1275 || (type == PROM_NODE_SBUS) || (type == PROM_NODE_EBUS))
398
sprintf (regstr, "@%x,%x", reg[0], reg[1]);
399
else if (type == PROM_NODE_PCI) {
400
if ((reg[0] >> 8) & 7)
401
sprintf (regstr, "@%x,%x", (reg[0] >> 11) & 0x1f, (reg[0] >> 8) & 7);
403
sprintf (regstr, "@%x", (reg[0] >> 11) & 0x1f);
405
sprintf (regstr, "@%x", reg[0]);
407
unsigned int regs[2];
409
/* Things get more complicated on UPA. If upa-portid exists,
410
then address is @upa-portid,second-int-in-reg, otherwise
411
it is @first-int-in-reg/16,second-int-in-reg (well, probably
412
upa-portid always exists, but just to be safe). */
413
memcpy (regs, reg, sizeof(regs));
414
prop = promGetProperty("upa-portid", &len);
415
if (prop && len == 4) {
416
reg = (unsigned int *)prop;
417
sprintf (regstr, "@%x,%x", reg[0], regs[1]);
419
sprintf (regstr, "@%x,%x", regs[0] >> 4, regs[1]);
426
promWalkNode2Pathname(char *path, int parent, int node, int searchNode, int type)
429
int len, ntype = type;
432
prop = promGetProperty("name", &len);
434
if (!prop || len <= 0)
436
if ((!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) && !type)
437
ntype = PROM_NODE_SBUS;
438
else if (!strcmp(prop, "ebus") && type == PROM_NODE_PCI)
439
ntype = PROM_NODE_EBUS;
440
else if (!strcmp(prop, "pci") && !type)
441
ntype = PROM_NODE_PCI;
442
strcpy (path + 1, prop);
443
p = promGetReg(type);
446
if (node == searchNode)
448
nextnode = promGetChild(node);
450
promWalkNode2Pathname(strchr(path, 0), node, nextnode, searchNode, ntype))
452
nextnode = promGetSibling(node);
454
promWalkNode2Pathname(path, parent, nextnode, searchNode, type))
460
sparcPromNode2Pathname(sbusPromNodePtr pnode)
464
if (!pnode->node) return NULL;
466
if (!ret) return NULL;
467
if (promWalkNode2Pathname(ret, promRootNode, promGetChild(promRootNode), pnode->node, 0))
474
promWalkPathname2Node(char *name, char *regstr, int parent, int type)
480
prop = promGetProperty("name", &len);
481
if (!prop || len <= 0)
483
if ((!strcmp(prop, "sbus") || !strcmp(prop, "sbi")) && !type)
484
type = PROM_NODE_SBUS;
485
else if (!strcmp(prop, "ebus") && type == PROM_NODE_PCI)
486
type = PROM_NODE_EBUS;
487
else if (!strcmp(prop, "pci") && !type)
488
type = PROM_NODE_PCI;
489
for (node = promGetChild(parent); node; node = promGetSibling(node)) {
490
prop = promGetProperty("name", &len);
491
if (!prop || len <= 0)
493
if (*name && strcmp(name, prop))
496
p = promGetReg(type);
497
if (! *p || strcmp(p + 1, regstr))
503
for (node = promGetChild(parent); node; node = promGetSibling(node)) {
504
ret = promWalkPathname2Node(name, regstr, node, type);
509
name = strchr(regstr, 0) + 1;
512
p = strchr(name, '/');
517
regstr = strchr(name, '@');
529
sparcPromPathname2Node(const char *pathName)
532
char *name, *regstr, *p;
534
i = strlen(pathName);
535
name = xalloc(i + 2);
536
if (! name) return 0;
537
strcpy (name, pathName);
541
p = strchr(name + 1, '/');
546
regstr = strchr(name, '@');
551
if (name + 1 == regstr)
554
i = promWalkPathname2Node(name + 1, regstr, promRootNode, 0);
560
xf86MapSbusMem(sbusDevicePtr psdp, unsigned long offset, unsigned long size)
563
unsigned long pagemask = xf86getpagesize() - 1;
564
unsigned long off = offset & ~pagemask;
565
unsigned long len = ((offset + size + pagemask) & ~pagemask) - off;
567
if (psdp->fd == -1) {
568
psdp->fd = open(psdp->device, O_RDWR);
571
} else if (psdp->fd < 0)
574
ret = (pointer) mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE,
576
if (ret == (pointer) -1) {
577
ret = (pointer) mmap (NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED,
580
if (ret == (pointer) -1)
583
return (char *)ret + (offset - off);
587
xf86UnmapSbusMem(sbusDevicePtr psdp, pointer addr, unsigned long size)
589
unsigned long mask = xf86getpagesize() - 1;
590
unsigned long base = (unsigned long)addr & ~mask;
591
unsigned long len = (((unsigned long)addr + size + mask) & ~mask) - base;
593
munmap ((pointer)base, len);
596
/* Tell OS that we are driving the HW cursor ourselves. */
598
xf86SbusHideOsHwCursor(sbusDevicePtr psdp)
600
struct fbcursor fbcursor;
601
unsigned char zeros[8];
603
memset(&fbcursor, 0, sizeof(fbcursor));
604
memset(&zeros, 0, sizeof(zeros));
605
fbcursor.cmap.count = 2;
606
fbcursor.cmap.red = zeros;
607
fbcursor.cmap.green = zeros;
608
fbcursor.cmap.blue = zeros;
609
fbcursor.image = (char *)zeros;
610
fbcursor.mask = (char *)zeros;
611
fbcursor.size.x = 32;
613
fbcursor.set = FB_CUR_SETALL;
614
ioctl(psdp->fd, FBIOSCURSOR, &fbcursor);
617
/* Set HW cursor colormap. */
619
xf86SbusSetOsHwCursorCmap(sbusDevicePtr psdp, int bg, int fg)
621
struct fbcursor fbcursor;
622
unsigned char red[2], green[2], blue[2];
624
memset(&fbcursor, 0, sizeof(fbcursor));
631
fbcursor.cmap.count = 2;
632
fbcursor.cmap.red = red;
633
fbcursor.cmap.green = green;
634
fbcursor.cmap.blue = blue;
635
fbcursor.set = FB_CUR_SETCMAP;
636
ioctl(psdp->fd, FBIOSCURSOR, &fbcursor);